From 63fbc60a003ea7b0cd3621b7c696caf6588b3567 Mon Sep 17 00:00:00 2001 From: Nordi98 Date: Wed, 6 Aug 2025 15:36:50 +0200 Subject: [PATCH] ed --- .../mh_Parking/cl_utils.lua | 976 ++++----- .../mh_Parking/client.lua | 420 ++-- .../mh_Parking/config.lua | 128 +- .../mh_Parking/fxmanifest.lua | 48 +- .../mh_Parking/mh_Parking.sql | 64 +- .../mh_Parking/server.lua | 1538 ++++++------- .../mh_Parking/sv_utils.lua | 302 +-- .../mh_garage/client/debug.lua | 0 .../mh_garage/client/main.lua | 0 .../mh_garage/client/retrieve.lua | 0 .../mh_garage/client/stored.lua | 0 .../mh_garage/client/vehicleadmin.lua | 0 .../client/vehicleadmin_integration.lua | 0 .../mh_garage/client/verwaltung.lua | 0 .../mh_garage/config/config.lua | 0 .../mh_garage/config/price.lua | 0 .../mh_garage/fxmanifest.lua | 0 .../mh_garage/server/log.lua | 0 .../mh_garage/server/server.lua | 0 .../mh_garage/server/vehicleadmin.lua | 0 .../sn_vehicleKey/client.lua | 1908 ++++++++--------- .../sn_vehicleKey/config.lua | 298 +-- .../sn_vehicleKey/fxmanifest.lua | 114 +- .../sn_vehicleKey/server.lua | 1006 ++++----- .../sn_vehicleKey/vehicle_keys.sql | 54 +- .../[carscripts]/jg-advancedgarages/.fxap | Bin 0 -> 178 bytes .../[carscripts]/jg-advancedgarages/README.md | 17 + .../client/cl-deformation.lua | 90 + .../jg-advancedgarages/client/cl-garage.lua | Bin 0 -> 9049 bytes .../jg-advancedgarages/client/cl-impound.lua | Bin 0 -> 3499 bytes .../jg-advancedgarages/client/cl-interior.lua | Bin 0 -> 5386 bytes .../client/cl-locations.lua | 186 ++ .../jg-advancedgarages/client/cl-main.lua | Bin 0 -> 2349 bytes .../client/cl-private-garages.lua | Bin 0 -> 2518 bytes .../jg-advancedgarages/client/cl-spawn.lua | Bin 0 -> 7047 bytes .../jg-advancedgarages/client/cl-vehicle.lua | Bin 0 -> 4371 bytes .../jg-advancedgarages/config/config-cl.lua | 67 + .../jg-advancedgarages/config/config-sv.lua | 1 + .../jg-advancedgarages/config/config.lua | 669 ++++++ .../framework/cl-functions.lua | 535 +++++ .../framework/esx/cl-esx.lua | 37 + .../framework/esx/sv-esx.lua | 23 + .../jg-advancedgarages/framework/main.lua | 61 + .../jg-advancedgarages/framework/qb/cl-qb.lua | 22 + .../jg-advancedgarages/framework/qb/sv-qb.lua | 55 + .../framework/qbx/cl-qbx.lua | 22 + .../framework/sv-functions.lua | 317 +++ .../jg-advancedgarages/fxmanifest.lua | 56 + .../jg-advancedgarages/install/run-esx.sql | 28 + .../jg-advancedgarages/install/run-qb.sql | 25 + .../jg-advancedgarages/locales/ar.lua | 142 ++ .../jg-advancedgarages/locales/cn.lua | 142 ++ .../jg-advancedgarages/locales/cs.lua | 143 ++ .../jg-advancedgarages/locales/da.lua | 143 ++ .../jg-advancedgarages/locales/de.lua | 143 ++ .../jg-advancedgarages/locales/en.lua | 142 ++ .../jg-advancedgarages/locales/es.lua | 141 ++ .../jg-advancedgarages/locales/fi.lua | 143 ++ .../jg-advancedgarages/locales/fr.lua | 142 ++ .../jg-advancedgarages/locales/hu.lua | 143 ++ .../jg-advancedgarages/locales/it.lua | 143 ++ .../jg-advancedgarages/locales/ja.lua | 142 ++ .../jg-advancedgarages/locales/lt.lua | 142 ++ .../jg-advancedgarages/locales/nl.lua | 143 ++ .../jg-advancedgarages/locales/pt.lua | 141 ++ .../jg-advancedgarages/locales/ro.lua | 142 ++ .../jg-advancedgarages/locales/sv.lua | 143 ++ .../jg-advancedgarages/locales/vi.lua | 142 ++ .../jg-advancedgarages/server/sv-garage.lua | Bin 0 -> 12355 bytes .../jg-advancedgarages/server/sv-impound.lua | Bin 0 -> 4357 bytes .../jg-advancedgarages/server/sv-initsql.lua | Bin 0 -> 1212 bytes .../jg-advancedgarages/server/sv-interior.lua | Bin 0 -> 1100 bytes .../server/sv-locations.lua | Bin 0 -> 2683 bytes .../jg-advancedgarages/server/sv-main.lua | Bin 0 -> 2408 bytes .../server/sv-private-garages.lua | Bin 0 -> 4564 bytes .../server/sv-society-garage.lua | Bin 0 -> 4165 bytes .../jg-advancedgarages/server/sv-spawn.lua | Bin 0 -> 3065 bytes .../jg-advancedgarages/server/sv-vehicle.lua | Bin 0 -> 5845 bytes .../server/sv-version-check.lua | Bin 0 -> 1913 bytes .../jg-advancedgarages/server/sv-webhooks.lua | 70 + .../jg-advancedgarages/shared/main.lua | Bin 0 -> 2218 bytes .../vehicle_images/README.md | 6 + .../web/dist/assets/index-CZ7rsOCg.js | 55 + .../web/dist/assets/index-DURuzDZl.css | 5 + .../jg-advancedgarages/web/dist/index.html | 14 + .../jg-advancedgarages/web/dist/vite.svg | 1 + 86 files changed, 8352 insertions(+), 3428 deletions(-) rename resources/{[carscripts] => [Developer]}/mh_Parking/cl_utils.lua (97%) rename resources/{[carscripts] => [Developer]}/mh_Parking/client.lua (96%) rename resources/{[carscripts] => [Developer]}/mh_Parking/config.lua (97%) rename resources/{[carscripts] => [Developer]}/mh_Parking/fxmanifest.lua (93%) rename resources/{[carscripts] => [Developer]}/mh_Parking/mh_Parking.sql (97%) rename resources/{[carscripts] => [Developer]}/mh_Parking/server.lua (97%) rename resources/{[carscripts] => [Developer]}/mh_Parking/sv_utils.lua (96%) rename resources/{[carscripts] => [Developer]}/mh_garage/client/debug.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/client/main.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/client/retrieve.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/client/stored.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/client/vehicleadmin.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/client/vehicleadmin_integration.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/client/verwaltung.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/config/config.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/config/price.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/fxmanifest.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/server/log.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/server/server.lua (100%) rename resources/{[carscripts] => [Developer]}/mh_garage/server/vehicleadmin.lua (100%) rename resources/{[carscripts] => [Developer]}/sn_vehicleKey/client.lua (97%) rename resources/{[carscripts] => [Developer]}/sn_vehicleKey/config.lua (97%) rename resources/{[carscripts] => [Developer]}/sn_vehicleKey/fxmanifest.lua (95%) rename resources/{[carscripts] => [Developer]}/sn_vehicleKey/server.lua (97%) rename resources/{[carscripts] => [Developer]}/sn_vehicleKey/vehicle_keys.sql (97%) create mode 100644 resources/[carscripts]/jg-advancedgarages/.fxap create mode 100644 resources/[carscripts]/jg-advancedgarages/README.md create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-deformation.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-garage.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-impound.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-interior.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-locations.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-main.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-private-garages.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-spawn.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/client/cl-vehicle.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/config/config-cl.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/config/config-sv.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/config/config.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/framework/cl-functions.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/framework/esx/cl-esx.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/framework/esx/sv-esx.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/framework/main.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/framework/qb/cl-qb.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/framework/qb/sv-qb.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/framework/qbx/cl-qbx.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/framework/sv-functions.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/fxmanifest.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/install/run-esx.sql create mode 100644 resources/[carscripts]/jg-advancedgarages/install/run-qb.sql create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/ar.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/cn.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/cs.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/da.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/de.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/en.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/es.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/fi.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/fr.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/hu.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/it.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/ja.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/lt.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/nl.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/pt.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/ro.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/sv.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/locales/vi.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-garage.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-impound.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-initsql.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-interior.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-locations.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-main.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-private-garages.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-society-garage.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-spawn.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-vehicle.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-version-check.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/server/sv-webhooks.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/shared/main.lua create mode 100644 resources/[carscripts]/jg-advancedgarages/vehicle_images/README.md create mode 100644 resources/[carscripts]/jg-advancedgarages/web/dist/assets/index-CZ7rsOCg.js create mode 100644 resources/[carscripts]/jg-advancedgarages/web/dist/assets/index-DURuzDZl.css create mode 100644 resources/[carscripts]/jg-advancedgarages/web/dist/index.html create mode 100644 resources/[carscripts]/jg-advancedgarages/web/dist/vite.svg diff --git a/resources/[carscripts]/mh_Parking/cl_utils.lua b/resources/[Developer]/mh_Parking/cl_utils.lua similarity index 97% rename from resources/[carscripts]/mh_Parking/cl_utils.lua rename to resources/[Developer]/mh_Parking/cl_utils.lua index 17c108175..0ea573caa 100644 --- a/resources/[carscripts]/mh_Parking/cl_utils.lua +++ b/resources/[Developer]/mh_Parking/cl_utils.lua @@ -1,488 +1,488 @@ --- logs text to the console -function Log(text) - if (Config.isDebug) then - Log(text) - end -end - --- Return all vehicle modifications in an array -function GetVehicleModifications(vehicle) - local color1, color2 = GetVehicleColours(vehicle) - local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) - - local extras = {} - for i = 0, 20, 1 do - if (DoesExtraExist(vehicle, i)) then - if (IsVehicleExtraTurnedOn(vehicle, i)) then - table.insert(extras, { i, 0 }) - else - table.insert(extras, { i, 1 }) - end - end - end - - local tiresBurst = {} - for i = 0, 5, 1 do - if (IsVehicleTyreBurst(vehicle, i, true)) then - table.insert(tiresBurst, { i, true }) - elseif (IsVehicleTyreBurst(vehicle, i, false)) then - table.insert(tiresBurst, { i, false }) - end - end - - local doorsMissing = {} - for i = 0, 7, 1 do - if (IsVehicleDoorDamaged(vehicle, i)) then - table.insert(doorsMissing, i) - end - end - - local windowsBroken = {} - --for i = 0, 13, 1 do - -- if (not IsVehicleWindowIntact(vehicle, i)) then - -- table.insert(windowsBroken, i) - -- end - --end - - -- custom colors - local hasCustomPrimaryColor = GetIsVehiclePrimaryColourCustom(vehicle) - local customPrimaryColor = nil - if (hasCustomPrimaryColor) then - local r, g, b = GetVehicleCustomPrimaryColour(vehicle) - customPrimaryColor = { r, g, b } - end - - local hasCustomSecondaryColor = GetIsVehicleSecondaryColourCustom(vehicle) - local customSecondaryColor = nil - if (hasCustomSecondaryColor) then - local r, g, b = GetVehicleCustomSecondaryColour(vehicle) - customSecondaryColor = { r, g, b } - end - - return { - -- 1 model - GetEntityModel(vehicle), - - -- 2 lockStatus - GetVehicleDoorLockStatus(vehicle), - - -- 3 health - math.floor(GetEntityHealth(vehicle) * 10.0) / 10.0, - -- 4 bodyHealth - math.floor(GetVehicleBodyHealth(vehicle) * 10.0) / 10.0, - -- 5 engineHealth - math.floor(GetVehicleEngineHealth(vehicle) * 10.0) / 10.0, - -- 6 petrolTankHealth - math.floor(GetVehiclePetrolTankHealth(vehicle) * 10.0) / 10.0, - - -- 7 dirtLevel - math.floor(GetVehicleDirtLevel(vehicle) * 10.0) / 10.0, - -- 8 fuelLevel - math.floor(exports[Config.exports]:GetFuel(vehicle) * 10.0) / 10.0, - - ---------------------------------------------------------------------- Implementierung Miho - --math.floor(DecorGetFloat(vehicle, Config.FuelDecor)*10) / 10.0, - ---------------------------------------------------------------------- Implementierung Miho ENDE - - -- 9 plateIndex - GetVehicleNumberPlateTextIndex(vehicle), - - -- 10 primaryColor - color1, - -- 11 secondaryColor - color2, - -- 12 pearlescentColor - pearlescentColor, - -- 13 wheelColor - wheelColor, - - -- 14 wheelType - GetVehicleWheelType(vehicle), - -- 15 customWheelsFront - GetVehicleModVariation(vehicle, 23); - -- 16 customWheelsBack - GetVehicleModVariation(vehicle, 24); - -- 17 windowTint - GetVehicleWindowTint(vehicle), - -- 18 enabledNeon - { - IsVehicleNeonLightEnabled(vehicle, 0), - IsVehicleNeonLightEnabled(vehicle, 1), - IsVehicleNeonLightEnabled(vehicle, 2), - IsVehicleNeonLightEnabled(vehicle, 3), - }, - -- 19 neonColor - table.pack(GetVehicleNeonLightsColour(vehicle)), - -- 20 tireSmokeColor - table.pack(GetVehicleTyreSmokeColor(vehicle)), - - -- 21 extras - extras, - - -- 22-32 mods - GetVehicleMod(vehicle, 0), - GetVehicleMod(vehicle, 1), - GetVehicleMod(vehicle, 2), - GetVehicleMod(vehicle, 3), - GetVehicleMod(vehicle, 4), - GetVehicleMod(vehicle, 5), - GetVehicleMod(vehicle, 6), - GetVehicleMod(vehicle, 7), - GetVehicleMod(vehicle, 8), - GetVehicleMod(vehicle, 9), - GetVehicleMod(vehicle, 10), - - -- 33-38 mods - GetVehicleMod(vehicle, 11), - GetVehicleMod(vehicle, 12), - GetVehicleMod(vehicle, 13), - GetVehicleMod(vehicle, 14), - GetVehicleMod(vehicle, 15), - GetVehicleMod(vehicle, 16), - - -- 39-41 mods - IsToggleModOn(vehicle, 18), - IsToggleModOn(vehicle, 20), - IsToggleModOn(vehicle, 22), - - -- 42-43 mods - GetVehicleMod(vehicle, 23), - GetVehicleMod(vehicle, 24), - - -- 44-66 mods - GetVehicleMod(vehicle, 25), - GetVehicleMod(vehicle, 26), - GetVehicleMod(vehicle, 27), - GetVehicleMod(vehicle, 28), - GetVehicleMod(vehicle, 29), - GetVehicleMod(vehicle, 30), - GetVehicleMod(vehicle, 31), - GetVehicleMod(vehicle, 32), - GetVehicleMod(vehicle, 33), - GetVehicleMod(vehicle, 34), - GetVehicleMod(vehicle, 35), - GetVehicleMod(vehicle, 36), - GetVehicleMod(vehicle, 37), - GetVehicleMod(vehicle, 38), - GetVehicleMod(vehicle, 39), - GetVehicleMod(vehicle, 40), - GetVehicleMod(vehicle, 41), - GetVehicleMod(vehicle, 42), - GetVehicleMod(vehicle, 43), - GetVehicleMod(vehicle, 44), - GetVehicleMod(vehicle, 45), - GetVehicleMod(vehicle, 46), - GetVehicleMod(vehicle, 48), - - -- 67 livery - GetVehicleLivery(vehicle), - - -- 68 missingDoors - doorsMissing, - - -- 69 bulletproofTires - not GetVehicleTyresCanBurst(vehicle), - -- 70 tiresBurst - tiresBurst, - - -- 71 brokenWindows - windowsBroken, - - -- 72 xenon lights - GetVehicleXenonLightsColour(vehicle), - - -- 73 custom primary color - customPrimaryColor, - -- 74 custom secondary color - customSecondaryColor, - - -- 75 interior color - GetVehicleInteriorColor(vehicle) - } -end - --- Apply all modifications to a vehicle entity -function SetVehicleModifications(vehicle, plate, modifications) - SetVehicleModKit(vehicle, 0) - - -- plate - SetVehicleNumberPlateText(vehicle, plate) - SetVehicleNumberPlateTextIndex(vehicle, modifications[9]) - - -- lockStatus - SetVehicleDoorsLocked(vehicle, modifications[2]) - - -- colours - SetVehicleColours(vehicle, modifications[10], modifications[11]) - if (modifications[73]) then - SetVehicleCustomPrimaryColour(vehicle, modifications[73][1], modifications[73][2], modifications[73][3]) - end - if (modifications[74]) then - SetVehicleCustomSecondaryColour(vehicle, modifications[74][1], modifications[74][2], modifications[74][3]) - end - if (modifications[75]) then - SetVehicleInteriorColor(vehicle, modifications[75]) - end - - SetVehicleExtraColours(vehicle, modifications[12], modifications[13]) - - SetVehicleTyreSmokeColor(vehicle, modifications[20][1], modifications[20][2], modifications[20][3]) - - -- wheels - SetVehicleWheelType(vehicle, modifications[14]) - - -- windows - SetVehicleWindowTint(vehicle, modifications[17]) - - -- neonlight - SetVehicleNeonLightEnabled(vehicle, 0, modifications[18][1]) - SetVehicleNeonLightEnabled(vehicle, 1, modifications[18][2]) - SetVehicleNeonLightEnabled(vehicle, 2, modifications[18][3]) - SetVehicleNeonLightEnabled(vehicle, 3, modifications[18][4]) - - SetVehicleNeonLightsColour(vehicle, modifications[19][1], modifications[19][2], modifications[19][3]) - - -- mods - SetVehicleMod(vehicle, 0, modifications[22], modifications[15]) - SetVehicleMod(vehicle, 1, modifications[23], modifications[15]) - SetVehicleMod(vehicle, 2, modifications[24], modifications[15]) - SetVehicleMod(vehicle, 3, modifications[25], modifications[15]) - SetVehicleMod(vehicle, 4, modifications[26], modifications[15]) - SetVehicleMod(vehicle, 5, modifications[27], modifications[15]) - SetVehicleMod(vehicle, 6, modifications[28], modifications[15]) - SetVehicleMod(vehicle, 7, modifications[29], modifications[15]) - SetVehicleMod(vehicle, 8, modifications[30], modifications[15]) - SetVehicleMod(vehicle, 9, modifications[31], modifications[15]) - SetVehicleMod(vehicle, 10, modifications[32], modifications[15]) - - SetVehicleMod(vehicle, 11, modifications[33], modifications[15]) - SetVehicleMod(vehicle, 12, modifications[34], modifications[15]) - SetVehicleMod(vehicle, 13, modifications[35], modifications[15]) - - SetVehicleMod(vehicle, 14, modifications[36], modifications[15]) - - SetVehicleMod(vehicle, 15, modifications[37], modifications[15]) - SetVehicleMod(vehicle, 16, modifications[38], modifications[15]) - - ToggleVehicleMod(vehicle, 18, modifications[39]) - ToggleVehicleMod(vehicle, 20, modifications[40]) - ToggleVehicleMod(vehicle, 22, modifications[41]) - - SetVehicleMod(vehicle, 23, modifications[42], modifications[15]) - SetVehicleMod(vehicle, 24, modifications[43], modifications[16]) - - SetVehicleMod(vehicle, 25, modifications[44], modifications[15]) - SetVehicleMod(vehicle, 26, modifications[45], modifications[15]) - SetVehicleMod(vehicle, 27, modifications[46], modifications[15]) - SetVehicleMod(vehicle, 28, modifications[47], modifications[15]) - SetVehicleMod(vehicle, 29, modifications[48], modifications[15]) - SetVehicleMod(vehicle, 30, modifications[49], modifications[15]) - SetVehicleMod(vehicle, 31, modifications[50], modifications[15]) - SetVehicleMod(vehicle, 32, modifications[51], modifications[15]) - SetVehicleMod(vehicle, 33, modifications[52], modifications[15]) - SetVehicleMod(vehicle, 34, modifications[53], modifications[15]) - SetVehicleMod(vehicle, 35, modifications[54], modifications[15]) - SetVehicleMod(vehicle, 36, modifications[55], modifications[15]) - SetVehicleMod(vehicle, 37, modifications[56], modifications[15]) - SetVehicleMod(vehicle, 38, modifications[57], modifications[15]) - SetVehicleMod(vehicle, 39, modifications[58], modifications[15]) - SetVehicleMod(vehicle, 40, modifications[59], modifications[15]) - SetVehicleMod(vehicle, 41, modifications[60], modifications[15]) - SetVehicleMod(vehicle, 42, modifications[61], modifications[15]) - SetVehicleMod(vehicle, 43, modifications[62], modifications[15]) - SetVehicleMod(vehicle, 44, modifications[63], modifications[15]) - SetVehicleMod(vehicle, 45, modifications[64], modifications[15]) - SetVehicleMod(vehicle, 46, modifications[65], modifications[15]) - SetVehicleMod(vehicle, 48, modifications[66], modifications[15]) - - SetVehicleLivery(vehicle, modifications[67]) - - -- extras - for i = 1, #modifications[21], 1 do - SetVehicleExtra(vehicle, modifications[21][i][1], modifications[21][i][2]) - end - - -- stats - SetEntityHealth(vehicle, modifications[3]) - SetVehicleBodyHealth(vehicle, modifications[4]) - SetVehicleEngineHealth(vehicle, modifications[5]) - SetVehiclePetrolTankHealth(vehicle, modifications[6]) - if (Config.renderScorched and (modifications[5] < -3999.0 or modifications[6] < -999.0)) then - TriggerServerEvent("mh_Parking:renderScorched", NetworkGetNetworkIdFromEntity(vehicle), true) - end - - SetVehicleDirtLevel(vehicle, modifications[7]) - exports[Config.exports]:SetFuel(vehicle, modifications[8]) - - ---------------------------------------------------------------------- Implementierung Miho - --[[ - fuel = modifications[8] - if type(fuel) == 'number' and fuel >= 0 and fuel <= 100 then - SetVehicleFuelLevel(vehicle, fuel + 0.0) - DecorSetFloat(vehicle, Config.FuelDecor, GetVehicleFuelLevel(vehicle)) - end - ]] - ---------------------------------------------------------------------- Implementierung Miho ENDE - - - -- doors - for i = 1, #modifications[68], 1 do - SetVehicleDoorBroken(vehicle, modifications[68][i], true) - end - - -- tires - SetVehicleTyresCanBurst(vehicle, not modifications[69]) - if (not modifications[69]) then - for i = 1, #modifications[70], 1 do - SetVehicleTyreBurst(vehicle, modifications[70][i][1], modifications[70][i][2], 1000.0) - end - end - - -- windows - for i = 1, #modifications[71], 1 do - SmashVehicleWindow(vehicle, modifications[71][i]) - end - - -- xenon lights - if (modifications[72]) then - SetVehicleXenonLightsColour(vehicle, modifications[72]) - end -end - --- Return closest loaded vehicle entity or nil if no vehicle is found -function GetClosestVehicle(position, maxRadius) - local vehicles = GetAllVehicles() - local dist = maxRadius - local closestVehicle = nil - - for i=1, #vehicles, 1 do - local vehicleCoords = GetEntityCoords(vehicles[i]) - local tempDist = Vdist(vehicleCoords.x, vehicleCoords.y, vehicleCoords.z, position.x, position.y, position.z) - if (tempDist < dist) then - dist = tempDist - closestVehicle = vehicles[i] - end - end - - if (closestVehicle ~= nil and DoesEntityExist(closestVehicle)) then - return closestVehicle - else - return nil - end -end - --- Returns all loaded vehicles on client side -function GetAllVehicles() - local vehicles = {} - - for vehicle in EnumerateVehicles() do - table.insert(vehicles, vehicle) - end - - return vehicles -end - -function IsVehicleBlacklisted(vehicle) - -- check class - local class = GetVehicleClass(vehicle) - for i = 1, #Config.classesBlacklist, 1 do - if (class == Config.classesBlacklist[i]) then - return true - end - end - - -- check model - local modelHash = GetEntityModel(vehicle) - for i = 1, #Config.vehiclesBlacklist, 1 do - if (modelHash == Config.vehiclesBlacklist[i]) then - return true - end - end - - return false -end - -function GetVehiclePosition(plate) - if (GetResourceState("kimi_callbacks") ~= "started") then - Log("^1[ERROR] \"kimi_callbacks\" is either not installed properly or hasn't been started!") - Log("^1[ERROR] The export \"GetVehiclePosition\" can only be used when having this resource installed.") - return nil - end - - if (plate == nil) then - Log("^1[ERROR] \"plate\" was nil while trying to call export \"GetVehiclePosition\"!") - return nil - end - - if (type(plate) ~= "string") then - Log("^1[ERROR] \"plate\" (\"" .. plate .. "\") needs to be of type string when calling export \"GetVehiclePosition\"!") - return nil - end - - local position = exports["kimi_callbacks"]:Trigger("AP:getVehiclePosition", plate:upper()) - - return position -end - -function GetVehiclePositions(...) - if (GetResourceState("kimi_callbacks") ~= "started") then - Log("^1[ERROR] \"kimi_callbacks\" is either not installed properly or hasn't been started!") - Log("^1[ERROR] The export \"GetVehiclePositions\" can only be used when having this resource installed.") - return nil - end - - local plates = { ... } - - for i, plate in ipairs(plates) do - if (plate == nil) then - Log("^1[ERROR] \"plate\" (Index: \"" .. i .. "\") was nil while trying to call export \"GetVehiclePositions\"!") - return nil - end - - if (type(plate) ~= "string") then - Log("^1[ERROR] \"plate\" (\"" .. plate .. "\") (Index: " .. i .. ") needs to be of type string when calling export \"GetVehiclePositions\"!") - return nil - end - - plates[i] = plates[i]:upper() - end - - local data = exports["kimi_callbacks"]:Trigger("AP:getVehiclePositions", plates) - - return data -end - --- getting all vehicles -function EnumerateVehicles() - return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle) -end -function EnumerateEntities(initFunc, moveFunc, disposeFunc) - return coroutine.wrap(function() - local iter, id = initFunc() - if not id or id == 0 then - disposeFunc(iter) - return - end - - local enum = {handle = iter, destructor = disposeFunc} - setmetatable(enum, entityEnumerator) - - local next = true - repeat - coroutine.yield(id) - next, id = moveFunc(iter) - until not next - - enum.destructor, enum.handle = nil, nil - disposeFunc(iter) - end) -end -local entityEnumerator = { - __gc = function(enum) - if enum.destructor and enum.handle then - enum.destructor(enum.handle) - end - enum.destructor = nil - enum.handle = nil - end -} +-- logs text to the console +function Log(text) + if (Config.isDebug) then + Log(text) + end +end + +-- Return all vehicle modifications in an array +function GetVehicleModifications(vehicle) + local color1, color2 = GetVehicleColours(vehicle) + local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) + + local extras = {} + for i = 0, 20, 1 do + if (DoesExtraExist(vehicle, i)) then + if (IsVehicleExtraTurnedOn(vehicle, i)) then + table.insert(extras, { i, 0 }) + else + table.insert(extras, { i, 1 }) + end + end + end + + local tiresBurst = {} + for i = 0, 5, 1 do + if (IsVehicleTyreBurst(vehicle, i, true)) then + table.insert(tiresBurst, { i, true }) + elseif (IsVehicleTyreBurst(vehicle, i, false)) then + table.insert(tiresBurst, { i, false }) + end + end + + local doorsMissing = {} + for i = 0, 7, 1 do + if (IsVehicleDoorDamaged(vehicle, i)) then + table.insert(doorsMissing, i) + end + end + + local windowsBroken = {} + --for i = 0, 13, 1 do + -- if (not IsVehicleWindowIntact(vehicle, i)) then + -- table.insert(windowsBroken, i) + -- end + --end + + -- custom colors + local hasCustomPrimaryColor = GetIsVehiclePrimaryColourCustom(vehicle) + local customPrimaryColor = nil + if (hasCustomPrimaryColor) then + local r, g, b = GetVehicleCustomPrimaryColour(vehicle) + customPrimaryColor = { r, g, b } + end + + local hasCustomSecondaryColor = GetIsVehicleSecondaryColourCustom(vehicle) + local customSecondaryColor = nil + if (hasCustomSecondaryColor) then + local r, g, b = GetVehicleCustomSecondaryColour(vehicle) + customSecondaryColor = { r, g, b } + end + + return { + -- 1 model + GetEntityModel(vehicle), + + -- 2 lockStatus + GetVehicleDoorLockStatus(vehicle), + + -- 3 health + math.floor(GetEntityHealth(vehicle) * 10.0) / 10.0, + -- 4 bodyHealth + math.floor(GetVehicleBodyHealth(vehicle) * 10.0) / 10.0, + -- 5 engineHealth + math.floor(GetVehicleEngineHealth(vehicle) * 10.0) / 10.0, + -- 6 petrolTankHealth + math.floor(GetVehiclePetrolTankHealth(vehicle) * 10.0) / 10.0, + + -- 7 dirtLevel + math.floor(GetVehicleDirtLevel(vehicle) * 10.0) / 10.0, + -- 8 fuelLevel + math.floor(exports[Config.exports]:GetFuel(vehicle) * 10.0) / 10.0, + + ---------------------------------------------------------------------- Implementierung Miho + --math.floor(DecorGetFloat(vehicle, Config.FuelDecor)*10) / 10.0, + ---------------------------------------------------------------------- Implementierung Miho ENDE + + -- 9 plateIndex + GetVehicleNumberPlateTextIndex(vehicle), + + -- 10 primaryColor + color1, + -- 11 secondaryColor + color2, + -- 12 pearlescentColor + pearlescentColor, + -- 13 wheelColor + wheelColor, + + -- 14 wheelType + GetVehicleWheelType(vehicle), + -- 15 customWheelsFront + GetVehicleModVariation(vehicle, 23); + -- 16 customWheelsBack + GetVehicleModVariation(vehicle, 24); + -- 17 windowTint + GetVehicleWindowTint(vehicle), + -- 18 enabledNeon + { + IsVehicleNeonLightEnabled(vehicle, 0), + IsVehicleNeonLightEnabled(vehicle, 1), + IsVehicleNeonLightEnabled(vehicle, 2), + IsVehicleNeonLightEnabled(vehicle, 3), + }, + -- 19 neonColor + table.pack(GetVehicleNeonLightsColour(vehicle)), + -- 20 tireSmokeColor + table.pack(GetVehicleTyreSmokeColor(vehicle)), + + -- 21 extras + extras, + + -- 22-32 mods + GetVehicleMod(vehicle, 0), + GetVehicleMod(vehicle, 1), + GetVehicleMod(vehicle, 2), + GetVehicleMod(vehicle, 3), + GetVehicleMod(vehicle, 4), + GetVehicleMod(vehicle, 5), + GetVehicleMod(vehicle, 6), + GetVehicleMod(vehicle, 7), + GetVehicleMod(vehicle, 8), + GetVehicleMod(vehicle, 9), + GetVehicleMod(vehicle, 10), + + -- 33-38 mods + GetVehicleMod(vehicle, 11), + GetVehicleMod(vehicle, 12), + GetVehicleMod(vehicle, 13), + GetVehicleMod(vehicle, 14), + GetVehicleMod(vehicle, 15), + GetVehicleMod(vehicle, 16), + + -- 39-41 mods + IsToggleModOn(vehicle, 18), + IsToggleModOn(vehicle, 20), + IsToggleModOn(vehicle, 22), + + -- 42-43 mods + GetVehicleMod(vehicle, 23), + GetVehicleMod(vehicle, 24), + + -- 44-66 mods + GetVehicleMod(vehicle, 25), + GetVehicleMod(vehicle, 26), + GetVehicleMod(vehicle, 27), + GetVehicleMod(vehicle, 28), + GetVehicleMod(vehicle, 29), + GetVehicleMod(vehicle, 30), + GetVehicleMod(vehicle, 31), + GetVehicleMod(vehicle, 32), + GetVehicleMod(vehicle, 33), + GetVehicleMod(vehicle, 34), + GetVehicleMod(vehicle, 35), + GetVehicleMod(vehicle, 36), + GetVehicleMod(vehicle, 37), + GetVehicleMod(vehicle, 38), + GetVehicleMod(vehicle, 39), + GetVehicleMod(vehicle, 40), + GetVehicleMod(vehicle, 41), + GetVehicleMod(vehicle, 42), + GetVehicleMod(vehicle, 43), + GetVehicleMod(vehicle, 44), + GetVehicleMod(vehicle, 45), + GetVehicleMod(vehicle, 46), + GetVehicleMod(vehicle, 48), + + -- 67 livery + GetVehicleLivery(vehicle), + + -- 68 missingDoors + doorsMissing, + + -- 69 bulletproofTires + not GetVehicleTyresCanBurst(vehicle), + -- 70 tiresBurst + tiresBurst, + + -- 71 brokenWindows + windowsBroken, + + -- 72 xenon lights + GetVehicleXenonLightsColour(vehicle), + + -- 73 custom primary color + customPrimaryColor, + -- 74 custom secondary color + customSecondaryColor, + + -- 75 interior color + GetVehicleInteriorColor(vehicle) + } +end + +-- Apply all modifications to a vehicle entity +function SetVehicleModifications(vehicle, plate, modifications) + SetVehicleModKit(vehicle, 0) + + -- plate + SetVehicleNumberPlateText(vehicle, plate) + SetVehicleNumberPlateTextIndex(vehicle, modifications[9]) + + -- lockStatus + SetVehicleDoorsLocked(vehicle, modifications[2]) + + -- colours + SetVehicleColours(vehicle, modifications[10], modifications[11]) + if (modifications[73]) then + SetVehicleCustomPrimaryColour(vehicle, modifications[73][1], modifications[73][2], modifications[73][3]) + end + if (modifications[74]) then + SetVehicleCustomSecondaryColour(vehicle, modifications[74][1], modifications[74][2], modifications[74][3]) + end + if (modifications[75]) then + SetVehicleInteriorColor(vehicle, modifications[75]) + end + + SetVehicleExtraColours(vehicle, modifications[12], modifications[13]) + + SetVehicleTyreSmokeColor(vehicle, modifications[20][1], modifications[20][2], modifications[20][3]) + + -- wheels + SetVehicleWheelType(vehicle, modifications[14]) + + -- windows + SetVehicleWindowTint(vehicle, modifications[17]) + + -- neonlight + SetVehicleNeonLightEnabled(vehicle, 0, modifications[18][1]) + SetVehicleNeonLightEnabled(vehicle, 1, modifications[18][2]) + SetVehicleNeonLightEnabled(vehicle, 2, modifications[18][3]) + SetVehicleNeonLightEnabled(vehicle, 3, modifications[18][4]) + + SetVehicleNeonLightsColour(vehicle, modifications[19][1], modifications[19][2], modifications[19][3]) + + -- mods + SetVehicleMod(vehicle, 0, modifications[22], modifications[15]) + SetVehicleMod(vehicle, 1, modifications[23], modifications[15]) + SetVehicleMod(vehicle, 2, modifications[24], modifications[15]) + SetVehicleMod(vehicle, 3, modifications[25], modifications[15]) + SetVehicleMod(vehicle, 4, modifications[26], modifications[15]) + SetVehicleMod(vehicle, 5, modifications[27], modifications[15]) + SetVehicleMod(vehicle, 6, modifications[28], modifications[15]) + SetVehicleMod(vehicle, 7, modifications[29], modifications[15]) + SetVehicleMod(vehicle, 8, modifications[30], modifications[15]) + SetVehicleMod(vehicle, 9, modifications[31], modifications[15]) + SetVehicleMod(vehicle, 10, modifications[32], modifications[15]) + + SetVehicleMod(vehicle, 11, modifications[33], modifications[15]) + SetVehicleMod(vehicle, 12, modifications[34], modifications[15]) + SetVehicleMod(vehicle, 13, modifications[35], modifications[15]) + + SetVehicleMod(vehicle, 14, modifications[36], modifications[15]) + + SetVehicleMod(vehicle, 15, modifications[37], modifications[15]) + SetVehicleMod(vehicle, 16, modifications[38], modifications[15]) + + ToggleVehicleMod(vehicle, 18, modifications[39]) + ToggleVehicleMod(vehicle, 20, modifications[40]) + ToggleVehicleMod(vehicle, 22, modifications[41]) + + SetVehicleMod(vehicle, 23, modifications[42], modifications[15]) + SetVehicleMod(vehicle, 24, modifications[43], modifications[16]) + + SetVehicleMod(vehicle, 25, modifications[44], modifications[15]) + SetVehicleMod(vehicle, 26, modifications[45], modifications[15]) + SetVehicleMod(vehicle, 27, modifications[46], modifications[15]) + SetVehicleMod(vehicle, 28, modifications[47], modifications[15]) + SetVehicleMod(vehicle, 29, modifications[48], modifications[15]) + SetVehicleMod(vehicle, 30, modifications[49], modifications[15]) + SetVehicleMod(vehicle, 31, modifications[50], modifications[15]) + SetVehicleMod(vehicle, 32, modifications[51], modifications[15]) + SetVehicleMod(vehicle, 33, modifications[52], modifications[15]) + SetVehicleMod(vehicle, 34, modifications[53], modifications[15]) + SetVehicleMod(vehicle, 35, modifications[54], modifications[15]) + SetVehicleMod(vehicle, 36, modifications[55], modifications[15]) + SetVehicleMod(vehicle, 37, modifications[56], modifications[15]) + SetVehicleMod(vehicle, 38, modifications[57], modifications[15]) + SetVehicleMod(vehicle, 39, modifications[58], modifications[15]) + SetVehicleMod(vehicle, 40, modifications[59], modifications[15]) + SetVehicleMod(vehicle, 41, modifications[60], modifications[15]) + SetVehicleMod(vehicle, 42, modifications[61], modifications[15]) + SetVehicleMod(vehicle, 43, modifications[62], modifications[15]) + SetVehicleMod(vehicle, 44, modifications[63], modifications[15]) + SetVehicleMod(vehicle, 45, modifications[64], modifications[15]) + SetVehicleMod(vehicle, 46, modifications[65], modifications[15]) + SetVehicleMod(vehicle, 48, modifications[66], modifications[15]) + + SetVehicleLivery(vehicle, modifications[67]) + + -- extras + for i = 1, #modifications[21], 1 do + SetVehicleExtra(vehicle, modifications[21][i][1], modifications[21][i][2]) + end + + -- stats + SetEntityHealth(vehicle, modifications[3]) + SetVehicleBodyHealth(vehicle, modifications[4]) + SetVehicleEngineHealth(vehicle, modifications[5]) + SetVehiclePetrolTankHealth(vehicle, modifications[6]) + if (Config.renderScorched and (modifications[5] < -3999.0 or modifications[6] < -999.0)) then + TriggerServerEvent("mh_Parking:renderScorched", NetworkGetNetworkIdFromEntity(vehicle), true) + end + + SetVehicleDirtLevel(vehicle, modifications[7]) + exports[Config.exports]:SetFuel(vehicle, modifications[8]) + + ---------------------------------------------------------------------- Implementierung Miho + --[[ + fuel = modifications[8] + if type(fuel) == 'number' and fuel >= 0 and fuel <= 100 then + SetVehicleFuelLevel(vehicle, fuel + 0.0) + DecorSetFloat(vehicle, Config.FuelDecor, GetVehicleFuelLevel(vehicle)) + end + ]] + ---------------------------------------------------------------------- Implementierung Miho ENDE + + + -- doors + for i = 1, #modifications[68], 1 do + SetVehicleDoorBroken(vehicle, modifications[68][i], true) + end + + -- tires + SetVehicleTyresCanBurst(vehicle, not modifications[69]) + if (not modifications[69]) then + for i = 1, #modifications[70], 1 do + SetVehicleTyreBurst(vehicle, modifications[70][i][1], modifications[70][i][2], 1000.0) + end + end + + -- windows + for i = 1, #modifications[71], 1 do + SmashVehicleWindow(vehicle, modifications[71][i]) + end + + -- xenon lights + if (modifications[72]) then + SetVehicleXenonLightsColour(vehicle, modifications[72]) + end +end + +-- Return closest loaded vehicle entity or nil if no vehicle is found +function GetClosestVehicle(position, maxRadius) + local vehicles = GetAllVehicles() + local dist = maxRadius + local closestVehicle = nil + + for i=1, #vehicles, 1 do + local vehicleCoords = GetEntityCoords(vehicles[i]) + local tempDist = Vdist(vehicleCoords.x, vehicleCoords.y, vehicleCoords.z, position.x, position.y, position.z) + if (tempDist < dist) then + dist = tempDist + closestVehicle = vehicles[i] + end + end + + if (closestVehicle ~= nil and DoesEntityExist(closestVehicle)) then + return closestVehicle + else + return nil + end +end + +-- Returns all loaded vehicles on client side +function GetAllVehicles() + local vehicles = {} + + for vehicle in EnumerateVehicles() do + table.insert(vehicles, vehicle) + end + + return vehicles +end + +function IsVehicleBlacklisted(vehicle) + -- check class + local class = GetVehicleClass(vehicle) + for i = 1, #Config.classesBlacklist, 1 do + if (class == Config.classesBlacklist[i]) then + return true + end + end + + -- check model + local modelHash = GetEntityModel(vehicle) + for i = 1, #Config.vehiclesBlacklist, 1 do + if (modelHash == Config.vehiclesBlacklist[i]) then + return true + end + end + + return false +end + +function GetVehiclePosition(plate) + if (GetResourceState("kimi_callbacks") ~= "started") then + Log("^1[ERROR] \"kimi_callbacks\" is either not installed properly or hasn't been started!") + Log("^1[ERROR] The export \"GetVehiclePosition\" can only be used when having this resource installed.") + return nil + end + + if (plate == nil) then + Log("^1[ERROR] \"plate\" was nil while trying to call export \"GetVehiclePosition\"!") + return nil + end + + if (type(plate) ~= "string") then + Log("^1[ERROR] \"plate\" (\"" .. plate .. "\") needs to be of type string when calling export \"GetVehiclePosition\"!") + return nil + end + + local position = exports["kimi_callbacks"]:Trigger("AP:getVehiclePosition", plate:upper()) + + return position +end + +function GetVehiclePositions(...) + if (GetResourceState("kimi_callbacks") ~= "started") then + Log("^1[ERROR] \"kimi_callbacks\" is either not installed properly or hasn't been started!") + Log("^1[ERROR] The export \"GetVehiclePositions\" can only be used when having this resource installed.") + return nil + end + + local plates = { ... } + + for i, plate in ipairs(plates) do + if (plate == nil) then + Log("^1[ERROR] \"plate\" (Index: \"" .. i .. "\") was nil while trying to call export \"GetVehiclePositions\"!") + return nil + end + + if (type(plate) ~= "string") then + Log("^1[ERROR] \"plate\" (\"" .. plate .. "\") (Index: " .. i .. ") needs to be of type string when calling export \"GetVehiclePositions\"!") + return nil + end + + plates[i] = plates[i]:upper() + end + + local data = exports["kimi_callbacks"]:Trigger("AP:getVehiclePositions", plates) + + return data +end + +-- getting all vehicles +function EnumerateVehicles() + return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle) +end +function EnumerateEntities(initFunc, moveFunc, disposeFunc) + return coroutine.wrap(function() + local iter, id = initFunc() + if not id or id == 0 then + disposeFunc(iter) + return + end + + local enum = {handle = iter, destructor = disposeFunc} + setmetatable(enum, entityEnumerator) + + local next = true + repeat + coroutine.yield(id) + next, id = moveFunc(iter) + until not next + + enum.destructor, enum.handle = nil, nil + disposeFunc(iter) + end) +end +local entityEnumerator = { + __gc = function(enum) + if enum.destructor and enum.handle then + enum.destructor(enum.handle) + end + enum.destructor = nil + enum.handle = nil + end +} diff --git a/resources/[carscripts]/mh_Parking/client.lua b/resources/[Developer]/mh_Parking/client.lua similarity index 96% rename from resources/[carscripts]/mh_Parking/client.lua rename to resources/[Developer]/mh_Parking/client.lua index 66ecd9eab..1ffe18c40 100644 --- a/resources/[carscripts]/mh_Parking/client.lua +++ b/resources/[Developer]/mh_Parking/client.lua @@ -1,210 +1,210 @@ -local enabled = true - -Citizen.CreateThread(function() - while (true) do - local playerPed = PlayerPedId() - if (DoesEntityExist(playerPed)) then - TriggerServerEvent("mh_Parking:syncPlayerPosition", GetEntityCoords(playerPed)) - end - - Citizen.Wait(3000) - end -end) - -Citizen.CreateThread(function() - while (true) do - Citizen.Wait(5 * 60 * 1000) - - local vehicle = GetVehiclePedIsIn(PlayerPedId()) - if (DoesEntityExist(vehicle)) then - TriggerEvent("mh_Parking:updateVehicle", vehicle) - end - end -end) - -Citizen.CreateThread(function() - Citizen.Wait(3000) - - local isInVehicle = false - local currentVehiclePlate = nil - local wasDead = false - - while (true) do - Citizen.Wait(50) - - local playerPed = PlayerPedId() - - if (not isInVehicle and IsPedInAnyVehicle(playerPed)) then - -- entered vehicle - - isInVehicle = true - - if (enabled) then - local vehicle = GetVehiclePedIsIn(playerPed, false) - if (NetworkGetEntityIsNetworked(vehicle) and not IsVehicleBlacklisted(vehicle)) then - local networkId = NetworkGetNetworkIdFromEntity(vehicle) - SetNetworkIdCanMigrate(netId, true) - local modifications = GetVehicleModifications(vehicle) - - currentVehiclePlate = GetVehicleNumberPlateText(vehicle) - - TriggerServerEvent("mh_Parking:enteredVehicle", networkId, currentVehiclePlate, modifications) - - Log("Vehicle " .. currentVehiclePlate .. " entered") - end - end - elseif (isInVehicle and not IsPedInAnyVehicle(playerPed, false)) then - -- left vehicle - - isInVehicle = false - - if (enabled and not wasDead) then - local vehicle = GetVehiclePedIsIn(playerPed, true) - - if (vehicle ~= 0) then - if (NetworkGetEntityIsNetworked(vehicle) and not IsVehicleBlacklisted(vehicle)) then - local networkId = NetworkGetNetworkIdFromEntity(vehicle) - SetNetworkIdCanMigrate(netId, true) - local modifications = GetVehicleModifications(vehicle) - - TriggerServerEvent("mh_Parking:leftVehicle", networkId, modifications) - - Log("Vehicle " .. GetVehicleNumberPlateText(vehicle) .. " left") - - -- if vehicle is deleted soon after - Citizen.CreateThread(function() - local veh = vehicle - local plate = GetVehicleNumberPlateText(veh) - local startTime = GetGameTimer() - local playerPed = PlayerPedId() - local playerPos - - while (true) do - Citizen.Wait(0) - - if (GetGameTimer() - startTime >= 1000) then - break - end - - if (not DoesEntityExist(veh)) then - TriggerServerEvent("mh_Parking:deleteVehicle", plate, false) - - Log("Vehicle " .. currentVehiclePlate .. " left and deleted after exit") - - currentVehiclePlate = nil - break - end - - playerPed = PlayerPedId() - playerPos = GetEntityCoords(playerPed) - vehPos = GetEntityCoords(veh) - - if (Vdist(playerPos.x, playerPos.y, playerPos.z, vehPos.x, vehPos.y, vehPos.z) > 50.0) then - currentVehiclePlate = nil - break - end - end - - currentVehiclePlate = nil - end) - end - elseif (currentVehiclePlate) then - TriggerServerEvent("mh_Parking:deleteVehicle", currentVehiclePlate, false) - - Log("Vehicle " .. currentVehiclePlate .. " left and deleted") - - currentVehiclePlate = nil - end - end - end - - if (not wasDead and IsPlayerDead(PlayerId())) then - wasDead = true - elseif (wasDead and not IsPlayerDead(PlayerId())) then - Citizen.CreateThread(function() - Citizen.Wait(1000) - - wasDead = false - end) - end - end -end) - -RegisterNetEvent("mh_Parking:setVehicleMods") -AddEventHandler("mh_Parking:setVehicleMods", function(netId, plate, modifications) - if (not IsModelInCdimage(modifications[1])) then - Log("Setting mods for " .. plate .. " failed. The model does NOT exist.") - TriggerServerEvent("mh_Parking:modelDoesNotExist", plate) - return - end - - local timer = GetGameTimer() - while (not NetworkDoesEntityExistWithNetworkId(netId)) do - Citizen.Wait(0) - - if (GetGameTimer() - 10000 > timer) then - Log("Setting mods for " .. plate .. " failed after 10s") - TriggerServerEvent("mh_Parking:setVehicleModsFailed", plate) - return - end - end - - local vehicle = NetworkGetEntityFromNetworkId(netId) - - if (DoesEntityExist(vehicle) and NetworkHasControlOfEntity(vehicle)) then - Log("Setting modifications for vehicle " .. plate) - - SetVehicleModifications(vehicle, plate, modifications) - TriggerServerEvent("mh_Parking:setVehicleModsSuccess", plate) - else - Log("Setting mods failed for vehicle " .. plate .. ". Vehicle does not exist") - TriggerServerEvent("mh_Parking:setVehicleModsFailed", plate) - end -end) - -AddEventHandler("mh_Parking:updateVehicle", function(vehicle) - if (vehicle == nil) then - Log("^1[ERROR] \"vehicle\" was nil while trying to update a vehicle!") - return - end - - if (DoesEntityExist(vehicle) and NetworkGetEntityIsNetworked(vehicle) and not IsVehicleBlacklisted(vehicle)) then - Log("Triggering manual update of vehicle") - - local networkId = NetworkGetNetworkIdFromEntity(vehicle) - local modifications = GetVehicleModifications(vehicle) - - TriggerServerEvent("mh_Parking:updateVehicle", networkId, modifications) - end -end) - -RegisterNetEvent("mh_Parking:enable") -AddEventHandler("mh_Parking:enable", function(enable) - if (enable == nil) then - Log("^1[ERROR] \"enable\" was nil while trying to enable/disable script!") - return - end - - enabled = enable - - if (enabled) then - Log("AdvancedParking enabled") - else - Log("AdvancedParking disabled") - end -end) - -RegisterNetEvent("mh_Parking:notification") -AddEventHandler("mh_Parking:notification", function(msg) - SetNotificationTextEntry('STRING') - AddTextComponentSubstringPlayerName(msg) - DrawNotification(false, true) -end) - -RegisterNetEvent("mh_Parking:renderScorched") -AddEventHandler("mh_Parking:renderScorched", function(vehicleNetId, scorched) - local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId) - if (DoesEntityExist(vehicle)) then - SetEntityRenderScorched(vehicle, scorched) - end -end) +local enabled = true + +Citizen.CreateThread(function() + while (true) do + local playerPed = PlayerPedId() + if (DoesEntityExist(playerPed)) then + TriggerServerEvent("mh_Parking:syncPlayerPosition", GetEntityCoords(playerPed)) + end + + Citizen.Wait(3000) + end +end) + +Citizen.CreateThread(function() + while (true) do + Citizen.Wait(5 * 60 * 1000) + + local vehicle = GetVehiclePedIsIn(PlayerPedId()) + if (DoesEntityExist(vehicle)) then + TriggerEvent("mh_Parking:updateVehicle", vehicle) + end + end +end) + +Citizen.CreateThread(function() + Citizen.Wait(3000) + + local isInVehicle = false + local currentVehiclePlate = nil + local wasDead = false + + while (true) do + Citizen.Wait(50) + + local playerPed = PlayerPedId() + + if (not isInVehicle and IsPedInAnyVehicle(playerPed)) then + -- entered vehicle + + isInVehicle = true + + if (enabled) then + local vehicle = GetVehiclePedIsIn(playerPed, false) + if (NetworkGetEntityIsNetworked(vehicle) and not IsVehicleBlacklisted(vehicle)) then + local networkId = NetworkGetNetworkIdFromEntity(vehicle) + SetNetworkIdCanMigrate(netId, true) + local modifications = GetVehicleModifications(vehicle) + + currentVehiclePlate = GetVehicleNumberPlateText(vehicle) + + TriggerServerEvent("mh_Parking:enteredVehicle", networkId, currentVehiclePlate, modifications) + + Log("Vehicle " .. currentVehiclePlate .. " entered") + end + end + elseif (isInVehicle and not IsPedInAnyVehicle(playerPed, false)) then + -- left vehicle + + isInVehicle = false + + if (enabled and not wasDead) then + local vehicle = GetVehiclePedIsIn(playerPed, true) + + if (vehicle ~= 0) then + if (NetworkGetEntityIsNetworked(vehicle) and not IsVehicleBlacklisted(vehicle)) then + local networkId = NetworkGetNetworkIdFromEntity(vehicle) + SetNetworkIdCanMigrate(netId, true) + local modifications = GetVehicleModifications(vehicle) + + TriggerServerEvent("mh_Parking:leftVehicle", networkId, modifications) + + Log("Vehicle " .. GetVehicleNumberPlateText(vehicle) .. " left") + + -- if vehicle is deleted soon after + Citizen.CreateThread(function() + local veh = vehicle + local plate = GetVehicleNumberPlateText(veh) + local startTime = GetGameTimer() + local playerPed = PlayerPedId() + local playerPos + + while (true) do + Citizen.Wait(0) + + if (GetGameTimer() - startTime >= 1000) then + break + end + + if (not DoesEntityExist(veh)) then + TriggerServerEvent("mh_Parking:deleteVehicle", plate, false) + + Log("Vehicle " .. currentVehiclePlate .. " left and deleted after exit") + + currentVehiclePlate = nil + break + end + + playerPed = PlayerPedId() + playerPos = GetEntityCoords(playerPed) + vehPos = GetEntityCoords(veh) + + if (Vdist(playerPos.x, playerPos.y, playerPos.z, vehPos.x, vehPos.y, vehPos.z) > 50.0) then + currentVehiclePlate = nil + break + end + end + + currentVehiclePlate = nil + end) + end + elseif (currentVehiclePlate) then + TriggerServerEvent("mh_Parking:deleteVehicle", currentVehiclePlate, false) + + Log("Vehicle " .. currentVehiclePlate .. " left and deleted") + + currentVehiclePlate = nil + end + end + end + + if (not wasDead and IsPlayerDead(PlayerId())) then + wasDead = true + elseif (wasDead and not IsPlayerDead(PlayerId())) then + Citizen.CreateThread(function() + Citizen.Wait(1000) + + wasDead = false + end) + end + end +end) + +RegisterNetEvent("mh_Parking:setVehicleMods") +AddEventHandler("mh_Parking:setVehicleMods", function(netId, plate, modifications) + if (not IsModelInCdimage(modifications[1])) then + Log("Setting mods for " .. plate .. " failed. The model does NOT exist.") + TriggerServerEvent("mh_Parking:modelDoesNotExist", plate) + return + end + + local timer = GetGameTimer() + while (not NetworkDoesEntityExistWithNetworkId(netId)) do + Citizen.Wait(0) + + if (GetGameTimer() - 10000 > timer) then + Log("Setting mods for " .. plate .. " failed after 10s") + TriggerServerEvent("mh_Parking:setVehicleModsFailed", plate) + return + end + end + + local vehicle = NetworkGetEntityFromNetworkId(netId) + + if (DoesEntityExist(vehicle) and NetworkHasControlOfEntity(vehicle)) then + Log("Setting modifications for vehicle " .. plate) + + SetVehicleModifications(vehicle, plate, modifications) + TriggerServerEvent("mh_Parking:setVehicleModsSuccess", plate) + else + Log("Setting mods failed for vehicle " .. plate .. ". Vehicle does not exist") + TriggerServerEvent("mh_Parking:setVehicleModsFailed", plate) + end +end) + +AddEventHandler("mh_Parking:updateVehicle", function(vehicle) + if (vehicle == nil) then + Log("^1[ERROR] \"vehicle\" was nil while trying to update a vehicle!") + return + end + + if (DoesEntityExist(vehicle) and NetworkGetEntityIsNetworked(vehicle) and not IsVehicleBlacklisted(vehicle)) then + Log("Triggering manual update of vehicle") + + local networkId = NetworkGetNetworkIdFromEntity(vehicle) + local modifications = GetVehicleModifications(vehicle) + + TriggerServerEvent("mh_Parking:updateVehicle", networkId, modifications) + end +end) + +RegisterNetEvent("mh_Parking:enable") +AddEventHandler("mh_Parking:enable", function(enable) + if (enable == nil) then + Log("^1[ERROR] \"enable\" was nil while trying to enable/disable script!") + return + end + + enabled = enable + + if (enabled) then + Log("AdvancedParking enabled") + else + Log("AdvancedParking disabled") + end +end) + +RegisterNetEvent("mh_Parking:notification") +AddEventHandler("mh_Parking:notification", function(msg) + SetNotificationTextEntry('STRING') + AddTextComponentSubstringPlayerName(msg) + DrawNotification(false, true) +end) + +RegisterNetEvent("mh_Parking:renderScorched") +AddEventHandler("mh_Parking:renderScorched", function(vehicleNetId, scorched) + local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId) + if (DoesEntityExist(vehicle)) then + SetEntityRenderScorched(vehicle, scorched) + end +end) diff --git a/resources/[carscripts]/mh_Parking/config.lua b/resources/[Developer]/mh_Parking/config.lua similarity index 97% rename from resources/[carscripts]/mh_Parking/config.lua rename to resources/[Developer]/mh_Parking/config.lua index 0348907ed..a3afe04e8 100644 --- a/resources/[carscripts]/mh_Parking/config.lua +++ b/resources/[Developer]/mh_Parking/config.lua @@ -1,64 +1,64 @@ -Config = {} - -Config.exports = "lc_fuel" -- LegacyFuel - --- set this to true if you want to see debug messages on client and server side -Config.isDebug = false - --- this controls the distance at which vehicles will spawn to the closest player --- (in meters) -Config.spawnDistance = 200.0 - --- this controls when a vehicle will be removed from the database table when --- calling the cleanup function (in hours; so 24 * 7 = one week) -Config.cleanUpThresholdTime = 24 * 7 - --- set this to false if you do not want entities render as scorched when they --- are completely broken -Config.renderScorched = true - --- vehicle classes that you do not want to save go here (remove the -- in front --- of the number if you want it blacklisted) -Config.classesBlacklist = { - -- 0, -- Compacts - -- 1, -- Sedans - -- 2, -- SUVs - -- 3, -- Coupes - -- 4, -- Muscle - -- 5, -- Sports Classics - -- 6, -- Sports - -- 7, -- Super - -- 8, -- Motorcycles - -- 9, -- Off-road - --10, -- Industrial - --11, -- Utility - --12, -- Vans - --13, -- Cycles - --14, -- Boats - --15, -- Helicopters - --16, -- Planes - --17, -- Service - --18, -- Emergency - --19, -- Military - --20, -- Commercial - 21, -- Trains -} --- other vehicles that you do not want to save can be inserted here (use `MODELNAME` --- when you put them in there) -Config.vehiclesBlacklist = { - --`blista`, -} - --- this lets you control if vehicles should be deleted (in minutes; 0 if you do not --- want to use it; this is useful for large servers with a lot of players) -Config.deleteTimer = 0 --- despawns all vehicles that are more than x meters away from a player -Config.deleteDistance = 25.0 --- when the notifications should be shown before the despawning --- needs to be in descending order in minutes and lower than Config.deleteTimer -Config.deleteNotificationTimes = { 5, 3, 2, 1 } --- notification to show players before deleting vehicles --- (use %s as placeholder for time left in minutes) -Config.timeLeftNotification = "Fahrzeuge Despawn in %s Minuten." --- notification to show players when deleting vehicles -Config.deleteNotification = "Lösche Fahrzeuge..." +Config = {} + +Config.exports = "lc_fuel" -- LegacyFuel + +-- set this to true if you want to see debug messages on client and server side +Config.isDebug = false + +-- this controls the distance at which vehicles will spawn to the closest player +-- (in meters) +Config.spawnDistance = 200.0 + +-- this controls when a vehicle will be removed from the database table when +-- calling the cleanup function (in hours; so 24 * 7 = one week) +Config.cleanUpThresholdTime = 24 * 7 + +-- set this to false if you do not want entities render as scorched when they +-- are completely broken +Config.renderScorched = true + +-- vehicle classes that you do not want to save go here (remove the -- in front +-- of the number if you want it blacklisted) +Config.classesBlacklist = { + -- 0, -- Compacts + -- 1, -- Sedans + -- 2, -- SUVs + -- 3, -- Coupes + -- 4, -- Muscle + -- 5, -- Sports Classics + -- 6, -- Sports + -- 7, -- Super + -- 8, -- Motorcycles + -- 9, -- Off-road + --10, -- Industrial + --11, -- Utility + --12, -- Vans + --13, -- Cycles + --14, -- Boats + --15, -- Helicopters + --16, -- Planes + --17, -- Service + --18, -- Emergency + --19, -- Military + --20, -- Commercial + 21, -- Trains +} +-- other vehicles that you do not want to save can be inserted here (use `MODELNAME` +-- when you put them in there) +Config.vehiclesBlacklist = { + --`blista`, +} + +-- this lets you control if vehicles should be deleted (in minutes; 0 if you do not +-- want to use it; this is useful for large servers with a lot of players) +Config.deleteTimer = 0 +-- despawns all vehicles that are more than x meters away from a player +Config.deleteDistance = 25.0 +-- when the notifications should be shown before the despawning +-- needs to be in descending order in minutes and lower than Config.deleteTimer +Config.deleteNotificationTimes = { 5, 3, 2, 1 } +-- notification to show players before deleting vehicles +-- (use %s as placeholder for time left in minutes) +Config.timeLeftNotification = "Fahrzeuge Despawn in %s Minuten." +-- notification to show players when deleting vehicles +Config.deleteNotification = "Lösche Fahrzeuge..." diff --git a/resources/[carscripts]/mh_Parking/fxmanifest.lua b/resources/[Developer]/mh_Parking/fxmanifest.lua similarity index 93% rename from resources/[carscripts]/mh_Parking/fxmanifest.lua rename to resources/[Developer]/mh_Parking/fxmanifest.lua index 4a3a6e3ce..b582ae591 100644 --- a/resources/[carscripts]/mh_Parking/fxmanifest.lua +++ b/resources/[Developer]/mh_Parking/fxmanifest.lua @@ -1,24 +1,24 @@ -fx_version 'cerulean' -games { 'gta5' } - -author 'Mîhó' -description 'Park all your vehicles anywhere!' -version '1.0.0' - -server_scripts { - '@oxmysql/lib/MySQL.lua', - 'config.lua', - 'sv_utils.lua', - 'server.lua' -} - -client_scripts { - 'config.lua', - 'cl_utils.lua', - 'client.lua' -} - -exports { - 'GetVehiclePosition', - 'GetVehiclePositions' -} +fx_version 'cerulean' +games { 'gta5' } + +author 'Mîhó' +description 'Park all your vehicles anywhere!' +version '1.0.0' + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'config.lua', + 'sv_utils.lua', + 'server.lua' +} + +client_scripts { + 'config.lua', + 'cl_utils.lua', + 'client.lua' +} + +exports { + 'GetVehiclePosition', + 'GetVehiclePositions' +} diff --git a/resources/[carscripts]/mh_Parking/mh_Parking.sql b/resources/[Developer]/mh_Parking/mh_Parking.sql similarity index 97% rename from resources/[carscripts]/mh_Parking/mh_Parking.sql rename to resources/[Developer]/mh_Parking/mh_Parking.sql index 916601482..1817779d8 100644 --- a/resources/[carscripts]/mh_Parking/mh_Parking.sql +++ b/resources/[Developer]/mh_Parking/mh_Parking.sql @@ -1,32 +1,32 @@ --- -------------------------------------------------------- --- Host: 127.0.0.1 --- Server version: 10.1.28-MariaDB - mariadb.org binary distribution --- Server OS: Win32 --- HeidiSQL Version: 11.0.0.5919 --- -------------------------------------------------------- - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET NAMES utf8 */; -/*!50503 SET NAMES utf8mb4 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; - --- Dumping structure for table fivem_testserver.vehicle_parking -CREATE TABLE IF NOT EXISTS `vehicle_parking` ( - `plate` varchar(8) NOT NULL, - `modifications` text NOT NULL, - `posX` float NOT NULL, - `posY` float NOT NULL, - `posZ` float NOT NULL, - `rotX` float NOT NULL, - `rotY` float NOT NULL, - `rotZ` float NOT NULL, - `lastUpdate` int(11) NOT NULL DEFAULT '0', - PRIMARY KEY (`plate`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- Data exporting was unselected. - -/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; -/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +-- -------------------------------------------------------- +-- Host: 127.0.0.1 +-- Server version: 10.1.28-MariaDB - mariadb.org binary distribution +-- Server OS: Win32 +-- HeidiSQL Version: 11.0.0.5919 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +-- Dumping structure for table fivem_testserver.vehicle_parking +CREATE TABLE IF NOT EXISTS `vehicle_parking` ( + `plate` varchar(8) NOT NULL, + `modifications` text NOT NULL, + `posX` float NOT NULL, + `posY` float NOT NULL, + `posZ` float NOT NULL, + `rotX` float NOT NULL, + `rotY` float NOT NULL, + `rotZ` float NOT NULL, + `lastUpdate` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`plate`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Data exporting was unselected. + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/resources/[carscripts]/mh_Parking/server.lua b/resources/[Developer]/mh_Parking/server.lua similarity index 97% rename from resources/[carscripts]/mh_Parking/server.lua rename to resources/[Developer]/mh_Parking/server.lua index 4ae686fe0..3fc6d85a5 100644 --- a/resources/[carscripts]/mh_Parking/server.lua +++ b/resources/[Developer]/mh_Parking/server.lua @@ -1,770 +1,770 @@ -local vehicles = {} -local DB_vehicles = {} - --- Command to delete ALL vehicles from the database table. Needs to be executed twice for security reason. -local deleteSavedVehicles = false -RegisterCommand("deleteSavedVehicles", function(source, args, raw) - if (deleteSavedVehicles) then - MySQL.query("DELETE FROM vehicle_parking", { }) - - vehicles = {} - - Log("Deleted all vehicles from the vehicle_parking table.") - else - Log("Are you sure that you want to delete all vehicles from the parking list?\nIf yes, type the command a second time!") - end - - deleteSavedVehicles = not deleteSavedVehicles -end, true) - --- read all vehicles from the database on startup and do a cleanup check -MySQL.ready(function() - -- fetch all database results - MySQL.query("SELECT plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate FROM vehicle_parking", {}, function(results) - Log("Found " .. #results .. " saved vehicles in vehicle_parking.") - - for i = 1, #results do - vehicles[results[i].plate] = { - handle = nil, - position = vector3(results[i].posX, results[i].posY, results[i].posZ), - rotation = vector3(results[i].rotX, results[i].rotY, results[i].rotZ), - modifications = json.decode(results[i].modifications), - lastUpdate = results[i].lastUpdate, - spawning = false, - spawningPlayer = nil, - faultyModel = false - } - end - - --CleanUp() - end) -end) - --- Default CleanUp function. Deletes vehicles from the database after a specific amount of time has passed (configurable in config) -function CleanUp() - local currentTime = os.time() - local threshold = 60 * 60 * Config.cleanUpThresholdTime - - local toDelete = {} - - for plate, vehicle in pairs(vehicles) do - if (vehicle.lastUpdate < os.difftime(currentTime, threshold)) then - - MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate", - { - ["@plate"] = plate - }) - - table.insert(toDelete, plate) - end - end - - for i = 1, #toDelete, 1 do - local plate = toDelete[i] - vehicles[plate] = nil - end - - Log("CleanUp complete. Deleted " .. #toDelete .. " entries.") -end - - - --- loop to spawn vehicles near players -Citizen.CreateThread(function() - while (true) do - Citizen.Wait(5000) - - if (GetActivePlayerCount() > 0) then - TrySpawnVehicles() - end - end -end) - -Citizen.CreateThread(function() - while (true) do - CallDB_Vehicles() - Citizen.Wait(60000 * 5) - end -end) - --- loop to delete vehicles -Citizen.CreateThread(function() - if (Config.deleteTimer <= 0) then - return - end - - while (true) do - Citizen.Wait(60000 * (Config.deleteTimer - Config.deleteNotificationTimes[1])) - - TriggerClientEvent("mh_Parking:notification", -1, string.format(Config.timeLeftNotification, Config.deleteNotificationTimes[1])) - for i = 2, #Config.deleteNotificationTimes, 1 do - Citizen.Wait(60000 * (Config.deleteNotificationTimes[i - 1] - Config.deleteNotificationTimes[i])) - TriggerClientEvent("mh_Parking:notification", -1, string.format(Config.timeLeftNotification, Config.deleteNotificationTimes[i])) - end - Citizen.Wait(60000 * Config.deleteNotificationTimes[#Config.deleteNotificationTimes]) - - DeleteAllVehicles() - end -end) - - - --- sync player position -RegisterServerEvent("mh_Parking:syncPlayerPosition") -AddEventHandler("mh_Parking:syncPlayerPosition", function(position) - activePlayerPositions[source] = position -end) - --- player disconnected -AddEventHandler("playerDropped", function(disconnectReason) - activePlayerPositions[source] = nil -end) - --- player entered a vehicle -RegisterServerEvent("mh_Parking:enteredVehicle") -AddEventHandler("mh_Parking:enteredVehicle", function(networkId, plate, modifications) - local vehicle = NetworkGetEntityFromNetworkId(networkId) - - if (DoesEntityExist(vehicle)) then - local currentTime = os.time() - - local position = GetEntityCoords(vehicle) - position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0) - local rotation = GetEntityRotation(vehicle) - rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0) - - if (vehicles[plate]) then - -- already on server list - - Log("Entered vehicle " .. plate .. ". Updating...") - - if (vehicles[plate].handle ~= vehicle) then - if (DoesEntityExist(vehicles[plate].handle)) then - DeleteEntity(vehicles[plate].handle) - end - - vehicles[plate].handle = vehicle - end - - vehicles[plate].position = position - vehicles[plate].rotation = rotation - vehicles[plate].modifications = modifications - vehicles[plate].lastUpdate = currentTime - - MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate", { - ["@plate"] = plate, - ["@posX"] = vehicles[plate].position.x, - ["@posY"] = vehicles[plate].position.y, - ["@posZ"] = vehicles[plate].position.z, - ["@rotX"] = vehicles[plate].rotation.x, - ["@rotY"] = vehicles[plate].rotation.y, - ["@rotZ"] = vehicles[plate].rotation.z, - ["@modifications"] = json.encode(vehicles[plate].modifications), - ["@lastUpdate"] = vehicles[plate].lastUpdate - }) - else - -- insert in db - - Log("Entered vehicle " .. plate .. ". Inserting new...") - - vehicles[plate] = { - handle = vehicle, - position = position, - rotation = rotation, - modifications = modifications, - lastUpdate = currentTime, - spawning = false, - spawningPlayer = nil - } - - MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs) - Log(json.encode(rs)) - if rs[1] then - Log("FOUND OWNER FROM VEHICLE") - - MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)", { - ["@plate"] = plate, - ["@posX"] = vehicles[plate].position.x, - ["@posY"] = vehicles[plate].position.y, - ["@posZ"] = vehicles[plate].position.z, - ["@rotX"] = vehicles[plate].rotation.x, - ["@rotY"] = vehicles[plate].rotation.y, - ["@rotZ"] = vehicles[plate].rotation.z, - ["@modifications"] = json.encode(vehicles[plate].modifications), - ["@lastUpdate"] = vehicles[plate].lastUpdate - }) - else - Log("1: NO VEHICLE FOUND") - end - end) - end - else - Log("Vehicle does not exist. Might be a Onesync error.") - end -end) - --- player left a vehicle -RegisterServerEvent("mh_Parking:leftVehicle") -AddEventHandler("mh_Parking:leftVehicle", function(networkId, modifications) - local vehicle = NetworkGetEntityFromNetworkId(networkId) - - if (DoesEntityExist(vehicle)) then - local currentTime = os.time() - - local plate = GetVehicleNumberPlateText(vehicle) - - local position = GetEntityCoords(vehicle) - position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0) - local rotation = GetEntityRotation(vehicle) - rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0) - - if (vehicles[plate]) then - -- already on server list - - Log("Left vehicle " .. plate .. ". Updating...") - - if (vehicles[plate].handle ~= vehicle) then - if (DoesEntityExist(vehicles[plate].handle)) then - DeleteEntity(vehicles[plate].handle) - end - - vehicles[plate].handle = vehicle - end - - vehicles[plate].position = position - vehicles[plate].rotation = rotation - vehicles[plate].modifications = modifications - vehicles[plate].lastUpdate = currentTime - - MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate",{ - ["@plate"] = plate, - ["@posX"] = vehicles[plate].position.x, - ["@posY"] = vehicles[plate].position.y, - ["@posZ"] = vehicles[plate].position.z, - ["@rotX"] = vehicles[plate].rotation.x, - ["@rotY"] = vehicles[plate].rotation.y, - ["@rotZ"] = vehicles[plate].rotation.z, - ["@modifications"] = json.encode(vehicles[plate].modifications), - ["@lastUpdate"] = currentTime - }) - else - -- insert in db - - Log("Left vehicle " .. plate .. ". Inserting new...") - - vehicles[plate] = { - handle = vehicle, - position = position, - rotation = rotation, - modifications = modifications, - lastUpdate = currentTime, - spawning = false, - spawningPlayer = nil - } - - MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs) - if rs[1] then - Log("FOUND OWNER FROM VEHICLE") - - MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)",{ - ["@plate"] = plate, - ["@posX"] = vehicles[plate].position.x, - ["@posY"] = vehicles[plate].position.y, - ["@posZ"] = vehicles[plate].position.z, - ["@rotX"] = vehicles[plate].rotation.x, - ["@rotY"] = vehicles[plate].rotation.y, - ["@rotZ"] = vehicles[plate].rotation.z, - ["@modifications"] = json.encode(vehicles[plate].modifications), - ["@lastUpdate"] = vehicles[plate].lastUpdate - }) - else - Log("2: NO VEHICLE FOUND") - end - end) - end - end -end) - --- update a vehicle with its modifications -RegisterServerEvent("mh_Parking:updateVehicle") -AddEventHandler("mh_Parking:updateVehicle", function(networkId, modifications) - local vehicle = NetworkGetEntityFromNetworkId(networkId) - - if (DoesEntityExist(vehicle)) then - local currentTime = os.time() - - local plate = GetVehicleNumberPlateText(vehicle) - - local position = GetEntityCoords(vehicle) - position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0) - local rotation = GetEntityRotation(vehicle) - rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0) - - if (vehicles[plate] ~= nil) then - -- already on server list - - Log("Updating vehicle " .. plate) - - if (vehicles[plate].handle ~= vehicle) then - if (DoesEntityExist(vehicles[plate].handle)) then - DeleteEntity(vehicles[plate].handle) - end - - vehicles[plate].handle = vehicle - end - - vehicles[plate].position = position - vehicles[plate].rotation = rotation - vehicles[plate].modifications = modifications - vehicles[plate].lastUpdate = currentTime - - MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate",{ - ["@plate"] = plate, - ["@posX"] = vehicles[plate].position.x, - ["@posY"] = vehicles[plate].position.y, - ["@posZ"] = vehicles[plate].position.z, - ["@rotX"] = vehicles[plate].rotation.x, - ["@rotY"] = vehicles[plate].rotation.y, - ["@rotZ"] = vehicles[plate].rotation.z, - ["@modifications"] = json.encode(vehicles[plate].modifications), - ["@lastUpdate"] = vehicles[plate].lastUpdate - }) - else - -- insert in db - - Log("Updating vehicle " .. plate .. ". Inserting new...") - - vehicles[plate] = { - handle = vehicle, - position = position, - rotation = rotation, - modifications = modifications, - lastUpdate = currentTime, - spawning = false, - spawningPlayer = nil - } - - MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs) - if rs[1] then - Log("FOUND OWNER FROM VEHICLE") - - MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)",{ - ["@plate"] = plate, - ["@posX"] = vehicles[plate].position.x, - ["@posY"] = vehicles[plate].position.y, - ["@posZ"] = vehicles[plate].position.z, - ["@rotX"] = vehicles[plate].rotation.x, - ["@rotY"] = vehicles[plate].rotation.y, - ["@rotZ"] = vehicles[plate].rotation.z, - ["@modifications"] = json.encode(vehicles[plate].modifications), - ["@lastUpdate"] = vehicles[plate].lastUpdate - }) - else - Log("3: NO VEHICLE FOUND") - end - end) - end - end -end) - --- delete a vehicle from the table (and world) with its plate -RegisterServerEvent("mh_Parking:deleteVehicle") -AddEventHandler("mh_Parking:deleteVehicle", function(plate, deleteEntity) - if (plate == nil) then - Log("^1mh_Parking: \"plate\" was nil while trying to delete vehicle!") - return - end - - Log("Trying to delete " .. tostring(plate)) - - if (vehicles[plate] ~= nil) then - if (deleteEntity and DoesEntityExist(vehicles[plate].handle)) then - DeleteEntity(vehicles[plate].handle) - end - - vehicles[plate] = nil - - MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate", - { - ["@plate"] = plate - }) - else - local loadedVehicles = GetAllVehicles() - local loadedVehicle = TryGetLoadedVehicle(plate, loadedVehicles) - - if (loadedVehicle ~= nil) then - if (deleteEntity and DoesEntityExist(loadedVehicle)) then - DeleteEntity(loadedVehicle) - end - - MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate", - { - ["@plate"] = plate - }) - end - end -end) - --- checks if vehicles have to be spawned and spawns them if necessary -function TrySpawnVehicles() - local loadedVehicles = GetAllVehicles() - - local playerVehiclePlates = {} - for id, position in pairs(activePlayerPositions) do - local ped = GetPlayerPed(id) - local veh = GetVehiclePedIsIn(ped, false) - - if (DoesEntityExist(veh)) then - table.insert(playerVehiclePlates, GetVehicleNumberPlateText(veh)) - end - end - - -- check, if vehicles need to be spawned - for plate, vehicleData in pairs(vehicles) do - local plateCheck = CheckPlate(plate) - if (plateCheck ~= false) then - - if (not vehicleData.faultyModel) then - if (not vehicleData.spawning) then - local closestPlayer, dist = GetClosestPlayerId(vehicleData.position) - - if (closestPlayer ~= nil and dist < Config.spawnDistance and not ContainsPlate(plate, playerVehiclePlates)) then - if (vehicleData.handle ~= nil and DoesEntityExist(vehicleData.handle)) then - -- vehicle found on server side - - UpdateVehicle(plate) - else - -- vehicle not found on server side - -- check, if it is loaded differently - - local loadedVehicle = TryGetLoadedVehicle(plate, loadedVehicles) - if (loadedVehicle ~= nil) then - -- vehicle found - - vehicleData.handle = loadedVehicle - - UpdateVehicle(plate) - else - -- vehicle not found - -- try and spawn it - - local playerId, distance = GetClosestPlayerId(vehicleData.position) - if (playerId and distance < Config.spawnDistance) then - vehicleData.spawning = true - - Citizen.CreateThread(function() - local vec4 = vector4(vehicleData.position.x, vehicleData.position.y, vehicleData.position.z, vehicleData.rotation.z) - local vehicle = Citizen.InvokeNative(GetHashKey("CREATE_AUTOMOBILE"), vehicleData.modifications[1], vec4.xyzw) - - while (not DoesEntityExist(vehicle)) do - Citizen.Wait(0) - end - - SetEntityCoords(vehicle, vehicleData.position.x, vehicleData.position.y, vehicleData.position.z) - SetEntityRotation(vehicle, vehicleData.rotation.x, vehicleData.rotation.y, vehicleData.rotation.z) - - vehicleData.handle = vehicle - - local networkOwner = -1 - while (networkOwner == -1) do - Citizen.Wait(0) - networkOwner = NetworkGetEntityOwner(vehicleData.handle) - end - - vehicleData.spawningPlayer = GetPlayerIdentifiersSorted(networkOwner)["license"] - - Log("Creating vehicle " .. plate .. " at " .. tostring(vehicleData.position) .. " at entity owner " .. tostring(networkOwner)) - - TriggerClientEvent("mh_Parking:setVehicleMods", networkOwner, NetworkGetNetworkIdFromEntity(vehicleData.handle), plate, vehicleData.modifications) - end) - end - end - end - end - elseif (vehicleData.spawningPlayer) then - -- if vehicle is currently spawning check if responsible player is still connected - if (not IsPlayerWithLicenseActive(vehicleData.spawningPlayer)) then - TriggerEvent("mh_Parking:setVehicleModsFailed", plate) - end - end - end - end - end -end - -RegisterServerEvent("mh_Parking:setVehicleModsSuccess") -AddEventHandler("mh_Parking:setVehicleModsSuccess", function(plate) - Log("Setting mods successful...") - - if (vehicles[plate]) then - vehicles[plate].spawning = false - vehicles[plate].spawningPlayer = nil - end -end) - -RegisterServerEvent("mh_Parking:setVehicleModsFailed") -AddEventHandler("mh_Parking:setVehicleModsFailed", function(plate) - Log("Setting mods for " .. plate .. " failed... retrying...") - - if (vehicles[plate] and vehicles[plate].handle and DoesEntityExist(vehicles[plate].handle)) then - local networkOwner = -1 - while (networkOwner == -1) do - Citizen.Wait(0) - networkOwner = NetworkGetEntityOwner(vehicles[plate].handle) - end - - local netOwnerLicense = GetPlayerIdentifiersSorted(networkOwner)["license"] - if (netOwnerLicense ~= nil) then - vehicles[plate].spawningPlayer = GetPlayerIdentifiersSorted(networkOwner)["license"] - - TriggerClientEvent("mh_Parking:setVehicleMods", networkOwner, NetworkGetNetworkIdFromEntity(vehicles[plate].handle), plate, vehicles[plate].modifications) - else - Log("Something went wrong while trying to get player license for spawning vehicle " .. tostring(plate) .. ". Despawning vehicle") - - DeleteEntity(vehicles[plate].handle) - - vehicles[plate].handle = nil - vehicles[plate].spawningPlayer = nil - vehicles[plate].spawning = false - end - end -end) - -RegisterServerEvent("mh_Parking:modelDoesNotExist") -AddEventHandler("mh_Parking:modelDoesNotExist", function(plate) - if (vehicles[plate] == nil) then - return - end - - if (DoesEntityExist(vehicles[plate].handle)) then - DeleteEntity(vehicles[plate].handle) - end - vehicles[plate].handle = nil - vehicles[plate].spawningPlayer = nil - vehicles[plate].spawning = false - - Log("The model for vehicle " .. tostring(plate) .. " does not exist. Removing from spawn pool...") - - vehicles[plate].faultyModel = true -end) - -RegisterServerEvent("mh_Parking:updatePlate") -AddEventHandler("mh_Parking:updatePlate", function(oldPlate, newPlate) - if (oldPlate == nil or newPlate == nil) then - Log("^1mh_Parking: \"oldPlate\" or \"newPlate\" was nil while trying to update a plate!") - return - end - - if (vehicles[oldPlate]) then - if (vehicles[newPlate]) then - Log("Updating plate failed. New plate was already there!") - else - vehicles[newPlate] = vehicles[oldPlate] - vehicles[oldPlate] = nil - - Log("Updating plate successful!") - - MySQL.query("UPDATE vehicle_parking SET plate = @newPlate WHERE plate = @oldPlate", - { - ["@newPlate"] = newPlate, - ["@oldPlate"] = oldPlate - }) - end - else - Log("Updating plate failed or unnecessary. Old plate was not found!") - end -end) - -function UpdateVehicle(plate) - local newPos = GetEntityCoords(vehicles[plate].handle) - local newRot = GetEntityRotation(vehicles[plate].handle) - newPos = vector3(math.floor(newPos.x * 100.0) * 0.01, math.floor(newPos.y * 100.0) * 0.01, math.floor(newPos.z * 100.0) * 0.01) - newRot = vector3(math.floor(newRot.x * 100.0) * 0.01, math.floor(newRot.y * 100.0) * 0.01, math.floor(newRot.z * 100.0) * 0.01) - - local newLockStatus = GetVehicleDoorLockStatus(vehicles[plate].handle) - local newEngineHealth = math.floor(GetVehicleEngineHealth(vehicles[plate].handle) * 10.0) * 0.1 - local newTankHealth = math.floor(GetVehiclePetrolTankHealth(vehicles[plate].handle) * 10.0) * 0.1 - if (Vector3DistFast(vehicles[plate].position, newPos) > 1.0 - or GetRotationDifference(vehicles[plate].rotation, newRot) > 15.0 - or newLockStatus ~= vehicles[plate].modifications[2] - or math.abs(newEngineHealth - vehicles[plate].modifications[5]) > 5.0 - or math.abs(newTankHealth - vehicles[plate].modifications[6]) > 5.0 - ) then - vehicles[plate].modifications[2] = newLockStatus - vehicles[plate].modifications[5] = newEngineHealth - vehicles[plate].modifications[6] = newTankHealth - - Log("Updating vehicle " .. plate) - - vehicles[plate].position = newPos - vehicles[plate].rotation = newRot - - MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications WHERE plate = @plate", - { - ["@posX"] = vehicles[plate].position.x, - ["@posY"] = vehicles[plate].position.y, - ["@posZ"] = vehicles[plate].position.z, - ["@rotX"] = vehicles[plate].rotation.x, - ["@rotY"] = vehicles[plate].rotation.y, - ["@rotZ"] = vehicles[plate].rotation.z, - ["@modifications"] = json.encode(vehicles[plate].modifications), - ["@plate"] = plate - }) - end -end - -function DeleteAllVehicles() - TriggerClientEvent("mh_Parking:notification", -1, Config.deleteNotification) - - local peds = GetAllPeds() - local playerPeds = {} - for i = 1, #peds, 1 do - if (IsPedAPlayer(peds[i])) then - table.insert(playerPeds, peds[i]) - end - end - - if (#playerPeds == 0) then - return - end - - local time = GetGameTimer() - - local vehs = GetAllVehicles() - local deleted = 0 - for i = 1, #vehs, 1 do - if (not IsAnyPlayerInsideVehicle(vehs[i], playerPeds)) then - local closestPlayer, distance = GetClosestPlayerPed(GetEntityCoords(vehs[i]), playerPeds) - if (closestPlayer ~= nil and distance > Config.deleteDistance) then - local plate = GetVehicleNumberPlateText(vehs[i]) - if (vehicles[plate] ~= nil) then - vehicles[plate] = nil - - MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate", - { - ["@plate"] = plate - }) - end - - DeleteEntity(vehs[i]) - - deleted = deleted + 1 - end - end - end - - Log("Deleted " .. tostring(deleted) .. "/" .. tostring(#vehs) .. " vehicles. Took " .. tostring((GetGameTimer() - time) / 1000.0) .. "sec") -end - -AddEventHandler("onResourceStop", function(name) - if (name ~= GetCurrentResourceName()) then - return - end - - -- delete vehicles that are still being spawned before actually stopping the resource - for plate, vehicleData in pairs(vehicles) do - if (vehicleData.spawning and DoesEntityExist(vehicleData.handle)) then - DeleteEntity(vehicleData.handle) - end - end -end) - --- render entity scorched (trigger with netid of the vehicle and false when repairing) -RegisterServerEvent("mh_Parking:renderScorched") -AddEventHandler("mh_Parking:renderScorched", function(vehicleNetId, scorched) - local vehicleHandle = NetworkGetEntityFromNetworkId(vehicleNetId) - if (DoesEntityExist(vehicleHandle)) then - TriggerClientEvent("mh_Parking:renderScorched", -1, vehicleNetId, scorched) - end -end) - -if (GetResourceState("kimi_callbacks") == "started") then - exports["kimi_callbacks"]:Register("AP:getVehiclePosition", function(source, plate) - local vehs = GetAllVehicles() - - for i, veh in ipairs(vehs) do - local vehPlate = GetVehicleNumberPlateText(veh) - if (plate == vehPlate or plate == string.gsub(vehPlate, "^%s*(.-)%s*$", "%1")) then - return GetEntityCoords(veh) - end - end - - for vehPlate, vehData in pairs(vehicles) do - if (plate == vehPlate or plate == string.gsub(vehPlate, "^%s*(.-)%s*$", "%1")) then - return vehData.position - end - end - - return nil - end) - - exports["kimi_callbacks"]:Register("AP:getVehiclePositions", function(source, plates) - local platePositions = {} - - Log("Looking for plates:") - for i, plate in ipairs(plates) do - Log("\"" .. plate .. "\"") - end - - local vehs = GetAllVehicles() - for i, veh in ipairs(vehs) do - local vehPlate = GetVehicleNumberPlateText(veh) - local trimmedVehPlate = string.gsub(vehPlate, "^%s*(.-)%s*$", "%1") - - for j, plate in ipairs(plates) do - if (plate == vehPlate or plate == trimmedVehPlate) then - platePositions[plate] = GetEntityCoords(veh) - - break - end - end - end - - for i, plate in ipairs(plates) do - if (platePositions[plate] == nil) then - for vehPlate, vehData in pairs(vehicles) do - local trimmedVehPlate = string.gsub(vehPlate, "^%s*(.-)%s*$", "%1") - - if (plate == vehPlate or plate == trimmedVehPlate) then - platePositions[plate] = vehData.position - - break - end - end - end - end - - return platePositions - end) -end - - -RegisterNetEvent('mh_Parking:removeVehicle') -AddEventHandler('mh_Parking:removeVehicle', function(plate) - print("mh_parking: "..plate) - vehicles[plate] = nil -end) - -function CallDB_Vehicles() - DB_vehicles = {} - MySQL.query('SELECT * FROM player_vehicles', {}, function(rs) - for k, v in pairs(rs) do - table.insert(DB_vehicles, v) - end - end) --DB_vehicles -end - -function CheckPlate(plate) -- DB_Players - for k, v in pairs(DB_vehicles) do - if Config.isDebug then - Log(json.encode(v)) - Log(plate) - Log(v.plate) - end - - if v.plate == plate then - return true - end - end - return false +local vehicles = {} +local DB_vehicles = {} + +-- Command to delete ALL vehicles from the database table. Needs to be executed twice for security reason. +local deleteSavedVehicles = false +RegisterCommand("deleteSavedVehicles", function(source, args, raw) + if (deleteSavedVehicles) then + MySQL.query("DELETE FROM vehicle_parking", { }) + + vehicles = {} + + Log("Deleted all vehicles from the vehicle_parking table.") + else + Log("Are you sure that you want to delete all vehicles from the parking list?\nIf yes, type the command a second time!") + end + + deleteSavedVehicles = not deleteSavedVehicles +end, true) + +-- read all vehicles from the database on startup and do a cleanup check +MySQL.ready(function() + -- fetch all database results + MySQL.query("SELECT plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate FROM vehicle_parking", {}, function(results) + Log("Found " .. #results .. " saved vehicles in vehicle_parking.") + + for i = 1, #results do + vehicles[results[i].plate] = { + handle = nil, + position = vector3(results[i].posX, results[i].posY, results[i].posZ), + rotation = vector3(results[i].rotX, results[i].rotY, results[i].rotZ), + modifications = json.decode(results[i].modifications), + lastUpdate = results[i].lastUpdate, + spawning = false, + spawningPlayer = nil, + faultyModel = false + } + end + + --CleanUp() + end) +end) + +-- Default CleanUp function. Deletes vehicles from the database after a specific amount of time has passed (configurable in config) +function CleanUp() + local currentTime = os.time() + local threshold = 60 * 60 * Config.cleanUpThresholdTime + + local toDelete = {} + + for plate, vehicle in pairs(vehicles) do + if (vehicle.lastUpdate < os.difftime(currentTime, threshold)) then + + MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate", + { + ["@plate"] = plate + }) + + table.insert(toDelete, plate) + end + end + + for i = 1, #toDelete, 1 do + local plate = toDelete[i] + vehicles[plate] = nil + end + + Log("CleanUp complete. Deleted " .. #toDelete .. " entries.") +end + + + +-- loop to spawn vehicles near players +Citizen.CreateThread(function() + while (true) do + Citizen.Wait(5000) + + if (GetActivePlayerCount() > 0) then + TrySpawnVehicles() + end + end +end) + +Citizen.CreateThread(function() + while (true) do + CallDB_Vehicles() + Citizen.Wait(60000 * 5) + end +end) + +-- loop to delete vehicles +Citizen.CreateThread(function() + if (Config.deleteTimer <= 0) then + return + end + + while (true) do + Citizen.Wait(60000 * (Config.deleteTimer - Config.deleteNotificationTimes[1])) + + TriggerClientEvent("mh_Parking:notification", -1, string.format(Config.timeLeftNotification, Config.deleteNotificationTimes[1])) + for i = 2, #Config.deleteNotificationTimes, 1 do + Citizen.Wait(60000 * (Config.deleteNotificationTimes[i - 1] - Config.deleteNotificationTimes[i])) + TriggerClientEvent("mh_Parking:notification", -1, string.format(Config.timeLeftNotification, Config.deleteNotificationTimes[i])) + end + Citizen.Wait(60000 * Config.deleteNotificationTimes[#Config.deleteNotificationTimes]) + + DeleteAllVehicles() + end +end) + + + +-- sync player position +RegisterServerEvent("mh_Parking:syncPlayerPosition") +AddEventHandler("mh_Parking:syncPlayerPosition", function(position) + activePlayerPositions[source] = position +end) + +-- player disconnected +AddEventHandler("playerDropped", function(disconnectReason) + activePlayerPositions[source] = nil +end) + +-- player entered a vehicle +RegisterServerEvent("mh_Parking:enteredVehicle") +AddEventHandler("mh_Parking:enteredVehicle", function(networkId, plate, modifications) + local vehicle = NetworkGetEntityFromNetworkId(networkId) + + if (DoesEntityExist(vehicle)) then + local currentTime = os.time() + + local position = GetEntityCoords(vehicle) + position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0) + local rotation = GetEntityRotation(vehicle) + rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0) + + if (vehicles[plate]) then + -- already on server list + + Log("Entered vehicle " .. plate .. ". Updating...") + + if (vehicles[plate].handle ~= vehicle) then + if (DoesEntityExist(vehicles[plate].handle)) then + DeleteEntity(vehicles[plate].handle) + end + + vehicles[plate].handle = vehicle + end + + vehicles[plate].position = position + vehicles[plate].rotation = rotation + vehicles[plate].modifications = modifications + vehicles[plate].lastUpdate = currentTime + + MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate", { + ["@plate"] = plate, + ["@posX"] = vehicles[plate].position.x, + ["@posY"] = vehicles[plate].position.y, + ["@posZ"] = vehicles[plate].position.z, + ["@rotX"] = vehicles[plate].rotation.x, + ["@rotY"] = vehicles[plate].rotation.y, + ["@rotZ"] = vehicles[plate].rotation.z, + ["@modifications"] = json.encode(vehicles[plate].modifications), + ["@lastUpdate"] = vehicles[plate].lastUpdate + }) + else + -- insert in db + + Log("Entered vehicle " .. plate .. ". Inserting new...") + + vehicles[plate] = { + handle = vehicle, + position = position, + rotation = rotation, + modifications = modifications, + lastUpdate = currentTime, + spawning = false, + spawningPlayer = nil + } + + MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs) + Log(json.encode(rs)) + if rs[1] then + Log("FOUND OWNER FROM VEHICLE") + + MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)", { + ["@plate"] = plate, + ["@posX"] = vehicles[plate].position.x, + ["@posY"] = vehicles[plate].position.y, + ["@posZ"] = vehicles[plate].position.z, + ["@rotX"] = vehicles[plate].rotation.x, + ["@rotY"] = vehicles[plate].rotation.y, + ["@rotZ"] = vehicles[plate].rotation.z, + ["@modifications"] = json.encode(vehicles[plate].modifications), + ["@lastUpdate"] = vehicles[plate].lastUpdate + }) + else + Log("1: NO VEHICLE FOUND") + end + end) + end + else + Log("Vehicle does not exist. Might be a Onesync error.") + end +end) + +-- player left a vehicle +RegisterServerEvent("mh_Parking:leftVehicle") +AddEventHandler("mh_Parking:leftVehicle", function(networkId, modifications) + local vehicle = NetworkGetEntityFromNetworkId(networkId) + + if (DoesEntityExist(vehicle)) then + local currentTime = os.time() + + local plate = GetVehicleNumberPlateText(vehicle) + + local position = GetEntityCoords(vehicle) + position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0) + local rotation = GetEntityRotation(vehicle) + rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0) + + if (vehicles[plate]) then + -- already on server list + + Log("Left vehicle " .. plate .. ". Updating...") + + if (vehicles[plate].handle ~= vehicle) then + if (DoesEntityExist(vehicles[plate].handle)) then + DeleteEntity(vehicles[plate].handle) + end + + vehicles[plate].handle = vehicle + end + + vehicles[plate].position = position + vehicles[plate].rotation = rotation + vehicles[plate].modifications = modifications + vehicles[plate].lastUpdate = currentTime + + MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate",{ + ["@plate"] = plate, + ["@posX"] = vehicles[plate].position.x, + ["@posY"] = vehicles[plate].position.y, + ["@posZ"] = vehicles[plate].position.z, + ["@rotX"] = vehicles[plate].rotation.x, + ["@rotY"] = vehicles[plate].rotation.y, + ["@rotZ"] = vehicles[plate].rotation.z, + ["@modifications"] = json.encode(vehicles[plate].modifications), + ["@lastUpdate"] = currentTime + }) + else + -- insert in db + + Log("Left vehicle " .. plate .. ". Inserting new...") + + vehicles[plate] = { + handle = vehicle, + position = position, + rotation = rotation, + modifications = modifications, + lastUpdate = currentTime, + spawning = false, + spawningPlayer = nil + } + + MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs) + if rs[1] then + Log("FOUND OWNER FROM VEHICLE") + + MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)",{ + ["@plate"] = plate, + ["@posX"] = vehicles[plate].position.x, + ["@posY"] = vehicles[plate].position.y, + ["@posZ"] = vehicles[plate].position.z, + ["@rotX"] = vehicles[plate].rotation.x, + ["@rotY"] = vehicles[plate].rotation.y, + ["@rotZ"] = vehicles[plate].rotation.z, + ["@modifications"] = json.encode(vehicles[plate].modifications), + ["@lastUpdate"] = vehicles[plate].lastUpdate + }) + else + Log("2: NO VEHICLE FOUND") + end + end) + end + end +end) + +-- update a vehicle with its modifications +RegisterServerEvent("mh_Parking:updateVehicle") +AddEventHandler("mh_Parking:updateVehicle", function(networkId, modifications) + local vehicle = NetworkGetEntityFromNetworkId(networkId) + + if (DoesEntityExist(vehicle)) then + local currentTime = os.time() + + local plate = GetVehicleNumberPlateText(vehicle) + + local position = GetEntityCoords(vehicle) + position = vector3(math.floor(position.x * 100.0) / 100.0, math.floor(position.y * 100.0) / 100.0, math.floor(position.z * 100.0) / 100.0) + local rotation = GetEntityRotation(vehicle) + rotation = vector3(math.floor(rotation.x * 100.0) / 100.0, math.floor(rotation.y * 100.0) / 100.0, math.floor(rotation.z * 100.0) / 100.0) + + if (vehicles[plate] ~= nil) then + -- already on server list + + Log("Updating vehicle " .. plate) + + if (vehicles[plate].handle ~= vehicle) then + if (DoesEntityExist(vehicles[plate].handle)) then + DeleteEntity(vehicles[plate].handle) + end + + vehicles[plate].handle = vehicle + end + + vehicles[plate].position = position + vehicles[plate].rotation = rotation + vehicles[plate].modifications = modifications + vehicles[plate].lastUpdate = currentTime + + MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications, lastUpdate = @lastUpdate WHERE plate = @plate",{ + ["@plate"] = plate, + ["@posX"] = vehicles[plate].position.x, + ["@posY"] = vehicles[plate].position.y, + ["@posZ"] = vehicles[plate].position.z, + ["@rotX"] = vehicles[plate].rotation.x, + ["@rotY"] = vehicles[plate].rotation.y, + ["@rotZ"] = vehicles[plate].rotation.z, + ["@modifications"] = json.encode(vehicles[plate].modifications), + ["@lastUpdate"] = vehicles[plate].lastUpdate + }) + else + -- insert in db + + Log("Updating vehicle " .. plate .. ". Inserting new...") + + vehicles[plate] = { + handle = vehicle, + position = position, + rotation = rotation, + modifications = modifications, + lastUpdate = currentTime, + spawning = false, + spawningPlayer = nil + } + + MySQL.query('SELECT * FROM player_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(rs) + if rs[1] then + Log("FOUND OWNER FROM VEHICLE") + + MySQL.query("INSERT INTO vehicle_parking (plate, posX, posY, posZ, rotX, rotY, rotZ, modifications, lastUpdate) VALUES (@plate, @posX, @posY, @posZ, @rotX, @rotY, @rotZ, @modifications, @lastUpdate)",{ + ["@plate"] = plate, + ["@posX"] = vehicles[plate].position.x, + ["@posY"] = vehicles[plate].position.y, + ["@posZ"] = vehicles[plate].position.z, + ["@rotX"] = vehicles[plate].rotation.x, + ["@rotY"] = vehicles[plate].rotation.y, + ["@rotZ"] = vehicles[plate].rotation.z, + ["@modifications"] = json.encode(vehicles[plate].modifications), + ["@lastUpdate"] = vehicles[plate].lastUpdate + }) + else + Log("3: NO VEHICLE FOUND") + end + end) + end + end +end) + +-- delete a vehicle from the table (and world) with its plate +RegisterServerEvent("mh_Parking:deleteVehicle") +AddEventHandler("mh_Parking:deleteVehicle", function(plate, deleteEntity) + if (plate == nil) then + Log("^1mh_Parking: \"plate\" was nil while trying to delete vehicle!") + return + end + + Log("Trying to delete " .. tostring(plate)) + + if (vehicles[plate] ~= nil) then + if (deleteEntity and DoesEntityExist(vehicles[plate].handle)) then + DeleteEntity(vehicles[plate].handle) + end + + vehicles[plate] = nil + + MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate", + { + ["@plate"] = plate + }) + else + local loadedVehicles = GetAllVehicles() + local loadedVehicle = TryGetLoadedVehicle(plate, loadedVehicles) + + if (loadedVehicle ~= nil) then + if (deleteEntity and DoesEntityExist(loadedVehicle)) then + DeleteEntity(loadedVehicle) + end + + MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate", + { + ["@plate"] = plate + }) + end + end +end) + +-- checks if vehicles have to be spawned and spawns them if necessary +function TrySpawnVehicles() + local loadedVehicles = GetAllVehicles() + + local playerVehiclePlates = {} + for id, position in pairs(activePlayerPositions) do + local ped = GetPlayerPed(id) + local veh = GetVehiclePedIsIn(ped, false) + + if (DoesEntityExist(veh)) then + table.insert(playerVehiclePlates, GetVehicleNumberPlateText(veh)) + end + end + + -- check, if vehicles need to be spawned + for plate, vehicleData in pairs(vehicles) do + local plateCheck = CheckPlate(plate) + if (plateCheck ~= false) then + + if (not vehicleData.faultyModel) then + if (not vehicleData.spawning) then + local closestPlayer, dist = GetClosestPlayerId(vehicleData.position) + + if (closestPlayer ~= nil and dist < Config.spawnDistance and not ContainsPlate(plate, playerVehiclePlates)) then + if (vehicleData.handle ~= nil and DoesEntityExist(vehicleData.handle)) then + -- vehicle found on server side + + UpdateVehicle(plate) + else + -- vehicle not found on server side + -- check, if it is loaded differently + + local loadedVehicle = TryGetLoadedVehicle(plate, loadedVehicles) + if (loadedVehicle ~= nil) then + -- vehicle found + + vehicleData.handle = loadedVehicle + + UpdateVehicle(plate) + else + -- vehicle not found + -- try and spawn it + + local playerId, distance = GetClosestPlayerId(vehicleData.position) + if (playerId and distance < Config.spawnDistance) then + vehicleData.spawning = true + + Citizen.CreateThread(function() + local vec4 = vector4(vehicleData.position.x, vehicleData.position.y, vehicleData.position.z, vehicleData.rotation.z) + local vehicle = Citizen.InvokeNative(GetHashKey("CREATE_AUTOMOBILE"), vehicleData.modifications[1], vec4.xyzw) + + while (not DoesEntityExist(vehicle)) do + Citizen.Wait(0) + end + + SetEntityCoords(vehicle, vehicleData.position.x, vehicleData.position.y, vehicleData.position.z) + SetEntityRotation(vehicle, vehicleData.rotation.x, vehicleData.rotation.y, vehicleData.rotation.z) + + vehicleData.handle = vehicle + + local networkOwner = -1 + while (networkOwner == -1) do + Citizen.Wait(0) + networkOwner = NetworkGetEntityOwner(vehicleData.handle) + end + + vehicleData.spawningPlayer = GetPlayerIdentifiersSorted(networkOwner)["license"] + + Log("Creating vehicle " .. plate .. " at " .. tostring(vehicleData.position) .. " at entity owner " .. tostring(networkOwner)) + + TriggerClientEvent("mh_Parking:setVehicleMods", networkOwner, NetworkGetNetworkIdFromEntity(vehicleData.handle), plate, vehicleData.modifications) + end) + end + end + end + end + elseif (vehicleData.spawningPlayer) then + -- if vehicle is currently spawning check if responsible player is still connected + if (not IsPlayerWithLicenseActive(vehicleData.spawningPlayer)) then + TriggerEvent("mh_Parking:setVehicleModsFailed", plate) + end + end + end + end + end +end + +RegisterServerEvent("mh_Parking:setVehicleModsSuccess") +AddEventHandler("mh_Parking:setVehicleModsSuccess", function(plate) + Log("Setting mods successful...") + + if (vehicles[plate]) then + vehicles[plate].spawning = false + vehicles[plate].spawningPlayer = nil + end +end) + +RegisterServerEvent("mh_Parking:setVehicleModsFailed") +AddEventHandler("mh_Parking:setVehicleModsFailed", function(plate) + Log("Setting mods for " .. plate .. " failed... retrying...") + + if (vehicles[plate] and vehicles[plate].handle and DoesEntityExist(vehicles[plate].handle)) then + local networkOwner = -1 + while (networkOwner == -1) do + Citizen.Wait(0) + networkOwner = NetworkGetEntityOwner(vehicles[plate].handle) + end + + local netOwnerLicense = GetPlayerIdentifiersSorted(networkOwner)["license"] + if (netOwnerLicense ~= nil) then + vehicles[plate].spawningPlayer = GetPlayerIdentifiersSorted(networkOwner)["license"] + + TriggerClientEvent("mh_Parking:setVehicleMods", networkOwner, NetworkGetNetworkIdFromEntity(vehicles[plate].handle), plate, vehicles[plate].modifications) + else + Log("Something went wrong while trying to get player license for spawning vehicle " .. tostring(plate) .. ". Despawning vehicle") + + DeleteEntity(vehicles[plate].handle) + + vehicles[plate].handle = nil + vehicles[plate].spawningPlayer = nil + vehicles[plate].spawning = false + end + end +end) + +RegisterServerEvent("mh_Parking:modelDoesNotExist") +AddEventHandler("mh_Parking:modelDoesNotExist", function(plate) + if (vehicles[plate] == nil) then + return + end + + if (DoesEntityExist(vehicles[plate].handle)) then + DeleteEntity(vehicles[plate].handle) + end + vehicles[plate].handle = nil + vehicles[plate].spawningPlayer = nil + vehicles[plate].spawning = false + + Log("The model for vehicle " .. tostring(plate) .. " does not exist. Removing from spawn pool...") + + vehicles[plate].faultyModel = true +end) + +RegisterServerEvent("mh_Parking:updatePlate") +AddEventHandler("mh_Parking:updatePlate", function(oldPlate, newPlate) + if (oldPlate == nil or newPlate == nil) then + Log("^1mh_Parking: \"oldPlate\" or \"newPlate\" was nil while trying to update a plate!") + return + end + + if (vehicles[oldPlate]) then + if (vehicles[newPlate]) then + Log("Updating plate failed. New plate was already there!") + else + vehicles[newPlate] = vehicles[oldPlate] + vehicles[oldPlate] = nil + + Log("Updating plate successful!") + + MySQL.query("UPDATE vehicle_parking SET plate = @newPlate WHERE plate = @oldPlate", + { + ["@newPlate"] = newPlate, + ["@oldPlate"] = oldPlate + }) + end + else + Log("Updating plate failed or unnecessary. Old plate was not found!") + end +end) + +function UpdateVehicle(plate) + local newPos = GetEntityCoords(vehicles[plate].handle) + local newRot = GetEntityRotation(vehicles[plate].handle) + newPos = vector3(math.floor(newPos.x * 100.0) * 0.01, math.floor(newPos.y * 100.0) * 0.01, math.floor(newPos.z * 100.0) * 0.01) + newRot = vector3(math.floor(newRot.x * 100.0) * 0.01, math.floor(newRot.y * 100.0) * 0.01, math.floor(newRot.z * 100.0) * 0.01) + + local newLockStatus = GetVehicleDoorLockStatus(vehicles[plate].handle) + local newEngineHealth = math.floor(GetVehicleEngineHealth(vehicles[plate].handle) * 10.0) * 0.1 + local newTankHealth = math.floor(GetVehiclePetrolTankHealth(vehicles[plate].handle) * 10.0) * 0.1 + if (Vector3DistFast(vehicles[plate].position, newPos) > 1.0 + or GetRotationDifference(vehicles[plate].rotation, newRot) > 15.0 + or newLockStatus ~= vehicles[plate].modifications[2] + or math.abs(newEngineHealth - vehicles[plate].modifications[5]) > 5.0 + or math.abs(newTankHealth - vehicles[plate].modifications[6]) > 5.0 + ) then + vehicles[plate].modifications[2] = newLockStatus + vehicles[plate].modifications[5] = newEngineHealth + vehicles[plate].modifications[6] = newTankHealth + + Log("Updating vehicle " .. plate) + + vehicles[plate].position = newPos + vehicles[plate].rotation = newRot + + MySQL.query("UPDATE vehicle_parking SET posX = @posX, posY = @posY, posZ = @posZ, rotX = @rotX, rotY = @rotY, rotZ = @rotZ, modifications = @modifications WHERE plate = @plate", + { + ["@posX"] = vehicles[plate].position.x, + ["@posY"] = vehicles[plate].position.y, + ["@posZ"] = vehicles[plate].position.z, + ["@rotX"] = vehicles[plate].rotation.x, + ["@rotY"] = vehicles[plate].rotation.y, + ["@rotZ"] = vehicles[plate].rotation.z, + ["@modifications"] = json.encode(vehicles[plate].modifications), + ["@plate"] = plate + }) + end +end + +function DeleteAllVehicles() + TriggerClientEvent("mh_Parking:notification", -1, Config.deleteNotification) + + local peds = GetAllPeds() + local playerPeds = {} + for i = 1, #peds, 1 do + if (IsPedAPlayer(peds[i])) then + table.insert(playerPeds, peds[i]) + end + end + + if (#playerPeds == 0) then + return + end + + local time = GetGameTimer() + + local vehs = GetAllVehicles() + local deleted = 0 + for i = 1, #vehs, 1 do + if (not IsAnyPlayerInsideVehicle(vehs[i], playerPeds)) then + local closestPlayer, distance = GetClosestPlayerPed(GetEntityCoords(vehs[i]), playerPeds) + if (closestPlayer ~= nil and distance > Config.deleteDistance) then + local plate = GetVehicleNumberPlateText(vehs[i]) + if (vehicles[plate] ~= nil) then + vehicles[plate] = nil + + MySQL.query("DELETE FROM vehicle_parking WHERE plate = @plate", + { + ["@plate"] = plate + }) + end + + DeleteEntity(vehs[i]) + + deleted = deleted + 1 + end + end + end + + Log("Deleted " .. tostring(deleted) .. "/" .. tostring(#vehs) .. " vehicles. Took " .. tostring((GetGameTimer() - time) / 1000.0) .. "sec") +end + +AddEventHandler("onResourceStop", function(name) + if (name ~= GetCurrentResourceName()) then + return + end + + -- delete vehicles that are still being spawned before actually stopping the resource + for plate, vehicleData in pairs(vehicles) do + if (vehicleData.spawning and DoesEntityExist(vehicleData.handle)) then + DeleteEntity(vehicleData.handle) + end + end +end) + +-- render entity scorched (trigger with netid of the vehicle and false when repairing) +RegisterServerEvent("mh_Parking:renderScorched") +AddEventHandler("mh_Parking:renderScorched", function(vehicleNetId, scorched) + local vehicleHandle = NetworkGetEntityFromNetworkId(vehicleNetId) + if (DoesEntityExist(vehicleHandle)) then + TriggerClientEvent("mh_Parking:renderScorched", -1, vehicleNetId, scorched) + end +end) + +if (GetResourceState("kimi_callbacks") == "started") then + exports["kimi_callbacks"]:Register("AP:getVehiclePosition", function(source, plate) + local vehs = GetAllVehicles() + + for i, veh in ipairs(vehs) do + local vehPlate = GetVehicleNumberPlateText(veh) + if (plate == vehPlate or plate == string.gsub(vehPlate, "^%s*(.-)%s*$", "%1")) then + return GetEntityCoords(veh) + end + end + + for vehPlate, vehData in pairs(vehicles) do + if (plate == vehPlate or plate == string.gsub(vehPlate, "^%s*(.-)%s*$", "%1")) then + return vehData.position + end + end + + return nil + end) + + exports["kimi_callbacks"]:Register("AP:getVehiclePositions", function(source, plates) + local platePositions = {} + + Log("Looking for plates:") + for i, plate in ipairs(plates) do + Log("\"" .. plate .. "\"") + end + + local vehs = GetAllVehicles() + for i, veh in ipairs(vehs) do + local vehPlate = GetVehicleNumberPlateText(veh) + local trimmedVehPlate = string.gsub(vehPlate, "^%s*(.-)%s*$", "%1") + + for j, plate in ipairs(plates) do + if (plate == vehPlate or plate == trimmedVehPlate) then + platePositions[plate] = GetEntityCoords(veh) + + break + end + end + end + + for i, plate in ipairs(plates) do + if (platePositions[plate] == nil) then + for vehPlate, vehData in pairs(vehicles) do + local trimmedVehPlate = string.gsub(vehPlate, "^%s*(.-)%s*$", "%1") + + if (plate == vehPlate or plate == trimmedVehPlate) then + platePositions[plate] = vehData.position + + break + end + end + end + end + + return platePositions + end) +end + + +RegisterNetEvent('mh_Parking:removeVehicle') +AddEventHandler('mh_Parking:removeVehicle', function(plate) + print("mh_parking: "..plate) + vehicles[plate] = nil +end) + +function CallDB_Vehicles() + DB_vehicles = {} + MySQL.query('SELECT * FROM player_vehicles', {}, function(rs) + for k, v in pairs(rs) do + table.insert(DB_vehicles, v) + end + end) --DB_vehicles +end + +function CheckPlate(plate) -- DB_Players + for k, v in pairs(DB_vehicles) do + if Config.isDebug then + Log(json.encode(v)) + Log(plate) + Log(v.plate) + end + + if v.plate == plate then + return true + end + end + return false end \ No newline at end of file diff --git a/resources/[carscripts]/mh_Parking/sv_utils.lua b/resources/[Developer]/mh_Parking/sv_utils.lua similarity index 96% rename from resources/[carscripts]/mh_Parking/sv_utils.lua rename to resources/[Developer]/mh_Parking/sv_utils.lua index 2705233f5..d5d01fd45 100644 --- a/resources/[carscripts]/mh_Parking/sv_utils.lua +++ b/resources/[Developer]/mh_Parking/sv_utils.lua @@ -1,151 +1,151 @@ -activePlayerPositions = {} - --- returns a loaded vehicled with a given number plate -function TryGetLoadedVehicle(plate, loadedVehicles) - for i = 1, #loadedVehicles, 1 do - if (plate == GetVehicleNumberPlateText(loadedVehicles[i]) and DoesEntityExist(loadedVehicles[i])) then - return loadedVehicles[i] - end - end - - return nil -end - -function ContainsPlate(plate, vehiclePlates) - for i = 1, #vehiclePlates, 1 do - if (plate == vehiclePlates[i]) then - return true - end - end - - return false -end - --- Logs text to the server console -function Log(text) - if (Config.isDebug) then - Print(GetCurrentResourceName() .. ": " .. text) - end -end - --- return the distance between two positions (Vector3) -function Vector3Dist(v1, v2) - return math.sqrt( (v2.x - v1.x) * (v2.x - v1.x) + (v2.y - v1.y) * (v2.y - v1.y) + (v2.z - v1.z) * (v2.z - v1.z) ) -end - --- return the distance between two positions without sqrt (Vector3) -function Vector3DistFast(v1, v2) - return (v2.x - v1.x) * (v2.x - v1.x) + (v2.y - v1.y) * (v2.y - v1.y) + (v2.z - v1.z) * (v2.z - v1.z) -end - --- returns the difference in degrees from the axis with the highest difference -function GetRotationDifference(r1, r2) - local x = math.abs(r1.x - r2.x) - local y = math.abs(r1.y - r2.y) - local z = math.abs(r1.z - r2.z) - - if (x > y and x > z) then - return x - elseif (y > z) then - return y - else - return z - end -end - --- get the amount of currently active players -function GetActivePlayerCount() - local playerCount = 0 - for k, v in pairs(activePlayerPositions) do - playerCount = playerCount + 1 - end - return playerCount -end - --- return the ID of the closest player -function GetClosestPlayerId(position) - local closestDistance = 1000000.0 - local closestPlayerID = nil - local closestPos = nil - - for playerID, pos in pairs(activePlayerPositions) do - local distance = Vector3DistFast(position, pos) - - if (distance < closestDistance) then - closestDistance = distance - closestPlayerID = playerID - closestPos = pos - end - end - - local distance = nil - if (closestPlayerID ~= nil) then - distance = Vector3Dist(position, closestPos) - end - - return closestPlayerID, distance -end - -function IsAnyPlayerInsideVehicle(vehicle, playerPeds) - for i = 1, #playerPeds, 1 do - local veh = GetVehiclePedIsIn(playerPeds[i], false) - - if (DoesEntityExist(veh) and veh == vehicle) then - return true - end - end - - return false -end - --- return the ped of the closest player -function GetClosestPlayerPed(position, playerPeds) - local closestDistance = 1000000.0 - local closestPlayerPed = nil - local closestPos = nil - - for k, playerPed in pairs(playerPeds) do - local pos = GetEntityCoords(playerPed) - local distance = Vector3DistFast(position, pos) - - if (distance < closestDistance) then - closestDistance = distance - closestPlayerPed = playerPed - closestPos = pos - end - end - - local distance = 0.0 - if (closestPlayerPed ~= nil) then - distance = Vector3Dist(position, closestPos) - end - - return closestPlayerPed, distance -end - --- returns true if a player is active on the server with the specified license -function IsPlayerWithLicenseActive(license) - for playerId, playerPos in pairs(activePlayerPositions) do - if (GetPlayerIdentifiersSorted(playerId)["license"] == license) then - return true - end - end - - return false -end - --- Return an array with all identifiers - e.g. ids["license"] = license:xxxxxxxxxxxxxxxx -function GetPlayerIdentifiersSorted(playerServerId) - local ids = {} - - local identifiers = GetPlayerIdentifiers(playerServerId) - - for k, identifier in pairs (identifiers) do - local i, j = string.find(identifier, ":") - local idType = string.sub(identifier, 1, i-1) - - ids[idType] = identifier - end - - return ids -end +activePlayerPositions = {} + +-- returns a loaded vehicled with a given number plate +function TryGetLoadedVehicle(plate, loadedVehicles) + for i = 1, #loadedVehicles, 1 do + if (plate == GetVehicleNumberPlateText(loadedVehicles[i]) and DoesEntityExist(loadedVehicles[i])) then + return loadedVehicles[i] + end + end + + return nil +end + +function ContainsPlate(plate, vehiclePlates) + for i = 1, #vehiclePlates, 1 do + if (plate == vehiclePlates[i]) then + return true + end + end + + return false +end + +-- Logs text to the server console +function Log(text) + if (Config.isDebug) then + Print(GetCurrentResourceName() .. ": " .. text) + end +end + +-- return the distance between two positions (Vector3) +function Vector3Dist(v1, v2) + return math.sqrt( (v2.x - v1.x) * (v2.x - v1.x) + (v2.y - v1.y) * (v2.y - v1.y) + (v2.z - v1.z) * (v2.z - v1.z) ) +end + +-- return the distance between two positions without sqrt (Vector3) +function Vector3DistFast(v1, v2) + return (v2.x - v1.x) * (v2.x - v1.x) + (v2.y - v1.y) * (v2.y - v1.y) + (v2.z - v1.z) * (v2.z - v1.z) +end + +-- returns the difference in degrees from the axis with the highest difference +function GetRotationDifference(r1, r2) + local x = math.abs(r1.x - r2.x) + local y = math.abs(r1.y - r2.y) + local z = math.abs(r1.z - r2.z) + + if (x > y and x > z) then + return x + elseif (y > z) then + return y + else + return z + end +end + +-- get the amount of currently active players +function GetActivePlayerCount() + local playerCount = 0 + for k, v in pairs(activePlayerPositions) do + playerCount = playerCount + 1 + end + return playerCount +end + +-- return the ID of the closest player +function GetClosestPlayerId(position) + local closestDistance = 1000000.0 + local closestPlayerID = nil + local closestPos = nil + + for playerID, pos in pairs(activePlayerPositions) do + local distance = Vector3DistFast(position, pos) + + if (distance < closestDistance) then + closestDistance = distance + closestPlayerID = playerID + closestPos = pos + end + end + + local distance = nil + if (closestPlayerID ~= nil) then + distance = Vector3Dist(position, closestPos) + end + + return closestPlayerID, distance +end + +function IsAnyPlayerInsideVehicle(vehicle, playerPeds) + for i = 1, #playerPeds, 1 do + local veh = GetVehiclePedIsIn(playerPeds[i], false) + + if (DoesEntityExist(veh) and veh == vehicle) then + return true + end + end + + return false +end + +-- return the ped of the closest player +function GetClosestPlayerPed(position, playerPeds) + local closestDistance = 1000000.0 + local closestPlayerPed = nil + local closestPos = nil + + for k, playerPed in pairs(playerPeds) do + local pos = GetEntityCoords(playerPed) + local distance = Vector3DistFast(position, pos) + + if (distance < closestDistance) then + closestDistance = distance + closestPlayerPed = playerPed + closestPos = pos + end + end + + local distance = 0.0 + if (closestPlayerPed ~= nil) then + distance = Vector3Dist(position, closestPos) + end + + return closestPlayerPed, distance +end + +-- returns true if a player is active on the server with the specified license +function IsPlayerWithLicenseActive(license) + for playerId, playerPos in pairs(activePlayerPositions) do + if (GetPlayerIdentifiersSorted(playerId)["license"] == license) then + return true + end + end + + return false +end + +-- Return an array with all identifiers - e.g. ids["license"] = license:xxxxxxxxxxxxxxxx +function GetPlayerIdentifiersSorted(playerServerId) + local ids = {} + + local identifiers = GetPlayerIdentifiers(playerServerId) + + for k, identifier in pairs (identifiers) do + local i, j = string.find(identifier, ":") + local idType = string.sub(identifier, 1, i-1) + + ids[idType] = identifier + end + + return ids +end diff --git a/resources/[carscripts]/mh_garage/client/debug.lua b/resources/[Developer]/mh_garage/client/debug.lua similarity index 100% rename from resources/[carscripts]/mh_garage/client/debug.lua rename to resources/[Developer]/mh_garage/client/debug.lua diff --git a/resources/[carscripts]/mh_garage/client/main.lua b/resources/[Developer]/mh_garage/client/main.lua similarity index 100% rename from resources/[carscripts]/mh_garage/client/main.lua rename to resources/[Developer]/mh_garage/client/main.lua diff --git a/resources/[carscripts]/mh_garage/client/retrieve.lua b/resources/[Developer]/mh_garage/client/retrieve.lua similarity index 100% rename from resources/[carscripts]/mh_garage/client/retrieve.lua rename to resources/[Developer]/mh_garage/client/retrieve.lua diff --git a/resources/[carscripts]/mh_garage/client/stored.lua b/resources/[Developer]/mh_garage/client/stored.lua similarity index 100% rename from resources/[carscripts]/mh_garage/client/stored.lua rename to resources/[Developer]/mh_garage/client/stored.lua diff --git a/resources/[carscripts]/mh_garage/client/vehicleadmin.lua b/resources/[Developer]/mh_garage/client/vehicleadmin.lua similarity index 100% rename from resources/[carscripts]/mh_garage/client/vehicleadmin.lua rename to resources/[Developer]/mh_garage/client/vehicleadmin.lua diff --git a/resources/[carscripts]/mh_garage/client/vehicleadmin_integration.lua b/resources/[Developer]/mh_garage/client/vehicleadmin_integration.lua similarity index 100% rename from resources/[carscripts]/mh_garage/client/vehicleadmin_integration.lua rename to resources/[Developer]/mh_garage/client/vehicleadmin_integration.lua diff --git a/resources/[carscripts]/mh_garage/client/verwaltung.lua b/resources/[Developer]/mh_garage/client/verwaltung.lua similarity index 100% rename from resources/[carscripts]/mh_garage/client/verwaltung.lua rename to resources/[Developer]/mh_garage/client/verwaltung.lua diff --git a/resources/[carscripts]/mh_garage/config/config.lua b/resources/[Developer]/mh_garage/config/config.lua similarity index 100% rename from resources/[carscripts]/mh_garage/config/config.lua rename to resources/[Developer]/mh_garage/config/config.lua diff --git a/resources/[carscripts]/mh_garage/config/price.lua b/resources/[Developer]/mh_garage/config/price.lua similarity index 100% rename from resources/[carscripts]/mh_garage/config/price.lua rename to resources/[Developer]/mh_garage/config/price.lua diff --git a/resources/[carscripts]/mh_garage/fxmanifest.lua b/resources/[Developer]/mh_garage/fxmanifest.lua similarity index 100% rename from resources/[carscripts]/mh_garage/fxmanifest.lua rename to resources/[Developer]/mh_garage/fxmanifest.lua diff --git a/resources/[carscripts]/mh_garage/server/log.lua b/resources/[Developer]/mh_garage/server/log.lua similarity index 100% rename from resources/[carscripts]/mh_garage/server/log.lua rename to resources/[Developer]/mh_garage/server/log.lua diff --git a/resources/[carscripts]/mh_garage/server/server.lua b/resources/[Developer]/mh_garage/server/server.lua similarity index 100% rename from resources/[carscripts]/mh_garage/server/server.lua rename to resources/[Developer]/mh_garage/server/server.lua diff --git a/resources/[carscripts]/mh_garage/server/vehicleadmin.lua b/resources/[Developer]/mh_garage/server/vehicleadmin.lua similarity index 100% rename from resources/[carscripts]/mh_garage/server/vehicleadmin.lua rename to resources/[Developer]/mh_garage/server/vehicleadmin.lua diff --git a/resources/[carscripts]/sn_vehicleKey/client.lua b/resources/[Developer]/sn_vehicleKey/client.lua similarity index 97% rename from resources/[carscripts]/sn_vehicleKey/client.lua rename to resources/[Developer]/sn_vehicleKey/client.lua index 1eb6c477c..cd3b39fda 100644 --- a/resources/[carscripts]/sn_vehicleKey/client.lua +++ b/resources/[Developer]/sn_vehicleKey/client.lua @@ -1,954 +1,954 @@ --- error when both menus are enabled -if (Config.useContextMenu and Config.useNativeUI) then - print("^1[ERROR] You can use only one menu or no menu at all. You cannot use both menus." - .. "\nMake sure to set at least one to false in the config and to edit the fxmanifest accordingly!") -end - -local keymakers = {} - -local lockNotif = nil -local createNewKeyNotif = nil - -local LockStatus = { - Unlocked = 1, - Locked = 2 -} - -local CB = exports["kimi_callbacks"] - -local menuPoolNativeUI -local keymakerMenuNativeUI -local keyInvMenuNativeUI -if (Config.useNativeUI) then - if (NativeUI == nil) then - print("^1[ERROR] NativeUI was not properly initialized! Make sure to install NativeUI and start it before this resource!") - end - - menuPoolNativeUI = NativeUI.CreatePool() - keymakerMenuNativeUI = NativeUI.CreateMenu(Config.Strings.keymakerTitle, Config.Strings.keymakerSub) - keyInvMenuNativeUI = NativeUI.CreateMenu(Config.Strings.keyInvTitle, Config.Strings.keyInvSub) -end - -local isAtKeymaker = false -local menuOpen = false - --- create client side peds -Citizen.CreateThread(function() - for i, keymaker in ipairs(Config.Keymakers) do - RequestModel(keymaker.model) - while not HasModelLoaded(keymaker.model) do - Citizen.Wait(0) - end - local ped = CreatePed(0, keymaker.model, keymaker.pos.x, keymaker.pos.y, keymaker.pos.z, keymaker.pos.w, false, true) - - SetBlockingOfNonTemporaryEvents(ped, true) - FreezeEntityPosition(ped, true) - SetEntityInvincible(ped, true) - - table.insert(keymakers, ped) - - -- add blip - local blip = AddBlipForCoord(keymaker.pos.x, keymaker.pos.y, keymaker.pos.z) - - SetBlipSprite(blip, 134) - SetBlipColour(blip, 0) - - SetBlipScale(blip, 1.0) - SetBlipDisplay(blip, 2) - SetBlipAsShortRange(blip, true) - - BeginTextCommandSetBlipName('STRING') - AddTextComponentSubstringPlayerName(Config.Strings.keymaker) - EndTextCommandSetBlipName(blip) - end -end) - --- main loop -Citizen.CreateThread(function() - while (true) do - Citizen.Wait(0) - - if (Config.useNativeUI) then - if (menuOpen) then - menuPoolNativeUI:ProcessMenus() - end - - if (isAtKeymaker) then - if (not menuOpen) then - ShowHelpText(Config.Strings.helpText) - end - - if (IsControlJustPressed(0, 51)) then - if (menuPoolNativeUI:IsAnyMenuOpen()) then - menuPoolNativeUI:CloseAllMenus() - menuOpen = false - else - GenerateKeymakerMenuNativeUI() - keymakerMenuNativeUI:Visible(true) - menuOpen = true - end - end - end - - - if (IsControlJustPressed(0, Config.keyMenuKey)) then - if (menuPoolNativeUI:IsAnyMenuOpen()) then - menuPoolNativeUI:CloseAllMenus() - menuOpen = false - else - GenerateKeyInventoryNativeUI() - keyInvMenuNativeUI:Visible(true) - menuOpen = true - end - end - end - - -- lock vehicle with key - --[[ if (Config.lockKey and IsControlJustPressed(0, Config.lockKey)) then - local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0) - if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then - ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked) - end - end ]] - end -end) - - - --- ContextMenu -if (Config.useContextMenu) then - local menuPool = MenuPool() - menuPool.OnOpenMenu = function(screenPosition, hitSomething, worldPosition, hitEntity, normalDirection) - local playerPos = GetEntityCoords(PlayerPedId()) - if (Vdist(worldPosition.x, worldPosition.y, worldPosition.z, playerPos.x, playerPos.y, playerPos.z) < Config.maxDistance) then - CreateMenu(screenPosition, hitEntity) - end - end - - function CreateMenu(screenPosition, hitEntity) - menuPool:Reset() - - if (hitEntity) then - if (hitEntity == PlayerPedId()) then - local vehicleData = CB:Trigger("VKC:getPlayerVehicleData") - local ownedKeys = GetPlayerKeys() - - menuPool:Reset() - - local playerMenu = menuPool:AddMenu() - - local ownVehMenu, ownVehMenuItem = menuPool:AddSubmenu(playerMenu, Config.Strings.CM.masterKeysTitle) - for i, vehicle in ipairs(vehicleData) do - local plate = vehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicle[2]) - end - - local item = ownVehMenu:AddItem(model .. " " .. plate) - end - - local ownKeyMenu, ownKeyMenuItem = menuPool:AddSubmenu(playerMenu, Config.Strings.CM.keysTitle) - for i, key in ipairs(ownedKeys) do - local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model)) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(key.model) - end - - local item = ownKeyMenu:AddItem(model .. " " .. key.plate) - item.rightText = Text("x" .. key.count) - end - - -- Fahrzeugübergabe-Menü hinzufügen - local transferVehMenu, transferVehMenuItem = menuPool:AddSubmenu(playerMenu, "Fahrzeug übergeben") - for i, vehicle in ipairs(vehicleData) do - local plate = vehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicle[2]) - end - - local item = transferVehMenu:AddItem(model .. " " .. plate) - item.closeMenuOnClick = true - item.OnClick = function() - -- Finde den nächsten Spieler - local player = GetClosestPlayer(5.0) - - if player then - local targetPlayerId = GetPlayerServerId(player) - local playerName = GetPlayerName(player) - - local success = CB:Trigger("VKC:transferVehicleOwnership", plate, targetPlayerId) - - if success then - Notification(string.format("Du hast dein %s an %s übergeben", model, playerName)) - else - Notification("Übergabe fehlgeschlagen") - end - else - Notification("Kein Spieler in der Nähe gefunden") - end - end - end - - playerMenu:SetPosition(screenPosition) - playerMenu:Visible(true) - elseif (IsEntityAKeymaker(hitEntity)) then - local vehicleData = GetPlayerVehicleData() - local ownedKeys = GetPlayerKeys() - - menuPool:Reset() - - local keymakerMenu = menuPool:AddMenu() - - local createKeyMenu, createKeyMenuItem = menuPool:AddSubmenu(keymakerMenu, Config.Strings.CM.createKeyTitle) - for i, vehicle in ipairs(vehicleData) do - local plate = vehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicle[2]) - end - local keyCount = GetKeyCount(plate, ownedKeys) - - local keyItem = createKeyMenu:AddItem(model .. " " .. plate) - keyItem.rightText = Text("x" .. tostring(keyCount)) - keyItem.OnClick = function() - local result = CB:Trigger("VKC:createNewKey", plate, 1) - if (type(result) == "boolean" and result == true) then - Notification(string.format(Config.Strings.createSuccess, model)) - - local oldCount = keyItem.rightText.title:gsub("x", "") - keyItem.rightText.title = "x" .. tostring(tonumber(oldCount) + 1) - elseif (type(result) == "string" and result == "noMoney") then - Notification(string.format(Config.Strings.createNoMoney, model)) - else - Notification(string.format(Config.Strings.createFailed, model)) - end - end - end - - local invalidateKeyMenu, invalidateKeyMenuItem = menuPool:AddSubmenu(keymakerMenu, Config.Strings.CM.invalKeyTitle) - for i, vehicle in ipairs(vehicleData) do - local plate = vehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicle[2]) - end - - local item = invalidateKeyMenu:AddItem(model .. " " .. plate) - item.closeMenuOnClick = true - item.OnClick = function() - local result = CB:Trigger("VKC:removeAllKeys", plate) - if (type(result) == "boolean" and result == true) then - Notification(string.format(Config.Strings.deleteKeys, model)) - elseif (type(result) == "string" and result == "noMoney") then - Notification(string.format(Config.Strings.removeNoMoney, vehName)) - else - Notification(string.format(Config.Strings.removeFailed, vehName)) - end - end - end - - keymakerMenu:SetPosition(screenPosition) - keymakerMenu:Visible(true) - elseif (IsEntityAPed(hitEntity) and IsPedAPlayer(hitEntity)) then - local ownedKeys = GetPlayerKeys() - - menuPool:Reset() - - local interactMenu = menuPool:AddMenu() - - local giveKeyMenu, giveKeyMenuItem = menuPool:AddSubmenu(interactMenu, Config.Strings.CM.giveKey) - for i, key in ipairs(ownedKeys) do - local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model)) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(key.model) - end - - local keyItem = giveKeyMenu:AddItem(model .. " " .. key.plate) - keyItem.rightText = Text("x" .. key.count) - keyItem.closeMenuOnClick = true - keyItem.OnClick = function() - local players = GetActivePlayers() - for i, player in ipairs(players) do - if (GetPlayerPed(player) == hitEntity) then - local success = CB:Trigger("VKC:giveKeyToPlayer", key.plate, GetPlayerServerId(player)) - if (success) then - Notification(string.format(Config.Strings.giveSuccess, model)) - else - Notification(string.format(Config.Strings.giveFailed, model)) - end - - break - end - end - end - end - - interactMenu:SetPosition(screenPosition) - interactMenu:Visible(true) - end - end - end - - function IsEntityAKeymaker(entity) - for i, keymaker in ipairs(keymakers) do - if (entity == keymaker) then - return true - end - end - - return false - end -end - - - --- NativeUI -function GenerateKeymakerMenuNativeUI() - keymakerMenuNativeUI:Clear() - - local vehicleData = GetPlayerVehicleData() - local ownedKeys = GetPlayerKeys() - - keymakerMenuNativeUI = NativeUI.CreateMenu(Config.Strings.NUI.keymakerMenuTitle, Config.Strings.NUI.keymakerMenuSub) - menuPoolNativeUI:Add(keymakerMenuNativeUI) - - local submenuCreateKey = menuPoolNativeUI:AddSubMenu(keymakerMenuNativeUI, Config.Strings.NUI.createKeyTitle, Config.Strings.NUI.createKeyDesc) - submenuCreateKey.ParentItem:RightLabel(">") - submenuCreateKey.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.createKeyTitle - for i, vehicle in ipairs(vehicleData) do - local plate = vehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicle[2]) - end - local keyCount = GetKeyCount(plate, ownedKeys) - - local vehItem = NativeUI.CreateItem(model .. " " .. plate, string.format(Config.Strings.NUI.createVehicleKey, model, plate)) - vehItem:RightLabel("x" .. tostring(keyCount)) - - submenuCreateKey:AddItem(vehItem) - end - submenuCreateKey.OnItemSelect = function(menu, item, index) - Citizen.CreateThread(function() - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicleData[index][2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicleData[index][2]) - end - - local result = CB:Trigger("VKC:createNewKey", vehicleData[index][1], 1) - if (type(result) == "boolean" and result == true) then - Notification(string.format(Config.Strings.createSuccess, model)) - - if (submenuCreateKey:Visible()) then - local oldCount = item.Label.Text._Text:gsub("x", "") - item:RightLabel("x" .. tostring(tonumber(oldCount) + 1)) - end - elseif (type(result) == "string" and result == "noMoney") then - Notification(string.format(Config.Strings.createNoMoney, model)) - else - Notification(string.format(Config.Strings.createFailed, model)) - end - end) - end - - local submenuInvalidateKey = menuPoolNativeUI:AddSubMenu(keymakerMenuNativeUI, Config.Strings.NUI.invalKeyTitle, Config.Strings.NUI.invalKeyDesc) - submenuInvalidateKey.ParentItem:RightLabel(">") - submenuInvalidateKey.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.invalKeyTitle - for i, vehicle in ipairs(vehicleData) do - local plate = vehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicle[2]) - end - - local keyItem = NativeUI.CreateItem(model .. " " .. plate, string.format(Config.Strings.NUI.invalVehicleKey, model, plate)) - submenuInvalidateKey:AddItem(keyItem) - end - submenuInvalidateKey.OnItemSelect = function(menu, item, index) - Citizen.CreateThread(function() - local result = CB:Trigger("VKC:removeAllKeys", vehicleData[index][1]) - - if (type(result) == "boolean" and result == true) then - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicleData[index][2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicleData[index][2]) - end - Notification(string.format(Config.Strings.deleteKeys, model)) - elseif (type(result) == "string" and result == "noMoney") then - Notification(string.format(Config.Strings.removeNoMoney, vehName)) - else - Notification(string.format(Config.Strings.removeFailed, vehName)) - end - end) - end - - keymakerMenuNativeUI.OnMenuClosed = function(menu) - menuOpen = false - end - - menuPoolNativeUI:ControlDisablingEnabled(false) - menuPoolNativeUI:MouseControlsEnabled(false) - - menuPoolNativeUI:RefreshIndex() -end - -function GenerateKeyInventoryNativeUI() - keyInvMenuNativeUI:Clear() - - local vehicleData = GetPlayerVehicleData() - local ownedKeys = GetPlayerKeys() - - keyInvMenuNativeUI = NativeUI.CreateMenu(Config.Strings.NUI.keyInventoryTitle, Config.Strings.NUI.keyInventorySub) - menuPoolNativeUI:Add(keyInvMenuNativeUI) - - local submenuShowMasterKeys = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, Config.Strings.NUI.masterKeysTitle, Config.Strings.NUI.masterKeysDesc) - submenuShowMasterKeys.ParentItem:RightLabel(">") - submenuShowMasterKeys.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.masterKeysTitle - for i, vehicle in ipairs(vehicleData) do - local plate = vehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicle[2]) - end - --local keyCount = GetKeyCount(plate, ownedKeys) - - local vehItem = NativeUI.CreateItem(model .. " " .. plate, "") - --vehItem:RightLabel("x" .. tostring(keyCount)) - submenuShowMasterKeys:AddItem(vehItem) - end - - -- Fahrzeugübergabe-Untermenü hinzufügen - local submenuTransferVehicle = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, "Fahrzeug übergeben", "Übertrage ein Fahrzeug an einen Spieler in der Nähe") - submenuTransferVehicle.ParentItem:RightLabel(">") - submenuTransferVehicle.Subtitle.Text._Text = "~b~Fahrzeug übergeben" - for i, vehicle in ipairs(vehicleData) do - local plate = vehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(vehicle[2]) - end - - local vehItem = NativeUI.CreateItem(model .. " " .. plate, "Wähle dieses Fahrzeug zum Übergeben") - submenuTransferVehicle:AddItem(vehItem) - end - - submenuTransferVehicle.OnItemSelect = function(menu, item, index) - local selectedVehicle = vehicleData[index] - local plate = selectedVehicle[1] - local model = GetLabelText(GetDisplayNameFromVehicleModel(selectedVehicle[2])) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(selectedVehicle[2]) - end - - -- Finde den nächsten Spieler - local player = GetClosestPlayer(5.0) - - if player then - local targetPlayerId = GetPlayerServerId(player) - local playerName = GetPlayerName(player) - - local success = CB:Trigger("VKC:transferVehicleOwnership", plate, targetPlayerId) - - if success then - lib.notify({ - title = "Fahrzeug übergeben", - description = "Du hast dein " .. model .. " an " .. playerName .. " übergeben", - position = "top", - type = "success", - icon = "car" - }) - else - lib.notify({ - title = "Fahrzeug übergeben", - description = "Übergabe fehlgeschlagen", - position = "top", - type = "error", - icon = "car" - }) - end - else - lib.notify({ - title = "Fahrzeug übergeben", - description = "Kein Spieler in der Nähe gefunden", - position = "top", - type = "error", - icon = "car" - }) - end - - menuPoolNativeUI:CloseAllMenus() - menuOpen = false - end - - local submenuShowKeys = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, Config.Strings.NUI.keysTitle, Config.Strings.NUI.keysDesc) - submenuShowKeys.ParentItem:RightLabel(">") - submenuShowKeys.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.keysTitle - for i, key in ipairs(ownedKeys) do - local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model)) - if (model == "NULL") then - model = GetDisplayNameFromVehicleModel(key.model) - end - - local submenuKey = menuPoolNativeUI:AddSubMenu(submenuShowKeys, model .. " " .. key.plate, "") - submenuKey.ParentItem:RightLabel("x" .. tostring(key.count) .. " >") - submenuKey.Subtitle.Text._Text = "~b~" .. model .. " " .. key.plate - - local giveItem = NativeUI.CreateItem(Config.Strings.NUI.giveKeyTitle, Config.Strings.NUI.giveKeyDesc) - submenuKey:AddItem(giveItem) - - local removeItem = NativeUI.CreateItem(Config.Strings.NUI.removeKeyTitle, Config.Strings.NUI.removeKeyDesc) - submenuKey:AddItem(removeItem) - - submenuKey.OnItemSelect = function(menu, item, index) - if (item == giveItem) then - Citizen.CreateThread(function() - local player = GetClosestPlayer(2.0) - if (player) then - local success = CB:Trigger("VKC:giveKeyToPlayer", key.plate, GetPlayerServerId(player)) - if (success) then - Notification(string.format(Config.Strings.giveSuccess, key.plate)) - else - Notification(string.format(Config.Strings.giveFailed, key.plate)) - end - else - Notification(string.format(Config.Strings.giveFailed, key.plate)) - end - end) - elseif (item == removeItem) then - Citizen.CreateThread(function() - local success = CB:Trigger("VKC:removeKey", key.plate, 1) - if (success) then - Notification(string.format(Config.Strings.removeSuccess, key.plate)) - - if (submenuShowKeys:Visible() or submenuKey:Visible()) then - local oldCount = submenuKey.ParentItem.Label.Text._Text:gsub("x", "") - oldCount = oldCount:gsub(" >", "") - submenuKey.ParentItem:RightLabel("x" .. tostring(tonumber(oldCount) - 1) .. " >") - end - else - Notification(string.format(Config.Strings.removeFailed, key.plate)) - end - end) - end - end - end - - keyInvMenuNativeUI.OnMenuClosed = function(menu) - menuOpen = false - end - - menuPoolNativeUI:ControlDisablingEnabled(false) - menuPoolNativeUI:MouseControlsEnabled(false) - - menuPoolNativeUI:RefreshIndex() -end - -if (Config.useNativeUI) then - Citizen.CreateThread(function() - while (true) do - Citizen.Wait(250) - - isAtKeymaker = false - - local pos = GetEntityCoords(PlayerPedId()) - for i, keymaker in ipairs(Config.Keymakers) do - if (Vdist(pos.x, pos.y, pos.z, keymaker.pos.x, keymaker.pos.y, keymaker.pos.z) < 2.0) then - isAtKeymaker = true - break - end - end - end - end) - - if (Config.keyMenuCommand) then - RegisterCommand(Config.keyMenuCommand, function(source, args, raw) - if (menuPoolNativeUI:IsAnyMenuOpen()) then - menuPoolNativeUI:CloseAllMenus() - end - - GenerateKeyInventoryNativeUI() - keyInvMenuNativeUI:Visible(true) - menuOpen = true - end, false) - end -end - - - --- lock vehicle -if (Config.lockCommand) then - RegisterCommand(Config.lockCommand, function(source, args, raw) - local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0) - if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then - ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked) - end - end, false) -end - -function ToggleLock(vehicle, lock) - local lockStatus = GetVehicleDoorLockStatus(vehicle) - - if (NetworkHasControlOfEntity(vehicle)) then - ToggleLockOnVehicle(vehicle, lock) - else - TriggerServerEvent("VKC:toggleLockNet", NetworkGetNetworkIdFromEntity(vehicle), lock) - end - - -- play sound - TriggerServerEvent("VKC:playDoorLockSoundNet", NetworkGetNetworkIdFromEntity(vehicle), lock) - - -- play remote animation - if (not IsPedInAnyVehicle(PlayerPedId(), false)) then - PlayRemoteAnimation() - end - - -- show notification - --[[ - if (lockNotif) then - RemoveNotification(lockNotif) - end - lockNotif = Notification(lockStatus == LockStatus.Locked and Config.Strings.unlockNotif or Config.Strings.lockNotif) - ]] -end - -function ToggleLockOnVehicle(vehicle, lock) - if (lock) then - SetVehicleDoorsShut(vehicle, false) - SetVehicleDoorsLocked(vehicle, LockStatus.Locked) - --exports['okokNotify']:Alert("Fahrzeug", "Du hast dein Fahrzeug Abgeschlossen", 3000, 'error') - lib.notify({ - title = "Fahrzeug", - description = "Du hast dein Fahrzeug Abgeschlossen", - position = "top", - type = "error", - icon = "car" - }) - - - SetVehicleLights(vehicle, 2) - Citizen.Wait(150) - SetVehicleLights(vehicle, 0) - Citizen.Wait(150) - SetVehicleLights(vehicle, 2) - Citizen.Wait(150) - SetVehicleLights(vehicle, 0) - else - SetVehicleDoorsLocked(vehicle, LockStatus.Unlocked) - --exports['okokNotify']:Alert("Fahrzeug", "Du hast dein Fahrzeug Aufgeschlossen", 3000, 'success') - lib.notify({ - title = "Fahrzeug", - description = "Du hast dein Fahrzeug Aufgeschlossen", - position = "top", - type = "success", - icon = "car" - }) - - SetVehicleLights(vehicle, 2) - Citizen.Wait(150) - SetVehicleLights(vehicle, 0) - Citizen.Wait(150) - SetVehicleLights(vehicle, 2) - Citizen.Wait(150) - SetVehicleLights(vehicle, 0) - Citizen.Wait(150) - SetVehicleLights(vehicle, 2) - Citizen.Wait(150) - SetVehicleLights(vehicle, 0) - Citizen.Wait(150) - SetVehicleLights(vehicle, 2) - Citizen.Wait(150) - SetVehicleLights(vehicle, 0) - Citizen.Wait(150) - SetVehicleLights(vehicle, 2) - Citizen.Wait(150) - SetVehicleLights(vehicle, 0) - end -end - -function PlayDoorLockSound(vehicle, lock) - if (lock) then - PlayVehicleDoorCloseSound(vehicle, 0) - else - PlayVehicleDoorOpenSound(vehicle, 0) - end -end - -if (Config.lockCommand or Config.lockKey) then - RegisterNetEvent("VKC:toggleLockOnPlayer") - AddEventHandler("VKC:toggleLockOnPlayer", function(vehicleNetId, unlocked) - local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId) - if (DoesEntityExist(vehicle) and NetworkHasControlOfEntity(vehicle)) then - local lockStatus = GetVehicleDoorLockStatus(vehicle) - ToggleLockOnVehicle(vehicle, unlocked) - end - end) - - RegisterNetEvent("VKC:playDoorLockSound") - AddEventHandler("VKC:playDoorLockSound", function(vehicleNetId, lock) - local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId) - if (DoesEntityExist(vehicle)) then - PlayDoorLockSound(vehicle, lock) - end - end) -end - - - -RegisterNetEvent("VKC:giveKeyNotif") -AddEventHandler("VKC:giveKeyNotif", function(plate) - Notification(string.format(Config.Strings.giveSuccessPly, plate)) -end) - --- Ereignis für Fahrzeugübergabe-Benachrichtigung -RegisterNetEvent("VKC:vehicleTransferNotif") -AddEventHandler("VKC:vehicleTransferNotif", function(plate, model) - lib.notify({ - title = "Fahrzeug erhalten", - description = "Du hast ein " .. model .. " mit dem Kennzeichen " .. plate .. " erhalten", - position = "top", - type = "success", - icon = "car" - }) -end) - - -function IsVehicleOwner(vehicle) - if (not DoesEntityExist(vehicle)) then - print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsVehicleOwner\"!") - return - end - - return CB:Trigger("VKC:isVehicleOwner", GetVehicleNumberPlateText(vehicle)) -end - -function IsKeyOwner(vehicle) - if (not DoesEntityExist(vehicle)) then - print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsKeyOwner\"!") - return - end - - return CB:Trigger("VKC:isKeyOwner", GetVehicleNumberPlateText(vehicle), GetEntityModel(vehicle)) -end - -function IsVehicleOrKeyOwner(vehicle) - if (not DoesEntityExist(vehicle)) then - print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsVehicleOrKeyOwner\"!") - return - end - - return CB:Trigger("VKC:isVehicleOrKeyOwner", GetVehicleNumberPlateText(vehicle), GetEntityModel(vehicle)) -end - -function GetPlayerKeys() - return CB:Trigger("VKC:getPlayerKeys") -end - -function GetPlayerVehicleData() - return CB:Trigger("VKC:getPlayerVehicleData") -end - - - --- play lock animation -function PlayRemoteAnimation() - Citizen.CreateThread(function() - RequestModel(keyPropHash) - RequestAnimDict("anim@mp_player_intmenu@key_fob@") - while (not HasModelLoaded(keyPropHash) and not HasAnimDictLoaded("anim@mp_player_intmenu@key_fob@")) do - Citizen.Wait(0) - end - - local playerPed = PlayerPedId() - local playerPos = GetEntityCoords(playerPed) - - local keyObj = CreateObjectNoOffset(keyPropHash, playerPos.x, playerPos.y, playerPos.z, true, true, false) - SetModelAsNoLongerNeeded(keyPropHash) - - local boneIndex = GetEntityBoneIndexByName(playerPed, "IK_R_Hand") - local offset = vector3(0.08, 0.025, -0.01) - local rotOffset = vector3(0, 70, 140) - AttachEntityToEntity(keyObj, playerPed, boneIndex, offset.x, offset.y, offset.z, rotOffset.x, rotOffset.y, rotOffset.z, false, false, true, false, 2, true) - - TaskPlayAnim(playerPed, "anim@mp_player_intmenu@key_fob@", "fob_click_fp", 8.0, 8.0, -1, 48, 1, false, false, false) - RemoveAnimDict("anim@mp_player_intmenu@key_fob@") - - Citizen.Wait(1500) - - DeleteEntity(keyObj) - end) -end - --- show text in upper left corner -function ShowHelpText(text) - BeginTextCommandDisplayHelp('STRING') - AddTextComponentSubstringPlayerName(text) - EndTextCommandDisplayHelp(0, false, true, -1) -end - --- displays a notification and returns its handle -function Notification(text) - SetNotificationTextEntry('STRING') - AddTextComponentSubstringPlayerName(text) - return DrawNotification(false, true) -end - --- get key count -function GetKeyCount(plate, keyArray) - for i, key in ipairs(keyArray) do - if (plate == key.plate) then - return key.count - end - end - - return 0 -end - --- get all players -function GetAllPlayers() - local players = {} - - for k, v in ipairs(GetActivePlayers()) do - table.insert(players, v) - end - - return players -end - --- get the closest player -function GetClosestPlayer(maxRange) - local playerPed = PlayerPedId() - local players = GetAllPlayers() - - local playerCoords = GetEntityCoords(playerPed) - - local closestDistance = maxRange - local closestPlayer = nil - - for i=1, #players, 1 do - local coords = GetEntityCoords(GetPlayerPed(players[i])) - local dist = Vdist(playerCoords.x, playerCoords.y, playerCoords.z, coords.x, coords.y, coords.z) - if (dist < closestDistance and players[i] ~= PlayerId()) then - closestDistance = dist - closestPlayer = players[i] - end - end - - if (closestPlayer ~= nil and DoesEntityExist(GetPlayerPed(closestPlayer))) then - return closestPlayer - else - return nil - end -end - --- Return closest loaded vehicle entity or nil if no vehicle is found -function GetClosestVehicle(position, maxRadius) - local vehicles = GetAllVehicles() - local dist = maxRadius - local closestVehicle = nil - - for i=1, #vehicles, 1 do - local vehicleCoords = GetEntityCoords(vehicles[i]) - local tempDist = Vdist(vehicleCoords.x, vehicleCoords.y, vehicleCoords.z, position.x, position.y, position.z) - if (tempDist < dist) then - dist = tempDist - closestVehicle = vehicles[i] - end - end - - if (closestVehicle ~= nil and DoesEntityExist(closestVehicle)) then - return closestVehicle - else - return nil - end -end - --- Returns all loaded vehicles on client side -function GetAllVehicles() - local vehicles = {} - - for vehicle in EnumerateVehicles() do - table.insert(vehicles, vehicle) - end - - return vehicles -end - --- getting all vehicles -function EnumerateVehicles() - return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle) -end -function EnumerateEntities(initFunc, moveFunc, disposeFunc) - return coroutine.wrap(function() - local iter, id = initFunc() - if not id or id == 0 then - disposeFunc(iter) - return - end - - local enum = {handle = iter, destructor = disposeFunc} - setmetatable(enum, entityEnumerator) - - local next = true - repeat - coroutine.yield(id) - next, id = moveFunc(iter) - until not next - - enum.destructor, enum.handle = nil, nil - disposeFunc(iter) - end) -end -local entityEnumerator = { - __gc = function(enum) - if enum.destructor and enum.handle then - enum.destructor(enum.handle) - end - enum.destructor = nil - enum.handle = nil - end -} - ---[[ - RegisterCommand("plate", function(source, args, raw) - local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0) - if (DoesEntityExist(vehicle)) then - SetVehicleNumberPlateText(vehicle, args[1]) - end - end, false) -]] - - -RegisterKeyMapping("vehicleLock", "Vehicle Lock", "keyboard", "PAGEUP") -RegisterCommand("vehicleLock", function() - local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0) - if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then - ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked) - end -end, false) - --- Integration mit dem Mietfahrzeug-System -RegisterNetEvent('vehiclerental:client:checkRentalKeys') -AddEventHandler('vehiclerental:client:checkRentalKeys', function() - TriggerServerEvent('vehiclerental:server:checkRentalKeys') -end) - --- Überprüfe Mietfahrzeug-Schlüssel beim Öffnen des Schlüssel-Menüs -if Config.useNativeUI then - -- Speichere die ursprüngliche Funktion - local originalGenerateKeyInventoryNativeUI = GenerateKeyInventoryNativeUI - - -- Überschreibe die Funktion - GenerateKeyInventoryNativeUI = function() - -- Überprüfe Mietfahrzeug-Schlüssel - TriggerServerEvent('vehiclerental:server:checkRentalKeys') - - -- Warte kurz, damit die Schlüssel aktualisiert werden können - Citizen.Wait(100) - - -- Rufe die ursprüngliche Funktion auf - originalGenerateKeyInventoryNativeUI() - end -end - +-- error when both menus are enabled +if (Config.useContextMenu and Config.useNativeUI) then + print("^1[ERROR] You can use only one menu or no menu at all. You cannot use both menus." + .. "\nMake sure to set at least one to false in the config and to edit the fxmanifest accordingly!") +end + +local keymakers = {} + +local lockNotif = nil +local createNewKeyNotif = nil + +local LockStatus = { + Unlocked = 1, + Locked = 2 +} + +local CB = exports["kimi_callbacks"] + +local menuPoolNativeUI +local keymakerMenuNativeUI +local keyInvMenuNativeUI +if (Config.useNativeUI) then + if (NativeUI == nil) then + print("^1[ERROR] NativeUI was not properly initialized! Make sure to install NativeUI and start it before this resource!") + end + + menuPoolNativeUI = NativeUI.CreatePool() + keymakerMenuNativeUI = NativeUI.CreateMenu(Config.Strings.keymakerTitle, Config.Strings.keymakerSub) + keyInvMenuNativeUI = NativeUI.CreateMenu(Config.Strings.keyInvTitle, Config.Strings.keyInvSub) +end + +local isAtKeymaker = false +local menuOpen = false + +-- create client side peds +Citizen.CreateThread(function() + for i, keymaker in ipairs(Config.Keymakers) do + RequestModel(keymaker.model) + while not HasModelLoaded(keymaker.model) do + Citizen.Wait(0) + end + local ped = CreatePed(0, keymaker.model, keymaker.pos.x, keymaker.pos.y, keymaker.pos.z, keymaker.pos.w, false, true) + + SetBlockingOfNonTemporaryEvents(ped, true) + FreezeEntityPosition(ped, true) + SetEntityInvincible(ped, true) + + table.insert(keymakers, ped) + + -- add blip + local blip = AddBlipForCoord(keymaker.pos.x, keymaker.pos.y, keymaker.pos.z) + + SetBlipSprite(blip, 134) + SetBlipColour(blip, 0) + + SetBlipScale(blip, 1.0) + SetBlipDisplay(blip, 2) + SetBlipAsShortRange(blip, true) + + BeginTextCommandSetBlipName('STRING') + AddTextComponentSubstringPlayerName(Config.Strings.keymaker) + EndTextCommandSetBlipName(blip) + end +end) + +-- main loop +Citizen.CreateThread(function() + while (true) do + Citizen.Wait(0) + + if (Config.useNativeUI) then + if (menuOpen) then + menuPoolNativeUI:ProcessMenus() + end + + if (isAtKeymaker) then + if (not menuOpen) then + ShowHelpText(Config.Strings.helpText) + end + + if (IsControlJustPressed(0, 51)) then + if (menuPoolNativeUI:IsAnyMenuOpen()) then + menuPoolNativeUI:CloseAllMenus() + menuOpen = false + else + GenerateKeymakerMenuNativeUI() + keymakerMenuNativeUI:Visible(true) + menuOpen = true + end + end + end + + + if (IsControlJustPressed(0, Config.keyMenuKey)) then + if (menuPoolNativeUI:IsAnyMenuOpen()) then + menuPoolNativeUI:CloseAllMenus() + menuOpen = false + else + GenerateKeyInventoryNativeUI() + keyInvMenuNativeUI:Visible(true) + menuOpen = true + end + end + end + + -- lock vehicle with key + --[[ if (Config.lockKey and IsControlJustPressed(0, Config.lockKey)) then + local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0) + if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then + ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked) + end + end ]] + end +end) + + + +-- ContextMenu +if (Config.useContextMenu) then + local menuPool = MenuPool() + menuPool.OnOpenMenu = function(screenPosition, hitSomething, worldPosition, hitEntity, normalDirection) + local playerPos = GetEntityCoords(PlayerPedId()) + if (Vdist(worldPosition.x, worldPosition.y, worldPosition.z, playerPos.x, playerPos.y, playerPos.z) < Config.maxDistance) then + CreateMenu(screenPosition, hitEntity) + end + end + + function CreateMenu(screenPosition, hitEntity) + menuPool:Reset() + + if (hitEntity) then + if (hitEntity == PlayerPedId()) then + local vehicleData = CB:Trigger("VKC:getPlayerVehicleData") + local ownedKeys = GetPlayerKeys() + + menuPool:Reset() + + local playerMenu = menuPool:AddMenu() + + local ownVehMenu, ownVehMenuItem = menuPool:AddSubmenu(playerMenu, Config.Strings.CM.masterKeysTitle) + for i, vehicle in ipairs(vehicleData) do + local plate = vehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicle[2]) + end + + local item = ownVehMenu:AddItem(model .. " " .. plate) + end + + local ownKeyMenu, ownKeyMenuItem = menuPool:AddSubmenu(playerMenu, Config.Strings.CM.keysTitle) + for i, key in ipairs(ownedKeys) do + local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model)) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(key.model) + end + + local item = ownKeyMenu:AddItem(model .. " " .. key.plate) + item.rightText = Text("x" .. key.count) + end + + -- Fahrzeugübergabe-Menü hinzufügen + local transferVehMenu, transferVehMenuItem = menuPool:AddSubmenu(playerMenu, "Fahrzeug übergeben") + for i, vehicle in ipairs(vehicleData) do + local plate = vehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicle[2]) + end + + local item = transferVehMenu:AddItem(model .. " " .. plate) + item.closeMenuOnClick = true + item.OnClick = function() + -- Finde den nächsten Spieler + local player = GetClosestPlayer(5.0) + + if player then + local targetPlayerId = GetPlayerServerId(player) + local playerName = GetPlayerName(player) + + local success = CB:Trigger("VKC:transferVehicleOwnership", plate, targetPlayerId) + + if success then + Notification(string.format("Du hast dein %s an %s übergeben", model, playerName)) + else + Notification("Übergabe fehlgeschlagen") + end + else + Notification("Kein Spieler in der Nähe gefunden") + end + end + end + + playerMenu:SetPosition(screenPosition) + playerMenu:Visible(true) + elseif (IsEntityAKeymaker(hitEntity)) then + local vehicleData = GetPlayerVehicleData() + local ownedKeys = GetPlayerKeys() + + menuPool:Reset() + + local keymakerMenu = menuPool:AddMenu() + + local createKeyMenu, createKeyMenuItem = menuPool:AddSubmenu(keymakerMenu, Config.Strings.CM.createKeyTitle) + for i, vehicle in ipairs(vehicleData) do + local plate = vehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicle[2]) + end + local keyCount = GetKeyCount(plate, ownedKeys) + + local keyItem = createKeyMenu:AddItem(model .. " " .. plate) + keyItem.rightText = Text("x" .. tostring(keyCount)) + keyItem.OnClick = function() + local result = CB:Trigger("VKC:createNewKey", plate, 1) + if (type(result) == "boolean" and result == true) then + Notification(string.format(Config.Strings.createSuccess, model)) + + local oldCount = keyItem.rightText.title:gsub("x", "") + keyItem.rightText.title = "x" .. tostring(tonumber(oldCount) + 1) + elseif (type(result) == "string" and result == "noMoney") then + Notification(string.format(Config.Strings.createNoMoney, model)) + else + Notification(string.format(Config.Strings.createFailed, model)) + end + end + end + + local invalidateKeyMenu, invalidateKeyMenuItem = menuPool:AddSubmenu(keymakerMenu, Config.Strings.CM.invalKeyTitle) + for i, vehicle in ipairs(vehicleData) do + local plate = vehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicle[2]) + end + + local item = invalidateKeyMenu:AddItem(model .. " " .. plate) + item.closeMenuOnClick = true + item.OnClick = function() + local result = CB:Trigger("VKC:removeAllKeys", plate) + if (type(result) == "boolean" and result == true) then + Notification(string.format(Config.Strings.deleteKeys, model)) + elseif (type(result) == "string" and result == "noMoney") then + Notification(string.format(Config.Strings.removeNoMoney, vehName)) + else + Notification(string.format(Config.Strings.removeFailed, vehName)) + end + end + end + + keymakerMenu:SetPosition(screenPosition) + keymakerMenu:Visible(true) + elseif (IsEntityAPed(hitEntity) and IsPedAPlayer(hitEntity)) then + local ownedKeys = GetPlayerKeys() + + menuPool:Reset() + + local interactMenu = menuPool:AddMenu() + + local giveKeyMenu, giveKeyMenuItem = menuPool:AddSubmenu(interactMenu, Config.Strings.CM.giveKey) + for i, key in ipairs(ownedKeys) do + local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model)) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(key.model) + end + + local keyItem = giveKeyMenu:AddItem(model .. " " .. key.plate) + keyItem.rightText = Text("x" .. key.count) + keyItem.closeMenuOnClick = true + keyItem.OnClick = function() + local players = GetActivePlayers() + for i, player in ipairs(players) do + if (GetPlayerPed(player) == hitEntity) then + local success = CB:Trigger("VKC:giveKeyToPlayer", key.plate, GetPlayerServerId(player)) + if (success) then + Notification(string.format(Config.Strings.giveSuccess, model)) + else + Notification(string.format(Config.Strings.giveFailed, model)) + end + + break + end + end + end + end + + interactMenu:SetPosition(screenPosition) + interactMenu:Visible(true) + end + end + end + + function IsEntityAKeymaker(entity) + for i, keymaker in ipairs(keymakers) do + if (entity == keymaker) then + return true + end + end + + return false + end +end + + + +-- NativeUI +function GenerateKeymakerMenuNativeUI() + keymakerMenuNativeUI:Clear() + + local vehicleData = GetPlayerVehicleData() + local ownedKeys = GetPlayerKeys() + + keymakerMenuNativeUI = NativeUI.CreateMenu(Config.Strings.NUI.keymakerMenuTitle, Config.Strings.NUI.keymakerMenuSub) + menuPoolNativeUI:Add(keymakerMenuNativeUI) + + local submenuCreateKey = menuPoolNativeUI:AddSubMenu(keymakerMenuNativeUI, Config.Strings.NUI.createKeyTitle, Config.Strings.NUI.createKeyDesc) + submenuCreateKey.ParentItem:RightLabel(">") + submenuCreateKey.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.createKeyTitle + for i, vehicle in ipairs(vehicleData) do + local plate = vehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicle[2]) + end + local keyCount = GetKeyCount(plate, ownedKeys) + + local vehItem = NativeUI.CreateItem(model .. " " .. plate, string.format(Config.Strings.NUI.createVehicleKey, model, plate)) + vehItem:RightLabel("x" .. tostring(keyCount)) + + submenuCreateKey:AddItem(vehItem) + end + submenuCreateKey.OnItemSelect = function(menu, item, index) + Citizen.CreateThread(function() + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicleData[index][2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicleData[index][2]) + end + + local result = CB:Trigger("VKC:createNewKey", vehicleData[index][1], 1) + if (type(result) == "boolean" and result == true) then + Notification(string.format(Config.Strings.createSuccess, model)) + + if (submenuCreateKey:Visible()) then + local oldCount = item.Label.Text._Text:gsub("x", "") + item:RightLabel("x" .. tostring(tonumber(oldCount) + 1)) + end + elseif (type(result) == "string" and result == "noMoney") then + Notification(string.format(Config.Strings.createNoMoney, model)) + else + Notification(string.format(Config.Strings.createFailed, model)) + end + end) + end + + local submenuInvalidateKey = menuPoolNativeUI:AddSubMenu(keymakerMenuNativeUI, Config.Strings.NUI.invalKeyTitle, Config.Strings.NUI.invalKeyDesc) + submenuInvalidateKey.ParentItem:RightLabel(">") + submenuInvalidateKey.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.invalKeyTitle + for i, vehicle in ipairs(vehicleData) do + local plate = vehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicle[2]) + end + + local keyItem = NativeUI.CreateItem(model .. " " .. plate, string.format(Config.Strings.NUI.invalVehicleKey, model, plate)) + submenuInvalidateKey:AddItem(keyItem) + end + submenuInvalidateKey.OnItemSelect = function(menu, item, index) + Citizen.CreateThread(function() + local result = CB:Trigger("VKC:removeAllKeys", vehicleData[index][1]) + + if (type(result) == "boolean" and result == true) then + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicleData[index][2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicleData[index][2]) + end + Notification(string.format(Config.Strings.deleteKeys, model)) + elseif (type(result) == "string" and result == "noMoney") then + Notification(string.format(Config.Strings.removeNoMoney, vehName)) + else + Notification(string.format(Config.Strings.removeFailed, vehName)) + end + end) + end + + keymakerMenuNativeUI.OnMenuClosed = function(menu) + menuOpen = false + end + + menuPoolNativeUI:ControlDisablingEnabled(false) + menuPoolNativeUI:MouseControlsEnabled(false) + + menuPoolNativeUI:RefreshIndex() +end + +function GenerateKeyInventoryNativeUI() + keyInvMenuNativeUI:Clear() + + local vehicleData = GetPlayerVehicleData() + local ownedKeys = GetPlayerKeys() + + keyInvMenuNativeUI = NativeUI.CreateMenu(Config.Strings.NUI.keyInventoryTitle, Config.Strings.NUI.keyInventorySub) + menuPoolNativeUI:Add(keyInvMenuNativeUI) + + local submenuShowMasterKeys = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, Config.Strings.NUI.masterKeysTitle, Config.Strings.NUI.masterKeysDesc) + submenuShowMasterKeys.ParentItem:RightLabel(">") + submenuShowMasterKeys.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.masterKeysTitle + for i, vehicle in ipairs(vehicleData) do + local plate = vehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicle[2]) + end + --local keyCount = GetKeyCount(plate, ownedKeys) + + local vehItem = NativeUI.CreateItem(model .. " " .. plate, "") + --vehItem:RightLabel("x" .. tostring(keyCount)) + submenuShowMasterKeys:AddItem(vehItem) + end + + -- Fahrzeugübergabe-Untermenü hinzufügen + local submenuTransferVehicle = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, "Fahrzeug übergeben", "Übertrage ein Fahrzeug an einen Spieler in der Nähe") + submenuTransferVehicle.ParentItem:RightLabel(">") + submenuTransferVehicle.Subtitle.Text._Text = "~b~Fahrzeug übergeben" + for i, vehicle in ipairs(vehicleData) do + local plate = vehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(vehicle[2]) + end + + local vehItem = NativeUI.CreateItem(model .. " " .. plate, "Wähle dieses Fahrzeug zum Übergeben") + submenuTransferVehicle:AddItem(vehItem) + end + + submenuTransferVehicle.OnItemSelect = function(menu, item, index) + local selectedVehicle = vehicleData[index] + local plate = selectedVehicle[1] + local model = GetLabelText(GetDisplayNameFromVehicleModel(selectedVehicle[2])) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(selectedVehicle[2]) + end + + -- Finde den nächsten Spieler + local player = GetClosestPlayer(5.0) + + if player then + local targetPlayerId = GetPlayerServerId(player) + local playerName = GetPlayerName(player) + + local success = CB:Trigger("VKC:transferVehicleOwnership", plate, targetPlayerId) + + if success then + lib.notify({ + title = "Fahrzeug übergeben", + description = "Du hast dein " .. model .. " an " .. playerName .. " übergeben", + position = "top", + type = "success", + icon = "car" + }) + else + lib.notify({ + title = "Fahrzeug übergeben", + description = "Übergabe fehlgeschlagen", + position = "top", + type = "error", + icon = "car" + }) + end + else + lib.notify({ + title = "Fahrzeug übergeben", + description = "Kein Spieler in der Nähe gefunden", + position = "top", + type = "error", + icon = "car" + }) + end + + menuPoolNativeUI:CloseAllMenus() + menuOpen = false + end + + local submenuShowKeys = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, Config.Strings.NUI.keysTitle, Config.Strings.NUI.keysDesc) + submenuShowKeys.ParentItem:RightLabel(">") + submenuShowKeys.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.keysTitle + for i, key in ipairs(ownedKeys) do + local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model)) + if (model == "NULL") then + model = GetDisplayNameFromVehicleModel(key.model) + end + + local submenuKey = menuPoolNativeUI:AddSubMenu(submenuShowKeys, model .. " " .. key.plate, "") + submenuKey.ParentItem:RightLabel("x" .. tostring(key.count) .. " >") + submenuKey.Subtitle.Text._Text = "~b~" .. model .. " " .. key.plate + + local giveItem = NativeUI.CreateItem(Config.Strings.NUI.giveKeyTitle, Config.Strings.NUI.giveKeyDesc) + submenuKey:AddItem(giveItem) + + local removeItem = NativeUI.CreateItem(Config.Strings.NUI.removeKeyTitle, Config.Strings.NUI.removeKeyDesc) + submenuKey:AddItem(removeItem) + + submenuKey.OnItemSelect = function(menu, item, index) + if (item == giveItem) then + Citizen.CreateThread(function() + local player = GetClosestPlayer(2.0) + if (player) then + local success = CB:Trigger("VKC:giveKeyToPlayer", key.plate, GetPlayerServerId(player)) + if (success) then + Notification(string.format(Config.Strings.giveSuccess, key.plate)) + else + Notification(string.format(Config.Strings.giveFailed, key.plate)) + end + else + Notification(string.format(Config.Strings.giveFailed, key.plate)) + end + end) + elseif (item == removeItem) then + Citizen.CreateThread(function() + local success = CB:Trigger("VKC:removeKey", key.plate, 1) + if (success) then + Notification(string.format(Config.Strings.removeSuccess, key.plate)) + + if (submenuShowKeys:Visible() or submenuKey:Visible()) then + local oldCount = submenuKey.ParentItem.Label.Text._Text:gsub("x", "") + oldCount = oldCount:gsub(" >", "") + submenuKey.ParentItem:RightLabel("x" .. tostring(tonumber(oldCount) - 1) .. " >") + end + else + Notification(string.format(Config.Strings.removeFailed, key.plate)) + end + end) + end + end + end + + keyInvMenuNativeUI.OnMenuClosed = function(menu) + menuOpen = false + end + + menuPoolNativeUI:ControlDisablingEnabled(false) + menuPoolNativeUI:MouseControlsEnabled(false) + + menuPoolNativeUI:RefreshIndex() +end + +if (Config.useNativeUI) then + Citizen.CreateThread(function() + while (true) do + Citizen.Wait(250) + + isAtKeymaker = false + + local pos = GetEntityCoords(PlayerPedId()) + for i, keymaker in ipairs(Config.Keymakers) do + if (Vdist(pos.x, pos.y, pos.z, keymaker.pos.x, keymaker.pos.y, keymaker.pos.z) < 2.0) then + isAtKeymaker = true + break + end + end + end + end) + + if (Config.keyMenuCommand) then + RegisterCommand(Config.keyMenuCommand, function(source, args, raw) + if (menuPoolNativeUI:IsAnyMenuOpen()) then + menuPoolNativeUI:CloseAllMenus() + end + + GenerateKeyInventoryNativeUI() + keyInvMenuNativeUI:Visible(true) + menuOpen = true + end, false) + end +end + + + +-- lock vehicle +if (Config.lockCommand) then + RegisterCommand(Config.lockCommand, function(source, args, raw) + local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0) + if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then + ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked) + end + end, false) +end + +function ToggleLock(vehicle, lock) + local lockStatus = GetVehicleDoorLockStatus(vehicle) + + if (NetworkHasControlOfEntity(vehicle)) then + ToggleLockOnVehicle(vehicle, lock) + else + TriggerServerEvent("VKC:toggleLockNet", NetworkGetNetworkIdFromEntity(vehicle), lock) + end + + -- play sound + TriggerServerEvent("VKC:playDoorLockSoundNet", NetworkGetNetworkIdFromEntity(vehicle), lock) + + -- play remote animation + if (not IsPedInAnyVehicle(PlayerPedId(), false)) then + PlayRemoteAnimation() + end + + -- show notification + --[[ + if (lockNotif) then + RemoveNotification(lockNotif) + end + lockNotif = Notification(lockStatus == LockStatus.Locked and Config.Strings.unlockNotif or Config.Strings.lockNotif) + ]] +end + +function ToggleLockOnVehicle(vehicle, lock) + if (lock) then + SetVehicleDoorsShut(vehicle, false) + SetVehicleDoorsLocked(vehicle, LockStatus.Locked) + --exports['okokNotify']:Alert("Fahrzeug", "Du hast dein Fahrzeug Abgeschlossen", 3000, 'error') + lib.notify({ + title = "Fahrzeug", + description = "Du hast dein Fahrzeug Abgeschlossen", + position = "top", + type = "error", + icon = "car" + }) + + + SetVehicleLights(vehicle, 2) + Citizen.Wait(150) + SetVehicleLights(vehicle, 0) + Citizen.Wait(150) + SetVehicleLights(vehicle, 2) + Citizen.Wait(150) + SetVehicleLights(vehicle, 0) + else + SetVehicleDoorsLocked(vehicle, LockStatus.Unlocked) + --exports['okokNotify']:Alert("Fahrzeug", "Du hast dein Fahrzeug Aufgeschlossen", 3000, 'success') + lib.notify({ + title = "Fahrzeug", + description = "Du hast dein Fahrzeug Aufgeschlossen", + position = "top", + type = "success", + icon = "car" + }) + + SetVehicleLights(vehicle, 2) + Citizen.Wait(150) + SetVehicleLights(vehicle, 0) + Citizen.Wait(150) + SetVehicleLights(vehicle, 2) + Citizen.Wait(150) + SetVehicleLights(vehicle, 0) + Citizen.Wait(150) + SetVehicleLights(vehicle, 2) + Citizen.Wait(150) + SetVehicleLights(vehicle, 0) + Citizen.Wait(150) + SetVehicleLights(vehicle, 2) + Citizen.Wait(150) + SetVehicleLights(vehicle, 0) + Citizen.Wait(150) + SetVehicleLights(vehicle, 2) + Citizen.Wait(150) + SetVehicleLights(vehicle, 0) + end +end + +function PlayDoorLockSound(vehicle, lock) + if (lock) then + PlayVehicleDoorCloseSound(vehicle, 0) + else + PlayVehicleDoorOpenSound(vehicle, 0) + end +end + +if (Config.lockCommand or Config.lockKey) then + RegisterNetEvent("VKC:toggleLockOnPlayer") + AddEventHandler("VKC:toggleLockOnPlayer", function(vehicleNetId, unlocked) + local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId) + if (DoesEntityExist(vehicle) and NetworkHasControlOfEntity(vehicle)) then + local lockStatus = GetVehicleDoorLockStatus(vehicle) + ToggleLockOnVehicle(vehicle, unlocked) + end + end) + + RegisterNetEvent("VKC:playDoorLockSound") + AddEventHandler("VKC:playDoorLockSound", function(vehicleNetId, lock) + local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId) + if (DoesEntityExist(vehicle)) then + PlayDoorLockSound(vehicle, lock) + end + end) +end + + + +RegisterNetEvent("VKC:giveKeyNotif") +AddEventHandler("VKC:giveKeyNotif", function(plate) + Notification(string.format(Config.Strings.giveSuccessPly, plate)) +end) + +-- Ereignis für Fahrzeugübergabe-Benachrichtigung +RegisterNetEvent("VKC:vehicleTransferNotif") +AddEventHandler("VKC:vehicleTransferNotif", function(plate, model) + lib.notify({ + title = "Fahrzeug erhalten", + description = "Du hast ein " .. model .. " mit dem Kennzeichen " .. plate .. " erhalten", + position = "top", + type = "success", + icon = "car" + }) +end) + + +function IsVehicleOwner(vehicle) + if (not DoesEntityExist(vehicle)) then + print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsVehicleOwner\"!") + return + end + + return CB:Trigger("VKC:isVehicleOwner", GetVehicleNumberPlateText(vehicle)) +end + +function IsKeyOwner(vehicle) + if (not DoesEntityExist(vehicle)) then + print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsKeyOwner\"!") + return + end + + return CB:Trigger("VKC:isKeyOwner", GetVehicleNumberPlateText(vehicle), GetEntityModel(vehicle)) +end + +function IsVehicleOrKeyOwner(vehicle) + if (not DoesEntityExist(vehicle)) then + print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsVehicleOrKeyOwner\"!") + return + end + + return CB:Trigger("VKC:isVehicleOrKeyOwner", GetVehicleNumberPlateText(vehicle), GetEntityModel(vehicle)) +end + +function GetPlayerKeys() + return CB:Trigger("VKC:getPlayerKeys") +end + +function GetPlayerVehicleData() + return CB:Trigger("VKC:getPlayerVehicleData") +end + + + +-- play lock animation +function PlayRemoteAnimation() + Citizen.CreateThread(function() + RequestModel(keyPropHash) + RequestAnimDict("anim@mp_player_intmenu@key_fob@") + while (not HasModelLoaded(keyPropHash) and not HasAnimDictLoaded("anim@mp_player_intmenu@key_fob@")) do + Citizen.Wait(0) + end + + local playerPed = PlayerPedId() + local playerPos = GetEntityCoords(playerPed) + + local keyObj = CreateObjectNoOffset(keyPropHash, playerPos.x, playerPos.y, playerPos.z, true, true, false) + SetModelAsNoLongerNeeded(keyPropHash) + + local boneIndex = GetEntityBoneIndexByName(playerPed, "IK_R_Hand") + local offset = vector3(0.08, 0.025, -0.01) + local rotOffset = vector3(0, 70, 140) + AttachEntityToEntity(keyObj, playerPed, boneIndex, offset.x, offset.y, offset.z, rotOffset.x, rotOffset.y, rotOffset.z, false, false, true, false, 2, true) + + TaskPlayAnim(playerPed, "anim@mp_player_intmenu@key_fob@", "fob_click_fp", 8.0, 8.0, -1, 48, 1, false, false, false) + RemoveAnimDict("anim@mp_player_intmenu@key_fob@") + + Citizen.Wait(1500) + + DeleteEntity(keyObj) + end) +end + +-- show text in upper left corner +function ShowHelpText(text) + BeginTextCommandDisplayHelp('STRING') + AddTextComponentSubstringPlayerName(text) + EndTextCommandDisplayHelp(0, false, true, -1) +end + +-- displays a notification and returns its handle +function Notification(text) + SetNotificationTextEntry('STRING') + AddTextComponentSubstringPlayerName(text) + return DrawNotification(false, true) +end + +-- get key count +function GetKeyCount(plate, keyArray) + for i, key in ipairs(keyArray) do + if (plate == key.plate) then + return key.count + end + end + + return 0 +end + +-- get all players +function GetAllPlayers() + local players = {} + + for k, v in ipairs(GetActivePlayers()) do + table.insert(players, v) + end + + return players +end + +-- get the closest player +function GetClosestPlayer(maxRange) + local playerPed = PlayerPedId() + local players = GetAllPlayers() + + local playerCoords = GetEntityCoords(playerPed) + + local closestDistance = maxRange + local closestPlayer = nil + + for i=1, #players, 1 do + local coords = GetEntityCoords(GetPlayerPed(players[i])) + local dist = Vdist(playerCoords.x, playerCoords.y, playerCoords.z, coords.x, coords.y, coords.z) + if (dist < closestDistance and players[i] ~= PlayerId()) then + closestDistance = dist + closestPlayer = players[i] + end + end + + if (closestPlayer ~= nil and DoesEntityExist(GetPlayerPed(closestPlayer))) then + return closestPlayer + else + return nil + end +end + +-- Return closest loaded vehicle entity or nil if no vehicle is found +function GetClosestVehicle(position, maxRadius) + local vehicles = GetAllVehicles() + local dist = maxRadius + local closestVehicle = nil + + for i=1, #vehicles, 1 do + local vehicleCoords = GetEntityCoords(vehicles[i]) + local tempDist = Vdist(vehicleCoords.x, vehicleCoords.y, vehicleCoords.z, position.x, position.y, position.z) + if (tempDist < dist) then + dist = tempDist + closestVehicle = vehicles[i] + end + end + + if (closestVehicle ~= nil and DoesEntityExist(closestVehicle)) then + return closestVehicle + else + return nil + end +end + +-- Returns all loaded vehicles on client side +function GetAllVehicles() + local vehicles = {} + + for vehicle in EnumerateVehicles() do + table.insert(vehicles, vehicle) + end + + return vehicles +end + +-- getting all vehicles +function EnumerateVehicles() + return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle) +end +function EnumerateEntities(initFunc, moveFunc, disposeFunc) + return coroutine.wrap(function() + local iter, id = initFunc() + if not id or id == 0 then + disposeFunc(iter) + return + end + + local enum = {handle = iter, destructor = disposeFunc} + setmetatable(enum, entityEnumerator) + + local next = true + repeat + coroutine.yield(id) + next, id = moveFunc(iter) + until not next + + enum.destructor, enum.handle = nil, nil + disposeFunc(iter) + end) +end +local entityEnumerator = { + __gc = function(enum) + if enum.destructor and enum.handle then + enum.destructor(enum.handle) + end + enum.destructor = nil + enum.handle = nil + end +} + +--[[ + RegisterCommand("plate", function(source, args, raw) + local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0) + if (DoesEntityExist(vehicle)) then + SetVehicleNumberPlateText(vehicle, args[1]) + end + end, false) +]] + + +RegisterKeyMapping("vehicleLock", "Vehicle Lock", "keyboard", "PAGEUP") +RegisterCommand("vehicleLock", function() + local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0) + if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then + ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked) + end +end, false) + +-- Integration mit dem Mietfahrzeug-System +RegisterNetEvent('vehiclerental:client:checkRentalKeys') +AddEventHandler('vehiclerental:client:checkRentalKeys', function() + TriggerServerEvent('vehiclerental:server:checkRentalKeys') +end) + +-- Überprüfe Mietfahrzeug-Schlüssel beim Öffnen des Schlüssel-Menüs +if Config.useNativeUI then + -- Speichere die ursprüngliche Funktion + local originalGenerateKeyInventoryNativeUI = GenerateKeyInventoryNativeUI + + -- Überschreibe die Funktion + GenerateKeyInventoryNativeUI = function() + -- Überprüfe Mietfahrzeug-Schlüssel + TriggerServerEvent('vehiclerental:server:checkRentalKeys') + + -- Warte kurz, damit die Schlüssel aktualisiert werden können + Citizen.Wait(100) + + -- Rufe die ursprüngliche Funktion auf + originalGenerateKeyInventoryNativeUI() + end +end + diff --git a/resources/[carscripts]/sn_vehicleKey/config.lua b/resources/[Developer]/sn_vehicleKey/config.lua similarity index 97% rename from resources/[carscripts]/sn_vehicleKey/config.lua rename to resources/[Developer]/sn_vehicleKey/config.lua index 6746abaa0..c79666444 100644 --- a/resources/[carscripts]/sn_vehicleKey/config.lua +++ b/resources/[Developer]/sn_vehicleKey/config.lua @@ -1,149 +1,149 @@ - -Config = {} - --- set at least one to false, otherwise both menus will clash --- and don't forget to comment the menu in the fxmanifest.lua if you don't use it! --- Setting both to true does not work! --- setting both to false results in no menu being usable at all --- you can then just include the exports in your own menu if you have one -Config.useContextMenu = false -Config.useNativeUI = true - --- set to nil if you don't want to use the command -Config.lockCommand = "lock" --- set to nil if you don't want to use the button (303, U) -Config.lockKey = 10 -- PageUp - --- set to nil if you don't want to use the command -Config.keyMenuCommand = "keys" --- set to nil if you don't want to use the button (311, K) -Config.keyMenuKey = 56 -- F9 - --- maximum distance (in meters) between the player and ContextMenu interaction point -Config.maxDistance = 5.0 - --- you can define more keymakers by just adding additional entries -Config.Keymakers = { - { - -- ped model (yes, the ` symbols are correct) - model = `s_m_m_autoshop_01`, - -- position and heading vector4(x, y, z, heading) - pos = vector4(170.33, -1799.13, 28.32, 313.0) - }, -} - --- define costs for creating a new key and exchanging locks -Config.Costs = { - GetMoney = "cash", -- cash or bank - newKey = 150, - exchangeLocks = 650 -} - --- define job vehicles like this (this acts as a key for those vehicles) --- models in `` --- either exact plates or just a string that should be in the vehicles plate --- e.g. "LSPD" will let a police officer lock/unlock any vehicle with the plate "LSPD1337" or "13LSPD37" -Config.JobVehicles = { --- examples: - --["police"] = { - --models = { - --`police`, - --`policeb`, - --`pbus` - --}, - --plates = { - --"" - --} - --}, - --["mechanic"] = { - -- models = { - -- `flatbed` - -- }, - -- plates = { - -- "MECH" - -- } - --}, -} - -Config.Strings = { - keymaker = "Schlüsseldienst", - - helpText = "~w~Drück ~g~E ~w~um mit den Schlüsseldienst zu reden", - - lockNotif = "~r~Fahrzeug Abgeschlossen", - unlockNotif = "~g~Fahrzeug Aufgeschlossen", - - createSuccess = "~g~Ersatzschlüssel Nachgemacht %s.", - createNoMoney = "~r~Schlüssel kann nicht nachgemacht werden, du hast zu wenig Geld dabei", - createFailed = "~r~Ersatzschlüssel machen Fehlgeschlagen %s!", - - giveSuccess = "~g~Schlüssel an %s Weitergegeben.", - giveSuccessPly = "~g~Schlüssel von %s erhalten ", - giveFailed = "~r~Schlüssel geben von %s Fehlgeschlagen", - - removeSuccess = "~r~Schlüssel für ~g~%s ~r~aus deiner Tasche Entfernt", - removeNoMoney = "~r~Schloss kann nicht bezahlt werden, du hast kein Geld dabei", - removeFailed = "~r~Entfernen von Schlüssel für ~g~%s ~r~Fehgeschlagen!", - - deleteKeys = "~r~Du hast für dein ~g~%s ~r~Das Schloss ausgetasucht, und somit sind jetzt alle Schlüssel nicht mehr Gültig.", - - - -- NativeUI - NUI = { - -- keymaker menu - keymakerMenuTitle = "Schlüssel-System", - keymakerMenuSub = "~g~Erstelle Schlüssel und Tausche deine Fahrzeug Schlösser aus", - - -- create key - createKeyTitle = "~g~Ersatzschlüssel erstellen", - createKeyDesc = "Erstelle einen neuen Schlüssel für eines Ihrer Fahrzeuge ", - createVehicleKey = "Erstelle einen Schlüssel für Ihr %s mit den Kennzeichen %s. ~g~Preis "..Config.Costs.newKey.."$", - - -- invalidate Key - invalKeyTitle = "~r~Fahrzeug Schlöss Tauschen", - invalKeyDesc = "Tausche die Schlösser von Ihren Auto aus, alle schlüssel sind damit nicht mehr Gültig!", - invalVehicleKey = "Schloss Tauschen von %s mit den Kennzeichen %s. ~g~Preis "..Config.Costs.exchangeLocks.."$", - - -- key Inventory - keyInventoryTitle = "Schlüssel", - keyInventorySub = "~g~Da sind alle deine Schlüssel", - - -- master keys - masterKeysTitle = "Hauptschlüssel", - masterKeysDesc = "~g~Zeigt alle deine Hauptschlüssel an", - - -- additional keys - keysTitle = "Ersatzschlüssel", - keysDesc = "~g~Zeigt alle deine Ersatzschlüssel an", - giveKeyTitle = "~g~Ersatzschlüssel Geben", - giveKeyDesc = "~g~Ersatzschlüssel Geben", - removeKeyTitle = "~r~Schlüssel Entfernen", - removeKeyDesc = "~r~Schlüssel Entfernen", - transferVehicleTitle = "~g~Fahrzeug übergeben", - transferVehicleDesc = "~g~Übertrage ein Fahrzeug an einen Spieler in der Nähe", - transferVehicleSuccess = "~g~Fahrzeug erfolgreich übergeben an %s", - transferVehicleFailed = "~r~Fahrzeugübergabe fehlgeschlagen", - transferVehicleReceived = "~g~Du hast ein Fahrzeug erhalten", - noPlayersNearby = "~r~Keine Spieler in der Nähe", - - - }, - - -- ContextMenu - CM = { - -- keymaker menu - createKeyTitle = "Ersatzschlüssel", - invalKeyTitle = "Schlossaustauschen", - - -- key inventory - masterKeysTitle = "~g~Hauptschlüssel", - keysTitle = "~b~Ersatzschlüssel", - - -- other player - giveKey = "~r~Gebe ein Schlüssel, an der Person", - - transferVehicleTitle = "Fahrzeug übergeben", - - } -} - + +Config = {} + +-- set at least one to false, otherwise both menus will clash +-- and don't forget to comment the menu in the fxmanifest.lua if you don't use it! +-- Setting both to true does not work! +-- setting both to false results in no menu being usable at all +-- you can then just include the exports in your own menu if you have one +Config.useContextMenu = false +Config.useNativeUI = true + +-- set to nil if you don't want to use the command +Config.lockCommand = "lock" +-- set to nil if you don't want to use the button (303, U) +Config.lockKey = 10 -- PageUp + +-- set to nil if you don't want to use the command +Config.keyMenuCommand = "keys" +-- set to nil if you don't want to use the button (311, K) +Config.keyMenuKey = 56 -- F9 + +-- maximum distance (in meters) between the player and ContextMenu interaction point +Config.maxDistance = 5.0 + +-- you can define more keymakers by just adding additional entries +Config.Keymakers = { + { + -- ped model (yes, the ` symbols are correct) + model = `s_m_m_autoshop_01`, + -- position and heading vector4(x, y, z, heading) + pos = vector4(170.33, -1799.13, 28.32, 313.0) + }, +} + +-- define costs for creating a new key and exchanging locks +Config.Costs = { + GetMoney = "cash", -- cash or bank + newKey = 150, + exchangeLocks = 650 +} + +-- define job vehicles like this (this acts as a key for those vehicles) +-- models in `` +-- either exact plates or just a string that should be in the vehicles plate +-- e.g. "LSPD" will let a police officer lock/unlock any vehicle with the plate "LSPD1337" or "13LSPD37" +Config.JobVehicles = { +-- examples: + --["police"] = { + --models = { + --`police`, + --`policeb`, + --`pbus` + --}, + --plates = { + --"" + --} + --}, + --["mechanic"] = { + -- models = { + -- `flatbed` + -- }, + -- plates = { + -- "MECH" + -- } + --}, +} + +Config.Strings = { + keymaker = "Schlüsseldienst", + + helpText = "~w~Drück ~g~E ~w~um mit den Schlüsseldienst zu reden", + + lockNotif = "~r~Fahrzeug Abgeschlossen", + unlockNotif = "~g~Fahrzeug Aufgeschlossen", + + createSuccess = "~g~Ersatzschlüssel Nachgemacht %s.", + createNoMoney = "~r~Schlüssel kann nicht nachgemacht werden, du hast zu wenig Geld dabei", + createFailed = "~r~Ersatzschlüssel machen Fehlgeschlagen %s!", + + giveSuccess = "~g~Schlüssel an %s Weitergegeben.", + giveSuccessPly = "~g~Schlüssel von %s erhalten ", + giveFailed = "~r~Schlüssel geben von %s Fehlgeschlagen", + + removeSuccess = "~r~Schlüssel für ~g~%s ~r~aus deiner Tasche Entfernt", + removeNoMoney = "~r~Schloss kann nicht bezahlt werden, du hast kein Geld dabei", + removeFailed = "~r~Entfernen von Schlüssel für ~g~%s ~r~Fehgeschlagen!", + + deleteKeys = "~r~Du hast für dein ~g~%s ~r~Das Schloss ausgetasucht, und somit sind jetzt alle Schlüssel nicht mehr Gültig.", + + + -- NativeUI + NUI = { + -- keymaker menu + keymakerMenuTitle = "Schlüssel-System", + keymakerMenuSub = "~g~Erstelle Schlüssel und Tausche deine Fahrzeug Schlösser aus", + + -- create key + createKeyTitle = "~g~Ersatzschlüssel erstellen", + createKeyDesc = "Erstelle einen neuen Schlüssel für eines Ihrer Fahrzeuge ", + createVehicleKey = "Erstelle einen Schlüssel für Ihr %s mit den Kennzeichen %s. ~g~Preis "..Config.Costs.newKey.."$", + + -- invalidate Key + invalKeyTitle = "~r~Fahrzeug Schlöss Tauschen", + invalKeyDesc = "Tausche die Schlösser von Ihren Auto aus, alle schlüssel sind damit nicht mehr Gültig!", + invalVehicleKey = "Schloss Tauschen von %s mit den Kennzeichen %s. ~g~Preis "..Config.Costs.exchangeLocks.."$", + + -- key Inventory + keyInventoryTitle = "Schlüssel", + keyInventorySub = "~g~Da sind alle deine Schlüssel", + + -- master keys + masterKeysTitle = "Hauptschlüssel", + masterKeysDesc = "~g~Zeigt alle deine Hauptschlüssel an", + + -- additional keys + keysTitle = "Ersatzschlüssel", + keysDesc = "~g~Zeigt alle deine Ersatzschlüssel an", + giveKeyTitle = "~g~Ersatzschlüssel Geben", + giveKeyDesc = "~g~Ersatzschlüssel Geben", + removeKeyTitle = "~r~Schlüssel Entfernen", + removeKeyDesc = "~r~Schlüssel Entfernen", + transferVehicleTitle = "~g~Fahrzeug übergeben", + transferVehicleDesc = "~g~Übertrage ein Fahrzeug an einen Spieler in der Nähe", + transferVehicleSuccess = "~g~Fahrzeug erfolgreich übergeben an %s", + transferVehicleFailed = "~r~Fahrzeugübergabe fehlgeschlagen", + transferVehicleReceived = "~g~Du hast ein Fahrzeug erhalten", + noPlayersNearby = "~r~Keine Spieler in der Nähe", + + + }, + + -- ContextMenu + CM = { + -- keymaker menu + createKeyTitle = "Ersatzschlüssel", + invalKeyTitle = "Schlossaustauschen", + + -- key inventory + masterKeysTitle = "~g~Hauptschlüssel", + keysTitle = "~b~Ersatzschlüssel", + + -- other player + giveKey = "~r~Gebe ein Schlüssel, an der Person", + + transferVehicleTitle = "Fahrzeug übergeben", + + } +} + diff --git a/resources/[carscripts]/sn_vehicleKey/fxmanifest.lua b/resources/[Developer]/sn_vehicleKey/fxmanifest.lua similarity index 95% rename from resources/[carscripts]/sn_vehicleKey/fxmanifest.lua rename to resources/[Developer]/sn_vehicleKey/fxmanifest.lua index d50237da2..8466e9ec2 100644 --- a/resources/[carscripts]/sn_vehicleKey/fxmanifest.lua +++ b/resources/[Developer]/sn_vehicleKey/fxmanifest.lua @@ -1,57 +1,57 @@ -fx_version 'cerulean' -games { 'gta5' } - -author 'Mîhó' -description 'Manage vehicle keys!' -version '1.1.1' - -dependency 'kimi_callbacks' -dependency 'NativeUI' - -server_scripts { - --'@mysql-async/lib/MySQL.lua', - '@oxmysql/lib/MySQL.lua', - - 'config.lua', - 'server.lua' -} - -client_scripts { - -- comment these lines if not using the ContextMenu - --'@ContextMenu/screenToWorld.lua', - --'@ContextMenu/Drawables/Color.lua', - --'@ContextMenu/Drawables/Rect.lua', - --'@ContextMenu/Drawables/Text.lua', - --'@ContextMenu/Drawables/Sprite.lua', - --'@ContextMenu/Menu/Item.lua', - --'@ContextMenu/Menu/TextItem.lua', - --'@ContextMenu/Menu/CheckboxItem.lua', - --'@ContextMenu/Menu/SubmenuItem.lua', - --'@ContextMenu/Menu/Separator.lua', - --'@ContextMenu/Menu/Border.lua', - --'@ContextMenu/Menu/Menu.lua', - --'@ContextMenu/Menu/MenuPool.lua', - - -- comment this line if not using NativeUILua - '@NativeUI/NativeUI.lua', - '@ox_lib/init.lua', - - 'config.lua', - 'client.lua' -} - -server_exports { - 'IsVehicleOwner', - 'IsKeyOwner', - 'IsVehicleOrKeyOwner', - 'GetPlayerKeys', - 'GetPlayerVehicles' -} - -exports { - 'IsVehicleOwner', - 'IsKeyOwner', - 'IsVehicleOrKeyOwner', - 'GetAllKeys', - 'GetAllVehicles' -} +fx_version 'cerulean' +games { 'gta5' } + +author 'Mîhó' +description 'Manage vehicle keys!' +version '1.1.1' + +dependency 'kimi_callbacks' +dependency 'NativeUI' + +server_scripts { + --'@mysql-async/lib/MySQL.lua', + '@oxmysql/lib/MySQL.lua', + + 'config.lua', + 'server.lua' +} + +client_scripts { + -- comment these lines if not using the ContextMenu + --'@ContextMenu/screenToWorld.lua', + --'@ContextMenu/Drawables/Color.lua', + --'@ContextMenu/Drawables/Rect.lua', + --'@ContextMenu/Drawables/Text.lua', + --'@ContextMenu/Drawables/Sprite.lua', + --'@ContextMenu/Menu/Item.lua', + --'@ContextMenu/Menu/TextItem.lua', + --'@ContextMenu/Menu/CheckboxItem.lua', + --'@ContextMenu/Menu/SubmenuItem.lua', + --'@ContextMenu/Menu/Separator.lua', + --'@ContextMenu/Menu/Border.lua', + --'@ContextMenu/Menu/Menu.lua', + --'@ContextMenu/Menu/MenuPool.lua', + + -- comment this line if not using NativeUILua + '@NativeUI/NativeUI.lua', + '@ox_lib/init.lua', + + 'config.lua', + 'client.lua' +} + +server_exports { + 'IsVehicleOwner', + 'IsKeyOwner', + 'IsVehicleOrKeyOwner', + 'GetPlayerKeys', + 'GetPlayerVehicles' +} + +exports { + 'IsVehicleOwner', + 'IsKeyOwner', + 'IsVehicleOrKeyOwner', + 'GetAllKeys', + 'GetAllVehicles' +} diff --git a/resources/[carscripts]/sn_vehicleKey/server.lua b/resources/[Developer]/sn_vehicleKey/server.lua similarity index 97% rename from resources/[carscripts]/sn_vehicleKey/server.lua rename to resources/[Developer]/sn_vehicleKey/server.lua index b7fa1a81e..950e8d089 100644 --- a/resources/[carscripts]/sn_vehicleKey/server.lua +++ b/resources/[Developer]/sn_vehicleKey/server.lua @@ -1,503 +1,503 @@ -local CB = exports["kimi_callbacks"] -local QBCore = exports['qb-core']:GetCoreObject() - - --- create a new key -CB:Register("VKC:createNewKey", function(source, plate, count) - local src = source - - if (plate == nil or count == nil) then - print("^1[ERROR] \"plate\" or \"count\" was nil while creating new key for id " .. tostring(src)) - - return false - end - - local Player = QBCore.Functions.GetPlayer(src) - if (Player) then - local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() - - if (Player.Functions.GetMoney('cash') >= Config.Costs.newKey) then - local results = MySQL.Sync.fetchAll("SELECT count FROM vehicle_keys WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Player.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - - local rows = 0 - if (#results > 0) then - rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count + @count WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Player.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate, - ["@count"] = count - }) - else - rows = MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @trimmedPlate, @count)", { - ["@owner"] = Player.PlayerData.citizenid, - ["@trimmedPlate"] = trimmedPlate, - ["@count"] = count - }) - end - - if (rows == 0) then - return false - end - - Player.Functions.RemoveMoney('cash', Config.Costs.newKey) - else - return "noMoney" - end - else - print("^1[ERROR] \"playerData\" was nil while creating new key for id " .. tostring(src)) - - return false - end - - return true -end) - --- remove a key from a plate -CB:Register("VKC:removeKey", function(source, plate, num) - local src = source - - if (plate == nil or num == nil) then - print("^1[ERROR] \"plate\" or \"num\" was nil while removing a key for id " .. tostring(src)) - - return false - end - - local Player = QBCore.Functions.GetPlayer(src) - if (Player) then - local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() - - local rows = MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate) and count = @num", { - ["@owner"] = Player.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate, - ["@num"] = num - }) - - if (rows == 0) then - rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count - @num WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Player.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate, - ["@num"] = num - }) - end - - if (rows == 0) then - return false - end - else - print("^1[ERROR] \"playerData\" was nil while removing a key for id " .. tostring(src)) - - return false - end - - return true -end) - --- remove a key from a plate -CB:Register("VKC:giveKeyToPlayer", function(source, plate, playerId) - local src = source - - if (plate == nil or playerId == nil) then - print("^1[ERROR] \"plate\" or \"playerId\" was nil while giving a key for id " .. tostring(src)) - - return false - end - - local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() - - local Playera = QBCore.Functions.GetPlayer(src) --MARK - local Playerb = QBCore.Functions.GetPlayer(playerId) - if (Playera and Playerb) then - local rows = MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate) and count = 1", { - ["@owner"] = Playera.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - - if (rows == 0) then - rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count - 1 WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Playera.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - end - - if (rows == 0) then - return false - else - local results = MySQL.Sync.fetchAll("SELECT count FROM vehicle_keys WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Playerb.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - - rows = 0 - if (#results > 0) then - rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count + 1 WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Playerb.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - else - rows = MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @trimmedPlate, 1)", { - ["@owner"] = Playerb.PlayerData.citizenid, - ["@trimmedPlate"] = trimmedPlate - }) - end - - if (rows == 0) then - return false - end - end - else - print("^1[ERROR] \"playerData\" or \"playerData2\" was nil while giving a key for id " .. tostring(src)) - - return false - end - - TriggerClientEvent("VKC:giveKeyNotif", playerId, trimmedPlate) - - return true -end) - --- remove all keys from a plate -CB:Register("VKC:removeAllKeys", function(source, plate) - local src = source - - if (plate == nil) then - print("^1[ERROR] \"plate\" was nil while removing all keys for " .. tostring(src)) - - return false - end - - local Player = QBCore.Functions.GetPlayer(src) - if (Player) then - local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() - - if (Player.Functions.GetMoney(Config.Costs.GetMoney) >= Config.Costs.exchangeLocks) then - MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE plate = @trimmedPlate", { - ["@trimmedPlate"] = trimmedPlate - }) - - Player.Functions.RemoveMoney(Config.Costs.GetMoney, Config.Costs.exchangeLocks) - - return true - else - return "noMoney" - end - end - - return false -end) - --- get all owned vehicles from player -function GetPlayerVehicleData(playerId) - if (playerId == nil) then - print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"GetOwnedVehicles\"!") - return - end - local Player = QBCore.Functions.GetPlayer(playerId) - local vehicles = {} - if (Player) then - local results = MySQL.Sync.fetchAll("SELECT plate, vehicle FROM player_vehicles WHERE citizenid = @owner", { - ["@owner"] = Player.PlayerData.citizenid - }) - - for i = 1, #results, 1 do - print(json.encode(results[i])) - table.insert(vehicles, { - results[i].plate, - results[i].vehicle}) - --json.decode(results[i].vehicles).model}) - end - else - print("^1[ERROR] \"playerData\" was nil while getting owned vehicles for id " .. tostring(playerId)) - end - - print(json.encode(vehicles)) - return vehicles -end -CB:Register("VKC:getPlayerVehicleData", GetPlayerVehicleData) - --- get all owned keys from player -function GetPlayerKeys(playerId) - if (playerId == nil) then - print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"GetOwnedKeys\"!") - return - end - - local keys = {} - - local Player = QBCore.Functions.GetPlayer(playerId) - if (Player) then - local results = MySQL.Sync.fetchAll("SELECT vehicle_keys.plate, vehicle_keys.count, player_vehicles.vehicle FROM vehicle_keys INNER JOIN player_vehicles ON vehicle_keys.plate = player_vehicles.plate WHERE vehicle_keys.owner = @owner", { - ["@owner"] = Player.PlayerData.citizenid - }) - - for i = 1, #results, 1 do - table.insert(keys, { - plate = results[i].plate, - count = results[i].count, - model = results[i].vehicle --json.decode(results[i].vehicle).model - }) - end - else - print("^1[ERROR] \"playerData\" was nil while getting owned keys for id " .. tostring(playerId)) - end - - return keys -end -CB:Register("VKC:getPlayerKeys", GetPlayerKeys) - --- return if playerId is owner of vehicle -function IsVehicleOwner(playerId, plate) - if (playerId == nil) then - print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsVehicleOwner\"!") - return - end - if (plate == nil) then - print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsVehicleOwner\"!") - return - end - - local Player = QBCore.Functions.GetPlayer(playerId) - if (Player) then - local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() - - local results = MySQL.Sync.fetchAll("SELECT plate FROM player_vehicles WHERE citizenid = @owner and (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Player.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - - if (#results > 0) then - return true - end - else - print("^1[ERROR] \"playerData\" was nil while getting vehicle ownership for id " .. tostring(playerId)) - end - - return false -end -CB:Register("VKC:isVehicleOwner", IsVehicleOwner) - --- return if playerId is owner of key -function IsKeyOwner(playerId, plate, model) - if (playerId == nil) then - print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsKeyOwner\"!") - return - end - if (plate == nil) then - print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsKeyOwner\"!") - return - end - if (model == nil) then - print("^1[ERROR] Parameter \"model\" was nil while triggering server export \"IsKeyOwner\"!") - return - end - - local Player = QBCore.Functions.GetPlayer(playerId) - if (Player) then - local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() - - if (IsJobVehicle(Player.PlayerData.job.name, trimmedPlate, model)) then - return true - end - - local results = MySQL.Sync.fetchAll("SELECT plate FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Player.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - - if (#results > 0) then - return true - end - else - print("^1[ERROR] \"playerData\" was nil while getting key ownership for id " .. tostring(playerId)) - end - - return false -end -exports["kimi_callbacks"]:Register("VKC:isKeyOwner", IsKeyOwner) - --- return if playerId is owner of vehicle or key -function IsVehicleOrKeyOwner(playerId, plate, model) - if (playerId == nil) then - print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!") - return - end - if (plate == nil) then - print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!") - return - end - if (model == nil) then - print("^1[ERROR] Parameter \"model\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!") - return - end - - local Player = QBCore.Functions.GetPlayer(playerId) - if (Player) then - local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() - - if (IsJobVehicle(Player.PlayerData.job.name, trimmedPlate, model)) then - return true - end - - local results = MySQL.Sync.fetchAll("SELECT plate FROM player_vehicles WHERE citizenid = @owner and (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Player.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - - if (#results > 0) then - return true - end - - results = MySQL.Sync.fetchAll("SELECT plate FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", { - ["@owner"] = Player.PlayerData.citizenid, - ["@plate"] = plate, - ["@trimmedPlate"] = trimmedPlate - }) - - if (#results > 0) then - return true - end - else - print("^1[ERROR] \"playerData\" was nil while getting vehicle or key ownership for id " .. tostring(playerId)) - end - - return false -end -CB:Register("VKC:isVehicleOrKeyOwner", IsVehicleOrKeyOwner) - - - --- if the given vehicle is a job vehicle -function IsJobVehicle(job, plate, model) - local jobData = Config.JobVehicles[job] - - if (jobData == nil) then - return false - end - - for i, m in ipairs(jobData.models) do - if (m == model) then - return true - end - end - - for i, p in ipairs(jobData.plates) do - if (plate:find(p:upper())) then - return true - end - end - - return false -end - - - --- toggle door lock over network to ensure it always works -RegisterServerEvent("VKC:toggleLockNet") -AddEventHandler("VKC:toggleLockNet", function(vehicleNetId, unlocked) - local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId) - if (DoesEntityExist(vehicle)) then - local entityOwner = NetworkGetEntityOwner(vehicle) - TriggerClientEvent("VKC:toggleLockOnPlayer", entityOwner, vehicleNetId, unlocked) - end -end) -RegisterServerEvent("VKC:playDoorLockSoundNet") -AddEventHandler("VKC:playDoorLockSoundNet", function(vehicleNetId, lock) - TriggerClientEvent("VKC:playDoorLockSound", -1, vehicleNetId, lock) -end) - - -RegisterServerEvent('VKC:setvehkey') -AddEventHandler('VKC:setvehkey', function(plate) - local _source = source - local xPlayer = QBCore.Functions.GetPlayer(_source) - - MySQL.query("INSERT INTO vehicle_keys(owner, plate, count) VALUES (?, ?, ?)", {xPlayer.PlayerData.citizenid, plate, 1}) -end) - -RegisterServerEvent('VKC:delvehkey') -AddEventHandler('VKC:delvehkey', function(plate, owner) - local _source = source - if owner then - local xPlayer = QBCore.Functions.GetPlayer(_source) - - MySQL.query("DELETE FROM vehicle_keys WHERE plate = ? and owner = ?", {plate, xPlayer.PlayerData.citizenid}) - else - MySQL.query("DELETE FROM vehicle_keys WHERE plate = ?", {plate}) - end -end) - --- Fahrzeugbesitz an einen anderen Spieler übertragen -CB:Register("VKC:transferVehicleOwnership", function(source, plate, targetPlayerId) - local src = source - - if (plate == nil or targetPlayerId == nil) then - print("^1[ERROR] \"plate\" or \"targetPlayerId\" was nil while transferring vehicle ownership for id " .. tostring(src)) - return false - end - - local Player = QBCore.Functions.GetPlayer(src) - local TargetPlayer = QBCore.Functions.GetPlayer(targetPlayerId) - - if (not Player or not TargetPlayer) then - print("^1[ERROR] Player or target player not found while transferring vehicle ownership") - return false - end - - local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() - - -- Überprüfen, ob der Spieler das Fahrzeug besitzt - local isOwner = IsVehicleOwner(src, trimmedPlate) - if not isOwner then - return false - end - - -- Fahrzeugmodell für die Benachrichtigung abrufen - local vehicleModel = nil - local results = MySQL.Sync.fetchAll("SELECT vehicle FROM player_vehicles WHERE plate = @plate AND citizenid = @owner", { - ["@plate"] = trimmedPlate, - ["@owner"] = Player.PlayerData.citizenid - }) - - if #results > 0 then - vehicleModel = results[1].vehicle - end - - -- Besitz in der Datenbank übertragen - local success = MySQL.Sync.execute("UPDATE player_vehicles SET citizenid = @newOwner WHERE plate = @plate AND citizenid = @oldOwner", { - ["@newOwner"] = TargetPlayer.PlayerData.citizenid, - ["@plate"] = trimmedPlate, - ["@oldOwner"] = Player.PlayerData.citizenid - }) - - if success > 0 then - -- Alle Schlüssel auf den neuen Besitzer übertragen - MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE plate = @plate", { - ["@plate"] = trimmedPlate - }) - - -- Einen Schlüssel dem neuen Besitzer geben - MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @plate, 1)", { - ["@owner"] = TargetPlayer.PlayerData.citizenid, - ["@plate"] = trimmedPlate - }) - - -- Den Zielspieler benachrichtigen - TriggerClientEvent("VKC:vehicleTransferNotif", targetPlayerId, trimmedPlate, vehicleModel) - - return true - end - - return false -end) +local CB = exports["kimi_callbacks"] +local QBCore = exports['qb-core']:GetCoreObject() + + +-- create a new key +CB:Register("VKC:createNewKey", function(source, plate, count) + local src = source + + if (plate == nil or count == nil) then + print("^1[ERROR] \"plate\" or \"count\" was nil while creating new key for id " .. tostring(src)) + + return false + end + + local Player = QBCore.Functions.GetPlayer(src) + if (Player) then + local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() + + if (Player.Functions.GetMoney('cash') >= Config.Costs.newKey) then + local results = MySQL.Sync.fetchAll("SELECT count FROM vehicle_keys WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Player.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + + local rows = 0 + if (#results > 0) then + rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count + @count WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Player.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate, + ["@count"] = count + }) + else + rows = MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @trimmedPlate, @count)", { + ["@owner"] = Player.PlayerData.citizenid, + ["@trimmedPlate"] = trimmedPlate, + ["@count"] = count + }) + end + + if (rows == 0) then + return false + end + + Player.Functions.RemoveMoney('cash', Config.Costs.newKey) + else + return "noMoney" + end + else + print("^1[ERROR] \"playerData\" was nil while creating new key for id " .. tostring(src)) + + return false + end + + return true +end) + +-- remove a key from a plate +CB:Register("VKC:removeKey", function(source, plate, num) + local src = source + + if (plate == nil or num == nil) then + print("^1[ERROR] \"plate\" or \"num\" was nil while removing a key for id " .. tostring(src)) + + return false + end + + local Player = QBCore.Functions.GetPlayer(src) + if (Player) then + local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() + + local rows = MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate) and count = @num", { + ["@owner"] = Player.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate, + ["@num"] = num + }) + + if (rows == 0) then + rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count - @num WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Player.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate, + ["@num"] = num + }) + end + + if (rows == 0) then + return false + end + else + print("^1[ERROR] \"playerData\" was nil while removing a key for id " .. tostring(src)) + + return false + end + + return true +end) + +-- remove a key from a plate +CB:Register("VKC:giveKeyToPlayer", function(source, plate, playerId) + local src = source + + if (plate == nil or playerId == nil) then + print("^1[ERROR] \"plate\" or \"playerId\" was nil while giving a key for id " .. tostring(src)) + + return false + end + + local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() + + local Playera = QBCore.Functions.GetPlayer(src) --MARK + local Playerb = QBCore.Functions.GetPlayer(playerId) + if (Playera and Playerb) then + local rows = MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate) and count = 1", { + ["@owner"] = Playera.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + + if (rows == 0) then + rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count - 1 WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Playera.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + end + + if (rows == 0) then + return false + else + local results = MySQL.Sync.fetchAll("SELECT count FROM vehicle_keys WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Playerb.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + + rows = 0 + if (#results > 0) then + rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count + 1 WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Playerb.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + else + rows = MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @trimmedPlate, 1)", { + ["@owner"] = Playerb.PlayerData.citizenid, + ["@trimmedPlate"] = trimmedPlate + }) + end + + if (rows == 0) then + return false + end + end + else + print("^1[ERROR] \"playerData\" or \"playerData2\" was nil while giving a key for id " .. tostring(src)) + + return false + end + + TriggerClientEvent("VKC:giveKeyNotif", playerId, trimmedPlate) + + return true +end) + +-- remove all keys from a plate +CB:Register("VKC:removeAllKeys", function(source, plate) + local src = source + + if (plate == nil) then + print("^1[ERROR] \"plate\" was nil while removing all keys for " .. tostring(src)) + + return false + end + + local Player = QBCore.Functions.GetPlayer(src) + if (Player) then + local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() + + if (Player.Functions.GetMoney(Config.Costs.GetMoney) >= Config.Costs.exchangeLocks) then + MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE plate = @trimmedPlate", { + ["@trimmedPlate"] = trimmedPlate + }) + + Player.Functions.RemoveMoney(Config.Costs.GetMoney, Config.Costs.exchangeLocks) + + return true + else + return "noMoney" + end + end + + return false +end) + +-- get all owned vehicles from player +function GetPlayerVehicleData(playerId) + if (playerId == nil) then + print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"GetOwnedVehicles\"!") + return + end + local Player = QBCore.Functions.GetPlayer(playerId) + local vehicles = {} + if (Player) then + local results = MySQL.Sync.fetchAll("SELECT plate, vehicle FROM player_vehicles WHERE citizenid = @owner", { + ["@owner"] = Player.PlayerData.citizenid + }) + + for i = 1, #results, 1 do + print(json.encode(results[i])) + table.insert(vehicles, { + results[i].plate, + results[i].vehicle}) + --json.decode(results[i].vehicles).model}) + end + else + print("^1[ERROR] \"playerData\" was nil while getting owned vehicles for id " .. tostring(playerId)) + end + + print(json.encode(vehicles)) + return vehicles +end +CB:Register("VKC:getPlayerVehicleData", GetPlayerVehicleData) + +-- get all owned keys from player +function GetPlayerKeys(playerId) + if (playerId == nil) then + print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"GetOwnedKeys\"!") + return + end + + local keys = {} + + local Player = QBCore.Functions.GetPlayer(playerId) + if (Player) then + local results = MySQL.Sync.fetchAll("SELECT vehicle_keys.plate, vehicle_keys.count, player_vehicles.vehicle FROM vehicle_keys INNER JOIN player_vehicles ON vehicle_keys.plate = player_vehicles.plate WHERE vehicle_keys.owner = @owner", { + ["@owner"] = Player.PlayerData.citizenid + }) + + for i = 1, #results, 1 do + table.insert(keys, { + plate = results[i].plate, + count = results[i].count, + model = results[i].vehicle --json.decode(results[i].vehicle).model + }) + end + else + print("^1[ERROR] \"playerData\" was nil while getting owned keys for id " .. tostring(playerId)) + end + + return keys +end +CB:Register("VKC:getPlayerKeys", GetPlayerKeys) + +-- return if playerId is owner of vehicle +function IsVehicleOwner(playerId, plate) + if (playerId == nil) then + print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsVehicleOwner\"!") + return + end + if (plate == nil) then + print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsVehicleOwner\"!") + return + end + + local Player = QBCore.Functions.GetPlayer(playerId) + if (Player) then + local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() + + local results = MySQL.Sync.fetchAll("SELECT plate FROM player_vehicles WHERE citizenid = @owner and (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Player.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + + if (#results > 0) then + return true + end + else + print("^1[ERROR] \"playerData\" was nil while getting vehicle ownership for id " .. tostring(playerId)) + end + + return false +end +CB:Register("VKC:isVehicleOwner", IsVehicleOwner) + +-- return if playerId is owner of key +function IsKeyOwner(playerId, plate, model) + if (playerId == nil) then + print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsKeyOwner\"!") + return + end + if (plate == nil) then + print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsKeyOwner\"!") + return + end + if (model == nil) then + print("^1[ERROR] Parameter \"model\" was nil while triggering server export \"IsKeyOwner\"!") + return + end + + local Player = QBCore.Functions.GetPlayer(playerId) + if (Player) then + local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() + + if (IsJobVehicle(Player.PlayerData.job.name, trimmedPlate, model)) then + return true + end + + local results = MySQL.Sync.fetchAll("SELECT plate FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Player.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + + if (#results > 0) then + return true + end + else + print("^1[ERROR] \"playerData\" was nil while getting key ownership for id " .. tostring(playerId)) + end + + return false +end +exports["kimi_callbacks"]:Register("VKC:isKeyOwner", IsKeyOwner) + +-- return if playerId is owner of vehicle or key +function IsVehicleOrKeyOwner(playerId, plate, model) + if (playerId == nil) then + print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!") + return + end + if (plate == nil) then + print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!") + return + end + if (model == nil) then + print("^1[ERROR] Parameter \"model\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!") + return + end + + local Player = QBCore.Functions.GetPlayer(playerId) + if (Player) then + local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() + + if (IsJobVehicle(Player.PlayerData.job.name, trimmedPlate, model)) then + return true + end + + local results = MySQL.Sync.fetchAll("SELECT plate FROM player_vehicles WHERE citizenid = @owner and (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Player.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + + if (#results > 0) then + return true + end + + results = MySQL.Sync.fetchAll("SELECT plate FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", { + ["@owner"] = Player.PlayerData.citizenid, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }) + + if (#results > 0) then + return true + end + else + print("^1[ERROR] \"playerData\" was nil while getting vehicle or key ownership for id " .. tostring(playerId)) + end + + return false +end +CB:Register("VKC:isVehicleOrKeyOwner", IsVehicleOrKeyOwner) + + + +-- if the given vehicle is a job vehicle +function IsJobVehicle(job, plate, model) + local jobData = Config.JobVehicles[job] + + if (jobData == nil) then + return false + end + + for i, m in ipairs(jobData.models) do + if (m == model) then + return true + end + end + + for i, p in ipairs(jobData.plates) do + if (plate:find(p:upper())) then + return true + end + end + + return false +end + + + +-- toggle door lock over network to ensure it always works +RegisterServerEvent("VKC:toggleLockNet") +AddEventHandler("VKC:toggleLockNet", function(vehicleNetId, unlocked) + local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId) + if (DoesEntityExist(vehicle)) then + local entityOwner = NetworkGetEntityOwner(vehicle) + TriggerClientEvent("VKC:toggleLockOnPlayer", entityOwner, vehicleNetId, unlocked) + end +end) +RegisterServerEvent("VKC:playDoorLockSoundNet") +AddEventHandler("VKC:playDoorLockSoundNet", function(vehicleNetId, lock) + TriggerClientEvent("VKC:playDoorLockSound", -1, vehicleNetId, lock) +end) + + +RegisterServerEvent('VKC:setvehkey') +AddEventHandler('VKC:setvehkey', function(plate) + local _source = source + local xPlayer = QBCore.Functions.GetPlayer(_source) + + MySQL.query("INSERT INTO vehicle_keys(owner, plate, count) VALUES (?, ?, ?)", {xPlayer.PlayerData.citizenid, plate, 1}) +end) + +RegisterServerEvent('VKC:delvehkey') +AddEventHandler('VKC:delvehkey', function(plate, owner) + local _source = source + if owner then + local xPlayer = QBCore.Functions.GetPlayer(_source) + + MySQL.query("DELETE FROM vehicle_keys WHERE plate = ? and owner = ?", {plate, xPlayer.PlayerData.citizenid}) + else + MySQL.query("DELETE FROM vehicle_keys WHERE plate = ?", {plate}) + end +end) + +-- Fahrzeugbesitz an einen anderen Spieler übertragen +CB:Register("VKC:transferVehicleOwnership", function(source, plate, targetPlayerId) + local src = source + + if (plate == nil or targetPlayerId == nil) then + print("^1[ERROR] \"plate\" or \"targetPlayerId\" was nil while transferring vehicle ownership for id " .. tostring(src)) + return false + end + + local Player = QBCore.Functions.GetPlayer(src) + local TargetPlayer = QBCore.Functions.GetPlayer(targetPlayerId) + + if (not Player or not TargetPlayer) then + print("^1[ERROR] Player or target player not found while transferring vehicle ownership") + return false + end + + local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper() + + -- Überprüfen, ob der Spieler das Fahrzeug besitzt + local isOwner = IsVehicleOwner(src, trimmedPlate) + if not isOwner then + return false + end + + -- Fahrzeugmodell für die Benachrichtigung abrufen + local vehicleModel = nil + local results = MySQL.Sync.fetchAll("SELECT vehicle FROM player_vehicles WHERE plate = @plate AND citizenid = @owner", { + ["@plate"] = trimmedPlate, + ["@owner"] = Player.PlayerData.citizenid + }) + + if #results > 0 then + vehicleModel = results[1].vehicle + end + + -- Besitz in der Datenbank übertragen + local success = MySQL.Sync.execute("UPDATE player_vehicles SET citizenid = @newOwner WHERE plate = @plate AND citizenid = @oldOwner", { + ["@newOwner"] = TargetPlayer.PlayerData.citizenid, + ["@plate"] = trimmedPlate, + ["@oldOwner"] = Player.PlayerData.citizenid + }) + + if success > 0 then + -- Alle Schlüssel auf den neuen Besitzer übertragen + MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE plate = @plate", { + ["@plate"] = trimmedPlate + }) + + -- Einen Schlüssel dem neuen Besitzer geben + MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @plate, 1)", { + ["@owner"] = TargetPlayer.PlayerData.citizenid, + ["@plate"] = trimmedPlate + }) + + -- Den Zielspieler benachrichtigen + TriggerClientEvent("VKC:vehicleTransferNotif", targetPlayerId, trimmedPlate, vehicleModel) + + return true + end + + return false +end) diff --git a/resources/[carscripts]/sn_vehicleKey/vehicle_keys.sql b/resources/[Developer]/sn_vehicleKey/vehicle_keys.sql similarity index 97% rename from resources/[carscripts]/sn_vehicleKey/vehicle_keys.sql rename to resources/[Developer]/sn_vehicleKey/vehicle_keys.sql index 871919da7..47a9d8550 100644 --- a/resources/[carscripts]/sn_vehicleKey/vehicle_keys.sql +++ b/resources/[Developer]/sn_vehicleKey/vehicle_keys.sql @@ -1,27 +1,27 @@ --- -------------------------------------------------------- --- Host: 127.0.0.1 --- Server version: 10.1.28-MariaDB - mariadb.org binary distribution --- Server OS: Win32 --- HeidiSQL Version: 11.0.0.5919 --- -------------------------------------------------------- - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET NAMES utf8 */; -/*!50503 SET NAMES utf8mb4 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; - --- Dumping structure for table essentialmode.vehicle_keys -CREATE TABLE IF NOT EXISTS `vehicle_keys` ( - `owner` varchar(60) NOT NULL, - `plate` varchar(8) NOT NULL, - `count` smallint(6) NOT NULL, - KEY `plate` (`plate`), - KEY `owner` (`owner`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- Data exporting was unselected. - -/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; -/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +-- -------------------------------------------------------- +-- Host: 127.0.0.1 +-- Server version: 10.1.28-MariaDB - mariadb.org binary distribution +-- Server OS: Win32 +-- HeidiSQL Version: 11.0.0.5919 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +-- Dumping structure for table essentialmode.vehicle_keys +CREATE TABLE IF NOT EXISTS `vehicle_keys` ( + `owner` varchar(60) NOT NULL, + `plate` varchar(8) NOT NULL, + `count` smallint(6) NOT NULL, + KEY `plate` (`plate`), + KEY `owner` (`owner`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Data exporting was unselected. + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/resources/[carscripts]/jg-advancedgarages/.fxap b/resources/[carscripts]/jg-advancedgarages/.fxap new file mode 100644 index 0000000000000000000000000000000000000000..49924cf20bd6ecd7e93b54ba3b83dd416222e7fb GIT binary patch literal 178 zcmV;j08Rf!SV2$$000000D$dZIw9tp%6U$}#?Uf^YEZ;CpF)DmrXJPge@6$BNvz3Q z`AYZ4j8hEDaVj+%xh_8Z(w%QJ^SY(zWnz^(3jMY7;GyqyOA{aJ=wi2wiq literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/README.md b/resources/[carscripts]/jg-advancedgarages/README.md new file mode 100644 index 000000000..0fb5a5643 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/README.md @@ -0,0 +1,17 @@ +# JG Scripts Advanced Garages v3 + +Hey there! Thanks so much for purchasing, it really means a lot to me. I've spent a lot of time on this script, and I hope you love it. This document has a bunch of the essential information that should help you out: + +## Useful Links + +🔧 Configure Advanced Garages in just minutes: https://configurator.jgscripts.com/advanced-garages + +📚 Documentation: https://docs.jgscripts.com/advanced-garages/introduction + +🔗 Official Website: https://jgscripts.com + +🛒 Store: https://store.jgscripts.com + +## Support + +Join Discord https://discord.jgscripts.com, and we will do whatever it takes to help you out and get you up and running! diff --git a/resources/[carscripts]/jg-advancedgarages/client/cl-deformation.lua b/resources/[carscripts]/jg-advancedgarages/client/cl-deformation.lua new file mode 100644 index 000000000..74175da05 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/client/cl-deformation.lua @@ -0,0 +1,90 @@ +-- A modified version of "VehicleDeformation" v1.0.1, by Kiminaze. Full credits go to him, so adibe by the license below. +-- Check out his other work: https://kiminazes-script-gems.tebex.io/ +-- +-- VehicleDeformation License: +-- +-- Copyright (c) 2021 Philipp Decker /// FiveM: Kiminaze / Discord: Kiminaze#9097 +-- By acquiring a copy of this code snippet for the "FiveM" modification for "Grand Theft +-- Auto V" you are granted permission to use and modify all of its parts. +-- You are allowed to (re-)distribute and sell resources that have been created with the +-- help of this code snippet. You have to include this license when doing so. +-- This code snippet is provided "as is" and the copyright holder of this code snippet can +-- not be held accountable for any damages occuring during the usage or modification of +-- this code snippet. + +local MAX_DEFORM_ITERATIONS = 50 -- iterations for damage application +local DEFORMATION_DAMAGE_THRESHOLD = 0.05 -- the minimum damage value at a deformation point + +function getVehicleDeformation(vehicle) + assert(vehicle ~= nil and DoesEntityExist(vehicle), "Parameter \"vehicle\" must be a valid vehicle entity!") + + -- check vehicle size and pre-calc values for offsets + local min, max = GetModelDimensions(GetEntityModel(vehicle)) + local X = (max.x - min.x) * 0.5 + local Y = (max.y - min.y) * 0.5 + local Z = (max.z - min.z) * 0.5 + local halfY = Y * 0.5 + + -- offsets for deformation check + local positions = {vector3(-X, Y, 0.0), vector3(-X, Y, Z), vector3(0.0, Y, 0.0), vector3(0.0, Y, Z), vector3(X, Y, 0.0), vector3(X, Y, Z), vector3(-X, halfY, 0.0), vector3(-X, halfY, Z), vector3(0.0, halfY, 0.0), vector3(0.0, halfY, Z), vector3(X, halfY, 0.0), vector3(X, halfY, Z), + vector3(-X, 0.0, 0.0), vector3(-X, 0.0, Z), vector3(0.0, 0.0, 0.0), vector3(0.0, 0.0, Z), vector3(X, 0.0, 0.0), vector3(X, 0.0, Z), vector3(-X, -halfY, 0.0), vector3(-X, -halfY, Z), vector3(0.0, -halfY, 0.0), vector3(0.0, -halfY, Z), vector3(X, -halfY, 0.0), + vector3(X, -halfY, Z), vector3(-X, -Y, 0.0), vector3(-X, -Y, Z), vector3(0.0, -Y, 0.0), vector3(0.0, -Y, Z), vector3(X, -Y, 0.0), vector3(X, -Y, Z)} + + -- get deformation from vehicle + local deformationPoints = {} + for i, pos in ipairs(positions) do + -- translate damage from vector3 to a float + local dmg = #(GetVehicleDeformationAtPos(vehicle, pos.x, pos.y, pos.z)) + if (dmg > DEFORMATION_DAMAGE_THRESHOLD) then + table.insert(deformationPoints, {pos, dmg}) + end + end + + return { + deformation = deformationPoints, + dirt = GetVehicleDirtLevel(vehicle) + } +end + +function setVehicleDeformation(vehicle, deformation) + assert(vehicle ~= nil and DoesEntityExist(vehicle), "Parameter \"vehicle\" must be a valid vehicle entity!") + assert(deformation ~= nil and type(deformation) == "table", "Parameter \"deformation\" must be a table!") + + local deformationPoints = deformation.deformation + local dirt = deformation.dirt + + CreateThread(function() + local handlingMult, damageMult = GetVehicleHandlingFloat(vehicle, "CHandlingData", "fDeformationDamageMult"), 20.0 + if handlingMult <= 0.55 then damageMult = 1000.0 + elseif handlingMult <= 0.65 then damageMult = 400.0 + elseif handlingMult <= 0.75 then damageMult = 200.0 end + + for _, def in ipairs(deformationPoints) do + def[1] = vector3(def[1].x, def[1].y, def[1].z) + end + + -- iterate over all deformation points and check if more than one application is necessary + -- looping is necessary for most vehicles that have a really bad damage model or take a lot of damage (e.g. neon, phantom3) + local deform = true + local iteration = 0 + + while deform and iteration < MAX_DEFORM_ITERATIONS do + if not DoesEntityExist(vehicle) then return end + + deform = false + + for _, def in ipairs(deformationPoints) do + if #(GetVehicleDeformationAtPos(vehicle, def[1].x, def[1].y, def[1].z)) < def[2] then + local offset = def[1] * 2.0 + SetVehicleDamage(vehicle, offset.x, offset.y, offset.z, def[2] * damageMult, 1000.0, true) + deform = true + end + end + + iteration = iteration + 1 + Wait(100) + end + + SetVehicleDirtLevel(vehicle, dirt) + end) +end \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/client/cl-garage.lua b/resources/[carscripts]/jg-advancedgarages/client/cl-garage.lua new file mode 100644 index 0000000000000000000000000000000000000000..db4a6deb71dab420f5e7c40663ac255cf6251cd9 GIT binary patch literal 9049 zcmV-fBc|L&SV2$$000000C?VNOD|xxZvhq?i;tp7gmmL=vwkE}V!;f*?j#gJ${(md zfJtN7P;w3_u5kArwka{xj-!9o@ESZ}6(-A42O=Kxo)=y)Z@Z8Im;ckqI631DdlUB( zcfqh59}hkMCcHpcK=YWY#^T_r*6dx2j;m3vX?3AVt=DYVU@0EFiVptScduD2%RdL4 z+CyOR0|`>ap%#S^9w>8Jy+D`+mMP-u05dMcP>r~cCj2In=@`YLf9l9R15q+yZ=t$H)e9@0fo-zM}0Fs>=6H~X+kF?4){EHHwYjreD)o^yx;h1 z60P`g{$O;d&y;b*PR$y7`P1zU<&ZUAT1v?qOupeGN1o>UcA7)BLU7Q^YC3AqEecyC zNjweap_@OygnBA?sr9*SzT^5o#~6{;-h}3Zf5$7s?J~(htpr$g{~eou&Tdry89vJ< zmmTf8vMAyU`8)iKM;~|AjM5ztxdN&}KQ$Qa{FTd^Xwq*@;0YXN%-#UUm!_e)fcv!b zZGx1XMeCff_TrY{$e;d=L(NzjDx^%<==KkX!L z>lZ{yIA*Ta;{l&}yPR-^vAH-VtChbls&t^I3sFtJ>nd4xu@I!|hbl?0OAfqG+iGxfT zO`o~~o4rqwbmVKsxOkLDB+f-^l}*>y;RDOGGHC+5+ElYk{kt`|?HsX|Is;ej34(e>e#?m(7xWv7bR5#fS@+j=K-)R_5DF;2g_vZ~nb=c2I= zrGycDcMPV#H49z9_xQ^S_D9QAT&^WM6Z87#mul4oCmiA4eOfBJPx9zVgkf15umW7e zVRPS*We`vmzpSu_Cq9zLD7?Nq8VOq>eGOo5b!d>PkiV1RJ}$%iaFPzbK&OEwx%$<1 zeap};wP(puFuS>pT7+Tj?n5a=|37lP47+gj-06dv!#)Hh6OB=)EiVPlx9 zo7Vsiwuve!-;#*`5lNwud)Tt7AZOi^QE)8Zn`3lZwH-mS$Iq~XuD?5i_Jdk;sk_YLn%f|^=NBs#Im?1@G_y? z-+=sI9Ux^nJmeQ6Sj%N#hOJy_4t&}c9T5$?5SDPxgZ;#4`{VNTELM}ynCXWTPf%LU z#f~d8Ch0cw{f{upTWPASvr`^w0SY|Iuh?y=A?mCg9Mso5fX5NM=50o@F#uo1zeX>( zt3Q69l3FnZJ~h^>vS9R(7d@uu5-!aFmKq?2ePd8niqxZZJ@SPNzwmVi6?YHyM=zTp zl2c0fIV%3%bK2(-oOL^jJ{)9+FoX@d5SlqSALQlYG}DgVjcy6VdnIFLY)J90%J(N` zFu8k@np?iAmm!GJfL~ujg$vA^d^3fIZrP1An1jD7;>qxZ-Q*s@j(Y=&Ir(QBlrHl| zNqG+=rH-vfdBNFQHhR!r0iHQ9f`@O>hn6App#@FC7;a>h%#uR* zo~t0-nY02dpczP^ewf-3|E|;-HcoOm1A1m4)F-6QdVzbGSq!PA^UdESx|-=9f^K3; zvV-CEBFQbscYUyjj>@MuJilLB#(6P_gXzht^!pdVg9@tZ>k8GB`k_M|!K^m2>5(l^ z{Rnk|^17YfOdz+}UrQURxT6(or{`e81*HeCnI7)z2yA8d(wzkdFQ4w+pmjX1B-5n9 z$8yC?Vb>_MH9FVlU4n*(UtZ)yaB=nN0vR^FyUiagrMbj(OEZ%0AAEu%r@h7ax(^f8 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 literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/client/cl-locations.lua b/resources/[carscripts]/jg-advancedgarages/client/cl-locations.lua new file mode 100644 index 000000000..106fd593d --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/client/cl-locations.lua @@ -0,0 +1,186 @@ +local GARAGE_ZONE_Z_DIST = 4.0 +local inVehicle, blips, zones, peds = nil, {}, {}, {} +local cachedGarageLocations + +function getAvailableGarageLocations() + if not cachedGarageLocations then + cachedGarageLocations = lib.callback.await("jg-advancedgarages:server:get-available-garage-locations", false) + end + + return cachedGarageLocations or {} +end + +---@param coords vector3 +---@param marker table +function drawMarkerOnFrame(coords, marker) + ---@diagnostic disable-next-line: missing-parameter + DrawMarker(marker.id, coords.x, coords.y, coords.z, 0, 0, 0, 0, 0, 0, marker.size.x, marker.size.y, marker.size.z, marker.color.r, marker.color.g, marker.color.b, marker.color.a, marker.bobUpAndDown, marker.faceCamera, 0, marker.rotate, marker.drawOnEnts) +end + +---@param name string +---@param coords vector3 +---@param blipId integer +---@param blipColour integer +---@param blipScale number +local function createBlip(name, coords, blipId, blipColour, blipScale) + local blip = AddBlipForCoord(coords.x, coords.y, coords.z) + SetBlipSprite(blip, blipId) + SetBlipColour(blip, blipColour) + SetBlipScale(blip, blipScale) + SetBlipAsShortRange(blip, true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString(name) + EndTextCommandSetBlipName(blip) + return blip +end + +---@param garageId string +---@param coords vector3|vector4 +---@param dist number +---@param marker? table | false | nil +---@param onEnter? function +---@param onExit? function +---@param inside? function +local function createLocation(garageId, coords, dist, marker, onEnter, onExit, inside) + local point = lib.zones.box({ + coords = coords, + size = vector3(dist, dist, GARAGE_ZONE_Z_DIST), + rotation = coords.w or 0, + garageId = garageId, + onEnter = onEnter, + onExit = onExit, + inside = inside + }) + + zones[#zones+1] = point + + local markerPoint = lib.points.new({ + coords = coords, + distance = dist * 4, + garageId = garageId + }) + + if not marker then return end + + function markerPoint:nearby() + drawMarkerOnFrame(coords, marker) + end + + zones[#zones+1] = markerPoint +end + +---Runs on tick while ped is in a garage zone +---@param garageId string +---@param garageType "car"|"sea"|"air" +---@param isImpound boolean +local function pedIsInGarageZone(garageId, garageType, isImpound) + local pedIsInVehicle = cache.vehicle and GetPedInVehicleSeat(cache.vehicle, -1) == cache.ped + local prompt = isImpound and Config.OpenImpoundPrompt or (pedIsInVehicle and Config.InsertVehiclePrompt or Config.OpenGaragePrompt) + local action = function() + if pedIsInVehicle then + TriggerEvent("jg-advancedgarages:client:store-vehicle", garageId, garageType, false) + else + TriggerEvent("jg-advancedgarages:client:open-garage", garageId, garageType, false) + end + end + + if inVehicle ~= pedIsInVehicle then + if Config.UseRadialMenu then + Framework.Client.RadialMenuAdd(garageId, prompt, action) + else + Framework.Client.ShowTextUI(prompt) + end + + inVehicle = pedIsInVehicle + end + + if Config.UseRadialMenu then return end + if IsControlJustPressed(0, isImpound and Config.OpenImpoundKeyBind or (pedIsInVehicle and Config.InsertVehicleKeyBind or Config.OpenGarageKeyBind)) then + action() + end +end + +---@param garages table +local function createTargetZones(garages) + for _, ped in ipairs(peds) do + Framework.Client.RemoveTarget(ped) + end + + for garageId, garage in pairs(garages) do + for _, zone in ipairs(zones) do zone:remove() end -- Remove existing zones + + entity = Framework.Client.RegisterTarget(false, garage.coords, garageId, garage.type, garage.garageType) + + peds[#peds+1] = entity + end +end + +---@param garages table +local function createZones(garages) + for _, zone in ipairs(zones) do zone:remove() end -- Remove existing zones + + for garageId, garage in pairs(garages) do + if garage then + -- Zone + createLocation( + garageId, + garage.coords, + garage.distance, + not garage.hideMarkers and garage.markers or false, + nil, + function() + if Config.UseRadialMenu then + Framework.Client.RadialMenuRemove(garageId) + else + Framework.Client.HideTextUI() + end + inVehicle = nil + end, + function() + pedIsInGarageZone(garageId, garage.type, garage.garageType == "impound") + end + ) + end + end +end + +local function createGarageZonesAndBlips() + for _, blip in ipairs(blips) do RemoveBlip(blip) end -- Remove existing blips + + local garages = getAvailableGarageLocations() + + if Config.UseTarget then + createTargetZones(garages) + else + createZones(garages) + end + + for garageId, garage in pairs(garages) do + if garage then + -- Blip + if not garage.hideBlip then + local blipName = garage.garageType == "impound" and Locale.impound or garage.garageType == "job" and Locale.jobGarage or garage.garageType == "gang" and Locale.gangGarage or Locale.garage + if garage.uniqueBlips then blipName = blipName .. ": " .. garageId end + local blip = createBlip(blipName, garage.coords, garage.blip.id, garage.blip.color, garage.blip.scale) + blips[#blips + 1] = blip + end + end + end +end + +RegisterNetEvent("jg-advancedgarages:client:update-blips-text-uis", function() + cachedGarageLocations = lib.callback.await("jg-advancedgarages:server:get-available-garage-locations", false) + createGarageZonesAndBlips() +end) + +CreateThread(function() + Wait(2500) + createGarageZonesAndBlips() +end) + +-- Delete peds in case the script restarts +AddEventHandler("onResourceStop", function(resourceName) + if (GetCurrentResourceName() == resourceName) then + for _, ped in ipairs(peds) do DeleteEntity(ped) end + end +end) \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/client/cl-main.lua b/resources/[carscripts]/jg-advancedgarages/client/cl-main.lua new file mode 100644 index 0000000000000000000000000000000000000000..d6e1971485ef78c2b8f1ab3828adbe4c4dc9684a GIT binary patch literal 2349 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 gWGHLgt<-e1gyRnTe8nC#2 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 literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/config/config-cl.lua b/resources/[carscripts]/jg-advancedgarages/config/config-cl.lua new file mode 100644 index 000000000..9b9729673 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/config/config-cl.lua @@ -0,0 +1,67 @@ +-- +-- Custom code for common events +-- + +---@param vehicle integer Vehicle entity +---@param vehicleDbData table Vehicle row from the database +---@param type "personal" | "job" | "gang" +RegisterNetEvent("jg-advancedgarages:client:InsertVehicle:config", function(vehicle, vehicleDbData, type) + -- Code placed in here will be run when the player inserts their vehicle (if the vehicle is owned; and passes all the checks) +end) + +---@param vehicle integer Vehicle entity +RegisterNetEvent("jg-advancedgarages:client:ImpoundVehicle:config", function(vehicle) + -- Code placed in here will be run just before the vehicle is set to impounded in the DB, and before the entity is deleted +end) + +---@param vehicle integer Vehicle entity +---@param vehicleDbData table Vehicle row from the database +---@param type "personal" | "job" | "gang" +RegisterNetEvent("jg-advancedgarages:client:TakeOutVehicle:config", function(vehicle, vehicleDbData, type) + -- Code placed in here will be run after a vehicle has been taken out of a garage +end) + +---@param plate string +---@param newOwnerPlayerId integer +RegisterNetEvent("jg-advancedgarages:client:TransferVehicle:config", function(plate, newOwnerPlayerId) + -- Code placed in here will be fired when a vehicle is transferred to another player via a public garage +end) + +---@param vehicle integer Vehicle entity +---@param plate string +---@param garageId string +---@param vehicleDbData table Vehicle row from the database +---@param props table Vehicle properties +---@param fuel integer Fuel level +---@param body integer Body health +---@param engine integer Engine health +---@param damageModel table Damage model +RegisterNetEvent('jg-advancedgarages:client:insert-vehicle-verification', function(vehicle, plate, garageId, vehicleDbData, props, fuel, body, engine, damageModel, cb) + cb(true) +end) + +---@param plate string +---@param vehicleDbData table Vehicle row from the database +---@param garageId string +lib.callback.register("jg-advancedgarages:client:takeout-vehicle-verification", function(plate, vehicleDbData, garageId) + return true +end) + +-- Check whether a vehicle can be transferred between players, return false to prevent +---@param fromPlayerSrc integer +---@param toPlayerSrc integer +---@param plate string +---@return boolean allowTransfer +lib.callback.register("jg-advancedgarages:client:transfer-vehicle-verification", function(fromPlayerSrc, toPlayerSrc, plate) + return true +end) + +-- Check whether a vehicle can be transferred between garages, return false to prevent +---@param currentGarageId string +---@param fromGarageId string +---@param toGarageId string +---@param plate string +---@return boolean allowTransfer +lib.callback.register("jg-advancedgarages:client:transfer-garage-verification", function(currentGarageId, fromGarageId, toGarageId, plate) + return true +end) \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/config/config-sv.lua b/resources/[carscripts]/jg-advancedgarages/config/config-sv.lua new file mode 100644 index 000000000..1cf043d4e --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/config/config-sv.lua @@ -0,0 +1 @@ +-- Add your own server code in here for custom functionality \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/config/config.lua b/resources/[carscripts]/jg-advancedgarages/config/config.lua new file mode 100644 index 000000000..e2187251d --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/config/config.lua @@ -0,0 +1,669 @@ +-- Generated with https://configurator.jgscripts.com at 8/6/2025, 1:32:52 PM + +Config = {} +Config.Locale = 'de' +Config.NumberAndDateFormat = 'en-US' +Config.Currency = 'USD' +Config.Framework = 'QBCore' +Config.FuelSystem = 'none' +Config.VehicleKeys = 'qb-vehiclekeys' +Config.Notifications = 'ox_lib' +Config.DrawText = 'jg-textui' +Config.OpenGarageKeyBind = 38 +Config.OpenGaragePrompt = '[E] Open Garage' +Config.OpenImpoundKeyBind = 38 +Config.OpenImpoundPrompt = '[E] Open Impound' +Config.InsertVehicleKeyBind = 38 +Config.InsertVehiclePrompt = '[E] Store Vehicle' +Config.ExitInteriorKeyBind = 38 +Config.ExitInteriorPrompt = '[E] Exit Garage' +Config.UseTarget = true +Config.TargetPed = 's_m_y_valet_01' +Config.Target = 'ox_target' +Config.UseRadialMenu = false +Config.RadialMenu = 'ox_lib' +Config.ShowVehicleImages = false +Config.DoNotSpawnInsideVehicle = false +Config.SaveVehicleDamage = true +Config.AdvancedVehicleDamage = true +Config.SaveVehiclePropsOnInsert = true +Config.SpawnVehiclesWithServerSetter = false +Config.TransferHidePlayerNames = false +Config.GarageVehicleTransferCost = 0 +Config.EnableTransfers = { + betweenGarages = false, + betweenPlayers = true, +} +Config.AllowInfiniteVehicleSpawns = false +Config.JobGaragesAllowInfiniteVehicleSpawns = false +Config.GangGaragesAllowInfiniteVehicleSpawns = false +Config.GarageVehicleReturnCost = 0 +Config.GarageVehicleReturnCostSocietyFund = false +Config.GarageShowBlips = true +Config.GarageUniqueBlips = false +Config.GarageUniqueLocations = true +Config.GarageEnableInteriors = true +Config.GarageLocations = { + ['Legion Square'] = { + coords = vector3(215.09, -805.17, 30.81), + spawn = vector4(212.42, -798.77, 30.88, 336.61), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['Islington South'] = { + coords = vector3(273.0, -343.85, 44.91), + spawn = vector4(270.75, -340.51, 44.92, 342.03), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['Grove Street'] = { + coords = vector3(14.66, -1728.52, 29.3), + spawn = vector4(23.93, -1722.9, 29.3, 310.58), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['Mirror Park'] = { + coords = vector3(1032.84, -765.1, 58.18), + spawn = vector4(1023.2, -764.27, 57.96, 319.66), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + Beach = { + coords = vector3(-1248.69, -1425.71, 4.32), + spawn = vector4(-1244.27, -1422.08, 4.32, 37.12), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['Great Ocean Highway'] = { + coords = vector3(-2961.58, 375.93, 15.02), + spawn = vector4(-2964.96, 372.07, 14.78, 86.07), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['Sandy South'] = { + coords = vector3(217.33, 2605.65, 46.04), + spawn = vector4(216.94, 2608.44, 46.33, 14.07), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['Sandy North'] = { + coords = vector3(1878.44, 3760.1, 32.94), + spawn = vector4(1880.14, 3757.73, 32.93, 215.54), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['North Vinewood Blvd'] = { + coords = vector3(365.21, 295.65, 103.46), + spawn = vector4(364.84, 289.73, 103.42, 164.23), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + Grapeseed = { + coords = vector3(1713.06, 4745.32, 41.96), + spawn = vector4(1710.64, 4746.94, 41.95, 90.11), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['Paleto Bay'] = { + coords = vector3(107.32, 6611.77, 31.98), + spawn = vector4(110.84, 6607.82, 31.86, 265.28), + distance = 15, + type = 'car', + hideBlip = false, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + Boats = { + coords = vector3(-795.15, -1510.79, 1.6), + spawn = vector4(-798.66, -1507.73, -0.47, 102.23), + distance = 20, + type = 'sea', + hideBlip = false, + blip = { + id = 410, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + Hangar = { + coords = vector3(-1243.49, -3391.88, 13.94), + spawn = vector4(-1258.4, -3394.56, 13.94, 328.23), + distance = 20, + type = 'air', + hideBlip = false, + blip = { + id = 423, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, +} +Config.PrivGarageCreateCommand = 'privategarages' +Config.PrivGarageCreateJobRestriction = { + 'realestate', +} +Config.PrivGarageEnableInteriors = true +Config.PrivGarageHideBlips = false +Config.PrivGarageBlip = { + id = 357, + color = 0, + scale = 0.7, +} +Config.JobGarageShowBlips = true +Config.JobGarageUniqueBlips = false +Config.JobGarageSetVehicleCommand = 'setjobvehicle' +Config.JobGarageRemoveVehicleCommand = 'removejobvehicle' +Config.JobGarageUniqueLocations = true +Config.JobGarageEnableInteriors = true +Config.JobGarageLocations = { + Mechanic = { + coords = vector3(157.86, -3005.9, 7.03), + spawn = vector4(165.26, -3014.94, 5.9, 268.8), + distance = 15, + job = { + 'mechanic', + }, + type = 'car', + vehiclesType = 'owned', + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideBlip = false, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + Police = { + coords = vector3(434.48, -1016.97, 28.83), + spawn = { + vector4(434.55, -1014.54, 28.49, 91.56), + }, + distance = 15, + type = 'car', + job = { + 'police', + }, + hideBlip = false, + vehiclesType = 'personal', + vehicles = { + { + model = 'police', + plate = 'PD', + minJobGrade = 0, + }, + { + model = 'police2', + plate = false, + minJobGrade = 3, + }, + }, + blip = { + id = 357, + color = 0, + scale = 0.6, + }, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + showLiveriesExtrasMenu = true, + }, +} +Config.GangGarageShowBlips = true +Config.GangGarageUniqueBlips = false +Config.GangGarageSetVehicleCommand = 'setgangvehicle' +Config.GangGarageRemoveVehicleCommand = 'removegangvehicle' +Config.GangGarageUniqueLocations = true +Config.GangGarageEnableInteriors = true +Config.GangGarageLocations = {} +Config.ImpoundCommand = 'iv' +Config.ImpoundFeesSocietyFund = false +Config.ImpoundShowBlips = true +Config.ImpoundUniqueBlips = false +Config.ImpoundTimeOptions = { + 0, + 1, + 4, + 12, + 24, + 72, + 168, +} +Config.ImpoundLocations = { + ['Impound A'] = { + coords = vector3(410.8, -1626.26, 29.29), + spawn = vector4(408.44, -1630.88, 29.29, 136.88), + distance = 15, + type = 'car', + job = { + 'police', + }, + blip = { + id = 68, + color = 0, + scale = 0.6, + }, + hideBlip = false, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, + ['Impound B'] = { + coords = vector3(1649.71, 3789.61, 34.79), + spawn = vector4(1643.66, 3798.36, 34.49, 216.16), + distance = 15, + type = 'car', + job = { + 'police', + }, + blip = { + id = 68, + color = 0, + scale = 0.6, + }, + hideBlip = false, + hideMarkers = true, + markers = { + id = 21, + size = { + x = 0.3, + y = 0.3, + z = 0.3, + }, + color = { + r = 255, + g = 255, + b = 255, + a = 120, + }, + bobUpAndDown = 0, + faceCamera = 0, + rotate = 1, + drawOnEnts = 0, + }, + }, +} +Config.GarageInteriorEntrance = vector4(227.96, -1003.06, -99.0, 358.0) +Config.GarageInteriorVehiclePositions = { + vec4(233.000000, -984.000000, -99.410004, 118.000000), + vec4(233.000000, -988.500000, -99.410004, 118.000000), + vec4(233.000000, -993.000000, -99.410004, 118.000000), + vec4(233.000000, -997.500000, -99.410004, 118.000000), + vec4(233.000000, -1002.000000, -99.410004, 118.000000), + vec4(223.600006, -979.000000, -99.410004, 235.199997), + vec4(223.600006, -983.599976, -99.410004, 235.199997), + vec4(223.600006, -988.200012, -99.410004, 235.199997), + vec4(223.600006, -992.799988, -99.410004, 235.199997), + vec4(223.600006, -997.400024, -99.410004, 235.199997), + vec4(223.600006, -1002.000000, -99.410004, 235.199997), +} +Config.ChangeVehiclePlate = 'vplate' +Config.DeleteVehicleFromDB = 'dvdb' +Config.ReturnVehicleToGarage = 'vreturn' +Config.VehicleLabels = { + spawnName = 'Pretty Vehicle Label', +} +Config.PlayerTransferBlacklist = { + 'spawnName', +} +Config.ReturnToPreviousRoutingBucket = false +Config.__v3Config = true diff --git a/resources/[carscripts]/jg-advancedgarages/framework/cl-functions.lua b/resources/[carscripts]/jg-advancedgarages/framework/cl-functions.lua new file mode 100644 index 000000000..b6442ace3 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/framework/cl-functions.lua @@ -0,0 +1,535 @@ +---@param text string +function Framework.Client.ShowTextUI(text) + if (Config.DrawText == "auto" and GetResourceState("jg-textui") == "started") or Config.DrawText == "jg-textui" then + exports["jg-textui"]:DrawText(text) + elseif (Config.DrawText == "auto" and GetResourceState("ox_lib") == "started") or Config.DrawText == "ox_lib" then + exports["ox_lib"]:showTextUI(text, { + position = "left-center" + }) + elseif (Config.DrawText == "auto" and GetResourceState("okokTextUI") == "started") or Config.DrawText == "okokTextUI" then + exports["okokTextUI"]:Open(text, "lightblue", "left") + elseif (Config.DrawText == "auto" and GetResourceState("ps-ui") == "started") or Config.DrawText == "ps-ui" then + exports["ps-ui"]:DisplayText(text, "primary") + elseif Config.Framework == "QBCore" then + exports["qb-core"]:DrawText(text) + else + error("You do not have a TextUI system set up!") + end +end + +function Framework.Client.HideTextUI() + if (Config.DrawText == "auto" and GetResourceState("jg-textui") == "started") or Config.DrawText == "jg-textui" then + exports["jg-textui"]:HideText() + elseif (Config.DrawText == "auto" and GetResourceState("ox_lib") == "started") or Config.DrawText == "ox_lib" then + exports["ox_lib"]:hideTextUI() + elseif (Config.DrawText == "auto" and GetResourceState("okokTextUI") == "started") or Config.DrawText == "okokTextUI" then + exports["okokTextUI"]:Close() + elseif (Config.DrawText == "auto" and GetResourceState("ps-ui") == "started") or Config.DrawText == "ps-ui" then + exports["ps-ui"]:HideText() + elseif Config.Framework == "QBCore" then + exports["qb-core"]:HideText() + else + error("You do not have a TextUI system set up!") + end +end + +---@param garageId string +---@param text string +---@param onSelect function +function Framework.Client.RadialMenuAdd(garageId, text, onSelect) + if not Config.UseRadialMenu then return end + + if (Config.RadialMenu == "auto" and GetResourceState("ox_lib") == "started") or Config.RadialMenu == "ox_lib" then + lib.addRadialItem({ + id = garageId, + icon = "warehouse", + label = text, + onSelect = onSelect + }) + else + error("You do not have a radial menu system set up!") + end +end + +---@param garageId string +function Framework.Client.RadialMenuRemove(garageId) + if not Config.UseRadialMenu then return end + + if (Config.RadialMenu == "auto" and GetResourceState("ox_lib") == "started") or Config.RadialMenu == "ox_lib" then + lib.removeRadialItem(garageId) + else + error("You do not have a radial menu system set up!") + end +end + +---@param entity? integer|false +---@param coords vector4|vector3 +---@param garageId string +---@param vehicleType "car"|"air"|"sea" +---@param garageType "personal"|"job"|"gang"|"impound" +---@return integer +function Framework.Client.RegisterTarget(entity, coords, garageId, vehicleType, garageType) + if not entity then + entity = createPedForTarget(coords) + end + + if (Config.Target == "auto" and GetResourceState("ox_target") == "started") or Config.Target == "ox_target" then + exports.ox_target:addLocalEntity(entity, { + { + label = garageType == "impound" and Config.OpenImpoundPrompt or Config.OpenGaragePrompt, + icon = "warehouse", + onSelect = function() + TriggerEvent("jg-advancedgarages:client:open-garage", garageId, vehicleType, false) + end + }, + garageType ~= "impound" and { + label = Config.InsertVehiclePrompt, + icon = "warehouse", + onSelect = function() + TriggerEvent("jg-advancedgarages:client:store-vehicle", garageId, vehicleType, false) + end + } or nil + }) + elseif (Config.Target == "auto" and GetResourceState("qb-target") == "started") or Config.Target == "qb-target" then + exports["qb-target"]:AddTargetEntity(entity, { + options = { + { + label = garageType == "impound" and Config.OpenImpoundPrompt or Config.OpenGaragePrompt, + targeticon = "fas fa-warehouse", + action = function() + TriggerEvent("jg-advancedgarages:client:open-garage", garageId, vehicleType, false) + end + }, + garageType ~= "impound" and { + label = Config.InsertVehiclePrompt, + targeticon = "fas fa-warehouse", + action = function() + TriggerEvent("jg-advancedgarages:client:store-vehicle", garageId, vehicleType, false) + end + } or nil + }, + distance = 10.0 + }) + else + error("You do not have a target system set up!") + end + + return entity +end + +---@param entity integer +function Framework.Client.RemoveTarget(entity) + if not entity then return end + + DeleteEntity(entity) + + if (Config.Target == "auto" and GetResourceState("ox_target") == "started") or Config.Target == "ox_target" then + exports.ox_target:removeLocalEntity(entity) + elseif (Config.Target == "auto" and GetResourceState("qb-target") == "started") or Config.Target == "qb-target" then + exports["qb-target"]:RemoveTargetEntity(entity) + else + error("You do not have a target system set up!") + end +end + +---@param msg string +---@param type? "success" | "warning" | "error" +---@param time? number +function Framework.Client.Notify(msg, type, time) + type = type or "success" + time = time or 5000 + + if (Config.Notifications == "auto" and GetResourceState("okokNotify") == "started") or Config.Notifications == "okokNotify" then + exports["okokNotify"]:Alert("Garages", msg, time, type) + elseif (Config.Notifications == "auto" and GetResourceState("ps-ui") == "started") or Config.Notifications == "ps-ui" then + exports["ps-ui"]:Notify(msg, type, time) + elseif (Config.Notifications == "auto" and GetResourceState("ox_lib") == "started") or Config.Notifications == "ox_lib" then + exports["ox_lib"]:notify({ + title = "Garages", + description = msg, + type = type + }) + else + if Config.Framework == "QBCore" then + return QBCore.Functions.Notify(msg, type, time) + elseif Config.Framework == "Qbox" then + exports.qbx_core:Notify(msg, type, time) + elseif Config.Framework == "ESX" then + return ESX.ShowNotification(msg, type) + end + end +end + +RegisterNetEvent("jg-advancedgarages:client:notify", function(...) + Framework.Client.Notify(...) +end) + +-- +-- Player Functions +-- + +---@return table | false playerData +function Framework.Client.GetPlayerData() + if Config.Framework == "QBCore" then + return QBCore.Functions.GetPlayerData() + elseif Config.Framework == "Qbox" then + return exports.qbx_core:GetPlayerData() + elseif Config.Framework == "ESX" then + return ESX.GetPlayerData() + end + + return false +end + +---@return string | false identifier +function Framework.Client.GetPlayerIdentifier() + local playerData = Framework.Client.GetPlayerData() + if not playerData then return false end + + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + return playerData.citizenid + elseif Config.Framework == "ESX" then + return playerData.identifier + end + + return false +end + +---@param type "cash" | "bank" | "money" +function Framework.Client.GetBalance(type) + if Config.Framework == "QBCore" then + return QBCore.Functions.GetPlayerData().money[type] + elseif Config.Framework == "Qbox" then + return exports.qbx_core:GetPlayerData().money[type] + elseif Config.Framework == "ESX" then + if type == "cash" then type = "money" end + + for i, acc in pairs(ESX.GetPlayerData().accounts) do + if acc.name == type then + return acc.money + end + end + + return 0 + end +end + +---@return {name: string, grade: number} | false job +function Framework.Client.GetPlayerJob() + local player = Framework.Client.GetPlayerData() + if not player or not player.job then return {} end + + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + return { + name = player.job.name, + label = player.job.label, + grade = player.job.grade.level + } + elseif Config.Framework == "ESX" then + return { + name = player.job.name, + label = player.job.label, + grade = player.job.grade + } + end + + return false +end + +---@return {name: string, grade: number} | false gang +function Framework.Client.GetPlayerGang() + if (Config.Gangs == "auto" and GetResourceState("rcore_gangs") == "started") or Config.Gangs == "rcore_gangs" then + local gang = exports.rcore_gangs:GetPlayerGang() + if not gang then return {} end + + return { + name = gang.name, + label = gang.name, + grade = 0 -- rcore_gangs' grade system are only strings + } + elseif (Config.Gangs == "auto" and GetResourceState("qb-gangs") == "started") or Config.Gangs == "qb-gangs" or Config.Framework == "QBCore" or Config.Framework == "Qbox" then + local player = Framework.Client.GetPlayerData() + if not player or not player.gang then return {} end + + return { + name = player.gang.name, + label = player.gang.label, + grade = player.gang.grade.level + } + elseif Config.Framework == "ESX" then + -- To implement gangs in ESX, enable Config.GangEnableCustomESXIntegration & then add the necessary exports here. + -- It must return the same data structure as QB/X above, with { name, label, grade } + -- Heads up, you must also add the exports to sv-functions.lua -> Framework.Server.GetPlayerGang + error("ESX does not natively support gangs."); + end + + return false +end + +---@return boolean dead +function Framework.Client.IsPlayerDead() + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + local player = Framework.Client.GetPlayerData() + if not player then return false end + + if player.metadata.isdead or player.metadata.inlaststand then + return true + end + elseif Config.Framework == "ESX" then + return IsEntityDead(cache.ped) + end + + return false +end + +-- +-- Vehicle Functions +-- + +---@param vehicle integer +---@return number fuelLevel +function Framework.Client.VehicleGetFuel(vehicle) + if not DoesEntityExist(vehicle) then return 0 end + + if (Config.FuelSystem == "LegacyFuel" or Config.FuelSystem == "ps-fuel" or Config.FuelSystem == "lj-fuel" or Config.FuelSystem == "cdn-fuel" or Config.FuelSystem == "hyon_gas_station" or Config.FuelSystem == "okokGasStation" or Config.FuelSystem == "nd_fuel" or Config.FuelSystem == "myFuel") then + return exports[Config.FuelSystem]:GetFuel(vehicle) + elseif Config.FuelSystem == "ti_fuel" then + local level, type = exports["ti_fuel"]:getFuel(vehicle) + TriggerServerEvent("jg-advancedgarages:server:save-ti-fuel-type", Framework.Client.GetPlate(vehicle), type) + return level + elseif Config.FuelSystem == "ox_fuel" or Config.FuelSystem == "Renewed-Fuel" then + return GetVehicleFuelLevel(vehicle) + elseif Config.FuelSystem == "rcore_fuel" then + return exports.rcore_fuel:GetVehicleFuelPercentage(vehicle) + else + return 65 -- or set up custom fuel system here... + end +end + +---@param vehicle integer +---@param fuel number +function Framework.Client.VehicleSetFuel(vehicle, fuel) + if not DoesEntityExist(vehicle) then return false end + + if (Config.FuelSystem == "LegacyFuel" or Config.FuelSystem == "ps-fuel" or Config.FuelSystem == "lj-fuel" or Config.FuelSystem == "cdn-fuel" or Config.FuelSystem == "hyon_gas_station" or Config.FuelSystem == "okokGasStation" or Config.FuelSystem == "nd_fuel" or Config.FuelSystem == "myFuel" or Config.FuelSystem == "Renewed-Fuel") then + exports[Config.FuelSystem]:SetFuel(vehicle, fuel) + elseif Config.FuelSystem == "ti_fuel" then + local fuelType = lib.callback.await("jg-advancedgarages:server:get-ti-fuel-type", false, Framework.Client.GetPlate(vehicle)) + exports["ti_fuel"]:setFuel(vehicle, fuel, fuelType or nil) + elseif Config.FuelSystem == "ox_fuel" then + Entity(vehicle).state.fuel = fuel + elseif Config.FuelSystem == "rcore_fuel" then + exports.rcore_fuel:SetVehicleFuel(vehicle, fuel) + else + -- Setup custom fuel system here + end +end + +---@param plate string +---@param vehicleEntity integer +---@param origin "personal" | "job" | "gang" +function Framework.Client.VehicleGiveKeys(plate, vehicleEntity, origin) + if not DoesEntityExist(vehicleEntity) then return false end + if not plate or plate == "" then + print("^1[ERROR] No plate provided to VehicleGiveKeys function^0") + return false + end + + plate = plate:upper() + + if Config.VehicleKeys == "qb-vehiclekeys" then + TriggerEvent("vehiclekeys:client:SetOwner", plate) + elseif Config.VehicleKeys == "qbx_vehiclekeys" then + TriggerEvent("vehiclekeys:client:SetOwner", plate) + -- lib.callback.await("qbx_vehiclekeys:server:giveKeys", false, VehToNet(vehicleEntity)) + elseif Config.VehicleKeys == "jaksam-vehicles-keys" then + TriggerServerEvent("vehicles_keys:selfGiveVehicleKeys", plate) + elseif Config.VehicleKeys == "mk_vehiclekeys" then + exports["mk_vehiclekeys"]:AddKey(vehicleEntity) + elseif Config.VehicleKeys == "qs-vehiclekeys" then + local model = GetDisplayNameFromVehicleModel(GetEntityModel(vehicleEntity)) + exports["qs-vehiclekeys"]:GiveKeys(plate, model) + elseif Config.VehicleKeys == "wasabi_carlock" then + exports.wasabi_carlock:GiveKey(plate) + elseif Config.VehicleKeys == "cd_garage" then + TriggerEvent("cd_garage:AddKeys", plate) + elseif Config.VehicleKeys == "okokGarage" then + TriggerServerEvent("okokGarage:GiveKeys", plate) + elseif Config.VehicleKeys == "t1ger_keys" then + if origin == "job" then + local vehicleName = GetDisplayNameFromVehicleModel(GetEntityModel(vehicleEntity)) + exports['t1ger_keys']:GiveJobKeys(plate, vehicleName, true) + else + TriggerServerEvent("t1ger_keys:updateOwnedKeys", plate, true) + end + elseif Config.VehicleKeys == "MrNewbVehicleKeys" then + exports.MrNewbVehicleKeys:GiveKeys(vehicleEntity) + elseif Config.VehicleKeys == "Renewed" then + exports["Renewed-Vehiclekeys"]:addKey(plate) + elseif Config.VehicleKeys == "tgiann-hotwire" then + exports["tgiann-hotwire"]:CheckKeyInIgnitionWhenSpawn(vehicleEntity, plate) + else + -- Setup custom key system here... + end +end + +---@param plate string +---@param vehicleEntity integer +---@param origin "personal" | "job" | "gang" +function Framework.Client.VehicleRemoveKeys(plate, vehicleEntity, origin) + if not DoesEntityExist(vehicleEntity) then return false end + if not plate or plate == "" then + print("^1[ERROR] No plate provided to VehicleRemoveKeys function^0") + return false + end + + plate = plate:upper() + + if Config.VehicleKeys == "qs-vehiclekeys" then + local model = GetDisplayNameFromVehicleModel(GetEntityModel(vehicleEntity)) + exports["qs-vehiclekeys"]:RemoveKeys(plate, model) + elseif Config.VehicleKeys == "wasabi_carlock" then + exports.wasabi_carlock:RemoveKey(plate) + elseif Config.VehicleKeys == "t1ger_keys" then + TriggerServerEvent("t1ger_keys:updateOwnedKeys", plate, false) + elseif Config.VehicleKeys == "MrNewbVehicleKeys" then + exports.MrNewbVehicleKeys:RemoveKeys(vehicleEntity) + elseif Config.VehicleKeys == "Renewed" then + exports["Renewed-Vehiclekeys"]:removeKey(plate) + else + -- Setup custom key system here... + end +end + + +---@param vehicle table +---@return string|number|false model +function Framework.Client.GetModelColumn(vehicle) + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + return vehicle.vehicle or tonumber(vehicle.hash) or false + elseif Config.Framework == "ESX" then + if not vehicle or not vehicle.vehicle then return false end + + if type(vehicle.vehicle) == "string" then + if not json.decode(vehicle.vehicle) then return false end + return json.decode(vehicle.vehicle).model + else + return vehicle.vehicle.model + end + end + + return false +end + +---@param vehicle integer +---@return table | false +function Framework.Client.GetModsColumn(vehicle) + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + if type(vehicle.mods) == "string" then + return json.decode(vehicle.mods) + else + return vehicle.mods + end + elseif Config.Framework == "ESX" then + if type(vehicle.vehicle) == "string" then + return json.decode(vehicle.vehicle) + else + return vehicle.vehicle + end + end + + return false +end + +---@param vehicle integer +---@return table|false props +function Framework.Client.GetVehicleProperties(vehicle) + if GetResourceState("jg-mechanic") == "started" then + return exports["jg-mechanic"]:getVehicleProperties(vehicle) + else + if Config.Framework == "QBCore" then + return QBCore.Functions.GetVehicleProperties(vehicle) + elseif Config.Framework == "Qbox" then + return lib.getVehicleProperties(vehicle) or false + elseif Config.Framework == "ESX" then + return ESX.Game.GetVehicleProperties(vehicle) + end + end + + return false +end + +---@param vehicle integer +---@param props table +function Framework.Client.SetVehicleProperties(vehicle, props) + if GetResourceState("jg-mechanic") == "started" then + return exports["jg-mechanic"]:setVehicleProperties(vehicle, props) + else + if Config.Framework == "QBCore" then + return QBCore.Functions.SetVehicleProperties(vehicle, props) + elseif Config.Framework == "Qbox" then + return lib.setVehicleProperties(vehicle, props) + elseif Config.Framework == "ESX" then + return ESX.Game.SetVehicleProperties(vehicle, props) + end + end +end + +---@param vehicle integer +---@return string|false plate +function Framework.Client.GetPlate(vehicle) + local plate = GetVehicleNumberPlateText(vehicle) + if not plate or plate == nil or plate == "" then return false end + + if GetResourceState("brazzers-fakeplates") == "started" then + local originalPlate = lib.callback.await("jg-advancedgarages:server:brazzers-get-plate-from-fakeplate", false, plate) + if originalPlate then plate = originalPlate end + end + + local trPlate = string.gsub(plate, "^%s*(.-)%s*$", "%1") + return trPlate +end + +-- Get a nice vehicle label from either QBCore shared or GTA natives +---@param model string | number +function Framework.Client.GetVehicleLabel(model) + local hash = convertModelToHash(model) + + if Config.VehicleLabels[model] then + return Config.VehicleLabels[model] + end + + if Config.VehicleLabels[tostring(hash)] then + return Config.VehicleLabels[tostring(hash)] + end + + if type(model) == "string" and Config.Framework == "QBCore" then + local vehShared = QBCore.Shared.Vehicles?[model] + if vehShared then + return vehShared.brand .. " " .. vehShared.name + end + end + + if Config.Framework == "Qbox" then + local vehShared = exports.qbx_core:GetVehiclesByHash()?[hash] + if vehShared then + return vehShared.brand .. " " .. vehShared.name + end + end + + local makeName = GetMakeNameFromVehicleModel(hash) + local modelName = GetDisplayNameFromVehicleModel(hash) + local label = GetLabelText(makeName) .. " " .. GetLabelText(modelName) + + if makeName == "CARNOTFOUND" or modelName == "CARNOTFOUND" then + label = tostring(model) + else + if GetLabelText(modelName) == "NULL" and GetLabelText(makeName) == "NULL" then + label = (makeName or "") .. " " .. (modelName or "") + elseif GetLabelText(makeName) == "NULL" then + label = GetLabelText(modelName) + end + end + + return label +end \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/framework/esx/cl-esx.lua b/resources/[carscripts]/jg-advancedgarages/framework/esx/cl-esx.lua new file mode 100644 index 000000000..82d22e102 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/framework/esx/cl-esx.lua @@ -0,0 +1,37 @@ +if (Config.Framework == "auto" and GetResourceState("es_extended") == "started") or Config.Framework == "ESX" then + -- Player data + Globals.PlayerData = ESX.GetPlayerData() + + RegisterNetEvent("esx:playerLoaded") + AddEventHandler("esx:playerLoaded", function(xPlayer) + Globals.PlayerData = xPlayer + TriggerEvent("jg-advancedgarages:client:update-blips-text-uis") + end) + + RegisterNetEvent("esx:setJob") + AddEventHandler("esx:setJob", function(job) + Globals.PlayerData.job = job + TriggerEvent("jg-advancedgarages:client:update-blips-text-uis") + end) + + -- ESX admincar replacement + RegisterNetEvent("jg-advancedgarages:client:set-vehicle-owned", function() + local vehicle = cache.vehicle + local vehicleProps = Framework.Client.GetVehicleProperties(vehicle) + if not vehicleProps then return end + + if not vehicle or vehicle == 0 then + return Framework.Client.Notify(Locale.notInsideVehicleError, "error") + end + + local plate = vehicleProps.plate + + local vehicleModel = GetEntityArchetypeName(vehicle) + local veh = lib.callback.await("jg-advancedgarages:server:get-vehicle", false, vehicleModel, plate) + if veh then + return Framework.Client.Notify(Locale.vehiclePlateExistsError, "error") + end + + TriggerServerEvent("jg-advancedgarages:server:set-vehicle-owned", vehicleProps) + end) +end diff --git a/resources/[carscripts]/jg-advancedgarages/framework/esx/sv-esx.lua b/resources/[carscripts]/jg-advancedgarages/framework/esx/sv-esx.lua new file mode 100644 index 000000000..22b64fd00 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/framework/esx/sv-esx.lua @@ -0,0 +1,23 @@ +if (Config.Framework == "auto" and GetResourceState("es_extended") == "started") or Config.Framework == "ESX" then + -- /admincar db insert + RegisterNetEvent("jg-advancedgarages:server:set-vehicle-owned", function(vehicleProps) + local src = source + + if not Framework.Server.IsAdmin(src) then + return Framework.Server.Notify(src, "INSUFFICIENT_PERMISSIONS", "error") + end + + local player = ESX.GetPlayerFromId(src) + + MySQL.insert.await("INSERT INTO owned_vehicles (owner, plate, vehicle) VALUES (?, ?, ?)", { + player.identifier, vehicleProps.plate, json.encode(vehicleProps) + }) + + Framework.Server.Notify(src, string.gsub(Locale.vehicleReceived, "%%{value}", vehicleProps.plate)) + end) + + -- /admincar command + ESX.RegisterCommand("admincar", "admin", function(xPlayer) + TriggerClientEvent("jg-advancedgarages:client:set-vehicle-owned", xPlayer.source) + end, false) +end diff --git a/resources/[carscripts]/jg-advancedgarages/framework/main.lua b/resources/[carscripts]/jg-advancedgarages/framework/main.lua new file mode 100644 index 000000000..3322c2555 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/framework/main.lua @@ -0,0 +1,61 @@ +QBCore, ESX = nil, nil +Framework = { + Client = {}, + Server = {}, + Queries = { + GetVehicles = "SELECT * FROM %s WHERE %s = ? AND job_vehicle = 0 AND gang_vehicle = 0", + GetJobVehicles = "SELECT * FROM %s WHERE %s = ? AND job_vehicle = 1 AND job_vehicle_rank <= ?", + GetGangVehicles = "SELECT * FROM %s WHERE %s = ? AND gang_vehicle = 1 AND gang_vehicle_rank <= ?", + GetImpoundVehiclesWhitelist = "SELECT * FROM %s WHERE garage_id = ? AND impound = 1", + GetImpoundVehiclesPublic = "SELECT * FROM %s WHERE garage_id = ? AND impound = 1 AND impound_retrievable = 1 AND (%s = ? OR %s = ? OR %s = ?)", + GetVehicle = "SELECT * FROM %s WHERE %s = ? AND plate = ?", + GetVehicleNoIdentifier = "SELECT * FROM %s WHERE plate = ?", + GetVehiclePlateOnly = "SELECT plate FROM %s WHERE plate = ?", + GetPrivateGarages = "SELECT * FROM player_priv_garages WHERE owners LIKE ?", + StoreVehicle = "UPDATE %s SET in_garage = 1, garage_id = ?, fuel = ?, body = ?, engine = ?, damage = ? WHERE %s IN (?) AND plate = ?", + SetInGarage = "UPDATE %s SET in_garage = 1 WHERE plate = ?", + UpdateProps = "UPDATE %s SET %s = ? WHERE plate = ?", + VehicleDriveOut = "UPDATE %s SET in_garage = 0 WHERE %s = ? AND plate = ?", + UpdateGarageId = "UPDATE %s SET garage_id = ? WHERE %s = ? AND plate = ?", + UpdatePlayerId = "UPDATE %s SET %s = ? WHERE %s = ? AND plate = ?", + UpdateVehicleNickname = "UPDATE %s SET nickname = ? WHERE %s = ? AND plate = ?", + UpdateVehiclePlate = "UPDATE %s SET plate = ?, %s = ? WHERE plate = ?", + ImpoundVehicle = "UPDATE %s SET impound = 1, impound_retrievable = ?, impound_data = ?, garage_id = ?, fuel = ?, body = ?, engine = ?, damage = ? WHERE plate = ?", + ImpoundReturnToGarage = "UPDATE %s SET impound = 0, impound_data = '', garage_id = ?, in_garage = ? WHERE plate = ?", + SetJobVehicle = "UPDATE %s SET %s = ?, job_vehicle = 1, job_vehicle_rank = ? WHERE plate = ?", + SetGangVehicle = "UPDATE %s SET %s = ?, gang_vehicle = 1, gang_vehicle_rank = ? WHERE plate = ?", + SetSocietyVehicleAsPlayerOwned = "UPDATE %s SET %s = ?, job_vehicle = 0, gang_vehicle = 0 WHERE plate = ?", + DeleteVehicle = "DELETE FROM %s WHERE plate = ?", + } +} + +if (Config.Framework == "auto" and GetResourceState("qbx_core") == "started") or Config.Framework == "Qbox" then + Config.Framework = "Qbox" + + Framework.VehiclesTable = "player_vehicles" + Framework.PlayerIdentifier = "citizenid" + Framework.VehProps = "mods" + Framework.PlayersTable = "players" + Framework.PlayersTableId = "citizenid" +elseif (Config.Framework == "auto" and GetResourceState("qb-core") == "started") or Config.Framework == "QBCore" then + QBCore = exports['qb-core']:GetCoreObject() + Config.Framework = "QBCore" + + Framework.VehiclesTable = "player_vehicles" + Framework.PlayerIdentifier = "citizenid" + Framework.VehProps = "mods" + Framework.PlayersTable = "players" + Framework.PlayersTableId = "citizenid" + +elseif (Config.Framework == "auto" and GetResourceState("es_extended") == "started") or Config.Framework == "ESX" then + ESX = exports["es_extended"]:getSharedObject() + Config.Framework = "ESX" + + Framework.VehiclesTable = "owned_vehicles" + Framework.PlayerIdentifier = "owner" + Framework.VehProps = "vehicle" + Framework.PlayersTable = "users" + Framework.PlayersTableId = "identifier" +else + error("You need to set the Config.Framework to either \"QBCore\" or \"ESX\" or \"Qbox\"!") +end diff --git a/resources/[carscripts]/jg-advancedgarages/framework/qb/cl-qb.lua b/resources/[carscripts]/jg-advancedgarages/framework/qb/cl-qb.lua new file mode 100644 index 000000000..31cdb1eda --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/framework/qb/cl-qb.lua @@ -0,0 +1,22 @@ +if (Config.Framework == "auto" and GetResourceState("qb-core") == "started") or Config.Framework == "QBCore" then + -- Player data + Globals.PlayerData = QBCore.Functions.GetPlayerData() + + RegisterNetEvent("QBCore:Client:OnPlayerLoaded") + AddEventHandler("QBCore:Client:OnPlayerLoaded", function() + Globals.PlayerData = QBCore.Functions.GetPlayerData() + TriggerEvent("jg-advancedgarages:client:update-blips-text-uis") + end) + + RegisterNetEvent("QBCore:Client:OnJobUpdate") + AddEventHandler("QBCore:Client:OnJobUpdate", function(job) + Globals.PlayerData.job = job + TriggerEvent("jg-advancedgarages:client:update-blips-text-uis") + end) + + RegisterNetEvent("QBCore:Client:OnGangUpdate") + AddEventHandler("QBCore:Client:OnGangUpdate", function(gang) + Globals.PlayerData.gang = gang + TriggerEvent("jg-advancedgarages:client:update-blips-text-uis") + end) +end diff --git a/resources/[carscripts]/jg-advancedgarages/framework/qb/sv-qb.lua b/resources/[carscripts]/jg-advancedgarages/framework/qb/sv-qb.lua new file mode 100644 index 000000000..168443bb0 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/framework/qb/sv-qb.lua @@ -0,0 +1,55 @@ +if (Config.Framework == "auto" and GetResourceState("qb-core") == "started") or Config.Framework == "QBCore" then + -- qb-phone fix + QBCore.Functions.CreateCallback("jg-advancedgarages:server:GetVehiclesPhone", function(source, cb) + local Player = QBCore.Functions.GetPlayer(source) + + local vehicles = MySQL.query.await("SELECT * FROM player_vehicles WHERE citizenid = ? AND job_vehicle = ? AND gang_vehicle = ?", {Player.PlayerData.citizenid, 0, 0}) + + for i, vehicle in pairs(vehicles) do + local vehShared = QBCore.Shared.Vehicles[vehicle.vehicle] + local vehBrand, vehName, vehState + local vehGarage = vehicle.garage_id + + if vehShared then + vehBrand = vehShared.brand + vehName = vehShared.name + else + vehBrand = "" + vehName = vehicle.vehicle + end + + if vehicle.impound == 1 then + vehGarage = Locale.impound + vehState = json.decode(vehicle.impound_data).reason + elseif vehicle.in_garage then + vehState = Locale.inGarage + else + vehState = Locale.notInGarage + end + + vehicles[i] = { + fullname = vehBrand .. " " .. vehName, + brand = vehBrand, + model = vehName, + garage = vehGarage, + state = vehState, + plate = vehicle.plate, + fuel = vehicle.fuel, + engine = vehicle.engine, + body = vehicle.body + } + end + + cb(vehicles) + end) + + -- qb-vehiclesales fix + QBCore.Functions.CreateCallback("qb-garage:server:checkVehicleOwner", function(source, cb, plate) + local src = source + local pData = QBCore.Functions.GetPlayer(src) + + local result = MySQL.single.await("SELECT * FROM player_vehicles WHERE plate = ? AND citizenid = ?", {plate, pData.PlayerData.citizenid}) + if result then cb(true, result.balance) + else cb(false) end + end) +end diff --git a/resources/[carscripts]/jg-advancedgarages/framework/qbx/cl-qbx.lua b/resources/[carscripts]/jg-advancedgarages/framework/qbx/cl-qbx.lua new file mode 100644 index 000000000..b6b32b18a --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/framework/qbx/cl-qbx.lua @@ -0,0 +1,22 @@ +if (Config.Framework == "auto" and GetResourceState("qbx_core") == "started") or Config.Framework == "Qbox" then + -- Player data + Globals.PlayerData = exports.qbx_core:GetPlayerData() + + RegisterNetEvent("QBCore:Client:OnPlayerLoaded") + AddEventHandler("QBCore:Client:OnPlayerLoaded", function() + Globals.PlayerData = exports.qbx_core:GetPlayerData() + TriggerEvent("jg-advancedgarages:client:update-blips-text-uis") + end) + + RegisterNetEvent("QBCore:Client:OnJobUpdate") + AddEventHandler("QBCore:Client:OnJobUpdate", function(job) + Globals.PlayerData.job = job + TriggerEvent("jg-advancedgarages:client:update-blips-text-uis") + end) + + RegisterNetEvent("QBCore:Client:OnGangUpdate") + AddEventHandler("QBCore:Client:OnGangUpdate", function(gang) + Globals.PlayerData.gang = gang + TriggerEvent("jg-advancedgarages:client:update-blips-text-uis") + end) +end diff --git a/resources/[carscripts]/jg-advancedgarages/framework/sv-functions.lua b/resources/[carscripts]/jg-advancedgarages/framework/sv-functions.lua new file mode 100644 index 000000000..20276a60e --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/framework/sv-functions.lua @@ -0,0 +1,317 @@ +-- +-- Core Functions +-- + +---@param src integer +---@param msg string +---@param type "success" | "warning" | "error" +function Framework.Server.Notify(src, msg, type) + TriggerClientEvent("jg-advancedgarages:client:notify", src, msg, type, 5000) +end + +---@param src integer +---@returns boolean +function Framework.Server.IsAdmin(src) + return IsPlayerAceAllowed(tostring(src), "command") or false +end + +function Framework.Server.PayIntoSocietyFund(jobName, money) + local usingNewQBBanking = GetResourceState("qb-banking") == "started" and tonumber(string.sub(GetResourceMetadata("qb-banking", "version", 0), 1, 3)) >= 2 + + if (Config.Banking == "auto" and GetResourceState("Renewed-Banking") == "started") or Config.Banking == "Renewed-Banking" then + exports['Renewed-Banking']:addAccountMoney(jobName, money) + elseif (Config.Banking == "auto" and GetResourceState("okokBanking") == "started") or Config.Banking == "okokBanking" then + exports['okokBanking']:AddMoney(jobName, money) + elseif (Config.Banking == "auto" and GetResourceState("fd_banking") == "started") or Config.banking == "fd_banking" then + exports.fd_banking:AddMoney(jobName, money) + elseif (Config.Banking == "auto" and (Config.Framework == "QBCore" or Config.Framework == "Qbox")) then + if usingNewQBBanking then + exports["qb-banking"]:AddMoney(jobName, money) + else + exports["qb-management"]:AddMoney(jobName, money) + end + elseif Config.Banking == "qb-banking" then + exports["qb-banking"]:AddMoney(jobName, money) + elseif Config.Banking == "qb-management" then + exports["qb-management"]:AddMoney(jobName, money) + elseif (Config.Banking == "auto" and Config.Framework == "ESX") or Config.Banking == "esx_addonaccount" then + TriggerEvent("esx_society:getSociety", jobName, function(society) + TriggerEvent("esx_addonaccount:getSharedAccount", society.account, function(account) + account.addMoney(money) + end) + end) + end +end + +-- +-- Player Functions +-- + +---@param src integer +function Framework.Server.GetPlayer(src) + if Config.Framework == "QBCore" then + return QBCore.Functions.GetPlayer(src) + elseif Config.Framework == "Qbox" then + return exports.qbx_core:GetPlayer(src) + elseif Config.Framework == "ESX" then + return ESX.GetPlayerFromId(src) + end +end + +---@param src integer +function Framework.Server.GetPlayerInfo(src) + local player = Framework.Server.GetPlayer(src) + if not player then return false end + + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + return { + name = player.PlayerData.charinfo.firstname .. " " .. player.PlayerData.charinfo.lastname + } + elseif Config.Framework == "ESX" then + return { + name = player.getName() + } + end +end + +---@param src integer +---@return {name:string,label:string,grade:number} | false +function Framework.Server.GetPlayerJob(src) + local player = Framework.Server.GetPlayer(src) + if not player then return false end + + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + if not player.PlayerData then return false end + + return { + name = player.PlayerData.job.name, + label = player.PlayerData.job.label, + grade = player.PlayerData.job.grade?.level or 0, + } + elseif Config.Framework == "ESX" then + return { + name = player.job.name, + label = player.job.label, + grade = player.job.grade + } + end + + return false +end + +---@param src integer +---@return {name:string,label:string,grade:number} | false +function Framework.Server.GetPlayerGang(src) + if (Config.Gangs == "auto" and GetResourceState("rcore_gangs") == "started") or Config.Gangs == "rcore_gangs" then + local gang = exports.rcore_gangs:GetPlayerGang(src) + if not gang then return {} end + + return { + name = gang.name, + label = gang.name, + grade = 0 -- rcore_gangs' grade system are only strings + } + elseif (Config.Gangs == "auto" and GetResourceState("qb-gangs") == "started") or Config.Gangs == "qb-gangs" or Config.Framework == "QBCore" or Config.Framework == "Qbox" then + + local player = Framework.Server.GetPlayer(src) + if not player then return false end + + return { + name = player.PlayerData.gang.name, + label = player.PlayerData.gang.label, + grade = player.PlayerData.gang.grade.level + } + elseif Config.Framework == "ESX" then + -- To implement gangs in ESX, enable Config.GangEnableCustomESXIntegration & then add the necessary exports here. + -- It must return the same data structure as QB/X above, with { name, label, grade } + -- Heads up, you must also add the exports to cl-functions.lua -> Framework.Client.GetPlayerGang + error("ESX does not natively support gangs."); + end + + return false +end + +---@param src integer +function Framework.Server.GetPlayerIdentifier(src) + local player = Framework.Server.GetPlayer(src) + if not player then return false end + + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + return player.PlayerData.citizenid + elseif Config.Framework == "ESX" then + return player.getIdentifier() + end +end + +---@param identifier string +function Framework.Server.GetSrcFromIdentifier(identifier) + if Config.Framework == "QBCore" then + local player = QBCore.Functions.GetPlayerByCitizenId(identifier) + if not player then return false end + return player.PlayerData.source + elseif Config.Framework == "Qbox" then + local player = exports.qbx_core:GetPlayerByCitizenId(identifier) + if not player then return false end + return player.PlayerData.source + elseif Config.Framework == "ESX" then + local xPlayer = ESX.GetPlayerFromIdentifier(identifier) + if not xPlayer then return false end + return xPlayer.source + end +end + +---@param src integer +---@param type "cash" | "bank" | "money" +function Framework.Server.GetPlayerBalance(src, type) + local player = Framework.Server.GetPlayer(src) + if not player then return 0 end + + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + return player.PlayerData.money[type] + elseif Config.Framework == "ESX" then + if type == "cash" then type = "money" end + + for i, acc in pairs(player.getAccounts()) do + if acc.name == type then + return acc.money + end + end + + return 0 + end +end + +---@param src integer +---@param amount number +---@param account "cash" | "bank" | "money" +---@return boolean success +function Framework.Server.PlayerRemoveMoney(src, amount, account) + local player = Framework.Server.GetPlayer(src) + account = account or "bank" + + if Framework.Server.GetPlayerBalance(src, account) < amount then + Framework.Server.Notify(src, Locale.notEnoughMoneyError, "error") + return false + end + + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + player.Functions.RemoveMoney(account, round(amount, 0)) + elseif Config.Framework == "ESX" then + if account == "cash" then account = "money" end + player.removeAccountMoney(account, round(amount, 0)) + end + + return true +end + +---@return {id:number,identifier:string,name:string}[] players +function Framework.Server.GetPlayers() + local players = {} + + for _, playerId in ipairs(GetPlayers()) do + players[#players+1] = { + id = tonumber(playerId), + identifier = Framework.Server.GetPlayerIdentifier(tonumber(playerId, 10)), + name = Framework.Server.GetPlayerInfo(tonumber(playerId, 10))?.name + } + end + + return players +end + +---@return table | false jobs +function Framework.Server.GetJobs() + if Config.Framework == "QBCore" then + return QBCore.Shared.Jobs + elseif Config.Framework == "Qbox" then + return exports.qbx_core:GetJobs() + elseif Config.Framework == "ESX" then + return ESX.GetJobs() + end + + return false +end + +---@return table | false gangs +function Framework.Server.GetGangs() + if (Config.Gangs == "auto" and GetResourceState("rcore_gangs") == "started") or Config.Gangs == "rcore_gangs" then + local gangs = MySQL.query.await("SELECT name FROM gangs") + return gangs or {} + elseif (Config.Gangs == "auto" and GetResourceState("qb-gangs") == "started") or Config.Gangs == "qb-gangs" then + if Config.Framework == "QBCore" then + return QBCore.Shared.Gangs + elseif Config.Framework == "Qbox" then + return exports.qbx_core:GetGangs() + end + elseif Config.Framework == "ESX" then + error("ESX does not natively support gangs."); + end + + return false +end + +---@param vehicle integer +---@return string | false plate +function Framework.Server.GetPlate(vehicle) + local plate = GetVehicleNumberPlateText(vehicle) + if not plate or plate == nil or plate == "" then return false end + + if GetResourceState("brazzers-fakeplates") == "started" then + local originalPlate = MySQL.scalar.await("SELECT plate FROM player_vehicles WHERE fakeplate = ?", {plate}) + if originalPlate then plate = originalPlate end + end + + local trPlate = string.gsub(plate, "^%s*(.-)%s*$", "%1") + return trPlate +end + +---@param vehicle boolean|QueryResult|unknown|{ [number]: { [string]: unknown }|{ [string]: unknown }} +---@return string | number | false model +function Framework.Server.GetModelColumn(vehicle) + if Config.Framework == "QBCore" or Config.Framework == "Qbox" then + return vehicle.vehicle or tonumber(vehicle.hash) or false + elseif Config.Framework == "ESX" then + if not vehicle or not vehicle.vehicle then return false end + + if type(vehicle.vehicle) == "string" then + if not json.decode(vehicle.vehicle) then return false end + return json.decode(vehicle.vehicle).model + else + return vehicle.vehicle.model + end + end + + return false +end + +-- +-- ti_fuel +-- + +RegisterNetEvent("jg-advancedgarages:server:save-ti-fuel-type", function(plate, type) + MySQL.query.await("ALTER TABLE " .. Framework.VehiclesTable .. " ADD COLUMN IF NOT EXISTS `ti_fuel_type` VARCHAR(100) DEFAULT '';") + MySQL.update.await("UPDATE " .. Framework.VehiclesTable .. " SET ti_fuel_type = ? WHERE plate = ?", {type, plate}); +end) + +lib.callback.register("jg-advancedgarages:server:get-ti-fuel-type", function(src, plate) + MySQL.query.await("ALTER TABLE " .. Framework.VehiclesTable .. " ADD COLUMN IF NOT EXISTS `ti_fuel_type` VARCHAR(100) DEFAULT '';") + return MySQL.scalar.await("SELECT ti_fuel_type FROM " .. Framework.VehiclesTable .. " WHERE plate = ?", {plate}) or false +end) + +-- +-- Brazzers-FakePlates +-- + +if GetResourceState("brazzers-fakeplates") == "started" then + lib.callback.register("jg-advancedgarages:server:brazzers-get-plate-from-fakeplate", function(_, fakeplate) + local result = MySQL.scalar.await("SELECT plate FROM player_vehicles WHERE fakeplate = ?", {fakeplate}) + if result then return result end + return false + end) + + lib.callback.register("jg-advancedgarages:server:brazzers-get-fakeplate-from-plate", function(_, plate) + local result = MySQL.scalar.await("SELECT fakeplate FROM player_vehicles WHERE plate = ?", {plate}) + if result then return result end + return false + end) +end \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/fxmanifest.lua b/resources/[carscripts]/jg-advancedgarages/fxmanifest.lua new file mode 100644 index 000000000..2b292bdaf --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/fxmanifest.lua @@ -0,0 +1,56 @@ +fx_version "cerulean" +game "gta5" +lua54 "yes" + +description "For support or other queries: discord.gg/jgscripts" +version 'v3.2.3' +author "JG Scripts" + +dependencies { + "oxmysql", + "ox_lib", + "/server:7290", + "/onesync", +} + +shared_scripts { + "@ox_lib/init.lua", + "config/config.lua", + "locales/*.lua", + "shared/main.lua", + "framework/main.lua" +} + +client_scripts { + "framework/**/cl-*.lua", + "config/config-cl.lua", + "client/cl-main.lua", + "client/*.lua" +} + +server_scripts { + "@oxmysql/lib/MySQL.lua", + "framework/**/sv-*.lua", + "config/config-sv.lua", + "server/sv-main.lua", + "server/*.lua" +} + +ui_page "web/dist/index.html" + +files { + "web/dist/index.html", + "web/dist/**/*", + "vehicle_images/*" +} + +escrow_ignore { + "config/**/*", + "framework/**/*", + "locales/*.lua", + "client/cl-deformation.lua", + "client/cl-locations.lua", + "server/sv-webhooks.lua" +} + +dependency '/assetpacks' \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/install/run-esx.sql b/resources/[carscripts]/jg-advancedgarages/install/run-esx.sql new file mode 100644 index 000000000..cddd0c78c --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/install/run-esx.sql @@ -0,0 +1,28 @@ +-- player_vehicles +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `fuel` INT(10) DEFAULT '100'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `engine` INT(10) DEFAULT '1000'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `body` INT(10) DEFAULT '1000'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `damage` LONGTEXT DEFAULT ''; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `in_garage` TINYINT(1) DEFAULT '1'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `garage_id` VARCHAR(255) DEFAULT 'Legion Square'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `job_vehicle` TINYINT(1) DEFAULT '0'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `job_vehicle_rank` INT(10) DEFAULT '0'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `gang_vehicle` TINYINT(1) DEFAULT '0'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `gang_vehicle_rank` INT(10) DEFAULT '0'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `impound` INT(10) DEFAULT '0'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `impound_retrievable` INT(10) DEFAULT '0'; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `impound_data` LONGTEXT DEFAULT ''; +ALTER TABLE `owned_vehicles` ADD COLUMN IF NOT EXISTS `nickname` VARCHAR(255) DEFAULT ''; + +CREATE TABLE IF NOT EXISTS `player_priv_garages` ( + `id` INT(11) unsigned NOT NULL AUTO_INCREMENT, + `owners` longtext, + `name` VARCHAR(255), + `type` VARCHAR(50), + `x` FLOAT, + `y` FLOAT, + `z` FLOAT, + `h` FLOAT, + `distance` INT(11) DEFAULT '10', + PRIMARY KEY (`id`) +); \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/install/run-qb.sql b/resources/[carscripts]/jg-advancedgarages/install/run-qb.sql new file mode 100644 index 000000000..4252afd0c --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/install/run-qb.sql @@ -0,0 +1,25 @@ +-- player_vehicles +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `damage` LONGTEXT DEFAULT ''; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `in_garage` TINYINT(1) DEFAULT '1'; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `garage_id` VARCHAR(255) DEFAULT 'Legion Square'; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `job_vehicle` TINYINT(1) DEFAULT '0'; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `job_vehicle_rank` INT(10) DEFAULT '0'; -- NEW +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `gang_vehicle` TINYINT(1) DEFAULT '0'; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `gang_vehicle_rank` INT(10) DEFAULT '0'; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `impound` INT(10) DEFAULT '0'; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `impound_retrievable` INT(10) DEFAULT '0'; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `impound_data` LONGTEXT DEFAULT ''; +ALTER TABLE `player_vehicles` ADD COLUMN IF NOT EXISTS `nickname` VARCHAR(255) DEFAULT ''; + +CREATE TABLE IF NOT EXISTS `player_priv_garages` ( + `id` INT(11) unsigned NOT NULL AUTO_INCREMENT, + `owners` longtext, + `name` VARCHAR(255), + `type` VARCHAR(50), + `x` FLOAT, + `y` FLOAT, + `z` FLOAT, + `h` FLOAT, + `distance` INT(11) DEFAULT '10', + PRIMARY KEY (`id`) +); \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/locales/ar.lua b/resources/[carscripts]/jg-advancedgarages/locales/ar.lua new file mode 100644 index 000000000..3418edf16 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/ar.lua @@ -0,0 +1,142 @@ +Locales = Locales or {} + +Locales['ar'] = { + yes = "نعم", + no = "لا", + garage = "كراج", + jobGarage = "كراج الوظيفة", + gangGarage = "كراج العصابة", + player = "لاعب", + impound = "حجز", + inGarage = "في الكراج", + notInGarage = "ليست في الكراج", + car = "سيارة", + air = "جوي", + sea = "بحري", + fuel = "وقود", + engine = "محرك", + body = "هيكل", + day = "يوم", + days = "أيام", + hour = "ساعة", + hours = "ساعات", + mins = "دقائق", + + -- User Interface + noVehicles = "لا توجد مركبات في هذا الكراج", + noVehiclesAvailableToDrive = "لا توجد مركبات متاحة للقيادة", + vehicles = "مركبة/مركبات", + vehiclePlate = "لوحة المركبة", + vehicleNotInGarage = "المركبة تُركت بالخارج", + vehicleTakeOut = "قيادة", + vehicleReturnAndTakeOut = "إرجاع وقيادة", + vehicleReturnToOwnersGarage = "إرجاع إلى كراج المالك", + transferToGarageOrPlayer = "نقل إلى كراج أو لاعب", + transferToGarage = "نقل إلى كراج", + transferToPlayer = "نقل إلى لاعب", + vehicleTransfer = "نقل", + noAvailableGarages = "لا توجد كراجات متاحة", + currentGarage = "الكراج الحالي", + noPlayersOnline = "لا يوجد لاعبين متصلين", + createPrivateGarage = "إنشاء كراج خاص", + pgAlertHeadsUp = "تنبيه!", + pgAlertText = "سيتم إنشاء الكراج وستظهر المركبات في الموقع والاتجاه الذي تقف فيه حاليًا.", + garageName = "اسم الكراج", + impoundInformation = "معلومات الحجز", + impoundedBy = "حجز بواسطة", + impoundedReason = "السبب", + impoundPlayerCanCollect = "يمكنك استلام مركبتك من الحجز.", + impoundCollectionContact = "يرجى الاتصال بـ %{value} لاستلام مركبتك.", + impoundNoVehicles = "لا توجد مركبات في الحجز", + impoundAvailable = "متاح", + impoundRetrievableByOwner = "يمكن استردادها بواسطة المالك", + impoundNoReason = "لم يتم تقديم سبب", + impoundVehicle = "حجز المركبة", + impoundReasonField = "السبب (اختياري)", + impoundTime = "وقت الحجز", + impoundAvailableImmediately = "متاح فورا", + impoundCost = "التكلفة", + changeVehiclePlate = "تغيير لوحة المركبة", + newPlate = "لوحة جديدة", + search = "البحث بالاسم أو اللوحة", + noPrivateGarages = "لا توجد كراجات خاصة", + editPrivateGarage = "تعديل الكراج الخاص", + owners = "المالك/المالكون", + location = "الموقع", + next = "التالي", + previous = "السابق", + page = "صفحة", + of = "من", + show = "عرض", + save = "حفظ", + edit = "تعديل", + delete = "حذف", + garageDeleteConfirm = "هل أنت متأكد أنك تريد حذف هذا الكراج؟", + privGarageSearch = "البحث بالاسم", + garageUpdatedSuccess = "تم تحديث الكراج بنجاح!", + getCurrentCoords = "احصل على الإحداثيات الحالية", + identifier = "المعرف", + name = "الاسم", + noPlayers = "لا يوجد لاعبين مضافين", + addPlayer = "إضافة لاعب", + loadingVehicle = "جارٍ تحميل المركبة...", + vehicleSetup = "إعداد المركبة", + extras = "إضافات", + extra = "إضافة", + liveries = "الطلاءات", + livery = "طلاء", + noLiveries = "لا توجد طلاءات متاحة", + noExtras = "لا توجد إضافات متاحة", + none = "لا شيء", + vehicleNeedsService = "تحتاج إلى صيانة", + type = "النوع", + goInside = "ادخل إلى الداخل", + + -- Notifications + insertVehicleTypeError = "يمكنك تخزين أنواع المركبات %{value} فقط في هذا الكراج", + insertVehiclePublicError = "لا يمكنك تخزين مركبات الوظيفة أو العصابة في الكراجات العامة", + vehicleParkedSuccess = "تم ركن المركبة في الكراج", + vehicleNotOwnedError = "أنت لا تملك هذه المركبة", + vehicleNotOwnedByPlayerError = "المركبة ليست مملوكة للاعب", + notEnoughMoneyError = "ليس لديك ما يكفي من المال في البنك", + vehicleNotYoursError = "المركبة لا تخصك", + notJobOrGangVehicle = "هذه ليست مركبة %{value}", + invalidGangError = "لم تقدم عصابة صالحة", + invalidJobError = "لم تقدم وظيفة صالحة", + notInsideVehicleError = "أنت لست جالسًا في مركبة", + vehicleAddedToGangGarageSuccess = "تمت إضافة المركبة إلى كراج العصابة %{value}!", + vehicleAddedToJobGarageSuccess = "تمت إضافة المركبة إلى كراج الوظيفة %{value}!", + moveCloserToVehicleError = "تحتاج إلى الاقتراب من المركبة", + noVehiclesNearbyError = "لا توجد مركبات قريبة", + commandPermissionsError = "غير مسموح لك باستخدام هذا الأمر", + actionNotAllowedError = "غير مسموح لك بفعل هذا", + garageNameExistsError = "اسم الكراج موجود بالفعل", + vehiclePlateExistsError = "لوحة المركبة مستخدمة بالفعل", + playerNotOnlineError = "اللاعب غير متصل", + vehicleTransferSuccess = "تم نقل المركبة إلى %{value}", + vehicleTransferSuccessGeneral = "تم نقل المركبة بنجاح", + vehicleReceived = "تلقيت مركبة باللوحة %{value}", + vehicleImpoundSuccess = "تم حجز المركبة بنجاح", + vehicleImpoundRemoveSuccess = "تم إزالة المركبة من الحجز", + vehicleImpoundReturnedToOwnerSuccess = "تم إرجاع المركبة إلى كراج المالك", + garageCreatedSuccess = "تم إنشاء الكراج بنجاح!", + vehiclePlateUpdateSuccess = "تم تعيين لوحة المركبة إلى %{value}", + vehicleDeletedSuccess = "تم حذف المركبة من قاعدة البيانات %{value}", + playerIsDead = "لا يمكنك فعل هذا وأنت ميت", + vehicleStoreError = "لا يمكنك تخزين هذه المركبة هنا", + + -- Commands + cmdSetGangVehicle = "إضافة المركبة الحالية إلى كراج العصابة", + cmdRemoveGangVehicle = "إعادة مركبة العصابة إلى ملكية اللاعب", + cmdSetJobVehicle = "إضافة المركبة الحالية إلى كراج الوظيفة", + cmdRemoveJobVehicle = "إعادة مركبة الوظيفة إلى ملكية اللاعب", + cmdArgGangName = "اسم العصابة", + cmdArgJobName = "اسم الوظيفة", + cmgArgMinGangRank = "الرتبة الدنيا للعصابة", + cmgArgMinJobRank = "الرتبة الدنيا للوظيفة", + cmdArgPlayerId = "معرف اللاعب للمالك الجديد", + cmdImpoundVehicle = "حجز مركبة", + cmdChangePlate = "تغيير لوحة المركبة (للمسؤولين فقط)", + cmdDeleteVeh = "حذف المركبة من قاعدة البيانات (للمسؤولين فقط)", + cmdCreatePrivGarage = "إنشاء كراج خاص للاعب", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/cn.lua b/resources/[carscripts]/jg-advancedgarages/locales/cn.lua new file mode 100644 index 000000000..c9f38e589 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/cn.lua @@ -0,0 +1,142 @@ +Locales = Locales or {} + +Locales['cn'] = { + yes = "是", + no = "否", + garage = "车库", + jobGarage = "工作车库", + gangGarage = "帮派车库", + player = "玩家", + impound = "扣押", + inGarage = "在车库中", + notInGarage = "不在车库中", + car = "汽车", + air = "空中", + sea = "海洋", + fuel = "燃油", + engine = "引擎", + body = "车身", + day = "天", + days = "天", + hour = "小时", + hours = "小时", + mins = "分钟", + + -- 用户界面 + noVehicles = "此车库没有车辆", + noVehiclesAvailableToDrive = "没有可供驾驶的车辆", + vehicles = "辆车", + vehiclePlate = "车牌", + vehicleNotInGarage = "车辆已被取出", + vehicleTakeOut = "驾驶", + vehicleReturnAndTakeOut = "归还并驾驶", + vehicleReturnToOwnersGarage = "返回车主的车库", + transferToGarageOrPlayer = "转移到车库或玩家", + transferToGarage = "转移到车库", + transferToPlayer = "转移到玩家", + vehicleTransfer = "车辆转移", + noAvailableGarages = "没有可用车库", + currentGarage = "当前车库", + noPlayersOnline = "当前没有在线玩家", + createPrivateGarage = "创建私人车库", + pgAlertHeadsUp = "提示!", + pgAlertText = "车库将会创建,车辆将会在您当前位置和方向生成。", + garageName = "车库名称", + impoundInformation = "扣押信息", + impoundedBy = "扣押者", + impoundedReason = "原因", + impoundPlayerCanCollect = "您可以从扣押处取回您的车辆。", + impoundCollectionContact = "请联系 %{value} 以便取回您的车辆。", + impoundNoVehicles = "扣押处没有车辆", + impoundAvailable = "可用", + impoundRetrievableByOwner = "车主可取回", + impoundNoReason = "未提供原因", + impoundVehicle = "扣押车辆", + impoundReasonField = "原因(可选)", + impoundTime = "扣押时间", + impoundAvailableImmediately = "可立即取回", + impoundCost = "费用", + changeVehiclePlate = "更改车牌", + newPlate = "新车牌", + search = "按名称或车牌搜索", + noPrivateGarages = "没有私人车库", + editPrivateGarage = "编辑私人车库", + owners = "车主", + location = "位置", + next = "下一页", + previous = "上一页", + page = "页", + of = "共", + show = "显示", + save = "保存", + edit = "编辑", + delete = "删除", + garageDeleteConfirm = "您确定要删除此车库吗?", + privGarageSearch = "按名称搜索", + garageUpdatedSuccess = "车库更新成功!", + getCurrentCoords = "获取当前坐标", + identifier = "标识符", + name = "名称", + noPlayers = "没有添加玩家", + addPlayer = "添加玩家", + loadingVehicle = "正在加载车辆...", + vehicleSetup = "车辆设置", + extras = "额外配件", + extra = "额外配件", + liveries = "涂装", + livery = "涂装", + noLiveries = "没有可用涂装", + noExtras = "没有可用配件", + none = "无", + vehicleNeedsService = "需要维修", + type = "类型", + goInside = "室内车库", + + -- 通知 + insertVehicleTypeError = "此车库只能存储 %{value} 类型的车辆", + insertVehiclePublicError = "您不能将工作或帮派车辆存入公共车库", + vehicleParkedSuccess = "车辆已停入车库", + vehicleNotOwnedError = "您不拥有这辆车", + vehicleNotOwnedByPlayerError = "此车辆不属于玩家", + notEnoughMoneyError = "您的银行余额不足", + vehicleNotYoursError = "这辆车不属于您", + notJobOrGangVehicle = "这不是 %{value} 车辆", + invalidGangError = "您没有提供有效的帮派", + invalidJobError = "您没有提供有效的工作", + notInsideVehicleError = "您没有坐在车辆内", + vehicleAddedToGangGarageSuccess = "车辆已添加到 %{value} 帮派车库!", + vehicleAddedToJobGarageSuccess = "车辆已添加到 %{value} 工作车库!", + moveCloserToVehicleError = "您需要靠近车辆", + noVehiclesNearbyError = "附近没有车辆", + commandPermissionsError = "您没有权限使用此命令", + actionNotAllowedError = "您没有权限执行此操作", + garageNameExistsError = "车库名称已存在", + vehiclePlateExistsError = "车牌已被使用", + playerNotOnlineError = "玩家不在线", + vehicleTransferSuccess = "车辆已转移给 %{value}", + vehicleTransferSuccessGeneral = "车辆转移成功", + vehicleReceived = "您已收到车牌为 %{value} 的车辆", + vehicleImpoundSuccess = "车辆成功扣押", + vehicleImpoundRemoveSuccess = "车辆已从扣押处移除", + vehicleImpoundReturnedToOwnerSuccess = "车辆已归还至车主的车库", + garageCreatedSuccess = "车库创建成功!", + vehiclePlateUpdateSuccess = "车牌已更新为 %{value}", + vehicleDeletedSuccess = "车辆已从数据库删除 %{value}", + playerIsDead = "您死了无法执行此操作", + vehicleStoreError = "您无法将此车辆存储在此处", + + -- 命令 + cmdSetGangVehicle = "将当前车辆添加到帮派车库", + cmdRemoveGangVehicle = "将帮派车辆归还为玩家车辆", + cmdSetJobVehicle = "将当前车辆添加到工作车库", + cmdRemoveJobVehicle = "将工作车辆归还为玩家车辆", + cmdArgGangName = "帮派名称", + cmdArgJobName = "工作名称", + cmgArgMinGangRank = "最低帮派等级", + cmgArgMinJobRank = "最低工作等级", + cmdArgPlayerId = "新车主的玩家ID", + cmdImpoundVehicle = "扣押一辆车辆", + cmdChangePlate = "更改车辆车牌(仅限管理员)", + cmdDeleteVeh = "删除车辆(仅限管理员)", + cmdCreatePrivGarage = "为玩家创建私人车库", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/cs.lua b/resources/[carscripts]/jg-advancedgarages/locales/cs.lua new file mode 100644 index 000000000..b0ba8acc0 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/cs.lua @@ -0,0 +1,143 @@ +Locales = Locales or {} + +Locales['cs'] = { + yes = "Ano", + ne = "Ne", + garage = "Garáž", + jobGarage = "Frakční Garáž", + gangGarage = "Gang Garáž", + player = "Hráč", + impound = "Odtahovka", + inGarage = "V garáži", + notInGarage = "Mimo garáž", + car = "Car", + air = "Air", + sea = "Sea", + fuel = "Palivo", + engine = "Motor", + body = "Karoserie", + day = "den", + days = "dní", + hour = "hodiny", + hours = "hodin", + + -- User Interface + noVehicles = "V této garáži nejsou žádná vozidla", + vehicles = "vozidlo(a)", + vehiclePlate = "SPZ vozidla", + vehicleNotInGarage = "Vozidlo není v garáži", + vehicleTakeOut = "Vytáhnout vozidlo", + vehicleReturnAndTakeOut = "Vyzvednout z odtahovky", + vehicleReturnToOwnersGarage = "Návrat do garáže majitele", + transferToGarageOrPlayer = "Převést do garáže nebo hráči", + transferToGarage = "Převést do garáže", + transferToPlayer = "Převést na hráče", + vehicleTransfer = "Převod", + noAvailableGarages = "Žádné dostupné garáže", + currentGarage = "Aktuální garáž", + noPlayersOnline = "Žádní hráči online", + createPrivateGarage = "Vytvořit soukromou garáž", + pgAlertHeadsUp = "Heads up!", + pgAlertText = "Vytvoří se garáž a vozidla se budou spawnovat přesně v místě a směru, kde právě stojíte.", + garageName = "Název garáže", + impoundInformation = "Informace o zabavení", + impoundedBy = "Zabaveno do", + impoundedReason = "Důvod", + impoundPlayerCanCollect = "Můžete si vyzvednout své vozidlo na odtahovce.", + impoundCollectionContact = "Kontaktujte prosím %{value}, abyste si mohli vyzvednout své vozidlo.", + impoundNoVehicles = "V blízkosti nejsou žádná vozidla", + impoundAvailable = "K dispozici", + impoundRetrievableByOwner = "Vyzvednutelné vlastníkem", + impoundNoReason = "Není uveden důvod", + impoundVehicle = "Zabavené vozidlo", + impoundReasonField = "Důvod (nepovinný)", + impoundTime = "Doba zabavení", + impoundAvailableImmediately = "K dispozici ihned", + impoundCost = "Cena", + changeVehiclePlate = "Vyměnit registrační značku vozidla", + newPlate = "Nová registrační značka", + search = "Hledejte podle jména nebo štítku", + noPrivateGarages = "Žádné soukromé garáže", + editPrivateGarage = "Upravit soukromou garáž", + owners = "Majitel(é)", + location = "Umístění", + next = "Další", + previous = "Předchozí", + page = "Stránka", + of = "z", + show = "Zobrazit", + save = "Uložit", + edit = "Upravit", + delete = "Odstranit", + garageDeleteConfirm = "Opravdu chcete tuto garáž odstranit?", + privGarageSearch = "Vyhledávání podle jména", + garageUpdatedSuccess = "Garáž úspěšně aktualizována!", + getCurrentCoords = "Získání aktuálních souřadnic", + identifier = "Identifikátor", + name = "Název", + noPlayers = "Nebyli přidáni žádní hráči", + addPlayer = "Přidat hráče", + loadingVehicle = "Nakládací vozidlo...", + vehicleSetup = "Nastavení vozidla", + extras = "Doplňky", + extra = "Extra", + liveries = "Liveries", + livery = "Livery", + noLiveries = "Nejsou k dispozici žádné livreje", + noExtras = "Žádné doplňky nejsou k dispozici", + none = "Žádné", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "V této garáži lze uložit pouze %{value} typů vozidel", + insertVehiclePublicError = "Do veřejných garáží nelze ukládat frakční vozidla", + vehicleParkedSuccess = "Vozidlo bylo zaparkováno do garáže", + vehicleNotOwnedError = "Toto vozidlo nevlastníte", + vehicleNotOwnedByPlayerError = "Vozidlo není ve vlastnictví tohoto hráče", + notEnoughMoneyError = "Nemáte v bance dostatek peněz", + vehicleNotYoursError = "Toto vozidlo vám nepatří", + notJobOrGangVehicle = "Toto není vozidlo %{value}", + invalidGangError = "Nezadali jste platný gang", + invalidJobError = "Nezadali jste platnou frakci", + notInsideVehicleError = "Nesedíte ve vozidle", + vehicleAddedToGangGarageSuccess = "Vozidlo bylo přidáno do garáže gangu %{value}!", + vehicleAddedToJobGarageSuccess = "Vozidlo bylo přidáno do garáže frakce %{value}!", + moveCloserToVehicleError = "Musíte se přiblížit k vozidlu", + noVehiclesNearbyError = "V blízkosti nejsou žádná vozidla", + commandPermissionsError = "Nemáte oprávnění na použítí tohoto příkazu", + actionNotAllowedError = "Nejste opravněn(a) provádět tuto akci", + garageNameExistsError = "Název garáže již existuje", + vehiclePlateExistsError = "SPZ vozidla je již použita", + playerNotOnlineError = "Hráč není online", + vehicleTransferSuccess = "Vozidlo převedeno na %{value}", + vehicleTransferSuccessGeneral = "Vozidlo bylo úspěšně převedeno", + vehicleReceived = "Získal jsi vozidlo se %{value}", + vehicleImpoundSuccess = "Vozidlo bylo úspěšně zabaveno", + vehicleImpoundRemoveSuccess = "Vozidlo bylo odstraněno z odtahovky", + vehicleImpoundReturnedToOwnerSuccess = "Vozidlo bylo vráceno do garáže majitele", + garageCreatedSuccess = "Garáž byla úspěšně vytvořena!", + vehiclePlateUpdateSuccess = "SPZ vozidla nastavena na %{value}", + vehicleDeletedSuccess = "Vozidlo bylo odstraněno z databáze %{value}", + playerIsDead = "Nemůžeš to udělat, dokud jsi mrtvý", + + -- Commands + cmdSetGangVehicle = "Přidat aktuální vozidlo do gang garáže", + cmdRemoveGangVehicle = "Nastavit vozidlo gangu zpět do vlastnictví hráče", + cmdSetJobVehicle = "Přidat aktuální vozidlo do garáže pro frakci", + cmdRemoveJobVehicle = "Nastavit frakční vozidlo zpět do vlastnictví hráče", + cmdArgGangName = "Název gangu", + cmdArgJobName = "Název jobu", + cmgArgMinGangRank = "Minimální hodnost gangu", + cmgArgMinJobRank = "Minimální pracovní zařazení", + cmdArgPlayerId = "ID hráče nového vlastníka", + cmdImpoundVehicle = "Zabavit vozidlo", + cmdChangePlate = "Změnit registrační značku vozidla (pouze pro administrátory)", + cmdDeleteVeh = "Odstranit vozidlo z databáze (pouze pro administrátory)", + cmdCreatePrivGarage = "Vytvořit soukromou garáž pro hráče", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/da.lua b/resources/[carscripts]/jg-advancedgarages/locales/da.lua new file mode 100644 index 000000000..77db3eea3 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/da.lua @@ -0,0 +1,143 @@ +Locales = Locales or {} + +Locales['da'] = { + yes = "Ja", + no = "Nej", + garage = "Garage", + jobGarage = "Job Garage", + gangGarage = "Bande Garage", + player = "Spiller", + impound = "Impound", + inGarage = "I garage", + notInGarage = "Ikke i garage", + car = "Bil", + air = "Fly", + sea = "Båd", + fuel = "Brændstof", + engine = "Motor", + body = "Karosseri", + day = "dag", + days = "dage", + hour = "time", + hours = "timer", + + -- User Interface + noVehicles = "Der er ingen køretøjer i denne garage", + vehicles = "køretøj(er)", + vehiclePlate = "Nummerplade", + vehicleNotInGarage = "Køretøj er ikke i denne garage", + vehicleTakeOut = "Tag ud", + vehicleReturnAndTakeOut = "Parker og tag ud", + vehicleReturnToOwnersGarage = "Send tilbage til ejers garage", + transferToGarageOrPlayer = "Overfør til en garage eller en spiller", + transferToGarage = "Overfør til garage", + transferToPlayer = "Overfør til spiller", + vehicleTransfer = "Overfør", + noAvailableGarages = "Ingen tilgængelige garager", + currentGarage = "Nuværende garage", + noPlayersOnline = "Ingen spillere online", + createPrivateGarage = "Opret privat garage", + pgAlertHeadsUp = "Pas på!", + pgAlertText = "The garage will be created and vehicles will spawn in the exact location and direction are you are currently standing.", + garageName = "Garage Navn", + impoundInformation = "Impound Information", + impoundedBy = "Impoundet af", + impoundedReason = "Grund", + impoundPlayerCanCollect = "Du kan hente dit køretøj hos impound.", + impoundCollectionContact = "Kontakt venligst %{value} for at hente dit køretøj.", + impoundNoVehicles = "Der er ingen køretøjer i dette impound", + impoundAvailable = "Tilgængelig", + impoundRetrievableByOwner = "Kan afhentes af ejer", + impoundNoReason = "Ingen grund angivet", + impoundVehicle = "Impound Køretøj", + impoundReasonField = "Grund (valgfri)", + impoundTime = "Impound Tid", + impoundAvailableImmediately = "Tilgængelig øjeblikkeligt", + impoundCost = "Pris", + changeVehiclePlate = "Skift nummerplade", + newPlate = "Ny nummerplade", + search = "Søg efter navn eller nummerplade", + noPrivateGarages = "Ingen private garager", + editPrivateGarage = "Rediger privat garage", + owners = "Ejer(e)", + location = "Placering", + next = "Næste", + previous = "Tidligere", + page = "Side", + of = "af", + show = "Vis", + save = "Gem", + edit = "Rediger", + delete = "Slet", + garageDeleteConfirm = "Er du sikker på, at du vil slette denne garage?", + privGarageSearch = "Søg efter navn", + garageUpdatedSuccess = "Garagen er blevet opdateret!", + getCurrentCoords = "Hent aktuelle koordinater", + identifier = "Identifikator", + name = "Navn", + noPlayers = "Der er ikke tilføjet nogen spillere", + addPlayer = "Tilføj spiller", + loadingVehicle = "Indlæser køretøj...", + vehicleSetup = "Opsætning af køretøj", + extras = "Ekstraudstyr", + extra = "Ekstra", + liveries = "Liveries", + livery = "Livery", + noLiveries = "Ingen liveries tilgængelige", + noExtras = "Ingen ekstraudstyr til rådighed", + none = "Ingen", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "Du kan kun opbevare %{value} i denne garage", + insertVehiclePublicError = "You can't store job or gang vehicles in public garages", + vehicleParkedSuccess = "Vehicle parked in garage", + vehicleNotOwnedError = "You don't own this vehicle", + vehicleNotOwnedByPlayerError = "Vehicle is not owned by a player", + notEnoughMoneyError = "Du har ikke nok penge i din bank", + vehicleNotYoursError = "Køretøj tilhører ikke dig", + notJobOrGangVehicle = "Dette er ikke en %{value}", + invalidGangError = "Du har ikke angivet en gyldig bande", + invalidJobError = "Du har ikke givet et gyldigt job", + notInsideVehicleError = "Du sidder ikke i et køretøj", + vehicleAddedToGangGarageSuccess = "Køretøj tilføjet til %{value} bande garagen!", + vehicleAddedToJobGarageSuccess = "Køretøj tilføjet til %{value} job garagen!", + moveCloserToVehicleError = "Du skal være tættere på køretøjet", + noVehiclesNearbyError = "Der er ingen køretøjer i nærheden", + commandPermissionsError = "Du må ikke bruge denne kommando", + actionNotAllowedError = "Du må ikke gøre dette", + garageNameExistsError = "Garagenavn eksisterer allerede", + vehiclePlateExistsError = "Nummerplade er allerede i brug", + playerNotOnlineError = "Spiller er ikke online", + vehicleTransferSuccess = "Køretøj overført til %{value}", + vehicleTransferSuccessGeneral = "Køretøj blev overført", + vehicleReceived = "Du modtog et køretøj med nummerpladen %{value}", + vehicleImpoundSuccess = "Køretøj blev impounded", + vehicleImpoundRemoveSuccess = "Køretøj blev fjernet fra impound", + vehicleImpoundReturnedToOwnerSuccess = "Køretøjet blev returneret til ejerens garage", + garageCreatedSuccess = "Garage oprettet!", + vehiclePlateUpdateSuccess = "Nummerplade ændret til %{value}", + vehicleDeletedSuccess = "Køretøj blev slettet fra databasen %{value}", + playerIsDead = "Du kan ikke gøre dette, mens du er død", + + -- Commands + cmdSetGangVehicle = "Tilføj dette køretøj til bandegaragen", + cmdRemoveGangVehicle = "Fjern bandekøretøjet og returner det til ejeren", + cmdSetJobVehicle = "Tilføj dette køretøj til jobgaragen", + cmdRemoveJobVehicle = "Fjern jobkøretøjet og returner det til ejeren", + cmdArgGangName = "Bande navn", + cmdArgJobName = "Job navn", + cmgArgMinGangRank = "Minimum bande rang", + cmgArgMinJobRank = "Minimum jobrangering", + cmdArgPlayerId = "Spiller-ID på ejeren", + cmdImpoundVehicle = "Impound et køretøj", + cmdChangePlate = "Skift nummerplade (Kun admin)", + cmdDeleteVeh = "Fjern køretøj fra databasen (Kun admin)", + cmdCreatePrivGarage = "Opret en privat garage til en spiller", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/de.lua b/resources/[carscripts]/jg-advancedgarages/locales/de.lua new file mode 100644 index 000000000..65deeaf95 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/de.lua @@ -0,0 +1,143 @@ +Locales = Locales or {} + +Locales['de'] = { + yes = "Ja", + no = "Nein", + garage = "Garage", + jobGarage = "Jobgarage", + gangGarage = "Ganggarage", + player = "Spieler", + impound = "Impound", + inGarage = "In der Garage", + notInGarage = "Nicht in der Garage", + car = "Auto", + air = "Flugzeug", + sea = "Boot", + fuel = "Tank", + engine = "Motor", + body = "Schaden", + day = "Tag", + days = "Tage", + hour = "Stunde", + hours = "Stunden", + + -- User Interface + noVehicles = "Keine Fahrzeuge in der Garage", + vehicles = "Fahrzeug(e)", + vehiclePlate = "Kennzeichen", + vehicleNotInGarage = "Nicht in der Garage", + vehicleTakeOut = "Ausparken", + vehicleReturnAndTakeOut = "Einparken und Ausparken", + vehicleReturnToOwnersGarage = "Zurück in die Privatgarage", + transferToGarageOrPlayer = "Transfer in eine andere Garage oder an einen Spieler", + transferToGarage = "Transfer in eine andere Garage", + transferToPlayer = "Transfer zu einem Spieler", + vehicleTransfer = "Transfer", + noAvailableGarages = "Keine Verfügbaren Garagen", + currentGarage = "Aktuelle Garage", + noPlayersOnline = "Kein Spieler online", + createPrivateGarage = "Private Garage erstellen", + pgAlertHeadsUp = "Kopf hoch!", + pgAlertText = "Garage wird erstellt und Fahrzeuge spawnen an der Stelle und in die Richtung die du schaust", + garageName = "Garagenname", + impoundInformation = "Impound Information", + impoundedBy = "Beschlagnahmt von", + impoundedReason = "Grund", + impoundPlayerCanCollect = "Fahrzeug kann am Impound ausgelöst werden", + impoundCollectionContact = "Kontaktiere %{value} um dein Fahrzeug auszulösen", + impoundNoVehicles = "Keine Fahrzeuge im Impound", + impoundAvailable = "Verfügbar", + impoundRetrievableByOwner = "Kann vom Eigentümer ausgelöst werden", + impoundNoReason = "Kein Grund angegeben", + impoundVehicle = "Fahrzeug beschlagnahmen", + impoundReasonField = "Grund (optional)", + impoundTime = "Impound Zeit", + impoundAvailableImmediately = "Sofort verfügbar", + impoundCost = "Kosten", + changeVehiclePlate = "Kennzeichen ändern", + newPlate = "Neues Kennzeichen", + search = "Suche nach Name oder Kennzeichen", + noPrivateGarages = "Keine privaten Garagen", + editPrivateGarage = "Private Garage bearbeiten", + owners = "Eigentümer(n)", + location = "Standort", + next = "Weiter", + previous = "Vorherige", + page = "Seite", + of = "von", + show = "Anzeigen", + save = "Speichern Sie", + edit = "Bearbeiten", + delete = "Löschen", + garageDeleteConfirm = "Sind Sie sicher, dass Sie diese Garage löschen wollen?", + privGarageSearch = "Suche nach Name", + garageUpdatedSuccess = "Garage erfolgreich aktualisiert!", + getCurrentCoords = "Aktuelle Koordinaten abrufen", + identifier = "Kennung", + name = "Name", + noPlayers = "Es sind keine Spieler hinzugefügt worden", + addPlayer = "Spieler hinzufügen", + loadingVehicle = "Fahrzeug laden...", + vehicleSetup = "Fahrzeug-Setup", + extras = "Extras", + extra = "Extra", + liveries = "Livreen", + livery = "Leihwagen", + noLiveries = "Keine Lackierungen verfügbar", + noExtras = "Keine Extras verfügbar", + none = "Keine", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "Du kannst hier nur %{value} einparken", + insertVehiclePublicError = "Du kannst keine Jobfahrzeuge in Öffentliche Garagen einparken", + vehicleParkedSuccess = "Erfolgreich eingeparkt", + vehicleNotOwnedError = "Du hast keinen Schlüssel", + vehicleNotOwnedByPlayerError = "Kein registriertes Fahrzeug", + notEnoughMoneyError = "Nicht genug Geld auf dem Konto", + vehicleNotYoursError = "Fahrzeug gehört nicht dir", + notJobOrGangVehicle = "Kein %{value} Fahrzeug", + invalidGangError = "Keine gültige Gang", + invalidJobError = "Kein gültiger Job", + notInsideVehicleError = "Du sitzt nicht in einem Fahrzeug", + vehicleAddedToGangGarageSuccess = "Fahrzeug zur %{value} Ganggarage hinzugefügt", + vehicleAddedToJobGarageSuccess = "Fahrzeug zur %{value} Jobgarage hinzugefügt", + moveCloserToVehicleError = "Du musst näher ans Fahrzeug", + noVehiclesNearbyError = "Kein Fahrzeug in der nähe", + commandPermissionsError = "Keine Berechtigung für diesen Command", + actionNotAllowedError = "Keine Berechtigung", + garageNameExistsError = "Garagenname exestiert bereites", + vehiclePlateExistsError = "Kennzeichen exestiert bereites", + playerNotOnlineError = "Spieler ist offline", + vehicleTransferSuccess = "Fahrzeug an %{value} übertragen", + vehicleTransferSuccessGeneral = "Fahrzeug erfolgreich übertragen", + vehicleReceived = "Fahrzeug mit dem Kennzeichen %{value} erhalten", + vehicleImpoundSuccess = "Fahrzeug erfolgreich beschlagnahmt", + vehicleImpoundRemoveSuccess = "Fahrzeug wurde aus dem Impound ausgelöst", + vehicleImpoundReturnedToOwnerSuccess = "Fahrzeug zurück in der Eigentümergarage", + garageCreatedSuccess = "Garage erfolgreich erstellt", + vehiclePlateUpdateSuccess = "Kennzeichen wurde zu %{value} geändert", + vehicleDeletedSuccess = "Fahrzeug aus der Datenbank %{value} gelöscht", + playerIsDead = "Sie können dies nicht tun, während Sie tot sind", + + -- Commands + cmdSetGangVehicle = "Aktuelles Fahrzeug einer Ganggarage hinzufügen", + cmdRemoveGangVehicle = "Setze das Gang-Fahrzeug wieder in den Besitz des Spielers", + cmdSetJobVehicle = "Aktuelles Fahrzeug einer Jobgarage hinzufügen", + cmdRemoveJobVehicle = "Setze das Job-Fahrzeug wieder in den Besitz des Spielers", + cmdArgGangName = "Gangname", + cmdArgJobName = "Jobname", + cmgArgMinGangRank = "Minimaler Gangrang", + cmgArgMinJobRank = "Mindestjobrang", + cmdArgPlayerId = "Spieler ID vom Eigentümer", + cmdImpoundVehicle = "Fahrzeug beschlagnahmen", + cmdChangePlate = "Kennzeichen ändern (Admin only)", + cmdDeleteVeh = "Fahrzeug aus der Datenbank löschen (Admin only)", + cmdCreatePrivGarage = "Private Garage erstellen", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/en.lua b/resources/[carscripts]/jg-advancedgarages/locales/en.lua new file mode 100644 index 000000000..c4f5f2f0e --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/en.lua @@ -0,0 +1,142 @@ +Locales = Locales or {} + +Locales['en'] = { + yes = "Yes", + no = "No", + garage = "Garage", + jobGarage = "Job Garage", + gangGarage = "Gang Garage", + player = "Player", + impound = "Impound", + inGarage = "In garage", + notInGarage = "Not in garage", + car = "Car", + air = "Air", + sea = "Sea", + fuel = "Fuel", + engine = "Engine", + body = "Body", + day = "day", + days = "days", + hour = "hour", + hours = "hours", + mins = "mins", + + -- User Interface + noVehicles = "There are no vehicles in this garage", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", + vehicles = "vehicle(s)", + vehiclePlate = "Vehicle Plate", + vehicleNotInGarage = "Vehicle has been left out", + vehicleTakeOut = "Drive", + vehicleReturnAndTakeOut = "Return & Drive", + vehicleReturnToOwnersGarage = "Return to Owner's Garage", + transferToGarageOrPlayer = "Transfer to a Garage or Player", + transferToGarage = "Transfer to a Garage", + transferToPlayer = "Transfer to a Player", + vehicleTransfer = "Transfer", + noAvailableGarages = "No available garages", + currentGarage = "Current garage", + noPlayersOnline = "No players online", + createPrivateGarage = "Create Private Garage", + pgAlertHeadsUp = "Heads up!", + pgAlertText = "The garage will be created and vehicles will spawn in the exact location and direction are you are currently standing.", + garageName = "Garage Name", + impoundInformation = "Impound Information", + impoundedBy = "Impounded by", + impoundedReason = "Reason", + impoundPlayerCanCollect = "You can collect your vehicle from the impound.", + impoundCollectionContact = "Please contact %{value} in order to collect your vehicle.", + impoundNoVehicles = "There are no vehicles in the impound", + impoundAvailable = "Available", + impoundRetrievableByOwner = "Retrievable by owner", + impoundNoReason = "No reason provided", + impoundVehicle = "Impound Vehicle", + impoundReasonField = "Reason (optional)", + impoundTime = "Impound Time", + impoundAvailableImmediately = "Available immediately", + impoundCost = "Cost", + changeVehiclePlate = "Change Vehicle Plate", + newPlate = "New Plate", + search = "Search by name or plate", + noPrivateGarages = "No private garages", + editPrivateGarage = "Edit Private Garage", + owners = "Owner(s)", + location = "Location", + next = "Next", + previous = "Previous", + page = "Page", + of = "of", + show = "Show", + save = "Save", + edit = "Edit", + delete = "Delete", + garageDeleteConfirm = "Are you sure you want to delete this garage?", + privGarageSearch = "Search by name", + garageUpdatedSuccess = "Garage successfully updated!", + getCurrentCoords = "Get current coordinates", + identifier = "Identifier", + name = "Name", + noPlayers = "There are no players added", + addPlayer = "Add player", + loadingVehicle = "Loading vehicle...", + vehicleSetup = "Vehicle Setup", + extras = "Extras", + extra = "Extra", + liveries = "Liveries", + livery = "Livery", + noLiveries = "No liveries available", + noExtras = "No extras available", + none = "None", + vehicleNeedsService = "Needs Service", + type = "Type", + goInside = "Go inside", + + -- Notifications + insertVehicleTypeError = "You can only store %{value} vehicle types in this garage", + insertVehiclePublicError = "You can't store job or gang vehicles in public garages", + vehicleParkedSuccess = "Vehicle parked in garage", + vehicleNotOwnedError = "You don't own this vehicle", + vehicleNotOwnedByPlayerError = "Vehicle is not owned by a player", + notEnoughMoneyError = "You don't have enough money in your bank", + vehicleNotYoursError = "Vehicle does not belong to you", + notJobOrGangVehicle = "This is not a %{value} vehicle", + invalidGangError = "You have not provided a valid gang", + invalidJobError = "You have not provided a valid job", + notInsideVehicleError = "You are not sat in a vehicle", + vehicleAddedToGangGarageSuccess = "Vehicle added to the %{value} gang garage!", + vehicleAddedToJobGarageSuccess = "Vehicle added to the %{value} job garage!", + moveCloserToVehicleError = "You need to move closer to the vehicle", + noVehiclesNearbyError = "There are no vehicles nearby", + commandPermissionsError = "You are not allowed to use this command", + actionNotAllowedError = "You are not allowed to do this", + garageNameExistsError = "Garage name already exists", + vehiclePlateExistsError = "Vehicle plate is already in use", + playerNotOnlineError = "Player is not online", + vehicleTransferSuccess = "Vehicle transferred to %{value}", + vehicleTransferSuccessGeneral = "Vehicle successfully transferred", + vehicleReceived = "You recieved a vehicle with the plate %{value}", + vehicleImpoundSuccess = "Vehicle successfully impounded", + vehicleImpoundRemoveSuccess = "Vehicle removed from impound", + vehicleImpoundReturnedToOwnerSuccess = "Vehicle returned to owner's garage", + garageCreatedSuccess = "Garage successfully created!", + vehiclePlateUpdateSuccess = "Vehicle plate set to %{value}", + vehicleDeletedSuccess = "Vehicle deleted from database %{value}", + playerIsDead = "You cannot do this while you are dead", + vehicleStoreError = "You cannot store this vehicle here", + + -- Commands + cmdSetGangVehicle = "Add current vehicle to a gang garage", + cmdRemoveGangVehicle = "Set gang vehicle back to player owned", + cmdSetJobVehicle = "Add current vehicle to a job garage", + cmdRemoveJobVehicle = "Set job vehicle back to player owned", + cmdArgGangName = "Gang name", + cmdArgJobName = "Job name", + cmgArgMinGangRank = "Minimum gang rank", + cmgArgMinJobRank = "Minimum job rank", + cmdArgPlayerId = "Player ID of new owner", + cmdImpoundVehicle = "Impound a vehicle", + cmdChangePlate = "Change vehicle plate (Admin only)", + cmdDeleteVeh = "Delete vehicle from database (Admin only)", + cmdCreatePrivGarage = "Create a private garage for a player", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/es.lua b/resources/[carscripts]/jg-advancedgarages/locales/es.lua new file mode 100644 index 000000000..743f4818d --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/es.lua @@ -0,0 +1,141 @@ +Locales = Locales or {} + +Locales['es'] = { + yes = "Si", + no = "No", + garage = "Garaje", + jobGarage = "Garaje Laboral", + gangGarage = "Garaje de Banda/Pandilla", + player = "Jugador", + impound = "Deposito", + inGarage = "En Garaje", + notInGarage = "No en Garaje", + car = "Coche", + air = "Aereo", + sea = "Maritimo", + fuel = "Combustible", + engine = "Motor", + body = "Carroceria", + day = "dia", + days = "dias", + hour = "hora", + hours = "horas", + + -- User Interface + noVehicles = "No hay vehículos en este garaje.", + vehicles = "Vehículo(s)", + vehiclePlate = "Matrícula del Vehículo", + vehicleNotInGarage = "Vehículo no en garaje", + vehicleTakeOut = "Conducir", + vehicleReturnAndTakeOut = "Devuelve y Conduce", + vehicleReturnToOwnersGarage = "Devolver al garaje del propietario", + transferToGarageOrPlayer = "Transferir a Garaje o Jugador", + transferToGarage = "Transferir a un Garaje", + transferToPlayer = "Transferir a un Jugador", + vehicleTransfer = "Transferir", + noAvailableGarages = "No hay garajes disponibles", + currentGarage = "Garaje Actual", + noPlayersOnline = "No hay jugadores en línea", + createPrivateGarage = "Crear Garaje Privado", + pgAlertHeadsUp = "Advertencia!", + pgAlertText = "Se creará el garaje y los vehículos aparecerán en la ubicación y dirección exactas en las que se encuentra actualmente.", + garageName = "Nombre del Garaje", + impoundInformation = "Información de Incautacion", + impoundedBy = "Incautado por ", + impoundedReason = "Razón", + impoundPlayerCanCollect = "Puedes recoger tu vehículo en el depósito.", + impoundCollectionContact = "Haga el favor de contactar con %{value} para poder reclamar su vehiculo.", + impoundNoVehicles = "No hay vehículos en el depósito.", + impoundAvailable = "Disponible", + impoundRetrievableByOwner = "Recuperable por el propietario", + impoundNoReason = "No se proporcionó ninguna razón", + impoundVehicle = "Incautar Vehiculo", + impoundReasonField = "Razon (opcional)", + impoundTime = "Tiempo de Incautacion", + impoundAvailableImmediately = "Disponible inmediatamente", + impoundCost = "Coste", + changeVehiclePlate = "Cambio de Matricula", + newPlate = "Matricula Nueva", + search = "Buscar por nombre o placa", + noPrivateGarages = "Sin garajes privados", + editPrivateGarage = "Editar Garaje Privado", + owners = "Propietario(s)", + location = "Ubicación", + next = "Siguiente", + previous = "Anterior", + page = "Página", + of = "de", + show = "Mostrar", + save = "Guardar", + edit = "Editar", + delete = "Borrar", + garageDeleteConfirm = "¿Estás seguro de que quieres borrar este garaje?", + privGarageSearch = "Buscar por nombre", + garageUpdatedSuccess = "¡Garaje actualizado con éxito!", + getCurrentCoords = "Obtener coordenadas actuales", + identifier = "Identificador", + name = "Nombre", + noPlayers = "No hay jugadores añadidos", + addPlayer = "Añadir jugador", + loadingVehicle = "Cargando vehículo...", + vehicleSetup = "Configuración del vehículo", + extras = "Extras", + extra = "Extra", + liveries = "Diseños", + livery = "Vinilo", + noLiveries = "No hay vinilos disponibles", + noExtras = "No hay extras disponibles", + none = "Ninguno", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "Solo puedes almacenar vehículos de tipo %{value} en este garaje", + insertVehiclePublicError = "No puede almacenar vehículos de trabajo o de banda en garajes públicos", + vehicleParkedSuccess = "Vehículo estacionado en garaje", + vehicleNotOwnedError = "No eres dueño de este vehículo", + vehicleNotOwnedByPlayerError = "El vehículo no es propiedad de un jugador.", + notEnoughMoneyError = "No tienes suficiente dinero en tu banco", + vehicleNotYoursError = "El vehículo no te pertenece", + notJobOrGangVehicle = "Este no es un vehículo de %{value}", + invalidGangError = "No ha proporcionado una banda válida", + invalidJobError = "No ha proporcionado un trabajo válido", + notInsideVehicleError = "No estás sentado en un vehículo.", + vehicleAddedToGangGarageSuccess = "Vehículo agregado al garaje de banda de %{value}!", + vehicleAddedToJobGarageSuccess = "Vehículo agregado al taller de trabajo de %{value}!", + moveCloserToVehicleError = "Necesitas acercarte al vehículo.", + noVehiclesNearbyError = "No hay vehículos cerca.", + commandPermissionsError = "No tienes permiso para usar este comando.", + actionNotAllowedError = "No tienes permitido hacer esto.", + garageNameExistsError = "El nombre del garaje ya existe", + vehiclePlateExistsError = "La placa del vehículo ya está en uso", + playerNotOnlineError = "El jugador no está en línea", + vehicleTransferSuccess = "Vehículo transferido a %{value}", + vehicleTransferSuccessGeneral = "Vehículo transferido con éxito", + vehicleReceived = "Recibiste un vehículo con matricula %{value}", + vehicleImpoundSuccess = "Vehículo incautado con éxito", + vehicleImpoundRemoveSuccess = "Vehículo retirado del depósito", + vehicleImpoundReturnedToOwnerSuccess = "Vehículo devuelto al garaje del propietario.", + garageCreatedSuccess = "¡Garaje creado con éxito!", + vehiclePlateUpdateSuccess = "Matrícula del vehículo establecida a %{value}", + vehicleDeletedSuccess = "Vehículo eliminado de la base de datos %{value}", + playerIsDead = "No puedes hacer esto mientras estás muerto", + + -- Commands + cmdSetGangVehicle = "Agregar el vehículo actual a un garaje de banda", + cmdRemoveGangVehicle = "Devolver el vehículo de la banda a propiedad del jugador", + cmdSetJobVehicle = "Agregar vehículo actual a un taller de trabajo", + cmdRemoveJobVehicle = "Devolver el vehículo de trabajo a propiedad del jugador", + cmdArgGangName = "Nombre de Banda", + cmdArgJobName = "Nombre de Trabajo", + cmdArgPlayerId = "ID de Jugador del nuevo propietario", + cmdImpoundVehicle = "Incautar un Vehículo", + cmdChangePlate = "Cambiar Matricula del Vehiculo (Solo Administracion)", + cmdDeleteVeh = "Eliminar vehículo de la base de datos (Solo Administracion)", + cmdCreatePrivGarage = "Crea un garaje privado para un jugador.", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/fi.lua b/resources/[carscripts]/jg-advancedgarages/locales/fi.lua new file mode 100644 index 000000000..10418e3ae --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/fi.lua @@ -0,0 +1,143 @@ +Locales = Locales or {} + +Locales['fi'] = { + yes = "Kyllä", + no = "Ei", + garage = "Autotalli", + jobGarage = "Työn Autotalli", + gangGarage = "Jengin Autotalli", + player = "Pelaaja", + impound = "Varikko", + inGarage = "Autotallissa", + notInGarage = "Ulkona tallista", + car = "Maa Ajoneuvo", + air = "Ilma Ajoneuvo", + sea = "Vesi Ajoneuvo", + fuel = "Bensa", + engine = "Moottori", + body = "Keho", + day = "päivä", + days = "päivät", + hour = "tunti", + hours = "tunnit", + + -- User Interface + noVehicles = "Ei ajoneuvoja tallissa", + vehicles = "Ajoneuvot", + vehiclePlate = "Rekisterikilpi", + vehicleNotInGarage = "Ajoneuvo ei ole tallissa", + vehicleTakeOut = "Aja", + vehicleReturnAndTakeOut = "Palauta talliin ja aja", + vehicleReturnToOwnersGarage = "Palauta omistajan talliin", + transferToGarageOrPlayer = "Siirrä autotalliin tai pelaajalle", + transferToGarage = "Siirrä autotalliin", + transferToPlayer = "Siirrä pelaajalle", + vehicleTransfer = "Siirrä", + noAvailableGarages = "Ei vapaita autotalleja", + currentGarage = "Tämän hetkinen talli", + noPlayersOnline = "Ei pelaajia kaupungissa", + createPrivateGarage = "Luo yksityinen autotalli", + pgAlertHeadsUp = "Heads up!", + pgAlertText = "The garage will be created and vehicles will spawn in the exact location and direction are you are currently standing.", + garageName = "Autotallin nimi", + impoundInformation = "Varkki tiedot", + impoundedBy = "Varikoijja", + impoundedReason = "Syy", + impoundPlayerCanCollect = "Voit hakea ajoneuvosi varikolta.", + impoundCollectionContact = "Ota yhteyttä %{value} saadaksesi ajoneuvon takaisin.", + impoundNoVehicles = "Ei ajoneivoja varikolla", + impoundAvailable = "Vapaa", + impoundRetrievableByOwner = "Omistaja voi hakea", + impoundNoReason = "Syytä ei ole annettu", + impoundVehicle = "Takavarikoi ajoneuvo", + impoundReasonField = "Syy", + impoundTime = "Varikoinnin pituus", + impoundAvailableImmediately = "Saatavilla heti", + impoundCost = "Hinta", + changeVehiclePlate = "Vaihda ajoneuvon kilpeä", + newPlate = "Uusi kilpi", + search = "Hae nimellä tai ajoneuvokilven mukaan", + noPrivateGarages = "Ei yksityisiä autotalleja", + editPrivateGarage = "Edit Yksityinen autotalli", + owners = "Omistaja(t)", + location = "Sijainti", + next = "Seuraava", + previous = "Edellinen", + page = "Sivu", + of = "of", + show = "Näytä", + save = "Tallenna", + edit = "Muokkaa", + delete = "Poista", + garageDeleteConfirm = "Haluatko varmasti poistaa tämän autotallin?", + privGarageSearch = "Haku nimen mukaan", + garageUpdatedSuccess = "Autotalli onnistuneesti päivitetty!", + getCurrentCoords = "Hae nykyiset koordinaatit", + identifier = "Tunniste", + name = "Nimi", + noPlayers = "Pelaajia ei ole lisätty", + addPlayer = "Lisää pelaaja", + loadingVehicle = "Ajoneuvon lastaus...", + vehicleSetup = "Ajoneuvon asennus", + extras = "Lisävarusteet", + extra = "Extra", + liveries = "maalaukset", + livery = "maksullisuus", + noLiveries = "Maalauksia ei ole saatavilla", + noExtras = "Ei lisävarusteita saatavilla", + none = "Ei ole", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "Voit ainoastaan tallettaa %{value} ajoneuvo tyyppejä tähän talliin", + insertVehiclePublicError = "Et voi tallettaa työn ajoneuvoja julkisiin talleihin", + vehicleParkedSuccess = "Ajoneuvo parkkeerattu talliin", + vehicleNotOwnedError = "Et omista tätä autoa", + vehicleNotOwnedByPlayerError = "Pelaaja ei omista tätä autoa", + notEnoughMoneyError = "Ei tarpeeksi rahaa pankissa", + vehicleNotYoursError = "Et omista ajoneuvoa", + notJobOrGangVehicle = "Tämä ei ole %{value} ajoneuvo", + invalidGangError = "You have not provided a valid gang", + invalidJobError = "You have not provided a valid job", + notInsideVehicleError = "Et ole ajoneuvossa", + vehicleAddedToGangGarageSuccess = "Vehicle added to the %{value} gang garage!", + vehicleAddedToJobGarageSuccess = "Vehicle added to the %{value} job garage!", + moveCloserToVehicleError = "Mene lähemmäs ajoneuvoa", + noVehiclesNearbyError = "Ei autoja lähellä", + commandPermissionsError = "Et saa käyttää tätä komentoa", + actionNotAllowedError = "Et saa tehdä tätä", + garageNameExistsError = "Tallin nimi on jo olemassa", + vehiclePlateExistsError = "Ajoneuvon kilpi on jo käytössä", + playerNotOnlineError = "Pelaaja ei ole kaupungissa", + vehicleTransferSuccess = "Ajoneuvo on siirretty: %{value}", + vehicleTransferSuccessGeneral = "Ajoneuvo on onnistuneesti siirretty", + vehicleReceived = "Sait ajoneuvon kilvellä %{value}", + vehicleImpoundSuccess = "Ajoneuvo on onnistuneesti Takavarikoitu", + vehicleImpoundRemoveSuccess = "Ajoneuvo on poistettu takavatikolta", + vehicleImpoundReturnedToOwnerSuccess = "Ajoneuvo on palautettu omistajan talliin", + garageCreatedSuccess = "Autotalli onnistuneesti luotu!", + vehiclePlateUpdateSuccess = "Ajoneuvon kilpi on laitettu %{value}", + vehicleDeletedSuccess = "Ajoneuvo on poistettu databasesta %{value}", + playerIsDead = "Et voi tehdä tätä, kun olet kuollut", + + -- Commands + cmdSetGangVehicle = "Add current vehicle to a gang garage", + cmdRemoveGangVehicle = "Set gang vehicle back to player owned", + cmdSetJobVehicle = "Add current vehicle to a job garage", + cmdRemoveJobVehicle = "Set job vehicle back to player owned", + cmdArgGangName = "Gang name", + cmdArgJobName = "Job name", + cmgArgMinGangRank = "Minimum gang rank", + cmgArgMinJobRank = "Minimum job rank", + cmdArgPlayerId = "Player ID of new owner", + cmdImpoundVehicle = "Impound a vehicle", + cmdChangePlate = "Change vehicle plate (Admin only)", + cmdDeleteVeh = "Delete vehicle from database (Admin only)", + cmdCreatePrivGarage = "Create a private garage for a player", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/fr.lua b/resources/[carscripts]/jg-advancedgarages/locales/fr.lua new file mode 100644 index 000000000..ab9e853d3 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/fr.lua @@ -0,0 +1,142 @@ +Locales = Locales or {} + +Locales['fr'] = { + yes = "Oui", + no = "Non", + garage = "Garage", + jobGarage = "Garage métier", + gangGarage = "Garage Gang", + player = "Joueurs", + impound = "Fourriere", + inGarage = "Dans le garage", + notInGarage = "Pas dans le garage", + car = "Voiture", + air = "Air", + sea = "Mer", + fuel = "Essence", + engine = "Moteur", + body = "Carroserie", + day = "Jour", + days = "Jours", + hour = "Heure", + hours = "Heures", + mins = "mins", + + -- User Interface + noVehicles = "Il n'y a aucun véhicule dans ce garage", + noVehiclesAvailableToDrive = "Aucun véhicule n'est disponible pour conduire", + vehicles = "Voiture(s)", + vehiclePlate = "Plaque du véhicule", + vehicleNotInGarage = "Le véhicule a été laissé de côté", + vehicleTakeOut = "Conduire", + vehicleReturnAndTakeOut = "Retour et conduite", + vehicleReturnToOwnersGarage = "Retour au garage du propriétaire", + transferToGarageOrPlayer = "Transfert vers un garage ou un joueur", + transferToGarage = "Transfert vers un garage", + transferToPlayer = "Transférer vers un joueur", + vehicleTransfer = "Transfert", + noAvailableGarages = "Aucun garage disponible", + currentGarage = "Garage actuel", + noPlayersOnline = "Aucun joueur en ligne", + createPrivateGarage = "Créer un garage privé", + pgAlertHeadsUp = "Attention !", + pgAlertText = "Le garage sera créé et les véhicules apparaîtront à l'emplacement et dans la direction exacts où vous vous trouvez actuellement.", + garageName = "Nom du garage", + impoundInformation = "Informations de mise en fourrière", + impoundedBy = "Mise en fourrière par", + impoundedReason = "Raison", + impoundPlayerCanCollect = "Vous pouvez récupérer votre véhicule à la fourrière.", + impoundCollectionContact = "Veuillez contacter %{value} afin de récupérer votre véhicule.", + impoundNoVehicles = "Il n'y a aucun véhicule dans la fourrière", + impoundAvailable = "Disponible", + impoundRetrievableByOwner = "Récupérable par le propriétaire", + impoundNoReason = "Aucune raison fournie", + impoundVehicle = "Véhicule mis en fourrière", + impoundReasonField = "Raison (facultatif)", + impoundTime = "Durée de mise en fourrière", + impoundAvailableImmediately = "Disponible immédiatement", + impoundCost = "Coût", + changeVehiclePlate = "Changer la plaque du véhicule", + newPlate = "Nouvelle plaque", + search = "Recherche par nom ou plaque", + noPrivateGarages = "Pas de garages privés", + editPrivateGarage = "Modifier le garage privé", + owners = "Propriétaire(s)", + location = "Location", + next = "Suivant", + previous = "Precedent", + page = "Page", + of = "de", + show = "Montrer", + save = "Sauvegarde", + edit = "Editer", + delete = "Supprimer", + garageDeleteConfirm = "Etes-vous sûr de vouloir supprimer ce garage ?", + privGarageSearch = "Rechercher par nom", + garageUpdatedSuccess = "Garage mis à jour avec succès !", + getCurrentCoords = "Obtenir les coordonnées actuelles", + identifier = "Identifiant", + name = "Nom", + noPlayers = "Aucun joueur n'a été ajouté", + addPlayer = "Ajouter un joueur", + chargementVehicle = "Chargement du véhicule...", + vehicleSetup = "Configuration du véhicule", + extras = "Suppléments", + extra = "Supplément", + liveries = "Livrées", + livery = "Livrée", + noLiveries = "Aucune livrée disponible", + noExtras = "Aucun extra disponible", + none = "Aucun(e)", + vehicleNeedsService = "Besoin de services", + type = "Genre", + goInside = "Aller à l'intérieur", + + -- Notifications + insertVehicleTypeError = "Vous ne pouvez stocker que %{value} types de véhicules dans ce garage", + insertVehiclePublicError = "Vous ne pouvez pas stocker de véhicules de travail ou de gang dans les garages publics", + vehicleParkedSuccess = "Véhicule garé dans le garage", + vehicleNotOwnedError = "Vous n'êtes pas propriétaire de ce véhicule", + vehicleNotOwnedByPlayerError = "Le véhicule n'appartient à aucun joueur", + notEnoughMoneyError = "Vous n'avez pas assez d'argent en banque", + vehicleNotYoursError = "Le véhicule ne vous appartient pas", + notJobOrGangVehicle = "Ceci n'est pas un véhicule %{value}", + invalidGangError = "Vous n'avez pas fourni de gang valide", + invalidJobError = "Vous n'avez pas fourni d'emploi valide", + notInsideVehicleError = "Vous n'êtes pas assis dans un véhicule", + vehicleAddedToGangGarageSuccess = "Véhicule ajouté au garage du gang %{value} !", + vehicleAddedToJobGarageSuccess = "Véhicule ajouté au garage de travail %{value} !", + moveCloserToVehicleError = "Vous devez vous rapprocher du véhicule", + noVehiclesNearbyError = "Il n'y a aucun véhicule à proximité", + commandPermissionsError = "Vous n'êtes pas autorisé à utiliser cette commande", + actionNotAllowedError = "Vous n'êtes pas autorisé à faire cela", + garageNameExistsError = "Le nom du garage existe déjà", + VehiclePlateExistsError = "La plaque du véhicule est déjà utilisée", + playerNotOnlineError = "Le joueur n'est pas en ligne", + vehicleTransferSuccess = "Véhicule transféré à %{value}", + vehicleTransferSuccessGeneral = "Véhicule transféré avec succès", + vehicleReceived = "Vous avez reçu un véhicule avec la plaque %{value}", + vehicleImpoundSuccess = "Véhicule mis en fourrière avec succès", + vehicleImpoundRemoveSuccess = "Véhicule retiré de la fourrière", + vehicleImpoundReturnedToOwnerSuccess = "Véhicule restitué au garage du propriétaire", + garageCreatedSuccess = "Garage créé avec succès !", + vehiclePlateUpdateSuccess = "Plaque du véhicule réglée sur %{value}", + vehicleDeletedSuccess = "Véhicule supprimé de la base de données %{value}", + playerIsDead = "Vous ne pouvez pas faire ça tant que vous êtes mort", + vehicleStoreError = "Vous ne pouvez pas stocker ce véhicule ici", + + -- Commands + cmdSetGangVehicle = "Ajouter le véhicule actuel à un garage collectif", + cmdRemoveGangVehicle = "Remettre le véhicule du gang comme appartenant au joueur", + cmdSetJobVehicle = "Ajouter le véhicule actuel à un garage", + cmdRemoveJobVehicle = "Remettre le véhicule de travail comme appartenant au joueur", + cmdArgGangName = "Nom du gang", + cmdArgJobName = "Nom du travail", + cmgArgMinGangRank = "Rang minimum du gang", + cmgArgMinJobRank = "Classement minimum du poste", + cmdArgPlayerId = "ID du joueur du nouveau propriétaire", + cmdImpoundVehicle = "Mise en fourrière d'un véhicule", + cmdChangePlate = "Changer la plaque du véhicule (Administrateur uniquement)", + cmdDeleteVeh = "Supprimer le véhicule de la base de données (Administrateur uniquement)", + cmdCreatePrivGarage = "Créer un garage privé pour un joueur", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/hu.lua b/resources/[carscripts]/jg-advancedgarages/locales/hu.lua new file mode 100644 index 000000000..d835d359b --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/hu.lua @@ -0,0 +1,143 @@ +Locales = Locales or {} -- Translated by: PSYCHO#0281 (psycho0281) + +Locales['hu'] = { -- Erre a sorra is figyelj oda!!! Ez nem en.lua, hanem hu.lua, ezt fxmanifest, vagy resource lua-ban is említeni kell :) + yes = "Igen", + no = "Nem", + garage = "Garázs", + jobGarage = "Munka garázs", + gangGarage = "Banda garázs", + player = "Játékos", + impound = "Lefoglalt", + inGarage = "Garázsban", + notInGarage = "Nincs a garázsban", + car = "Autó", + air = "Repülő", + sea = "Hajó", + fuel = "Üzemanyag", + engine = "Motor", + body = "Karosszéria", + day = "nap", + days = "napok", + hour = "óra", + hours = "órák", + + -- User Interface + noVehicles = "Ebben a garázsban nincsenek járművek", + vehicles = "jármű(vek)", + vehiclePlate = "Rendszám", + vehicleNotInGarage = "A jármű nincs garázsban", + vehicleTakeOut = "Vezetés", + vehicleReturnAndTakeOut = "Vissza és vezetés", + vehicleReturnToOwnersGarage = "Visszarakás a tulajdonos garázsába", + transferToGarageOrPlayer = "Átszállítás egy garázsba vagy a játékosnak", + transferToGarage = "Átszállítás garázsba", + transferToPlayer = "Átszállítás játékosnak", + vehicleTransfer = "Átadás", + noAvailableGarages = "Nincs szabad garázs", + currentGarage = "Jelenlegi garázs", + noPlayersOnline = "Nincs ilyen elérhető játékos", + createPrivateGarage = "Privát garázs készítése", + pgAlertHeadsUp = "Fel a fejjel!", + pgAlertText = "A garázs létrejön, és a járművek pontosan azon a helyen és irányban fognak megjelenni, ahol éppen áll.", + garageName = "Garázs neve", + impoundInformation = "Lefoglaltak információ", + impoundedBy = "Lefoglalta", + impoundedReason = "Indok", + impoundPlayerCanCollect = "Gépkocsiját átveheti a lefoglaltakban.", + impoundCollectionContact = "Kérjük, vegye fel a kapcsolatot %{value} a jármű átvétele érdekében.", + impoundNoVehicles = "Nincs lefoglalt autó", + impoundAvailable = "Elérhető", + impoundRetrievableByOwner = "Tulajdonos által átvehető", + impoundNoReason = "Indoklás nélkül", + impoundVehicle = "Lefoglalt jármű", + impoundReasonField = "Indok (nem kötelező)", + impoundTime = "Lefoglalt idő", + impoundAvailableImmediately = "Azonnal elérhető", + impoundCost = "Költség", + changeVehiclePlate = "Rendszámtábla cserélése", + newPlate = "Új rendszám", + search = "Keresés név vagy rendszám alapján", + noPrivateGarages = "Nincs privát garázsod", + editPrivateGarage = "Privát garázs szerkesztése", + owners = "Tulajdonos(ok)", + location = "Elhelyezkedés", + next = "Következő", + previous = "Előző", + page = "Oldal", + of = "nak,-nek", + show = "Mutatás", + save = "Mentés", + edit = "Szerkesztés", + delete = "Törlés", + garageDeleteConfirm = "Biztosan törli ezt a garázst?", + privGarageSearch = "Keresés név alapján", + garageUpdatedSuccess = "Garázs sikeresen frissítve!", + getCurrentCoords = "Jelenlegi koordináták lekérdezése", + identifier = "Azonosító", + name = "Név", + noPlayers = "Nincsenek hozzáadott játékosok", + addPlayer = "Játékos hozzáadása", + loadingVehicle = "Jármű betöltése...", + vehicleSetup = "Járműbeállítás", + extras = "Extrák", + extra = "Extra", + liveries = "Festések", + livery = "Festés", + noLiveries = "Nincs elérhető festés", + noExtras = "Nincsenek extrák", + none = "Semmi", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "Ebben a garázsban csak %{value} járműtípusokat tárolhat", + insertVehiclePublicError = "Nem tárolhat munkahelyi vagy bandajárműveket nyilvános garázsokban", + vehicleParkedSuccess = "Jármű leparkolva", + vehicleNotOwnedError = "Nem Ön a tulajdonosa ennek a járműnek", + vehicleNotOwnedByPlayerError = "A jármű nem játékos tulajdonában van", + notEnoughMoneyError = "Nincs elég pénzed a bankodban", + vehicleNotYoursError = "A jármű nem az Öné", + notJobOrGangVehicle = "Ez nem %{value} jármű", + invalidGangError = "Nem adott meg érvényes bandát", + invalidJobError = "Nem adott meg érvényes állást", + notInsideVehicleError = "Nem ülsz járműben", + vehicleAddedToGangGarageSuccess = "A jármű bekerült a %{value} banda garázsba!", + vehicleAddedToJobGarageSuccess = "A jármű bekerült a %{value} munka garázsba!", + moveCloserToVehicleError = "Közelebb kell mennie a járműhöz", + noVehiclesNearbyError = "A közelben nincsenek járművek", + commandPermissionsError = "Nem használhatja ezt a parancsot", + actionNotAllowedError = "Ehhez nincs engedélye", + garageNameExistsError = "A garázsnév már létezik", + vehiclePlateExistsError = "A jármű táblája már használatban van", + playerNotOnlineError = "Játékos nincs online", + vehicleTransferSuccess = "Jármű átadva neki: %{value}", + vehicleTransferSuccessGeneral = "A jármű sikeresen átadva", + vehicleReceived = "Te kaptál egy járművet, ezzel a rendszámmal %{value}", + vehicleImpoundSuccess = "Sikeresen lefoglalták a járművet", + vehicleImpoundRemoveSuccess = "Sikeresen kilett véve a lefoglaltakból", + vehicleImpoundReturnedToOwnerSuccess = "A jármű visszakerült a tulajdonos garázsába", + garageCreatedSuccess = "Garázs sikeresen létrehozva!", + vehiclePlateUpdateSuccess = "Rendszám beállítva erre: %{value}", + vehicleDeletedSuccess = "Jármű törölve az adatbázisból %{value}", + playerIsDead = "Ezt nem teheted, amíg halott vagy", + + -- Commands + cmdSetGangVehicle = "Jelenlegi jármű hozzáadása a banda garázshoz", + cmdRemoveGangVehicle = "Banda garázsból visszarakás a játékos tulajdonába", + cmdSetJobVehicle = "Jelenlegi jármű hozzáadása a munka garázshoz", + cmdRemoveJobVehicle = "Munka garázsból visszarakás a játékos tulajdonába", + cmdArgGangName = "Banda neve", + cmdArgJobName = "Mubka neve", + cmgArgMinGangRank = "Minimum banda rang", + cmgArgMinJobRank = "Minimum beosztás", + cmdArgPlayerId = "Az új tulajdonos játékosazonosítója", + cmdImpoundVehicle = "Jármű lefoglalása", + cmdChangePlate = "Rendszámtábla cseréje (csak rendszergazda)", + cmdDeleteVeh = "Jármű törlése az adatbázisból (csak rendszergazda)", + cmdCreatePrivGarage = "Privát garázs létrehozása egy játékos számára", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/it.lua b/resources/[carscripts]/jg-advancedgarages/locales/it.lua new file mode 100644 index 000000000..6c69c63f6 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/it.lua @@ -0,0 +1,143 @@ +Locales = Locales or {} + +Locales['it'] = { + yes = "Si", + no = "No", + garage = "Garage", + jobGarage = "Garage Lavoro", + gangGarage = "Garage Gang", + player = "Giocatore", + impound = "Sequestro", + inGarage = "In Garage", + notInGarage = "Fuori dal Garage", + car = "Macchina", + air = "Aereo", + sea = "Barche", + fuel = "Benzina", + engine = "Motore", + body = "Carrozzeria", + day = "Giorno", + days = "Giorni", + hour = "Ora", + hours = "Ore", + + -- User Interface + noVehicles = "Non ci sono veicoli in questo garage", + vehicles = "Veicoli", + vehiclePlate = "Targa Veicolo", + vehicleNotInGarage = "Veicolo non in garage", + vehicleTakeOut = "Prendi il Veicolo", + vehicleReturnAndTakeOut = "Ritorna e prendi il veicolo", + vehicleReturnToOwnersGarage = "Ritorna nel garage del propietario", + transferToGarageOrPlayer = "Trasferisci al garage o al giocatore", + transferToGarage = "Trasferisci al Garage", + transferToPlayer = "Trasferisci al Giocatore", + vehicleTransfer = "Trasferisci", + noAvailableGarages = "Nessun Garage Disponibile", + currentGarage = "Garage Attuale", + noPlayersOnline = "Nessun Giocatore Online", + createPrivateGarage = "Crea Garage Privato", + pgAlertHeadsUp = "Dritta!", + pgAlertText = "Il garage verrà creato e i veicoli appariranno nella posizione e nella direzione esatte in cui ti trovi attualmente.", + garageName = "Nome Garage", + impoundInformation = "Informazioni Sequestro", + impoundedBy = "Sequestrato da", + impoundedReason = "Motivo", + impoundPlayerCanCollect = "Non puoi prelevare il veicolo dal sequestro.", + impoundCollectionContact = "Contatta %{value} per prelevare il tuo veicolo.", + impoundNoVehicles = "Nessun Veicolo Sequestrato", + impoundAvailable = "Disponibile", + impoundRetrievableByOwner = "Ritirabile dal Propietario", + impoundNoReason = "Nessun Motivo Segnalato", + impoundVehicle = "Sequestra Veicolo", + impoundReasonField = "Motivo (Opzionale)", + impoundTime = "Tempo Sequestro", + impoundAvailableImmediately = "Disponibile Ora", + impoundCost = "Costo", + changeVehiclePlate = "Cambia Targa Veicolo", + newPlate = "Nuova Targa", + search = "Ricerca per nome o targa", + noPrivateGarages = "Nessun garage privato", + editPrivateGarage = "Modifica garage privato", + owners = "Proprietario/i", + location = "Posizione", + next = "Successivo", + previous = "Precedente", + page = "Pagina", + of = "di", + show = "Mostra", + save = "Salva", + edit = "Modifica", + delete = "Elimina", + garageDeleteConfirm = "Sei sicuro di voler cancellare questo garage?", + privGarageSearch = "Ricerca per nome", + garageUpdatedSuccess = "Garage aggiornato con successo!", + getCurrentCoords = "Ottenere le coordinate attuali", + identifier = "Identificativo", + name = "Nome", + noPlayers = "Non sono stati aggiunti giocatori", + addPlayer = "Aggiungi giocatore", + loadingVehicle = "Caricamento del veicolo...", + vehicleSetup = "Configurazione del veicolo", + extras = "Extras", + extra = "Extra", + liveries = "Livree", + livery = "Livrea", + noLiveries = "Nessuna livrea disponibile", + noExtras = "Nessun extra disponibile", + none = "Nessuno", + vehicleNeedsService = "Serve Manutenzione", + type = "Tipo", + + -- Notifications + insertVehicleTypeError = "Puoi depositare %{value} tipi di veicoli in questo garage", + insertVehiclePublicError = "Non puoi depositare veicoli gang o lavorativi in garage pubblici", + vehicleParkedSuccess = "Veicolo Parcheggiato", + vehicleNotOwnedError = "Non sei il propietario del veicolo", + vehicleNotOwnedByPlayerError = "Il veicolo non è tuo", + notEnoughMoneyError = "Non hai abbastanza soldi in banca", + vehicleNotYoursError = "Il veicolo non ti appartiene", + notJobOrGangVehicle = "Questo non è un %{value} veicolo", + invalidGangError = "Gang non valida", + invalidJobError = "Lavoro non valido", + notInsideVehicleError = "Non sei in un veicolo", + vehicleAddedToGangGarageSuccess = "Veicolo aggiunto al %{value} garage gang!", + vehicleAddedToJobGarageSuccess = "Veicolo aggiunto al %{value} garage lavorativo!", + moveCloserToVehicleError = "Devi avvicinarti al Veicolo", + noVehiclesNearbyError = "Nessun veicolo vicino", + commandPermissionsError = "Non sei autorizzato ad usare questo comando", + actionNotAllowedError = "Non sei autorizzato a fare questo", + garageNameExistsError = "Nome garage esistente", + vehiclePlateExistsError = "Targa veicolo già esistente", + playerNotOnlineError = "Giocatore Offline", + vehicleTransferSuccess = "Veicolo trasferito a %{value}", + vehicleTransferSuccessGeneral = "Veicolo trasferito correttamente", + vehicleReceived = "Hai ricevuto un veicolo con targa %{value}", + vehicleImpoundSuccess = "Veicolo sequestrato correttamente", + vehicleImpoundRemoveSuccess = "Veicolo rimosso dal sequestro", + vehicleImpoundReturnedToOwnerSuccess = "Veicolo restituito al garage del propietario", + garageCreatedSuccess = "Garage creato correttamente!", + vehiclePlateUpdateSuccess = "Targa cambiata in %{value}", + vehicleDeletedSuccess = "Veicolo eliminato dal database %{value}", + playerIsDead = "Sei morto! Non puoi farlo", + + -- Commands + cmdSetGangVehicle = "Aggiungi veicolo attuale al garage gang", + cmdRemoveGangVehicle = "Ritorna veicolo gang al propietario", + cmdSetJobVehicle = "Aggiungi veicolo attuale al garage lavorativo", + cmdRemoveJobVehicle = "Ritorna veicolo lavorativo al propietario", + cmdArgGangName = "Nome gang", + cmdArgJobName = "Nome lavoro", + cmgArgMinGangRank = "Grado minimo gang", + cmgArgMinJobRank = "Grado minimo lavoro", + cmdArgPlayerId = "ID giocatore del destinatario", + cmdImpoundVehicle = "Sequestra veicolo", + cmdChangePlate = "Cambia targa veicolo (Solo Admin)", + cmdDeleteVeh = "Cancella veicolo dal database (Solo Admin)", + cmdCreatePrivGarage = "Crea un garage privato per il giocatore", + + -- v3 + vehicleStoreError = "Non puoi depositare il tuo veicolo qui", + mins = "minuti", + noVehiclesAvailableToDrive = "Non ci sono veicoli disponibili da guidare", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/ja.lua b/resources/[carscripts]/jg-advancedgarages/locales/ja.lua new file mode 100644 index 000000000..831aa4e27 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/ja.lua @@ -0,0 +1,142 @@ +Locales = Locales or {} + +Locales['ja'] = { + yes = "はい", + no = "いいえ", + garage = "ガレージ", + jobGarage = "仕事用ガレージ", + gangGarage = "ギャング用ガレージ", + player = "プレイヤー", + impound = "押収", + inGarage = "ガレージ内", + notInGarage = "ガレージ外", + car = "車", + air = "空", + sea = "海", + fuel = "燃料", + engine = "エンジン", + body = "ボディ", + day = "日", + days = "日々", + hour = "時間", + hours = "時間", + mins = "分", + + -- ユーザーインターフェース + noVehicles = "このガレージには車両がありません", + noVehiclesAvailableToDrive = "運転可能な車両はありません", + vehicles = "車両", + vehiclePlate = "ナンバープレート", + vehicleNotInGarage = "車両はガレージに入っていません", + vehicleTakeOut = "運転する", + vehicleReturnAndTakeOut = "返却 & 運転", + vehicleReturnToOwnersGarage = "オーナーのガレージに返却", + transferToGarageOrPlayer = "ガレージまたはプレイヤーに転送", + transferToGarage = "ガレージに転送", + transferToPlayer = "プレイヤーに転送", + vehicleTransfer = "転送", + noAvailableGarages = "利用可能なガレージはありません", + currentGarage = "現在のガレージ", + noPlayersOnline = "オンラインのプレイヤーがありません", + createPrivateGarage = "プライベートガレージを作成", + pgAlertHeadsUp = "注意!", + pgAlertText = "ガレージは作成され、車両は現在立っている位置と方向に出現します。", + garageName = "ガレージ名", + impoundInformation = "押収情報", + impoundedBy = "押収者", + impoundedReason = "理由", + impoundPlayerCanCollect = "車両を押収所から受け取ることができます。", + impoundCollectionContact = "%{value} に連絡して車両を受け取ってください。", + impoundNoVehicles = "押収所には車両がありません", + impoundAvailable = "利用可能", + impoundRetrievableByOwner = "オーナーが回収可能", + impoundNoReason = "理由なし", + impoundVehicle = "車両を押収", + impoundReasonField = "理由(任意)", + impoundTime = "押収時間", + impoundAvailableImmediately = "すぐに利用可能", + impoundCost = "費用", + changeVehiclePlate = "車両ナンバープレートの変更", + newPlate = "新しいナンバープレート", + search = "名前またはナンバープレートで検索", + noPrivateGarages = "プライベートガレージはありません", + editPrivateGarage = "プライベートガレージを編集", + owners = "オーナー", + location = "場所", + next = "次", + previous = "前", + page = "ページ", + of = "の", + show = "表示", + save = "保存", + edit = "編集", + delete = "削除", + garageDeleteConfirm = "本当にこのガレージを削除してもよろしいですか?", + privGarageSearch = "名前で検索", + garageUpdatedSuccess = "ガレージが正常に更新されました!", + getCurrentCoords = "現在の座標を取得", + identifier = "識別子", + name = "名前", + noPlayers = "プレイヤーが追加されていません", + addPlayer = "プレイヤーを追加", + loadingVehicle = "車両を読み込み中...", + vehicleSetup = "車両設定", + extras = "エクストラ", + extra = "エクストラ", + liveries = "ラッピング", + livery = "ラッピング", + noLiveries = "利用可能なラッピングはありません", + noExtras = "利用可能なエクストラはありません", + none = "なし", + vehicleNeedsService = "整備が必要", + type = "タイプ", + goInside = "中に入る", + + -- 通知 + insertVehicleTypeError = "このガレージには %{value} の車両タイプのみ収納できます", + insertVehiclePublicError = "公共ガレージには仕事用またはギャング車両を収納できません", + vehicleParkedSuccess = "車両がガレージに駐車されました", + vehicleNotOwnedError = "この車両はあなたのものではありません", + vehicleNotOwnedByPlayerError = "この車両はプレイヤーが所有していません", + notEnoughMoneyError = "銀行に十分なお金がありません", + vehicleNotYoursError = "この車両はあなたのものではありません", + notJobOrGangVehicle = "これは %{value} 車両ではありません", + invalidGangError = "有効なギャング名が提供されていません", + invalidJobError = "有効な仕事名が提供されていません", + notInsideVehicleError = "車両に乗っていません", + vehicleAddedToGangGarageSuccess = "車両が %{value} ギャングガレージに追加されました!", + vehicleAddedToJobGarageSuccess = "車両が %{value} 仕事用ガレージに追加されました!", + moveCloserToVehicleError = "車両に近づく必要があります", + noVehiclesNearbyError = "近くに車両がありません", + commandPermissionsError = "このコマンドを使用する権限がありません", + actionNotAllowedError = "この行動は許可されていません", + garageNameExistsError = "ガレージ名はすでに存在します", + vehiclePlateExistsError = "この車両のナンバープレートはすでに使用されています", + playerNotOnlineError = "プレイヤーはオンラインではありません", + vehicleTransferSuccess = "車両が %{value} に転送されました", + vehicleTransferSuccessGeneral = "車両が正常に転送されました", + vehicleReceived = "車両 %{value} のナンバープレートを受け取りました", + vehicleImpoundSuccess = "車両が正常に押収されました", + vehicleImpoundRemoveSuccess = "車両が押収所から削除されました", + vehicleImpoundReturnedToOwnerSuccess = "車両がオーナーのガレージに返却されました", + garageCreatedSuccess = "ガレージが正常に作成されました!", + vehiclePlateUpdateSuccess = "車両ナンバープレートが %{value} に設定されました", + vehicleDeletedSuccess = "車両がデータベースから削除されました %{value}", + playerIsDead = "死んでいるため、この操作はできません", + vehicleStoreError = "この車両はここに保管できません", + + -- コマンド + cmdSetGangVehicle = "現在の車両をギャングガレージに追加", + cmdRemoveGangVehicle = "ギャング車両をプレイヤー所有に戻す", + cmdSetJobVehicle = "現在の車両を仕事用ガレージに追加", + cmdRemoveJobVehicle = "仕事車両をプレイヤー所有に戻す", + cmdArgGangName = "ギャング名", + cmdArgJobName = "仕事名", + cmgArgMinGangRank = "最低ギャングランク", + cmgArgMinJobRank = "最低仕事ランク", + cmdArgPlayerId = "新しいオーナーのプレイヤーID", + cmdImpoundVehicle = "車両を押収", + cmdChangePlate = "車両ナンバープレートを変更(管理者のみ)", + cmdDeleteVeh = "車両をデータベースから削除(管理者のみ)", + cmdCreatePrivGarage = "プレイヤー用のプライベートガレージを作成", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/lt.lua b/resources/[carscripts]/jg-advancedgarages/locales/lt.lua new file mode 100644 index 000000000..72a15f214 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/lt.lua @@ -0,0 +1,142 @@ +Locales = Locales or {} + +Locales['lt'] = { + yes = "Taip", + no = "Ne", + garage = "Garažas", + jobGarage = "Darbo garažas", + gangGarage = "Gaujos garažas", + player = "Asmuo", + impound = "Konfiskavimo aikštelė", + inGarage = "Šiuo metu garaže", + notInGarage = "Garaže nėra", + car = "Transporto priemonė", + air = "Lėktuvas", + sea = "Laivas", + fuel = "Degalai", + engine = "Variklis", + body = "Kėbulas", + day = "diena", + days = "dienos", + hour = "valanda", + hours = "valandos", + mins = "mins", + + -- User Interface + noVehicles = "Šiame garaže nėra transporto priemonių", + noVehiclesAvailableToDrive = "Šiuo metu nėra transporto priemonių, kurias galėtumėte vairuoti", + vehicles = "tr.priemonė-(s)", + vehiclePlate = "Numeriai", + vehicleNotInGarage = "Tr.priemonės nėra garaže", + vehicleTakeOut = "Vairuoti", + vehicleReturnAndTakeOut = "Gražinti & Vairuoti", + vehicleReturnToOwnersGarage = "Grąžinti savininkui į garažą", + transferToGarageOrPlayer = "Perkelti į garažą arba asmeniui", + transferToGarage = "Perkelti į garažą", + transferToPlayer = "Perleisti žaidėjui", + vehicleTransfer = "Perkelti", + noAvailableGarages = "Nėra galimų garažų", + currentGarage = "Dabartinis garažas", + noPlayersOnline = "Nėra prisijungusių žaidėjų", + createPrivateGarage = "Sukurti privatų garažą", + pgAlertHeadsUp = "Dėmesio!", + pgAlertText = "Garažas bus sukurtas, o transporto priemonė atsiras tiklsiai ten, kur dabar stovite.", + garageName = "Garažo pavadinimas", + impoundInformation = "Konfiskavimo informacija", + impoundedBy = "Konfiskavo", + impoundedReason = "Priežastis", + impoundPlayerCanCollect = "Savo transporto priemonę galite atsiimti iš konfiskavimo aikštelės.", + impoundCollectionContact = "Prašome susisiekti su %{value}, kad galėtumėte atsiimti savo transporto priemonę.", + impoundNoVehicles = "Konfiskavimo aikštelėje nėra transporto priemonių", + impoundAvailable = "Galima", + impoundRetrievableByOwner = "Atsiimti gali savininkas?", + impoundNoReason = "Priežastis nenurodyta", + impoundVehicle = "Transporto priemonės konfiskavimas", + impoundReasonField = "Priežastis (nebūtina)", + impoundTime = "Konfiskavimo laikas", + impoundAvailableImmediately = "Atsiimti gali iškart", + impoundCost = "Atsiėmimo kaina", + changeVehiclePlate = "Numerių keitimas", + newPlate = "Nauji numeriai", + search = "Ieškoti pagal pavadinimą arba numerius", + noPrivateGarages = "Privačių garažų nėra", + editPrivateGarage = "Redaguoti privatų garažą", + owners = "Savininkas(-ai)", + location = "Vietovė", + next = "Kitas", + previous = "Praeitas", + page = "Puslapis", + of = "iš", + show = "Rodyti", + save = "Išsaugoti", + edit = "Redaguoti", + delete = "Ištrinti", + garageDeleteConfirm = "Ar tikrai norite ištrinti garažą?", + privGarageSearch = "Ieškoti pagal pavadinima", + garageUpdatedSuccess = "Garažas sėkmingai atnaujintas!", + getCurrentCoords = "Išgauti koordinates", + identifier = "Identifikatorius", + name = "Vardas", + noPlayers = "Žaidėjų nėra pridėta", + addPlayer = "Pridėti žaidėją", + loadingVehicle = "Užkraunama...", + vehicleSetup = "Papildiniai", + extras = "Extra", + extra = "Extra", + liveries = "Lipdukai", + livery = "Lipdukas", + noLiveries = "Lipdukų nėra", + noExtras = "Extra papildinių nėra", + none = "Nėra", + vehicleNeedsService = "Reikia serviso", + type = "Tipas", + goInside = "Eiti į vidų", + + -- Notifications + insertVehicleTypeError = "Šiame garaže galite laikyti tik %{value} transporto priemonių tipus", + insertVehiclePublicError = "Negalite pastatyti darbo arba gaujų transporto priemonių tarp viešojo garažo", + vehicleParkedSuccess = "Transporto priemonė pastatyta į garažą", + vehicleNotOwnedError = "Ši transporto priemonė nepriklauso jums", + vehicleNotOwnedByPlayerError = "Transporto priemonė nepriklauso jokiam asmeniui", + notEnoughMoneyError = "Neturite pakankamai pinigų banke", + vehicleNotYoursError = "Transporto priemonė jums nepriklauso", + notJobOrGangVehicle = "Tai nėra %{value} transporto priemonė", + invalidGangError = "Jūs nenurodėte tinkamos gaujos", + invalidJobError = "Jūs nenurodėte tinkamo darbo", + notInsideVehicleError = "Jūs nesate transporto priemonėje", + vehicleAddedToGangGarageSuccess = "Transporto priemonė pridėta į %{value} gaujos garažą!", + vehicleAddedToJobGarageSuccess = "Transporto priemonė pridėta į %{value} darbo garažą!", + moveCloserToVehicleError = "Turite prieiti arčiau transporto priemonės", + noVehiclesNearbyError = "Šalia transporto priemonės nėra", + commandPermissionsError = "Neturite leidimo naudoti šios komandos", + actionNotAllowedError = "Šio veiksmo atlikti negalite", + garageNameExistsError = "Garažo pavadinimas jau yra užimtas", + vehiclePlateExistsError = "Transporto priemonės numeriai jau yra užimti", + playerNotOnlineError = "Žaidėjas nėra prisijungęs", + vehicleTransferSuccess = "Transporto priemonė perkelta į %{value}", + vehicleTransferSuccessGeneral = "Transporto priemonė sėkmingai perleista", + vehicleReceived = "Jūs gavote transporto priemonę kurios numeriai yra %{value}", + vehicleImpoundSuccess = "Transporto priemonė sėkmingai konfiskuota", + vehicleImpoundRemoveSuccess = "Transporto priemonė buvo ištraukta iš konfiskavimo aikštelės", + vehicleImpoundReturnedToOwnerSuccess = "Transporto priemonė grąžinta savininkui į garažą", + garageCreatedSuccess = "Garažas sėkmingai sukurtas!", + vehiclePlateUpdateSuccess = "Transporto priemonės numeriai pakeisti į %{value}", + vehicleDeletedSuccess = "Transporto priemonė sėkmingai pašalinta iš duomenu bazės %{value}", + playerIsDead = "Šio veiksmo negalite atlikti kol esate negyvas", + vehicleStoreError = "Šios transporto priemonės laikyti čia negalite", + + -- Commands + cmdSetGangVehicle = "Pridėti dabartinę transporto priemonę į gaujos garažą", + cmdRemoveGangVehicle = "Grąžinti gaujos transporto priemonę savininkui", + cmdSetJobVehicle = "Pridėti dabartine transporto priemonę į darbo garažą", + cmdRemoveJobVehicle = "Gražinti darbinę transporto priemonę savininkui", + cmdArgGangName = "Gaujos pavadinimas", + cmdArgJobName = "Darbo pavadinimas", + cmgArgMinGangRank = "Minimalus gaujos rangas", + cmgArgMinJobRank = "Minimalus darbo rangas", + cmdArgPlayerId = "Naujo savininko ID", + cmdImpoundVehicle = "Konfiskuoti transporto priemonę", + cmdChangePlate = "Keisit transporto priemonės numerius (Tik administracija)", + cmdDeleteVeh = "Ištrinti transporto priemonę iš duomenų bazės (Tik administracija)", + cmdCreatePrivGarage = "Sukurti privatų garažą", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/nl.lua b/resources/[carscripts]/jg-advancedgarages/locales/nl.lua new file mode 100644 index 000000000..6444cfa1d --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/nl.lua @@ -0,0 +1,143 @@ +Locales = Locales or {} + +Locales['nl'] = { + yes = "Ja", + no = "Nee", + garage = "Garage", + jobGarage = "Baan Garage", + gangGarage = "Bende Garage", + player = "Speler", + impound = "Inbeslagname", + inGarage = "In garage", + notInGarage = "Niet in garage", + car = "Auto", + air = "Lucht", + sea = "Zee", + fuel = "Brandstof", + engine = "Motor", + body = "Carrosserie", + day = "dag", + days = "dagen", + hour = "uur", + hours = "uren", + + -- User Interface + noVehicles = "Er zijn geen voertuigen beschikbaar in deze garage", + vehicles = "voertuigen", + vehiclePlate = "Kenteken", + vehicleNotInGarage = "Voertuig is niet in aanwezig in de garage", + vehicleTakeOut = "Uitnemen", + vehicleReturnAndTakeOut = "Retour & Afhaal", + vehicleReturnToOwnersGarage = "Terug brengen naar de Garage van de Eigenaar", + transferToGarageOrPlayer = "Overdracht naar een Garage of Speler", + transferToGarage = "Overdracht naar een Garage", + transferToPlayer = "Overdracht naar een Speler", + vehicleTransfer = "Overdracht", + noAvailableGarages = "Geen beschikbare garages", + currentGarage = "Huidige garage", + noPlayersOnline = "Geen spelers online", + createPrivateGarage = "Privégarage creëren", + pgAlertHeadsUp = "Let op!", + pgAlertText = "De garage wordt gemaakt en voertuigen spawnen in de exacte locatie en richting waarin u zich momenteel bevindt.", + garageName = "Garage Naam", + impoundInformation = "Inbeslagname Informatie", + impoundedBy = "In beslag genomen door", + impoundedReason = "Reden", + impoundPlayerCanCollect = "U kunt uw voertuig ophalen bij de inbeslagname.", + impoundCollectionContact = "Neem contact op met %{value} om uw voertuig op te halen.", + impoundNoVehicles = "Er zijn geen voertuigen in de inbeslagneming", + impoundAvailable = "Beschikbaar", + impoundRetrievableByOwner = "Ophaalbaar door de eigenaar", + impoundNoReason = "Geen reden opgegeven", + impoundVehicle = "Voertuig in beslag nemen", + impoundReasonField = "Reden (optioneel)", + impoundTime = "Inbeslagnemingstijd", + impoundAvailableImmediately = "Onmiddellijk beschikbaar", + impoundCost = "Kosten", + changeVehiclePlate = "Voertuigkenteken wijzigen", + newPlate = "Nieuw Kenteken", + search = "Zoek op naam of plaat", + noPrivateGarages = "Geen privégarages", + editPrivateGarage = "Bewerk privégarage", + owners = "Eigenaar(s)", + location = "Locatie", + next = "Volgende", + previous = "Vorige", + page = "Pagina", + of = "van", + show = "Toon", + save = "Opslaan", + edit = "Bewerk", + delete = "Verwijder", + garageDeleteConfirm = "Weet je zeker dat je deze garage wilt verwijderen?", + privGarageSearch = "Zoeken op naam", + garageUpdatedSuccess = "Garage succesvol bijgewerkt!", + getCurrentCoords = "Huidige coördinaten ophalen", + identifier = "Identificatie", + name = "Naam", + noPlayers = "Er zijn geen spelers toegevoegd", + addPlayer = "Speler toevoegen", + loadingVehicle = "Voertuig laden...", + vehicleSetup = "Voertuig instellen", + extras = "Extra's", + extra = "Extra", + liveries = "Liveries", + livery = "Livery", + noLiveries = "Geen liveries beschikbaar", + noExtras = "Geen extra's beschikbaar", + none = "Geen", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "U kunt alleen opslaan %{value} voertuigtypes in deze garage", + insertVehiclePublicError = "Je kunt geen baan- of bendevoertuigen opslaan in openbare garages", + vehicleParkedSuccess = "Voertuig geparkeerd in garage", + vehicleNotOwnedError = "U bent niet de eigenaar van dit voertuig", + vehicleNotOwnedByPlayerError = "Dit voertuig is geen eigendom van een speler", + notEnoughMoneyError = "U heeft niet genoeg geld op uw bank", + vehicleNotYoursError = "Dit voertuig is niet van jou", + notJobOrGangVehicle = "Dit is geen %{value} voertuig", + invalidGangError = "Je heeft geen geldige bende opgegeven", + invalidJobError = "Je heeft geen geldige baan opgegeven", + notInsideVehicleError = "Je zit niet in een voertuig", + vehicleAddedToGangGarageSuccess = "Voertuig toegevoegd aan de %{value} bende garage!", + vehicleAddedToJobGarageSuccess = "Voertuig toegevoegd aan de %{value} baan garage!", + moveCloserToVehicleError = "Je moet dichter bij het voertuig gaan staan", + noVehiclesNearbyError = "Er zijn geen voertuigen in de buurt", + commandPermissionsError = "Je hebt de rechten niet om dit commando te gebruiken", + actionNotAllowedError = "Dit mag je niet doen", + garageNameExistsError = "Garagenaam is al in gebruik", + vehiclePlateExistsError = "Voertuigkenteken is al in gebruik", + playerNotOnlineError = "Speler is niet online", + vehicleTransferSuccess = "Voertuig overgedragen aan %{value}", + vehicleTransferSuccessGeneral = "Voertuig succesvol overgedragen", + vehicleReceived = "U heeft een voertuig met kenteken %{value} ontvangen", + vehicleImpoundSuccess = "Voertuig succesvol in beslag genomen", + vehicleImpoundRemoveSuccess = "Voertuig uit beslag genomen", + vehicleImpoundReturnedToOwnerSuccess = "Voertuig teruggebracht naar de garage van de eigenaar", + garageCreatedSuccess = "Garage succesvol aangemaakt!", + vehiclePlateUpdateSuccess = "Voertuigkenteken ingesteld op %{value}", + vehicleDeletedSuccess = "Voertuig verwijderd uit de database %{value}", + playerIsDead = "Je kunt dit niet doen als je dood bent", + + -- Commands + cmdSetGangVehicle = "Huidig voertuig toevoegen aan een bendegarage", + cmdRemoveGangVehicle = "Stel bendevoertuig terug in als eigendom van de speler", + cmdSetJobVehicle = "Huidig voertuig toevoegen aan een baangarage", + cmdRemoveJobVehicle = "Stel baanvoertuig terug in als eigendom van de speler", + cmdArgGangName = "Bende naam", + cmdArgJobName = "Baan naam", + cmgArgMinGangRank = "Minimale benderang", + cmgArgMinJobRank = "Minimale functierang", + cmdArgPlayerId = "Speler-ID van nieuwe eigenaar", + cmdImpoundVehicle = "Een voertuig in beslag nemen", + cmdChangePlate = "Wijzig kentekenplaat (Alleen beheerder)", + cmdDeleteVeh = "Voertuig verwijderen uit de database (Alleen beheerder)", + cmdCreatePrivGarage = "Privégarage creëren voor een Speler", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/pt.lua b/resources/[carscripts]/jg-advancedgarages/locales/pt.lua new file mode 100644 index 000000000..d7fdacca6 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/pt.lua @@ -0,0 +1,141 @@ +Locales = Locales or {} + +Locales['pt'] = { + yes = "Sim", + no = "Não", + garage = "Garagem", + jobGarage = "Garagem de Trabalho", + gangGarage = "Garagem de Organização", + player = "Jogador", + impound = "Apreendidos", + inGarage = "Na Garagem", + notInGarage = "Fora da Garagem", + car = "Garagem", + air = "Garagem", + sea = "Garagem", + fuel = "Combustível", + engine = "Motor", + body = "Chassi", + day = "Dia", + days = "Dias", + hour = "Hora", + hours = "Horas", + + -- User Interface + noVehicles = "Não há veículos nesta garagem", + vehicles = "Total de Viaturas", + vehiclePlate = "Matrícula do veículo", + vehicleNotInGarage = "Veículo não está na garagem", + vehicleTakeOut = "Retirar", + vehicleReturnAndTakeOut = "Voltar a Retirar", + vehicleReturnToOwnersGarage = "Voltar à garagem do proprietário", + transferToGarageOrPlayer = "Transferir para uma Garagem ou Jogador", + transferToGarage = "Transferir para uma Garagem", + transferToPlayer = "Transferir para um Jogador", + vehicleTransfer = "Transferir", + noAvailableGarages = "Sem garagens disponíveis", + currentGarage = "Garagem atual", + noPlayersOnline = "Sem jogadores online", + createPrivateGarage = "Criar Garagem Privada", + pgAlertHeadsUp = "Atenção!", + pgAlertText = "A garagem será criada e os veículos aparecerão na localização e direção exatas que você está atualmente.", + garageName = "Nome da Garagem", + impoundInformation = "Informações da Apreensão", + impoundedBy = "Apreendido por", + impoundedReason = "Razão", + impoundPlayerCanCollect = "Você pode retirar o seu veículo dos Apreendidos.", + impoundCollectionContact = "Por favor entre em contato %{value} Para retirar o seu veículo.", + impoundNoVehicles = "Não há veículos nos Apreendidos", + impoundAvailable = "Disponível", + impoundRetrievableByOwner = "Recuperável pelo proprietário", + impoundNoReason = "Nenhuma razão fornecida", + impoundVehicle = "Apreender o Veículo", + impoundReasonField = "Razão", + impoundTime = "Tempo de Apreensão", + impoundAvailableImmediately = "Disponível imediatamente", + impoundCost = "Preço", + changeVehiclePlate = "Mudar a Matrícula", + newPlate = "Nova Matrícula", + search = "Pesquise por nome ou placa", + noPrivateGarages = "Sem garagens privadas", + editPrivateGarage = "Editar garagem privada", + owners = "Proprietário(s)", + location = "Localização", + next = "Seguinte", + previous = "Anterior", + page = "Página", + of = "de", + show = "Mostrar", + save = "Guardar", + edit = "Editar", + delete = "Eliminar", + garageDeleteConfirm = "Tem a certeza de que pretende apagar esta garagem?", + privGarageSearch = "Procurar por nome", + garageUpdatedSuccess = "Garagem actualizada com sucesso!", + getCurrentCoords = "Obter as coordenadas actuais", + identifier = "Identificador", + name = "Nome", + noPlayers = "Não há jogadores adicionados", + addPlayer = "Adicionar jogador", + loadingVehicle = "Carregamento do veículo...", + vehicleSetup = "Configuração do veículo", + extras = "Suplementos", + extra = "Suplemento", + liveries = "Fígados", + livery = "Fígado", + noLiveries = "Não existem pinturas disponíveis", + noExtras = "Não há extras disponíveis", + none = "Nenhum", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "Não pode guardar nesta garagem.", + insertVehiclePublicError = "Você não pode armazenar veículos de emprego ou gangues em garagens públicas", + vehicleParkedSuccess = "Veículo guardado na garagem", + vehicleNotOwnedError = "Você não é dono este veículo", + vehicleNotOwnedByPlayerError = "O veículo não é de propriedade de um jogador", + notEnoughMoneyError = "Você não tem dinheiro suficiente em seu banco", + vehicleNotYoursError = "Veículo não pertence a você", + notJobOrGangVehicle = "Isso não é um %{value} veículo", + invalidGangError = "Você não forneceu uma gangue válida", + invalidJobError = "Você não forneceu um trabalho válido", + notInsideVehicleError = "Você não está sentado em um veículo", + vehicleAddedToGangGarageSuccess = "Veículo adicionado ao %{value} Garagem de gangues!", + vehicleAddedToJobGarageSuccess = "Veículo adicionado ao %{value} Jó Garage!", + moveCloserToVehicleError = "Você precisa se aproximar do veículo", + noVehiclesNearbyError = "Não há veículos próximos", + commandPermissionsError = "Você não tem permissão para usar este comando", + actionNotAllowedError = "Você não tem permissão para fazer isso", + garageNameExistsError = "O nome da garagem já existe", + vehiclePlateExistsError = "A placa do veículo já está em uso", + playerNotOnlineError = "Jogador não está online", + vehicleTransferSuccess = "Veículo transferido para %{value}", + vehicleTransferSuccessGeneral = "Veículo transferido com sucesso", + vehicleReceived = "Você recebeu um veículo com a matricula %{value}", + vehicleImpoundSuccess = "Veículo foi apreendido", + vehicleImpoundRemoveSuccess = "Veículo foi removido dos Apreenndidos!", + vehicleImpoundReturnedToOwnerSuccess = "Veículo voltou à garagem do proprietário", + garageCreatedSuccess = "Garagem criada com sucesso!", + vehiclePlateUpdateSuccess = "Placa do veículo definido para %{value}", + vehicleDeletedSuccess = "Veículo excluído do banco de dados %{value}", + playerIsDead = "Você não pode fazer isso enquanto estiver morto", + + -- Commands + cmdSetGangVehicle = "Adicione o veículo atual a uma garagem de gangue", + cmdRemoveGangVehicle = "Defina o veículo de gangue de volta ao jogador de propriedade", + cmdSetJobVehicle = "Adicione o veículo atual a uma garagem de Trabalho", + cmdRemoveJobVehicle = "Defina o veículo de trabalho de volta para o jogador de propriedade", + cmdArgGangName = "Gang Nome", + cmdArgJobName = "Trabalho Nome", + cmdArgPlayerId = "ID do jogador do novo proprietário", + cmdImpoundVehicle = "Apreender um veículo", + cmdChangePlate = "Altere a placa do veículo (Admin apenas)", + cmdDeleteVeh = "Excluir veículo do banco de dados (Admin apenas)", + cmdCreatePrivGarage = "Criar uma garagem privada para um jogador", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/ro.lua b/resources/[carscripts]/jg-advancedgarages/locales/ro.lua new file mode 100644 index 000000000..3175778b0 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/ro.lua @@ -0,0 +1,142 @@ +Locales = Locales or {} + +Locales['ro'] = { + yes = "Da", + no = "Nu", + garage = "Garaj", + jobGarage = "Garaj de serviciu", + gangGarage = "Garajul bandei", + player = "Jucător", + impound = "Depozit", + inGarage = "În garaj", + notInGarage = "Nu este în garaj", + car = "Mașină", + air = "Aer", + sea = "Mare", + fuel = "Combustibil", + engine = "Motor", + body = "Caroserie", + day = "zi", + days = "zile", + hour = "oră", + hours = "ore", + mins = "minute", + + -- Interfața utilizatorului + noVehicles = "Nu există vehicule în acest garaj", + noVehiclesAvailableToDrive = "Nu există vehicule disponibile pentru a conduce", + vehicles = "vehicul(e)", + vehiclePlate = "Număr de înmatriculare", + vehicleNotInGarage = "Vehiculul a fost lăsat afară", + vehicleTakeOut = "Condu", + vehicleReturnAndTakeOut = "Întoarce & Condu", + vehicleReturnToOwnersGarage = "Întoarce la garajul proprietarului", + transferToGarageOrPlayer = "Transferă la un garaj sau jucător", + transferToGarage = "Transferă la un garaj", + transferToPlayer = "Transferă la un jucător", + vehicleTransfer = "Transfer", + noAvailableGarages = "Nu există garaje disponibile", + currentGarage = "Garaj curent", + noPlayersOnline = "Nu sunt jucători online", + createPrivateGarage = "Creează un garaj privat", + pgAlertHeadsUp = "Atenție!", + pgAlertText = "Garajul va fi creat și vehiculele vor apărea exact în locația și direcția în care te afli în prezent.", + garageName = "Nume Garaj", + impoundInformation = "Informații despre depozit", + impoundedBy = "Depozitat de", + impoundedReason = "Motiv", + impoundPlayerCanCollect = "Poți să îți recuperezi vehiculul din depozit.", + impoundCollectionContact = "Te rugăm să contactezi %{value} pentru a-ți recupera vehiculul.", + impoundNoVehicles = "Nu există vehicule în depozit", + impoundAvailable = "Disponibil", + impoundRetrievableByOwner = "Poate fi recuperat de proprietar", + impoundNoReason = "Niciun motiv furnizat", + impoundVehicle = "Depozitează vehiculul", + impoundReasonField = "Motiv (opțional)", + impoundTime = "Timp de depozitare", + impoundAvailableImmediately = "Disponibil imediat", + impoundCost = "Cost", + changeVehiclePlate = "Schimbă numărul de înmatriculare", + newPlate = "Număr nou", + search = "Caută după nume sau număr", + noPrivateGarages = "Nu există garaje private", + editPrivateGarage = "Editează Garaj Privat", + owners = "Proprietar(i)", + location = "Locație", + next = "Următor", + previous = "Anterior", + page = "Pagină", + of = "din", + show = "Arată", + save = "Salvează", + edit = "Editează", + delete = "Șterge", + garageDeleteConfirm = "Ești sigur că vrei să ștergi acest garaj?", + privGarageSearch = "Caută după nume", + garageUpdatedSuccess = "Garaj actualizat cu succes!", + getCurrentCoords = "Obține coordonatele curente", + identifier = "Identificator", + name = "Nume", + noPlayers = "Nu există jucători adăugați", + addPlayer = "Adaugă jucător", + loadingVehicle = "Se încarcă vehiculul...", + vehicleSetup = "Configurare Vehicul", + extras = "Extraopțiuni", + extra = "Extraopțiune", + liveries = "Livree", + livery = "Livrea", + noLiveries = "Nu există livree disponibile", + noExtras = "Nu există extraopțiuni disponibile", + none = "Niciunul", + vehicleNeedsService = "Necesită service", + type = "Tip", + goInside = "Intră înăuntru", + + -- Notificări + insertVehicleTypeError = "Poți depozita doar vehicule de tip %{value} în acest garaj", + insertVehiclePublicError = "Nu poți depozita vehicule de serviciu sau de bandă în garajele publice", + vehicleParkedSuccess = "Vehicul parcat în garaj", + vehicleNotOwnedError = "Nu deții acest vehicul", + vehicleNotOwnedByPlayerError = "Vehiculul nu este deținut de un jucător", + notEnoughMoneyError = "Nu ai destui bani în bancă", + vehicleNotYoursError = "Vehiculul nu îți aparține", + notJobOrGangVehicle = "Acesta nu este un vehicul %{value}", + invalidGangError = "Nu ai furnizat o bandă validă", + invalidJobError = "Nu ai furnizat un job valid", + notInsideVehicleError = "Nu ești într-un vehicul", + vehicleAddedToGangGarageSuccess = "Vehicul adăugat în garajul bandei %{value}!", + vehicleAddedToJobGarageSuccess = "Vehicul adăugat în garajul de serviciu %{value}!", + moveCloserToVehicleError = "Trebuie să te apropii de vehicul", + noVehiclesNearbyError = "Nu există vehicule în apropiere", + commandPermissionsError = "Nu ai permisiunea de a folosi această comandă", + actionNotAllowedError = "Nu ai permisiunea să faci asta", + garageNameExistsError = "Numele garajului există deja", + vehiclePlateExistsError = "Numărul de înmatriculare este deja utilizat", + playerNotOnlineError = "Jucătorul nu este online", + vehicleTransferSuccess = "Vehicul transferat la %{value}", + vehicleTransferSuccessGeneral = "Vehicul transferat cu succes", + vehicleReceived = "Ai primit un vehicul cu numărul %{value}", + vehicleImpoundSuccess = "Vehicul depozitat cu succes", + vehicleImpoundRemoveSuccess = "Vehicul eliminat din depozit", + vehicleImpoundReturnedToOwnerSuccess = "Vehiculul a fost returnat în garajul proprietarului", + garageCreatedSuccess = "Garaj creat cu succes!", + vehiclePlateUpdateSuccess = "Numărul de înmatriculare a fost schimbat în %{value}", + vehicleDeletedSuccess = "Vehicul șters din baza de date %{value}", + playerIsDead = "Nu poți face asta când ești mort", + vehicleStoreError = "Nu poți depozita acest vehicul aici", + + -- Comenzi + cmdSetGangVehicle = "Adaugă vehiculul curent în garajul bandei", + cmdRemoveGangVehicle = "Setează vehiculul bandei înapoi ca deținut de jucător", + cmdSetJobVehicle = "Adaugă vehiculul curent în garajul de serviciu", + cmdRemoveJobVehicle = "Setează vehiculul de serviciu înapoi ca deținut de jucător", + cmdArgGangName = "Numele bandei", + cmdArgJobName = "Numele jobului", + cmgArgMinGangRank = "Rangul minim în bandă", + cmgArgMinJobRank = "Rangul minim la job", + cmdArgPlayerId = "ID-ul jucătorului noului proprietar", + cmdImpoundVehicle = "Depozitează un vehicul", + cmdChangePlate = "Schimbă numărul de înmatriculare (doar Admin)", + cmdDeleteVeh = "Șterge vehicul din baza de date (doar Admin)", + cmdCreatePrivGarage = "Creează un garaj privat pentru un jucător", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/sv.lua b/resources/[carscripts]/jg-advancedgarages/locales/sv.lua new file mode 100644 index 000000000..fd26a6334 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/sv.lua @@ -0,0 +1,143 @@ +Locales = Locales or {} + +Locales['sv'] = { + yes = "Ja", + no = "Nej", + garage = "garage", + jobGarage = "jobb Garage", + gangGarage = "gäng Garage", + player = "spelare", + impound = "bärgare", + inGarage = "i garaget", + notInGarage = "inte i garaget", + car = "bil", + air = "luft", + sea = "vatten", + fuel = "bränsle", + engine = "motor", + body = "chassie", + day = "dag", + days = "dagar", + hour = "timme", + hours = "timmar", + + -- User Interface + noVehicles = "Det finns inga fordon i detta garaget", + vehicles = "bil(ar)", + vehiclePlate = "Registreringsskylt", + vehicleNotInGarage = "Fordonet är inte i garaget", + vehicleTakeOut = "Ta ut", + vehicleReturnAndTakeOut = "Flytta & Kör", + vehicleReturnToOwnersGarage = "Lämna tillbaka till ägarens garage", + transferToGarageOrPlayer = "Flytta till ett garage eller spelare", + transferToGarage = "Flytta till ett garage", + transferToPlayer = "Flytta till en spelare", + vehicleTransfer = "Flytta", + noAvailableGarages = "Inga tillgängliga garage", + currentGarage = "Nuvarande garage", + noPlayersOnline = "Inga spelare online", + createPrivateGarage = "Skapa privat garage", + pgAlertHeadsUp = "Akta!", + pgAlertText = "Garaget skapas och fordon kommer att spawnas på din position och åt det håll du står.", + garageName = "Garage Namn", + impoundInformation = "Bärgar Information", + impoundedBy = "Bärgad av", + impoundedReason = "Orsak", + impoundPlayerCanCollect = "Du kan hämta din bil från bärgaren.", + impoundCollectionContact = "Kontakta %{value} för att hämta ditt fordon.", + impoundNoVehicles = "Det finns inga fordon hos bärgaren.", + impoundAvailable = "Tillgänglig", + impoundRetrievableByOwner = "Kan hämtas av ägaren", + impoundNoReason = "Ingen anledning tillgänglig", + impoundVehicle = "Bärgat fordon", + impoundReasonField = "Orsak (valfritt)", + impoundTime = "Tid hos bärgaren", + impoundAvailableImmediately = "Tillgänglig direkt", + impoundCost = "Kostnad", + changeVehiclePlate = "Ändra registreringsnummer", + newPlate = "Nytt registreringsnummer", + search = "Sök med namn eller registreringsskylt", + noPrivateGarages = "Inga privata garage", + editPrivateGarage = "Ändra privat garage", + owners = "Ägare(n)", + location = "Plats", + next = "Nästa", + previous = "Tidigare", + page = "Sida", + of = "av", + show = "Visa", + save = "Spara", + edit = "Redigera", + delete = "Radera", + garageDeleteConfirm = "Är du säker på att du vill ta bort detta garage?", + privGarageSearch = "Sök efter namn", + garageUpdatedSuccess = "Garaget har uppdaterats framgångsrikt!", + getCurrentCoords = "Hämta aktuella koordinater", + identifier = "Identifierare", + name = "Namn", + noPlayers = "Inga spelare har tillkommit", + addPlayer = "Lägg till spelare", + loadingVehicle = "Lastning av fordon...", + vehicleSetup = "Inställning av fordon", + extras = "Extramaterial", + extra = "Extra", + liveries = "Liveries", + livery = "livery", + noLiveries = "Inga liveries tillgängliga", + noExtras = "Inga extrafunktioner tillgängliga", + none = "Ingen", + vehicleNeedsService = "Dags för service", + type = "Typ", + + -- Notifications + insertVehicleTypeError = "Du kan endast förvara %{value} fordonstyp i detta garage", + insertVehiclePublicError = "Du kan inte förvara Gäng eller Jobbfordon i allmänna garaget", + vehicleParkedSuccess = "Fordonet är parkerat i garaget", + vehicleNotOwnedError = "Du äger inte detta fordon", + vehicleNotOwnedByPlayerError = "Fordonet ägs inte av en spelare", + notEnoughMoneyError = "Du har inte nog med pengar på banken", + vehicleNotYoursError = "Fordonet tillhör inte dig", + notJobOrGangVehicle = "Detta är inte ett %{value} fordon", + invalidGangError = "Du har inte angett ett giltigt gäng", + invalidJobError = "Du har inte angett ett giltigt jobb", + notInsideVehicleError = "Du sitter inte i fordonet", + vehicleAddedToGangGarageSuccess = "Fordonet är inlagt i %{value} Gäng garage!", + vehicleAddedToJobGarageSuccess = "Fordonet är inlagt %{value} jobb garage!", + moveCloserToVehicleError = "Du måste vara närmare fordonet", + noVehiclesNearbyError = "Det finns inga fordon i närheten", + commandPermissionsError = "Du får inte använda detta kommando", + actionNotAllowedError = "Du får inte göra detta", + garageNameExistsError = "Garagenamnet existerar redan", + vehiclePlateExistsError = "Registreringsnummer finns redan", + playerNotOnlineError = "Spelaren är inte online", + vehicleTransferSuccess = "Fordonet fördes över till %{value}", + vehicleTransferSuccessGeneral = "Fordonet har överförts", + vehicleReceived = "Du fick ett fordon med skylten %{value}", + vehicleImpoundSuccess = "Fordonet är bärgad", + vehicleImpoundRemoveSuccess = "Fordonet hämtad från bärgaren", + vehicleImpoundReturnedToOwnerSuccess = "Fordonet återlämnades till ägarens garage", + garageCreatedSuccess = "Garage har skapats!", + vehiclePlateUpdateSuccess = "Fordonsskylt är uppdaterad till %{value}", + vehicleDeletedSuccess = "Fordonet raderat från databasen %{value}", + playerIsDead = "Du kan inte göra detta då du är död", + + -- Commands + cmdSetGangVehicle = "Lägg till nuvarande fordon till ett gänggarage", + cmdRemoveGangVehicle = "Sätt tillbaka gängfordonet till spelarägt", + cmdSetJobVehicle = "Lägg till aktuellt fordon till ett jobbgarage", + cmdRemoveJobVehicle = "Sätt tillbaka Jobbfordonet till spelarägt", + cmdArgGangName = "Gängnamn", + cmdArgJobName = "Jobbnamn", + cmgArgMinGangRank = "Minimum gäng rank", + cmgArgMinJobRank = "Minimum jobb rank", + cmdArgPlayerId = "SpelarID för nya ägare", + cmdImpoundVehicle = "Bärga ett fordon", + cmdChangePlate = "Ändra fordonsskylt (Admin endast)", + cmdDeleteVeh = "Ta bort fordon från databasen (Admin endast)", + cmdCreatePrivGarage = "Gör ett privatgarage till en spelare", + + -- v3 + vehicleStoreError = "Du kan inte ställa in detta fordonet här", + mins = "minuter", + noVehiclesAvailableToDrive = "Det finns inga fordon i detta garaget", +} diff --git a/resources/[carscripts]/jg-advancedgarages/locales/vi.lua b/resources/[carscripts]/jg-advancedgarages/locales/vi.lua new file mode 100644 index 000000000..bb7675f86 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/locales/vi.lua @@ -0,0 +1,142 @@ +Locales = Locales or {} + +Locales['vi'] = { + yes = "Có", + no = "Không", + garage = "Bãi đậu xe", + jobGarage = "Bãi đậu xe công việc", + gangGarage = "Gang Garage", + player = "Người chơi", + impound = "Bị giam", + inGarage = "Trong gara", + notInGarage = "Bên ngoài", + car = "Xe", + air = "Máy bay", + sea = "Thuyền", + fuel = "Xăng", + engine = "Động cơ", + body = "Thân vỏ", + day = "ngày", + days = "ngày", + hour = "giờ", + hours = "giờ", + + -- User Interface + noVehicles = "Không có xe nào trong gara này", + vehicles = "Xe", + vehiclePlate = "Biển số xe", + vehicleNotInGarage = "Xe không ở trong gara", + vehicleTakeOut = "Lấy xe", + vehicleReturnAndTakeOut = "Thanh toán và lấy xe", + vehicleReturnToOwnersGarage = "Gửi về garage", + transferToGarageOrPlayer = "Transfer to a Garage or Player", + transferToGarage = "Transfer to a Garage", + transferToPlayer = "", + vehicleTransfer = "Chuyển nhượng", + noAvailableGarages = "Không có gara", + currentGarage = "Gara hiện tại", + noPlayersOnline = "Không có người chơi online", + createPrivateGarage = "Tạo gara cá nhân", + pgAlertHeadsUp = "Đứng lên!", + pgAlertText = "Gara sẽ được tạo ra và xe được lấy ra sẽ xuất hiện ngay vị trí mà bạn đang đứng.", + garageName = "Tên Gara", + impoundInformation = "Thông tin giam xe", + impoundedBy = "Giam bởi", + impoundedReason = "Lý do", + impoundPlayerCanCollect = "Bạn có thể lấy xe của mình từ bãi giam xe.", + impoundCollectionContact = "Vui lòng liên hệ %{value} hoặc Police để chuộc lại xe của bạn.", + impoundNoVehicles = "Bạn không có Xe nào bị giam giữ", + impoundAvailable = "Được phép lấy vào lúc ", + impoundAvailableGreen = "Có thể lấy", + impoundRetrievableByOwner = "Chủ xe có thể tự lấy xe ra", + impoundNoReason = "Lý do trống", + impoundVehicle = "Tạm giữ xe", + impoundReasonField = "Lý do", + impoundTime = "Thời gian giam", + impoundAvailableImmediately = "Không có", + impoundCost = "Giá", + changeVehiclePlate = "Đổi biển số xe", + newPlate = "Biển số mới", + search = "Tìm kiếm theo tên hoặc biển số xe", + noPrivateGarages = "Không có nhà để xe riêng", + editPrivateGarage = "Chỉnh sửa nhà để xe riêng", + owners = "Những chủ sở hữu)", + location = "Vị trí", + next = "Kế tiếp", + previous = "Trước", + page = "Trang", + of = "của", + show = "Trình diễn", + save = "Cứu", + edit = "Biên tập", + delete = "Xóa bỏ", + garageDeleteConfirm = "Bạn có chắc chắn muốn xóa gara này không?", + privGarageSearch = "Tìm kiếm theo tên", + garageUpdatedSuccess = "Nhà để xe được cập nhật thành công!", + getCurrentCoords = "Nhận tọa độ hiện tại", + identifier = "định danh", + name = "Tên", + noPlayers = "Không có người chơi nào được thêm vào", + addPlayer = "thêm người chơi", + loadingVehicle = "Tải xe...", + vehicleSetup = "Thiết lập xe", + extras = "Tiện ích bổ sung", + extra = "Thêm", + liveries = "gan", + livery = "gan", + noLiveries = "không có gan", + noExtras = "Không có tính năng bổ sung", + none = "Không có", + vehicleNeedsService = "Needs Service", + type = "Type", + + -- Notifications + insertVehicleTypeError = "Bạn chỉ có thể để %{value} vào trong gara này!", + insertVehiclePublicError = "Bạn không thể cất xe tổ chức vào trong gara công cộng!", + vehicleParkedSuccess = "Cất xe vào gara thành công", + vehicleNotOwnedError = "Bạn không phải là chủ sở hữu của chiếc xe này!", + vehicleNotOwnedByPlayerError = "Xe này không thuộc sở hữu của người chơi nào!", + notEnoughMoneyError = "Bạn không đủ tiền trong ngân hàng!", + vehicleNotYoursError = "Xe này không thuộc về bạn!", + notJobOrGangVehicle = "Đây không phải là xe của %{value}", + invalidGangError = "Tên gang không hợp lệ!", + invalidJobError = "Tên job không hợp lệ!", + notInsideVehicleError = "Bạn không ngồi trên xe", + vehicleAddedToGangGarageSuccess = "Xe này đã được thêm vào %{value}!", + vehicleAddedToJobGarageSuccess = "Xe này đã được thêm vào %{value}!", + moveCloserToVehicleError = "Bạn cần di chuyển đến gần xe hơn!", + noVehiclesNearbyError = "Không có chiếc xe nào gần bạn!", + commandPermissionsError = "Bạn không thể sử dụng lệnh này!", + actionNotAllowedError = "Bạn không được phép làm điều này!", + garageNameExistsError = "Tên gara này đã tồn tại!", + vehiclePlateExistsError = "Biển số xe này đã tồn tại", + playerNotOnlineError = "Người chơi này không online", + vehicleTransferSuccess = "Xe được chuyển đến %{value}", + vehicleTransferSuccessGeneral = "Xe của bạn đã được chuyển thành công!", + vehicleReceived = "Bạn đã nhận được một chiếc xe với biển số %{value}", + vehicleImpoundSuccess = "Tạm giữ xe thành công!", + vehicleImpoundRemoveSuccess = "Xe đã được chuộc thành công", + vehicleImpoundReturnedToOwnerSuccess = "Xe này đã được chuyển về gara chủ sở hữu", + garageCreatedSuccess = "Tạo gara thành công!", + vehiclePlateUpdateSuccess = "Biển số xe được đổi thành: %{value}", + vehicleDeletedSuccess = "Xe này đã được xoá khỏi database %{value}", + playerIsDead = "Bạn không thể làm điều này trong khi bạn đã chết", + + -- Commands + cmdSetGangVehicle = "Thêm Xe hiện tại vào một Gang", + cmdRemoveGangVehicle = "Đặt xe gang thành xe cá nhân", + cmdSetJobVehicle = "Thêm xe hiện tại vào một nghề nào đó", + cmdRemoveJobVehicle = "Đặt xe nghề thành xe cá nhân", + cmdArgGangName = "Tên Gang", + cmdArgJobName = "Tên Job", + cmdArgPlayerId = "ID của chủ sỡ hữu mới", + cmdImpoundVehicle = "Giam giữ xe", + cmdChangePlate = "Đổi biển số xe (Admin only)", + cmdDeleteVeh = "Xoá xe khỏi dữ liệu máy chủ (Admin only)", + cmdCreatePrivGarage = "Tạo gara cá nhân", + + -- v3 + vehicleStoreError = "You cannot store this vehicle here", + mins = "mins", + noVehiclesAvailableToDrive = "There are no vehicles available to drive", +} diff --git a/resources/[carscripts]/jg-advancedgarages/server/sv-garage.lua b/resources/[carscripts]/jg-advancedgarages/server/sv-garage.lua new file mode 100644 index 0000000000000000000000000000000000000000..2597279a5b7b24ea145c3aa7bb9a008cf00e0018 GIT binary patch literal 12355 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 SLaFMjn|>htf0CNJp_54Cw-L4g literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/server/sv-locations.lua b/resources/[carscripts]/jg-advancedgarages/server/sv-locations.lua new file mode 100644 index 0000000000000000000000000000000000000000..17ebb5b6d1ee7171fe2cc7d5383a727337533819 GIT binary patch literal 2683 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 literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/server/sv-private-garages.lua b/resources/[carscripts]/jg-advancedgarages/server/sv-private-garages.lua new file mode 100644 index 0000000000000000000000000000000000000000..c271f984fc64ca1f49030c5f07b373c126c1b495 GIT binary patch literal 4564 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 literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/server/sv-society-garage.lua b/resources/[carscripts]/jg-advancedgarages/server/sv-society-garage.lua new file mode 100644 index 0000000000000000000000000000000000000000..6c333cec5153eec52d02ef4d1a783d5877a7d887 GIT binary patch literal 4165 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 HZnsR2{o(#A literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/server/sv-vehicle.lua b/resources/[carscripts]/jg-advancedgarages/server/sv-vehicle.lua new file mode 100644 index 0000000000000000000000000000000000000000..b88e25d2ed9689e2cfd1aa65a237e9dfc1bc337a GIT binary patch literal 5845 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 literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/server/sv-version-check.lua b/resources/[carscripts]/jg-advancedgarages/server/sv-version-check.lua new file mode 100644 index 0000000000000000000000000000000000000000..bc7ca70bb272826316b30e7cd1e34dac91cb0527 GIT binary patch literal 1913 zcmV-<2Zs1YSV2$$000000M~D+11Co?Cg`^v+G~3m(#*- zo}b8Uno?E|Sd$M6SQ54mDx@0m#kHV=#2oP^0m1F&sMkuubS>&yqP6t{i;xMDa2h_T z-KV?ysC0CnJjEOt1hRE2p;?a|EIy2`PFzUd%GG|3eW2x#lNAw!r45S-%&kS0r_eGez_y?N8lM9P5c>G3Zb{+FqdyM}G18%)KU zH#+P5YULTef1I2U4PBa3DSBk?4C^Qur72pnoknVb$wj$!=tQ1W4bMK85MYq=K{DXd-r-+pdt?1 z8(>Clu+A%0RZ#PiBK-xwQc_~5l&ENN7DsYCQ}x>7TpzsKZMs@8wS#6v zK)QKcM;Tp#!)%rHELUbK01TyO%E|s1wH}{=`?w)L#@#%!8Zt_;)%4@!(9@oYb-^EL z7^4Fq{;2}?>^Jk6&c2KWw=d2WqTBF9s>`0 zf{nAz6naXAD-PHTxg-~6rs==p!sg((|KdBGX5E1PJnwRCKfkX4kvQa(l>9k%r|(_N zQ+|V~)r<#AjU!&-1!3IWQ-BD{yc;gJhSd+cMThe9q?aEdZGwE4HBn9>O{_Y5TKTYf z-j{3VVDZrvdM#zUHDnxk{V8UR^OC+&nDK!ZwMxX+>>-T_F?WALU$Kc1vLIk^x!lm? zX3kd{*uJNVFLl9WbWx>4R*R$r#Ws+wYEjmg^lcH!2BKJNse@3YbudAueIoZRUbULE zF-7-PdncG2wKurQ`oE*$&q-1%>%Vii=x4Wd{hBehMqMzHCwH@zIxCULyiAO7cI+)| zoj+T;2JP{MA6dSHx&n-h70#!qT3cg4wUybnd$DqLfeN){j|JN11Dhu<(66Pp844`E z`y-OUIufkR2cTRMl=?Jnnxf5LUF!AxY7hKRti^w4yTkr`rA0gzNQ*nJO)xKnP;-Qn zR#q$p4O4VDQ(`0nDMXkh!VBXvuWmqk?7Zqe&N8Puo)kV_UQv-__>-df=hR9FKB;=y z-^K@6$>@on+@KOCZaH07UBK~-&u)bjnUq31i;IZ`TzFKFaEtTS9g0%tMHsiamjSFi z4~jTmY0NO-z~O$}J3;!eFc9odjqc~B9eAh=dP@P!9YhbhJBCWC6$br8<5Szc9^^Ze*%y&LK-6OVQTL_nU_pJ6q;t4z-B`fv6Bf)6y-tcgQ zw0d&(9djuo_r@3R!5ddBtM`%h(4qDsnskujX);BY1C!5tH%T z5(*+09Yr%>Pj}ukp5Jh)OR*8*(h|HAk1cRZ9F9>wW{d}VxJIEL6QcL%RD(n&ag(v% z+wRMwe-JygEn%9n0BcP3nXH|?s1DCZ1zJ{^XxhR-rFmgcVqD6{mg^1&+F9>_M3}L; literal 0 HcmV?d00001 diff --git a/resources/[carscripts]/jg-advancedgarages/server/sv-webhooks.lua b/resources/[carscripts]/jg-advancedgarages/server/sv-webhooks.lua new file mode 100644 index 000000000..b11b362f4 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/server/sv-webhooks.lua @@ -0,0 +1,70 @@ +-- +-- Discord Webhooks +-- +Webhooks = {} +Webhooks.VehicleTakeOutAndInsert = "" +Webhooks.VehiclePlayerTransfer = "" +Webhooks.VehicleGarageTransfer = "" +Webhooks.Impound = "" +Webhooks.PrivateGarages = "" + +--[[ + EXAMPLE WEBHOOK CALL + + sendWebhook(src, Webhooks.VehicleTakeOutAndInsert, "Webhook Title", "success", { + { key = "Data fields", value = "Data value" }, + { key = "Data fields 2", value = "Data value 2" } + }) +]]-- + +function sendWebhook(playerId, webhookUrl, title, type, data) + if not webhookUrl then return end + + local identifier = Framework.Server.GetPlayerIdentifier(playerId) + if not identifier then return false end + + local color = 0xff6700 + if type == "success" then color = 0x2ecc71 end + if type == "danger" then color = 0xe74c3c end + + local player = Framework.Server.GetPlayerInfo(playerId) + if not player then return false end + + local fields = { + { + name = "Player", + value = string.format("%s (%s)", player.name, identifier), + inline = false + } + } + for _, row in pairs(data) do + fields[#fields + 1] = { + name = row.key, + value = tostring(row.value), + inline = true + } + end + + local body = { + username = "JG Advanced Garages Webhook", + avatar_url = "https://forum.cfx.re/user_avatar/forum.cfx.re/jgscripts/288/3621910_2.png", + content = "", + embeds = { + { + type = "rich", + title = title, + description = "", + color = color, + fields = fields + } + } + } + + PerformHttpRequest( + webhookUrl, + function(err, text, header) end, + "POST", + json.encode(body), + {["Content-Type"] = "application/json"} + ) +end \ No newline at end of file diff --git a/resources/[carscripts]/jg-advancedgarages/shared/main.lua b/resources/[carscripts]/jg-advancedgarages/shared/main.lua new file mode 100644 index 0000000000000000000000000000000000000000..00e8808f82648aad3fb6fc78b286a32fcc57ecf7 GIT binary patch literal 2218 zcmV;b2vzq+SV2$$0000007wN)9qlmocWvRxg{hH)~0+Q+#D`p+I@@&C$5W-lx378;gTAv2vtgc5T^3sPRdB8(^@BD@_ zw1|vM&W;r$R${VxcIKkbC3DmY;@@c@Qq-#}{nQZgQ0b|y$}`AL?KAIBqjUNHcPFv) zm><|h?kf{o*!$6RH5zO%Lh3=h2VRt^z(54h#BCDF2EP{}!f&xEl@Umvz9Y+?mY7_g z&)hYIo14}eMtxyaiXEY|*+?mujQ>k&VUvYIiEBy@QddmFaBj0SKh7tDbnFKdl%KbV zuZyi!+Rc^pa`>)EK(RR7xn#mnSgpD06IZ-gAFOZ{p0O2`?-c>pQcF+-OiEhYO}O-i z+?wjN+uH`#fa>rmsNK{4C7hyqawCFR3EoOjwyi~d#*Sn|KDQ&}^j1-BLbiuGs`QWo zjtND4K3fq3r2`_#&9^Bv*;aF0d4o9z3@PMbz*G=aA2L^T|!#OW`2FmC`Ax)CBOW5f;{*a0pW~#(%^SoyIPZYeP#1s8)p1`bK2Y_`^ctnx}GY z^;<{$&xN}IM}y5~U(9=8SG|9R8VhFoCl&sNuqF2n*uZD=1|cIx_1^wBj6@W2DtJtDPCUP< ziRmSf_2iLobV`T}P~3w4$h}3+^*kiz2x%z97TZUl4STjXt{h6s(L6AAu5*-?=g`sa zU9Qa&`o-t*_oc3tO|2=7W?okQCKcTZBstlMMg17BzC(rL#UwL+ts$&~fxJ>PE*q~g zwg)I&^@VObp#!5F#CUk0A;P1y3~QI2Gy9W?R@MRt$=f*N#cRT#Ox(blRN7QVw`U`A z2VXR4(lm6DwZ*%2&`1NjvSuJA#!NGc&P!;v6I^f%>T$c-Dmn+! z7p7PG$Sk0|WjWNGmMJt3fgFP&meM9v?pWxx>C>OM)ubl;Tmm&Uq$-6Y8TO>C?P;mM zXJ9R(6FJIkam6U(0H2-00nuy}Nw+ftM8P;)k|2ysh7{HW=DOQX$~f`RhDVAa488{3yM(m$&j zid%}O95>RYmbB~SHW4N+y(c5o12S`u8_u&oZf27+!vta8L#^xF#9rv6QC#BxQXf}7ptH~b#1Wgm(lFG?JaG(15=(W z3(Eap<3P6LjW!=cS0^D|w*O`ySQM1J{?NVSa}gkXA8G&oYeh!T^TE7w01tX18ZLGk z%&%9}8b9iniYAXdUcKE+q@_Mmtt@J=IroUi|=_j0d%@UFGew%j1E62iOo6 zIzHFuIPg%Zo*&g>^@NFsJMcMNgt8W$i;@=3p_9t}#k;YUgQ_Ju02RFs#DlzdTjU1w zlQ_VK5}_J2c3QBIm?e~TZ8mnII4c;{c`pegWvXq^ZRnd*=msO-D%b*{9(;S5W)~f~ zmE{>U>q&TEpfC|j+Ocni0Y_)qkrkz8>PFdppSt^+&ts@s1S5uL++3Ub!t|M8?VS6h za#PCnzRN*KU{r;-oeDI33-$$FuIyc>gZ% z0ZAXOz{|6Ay{B^=cJcUpaN z17Rg_Gx}@Cqr{&yap2|Km!p^wr1>hf-M=?SVR4 zv~`yyKj5#>9Ya!mk}$<~RZCFGT`Vqh#*maUE>kGDOu7JFU!?Urh;bnfjEOI;Cp=-H s!aRYx2L;-Usp!mt8{>(-Ae()=>(i||r((i={exports:{}}).exports,i),i.exports);var f1=Fv((xn,Sn)=>{(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const d of document.querySelectorAll('link[rel="modulepreload"]'))u(d);new MutationObserver(d=>{for(const p of d)if(p.type==="childList")for(const m of p.addedNodes)m.tagName==="LINK"&&m.rel==="modulepreload"&&u(m)}).observe(document,{childList:!0,subtree:!0});function l(d){const p={};return d.integrity&&(p.integrity=d.integrity),d.referrerPolicy&&(p.referrerPolicy=d.referrerPolicy),d.crossOrigin==="use-credentials"?p.credentials="include":d.crossOrigin==="anonymous"?p.credentials="omit":p.credentials="same-origin",p}function u(d){if(d.ep)return;d.ep=!0;const p=l(d);fetch(d.href,p)}})();function Ni(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}var Zu={exports:{}},Sl={},ec={exports:{}},Xe={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var np;function Av(){if(np)return Xe;np=1;var r=Symbol.for("react.element"),i=Symbol.for("react.portal"),l=Symbol.for("react.fragment"),u=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),p=Symbol.for("react.provider"),m=Symbol.for("react.context"),C=Symbol.for("react.forward_ref"),R=Symbol.for("react.suspense"),g=Symbol.for("react.memo"),P=Symbol.for("react.lazy"),O=Symbol.iterator;function I(N){return N===null||typeof N!="object"?null:(N=O&&N[O]||N["@@iterator"],typeof N=="function"?N:null)}var Q={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},z=Object.assign,J={};function V(N,H,Re){this.props=N,this.context=H,this.refs=J,this.updater=Re||Q}V.prototype.isReactComponent={},V.prototype.setState=function(N,H){if(typeof N!="object"&&typeof N!="function"&&N!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,N,H,"setState")},V.prototype.forceUpdate=function(N){this.updater.enqueueForceUpdate(this,N,"forceUpdate")};function ce(){}ce.prototype=V.prototype;function oe(N,H,Re){this.props=N,this.context=H,this.refs=J,this.updater=Re||Q}var se=oe.prototype=new ce;se.constructor=oe,z(se,V.prototype),se.isPureReactComponent=!0;var He=Array.isArray,D=Object.prototype.hasOwnProperty,K={current:null},pe={key:!0,ref:!0,__self:!0,__source:!0};function vt(N,H,Re){var Ne,Me={},Ve=null,qe=null;if(H!=null)for(Ne in H.ref!==void 0&&(qe=H.ref),H.key!==void 0&&(Ve=""+H.key),H)D.call(H,Ne)&&!pe.hasOwnProperty(Ne)&&(Me[Ne]=H[Ne]);var Ke=arguments.length-2;if(Ke===1)Me.children=Re;else if(1>>1,H=X[N];if(0>>1;Nd(Me,le))Ved(qe,Me)?(X[N]=qe,X[Ve]=le,N=Ve):(X[N]=Me,X[Ne]=le,N=Ne);else if(Ved(qe,le))X[N]=qe,X[Ve]=le,N=Ve;else break e}}return Ce}function d(X,Ce){var le=X.sortIndex-Ce.sortIndex;return le!==0?le:X.id-Ce.id}if(typeof performance=="object"&&typeof performance.now=="function"){var p=performance;r.unstable_now=function(){return p.now()}}else{var m=Date,C=m.now();r.unstable_now=function(){return m.now()-C}}var R=[],g=[],P=1,O=null,I=3,Q=!1,z=!1,J=!1,V=typeof setTimeout=="function"?setTimeout:null,ce=typeof clearTimeout=="function"?clearTimeout:null,oe=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function se(X){for(var Ce=l(g);Ce!==null;){if(Ce.callback===null)u(g);else if(Ce.startTime<=X)u(g),Ce.sortIndex=Ce.expirationTime,i(R,Ce);else break;Ce=l(g)}}function He(X){if(J=!1,se(X),!z)if(l(R)!==null)z=!0,ct(D);else{var Ce=l(g);Ce!==null&&et(He,Ce.startTime-X)}}function D(X,Ce){z=!1,J&&(J=!1,ce(vt),vt=-1),Q=!0;var le=I;try{for(se(Ce),O=l(R);O!==null&&(!(O.expirationTime>Ce)||X&&!$t());){var N=O.callback;if(typeof N=="function"){O.callback=null,I=O.priorityLevel;var H=N(O.expirationTime<=Ce);Ce=r.unstable_now(),typeof H=="function"?O.callback=H:O===l(R)&&u(R),se(Ce)}else u(R);O=l(R)}if(O!==null)var Re=!0;else{var Ne=l(g);Ne!==null&&et(He,Ne.startTime-Ce),Re=!1}return Re}finally{O=null,I=le,Q=!1}}var K=!1,pe=null,vt=-1,At=5,_t=-1;function $t(){return!(r.unstable_now()-_tX||125N?(X.sortIndex=le,i(g,X),l(R)===null&&X===l(g)&&(J?(ce(vt),vt=-1):J=!0,et(He,le-N))):(X.sortIndex=H,i(R,X),z||Q||(z=!0,ct(D))),X},r.unstable_shouldYield=$t,r.unstable_wrapCallback=function(X){var Ce=I;return function(){var le=I;I=Ce;try{return X.apply(this,arguments)}finally{I=le}}}}(rc)),rc}var ap;function $v(){return ap||(ap=1,nc.exports=bv()),nc.exports}/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var sp;function Dv(){if(sp)return dn;sp=1;var r=ls(),i=$v();function l(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),R=Object.prototype.hasOwnProperty,g=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,P={},O={};function I(e){return R.call(O,e)?!0:R.call(P,e)?!1:g.test(e)?O[e]=!0:(P[e]=!0,!1)}function Q(e,t,n,o){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return o?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function z(e,t,n,o){if(t===null||typeof t>"u"||Q(e,t,n,o))return!0;if(o)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function J(e,t,n,o,a,c,v){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=o,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=c,this.removeEmptyString=v}var V={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){V[e]=new J(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];V[t]=new J(t,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){V[e]=new J(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){V[e]=new J(e,2,!1,e,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){V[e]=new J(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){V[e]=new J(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){V[e]=new J(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){V[e]=new J(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){V[e]=new J(e,5,!1,e.toLowerCase(),null,!1,!1)});var ce=/[\-:]([a-z])/g;function oe(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(ce,oe);V[t]=new J(t,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(ce,oe);V[t]=new J(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(ce,oe);V[t]=new J(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){V[e]=new J(e,1,!1,e.toLowerCase(),null,!1,!1)}),V.xlinkHref=new J("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){V[e]=new J(e,1,!1,e.toLowerCase(),null,!0,!0)});function se(e,t,n,o){var a=V.hasOwnProperty(t)?V[t]:null;(a!==null?a.type!==0:o||!(2E||a[v]!==c[E]){var T=` +`+a[v].replace(" at new "," at ");return e.displayName&&T.includes("")&&(T=T.replace("",e.displayName)),T}while(1<=v&&0<=E);break}}}finally{Re=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?H(e):""}function Me(e){switch(e.tag){case 5:return H(e.type);case 16:return H("Lazy");case 13:return H("Suspense");case 19:return H("SuspenseList");case 0:case 2:case 15:return e=Ne(e.type,!1),e;case 11:return e=Ne(e.type.render,!1),e;case 1:return e=Ne(e.type,!0),e;default:return""}}function Ve(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case pe:return"Fragment";case K:return"Portal";case At:return"Profiler";case vt:return"StrictMode";case tt:return"Suspense";case nt:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case $t:return(e.displayName||"Context")+".Consumer";case _t:return(e._context.displayName||"Context")+".Provider";case Lt:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case It:return t=e.displayName||null,t!==null?t:Ve(e.type)||"Memo";case ct:t=e._payload,e=e._init;try{return Ve(e(t))}catch{}}return null}function qe(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Ve(t);case 8:return t===vt?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Ke(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Ze(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function gt(e){var t=Ze(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),o=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var a=n.get,c=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(v){o=""+v,c.call(this,v)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return o},setValue:function(v){o=""+v},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Zt(e){e._valueTracker||(e._valueTracker=gt(e))}function pn(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),o="";return e&&(o=Ze(e)?e.checked?"true":"false":e.value),e=o,e!==n?(t.setValue(e),!0):!1}function Kt(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function nn(e,t){var n=t.checked;return le({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function lt(e,t){var n=t.defaultValue==null?"":t.defaultValue,o=t.checked!=null?t.checked:t.defaultChecked;n=Ke(t.value!=null?t.value:n),e._wrapperState={initialChecked:o,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function Fn(e,t){t=t.checked,t!=null&&se(e,"checked",t,!1)}function mn(e,t){Fn(e,t);var n=Ke(t.value),o=t.type;if(n!=null)o==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(o==="submit"||o==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?An(e,t.type,n):t.hasOwnProperty("defaultValue")&&An(e,t.type,Ke(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Er(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var o=t.type;if(!(o!=="submit"&&o!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function An(e,t,n){(t!=="number"||Kt(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Ln=Array.isArray;function Cn(e,t,n,o){if(e=e.options,t){t={};for(var a=0;a"+t.valueOf().toString()+"",t=dt.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Mn(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var bn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Oi=["Webkit","ms","Moz","O"];Object.keys(bn).forEach(function(e){Oi.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),bn[t]=bn[e]})});function Kr(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||bn.hasOwnProperty(e)&&bn[e]?(""+t).trim():t+"px"}function Qr(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var o=n.indexOf("--")===0,a=Kr(n,t[n],o);n==="float"&&(n="cssFloat"),o?e.setProperty(n,a):e[n]=a}}var Dl=le({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Mo(e,t){if(t){if(Dl[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(l(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(l(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(l(61))}if(t.style!=null&&typeof t.style!="object")throw Error(l(62))}}function bo(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var $o=null;function Do(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Bo=null,rr=null,or=null;function Fi(e){if(e=ll(e)){if(typeof Bo!="function")throw Error(l(280));var t=e.stateNode;t&&(t=ca(t),Bo(e.stateNode,e.type,t))}}function jr(e){rr?or?or.push(e):or=[e]:rr=e}function Ai(){if(rr){var e=rr,t=or;if(or=rr=null,Fi(e),t)for(e=0;e>>=0,e===0?32:31-(ks(e)/Ts|0)|0}var Ko=64,Qo=4194304;function Jr(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Xo(e,t){var n=e.pendingLanes;if(n===0)return 0;var o=0,a=e.suspendedLanes,c=e.pingedLanes,v=n&268435455;if(v!==0){var E=v&~a;E!==0?o=Jr(E):(c&=v,c!==0&&(o=Jr(c)))}else v=n&~a,v!==0?o=Jr(v):c!==0&&(o=Jr(c));if(o===0)return 0;if(t!==0&&t!==o&&(t&a)===0&&(a=o&-o,c=t&-t,a>=c||a===16&&(c&4194240)!==0))return t;if((o&4)!==0&&(o|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=o;0n;n++)t.push(e);return t}function Zr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-hn(t),e[t]=n}function Ps(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var o=e.eventTimes;for(e=e.expirationTimes;0=uo),Ji=" ",co=!1;function fo(e,t){switch(e){case"keyup":return ea.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Zi(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ar=!1;function Fs(e,t){switch(e){case"compositionend":return Zi(t);case"keypress":return t.which!==32?null:(co=!0,Ji);case"textInput":return e=t.data,e===Ji&&co?null:e;default:return null}}function As(e,t){if(ar)return e==="compositionend"||!so&&fo(e,t)?(e=j(),w=y=h=null,ar=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=o}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=od(n)}}function ld(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?ld(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function ad(){for(var e=window,t=Kt();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Kt(e.document)}return t}function Ms(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Bh(e){var t=ad(),n=e.focusedElem,o=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&ld(n.ownerDocument.documentElement,n)){if(o!==null&&Ms(n)){if(t=o.start,e=o.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var a=n.textContent.length,c=Math.min(o.start,a);o=o.end===void 0?c:Math.min(o.end,a),!e.extend&&c>o&&(a=o,o=c,c=a),a=id(n,c);var v=id(n,o);a&&v&&(e.rangeCount!==1||e.anchorNode!==a.node||e.anchorOffset!==a.offset||e.focusNode!==v.node||e.focusOffset!==v.offset)&&(t=t.createRange(),t.setStart(a.node,a.offset),e.removeAllRanges(),c>o?(e.addRange(t),e.extend(v.node,v.offset)):(t.setEnd(v.node,v.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,ri=null,bs=null,tl=null,$s=!1;function sd(e,t,n){var o=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;$s||ri==null||ri!==Kt(o)||(o=ri,"selectionStart"in o&&Ms(o)?o={start:o.selectionStart,end:o.selectionEnd}:(o=(o.ownerDocument&&o.ownerDocument.defaultView||window).getSelection(),o={anchorNode:o.anchorNode,anchorOffset:o.anchorOffset,focusNode:o.focusNode,focusOffset:o.focusOffset}),tl&&el(tl,o)||(tl=o,o=aa(bs,"onSelect"),0si||(e.current=qs[si],qs[si]=null,si--)}function mt(e,t){si++,qs[si]=e.current,e.current=t}var Ir={},Qt=Pr(Ir),ln=Pr(!1),vo=Ir;function ui(e,t){var n=e.type.contextTypes;if(!n)return Ir;var o=e.stateNode;if(o&&o.__reactInternalMemoizedUnmaskedChildContext===t)return o.__reactInternalMemoizedMaskedChildContext;var a={},c;for(c in n)a[c]=t[c];return o&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=a),a}function an(e){return e=e.childContextTypes,e!=null}function da(){wt(ln),wt(Qt)}function Ed(e,t,n){if(Qt.current!==Ir)throw Error(l(168));mt(Qt,t),mt(ln,n)}function jd(e,t,n){var o=e.stateNode;if(t=t.childContextTypes,typeof o.getChildContext!="function")return n;o=o.getChildContext();for(var a in o)if(!(a in t))throw Error(l(108,qe(e)||"Unknown",a));return le({},n,o)}function fa(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Ir,vo=Qt.current,mt(Qt,e),mt(ln,ln.current),!0}function Rd(e,t,n){var o=e.stateNode;if(!o)throw Error(l(169));n?(e=jd(e,t,vo),o.__reactInternalMemoizedMergedChildContext=e,wt(ln),wt(Qt),mt(Qt,e)):wt(ln),mt(ln,n)}var ur=null,pa=!1,Ys=!1;function kd(e){ur===null?ur=[e]:ur.push(e)}function Jh(e){pa=!0,kd(e)}function Or(){if(!Ys&&ur!==null){Ys=!0;var e=0,t=ot;try{var n=ur;for(ot=1;e>=v,a-=v,cr=1<<32-hn(t)+a|n<be?(zt=Oe,Oe=null):zt=Oe.sibling;var it=W(F,Oe,A[be],ne);if(it===null){Oe===null&&(Oe=zt);break}e&&Oe&&it.alternate===null&&t(F,Oe),_=c(it,_,be),Ie===null?Ee=it:Ie.sibling=it,Ie=it,Oe=zt}if(be===A.length)return n(F,Oe),Ct&&yo(F,be),Ee;if(Oe===null){for(;bebe?(zt=Oe,Oe=null):zt=Oe.sibling;var zr=W(F,Oe,it.value,ne);if(zr===null){Oe===null&&(Oe=zt);break}e&&Oe&&zr.alternate===null&&t(F,Oe),_=c(zr,_,be),Ie===null?Ee=zr:Ie.sibling=zr,Ie=zr,Oe=zt}if(it.done)return n(F,Oe),Ct&&yo(F,be),Ee;if(Oe===null){for(;!it.done;be++,it=A.next())it=Y(F,it.value,ne),it!==null&&(_=c(it,_,be),Ie===null?Ee=it:Ie.sibling=it,Ie=it);return Ct&&yo(F,be),Ee}for(Oe=o(F,Oe);!it.done;be++,it=A.next())it=fe(Oe,F,be,it.value,ne),it!==null&&(e&&it.alternate!==null&&Oe.delete(it.key===null?be:it.key),_=c(it,_,be),Ie===null?Ee=it:Ie.sibling=it,Ie=it);return e&&Oe.forEach(function(Ov){return t(F,Ov)}),Ct&&yo(F,be),Ee}function Nt(F,_,A,ne){if(typeof A=="object"&&A!==null&&A.type===pe&&A.key===null&&(A=A.props.children),typeof A=="object"&&A!==null){switch(A.$$typeof){case D:e:{for(var Ee=A.key,Ie=_;Ie!==null;){if(Ie.key===Ee){if(Ee=A.type,Ee===pe){if(Ie.tag===7){n(F,Ie.sibling),_=a(Ie,A.props.children),_.return=F,F=_;break e}}else if(Ie.elementType===Ee||typeof Ee=="object"&&Ee!==null&&Ee.$$typeof===ct&&Od(Ee)===Ie.type){n(F,Ie.sibling),_=a(Ie,A.props),_.ref=al(F,Ie,A),_.return=F,F=_;break e}n(F,Ie);break}else t(F,Ie);Ie=Ie.sibling}A.type===pe?(_=ko(A.props.children,F.mode,ne,A.key),_.return=F,F=_):(ne=za(A.type,A.key,A.props,null,F.mode,ne),ne.ref=al(F,_,A),ne.return=F,F=ne)}return v(F);case K:e:{for(Ie=A.key;_!==null;){if(_.key===Ie)if(_.tag===4&&_.stateNode.containerInfo===A.containerInfo&&_.stateNode.implementation===A.implementation){n(F,_.sibling),_=a(_,A.children||[]),_.return=F,F=_;break e}else{n(F,_);break}else t(F,_);_=_.sibling}_=Qu(A,F.mode,ne),_.return=F,F=_}return v(F);case ct:return Ie=A._init,Nt(F,_,Ie(A._payload),ne)}if(Ln(A))return ge(F,_,A,ne);if(Ce(A))return Se(F,_,A,ne);ga(F,A)}return typeof A=="string"&&A!==""||typeof A=="number"?(A=""+A,_!==null&&_.tag===6?(n(F,_.sibling),_=a(_,A),_.return=F,F=_):(n(F,_),_=Ku(A,F.mode,ne),_.return=F,F=_),v(F)):n(F,_)}return Nt}var pi=Fd(!0),Ad=Fd(!1),ya=Pr(null),wa=null,mi=null,ru=null;function ou(){ru=mi=wa=null}function iu(e){var t=ya.current;wt(ya),e._currentValue=t}function lu(e,t,n){for(;e!==null;){var o=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,o!==null&&(o.childLanes|=t)):o!==null&&(o.childLanes&t)!==t&&(o.childLanes|=t),e===n)break;e=e.return}}function hi(e,t){wa=e,ru=mi=null,e=e.dependencies,e!==null&&e.firstContext!==null&&((e.lanes&t)!==0&&(sn=!0),e.firstContext=null)}function Tn(e){var t=e._currentValue;if(ru!==e)if(e={context:e,memoizedValue:t,next:null},mi===null){if(wa===null)throw Error(l(308));mi=e,wa.dependencies={lanes:0,firstContext:e}}else mi=mi.next=e;return t}var wo=null;function au(e){wo===null?wo=[e]:wo.push(e)}function Ld(e,t,n,o){var a=t.interleaved;return a===null?(n.next=n,au(t)):(n.next=a.next,a.next=n),t.interleaved=n,fr(e,o)}function fr(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Fr=!1;function su(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Md(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function pr(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function Ar(e,t,n){var o=e.updateQueue;if(o===null)return null;if(o=o.shared,(rt&2)!==0){var a=o.pending;return a===null?t.next=t:(t.next=a.next,a.next=t),o.pending=t,fr(e,n)}return a=o.interleaved,a===null?(t.next=t,au(o)):(t.next=a.next,a.next=t),o.interleaved=t,fr(e,n)}function xa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var o=t.lanes;o&=e.pendingLanes,n|=o,t.lanes=n,qo(e,n)}}function bd(e,t){var n=e.updateQueue,o=e.alternate;if(o!==null&&(o=o.updateQueue,n===o)){var a=null,c=null;if(n=n.firstBaseUpdate,n!==null){do{var v={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};c===null?a=c=v:c=c.next=v,n=n.next}while(n!==null);c===null?a=c=t:c=c.next=t}else a=c=t;n={baseState:o.baseState,firstBaseUpdate:a,lastBaseUpdate:c,shared:o.shared,effects:o.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Sa(e,t,n,o){var a=e.updateQueue;Fr=!1;var c=a.firstBaseUpdate,v=a.lastBaseUpdate,E=a.shared.pending;if(E!==null){a.shared.pending=null;var T=E,L=T.next;T.next=null,v===null?c=L:v.next=L,v=T;var U=e.alternate;U!==null&&(U=U.updateQueue,E=U.lastBaseUpdate,E!==v&&(E===null?U.firstBaseUpdate=L:E.next=L,U.lastBaseUpdate=T))}if(c!==null){var Y=a.baseState;v=0,U=L=T=null,E=c;do{var W=E.lane,fe=E.eventTime;if((o&W)===W){U!==null&&(U=U.next={eventTime:fe,lane:0,tag:E.tag,payload:E.payload,callback:E.callback,next:null});e:{var ge=e,Se=E;switch(W=t,fe=n,Se.tag){case 1:if(ge=Se.payload,typeof ge=="function"){Y=ge.call(fe,Y,W);break e}Y=ge;break e;case 3:ge.flags=ge.flags&-65537|128;case 0:if(ge=Se.payload,W=typeof ge=="function"?ge.call(fe,Y,W):ge,W==null)break e;Y=le({},Y,W);break e;case 2:Fr=!0}}E.callback!==null&&E.lane!==0&&(e.flags|=64,W=a.effects,W===null?a.effects=[E]:W.push(E))}else fe={eventTime:fe,lane:W,tag:E.tag,payload:E.payload,callback:E.callback,next:null},U===null?(L=U=fe,T=Y):U=U.next=fe,v|=W;if(E=E.next,E===null){if(E=a.shared.pending,E===null)break;W=E,E=W.next,W.next=null,a.lastBaseUpdate=W,a.shared.pending=null}}while(!0);if(U===null&&(T=Y),a.baseState=T,a.firstBaseUpdate=L,a.lastBaseUpdate=U,t=a.shared.interleaved,t!==null){a=t;do v|=a.lane,a=a.next;while(a!==t)}else c===null&&(a.shared.lanes=0);Co|=v,e.lanes=v,e.memoizedState=Y}}function $d(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var o=pu.transition;pu.transition={};try{e(!1),t()}finally{ot=n,pu.transition=o}}function rf(){return _n().memoizedState}function nv(e,t,n){var o=$r(e);if(n={lane:o,action:n,hasEagerState:!1,eagerState:null,next:null},of(e))lf(t,n);else if(n=Ld(e,t,n,o),n!==null){var a=tn();Wn(n,e,o,a),af(n,t,o)}}function rv(e,t,n){var o=$r(e),a={lane:o,action:n,hasEagerState:!1,eagerState:null,next:null};if(of(e))lf(t,a);else{var c=e.alternate;if(e.lanes===0&&(c===null||c.lanes===0)&&(c=t.lastRenderedReducer,c!==null))try{var v=t.lastRenderedState,E=c(v,n);if(a.hasEagerState=!0,a.eagerState=E,Bn(E,v)){var T=t.interleaved;T===null?(a.next=a,au(t)):(a.next=T.next,T.next=a),t.interleaved=a;return}}catch{}finally{}n=Ld(e,t,a,o),n!==null&&(a=tn(),Wn(n,e,o,a),af(n,t,o))}}function of(e){var t=e.alternate;return e===Rt||t!==null&&t===Rt}function lf(e,t){dl=ja=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function af(e,t,n){if((n&4194240)!==0){var o=t.lanes;o&=e.pendingLanes,n|=o,t.lanes=n,qo(e,n)}}var Ta={readContext:Tn,useCallback:Xt,useContext:Xt,useEffect:Xt,useImperativeHandle:Xt,useInsertionEffect:Xt,useLayoutEffect:Xt,useMemo:Xt,useReducer:Xt,useRef:Xt,useState:Xt,useDebugValue:Xt,useDeferredValue:Xt,useTransition:Xt,useMutableSource:Xt,useSyncExternalStore:Xt,useId:Xt,unstable_isNewReconciler:!1},ov={readContext:Tn,useCallback:function(e,t){return Zn().memoizedState=[e,t===void 0?null:t],e},useContext:Tn,useEffect:Xd,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Ra(4194308,4,Jd.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ra(4194308,4,e,t)},useInsertionEffect:function(e,t){return Ra(4,2,e,t)},useMemo:function(e,t){var n=Zn();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var o=Zn();return t=n!==void 0?n(t):t,o.memoizedState=o.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},o.queue=e,e=e.dispatch=nv.bind(null,Rt,e),[o.memoizedState,e]},useRef:function(e){var t=Zn();return e={current:e},t.memoizedState=e},useState:Kd,useDebugValue:xu,useDeferredValue:function(e){return Zn().memoizedState=e},useTransition:function(){var e=Kd(!1),t=e[0];return e=tv.bind(null,e[1]),Zn().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var o=Rt,a=Zn();if(Ct){if(n===void 0)throw Error(l(407));n=n()}else{if(n=t(),Bt===null)throw Error(l(349));(So&30)!==0||Hd(o,t,n)}a.memoizedState=n;var c={value:n,getSnapshot:t};return a.queue=c,Xd(Vd.bind(null,o,c,e),[e]),o.flags|=2048,ml(9,Gd.bind(null,o,c,n,t),void 0,null),n},useId:function(){var e=Zn(),t=Bt.identifierPrefix;if(Ct){var n=dr,o=cr;n=(o&~(1<<32-hn(o)-1)).toString(32)+n,t=":"+t+"R"+n,n=fl++,0<\/script>",e=e.removeChild(e.firstChild)):typeof o.is=="string"?e=v.createElement(n,{is:o.is}):(e=v.createElement(n),n==="select"&&(v=e,o.multiple?v.multiple=!0:o.size&&(v.size=o.size))):e=v.createElementNS(e,n),e[Yn]=t,e[il]=o,Tf(e,t,!1,!1),t.stateNode=e;e:{switch(v=bo(n,o),n){case"dialog":yt("cancel",e),yt("close",e),a=o;break;case"iframe":case"object":case"embed":yt("load",e),a=o;break;case"video":case"audio":for(a=0;axi&&(t.flags|=128,o=!0,hl(c,!1),t.lanes=4194304)}else{if(!o)if(e=Ca(v),e!==null){if(t.flags|=128,o=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),hl(c,!0),c.tail===null&&c.tailMode==="hidden"&&!v.alternate&&!Ct)return qt(t),null}else 2*Et()-c.renderingStartTime>xi&&n!==1073741824&&(t.flags|=128,o=!0,hl(c,!1),t.lanes=4194304);c.isBackwards?(v.sibling=t.child,t.child=v):(n=c.last,n!==null?n.sibling=v:t.child=v,c.last=v)}return c.tail!==null?(t=c.tail,c.rendering=t,c.tail=t.sibling,c.renderingStartTime=Et(),t.sibling=null,n=jt.current,mt(jt,o?n&1|2:n&1),t):(qt(t),null);case 22:case 23:return Vu(),o=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==o&&(t.flags|=8192),o&&(t.mode&1)!==0?(yn&1073741824)!==0&&(qt(t),t.subtreeFlags&6&&(t.flags|=8192)):qt(t),null;case 24:return null;case 25:return null}throw Error(l(156,t.tag))}function fv(e,t){switch(Zs(t),t.tag){case 1:return an(t.type)&&da(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return vi(),wt(ln),wt(Qt),fu(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 5:return cu(t),null;case 13:if(wt(jt),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(l(340));fi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return wt(jt),null;case 4:return vi(),null;case 10:return iu(t.type._context),null;case 22:case 23:return Vu(),null;case 24:return null;default:return null}}var Ia=!1,Yt=!1,pv=typeof WeakSet=="function"?WeakSet:Set,he=null;function yi(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(o){Tt(e,t,o)}else n.current=null}function Ou(e,t,n){try{n()}catch(o){Tt(e,t,o)}}var Pf=!1;function mv(e,t){if(Vs=lo,e=ad(),Ms(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var o=n.getSelection&&n.getSelection();if(o&&o.rangeCount!==0){n=o.anchorNode;var a=o.anchorOffset,c=o.focusNode;o=o.focusOffset;try{n.nodeType,c.nodeType}catch{n=null;break e}var v=0,E=-1,T=-1,L=0,U=0,Y=e,W=null;t:for(;;){for(var fe;Y!==n||a!==0&&Y.nodeType!==3||(E=v+a),Y!==c||o!==0&&Y.nodeType!==3||(T=v+o),Y.nodeType===3&&(v+=Y.nodeValue.length),(fe=Y.firstChild)!==null;)W=Y,Y=fe;for(;;){if(Y===e)break t;if(W===n&&++L===a&&(E=v),W===c&&++U===o&&(T=v),(fe=Y.nextSibling)!==null)break;Y=W,W=Y.parentNode}Y=fe}n=E===-1||T===-1?null:{start:E,end:T}}else n=null}n=n||{start:0,end:0}}else n=null;for(Ws={focusedElem:e,selectionRange:n},lo=!1,he=t;he!==null;)if(t=he,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,he=e;else for(;he!==null;){t=he;try{var ge=t.alternate;if((t.flags&1024)!==0)switch(t.tag){case 0:case 11:case 15:break;case 1:if(ge!==null){var Se=ge.memoizedProps,Nt=ge.memoizedState,F=t.stateNode,_=F.getSnapshotBeforeUpdate(t.elementType===t.type?Se:Hn(t.type,Se),Nt);F.__reactInternalSnapshotBeforeUpdate=_}break;case 3:var A=t.stateNode.containerInfo;A.nodeType===1?A.textContent="":A.nodeType===9&&A.documentElement&&A.removeChild(A.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(l(163))}}catch(ne){Tt(t,t.return,ne)}if(e=t.sibling,e!==null){e.return=t.return,he=e;break}he=t.return}return ge=Pf,Pf=!1,ge}function vl(e,t,n){var o=t.updateQueue;if(o=o!==null?o.lastEffect:null,o!==null){var a=o=o.next;do{if((a.tag&e)===e){var c=a.destroy;a.destroy=void 0,c!==void 0&&Ou(t,n,c)}a=a.next}while(a!==o)}}function Oa(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var o=n.create;n.destroy=o()}n=n.next}while(n!==t)}}function Fu(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function If(e){var t=e.alternate;t!==null&&(e.alternate=null,If(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Yn],delete t[il],delete t[Xs],delete t[qh],delete t[Yh])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Of(e){return e.tag===5||e.tag===3||e.tag===4}function Ff(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Of(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Au(e,t,n){var o=e.tag;if(o===5||o===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=ua));else if(o!==4&&(e=e.child,e!==null))for(Au(e,t,n),e=e.sibling;e!==null;)Au(e,t,n),e=e.sibling}function Lu(e,t,n){var o=e.tag;if(o===5||o===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(o!==4&&(e=e.child,e!==null))for(Lu(e,t,n),e=e.sibling;e!==null;)Lu(e,t,n),e=e.sibling}var Wt=null,Gn=!1;function Lr(e,t,n){for(n=n.child;n!==null;)Af(e,t,n),n=n.sibling}function Af(e,t,n){if(En&&typeof En.onCommitFiberUnmount=="function")try{En.onCommitFiberUnmount(Uo,n)}catch{}switch(n.tag){case 5:Yt||yi(n,t);case 6:var o=Wt,a=Gn;Wt=null,Lr(e,t,n),Wt=o,Gn=a,Wt!==null&&(Gn?(e=Wt,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Wt.removeChild(n.stateNode));break;case 18:Wt!==null&&(Gn?(e=Wt,n=n.stateNode,e.nodeType===8?Qs(e.parentNode,n):e.nodeType===1&&Qs(e,n),io(e)):Qs(Wt,n.stateNode));break;case 4:o=Wt,a=Gn,Wt=n.stateNode.containerInfo,Gn=!0,Lr(e,t,n),Wt=o,Gn=a;break;case 0:case 11:case 14:case 15:if(!Yt&&(o=n.updateQueue,o!==null&&(o=o.lastEffect,o!==null))){a=o=o.next;do{var c=a,v=c.destroy;c=c.tag,v!==void 0&&((c&2)!==0||(c&4)!==0)&&Ou(n,t,v),a=a.next}while(a!==o)}Lr(e,t,n);break;case 1:if(!Yt&&(yi(n,t),o=n.stateNode,typeof o.componentWillUnmount=="function"))try{o.props=n.memoizedProps,o.state=n.memoizedState,o.componentWillUnmount()}catch(E){Tt(n,t,E)}Lr(e,t,n);break;case 21:Lr(e,t,n);break;case 22:n.mode&1?(Yt=(o=Yt)||n.memoizedState!==null,Lr(e,t,n),Yt=o):Lr(e,t,n);break;default:Lr(e,t,n)}}function Lf(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new pv),t.forEach(function(o){var a=Ev.bind(null,e,o);n.has(o)||(n.add(o),o.then(a,a))})}}function Vn(e,t){var n=t.deletions;if(n!==null)for(var o=0;oa&&(a=v),o&=~c}if(o=a,o=Et()-o,o=(120>o?120:480>o?480:1080>o?1080:1920>o?1920:3e3>o?3e3:4320>o?4320:1960*vv(o/1960))-o,10e?16:e,br===null)var o=!1;else{if(e=br,br=null,ba=0,(rt&6)!==0)throw Error(l(331));var a=rt;for(rt|=4,he=e.current;he!==null;){var c=he,v=c.child;if((he.flags&16)!==0){var E=c.deletions;if(E!==null){for(var T=0;TEt()-$u?jo(e,0):bu|=n),cn(e,t)}function Qf(e,t){t===0&&((e.mode&1)===0?t=1:(t=Qo,Qo<<=1,(Qo&130023424)===0&&(Qo=4194304)));var n=tn();e=fr(e,t),e!==null&&(Zr(e,t,n),cn(e,n))}function Cv(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Qf(e,n)}function Ev(e,t){var n=0;switch(e.tag){case 13:var o=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:o=e.stateNode;break;default:throw Error(l(314))}o!==null&&o.delete(t),Qf(e,n)}var Xf;Xf=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||ln.current)sn=!0;else{if((e.lanes&n)===0&&(t.flags&128)===0)return sn=!1,cv(e,t,n);sn=(e.flags&131072)!==0}else sn=!1,Ct&&(t.flags&1048576)!==0&&Td(t,ha,t.index);switch(t.lanes=0,t.tag){case 2:var o=t.type;Pa(e,t),e=t.pendingProps;var a=ui(t,Qt.current);hi(t,n),a=hu(null,t,o,e,a,n);var c=vu();return t.flags|=1,typeof a=="object"&&a!==null&&typeof a.render=="function"&&a.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,an(o)?(c=!0,fa(t)):c=!1,t.memoizedState=a.state!==null&&a.state!==void 0?a.state:null,su(t),a.updater=_a,t.stateNode=a,a._reactInternals=t,Cu(t,o,e,n),t=ku(null,t,o,!0,c,n)):(t.tag=0,Ct&&c&&Js(t),en(null,t,a,n),t=t.child),t;case 16:o=t.elementType;e:{switch(Pa(e,t),e=t.pendingProps,a=o._init,o=a(o._payload),t.type=o,a=t.tag=Rv(o),e=Hn(o,e),a){case 0:t=Ru(null,t,o,e,n);break e;case 1:t=Sf(null,t,o,e,n);break e;case 11:t=vf(null,t,o,e,n);break e;case 14:t=gf(null,t,o,Hn(o.type,e),n);break e}throw Error(l(306,o,""))}return t;case 0:return o=t.type,a=t.pendingProps,a=t.elementType===o?a:Hn(o,a),Ru(e,t,o,a,n);case 1:return o=t.type,a=t.pendingProps,a=t.elementType===o?a:Hn(o,a),Sf(e,t,o,a,n);case 3:e:{if(Cf(t),e===null)throw Error(l(387));o=t.pendingProps,c=t.memoizedState,a=c.element,Md(e,t),Sa(t,o,null,n);var v=t.memoizedState;if(o=v.element,c.isDehydrated)if(c={element:o,isDehydrated:!1,cache:v.cache,pendingSuspenseBoundaries:v.pendingSuspenseBoundaries,transitions:v.transitions},t.updateQueue.baseState=c,t.memoizedState=c,t.flags&256){a=gi(Error(l(423)),t),t=Ef(e,t,o,n,a);break e}else if(o!==a){a=gi(Error(l(424)),t),t=Ef(e,t,o,n,a);break e}else for(gn=Nr(t.stateNode.containerInfo.firstChild),vn=t,Ct=!0,zn=null,n=Ad(t,null,o,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(fi(),o===a){t=mr(e,t,n);break e}en(e,t,o,n)}t=t.child}return t;case 5:return Dd(t),e===null&&tu(t),o=t.type,a=t.pendingProps,c=e!==null?e.memoizedProps:null,v=a.children,Us(o,a)?v=null:c!==null&&Us(o,c)&&(t.flags|=32),xf(e,t),en(e,t,v,n),t.child;case 6:return e===null&&tu(t),null;case 13:return jf(e,t,n);case 4:return uu(t,t.stateNode.containerInfo),o=t.pendingProps,e===null?t.child=pi(t,null,o,n):en(e,t,o,n),t.child;case 11:return o=t.type,a=t.pendingProps,a=t.elementType===o?a:Hn(o,a),vf(e,t,o,a,n);case 7:return en(e,t,t.pendingProps,n),t.child;case 8:return en(e,t,t.pendingProps.children,n),t.child;case 12:return en(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(o=t.type._context,a=t.pendingProps,c=t.memoizedProps,v=a.value,mt(ya,o._currentValue),o._currentValue=v,c!==null)if(Bn(c.value,v)){if(c.children===a.children&&!ln.current){t=mr(e,t,n);break e}}else for(c=t.child,c!==null&&(c.return=t);c!==null;){var E=c.dependencies;if(E!==null){v=c.child;for(var T=E.firstContext;T!==null;){if(T.context===o){if(c.tag===1){T=pr(-1,n&-n),T.tag=2;var L=c.updateQueue;if(L!==null){L=L.shared;var U=L.pending;U===null?T.next=T:(T.next=U.next,U.next=T),L.pending=T}}c.lanes|=n,T=c.alternate,T!==null&&(T.lanes|=n),lu(c.return,n,t),E.lanes|=n;break}T=T.next}}else if(c.tag===10)v=c.type===t.type?null:c.child;else if(c.tag===18){if(v=c.return,v===null)throw Error(l(341));v.lanes|=n,E=v.alternate,E!==null&&(E.lanes|=n),lu(v,n,t),v=c.sibling}else v=c.child;if(v!==null)v.return=c;else for(v=c;v!==null;){if(v===t){v=null;break}if(c=v.sibling,c!==null){c.return=v.return,v=c;break}v=v.return}c=v}en(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,o=t.pendingProps.children,hi(t,n),a=Tn(a),o=o(a),t.flags|=1,en(e,t,o,n),t.child;case 14:return o=t.type,a=Hn(o,t.pendingProps),a=Hn(o.type,a),gf(e,t,o,a,n);case 15:return yf(e,t,t.type,t.pendingProps,n);case 17:return o=t.type,a=t.pendingProps,a=t.elementType===o?a:Hn(o,a),Pa(e,t),t.tag=1,an(o)?(e=!0,fa(t)):e=!1,hi(t,n),uf(t,o,a),Cu(t,o,a,n),ku(null,t,o,!0,e,n);case 19:return kf(e,t,n);case 22:return wf(e,t,n)}throw Error(l(156,t.tag))};function qf(e,t){return Gl(e,t)}function jv(e,t,n,o){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=o,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Pn(e,t,n,o){return new jv(e,t,n,o)}function Uu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Rv(e){if(typeof e=="function")return Uu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Lt)return 11;if(e===It)return 14}return 2}function Br(e,t){var n=e.alternate;return n===null?(n=Pn(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function za(e,t,n,o,a,c){var v=2;if(o=e,typeof e=="function")Uu(e)&&(v=1);else if(typeof e=="string")v=5;else e:switch(e){case pe:return ko(n.children,a,c,t);case vt:v=8,a|=8;break;case At:return e=Pn(12,n,t,a|2),e.elementType=At,e.lanes=c,e;case tt:return e=Pn(13,n,t,a),e.elementType=tt,e.lanes=c,e;case nt:return e=Pn(19,n,t,a),e.elementType=nt,e.lanes=c,e;case et:return Ha(n,a,c,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case _t:v=10;break e;case $t:v=9;break e;case Lt:v=11;break e;case It:v=14;break e;case ct:v=16,o=null;break e}throw Error(l(130,e==null?e:typeof e,""))}return t=Pn(v,n,t,a),t.elementType=e,t.type=o,t.lanes=c,t}function ko(e,t,n,o){return e=Pn(7,e,o,t),e.lanes=n,e}function Ha(e,t,n,o){return e=Pn(22,e,o,t),e.elementType=et,e.lanes=n,e.stateNode={isHidden:!1},e}function Ku(e,t,n){return e=Pn(6,e,null,t),e.lanes=n,e}function Qu(e,t,n){return t=Pn(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function kv(e,t,n,o,a){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Gi(0),this.expirationTimes=Gi(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Gi(0),this.identifierPrefix=o,this.onRecoverableError=a,this.mutableSourceEagerHydrationData=null}function Xu(e,t,n,o,a,c,v,E,T){return e=new kv(e,t,n,E,T),t===1?(t=1,c===!0&&(t|=8)):t=0,c=Pn(3,null,null,t),e.current=c,c.stateNode=e,c.memoizedState={element:o,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},su(c),e}function Tv(e,t,n){var o=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(r)}catch(i){console.error(i)}}return r(),tc.exports=Dv(),tc.exports}var cp;function Bv(){if(cp)return Xa;cp=1;var r=lm();return Xa.createRoot=r.createRoot,Xa.hydrateRoot=r.hydrateRoot,Xa}var zv=Bv();const Hv=Ni(zv),am=S.createContext(void 0),Pt=()=>{const r=S.useContext(am);if(!r)throw new Error("Must be used in the AppProvider");return r},Gv="https://jg-advancedgarages/",Jt=async(r,i,l)=>{const u=async(d,p)=>{try{const C=await(await fetch((l||Gv)+r,{method:"POST",headers:{"Content-Type":"application/json; charset=UTF-8"},body:i?JSON.stringify(i):void 0})).json();typeof C=="object"&&C.error&&p({error:!0,reason:C.error}),d(C)}catch(m){p(m)}};return await new Promise(u)};var oc={exports:{}};/*! + Copyright (c) 2018 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/var dp;function Vv(){return dp||(dp=1,function(r){(function(){var i={}.hasOwnProperty;function l(){for(var p="",m=0;m1?P-1:0),I=1;I{p.target===r&&(d(),i(p))},l+u)}function Cl(...r){return r.filter(i=>i!=null).reduce((i,l)=>{if(typeof l!="function")throw new Error("Invalid Argument Type, must only provide functions, undefined, or null.");return i===null?l:function(...d){i.apply(this,d),l.apply(this,d)}},null)}function vm(r){r.offsetHeight}const yp=r=>!r||typeof r=="function"?r:i=>{r.current=i};function hg(r,i){const l=yp(r),u=yp(i);return d=>{l&&l(d),u&&u(d)}}function Al(r,i){return S.useMemo(()=>hg(r,i),[r,i])}function vg(r){return r&&"setState"in r?Ri.findDOMNode(r):r??null}const gm=tr.forwardRef(({onEnter:r,onEntering:i,onEntered:l,onExit:u,onExiting:d,onExited:p,addEndListener:m,children:C,childRef:R,...g},P)=>{const O=S.useRef(null),I=Al(O,R),Q=K=>{I(vg(K))},z=K=>pe=>{K&&O.current&&K(O.current,pe)},J=S.useCallback(z(r),[r]),V=S.useCallback(z(i),[i]),ce=S.useCallback(z(l),[l]),oe=S.useCallback(z(u),[u]),se=S.useCallback(z(d),[d]),He=S.useCallback(z(p),[p]),D=S.useCallback(z(m),[m]);return f.jsx(Sr,{ref:P,...g,onEnter:J,onEntered:ce,onEntering:V,onExit:oe,onExited:He,onExiting:se,addEndListener:D,nodeRef:O,children:typeof C=="function"?(K,pe)=>C(K,{...pe,ref:Q}):tr.cloneElement(C,{ref:Q})})}),gg={height:["marginTop","marginBottom"],width:["marginLeft","marginRight"]};function yg(r,i){const l=`offset${r[0].toUpperCase()}${r.slice(1)}`,u=i[l],d=gg[r];return u+parseInt(yr(i,d[0]),10)+parseInt(yr(i,d[1]),10)}const wg={[Hr]:"collapse",[ts]:"collapsing",[vr]:"collapsing",[Gr]:"collapse show"},xg=tr.forwardRef(({onEnter:r,onEntering:i,onEntered:l,onExit:u,onExiting:d,className:p,children:m,dimension:C="height",in:R=!1,timeout:g=300,mountOnEnter:P=!1,unmountOnExit:O=!1,appear:I=!1,getDimensionValue:Q=yg,...z},J)=>{const V=typeof C=="function"?C():C,ce=S.useMemo(()=>Cl(K=>{K.style[V]="0"},r),[V,r]),oe=S.useMemo(()=>Cl(K=>{const pe=`scroll${V[0].toUpperCase()}${V.slice(1)}`;K.style[V]=`${K[pe]}px`},i),[V,i]),se=S.useMemo(()=>Cl(K=>{K.style[V]=null},l),[V,l]),He=S.useMemo(()=>Cl(K=>{K.style[V]=`${Q(V,K)}px`,vm(K)},u),[u,Q,V]),D=S.useMemo(()=>Cl(K=>{K.style[V]=null},d),[V,d]);return f.jsx(gm,{ref:J,addEndListener:hm,...z,"aria-expanded":z.role?R:null,onEnter:ce,onEntering:oe,onEntered:se,onExit:He,onExiting:D,childRef:m.ref,in:R,timeout:g,mountOnEnter:P,unmountOnExit:O,appear:I,children:(K,pe)=>tr.cloneElement(m,{...pe,className:_e(p,m.props.className,wg[K],V==="width"&&"collapse-horizontal")})})});function ym(r,i){return Array.isArray(r)?r.includes(i):r===i}const Ll=S.createContext({});Ll.displayName="AccordionContext";const Fc=S.forwardRef(({as:r="div",bsPrefix:i,className:l,children:u,eventKey:d,...p},m)=>{const{activeEventKey:C}=S.useContext(Ll);return i=ze(i,"accordion-collapse"),f.jsx(xg,{ref:m,in:ym(C,d),...p,className:_e(l,i),children:f.jsx(r,{children:S.Children.only(u)})})});Fc.displayName="AccordionCollapse";const ss=S.createContext({eventKey:""});ss.displayName="AccordionItemContext";const Ac=S.forwardRef(({as:r="div",bsPrefix:i,className:l,onEnter:u,onEntering:d,onEntered:p,onExit:m,onExiting:C,onExited:R,...g},P)=>{i=ze(i,"accordion-body");const{eventKey:O}=S.useContext(ss);return f.jsx(Fc,{eventKey:O,onEnter:u,onEntering:d,onEntered:p,onExit:m,onExiting:C,onExited:R,children:f.jsx(r,{ref:P,...g,className:_e(l,i)})})});Ac.displayName="AccordionBody";function Sg(r,i){const{activeEventKey:l,onSelect:u,alwaysOpen:d}=S.useContext(Ll);return p=>{let m=r===l?null:r;d&&(Array.isArray(l)?l.includes(r)?m=l.filter(C=>C!==r):m=[...l,r]:m=[r]),u==null||u(m,p),i==null||i(p)}}const Lc=S.forwardRef(({as:r="button",bsPrefix:i,className:l,onClick:u,...d},p)=>{i=ze(i,"accordion-button");const{eventKey:m}=S.useContext(ss),C=Sg(m,u),{activeEventKey:R}=S.useContext(Ll);return r==="button"&&(d.type="button"),f.jsx(r,{ref:p,onClick:C,...d,"aria-expanded":Array.isArray(R)?R.includes(m):m===R,className:_e(l,i,!ym(R,m)&&"collapsed")})});Lc.displayName="AccordionButton";const wm=S.forwardRef(({as:r="h2",bsPrefix:i,className:l,children:u,onClick:d,...p},m)=>(i=ze(i,"accordion-header"),f.jsx(r,{ref:m,...p,className:_e(l,i),children:f.jsx(Lc,{onClick:d,children:u})})));wm.displayName="AccordionHeader";const xm=S.forwardRef(({as:r="div",bsPrefix:i,className:l,eventKey:u,...d},p)=>{i=ze(i,"accordion-item");const m=S.useMemo(()=>({eventKey:u}),[u]);return f.jsx(ss.Provider,{value:m,children:f.jsx(r,{ref:p,...d,className:_e(l,i)})})});xm.displayName="AccordionItem";const Sm=S.forwardRef((r,i)=>{const{as:l="div",activeKey:u,bsPrefix:d,className:p,onSelect:m,flush:C,alwaysOpen:R,...g}=um(r,{activeKey:"onSelect"}),P=ze(d,"accordion"),O=S.useMemo(()=>({activeEventKey:u,onSelect:m,alwaysOpen:R}),[u,m,R]);return f.jsx(Ll.Provider,{value:O,children:f.jsx(l,{ref:i,...g,className:_e(p,P,C&&`${P}-flush`)})})});Sm.displayName="Accordion";const _l=Object.assign(Sm,{Button:Lc,Collapse:Fc,Item:xm,Header:wm,Body:Ac});function Cg(r){const i=S.useRef(r);return S.useEffect(()=>{i.current=r},[r]),i}function On(r){const i=Cg(r);return S.useCallback(function(...l){return i.current&&i.current(...l)},[i])}const us=r=>S.forwardRef((i,l)=>f.jsx("div",{...i,ref:l,className:_e(i.className,r)})),Cm=us("h4");Cm.displayName="DivStyledAsH4";const Em=S.forwardRef(({className:r,bsPrefix:i,as:l=Cm,...u},d)=>(i=ze(i,"alert-heading"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Em.displayName="AlertHeading";function Eg(){return S.useState(null)}function jg(){const r=S.useRef(!0),i=S.useRef(()=>r.current);return S.useEffect(()=>(r.current=!0,()=>{r.current=!1}),[]),i.current}function Rg(r){const i=S.useRef(null);return S.useEffect(()=>{i.current=r}),i.current}const kg=typeof global<"u"&&global.navigator&&global.navigator.product==="ReactNative",Tg=typeof document<"u",wp=Tg||kg?S.useLayoutEffect:S.useEffect,_g=["as","disabled"];function Ng(r,i){if(r==null)return{};var l={},u=Object.keys(r),d,p;for(p=0;p=0)&&(l[d]=r[d]);return l}function Pg(r){return!r||r.trim()==="#"}function Mc({tagName:r,disabled:i,href:l,target:u,rel:d,role:p,onClick:m,tabIndex:C=0,type:R}){r||(l!=null||u!=null||d!=null?r="a":r="button");const g={tagName:r};if(r==="button")return[{type:R||"button",disabled:i},g];const P=I=>{if((i||r==="a"&&Pg(l))&&I.preventDefault(),i){I.stopPropagation();return}m==null||m(I)},O=I=>{I.key===" "&&(I.preventDefault(),P(I))};return r==="a"&&(l||(l="#"),i&&(l=void 0)),[{role:p??"button",disabled:void 0,tabIndex:i?void 0:C,href:l,target:r==="a"?u:void 0,"aria-disabled":i||void 0,rel:r==="a"?d:void 0,onClick:P,onKeyDown:O},g]}const Ig=S.forwardRef((r,i)=>{let{as:l,disabled:u}=r,d=Ng(r,_g);const[p,{tagName:m}]=Mc(Object.assign({tagName:l,disabled:u},d));return f.jsx(m,Object.assign({},d,p,{ref:i}))});Ig.displayName="Button";const Og=["onKeyDown"];function Fg(r,i){if(r==null)return{};var l={},u=Object.keys(r),d,p;for(p=0;p=0)&&(l[d]=r[d]);return l}function Ag(r){return!r||r.trim()==="#"}const jm=S.forwardRef((r,i)=>{let{onKeyDown:l}=r,u=Fg(r,Og);const[d]=Mc(Object.assign({tagName:"a"},u)),p=On(m=>{d.onKeyDown(m),l==null||l(m)});return Ag(u.href)||u.role==="button"?f.jsx("a",Object.assign({ref:i},u,d,{onKeyDown:p})):f.jsx("a",Object.assign({ref:i},u,{onKeyDown:l}))});jm.displayName="Anchor";const Rm=S.forwardRef(({className:r,bsPrefix:i,as:l=jm,...u},d)=>(i=ze(i,"alert-link"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Rm.displayName="AlertLink";const Lg={[vr]:"show",[Gr]:"show"},Nl=S.forwardRef(({className:r,children:i,transitionClasses:l={},onEnter:u,...d},p)=>{const m={in:!1,timeout:300,mountOnEnter:!1,unmountOnExit:!1,appear:!1,...d},C=S.useCallback((R,g)=>{vm(R),u==null||u(R,g)},[u]);return f.jsx(gm,{ref:p,addEndListener:hm,...m,onEnter:C,childRef:i.ref,children:(R,g)=>S.cloneElement(i,{...g,className:_e("fade",r,i.props.className,Lg[R],l[R])})})});Nl.displayName="Fade";const Mg={"aria-label":wr.string,onClick:wr.func,variant:wr.oneOf(["white"])},cs=S.forwardRef(({className:r,variant:i,"aria-label":l="Close",...u},d)=>f.jsx("button",{ref:d,type:"button",className:_e("btn-close",i&&`btn-close-${i}`,r),"aria-label":l,...u}));cs.displayName="CloseButton";cs.propTypes=Mg;const km=S.forwardRef((r,i)=>{const{bsPrefix:l,show:u=!0,closeLabel:d="Close alert",closeVariant:p,className:m,children:C,variant:R="primary",onClose:g,dismissible:P,transition:O=Nl,...I}=um(r,{show:"onClose"}),Q=ze(l,"alert"),z=On(ce=>{g&&g(!1,ce)}),J=O===!0?Nl:O,V=f.jsxs("div",{role:"alert",...J?void 0:I,ref:i,className:_e(m,Q,R&&`${Q}-${R}`,P&&`${Q}-dismissible`),children:[P&&f.jsx(cs,{onClick:z,"aria-label":d,variant:p}),C]});return J?f.jsx(J,{unmountOnExit:!0,...I,ref:void 0,in:u,children:V}):u?V:null});km.displayName="Alert";const bg=Object.assign(km,{Link:Rm,Heading:Em}),fn=S.forwardRef(({bsPrefix:r,bg:i="primary",pill:l=!1,text:u,className:d,as:p="span",...m},C)=>{const R=ze(r,"badge");return f.jsx(p,{ref:C,...m,className:_e(d,R,l&&"rounded-pill",u&&`text-${u}`,i&&`bg-${i}`)})});fn.displayName="Badge";const at=S.forwardRef(({as:r,bsPrefix:i,variant:l="primary",size:u,active:d=!1,disabled:p=!1,className:m,...C},R)=>{const g=ze(i,"btn"),[P,{tagName:O}]=Mc({tagName:r,disabled:p,...C}),I=O;return f.jsx(I,{...P,...C,ref:R,disabled:p,className:_e(m,g,d&&"active",l&&`${g}-${l}`,u&&`${g}-${u}`,C.href&&p&&"disabled")})});at.displayName="Button";const Tm=S.forwardRef(({bsPrefix:r,size:i,vertical:l=!1,className:u,role:d="group",as:p="div",...m},C)=>{const R=ze(r,"btn-group");let g=R;return l&&(g=`${R}-vertical`),f.jsx(p,{...m,ref:C,role:d,className:_e(u,g,i&&`${R}-${i}`)})});Tm.displayName="ButtonGroup";const bc=S.forwardRef(({className:r,bsPrefix:i,as:l="div",...u},d)=>(i=ze(i,"card-body"),f.jsx(l,{ref:d,className:_e(r,i),...u})));bc.displayName="CardBody";const _m=S.forwardRef(({className:r,bsPrefix:i,as:l="div",...u},d)=>(i=ze(i,"card-footer"),f.jsx(l,{ref:d,className:_e(r,i),...u})));_m.displayName="CardFooter";const Nm=S.createContext(null);Nm.displayName="CardHeaderContext";const Pm=S.forwardRef(({bsPrefix:r,className:i,as:l="div",...u},d)=>{const p=ze(r,"card-header"),m=S.useMemo(()=>({cardHeaderBsPrefix:p}),[p]);return f.jsx(Nm.Provider,{value:m,children:f.jsx(l,{ref:d,...u,className:_e(i,p)})})});Pm.displayName="CardHeader";const Im=S.forwardRef(({bsPrefix:r,className:i,variant:l,as:u="img",...d},p)=>{const m=ze(r,"card-img");return f.jsx(u,{ref:p,className:_e(l?`${m}-${l}`:m,i),...d})});Im.displayName="CardImg";const Om=S.forwardRef(({className:r,bsPrefix:i,as:l="div",...u},d)=>(i=ze(i,"card-img-overlay"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Om.displayName="CardImgOverlay";const Fm=S.forwardRef(({className:r,bsPrefix:i,as:l="a",...u},d)=>(i=ze(i,"card-link"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Fm.displayName="CardLink";const $g=us("h6"),Am=S.forwardRef(({className:r,bsPrefix:i,as:l=$g,...u},d)=>(i=ze(i,"card-subtitle"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Am.displayName="CardSubtitle";const Lm=S.forwardRef(({className:r,bsPrefix:i,as:l="p",...u},d)=>(i=ze(i,"card-text"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Lm.displayName="CardText";const Dg=us("h5"),Mm=S.forwardRef(({className:r,bsPrefix:i,as:l=Dg,...u},d)=>(i=ze(i,"card-title"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Mm.displayName="CardTitle";const bm=S.forwardRef(({bsPrefix:r,className:i,bg:l,text:u,border:d,body:p=!1,children:m,as:C="div",...R},g)=>{const P=ze(r,"card");return f.jsx(C,{ref:g,...R,className:_e(i,P,l&&`bg-${l}`,u&&`text-${u}`,d&&`border-${d}`),children:p?f.jsx(bc,{children:m}):m})});bm.displayName="Card";const Vr=Object.assign(bm,{Img:Im,Title:Mm,Subtitle:Am,Body:bc,Link:Fm,Text:Lm,Header:Pm,Footer:_m,ImgOverlay:Om});function Bg(r){const i=S.useRef(r);return i.current=r,i}function $m(r){const i=Bg(r);S.useEffect(()=>()=>i.current(),[])}function zg(r,i){let l=0;return S.Children.map(r,u=>S.isValidElement(u)?i(u,l++):u)}function Hg(r,i){return S.Children.toArray(r).some(l=>S.isValidElement(l)&&l.type===i)}function Gg({as:r,bsPrefix:i,className:l,...u}){i=ze(i,"col");const d=cm(),p=dm(),m=[],C=[];return d.forEach(R=>{const g=u[R];delete u[R];let P,O,I;typeof g=="object"&&g!=null?{span:P,offset:O,order:I}=g:P=g;const Q=R!==p?`-${R}`:"";P&&m.push(P===!0?`${i}${Q}`:`${i}${Q}-${P}`),I!=null&&C.push(`order${Q}-${I}`),O!=null&&C.push(`offset${Q}-${O}`)}),[{...u,className:_e(l,...m,...C)},{as:r,bsPrefix:i,spans:m}]}const ki=S.forwardRef((r,i)=>{const[{className:l,...u},{as:d="div",bsPrefix:p,spans:m}]=Gg(r);return f.jsx(d,{...u,ref:i,className:_e(l,!m.length&&p)})});ki.displayName="Col";var Vg=Function.prototype.bind.call(Function.prototype.call,[].slice);function Ei(r,i){return Vg(r.querySelectorAll(i))}function xp(r,i){if(r.contains)return r.contains(i);if(r.compareDocumentPosition)return r===i||!!(r.compareDocumentPosition(i)&16)}const Wg="data-rr-ui-";function Ug(r){return`${Wg}${r}`}const Dm=S.createContext(Pi?window:void 0);Dm.Provider;function $c(){return S.useContext(Dm)}const Bm=S.createContext(null);Bm.displayName="InputGroupContext";const Kg={type:wr.string,tooltip:wr.bool,as:wr.elementType},ds=S.forwardRef(({as:r="div",className:i,type:l="valid",tooltip:u=!1,...d},p)=>f.jsx(r,{...d,ref:p,className:_e(i,`${l}-${u?"tooltip":"feedback"}`)}));ds.displayName="Feedback";ds.propTypes=Kg;const xr=S.createContext({}),Ml=S.forwardRef(({id:r,bsPrefix:i,className:l,type:u="checkbox",isValid:d=!1,isInvalid:p=!1,as:m="input",...C},R)=>{const{controlId:g}=S.useContext(xr);return i=ze(i,"form-check-input"),f.jsx(m,{...C,ref:R,type:u,id:r||g,className:_e(l,i,d&&"is-valid",p&&"is-invalid")})});Ml.displayName="FormCheckInput";const rs=S.forwardRef(({bsPrefix:r,className:i,htmlFor:l,...u},d)=>{const{controlId:p}=S.useContext(xr);return r=ze(r,"form-check-label"),f.jsx("label",{...u,ref:d,htmlFor:l||p,className:_e(i,r)})});rs.displayName="FormCheckLabel";const zm=S.forwardRef(({id:r,bsPrefix:i,bsSwitchPrefix:l,inline:u=!1,reverse:d=!1,disabled:p=!1,isValid:m=!1,isInvalid:C=!1,feedbackTooltip:R=!1,feedback:g,feedbackType:P,className:O,style:I,title:Q="",type:z="checkbox",label:J,children:V,as:ce="input",...oe},se)=>{i=ze(i,"form-check"),l=ze(l,"form-switch");const{controlId:He}=S.useContext(xr),D=S.useMemo(()=>({controlId:r||He}),[He,r]),K=!V&&J!=null&&J!==!1||Hg(V,rs),pe=f.jsx(Ml,{...oe,type:z==="switch"?"checkbox":z,ref:se,isValid:m,isInvalid:C,disabled:p,as:ce});return f.jsx(xr.Provider,{value:D,children:f.jsx("div",{style:I,className:_e(O,K&&i,u&&`${i}-inline`,d&&`${i}-reverse`,z==="switch"&&l),children:V||f.jsxs(f.Fragment,{children:[pe,K&&f.jsx(rs,{title:Q,children:J}),g&&f.jsx(ds,{type:P,tooltip:R,children:g})]})})})});zm.displayName="FormCheck";const os=Object.assign(zm,{Input:Ml,Label:rs}),Hm=S.forwardRef(({bsPrefix:r,type:i,size:l,htmlSize:u,id:d,className:p,isValid:m=!1,isInvalid:C=!1,plaintext:R,readOnly:g,as:P="input",...O},I)=>{const{controlId:Q}=S.useContext(xr);return r=ze(r,"form-control"),f.jsx(P,{...O,type:i,size:u,ref:I,readOnly:g,id:d||Q,className:_e(p,R?`${r}-plaintext`:r,l&&`${r}-${l}`,i==="color"&&`${r}-color`,m&&"is-valid",C&&"is-invalid")})});Hm.displayName="FormControl";const Qg=Object.assign(Hm,{Feedback:ds}),Gm=S.forwardRef(({className:r,bsPrefix:i,as:l="div",...u},d)=>(i=ze(i,"form-floating"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Gm.displayName="FormFloating";const Dc=S.forwardRef(({controlId:r,as:i="div",...l},u)=>{const d=S.useMemo(()=>({controlId:r}),[r]);return f.jsx(xr.Provider,{value:d,children:f.jsx(i,{...l,ref:u})})});Dc.displayName="FormGroup";const Vm=S.forwardRef(({as:r="label",bsPrefix:i,column:l=!1,visuallyHidden:u=!1,className:d,htmlFor:p,...m},C)=>{const{controlId:R}=S.useContext(xr);i=ze(i,"form-label");let g="col-form-label";typeof l=="string"&&(g=`${g} ${g}-${l}`);const P=_e(d,i,u&&"visually-hidden",l&&g);return p=p||R,l?f.jsx(ki,{ref:C,as:"label",className:P,htmlFor:p,...m}):f.jsx(r,{ref:C,className:P,htmlFor:p,...m})});Vm.displayName="FormLabel";const Wm=S.forwardRef(({bsPrefix:r,className:i,id:l,...u},d)=>{const{controlId:p}=S.useContext(xr);return r=ze(r,"form-range"),f.jsx("input",{...u,type:"range",ref:d,className:_e(i,r),id:l||p})});Wm.displayName="FormRange";const Um=S.forwardRef(({bsPrefix:r,size:i,htmlSize:l,className:u,isValid:d=!1,isInvalid:p=!1,id:m,...C},R)=>{const{controlId:g}=S.useContext(xr);return r=ze(r,"form-select"),f.jsx("select",{...C,size:l,ref:R,className:_e(u,r,i&&`${r}-${i}`,d&&"is-valid",p&&"is-invalid"),id:m||g})});Um.displayName="FormSelect";const Km=S.forwardRef(({bsPrefix:r,className:i,as:l="small",muted:u,...d},p)=>(r=ze(r,"form-text"),f.jsx(l,{...d,ref:p,className:_e(i,r,u&&"text-muted")})));Km.displayName="FormText";const Qm=S.forwardRef((r,i)=>f.jsx(os,{...r,ref:i,type:"switch"}));Qm.displayName="Switch";const Xg=Object.assign(Qm,{Input:os.Input,Label:os.Label}),Xm=S.forwardRef(({bsPrefix:r,className:i,children:l,controlId:u,label:d,...p},m)=>(r=ze(r,"form-floating"),f.jsxs(Dc,{ref:m,className:_e(i,r),controlId:u,...p,children:[l,f.jsx("label",{htmlFor:u,children:d})]})));Xm.displayName="FloatingLabel";const qg={_ref:wr.any,validated:wr.bool,as:wr.elementType},Bc=S.forwardRef(({className:r,validated:i,as:l="form",...u},d)=>f.jsx(l,{...u,ref:d,className:_e(r,i&&"was-validated")}));Bc.displayName="Form";Bc.propTypes=qg;const De=Object.assign(Bc,{Group:Dc,Control:Qg,Floating:Gm,Check:os,Switch:Xg,Label:Vm,Text:Km,Range:Wm,Select:Um,FloatingLabel:Xm}),fs=S.forwardRef(({className:r,bsPrefix:i,as:l="span",...u},d)=>(i=ze(i,"input-group-text"),f.jsx(l,{ref:d,className:_e(r,i),...u})));fs.displayName="InputGroupText";const Yg=r=>f.jsx(fs,{children:f.jsx(Ml,{type:"checkbox",...r})}),Jg=r=>f.jsx(fs,{children:f.jsx(Ml,{type:"radio",...r})}),qm=S.forwardRef(({bsPrefix:r,size:i,hasValidation:l,className:u,as:d="div",...p},m)=>{r=ze(r,"input-group");const C=S.useMemo(()=>({}),[]);return f.jsx(Bm.Provider,{value:C,children:f.jsx(d,{ref:m,...p,className:_e(u,r,i&&`${r}-${i}`,l&&"has-validation")})})});qm.displayName="InputGroup";const Po=Object.assign(qm,{Text:fs,Radio:Jg,Checkbox:Yg});var Ya;function Sp(r){if((!Ya&&Ya!==0||r)&&Pi){var i=document.createElement("div");i.style.position="absolute",i.style.top="-9999px",i.style.width="50px",i.style.height="50px",i.style.overflow="scroll",document.body.appendChild(i),Ya=i.offsetWidth-i.clientWidth,document.body.removeChild(i)}return Ya}function uc(r){r===void 0&&(r=as());try{var i=r.activeElement;return!i||!i.nodeName?null:i}catch{return r.body}}function Zg(r=document){const i=r.defaultView;return Math.abs(i.innerWidth-r.documentElement.clientWidth)}const Cp=Ug("modal-open");class zc{constructor({ownerDocument:i,handleContainerOverflow:l=!0,isRTL:u=!1}={}){this.handleContainerOverflow=l,this.isRTL=u,this.modals=[],this.ownerDocument=i}getScrollbarWidth(){return Zg(this.ownerDocument)}getElement(){return(this.ownerDocument||document).body}setModalAttributes(i){}removeModalAttributes(i){}setContainerStyle(i){const l={overflow:"hidden"},u=this.isRTL?"paddingLeft":"paddingRight",d=this.getElement();i.style={overflow:d.style.overflow,[u]:d.style[u]},i.scrollBarWidth&&(l[u]=`${parseInt(yr(d,u)||"0",10)+i.scrollBarWidth}px`),d.setAttribute(Cp,""),yr(d,l)}reset(){[...this.modals].forEach(i=>this.remove(i))}removeContainerStyle(i){const l=this.getElement();l.removeAttribute(Cp),Object.assign(l.style,i.style)}add(i){let l=this.modals.indexOf(i);return l!==-1||(l=this.modals.length,this.modals.push(i),this.setModalAttributes(i),l!==0)||(this.state={scrollBarWidth:this.getScrollbarWidth(),style:{}},this.handleContainerOverflow&&this.setContainerStyle(this.state)),l}remove(i){const l=this.modals.indexOf(i);l!==-1&&(this.modals.splice(l,1),!this.modals.length&&this.handleContainerOverflow&&this.removeContainerStyle(this.state),this.removeModalAttributes(i))}isTopModal(i){return!!this.modals.length&&this.modals[this.modals.length-1]===i}}const cc=(r,i)=>Pi?r==null?(i||as()).body:(typeof r=="function"&&(r=r()),r&&"current"in r&&(r=r.current),r&&("nodeType"in r||r.getBoundingClientRect)?r:null):null;function ey(r,i){const l=$c(),[u,d]=S.useState(()=>cc(r,l==null?void 0:l.document));if(!u){const p=cc(r);p&&d(p)}return S.useEffect(()=>{},[i,u]),S.useEffect(()=>{const p=cc(r);p!==u&&d(p)},[r,u]),u}function ty({children:r,in:i,onExited:l,mountOnEnter:u,unmountOnExit:d}){const p=S.useRef(null),m=S.useRef(i),C=On(l);S.useEffect(()=>{i?m.current=!0:C(p.current)},[i,C]);const R=Al(p,r.ref),g=S.cloneElement(r,{ref:R});return i?g:d||!m.current&&u?null:g}function ny(r){return r.code==="Escape"||r.keyCode===27}function ry(){const r=S.version.split(".");return{major:+r[0],minor:+r[1],patch:+r[2]}}const oy=["onEnter","onEntering","onEntered","onExit","onExiting","onExited","addEndListener","children"];function iy(r,i){if(r==null)return{};var l={},u=Object.keys(r),d,p;for(p=0;p=0)&&(l[d]=r[d]);return l}function ly(r){let{onEnter:i,onEntering:l,onEntered:u,onExit:d,onExiting:p,onExited:m,addEndListener:C,children:R}=r,g=iy(r,oy);const{major:P}=ry(),O=P>=19?R.props.ref:R.ref,I=S.useRef(null),Q=Al(I,typeof R=="function"?null:O),z=K=>pe=>{K&&I.current&&K(I.current,pe)},J=S.useCallback(z(i),[i]),V=S.useCallback(z(l),[l]),ce=S.useCallback(z(u),[u]),oe=S.useCallback(z(d),[d]),se=S.useCallback(z(p),[p]),He=S.useCallback(z(m),[m]),D=S.useCallback(z(C),[C]);return Object.assign({},g,{nodeRef:I},i&&{onEnter:J},l&&{onEntering:V},u&&{onEntered:ce},d&&{onExit:oe},p&&{onExiting:se},m&&{onExited:He},C&&{addEndListener:D},{children:typeof R=="function"?(K,pe)=>R(K,Object.assign({},pe,{ref:Q})):S.cloneElement(R,{ref:Q})})}const ay=["component"];function sy(r,i){if(r==null)return{};var l={},u=Object.keys(r),d,p;for(p=0;p=0)&&(l[d]=r[d]);return l}const uy=S.forwardRef((r,i)=>{let{component:l}=r,u=sy(r,ay);const d=ly(u);return f.jsx(l,Object.assign({ref:i},d))});function cy({in:r,onTransition:i}){const l=S.useRef(null),u=S.useRef(!0),d=On(i);return wp(()=>{if(!l.current)return;let p=!1;return d({in:r,element:l.current,initial:u.current,isStale:()=>p}),()=>{p=!0}},[r,d]),wp(()=>(u.current=!1,()=>{u.current=!0}),[]),l}function dy({children:r,in:i,onExited:l,onEntered:u,transition:d}){const[p,m]=S.useState(!i);i&&p&&m(!1);const C=cy({in:!!i,onTransition:g=>{const P=()=>{g.isStale()||(g.in?u==null||u(g.element,g.initial):(m(!0),l==null||l(g.element)))};Promise.resolve(d(g)).then(P,O=>{throw g.in||m(!0),O})}}),R=Al(C,r.ref);return p&&!i?null:S.cloneElement(r,{ref:R})}function Ep(r,i,l){return r?f.jsx(uy,Object.assign({},l,{component:r})):i?f.jsx(dy,Object.assign({},l,{transition:i})):f.jsx(ty,Object.assign({},l))}const fy=["show","role","className","style","children","backdrop","keyboard","onBackdropClick","onEscapeKeyDown","transition","runTransition","backdropTransition","runBackdropTransition","autoFocus","enforceFocus","restoreFocus","restoreFocusOptions","renderDialog","renderBackdrop","manager","container","onShow","onHide","onExit","onExited","onExiting","onEnter","onEntering","onEntered"];function py(r,i){if(r==null)return{};var l={},u=Object.keys(r),d,p;for(p=0;p=0)&&(l[d]=r[d]);return l}let dc;function my(r){return dc||(dc=new zc({ownerDocument:r==null?void 0:r.document})),dc}function hy(r){const i=$c(),l=r||my(i),u=S.useRef({dialog:null,backdrop:null});return Object.assign(u.current,{add:()=>l.add(u.current),remove:()=>l.remove(u.current),isTopModal:()=>l.isTopModal(u.current),setDialogRef:S.useCallback(d=>{u.current.dialog=d},[]),setBackdropRef:S.useCallback(d=>{u.current.backdrop=d},[])})}const Ym=S.forwardRef((r,i)=>{let{show:l=!1,role:u="dialog",className:d,style:p,children:m,backdrop:C=!0,keyboard:R=!0,onBackdropClick:g,onEscapeKeyDown:P,transition:O,runTransition:I,backdropTransition:Q,runBackdropTransition:z,autoFocus:J=!0,enforceFocus:V=!0,restoreFocus:ce=!0,restoreFocusOptions:oe,renderDialog:se,renderBackdrop:He=lt=>f.jsx("div",Object.assign({},lt)),manager:D,container:K,onShow:pe,onHide:vt=()=>{},onExit:At,onExited:_t,onExiting:$t,onEnter:Lt,onEntering:tt,onEntered:nt}=r,It=py(r,fy);const ct=$c(),et=ey(K),X=hy(D),Ce=jg(),le=Rg(l),[N,H]=S.useState(!l),Re=S.useRef(null);S.useImperativeHandle(i,()=>X,[X]),Pi&&!le&&l&&(Re.current=uc(ct==null?void 0:ct.document)),l&&N&&H(!1);const Ne=On(()=>{if(X.add(),gt.current=ns(document,"keydown",Ke),Ze.current=ns(document,"focus",()=>setTimeout(Ve),!0),pe&&pe(),J){var lt,Fn;const mn=uc((lt=(Fn=X.dialog)==null?void 0:Fn.ownerDocument)!=null?lt:ct==null?void 0:ct.document);X.dialog&&mn&&!xp(X.dialog,mn)&&(Re.current=mn,X.dialog.focus())}}),Me=On(()=>{if(X.remove(),gt.current==null||gt.current(),Ze.current==null||Ze.current(),ce){var lt;(lt=Re.current)==null||lt.focus==null||lt.focus(oe),Re.current=null}});S.useEffect(()=>{!l||!et||Ne()},[l,et,Ne]),S.useEffect(()=>{N&&Me()},[N,Me]),$m(()=>{Me()});const Ve=On(()=>{if(!V||!Ce()||!X.isTopModal())return;const lt=uc(ct==null?void 0:ct.document);X.dialog&<&&!xp(X.dialog,lt)&&X.dialog.focus()}),qe=On(lt=>{lt.target===lt.currentTarget&&(g==null||g(lt),C===!0&&vt())}),Ke=On(lt=>{R&&ny(lt)&&X.isTopModal()&&(P==null||P(lt),lt.defaultPrevented||vt())}),Ze=S.useRef(),gt=S.useRef(),Zt=(...lt)=>{H(!0),_t==null||_t(...lt)};if(!et)return null;const pn=Object.assign({role:u,ref:X.setDialogRef,"aria-modal":u==="dialog"?!0:void 0},It,{style:p,className:d,tabIndex:-1});let Kt=se?se(pn):f.jsx("div",Object.assign({},pn,{children:S.cloneElement(m,{role:"document"})}));Kt=Ep(O,I,{unmountOnExit:!0,mountOnEnter:!0,appear:!0,in:!!l,onExit:At,onExiting:$t,onExited:Zt,onEnter:Lt,onEntering:tt,onEntered:nt,children:Kt});let nn=null;return C&&(nn=He({ref:X.setBackdropRef,onClick:qe}),nn=Ep(Q,z,{in:!!l,appear:!0,mountOnEnter:!0,unmountOnExit:!0,children:nn})),f.jsx(f.Fragment,{children:Ri.createPortal(f.jsxs(f.Fragment,{children:[nn,Kt]}),et)})});Ym.displayName="Modal";const vy=Object.assign(Ym,{Manager:zc});function gy(r,i){return r.classList?r.classList.contains(i):(" "+(r.className.baseVal||r.className)+" ").indexOf(" "+i+" ")!==-1}function yy(r,i){r.classList?r.classList.add(i):gy(r,i)||(typeof r.className=="string"?r.className=r.className+" "+i:r.setAttribute("class",(r.className&&r.className.baseVal||"")+" "+i))}function jp(r,i){return r.replace(new RegExp("(^|\\s)"+i+"(?:\\s|$)","g"),"$1").replace(/\s+/g," ").replace(/^\s*|\s*$/g,"")}function wy(r,i){r.classList?r.classList.remove(i):typeof r.className=="string"?r.className=jp(r.className,i):r.setAttribute("class",jp(r.className&&r.className.baseVal||"",i))}const ji={FIXED_CONTENT:".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",STICKY_CONTENT:".sticky-top",NAVBAR_TOGGLER:".navbar-toggler"};class xy extends zc{adjustAndStore(i,l,u){const d=l.style[i];l.dataset[i]=d,yr(l,{[i]:`${parseFloat(yr(l,i))+u}px`})}restore(i,l){const u=l.dataset[i];u!==void 0&&(delete l.dataset[i],yr(l,{[i]:u}))}setContainerStyle(i){super.setContainerStyle(i);const l=this.getElement();if(yy(l,"modal-open"),!i.scrollBarWidth)return;const u=this.isRTL?"paddingLeft":"paddingRight",d=this.isRTL?"marginLeft":"marginRight";Ei(l,ji.FIXED_CONTENT).forEach(p=>this.adjustAndStore(u,p,i.scrollBarWidth)),Ei(l,ji.STICKY_CONTENT).forEach(p=>this.adjustAndStore(d,p,-i.scrollBarWidth)),Ei(l,ji.NAVBAR_TOGGLER).forEach(p=>this.adjustAndStore(d,p,i.scrollBarWidth))}removeContainerStyle(i){super.removeContainerStyle(i);const l=this.getElement();wy(l,"modal-open");const u=this.isRTL?"paddingLeft":"paddingRight",d=this.isRTL?"marginLeft":"marginRight";Ei(l,ji.FIXED_CONTENT).forEach(p=>this.restore(u,p)),Ei(l,ji.STICKY_CONTENT).forEach(p=>this.restore(d,p)),Ei(l,ji.NAVBAR_TOGGLER).forEach(p=>this.restore(d,p))}}let fc;function Sy(r){return fc||(fc=new xy(r)),fc}const Jm=S.forwardRef(({className:r,bsPrefix:i,as:l="div",...u},d)=>(i=ze(i,"modal-body"),f.jsx(l,{ref:d,className:_e(r,i),...u})));Jm.displayName="ModalBody";const Zm=S.createContext({onHide(){}}),Hc=S.forwardRef(({bsPrefix:r,className:i,contentClassName:l,centered:u,size:d,fullscreen:p,children:m,scrollable:C,...R},g)=>{r=ze(r,"modal");const P=`${r}-dialog`,O=typeof p=="string"?`${r}-fullscreen-${p}`:`${r}-fullscreen`;return f.jsx("div",{...R,ref:g,className:_e(P,i,d&&`${r}-${d}`,u&&`${P}-centered`,C&&`${P}-scrollable`,p&&O),children:f.jsx("div",{className:_e(`${r}-content`,l),children:m})})});Hc.displayName="ModalDialog";const eh=S.forwardRef(({className:r,bsPrefix:i,as:l="div",...u},d)=>(i=ze(i,"modal-footer"),f.jsx(l,{ref:d,className:_e(r,i),...u})));eh.displayName="ModalFooter";const Cy=S.forwardRef(({closeLabel:r="Close",closeVariant:i,closeButton:l=!1,onHide:u,children:d,...p},m)=>{const C=S.useContext(Zm),R=On(()=>{C==null||C.onHide(),u==null||u()});return f.jsxs("div",{ref:m,...p,children:[d,l&&f.jsx(cs,{"aria-label":r,variant:i,onClick:R})]})}),th=S.forwardRef(({bsPrefix:r,className:i,closeLabel:l="Close",closeButton:u=!1,...d},p)=>(r=ze(r,"modal-header"),f.jsx(Cy,{ref:p,...d,className:_e(i,r),closeLabel:l,closeButton:u})));th.displayName="ModalHeader";const Ey=us("h4"),nh=S.forwardRef(({className:r,bsPrefix:i,as:l=Ey,...u},d)=>(i=ze(i,"modal-title"),f.jsx(l,{ref:d,className:_e(r,i),...u})));nh.displayName="ModalTitle";function jy(r){return f.jsx(Nl,{...r,timeout:null})}function Ry(r){return f.jsx(Nl,{...r,timeout:null})}const rh=S.forwardRef(({bsPrefix:r,className:i,style:l,dialogClassName:u,contentClassName:d,children:p,dialogAs:m=Hc,"data-bs-theme":C,"aria-labelledby":R,"aria-describedby":g,"aria-label":P,show:O=!1,animation:I=!0,backdrop:Q=!0,keyboard:z=!0,onEscapeKeyDown:J,onShow:V,onHide:ce,container:oe,autoFocus:se=!0,enforceFocus:He=!0,restoreFocus:D=!0,restoreFocusOptions:K,onEntered:pe,onExit:vt,onExiting:At,onEnter:_t,onEntering:$t,onExited:Lt,backdropClassName:tt,manager:nt,...It},ct)=>{const[et,X]=S.useState({}),[Ce,le]=S.useState(!1),N=S.useRef(!1),H=S.useRef(!1),Re=S.useRef(null),[Ne,Me]=Eg(),Ve=Al(ct,Me),qe=On(ce),Ke=Jv();r=ze(r,"modal");const Ze=S.useMemo(()=>({onHide:qe}),[qe]);function gt(){return nt||Sy({isRTL:Ke})}function Zt(ue){if(!Pi)return;const Ge=gt().getScrollbarWidth()>0,dt=ue.scrollHeight>as(ue).documentElement.clientHeight;X({paddingRight:Ge&&!dt?Sp():void 0,paddingLeft:!Ge&&dt?Sp():void 0})}const pn=On(()=>{Ne&&Zt(Ne.dialog)});$m(()=>{Rc(window,"resize",pn),Re.current==null||Re.current()});const Kt=()=>{N.current=!0},nn=ue=>{N.current&&Ne&&ue.target===Ne.dialog&&(H.current=!0),N.current=!1},lt=()=>{le(!0),Re.current=mm(Ne.dialog,()=>{le(!1)})},Fn=ue=>{ue.target===ue.currentTarget&<()},mn=ue=>{if(Q==="static"){Fn(ue);return}if(H.current||ue.target!==ue.currentTarget){H.current=!1;return}ce==null||ce()},Er=ue=>{z?J==null||J(ue):(ue.preventDefault(),Q==="static"&<())},An=(ue,Ge)=>{ue&&Zt(ue),_t==null||_t(ue,Ge)},Ln=ue=>{Re.current==null||Re.current(),vt==null||vt(ue)},Cn=(ue,Ge)=>{$t==null||$t(ue,Ge),pm(window,"resize",pn)},M=ue=>{ue&&(ue.style.display=""),Lt==null||Lt(ue),Rc(window,"resize",pn)},de=S.useCallback(ue=>f.jsx("div",{...ue,className:_e(`${r}-backdrop`,tt,!I&&"show")}),[I,tt,r]),ve={...l,...et};ve.display="block";const je=ue=>f.jsx("div",{role:"dialog",...ue,style:ve,className:_e(i,r,Ce&&`${r}-static`,!I&&"show"),onClick:Q?mn:void 0,onMouseUp:nn,"data-bs-theme":C,"aria-label":P,"aria-labelledby":R,"aria-describedby":g,children:f.jsx(m,{...It,onMouseDown:Kt,className:u,contentClassName:d,children:p})});return f.jsx(Zm.Provider,{value:Ze,children:f.jsx(vy,{show:O,ref:Ve,backdrop:Q,container:oe,keyboard:!0,autoFocus:se,enforceFocus:He,restoreFocus:D,restoreFocusOptions:K,onEscapeKeyDown:Er,onShow:V,onHide:ce,onEnter:An,onEntering:Cn,onEntered:pe,onExit:Ln,onExiting:At,onExited:M,manager:gt(),transition:I?jy:void 0,backdropTransition:I?Ry:void 0,renderBackdrop:de,renderDialog:je})})});rh.displayName="Modal";const $e=Object.assign(rh,{Body:Jm,Header:th,Title:nh,Footer:eh,Dialog:Hc,TRANSITION_DURATION:300,BACKDROP_TRANSITION_DURATION:150}),Rp=1e3;function ky(r,i,l){const u=(r-i)/(l-i)*100;return Math.round(u*Rp)/Rp}function kp({min:r,now:i,max:l,label:u,visuallyHidden:d,striped:p,animated:m,className:C,style:R,variant:g,bsPrefix:P,...O},I){return f.jsx("div",{ref:I,...O,role:"progressbar",className:_e(C,`${P}-bar`,{[`bg-${g}`]:g,[`${P}-bar-animated`]:m,[`${P}-bar-striped`]:m||p}),style:{width:`${ky(i,r,l)}%`,...R},"aria-valuenow":i,"aria-valuemin":r,"aria-valuemax":l,children:d?f.jsx("span",{className:"visually-hidden",children:u}):u})}const es=S.forwardRef(({isChild:r=!1,...i},l)=>{const u={min:0,max:100,animated:!1,visuallyHidden:!1,striped:!1,...i};if(u.bsPrefix=ze(u.bsPrefix,"progress"),r)return kp(u,l);const{min:d,now:p,max:m,label:C,visuallyHidden:R,striped:g,animated:P,bsPrefix:O,variant:I,className:Q,children:z,...J}=u;return f.jsx("div",{ref:l,...J,className:_e(Q,O),children:z?zg(z,V=>S.cloneElement(V,{isChild:!0})):kp({min:d,now:p,max:m,label:C,visuallyHidden:R,striped:g,animated:P,bsPrefix:O,variant:I},l)})});es.displayName="ProgressBar";const kc=S.forwardRef(({bsPrefix:r,className:i,as:l="div",...u},d)=>{const p=ze(r,"row"),m=cm(),C=dm(),R=`${p}-cols`,g=[];return m.forEach(P=>{const O=u[P];delete u[P];let I;O!=null&&typeof O=="object"?{cols:I}=O:I=O;const Q=P!==C?`-${P}`:"";I!=null&&g.push(`${R}${Q}-${I}`)}),f.jsx(l,{ref:d,...u,className:_e(i,p,...g)})});kc.displayName="Row";const Ty=S.forwardRef(({bsPrefix:r,className:i,striped:l,bordered:u,borderless:d,hover:p,size:m,variant:C,responsive:R,...g},P)=>{const O=ze(r,"table"),I=_e(i,O,C&&`${O}-${C}`,m&&`${O}-${m}`,l&&`${O}-${typeof l=="string"?`striped-${l}`:"striped"}`,u&&`${O}-bordered`,d&&`${O}-borderless`,p&&`${O}-hover`),Q=f.jsx("table",{...g,className:I,ref:P});if(R){let z=`${O}-responsive`;return typeof R=="string"&&(z=`${z}-${R}`),f.jsx("div",{className:z,children:Q})}return Q}),Gc=S.createContext(void 0),Vc=()=>{const r=S.useContext(Gc);if(!r)throw new Error("Must be used in the GarageProvider");return r},Wc=({vehicle:r,availableDate:i,isAvailable:l})=>{const{event:u,config:d,locale:p}=Pt(),{vehiclesDispatch:m}=Vc(),[C,R]=S.useState(r.nickname||""),[g,P]=S.useState(!1);S.useEffect(()=>{R(r.nickname||"")},[r.nickname]);const O=async()=>{if(!g)return P(!0);P(!1),await Jt("vehicle-set-nickname",{plate:r.plate,nickname:C,garageId:u.garageId}),m&&m({type:"SET_NICKNAME",payload:{plate:r.plate,nickname:C}})},I=S.useMemo(()=>` + url(https://cfx-nui-jg-advancedgarages/vehicle_images/${r.model}.png), + url(https://cfx-nui-jg-dealerships/vehicle_images/${r.model}.png), + url(https://docs.fivem.net/vehicles/${r.model}.webp) + `,[r]),Q=S.useMemo(()=>r.garageId===u.garageId,[u.garageId,r.garageId]);return f.jsxs("div",{className:"d-flex gap-2 flex-fill align-items-center",children:[d.ShowVehicleImages&&f.jsx("div",{className:"garage-row-image flex-shrink-0",style:{backgroundImage:I}}),f.jsxs("div",{className:"flex-1 d-flex flex-fill justify-content-between align-items-center vehicle-acc-header",children:[f.jsxs("div",{children:[f.jsxs("div",{className:"d-flex align-items-center",children:[g?f.jsx("input",{onClick:z=>z.stopPropagation(),value:C,onChange:z=>{z.preventDefault(),R(z.target.value)},onKeyDown:z=>{z.stopPropagation(),z.key==="Enter"&&O(),z.key==="Escape"&&P(!1)},className:"edit-vehicle-name-input",autoFocus:!0,placeholder:r.vehicleLabel,maxLength:50}):f.jsx("h6",{className:"m-0 leading-7",children:C||r.vehicleLabel}),r.plate&&r.garageId&&!u.isImpound&&f.jsx(at,{variant:"link",size:"sm",className:g?void 0:"edit-vehicle-name",onClick:z=>{z.stopPropagation(),O()},children:f.jsx("i",{className:g?"bi-check-circle-fill":"bi-pencil-fill"})})]}),r.plate&&f.jsxs("div",{className:"d-flex gap-2 mt-1",children:[f.jsx(fn,{bg:"black",text:"warning",className:"font-mono",children:r.plate}),typeof r.mileage=="number"&&f.jsxs(fn,{bg:"none",text:"muted",children:[f.jsx("i",{className:"bi-speedometer2 me-1"}),Math.floor(r.mileage*(d.MileageUnit==="miles"?.621371:1)),d.MileageUnit==="miles"?" mi":" km"]}),!!r.needsServicing&&!u.isImpound&&f.jsxs(fn,{bg:"none",text:"danger",className:"me-2",children:[f.jsx("i",{className:"bi-exclamation-triangle-fill me-1"}),p.vehicleNeedsService]}),!!r.financed&&!u.isImpound&&f.jsx(fn,{bg:"none",text:r.financeData.payment_failed?"danger":"success",className:"me-2",children:r.financeData.payment_failed?f.jsxs(f.Fragment,{children:[f.jsx("i",{className:"bi-exclamation-triangle-fill me-1"}),p.failed]}):f.jsxs(f.Fragment,{children:[f.jsx("i",{className:"bi-check-circle-fill me-1"}),p.activeFinance]})})]})]}),f.jsx("div",{className:"me-3",children:u.isImpound?!u.hasWhitelistedJob&&(l?f.jsx(fn,{bg:"success",children:p.impoundAvailable}):f.jsxs(fn,{bg:"warning",text:"dark",children:[p.impoundAvailable," ",i]})):r.impound?f.jsxs(fn,{bg:"danger",children:[f.jsx("i",{className:"bi-exclamation-triangle-fill me-1"}),p.impound]}):u.checkVehicleGarageId&&f.jsxs(fn,{bg:Q?"primary":"none",text:Q?"white":"muted",children:[f.jsx("i",{className:"bi-geo-alt-fill me-1"}),r.garageId]})})]})]})},oh=({vehicle:r})=>{const{locale:i}=Pt(),l=u=>u>=0&&u<=.25?"danger":"primary";return f.jsxs("div",{children:[f.jsxs("div",{className:"d-flex align-items-center",children:[f.jsx("div",{className:"w-25 text-muted",children:i.fuel}),f.jsx("div",{className:"flex-fill",children:f.jsx(es,{variant:l(r.fuel/100),now:r.fuel/100*100,label:`${Math.ceil(r.fuel/100*100)}%`})})]}),f.jsxs("div",{className:"d-flex align-items-center",children:[f.jsx("div",{className:"w-25 text-muted",children:i.engine}),f.jsx("div",{className:"flex-fill",children:f.jsx(es,{variant:l(r.engine/1e3),now:r.engine/1e3*100,label:`${Math.ceil(r.engine/1e3*100)}%`})})]}),f.jsxs("div",{className:"d-flex align-items-center",children:[f.jsx("div",{className:"w-25 text-muted",children:i.body}),f.jsx("div",{className:"flex-fill",children:f.jsx(es,{variant:l(r.body/1e3),now:r.body/1e3*100,label:`${Math.ceil(r.body/1e3*100)}%`})})]})]})};Date.prototype.addHours=function(r){return this.setTime(this.getTime()+r*60*60*1e3),this};const Ti=(r,i)=>{try{return r==null?void 0:r.toLocaleString((i==null?void 0:i.NumberAndDateFormat)||"en-US",{style:"currency",currency:(i==null?void 0:i.Currency)||"USD",maximumFractionDigits:0})}catch{return"InvalidLocale"}},_y=({vehicle:r,show:i,onHide:l})=>{var ce,oe,se,He;const{event:u,locale:d,config:p}=Pt(),{vehiclesDispatch:m}=Vc(),C=S.useMemo(()=>{var D;return((D=u.transferGarages)==null?void 0:D.filter(K=>r.garageId!==K))||[]},[r.garageId,u.transferGarages]),[R,g]=S.useState(p.EnableTransfers.betweenGarages&&u.checkVehicleGarageId?"garage":"player"),[P,O]=S.useState(C.find(D=>D===u.garageId)||C[0]),[I,Q]=S.useState((oe=(ce=u.onlinePlayers)==null?void 0:ce[0])==null?void 0:oe.id),[z,J]=S.useState(!1);S.useEffect(()=>{var D,K;i&&(O(C.find(pe=>pe===u.garageId)||C[0]),Q((K=(D=u.onlinePlayers)==null?void 0:D[0])==null?void 0:K.id))},[i,C,u]);const V=async D=>{D.preventDefault(),J(!0);try{await Jt("garage-transfer-vehicle",{garageId:u.garageId,plate:r.plate,transferType:R,transferPlayerId:I,transferGarageId:P,fromGarageId:r.garageId}),m&&(R==="garage"?m({type:"SET_GARAGE_ID",payload:{plate:r.plate,garageId:P}}):R==="player"&&m({type:"DELETE_VEHICLE",payload:{plate:r.plate}}))}catch{console.error("Could not transfer vehicle.")}J(!1),l()};return f.jsx($e,{show:i,onHide:l,centered:!0,style:{zIndex:9999},children:f.jsxs(De,{onSubmit:V,children:[f.jsx($e.Header,{closeButton:!0,children:d.vehicleTransfer}),f.jsx($e.Body,{children:f.jsxs("div",{className:"d-flex align-items-center",children:[f.jsxs(De.Select,{className:"me-1 w-25 flex-shrink-0",value:R,onChange:D=>g(D.target.value),required:!0,children:[p.EnableTransfers.betweenGarages&&u.checkVehicleGarageId&&f.jsx("option",{value:"garage",children:d.garage}),p.EnableTransfers.betweenPlayers&&!r.blacklisted&&!r.financed&&!u.isJobGarage&&f.jsx("option",{value:"player",children:d.player})]}),f.jsxs("div",{className:"flex-fill",children:[R==="garage"&&f.jsx(De.Select,{value:P,onChange:D=>O(D.target.value),required:!0,children:C.length?C.map(D=>f.jsxs("option",{value:D,children:[D," ",r.garageId===D&&`(${d.currentGarage})`]},D)):f.jsx("option",{disabled:!0,children:d.noAvailableGarages})}),R==="player"&&f.jsx(De.Select,{value:I,onChange:D=>Q(parseInt(D.target.value)),required:!0,children:(se=u.onlinePlayers)!=null&&se.length?(He=u.onlinePlayers)==null?void 0:He.map(({id:D,name:K})=>f.jsx("option",{value:D,children:p.TransferHidePlayerNames?`ID: ${D}`:`${K} (#${D})`},D)):f.jsx("option",{disabled:!0,children:d.noPlayersOnline})})]})]})}),f.jsx($e.Footer,{children:f.jsxs(at,{variant:"primary",className:"ms-1 flex-shrink-0",type:"submit",disabled:z,children:[d.vehicleTransfer,p.GarageVehicleTransferCost>0&&f.jsx(fn,{bg:"white",text:"primary",className:"ms-1",children:R==="garage"&&p.GarageVehicleTransferCost>0&&Ti(p.GarageVehicleTransferCost,p)})]})})]})})},Ny=({vehicle:r})=>{const{event:i,locale:l,config:u,onCloseModal:d}=Pt(),[p,m]=S.useState(!1),[C,R]=S.useState(!1),g=async()=>{R(!0);try{const P=await Jt("drive-vehicle",{model:r.hash,plate:r.plate,garageId:i.garageId,spawnerIndex:r.spawnerIndex,spawnCoords:i.spawnCoords||!1});P&&!P.noClose&&d()}catch{console.error("Could not take vehicle out.")}R(!1)};return f.jsxs("div",{className:"d-flex justify-content-between mt-4",children:[C?f.jsx(at,{variant:"primary",disabled:!0,children:l.loadingVehicle}):r.isSpawned?f.jsxs(at,{variant:"danger",disabled:!0,children:[f.jsx("i",{className:"bi-dash-circle-dotted me-2"}),l.vehicleNotInGarage]}):!i.checkVehicleGarageId||r.garageId===i.garageId?f.jsxs(at,{variant:"primary",onClick:g,children:[f.jsx("i",{className:"bi-arrow-right me-2"}),r.inGarage?l.vehicleTakeOut:f.jsxs("span",{children:[f.jsx("span",{children:l.vehicleReturnAndTakeOut}),f.jsx(fn,{bg:"white",text:"primary",className:"ms-1",children:u.GarageVehicleReturnCost>0&&Ti(u.GarageVehicleReturnCost,u)})]})]}):f.jsxs(at,{variant:"primary",disabled:!0,children:[f.jsx("i",{className:"bi-slash-circle me-2"}),l.inGarage," ",r.garageId]}),!r.isSpawned&&!i.isSpawnerGarage&&(u.EnableTransfers.betweenGarages&&i.checkVehicleGarageId||!i.isJobGarage&&u.EnableTransfers.betweenPlayers)&&f.jsxs(f.Fragment,{children:[f.jsxs(at,{variant:"secondary",onClick:()=>m(P=>!P),children:[f.jsx("i",{className:"bi-arrow-left-right me-2"}),l.vehicleTransfer]}),f.jsx(_y,{vehicle:r,show:p,onHide:()=>m(!1)})]})]})},Py=({vehicle:r})=>{const{locale:i}=Pt(),l=JSON.parse(r.impoundData||"{}");return f.jsxs(Vr,{border:"danger",className:"mt-4",children:[f.jsxs(Vr.Header,{className:"bg-danger text-white",children:[f.jsx("i",{className:"bi-exclamation-triangle-fill me-2"}),i.impoundInformation]}),f.jsxs(Vr.Body,{children:[f.jsxs("p",{children:[f.jsxs("span",{className:"text-muted",children:[i.impound,": "]}),r.garageId]}),f.jsxs("p",{children:[f.jsxs("span",{className:"text-muted",children:[i.impoundedBy,": "]}),l.charname]}),f.jsxs("p",{children:[f.jsxs("span",{className:"text-muted",children:[i.impoundedReason,": "]}),l.reason||i.impoundNoReason]}),r.impoundRetrievable?f.jsx("p",{className:"text-success m-0",children:i.impoundPlayerCanCollect}):f.jsx("p",{className:"text-danger m-0",children:i.impoundCollectionContact.replace("%{value}",l.charname)})]})]})},Iy=({type:r,onHide:i,vehicle:l})=>{const{config:u,locale:d}=Pt(),{vehiclesDispatch:p}=Vc(),m=S.useMemo(()=>l.financeData,[l.financeData]),C=async()=>{try{await Jt("finance-make-payment",{type:r,plate:l.plate},"https://jg-dealerships/"),p&&(r==="payment"&&m.payments_complete+1i(),style:{zIndex:9999},centered:!0,children:[f.jsx($e.Header,{closeButton:!0,children:d.makePayment}),f.jsxs($e.Body,{children:[`${d.earlyPaymentConfirmation} `,Ti(r==="payment"?m.recurring_payment:r==="pay-in-full"?m.total-m.paid:0,u),"?"]}),f.jsxs($e.Footer,{children:[f.jsx(at,{variant:"primary",onClick:C,children:d.yes}),f.jsx(at,{variant:"secondary",onClick:()=>i(),children:d.no})]})]})},Oy=({vehicle:r})=>{const{config:i,locale:l}=Pt(),[u,d]=S.useState(!1),[p,m]=S.useState(""),C=S.useMemo(()=>r.financeData||{},[r.financeData]);return S.useEffect(()=>{const R=()=>{C.payment_failed&&C.seconds_to_repo?(C.seconds_to_repo-=10,C.seconds_to_repo/3600>1.5?m(`${Math.round(C.seconds_to_repo/3600)} ${l.hours||"hours(s)"}`):m(`${Math.round(C.seconds_to_repo/60)} ${l.mins||"min(s)"}`)):C.seconds_to_next_payment&&(C.seconds_to_next_payment-=10,C.seconds_to_next_payment/3600>1.5?m(`${Math.round(C.seconds_to_next_payment/3600)} ${l.hours||"hours(s)"}`):m(`${Math.round(C.seconds_to_next_payment/60)} ${l.mins||"min(s)"}`))};R();const g=setInterval(()=>R(),1e4);return()=>clearInterval(g)},[i,C,l.hours,l.mins]),f.jsx(Vr,{className:"mt-4",children:f.jsxs(Vr.Body,{children:[C.payment_failed&&f.jsxs(bg,{variant:"danger",children:[f.jsx("i",{className:"bi-exclamation-triangle-fill me-2"}),l.repossessionWarning]}),f.jsxs("div",{className:"d-flex justify-content-between",children:[f.jsxs("div",{className:"flex-fill",children:[f.jsxs("div",{className:"d-flex justify-content-between mb-2",children:[f.jsxs("div",{children:[f.jsx("small",{children:l.recurringPayment}),f.jsx("h4",{className:"white",children:Ti(C.recurring_payment,i)})]}),f.jsxs("div",{children:[f.jsx("small",{children:l.remainingBalance}),f.jsx("h4",{className:"white",children:Ti(C.total-C.paid,i)})]}),f.jsxs("div",{children:[f.jsx("small",{children:l.remainingPayments}),f.jsxs("h4",{className:"white",children:[C.payments_complete,f.jsxs("small",{children:[" / ",C.total_payments]})]})]})]}),f.jsx("div",{className:"mb-4",children:f.jsxs("small",{children:[f.jsx("i",{className:"bi-clock me-2"}),`${l.paymentTakenEvery} `,f.jsxs("strong",{children:[C.payment_interval," ",l.hours]}),`. ${C.payment_failed?l.vehicleRepossessed:l.nextPayment} `,f.jsx("strong",{children:p})]})})]}),f.jsxs("div",{className:"d-flex flex-column ms-5",children:[f.jsx(at,{size:"sm",className:"mb-2",variant:"primary",onClick:()=>d("payment"),children:l.makePayment}),f.jsx(at,{size:"sm",variant:"outline-primary",onClick:()=>d("pay-in-full"),children:l.payInFull}),f.jsx(Iy,{type:u,onHide:()=>d(!1),vehicle:r})]})]}),f.jsx("div",{className:"finance-container",children:f.jsxs("div",{className:"finance-progress-bar",children:[f.jsx("div",{className:"finance-progress-bar-inner bg-success",style:{width:(C.payments_complete-1)/(C.total_payments-1)*100+"%"}}),f.jsx("div",{className:"points-container",children:Array(C.total_payments).fill(!0).map((R,g)=>f.jsx("div",{className:"point",children:f.jsx("i",{className:`${gf.jsxs("div",{children:[f.jsx(_l.Header,{children:f.jsx(Wc,{vehicle:r})}),f.jsxs(Ac,{children:[f.jsx(oh,{vehicle:r}),r.impound?f.jsx(Py,{vehicle:r}):f.jsxs("div",{children:[!!r.financed&&f.jsx(Oy,{vehicle:r}),f.jsx(Ny,{vehicle:r})]})]})]}),Ay=(r,i)=>{switch(i.type){case"SET_VEHICLES":return[...i.payload.vehicles];case"SET_NICKNAME":return r.map(l=>l.plate===i.payload.plate?{...l,nickname:i.payload.nickname}:l);case"SET_FINANCED":return r.map(l=>l.plate===i.payload.plate?{...l,financed:i.payload.financed}:l);case"SET_FINANCE_DATA":return r.map(l=>l.plate===i.payload.plate?{...l,financeData:{...l.financeData,...i.payload.financeData}}:l);case"SET_GARAGE_ID":return r.map(l=>l.plate===i.payload.plate?{...l,garageId:i.payload.garageId}:l);case"DELETE_VEHICLE":return r.filter(l=>l.plate!==i.payload.plate);default:throw Error("Unknown action.")}},ps=()=>f.jsx(fn,{bg:"secondary",text:"dark",children:"JG Scripts"}),Ly=({vehicle:r,impoundMetadata:i,availableDate:l})=>{const{event:u,locale:d}=Pt();return f.jsxs("div",{children:[f.jsxs("p",{children:[f.jsxs("span",{className:"text-muted",children:[d.impoundedBy,": "]}),i.charname]}),f.jsxs("p",{children:[f.jsxs("span",{className:"text-muted",children:[d.impoundedReason,": "]}),i.reason||d.impoundNoReason]}),u.hasWhitelistedJob&&f.jsxs("p",{children:[f.jsxs("span",{className:"text-muted",children:[d.impoundRetrievableByOwner,":"," "]}),r.impoundRetrievable?f.jsxs("span",{children:[d.yes,f.jsxs(fn,{bg:"warning",text:"dark",className:"ms-1",children:[d.impoundAvailable," ",l]})]}):d.no]})]})},My=({vehicle:r,isAvailable:i,impoundMetadata:l})=>{const{event:u,config:d,locale:p,onCloseModal:m}=Pt(),[C,R]=S.useState(!1),g=async()=>{R(!0);try{await Jt("impound-drive-vehicle",{plate:r.plate,impoundId:u.garageId,originalGarageId:l.original_garage_id}),m()}catch{console.error("Something went wrong.")}R(!1)},P=async()=>{R(!0);try{await Jt("impound-return-vehicle",{plate:r.plate,impoundId:u.garageId,originalGarageId:l.original_garage_id}),m()}catch{console.error("Something went wrong.")}R(!1)};return f.jsxs("div",{className:"d-flex justify-content-between",children:[u.hasWhitelistedJob&&f.jsxs(at,{variant:"primary",onClick:P,disabled:C,children:[f.jsx("i",{className:"bi-box-arrow-in-right me-2"}),p.vehicleReturnToOwnersGarage]}),(u.hasWhitelistedJob||i)&&f.jsxs(at,{variant:u.hasWhitelistedJob?"secondary":"primary",onClick:g,disabled:C,children:[f.jsx("i",{className:"bi-arrow-right me-2"}),p.vehicleTakeOut,!u.hasWhitelistedJob&&f.jsx(fn,{bg:"white",text:"primary",className:"ms-1",children:l.retrieval_cost>0&&Ti(l.retrieval_cost,d)})]})]})},by=({vehicle:r})=>{const{config:i}=Pt(),l=S.useMemo(()=>JSON.parse(r.impoundData||"{}"),[r.impoundData]),u=S.useMemo(()=>new Date>new Date(l.retrieval_date),[l]),d=S.useMemo(()=>new Date(l.retrieval_date).toLocaleDateString(i.DateFormat,{day:"numeric",month:"long",hour:"numeric",minute:"numeric",timeZoneName:"short"}),[l,i]);return f.jsxs("div",{children:[f.jsx(_l.Header,{children:f.jsx(Wc,{vehicle:r,isAvailable:u,availableDate:d})}),f.jsxs(_l.Body,{children:[f.jsx(Ly,{vehicle:r,impoundMetadata:l,availableDate:d}),f.jsx(My,{vehicle:r,impoundMetadata:l,isAvailable:u})]})]})},$y=()=>{const{event:r,config:i,locale:l,onCloseModal:u}=Pt(),[d,p]=S.useState(""),[m,C]=S.useReducer(Ay,r.vehicles||[]);S.useEffect(()=>{C({type:"SET_VEHICLES",payload:{vehicles:r.vehicles||[]}})},[r.vehicles]);const R=async()=>{Jt("enter-garage-interior",{garageId:r.garageId,vehicleType:r.vehicleType||"car"}),u()},g=S.useMemo(()=>m.filter(({nickname:P,vehicleLabel:O,plate:I})=>{const Q=d.toLocaleLowerCase().split(" ").filter(z=>z).map(z=>z.trim());return Q.filter(z=>`${P||""} ${O} ${I}`.toLocaleLowerCase().includes(z)).length===Q.length}).reduce((P,O)=>O.garageId===r.garageId&&!O.impound?[O,...P]:[...P,O],[]),[d,m,r.garageId]);return f.jsx(Gc.Provider,{value:{vehiclesDispatch:C},children:f.jsxs($e,{show:r.type==="show-garage",onHide:u,backdrop:!1,centered:!0,size:"lg",scrollable:!0,children:[f.jsx($e.Header,{closeButton:!0,children:f.jsx("div",{className:"flex justify-between w-full items-center mr-3",children:f.jsxs($e.Title,{as:"h5",children:[f.jsxs("span",{className:"text-muted p-1 pe-3",children:[r.vehicleType==="car"&&f.jsx("i",{className:"bi-car-front"}),r.vehicleType==="sea"&&f.jsx("i",{className:"bi-water"}),r.vehicleType==="air"&&f.jsx("i",{className:"bi-airplane"})]}),f.jsx("span",{children:r.garageId||l.garage})]})})}),f.jsxs($e.Body,{className:"p-0 pb-2",children:[f.jsxs("div",{className:"search-bar p-3 flex gap-3",children:[f.jsxs(Po,{children:[f.jsx(Po.Text,{children:f.jsx("i",{className:"bi-search"})}),f.jsx(De.Control,{type:"search",value:d,onChange:P=>p(P.target.value),placeholder:l.search})]}),r.enableInteriors&&f.jsxs(f.Fragment,{children:[f.jsx("div",{className:"border"}),f.jsxs(at,{variant:"primary",className:"flex-shrink-0",onClick:R,children:[f.jsx("i",{className:"bi-person-walking me-1"}),l.goInside]})]})]}),m.length?f.jsx(_l,{defaultActiveKey:"0",children:g.map(P=>{var O;return f.jsx(_l.Item,{eventKey:(O=P.id)==null?void 0:O.toString(),onKeyUp:I=>I.preventDefault(),children:r.isImpound?f.jsx(by,{vehicle:P}):f.jsx(Fy,{vehicle:P})},P.id)})}):f.jsx("div",{className:"p-3 text-center",children:l.noVehicles})]}),f.jsxs($e.Footer,{className:"d-flex justify-content-between text-muted",children:[f.jsxs("span",{children:[m.length," ",l.vehicles]}),!i.HideWatermark&&f.jsx(ps,{})]})]})})},Dy=()=>{var J,V,ce;const{event:r,locale:i,config:l,onCloseModal:u}=Pt(),[d,p]=S.useState(""),[m,C]=S.useState(!1),[R,g]=S.useState("0"),[P,O]=S.useState(""),[I,Q]=S.useState((J=r.impoundLocations)==null?void 0:J[0]);S.useEffect(()=>{var oe;r.type==="show-impound-form"&&(p(""),C(!1),g("0"),O(""),Q((oe=r.impoundLocations)==null?void 0:oe[0]))},[r]);const z=async oe=>{oe.preventDefault();try{await Jt("impound-vehicle",{plate:r.plate,impoundId:I,reason:d,retrievable:m,retrievalCost:parseInt(P||"0"),retrievalDate:new Date().addHours(parseInt(R||"0")).toString()}),u()}catch{console.error("Something went wrong.")}};return f.jsx($e,{show:r.type==="show-impound-form",onHide:u,backdrop:!1,centered:!0,children:f.jsxs(De,{onSubmit:z,children:[f.jsx($e.Header,{closeButton:!0,children:f.jsx($e.Title,{as:"h5",children:i.impoundVehicle})}),f.jsxs($e.Body,{children:[f.jsxs("div",{className:"mb-3",children:[f.jsx(De.Label,{children:i.vehiclePlate}),f.jsx(De.Control,{type:"text",value:r.plate,readOnly:!0,disabled:!0})]}),f.jsxs("div",{className:"mb-3",children:[f.jsx(De.Label,{children:i.impound}),f.jsx(De.Select,{value:I,onChange:oe=>Q(oe.target.value),required:!0,children:(V=r.impoundLocations)!=null&&V.length?(ce=r.impoundLocations)==null?void 0:ce.map(oe=>f.jsx("option",{value:oe,children:oe},oe)):f.jsx("option",{disabled:!0,children:i.noAvailableGarages})})]}),f.jsxs("div",{className:"mb-3",children:[f.jsx(De.Label,{children:i.impoundReasonField}),f.jsx(De.Control,{type:"text",value:d,onChange:oe=>p(oe.target.value)})]}),f.jsx("div",{className:"mb-3",children:f.jsx(De.Check,{type:"checkbox",id:"retrievable",label:i.impoundRetrievableByOwner,checked:m,onChange:oe=>C(oe.target.checked)})}),m&&f.jsxs("div",{children:[f.jsxs("div",{className:"mb-3",children:[f.jsx(De.Label,{children:i.impoundTime}),f.jsx(De.Select,{value:R,onChange:oe=>g(oe.target.value),required:!0,children:(l.ImpoundTimeOptions||[]).map(oe=>f.jsx("option",{value:oe,children:oe?oe<=1?`${60*oe} ${i.mins}`:oe<48?`${oe} ${i.hours}`:`${Math.floor(oe/24)} ${i.days} ${oe%24>0?`${oe%24} ${i.hours}`:""}`:i.impoundAvailableImmediately}))})]}),f.jsxs("div",{className:"mb-3",children:[f.jsx(De.Label,{children:i.impoundCost}),f.jsxs(Po,{children:[f.jsx(Po.Text,{children:l.Currency}),f.jsx(De.Control,{type:"number",value:P,onChange:oe=>O(oe.target.value),required:!0,min:0})]})]})]})]}),f.jsxs($e.Footer,{className:"d-flex justify-content-between text-muted",children:[f.jsx(at,{variant:"primary",type:"submit",children:i.impoundVehicle}),!l.HideWatermark&&f.jsx(ps,{})]})]})})},By=()=>{const{event:r,locale:i,config:l,onCloseModal:u}=Pt(),[d,p]=S.useState("");S.useEffect(()=>{r.type==="show-vplate-form"&&p("")},[r.type]);const m=async C=>{C.preventDefault();try{await Jt("change-vehicle-plate",{newPlate:d.toUpperCase().trim()}),u()}catch{console.error("Something went wrong.")}};return f.jsx($e,{show:r.type==="show-vplate-form",onHide:u,backdrop:!1,centered:!0,children:f.jsxs(De,{onSubmit:m,children:[f.jsx($e.Header,{closeButton:!0,children:f.jsx($e.Title,{as:"h5",children:i.changeVehiclePlate})}),f.jsxs($e.Body,{children:[f.jsxs("div",{className:"mb-3",children:[f.jsx(De.Label,{children:i.vehiclePlate}),f.jsx(De.Control,{type:"text",value:r.plate,readOnly:!0,disabled:!0})]}),f.jsxs("div",{children:[f.jsx(De.Label,{children:i.newPlate}),f.jsx(De.Control,{type:"text",value:d,onChange:C=>p(C.target.value),maxLength:8,pattern:"^[a-zA-Z0-9 ]*",title:"Only letters, numbers and spaces allowed",required:!0})]})]}),f.jsxs($e.Footer,{className:"d-flex justify-content-between text-muted",children:[f.jsx(at,{variant:"primary",type:"submit",children:i.changeVehiclePlate}),l&&!l.HideWatermark&&f.jsx(ps,{})]})]})})},zy=()=>{const{event:r,locale:i,onCloseModal:l}=Pt(),[u,d]=S.useState("liveries"),p=S.useMemo(()=>{var g;return(g=r.extras)==null?void 0:g.filter(({available:P})=>P)},[r.extras]),m=async g=>{await Jt("toggle-livery",{livery_id:parseInt(g)})},C=async(g,P)=>{await Jt("toggle-extra",{extra_id:parseInt(g),disabled:P?0:1})},R=async()=>{await Jt("exit-liveries-extras-menu"),d("liveries"),l()};return r.type!=="show-liveries-extras-menu"?null:f.jsx("div",{className:"modal show",style:{display:"block",position:"fixed",width:300,height:"fit-content",bottom:20,left:20,top:"unset",padding:0},children:f.jsxs($e.Dialog,{style:{margin:0},children:[f.jsxs($e.Header,{closeButton:!0,onHide:R,children:[f.jsx("i",{className:"bi-tools me-2 text-lg"}),f.jsx($e.Title,{as:"h5",children:i.vehicleSetup})]}),f.jsxs($e.Body,{children:[f.jsx(Tm,{style:{width:"100%"},children:["liveries","extras"].map(g=>f.jsx(at,{variant:u===g?"primary":"dark",onClick:()=>d(g),children:i[g]}))}),f.jsx("div",{className:"mt-3",children:u==="liveries"&&(!r.liveriesCount||r.liveriesCount<1?i.noLiveries:f.jsxs("div",{children:[f.jsx("div",{className:"mt-2",children:f.jsx(De.Check,{id:"livery-none",name:"vehicle-livery",type:"radio",value:0,label:`${i.none}`,defaultChecked:r.currentLivery===0,onChange:g=>m(g.target.value)})}),Array(r.liveriesCount).fill("").map((g,P)=>f.jsx("div",{className:"mt-2",children:f.jsx(De.Check,{id:`livery-${P+1}`,name:"vehicle-livery",type:"radio",value:P+1,label:`${i.livery} ${P+1}`,defaultChecked:r.currentLivery===P+1,onChange:O=>m(O.target.value)})}))]}))}),f.jsx("div",{children:u==="extras"&&(p.length?p.map(({id:g,enabled:P})=>f.jsx("div",{className:"mt-2",children:f.jsx(De.Check,{id:`extra-${g}`,type:"switch",label:`${i.extra} ${g}`,defaultChecked:P,onChange:O=>C(g,O.target.checked)})})):i.noExtras)}),f.jsxs(at,{size:"lg",style:{width:"100%"},className:"mt-3",onClick:R,children:[f.jsx("i",{className:"bi-arrow-right me-2"}),i.vehicleTakeOut]})]})]})})};var pc={exports:{}},Rl={exports:{}},Hy=Rl.exports,Tp;function Gy(){return Tp||(Tp=1,function(r,i){(function(l,u){u(i,ls())})(Hy,function(l,u){function d(s,h,y,w,j,x,k){try{var $=s[x](k),b=$.value}catch(B){return void y(B)}$.done?h(b):Promise.resolve(b).then(w,j)}function p(s){return function(){var h=this,y=arguments;return new Promise(function(w,j){var x=s.apply(h,y);function k(b){d(x,w,j,k,$,"next",b)}function $(b){d(x,w,j,k,$,"throw",b)}k(void 0)})}}function m(){return(m=Object.assign||function(s){for(var h=1;h=0||(j[y]=s[y]);return j}function R(s){var h=function(y,w){if(typeof y!="object"||y===null)return y;var j=y[Symbol.toPrimitive];if(j!==void 0){var x=j.call(y,w);if(typeof x!="object")return x;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(y)}(s,"string");return typeof h=="symbol"?h:String(h)}u=u&&Object.prototype.hasOwnProperty.call(u,"default")?u.default:u;var g={init:"init"},P=function(s){var h=s.value;return h===void 0?"":h},O=function(){return u.createElement(u.Fragment,null," ")},I={Cell:P,width:150,minWidth:0,maxWidth:Number.MAX_SAFE_INTEGER};function Q(){for(var s=arguments.length,h=new Array(s),y=0;y(x=typeof x=="number"?x:1/0)){var k=j;j=x,x=k}return s.filter(function($){return h.some(function(b){var B=$.values[b];return B>=j&&B<=x})})};Fi.autoRemove=function(s){return!s||typeof s[0]!="number"&&typeof s[1]!="number"};var jr=Object.freeze({__proto__:null,text:Qr,exactText:Dl,exactTextCase:Mo,includes:bo,includesAll:$o,includesSome:Do,includesValue:Bo,exact:rr,equals:or,between:Fi});g.resetFilters="resetFilters",g.setFilter="setFilter",g.setAllFilters="setAllFilters";var Ai=function(s){s.stateReducers.push(Bl),s.useInstance.push(zl)};function Bl(s,h,y,w){if(h.type===g.init)return m({filters:[]},s);if(h.type===g.resetFilters)return m({},s,{filters:w.initialState.filters||[]});if(h.type===g.setFilter){var j=h.columnId,x=h.filterValue,k=w.allColumns,$=w.filterTypes,b=k.find(function(ie){return ie.id===j});if(!b)throw new Error("React-Table: Could not find a column with id: "+j);var B=X(b.filter,$||{},jr),ee=s.filters.find(function(ie){return ie.id===j}),q=oe(x,ee&&ee.value);return Ce(B.autoRemove,q,b)?m({},s,{filters:s.filters.filter(function(ie){return ie.id!==j})}):m({},s,ee?{filters:s.filters.map(function(ie){return ie.id===j?{id:j,value:q}:ie})}:{filters:[].concat(s.filters,[{id:j,value:q}])})}if(h.type===g.setAllFilters){var te=h.filters,G=w.allColumns,Z=w.filterTypes;return m({},s,{filters:oe(te,s.filters).filter(function(ie){var ae=G.find(function(ye){return ye.id===ie.id});return!Ce(X(ae.filter,Z||{},jr).autoRemove,ie.value,ae)})})}}function zl(s){var h=s.data,y=s.rows,w=s.flatRows,j=s.rowsById,x=s.allColumns,k=s.filterTypes,$=s.manualFilters,b=s.defaultCanFilter,B=b!==void 0&&b,ee=s.disableFilters,q=s.state.filters,te=s.dispatch,G=s.autoResetFilters,Z=G===void 0||G,ie=u.useCallback(function(me,Ae){te({type:g.setFilter,columnId:me,filterValue:Ae})},[te]),ae=u.useCallback(function(me){te({type:g.setAllFilters,filters:me})},[te]);x.forEach(function(me){var Ae=me.id,We=me.accessor,Te=me.defaultCanFilter,Pe=me.disableFilters;me.canFilter=We?nt(Pe!==!0&&void 0,ee!==!0&&void 0,!0):nt(Te,B,!1),me.setFilter=function(Le){return ie(me.id,Le)};var Ye=q.find(function(Le){return Le.id===Ae});me.filterValue=Ye&&Ye.value});var ye=u.useMemo(function(){if($||!q.length)return[y,w,j];var me=[],Ae={};return[function We(Te,Pe){Pe===void 0&&(Pe=0);var Ye=Te;return(Ye=q.reduce(function(Le,Je){var Qe=Je.id,st=Je.value,xe=x.find(function(St){return St.id===Qe});if(!xe)return Le;Pe===0&&(xe.preFilteredRows=Le);var Ue=X(xe.filter,k||{},jr);return Ue?(xe.filteredRows=Ue(Le,[Qe],st),xe.filteredRows):(console.warn("Could not find a valid 'column.filter' for column with the ID: "+xe.id+"."),Le)},Te)).forEach(function(Le){me.push(Le),Ae[Le.id]=Le,Le.subRows&&(Le.subRows=Le.subRows&&Le.subRows.length>0?We(Le.subRows,Pe+1):Le.subRows)}),Ye}(y),me,Ae]},[$,q,y,w,j,x,k]),Be=ye[0],we=ye[1],re=ye[2];u.useMemo(function(){x.filter(function(me){return!q.find(function(Ae){return Ae.id===me.id})}).forEach(function(me){me.preFilteredRows=Be,me.filteredRows=Be})},[Be,q,x]);var Fe=se(Z);D(function(){Fe()&&te({type:g.resetFilters})},[te,$?null:h]),Object.assign(s,{preFilteredRows:y,preFilteredFlatRows:w,preFilteredRowsById:j,filteredRows:Be,filteredFlatRows:we,filteredRowsById:re,rows:Be,flatRows:we,rowsById:re,setFilter:ie,setAllFilters:ae})}Ai.pluginName="useFilters",g.resetGlobalFilter="resetGlobalFilter",g.setGlobalFilter="setGlobalFilter";var zo=function(s){s.stateReducers.push(Hl),s.useInstance.push(Xr)};function Hl(s,h,y,w){if(h.type===g.resetGlobalFilter)return m({},s,{globalFilter:w.initialState.globalFilter||void 0});if(h.type===g.setGlobalFilter){var j=h.filterValue,x=w.userFilterTypes,k=X(w.globalFilter,x||{},jr),$=oe(j,s.globalFilter);return Ce(k.autoRemove,$)?(s.globalFilter,C(s,["globalFilter"])):m({},s,{globalFilter:$})}}function Xr(s){var h=s.data,y=s.rows,w=s.flatRows,j=s.rowsById,x=s.allColumns,k=s.filterTypes,$=s.globalFilter,b=s.manualGlobalFilter,B=s.state.globalFilter,ee=s.dispatch,q=s.autoResetGlobalFilter,te=q===void 0||q,G=s.disableGlobalFilter,Z=u.useCallback(function(re){ee({type:g.setGlobalFilter,filterValue:re})},[ee]),ie=u.useMemo(function(){if(b||B===void 0)return[y,w,j];var re=[],Fe={},me=X($,k||{},jr);if(!me)return console.warn("Could not find a valid 'globalFilter' option."),y;x.forEach(function(We){var Te=We.disableGlobalFilter;We.canFilter=nt(Te!==!0&&void 0,G!==!0&&void 0,!0)});var Ae=x.filter(function(We){return We.canFilter===!0});return[function We(Te){return(Te=me(Te,Ae.map(function(Pe){return Pe.id}),B)).forEach(function(Pe){re.push(Pe),Fe[Pe.id]=Pe,Pe.subRows=Pe.subRows&&Pe.subRows.length?We(Pe.subRows):Pe.subRows}),Te}(y),re,Fe]},[b,B,$,k,x,y,w,j,G]),ae=ie[0],ye=ie[1],Be=ie[2],we=se(te);D(function(){we()&&ee({type:g.resetGlobalFilter})},[ee,b?null:h]),Object.assign(s,{preGlobalFilteredRows:y,preGlobalFilteredFlatRows:w,preGlobalFilteredRowsById:j,globalFilteredRows:ae,globalFilteredFlatRows:ye,globalFilteredRowsById:Be,rows:ae,flatRows:ye,rowsById:Be,setGlobalFilter:Z,disableGlobalFilter:G})}function Ho(s,h){return h.reduce(function(y,w){return y+(typeof w=="number"?w:0)},0)}zo.pluginName="useGlobalFilter";var Rr=Object.freeze({__proto__:null,sum:Ho,min:function(s){var h=s[0]||0;return s.forEach(function(y){typeof y=="number"&&(h=Math.min(h,y))}),h},max:function(s){var h=s[0]||0;return s.forEach(function(y){typeof y=="number"&&(h=Math.max(h,y))}),h},minMax:function(s){var h=s[0]||0,y=s[0]||0;return s.forEach(function(w){typeof w=="number"&&(h=Math.min(h,w),y=Math.max(y,w))}),h+".."+y},average:function(s){return Ho(0,s)/s.length},median:function(s){if(!s.length)return null;var h=Math.floor(s.length/2),y=[].concat(s).sort(function(w,j){return w-j});return s.length%2!=0?y[h]:(y[h-1]+y[h])/2},unique:function(s){return Array.from(new Set(s).values())},uniqueCount:function(s){return new Set(s).size},count:function(s){return s.length}}),ws=[],qr={};g.resetGroupBy="resetGroupBy",g.setGroupBy="setGroupBy",g.toggleGroupBy="toggleGroupBy";var Yr=function(s){s.getGroupByToggleProps=[Go],s.stateReducers.push(Li),s.visibleColumnsDeps.push(function(h,y){var w=y.instance;return[].concat(h,[w.state.groupBy])}),s.visibleColumns.push(xs),s.useInstance.push(Cs),s.prepareRow.push(ir)};Yr.pluginName="useGroupBy";var Go=function(s,h){var y=h.header;return[s,{onClick:y.canGroupBy?function(w){w.persist(),y.toggleGroupBy()}:void 0,style:{cursor:y.canGroupBy?"pointer":void 0},title:"Toggle GroupBy"}]};function Li(s,h,y,w){if(h.type===g.init)return m({groupBy:[]},s);if(h.type===g.resetGroupBy)return m({},s,{groupBy:w.initialState.groupBy||[]});if(h.type===g.setGroupBy)return m({},s,{groupBy:h.value});if(h.type===g.toggleGroupBy){var j=h.columnId,x=h.value,k=x!==void 0?x:!s.groupBy.includes(j);return m({},s,k?{groupBy:[].concat(s.groupBy,[j])}:{groupBy:s.groupBy.filter(function($){return $!==j})})}}function xs(s,h){var y=h.instance.state.groupBy,w=y.map(function(x){return s.find(function(k){return k.id===x})}).filter(Boolean),j=s.filter(function(x){return!y.includes(x.id)});return(s=[].concat(w,j)).forEach(function(x){x.isGrouped=y.includes(x.id),x.groupedIndex=y.indexOf(x.id)}),s}var Ss={};function Cs(s){var h=s.data,y=s.rows,w=s.flatRows,j=s.rowsById,x=s.allColumns,k=s.flatHeaders,$=s.groupByFn,b=$===void 0?Mi:$,B=s.manualGroupBy,ee=s.aggregations,q=ee===void 0?Ss:ee,te=s.plugins,G=s.state.groupBy,Z=s.dispatch,ie=s.autoResetGroupBy,ae=ie===void 0||ie,ye=s.disableGroupBy,Be=s.defaultCanGroupBy,we=s.getHooks;ce(te,["useColumnOrder","useFilters"],"useGroupBy");var re=se(s);x.forEach(function(xe){var Ue=xe.accessor,St=xe.defaultGroupBy,Gt=xe.disableGroupBy;xe.canGroupBy=Ue?nt(xe.canGroupBy,Gt!==!0&&void 0,ye!==!0&&void 0,!0):nt(xe.canGroupBy,St,Be,!1),xe.canGroupBy&&(xe.toggleGroupBy=function(){return s.toggleGroupBy(xe.id)}),xe.Aggregated=xe.Aggregated||xe.Cell});var Fe=u.useCallback(function(xe,Ue){Z({type:g.toggleGroupBy,columnId:xe,value:Ue})},[Z]),me=u.useCallback(function(xe){Z({type:g.setGroupBy,value:xe})},[Z]);k.forEach(function(xe){xe.getGroupByToggleProps=z(we().getGroupByToggleProps,{instance:re(),header:xe})});var Ae=u.useMemo(function(){if(B||!G.length)return[y,w,j,ws,qr,w,j];var xe=G.filter(function(Ot){return x.find(function(Xn){return Xn.id===Ot})}),Ue=[],St={},Gt=[],ke={},ft=[],kt={},Vt=function Ot(Xn,Dn,ea){if(Dn===void 0&&(Dn=0),Dn===xe.length)return Xn.map(function(Zo){return m({},Zo,{depth:Dn})});var so=xe[Dn],uo=b(Xn,so);return Object.entries(uo).map(function(Zo,ta){var Ji=Zo[0],co=Zo[1],fo=so+":"+Ji,Zi=Ot(co,Dn+1,fo=ea?ea+">"+fo:fo),ar=Dn?ct(co,"leafRows"):co,Fs=function(on,ei,na){var qn={};return x.forEach(function(pt){if(xe.includes(pt.id))qn[pt.id]=ei[0]?ei[0].values[pt.id]:null;else{var ra=typeof pt.aggregate=="function"?pt.aggregate:q[pt.aggregate]||Rr[pt.aggregate];if(ra){var ti=ei.map(function(po){return po.values[pt.id]}),Ls=on.map(function(po){var mo=po.values[pt.id];if(!na&&pt.aggregateValue){var ni=typeof pt.aggregateValue=="function"?pt.aggregateValue:q[pt.aggregateValue]||Rr[pt.aggregateValue];if(!ni)throw console.info({column:pt}),new Error("React Table: Invalid column.aggregateValue option for column listed above");mo=ni(mo,po,pt)}return mo});qn[pt.id]=ra(Ls,ti)}else{if(pt.aggregate)throw console.info({column:pt}),new Error("React Table: Invalid column.aggregate option for column listed above");qn[pt.id]=null}}}),qn}(ar,co,Dn),As={id:fo,isGrouped:!0,groupByID:so,groupByVal:Ji,values:Fs,subRows:Zi,leafRows:ar,depth:Dn,index:ta};return Zi.forEach(function(on){Ue.push(on),St[on.id]=on,on.isGrouped?(Gt.push(on),ke[on.id]=on):(ft.push(on),kt[on.id]=on)}),As})}(y);return Vt.forEach(function(Ot){Ue.push(Ot),St[Ot.id]=Ot,Ot.isGrouped?(Gt.push(Ot),ke[Ot.id]=Ot):(ft.push(Ot),kt[Ot.id]=Ot)}),[Vt,Ue,St,Gt,ke,ft,kt]},[B,G,y,w,j,x,q,b]),We=Ae[0],Te=Ae[1],Pe=Ae[2],Ye=Ae[3],Le=Ae[4],Je=Ae[5],Qe=Ae[6],st=se(ae);D(function(){st()&&Z({type:g.resetGroupBy})},[Z,B?null:h]),Object.assign(s,{preGroupedRows:y,preGroupedFlatRow:w,preGroupedRowsById:j,groupedRows:We,groupedFlatRows:Te,groupedRowsById:Pe,onlyGroupedFlatRows:Ye,onlyGroupedRowsById:Le,nonGroupedFlatRows:Je,nonGroupedRowsById:Qe,rows:We,flatRows:Te,rowsById:Pe,toggleGroupBy:Fe,setGroupBy:me})}function ir(s){s.allCells.forEach(function(h){var y;h.isGrouped=h.column.isGrouped&&h.column.id===s.groupByID,h.isPlaceholder=!h.isGrouped&&h.column.isGrouped,h.isAggregated=!h.isGrouped&&!h.isPlaceholder&&((y=s.subRows)==null?void 0:y.length)})}function Mi(s,h){return s.reduce(function(y,w,j){var x=""+w.values[h];return y[x]=Array.isArray(y[x])?y[x]:[],y[x].push(w),y},{})}var bi=/([0-9]+)/gm;function $i(s,h){return s===h?0:s>h?1:-1}function kr(s,h,y){return[s.values[y],h.values[y]]}function Di(s){return typeof s=="number"?isNaN(s)||s===1/0||s===-1/0?"":String(s):typeof s=="string"?s:""}var Gl=Object.freeze({__proto__:null,alphanumeric:function(s,h,y){var w=kr(s,h,y),j=w[0],x=w[1];for(j=Di(j),x=Di(x),j=j.split(bi).filter(Boolean),x=x.split(bi).filter(Boolean);j.length&&x.length;){var k=j.shift(),$=x.shift(),b=parseInt(k,10),B=parseInt($,10),ee=[b,B].sort();if(isNaN(ee[0])){if(k>$)return 1;if($>k)return-1}else{if(isNaN(ee[1]))return isNaN(b)?-1:1;if(b>B)return 1;if(B>b)return-1}}return j.length-x.length},datetime:function(s,h,y){var w=kr(s,h,y),j=w[0],x=w[1];return $i(j=j.getTime(),x=x.getTime())},basic:function(s,h,y){var w=kr(s,h,y);return $i(w[0],w[1])},string:function(s,h,y){var w=kr(s,h,y),j=w[0],x=w[1];for(j=j.split("").filter(Boolean),x=x.split("").filter(Boolean);j.length&&x.length;){var k=j.shift(),$=x.shift(),b=k.toLowerCase(),B=$.toLowerCase();if(b>B)return 1;if(B>b)return-1;if(k>$)return 1;if($>k)return-1}return j.length-x.length},number:function(s,h,y){var w=kr(s,h,y),j=w[0],x=w[1],k=/[^0-9.]/gi;return $i(j=Number(String(j).replace(k,"")),x=Number(String(x).replace(k,"")))}});g.resetSortBy="resetSortBy",g.setSortBy="setSortBy",g.toggleSortBy="toggleSortBy",g.clearSortBy="clearSortBy",I.sortType="alphanumeric",I.sortDescFirst=!1;var Bi=function(s){s.getSortByToggleProps=[Es],s.stateReducers.push(js),s.useInstance.push(Et)};Bi.pluginName="useSortBy";var Es=function(s,h){var y=h.instance,w=h.column,j=y.isMultiSortEvent,x=j===void 0?function(k){return k.shiftKey}:j;return[s,{onClick:w.canSort?function(k){k.persist(),w.toggleSortBy(void 0,!y.disableMultiSort&&x(k))}:void 0,style:{cursor:w.canSort?"pointer":void 0},title:w.canSort?"Toggle SortBy":void 0}]};function js(s,h,y,w){if(h.type===g.init)return m({sortBy:[]},s);if(h.type===g.resetSortBy)return m({},s,{sortBy:w.initialState.sortBy||[]});if(h.type===g.clearSortBy)return m({},s,{sortBy:s.sortBy.filter(function(re){return re.id!==h.columnId})});if(h.type===g.setSortBy)return m({},s,{sortBy:h.sortBy});if(h.type===g.toggleSortBy){var j,x=h.columnId,k=h.desc,$=h.multi,b=w.allColumns,B=w.disableMultiSort,ee=w.disableSortRemove,q=w.disableMultiRemove,te=w.maxMultiSortColCount,G=te===void 0?Number.MAX_SAFE_INTEGER:te,Z=s.sortBy,ie=b.find(function(re){return re.id===x}).sortDescFirst,ae=Z.find(function(re){return re.id===x}),ye=Z.findIndex(function(re){return re.id===x}),Be=k!=null,we=[];return(j=!B&&$?ae?"toggle":"add":ye!==Z.length-1||Z.length!==1?"replace":ae?"toggle":"replace")!="toggle"||ee||Be||$&&q||!(ae&&ae.desc&&!ie||!ae.desc&&ie)||(j="remove"),j==="replace"?we=[{id:x,desc:Be?k:ie}]:j==="add"?(we=[].concat(Z,[{id:x,desc:Be?k:ie}])).splice(0,we.length-G):j==="toggle"?we=Z.map(function(re){return re.id===x?m({},re,{desc:Be?k:!ae.desc}):re}):j==="remove"&&(we=Z.filter(function(re){return re.id!==x})),m({},s,{sortBy:we})}}function Et(s){var h=s.data,y=s.rows,w=s.flatRows,j=s.allColumns,x=s.orderByFn,k=x===void 0?Vl:x,$=s.sortTypes,b=s.manualSortBy,B=s.defaultCanSort,ee=s.disableSortBy,q=s.flatHeaders,te=s.state.sortBy,G=s.dispatch,Z=s.plugins,ie=s.getHooks,ae=s.autoResetSortBy,ye=ae===void 0||ae;ce(Z,["useFilters","useGlobalFilter","useGroupBy","usePivotColumns"],"useSortBy");var Be=u.useCallback(function(Te){G({type:g.setSortBy,sortBy:Te})},[G]),we=u.useCallback(function(Te,Pe,Ye){G({type:g.toggleSortBy,columnId:Te,desc:Pe,multi:Ye})},[G]),re=se(s);q.forEach(function(Te){var Pe=Te.accessor,Ye=Te.canSort,Le=Te.disableSortBy,Je=Te.id,Qe=Pe?nt(Le!==!0&&void 0,ee!==!0&&void 0,!0):nt(B,Ye,!1);Te.canSort=Qe,Te.canSort&&(Te.toggleSortBy=function(xe,Ue){return we(Te.id,xe,Ue)},Te.clearSortBy=function(){G({type:g.clearSortBy,columnId:Te.id})}),Te.getSortByToggleProps=z(ie().getSortByToggleProps,{instance:re(),column:Te});var st=te.find(function(xe){return xe.id===Je});Te.isSorted=!!st,Te.sortedIndex=te.findIndex(function(xe){return xe.id===Je}),Te.isSortedDesc=Te.isSorted?st.desc:void 0});var Fe=u.useMemo(function(){if(b||!te.length)return[y,w];var Te=[],Pe=te.filter(function(Ye){return j.find(function(Le){return Le.id===Ye.id})});return[function Ye(Le){var Je=k(Le,Pe.map(function(Qe){var st=j.find(function(St){return St.id===Qe.id});if(!st)throw new Error("React-Table: Could not find a column with id: "+Qe.id+" while sorting");var xe=st.sortType,Ue=It(xe)||($||{})[xe]||Gl[xe];if(!Ue)throw new Error("React-Table: Could not find a valid sortType of '"+xe+"' for column '"+Qe.id+"'.");return function(St,Gt){return Ue(St,Gt,Qe.id,Qe.desc)}}),Pe.map(function(Qe){var st=j.find(function(xe){return xe.id===Qe.id});return st&&st.sortInverted?Qe.desc:!Qe.desc}));return Je.forEach(function(Qe){Te.push(Qe),Qe.subRows&&Qe.subRows.length!==0&&(Qe.subRows=Ye(Qe.subRows))}),Je}(y),Te]},[b,te,y,w,j,k,$]),me=Fe[0],Ae=Fe[1],We=se(ye);D(function(){We()&&G({type:g.resetSortBy})},[b?null:h]),Object.assign(s,{preSortedRows:y,preSortedFlatRows:w,sortedRows:me,sortedFlatRows:Ae,rows:me,flatRows:Ae,setSortBy:Be,toggleSortBy:we})}function Vl(s,h,y){return[].concat(s).sort(function(w,j){for(var x=0;xs.pageIndex?$=j===-1?x.length>=s.pageSize:k-1),$?m({},s,{pageIndex:k}):s}if(h.type===g.setPageSize){var b=h.pageSize,B=s.pageSize*s.pageIndex;return m({},s,{pageIndex:Math.floor(B/b),pageSize:b})}}function Wo(s){var h=s.rows,y=s.autoResetPage,w=y===void 0||y,j=s.manualExpandedKey,x=j===void 0?"expanded":j,k=s.plugins,$=s.pageCount,b=s.paginateExpandedRows,B=b===void 0||b,ee=s.expandSubRows,q=ee===void 0||ee,te=s.state,G=te.pageSize,Z=te.pageIndex,ie=te.expanded,ae=te.globalFilter,ye=te.filters,Be=te.groupBy,we=te.sortBy,re=s.dispatch,Fe=s.data,me=s.manualPagination;ce(k,["useGlobalFilter","useFilters","useGroupBy","useSortBy","useExpanded"],"usePagination");var Ae=se(w);D(function(){Ae()&&re({type:g.resetPage})},[re,me?null:Fe,ae,ye,Be,we]);var We=me?$:Math.ceil(h.length/G),Te=u.useMemo(function(){return We>0?[].concat(new Array(We)).fill(null).map(function(Ue,St){return St}):[]},[We]),Pe=u.useMemo(function(){var Ue;if(me)Ue=h;else{var St=G*Z,Gt=St+G;Ue=h.slice(St,Gt)}return B?Ue:et(Ue,{manualExpandedKey:x,expanded:ie,expandSubRows:q})},[q,ie,x,me,Z,G,B,h]),Ye=Z>0,Le=We===-1?Pe.length>=G:Z-1&&x.push(j.splice(b,1)[0])};j.length&&w.length;)k();return[].concat(x,j)}function Yo(s){var h=s.dispatch;s.setColumnOrder=u.useCallback(function(y){return h({type:g.setColumnOrder,columnOrder:y})},[h])}Ui.pluginName="useColumnOrder",I.canResize=!0,g.columnStartResizing="columnStartResizing",g.columnResizing="columnResizing",g.columnDoneResizing="columnDoneResizing",g.resetResize="resetResize";var $n=function(s){s.getResizerProps=[Kn],s.getHeaderProps.push({style:{position:"relative"}}),s.stateReducers.push(Qn),s.useInstance.push(to),s.useInstanceBeforeDimensions.push(eo)},Kn=function(s,h){var y=h.instance,w=h.header,j=y.dispatch,x=function(k,$){var b=!1;if(k.type==="touchstart"){if(k.touches&&k.touches.length>1)return;b=!0}var B,ee,q=function(we){var re=[];return function Fe(me){me.columns&&me.columns.length&&me.columns.map(Fe),re.push(me)}(we),re}($).map(function(we){return[we.id,we.totalWidth]}),te=b?Math.round(k.touches[0].clientX):k.clientX,G=function(){window.cancelAnimationFrame(B),B=null,j({type:g.columnDoneResizing})},Z=function(){window.cancelAnimationFrame(B),B=null,j({type:g.columnResizing,clientX:ee})},ie=function(we){ee=we,B||(B=window.requestAnimationFrame(Z))},ae={mouse:{moveEvent:"mousemove",moveHandler:function(we){return ie(we.clientX)},upEvent:"mouseup",upHandler:function(we){document.removeEventListener("mousemove",ae.mouse.moveHandler),document.removeEventListener("mouseup",ae.mouse.upHandler),G()}},touch:{moveEvent:"touchmove",moveHandler:function(we){return we.cancelable&&(we.preventDefault(),we.stopPropagation()),ie(we.touches[0].clientX),!1},upEvent:"touchend",upHandler:function(we){document.removeEventListener(ae.touch.moveEvent,ae.touch.moveHandler),document.removeEventListener(ae.touch.upEvent,ae.touch.moveHandler),G()}}},ye=b?ae.touch:ae.mouse,Be=!!function(){if(typeof N=="boolean")return N;var we=!1;try{var re={get passive(){return we=!0,!1}};window.addEventListener("test",null,re),window.removeEventListener("test",null,re)}catch{we=!1}return N=we}()&&{passive:!1};document.addEventListener(ye.moveEvent,ye.moveHandler,Be),document.addEventListener(ye.upEvent,ye.upHandler,Be),j({type:g.columnStartResizing,columnId:$.id,columnWidth:$.totalWidth,headerIdWidths:q,clientX:te})};return[s,{onMouseDown:function(k){return k.persist()||x(k,w)},onTouchStart:function(k){return k.persist()||x(k,w)},style:{cursor:"col-resize"},draggable:!1,role:"separator"}]};function Qn(s,h){if(h.type===g.init)return m({columnResizing:{columnWidths:{}}},s);if(h.type===g.resetResize)return m({},s,{columnResizing:{columnWidths:{}}});if(h.type===g.columnStartResizing){var y=h.clientX,w=h.columnId,j=h.columnWidth,x=h.headerIdWidths;return m({},s,{columnResizing:m({},s.columnResizing,{startX:y,headerIdWidths:x,columnWidth:j,isResizingColumn:w})})}if(h.type===g.columnResizing){var k=h.clientX,$=s.columnResizing,b=$.startX,B=$.columnWidth,ee=$.headerIdWidths,q=(k-b)/B,te={};return(ee===void 0?[]:ee).forEach(function(G){var Z=G[0],ie=G[1];te[Z]=Math.max(ie+ie*q,0)}),m({},s,{columnResizing:m({},s.columnResizing,{columnWidths:m({},s.columnResizing.columnWidths,{},te)})})}return h.type===g.columnDoneResizing?m({},s,{columnResizing:m({},s.columnResizing,{startX:null,isResizingColumn:null})}):void 0}$n.pluginName="useResizeColumns";var eo=function(s){var h=s.flatHeaders,y=s.disableResizing,w=s.getHooks,j=s.state.columnResizing,x=se(s);h.forEach(function(k){var $=nt(k.disableResizing!==!0&&void 0,y!==!0&&void 0,!0);k.canResize=$,k.width=j.columnWidths[k.id]||k.originalWidth||k.width,k.isResizing=j.isResizingColumn===k.id,$&&(k.getResizerProps=z(w().getResizerProps,{instance:x(),header:k}))})};function to(s){var h=s.plugins,y=s.dispatch,w=s.autoResetResize,j=w===void 0||w,x=s.columns;ce(h,["useAbsoluteLayout"],"useResizeColumns");var k=se(j);D(function(){k()&&y({type:g.resetResize})},[x]);var $=u.useCallback(function(){return y({type:g.resetResize})},[y]);Object.assign(s,{resetResizing:$})}var jn={position:"absolute",top:0},Jl=function(s){s.getTableBodyProps.push(no),s.getRowProps.push(no),s.getHeaderGroupProps.push(no),s.getFooterGroupProps.push(no),s.getHeaderProps.push(function(h,y){var w=y.column;return[h,{style:m({},jn,{left:w.totalLeft+"px",width:w.totalWidth+"px"})}]}),s.getCellProps.push(function(h,y){var w=y.cell;return[h,{style:m({},jn,{left:w.column.totalLeft+"px",width:w.column.totalWidth+"px"})}]}),s.getFooterProps.push(function(h,y){var w=y.column;return[h,{style:m({},jn,{left:w.totalLeft+"px",width:w.totalWidth+"px"})}]})};Jl.pluginName="useAbsoluteLayout";var no=function(s,h){return[s,{style:{position:"relative",width:h.instance.totalColumnsWidth+"px"}}]},lr={display:"inline-block",boxSizing:"border-box"},Qi=function(s,h){return[s,{style:{display:"flex",width:h.instance.totalColumnsWidth+"px"}}]},Xi=function(s){s.getRowProps.push(Qi),s.getHeaderGroupProps.push(Qi),s.getFooterGroupProps.push(Qi),s.getHeaderProps.push(function(h,y){var w=y.column;return[h,{style:m({},lr,{width:w.totalWidth+"px"})}]}),s.getCellProps.push(function(h,y){var w=y.cell;return[h,{style:m({},lr,{width:w.column.totalWidth+"px"})}]}),s.getFooterProps.push(function(h,y){var w=y.column;return[h,{style:m({},lr,{width:w.totalWidth+"px"})}]})};function ro(s){s.getTableProps.push(Zl),s.getRowProps.push(qi),s.getHeaderGroupProps.push(qi),s.getFooterGroupProps.push(qi),s.getHeaderProps.push(oo),s.getCellProps.push(io),s.getFooterProps.push(Tr)}Xi.pluginName="useBlockLayout",ro.pluginName="useFlexLayout";var Zl=function(s,h){return[s,{style:{minWidth:h.instance.totalColumnsMinWidth+"px"}}]},qi=function(s,h){return[s,{style:{display:"flex",flex:"1 0 auto",minWidth:h.instance.totalColumnsMinWidth+"px"}}]},oo=function(s,h){var y=h.column;return[s,{style:{boxSizing:"border-box",flex:y.totalFlexWidth?y.totalFlexWidth+" 0 auto":void 0,minWidth:y.totalMinWidth+"px",width:y.totalWidth+"px"}}]},io=function(s,h){var y=h.cell;return[s,{style:{boxSizing:"border-box",flex:y.column.totalFlexWidth+" 0 auto",minWidth:y.column.totalMinWidth+"px",width:y.column.totalWidth+"px"}}]},Tr=function(s,h){var y=h.column;return[s,{style:{boxSizing:"border-box",flex:y.totalFlexWidth?y.totalFlexWidth+" 0 auto":void 0,minWidth:y.totalMinWidth+"px",width:y.totalWidth+"px"}}]};function lo(s){s.stateReducers.push(Jo),s.getTableProps.push(Is),s.getHeaderProps.push(Os),s.getRowProps.push(Yi)}g.columnStartResizing="columnStartResizing",g.columnResizing="columnResizing",g.columnDoneResizing="columnDoneResizing",g.resetResize="resetResize",lo.pluginName="useGridLayout";var Is=function(s,h){var y=h.instance;return[s,{style:{display:"grid",gridTemplateColumns:y.visibleColumns.map(function(w){var j;return y.state.gridLayout.columnWidths[w.id]?y.state.gridLayout.columnWidths[w.id]+"px":(j=y.state.columnResizing)!=null&&j.isResizingColumn?y.state.gridLayout.startWidths[w.id]+"px":typeof w.width=="number"?w.width+"px":w.width}).join(" ")}}]},Os=function(s,h){var y=h.column;return[s,{id:"header-cell-"+y.id,style:{position:"sticky",gridColumn:"span "+y.totalVisibleHeaderCount}}]},Yi=function(s,h){var y=h.row;return y.isExpanded?[s,{style:{gridColumn:"1 / "+(y.cells.length+1)}}]:[s,{}]};function Jo(s,h,y,w){if(h.type===g.init)return m({gridLayout:{columnWidths:{}}},s);if(h.type===g.resetResize)return m({},s,{gridLayout:{columnWidths:{}}});if(h.type===g.columnStartResizing){var j=h.columnId,x=h.headerIdWidths,k=ao(j);if(k!==void 0){var $=w.visibleColumns.reduce(function(re,Fe){var me;return m({},re,((me={})[Fe.id]=ao(Fe.id),me))},{}),b=w.visibleColumns.reduce(function(re,Fe){var me;return m({},re,((me={})[Fe.id]=Fe.minWidth,me))},{}),B=w.visibleColumns.reduce(function(re,Fe){var me;return m({},re,((me={})[Fe.id]=Fe.maxWidth,me))},{}),ee=x.map(function(re){var Fe=re[0];return[Fe,ao(Fe)]});return m({},s,{gridLayout:m({},s.gridLayout,{startWidths:$,minWidths:b,maxWidths:B,headerIdGridWidths:ee,columnWidth:k})})}return s}if(h.type===g.columnResizing){var q=h.clientX,te=s.columnResizing.startX,G=s.gridLayout,Z=G.columnWidth,ie=G.minWidths,ae=G.maxWidths,ye=G.headerIdGridWidths,Be=(q-te)/Z,we={};return(ye===void 0?[]:ye).forEach(function(re){var Fe=re[0],me=re[1];we[Fe]=Math.min(Math.max(ie[Fe],me+me*Be),ae[Fe])}),m({},s,{gridLayout:m({},s.gridLayout,{columnWidths:m({},s.gridLayout.columnWidths,{},we)})})}return h.type===g.columnDoneResizing?m({},s,{gridLayout:m({},s.gridLayout,{startWidths:{},minWidths:{},maxWidths:{}})}):void 0}function ao(s){var h,y=(h=document.getElementById("header-cell-"+s))==null?void 0:h.offsetWidth;if(y!==void 0)return y}l._UNSTABLE_usePivotColumns=Ul,l.actions=g,l.defaultColumn=I,l.defaultGroupByFn=Mi,l.defaultOrderByFn=Vl,l.defaultRenderer=P,l.emptyRenderer=O,l.ensurePluginOrder=ce,l.flexRender=pe,l.functionalUpdate=oe,l.loopHooks=V,l.makePropGetter=z,l.makeRenderer=K,l.reduceHooks=J,l.safeUseLayoutEffect=He,l.useAbsoluteLayout=Jl,l.useAsyncDebounce=function(s,h){h===void 0&&(h=0);var y=u.useRef({}),w=se(s),j=se(h);return u.useCallback(function(){var x=p(regeneratorRuntime.mark(function k(){var $,b,B,ee=arguments;return regeneratorRuntime.wrap(function(q){for(;;)switch(q.prev=q.next){case 0:for($=ee.length,b=new Array($),B=0;B<$;B++)b[B]=ee[B];return y.current.promise||(y.current.promise=new Promise(function(te,G){y.current.resolve=te,y.current.reject=G})),y.current.timeout&&clearTimeout(y.current.timeout),y.current.timeout=setTimeout(p(regeneratorRuntime.mark(function te(){return regeneratorRuntime.wrap(function(G){for(;;)switch(G.prev=G.next){case 0:return delete y.current.timeout,G.prev=1,G.t0=y.current,G.next=5,w().apply(void 0,b);case 5:G.t1=G.sent,G.t0.resolve.call(G.t0,G.t1),G.next=12;break;case 9:G.prev=9,G.t2=G.catch(1),y.current.reject(G.t2);case 12:return G.prev=12,delete y.current.promise,G.finish(12);case 15:case"end":return G.stop()}},te,null,[[1,9,12,15]])})),j()),q.abrupt("return",y.current.promise);case 5:case"end":return q.stop()}},k)}));return function(){return x.apply(this,arguments)}}(),[w,j])},l.useBlockLayout=Xi,l.useColumnOrder=Ui,l.useExpanded=dt,l.useFilters=Ai,l.useFlexLayout=ro,l.useGetLatest=se,l.useGlobalFilter=zo,l.useGridLayout=lo,l.useGroupBy=Yr,l.useMountedLayoutEffect=D,l.usePagination=Vo,l.useResizeColumns=$n,l.useRowSelect=Kl,l.useRowState=Vi,l.useSortBy=Bi,l.useTable=function(s){for(var h=arguments.length,y=new Array(h>1?h-1:0),w=1;w-1}function x0(r,i){var l=this.__data__,u=ms(l,r);return u<0?(++this.size,l.push([r,i])):l[u][1]=i,this}function Cr(r){var i=-1,l=r==null?0:r.length;for(this.clear();++i-1&&r%1==0&&r-1&&r%1==0&&r<=xw}var Sw="[object Arguments]",Cw="[object Array]",Ew="[object Boolean]",jw="[object Date]",Rw="[object Error]",kw="[object Function]",Tw="[object Map]",_w="[object Number]",Nw="[object Object]",Pw="[object RegExp]",Iw="[object Set]",Ow="[object String]",Fw="[object WeakMap]",Aw="[object ArrayBuffer]",Lw="[object DataView]",Mw="[object Float32Array]",bw="[object Float64Array]",$w="[object Int8Array]",Dw="[object Int16Array]",Bw="[object Int32Array]",zw="[object Uint8Array]",Hw="[object Uint8ClampedArray]",Gw="[object Uint16Array]",Vw="[object Uint32Array]",xt={};xt[Mw]=xt[bw]=xt[$w]=xt[Dw]=xt[Bw]=xt[zw]=xt[Hw]=xt[Gw]=xt[Vw]=!0;xt[Sw]=xt[Cw]=xt[Aw]=xt[Ew]=xt[Lw]=xt[jw]=xt[Rw]=xt[kw]=xt[Tw]=xt[_w]=xt[Nw]=xt[Pw]=xt[Iw]=xt[Ow]=xt[Fw]=!1;function Ww(r){return Fo(r)&&vh(r.length)&&!!xt[Oo(r)]}function Kc(r){return function(i){return r(i)}}var gh=typeof xn=="object"&&xn&&!xn.nodeType&&xn,kl=gh&&typeof Sn=="object"&&Sn&&!Sn.nodeType&&Sn,Uw=kl&&kl.exports===gh,hc=Uw&&ih.process,_i=function(){try{var r=kl&&kl.require&&kl.require("util").types;return r||hc&&hc.binding&&hc.binding("util")}catch{}}(),bp=_i&&_i.isTypedArray,Kw=bp?Kc(bp):Ww,Qw=Object.prototype,Xw=Qw.hasOwnProperty;function yh(r,i){var l=$l(r),u=!l&&pw(r),d=!l&&!u&&hh(r),p=!l&&!u&&!d&&Kw(r),m=l||u||d||p,C=m?uw(r.length,String):[],R=C.length;for(var g in r)(i||Xw.call(r,g))&&!(m&&(g=="length"||d&&(g=="offset"||g=="parent")||p&&(g=="buffer"||g=="byteLength"||g=="byteOffset")||ww(g,R)))&&C.push(g);return C}var qw=Object.prototype;function Qc(r){var i=r&&r.constructor,l=typeof i=="function"&&i.prototype||qw;return r===l}var Yw=ah(Object.keys,Object),Jw=Object.prototype,Zw=Jw.hasOwnProperty;function ex(r){if(!Qc(r))return Yw(r);var i=[];for(var l in Object(r))Zw.call(r,l)&&l!="constructor"&&i.push(l);return i}function wh(r){return r!=null&&vh(r.length)&&!ch(r)}function Xc(r){return wh(r)?yh(r):ex(r)}function tx(r,i){return r&&vs(i,Xc(i),r)}function nx(r){var i=[];if(r!=null)for(var l in Object(r))i.push(l);return i}var rx=Object.prototype,ox=rx.hasOwnProperty;function ix(r){if(!bl(r))return nx(r);var i=Qc(r),l=[];for(var u in r)u=="constructor"&&(i||!ox.call(r,u))||l.push(u);return l}function qc(r){return wh(r)?yh(r,!0):ix(r)}function lx(r,i){return r&&vs(i,qc(i),r)}var xh=typeof xn=="object"&&xn&&!xn.nodeType&&xn,$p=xh&&typeof Sn=="object"&&Sn&&!Sn.nodeType&&Sn,ax=$p&&$p.exports===xh,Dp=ax?nr.Buffer:void 0,Bp=Dp?Dp.allocUnsafe:void 0;function sx(r,i){if(i)return r.slice();var l=r.length,u=Bp?Bp(l):new r.constructor(l);return r.copy(u),u}function Sh(r,i){var l=-1,u=r.length;for(i||(i=Array(u));++l=0)&&(l[d]=r[d]);return l}var gs=S.createContext(void 0);gs.displayName="FormikContext";gs.Provider;gs.Consumer;function QS(){var r=S.useContext(gs);return r}var Un=function(i){return typeof i=="function"},ys=function(i){return i!==null&&typeof i=="object"},XS=function(i){return String(Math.floor(Number(i)))===i},wc=function(i){return Object.prototype.toString.call(i)==="[object String]"},xc=function(i){return ys(i)&&Un(i.then)};function wn(r,i,l,u){u===void 0&&(u=0);for(var d=Ih(i);r&&u=0?[]:{}}}return(p===0?r:d)[m[p]]===l?r:(l===void 0?delete d[m[p]]:d[m[p]]=l,p===0&&l===void 0&&delete u[m[p]],u)}function Fh(r,i,l,u){l===void 0&&(l=new WeakMap),u===void 0&&(u={});for(var d=0,p=Object.keys(r);d0?de.map(function(je){return _t(je,wn(M,je))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")];return Promise.all(ve).then(function(je){return je.reduce(function(ue,Ge,dt){return Ge==="DO_NOT_DELETE_YOU_WILL_BE_FIRED"||Ge&&(ue=No(ue,de[dt],Ge)),ue},{})})},[_t]),Lt=S.useCallback(function(M){return Promise.all([$t(M),I.validationSchema?At(M):{},I.validate?vt(M):{}]).then(function(de){var ve=de[0],je=de[1],ue=de[2],Ge=Tc.all([ve,je,ue],{arrayMerge:e1});return Ge})},[I.validate,I.validationSchema,$t,vt,At]),tt=In(function(M){return M===void 0&&(M=K.values),pe({type:"SET_ISVALIDATING",payload:!0}),Lt(M).then(function(de){return ce.current&&(pe({type:"SET_ISVALIDATING",payload:!1}),pe({type:"SET_ERRORS",payload:de})),de})});S.useEffect(function(){m&&ce.current===!0&&_o(Q.current,I.initialValues)&&tt(Q.current)},[m,tt]);var nt=S.useCallback(function(M){var de=M&&M.values?M.values:Q.current,ve=M&&M.errors?M.errors:z.current?z.current:I.initialErrors||{},je=M&&M.touched?M.touched:J.current?J.current:I.initialTouched||{},ue=M&&M.status?M.status:V.current?V.current:I.initialStatus;Q.current=de,z.current=ve,J.current=je,V.current=ue;var Ge=function(){pe({type:"RESET_FORM",payload:{isSubmitting:!!M&&!!M.isSubmitting,errors:ve,touched:je,status:ue,values:de,isValidating:!!M&&!!M.isValidating,submitCount:M&&M.submitCount&&typeof M.submitCount=="number"?M.submitCount:0}})};if(I.onReset){var dt=I.onReset(K.values,Kt);xc(dt)?dt.then(Ge):Ge()}else Ge()},[I.initialErrors,I.initialStatus,I.initialTouched,I.onReset]);S.useEffect(function(){ce.current===!0&&!_o(Q.current,I.initialValues)&&g&&(Q.current=I.initialValues,nt(),m&&tt(Q.current))},[g,I.initialValues,nt,m,tt]),S.useEffect(function(){g&&ce.current===!0&&!_o(z.current,I.initialErrors)&&(z.current=I.initialErrors||To,pe({type:"SET_ERRORS",payload:I.initialErrors||To}))},[g,I.initialErrors]),S.useEffect(function(){g&&ce.current===!0&&!_o(J.current,I.initialTouched)&&(J.current=I.initialTouched||Za,pe({type:"SET_TOUCHED",payload:I.initialTouched||Za}))},[g,I.initialTouched]),S.useEffect(function(){g&&ce.current===!0&&!_o(V.current,I.initialStatus)&&(V.current=I.initialStatus,pe({type:"SET_STATUS",payload:I.initialStatus}))},[g,I.initialStatus,I.initialTouched]);var It=In(function(M){if(oe.current[M]&&Un(oe.current[M].validate)){var de=wn(K.values,M),ve=oe.current[M].validate(de);return xc(ve)?(pe({type:"SET_ISVALIDATING",payload:!0}),ve.then(function(je){return je}).then(function(je){pe({type:"SET_FIELD_ERROR",payload:{field:M,value:je}}),pe({type:"SET_ISVALIDATING",payload:!1})})):(pe({type:"SET_FIELD_ERROR",payload:{field:M,value:ve}}),Promise.resolve(ve))}else if(I.validationSchema)return pe({type:"SET_ISVALIDATING",payload:!0}),At(K.values,M).then(function(je){return je}).then(function(je){pe({type:"SET_FIELD_ERROR",payload:{field:M,value:wn(je,M)}}),pe({type:"SET_ISVALIDATING",payload:!1})});return Promise.resolve()}),ct=S.useCallback(function(M,de){var ve=de.validate;oe.current[M]={validate:ve}},[]),et=S.useCallback(function(M){delete oe.current[M]},[]),X=In(function(M,de){pe({type:"SET_TOUCHED",payload:M});var ve=de===void 0?d:de;return ve?tt(K.values):Promise.resolve()}),Ce=S.useCallback(function(M){pe({type:"SET_ERRORS",payload:M})},[]),le=In(function(M,de){var ve=Un(M)?M(K.values):M;pe({type:"SET_VALUES",payload:ve});var je=de===void 0?l:de;return je?tt(ve):Promise.resolve()}),N=S.useCallback(function(M,de){pe({type:"SET_FIELD_ERROR",payload:{field:M,value:de}})},[]),H=In(function(M,de,ve){pe({type:"SET_FIELD_VALUE",payload:{field:M,value:de}});var je=ve===void 0?l:ve;return je?tt(No(K.values,M,de)):Promise.resolve()}),Re=S.useCallback(function(M,de){var ve=de,je=M,ue;if(!wc(M)){M.persist&&M.persist();var Ge=M.target?M.target:M.currentTarget,dt=Ge.type,rn=Ge.name,Mn=Ge.id,bn=Ge.value,Oi=Ge.checked;Ge.outerHTML;var Kr=Ge.options,Qr=Ge.multiple;ve=de||rn||Mn,je=/number|range/.test(dt)?(ue=parseFloat(bn),isNaN(ue)?"":ue):/checkbox/.test(dt)?n1(wn(K.values,ve),Oi,bn):Kr&&Qr?t1(Kr):bn}ve&&H(ve,je)},[H,K.values]),Ne=In(function(M){if(wc(M))return function(de){return Re(de,M)};Re(M)}),Me=In(function(M,de,ve){de===void 0&&(de=!0),pe({type:"SET_FIELD_TOUCHED",payload:{field:M,value:de}});var je=ve===void 0?d:ve;return je?tt(K.values):Promise.resolve()}),Ve=S.useCallback(function(M,de){M.persist&&M.persist();var ve=M.target,je=ve.name,ue=ve.id;ve.outerHTML;var Ge=de||je||ue;Me(Ge,!0)},[Me]),qe=In(function(M){if(wc(M))return function(de){return Ve(de,M)};Ve(M)}),Ke=S.useCallback(function(M){Un(M)?pe({type:"SET_FORMIK_STATE",payload:M}):pe({type:"SET_FORMIK_STATE",payload:function(){return M}})},[]),Ze=S.useCallback(function(M){pe({type:"SET_STATUS",payload:M})},[]),gt=S.useCallback(function(M){pe({type:"SET_ISSUBMITTING",payload:M})},[]),Zt=In(function(){return pe({type:"SUBMIT_ATTEMPT"}),tt().then(function(M){var de=M instanceof Error,ve=!de&&Object.keys(M).length===0;if(ve){var je;try{if(je=nn(),je===void 0)return}catch(ue){throw ue}return Promise.resolve(je).then(function(ue){return ce.current&&pe({type:"SUBMIT_SUCCESS"}),ue}).catch(function(ue){if(ce.current)throw pe({type:"SUBMIT_FAILURE"}),ue})}else if(ce.current&&(pe({type:"SUBMIT_FAILURE"}),de))throw M})}),pn=In(function(M){M&&M.preventDefault&&Un(M.preventDefault)&&M.preventDefault(),M&&M.stopPropagation&&Un(M.stopPropagation)&&M.stopPropagation(),Zt().catch(function(de){console.warn("Warning: An unhandled error was caught from submitForm()",de)})}),Kt={resetForm:nt,validateForm:tt,validateField:It,setErrors:Ce,setFieldError:N,setFieldTouched:Me,setFieldValue:H,setStatus:Ze,setSubmitting:gt,setTouched:X,setValues:le,setFormikState:Ke,submitForm:Zt},nn=In(function(){return P(K.values,Kt)}),lt=In(function(M){M&&M.preventDefault&&Un(M.preventDefault)&&M.preventDefault(),M&&M.stopPropagation&&Un(M.stopPropagation)&&M.stopPropagation(),nt()}),Fn=S.useCallback(function(M){return{value:wn(K.values,M),error:wn(K.errors,M),touched:!!wn(K.touched,M),initialValue:wn(Q.current,M),initialTouched:!!wn(J.current,M),initialError:wn(z.current,M)}},[K.errors,K.touched,K.values]),mn=S.useCallback(function(M){return{setValue:function(ve,je){return H(M,ve,je)},setTouched:function(ve,je){return Me(M,ve,je)},setError:function(ve){return N(M,ve)}}},[H,Me,N]),Er=S.useCallback(function(M){var de=ys(M),ve=de?M.name:M,je=wn(K.values,ve),ue={name:ve,value:je,onChange:Ne,onBlur:qe};if(de){var Ge=M.type,dt=M.value,rn=M.as,Mn=M.multiple;Ge==="checkbox"?dt===void 0?ue.checked=!!je:(ue.checked=!!(Array.isArray(je)&&~je.indexOf(dt)),ue.value=dt):Ge==="radio"?(ue.checked=je===dt,ue.value=dt):rn==="select"&&Mn&&(ue.value=ue.value||[],ue.multiple=!0)}return ue},[qe,Ne,K.values]),An=S.useMemo(function(){return!_o(Q.current,K.values)},[Q.current,K.values]),Ln=S.useMemo(function(){return typeof C<"u"?An?K.errors&&Object.keys(K.errors).length===0:C!==!1&&Un(C)?C(I):C:K.errors&&Object.keys(K.errors).length===0},[C,An,K.errors,I]),Cn=Ht({},K,{initialValues:Q.current,initialErrors:z.current,initialTouched:J.current,initialStatus:V.current,handleBlur:qe,handleChange:Ne,handleReset:lt,handleSubmit:pn,resetForm:nt,setErrors:Ce,setFormikState:Ke,setFieldTouched:Me,setFieldValue:H,setFieldError:N,setStatus:Ze,setSubmitting:gt,setTouched:X,setValues:le,submitForm:Zt,validateForm:tt,validateField:It,isValid:Ln,dirty:An,unregisterField:et,registerField:ct,getFieldProps:Er,getFieldMeta:Fn,getFieldHelpers:mn,validateOnBlur:d,validateOnChange:l,validateOnMount:m});return Cn}function JS(r){var i={};if(r.inner){if(r.inner.length===0)return No(i,r.path,r.message);for(var d=r.inner,l=Array.isArray(d),u=0,d=l?d:d[Symbol.iterator]();;){var p;if(l){if(u>=d.length)break;p=d[u++]}else{if(u=d.next(),u.done)break;p=u.value}var m=p;wn(i,m.path)||(i=No(i,m.path,m.message))}}return i}function ZS(r,i,l,u){l===void 0&&(l=!1);var d=Oc(r);return i[l?"validateSync":"validate"](d,{abortEarly:!1,context:d})}function Oc(r){var i=Array.isArray(r)?[]:{};for(var l in r)if(Object.prototype.hasOwnProperty.call(r,l)){var u=String(l);Array.isArray(r[u])===!0?i[u]=r[u].map(function(d){return Array.isArray(d)===!0||Ip(d)?Oc(d):d!==""?d:void 0}):Ip(r[u])?i[u]=Oc(r[u]):i[u]=r[u]!==""?r[u]:void 0}return i}function e1(r,i,l){var u=r.slice();return i.forEach(function(p,m){if(typeof u[m]>"u"){var C=l.clone!==!1,R=C&&l.isMergeableObject(p);u[m]=R?Tc(Array.isArray(p)?[]:{},p,l):p}else l.isMergeableObject(p)?u[m]=Tc(r[m],p,l):r.indexOf(p)===-1&&u.push(p)}),u}function t1(r){return Array.from(r).filter(function(i){return i.selected}).map(function(i){return i.value})}function n1(r,i,l){if(typeof r=="boolean")return!!i;var u=[],d=!1,p=-1;if(Array.isArray(r))u=r,p=r.indexOf(l),d=p>=0;else if(!l||l=="true"||l=="false")return!!i;return i&&l&&!d?u.concat(l):d?u.slice(0,p).concat(u.slice(p+1)):u}var r1=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u"?S.useLayoutEffect:S.useEffect;function In(r){var i=S.useRef(r);return r1(function(){i.current=r}),S.useCallback(function(){for(var l=arguments.length,u=new Array(l),d=0;d{const{event:d,locale:p}=Pt(),[m,C]=S.useState(""),R=S.useMemo(()=>(d.allPlayers||[]).filter(({identifier:P})=>!l.find(O=>O.identifier===P)),[d.allPlayers,l]),g=async()=>{if(!m)return!1;u(d.allPlayers.find(({identifier:P})=>P===m)),C(""),i()};return f.jsxs($e,{show:r,onHide:i,centered:!0,style:{zIndex:99999},children:[f.jsx($e.Header,{closeButton:!0,children:f.jsx($e.Title,{as:"h6",children:p.addPlayer})}),f.jsxs($e.Body,{children:[f.jsxs(De.Group,{className:"mb-3",children:[f.jsx(De.Label,{children:p.player}),f.jsxs(De.Select,{value:m,onChange:P=>C(P.target.value),children:[f.jsx("option",{value:"",children:"Select player"}),R.map(({identifier:P,name:O})=>f.jsx("option",{value:P,children:O},P))]})]}),f.jsx(at,{onClick:g,variant:"primary",disabled:!m,children:p.addPlayer})]})]})},Ah=({show:r,onHide:i,onUpdate:l,type:u,garage:d})=>{const{event:p,locale:m}=Pt(),[C,R]=S.useState(!1),g=YS({initialValues:{name:d.name||"",type:d.type||"car",x:d.x,y:d.y,z:d.z,h:d.h,distance:d.distance||10,owners:d.owners?typeof d.owners=="string"?JSON.parse(d.owners||"[]"):d.owners:[]},onSubmit:async O=>{if(u==="edit")await fetch("https://jg-advancedgarages/edit-private-garage",{method:"POST",headers:{"Content-Type":"application/json; charset=UTF-8"},body:JSON.stringify({...O,id:d.id})}),l(O);else if(u==="add"){if(p.garages.find(({name:z})=>z===O.name)||!await Jt("is-garage-name-available",{name:O.name}))return g.setErrors({name:m.garageNameExistsError});const Q=await(await fetch("https://jg-advancedgarages/create-private-garage",{method:"POST",headers:{"Content-Type":"application/json; charset=UTF-8"},body:JSON.stringify(O)})).json();l({...O,id:Q.id}),g.resetForm({})}i()}}),P=async()=>{const O=await Jt("get-current-coords");g.setFieldValue("x",O.x),g.setFieldValue("y",O.y),g.setFieldValue("z",O.z),g.setFieldValue("h",O.h)};return f.jsxs($e,{show:r,onHide:i,size:"lg",centered:!0,style:{zIndex:9999},children:[f.jsx($e.Header,{closeButton:!0,children:f.jsx($e.Title,{as:"h5",children:u==="edit"?m.editPrivateGarage:m.createPrivateGarage})}),f.jsx($e.Body,{children:f.jsxs(De,{onSubmit:g.handleSubmit,children:[f.jsxs(kc,{children:[f.jsx(ki,{children:f.jsxs(De.Group,{className:"mb-3",children:[f.jsx(De.Label,{children:m.garageName}),f.jsx(De.Control,{type:"text",id:"name",value:g.values.name,onChange:g.handleChange,isInvalid:!!g.touched.name&&!!g.errors.name,disabled:u==="edit",required:!0}),f.jsx(De.Control.Feedback,{type:"invalid",children:g.errors.name})]})}),f.jsxs(ki,{sm:3,children:[f.jsx(De.Label,{children:m.type}),f.jsxs(De.Select,{id:"type",name:"type",value:g.values.type,onChange:g.handleChange,children:[f.jsx("option",{value:"car",children:m.car}),f.jsx("option",{value:"sea",children:m.sea}),f.jsx("option",{value:"air",children:m.air})]})]})]}),f.jsxs(kc,{children:[f.jsx(ki,{children:f.jsxs(De.Group,{className:"mb-3",children:[f.jsxs("div",{className:"flex justify-between",children:[f.jsxs(De.Label,{children:[m.location," (x, y, z, heading)"]}),f.jsxs(at,{variant:"link",className:"p-0 leading-none !no-underline",size:"sm",onClick:P,children:[f.jsx("i",{className:"bi-geo"})," Get Location"]})]}),f.jsxs(Po,{children:[f.jsx(De.Control,{type:"number",id:"x",value:g.values.x,onChange:g.handleChange,placeholder:"x",required:!0}),f.jsx(De.Control,{type:"number",id:"y",value:g.values.y,onChange:g.handleChange,placeholder:"y",required:!0}),f.jsx(De.Control,{type:"number",id:"z",value:g.values.z,onChange:g.handleChange,placeholder:"z",required:!0}),f.jsx(De.Control,{type:"number",id:"h",value:g.values.h,onChange:g.handleChange,placeholder:"Heading",required:!0})]})]})}),f.jsx(ki,{sm:3,children:f.jsxs(De.Group,{className:"mb-3",children:[f.jsx(De.Label,{children:"Radius"}),f.jsx(De.Control,{type:"number",id:"distance",value:g.values.distance,onChange:g.handleChange,required:!0})]})})]}),f.jsxs(Vr,{className:"mb-3",children:[f.jsxs(Vr.Header,{className:"flex items-center justify-between",children:[f.jsx("div",{children:m.owners}),f.jsx(at,{variant:"dark",className:"!p-0 !leading-none !text-2xl text-white",size:"sm",onClick:()=>R(!0),children:f.jsx("i",{className:"bi-plus "})})]}),f.jsxs(Vr.Body,{children:[g.values.owners.length?f.jsxs("table",{style:{width:"100%"},children:[f.jsx("thead",{children:f.jsxs("tr",{children:[f.jsx("th",{children:m.identifier}),f.jsx("th",{children:m.name}),f.jsx("th",{})]})}),f.jsx("tbody",{children:g.values.owners.map(({identifier:O,name:I})=>f.jsxs("tr",{children:[f.jsx("td",{style:{maxWidth:"20px",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},children:f.jsx("code",{children:O})}),f.jsx("td",{children:I}),f.jsx("td",{style:{float:"right"},children:f.jsxs(at,{size:"sm",variant:"danger",onClick:()=>g.setFieldValue("owners",g.values.owners.filter(Q=>Q.identifier!==O)),children:[f.jsx("i",{className:"bi-trash me-2"}),"Remove"]})})]},O))})]}):m.noPlayers,f.jsx(i1,{show:C,onHide:()=>R(!1),currentOwners:g.values.owners,onAddOwner:O=>g.setFieldValue("owners",[O,...g.values.owners])})]})]}),f.jsx(at,{type:"submit",children:m.save})]})})]})},l1=({show:r,onHide:i,onConfirm:l})=>{const{locale:u}=Pt();return f.jsxs($e,{size:"sm",show:r,onHide:i,centered:!0,style:{zIndex:9999},children:[f.jsx($e.Header,{closeButton:!0,children:f.jsx($e.Title,{as:"h5",children:u.delete})}),f.jsxs($e.Body,{children:[f.jsx("p",{children:u.garageDeleteConfirm}),f.jsxs("div",{className:"d-flex gap-2",children:[f.jsx(at,{onClick:l,variant:"danger",children:"Confirm"}),f.jsx(at,{onClick:i,variant:"dark",children:"Cancel"})]})]})]})},a1=({garage:r,updateGarage:i,deleteGarage:l})=>{var P;const{locale:u}=Pt(),[d,p]=S.useState(!1),[m,C]=S.useState(!1),R=typeof(r==null?void 0:r.owners)=="string"?JSON.parse((r==null?void 0:r.owners)||"[]"):r==null?void 0:r.owners,g=async()=>{l(),await Jt("delete-private-garage",{id:r.id,name:r.name,owners:R})};return f.jsxs("tr",{children:[f.jsx("td",{className:"align-middle",children:r.name}),f.jsx("td",{className:"align-middle",children:R!=null&&R.length?(P=R==null?void 0:R.map(({name:O})=>O))==null?void 0:P.join(", "):"-"}),f.jsxs("td",{className:"align-middle d-flex gap-2 justify-content-end",children:[f.jsxs(at,{onClick:()=>p(!0),size:"sm",variant:"dark",children:[f.jsx("i",{className:"bi-pencil me-1"})," ",u.edit]}),f.jsx(Ah,{type:"edit",show:d,onHide:()=>p(!1),garage:r,onUpdate:O=>i({...r,...O})}),f.jsxs(at,{onClick:()=>C(!0),size:"sm",variant:"danger",children:[f.jsx("i",{className:"bi-trash me-1"})," ",u.delete]}),f.jsx(l1,{show:m,onHide:()=>C(!1),onConfirm:g})]})]})},s1=({data:r,columns:i,setGarages:l})=>{const{locale:u}=Pt(),{getTableProps:d,getTableBodyProps:p,headerGroups:m,page:C,canPreviousPage:R,canNextPage:g,pageOptions:P,nextPage:O,previousPage:I,setPageSize:Q,state:{pageIndex:z,pageSize:J}}=Np.useTable({columns:i,data:r,autoResetPage:!1,autoResetFilters:!1},Np.usePagination);return f.jsxs("div",{children:[f.jsxs(Ty,{hover:!0,className:"bootstrap-table",...d(),children:[f.jsx("thead",{children:m.map(V=>f.jsx("tr",{...V.getHeaderGroupProps(),children:V.headers.map(ce=>f.jsx("th",{...ce.getHeaderProps(),children:ce.render("Header")}))}))}),f.jsx("tbody",{...p(),children:C.length?C.map(V=>f.jsx(a1,{garage:V.original,updateGarage:ce=>l(oe=>oe.map(se=>se.id===V.original.id?ce:se)),deleteGarage:()=>l(ce=>ce.filter(({id:oe})=>oe!==V.original.id))},V.original.id)):f.jsx("tr",{children:f.jsx("td",{colSpan:100,align:"center",children:u.noPrivateGarages})})})]}),f.jsxs("div",{className:"pagination d-flex justify-content-center gap-4",children:[f.jsx(at,{variant:"dark",onClick:()=>I(),disabled:!R,children:f.jsx("i",{className:"bi-chevron-left"})}),f.jsxs("div",{className:"d-flex align-items-center",children:[f.jsxs("span",{className:"me-3",children:[u.page," ",z+1," ",u.of," ",P.length]}),f.jsx(De.Select,{size:"sm",value:J,onChange:V=>{Q(Number(V.target.value))},style:{width:110},children:[10,20,30,40,50].map(V=>f.jsxs("option",{value:V,children:[u.show," ",V]},V))})]}),f.jsx(at,{variant:"dark",onClick:()=>O(),disabled:!g,children:f.jsx("i",{className:"bi-chevron-right"})})]})]})},u1=()=>{const{event:r,locale:i,onCloseModal:l,config:u}=Pt(),[d,p]=S.useState([]),[m,C]=S.useState(""),[R,g]=S.useState(!1);S.useEffect(()=>{r.garages&&p(r.garages||[])},[r.garages]);const P=S.useMemo(()=>(d==null?void 0:d.filter(({name:I,owners:Q})=>{const z=m.toLocaleLowerCase().split(" ").filter(J=>J).map(J=>J.trim());return z.filter(J=>`${I} ${Q}`.toLocaleLowerCase().includes(J)).length===z.length}))||[],[d,m]),O=S.useMemo(()=>[{Header:i==null?void 0:i.garageName,accessor:"name"},{Header:i==null?void 0:i.owners,accessor:"owners"},{Header:"",accessor:"_"}],[i]);return r.type!=="showPrivGarages"?null:f.jsxs($e,{show:!0,onHide:l,backdrop:!1,centered:!0,size:"xl",children:[f.jsx($e.Header,{closeButton:!0,children:f.jsx($e.Title,{as:"h5",children:i.createPrivateGarage})}),f.jsxs($e.Body,{className:"p-0 pb-0",children:[f.jsxs("div",{className:"search-bar p-3 d-flex gap-3",children:[f.jsxs(Po,{children:[f.jsx(Po.Text,{children:f.jsx("i",{className:"bi-search"})}),f.jsx(De.Control,{type:"search",value:m,onChange:I=>C(I.target.value),placeholder:i.privGarageSearch})]}),f.jsxs(at,{variant:"primary",className:"flex-shrink-0",onClick:()=>g(!0),children:[f.jsx("i",{className:"bi-plus-lg me-1"})," ",i.createPrivateGarage]})]}),f.jsx("div",{className:"p-3 pt-0",children:f.jsx(s1,{columns:O,data:P,setGarages:p})}),f.jsx(Ah,{type:"add",show:R,onHide:()=>g(!1),garage:{},onUpdate:I=>p(Q=>[I,...Q])})]}),!u.HideWatermark&&f.jsx($e.Footer,{children:f.jsx(ps,{})})]})},c1=()=>{const{event:r}=Pt();return r.type!=="show-interior-vehicle"?null:f.jsx(Gc.Provider,{value:{},children:f.jsx("div",{className:"modal show",style:{display:"block",padding:0,top:30},children:f.jsxs($e.Dialog,{children:[f.jsx($e.Header,{children:f.jsx(Wc,{vehicle:r.vehicle})}),f.jsx($e.Body,{children:f.jsx(oh,{vehicle:r.vehicle})})]})})})},d1=()=>{const[r,i]=S.useState({}),[l,u]=S.useState({}),[d,p]=S.useState({});S.useEffect(()=>{const R=({data:g})=>{g.source||(g.type==="hide"?i(P=>({...P,type:!1})):r.type!=="show-tablet"&&g.instructionText?i({type:"show-instruction-text",...g}):g.type?(i(g||{}),u(g.config||{}),p(g.locale||{})):(i(P=>({...P,...g})),g.locale&&p(g.locale)))};return window.addEventListener("message",R),()=>window.removeEventListener("message",R)},[r]);const m=async()=>{i({...r,type:!1}),await Jt("close")};return f.jsx(am.Provider,{value:{event:r,setEvent:i,config:l,locale:d,onCloseModal:m},children:f.jsxs("div",{className:"jg-container",children:[!1,f.jsx($y,{}),f.jsx(Dy,{}),f.jsx(By,{}),f.jsx(zy,{}),f.jsx(u1,{}),f.jsx(c1,{})]})})};Hv.createRoot(document.getElementById("root")).render(f.jsx(tr.StrictMode,{children:f.jsx(d1,{})}))});export default f1(); diff --git a/resources/[carscripts]/jg-advancedgarages/web/dist/assets/index-DURuzDZl.css b/resources/[carscripts]/jg-advancedgarages/web/dist/assets/index-DURuzDZl.css new file mode 100644 index 000000000..d5b0945e1 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/web/dist/assets/index-DURuzDZl.css @@ -0,0 +1,5 @@ +@charset "UTF-8";@import"https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&display=swap";@import"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css";*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.fixed{position:fixed}.m-0{margin:0}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.me-1{margin-inline-end:.25rem}.me-2{margin-inline-end:.5rem}.me-3{margin-inline-end:.75rem}.mr-3{margin-right:.75rem}.ms-1{margin-inline-start:.25rem}.ms-5{margin-inline-start:1.25rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.block{display:block}.flex{display:flex}.table{display:table}.hidden{display:none}.w-full{width:100%}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.border{border-width:1px}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.\!p-0{padding:0!important}.p-0{padding:0}.p-1{padding:.25rem}.p-3{padding:.75rem}.pb-0{padding-bottom:0}.pb-2{padding-bottom:.5rem}.pe-3{padding-inline-end:.75rem}.pt-0{padding-top:0}.text-center{text-align:center}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.\!text-2xl{font-size:1.5rem!important;line-height:2rem!important}.text-lg{font-size:1.125rem;line-height:1.75rem}.\!leading-none{line-height:1!important}.leading-7{line-height:1.75rem}.leading-none{line-height:1}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.\!no-underline{text-decoration-line:none!important}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}/*! +* Bootstrap v5.3.0 (https://getbootstrap.com/) +* Copyright 2011-2023 The Bootstrap Authors +* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) +*/:root,[data-bs-theme=light]{--bs-blue: #0d6efd;--bs-indigo: #6610f2;--bs-purple: #6f42c1;--bs-pink: #d63384;--bs-red: #dc3545;--bs-orange: #fd7e14;--bs-yellow: #ffc107;--bs-green: #198754;--bs-teal: #20c997;--bs-cyan: #0dcaf0;--bs-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-primary: #0d6efd;--bs-secondary: #6c757d;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-primary-rgb: 13, 110, 253;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: #052c65;--bs-secondary-text-emphasis: #2b2f32;--bs-success-text-emphasis: #0a3622;--bs-info-text-emphasis: #055160;--bs-warning-text-emphasis: #664d03;--bs-danger-text-emphasis: #58151c;--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: #cfe2ff;--bs-secondary-bg-subtle: #e2e3e5;--bs-success-bg-subtle: #d1e7dd;--bs-info-bg-subtle: #cff4fc;--bs-warning-bg-subtle: #fff3cd;--bs-danger-bg-subtle: #f8d7da;--bs-light-bg-subtle: #fcfcfd;--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: #9ec5fe;--bs-secondary-border-subtle: #c4c8cb;--bs-success-border-subtle: #a3cfbb;--bs-info-border-subtle: #9eeaf9;--bs-warning-border-subtle: #ffe69c;--bs-danger-border-subtle: #f1aeb5;--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient( 180deg, rgba(255, 255, 255, .15), rgba(255, 255, 255, 0) );--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #fff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, .75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, .5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #0d6efd;--bs-link-color-rgb: 13, 110, 253;--bs-link-decoration: underline;--bs-link-hover-color: #0a58ca;--bs-link-hover-color-rgb: 10, 88, 202;--bs-code-color: #d63384;--bs-highlight-bg: #fff3cd;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, .175);--bs-border-radius: .375rem;--bs-border-radius-sm: .25rem;--bs-border-radius-lg: .5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-box-shadow-sm: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, .175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, .075);--bs-focus-ring-width: .25rem;--bs-focus-ring-opacity: .25;--bs-focus-ring-color: rgba(13, 110, 253, .25);--bs-form-valid-color: #198754;--bs-form-valid-border-color: #198754;--bs-form-invalid-color: #dc3545;--bs-form-invalid-border-color: #dc3545}[data-bs-theme=dark]{--bs-body-color: #adb5bd;--bs-body-color-rgb: 173, 181, 189;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(173, 181, 189, .75);--bs-secondary-color-rgb: 173, 181, 189;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(173, 181, 189, .5);--bs-tertiary-color-rgb: 173, 181, 189;--bs-tertiary-bg: #2b3035;--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: #6ea8fe;--bs-secondary-text-emphasis: #a7acb1;--bs-success-text-emphasis: #75b798;--bs-info-text-emphasis: #6edff6;--bs-warning-text-emphasis: #ffda6a;--bs-danger-text-emphasis: #ea868f;--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: #031633;--bs-secondary-bg-subtle: #161719;--bs-success-bg-subtle: #051b11;--bs-info-bg-subtle: #032830;--bs-warning-bg-subtle: #332701;--bs-danger-bg-subtle: #2c0b0e;--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: #084298;--bs-secondary-border-subtle: #41464b;--bs-success-border-subtle: #0f5132;--bs-info-border-subtle: #087990;--bs-warning-border-subtle: #997404;--bs-danger-border-subtle: #842029;--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: #6ea8fe;--bs-link-hover-color: #8bb9fe;--bs-link-color-rgb: 110, 168, 254;--bs-link-hover-color-rgb: 139, 185, 254;--bs-code-color: #e685b5;--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, .15);--bs-form-valid-color: #75b798;--bs-form-valid-border-color: #75b798;--bs-form-invalid-color: #ea868f;--bs-form-invalid-border-color: #ea868f}*,:after,:before{box-sizing:border-box}@media (prefers-reduced-motion: no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width: 1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width: 1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width: 1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width: 1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity, 1));text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled,.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer:before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width: 576px){.container,.container-sm{max-width:540px}}@media (min-width: 768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width: 992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width: 1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width: 1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.row{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x: 0}.g-0,.gy-0{--bs-gutter-y: 0}.g-1,.gx-1{--bs-gutter-x: .25rem}.g-1,.gy-1{--bs-gutter-y: .25rem}.g-2,.gx-2{--bs-gutter-x: .5rem}.g-2,.gy-2{--bs-gutter-y: .5rem}.g-3,.gx-3{--bs-gutter-x: 1rem}.g-3,.gy-3{--bs-gutter-y: 1rem}.g-4,.gx-4{--bs-gutter-x: 1.5rem}.g-4,.gy-4{--bs-gutter-y: 1.5rem}.g-5,.gx-5{--bs-gutter-x: 3rem}.g-5,.gy-5{--bs-gutter-y: 3rem}@media (min-width: 576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x: 0}.g-sm-0,.gy-sm-0{--bs-gutter-y: 0}.g-sm-1,.gx-sm-1{--bs-gutter-x: .25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y: .25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x: .5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y: .5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x: 1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y: 1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x: 1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y: 1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x: 3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y: 3rem}}@media (min-width: 768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x: 0}.g-md-0,.gy-md-0{--bs-gutter-y: 0}.g-md-1,.gx-md-1{--bs-gutter-x: .25rem}.g-md-1,.gy-md-1{--bs-gutter-y: .25rem}.g-md-2,.gx-md-2{--bs-gutter-x: .5rem}.g-md-2,.gy-md-2{--bs-gutter-y: .5rem}.g-md-3,.gx-md-3{--bs-gutter-x: 1rem}.g-md-3,.gy-md-3{--bs-gutter-y: 1rem}.g-md-4,.gx-md-4{--bs-gutter-x: 1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y: 1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x: 3rem}.g-md-5,.gy-md-5{--bs-gutter-y: 3rem}}@media (min-width: 992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x: 0}.g-lg-0,.gy-lg-0{--bs-gutter-y: 0}.g-lg-1,.gx-lg-1{--bs-gutter-x: .25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y: .25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x: .5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y: .5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x: 1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y: 1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x: 1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y: 1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x: 3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y: 3rem}}@media (min-width: 1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x: 0}.g-xl-0,.gy-xl-0{--bs-gutter-y: 0}.g-xl-1,.gx-xl-1{--bs-gutter-x: .25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y: .25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x: .5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y: .5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x: 1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y: 1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x: 1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y: 1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x: 3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y: 3rem}}@media (min-width: 1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x: 0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y: 0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x: .25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y: .25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x: .5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y: .5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x: 1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y: 1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x: 1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y: 1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x: 3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y: 3rem}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: var(--bs-body-color);--bs-table-bg: var(--bs-body-bg);--bs-table-border-color: var(--bs-border-color);--bs-table-accent-bg: transparent;--bs-table-striped-color: var(--bs-body-color);--bs-table-striped-bg: rgba(0, 0, 0, .05);--bs-table-active-color: var(--bs-body-color);--bs-table-active-bg: rgba(0, 0, 0, .1);--bs-table-hover-color: var(--bs-body-color);--bs-table-hover-bg: rgba(0, 0, 0, .075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #cfe2ff;--bs-table-border-color: #bacbe6;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #cbccce;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d1e7dd;--bs-table-border-color: #bcd0c7;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #cff4fc;--bs-table-border-color: #badce3;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff3cd;--bs-table-border-color: #e6dbb9;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #f8d7da;--bs-table-border-color: #dfc2c4;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #212529;--bs-table-border-color: #373b3e;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #fff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #fff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + var(--bs-border-width) * 2);padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + var(--bs-border-width) * 2);padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + var(--bs-border-width) * 2)}textarea.form-control-sm{min-height:calc(1.5em + .5rem + var(--bs-border-width) * 2)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + var(--bs-border-width) * 2)}.form-control-color{width:3rem;height:calc(1.5em + .75rem + var(--bs-border-width) * 2);padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + var(--bs-border-width) * 2)}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + var(--bs-border-width) * 2)}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23adb5bd' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg: var(--bs-body-bg);width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem #0d6efd40}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem #0d6efd40}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-tertiary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-tertiary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + var(--bs-border-width) * 2);min-height:calc(3.5rem + var(--bs-border-width) * 2);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label:after{position:absolute;top:1rem;right:.375rem;bottom:1rem;left:.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control-plaintext~label:after,.form-floating>.form-control:focus~label:after,.form-floating>.form-control:not(:placeholder-shown)~label:after,.form-floating>.form-select~label:after{position:absolute;top:1rem;right:.375rem;bottom:1rem;left:.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>:disabled~label{color:#6c757d}.form-floating>:disabled~label:after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3.75rem + 1.5em)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3.75rem + 1.5em)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x: .75rem;--bs-btn-padding-y: .375rem;--bs-btn-font-family: ;--bs-btn-font-size: 1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: var(--bs-body-color);--bs-btn-bg: transparent;--bs-btn-border-width: var(--bs-border-width);--bs-btn-border-color: transparent;--bs-btn-border-radius: var(--bs-border-radius);--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);--bs-btn-disabled-opacity: .65;--bs-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color: #fff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #0b5ed7;--bs-btn-hover-border-color: #0a58ca;--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: #0a58ca;--bs-btn-active-border-color: #0a53be;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #fff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #fff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #157347;--bs-btn-hover-border-color: #146c43;--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #fff;--bs-btn-active-bg: #146c43;--bs-btn-active-border-color: #13653f;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #31d2f2;--bs-btn-hover-border-color: #25cff2;--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: #3dd5f3;--bs-btn-active-border-color: #25cff2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffca2c;--bs-btn-hover-border-color: #ffc720;--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffcd39;--bs-btn-active-border-color: #ffc720;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #fff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #bb2d3b;--bs-btn-hover-border-color: #b02a37;--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #fff;--bs-btn-active-bg: #b02a37;--bs-btn-active-border-color: #a52834;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #fff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #fff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #fff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #fff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: var(--bs-link-color);--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: var(--bs-link-hover-color);--bs-btn-hover-border-color: transparent;--bs-btn-active-color: var(--bs-link-hover-color);--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y: .5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size: 1.25rem;--bs-btn-border-radius: var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y: .25rem;--bs-btn-padding-x: .5rem;--bs-btn-font-size: .875rem;--bs-btn-border-radius: var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty:after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: .5rem;--bs-dropdown-spacer: .125rem;--bs-dropdown-font-size: 1rem;--bs-dropdown-color: var(--bs-body-color);--bs-dropdown-bg: var(--bs-body-bg);--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-border-radius: var(--bs-border-radius);--bs-dropdown-border-width: var(--bs-border-width);--bs-dropdown-inner-border-radius: calc( var(--bs-border-radius) - var(--bs-border-width) );--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y: .5rem;--bs-dropdown-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-dropdown-link-color: var(--bs-body-color);--bs-dropdown-link-hover-color: var(--bs-body-color);--bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: var(--bs-tertiary-color);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: .25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: .5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-toggle:after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";display:none}.dropstart .dropdown-toggle:before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty:after{margin-left:0}.dropstart .dropdown-toggle:before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius, 0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, .15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split:after,.dropend .dropdown-toggle-split:after,.dropup .dropdown-toggle-split:after{margin-left:0}.dropstart .dropdown-toggle-split:before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: .5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-link-color);--bs-nav-link-hover-color: var(--bs-link-hover-color);--bs-nav-link-disabled-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.nav-link.disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: var(--bs-border-width);--bs-nav-tabs-border-color: var(--bs-border-color);--bs-nav-tabs-border-radius: var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color: var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg: var(--bs-body-bg);--bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.disabled,.nav-tabs .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: var(--bs-border-radius);--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: .125rem;--bs-nav-underline-link-active-color: var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: .5rem;--bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), .65);--bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), .8);--bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), .3);--bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y: .3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x: .5rem;--bs-navbar-toggler-padding-y: .25rem;--bs-navbar-toggler-padding-x: .75rem;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), .15);--bs-navbar-toggler-border-radius: var(--bs-border-radius);--bs-navbar-toggler-focus-width: .25rem;--bs-navbar-toggler-transition: box-shadow .15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: .5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media (min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: rgba(255, 255, 255, .55);--bs-navbar-hover-color: rgba(255, 255, 255, .75);--bs-navbar-disabled-color: rgba(255, 255, 255, .25);--bs-navbar-active-color: #fff;--bs-navbar-brand-color: #fff;--bs-navbar-brand-hover-color: #fff;--bs-navbar-toggler-border-color: rgba(255, 255, 255, .1);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: .5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: var(--bs-border-width);--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc( var(--bs-border-radius) - (var(--bs-border-width)) );--bs-card-cap-padding-y: .5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(var(--bs-body-color-rgb), .03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: var(--bs-body-bg);--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: .75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width: 576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: var(--bs-body-color);--bs-accordion-bg: var(--bs-body-bg);--bs-accordion-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out, border-radius .15s ease;--bs-accordion-border-color: var(--bs-border-color);--bs-accordion-border-width: var(--bs-border-width);--bs-accordion-border-radius: var(--bs-border-radius);--bs-accordion-inner-border-radius: calc( var(--bs-border-radius) - (var(--bs-border-width)) );--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: var(--bs-body-color);--bs-accordion-btn-bg: var(--bs-accordion-bg);--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform .2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #86b7fe;--bs-accordion-btn-focus-box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: var(--bs-primary-text-emphasis);--bs-accordion-active-bg: var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed):after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button:after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion: reduce){.accordion-button:after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button:after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: var(--bs-secondary-color);--bs-breadcrumb-item-padding-x: .5rem;--bs-breadcrumb-item-active-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item:before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: .75rem;--bs-pagination-padding-y: .375rem;--bs-pagination-font-size: 1rem;--bs-pagination-color: var(--bs-link-color);--bs-pagination-bg: var(--bs-body-bg);--bs-pagination-border-width: var(--bs-border-width);--bs-pagination-border-color: var(--bs-border-color);--bs-pagination-border-radius: var(--bs-border-radius);--bs-pagination-hover-color: var(--bs-link-hover-color);--bs-pagination-hover-bg: var(--bs-tertiary-bg);--bs-pagination-hover-border-color: var(--bs-border-color);--bs-pagination-focus-color: var(--bs-link-hover-color);--bs-pagination-focus-bg: var(--bs-secondary-bg);--bs-pagination-focus-box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: var(--bs-secondary-color);--bs-pagination-disabled-bg: var(--bs-secondary-bg);--bs-pagination-disabled-border-color: var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: .75rem;--bs-pagination-font-size: 1.25rem;--bs-pagination-border-radius: var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x: .5rem;--bs-pagination-padding-y: .25rem;--bs-pagination-font-size: .875rem;--bs-pagination-border-radius: var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x: .65em;--bs-badge-padding-y: .35em;--bs-badge-font-size: .75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius: var(--bs-border-radius);--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size: .75rem;--bs-progress-bg: var(--bs-secondary-bg);--bs-progress-border-radius: var(--bs-border-radius);--bs-progress-box-shadow: var(--bs-box-shadow-inset);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width .6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: var(--bs-body-color);--bs-list-group-bg: var(--bs-body-bg);--bs-list-group-border-color: var(--bs-border-color);--bs-list-group-border-width: var(--bs-border-width);--bs-list-group-border-radius: var(--bs-border-radius);--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: .5rem;--bs-list-group-action-color: var(--bs-secondary-color);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-tertiary-bg);--bs-list-group-action-active-color: var(--bs-body-color);--bs-list-group-action-active-bg: var(--bs-secondary-bg);--bs-list-group-disabled-color: var(--bs-secondary-color);--bs-list-group-disabled-bg: var(--bs-body-bg);--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item:before{content:counters(section,".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width: 576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: .5;--bs-btn-close-hover-opacity: .75;--bs-btn-close-focus-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: .25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white,[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: .75rem;--bs-toast-padding-y: .5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size: .875rem;--bs-toast-color: ;--bs-toast-bg: rgba(var(--bs-body-bg-rgb), .85);--bs-toast-border-width: var(--bs-border-width);--bs-toast-border-color: var(--bs-border-color-translucent);--bs-toast-border-radius: var(--bs-border-radius);--bs-toast-box-shadow: var(--bs-box-shadow);--bs-toast-header-color: var(--bs-secondary-color);--bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), .85);--bs-toast-header-border-color: var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: .5rem;--bs-modal-color: ;--bs-modal-bg: var(--bs-body-bg);--bs-modal-border-color: var(--bs-border-color-translucent);--bs-modal-border-width: var(--bs-border-width);--bs-modal-border-radius: var(--bs-border-radius-lg);--bs-modal-box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-modal-inner-border-radius: calc( var(--bs-border-radius-lg) - (var(--bs-border-width)) );--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: var(--bs-border-color);--bs-modal-header-border-width: var(--bs-border-width);--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: .5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: var(--bs-border-color);--bs-modal-footer-border-width: var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translateY(-50px)}@media (prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: .5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media (min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media (min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: .5rem;--bs-tooltip-padding-y: .25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size: .875rem;--bs-tooltip-color: var(--bs-body-bg);--bs-tooltip-bg: var(--bs-emphasis-color);--bs-tooltip-border-radius: var(--bs-border-radius);--bs-tooltip-opacity: .9;--bs-tooltip-arrow-width: .8rem;--bs-tooltip-arrow-height: .4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow:before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow:before,.bs-tooltip-top .tooltip-arrow:before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow:before,.bs-tooltip-end .tooltip-arrow:before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow:before,.bs-tooltip-bottom .tooltip-arrow:before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow:before,.bs-tooltip-start .tooltip-arrow:before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size: .875rem;--bs-popover-bg: var(--bs-body-bg);--bs-popover-border-width: var(--bs-border-width);--bs-popover-border-color: var(--bs-border-color-translucent);--bs-popover-border-radius: var(--bs-border-radius-lg);--bs-popover-inner-border-radius: calc( var(--bs-border-radius-lg) - var(--bs-border-width) );--bs-popover-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: .5rem;--bs-popover-header-font-size: 1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: var(--bs-secondary-bg);--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: var(--bs-body-color);--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: .5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow:after,.popover .popover-arrow:before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before,.bs-popover-top>.popover-arrow:after,.bs-popover-top>.popover-arrow:before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before,.bs-popover-top>.popover-arrow:before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after,.bs-popover-top>.popover-arrow:after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before,.bs-popover-end>.popover-arrow:after,.bs-popover-end>.popover-arrow:before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before,.bs-popover-end>.popover-arrow:before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after,.bs-popover-end>.popover-arrow:after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before,.bs-popover-bottom>.popover-arrow:after,.bs-popover-bottom>.popover-arrow:before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before,.bs-popover-bottom>.popover-arrow:before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after,.bs-popover-bottom>.popover-arrow:after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header:before,.bs-popover-bottom .popover-header:before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before,.bs-popover-start>.popover-arrow:after,.bs-popover-start>.popover-arrow:before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before,.bs-popover-start>.popover-arrow:before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after,.bs-popover-start>.popover-arrow:after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner:after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translate(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translate(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion: reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -.125em;--bs-spinner-border-width: .25em;--bs-spinner-animation-speed: .75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: .2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -.125em;--bs-spinner-animation-speed: .75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media (prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: var(--bs-body-color);--bs-offcanvas-bg: var(--bs-body-bg);--bs-offcanvas-border-width: var(--bs-border-width);--bs-offcanvas-border-color: var(--bs-border-color-translucent);--bs-offcanvas-box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-offcanvas-transition: transform .3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media (max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 575.98px) and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 767.98px) and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 991.98px) and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn:before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,#000c,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{to{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix:after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(13,110,253,var(--bs-bg-opacity, 1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(108,117,125,var(--bs-bg-opacity, 1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(25,135,84,var(--bs-bg-opacity, 1))!important}.text-bg-info{color:#000!important;background-color:RGBA(13,202,240,var(--bs-bg-opacity, 1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(255,193,7,var(--bs-bg-opacity, 1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(220,53,69,var(--bs-bg-opacity, 1))!important}.text-bg-light{color:#000!important;background-color:RGBA(248,249,250,var(--bs-bg-opacity, 1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(33,37,41,var(--bs-bg-opacity, 1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity, 1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity, 1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity, 1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity, 1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity, 1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity, 1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity, 1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity, 1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity, 1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity, 1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity, 1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity, 1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity, 1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity, 1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity, 1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity, 1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity, 1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity, .75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity, .75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity, .5));text-underline-offset:.25em;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform, translate3d(.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio:before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media (min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link:after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem #00000026!important}.shadow-sm{box-shadow:0 .125rem .25rem #00000013!important}.shadow-lg{box-shadow:0 1rem 3rem #0000002d!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color: rgba( var(--bs-primary-rgb), var(--bs-focus-ring-opacity) )}.focus-ring-secondary{--bs-focus-ring-color: rgba( var(--bs-secondary-rgb), var(--bs-focus-ring-opacity) )}.focus-ring-success{--bs-focus-ring-color: rgba( var(--bs-success-rgb), var(--bs-focus-ring-opacity) )}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba( var(--bs-warning-rgb), var(--bs-focus-ring-opacity) )}.focus-ring-danger{--bs-focus-ring-color: rgba( var(--bs-danger-rgb), var(--bs-focus-ring-opacity) )}.focus-ring-light{--bs-focus-ring-color: rgba( var(--bs-light-rgb), var(--bs-focus-ring-opacity) )}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translate(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity: .1}.border-opacity-25{--bs-border-opacity: .25}.border-opacity-50{--bs-border-opacity: .5}.border-opacity-75{--bs-border-opacity: .75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity: 1;color:#00000080!important}.text-white-50{--bs-text-opacity: 1;color:#ffffff80!important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity: 1;color:inherit!important}.text-opacity-25{--bs-text-opacity: .25}.text-opacity-50{--bs-text-opacity: .5}.text-opacity-75{--bs-text-opacity: .75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10,.link-opacity-10-hover:hover{--bs-link-opacity: .1}.link-opacity-25,.link-opacity-25-hover:hover{--bs-link-opacity: .25}.link-opacity-50,.link-opacity-50-hover:hover{--bs-link-opacity: .5}.link-opacity-75,.link-opacity-75-hover:hover{--bs-link-opacity: .75}.link-opacity-100,.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1,.link-offset-1-hover:hover{text-underline-offset:.125em!important}.link-offset-2,.link-offset-2-hover:hover{text-underline-offset:.25em!important}.link-offset-3,.link-offset-3-hover:hover{text-underline-offset:.375em!important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity, 1))!important}.link-underline-opacity-0,.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10,.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: .1}.link-underline-opacity-25,.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: .25}.link-underline-opacity-50,.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: .5}.link-underline-opacity-75,.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: .75}.link-underline-opacity-100,.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity: 1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity: .1}.bg-opacity-25{--bs-bg-opacity: .25}.bg-opacity-50{--bs-bg-opacity: .5}.bg-opacity-75{--bs-bg-opacity: .75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width: 576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width: 768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width: 992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width: 1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width: 1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width: 1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}}*{box-sizing:border-box}html,body{font-family:Plus Jakarta Sans,sans-serif!important;background:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.jg-container{position:absolute;width:100vw;height:100vh}body,#root,.dev-bg{overflow:hidden!important}::-webkit-scrollbar{width:15px;height:15px;border-radius:10px;overflow:hidden}::-webkit-scrollbar-track{background-color:var(--bs-dark-border-subtle)}::-webkit-scrollbar-track-piece{background-color:var(--bs-dark)}::-webkit-scrollbar-thumb{height:50px;background-color:var(--bs-dark-border-subtle);border-radius:100px;border:4px solid var(--bs-dark)}::-webkit-scrollbar-corner{background-color:var(--bs-dark-border-subtle)}::-webkit-resizer{background-color:var(--bs-dark-border-subtle)}.dev-bg{width:100vw;height:100vh;background:#000;background-size:cover;background-position:50% 50%;position:absolute;overflow:none!important}.dev-menu{position:fixed;top:0;left:0}.modal-content{border-radius:10px!important}.modal-header{border-radius:10px 10px 0 0!important}.modal-footer{border-radius:0 0 10px 10px!important}.accordion-button{box-shadow:none!important}.accordion-button:not(.collapsed){background-color:var(--bs-tertiary-bg)!important;color:#fff!important}.accordion-item{border:none!important}.edit-vehicle-name{opacity:0!important}.vehicle-acc-header:hover .edit-vehicle-name{opacity:1!important}.edit-vehicle-name-input{border:1px dashed #999;outline:none;background-color:transparent;color:#fff;padding:5px 7px;border-radius:5px;width:400px}.search-bar{position:sticky;top:0;z-index:99;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.finance-container{height:20px}.finance-progress-bar{margin:5px;position:relative;width:calc(100% - 5px);height:4px;background:#555}.finance-progress-bar-inner{position:absolute;left:0;max-width:100%;height:4px}.finance-progress-bar .points-container{display:flex;justify-content:space-between}.finance-progress-bar .point{position:relative;width:18px;height:18px;background-color:#fff;border-radius:100%;margin-top:-6px;margin-left:-3px;z-index:1}.finance-progress-bar .point i{position:absolute;top:-1px;left:-1px;line-height:0;font-size:20px;color:#555}.modal-backdrop.show{z-index:9999!important}.garage-row-image{width:70px;height:50px;margin-right:10px;background-size:contain;background-position:50% 50%;background-repeat:no-repeat} diff --git a/resources/[carscripts]/jg-advancedgarages/web/dist/index.html b/resources/[carscripts]/jg-advancedgarages/web/dist/index.html new file mode 100644 index 000000000..c1d432a29 --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/web/dist/index.html @@ -0,0 +1,14 @@ + + + + + + + jg-advancedgarages-web + + + + +
+ + diff --git a/resources/[carscripts]/jg-advancedgarages/web/dist/vite.svg b/resources/[carscripts]/jg-advancedgarages/web/dist/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/resources/[carscripts]/jg-advancedgarages/web/dist/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file