diff --git a/.claude/settings.local.json b/.claude/settings.local.json index b7f2a738d..53151696d 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -13,7 +13,8 @@ "Bash(fi)", "Bash(ls:*)", "Bash(./testing/cucumber/features/environment.py -v)", - "Bash(./testing/cucumber/features/autojob.feature -v)" + "Bash(./testing/cucumber/features/autojob.feature -v)", + "Bash(git rev-parse:*)" ], "deny": [] } diff --git a/scan-upload-improvements.md b/scan-upload-improvements.md new file mode 100644 index 000000000..56f401a5e --- /dev/null +++ b/scan-upload-improvements.md @@ -0,0 +1,56 @@ +# Scan Upload Feature Improvements + +## Code Improvements + +1. **Modular JavaScript Architecture** + - Split the monolithic `scan-upload-direct.js` into logical modules: + - `logger.js`: Handles logging and status updates + - `peer-connection.js`: Manages WebRTC peer connections + - `camera.js`: Controls mobile camera functionality + - `scan-upload.js`: Main module that coordinates everything + +2. **Separated CSS from HTML** + - Created dedicated CSS files: + - `scan-upload.css`: Styles for the desktop scan-upload page + - `mobile-scanner.css`: Styles for the mobile camera interface + +3. **Improved Error Handling** + - Added better error handling throughout the codebase + - Improved user feedback for connection and camera issues + - Enhanced debug logging capabilities + +4. **Backward Compatibility** + - Created a compatibility layer that maintains the old API + - Allows gradual migration to the new code structure + - Ensures existing integrations won't break + +## UI Improvements + +1. **Enhanced Responsive Design** + - Improved mobile layout with proper media queries + - Better handling of different screen sizes + +2. **Better Visual Feedback** + - Clearer status messages for users + - Improved styling of the scan result display + - Enhanced debug information presentation + +3. **Localization Support** + - Added proper Thymeleaf text references for all UI elements + - Uses the existing messages system for translations + +## Security Improvements + +1. **Enhanced WebRTC Implementation** + - Better handling of connection errors + - Improved security for peer connections + - Structured error handling for failed connections + +## Next Steps + +Potential future improvements: + +1. Add more robust testing for the WebRTC functionality +2. Consider implementing a fallback method if WebRTC is not available +3. Add support for scanning multiple documents in one session +4. Implement better image quality control options \ No newline at end of file diff --git a/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java b/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java index c55eecad6..e6fd0f204 100644 --- a/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java +++ b/src/main/java/stirling/software/SPDF/config/CleanUrlInterceptor.java @@ -24,7 +24,9 @@ public class CleanUrlInterceptor implements HandlerInterceptor { "file", "messageType", "infoMessage", - "async"); + "async", + "session", + "t"); @Override public boolean preHandle( diff --git a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java index c9872992a..77d988910 100644 --- a/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java @@ -173,6 +173,7 @@ public class EndpointConfiguration { addEndpointToGroup("Other", "get-info-on-pdf"); addEndpointToGroup("Other", "show-javascript"); addEndpointToGroup("Other", "remove-image-pdf"); + addEndpointToGroup("Other", "scan-upload"); // CLI addEndpointToGroup("CLI", "compress-pdf"); diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/ScanUploadController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/ScanUploadController.java new file mode 100644 index 000000000..26fad3768 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/misc/ScanUploadController.java @@ -0,0 +1,24 @@ +package stirling.software.SPDF.controller.api.misc; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.tags.Tag; + +import lombok.extern.slf4j.Slf4j; + +/** + * Controller for scan upload functionality - WebRTC version. + * + * This controller is completely empty as all functionality has been moved to WebRTC. + * The image transfer happens directly between browsers without any server involvement. + */ +@RestController +@RequestMapping("/api/v1/misc") +@Tag(name = "Misc", description = "Miscellaneous APIs") +@Hidden +@Slf4j +public class ScanUploadController { + // All functionality has been moved to client-side WebRTC +} \ No newline at end of file diff --git a/src/main/java/stirling/software/SPDF/controller/web/ScanUploadWebController.java b/src/main/java/stirling/software/SPDF/controller/web/ScanUploadWebController.java new file mode 100644 index 000000000..ca0a76b69 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/web/ScanUploadWebController.java @@ -0,0 +1,49 @@ +package stirling.software.SPDF.controller.web; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.tags.Tag; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * Web controller for the scan-upload functionality. + */ +@Controller +@Tag(name = "Scan Upload", description = "Scan Upload Web Interface") +@Slf4j +@RequiredArgsConstructor +public class ScanUploadWebController { + + /** + * Serves the scan-upload page for desktop/PC view. + * + * @param model the Spring MVC model + * @return the template name to render + */ + @GetMapping("/scan-upload") + @Hidden + public String scanUploadForm(Model model) { + model.addAttribute("currentPage", "scan-upload"); + return "misc/scan-upload"; + } + + /** + * Serves the mobile page for camera capture and upload. + * + * @param model the Spring MVC model + * @param session the session ID parameter + * @return the template name to render + */ + @GetMapping("/mobile") + @Hidden + public String mobileView(Model model, @RequestParam(name = "session", required = false) String session) { + model.addAttribute("sessionId", session); + return "misc/mobile"; + } +} \ No newline at end of file diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index 1f72b0213..28635d963 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -1549,7 +1549,7 @@ validateSignature.cert.bits=bits #################### cookieBanner.popUp.title=How we use Cookies cookieBanner.popUp.description.1=We use cookies and other technologies to make Stirling PDF work better for you—helping us improve our tools and keep building features you'll love. -cookieBanner.popUp.description.2=If you’d rather not, clicking 'No Thanks' will only enable the essential cookies needed to keep things running smoothly. +cookieBanner.popUp.description.2=If you'd rather not, clicking 'No Thanks' will only enable the essential cookies needed to keep things running smoothly. cookieBanner.popUp.acceptAllBtn=Okay cookieBanner.popUp.acceptNecessaryBtn=No Thanks cookieBanner.popUp.showPreferencesBtn=Manage preferences @@ -1565,7 +1565,7 @@ cookieBanner.preferencesModal.description.2=Stirling PDF cannot—and will never cookieBanner.preferencesModal.description.3=Your privacy and trust are at the core of what we do. cookieBanner.preferencesModal.necessary.title.1=Strictly Necessary Cookies cookieBanner.preferencesModal.necessary.title.2=Always Enabled -cookieBanner.preferencesModal.necessary.description=These cookies are essential for the website to function properly. They enable core features like setting your privacy preferences, logging in, and filling out forms—which is why they can’t be turned off. +cookieBanner.preferencesModal.necessary.description=These cookies are essential for the website to function properly. They enable core features like setting your privacy preferences, logging in, and filling out forms—which is why they can't be turned off. cookieBanner.preferencesModal.analytics.title=Analytics cookieBanner.preferencesModal.analytics.description=These cookies help us understand how our tools are being used, so we can focus on building the features our community values most. Rest assured—Stirling PDF cannot and will never track the content of the documents you work with. @@ -1604,3 +1604,30 @@ fakeScan.blur=Blur fakeScan.noise=Noise fakeScan.yellowish=Yellowish (simulate old paper) fakeScan.resolution=Resolution (DPI) + +#scan-upload +scan-upload.title=Scan and Upload +scan-upload.description=Scan a document or photo with your phone and send it directly to this browser. +scan-upload.instructions.title=Scan this QR code with your phone +scan-upload.instructions.text=Use your phone's camera to scan the QR code, then take a photo of your document. +scan-upload.session=Session ID: +scan-upload.result=Scan Result +scan-upload.download=Download +scan-upload.new-scan=New Scan + +#mobile +mobile.title=Mobile Scanner +mobile.align-document=Align your document within the frame +mobile.retake=Retake +mobile.upload=Upload +mobile.uploading=Uploading... +mobile.success=Success! +mobile.success-message=Your scan has been successfully uploaded +mobile.camera-access=Camera Access Required +mobile.camera-permission=Please allow access to your camera to scan documents +mobile.grant-access=Grant Access + +#home.scan-upload +home.scan-upload.title=Scan and Upload +home.scan-upload.desc=Scan a document with your phone and send it to your browser +scan-upload.tags=scan,upload,photo,camera,mobile \ No newline at end of file diff --git a/src/main/resources/static/css/mobile-scanner.css b/src/main/resources/static/css/mobile-scanner.css new file mode 100644 index 000000000..89ce4edaf --- /dev/null +++ b/src/main/resources/static/css/mobile-scanner.css @@ -0,0 +1,415 @@ +/* Mobile Scanner CSS */ + +body { + background: var(--md-sys-color-background, #000); + color: var(--md-sys-color-on-background, #fff); + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + overflow: hidden; + height: 100vh; /* Fix height to prevent scrolling */ + position: fixed; /* Prevent body scrolling */ + width: 100%; +} + +.app-header { + padding: 10px; + background: rgba(var(--md-elevation-shadow-color-rgb, 0, 0, 0), 0.5); +} + +.input-method-tabs { + display: flex; + border-radius: 8px; + overflow: hidden; + background: rgba(var(--md-sys-color-on-background, 255, 255, 255), 0.1); + margin-bottom: 10px; +} + +.input-tab { + flex: 1; + padding: 12px; + text-align: center; + background: transparent; + border: none; + color: var(--md-sys-color-on-background, #fff); + font-weight: 500; + transition: background 0.3s; + cursor: pointer; +} + +.input-tab.active { + background: var(--md-sys-color-primary, #4CAF50); + color: var(--md-sys-color-on-primary, #fff); +} + +.file-upload-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 70vh; + padding: 20px; +} + +.file-upload-label { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 180px; + height: 180px; + border: 2px dashed var(--md-sys-color-outline, rgba(var(--md-sys-color-on-background, 255, 255, 255), 0.5)); + border-radius: 10px; + cursor: pointer; + transition: all 0.3s; +} + +.file-upload-label:hover { + border-color: var(--md-sys-color-primary, #4CAF50); + background: rgba(255,255,255,0.05); +} + +.upload-icon { + font-size: 48px; + color: var(--md-sys-color-primary, #4CAF50); + margin-bottom: 10px; +} + +.upload-text { + color: var(--md-sys-color-on-background, #fff); + font-size: 16px; +} + +.file-preview-container { + width: 100%; + max-width: 300px; + margin-top: 20px; +} + +.file-preview { + width: 100%; + border-radius: 8px; + margin-bottom: 15px; +} + +.file-actions { + display: flex; + justify-content: space-between; + gap: 8px; +} + +.container, .review-container { + display: flex; + flex-direction: column; + height: calc(100vh - 50px); /* Account for header */ + box-sizing: border-box; + padding: 10px; + overflow: hidden; /* Prevent container scrolling */ +} + +.camera-container { + flex: 1; + position: relative; + background: var(--md-sys-color-surface-container, #222); + border-radius: 10px; + overflow: hidden; + max-height: 70vh; + margin-bottom: 15px; +} + +#camera-view { + width: 100%; + height: 100%; + object-fit: cover; +} + +.controls, .review-controls { + position: fixed; + bottom: 20px; + left: 10px; + right: 10px; + display: flex; + justify-content: space-between; + z-index: 5; +} + +.capture-btn, .review-btn { + border: none; + cursor: pointer; + font-weight: bold; +} + +.capture-btn { + width: 70px; + height: 70px; + border-radius: 50%; + background: white; + position: relative; + border: 3px solid rgba(255,255,255,0.5); + margin: auto; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.3); +} + +.capture-btn::after { + content: ''; + position: absolute; + top: 5px; + left: 5px; + width: 60px; + height: 60px; + background: white; + border-radius: 50%; +} + +.review-container { + display: none; + padding-bottom: 80px; /* Make room for batch preview */ +} + +.preview-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 0; +} + +.preview-header h3 { + margin: 0; + font-size: 18px; + font-weight: 500; +} + +.preview-controls { + display: flex; + align-items: center; + gap: 10px; +} + +.batch-btn { + background: var(--md-sys-color-secondary, #4285F4); + color: var(--md-sys-color-on-secondary, white); + border: none; + border-radius: 20px; + padding: 8px 12px; + font-size: 14px; + font-weight: 500; + cursor: pointer; +} + +.batch-counter { + font-size: 14px; + color: var(--md-sys-color-on-background, white); + opacity: 0.8; +} + +.batch-preview { + position: fixed; + bottom: 80px; /* Positioned above the camera controls */ + left: 0; + right: 0; + background: rgba(var(--md-elevation-shadow-color-rgb, 0, 0, 0), 0.8); + padding: 10px; + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease; + z-index: 6; /* Below the controls (z-index: 10) */ +} + +.loading-message { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(var(--md-elevation-shadow-color-rgb, 0, 0, 0), 0.7); + color: var(--md-sys-color-on-background, #fff); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + font-size: 18px; +} + +.batch-preview.active { + max-height: 120px; +} + +.batch-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.batch-actions { + display: flex; + gap: 8px; +} + +.upload-batch-btn { + background: var(--md-sys-color-primary, #4CAF50); + color: var(--md-sys-color-on-primary, white); + border: none; + border-radius: 15px; + padding: 4px 12px; + font-size: 12px; + font-weight: 500; + cursor: pointer; +} + +.batch-header h4 { + margin: 0; + font-size: 14px; + font-weight: normal; +} + +.clear-btn { + background: var(--md-sys-color-error, #f44336); + color: var(--md-sys-color-on-error, white); + border: none; + border-radius: 15px; + padding: 4px 8px; + font-size: 12px; + cursor: pointer; +} + +.batch-thumbnails { + display: flex; + overflow-x: auto; + gap: 10px; + padding-bottom: 5px; +} + +.batch-thumbnail { + position: relative; + width: 60px; + height: 60px; + flex-shrink: 0; + border-radius: 5px; + overflow: hidden; +} + +.batch-thumbnail img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.remove-thumbnail { + position: absolute; + top: 2px; + right: 2px; + width: 18px; + height: 18px; + background: rgba(var(--md-elevation-shadow-color-rgb, 0, 0, 0), 0.6); + color: var(--md-sys-color-on-error, white); + border: none; + border-radius: 50%; + font-size: 10px; + line-height: 1; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} + +#capture-preview { + width: 100%; + object-fit: contain; + border-radius: 10px; + background: var(--md-sys-color-surface-container, #222); + max-height: 70vh; + flex: 1; +} + +.retake-btn { + background: var(--md-sys-color-error, #f44336); + color: var(--md-sys-color-on-error, white); + border-radius: 25px; + padding: 12px 20px; + width: 45%; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + text-transform: uppercase; + font-weight: 500; + border: none; +} + +.upload-btn { + background: var(--md-sys-color-primary, #4CAF50); + color: var(--md-sys-color-on-primary, white); + border-radius: 25px; + padding: 12px 20px; + width: 45%; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + text-transform: uppercase; + font-weight: 500; + border: none; +} + +.spinner, .success-message, .camera-error { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + justify-content: center; + align-items: center; + flex-direction: column; + z-index: 1000; + text-align: center; +} + +.spinner { + background: rgba(var(--md-elevation-shadow-color-rgb, 0, 0, 0), 0.7); +} + +.spinner-border { + border: 0.25em solid var(--md-sys-color-on-background, white); + border-right-color: transparent; + border-radius: 50%; + width: 3rem; + height: 3rem; + animation: spin 0.75s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.success-message { + background: rgba(var(--md-elevation-shadow-color-rgb, 0, 0, 0), 0.7); + color: var(--md-sys-color-on-background, white); +} + +.success-message i { + font-size: 60px; + color: var(--md-sys-color-primary, #4CAF50); + margin-bottom: 20px; +} + +.camera-error { + background: rgba(var(--md-elevation-shadow-color-rgb, 0, 0, 0), 0.9); + color: var(--md-sys-color-on-background, white); + padding: 20px; +} + +/* Add more polished styling */ +.spinner-text { + margin-top: 15px; + font-size: 16px; + font-weight: 500; +} + +.success-message h2 { + font-weight: 500; + margin-top: 0; +} + +.success-message p { + font-size: 16px; + opacity: 0.9; +} \ No newline at end of file diff --git a/src/main/resources/static/css/scan-upload.css b/src/main/resources/static/css/scan-upload.css new file mode 100644 index 000000000..0f8fe83bb --- /dev/null +++ b/src/main/resources/static/css/scan-upload.css @@ -0,0 +1,119 @@ +/* Scan Upload CSS */ + +.scan-container { + margin: 20px auto; + max-width: 800px; +} + +.card-header h2 { + color: var(--md-sys-color-on-surface, #000); +} + +.card-body { + color: var(--md-sys-color-on-surface, #000); +} + +#qrcode-container, .scan-result-container { + margin: 20px; + text-align: center; +} + +.image-gallery { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 15px; + margin-bottom: 20px; +} + +.image-card { + border-radius: 8px; + overflow: hidden; + background: var(--md-sys-color-surface-container, #fff); + box-shadow: 0 2px 5px rgba(var(--md-elevation-shadow-color-rgb), 0.2); + transition: transform 0.2s ease; +} + +.image-card:hover { + transform: translateY(-3px); +} + +.gallery-image { + width: 100%; + height: 150px; + object-fit: cover; + display: block; +} + +.image-actions { + padding: 10px; + display: flex; + justify-content: space-between; +} + +.image-action-btn { + font-size: 0.8rem; + padding: 0.25rem 0.5rem; +} + +.session-id, .status-msg { + margin-top: 10px; + font-family: monospace; + background: var(--md-sys-color-surface-container-low, #f8f9fa); + color: var(--md-sys-color-on-surface, #000); + padding: 8px; + border-radius: 4px; + display: inline-block; +} + +.actions { + margin-top: 15px; + display: flex; + justify-content: center; + gap: 10px; +} + +.scan-info { + background-color: var(--md-sys-color-surface-variant, #f0f0f0); + border-left: 4px solid var(--md-sys-color-primary, #0d6efd); + padding: 15px; + margin-bottom: 20px; + border-radius: 4px; + color: var(--md-sys-color-on-surface-variant, #000); +} + +.alert-info { + color: var(--md-sys-color-on-surface-variant, #000); +} + +/* Ensure download button has proper colors */ +#download-btn { + background-color: var(--md-sys-color-primary); + color: var(--md-sys-color-on-primary); + border-color: var(--md-sys-color-primary); +} + +#new-scan-btn { + background-color: var(--md-sys-color-secondary); + color: var(--md-sys-color-on-secondary); + border-color: var(--md-sys-color-secondary); +} + +@media (max-width: 768px) { + .scan-container { + margin: 10px; + } + + #qrcode-container, .scan-result-container { + margin: 10px; + } + + .actions { + flex-direction: column; + align-items: center; + } + + .actions .btn { + width: 100%; + margin-bottom: 10px; + } +} \ No newline at end of file diff --git a/src/main/resources/static/js/languageSelection.js b/src/main/resources/static/js/languageSelection.js index 7d4b8bc0c..aadfe309b 100644 --- a/src/main/resources/static/js/languageSelection.js +++ b/src/main/resources/static/js/languageSelection.js @@ -16,8 +16,10 @@ function setLanguageForDropdown(dropdownClass) { function updateUrlWithLanguage(languageCode) { const currentURL = new URL(window.location.href); - currentURL.searchParams.set('lang', languageCode); - window.location.href = currentURL.toString(); + if (currentURL.searchParams.get('lang') !== languageCode) { + currentURL.searchParams.set('lang', languageCode); + window.location.href = currentURL.toString(); + } } function handleDropdownItemClick(event) { @@ -32,15 +34,25 @@ function handleDropdownItemClick(event) { } function checkUserLanguage(defaultLocale) { + const currentLanguageInDOM = document.documentElement.getAttribute('data-language'); + const currentURL = new URL(window.location.href); + const langParam = currentURL.searchParams.get('lang'); + if ( !localStorage.getItem('languageCode') || - document.documentElement.getAttribute('data-language') != defaultLocale + currentLanguageInDOM !== defaultLocale || + langParam !== defaultLocale ) { localStorage.setItem('languageCode', defaultLocale); - updateUrlWithLanguage(defaultLocale); + + if (langParam !== defaultLocale) { + currentURL.searchParams.set('lang', defaultLocale); + window.location.href = currentURL.toString(); + } } } + function initLanguageSettings() { document.addEventListener('DOMContentLoaded', function () { setLanguageForDropdown('.lang_dropdown-item'); diff --git a/src/main/resources/static/js/scan-upload-direct.js b/src/main/resources/static/js/scan-upload-direct.js new file mode 100644 index 000000000..6df4a6a6b --- /dev/null +++ b/src/main/resources/static/js/scan-upload-direct.js @@ -0,0 +1,65 @@ +/** + * Backward compatibility script for scan-upload-direct.js + * This loads the modular version + */ + +// Add async script loading +function loadScript(src, async = true) { + return new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.src = src; + script.async = async; + script.onload = resolve; + script.onerror = reject; + document.head.appendChild(script); + }); +} + +// Load the modules asynchronously +async function loadModules() { + try { + console.info('Loading scan-upload modules via compatibility layer...'); + + // If using type="module" is not supported, load individual scripts + if (typeof window.initScanUploadPC !== 'function' && + typeof window.initScanUploadMobile !== 'function') { + + // Load the necessary scripts + await loadScript('/js/scan-upload/logger.js', true); + await loadScript('/js/scan-upload/peer-connection.js', true); + await loadScript('/js/scan-upload/camera.js', true); + await loadScript('/js/scan-upload/scan-upload.js', true); + + console.info('Modules loaded via compatibility layer'); + } + } catch (error) { + console.error('Error loading modules:', error); + alert('Failed to load scan-upload modules. Please try refreshing the page.'); + } +} + +// Load scripts on page load +document.addEventListener('DOMContentLoaded', loadModules); + +// Forward function calls to the module implementations +window.initScanUploadPC = function() { + if (typeof window.initScanUploadPC === 'function') { + return window.initScanUploadPC(); + } else { + console.error('ScanUpload module not loaded correctly'); + } +}; + +window.initScanUploadMobile = function() { + if (typeof window.initScanUploadMobile === 'function') { + return window.initScanUploadMobile(); + } else { + console.error('ScanUpload module not loaded correctly'); + } +}; + +// Backward compatibility stubs +window.generateRandomId = function() { return 'xxxx-xxxx-xxxx-xxxx'.replace(/[x]/g, () => (Math.random() * 16 | 0).toString(16)); }; +window.updateStatus = function(message) { console.log(message); }; +window.showError = function(message) { alert("Upload Error: " + message); }; +window.logDebug = function(message) { console.log("LOG:", message); }; \ No newline at end of file diff --git a/src/main/resources/static/js/scan-upload/camera.js b/src/main/resources/static/js/scan-upload/camera.js new file mode 100644 index 000000000..f2590057d --- /dev/null +++ b/src/main/resources/static/js/scan-upload/camera.js @@ -0,0 +1,496 @@ +/** + * Camera handling module for the mobile scanner + */ +import Logger from './logger.js'; +import PeerConnection from './peer-connection.js'; + +const Camera = { + stream: null, + capturedImageData: null, + capturedImages: [], + + /** + * Initialize the camera and file upload on mobile device + */ + init: function() { + // Initialize camera + this.initCamera(); + + // Set up tab switching + this.setupTabs(); + + // Set up file upload handling + this.setupFileUpload(); + }, + + /** + * Initialize the camera + */ + initCamera: function() { + navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' }, audio: false }) + .then(stream => { + this.stream = stream; + // Camera stream started + document.getElementById('camera-view').srcObject = stream; + this.setupCameraControls(); + }) + .catch((err) => { + console.error("Camera error:", err); + document.getElementById('camera-error').style.display = 'flex'; + Logger.showError("Camera access denied or unavailable"); + + // Automatically switch to file upload if camera fails + this.switchToFileUpload(); + }); + }, + + /** + * Set up tab switching between camera and file upload + */ + setupTabs: function() { + const cameraTab = document.getElementById('camera-tab'); + const fileTab = document.getElementById('file-tab'); + + if (cameraTab && fileTab) { + cameraTab.addEventListener('click', () => this.switchToCamera()); + fileTab.addEventListener('click', () => this.switchToFileUpload()); + } + }, + + /** + * Switch to camera view + */ + switchToCamera: function() { + document.getElementById('camera-tab').classList.add('active'); + document.getElementById('file-tab').classList.remove('active'); + document.getElementById('camera-container').style.display = 'flex'; + document.getElementById('file-container').style.display = 'none'; + }, + + /** + * Switch to file upload view + */ + switchToFileUpload: function() { + document.getElementById('file-tab').classList.add('active'); + document.getElementById('camera-tab').classList.remove('active'); + document.getElementById('file-container').style.display = 'flex'; + document.getElementById('camera-container').style.display = 'none'; + }, + + /** + * Set up event listeners for camera controls + */ + setupCameraControls: function() { + const captureBtn = document.getElementById('capture-button'); + if (captureBtn) { + captureBtn.onclick = () => this.captureImage(); + } + + const uploadBtn = document.getElementById('upload-button'); + if (uploadBtn) { + uploadBtn.onclick = () => this.uploadImage(); + } else { + console.warn('Upload button not found'); + } + + const retakeBtn = document.getElementById('retake-button'); + if (retakeBtn) { + retakeBtn.onclick = () => this.retakeImage(); + } + + // Add batch-related controls + const addToBatchBtn = document.getElementById('add-to-batch-btn'); + if (addToBatchBtn) { + addToBatchBtn.onclick = () => this.addToBatch(); + } + + const uploadBatchBtn = document.getElementById('upload-batch-btn'); + if (uploadBatchBtn) { + uploadBatchBtn.onclick = () => this.uploadBatch(); + } + + const clearBatchBtn = document.getElementById('clear-batch-btn'); + if (clearBatchBtn) { + clearBatchBtn.onclick = () => this.clearBatch(); + } + }, + + /** + * Set up file upload functionality + */ + setupFileUpload: function() { + const fileInput = document.getElementById('file-input'); + const filePreview = document.getElementById('file-preview'); + const filePreviewContainer = document.getElementById('file-preview-container'); + const cancelFileBtn = document.getElementById('cancel-file-btn'); + const uploadFileBtn = document.getElementById('upload-file-btn'); + const addFileToBatchBtn = document.getElementById('add-file-to-batch-btn'); + + if (fileInput) { + fileInput.onchange = (e) => { + const files = e.target.files; + if (files.length > 0) { + // Handle multiple files if supported + if (files.length === 1) { + // Single file - show preview + const file = files[0]; + const reader = new FileReader(); + reader.onload = (e) => { + filePreview.src = e.target.result; + this.capturedImageData = e.target.result; + filePreviewContainer.style.display = 'block'; + }; + reader.readAsDataURL(file); + } else { + // Multiple files - add all to batch + this.addFilesToBatch(files); + fileInput.value = ''; // Reset input + } + } + }; + } + + if (cancelFileBtn) { + cancelFileBtn.onclick = () => { + fileInput.value = ''; + filePreview.src = ''; + this.capturedImageData = null; + filePreviewContainer.style.display = 'none'; + }; + } + + if (uploadFileBtn) { + uploadFileBtn.onclick = () => { + if (this.capturedImageData) { + this.uploadImage(); + } else { + Logger.showError("No image selected. Please select an image first."); + } + }; + } + + if (addFileToBatchBtn) { + addFileToBatchBtn.onclick = () => { + if (this.capturedImageData) { + // Add current file to batch + this.addFileToBatch(); + } else { + Logger.showError("No image selected. Please select an image first."); + } + }; + } + }, + + /** + * Add current file to batch + */ + addFileToBatch: function() { + if (!this.capturedImageData) { + Logger.showError("No image selected. Please select an image first."); + return; + } + + // Add current image to the batch + this.capturedImages.push(this.capturedImageData); + + // Update batch counter + this.updateBatchCounter(); + + // Add thumbnail to batch preview + this.addThumbnail(this.capturedImageData); + + // Show batch preview if it's the first image + if (this.capturedImages.length === 1) { + document.getElementById('batch-preview').classList.add('active'); + } + + // Reset file input and preview + const fileInput = document.getElementById('file-input'); + const filePreview = document.getElementById('file-preview'); + const filePreviewContainer = document.getElementById('file-preview-container'); + + if (fileInput) fileInput.value = ''; + if (filePreview) filePreview.src = ''; + if (filePreviewContainer) filePreviewContainer.style.display = 'none'; + + this.capturedImageData = null; + }, + + /** + * Add multiple files to batch + * @param {FileList} files - List of files to add + */ + addFilesToBatch: function(files) { + if (!files || files.length === 0) return; + + // Show loading indicator + const loadingMessage = document.createElement('div'); + loadingMessage.className = 'loading-message'; + loadingMessage.textContent = 'Processing files...'; + document.body.appendChild(loadingMessage); + + // Process each file + let processed = 0; + Array.from(files).forEach(file => { + const reader = new FileReader(); + reader.onload = (e) => { + // Add to batch + this.capturedImages.push(e.target.result); + this.addThumbnail(e.target.result); + + processed++; + if (processed === files.length) { + // All files processed + document.body.removeChild(loadingMessage); + + // Update counter and show batch + this.updateBatchCounter(); + document.getElementById('batch-preview').classList.add('active'); + } + }; + reader.readAsDataURL(file); + }); + }, + + /** + * Capture an image from the camera + */ + captureImage: function() { + // Capture button clicked + + const canvas = document.createElement('canvas'); + const video = document.getElementById('camera-view'); + + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + canvas.getContext('2d').drawImage(video, 0, 0); + + this.capturedImageData = canvas.toDataURL('image/jpeg', 0.9); + document.getElementById('capture-preview').src = this.capturedImageData; + + document.querySelector('.container').style.display = 'none'; + document.getElementById('review-container').style.display = 'flex'; + + // Image captured + }, + + /** + * Add the current image to the batch + */ + addToBatch: function() { + if (!this.capturedImageData) { + Logger.showError("No image captured. Please take a picture first."); + return; + } + + // Add current image to the batch + this.capturedImages.push(this.capturedImageData); + + // Update batch counter + this.updateBatchCounter(); + + // Add thumbnail to batch preview + this.addThumbnail(this.capturedImageData); + + // Show batch preview if it's the first image + if (this.capturedImages.length === 1) { + document.getElementById('batch-preview').classList.add('active'); + } + + // Return to camera view + this.retakeImage(); + }, + + /** + * Update the batch counter + */ + updateBatchCounter: function() { + const counter = document.getElementById('batch-counter'); + const count = this.capturedImages.length; + counter.textContent = count + (count === 1 ? ' image' : ' images'); + }, + + /** + * Add a thumbnail to the batch preview + * @param {string} dataUrl - Image data URL + */ + addThumbnail: function(dataUrl) { + const container = document.getElementById('batch-thumbnails'); + const index = this.capturedImages.length - 1; + + const thumbnail = document.createElement('div'); + thumbnail.className = 'batch-thumbnail'; + thumbnail.dataset.index = index; + + const img = document.createElement('img'); + img.src = dataUrl; + img.alt = 'Thumbnail'; + + const removeBtn = document.createElement('button'); + removeBtn.className = 'remove-thumbnail'; + removeBtn.innerHTML = '×'; + removeBtn.onclick = (e) => { + e.stopPropagation(); + this.removeFromBatch(index); + }; + + thumbnail.appendChild(img); + thumbnail.appendChild(removeBtn); + container.appendChild(thumbnail); + }, + + /** + * Remove an image from the batch + * @param {number} index - Index of the image to remove + */ + removeFromBatch: function(index) { + // Remove from array + this.capturedImages.splice(index, 1); + + // Update batch counter + this.updateBatchCounter(); + + // Refresh thumbnails + this.refreshThumbnails(); + + // Hide batch preview if no images left + if (this.capturedImages.length === 0) { + document.getElementById('batch-preview').classList.remove('active'); + } + }, + + /** + * Clear all images from the batch + */ + clearBatch: function() { + this.capturedImages = []; + this.updateBatchCounter(); + document.getElementById('batch-thumbnails').innerHTML = ''; + document.getElementById('batch-preview').classList.remove('active'); + }, + + /** + * Refresh all thumbnails in the batch preview + */ + refreshThumbnails: function() { + const container = document.getElementById('batch-thumbnails'); + container.innerHTML = ''; + + this.capturedImages.forEach((dataUrl, index) => { + this.addThumbnail(dataUrl); + }); + }, + + /** + * Upload all captured images + */ + uploadImage: function() { + // Check if we have images in the batch or just the current preview + if (this.capturedImages.length > 0) { + // Upload all images in the batch + this.uploadBatch(); + } else if (this.capturedImageData) { + // Upload just the current image + PeerConnection.sendImage(this.capturedImageData); + } else { + Logger.showError("No images captured. Please take pictures first."); + } + }, + + /** + * Upload all images in the batch + */ + uploadBatch: function() { + if (this.capturedImages.length === 0) { + Logger.showError("Batch is empty. Please add images first."); + return; + } + + // Show spinner + document.getElementById('spinner').style.display = 'flex'; + + // Send each image sequentially + const totalImages = this.capturedImages.length; + let uploadedCount = 0; + + const sendNextImage = (index) => { + if (index >= this.capturedImages.length) { + // All images sent, send completion notification + PeerConnection.connection.send({ type: 'batch-complete' }); + + // Hide spinner and show success message + setTimeout(() => { + document.getElementById('spinner').style.display = 'none'; + document.getElementById('success-message').style.display = 'flex'; + + // Close window after success + setTimeout(() => window.close(), 3000); + }, 1000); + + return; + } + + // Update spinner text + const spinnerText = document.querySelector('.spinner-text'); + spinnerText.textContent = `Uploading ${index + 1}/${totalImages}`; + + // Send image + const dataUrl = this.capturedImages[index]; + + try { + // Using the peer connection directly for more control + if (PeerConnection.connection && PeerConnection.connection.open) { + PeerConnection.connection.send({ type: 'scan-image', data: dataUrl }); + + // Wait a bit before sending next image to prevent overwhelming the connection + setTimeout(() => sendNextImage(index + 1), 500); + } else { + // Connection not ready yet, set up connection first + PeerConnection.connection = PeerConnection.peer.connect(PeerConnection.sessionId, { reliable: true }); + + PeerConnection.connection.on('open', () => { + PeerConnection.connection.send({ type: 'scan-image', data: dataUrl }); + setTimeout(() => sendNextImage(index + 1), 500); + }); + + PeerConnection.connection.on('error', (err) => { + console.error("Connection error:", err); + Logger.showError("Upload failed: " + (err.message || "unknown error")); + + // Try to continue with remaining images + setTimeout(() => sendNextImage(index + 1), 1000); + }); + } + } catch (err) { + console.error("Send error:", err); + Logger.showError("Failed to send image: " + (err.message || "unknown error")); + + // Try to continue with remaining images + setTimeout(() => sendNextImage(index + 1), 1000); + } + }; + + // Start sending images + sendNextImage(0); + }, + + /** + * Switch back to camera view for retaking the image + */ + retakeImage: function() { + document.querySelector('.container').style.display = 'flex'; + document.getElementById('review-container').style.display = 'none'; + // Retake selected + }, + + /** + * Stop the camera stream + */ + stop: function() { + if (this.stream) { + this.stream.getTracks().forEach(track => track.stop()); + } + } +}; + +export default Camera; \ No newline at end of file diff --git a/src/main/resources/static/js/scan-upload/image-utils.js b/src/main/resources/static/js/scan-upload/image-utils.js new file mode 100644 index 000000000..29fcd590b --- /dev/null +++ b/src/main/resources/static/js/scan-upload/image-utils.js @@ -0,0 +1,79 @@ +/** + * Utility functions for handling images in the scan upload feature + */ + +const ImageUtils = { + /** + * Download all images as a ZIP file + * @param {NodeList} images - Collection of image elements + */ + downloadAllAsZip: function(images) { + if (!images || images.length === 0) { + console.warn('No images to download'); + return; + } + + // Load JSZip dynamically + const script = document.createElement('script'); + script.src = '/js/thirdParty/jszip.min.js'; + script.onload = () => { + this.createZip(images); + }; + script.onerror = () => { + console.error('Failed to load JSZip'); + alert('Failed to load ZIP library. Please try downloading images individually.'); + }; + document.head.appendChild(script); + }, + + /** + * Create ZIP file with images + * @param {NodeList} images - Collection of image elements + */ + createZip: function(images) { + try { + // JSZip is now loaded globally + const zip = new JSZip(); + const timestamp = new Date().toISOString().slice(0, 10); + + // Add each image to the zip + for (let i = 0; i < images.length; i++) { + const img = images[i]; + // Extract base64 data from data URL + const dataUrl = img.src; + const base64Data = dataUrl.split(',')[1]; + + // Add to zip + zip.file(`scan-${i+1}.jpg`, base64Data, {base64: true}); + } + + // Generate the zip file + zip.generateAsync({type: 'blob'}).then((blob) => { + // Create download link + const link = document.createElement('a'); + link.href = URL.createObjectURL(blob); + link.download = `scans-${timestamp}.zip`; + + // Trigger download + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }); + + } catch (error) { + console.error('Error creating ZIP file:', error); + alert('Failed to create ZIP file. Please try downloading images individually.'); + } + }, + + /** + * Convert a data URL to a Blob + * @param {string} url - Data URL + * @returns {Promise} - Promise resolving to a Blob + */ + urlToBlob: function(url) { + return fetch(url).then(response => response.blob()); + } +}; + +export default ImageUtils; \ No newline at end of file diff --git a/src/main/resources/static/js/scan-upload/logger.js b/src/main/resources/static/js/scan-upload/logger.js new file mode 100644 index 000000000..da518b96f --- /dev/null +++ b/src/main/resources/static/js/scan-upload/logger.js @@ -0,0 +1,39 @@ +/** + * Simplified logger module for the scan-upload functionality + */ +const Logger = { + /** + * Log a debug message to the console (disabled in production) + * @param {string} message - Message to log + */ + debug: function(message) { + // Debug logging disabled + }, + + /** + * Update status message in the UI + * @param {string} message - Status message to display + */ + updateStatus: function(message) { + const el = document.getElementById('status-message'); + if (el) { + el.textContent = message; + el.style.display = message ? 'block' : 'none'; + } + }, + + /** + * Show an error message + * @param {string} message - Error message to display + */ + showError: function(message) { + this.updateStatus("Error: " + message); + + // Only show alerts for critical errors + if (message.includes('failed') || message.includes('denied')) { + alert("Upload Error: " + message); + } + } +}; + +export default Logger; \ No newline at end of file diff --git a/src/main/resources/static/js/scan-upload/peer-connection.js b/src/main/resources/static/js/scan-upload/peer-connection.js new file mode 100644 index 000000000..39d67e9d9 --- /dev/null +++ b/src/main/resources/static/js/scan-upload/peer-connection.js @@ -0,0 +1,260 @@ +/** + * WebRTC peer connection module for scan-upload functionality + */ +import Logger from './logger.js'; + +const PeerConnection = { + peer: null, + connection: null, + sessionId: null, + isReceiver: false, + + /** + * Generate a random session ID + * @returns {string} Random session ID + */ + generateRandomId: function() { + return 'xxxx-xxxx-xxxx-xxxx'.replace(/[x]/g, () => (Math.random() * 16 | 0).toString(16)); + }, + + /** + * Initialize a peer connection + * @param {string} id - Peer ID + * @param {boolean} isReceiver - Whether this peer is receiving images + */ + init: function(id, isReceiver) { + this.sessionId = id; + this.isReceiver = isReceiver; + + this.peer = new Peer(id, { + config: { + iceServers: [ + { urls: 'stun:stun.l.google.com:19302' }, + { urls: 'stun:stun1.l.google.com:19302' }, + { urls: 'stun:stun2.l.google.com:19302' }, + { urls: 'turn:numb.viagenie.ca', credential: 'muazkh', username: 'webrtc@live.com' }, + { urls: 'turn:192.158.29.39:3478?transport=udp', credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', username: '28224511:1379330808' }, + { urls: 'turn:192.158.29.39:3478?transport=tcp', credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', username: '28224511:1379330808' }, + { urls: 'turn:turn.bistri.com:80', credential: 'homeo', username: 'homeo' }, + { urls: 'turn:turn.anyfirewall.com:443?transport=tcp', credential: 'webrtc', username: 'webrtc' } + ] + }, + debug: 2 + }); + + // Peer created + + this.setupEventListeners(); + }, + + /** + * Set up event listeners for the peer connection + */ + setupEventListeners: function() { + this.peer.on('disconnected', () => { + console.warn("PeerJS disconnected"); + Logger.showError("Disconnected from PeerJS server"); + }); + + this.peer.on('close', () => { + console.log("PeerJS connection closed"); + }); + + if (this.isReceiver) { + this.peer.on('connection', conn => { + this.connection = conn; + // Receiver connected + + conn.on('data', data => { + if (data.type === 'scan-image') { + Logger.updateStatus('Scan received'); + document.getElementById('qrcode-container').style.display = 'none'; + + // Create new image container for each received image + this.addImageToGallery(data.data); + + document.querySelector('.scan-result-container').style.display = 'block'; + } + else if (data.type === 'batch-complete') { + Logger.updateStatus('Batch upload complete'); + } + }); + }); + } + + this.peer.on('error', (err) => { + console.error("PeerJS Error:", err); + // PeerJS error occurred + Logger.showError("PeerJS error: " + err.type + " - " + (err.message || "unknown")); + }); + }, + + /** + * Send an image to the peer + * @param {string} dataUrl - Image data URL + * @param {boolean} closeAfterSend - Whether to close the window after sending (default: true) + */ + sendImage: function(dataUrl, closeAfterSend = true) { + // Attempt to send image + + if (!this.connection || !this.connection.open) { + // Establishing connection to peer + this.connection = this.peer.connect(this.sessionId, { reliable: true }); + + let waited = 0; + const pollInterval = setInterval(() => { + if (this.connection.open) { + clearInterval(pollInterval); + return; + } + waited += 1000; + if (waited >= 10000) { + clearInterval(pollInterval); + console.warn('Connection still not open after 10s. Forcing retry.'); + Logger.showError('Connection failed after retry. Check network or switch to same Wi-Fi.'); + } else { + // Still waiting for connection + } + }, 1000); + + this.connection.on('open', () => { + // Connection opened + this.connection.send({ type: 'scan-image', data: dataUrl }); + + // Only show success and close window if this is the final image + if (closeAfterSend) { + document.getElementById('spinner').style.display = 'flex'; + setTimeout(() => { + document.getElementById('spinner').style.display = 'none'; + document.getElementById('success-message').style.display = 'flex'; + setTimeout(() => window.close(), 3000); + }, 1000); + } + }); + + this.connection.on('error', (err) => { + clearInterval(pollInterval); + console.error("Connection error:", err); + // Connection error occurred + Logger.showError("Upload failed: " + (err.message || "unknown error")); + }); + } else { + try { + // Using existing connection + this.connection.send({ type: 'scan-image', data: dataUrl }); + + // Only show success and close window if this is the final image + if (closeAfterSend) { + document.getElementById('spinner').style.display = 'flex'; + setTimeout(() => { + document.getElementById('spinner').style.display = 'none'; + document.getElementById('success-message').style.display = 'flex'; + setTimeout(() => window.close(), 3000); + }, 1000); + } + } catch (err) { + console.error("Send error:", err); + // Send error occurred + Logger.showError("Failed to send image: " + (err.message || "unknown error")); + } + } + }, + + /** + * Reset the peer connection + */ + reset: function() { + if (this.peer) { + this.peer.destroy(); + } + this.connection = null; + }, + + /** + * Generate a QR code with the session URL + * @param {string} sessionId - Session ID + * @param {HTMLElement} container - QR code container element + */ + generateQRCode: function(sessionId, container) { + const url = `${window.location.origin}/mobile?session=${sessionId}`; + + // Clear previous QR code if any + container.innerHTML = ''; + + new QRCode(container, { + text: url, + width: 256, + height: 256, + colorDark: "#000", + colorLight: "#fff", + correctLevel: QRCode.CorrectLevel.H + }); + + // Add link below QR code + const a = document.createElement('a'); + a.href = url; + a.textContent = url; + a.style.color = '#0af'; + a.style.display = 'block'; + a.style.marginTop = '10px'; + container.appendChild(a); + }, + + /** + * Add a new image to the gallery + * @param {string} dataUrl - Image data URL + */ + addImageToGallery: function(dataUrl) { + const galleryContainer = document.getElementById('image-gallery'); + if (!galleryContainer) { + console.error('Gallery container not found'); + return; + } + + // Create a new card for the image + const card = document.createElement('div'); + card.className = 'image-card'; + + // Create image element + const img = document.createElement('img'); + img.src = dataUrl; + img.className = 'gallery-image'; + img.alt = 'Scanned Image'; + + // Create download button + const downloadBtn = document.createElement('a'); + downloadBtn.href = dataUrl; + downloadBtn.className = 'btn btn-primary btn-sm image-action-btn'; + downloadBtn.textContent = 'Download'; + downloadBtn.download = `scan-${new Date().getTime()}.jpg`; + + // Create delete button + const deleteBtn = document.createElement('button'); + deleteBtn.className = 'btn btn-danger btn-sm image-action-btn'; + deleteBtn.textContent = 'Remove'; + deleteBtn.onclick = function() { + card.remove(); + + // If all images are removed, hide the gallery + if (galleryContainer.children.length === 0) { + document.querySelector('.scan-result-container').style.display = 'none'; + document.getElementById('qrcode-container').style.display = 'block'; + } + }; + + // Create actions container + const actions = document.createElement('div'); + actions.className = 'image-actions'; + actions.appendChild(downloadBtn); + actions.appendChild(deleteBtn); + + // Add all elements to the card + card.appendChild(img); + card.appendChild(actions); + + // Add the card to the gallery + galleryContainer.appendChild(card); + } +}; + +export default PeerConnection; \ No newline at end of file diff --git a/src/main/resources/static/js/scan-upload/scan-upload.js b/src/main/resources/static/js/scan-upload/scan-upload.js new file mode 100644 index 000000000..6451c81ae --- /dev/null +++ b/src/main/resources/static/js/scan-upload/scan-upload.js @@ -0,0 +1,83 @@ +/** + * Main scan upload module + */ +import Logger from './logger.js'; +import PeerConnection from './peer-connection.js'; +import Camera from './camera.js'; +import ImageUtils from './image-utils.js'; + +/** + * Initialize scan upload on PC/desktop + */ +function initScanUploadPC() { + // Set as receiver (desktop) + PeerConnection.init(PeerConnection.generateRandomId(), true); + + // Display session ID + document.getElementById('session-id').textContent = PeerConnection.sessionId; + + // Generate QR code + const qrcodeContainer = document.getElementById('qrcode'); + PeerConnection.generateQRCode(PeerConnection.sessionId, qrcodeContainer); + + // Set up buttons + document.getElementById('new-scan-btn').onclick = resetConnection; + document.getElementById('download-all-btn').onclick = downloadAllImages; + + // Desktop initialized +} + +/** + * Initialize scan upload on mobile + */ +function initScanUploadMobile() { + // Initialize mobile app + + // Extract session ID from URL + const urlParams = new URLSearchParams(window.location.search); + const sessionId = urlParams.get('session'); + + if (!sessionId) { + Logger.showError('Missing session ID in URL'); + return; + } + + // Initialize peer connection (not as receiver) + PeerConnection.init(PeerConnection.generateRandomId(), false); + PeerConnection.sessionId = sessionId; + + // Initialize camera + Camera.init(); + + // Mobile initialized +} + +/** + * Reset the connection + */ +function resetConnection() { + PeerConnection.reset(); + initScanUploadPC(); +} + +/** + * Download all images as a ZIP + */ +function downloadAllImages() { + const images = document.querySelectorAll('.gallery-image'); + if (images.length === 0) { + alert('No images to download'); + return; + } + + ImageUtils.downloadAllAsZip(images); +} + +// Export functions for global use +window.initScanUploadPC = initScanUploadPC; +window.initScanUploadMobile = initScanUploadMobile; + +// Initialize based on page load +document.addEventListener('DOMContentLoaded', () => { + // This will be initialized from the HTML page based on which view is loaded +}); \ No newline at end of file diff --git a/src/main/resources/static/js/thirdParty/eventemitter.min.js b/src/main/resources/static/js/thirdParty/eventemitter.min.js new file mode 100644 index 000000000..9cba7f93a --- /dev/null +++ b/src/main/resources/static/js/thirdParty/eventemitter.min.js @@ -0,0 +1,7 @@ +/*! + * EventEmitter v5.2.9 - git.io/ee + * Unlicense - http://unlicense.org/ + * Oliver Caldwell - https://oli.me.uk/ + * @preserve + */ +!function(e){"use strict";function t(){}function n(e,t){for(var n=e.length;n--;)if(e[n].listener===t)return n;return-1}function r(e){return function(){return this[e].apply(this,arguments)}}function i(e){return"function"==typeof e||e instanceof RegExp||!(!e||"object"!=typeof e)&&i(e.listener)}var o=t.prototype,s=e.EventEmitter;o.getListeners=function(e){var t,n,r=this._getEvents();if(e instanceof RegExp){t={};for(n in r)r.hasOwnProperty(n)&&e.test(n)&&(t[n]=r[n])}else t=r[e]||(r[e]=[]);return t},o.flattenListeners=function(e){var t,n=[];for(t=0;te.length)&&(t=e.length);for(var r=0,n=new Array(t);r0){var e=new Uint8Array(this._pieces);p.useArrayBufferView||(e=e.buffer),this._parts.push(e),this._pieces=[]}},u.prototype.getBuffer=function(){if(this.flush(),p.useBlobBuilder){for(var e=new d,t=0,r=this._parts.length;t>23&255)-127;return(0===e>>31?1:-1)*(8388607&e|8388608)*Math.pow(2,t-23)},h.prototype.unpack_double=function(){var e=this.unpack_uint32(),t=this.unpack_uint32(),r=(e>>20&2047)-1023;return(0===e>>31?1:-1)*((1048575&e|1048576)*Math.pow(2,r-20)+t*Math.pow(2,r-52))},h.prototype.read=function(e){var t=this.index;if(t+e<=this.length)return this.dataView.subarray(t,t+e);throw new Error("BinaryPackFailure: read index out of range")},m.prototype.getBuffer=function(){return this.bufferBuilder.getBuffer()},m.prototype.pack=function(e){var t=void 0===e?"undefined":c(e);if("string"===t)this.pack_string(e);else if("number"===t)Math.floor(e)===e?this.pack_integer(e):this.pack_double(e);else if("boolean"===t)!0===e?this.bufferBuilder.append(195):!1===e&&this.bufferBuilder.append(194);else if("undefined"===t)this.bufferBuilder.append(192);else{if("object"!==t)throw new Error('Type "'+t+'" not yet supported');if(null===e)this.bufferBuilder.append(192);else{var r=e.constructor;if(r==Array)this.pack_array(e);else if(r==Blob||r==File||e instanceof Blob||e instanceof File)this.pack_bin(e);else if(r==ArrayBuffer)f.useArrayBufferView?this.pack_bin(new Uint8Array(e)):this.pack_bin(e);else if("BYTES_PER_ELEMENT"in e)f.useArrayBufferView?this.pack_bin(new Uint8Array(e.buffer)):this.pack_bin(e.buffer);else if(r==Object||r.toString().startsWith("class"))this.pack_object(e);else if(r==Date)this.pack_string(e.toString());else{if("function"!=typeof e.toBinaryPack)throw new Error('Type "'+r.toString()+'" not yet supported');this.bufferBuilder.append(e.toBinaryPack())}}}this.bufferBuilder.flush()},m.prototype.pack_bin=function(e){var t=e.length||e.byteLength||e.size;if(t<=15)this.pack_uint8(160+t);else if(t<=65535)this.bufferBuilder.append(218),this.pack_uint16(t);else{if(!(t<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(219),this.pack_uint32(t)}this.bufferBuilder.append(e)},m.prototype.pack_string=function(e){var t=function(e){return e.length>600?new Blob([e]).size:e.replace(/[^\u0000-\u007F]/g,v).length}(e);if(t<=15)this.pack_uint8(176+t);else if(t<=65535)this.bufferBuilder.append(216),this.pack_uint16(t);else{if(!(t<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(217),this.pack_uint32(t)}this.bufferBuilder.append(e)},m.prototype.pack_array=function(e){var t=e.length;if(t<=15)this.pack_uint8(144+t);else if(t<=65535)this.bufferBuilder.append(220),this.pack_uint16(t);else{if(!(t<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(221),this.pack_uint32(t)}for(var r=0;r=-32&&e<=127)this.bufferBuilder.append(255&e);else if(e>=0&&e<=255)this.bufferBuilder.append(204),this.pack_uint8(e);else if(e>=-128&&e<=127)this.bufferBuilder.append(208),this.pack_int8(e);else if(e>=0&&e<=65535)this.bufferBuilder.append(205),this.pack_uint16(e);else if(e>=-32768&&e<=32767)this.bufferBuilder.append(209),this.pack_int16(e);else if(e>=0&&e<=4294967295)this.bufferBuilder.append(206),this.pack_uint32(e);else if(e>=-2147483648&&e<=2147483647)this.bufferBuilder.append(210),this.pack_int32(e);else if(e>=-0x8000000000000000&&e<=0x8000000000000000)this.bufferBuilder.append(211),this.pack_int64(e);else{if(!(e>=0&&e<=0x10000000000000000))throw new Error("Invalid integer");this.bufferBuilder.append(207),this.pack_uint64(e)}},m.prototype.pack_double=function(e){var t=0;e<0&&(t=1,e=-e);var r=Math.floor(Math.log(e)/Math.LN2),n=e/Math.pow(2,r)-1,i=Math.floor(n*Math.pow(2,52)),o=Math.pow(2,32),a=t<<31|r+1023<<20|i/o&1048575,s=i%o;this.bufferBuilder.append(203),this.pack_int32(a),this.pack_int32(s)},m.prototype.pack_object=function(e){var t=Object.keys(e).length;if(t<=15)this.pack_uint8(128+t);else if(t<=65535)this.bufferBuilder.append(222),this.pack_uint16(t);else{if(!(t<=4294967295))throw new Error("Invalid length");this.bufferBuilder.append(223),this.pack_uint32(t)}for(var r in e)e.hasOwnProperty(r)&&(this.pack(r),this.pack(e[r]))},m.prototype.pack_uint8=function(e){this.bufferBuilder.append(e)},m.prototype.pack_uint16=function(e){this.bufferBuilder.append(e>>8),this.bufferBuilder.append(255&e)},m.prototype.pack_uint32=function(e){var t=4294967295&e;this.bufferBuilder.append((4278190080&t)>>>24),this.bufferBuilder.append((16711680&t)>>>16),this.bufferBuilder.append((65280&t)>>>8),this.bufferBuilder.append(255&t)},m.prototype.pack_uint64=function(e){var t=e/Math.pow(2,32),r=e%Math.pow(2,32);this.bufferBuilder.append((4278190080&t)>>>24),this.bufferBuilder.append((16711680&t)>>>16),this.bufferBuilder.append((65280&t)>>>8),this.bufferBuilder.append(255&t),this.bufferBuilder.append((4278190080&r)>>>24),this.bufferBuilder.append((16711680&r)>>>16),this.bufferBuilder.append((65280&r)>>>8),this.bufferBuilder.append(255&r)},m.prototype.pack_int8=function(e){this.bufferBuilder.append(255&e)},m.prototype.pack_int16=function(e){this.bufferBuilder.append((65280&e)>>8),this.bufferBuilder.append(255&e)},m.prototype.pack_int32=function(e){this.bufferBuilder.append(e>>>24&255),this.bufferBuilder.append((16711680&e)>>>16),this.bufferBuilder.append((65280&e)>>>8),this.bufferBuilder.append(255&e)},m.prototype.pack_int64=function(e){var t=Math.floor(e/Math.pow(2,32)),r=e%Math.pow(2,32);this.bufferBuilder.append((4278190080&t)>>>24),this.bufferBuilder.append((16711680&t)>>>16),this.bufferBuilder.append((65280&t)>>>8),this.bufferBuilder.append(255&t),this.bufferBuilder.append((4278190080&r)>>>24),this.bufferBuilder.append((16711680&r)>>>16),this.bufferBuilder.append((65280&r)>>>8),this.bufferBuilder.append(255&r)};var y=!0,g=!0;function b(e,t,r){var n=e.match(t);return n&&n.length>=r&&parseInt(n[r],10)}function C(e,t,r){if(e.RTCPeerConnection){var n=e.RTCPeerConnection.prototype,i=n.addEventListener;n.addEventListener=function(e,n){if(e!==t)return i.apply(this,arguments);var o=function(e){var t=r(e);t&&(n.handleEvent?n.handleEvent(t):n(t))};return this._eventMap=this._eventMap||{},this._eventMap[t]||(this._eventMap[t]=new Map),this._eventMap[t].set(n,o),i.apply(this,[e,o])};var o=n.removeEventListener;n.removeEventListener=function(e,r){if(e!==t||!this._eventMap||!this._eventMap[t])return o.apply(this,arguments);if(!this._eventMap[t].has(r))return o.apply(this,arguments);var n=this._eventMap[t].get(r);return this._eventMap[t].delete(r),0===this._eventMap[t].size&&delete this._eventMap[t],0===Object.keys(this._eventMap).length&&delete this._eventMap,o.apply(this,[e,n])},Object.defineProperty(n,"on"+t,{get:function(){return this["_on"+t]},set:function(e){this["_on"+t]&&(this.removeEventListener(t,this["_on"+t]),delete this["_on"+t]),e&&this.addEventListener(t,this["_on"+t]=e)},enumerable:!0,configurable:!0})}}function _(e){return"boolean"!=typeof e?new Error("Argument type: "+(void 0===e?"undefined":c(e))+". Please use a boolean."):(y=e,e?"adapter.js logging disabled":"adapter.js logging enabled")}function S(e){return"boolean"!=typeof e?new Error("Argument type: "+(void 0===e?"undefined":c(e))+". Please use a boolean."):(g=!e,"adapter.js deprecation warnings "+(e?"disabled":"enabled"))}function T(){if("object"==typeof window){if(y)return;"undefined"!=typeof console&&"function"==typeof console.log&&console.log.apply(console,arguments)}}function k(e,t){g&&console.warn(e+" is deprecated, please use "+t+" instead.")}function w(e){var t={browser:null,version:null};if(void 0===e||!e.navigator)return t.browser="Not a browser.",t;var r=e.navigator;if(r.mozGetUserMedia)t.browser="firefox",t.version=b(r.userAgent,/Firefox\/(\d+)\./,1);else if(r.webkitGetUserMedia||!1===e.isSecureContext&&e.webkitRTCPeerConnection&&!e.RTCIceGatherer)t.browser="chrome",t.version=b(r.userAgent,/Chrom(e|ium)\/(\d+)\./,2);else if(r.mediaDevices&&r.userAgent.match(/Edge\/(\d+).(\d+)$/))t.browser="edge",t.version=b(r.userAgent,/Edge\/(\d+).(\d+)$/,2);else{if(!e.RTCPeerConnection||!r.userAgent.match(/AppleWebKit\/(\d+)\./))return t.browser="Not a supported browser.",t;t.browser="safari",t.version=b(r.userAgent,/AppleWebKit\/(\d+)\./,1),t.supportsUnifiedPlan=e.RTCRtpTransceiver&&"currentDirection"in e.RTCRtpTransceiver.prototype}return t}function P(e){return"[object Object]"===Object.prototype.toString.call(e)}function R(e){return P(e)?Object.keys(e).reduce((function(t,r){var n=P(e[r]),i=n?R(e[r]):e[r],a=n&&!Object.keys(i).length;return void 0===i||a?t:Object.assign(t,o({},r,i))}),{}):e}function E(e,t,r){t&&!r.has(t.id)&&(r.set(t.id,t),Object.keys(t).forEach((function(n){n.endsWith("Id")?E(e,e.get(t[n]),r):n.endsWith("Ids")&&t[n].forEach((function(t){E(e,e.get(t),r)}))})))}function x(e,t,r){var n=r?"outbound-rtp":"inbound-rtp",i=new Map;if(null===t)return i;var o=[];return e.forEach((function(e){"track"===e.type&&e.trackIdentifier===t.id&&o.push(e)})),o.forEach((function(t){e.forEach((function(r){r.type===n&&r.trackId===t.id&&E(e,r,i)}))})),i}var D={};t(D,"shimMediaStream",(function(){return j})),t(D,"shimOnTrack",(function(){return A})),t(D,"shimGetSendersWithDtmf",(function(){return L})),t(D,"shimGetStats",(function(){return B})),t(D,"shimSenderReceiverGetStats",(function(){return N})),t(D,"shimAddTrackRemoveTrackWithNative",(function(){return F})),t(D,"shimAddTrackRemoveTrack",(function(){return U})),t(D,"shimPeerConnection",(function(){return z})),t(D,"fixNegotiationNeeded",(function(){return G})),t(D,"shimGetUserMedia",(function(){return I})),t(D,"shimGetDisplayMedia",(function(){return M}));var O=T;function I(e,t){var r=e&&e.navigator;if(r.mediaDevices){var n=function(e){if("object"!=typeof e||e.mandatory||e.optional)return e;var t={};return Object.keys(e).forEach((function(r){if("require"!==r&&"advanced"!==r&&"mediaSource"!==r){var n="object"==typeof e[r]?e[r]:{ideal:e[r]};void 0!==n.exact&&"number"==typeof n.exact&&(n.min=n.max=n.exact);var i=function(e,t){return e?e+t.charAt(0).toUpperCase()+t.slice(1):"deviceId"===t?"sourceId":t};if(void 0!==n.ideal){t.optional=t.optional||[];var o={};"number"==typeof n.ideal?(o[i("min",r)]=n.ideal,t.optional.push(o),(o={})[i("max",r)]=n.ideal,t.optional.push(o)):(o[i("",r)]=n.ideal,t.optional.push(o))}void 0!==n.exact&&"number"!=typeof n.exact?(t.mandatory=t.mandatory||{},t.mandatory[i("",r)]=n.exact):["min","max"].forEach((function(e){void 0!==n[e]&&(t.mandatory=t.mandatory||{},t.mandatory[i(e,r)]=n[e])}))}})),e.advanced&&(t.optional=(t.optional||[]).concat(e.advanced)),t},i=function(e,i){if(t.version>=61)return i(e);if((e=JSON.parse(JSON.stringify(e)))&&"object"==typeof e.audio){var o=function(e,t,r){t in e&&!(r in e)&&(e[r]=e[t],delete e[t])};o((e=JSON.parse(JSON.stringify(e))).audio,"autoGainControl","googAutoGainControl"),o(e.audio,"noiseSuppression","googNoiseSuppression"),e.audio=n(e.audio)}if(e&&"object"==typeof e.video){var a=e.video.facingMode;a=a&&("object"==typeof a?a:{ideal:a});var s,c=t.version<66;if(a&&("user"===a.exact||"environment"===a.exact||"user"===a.ideal||"environment"===a.ideal)&&(!r.mediaDevices.getSupportedConstraints||!r.mediaDevices.getSupportedConstraints().facingMode||c))if(delete e.video.facingMode,"environment"===a.exact||"environment"===a.ideal?s=["back","rear"]:"user"!==a.exact&&"user"!==a.ideal||(s=["front"]),s)return r.mediaDevices.enumerateDevices().then((function(t){var r=(t=t.filter((function(e){return"videoinput"===e.kind}))).find((function(e){return s.some((function(t){return e.label.toLowerCase().includes(t)}))}));return!r&&t.length&&s.includes("back")&&(r=t[t.length-1]),r&&(e.video.deviceId=a.exact?{exact:r.deviceId}:{ideal:r.deviceId}),e.video=n(e.video),O("chrome: "+JSON.stringify(e)),i(e)}));e.video=n(e.video)}return O("chrome: "+JSON.stringify(e)),i(e)},o=function(e){return t.version>=64?e:{name:{PermissionDeniedError:"NotAllowedError",PermissionDismissedError:"NotAllowedError",InvalidStateError:"NotAllowedError",DevicesNotFoundError:"NotFoundError",ConstraintNotSatisfiedError:"OverconstrainedError",TrackStartError:"NotReadableError",MediaDeviceFailedDueToShutdown:"NotAllowedError",MediaDeviceKillSwitchOn:"NotAllowedError",TabCaptureError:"AbortError",ScreenCaptureError:"AbortError",DeviceCaptureError:"AbortError"}[e.name]||e.name,message:e.message,constraint:e.constraint||e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}};if(r.getUserMedia=function(e,t,n){i(e,(function(e){r.webkitGetUserMedia(e,t,(function(e){n&&n(o(e))}))}))}.bind(r),r.mediaDevices.getUserMedia){var a=r.mediaDevices.getUserMedia.bind(r.mediaDevices);r.mediaDevices.getUserMedia=function(e){return i(e,(function(e){return a(e).then((function(t){if(e.audio&&!t.getAudioTracks().length||e.video&&!t.getVideoTracks().length)throw t.getTracks().forEach((function(e){e.stop()})),new DOMException("","NotFoundError");return t}),(function(e){return Promise.reject(o(e))}))}))}}}}function M(e,t){e.navigator.mediaDevices&&"getDisplayMedia"in e.navigator.mediaDevices||e.navigator.mediaDevices&&("function"==typeof t?e.navigator.mediaDevices.getDisplayMedia=function(r){return t(r).then((function(t){var n=r.video&&r.video.width,i=r.video&&r.video.height,o=r.video&&r.video.frameRate;return r.video={mandatory:{chromeMediaSource:"desktop",chromeMediaSourceId:t,maxFrameRate:o||3}},n&&(r.video.mandatory.maxWidth=n),i&&(r.video.mandatory.maxHeight=i),e.navigator.mediaDevices.getUserMedia(r)}))}:console.error("shimGetDisplayMedia: getSourceId argument is not a function"))}function j(e){e.MediaStream=e.MediaStream||e.webkitMediaStream}function A(e){if("object"==typeof e&&e.RTCPeerConnection&&!("ontrack"in e.RTCPeerConnection.prototype)){Object.defineProperty(e.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(e){this._ontrack&&this.removeEventListener("track",this._ontrack),this.addEventListener("track",this._ontrack=e)},enumerable:!0,configurable:!0});var t=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(){if(!this._ontrackpoly){var r=this;this._ontrackpoly=function(t){var n=r;t.stream.addEventListener("addtrack",(function(r){var i;i=e.RTCPeerConnection.prototype.getReceivers?n.getReceivers().find((function(e){return e.track&&e.track.id===r.track.id})):{track:r.track};var o=new Event("track");o.track=r.track,o.receiver=i,o.transceiver={receiver:i},o.streams=[t.stream],n.dispatchEvent(o)})),t.stream.getTracks().forEach((function(r){var i;i=e.RTCPeerConnection.prototype.getReceivers?n.getReceivers().find((function(e){return e.track&&e.track.id===r.id})):{track:r};var o=new Event("track");o.track=r,o.receiver=i,o.transceiver={receiver:i},o.streams=[t.stream],n.dispatchEvent(o)}))},this.addEventListener("addstream",this._ontrackpoly)}return t.apply(this,arguments)}}else C(e,"track",(function(e){return e.transceiver||Object.defineProperty(e,"transceiver",{value:{receiver:e.receiver}}),e}))}function L(e){if("object"==typeof e&&e.RTCPeerConnection&&!("getSenders"in e.RTCPeerConnection.prototype)&&"createDTMFSender"in e.RTCPeerConnection.prototype){var t=function(e,t){return{track:t,get dtmf(){return void 0===this._dtmf&&("audio"===t.kind?this._dtmf=e.createDTMFSender(t):this._dtmf=null),this._dtmf},_pc:e}};if(!e.RTCPeerConnection.prototype.getSenders){e.RTCPeerConnection.prototype.getSenders=function(){return this._senders=this._senders||[],this._senders.slice()};var r=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addTrack=function(e,n){var i=r.apply(this,arguments);return i||(i=t(this,e),this._senders.push(i)),i};var n=e.RTCPeerConnection.prototype.removeTrack;e.RTCPeerConnection.prototype.removeTrack=function(e){n.apply(this,arguments);var t=this._senders.indexOf(e);-1!==t&&this._senders.splice(t,1)}}var i=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(e){var r=this;this._senders=this._senders||[],i.apply(this,[e]),e.getTracks().forEach((function(e){r._senders.push(t(r,e))}))};var o=e.RTCPeerConnection.prototype.removeStream;e.RTCPeerConnection.prototype.removeStream=function(e){var t=this;this._senders=this._senders||[],o.apply(this,[e]),e.getTracks().forEach((function(e){var r=t._senders.find((function(t){return t.track===e}));r&&t._senders.splice(t._senders.indexOf(r),1)}))}}else if("object"==typeof e&&e.RTCPeerConnection&&"getSenders"in e.RTCPeerConnection.prototype&&"createDTMFSender"in e.RTCPeerConnection.prototype&&e.RTCRtpSender&&!("dtmf"in e.RTCRtpSender.prototype)){var a=e.RTCPeerConnection.prototype.getSenders;e.RTCPeerConnection.prototype.getSenders=function(){var e=this,t=a.apply(this,[]);return t.forEach((function(t){return t._pc=e})),t},Object.defineProperty(e.RTCRtpSender.prototype,"dtmf",{get:function(){return void 0===this._dtmf&&("audio"===this.track.kind?this._dtmf=this._pc.createDTMFSender(this.track):this._dtmf=null),this._dtmf}})}}function B(e){if(e.RTCPeerConnection){var t=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){var e=this,r=s(arguments,3),n=r[0],i=r[1],o=r[2];if(arguments.length>0&&"function"==typeof n)return t.apply(this,arguments);if(0===t.length&&(0===arguments.length||"function"!=typeof n))return t.apply(this,[]);var a=function(e){var t={};return e.result().forEach((function(e){var r={id:e.id,timestamp:e.timestamp,type:{localcandidate:"local-candidate",remotecandidate:"remote-candidate"}[e.type]||e.type};e.names().forEach((function(t){r[t]=e.stat(t)})),t[r.id]=r})),t},c=function(e){return new Map(Object.keys(e).map((function(t){return[t,e[t]]})))};if(arguments.length>=2){var p=function(e){i(c(a(e)))};return t.apply(this,[p,n])}return new Promise((function(r,n){t.apply(e,[function(e){r(c(a(e)))},n])})).then(i,o)}}}function N(e){if("object"==typeof e&&e.RTCPeerConnection&&e.RTCRtpSender&&e.RTCRtpReceiver){if(!("getStats"in e.RTCRtpSender.prototype)){var t=e.RTCPeerConnection.prototype.getSenders;t&&(e.RTCPeerConnection.prototype.getSenders=function(){var e=this,r=t.apply(this,[]);return r.forEach((function(t){return t._pc=e})),r});var r=e.RTCPeerConnection.prototype.addTrack;r&&(e.RTCPeerConnection.prototype.addTrack=function(){var e=r.apply(this,arguments);return e._pc=this,e}),e.RTCRtpSender.prototype.getStats=function(){var e=this;return this._pc.getStats().then((function(t){return x(t,e.track,!0)}))}}if(!("getStats"in e.RTCRtpReceiver.prototype)){var n=e.RTCPeerConnection.prototype.getReceivers;n&&(e.RTCPeerConnection.prototype.getReceivers=function(){var e=this,t=n.apply(this,[]);return t.forEach((function(t){return t._pc=e})),t}),C(e,"track",(function(e){return e.receiver._pc=e.srcElement,e})),e.RTCRtpReceiver.prototype.getStats=function(){var e=this;return this._pc.getStats().then((function(t){return x(t,e.track,!1)}))}}if("getStats"in e.RTCRtpSender.prototype&&"getStats"in e.RTCRtpReceiver.prototype){var i=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){if(arguments.length>0&&arguments[0]instanceof e.MediaStreamTrack){var t,r,n,o=arguments[0];return this.getSenders().forEach((function(e){e.track===o&&(t?n=!0:t=e)})),this.getReceivers().forEach((function(e){return e.track===o&&(r?n=!0:r=e),e.track===o})),n||t&&r?Promise.reject(new DOMException("There are more than one sender or receiver for the track.","InvalidAccessError")):t?t.getStats():r?r.getStats():Promise.reject(new DOMException("There is no sender or receiver for the track.","InvalidAccessError"))}return i.apply(this,arguments)}}}}function F(e){e.RTCPeerConnection.prototype.getLocalStreams=function(){var e=this;return this._shimmedLocalStreams=this._shimmedLocalStreams||{},Object.keys(this._shimmedLocalStreams).map((function(t){return e._shimmedLocalStreams[t][0]}))};var t=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addTrack=function(e,r){if(!r)return t.apply(this,arguments);this._shimmedLocalStreams=this._shimmedLocalStreams||{};var n=t.apply(this,arguments);return this._shimmedLocalStreams[r.id]?-1===this._shimmedLocalStreams[r.id].indexOf(n)&&this._shimmedLocalStreams[r.id].push(n):this._shimmedLocalStreams[r.id]=[r,n],n};var r=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(e){var t=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{},e.getTracks().forEach((function(e){if(t.getSenders().find((function(t){return t.track===e})))throw new DOMException("Track already exists.","InvalidAccessError")}));var n=this.getSenders();r.apply(this,arguments);var i=this.getSenders().filter((function(e){return-1===n.indexOf(e)}));this._shimmedLocalStreams[e.id]=[e].concat(i)};var n=e.RTCPeerConnection.prototype.removeStream;e.RTCPeerConnection.prototype.removeStream=function(e){return this._shimmedLocalStreams=this._shimmedLocalStreams||{},delete this._shimmedLocalStreams[e.id],n.apply(this,arguments)};var i=e.RTCPeerConnection.prototype.removeTrack;e.RTCPeerConnection.prototype.removeTrack=function(e){var t=this;return this._shimmedLocalStreams=this._shimmedLocalStreams||{},e&&Object.keys(this._shimmedLocalStreams).forEach((function(r){var n=t._shimmedLocalStreams[r].indexOf(e);-1!==n&&t._shimmedLocalStreams[r].splice(n,1),1===t._shimmedLocalStreams[r].length&&delete t._shimmedLocalStreams[r]})),i.apply(this,arguments)}}function U(e,t){var r=function(e,t){var r=t.sdp;return Object.keys(e._reverseStreams||[]).forEach((function(t){var n=e._reverseStreams[t],i=e._streams[n.id];r=r.replace(new RegExp(i.id,"g"),n.id)})),new RTCSessionDescription({type:t.type,sdp:r})},n=function(e,t){var r=t.sdp;return Object.keys(e._reverseStreams||[]).forEach((function(t){var n=e._reverseStreams[t],i=e._streams[n.id];r=r.replace(new RegExp(n.id,"g"),i.id)})),new RTCSessionDescription({type:t.type,sdp:r})};if(e.RTCPeerConnection){if(e.RTCPeerConnection.prototype.addTrack&&t.version>=65)return F(e);var i=e.RTCPeerConnection.prototype.getLocalStreams;e.RTCPeerConnection.prototype.getLocalStreams=function(){var e=this,t=i.apply(this);return this._reverseStreams=this._reverseStreams||{},t.map((function(t){return e._reverseStreams[t.id]}))};var a=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(t){var r=this;if(this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{},t.getTracks().forEach((function(e){if(r.getSenders().find((function(t){return t.track===e})))throw new DOMException("Track already exists.","InvalidAccessError")})),!this._reverseStreams[t.id]){var n=new e.MediaStream(t.getTracks());this._streams[t.id]=n,this._reverseStreams[n.id]=t,t=n}a.apply(this,[t])};var s=e.RTCPeerConnection.prototype.removeStream;e.RTCPeerConnection.prototype.removeStream=function(e){this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{},s.apply(this,[this._streams[e.id]||e]),delete this._reverseStreams[this._streams[e.id]?this._streams[e.id].id:e.id],delete this._streams[e.id]},e.RTCPeerConnection.prototype.addTrack=function(t,r){if("closed"===this.signalingState)throw new DOMException("The RTCPeerConnection's signalingState is 'closed'.","InvalidStateError");var n=[].slice.call(arguments,1);if(1!==n.length||!n[0].getTracks().find((function(e){return e===t})))throw new DOMException("The adapter.js addTrack polyfill only supports a single stream which is associated with the specified track.","NotSupportedError");var i=this.getSenders().find((function(e){return e.track===t}));if(i)throw new DOMException("Track already exists.","InvalidAccessError");this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{};var o=this._streams[r.id];if(o){var a=this;o.addTrack(t),Promise.resolve().then((function(){a.dispatchEvent(new Event("negotiationneeded"))}))}else{var s=new e.MediaStream([t]);this._streams[r.id]=s,this._reverseStreams[s.id]=r,this.addStream(s)}return this.getSenders().find((function(e){return e.track===t}))},["createOffer","createAnswer"].forEach((function(t){var n=e.RTCPeerConnection.prototype[t],i=o({},t,(function(){var e=this,t=arguments,i=arguments.length&&"function"==typeof arguments[0];return i?n.apply(this,[function(n){var i=r(e,n);t[0].apply(null,[i])},function(e){t[1]&&t[1].apply(null,e)},arguments[2]]):n.apply(this,arguments).then((function(t){return r(e,t)}))}));e.RTCPeerConnection.prototype[t]=i[t]}));var c=e.RTCPeerConnection.prototype.setLocalDescription;e.RTCPeerConnection.prototype.setLocalDescription=function(){return arguments.length&&arguments[0].type?(arguments[0]=n(this,arguments[0]),c.apply(this,arguments)):c.apply(this,arguments)};var p=Object.getOwnPropertyDescriptor(e.RTCPeerConnection.prototype,"localDescription");Object.defineProperty(e.RTCPeerConnection.prototype,"localDescription",{get:function(){var e=p.get.apply(this);return""===e.type?e:r(this,e)}}),e.RTCPeerConnection.prototype.removeTrack=function(e){var t,r=this;if("closed"===this.signalingState)throw new DOMException("The RTCPeerConnection's signalingState is 'closed'.","InvalidStateError");if(!e._pc)throw new DOMException("Argument 1 of RTCPeerConnection.removeTrack does not implement interface RTCRtpSender.","TypeError");if(!(e._pc===this))throw new DOMException("Sender was not created by this connection.","InvalidAccessError");this._streams=this._streams||{},Object.keys(this._streams).forEach((function(n){r._streams[n].getTracks().find((function(t){return e.track===t}))&&(t=r._streams[n])})),t&&(1===t.getTracks().length?this.removeStream(this._reverseStreams[t.id]):t.removeTrack(e.track),this.dispatchEvent(new Event("negotiationneeded")))}}}function z(e,t){!e.RTCPeerConnection&&e.webkitRTCPeerConnection&&(e.RTCPeerConnection=e.webkitRTCPeerConnection),e.RTCPeerConnection&&t.version<53&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(t){var r=e.RTCPeerConnection.prototype[t],n=o({},t,(function(){return arguments[0]=new("addIceCandidate"===t?e.RTCIceCandidate:e.RTCSessionDescription)(arguments[0]),r.apply(this,arguments)}));e.RTCPeerConnection.prototype[t]=n[t]}))}function G(e,t){C(e,"negotiationneeded",(function(e){var r=e.target;if(!(t.version<72||r.getConfiguration&&"plan-b"===r.getConfiguration().sdpSemantics)||"stable"===r.signalingState)return e}))}var V={};t(V,"shimPeerConnection",(function(){return ee})),t(V,"shimReplaceTrack",(function(){return te})),t(V,"shimGetUserMedia",(function(){return Z})),t(V,"shimGetDisplayMedia",(function(){return $}));var J,W={},H={};function K(e,t,r,n,i){var o=W.writeRtpDescription(e.kind,t);if(o+=W.writeIceParameters(e.iceGatherer.getLocalParameters()),o+=W.writeDtlsParameters(e.dtlsTransport.getLocalParameters(),"offer"===r?"actpass":i||"active"),o+="a=mid:"+e.mid+"\r\n",e.rtpSender&&e.rtpReceiver?o+="a=sendrecv\r\n":e.rtpSender?o+="a=sendonly\r\n":e.rtpReceiver?o+="a=recvonly\r\n":o+="a=inactive\r\n",e.rtpSender){var a=e.rtpSender._initialTrackId||e.rtpSender.track.id;e.rtpSender._initialTrackId=a;var s="msid:"+(n?n.id:"-")+" "+a+"\r\n";o+="a="+s,o+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" "+s,e.sendEncodingParameters[0].rtx&&(o+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" "+s,o+="a=ssrc-group:FID "+e.sendEncodingParameters[0].ssrc+" "+e.sendEncodingParameters[0].rtx.ssrc+"\r\n")}return o+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" cname:"+W.localCName+"\r\n",e.rtpSender&&e.sendEncodingParameters[0].rtx&&(o+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" cname:"+W.localCName+"\r\n"),o}function Y(e,t){var r={codecs:[],headerExtensions:[],fecMechanisms:[]},n=function(e,t){e=parseInt(e,10);for(var r=0;r0?t[0].split("/")[1]:"sendrecv",uri:t[1]}},H.writeExtmap=function(e){return"a=extmap:"+(e.id||e.preferredId)+(e.direction&&"sendrecv"!==e.direction?"/"+e.direction:"")+" "+e.uri+"\r\n"},H.parseFmtp=function(e){for(var t,r={},n=e.substr(e.indexOf(" ")+1).split(";"),i=0;i-1?(r.attribute=e.substr(t+1,n-t-1),r.value=e.substr(n+1)):r.attribute=e.substr(t+1),r},H.parseSsrcGroup=function(e){var t=e.substr(13).split(" ");return{semantics:t.shift(),ssrcs:t.map((function(e){return parseInt(e,10)}))}},H.getMid=function(e){var t=H.matchPrefix(e,"a=mid:")[0];if(t)return t.substr(6)},H.parseFingerprint=function(e){var t=e.substr(14).split(" ");return{algorithm:t[0].toLowerCase(),value:t[1]}},H.getDtlsParameters=function(e,t){return{role:"auto",fingerprints:H.matchPrefix(e+t,"a=fingerprint:").map(H.parseFingerprint)}},H.writeDtlsParameters=function(e,t){var r="a=setup:"+t+"\r\n";return e.fingerprints.forEach((function(e){r+="a=fingerprint:"+e.algorithm+" "+e.value+"\r\n"})),r},H.parseCryptoLine=function(e){var t=e.substr(9).split(" ");return{tag:parseInt(t[0],10),cryptoSuite:t[1],keyParams:t[2],sessionParams:t.slice(3)}},H.writeCryptoLine=function(e){return"a=crypto:"+e.tag+" "+e.cryptoSuite+" "+("object"==typeof e.keyParams?H.writeCryptoKeyParams(e.keyParams):e.keyParams)+(e.sessionParams?" "+e.sessionParams.join(" "):"")+"\r\n"},H.parseCryptoKeyParams=function(e){if(0!==e.indexOf("inline:"))return null;var t=e.substr(7).split("|");return{keyMethod:"inline",keySalt:t[0],lifeTime:t[1],mkiValue:t[2]?t[2].split(":")[0]:void 0,mkiLength:t[2]?t[2].split(":")[1]:void 0}},H.writeCryptoKeyParams=function(e){return e.keyMethod+":"+e.keySalt+(e.lifeTime?"|"+e.lifeTime:"")+(e.mkiValue&&e.mkiLength?"|"+e.mkiValue+":"+e.mkiLength:"")},H.getCryptoParameters=function(e,t){return H.matchPrefix(e+t,"a=crypto:").map(H.parseCryptoLine)},H.getIceParameters=function(e,t){var r=H.matchPrefix(e+t,"a=ice-ufrag:")[0],n=H.matchPrefix(e+t,"a=ice-pwd:")[0];return r&&n?{usernameFragment:r.substr(12),password:n.substr(10)}:null},H.writeIceParameters=function(e){return"a=ice-ufrag:"+e.usernameFragment+"\r\na=ice-pwd:"+e.password+"\r\n"},H.parseRtpParameters=function(e){for(var t={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},r=H.splitLines(e)[0].split(" "),n=3;n0?"9":"0",r+=" UDP/TLS/RTP/SAVPF ",r+=t.codecs.map((function(e){return void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType})).join(" ")+"\r\n",r+="c=IN IP4 0.0.0.0\r\n",r+="a=rtcp:9 IN IP4 0.0.0.0\r\n",t.codecs.forEach((function(e){r+=H.writeRtpMap(e),r+=H.writeFmtp(e),r+=H.writeRtcpFb(e)}));var n=0;return t.codecs.forEach((function(e){e.maxptime>n&&(n=e.maxptime)})),n>0&&(r+="a=maxptime:"+n+"\r\n"),r+="a=rtcp-mux\r\n",t.headerExtensions&&t.headerExtensions.forEach((function(e){r+=H.writeExtmap(e)})),r},H.parseRtpEncodingParameters=function(e){var t,r=[],n=H.parseRtpParameters(e),i=-1!==n.fecMechanisms.indexOf("RED"),o=-1!==n.fecMechanisms.indexOf("ULPFEC"),a=H.matchPrefix(e,"a=ssrc:").map((function(e){return H.parseSsrcMedia(e)})).filter((function(e){return"cname"===e.attribute})),s=a.length>0&&a[0].ssrc,c=H.matchPrefix(e,"a=ssrc-group:FID").map((function(e){return e.substr(17).split(" ").map((function(e){return parseInt(e,10)}))}));c.length>0&&c[0].length>1&&c[0][0]===s&&(t=c[0][1]),n.codecs.forEach((function(e){if("RTX"===e.name.toUpperCase()&&e.parameters.apt){var n={ssrc:s,codecPayloadType:parseInt(e.parameters.apt,10)};s&&t&&(n.rtx={ssrc:t}),r.push(n),i&&((n=JSON.parse(JSON.stringify(n))).fec={ssrc:s,mechanism:o?"red+ulpfec":"red"},r.push(n))}})),0===r.length&&s&&r.push({ssrc:s});var p=H.matchPrefix(e,"b=");return p.length&&(p=0===p[0].indexOf("b=TIAS:")?parseInt(p[0].substr(7),10):0===p[0].indexOf("b=AS:")?950*parseInt(p[0].substr(5),10)-16e3:void 0,r.forEach((function(e){e.maxBitrate=p}))),r},H.parseRtcpParameters=function(e){var t={},r=H.matchPrefix(e,"a=ssrc:").map((function(e){return H.parseSsrcMedia(e)})).filter((function(e){return"cname"===e.attribute}))[0];r&&(t.cname=r.value,t.ssrc=r.ssrc);var n=H.matchPrefix(e,"a=rtcp-rsize");t.reducedSize=n.length>0,t.compound=0===n.length;var i=H.matchPrefix(e,"a=rtcp-mux");return t.mux=i.length>0,t},H.parseMsid=function(e){var t,r=H.matchPrefix(e,"a=msid:");if(1===r.length)return{stream:(t=r[0].substr(7).split(" "))[0],track:t[1]};var n=H.matchPrefix(e,"a=ssrc:").map((function(e){return H.parseSsrcMedia(e)})).filter((function(e){return"msid"===e.attribute}));return n.length>0?{stream:(t=n[0].value.split(" "))[0],track:t[1]}:void 0},H.parseSctpDescription=function(e){var t,r=H.parseMLine(e),n=H.matchPrefix(e,"a=max-message-size:");n.length>0&&(t=parseInt(n[0].substr(19),10)),isNaN(t)&&(t=65536);var i=H.matchPrefix(e,"a=sctp-port:");if(i.length>0)return{port:parseInt(i[0].substr(12),10),protocol:r.fmt,maxMessageSize:t};if(H.matchPrefix(e,"a=sctpmap:").length>0){var o=H.matchPrefix(e,"a=sctpmap:")[0].substr(10).split(" ");return{port:parseInt(o[0],10),protocol:o[1],maxMessageSize:t}}},H.writeSctpDescription=function(e,t){var r=[];return r="DTLS/SCTP"!==e.protocol?["m="+e.kind+" 9 "+e.protocol+" "+t.protocol+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctp-port:"+t.port+"\r\n"]:["m="+e.kind+" 9 "+e.protocol+" "+t.port+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctpmap:"+t.port+" "+t.protocol+" 65535\r\n"],void 0!==t.maxMessageSize&&r.push("a=max-message-size:"+t.maxMessageSize+"\r\n"),r.join("")},H.generateSessionId=function(){return Math.random().toString().substr(2,21)},H.writeSessionBoilerplate=function(e,t,r){var n=void 0!==t?t:2;return"v=0\r\no="+(r||"thisisadapterortc")+" "+(e||H.generateSessionId())+" "+n+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},H.writeMediaSection=function(e,t,r,n){var i=H.writeRtpDescription(e.kind,t);if(i+=H.writeIceParameters(e.iceGatherer.getLocalParameters()),i+=H.writeDtlsParameters(e.dtlsTransport.getLocalParameters(),"offer"===r?"actpass":"active"),i+="a=mid:"+e.mid+"\r\n",e.direction?i+="a="+e.direction+"\r\n":e.rtpSender&&e.rtpReceiver?i+="a=sendrecv\r\n":e.rtpSender?i+="a=sendonly\r\n":e.rtpReceiver?i+="a=recvonly\r\n":i+="a=inactive\r\n",e.rtpSender){var o="msid:"+n.id+" "+e.rtpSender.track.id+"\r\n";i+="a="+o,i+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" "+o,e.sendEncodingParameters[0].rtx&&(i+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" "+o,i+="a=ssrc-group:FID "+e.sendEncodingParameters[0].ssrc+" "+e.sendEncodingParameters[0].rtx.ssrc+"\r\n")}return i+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" cname:"+H.localCName+"\r\n",e.rtpSender&&e.sendEncodingParameters[0].rtx&&(i+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" cname:"+H.localCName+"\r\n"),i},H.getDirection=function(e,t){for(var r=H.splitLines(e),n=0;n=14393&&-1===e.indexOf("?transport=udp"):(r=!0,!0)})),delete e.url,e.urls=i?n[0]:n,!!n.length}}))}(r.iceServers||[],t),this._iceGatherers=[],r.iceCandidatePoolSize)for(var o=r.iceCandidatePoolSize;o>0;o--)this._iceGatherers.push(new e.RTCIceGatherer({iceServers:r.iceServers,gatherPolicy:r.iceTransportPolicy}));else r.iceCandidatePoolSize=0;this._config=r,this.transceivers=[],this._sdpSessionId=W.generateSessionId(),this._sdpSessionVersion=0,this._dtlsRole=void 0,this._isClosed=!1};Object.defineProperty(i.prototype,"localDescription",{configurable:!0,get:function(){return this._localDescription}}),Object.defineProperty(i.prototype,"remoteDescription",{configurable:!0,get:function(){return this._remoteDescription}}),i.prototype.onicecandidate=null,i.prototype.onaddstream=null,i.prototype.ontrack=null,i.prototype.onremovestream=null,i.prototype.onsignalingstatechange=null,i.prototype.oniceconnectionstatechange=null,i.prototype.onconnectionstatechange=null,i.prototype.onicegatheringstatechange=null,i.prototype.onnegotiationneeded=null,i.prototype.ondatachannel=null,i.prototype._dispatchEvent=function(e,t){this._isClosed||(this.dispatchEvent(t),"function"==typeof this["on"+e]&&this["on"+e](t))},i.prototype._emitGatheringStateChange=function(){var e=new Event("icegatheringstatechange");this._dispatchEvent("icegatheringstatechange",e)},i.prototype.getConfiguration=function(){return this._config},i.prototype.getLocalStreams=function(){return this.localStreams},i.prototype.getRemoteStreams=function(){return this.remoteStreams},i.prototype._createTransceiver=function(e,t){var r=this.transceivers.length>0,n={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:e,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,associatedRemoteMediaStreams:[],wantReceive:!0};if(this.usingBundle&&r)n.iceTransport=this.transceivers[0].iceTransport,n.dtlsTransport=this.transceivers[0].dtlsTransport;else{var i=this._createIceAndDtlsTransports();n.iceTransport=i.iceTransport,n.dtlsTransport=i.dtlsTransport}return t||this.transceivers.push(n),n},i.prototype.addTrack=function(t,r){if(this._isClosed)throw X("InvalidStateError","Attempted to call addTrack on a closed peerconnection.");var n;if(this.transceivers.find((function(e){return e.track===t})))throw X("InvalidAccessError","Track already exists.");for(var i=0;i=15025)e.getTracks().forEach((function(t){r.addTrack(t,e)}));else{var n=e.clone();e.getTracks().forEach((function(e,t){var r=n.getTracks()[t];e.addEventListener("enabled",(function(e){r.enabled=e.enabled}))})),n.getTracks().forEach((function(e){r.addTrack(e,n)}))}},i.prototype.removeTrack=function(t){if(this._isClosed)throw X("InvalidStateError","Attempted to call removeTrack on a closed peerconnection.");if(!(t instanceof e.RTCRtpSender))throw new TypeError("Argument 1 of RTCPeerConnection.removeTrack does not implement interface RTCRtpSender.");var r=this.transceivers.find((function(e){return e.rtpSender===t}));if(!r)throw X("InvalidAccessError","Sender was not created by this connection.");var n=r.stream;r.rtpSender.stop(),r.rtpSender=null,r.track=null,r.stream=null,-1===this.transceivers.map((function(e){return e.stream})).indexOf(n)&&this.localStreams.indexOf(n)>-1&&this.localStreams.splice(this.localStreams.indexOf(n),1),this._maybeFireNegotiationNeeded()},i.prototype.removeStream=function(e){var t=this;e.getTracks().forEach((function(e){var r=t.getSenders().find((function(t){return t.track===e}));r&&t.removeTrack(r)}))},i.prototype.getSenders=function(){return this.transceivers.filter((function(e){return!!e.rtpSender})).map((function(e){return e.rtpSender}))},i.prototype.getReceivers=function(){return this.transceivers.filter((function(e){return!!e.rtpReceiver})).map((function(e){return e.rtpReceiver}))},i.prototype._createIceGatherer=function(t,r){var n=this;if(r&&t>0)return this.transceivers[0].iceGatherer;if(this._iceGatherers.length)return this._iceGatherers.shift();var i=new e.RTCIceGatherer({iceServers:this._config.iceServers,gatherPolicy:this._config.iceTransportPolicy});return Object.defineProperty(i,"state",{value:"new",writable:!0}),this.transceivers[t].bufferedCandidateEvents=[],this.transceivers[t].bufferCandidates=function(e){var r=!e.candidate||0===Object.keys(e.candidate).length;i.state=r?"completed":"gathering",null!==n.transceivers[t].bufferedCandidateEvents&&n.transceivers[t].bufferedCandidateEvents.push(e)},i.addEventListener("localcandidate",this.transceivers[t].bufferCandidates),i},i.prototype._gather=function(t,r){var n=this,i=this.transceivers[r].iceGatherer;if(!i.onlocalcandidate){var o=this.transceivers[r].bufferedCandidateEvents;this.transceivers[r].bufferedCandidateEvents=null,i.removeEventListener("localcandidate",this.transceivers[r].bufferCandidates),i.onlocalcandidate=function(e){if(!(n.usingBundle&&r>0)){var o=new Event("icecandidate");o.candidate={sdpMid:t,sdpMLineIndex:r};var a=e.candidate,s=!a||0===Object.keys(a).length;if(s)"new"!==i.state&&"gathering"!==i.state||(i.state="completed");else{"new"===i.state&&(i.state="gathering"),a.component=1,a.ufrag=i.getLocalParameters().usernameFragment;var c=W.writeCandidate(a);o.candidate=Object.assign(o.candidate,W.parseCandidate(c)),o.candidate.candidate=c,o.candidate.toJSON=function(){return{candidate:o.candidate.candidate,sdpMid:o.candidate.sdpMid,sdpMLineIndex:o.candidate.sdpMLineIndex,usernameFragment:o.candidate.usernameFragment}}}var p=W.getMediaSections(n._localDescription.sdp);p[o.candidate.sdpMLineIndex]+=s?"a=end-of-candidates\r\n":"a="+o.candidate.candidate+"\r\n",n._localDescription.sdp=W.getDescription(n._localDescription.sdp)+p.join("");var d=n.transceivers.every((function(e){return e.iceGatherer&&"completed"===e.iceGatherer.state}));"gathering"!==n.iceGatheringState&&(n.iceGatheringState="gathering",n._emitGatheringStateChange()),s||n._dispatchEvent("icecandidate",o),d&&(n._dispatchEvent("icecandidate",new Event("icecandidate")),n.iceGatheringState="complete",n._emitGatheringStateChange())}},e.setTimeout((function(){o.forEach((function(e){i.onlocalcandidate(e)}))}),0)}},i.prototype._createIceAndDtlsTransports=function(){var t=this,r=new e.RTCIceTransport(null);r.onicestatechange=function(){t._updateIceConnectionState(),t._updateConnectionState()};var n=new e.RTCDtlsTransport(r);return n.ondtlsstatechange=function(){t._updateConnectionState()},n.onerror=function(){Object.defineProperty(n,"state",{value:"failed",writable:!0}),t._updateConnectionState()},{iceTransport:r,dtlsTransport:n}},i.prototype._disposeIceAndDtlsTransports=function(e){var t=this.transceivers[e].iceGatherer;t&&(delete t.onlocalcandidate,delete this.transceivers[e].iceGatherer);var r=this.transceivers[e].iceTransport;r&&(delete r.onicestatechange,delete this.transceivers[e].iceTransport);var n=this.transceivers[e].dtlsTransport;n&&(delete n.ondtlsstatechange,delete n.onerror,delete this.transceivers[e].dtlsTransport)},i.prototype._transceive=function(e,r,n){var i=Y(e.localCapabilities,e.remoteCapabilities);r&&e.rtpSender&&(i.encodings=e.sendEncodingParameters,i.rtcp={cname:W.localCName,compound:e.rtcpParameters.compound},e.recvEncodingParameters.length&&(i.rtcp.ssrc=e.recvEncodingParameters[0].ssrc),e.rtpSender.send(i)),n&&e.rtpReceiver&&i.codecs.length>0&&("video"===e.kind&&e.recvEncodingParameters&&t<15019&&e.recvEncodingParameters.forEach((function(e){delete e.rtx})),e.recvEncodingParameters.length?i.encodings=e.recvEncodingParameters:i.encodings=[{}],i.rtcp={compound:e.rtcpParameters.compound},e.rtcpParameters.cname&&(i.rtcp.cname=e.rtcpParameters.cname),e.sendEncodingParameters.length&&(i.rtcp.ssrc=e.sendEncodingParameters[0].ssrc),e.rtpReceiver.receive(i))},i.prototype.setLocalDescription=function(e){var t,r,n=this;if(-1===["offer","answer"].indexOf(e.type))return Promise.reject(X("TypeError",'Unsupported type "'+e.type+'"'));if(!q("setLocalDescription",e.type,n.signalingState)||n._isClosed)return Promise.reject(X("InvalidStateError","Can not set local "+e.type+" in state "+n.signalingState));if("offer"===e.type)t=W.splitSections(e.sdp),r=t.shift(),t.forEach((function(e,t){var r=W.parseRtpParameters(e);n.transceivers[t].localCapabilities=r})),n.transceivers.forEach((function(e,t){n._gather(e.mid,t)}));else if("answer"===e.type){t=W.splitSections(n._remoteDescription.sdp),r=t.shift();var i=W.matchPrefix(r,"a=ice-lite").length>0;t.forEach((function(e,t){var o=n.transceivers[t],a=o.iceGatherer,s=o.iceTransport,c=o.dtlsTransport,p=o.localCapabilities,d=o.remoteCapabilities;if(!(W.isRejected(e)&&0===W.matchPrefix(e,"a=bundle-only").length)&&!o.rejected){var u=W.getIceParameters(e,r),l=W.getDtlsParameters(e,r);i&&(l.role="server"),n.usingBundle&&0!==t||(n._gather(o.mid,t),"new"===s.state&&s.start(a,u,i?"controlling":"controlled"),"new"===c.state&&c.start(l));var f=Y(p,d);n._transceive(o,f.codecs.length>0,!1)}}))}return n._localDescription={type:e.type,sdp:e.sdp},"offer"===e.type?n._updateSignalingState("have-local-offer"):n._updateSignalingState("stable"),Promise.resolve()},i.prototype.setRemoteDescription=function(i){var o=this;if(-1===["offer","answer"].indexOf(i.type))return Promise.reject(X("TypeError",'Unsupported type "'+i.type+'"'));if(!q("setRemoteDescription",i.type,o.signalingState)||o._isClosed)return Promise.reject(X("InvalidStateError","Can not set remote "+i.type+" in state "+o.signalingState));var a={};o.remoteStreams.forEach((function(e){a[e.id]=e}));var s=[],c=W.splitSections(i.sdp),p=c.shift(),d=W.matchPrefix(p,"a=ice-lite").length>0,u=W.matchPrefix(p,"a=group:BUNDLE ").length>0;o.usingBundle=u;var l=W.matchPrefix(p,"a=ice-options:")[0];return o.canTrickleIceCandidates=!!l&&l.substr(14).split(" ").indexOf("trickle")>=0,c.forEach((function(n,c){var l=W.splitLines(n),f=W.getKind(n),h=W.isRejected(n)&&0===W.matchPrefix(n,"a=bundle-only").length,m=l[0].substr(2).split(" ")[2],v=W.getDirection(n,p),y=W.parseMsid(n),g=W.getMid(n)||W.generateIdentifier();if(h||"application"===f&&("DTLS/SCTP"===m||"UDP/DTLS/SCTP"===m))o.transceivers[c]={mid:g,kind:f,protocol:m,rejected:!0};else{var b,C,_,S,T,k,w,P,R;!h&&o.transceivers[c]&&o.transceivers[c].rejected&&(o.transceivers[c]=o._createTransceiver(f,!0));var E,x,D=W.parseRtpParameters(n);h||(E=W.getIceParameters(n,p),(x=W.getDtlsParameters(n,p)).role="client"),w=W.parseRtpEncodingParameters(n);var O=W.parseRtcpParameters(n),I=W.matchPrefix(n,"a=end-of-candidates",p).length>0,M=W.matchPrefix(n,"a=candidate:").map((function(e){return W.parseCandidate(e)})).filter((function(e){return 1===e.component}));if(("offer"===i.type||"answer"===i.type)&&!h&&u&&c>0&&o.transceivers[c]&&(o._disposeIceAndDtlsTransports(c),o.transceivers[c].iceGatherer=o.transceivers[0].iceGatherer,o.transceivers[c].iceTransport=o.transceivers[0].iceTransport,o.transceivers[c].dtlsTransport=o.transceivers[0].dtlsTransport,o.transceivers[c].rtpSender&&o.transceivers[c].rtpSender.setTransport(o.transceivers[0].dtlsTransport),o.transceivers[c].rtpReceiver&&o.transceivers[c].rtpReceiver.setTransport(o.transceivers[0].dtlsTransport)),"offer"!==i.type||h){if("answer"===i.type&&!h){C=(b=o.transceivers[c]).iceGatherer,_=b.iceTransport,S=b.dtlsTransport,T=b.rtpReceiver,k=b.sendEncodingParameters,P=b.localCapabilities,o.transceivers[c].recvEncodingParameters=w,o.transceivers[c].remoteCapabilities=D,o.transceivers[c].rtcpParameters=O,M.length&&"new"===_.state&&(!d&&!I||u&&0!==c?M.forEach((function(e){Q(b.iceTransport,e)})):_.setRemoteCandidates(M)),u&&0!==c||("new"===_.state&&_.start(C,E,"controlling"),"new"===S.state&&S.start(x)),!Y(b.localCapabilities,b.remoteCapabilities).codecs.filter((function(e){return"rtx"===e.name.toLowerCase()})).length&&b.sendEncodingParameters[0].rtx&&delete b.sendEncodingParameters[0].rtx,o._transceive(b,"sendrecv"===v||"recvonly"===v,"sendrecv"===v||"sendonly"===v),!T||"sendrecv"!==v&&"sendonly"!==v?delete b.rtpReceiver:(R=T.track,y?(a[y.stream]||(a[y.stream]=new e.MediaStream),r(R,a[y.stream]),s.push([R,T,a[y.stream]])):(a.default||(a.default=new e.MediaStream),r(R,a.default),s.push([R,T,a.default])))}}else{(b=o.transceivers[c]||o._createTransceiver(f)).mid=g,b.iceGatherer||(b.iceGatherer=o._createIceGatherer(c,u)),M.length&&"new"===b.iceTransport.state&&(!I||u&&0!==c?M.forEach((function(e){Q(b.iceTransport,e)})):b.iceTransport.setRemoteCandidates(M)),P=e.RTCRtpReceiver.getCapabilities(f),t<15019&&(P.codecs=P.codecs.filter((function(e){return"rtx"!==e.name}))),k=b.sendEncodingParameters||[{ssrc:1001*(2*c+2)}];var j,A=!1;if("sendrecv"===v||"sendonly"===v){if(A=!b.rtpReceiver,T=b.rtpReceiver||new e.RTCRtpReceiver(b.dtlsTransport,f),A)R=T.track,y&&"-"===y.stream||(y?(a[y.stream]||(a[y.stream]=new e.MediaStream,Object.defineProperty(a[y.stream],"id",{get:function(){return y.stream}})),Object.defineProperty(R,"id",{get:function(){return y.track}}),j=a[y.stream]):(a.default||(a.default=new e.MediaStream),j=a.default)),j&&(r(R,j),b.associatedRemoteMediaStreams.push(j)),s.push([R,T,j])}else b.rtpReceiver&&b.rtpReceiver.track&&(b.associatedRemoteMediaStreams.forEach((function(t){var r=t.getTracks().find((function(e){return e.id===b.rtpReceiver.track.id}));r&&function(t,r){r.removeTrack(t),r.dispatchEvent(new e.MediaStreamTrackEvent("removetrack",{track:t}))}(r,t)})),b.associatedRemoteMediaStreams=[]);b.localCapabilities=P,b.remoteCapabilities=D,b.rtpReceiver=T,b.rtcpParameters=O,b.sendEncodingParameters=k,b.recvEncodingParameters=w,o._transceive(o.transceivers[c],!1,A)}}})),void 0===o._dtlsRole&&(o._dtlsRole="offer"===i.type?"active":"passive"),o._remoteDescription={type:i.type,sdp:i.sdp},"offer"===i.type?o._updateSignalingState("have-remote-offer"):o._updateSignalingState("stable"),Object.keys(a).forEach((function(t){var r=a[t];if(r.getTracks().length){if(-1===o.remoteStreams.indexOf(r)){o.remoteStreams.push(r);var i=new Event("addstream");i.stream=r,e.setTimeout((function(){o._dispatchEvent("addstream",i)}))}s.forEach((function(e){var t=e[0],i=e[1];r.id===e[2].id&&n(o,t,i,[r])}))}})),s.forEach((function(e){e[2]||n(o,e[0],e[1],[])})),e.setTimeout((function(){o&&o.transceivers&&o.transceivers.forEach((function(e){e.iceTransport&&"new"===e.iceTransport.state&&e.iceTransport.getRemoteCandidates().length>0&&(console.warn("Timeout for addRemoteCandidate. Consider sending an end-of-candidates notification"),e.iceTransport.addRemoteCandidate({}))}))}),4e3),Promise.resolve()},i.prototype.close=function(){this.transceivers.forEach((function(e){e.iceTransport&&e.iceTransport.stop(),e.dtlsTransport&&e.dtlsTransport.stop(),e.rtpSender&&e.rtpSender.stop(),e.rtpReceiver&&e.rtpReceiver.stop()})),this._isClosed=!0,this._updateSignalingState("closed")},i.prototype._updateSignalingState=function(e){this.signalingState=e;var t=new Event("signalingstatechange");this._dispatchEvent("signalingstatechange",t)},i.prototype._maybeFireNegotiationNeeded=function(){var t=this;"stable"===this.signalingState&&!0!==this.needNegotiation&&(this.needNegotiation=!0,e.setTimeout((function(){if(t.needNegotiation){t.needNegotiation=!1;var e=new Event("negotiationneeded");t._dispatchEvent("negotiationneeded",e)}}),0))},i.prototype._updateIceConnectionState=function(){var e,t={new:0,closed:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};if(this.transceivers.forEach((function(e){e.iceTransport&&!e.rejected&&t[e.iceTransport.state]++})),e="new",t.failed>0?e="failed":t.checking>0?e="checking":t.disconnected>0?e="disconnected":t.new>0?e="new":t.connected>0?e="connected":t.completed>0&&(e="completed"),e!==this.iceConnectionState){this.iceConnectionState=e;var r=new Event("iceconnectionstatechange");this._dispatchEvent("iceconnectionstatechange",r)}},i.prototype._updateConnectionState=function(){var e,t={new:0,closed:0,connecting:0,connected:0,completed:0,disconnected:0,failed:0};if(this.transceivers.forEach((function(e){e.iceTransport&&e.dtlsTransport&&!e.rejected&&(t[e.iceTransport.state]++,t[e.dtlsTransport.state]++)})),t.connected+=t.completed,e="new",t.failed>0?e="failed":t.connecting>0?e="connecting":t.disconnected>0?e="disconnected":t.new>0?e="new":t.connected>0&&(e="connected"),e!==this.connectionState){this.connectionState=e;var r=new Event("connectionstatechange");this._dispatchEvent("connectionstatechange",r)}},i.prototype.createOffer=function(){var r=this;if(r._isClosed)return Promise.reject(X("InvalidStateError","Can not call createOffer after close"));var n=r.transceivers.filter((function(e){return"audio"===e.kind})).length,i=r.transceivers.filter((function(e){return"video"===e.kind})).length,o=arguments[0];if(o){if(o.mandatory||o.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==o.offerToReceiveAudio&&(n=!0===o.offerToReceiveAudio?1:!1===o.offerToReceiveAudio?0:o.offerToReceiveAudio),void 0!==o.offerToReceiveVideo&&(i=!0===o.offerToReceiveVideo?1:!1===o.offerToReceiveVideo?0:o.offerToReceiveVideo)}for(r.transceivers.forEach((function(e){"audio"===e.kind?--n<0&&(e.wantReceive=!1):"video"===e.kind&&--i<0&&(e.wantReceive=!1)}));n>0||i>0;)n>0&&(r._createTransceiver("audio"),n--),i>0&&(r._createTransceiver("video"),i--);var a=W.writeSessionBoilerplate(r._sdpSessionId,r._sdpSessionVersion++);r.transceivers.forEach((function(n,i){var o=n.track,a=n.kind,s=n.mid||W.generateIdentifier();n.mid=s,n.iceGatherer||(n.iceGatherer=r._createIceGatherer(i,r.usingBundle));var c=e.RTCRtpSender.getCapabilities(a);t<15019&&(c.codecs=c.codecs.filter((function(e){return"rtx"!==e.name}))),c.codecs.forEach((function(e){"H264"===e.name&&void 0===e.parameters["level-asymmetry-allowed"]&&(e.parameters["level-asymmetry-allowed"]="1"),n.remoteCapabilities&&n.remoteCapabilities.codecs&&n.remoteCapabilities.codecs.forEach((function(t){e.name.toLowerCase()===t.name.toLowerCase()&&e.clockRate===t.clockRate&&(e.preferredPayloadType=t.payloadType)}))})),c.headerExtensions.forEach((function(e){(n.remoteCapabilities&&n.remoteCapabilities.headerExtensions||[]).forEach((function(t){e.uri===t.uri&&(e.id=t.id)}))}));var p=n.sendEncodingParameters||[{ssrc:1001*(2*i+1)}];o&&t>=15019&&"video"===a&&!p[0].rtx&&(p[0].rtx={ssrc:p[0].ssrc+1}),n.wantReceive&&(n.rtpReceiver=new e.RTCRtpReceiver(n.dtlsTransport,a)),n.localCapabilities=c,n.sendEncodingParameters=p})),"max-compat"!==r._config.bundlePolicy&&(a+="a=group:BUNDLE "+r.transceivers.map((function(e){return e.mid})).join(" ")+"\r\n"),a+="a=ice-options:trickle\r\n",r.transceivers.forEach((function(e,t){a+=K(e,e.localCapabilities,"offer",e.stream,r._dtlsRole),a+="a=rtcp-rsize\r\n",!e.iceGatherer||"new"===r.iceGatheringState||0!==t&&r.usingBundle||(e.iceGatherer.getLocalCandidates().forEach((function(e){e.component=1,a+="a="+W.writeCandidate(e)+"\r\n"})),"completed"===e.iceGatherer.state&&(a+="a=end-of-candidates\r\n"))}));var s=new e.RTCSessionDescription({type:"offer",sdp:a});return Promise.resolve(s)},i.prototype.createAnswer=function(){var r=this;if(r._isClosed)return Promise.reject(X("InvalidStateError","Can not call createAnswer after close"));if("have-remote-offer"!==r.signalingState&&"have-local-pranswer"!==r.signalingState)return Promise.reject(X("InvalidStateError","Can not call createAnswer in signalingState "+r.signalingState));var n=W.writeSessionBoilerplate(r._sdpSessionId,r._sdpSessionVersion++);r.usingBundle&&(n+="a=group:BUNDLE "+r.transceivers.map((function(e){return e.mid})).join(" ")+"\r\n"),n+="a=ice-options:trickle\r\n";var i=W.getMediaSections(r._remoteDescription.sdp).length;r.transceivers.forEach((function(e,o){if(!(o+1>i)){if(e.rejected)return"application"===e.kind?"DTLS/SCTP"===e.protocol?n+="m=application 0 DTLS/SCTP 5000\r\n":n+="m=application 0 "+e.protocol+" webrtc-datachannel\r\n":"audio"===e.kind?n+="m=audio 0 UDP/TLS/RTP/SAVPF 0\r\na=rtpmap:0 PCMU/8000\r\n":"video"===e.kind&&(n+="m=video 0 UDP/TLS/RTP/SAVPF 120\r\na=rtpmap:120 VP8/90000\r\n"),void(n+="c=IN IP4 0.0.0.0\r\na=inactive\r\na=mid:"+e.mid+"\r\n");var a;if(e.stream)"audio"===e.kind?a=e.stream.getAudioTracks()[0]:"video"===e.kind&&(a=e.stream.getVideoTracks()[0]),a&&t>=15019&&"video"===e.kind&&!e.sendEncodingParameters[0].rtx&&(e.sendEncodingParameters[0].rtx={ssrc:e.sendEncodingParameters[0].ssrc+1});var s=Y(e.localCapabilities,e.remoteCapabilities);!s.codecs.filter((function(e){return"rtx"===e.name.toLowerCase()})).length&&e.sendEncodingParameters[0].rtx&&delete e.sendEncodingParameters[0].rtx,n+=K(e,s,"answer",e.stream,r._dtlsRole),e.rtcpParameters&&e.rtcpParameters.reducedSize&&(n+="a=rtcp-rsize\r\n")}}));var o=new e.RTCSessionDescription({type:"answer",sdp:n});return Promise.resolve(o)},i.prototype.addIceCandidate=function(e){var t,r=this;return e&&void 0===e.sdpMLineIndex&&!e.sdpMid?Promise.reject(new TypeError("sdpMLineIndex or sdpMid required")):new Promise((function(n,i){if(!r._remoteDescription)return i(X("InvalidStateError","Can not add ICE candidate without a remote description"));if(e&&""!==e.candidate){var o=e.sdpMLineIndex;if(e.sdpMid)for(var a=0;a0?W.parseCandidate(e.candidate):{};if("tcp"===c.protocol&&(0===c.port||9===c.port))return n();if(c.component&&1!==c.component)return n();if((0===o||o>0&&s.iceTransport!==r.transceivers[0].iceTransport)&&!Q(s.iceTransport,c))return i(X("OperationError","Can not add ICE candidate"));var p=e.candidate.trim();0===p.indexOf("a=")&&(p=p.substr(2)),(t=W.getMediaSections(r._remoteDescription.sdp))[o]+="a="+(c.type?p:"end-of-candidates")+"\r\n",r._remoteDescription.sdp=W.getDescription(r._remoteDescription.sdp)+t.join("")}else for(var d=0;d55&&"autoGainControl"in r.mediaDevices.getSupportedConstraints())){var i=function(e,t,r){t in e&&!(r in e)&&(e[r]=e[t],delete e[t])},o=r.mediaDevices.getUserMedia.bind(r.mediaDevices);if(r.mediaDevices.getUserMedia=function(e){return"object"==typeof e&&"object"==typeof e.audio&&(e=JSON.parse(JSON.stringify(e)),i(e.audio,"autoGainControl","mozAutoGainControl"),i(e.audio,"noiseSuppression","mozNoiseSuppression")),o(e)},n&&n.prototype.getSettings){var a=n.prototype.getSettings;n.prototype.getSettings=function(){var e=a.apply(this,arguments);return i(e,"mozAutoGainControl","autoGainControl"),i(e,"mozNoiseSuppression","noiseSuppression"),e}}if(n&&n.prototype.applyConstraints){var s=n.prototype.applyConstraints;n.prototype.applyConstraints=function(e){return"audio"===this.kind&&"object"==typeof e&&(e=JSON.parse(JSON.stringify(e)),i(e,"autoGainControl","mozAutoGainControl"),i(e,"noiseSuppression","mozNoiseSuppression")),s.apply(this,[e])}}}}function ie(e,t){e.navigator.mediaDevices&&"getDisplayMedia"in e.navigator.mediaDevices||e.navigator.mediaDevices&&(e.navigator.mediaDevices.getDisplayMedia=function(r){if(!r||!r.video){var n=new DOMException("getDisplayMedia without video constraints is undefined");return n.name="NotFoundError",n.code=8,Promise.reject(n)}return!0===r.video?r.video={mediaSource:t}:r.video.mediaSource=t,e.navigator.mediaDevices.getUserMedia(r)})}function oe(e){"object"==typeof e&&e.RTCTrackEvent&&"receiver"in e.RTCTrackEvent.prototype&&!("transceiver"in e.RTCTrackEvent.prototype)&&Object.defineProperty(e.RTCTrackEvent.prototype,"transceiver",{get:function(){return{receiver:this.receiver}}})}function ae(e,t){if("object"==typeof e&&(e.RTCPeerConnection||e.mozRTCPeerConnection)){!e.RTCPeerConnection&&e.mozRTCPeerConnection&&(e.RTCPeerConnection=e.mozRTCPeerConnection),t.version<53&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(t){var r=e.RTCPeerConnection.prototype[t],n=o({},t,(function(){return arguments[0]=new("addIceCandidate"===t?e.RTCIceCandidate:e.RTCSessionDescription)(arguments[0]),r.apply(this,arguments)}));e.RTCPeerConnection.prototype[t]=n[t]}));var r={inboundrtp:"inbound-rtp",outboundrtp:"outbound-rtp",candidatepair:"candidate-pair",localcandidate:"local-candidate",remotecandidate:"remote-candidate"},n=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){var e=s(arguments,3),i=e[0],o=e[1],a=e[2];return n.apply(this,[i||null]).then((function(e){if(t.version<53&&!o)try{e.forEach((function(e){e.type=r[e.type]||e.type}))}catch(t){if("TypeError"!==t.name)throw t;e.forEach((function(t,n){e.set(n,Object.assign({},t,{type:r[t.type]||t.type}))}))}return e})).then(o,a)}}}function se(e){if("object"==typeof e&&e.RTCPeerConnection&&e.RTCRtpSender&&(!e.RTCRtpSender||!("getStats"in e.RTCRtpSender.prototype))){var t=e.RTCPeerConnection.prototype.getSenders;t&&(e.RTCPeerConnection.prototype.getSenders=function(){var e=this,r=t.apply(this,[]);return r.forEach((function(t){return t._pc=e})),r});var r=e.RTCPeerConnection.prototype.addTrack;r&&(e.RTCPeerConnection.prototype.addTrack=function(){var e=r.apply(this,arguments);return e._pc=this,e}),e.RTCRtpSender.prototype.getStats=function(){return this.track?this._pc.getStats(this.track):Promise.resolve(new Map)}}}function ce(e){if("object"==typeof e&&e.RTCPeerConnection&&e.RTCRtpSender&&(!e.RTCRtpSender||!("getStats"in e.RTCRtpReceiver.prototype))){var t=e.RTCPeerConnection.prototype.getReceivers;t&&(e.RTCPeerConnection.prototype.getReceivers=function(){var e=this,r=t.apply(this,[]);return r.forEach((function(t){return t._pc=e})),r}),C(e,"track",(function(e){return e.receiver._pc=e.srcElement,e})),e.RTCRtpReceiver.prototype.getStats=function(){return this._pc.getStats(this.track)}}}function pe(e){e.RTCPeerConnection&&!("removeStream"in e.RTCPeerConnection.prototype)&&(e.RTCPeerConnection.prototype.removeStream=function(e){var t=this;k("removeStream","removeTrack"),this.getSenders().forEach((function(r){r.track&&e.getTracks().includes(r.track)&&t.removeTrack(r)}))})}function de(e){e.DataChannel&&!e.RTCDataChannel&&(e.RTCDataChannel=e.DataChannel)}function ue(e){if("object"==typeof e&&e.RTCPeerConnection){var t=e.RTCPeerConnection.prototype.addTransceiver;t&&(e.RTCPeerConnection.prototype.addTransceiver=function(){this.setParametersPromises=[];var e=arguments[1],r=e&&"sendEncodings"in e;r&&e.sendEncodings.forEach((function(e){if("rid"in e){if(!/^[a-z0-9]{0,16}$/i.test(e.rid))throw new TypeError("Invalid RID value provided.")}if("scaleResolutionDownBy"in e&&!(parseFloat(e.scaleResolutionDownBy)>=1))throw new RangeError("scale_resolution_down_by must be >= 1.0");if("maxFramerate"in e&&!(parseFloat(e.maxFramerate)>=0))throw new RangeError("max_framerate must be >= 0.0")}));var n=t.apply(this,arguments);if(r){var i=n.sender,o=i.getParameters();(!("encodings"in o)||1===o.encodings.length&&0===Object.keys(o.encodings[0]).length)&&(o.encodings=e.sendEncodings,i.sendEncodings=e.sendEncodings,this.setParametersPromises.push(i.setParameters(o).then((function(){delete i.sendEncodings})).catch((function(){delete i.sendEncodings}))))}return n})}}function le(e){if("object"==typeof e&&e.RTCRtpSender){var t=e.RTCRtpSender.prototype.getParameters;t&&(e.RTCRtpSender.prototype.getParameters=function(){var e=t.apply(this,arguments);return"encodings"in e||(e.encodings=[].concat(this.sendEncodings||[{}])),e})}}function fe(e){if("object"==typeof e&&e.RTCPeerConnection){var t=e.RTCPeerConnection.prototype.createOffer;e.RTCPeerConnection.prototype.createOffer=function(){var e=this,r=arguments;return this.setParametersPromises&&this.setParametersPromises.length?Promise.all(this.setParametersPromises).then((function(){return t.apply(e,r)})).finally((function(){e.setParametersPromises=[]})):t.apply(this,arguments)}}}function he(e){if("object"==typeof e&&e.RTCPeerConnection){var t=e.RTCPeerConnection.prototype.createAnswer;e.RTCPeerConnection.prototype.createAnswer=function(){var e=this,r=arguments;return this.setParametersPromises&&this.setParametersPromises.length?Promise.all(this.setParametersPromises).then((function(){return t.apply(e,r)})).finally((function(){e.setParametersPromises=[]})):t.apply(this,arguments)}}}t(re,"shimOnTrack",(function(){return oe})),t(re,"shimPeerConnection",(function(){return ae})),t(re,"shimSenderGetStats",(function(){return se})),t(re,"shimReceiverGetStats",(function(){return ce})),t(re,"shimRemoveStream",(function(){return pe})),t(re,"shimRTCDataChannel",(function(){return de})),t(re,"shimAddTransceiver",(function(){return ue})),t(re,"shimGetParameters",(function(){return le})),t(re,"shimCreateOffer",(function(){return fe})),t(re,"shimCreateAnswer",(function(){return he})),t(re,"shimGetUserMedia",(function(){return ne})),t(re,"shimGetDisplayMedia",(function(){return ie}));var me={};function ve(e){if("object"==typeof e&&e.RTCPeerConnection){if("getLocalStreams"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.getLocalStreams=function(){return this._localStreams||(this._localStreams=[]),this._localStreams}),!("addStream"in e.RTCPeerConnection.prototype)){var t=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addStream=function(e){var r=this;this._localStreams||(this._localStreams=[]),this._localStreams.includes(e)||this._localStreams.push(e),e.getAudioTracks().forEach((function(n){return t.call(r,n,e)})),e.getVideoTracks().forEach((function(n){return t.call(r,n,e)}))},e.RTCPeerConnection.prototype.addTrack=function(e){for(var r=arguments.length,n=new Array(r>1?r-1:0),i=1;i=0)){e._remoteStreams.push(t);var r=new Event("addstream");r.stream=t,e.dispatchEvent(r)}}))}),t.apply(e,arguments)}}}function ge(e){if("object"==typeof e&&e.RTCPeerConnection){var t=e.RTCPeerConnection.prototype,r=t.createOffer,n=t.createAnswer,i=t.setLocalDescription,o=t.setRemoteDescription,a=t.addIceCandidate;t.createOffer=function(e,t){var n=arguments.length>=2?arguments[2]:arguments[0],i=r.apply(this,[n]);return t?(i.then(e,t),Promise.resolve()):i},t.createAnswer=function(e,t){var r=arguments.length>=2?arguments[2]:arguments[0],i=n.apply(this,[r]);return t?(i.then(e,t),Promise.resolve()):i};var s=function(e,t,r){var n=i.apply(this,[e]);return r?(n.then(t,r),Promise.resolve()):n};t.setLocalDescription=s,s=function(e,t,r){var n=o.apply(this,[e]);return r?(n.then(t,r),Promise.resolve()):n},t.setRemoteDescription=s,s=function(e,t,r){var n=a.apply(this,[e]);return r?(n.then(t,r),Promise.resolve()):n},t.addIceCandidate=s}}function be(e){var t=e&&e.navigator;if(t.mediaDevices&&t.mediaDevices.getUserMedia){var r=t.mediaDevices,n=r.getUserMedia.bind(r);t.mediaDevices.getUserMedia=function(e){return n(Ce(e))}}!t.getUserMedia&&t.mediaDevices&&t.mediaDevices.getUserMedia&&(t.getUserMedia=function(e,r,n){t.mediaDevices.getUserMedia(e).then(r,n)}.bind(t))}function Ce(e){return e&&void 0!==e.video?Object.assign({},e,{video:R(e.video)}):e}function _e(e){if(e.RTCPeerConnection){var t=e.RTCPeerConnection;e.RTCPeerConnection=function(e,r){if(e&&e.iceServers){for(var n=[],i=0;i0?i=parseInt(o[0].substr(19),10):"firefox"===r.browser&&-1!==n&&(i=2147483637),i},s=t.RTCPeerConnection.prototype.setRemoteDescription;t.RTCPeerConnection.prototype.setRemoteDescription=function(){if(this._sctp=null,"chrome"===r.browser&&r.version>=76){var e=this.getConfiguration().sdpSemantics;"plan-b"===e&&Object.defineProperty(this,"sctp",{get:function(){return void 0===this._sctp?null:this._sctp},enumerable:!0,configurable:!0})}if(n(arguments[0])){var t,c=i(arguments[0]),p=o(c),d=a(arguments[0],c);t=0===p&&0===d?Number.POSITIVE_INFINITY:0===p||0===d?Math.max(p,d):Math.min(p,d);var u={};Object.defineProperty(u,"maxMessageSize",{get:function(){return t}}),this._sctp=u}return s.apply(this,arguments)}}}function Ee(e){var t=function(e,t){var r=e.send;e.send=function(){var n=arguments[0],i=n.length||n.size||n.byteLength;if("open"===e.readyState&&t.sctp&&i>t.sctp.maxMessageSize)throw new TypeError("Message too large (can send a maximum of "+t.sctp.maxMessageSize+" bytes)");return r.apply(e,arguments)}};if(e.RTCPeerConnection&&"createDataChannel"in e.RTCPeerConnection.prototype){var r=e.RTCPeerConnection.prototype.createDataChannel;e.RTCPeerConnection.prototype.createDataChannel=function(){var e=r.apply(this,arguments);return t(e,this),e},C(e,"datachannel",(function(e){return t(e.channel,e.target),e}))}}function xe(e){if(e.RTCPeerConnection&&!("connectionState"in e.RTCPeerConnection.prototype)){var t=e.RTCPeerConnection.prototype;Object.defineProperty(t,"connectionState",{get:function(){return{completed:"connected",checking:"connecting"}[this.iceConnectionState]||this.iceConnectionState},enumerable:!0,configurable:!0}),Object.defineProperty(t,"onconnectionstatechange",{get:function(){return this._onconnectionstatechange||null},set:function(e){this._onconnectionstatechange&&(this.removeEventListener("connectionstatechange",this._onconnectionstatechange),delete this._onconnectionstatechange),e&&this.addEventListener("connectionstatechange",this._onconnectionstatechange=e)},enumerable:!0,configurable:!0}),["setLocalDescription","setRemoteDescription"].forEach((function(e){var r=t[e];t[e]=function(){return this._connectionstatechangepoly||(this._connectionstatechangepoly=function(e){var t=e.target;if(t._lastConnectionState!==t.connectionState){t._lastConnectionState=t.connectionState;var r=new Event("connectionstatechange",e);t.dispatchEvent(r)}return e},this.addEventListener("iceconnectionstatechange",this._connectionstatechangepoly)),r.apply(this,arguments)}}))}}function De(e,t){if(e.RTCPeerConnection&&!("chrome"===t.browser&&t.version>=71||"safari"===t.browser&&t.version>=605)){var r=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(t){if(t&&t.sdp&&-1!==t.sdp.indexOf("\na=extmap-allow-mixed")){var n=t.sdp.split("\n").filter((function(e){return"a=extmap-allow-mixed"!==e.trim()})).join("\n");e.RTCSessionDescription&&t instanceof e.RTCSessionDescription?arguments[0]=new e.RTCSessionDescription({type:t.type,sdp:n}):t.sdp=n}return r.apply(this,arguments)}}}function Oe(e,t){if(e.RTCPeerConnection&&e.RTCPeerConnection.prototype){var r=e.RTCPeerConnection.prototype.addIceCandidate;r&&0!==r.length&&(e.RTCPeerConnection.prototype.addIceCandidate=function(){return arguments[0]?("chrome"===t.browser&&t.version<78||"firefox"===t.browser&&t.version<68||"safari"===t.browser)&&arguments[0]&&""===arguments[0].candidate?Promise.resolve():r.apply(this,arguments):(arguments[1]&&arguments[1].apply(null),Promise.resolve())})}}t(we,"shimRTCIceCandidate",(function(){return Pe})),t(we,"shimMaxMessageSize",(function(){return Re})),t(we,"shimSendThrowTypeError",(function(){return Ee})),t(we,"shimConnectionState",(function(){return xe})),t(we,"removeExtmapAllowMixed",(function(){return De})),t(we,"shimAddIceCandidateNullOrEmpty",(function(){return Oe}));var Ie,Me,je=function(){var e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).window,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{shimChrome:!0,shimFirefox:!0,shimEdge:!0,shimSafari:!0},r=T,n=w(e),i={browserDetails:n,commonShim:we,extractVersion:b,disableLog:_,disableWarnings:S};switch(n.browser){case"chrome":if(!D||!D.shimPeerConnection||!t.shimChrome)return r("Chrome shim is not included in this adapter release."),i;if(null===n.version)return r("Chrome shim can not determine version, not shimming."),i;r("adapter.js shimming chrome."),i.browserShim=D,we.shimAddIceCandidateNullOrEmpty(e,n),D.shimGetUserMedia(e,n),D.shimMediaStream(e,n),D.shimPeerConnection(e,n),D.shimOnTrack(e,n),D.shimAddTrackRemoveTrack(e,n),D.shimGetSendersWithDtmf(e,n),D.shimGetStats(e,n),D.shimSenderReceiverGetStats(e,n),D.fixNegotiationNeeded(e,n),we.shimRTCIceCandidate(e,n),we.shimConnectionState(e,n),we.shimMaxMessageSize(e,n),we.shimSendThrowTypeError(e,n),we.removeExtmapAllowMixed(e,n);break;case"firefox":if(!re||!re.shimPeerConnection||!t.shimFirefox)return r("Firefox shim is not included in this adapter release."),i;r("adapter.js shimming firefox."),i.browserShim=re,we.shimAddIceCandidateNullOrEmpty(e,n),re.shimGetUserMedia(e,n),re.shimPeerConnection(e,n),re.shimOnTrack(e,n),re.shimRemoveStream(e,n),re.shimSenderGetStats(e,n),re.shimReceiverGetStats(e,n),re.shimRTCDataChannel(e,n),re.shimAddTransceiver(e,n),re.shimGetParameters(e,n),re.shimCreateOffer(e,n),re.shimCreateAnswer(e,n),we.shimRTCIceCandidate(e,n),we.shimConnectionState(e,n),we.shimMaxMessageSize(e,n),we.shimSendThrowTypeError(e,n);break;case"edge":if(!V||!V.shimPeerConnection||!t.shimEdge)return r("MS edge shim is not included in this adapter release."),i;r("adapter.js shimming edge."),i.browserShim=V,V.shimGetUserMedia(e,n),V.shimGetDisplayMedia(e,n),V.shimPeerConnection(e,n),V.shimReplaceTrack(e,n),we.shimMaxMessageSize(e,n),we.shimSendThrowTypeError(e,n);break;case"safari":if(!me||!t.shimSafari)return r("Safari shim is not included in this adapter release."),i;r("adapter.js shimming safari."),i.browserShim=me,we.shimAddIceCandidateNullOrEmpty(e,n),me.shimRTCIceServerUrls(e,n),me.shimCreateOfferLegacy(e,n),me.shimCallbacksAPI(e,n),me.shimLocalStreamsAPI(e,n),me.shimRemoteStreamsAPI(e,n),me.shimTrackEventTransceiver(e,n),me.shimGetUserMedia(e,n),me.shimAudioContext(e,n),we.shimRTCIceCandidate(e,n),we.shimMaxMessageSize(e,n),we.shimSendThrowTypeError(e,n),we.removeExtmapAllowMixed(e,n);break;default:r("Unsupported browser!")}return i}({window:"undefined"==typeof window?void 0:window}),Ae=je,Le=Ae.default||Ae,Be=new((Ie=function(){this.isIOS=["iPad","iPhone","iPod"].includes(navigator.platform),this.supportedBrowsers=["firefox","chrome","safari"],this.minFirefoxVersion=59,this.minChromeVersion=72,this.minSafariVersion=605}).prototype.isWebRTCSupported=function(){return"undefined"!=typeof RTCPeerConnection},Ie.prototype.isBrowserSupported=function(){var e=this.getBrowser(),t=this.getVersion();return!!this.supportedBrowsers.includes(e)&&("chrome"===e?t>=this.minChromeVersion:"firefox"===e?t>=this.minFirefoxVersion:"safari"===e&&!this.isIOS&&t>=this.minSafariVersion)},Ie.prototype.getBrowser=function(){return Le.browserDetails.browser},Ie.prototype.getVersion=function(){return Le.browserDetails.version||0},Ie.prototype.isUnifiedPlanSupported=function(){var e,t=this.getBrowser(),r=Le.browserDetails.version||0;if("chrome"===t&&r=this.minFirefoxVersion)return!0;if(!window.RTCRtpTransceiver||!("currentDirection"in RTCRtpTransceiver.prototype))return!1;var n=!1;try{(e=new RTCPeerConnection).addTransceiver("audio"),n=!0}catch(e){}finally{e&&e.close()}return n},Ie.prototype.toString=function(){return"Supports:\n browser:".concat(this.getBrowser(),"\n version:").concat(this.getVersion(),"\n isIOS:").concat(this.isIOS,"\n isWebRTCSupported:").concat(this.isWebRTCSupported(),"\n isBrowserSupported:").concat(this.isBrowserSupported(),"\n isUnifiedPlanSupported:").concat(this.isUnifiedPlanSupported())},Ie),Ne={iceServers:[{urls:"stun:stun.l.google.com:19302"},{urls:["turn:eu-0.turn.peerjs.com:3478","turn:us-0.turn.peerjs.com:3478"],username:"peerjs",credential:"peerjsp"}],sdpSemantics:"unified-plan"},Fe=new((Me=function(){this.CLOUD_HOST="0.peerjs.com",this.CLOUD_PORT=443,this.chunkedBrowsers={Chrome:1,chrome:1},this.chunkedMTU=16300,this.defaultConfig=Ne,this.browser=Be.getBrowser(),this.browserVersion=Be.getVersion(),this.supports=function(){var e,t={browser:Be.isBrowserSupported(),webRTC:Be.isWebRTCSupported(),audioVideo:!1,data:!1,binaryBlob:!1,reliable:!1};if(!t.webRTC)return t;try{e=new RTCPeerConnection(Ne),t.audioVideo=!0;var r=void 0;try{r=e.createDataChannel("_PEERJSTEST",{ordered:!0}),t.data=!0,t.reliable=!!r.ordered;try{r.binaryType="blob",t.binaryBlob=!Be.isIOS}catch(e){}}catch(e){}finally{r&&r.close()}}catch(e){}finally{e&&e.close()}return t}(),this.pack=e(r).pack,this.unpack=e(r).unpack,this._dataCount=1}).prototype.noop=function(){},Me.prototype.validateId=function(e){return!e||/^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/.test(e)},Me.prototype.chunk=function(e){for(var t=[],r=e.size,n=Math.ceil(r/Fe.chunkedMTU),i=0,o=0;o0)&&!(n=o.next()).done;)a.push(n.value)}catch(e){i={error:e}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(i)throw i.error}}return a},Ze=function(e,t,r){if(r||2===arguments.length)for(var n,i=0,o=t.length;i=Qe.All&&this._print.apply(this,Ze([Qe.All],Xe(e),!1))},et.prototype.warn=function(){for(var e=[],t=0;t=Qe.Warnings&&this._print.apply(this,Ze([Qe.Warnings],Xe(e),!1))},et.prototype.error=function(){for(var e=[],t=0;t=Qe.Errors&&this._print.apply(this,Ze([Qe.Errors],Xe(e),!1))},et.prototype.setLogFunction=function(e){this._print=e},et.prototype._print=function(e){for(var t=[],r=1;r=Qe.All?console.log.apply(console,Ze([],Xe(n),!1)):e>=Qe.Warnings?console.warn.apply(console,Ze(["WARNING"],Xe(n),!1)):e>=Qe.Errors&&console.error.apply(console,Ze(["ERROR"],Xe(n),!1))},et),st=new at,ct={};t(ct,"Socket",(function(){return mt}),(function(e){return mt=e})),function(e){e.Data="data",e.Media="media"}(tt||(tt={})),function(e){e.BrowserIncompatible="browser-incompatible",e.Disconnected="disconnected",e.InvalidID="invalid-id",e.InvalidKey="invalid-key",e.Network="network",e.PeerUnavailable="peer-unavailable",e.SslUnavailable="ssl-unavailable",e.ServerError="server-error",e.SocketError="socket-error",e.SocketClosed="socket-closed",e.UnavailableID="unavailable-id",e.WebRTC="webrtc"}(rt||(rt={})),function(e){e.Binary="binary",e.BinaryUTF8="binary-utf8",e.JSON="json"}(nt||(nt={})),function(e){e.Message="message",e.Disconnected="disconnected",e.Error="error",e.Close="close"}(it||(it={})),function(e){e.Heartbeat="HEARTBEAT",e.Candidate="CANDIDATE",e.Offer="OFFER",e.Answer="ANSWER",e.Open="OPEN",e.Error="ERROR",e.IdTaken="ID-TAKEN",e.InvalidKey="INVALID-KEY",e.Leave="LEAVE",e.Expire="EXPIRE"}(ot||(ot={}));var pt;pt=JSON.parse('{"name":"peerjs","version":"1.4.7","keywords":["peerjs","webrtc","p2p","rtc"],"description":"PeerJS client","homepage":"https://peerjs.com","bugs":{"url":"https://github.com/peers/peerjs/issues"},"repository":{"type":"git","url":"https://github.com/peers/peerjs"},"license":"MIT","contributors":["Michelle Bu ","afrokick ","ericz ","Jairo ","Jonas Gloning <34194370+jonasgloning@users.noreply.github.com>","Jairo Caro-Accino Viciana ","Carlos Caballero ","hc ","Muhammad Asif ","PrashoonB ","Harsh Bardhan Mishra <47351025+HarshCasper@users.noreply.github.com>","akotynski ","lmb ","Jairooo ","Moritz Stückler ","Simon ","Denis Lukov ","Philipp Hancke ","Hans Oksendahl ","Jess ","khankuan ","DUODVK ","XiZhao ","Matthias Lohr ","=frank tree <=frnktrb@googlemail.com>","Andre Eckardt ","Chris Cowan ","Alex Chuev ","alxnull ","Yemel Jardi ","Ben Parnell ","Benny Lichtner ","fresheneesz ","bob.barstead@exaptive.com ","chandika ","emersion ","Christopher Van ","eddieherm ","Eduardo Pinho ","Evandro Zanatta ","Gardner Bickford ","Gian Luca ","PatrickJS ","jonnyf ","Hizkia Felix ","Hristo Oskov ","Isaac Madwed ","Ilya Konanykhin ","jasonbarry ","Jonathan Burke ","Josh Hamit ","Jordan Austin ","Joel Wetzell ","xizhao ","Alberto Torres ","Jonathan Mayol ","Jefferson Felix ","Rolf Erik Lekang ","Kevin Mai-Husan Chia ","Pepijn de Vos ","JooYoung ","Tobias Speicher ","Steve Blaurock ","Kyrylo Shegeda ","Diwank Singh Tomer ","Sören Balko ","Arpit Solanki ","Yuki Ito ","Artur Zayats "],"funding":{"type":"opencollective","url":"https://opencollective.com/peer"},"collective":{"type":"opencollective","url":"https://opencollective.com/peer"},"files":["dist/*"],"sideEffects":["lib/global.ts","lib/supports.ts"],"main":"dist/bundler.cjs","module":"dist/bundler.mjs","browser-minified":"dist/peerjs.min.js","browser-unminified":"dist/peerjs.js","types":"dist/types.d.ts","engines":{"node":">= 10"},"targets":{"types":{"source":"lib/exports.ts"},"main":{"source":"lib/exports.ts","sourceMap":{"inlineSources":true}},"module":{"source":"lib/exports.ts","includeNodeModules":["eventemitter3"],"sourceMap":{"inlineSources":true}},"browser-minified":{"context":"browser","outputFormat":"global","optimize":true,"engines":{"browsers":"cover 99%, not dead"},"source":"lib/global.ts"},"browser-unminified":{"context":"browser","outputFormat":"global","optimize":false,"engines":{"browsers":"cover 99%, not dead"},"source":"lib/global.ts"}},"scripts":{"contributors":"git-authors-cli --print=false && prettier --write package.json && git add package.json package-lock.json && git commit -m \\"chore(contributors): update and sort contributors list\\"","check":"tsc --noEmit","watch":"parcel watch","build":"rm -rf dist && parcel build","prepublishOnly":"npm run build","test":"mocha -r ts-node/register -r jsdom-global/register test/**/*.ts","format":"prettier --write .","semantic-release":"semantic-release"},"devDependencies":{"@parcel/config-default":"^2.5.0","@parcel/packager-ts":"^2.5.0","@parcel/transformer-typescript-tsc":"^2.5.0","@parcel/transformer-typescript-types":"^2.5.0","@semantic-release/changelog":"^6.0.1","@semantic-release/git":"^10.0.1","@types/chai":"^4.3.0","@types/mocha":"^9.1.0","@types/node":"^17.0.18","chai":"^4.3.6","git-authors-cli":"^1.0.40","jsdom":"^19.0.0","jsdom-global":"^3.0.2","mocha":"^9.2.0","mock-socket":"8.0.5","parcel":"^2.5.0","parcel-transformer-tsc-sourcemaps":"^1.0.2","prettier":"^2.6.2","semantic-release":"^19.0.2","standard":"^16.0.4","ts-node":"^10.5.0","typescript":"^4.5.5"},"dependencies":{"@swc/helpers":"^0.3.13","eventemitter3":"^4.0.7","peerjs-js-binarypack":"1.0.1","webrtc-adapter":"^7.7.1"}}');var dt,ut=(dt=function(e,t){return(dt=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(e,t)},function(e,t){var r=function(){this.constructor=e};if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");dt(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),lt=function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,i,o=r.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(n=o.next()).done;)a.push(n.value)}catch(e){i={error:e}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(i)throw i.error}}return a},ft=function(e,t,r){if(r||2===arguments.length)for(var n,i=0,o=t.length;i=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},mt=function(e){var t=function(t,r,n,i,o,a){void 0===a&&(a=5e3);var s=e.call(this)||this;s.pingInterval=a,s._disconnected=!0,s._messagesQueue=[];var c=t?"wss://":"ws://";return s._baseUrl=c+r+":"+n+i+"peerjs?key="+o,s};return ut(t,e),t.prototype.start=function(e,t){var r=this;this._id=e;var n="".concat(this._baseUrl,"&id=").concat(e,"&token=").concat(t);!this._socket&&this._disconnected&&(this._socket=new WebSocket(n+"&version="+pt.version),this._disconnected=!1,this._socket.onmessage=function(e){var t;try{t=JSON.parse(e.data),qe.default.log("Server message received:",t)}catch(t){return void qe.default.log("Invalid server message",e.data)}r.emit(it.Message,t)},this._socket.onclose=function(e){r._disconnected||(qe.default.log("Socket closed.",e),r._cleanup(),r._disconnected=!0,r.emit(it.Disconnected))},this._socket.onopen=function(){r._disconnected||(r._sendQueuedMessages(),qe.default.log("Socket open"),r._scheduleHeartbeat())})},t.prototype._scheduleHeartbeat=function(){var e=this;this._wsPingTimer=setTimeout((function(){e._sendHeartbeat()}),this.pingInterval)},t.prototype._sendHeartbeat=function(){if(this._wsOpen()){var e=JSON.stringify({type:ot.Heartbeat});this._socket.send(e),this._scheduleHeartbeat()}else qe.default.log("Cannot send heartbeat, because socket closed")},t.prototype._wsOpen=function(){return!!this._socket&&1===this._socket.readyState},t.prototype._sendQueuedMessages=function(){var e,t,r=ft([],lt(this._messagesQueue),!1);this._messagesQueue=[];try{for(var n=ht(r),i=n.next();!i.done;i=n.next()){var o=i.value;this.send(o)}}catch(t){e={error:t}}finally{try{i&&!i.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}},t.prototype.send=function(e){if(!this._disconnected)if(this._id)if(e.type){if(this._wsOpen()){var t=JSON.stringify(e);this._socket.send(t)}}else this.emit(it.Error,"Invalid message");else this._messagesQueue.push(e)},t.prototype.close=function(){this._disconnected||(this._cleanup(),this._disconnected=!0)},t.prototype._cleanup=function(){this._socket&&(this._socket.onopen=this._socket.onmessage=this._socket.onclose=null,this._socket.close(),this._socket=void 0),clearTimeout(this._wsPingTimer)},t}(ze.EventEmitter),vt={};t(vt,"MediaConnection",(function(){return Et}),(function(e){return Et=e}));var yt={};t(yt,"Negotiator",(function(){return _t}),(function(e){return _t=e}));var gt=function(){return gt=Object.assign||function(e){for(var t,r=1,n=arguments.length;r0&&i[i.length-1])||6!==o[0]&&2!==o[0])){c=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},Et=function(e){function t(r,n,i){var o=e.call(this,r,n,i)||this;return o._localStream=o.options._stream,o.connectionId=o.options.connectionId||t.ID_PREFIX+Fe.randomToken(),o._negotiator=new yt.Negotiator(o),o._localStream&&o._negotiator.startConnection({_stream:o._localStream,originator:!0}),o}return wt(t,e),Object.defineProperty(t.prototype,"type",{get:function(){return tt.Media},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"localStream",{get:function(){return this._localStream},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"remoteStream",{get:function(){return this._remoteStream},enumerable:!1,configurable:!0}),t.prototype.addStream=function(t){qe.default.log("Receiving stream",t),this._remoteStream=t,e.prototype.emit.call(this,"stream",t)},t.prototype.handleMessage=function(e){var t=e.type,r=e.payload;switch(e.type){case ot.Answer:this._negotiator.handleSDP(t,r.sdp),this._open=!0;break;case ot.Candidate:this._negotiator.handleCandidate(r.candidate);break;default:qe.default.warn("Unrecognized message type:".concat(t," from peer:").concat(this.peer))}},t.prototype.answer=function(e,t){var r,n;if(void 0===t&&(t={}),this._localStream)qe.default.warn("Local stream already exists on this MediaConnection. Are you answering a call twice?");else{this._localStream=e,t&&t.sdpTransform&&(this.options.sdpTransform=t.sdpTransform),this._negotiator.startConnection(Pt(Pt({},this.options._payload),{_stream:e}));var i=this.provider._getMessages(this.connectionId);try{for(var o=Rt(i),a=o.next();!a.done;a=o.next()){var s=a.value;this.handleMessage(s)}}catch(e){r={error:e}}finally{try{a&&!a.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}this._open=!0}},t.prototype.close=function(){this._negotiator&&(this._negotiator.cleanup(),this._negotiator=null),this._localStream=null,this._remoteStream=null,this.provider&&(this.provider._removeConnection(this),this.provider=null),this.options&&this.options._stream&&(this.options._stream=null),this.open&&(this._open=!1,e.prototype.emit.call(this,"close"))},t.ID_PREFIX="mc_",t}(St.BaseConnection),xt={};t(xt,"DataConnection",(function(){return At}),(function(e){return At=e}));var Dt={};t(Dt,"EncodingQueue",(function(){return It}),(function(e){return It=e}));var Ot=function(){var e=function(t,r){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(t,r)};return function(t,r){var n=function(){this.constructor=t};if("function"!=typeof r&&null!==r)throw new TypeError("Class extends value "+String(r)+" is not a constructor or null");e(t,r),t.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),It=function(e){var t=function(){var t=e.call(this)||this;return t.fileReader=new FileReader,t._queue=[],t._processing=!1,t.fileReader.onload=function(e){t._processing=!1,e.target&&t.emit("done",e.target.result),t.doNextTask()},t.fileReader.onerror=function(e){qe.default.error("EncodingQueue error:",e),t._processing=!1,t.destroy(),t.emit("error",e)},t};return Ot(t,e),Object.defineProperty(t.prototype,"queue",{get:function(){return this._queue},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"size",{get:function(){return this.queue.length},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"processing",{get:function(){return this._processing},enumerable:!1,configurable:!0}),t.prototype.enque=function(e){this.queue.push(e),this.processing||this.doNextTask()},t.prototype.destroy=function(){this.fileReader.abort(),this._queue=[]},t.prototype.doNextTask=function(){0!==this.size&&(this.processing||(this._processing=!0,this.fileReader.readAsArrayBuffer(this.queue.shift())))},t}(ze.EventEmitter),Mt=function(){var e=function(t,r){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])})(t,r)};return function(t,r){var n=function(){this.constructor=t};if("function"!=typeof r&&null!==r)throw new TypeError("Class extends value "+String(r)+" is not a constructor or null");e(t,r),t.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),jt=function(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},At=function(e){function t(r,n,i){var o=e.call(this,r,n,i)||this;return o.stringify=JSON.stringify,o.parse=JSON.parse,o._buffer=[],o._bufferSize=0,o._buffering=!1,o._chunkedData={},o._encodingQueue=new Dt.EncodingQueue,o.connectionId=o.options.connectionId||t.ID_PREFIX+Fe.randomToken(),o.label=o.options.label||o.connectionId,o.serialization=o.options.serialization||nt.Binary,o.reliable=!!o.options.reliable,o._encodingQueue.on("done",(function(e){o._bufferedSend(e)})),o._encodingQueue.on("error",(function(){qe.default.error("DC#".concat(o.connectionId,": Error occured in encoding from blob to arraybuffer, close DC")),o.close()})),o._negotiator=new yt.Negotiator(o),o._negotiator.startConnection(o.options._payload||{originator:!0}),o}return Mt(t,e),Object.defineProperty(t.prototype,"type",{get:function(){return tt.Data},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"dataChannel",{get:function(){return this._dc},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"bufferSize",{get:function(){return this._bufferSize},enumerable:!1,configurable:!0}),t.prototype.initialize=function(e){this._dc=e,this._configureDataChannel()},t.prototype._configureDataChannel=function(){var e=this;Fe.supports.binaryBlob&&!Fe.supports.reliable||(this.dataChannel.binaryType="arraybuffer"),this.dataChannel.onopen=function(){qe.default.log("DC#".concat(e.connectionId," dc connection success")),e._open=!0,e.emit("open")},this.dataChannel.onmessage=function(t){qe.default.log("DC#".concat(e.connectionId," dc onmessage:"),t.data),e._handleDataMessage(t)},this.dataChannel.onclose=function(){qe.default.log("DC#".concat(e.connectionId," dc closed for:"),e.peer),e.close()}},t.prototype._handleDataMessage=function(t){var r=this,n=t.data,i=n.constructor,o=n;if(this.serialization===nt.Binary||this.serialization===nt.BinaryUTF8){if(i===Blob)return void Fe.blobToArrayBuffer(n,(function(e){var t=Fe.unpack(e);r.emit("data",t)}));if(i===ArrayBuffer)o=Fe.unpack(n);else if(i===String){var a=Fe.binaryStringToArrayBuffer(n);o=Fe.unpack(a)}}else this.serialization===nt.JSON&&(o=this.parse(n));o.__peerData?this._handleChunk(o):e.prototype.emit.call(this,"data",o)},t.prototype._handleChunk=function(e){var t=e.__peerData,r=this._chunkedData[t]||{data:[],count:0,total:e.total};if(r.data[e.n]=e.data,r.count++,this._chunkedData[t]=r,r.total===r.count){delete this._chunkedData[t];var n=new Blob(r.data);this._handleDataMessage({data:n})}},t.prototype.close=function(){this._buffer=[],this._bufferSize=0,this._chunkedData={},this._negotiator&&(this._negotiator.cleanup(),this._negotiator=null),this.provider&&(this.provider._removeConnection(this),this.provider=null),this.dataChannel&&(this.dataChannel.onopen=null,this.dataChannel.onmessage=null,this.dataChannel.onclose=null,this._dc=null),this._encodingQueue&&(this._encodingQueue.destroy(),this._encodingQueue.removeAllListeners(),this._encodingQueue=null),this.open&&(this._open=!1,e.prototype.emit.call(this,"close"))},t.prototype.send=function(t,r){if(this.open)if(this.serialization===nt.JSON)this._bufferedSend(this.stringify(t));else if(this.serialization===nt.Binary||this.serialization===nt.BinaryUTF8){var n=Fe.pack(t);if(!r&&n.size>Fe.chunkedMTU)return void this._sendChunks(n);Fe.supports.binaryBlob?this._bufferedSend(n):this._encodingQueue.enque(n)}else this._bufferedSend(t);else e.prototype.emit.call(this,"error",new Error("Connection is not open. You should listen for the `open` event before sending messages."))},t.prototype._bufferedSend=function(e){!this._buffering&&this._trySend(e)||(this._buffer.push(e),this._bufferSize=this._buffer.length)},t.prototype._trySend=function(e){var r=this;if(!this.open)return!1;if(this.dataChannel.bufferedAmount>t.MAX_BUFFERED_AMOUNT)return this._buffering=!0,setTimeout((function(){r._buffering=!1,r._tryBuffer()}),50),!1;try{this.dataChannel.send(e)}catch(e){return qe.default.error("DC#:".concat(this.connectionId," Error when sending:"),e),this._buffering=!0,this.close(),!1}return!0},t.prototype._tryBuffer=function(){if(this.open&&0!==this._buffer.length){var e=this._buffer[0];this._trySend(e)&&(this._buffer.shift(),this._bufferSize=this._buffer.length,this._tryBuffer())}},t.prototype._sendChunks=function(e){var t,r,n=Fe.chunk(e);qe.default.log("DC#".concat(this.connectionId," Try to send ").concat(n.length," chunks..."));try{for(var i=jt(n),o=i.next();!o.done;o=i.next()){var a=o.value;this.send(a,!0)}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(t)throw t.error}}},t.prototype.handleMessage=function(e){var t=e.payload;switch(e.type){case ot.Answer:this._negotiator.handleSDP(e.type,t.sdp);break;case ot.Candidate:this._negotiator.handleCandidate(t.candidate);break;default:qe.default.warn("Unrecognized message type:",e.type,"from peer:",this.peer)}},t.ID_PREFIX="dc_",t.MAX_BUFFERED_AMOUNT=8388608,t}(St.BaseConnection),Lt={};t(Lt,"API",(function(){return Ft}),(function(e){return Ft=e}));var Bt=function(e,t,r,n){return new(r||(r=Promise))((function(i,o){var a=function(e){try{c(n.next(e))}catch(e){o(e)}},s=function(e){try{c(n.throw(e))}catch(e){o(e)}},c=function(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)};c((n=n.apply(e,t||[])).next())}))},Nt=function(e,t){var r,n,i,o,a=function(e){return function(t){return s([e,t])}},s=function(o){if(r)throw new TypeError("Generator is already executing.");for(;c;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return c.label++,{value:o[1],done:!1};case 5:c.label++,n=o[1],o=[0];continue;case 7:o=c.ops.pop(),c.trys.pop();continue;default:if(!(i=c.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){c=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},Vt=function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,i,o=r.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(n=o.next()).done;)a.push(n.value)}catch(e){i={error:e}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(i)throw i.error}}return a},Jt=function(e){function t(r,n){var i,o=e.call(this)||this;return o._id=null,o._lastServerId=null,o._destroyed=!1,o._disconnected=!1,o._open=!1,o._connections=new Map,o._lostMessages=new Map,r&&r.constructor==Object?n=r:r&&(i=r.toString()),n=zt({debug:0,host:Fe.CLOUD_HOST,port:Fe.CLOUD_PORT,path:"/",key:t.DEFAULT_KEY,token:Fe.randomToken(),config:Fe.defaultConfig,referrerPolicy:"strict-origin-when-cross-origin"},n),o._options=n,"/"===o._options.host&&(o._options.host=window.location.hostname),o._options.path&&("/"!==o._options.path[0]&&(o._options.path="/"+o._options.path),"/"!==o._options.path[o._options.path.length-1]&&(o._options.path+="/")),void 0===o._options.secure&&o._options.host!==Fe.CLOUD_HOST?o._options.secure=Fe.isSecure():o._options.host==Fe.CLOUD_HOST&&(o._options.secure=!0),o._options.logFunction&&qe.default.setLogFunction(o._options.logFunction),qe.default.logLevel=o._options.debug||0,o._api=new Lt.API(n),o._socket=o._createServerConnection(),Fe.supports.audioVideo||Fe.supports.data?i&&!Fe.validateId(i)?(o._delayedAbort(rt.InvalidID,'ID "'.concat(i,'" is invalid')),o):(i?o._initialize(i):o._api.retrieveId().then((function(e){return o._initialize(e)})).catch((function(e){return o._abort(rt.ServerError,e)})),o):(o._delayedAbort(rt.BrowserIncompatible,"The current browser does not support WebRTC"),o)}return Ut(t,e),Object.defineProperty(t.prototype,"id",{get:function(){return this._id},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"options",{get:function(){return this._options},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"open",{get:function(){return this._open},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"socket",{get:function(){return this._socket},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"connections",{get:function(){var e,t,r=Object.create(null);try{for(var n=Gt(this._connections),i=n.next();!i.done;i=n.next()){var o=Vt(i.value,2),a=o[0],s=o[1];r[a]=s}}catch(t){e={error:t}}finally{try{i&&!i.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}return r},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"destroyed",{get:function(){return this._destroyed},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"disconnected",{get:function(){return this._disconnected},enumerable:!1,configurable:!0}),t.prototype._createServerConnection=function(){var e=this,t=new ct.Socket(this._options.secure,this._options.host,this._options.port,this._options.path,this._options.key,this._options.pingInterval);return t.on(it.Message,(function(t){e._handleMessage(t)})),t.on(it.Error,(function(t){e._abort(rt.SocketError,t)})),t.on(it.Disconnected,(function(){e.disconnected||(e.emitError(rt.Network,"Lost connection to server."),e.disconnect())})),t.on(it.Close,(function(){e.disconnected||e._abort(rt.SocketClosed,"Underlying socket is already closed.")})),t},t.prototype._initialize=function(e){this._id=e,this.socket.start(e,this._options.token)},t.prototype._handleMessage=function(e){var t,r,n=e.type,i=e.payload,o=e.src;switch(n){case ot.Open:this._lastServerId=this.id,this._open=!0,this.emit("open",this.id);break;case ot.Error:this._abort(rt.ServerError,i.msg);break;case ot.IdTaken:this._abort(rt.UnavailableID,'ID "'.concat(this.id,'" is taken'));break;case ot.InvalidKey:this._abort(rt.InvalidKey,'API KEY "'.concat(this._options.key,'" is invalid'));break;case ot.Leave:qe.default.log("Received leave message from ".concat(o)),this._cleanupPeer(o),this._connections.delete(o);break;case ot.Expire:this.emitError(rt.PeerUnavailable,"Could not connect to peer ".concat(o));break;case ot.Offer:var a=i.connectionId;if((f=this.getConnection(o,a))&&(f.close(),qe.default.warn("Offer received for existing Connection ID:".concat(a))),i.type===tt.Media){var s=new vt.MediaConnection(o,this,{connectionId:a,_payload:i,metadata:i.metadata});f=s,this._addConnection(o,f),this.emit("call",s)}else{if(i.type!==tt.Data)return void qe.default.warn("Received malformed connection type:".concat(i.type));var c=new xt.DataConnection(o,this,{connectionId:a,_payload:i,metadata:i.metadata,label:i.label,serialization:i.serialization,reliable:i.reliable});f=c,this._addConnection(o,f),this.emit("connection",c)}var p=this._getMessages(a);try{for(var d=Gt(p),u=d.next();!u.done;u=d.next()){var l=u.value;f.handleMessage(l)}}catch(e){t={error:e}}finally{try{u&&!u.done&&(r=d.return)&&r.call(d)}finally{if(t)throw t.error}}break;default:if(!i)return void qe.default.warn("You received a malformed message from ".concat(o," of type ").concat(n));var f;a=i.connectionId;(f=this.getConnection(o,a))&&f.peerConnection?f.handleMessage(e):a?this._storeMessage(a,e):qe.default.warn("You received an unrecognized message:",e)}},t.prototype._storeMessage=function(e,t){this._lostMessages.has(e)||this._lostMessages.set(e,[]),this._lostMessages.get(e).push(t)},t.prototype._getMessages=function(e){var t=this._lostMessages.get(e);return t?(this._lostMessages.delete(e),t):[]},t.prototype.connect=function(e,t){if(void 0===t&&(t={}),this.disconnected)return qe.default.warn("You cannot connect to a new Peer because you called .disconnect() on this Peer and ended your connection with the server. You can create a new Peer to reconnect, or call reconnect on this peer if you believe its ID to still be available."),void this.emitError(rt.Disconnected,"Cannot connect to new Peer after disconnecting from server.");var r=new xt.DataConnection(e,this,t);return this._addConnection(e,r),r},t.prototype.call=function(e,t,r){if(void 0===r&&(r={}),this.disconnected)return qe.default.warn("You cannot connect to a new Peer because you called .disconnect() on this Peer and ended your connection with the server. You can create a new Peer to reconnect."),void this.emitError(rt.Disconnected,"Cannot connect to new Peer after disconnecting from server.");if(t){var n=new vt.MediaConnection(e,this,zt(zt({},r),{_stream:t}));return this._addConnection(e,n),n}qe.default.error("To call a peer, you must provide a stream from your browser's `getUserMedia`.")},t.prototype._addConnection=function(e,t){qe.default.log("add connection ".concat(t.type,":").concat(t.connectionId," to peerId:").concat(e)),this._connections.has(e)||this._connections.set(e,[]),this._connections.get(e).push(t)},t.prototype._removeConnection=function(e){var t=this._connections.get(e.peer);if(t){var r=t.indexOf(e);-1!==r&&t.splice(r,1)}this._lostMessages.delete(e.connectionId)},t.prototype.getConnection=function(e,t){var r,n,i=this._connections.get(e);if(!i)return null;try{for(var o=Gt(i),a=o.next();!a.done;a=o.next()){var s=a.value;if(s.connectionId===t)return s}}catch(e){r={error:e}}finally{try{a&&!a.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}return null},t.prototype._delayedAbort=function(e,t){var r=this;setTimeout((function(){r._abort(e,t)}),0)},t.prototype._abort=function(e,t){qe.default.error("Aborting!"),this.emitError(e,t),this._lastServerId?this.disconnect():this.destroy()},t.prototype.emitError=function(e,t){var r;qe.default.error("Error:",t),(r="string"==typeof t?new Error(t):t).type=e,this.emit("error",r)},t.prototype.destroy=function(){this.destroyed||(qe.default.log("Destroy peer with ID:".concat(this.id)),this.disconnect(),this._cleanup(),this._destroyed=!0,this.emit("close"))},t.prototype._cleanup=function(){var e,t;try{for(var r=Gt(this._connections.keys()),n=r.next();!n.done;n=r.next()){var i=n.value;this._cleanupPeer(i),this._connections.delete(i)}}catch(t){e={error:t}}finally{try{n&&!n.done&&(t=r.return)&&t.call(r)}finally{if(e)throw e.error}}this.socket.removeAllListeners()},t.prototype._cleanupPeer=function(e){var t,r,n=this._connections.get(e);if(n)try{for(var i=Gt(n),o=i.next();!o.done;o=i.next()){o.value.close()}}catch(e){t={error:e}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(t)throw t.error}}},t.prototype.disconnect=function(){if(!this.disconnected){var e=this.id;qe.default.log("Disconnect peer with ID:".concat(e)),this._disconnected=!0,this._open=!1,this.socket.close(),this._lastServerId=e,this._id=null,this.emit("disconnected",e)}},t.prototype.reconnect=function(){if(this.disconnected&&!this.destroyed)qe.default.log("Attempting reconnection to server with ID ".concat(this._lastServerId)),this._disconnected=!1,this._initialize(this._lastServerId);else{if(this.destroyed)throw new Error("This peer cannot reconnect to the server. It has already been destroyed.");if(this.disconnected||this.open)throw new Error("Peer ".concat(this.id," cannot reconnect because it is not disconnected from the server!"));qe.default.error("In a hurry? We're still trying to make the initial connection!")}},t.prototype.listAllPeers=function(e){var t=this;void 0===e&&(e=function(e){}),this._api.listAllPeers().then((function(t){return e(t)})).catch((function(e){return t._abort(rt.ServerError,e)}))},t.DEFAULT_KEY="peerjs",t}(ze.EventEmitter);window.peerjs={Peer:Ue.Peer,util:Fe},window.Peer=Ue.Peer}(); +//# sourceMappingURL=peerjs.min.js.map diff --git a/src/main/resources/static/js/thirdParty/qrcode.min.js b/src/main/resources/static/js/thirdParty/qrcode.min.js new file mode 100644 index 000000000..993e88f39 --- /dev/null +++ b/src/main/resources/static/js/thirdParty/qrcode.min.js @@ -0,0 +1 @@ +var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push("");for(var i=0;d>i;i++)g.push('');g.push("")}g.push("
"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}(); \ No newline at end of file diff --git a/src/main/resources/static/js/thirdParty/sockjs.min.js b/src/main/resources/static/js/thirdParty/sockjs.min.js new file mode 100644 index 000000000..4d302a4c4 --- /dev/null +++ b/src/main/resources/static/js/thirdParty/sockjs.min.js @@ -0,0 +1,3 @@ +/* sockjs-client v1.6.1 | http://sockjs.org | MIT license */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).SockJS=e()}}(function(){return function i(s,a,l){function u(t,e){if(!a[t]){if(!s[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(c)return c(t,!0);var r=new Error("Cannot find module '"+t+"'");throw r.code="MODULE_NOT_FOUND",r}var o=a[t]={exports:{}};s[t][0].call(o.exports,function(e){return u(s[t][1][e]||e)},o,o.exports,i,s,a,l)}return a[t].exports}for(var c="function"==typeof require&&require,e=0;e>>0;if(!a(e))throw new TypeError;for(;++i>>0;if(!r)return-1;var o=0;for(1>>0:function(e){return e>>>0}(t);(o=e.exec(n))&&!(u<(i=o.index+o[0].length)&&(a.push(n.slice(u,o.index)),!_&&1=t));)e.lastIndex===o.index&&e.lastIndex++;return u===n.length?!s&&e.test("")||a.push(""):a.push(n.slice(u)),a.length>t?a.slice(0,t):a}):"0".split(void 0,0).length&&(s.split=function(e,t){return void 0===e&&0===t?[]:E.call(this,e,t)});var S=s.substr,O="".substr&&"b"!=="0b".substr(-1);d(s,{substr:function(e,t){return S.call(this,e<0&&(e=this.length+e)<0?0:e,t)}},O)},{}],16:[function(e,t,n){"use strict";t.exports=[e("./transport/websocket"),e("./transport/xhr-streaming"),e("./transport/xdr-streaming"),e("./transport/eventsource"),e("./transport/lib/iframe-wrap")(e("./transport/eventsource")),e("./transport/htmlfile"),e("./transport/lib/iframe-wrap")(e("./transport/htmlfile")),e("./transport/xhr-polling"),e("./transport/xdr-polling"),e("./transport/lib/iframe-wrap")(e("./transport/xhr-polling")),e("./transport/jsonp-polling")]},{"./transport/eventsource":20,"./transport/htmlfile":21,"./transport/jsonp-polling":23,"./transport/lib/iframe-wrap":26,"./transport/websocket":38,"./transport/xdr-polling":39,"./transport/xdr-streaming":40,"./transport/xhr-polling":41,"./transport/xhr-streaming":42}],17:[function(o,f,e){(function(r){(function(){"use strict";var i=o("events").EventEmitter,e=o("inherits"),s=o("../../utils/event"),a=o("../../utils/url"),l=r.XMLHttpRequest,u=function(){};function c(e,t,n,r){u(e,t);var o=this;i.call(this),setTimeout(function(){o._start(e,t,n,r)},0)}e(c,i),c.prototype._start=function(e,t,n,r){var o=this;try{this.xhr=new l}catch(e){}if(!this.xhr)return u("no xhr"),this.emit("finish",0,"no xhr support"),void this._cleanup();t=a.addQuery(t,"t="+ +new Date),this.unloadRef=s.unloadAdd(function(){u("unload cleanup"),o._cleanup(!0)});try{this.xhr.open(e,t,!0),this.timeout&&"timeout"in this.xhr&&(this.xhr.timeout=this.timeout,this.xhr.ontimeout=function(){u("xhr timeout"),o.emit("finish",0,""),o._cleanup(!1)})}catch(e){return u("exception",e),this.emit("finish",0,""),void this._cleanup(!1)}if(r&&r.noCredentials||!c.supportsCORS||(u("withCredentials"),this.xhr.withCredentials=!0),r&&r.headers)for(var i in r.headers)this.xhr.setRequestHeader(i,r.headers[i]);this.xhr.onreadystatechange=function(){if(o.xhr){var e,t,n=o.xhr;switch(u("readyState",n.readyState),n.readyState){case 3:try{t=n.status,e=n.responseText}catch(e){}u("status",t),1223===t&&(t=204),200===t&&e&&0')}catch(e){var n=f.document.createElement("iframe");return n.name=t,n}}(r);o.id=r,o.style.display="none",s.appendChild(o);try{a.value=t}catch(e){}s.submit();function i(e){c("completed",r,e),o.onerror&&(o.onreadystatechange=o.onerror=o.onload=null,setTimeout(function(){c("cleaning up",r),o.parentNode.removeChild(o),o=null},500),a.value="",n(e))}return o.onerror=function(){c("onerror",r),i()},o.onload=function(){c("onload",r),i()},o.onreadystatechange=function(e){c("onreadystatechange",r,o.readyState,e),"complete"===o.readyState&&i()},function(){c("aborted",r),i(new Error("Aborted"))}}}).call(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../../utils/random":50,"../../utils/url":52,"debug":void 0}],34:[function(r,u,e){(function(l){(function(){"use strict";var o=r("events").EventEmitter,e=r("inherits"),i=r("../../utils/event"),t=r("../../utils/browser"),s=r("../../utils/url"),a=function(){};function n(e,t,n){a(e,t);var r=this;o.call(this),setTimeout(function(){r._start(e,t,n)},0)}e(n,o),n.prototype._start=function(e,t,n){a("_start");var r=this,o=new l.XDomainRequest;t=s.addQuery(t,"t="+ +new Date),o.onerror=function(){a("onerror"),r._error()},o.ontimeout=function(){a("ontimeout"),r._error()},o.onprogress=function(){a("progress",o.responseText),r.emit("chunk",200,o.responseText)},o.onload=function(){a("load"),r.emit("finish",200,o.responseText),r._cleanup(!1)},this.xdr=o,this.unloadRef=i.unloadAdd(function(){r._cleanup(!0)});try{this.xdr.open(e,t),this.timeout&&(this.xdr.timeout=this.timeout),this.xdr.send(n)}catch(e){this._error()}},n.prototype._error=function(){this.emit("finish",0,""),this._cleanup(!1)},n.prototype._cleanup=function(e){if(a("cleanup",e),this.xdr){if(this.removeAllListeners(),i.unloadDel(this.unloadRef),this.xdr.ontimeout=this.xdr.onerror=this.xdr.onprogress=this.xdr.onload=null,e)try{this.xdr.abort()}catch(e){}this.unloadRef=this.xdr=null}},n.prototype.close=function(){a("close"),this._cleanup(!0)},n.enabled=!(!l.XDomainRequest||!t.hasDomain()),u.exports=n}).call(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../../utils/browser":44,"../../utils/event":46,"../../utils/url":52,"debug":void 0,"events":3,"inherits":54}],35:[function(e,t,n){"use strict";var r=e("inherits"),o=e("../driver/xhr");function i(e,t,n,r){o.call(this,e,t,n,r)}r(i,o),i.enabled=o.enabled&&o.supportsCORS,t.exports=i},{"../driver/xhr":17,"inherits":54}],36:[function(e,t,n){"use strict";var r=e("events").EventEmitter;function o(){var e=this;r.call(this),this.to=setTimeout(function(){e.emit("finish",200,"{}")},o.timeout)}e("inherits")(o,r),o.prototype.close=function(){clearTimeout(this.to)},o.timeout=2e3,t.exports=o},{"events":3,"inherits":54}],37:[function(e,t,n){"use strict";var r=e("inherits"),o=e("../driver/xhr");function i(e,t,n){o.call(this,e,t,n,{noCredentials:!0})}r(i,o),i.enabled=o.enabled,t.exports=i},{"../driver/xhr":17,"inherits":54}],38:[function(e,t,n){"use strict";var i=e("../utils/event"),s=e("../utils/url"),r=e("inherits"),a=e("events").EventEmitter,l=e("./driver/websocket"),u=function(){};function c(e,t,n){if(!c.enabled())throw new Error("Transport created when disabled");a.call(this),u("constructor",e);var r=this,o=s.addPath(e,"/websocket");o="https"===o.slice(0,5)?"wss"+o.slice(5):"ws"+o.slice(4),this.url=o,this.ws=new l(this.url,[],n),this.ws.onmessage=function(e){u("message event",e.data),r.emit("message",e.data)},this.unloadRef=i.unloadAdd(function(){u("unload"),r.ws.close()}),this.ws.onclose=function(e){u("close event",e.code,e.reason),r.emit("close",e.code,e.reason),r._cleanup()},this.ws.onerror=function(e){u("error event",e),r.emit("close",1006,"WebSocket connection broken"),r._cleanup()}}r(c,a),c.prototype.send=function(e){var t="["+e+"]";u("send",t),this.ws.send(t)},c.prototype.close=function(){u("close");var e=this.ws;this._cleanup(),e&&e.close()},c.prototype._cleanup=function(){u("_cleanup");var e=this.ws;e&&(e.onmessage=e.onclose=e.onerror=null),i.unloadDel(this.unloadRef),this.unloadRef=this.ws=null,this.removeAllListeners()},c.enabled=function(){return u("enabled"),!!l},c.transportName="websocket",c.roundTrips=2,t.exports=c},{"../utils/event":46,"../utils/url":52,"./driver/websocket":19,"debug":void 0,"events":3,"inherits":54}],39:[function(e,t,n){"use strict";var r=e("inherits"),o=e("./lib/ajax-based"),i=e("./xdr-streaming"),s=e("./receiver/xhr"),a=e("./sender/xdr");function l(e){if(!a.enabled)throw new Error("Transport created when disabled");o.call(this,e,"/xhr",s,a)}r(l,o),l.enabled=i.enabled,l.transportName="xdr-polling",l.roundTrips=2,t.exports=l},{"./lib/ajax-based":24,"./receiver/xhr":32,"./sender/xdr":34,"./xdr-streaming":40,"inherits":54}],40:[function(e,t,n){"use strict";var r=e("inherits"),o=e("./lib/ajax-based"),i=e("./receiver/xhr"),s=e("./sender/xdr");function a(e){if(!s.enabled)throw new Error("Transport created when disabled");o.call(this,e,"/xhr_streaming",i,s)}r(a,o),a.enabled=function(e){return!e.cookie_needed&&!e.nullOrigin&&(s.enabled&&e.sameScheme)},a.transportName="xdr-streaming",a.roundTrips=2,t.exports=a},{"./lib/ajax-based":24,"./receiver/xhr":32,"./sender/xdr":34,"inherits":54}],41:[function(e,t,n){"use strict";var r=e("inherits"),o=e("./lib/ajax-based"),i=e("./receiver/xhr"),s=e("./sender/xhr-cors"),a=e("./sender/xhr-local");function l(e){if(!a.enabled&&!s.enabled)throw new Error("Transport created when disabled");o.call(this,e,"/xhr",i,s)}r(l,o),l.enabled=function(e){return!e.nullOrigin&&(!(!a.enabled||!e.sameOrigin)||s.enabled)},l.transportName="xhr-polling",l.roundTrips=2,t.exports=l},{"./lib/ajax-based":24,"./receiver/xhr":32,"./sender/xhr-cors":35,"./sender/xhr-local":37,"inherits":54}],42:[function(l,u,e){(function(a){(function(){"use strict";var e=l("inherits"),t=l("./lib/ajax-based"),n=l("./receiver/xhr"),r=l("./sender/xhr-cors"),o=l("./sender/xhr-local"),i=l("../utils/browser");function s(e){if(!o.enabled&&!r.enabled)throw new Error("Transport created when disabled");t.call(this,e,"/xhr_streaming",n,r)}e(s,t),s.enabled=function(e){return!e.nullOrigin&&(!i.isOpera()&&r.enabled)},s.transportName="xhr-streaming",s.roundTrips=2,s.needBody=!!a.document,u.exports=s}).call(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../utils/browser":44,"./lib/ajax-based":24,"./receiver/xhr":32,"./sender/xhr-cors":35,"./sender/xhr-local":37,"inherits":54}],43:[function(e,t,n){(function(n){(function(){"use strict";n.crypto&&n.crypto.getRandomValues?t.exports.randomBytes=function(e){var t=new Uint8Array(e);return n.crypto.getRandomValues(t),t}:t.exports.randomBytes=function(e){for(var t=new Array(e),n=0;n + + + + +
+
+ + +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+

Preview

+
+ + 0 images +
+
+ Preview +
+ + +
+
+ +
+
+

Batch Images

+
+ + +
+
+
+
+
+
+
Uploading...
+
+
+ +

Success!

+

Scan uploaded

+
+
+ +

Camera Access Required

+

Please allow camera access and reload this page over HTTPS.

+
+ + + + + + diff --git a/src/main/resources/templates/misc/scan-upload.html b/src/main/resources/templates/misc/scan-upload.html new file mode 100644 index 000000000..71adbde4e --- /dev/null +++ b/src/main/resources/templates/misc/scan-upload.html @@ -0,0 +1,52 @@ + + + + + + + + + + +
+
+ +
+
+
+

Scan and Upload

+
+
+
+

Scan with your phone and upload directly to this browser.

+
+
+
+

Scan this QR code with your phone

+
+
Session ID:
+
+ +
+
+
+
+
+ + +