From 3404fb987502c97add63f8d8d30036e5007f4bc9 Mon Sep 17 00:00:00 2001 From: spaethf Date: Sat, 26 Sep 2026 23:24:14 +0200 Subject: [PATCH] Release 1.1.0: QR-Reportimport, Regal-Auswahlmodal, Einlagern/Auslagern-Verknuepfungen aus Reifenlager, Stabilitaetsfixes --- Lagerbestand/Components/App.razor | 1 + .../Components/Pages/StorageLocations.razor | 317 ++++++-- .../Pages/StorageLocations.razor.css | 377 +++++---- .../Components/Pages/TireCheckin.razor | 605 +++++++++++++- .../Components/Pages/TireCheckin.razor.css | 630 ++++++++++++++- .../Components/Pages/TireCheckout.razor | 428 +++++++++- .../Components/Pages/TireCheckout.razor.css | 363 ++++++++- .../Components/Pages/TireStorage.razor | 737 ++++++++++++----- .../Components/Pages/TireStorage.razor.css | 760 +++++++++++++----- .../Components/Shared/QrScannerModal.razor | 161 ++++ .../Shared/QrScannerModal.razor.css | 142 ++++ .../Shared/StorageLocationPickerModal.razor | 190 +++++ .../StorageLocationPickerModal.razor.css | 309 +++++++ Lagerbestand/Data/AppDbContext.cs | 28 +- Lagerbestand/Lagerbestand.csproj | 3 + Lagerbestand/Models/TireInspection.cs | 116 +++ Lagerbestand/Models/TireStack.cs | 14 +- Lagerbestand/Program.cs | 4 + Lagerbestand/Services/DatabaseInitializer.cs | 56 +- .../Services/StorageLocationService.cs | 19 +- Lagerbestand/Services/TireReportService.cs | 343 ++++++++ Lagerbestand/Services/TireStackService.cs | 154 +++- Lagerbestand/appsettings.json | 4 + Lagerbestand/wwwroot/js/qr-scanner.js | 88 ++ .../lib/html5-qrcode/html5-qrcode.min.js | 1 + 25 files changed, 5106 insertions(+), 744 deletions(-) create mode 100644 Lagerbestand/Components/Shared/QrScannerModal.razor create mode 100644 Lagerbestand/Components/Shared/QrScannerModal.razor.css create mode 100644 Lagerbestand/Components/Shared/StorageLocationPickerModal.razor create mode 100644 Lagerbestand/Components/Shared/StorageLocationPickerModal.razor.css create mode 100644 Lagerbestand/Models/TireInspection.cs create mode 100644 Lagerbestand/Services/TireReportService.cs create mode 100644 Lagerbestand/wwwroot/js/qr-scanner.js create mode 100644 Lagerbestand/wwwroot/lib/html5-qrcode/html5-qrcode.min.js diff --git a/Lagerbestand/Components/App.razor b/Lagerbestand/Components/App.razor index 9bf09c2..af41648 100644 --- a/Lagerbestand/Components/App.razor +++ b/Lagerbestand/Components/App.razor @@ -236,6 +236,7 @@ @* Blazor Framework - defer loading *@ + diff --git a/Lagerbestand/Components/Pages/StorageLocations.razor b/Lagerbestand/Components/Pages/StorageLocations.razor index f66eaa3..ac2c250 100644 --- a/Lagerbestand/Components/Pages/StorageLocations.razor +++ b/Lagerbestand/Components/Pages/StorageLocations.razor @@ -44,85 +44,54 @@ else -
-
- @allLocations.Count - Gesamt +
+
+ + + + +
-
- @allLocations.Count(l => !l.IsOccupied) - Frei -
-
- @allLocations.Count(l => l.IsOccupied) - Belegt -
-
- @allLocations.Count(l => l.Area == AreaType.Lager) - 🏭 Lager -
-
- @allLocations.Count(l => l.Area == AreaType.Werkstatt) - 🔧 Werkstatt -
-
-
-
- Gebäude -
- - - -
-
- -
- Reihe -
- -
-
- -
- Status -
- - - -
-
- -
- Suche +
+ + @if (viewMode == "grid") + { + + } + @if (HasActiveFilters) + { + + }
@@ -456,7 +425,85 @@ else { var ts = selectedLocation.OccupiedTireStack;
-

📦 Eingelagerter Reifenstapel

+
+

📦 Eingelagerter Reifenstapel

+ @if (!isEditingTireStack) + { + + } +
+ @if (isEditingTireStack && editTireStack != null) + { +
+
+ +
+ + + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ +
+ + +
+
+ @if (editTireStack.WithRims) + { +
+ + +
+ } +
+
+ + +
+
+ + +
+
+ } + else + {
@@ -486,6 +533,7 @@ else Eingelagert am @ts.StoredAt.ToLocalTime().ToString("dd.MM.yyyy") • @ts.DaysStored Tage
+ }
} @@ -677,6 +725,11 @@ else private StorageLocation? selectedLocation; private string? detailsError; + // Tire stack inline editing + private bool isEditingTireStack; + private bool isSavingTireStack; + private TireStack? editTireStack; + // Delete confirmation private bool showDeleteConfirm; private StorageLocation? locationToDelete; @@ -820,8 +873,44 @@ else ApplyFilter(); } - private void FilterByStatusAvailable() => FilterByStatus(StatusAvailable); - private void FilterByStatusOccupied() => FilterByStatus(StatusOccupied); + private void FilterByStatusAvailable() => FilterByStatus(statusFilter == StatusAvailable ? null : StatusAvailable); + private void FilterByStatusOccupied() => FilterByStatus(statusFilter == StatusOccupied ? null : StatusOccupied); + + private bool HasActiveFilters => + selectedArea != null || statusFilter != null || + !string.IsNullOrEmpty(selectedRow) || !string.IsNullOrEmpty(searchTerm); + + private void ResetFilters() + { + selectedArea = null; + statusFilter = null; + selectedRow = null; + searchTerm = ""; + ApplyFilter(); + } + + private bool allRowsCollapsed => + filteredLocations.Count > 0 && + filteredLocations.GroupBy(l => $"{l.Area}-{l.Row}").All(g => collapsedRows.Contains(g.Key)); + + private void ToggleAllRows() + { + var rowKeys = filteredLocations + .GroupBy(l => $"{l.Area}-{l.Row}") + .Select(g => g.Key) + .ToList(); + + if (allRowsCollapsed) + { + foreach (var key in rowKeys) + collapsedRows.Remove(key); + } + else + { + foreach (var key in rowKeys) + collapsedRows.Add(key); + } + } private void ApplyFilter() { @@ -869,6 +958,8 @@ else private async Task ShowLocationDetails(StorageLocation location) { detailsError = null; + isEditingTireStack = false; + editTireStack = null; selectedLocation = await StorageLocationService.GetByIdAsync(location.Id); } @@ -876,6 +967,78 @@ else { selectedLocation = null; detailsError = null; + isEditingTireStack = false; + editTireStack = null; + } + + private void StartEditTireStack() + { + var ts = selectedLocation?.OccupiedTireStack; + if (ts == null) return; + + // Edit a copy so cancel does not mutate the displayed entity + editTireStack = new TireStack + { + Id = ts.Id, + Season = ts.Season, + TireSize = ts.TireSize, + TireBrand = ts.TireBrand, + TireModel = ts.TireModel, + TreadDepth = ts.TreadDepth, + WithRims = ts.WithRims, + RimSize = ts.RimSize, + Notes = ts.Notes + }; + isEditingTireStack = true; + detailsError = null; + } + + private void CancelEditTireStack() + { + isEditingTireStack = false; + editTireStack = null; + } + + private async Task SaveTireStack() + { + if (editTireStack == null || selectedLocation == null) return; + + isSavingTireStack = true; + detailsError = null; + try + { + var stack = await TireStackService.GetByIdAsync(editTireStack.Id); + if (stack == null) + { + detailsError = "Reifenstapel nicht gefunden."; + return; + } + + stack.Season = editTireStack.Season; + stack.TireSize = editTireStack.TireSize; + stack.TireBrand = editTireStack.TireBrand; + stack.TireModel = editTireStack.TireModel; + stack.TreadDepth = editTireStack.TreadDepth; + stack.WithRims = editTireStack.WithRims; + stack.RimSize = editTireStack.WithRims ? editTireStack.RimSize : null; + stack.Notes = editTireStack.Notes; + + await TireStackService.UpdateAsync(stack); + + // Refresh modal + list so chips/season colors update everywhere + selectedLocation = await StorageLocationService.GetByIdAsync(selectedLocation.Id); + await LoadLocations(); + isEditingTireStack = false; + editTireStack = null; + } + catch (Exception ex) + { + detailsError = $"Fehler beim Speichern: {ex.Message}"; + } + finally + { + isSavingTireStack = false; + } } private async Task ShowAddLocation() diff --git a/Lagerbestand/Components/Pages/StorageLocations.razor.css b/Lagerbestand/Components/Pages/StorageLocations.razor.css index a76e481..f5277f3 100644 --- a/Lagerbestand/Components/Pages/StorageLocations.razor.css +++ b/Lagerbestand/Components/Pages/StorageLocations.razor.css @@ -39,8 +39,8 @@ .page-header { display: flex; flex-direction: column; - gap: 0.75rem; - margin-bottom: 1rem; + gap: 0.5rem; + margin-bottom: 0.75rem; } @media (min-width: 480px) { @@ -50,7 +50,7 @@ align-items: center; flex-wrap: wrap; gap: 1rem; - margin-bottom: 1.25rem; + margin-bottom: 0.75rem; } } @@ -134,137 +134,156 @@ } /* ======================================== - Statistics Bar - Responsive + Compact Toolbar (Stats + Filter combined) ======================================== */ -.stats-bar { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 0.75rem; - margin-bottom: 1rem; - padding: 0.75rem; - background: var(--surface-elevated); - border-radius: var(--radius-lg); - border: 0.5px solid var(--border-light); -} - -@media (min-width: 480px) { - .stats-bar { - display: flex; - gap: 1rem; - padding: 1rem; - margin-bottom: 1.25rem; - overflow-x: auto; - } -} - -@media (min-width: 768px) { - .stats-bar { - gap: 2rem; - } -} - -.stat { - text-align: center; - padding: 0 0.5rem; -} - -@media (min-width: 480px) { - .stat { - flex: 1; - min-width: 80px; - padding: 0 1rem; - border-right: 1px solid var(--border-light); - } - - .stat:last-child { - border-right: none; - } -} - -.stat-value { - display: block; - font-family: var(--font-family-heading); - font-size: clamp(1.25rem, 4vw, 1.75rem); - font-weight: var(--font-weight-bold); - color: var(--text-primary); -} - -.stat.available .stat-value { - color: var(--color-success); -} - -.stat.occupied .stat-value { - color: var(--color-warning); -} - -.stat-label { - font-family: var(--font-family-base); - font-size: clamp(0.65rem, 2vw, 0.75rem); - color: var(--text-tertiary); - text-transform: uppercase; -} - -/* ======================================== - Filter Bar - Responsive - ======================================== */ -.filter-bar { +.toolbar { + position: sticky; + top: 0; + z-index: 10; display: flex; flex-direction: column; - gap: 0.75rem; - margin-bottom: 1rem; - padding: 1rem; - background: rgba(28, 28, 30, 0.4); + gap: 0.5rem; + margin-bottom: 0.75rem; + padding: 0.6rem 0.75rem; + background: rgba(28, 28, 30, 0.92); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); border-radius: var(--radius-lg); border: 0.5px solid var(--border-light); } -@media (min-width: 768px) { - .filter-bar { +@media (min-width: 1024px) { + .toolbar { flex-direction: row; + align-items: center; + justify-content: space-between; flex-wrap: wrap; - align-items: flex-end; - gap: 1.25rem; - margin-bottom: 1.25rem; + gap: 0.75rem; } } -.filter-group { - display: flex; - flex-direction: column; - gap: 0.35rem; -} - -.filter-label { - font-family: var(--font-family-base); - font-size: 0.7rem; - font-weight: var(--font-weight-semibold); - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.filter-group.search-group { - flex: 1; - min-width: 200px; -} - -@media (max-width: 767.98px) { - .filter-group.search-group { - order: -1; - } -} - -/* Area & Status Filter */ -.area-filter, -.status-filter { +/* Stat chips - clickable, act as filters */ +.stat-chips { display: flex; gap: 6px; flex-wrap: wrap; } -/* Row Filter */ -.row-filter { - min-width: 120px; +.stat-chip { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 5px 10px; + background: rgba(0, 0, 0, 0.3); + border: 0.5px solid var(--border-default); + border-radius: var(--radius-sm); + color: var(--text-secondary); + font-family: var(--font-family-base); + font-size: var(--text-xs); + cursor: pointer; + transition: all var(--duration-fast) var(--ease-default); + white-space: nowrap; + min-height: 32px; +} + +.stat-chip:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.2); +} + +.stat-chip .chip-value { + font-family: var(--font-family-heading); + font-size: var(--text-sm); + font-weight: var(--font-weight-bold); + color: var(--text-primary); +} + +.stat-chip.active { + background: rgba(220, 38, 38, 0.15); + border-color: var(--border-focus); + color: var(--text-primary); +} + +.stat-chip.available .chip-value { + color: var(--color-success); +} + +.stat-chip.available.active { + background: rgba(34, 197, 94, 0.15); + border-color: rgba(34, 197, 94, 0.4); + color: var(--color-success); +} + +.stat-chip.occupied .chip-value { + color: var(--color-warning); +} + +.stat-chip.occupied.active { + background: rgba(251, 191, 36, 0.15); + border-color: rgba(251, 191, 36, 0.4); + color: var(--color-warning); +} + +.stat-chip.lager.active { + background: rgba(251, 191, 36, 0.15); + border-color: rgba(251, 191, 36, 0.4); + color: var(--color-warning); +} + +.stat-chip.werkstatt.active { + background: rgba(96, 165, 250, 0.15); + border-color: rgba(96, 165, 250, 0.4); + color: var(--color-info-light); +} + +/* Toolbar controls: search + row select + collapse toggle */ +.toolbar-controls { + display: flex; + gap: 6px; + flex-wrap: wrap; + align-items: center; +} + +.toolbar-controls .search-box { + flex: 1; + min-width: 160px; +} + +.toolbar-controls .row-select { + width: auto; + min-width: 110px; + padding: 7px 10px; + background: rgba(0, 0, 0, 0.3); + border: 0.5px solid var(--border-default); + border-radius: var(--radius-sm); + color: var(--text-primary); + font-family: var(--font-family-base); + font-size: var(--text-xs); + min-height: 34px; +} + +.toolbar-controls .btn-sm { + padding: 6px 10px; + font-size: var(--text-xs); + min-height: 34px; + background: rgba(0, 0, 0, 0.3); + border: 0.5px solid var(--border-default); + border-radius: var(--radius-sm); + color: var(--text-secondary); + cursor: pointer; + white-space: nowrap; + transition: all var(--duration-fast) var(--ease-default); +} + +.toolbar-controls .btn-sm:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.2); + color: var(--text-primary); +} + +.toolbar-controls .clear-filters { + color: var(--color-error-light); + border-color: rgba(239, 68, 68, 0.3); } /* Filter Buttons */ @@ -323,14 +342,15 @@ } .search-box .form-control { - padding: 10px 14px; + padding: 7px 12px; background: rgba(0, 0, 0, 0.3); border: 0.5px solid var(--border-default); border-radius: var(--radius-sm); color: var(--text-primary); font-family: var(--font-family-base); - font-size: var(--text-base); + font-size: var(--text-sm); width: 100%; + min-height: 34px; } .search-box .form-control:focus { @@ -400,8 +420,8 @@ Area Section (Grid View) ======================================== */ .area-section { - margin-bottom: 1.5rem; - padding: 1rem; + margin-bottom: 1rem; + padding: 0.75rem; background: rgba(28, 28, 30, 0.4); border-radius: var(--radius-xl); border: 0.5px solid var(--border-light); @@ -409,8 +429,8 @@ @media (min-width: 480px) { .area-section { - padding: 1.25rem; - margin-bottom: 2rem; + padding: 1rem; + margin-bottom: 1.25rem; } } @@ -424,22 +444,32 @@ .area-title { font-family: var(--font-family-base); - font-size: var(--text-lg); + font-size: var(--text-base); font-weight: var(--font-weight-semibold); color: var(--text-primary); - margin: 0 0 1rem 0; - padding-bottom: 0.75rem; + margin: 0 0 0.6rem 0; + padding-bottom: 0.4rem; border-bottom: 0.5px solid var(--border-default); } .row-section { - margin-bottom: 1rem; + margin-bottom: 0.6rem; } .row-section:last-child { margin-bottom: 0; } +.position-title { + font-family: var(--font-family-base); + font-size: 0.7rem; + font-weight: var(--font-weight-semibold); + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; + margin: 0.5rem 0 0.3rem 0; +} + .row-header { display: flex; align-items: center; @@ -447,8 +477,8 @@ width: 100%; background: none; border: none; - padding: 0.35rem 0; - margin: 0 0 0.75rem 0; + padding: 0.25rem 0.25rem; + margin: 0 0 0.4rem 0; cursor: pointer; text-align: left; border-radius: 6px; @@ -500,7 +530,7 @@ .location-grid { display: grid; grid-template-columns: repeat(2, 1fr); - gap: 8px; + gap: 6px; } @media (min-width: 400px) { @@ -511,14 +541,14 @@ @media (min-width: 480px) { .location-grid { - grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); - gap: 10px; + grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); + gap: 8px; } } @media (min-width: 768px) { .location-grid { - grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(115px, 1fr)); } } @@ -527,11 +557,11 @@ background: var(--surface-elevated); border: 0.5px solid var(--border-default); border-radius: var(--radius-md); - padding: 10px; + padding: 8px; cursor: pointer; transition: all var(--duration-fast) var(--ease-default); position: relative; - min-height: 70px; + min-height: 58px; } .location-card:hover { @@ -1144,6 +1174,83 @@ margin: 0 0 12px 0; } +.stored-tires-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +.stored-tires-header h4 { + margin-bottom: 0; +} + +.tirestack-edit-form { + margin-top: 12px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.tirestack-edit-form .form-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; +} + +.tirestack-edit-form .season-selector, +.tirestack-edit-form .toggle-group { + display: flex; + gap: 8px; +} + +.tirestack-edit-form .season-btn, +.tirestack-edit-form .toggle-btn { + flex: 1; + padding: 8px 10px; + border: 0.5px solid var(--border-light); + border-radius: var(--radius-md); + background: rgba(0, 0, 0, 0.2); + color: var(--text-secondary); + font-size: var(--text-sm); + cursor: pointer; + transition: all 0.15s ease; +} + +.tirestack-edit-form .season-btn:hover, +.tirestack-edit-form .toggle-btn:hover { + border-color: var(--text-secondary); +} + +.tirestack-edit-form .season-btn.active, +.tirestack-edit-form .toggle-btn.active { + border-color: var(--accent, #4a9eff); + color: var(--text-primary); + background: rgba(74, 158, 255, 0.15); +} + +.tirestack-edit-form .season-btn.active.summer { + border-color: #f5a623; + background: rgba(245, 166, 35, 0.15); +} + +.tirestack-edit-form .season-btn.active.winter { + border-color: #4a9eff; + background: rgba(74, 158, 255, 0.15); +} + +.tirestack-edit-form .season-btn.active.allseason { + border-color: #7ed321; + background: rgba(126, 211, 33, 0.15); +} + +.tirestack-edit-form .form-actions { + display: flex; + justify-content: flex-end; + gap: 8px; +} + + .stored-item { padding: 0; } diff --git a/Lagerbestand/Components/Pages/TireCheckin.razor b/Lagerbestand/Components/Pages/TireCheckin.razor index d24e0ab..abcbd68 100644 --- a/Lagerbestand/Components/Pages/TireCheckin.razor +++ b/Lagerbestand/Components/Pages/TireCheckin.razor @@ -5,6 +5,7 @@ @inject IStorageLocationService StorageLocationService @inject ILocationCodeService LocationCodeService @inject ITireStackService TireStackService +@inject ITireReportService TireReportService @inject ICatalogService CatalogService @inject IFileStorageService FileStorageService @inject UserSessionService UserSession @@ -474,6 +475,42 @@ else
} + @if (!isInventoryMode) + { + @* QR report scan *@ +
+ @if (pendingReport == null) + { +
+ + Profiltiefen-Report (Launch TTS01) per QR-Code übernehmen +
+ + } + else + { +
+
+ + Report wird mit dem neuen Stapel gespeichert + +
+ @ReportSummaryFragment(pendingReport) +
+ } +
+ } + @* Tire/Felgen Form *@
@if (!isFelgenCategory) @@ -506,6 +543,10 @@ else else { + @if (tireSizeFromVehicle && !string.IsNullOrEmpty(tireStack.TireSize)) + { + 🚗 Vom Fahrzeug übernommen + } }
@@ -657,7 +698,7 @@ else @* Step 3: Storage Location *@ @if (currentStep == 3) { -
+
@if (isInventoryMode) { @@ -676,32 +717,104 @@ else

Lagerplatz auswählen

-
- @* Area Filter *@ -
- - - -
- - @* Row Filter *@ -
- + else + { +
+ Kunde + 👤 @selectedCustomer?.FullName +
+ @if (selectedVehicle != null) + { +
+ Fahrzeug + 🚗 @selectedVehicle.DisplayName +
+ } + } +
+ @(isFelgenCategory ? "Felgen" : "Reifen") + + @(isInventoryMode && useCustomItemCount ? tireStack.ItemCount : TireStack.TiresPerStack) Stück + @if (!isFelgenCategory) + { + @(tireStack.Season == TireSeason.Sommer ? "☀️" : tireStack.Season == TireSeason.Winter ? "❄️" : "🔄") @tireStack.Season + } + +
+ @if (!string.IsNullOrEmpty(tireStack.TireSize)) + { +
+ Größe + @tireStack.TireSize @(tireStack.WithRims && !isFelgenCategory ? "| mit Felgen" : "") +
+ } + @if (!string.IsNullOrEmpty(tireStack.TireBrand) || !string.IsNullOrEmpty(tireStack.TireModel)) + { +
+ Marke + @tireStack.TireBrand @tireStack.TireModel +
+ } +
+ Lagerplatz + + + +
+
+ +
+ } + + @if (locationSelectorCollapsed && selectedLocation != null) + { + + } + else + { +
+ @* Area & Row Filter combined *@ +
+
+ + + +
+ +
+ +
@* Location Grid *@ @@ -720,7 +833,7 @@ else

@(areaGroup.Key == AreaType.Lager ? "🏭" : "🔧") @areaGroup.Key.GetDisplayName()

- + @foreach (var rowGroup in areaGroup.GroupBy(l => l.Row).OrderBy(g => g.Key)) {
@@ -742,16 +855,6 @@ else } }
- - @if (selectedLocation != null) - { -
-
📍
-
- -
- -
} @if (!string.IsNullOrEmpty(errorMessage)) @@ -873,6 +976,159 @@ else
} + + + +@* Report preview / assignment modal *@ +@if (scannedReport != null) +{ +
+ +
+} + +@* Report attached to existing stack – success *@ +@if (reportAttachedTo != null) +{ +
+ +
+} } @code { @@ -923,6 +1179,179 @@ else private string? zoomImageUrl; private string? zoomImageTitle; + // QR report + private enum ReportAssignMode { Existing, New } + private bool showQrScanner; + private bool isLoadingReport; + private TireReportData? scannedReport; + private TireReportData? pendingReport; + private ReportAssignMode reportMode = ReportAssignMode.New; + private List customerStacksForReport = new(); + private Guid? reportTargetStackId; + private string? reportError; + private TireStack? reportAttachedTo; + private const int NotesMaxLength = 1000; + + private static string RatingClass(TireMeasureRating r) => r switch + { + TireMeasureRating.Ok => "ok", + TireMeasureRating.Warning => "warn", + TireMeasureRating.Critical => "crit", + _ => "none" + }; + + private static string RatingClass(TireReportData r, decimal? mm) => RatingClass(TireInspection.RateDepth(mm, r.CriticalThreshold, r.WarningThreshold)); + + private RenderFragment ReportSummaryFragment => report => __builder => + { +
+ @if (!string.IsNullOrEmpty(report.LicensePlate)) { 🚗 @report.LicensePlate } + @if (report.Mileage.HasValue) { @report.Mileage.Value.ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("de-DE")) km } + VL @Fmt(report.TreadDepthFL) + VR @Fmt(report.TreadDepthFR) + HL @Fmt(report.TreadDepthRL) + HR @Fmt(report.TreadDepthRR) +
+ }; + + private static string Fmt(decimal? mm) => mm.HasValue ? mm.Value.ToString("0.0", System.Globalization.CultureInfo.GetCultureInfo("de-DE")) + " mm" : "–"; + + private void OpenQrScanner() + { + reportError = null; + showQrScanner = true; + } + + private async Task OnQrScanned(string text) + { + showQrScanner = false; + + if (selectedCustomer == null) + { + errorMessage = "Bitte zuerst einen Kunden auswählen."; + return; + } + + if (!TireReportService.TryParseReportUrl(text, out var recordSn, out _)) + { + errorMessage = "Der QR-Code enthält keinen gültigen Reifen-Report-Link."; + return; + } + + isLoadingReport = true; + errorMessage = null; + StateHasChanged(); + + try + { + var report = await TireReportService.FetchAsync(recordSn); + + var stacks = await TireStackService.GetByCustomerAsync(selectedCustomer.Id); + customerStacksForReport = stacks + .Where(s => s.IsActive && s.Status != TireStackStatus.PickedUp) + .OrderByDescending(s => selectedVehicle != null && s.VehicleId == selectedVehicle.Id) + .ThenByDescending(s => s.Status == TireStackStatus.Stored) + .ThenByDescending(s => s.StoredAt) + .ToList(); + + reportMode = customerStacksForReport.Count > 0 ? ReportAssignMode.Existing : ReportAssignMode.New; + reportTargetStackId = customerStacksForReport.FirstOrDefault()?.Id; + reportError = null; + scannedReport = report; + } + catch (TireReportException ex) + { + errorMessage = ex.Message; + } + catch (Exception ex) + { + errorMessage = $"Report konnte nicht verarbeitet werden: {ex.Message}"; + } + finally + { + isLoadingReport = false; + } + } + + private void SetReportMode(ReportAssignMode mode) + { + reportMode = mode; + reportError = null; + } + + private void CloseReportModal() + { + scannedReport = null; + reportError = null; + } + + private async Task AttachReportToExisting() + { + if (scannedReport == null || reportTargetStackId == null) return; + + isProcessing = true; + reportError = null; + StateHasChanged(); + + try + { + scannedReport.RecomputeRatings(); + await TireStackService.AddInspectionAsync(scannedReport.ToInspection(reportTargetStackId.Value, UserSession.CurrentUser?.Id)); + reportAttachedTo = customerStacksForReport.FirstOrDefault(s => s.Id == reportTargetStackId.Value); + scannedReport = null; + } + catch (Exception ex) + { + reportError = $"Speichern fehlgeschlagen: {ex.Message}"; + } + finally + { + isProcessing = false; + } + } + + private void ApplyReportToNew() + { + if (scannedReport == null) return; + + scannedReport.RecomputeRatings(); + pendingReport = scannedReport; + scannedReport = null; + + var de = System.Globalization.CultureInfo.GetCultureInfo("de-DE"); + var lines = new List(); + if (!string.IsNullOrEmpty(pendingReport.LicensePlate)) lines.Add($"Kennzeichen: {pendingReport.LicensePlate}"); + if (pendingReport.Mileage.HasValue) lines.Add($"km-Stand: {pendingReport.Mileage.Value.ToString("N0", de)}"); + if (pendingReport.HasTreadData) + lines.Add($"Profil VL {Fmt(pendingReport.TreadDepthFL)} / VR {Fmt(pendingReport.TreadDepthFR)} / HL {Fmt(pendingReport.TreadDepthRL)} / HR {Fmt(pendingReport.TreadDepthRR)}"); + if (!string.IsNullOrEmpty(pendingReport.Recommendation)) lines.Add(pendingReport.Recommendation); + + var block = string.Join("\n", lines); + if (!string.IsNullOrWhiteSpace(block)) + { + var merged = string.IsNullOrWhiteSpace(tireStack.Notes) ? block : tireStack.Notes.TrimEnd() + "\n" + block; + tireStack.Notes = merged.Length <= NotesMaxLength ? merged : merged[..NotesMaxLength]; + showDetailsExpanded = true; + } + + if (pendingReport.HasTreadData) + { + var minDepth = new[] { pendingReport.TreadDepthFL, pendingReport.TreadDepthFR, pendingReport.TreadDepthRL, pendingReport.TreadDepthRR } + .Where(v => v.HasValue).Select(v => v!.Value).Min(); + tireStack.Condition = minDepth < TireInspection.DefaultWarningThreshold ? TireCondition.Poor + : minDepth < 5m ? TireCondition.Fair + : TireCondition.Good; + } + + _ = SaveDraftAsync(); + } + + private void RemovePendingReport() + { + pendingReport = null; + _ = SaveDraftAsync(); + } + // Computed helpers private bool isFelgenCategory => isInventoryMode && selectedCategory?.Type == CatalogItemType.Felgen; @@ -954,8 +1383,16 @@ else // Cleared on successful CompleteCheckin and on ResetForm. // ------------------------------------------------------------------ private const string DraftKey = "tire-checkin"; + private static readonly System.Text.Json.JsonSerializerOptions DraftJsonOptions = new() + { + ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles, + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull + }; private bool _draftRestoreAttempted; private bool _isRestoringDraft; + + [SupplyParameterFromQuery(Name = "customerId")] + public Guid? PreselectedCustomerId { get; set; } private CancellationTokenSource? _draftDebounceCts; private CancellationTokenSource? _searchDebounceCts; private readonly SemaphoreSlim _searchLock = new(1, 1); @@ -965,10 +1402,37 @@ else if (firstRender && UserSession.IsWorkerOrAdmin && !_draftRestoreAttempted) { _draftRestoreAttempted = true; + + if (PreselectedCustomerId.HasValue) + { + await PreselectCustomerAsync(PreselectedCustomerId.Value); + return; + } + await TryRestoreDraftAsync(); } } + private async Task PreselectCustomerAsync(Guid customerId) + { + try + { + var customer = await CustomerService.GetByIdAsync(customerId); + if (customer == null) return; + + try { await JS.InvokeVoidAsync("appInterop.clearDraft", DraftKey); } catch { } + + isInventoryMode = false; + await SelectCustomer(customer); + GoToStep2(); + StateHasChanged(); + } + catch (Exception ex) + { + errorMessage = $"Kunde konnte nicht geladen werden: {ex.Message}"; + } + } + private async Task TryRestoreDraftAsync() { try @@ -976,7 +1440,7 @@ else var json = await JS.InvokeAsync("appInterop.loadDraft", DraftKey); if (string.IsNullOrWhiteSpace(json)) return; - var draft = System.Text.Json.JsonSerializer.Deserialize(json); + var draft = System.Text.Json.JsonSerializer.Deserialize(json, DraftJsonOptions); if (draft == null) return; _isRestoringDraft = true; @@ -1012,6 +1476,8 @@ else tireStack = draft.TireStack; } + pendingReport = draft.PendingReport; + if (draft.SelectedLocationId.HasValue) { selectedLocation = allLocations.FirstOrDefault(l => l.Id == draft.SelectedLocationId.Value); @@ -1083,10 +1549,11 @@ else SelectedLocationId = selectedLocation?.Id, UseCustomItemCount = useCustomItemCount, ShowDetailsExpanded = showDetailsExpanded, - TireStack = tireStack + TireStack = tireStack, + PendingReport = pendingReport }; - var json = System.Text.Json.JsonSerializer.Serialize(draft); + var json = System.Text.Json.JsonSerializer.Serialize(draft, DraftJsonOptions); await JS.InvokeVoidAsync("appInterop.saveDraft", DraftKey, json); await JS.InvokeVoidAsync("appInterop.setUnsaved", HasMeaningfulDraft()); } @@ -1127,6 +1594,7 @@ else public bool UseCustomItemCount { get; set; } public bool ShowDetailsExpanded { get; set; } public TireStack? TireStack { get; set; } + public TireReportData? PendingReport { get; set; } } private async Task LoadLocations() @@ -1251,6 +1719,8 @@ else selectedVehicle = null; } + ApplyVehicleTireSize(); + _ = SaveDraftAsync(); } @@ -1258,9 +1728,26 @@ else { selectedVehicle = vehicle; showAddVehicleForm = false; + ApplyVehicleTireSize(); _ = SaveDraftAsync(); } + /// + /// Übernimmt die Reifengröße des gewählten Fahrzeugs in den Reifenstapel, + /// sofern noch keine (abweichende) Größe manuell erfasst wurde. + /// + private void ApplyVehicleTireSize() + { + if (isInventoryMode) return; + if (string.IsNullOrWhiteSpace(selectedVehicle?.TireSize)) return; + + if (string.IsNullOrWhiteSpace(tireStack.TireSize) || tireSizeFromVehicle) + { + OnTireSizeChanged(selectedVehicle.TireSize); + tireSizeFromVehicle = true; + } + } + private void ShowNewVehicleForm() { showAddVehicleForm = true; @@ -1285,6 +1772,7 @@ else showAddVehicleForm = false; newVehicle = new Vehicle(); errorMessage = null; + ApplyVehicleTireSize(); } catch (Exception ex) { @@ -1344,6 +1832,7 @@ else newCustomer = new Customer(); newVehicle = new Vehicle(); errorMessage = null; + ApplyVehicleTireSize(); } catch (Exception ex) { @@ -1441,6 +1930,7 @@ else private async Task GoToStep3() { await LoadLocations(); + locationSelectorCollapsed = selectedLocation != null; currentStep = 3; _ = SaveDraftAsync(); } @@ -1451,18 +1941,27 @@ else _ = SaveDraftAsync(); } + private bool locationSelectorCollapsed; + private void SelectLocation(StorageLocation location) { if (!location.IsOccupied && location.IsAvailable) { selectedLocation = location; + locationSelectorCollapsed = true; _ = SaveDraftAsync(); } } + private void ExpandLocationSelector() + { + locationSelectorCollapsed = false; + } + private void ClearSelectedLocation() { selectedLocation = null; + locationSelectorCollapsed = false; } private async Task CompleteCheckin() @@ -1501,6 +2000,19 @@ else createdTireStack = created; + if (pendingReport != null) + { + try + { + await TireStackService.AddInspectionAsync(pendingReport.ToInspection(created.Id, UserSession.CurrentUser?.Id)); + } + catch (Exception ex) + { + errorMessage = $"Stapel eingelagert, Report konnte aber nicht gespeichert werden: {ex.Message}"; + } + pendingReport = null; + } + currentStep = 4; await ClearDraftAsync(); } @@ -1533,9 +2045,11 @@ else showAddVehicleForm = false; tireStack = new TireStack(); showDetailsExpanded = false; + tireSizeFromVehicle = false; selectedLocation = null; selectedAreaFilter = null; selectedRowFilter = null; + locationSelectorCollapsed = false; createdTireStack = null; errorMessage = null; useCustomItemCount = false; @@ -1544,6 +2058,13 @@ else showImageZoom = false; zoomImageUrl = null; zoomImageTitle = null; + showQrScanner = false; + scannedReport = null; + pendingReport = null; + reportAttachedTo = null; + reportError = null; + customerStacksForReport.Clear(); + reportTargetStackId = null; _ = ClearDraftAsync(); } @@ -1563,8 +2084,14 @@ else tireStack.RimSize = isAlu ? "Alu" : "Stahl"; } + private bool tireSizeFromVehicle; + private void OnTireSizeChanged(string? value) { + if (tireStack.TireSize != value && value != selectedVehicle?.TireSize) + { + tireSizeFromVehicle = false; + } tireStack.TireSize = value; // Auto-derive rim size from the R value of the tire size (e.g. "225/45 R17" -> "17 Zoll") diff --git a/Lagerbestand/Components/Pages/TireCheckin.razor.css b/Lagerbestand/Components/Pages/TireCheckin.razor.css index faf81a4..138cad9 100644 --- a/Lagerbestand/Components/Pages/TireCheckin.razor.css +++ b/Lagerbestand/Components/Pages/TireCheckin.razor.css @@ -212,6 +212,18 @@ } } +/* Step 3 (Lagerplatz/Regalansicht): volle Breite nutzen */ +.checkin-card.wide { + max-width: none; + width: 100%; +} + +@media (min-width: 1024px) { + .checkin-card.wide { + padding: 2rem 2.5rem; + } +} + .checkin-card h2 { font-family: 'Rajdhani', sans-serif; font-size: clamp(1.25rem, 4vw, 1.75rem); @@ -1192,38 +1204,90 @@ select.form-control { /* ======================================== Area Filter - Responsive ======================================== */ +.location-filter-row { + display: flex; + gap: 6px; + flex-wrap: wrap; + align-items: center; + margin-bottom: 0.6rem; +} + +.location-filter-row .row-filter { + margin-bottom: 0; + flex: 1; + min-width: 120px; +} + +.location-filter-row .row-filter .form-control { + min-height: 36px; + padding: 6px 10px; + font-size: 0.85rem; +} + +/* Collapsed bar after a location was selected */ +.location-collapsed-bar { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + padding: 10px 14px; + background: rgba(34, 197, 94, 0.1); + border: 0.5px solid rgba(34, 197, 94, 0.35); + border-radius: 10px; + margin-bottom: 0.75rem; + cursor: pointer; + transition: all 0.2s ease; + text-align: left; +} + +.location-collapsed-bar:hover { + background: rgba(34, 197, 94, 0.16); + border-color: rgba(34, 197, 94, 0.5); +} + +.location-collapsed-bar .collapsed-icon { + font-family: "Apple Color Emoji", "Segoe UI Emoji", sans-serif; + font-size: 1.1rem; +} + +.location-collapsed-bar .collapsed-code { + font-family: 'Orbitron', monospace; + font-size: 1rem; + font-weight: 700; + color: #22c55e; +} + +.location-collapsed-bar .collapsed-hint { + margin-left: auto; + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.5); + white-space: nowrap; +} + .area-filter { display: flex; gap: 6px; - margin-bottom: 0.75rem; flex-wrap: wrap; } -@media (min-width: 480px) { - .area-filter { - gap: 8px; - margin-bottom: 1rem; - } -} - .filter-btn { - padding: 10px 12px; + padding: 6px 10px; background: rgba(28, 28, 30, 0.8); border: 0.5px solid rgba(255, 255, 255, 0.1); border-radius: 8px; color: rgba(255, 255, 255, 0.6); font-family: "Apple Color Emoji", "Segoe UI Emoji", 'Rajdhani', sans-serif; - font-size: 0.85rem; + font-size: 0.8rem; cursor: pointer; transition: all 0.2s ease; - min-height: 44px; + min-height: 36px; } @media (min-width: 480px) { .filter-btn { - padding: 10px 14px; - border-radius: 10px; - font-size: 0.9rem; + padding: 6px 12px; + font-size: 0.85rem; } } @@ -1266,51 +1330,51 @@ select.form-control { Area Section - Responsive ======================================== */ .area-section { - margin-bottom: 1.25rem; + margin-bottom: 0.75rem; } @media (min-width: 480px) { .area-section { - margin-bottom: 1.5rem; + margin-bottom: 1rem; } } .area-title { font-family: 'Rajdhani', sans-serif; - font-size: 1rem; + font-size: 0.9rem; font-weight: 600; color: rgba(255, 255, 255, 0.8); - margin: 0 0 0.5rem 0; + margin: 0 0 0.4rem 0; } @media (min-width: 480px) { .area-title { - font-size: 1.1rem; - margin: 0 0 0.75rem 0; + font-size: 0.95rem; + margin: 0 0 0.5rem 0; } } .row-section { - margin-bottom: 0.75rem; + margin-bottom: 0.5rem; } @media (min-width: 480px) { .row-section { - margin-bottom: 1rem; + margin-bottom: 0.6rem; } } .row-label { font-family: 'Rajdhani', sans-serif; - font-size: 0.8rem; + font-size: 0.75rem; color: rgba(255, 255, 255, 0.5); display: block; - margin-bottom: 0.5rem; + margin-bottom: 0.3rem; } @media (min-width: 480px) { .row-label { - font-size: 0.85rem; + font-size: 0.8rem; } } @@ -1319,50 +1383,49 @@ select.form-control { ======================================== */ .location-grid { display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 6px; + grid-template-columns: repeat(4, 1fr); + gap: 5px; } @media (min-width: 400px) { .location-grid { - grid-template-columns: repeat(4, 1fr); - gap: 8px; + grid-template-columns: repeat(5, 1fr); + gap: 6px; } } @media (min-width: 768px) { .location-grid { - grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(78px, 1fr)); } } @media (min-width: 1024px) { .location-grid { - grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); - gap: 12px; + grid-template-columns: repeat(auto-fill, minmax(85px, 1fr)); + gap: 8px; } } .location-tile { - aspect-ratio: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; - gap: 2px; + gap: 1px; background: rgba(0, 0, 0, 0.3); border: 0.5px solid rgba(255, 255, 255, 0.12); border-radius: 8px; cursor: pointer; transition: all 0.2s ease; - min-height: 60px; + min-height: 44px; + padding: 4px 2px; } @media (min-width: 480px) { .location-tile { - gap: 4px; - border-radius: 10px; - min-height: 70px; + gap: 2px; + min-height: 48px; } } @@ -1429,6 +1492,110 @@ select.form-control { } } +/* ======================================== + Checkin Summary (before saving) + ======================================== */ +.checkin-summary { + position: relative; + background: linear-gradient(135deg, rgba(34, 197, 94, 0.08), rgba(28, 28, 30, 0.6)); + border: 0.5px solid rgba(34, 197, 94, 0.35); + border-radius: 14px; + padding: 14px 16px; + margin-bottom: 1rem; + animation: summary-fade-in 0.25s ease; +} + +@keyframes summary-fade-in { + from { + opacity: 0; + transform: translateY(6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.summary-title { + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; + font-weight: 600; + color: #ffffff; + margin: 0 0 10px 0; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.summary-grid { + display: grid; + grid-template-columns: 1fr; + gap: 6px 16px; +} + +@media (min-width: 480px) { + .summary-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 768px) { + .summary-grid { + grid-template-columns: repeat(3, 1fr); + } +} + +.summary-item { + display: flex; + flex-direction: column; + gap: 2px; + padding: 6px 10px; + background: rgba(0, 0, 0, 0.25); + border-radius: 8px; + min-width: 0; +} + +.summary-item.highlight { + background: rgba(34, 197, 94, 0.12); + border: 0.5px solid rgba(34, 197, 94, 0.4); +} + +.summary-label { + font-family: 'Rajdhani', sans-serif; + font-size: 0.65rem; + color: rgba(255, 255, 255, 0.45); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.summary-value { + font-family: 'Rajdhani', sans-serif; + font-size: 0.9rem; + font-weight: 600; + color: #ffffff; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.summary-value.location { + white-space: normal; +} + +.summary-clear { + position: absolute; + top: 10px; + right: 10px; +} + +/* Field hint (e.g. tire size taken from vehicle) */ +.field-hint { + display: inline-block; + margin-top: 4px; + font-family: 'Rajdhani', sans-serif; + font-size: 0.75rem; + color: #22c55e; +} + .location-icon { font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif; font-size: 1.25rem; @@ -2237,3 +2404,390 @@ select.form-control { max-height: 75vh; } } + +/* ======================================== + QR Report Scan (Step 2) + ======================================== */ +.report-scan-bar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + flex-wrap: wrap; + background: rgba(255, 255, 255, 0.04); + border: 0.5px dashed rgba(255, 255, 255, 0.2); + border-radius: 12px; + padding: 12px 16px; + margin-bottom: 1.25rem; +} + +.report-scan-text { + display: flex; + align-items: center; + gap: 10px; + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; + color: rgba(255, 255, 255, 0.75); +} + +.report-scan-icon { + font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif; + font-size: 1.3rem; + line-height: 1; +} + +.report-scan-bar .btn { + display: inline-flex; + align-items: center; + gap: 8px; +} + +.report-attached { + width: 100%; + display: flex; + flex-direction: column; + gap: 8px; +} + +.report-attached-head { + display: flex; + align-items: center; + gap: 10px; + font-family: 'Rajdhani', sans-serif; + color: #ffffff; +} + +.report-attached-head .btn-link { + margin-left: auto; +} + +.report-summary { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.report-chip { + font-family: 'Rajdhani', sans-serif; + font-size: 0.85rem; + font-weight: 600; + padding: 3px 10px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.08); + color: rgba(255, 255, 255, 0.85); + border: 0.5px solid rgba(255, 255, 255, 0.12); +} + +.report-chip.rating-ok { background: rgba(34, 197, 94, 0.15); border-color: rgba(34, 197, 94, 0.4); color: #86efac; } +.report-chip.rating-warn { background: rgba(250, 204, 21, 0.15); border-color: rgba(250, 204, 21, 0.4); color: #fde047; } +.report-chip.rating-crit { background: rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.4); color: #fca5a5; } + +/* Report modal */ +.report-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.8); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; + padding: 1rem; + z-index: 1150; +} + +.report-dialog { + background: #1c1c1e; + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 16px; + width: 100%; + max-width: 640px; + max-height: 92vh; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.report-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 1rem; + padding: 1rem 1.25rem; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.1); +} + +.report-header h3 { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-size: 1.2rem; + font-weight: 700; + color: #ffffff; +} + +.report-subtitle { + margin: 0.2rem 0 0; + font-family: 'Rajdhani', sans-serif; + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.55); +} + +.report-close { + background: none; + border: none; + color: rgba(255, 255, 255, 0.6); + font-size: 1.1rem; + cursor: pointer; + padding: 4px 8px; + border-radius: 6px; +} + +.report-close:hover { + background: rgba(255, 255, 255, 0.1); + color: #ffffff; +} + +.report-body { + padding: 1rem 1.25rem; + overflow-y: auto; + flex: 1; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.report-warning { + background: rgba(250, 204, 21, 0.1); + border: 0.5px solid rgba(250, 204, 21, 0.35); + color: #fde047; + border-radius: 10px; + padding: 10px 14px; + font-family: 'Rajdhani', sans-serif; + font-size: 0.9rem; +} + +.report-meta { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; +} + +.report-meta .form-group { + margin: 0; +} + +.tread-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; +} + +.tread-cell { + border-radius: 12px; + padding: 10px 12px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.12); +} + +.tread-cell.rating-ok { border-color: rgba(34, 197, 94, 0.5); background: rgba(34, 197, 94, 0.08); } +.tread-cell.rating-warn { border-color: rgba(250, 204, 21, 0.5); background: rgba(250, 204, 21, 0.08); } +.tread-cell.rating-crit { border-color: rgba(239, 68, 68, 0.5); background: rgba(239, 68, 68, 0.08); } + +.tread-cell label { + display: block; + font-family: 'Rajdhani', sans-serif; + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.06em; + color: rgba(255, 255, 255, 0.55); + margin-bottom: 6px; +} + +.tread-input { + display: flex; + align-items: center; + gap: 6px; +} + +.tread-input .form-control { + max-width: 110px; + font-family: 'Orbitron', monospace; + font-weight: 600; +} + +.tread-input span { + font-family: 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.6); +} + +.report-recommendation { + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; + color: rgba(255, 255, 255, 0.85); + background: rgba(96, 165, 250, 0.1); + border: 0.5px solid rgba(96, 165, 250, 0.25); + border-radius: 10px; + padding: 10px 14px; +} + +.report-link { + font-family: 'Rajdhani', sans-serif; + font-size: 0.85rem; + color: #60a5fa; + align-self: flex-start; +} + +.report-choice h4 { + font-family: 'Rajdhani', sans-serif; + font-size: 1rem; + font-weight: 700; + color: #ffffff; + margin: 0 0 10px; +} + +.report-choice-buttons { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; +} + +.choice-btn { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 2px; + text-align: left; + padding: 12px 14px; + border-radius: 12px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.12); + color: #ffffff; + cursor: pointer; + transition: border-color 0.15s, background 0.15s; +} + +.choice-btn:hover:not(:disabled) { + border-color: rgba(255, 255, 255, 0.3); +} + +.choice-btn.active { + border-color: #dc2626; + background: rgba(220, 38, 38, 0.12); +} + +.choice-btn:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +.choice-icon { + font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif; + font-size: 1.3rem; +} + +.choice-title { + font-family: 'Rajdhani', sans-serif; + font-weight: 700; + font-size: 1rem; +} + +.choice-sub { + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.55); +} + +.stack-pick-list { + display: flex; + flex-direction: column; + gap: 6px; + margin-top: 10px; + max-height: 220px; + overflow-y: auto; +} + +.stack-pick-item { + display: flex; + flex-direction: column; + gap: 2px; + text-align: left; + padding: 10px 12px; + border-radius: 10px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.1); + color: #ffffff; + cursor: pointer; +} + +.stack-pick-item:hover { + border-color: rgba(255, 255, 255, 0.3); +} + +.stack-pick-item.selected { + border-color: #dc2626; + background: rgba(220, 38, 38, 0.12); +} + +.stack-pick-main { + display: flex; + flex-wrap: wrap; + gap: 10px; + font-family: 'Rajdhani', sans-serif; + font-weight: 600; +} + +.stack-pick-sub { + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.55); +} + +.report-footer { + display: flex; + justify-content: flex-end; + gap: 10px; + padding: 0.9rem 1.25rem; + border-top: 0.5px solid rgba(255, 255, 255, 0.1); +} + +.report-footer.center { + justify-content: center; + border-top: none; +} + +.report-footer .btn { + display: inline-flex; + align-items: center; + gap: 8px; +} + +.report-success { + max-width: 420px; + text-align: center; + padding: 1.5rem 1.25rem 0.5rem; +} + +.report-success h3 { + font-family: 'Rajdhani', sans-serif; + font-size: 1.3rem; + font-weight: 700; + color: #ffffff; + margin: 0.5rem 0 0.25rem; +} + +.report-success p { + font-family: 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.7); +} + +.mono { + font-family: 'Orbitron', monospace; + letter-spacing: 0.03em; +} + +@media (max-width: 480px) { + .report-meta, + .tread-grid, + .report-choice-buttons { + grid-template-columns: 1fr; + } +} diff --git a/Lagerbestand/Components/Pages/TireCheckout.razor b/Lagerbestand/Components/Pages/TireCheckout.razor index 8152e4e..89bc37f 100644 --- a/Lagerbestand/Components/Pages/TireCheckout.razor +++ b/Lagerbestand/Components/Pages/TireCheckout.razor @@ -1,8 +1,9 @@ @page "/tire-checkout" @using Lagerbestand.Components.Shared -@implements IDisposable +@implements IAsyncDisposable @inject ICustomerService CustomerService @inject ITireStackService TireStackService +@inject IStorageLocationService StorageLocationService @inject UserSessionService UserSession Reifenstapel Abholen - Reifen Späth Lagerverwaltung @@ -169,6 +170,164 @@ else
} + @* Tire Swap Panel *@ + @if (swapOutgoing != null) + { +
+
+

Reifenwechsel

+ +
+ +
+ @* Outgoing *@ +
+

Herausgabe (wird montiert)

+
+
Ticket
@swapOutgoing.TicketNumber
+
Kunde
@swapOutgoing.Customer?.FullName
+ @if (swapOutgoing.Vehicle != null) + { +
Fahrzeug
@swapOutgoing.Vehicle.Make @swapOutgoing.Vehicle.Model
+ } +
Saison
@SeasonLabel(swapOutgoing.Season)
+
Größe
@(swapOutgoing.TireSize ?? "-")
+
Marke / Modell
@(string.IsNullOrWhiteSpace(swapOutgoing.TireBrand) && string.IsNullOrWhiteSpace(swapOutgoing.TireModel) ? "-" : $"{swapOutgoing.TireBrand} {swapOutgoing.TireModel}".Trim())
+
Lagerplatz
+ @if (swapOutgoing.StorageLocation != null) + { + + } + else + { + - + } +
+
+
+ + @* Incoming *@ +
+

Einlagerung (kommt vom Fahrzeug)

+ +
+ + +
+ + @if (swapUseHistory) + { +
+ @foreach (var h in swapHistory) + { + var isSameSeason = h.Season == swapOutgoing.Season; + + } +
+ } + else + { +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ } +
+
+ + @* Target location *@ +
+ Lagerplatz für Einlagerung: + @if (swapTargetLocation != null) + { + + @if (swapTargetLocation.Id == swapOutgoing.StorageLocationId) + { + (frei werdender Platz) + } + else + { + + } + } + else + { + Kein Lagerplatz gewählt + } + +
+ +
+ +
+
+ } + @* Search Results *@ @if (searchResults.Count > 0) { @@ -182,7 +341,7 @@ else { var isAlreadyScanned = scannedTireStacks.Any(s => s.Id == ts.Id);
+ @onclick="() => OnResultClicked(ts)" role="listitem">
@ts.TicketNumber @@ -235,6 +394,74 @@ else
} + @* Storage location picker (rack view) for swap *@ + @if (swapOutgoing != null) + { + + } + + @* Action Chooser Modal *@ + @if (actionCandidate != null) + { +
+ +
+ } + + @* Swap Success Modal *@ + @if (swapResult != null) + { +
+
+
✓
+

Reifenwechsel erfolgreich!

+
+
+ ⬆️ @swapResult.Outgoing.TicketNumber + @SeasonLabel(swapResult.Outgoing.Season) montiert +
+
+ ⬇️ @swapResult.Incoming.TicketNumber + @SeasonLabel(swapResult.Incoming.Season) eingelagert auf @swapResult.NewLocationCode +
+
+ @if (swapResult.FreedLocationCode != null && swapResult.FreedLocationCode != swapResult.NewLocationCode) + { +

Lagerplatz @swapResult.FreedLocationCode ist wieder frei.

+ } + +
+
+ } + @* Success Modal *@ @if (showSuccess) { @@ -297,6 +524,200 @@ else private CancellationTokenSource? _searchDebounceCts; private readonly SemaphoreSlim _searchLock = new(1, 1); + // Action chooser / swap flow + private TireStack? actionCandidate; + private TireStack? swapOutgoing; + private List swapHistory = new(); + private TireStack? swapSelectedHistory; + private bool swapUseHistory; + private TireStack swapNew = new(); + private bool showLocationPicker; + private StorageLocation? swapTargetLocation; + private Guid? swapTargetLocationId => swapTargetLocation?.Id; + private SwapResult? swapResult; + + private bool CanSwap => swapOutgoing != null && (swapUseHistory ? swapSelectedHistory != null : !string.IsNullOrWhiteSpace(swapNew.TireSize)); + + [SupplyParameterFromQuery(Name = "stackId")] + public Guid? PreselectedStackId { get; set; } + + protected override async Task OnInitializedAsync() + { + if (!PreselectedStackId.HasValue || !UserSession.IsWorkerOrAdmin) return; + + try + { + var stack = await TireStackService.GetByIdAsync(PreselectedStackId.Value); + if (stack == null) + { + errorMessage = "Der gewählte Reifenstapel wurde nicht gefunden."; + return; + } + + searchResults = new List { stack }; + OnResultClicked(stack); + } + catch (Exception ex) + { + errorMessage = $"Reifenstapel konnte nicht geladen werden: {ex.Message}"; + } + } + + private static string SeasonIcon(TireSeason s) => s == TireSeason.Sommer ? "☀️" : s == TireSeason.Winter ? "❄️" : "🔄"; + private static string SeasonLabel(TireSeason s) => s == TireSeason.Sommer ? "☀️ Sommer" : s == TireSeason.Winter ? "❄️ Winter" : "🔄 Allrad"; + + private void OnResultClicked(TireStack ts) + { + if (ts.Status != TireStackStatus.Stored) + { + errorMessage = $"'{ts.TicketNumber}' ist nicht eingelagert"; + return; + } + + // Inventory stacks and already selected stacks toggle directly + if (ts.IsInventory || scannedTireStacks.Any(s => s.Id == ts.Id)) + { + AddToScannedList(ts); + return; + } + + actionCandidate = ts; + errorMessage = null; + } + + private void CloseActionChooser() => actionCandidate = null; + + private void ChoosePickup() + { + if (actionCandidate == null) return; + AddToScannedList(actionCandidate); + actionCandidate = null; + } + + private async Task ChooseSwap() + { + if (actionCandidate == null) return; + var ts = actionCandidate; + actionCandidate = null; + await StartSwap(ts); + } + + private async Task StartSwap(TireStack outgoing) + { + swapOutgoing = outgoing; + swapResult = null; + showLocationPicker = false; + swapTargetLocation = outgoing.StorageLocation; + swapSelectedHistory = null; + errorMessage = null; + successMessage = null; + + var oppositeSeason = outgoing.Season == TireSeason.Sommer ? TireSeason.Winter + : outgoing.Season == TireSeason.Winter ? TireSeason.Sommer + : TireSeason.Allrad; + + swapNew = new TireStack + { + Season = oppositeSeason, + TireSize = outgoing.Vehicle?.TireSize ?? outgoing.TireSize, + WithRims = outgoing.WithRims, + Condition = TireCondition.Good, + CustomerId = outgoing.CustomerId, + VehicleId = outgoing.VehicleId + }; + + await _searchLock.WaitAsync(); + try + { + var history = outgoing.CustomerId.HasValue + ? await TireStackService.GetByCustomerAsync(outgoing.CustomerId.Value) + : new List(); + + swapHistory = history + .Where(h => h.Id != outgoing.Id && (h.Status == TireStackStatus.OnVehicle || h.Status == TireStackStatus.PickedUp)) + .OrderBy(h => h.Season == outgoing.Season) + .ThenByDescending(h => h.PickedUpAt) + .ToList(); + } + catch (Exception ex) + { + swapHistory = new(); + errorMessage = $"Historie konnte nicht geladen werden: {ex.Message}"; + } + finally + { + _searchLock.Release(); + } + + swapUseHistory = swapHistory.Count > 0; + swapSelectedHistory = swapHistory.FirstOrDefault(h => h.Season != outgoing.Season) ?? swapHistory.FirstOrDefault(); + } + + private void OnTargetLocationSelected(StorageLocation loc) + { + swapTargetLocation = loc; + } + + private void ResetTargetLocation() + { + swapTargetLocation = swapOutgoing?.StorageLocation; + } + + private void CancelSwap() + { + swapOutgoing = null; + swapHistory.Clear(); + swapSelectedHistory = null; + showLocationPicker = false; + swapTargetLocation = null; + } + + private async Task ProcessSwap() + { + if (swapOutgoing == null || !CanSwap) return; + + isProcessing = true; + errorMessage = null; + StateHasChanged(); + + await _searchLock.WaitAsync(); + try + { + var incoming = swapUseHistory + ? new TireStack + { + Id = swapSelectedHistory!.Id, + Condition = swapSelectedHistory.Condition, + Notes = swapSelectedHistory.Notes, + VehicleId = swapOutgoing.VehicleId + } + : swapNew; + + var targetLocation = swapTargetLocationId == swapOutgoing.StorageLocationId ? null : swapTargetLocationId; + + swapResult = await TireStackService.SwapAsync( + swapOutgoing.Id, + incoming, + targetLocation, + UserSession.CurrentUser?.Id); + + CancelSwap(); + searchResults.Clear(); + searchTerm = ""; + } + catch (Exception ex) + { + errorMessage = $"Fehler beim Reifenwechsel: {ex.Message}"; + } + finally + { + _searchLock.Release(); + isProcessing = false; + } + } + + private void CloseSwapSuccess() => swapResult = null; + private async Task SearchTireStacks() { if (string.IsNullOrWhiteSpace(searchTerm) || searchTerm.Length < 2) @@ -435,10 +856,11 @@ else freedLocations.Clear(); } - public void Dispose() + public ValueTask DisposeAsync() { _searchDebounceCts?.Cancel(); _searchDebounceCts?.Dispose(); _searchLock.Dispose(); + return ValueTask.CompletedTask; } } diff --git a/Lagerbestand/Components/Pages/TireCheckout.razor.css b/Lagerbestand/Components/Pages/TireCheckout.razor.css index d79dd43..4a14ea1 100644 --- a/Lagerbestand/Components/Pages/TireCheckout.razor.css +++ b/Lagerbestand/Components/Pages/TireCheckout.razor.css @@ -712,6 +712,363 @@ margin-bottom: 1.5rem !important; } +/* ======================================== + Action chooser modal + ======================================== */ +.action-modal { + max-width: 460px; +} + +.action-subject { + line-height: 1.6; +} + +.action-subject .vehicle-info { + display: inline-block; + margin-left: 6px; + background: rgba(255, 255, 255, 0.1); + padding: 1px 8px; + border-radius: 6px; + font-size: 0.85rem; +} + +.mono { + font-family: 'Orbitron', monospace; + font-size: 0.85em; + letter-spacing: 0.04em; + color: #60a5fa; +} + +.action-buttons { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.75rem; + margin: 1.25rem 0; +} + +.action-btn { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + padding: 1rem 0.75rem; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 14px; + color: #ffffff; + cursor: pointer; + transition: all 0.15s ease; + font-family: 'Rajdhani', sans-serif; +} + +.action-btn:hover { + background: rgba(239, 68, 68, 0.15); + border-color: rgba(239, 68, 68, 0.5); +} + +.action-btn.swap:hover { + background: rgba(96, 165, 250, 0.15); + border-color: rgba(96, 165, 250, 0.5); +} + +.action-icon { + font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif; + font-size: 1.8rem; + line-height: 1; +} + +.action-label { + font-size: 1.05rem; + font-weight: 700; +} + +.action-desc { + font-size: 0.75rem; + color: rgba(255, 255, 255, 0.55); + text-align: center; +} + +/* ======================================== + Swap panel + ======================================== */ +.swap-panel { + background: rgba(28, 28, 30, 0.95); + border: 1px solid rgba(96, 165, 250, 0.4); + border-radius: 16px; + padding: 1rem; + margin: 0 auto 1.5rem; +} + +.swap-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.75rem; + margin-bottom: 1rem; +} + +.swap-header h2 { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-size: 1.3rem; + font-weight: 700; + color: #ffffff; +} + +.swap-columns { + display: grid; + grid-template-columns: 1fr; + gap: 0.75rem; +} + +@media (min-width: 768px) { + .swap-columns { + grid-template-columns: 1fr 1fr; + gap: 1rem; + } +} + +.swap-box { + background: rgba(255, 255, 255, 0.03); + border: 0.5px solid rgba(255, 255, 255, 0.08); + border-radius: 12px; + padding: 0.75rem 1rem; +} + +.swap-box.outgoing { + border-left: 3px solid #ef4444; +} + +.swap-box.incoming { + border-left: 3px solid #22c55e; +} + +.swap-box-title { + margin: 0 0 0.5rem; + padding-bottom: 0.4rem; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.1); + font-family: 'Rajdhani', sans-serif; + font-size: 0.9rem; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.75); +} + +.swap-rows { + margin: 0; + display: flex; + flex-direction: column; +} + +.swap-row { + display: grid; + grid-template-columns: minmax(100px, 36%) 1fr; + gap: 0.5rem; + align-items: center; + padding: 0.35rem 0; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.05); +} + +.swap-row:last-child { + border-bottom: none; +} + +.swap-row dt { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-size: 0.85rem; + font-weight: 600; + color: rgba(255, 255, 255, 0.5); +} + +.swap-row dd { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; + font-weight: 600; + color: #ffffff; + overflow-wrap: anywhere; +} + +.swap-tabs { + display: flex; + gap: 4px; + background: rgba(0, 0, 0, 0.3); + border-radius: 10px; + padding: 4px; + margin-bottom: 0.75rem; +} + +.swap-tab { + flex: 1; + padding: 8px; + background: transparent; + border: none; + border-radius: 8px; + color: rgba(255, 255, 255, 0.6); + font-family: 'Rajdhani', sans-serif; + font-weight: 600; + font-size: 0.9rem; + cursor: pointer; +} + +.swap-tab.active { + background: rgba(96, 165, 250, 0.2); + color: #ffffff; +} + +.swap-tab:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.history-list { + display: flex; + flex-direction: column; + gap: 6px; + max-height: 260px; + overflow-y: auto; +} + +.history-item { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + text-align: left; + padding: 8px 10px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 10px; + color: #ffffff; + cursor: pointer; + font-family: 'Rajdhani', sans-serif; +} + +.history-item:hover { + border-color: rgba(255, 255, 255, 0.25); +} + +.history-item.selected { + border-color: #22c55e; + background: rgba(34, 197, 94, 0.12); +} + +.history-item.same-season { + opacity: 0.7; +} + +.history-season { + font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif; + font-size: 1.3rem; + flex-shrink: 0; +} + +.history-main { + display: flex; + flex-direction: column; + gap: 1px; + min-width: 0; + flex: 1; +} + +.history-detail { + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.75); +} + +.history-meta { + font-size: 0.75rem; + color: rgba(255, 255, 255, 0.45); +} + +.history-warn { + flex-shrink: 0; +} + +.form-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.6rem 0.75rem; +} + +@media (max-width: 479px) { + .form-grid { + grid-template-columns: 1fr; + } +} + +.form-group { + display: flex; + flex-direction: column; + gap: 0.2rem; +} + +.form-group-wide { + grid-column: 1 / -1; +} + +.form-group label { + font-family: 'Rajdhani', sans-serif; + font-weight: 600; + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.65); +} + +.form-group .form-control { + background: rgba(255, 255, 255, 0.06); + border: 0.5px solid rgba(255, 255, 255, 0.15); + border-radius: 8px; + color: #ffffff; + padding: 7px 10px; + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; +} + +.form-group .form-control:focus { + outline: none; + border-color: #60a5fa; +} + +.swap-location { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.5rem 0.75rem; + margin-top: 1rem; + padding: 0.75rem 1rem; + background: rgba(0, 0, 0, 0.3); + border-radius: 12px; +} + +.swap-location-label { + font-family: 'Rajdhani', sans-serif; + font-weight: 600; + color: rgba(255, 255, 255, 0.7); +} + +.swap-location-hint { + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.45); +} + +.swap-location-select { + flex: 1; + min-width: 200px; + background: rgba(255, 255, 255, 0.06); + border: 0.5px solid rgba(255, 255, 255, 0.15); + border-radius: 8px; + color: #ffffff; + padding: 7px 10px; + font-family: 'Rajdhani', sans-serif; +} + +.swap-actions { + margin-top: 1rem; +} + /* ======================================== Responsive ======================================== */ @@ -726,7 +1083,8 @@ .checkout-card, .results-section, - .scanned-section { + .scanned-section, + .swap-panel { max-width: 600px; } } @@ -738,7 +1096,8 @@ .checkout-card, .results-section, - .scanned-section { + .scanned-section, + .swap-panel { max-width: 700px; } } diff --git a/Lagerbestand/Components/Pages/TireStorage.razor b/Lagerbestand/Components/Pages/TireStorage.razor index 84ee90a..cd451cb 100644 --- a/Lagerbestand/Components/Pages/TireStorage.razor +++ b/Lagerbestand/Components/Pages/TireStorage.razor @@ -40,120 +40,101 @@ else
- @* Statistics *@ -
-
- @stats.TotalStacksStored - Stapel (@stats.TotalTiresStored Reifen) -
-
- @stats.CustomerStackCount - Kundenstapel -
-
- @stats.InventoryStackCount - Lagerbestand -
-
- @stats.AvailableLocations - Freie Plätze -
+ @* Compact Toolbar: Stats as clickable filter chips + controls *@ +
+
+ + + + + @stats.AvailableLocations Frei + +
+ +
+ + +
+ Nach Saison filtern + + + +
+ + @if (typeFilter == true && categories.Count > 0) + { + + } + +
+ + +
+ + @if (HasActiveFilters) + { + + } +
- @* Type Filter (Customer vs Inventory) *@ - - - @* View Toggle (List / Rack Grid) *@ - - - @* Search & Filter *@ -
- - - Durchsucht Namen, Fahrzeuge, Kategorien und Ticket-Nummern - -
- Nach Saison filtern - - - - -
-
- - @* Category Filter (only when showing inventory) *@ - @if (typeFilter == true && categories.Count > 0) - { -
- - -
- } - @* Tire Stacks List *@ @if (isLoading) { @@ -224,24 +205,22 @@ else @if (selectedLocation.IsOccupied && selectedLocation.OccupiedTireStack != null) { var stack = selectedLocation.OccupiedTireStack; -
-
-
Ticket-Nr.
-
@stack.TicketNumber
+ @StackDetailLists(stack) + @if (!string.IsNullOrEmpty(stack.Notes)) + { +
+ Notizen: + @stack.Notes
-
-
@(stack.IsInventory ? "Kategorie" : "Kunde")
-
@(stack.IsInventory ? stack.CatalogItem?.Name ?? "Lagerbestand" : stack.Customer?.FullName ?? "-")
-
-
-
Reifen
-
@(stack.TireSize ?? "-") @(stack.WithRims ? "| mit Felgen" : "")
-
-
-
Eingelagert
-
@stack.StoredAt.ToLocalTime().ToString("dd.MM.yyyy")
-
-
+ } + } else if (!selectedLocation.IsAvailable) { @@ -270,110 +249,171 @@ else } else { + @if (selectedStack != null) + { + + } +
@foreach (var ts in filteredTireStacks) { -
-
-
-
- @(ts.Season == TireSeason.Sommer ? "☀️" : ts.Season == TireSeason.Winter ? "❄️" : "🔄") -
-
- @if (ts.IsInventory) - { - - @(ts.CatalogItem?.Name ?? "Lagerbestand") - - } - else - { - @ts.Customer?.FullName - } - 1 Stapel (@TireStack.TiresPerStack Reifen) @(ts.TireSize != null ? $"| {ts.TireSize}" : "") @(ts.WithRims ? "| mit Felgen" : "") -
-
-
- @(ts.StorageLocation?.Code ?? "-") - @if (!ts.IsInventory && ts.Vehicle != null) - { - @ts.Vehicle.ShortName - } + aria-selected="@(selectedStack?.Id == ts.Id)"> +
+
@if (ts.IsInventory) { + + @(ts.CatalogItem?.Name ?? "Lagerbestand") + Lager } + else + { + @ts.Customer?.FullName + @if (ts.Vehicle != null) + { + @ts.Vehicle.Make @ts.Vehicle.Model + } + } +
+
+ @if (ts.StorageLocation != null) + { + + @ts.StorageLocation.Area.GetDisplayName() + Regal @ts.StorageLocation.Row + @ts.StorageLocation.Position.GetShortName() + P@(ts.StorageLocation.SlotNumber) + + } + else + { + - + }
- - @if (expandedId == ts.Id) - { -
-
-
-
Ticket-Nr.
-
@ts.TicketNumber
-
-
-
Reifenstapel
-
1 Stapel (@TireStack.TiresPerStack Reifen)
-
- @if (ts.IsInventory && ts.CatalogItem != null) - { -
-
Kategorie
-
@ts.CatalogItem.Name
-
- } -
-
Marke
-
@(ts.TireBrand ?? "-")
-
-
-
Modell
-
@(ts.TireModel ?? "-")
-
-
-
Zustand
-
@ts.ConditionText
-
-
-
Eingelagert
-
-
-
-
Dauer
-
@ts.DaysStored Tage
-
-
- @if (!string.IsNullOrEmpty(ts.Notes)) - { -
- Notizen: - @ts.Notes -
- } - -
- } +
+ + @(ts.Season == TireSeason.Sommer ? "☀️" : ts.Season == TireSeason.Winter ? "❄️" : "🔄") + + @ts.ItemCount Reifen @(ts.TireSize != null ? $"| {ts.TireSize}" : "") @(ts.TireModel != null ? $"| {ts.TireModel}" : "") @(ts.WithRims ? "| mit Felgen" : "") +
}
} + @if (showEditModal && editStack != null) + { + + } + @* Expiring Pickups Warning (only for customer stacks) *@ @if (expiringPickups.Count > 0) { @@ -394,6 +434,136 @@ else } @code { + private static string CheckinUrl(TireStack stack) => $"/tire-checkin?customerId={stack.CustomerId}"; + private static string CheckoutUrl(TireStack stack) => $"/tire-checkout?stackId={stack.Id}"; + + private RenderFragment StackDetailLists => stack => __builder => + { +
+
+

@(stack.IsInventory ? "Bestand & Lagerplatz" : "Kunde & Lagerplatz")

+
+
+
Ticket-Nr.
+
@stack.TicketNumber
+
+ @if (stack.IsInventory) + { +
+
Kategorie
+
@(stack.CatalogItem?.Name ?? "Lagerbestand")
+
+ } + else + { +
+
Kunde
+
@(stack.Customer?.FullName ?? "-")
+
+
+
Kundennr.
+
@(stack.Customer?.CustomerNumber ?? "-")
+
+
+
Telefon
+
@(stack.Customer?.Phone ?? "-")
+
+
+
Fahrzeug
+
@(stack.Vehicle != null ? $"{stack.Vehicle.Make} {stack.Vehicle.Model}".Trim() : "-")
+
+ } +
+
Lagerplatz
+
+ @if (stack.StorageLocation != null) + { + + @stack.StorageLocation.Area.GetDisplayName() + Regal @stack.StorageLocation.Row + @stack.StorageLocation.Position.GetShortName() + P@(stack.StorageLocation.SlotNumber) + + } + else + { + - + } +
+
+
+
Code
+
@(stack.StorageLocation?.Code ?? "-")
+
+
+
+ +
+

Reifen & Lagerung

+
+
+
Anzahl
+
@stack.ItemCount Reifen
+
+
+
Größe
+
@(stack.TireSize ?? "-")
+
+
+
Marke / Modell
+
@(string.Join(" ", new[] { stack.TireBrand, stack.TireModel }.Where(s => !string.IsNullOrWhiteSpace(s))) is { Length: > 0 } bm ? bm : "-")
+
+
+
Saison
+
@(stack.Season == TireSeason.Sommer ? "☀️ Sommer" : stack.Season == TireSeason.Winter ? "❄️ Winter" : "🔄 Allrad")
+
+
+
Felgen
+
@(stack.WithRims ? "Mit Felgen" : "Ohne Felgen")
+
+
+
Zustand
+
@stack.ConditionText
+
+
+
Eingelagert
+
(@stack.DaysStored Tage)
+
+ @if (stack.ExpectedPickupDate.HasValue) + { +
+
Abholung erwartet
+
+
+ } + @if (latestInspections.TryGetValue(stack.Id, out var insp) && insp != null) + { +
+
Letzte Messung
+
+
+ VL @FmtMm(insp.TreadDepthFL) + VR @FmtMm(insp.TreadDepthFR) + HL @FmtMm(insp.TreadDepthRL) + HR @FmtMm(insp.TreadDepthRR) +
+ + @((insp.MeasuredAt ?? insp.CreatedAt).ToLocalTime().ToString("dd.MM.yyyy")) + @if (insp.Mileage.HasValue) { · @insp.Mileage.Value.ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("de-DE")) km } + @if (!string.IsNullOrEmpty(insp.LicensePlate)) { · @insp.LicensePlate } + + @if (!string.IsNullOrEmpty(insp.ReportUrl)) + { + Report öffnen ↗ + } +
+
+ } +
+
+
+ }; + private List allTireStacks = new(); private List filteredTireStacks = new(); private List expiringPickups = new(); @@ -404,7 +574,36 @@ else private TireSeason? seasonFilter; private bool? typeFilter; // null = all, false = customer, true = inventory private string selectedCategoryId = ""; - private Guid? expandedId; + private TireStack? selectedStack; + private readonly Dictionary latestInspections = new(); + + private static string RatingClass(TireMeasureRating r) => r switch + { + TireMeasureRating.Ok => "ok", + TireMeasureRating.Warning => "warn", + TireMeasureRating.Critical => "crit", + _ => "none" + }; + + private static string FmtMm(decimal? mm) => mm.HasValue ? mm.Value.ToString("0.0", System.Globalization.CultureInfo.GetCultureInfo("de-DE")) + " mm" : "–"; + + private async Task LoadLatestInspection(TireStack ts) + { + if (latestInspections.ContainsKey(ts.Id)) return; + try + { + latestInspections[ts.Id] = await TireStackService.GetLatestInspectionAsync(ts.Id); + } + catch + { + latestInspections[ts.Id] = null; + } + } + private TireStack? editStack; + private TireStack? editSource; + private bool showEditModal; + private bool isSaving; + private string? editError; private bool isLoading = true; private bool showGridView; private List allLocations = new(); @@ -487,6 +686,19 @@ else ApplyFilters(); } + private bool HasActiveFilters => + typeFilter != null || seasonFilter != null || + !string.IsNullOrEmpty(selectedCategoryId) || !string.IsNullOrWhiteSpace(searchTerm); + + private void ResetFilters() + { + typeFilter = null; + seasonFilter = null; + selectedCategoryId = ""; + searchTerm = ""; + ApplyFilters(); + } + private void ApplyFilters() { var query = allTireStacks.AsEnumerable(); @@ -532,9 +744,86 @@ else filteredTireStacks = query.OrderBy(ts => ts.StorageLocation?.Code).ToList(); } - private void ToggleDetails(Guid id) + private async Task SelectStack(TireStack ts) { - expandedId = expandedId == id ? null : id; + selectedStack = selectedStack?.Id == ts.Id ? null : ts; + if (selectedStack != null) + { + await LoadLatestInspection(selectedStack); + } + } + + private void OpenEditModal() + { + if (selectedStack == null) return; + OpenEditModalFor(selectedStack); + } + + private void OpenEditModalFor(TireStack source) + { + editSource = source; + editStack = new TireStack + { + Id = source.Id, + TireSize = source.TireSize, + TireBrand = source.TireBrand, + TireModel = source.TireModel, + ItemCount = source.ItemCount, + Season = source.Season, + Condition = source.Condition, + WithRims = source.WithRims, + Notes = source.Notes, + TicketNumber = source.TicketNumber + }; + editError = null; + showEditModal = true; + } + + private void CloseEditModal() + { + if (isSaving) return; + showEditModal = false; + editStack = null; + editSource = null; + editError = null; + } + + private async Task SaveEdit() + { + if (editStack == null || editSource == null) return; + isSaving = true; + editError = null; + try + { + editSource.TireSize = editStack.TireSize; + editSource.TireBrand = editStack.TireBrand; + editSource.TireModel = editStack.TireModel; + editSource.ItemCount = editStack.ItemCount; + editSource.Season = editStack.Season; + editSource.Condition = editStack.Condition; + editSource.WithRims = editStack.WithRims; + editSource.Notes = editStack.Notes; + + await TireStackService.UpdateAsync(editSource); + + showEditModal = false; + editStack = null; + editSource = null; + var selectedId = selectedStack?.Id; + await LoadData(); + if (selectedId.HasValue) + { + selectedStack = allTireStacks.FirstOrDefault(ts => ts.Id == selectedId.Value); + } + } + catch (Exception ex) + { + editError = $"Fehler beim Speichern: {ex.Message}"; + } + finally + { + isSaving = false; + } } private StorageLocation? GetLocation(AreaType area, int row, ShelfPosition pos, int slot) @@ -542,10 +831,14 @@ else return locationLookup.TryGetValue((area, row, pos, slot), out var loc) ? loc : null; } - private void SelectLocation(StorageLocation? location) + private async Task SelectLocation(StorageLocation? location) { if (location == null) return; selectedLocation = selectedLocation?.Id == location.Id ? null : location; + if (selectedLocation?.OccupiedTireStack != null) + { + await LoadLatestInspection(selectedLocation.OccupiedTireStack); + } } private string GetCellTooltip(StorageLocation? loc, AreaType area, int row, ShelfPosition pos, int slot) diff --git a/Lagerbestand/Components/Pages/TireStorage.razor.css b/Lagerbestand/Components/Pages/TireStorage.razor.css index 582d5a4..2d9ab50 100644 --- a/Lagerbestand/Components/Pages/TireStorage.razor.css +++ b/Lagerbestand/Components/Pages/TireStorage.razor.css @@ -34,12 +34,12 @@ Page Header - Responsive ======================================== */ .page-header { - margin-bottom: 1rem; + margin-bottom: 0.75rem; } @media (min-width: 480px) { .page-header { - margin-bottom: 1.5rem; + margin-bottom: 0.75rem; } } @@ -85,193 +85,145 @@ } /* ======================================== - Statistics Grid - Responsive + Compact Toolbar (Stats + Filter combined) ======================================== */ -.stats-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 8px; - margin-bottom: 1rem; -} - -@media (min-width: 480px) { - .stats-grid { - grid-template-columns: repeat(4, 1fr); - gap: 10px; - margin-bottom: 1.5rem; - } -} - -@media (min-width: 768px) { - .stats-grid { - gap: 16px; - } -} - -@media (min-width: 1024px) { - .stats-grid { - gap: 20px; - } -} - -.stat-card { - background: rgba(28, 28, 30, 0.8); - border: 0.5px solid rgba(255, 255, 255, 0.1); +.toolbar { + position: sticky; + top: 0; + z-index: 10; + display: flex; + flex-direction: column; + gap: 0.5rem; + margin-bottom: 0.75rem; + padding: 0.6rem 0.75rem; + background: rgba(28, 28, 30, 0.92); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); border-radius: 12px; - padding: 12px; - text-align: center; -} - -@media (min-width: 480px) { - .stat-card { - padding: 14px; - border-radius: 14px; - } -} - -@media (min-width: 768px) { - .stat-card { - padding: 20px; - } + border: 0.5px solid rgba(255, 255, 255, 0.1); } @media (min-width: 1024px) { - .stat-card { - padding: 24px; - border-radius: 16px; + .toolbar { + flex-direction: row; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 0.75rem; } } -.stat-value { - display: block; - font-family: 'Orbitron', monospace; - font-size: clamp(1.25rem, 4vw, 2.25rem); - font-weight: 700; - color: #ffffff; - margin-bottom: 4px; -} - -.stat-value.summer { - color: #fbbf24; -} - -.stat-value.winter { - color: #60a5fa; -} - -.stat-label { - font-family: 'Rajdhani', sans-serif; - font-size: clamp(0.65rem, 2vw, 0.85rem); - color: rgba(255, 255, 255, 0.5); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -/* ======================================== - Type Filter - Responsive - ======================================== */ -.type-filter { +/* Stat chips - clickable, act as filters */ +.stat-chips { display: flex; gap: 6px; - margin-bottom: 0.75rem; - background: rgba(28, 28, 30, 0.6); - padding: 5px; - border-radius: 10px; -} - -@media (min-width: 480px) { - .type-filter { - gap: 8px; - padding: 6px; - border-radius: 12px; - margin-bottom: 1rem; - } -} - -.type-btn { - flex: 1; - padding: 8px 10px; - background: transparent; - border: none; - border-radius: 6px; - color: rgba(255, 255, 255, 0.5); - font-family: 'Rajdhani', sans-serif; - font-size: 0.8rem; - font-weight: 500; - cursor: pointer; - transition: all 0.2s ease; - white-space: nowrap; - min-height: 40px; -} - -@media (min-width: 480px) { - .type-btn { - padding: 10px 14px; - font-size: 0.85rem; - border-radius: 8px; - min-height: 44px; - } -} - -.type-btn:hover { - color: rgba(255, 255, 255, 0.7); - background: rgba(255, 255, 255, 0.05); -} - -.type-btn.active { - background: rgba(220, 38, 38, 0.15); - border: 1px solid rgba(220, 38, 38, 0.3); - color: #ffffff; -} - -/* ======================================== - Filter Bar - Responsive - ======================================== */ -.filter-bar { - display: flex; - gap: 8px; - margin-bottom: 1rem; flex-wrap: wrap; } -@media (min-width: 480px) { - .filter-bar { - gap: 10px; - margin-bottom: 1.5rem; - } +.stat-chip { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 5px 10px; + background: rgba(0, 0, 0, 0.3); + border: 0.5px solid rgba(255, 255, 255, 0.1); + border-radius: 8px; + color: rgba(255, 255, 255, 0.6); + font-family: 'Rajdhani', sans-serif; + font-size: 0.75rem; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; + min-height: 32px; } -@media (min-width: 768px) { - .filter-bar { - gap: 14px; - } +.stat-chip.static { + cursor: default; +} + +.stat-chip:not(.static):hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.2); +} + +.stat-chip .chip-value { + font-family: 'Orbitron', monospace; + font-size: 0.85rem; + font-weight: 700; + color: #ffffff; +} + +.stat-chip .chip-value.free { + color: #22c55e; +} + +.stat-chip.active { + background: rgba(220, 38, 38, 0.15); + border-color: rgba(220, 38, 38, 0.4); + color: #ffffff; +} + +.stat-chip.customer.active { + background: rgba(96, 165, 250, 0.15); + border-color: rgba(96, 165, 250, 0.4); + color: #60a5fa; +} + +.stat-chip.inventory.active { + background: rgba(251, 191, 36, 0.15); + border-color: rgba(251, 191, 36, 0.4); + color: #fbbf24; +} + +/* Toolbar controls: search + season + category + view toggle */ +.toolbar-controls { + display: flex; + gap: 6px; + flex-wrap: wrap; + align-items: center; +} + +.toolbar-controls .search-box { + flex: 1; + min-width: 160px; +} + +.toolbar-controls .clear-filters { + padding: 6px 10px; + font-size: 0.75rem; + min-height: 34px; + background: rgba(0, 0, 0, 0.3); + border: 0.5px solid rgba(239, 68, 68, 0.3); + border-radius: 8px; + color: #f87171; + cursor: pointer; + white-space: nowrap; + transition: all 0.2s ease; +} + +.toolbar-controls .clear-filters:hover { + background: rgba(239, 68, 68, 0.1); + border-color: rgba(239, 68, 68, 0.5); } .search-input { flex: 1; min-width: 0; width: 100%; - padding: 12px 14px; - background: rgba(28, 28, 30, 0.8); + padding: 7px 12px; + background: rgba(0, 0, 0, 0.3); border: 0.5px solid rgba(255, 255, 255, 0.1); - border-radius: 10px; + border-radius: 8px; color: #ffffff; font-family: 'Rajdhani', sans-serif; font-size: 16px; /* Prevents iOS zoom */ + min-height: 34px; } @media (min-width: 480px) { .search-input { min-width: 200px; - border-radius: 12px; - } -} - -@media (min-width: 768px) { - .search-input { - max-width: 400px; - padding: 14px 18px; - font-size: 1rem; + font-size: 0.9rem; } } @@ -288,18 +240,14 @@ display: flex; gap: 6px; flex-wrap: wrap; -} - -@media (max-width: 479.98px) { - .filter-buttons { - width: 100%; - justify-content: flex-start; - } + border: none; + margin: 0; + padding: 0; } .filter-btn { - padding: 10px 12px; - background: rgba(28, 28, 30, 0.8); + padding: 5px 10px; + background: rgba(0, 0, 0, 0.3); border: 0.5px solid rgba(255, 255, 255, 0.1); border-radius: 8px; color: rgba(255, 255, 255, 0.6); @@ -307,15 +255,7 @@ font-size: 0.85rem; cursor: pointer; transition: all 0.2s ease; - min-height: 44px; -} - -@media (min-width: 480px) { - .filter-btn { - padding: 10px 14px; - border-radius: 10px; - font-size: 0.9rem; - } + min-height: 34px; } .filter-btn:hover { @@ -877,41 +817,27 @@ } /* ======================================== - Category Filter - Responsive + Category Select (in Toolbar) ======================================== */ -.category-filter { - margin-bottom: 0.75rem; -} - -@media (min-width: 480px) { - .category-filter { - margin-bottom: 1rem; - } -} - -.category-filter .form-control { - width: 100%; - padding: 10px 14px; - background: rgba(28, 28, 30, 0.8); +.category-select { + width: auto; + min-width: 140px; + padding: 6px 10px; + background: rgba(0, 0, 0, 0.3); border: 0.5px solid rgba(255, 255, 255, 0.1); - border-radius: 10px; + border-radius: 8px; color: #ffffff; font-family: 'Rajdhani', sans-serif; - font-size: 16px; /* Prevents iOS zoom */ + font-size: 0.8rem; + min-height: 34px; } -@media (min-width: 480px) { - .category-filter .form-control { - max-width: 300px; - } -} - -.category-filter .form-control:focus { +.category-select:focus { outline: none; border-color: rgba(220, 38, 38, 0.5); } -.category-filter .form-control option { +.category-select option { background: #1c1c1e; color: #ffffff; } @@ -921,26 +847,26 @@ ======================================== */ .view-toggle { display: flex; - gap: 6px; - margin-bottom: 0.75rem; - background: rgba(28, 28, 30, 0.6); - padding: 5px; - border-radius: 10px; + gap: 4px; + background: rgba(0, 0, 0, 0.3); + padding: 3px; + border-radius: 8px; + border: 0.5px solid rgba(255, 255, 255, 0.1); } .view-btn { - flex: 1; - padding: 8px 10px; + padding: 5px 10px; background: transparent; border: none; border-radius: 6px; color: rgba(255, 255, 255, 0.5); font-family: 'Rajdhani', sans-serif; - font-size: 0.85rem; + font-size: 0.8rem; font-weight: 500; cursor: pointer; transition: all 0.2s ease; - min-height: 40px; + min-height: 28px; + white-space: nowrap; } .view-btn:hover { @@ -1194,4 +1120,416 @@ margin: 0.5rem 0; } +/* ======================================== + Card two-row layout + ======================================== */ +.card-row { + display: flex; + align-items: center; + gap: 10px; +} + +.card-row-primary { + justify-content: space-between; + padding: 12px 14px 6px; +} + +.card-row-secondary { + padding: 0 14px 12px; + gap: 8px; +} + +@media (min-width: 768px) { + .card-row-primary { + padding: 16px 24px 8px; + } + + .card-row-secondary { + padding: 0 24px 16px; + } +} + +.card-identity { + display: flex; + align-items: center; + gap: 10px; + min-width: 0; + flex: 1; +} + +.card-row .customer-name { + font-size: 1.05rem; +} + +@media (min-width: 768px) { + .card-row .customer-name { + font-size: 1.2rem; + } +} + +.vehicle-badge { + background: rgba(255, 255, 255, 0.1); + border-radius: 6px; + padding: 2px 8px; + font-family: 'Rajdhani', sans-serif; + font-weight: 600; + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.85); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 40vw; +} + +@media (min-width: 768px) { + .vehicle-badge { + font-size: 0.9rem; + } +} + +.card-location { + flex-shrink: 0; +} + +.location-indicator { + display: inline-flex; + align-items: center; + gap: 4px; + font-family: 'Rajdhani', sans-serif; + font-weight: 600; + font-size: 0.8rem; + white-space: nowrap; +} + +@media (min-width: 768px) { + .location-indicator { + font-size: 0.95rem; + gap: 6px; + } +} + +.loc-area { + padding: 2px 8px; + border-radius: 6px; + font-weight: 700; +} + +.loc-area.werkstatt { + background: rgba(155, 89, 182, 0.2); + color: #c084fc; +} + +.loc-area.lager { + background: rgba(52, 152, 219, 0.2); + color: #60a5fa; +} + +.loc-part { + background: rgba(255, 255, 255, 0.08); + padding: 2px 6px; + border-radius: 6px; + color: rgba(255, 255, 255, 0.85); +} + +.card-row-secondary .season-indicator { + width: 28px; + height: 28px; + font-size: 0.9rem; + border-radius: 6px; +} + +.tireset-card.selected { + border-color: #60a5fa; + box-shadow: 0 0 0 1px rgba(96, 165, 250, 0.4); +} + +/* ======================================== + Selected stack details panel + ======================================== */ +.stack-details-panel { + background: rgba(28, 28, 30, 0.95); + border: 1px solid rgba(96, 165, 250, 0.4); + border-radius: 12px; + padding: 1rem; + margin-bottom: 1rem; +} + +@media (min-width: 768px) { + .stack-details-panel { + padding: 1.25rem 1.5rem; + border-radius: 16px; + } +} + +.stack-details-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.75rem; + flex-wrap: wrap; + margin-bottom: 0.75rem; +} + +.stack-details-title { + display: flex; + align-items: center; + gap: 10px; + min-width: 0; + flex-wrap: wrap; +} + +.stack-details-title h2 { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-weight: 700; + color: #ffffff; + font-size: 1.2rem; +} + +@media (min-width: 768px) { + .stack-details-title h2 { + font-size: 1.4rem; + } +} + +.stack-details-actions { + display: flex; + gap: 0.5rem; + flex-shrink: 0; +} + +.detail-columns { + display: grid; + grid-template-columns: 1fr; + gap: 0.75rem; + margin-bottom: 0.75rem; +} + +@media (min-width: 768px) { + .detail-columns { + grid-template-columns: 1fr 1fr; + gap: 1rem; + } +} + +.detail-list { + background: rgba(255, 255, 255, 0.03); + border: 0.5px solid rgba(255, 255, 255, 0.08); + border-radius: 10px; + padding: 0.75rem 1rem; +} + +.detail-list-title { + margin: 0 0 0.5rem; + padding-bottom: 0.4rem; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.1); + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.75); +} + +.detail-rows { + margin: 0; + display: flex; + flex-direction: column; +} + +.detail-row { + display: grid; + grid-template-columns: minmax(110px, 38%) 1fr; + gap: 0.75rem; + align-items: center; + padding: 0.4rem 0; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.05); +} + +.detail-row:last-child { + border-bottom: none; +} + +.detail-row dt { + font-family: 'Rajdhani', sans-serif; + font-size: 0.85rem; + font-weight: 600; + color: rgba(255, 255, 255, 0.5); + margin: 0; +} + +.detail-row dd { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; + font-weight: 600; + color: #ffffff; + min-width: 0; + overflow-wrap: anywhere; +} + +.detail-row dd.mono { + font-family: 'Orbitron', monospace; + font-size: 0.85rem; + letter-spacing: 0.04em; + color: #60a5fa; +} + +.detail-row .muted { + color: rgba(255, 255, 255, 0.5); + font-weight: 500; +} + +/* ======================================== + Edit modal + ======================================== */ +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.65); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + padding: 1rem; +} + +.modal-dialog { + background: #1c1c1e; + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 16px; + width: 100%; + max-width: 560px; + max-height: 90vh; + overflow-y: auto; + display: flex; + flex-direction: column; +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 1.25rem; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.1); +} + +.modal-header h2 { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-size: 1.1rem; + font-weight: 700; + color: #ffffff; +} + +.modal-close { + background: none; + border: none; + color: rgba(255, 255, 255, 0.6); + font-size: 1.1rem; + cursor: pointer; + padding: 4px 8px; + border-radius: 6px; +} + +.modal-close:hover { + background: rgba(255, 255, 255, 0.1); + color: #ffffff; +} + +.modal-body { + padding: 1rem 1.25rem; +} + +.form-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.75rem 1rem; +} + +@media (max-width: 479px) { + .form-grid { + grid-template-columns: 1fr; + } +} + +.form-group { + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.form-group-wide { + grid-column: 1 / -1; +} + +.form-group label { + font-family: 'Rajdhani', sans-serif; + font-weight: 600; + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.7); +} + +.form-group .form-control { + background: rgba(255, 255, 255, 0.06); + border: 0.5px solid rgba(255, 255, 255, 0.15); + border-radius: 8px; + color: #ffffff; + padding: 8px 10px; + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; +} + +.form-group .form-control:focus { + outline: none; + border-color: #60a5fa; +} + +.edit-error { + color: #f87171; + font-family: 'Rajdhani', sans-serif; + margin: 0.75rem 0 0; +} + +.modal-footer { + display: flex; + justify-content: flex-end; + gap: 0.5rem; + padding: 1rem 1.25rem; + border-top: 0.5px solid rgba(255, 255, 255, 0.1); +} + +/* ======================================== + Tread depth measurement (detail list) + ======================================== */ +.tread-chips { + display: flex; + flex-wrap: wrap; + gap: 4px; + margin-bottom: 4px; +} + +.tread-chip { + font-family: 'Rajdhani', sans-serif; + font-size: 0.78rem; + font-weight: 600; + padding: 2px 8px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.08); + color: rgba(255, 255, 255, 0.85); + border: 0.5px solid rgba(255, 255, 255, 0.12); +} + +.tread-chip.rating-ok { background: rgba(34, 197, 94, 0.15); border-color: rgba(34, 197, 94, 0.4); color: #86efac; } +.tread-chip.rating-warn { background: rgba(250, 204, 21, 0.15); border-color: rgba(250, 204, 21, 0.4); color: #fde047; } +.tread-chip.rating-crit { background: rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.4); color: #fca5a5; } + +.report-link { + display: inline-block; + margin-top: 2px; + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + color: #60a5fa; +} + /* Reduced motion: inherited from app.css (section 17) */ diff --git a/Lagerbestand/Components/Shared/QrScannerModal.razor b/Lagerbestand/Components/Shared/QrScannerModal.razor new file mode 100644 index 0000000..f13f40a --- /dev/null +++ b/Lagerbestand/Components/Shared/QrScannerModal.razor @@ -0,0 +1,161 @@ +@implements IAsyncDisposable +@inject IJSRuntime JS + +@if (IsOpen) +{ +
+ +
+} + +@code { + [Parameter] public bool IsOpen { get; set; } + [Parameter] public EventCallback IsOpenChanged { get; set; } + [Parameter] public string Title { get; set; } = "QR-Code scannen"; + [Parameter] public string? Subtitle { get; set; } + [Parameter] public EventCallback OnScanned { get; set; } + + private readonly string _elementId = $"qr-reader-{Guid.NewGuid():N}"; + private DotNetObjectReference? _selfRef; + private bool _scannerActive; + private bool _wasOpen; + private bool isStarting; + private string? cameraError; + private string manualText = ""; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (IsOpen && !_wasOpen) + { + _wasOpen = true; + await StartScanner(); + } + else if (!IsOpen && _wasOpen) + { + _wasOpen = false; + await StopScanner(); + } + } + + private async Task StartScanner() + { + cameraError = null; + isStarting = true; + manualText = ""; + StateHasChanged(); + + try + { + _selfRef ??= DotNetObjectReference.Create(this); + await JS.InvokeVoidAsync("qrScanner.start", _elementId, _selfRef); + _scannerActive = true; + } + catch (JSException ex) + { + cameraError = ExtractMessage(ex.Message); + } + catch (Exception ex) + { + cameraError = ex.Message; + } + finally + { + isStarting = false; + StateHasChanged(); + } + } + + private static string ExtractMessage(string raw) + { + if (raw.Contains("NotAllowedError", StringComparison.OrdinalIgnoreCase) || raw.Contains("Permission", StringComparison.OrdinalIgnoreCase)) + return "Kamerazugriff wurde verweigert. Bitte Berechtigung im Browser erlauben."; + if (raw.Contains("NotFoundError", StringComparison.OrdinalIgnoreCase) || raw.Contains("Keine Kamera", StringComparison.OrdinalIgnoreCase)) + return "Keine Kamera gefunden."; + var idx = raw.IndexOf('\n'); + return idx > 0 ? raw[..idx] : raw; + } + + private async Task StopScanner() + { + if (!_scannerActive) return; + _scannerActive = false; + try { await JS.InvokeVoidAsync("qrScanner.stop"); } catch { } + } + + [JSInvokable] + public async Task OnQrScanned(string text) + { + if (string.IsNullOrWhiteSpace(text)) return; + await Close(); + await OnScanned.InvokeAsync(text.Trim()); + } + + private async Task SubmitManual() + { + if (string.IsNullOrWhiteSpace(manualText)) return; + var text = manualText.Trim(); + await Close(); + await OnScanned.InvokeAsync(text); + } + + private async Task OnManualKeyDown(KeyboardEventArgs e) + { + if (e.Key == "Enter") await SubmitManual(); + } + + private async Task Cancel() => await Close(); + + private async Task Close() + { + await StopScanner(); + _wasOpen = false; + if (IsOpen) + { + IsOpen = false; + await IsOpenChanged.InvokeAsync(false); + } + } + + public async ValueTask DisposeAsync() + { + await StopScanner(); + _selfRef?.Dispose(); + } +} diff --git a/Lagerbestand/Components/Shared/QrScannerModal.razor.css b/Lagerbestand/Components/Shared/QrScannerModal.razor.css new file mode 100644 index 0000000..2c5ba7a --- /dev/null +++ b/Lagerbestand/Components/Shared/QrScannerModal.razor.css @@ -0,0 +1,142 @@ +.qr-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.85); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; + padding: 1rem; + z-index: 1200; +} + +.qr-dialog { + background: #1c1c1e; + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 16px; + width: 100%; + max-width: 520px; + max-height: 92vh; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.qr-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 1rem; + padding: 1rem 1.25rem; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.1); +} + +.qr-header h3 { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-size: 1.2rem; + font-weight: 700; + color: #ffffff; +} + +.qr-subtitle { + margin: 0.2rem 0 0; + font-family: 'Rajdhani', sans-serif; + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.55); +} + +.qr-close { + background: none; + border: none; + color: rgba(255, 255, 255, 0.6); + font-size: 1.1rem; + cursor: pointer; + padding: 4px 8px; + border-radius: 6px; +} + +.qr-close:hover { + background: rgba(255, 255, 255, 0.1); + color: #ffffff; +} + +.qr-body { + padding: 1rem 1.25rem 1.25rem; + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 0.9rem; +} + +.qr-viewport { + width: 100%; + min-height: 260px; + border-radius: 12px; + overflow: hidden; + background: #000; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +::deep .qr-viewport video { + width: 100% !important; + border-radius: 12px; +} + +::deep .qr-viewport img[alt="Info icon"], +::deep .qr-viewport img[alt="Camera based scan"] { + display: none; +} + +.qr-status { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; + color: rgba(255, 255, 255, 0.7); + text-align: center; +} + +.qr-status.error { + color: #f87171; +} + +.qr-status .spinner { + width: 16px; + height: 16px; + border: 2px solid rgba(255, 255, 255, 0.2); + border-top-color: #dc2626; + border-radius: 50%; + animation: qr-spin 0.8s linear infinite; +} + +@keyframes qr-spin { + to { transform: rotate(360deg); } +} + +.qr-manual { + border-top: 0.5px solid rgba(255, 255, 255, 0.1); + padding-top: 0.9rem; +} + +.qr-manual label { + display: block; + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.05em; + color: rgba(255, 255, 255, 0.5); + margin-bottom: 0.4rem; +} + +.qr-manual-row { + display: flex; + gap: 0.5rem; +} + +.qr-manual-row .form-control { + flex: 1; + min-width: 0; +} diff --git a/Lagerbestand/Components/Shared/StorageLocationPickerModal.razor b/Lagerbestand/Components/Shared/StorageLocationPickerModal.razor new file mode 100644 index 0000000..2ba98c6 --- /dev/null +++ b/Lagerbestand/Components/Shared/StorageLocationPickerModal.razor @@ -0,0 +1,190 @@ +@using Lagerbestand.Models +@using Lagerbestand.Services +@inject IStorageLocationService StorageLocationService + +@if (IsOpen) +{ +
+ +
+} + +@code { + [Parameter] public bool IsOpen { get; set; } + [Parameter] public EventCallback IsOpenChanged { get; set; } + + /// Currently selected location (pre-selected when opening). + [Parameter] public Guid? SelectedLocationId { get; set; } + + /// Location that is about to be freed (e.g. during a swap) – shown as selectable. + [Parameter] public Guid? HighlightLocationId { get; set; } + + [Parameter] public string? Subtitle { get; set; } + + [Parameter] public EventCallback OnSelected { get; set; } + + private bool isLoading; + private bool wasOpen; + private List allLocations = new(); + private Dictionary<(AreaType, int, ShelfPosition, int), StorageLocation> lookup = new(); + private StorageLocation? pendingLocation; + + protected override async Task OnParametersSetAsync() + { + if (IsOpen && !wasOpen) + { + wasOpen = true; + await LoadAsync(); + } + else if (!IsOpen) + { + wasOpen = false; + } + } + + private async Task LoadAsync() + { + isLoading = true; + try + { + allLocations = await StorageLocationService.GetAllAsync(); + lookup = allLocations.ToDictionary(l => (l.Area, l.Row, l.Position, l.SlotNumber)); + pendingLocation = SelectedLocationId.HasValue + ? allLocations.FirstOrDefault(l => l.Id == SelectedLocationId.Value) + : null; + } + finally + { + isLoading = false; + } + } + + private StorageLocation? GetLocation(AreaType area, int row, ShelfPosition pos, int slot) + => lookup.TryGetValue((area, row, pos, slot), out var loc) ? loc : null; + + private void Select(StorageLocation? loc) + { + if (loc == null) return; + pendingLocation = loc; + } + + private async Task Confirm() + { + if (pendingLocation == null) return; + await OnSelected.InvokeAsync(pendingLocation); + await Close(); + } + + private Task Cancel() => Close(); + + private async Task Close() + { + IsOpen = false; + await IsOpenChanged.InvokeAsync(false); + } + + private string GetTooltip(StorageLocation? loc, AreaType area, int row, ShelfPosition pos, int slot, bool isHighlighted) + { + var baseText = $"{area.GetDisplayName()}, Reihe {row}, {pos.GetDisplayName()}, Platz {slot}"; + if (loc == null) return $"{baseText} – nicht angelegt"; + if (isHighlighted) return $"{baseText} – wird frei"; + if (!loc.IsAvailable) return $"{baseText} – gesperrt"; + if (loc.IsOccupied) return $"{baseText} – belegt"; + return $"{baseText} – frei"; + } +} diff --git a/Lagerbestand/Components/Shared/StorageLocationPickerModal.razor.css b/Lagerbestand/Components/Shared/StorageLocationPickerModal.razor.css new file mode 100644 index 0000000..db041bc --- /dev/null +++ b/Lagerbestand/Components/Shared/StorageLocationPickerModal.razor.css @@ -0,0 +1,309 @@ +/* ======================================== + Overlay & Dialog + ======================================== */ +.picker-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.8); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; + padding: 1rem; + z-index: 1100; +} + +.picker-dialog { + background: #1c1c1e; + border: 1px solid rgba(255, 255, 255, 0.15); + border-radius: 16px; + width: 100%; + max-width: 1100px; + max-height: 92vh; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.picker-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 1rem; + padding: 1rem 1.25rem; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.1); +} + +.picker-header h2 { + margin: 0; + font-family: 'Rajdhani', sans-serif; + font-size: 1.2rem; + font-weight: 700; + color: #ffffff; +} + +.picker-subtitle { + margin: 0.2rem 0 0; + font-family: 'Rajdhani', sans-serif; + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.55); +} + +.picker-close { + background: none; + border: none; + color: rgba(255, 255, 255, 0.6); + font-size: 1.1rem; + cursor: pointer; + padding: 4px 8px; + border-radius: 6px; +} + +.picker-close:hover { + background: rgba(255, 255, 255, 0.1); + color: #ffffff; +} + +.picker-body { + padding: 1rem 1.25rem; + overflow-y: auto; + flex: 1; +} + +.picker-loading { + text-align: center; + padding: 2rem; + color: rgba(255, 255, 255, 0.6); + font-family: 'Rajdhani', sans-serif; +} + +.picker-footer { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 0.75rem; + padding: 0.85rem 1.25rem; + border-top: 0.5px solid rgba(255, 255, 255, 0.1); +} + +.picker-selection { + display: flex; + align-items: center; + gap: 0.5rem; + font-family: 'Rajdhani', sans-serif; +} + +.picker-selection-label { + font-weight: 600; + color: rgba(255, 255, 255, 0.7); +} + +.picker-selection-hint { + color: rgba(255, 255, 255, 0.45); +} + +.picker-actions { + display: flex; + gap: 0.5rem; +} + +/* ======================================== + Rack Grid (mirrors TireStorage rack view) + ======================================== */ +.rack-view { + display: flex; + flex-direction: column; + gap: 1rem; + width: 100%; +} + +@media (min-width: 1024px) { + .rack-view { + display: grid; + grid-template-columns: 1fr 1fr; + align-items: start; + } +} + +.building-section { + background: rgba(28, 28, 30, 0.8); + border: 0.5px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 1rem; + width: 100%; +} + +.building-title { + font-family: 'Rajdhani', sans-serif; + font-size: 1.05rem; + font-weight: 600; + color: #ffffff; + margin: 0 0 0.75rem 0; + padding-bottom: 0.4rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.08); +} + +.rack-row { + margin-bottom: 0.75rem; +} + +.row-title { + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + font-weight: 600; + color: rgba(255, 255, 255, 0.7); + margin: 0 0 0.3rem 0; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.rack-sides { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; +} + +@media (max-width: 767.98px) { + .rack-sides { + grid-template-columns: 1fr; + gap: 0.5rem; + } +} + +.rack-side { + min-width: 0; +} + +.side-label { + display: block; + font-size: 0.65rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + color: rgba(255, 255, 255, 0.4); + margin-bottom: 0.2rem; +} + +.rack-level { + display: flex; + align-items: center; + gap: 0.4rem; + margin: 0.2rem 0; +} + +.level-label { + width: 2.6rem; + flex-shrink: 0; + font-size: 0.65rem; + color: rgba(255, 255, 255, 0.4); +} + +.rack-cells { + display: grid; + grid-template-columns: repeat(9, 1fr); + gap: 4px; + flex: 1; + min-width: 0; +} + +.rack-cell { + width: 100%; + min-height: 2rem; + border-radius: 6px; + border: 1px solid transparent; + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + font-weight: 700; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: transform 0.15s ease, box-shadow 0.15s ease; + padding: 0; +} + +.rack-cell:not(:disabled):hover { + transform: scale(1.1); +} + +.rack-cell.free { + background: rgba(34, 197, 94, 0.15); + border-color: rgba(34, 197, 94, 0.4); + color: #4ade80; +} + +.rack-cell.freeing { + background: rgba(96, 165, 250, 0.18); + border-color: rgba(96, 165, 250, 0.5); + color: #93c5fd; +} + +.rack-cell.occupied { + background: rgba(220, 38, 38, 0.2); + border-color: rgba(220, 38, 38, 0.45); + color: #f87171; + cursor: not-allowed; +} + +.rack-cell.blocked { + background: rgba(148, 163, 184, 0.15); + border-color: rgba(148, 163, 184, 0.3); + color: rgba(255, 255, 255, 0.35); + cursor: not-allowed; +} + +.rack-cell.missing { + background: transparent; + border: 1px dashed rgba(255, 255, 255, 0.12); + color: rgba(255, 255, 255, 0.2); + cursor: default; +} + +.rack-cell.selected { + outline: 2px solid #22c55e; + outline-offset: 1px; + box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.25); +} + +/* ======================================== + Legend + ======================================== */ +.rack-legend { + display: flex; + gap: 1rem; + flex-wrap: wrap; + margin-top: 0.75rem; + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.6); + font-family: 'Rajdhani', sans-serif; +} + +.legend-item { + display: inline-flex; + align-items: center; + gap: 0.35rem; +} + +.legend-swatch { + width: 0.9rem; + height: 0.9rem; + border-radius: 4px; + display: inline-block; +} + +.legend-swatch.free { + background: rgba(34, 197, 94, 0.4); +} + +.legend-swatch.freeing { + background: rgba(96, 165, 250, 0.5); +} + +.legend-swatch.occupied { + background: rgba(220, 38, 38, 0.45); +} + +.legend-swatch.blocked { + background: rgba(148, 163, 184, 0.35); +} diff --git a/Lagerbestand/Data/AppDbContext.cs b/Lagerbestand/Data/AppDbContext.cs index febf96a..b77a0a7 100644 --- a/Lagerbestand/Data/AppDbContext.cs +++ b/Lagerbestand/Data/AppDbContext.cs @@ -17,6 +17,7 @@ public class AppDbContext : DbContext public DbSet StorageLocations => Set(); public DbSet TireStacks => Set(); public DbSet TireItems => Set(); + public DbSet TireInspections => Set(); public DbSet SiteSettings => Set(); // Kanban entities @@ -84,7 +85,7 @@ public class AppDbContext : DbContext { entity.ToTable("Customers"); entity.HasKey(e => e.Id); - entity.Property(e => e.FirstName).IsRequired().HasMaxLength(100); + entity.Property(e => e.FirstName).HasMaxLength(100); entity.Property(e => e.LastName).IsRequired().HasMaxLength(100); entity.Property(e => e.Company).HasMaxLength(200); entity.Property(e => e.Phone).HasMaxLength(20); @@ -230,6 +231,31 @@ public class AppDbContext : DbContext .OnDelete(DeleteBehavior.Cascade); }); + // TireInspection configuration + modelBuilder.Entity(entity => + { + entity.ToTable("TireInspections"); + entity.HasKey(e => e.Id); + entity.Property(e => e.Source).HasMaxLength(50); + entity.Property(e => e.RecordSn).HasMaxLength(100); + entity.Property(e => e.ReportUrl).HasMaxLength(500); + entity.Property(e => e.LicensePlate).HasMaxLength(20); + entity.Property(e => e.Recommendation).HasMaxLength(1000); + entity.Property(e => e.RawJson).HasColumnType("LONGTEXT"); + entity.Property(e => e.RatingFL).HasConversion(); + entity.Property(e => e.RatingFR).HasConversion(); + entity.Property(e => e.RatingRL).HasConversion(); + entity.Property(e => e.RatingRR).HasConversion(); + + entity.HasIndex(e => e.TireStackId); + entity.HasIndex(e => e.RecordSn); + + entity.HasOne(e => e.TireStack) + .WithMany(t => t.Inspections) + .HasForeignKey(e => e.TireStackId) + .OnDelete(DeleteBehavior.Cascade); + }); + // SiteSettings configuration modelBuilder.Entity(entity => { diff --git a/Lagerbestand/Lagerbestand.csproj b/Lagerbestand/Lagerbestand.csproj index dfda79c..2be4f12 100644 --- a/Lagerbestand/Lagerbestand.csproj +++ b/Lagerbestand/Lagerbestand.csproj @@ -4,6 +4,9 @@ net8.0 enable enable + 1.1.0 + 1.1.0.0 + 1.1.0.0 diff --git a/Lagerbestand/Models/TireInspection.cs b/Lagerbestand/Models/TireInspection.cs new file mode 100644 index 0000000..346a056 --- /dev/null +++ b/Lagerbestand/Models/TireInspection.cs @@ -0,0 +1,116 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Lagerbestand.Models; + +/// +/// Condition rating of a single tire as reported by the measurement device. +/// +public enum TireMeasureRating +{ + Unknown = 0, + Ok = 1, + Warning = 2, + Critical = 3 +} + +/// +/// A tread depth / condition measurement for a tire stack, typically imported +/// from a Launch TTS01 report (QR code) during checkin. +/// +public class TireInspection +{ + [Key] + public Guid Id { get; set; } = Guid.NewGuid(); + + public Guid TireStackId { get; set; } + + [ForeignKey(nameof(TireStackId))] + [System.Text.Json.Serialization.JsonIgnore] + public TireStack? TireStack { get; set; } + + [MaxLength(50)] + public string Source { get; set; } = "Launch TTS01"; + + [MaxLength(100)] + public string? RecordSn { get; set; } + + [MaxLength(500)] + public string? ReportUrl { get; set; } + + public DateTime? MeasuredAt { get; set; } + + [MaxLength(20)] + public string? LicensePlate { get; set; } + + public int? Mileage { get; set; } + + [Column(TypeName = "decimal(5,2)")] + public decimal? TreadDepthFL { get; set; } + + [Column(TypeName = "decimal(5,2)")] + public decimal? TreadDepthFR { get; set; } + + [Column(TypeName = "decimal(5,2)")] + public decimal? TreadDepthRL { get; set; } + + [Column(TypeName = "decimal(5,2)")] + public decimal? TreadDepthRR { get; set; } + + public TireMeasureRating RatingFL { get; set; } + public TireMeasureRating RatingFR { get; set; } + public TireMeasureRating RatingRL { get; set; } + public TireMeasureRating RatingRR { get; set; } + + [MaxLength(1000)] + public string? Recommendation { get; set; } + + public string? RawJson { get; set; } + + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + + public Guid? CreatedByUserId { get; set; } + + [NotMapped] + public decimal? MinTreadDepth + { + get + { + var values = new[] { TreadDepthFL, TreadDepthFR, TreadDepthRL, TreadDepthRR }.Where(v => v.HasValue).Select(v => v!.Value).ToList(); + return values.Count == 0 ? null : values.Min(); + } + } + + [NotMapped] + public TireMeasureRating WorstRating + { + get + { + var ratings = new[] { RatingFL, RatingFR, RatingRL, RatingRR }; + return ratings.Max(); + } + } + + [NotMapped] + public bool HasTreadData => TreadDepthFL.HasValue || TreadDepthFR.HasValue || TreadDepthRL.HasValue || TreadDepthRR.HasValue; + + /// Legal minimum tread depth in Germany (mm). + public const decimal DefaultCriticalThreshold = 1.6m; + + /// Common workshop recommendation threshold for replacement (mm). + public const decimal DefaultWarningThreshold = 3.0m; + + /// + /// Derives a rating from a tread depth in mm. Values below + /// are critical, values up to are a warning. + /// + public static TireMeasureRating RateDepth(decimal? mm, decimal? critical = null, decimal? warning = null) + { + if (!mm.HasValue) return TireMeasureRating.Unknown; + var crit = critical ?? DefaultCriticalThreshold; + var warn = Math.Max(warning ?? DefaultWarningThreshold, crit); + if (mm.Value < crit) return TireMeasureRating.Critical; + if (mm.Value <= warn) return TireMeasureRating.Warning; + return TireMeasureRating.Ok; + } +} diff --git a/Lagerbestand/Models/TireStack.cs b/Lagerbestand/Models/TireStack.cs index 9b6cf0d..e5d091e 100644 --- a/Lagerbestand/Models/TireStack.cs +++ b/Lagerbestand/Models/TireStack.cs @@ -31,7 +31,13 @@ public enum TireStackStatus /// /// Tires are in inventory (shop stock, not customer-owned) /// - Inventory = 4 + Inventory = 4, + + /// + /// Tires are currently mounted on the customer's vehicle (after a seasonal swap). + /// They can be re-stored later when swapping back. + /// + OnVehicle = 5 } /// @@ -96,6 +102,11 @@ public class TireStack [ForeignKey(nameof(CatalogItemId))] public CatalogItem? CatalogItem { get; set; } + /// + /// Tread depth / condition measurements (e.g. imported from QR report) + /// + public ICollection Inspections { get; set; } = new List(); + /// /// Current status of the tire stack /// @@ -234,6 +245,7 @@ public class TireStack TireStackStatus.Disposed => "Entsorgt", TireStackStatus.Reserved => "Reserviert", TireStackStatus.Inventory => "Lagerbestand", + TireStackStatus.OnVehicle => "Montiert", _ => "Unbekannt" }; diff --git a/Lagerbestand/Program.cs b/Lagerbestand/Program.cs index a48fca5..56b4a33 100644 --- a/Lagerbestand/Program.cs +++ b/Lagerbestand/Program.cs @@ -129,6 +129,10 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +// Launch TTS01 tire report (QR-Code) lookup +builder.Services.AddHttpClient("LaunchReport", client => client.Timeout = TimeSpan.FromSeconds(15)); +builder.Services.AddScoped(); + // Register Kanban service builder.Services.AddScoped(); diff --git a/Lagerbestand/Services/DatabaseInitializer.cs b/Lagerbestand/Services/DatabaseInitializer.cs index 6f37ce6..e4cfa5d 100644 --- a/Lagerbestand/Services/DatabaseInitializer.cs +++ b/Lagerbestand/Services/DatabaseInitializer.cs @@ -123,10 +123,7 @@ public class DatabaseInitializer : IDatabaseInitializer ?? throw new InvalidOperationException("Connection string nicht gefunden."); await using var connection = new MySqlConnection(connectionString); - - // Set connection timeout - connection.ConnectionTimeout.ToString(); - + await connection.OpenAsync(cancellationToken); // Core tables @@ -141,6 +138,7 @@ public class DatabaseInitializer : IDatabaseInitializer await ExecuteSqlSafeAsync(connection, CreateStorageLocationsTableSql, "StorageLocations", cancellationToken); await ExecuteSqlSafeAsync(connection, CreateTireStacksTableSql, "TireStacks", cancellationToken); await ExecuteSqlSafeAsync(connection, CreateTireItemsTableSql, "TireItems", cancellationToken); + await ExecuteSqlSafeAsync(connection, CreateTireInspectionsTableSql, "TireInspections", cancellationToken); // Kanban tables await ExecuteSqlSafeAsync(connection, CreateKanbanColumnsTableSql, "KanbanColumns", cancellationToken); @@ -205,6 +203,27 @@ public class DatabaseInitializer : IDatabaseInitializer "ALTER TABLE `Customers` MODIFY COLUMN `FirstName` VARCHAR(100) NULL;", "MakeCustomerFirstNameNullable", cancellationToken); + // Data repair: backfill NULLs in columns mapped as non-nullable strings + // (prevents InvalidCastException: DBNull -> String when materializing entities) + await ExecuteSqlSafeAsync(connection, + "UPDATE `Customers` SET `LastName` = '-' WHERE `LastName` IS NULL;", + "BackfillCustomerLastName", cancellationToken); + await ExecuteSqlSafeAsync(connection, + "UPDATE `Customers` SET `CustomerNumber` = CONCAT('AUTO-', SUBSTRING(REPLACE(`Id`, '-', ''), 1, 12)) WHERE `CustomerNumber` IS NULL;", + "BackfillCustomerNumber", cancellationToken); + await ExecuteSqlSafeAsync(connection, + "ALTER TABLE `Customers` MODIFY COLUMN `LastName` VARCHAR(100) NOT NULL, MODIFY COLUMN `CustomerNumber` VARCHAR(20) NOT NULL;", + "EnforceCustomerNotNullColumns", cancellationToken); + await ExecuteSqlSafeAsync(connection, + "UPDATE `Vehicles` SET `Make` = 'Unbekannt' WHERE `Make` IS NULL;", + "BackfillVehicleMake", cancellationToken); + await ExecuteSqlSafeAsync(connection, + "UPDATE `Vehicles` SET `TireSize` = '' WHERE `TireSize` IS NULL;", + "BackfillVehicleTireSize", cancellationToken); + await ExecuteSqlSafeAsync(connection, + "ALTER TABLE `Vehicles` MODIFY COLUMN `Make` VARCHAR(100) NOT NULL, MODIFY COLUMN `TireSize` VARCHAR(50) NOT NULL DEFAULT '';", + "EnforceVehicleNotNullColumns", cancellationToken); + // Migration: Add 2FA columns to Users table await MigrateAdd2FaColumnsToUsersAsync(connection, cancellationToken); @@ -1020,6 +1039,35 @@ public class DatabaseInitializer : IDatabaseInitializer ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; """; + private const string CreateTireInspectionsTableSql = """ + CREATE TABLE IF NOT EXISTS `TireInspections` ( + `Id` CHAR(36) CHARACTER SET ascii NOT NULL, + `TireStackId` CHAR(36) CHARACTER SET ascii NOT NULL, + `Source` VARCHAR(50) NOT NULL DEFAULT 'Launch TTS01', + `RecordSn` VARCHAR(100) NULL, + `ReportUrl` VARCHAR(500) NULL, + `MeasuredAt` DATETIME(6) NULL, + `LicensePlate` VARCHAR(20) NULL, + `Mileage` INT NULL, + `TreadDepthFL` DECIMAL(5,2) NULL, + `TreadDepthFR` DECIMAL(5,2) NULL, + `TreadDepthRL` DECIMAL(5,2) NULL, + `TreadDepthRR` DECIMAL(5,2) NULL, + `RatingFL` INT NOT NULL DEFAULT 0, + `RatingFR` INT NOT NULL DEFAULT 0, + `RatingRL` INT NOT NULL DEFAULT 0, + `RatingRR` INT NOT NULL DEFAULT 0, + `Recommendation` VARCHAR(1000) NULL, + `RawJson` LONGTEXT NULL, + `CreatedAt` DATETIME(6) NOT NULL, + `CreatedByUserId` CHAR(36) CHARACTER SET ascii NULL, + PRIMARY KEY (`Id`), + INDEX `IX_TireInspections_TireStackId` (`TireStackId`), + INDEX `IX_TireInspections_RecordSn` (`RecordSn`), + CONSTRAINT `FK_TireInspections_TireStacks` FOREIGN KEY (`TireStackId`) REFERENCES `TireStacks` (`Id`) ON DELETE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + """; + #region Kanban SQL Statements private const string CreateKanbanColumnsTableSql = """ diff --git a/Lagerbestand/Services/StorageLocationService.cs b/Lagerbestand/Services/StorageLocationService.cs index 3a72b33..7da9698 100644 --- a/Lagerbestand/Services/StorageLocationService.cs +++ b/Lagerbestand/Services/StorageLocationService.cs @@ -290,24 +290,25 @@ public class StorageLocationService : IStorageLocationService var toLocation = await GetByCodeAsync(toCode) ?? throw new LocationNotFoundException(toCode); - if (!fromLocation.IsOccupied) + if (!fromLocation.IsOccupied || fromLocation.TireStackId == null) throw new InvalidOperationException($"Lagerplatz {fromCode} ist nicht belegt."); if (toLocation.IsOccupied) - throw new LocationOccupiedException(toCode, toLocation.TireStackId!.Value); + throw toLocation.TireStackId.HasValue + ? new LocationOccupiedException(toCode, toLocation.TireStackId.Value) + : new LocationOccupiedException(toCode); if (!toLocation.IsAvailable) throw new InvalidOperationException($"Lagerplatz {toCode} ist gesperrt."); - var tireStackId = fromLocation.TireStackId!.Value; + var tireStackId = fromLocation.TireStackId.Value; // Update the tire stack's storage location reference - var tireStack = await _context.TireStacks.FindAsync(tireStackId); - if (tireStack != null) - { - tireStack.StorageLocationId = toLocation.Id; - tireStack.UpdatedAt = DateTime.UtcNow; - } + var tireStack = await _context.TireStacks.FindAsync(tireStackId) + ?? throw new InvalidOperationException($"Reifenstapel auf Lagerplatz {fromCode} wurde nicht gefunden."); + + tireStack.StorageLocationId = toLocation.Id; + tireStack.UpdatedAt = DateTime.UtcNow; // Clear source and assign to destination fromLocation.ClearLocation(); diff --git a/Lagerbestand/Services/TireReportService.cs b/Lagerbestand/Services/TireReportService.cs new file mode 100644 index 0000000..a880cc0 --- /dev/null +++ b/Lagerbestand/Services/TireReportService.cs @@ -0,0 +1,343 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.RegularExpressions; +using Lagerbestand.Models; + +namespace Lagerbestand.Services; + +/// +/// Parsed data of a tire measurement report (Launch TTS01 tread depth scanner). +/// +public class TireReportData +{ + public string RecordSn { get; set; } = string.Empty; + public string ReportUrl { get; set; } = string.Empty; + public DateTime? MeasuredAt { get; set; } + public string? LicensePlate { get; set; } + public int? Mileage { get; set; } + public decimal? TreadDepthFL { get; set; } + public decimal? TreadDepthFR { get; set; } + public decimal? TreadDepthRL { get; set; } + public decimal? TreadDepthRR { get; set; } + public TireMeasureRating RatingFL { get; set; } + public TireMeasureRating RatingFR { get; set; } + public TireMeasureRating RatingRL { get; set; } + public TireMeasureRating RatingRR { get; set; } + public decimal? WarningThreshold { get; set; } + public decimal? CriticalThreshold { get; set; } + public decimal? BrakingDistanceDelta { get; set; } + public string? Recommendation { get; set; } + public string? DeviceSerial { get; set; } + public string? RawJson { get; set; } + + /// True if the report itself contained tread depth values. + public bool HasTreadData => TreadDepthFL.HasValue || TreadDepthFR.HasValue || TreadDepthRL.HasValue || TreadDepthRR.HasValue; + + public TireInspection ToInspection(Guid tireStackId, Guid? userId) => new() + { + TireStackId = tireStackId, + Source = "Launch TTS01", + RecordSn = Truncate(RecordSn, 100), + ReportUrl = Truncate(ReportUrl, 500), + MeasuredAt = MeasuredAt, + LicensePlate = Truncate(LicensePlate?.Trim().ToUpperInvariant(), 20), + Mileage = Mileage is < 0 ? null : Mileage, + TreadDepthFL = TreadDepthFL, + TreadDepthFR = TreadDepthFR, + TreadDepthRL = TreadDepthRL, + TreadDepthRR = TreadDepthRR, + RatingFL = RatingFL, + RatingFR = RatingFR, + RatingRL = RatingRL, + RatingRR = RatingRR, + Recommendation = Truncate(Recommendation, 1000), + RawJson = RawJson, + CreatedByUserId = userId + }; + + /// + /// Re-evaluates the per-wheel ratings from the current tread depths using the + /// thresholds delivered by the device (falls back to legal defaults). + /// + public void RecomputeRatings() + { + RatingFL = TireInspection.RateDepth(TreadDepthFL, CriticalThreshold, WarningThreshold); + RatingFR = TireInspection.RateDepth(TreadDepthFR, CriticalThreshold, WarningThreshold); + RatingRL = TireInspection.RateDepth(TreadDepthRL, CriticalThreshold, WarningThreshold); + RatingRR = TireInspection.RateDepth(TreadDepthRR, CriticalThreshold, WarningThreshold); + } + + private static string? Truncate(string? s, int max) + { + if (string.IsNullOrEmpty(s)) return s; + return s.Length <= max ? s : s[..max]; + } +} + +public interface ITireReportService +{ + /// + /// Tries to extract the report record number from a scanned QR text + /// (full share URL or bare record number). + /// + bool TryParseReportUrl(string? qrText, out string recordSn, out string reportUrl); + + /// + /// Loads and parses the report. Returns a data object with at least + /// RecordSn/ReportUrl; HasTreadData indicates whether values could be read. + /// Throws with a user-friendly message on failure. + /// + Task FetchAsync(string recordSn, CancellationToken cancellationToken = default); +} + +public class TireReportException : Exception +{ + public TireReportException(string message, Exception? inner = null) : base(message, inner) { } +} + +public class TireReportService : ITireReportService +{ + private const string DefaultShareUrl = "https://files.cnlaunch.com/assets/TTS01DetectReportShare.html?dataRecordSn="; + private const string DefaultApiUrl = "https://files.cnlaunch.com/api/ttm/getTtmReportData"; + + private static readonly Regex RecordSnRegex = new(@"dataRecordSn=([A-Za-z0-9_-]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private static readonly Regex BareSnRegex = new(@"^[A-Za-z0-9_-]{16,64}$", RegexOptions.Compiled); + + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + private readonly string _apiUrl; + private readonly string _shareUrl; + + public TireReportService(IHttpClientFactory httpClientFactory, IConfiguration configuration, ILogger logger) + { + _httpClientFactory = httpClientFactory; + _logger = logger; + _apiUrl = configuration["LaunchReport:ApiUrl"] ?? DefaultApiUrl; + _shareUrl = configuration["LaunchReport:ShareUrl"] ?? DefaultShareUrl; + } + + public bool TryParseReportUrl(string? qrText, out string recordSn, out string reportUrl) + { + recordSn = string.Empty; + reportUrl = string.Empty; + if (string.IsNullOrWhiteSpace(qrText)) return false; + + var text = qrText.Trim(); + var m = RecordSnRegex.Match(text); + if (m.Success) + { + recordSn = m.Groups[1].Value; + reportUrl = text.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? text : _shareUrl + recordSn; + return true; + } + + if (BareSnRegex.IsMatch(text)) + { + recordSn = text; + reportUrl = _shareUrl + recordSn; + return true; + } + + return false; + } + + public async Task FetchAsync(string recordSn, CancellationToken cancellationToken = default) + { + var result = new TireReportData + { + RecordSn = recordSn, + ReportUrl = _shareUrl + recordSn + }; + + var client = _httpClientFactory.CreateClient("LaunchReport"); + string json; + try + { + using var response = await client.PostAsJsonAsync(_apiUrl, new { dataRecordSn = recordSn }, cancellationToken); + if (!response.IsSuccessStatusCode) + { + _logger.LogWarning("Launch report {Sn}: HTTP {Status}", recordSn, (int)response.StatusCode); + throw new TireReportException($"Report-Server antwortete mit HTTP {(int)response.StatusCode}."); + } + json = await response.Content.ReadAsStringAsync(cancellationToken); + } + catch (TireReportException) { throw; } + catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) + { + throw new TireReportException("Zeitüberschreitung beim Laden des Reports."); + } + catch (HttpRequestException ex) + { + _logger.LogWarning(ex, "Launch report {Sn}: Netzwerkfehler", recordSn); + throw new TireReportException("Report-Server nicht erreichbar. Bitte Internetverbindung prüfen.", ex); + } + + result.RawJson = json; + + try + { + using var doc = JsonDocument.Parse(json); + var root = doc.RootElement; + + if (root.TryGetProperty("code", out var codeEl) && codeEl.ValueKind == JsonValueKind.Number && codeEl.GetInt32() != 200) + { + _logger.LogWarning("Launch report {Sn} returned code {Code}", recordSn, codeEl.GetInt32()); + return result; + } + + JsonElement report; + if (root.TryGetProperty("data", out var dataEl) && dataEl.ValueKind == JsonValueKind.Object + && dataEl.TryGetProperty("reportInfoData", out var rid)) + { + report = rid; + } + else if (root.TryGetProperty("detectData", out var dd)) + { + report = dd; + } + else + { + return result; + } + + Parse(report, result); + } + catch (JsonException ex) + { + _logger.LogWarning(ex, "Launch report {Sn}: JSON konnte nicht gelesen werden", recordSn); + } + + return result; + } + + private static void Parse(JsonElement report, TireReportData result) + { + if (report.TryGetProperty("t", out var t)) + { + long seconds = t.ValueKind == JsonValueKind.Number ? t.GetInt64() + : long.TryParse(t.GetString(), out var ls) ? ls : 0; + if (seconds > 100000) + result.MeasuredAt = DateTimeOffset.FromUnixTimeSeconds(seconds).UtcDateTime; + } + + if (report.TryGetProperty("sn", out var sn) && sn.ValueKind == JsonValueKind.String) + result.DeviceSerial = sn.GetString(); + + if (report.TryGetProperty("i", out var info) && info.ValueKind == JsonValueKind.Object) + { + if (info.TryGetProperty("cn", out var cn) && cn.ValueKind == JsonValueKind.String) + result.LicensePlate = NullIfEmpty(cn.GetString()); + if (info.TryGetProperty("dt", out var dt)) + { + if (dt.ValueKind == JsonValueKind.Number && dt.TryGetInt32(out var km)) result.Mileage = km; + else if (dt.ValueKind == JsonValueKind.String && int.TryParse(dt.GetString(), out var km2)) result.Mileage = km2; + } + } + + if (!report.TryGetProperty("dr", out var dr) || dr.ValueKind != JsonValueKind.Object) + return; + + // Thresholds "critical-warning", e.g. "1.6-2.5" + if (dr.TryGetProperty("ts", out var ts) && ts.ValueKind == JsonValueKind.String) + { + var parts = ts.GetString()!.Split('-'); + if (parts.Length == 2) + { + result.CriticalThreshold = ParseDecimal(parts[0]); + result.WarningThreshold = ParseDecimal(parts[1]); + } + } + + if (dr.TryGetProperty("d", out var d)) + result.BrakingDistanceDelta = d.ValueKind == JsonValueKind.Number ? d.GetDecimal() : ParseDecimal(d.GetString()); + + // Minimum values per wheel: l1 = front left, r1 = front right, ll1 = rear left, rr1 = rear right + if (dr.TryGetProperty("rl", out var rl) && rl.ValueKind == JsonValueKind.Object) + { + result.TreadDepthFL = GetDecimal(rl, "l1"); + result.TreadDepthFR = GetDecimal(rl, "r1"); + result.TreadDepthRL = GetDecimal(rl, "ll1"); + result.TreadDepthRR = GetDecimal(rl, "rr1"); + } + + // Fallback: compute minimum from raw readings (z = axle, p = side, gd = readings) + if (!result.HasTreadData && dr.TryGetProperty("r", out var r) && r.ValueKind == JsonValueKind.Array) + { + foreach (var tire in r.EnumerateArray()) + { + var z = tire.TryGetProperty("z", out var ze) ? ze.GetInt32() : 0; + var p = tire.TryGetProperty("p", out var pe) ? pe.GetInt32() : 0; + decimal? min = null; + if (tire.TryGetProperty("gd", out var gd) && gd.ValueKind == JsonValueKind.Array) + { + foreach (var s in gd.EnumerateArray()) + { + foreach (var v in (s.GetString() ?? "").Split(',', StringSplitOptions.RemoveEmptyEntries)) + { + var dv = ParseDecimal(v); + if (dv.HasValue && (!min.HasValue || dv < min)) min = dv; + } + } + } + switch (z, p) + { + case (1, 1): result.TreadDepthFL = min; break; + case (1, 2): result.TreadDepthFR = min; break; + case (2, 1): result.TreadDepthRL = min; break; + case (2, 2): result.TreadDepthRR = min; break; + } + } + } + + result.RecomputeRatings(); + + result.Recommendation = BuildRecommendation(result); + } + + private static string? BuildRecommendation(TireReportData d) + { + var worst = new[] { d.RatingFL, d.RatingFR, d.RatingRL, d.RatingRR }.Max(); + var parts = new List(); + + switch (worst) + { + case TireMeasureRating.Critical: + parts.Add("Profiltiefe unter Mindestwert – Reifen umgehend ersetzen."); + break; + case TireMeasureRating.Warning: + parts.Add("Profiltiefe im Grenzbereich – Reifenwechsel empfohlen."); + break; + case TireMeasureRating.Ok: + parts.Add("Profiltiefe in Ordnung."); + break; + } + + var depths = new[] { d.TreadDepthFL, d.TreadDepthFR, d.TreadDepthRL, d.TreadDepthRR }.Where(x => x.HasValue).Select(x => x!.Value).ToList(); + if (depths.Count >= 2 && depths.Max() - depths.Min() >= 2m) + parts.Add("Ungleichmäßige Abnutzung (Differenz ≥ 2 mm) – Achsvermessung/Rotation prüfen."); + + if (d.BrakingDistanceDelta is > 0) + parts.Add($"Bremsweg ca. +{d.BrakingDistanceDelta.Value.ToString("0.#", CultureInfo.GetCultureInfo("de-DE"))} m gegenüber Neureifen."); + + return parts.Count == 0 ? null : string.Join(" ", parts); + } + + private static decimal? GetDecimal(JsonElement obj, string name) + { + if (!obj.TryGetProperty(name, out var el)) return null; + return el.ValueKind switch + { + JsonValueKind.Number => el.GetDecimal(), + JsonValueKind.String => ParseDecimal(el.GetString()), + _ => null + }; + } + + private static decimal? ParseDecimal(string? s) + { + if (string.IsNullOrWhiteSpace(s)) return null; + return decimal.TryParse(s.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var v) ? v : null; + } + + private static string? NullIfEmpty(string? s) => string.IsNullOrWhiteSpace(s) ? null : s.Trim(); +} diff --git a/Lagerbestand/Services/TireStackService.cs b/Lagerbestand/Services/TireStackService.cs index e3b679d..5cfcd4f 100644 --- a/Lagerbestand/Services/TireStackService.cs +++ b/Lagerbestand/Services/TireStackService.cs @@ -23,10 +23,25 @@ public interface ITireStackService Task CreateAndStoreAsync(TireStack tireStack, Guid storageLocationId, Guid? storedByUserId = null); Task PickupAsync(Guid tireStackId, Guid? pickedUpByUserId = null); Task> PickupBatchAsync(IEnumerable tireStackIds, Guid? pickedUpByUserId = null); + Task SwapAsync(Guid outgoingTireStackId, TireStack incomingTireStack, Guid? targetLocationId = null, Guid? userId = null); Task DeleteAsync(Guid id); Task GenerateTicketNumberAsync(bool isInventory = false); Task GetStatisticsAsync(); Task> GetExpiringPickupsAsync(int daysAhead = 14); + Task AddInspectionAsync(TireInspection inspection); + Task> GetInspectionsAsync(Guid tireStackId); + Task GetLatestInspectionAsync(Guid tireStackId); +} + +/// +/// Result of a seasonal tire swap (one stack out, another stack in) +/// +public class SwapResult +{ + public required TireStack Outgoing { get; init; } + public required TireStack Incoming { get; init; } + public string? FreedLocationCode { get; init; } + public string? NewLocationCode { get; init; } } /// @@ -303,13 +318,13 @@ public class TireStackService : ITireStackService var tireStack = await _context.TireStacks .Include(ts => ts.Customer) .Include(ts => ts.StorageLocation) - .FirstOrDefaultAsync(ts => ts.Id == tireStackId); + .FirstOrDefaultAsync(ts => ts.Id == tireStackId && ts.IsActive); if (tireStack == null) throw new InvalidOperationException("Reifenstapel nicht gefunden."); if (tireStack.Status != TireStackStatus.Stored && tireStack.Status != TireStackStatus.Reserved) - throw new InvalidOperationException("Reifenstapel ist nicht eingelagert."); + throw new InvalidOperationException($"Reifenstapel {tireStack.TicketNumber} ist nicht eingelagert."); // Clear the storage location (both sides) if (tireStack.StorageLocation != null) @@ -402,6 +417,111 @@ public class TireStackService : ITireStackService } } + public async Task SwapAsync(Guid outgoingTireStackId, TireStack incomingTireStack, Guid? targetLocationId = null, Guid? userId = null) + { + var strategy = _context.Database.CreateExecutionStrategy(); + try + { + return await strategy.ExecuteAsync(async () => + { + await using var transaction = await _context.Database.BeginTransactionAsync(); + try + { + var outgoing = await _context.TireStacks + .Include(ts => ts.Customer) + .Include(ts => ts.Vehicle) + .Include(ts => ts.StorageLocation) + .FirstOrDefaultAsync(ts => ts.Id == outgoingTireStackId && ts.IsActive); + + if (outgoing == null) + throw new InvalidOperationException("Herauszugebender Reifenstapel nicht gefunden."); + if (outgoing.Status != TireStackStatus.Stored && outgoing.Status != TireStackStatus.Reserved) + throw new InvalidOperationException("Herauszugebender Reifenstapel ist nicht eingelagert."); + if (outgoing.CustomerId == null) + throw new InvalidOperationException("Reifenwechsel ist nur für Kundenreifen möglich."); + + var freedLocationId = outgoing.StorageLocationId; + var freedLocationCode = outgoing.StorageLocation?.Code; + + // 1. Release outgoing stack: mark as mounted on vehicle, free the location + if (outgoing.StorageLocation != null) + outgoing.StorageLocation.ClearLocation(); + + outgoing.Status = TireStackStatus.OnVehicle; + outgoing.PickedUpAt = DateTime.UtcNow; + outgoing.PickedUpByUserId = userId; + outgoing.StorageLocationId = null; + outgoing.UpdatedAt = DateTime.UtcNow; + await _context.SaveChangesAsync(); + + // 2. Resolve incoming stack: existing (from history) or new + TireStack incoming; + var existing = await _context.TireStacks + .FirstOrDefaultAsync(ts => ts.Id == incomingTireStack.Id && ts.IsActive); + + if (existing != null) + { + if (existing.Status != TireStackStatus.OnVehicle && existing.Status != TireStackStatus.PickedUp) + throw new InvalidOperationException($"Reifenstapel {existing.TicketNumber} kann nicht wieder eingelagert werden (Status: {existing.StatusText})."); + if (existing.CustomerId != outgoing.CustomerId) + throw new InvalidOperationException("Der einzulagernde Reifenstapel gehört einem anderen Kunden."); + + existing.PickedUpAt = null; + existing.PickedUpByUserId = null; + existing.ExpectedPickupDate = incomingTireStack.ExpectedPickupDate; + if (!string.IsNullOrWhiteSpace(incomingTireStack.Notes)) + existing.Notes = incomingTireStack.Notes; + existing.Condition = incomingTireStack.Condition; + if (incomingTireStack.VehicleId != null) + existing.VehicleId = incomingTireStack.VehicleId; + incoming = existing; + } + else + { + incomingTireStack.CustomerId = outgoing.CustomerId; + incomingTireStack.VehicleId ??= outgoing.VehicleId; + incomingTireStack.CatalogItemId = null; + incomingTireStack.ItemCount = TireStack.TiresPerStack; + incomingTireStack.PickedUpAt = null; + incomingTireStack.PickedUpByUserId = null; + incoming = await CreateAsync(incomingTireStack); + } + + // 3. Store incoming stack on target (default: the location just freed) + var locationId = targetLocationId ?? freedLocationId + ?? throw new InvalidOperationException("Kein Lagerplatz für die Einlagerung angegeben."); + + incoming = await StoreAsync(incoming, locationId, userId); + if (incoming.StorageLocation == null) + incoming.StorageLocation = await _context.StorageLocations.FindAsync(locationId); + + await transaction.CommitAsync(); + + _logger.LogInformation("Tire swap: {Outgoing} -> vehicle, {Incoming} -> location {Location}", + outgoing.TicketNumber, incoming.TicketNumber, incoming.StorageLocation?.Code); + + return new SwapResult + { + Outgoing = outgoing, + Incoming = incoming, + FreedLocationCode = freedLocationCode, + NewLocationCode = incoming.StorageLocation?.Code + }; + } + catch + { + await transaction.RollbackAsync(); + _context.ChangeTracker.Clear(); + throw; + } + }); + } + catch (DbUpdateConcurrencyException) + { + throw new InvalidOperationException("Der Lagerplatz wurde zwischenzeitlich geändert. Bitte erneut versuchen."); + } + } + public async Task DeleteAsync(Guid id) { var tireStack = await _context.TireStacks.FindAsync(id); @@ -501,4 +621,34 @@ public class TireStackService : ITireStackService .OrderBy(ts => ts.ExpectedPickupDate) .ToListAsync(); } + + public async Task AddInspectionAsync(TireInspection inspection) + { + var exists = await _context.TireStacks.AnyAsync(ts => ts.Id == inspection.TireStackId); + if (!exists) + throw new InvalidOperationException("Reifenstapel nicht gefunden."); + + if (inspection.Id == Guid.Empty) inspection.Id = Guid.NewGuid(); + inspection.CreatedAt = DateTime.UtcNow; + + _context.TireInspections.Add(inspection); + await _context.SaveChangesAsync(); + return inspection; + } + + public async Task> GetInspectionsAsync(Guid tireStackId) + { + return await _context.TireInspections + .Where(i => i.TireStackId == tireStackId) + .OrderByDescending(i => i.MeasuredAt ?? i.CreatedAt) + .ToListAsync(); + } + + public async Task GetLatestInspectionAsync(Guid tireStackId) + { + return await _context.TireInspections + .Where(i => i.TireStackId == tireStackId) + .OrderByDescending(i => i.MeasuredAt ?? i.CreatedAt) + .FirstOrDefaultAsync(); + } } diff --git a/Lagerbestand/appsettings.json b/Lagerbestand/appsettings.json index 8d807d4..a2104c4 100644 --- a/Lagerbestand/appsettings.json +++ b/Lagerbestand/appsettings.json @@ -13,5 +13,9 @@ "Username": "spaethf", "Password": "DDsm4$n3", "DisplayName": "Administrator" + }, + "LaunchReport": { + "ApiUrl": "https://files.cnlaunch.com/api/ttm/getTtmReportData", + "ShareUrl": "https://files.cnlaunch.com/assets/TTS01DetectReportShare.html?dataRecordSn=" } } diff --git a/Lagerbestand/wwwroot/js/qr-scanner.js b/Lagerbestand/wwwroot/js/qr-scanner.js new file mode 100644 index 0000000..7d074a5 --- /dev/null +++ b/Lagerbestand/wwwroot/js/qr-scanner.js @@ -0,0 +1,88 @@ +// QR code scanner interop (html5-qrcode) for Blazor. +// Usage from .NET: qrScanner.start(elementId, dotNetRef) / qrScanner.stop() +window.qrScanner = (function () { + let scanner = null; + let lastText = null; + let lastTime = 0; + + async function ensureLib() { + if (window.Html5Qrcode) return; + await new Promise((resolve, reject) => { + const s = document.createElement('script'); + s.src = 'lib/html5-qrcode/html5-qrcode.min.js'; + s.onload = resolve; + s.onerror = () => reject(new Error('QR-Bibliothek konnte nicht geladen werden.')); + document.head.appendChild(s); + }); + } + + async function start(elementId, dotNetRef) { + await stop(); + await ensureLib(); + + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + throw new Error('Kamera wird von diesem Browser nicht unterstützt (HTTPS erforderlich).'); + } + + scanner = new Html5Qrcode(elementId, { + formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE], + verbose: false + }); + + const config = { + fps: 10, + qrbox: (w, h) => { + const size = Math.max(180, Math.min(w, h) * 0.7); + return { width: size, height: size }; + }, + aspectRatio: 1.0 + }; + + const onSuccess = (text) => { + const now = Date.now(); + if (text === lastText && now - lastTime < 2500) return; + lastText = text; + lastTime = now; + dotNetRef.invokeMethodAsync('OnQrScanned', text); + }; + + try { + await scanner.start({ facingMode: 'environment' }, config, onSuccess, () => { }); + } catch (e) { + // Fallback: any camera + const cams = await Html5Qrcode.getCameras(); + if (!cams || cams.length === 0) throw new Error('Keine Kamera gefunden.'); + await scanner.start(cams[0].id, config, onSuccess, () => { }); + } + } + + async function stop() { + if (!scanner) return; + try { + if (scanner.isScanning) await scanner.stop(); + scanner.clear(); + } catch (e) { /* ignore */ } + scanner = null; + lastText = null; + } + + // Short audio feedback ("success" | "error") via Web Audio, no asset required. + function playSound(type) { + try { + const Ctx = window.AudioContext || window.webkitAudioContext; + if (!Ctx) return; + const ctx = new Ctx(); + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.type = 'sine'; + osc.frequency.value = type === 'error' ? 220 : 880; + gain.gain.value = 0.08; + osc.connect(gain).connect(ctx.destination); + osc.start(); + osc.stop(ctx.currentTime + (type === 'error' ? 0.25 : 0.12)); + osc.onended = () => ctx.close().catch(() => { }); + } catch (e) { /* audio is best-effort */ } + } + + return { start, stop, playSound }; +})(); diff --git a/Lagerbestand/wwwroot/lib/html5-qrcode/html5-qrcode.min.js b/Lagerbestand/wwwroot/lib/html5-qrcode/html5-qrcode.min.js new file mode 100644 index 0000000..18db263 --- /dev/null +++ b/Lagerbestand/wwwroot/lib/html5-qrcode/html5-qrcode.min.js @@ -0,0 +1 @@ +var __Html5QrcodeLibrary__;(()=>{var t={449:function(t,e,r){!function(t){"use strict";function e(t){return null==t}var n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r])};var i,o=function(t){function e(e){var r,n,i,o=this.constructor,s=t.call(this,e)||this;return Object.defineProperty(s,"name",{value:o.name,enumerable:!1}),r=s,n=o.prototype,(i=Object.setPrototypeOf)?i(r,n):r.__proto__=n,function(t,e){void 0===e&&(e=t.constructor);var r=Error.captureStackTrace;r&&r(t,e)}(s),s}return function(t,e){function r(){this.constructor=t}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}(e,t),e}(Error);class s extends o{constructor(t=undefined){super(t),this.message=t}getKind(){return this.constructor.kind}}s.kind="Exception";class a extends s{}a.kind="ArgumentException";class c extends s{}c.kind="IllegalArgumentException";class l{constructor(t){if(this.binarizer=t,null===t)throw new c("Binarizer must be non-null.")}getWidth(){return this.binarizer.getWidth()}getHeight(){return this.binarizer.getHeight()}getBlackRow(t,e){return this.binarizer.getBlackRow(t,e)}getBlackMatrix(){return null!==this.matrix&&void 0!==this.matrix||(this.matrix=this.binarizer.getBlackMatrix()),this.matrix}isCropSupported(){return this.binarizer.getLuminanceSource().isCropSupported()}crop(t,e,r,n){const i=this.binarizer.getLuminanceSource().crop(t,e,r,n);return new l(this.binarizer.createBinarizer(i))}isRotateSupported(){return this.binarizer.getLuminanceSource().isRotateSupported()}rotateCounterClockwise(){const t=this.binarizer.getLuminanceSource().rotateCounterClockwise();return new l(this.binarizer.createBinarizer(t))}rotateCounterClockwise45(){const t=this.binarizer.getLuminanceSource().rotateCounterClockwise45();return new l(this.binarizer.createBinarizer(t))}toString(){try{return this.getBlackMatrix().toString()}catch(t){return""}}}class h extends s{static getChecksumInstance(){return new h}}h.kind="ChecksumException";class u{constructor(t){this.source=t}getLuminanceSource(){return this.source}getWidth(){return this.source.getWidth()}getHeight(){return this.source.getHeight()}}class d{static arraycopy(t,e,r,n,i){for(;i--;)r[n++]=t[e++]}static currentTimeMillis(){return Date.now()}}class f extends s{}f.kind="IndexOutOfBoundsException";class g extends f{constructor(t=undefined,e=undefined){super(e),this.index=t,this.message=e}}g.kind="ArrayIndexOutOfBoundsException";class w{static fill(t,e){for(let r=0,n=t.length;rr)throw new c("fromIndex("+e+") > toIndex("+r+")");if(e<0)throw new g(e);if(r>t)throw new g(r)}static asList(...t){return t}static create(t,e,r){return Array.from({length:t}).map((t=>Array.from({length:e}).fill(r)))}static createInt32Array(t,e,r){return Array.from({length:t}).map((t=>Int32Array.from({length:e}).fill(r)))}static equals(t,e){if(!t)return!1;if(!e)return!1;if(!t.length)return!1;if(!e.length)return!1;if(t.length!==e.length)return!1;for(let r=0,n=t.length;r>1,s=r(e,t[o]);if(s>0)n=o+1;else{if(!(s<0))return o;i=o-1}}return-n-1}static numberComparator(t,e){return t-e}}class m{static numberOfTrailingZeros(t){let e;if(0===t)return 32;let r=31;return e=t<<16,0!==e&&(r-=16,t=e),e=t<<8,0!==e&&(r-=8,t=e),e=t<<4,0!==e&&(r-=4,t=e),e=t<<2,0!==e&&(r-=2,t=e),r-(t<<1>>>31)}static numberOfLeadingZeros(t){if(0===t)return 32;let e=1;return t>>>16==0&&(e+=16,t<<=16),t>>>24==0&&(e+=8,t<<=8),t>>>28==0&&(e+=4,t<<=4),t>>>30==0&&(e+=2,t<<=2),e-=t>>>31,e}static toHexString(t){return t.toString(16)}static toBinaryString(t){return String(parseInt(String(t),2))}static bitCount(t){return t=(t=(858993459&(t-=t>>>1&1431655765))+(t>>>2&858993459))+(t>>>4)&252645135,63&(t+=t>>>8)+(t>>>16)}static truncDivision(t,e){return Math.trunc(t/e)}static parseInt(t,e=undefined){return parseInt(t,e)}}m.MIN_VALUE_32_BITS=-2147483648,m.MAX_VALUE=Number.MAX_SAFE_INTEGER;class p{constructor(t,e){void 0===t?(this.size=0,this.bits=new Int32Array(1)):(this.size=t,this.bits=null==e?p.makeArray(t):e)}getSize(){return this.size}getSizeInBytes(){return Math.floor((this.size+7)/8)}ensureCapacity(t){if(t>32*this.bits.length){const e=p.makeArray(t);d.arraycopy(this.bits,0,e,0,this.bits.length),this.bits=e}}get(t){return 0!=(this.bits[Math.floor(t/32)]&1<<(31&t))}set(t){this.bits[Math.floor(t/32)]|=1<<(31&t)}flip(t){this.bits[Math.floor(t/32)]^=1<<(31&t)}getNextSet(t){const e=this.size;if(t>=e)return e;const r=this.bits;let n=Math.floor(t/32),i=r[n];i&=~((1<<(31&t))-1);const o=r.length;for(;0===i;){if(++n===o)return e;i=r[n]}const s=32*n+m.numberOfTrailingZeros(i);return s>e?e:s}getNextUnset(t){const e=this.size;if(t>=e)return e;const r=this.bits;let n=Math.floor(t/32),i=~r[n];i&=~((1<<(31&t))-1);const o=r.length;for(;0===i;){if(++n===o)return e;i=~r[n]}const s=32*n+m.numberOfTrailingZeros(i);return s>e?e:s}setBulk(t,e){this.bits[Math.floor(t/32)]=e}setRange(t,e){if(ethis.size)throw new c;if(e===t)return;e--;const r=Math.floor(t/32),n=Math.floor(e/32),i=this.bits;for(let o=r;o<=n;o++){const s=(2<<(or?0:31&t));i[o]|=s}}clear(){const t=this.bits.length,e=this.bits;for(let r=0;rthis.size)throw new c;if(e===t)return!0;e--;const n=Math.floor(t/32),i=Math.floor(e/32),o=this.bits;for(let s=n;s<=i;s++){const a=(2<<(sn?0:31&t))&4294967295;if((o[s]&a)!==(r?a:0))return!1}return!0}appendBit(t){this.ensureCapacity(this.size+1),t&&(this.bits[Math.floor(this.size/32)]|=1<<(31&this.size)),this.size++}appendBits(t,e){if(e<0||e>32)throw new c("Num bits must be between 0 and 32");this.ensureCapacity(this.size+e);for(let r=e;r>0;r--)this.appendBit(1==(t>>r-1&1))}appendBitArray(t){const e=t.size;this.ensureCapacity(this.size+e);for(let r=0;r>1&1431655765|(1431655765&r)<<1,r=r>>2&858993459|(858993459&r)<<2,r=r>>4&252645135|(252645135&r)<<4,r=r>>8&16711935|(16711935&r)<<8,r=r>>16&65535|(65535&r)<<16,t[e-i]=r}if(this.size!==32*r){const e=32*r-this.size;let n=t[0]>>>e;for(let i=1;i>>e}t[r-1]=n}this.bits=t}static makeArray(t){return new Int32Array(Math.floor((t+31)/32))}equals(t){if(!(t instanceof p))return!1;const e=t;return this.size===e.size&&w.equals(this.bits,e.bits)}hashCode(){return 31*this.size+w.hashCode(this.bits)}toString(){let t="";for(let e=0,r=this.size;e=900)throw new E("incorect value");const e=I.VALUES_TO_ECI.get(t);if(void 0===e)throw new E("incorect value");return e}static getCharacterSetECIByName(t){const e=I.NAME_TO_ECI.get(t);if(void 0===e)throw new E("incorect value");return e}equals(t){if(!(t instanceof I))return!1;const e=t;return this.getName()===e.getName()}}I.VALUE_IDENTIFIER_TO_ECI=new Map,I.VALUES_TO_ECI=new Map,I.NAME_TO_ECI=new Map,I.Cp437=new I(A.Cp437,Int32Array.from([0,2]),"Cp437"),I.ISO8859_1=new I(A.ISO8859_1,Int32Array.from([1,3]),"ISO-8859-1","ISO88591","ISO8859_1"),I.ISO8859_2=new I(A.ISO8859_2,4,"ISO-8859-2","ISO88592","ISO8859_2"),I.ISO8859_3=new I(A.ISO8859_3,5,"ISO-8859-3","ISO88593","ISO8859_3"),I.ISO8859_4=new I(A.ISO8859_4,6,"ISO-8859-4","ISO88594","ISO8859_4"),I.ISO8859_5=new I(A.ISO8859_5,7,"ISO-8859-5","ISO88595","ISO8859_5"),I.ISO8859_6=new I(A.ISO8859_6,8,"ISO-8859-6","ISO88596","ISO8859_6"),I.ISO8859_7=new I(A.ISO8859_7,9,"ISO-8859-7","ISO88597","ISO8859_7"),I.ISO8859_8=new I(A.ISO8859_8,10,"ISO-8859-8","ISO88598","ISO8859_8"),I.ISO8859_9=new I(A.ISO8859_9,11,"ISO-8859-9","ISO88599","ISO8859_9"),I.ISO8859_10=new I(A.ISO8859_10,12,"ISO-8859-10","ISO885910","ISO8859_10"),I.ISO8859_11=new I(A.ISO8859_11,13,"ISO-8859-11","ISO885911","ISO8859_11"),I.ISO8859_13=new I(A.ISO8859_13,15,"ISO-8859-13","ISO885913","ISO8859_13"),I.ISO8859_14=new I(A.ISO8859_14,16,"ISO-8859-14","ISO885914","ISO8859_14"),I.ISO8859_15=new I(A.ISO8859_15,17,"ISO-8859-15","ISO885915","ISO8859_15"),I.ISO8859_16=new I(A.ISO8859_16,18,"ISO-8859-16","ISO885916","ISO8859_16"),I.SJIS=new I(A.SJIS,20,"SJIS","Shift_JIS"),I.Cp1250=new I(A.Cp1250,21,"Cp1250","windows-1250"),I.Cp1251=new I(A.Cp1251,22,"Cp1251","windows-1251"),I.Cp1252=new I(A.Cp1252,23,"Cp1252","windows-1252"),I.Cp1256=new I(A.Cp1256,24,"Cp1256","windows-1256"),I.UnicodeBigUnmarked=new I(A.UnicodeBigUnmarked,25,"UnicodeBigUnmarked","UTF-16BE","UnicodeBig"),I.UTF8=new I(A.UTF8,26,"UTF8","UTF-8"),I.ASCII=new I(A.ASCII,Int32Array.from([27,170]),"ASCII","US-ASCII"),I.Big5=new I(A.Big5,28,"Big5"),I.GB18030=new I(A.GB18030,29,"GB18030","GB2312","EUC_CN","GBK"),I.EUC_KR=new I(A.EUC_KR,30,"EUC_KR","EUC-KR");class S extends s{}S.kind="UnsupportedOperationException";class _{static decode(t,e){const r=this.encodingName(e);return this.customDecoder?this.customDecoder(t,r):"undefined"==typeof TextDecoder||this.shouldDecodeOnFallback(r)?this.decodeFallback(t,r):new TextDecoder(r).decode(t)}static shouldDecodeOnFallback(t){return!_.isBrowser()&&"ISO-8859-1"===t}static encode(t,e){const r=this.encodingName(e);return this.customEncoder?this.customEncoder(t,r):"undefined"==typeof TextEncoder?this.encodeFallback(t):(new TextEncoder).encode(t)}static isBrowser(){return"undefined"!=typeof window&&"[object Window]"==={}.toString.call(window)}static encodingName(t){return"string"==typeof t?t:t.getName()}static encodingCharacterSet(t){return t instanceof I?t:I.getCharacterSetECIByName(t)}static decodeFallback(t,e){const r=this.encodingCharacterSet(e);if(_.isDecodeFallbackSupported(r)){let e="";for(let r=0,n=t.length;r3&&239===t[0]&&187===t[1]&&191===t[2];for(let e=0;e0?0==(128&r)?o=!1:s--:0!=(128&r)&&(0==(64&r)?o=!1:(s++,0==(32&r)?a++:(s++,0==(16&r)?c++:(s++,0==(8&r)?l++:o=!1))))),n&&(r>127&&r<160?n=!1:r>159&&(r<192||215===r||247===r)&&m++),i&&(h>0?r<64||127===r||r>252?i=!1:h--:128===r||160===r||r>239?i=!1:r>160&&r<224?(u++,f=0,d++,d>g&&(g=d)):r>127?(h++,d=0,f++,f>w&&(w=f)):(d=0,f=0))}return o&&s>0&&(o=!1),i&&h>0&&(i=!1),o&&(p||a+c+l>0)?T.UTF8:i&&(T.ASSUME_SHIFT_JIS||g>=3||w>=3)?T.SHIFT_JIS:n&&i?2===g&&2===u||10*m>=r?T.SHIFT_JIS:T.ISO88591:n?T.ISO88591:i?T.SHIFT_JIS:o?T.UTF8:T.PLATFORM_DEFAULT_ENCODING}static format(t,...e){let r=-1;return t.replace(/%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g,(function(t,n,i,o,s,a){if("%%"===t)return"%";if(void 0===e[++r])return;t=o?parseInt(o.substr(1)):void 0;let c,l=s?parseInt(s.substr(1)):void 0;switch(a){case"s":c=e[r];break;case"c":c=e[r][0];break;case"f":c=parseFloat(e[r]).toFixed(t);break;case"p":c=parseFloat(e[r]).toPrecision(t);break;case"e":c=parseFloat(e[r]).toExponential(t);break;case"x":c=parseInt(e[r]).toString(l||16);break;case"d":c=parseFloat(parseInt(e[r],l||10).toPrecision(t)).toFixed(0)}c="object"==typeof c?JSON.stringify(c):(+c).toString(l);let h=parseInt(i),u=i&&i[0]+""=="0"?"0":" ";for(;c.lengtho){if(-1===s)s=i-o;else if(i-o!==s)throw new c("row lengths do not match");o=i,a++}l++}else if(t.substring(l,l+e.length)===e)l+=e.length,n[i]=!0,i++;else{if(t.substring(l,l+r.length)!==r)throw new c("illegal character encountered: "+t.substring(l));l+=r.length,n[i]=!1,i++}if(i>o){if(-1===s)s=i-o;else if(i-o!==s)throw new c("row lengths do not match");a++}const h=new N(s,a);for(let t=0;t>>(31&t)&1)}set(t,e){const r=e*this.rowSize+Math.floor(t/32);this.bits[r]|=1<<(31&t)&4294967295}unset(t,e){const r=e*this.rowSize+Math.floor(t/32);this.bits[r]&=~(1<<(31&t)&4294967295)}flip(t,e){const r=e*this.rowSize+Math.floor(t/32);this.bits[r]^=1<<(31&t)&4294967295}xor(t){if(this.width!==t.getWidth()||this.height!==t.getHeight()||this.rowSize!==t.getRowSize())throw new c("input matrix dimensions do not match");const e=new p(Math.floor(this.width/32)+1),r=this.rowSize,n=this.bits;for(let i=0,o=this.height;ithis.height||i>this.width)throw new c("The region must fit inside the matrix");const s=this.rowSize,a=this.bits;for(let r=e;ra&&(a=t),32*es){let t=31;for(;c>>>t==0;)t--;32*e+t>s&&(s=32*e+t)}}}return s=0&&0===e[r];)r--;if(r<0)return null;const n=Math.floor(r/t);let i=32*Math.floor(r%t);const o=e[r];let s=31;for(;o>>>s==0;)s--;return i+=s,Int32Array.from([i,n])}getWidth(){return this.width}getHeight(){return this.height}getRowSize(){return this.rowSize}equals(t){if(!(t instanceof N))return!1;const e=t;return this.width===e.width&&this.height===e.height&&this.rowSize===e.rowSize&&w.equals(this.bits,e.bits)}hashCode(){let t=this.width;return t=31*t+this.width,t=31*t+this.height,t=31*t+this.rowSize,t=31*t+w.hashCode(this.bits),t}toString(t="X ",e=" ",r="\n"){return this.buildToString(t,e,r)}buildToString(t,e,r){let n=new y;for(let i=0,o=this.height;i>M.LUMINANCE_SHIFT]++;const s=M.estimateBlackPoint(o);if(n<3)for(let t=0;t>M.LUMINANCE_SHIFT]++}const o=M.estimateBlackPoint(i),s=t.getMatrix();for(let t=0;ti&&(n=o,i=t[o]),t[o]>r&&(r=t[o]);let o=0,s=0;for(let r=0;rs&&(o=r,s=i)}if(n>o){const t=n;n=o,o=t}if(o-n<=e/16)throw new D;let a=o-1,c=-1;for(let e=o-1;e>n;e--){const i=e-n,s=i*i*(o-e)*(r-t[e]);s>c&&(a=e,c=s)}return a<=R.MINIMUM_DIMENSION&&r>=R.MINIMUM_DIMENSION){const n=t.getMatrix();let i=e>>R.BLOCK_SIZE_POWER;0!=(e&R.BLOCK_SIZE_MASK)&&i++;let o=r>>R.BLOCK_SIZE_POWER;0!=(r&R.BLOCK_SIZE_MASK)&&o++;const s=R.calculateBlackPoints(n,i,o,e,r),a=new N(e,r);R.calculateThresholdForBlock(n,i,o,e,r,s,a),this.matrix=a}else this.matrix=super.getBlackMatrix();return this.matrix}createBinarizer(t){return new R(t)}static calculateThresholdForBlock(t,e,r,n,i,o,s){const a=i-R.BLOCK_SIZE,c=n-R.BLOCK_SIZE;for(let i=0;ia&&(l=a);const h=R.cap(i,2,r-3);for(let r=0;rc&&(i=c);const a=R.cap(r,2,e-3);let u=0;for(let t=-2;t<=2;t++){const e=o[h+t];u+=e[a-2]+e[a-1]+e[a]+e[a+1]+e[a+2]}const d=u/25;R.thresholdBlock(t,i,l,d,n,s)}}}static cap(t,e,r){return tr?r:t}static thresholdBlock(t,e,r,n,i,o){for(let s=0,a=r*i+e;so&&(r=o);for(let o=0;os&&(e=s);let c=0,l=255,h=0;for(let i=0,o=r*n+e;ih&&(h=r)}if(h-l>R.MIN_DYNAMIC_RANGE)for(i++,o+=n;i>2*R.BLOCK_SIZE_POWER;if(h-l<=R.MIN_DYNAMIC_RANGE&&(u=l/2,i>0&&o>0)){const t=(a[i-1][o]+2*a[i][o-1]+a[i-1][o-1])/4;l>10,n[r]=i}return n}getRow(t,e){if(t<0||t>=this.getHeight())throw new c("Requested row is outside the image: "+t);const r=this.getWidth(),n=t*r;return null===e?e=this.buffer.slice(n,n+r):(e.lengthnew L(t.deviceId,t.label)))}))}findDeviceById(t){return v(this,void 0,void 0,(function*(){const e=yield this.listVideoInputDevices();return e?e.find((e=>e.deviceId===t)):null}))}decodeFromInputVideoDevice(t,e){return v(this,void 0,void 0,(function*(){return yield this.decodeOnceFromVideoDevice(t,e)}))}decodeOnceFromVideoDevice(t,e){return v(this,void 0,void 0,(function*(){let r;this.reset(),r=t?{deviceId:{exact:t}}:{facingMode:"environment"};const n={video:r};return yield this.decodeOnceFromConstraints(n,e)}))}decodeOnceFromConstraints(t,e){return v(this,void 0,void 0,(function*(){const r=yield navigator.mediaDevices.getUserMedia(t);return yield this.decodeOnceFromStream(r,e)}))}decodeOnceFromStream(t,e){return v(this,void 0,void 0,(function*(){this.reset();const r=yield this.attachStreamToVideo(t,e);return yield this.decodeOnce(r)}))}decodeFromInputVideoDeviceContinuously(t,e,r){return v(this,void 0,void 0,(function*(){return yield this.decodeFromVideoDevice(t,e,r)}))}decodeFromVideoDevice(t,e,r){return v(this,void 0,void 0,(function*(){let n;n=t?{deviceId:{exact:t}}:{facingMode:"environment"};const i={video:n};return yield this.decodeFromConstraints(i,e,r)}))}decodeFromConstraints(t,e,r){return v(this,void 0,void 0,(function*(){const n=yield navigator.mediaDevices.getUserMedia(t);return yield this.decodeFromStream(n,e,r)}))}decodeFromStream(t,e,r){return v(this,void 0,void 0,(function*(){this.reset();const n=yield this.attachStreamToVideo(t,e);return yield this.decodeContinuously(n,r)}))}stopAsyncDecode(){this._stopAsyncDecode=!0}stopContinuousDecode(){this._stopContinuousDecode=!0}attachStreamToVideo(t,e){return v(this,void 0,void 0,(function*(){const r=this.prepareVideoElement(e);return this.addVideoSource(r,t),this.videoElement=r,this.stream=t,yield this.playVideoOnLoadAsync(r),r}))}playVideoOnLoadAsync(t){return new Promise(((e,r)=>this.playVideoOnLoad(t,(()=>e()))))}playVideoOnLoad(t,e){this.videoEndedListener=()=>this.stopStreams(),this.videoCanPlayListener=()=>this.tryPlayVideo(t),t.addEventListener("ended",this.videoEndedListener),t.addEventListener("canplay",this.videoCanPlayListener),t.addEventListener("playing",e),this.tryPlayVideo(t)}isVideoPlaying(t){return t.currentTime>0&&!t.paused&&!t.ended&&t.readyState>2}tryPlayVideo(t){return v(this,void 0,void 0,(function*(){if(this.isVideoPlaying(t))console.warn("Trying to play video that is already playing.");else try{yield t.play()}catch(t){console.warn("It was not possible to play the video.")}}))}getMediaElement(t,e){const r=document.getElementById(t);if(!r)throw new a(`element with id '${t}' not found`);if(r.nodeName.toLowerCase()!==e.toLowerCase())throw new a(`element with id '${t}' must be an ${e} element`);return r}decodeFromImage(t,e){if(!t&&!e)throw new a("either imageElement with a src set or an url must be provided");return e&&!t?this.decodeFromImageUrl(e):this.decodeFromImageElement(t)}decodeFromVideo(t,e){if(!t&&!e)throw new a("Either an element with a src set or an URL must be provided");return e&&!t?this.decodeFromVideoUrl(e):this.decodeFromVideoElement(t)}decodeFromVideoContinuously(t,e,r){if(void 0===t&&void 0===e)throw new a("Either an element with a src set or an URL must be provided");return e&&!t?this.decodeFromVideoUrlContinuously(e,r):this.decodeFromVideoElementContinuously(t,r)}decodeFromImageElement(t){if(!t)throw new a("An image element must be provided.");this.reset();const e=this.prepareImageElement(t);let r;return this.imageElement=e,r=this.isImageLoaded(e)?this.decodeOnce(e,!1,!0):this._decodeOnLoadImage(e),r}decodeFromVideoElement(t){const e=this._decodeFromVideoElementSetup(t);return this._decodeOnLoadVideo(e)}decodeFromVideoElementContinuously(t,e){const r=this._decodeFromVideoElementSetup(t);return this._decodeOnLoadVideoContinuously(r,e)}_decodeFromVideoElementSetup(t){if(!t)throw new a("A video element must be provided.");this.reset();const e=this.prepareVideoElement(t);return this.videoElement=e,e}decodeFromImageUrl(t){if(!t)throw new a("An URL must be provided.");this.reset();const e=this.prepareImageElement();this.imageElement=e;const r=this._decodeOnLoadImage(e);return e.src=t,r}decodeFromVideoUrl(t){if(!t)throw new a("An URL must be provided.");this.reset();const e=this.prepareVideoElement(),r=this.decodeFromVideoElement(e);return e.src=t,r}decodeFromVideoUrlContinuously(t,e){if(!t)throw new a("An URL must be provided.");this.reset();const r=this.prepareVideoElement(),n=this.decodeFromVideoElementContinuously(r,e);return r.src=t,n}_decodeOnLoadImage(t){return new Promise(((e,r)=>{this.imageLoadedListener=()=>this.decodeOnce(t,!1,!0).then(e,r),t.addEventListener("load",this.imageLoadedListener)}))}_decodeOnLoadVideo(t){return v(this,void 0,void 0,(function*(){return yield this.playVideoOnLoadAsync(t),yield this.decodeOnce(t)}))}_decodeOnLoadVideoContinuously(t,e){return v(this,void 0,void 0,(function*(){yield this.playVideoOnLoadAsync(t),this.decodeContinuously(t,e)}))}isImageLoaded(t){return!!t.complete&&0!==t.naturalWidth}prepareImageElement(t){let e;return void 0===t&&(e=document.createElement("img"),e.width=200,e.height=200),"string"==typeof t&&(e=this.getMediaElement(t,"img")),t instanceof HTMLImageElement&&(e=t),e}prepareVideoElement(t){let e;return t||"undefined"==typeof document||(e=document.createElement("video"),e.width=200,e.height=200),"string"==typeof t&&(e=this.getMediaElement(t,"video")),t instanceof HTMLVideoElement&&(e=t),e.setAttribute("autoplay","true"),e.setAttribute("muted","true"),e.setAttribute("playsinline","true"),e}decodeOnce(t,e=!0,r=!0){this._stopAsyncDecode=!1;const n=(i,o)=>{if(this._stopAsyncDecode)return o(new D("Video stream has ended before any code could be detected.")),void(this._stopAsyncDecode=void 0);try{i(this.decode(t))}catch(t){if(e&&t instanceof D||(t instanceof h||t instanceof E)&&r)return setTimeout(n,this._timeBetweenDecodingAttempts,i,o);o(t)}};return new Promise(((t,e)=>n(t,e)))}decodeContinuously(t,e){this._stopContinuousDecode=!1;const r=()=>{if(this._stopContinuousDecode)this._stopContinuousDecode=void 0;else try{const n=this.decode(t);e(n,null),setTimeout(r,this.timeBetweenScansMillis)}catch(t){e(null,t),(t instanceof h||t instanceof E||t instanceof D)&&setTimeout(r,this._timeBetweenDecodingAttempts)}};r()}decode(t){const e=this.createBinaryBitmap(t);return this.decodeBitmap(e)}_isHTMLVideoElement(t){return 0!==t.videoWidth}drawFrameOnCanvas(t,e,r){e||(e={sx:0,sy:0,sWidth:t.videoWidth,sHeight:t.videoHeight,dx:0,dy:0,dWidth:t.videoWidth,dHeight:t.videoHeight}),r||(r=this.captureCanvasContext),r.drawImage(t,e.sx,e.sy,e.sWidth,e.sHeight,e.dx,e.dy,e.dWidth,e.dHeight)}drawImageOnCanvas(t,e,r=this.captureCanvasContext){e||(e={sx:0,sy:0,sWidth:t.naturalWidth,sHeight:t.naturalHeight,dx:0,dy:0,dWidth:t.naturalWidth,dHeight:t.naturalHeight}),r||(r=this.captureCanvasContext),r.drawImage(t,e.sx,e.sy,e.sWidth,e.sHeight,e.dx,e.dy,e.dWidth,e.dHeight)}createBinaryBitmap(t){this.getCaptureCanvasContext(t),this._isHTMLVideoElement(t)?this.drawFrameOnCanvas(t):this.drawImageOnCanvas(t);const e=this.getCaptureCanvas(t),r=new B(e),n=new R(r);return new l(n)}getCaptureCanvasContext(t){if(!this.captureCanvasContext){const e=this.getCaptureCanvas(t).getContext("2d");this.captureCanvasContext=e}return this.captureCanvasContext}getCaptureCanvas(t){if(!this.captureCanvas){const e=this.createCaptureCanvas(t);this.captureCanvas=e}return this.captureCanvas}decodeBitmap(t){return this.reader.decode(t,this._hints)}createCaptureCanvas(t){if("undefined"==typeof document)return this._destroyCaptureCanvas(),null;const e=document.createElement("canvas");let r,n;return void 0!==t&&(t instanceof HTMLVideoElement?(r=t.videoWidth,n=t.videoHeight):t instanceof HTMLImageElement&&(r=t.naturalWidth||t.width,n=t.naturalHeight||t.height)),e.style.width=r+"px",e.style.height=n+"px",e.width=r,e.height=n,e}stopStreams(){this.stream&&(this.stream.getVideoTracks().forEach((t=>t.stop())),this.stream=void 0),!1===this._stopAsyncDecode&&this.stopAsyncDecode(),!1===this._stopContinuousDecode&&this.stopContinuousDecode()}reset(){this.stopStreams(),this._destroyVideoElement(),this._destroyImageElement(),this._destroyCaptureCanvas()}_destroyVideoElement(){this.videoElement&&(void 0!==this.videoEndedListener&&this.videoElement.removeEventListener("ended",this.videoEndedListener),void 0!==this.videoPlayingEventListener&&this.videoElement.removeEventListener("playing",this.videoPlayingEventListener),void 0!==this.videoCanPlayListener&&this.videoElement.removeEventListener("loadedmetadata",this.videoCanPlayListener),this.cleanVideoSource(this.videoElement),this.videoElement=void 0)}_destroyImageElement(){this.imageElement&&(void 0!==this.imageLoadedListener&&this.imageElement.removeEventListener("load",this.imageLoadedListener),this.imageElement.src=void 0,this.imageElement.removeAttribute("src"),this.imageElement=void 0)}_destroyCaptureCanvas(){this.captureCanvasContext=void 0,this.captureCanvas=void 0}addVideoSource(t,e){try{t.srcObject=e}catch(r){t.src=URL.createObjectURL(e)}}cleanVideoSource(t){try{t.srcObject=null}catch(e){t.src=""}this.videoElement.removeAttribute("src")}}class x{constructor(t,e,r=(null==e?0:8*e.length),n,i,o=d.currentTimeMillis()){this.text=t,this.rawBytes=e,this.numBits=r,this.resultPoints=n,this.format=i,this.timestamp=o,this.text=t,this.rawBytes=e,this.numBits=null==r?null==e?0:8*e.length:r,this.resultPoints=n,this.format=i,this.resultMetadata=null,this.timestamp=null==o?d.currentTimeMillis():o}getText(){return this.text}getRawBytes(){return this.rawBytes}getNumBits(){return this.numBits}getResultPoints(){return this.resultPoints}getBarcodeFormat(){return this.format}getResultMetadata(){return this.resultMetadata}putMetadata(t,e){null===this.resultMetadata&&(this.resultMetadata=new Map),this.resultMetadata.set(t,e)}putAllMetadata(t){null!==t&&(null===this.resultMetadata?this.resultMetadata=t:this.resultMetadata=new Map(t))}addResultPoints(t){const e=this.resultPoints;if(null===e)this.resultPoints=t;else if(null!==t&&t.length>0){const r=new Array(e.length+t.length);d.arraycopy(e,0,r,0,e.length),d.arraycopy(t,0,r,e.length,t.length),this.resultPoints=r}}getTimestamp(){return this.timestamp}toString(){return this.text}}!function(t){t[t.AZTEC=0]="AZTEC",t[t.CODABAR=1]="CODABAR",t[t.CODE_39=2]="CODE_39",t[t.CODE_93=3]="CODE_93",t[t.CODE_128=4]="CODE_128",t[t.DATA_MATRIX=5]="DATA_MATRIX",t[t.EAN_8=6]="EAN_8",t[t.EAN_13=7]="EAN_13",t[t.ITF=8]="ITF",t[t.MAXICODE=9]="MAXICODE",t[t.PDF_417=10]="PDF_417",t[t.QR_CODE=11]="QR_CODE",t[t.RSS_14=12]="RSS_14",t[t.RSS_EXPANDED=13]="RSS_EXPANDED",t[t.UPC_A=14]="UPC_A",t[t.UPC_E=15]="UPC_E",t[t.UPC_EAN_EXTENSION=16]="UPC_EAN_EXTENSION"}(P||(P={}));var k,U=P;!function(t){t[t.OTHER=0]="OTHER",t[t.ORIENTATION=1]="ORIENTATION",t[t.BYTE_SEGMENTS=2]="BYTE_SEGMENTS",t[t.ERROR_CORRECTION_LEVEL=3]="ERROR_CORRECTION_LEVEL",t[t.ISSUE_NUMBER=4]="ISSUE_NUMBER",t[t.SUGGESTED_PRICE=5]="SUGGESTED_PRICE",t[t.POSSIBLE_COUNTRY=6]="POSSIBLE_COUNTRY",t[t.UPC_EAN_EXTENSION=7]="UPC_EAN_EXTENSION",t[t.PDF417_EXTRA_METADATA=8]="PDF417_EXTRA_METADATA",t[t.STRUCTURED_APPEND_SEQUENCE=9]="STRUCTURED_APPEND_SEQUENCE",t[t.STRUCTURED_APPEND_PARITY=10]="STRUCTURED_APPEND_PARITY"}(k||(k={}));var H,V,z,G,Y,X,W=k;class j{constructor(t,e,r,n,i=-1,o=-1){this.rawBytes=t,this.text=e,this.byteSegments=r,this.ecLevel=n,this.structuredAppendSequenceNumber=i,this.structuredAppendParity=o,this.numBits=null==t?0:8*t.length}getRawBytes(){return this.rawBytes}getNumBits(){return this.numBits}setNumBits(t){this.numBits=t}getText(){return this.text}getByteSegments(){return this.byteSegments}getECLevel(){return this.ecLevel}getErrorsCorrected(){return this.errorsCorrected}setErrorsCorrected(t){this.errorsCorrected=t}getErasures(){return this.erasures}setErasures(t){this.erasures=t}getOther(){return this.other}setOther(t){this.other=t}hasStructuredAppend(){return this.structuredAppendParity>=0&&this.structuredAppendSequenceNumber>=0}getStructuredAppendParity(){return this.structuredAppendParity}getStructuredAppendSequenceNumber(){return this.structuredAppendSequenceNumber}}class Z{exp(t){return this.expTable[t]}log(t){if(0===t)throw new c;return this.logTable[t]}static addOrSubtract(t,e){return t^e}}class Q{constructor(t,e){if(0===e.length)throw new c;this.field=t;const r=e.length;if(r>1&&0===e[0]){let t=1;for(;tr.length){const t=e;e=r,r=t}let n=new Int32Array(r.length);const i=r.length-e.length;d.arraycopy(r,0,n,0,i);for(let t=i;t=t.getDegree()&&!n.isZero();){const i=n.getDegree()-t.getDegree(),s=e.multiply(n.getCoefficient(n.getDegree()),o),a=t.multiplyByMonomial(i,s),c=e.buildMonomial(i,s);r=r.addOrSubtract(c),n=n.addOrSubtract(a)}return[r,n]}toString(){let t="";for(let e=this.getDegree();e>=0;e--){let r=this.getCoefficient(e);if(0!==r){if(r<0?(t+=" - ",r=-r):t.length>0&&(t+=" + "),0===e||1!==r){const e=this.field.log(r);0===e?t+="1":1===e?t+="a":(t+="a^",t+=e)}0!==e&&(1===e?t+="x":(t+="x^",t+=e))}}return t}}class K extends s{}K.kind="ArithmeticException";class q extends Z{constructor(t,e,r){super(),this.primitive=t,this.size=e,this.generatorBase=r;const n=new Int32Array(e);let i=1;for(let r=0;r=e&&(i^=t,i&=e-1);this.expTable=n;const o=new Int32Array(e);for(let t=0;t=(r/2|0);){let t=i,e=s;if(i=o,s=a,i.isZero())throw new J("r_{i-1} was zero");o=t;let r=n.getZero();const c=i.getCoefficient(i.getDegree()),l=n.inverse(c);for(;o.getDegree()>=i.getDegree()&&!o.isZero();){const t=o.getDegree()-i.getDegree(),e=n.multiply(o.getCoefficient(o.getDegree()),l);r=r.addOrSubtract(n.buildMonomial(t,e)),o=o.addOrSubtract(i.multiplyByMonomial(t,e))}if(a=r.multiply(s).addOrSubtract(e),o.getDegree()>=i.getDegree())throw new $("Division algorithm failed to reduce polynomial?")}const c=a.getCoefficient(0);if(0===c)throw new J("sigmaTilde(0) was zero");const l=n.inverse(c);return[a.multiplyScalar(l),o.multiplyScalar(l)]}findErrorLocations(t){const e=t.getDegree();if(1===e)return Int32Array.from([t.getCoefficient(1)]);const r=new Int32Array(e);let n=0;const i=this.field;for(let o=1;o1,h,h+r-1),h+=r-1;else for(let t=r-1;t>=0;--t)l[h++]=0!=(e&1<=8?et.readCode(t,e,8):et.readCode(t,e,r)<<8-r}static convertBoolArrayToByteArray(t){let e=new Uint8Array((t.length+7)/8);for(let r=0;r","?","[","]","{","}","CTRL_UL"],et.DIGIT_TABLE=["CTRL_PS"," ","0","1","2","3","4","5","6","7","8","9",",",".","CTRL_UL","CTRL_US"];class rt{constructor(){}static round(t){return NaN===t?0:t<=Number.MIN_SAFE_INTEGER?Number.MIN_SAFE_INTEGER:t>=Number.MAX_SAFE_INTEGER?Number.MAX_SAFE_INTEGER:t+(t<0?-.5:.5)|0}static distance(t,e,r,n){const i=t-r,o=e-n;return Math.sqrt(i*i+o*o)}static sum(t){let e=0;for(let r=0,n=t.length;r!==n;r++)e+=t[r];return e}}class nt{static floatToIntBits(t){return t}}nt.MAX_VALUE=Number.MAX_SAFE_INTEGER;class it{constructor(t,e){this.x=t,this.y=e}getX(){return this.x}getY(){return this.y}equals(t){if(t instanceof it){const e=t;return this.x===e.x&&this.y===e.y}return!1}hashCode(){return 31*nt.floatToIntBits(this.x)+nt.floatToIntBits(this.y)}toString(){return"("+this.x+","+this.y+")"}static orderBestPatterns(t){const e=this.distance(t[0],t[1]),r=this.distance(t[1],t[2]),n=this.distance(t[0],t[2]);let i,o,s;if(r>=e&&r>=n?(o=t[0],i=t[1],s=t[2]):n>=r&&n>=e?(o=t[1],i=t[0],s=t[2]):(o=t[2],i=t[0],s=t[1]),this.crossProductZ(i,o,s)<0){const t=i;i=s,s=t}t[0]=i,t[1]=o,t[2]=s}static distance(t,e){return rt.distance(t.x,t.y,e.x,e.y)}static crossProductZ(t,e,r){const n=e.x,i=e.y;return(r.x-n)*(t.y-i)-(r.y-i)*(t.x-n)}}class ot{constructor(t,e){this.bits=t,this.points=e}getBits(){return this.bits}getPoints(){return this.points}}class st extends ot{constructor(t,e,r,n,i){super(t,e),this.compact=r,this.nbDatablocks=n,this.nbLayers=i}getNbLayers(){return this.nbLayers}getNbDatablocks(){return this.nbDatablocks}isCompact(){return this.compact}}class at{constructor(t,e,r,n){this.image=t,this.height=t.getHeight(),this.width=t.getWidth(),null==e&&(e=at.INIT_SIZE),null==r&&(r=t.getWidth()/2|0),null==n&&(n=t.getHeight()/2|0);const i=e/2|0;if(this.leftInit=r-i,this.rightInit=r+i,this.upInit=n-i,this.downInit=n+i,this.upInit<0||this.leftInit<0||this.downInit>=this.height||this.rightInit>=this.width)throw new D}detect(){let t=this.leftInit,e=this.rightInit,r=this.upInit,n=this.downInit,i=!1,o=!0,s=!1,a=!1,c=!1,l=!1,h=!1;const u=this.width,d=this.height;for(;o;){o=!1;let f=!0;for(;(f||!a)&&e=u){i=!0;break}let g=!0;for(;(g||!c)&&n=d){i=!0;break}let w=!0;for(;(w||!l)&&t>=0;)w=this.containsBlackPoint(r,n,t,!1),w?(t--,o=!0,l=!0):l||t--;if(t<0){i=!0;break}let m=!0;for(;(m||!h)&&r>=0;)m=this.containsBlackPoint(t,e,r,!0),m?(r--,o=!0,h=!0):h||r--;if(r<0){i=!0;break}o&&(s=!0)}if(!i&&s){const i=e-t;let o=null;for(let e=1;null===o&&er||s<-1||s>n)throw new D;i=!1,-1===o?(e[t]=0,i=!0):o===r&&(e[t]=r-1,i=!0),-1===s?(e[t+1]=0,i=!0):s===n&&(e[t+1]=n-1,i=!0)}i=!0;for(let t=e.length-2;t>=0&&i;t-=2){const o=Math.floor(e[t]),s=Math.floor(e[t+1]);if(o<-1||o>r||s<-1||s>n)throw new D;i=!1,-1===o?(e[t]=0,i=!0):o===r&&(e[t]=r-1,i=!0),-1===s?(e[t+1]=0,i=!0):s===n&&(e[t+1]=n-1,i=!0)}}}class lt{constructor(t,e,r,n,i,o,s,a,c){this.a11=t,this.a21=e,this.a31=r,this.a12=n,this.a22=i,this.a32=o,this.a13=s,this.a23=a,this.a33=c}static quadrilateralToQuadrilateral(t,e,r,n,i,o,s,a,c,l,h,u,d,f,g,w){const m=lt.quadrilateralToSquare(t,e,r,n,i,o,s,a);return lt.squareToQuadrilateral(c,l,h,u,d,f,g,w).times(m)}transformPoints(t){const e=t.length,r=this.a11,n=this.a12,i=this.a13,o=this.a21,s=this.a22,a=this.a23,c=this.a31,l=this.a32,h=this.a33;for(let u=0;u>1&127):(n<<=10,n+=(e>>2&992)+(e>>1&31))}let i=this.getCorrectedParameterData(n,this.compact);this.compact?(this.nbLayers=1+(i>>6),this.nbDataBlocks=1+(63&i)):(this.nbLayers=1+(i>>11),this.nbDataBlocks=1+(2047&i))}getRotation(t,e){let r=0;t.forEach(((t,n,i)=>{r=(t>>e-2<<1)+(1&t)+(r<<3)})),r=((1&r)<<11)+(r>>1);for(let t=0;t<4;t++)if(m.bitCount(r^this.EXPECTED_CORNER_BITS[t])<=2)return t;throw new D}getCorrectedParameterData(t,e){let r,n;e?(r=7,n=2):(r=10,n=4);let i=r-n,o=new Int32Array(r);for(let e=r-1;e>=0;--e)o[e]=15&t,t>>=4;try{new tt(q.AZTEC_PARAM).decode(o,i)}catch(t){throw new D}let s=0;for(let t=0;t2){let r=this.distancePoint(c,t)*this.nbCenterLayers/(this.distancePoint(i,e)*(this.nbCenterLayers+2));if(r<.75||r>1.25||!this.isWhiteOrBlackRectangle(t,s,a,c))break}e=t,r=s,n=a,i=c,o=!o}if(5!==this.nbCenterLayers&&7!==this.nbCenterLayers)throw new D;this.compact=5===this.nbCenterLayers;let s=new it(e.getX()+.5,e.getY()-.5),a=new it(r.getX()+.5,r.getY()+.5),c=new it(n.getX()-.5,n.getY()+.5),l=new it(i.getX()-.5,i.getY()-.5);return this.expandSquare([s,a,c,l],2*this.nbCenterLayers-3,2*this.nbCenterLayers)}getMatrixCenter(){let t,e,r,n;try{let i=new at(this.image).detect();t=i[0],e=i[1],r=i[2],n=i[3]}catch(i){let o=this.image.getWidth()/2,s=this.image.getHeight()/2;t=this.getFirstDifferent(new dt(o+7,s-7),!1,1,-1).toResultPoint(),e=this.getFirstDifferent(new dt(o+7,s+7),!1,1,1).toResultPoint(),r=this.getFirstDifferent(new dt(o-7,s+7),!1,-1,1).toResultPoint(),n=this.getFirstDifferent(new dt(o-7,s-7),!1,-1,-1).toResultPoint()}let i=rt.round((t.getX()+n.getX()+e.getX()+r.getX())/4),o=rt.round((t.getY()+n.getY()+e.getY()+r.getY())/4);try{let s=new at(this.image,15,i,o).detect();t=s[0],e=s[1],r=s[2],n=s[3]}catch(s){t=this.getFirstDifferent(new dt(i+7,o-7),!1,1,-1).toResultPoint(),e=this.getFirstDifferent(new dt(i+7,o+7),!1,1,1).toResultPoint(),r=this.getFirstDifferent(new dt(i-7,o+7),!1,-1,1).toResultPoint(),n=this.getFirstDifferent(new dt(i-7,o-7),!1,-1,-1).toResultPoint()}return i=rt.round((t.getX()+n.getX()+e.getX()+r.getX())/4),o=rt.round((t.getY()+n.getY()+e.getY()+r.getY())/4),new dt(i,o)}getMatrixCornerPoints(t){return this.expandSquare(t,2*this.nbCenterLayers,this.getDimension())}sampleGrid(t,e,r,n,i){let o=ut.getInstance(),s=this.getDimension(),a=s/2-this.nbCenterLayers,c=s/2+this.nbCenterLayers;return o.sampleGrid(t,s,s,a,a,c,a,c,c,a,c,e.getX(),e.getY(),r.getX(),r.getY(),n.getX(),n.getY(),i.getX(),i.getY())}sampleLine(t,e,r){let n=0,i=this.distanceResultPoint(t,e),o=i/r,s=t.getX(),a=t.getY(),c=o*(e.getX()-t.getX())/i,l=o*(e.getY()-t.getY())/i;for(let t=0;t.1&&h<.9?0:h<=.1===c?1:-1}getFirstDifferent(t,e,r,n){let i=t.getX()+r,o=t.getY()+n;for(;this.isValid(i,o)&&this.image.get(i,o)===e;)i+=r,o+=n;for(i-=r,o-=n;this.isValid(i,o)&&this.image.get(i,o)===e;)i+=r;for(i-=r;this.isValid(i,o)&&this.image.get(i,o)===e;)o+=n;return o-=n,new dt(i,o)}expandSquare(t,e,r){let n=r/(2*e),i=t[0].getX()-t[2].getX(),o=t[0].getY()-t[2].getY(),s=(t[0].getX()+t[2].getX())/2,a=(t[0].getY()+t[2].getY())/2,c=new it(s+n*i,a+n*o),l=new it(s-n*i,a-n*o);return i=t[1].getX()-t[3].getX(),o=t[1].getY()-t[3].getY(),s=(t[1].getX()+t[3].getX())/2,a=(t[1].getY()+t[3].getY())/2,[c,new it(s+n*i,a+n*o),l,new it(s-n*i,a-n*o)]}isValid(t,e){return t>=0&&t0&&e{r.foundPossibleResultPoint(t)}))}}reset(){}}class wt{decode(t,e){try{return this.doDecode(t,e)}catch(r){if(e&&!0===e.get(C.TRY_HARDER)&&t.isRotateSupported()){const r=t.rotateCounterClockwise(),n=this.doDecode(r,e),i=n.getResultMetadata();let o=270;null!==i&&!0===i.get(W.ORIENTATION)&&(o+=i.get(W.ORIENTATION)%360),n.putMetadata(W.ORIENTATION,o);const s=n.getResultPoints();if(null!==s){const t=r.getHeight();for(let e=0;e>(o?8:5));let a;a=o?n:15;const c=Math.trunc(n/2);for(let o=0;o=n)break;try{i=t.getBlackRow(l,i)}catch(t){continue}for(let t=0;t<2;t++){if(1===t&&(i.reverse(),e&&!0===e.get(C.NEED_RESULT_POINT_CALLBACK))){const t=new Map;e.forEach(((e,r)=>t.set(r,e))),t.delete(C.NEED_RESULT_POINT_CALLBACK),e=t}try{const n=this.decodeRow(l,i,e);if(1===t){n.putMetadata(W.ORIENTATION,180);const t=n.getResultPoints();null!==t&&(t[0]=new it(r-t[0].getX()-1,t[0].getY()),t[1]=new it(r-t[1].getX()-1,t[1].getY()))}return n}catch(t){}}}throw new D}static recordPattern(t,e,r){const n=r.length;for(let t=0;t=i)throw new D;let o=!t.get(e),s=0,a=e;for(;a0&&n>=0;)t.get(--e)!==i&&(n--,i=!i);if(n>=0)throw new D;wt.recordPattern(t,e+1,r)}static patternMatchVariance(t,e,r){const n=t.length;let i=0,o=0;for(let r=0;ro?n-o:o-n;if(c>r)return Number.POSITIVE_INFINITY;a+=c}return a/i}}class mt extends wt{static findStartPattern(t){const e=t.getSize(),r=t.getNextSet(0);let n=0,i=Int32Array.from([0,0,0,0,0,0]),o=r,s=!1;for(let a=r;a=0&&t.isRange(Math.max(0,o-(a-o)/2),o,!1))return Int32Array.from([o,a,r]);o+=i[0]+i[1],i=i.slice(2,i.length-1),i[n-1]=0,i[n]=0,n--}else n++;i[n]=1,s=!s}throw new D}static decodeCode(t,e,r){wt.recordPattern(t,r,e);let n=mt.MAX_AVG_VARIANCE,i=-1;for(let t=0;t=0)return i;throw new D}decodeRow(t,e,r){const n=r&&!0===r.get(C.ASSUME_GS1),i=mt.findStartPattern(e),o=i[2];let s=0;const a=new Uint8Array(20);let c;switch(a[s++]=o,o){case mt.CODE_START_A:c=mt.CODE_CODE_A;break;case mt.CODE_START_B:c=mt.CODE_CODE_B;break;case mt.CODE_START_C:c=mt.CODE_CODE_C;break;default:throw new E}let l=!1,u=!1,d="",f=i[0],g=i[1];const w=Int32Array.from([0,0,0,0,0,0]);let m=0,p=0,A=o,I=0,S=!0,_=!1,T=!1;for(;!l;){const t=u;switch(u=!1,m=p,p=mt.decodeCode(e,w,g),a[s++]=p,p!==mt.CODE_STOP&&(S=!0),p!==mt.CODE_STOP&&(I++,A+=I*p),f=g,g+=w.reduce(((t,e)=>t+e),0),p){case mt.CODE_START_A:case mt.CODE_START_B:case mt.CODE_START_C:throw new E}switch(c){case mt.CODE_CODE_A:if(p<64)d+=T===_?String.fromCharCode(" ".charCodeAt(0)+p):String.fromCharCode(" ".charCodeAt(0)+p+128),T=!1;else if(p<96)d+=T===_?String.fromCharCode(p-64):String.fromCharCode(p+64),T=!1;else switch(p!==mt.CODE_STOP&&(S=!1),p){case mt.CODE_FNC_1:n&&(0===d.length?d+="]C1":d+=String.fromCharCode(29));break;case mt.CODE_FNC_2:case mt.CODE_FNC_3:break;case mt.CODE_FNC_4_A:!_&&T?(_=!0,T=!1):_&&T?(_=!1,T=!1):T=!0;break;case mt.CODE_SHIFT:u=!0,c=mt.CODE_CODE_B;break;case mt.CODE_CODE_B:c=mt.CODE_CODE_B;break;case mt.CODE_CODE_C:c=mt.CODE_CODE_C;break;case mt.CODE_STOP:l=!0}break;case mt.CODE_CODE_B:if(p<96)d+=T===_?String.fromCharCode(" ".charCodeAt(0)+p):String.fromCharCode(" ".charCodeAt(0)+p+128),T=!1;else switch(p!==mt.CODE_STOP&&(S=!1),p){case mt.CODE_FNC_1:n&&(0===d.length?d+="]C1":d+=String.fromCharCode(29));break;case mt.CODE_FNC_2:case mt.CODE_FNC_3:break;case mt.CODE_FNC_4_B:!_&&T?(_=!0,T=!1):_&&T?(_=!1,T=!1):T=!0;break;case mt.CODE_SHIFT:u=!0,c=mt.CODE_CODE_A;break;case mt.CODE_CODE_A:c=mt.CODE_CODE_A;break;case mt.CODE_CODE_C:c=mt.CODE_CODE_C;break;case mt.CODE_STOP:l=!0}break;case mt.CODE_CODE_C:if(p<100)p<10&&(d+="0"),d+=p;else switch(p!==mt.CODE_STOP&&(S=!1),p){case mt.CODE_FNC_1:n&&(0===d.length?d+="]C1":d+=String.fromCharCode(29));break;case mt.CODE_CODE_A:c=mt.CODE_CODE_A;break;case mt.CODE_CODE_B:c=mt.CODE_CODE_B;break;case mt.CODE_STOP:l=!0}}t&&(c=c===mt.CODE_CODE_A?mt.CODE_CODE_B:mt.CODE_CODE_A)}const y=g-f;if(g=e.getNextUnset(g),!e.isRange(g,Math.min(e.getSize(),g+(g-f)/2),!1))throw new D;if(A-=I*m,A%103!==m)throw new h;const N=d.length;if(0===N)throw new D;N>0&&S&&(d=c===mt.CODE_CODE_C?d.substring(0,N-2):d.substring(0,N-1));const M=(i[1]+i[0])/2,R=f+y/2,O=a.length,b=new Uint8Array(O);for(let t=0;tn&&(i=e);n=i,e=0;let o=0,s=0;for(let i=0;in&&(s|=1<0;i++){let r=t[i];if(r>n&&(e--,2*r>=o))return-1}return s}}while(e>3);return-1}static patternToChar(t){for(let e=0;e="A"&&i<="Z"))throw new E;o=String.fromCharCode(i.charCodeAt(0)+32);break;case"$":if(!(i>="A"&&i<="Z"))throw new E;o=String.fromCharCode(i.charCodeAt(0)-64);break;case"%":if(i>="A"&&i<="E")o=String.fromCharCode(i.charCodeAt(0)-38);else if(i>="F"&&i<="J")o=String.fromCharCode(i.charCodeAt(0)-11);else if(i>="K"&&i<="O")o=String.fromCharCode(i.charCodeAt(0)+16);else if(i>="P"&&i<="T")o=String.fromCharCode(i.charCodeAt(0)+43);else if("U"===i)o="\0";else if("V"===i)o="@";else if("W"===i)o="`";else{if("X"!==i&&"Y"!==i&&"Z"!==i)throw new E;o=""}break;case"/":if(i>="A"&&i<="O")o=String.fromCharCode(i.charCodeAt(0)-32);else{if("Z"!==i)throw new E;o=":"}}r+=o,n++}else r+=e}return r}}pt.ALPHABET_STRING="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%",pt.CHARACTER_ENCODINGS=[52,289,97,352,49,304,112,37,292,100,265,73,328,25,280,88,13,268,76,28,259,67,322,19,274,82,7,262,70,22,385,193,448,145,400,208,133,388,196,168,162,138,42],pt.ASTERISK_ENCODING=148;class At extends wt{constructor(){super(...arguments),this.narrowLineWidth=-1}decodeRow(t,e,r){let n=this.decodeStart(e),i=this.decodeEnd(e),o=new y;At.decodeMiddle(e,n[1],i[0],o);let s=o.toString(),a=null;null!=r&&(a=r.get(C.ALLOWED_LENGTHS)),null==a&&(a=At.DEFAULT_ALLOWED_LENGTHS);let c=s.length,l=!1,h=0;for(let t of a){if(c===t){l=!0;break}t>h&&(h=t)}if(!l&&c>h&&(l=!0),!l)throw new E;const u=[new it(n[1],t),new it(i[0],t)];return new x(s,null,0,u,U.ITF,(new Date).getTime())}static decodeMiddle(t,e,r,n){let i=new Int32Array(10),o=new Int32Array(5),s=new Int32Array(5);for(i.fill(0),o.fill(0),s.fill(0);e0&&n>=0&&!t.get(n);n--)r--;if(0!==r)throw new D}static skipWhiteSpace(t){const e=t.getSize(),r=t.getNextSet(0);if(r===e)throw new D;return r}decodeEnd(t){t.reverse();try{let e,r=At.skipWhiteSpace(t);try{e=At.findGuardPattern(t,r,At.END_PATTERN_REVERSED[0])}catch(n){n instanceof D&&(e=At.findGuardPattern(t,r,At.END_PATTERN_REVERSED[1]))}this.validateQuietZone(t,e[0]);let n=e[0];return e[0]=t.getSize()-e[1],e[1]=t.getSize()-n,e}finally{t.reverse()}}static findGuardPattern(t,e,r){let n=r.length,i=new Int32Array(n),o=t.getSize(),s=!1,a=0,c=e;i.fill(0);for(let l=e;l=0)return r%10;throw new D}}At.PATTERNS=[Int32Array.from([1,1,2,2,1]),Int32Array.from([2,1,1,1,2]),Int32Array.from([1,2,1,1,2]),Int32Array.from([2,2,1,1,1]),Int32Array.from([1,1,2,1,2]),Int32Array.from([2,1,2,1,1]),Int32Array.from([1,2,2,1,1]),Int32Array.from([1,1,1,2,2]),Int32Array.from([2,1,1,2,1]),Int32Array.from([1,2,1,2,1]),Int32Array.from([1,1,3,3,1]),Int32Array.from([3,1,1,1,3]),Int32Array.from([1,3,1,1,3]),Int32Array.from([3,3,1,1,1]),Int32Array.from([1,1,3,1,3]),Int32Array.from([3,1,3,1,1]),Int32Array.from([1,3,3,1,1]),Int32Array.from([1,1,1,3,3]),Int32Array.from([3,1,1,3,1]),Int32Array.from([1,3,1,3,1])],At.MAX_AVG_VARIANCE=.38,At.MAX_INDIVIDUAL_VARIANCE=.5,At.DEFAULT_ALLOWED_LENGTHS=[6,8,10,12,14],At.START_PATTERN=Int32Array.from([1,1,1,1]),At.END_PATTERN_REVERSED=[Int32Array.from([1,1,2]),Int32Array.from([1,1,3])];class Ct extends wt{constructor(){super(...arguments),this.decodeRowStringBuffer=""}static findStartGuardPattern(t){let e,r=!1,n=0,i=Int32Array.from([0,0,0]);for(;!r;){i=Int32Array.from([0,0,0]),e=Ct.findGuardPattern(t,n,!1,this.START_END_PATTERN,i);let o=e[0];n=e[1];let s=o-(n-o);s>=0&&(r=t.isRange(s,o,!1))}return e}static checkChecksum(t){return Ct.checkStandardUPCEANChecksum(t)}static checkStandardUPCEANChecksum(t){let e=t.length;if(0===e)return!1;let r=parseInt(t.charAt(e-1),10);return Ct.getStandardUPCEANChecksum(t.substring(0,e-1))===r}static getStandardUPCEANChecksum(t){let e=t.length,r=0;for(let n=e-1;n>=0;n-=2){let e=t.charAt(n).charCodeAt(0)-"0".charCodeAt(0);if(e<0||e>9)throw new E;r+=e}r*=3;for(let n=e-2;n>=0;n-=2){let e=t.charAt(n).charCodeAt(0)-"0".charCodeAt(0);if(e<0||e>9)throw new E;r+=e}return(1e3-r)%10}static decodeEnd(t,e){return Ct.findGuardPattern(t,e,!1,Ct.START_END_PATTERN,new Int32Array(Ct.START_END_PATTERN.length).fill(0))}static findGuardPatternWithoutCounters(t,e,r,n){return this.findGuardPattern(t,e,r,n,new Int32Array(n.length))}static findGuardPattern(t,e,r,n,i){let o=t.getSize(),s=0,a=e=r?t.getNextUnset(e):t.getNextSet(e),c=n.length,l=r;for(let r=e;r=0)return o;throw new D}}Ct.MAX_AVG_VARIANCE=.48,Ct.MAX_INDIVIDUAL_VARIANCE=.7,Ct.START_END_PATTERN=Int32Array.from([1,1,1]),Ct.MIDDLE_PATTERN=Int32Array.from([1,1,1,1,1]),Ct.END_PATTERN=Int32Array.from([1,1,1,1,1,1]),Ct.L_PATTERNS=[Int32Array.from([3,2,1,1]),Int32Array.from([2,2,2,1]),Int32Array.from([2,1,2,2]),Int32Array.from([1,4,1,1]),Int32Array.from([1,1,3,2]),Int32Array.from([1,2,3,1]),Int32Array.from([1,1,1,4]),Int32Array.from([1,3,1,2]),Int32Array.from([1,2,1,3]),Int32Array.from([3,1,1,2])];class Et{constructor(){this.CHECK_DIGIT_ENCODINGS=[24,20,18,17,12,6,3,10,9,5],this.decodeMiddleCounters=Int32Array.from([0,0,0,0]),this.decodeRowStringBuffer=""}decodeRow(t,e,r){let n=this.decodeRowStringBuffer,i=this.decodeMiddle(e,r,n),o=n.toString(),s=Et.parseExtensionString(o),a=[new it((r[0]+r[1])/2,t),new it(i,t)],c=new x(o,null,0,a,U.UPC_EAN_EXTENSION,(new Date).getTime());return null!=s&&c.putAllMetadata(s),c}decodeMiddle(t,e,r){let n=this.decodeMiddleCounters;n[0]=0,n[1]=0,n[2]=0,n[3]=0;let i=t.getSize(),o=e[1],s=0;for(let e=0;e<5&&o=10&&(s|=1<<4-e),4!==e&&(o=t.getNextSet(o),o=t.getNextUnset(o))}if(5!==r.length)throw new D;let a=this.determineCheckDigit(s);if(Et.extensionChecksum(r.toString())!==a)throw new D;return o}static extensionChecksum(t){let e=t.length,r=0;for(let n=e-2;n>=0;n-=2)r+=t.charAt(n).charCodeAt(0)-"0".charCodeAt(0);r*=3;for(let n=e-1;n>=0;n-=2)r+=t.charAt(n).charCodeAt(0)-"0".charCodeAt(0);return r*=3,r%10}determineCheckDigit(t){for(let e=0;e<10;e++)if(t===this.CHECK_DIGIT_ENCODINGS[e])return e;throw new D}static parseExtensionString(t){if(5!==t.length)return null;let e=Et.parseExtension5String(t);return null==e?null:new Map([[W.SUGGESTED_PRICE,e]])}static parseExtension5String(t){let e;switch(t.charAt(0)){case"0":e="£";break;case"5":e="$";break;case"9":switch(t){case"90000":return null;case"99991":return"0.00";case"99990":return"Used"}e="";break;default:e=""}let r=parseInt(t.substring(1)),n=r%100;return e+(r/100).toString()+"."+(n<10?"0"+n:n.toString())}}class It{constructor(){this.decodeMiddleCounters=Int32Array.from([0,0,0,0]),this.decodeRowStringBuffer=""}decodeRow(t,e,r){let n=this.decodeRowStringBuffer,i=this.decodeMiddle(e,r,n),o=n.toString(),s=It.parseExtensionString(o),a=[new it((r[0]+r[1])/2,t),new it(i,t)],c=new x(o,null,0,a,U.UPC_EAN_EXTENSION,(new Date).getTime());return null!=s&&c.putAllMetadata(s),c}decodeMiddle(t,e,r){let n=this.decodeMiddleCounters;n[0]=0,n[1]=0,n[2]=0,n[3]=0;let i=t.getSize(),o=e[1],s=0;for(let e=0;e<2&&o=10&&(s|=1<<1-e),1!==e&&(o=t.getNextSet(o),o=t.getNextUnset(o))}if(2!==r.length)throw new D;if(parseInt(r.toString())%4!==s)throw new D;return o}static parseExtensionString(t){return 2!==t.length?null:new Map([[W.ISSUE_NUMBER,parseInt(t)]])}}class St{static decodeRow(t,e,r){let n=Ct.findGuardPattern(e,r,!1,this.EXTENSION_START_PATTERN,new Int32Array(this.EXTENSION_START_PATTERN.length).fill(0));try{return(new Et).decodeRow(t,e,n)}catch(r){return(new It).decodeRow(t,e,n)}}}St.EXTENSION_START_PATTERN=Int32Array.from([1,1,2]);class _t extends Ct{constructor(){super(),this.decodeRowStringBuffer="",_t.L_AND_G_PATTERNS=_t.L_PATTERNS.map((t=>Int32Array.from(t)));for(let t=10;t<20;t++){let e=_t.L_PATTERNS[t-10],r=new Int32Array(e.length);for(let t=0;t=e.getSize()||!e.isRange(l,u,!1))throw new D;let d=a.toString();if(d.length<8)throw new E;if(!_t.checkChecksum(d))throw new h;let f=(n[1]+n[0])/2,g=(c[1]+c[0])/2,w=this.getBarcodeFormat(),m=[new it(f,t),new it(g,t)],p=new x(d,null,0,m,w,(new Date).getTime()),A=0;try{let r=St.decodeRow(t,e,c[1]);p.putMetadata(W.UPC_EAN_EXTENSION,r.getText()),p.putAllMetadata(r.getResultMetadata()),p.addResultPoints(r.getResultPoints()),A=r.getText().length}catch(t){}let I=null==r?null:r.get(C.ALLOWED_EAN_EXTENSIONS);if(null!=I){let t=!1;for(let e in I)if(A.toString()===e){t=!0;break}if(!t)throw new D}return p}decodeEnd(t,e){return _t.findGuardPattern(t,e,!1,_t.START_END_PATTERN,new Int32Array(_t.START_END_PATTERN.length).fill(0))}static checkChecksum(t){return _t.checkStandardUPCEANChecksum(t)}static checkStandardUPCEANChecksum(t){let e=t.length;if(0===e)return!1;let r=parseInt(t.charAt(e-1),10);return _t.getStandardUPCEANChecksum(t.substring(0,e-1))===r}static getStandardUPCEANChecksum(t){let e=t.length,r=0;for(let n=e-1;n>=0;n-=2){let e=t.charAt(n).charCodeAt(0)-"0".charCodeAt(0);if(e<0||e>9)throw new E;r+=e}r*=3;for(let n=e-2;n>=0;n-=2){let e=t.charAt(n).charCodeAt(0)-"0".charCodeAt(0);if(e<0||e>9)throw new E;r+=e}return(1e3-r)%10}}class Tt extends _t{constructor(){super(),this.decodeMiddleCounters=Int32Array.from([0,0,0,0])}decodeMiddle(t,e,r){let n=this.decodeMiddleCounters;n[0]=0,n[1]=0,n[2]=0,n[3]=0;let i=t.getSize(),o=e[1],s=0;for(let e=0;e<6&&o=10&&(s|=1<<5-e)}r=Tt.determineFirstDigit(r,s),o=_t.findGuardPattern(t,o,!0,_t.MIDDLE_PATTERN,new Int32Array(_t.MIDDLE_PATTERN.length).fill(0))[1];for(let e=0;e<6&&ot));n[0]=0,n[1]=0,n[2]=0,n[3]=0;const i=t.getSize();let o=e[1],s=0;for(let e=0;e<6&&o=10&&(s|=1<<5-e)}return{rowOffset:o,resultString:Dt.determineNumSysAndCheckDigit(r,s)}}decodeEnd(t,e){return Dt.findGuardPatternWithoutCounters(t,e,!0,Dt.MIDDLE_END_PATTERN)}checkChecksum(t){return _t.checkChecksum(Dt.convertUPCEtoUPCA(t))}static determineNumSysAndCheckDigit(t,e){for(let r=0;r<=1;r++)for(let n=0;n<10;n++)if(e===this.NUMSYS_AND_CHECK_DIGIT_PATTERNS[r][n])return String.fromCharCode("0".charCodeAt(0)+r)+t+String.fromCharCode("0".charCodeAt(0)+n);throw D.getNotFoundInstance()}getBarcodeFormat(){return U.UPC_E}static convertUPCEtoUPCA(t){const e=t.slice(1,7).split("").map((t=>t.charCodeAt(0))),r=new y;r.append(t.charAt(0));let n=e[5];switch(n){case 0:case 1:case 2:r.appendChars(e,0,2),r.append(n),r.append("0000"),r.appendChars(e,2,3);break;case 3:r.appendChars(e,0,3),r.append("00000"),r.appendChars(e,3,2);break;case 4:r.appendChars(e,0,4),r.append("00000"),r.append(e[4]);break;default:r.appendChars(e,0,5),r.append("0000"),r.append(n)}return t.length>=8&&r.append(t.charAt(7)),r.toString()}}Dt.MIDDLE_END_PATTERN=Int32Array.from([1,1,1,1,1,1]),Dt.NUMSYS_AND_CHECK_DIGIT_PATTERNS=[Int32Array.from([56,52,50,49,44,38,35,42,41,37]),Int32Array.from([7,11,13,14,19,25,28,21,22,26])];class Mt extends wt{constructor(t){super();let r=null==t?null:t.get(C.POSSIBLE_FORMATS),n=[];e(r)?(n.push(new Tt),n.push(new Nt),n.push(new yt),n.push(new Dt)):(r.indexOf(U.EAN_13)>-1&&n.push(new Tt),r.indexOf(U.UPC_A)>-1&&n.push(new Nt),r.indexOf(U.EAN_8)>-1&&n.push(new yt),r.indexOf(U.UPC_E)>-1&&n.push(new Dt)),this.readers=n}decodeRow(t,e,r){for(let n of this.readers)try{const i=n.decodeRow(t,e,r),o=i.getBarcodeFormat()===U.EAN_13&&"0"===i.getText().charAt(0),s=null==r?null:r.get(C.POSSIBLE_FORMATS),a=null==s||s.includes(U.UPC_A);if(o&&a){const t=i.getRawBytes(),e=new x(i.getText().substring(1),t,t?t.length:null,i.getResultPoints(),U.UPC_A);return e.putAllMetadata(i.getResultMetadata()),e}return i}catch(t){}throw new D}reset(){for(let t of this.readers)t.reset()}}class Rt extends wt{constructor(){super(),this.decodeFinderCounters=new Int32Array(4),this.dataCharacterCounters=new Int32Array(8),this.oddRoundingErrors=new Array(4),this.evenRoundingErrors=new Array(4),this.oddCounts=new Array(this.dataCharacterCounters.length/2),this.evenCounts=new Array(this.dataCharacterCounters.length/2)}getDecodeFinderCounters(){return this.decodeFinderCounters}getDataCharacterCounters(){return this.dataCharacterCounters}getOddRoundingErrors(){return this.oddRoundingErrors}getEvenRoundingErrors(){return this.evenRoundingErrors}getOddCounts(){return this.oddCounts}getEvenCounts(){return this.evenCounts}parseFinderValue(t,e){for(let r=0;rn&&(n=e[i],r=i);t[r]++}static decrement(t,e){let r=0,n=e[0];for(let i=1;i=Rt.MIN_FINDER_PATTERN_RATIO&&r<=Rt.MAX_FINDER_PATTERN_RATIO){let e=Number.MAX_SAFE_INTEGER,r=Number.MIN_SAFE_INTEGER;for(let n of t)n>r&&(r=n),n=s-a-1&&(t-=Bt.combins(n-c-(s-a),s-a-2)),s-a-1>1){let r=0;for(let t=n-c-(s-a-2);t>e;t--)r+=Bt.combins(n-c-t-1,s-a-3);t-=r*(s-1-a)}else n-c>e&&t--;i+=t}n-=c}return i}static combins(t,e){let r,n;t-e>e?(n=e,r=t-e):(n=t-e,r=e);let i=1,o=1;for(let e=t;e>r;e--)i*=e,o<=n&&(i/=o,o++);for(;o<=n;)i/=o,o++;return i}}class Lt{static buildBitArray(t){let e=2*t.length-1;null==t[t.length-1].getRightChar()&&(e-=1);let r=new p(12*e),n=0,i=t[0].getRightChar().getValue();for(let t=11;t>=0;--t)0!=(i&1<=0;--t)0!=(o&1<=0;--e)0!=(t&1<10||r<0||r>10)throw new E;this.firstDigit=e,this.secondDigit=r}getFirstDigit(){return this.firstDigit}getSecondDigit(){return this.secondDigit}getValue(){return 10*this.firstDigit+this.secondDigit}isFirstDigitFNC1(){return this.firstDigit===kt.FNC1}isSecondDigitFNC1(){return this.secondDigit===kt.FNC1}isAnyFNC1(){return this.firstDigit===kt.FNC1||this.secondDigit===kt.FNC1}}kt.FNC1=10;class Ut{constructor(){}static parseFieldsInGeneralPurpose(t){if(!t)return null;if(t.length<2)throw new D;let e=t.substring(0,2);for(let r of Ut.TWO_DIGIT_DATA_LENGTH)if(r[0]===e)return r[1]===Ut.VARIABLE_LENGTH?Ut.processVariableAI(2,r[2],t):Ut.processFixedAI(2,r[1],t);if(t.length<3)throw new D;let r=t.substring(0,3);for(let e of Ut.THREE_DIGIT_DATA_LENGTH)if(e[0]===r)return e[1]===Ut.VARIABLE_LENGTH?Ut.processVariableAI(3,e[2],t):Ut.processFixedAI(3,e[1],t);for(let e of Ut.THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH)if(e[0]===r)return e[1]===Ut.VARIABLE_LENGTH?Ut.processVariableAI(4,e[2],t):Ut.processFixedAI(4,e[1],t);if(t.length<4)throw new D;let n=t.substring(0,4);for(let e of Ut.FOUR_DIGIT_DATA_LENGTH)if(e[0]===n)return e[1]===Ut.VARIABLE_LENGTH?Ut.processVariableAI(4,e[2],t):Ut.processFixedAI(4,e[1],t);throw new D}static processFixedAI(t,e,r){if(r.lengththis.information.getSize())return t+4<=this.information.getSize();for(let e=t;ethis.information.getSize()){let e=this.extractNumericValueFromBitArray(t,4);return new kt(this.information.getSize(),0===e?kt.FNC1:e-1,kt.FNC1)}let e=this.extractNumericValueFromBitArray(t,7);return new kt(t+7,(e-8)/11,(e-8)%11)}extractNumericValueFromBitArray(t,e){return Ht.extractNumericValueFromBitArray(this.information,t,e)}static extractNumericValueFromBitArray(t,e,r){let n=0;for(let i=0;ithis.information.getSize())return!1;let e=this.extractNumericValueFromBitArray(t,5);if(e>=5&&e<16)return!0;if(t+7>this.information.getSize())return!1;let r=this.extractNumericValueFromBitArray(t,7);if(r>=64&&r<116)return!0;if(t+8>this.information.getSize())return!1;let n=this.extractNumericValueFromBitArray(t,8);return n>=232&&n<253}decodeIsoIec646(t){let e=this.extractNumericValueFromBitArray(t,5);if(15===e)return new Ft(t+5,Ft.FNC1);if(e>=5&&e<15)return new Ft(t+5,"0"+(e-5));let r,n=this.extractNumericValueFromBitArray(t,7);if(n>=64&&n<90)return new Ft(t+7,""+(n+1));if(n>=90&&n<116)return new Ft(t+7,""+(n+7));switch(this.extractNumericValueFromBitArray(t,8)){case 232:r="!";break;case 233:r='"';break;case 234:r="%";break;case 235:r="&";break;case 236:r="'";break;case 237:r="(";break;case 238:r=")";break;case 239:r="*";break;case 240:r="+";break;case 241:r=",";break;case 242:r="-";break;case 243:r=".";break;case 244:r="/";break;case 245:r=":";break;case 246:r=";";break;case 247:r="<";break;case 248:r="=";break;case 249:r=">";break;case 250:r="?";break;case 251:r="_";break;case 252:r=" ";break;default:throw new E}return new Ft(t+8,r)}isStillAlpha(t){if(t+5>this.information.getSize())return!1;let e=this.extractNumericValueFromBitArray(t,5);if(e>=5&&e<16)return!0;if(t+6>this.information.getSize())return!1;let r=this.extractNumericValueFromBitArray(t,6);return r>=16&&r<63}decodeAlphanumeric(t){let e=this.extractNumericValueFromBitArray(t,5);if(15===e)return new Ft(t+5,Ft.FNC1);if(e>=5&&e<15)return new Ft(t+5,"0"+(e-5));let r,n=this.extractNumericValueFromBitArray(t,6);if(n>=32&&n<58)return new Ft(t+6,""+(n+33));switch(n){case 58:r="*";break;case 59:r=",";break;case 60:r="-";break;case 61:r=".";break;case 62:r="/";break;default:throw new $("Decoding invalid alphanumeric value: "+n)}return new Ft(t+6,r)}isAlphaTo646ToAlphaLatch(t){if(t+1>this.information.getSize())return!1;for(let e=0;e<5&&e+tthis.information.getSize())return!1;for(let e=t;ethis.information.getSize())return!1;for(let e=0;e<4&&e+t{e.forEach((e=>{t.getLeftChar().getValue()===e.getLeftChar().getValue()&&t.getRightChar().getValue()===e.getRightChar().getValue()&&t.getFinderPatter().getValue()===e.getFinderPatter().getValue()&&(r=!0)}))})),r}}class ee extends Rt{constructor(t){super(...arguments),this.pairs=new Array(ee.MAX_PAIRS),this.rows=new Array,this.startEnd=[2],this.verbose=!0===t}decodeRow(t,e,r){this.pairs.length=0,this.startFromEven=!1;try{return ee.constructResult(this.decodeRow2pairs(t,e))}catch(t){this.verbose&&console.log(t)}return this.pairs.length=0,this.startFromEven=!0,ee.constructResult(this.decodeRow2pairs(t,e))}reset(){this.pairs.length=0,this.rows.length=0}decodeRow2pairs(t,e){let r,n=!1;for(;!n;)try{this.pairs.push(this.retrieveNextPair(e,this.pairs,t))}catch(t){if(t instanceof D){if(!this.pairs.length)throw new D;n=!0}}if(this.checkChecksum())return this.pairs;if(r=!!this.rows.length,this.storeRow(t,!1),r){let t=this.checkRowsBoolean(!1);if(null!=t)return t;if(t=this.checkRowsBoolean(!0),null!=t)return t}throw new D}checkRowsBoolean(t){if(this.rows.length>25)return this.rows.length=0,null;this.pairs.length=0,t&&(this.rows=this.rows.reverse());let e=null;try{e=this.checkRows(new Array,0)}catch(t){this.verbose&&console.log(t)}return t&&(this.rows=this.rows.reverse()),e}checkRows(t,e){for(let r=e;re.length)continue;let r=!0;for(let n=0;nt){i=e.isEquivalent(this.pairs);break}n=e.isEquivalent(this.pairs),r++}i||n||ee.isPartialRow(this.pairs,this.rows)||(this.rows.push(r,new te(this.pairs,t,e)),this.removePartialRows(this.pairs,this.rows))}removePartialRows(t,e){for(let r of e)if(r.getPairs().length!==t.length)for(let e of r.getPairs())for(let r of t)if($t.equals(e,r))break}static isPartialRow(t,e){for(let r of e){let e=!0;for(let n of t){let t=!1;for(let e of r.getPairs())if(n.equals(e)){t=!0;break}if(!t){e=!1;break}}if(e)return!0}return!1}getRows(){return this.rows}static constructResult(t){let e=Jt(Lt.buildBitArray(t)).parseInformation(),r=t[0].getFinderPattern().getResultPoints(),n=t[t.length-1].getFinderPattern().getResultPoints(),i=[r[0],r[1],n[0],n[1]];return new x(e,null,null,i,U.RSS_EXPANDED,null)}checkChecksum(){let t=this.pairs.get(0),e=t.getLeftChar(),r=t.getRightChar();if(null==r)return!1;let n=r.getChecksumPortion(),i=2;for(let t=1;t=0?r:this.isEmptyPair(e)?0:e[e.length-1].getFinderPattern().getStartEnd()[1];let s=e.length%2!=0;this.startFromEven&&(s=!s);let a=!1;for(;i=0&&!t.get(e);)e--;e++,n=this.startEnd[0]-e,i=e,o=this.startEnd[1]}else i=this.startEnd[0],o=t.getNextUnset(this.startEnd[1]+1),n=o-this.startEnd[1];let s,a=this.getDecodeFinderCounters();d.arraycopy(a,0,a,1,a.length-1),a[0]=n;try{s=this.parseFinderValue(a,ee.FINDER_PATTERNS)}catch(t){return null}return new bt(s,[i,o],i,o,e)}decodeDataCharacter(t,e,r,n){let i=this.getDataCharacterCounters();for(let t=0;t.3)throw new D;let a=this.getOddCounts(),c=this.getEvenCounts(),l=this.getOddRoundingErrors(),h=this.getEvenRoundingErrors();for(let t=0;t8){if(e>8.7)throw new D;r=8}let n=t/2;0==(1&t)?(a[n]=r,l[n]=e-r):(c[n]=r,h[n]=e-r)}this.adjustOddEvenCounts(17);let u=4*e.getValue()+(r?0:2)+(n?0:1)-1,d=0,f=0;for(let t=a.length-1;t>=0;t--){if(ee.isNotA1left(e,r,n)){let e=ee.WEIGHTS[u][2*t];f+=a[t]*e}d+=a[t]}let g=0;for(let t=c.length-1;t>=0;t--)if(ee.isNotA1left(e,r,n)){let e=ee.WEIGHTS[u][2*t+1];g+=c[t]*e}let w=f+g;if(0!=(1&d)||d>13||d<4)throw new D;let m=(13-d)/2,p=ee.SYMBOL_WIDEST[m],A=9-p,C=Bt.getRSSvalue(a,p,!0),E=Bt.getRSSvalue(c,A,!1),I=ee.EVEN_TOTAL_SUBSET[m],S=ee.GSUM[m];return new Ot(C*I+E+S,w)}static isNotA1left(t,e,r){return!(0==t.getValue()&&e&&r)}adjustOddEvenCounts(t){let e=rt.sum(new Int32Array(this.getOddCounts())),r=rt.sum(new Int32Array(this.getEvenCounts())),n=!1,i=!1;e>13?i=!0:e<4&&(n=!0);let o=!1,s=!1;r>13?s=!0:r<4&&(o=!0);let a=e+r-t,c=1==(1&e),l=0==(1&r);if(1==a)if(c){if(l)throw new D;i=!0}else{if(!l)throw new D;s=!0}else if(-1==a)if(c){if(l)throw new D;n=!0}else{if(!l)throw new D;o=!0}else{if(0!=a)throw new D;if(c){if(!l)throw new D;e1)for(let e of this.possibleRightPairs)if(e.getCount()>1&&ne.checkChecksum(t,e))return ne.constructResult(t,e);throw new D}static addOrTally(t,e){if(null==e)return;let r=!1;for(let n of t)if(n.getValue()===e.getValue()){n.incrementCount(),r=!0;break}r||t.push(e)}reset(){this.possibleLeftPairs.length=0,this.possibleRightPairs.length=0}static constructResult(t,e){let r=4537077*t.getValue()+e.getValue(),n=new String(r).toString(),i=new y;for(let t=13-n.length;t>0;t--)i.append("0");i.append(n);let o=0;for(let t=0;t<13;t++){let e=i.charAt(t).charCodeAt(0)-"0".charCodeAt(0);o+=0==(1&t)?3*e:e}o=10-o%10,10===o&&(o=0),i.append(o.toString());let s=t.getFinderPattern().getResultPoints(),a=e.getFinderPattern().getResultPoints();return new x(i.toString(),null,0,[s[0],s[1],a[0],a[1]],U.RSS_14,(new Date).getTime())}static checkChecksum(t,e){let r=(t.getChecksumPortion()+16*e.getChecksumPortion())%79,n=9*t.getFinderPattern().getValue()+e.getFinderPattern().getValue();return n>72&&n--,n>8&&n--,r===n}decodePair(t,e,r,n){try{let i=this.findFinderPattern(t,e),o=this.parseFoundFinderPattern(t,r,e,i),s=null==n?null:n.get(C.NEED_RESULT_POINT_CALLBACK);if(null!=s){let n=(i[0]+i[1])/2;e&&(n=t.getSize()-1-n),s.foundPossibleResultPoint(new it(n,r))}let a=this.decodeDataCharacter(t,o,!0),c=this.decodeDataCharacter(t,o,!1);return new re(1597*a.getValue()+c.getValue(),a.getChecksumPortion()+4*c.getChecksumPortion(),o)}catch(t){return null}}decodeDataCharacter(t,e,r){let n=this.getDataCharacterCounters();for(let t=0;t8&&(r=8);let i=Math.floor(t/2);0==(1&t)?(s[i]=r,c[i]=e-r):(a[i]=r,l[i]=e-r)}this.adjustOddEvenCounts(r,i);let h=0,u=0;for(let t=s.length-1;t>=0;t--)u*=9,u+=s[t],h+=s[t];let d=0,f=0;for(let t=a.length-1;t>=0;t--)d*=9,d+=a[t],f+=a[t];let g=u+3*d;if(r){if(0!=(1&h)||h>12||h<4)throw new D;let t=(12-h)/2,e=ne.OUTSIDE_ODD_WIDEST[t],r=9-e,n=Bt.getRSSvalue(s,e,!1),i=Bt.getRSSvalue(a,r,!0),o=ne.OUTSIDE_EVEN_TOTAL_SUBSET[t],c=ne.OUTSIDE_GSUM[t];return new Ot(n*o+i+c,g)}{if(0!=(1&f)||f>10||f<4)throw new D;let t=(10-f)/2,e=ne.INSIDE_ODD_WIDEST[t],r=9-e,n=Bt.getRSSvalue(s,e,!0),i=Bt.getRSSvalue(a,r,!1),o=ne.INSIDE_ODD_TOTAL_SUBSET[t],c=ne.INSIDE_GSUM[t];return new Ot(i*o+n+c,g)}}findFinderPattern(t,e){let r=this.getDecodeFinderCounters();r[0]=0,r[1]=0,r[2]=0,r[3]=0;let n=t.getSize(),i=!1,o=0;for(;o=0&&i!==t.get(o);)o--;o++;const s=n[0]-o,a=this.getDecodeFinderCounters(),c=new Int32Array(a.length);d.arraycopy(a,0,c,1,a.length-1),c[0]=s;const l=this.parseFinderValue(c,ne.FINDER_PATTERNS);let h=o,u=n[1];return r&&(h=t.getSize()-1-h,u=t.getSize()-1-u),new bt(l,[o,n[1]],h,u,e)}adjustOddEvenCounts(t,e){let r=rt.sum(new Int32Array(this.getOddCounts())),n=rt.sum(new Int32Array(this.getEvenCounts())),i=!1,o=!1,s=!1,a=!1;t?(r>12?o=!0:r<4&&(i=!0),n>12?a=!0:n<4&&(s=!0)):(r>11?o=!0:r<5&&(i=!0),n>10?a=!0:n<4&&(s=!0));let c=r+n-e,l=(1&r)==(t?1:0),h=1==(1&n);if(1===c)if(l){if(h)throw new D;o=!0}else{if(!h)throw new D;a=!0}else if(-1===c)if(l){if(h)throw new D;i=!0}else{if(!h)throw new D;s=!0}else{if(0!==c)throw new D;if(l){if(!h)throw new D;rt.reset()))}}class oe{constructor(t,e,r){this.ecCodewords=t,this.ecBlocks=[e],r&&this.ecBlocks.push(r)}getECCodewords(){return this.ecCodewords}getECBlocks(){return this.ecBlocks}}class se{constructor(t,e){this.count=t,this.dataCodewords=e}getCount(){return this.count}getDataCodewords(){return this.dataCodewords}}class ae{constructor(t,e,r,n,i,o){this.versionNumber=t,this.symbolSizeRows=e,this.symbolSizeColumns=r,this.dataRegionSizeRows=n,this.dataRegionSizeColumns=i,this.ecBlocks=o;let s=0;const a=o.getECCodewords(),c=o.getECBlocks();for(let t of c)s+=t.getCount()*(t.getDataCodewords()+a);this.totalCodewords=s}getVersionNumber(){return this.versionNumber}getSymbolSizeRows(){return this.symbolSizeRows}getSymbolSizeColumns(){return this.symbolSizeColumns}getDataRegionSizeRows(){return this.dataRegionSizeRows}getDataRegionSizeColumns(){return this.dataRegionSizeColumns}getTotalCodewords(){return this.totalCodewords}getECBlocks(){return this.ecBlocks}static getVersionForDimensions(t,e){if(0!=(1&t)||0!=(1&e))throw new E;for(let r of ae.VERSIONS)if(r.symbolSizeRows===t&&r.symbolSizeColumns===e)return r;throw new E}toString(){return""+this.versionNumber}static buildVersions(){return[new ae(1,10,10,8,8,new oe(5,new se(1,3))),new ae(2,12,12,10,10,new oe(7,new se(1,5))),new ae(3,14,14,12,12,new oe(10,new se(1,8))),new ae(4,16,16,14,14,new oe(12,new se(1,12))),new ae(5,18,18,16,16,new oe(14,new se(1,18))),new ae(6,20,20,18,18,new oe(18,new se(1,22))),new ae(7,22,22,20,20,new oe(20,new se(1,30))),new ae(8,24,24,22,22,new oe(24,new se(1,36))),new ae(9,26,26,24,24,new oe(28,new se(1,44))),new ae(10,32,32,14,14,new oe(36,new se(1,62))),new ae(11,36,36,16,16,new oe(42,new se(1,86))),new ae(12,40,40,18,18,new oe(48,new se(1,114))),new ae(13,44,44,20,20,new oe(56,new se(1,144))),new ae(14,48,48,22,22,new oe(68,new se(1,174))),new ae(15,52,52,24,24,new oe(42,new se(2,102))),new ae(16,64,64,14,14,new oe(56,new se(2,140))),new ae(17,72,72,16,16,new oe(36,new se(4,92))),new ae(18,80,80,18,18,new oe(48,new se(4,114))),new ae(19,88,88,20,20,new oe(56,new se(4,144))),new ae(20,96,96,22,22,new oe(68,new se(4,174))),new ae(21,104,104,24,24,new oe(56,new se(6,136))),new ae(22,120,120,18,18,new oe(68,new se(6,175))),new ae(23,132,132,20,20,new oe(62,new se(8,163))),new ae(24,144,144,22,22,new oe(62,new se(8,156),new se(2,155))),new ae(25,8,18,6,16,new oe(7,new se(1,5))),new ae(26,8,32,6,14,new oe(11,new se(1,10))),new ae(27,12,26,10,24,new oe(14,new se(1,16))),new ae(28,12,36,10,16,new oe(18,new se(1,22))),new ae(29,16,36,14,16,new oe(24,new se(1,32))),new ae(30,16,48,14,22,new oe(28,new se(1,49)))]}}ae.VERSIONS=ae.buildVersions();class ce{constructor(t){const e=t.getHeight();if(e<8||e>144||0!=(1&e))throw new E;this.version=ce.readVersion(t),this.mappingBitMatrix=this.extractDataRegion(t),this.readMappingMatrix=new N(this.mappingBitMatrix.getWidth(),this.mappingBitMatrix.getHeight())}getVersion(){return this.version}static readVersion(t){const e=t.getHeight(),r=t.getWidth();return ae.getVersionForDimensions(e,r)}readCodewords(){const t=new Int8Array(this.version.getTotalCodewords());let e=0,r=4,n=0;const i=this.mappingBitMatrix.getHeight(),o=this.mappingBitMatrix.getWidth();let s=!1,a=!1,c=!1,l=!1;do{if(r!==i||0!==n||s)if(r!==i-2||0!==n||0==(3&o)||a)if(r!==i+4||2!==n||0!=(7&o)||c)if(r!==i-2||0!==n||4!=(7&o)||l){do{r=0&&!this.readMappingMatrix.get(n,r)&&(t[e++]=255&this.readUtah(r,n,i,o)),r-=2,n+=2}while(r>=0&&n=0&&n=0);r+=3,n+=1}else t[e++]=255&this.readCorner4(i,o),r-=2,n+=2,l=!0;else t[e++]=255&this.readCorner3(i,o),r-=2,n+=2,c=!0;else t[e++]=255&this.readCorner2(i,o),r-=2,n+=2,a=!0;else t[e++]=255&this.readCorner1(i,o),r-=2,n+=2,s=!0}while(r7?e-1:e;o[n].codewords[i]=t[h++]}if(h!==t.length)throw new c;return o}getNumDataCodewords(){return this.numDataCodewords}getCodewords(){return this.codewords}}class he{constructor(t){this.bytes=t,this.byteOffset=0,this.bitOffset=0}getBitOffset(){return this.bitOffset}getByteOffset(){return this.byteOffset}readBits(t){if(t<1||t>32||t>this.available())throw new c(""+t);let e=0,r=this.bitOffset,n=this.byteOffset;const i=this.bytes;if(r>0){const o=8-r,s=t>8-s<>a,t-=s,r+=s,8===r&&(r=0,n++)}if(t>0){for(;t>=8;)e=e<<8|255&i[n],n++,t-=8;if(t>0){const o=8-t,s=255>>o<>o,r+=t}}return this.bitOffset=r,this.byteOffset=n,e}available(){return 8*(this.bytes.length-this.byteOffset)-this.bitOffset}}!function(t){t[t.PAD_ENCODE=0]="PAD_ENCODE",t[t.ASCII_ENCODE=1]="ASCII_ENCODE",t[t.C40_ENCODE=2]="C40_ENCODE",t[t.TEXT_ENCODE=3]="TEXT_ENCODE",t[t.ANSIX12_ENCODE=4]="ANSIX12_ENCODE",t[t.EDIFACT_ENCODE=5]="EDIFACT_ENCODE",t[t.BASE256_ENCODE=6]="BASE256_ENCODE"}(V||(V={}));class ue{static decode(t){const e=new he(t),r=new y,n=new y,i=new Array;let o=V.ASCII_ENCODE;do{if(o===V.ASCII_ENCODE)o=this.decodeAsciiSegment(e,r,n);else{switch(o){case V.C40_ENCODE:this.decodeC40Segment(e,r);break;case V.TEXT_ENCODE:this.decodeTextSegment(e,r);break;case V.ANSIX12_ENCODE:this.decodeAnsiX12Segment(e,r);break;case V.EDIFACT_ENCODE:this.decodeEdifactSegment(e,r);break;case V.BASE256_ENCODE:this.decodeBase256Segment(e,r,i);break;default:throw new E}o=V.ASCII_ENCODE}}while(o!==V.PAD_ENCODE&&e.available()>0);return n.length()>0&&r.append(n.toString()),new j(t,r.toString(),0===i.length?null:i,null)}static decodeAsciiSegment(t,e,r){let n=!1;do{let i=t.readBits(8);if(0===i)throw new E;if(i<=128)return n&&(i+=128),e.append(String.fromCharCode(i-1)),V.ASCII_ENCODE;if(129===i)return V.PAD_ENCODE;if(i<=229){const t=i-130;t<10&&e.append("0"),e.append(""+t)}else switch(i){case 230:return V.C40_ENCODE;case 231:return V.BASE256_ENCODE;case 232:e.append(String.fromCharCode(29));break;case 233:case 234:case 241:break;case 235:n=!0;break;case 236:e.append("[)>05"),r.insert(0,"");break;case 237:e.append("[)>06"),r.insert(0,"");break;case 238:return V.ANSIX12_ENCODE;case 239:return V.TEXT_ENCODE;case 240:return V.EDIFACT_ENCODE;default:if(254!==i||0!==t.available())throw new E}}while(t.available()>0);return V.ASCII_ENCODE}static decodeC40Segment(t,e){let r=!1;const n=[];let i=0;do{if(8===t.available())return;const o=t.readBits(8);if(254===o)return;this.parseTwoBytes(o,t.readBits(8),n);for(let t=0;t<3;t++){const o=n[t];switch(i){case 0:if(o<3)i=o+1;else{if(!(o0)}static decodeTextSegment(t,e){let r=!1,n=[],i=0;do{if(8===t.available())return;const o=t.readBits(8);if(254===o)return;this.parseTwoBytes(o,t.readBits(8),n);for(let t=0;t<3;t++){const o=n[t];switch(i){case 0:if(o<3)i=o+1;else{if(!(o0)}static decodeAnsiX12Segment(t,e){const r=[];do{if(8===t.available())return;const n=t.readBits(8);if(254===n)return;this.parseTwoBytes(n,t.readBits(8),r);for(let t=0;t<3;t++){const n=r[t];switch(n){case 0:e.append("\r");break;case 1:e.append("*");break;case 2:e.append(">");break;case 3:e.append(" ");break;default:if(n<14)e.append(String.fromCharCode(n+44));else{if(!(n<40))throw new E;e.append(String.fromCharCode(n+51))}}}}while(t.available()>0)}static parseTwoBytes(t,e,r){let n=(t<<8)+e-1,i=Math.floor(n/1600);r[0]=i,n-=1600*i,i=Math.floor(n/40),r[1]=i,r[2]=n-40*i}static decodeEdifactSegment(t,e){do{if(t.available()<=16)return;for(let r=0;r<4;r++){let r=t.readBits(6);if(31===r){const e=8-t.getBitOffset();return void(8!==e&&t.readBits(e))}0==(32&r)&&(r|=64),e.append(String.fromCharCode(r))}}while(t.available()>0)}static decodeBase256Segment(t,e,r){let n=1+t.getByteOffset();const i=this.unrandomize255State(t.readBits(8),n++);let o;if(o=0===i?t.available()/8|0:i<250?i:250*(i-249)+this.unrandomize255State(t.readBits(8),n++),o<0)throw new E;const s=new Uint8Array(o);for(let e=0;e=0?r:r+256}}ue.C40_BASIC_SET_CHARS=["*","*","*"," ","0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"],ue.C40_SHIFT2_SET_CHARS=["!",'"',"#","$","%","&","'","(",")","*","+",",","-",".","/",":",";","<","=",">","?","@","[","\\","]","^","_"],ue.TEXT_BASIC_SET_CHARS=["*","*","*"," ","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],ue.TEXT_SHIFT2_SET_CHARS=ue.C40_SHIFT2_SET_CHARS,ue.TEXT_SHIFT3_SET_CHARS=["`","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","{","|","}","~",String.fromCharCode(127)];class de{constructor(){this.rsDecoder=new tt(q.DATA_MATRIX_FIELD_256)}decode(t){const e=new ce(t),r=e.getVersion(),n=e.readCodewords(),i=le.getDataBlocks(n,r);let o=0;for(let t of i)o+=t.getNumDataCodewords();const s=new Uint8Array(o),a=i.length;for(let t=0;ts&&(l=s,h[0]=e,h[1]=r,h[2]=n,h[3]=i),l>a&&(l=a,h[0]=r,h[1]=n,h[2]=i,h[3]=e),l>c&&(h[0]=n,h[1]=i,h[2]=e,h[3]=r),h}detectSolid2(t){let e=t[0],r=t[1],n=t[2],i=t[3],o=this.transitionsBetween(e,i),s=fe.shiftPoint(r,n,4*(o+1)),a=fe.shiftPoint(n,r,4*(o+1));return this.transitionsBetween(s,e)this.transitionsBetween(a,h)+this.transitionsBetween(c,h)?l:h:l:this.isValid(h)?h:null}shiftToModuleCenter(t){let e=t[0],r=t[1],n=t[2],i=t[3],o=this.transitionsBetween(e,i)+1,s=this.transitionsBetween(n,i)+1,a=fe.shiftPoint(e,r,4*s),c=fe.shiftPoint(n,r,4*o);o=this.transitionsBetween(a,i)+1,s=this.transitionsBetween(c,i)+1,1==(1&o)&&(o+=1),1==(1&s)&&(s+=1);let l,h,u=(e.getX()+r.getX()+n.getX()+i.getX())/4,d=(e.getY()+r.getY()+n.getY()+i.getY())/4;return e=fe.moveAway(e,u,d),r=fe.moveAway(r,u,d),n=fe.moveAway(n,u,d),i=fe.moveAway(i,u,d),a=fe.shiftPoint(e,r,4*s),a=fe.shiftPoint(a,i,4*o),l=fe.shiftPoint(r,e,4*s),l=fe.shiftPoint(l,n,4*o),c=fe.shiftPoint(n,i,4*s),c=fe.shiftPoint(c,r,4*o),h=fe.shiftPoint(i,n,4*s),h=fe.shiftPoint(h,e,4*o),[a,l,c,h]}isValid(t){return t.getX()>=0&&t.getX()0&&t.getY()Math.abs(i-r);if(s){let t=r;r=n,n=t,t=i,i=o,o=t}let a=Math.abs(i-r),c=Math.abs(o-n),l=-a/2,h=n0){if(e===o)break;e+=h,l-=a}}return d}}class ge{constructor(){this.decoder=new de}decode(t,e=null){let r,n;if(null!=e&&e.has(C.PURE_BARCODE)){const e=ge.extractPureBits(t.getBlackMatrix());r=this.decoder.decode(e),n=ge.NO_POINTS}else{const e=new fe(t.getBlackMatrix()).detect();r=this.decoder.decode(e.getBits()),n=e.getPoints()}const i=r.getRawBytes(),o=new x(r.getText(),i,8*i.length,n,U.DATA_MATRIX,d.currentTimeMillis()),s=r.getByteSegments();null!=s&&o.putMetadata(W.BYTE_SEGMENTS,s);const a=r.getECLevel();return null!=a&&o.putMetadata(W.ERROR_CORRECTION_LEVEL,a),o}reset(){}static extractPureBits(t){const e=t.getTopLeftOnBit(),r=t.getBottomRightOnBit();if(null==e||null==r)throw new D;const n=this.moduleSize(e,t);let i=e[1];const o=r[1];let s=e[0];const a=(r[0]-s+1)/n,c=(o-i+1)/n;if(a<=0||c<=0)throw new D;const l=n/2;i+=l,s+=l;const h=new N(a,c);for(let e=0;e=we.FOR_BITS.size)throw new c;return we.FOR_BITS.get(t)}}we.FOR_BITS=new Map,we.FOR_VALUE=new Map,we.L=new we(z.L,"L",1),we.M=new we(z.M,"M",0),we.Q=new we(z.Q,"Q",3),we.H=new we(z.H,"H",2);class me{constructor(t){this.errorCorrectionLevel=we.forBits(t>>3&3),this.dataMask=7&t}static numBitsDiffering(t,e){return m.bitCount(t^e)}static decodeFormatInformation(t,e){const r=me.doDecodeFormatInformation(t,e);return null!==r?r:me.doDecodeFormatInformation(t^me.FORMAT_INFO_MASK_QR,e^me.FORMAT_INFO_MASK_QR)}static doDecodeFormatInformation(t,e){let r=Number.MAX_SAFE_INTEGER,n=0;for(const i of me.FORMAT_INFO_DECODE_LOOKUP){const o=i[0];if(o===t||o===e)return new me(i[1]);let s=me.numBitsDiffering(t,o);s40)throw new c;return Ce.VERSIONS[t-1]}static decodeVersionInformation(t){let e=Number.MAX_SAFE_INTEGER,r=0;for(let n=0;n6&&(e.setRegion(t-11,0,3,6),e.setRegion(0,t-11,6,3)),e}toString(){return""+this.versionNumber}}Ce.VERSION_DECODE_INFO=Int32Array.from([31892,34236,39577,42195,48118,51042,55367,58893,63784,68472,70749,76311,79154,84390,87683,92361,96236,102084,102881,110507,110734,117786,119615,126325,127568,133589,136944,141498,145311,150283,152622,158308,161089,167017]),Ce.VERSIONS=[new Ce(1,new Int32Array(0),new pe(7,new Ae(1,19)),new pe(10,new Ae(1,16)),new pe(13,new Ae(1,13)),new pe(17,new Ae(1,9))),new Ce(2,Int32Array.from([6,18]),new pe(10,new Ae(1,34)),new pe(16,new Ae(1,28)),new pe(22,new Ae(1,22)),new pe(28,new Ae(1,16))),new Ce(3,Int32Array.from([6,22]),new pe(15,new Ae(1,55)),new pe(26,new Ae(1,44)),new pe(18,new Ae(2,17)),new pe(22,new Ae(2,13))),new Ce(4,Int32Array.from([6,26]),new pe(20,new Ae(1,80)),new pe(18,new Ae(2,32)),new pe(26,new Ae(2,24)),new pe(16,new Ae(4,9))),new Ce(5,Int32Array.from([6,30]),new pe(26,new Ae(1,108)),new pe(24,new Ae(2,43)),new pe(18,new Ae(2,15),new Ae(2,16)),new pe(22,new Ae(2,11),new Ae(2,12))),new Ce(6,Int32Array.from([6,34]),new pe(18,new Ae(2,68)),new pe(16,new Ae(4,27)),new pe(24,new Ae(4,19)),new pe(28,new Ae(4,15))),new Ce(7,Int32Array.from([6,22,38]),new pe(20,new Ae(2,78)),new pe(18,new Ae(4,31)),new pe(18,new Ae(2,14),new Ae(4,15)),new pe(26,new Ae(4,13),new Ae(1,14))),new Ce(8,Int32Array.from([6,24,42]),new pe(24,new Ae(2,97)),new pe(22,new Ae(2,38),new Ae(2,39)),new pe(22,new Ae(4,18),new Ae(2,19)),new pe(26,new Ae(4,14),new Ae(2,15))),new Ce(9,Int32Array.from([6,26,46]),new pe(30,new Ae(2,116)),new pe(22,new Ae(3,36),new Ae(2,37)),new pe(20,new Ae(4,16),new Ae(4,17)),new pe(24,new Ae(4,12),new Ae(4,13))),new Ce(10,Int32Array.from([6,28,50]),new pe(18,new Ae(2,68),new Ae(2,69)),new pe(26,new Ae(4,43),new Ae(1,44)),new pe(24,new Ae(6,19),new Ae(2,20)),new pe(28,new Ae(6,15),new Ae(2,16))),new Ce(11,Int32Array.from([6,30,54]),new pe(20,new Ae(4,81)),new pe(30,new Ae(1,50),new Ae(4,51)),new pe(28,new Ae(4,22),new Ae(4,23)),new pe(24,new Ae(3,12),new Ae(8,13))),new Ce(12,Int32Array.from([6,32,58]),new pe(24,new Ae(2,92),new Ae(2,93)),new pe(22,new Ae(6,36),new Ae(2,37)),new pe(26,new Ae(4,20),new Ae(6,21)),new pe(28,new Ae(7,14),new Ae(4,15))),new Ce(13,Int32Array.from([6,34,62]),new pe(26,new Ae(4,107)),new pe(22,new Ae(8,37),new Ae(1,38)),new pe(24,new Ae(8,20),new Ae(4,21)),new pe(22,new Ae(12,11),new Ae(4,12))),new Ce(14,Int32Array.from([6,26,46,66]),new pe(30,new Ae(3,115),new Ae(1,116)),new pe(24,new Ae(4,40),new Ae(5,41)),new pe(20,new Ae(11,16),new Ae(5,17)),new pe(24,new Ae(11,12),new Ae(5,13))),new Ce(15,Int32Array.from([6,26,48,70]),new pe(22,new Ae(5,87),new Ae(1,88)),new pe(24,new Ae(5,41),new Ae(5,42)),new pe(30,new Ae(5,24),new Ae(7,25)),new pe(24,new Ae(11,12),new Ae(7,13))),new Ce(16,Int32Array.from([6,26,50,74]),new pe(24,new Ae(5,98),new Ae(1,99)),new pe(28,new Ae(7,45),new Ae(3,46)),new pe(24,new Ae(15,19),new Ae(2,20)),new pe(30,new Ae(3,15),new Ae(13,16))),new Ce(17,Int32Array.from([6,30,54,78]),new pe(28,new Ae(1,107),new Ae(5,108)),new pe(28,new Ae(10,46),new Ae(1,47)),new pe(28,new Ae(1,22),new Ae(15,23)),new pe(28,new Ae(2,14),new Ae(17,15))),new Ce(18,Int32Array.from([6,30,56,82]),new pe(30,new Ae(5,120),new Ae(1,121)),new pe(26,new Ae(9,43),new Ae(4,44)),new pe(28,new Ae(17,22),new Ae(1,23)),new pe(28,new Ae(2,14),new Ae(19,15))),new Ce(19,Int32Array.from([6,30,58,86]),new pe(28,new Ae(3,113),new Ae(4,114)),new pe(26,new Ae(3,44),new Ae(11,45)),new pe(26,new Ae(17,21),new Ae(4,22)),new pe(26,new Ae(9,13),new Ae(16,14))),new Ce(20,Int32Array.from([6,34,62,90]),new pe(28,new Ae(3,107),new Ae(5,108)),new pe(26,new Ae(3,41),new Ae(13,42)),new pe(30,new Ae(15,24),new Ae(5,25)),new pe(28,new Ae(15,15),new Ae(10,16))),new Ce(21,Int32Array.from([6,28,50,72,94]),new pe(28,new Ae(4,116),new Ae(4,117)),new pe(26,new Ae(17,42)),new pe(28,new Ae(17,22),new Ae(6,23)),new pe(30,new Ae(19,16),new Ae(6,17))),new Ce(22,Int32Array.from([6,26,50,74,98]),new pe(28,new Ae(2,111),new Ae(7,112)),new pe(28,new Ae(17,46)),new pe(30,new Ae(7,24),new Ae(16,25)),new pe(24,new Ae(34,13))),new Ce(23,Int32Array.from([6,30,54,78,102]),new pe(30,new Ae(4,121),new Ae(5,122)),new pe(28,new Ae(4,47),new Ae(14,48)),new pe(30,new Ae(11,24),new Ae(14,25)),new pe(30,new Ae(16,15),new Ae(14,16))),new Ce(24,Int32Array.from([6,28,54,80,106]),new pe(30,new Ae(6,117),new Ae(4,118)),new pe(28,new Ae(6,45),new Ae(14,46)),new pe(30,new Ae(11,24),new Ae(16,25)),new pe(30,new Ae(30,16),new Ae(2,17))),new Ce(25,Int32Array.from([6,32,58,84,110]),new pe(26,new Ae(8,106),new Ae(4,107)),new pe(28,new Ae(8,47),new Ae(13,48)),new pe(30,new Ae(7,24),new Ae(22,25)),new pe(30,new Ae(22,15),new Ae(13,16))),new Ce(26,Int32Array.from([6,30,58,86,114]),new pe(28,new Ae(10,114),new Ae(2,115)),new pe(28,new Ae(19,46),new Ae(4,47)),new pe(28,new Ae(28,22),new Ae(6,23)),new pe(30,new Ae(33,16),new Ae(4,17))),new Ce(27,Int32Array.from([6,34,62,90,118]),new pe(30,new Ae(8,122),new Ae(4,123)),new pe(28,new Ae(22,45),new Ae(3,46)),new pe(30,new Ae(8,23),new Ae(26,24)),new pe(30,new Ae(12,15),new Ae(28,16))),new Ce(28,Int32Array.from([6,26,50,74,98,122]),new pe(30,new Ae(3,117),new Ae(10,118)),new pe(28,new Ae(3,45),new Ae(23,46)),new pe(30,new Ae(4,24),new Ae(31,25)),new pe(30,new Ae(11,15),new Ae(31,16))),new Ce(29,Int32Array.from([6,30,54,78,102,126]),new pe(30,new Ae(7,116),new Ae(7,117)),new pe(28,new Ae(21,45),new Ae(7,46)),new pe(30,new Ae(1,23),new Ae(37,24)),new pe(30,new Ae(19,15),new Ae(26,16))),new Ce(30,Int32Array.from([6,26,52,78,104,130]),new pe(30,new Ae(5,115),new Ae(10,116)),new pe(28,new Ae(19,47),new Ae(10,48)),new pe(30,new Ae(15,24),new Ae(25,25)),new pe(30,new Ae(23,15),new Ae(25,16))),new Ce(31,Int32Array.from([6,30,56,82,108,134]),new pe(30,new Ae(13,115),new Ae(3,116)),new pe(28,new Ae(2,46),new Ae(29,47)),new pe(30,new Ae(42,24),new Ae(1,25)),new pe(30,new Ae(23,15),new Ae(28,16))),new Ce(32,Int32Array.from([6,34,60,86,112,138]),new pe(30,new Ae(17,115)),new pe(28,new Ae(10,46),new Ae(23,47)),new pe(30,new Ae(10,24),new Ae(35,25)),new pe(30,new Ae(19,15),new Ae(35,16))),new Ce(33,Int32Array.from([6,30,58,86,114,142]),new pe(30,new Ae(17,115),new Ae(1,116)),new pe(28,new Ae(14,46),new Ae(21,47)),new pe(30,new Ae(29,24),new Ae(19,25)),new pe(30,new Ae(11,15),new Ae(46,16))),new Ce(34,Int32Array.from([6,34,62,90,118,146]),new pe(30,new Ae(13,115),new Ae(6,116)),new pe(28,new Ae(14,46),new Ae(23,47)),new pe(30,new Ae(44,24),new Ae(7,25)),new pe(30,new Ae(59,16),new Ae(1,17))),new Ce(35,Int32Array.from([6,30,54,78,102,126,150]),new pe(30,new Ae(12,121),new Ae(7,122)),new pe(28,new Ae(12,47),new Ae(26,48)),new pe(30,new Ae(39,24),new Ae(14,25)),new pe(30,new Ae(22,15),new Ae(41,16))),new Ce(36,Int32Array.from([6,24,50,76,102,128,154]),new pe(30,new Ae(6,121),new Ae(14,122)),new pe(28,new Ae(6,47),new Ae(34,48)),new pe(30,new Ae(46,24),new Ae(10,25)),new pe(30,new Ae(2,15),new Ae(64,16))),new Ce(37,Int32Array.from([6,28,54,80,106,132,158]),new pe(30,new Ae(17,122),new Ae(4,123)),new pe(28,new Ae(29,46),new Ae(14,47)),new pe(30,new Ae(49,24),new Ae(10,25)),new pe(30,new Ae(24,15),new Ae(46,16))),new Ce(38,Int32Array.from([6,32,58,84,110,136,162]),new pe(30,new Ae(4,122),new Ae(18,123)),new pe(28,new Ae(13,46),new Ae(32,47)),new pe(30,new Ae(48,24),new Ae(14,25)),new pe(30,new Ae(42,15),new Ae(32,16))),new Ce(39,Int32Array.from([6,26,54,82,110,138,166]),new pe(30,new Ae(20,117),new Ae(4,118)),new pe(28,new Ae(40,47),new Ae(7,48)),new pe(30,new Ae(43,24),new Ae(22,25)),new pe(30,new Ae(10,15),new Ae(67,16))),new Ce(40,Int32Array.from([6,30,58,86,114,142,170]),new pe(30,new Ae(19,118),new Ae(6,119)),new pe(28,new Ae(18,47),new Ae(31,48)),new pe(30,new Ae(34,24),new Ae(34,25)),new pe(30,new Ae(20,15),new Ae(61,16)))],function(t){t[t.DATA_MASK_000=0]="DATA_MASK_000",t[t.DATA_MASK_001=1]="DATA_MASK_001",t[t.DATA_MASK_010=2]="DATA_MASK_010",t[t.DATA_MASK_011=3]="DATA_MASK_011",t[t.DATA_MASK_100=4]="DATA_MASK_100",t[t.DATA_MASK_101=5]="DATA_MASK_101",t[t.DATA_MASK_110=6]="DATA_MASK_110",t[t.DATA_MASK_111=7]="DATA_MASK_111"}(G||(G={}));class Ee{constructor(t,e){this.value=t,this.isMasked=e}unmaskBitMatrix(t,e){for(let r=0;r0==(t+e&1)))],[G.DATA_MASK_001,new Ee(G.DATA_MASK_001,((t,e)=>0==(1&t)))],[G.DATA_MASK_010,new Ee(G.DATA_MASK_010,((t,e)=>e%3==0))],[G.DATA_MASK_011,new Ee(G.DATA_MASK_011,((t,e)=>(t+e)%3==0))],[G.DATA_MASK_100,new Ee(G.DATA_MASK_100,((t,e)=>0==(Math.floor(t/2)+Math.floor(e/3)&1)))],[G.DATA_MASK_101,new Ee(G.DATA_MASK_101,((t,e)=>t*e%6==0))],[G.DATA_MASK_110,new Ee(G.DATA_MASK_110,((t,e)=>t*e%6<3))],[G.DATA_MASK_111,new Ee(G.DATA_MASK_111,((t,e)=>0==(t+e+t*e%3&1)))]]);class Ie{constructor(t){const e=t.getHeight();if(e<21||1!=(3&e))throw new E;this.bitMatrix=t}readFormatInformation(){if(null!==this.parsedFormatInfo&&void 0!==this.parsedFormatInfo)return this.parsedFormatInfo;let t=0;for(let e=0;e<6;e++)t=this.copyBit(e,8,t);t=this.copyBit(7,8,t),t=this.copyBit(8,8,t),t=this.copyBit(8,7,t);for(let e=5;e>=0;e--)t=this.copyBit(8,e,t);const e=this.bitMatrix.getHeight();let r=0;const n=e-7;for(let t=e-1;t>=n;t--)r=this.copyBit(8,t,r);for(let t=e-8;t=0;e--)for(let i=t-9;i>=n;i--)r=this.copyBit(i,e,r);let i=Ce.decodeVersionInformation(r);if(null!==i&&i.getDimensionForVersion()===t)return this.parsedVersion=i,i;r=0;for(let e=5;e>=0;e--)for(let i=t-9;i>=n;i--)r=this.copyBit(e,i,r);if(i=Ce.decodeVersionInformation(r),null!==i&&i.getDimensionForVersion()===t)return this.parsedVersion=i,i;throw new E}copyBit(t,e,r){return(this.isMirror?this.bitMatrix.get(e,t):this.bitMatrix.get(t,e))?r<<1|1:r<<1}readCodewords(){const t=this.readFormatInformation(),e=this.readVersion(),r=Ee.values.get(t.getDataMask()),n=this.bitMatrix.getHeight();r.unmaskBitMatrix(this.bitMatrix,n);const i=e.buildFunctionPattern();let o=!0;const s=new Uint8Array(e.getTotalCodewords());let a=0,c=0,l=0;for(let t=n-1;t>0;t-=2){6===t&&t--;for(let e=0;e=0&&s[h].codewords.length!==l;)h--;h++;const u=l-n.getECCodewordsPerBlock();let d=0;for(let e=0;et.available())throw new E;const n=new Uint8Array(2*r);let i=0;for(;r>0;){const e=t.readBits(13);let o=e/96<<8&4294967295|e%96;o+=o<959?41377:42657,n[i]=o>>8&255,n[i+1]=255&o,i+=2,r--}try{e.append(_.decode(n,T.GB2312))}catch(t){throw new E(t)}}static decodeKanjiSegment(t,e,r){if(13*r>t.available())throw new E;const n=new Uint8Array(2*r);let i=0;for(;r>0;){const e=t.readBits(13);let o=e/192<<8&4294967295|e%192;o+=o<7936?33088:49472,n[i]=o>>8,n[i+1]=o,i+=2,r--}try{e.append(_.decode(n,T.SHIFT_JIS))}catch(t){throw new E(t)}}static decodeByteSegment(t,e,r,n,i,o){if(8*r>t.available())throw new E;const s=new Uint8Array(r);for(let e=0;e=Te.ALPHANUMERIC_CHARS.length)throw new E;return Te.ALPHANUMERIC_CHARS[t]}static decodeAlphanumericSegment(t,e,r,n){const i=e.length();for(;r>1;){if(t.available()<11)throw new E;const n=t.readBits(11);e.append(Te.toAlphaNumericChar(Math.floor(n/45))),e.append(Te.toAlphaNumericChar(n%45)),r-=2}if(1===r){if(t.available()<6)throw new E;e.append(Te.toAlphaNumericChar(t.readBits(6)))}if(n)for(let t=i;t=3;){if(t.available()<10)throw new E;const n=t.readBits(10);if(n>=1e3)throw new E;e.append(Te.toAlphaNumericChar(Math.floor(n/100))),e.append(Te.toAlphaNumericChar(Math.floor(n/10)%10)),e.append(Te.toAlphaNumericChar(n%10)),r-=3}if(2===r){if(t.available()<7)throw new E;const r=t.readBits(7);if(r>=100)throw new E;e.append(Te.toAlphaNumericChar(Math.floor(r/10))),e.append(Te.toAlphaNumericChar(r%10))}else if(1===r){if(t.available()<4)throw new E;const r=t.readBits(4);if(r>=10)throw new E;e.append(Te.toAlphaNumericChar(r))}}static parseECIValue(t){const e=t.readBits(8);if(0==(128&e))return 127&e;if(128==(192&e))return(63&e)<<8&4294967295|t.readBits(8);if(192==(224&e))return(31&e)<<16&4294967295|t.readBits(16);throw new E}}Te.ALPHANUMERIC_CHARS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:",Te.GB2312_SUBSET=1;class ye{constructor(t){this.mirrored=t}isMirrored(){return this.mirrored}applyMirroredCorrection(t){if(!this.mirrored||null===t||t.length<3)return;const e=t[0];t[0]=t[2],t[2]=e}}class Ne{constructor(){this.rsDecoder=new tt(q.QR_CODE_FIELD_256)}decodeBooleanArray(t,e){return this.decodeBitMatrix(N.parseFromBooleanArray(t),e)}decodeBitMatrix(t,e){const r=new Ie(t);let n=null;try{return this.decodeBitMatrixParser(r,e)}catch(t){n=t}try{r.remask(),r.setMirror(!0),r.readVersion(),r.readFormatInformation(),r.mirror();const t=this.decodeBitMatrixParser(r,e);return t.setOther(new ye(!0)),t}catch(t){if(null!==n)throw n;throw t}}decodeBitMatrixParser(t,e){const r=t.readVersion(),n=t.readFormatInformation().getErrorCorrectionLevel(),i=t.readCodewords(),o=Se.getDataBlocks(i,r,n);let s=0;for(const t of o)s+=t.getNumDataCodewords();const a=new Uint8Array(s);let c=0;for(const t of o){const e=t.getCodewords(),r=t.getNumDataCodewords();this.correctErrors(e,r);for(let t=0;t=r)return!1;return!0}crossCheckVertical(t,e,r,n){const i=this.image,o=i.getHeight(),s=this.crossCheckStateCount;s[0]=0,s[1]=0,s[2]=0;let a=t;for(;a>=0&&i.get(e,a)&&s[1]<=r;)s[1]++,a--;if(a<0||s[1]>r)return NaN;for(;a>=0&&!i.get(e,a)&&s[0]<=r;)s[0]++,a--;if(s[0]>r)return NaN;for(a=t+1;ar)return NaN;for(;ar)return NaN;const c=s[0]+s[1]+s[2];return 5*Math.abs(c-n)>=2*n?NaN:this.foundPatternCross(s)?Me.centerFromEnd(s,a):NaN}handlePossibleCenter(t,e,r){const n=t[0]+t[1]+t[2],i=Me.centerFromEnd(t,r),o=this.crossCheckVertical(e,i,2*t[1],n);if(!isNaN(o)){const e=(t[0]+t[1]+t[2])/3;for(const t of this.possibleCenters)if(t.aboutEquals(e,o,i))return t.combineEstimate(o,i,e);const r=new De(i,o,e);this.possibleCenters.push(r),null!==this.resultPointCallback&&void 0!==this.resultPointCallback&&this.resultPointCallback.foundPossibleResultPoint(r)}return null}}class Re extends it{constructor(t,e,r,n){super(t,e),this.estimatedModuleSize=r,this.count=n,void 0===n&&(this.count=1)}getEstimatedModuleSize(){return this.estimatedModuleSize}getCount(){return this.count}aboutEquals(t,e,r){if(Math.abs(e-this.getY())<=t&&Math.abs(r-this.getX())<=t){const e=Math.abs(t-this.estimatedModuleSize);return e<=1||e<=this.estimatedModuleSize}return!1}combineEstimate(t,e,r){const n=this.count+1,i=(this.count*this.getX()+e)/n,o=(this.count*this.getY()+t)/n,s=(this.count*this.estimatedModuleSize+r)/n;return new Re(i,o,s,n)}}class Oe{constructor(t){this.bottomLeft=t[0],this.topLeft=t[1],this.topRight=t[2]}getBottomLeft(){return this.bottomLeft}getTopLeft(){return this.topLeft}getTopRight(){return this.topRight}}class be{constructor(t,e){this.image=t,this.resultPointCallback=e,this.possibleCenters=[],this.crossCheckStateCount=new Int32Array(5),this.resultPointCallback=e}getImage(){return this.image}getPossibleCenters(){return this.possibleCenters}find(t){const e=null!=t&&void 0!==t.get(C.TRY_HARDER),r=null!=t&&void 0!==t.get(C.PURE_BARCODE),n=this.image,i=n.getHeight(),o=n.getWidth();let s=Math.floor(3*i/(4*be.MAX_MODULES));(sc[2]&&(t+=e-c[2]-s,i=o-1)}e=0,c[0]=0,c[1]=0,c[2]=0,c[3]=0,c[4]=0}else c[0]=c[2],c[1]=c[3],c[2]=c[4],c[3]=1,c[4]=0,e=3;else c[++e]++;else c[e]++;be.foundPatternCross(c)&&!0===this.handlePossibleCenter(c,t,o,r)&&(s=c[0],this.hasSkipped&&(a=this.haveMultiplyConfirmedCenters()))}const l=this.selectBestPatterns();return it.orderBestPatterns(l),new Oe(l)}static centerFromEnd(t,e){return e-t[4]-t[3]-t[2]/2}static foundPatternCross(t){let e=0;for(let r=0;r<5;r++){const n=t[r];if(0===n)return!1;e+=n}if(e<7)return!1;const r=e/7,n=r/2;return Math.abs(r-t[0])=o&&e>=o&&s.get(e-o,t-o);)i[2]++,o++;if(t=o&&e>=o&&!s.get(e-o,t-o)&&i[1]<=r;)i[1]++,o++;if(tr)return!1;for(;t>=o&&e>=o&&s.get(e-o,t-o)&&i[0]<=r;)i[0]++,o++;if(i[0]>r)return!1;const a=s.getHeight(),c=s.getWidth();for(o=1;t+o=a||e+o>=c)return!1;for(;t+o=a||e+o>=c||i[3]>=r)return!1;for(;t+o=r)return!1;const l=i[0]+i[1]+i[2]+i[3]+i[4];return Math.abs(l-n)<2*n&&be.foundPatternCross(i)}crossCheckVertical(t,e,r,n){const i=this.image,o=i.getHeight(),s=this.getCrossCheckStateCount();let a=t;for(;a>=0&&i.get(e,a);)s[2]++,a--;if(a<0)return NaN;for(;a>=0&&!i.get(e,a)&&s[1]<=r;)s[1]++,a--;if(a<0||s[1]>r)return NaN;for(;a>=0&&i.get(e,a)&&s[0]<=r;)s[0]++,a--;if(s[0]>r)return NaN;for(a=t+1;a=r)return NaN;for(;a=r)return NaN;const c=s[0]+s[1]+s[2]+s[3]+s[4];return 5*Math.abs(c-n)>=2*n?NaN:be.foundPatternCross(s)?be.centerFromEnd(s,a):NaN}crossCheckHorizontal(t,e,r,n){const i=this.image,o=i.getWidth(),s=this.getCrossCheckStateCount();let a=t;for(;a>=0&&i.get(a,e);)s[2]++,a--;if(a<0)return NaN;for(;a>=0&&!i.get(a,e)&&s[1]<=r;)s[1]++,a--;if(a<0||s[1]>r)return NaN;for(;a>=0&&i.get(a,e)&&s[0]<=r;)s[0]++,a--;if(s[0]>r)return NaN;for(a=t+1;a=r)return NaN;for(;a=r)return NaN;const c=s[0]+s[1]+s[2]+s[3]+s[4];return 5*Math.abs(c-n)>=n?NaN:be.foundPatternCross(s)?be.centerFromEnd(s,a):NaN}handlePossibleCenter(t,e,r,n){const i=t[0]+t[1]+t[2]+t[3]+t[4];let o=be.centerFromEnd(t,r),s=this.crossCheckVertical(e,Math.floor(o),t[2],i);if(!isNaN(s)&&(o=this.crossCheckHorizontal(Math.floor(o),Math.floor(s),t[2],i),!isNaN(o)&&(!n||this.crossCheckDiagonal(Math.floor(s),Math.floor(o),t[2],i)))){const t=i/7;let e=!1;const r=this.possibleCenters;for(let n=0,i=r.length;n=be.CENTER_QUORUM){if(null!=t)return this.hasSkipped=!0,Math.floor((Math.abs(t.getX()-e.getX())-Math.abs(t.getY()-e.getY()))/2);t=e}return 0}haveMultiplyConfirmedCenters(){let t=0,e=0;const r=this.possibleCenters.length;for(const r of this.possibleCenters)r.getCount()>=be.CENTER_QUORUM&&(t++,e+=r.getEstimatedModuleSize());if(t<3)return!1;const n=e/r;let i=0;for(const t of this.possibleCenters)i+=Math.abs(t.getEstimatedModuleSize()-n);return i<=.05*e}selectBestPatterns(){const t=this.possibleCenters.length;if(t<3)throw new D;const e=this.possibleCenters;let r;if(t>3){let n=0,i=0;for(const t of this.possibleCenters){const e=t.getEstimatedModuleSize();n+=e,i+=e*e}r=n/t;let o=Math.sqrt(i/t-r*r);e.sort(((t,e)=>{const n=Math.abs(e.getEstimatedModuleSize()-r),i=Math.abs(t.getEstimatedModuleSize()-r);return ni?1:0}));const s=Math.max(.2*r,o);for(let t=0;t3;t++){const n=e[t];Math.abs(n.getEstimatedModuleSize()-r)>s&&(e.splice(t,1),t--)}}if(e.length>3){let t=0;for(const r of e)t+=r.getEstimatedModuleSize();r=t/e.length,e.sort(((t,e)=>{if(e.getCount()===t.getCount()){const n=Math.abs(e.getEstimatedModuleSize()-r),i=Math.abs(t.getEstimatedModuleSize()-r);return ni?-1:0}return e.getCount()-t.getCount()})),e.splice(3)}return[e[0],e[1],e[2]]}}be.CENTER_QUORUM=2,be.MIN_SKIP=3,be.MAX_MODULES=57;class Be{constructor(t){this.image=t}getImage(){return this.image}getResultPointCallback(){return this.resultPointCallback}detect(t){this.resultPointCallback=null==t?null:t.get(C.NEED_RESULT_POINT_CALLBACK);const e=new be(this.image,this.resultPointCallback).find(t);return this.processFinderPatternInfo(e)}processFinderPatternInfo(t){const e=t.getTopLeft(),r=t.getTopRight(),n=t.getBottomLeft(),i=this.calculateModuleSize(e,r,n);if(i<1)throw new D("No pattern found in proccess finder.");const o=Be.computeDimension(e,r,n,i),s=Ce.getProvisionalVersionForDimension(o),a=s.getDimensionForVersion()-7;let c=null;if(s.getAlignmentPatternCenters().length>0){const t=r.getX()-e.getX()+n.getX(),o=r.getY()-e.getY()+n.getY(),s=1-3/a,l=Math.floor(e.getX()+s*(t-e.getX())),h=Math.floor(e.getY()+s*(o-e.getY()));for(let t=4;t<=16;t<<=1)try{c=this.findAlignmentInRegion(i,l,h,t);break}catch(t){if(!(t instanceof D))throw t}}const l=Be.createTransform(e,r,n,c,o),h=Be.sampleGrid(this.image,l,o);let u;return u=null===c?[n,e,r]:[n,e,r,c],new ot(h,u)}static createTransform(t,e,r,n,i){const o=i-3.5;let s,a,c,l;return null!==n?(s=n.getX(),a=n.getY(),c=o-3,l=c):(s=e.getX()-t.getX()+r.getX(),a=e.getY()-t.getY()+r.getY(),c=o,l=o),lt.quadrilateralToQuadrilateral(3.5,3.5,o,3.5,c,l,3.5,o,t.getX(),t.getY(),e.getX(),e.getY(),s,a,r.getX(),r.getY())}static sampleGrid(t,e,r){return ut.getInstance().sampleGridWithTransform(t,r,r,e)}static computeDimension(t,e,r,n){const i=rt.round(it.distance(t,e)/n),o=rt.round(it.distance(t,r)/n);let s=Math.floor((i+o)/2)+7;switch(3&s){case 0:s++;break;case 2:s--;break;case 3:throw new D("Dimensions could be not found.")}return s}calculateModuleSize(t,e,r){return(this.calculateModuleSizeOneWay(t,e)+this.calculateModuleSizeOneWay(t,r))/2}calculateModuleSizeOneWay(t,e){const r=this.sizeOfBlackWhiteBlackRunBothWays(Math.floor(t.getX()),Math.floor(t.getY()),Math.floor(e.getX()),Math.floor(e.getY())),n=this.sizeOfBlackWhiteBlackRunBothWays(Math.floor(e.getX()),Math.floor(e.getY()),Math.floor(t.getX()),Math.floor(t.getY()));return isNaN(r)?n/7:isNaN(n)?r/7:(r+n)/14}sizeOfBlackWhiteBlackRunBothWays(t,e,r,n){let i=this.sizeOfBlackWhiteBlackRun(t,e,r,n),o=1,s=t-(r-t);s<0?(o=t/(t-s),s=0):s>=this.image.getWidth()&&(o=(this.image.getWidth()-1-t)/(s-t),s=this.image.getWidth()-1);let a=Math.floor(e-(n-e)*o);return o=1,a<0?(o=e/(e-a),a=0):a>=this.image.getHeight()&&(o=(this.image.getHeight()-1-e)/(a-e),a=this.image.getHeight()-1),s=Math.floor(t+(s-t)*o),i+=this.sizeOfBlackWhiteBlackRun(t,e,s,a),i-1}sizeOfBlackWhiteBlackRun(t,e,r,n){const i=Math.abs(n-e)>Math.abs(r-t);if(i){let i=t;t=e,e=i,i=r,r=n,n=i}const o=Math.abs(r-t),s=Math.abs(n-e);let a=-o/2;const c=t0){if(d===n)break;d+=l,a-=o}}return 2===h?rt.distance(r+c,n,t,e):NaN}findAlignmentInRegion(t,e,r,n){const i=Math.floor(n*t),o=Math.max(0,e-i),s=Math.min(this.image.getWidth()-1,e+i);if(s-o<3*t)throw new D("Alignment top exceeds estimated module size.");const a=Math.max(0,r-i),c=Math.min(this.image.getHeight()-1,r+i);if(c-a<3*t)throw new D("Alignment bottom exceeds estimated module size.");return new Me(this.image,o,a,s-o,c-a,t,this.resultPointCallback).find()}}class Le{constructor(){this.decoder=new Ne}getDecoder(){return this.decoder}decode(t,e){let r,n;if(null!=e&&void 0!==e.get(C.PURE_BARCODE)){const i=Le.extractPureBits(t.getBlackMatrix());r=this.decoder.decodeBitMatrix(i,e),n=Le.NO_POINTS}else{const i=new Be(t.getBlackMatrix()).detect(e);r=this.decoder.decodeBitMatrix(i.getBits(),e),n=i.getPoints()}r.getOther()instanceof ye&&r.getOther().applyMirroredCorrection(n);const i=new x(r.getText(),r.getRawBytes(),void 0,n,U.QR_CODE,void 0),o=r.getByteSegments();null!==o&&i.putMetadata(W.BYTE_SEGMENTS,o);const s=r.getECLevel();return null!==s&&i.putMetadata(W.ERROR_CORRECTION_LEVEL,s),r.hasStructuredAppend()&&(i.putMetadata(W.STRUCTURED_APPEND_SEQUENCE,r.getStructuredAppendSequenceNumber()),i.putMetadata(W.STRUCTURED_APPEND_PARITY,r.getStructuredAppendParity())),i}reset(){}static extractPureBits(t){const e=t.getTopLeftOnBit(),r=t.getBottomRightOnBit();if(null===e||null===r)throw new D;const n=this.moduleSize(e,t);let i=e[1],o=r[1],s=e[0],a=r[0];if(s>=a||i>=o)throw new D;if(o-i!=a-s&&(a=s+(o-i),a>=t.getWidth()))throw new D;const c=Math.round((a-s+1)/n),l=Math.round((o-i+1)/n);if(c<=0||l<=0)throw new D;if(l!==c)throw new D;const h=Math.floor(n/2);i+=h,s+=h;const u=s+Math.floor((c-1)*n)-a;if(u>0){if(u>h)throw new D;s-=u}const d=i+Math.floor((l-1)*n)-o;if(d>0){if(d>h)throw new D;i-=d}const f=new N(c,l);for(let e=0;e0;){const s=Fe.findGuardPattern(t,i,--n,r,!1,o,c);if(null==s){n++;break}e=s}s[0]=new it(e[0],n),s[1]=new it(e[1],n),a=!0;break}}let l=n+1;if(a){let n=0,i=Int32Array.from([Math.trunc(s[0].getX()),Math.trunc(s[1].getX())]);for(;lFe.SKIPPED_ROW_COUNT_MAX)break;n++}}l-=n+1,s[2]=new it(i[0],l),s[3]=new it(i[1],l)}return l-n0&&c++o?n-o:o-n;if(c>r)return 1/0;a+=c}return a/i}}Fe.INDEXES_START_PATTERN=Int32Array.from([0,4,1,5]),Fe.INDEXES_STOP_PATTERN=Int32Array.from([6,2,7,3]),Fe.MAX_AVG_VARIANCE=.42,Fe.MAX_INDIVIDUAL_VARIANCE=.8,Fe.START_PATTERN=Int32Array.from([8,1,1,1,1,1,1,3]),Fe.STOP_PATTERN=Int32Array.from([7,1,1,3,1,1,1,2,1]),Fe.MAX_PIXEL_DRIFT=3,Fe.MAX_PATTERN_DRIFT=5,Fe.SKIPPED_ROW_COUNT_MAX=25,Fe.ROW_STEP=5,Fe.BARCODE_MIN_HEIGHT=10;class xe{constructor(t,e){if(0===e.length)throw new c;this.field=t;let r=e.length;if(r>1&&0===e[0]){let t=1;for(;tr.length){let t=e;e=r,r=t}let n=new Int32Array(r.length),i=r.length-e.length;d.arraycopy(r,0,n,0,i);for(let t=i;t=0;e--){let r=this.getCoefficient(e);0!==r&&(r<0?(t.append(" - "),r=-r):t.length()>0&&t.append(" + "),0!==e&&1===r||t.append(r),0!==e&&(1===e?t.append("x"):(t.append("x^"),t.append(e))))}return t.toString()}}class ke{add(t,e){return(t+e)%this.modulus}subtract(t,e){return(this.modulus+t-e)%this.modulus}exp(t){return this.expTable[t]}log(t){if(0===t)throw new c;return this.logTable[t]}inverse(t){if(0===t)throw new K;return this.expTable[this.modulus-this.logTable[t]-1]}multiply(t,e){return 0===t||0===e?0:this.expTable[(this.logTable[t]+this.logTable[e])%(this.modulus-1)]}getSize(){return this.modulus}equals(t){return t===this}}class Ue extends ke{constructor(t,e){super(),this.modulus=t,this.expTable=new Int32Array(t),this.logTable=new Int32Array(t);let r=1;for(let n=0;n0;t--){let r=n.evaluateAt(this.field.exp(t));i[e-t]=r,0!==r&&(o=!0)}if(!o)return 0;let s=this.field.getOne();if(null!=r)for(const e of r){let r=this.field.exp(t.length-1-e),n=new xe(this.field,new Int32Array([this.field.subtract(0,r),1]));s=s.multiply(n)}let a=new xe(this.field,i),c=this.runEuclideanAlgorithm(this.field.buildMonomial(e,1),a,e),l=c[0],u=c[1],d=this.findErrorLocations(l),f=this.findErrorMagnitudes(u,l,d);for(let e=0;e=Math.round(r/2);){let t=n,e=o;if(n=i,o=s,n.isZero())throw h.getChecksumInstance();i=t;let r=this.field.getZero(),a=n.getCoefficient(n.getDegree()),c=this.field.inverse(a);for(;i.getDegree()>=n.getDegree()&&!i.isZero();){let t=i.getDegree()-n.getDegree(),e=this.field.multiply(i.getCoefficient(i.getDegree()),c);r=r.add(this.field.buildMonomial(t,e)),i=i.subtract(n.multiplyByMonomial(t,e))}s=r.multiply(o).subtract(e).negative()}let a=s.getCoefficient(0);if(0===a)throw h.getChecksumInstance();let c=this.field.inverse(a);return[s.multiply(c),i.multiply(c)]}findErrorLocations(t){let e=t.getDegree(),r=new Int32Array(e),n=0;for(let i=1;i0){let e=r?this.topLeft:this.topRight,i=Math.trunc(e.getY()-t);i<0&&(i=0);let s=new it(e.getX(),i);r?n=s:o=s}if(e>0){let t=r?this.bottomLeft:this.bottomRight,n=Math.trunc(t.getY()+e);n>=this.image.getHeight()&&(n=this.image.getHeight()-1);let o=new it(t.getX(),n);r?i=o:s=o}return new Ve(this.image,n,i,o,s)}getMinX(){return this.minX}getMaxX(){return this.maxX}getMinY(){return this.minY}getMaxY(){return this.maxY}getTopLeft(){return this.topLeft}getTopRight(){return this.topRight}getBottomLeft(){return this.bottomLeft}getBottomRight(){return this.bottomRight}}class ze{constructor(t,e,r,n){this.columnCount=t,this.errorCorrectionLevel=n,this.rowCountUpperPart=e,this.rowCountLowerPart=r,this.rowCount=e+r}getColumnCount(){return this.columnCount}getErrorCorrectionLevel(){return this.errorCorrectionLevel}getRowCount(){return this.rowCount}getRowCountUpperPart(){return this.rowCountUpperPart}getRowCountLowerPart(){return this.rowCountLowerPart}}class Ge{constructor(){this.buffer=""}static form(t,e){let r=-1;return t.replace(/%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g,(function(t,n,i,o,s,a){if("%%"===t)return"%";if(void 0===e[++r])return;t=o?parseInt(o.substr(1)):void 0;let c,l=s?parseInt(s.substr(1)):void 0;switch(a){case"s":c=e[r];break;case"c":c=e[r][0];break;case"f":c=parseFloat(e[r]).toFixed(t);break;case"p":c=parseFloat(e[r]).toPrecision(t);break;case"e":c=parseFloat(e[r]).toExponential(t);break;case"x":c=parseInt(e[r]).toString(l||16);break;case"d":c=parseFloat(parseInt(e[r],l||10).toPrecision(t)).toFixed(0)}c="object"==typeof c?JSON.stringify(c):(+c).toString(l);let h=parseInt(i),u=i&&i[0]+""=="0"?"0":" ";for(;c.length=0&&(e=this.codewords[n],null!=e))return e;if(n=this.imageRowToCodewordIndex(t)+r,nr,getValue:()=>n};i.getValue()>t?(t=i.getValue(),e=[],e.push(i.getKey())):i.getValue()===t&&e.push(i.getKey())}return Pe.toIntArray(e)}getConfidence(t){return this.values.get(t)}}class We extends Ye{constructor(t,e){super(t),this._isLeft=e}setRowNumbers(){for(let t of this.getCodewords())null!=t&&t.setRowNumberAsRowIndicatorColumn()}adjustCompleteIndicatorColumnRowNumbers(t){let e=this.getCodewords();this.setRowNumbers(),this.removeIncorrectCodewords(e,t);let r=this.getBoundingBox(),n=this._isLeft?r.getTopLeft():r.getTopRight(),i=this._isLeft?r.getBottomLeft():r.getBottomRight(),o=this.imageRowToCodewordIndex(Math.trunc(n.getY())),s=this.imageRowToCodewordIndex(Math.trunc(i.getY())),a=-1,c=1,l=0;for(let r=o;r=t.getRowCount()||i>r)e[r]=null;else{let t;t=c>2?(c-2)*i:i;let o=t>=r;for(let n=1;n<=t&&!o;n++)o=null!=e[r-n];o?e[r]=null:(a=n.getRowNumber(),l=1)}}}getRowHeights(){let t=this.getBarcodeMetadata();if(null==t)return null;this.adjustIncompleteIndicatorColumnRowNumbers(t);let e=new Int32Array(t.getRowCount());for(let t of this.getCodewords())if(null!=t){let r=t.getRowNumber();if(r>=e.length)continue;e[r]++}return e}adjustIncompleteIndicatorColumnRowNumbers(t){let e=this.getBoundingBox(),r=this._isLeft?e.getTopLeft():e.getTopRight(),n=this._isLeft?e.getBottomLeft():e.getBottomRight(),i=this.imageRowToCodewordIndex(Math.trunc(r.getY())),o=this.imageRowToCodewordIndex(Math.trunc(n.getY())),s=this.getCodewords(),a=-1;for(let e=i;e=t.getRowCount()?s[e]=null:a=r.getRowNumber())}}getBarcodeMetadata(){let t=this.getCodewords(),e=new Xe,r=new Xe,n=new Xe,i=new Xe;for(let o of t){if(null==o)continue;o.setRowNumberAsRowIndicatorColumn();let t=o.getValue()%30,s=o.getRowNumber();switch(this._isLeft||(s+=2),s%3){case 0:r.setValue(3*t+1);break;case 1:i.setValue(t/3),n.setValue(t%3);break;case 2:e.setValue(t+1)}}if(0===e.getValue().length||0===r.getValue().length||0===n.getValue().length||0===i.getValue().length||e.getValue()[0]<1||r.getValue()[0]+n.getValue()[0]Pe.MAX_ROWS_IN_BARCODE)return null;let o=new ze(e.getValue()[0],r.getValue()[0],n.getValue()[0],i.getValue()[0]);return this.removeIncorrectCodewords(t,o),o}removeIncorrectCodewords(t,e){for(let r=0;re.getRowCount())t[r]=null;else switch(this._isLeft||(o+=2),o%3){case 0:3*i+1!==e.getRowCountUpperPart()&&(t[r]=null);break;case 1:Math.trunc(i/3)===e.getErrorCorrectionLevel()&&i%3===e.getRowCountLowerPart()||(t[r]=null);break;case 2:i+1!==e.getColumnCount()&&(t[r]=null)}}}isLeft(){return this._isLeft}toString(){return"IsLeft: "+this._isLeft+"\n"+super.toString()}}class je{constructor(t,e){this.ADJUST_ROW_NUMBER_SKIP=2,this.barcodeMetadata=t,this.barcodeColumnCount=t.getColumnCount(),this.boundingBox=e,this.detectionResultColumns=new Array(this.barcodeColumnCount+2)}getDetectionResultColumns(){this.adjustIndicatorColumnRowNumbers(this.detectionResultColumns[0]),this.adjustIndicatorColumnRowNumbers(this.detectionResultColumns[this.barcodeColumnCount+1]);let t,e=Pe.MAX_CODEWORDS_IN_BARCODE;do{t=e,e=this.adjustRowNumbersAndGetCount()}while(e>0&&e0&&i0&&(s[0]=r[e-1],s[4]=i[e-1],s[5]=o[e-1]),e>1&&(s[8]=r[e-2],s[10]=i[e-2],s[11]=o[e-2]),e>=1;r=1&e,Qe.RATIOS_TABLE[t]||(Qe.RATIOS_TABLE[t]=new Array(Pe.BARS_IN_MODULE)),Qe.RATIOS_TABLE[t][Pe.BARS_IN_MODULE-n-1]=Math.fround(i/Pe.MODULES_IN_CODEWORD)}}this.bSymbolTableReady=!0}static getDecodedValue(t){let e=Qe.getDecodedCodewordValue(Qe.sampleBitCounts(t));return-1!==e?e:Qe.getClosestDecodedValue(t)}static sampleBitCounts(t){let e=rt.sum(t),r=new Int32Array(Pe.BARS_IN_MODULE),n=0,i=0;for(let o=0;o1)for(let n=0;n=n)break}enew Array(Pe.BARS_IN_MODULE)));class Ke{constructor(){this.segmentCount=-1,this.fileSize=-1,this.timestamp=-1,this.checksum=-1}getSegmentIndex(){return this.segmentIndex}setSegmentIndex(t){this.segmentIndex=t}getFileId(){return this.fileId}setFileId(t){this.fileId=t}getOptionalData(){return this.optionalData}setOptionalData(t){this.optionalData=t}isLastSegment(){return this.lastSegment}setLastSegment(t){this.lastSegment=t}getSegmentCount(){return this.segmentCount}setSegmentCount(t){this.segmentCount=t}getSender(){return this.sender||null}setSender(t){this.sender=t}getAddressee(){return this.addressee||null}setAddressee(t){this.addressee=t}getFileName(){return this.fileName}setFileName(t){this.fileName=t}getFileSize(){return this.fileSize}setFileSize(t){this.fileSize=t}getChecksum(){return this.checksum}setChecksum(t){this.checksum=t}getTimestamp(){return this.timestamp}setTimestamp(t){this.timestamp=t}}class qe{static parseLong(t,e=undefined){return parseInt(t,e)}}class Je extends s{}Je.kind="NullPointerException";class $e{writeBytes(t){this.writeBytesOffset(t,0,t.length)}writeBytesOffset(t,e,r){if(null==t)throw new Je;if(e<0||e>t.length||r<0||e+r>t.length||e+r<0)throw new f;if(0!==r)for(let n=0;n0&&this.grow(t)}grow(t){let e=this.buf.length<<1;if(e-t<0&&(e=t),e<0){if(t<0)throw new tr;e=m.MAX_VALUE}this.buf=w.copyOfUint8Array(this.buf,e)}write(t){this.ensureCapacity(this.count+1),this.buf[this.count]=t,this.count+=1}writeBytesOffset(t,e,r){if(e<0||e>t.length||r<0||e+r-t.length>0)throw new f;this.ensureCapacity(this.count+r),d.arraycopy(t,e,this.buf,this.count,r),this.count+=r}writeTo(t){t.writeBytesOffset(this.buf,0,this.count)}reset(){this.count=0}toByteArray(){return w.copyOfUint8Array(this.buf,this.count)}size(){return this.count}toString(t){return t?"string"==typeof t?this.toString_string(t):this.toString_number(t):this.toString_void()}toString_void(){return new String(this.buf).toString()}toString_string(t){return new String(this.buf).toString()}toString_number(t){return new String(this.buf).toString()}close(){}}function rr(){if("undefined"!=typeof window)return window.BigInt||null;if(void 0!==r.g)return r.g.BigInt||null;if("undefined"!=typeof self)return self.BigInt||null;throw new Error("Can't search globals for BigInt!")}let nr;function ir(t){if(void 0===nr&&(nr=rr()),null===nr)throw new Error("BigInt is not supported!");return nr(t)}!function(t){t[t.ALPHA=0]="ALPHA",t[t.LOWER=1]="LOWER",t[t.MIXED=2]="MIXED",t[t.PUNCT=3]="PUNCT",t[t.ALPHA_SHIFT=4]="ALPHA_SHIFT",t[t.PUNCT_SHIFT=5]="PUNCT_SHIFT"}(X||(X={}));class or{static decode(t,e){let r=new y(""),n=I.ISO8859_1;r.enableDecoding(n);let i=1,o=t[i++],s=new Ke;for(;it[0])throw E.getFormatInstance();let n=new Int32Array(or.NUMBER_OF_SEQUENCE_CODEWORDS);for(let r=0;r0){for(let t=0;t<6;++t)o.write(Number(ir(a)>>ir(8*(5-t))));a=0,s=0}}n===e[0]&&r0){for(let t=0;t<6;++t)o.write(Number(ir(a)>>ir(8*(5-t))));a=0,s=0}}}return i.append(_.decode(o.toByteArray(),r)),n}static numericCompaction(t,e,r){let n=0,i=!1,o=new Int32Array(or.MAX_NUMERIC_CODEWORDS);for(;e0&&(r.append(or.decodeBase900toBase10(o,n)),n=0)}return e}static decodeBase900toBase10(t,e){let r=ir(0);for(let n=0;n@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'",or.MIXED_CHARS="0123456789&\r\t,:#-.$/+%*=^",or.EXP900=rr()?function(){let t=[];t[0]=ir(1);let e=ir(900);t[1]=e;for(let r=2;r<16;r++)t[r]=t[r-1]*e;return t}():[],or.NUMBER_OF_SEQUENCE_CODEWORDS=2;class sr{constructor(){}static decode(t,e,r,n,i,o,s){let a,c=new Ve(t,e,r,n,i),l=null,h=null;for(let r=!0;;r=!1){if(null!=e&&(l=sr.getRowIndicatorColumn(t,c,e,!0,o,s)),null!=n&&(h=sr.getRowIndicatorColumn(t,c,n,!1,o,s)),a=sr.merge(l,h),null==a)throw D.getNotFoundInstance();let i=a.getBoundingBox();if(!r||null==i||!(i.getMinY()c.getMaxY()))break;c=i}a.setBoundingBox(c);let u=a.getBarcodeColumnCount()+1;a.setDetectionResultColumn(0,l),a.setDetectionResultColumn(u,h);let d=null!=l;for(let e=1;e<=u;e++){let r,n=d?e:u-e;if(void 0!==a.getDetectionResultColumn(n))continue;r=0===n||n===u?new We(c,0===n):new Ye(c),a.setDetectionResultColumn(n,r);let i=-1,l=i;for(let e=c.getMinY();e<=c.getMaxY();e++){if(i=sr.getStartColumn(a,n,e,d),i<0||i>c.getMaxX()){if(-1===l)continue;i=l}let h=sr.detectCodeword(t,c.getMinX(),c.getMaxX(),d,i,e,o,s);null!=h&&(r.setCodeword(e,h),l=i,o=Math.min(o,h.getWidth()),s=Math.max(s,h.getWidth()))}}return sr.createDecoderResult(a)}static merge(t,e){if(null==t&&null==e)return null;let r=sr.getBarcodeMetadata(t,e);if(null==r)return null;let n=Ve.merge(sr.adjustBoundingBox(t),sr.adjustBoundingBox(e));return new je(r,n)}static adjustBoundingBox(t){if(null==t)return null;let e=t.getRowHeights();if(null==e)return null;let r=sr.getMax(e),n=0;for(let t of e)if(n+=r-t,t>0)break;let i=t.getCodewords();for(let t=0;n>0&&null==i[t];t++)n--;let o=0;for(let t=e.length-1;t>=0&&(o+=r-e[t],!(e[t]>0));t--);for(let t=i.length-1;o>0&&null==i[t];t--)o--;return t.getBoundingBox().addMissingRows(n,o,t.isLeft())}static getMax(t){let e=-1;for(let r of t)e=Math.max(e,r);return e}static getBarcodeMetadata(t,e){let r,n;return null==t||null==(r=t.getBarcodeMetadata())?null==e?null:e.getBarcodeMetadata():null==e||null==(n=e.getBarcodeMetadata())?r:r.getColumnCount()!==n.getColumnCount()&&r.getErrorCorrectionLevel()!==n.getErrorCorrectionLevel()&&r.getRowCount()!==n.getRowCount()?null:r}static getRowIndicatorColumn(t,e,r,n,i,o){let s=new We(e,n);for(let a=0;a<2;a++){let c=0===a?1:-1,l=Math.trunc(Math.trunc(r.getX()));for(let a=Math.trunc(Math.trunc(r.getY()));a<=e.getMaxY()&&a>=e.getMinY();a+=c){let e=sr.detectCodeword(t,0,t.getWidth(),n,l,a,i,o);null!=e&&(s.setCodeword(a,e),l=n?e.getStartX():e.getEndX())}}return s}static adjustCodewordCount(t,e){let r=e[0][1],n=r.getValue(),i=t.getBarcodeColumnCount()*t.getBarcodeRowCount()-sr.getNumberOfECCodeWords(t.getBarcodeECLevel());if(0===n.length){if(i<1||i>Pe.MAX_CODEWORDS_IN_BARCODE)throw D.getNotFoundInstance();r.setValue(i)}else n[0]!==i&&r.setValue(i)}static createDecoderResult(t){let e=sr.createBarcodeMatrix(t);sr.adjustCodewordCount(t,e);let r=new Array,n=new Int32Array(t.getBarcodeRowCount()*t.getBarcodeColumnCount()),i=[],o=new Array;for(let s=0;s0;){for(let t=0;tnew Array(t.getBarcodeColumnCount()+2)));for(let t=0;t=0){if(n>=e.length)continue;e[n][r].setValue(t.getValue())}}r++}return e}static isValidBarcodeColumn(t,e){return e>=0&&e<=t.getBarcodeColumnCount()+1}static getStartColumn(t,e,r,n){let i=n?1:-1,o=null;if(sr.isValidBarcodeColumn(t,e-i)&&(o=t.getDetectionResultColumn(e-i).getCodeword(r)),null!=o)return n?o.getEndX():o.getStartX();if(o=t.getDetectionResultColumn(e).getCodewordNearby(r),null!=o)return n?o.getStartX():o.getEndX();if(sr.isValidBarcodeColumn(t,e-i)&&(o=t.getDetectionResultColumn(e-i).getCodewordNearby(r)),null!=o)return n?o.getEndX():o.getStartX();let s=0;for(;sr.isValidBarcodeColumn(t,e-i);){e-=i;for(let r of t.getDetectionResultColumn(e).getCodewords())if(null!=r)return(n?r.getEndX():r.getStartX())+i*s*(r.getEndX()-r.getStartX());s++}return n?t.getBoundingBox().getMinX():t.getBoundingBox().getMaxX()}static detectCodeword(t,e,r,n,i,o,s,a){i=sr.adjustCodewordStartColumn(t,e,r,n,i,o);let c,l=sr.getModuleBitCount(t,e,r,n,i,o);if(null==l)return null;let h=rt.sum(l);if(n)c=i+h;else{for(let t=0;t=e)&&c=e:ssr.CODEWORD_SKEW_SIZE)return i;s+=a}a=-a,n=!n}return s}static checkCodewordSkew(t,e,r){return e-sr.CODEWORD_SKEW_SIZE<=t&&t<=r+sr.CODEWORD_SKEW_SIZE}static decodeCodewords(t,e,r){if(0===t.length)throw E.getFormatInstance();let n=1<r/2+sr.MAX_ERRORS||r<0||r>sr.MAX_EC_CODEWORDS)throw h.getChecksumInstance();return sr.errorCorrection.decode(t,r,e)}static verifyCodewordCount(t,e){if(t.length<4)throw E.getFormatInstance();let r=t[0];if(r>t.length)throw E.getFormatInstance();if(0===r){if(!(e>=1;return e}static getCodewordBucketNumber(t){return t instanceof Int32Array?this.getCodewordBucketNumber_Int32Array(t):this.getCodewordBucketNumber_number(t)}static getCodewordBucketNumber_number(t){return sr.getCodewordBucketNumber(sr.getBitCountForCodeword(t))}static getCodewordBucketNumber_Int32Array(t){return(t[0]-t[2]+t[4]-t[6]+9)%9}static toString(t){let e=new Ge;for(let r=0;rt))}static getMaxWidth(t,e){return null==t||null==e?0:Math.trunc(Math.abs(t.getX()-e.getX()))}static getMinWidth(t,e){return null==t||null==e?m.MAX_VALUE:Math.trunc(Math.abs(t.getX()-e.getX()))}static getMaxCodewordWidth(t){return Math.floor(Math.max(Math.max(ar.getMaxWidth(t[0],t[4]),ar.getMaxWidth(t[6],t[2])*Pe.MODULES_IN_CODEWORD/Pe.MODULES_IN_STOP_PATTERN),Math.max(ar.getMaxWidth(t[1],t[5]),ar.getMaxWidth(t[7],t[3])*Pe.MODULES_IN_CODEWORD/Pe.MODULES_IN_STOP_PATTERN)))}static getMinCodewordWidth(t){return Math.floor(Math.min(Math.min(ar.getMinWidth(t[0],t[4]),ar.getMinWidth(t[6],t[2])*Pe.MODULES_IN_CODEWORD/Pe.MODULES_IN_STOP_PATTERN),Math.min(ar.getMinWidth(t[1],t[5]),ar.getMinWidth(t[7],t[3])*Pe.MODULES_IN_CODEWORD/Pe.MODULES_IN_STOP_PATTERN)))}reset(){}}class cr extends s{}cr.kind="ReaderException";class lr{constructor(t,e){this.verbose=!0===t,e&&this.setHints(e)}decode(t,e){return e&&this.setHints(e),this.decodeInternal(t)}decodeWithState(t){return null!==this.readers&&void 0!==this.readers||this.setHints(null),this.decodeInternal(t)}setHints(t){this.hints=t;const r=!e(t)&&!0===t.get(C.TRY_HARDER),n=e(t)?null:t.get(C.POSSIBLE_FORMATS),i=new Array;if(!e(n)){const e=n.some((t=>t===U.UPC_A||t===U.UPC_E||t===U.EAN_13||t===U.EAN_8||t===U.CODABAR||t===U.CODE_39||t===U.CODE_93||t===U.CODE_128||t===U.ITF||t===U.RSS_14||t===U.RSS_EXPANDED));e&&!r&&i.push(new ie(t,this.verbose)),n.includes(U.QR_CODE)&&i.push(new Le),n.includes(U.DATA_MATRIX)&&i.push(new ge),n.includes(U.AZTEC)&&i.push(new gt),n.includes(U.PDF_417)&&i.push(new ar),e&&r&&i.push(new ie(t,this.verbose))}0===i.length&&(r||i.push(new ie(t,this.verbose)),i.push(new Le),i.push(new ge),i.push(new gt),i.push(new ar),r&&i.push(new ie(t,this.verbose))),this.readers=i}reset(){if(null!==this.readers)for(const t of this.readers)t.reset()}decodeInternal(t){if(null===this.readers)throw new cr("No readers where selected, nothing can be read.");for(const e of this.readers)try{return e.decode(t,this.hints)}catch(t){if(t instanceof cr)continue}throw new D("No MultiFormat Readers were able to detect the code.")}}var hr;!function(t){t[t.ERROR_CORRECTION=0]="ERROR_CORRECTION",t[t.CHARACTER_SET=1]="CHARACTER_SET",t[t.DATA_MATRIX_SHAPE=2]="DATA_MATRIX_SHAPE",t[t.MIN_SIZE=3]="MIN_SIZE",t[t.MAX_SIZE=4]="MAX_SIZE",t[t.MARGIN=5]="MARGIN",t[t.PDF417_COMPACT=6]="PDF417_COMPACT",t[t.PDF417_COMPACTION=7]="PDF417_COMPACTION",t[t.PDF417_DIMENSIONS=8]="PDF417_DIMENSIONS",t[t.AZTEC_LAYERS=9]="AZTEC_LAYERS",t[t.QR_VERSION=10]="QR_VERSION"}(hr||(hr={}));var ur=hr;class dr{constructor(t){this.field=t,this.cachedGenerators=[],this.cachedGenerators.push(new Q(t,Int32Array.from([1])))}buildGenerator(t){const e=this.cachedGenerators;if(t>=e.length){let r=e[e.length-1];const n=this.field;for(let i=e.length;i<=t;i++){const t=r.multiply(new Q(n,Int32Array.from([1,n.exp(i-1+n.getGeneratorBase())])));e.push(t),r=t}}return e[t]}encode(t,e){if(0===e)throw new c("No error correction bytes");const r=t.length-e;if(r<=0)throw new c("No data bytes provided");const n=this.buildGenerator(e),i=new Int32Array(r);d.arraycopy(t,0,i,0,r);let o=new Q(this.field,i);o=o.multiplyByMonomial(e,1);const s=o.divide(n)[1].getCoefficients(),a=e-s.length;for(let e=0;e=5&&(r+=fr.N1+(n-5)),n=1,s=i)}n>=5&&(r+=fr.N1+(n-5))}return r}}fr.N1=3,fr.N2=3,fr.N3=40,fr.N4=10;class gr{constructor(t,e){this.width=t,this.height=e;const r=new Array(e);for(let n=0;n!==e;n++)r[n]=new Uint8Array(t);this.bytes=r}getHeight(){return this.height}getWidth(){return this.width}get(t,e){return this.bytes[e][t]}getArray(){return this.bytes}setNumber(t,e,r){this.bytes[e][t]=r}setBoolean(t,e,r){this.bytes[e][t]=r?1:0}clear(t){for(const e of this.bytes)w.fill(e,t)}equals(t){if(!(t instanceof gr))return!1;const e=t;if(this.width!==e.width)return!1;if(this.height!==e.height)return!1;for(let t=0,r=this.height;t>\n"),t.toString()}setMode(t){this.mode=t}setECLevel(t){this.ecLevel=t}setVersion(t){this.version=t}setMaskPattern(t){this.maskPattern=t}setMatrix(t){this.matrix=t}static isValidMaskPattern(t){return t>=0&&t0;){for(6===o&&(o-=1);s>=0&&s=r;)t^=e<=0)for(let t=0;t!==r;t++){const r=n[t];r>=0&&pr.isEmpty(e.get(r,i))&&pr.embedPositionAdjustmentPattern(r-2,i-2,e)}}}}pr.POSITION_DETECTION_PATTERN=Array.from([Int32Array.from([1,1,1,1,1,1,1]),Int32Array.from([1,0,0,0,0,0,1]),Int32Array.from([1,0,1,1,1,0,1]),Int32Array.from([1,0,1,1,1,0,1]),Int32Array.from([1,0,1,1,1,0,1]),Int32Array.from([1,0,0,0,0,0,1]),Int32Array.from([1,1,1,1,1,1,1])]),pr.POSITION_ADJUSTMENT_PATTERN=Array.from([Int32Array.from([1,1,1,1,1]),Int32Array.from([1,0,0,0,1]),Int32Array.from([1,0,1,0,1]),Int32Array.from([1,0,0,0,1]),Int32Array.from([1,1,1,1,1])]),pr.POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE=Array.from([Int32Array.from([-1,-1,-1,-1,-1,-1,-1]),Int32Array.from([6,18,-1,-1,-1,-1,-1]),Int32Array.from([6,22,-1,-1,-1,-1,-1]),Int32Array.from([6,26,-1,-1,-1,-1,-1]),Int32Array.from([6,30,-1,-1,-1,-1,-1]),Int32Array.from([6,34,-1,-1,-1,-1,-1]),Int32Array.from([6,22,38,-1,-1,-1,-1]),Int32Array.from([6,24,42,-1,-1,-1,-1]),Int32Array.from([6,26,46,-1,-1,-1,-1]),Int32Array.from([6,28,50,-1,-1,-1,-1]),Int32Array.from([6,30,54,-1,-1,-1,-1]),Int32Array.from([6,32,58,-1,-1,-1,-1]),Int32Array.from([6,34,62,-1,-1,-1,-1]),Int32Array.from([6,26,46,66,-1,-1,-1]),Int32Array.from([6,26,48,70,-1,-1,-1]),Int32Array.from([6,26,50,74,-1,-1,-1]),Int32Array.from([6,30,54,78,-1,-1,-1]),Int32Array.from([6,30,56,82,-1,-1,-1]),Int32Array.from([6,30,58,86,-1,-1,-1]),Int32Array.from([6,34,62,90,-1,-1,-1]),Int32Array.from([6,28,50,72,94,-1,-1]),Int32Array.from([6,26,50,74,98,-1,-1]),Int32Array.from([6,30,54,78,102,-1,-1]),Int32Array.from([6,28,54,80,106,-1,-1]),Int32Array.from([6,32,58,84,110,-1,-1]),Int32Array.from([6,30,58,86,114,-1,-1]),Int32Array.from([6,34,62,90,118,-1,-1]),Int32Array.from([6,26,50,74,98,122,-1]),Int32Array.from([6,30,54,78,102,126,-1]),Int32Array.from([6,26,52,78,104,130,-1]),Int32Array.from([6,30,56,82,108,134,-1]),Int32Array.from([6,34,60,86,112,138,-1]),Int32Array.from([6,30,58,86,114,142,-1]),Int32Array.from([6,34,62,90,118,146,-1]),Int32Array.from([6,30,54,78,102,126,150]),Int32Array.from([6,24,50,76,102,128,154]),Int32Array.from([6,28,54,80,106,132,158]),Int32Array.from([6,32,58,84,110,136,162]),Int32Array.from([6,26,54,82,110,138,166]),Int32Array.from([6,30,58,86,114,142,170])]),pr.TYPE_INFO_COORDINATES=Array.from([Int32Array.from([8,0]),Int32Array.from([8,1]),Int32Array.from([8,2]),Int32Array.from([8,3]),Int32Array.from([8,4]),Int32Array.from([8,5]),Int32Array.from([8,7]),Int32Array.from([8,8]),Int32Array.from([7,8]),Int32Array.from([5,8]),Int32Array.from([4,8]),Int32Array.from([3,8]),Int32Array.from([2,8]),Int32Array.from([1,8]),Int32Array.from([0,8])]),pr.VERSION_INFO_POLY=7973,pr.TYPE_INFO_POLY=1335,pr.TYPE_INFO_MASK_PATTERN=21522;class Ar{constructor(t,e){this.dataBytes=t,this.errorCorrectionBytes=e}getDataBytes(){return this.dataBytes}getErrorCorrectionBytes(){return this.errorCorrectionBytes}}class Cr{constructor(){}static calculateMaskPenalty(t){return fr.applyMaskPenaltyRule1(t)+fr.applyMaskPenaltyRule2(t)+fr.applyMaskPenaltyRule3(t)+fr.applyMaskPenaltyRule4(t)}static encode(t,e,r=null){let n=Cr.DEFAULT_BYTE_MODE_ENCODING;const i=null!==r&&void 0!==r.get(ur.CHARACTER_SET);i&&(n=r.get(ur.CHARACTER_SET).toString());const o=this.chooseMode(t,n),s=new p;if(o===_e.BYTE&&(i||Cr.DEFAULT_BYTE_MODE_ENCODING!==n)){const t=I.getCharacterSetECIByName(n);void 0!==t&&this.appendECI(t,s)}this.appendModeInfo(o,s);const a=new p;let c;if(this.appendBytes(t,o,a,n),null!==r&&void 0!==r.get(ur.QR_VERSION)){const t=Number.parseInt(r.get(ur.QR_VERSION).toString(),10);c=Ce.getVersionForNumber(t);const n=this.calculateBitsNeeded(o,s,a,c);if(!this.willFit(n,c,e))throw new mr("Data too big for requested version")}else c=this.recommendVersion(e,o,s,a);const l=new p;l.appendBitArray(s);const h=o===_e.BYTE?a.getSizeInBytes():t.length;this.appendLengthInfo(h,c,o,l),l.appendBitArray(a);const u=c.getECBlocksForLevel(e),d=c.getTotalCodewords()-u.getTotalECCodewords();this.terminateBits(d,l);const f=this.interleaveWithECBytes(l,c.getTotalCodewords(),d,u.getNumBlocks()),g=new wr;g.setECLevel(e),g.setMode(o),g.setVersion(c);const w=c.getDimensionForVersion(),m=new gr(w,w),A=this.chooseMaskPattern(f,e,c,m);return g.setMaskPattern(A),pr.buildMatrix(f,e,c,A,m),g.setMatrix(m),g}static recommendVersion(t,e,r,n){const i=this.calculateBitsNeeded(e,r,n,Ce.getVersionForNumber(1)),o=this.chooseVersion(i,t),s=this.calculateBitsNeeded(e,r,n,o);return this.chooseVersion(s,t)}static calculateBitsNeeded(t,e,r,n){return e.getSize()+t.getCharacterCountBits(n)+r.getSize()}static getAlphanumericCode(t){return t159)&&(r<224||r>235))return!1}return!0}static chooseMaskPattern(t,e,r,n){let i=Number.MAX_SAFE_INTEGER,o=-1;for(let s=0;s=(t+7)/8}static terminateBits(t,e){const r=8*t;if(e.getSize()>r)throw new mr("data bits cannot fit in the QR Code"+e.getSize()+" > "+r);for(let t=0;t<4&&e.getSize()0)for(let t=n;t<8;t++)e.appendBit(!1);const i=t-e.getSizeInBytes();for(let t=0;t=r)throw new mr("Block ID too large");const s=t%r,a=r-s,c=Math.floor(t/r),l=c+1,h=Math.floor(e/r),u=h+1,d=c-h,f=l-u;if(d!==f)throw new mr("EC bytes mismatch");if(r!==a+s)throw new mr("RS blocks mismatch");if(t!==(h+d)*a+(u+f)*s)throw new mr("Total bytes mismatch");n=1<=0&&e<=9}static appendNumericBytes(t,e){const r=t.length;let n=0;for(;n=33088&&n<=40956?i=n-33088:n>=57408&&n<=60351&&(i=n-49472),-1===i)throw new mr("Invalid byte sequence");const o=192*(i>>8)+(255&i);e.appendBits(o,13)}}static appendECI(t,e){e.appendBits(_e.ECI.getBits(),4),e.appendBits(t.getValue(),8)}}Cr.ALPHANUMERIC_TABLE=Int32Array.from([-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,36,-1,-1,-1,37,38,-1,-1,-1,-1,39,40,-1,41,42,43,0,1,2,3,4,5,6,7,8,9,44,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1]),Cr.DEFAULT_BYTE_MODE_ENCODING=I.UTF8.getName();class Er{write(t,e,r,n=null){if(0===t.length)throw new c("Found empty contents");if(e<0||r<0)throw new c("Requested dimensions are too small: "+e+"x"+r);let i=we.L,o=Er.QUIET_ZONE_SIZE;null!==n&&(void 0!==n.get(ur.ERROR_CORRECTION)&&(i=we.fromString(n.get(ur.ERROR_CORRECTION).toString())),void 0!==n.get(ur.MARGIN)&&(o=Number.parseInt(n.get(ur.MARGIN).toString(),10)));const s=Cr.encode(t,i,n);return this.renderResult(s,e,r,o)}writeToDom(t,e,r,n,i=null){"string"==typeof t&&(t=document.querySelector(t));const o=this.write(e,r,n,i);t&&t.appendChild(o)}renderResult(t,e,r,n){const i=t.getMatrix();if(null===i)throw new $;const o=i.getWidth(),s=i.getHeight(),a=o+2*n,c=s+2*n,l=Math.max(e,a),h=Math.max(r,c),u=Math.min(Math.floor(l/a),Math.floor(h/c)),d=Math.floor((l-o*u)/2),f=Math.floor((h-s*u)/2),g=this.createSVGElement(l,h);for(let t=0,e=f;te||i+s>r)throw new c("Crop rectangle does not fit within image data.");a&&this.reverseHorizontal(o,s)}getRow(t,e){if(t<0||t>=this.getHeight())throw new c("Requested row is outside the image: "+t);const r=this.getWidth();(null==e||e.length>16&255,o=r>>7&510,s=255&r;i[e]=(n+o+s)/4&255}this.luminances=i}else this.luminances=t;if(void 0===n&&(this.dataWidth=e),void 0===i&&(this.dataHeight=r),void 0===o&&(this.left=0),void 0===s&&(this.top=0),this.left+e>this.dataWidth||this.top+r>this.dataHeight)throw new c("Crop rectangle does not fit within image data.")}getRow(t,e){if(t<0||t>=this.getHeight())throw new c("Requested row is outside the image: "+t);const r=this.getWidth();(null==e||e.length"}}class Or extends Rr{constructor(t,e,r){super(t,0,0),this.binaryShiftStart=e,this.binaryShiftByteCount=r}appendTo(t,e){for(let r=0;r62?t.appendBits(this.binaryShiftByteCount-31,16):0===r?t.appendBits(Math.min(this.binaryShiftByteCount,31),5):t.appendBits(this.binaryShiftByteCount-31,5)),t.appendBits(e[this.binaryShiftStart+r],8)}addBinaryShift(t,e){return new Or(this,t,e)}toString(){return"<"+this.binaryShiftStart+"::"+(this.binaryShiftStart+this.binaryShiftByteCount-1)+">"}}function br(t,e,r){return new Rr(t,e,r)}const Br=["UPPER","LOWER","DIGIT","MIXED","PUNCT"],Lr=0,Pr=1,vr=2,Fr=3,xr=4,kr=new Rr(null,0,0),Ur=[Int32Array.from([0,327708,327710,327709,656318]),Int32Array.from([590318,0,327710,327709,656318]),Int32Array.from([262158,590300,0,590301,932798]),Int32Array.from([327709,327708,656318,0,327710]),Int32Array.from([327711,656380,656382,656381,0])];const Hr=function(t){for(let e of t)w.fill(e,-1);return t[Lr][xr]=0,t[Pr][xr]=0,t[Pr][Lr]=28,t[Fr][xr]=0,t[vr][xr]=0,t[vr][Lr]=15,t}(w.createInt32Array(6,6));class Vr{constructor(t,e,r,n){this.token=t,this.mode=e,this.binaryShiftByteCount=r,this.bitCount=n}getMode(){return this.mode}getToken(){return this.token}getBinaryShiftByteCount(){return this.binaryShiftByteCount}getBitCount(){return this.bitCount}latchAndAppend(t,e){let r=this.bitCount,n=this.token;if(t!==this.mode){let e=Ur[this.mode][t];n=br(n,65535&e,e>>16),r+=e>>16}let i=t===vr?4:5;return n=br(n,e,i),new Vr(n,t,0,r+i)}shiftAndAppend(t,e){let r=this.token,n=this.mode===vr?4:5;return r=br(r,Hr[this.mode][t],n),r=br(r,e,5),new Vr(r,this.mode,0,this.bitCount+n+5)}addBinaryShiftChar(t){let e=this.token,r=this.mode,n=this.bitCount;if(this.mode===xr||this.mode===vr){let t=Ur[r][Lr];e=br(e,65535&t,t>>16),n+=t>>16,r=Lr}let i=0===this.binaryShiftByteCount||31===this.binaryShiftByteCount?18:62===this.binaryShiftByteCount?9:8,o=new Vr(e,r,this.binaryShiftByteCount+1,n+i);return 2078===o.binaryShiftByteCount&&(o=o.endBinaryShift(t+1)),o}endBinaryShift(t){if(0===this.binaryShiftByteCount)return this;let e=this.token;return e=function(t,e,r){return new Or(t,e,r)}(e,t-this.binaryShiftByteCount,this.binaryShiftByteCount),new Vr(e,this.mode,0,this.bitCount)}isBetterThanOrEqualTo(t){let e=this.bitCount+(Ur[this.mode][t.mode]>>16);return this.binaryShiftByteCountt.binaryShiftByteCount&&t.binaryShiftByteCount>0&&(e+=10),e<=t.bitCount}toBitArray(t){let e=[];for(let r=this.endBinaryShift(t.length).token;null!==r;r=r.getPrevious())e.unshift(r);let r=new p;for(const n of e)n.appendTo(r,t);return r}toString(){return T.format("%s bits=%d bytes=%d",Br[this.mode],this.bitCount,this.binaryShiftByteCount)}static calculateBinaryShiftCost(t){return t.binaryShiftByteCount>62?21:t.binaryShiftByteCount>31?20:t.binaryShiftByteCount>0?10:0}}Vr.INITIAL_STATE=new Vr(kr,Lr,0,0);const zr=function(t){const e=T.getCharCode(" "),r=T.getCharCode("."),n=T.getCharCode(",");t[Lr][e]=1;const i=T.getCharCode("Z"),o=T.getCharCode("A");for(let e=o;e<=i;e++)t[Lr][e]=e-o+2;t[Pr][e]=1;const s=T.getCharCode("z"),a=T.getCharCode("a");for(let e=a;e<=s;e++)t[Pr][e]=e-a+2;t[vr][e]=1;const c=T.getCharCode("9"),l=T.getCharCode("0");for(let e=l;e<=c;e++)t[vr][e]=e-l+2;t[vr][n]=12,t[vr][r]=13;const h=["\0"," ","","","","","","","","\b","\t","\n","\v","\f","\r","","","","","","@","\\","^","_","`","|","~",""];for(let e=0;e","?","[","]","{","}"];for(let e=0;e0&&(t[xr][T.getCharCode(u[e])]=e);return t}(w.createInt32Array(5,256));class Gr{constructor(t){this.text=t}encode(){const t=T.getCharCode(" "),e=T.getCharCode("\n");let r=Dr.singletonList(Vr.INITIAL_STATE);for(let n=0;n0?(r=Gr.updateStateListForPair(r,n,i),n++):r=this.updateStateListForChar(r,n)}return Dr.min(r,((t,e)=>t.getBitCount()-e.getBitCount())).toBitArray(this.text)}updateStateListForChar(t,e){const r=[];for(let n of t)this.updateStateForChar(n,e,r);return Gr.simplifyStates(r)}updateStateForChar(t,e,r){let n=255&this.text[e],i=zr[t.getMode()][n]>0,o=null;for(let s=0;s<=xr;s++){let a=zr[s][n];if(a>0){if(null==o&&(o=t.endBinaryShift(e)),!i||s===t.getMode()||s===vr){const t=o.latchAndAppend(s,a);r.push(t)}if(!i&&Hr[t.getMode()][s]>=0){const t=o.shiftAndAppend(s,a);r.push(t)}}}if(t.getBinaryShiftByteCount()>0||0===zr[t.getMode()][n]){let n=t.addBinaryShiftChar(e);r.push(n)}}static updateStateListForPair(t,e,r){const n=[];for(let i of t)this.updateStateForPair(i,e,r,n);return this.simplifyStates(n)}static updateStateForPair(t,e,r,n){let i=t.endBinaryShift(e);if(n.push(i.latchAndAppend(xr,r)),t.getMode()!==xr&&n.push(i.shiftAndAppend(xr,r)),3===r||4===r){let t=i.latchAndAppend(vr,16-r).latchAndAppend(vr,1);n.push(t)}if(t.getBinaryShiftByteCount()>0){let r=t.addBinaryShiftChar(e).addBinaryShiftChar(e+1);n.push(r)}}static simplifyStates(t){let e=[];for(const r of t){let t=!0;for(const n of e){if(n.isBetterThanOrEqualTo(r)){t=!1;break}r.isBetterThanOrEqualTo(n)&&(e=e.filter((t=>t!==n)))}t&&e.push(r)}return e}}class Yr{constructor(){}static encodeBytes(t){return Yr.encode(t,Yr.DEFAULT_EC_PERCENT,Yr.DEFAULT_AZTEC_LAYERS)}static encode(t,e,r){let n,i,o,s,a,l=new Gr(t).encode(),h=m.truncDivision(l.getSize()*e,100)+11,u=l.getSize()+h;if(r!==Yr.DEFAULT_AZTEC_LAYERS){if(n=r<0,i=Math.abs(r),i>(n?Yr.MAX_NB_BITS_COMPACT:Yr.MAX_NB_BITS))throw new c(T.format("Illegal value %s for layers",r));o=Yr.totalBitsInLayer(i,n),s=Yr.WORD_SIZE[i];let t=o-o%s;if(a=Yr.stuffBits(l,s),a.getSize()+h>t)throw new c("Data to large for user specified layer");if(n&&a.getSize()>64*s)throw new c("Data to large for user specified layer")}else{s=0,a=null;for(let t=0;;t++){if(t>Yr.MAX_NB_BITS)throw new c("Data too large for an Aztec code");if(n=t<=3,i=n?t+1:t,o=Yr.totalBitsInLayer(i,n),u>o)continue;null!=a&&s===Yr.WORD_SIZE[i]||(s=Yr.WORD_SIZE[i],a=Yr.stuffBits(l,s));let e=o-o%s;if(!(n&&a.getSize()>64*s)&&a.getSize()+h<=e)break}}let d,f=Yr.generateCheckWords(a,o,s),g=a.getSize()/s,w=Yr.generateModeMessage(n,i,g),p=(n?11:14)+4*i,A=new Int32Array(p);if(n){d=p;for(let t=0;t=n||t.get(o+r))&&(s|=1<{for(var n in e)r.o(e,n)&&!r.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),r.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var n={};(()=>{"use strict";var t;r.r(n),r.d(n,{Html5Qrcode:()=>W,Html5QrcodeScanType:()=>i,Html5QrcodeScanner:()=>ft,Html5QrcodeScannerState:()=>w,Html5QrcodeSupportedFormats:()=>t}),function(t){t[t.QR_CODE=0]="QR_CODE",t[t.AZTEC=1]="AZTEC",t[t.CODABAR=2]="CODABAR",t[t.CODE_39=3]="CODE_39",t[t.CODE_93=4]="CODE_93",t[t.CODE_128=5]="CODE_128",t[t.DATA_MATRIX=6]="DATA_MATRIX",t[t.MAXICODE=7]="MAXICODE",t[t.ITF=8]="ITF",t[t.EAN_13=9]="EAN_13",t[t.EAN_8=10]="EAN_8",t[t.PDF_417=11]="PDF_417",t[t.RSS_14=12]="RSS_14",t[t.RSS_EXPANDED=13]="RSS_EXPANDED",t[t.UPC_A=14]="UPC_A",t[t.UPC_E=15]="UPC_E",t[t.UPC_EAN_EXTENSION=16]="UPC_EAN_EXTENSION"}(t||(t={}));var e,i,o=new Map([[t.QR_CODE,"QR_CODE"],[t.AZTEC,"AZTEC"],[t.CODABAR,"CODABAR"],[t.CODE_39,"CODE_39"],[t.CODE_93,"CODE_93"],[t.CODE_128,"CODE_128"],[t.DATA_MATRIX,"DATA_MATRIX"],[t.MAXICODE,"MAXICODE"],[t.ITF,"ITF"],[t.EAN_13,"EAN_13"],[t.EAN_8,"EAN_8"],[t.PDF_417,"PDF_417"],[t.RSS_14,"RSS_14"],[t.RSS_EXPANDED,"RSS_EXPANDED"],[t.UPC_A,"UPC_A"],[t.UPC_E,"UPC_E"],[t.UPC_EAN_EXTENSION,"UPC_EAN_EXTENSION"]]);function s(e){return Object.values(t).includes(e)}!function(t){t[t.UNKNOWN=0]="UNKNOWN",t[t.URL=1]="URL"}(e||(e={})),function(t){t[t.SCAN_TYPE_CAMERA=0]="SCAN_TYPE_CAMERA",t[t.SCAN_TYPE_FILE=1]="SCAN_TYPE_FILE"}(i||(i={}));var a,c=function(){function t(){}return t.GITHUB_PROJECT_URL="https://github.com/mebjas/html5-qrcode",t.SCAN_DEFAULT_FPS=2,t.DEFAULT_DISABLE_FLIP=!1,t.DEFAULT_REMEMBER_LAST_CAMERA_USED=!0,t.DEFAULT_SUPPORTED_SCAN_TYPE=[i.SCAN_TYPE_CAMERA,i.SCAN_TYPE_FILE],t}(),l=function(){function t(t,e){this.format=t,this.formatName=e}return t.prototype.toString=function(){return this.formatName},t.create=function(e){if(!o.has(e))throw"".concat(e," not in html5QrcodeSupportedFormatsTextMap");return new t(e,o.get(e))},t}(),h=function(){function t(){}return t.createFromText=function(t){return{decodedText:t,result:{text:t}}},t.createFromQrcodeResult=function(t){return{decodedText:t.text,result:t}},t}();!function(t){t[t.UNKWOWN_ERROR=0]="UNKWOWN_ERROR",t[t.IMPLEMENTATION_ERROR=1]="IMPLEMENTATION_ERROR",t[t.NO_CODE_FOUND_ERROR=2]="NO_CODE_FOUND_ERROR"}(a||(a={}));var u=function(){function t(){}return t.createFrom=function(t){return{errorMessage:t,type:a.UNKWOWN_ERROR}},t}(),d=function(){function t(t){this.verbose=t}return t.prototype.log=function(t){this.verbose&&console.log(t)},t.prototype.warn=function(t){this.verbose&&console.warn(t)},t.prototype.logError=function(t,e){(this.verbose||!0===e)&&console.error(t)},t.prototype.logErrors=function(t){if(0===t.length)throw"Logger#logError called without arguments";this.verbose&&console.error(t)},t}();function f(t){return null==t}var g,w,m=function(){function t(){}return t.codeParseError=function(t){return"QR code parse error, error = ".concat(t)},t.errorGettingUserMedia=function(t){return"Error getting userMedia, error = ".concat(t)},t.onlyDeviceSupportedError=function(){return"The device doesn't support navigator.mediaDevices , only supported cameraIdOrConfig in this case is deviceId parameter (string)."},t.cameraStreamingNotSupported=function(){return"Camera streaming not supported by the browser."},t.unableToQuerySupportedDevices=function(){return"Unable to query supported devices, unknown error."},t.insecureContextCameraQueryError=function(){return"Camera access is only supported in secure context like https or localhost."},t.scannerPaused=function(){return"Scanner paused"},t}(),p=function(){function t(){}return t.scanningStatus=function(){return"Scanning"},t.idleStatus=function(){return"Idle"},t.errorStatus=function(){return"Error"},t.permissionStatus=function(){return"Permission"},t.noCameraFoundErrorStatus=function(){return"No Cameras"},t.lastMatch=function(t){return"Last Match: ".concat(t)},t.codeScannerTitle=function(){return"Code Scanner"},t.cameraPermissionTitle=function(){return"Request Camera Permissions"},t.cameraPermissionRequesting=function(){return"Requesting camera permissions..."},t.noCameraFound=function(){return"No camera found"},t.scanButtonStopScanningText=function(){return"Stop Scanning"},t.scanButtonStartScanningText=function(){return"Start Scanning"},t.torchOnButton=function(){return"Switch On Torch"},t.torchOffButton=function(){return"Switch Off Torch"},t.torchOnFailedMessage=function(){return"Failed to turn on torch"},t.torchOffFailedMessage=function(){return"Failed to turn off torch"},t.scanButtonScanningStarting=function(){return"Launching Camera..."},t.textIfCameraScanSelected=function(){return"Scan an Image File"},t.textIfFileScanSelected=function(){return"Scan using camera directly"},t.selectCamera=function(){return"Select Camera"},t.fileSelectionChooseImage=function(){return"Choose Image"},t.fileSelectionChooseAnother=function(){return"Choose Another"},t.fileSelectionNoImageSelected=function(){return"No image choosen"},t.anonymousCameraPrefix=function(){return"Anonymous Camera"},t.dragAndDropMessage=function(){return"Or drop an image to scan"},t.dragAndDropMessageOnlyImages=function(){return"Or drop an image to scan (other files not supported)"},t.zoom=function(){return"zoom"},t.loadingImage=function(){return"Loading image..."},t.cameraScanAltText=function(){return"Camera based scan"},t.fileScanAltText=function(){return"Fule based scan"},t}(),A=function(){function t(){}return t.poweredBy=function(){return"Powered by "},t.reportIssues=function(){return"Report issues"},t}(),C=function(){function t(){}return t.isMediaStreamConstraintsValid=function(t,e){if("object"!=typeof t){var r=typeof t;return e.logError("videoConstraints should be of type object, the "+"object passed is of type ".concat(r,"."),!0),!1}for(var n=new Set(["autoGainControl","channelCount","echoCancellation","latency","noiseSuppression","sampleRate","sampleSize","volume"]),i=0,o=Object.keys(t);i0&&i[i.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]r&&(r=s,e=o)}if(!e)throw"No largest barcode found";return e},e.prototype.createBarcodeDetectorFormats=function(t){for(var e=[],r=0,n=t;r0&&i[i.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=n&&(t.isClosed=!0,t.parentElement.removeChild(t.surface),e())}))}))},t.prototype.getCapabilities=function(){return new B(this.getFirstTrackOrFail())},t}(),P=function(){function t(t){this.mediaStream=t}return t.prototype.render=function(t,e,r){return D(this,void 0,void 0,(function(){return M(this,(function(n){return[2,L.create(t,this.mediaStream,e,r)]}))}))},t.create=function(e){return D(this,void 0,void 0,(function(){var r;return M(this,(function(n){switch(n.label){case 0:if(!navigator.mediaDevices)throw"navigator.mediaDevices not supported";return r={audio:!1,video:e},[4,navigator.mediaDevices.getUserMedia(r)];case 1:return[2,new t(n.sent())]}}))}))},t}(),v=function(t,e,r,n){return new(r||(r=Promise))((function(i,o){function s(t){try{c(n.next(t))}catch(t){o(t)}}function a(t){try{c(n.throw(t))}catch(t){o(t)}}function c(t){var e;t.done?i(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(s,a)}c((n=n.apply(t,e||[])).next())}))},F=function(t,e){var r,n,i,o,s={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(a){return function(c){return function(a){if(r)throw new TypeError("Generator is already executing.");for(;o&&(o=0,a[0]&&(s=0)),s;)try{if(r=1,n&&(i=2&a[0]?n.return:a[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,a[1])).done)return i;switch(n=0,i&&(a=[2&a[0],i.value]),a[0]){case 0:case 1:i=a;break;case 4:return s.label++,{value:a[1],done:!1};case 5:s.label++,n=a[1],a=[0];continue;case 7:a=s.ops.pop(),s.trys.pop();continue;default:if(!((i=(i=s.trys).length>0&&i[i.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]t&&(this.logger.warn("`qrbox.width` or `qrbox` is larger than the width of the root element. The width will be truncated to the width of root element."),i=t),i)},e.prototype.validateQrboxConfig=function(t){if("number"!=typeof t&&"function"!=typeof t&&(void 0===t.width||void 0===t.height))throw"Invalid instance of QrDimensions passed for 'config.qrbox'. Both 'width' and 'height' should be set."},e.prototype.toQrdimensions=function(t,e,r){if("number"==typeof r)return{width:r,height:r};if("function"==typeof r)try{return r(t,e)}catch(t){throw new Error("qrbox config was passed as a function but it failed with unknown error"+t)}return r},e.prototype.setupUi=function(t,e,r){r.isShadedBoxEnabled()&&this.validateQrboxSize(t,e,r);var n=f(r.qrbox)?{width:t,height:e}:r.qrbox;this.validateQrboxConfig(n);var i=this.toQrdimensions(t,e,n);i.height>e&&this.logger.warn("[Html5Qrcode] config.qrbox has height that isgreater than the height of the video stream. Shading will be ignored");var o=r.isShadedBoxEnabled()&&i.height<=e,s={x:0,y:0,width:t,height:e},a=o?this.getShadedRegionBounds(t,e,i):s,c=this.createCanvasElement(a.width,a.height),l=c.getContext("2d",{willReadFrequently:!0});l.canvas.width=a.width,l.canvas.height=a.height,this.element.append(c),o&&this.possiblyInsertShadingElement(this.element,t,e,i),this.createScannerPausedUiElement(this.element),this.qrRegion=a,this.context=l,this.canvasElement=c},e.prototype.createScannerPausedUiElement=function(t){var e=document.createElement("div");e.innerText=m.scannerPaused(),e.style.display="none",e.style.position="absolute",e.style.top="0px",e.style.zIndex="1",e.style.background="rgba(9, 9, 9, 0.46)",e.style.color="#FFECEC",e.style.textAlign="center",e.style.width="100%",t.appendChild(e),this.scannerPausedUiElement=e},e.prototype.scanContext=function(t,e){var r=this;return this.stateManagerProxy.isPaused()?Promise.resolve(!1):this.qrcode.decodeAsync(this.canvasElement).then((function(e){return t(e.text,h.createFromQrcodeResult(e)),r.possiblyUpdateShaders(!0),!0})).catch((function(t){r.possiblyUpdateShaders(!1);var n=m.codeParseError(t);return e(n,u.createFrom(n)),!1}))},e.prototype.foreverScan=function(t,e,r){var n=this;if(this.shouldScan&&this.renderedCamera){var i=this.renderedCamera.getSurface(),o=i.videoWidth/i.clientWidth,s=i.videoHeight/i.clientHeight;if(!this.qrRegion)throw"qrRegion undefined when localMediaStream is ready.";var a=this.qrRegion.width*o,c=this.qrRegion.height*s,l=this.qrRegion.x*o,h=this.qrRegion.y*s;this.context.drawImage(i,l,h,a,c,0,0,this.qrRegion.width,this.qrRegion.height);var u=function(){n.foreverScanTimeout=setTimeout((function(){n.foreverScan(t,e,r)}),n.getTimeoutFps(t.fps))};this.scanContext(e,r).then((function(i){i||!0===t.disableFlip?u():(n.context.translate(n.context.canvas.width,0),n.context.scale(-1,1),n.scanContext(e,r).finally((function(){u()})))})).catch((function(t){n.logger.logError("Error happend while scanning context",t),u()}))}},e.prototype.createVideoConstraints=function(t){if("string"==typeof t)return{deviceId:{exact:t}};if("object"==typeof t){var e="facingMode",r="deviceId",n={user:!0,environment:!0},i="exact",o=function(t){if(t in n)return!0;throw"config has invalid 'facingMode' value = "+"'".concat(t,"'")},s=Object.keys(t);if(1!==s.length)throw"'cameraIdOrConfig' object should have exactly 1 key,"+" if passed as an object, found ".concat(s.length," keys");var a=Object.keys(t)[0];if(a!==e&&a!==r)throw"Only '".concat(e,"' and '").concat(r,"' ")+" are supported for 'cameraIdOrConfig'";if(a!==e){var c=t.deviceId;if("string"==typeof c)return{deviceId:c};if("object"==typeof c){if(i in c)return{deviceId:{exact:c["".concat(i)]}};throw"'deviceId' should be string or object with"+" ".concat(i," as key.")}throw"Invalid type of 'deviceId' = ".concat(typeof c)}var l=t.facingMode;if("string"==typeof l){if(o(l))return{facingMode:l}}else{if("object"!=typeof l)throw"Invalid type of 'facingMode' = ".concat(typeof l);if(!(i in l))throw"'facingMode' should be string or object with"+" ".concat(i," as key.");if(o(l["".concat(i)]))return{facingMode:{exact:l["".concat(i)]}}}}throw"Invalid type of 'cameraIdOrConfig' = ".concat(typeof t)},e.prototype.computeCanvasDrawConfig=function(t,e,r,n){if(t<=r&&e<=n)return{x:(r-t)/2,y:(n-e)/2,width:t,height:e};var i=t,o=e;return t>r&&(e*=r/t,t=r),e>n&&(t*=n/e,e=n),this.logger.log("Image downsampled from "+"".concat(i,"X").concat(o)+" to ".concat(t,"X").concat(e,".")),this.computeCanvasDrawConfig(t,e,r,n)},e.prototype.clearElement=function(){if(this.stateManagerProxy.isScanning())throw"Cannot clear while scan is ongoing, close it first.";var t=document.getElementById(this.elementId);t&&(t.innerHTML="")},e.prototype.possiblyUpdateShaders=function(t){this.qrMatch!==t&&(this.hasBorderShaders&&this.borderShaders&&this.borderShaders.length&&this.borderShaders.forEach((function(e){e.style.backgroundColor=t?Y.BORDER_SHADER_MATCH_COLOR:Y.BORDER_SHADER_DEFAULT_COLOR})),this.qrMatch=t)},e.prototype.possiblyCloseLastScanImageFile=function(){this.lastScanImageFile&&(URL.revokeObjectURL(this.lastScanImageFile),this.lastScanImageFile=null)},e.prototype.createCanvasElement=function(t,e,r){var n=t,i=e,o=document.createElement("canvas");return o.style.width="".concat(n,"px"),o.style.height="".concat(i,"px"),o.style.display="none",o.id=f(r)?"qr-canvas":r,o},e.prototype.getShadedRegionBounds=function(t,e,r){if(r.width>t||r.height>e)throw"'config.qrbox' dimensions should not be greater than the dimensions of the root HTML element.";return{x:(t-r.width)/2,y:(e-r.height)/2,width:r.width,height:r.height}},e.prototype.possiblyInsertShadingElement=function(t,e,r,n){if(!(e-n.width<1||r-n.height<1)){var i=document.createElement("div");i.style.position="absolute";var o=(e-n.width)/2,s=(r-n.height)/2;if(i.style.borderLeft="".concat(o,"px solid rgba(0, 0, 0, 0.48)"),i.style.borderRight="".concat(o,"px solid rgba(0, 0, 0, 0.48)"),i.style.borderTop="".concat(s,"px solid rgba(0, 0, 0, 0.48)"),i.style.borderBottom="".concat(s,"px solid rgba(0, 0, 0, 0.48)"),i.style.boxSizing="border-box",i.style.top="0px",i.style.bottom="0px",i.style.left="0px",i.style.right="0px",i.id="".concat(Y.SHADED_REGION_ELEMENT_ID),e-n.width<11||r-n.height<11)this.hasBorderShaders=!1;else{this.insertShaderBorders(i,40,5,-5,null,0,!0),this.insertShaderBorders(i,40,5,-5,null,0,!1),this.insertShaderBorders(i,40,5,null,-5,0,!0),this.insertShaderBorders(i,40,5,null,-5,0,!1),this.insertShaderBorders(i,5,45,-5,null,-5,!0),this.insertShaderBorders(i,5,45,null,-5,-5,!0),this.insertShaderBorders(i,5,45,-5,null,-5,!1),this.insertShaderBorders(i,5,45,null,-5,-5,!1),this.hasBorderShaders=!0}t.append(i)}},e.prototype.insertShaderBorders=function(t,e,r,n,i,o,s){var a=document.createElement("div");a.style.position="absolute",a.style.backgroundColor=Y.BORDER_SHADER_DEFAULT_COLOR,a.style.width="".concat(e,"px"),a.style.height="".concat(r,"px"),null!==n&&(a.style.top="".concat(n,"px")),null!==i&&(a.style.bottom="".concat(i,"px")),s?a.style.left="".concat(o,"px"):a.style.right="".concat(o,"px"),this.borderShaders||(this.borderShaders=[]),this.borderShaders.push(a),t.appendChild(a)},e.prototype.showPausedState=function(){if(!this.scannerPausedUiElement)throw"[internal error] scanner paused UI element not found";this.scannerPausedUiElement.style.display="block"},e.prototype.hidePausedState=function(){if(!this.scannerPausedUiElement)throw"[internal error] scanner paused UI element not found";this.scannerPausedUiElement.style.display="none"},e.prototype.getTimeoutFps=function(t){return 1e3/t},e}(),j="data:image/svg+xml;base64,",Z=j+"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNzEuNjQzIDM3MS42NDMiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDM3MS42NDMgMzcxLjY0MyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBhdGggZD0iTTEwNS4wODQgMzguMjcxaDE2My43Njh2MjBIMTA1LjA4NHoiLz48cGF0aCBkPSJNMzExLjU5NiAxOTAuMTg5Yy03LjQ0MS05LjM0Ny0xOC40MDMtMTYuMjA2LTMyLjc0My0yMC41MjJWMzBjMC0xNi41NDItMTMuNDU4LTMwLTMwLTMwSDEyNS4wODRjLTE2LjU0MiAwLTMwIDEzLjQ1OC0zMCAzMHYxMjAuMTQzaC04LjI5NmMtMTYuNTQyIDAtMzAgMTMuNDU4LTMwIDMwdjEuMzMzYTI5LjgwNCAyOS44MDQgMCAwIDAgNC42MDMgMTUuOTM5Yy03LjM0IDUuNDc0LTEyLjEwMyAxNC4yMjEtMTIuMTAzIDI0LjA2MXYxLjMzM2MwIDkuODQgNC43NjMgMTguNTg3IDEyLjEwMyAyNC4wNjJhMjkuODEgMjkuODEgMCAwIDAtNC42MDMgMTUuOTM4djEuMzMzYzAgMTYuNTQyIDEzLjQ1OCAzMCAzMCAzMGg4LjMyNGMuNDI3IDExLjYzMSA3LjUwMyAyMS41ODcgMTcuNTM0IDI2LjE3Ny45MzEgMTAuNTAzIDQuMDg0IDMwLjE4NyAxNC43NjggNDUuNTM3YTkuOTg4IDkuOTg4IDAgMCAwIDguMjE2IDQuMjg4IDkuOTU4IDkuOTU4IDAgMCAwIDUuNzA0LTEuNzkzYzQuNTMzLTMuMTU1IDUuNjUtOS4zODggMi40OTUtMTMuOTIxLTYuNzk4LTkuNzY3LTkuNjAyLTIyLjYwOC0xMC43Ni0zMS40aDgyLjY4NWMuMjcyLjQxNC41NDUuODE4LjgxNSAxLjIxIDMuMTQyIDQuNTQxIDkuMzcyIDUuNjc5IDEzLjkxMyAyLjUzNCA0LjU0Mi0zLjE0MiA1LjY3Ny05LjM3MSAyLjUzNS0xMy45MTMtMTEuOTE5LTE3LjIyOS04Ljc4Ny0zNS44ODQgOS41ODEtNTcuMDEyIDMuMDY3LTIuNjUyIDEyLjMwNy0xMS43MzIgMTEuMjE3LTI0LjAzMy0uODI4LTkuMzQzLTcuMTA5LTE3LjE5NC0xOC42NjktMjMuMzM3YTkuODU3IDkuODU3IDAgMCAwLTEuMDYxLS40ODZjLS40NjYtLjE4Mi0xMS40MDMtNC41NzktOS43NDEtMTUuNzA2IDEuMDA3LTYuNzM3IDE0Ljc2OC04LjI3MyAyMy43NjYtNy42NjYgMjMuMTU2IDEuNTY5IDM5LjY5OCA3LjgwMyA0Ny44MzYgMTguMDI2IDUuNzUyIDcuMjI1IDcuNjA3IDE2LjYyMyA1LjY3MyAyOC43MzMtLjQxMyAyLjU4NS0uODI0IDUuMjQxLTEuMjQ1IDcuOTU5LTUuNzU2IDM3LjE5NC0xMi45MTkgODMuNDgzLTQ5Ljg3IDExNC42NjEtNC4yMjEgMy41NjEtNC43NTYgOS44Ny0xLjE5NCAxNC4wOTJhOS45OCA5Ljk4IDAgMCAwIDcuNjQ4IDMuNTUxIDkuOTU1IDkuOTU1IDAgMCAwIDYuNDQ0LTIuMzU4YzQyLjY3Mi0zNi4wMDUgNTAuODAyLTg4LjUzMyA1Ni43MzctMTI2Ljg4OC40MTUtMi42ODQuODIxLTUuMzA5IDEuMjI5LTcuODYzIDIuODM0LTE3LjcyMS0uNDU1LTMyLjY0MS05Ljc3Mi00NC4zNDV6bS0yMzIuMzA4IDQyLjYyYy01LjUxNCAwLTEwLTQuNDg2LTEwLTEwdi0xLjMzM2MwLTUuNTE0IDQuNDg2LTEwIDEwLTEwaDE1djIxLjMzM2gtMTV6bS0yLjUtNTIuNjY2YzAtNS41MTQgNC40ODYtMTAgMTAtMTBoNy41djIxLjMzM2gtNy41Yy01LjUxNCAwLTEwLTQuNDg2LTEwLTEwdi0xLjMzM3ptMTcuNSA5My45OTloLTcuNWMtNS41MTQgMC0xMC00LjQ4Ni0xMC0xMHYtMS4zMzNjMC01LjUxNCA0LjQ4Ni0xMCAxMC0xMGg3LjV2MjEuMzMzem0zMC43OTYgMjguODg3Yy01LjUxNCAwLTEwLTQuNDg2LTEwLTEwdi04LjI3MWg5MS40NTdjLS44NTEgNi42NjgtLjQzNyAxMi43ODcuNzMxIDE4LjI3MWgtODIuMTg4em03OS40ODItMTEzLjY5OGMtMy4xMjQgMjAuOTA2IDEyLjQyNyAzMy4xODQgMjEuNjI1IDM3LjA0IDUuNDQxIDIuOTY4IDcuNTUxIDUuNjQ3IDcuNzAxIDcuMTg4LjIxIDIuMTUtMi41NTMgNS42ODQtNC40NzcgNy4yNTEtLjQ4Mi4zNzgtLjkyOS44LTEuMzM1IDEuMjYxLTYuOTg3IDcuOTM2LTExLjk4MiAxNS41Mi0xNS40MzIgMjIuNjg4aC05Ny41NjRWMzBjMC01LjUxNCA0LjQ4Ni0xMCAxMC0xMGgxMjMuNzY5YzUuNTE0IDAgMTAgNC40ODYgMTAgMTB2MTM1LjU3OWMtMy4wMzItLjM4MS02LjE1LS42OTQtOS4zODktLjkxNC0yNS4xNTktMS42OTQtNDIuMzcgNy43NDgtNDQuODk4IDI0LjY2NnoiLz48cGF0aCBkPSJNMTc5LjEyOSA4My4xNjdoLTI0LjA2YTUgNSAwIDAgMC01IDV2MjQuMDYxYTUgNSAwIDAgMCA1IDVoMjQuMDZhNSA1IDAgMCAwIDUtNVY4OC4xNjdhNSA1IDAgMCAwLTUtNXpNMTcyLjYyOSAxNDIuODZoLTEyLjU2VjEzMC44YTUgNSAwIDEgMC0xMCAwdjE3LjA2MWE1IDUgMCAwIDAgNSA1aDE3LjU2YTUgNSAwIDEgMCAwLTEwLjAwMXpNMjE2LjU2OCA4My4xNjdoLTI0LjA2YTUgNSAwIDAgMC01IDV2MjQuMDYxYTUgNSAwIDAgMCA1IDVoMjQuMDZhNSA1IDAgMCAwIDUtNVY4OC4xNjdhNSA1IDAgMCAwLTUtNXptLTUgMjQuMDYxaC0xNC4wNlY5My4xNjdoMTQuMDZ2MTQuMDYxek0yMTEuNjY5IDEyNS45MzZIMTk3LjQxYTUgNSAwIDAgMC01IDV2MTQuMjU3YTUgNSAwIDAgMCA1IDVoMTQuMjU5YTUgNSAwIDAgMCA1LTV2LTE0LjI1N2E1IDUgMCAwIDAtNS01eiIvPjwvc3ZnPg==",Q=j+"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1OS4wMTggNTkuMDE4IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1OS4wMTggNTkuMDE4IiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBkPSJtNTguNzQxIDU0LjgwOS01Ljk2OS02LjI0NGExMC43NCAxMC43NCAwIDAgMCAyLjgyLTcuMjVjMC01Ljk1My00Ljg0My0xMC43OTYtMTAuNzk2LTEwLjc5NlMzNCAzNS4zNjEgMzQgNDEuMzE0IDM4Ljg0MyA1Mi4xMSA0NC43OTYgNTIuMTFjMi40NDEgMCA0LjY4OC0uODI0IDYuNDk5LTIuMTk2bDYuMDAxIDYuMjc3YS45OTguOTk4IDAgMCAwIDEuNDE0LjAzMiAxIDEgMCAwIDAgLjAzMS0xLjQxNHpNMzYgNDEuMzE0YzAtNC44NSAzLjk0Ni04Ljc5NiA4Ljc5Ni04Ljc5NnM4Ljc5NiAzLjk0NiA4Ljc5NiA4Ljc5Ni0zLjk0NiA4Ljc5Ni04Ljc5NiA4Ljc5NlMzNiA0Ni4xNjQgMzYgNDEuMzE0ek0xMC40MzEgMTYuMDg4YzAgMy4wNyAyLjQ5OCA1LjU2OCA1LjU2OSA1LjU2OHM1LjU2OS0yLjQ5OCA1LjU2OS01LjU2OGMwLTMuMDcxLTIuNDk4LTUuNTY5LTUuNTY5LTUuNTY5cy01LjU2OSAyLjQ5OC01LjU2OSA1LjU2OXptOS4xMzggMGMwIDEuOTY4LTEuNjAyIDMuNTY4LTMuNTY5IDMuNTY4cy0zLjU2OS0xLjYwMS0zLjU2OS0zLjU2OCAxLjYwMi0zLjU2OSAzLjU2OS0zLjU2OSAzLjU2OSAxLjYwMSAzLjU2OSAzLjU2OXoiLz48cGF0aCBkPSJtMzAuODgyIDI4Ljk4NyA5LjE4LTEwLjA1NCAxMS4yNjIgMTAuMzIzYTEgMSAwIDAgMCAxLjM1MS0xLjQ3NWwtMTItMTFhMSAxIDAgMCAwLTEuNDE0LjA2M2wtOS43OTQgMTAuNzI3LTQuNzQzLTQuNzQzYTEuMDAzIDEuMDAzIDAgMCAwLTEuMzY4LS4wNDRMNi4zMzkgMzcuNzY4YTEgMSAwIDEgMCAxLjMyMiAxLjUwMWwxNi4zMTMtMTQuMzYyIDcuMzE5IDcuMzE4YS45OTkuOTk5IDAgMSAwIDEuNDE0LTEuNDE0bC0xLjgyNS0xLjgyNHoiLz48cGF0aCBkPSJNMzAgNDYuNTE4SDJ2LTQyaDU0djI4YTEgMSAwIDEgMCAyIDB2LTI5YTEgMSAwIDAgMC0xLTFIMWExIDEgMCAwIDAtMSAxdjQ0YTEgMSAwIDAgMCAxIDFoMjlhMSAxIDAgMSAwIDAtMnoiLz48L3N2Zz4=",K=j+"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NjAgNDYwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0NjAgNDYwIiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBkPSJNMjMwIDBDMTAyLjk3NSAwIDAgMTAyLjk3NSAwIDIzMHMxMDIuOTc1IDIzMCAyMzAgMjMwIDIzMC0xMDIuOTc0IDIzMC0yMzBTMzU3LjAyNSAwIDIzMCAwem0zOC4zMzMgMzc3LjM2YzAgOC42NzYtNy4wMzQgMTUuNzEtMTUuNzEgMTUuNzFoLTQzLjEwMWMtOC42NzYgMC0xNS43MS03LjAzNC0xNS43MS0xNS43MVYyMDIuNDc3YzAtOC42NzYgNy4wMzMtMTUuNzEgMTUuNzEtMTUuNzFoNDMuMTAxYzguNjc2IDAgMTUuNzEgNy4wMzMgMTUuNzEgMTUuNzFWMzc3LjM2ek0yMzAgMTU3Yy0yMS41MzkgMC0zOS0xNy40NjEtMzktMzlzMTcuNDYxLTM5IDM5LTM5IDM5IDE3LjQ2MSAzOSAzOS0xNy40NjEgMzktMzkgMzl6Ii8+PC9zdmc+",q=function(){function t(){}return t.createDefault=function(){return{hasPermission:!1,lastUsedCameraId:null}},t}(),J=function(){function t(){this.data=q.createDefault();var e=localStorage.getItem(t.LOCAL_STORAGE_KEY);e?this.data=JSON.parse(e):this.reset()}return t.prototype.hasCameraPermissions=function(){return this.data.hasPermission},t.prototype.getLastUsedCameraId=function(){return this.data.lastUsedCameraId},t.prototype.setHasPermission=function(t){this.data.hasPermission=t,this.flush()},t.prototype.setLastUsedCameraId=function(t){this.data.lastUsedCameraId=t,this.flush()},t.prototype.resetLastUsedCameraId=function(){this.data.lastUsedCameraId=null,this.flush()},t.prototype.reset=function(){this.data=q.createDefault(),this.flush()},t.prototype.flush=function(){localStorage.setItem(t.LOCAL_STORAGE_KEY,JSON.stringify(this.data))},t.LOCAL_STORAGE_KEY="HTML5_QRCODE_DATA",t}(),$=function(){function t(){this.infoDiv=document.createElement("div")}return t.prototype.renderInto=function(t){this.infoDiv.style.position="absolute",this.infoDiv.style.top="10px",this.infoDiv.style.right="10px",this.infoDiv.style.zIndex="2",this.infoDiv.style.display="none",this.infoDiv.style.padding="5pt",this.infoDiv.style.border="1px solid #171717",this.infoDiv.style.fontSize="10pt",this.infoDiv.style.background="rgb(0 0 0 / 69%)",this.infoDiv.style.borderRadius="5px",this.infoDiv.style.textAlign="center",this.infoDiv.style.fontWeight="400",this.infoDiv.style.color="white",this.infoDiv.innerText=A.poweredBy();var e=document.createElement("a");e.innerText="ScanApp",e.href="https://scanapp.org",e.target="new",e.style.color="white",this.infoDiv.appendChild(e);var r=document.createElement("br"),n=document.createElement("br");this.infoDiv.appendChild(r),this.infoDiv.appendChild(n);var i=document.createElement("a");i.innerText=A.reportIssues(),i.href="https://github.com/mebjas/html5-qrcode/issues",i.target="new",i.style.color="white",this.infoDiv.appendChild(i),t.appendChild(this.infoDiv)},t.prototype.show=function(){this.infoDiv.style.display="block"},t.prototype.hide=function(){this.infoDiv.style.display="none"},t}(),tt=function(){function t(t,e){this.isShowingInfoIcon=!0,this.onTapIn=t,this.onTapOut=e,this.infoIcon=document.createElement("img")}return t.prototype.renderInto=function(t){var e=this;this.infoIcon.alt="Info icon",this.infoIcon.src=K,this.infoIcon.style.position="absolute",this.infoIcon.style.top="4px",this.infoIcon.style.right="4px",this.infoIcon.style.opacity="0.6",this.infoIcon.style.cursor="pointer",this.infoIcon.style.zIndex="2",this.infoIcon.style.width="16px",this.infoIcon.style.height="16px",this.infoIcon.onmouseover=function(t){return e.onHoverIn()},this.infoIcon.onmouseout=function(t){return e.onHoverOut()},this.infoIcon.onclick=function(t){return e.onClick()},t.appendChild(this.infoIcon)},t.prototype.onHoverIn=function(){this.isShowingInfoIcon&&(this.infoIcon.style.opacity="1")},t.prototype.onHoverOut=function(){this.isShowingInfoIcon&&(this.infoIcon.style.opacity="0.6")},t.prototype.onClick=function(){this.isShowingInfoIcon?(this.isShowingInfoIcon=!1,this.onTapIn(),this.infoIcon.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAQgAAAEIBarqQRAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAE1SURBVDiNfdI7S0NBEAXgLya1otFgpbYSbISAgpXYi6CmiH9KCAiChaVga6OiWPgfRDQ+0itaGVNosXtluWwcuMzePfM4M3sq8lbHBubwg1dc4m1E/J/N4ghDPOIsfk/4xiEao5KX0McFljN4C9d4QTPXuY99jP3DsIoDPGM6BY5i5yI5R7O4q+ImFkJY2DCh3cAH2klyB+9J1xUMMAG7eCh1a+Mr+k48b5diXrFVwwLuS+BJ9MfR7+G0FHOHhTHhnXNWS87VDF4pcnfQK4Ep7XScNLmPTZgURNKKYENYWDpzW1BhscS1WHS8CDgURFJQrWcoF3c13KKbgg1BYQfy8xZWEzTTw1QZbAoKu8FqJnktdu5hcVSHmchiILzzuaDQvjBzV2m8yohCE1jHfPx/xhU+y4G/D75ELlRJsSYAAAAASUVORK5CYII=",this.infoIcon.style.opacity="1"):(this.isShowingInfoIcon=!0,this.onTapOut(),this.infoIcon.src=K,this.infoIcon.style.opacity="0.6")},t}(),et=function(){function t(){var t=this;this.infoDiv=new $,this.infoIcon=new tt((function(){t.infoDiv.show()}),(function(){t.infoDiv.hide()}))}return t.prototype.renderInto=function(t){this.infoDiv.renderInto(t),this.infoIcon.renderInto(t)},t}(),rt=function(){function t(){}return t.hasPermissions=function(){return t=this,e=void 0,n=function(){var t,e,r,n;return function(t,e){var r,n,i,o,s={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(a){return function(c){return function(a){if(r)throw new TypeError("Generator is already executing.");for(;o&&(o=0,a[0]&&(s=0)),s;)try{if(r=1,n&&(i=2&a[0]?n.return:a[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,a[1])).done)return i;switch(n=0,i&&(a=[2&a[0],i.value]),a[0]){case 0:case 1:i=a;break;case 4:return s.label++,{value:a[1],done:!1};case 5:s.label++,n=a[1],a=[0];continue;case 7:a=s.ops.pop(),s.trys.pop();continue;default:if(!((i=(i=s.trys).length>0&&i[i.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]1},t.prototype.isCameraScanRequired=function(){for(var e=0,r=this.supportedScanTypes;ee)throw"Max ".concat(e," values expected for ")+"supportedScanTypes";for(var r=0,n=t;r0&&i[i.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]20){var e=t.substring(0,8),r=t.length,n=t.substring(r-8,r);t="".concat(e,"....").concat(n)}var i=p.fileSelectionChooseAnother()+" - "+t;this.fileSelectionButton.innerText=i},t.prototype.setInitialValueToButton=function(){var t=p.fileSelectionChooseImage()+" - "+p.fileSelectionNoImageSelected();this.fileSelectionButton.innerText=t},t.prototype.getFileScanInputId=function(){return"html5-qrcode-private-filescan-input"},t.create=function(e,r,n){return new t(e,r,n)},t}(),ut=function(){function t(t){this.selectElement=ot.createElement("select",it.CAMERA_SELECTION_SELECT_ID),this.cameras=t,this.options=[]}return t.prototype.render=function(t){var e=document.createElement("span");e.style.marginRight="10px";var r=this.cameras.length;if(0===r)throw new Error("No cameras found");if(1===r)e.style.display="none";else{var n=p.selectCamera();e.innerText="".concat(n," (").concat(this.cameras.length,") ")}for(var i=1,o=0,s=this.cameras;o0?(t.removeChild(e),n.renderCameraSelection(r)):(n.setHeaderMessage(p.noCameraFound(),U.STATUS_WARNING),i())})).catch((function(t){n.persistedDataManager.setHasPermission(!1),r?r.disabled=!1:i(),n.setHeaderMessage(t,U.STATUS_WARNING),n.showHideScanTypeSwapLink(!0)}))},t.prototype.createPermissionButton=function(t,e){var r=this,n=ot.createElement("button",this.getCameraPermissionButtonId());n.innerText=p.cameraPermissionTitle(),n.addEventListener("click",(function(){n.disabled=!0,r.createCameraListUi(t,e,n)})),e.appendChild(n)},t.prototype.createPermissionsUi=function(t,e){var r=this;nt.isCameraScanType(this.currentScanType)&&this.persistedDataManager.hasCameraPermissions()?rt.hasPermissions().then((function(n){n?r.createCameraListUi(t,e):(r.persistedDataManager.setHasPermission(!1),r.createPermissionButton(t,e))})).catch((function(n){r.persistedDataManager.setHasPermission(!1),r.createPermissionButton(t,e)})):this.createPermissionButton(t,e)},t.prototype.createSectionControlPanel=function(){var t=document.getElementById(this.getDashboardSectionId()),e=document.createElement("div");t.appendChild(e);var r=document.createElement("div");r.id=this.getDashboardSectionCameraScanRegionId(),r.style.display=nt.isCameraScanType(this.currentScanType)?"block":"none",e.appendChild(r);var n=document.createElement("div");n.style.textAlign="center",r.appendChild(n),this.scanTypeSelector.isCameraScanRequired()&&this.createPermissionsUi(r,n),this.renderFileScanUi(e)},t.prototype.renderFileScanUi=function(t){var e=nt.isFileScanType(this.currentScanType),r=this;this.fileSelectionUi=ht.create(t,e,(function(t){if(!r.html5Qrcode)throw"html5Qrcode not defined";nt.isFileScanType(r.currentScanType)&&(r.setHeaderMessage(p.loadingImage()),r.html5Qrcode.scanFileV2(t,!0).then((function(t){r.resetHeaderMessage(),r.qrCodeSuccessCallback(t.decodedText,t)})).catch((function(t){r.setHeaderMessage(t,U.STATUS_WARNING),r.qrCodeErrorCallback(t,u.createFrom(t))})))}))},t.prototype.renderCameraSelection=function(t){var e=this,r=this,n=document.getElementById(this.getDashboardSectionCameraScanRegionId());n.style.textAlign="center";var i=dt.create(n,!1),o=ut.create(n,t),s=document.createElement("span"),a=ot.createElement("button",it.CAMERA_START_BUTTON_ID);a.innerText=p.scanButtonStartScanningText(),s.appendChild(a);var c,l=ot.createElement("button",it.CAMERA_STOP_BUTTON_ID);l.innerText=p.scanButtonStopScanningText(),l.style.display="none",l.disabled=!0,s.appendChild(l),n.appendChild(s);var h=function(t){t||(a.style.display="none"),a.innerText=p.scanButtonStartScanningText(),a.style.opacity="1",a.disabled=!1,t&&(a.style.display="inline-block")};if(a.addEventListener("click",(function(t){a.innerText=p.scanButtonScanningStarting(),o.disable(),a.disabled=!0,a.style.opacity="0.5",e.scanTypeSelector.hasMoreThanOneScanType()&&r.showHideScanTypeSwapLink(!1),r.resetHeaderMessage();var n,u=o.getValue();r.persistedDataManager.setLastUsedCameraId(u),r.html5Qrcode.start(u,(n=r.config,{fps:n.fps,qrbox:n.qrbox,aspectRatio:n.aspectRatio,disableFlip:n.disableFlip,videoConstraints:n.videoConstraints}),r.qrCodeSuccessCallback,r.qrCodeErrorCallback).then((function(t){l.disabled=!1,l.style.display="inline-block",h(!1);var n=r.html5Qrcode.getRunningTrackCameraCapabilities();!0===e.config.showTorchButtonIfSupported&&function(t){t.torchFeature().isSupported()?(c?c.updateTorchCapability(t.torchFeature()):c=lt.create(s,t.torchFeature(),{display:"none",marginLeft:"5px"},(function(t){r.setHeaderMessage(t,U.STATUS_WARNING)})),c.show()):c&&c.hide()}(n),!0===e.config.showZoomSliderIfSupported&&function(t){var r=t.zoomFeature();if(r.isSupported()){i.setOnCameraZoomValueChangeCallback((function(t){r.apply(t)}));var n,o,s,a=1;e.config.defaultZoomValueIfSupported&&(a=e.config.defaultZoomValueIfSupported),n=a,o=r.min(),a=n>(s=r.max())?s:n",e.appendChild(t.cameraScanImage)},this.cameraScanImage.width=64,this.cameraScanImage.style.opacity="0.8",this.cameraScanImage.src=Z,this.cameraScanImage.alt=p.cameraScanAltText()},t.prototype.insertFileScanImageToScanRegion=function(){var t=this,e=document.getElementById(this.getScanRegionId());if(this.fileScanImage)return e.innerHTML="
",void e.appendChild(this.fileScanImage);this.fileScanImage=new Image,this.fileScanImage.onload=function(r){e.innerHTML="
",e.appendChild(t.fileScanImage)},this.fileScanImage.width=64,this.fileScanImage.style.opacity="0.8",this.fileScanImage.src=Q,this.fileScanImage.alt=p.fileScanAltText()},t.prototype.clearScanRegion=function(){document.getElementById(this.getScanRegionId()).innerHTML=""},t.prototype.getDashboardSectionId=function(){return"".concat(this.elementId,"__dashboard_section")},t.prototype.getDashboardSectionCameraScanRegionId=function(){return"".concat(this.elementId,"__dashboard_section_csr")},t.prototype.getDashboardSectionSwapLinkId=function(){return it.SCAN_TYPE_CHANGE_ANCHOR_ID},t.prototype.getScanRegionId=function(){return"".concat(this.elementId,"__scan_region")},t.prototype.getDashboardId=function(){return"".concat(this.elementId,"__dashboard")},t.prototype.getHeaderMessageContainerId=function(){return"".concat(this.elementId,"__header_message")},t.prototype.getCameraPermissionButtonId=function(){return it.CAMERA_PERMISSION_BUTTON_ID},t.prototype.getCameraScanRegion=function(){return document.getElementById(this.getDashboardSectionCameraScanRegionId())},t.prototype.getDashboardSectionSwapLink=function(){return document.getElementById(this.getDashboardSectionSwapLinkId())},t.prototype.getHeaderMessageDiv=function(){return document.getElementById(this.getHeaderMessageContainerId())},t}()})(),__Html5QrcodeLibrary__=n})();if (window) { if (!Html5QrcodeScanner) { var Html5QrcodeScanner = window.__Html5QrcodeLibrary__.Html5QrcodeScanner; } if (!Html5Qrcode) { var Html5Qrcode = window.__Html5QrcodeLibrary__.Html5Qrcode; } if (!Html5QrcodeSupportedFormats) { var Html5QrcodeSupportedFormats = window.__Html5QrcodeLibrary__.Html5QrcodeSupportedFormats } if (!Html5QrcodeScannerState) { var Html5QrcodeScannerState = window.__Html5QrcodeLibrary__.Html5QrcodeScannerState; } if (!Html5QrcodeScanType) { var Html5QrcodeScanType = window.__Html5QrcodeLibrary__.Html5QrcodeScanType; }} \ No newline at end of file