diff --git a/cereal/custom.capnp b/cereal/custom.capnp index 3348e859e..3172be481 100644 --- a/cereal/custom.capnp +++ b/cereal/custom.capnp @@ -10,10 +10,13 @@ $Cxx.namespace("cereal"); # DO rename the structs # DON'T change the identifier (e.g. @0x81c2f05a394cf4af) -struct CustomReserved0 @0x81c2f05a394cf4af { +struct DpControlsState @0x81c2f05a394cf4af { + alkaActive @0 :Bool; } -struct CustomReserved1 @0xaedffd8f31e7b55d { +struct ModelExt @0xaedffd8f31e7b55d { + leftEdgeDetected @0 :Bool; + rightEdgeDetected @1 :Bool; } struct CustomReserved2 @0xf35cc4560bbf6ec2 { diff --git a/cereal/log.capnp b/cereal/log.capnp index e75684356..9eb0ef887 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -2622,8 +2622,8 @@ struct Event { # DO change the name of the field and struct # DON'T change the ID (e.g. @107) # DON'T change which struct it points to - customReserved0 @107 :Custom.CustomReserved0; - customReserved1 @108 :Custom.CustomReserved1; + dpControlsState @107 :Custom.DpControlsState; + modelExt @108 :Custom.ModelExt; customReserved2 @109 :Custom.CustomReserved2; customReserved3 @110 :Custom.CustomReserved3; customReserved4 @111 :Custom.CustomReserved4; diff --git a/cereal/services.py b/cereal/services.py index a4c7463f2..428aaff90 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -95,6 +95,8 @@ _services: dict[str, tuple] = { "customReservedRawData0": (True, 0.), "customReservedRawData1": (True, 0.), "customReservedRawData2": (True, 0.), + "dpControlsState": (False, 100., 10), + "modelExt": (True, 20.), } SERVICE_LIST = {name: Service(*vals) for idx, (name, vals) in enumerate(_services.items())} diff --git a/common/params_keys.h b/common/params_keys.h index 3167df8b1..1759cbdd4 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -131,4 +131,26 @@ inline static std::unordered_map keys = { {"Version", {PERSISTENT, STRING}}, {"dp_device_last_log", {CLEAR_ON_ONROAD_TRANSITION, STRING}}, {"dp_device_reset_conf", {CLEAR_ON_MANAGER_START, BOOL}}, + {"dp_device_is_rhd", {PERSISTENT, BOOL, "0"}}, + {"dp_device_monitoring_disabled", {PERSISTENT, BOOL, "0"}}, + {"dp_device_beep", {PERSISTENT, BOOL, "0"}}, + {"dp_lat_alka", {PERSISTENT, BOOL, "0"}}, + {"dp_ui_display_mode", {PERSISTENT, BOOL, "0"}}, + {"dp_device_model_selected", {PERSISTENT, STRING}}, + {"dp_device_model_list", {PERSISTENT, STRING}}, + {"dp_lat_lca_speed", {PERSISTENT, INT, "20"}}, + {"dp_lat_lca_auto_sec", {PERSISTENT, FLOAT, "0.0"}}, + {"dp_device_go_off_road", {CLEAR_ON_MANAGER_START, BOOL}}, + {"dp_ui_hide_hud_speed_kph", {PERSISTENT, INT, "0"}}, + {"dp_lon_ext_radar", {PERSISTENT, BOOL, "0"}}, + {"dp_lat_road_edge_detection", {PERSISTENT, BOOL, "0"}}, + {"dp_ui_rainbow", {PERSISTENT, BOOL, "0"}}, + {"dp_lon_acm", {PERSISTENT, BOOL, "0"}}, + {"dp_lon_acm_downhill", {PERSISTENT, BOOL, "0"}}, + {"dp_lon_aem", {PERSISTENT, BOOL, "0"}}, + {"dp_device_audible_alert_mode", {PERSISTENT, INT, "0"}}, + {"dp_device_auto_shutdown_in", {PERSISTENT, INT, "-5"}}, + {"dp_ui_radar_tracks", {PERSISTENT, BOOL, "0"}}, + {"dp_dev_dashy", {PERSISTENT, INT, "0"}}, + {"dp_dev_delay_loggerd", {PERSISTENT, INT, "0"}}, }; diff --git a/dragonpilot/dashy/.nojekyll b/dragonpilot/dashy/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/dragonpilot/dashy/LICENSE.md b/dragonpilot/dashy/LICENSE.md new file mode 100644 index 000000000..aa1b82f61 --- /dev/null +++ b/dragonpilot/dashy/LICENSE.md @@ -0,0 +1,15 @@ +Copyright (c) 2025, Rick Lan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, and/or sublicense, +for non-commercial purposes only, subject to the following conditions: + +- The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +- Commercial use (e.g. use in a product, service, or activity intended to + generate revenue) is prohibited without explicit written permission from + the copyright holder. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/dragonpilot/dashy/README.md b/dragonpilot/dashy/README.md new file mode 100644 index 000000000..df5bb01eb --- /dev/null +++ b/dragonpilot/dashy/README.md @@ -0,0 +1,46 @@ +# Dashy Release Branch + +This is the production-ready release branch of Dashy - Dragonpilot's All-in-one System Hub for You. + +## 🚀 Quick Installation + +```bash +git clone -b release https://github.com/efinilan/dashy +cd dashy +python3 backend/server.py +``` + +## 📁 What's Included + +- `backend/` - Python server with all dependencies included +- `web/` - Pre-built web interface (minified and optimized) + +## 🌐 Access + +After starting the server, open Chrome browser and navigate to: +``` +http://:5088 +``` + +## 🔧 Requirements + +- Network connection +- Port 5088 available + +## 📄 License + +Copyright (c) 2025, Rick Lan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, and/or sublicense, +for non-commercial purposes only, subject to the following conditions: + +- The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +- Commercial use (e.g. use in a product, service, or activity intended to + generate revenue) is prohibited without explicit written permission from + the copyright holder. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/dragonpilot/dashy/backend/.gitignore b/dragonpilot/dashy/backend/.gitignore new file mode 100644 index 000000000..bee8a64b7 --- /dev/null +++ b/dragonpilot/dashy/backend/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/dragonpilot/dashy/backend/server.py b/dragonpilot/dashy/backend/server.py new file mode 100755 index 000000000..407a63115 --- /dev/null +++ b/dragonpilot/dashy/backend/server.py @@ -0,0 +1,194 @@ +""" +Copyright (c) 2025, Rick Lan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, and/or sublicense, +for non-commercial purposes only, subject to the following conditions: + +- The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +- Commercial use (e.g. use in a product, service, or activity intended to + generate revenue) is prohibited without explicit written permission from + the copyright holder. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" + +#!/usr/bin/env python3 + +import argparse +# import asyncio +# import json +import os +import logging +from datetime import datetime +from urllib.parse import quote +# import socket +# import sys + +from aiohttp import web + +from openpilot.common.params import Params +from openpilot.system.hardware import PC + + +# --- File Browser Settings --- +DEFAULT_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..') if PC else '/data/media/0/realdata') +WEB_DIST_PATH = os.path.join(os.path.dirname(__file__), "..", "web", "dist") + +def get_safe_path(requested_path): + """Ensures the requested path is within DEFAULT_DIR, preventing arbitrary file access""" + combined_path = os.path.join(DEFAULT_DIR, requested_path.lstrip('/')) + safe_path = os.path.realpath(combined_path) + if os.path.commonpath((safe_path, DEFAULT_DIR)) == DEFAULT_DIR: + return safe_path + return None + +async def list_files_api(request): + """API endpoint to list files and folders""" + try: + path_param = request.query.get('path', '/') + safe_path = get_safe_path(path_param) + if not safe_path or not os.path.isdir(safe_path): + return web.json_response({'error': 'Invalid or Not Found Path'}, status=404) + items = [] + for entry in os.listdir(safe_path): + full_path = os.path.join(safe_path, entry) + try: + stat = os.stat(full_path) + is_dir = os.path.isdir(full_path) + items.append({ + 'name': entry, + 'is_dir': is_dir, + 'mtime': datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M'), + 'size': stat.st_size if not is_dir else 0 + }) + except FileNotFoundError: + continue + directories = sorted([item for item in items if item['is_dir']], key=lambda x: x['mtime'], reverse=True) + files = sorted([item for item in items if not item['is_dir']], key=lambda x: x['mtime'], reverse=True) + items = directories + files + relative_path = os.path.relpath(safe_path, DEFAULT_DIR) + if relative_path == '.': + relative_path = '' + return web.json_response({'path': relative_path, 'files': items}) + except Exception as e: + return web.json_response({'error': str(e)}, status=500) + +async def serve_player_api(request): + """API endpoint to serve the HLS player page""" + file_path = request.query.get('file') + if not file_path: + return web.Response(text="File parameter is required.", status=400) + + player_html_path = os.path.join(WEB_DIST_PATH, 'pages', 'player.html') + try: + with open(player_html_path, 'r') as f: + html_template = f.read() + except FileNotFoundError: + return web.Response(text="Player HTML not found.", status=500) + + encoded_path = quote(file_path) + html = html_template.replace('{{FILE_PATH}}', encoded_path) + return web.Response(text=html, content_type='text/html') + +async def serve_manifest_api(request): + """API endpoint to dynamically generate m3u8 playlist""" + file_path = request.query.get('file').lstrip('/') + if not file_path: + return web.Response(text="File parameter is required.", status=400) + encoded_path = quote(file_path) + manifest = f"""#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-TARGETDURATION:60\n#EXT-X-PLAYLIST-TYPE:VOD\n#EXTINF:60.0,\n/media/{encoded_path}\n#EXT-X-ENDLIST\n""" + return web.Response(text=manifest, content_type='application/vnd.apple.mpegurl') + +async def save_settings_api(request): + """API endpoint to receive and save settings""" + try: + data = await request.json() + logging.getLogger("web_ui").info(f"Received settings to save: {data}") + return web.json_response({'status': 'success', 'message': 'Settings saved successfully!'}) + except Exception as e: + logging.getLogger("web_ui").error(f"Error saving settings: {e}") + return web.json_response({'status': 'error', 'message': str(e)}, status=500) + +async def init_api(request): + """API endpoint to provide initial data to the client.""" + try: + params = Params() + return web.json_response({ + 'is_metric': params.get_bool("IsMetric"), + 'dp_dev_dashy': int(params.get("dp_dev_dashy") or 0) + }) + except Exception as e: + logging.getLogger("web_ui").error(f"Error fetching initial data: {e}") + return web.json_response({'error': f"Error fetching initial data: {e}"}, status=500) + +async def on_startup(app): + logging.getLogger("web_ui").info("Web UI application starting up...") + +async def on_cleanup(app): + logging.getLogger("web_ui").info("Web UI application shutting down...") + +# --- CORS Middleware --- +@web.middleware +async def cors_middleware(request, handler): + response = await handler(request) + response.headers['Access-Control-Allow-Origin'] = '*' + response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS' + response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization' + return response + +async def handle_cors_preflight(request): + if request.method == 'OPTIONS': + headers = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + 'Access-Control-Max-Age': '86400', + } + return web.Response(status=200, headers=headers) + return await request.app['handler'](request) + +def setup_aiohttp_app(host: str, port: int, debug: bool): + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') + logging.getLogger("web_ui").setLevel(logging.DEBUG if debug else logging.INFO) + + app = web.Application(middlewares=[cors_middleware]) + app['port'] = port + + # Register API endpoints + app.router.add_get("/api/init", init_api) + app.router.add_get("/api/files", list_files_api) + app.router.add_get("/api/play", serve_player_api) + app.router.add_get("/api/manifest.m3u8", serve_manifest_api) + # app.router.add_post("/api/settings", save_settings_api) + + # Static files + app.router.add_static('/media', path=DEFAULT_DIR, name='media', show_index=False, follow_symlinks=False) + app.router.add_static('/download', path=DEFAULT_DIR, name='download', show_index=False, follow_symlinks=False) + app.router.add_get("/", lambda r: web.FileResponse(os.path.join(WEB_DIST_PATH, "index.html"))) + app.router.add_static("/", path=WEB_DIST_PATH) + + app.on_startup.append(on_startup) + app.on_cleanup.append(on_cleanup) + + # Add CORS preflight handler + app.router.add_route('OPTIONS', '/{tail:.*}', handle_cors_preflight) + + return app + +def main(): + # rick - may need "sudo ufw allow 5088" to allow port access + parser = argparse.ArgumentParser(description="Dashy Server") + parser.add_argument("--host", type=str, default="0.0.0.0", help="Host to listen on") + parser.add_argument("--port", type=int, default=5088, help="Port to listen on") + parser.add_argument("--debug", action="store_true", help="Enable debug mode") + args = parser.parse_args() + + app = setup_aiohttp_app(args.host, args.port, args.debug) + web.run_app(app, host=args.host, port=args.port) + +if __name__ == "__main__": + main() diff --git a/dragonpilot/dashy/web/dist/README.md b/dragonpilot/dashy/web/dist/README.md new file mode 100644 index 000000000..24d84a3b4 --- /dev/null +++ b/dragonpilot/dashy/web/dist/README.md @@ -0,0 +1,58 @@ +# dashy - dragonpilot's All-in-one System Hub for You + +A modern web-based dashboard for monitoring and controlling your dragonpilot/openpilot remotely. + +## Usage + +These files should be served by the Dashy backend server running on your comma device. + +Access the interface by navigating to `http://:5088` in Chrome browser. + +## Files + +- `index.html` - Main application +- `js/app.js` - Minified JavaScript bundle +- `css/styles.css` - Minified styles +- `icons/` - Favicon +- `pages/player.html` - HLS video player + +## Features + +- **Live Driving View** - Real-time WebRTC video with augmented reality overlay +- **File Browser** - Access and stream driving recordings +- **Settings Control** - Configure vehicle and display preferences + +## 🎮 Usage + +### Navigation +- **Driving View** - Live camera feed with lane lines and path visualization +- **Files** - Browse `/data/media/0/realdata` recordings +- **Local Settings** - Adjust display preferences + +### Display Options +- Metric/Imperial units +- HUD mode for windshield projection + +## Requirements + +- dragonpilot/openpilot device (comma 3/3X) +- Chrome browser (recommended) +- Same network connection as vehicle + +## 📄 License + +Copyright (c) 2025, Rick Lan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, and/or sublicense, +for non-commercial purposes only, subject to the following conditions: + +- The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +- Commercial use (e.g. use in a product, service, or activity intended to + generate revenue) is prohibited without explicit written permission from + the copyright holder. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/dragonpilot/dashy/web/dist/css/styles.css b/dragonpilot/dashy/web/dist/css/styles.css new file mode 100644 index 000000000..258ba4608 --- /dev/null +++ b/dragonpilot/dashy/web/dist/css/styles.css @@ -0,0 +1 @@ +:root{--bg-dark:#1a202c;--bg-med:#2d3748;--bg-light:#4a5568;--border-color:#4a5568;--text-light:#e2e8f0;--text-med:#a0aec0;--accent-blue:#4299e1;--accent-green:#48bb78;--border-color-disengaged:#173349C8;--border-color-override:#919B95F1;--border-color-engaged:#178644F1;--alert-red:rgba(200, 0, 0, 0.95);--alert-orange:rgba(254, 140, 52, 0.95);--alert-black:rgba(0, 0, 0, 0.65)}body,html{margin:0;padding:0;width:100%;height:100%;overflow:hidden;background-color:var(--bg-dark);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}#app-container,.page{width:100%;height:100%;flex-direction:column}#app-container{display:flex}nav{background-color:var(--bg-med);flex-shrink:0;position:absolute;top:0;width:100%;z-index:1000;opacity:0;pointer-events:none;transition:opacity .3s cubic-bezier(.4,0,.2,1);will-change:opacity}nav.visible{opacity:1;pointer-events:auto}nav button{flex-grow:1;padding:12px 0;font-size:1rem;font-weight:500;background-color:transparent;border:0;border-bottom:3px solid transparent;color:var(--text-med);cursor:pointer;transition:color .2s,border-color .2s}#files-breadcrumbs a:hover,body,html,nav button:hover{color:var(--text-light)}nav button.active{color:#fff;border-bottom-color:var(--accent-blue)}.page{display:none;overflow:hidden;background-color:var(--bg-dark);position:relative;contain:layout style paint}.page.active,nav{display:flex}#driving-page-content{position:relative;width:100%;flex-grow:1;min-height:0;box-sizing:border-box}#uiCanvas,#videoPlayer{position:absolute;top:0;left:0;width:100%;height:100%;will-change:transform;transform:translateZ(0);backface-visibility:hidden}#videoPlayer{object-fit:cover;background-color:#000}#videoPlayer.hud-mode{transform:scaleY(-1)}#uiCanvas{z-index:1}.settings-page-wrapper{width:100%;height:100%;overflow-y:auto;padding:1.5rem;box-sizing:border-box;padding-bottom:80px;padding-top:60px}.settings-page h1{margin-top:0;color:#fff;border-bottom:1px solid var(--border-color);padding-bottom:.5rem}.settings-category{margin-top:2rem}.settings-category h2{color:var(--accent-blue);font-size:1.2rem;margin-bottom:1rem;border-bottom:1px solid var(--bg-light);padding-bottom:.5rem}.setting-item{background-color:var(--bg-med);padding:1rem;border-radius:8px;margin-bottom:1rem;display:flex;justify-content:space-between;align-items:center}#driving-page-content{background-color:#000}.setting-label p{margin:0;font-weight:500}.setting-label span{font-size:.85rem;color:var(--text-med)}.setting-control{display:flex;align-items:center;gap:10px}.toggle-switch{position:relative;display:inline-block;width:50px;height:28px}.toggle-switch input{opacity:0;width:0;height:0}.toggle-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:var(--bg-light);transition:background-color .4s cubic-bezier(.4,0,.2,1);border-radius:28px}.toggle-slider:before{position:absolute;content:"";height:20px;width:20px;left:4px;bottom:4px;background-color:#fff;transition:transform .4s cubic-bezier(.4,0,.2,1);border-radius:50%}input:checked+.toggle-slider{background-color:var(--accent-green)}input:checked+.toggle-slider:before{transform:translateX(22px)}.btn-group button,.stepper button{background:var(--bg-light);cursor:pointer}.stepper button{border:0;color:var(--text-light);width:30px;height:30px;border-radius:50%;font-size:1.2rem;line-height:30px;text-align:center}.stepper-value{font-weight:500;min-width:40px;text-align:center}.btn-group button{border:1px solid var(--border-color);color:var(--text-med);padding:8px 16px;transition:background-color .2s}.btn-group button:first-child{border-radius:8px 0 0 8px}.btn-group button:last-child{border-radius:0 8px 8px 0}.btn-group button.active{background:var(--accent-blue);color:#fff}.text-input{background:var(--bg-light);border:1px solid var(--border-color);color:var(--text-light);border-radius:8px;padding:8px 12px;font-size:1rem;width:150px}#save-bar{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(to top,#1a202c,rgba(26,32,44,.8));padding:1rem;display:flex;justify-content:flex-end;align-items:center;gap:1rem}#save-status{color:var(--text-med);transition:opacity .5s}#save-settings-btn{background-color:var(--accent-blue);color:#fff;border:0;padding:10px 25px;border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:background-color .2s}#save-settings-btn:hover{background-color:#2b6cb0}#save-settings-btn:disabled{background-color:var(--bg-light);cursor:not-allowed}#files-page{padding:1rem;box-sizing:border-box;overflow-y:auto;padding-top:60px}#files-breadcrumbs{margin-bottom:1rem;font-size:1.1em;word-wrap:break-word}#files-breadcrumbs a,#files-table td a{color:var(--text-med);text-decoration:none}#files-table{width:100%;border-collapse:collapse}#files-table td,#files-table th{padding:10px 8px;text-align:left;border-bottom:1px solid var(--bg-med);white-space:nowrap}#files-table th{font-weight:600}#files-table tr:hover{background-color:var(--bg-med)}#files-table td a{color:var(--text-light);font-weight:500}.file-icon{display:inline-block;width:2em;text-align:center}.file-size{text-align:right;color:var(--text-med)}.play-button{font-weight:700;color:#28a745;font-size:1.5em;cursor:pointer;text-decoration:none} \ No newline at end of file diff --git a/dragonpilot/dashy/web/dist/icons/icon-192x192.png b/dragonpilot/dashy/web/dist/icons/icon-192x192.png new file mode 100644 index 000000000..c1481e9de Binary files /dev/null and b/dragonpilot/dashy/web/dist/icons/icon-192x192.png differ diff --git a/dragonpilot/dashy/web/dist/index.html b/dragonpilot/dashy/web/dist/index.html new file mode 100644 index 000000000..41e3e85c4 --- /dev/null +++ b/dragonpilot/dashy/web/dist/index.html @@ -0,0 +1 @@ +Dashy by dragonpilot
NameLast ModifiedSize

Local Settings

\ No newline at end of file diff --git a/dragonpilot/dashy/web/dist/js/app.js b/dragonpilot/dashy/web/dist/js/app.js new file mode 100644 index 000000000..a04c57479 --- /dev/null +++ b/dragonpilot/dashy/web/dist/js/app.js @@ -0,0 +1 @@ +const t=500,e=10,i=100,a=.5,s=60,n=1/30,r=[{r:13,g:248,b:122,a:102},{r:114,g:255,b:92,a:89},{r:114,g:255,b:92,a:0}],o=[{r:242,g:242,b:242,a:102},{r:242,g:242,b:242,a:89},{r:242,g:242,b:242,a:0}];function l(t,e){const i=[[0,0,0],[0,0,0],[0,0,0]];for(let a=0;a<3;a++)for(let s=0;s<3;s++)i[a][s]=t[a][0]*e[0][s]+t[a][1]*e[1][s]+t[a][2]*e[2][s];return i}function d(t,e){return[t[0][0]*e[0]+t[0][1]*e[1]+t[0][2]*e[2],t[1][0]*e[0]+t[1][1]*e[1]+t[1][2]*e[2],t[2][0]*e[0]+t[2][1]*e[1]+t[2][2]*e[2]]}function h(t,e,i,a){const s=t[0][0]*e+t[0][1]*i+t[0][2]*a,n=t[1][0]*e+t[1][1]*i+t[1][2]*a,r=t[2][0]*e+t[2][1]*i+t[2][2]*a;return Math.abs(r)<1e-6?{x:0,y:0,z:0,valid:!1}:{x:s/r,y:n/r,z:r,valid:!0}}function c(t,e,i){return Math.max(e,Math.min(i,t))}function _(t){const[e,i,a]=t,s=Math.cos(e),n=Math.sin(e),r=Math.cos(i),o=Math.sin(i),l=Math.cos(a),d=Math.sin(a);return[[l*r,l*o*n-d*s,l*o*s+d*n],[d*r,d*o*n+l*s,d*o*s-l*n],[-o,r*n,r*s]]}const g=[[0,-1,0],[0,0,-1],[1,0,0]],u={tici:{fcam:{intrinsics:[[2648,0,964],[0,2648,604],[0,0,1]],width:1928,height:1208}},mici:{fcam:{intrinsics:[[1141.5,0,672],[0,1141.5,380],[0,0,1]],width:1344,height:760}}};class p{constructor(){window.debug,this._longitudinal_control=!1,this._experimental_mode=!1,this._blend_factor=1,this._prev_allow_throttle=!0,this._lane_line_probs=new Float32Array(4),this._road_edge_stds=new Float32Array(2),this._lead_vehicles=[{},{}],this._path_offset_z=1.22,this._use_simple_lines=!0,this._path={raw_points:[],projected_points:[]},this._lane_lines=[{raw_points:[],projected_points:[]},{raw_points:[],projected_points:[]},{raw_points:[],projected_points:[]},{raw_points:[],projected_points:[]}],this._road_edges=[{raw_points:[],projected_points:[]},{raw_points:[],projected_points:[]}],this._acceleration_x=new Float32Array(0),this._maxPoints=200,this._leftPointsBuffer=new Array(this._maxPoints),this._rightPointsBuffer=new Array(this._maxPoints),this._transformCache=new Map,this._transformCacheValid=!1,this._batchTransformEnabled=!0,this._batchLeftX=new Float32Array(this._maxPoints),this._batchLeftY=new Float32Array(this._maxPoints),this._batchLeftZ=new Float32Array(this._maxPoints),this._batchRightX=new Float32Array(this._maxPoints),this._batchRightY=new Float32Array(this._maxPoints),this._batchRightZ=new Float32Array(this._maxPoints),this._gradientCache=new Map,this._gradientCacheMaxSize=20,this._pathCache=new Map,this._pathCacheMaxSize=10,this._lastPathPoints=null,this._lastPathHash=null,this._pathLengthCache=new Map,this._lastPathLengthCacheClear=0,this._framePathLengthCache=new Map,this._lastFrameTime=0,this._car_space_transform=[[1,0,0],[0,1,0],[0,0,1]],this._transform_dirty=!0,this._clip_region=null,this._rect=null,setInterval(()=>{this._transformCache.clear(),this._pathLengthCache.clear(),this._gradientCache.clear(),window.debug},3e4),this._exp_gradient={start:[0,1],end:[0,0],colors:[],stops:[]}}set_transform(t){window.debug,this._car_space_transform=t,this._transform_dirty=!0,this._transformCache.clear(),this._transformCacheValid=!1,this._gradientCache.clear(),this._transform_logged||(this._transform_logged=!0)}set_simple_lines_mode(t){window.debug,this._use_simple_lines=t}clear_caches(){window.debug,this._transformCache.clear(),this._transformCacheValid=!1,this._gradientCache.clear(),this._pathCache.clear(),this._lastPathHash=null}render(t,e,i){if(window.debug,this._rect=t,this.ctx=i,i.lineCap="round",i.lineJoin="round",this._debug_logged||(this._debug_logged=!0),!e.liveCalibration||!e.modelV2)return;this._clip_region={x:t.x,y:t.y,width:t.width,height:t.height},e.selfdriveState&&(this._experimental_mode=e.selfdriveState.experimentalMode||!1);const a=e.liveCalibration;a&&a.height&&a.height.length>0&&(this._path_offset_z=a.height[0]),e.updated&&e.updated.carParams?this._longitudinal_control=e.carParams.openpilotLongitudinalControl||!1:e.seen&&e.seen.carParams||(this._longitudinal_control=!0);const s=e.modelV2;if(!s)return;const n=e.valid&&e.valid.radarState?e.radarState:null,r=n?n.leadOne:null,o=this._longitudinal_control&&null!==n;!this._radar_logged&&n&&(this._radar_logged=!0);const l=e.updated&&e.updated.modelV2,d=e.updated&&e.updated.radarState;if(this._update_logged||!l&&!d||(this._update_logged=!0),l||d||this._transform_dirty){l&&this._update_raw_points(s);const t=this._path.raw_points.map(t=>t[0]);if(0===t.length)return;this._update_model(r,t),o&&this._update_leads(n,t),this._transform_dirty=!1}this._draw_lane_lines(),this._draw_path(e),o&&n&&this._draw_lead_indicator()}_update_raw_points(t){if(window.debug,t.position){this._path.raw_points.length=0;for(let e=0;e200){Array.from(this._transformCache.keys()).slice(0,100).forEach(t=>this._transformCache.delete(t)),window.debug}if(this._pathCache.size>this._pathCacheMaxSize){const t=Array.from(this._pathCache.entries()).slice(-5);this._pathCache.clear(),t.forEach(([t,e])=>this._pathCache.set(t,e))}t.laneLines&&t.laneLines.forEach((t,e)=>{this._lane_lines[e].raw_points.length=0;for(let i=0;i{this._road_edges[e].raw_points.length=0;for(let i=0;it[0]),s);this._batch_update_lines(n,t,a),this._update_experimental_gradient(this._rect.height)}_batch_update_lines(t,a,s){const n=[];for(let e=0;et[0]>=0);t.length>0&&(i.push({...a,points:t,startIdx:e,numPoints:t.length}),e+=2*t.length)}if(0===e)return;const a=new Float32Array(e),s=new Float32Array(e),n=new Float32Array(e);let r=0;for(const t of i)for(let e=0;e1){const t=[],e=[];let s=1/0;for(let n=0;ne.push(t));for(let t=a.length-1;t>=0;t--)e.push(a[t]);t.line.projected_points=e}}_update_leads(t,e){window.debug,this._lead_vehicles=[{},{}];const i=[t.leadOne,t.leadTwo],a=[],s={x:[],y:[],z:[]};for(let t=0;t=1e-6){const t=1/v;s[n]={x:m*t,y:b*t,valid:!0},r++}else s[n]={x:0,y:0,valid:!1}}return{points:s,validCount:r}}_map_line_to_polygon(t,e,i,a,s=!0){if(window.debug,0===t.length)return[];let n=t.slice(0,a+1);if(n=n.filter(t=>t[0]>=0),0===n.length)return[];const r=n.length,o=[],l=[];if(this._batchTransformEnabled&&r>10){for(let t=0;t1){const t=[],e=[];let i=1/0;for(let a=0;ad.push(t));for(let t=l.length-1;t>=0;t--)d.push(l[t]);return d}_get_path_length_idx(t,e){if(window.debug,0===t.length)return 0;const i=`${t.length}_${e.toFixed(2)}`,a=Date.now();if(a!==this._lastFrameTime&&(this._framePathLengthCache.clear(),this._lastFrameTime=a),this._framePathLengthCache.has(i))return this._framePathLengthCache.get(i);if(this._pathLengthCache.has(i)){const t=this._pathLengthCache.get(i);return this._framePathLengthCache.set(i,t),t}a-this._lastPathLengthCacheClear>6e4&&(this._pathLengthCache.clear(),this._lastPathLengthCacheClear=a);let s=0;for(let i=0;i{if(0===t.projected_points.length)return;const i=c(this._lane_line_probs[e],0,.7);this._draw_polygon(t.projected_points,`rgba(255, 255, 255, ${i})`)}),this._road_edges.forEach((t,e)=>{if(0===t.projected_points.length)return;const i=c(1-this._road_edge_stds[e],0,1);this._draw_polygon(t.projected_points,`rgba(255, 0, 0, ${i})`)}))}_batch_draw_all_lines(){const t=[];if(this._lane_lines.forEach((e,i)=>{if(e.raw_points.length<2)return;const a=this._lane_line_probs[i];if(a<.1)return;const s=c(a,0,.7);t.push({points:e.raw_points,color:`rgba(255, 255, 255, ${s})`,lineWidth:4})}),this._road_edges.forEach((e,i)=>{if(e.raw_points.length<2)return;const a=this._road_edge_stds[i];if(a>.9)return;const s=c(1-a,0,1);t.push({points:e.raw_points,color:`rgba(255, 0, 0, ${s})`,lineWidth:4})}),0===t.length)return;let e=0;const i=[];for(const a of t){const t=[];for(let e=0;e=0&&i[0]<=100&&t.push(e)}t.length>=2&&(i.push({...a,validIndices:t,startIdx:e,numPoints:t.length}),e+=t.length)}if(0===e)return;const a=new Float32Array(e),s=new Float32Array(e),n=new Float32Array(e);let r=0;for(const t of i)for(const e of t.validIndices){const i=t.points[e];a[r]=i[0],s[r]=i[1],n[r]=i[2],r++}const o=this._batch_transform(a,s,n,e),l=this.ctx;for(const t of i){l.strokeStyle=t.color,l.lineWidth=t.lineWidth,l.beginPath();let e=!1;for(let i=0;i0&&t.validIndices[i]-t.validIndices[i-1]===1?l.lineTo(s.x,s.y):(l.stroke(),l.beginPath(),l.moveTo(s.x,s.y)):(l.moveTo(s.x,s.y),e=!0):e&&(l.stroke(),l.beginPath(),e=!1)}e&&l.stroke()}}_draw_path(t){if(window.debug,0!==this._path.projected_points.length)if(this._experimental_mode)this._exp_gradient.colors.length>2?this._draw_polygon_gradient(this._path.projected_points,this._exp_gradient):this._draw_polygon(this._path.projected_points,"rgba(255, 255, 255, 0.12)");else{const e=t.longitudinalPlan&&t.longitudinalPlan.allowThrottle||!this._longitudinal_control;e!==this._prev_allow_throttle&&(this._prev_allow_throttle=e,this._blend_factor=Math.max(1-this._blend_factor,0)),this._blend_factor<1&&(this._blend_factor=Math.min(this._blend_factor+n,1));const i=e?o:r,a=e?r:o,s={start:[0,1],end:[0,0],colors:this._blend_colors(i,a,this._blend_factor),stops:[0,.5,1]};this._draw_polygon_gradient(this._path.projected_points,s)}}_draw_polygon(t,e){if(window.debug,t.length<3)return;const i=this.ctx;i.fillStyle=e;const a=this._getCachedPath2D(t);i.fill(a)}_getCachedPath2D(t){window.debug;const e=this._generatePointsHash(t);if(this._pathCache.has(e))return this._pathCache.get(e);const i=new Path2D;i.moveTo(t[0][0],t[0][1]);for(let e=1;ethis._pathCacheMaxSize){const t=this._pathCache.keys().next().value;this._pathCache.delete(t)}return i}_generatePointsHash(t){if(window.debug,t.length<3)return"empty";const e=t[0],i=t[Math.floor(t.length/2)],a=t[t.length-1],s=t=>Math.round(10*t)/10;return`${t.length}:${s(e[0])},${s(e[1])}:${s(i[0])},${s(i[1])}:${s(a[0])},${s(a[1])}`}_draw_simple_line(t,e,a=2){if(window.debug,t.length<2)return;const s=this.ctx;s.strokeStyle=e,s.lineWidth=a;const n=Math.min(i,t[t.length-1][0]||i),r=[],o=[],l=[],d=[];for(let e=0;e=0&&i[0]<=n&&(r.push(e),o.push(i[0]),l.push(i[1]),d.push(i[2]))}if(r.length<2)return;const h=this._batch_transform(new Float32Array(o),new Float32Array(l),new Float32Array(d),o.length);let c=!1;s.beginPath();for(let t=0;t0&&r[t]-r[t-1]===1?s.lineTo(e.x,e.y):(s.stroke(),s.beginPath(),s.moveTo(e.x,e.y)):(s.moveTo(e.x,e.y),c=!0):c&&(s.stroke(),s.beginPath(),c=!1)}c&&s.stroke()}_draw_polygon_gradient(t,e){if(window.debug,t.length<3)return;const i=this.ctx,a=this._rect,s=e.start[0]*a.width+a.x,n=e.start[1]*a.height+a.y,r=e.end[0]*a.width+a.x,o=e.end[1]*a.height+a.y,l=this._getCachedGradient(i,s,n,r,o,e),d=this._getCachedPath2D(t);i.fillStyle=l,i.fill(d)}_getCachedGradient(t,e,i,a,s,n){window.debug;const r=`${Math.round(e)},${Math.round(i)},${Math.round(a)},${Math.round(s)}:${n.colors.map(t=>`${t.r},${t.g},${t.b},${t.a}`).join("|")}:${n.stops.join(",")}`;if(this._gradientCache.has(r))return this._gradientCache.get(r);const o=t.createLinearGradient(e,i,a,s);for(let t=0;tthis._gradientCacheMaxSize){const t=this._gradientCache.keys().next().value;this._gradientCache.delete(t)}return o}_blend_colors(t,e,i){if(window.debug,i>=1)return e;if(i<=0)return t;const a=1-i;return t.map((t,s)=>{const n=e[s];return{r:Math.round(a*t.r+i*n.r),g:Math.round(a*t.g+i*n.g),b:Math.round(a*t.b+i*n.b),a:Math.round(a*t.a+i*n.a)}})}_update_experimental_gradient(t){window.debug,this._exp_gradient.colors=[],this._exp_gradient.stops=[]}_update_lead_vehicle(t,e,i,a){window.debug;const s=1.57*c(750/(t/3+30),15,30)*1;this._lead_size_logged||(this._lead_size_logged=!0);const n=c(i[0],0,a.width-s/2),r=Math.min(i[1],a.height-.6*s),o=s/5,l=s/10;let d=0;return t<40&&(d=255*(1-t/40),e<0&&(d+=e/10*-1*255),d=Math.min(d,255)),{glow:[[n+1.35*s+o,r+s+l],[n,r-l],[n-1.35*s-o,r+s+l]],chevron:[[n+1.25*s,r+s],[n,r],[n-1.25*s,r+s]],fill_alpha:d}}_draw_lead_indicator(){window.debug,this._lead_debug_logged||(this._lead_debug_logged=!0),this._lead_vehicles.forEach(t=>{t.glow&&t.chevron&&(this._draw_triangle_fan(t.glow,"rgba(218, 202, 37, 1)"),this._draw_triangle_fan(t.chevron,`rgba(201, 34, 49, ${t.fill_alpha/255})`))})}_draw_triangle_fan(t,e){if(window.debug,t.length<3)return;const i=this.ctx;i.fillStyle=e;const a=t[0],s=new Path2D;for(let e=1;e0&&this.set_speed0&&e-this.started_time>5e3?G:null;t.updated&&t.updated.selfdriveState&&(this.last_selfdrive_time=e);const i=t.deviceState;if(i&&["tici","tizi","mici"].includes(i.deviceType)&&this.last_selfdrive_time>0){const i=(e-this.last_selfdrive_time)/1e3;if(i>5){const e=t.selfdriveState;return e&&e.enabled&&i-515?A:I;this.ctx.font=`bold ${i}px Arial`,this.ctx.textBaseline="middle",this.ctx.fillText(e.text1,t.x+t.width/2,t.y+t.height/2),this.ctx.font="bold 48px Arial",this.ctx.textBaseline="top",this.ctx.fillText(e.text2,t.x+t.width/2,t.y+2*t.height/3)}}}window.AlertRenderer=j;const N=8,H="calibrated",W=[1.22],q={DISENGAGED:{r:23,g:51,b:73,a:200},OVERRIDE:{r:145,g:155,b:149,a:241},ENGAGED:{r:23,g:134,b:68,a:241}};function c(t,e,i){return Math.max(e,Math.min(i,t))}class U{constructor(){window.debug,this.device_camera=null,this.view_from_calib=[...g.map(t=>[...t])],this._last_calib_time=0,this._last_rect_dims={width:0,height:0},this._cached_matrix=null,this._content_rect={x:0,y:0,width:0,height:0},this.model_renderer=new p,this._hud_renderer=new C,this.alert_renderer=new j,this._click_callback=null}render(t,e,i){window.debug,this.sm=e,this.ctx=i,this._update_calibration();const a=t.width-16,s=t.height-16,n=this.device_camera||u.tici,r=a/s,o=n.fcam.width/n.fcam.height;let l=a,d=s,h=t.x+8,c=t.y+8;r>o?(l=s*o,h=t.x+8+(a-l)/2):(d=a/o,c=t.y+8+(s-d)/2),this._content_rect={x:h,y:c,width:l,height:d},this._draw_border(t),i.save(),i.beginPath(),i.rect(Math.floor(t.x),Math.floor(t.y),Math.floor(t.width),Math.floor(t.height)),i.clip(),this._calc_frame_matrix(),this.model_renderer.render(t,e,i),i.restore(),this._hud_renderer.render(t,e,i);this.alert_renderer.render(t,e,i);this._hud_renderer.handle_mouse_event(t)||this._click_callback}set_callbacks(t=null){window.debug,this._click_callback=t}invalidate_transform_cache(){window.debug,this._cached_matrix=null,this._last_rect_dims={width:0,height:0},this._last_calib_time=0,this.model_renderer&&this.model_renderer.clear_caches(),this.model_renderer&&(this.model_renderer._transform_dirty=!0)}_update_calibration(){window.debug;const t=this.sm;if(!this.device_camera&&t.seen&&t.seen.roadCameraState&&t.seen.deviceState){const e=t.deviceState?t.deviceState.deviceType:"tici";this.device_camera="mici"===e?u.mici:u.tici}if(!t.liveCalibration)return;const e=t.liveCalibration;if(!e.rpyCalib||3!==e.rpyCalib.length||e.calStatus!==H)return void(e.calStatus!==H&&(this.view_from_calib=[...g.map(t=>[...t])]));const i=_(e.rpyCalib);this.view_from_calib=l(g,i),this._cached_matrix=null}_calc_frame_matrix(){window.debug;const t=this.sm.updated&&this.sm.updated.liveCalibration,e=this.sm.recv_frame?this.sm.recv_frame.liveCalibration:Date.now(),i=this.ctx.canvas.width,a=this.ctx.canvas.height,s={width:i,height:a};if(!t&&this._last_calib_time===e&&this._last_rect_dims.width===s.width&&this._last_rect_dims.height===s.height&&null!==this._cached_matrix)return this._cached_matrix;const n=this.device_camera||u.tici,r=n.fcam.intrinsics,o=n.fcam.width,d=n.fcam.height,h=this.view_from_calib,c=(this._content_rect.x,this._content_rect.y,this._content_rect.width,this._content_rect.height,Math.max(i/o,a/d)),_=r[0][0]*c*1.1,g=l([[-_,0,i/2],[0,-_,a/2],[0,0,1]],h);return this.model_renderer.set_transform(g),this._last_calib_time=e,this._last_rect_dims=s,this._cached_matrix=g,this._cached_matrix}_draw_border(t){window.debug;const e=this.sm.selfdriveState&&this.sm.selfdriveState.engageable?"ENGAGED":"DISENGAGED",i=q[e]||q.DISENGAGED;this.ctx.strokeStyle=`rgba(${i.r}, ${i.g}, ${i.b}, ${i.a/255})`,this.ctx.lineWidth=8,this.ctx.strokeRect(t.x,t.y,t.width,t.height)}}window.AugmentedRoadView=U;const X=new URLSearchParams(window.location.search),Y="true"===X.get("debug"),J="true"===localStorage.getItem("debug");if(window.debug=Y||J||!1,Y!==J&&(Y?localStorage.setItem("debug","true"):X.has("debug")&&localStorage.removeItem("debug")),window._originalConsoleLog=console.log,console.log=function(...t){window.debug&&window._originalConsoleLog(...t)},window.debug){window._originalConsoleLog("%c🐛 Debug Mode Enabled","color: #00ff00; font-weight: bold; font-size: 16px"),window._originalConsoleLog("To disable: add ?debug=false to URL or run dashy.debug(false)");const t=document.createElement("div");t.id="debug-indicator",t.textContent="🐛 DEBUG",t.style.cssText="\n position: fixed;\n top: 10px;\n right: 10px;\n background: rgba(255, 0, 0, 0.8);\n color: white;\n padding: 5px 10px;\n border-radius: 5px;\n font-family: monospace;\n font-size: 12px;\n z-index: 10000;\n pointer-events: none;\n ",document.addEventListener("DOMContentLoaded",()=>{document.body.appendChild(t)})}window.dashy={debug:function(t=!0){return window.debug=t,t?(localStorage.setItem("debug","true"),window._originalConsoleLog("%c🐛 Debug Mode Enabled","color: #00ff00; font-weight: bold"),window._originalConsoleLog("Refresh page to see all debug logs")):(localStorage.removeItem("debug"),window._originalConsoleLog("%c🔇 Debug Mode Disabled","color: #ff0000; font-weight: bold")),t?"Debug enabled":"Debug disabled"},perf:function(){const t={fps:window._fps||0,frameTime:window._frameTime||0,drawCalls:window._drawCalls||0,canvasOps:window._canvasOps||0};return window._originalConsoleLog("%cPerformance Metrics","color: #00aaff; font-weight: bold"),window._originalConsoleLog(t),t},help:function(){window._originalConsoleLog("%cDashy Debug Commands:","color: #ffaa00; font-weight: bold; font-size: 14px"),window._originalConsoleLog("dashy.debug(true/false) - Enable/disable debug mode"),window._originalConsoleLog("dashy.perf() - Show performance metrics"),window._originalConsoleLog("dashy.help() - Show this help"),window._originalConsoleLog("\nURL Parameters:"),window._originalConsoleLog("?debug=true - Enable debug mode"),window._originalConsoleLog("?debug=false - Disable debug mode")}},function(){let t=0,e=null,i=0;function a(a,s,n){const r=document.getElementById("driving-page");if(!r||!r.classList.contains("active"))return;const o=window.innerWidth,l=window.innerHeight;if(a>o-100&&s>l-100){const r=Date.now();if(r-i<100)return void window._originalConsoleLog(`[Debug Toggle] Ignoring duplicate ${n} event`);if(i=r,t++,window._originalConsoleLog(`[Debug Toggle] ${n} count: ${t}/5 (at ${a},${s})`),e&&clearTimeout(e),e=setTimeout(()=>{t=0,window._originalConsoleLog("[Debug Toggle] Tap count reset to 0")},1e3),5===t){t=0;const e=!window.debug;window.dashy.debug(e);const i=document.createElement("div");i.textContent=e?"🐛 Debug Enabled":"🔇 Debug Disabled",i.style.cssText=`\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: ${e?"rgba(0, 255, 0, 0.9)":"rgba(255, 0, 0, 0.9)"};\n color: white;\n padding: 20px 40px;\n border-radius: 10px;\n font-size: 24px;\n font-weight: bold;\n z-index: 10001;\n pointer-events: none;\n `,document.body.appendChild(i),navigator.vibrate&&navigator.vibrate(e?[100,50,100]:[200]),setTimeout(()=>{i.remove(),location.reload()},1500)}}}document.addEventListener("touchstart",t=>{const e=t.touches[0];e.clientX>window.innerWidth-100&&e.clientY>window.innerHeight-100&&(a(e.clientX,e.clientY,"Touch"),t.preventDefault())},{passive:!1}),document.addEventListener("click",t=>{t.clientX>window.innerWidth-100&&t.clientY>window.innerHeight-100&&a(t.clientX,t.clientY,"Click")})}();const Z={sections:[{title:"Visual",settings:[{id:"HudModeEnabled",type:"toggle",label:"Heads-up Display (HUD) Mode",description:"Mirror the display for windshield projection.",defaultValue:!1,storage:"local"},{id:"ShowVideoInHud",type:"toggle",label:"Show Video",description:"Show or hide video stream in HUD mode.",defaultValue:!0,storage:"local",indent:!0,dependsOn:"HudModeEnabled"}]}]},K={events:{},on(t,e){return this.events[t]||(this.events[t]=[]),this.events[t].push(e),()=>this.off(t,e)},off(t,e){this.events[t]&&(this.events[t]=this.events[t].filter(t=>t!==e))},emit(t,e){this.events[t]&&this.events[t].forEach(t=>t(e))}},Q={_data:{settings:{},localSettings:{},ui:{currentPage:"files",navBarVisible:!1,hudModeEnabled:!1,showVideoInHud:!0},files:{currentPath:"/",items:[]}},get(t){return t.split(".").reduce((t,e)=>t?.[e],this._data)},set(t,e){const i=t.split("."),a=i.pop(),s=i.reduce((t,e)=>(t[e]||(t[e]={}),t[e]),this._data),n=s[a];n!==e&&(s[a]=e,K.emit("state:change",{path:t,value:e,oldValue:n}),K.emit(`state:${t}`,e))},subscribe:(t,e)=>K.on(`state:${t}`,e)},tt={fileRow:(t,e)=>{const i=t.is_dir?"📁":t.name.endsWith(".ts")?"🎞️":"📄",a=`${e}/${t.name}`.replace("//","/");return`\n \n ${i}${t.name.endsWith(".ts")?``:""}\n ${t.is_dir?`${t.name}`:`${t.name}`}\n ${t.mtime}\n ${t.is_dir?"-":Dt(t.size)}\n \n `},breadcrumb:t=>{const e=t.split("/").filter(Boolean);let i="";const a=['root'];return e.forEach((t,s)=>{i+="/"+t,s===e.length-1?a.push(t):a.push(`${t}`)}),a.join(" / ")},alert:(t,e,i="normal")=>`\n
\n

${t}

\n ${e?`

${e}

`:""}\n
\n `};function et(t,...e){const i=t(...e),a=document.createElement("div");return a.innerHTML=i,a.firstElementChild||a.childNodes}function it(t,e,i={}){const a=document.createElement(t);return e&&(a.className=e),Object.entries(i).forEach(([t,e])=>{"dataset"===t?Object.entries(e).forEach(([t,e])=>{a.dataset[t]=e}):a[t]=e}),a}function at(t){const e=it("label","toggle-switch"),i=it("input","",{type:"checkbox",dataset:{param:t.id}});t.storage&&(i.dataset.storage=t.storage),t.defaultValue&&(i.checked=!0);const a=it("span","toggle-slider");return e.appendChild(i),e.appendChild(a),e}function st(t){const e=it("div","setting-control stepper",{dataset:{param:t.id}});void 0!==t.min&&(e.dataset.min=t.min),void 0!==t.max&&(e.dataset.max=t.max);const i=it("button","",{dataset:{step:-t.step},textContent:"-"}),a=it("span","stepper-value",{textContent:t.defaultValue}),s=it("button","",{dataset:{step:t.step},textContent:"+"});return e.appendChild(i),e.appendChild(a),e.appendChild(s),e}function nt(t){const e=it("div","setting-control btn-group",{dataset:{param:t.id}});return t.storage&&(e.dataset.storage=t.storage),t.options.forEach(i=>{const a=it("button","",{dataset:{value:i.value},textContent:i.text});i.value===t.defaultValue&&a.classList.add("active"),e.appendChild(a)}),e}function rt(t){return it("input","text-input",{type:"text",placeholder:t.placeholder||"",dataset:{param:t.id}})}function ot(t){const e=it("div","setting-item",{id:"ShowVideoInHud"===t.id?"show-video-setting":""});t.indent&&(e.style.marginLeft="2rem"),t.dependsOn&&(e.style.display="none");const i=it("div","setting-label"),a=it("p","",{textContent:t.label}),s=it("span","",{textContent:t.description});i.appendChild(a),i.appendChild(s);const n=it("div","setting-control");let r;switch(t.type){case"toggle":r=at(t);break;case"stepper":return r=st(t),e.appendChild(i),e.appendChild(r),e;case"btn-group":return r=nt(t),e.appendChild(i),e.appendChild(r),e;case"text-input":r=rt(t),n.appendChild(r)}return"toggle"===t.type&&n.appendChild(r),e.appendChild(i),e.appendChild(n),e}function lt(t,e){t.sections.forEach(t=>{const i=it("div","settings-category"),a=it("h2","",{textContent:t.title});i.appendChild(a),t.settings.forEach(t=>{i.appendChild(ot(t))}),e.appendChild(i)})}const dt=document.getElementById("app-container"),ht=document.getElementById("driving-page"),ct=document.getElementById("files-page"),_t=document.getElementById("settings-page"),gt=document.getElementById("local-settings-page"),ut=document.getElementById("nav-driving"),pt=document.getElementById("nav-files"),ft=document.getElementById("nav-settings"),wt=document.getElementById("nav-local-settings"),mt=document.getElementById("files-breadcrumbs"),bt=document.querySelector("#files-table tbody"),vt=document.getElementById("driving-page-content"),xt=document.getElementById("videoPlayer"),yt=document.getElementById("uiCanvas"),Ct=yt.getContext("2d");function St(){window.debug,document.addEventListener("click",t=>{if(t.target.matches("nav button")){const e=t.target.id.replace("nav-","");return void It(e)}if(t.target.matches(".stepper button")){const e=t.target.parentElement,i=e.querySelector(".stepper-value"),a=parseFloat(t.target.dataset.step),s=parseFloat(e.dataset.min)||-1/0,n=parseFloat(e.dataset.max)||1/0;let r=parseFloat(i.textContent)+a;String(a).includes(".")&&(r=parseFloat(r.toFixed(2))),i.textContent=Math.max(s,Math.min(n,r));const o=t.target.closest("[data-param]");return void(o&&"local"===o.dataset.storage&&Le(()=>{const t=o.dataset.param,e=Et(!0)[t];void 0!==e&&Mt(t,e)},50))}if(t.target.matches(".btn-group button")){t.target.parentElement.querySelectorAll("button").forEach(t=>t.classList.remove("active")),t.target.classList.add("active");const e=t.target.closest("[data-param]");return void(e&&"local"===e.dataset.storage&&Le(()=>{const t=e.dataset.param,i=Et(!0)[t];void 0!==i&&Mt(t,i)},50))}if(t.target.matches("#files-table a, #files-breadcrumbs a")){if(t.target.href&&t.target.href.includes("/api/play"))return;const e=t.target.dataset.path;return void(void 0!==e&&(t.preventDefault(),Bt(e)))}}),document.addEventListener("change",t=>{const e=t.target.closest("[data-param]");e&&"local"===e.dataset.storage&&Le(()=>{const t=e.dataset.param,i=Et(!0)[t];void 0!==i&&Mt(t,i)},50)}),document.addEventListener("input",t=>{const e=t.target.closest('[data-param][data-storage="local"]');e&&t.target.matches(".text-input")&&Mt(e.dataset.param,t.target.value)})}function Et(t=!0){window.debug;const e={},i=t?'[data-param][data-storage="local"]':'[data-param]:not([data-storage="local"])';return document.querySelectorAll(i).forEach(t=>{const i=t.dataset.param;t.matches('input[type="checkbox"]')?e[i]=t.checked:t.matches(".stepper")?e[i]=parseFloat(t.querySelector(".stepper-value").textContent):t.matches(".btn-group")?e[i]=t.querySelector("button.active").dataset.value:t.matches(".text-input")&&(e[i]=t.value)}),e}function Mt(t,e){window.debug;try{let i=JSON.parse(localStorage.getItem("dashySettings"))||{};i[t]=e,localStorage.setItem("dashySettings",JSON.stringify(i)),Pt(t,e)}catch(t){}}let Tt;function Lt(){const t=Q.get("ui.hudModeEnabled"),e=Q.get("ui.showVideoInHud");xt.style.display=t&&!e?"none":""}function Pt(t,e){window.debug,Q.set(`ui.${t.charAt(0).toLowerCase()+t.slice(1)}`,e)}function $t(){Q.subscribe("ui.theme",t=>{}),Q.subscribe("ui.hudModeEnabled",t=>{if(t){xt.classList.add("hud-mode");const t=document.getElementById("show-video-setting");t&&(t.style.display="")}else{xt.classList.remove("hud-mode");const t=document.getElementById("show-video-setting");t&&(t.style.display="none"),xt.style.display=""}Lt()}),Q.subscribe("ui.showVideoInHud",t=>{Lt()}),Q.subscribe("ui.navBarVisible",t=>{K.emit("nav:visibility",t)}),Q.subscribe("ui.currentPage",t=>{K.emit("page:change",t)})}function At(){window.debug;try{const t=JSON.parse(localStorage.getItem("dashySettings"))||{};for(const[e,i]of Object.entries(t)){const t=document.querySelector(`[data-param="${e}"][data-storage="local"]`);if(t)if(t.matches('input[type="checkbox"]'))t.checked=i;else if(t.matches(".stepper"))t.querySelector(".stepper-value").textContent=i;else if(t.matches(".btn-group")){t.querySelectorAll("button").forEach(t=>t.classList.remove("active"));const e=t.querySelector(`[data-value="${i}"]`);e&&e.classList.add("active")}else t.matches(".text-input")&&(t.value=i);Pt(e,i)}Q.get("ui.hudModeEnabled")?document.getElementById("show-video-setting").style.display="":document.getElementById("show-video-setting").style.display="none"}catch(t){}}function It(t){window.debug,document.querySelectorAll(".page").forEach(t=>t.classList.remove("active")),document.querySelectorAll("nav button").forEach(t=>t.classList.remove("active")),document.getElementById(`${t}-page`).classList.add("active"),document.getElementById(`nav-${t}`).classList.add("active"),"files"!==t||bt.hasChildNodes()||Bt("/"),"driving"===t?(Me.classList.remove("visible"),$e(Te)):(Me.classList.add("visible"),$e(Te))}function Dt(t){if(0===t)return"0 B";const e=Math.floor(Math.log(t)/Math.log(1024));return parseFloat((t/Math.pow(1024,e)).toFixed(1))+" "+["B","KB","MB","GB","TB"][e]}function Rt(t){if(window.debug,Nt===t)return;Nt=t;const e=1===t||"1"===t,i=2===t||"2"===t;ut&&(ut.style.display=i?"":"none"),wt&&(wt.style.display=i?"":"none"),pt&&(pt.style.display=""),ft&&(ft.style.display=e||i?"none":"");let a="files";Q.get("ui.currentPage")!==a&&It(a)}function kt(t,e){let i;return function(...a){clearTimeout(i),i=setTimeout(()=>{clearTimeout(i),t(...a)},e)}}const zt=new Map;async function Bt(t="/"){window.debug;const e=zt.get(t);e&&e.abort();const i=new AbortController;zt.set(t,i);try{bt.innerHTML='Loading...';const e=await fetch(`/api/files?path=${encodeURIComponent(t)}`,{signal:i.signal});if(!e.ok)throw new Error(`Server error: ${e.statusText}`);const a=await e.json();Ft(a.path),Gt(a.path,a.files)}catch(t){if("AbortError"===t.name)return;bt.innerHTML=`Failed to load files: ${t.message}`}finally{zt.delete(t)}}function Ft(t){mt.innerHTML="Path: "+tt.breadcrumb(t),Q.set("files.currentPath",t)}function Gt(t,e){Q.set("files.items",e);let i="";if(t){const e=t.substring(0,t.lastIndexOf("/"))||"/";i+=`⤴️.. (Parent Directory)`}e.forEach(e=>{i+=tt.fileRow(e,t)}),bt.innerHTML=i}let Vt,Ot,jt=!1,Nt=null,Ht=null,Wt=null;const qt={modelV2:null,liveCalibration:null,longitudinalPlan:null,radarState:null,selfdriveState:null,deviceState:null,carState:null,controlsState:null,roadCameraState:null,driverStateV2:null,driverMonitoringState:null,recv_frame:{},recv_time:{},updated:{},valid:{},seen:{},frame:0};let Ut=0,Xt=0,Yt=0,Jt=0,Zt=0;const Kt={sm:qt,started_frame:0,is_metric:!1,status:"DISENGAGED",engaged:!1},Qt={textContent:""},te={style:{backgroundColor:""}},ee=20,ie=50;let ae=0,se=0,ne=0,re=!1;function oe(){window.debug;const{width:t,height:e}=vt.getBoundingClientRect();t>0&&(yt.width!==t||yt.height!==e)&&(yt.width=t,yt.height=e,Wt&&Wt.invalidate_transform_cache(),!Wt&&yt.width>0&&yt.height>0&&(Wt=new U,Wt.set_callbacks(()=>{qt.selfdriveState&&(qt.selfdriveState.experimentalMode=!qt.selfdriveState.experimentalMode)}),requestAnimationFrame(Fe)))}const le=new ResizeObserver(()=>oe());function de(){window.debug,!Wt&&yt.width>0&&yt.height>0&&(Wt=new U,Wt.set_callbacks(()=>{qt.selfdriveState&&(qt.selfdriveState.experimentalMode=!qt.selfdriveState.experimentalMode)}),requestAnimationFrame(Fe))}function he(t,e){window.debug,Qt.textContent=t;const i={green:"#48bb78",yellow:"#f6e05e",red:"#f56565"};te.style.backgroundColor=i[e]||i.red,we=!0,$e(Tt),Tt=Le(()=>{Qt.textContent="",we=!0},5e3)}le.observe(vt),window.addEventListener("orientationchange",()=>oe());let ce=0,_e=[];const ge=500;function ue(){window.debug;const t=Date.now();if(t-ce0&&t-Yt>2e3&&e.push({text:"Model data stale",severity:"warning"}),Jt>0&&t-Jt>2e3&&e.push({text:"Car state stale",severity:"warning"}),Zt>0&&t-Zt>3e3&&e.push({text:"Selfdrive state stale",severity:"critical"}),_e=e,e}let pe="",fe="",we=!0,me=null,be=null,ve=null;function xe(){window.debug;const t=Qt.textContent,e=te.style.backgroundColor;t===pe&&e===fe||(we=!0,pe=t,fe=e);const i=ue();if(i.length>0&&!t){const t=i.find(t=>"critical"===t.severity)||i[0];return void he(t.text,"critical"===t.severity?"red":"yellow")}if(t){if(ve&&ve.width===yt.width&&ve.height===yt.height||(we=!0,ve={width:yt.width,height:yt.height}),we){we=!1;const i=12,a=4,s=12;Ct.font=`${s}px Arial`;const n=Ct.measureText(t).width+2*i+6+4,r=s+2*a;me&&me.width===n&&me.height===r||(me=document.createElement("canvas"),me.width=n,me.height=r,be=me.getContext("2d")),be.clearRect(0,0,n,r);const o=5;be.fillStyle="rgba(0, 0, 0, 0.7)",be.beginPath(),be.roundRect(0,0,n,r,o),be.fill();const l=3,d=i+l,h=r/2;be.fillStyle=e,be.beginPath(),be.arc(d,h,l,0,2*Math.PI),be.fill(),be.fillStyle="white",be.font=`${s}px Arial`,be.textAlign="left",be.textBaseline="middle";const c=d+l+4;be.fillText(t,c,h)}if(me){const t=15,e=yt.width/2-me.width/2,i=yt.height-me.height-t;Ct.drawImage(me,e,i)}}}function ye(t){window.debug;const e=t.split("\r\n");let i=-1;const a=[];for(let t=0;t!n.includes(t)),l=r.slice(0,3).concat(n,o).join(" ");return e[i]=l,e.join("\r\n")}const Ce=new Set,Se=new Set;let Ee,Me,Te;function Le(t,e){const i=setTimeout(()=>{t(),Ce.delete(i)},e);return Ce.add(i),i}function Pe(t,e){const i=setInterval(t,e);return Se.add(i),i}function $e(t){clearTimeout(t),Ce.delete(t)}function Ae(t){clearInterval(t),Se.delete(t)}function Ie(){window.debug,Ce.forEach(t=>clearTimeout(t)),Ce.clear(),Se.forEach(t=>clearInterval(t)),Se.clear(),clearTimeout(Ee),clearInterval(Ht),Ht=null,Vt&&(Vt.close(),Vt=null),Ot&&(Ot.close(),Ot=null),Wt=null,window.animationFrameId&&cancelAnimationFrame(window.animationFrameId)}function De(){window.debug;const t=window.location.hostname;Ie(),ht.classList.contains("active")||2===Nt&&It("driving"),ke(t),de()}async function Re(){window.debug;const t=window.location.hostname;he(`Connecting to ${t}...`,"yellow");try{const e=await fetch(`http://${t}:5088/api/init`,{method:"GET",signal:AbortSignal.timeout(5e3)});if(!e.ok)throw new Error(`Connection failed: ${e.statusText}`);{const i=await e.json();jt=i.is_metric,Kt.is_metric=jt,void 0!==i.dp_dev_dashy?(Rt(i.dp_dev_dashy),2===i.dp_dev_dashy&&ke(t)):Rt(null)}}catch(e){he(`Could not connect to device at ${t}.`,"red")}}async function ke(t){window.debug,he("Initializing WebRTC...","yellow"),clearTimeout(Ee),lastDataReceivedTime=Date.now(),Vt&&(Vt.close(),Vt=null);try{Vt=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});Be(Vt.createDataChannel("data")),Vt.ontrack=t=>{"video"===t.track.kind&&(xt.srcObject=t.streams[0],oe(),he("Video connected","green"),xt.onplaying=()=>{clearTimeout(Ee)})},Vt.onconnectionstatechange=()=>{"failed"===Vt.connectionState||"disconnected"===Vt.connectionState||"closed"===Vt.connectionState?(he("WebRTC Error: Could not connect to server (server may be down or inaccessible)","red"),"driving"===Q.get("ui.currentPage")&&(Ee=Le(()=>De(),5e3))):"connected"===Vt.connectionState&&(he("WebRTC Connected","green"),clearTimeout(Ee))},Vt.addTransceiver("video",{direction:"recvonly"});const e=await Vt.createOffer();e.sdp=ye(e.sdp),await Vt.setLocalDescription(e);const i=await fetch(`http://${t}:5001/stream`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sdp:Vt.localDescription.sdp,cameras:["road"],bridge_services_in:[],bridge_services_out:["modelV2","liveCalibration","longitudinalPlan","radarState","selfdriveState","deviceState","carState","controlsState"]})});if(!i.ok){const t=await i.text();throw new Error(`HTTP Error! Status: ${i.status}, Message: ${t}`)}const a=await i.json();await Vt.setRemoteDescription(new RTCSessionDescription(a)),ze()}catch(t){let e=`WebRTC Error: ${t.message}`;t.message.includes("Failed to fetch")&&(e="WebRTC Error: Could not connect to server (server may be down or inaccessible)"),he(e,"red"),t.message.includes("Failed to fetch")&&"driving"===Q.get("ui.currentPage")&&(Ee=setTimeout(()=>De(),5e3))}}function ze(){window.debug,Ae(Ht),lastDataReceivedTime=Date.now(),lastVideoPlaybackTime=xt.currentTime,Ht=Pe(()=>{let t=!1,e="";Date.now()-lastDataReceivedTime>5e3&&(t=!0,e="Data stream stalled"),t||xt.paused||xt.currentTime!==lastVideoPlaybackTime||(t=!0,e="Video stream stalled"),t&&(he(`${e}. Reconnecting...`,"yellow"),De()),lastVideoPlaybackTime=xt.currentTime},2e3)}function Be(t){window.debug;const e=new TextDecoder("utf-8");let i="";function a(t){try{const e=JSON.parse(t.replace(/\bNaN\b/g,"null"));lastDataReceivedTime=Date.now();const i=Date.now();e.data&&void 0!==e.data.dp_dev_dashy&&Rt(e.data.dp_dev_dashy);const a=e.type;qt[a]=e.data,qt.recv_frame[a]=qt.frame,qt.recv_time[a]=i/1e3,qt.updated[a]=!0,qt.valid[a]=!0,qt.seen[a]=!0,"selfdriveState"===a?(Zt=i,0===Ut&&(Ut=i,Xt=qt.frame)):"modelV2"===a?Yt=i:"carState"===a&&(Jt=i),qt.frame++}catch(t){}}t.onmessage=t=>{const s="string"==typeof t.data?t.data:e.decode(t.data,{stream:!0});let n;for(i+=s;-1!==(n=i.indexOf("}{"));){a(i.substring(0,n+1)),i=i.substring(n+1)}i.length>0&&(a(i),i="")}}function Fe(t){window.animationFrameId=requestAnimationFrame(Fe);const e=t-ae;if(!(et.classList.remove("active")),document.querySelectorAll("nav button").forEach(t=>t.classList.remove("active")),document.getElementById(`${t}-page`).classList.add("active"),document.getElementById(`nav-${t}`).classList.add("active"),"files"!==t||bt.hasChildNodes()||Bt("/"),"driving"===e&&"driving"!==t&&Ie(),"driving"===t&&"driving"!==e&&De(),"driving"===t?(Me.classList.remove("visible"),Q.set("ui.navBarVisible",!1),vt.addEventListener("click",Ge)):(Me.classList.add("visible"),Q.set("ui.navBarVisible",!0),vt.removeEventListener("click",Ge),clearTimeout(Te))}function Ge(){Me||(Me=document.querySelector("nav")),Me.classList.toggle("visible"),Me.classList.contains("visible")?($e(Te),Te=Le(()=>{Me.classList.remove("visible")},3e3)):$e(Te)}async function Ve(){window.debug;document.getElementById("settings-content");const t=document.getElementById("local-settings-content");lt(Z,t),Me=document.querySelector("nav"),ut&&(ut.style.display="none"),wt&&(wt.style.display="none"),St();document.getElementById("driving-page-content").addEventListener("click",t=>{ht.classList.contains("active")&&Ge()}),xt.addEventListener("click",t=>{ht.classList.contains("active")&&Ge()}),yt.addEventListener("click",t=>{ht.classList.contains("active")&&Ge()}),$t(),At(),await Re(),It("files"),de(),xt.onstalled=()=>{"driving"===Q.get("ui.currentPage")&&De()},xt.onplaying=()=>{clearTimeout(Ee)}}window.addEventListener("beforeunload",Ie),window.addEventListener("unload",Ie),Ve(); diff --git a/dragonpilot/dashy/web/dist/lib/hls.js b/dragonpilot/dashy/web/dist/lib/hls.js new file mode 100644 index 000000000..2fd899f21 --- /dev/null +++ b/dragonpilot/dashy/web/dist/lib/hls.js @@ -0,0 +1,2 @@ +!function e(t){var r,i;r=this,i=function(){"use strict";function r(e,t){for(var r=0;r=this.minWeight_},t.getEstimate=function(){return this.canEstimate()?Math.min(this.fast_.getEstimate(),this.slow_.getEstimate()):this.defaultEstimate_},t.getEstimateTTFB=function(){return this.ttfb_.getTotalWeight()>=this.minWeight_?this.ttfb_.getEstimate():this.defaultTTFB_},t.destroy=function(){},i(e,[{key:"defaultEstimate",get:function(){return this.defaultEstimate_}}])}(),N=function(e,t){this.trace=void 0,this.debug=void 0,this.log=void 0,this.warn=void 0,this.info=void 0,this.error=void 0;var r="["+e+"]:";this.trace=U,this.debug=t.debug.bind(null,r),this.log=t.log.bind(null,r),this.warn=t.warn.bind(null,r),this.info=t.info.bind(null,r),this.error=t.error.bind(null,r)},U=function(){},B={trace:U,debug:U,log:U,warn:U,info:U,error:U};function G(){return a({},B)}function K(e,t,r){return t[e]?t[e].bind(t):function(e,t){var r=self.console[e];return r?r.bind(self.console,(t?"["+t+"] ":"")+"["+e+"] >"):U}(e,r)}var V=G();function H(e,t,r){var i=G();if("object"==typeof console&&!0===e||"object"==typeof e){var n=["debug","log","info","warn","error"];n.forEach((function(t){i[t]=K(t,e,r)}));try{i.log('Debug logs enabled for "'+t+'" in hls.js version 1.6.6')}catch(e){return G()}n.forEach((function(t){V[t]=K(t,e)}))}else a(V,i);return i}var Y=V;function W(e){if(void 0===e&&(e=!0),"undefined"!=typeof self)return(e||!self.MediaSource)&&self.ManagedMediaSource||self.MediaSource||self.WebKitMediaSource}function j(e,t){var r=Object.keys(e),i=Object.keys(t),n=r.length,a=i.length;return!n||!a||n===a&&!r.some((function(e){return-1===i.indexOf(e)}))}function q(e,t){if(void 0===t&&(t=!1),"undefined"!=typeof TextDecoder){var r=new TextDecoder("utf-8").decode(e);if(t){var i=r.indexOf("\0");return-1!==i?r.substring(0,i):r}return r.replace(/\0/g,"")}for(var n,a,s,o=e.length,l="",u=0;u>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:l+=String.fromCharCode(n);break;case 12:case 13:a=e[u++],l+=String.fromCharCode((31&n)<<6|63&a);break;case 14:a=e[u++],s=e[u++],l+=String.fromCharCode((15&n)<<12|(63&a)<<6|(63&s)<<0)}}return l}var X={hexDump:function(e){for(var t="",r=0;r1||1===r&&this.levelkeys[t[0]].encrypted)return!0}return!1}},{key:"programDateTime",get:function(){return null===this._programDateTime&&this.rawProgramDateTime&&(this.programDateTime=Date.parse(this.rawProgramDateTime)),this._programDateTime},set:function(e){A(e)?this._programDateTime=e:this._programDateTime=this.rawProgramDateTime=null}},{key:"ref",get:function(){return ee(this)?(this._ref||(this._ref={base:this.base,start:this.start,duration:this.duration,sn:this.sn,programDateTime:this.programDateTime}),this._ref):null}}])}(Z),re=function(e){function t(t,r,i,n,a){var s;(s=e.call(this,i)||this).fragOffset=0,s.duration=0,s.gap=!1,s.independent=!1,s.relurl=void 0,s.fragment=void 0,s.index=void 0,s.duration=t.decimalFloatingPoint("DURATION"),s.gap=t.bool("GAP"),s.independent=t.bool("INDEPENDENT"),s.relurl=t.enumeratedString("URI"),s.fragment=r,s.index=n;var o=t.enumeratedString("BYTERANGE");return o&&s.setByteRange(o,a),a&&(s.fragOffset=a.fragOffset+a.duration),s}return o(t,e),i(t,[{key:"start",get:function(){return this.fragment.start+this.fragOffset}},{key:"end",get:function(){return this.start+this.duration}},{key:"loaded",get:function(){var e=this.elementaryStreams;return!!(e.audio||e.video||e.audiovideo)}}])}(Z);function ie(e,t){var r=Object.getPrototypeOf(e);if(r){var i=Object.getOwnPropertyDescriptor(r,t);return i||ie(r,t)}}var ne=Math.pow(2,32)-1,ae=[].push,se={video:1,audio:2,id3:3,text:4};function oe(e){return String.fromCharCode.apply(null,e)}function le(e,t){var r=e[t]<<8|e[t+1];return r<0?65536+r:r}function ue(e,t){var r=he(e,t);return r<0?4294967296+r:r}function de(e,t){var r=ue(e,t);return r*=Math.pow(2,32),r+=ue(e,t+4)}function he(e,t){return e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3]}function fe(e,t){var r=[];if(!t.length)return r;for(var i=e.byteLength,n=0;n1?n+a:i;if(oe(e.subarray(n+4,n+8))===t[0])if(1===t.length)r.push(e.subarray(n+8,s));else{var o=fe(e.subarray(n+8,s),t.slice(1));o.length&&ae.apply(r,o)}n=s}return r}function ce(e){var t=[],r=e[0],i=8,n=ue(e,i);i+=4;var a=0,s=0;0===r?(a=ue(e,i),s=ue(e,i+4),i+=8):(a=de(e,i),s=de(e,i+8),i+=16),i+=2;var o=e.length+s,l=le(e,i);i+=2;for(var u=0;u>>31)return Y.warn("SIDX has hierarchical references (not supported)"),null;var c=ue(e,d);d+=4,t.push({referenceSize:f,subsegmentDuration:c,info:{duration:c/n,start:o,end:o+f-1}}),o+=f,i=d+=4}return{earliestPresentationTime:a,timescale:n,version:r,referencesCount:l,references:t}}function ge(e){for(var t=[],r=fe(e,["moov","trak"]),i=0;i3&&(a+="."+ye(u[1])+ye(u[2])+ye(u[3]),t=me("avc1"===l?"dva1":"dvav",i));break;case"mp4a":var d=fe(r,[n])[0],h=fe(d.subarray(28),["esds"])[0];if(h&&h.length>7){var f=4;if(3!==h[f++])break;f=pe(h,f),f+=2;var c=h[f++];if(128&c&&(f+=2),64&c&&(f+=h[f++]),4!==h[f++])break;f=pe(h,f);var g=h[f++];if(64!==g)break;if(a+="."+ye(g),f+=12,5!==h[f++])break;f=pe(h,f);var v=h[f++],m=(248&v)>>3;31===m&&(m+=1+((7&v)<<3)+((224&h[f])>>5)),a+="."+m}break;case"hvc1":case"hev1":var p=fe(i,["hvcC"])[0];if(p&&p.length>12){var y=p[1],E=["","A","B","C"][y>>6],T=31&y,S=ue(p,2),A=(32&y)>>5?"H":"L",L=p[12],R=p.subarray(6,12);a+="."+E+T,a+="."+function(e){for(var t=0,r=0;r<32;r++)t|=(e>>r&1)<<31-r;return t>>>0}(S).toString(16).toUpperCase(),a+="."+A+L;for(var I="",k=R.length;k--;){var b=R[k];(b||I)&&(I="."+b.toString(16).toUpperCase()+I)}a+=I}t=me("hev1"==l?"dvhe":"dvh1",i);break;case"dvh1":case"dvhe":case"dvav":case"dva1":case"dav1":a=me(a,i)||a;break;case"vp09":var D=fe(i,["vpcC"])[0];if(D&&D.length>6){var _=D[4],P=D[5],C=D[6]>>4&15;a+="."+Ee(_)+"."+Ee(P)+"."+Ee(C)}break;case"av01":var w=fe(i,["av1C"])[0];if(w&&w.length>2){var O=w[1]>>>5,x=31&w[1],M=w[2]>>>7?"H":"M",F=(64&w[2])>>6,N=(32&w[2])>>5,U=2===O&&F?N?12:10:F?10:8,B=(16&w[2])>>4,G=(8&w[2])>>3,K=(4&w[2])>>2,V=3&w[2];a+="."+O+"."+Ee(x)+M+"."+Ee(U)+"."+B+"."+G+K+V+"."+Ee(1)+"."+Ee(1)+"."+Ee(1)+".0",t=me("dav1",i)}}return{codec:a,encrypted:s,supplemental:t}}function me(e,t){var r=fe(t,["dvvC"]),i=r.length?r[0]:fe(t,["dvcC"])[0];if(i){var n=i[2]>>1&127,a=i[2]<<5&32|i[3]>>3&31;return e+"."+Ee(n)+"."+Ee(a)}}function pe(e,t){for(var r=t+5;128&e[t++]&&t>1&63;return 39===r||40===r}return 6==(31&t)}function Ie(e,t,r,i){var n=ke(e),a=0;a+=t;for(var s=0,o=0,l=0;a=n.length)break;s+=l=n[a++]}while(255===l);o=0;do{if(a>=n.length)break;o+=l=n[a++]}while(255===l);var u=n.length-a,d=a;if(ou){Y.error("Malformed SEI payload. "+o+" is too small, only "+u+" bytes left to parse.");break}if(4===s){if(181===n[d++]){var h=le(n,d);if(d+=2,49===h){var f=ue(n,d);if(d+=4,1195456820===f){var c=n[d++];if(3===c){var g=n[d++],v=64&g,m=v?2+3*(31&g):0,p=new Uint8Array(m);if(v){p[0]=g;for(var y=1;y16){for(var E=[],T=0;T<16;T++){var S=n[d++].toString(16);E.push(1==S.length?"0"+S:S),3!==T&&5!==T&&7!==T&&9!==T||E.push("-")}for(var A=o-16,L=new Uint8Array(A),R=0;R0&&new DataView(a.buffer).setUint32(0,r.byteLength,!1),function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),i=1;i>24&255,o[1]=a>>16&255,o[2]=a>>8&255,o[3]=255&a,o.set(e,4),s=0,a=8;s>>24;if(0!==n&&1!==n)return{offset:r,size:t};var a=e.buffer,s=X.hexDump(new Uint8Array(a,r+12,16)),o=null,l=0;if(0===n)l=28;else if(1===n){var u=e.getUint32(28);if(!u||i<32+16*u)return{offset:r,size:t};o=[];for(var d=0;d4||-1!==["ac-3","ec-3","alac","fLaC","Opus"].indexOf(e))&&(Ke(e,"audio")||Ke(e,"video")))return e;if(t){var r=t.split(",");if(r.length>1){if(e)for(var i=r.length;i--;)if(r[i].substring(0,4)===e.substring(0,4))return r[i];return r[0]}}return t||e}function Ke(e,t){return Ce(e,t)&&Oe(e,t)}function Ve(e){if(e.startsWith("av01.")){for(var t=e.split("."),r=["0","111","01","01","01","0"],i=t.length;i>4&&i<10;i++)t[i]=r[i-4];return t.join(".")}return e}function He(e){var t=W(e)||{isTypeSupported:function(){return!1}};return{mpeg:t.isTypeSupported("audio/mpeg"),mp3:t.isTypeSupported('audio/mp4; codecs="mp3"'),ac3:t.isTypeSupported('audio/mp4; codecs="ac-3"')}}function Ye(e){return e.replace(/^.+codecs=["']?([^"']+).*$/,"$1")}var We={supported:!0,configurations:[],decodingInfoResults:[{supported:!0,powerEfficient:!0,smooth:!0}]};function je(e,t){return{supported:!1,configurations:t,decodingInfoResults:[{supported:!1,smooth:!1,powerEfficient:!1}],error:e}}function qe(e,t,r,i){void 0===i&&(i={});var n=e.videoCodec;if(!n&&!e.audioCodec||!r)return Promise.resolve(We);for(var a=[],s=function(e){var t,r=null==(t=e.videoCodec)?void 0:t.split(","),i=Qe(e),n=e.width||640,a=e.height||480,s=e.frameRate||30,o=e.videoRange.toLowerCase();return r?r.map((function(e){var t={contentType:xe(Ve(e),"video"),width:n,height:a,bitrate:i,framerate:s};return"sdr"!==o&&(t.transferFunction=o),t})):[]}(e),o=s.length,l=function(e,t,r){var i,n=null==(i=e.audioCodec)?void 0:i.split(","),a=Qe(e);return n&&e.audioGroups?e.audioGroups.reduce((function(e,i){var s,o=i?null==(s=t.groups[i])?void 0:s.tracks:null;return o?o.reduce((function(e,t){if(t.groupId===i){var s=parseFloat(t.channels||"");n.forEach((function(t){var i={contentType:xe(t,"audio"),bitrate:r?Xe(t,a):a};s&&(i.channels=""+s),e.push(i)}))}return e}),e):e}),[]):[]}(e,t,o>0),u=l.length,d=o||1*u||1;d--;){var h={type:"media-source"};if(o&&(h.video=s[d%o]),u){h.audio=l[d%u];var f=h.audio.bitrate;h.video&&f&&(h.video.bitrate-=f)}a.push(h)}if(n){var c=navigator.userAgent;if(n.split(",").some((function(e){return Le(e)}))&&_e())return Promise.resolve(je(new Error("Overriding Windows Firefox HEVC MediaCapabilities result based on user-agent string: ("+c+")"),a))}return Promise.all(a.map((function(e){var t,n,a,s,o=(n="",a=(t=e).audio,(s=t.video)&&(n+=Ye(s.contentType)+"_r"+s.height+"x"+s.width+"f"+Math.ceil(s.framerate)+(s.transferFunction||"sd")+"_"+Math.ceil(s.bitrate/1e5)),a&&(n+=(s?"_":"")+Ye(a.contentType)+"_c"+a.channels),n);return i[o]||(i[o]=r.decodingInfo(e))}))).then((function(e){return{supported:!e.some((function(e){return!e.supported})),configurations:a,decodingInfoResults:e}})).catch((function(e){return{supported:!1,configurations:a,decodingInfoResults:[],error:e}}))}function Xe(e,t){if(t<=1)return 1;var r=128e3;return"ec-3"===e?r=768e3:"ac-3"===e&&(r=64e4),Math.min(t/2,r)}function Qe(e){return 1e3*Math.ceil(Math.max(.9*e.bitrate,e.averageBitrate)/1e3)||1}var ze=["NONE","TYPE-0","TYPE-1",null],$e=["SDR","PQ","HLG"],Je="",Ze="YES",et="v2";function tt(e){var t=e.canSkipUntil,r=e.canSkipDateRanges,i=e.age;return t&&i-1;i--)if(r(e[i]))return i;for(var n=t+1;n-1&&v!==g,p=!!e||m;if(p||!l.paused&&l.playbackRate&&l.readyState){var y=s.mainForwardBufferInfo;if(p||null!==y){var E=r.bwEstimator.getEstimateTTFB(),T=Math.abs(l.playbackRate);if(!(f<=Math.max(E,h/(2*T)*1e3))){var S=y?y.len/T:0,L=d.loading.first?d.loading.first-d.loading.start:-1,R=d.loaded&&L>-1,I=r.getBwEstimate(),k=s.levels,D=k[g],_=Math.max(d.loaded,Math.round(h*(n.bitrate||D.averageBitrate)/8)),P=R?f-L:f;P<1&&R&&(P=Math.min(f,8*d.loaded/I));var C=R?1e3*d.loaded/P:0,w=E/1e3,O=C?(_-d.loaded)/C:8*_/I+w;if(!(O<=S)){var x,M=C?8*C:I,F=!0===(null==(t=(null==e?void 0:e.details)||r.hls.latestLevelDetails)?void 0:t.live),N=r.hls.config.abrBandWidthUpFactor,U=Number.POSITIVE_INFINITY;for(x=g-1;x>c;x--){var B=k[x].maxBitrate,G=!k[x].details||F;if((U=r.getTimeToLoadFrag(w,M,h*B,G))=O||U>10*h)){R?r.bwEstimator.sample(f-Math.min(E,L),d.loaded):r.bwEstimator.sampleTTFB(f);var K=k[x].maxBitrate;r.getBwEstimate()*N>K&&r.resetEstimator(K);var V=r.findBestLevel(K,c,x,0,S,1,1);V>-1&&(x=V),r.warn("Fragment "+n.sn+(a?" part "+a.index:"")+" of level "+g+" is loading too slowly;\n Fragment duration: "+n.duration.toFixed(3)+"\n Time to underbuffer: "+S.toFixed(3)+" s\n Estimated load time for current fragment: "+O.toFixed(3)+" s\n Estimated load time for down switch fragment: "+U.toFixed(3)+" s\n TTFB estimate: "+(0|L)+" ms\n Current BW estimate: "+(A(I)?0|I:"Unknown")+" bps\n New BW estimate: "+(0|r.getBwEstimate())+" bps\n Switching to level "+x+" @ "+(0|K)+" bps"),s.nextLoadLevel=s.nextAutoLevel=x,r.clearTimer();var H=function(){if(r.clearTimer(),r.fragCurrent===n&&r.hls.loadLevel===x&&x>0){var e=r.getStarvationDelay();if(r.warn("Aborting inflight request "+(x>0?"and switching down":"")+"\n Fragment duration: "+n.duration.toFixed(3)+" s\n Time to underbuffer: "+e.toFixed(3)+" s"),n.abortRequests(),r.fragCurrent=r.partCurrent=null,x>c){var t=r.findBestLevel(r.hls.levels[c].bitrate,c,x,0,e,1,1);-1===t&&(t=c),r.hls.nextLoadLevel=r.hls.nextAutoLevel=t,r.resetEstimator(r.hls.levels[t].bitrate)}}};m||O>2*U?H():r.timer=self.setInterval(H,1e3*U),s.trigger(b.FRAG_LOAD_EMERGENCY_ABORTED,{frag:n,part:a,stats:d})}}}}}}}},r.hls=t,r.bwEstimator=r.initEstimator(),r.registerListeners(),r}o(t,e);var r=t.prototype;return r.resetEstimator=function(e){e&&(this.log("setting initial bwe to "+e),this.hls.config.abrEwmaDefaultEstimate=e),this.firstSelection=-1,this.bwEstimator=this.initEstimator()},r.initEstimator=function(){var e=this.hls.config;return new F(e.abrEwmaSlowVoD,e.abrEwmaFastVoD,e.abrEwmaDefaultEstimate)},r.registerListeners=function(){var e=this.hls;e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.FRAG_LOADING,this.onFragLoading,this),e.on(b.FRAG_LOADED,this.onFragLoaded,this),e.on(b.FRAG_BUFFERED,this.onFragBuffered,this),e.on(b.LEVEL_SWITCHING,this.onLevelSwitching,this),e.on(b.LEVEL_LOADED,this.onLevelLoaded,this),e.on(b.LEVELS_UPDATED,this.onLevelsUpdated,this),e.on(b.MAX_AUTO_LEVEL_UPDATED,this.onMaxAutoLevelUpdated,this),e.on(b.ERROR,this.onError,this)},r.unregisterListeners=function(){var e=this.hls;e&&(e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.FRAG_LOADING,this.onFragLoading,this),e.off(b.FRAG_LOADED,this.onFragLoaded,this),e.off(b.FRAG_BUFFERED,this.onFragBuffered,this),e.off(b.LEVEL_SWITCHING,this.onLevelSwitching,this),e.off(b.LEVEL_LOADED,this.onLevelLoaded,this),e.off(b.LEVELS_UPDATED,this.onLevelsUpdated,this),e.off(b.MAX_AUTO_LEVEL_UPDATED,this.onMaxAutoLevelUpdated,this),e.off(b.ERROR,this.onError,this))},r.destroy=function(){this.unregisterListeners(),this.clearTimer(),this.hls=this._abandonRulesCheck=this.supportedCache=null,this.fragCurrent=this.partCurrent=null},r.onManifestLoading=function(e,t){this.lastLoadedFragLevel=-1,this.firstSelection=-1,this.lastLevelLoadSec=0,this.supportedCache={},this.fragCurrent=this.partCurrent=null,this.onLevelsUpdated(),this.clearTimer()},r.onLevelsUpdated=function(){this.lastLoadedFragLevel>-1&&this.fragCurrent&&(this.lastLoadedFragLevel=this.fragCurrent.level),this._nextAutoLevel=-1,this.onMaxAutoLevelUpdated(),this.codecTiers=null,this.audioTracksByGroup=null},r.onMaxAutoLevelUpdated=function(){this.firstSelection=-1,this.nextAutoLevelKey=""},r.onFragLoading=function(e,t){var r,i=t.frag;this.ignoreFragment(i)||(i.bitrateTest||(this.fragCurrent=i,this.partCurrent=null!=(r=t.part)?r:null),this.clearTimer(),this.timer=self.setInterval(this._abandonRulesCheck,100))},r.onLevelSwitching=function(e,t){this.clearTimer()},r.onError=function(e,t){if(!t.fatal)switch(t.details){case k.BUFFER_ADD_CODEC_ERROR:case k.BUFFER_APPEND_ERROR:this.lastLoadedFragLevel=-1,this.firstSelection=-1;break;case k.FRAG_LOAD_TIMEOUT:var r=t.frag,i=this.fragCurrent,n=this.partCurrent;if(r&&i&&r.sn===i.sn&&r.level===i.level){var a=performance.now(),s=n?n.stats:r.stats,o=a-s.loading.start,l=s.loading.first?s.loading.first-s.loading.start:-1;if(s.loaded&&l>-1){var u=this.bwEstimator.getEstimateTTFB();this.bwEstimator.sample(o-Math.min(u,l),s.loaded)}else this.bwEstimator.sampleTTFB(o)}}},r.getTimeToLoadFrag=function(e,t,r,i){return e+r/t+(i?e+this.lastLevelLoadSec:0)},r.onLevelLoaded=function(e,t){var r=this.hls.config,i=t.stats.loading,n=i.end-i.first;A(n)&&(this.lastLevelLoadSec=n/1e3),t.details.live?this.bwEstimator.update(r.abrEwmaSlowLive,r.abrEwmaFastLive):this.bwEstimator.update(r.abrEwmaSlowVoD,r.abrEwmaFastVoD),this.timer>-1&&this._abandonRulesCheck(t.levelInfo)},r.onFragLoaded=function(e,t){var r=t.frag,i=t.part,n=i?i.stats:r.stats;if(r.type===w&&this.bwEstimator.sampleTTFB(n.loading.first-n.loading.start),!this.ignoreFragment(r)){if(this.clearTimer(),r.level===this._nextAutoLevel&&(this._nextAutoLevel=-1),this.firstSelection=-1,this.hls.config.abrMaxWithRealBitrate){var a=i?i.duration:r.duration,s=this.hls.levels[r.level],o=(s.loaded?s.loaded.bytes:0)+n.loaded,l=(s.loaded?s.loaded.duration:0)+a;s.loaded={bytes:o,duration:l},s.realBitrate=Math.round(8*o/l)}if(r.bitrateTest){var u={stats:n,frag:r,part:i,id:r.type};this.onFragBuffered(b.FRAG_BUFFERED,u),r.bitrateTest=!1}else this.lastLoadedFragLevel=r.level}},r.onFragBuffered=function(e,t){var r=t.frag,i=t.part,n=null!=i&&i.stats.loaded?i.stats:r.stats;if(!n.aborted&&!this.ignoreFragment(r)){var a=n.parsing.end-n.loading.start-Math.min(n.loading.first-n.loading.start,this.bwEstimator.getEstimateTTFB());this.bwEstimator.sample(a,n.loaded),n.bwEstimate=this.getBwEstimate(),r.bitrateTest?this.bitrateTestDelay=a/1e3:this.bitrateTestDelay=0}},r.ignoreFragment=function(e){return e.type!==w||"initSegment"===e.sn},r.clearTimer=function(){this.timer>-1&&(self.clearInterval(this.timer),this.timer=-1)},r.getAutoLevelKey=function(){return this.getBwEstimate()+"_"+this.getStarvationDelay().toFixed(2)},r.getNextABRAutoLevel=function(){var e=this.fragCurrent,t=this.partCurrent,r=this.hls;if(r.levels.length<=1)return r.loadLevel;var i=r.maxAutoLevel,n=r.config,a=r.minAutoLevel,s=t?t.duration:e?e.duration:0,o=this.getBwEstimate(),l=this.getStarvationDelay(),u=n.abrBandWidthFactor,d=n.abrBandWidthUpFactor;if(l){var h=this.findBestLevel(o,a,i,l,0,u,d);if(h>=0)return this.rebufferNotice=-1,h}var f=s?Math.min(s,n.maxStarvationDelay):n.maxStarvationDelay;if(!l){var c=this.bitrateTestDelay;c&&(f=(s?Math.min(s,n.maxLoadingDelay):n.maxLoadingDelay)-c,this.info("bitrate test took "+Math.round(1e3*c)+"ms, set first fragment max fetchDuration to "+Math.round(1e3*f)+" ms"),u=d=1)}var g=this.findBestLevel(o,a,i,l,f,u,d);if(this.rebufferNotice!==g&&(this.rebufferNotice=g,this.info((l?"rebuffering expected":"buffer is empty")+", optimal quality level "+g)),g>-1)return g;var v=r.levels[a],m=r.loadLevelObj;return m&&(null==v?void 0:v.bitrate)0),f=Math.min(f,t.minHeight),c=Math.min(c,t.minFramerate),g=Math.min(g,t.minBitrate),T.filter((function(e){return t.videoRanges[e]>0})).length>0&&(h=!0)},L=a.length;L--;)S();f=A(f)?f:0,c=A(c)?c:0;var R=Math.max(1080,f),I=Math.max(30,c);g=A(g)?g:r,r=Math.max(g,r),h||(t=void 0);var k=a.length>1;return{codecSet:a.reduce((function(t,i){var n=e[i];if(i===t)return t;if(p=h?T.filter((function(e){return n.videoRanges[e]>0})):[],k){if(n.minBitrate>r)return ot(i,"min bitrate of "+n.minBitrate+" > current estimate of "+r),t;if(!n.hasDefaultAudio)return ot(i,"no renditions with default or auto-select sound found"),t;if(o&&i.indexOf(o.substring(0,4))%5!=0)return ot(i,'audio codec preference "'+o+'" not found'),t;if(s&&!u){if(!n.channels[s])return ot(i,"no renditions with "+s+" channel sound found (channels options: "+Object.keys(n.channels)+")"),t}else if((!o||u)&&d&&0===n.channels[2])return ot(i,"no renditions with stereo sound found"),t;if(n.minHeight>R)return ot(i,"min resolution of "+n.minHeight+" > maximum of "+R),t;if(n.minFramerate>I)return ot(i,"min framerate of "+n.minFramerate+" > maximum of "+I),t;if(!p.some((function(e){return n.videoRanges[e]>0})))return ot(i,"no variants with VIDEO-RANGE of "+st(p)+" found"),t;if(l&&i.indexOf(l.substring(0,4))%5!=0)return ot(i,'video codec preference "'+l+'" not found'),t;if(n.maxScore=Fe(t)||n.fragmentError>e[t].fragmentError)?t:(v=n.minIndex,m=n.maxScore,i)}),void 0),videoRanges:p,preferHDR:E,minFramerate:c,minBitrate:g,minIndex:v}}(P,R,e,k,b),w=C.codecSet,O=C.videoRanges,x=C.minFramerate,M=C.minBitrate,F=C.minIndex,N=C.preferHDR;_=F,E=w,R=N?O[O.length-1]:O[0],I=x,e=Math.max(e,M),this.log("picked start tier "+st(C))}else E=null==T?void 0:T.codecSet,R=null==T?void 0:T.videoRange;for(var U,B=c?c.duration:f?f.duration:0,G=this.bwEstimator.getEstimateTTFB()/1e3,K=[],V=function(){var t,o,f=v[H],g=H>h;if(!f)return 0;if(y.useMediaCapabilities&&!f.supportedResult&&!f.supportedPromise){var m=navigator.mediaCapabilities;"function"==typeof(null==m?void 0:m.decodingInfo)&&function(e,t,r,i,n,a){var s=e.videoCodec,o=e.audioCodec?e.audioGroups:null,l=null==a?void 0:a.audioCodec,u=null==a?void 0:a.channels,d=u?parseInt(u):l?1/0:2,h=null;if(null!=o&&o.length)try{h=1===o.length&&o[0]?t.groups[o[0]].channels:o.reduce((function(e,r){if(r){var i=t.groups[r];if(!i)throw new Error("Audio track group "+r+" not found");Object.keys(i.channels).forEach((function(t){e[t]=(e[t]||0)+i.channels[t]}))}return e}),{2:0})}catch(e){return!0}return void 0!==s&&(s.split(",").some((function(e){return Le(e)}))||e.width>1920&&e.height>1088||e.height>1920&&e.width>1088||e.frameRate>Math.max(i,30)||"SDR"!==e.videoRange&&e.videoRange!==r||e.bitrate>Math.max(n,8e6))||!!h&&A(d)&&Object.keys(h).some((function(e){return parseInt(e)>d}))}(f,D,R,I,e,k)?(f.supportedPromise=qe(f,D,m,l.supportedCache),f.supportedPromise.then((function(e){if(l.hls){f.supportedResult=e;var t=l.hls.levels,r=t.indexOf(f);e.error?l.warn('MediaCapabilities decodingInfo error: "'+e.error+'" for level '+r+" "+st(e)):e.supported?e.decodingInfoResults.some((function(e){return!1===e.smooth||!1===e.powerEfficient}))&&l.log("MediaCapabilities decodingInfo for level "+r+" not smooth or powerEfficient: "+st(e)):(l.warn("Unsupported MediaCapabilities decodingInfo result for level "+r+" "+st(e)),r>-1&&t.length>1&&(l.log("Removing unsupported level "+r),l.hls.removeLevel(r),-1===l.hls.loadLevel&&(l.hls.nextLoadLevel=0)))}}))):f.supportedResult=We}if((E&&f.codecSet!==E||R&&f.videoRange!==R||g&&I>f.frameRate||!g&&I>0&&I=2*B&&0===n?f.averageBitrate:f.maxBitrate,w=l.getTimeToLoadFrag(G,T,C*P,void 0===b);if(T>=C&&(H===d||0===f.loadError&&0===f.fragmentError)&&(w<=G||!A(w)||S&&!l.bitrateTestDelay||w"+H+" adjustedbw("+Math.round(T)+")-bitrate="+Math.round(T-C)+" ttfb:"+G.toFixed(1)+" avgDuration:"+P.toFixed(1)+" maxFetchDuration:"+u.toFixed(1)+" fetchDuration:"+w.toFixed(1)+" firstSelection:"+L+" codecSet:"+f.codecSet+" videoRange:"+f.videoRange+" hls.loadLevel:"+p)),L&&(l.firstSelection=H),{v:H}}},H=r;H>=t;H--)if(0!==(U=V())&&U)return U.v;return-1},r.deriveNextAutoLevel=function(e){var t=this.hls,r=t.maxAutoLevel,i=t.minAutoLevel;return Math.min(Math.max(e,i),r)},i(t,[{key:"firstAutoLevel",get:function(){var e=this.hls,t=e.maxAutoLevel,r=e.minAutoLevel,i=this.getBwEstimate(),n=this.hls.config.maxStarvationDelay,a=this.findBestLevel(i,r,t,0,n,1,1);if(a>-1)return a;var s=this.hls.firstLevel,o=Math.min(Math.max(s,r),t);return this.warn("Could not find best starting auto level. Defaulting to first in playlist "+s+" clamped to "+o),o}},{key:"forcedAutoLevel",get:function(){return this.nextAutoLevelKey?-1:this._nextAutoLevel}},{key:"nextAutoLevel",get:function(){var e=this.forcedAutoLevel,t=this.bwEstimator.canEstimate(),r=this.lastLoadedFragLevel>-1;if(!(-1===e||t&&r&&this.nextAutoLevelKey!==this.getAutoLevelKey()))return e;var i=t&&r?this.getNextABRAutoLevel():this.firstAutoLevel;if(-1!==e){var n=this.hls.levels;if(n.length>Math.max(e,i)&&n[e].loadError<=n[i].loadError)return e}return this._nextAutoLevel=i,this.nextAutoLevelKey=this.getAutoLevelKey(),i},set:function(e){var t=this.deriveNextAutoLevel(e);this._nextAutoLevel!==t&&(this.nextAutoLevelKey="",this._nextAutoLevel=t)}}])}(N),mt=function(e,t){for(var r=0,i=e.length-1,n=null,a=null;r<=i;){var s=t(a=e[n=(r+i)/2|0]);if(s>0)r=n+1;else{if(!(s<0))return a;i=n-1}}return null};function pt(e,t,r,i,n){void 0===r&&(r=0),void 0===i&&(i=0),void 0===n&&(n=.005);var a=null;if(e){a=t[1+e.sn-t[0].sn]||null;var s=e.endDTS-r;s>0&&s<15e-7&&(r+=15e-7),a&&e.level!==a.level&&a.end<=e.end&&(a=t[2+e.sn-t[0].sn]||null)}else 0===r&&0===t[0].start&&(a=t[0]);if(a&&((!e||e.level===a.level)&&0===yt(r,i,a)||function(e,t,r){if(t&&0===t.start&&t.level0){var i=t.tagList.reduce((function(e,t){return"INF"===t[0]&&(e+=parseFloat(t[1])),e}),r);return e.start<=i}return!1}(a,e,Math.min(n,i))))return a;var o=mt(t,yt.bind(null,r,i));return!o||o===e&&a?a:o}function yt(e,t,r){if(void 0===e&&(e=0),void 0===t&&(t=0),r.start<=e&&r.start+r.duration>e)return 0;var i=Math.min(t,r.duration+(r.deltaPTS?r.deltaPTS:0));return r.start+r.duration-i<=e?1:r.start-i>e&&r.start?-1:0}function Et(e,t,r){var i=1e3*Math.min(t,r.duration+(r.deltaPTS?r.deltaPTS:0));return(r.endProgramDateTime||0)-i>e}function Tt(e,t,r){if(e&&e.startCC<=t&&e.endCC>=t){var i,n=e.fragments,a=e.fragmentHint;return a&&(n=n.concat(a)),mt(n,(function(e){return e.cct?-1:(i=e,e.end<=r?1:e.start>r?-1:0)})),i||null}return null}function St(e){switch(e.details){case k.FRAG_LOAD_TIMEOUT:case k.KEY_LOAD_TIMEOUT:case k.LEVEL_LOAD_TIMEOUT:case k.MANIFEST_LOAD_TIMEOUT:return!0}return!1}function At(e,t){var r=St(t);return e.default[(r?"timeout":"error")+"Retry"]}function Lt(e,t){var r="linear"===e.backoff?1:Math.pow(2,t);return Math.min(r*e.retryDelayMs,e.maxRetryDelayMs)}function Rt(e){return d(d({},e),{errorRetry:null,timeoutRetry:null})}function It(e,t,r,i){if(!e)return!1;var n=null==i?void 0:i.code,a=t499)}(n)||!!r);return e.shouldRetry?e.shouldRetry(e,t,r,i,a):a}var kt=0,bt=2,Dt=3,_t=5,Pt=0,Ct=1,wt=2,Ot=function(e){function t(t){var r;return(r=e.call(this,"error-controller",t.logger)||this).hls=void 0,r.playlistError=0,r.penalizedRenditions={},r.hls=t,r.registerListeners(),r}o(t,e);var r=t.prototype;return r.registerListeners=function(){var e=this.hls;e.on(b.ERROR,this.onError,this),e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.LEVEL_UPDATED,this.onLevelUpdated,this)},r.unregisterListeners=function(){var e=this.hls;e&&(e.off(b.ERROR,this.onError,this),e.off(b.ERROR,this.onErrorOut,this),e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.LEVEL_UPDATED,this.onLevelUpdated,this))},r.destroy=function(){this.unregisterListeners(),this.hls=null,this.penalizedRenditions={}},r.startLoad=function(e){},r.stopLoad=function(){this.playlistError=0},r.getVariantLevelIndex=function(e){return(null==e?void 0:e.type)===w?e.level:this.hls.loadLevel},r.onManifestLoading=function(){this.playlistError=0,this.penalizedRenditions={}},r.onLevelUpdated=function(){this.playlistError=0},r.onError=function(e,t){var r;if(!t.fatal){var i=this.hls,n=t.context;switch(t.details){case k.FRAG_LOAD_ERROR:case k.FRAG_LOAD_TIMEOUT:case k.KEY_LOAD_ERROR:case k.KEY_LOAD_TIMEOUT:return void(t.errorAction=this.getFragRetryOrSwitchAction(t));case k.FRAG_PARSING_ERROR:if(null!=(r=t.frag)&&r.gap)return void(t.errorAction=xt());case k.FRAG_GAP:case k.FRAG_DECRYPT_ERROR:return t.errorAction=this.getFragRetryOrSwitchAction(t),void(t.errorAction.action=bt);case k.LEVEL_EMPTY_ERROR:case k.LEVEL_PARSING_ERROR:var a,s,o=t.parent===w?t.level:i.loadLevel;return void(t.details===k.LEVEL_EMPTY_ERROR&&null!=(a=t.context)&&null!=(s=a.levelDetails)&&s.live?t.errorAction=this.getPlaylistRetryOrSwitchAction(t,o):(t.levelRetry=!1,t.errorAction=this.getLevelSwitchAction(t,o)));case k.LEVEL_LOAD_ERROR:case k.LEVEL_LOAD_TIMEOUT:return void("number"==typeof(null==n?void 0:n.level)&&(t.errorAction=this.getPlaylistRetryOrSwitchAction(t,n.level)));case k.AUDIO_TRACK_LOAD_ERROR:case k.AUDIO_TRACK_LOAD_TIMEOUT:case k.SUBTITLE_LOAD_ERROR:case k.SUBTITLE_TRACK_LOAD_TIMEOUT:if(n){var l=i.loadLevelObj;if(l&&(n.type===P&&l.hasAudioGroup(n.groupId)||n.type===C&&l.hasSubtitleGroup(n.groupId)))return t.errorAction=this.getPlaylistRetryOrSwitchAction(t,i.loadLevel),t.errorAction.action=bt,void(t.errorAction.flags=Ct)}return;case k.KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED:var u=i.loadLevelObj,d=null==u?void 0:u.attrs["HDCP-LEVEL"];return void(d?t.errorAction={action:bt,flags:wt,hdcpLevel:d}:this.keySystemError(t));case k.BUFFER_ADD_CODEC_ERROR:case k.REMUX_ALLOC_ERROR:case k.BUFFER_APPEND_ERROR:var h;return void(t.errorAction||(t.errorAction=this.getLevelSwitchAction(t,null!=(h=t.level)?h:i.loadLevel)));case k.INTERNAL_EXCEPTION:case k.BUFFER_APPENDING_ERROR:case k.BUFFER_FULL_ERROR:case k.LEVEL_SWITCH_ERROR:case k.BUFFER_STALLED_ERROR:case k.BUFFER_SEEK_OVER_HOLE:case k.BUFFER_NUDGE_ON_STALL:return void(t.errorAction=xt())}t.type===I.KEY_SYSTEM_ERROR&&this.keySystemError(t)}},r.keySystemError=function(e){var t=this.getVariantLevelIndex(e.frag);e.levelRetry=!1,e.errorAction=this.getLevelSwitchAction(e,t)},r.getPlaylistRetryOrSwitchAction=function(e,t){var r=At(this.hls.config.playlistLoadPolicy,e),i=this.playlistError++;if(It(r,i,St(e),e.response))return{action:_t,flags:Pt,retryConfig:r,retryCount:i};var n=this.getLevelSwitchAction(e,t);return r&&(n.retryConfig=r,n.retryCount=i),n},r.getFragRetryOrSwitchAction=function(e){var t=this.hls,r=this.getVariantLevelIndex(e.frag),i=t.levels[r],n=t.config,a=n.fragLoadPolicy,s=n.keyLoadPolicy,o=At(e.details.startsWith("key")?s:a,e),l=t.levels.reduce((function(e,t){return e+t.fragmentError}),0);if(i&&(e.details!==k.FRAG_GAP&&i.fragmentError++,It(o,l,St(e),e.response)))return{action:_t,flags:Pt,retryConfig:o,retryCount:l};var u=this.getLevelSwitchAction(e,r);return o&&(u.retryConfig=o,u.retryCount=l),u},r.getLevelSwitchAction=function(e,t){var r=this.hls;null==t&&(t=r.loadLevel);var i=this.hls.levels[t];if(i){var n,a,s=e.details;i.loadError++,s===k.BUFFER_APPEND_ERROR&&i.fragmentError++;var o=-1,l=r.levels,u=r.loadLevel,d=r.minAutoLevel,h=r.maxAutoLevel;r.autoLevelEnabled||r.config.preserveManualLevelOnError||(r.loadLevel=-1);for(var f,c=null==(n=e.frag)?void 0:n.type,g=(c===O&&s===k.FRAG_PARSING_ERROR||"audio"===e.sourceBufferName&&(s===k.BUFFER_ADD_CODEC_ERROR||s===k.BUFFER_APPEND_ERROR))&&l.some((function(e){var t=e.audioCodec;return i.audioCodec!==t})),v="video"===e.sourceBufferName&&(s===k.BUFFER_ADD_CODEC_ERROR||s===k.BUFFER_APPEND_ERROR)&&l.some((function(e){var t=e.codecSet,r=e.audioCodec;return i.codecSet!==t&&i.audioCodec===r})),m=null!=(a=e.context)?a:{},p=m.type,y=m.groupId,E=function(){var t=(T+u)%l.length;if(t!==u&&t>=d&&t<=h&&0===l[t].loadError){var r,n,a=l[t];if(s===k.FRAG_GAP&&c===w&&e.frag){var f=l[t].details;if(f){var m=pt(e.frag,f.fragments,e.frag.start);if(null!=m&&m.gap)return 0}}else{if(p===P&&a.hasAudioGroup(y)||p===C&&a.hasSubtitleGroup(y))return 0;if(c===O&&null!=(r=i.audioGroups)&&r.some((function(e){return a.hasAudioGroup(e)}))||c===x&&null!=(n=i.subtitleGroups)&&n.some((function(e){return a.hasSubtitleGroup(e)}))||g&&i.audioCodec===a.audioCodec||!g&&i.audioCodec!==a.audioCodec||v&&i.codecSet===a.codecSet)return 0}return o=t,1}},T=l.length;T--&&(0===(f=E())||1!==f););if(o>-1&&r.loadLevel!==o)return e.levelRetry=!0,this.playlistError=0,{action:bt,flags:Pt,nextAutoLevel:o}}return{action:bt,flags:Ct}},r.onErrorOut=function(e,t){var r;switch(null==(r=t.errorAction)?void 0:r.action){case kt:break;case bt:this.sendAlternateToPenaltyBox(t),t.errorAction.resolved||t.details===k.FRAG_GAP?/MediaSource readyState: ended/.test(t.error.message)&&(this.warn('MediaSource ended after "'+t.sourceBufferName+'" sourceBuffer append error. Attempting to recover from media error.'),this.hls.recoverMediaError()):t.fatal=!0}t.fatal&&this.hls.stopLoad()},r.sendAlternateToPenaltyBox=function(e){var t=this.hls,r=e.errorAction;if(r){var i=r.flags,n=r.hdcpLevel,a=r.nextAutoLevel;switch(i){case Pt:this.switchLevel(e,a);break;case wt:n&&(t.maxHdcpLevel=ze[ze.indexOf(n)-1],r.resolved=!0),this.warn('Restricting playback to HDCP-LEVEL of "'+t.maxHdcpLevel+'" or lower')}r.resolved||this.switchLevel(e,a)}},r.switchLevel=function(e,t){if(void 0!==t&&e.errorAction&&(this.warn("switching to level "+t+" after "+e.details),this.hls.nextAutoLevel=t,e.errorAction.resolved=!0,this.hls.nextLoadLevel=this.hls.nextAutoLevel,e.details===k.BUFFER_ADD_CODEC_ERROR&&e.mimeType&&"audiovideo"!==e.sourceBufferName))for(var r=Ye(e.mimeType),i=this.hls.levels,n=i.length;n--;)i[n][e.sourceBufferName+"Codec"]===r&&this.hls.removeLevel(n)},t}(N);function xt(e){var t={action:kt,flags:Pt};return e&&(t.resolved=!0),t}var Mt="NOT_LOADED",Ft="APPENDING",Nt="PARTIAL",Ut="OK",Bt=function(){function e(e){this.activePartLists=Object.create(null),this.endListFragments=Object.create(null),this.fragments=Object.create(null),this.timeRanges=Object.create(null),this.bufferPadding=.2,this.hls=void 0,this.hasGaps=!1,this.hls=e,this._registerListeners()}var t=e.prototype;return t._registerListeners=function(){var e=this.hls;e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.BUFFER_APPENDED,this.onBufferAppended,this),e.on(b.FRAG_BUFFERED,this.onFragBuffered,this),e.on(b.FRAG_LOADED,this.onFragLoaded,this)},t._unregisterListeners=function(){var e=this.hls;e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.BUFFER_APPENDED,this.onBufferAppended,this),e.off(b.FRAG_BUFFERED,this.onFragBuffered,this),e.off(b.FRAG_LOADED,this.onFragLoaded,this)},t.destroy=function(){this._unregisterListeners(),this.fragments=this.activePartLists=this.endListFragments=this.timeRanges=null},t.getAppendedFrag=function(e,t){var r=this.activePartLists[t];if(r)for(var i=r.length;i--;){var n=r[i];if(!n)break;var a=n.end;if(n.start<=e&&null!==a&&e<=a)return n}return this.getBufferedFrag(e,t)},t.getBufferedFrag=function(e,t){return this.getFragAtPos(e,t,!0)},t.getFragAtPos=function(e,t,r){for(var i=this.fragments,n=Object.keys(i),a=n.length;a--;){var s=i[n[a]];if((null==s?void 0:s.body.type)===t&&(!r||s.buffered)){var o=s.body;if(o.start<=e&&e<=o.end)return o}}return null},t.detectEvictedFragments=function(e,t,r,i,n){var a=this;this.timeRanges&&(this.timeRanges[e]=t);var s=(null==i?void 0:i.fragment.sn)||-1;Object.keys(this.fragments).forEach((function(i){var o=a.fragments[i];if(o&&!(s>=o.body.sn))if(o.buffered||o.loaded&&!n){var l=o.range[e];l&&(0!==l.time.length?l.time.some((function(e){var r=!a.isTimeBuffered(e.startPTS,e.endPTS,t);return r&&a.removeFragment(o.body),r})):a.removeFragment(o.body))}else o.body.type===r&&a.removeFragment(o.body)}))},t.detectPartialFragments=function(e){var t=this,r=this.timeRanges;if(r&&"initSegment"!==e.frag.sn){var i=e.frag,n=Kt(i),a=this.fragments[n];if(!(!a||a.buffered&&i.gap)){var s=!i.relurl;Object.keys(r).forEach((function(n){var o=i.elementaryStreams[n];if(o){var l=r[n],u=s||!0===o.partial;a.range[n]=t.getBufferedTimes(i,e.part,u,l)}})),a.loaded=null,Object.keys(a.range).length?(a.buffered=!0,(a.body.endList=i.endList||a.body.endList)&&(this.endListFragments[a.body.type]=a),Gt(a)||this.removeParts(i.sn-1,i.type)):this.removeFragment(a.body)}}},t.removeParts=function(e,t){var r=this.activePartLists[t];r&&(this.activePartLists[t]=Vt(r,(function(t){return t.fragment.sn>=e})))},t.fragBuffered=function(e,t){var r=Kt(e),i=this.fragments[r];!i&&t&&(i=this.fragments[r]={body:e,appendedPTS:null,loaded:null,buffered:!1,range:Object.create(null)},e.gap&&(this.hasGaps=!0)),i&&(i.loaded=null,i.buffered=!0)},t.getBufferedTimes=function(e,t,r,i){for(var n={time:[],partial:r},a=e.start,s=e.end,o=e.minEndPTS||s,l=e.maxStartPTS||a,u=0;u=d&&o<=h){n.time.push({startPTS:Math.max(a,i.start(u)),endPTS:Math.min(s,i.end(u))});break}if(ad){var f=Math.max(a,i.start(u)),c=Math.min(s,i.end(u));c>f&&(n.partial=!0,n.time.push({startPTS:f,endPTS:c}))}else if(s<=d)break}return n},t.getPartialFragment=function(e){var t,r,i,n=null,a=0,s=this.bufferPadding,o=this.fragments;return Object.keys(o).forEach((function(l){var u=o[l];u&&Gt(u)&&(r=u.body.start-s,i=u.body.end+s,e>=r&&e<=i&&(t=Math.min(e-r,i-e),a<=t&&(n=u.body,a=t)))})),n},t.isEndListAppended=function(e){var t=this.endListFragments[e];return void 0!==t&&(t.buffered||Gt(t))},t.getState=function(e){var t=Kt(e),r=this.fragments[t];return r?r.buffered?Gt(r)?Nt:Ut:Ft:Mt},t.isTimeBuffered=function(e,t,r){for(var i,n,a=0;a=i&&t<=n)return!0;if(t<=i)return!1}return!1},t.onManifestLoading=function(){this.removeAllFragments()},t.onFragLoaded=function(e,t){if("initSegment"!==t.frag.sn&&!t.frag.bitrateTest){var r=t.frag,i=t.part?null:t,n=Kt(r);this.fragments[n]={body:r,appendedPTS:null,loaded:i,buffered:!1,range:Object.create(null)}}},t.onBufferAppended=function(e,t){var r=t.frag,i=t.part,n=t.timeRanges,a=t.type;if("initSegment"!==r.sn){var s=r.type;if(i){var o=this.activePartLists[s];o||(this.activePartLists[s]=o=[]),o.push(i)}this.timeRanges=n;var l=n[a];this.detectEvictedFragments(a,l,s,i)}},t.onFragBuffered=function(e,t){this.detectPartialFragments(t)},t.hasFragment=function(e){var t=Kt(e);return!!this.fragments[t]},t.hasFragments=function(e){var t=this.fragments,r=Object.keys(t);if(!e)return r.length>0;for(var i=r.length;i--;){var n=t[r[i]];if((null==n?void 0:n.body.type)===e)return!0}return!1},t.hasParts=function(e){var t;return!(null==(t=this.activePartLists[e])||!t.length)},t.removeFragmentsInRange=function(e,t,r,i,n){var a=this;i&&!this.hasGaps||Object.keys(this.fragments).forEach((function(s){var o=a.fragments[s];if(o){var l=o.body;l.type!==r||i&&!l.gap||l.starte&&(o.buffered||n)&&a.removeFragment(l)}}))},t.removeFragment=function(e){var t=Kt(e);e.clearElementaryStreamInfo();var r=this.activePartLists[e.type];if(r){var i=e.sn;this.activePartLists[e.type]=Vt(r,(function(e){return e.fragment.sn!==i}))}delete this.fragments[t],e.endList&&delete this.endListFragments[e.type]},t.removeAllFragments=function(){var e,t;this.fragments=Object.create(null),this.endListFragments=Object.create(null),this.activePartLists=Object.create(null),this.hasGaps=!1;var r=null==(e=this.hls)||null==(t=e.latestLevelDetails)?void 0:t.partList;r&&r.forEach((function(e){return e.clearElementaryStreamInfo()}))},e}();function Gt(e){var t,r,i;return e.buffered&&(e.body.gap||(null==(t=e.range.video)?void 0:t.partial)||(null==(r=e.range.audio)?void 0:r.partial)||(null==(i=e.range.audiovideo)?void 0:i.partial))}function Kt(e){return e.type+"_"+e.level+"_"+e.sn}function Vt(e,t){return e.filter((function(e){var r=t(e);return r||e.clearElementaryStreamInfo(),r}))}var Ht=0,Yt=1,Wt=function(){function e(e,t,r){this.subtle=void 0,this.aesIV=void 0,this.aesMode=void 0,this.subtle=e,this.aesIV=t,this.aesMode=r}return e.prototype.decrypt=function(e,t){switch(this.aesMode){case Ht:return this.subtle.decrypt({name:"AES-CBC",iv:this.aesIV},t,e);case Yt:return this.subtle.decrypt({name:"AES-CTR",counter:this.aesIV,length:64},t,e);default:throw new Error("[AESCrypto] invalid aes mode "+this.aesMode)}},e}(),jt=function(){function e(){this.rcon=[0,1,2,4,8,16,32,64,128,27,54],this.subMix=[new Uint32Array(256),new Uint32Array(256),new Uint32Array(256),new Uint32Array(256)],this.invSubMix=[new Uint32Array(256),new Uint32Array(256),new Uint32Array(256),new Uint32Array(256)],this.sBox=new Uint32Array(256),this.invSBox=new Uint32Array(256),this.key=new Uint32Array(0),this.ksRows=0,this.keySize=0,this.keySchedule=void 0,this.invKeySchedule=void 0,this.initTable()}var t=e.prototype;return t.uint8ArrayToUint32Array_=function(e){for(var t=new DataView(e),r=new Uint32Array(4),i=0;i<4;i++)r[i]=t.getUint32(4*i);return r},t.initTable=function(){var e=this.sBox,t=this.invSBox,r=this.subMix,i=r[0],n=r[1],a=r[2],s=r[3],o=this.invSubMix,l=o[0],u=o[1],d=o[2],h=o[3],f=new Uint32Array(256),c=0,g=0,v=0;for(v=0;v<256;v++)f[v]=v<128?v<<1:v<<1^283;for(v=0;v<256;v++){var m=g^g<<1^g<<2^g<<3^g<<4;m=m>>>8^255&m^99,e[c]=m,t[m]=c;var p=f[c],y=f[p],E=f[y],T=257*f[m]^16843008*m;i[c]=T<<24|T>>>8,n[c]=T<<16|T>>>16,a[c]=T<<8|T>>>24,s[c]=T,T=16843009*E^65537*y^257*p^16843008*c,l[m]=T<<24|T>>>8,u[m]=T<<16|T>>>16,d[m]=T<<8|T>>>24,h[m]=T,c?(c=p^f[f[f[E^p]]],g^=f[f[g]]):c=g=1}},t.expandKey=function(e){for(var t=this.uint8ArrayToUint32Array_(e),r=!0,i=0;i1&&this.tickImmediate(),this._tickCallCount=0)},r.tickImmediate=function(){this.clearNextTick(),this._tickTimer=self.setTimeout(this._boundTick,0)},r.doTick=function(){},t}(N),tr=function(e,t,r,i,n,a){void 0===i&&(i=0),void 0===n&&(n=-1),void 0===a&&(a=!1),this.level=void 0,this.sn=void 0,this.part=void 0,this.id=void 0,this.size=void 0,this.partial=void 0,this.transmuxing={start:0,executeStart:0,executeEnd:0,end:0},this.buffering={audio:{start:0,executeStart:0,executeEnd:0,end:0},video:{start:0,executeStart:0,executeEnd:0,end:0},audiovideo:{start:0,executeStart:0,executeEnd:0,end:0}},this.level=e,this.sn=t,this.id=r,this.size=i,this.part=n,this.partial=a},rr={length:0,start:function(){return 0},end:function(){return 0}},ir=function(){function e(){}return e.isBuffered=function(t,r){if(t)for(var i=e.getBuffered(t),n=i.length;n--;)if(r>=i.start(n)&&r<=i.end(n))return!0;return!1},e.bufferedRanges=function(t){if(t){var r=e.getBuffered(t);return e.timeRangesToArray(r)}return[]},e.timeRangesToArray=function(e){for(var t=[],r=0;r1&&e.sort((function(e,t){return e.start-t.start||t.end-e.end}));var i=-1,n=[];if(r)for(var a=0;a=e[a].start&&t<=e[a].end&&(i=a);var s=n.length;if(s){var o=n[s-1].end;e[a].start-oo&&(n[s-1].end=e[a].end):n.push(e[a])}else n.push(e[a])}else n=e;for(var l,u=0,d=t,h=t,f=0;f=c&&t<=g&&(i=f),t+r>=c&&tNumber.MAX_SAFE_INTEGER?1/0:t},t.hexadecimalInteger=function(e){if(this[e]){var t=(this[e]||"0x").slice(2);t=(1&t.length?"0":"")+t;for(var r=new Uint8Array(t.length/2),i=0;iNumber.MAX_SAFE_INTEGER?1/0:t},t.decimalFloatingPoint=function(e){return parseFloat(this[e])},t.optionalFloat=function(e,t){var r=this[e];return r?parseFloat(r):t},t.enumeratedString=function(e){return this[e]},t.enumeratedStringList=function(e,t){var r=this[e];return(r?r.split(/[ ,]+/):[]).reduce((function(e,t){return e[t.toLowerCase()]=!0,e}),t)},t.bool=function(e){return"YES"===this[e]},t.decimalResolution=function(e){var t=ur.exec(this[e]);if(null!==t)return{width:parseInt(t[1],10),height:parseInt(t[2],10)}},e.parseAttrList=function(e,t){var r,i={};for(dr.lastIndex=0;null!==(r=dr.exec(e));){var n=r[1].trim(),a=r[2],s=0===a.indexOf('"')&&a.lastIndexOf('"')===a.length-1,o=!1;if(s)a=a.slice(1,-1);else switch(n){case"IV":case"SCTE35-CMD":case"SCTE35-IN":case"SCTE35-OUT":o=!0}if(t&&(s||o))a=sr(t,a);else if(!o&&!s)switch(n){case"CLOSED-CAPTIONS":if("NONE"===a)break;case"ALLOWED-CPC":case"CLASS":case"ASSOC-LANGUAGE":case"AUDIO":case"BYTERANGE":case"CHANNELS":case"CHARACTERISTICS":case"CODECS":case"DATA-ID":case"END-DATE":case"GROUP-ID":case"ID":case"IMPORT":case"INSTREAM-ID":case"KEYFORMAT":case"KEYFORMATVERSIONS":case"LANGUAGE":case"NAME":case"PATHWAY-ID":case"QUERYPARAM":case"RECENTLY-REMOVED-DATERANGES":case"SERVER-URI":case"STABLE-RENDITION-ID":case"STABLE-VARIANT-ID":case"START-DATE":case"SUBTITLES":case"SUPPLEMENTAL-CODECS":case"URI":case"VALUE":case"VIDEO":case"X-ASSET-LIST":case"X-ASSET-URI":Y.warn(e+": attribute "+n+" is missing quotes")}i[n]=a}return i},i(e,[{key:"clientAttrs",get:function(){return Object.keys(this).filter((function(e){return"X-"===e.substring(0,2)}))}}])}();function fr(e){return"SCTE35-OUT"===e||"SCTE35-IN"===e||"SCTE35-CMD"===e}var cr=function(){return i((function(e,t,r){var i;if(void 0===r&&(r=0),this.attr=void 0,this.tagAnchor=void 0,this.tagOrder=void 0,this._startDate=void 0,this._endDate=void 0,this._dateAtEnd=void 0,this._cue=void 0,this._badValueForSameId=void 0,this.tagAnchor=(null==t?void 0:t.tagAnchor)||null,this.tagOrder=null!=(i=null==t?void 0:t.tagOrder)?i:r,t){var n=t.attr;for(var s in n)if(Object.prototype.hasOwnProperty.call(e,s)&&e[s]!==n[s]){Y.warn('DATERANGE tag attribute: "'+s+'" does not match for tags with ID: "'+e.ID+'"'),this._badValueForSameId=s;break}e=a(new hr({}),n,e)}if(this.attr=e,t?(this._startDate=t._startDate,this._cue=t._cue,this._endDate=t._endDate,this._dateAtEnd=t._dateAtEnd):this._startDate=new Date(e["START-DATE"]),"END-DATE"in this.attr){var o=(null==t?void 0:t.endDate)||new Date(this.attr["END-DATE"]);A(o.getTime())&&(this._endDate=o)}}),[{key:"id",get:function(){return this.attr.ID}},{key:"class",get:function(){return this.attr.CLASS}},{key:"cue",get:function(){var e=this._cue;return void 0===e?this._cue=this.attr.enumeratedStringList(this.attr.CUE?"CUE":"X-CUE",{pre:!1,post:!1,once:!1}):e}},{key:"startTime",get:function(){var e=this.tagAnchor;return null===e||null===e.programDateTime?(Y.warn('Expected tagAnchor Fragment with PDT set for DateRange "'+this.id+'": '+e),NaN):e.start+(this.startDate.getTime()-e.programDateTime)/1e3}},{key:"startDate",get:function(){return this._startDate}},{key:"endDate",get:function(){var e=this._endDate||this._dateAtEnd;if(e)return e;var t=this.duration;return null!==t?this._dateAtEnd=new Date(this._startDate.getTime()+1e3*t):null}},{key:"duration",get:function(){if("DURATION"in this.attr){var e=this.attr.decimalFloatingPoint("DURATION");if(A(e))return e}else if(this._endDate)return(this._endDate.getTime()-this._startDate.getTime())/1e3;return null}},{key:"plannedDuration",get:function(){return"PLANNED-DURATION"in this.attr?this.attr.decimalFloatingPoint("PLANNED-DURATION"):null}},{key:"endOnNext",get:function(){return this.attr.bool("END-ON-NEXT")}},{key:"isInterstitial",get:function(){return"com.apple.hls.interstitial"===this.class}},{key:"isValid",get:function(){return!!this.id&&!this._badValueForSameId&&A(this.startDate.getTime())&&(null===this.duration||this.duration>=0)&&(!this.endOnNext||!!this.class)&&(!this.attr.CUE||!this.cue.pre&&!this.cue.post||this.cue.pre!==this.cue.post)&&(!this.isInterstitial||"X-ASSET-URI"in this.attr||"X-ASSET-LIST"in this.attr)}}])}(),gr=function(){function e(e){this.PTSKnown=!1,this.alignedSliding=!1,this.averagetargetduration=void 0,this.endCC=0,this.endSN=0,this.fragments=void 0,this.fragmentHint=void 0,this.partList=null,this.dateRanges=void 0,this.dateRangeTagCount=0,this.live=!0,this.requestScheduled=-1,this.ageHeader=0,this.advancedDateTime=void 0,this.updated=!0,this.advanced=!0,this.misses=0,this.startCC=0,this.startSN=0,this.startTimeOffset=null,this.targetduration=0,this.totalduration=0,this.type=null,this.url=void 0,this.m3u8="",this.version=null,this.canBlockReload=!1,this.canSkipUntil=0,this.canSkipDateRanges=!1,this.skippedSegments=0,this.recentlyRemovedDateranges=void 0,this.partHoldBack=0,this.holdBack=0,this.partTarget=0,this.preloadHint=void 0,this.renditionReports=void 0,this.tuneInGoal=0,this.deltaUpdateFailed=void 0,this.driftStartTime=0,this.driftEndTime=0,this.driftStart=0,this.driftEnd=0,this.encryptedFragments=void 0,this.playlistParsingError=null,this.variableList=null,this.hasVariableRefs=!1,this.appliedTimelineOffset=void 0,this.fragments=[],this.encryptedFragments=[],this.dateRanges={},this.url=e}return e.prototype.reloaded=function(e){if(!e)return this.advanced=!0,void(this.updated=!0);var t=this.lastPartSn-e.lastPartSn,r=this.lastPartIndex-e.lastPartIndex;this.updated=this.endSN!==e.endSN||!!r||!!t||!this.live,this.advanced=this.endSN>e.endSN||t>0||0===t&&r>0,this.updated||this.advanced?this.misses=Math.floor(.6*e.misses):this.misses=e.misses+1},i(e,[{key:"hasProgramDateTime",get:function(){return!!this.fragments.length&&A(this.fragments[this.fragments.length-1].programDateTime)}},{key:"levelTargetDuration",get:function(){return this.averagetargetduration||this.targetduration||10}},{key:"drift",get:function(){var e=this.driftEndTime-this.driftStartTime;return e>0?1e3*(this.driftEnd-this.driftStart)/e:1}},{key:"edge",get:function(){return this.partEnd||this.fragmentEnd}},{key:"partEnd",get:function(){var e;return null!=(e=this.partList)&&e.length?this.partList[this.partList.length-1].end:this.fragmentEnd}},{key:"fragmentEnd",get:function(){var e;return null!=(e=this.fragments)&&e.length?this.fragments[this.fragments.length-1].end:0}},{key:"fragmentStart",get:function(){var e;return null!=(e=this.fragments)&&e.length?this.fragments[0].start:0}},{key:"age",get:function(){return this.advancedDateTime?Math.max(Date.now()-this.advancedDateTime,0)/1e3:0}},{key:"lastPartIndex",get:function(){var e;return null!=(e=this.partList)&&e.length?this.partList[this.partList.length-1].index:-1}},{key:"maxPartIndex",get:function(){var e=this.partList;if(e){var t=this.lastPartIndex;if(-1!==t){for(var r=e.length;r--;)if(e[r].index>t)return e[r].index;return t}}return 0}},{key:"lastPartSn",get:function(){var e;return null!=(e=this.partList)&&e.length?this.partList[this.partList.length-1].fragment.sn:this.endSN}},{key:"expired",get:function(){if(this.live&&this.age&&this.misses<3){var e=this.partEnd-this.fragmentStart;return this.age>Math.max(e,this.totalduration)+this.levelTargetDuration}return!1}}])}();function vr(e){return"AES-128"===e||"AES-256"===e||"AES-256-CTR"===e}function mr(e){switch(e){case"AES-128":case"AES-256":return Ht;case"AES-256-CTR":return Yt;default:throw new Error("invalid full segment method "+e)}}function pr(e){return Uint8Array.from(atob(e),(function(e){return e.charCodeAt(0)}))}function yr(e){return Uint8Array.from(unescape(encodeURIComponent(e)),(function(e){return e.charCodeAt(0)}))}function Er(e){var t,r,i=e.split(":"),n=null;if("data"===i[0]&&2===i.length){var a=i[1].split(";"),s=a[a.length-1].split(",");if(2===s.length){var o="base64"===s[0],l=s[1];o?(a.splice(-1,1),n=pr(l)):(t=yr(l).subarray(0,16),(r=new Uint8Array(16)).set(t,16-t.length),n=r)}}return n}var Tr="undefined"!=typeof self?self:void 0,Sr={CLEARKEY:"org.w3.clearkey",FAIRPLAY:"com.apple.fps",PLAYREADY:"com.microsoft.playready",WIDEVINE:"com.widevine.alpha"},Ar="org.w3.clearkey",Lr="com.apple.streamingkeydelivery",Rr="com.microsoft.playready",Ir="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";function kr(e){switch(e){case Lr:return Sr.FAIRPLAY;case Rr:return Sr.PLAYREADY;case Ir:return Sr.WIDEVINE;case Ar:return Sr.CLEARKEY}}var br="1077efecc0b24d02ace33c1e52e2fb4b",Dr="e2719d58a985b3c9781ab030af78d30e",_r="9a04f07998404286ab92e65be0885f95",Pr="edef8ba979d64acea3c827dcd51d21ed";function Cr(e){return e===Pr?Sr.WIDEVINE:e===_r?Sr.PLAYREADY:e===br||e===Dr?Sr.CLEARKEY:void 0}function wr(e){switch(e){case Sr.FAIRPLAY:return Lr;case Sr.PLAYREADY:return Rr;case Sr.WIDEVINE:return Ir;case Sr.CLEARKEY:return Ar}}function Or(e){var t=e.drmSystems,r=e.widevineLicenseUrl,i=t?[Sr.FAIRPLAY,Sr.WIDEVINE,Sr.PLAYREADY,Sr.CLEARKEY].filter((function(e){return!!t[e]})):[];return!i[Sr.WIDEVINE]&&r&&i.push(Sr.WIDEVINE),i}var xr,Mr=null!=Tr&&null!=(xr=Tr.navigator)&&xr.requestMediaKeySystemAccess?self.navigator.requestMediaKeySystemAccess.bind(self.navigator):null;function Fr(e){var t=new Uint16Array(e.buffer,e.byteOffset,e.byteLength/2),r=String.fromCharCode.apply(null,Array.from(t)),i=r.substring(r.indexOf("<"),r.length),n=(new DOMParser).parseFromString(i,"text/xml").getElementsByTagName("KID")[0];if(n){var a=n.childNodes[0]?n.childNodes[0].nodeValue:n.getAttribute("VALUE");if(a){var s=pr(a).subarray(0,16);return function(e){var t=function(e,t,r){var i=e[t];e[t]=e[r],e[r]=i};t(e,0,3),t(e,1,2),t(e,4,5),t(e,6,7)}(s),s}}return null}var Nr={},Ur=function(){function e(e,t,r,i,n){void 0===i&&(i=[1]),void 0===n&&(n=null),this.uri=void 0,this.method=void 0,this.keyFormat=void 0,this.keyFormatVersions=void 0,this.encrypted=void 0,this.isCommonEncryption=void 0,this.iv=null,this.key=null,this.keyId=null,this.pssh=null,this.method=e,this.uri=t,this.keyFormat=r,this.keyFormatVersions=i,this.iv=n,this.encrypted=!!e&&"NONE"!==e,this.isCommonEncryption=this.encrypted&&!vr(e)}e.clearKeyUriToKeyIdMap=function(){Nr={}};var t=e.prototype;return t.isSupported=function(){if(this.method){if(vr(this.method)||"NONE"===this.method)return!0;if("identity"===this.keyFormat)return"SAMPLE-AES"===this.method;switch(this.keyFormat){case Lr:case Ir:case Rr:case Ar:return-1!==["ISO-23001-7","SAMPLE-AES","SAMPLE-AES-CENC","SAMPLE-AES-CTR"].indexOf(this.method)}}return!1},t.getDecryptData=function(t){if(!this.encrypted||!this.uri)return null;if(vr(this.method)&&this.uri&&!this.iv){"number"!=typeof t&&(Y.warn('missing IV for initialization segment with method="'+this.method+'" - compliance issue'),t=0);var r=function(e){for(var t=new Uint8Array(16),r=12;r<16;r++)t[r]=e>>8*(15-r)&255;return t}(t);return new e(this.method,this.uri,"identity",this.keyFormatVersions,r)}var i=Er(this.uri);if(i)switch(this.keyFormat){case Ir:this.pssh=i,i.length>=22&&(this.keyId=i.subarray(i.length-22,i.length-6));break;case Rr:var n=new Uint8Array([154,4,240,121,152,64,66,134,171,146,230,91,224,136,95,149]);this.pssh=be(n,0,i),this.keyId=Fr(i);break;default:var a=i.subarray(0,16);if(16!==a.length){var s=new Uint8Array(16);s.set(a,16-a.length),a=s}this.keyId=a}if(!this.keyId||16!==this.keyId.byteLength){var o=Nr[this.uri];if(!o){var l=Object.keys(Nr).length%Number.MAX_SAFE_INTEGER;o=new Uint8Array(16),new DataView(o.buffer,12,4).setUint32(0,l),Nr[this.uri]=o}this.keyId=o}return this},e}(),Br=/#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-(SESSION-DATA|SESSION-KEY|DEFINE|CONTENT-STEERING|START):([^\r\n]*)[\r\n]+/g,Gr=/#EXT-X-MEDIA:(.*)/g,Kr=/^#EXT(?:INF|-X-TARGETDURATION):/m,Vr=new RegExp([/#EXTINF:\s*(\d*(?:\.\d+)?)(?:,(.*)\s+)?/.source,/(?!#) *(\S[^\r\n]*)/.source,/#.*/.source].join("|"),"g"),Hr=new RegExp([/#EXT-X-(PROGRAM-DATE-TIME|BYTERANGE|DATERANGE|DEFINE|KEY|MAP|PART|PART-INF|PLAYLIST-TYPE|PRELOAD-HINT|RENDITION-REPORT|SERVER-CONTROL|SKIP|START):(.+)/.source,/#EXT-X-(BITRATE|DISCONTINUITY-SEQUENCE|MEDIA-SEQUENCE|TARGETDURATION|VERSION): *(\d+)/.source,/#EXT-X-(DISCONTINUITY|ENDLIST|GAP|INDEPENDENT-SEGMENTS)/.source,/(#)([^:]*):(.*)/.source,/(#)(.*)(?:.*)\r?\n?/.source].join("|")),Yr=function(){function e(){}return e.findGroup=function(e,t){for(var r=0;r0&&a.length0&&ti(c,C,l),p=c.startSN=parseInt(w);break;case"SKIP":c.skippedSegments&&ei(c,C,l);var x=new hr(w,c),M=x.decimalInteger("SKIPPED-SEGMENTS");if(A(M)){c.skippedSegments+=M;for(var F=M;F--;)g.push(null);p+=M}var N=x.enumeratedString("RECENTLY-REMOVED-DATERANGES");N&&(c.recentlyRemovedDateranges=(c.recentlyRemovedDateranges||[]).concat(N.split("\t")));break;case"TARGETDURATION":0!==c.targetduration&&ei(c,C,l),c.targetduration=Math.max(parseInt(w),1);break;case"VERSION":null!==c.version&&ei(c,C,l),c.version=parseInt(w);break;case"INDEPENDENT-SEGMENTS":break;case"ENDLIST":c.live||ei(c,C,l),c.live=!1;break;case"#":(w||O)&&R.tagList.push(O?[w,O]:[w]);break;case"DISCONTINUITY":T++,R.tagList.push(["DIS"]);break;case"GAP":R.gap=!0,R.tagList.push([C]);break;case"BITRATE":R.tagList.push([C,w]),S=1e3*parseInt(w),A(S)?R.bitrate=S:S=0;break;case"DATERANGE":var U=new hr(w,c),B=new cr(U,c.dateRanges[U.ID],c.dateRangeTagCount);c.dateRangeTagCount++,B.isValid||c.skippedSegments?c.dateRanges[B.id]=B:Y.warn('Ignoring invalid DATERANGE tag: "'+w+'"'),R.tagList.push(["EXT-X-DATERANGE",w]);break;case"DEFINE":var G=new hr(w,c);"IMPORT"in G?lr(c,G,s):or(c,G,t);break;case"DISCONTINUITY-SEQUENCE":0!==c.startCC?ei(c,C,l):g.length>0&&ti(c,C,l),c.startCC=T=parseInt(w);break;case"KEY":var K=qr(w,t,c);if(K.isSupported()){if("NONE"===K.method){d=void 0;break}d||(d={}),d[K.keyFormat]&&(d=a({},d)),d[K.keyFormat]=K}else Y.warn('[Keys] Ignoring invalid EXT-X-KEY tag: "'+w+'"');break;case"START":c.startTimeOffset=Xr(w);break;case"MAP":var V=new hr(w,c);if(R.duration){var H=new te(i,f);Jr(H,V,r,d),m=H,R.initSegment=m,m.rawProgramDateTime&&!R.rawProgramDateTime&&(R.rawProgramDateTime=m.rawProgramDateTime)}else{var W=R.byteRangeEndOffset;if(W){var j=R.byteRangeStartOffset;b=W-j+"@"+j}else b=null;Jr(R,V,r,d),m=R,k=!0}m.cc=T;break;case"SERVER-CONTROL":h&&ei(c,C,l),h=new hr(w),c.canBlockReload=h.bool("CAN-BLOCK-RELOAD"),c.canSkipUntil=h.optionalFloat("CAN-SKIP-UNTIL",0),c.canSkipDateRanges=c.canSkipUntil>0&&h.bool("CAN-SKIP-DATERANGES"),c.partHoldBack=h.optionalFloat("PART-HOLD-BACK",0),c.holdBack=h.optionalFloat("HOLD-BACK",0);break;case"PART-INF":c.partTarget&&ei(c,C,l);var q=new hr(w);c.partTarget=q.decimalFloatingPoint("PART-TARGET");break;case"PART":var X=c.partList;X||(X=c.partList=[]);var Q=y>0?X[X.length-1]:void 0,z=y++,$=new hr(w,c),J=new re($,R,f,z,Q);X.push(J),R.duration+=J.duration;break;case"PRELOAD-HINT":var Z=new hr(w,c);c.preloadHint=Z;break;case"RENDITION-REPORT":var ee=new hr(w,c);c.renditionReports=c.renditionReports||[],c.renditionReports.push(ee);break;default:Y.warn("line parsed but not handled: "+l)}}}L&&!L.relurl?(g.pop(),E-=L.duration,c.partList&&(c.fragmentHint=L)):c.partList&&($r(R,L,v),R.cc=T,c.fragmentHint=R,d&&Zr(R,d,c)),c.targetduration||(c.playlistParsingError=new Error("#EXT-X-TARGETDURATION is required"));var ie=g.length,ne=g[0],ae=g[ie-1];if((E+=c.skippedSegments*c.targetduration)>0&&ie&&ae){c.averagetargetduration=E/ie;var se=ae.sn;c.endSN="initSegment"!==se?se:0,c.live||(ae.endList=!0),ne&&void 0===c.startCC&&(c.startCC=ne.cc),I>0&&(function(e,t){for(var r=e[t],i=t;i--;){var n=e[i];if(!n)return;n.programDateTime=r.programDateTime-1e3*n.duration,r=n}}(g,I),ne&&v.unshift(ne))}else c.endSN=0,c.startCC=0;return c.fragmentHint&&(E+=c.fragmentHint.duration),c.totalduration=E,v.length&&c.dateRangeTagCount&&ne&&Wr(v,c),c.endCC=T,c},e}();function Wr(e,t){var r=e.length;if(r)for(var i=e[r-1],n=t.live?1/0:t.totalduration,a=Object.keys(t.dateRanges),s=a.length;s--;){var o=t.dateRanges[a[s]],l=o.startDate.getTime();o.tagAnchor=i.ref;for(var u=r;u--;){var d=jr(t,l,e,u,n);if(-1!==d){o.tagAnchor=t.fragments[d].ref;break}}}}function jr(e,t,r,i,n){var a=r[i];if(a){var s,o=a.programDateTime;if((t>=o||0===i)&&t<=o+1e3*(((null==(s=r[i+1])?void 0:s.start)||n)-a.start)){var l=r[i].sn-e.startSN,u=e.fragments;if(u.length>r.length)for(var d=(r[i+1]||u[u.length-1]).sn-e.startSN;d>l;d--){var h=u[d].programDateTime;if(t>=h&&te.sn?(n=r-e.start,i=e):(n=e.start-r,i=t),i.duration!==n&&i.setDuration(n)}else t.sn>e.sn?e.cc===t.cc&&e.minEndPTS?t.setStart(e.start+(e.minEndPTS-e.start)):t.setStart(e.start+e.duration):t.setStart(Math.max(e.start-t.duration,0))}function ii(e,t,r,i,n,a){i-r<=0&&(Y.warn("Fragment should have a positive duration",t),i=r+t.duration,a=n+t.duration);var s=r,o=i,l=t.startPTS,u=t.endPTS;if(A(l)){var d=Math.abs(l-r);A(t.deltaPTS)?t.deltaPTS=Math.max(d,t.deltaPTS):t.deltaPTS=d,s=Math.max(r,l),r=Math.min(r,l),n=Math.min(n,t.startDTS),o=Math.min(i,u),i=Math.max(i,u),a=Math.max(a,t.endDTS)}var h=r-t.start;0!==t.start&&t.setStart(r),t.setDuration(i-t.start),t.startPTS=r,t.maxStartPTS=s,t.startDTS=n,t.endPTS=i,t.minEndPTS=o,t.endDTS=a;var f,c=t.sn;if(!e||ce.endSN)return 0;var g=c-e.startSN,v=e.fragments;for(v[g]=t,f=g;f>0;f--)ri(v[f],v[f-1]);for(f=g;f=0;s--){var o=n[s].initSegment;if(o){i=o;break}}e.fragmentHint&&delete e.fragmentHint.endPTS,function(e,t,r){for(var i=t.skippedSegments,n=Math.max(e.startSN,t.startSN)-t.startSN,a=(e.fragmentHint?1:0)+(i?t.endSN:Math.min(e.endSN,t.endSN))-t.startSN,s=t.startSN-e.startSN,o=t.fragmentHint?t.fragments.concat(t.fragmentHint):t.fragments,l=e.fragmentHint?e.fragments.concat(e.fragmentHint):e.fragments,u=n;u<=a;u++){var d=l[s+u],h=o[u];if(i&&!h&&d&&(h=t.fragments[u]=d),d&&h){if(r(d,h,u,o),d.url&&d.url!==h.url)return void(t.playlistParsingError=ai("media sequence mismatch "+h.sn+":",e,t,0,h));if(d.cc!==h.cc)return void(t.playlistParsingError=ai("discontinuity sequence mismatch ("+d.cc+"!="+h.cc+")",e,t,0,h))}}}(e,t,(function(e,n,a,s){if((!t.startCC||t.skippedSegments)&&n.cc!==e.cc){for(var o=e.cc-n.cc,l=a;l=0,s=0;if(a&&it){var n=1e3*i[i.length-1].duration;ne.startCC)}(t,e)){var r=Math.min(t.endCC,e.endCC),i=ci(t.fragments,r),n=ci(e.fragments,r);i&&n&&(Y.log("Aligning playlist at start of dicontinuity sequence "+r),vi(i.start-n.start,e))}}function pi(e,t){if(e.hasProgramDateTime&&t.hasProgramDateTime){var r=e.fragments,i=t.fragments;if(r.length&&i.length){var n,a,s=Math.min(t.endCC,e.endCC);t.startCCl.end){var c=o>f;(os.lastCurrentTime&&(s.lastCurrentTime=o),!s.loadingParts)){var g=Math.max(l.end,o),v=s.shouldLoadParts(s.getLevelDetails(),g);v&&(s.log("LL-Part loading ON after seeking to "+o.toFixed(2)+" with buffer @"+g.toFixed(2)),s.loadingParts=v)}s.hls.hasEnoughToStart||(s.log("Setting "+(u?"startPosition":"nextLoadPosition")+" to "+o+" for seek without enough to start"),s.nextLoadPosition=o,u&&(s.startPosition=o)),s.tickImmediate()},s.onMediaEnded=function(){s.log("setting startPosition to 0 because media ended"),s.startPosition=s.lastCurrentTime=0},s.playlistType=a,s.hls=t,s.fragmentLoader=new zt(t.config),s.keyLoader=i,s.fragmentTracker=r,s.config=t.config,s.decrypter=new Xt(t.config),s}o(t,e);var r=t.prototype;return r.registerListeners=function(){var e=this.hls;e.on(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.on(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.MANIFEST_LOADED,this.onManifestLoaded,this),e.on(b.ERROR,this.onError,this)},r.unregisterListeners=function(){var e=this.hls;e.off(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.off(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.MANIFEST_LOADED,this.onManifestLoaded,this),e.off(b.ERROR,this.onError,this)},r.doTick=function(){this.onTickEnd()},r.onTickEnd=function(){},r.startLoad=function(e){},r.stopLoad=function(){if(this.state!==Ei.STOPPED){this.fragmentLoader.abort(),this.keyLoader.abort(this.playlistType);var e=this.fragCurrent;null!=e&&e.loader&&(e.abortRequests(),this.fragmentTracker.removeFragment(e)),this.resetTransmuxer(),this.fragCurrent=null,this.fragPrevious=null,this.clearInterval(),this.clearNextTick(),this.state=Ei.STOPPED}},r.pauseBuffering=function(){this.buffering=!1},r.resumeBuffering=function(){this.buffering=!0},r._streamEnded=function(e,t){if(t.live||!this.media)return!1;var r=e.end||0,i=this.config.timelineOffset||0;if(r<=i)return!1;var n=e.buffered;this.config.maxBufferHole&&n&&n.length>1&&(e=ir.bufferedInfo(n,e.start,0));var a=e.nextStart;if(a&&a>i&&a0&&null!=a&&a.key&&a.iv&&vr(a.method)){var s=self.performance.now();return r.decrypter.decrypt(new Uint8Array(n),a.key.buffer,a.iv.buffer,mr(a.method)).catch((function(e){throw t.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.FRAG_DECRYPT_ERROR,fatal:!1,error:e,reason:e.message,frag:i}),e})).then((function(n){var a=self.performance.now();return t.trigger(b.FRAG_DECRYPTED,{frag:i,payload:n,stats:{tstart:s,tdecrypt:a}}),e.payload=n,r.completeInitSegmentLoad(e)}))}return r.completeInitSegmentLoad(e)})).catch((function(t){r.state!==Ei.STOPPED&&r.state!==Ei.ERROR&&(r.warn(t),r.resetFragmentLoading(e))}))},r.completeInitSegmentLoad=function(e){if(!this.levels)throw new Error("init load aborted, missing levels");var t=e.frag.stats;this.state!==Ei.STOPPED&&(this.state=Ei.IDLE),e.frag.data=new Uint8Array(e.payload),t.parsing.start=t.buffering.start=self.performance.now(),t.parsing.end=t.buffering.end=self.performance.now(),this.tick()},r.fragContextChanged=function(e){var t=this.fragCurrent;return!e||!t||e.sn!==t.sn||e.level!==t.level},r.fragBufferedComplete=function(e,t){var r=this.mediaBuffer?this.mediaBuffer:this.media;if(this.log("Buffered "+e.type+" sn: "+e.sn+(t?" part: "+t.index:"")+" of "+this.fragInfo(e,!1,t)+" > buffer:"+(r?yi(ir.getBuffered(r)):"(detached)")+")"),ee(e)){var i;if(e.type!==x){var n=e.elementaryStreams;if(!Object.keys(n).some((function(e){return!!n[e]})))return void(this.state=Ei.IDLE)}var a=null==(i=this.levels)?void 0:i[e.level];null!=a&&a.fragmentError&&(this.log("Resetting level fragment error count of "+a.fragmentError+" on frag buffered"),a.fragmentError=0)}this.state=Ei.IDLE},r._handleFragmentLoadComplete=function(e){var t=this.transmuxer;if(t){var r=e.frag,i=e.part,n=e.partsLoaded,a=!n||0===n.length||n.some((function(e){return!e})),s=new tr(r.level,r.sn,r.stats.chunkCount+1,0,i?i.index:-1,!a);t.flush(s)}},r._handleFragmentLoadProgress=function(e){},r._doFragLoad=function(e,t,r,i){var n,a=this;void 0===r&&(r=null),this.fragCurrent=e;var s=null==t?void 0:t.details;if(!this.levels||!s)throw new Error("frag load aborted, missing level"+(s?"":" detail")+"s");var o=null;!e.encrypted||null!=(n=e.decryptdata)&&n.key?e.encrypted||(o=this.keyLoader.loadClear(e,s.encryptedFragments))&&this.log("[eme] blocking frag load until media-keys acquired"):(this.log("Loading key for "+e.sn+" of ["+s.startSN+"-"+s.endSN+"], "+this.playlistLabel()+" "+e.level),this.state=Ei.KEY_LOADING,this.fragCurrent=e,o=this.keyLoader.load(e).then((function(e){if(!a.fragContextChanged(e.frag))return a.hls.trigger(b.KEY_LOADED,e),a.state===Ei.KEY_LOADING&&(a.state=Ei.IDLE),e})),this.hls.trigger(b.KEY_LOADING,{frag:e}),null===this.fragCurrent&&(o=Promise.reject(new Error("frag load aborted, context changed in KEY_LOADING"))));var l=this.fragPrevious;if(ee(e)&&(!l||e.sn!==l.sn)){var u=this.shouldLoadParts(t.details,e.end);u!==this.loadingParts&&(this.log("LL-Part loading "+(u?"ON":"OFF")+" loading sn "+(null==l?void 0:l.sn)+"->"+e.sn),this.loadingParts=u)}if(r=Math.max(e.start,r||0),this.loadingParts&&ee(e)){var d=s.partList;if(d&&i){r>e.end&&s.fragmentHint&&(e=s.fragmentHint);var h=this.getNextPart(d,e,r);if(h>-1){var f,c=d[h];return e=this.fragCurrent=c.fragment,this.log("Loading "+e.type+" sn: "+e.sn+" part: "+c.index+" ("+h+"/"+(d.length-1)+") of "+this.fragInfo(e,!1,c)+") cc: "+e.cc+" ["+s.startSN+"-"+s.endSN+"], target: "+parseFloat(r.toFixed(3))),this.nextLoadPosition=c.start+c.duration,this.state=Ei.FRAG_LOADING,f=o?o.then((function(r){return!r||a.fragContextChanged(r.frag)?null:a.doFragPartsLoad(e,c,t,i)})).catch((function(e){return a.handleFragLoadError(e)})):this.doFragPartsLoad(e,c,t,i).catch((function(e){return a.handleFragLoadError(e)})),this.hls.trigger(b.FRAG_LOADING,{frag:e,part:c,targetBufferTime:r}),null===this.fragCurrent?Promise.reject(new Error("frag load aborted, context changed in FRAG_LOADING parts")):f}if(!e.url||this.loadedEndOfParts(d,r))return Promise.resolve(null)}}if(ee(e)&&this.loadingParts)this.log("LL-Part loading OFF after next part miss @"+r.toFixed(2)),this.loadingParts=!1;else if(!e.url)return Promise.resolve(null);this.log("Loading "+e.type+" sn: "+e.sn+" of "+this.fragInfo(e,!1)+") cc: "+e.cc+" "+(s?"["+s.startSN+"-"+s.endSN+"]":"")+", target: "+parseFloat(r.toFixed(3))),A(e.sn)&&!this.bitrateTest&&(this.nextLoadPosition=e.start+e.duration),this.state=Ei.FRAG_LOADING;var g,v=this.config.progressive;return g=v&&o?o.then((function(t){return!t||a.fragContextChanged(null==t?void 0:t.frag)?null:a.fragmentLoader.load(e,i)})).catch((function(e){return a.handleFragLoadError(e)})):Promise.all([this.fragmentLoader.load(e,v?i:void 0),o]).then((function(e){var t=e[0];return!v&&t&&i&&i(t),t})).catch((function(e){return a.handleFragLoadError(e)})),this.hls.trigger(b.FRAG_LOADING,{frag:e,targetBufferTime:r}),null===this.fragCurrent?Promise.reject(new Error("frag load aborted, context changed in FRAG_LOADING")):g},r.doFragPartsLoad=function(e,t,r,i){var n=this;return new Promise((function(a,s){var o,l=[],u=null==(o=r.details)?void 0:o.partList,d=function(t){n.fragmentLoader.loadPart(e,t,i).then((function(i){l[t.index]=i;var s=i.part;n.hls.trigger(b.FRAG_LOADED,i);var o=di(r.details,e.sn,t.index+1)||hi(u,e.sn,t.index+1);if(!o)return a({frag:e,part:s,partsLoaded:l});d(o)})).catch(s)};d(t)}))},r.handleFragLoadError=function(e){if("data"in e){var t=e.data;e.data&&t.details===k.INTERNAL_ABORTED?this.handleFragLoadAborted(t.frag,t.part):this.hls.trigger(b.ERROR,t)}else this.hls.trigger(b.ERROR,{type:I.OTHER_ERROR,details:k.INTERNAL_EXCEPTION,err:e,error:e,fatal:!0});return null},r._handleTransmuxerFlush=function(e){var t=this.getCurrentContext(e);if(t&&this.state===Ei.PARSING){var r=t.frag,i=t.part,n=t.level,a=self.performance.now();r.stats.parsing.end=a,i&&(i.stats.parsing.end=a);var s=this.getLevelDetails(),o=s&&r.sn>s.endSN||this.shouldLoadParts(s,r.end);o!==this.loadingParts&&(this.log("LL-Part loading "+(o?"ON":"OFF")+" after parsing segment ending @"+r.end.toFixed(2)),this.loadingParts=o),this.updateLevelTiming(r,i,n,e.partial)}else this.fragCurrent||this.state===Ei.STOPPED||this.state===Ei.ERROR||(this.state=Ei.IDLE)},r.shouldLoadParts=function(e,t){if(this.config.lowLatencyMode){if(!e)return this.loadingParts;if(null!=e&&e.partList){var r,i,n=e.partList[0];if(t>=n.end+((null==(r=e.fragmentHint)?void 0:r.duration)||0)&&(this.hls.hasEnoughToStart?(null==(i=this.media)?void 0:i.currentTime)||this.lastCurrentTime:this.getLoadPosition())>n.start-n.fragment.duration)return!0}}return!1},r.getCurrentContext=function(e){var t=this.levels,r=this.fragCurrent,i=e.level,n=e.sn,a=e.part;if(null==t||!t[i])return this.warn("Levels object was unset while buffering fragment "+n+" of "+this.playlistLabel()+" "+i+". The current chunk will not be buffered."),null;var s=t[i],o=s.details,l=a>-1?di(o,n,a):null,u=l?l.fragment:ui(o,n,r);return u?(r&&r!==u&&(u.stats=r.stats),{frag:u,part:l,level:s}):null},r.bufferFragmentData=function(e,t,r,i,n){var a;if(e&&this.state===Ei.PARSING){var s=e.data1,o=e.data2,l=s;if(s&&o&&(l=Se(s,o)),null!=(a=l)&&a.length){var u=this.initPTS[t.cc],d=u?-u.baseTime/u.timescale:void 0,h={type:e.type,frag:t,part:r,chunkMeta:i,offset:d,parent:t.type,data:l};if(this.hls.trigger(b.BUFFER_APPENDING,h),e.dropped&&e.independent&&!r){if(n)return;this.flushBufferGap(t)}}}},r.flushBufferGap=function(e){var t=this.media;if(t)if(ir.isBuffered(t,t.currentTime)){var r=t.currentTime,i=ir.bufferInfo(t,r,0),n=e.duration,a=Math.min(2*this.config.maxFragLookUpTolerance,.25*n),s=Math.max(Math.min(e.start-a,i.end-a),r+a);e.start-s>a&&this.flushMainBuffer(s,e.start)}else this.flushMainBuffer(0,e.start)},r.getFwdBufferInfo=function(e,t){var r,i=this.getLoadPosition();if(!A(i))return null;var n=this.lastCurrentTime>i||null!=(r=this.media)&&r.paused?0:this.config.maxBufferHole;return this.getFwdBufferInfoAtPos(e,i,t,n)},r.getFwdBufferInfoAtPos=function(e,t,r,i){var n=ir.bufferInfo(e,t,i);if(0===n.len&&void 0!==n.nextStart){var a=this.fragmentTracker.getBufferedFrag(t,r);if(a&&(n.nextStart<=a.end||a.gap)){var s=Math.max(Math.min(n.nextStart,a.end)-t,i);return ir.bufferInfo(e,t,s)}}return n},r.getMaxBufferLength=function(e){var t,r=this.config;return t=e?Math.max(8*r.maxBufferSize/e,r.maxBufferLength):r.maxBufferLength,Math.min(t,r.maxMaxBufferLength)},r.reduceMaxBufferLength=function(e,t){var r=this.config,i=Math.max(Math.min(e-t,r.maxBufferLength),t),n=Math.max(e-3*t,r.maxMaxBufferLength/2,i);return n>=i&&(r.maxMaxBufferLength=n,this.warn("Reduce max buffer length to "+n+"s"),!0)},r.getAppendedFrag=function(e,t){var r;void 0===t&&(t=w);var i=null==(r=this.fragmentTracker)?void 0:r.getAppendedFrag(e,t);return i&&"fragment"in i?i.fragment:i},r.getNextFragment=function(e,t){var r=t.fragments,i=r.length;if(!i)return null;var n=this.config,a=r[0].start,s=n.lowLatencyMode&&!!t.partList,o=null;if(t.live){var l=n.initialLiveManifestSize;if(i=a?d:h)||o.start:e;this.log("Setting startPosition to "+f+" to match start frag at live edge. mainStart: "+d+" liveSyncPosition: "+h+" frag.start: "+(null==(u=o)?void 0:u.start)),this.startPosition=this.nextLoadPosition=f}}else e<=a&&(o=r[0]);if(!o){var c=this.loadingParts?t.partEnd:t.fragmentEnd;o=this.getFragmentAtPosition(e,c,t)}var g=this.filterReplacedPrimary(o,t);if(!g&&o){var v=o.sn-t.startSN;g=this.filterReplacedPrimary(r[v+1]||null,t)}return this.mapToInitFragWhenRequired(g)},r.isLoopLoading=function(e,t){var r=this.fragmentTracker.getState(e);return(r===Ut||r===Nt&&!!e.gap)&&this.nextLoadPosition>t},r.getNextFragmentLoopLoading=function(e,t,r,i,n){var a=null;if(e.gap&&(a=this.getNextFragment(this.nextLoadPosition,t))&&!a.gap&&r.nextStart){var s=this.getFwdBufferInfoAtPos(this.mediaBuffer?this.mediaBuffer:this.media,r.nextStart,i,0);if(null!==s&&r.len+s.len>=n){var o=a.sn;return this.loopSn!==o&&(this.log('buffer full after gaps in "'+i+'" playlist starting at sn: '+o),this.loopSn=o),null}}return this.loopSn=void 0,a},r.filterReplacedPrimary=function(e,t){if(!e)return e;if(Si(this.hls.config)&&e.type!==x){var r=this.hls.interstitialsManager,i=null==r?void 0:r.bufferingItem;if(i){var n=i.event;if(n){if(n.appendInPlace||Math.abs(e.start-i.start)>1||0===i.start)return null}else{if(e.end<=i.start&&!1===(null==t?void 0:t.live))return null;if(e.start>i.end&&i.nextEvent&&(i.nextEvent.appendInPlace||e.start-i.end>1))return null}}var a=null==r?void 0:r.playerQueue;if(a)for(var s=a.length;s--;){var o=a[s].interstitial;if(o.appendInPlace&&e.start>=o.startTime&&e.end<=o.resumeTime)return null}}return e},r.mapToInitFragWhenRequired=function(e){return null==e||!e.initSegment||null!=e&&e.initSegment.data||this.bitrateTest?e:e.initSegment},r.getNextPart=function(e,t,r){for(var i=-1,n=!1,a=!0,s=0,o=e.length;s-1&&rr.start&&r.loaded},r.getInitialLiveFragment=function(e){var t=e.fragments,r=this.fragPrevious,i=null;if(r){if(e.hasProgramDateTime&&(this.log("Live playlist, switching playlist, load frag with same PDT: "+r.programDateTime),i=function(e,t,r){if(null===t||!Array.isArray(e)||!e.length||!A(t))return null;if(t<(e[0].programDateTime||0))return null;if(t>=(e[e.length-1].endProgramDateTime||0))return null;for(var i=0;i=e.startSN&&n<=e.endSN){var a=t[n-e.startSN];r.cc===a.cc&&(i=a,this.log("Live playlist, switching playlist, load frag with next SN: "+i.sn))}i||(i=Tt(e,r.cc,r.end))&&this.log("Live playlist, switching playlist, load frag with same CC: "+i.sn)}}else{var s=this.hls.liveSyncPosition;null!==s&&(i=this.getFragmentAtPosition(s,this.bitrateTest?e.fragmentEnd:e.edge,e))}return i},r.getFragmentAtPosition=function(e,t,r){var i,n,a=this.config,s=this.fragPrevious,o=r.fragments,l=r.endSN,u=r.fragmentHint,d=a.maxFragLookUpTolerance,h=r.partList,f=!!(this.loadingParts&&null!=h&&h.length&&u);if(f&&u&&!this.bitrateTest&&h[h.length-1].fragment.sn===u.sn&&(o=o.concat(u),l=u.sn),i=et-d||null!=(n=this.media)&&n.paused||!this.startFragRequested?0:d):o[o.length-1]){var c=i.sn-r.startSN,g=this.fragmentTracker.getState(i);if((g===Ut||g===Nt&&i.gap)&&(s=i),s&&i.sn===s.sn&&(!f||h[0].fragment.sn>i.sn||!r.live&&!f)&&s&&i.level===s.level){var v=o[c+1];i=i.sn"+e.startSN+" fragments: "+i),o}return n},r.waitForCdnTuneIn=function(e){return e.live&&e.canBlockReload&&e.partTarget&&e.tuneInGoal>Math.max(e.partHoldBack,3*e.partTarget)},r.setStartPosition=function(e,t){var r=this.startPosition;r=0&&(r=this.nextLoadPosition),r},r.handleFragLoadAborted=function(e,t){this.transmuxer&&e.type===this.playlistType&&ee(e)&&e.stats.aborted&&(this.log("Fragment "+e.sn+(t?" part "+t.index:"")+" of "+this.playlistLabel()+" "+e.level+" was aborted"),this.resetFragmentLoading(e))},r.resetFragmentLoading=function(e){this.fragCurrent&&(this.fragContextChanged(e)||this.state===Ei.FRAG_LOADING_WAITING_RETRY)||(this.state=Ei.IDLE)},r.onFragmentOrKeyLoadError=function(e,t){if(t.chunkMeta&&!t.frag){var r=this.getCurrentContext(t.chunkMeta);r&&(t.frag=r.frag)}var i=t.frag;if(i&&i.type===e&&this.levels)if(this.fragContextChanged(i)){var n;this.warn("Frag load error must match current frag to retry "+i.url+" > "+(null==(n=this.fragCurrent)?void 0:n.url))}else{var a=t.details===k.FRAG_GAP;a&&this.fragmentTracker.fragBuffered(i,!0);var s=t.errorAction,o=s||{},l=o.action,u=o.flags,d=o.retryCount,h=void 0===d?0:d,f=o.retryConfig,c=!!s&&!!f,g=c&&l===_t,v=c&&!s.resolved&&u===Ct;if(!g&&v&&ee(i)&&!i.endList)this.resetFragmentErrors(e),this.treatAsGap(i),s.resolved=!0;else if((g||v)&&h.5;n&&this.reduceMaxBufferLength(i.len,(null==t?void 0:t.duration)||10);var a=!n;return a&&this.warn("Buffer full error while media.currentTime is not buffered, flush "+r+" buffer"),t&&(this.fragmentTracker.removeFragment(t),this.nextLoadPosition=t.start),this.resetLoadingState(),a}return!1},r.resetFragmentErrors=function(e){e===O&&(this.fragCurrent=null),this.hls.hasEnoughToStart||(this.startFragRequested=!1),this.state!==Ei.STOPPED&&(this.state=Ei.IDLE)},r.afterBufferFlushed=function(e,t,r){if(e){var i=ir.getBuffered(e);this.fragmentTracker.detectEvictedFragments(t,i,r),this.state===Ei.ENDED&&this.resetLoadingState()}},r.resetLoadingState=function(){this.log("Reset loading state"),this.fragCurrent=null,this.fragPrevious=null,this.state!==Ei.STOPPED&&(this.state=Ei.IDLE)},r.resetStartWhenNotLoaded=function(e){if(!this.hls.hasEnoughToStart){this.startFragRequested=!1;var t=e?e.details:null;null!=t&&t.live?(this.log("resetting startPosition for live start"),this.startPosition=-1,this.setStartPosition(t,t.fragmentStart),this.resetLoadingState()):this.nextLoadPosition=this.startPosition}},r.resetWhenMissingContext=function(e){this.warn("The loading context changed while buffering fragment "+e.sn+" of "+this.playlistLabel()+" "+e.level+". This chunk will not be buffered."),this.removeUnbufferedFrags(),this.resetStartWhenNotLoaded(this.levelLastLoaded),this.resetLoadingState()},r.removeUnbufferedFrags=function(e){void 0===e&&(e=0),this.fragmentTracker.removeFragmentsInRange(e,1/0,this.playlistType,!1,!0)},r.updateLevelTiming=function(e,t,r,i){var n=this,a=r.details;if(a){var s;if(!Object.keys(e.elementaryStreams).reduce((function(t,s){var o=e.elementaryStreams[s];if(o){var l=o.endPTS-o.startPTS;if(l<=0)return n.warn("Could not parse fragment "+e.sn+" "+s+" duration reliably ("+l+")"),t||!1;var u=i?0:ii(a,e,o.startPTS,o.endPTS,o.startDTS,o.endDTS);return n.hls.trigger(b.LEVEL_PTS_UPDATED,{details:a,level:r,drift:u,type:s,frag:e,start:o.startPTS,end:o.endPTS}),!0}return t}),!1)&&(0===r.fragmentError&&this.treatAsGap(e,r),null===(null==(s=this.transmuxer)?void 0:s.error))){var o=new Error("Found no media in fragment "+e.sn+" of "+this.playlistLabel()+" "+e.level+" resetting transmuxer to fallback to playlist timing");if(this.warn(o.message),this.hls.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.FRAG_PARSING_ERROR,fatal:!1,error:o,frag:e,reason:"Found no media in msn "+e.sn+" of "+this.playlistLabel()+' "'+r.url+'"'}),!this.hls)return;this.resetTransmuxer()}this.state=Ei.PARSED,this.log("Parsed "+e.type+" sn: "+e.sn+(t?" part: "+t.index:"")+" of "+this.fragInfo(e,!1,t)+")"),this.hls.trigger(b.FRAG_PARSED,{frag:e,part:t})}else this.warn("level.details undefined")},r.playlistLabel=function(){return this.playlistType===w?"level":"track"},r.fragInfo=function(e,t,r){var i,n;return void 0===t&&(t=!0),this.playlistLabel()+" "+e.level+" ("+(r?"part":"frag")+":["+(null!=(i=t&&!r?e.startPTS:(r||e).start)?i:NaN).toFixed(3)+"-"+(null!=(n=t&&!r?e.endPTS:(r||e).end)?n:NaN).toFixed(3)+"]"+(r&&"main"===e.type?"INDEPENDENT="+(r.independent?"YES":"NO"):"")},r.treatAsGap=function(e,t){t&&t.fragmentError++,e.gap=!0,this.fragmentTracker.removeFragment(e),this.fragmentTracker.fragBuffered(e,!0)},r.resetTransmuxer=function(){var e;null==(e=this.transmuxer)||e.reset()},r.recoverWorkerError=function(e){"demuxerWorker"===e.event&&(this.fragmentTracker.removeAllFragments(),this.transmuxer&&(this.transmuxer.destroy(),this.transmuxer=null),this.resetStartWhenNotLoaded(this.levelLastLoaded),this.resetLoadingState())},i(t,[{key:"startPositionValue",get:function(){var e=this.nextLoadPosition,t=this.startPosition;return-1===t&&e?e:t}},{key:"bufferingEnabled",get:function(){return this.buffering}},{key:"inFlightFrag",get:function(){return{frag:this.fragCurrent,state:this.state}}},{key:"timelineOffset",get:function(){var e,t=this.config.timelineOffset;return t?(null==(e=this.getLevelDetails())?void 0:e.appliedTimelineOffset)||t:0}},{key:"primaryPrefetch",get:function(){var e,t;return!(!Si(this.hls.config)||!(null==(e=this.hls.interstitialsManager)||null==(t=e.playingItem)?void 0:t.event))}},{key:"state",get:function(){return this._state},set:function(e){var t=this._state;t!==e&&(this._state=e,this.log(t+"->"+e))}}])}(er);function Si(e){return!!e.interstitialsController&&!1!==e.enableInterstitialPlayback}var Ai=function(){function e(){this.chunks=[],this.dataLength=0}var t=e.prototype;return t.push=function(e){this.chunks.push(e),this.dataLength+=e.length},t.flush=function(){var e,t=this.chunks,r=this.dataLength;return t.length?(e=1===t.length?t[0]:function(e,t){for(var r=new Uint8Array(t),i=0,n=0;n0)return e.subarray(r,r+i)}function bi(e,t){return 255===e[t]&&240==(246&e[t+1])}function Di(e,t){return 1&e[t+1]?7:9}function _i(e,t){return(3&e[t+3])<<11|e[t+4]<<3|(224&e[t+5])>>>5}function Pi(e,t){return t+1=e.length)return!1;var i=_i(e,t);if(i<=r)return!1;var n=t+i;return n===e.length||Pi(e,n)}return!1}function wi(e,t,r,i,n){if(!e.samplerate){var s=function(e,t,r,i){var n=t[r+2],a=n>>2&15;if(!(a>12)){var s=1+(n>>6&3),o=t[r+3]>>6&3|(1&n)<<2,l="mp4a.40."+s,u=[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350][a],d=a;5!==s&&29!==s||(d-=3);var h=[s<<3|(14&d)>>1,(1&d)<<7|o<<3];return Y.log("manifest codec:"+i+", parsed codec:"+l+", channels:"+o+", rate:"+u+" (ADTS object type:"+s+" sampling index:"+a+")"),{config:h,samplerate:u,channelCount:o,codec:l,parsedCodec:l,manifestCodec:i}}var f=new Error("invalid ADTS sampling index:"+a);e.emit(b.ERROR,b.ERROR,{type:I.MEDIA_ERROR,details:k.FRAG_PARSING_ERROR,fatal:!0,error:f,reason:f.message})}(t,r,i,n);if(!s)return;a(e,s)}}function Oi(e){return 9216e4/e}function xi(e,t,r,i,n){var a,s=i+n*Oi(e.samplerate),o=function(e,t){var r=Di(e,t);if(t+r<=e.length){var i=_i(e,t)-r;if(i>0)return{headerLength:r,frameLength:i}}}(t,r);if(o){var l=o.frameLength,u=o.headerLength,d=u+l,h=Math.max(0,r+d-t.length);h?(a=new Uint8Array(d-u)).set(t.subarray(r+u,t.length),0):a=t.subarray(r+u,r+d);var f={unit:a,pts:s};return h||e.samples.push(f),{sample:f,length:d,missing:h}}var c=t.length-r;return(a=new Uint8Array(c)).set(t.subarray(r,t.length),0),{sample:{unit:a,pts:s},length:c,missing:-1}}function Mi(e,t){return Ri(e,t)&&Ii(e,t+6)+10<=e.length-t}function Fi(e,t,r){return void 0===t&&(t=0),void 0===r&&(r=1/0),function(e,t,r,i){var n=function(e){return e instanceof ArrayBuffer?e:e.buffer}(e),a=1;"BYTES_PER_ELEMENT"in i&&(a=i.BYTES_PER_ELEMENT);var s,o=(s=e)&&s.buffer instanceof ArrayBuffer&&void 0!==s.byteLength&&void 0!==s.byteOffset?e.byteOffset:0,l=(o+e.byteLength)/a,u=(o+t)/a,d=Math.floor(Math.max(0,Math.min(u,l))),h=Math.floor(Math.min(d+Math.max(r,0),l));return new i(n,d,h-d)}(e,t,r,Uint8Array)}function Ni(e){var t={key:e.type,description:"",data:"",mimeType:null,pictureType:null};if(!(e.size<2))if(3===e.data[0]){var r=e.data.subarray(1).indexOf(0);if(-1!==r){var i=q(Fi(e.data,1,r)),n=e.data[2+r],a=e.data.subarray(3+r).indexOf(0);if(-1!==a){var s,o=q(Fi(e.data,3+r,a));return s="--\x3e"===i?q(Fi(e.data,4+r+a)):function(e){return e instanceof ArrayBuffer?e:0==e.byteOffset&&e.byteLength==e.buffer.byteLength?e.buffer:new Uint8Array(e).buffer}(e.data.subarray(4+r+a)),t.mimeType=i,t.pictureType=n,t.description=o,t.data=s,t}}}else console.log("Ignore frame with unrecognized character encoding")}function Ui(e){return"PRIV"===e.type?function(e){if(!(e.size<2)){var t=q(e.data,!0),r=new Uint8Array(e.data.subarray(t.length+1));return{key:e.type,info:t,data:r.buffer}}}(e):"W"===e.type[0]?function(e){if("WXXX"===e.type){if(e.size<2)return;var t=1,r=q(e.data.subarray(t),!0);t+=r.length+1;var i=q(e.data.subarray(t));return{key:e.type,info:r,data:i}}var n=q(e.data);return{key:e.type,info:"",data:n}}(e):"APIC"===e.type?Ni(e):function(e){if(!(e.size<2)){if("TXXX"===e.type){var t=1,r=q(e.data.subarray(t),!0);t+=r.length+1;var i=q(e.data.subarray(t));return{key:e.type,info:r,data:i}}var n=q(e.data.subarray(1));return{key:e.type,info:"",data:n}}}(e)}function Bi(e){var t=String.fromCharCode(e[0],e[1],e[2],e[3]),r=Ii(e,4);return{type:t,size:r,data:e.subarray(10,10+r)}}var Gi=10,Ki=10;function Vi(e){for(var t=0,r=[];Ri(e,t);){var i=Ii(e,t+6);e[t+5]>>6&1&&(t+=Gi);for(var n=(t+=Gi)+i;t+Ki0&&s.samples.push({pts:this.lastPTS,dts:this.lastPTS,data:i,type:ji.audioId3,duration:Number.POSITIVE_INFINITY});nt.length)){var a=rn(t,r);if(a&&r+a.frameLength<=t.length){var s=i+n*(9e4*a.samplesPerFrame/a.sampleRate),o={unit:t.subarray(r,r+a.frameLength),pts:s,dts:s};return e.config=[],e.channelCount=a.channelCount,e.samplerate=a.sampleRate,e.samples.push(o),{sample:o,length:a.frameLength,missing:0}}}}function rn(e,t){var r=e[t+1]>>3&3,i=e[t+1]>>1&3,n=e[t+2]>>4&15,a=e[t+2]>>2&3;if(1!==r&&0!==n&&15!==n&&3!==a){var s=e[t+2]>>1&1,o=e[t+3]>>6,l=1e3*$i[14*(3===r?3-i:3===i?3:4)+n-1],u=Ji[3*(3===r?0:2===r?1:2)+a],d=3===o?1:2,h=Zi[r][i],f=en[i],c=8*h*f,g=Math.floor(h*l/u+s)*f;if(null===zi){var v=(navigator.userAgent||"").match(/Chrome\/(\d+)/i);zi=v?parseInt(v[1]):0}return!!zi&&zi<=87&&2===i&&l>=224e3&&0===o&&(e[t+3]=128|e[t+3]),{sampleRate:u,channelCount:d,frameLength:g,samplesPerFrame:c}}}function nn(e,t){return 255===e[t]&&224==(224&e[t+1])&&0!=(6&e[t+1])}function an(e,t){return t+10;){s[0]=e[t];var o=Math.min(i,8),l=8-o;a[0]=4278190080>>>24+l<>l,r=r?r<t.length)return-1;if(11!==t[r]||119!==t[r+1])return-1;var a=t[r+4]>>6;if(a>=3)return-1;var s=[48e3,44100,32e3][a],o=63&t[r+4],l=2*[64,69,96,64,70,96,80,87,120,80,88,120,96,104,144,96,105,144,112,121,168,112,122,168,128,139,192,128,140,192,160,174,240,160,175,240,192,208,288,192,209,288,224,243,336,224,244,336,256,278,384,256,279,384,320,348,480,320,349,480,384,417,576,384,418,576,448,487,672,448,488,672,512,557,768,512,558,768,640,696,960,640,697,960,768,835,1152,768,836,1152,896,975,1344,896,976,1344,1024,1114,1536,1024,1115,1536,1152,1253,1728,1152,1254,1728,1280,1393,1920,1280,1394,1920][3*o+a];if(r+l>t.length)return-1;var u=t[r+6]>>5,d=0;2===u?d+=2:(1&u&&1!==u&&(d+=2),4&u&&(d+=2));var h=(t[r+6]<<8|t[r+7])>>12-d&1,f=[2,1,2,3,3,4,4,5][u]+h,c=t[r+5]>>3,g=7&t[r+5],v=new Uint8Array([a<<6|c<<1|g>>2,(3&g)<<6|u<<3|h<<2|o>>4,o<<4&224]),m=i+n*(1536/s*9e4),p=t.subarray(r,r+l);return e.config=v,e.channelCount=f,e.samplerate=s,e.samples.push({unit:p,pts:m}),l}var hn=function(e){function t(){return e.apply(this,arguments)||this}o(t,e);var r=t.prototype;return r.resetInitSegment=function(t,r,i,n){e.prototype.resetInitSegment.call(this,t,r,i,n),this._audioTrack={container:"audio/mpeg",type:"audio",id:2,pid:-1,sequenceNumber:0,segmentCodec:"mp3",samples:[],manifestCodec:r,duration:n,inputTimeScale:9e4,dropped:0}},t.probe=function(e){if(!e)return!1;var t=ki(e,0),r=(null==t?void 0:t.length)||0;if(t&&11===e[r]&&119===e[r+1]&&void 0!==Wi(t)&&ln(e,r)<=16)return!1;for(var i=e.length;r8&&109===e[r+4]&&111===e[r+5]&&111===e[r+6]&&102===e[r+7])return!0;r=i>1?r+i:t}return!1}(e)},t.demux=function(e,t){this.timeOffset=t;var r=e,i=this.videoTrack,n=this.txtTrack;if(this.config.progressive){this.remainderData&&(r=Se(this.remainderData,e));var a=function(e){var t={valid:null,remainder:null},r=fe(e,["moof"]);if(r.length<2)return t.remainder=e,t;var i=r[r.length-1];return t.valid=e.slice(0,i.byteOffset-8),t.remainder=e.slice(i.byteOffset-8),t}(r);this.remainderData=a.remainder,i.samples=a.valid||new Uint8Array}else i.samples=r;var s=this.extractID3Track(i,t);return n.samples=Ae(t,i),{videoTrack:i,audioTrack:this.audioTrack,id3Track:s,textTrack:this.txtTrack}},t.flush=function(){var e=this.timeOffset,t=this.videoTrack,r=this.txtTrack;t.samples=this.remainderData||new Uint8Array,this.remainderData=null;var i=this.extractID3Track(t,this.timeOffset);return r.samples=Ae(e,t),{videoTrack:t,audioTrack:qi(),id3Track:i,textTrack:qi()}},t.extractID3Track=function(e,t){var r=this,i=this.id3Track;if(e.samples.length){var n=fe(e.samples,["emsg"]);n&&n.forEach((function(e){var n=function(e){var t=e[0],r="",i="",n=0,a=0,s=0,o=0,l=0,u=0;if(0===t){for(;"\0"!==oe(e.subarray(u,u+1));)r+=oe(e.subarray(u,u+1)),u+=1;for(r+=oe(e.subarray(u,u+1)),u+=1;"\0"!==oe(e.subarray(u,u+1));)i+=oe(e.subarray(u,u+1)),u+=1;i+=oe(e.subarray(u,u+1)),u+=1,n=ue(e,12),a=ue(e,16),o=ue(e,20),l=ue(e,24),u=28}else if(1===t){n=ue(e,u+=4);var d=ue(e,u+=4),h=ue(e,u+=4);for(u+=4,s=Math.pow(2,32)*d+h,L(s)||(s=Number.MAX_SAFE_INTEGER,Y.warn("Presentation time exceeds safe integer limit and wrapped to max safe integer in parsing emsg box")),o=ue(e,u),l=ue(e,u+=4),u+=4;"\0"!==oe(e.subarray(u,u+1));)r+=oe(e.subarray(u,u+1)),u+=1;for(r+=oe(e.subarray(u,u+1)),u+=1;"\0"!==oe(e.subarray(u,u+1));)i+=oe(e.subarray(u,u+1)),u+=1;i+=oe(e.subarray(u,u+1)),u+=1}return{schemeIdUri:r,value:i,timeScale:n,presentationTime:s,presentationTimeDelta:a,eventDuration:o,id:l,payload:e.subarray(u,e.byteLength)}}(e);if(fn.test(n.schemeIdUri)){var a=gn(n,t),s=4294967295===n.eventDuration?Number.POSITIVE_INFINITY:n.eventDuration/n.timeScale;s<=.001&&(s=Number.POSITIVE_INFINITY);var o=n.payload;i.samples.push({data:o,len:o.byteLength,dts:a,pts:a,type:ji.emsg,duration:s})}else if(r.config.enableEmsgKLVMetadata&&n.schemeIdUri.startsWith("urn:misb:KLV:bin:1910.1")){var l=gn(n,t);i.samples.push({data:n.payload,len:n.payload.byteLength,dts:l,pts:l,type:ji.misbklv,duration:Number.POSITIVE_INFINITY})}}))}return i},t.demuxSampleAes=function(e,t,r){return Promise.reject(new Error("The MP4 demuxer does not support SAMPLE-AES decryption"))},t.destroy=function(){this.config=null,this.remainderData=null,this.videoTrack=this.audioTrack=this.id3Track=this.txtTrack=void 0},e}();function gn(e,t){return A(e.presentationTime)?e.presentationTime/e.timeScale:t+e.presentationTimeDelta/e.timeScale}var vn=function(){function e(e,t,r){this.keyData=void 0,this.decrypter=void 0,this.keyData=r,this.decrypter=new Xt(t,{removePKCS7Padding:!1})}var t=e.prototype;return t.decryptBuffer=function(e){return this.decrypter.decrypt(e,this.keyData.key.buffer,this.keyData.iv.buffer,Ht)},t.decryptAacSample=function(e,t,r){var i=this,n=e[t].unit;if(!(n.length<=16)){var a=n.subarray(16,n.length-n.length%16),s=a.buffer.slice(a.byteOffset,a.byteOffset+a.length);this.decryptBuffer(s).then((function(a){var s=new Uint8Array(a);n.set(s,16),i.decrypter.isSync()||i.decryptAacSamples(e,t+1,r)}))}},t.decryptAacSamples=function(e,t,r){for(;;t++){if(t>=e.length)return void r();if(!(e[t].unit.length<32||(this.decryptAacSample(e,t,r),this.decrypter.isSync())))return}},t.getAvcEncryptedData=function(e){for(var t=16*Math.floor((e.length-48)/160)+16,r=new Int8Array(t),i=0,n=32;n=e.length)return void i();for(var n=e[t].units;!(r>=n.length);r++){var a=n[r];if(!(a.data.length<=48||1!==a.type&&5!==a.type||(this.decryptAvcSample(e,t,r,i,a),this.decrypter.isSync())))return}}},e}(),mn=function(){function e(){this.VideoSample=null}var t=e.prototype;return t.createVideoSample=function(e,t,r){return{key:e,frame:!1,pts:t,dts:r,units:[],length:0}},t.getLastNalUnit=function(e){var t,r,i=this.VideoSample;if(i&&0!==i.units.length||(i=e[e.length-1]),null!=(t=i)&&t.units){var n=i.units;r=n[n.length-1]}return r},t.pushAccessUnit=function(e,t){if(e.units.length&&e.frame){if(void 0===e.pts){var r=t.samples,i=r.length;if(!i)return void t.dropped++;var n=r[i-1];e.pts=n.pts,e.dts=n.dts}t.samples.push(e)}},t.parseNALu=function(e,t,r){var i,n,a=t.byteLength,s=e.naluState||0,o=s,l=[],u=0,d=-1,h=0;for(-1===s&&(d=0,h=this.getNALuType(t,0),s=0,u=1);u=0){var f={data:t.subarray(d,n),type:h};l.push(f)}else{var c=this.getLastNalUnit(e.samples);c&&(o&&u<=4-o&&c.state&&(c.data=c.data.subarray(0,c.data.byteLength-o)),n>0&&(c.data=Se(c.data,t.subarray(0,n)),c.state=0))}u=0&&s>=0){var g={data:t.subarray(d,a),type:h,state:s};l.push(g)}if(0===l.length){var v=this.getLastNalUnit(e.samples);v&&(v.data=Se(v.data,t))}return e.naluState=s,l},e}(),pn=function(){function e(e){this.data=void 0,this.bytesAvailable=void 0,this.word=void 0,this.bitsAvailable=void 0,this.data=e,this.bytesAvailable=e.byteLength,this.word=0,this.bitsAvailable=0}var t=e.prototype;return t.loadWord=function(){var e=this.data,t=this.bytesAvailable,r=e.byteLength-t,i=new Uint8Array(4),n=Math.min(4,t);if(0===n)throw new Error("no bytes available");i.set(e.subarray(r,r+n)),this.word=new DataView(i.buffer).getUint32(0),this.bitsAvailable=8*n,this.bytesAvailable-=n},t.skipBits=function(e){var t;e=Math.min(e,8*this.bytesAvailable+this.bitsAvailable),this.bitsAvailable>e?(this.word<<=e,this.bitsAvailable-=e):(e-=this.bitsAvailable,e-=(t=e>>3)<<3,this.bytesAvailable-=t,this.loadWord(),this.word<<=e,this.bitsAvailable-=e)},t.readBits=function(e){var t=Math.min(this.bitsAvailable,e),r=this.word>>>32-t;if(e>32&&Y.error("Cannot read more than 32 bits at a time"),this.bitsAvailable-=t,this.bitsAvailable>0)this.word<<=t;else{if(!(this.bytesAvailable>0))throw new Error("no bits available");this.loadWord()}return(t=e-t)>0&&this.bitsAvailable?r<>>e))return this.word<<=e,this.bitsAvailable-=e,e;return this.loadWord(),e+this.skipLZ()},t.skipUEG=function(){this.skipBits(1+this.skipLZ())},t.skipEG=function(){this.skipBits(1+this.skipLZ())},t.readUEG=function(){var e=this.skipLZ();return this.readBits(e+1)-1},t.readEG=function(){var e=this.readUEG();return 1&e?1+e>>>1:-1*(e>>>1)},t.readBoolean=function(){return 1===this.readBits(1)},t.readUByte=function(){return this.readBits(8)},t.readUShort=function(){return this.readBits(16)},t.readUInt=function(){return this.readBits(32)},e}(),yn=function(e){function t(){return e.apply(this,arguments)||this}o(t,e);var r=t.prototype;return r.parsePES=function(e,t,r,i){var n,a=this,s=this.parseNALu(e,r.data,i),o=this.VideoSample,l=!1;r.data=null,o&&s.length&&!e.audFound&&(this.pushAccessUnit(o,e),o=this.VideoSample=this.createVideoSample(!1,r.pts,r.dts)),s.forEach((function(i){var s,u;switch(i.type){case 1:var d=!1;n=!0;var h,f=i.data;if(l&&f.length>4){var c=a.readSliceType(f);2!==c&&4!==c&&7!==c&&9!==c||(d=!0)}d&&null!=(h=o)&&h.frame&&!o.key&&(a.pushAccessUnit(o,e),o=a.VideoSample=null),o||(o=a.VideoSample=a.createVideoSample(!0,r.pts,r.dts)),o.frame=!0,o.key=d;break;case 5:n=!0,null!=(s=o)&&s.frame&&!o.key&&(a.pushAccessUnit(o,e),o=a.VideoSample=null),o||(o=a.VideoSample=a.createVideoSample(!0,r.pts,r.dts)),o.key=!0,o.frame=!0;break;case 6:n=!0,Ie(i.data,1,r.pts,t.samples);break;case 7:var g,v;n=!0,l=!0;var m=i.data,p=a.readSPS(m);if(!e.sps||e.width!==p.width||e.height!==p.height||(null==(g=e.pixelRatio)?void 0:g[0])!==p.pixelRatio[0]||(null==(v=e.pixelRatio)?void 0:v[1])!==p.pixelRatio[1]){e.width=p.width,e.height=p.height,e.pixelRatio=p.pixelRatio,e.sps=[m];for(var y=m.subarray(1,4),E="avc1.",T=0;T<3;T++){var S=y[T].toString(16);S.length<2&&(S="0"+S),E+=S}e.codec=E}break;case 8:n=!0,e.pps=[i.data];break;case 9:n=!0,e.audFound=!0,null!=(u=o)&&u.frame&&(a.pushAccessUnit(o,e),o=null),o||(o=a.VideoSample=a.createVideoSample(!1,r.pts,r.dts));break;case 12:n=!0;break;default:n=!1}o&&n&&o.units.push(i)})),i&&o&&(this.pushAccessUnit(o,e),this.VideoSample=null)},r.getNALuType=function(e,t){return 31&e[t]},r.readSliceType=function(e){var t=new pn(e);return t.readUByte(),t.readUEG(),t.readUEG()},r.skipScalingList=function(e,t){for(var r=8,i=8,n=0;n>>1},r.ebsp2rbsp=function(e){for(var t=new Uint8Array(e.byteLength),r=0,i=0;i=2&&3===e[i]&&0===e[i-1]&&0===e[i-2]||(t[r]=e[i],r++);return new Uint8Array(t.buffer,0,r)},r.pushAccessUnit=function(t,r){e.prototype.pushAccessUnit.call(this,t,r),this.initVPS&&(this.initVPS=null)},r.readVPS=function(e){var t=new pn(e);return t.readUByte(),t.readUByte(),t.readBits(4),t.skipBits(2),t.readBits(6),{numTemporalLayers:t.readBits(3)+1,temporalIdNested:t.readBoolean()}},r.readSPS=function(e){var t=new pn(this.ebsp2rbsp(e));t.readUByte(),t.readUByte(),t.readBits(4);var r=t.readBits(3);t.readBoolean();for(var i=t.readBits(2),n=t.readBoolean(),a=t.readBits(5),s=t.readUByte(),o=t.readUByte(),l=t.readUByte(),u=t.readUByte(),d=t.readUByte(),h=t.readUByte(),f=t.readUByte(),c=t.readUByte(),g=t.readUByte(),v=t.readUByte(),m=t.readUByte(),p=[],y=[],E=0;E0)for(var T=r;T<8;T++)t.readBits(2);for(var S=0;S1&&t.readEG();for(var N=0;N0&&se<16?(ee=[1,12,10,16,40,24,20,32,80,18,15,64,160,4,3,2][se-1],te=[1,11,11,11,33,11,11,11,33,11,11,33,99,3,2,1][se-1]):255===se&&(ee=t.readBits(16),te=t.readBits(16))}if(t.readBoolean()&&t.readBoolean(),t.readBoolean()&&(t.readBits(3),t.readBoolean(),t.readBoolean()&&(t.readUByte(),t.readUByte(),t.readUByte())),t.readBoolean()&&(t.readUEG(),t.readUEG()),t.readBoolean(),t.readBoolean(),t.readBoolean(),(ae=t.readBoolean())&&(k+=t.readUEG(),b+=t.readUEG(),D+=t.readUEG(),_+=t.readUEG()),t.readBoolean()&&(ie=t.readBits(32),ne=t.readBits(32),t.readBoolean()&&t.readUEG(),t.readBoolean())){var oe=t.readBoolean(),le=t.readBoolean(),ue=!1;(oe||le)&&((ue=t.readBoolean())&&(t.readUByte(),t.readBits(5),t.readBoolean(),t.readBits(5)),t.readBits(4),t.readBits(4),ue&&t.readBits(4),t.readBits(5),t.readBits(5),t.readBits(5));for(var de=0;de<=r;de++){var he=!1;(re=t.readBoolean())||t.readBoolean()?t.readEG():he=t.readBoolean();var fe=he?1:t.readUEG()+1;if(oe)for(var ce=0;ce>Ae&1)<<31-Ae)>>>0;var Le=Se.toString(16);return 1===a&&"2"===Le&&(Le="6"),{codecString:"hvc1."+Ee+a+"."+Le+"."+(n?"H":"L")+m+".B0",params:{general_tier_flag:n,general_profile_idc:a,general_profile_space:i,general_profile_compatibility_flags:[s,o,l,u],general_constraint_indicator_flags:[d,h,f,c,g,v],general_level_idc:m,bit_depth:P+8,bit_depth_luma_minus8:P,bit_depth_chroma_minus8:C,min_spatial_segmentation_idc:Z,chroma_format_idc:A,frame_rate:{fixed:re,fps:ne/ie}},width:ve,height:me,pixelRatio:[ee,te]}},r.readPPS=function(e){var t=new pn(this.ebsp2rbsp(e));t.readUByte(),t.readUByte(),t.skipUEG(),t.skipUEG(),t.skipBits(2),t.skipBits(3),t.skipBits(2),t.skipUEG(),t.skipUEG(),t.skipEG(),t.skipBits(2),t.readBoolean()&&t.skipUEG(),t.skipEG(),t.skipEG(),t.skipBits(4);var r=t.readBoolean(),i=t.readBoolean(),n=1;return i&&r?n=0:i?n=3:r&&(n=2),{parallelismType:n}},r.matchSPS=function(e,t){return String.fromCharCode.apply(null,e).substr(3)===String.fromCharCode.apply(null,t).substr(3)},t}(mn),Tn=188,Sn=function(){function e(e,t,r,i){this.logger=void 0,this.observer=void 0,this.config=void 0,this.typeSupported=void 0,this.sampleAes=null,this.pmtParsed=!1,this.audioCodec=void 0,this.videoCodec=void 0,this._pmtId=-1,this._videoTrack=void 0,this._audioTrack=void 0,this._id3Track=void 0,this._txtTrack=void 0,this.aacOverFlow=null,this.remainderData=null,this.videoParser=void 0,this.observer=e,this.config=t,this.typeSupported=r,this.logger=i,this.videoParser=null}e.probe=function(t,r){var i=e.syncOffset(t);return i>0&&r.warn("MPEG2-TS detected but first sync word found @ offset "+i),-1!==i},e.syncOffset=function(e){for(var t=e.length,r=Math.min(940,t-Tn)+1,i=0;i1&&(0===a&&s>2||o+Tn>r))return a}i++}return-1},e.createTrack=function(e,t){return{container:"video"===e||"audio"===e?"video/mp2t":void 0,type:e,id:se[e],pid:-1,inputTimeScale:9e4,sequenceNumber:0,samples:[],dropped:0,duration:"audio"===e?t:void 0}};var t=e.prototype;return t.resetInitSegment=function(t,r,i,n){this.pmtParsed=!1,this._pmtId=-1,this._videoTrack=e.createTrack("video"),this._videoTrack.duration=n,this._audioTrack=e.createTrack("audio",n),this._id3Track=e.createTrack("id3"),this._txtTrack=e.createTrack("text"),this._audioTrack.segmentCodec="aac",this.aacOverFlow=null,this.remainderData=null,this.audioCodec=r,this.videoCodec=i},t.resetTimeStamp=function(){},t.resetContiguity=function(){var e=this._audioTrack,t=this._videoTrack,r=this._id3Track;e&&(e.pesData=null),t&&(t.pesData=null),r&&(r.pesData=null),this.aacOverFlow=null,this.remainderData=null},t.demux=function(t,r,i,n){var a;void 0===i&&(i=!1),void 0===n&&(n=!1),i||(this.sampleAes=null);var s=this._videoTrack,o=this._audioTrack,l=this._id3Track,u=this._txtTrack,d=s.pid,h=s.pesData,f=o.pid,c=l.pid,g=o.pesData,v=l.pesData,m=null,p=this.pmtParsed,y=this._pmtId,E=t.length;if(this.remainderData&&(E=(t=Se(this.remainderData,t)).length,this.remainderData=null),E>4>1){if((I=A+5+t[A+4])===A+Tn)continue}else I=A+4;switch(R){case d:if(L){if(h&&(a=bn(h,this.logger))){if(null===this.videoParser)switch(s.segmentCodec){case"avc":this.videoParser=new yn;break;case"hevc":this.videoParser=new En}null!==this.videoParser&&this.videoParser.parsePES(s,u,a,!1)}h={data:[],size:0}}h&&(h.data.push(t.subarray(I,A+Tn)),h.size+=A+Tn-I);break;case f:if(L){if(g&&(a=bn(g,this.logger)))switch(o.segmentCodec){case"aac":this.parseAACPES(o,a);break;case"mp3":this.parseMPEGPES(o,a);break;case"ac3":this.parseAC3PES(o,a)}g={data:[],size:0}}g&&(g.data.push(t.subarray(I,A+Tn)),g.size+=A+Tn-I);break;case c:L&&(v&&(a=bn(v,this.logger))&&this.parseID3PES(l,a),v={data:[],size:0}),v&&(v.data.push(t.subarray(I,A+Tn)),v.size+=A+Tn-I);break;case 0:L&&(I+=t[I]+1),y=this._pmtId=Ln(t,I);break;case y:L&&(I+=t[I]+1);var k=Rn(t,I,this.typeSupported,i,this.observer,this.logger);(d=k.videoPid)>0&&(s.pid=d,s.segmentCodec=k.segmentVideoCodec),(f=k.audioPid)>0&&(o.pid=f,o.segmentCodec=k.segmentAudioCodec),(c=k.id3Pid)>0&&(l.pid=c),null===m||p||(this.logger.warn("MPEG-TS PMT found at "+A+" after unknown PID '"+m+"'. Backtracking to sync byte @"+T+" to parse all TS packets."),m=null,A=T-188),p=this.pmtParsed=!0;break;case 17:case 8191:break;default:m=R}}else S++;S>0&&In(this.observer,new Error("Found "+S+" TS packet/s that do not start with 0x47"),void 0,this.logger),s.pesData=h,o.pesData=g,l.pesData=v;var b={audioTrack:o,videoTrack:s,id3Track:l,textTrack:u};return n&&this.extractRemainingSamples(b),b},t.flush=function(){var e,t=this.remainderData;return this.remainderData=null,e=t?this.demux(t,-1,!1,!0):{videoTrack:this._videoTrack,audioTrack:this._audioTrack,id3Track:this._id3Track,textTrack:this._txtTrack},this.extractRemainingSamples(e),this.sampleAes?this.decrypt(e,this.sampleAes):e},t.extractRemainingSamples=function(e){var t,r=e.audioTrack,i=e.videoTrack,n=e.id3Track,a=e.textTrack,s=i.pesData,o=r.pesData,l=n.pesData;if(s&&(t=bn(s,this.logger))){if(null===this.videoParser)switch(i.segmentCodec){case"avc":this.videoParser=new yn;break;case"hevc":this.videoParser=new En}null!==this.videoParser&&(this.videoParser.parsePES(i,a,t,!0),i.pesData=null)}else i.pesData=s;if(o&&(t=bn(o,this.logger))){switch(r.segmentCodec){case"aac":this.parseAACPES(r,t);break;case"mp3":this.parseMPEGPES(r,t);break;case"ac3":this.parseAC3PES(r,t)}r.pesData=null}else null!=o&&o.size&&this.logger.log("last AAC PES packet truncated,might overlap between fragments"),r.pesData=o;l&&(t=bn(l,this.logger))?(this.parseID3PES(n,t),n.pesData=null):n.pesData=l},t.demuxSampleAes=function(e,t,r){var i=this.demux(e,r,!0,!this.config.progressive),n=this.sampleAes=new vn(this.observer,this.config,t);return this.decrypt(i,n)},t.decrypt=function(e,t){return new Promise((function(r){var i=e.audioTrack,n=e.videoTrack;i.samples&&"aac"===i.segmentCodec?t.decryptAacSamples(i.samples,0,(function(){n.samples?t.decryptAvcSamples(n.samples,0,0,(function(){r(e)})):r(e)})):n.samples&&t.decryptAvcSamples(n.samples,0,0,(function(){r(e)}))}))},t.destroy=function(){this.observer&&this.observer.removeAllListeners(),this.config=this.logger=this.observer=null,this.aacOverFlow=this.videoParser=this.remainderData=this.sampleAes=null,this._videoTrack=this._audioTrack=this._id3Track=this._txtTrack=void 0},t.parseAACPES=function(e,t){var r,i,n,a=0,s=this.aacOverFlow,o=t.data;if(s){this.aacOverFlow=null;var l=s.missing,u=s.sample.unit.byteLength;if(-1===l)o=Se(s.sample.unit,o);else{var d=u-l;s.sample.unit.set(o.subarray(0,l),d),e.samples.push(s.sample),a=s.missing}}for(r=a,i=o.length;r0;)o+=n;else this.logger.warn("[tsdemuxer]: AC3 PES unknown PTS")},t.parseID3PES=function(e,t){if(void 0!==t.pts){var r=a({},t,{type:this._videoTrack?ji.emsg:ji.audioId3,duration:Number.POSITIVE_INFINITY});e.samples.push(r)}else this.logger.warn("[tsdemuxer]: ID3 PES unknown PTS")},e}();function An(e,t){return((31&e[t+1])<<8)+e[t+2]}function Ln(e,t){return(31&e[t+10])<<8|e[t+11]}function Rn(e,t,r,i,n,a){var s={audioPid:-1,videoPid:-1,id3Pid:-1,segmentVideoCodec:"avc",segmentAudioCodec:"aac"},o=t+3+((15&e[t+1])<<8|e[t+2])-4;for(t+=12+((15&e[t+10])<<8|e[t+11]);t0)for(var d=t+5,h=u;h>2;){106===e[d]&&(!0!==r.ac3?a.log("AC-3 audio found, not supported in this browser for now"):(s.audioPid=l,s.segmentAudioCodec="ac3"));var f=e[d+1]+2;d+=f,h-=f}break;case 194:case 135:return In(n,new Error("Unsupported EC-3 in M2TS found"),void 0,a),s;case 36:-1===s.videoPid&&(s.videoPid=l,s.segmentVideoCodec="hevc",a.log("HEVC in M2TS found"))}t+=u+5}return s}function In(e,t,r,i){i.warn("parsing error: "+t.message),e.emit(b.ERROR,b.ERROR,{type:I.MEDIA_ERROR,details:k.FRAG_PARSING_ERROR,fatal:!1,levelRetry:r,error:t,reason:t.message})}function kn(e,t){t.log(e+" with AES-128-CBC encryption found in unencrypted stream")}function bn(e,t){var r,i,n,a,s,o=0,l=e.data;if(!e||0===e.size)return null;for(;l[0].length<19&&l.length>1;)l[0]=Se(l[0],l[1]),l.splice(1,1);if(1===((r=l[0])[0]<<16)+(r[1]<<8)+r[2]){if((i=(r[4]<<8)+r[5])&&i>e.size-6)return null;var u=r[7];192&u&&(a=536870912*(14&r[9])+4194304*(255&r[10])+16384*(254&r[11])+128*(255&r[12])+(254&r[13])/2,64&u?a-(s=536870912*(14&r[14])+4194304*(255&r[15])+16384*(254&r[16])+128*(255&r[17])+(254&r[18])/2)>54e5&&(t.warn(Math.round((a-s)/9e4)+"s delta between PTS and DTS, align them"),a=s):s=a);var d=(n=r[8])+9;if(e.size<=d)return null;e.size-=d;for(var h=new Uint8Array(e.size),f=0,c=l.length;fg){d-=g;continue}r=r.subarray(d),g-=d,d=0}h.set(r,o),o+=g}return i&&(i-=n+3),{data:h,pts:a,dts:s,len:i}}return null}var Dn=function(){function e(){}return e.getSilentFrame=function(e,t){if("mp4a.40.2"===e){if(1===t)return new Uint8Array([0,200,0,128,35,128]);if(2===t)return new Uint8Array([33,0,73,144,2,25,0,35,128]);if(3===t)return new Uint8Array([0,200,0,128,32,132,1,38,64,8,100,0,142]);if(4===t)return new Uint8Array([0,200,0,128,32,132,1,38,64,8,100,0,128,44,128,8,2,56]);if(5===t)return new Uint8Array([0,200,0,128,32,132,1,38,64,8,100,0,130,48,4,153,0,33,144,2,56]);if(6===t)return new Uint8Array([0,200,0,128,32,132,1,38,64,8,100,0,130,48,4,153,0,33,144,2,0,178,0,32,8,224])}else{if(1===t)return new Uint8Array([1,64,34,128,163,78,230,128,186,8,0,0,0,28,6,241,193,10,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,94]);if(2===t)return new Uint8Array([1,64,34,128,163,94,230,128,186,8,0,0,0,0,149,0,6,241,161,10,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,94]);if(3===t)return new Uint8Array([1,64,34,128,163,94,230,128,186,8,0,0,0,0,149,0,6,241,161,10,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,94])}},e}(),_n=Math.pow(2,32)-1,Pn=function(){function e(){}return e.init=function(){var t;for(t in e.types={avc1:[],avcC:[],hvc1:[],hvcC:[],btrt:[],dinf:[],dref:[],esds:[],ftyp:[],hdlr:[],mdat:[],mdhd:[],mdia:[],mfhd:[],minf:[],moof:[],moov:[],mp4a:[],".mp3":[],dac3:[],"ac-3":[],mvex:[],mvhd:[],pasp:[],sdtp:[],stbl:[],stco:[],stsc:[],stsd:[],stsz:[],stts:[],tfdt:[],tfhd:[],traf:[],trak:[],trun:[],trex:[],tkhd:[],vmhd:[],smhd:[]},e.types)e.types.hasOwnProperty(t)&&(e.types[t]=[t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2),t.charCodeAt(3)]);var r=new Uint8Array([0,0,0,0,0,0,0,0,118,105,100,101,0,0,0,0,0,0,0,0,0,0,0,0,86,105,100,101,111,72,97,110,100,108,101,114,0]),i=new Uint8Array([0,0,0,0,0,0,0,0,115,111,117,110,0,0,0,0,0,0,0,0,0,0,0,0,83,111,117,110,100,72,97,110,100,108,101,114,0]);e.HDLR_TYPES={video:r,audio:i};var n=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,12,117,114,108,32,0,0,0,1]),a=new Uint8Array([0,0,0,0,0,0,0,0]);e.STTS=e.STSC=e.STCO=a,e.STSZ=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0]),e.VMHD=new Uint8Array([0,0,0,1,0,0,0,0,0,0,0,0]),e.SMHD=new Uint8Array([0,0,0,0,0,0,0,0]),e.STSD=new Uint8Array([0,0,0,0,0,0,0,1]);var s=new Uint8Array([105,115,111,109]),o=new Uint8Array([97,118,99,49]),l=new Uint8Array([0,0,0,1]);e.FTYP=e.box(e.types.ftyp,s,l,s,o),e.DINF=e.box(e.types.dinf,e.box(e.types.dref,n))},e.box=function(e){for(var t=8,r=arguments.length,i=new Array(r>1?r-1:0),n=1;n>24&255,o[1]=t>>16&255,o[2]=t>>8&255,o[3]=255&t,o.set(e,4),a=0,t=8;a>24&255,t>>16&255,t>>8&255,255&t,i>>24,i>>16&255,i>>8&255,255&i,n>>24,n>>16&255,n>>8&255,255&n,85,196,0,0]))},e.mdia=function(t){return e.box(e.types.mdia,e.mdhd(t.timescale||0,t.duration||0),e.hdlr(t.type),e.minf(t))},e.mfhd=function(t){return e.box(e.types.mfhd,new Uint8Array([0,0,0,0,t>>24,t>>16&255,t>>8&255,255&t]))},e.minf=function(t){return"audio"===t.type?e.box(e.types.minf,e.box(e.types.smhd,e.SMHD),e.DINF,e.stbl(t)):e.box(e.types.minf,e.box(e.types.vmhd,e.VMHD),e.DINF,e.stbl(t))},e.moof=function(t,r,i){return e.box(e.types.moof,e.mfhd(t),e.traf(i,r))},e.moov=function(t){for(var r=t.length,i=[];r--;)i[r]=e.trak(t[r]);return e.box.apply(null,[e.types.moov,e.mvhd(t[0].timescale||0,t[0].duration||0)].concat(i).concat(e.mvex(t)))},e.mvex=function(t){for(var r=t.length,i=[];r--;)i[r]=e.trex(t[r]);return e.box.apply(null,[e.types.mvex].concat(i))},e.mvhd=function(t,r){r*=t;var i=Math.floor(r/(_n+1)),n=Math.floor(r%(_n+1)),a=new Uint8Array([1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,3,t>>24&255,t>>16&255,t>>8&255,255&t,i>>24,i>>16&255,i>>8&255,255&i,n>>24,n>>16&255,n>>8&255,255&n,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]);return e.box(e.types.mvhd,a)},e.sdtp=function(t){var r,i,n=t.samples||[],a=new Uint8Array(4+n.length);for(r=0;r>>8&255),a.push(255&n),a=a.concat(Array.prototype.slice.call(i));for(r=0;r>>8&255),s.push(255&n),s=s.concat(Array.prototype.slice.call(i));var o=e.box(e.types.avcC,new Uint8Array([1,a[3],a[4],a[5],255,224|t.sps.length].concat(a).concat([t.pps.length]).concat(s))),l=t.width,u=t.height,d=t.pixelRatio[0],h=t.pixelRatio[1];return e.box(e.types.avc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,l>>8&255,255&l,u>>8&255,255&u,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,100,97,105,108,121,109,111,116,105,111,110,47,104,108,115,46,106,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),o,e.box(e.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])),e.box(e.types.pasp,new Uint8Array([d>>24,d>>16&255,d>>8&255,255&d,h>>24,h>>16&255,h>>8&255,255&h])))},e.esds=function(e){var t=e.config;return new Uint8Array([0,0,0,0,3,25,0,1,0,4,17,64,21,0,0,0,0,0,0,0,0,0,0,0,5,2].concat(t,[6,1,2]))},e.audioStsd=function(e){var t=e.samplerate||0;return new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,e.channelCount||0,0,16,0,0,0,0,t>>8&255,255&t,0,0])},e.mp4a=function(t){return e.box(e.types.mp4a,e.audioStsd(t),e.box(e.types.esds,e.esds(t)))},e.mp3=function(t){return e.box(e.types[".mp3"],e.audioStsd(t))},e.ac3=function(t){return e.box(e.types["ac-3"],e.audioStsd(t),e.box(e.types.dac3,t.config))},e.stsd=function(t){var r=t.segmentCodec;if("audio"===t.type){if("aac"===r)return e.box(e.types.stsd,e.STSD,e.mp4a(t));if("ac3"===r&&t.config)return e.box(e.types.stsd,e.STSD,e.ac3(t));if("mp3"===r&&"mp3"===t.codec)return e.box(e.types.stsd,e.STSD,e.mp3(t))}else{if(!t.pps||!t.sps)throw new Error("video track missing pps or sps");if("avc"===r)return e.box(e.types.stsd,e.STSD,e.avc1(t));if("hevc"===r&&t.vps)return e.box(e.types.stsd,e.STSD,e.hvc1(t))}throw new Error("unsupported "+t.type+" segment codec ("+r+"/"+t.codec+")")},e.tkhd=function(t){var r=t.id,i=(t.duration||0)*(t.timescale||0),n=t.width||0,a=t.height||0,s=Math.floor(i/(_n+1)),o=Math.floor(i%(_n+1));return e.box(e.types.tkhd,new Uint8Array([1,0,0,7,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,3,r>>24&255,r>>16&255,r>>8&255,255&r,0,0,0,0,s>>24,s>>16&255,s>>8&255,255&s,o>>24,o>>16&255,o>>8&255,255&o,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,n>>8&255,255&n,0,0,a>>8&255,255&a,0,0]))},e.traf=function(t,r){var i=e.sdtp(t),n=t.id,a=Math.floor(r/(_n+1)),s=Math.floor(r%(_n+1));return e.box(e.types.traf,e.box(e.types.tfhd,new Uint8Array([0,0,0,0,n>>24,n>>16&255,n>>8&255,255&n])),e.box(e.types.tfdt,new Uint8Array([1,0,0,0,a>>24,a>>16&255,a>>8&255,255&a,s>>24,s>>16&255,s>>8&255,255&s])),e.trun(t,i.length+16+20+8+16+8+8),i)},e.trak=function(t){return t.duration=t.duration||4294967295,e.box(e.types.trak,e.tkhd(t),e.mdia(t))},e.trex=function(t){var r=t.id;return e.box(e.types.trex,new Uint8Array([0,0,0,0,r>>24,r>>16&255,r>>8&255,255&r,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]))},e.trun=function(t,r){var i,n,a,s,o,l,u=t.samples||[],d=u.length,h=12+16*d,f=new Uint8Array(h);for(r+=8+h,f.set(["video"===t.type?1:0,0,15,1,d>>>24&255,d>>>16&255,d>>>8&255,255&d,r>>>24&255,r>>>16&255,r>>>8&255,255&r],0),i=0;i>>24&255,a>>>16&255,a>>>8&255,255&a,s>>>24&255,s>>>16&255,s>>>8&255,255&s,o.isLeading<<2|o.dependsOn,o.isDependedOn<<6|o.hasRedundancy<<4|o.paddingValue<<1|o.isNonSync,61440&o.degradPrio,15&o.degradPrio,l>>>24&255,l>>>16&255,l>>>8&255,255&l],12+16*i);return e.box(e.types.trun,f)},e.initSegment=function(t){e.types||e.init();var r=e.moov(t);return Se(e.FTYP,r)},e.hvc1=function(t){for(var r=t.params,i=[t.vps,t.sps,t.pps],n=new Uint8Array([1,r.general_profile_space<<6|(r.general_tier_flag?32:0)|r.general_profile_idc,r.general_profile_compatibility_flags[0],r.general_profile_compatibility_flags[1],r.general_profile_compatibility_flags[2],r.general_profile_compatibility_flags[3],r.general_constraint_indicator_flags[0],r.general_constraint_indicator_flags[1],r.general_constraint_indicator_flags[2],r.general_constraint_indicator_flags[3],r.general_constraint_indicator_flags[4],r.general_constraint_indicator_flags[5],r.general_level_idc,240|r.min_spatial_segmentation_idc>>8,255&r.min_spatial_segmentation_idc,252|r.parallelismType,252|r.chroma_format_idc,248|r.bit_depth_luma_minus8,248|r.bit_depth_chroma_minus8,0,parseInt(r.frame_rate.fps),3|r.temporal_id_nested<<2|r.num_temporal_layers<<3|(r.frame_rate.fixed?64:0),i.length]),a=n.length,s=0;s>8,255&i[d][h].length]),a),a+=2,l.set(i[d][h],a),a+=i[d][h].length}var f=e.box(e.types.hvcC,l),c=t.width,g=t.height,v=t.pixelRatio[0],m=t.pixelRatio[1];return e.box(e.types.hvc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,c>>8&255,255&c,g>>8&255,255&g,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,100,97,105,108,121,109,111,116,105,111,110,47,104,108,115,46,106,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),f,e.box(e.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])),e.box(e.types.pasp,new Uint8Array([v>>24,v>>16&255,v>>8&255,255&v,m>>24,m>>16&255,m>>8&255,255&m])))},e}();Pn.types=void 0,Pn.HDLR_TYPES=void 0,Pn.STTS=void 0,Pn.STSC=void 0,Pn.STCO=void 0,Pn.STSZ=void 0,Pn.VMHD=void 0,Pn.SMHD=void 0,Pn.STSD=void 0,Pn.FTYP=void 0,Pn.DINF=void 0;var Cn=9e4;function wn(e,t,r,i){void 0===r&&(r=1),void 0===i&&(i=!1);var n=e*t*r;return i?Math.round(n):n}function On(e,t){return wn(e,1e3,1/Cn,t)}var xn=null,Mn=null;function Fn(e,t,r,i){return{duration:t,size:r,cts:i,flags:{isLeading:0,isDependedOn:0,hasRedundancy:0,degradPrio:0,dependsOn:e?2:1,isNonSync:e?0:1}}}var Nn=function(e){function t(t,r,i,n){var a;if((a=e.call(this,"mp4-remuxer",n)||this).observer=void 0,a.config=void 0,a.typeSupported=void 0,a.ISGenerated=!1,a._initPTS=null,a._initDTS=null,a.nextVideoTs=null,a.nextAudioTs=null,a.videoSampleDuration=null,a.isAudioContiguous=!1,a.isVideoContiguous=!1,a.videoTrackConfig=void 0,a.observer=t,a.config=r,a.typeSupported=i,a.ISGenerated=!1,null===xn){var s=(navigator.userAgent||"").match(/Chrome\/(\d+)/i);xn=s?parseInt(s[1]):0}if(null===Mn){var o=navigator.userAgent.match(/Safari\/(\d+)/i);Mn=o?parseInt(o[1]):0}return a}o(t,e);var r=t.prototype;return r.destroy=function(){this.config=this.videoTrackConfig=this._initPTS=this._initDTS=null},r.resetTimeStamp=function(e){this.log("initPTS & initDTS reset"),this._initPTS=this._initDTS=e},r.resetNextTimestamp=function(){this.log("reset next timestamp"),this.isVideoContiguous=!1,this.isAudioContiguous=!1},r.resetInitSegment=function(){this.log("ISGenerated flag reset"),this.ISGenerated=!1,this.videoTrackConfig=void 0},r.getVideoStartPts=function(e){var t=!1,r=e[0].pts,i=e.reduce((function(e,i){var n=i.pts,a=n-e;return a<-4294967296&&(t=!0,a=(n=Un(n,r))-e),a>0?e:n}),r);return t&&this.debug("PTS rollover detected"),i},r.remux=function(e,t,r,i,n,a,s,o){var l,u,d,h,f,c,g=n,v=n,m=e.pid>-1,p=t.pid>-1,y=t.samples.length,E=e.samples.length>0,T=s&&y>0||y>1;if((!m||E)&&(!p||T)||this.ISGenerated||s){if(this.ISGenerated){var S,A,L,R,I=this.videoTrackConfig;(I&&(t.width!==I.width||t.height!==I.height||(null==(S=t.pixelRatio)?void 0:S[0])!==(null==(A=I.pixelRatio)?void 0:A[0])||(null==(L=t.pixelRatio)?void 0:L[1])!==(null==(R=I.pixelRatio)?void 0:R[1]))||!I&&T||null===this.nextAudioTs&&E)&&this.resetInitSegment()}this.ISGenerated||(d=this.generateIS(e,t,n,a));var k,b=this.isVideoContiguous,D=-1;if(T&&(D=function(e){for(var t=0;t0){this.warn("Dropped "+D+" out of "+y+" video samples due to a missing keyframe");var _=this.getVideoStartPts(t.samples);t.samples=t.samples.slice(D),t.dropped+=D,k=v+=(t.samples[0].pts-_)/t.inputTimeScale}else-1===D&&(this.warn("No keyframe found out of "+y+" video samples"),c=!1);if(this.ISGenerated){if(E&&T){var P=this.getVideoStartPts(t.samples),C=(Un(e.samples[0].pts,P)-P)/t.inputTimeScale;g+=Math.max(0,C),v+=Math.max(0,-C)}if(E){if(e.samplerate||(this.warn("regenerate InitSegment as audio detected"),d=this.generateIS(e,t,n,a)),u=this.remuxAudio(e,g,this.isAudioContiguous,a,p||T||o===O?v:void 0),T){var w=u?u.endPTS-u.startPTS:0;t.inputTimeScale||(this.warn("regenerate InitSegment as video detected"),d=this.generateIS(e,t,n,a)),l=this.remuxVideo(t,v,b,w)}}else T&&(l=this.remuxVideo(t,v,b,0));l&&(l.firstKeyFrame=D,l.independent=-1!==D,l.firstKeyFramePTS=k)}}return this.ISGenerated&&this._initPTS&&this._initDTS&&(r.samples.length&&(f=Bn(r,n,this._initPTS,this._initDTS)),i.samples.length&&(h=Gn(i,n,this._initPTS))),{audio:u,video:l,initSegment:d,independent:c,text:h,id3:f}},r.generateIS=function(e,t,r,i){var n,a,s,o,l=e.samples,u=t.samples,d=this.typeSupported,h={},f=this._initPTS,c=!f||i,g="audio/mp4";if(c&&(n=a=1/0),e.config&&l.length){switch(e.timescale=e.samplerate,e.segmentCodec){case"mp3":d.mpeg?(g="audio/mpeg",e.codec=""):d.mp3&&(e.codec="mp3");break;case"ac3":e.codec="ac-3"}h.audio={id:"audio",container:g,codec:e.codec,initSegment:"mp3"===e.segmentCodec&&d.mpeg?new Uint8Array(0):Pn.initSegment([e]),metadata:{channelCount:e.channelCount}},c&&(o=e.id,s=e.inputTimeScale,f&&s===f.timescale?c=!1:n=a=l[0].pts-Math.round(s*r))}if(t.sps&&t.pps&&u.length){if(t.timescale=t.inputTimeScale,h.video={id:"main",container:"video/mp4",codec:t.codec,initSegment:Pn.initSegment([t]),metadata:{width:t.width,height:t.height}},c)if(o=t.id,s=t.inputTimeScale,f&&s===f.timescale)c=!1;else{var v=this.getVideoStartPts(u),m=Math.round(s*r);a=Math.min(a,Un(u[0].dts,v)-m),n=Math.min(n,v-m)}this.videoTrackConfig={width:t.width,height:t.height,pixelRatio:t.pixelRatio}}if(Object.keys(h).length)return this.ISGenerated=!0,c?(this._initPTS={baseTime:n,timescale:s},this._initDTS={baseTime:a,timescale:s}):n=s=void 0,{tracks:h,initPTS:n,timescale:s,trackId:o}},r.remuxVideo=function(e,t,r,i){var n,s,o=e.inputTimeScale,l=e.samples,u=[],d=l.length,h=this._initPTS,f=h.baseTime*o/h.timescale,c=this.nextVideoTs,g=8,v=this.videoSampleDuration,m=Number.POSITIVE_INFINITY,p=Number.NEGATIVE_INFINITY,y=!1;if(!r||null===c){var E=f+t*o,T=l[0].pts-Un(l[0].dts,l[0].pts);xn&&null!==c&&Math.abs(E-T-(c+f))<15e3?r=!0:c=E-T-f}for(var S=c+f,A=0;A0?A-1:A].dts&&(y=!0)}y&&l.sort((function(e,t){var r=e.dts-t.dts,i=e.pts-t.pts;return r||i})),n=l[0].dts;var R=(s=l[l.length-1].dts)-n,D=R?Math.round(R/(d-1)):v||e.inputTimeScale/30;if(r){var _=n-S,P=_>D,C=_<-1;if((P||C)&&(P?this.warn((e.segmentCodec||"").toUpperCase()+": "+On(_,!0)+" ms ("+_+"dts) hole between fragments detected at "+t.toFixed(3)):this.warn((e.segmentCodec||"").toUpperCase()+": "+On(-_,!0)+" ms ("+_+"dts) overlapping between fragments detected at "+t.toFixed(3)),!C||S>=l[0].pts||xn)){n=S;var w=l[0].pts-_;if(P)l[0].dts=n,l[0].pts=w;else for(var O=!0,x=0;xw&&O);x++){var M=l[x].pts;if(l[x].dts-=_,l[x].pts-=_,x0?te.dts-l[ee-1].dts:D;if(ue=ee>0?te.pts-l[ee-1].pts:D,de.stretchShortVideoTrack&&null!==this.nextAudioTs){var fe=Math.floor(de.maxBufferHole*o),ce=(i?m+i*o:this.nextAudioTs+f)-te.pts;ce>fe?((v=ce-he)<0?v=he:Q=!0,this.log("It is approximately "+ce/90+" ms to the next segment; using duration "+v/90+" ms for the last video frame.")):v=he}else v=he}var ge=Math.round(te.pts-te.dts);z=Math.min(z,v),J=Math.max(J,v),$=Math.min($,ue),Z=Math.max(Z,ue),u.push(Fn(te.key,v,ie,ge))}if(u.length)if(xn){if(xn<70){var ve=u[0].flags;ve.dependsOn=2,ve.isNonSync=0}}else if(Mn&&Z-$0&&(i&&Math.abs(y-(m+p))<9e3||Math.abs(Un(g[0].pts,y)-(m+p))<20*u),g.forEach((function(e){e.pts=Un(e.pts,y)})),!r||m<0){if(g=g.filter((function(e){return e.pts>=0})),!g.length)return;m=0===n?0:i&&!c?Math.max(0,y-p):g[0].pts-p}if("aac"===e.segmentCodec)for(var E=this.config.maxAudioFramesDrift,T=0,S=m+p;T=E*u&&D<1e4&&c){var _=Math.round(R/u);for(S=L-_*u;S<0&&_&&u;)_--,S+=u;0===T&&(this.nextAudioTs=m=S-p),this.warn("Injecting "+_+" audio frames @ "+((S-p)/s).toFixed(3)+"s due to "+Math.round(1e3*R/s)+" ms gap.");for(var P=0;P<_;P++){var C=Dn.getSilentFrame(e.parsedCodec||e.manifestCodec||e.codec,e.channelCount);C||(this.log("Unable to get silent frame for given audio codec; duplicating last frame instead."),C=A.unit.subarray()),g.splice(T,0,{unit:C,pts:S}),S+=u,T++}}A.pts=S,S+=u}for(var w,O=null,x=null,M=0,F=g.length;F--;)M+=g[F].unit.byteLength;for(var N=0,U=g.length;N0))return;M+=v;try{w=new Uint8Array(M)}catch(e){return void this.observer.emit(b.ERROR,b.ERROR,{type:I.MUX_ERROR,details:k.REMUX_ALLOC_ERROR,fatal:!1,error:e,bytes:M,reason:"fail allocating audio mdat "+M})}h||(new DataView(w.buffer).setUint32(0,M),w.set(Pn.types.mdat,4))}w.set(G,v);var V=G.byteLength;v+=V,f.push(Fn(!0,l,V,0)),x=K}var H=f.length;if(H){var Y=f[f.length-1];m=x-p,this.nextAudioTs=m+o*Y.duration;var W=h?new Uint8Array(0):Pn.moof(e.sequenceNumber++,O/o,a({},e,{samples:f}));e.samples=[];var j=(O-p)/s,q=m/s,X={data1:W,data2:w,startPTS:j,endPTS:q,startDTS:j,endDTS:q,type:"audio",hasAudio:!0,hasVideo:!1,nb:H};return this.isAudioContiguous=!0,X}},t}(N);function Un(e,t){var r;if(null===t)return e;for(r=t4294967296;)e+=r;return e}function Bn(e,t,r,i){var n=e.samples.length;if(n){for(var a=e.inputTimeScale,s=0;s0;n||(i=fe(t,["encv"])),i.forEach((function(e){fe(n?e.subarray(28):e.subarray(78),["sinf"]).forEach((function(e){var t=Te(e);if(t){var i=t.subarray(8,24);i.some((function(e){return 0!==e}))||(Y.log("[eme] Patching keyId in 'enc"+(n?"a":"v")+">sinf>>tenc' box: "+X.hexDump(i)+" -> "+X.hexDump(r)),t.set(r,8))}}))}))})),e}(e,i)),this.emitInitSegment=!0},r.generateInitSegment=function(e){var t=this.audioCodec,r=this.videoCodec;if(null==e||!e.byteLength)return this.initTracks=void 0,void(this.initData=void 0);var i=this.initData=ge(e);i.audio&&(t=Yn(i.audio,z,this)),i.video&&(r=Yn(i.video,$,this));var n={};i.audio&&i.video?n.audiovideo={container:"video/mp4",codec:t+","+r,supplemental:i.video.supplemental,initSegment:e,id:"main"}:i.audio?n.audio={container:"audio/mp4",codec:t,initSegment:e,id:"audio"}:i.video?n.video={container:"video/mp4",codec:r,supplemental:i.video.supplemental,initSegment:e,id:"main"}:this.warn("initSegment does not contain moov or trak boxes."),this.initTracks=n},r.remux=function(e,t,r,i,n,a){var s,o,l=this.initPTS,u=this.lastEndTime,d={audio:void 0,video:void 0,text:i,id3:r,initSegment:void 0};A(u)||(u=this.lastEndTime=n||0);var h=t.samples;if(null==h||!h.length)return d;var f={initPTS:void 0,timescale:void 0,trackId:void 0},c=this.initData;if(null!=(s=c)&&s.length||(this.generateInitSegment(h),c=this.initData),null==(o=c)||!o.length)return this.warn("Failed to generate initSegment."),d;this.emitInitSegment&&(f.tracks=this.initTracks,this.emitInitSegment=!1);var g,v=function(e,t,r){for(var i={},n=fe(e,["moof","traf"]),a=0;an}(l,L,n,R)&&f.timescale===l.timescale||(f.initPTS=L-n,f.timescale=1,l&&1===l.timescale&&this.warn("Adjusting initPTS @"+n+" from "+l.baseTime/l.timescale+" to "+f.initPTS),this.initPTS=l={baseTime:f.initPTS,timescale:1});var k=e?L-l.baseTime/l.timescale:u,b=k+R;R>0?this.lastEndTime=b:(this.warn("Duration parsed from mp4 should be greater than zero"),this.resetNextTimestamp());var D=!!c.audio,_=!!c.video,P="";D&&(P+="audio"),_&&(P+="video");var C={data1:h,startPTS:k,startDTS:k,endPTS:b,endDTS:b,type:P,hasAudio:D,hasVideo:_,nb:1,dropped:0};d.audio=D&&!_?C:void 0,d.video=_?C:void 0;var w=null==p?void 0:p.sampleCount;if(w){var O=p.keyFrameIndex,x=-1!==O;C.nb=w,C.dropped=0===O||this.isVideoContiguous?0:x?O:w,C.independent=x,C.firstKeyFrame=O,x&&p.keyFrameStart&&(C.firstKeyFramePTS=(p.keyFrameStart-l.baseTime)/l.timescale),this.isVideoContiguous||(d.independent=x),this.isVideoContiguous||(this.isVideoContiguous=x),C.dropped&&this.warn("fmp4 does not start with IDR: firstIDR "+O+"/"+w+" dropped: "+C.dropped+" start: "+(C.firstKeyFramePTS||"NA"))}return d.initSegment=f,d.id3=Bn(r,n,l,l),i.samples.length&&(d.text=Gn(i,n,l)),d},t}(N);function Hn(e,t,r){return void 0===r&&(r=!1),void 0!==(null==e?void 0:e.start)?(e.start+(r?e.duration:0))/e.timescale:t}function Yn(e,t,r){var i=null==e?void 0:e.codec;return i&&i.length>4?i:t===z?"ec-3"===i||"ac-3"===i||"alac"===i?i:"fLaC"===i||"Opus"===i?Be(i,!1):(r.warn('Unhandled audio codec "'+i+'" in mp4 MAP'),i||"mp4a"):(r.warn('Unhandled video codec "'+i+'" in mp4 MAP'),i||"avc1")}try{Kn=self.performance.now.bind(self.performance)}catch(e){Kn=Date.now}var Wn=[{demux:cn,remux:Vn},{demux:Sn,remux:Nn},{demux:on,remux:Nn},{demux:hn,remux:Nn}];Wn.splice(2,0,{demux:un,remux:Nn});var jn=function(){function e(e,t,r,i,n,a){this.asyncResult=!1,this.logger=void 0,this.observer=void 0,this.typeSupported=void 0,this.config=void 0,this.id=void 0,this.demuxer=void 0,this.remuxer=void 0,this.decrypter=void 0,this.probe=void 0,this.decryptionPromise=null,this.transmuxConfig=void 0,this.currentTransmuxState=void 0,this.observer=e,this.typeSupported=t,this.config=r,this.id=n,this.logger=a}var t=e.prototype;return t.configure=function(e){this.transmuxConfig=e,this.decrypter&&this.decrypter.reset()},t.push=function(e,t,r,i){var n=this,a=r.transmuxing;a.executeStart=Kn();var s=new Uint8Array(e),o=this.currentTransmuxState,l=this.transmuxConfig;i&&(this.currentTransmuxState=i);var u=i||o,d=u.contiguous,h=u.discontinuity,f=u.trackSwitch,c=u.accurateTimeOffset,g=u.timeOffset,v=u.initSegmentChange,m=l.audioCodec,p=l.videoCodec,y=l.defaultInitPts,E=l.duration,T=l.initSegmentData,S=function(e,t){var r=null;return e.byteLength>0&&null!=(null==t?void 0:t.key)&&null!==t.iv&&null!=t.method&&(r=t),r}(s,t);if(S&&vr(S.method)){var A=this.getDecrypter(),L=mr(S.method);if(!A.isSync())return this.asyncResult=!0,this.decryptionPromise=A.webCryptoDecrypt(s,S.key.buffer,S.iv.buffer,L).then((function(e){var t=n.push(e,null,r);return n.decryptionPromise=null,t})),this.decryptionPromise;var R=A.softwareDecrypt(s,S.key.buffer,S.iv.buffer,L);if(r.part>-1){var D=A.flush();R=D?D.buffer:D}if(!R)return a.executeEnd=Kn(),qn(r);s=new Uint8Array(R)}var _=this.needsProbing(h,f);if(_){var P=this.configureTransmuxer(s);if(P)return this.logger.warn("[transmuxer] "+P.message),this.observer.emit(b.ERROR,b.ERROR,{type:I.MEDIA_ERROR,details:k.FRAG_PARSING_ERROR,fatal:!1,error:P,reason:P.message}),a.executeEnd=Kn(),qn(r)}(h||f||v||_)&&this.resetInitSegment(T,m,p,E,t),(h||v||_)&&this.resetInitialTimestamp(y),d||this.resetContiguity();var C=this.transmux(s,S,g,c,r);this.asyncResult=Xn(C);var w=this.currentTransmuxState;return w.contiguous=!0,w.discontinuity=!1,w.trackSwitch=!1,a.executeEnd=Kn(),C},t.flush=function(e){var t=this,r=e.transmuxing;r.executeStart=Kn();var i=this.decrypter,n=this.currentTransmuxState,a=this.decryptionPromise;if(a)return this.asyncResult=!0,a.then((function(){return t.flush(e)}));var s=[],o=n.timeOffset;if(i){var l=i.flush();l&&s.push(this.push(l.buffer,null,e))}var u=this.demuxer,d=this.remuxer;if(!u||!d){r.executeEnd=Kn();var h=[qn(e)];return this.asyncResult?Promise.resolve(h):h}var f=u.flush(o);return Xn(f)?(this.asyncResult=!0,f.then((function(r){return t.flushRemux(s,r,e),s}))):(this.flushRemux(s,f,e),this.asyncResult?Promise.resolve(s):s)},t.flushRemux=function(e,t,r){var i=t.audioTrack,n=t.videoTrack,a=t.id3Track,s=t.textTrack,o=this.currentTransmuxState,l=o.accurateTimeOffset,u=o.timeOffset;this.logger.log("[transmuxer.ts]: Flushed "+this.id+" sn: "+r.sn+(r.part>-1?" part: "+r.part:"")+" of "+(this.id===w?"level":"track")+" "+r.level);var d=this.remuxer.remux(i,n,a,s,u,l,!0,this.id);e.push({remuxResult:d,chunkMeta:r}),r.transmuxing.executeEnd=Kn()},t.resetInitialTimestamp=function(e){var t=this.demuxer,r=this.remuxer;t&&r&&(t.resetTimeStamp(e),r.resetTimeStamp(e))},t.resetContiguity=function(){var e=this.demuxer,t=this.remuxer;e&&t&&(e.resetContiguity(),t.resetNextTimestamp())},t.resetInitSegment=function(e,t,r,i,n){var a=this.demuxer,s=this.remuxer;a&&s&&(a.resetInitSegment(e,t,r,i),s.resetInitSegment(e,t,r,n))},t.destroy=function(){this.demuxer&&(this.demuxer.destroy(),this.demuxer=void 0),this.remuxer&&(this.remuxer.destroy(),this.remuxer=void 0)},t.transmux=function(e,t,r,i,n){return t&&"SAMPLE-AES"===t.method?this.transmuxSampleAes(e,t,r,i,n):this.transmuxUnencrypted(e,r,i,n)},t.transmuxUnencrypted=function(e,t,r,i){var n=this.demuxer.demux(e,t,!1,!this.config.progressive),a=n.audioTrack,s=n.videoTrack,o=n.id3Track,l=n.textTrack;return{remuxResult:this.remuxer.remux(a,s,o,l,t,r,!1,this.id),chunkMeta:i}},t.transmuxSampleAes=function(e,t,r,i,n){var a=this;return this.demuxer.demuxSampleAes(e,t,r).then((function(e){return{remuxResult:a.remuxer.remux(e.audioTrack,e.videoTrack,e.id3Track,e.textTrack,r,i,!1,a.id),chunkMeta:n}}))},t.configureTransmuxer=function(e){for(var t,r=this.config,i=this.observer,n=this.typeSupported,a=0,s=Wn.length;a1&&l.id===(null==p?void 0:p.stats.chunkCount),L=!E&&(1===T||0===T&&(1===S||A&&S<=0)),R=self.performance.now();(E||T||0===n.stats.parsing.start)&&(n.stats.parsing.start=R),!a||!S&&L||(a.stats.parsing.start=R);var I=!(p&&(null==(d=n.initSegment)?void 0:d.url)===(null==(h=p.initSegment)?void 0:h.url)),k=new zn(y,L,o,E,v,I);if(!L||y||I){this.hls.logger.log("[transmuxer-interface]: Starting new transmux session for "+n.type+" sn: "+l.sn+(l.part>-1?" part: "+l.part:"")+" "+(this.id===w?"level":"track")+": "+l.level+" id: "+l.id+"\n discontinuity: "+y+"\n trackSwitch: "+E+"\n contiguous: "+L+"\n accurateTimeOffset: "+o+"\n timeOffset: "+v+"\n initSegmentChange: "+I);var b=new Qn(r,i,t,s,u);this.configureTransmuxer(b)}if(this.frag=n,this.part=a,this.workerContext)this.workerContext.worker.postMessage({instanceNo:c,cmd:"demux",data:e,decryptdata:m,chunkMeta:l,state:k},e instanceof ArrayBuffer?[e]:[]);else if(g){var D=g.push(e,m,l,k);Xn(D)?D.then((function(e){f.handleTransmuxComplete(e)})).catch((function(e){f.transmuxerError(e,l,"transmuxer-interface push error")})):this.handleTransmuxComplete(D)}},r.flush=function(e){var t=this;e.transmuxing.start=self.performance.now();var r=this.instanceNo,i=this.transmuxer;if(this.workerContext)this.workerContext.worker.postMessage({instanceNo:r,cmd:"flush",chunkMeta:e});else if(i){var n=i.flush(e);Xn(n)?n.then((function(r){t.handleFlushResult(r,e)})).catch((function(r){t.transmuxerError(r,e,"transmuxer-interface flush error")})):this.handleFlushResult(n,e)}},r.transmuxerError=function(e,t,r){this.hls&&(this.error=e,this.hls.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.FRAG_PARSING_ERROR,chunkMeta:t,frag:this.frag||void 0,part:this.part||void 0,fatal:!1,error:e,err:e,reason:r}))},r.handleFlushResult=function(e,t){var r=this;e.forEach((function(e){r.handleTransmuxComplete(e)})),this.onFlush(t)},r.configureTransmuxer=function(e){var t=this.instanceNo,r=this.transmuxer;this.workerContext?this.workerContext.worker.postMessage({instanceNo:t,cmd:"configure",config:e}):r&&r.configure(e)},r.handleTransmuxComplete=function(e){e.chunkMeta.transmuxing.end=self.performance.now(),this.onTransmuxComplete(e)},t}(),sa=function(e){function t(t,r,i){var n;return(n=e.call(this,t,r,i,"audio-stream-controller",O)||this).mainAnchor=null,n.mainFragLoading=null,n.audioOnly=!1,n.bufferedTrack=null,n.switchingTrack=null,n.trackId=-1,n.waitingData=null,n.mainDetails=null,n.flushing=!1,n.bufferFlushed=!1,n.cachedTrackLoadedData=null,n.registerListeners(),n}o(t,e);var r=t.prototype;return r.onHandlerDestroying=function(){this.unregisterListeners(),e.prototype.onHandlerDestroying.call(this),this.resetItem()},r.resetItem=function(){this.mainDetails=this.mainAnchor=this.mainFragLoading=this.bufferedTrack=this.switchingTrack=this.waitingData=this.cachedTrackLoadedData=null},r.registerListeners=function(){e.prototype.registerListeners.call(this);var t=this.hls;t.on(b.LEVEL_LOADED,this.onLevelLoaded,this),t.on(b.AUDIO_TRACKS_UPDATED,this.onAudioTracksUpdated,this),t.on(b.AUDIO_TRACK_SWITCHING,this.onAudioTrackSwitching,this),t.on(b.AUDIO_TRACK_LOADED,this.onAudioTrackLoaded,this),t.on(b.BUFFER_RESET,this.onBufferReset,this),t.on(b.BUFFER_CREATED,this.onBufferCreated,this),t.on(b.BUFFER_FLUSHING,this.onBufferFlushing,this),t.on(b.BUFFER_FLUSHED,this.onBufferFlushed,this),t.on(b.INIT_PTS_FOUND,this.onInitPtsFound,this),t.on(b.FRAG_LOADING,this.onFragLoading,this),t.on(b.FRAG_BUFFERED,this.onFragBuffered,this)},r.unregisterListeners=function(){var t=this.hls;t&&(e.prototype.unregisterListeners.call(this),t.off(b.LEVEL_LOADED,this.onLevelLoaded,this),t.off(b.AUDIO_TRACKS_UPDATED,this.onAudioTracksUpdated,this),t.off(b.AUDIO_TRACK_SWITCHING,this.onAudioTrackSwitching,this),t.off(b.AUDIO_TRACK_LOADED,this.onAudioTrackLoaded,this),t.off(b.BUFFER_RESET,this.onBufferReset,this),t.off(b.BUFFER_CREATED,this.onBufferCreated,this),t.off(b.BUFFER_FLUSHING,this.onBufferFlushing,this),t.off(b.BUFFER_FLUSHED,this.onBufferFlushed,this),t.off(b.INIT_PTS_FOUND,this.onInitPtsFound,this),t.off(b.FRAG_LOADING,this.onFragLoading,this),t.off(b.FRAG_BUFFERED,this.onFragBuffered,this))},r.onInitPtsFound=function(e,t){var r=t.frag,i=t.id,n=t.initPTS,a=t.timescale;if(i===w){var s=r.cc,o=this.fragCurrent;if(this.initPTS[s]={baseTime:n,timescale:a},this.log("InitPTS for cc: "+s+" found from main: "+n+"/"+a),this.mainAnchor=r,this.state===Ei.WAITING_INIT_PTS){var l=this.waitingData;(!l&&!this.loadingParts||l&&l.frag.cc!==s)&&this.syncWithAnchor(r,null==l?void 0:l.frag)}else!this.hls.hasEnoughToStart&&o&&o.cc!==s?(o.abortRequests(),this.syncWithAnchor(r,o)):this.state===Ei.IDLE&&this.tick()}},r.getLoadPosition=function(){return!this.startFragRequested&&this.nextLoadPosition>=0?this.nextLoadPosition:e.prototype.getLoadPosition.call(this)},r.syncWithAnchor=function(e,t){var r,i=(null==(r=this.mainFragLoading)?void 0:r.frag)||null;if(!t||(null==i?void 0:i.cc)!==t.cc){var n=(i||e).cc,a=Tt(this.getLevelDetails(),n,this.getLoadPosition());a&&(this.log("Waiting fragment cc ("+(null==t?void 0:t.cc)+") cancelled because video is at cc "+e.cc),this.startFragRequested=!1,this.nextLoadPosition=a.start,this.resetLoadingState(),this.state===Ei.IDLE&&this.doTickIdle())}},r.startLoad=function(e,t){if(!this.levels)return this.startPosition=e,void(this.state=Ei.STOPPED);var r=this.lastCurrentTime;this.stopLoad(),this.setInterval(100),r>0&&-1===e?(this.log("Override startPosition with lastCurrentTime @"+r.toFixed(3)),e=r,this.state=Ei.IDLE):this.state=Ei.WAITING_TRACK,this.nextLoadPosition=this.lastCurrentTime=e+this.timelineOffset,this.startPosition=t?-1:e,this.tick()},r.doTick=function(){switch(this.state){case Ei.IDLE:this.doTickIdle();break;case Ei.WAITING_TRACK:var t=this.levels,r=this.trackId,i=null==t?void 0:t[r],n=null==i?void 0:i.details;if(n&&!this.waitForLive(i)){if(this.waitForCdnTuneIn(n))break;this.state=Ei.WAITING_INIT_PTS}break;case Ei.FRAG_LOADING_WAITING_RETRY:var a,s=performance.now(),o=this.retryDate;if(!o||s>=o||null!=(a=this.media)&&a.seeking){var l=this.levels,u=this.trackId;this.log("RetryDate reached, switch back to IDLE state"),this.resetStartWhenNotLoaded((null==l?void 0:l[u])||null),this.state=Ei.IDLE}break;case Ei.WAITING_INIT_PTS:var d=this.waitingData;if(d){var h=d.frag,f=d.part,c=d.cache,g=d.complete,v=this.mainAnchor;if(void 0!==this.initPTS[h.cc]){this.waitingData=null,this.state=Ei.FRAG_LOADING;var m={frag:h,part:f,payload:c.flush().buffer,networkDetails:null};this._handleFragmentLoadProgress(m),g&&e.prototype._handleFragmentLoadComplete.call(this,m)}else v&&v.cc!==d.frag.cc&&this.syncWithAnchor(v,d.frag)}else this.state=Ei.IDLE}this.onTickEnd()},r.resetLoadingState=function(){var t=this.waitingData;t&&(this.fragmentTracker.removeFragment(t.frag),this.waitingData=null),e.prototype.resetLoadingState.call(this)},r.onTickEnd=function(){var e=this.media;null!=e&&e.readyState&&(this.lastCurrentTime=e.currentTime)},r.doTickIdle=function(){var e,t=this.hls,r=this.levels,i=this.media,n=this.trackId,a=t.config;if(this.buffering&&(i||this.primaryPrefetch||!this.startFragRequested&&a.startFragPrefetch)&&null!=r&&r[n]){var s=r[n],o=s.details;if(!o||this.waitForLive(s)||this.waitForCdnTuneIn(o))return this.state=Ei.WAITING_TRACK,void(this.startFragRequested=!1);var l=this.mediaBuffer?this.mediaBuffer:this.media;this.bufferFlushed&&l&&(this.bufferFlushed=!1,this.afterBufferFlushed(l,z,O));var u=this.getFwdBufferInfo(l,O);if(null!==u){if(!this.switchingTrack&&this._streamEnded(u,o))return t.trigger(b.BUFFER_EOS,{type:"audio"}),void(this.state=Ei.ENDED);var d=u.len,h=t.maxBufferLength,f=o.fragments,c=f[0].start,g=this.getLoadPosition(),v=this.flushing?g:u.end;if(this.switchingTrack&&i){var m=g;o.PTSKnown&&mc||u.nextStart)&&(this.log("Alt audio track ahead of main track, seek to start of alt audio track"),i.currentTime=c+.05)}if(!(d>=h&&!this.switchingTrack&&vy.end){var E=this.fragmentTracker.getFragAtPos(v,w);E&&E.end>y.end&&(y=E,this.mainFragLoading={frag:E,targetBufferTime:null})}if(p.start>y.end)return}this.loadFragment(p,s,v)}else this.bufferFlushed=!0}}}},r.onMediaDetaching=function(t,r){this.bufferFlushed=this.flushing=!1,e.prototype.onMediaDetaching.call(this,t,r)},r.onAudioTracksUpdated=function(e,t){var r=t.audioTracks;this.resetTransmuxer(),this.levels=r.map((function(e){return new it(e)}))},r.onAudioTrackSwitching=function(e,t){var r=!!t.url;this.trackId=t.id;var i=this.fragCurrent;i&&(i.abortRequests(),this.removeUnbufferedFrags(i.start)),this.resetLoadingState(),r?(this.switchingTrack=t,this.flushAudioIfNeeded(t),this.state!==Ei.STOPPED&&(this.setInterval(100),this.state=Ei.IDLE,this.tick())):(this.resetTransmuxer(),this.switchingTrack=null,this.bufferedTrack=t,this.clearInterval())},r.onManifestLoading=function(){e.prototype.onManifestLoading.call(this),this.bufferFlushed=this.flushing=this.audioOnly=!1,this.resetItem(),this.trackId=-1},r.onLevelLoaded=function(e,t){this.mainDetails=t.details;var r=this.cachedTrackLoadedData;r&&(this.cachedTrackLoadedData=null,this.onAudioTrackLoaded(b.AUDIO_TRACK_LOADED,r))},r.onAudioTrackLoaded=function(e,t){var r,i=this.levels,n=t.details,a=t.id,s=t.groupId,o=t.track;if(i){var l=this.mainDetails;if(!l||n.endCC>l.endCC||l.expired)return this.cachedTrackLoadedData=t,void(this.state!==Ei.STOPPED&&(this.state=Ei.WAITING_TRACK));this.cachedTrackLoadedData=null,this.log("Audio track "+a+' "'+o.name+'" of "'+s+'" loaded ['+n.startSN+","+n.endSN+"]"+(n.lastPartSn?"[part-"+n.lastPartSn+"-"+n.lastPartIndex+"]":"")+",duration:"+n.totalduration);var u=i[a],d=0;if(n.live||null!=(r=u.details)&&r.live){if(this.checkLiveUpdate(n),n.deltaUpdateFailed)return;var h;u.details&&(d=this.alignPlaylists(n,u.details,null==(h=this.levelLastLoaded)?void 0:h.details)),n.alignedSliding||(mi(n,l),n.alignedSliding||pi(n,l),d=n.fragmentStart)}u.details=n,this.levelLastLoaded=u,this.startFragRequested||this.setStartPosition(l,d),this.hls.trigger(b.AUDIO_TRACK_UPDATED,{details:n,id:a,groupId:t.groupId}),this.state!==Ei.WAITING_TRACK||this.waitForCdnTuneIn(n)||(this.state=Ei.IDLE),this.tick()}else this.warn("Audio tracks reset while loading track "+a+' "'+o.name+'" of "'+s+'"')},r._handleFragmentLoadProgress=function(e){var t,r=e.frag,i=e.part,n=e.payload,a=this.config,s=this.trackId,o=this.levels;if(o){var l=o[s];if(l){var u=l.details;if(!u)return this.warn("Audio track details undefined on fragment load progress"),void this.removeUnbufferedFrags(r.start);var d=a.defaultAudioCodec||l.audioCodec||"mp4a.40.2",h=this.transmuxer;h||(h=this.transmuxer=new aa(this.hls,O,this._handleTransmuxComplete.bind(this),this._handleTransmuxerFlush.bind(this)));var f=this.initPTS[r.cc],c=null==(t=r.initSegment)?void 0:t.data;if(void 0!==f){var g=i?i.index:-1,v=-1!==g,m=new tr(r.level,r.sn,r.stats.chunkCount,n.byteLength,g,v);h.push(n,c,d,"",r,i,u.totalduration,!1,m,f)}else this.log("Unknown video PTS for cc "+r.cc+", waiting for video PTS before demuxing audio frag "+r.sn+" of ["+u.startSN+" ,"+u.endSN+"],track "+s),(this.waitingData=this.waitingData||{frag:r,part:i,cache:new Ai,complete:!1}).cache.push(new Uint8Array(n)),this.state!==Ei.STOPPED&&(this.state=Ei.WAITING_INIT_PTS)}else this.warn("Audio track is undefined on fragment load progress")}else this.warn("Audio tracks were reset while fragment load was in progress. Fragment "+r.sn+" of level "+r.level+" will not be buffered")},r._handleFragmentLoadComplete=function(t){this.waitingData?this.waitingData.complete=!0:e.prototype._handleFragmentLoadComplete.call(this,t)},r.onBufferReset=function(){this.mediaBuffer=null},r.onBufferCreated=function(e,t){this.bufferFlushed=this.flushing=!1;var r=t.tracks.audio;r&&(this.mediaBuffer=r.buffer||null)},r.onFragLoading=function(e,t){!this.audioOnly&&t.frag.type===w&&ee(t.frag)&&(this.mainFragLoading=t,this.state===Ei.IDLE&&this.tick())},r.onFragBuffered=function(e,t){var r=t.frag,i=t.part;if(r.type===O)if(this.fragContextChanged(r))this.warn("Fragment "+r.sn+(i?" p: "+i.index:"")+" of level "+r.level+" finished buffering, but was aborted. state: "+this.state+", audioSwitch: "+(this.switchingTrack?this.switchingTrack.name:"false"));else{if(ee(r)){this.fragPrevious=r;var n=this.switchingTrack;n&&(this.bufferedTrack=n,this.switchingTrack=null,this.hls.trigger(b.AUDIO_TRACK_SWITCHED,d({},n)))}this.fragBufferedComplete(r,i),this.media&&this.tick()}else this.audioOnly||r.type!==w||r.elementaryStreams.video||r.elementaryStreams.audiovideo||(this.audioOnly=!0,this.mainFragLoading=null)},r.onError=function(t,r){var i;if(r.fatal)this.state=Ei.ERROR;else switch(r.details){case k.FRAG_GAP:case k.FRAG_PARSING_ERROR:case k.FRAG_DECRYPT_ERROR:case k.FRAG_LOAD_ERROR:case k.FRAG_LOAD_TIMEOUT:case k.KEY_LOAD_ERROR:case k.KEY_LOAD_TIMEOUT:this.onFragmentOrKeyLoadError(O,r);break;case k.AUDIO_TRACK_LOAD_ERROR:case k.AUDIO_TRACK_LOAD_TIMEOUT:case k.LEVEL_PARSING_ERROR:r.levelRetry||this.state!==Ei.WAITING_TRACK||(null==(i=r.context)?void 0:i.type)!==P||(this.state=Ei.IDLE);break;case k.BUFFER_ADD_CODEC_ERROR:case k.BUFFER_APPEND_ERROR:if("audio"!==r.parent)return;this.reduceLengthAndFlushBuffer(r)||this.resetLoadingState();break;case k.BUFFER_FULL_ERROR:if("audio"!==r.parent)return;this.reduceLengthAndFlushBuffer(r)&&(this.bufferedTrack=null,e.prototype.flushMainBuffer.call(this,0,Number.POSITIVE_INFINITY,"audio"));break;case k.INTERNAL_EXCEPTION:this.recoverWorkerError(r)}},r.onBufferFlushing=function(e,t){t.type!==$&&(this.flushing=!0)},r.onBufferFlushed=function(e,t){var r=t.type;if(r!==$){this.flushing=!1,this.bufferFlushed=!0,this.state===Ei.ENDED&&(this.state=Ei.IDLE);var i=this.mediaBuffer||this.media;i&&(this.afterBufferFlushed(i,r,O),this.tick())}},r._handleTransmuxComplete=function(e){var t,r="audio",i=this.hls,n=e.remuxResult,s=e.chunkMeta,o=this.getCurrentContext(s);if(o){var l=o.frag,u=o.part,d=o.level,h=d.details,f=n.audio,c=n.text,g=n.id3,v=n.initSegment;if(!this.fragContextChanged(l)&&h){if(this.state=Ei.PARSING,this.switchingTrack&&f&&this.completeAudioSwitch(this.switchingTrack),null!=v&&v.tracks){var m=l.initSegment||l;this._bufferInitSegment(d,v.tracks,m,s),i.trigger(b.FRAG_PARSING_INIT_SEGMENT,{frag:m,id:r,tracks:v.tracks})}if(f){var p=f.startPTS,y=f.endPTS,E=f.startDTS,T=f.endDTS;u&&(u.elementaryStreams[z]={startPTS:p,endPTS:y,startDTS:E,endDTS:T}),l.setElementaryStreamInfo(z,p,y,E,T),this.bufferFragmentData(f,l,u,s)}if(null!=g&&null!=(t=g.samples)&&t.length){var S=a({id:r,frag:l,details:h},g);i.trigger(b.FRAG_PARSING_METADATA,S)}if(c){var A=a({id:r,frag:l,details:h},c);i.trigger(b.FRAG_PARSING_USERDATA,A)}}else this.fragmentTracker.removeFragment(l)}else this.resetWhenMissingContext(s)},r._bufferInitSegment=function(e,t,r,i){if(this.state===Ei.PARSING&&(t.video&&delete t.video,t.audiovideo&&delete t.audiovideo,t.audio)){var n=t.audio;n.id=O;var a=e.audioCodec;this.log("Init audio buffer, container:"+n.container+", codecs[level/parsed]=["+a+"/"+n.codec+"]"),a&&1===a.split(",").length&&(n.levelCodec=a),this.hls.trigger(b.BUFFER_CODECS,t);var s=n.initSegment;if(null!=s&&s.byteLength){var o={type:"audio",frag:r,part:null,chunkMeta:i,parent:r.type,data:s};this.hls.trigger(b.BUFFER_APPENDING,o)}this.tickImmediate()}},r.loadFragment=function(t,r,i){var n,a=this.fragmentTracker.getState(t);if(this.switchingTrack||a===Mt||a===Nt)if(ee(t))if(null!=(n=r.details)&&n.live&&!this.initPTS[t.cc]){this.log("Waiting for video PTS in continuity counter "+t.cc+" of live stream before loading audio fragment "+t.sn+" of level "+this.trackId),this.state=Ei.WAITING_INIT_PTS;var s=this.mainDetails;s&&s.fragmentStart!==r.details.fragmentStart&&pi(r.details,s)}else e.prototype.loadFragment.call(this,t,r,i);else this._loadInitSegment(t,r);else this.clearTrackerIfNeeded(t)},r.flushAudioIfNeeded=function(t){if(this.media&&this.bufferedTrack){var r=this.bufferedTrack;ht({name:r.name,lang:r.lang,assocLang:r.assocLang,characteristics:r.characteristics,audioCodec:r.audioCodec,channels:r.channels},t,ft)||(gt(t.url,this.hls)?(this.log("Switching audio track : flushing all audio"),e.prototype.flushMainBuffer.call(this,0,Number.POSITIVE_INFINITY,"audio"),this.bufferedTrack=null):this.bufferedTrack=t)}},r.completeAudioSwitch=function(e){var t=this.hls;this.flushAudioIfNeeded(e),this.bufferedTrack=e,this.switchingTrack=null,t.trigger(b.AUDIO_TRACK_SWITCHED,d({},e))},t}(Ti),oa=function(e){function t(t,r){var i;return(i=e.call(this,r,t.logger)||this).hls=void 0,i.canLoad=!1,i.timer=-1,i.hls=t,i}o(t,e);var r=t.prototype;return r.destroy=function(){this.clearTimer(),this.hls=this.log=this.warn=null},r.clearTimer=function(){-1!==this.timer&&(self.clearTimeout(this.timer),this.timer=-1)},r.startLoad=function(){this.canLoad=!0,this.loadPlaylist()},r.stopLoad=function(){this.canLoad=!1,this.clearTimer()},r.switchParams=function(e,t,r){var i=null==t?void 0:t.renditionReports;if(i){for(var n=-1,a=0;a=0&&h>t.partTarget&&(d+=1)}var f=r&&tt(r);return new rt(u,d>=0?d:void 0,f)}}},r.loadPlaylist=function(e){this.clearTimer()},r.loadingPlaylist=function(e,t){this.clearTimer()},r.shouldLoadPlaylist=function(e){return this.canLoad&&!!e&&!!e.url&&(!e.details||e.details.live)},r.getUrlWithDirectives=function(e,t){if(t)try{return t.addDirectives(e)}catch(e){this.warn("Could not construct new URL with HLS Delivery Directives: "+e)}return e},r.playlistLoaded=function(e,t,r){var i=t.details,n=t.stats,a=self.performance.now(),s=n.loading.first?Math.max(0,a-n.loading.first):0;i.advancedDateTime=Date.now()-s;var o=this.hls.config.timelineOffset;if(o!==i.appliedTimelineOffset){var l=Math.max(o||0,0);i.appliedTimelineOffset=l,i.fragments.forEach((function(e){e.start=e.playlistOffset+l}))}if(i.live||null!=r&&r.live){var u="levelInfo"in t?t.levelInfo:t.track;if(i.reloaded(r),r&&i.fragments.length>0){ni(r,i);var d=i.playlistParsingError;if(d){this.warn(d);var h=this.hls;if(!h.config.ignorePlaylistParsingErrors){var f,c=t.networkDetails;return void h.trigger(b.ERROR,{type:I.NETWORK_ERROR,details:k.LEVEL_PARSING_ERROR,fatal:!1,url:i.url,error:d,reason:d.message,level:t.level||void 0,parent:null==(f=i.fragments[0])?void 0:f.type,networkDetails:c,stats:n})}i.playlistParsingError=null}}-1===i.requestScheduled&&(i.requestScheduled=n.loading.start);var g,v=this.hls.mainForwardBufferInfo,m=v?v.end-v.len:0,p=li(i,1e3*(i.edge-m));if(i.requestScheduled+p0){if(_>3*i.targetduration)this.log("Playlist last advanced "+D.toFixed(2)+"s ago. Omitting segment and part directives."),y=void 0,E=void 0;else if(null!=r&&r.tuneInGoal&&_-i.partTarget>r.tuneInGoal)this.warn("CDN Tune-in goal increased from: "+r.tuneInGoal+" to: "+P+" with playlist age: "+i.age),P=0;else{var C=Math.floor(P/i.targetduration);y+=C,void 0!==E&&(E+=Math.round(P%i.targetduration/i.partTarget)),this.log("CDN Tune-in age: "+i.ageHeader+"s last advanced "+D.toFixed(2)+"s goal: "+P+" skip sn "+C+" to part "+E)}i.tuneInGoal=P}if(g=this.getDeliveryDirectives(i,t.deliveryDirectives,y,E),T||!R)return i.requestScheduled=a,void this.loadingPlaylist(u,g)}else(i.canBlockReload||i.canSkipUntil)&&(g=this.getDeliveryDirectives(i,t.deliveryDirectives,y,E));g&&void 0!==y&&i.canBlockReload&&(i.requestScheduled=n.loading.first+Math.max(p-2*s,p/2)),this.scheduleLoading(u,g,i)}else this.clearTimer()},r.scheduleLoading=function(e,t,r){var i=this,n=r||e.details;if(n){var a=self.performance.now(),s=n.requestScheduled;if(a>=s)this.loadingPlaylist(e,t);else{var o=s-a;this.log("reload live playlist "+(e.name||e.bitrate+"bps")+" in "+Math.round(o)+" ms"),this.clearTimer(),this.timer=self.setTimeout((function(){return i.loadingPlaylist(e,t)}),o)}}else this.loadingPlaylist(e,t)},r.getDeliveryDirectives=function(e,t,r,i){var n=tt(e);return null!=t&&t.skip&&e.deltaUpdateFailed&&(r=t.msn,i=t.part,n=Je),new rt(r,i,n)},r.checkRetry=function(e){var t=this,r=e.details,i=St(e),n=e.errorAction,a=n||{},s=a.action,o=a.retryCount,l=void 0===o?0:o,u=a.retryConfig,d=!!n&&!!u&&(s===_t||!n.resolved&&s===bt);if(d){var h;if(l>=u.maxNumRetry)return!1;if(i&&null!=(h=e.context)&&h.deliveryDirectives)this.warn("Retrying playlist loading "+(l+1)+"/"+u.maxNumRetry+' after "'+r+'" without delivery-directives'),this.loadPlaylist();else{var f=Lt(u,l);this.clearTimer(),this.timer=self.setTimeout((function(){return t.loadPlaylist()}),f),this.warn("Retrying playlist loading "+(l+1)+"/"+u.maxNumRetry+' after "'+r+'" in '+f+"ms")}e.levelRetry=!0,n.resolved=!0}return d},t}(N);function la(e,t){if(e.length!==t.length)return!1;for(var r=0;r-1)n=a[o];else{var l=dt(s,this.tracks);n=this.tracks[l]}}var u=this.findTrackId(n);-1===u&&n&&(u=this.findTrackId(null));var d={audioTracks:a};this.log("Updating audio tracks, "+a.length+" track(s) found in group(s): "+(null==r?void 0:r.join(","))),this.hls.trigger(b.AUDIO_TRACKS_UPDATED,d);var h=this.trackId;if(-1!==u&&-1===h)this.setAudioTrack(u);else if(a.length&&-1===h){var f,c=new Error("No audio track selected for current audio group-ID(s): "+(null==(f=this.groupIds)?void 0:f.join(","))+" track count: "+a.length);this.warn(c.message),this.hls.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.AUDIO_TRACK_LOAD_ERROR,fatal:!0,error:c})}}}},r.onError=function(e,t){!t.fatal&&t.context&&(t.context.type!==P||t.context.id!==this.trackId||this.groupIds&&-1===this.groupIds.indexOf(t.context.groupId)||this.checkRetry(t))},r.setAudioOption=function(e){var t=this.hls;if(t.config.audioPreference=e,e){var r=this.allAudioTracks;if(this.selectDefaultTrack=!1,r.length){var i=this.currentTrack;if(i&&ht(e,i,ft))return i;var n=dt(e,this.tracksInGroup,ft);if(n>-1){var a=this.tracksInGroup[n];return this.setAudioTrack(n),a}if(i){var s=t.loadLevel;-1===s&&(s=t.firstAutoLevel);var o=function(e,t,r,i,n){var a=t[i],s=t.reduce((function(e,t,r){var i=t.uri;return(e[i]||(e[i]=[])).push(r),e}),{})[a.uri];s.length>1&&(i=Math.max.apply(Math,s));var o=a.videoRange,l=a.frameRate,u=a.codecSet.substring(0,4),d=ct(t,i,(function(t){if(t.videoRange!==o||t.frameRate!==l||t.codecSet.substring(0,4)!==u)return!1;var i=t.audioGroups,a=r.filter((function(e){return!i||-1!==i.indexOf(e.groupId)}));return dt(e,a,n)>-1}));return d>-1?d:ct(t,i,(function(t){var i=t.audioGroups,a=r.filter((function(e){return!i||-1!==i.indexOf(e.groupId)}));return dt(e,a,n)>-1}))}(e,t.levels,r,s,ft);if(-1===o)return null;t.nextLoadLevel=o}if(e.channels||e.audioCodec){var l=dt(e,r);if(l>-1)return r[l]}}}return null},r.setAudioTrack=function(e){var t=this.tracksInGroup;if(e<0||e>=t.length)this.warn("Invalid audio track id: "+e);else{this.selectDefaultTrack=!1;var r=this.currentTrack,i=t[e],n=i.details&&!i.details.live;if(!(e===this.trackId&&i===r&&n||(this.log("Switching to audio-track "+e+' "'+i.name+'" lang:'+i.lang+" group:"+i.groupId+" channels:"+i.channels),this.trackId=e,this.currentTrack=i,this.hls.trigger(b.AUDIO_TRACK_SWITCHING,d({},i)),n))){var a=this.switchParams(i.url,null==r?void 0:r.details,i.details);this.loadPlaylist(a)}}},r.findTrackId=function(e){for(var t=this.tracksInGroup,r=0;r":"\n"+this.list("video")+"\n"+this.list("audio")+"\n"+this.list("audiovideo")+"}"},t.list=function(e){var t,r;return null!=(t=this.queues)&&t[e]||null!=(r=this.tracks)&&r[e]?e+": ("+this.listSbInfo(e)+") "+this.listOps(e):""},t.listSbInfo=function(e){var t,r=null==(t=this.tracks)?void 0:t[e],i=null==r?void 0:r.buffer;return i?"SourceBuffer"+(i.updating?" updating":"")+(r.ended?" ended":"")+(r.ending?" ending":""):"none"},t.listOps=function(e){var t;return(null==(t=this.queues)?void 0:t[e].map((function(e){return e.label})).join(", "))||""},e}(),ca=/(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/,ga="HlsJsTrackRemovedError",va=function(e){function t(t){var r;return(r=e.call(this,t)||this).name=ga,r}return o(t,e),t}(c(Error)),ma=function(e){function t(t,r){var i,n;return(i=e.call(this,"buffer-controller",t.logger)||this).hls=void 0,i.fragmentTracker=void 0,i.details=null,i._objectUrl=null,i.operationQueue=null,i.bufferCodecEventsTotal=0,i.media=null,i.mediaSource=null,i.lastMpegAudioChunk=null,i.blockedAudioAppend=null,i.lastVideoAppendEnd=0,i.appendSource=void 0,i.transferData=void 0,i.overrides=void 0,i.appendErrors={audio:0,video:0,audiovideo:0},i.tracks={},i.sourceBuffers=[[null,null],[null,null]],i._onEndStreaming=function(e){var t;i.hls&&"open"===(null==(t=i.mediaSource)?void 0:t.readyState)&&i.hls.pauseBuffering()},i._onStartStreaming=function(e){i.hls&&i.hls.resumeBuffering()},i._onMediaSourceOpen=function(e){var t=i,r=t.media,n=t.mediaSource;e&&i.log("Media source opened"),r&&n&&(n.removeEventListener("sourceopen",i._onMediaSourceOpen),r.removeEventListener("emptied",i._onMediaEmptied),i.updateDuration(),i.hls.trigger(b.MEDIA_ATTACHED,{media:r,mediaSource:n}),null!==i.mediaSource&&i.checkPendingTracks())},i._onMediaSourceClose=function(){i.log("Media source closed")},i._onMediaSourceEnded=function(){i.log("Media source ended")},i._onMediaEmptied=function(){var e=i,t=e.mediaSrc,r=e._objectUrl;t!==r&&i.error("Media element src was set while attaching MediaSource ("+r+" > "+t+")")},i.hls=t,i.fragmentTracker=r,i.appendSource=(n=W(t.config.preferManagedMediaSource),"undefined"!=typeof self&&n===self.ManagedMediaSource),i.initTracks(),i.registerListeners(),i}o(t,e);var r=t.prototype;return r.hasSourceTypes=function(){return Object.keys(this.tracks).length>0},r.destroy=function(){this.unregisterListeners(),this.details=null,this.lastMpegAudioChunk=this.blockedAudioAppend=null,this.transferData=this.overrides=void 0,this.operationQueue&&(this.operationQueue.destroy(),this.operationQueue=null),this.hls=this.fragmentTracker=null,this._onMediaSourceOpen=this._onMediaSourceClose=null,this._onMediaSourceEnded=null,this._onStartStreaming=this._onEndStreaming=null},r.registerListeners=function(){var e=this.hls;e.on(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.on(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.MANIFEST_PARSED,this.onManifestParsed,this),e.on(b.BUFFER_RESET,this.onBufferReset,this),e.on(b.BUFFER_APPENDING,this.onBufferAppending,this),e.on(b.BUFFER_CODECS,this.onBufferCodecs,this),e.on(b.BUFFER_EOS,this.onBufferEos,this),e.on(b.BUFFER_FLUSHING,this.onBufferFlushing,this),e.on(b.LEVEL_UPDATED,this.onLevelUpdated,this),e.on(b.FRAG_PARSED,this.onFragParsed,this),e.on(b.FRAG_CHANGED,this.onFragChanged,this),e.on(b.ERROR,this.onError,this)},r.unregisterListeners=function(){var e=this.hls;e.off(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.off(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.MANIFEST_PARSED,this.onManifestParsed,this),e.off(b.BUFFER_RESET,this.onBufferReset,this),e.off(b.BUFFER_APPENDING,this.onBufferAppending,this),e.off(b.BUFFER_CODECS,this.onBufferCodecs,this),e.off(b.BUFFER_EOS,this.onBufferEos,this),e.off(b.BUFFER_FLUSHING,this.onBufferFlushing,this),e.off(b.LEVEL_UPDATED,this.onLevelUpdated,this),e.off(b.FRAG_PARSED,this.onFragParsed,this),e.off(b.FRAG_CHANGED,this.onFragChanged,this),e.off(b.ERROR,this.onError,this)},r.transferMedia=function(){var e=this,t=this.media,r=this.mediaSource;if(!t)return null;var i={};if(this.operationQueue){var n=this.isUpdating();n||this.operationQueue.removeBlockers();var s=this.isQueued();(n||s)&&this.warn("Transfering MediaSource with"+(s?" operations in queue":"")+(n?" updating SourceBuffer(s)":"")+" "+this.operationQueue),this.operationQueue.destroy()}var o=this.transferData;return!this.sourceBufferCount&&o&&o.mediaSource===r?a(i,o.tracks):this.sourceBuffers.forEach((function(t){var r=t[0];r&&(i[r]=a({},e.tracks[r]),e.removeBuffer(r)),t[0]=t[1]=null})),{media:t,mediaSource:r,tracks:i}},r.initTracks=function(){this.sourceBuffers=[[null,null],[null,null]],this.tracks={},this.resetQueue(),this.resetAppendErrors(),this.lastMpegAudioChunk=this.blockedAudioAppend=null,this.lastVideoAppendEnd=0},r.onManifestLoading=function(){this.bufferCodecEventsTotal=0,this.details=null},r.onManifestParsed=function(e,t){var r,i=2;(t.audio&&!t.video||!t.altAudio)&&(i=1),this.bufferCodecEventsTotal=i,this.log(i+" bufferCodec event(s) expected."),null!=(r=this.transferData)&&r.mediaSource&&this.sourceBufferCount&&i&&this.bufferCreated()},r.onMediaAttaching=function(e,t){var r=this.media=t.media,i=W(this.appendSource);if(this.transferData=this.overrides=void 0,r&&i){var n=!!t.mediaSource;(n||t.overrides)&&(this.transferData=t,this.overrides=t.overrides);var a=this.mediaSource=t.mediaSource||new i;if(this.assignMediaSource(a),n)this._objectUrl=r.src,this.attachTransferred();else{var s=this._objectUrl=self.URL.createObjectURL(a);if(this.appendSource)try{r.removeAttribute("src");var o=self.ManagedMediaSource;r.disableRemotePlayback=r.disableRemotePlayback||o&&a instanceof o,pa(r),function(e,t){var r=self.document.createElement("source");r.type="video/mp4",r.src=t,e.appendChild(r)}(r,s),r.load()}catch(e){r.src=s}else r.src=s}r.addEventListener("emptied",this._onMediaEmptied)}},r.assignMediaSource=function(e){var t,r;this.log(((null==(t=this.transferData)?void 0:t.mediaSource)===e?"transferred":"created")+" media source: "+(null==(r=e.constructor)?void 0:r.name)),e.addEventListener("sourceopen",this._onMediaSourceOpen),e.addEventListener("sourceended",this._onMediaSourceEnded),e.addEventListener("sourceclose",this._onMediaSourceClose),this.appendSource&&(e.addEventListener("startstreaming",this._onStartStreaming),e.addEventListener("endstreaming",this._onEndStreaming))},r.attachTransferred=function(){var e=this,t=this.media,r=this.transferData;if(r&&t){var i=this.tracks,n=r.tracks,a=n?Object.keys(n):null,s=a?a.length:0,o=function(){e.media&&e.mediaSourceOpenOrEnded&&e._onMediaSourceOpen()};if(n&&a&&s){if(!this.tracksReady)return this.hls.config.startFragPrefetch=!0,void this.log("attachTransferred: waiting for SourceBuffer track info");if(this.log("attachTransferred: (bufferCodecEventsTotal "+this.bufferCodecEventsTotal+")\nrequired tracks: "+st(i,(function(e,t){return"initSegment"===e?void 0:t}))+";\ntransfer tracks: "+st(n,(function(e,t){return"initSegment"===e?void 0:t}))+"}"),!j(n,i)){r.mediaSource=null,r.tracks=void 0;var l=t.currentTime,u=this.details,d=Math.max(l,(null==u?void 0:u.fragments[0].start)||0);return d-l>1?void this.log("attachTransferred: waiting for playback to reach new tracks start time "+l+" -> "+d):(this.warn('attachTransferred: resetting MediaSource for incompatible tracks ("'+Object.keys(n)+'"->"'+Object.keys(i)+'") start time: '+d+" currentTime: "+l),this.onMediaDetaching(b.MEDIA_DETACHING,{}),this.onMediaAttaching(b.MEDIA_ATTACHING,r),void(t.currentTime=d))}this.transferData=void 0,a.forEach((function(t){var r=t,i=n[r];if(i){var a=i.buffer;if(a){var s=e.fragmentTracker,o=i.id;if(s.hasFragments(o)||s.hasParts(o)){var l=ir.getBuffered(a);s.detectEvictedFragments(r,l,o,null,!0)}var u=ya(r),d=[r,a];e.sourceBuffers[u]=d,a.updating&&e.operationQueue&&e.operationQueue.prependBlocker(r),e.trackSourceBuffer(r,i)}}})),o(),this.bufferCreated()}else this.log("attachTransferred: MediaSource w/o SourceBuffers"),o()}},r.onMediaDetaching=function(e,t){var r=this,i=!!t.transferMedia;this.transferData=this.overrides=void 0;var n=this.media,a=this.mediaSource,s=this._objectUrl;if(a){if(this.log("media source "+(i?"transferring":"detaching")),i)this.sourceBuffers.forEach((function(e){var t=e[0];t&&r.removeBuffer(t)})),this.resetQueue();else{if(this.mediaSourceOpenOrEnded){var o="open"===a.readyState;try{for(var l=a.sourceBuffers,u=l.length;u--;)o&&l[u].abort(),a.removeSourceBuffer(l[u]);o&&a.endOfStream()}catch(e){this.warn("onMediaDetaching: "+e.message+" while calling endOfStream")}}this.sourceBufferCount&&this.onBufferReset()}a.removeEventListener("sourceopen",this._onMediaSourceOpen),a.removeEventListener("sourceended",this._onMediaSourceEnded),a.removeEventListener("sourceclose",this._onMediaSourceClose),this.appendSource&&(a.removeEventListener("startstreaming",this._onStartStreaming),a.removeEventListener("endstreaming",this._onEndStreaming)),this.mediaSource=null,this._objectUrl=null}n&&(n.removeEventListener("emptied",this._onMediaEmptied),i||(s&&self.URL.revokeObjectURL(s),this.mediaSrc===s?(n.removeAttribute("src"),this.appendSource&&pa(n),n.load()):this.warn("media|source.src was changed by a third party - skip cleanup")),this.media=null),this.hls.trigger(b.MEDIA_DETACHED,t)},r.onBufferReset=function(){var e=this;this.sourceBuffers.forEach((function(t){var r=t[0];r&&e.resetBuffer(r)})),this.initTracks()},r.resetBuffer=function(e){var t,r=null==(t=this.tracks[e])?void 0:t.buffer;if(this.removeBuffer(e),r)try{var i;null!=(i=this.mediaSource)&&i.sourceBuffers.length&&this.mediaSource.removeSourceBuffer(r)}catch(t){this.warn("onBufferReset "+e,t)}delete this.tracks[e]},r.removeBuffer=function(e){this.removeBufferListeners(e),this.sourceBuffers[ya(e)]=[null,null];var t=this.tracks[e];t&&(t.buffer=void 0)},r.resetQueue=function(){this.operationQueue&&this.operationQueue.destroy(),this.operationQueue=new fa(this.tracks)},r.onBufferCodecs=function(e,t){var r=this,i=this.tracks,n=Object.keys(t);this.log('BUFFER_CODECS: "'+n+'" (current SB count '+this.sourceBufferCount+")");var a="audiovideo"in t&&(i.audio||i.video)||i.audiovideo&&("audio"in t||"video"in t),s=!a&&this.sourceBufferCount&&this.media&&n.some((function(e){return!i[e]}));a||s?this.warn('Unsupported transition between "'+Object.keys(i)+'" and "'+n+'" SourceBuffers'):(n.forEach((function(e){var n,a,s,o=t[e],l=o.id,u=o.codec,d=o.levelCodec,h=o.container,f=o.metadata,c=o.supplemental,g=i[e],v=null==(n=r.transferData)||null==(a=n.tracks)?void 0:a[e],m=null!=v&&v.buffer?v:g,p=(null==m?void 0:m.pendingCodec)||(null==m?void 0:m.codec),y=null==m?void 0:m.levelCodec;g||(g=i[e]={buffer:void 0,listeners:[],codec:u,supplemental:c,container:h,levelCodec:d,metadata:f,id:l});var E=Ge(p,y),T=null==E?void 0:E.replace(ca,"$1"),S=Ge(u,d),A=null==(s=S)?void 0:s.replace(ca,"$1");S&&E&&T!==A&&("audio"===e.slice(0,5)&&(S=Be(S,r.appendSource)),r.log("switching codec "+p+" to "+S),S!==(g.pendingCodec||g.codec)&&(g.pendingCodec=S),g.container=h,r.appendChangeType(e,h,S))})),(this.tracksReady||this.sourceBufferCount)&&(t.tracks=this.sourceBufferTracks),this.sourceBufferCount||this.mediaSourceOpenOrEnded&&this.checkPendingTracks())},r.appendChangeType=function(e,t,r){var i=this,n=t+";codecs="+r,a={label:"change-type="+n,execute:function(){var a=i.tracks[e];if(a){var s=a.buffer;null!=s&&s.changeType&&(i.log("changing "+e+" sourceBuffer type to "+n),s.changeType(n),a.codec=r,a.container=t)}i.shiftAndExecuteNext(e)},onStart:function(){},onComplete:function(){},onError:function(t){i.warn("Failed to change "+e+" SourceBuffer type",t)}};this.append(a,e,this.isPending(this.tracks[e]))},r.blockAudio=function(e){var t,r=this,i=e.start,n=i+.05*e.duration;if(!0!==(null==(t=this.fragmentTracker.getAppendedFrag(i,w))?void 0:t.gap)){var a={label:"block-audio",execute:function(){var e,t=r.tracks.video;(r.lastVideoAppendEnd>n||null!=t&&t.buffer&&ir.isBuffered(t.buffer,n)||!0===(null==(e=r.fragmentTracker.getAppendedFrag(n,w))?void 0:e.gap))&&(r.blockedAudioAppend=null,r.shiftAndExecuteNext("audio"))},onStart:function(){},onComplete:function(){},onError:function(e){r.warn("Error executing block-audio operation",e)}};this.blockedAudioAppend={op:a,frag:e},this.append(a,"audio",!0)}},r.unblockAudio=function(){var e=this.blockedAudioAppend,t=this.operationQueue;e&&t&&(this.blockedAudioAppend=null,t.unblockAudio(e.op))},r.onBufferAppending=function(e,t){var r=this,i=this.tracks,n=t.data,a=t.type,s=t.parent,o=t.frag,l=t.part,u=t.chunkMeta,d=t.offset,h=u.buffering[a],f=o.sn,c=o.cc,g=self.performance.now();h.start=g;var v=o.stats.buffering,m=l?l.stats.buffering:null;0===v.start&&(v.start=g),m&&0===m.start&&(m.start=g);var p=i.audio,y=!1;"audio"===a&&"audio/mpeg"===(null==p?void 0:p.container)&&(y=!this.lastMpegAudioChunk||1===u.id||this.lastMpegAudioChunk.sn!==u.sn,this.lastMpegAudioChunk=u);var E=i.video,T=null==E?void 0:E.buffer;if(T&&"initSegment"!==f){var S=l||o,L=this.blockedAudioAppend;if("audio"!==a||"main"===s||this.blockedAudioAppend){if("video"===a){var R=S.end;if(L){var D=L.frag.start;(R>D||R=r.hls.config.appendErrorMaxRetry||n)&&(i.fatal=!0)}r.hls.trigger(b.ERROR,i)}};this.append(O,a,this.isPending(this.tracks[a]))},r.getFlushOp=function(e,t,r){var i=this;return this.log('queuing "'+e+'" remove '+t+"-"+r),{label:"remove",execute:function(){i.removeExecutor(e,t,r)},onStart:function(){},onComplete:function(){i.hls.trigger(b.BUFFER_FLUSHED,{type:e})},onError:function(n){i.warn("Failed to remove "+t+"-"+r+' from "'+e+'" SourceBuffer',n)}}},r.onBufferFlushing=function(e,t){var r=this,i=t.type,n=t.startOffset,a=t.endOffset;i?this.append(this.getFlushOp(i,n,a),i):this.sourceBuffers.forEach((function(e){var t=e[0];t&&r.append(r.getFlushOp(t,n,a),t)}))},r.onFragParsed=function(e,t){var r=this,i=t.frag,n=t.part,a=[],s=n?n.elementaryStreams:i.elementaryStreams;s[J]?a.push("audiovideo"):(s[z]&&a.push("audio"),s[$]&&a.push("video")),0===a.length&&this.warn("Fragments must have at least one ElementaryStreamType set. type: "+i.type+" level: "+i.level+" sn: "+i.sn),this.blockBuffers((function(){var e=self.performance.now();i.stats.buffering.end=e,n&&(n.stats.buffering.end=e);var t=n?n.stats:i.stats;r.hls.trigger(b.FRAG_BUFFERED,{frag:i,part:n,stats:t,id:i.type})}),a).catch((function(e){r.warn("Fragment buffered callback "+e),r.stepOperationQueue(r.sourceBufferTypes)}))},r.onFragChanged=function(e,t){this.trimBuffers()},r.onBufferEos=function(e,t){var r,i=this;this.sourceBuffers.forEach((function(e){var r=e[0];if(r){var n=i.tracks[r];t.type&&t.type!==r||(n.ending=!0,n.ended||(n.ended=!0,i.log(r+" buffer reached EOS")))}}));var n=!1!==(null==(r=this.overrides)?void 0:r.endOfStream);this.sourceBufferCount>0&&!this.sourceBuffers.some((function(e){var t,r=e[0];return r&&!(null!=(t=i.tracks[r])&&t.ended)}))&&(n?(this.log("Queueing EOS"),this.blockUntilOpen((function(){i.tracksEnded();var e=i.mediaSource;e&&"open"===e.readyState?(i.log("Calling mediaSource.endOfStream()"),e.endOfStream(),i.hls.trigger(b.BUFFERED_TO_END,void 0)):e&&i.log("Could not call mediaSource.endOfStream(). mediaSource.readyState: "+e.readyState)}))):(this.tracksEnded(),this.hls.trigger(b.BUFFERED_TO_END,void 0)))},r.tracksEnded=function(){var e=this;this.sourceBuffers.forEach((function(t){var r=t[0];if(null!==r){var i=e.tracks[r];i&&(i.ending=!1)}}))},r.onLevelUpdated=function(e,t){var r=t.details;r.fragments.length&&(this.details=r,this.updateDuration())},r.updateDuration=function(){var e=this;this.blockUntilOpen((function(){var t=e.getDurationAndRange();t&&e.updateMediaSource(t)}))},r.onError=function(e,t){if(t.details===k.BUFFER_APPEND_ERROR&&t.frag){var r,i=null==(r=t.errorAction)?void 0:r.nextAutoLevel;A(i)&&i!==t.frag.level&&this.resetAppendErrors()}},r.resetAppendErrors=function(){this.appendErrors={audio:0,video:0,audiovideo:0}},r.trimBuffers=function(){var e=this.hls,t=this.details,r=this.media;if(r&&null!==t&&this.sourceBufferCount){var i=e.config,n=r.currentTime,a=t.levelTargetDuration,s=t.live&&null!==i.liveBackBufferLength?i.liveBackBufferLength:i.backBufferLength;if(A(s)&&s>=0){var o=Math.max(s,a),l=Math.floor(n/a)*a-o;this.flushBackBuffer(n,a,l)}if(A(i.frontBufferFlushThreshold)&&i.frontBufferFlushThreshold>0){var u=Math.max(i.maxBufferLength,i.frontBufferFlushThreshold),d=Math.max(u,a),h=Math.floor(n/a)*a+d;this.flushFrontBuffer(n,a,h)}}},r.flushBackBuffer=function(e,t,r){var i=this;this.sourceBuffers.forEach((function(e){var t=e[0],n=e[1];if(n){var a=ir.getBuffered(n);if(a.length>0&&r>a.start(0)){var s;i.hls.trigger(b.BACK_BUFFER_REACHED,{bufferEnd:r});var o=i.tracks[t];if(null!=(s=i.details)&&s.live)i.hls.trigger(b.LIVE_BACK_BUFFER_REACHED,{bufferEnd:r});else if(null!=o&&o.ended)return void i.log("Cannot flush "+t+" back buffer while SourceBuffer is in ended state");i.hls.trigger(b.BUFFER_FLUSHING,{startOffset:0,endOffset:r,type:t})}}}))},r.flushFrontBuffer=function(e,t,r){var i=this;this.sourceBuffers.forEach((function(t){var n=t[0],a=t[1];if(a){var s=ir.getBuffered(a),o=s.length;if(o<2)return;var l=s.start(o-1),u=s.end(o-1);if(r>l||e>=l&&e<=u)return;i.hls.trigger(b.BUFFER_FLUSHING,{startOffset:l,endOffset:1/0,type:n})}}))},r.getDurationAndRange=function(){var e,t=this.details,r=this.mediaSource;if(!t||!this.media||"open"!==(null==r?void 0:r.readyState))return null;var i=t.edge;if(t.live&&this.hls.config.liveDurationInfinity){if(t.fragments.length&&t.live&&r.setLiveSeekableRange){var n=Math.max(0,t.fragmentStart);return{duration:1/0,start:n,end:Math.max(n,i)}}return{duration:1/0}}var a=null==(e=this.overrides)?void 0:e.duration;if(a)return A(a)?{duration:a}:null;var s=this.media.duration;return i>(A(r.duration)?r.duration:0)&&i>s||!A(s)?{duration:i}:null},r.updateMediaSource=function(e){var t=e.duration,r=e.start,i=e.end,n=this.mediaSource;this.media&&n&&"open"===n.readyState&&(n.duration!==t&&(A(t)&&this.log("Updating MediaSource duration to "+t.toFixed(3)),n.duration=t),void 0!==r&&void 0!==i&&(this.log("MediaSource duration is set to "+n.duration+". Setting seekable range to "+r+"-"+i+"."),n.setLiveSeekableRange(r,i)))},r.checkPendingTracks=function(){var e=this.bufferCodecEventsTotal,t=this.pendingTrackCount,r=this.tracks;if(this.log("checkPendingTracks (pending: "+t+" codec events expected: "+e+") "+st(r)),this.tracksReady){var i,n=null==(i=this.transferData)?void 0:i.tracks;n&&Object.keys(n).length?this.attachTransferred():this.createSourceBuffers()}},r.bufferCreated=function(){var e=this;if(this.sourceBufferCount){var t={};this.sourceBuffers.forEach((function(r){var i=r[0],n=r[1];if(i){var a=e.tracks[i];t[i]={buffer:n,container:a.container,codec:a.codec,supplemental:a.supplemental,levelCodec:a.levelCodec,id:a.id,metadata:a.metadata}}})),this.hls.trigger(b.BUFFER_CREATED,{tracks:t}),this.log("SourceBuffers created. Running queue: "+this.operationQueue),this.sourceBuffers.forEach((function(t){var r=t[0];e.executeNext(r)}))}else{var r=new Error("could not create source buffer for media codec(s)");this.hls.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.BUFFER_INCOMPATIBLE_CODECS_ERROR,fatal:!0,error:r,reason:r.message})}},r.createSourceBuffers=function(){var e=this.tracks,t=this.sourceBuffers,r=this.mediaSource;if(!r)throw new Error("createSourceBuffers called when mediaSource was null");for(var i in e){var n=i,a=e[n];if(this.isPending(a)){var s=this.getTrackCodec(a,n),o=a.container+";codecs="+s;a.codec=s,this.log("creating sourceBuffer("+o+")"+(this.currentOp(n)?" Queued":"")+" "+st(a));try{var l=r.addSourceBuffer(o),u=ya(n),d=[n,l];t[u]=d,a.buffer=l}catch(e){var h;return this.error("error while trying to add sourceBuffer: "+e.message),this.shiftAndExecuteNext(n),null==(h=this.operationQueue)||h.removeBlockers(),delete this.tracks[n],void this.hls.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.BUFFER_ADD_CODEC_ERROR,fatal:!1,error:e,sourceBufferName:n,mimeType:o,parent:a.id})}this.trackSourceBuffer(n,a)}}this.bufferCreated()},r.getTrackCodec=function(e,t){var r=e.supplemental,i=e.codec;r&&("video"===t||"audiovideo"===t)&&we(r,"video")&&(i=function(e,t){var r=[];if(e)for(var i=e.split(","),n=0;n=r&&(this.log("Updating "+i+" SourceBuffer timestampOffset to "+t+" (sn: "+n+" cc: "+a+")"),e.timestampOffset=t)},r.removeExecutor=function(e,t,r){var i=this.media,n=this.mediaSource,a=this.tracks[e],s=null==a?void 0:a.buffer;if(!i||!n||!s)return this.warn("Attempting to remove from the "+e+" SourceBuffer, but it does not exist"),void this.shiftAndExecuteNext(e);var o=A(i.duration)?i.duration:1/0,l=A(n.duration)?n.duration:1/0,u=Math.max(0,t),d=Math.min(r,o,l);d>u&&(!a.ending||a.ended)?(a.ended=!1,this.log("Removing ["+u+","+d+"] from the "+e+" SourceBuffer"),s.remove(u,d)):this.shiftAndExecuteNext(e)},r.appendExecutor=function(e,t){var r=this.tracks[t],i=null==r?void 0:r.buffer;if(!i)throw new va("Attempting to append to the "+t+" SourceBuffer, but it does not exist");r.ending=!1,r.ended=!1,i.appendBuffer(e)},r.blockUntilOpen=function(e){var t=this;if(this.isUpdating()||this.isQueued())this.blockBuffers(e).catch((function(e){t.warn("SourceBuffer blocked callback "+e),t.stepOperationQueue(t.sourceBufferTypes)}));else try{e()}catch(e){this.warn("Callback run without blocking "+this.operationQueue+" "+e)}},r.isUpdating=function(){return this.sourceBuffers.some((function(e){var t=e[0],r=e[1];return t&&r.updating}))},r.isQueued=function(){var e=this;return this.sourceBuffers.some((function(t){var r=t[0];return r&&!!e.currentOp(r)}))},r.isPending=function(e){return!!e&&!e.buffer},r.blockBuffers=function(e,t){var r=this;if(void 0===t&&(t=this.sourceBufferTypes),!t.length)return this.log("Blocking operation requested, but no SourceBuffers exist"),Promise.resolve().then(e);var i=this.operationQueue,n=t.map((function(e){return r.appendBlocker(e)}));return t.length>1&&!!this.blockedAudioAppend&&this.unblockAudio(),Promise.all(n).then((function(t){i===r.operationQueue&&(e(),r.stepOperationQueue(r.sourceBufferTypes))}))},r.stepOperationQueue=function(e){var t=this;e.forEach((function(e){var r,i=null==(r=t.tracks[e])?void 0:r.buffer;i&&!i.updating&&t.shiftAndExecuteNext(e)}))},r.append=function(e,t,r){this.operationQueue&&this.operationQueue.append(e,t,r)},r.appendBlocker=function(e){if(this.operationQueue)return this.operationQueue.appendBlocker(e)},r.currentOp=function(e){return this.operationQueue?this.operationQueue.current(e):null},r.executeNext=function(e){e&&this.operationQueue&&this.operationQueue.executeNext(e)},r.shiftAndExecuteNext=function(e){this.operationQueue&&this.operationQueue.shiftAndExecuteNext(e)},r.addBufferListener=function(e,t,r){var i=this.tracks[e];if(i){var n=i.buffer;if(n){var a=r.bind(this,e);i.listeners.push({event:t,listener:a}),n.addEventListener(t,a)}}},r.removeBufferListeners=function(e){var t=this.tracks[e];if(t){var r=t.buffer;r&&(t.listeners.forEach((function(e){r.removeEventListener(e.event,e.listener)})),t.listeners.length=0)}},i(t,[{key:"mediaSourceOpenOrEnded",get:function(){var e,t=null==(e=this.mediaSource)?void 0:e.readyState;return"open"===t||"ended"===t}},{key:"sourceBufferTracks",get:function(){var e=this;return Object.keys(this.tracks).reduce((function(t,r){var i=e.tracks[r];return t[r]={id:i.id,container:i.container,codec:i.codec,levelCodec:i.levelCodec},t}),{})}},{key:"bufferedToEnd",get:function(){var e=this;return this.sourceBufferCount>0&&!this.sourceBuffers.some((function(t){var r,i,n=t[0];return n&&(!(null!=(r=e.tracks[n])&&r.ended)||(null==(i=e.tracks[n])?void 0:i.ending))}))}},{key:"tracksReady",get:function(){var e=this.pendingTrackCount;return e>0&&(e>=this.bufferCodecEventsTotal||this.isPending(this.tracks.audiovideo))}},{key:"mediaSrc",get:function(){var e,t,r=(null==(e=this.media)||null==(t=e.querySelector)?void 0:t.call(e,"source"))||this.media;return null==r?void 0:r.src}},{key:"pendingTrackCount",get:function(){var e=this;return Object.keys(this.tracks).reduce((function(t,r){return t+(e.isPending(e.tracks[r])?1:0)}),0)}},{key:"sourceBufferCount",get:function(){return this.sourceBuffers.reduce((function(e,t){return e+(t[0]?1:0)}),0)}},{key:"sourceBufferTypes",get:function(){return this.sourceBuffers.map((function(e){return e[0]})).filter((function(e){return!!e}))}}])}(N);function pa(e){var t=e.querySelectorAll("source");[].slice.call(t).forEach((function(t){e.removeChild(t)}))}function ya(e){return"audio"===e?1:0}var Ea,Ta=function(){function e(e){this.hls=void 0,this.autoLevelCapping=void 0,this.firstLevel=void 0,this.media=void 0,this.restrictedLevels=void 0,this.timer=void 0,this.clientRect=void 0,this.streamController=void 0,this.hls=e,this.autoLevelCapping=Number.POSITIVE_INFINITY,this.firstLevel=-1,this.media=null,this.restrictedLevels=[],this.timer=void 0,this.clientRect=null,this.registerListeners()}var t=e.prototype;return t.setStreamController=function(e){this.streamController=e},t.destroy=function(){this.hls&&this.unregisterListener(),this.timer&&this.stopCapping(),this.media=null,this.clientRect=null,this.hls=this.streamController=null},t.registerListeners=function(){var e=this.hls;e.on(b.FPS_DROP_LEVEL_CAPPING,this.onFpsDropLevelCapping,this),e.on(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.on(b.MANIFEST_PARSED,this.onManifestParsed,this),e.on(b.LEVELS_UPDATED,this.onLevelsUpdated,this),e.on(b.BUFFER_CODECS,this.onBufferCodecs,this),e.on(b.MEDIA_DETACHING,this.onMediaDetaching,this)},t.unregisterListener=function(){var e=this.hls;e.off(b.FPS_DROP_LEVEL_CAPPING,this.onFpsDropLevelCapping,this),e.off(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.off(b.MANIFEST_PARSED,this.onManifestParsed,this),e.off(b.LEVELS_UPDATED,this.onLevelsUpdated,this),e.off(b.BUFFER_CODECS,this.onBufferCodecs,this),e.off(b.MEDIA_DETACHING,this.onMediaDetaching,this)},t.onFpsDropLevelCapping=function(e,t){var r=this.hls.levels[t.droppedLevel];this.isLevelAllowed(r)&&this.restrictedLevels.push({bitrate:r.bitrate,height:r.height,width:r.width})},t.onMediaAttaching=function(e,t){this.media=t.media instanceof HTMLVideoElement?t.media:null,this.clientRect=null,this.timer&&this.hls.levels.length&&this.detectPlayerSize()},t.onManifestParsed=function(e,t){var r=this.hls;this.restrictedLevels=[],this.firstLevel=t.firstLevel,r.config.capLevelToPlayerSize&&t.video&&this.startCapping()},t.onLevelsUpdated=function(e,t){this.timer&&A(this.autoLevelCapping)&&this.detectPlayerSize()},t.onBufferCodecs=function(e,t){this.hls.config.capLevelToPlayerSize&&t.video&&this.startCapping()},t.onMediaDetaching=function(){this.stopCapping(),this.media=null},t.detectPlayerSize=function(){if(this.media){if(this.mediaHeight<=0||this.mediaWidth<=0)return void(this.clientRect=null);var e=this.hls.levels;if(e.length){var t=this.hls,r=this.getMaxLevel(e.length-1);r!==this.autoLevelCapping&&t.logger.log("Setting autoLevelCapping to "+r+": "+e[r].height+"p@"+e[r].bitrate+" for media "+this.mediaWidth+"x"+this.mediaHeight),t.autoLevelCapping=r,t.autoLevelEnabled&&t.autoLevelCapping>this.autoLevelCapping&&this.streamController&&this.streamController.nextLevelSwitch(),this.autoLevelCapping=t.autoLevelCapping}}},t.getMaxLevel=function(t){var r=this,i=this.hls.levels;if(!i.length)return-1;var n=i.filter((function(e,i){return r.isLevelAllowed(e)&&i<=t}));return this.clientRect=null,e.getMaxLevelByMediaSize(n,this.mediaWidth,this.mediaHeight)},t.startCapping=function(){this.timer||(this.autoLevelCapping=Number.POSITIVE_INFINITY,self.clearInterval(this.timer),this.timer=self.setInterval(this.detectPlayerSize.bind(this),1e3),this.detectPlayerSize())},t.stopCapping=function(){this.restrictedLevels=[],this.firstLevel=-1,this.autoLevelCapping=Number.POSITIVE_INFINITY,this.timer&&(self.clearInterval(this.timer),this.timer=void 0)},t.getDimensions=function(){if(this.clientRect)return this.clientRect;var e=this.media,t={width:0,height:0};if(e){var r=e.getBoundingClientRect();t.width=r.width,t.height=r.height,t.width||t.height||(t.width=r.right-r.left||e.width||0,t.height=r.bottom-r.top||e.height||0)}return this.clientRect=t,t},t.isLevelAllowed=function(e){return!this.restrictedLevels.some((function(t){return e.bitrate===t.bitrate&&e.width===t.width&&e.height===t.height}))},e.getMaxLevelByMediaSize=function(e,t,r){if(null==e||!e.length)return-1;for(var i,n,a=e.length-1,s=Math.max(t,r),o=0;o=s||l.height>=s)&&(i=l,!(n=e[o+1])||i.width!==n.width||i.height!==n.height)){a=o;break}}return a},i(e,[{key:"mediaWidth",get:function(){return this.getDimensions().width*this.contentScaleFactor}},{key:"mediaHeight",get:function(){return this.getDimensions().height*this.contentScaleFactor}},{key:"contentScaleFactor",get:function(){var e=1;if(!this.hls.config.ignoreDevicePixelRatio)try{e=self.devicePixelRatio}catch(e){}return Math.min(e,this.hls.config.maxDevicePixelRatio)}}])}(),Sa={MANIFEST:"m",AUDIO:"a",VIDEO:"v",MUXED:"av",INIT:"i",CAPTION:"c",TIMED_TEXT:"tt",KEY:"k",OTHER:"o"},Aa={HLS:"h"},La={OBJECT:"CMCD-Object",REQUEST:"CMCD-Request",SESSION:"CMCD-Session",STATUS:"CMCD-Status"},Ra=((Ea={})[La.OBJECT]=["br","d","ot","tb"],Ea[La.REQUEST]=["bl","dl","mtp","nor","nrr","su"],Ea[La.SESSION]=["cid","pr","sf","sid","st","v"],Ea[La.STATUS]=["bs","rtp"],Ea),Ia=function e(t,r){Array.isArray(t)&&(t=t.map((function(t){return t instanceof e?t:new e(t)}))),this.value=t,this.params=r},ka="Dict";function ba(e,t,r,i){return new Error("failed to "+e+' "'+(n=t,(Array.isArray(n)?JSON.stringify(n):n instanceof Map?"Map{}":n instanceof Set?"Set{}":"object"==typeof n?JSON.stringify(n):String(n))+'" as ')+r,{cause:i});var n}function Da(e,t,r){return ba("serialize",e,t,r)}var _a=function(e){this.description=e},Pa="Bare Item",Ca="Boolean",wa="Byte Sequence";function Oa(e){if(!1===ArrayBuffer.isView(e))throw Da(e,wa);return":"+(t=e,btoa(String.fromCharCode.apply(String,t))+":");var t}var xa="Integer";function Ma(e){if(function(e){return e<-999999999999999||99999999999999912)throw Da(e,Na);var r=t.toString();return r.includes(".")?r:r+".0"}var Ba="String",Ga=/[\x00-\x1f\x7f]+/,Ka="Token";function Va(e){var t,r=(t=e).description||t.toString().slice(7,-1);if(!1===/^([a-zA-Z*])([!#$%&'*+\-.^_`|~\w:/]*)$/.test(r))throw Da(r,Ka);return r}function Ha(e){switch(typeof e){case"number":if(!A(e))throw Da(e,Pa);return Number.isInteger(e)?Ma(e):Ua(e);case"string":return function(e){if(Ga.test(e))throw Da(e,Ba);return'"'+e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'}(e);case"symbol":return Va(e);case"boolean":return function(e){if("boolean"!=typeof e)throw Da(e,Ca);return e?"?1":"?0"}(e);case"object":if(e instanceof Date)return function(e){return"@"+Ma(e.getTime()/1e3)}(e);if(e instanceof Uint8Array)return Oa(e);if(e instanceof _a)return Va(e);default:throw Da(e,Pa)}}var Ya="Key";function Wa(e){if(!1===/^[a-z*][a-z0-9\-_.*]*$/.test(e))throw Da(e,Ya);return e}function ja(e){return null==e?"":Object.entries(e).map((function(e){var t=e[0],r=e[1];return!0===r?";"+Wa(t):";"+Wa(t)+"="+Ha(r)})).join("")}function qa(e){return e instanceof Ia?""+Ha(e.value)+ja(e.params):Ha(e)}function Xa(e,t){if(void 0===t&&(t={whitespace:!0}),"object"!=typeof e)throw Da(e,ka);var r=e instanceof Map?e.entries():Object.entries(e),i=(null==t?void 0:t.whitespace)?" ":"";return Array.from(r).map((function(e){var t=e[0],r=e[1];r instanceof Ia==0&&(r=new Ia(r));var i,n=Wa(t);return!0===r.value?n+=ja(r.params):(n+="=",Array.isArray(r.value)?n+="("+(i=r).value.map(qa).join(" ")+")"+ja(i.params):n+=qa(r)),n})).join(","+i)}var Qa=function(e){return Math.round(e)},za=function(e){return 100*Qa(e/100)},$a={br:Qa,d:Qa,bl:za,dl:za,mtp:za,nor:function(e,t){return(null==t?void 0:t.baseUrl)&&(e=function(e,t){var r=new URL(e),i=new URL(t);if(r.origin!==i.origin)return e;for(var n=r.pathname.split("/").slice(1),a=i.pathname.split("/").slice(1,-1);n[0]===a[0];)n.shift(),a.shift();for(;a.length;)a.shift(),n.unshift("..");return n.join("/")}(e,t.baseUrl)),encodeURIComponent(e)},rtp:za,tb:Qa};function Ja(e,t){var r={};if(null==e||"object"!=typeof e)return r;var i=Object.keys(e).sort(),n=a({},$a,null==t?void 0:t.formatters),s=null==t?void 0:t.filter;return i.forEach((function(i){if(!(null==s?void 0:s(i))){var a=e[i],o=n[i];o&&(a=o(a,t)),"v"===i&&1===a||"pr"==i&&1===a||function(e){return"number"==typeof e?A(e):null!=e&&""!==e&&!1!==e}(a)&&(function(e){return"ot"===e||"sf"===e||"st"===e}(i)&&"string"==typeof a&&(a=new _a(a)),r[i]=a)}})),r}function Za(e,t){return void 0===t&&(t={}),e?function(e,t){return Xa(e,t)}(Ja(e,t),a({whitespace:!1},t)):""}function es(e,t,r){return a(e,function(e,t){void 0===t&&(t={});var r={};if(!e)return r;var i=Object.entries(e),n=Object.entries(Ra).concat(Object.entries((null==t?void 0:t.customHeaderMap)||{})),a=i.reduce((function(e,t){var r,i,a=t[0],s=t[1],o=(null===(r=n.find((function(e){return e[1].includes(a)})))||void 0===r?void 0:r[0])||La.REQUEST;return null!==(i=e[o])&&void 0!==i||(e[o]={}),e[o][a]=s,e}),{});return Object.entries(a).reduce((function(e,r){var i=r[0],n=r[1];return e[i]=Za(n,t),e}),r)}(t,r))}var ts="CMCD",rs=/CMCD=[^&#]+/;function is(e,t,r){var i=function(e,t){if(void 0===t&&(t={}),!e)return"";var r=Za(e,t);return ts+"="+encodeURIComponent(r)}(t,r);if(!i)return e;if(rs.test(e))return e.replace(rs,i);var n=e.includes("?")?"&":"?";return""+e+n+i}var ns=function(){function e(e){var t=this;this.hls=void 0,this.config=void 0,this.media=void 0,this.sid=void 0,this.cid=void 0,this.useHeaders=!1,this.includeKeys=void 0,this.initialized=!1,this.starved=!1,this.buffering=!0,this.audioBuffer=void 0,this.videoBuffer=void 0,this.onWaiting=function(){t.initialized&&(t.starved=!0),t.buffering=!0},this.onPlaying=function(){t.initialized||(t.initialized=!0),t.buffering=!1},this.applyPlaylistData=function(e){try{t.apply(e,{ot:Sa.MANIFEST,su:!t.initialized})}catch(e){t.hls.logger.warn("Could not generate manifest CMCD data.",e)}},this.applyFragmentData=function(e){try{var r=e.frag,i=e.part,n=t.hls.levels[r.level],a=t.getObjectType(r),s={d:1e3*(i||r).duration,ot:a};a!==Sa.VIDEO&&a!==Sa.AUDIO&&a!=Sa.MUXED||(s.br=n.bitrate/1e3,s.tb=t.getTopBandwidth(a)/1e3,s.bl=t.getBufferLength(a));var o=i?t.getNextPart(i):t.getNextFrag(r);null!=o&&o.url&&o.url!==r.url&&(s.nor=o.url),t.apply(e,s)}catch(e){t.hls.logger.warn("Could not generate segment CMCD data.",e)}},this.hls=e;var r=this.config=e.config,i=r.cmcd;null!=i&&(r.pLoader=this.createPlaylistLoader(),r.fLoader=this.createFragmentLoader(),this.sid=i.sessionId||e.sessionId,this.cid=i.contentId,this.useHeaders=!0===i.useHeaders,this.includeKeys=i.includeKeys,this.registerListeners())}var t=e.prototype;return t.registerListeners=function(){var e=this.hls;e.on(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.on(b.MEDIA_DETACHED,this.onMediaDetached,this),e.on(b.BUFFER_CREATED,this.onBufferCreated,this)},t.unregisterListeners=function(){var e=this.hls;e.off(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.off(b.MEDIA_DETACHED,this.onMediaDetached,this),e.off(b.BUFFER_CREATED,this.onBufferCreated,this)},t.destroy=function(){this.unregisterListeners(),this.onMediaDetached(),this.hls=this.config=this.audioBuffer=this.videoBuffer=null,this.onWaiting=this.onPlaying=this.media=null},t.onMediaAttached=function(e,t){this.media=t.media,this.media.addEventListener("waiting",this.onWaiting),this.media.addEventListener("playing",this.onPlaying)},t.onMediaDetached=function(){this.media&&(this.media.removeEventListener("waiting",this.onWaiting),this.media.removeEventListener("playing",this.onPlaying),this.media=null)},t.onBufferCreated=function(e,t){var r,i;this.audioBuffer=null==(r=t.tracks.audio)?void 0:r.buffer,this.videoBuffer=null==(i=t.tracks.video)?void 0:i.buffer},t.createData=function(){var e;return{v:1,sf:Aa.HLS,sid:this.sid,cid:this.cid,pr:null==(e=this.media)?void 0:e.playbackRate,mtp:this.hls.bandwidthEstimate/1e3}},t.apply=function(e,t){void 0===t&&(t={}),a(t,this.createData());var r=t.ot===Sa.INIT||t.ot===Sa.VIDEO||t.ot===Sa.MUXED;this.starved&&r&&(t.bs=!0,t.su=!0,this.starved=!1),null==t.su&&(t.su=this.buffering);var i=this.includeKeys;i&&(t=Object.keys(t).reduce((function(e,r){return i.includes(r)&&(e[r]=t[r]),e}),{}));var n={baseUrl:e.url};this.useHeaders?(e.headers||(e.headers={}),es(e.headers,t,n)):e.url=is(e.url,t,n)},t.getNextFrag=function(e){var t,r=null==(t=this.hls.levels[e.level])?void 0:t.details;if(r){var i=e.sn-r.startSN;return r.fragments[i+1]}},t.getNextPart=function(e){var t,r,i=e.index,n=e.fragment,a=null==(t=this.hls.levels[n.level])||null==(r=t.details)?void 0:r.partList;if(a)for(var s=n.sn,o=a.length-1;o>=0;o--){var l=a[o];if(l.index===i&&l.fragment.sn===s)return a[o+1]}},t.getObjectType=function(e){var t=e.type;return"subtitle"===t?Sa.TIMED_TEXT:"initSegment"===e.sn?Sa.INIT:"audio"===t?Sa.AUDIO:"main"===t?this.hls.audioTracks.length?Sa.VIDEO:Sa.MUXED:void 0},t.getTopBandwidth=function(e){var t,r=0,i=this.hls;if(e===Sa.AUDIO)t=i.audioTracks;else{var n=i.maxAutoLevel,a=n>-1?n+1:i.levels.length;t=i.levels.slice(0,a)}return t.forEach((function(e){e.bitrate>r&&(r=e.bitrate)})),r>0?r:NaN},t.getBufferLength=function(e){var t=this.media,r=e===Sa.AUDIO?this.audioBuffer:this.videoBuffer;return r&&t?1e3*ir.bufferInfo(r,t.currentTime,this.config.maxBufferHole).len:NaN},t.createPlaylistLoader=function(){var e=this.config.pLoader,t=this.applyPlaylistData,r=e||this.config.loader;return function(){function e(e){this.loader=void 0,this.loader=new r(e)}var n=e.prototype;return n.destroy=function(){this.loader.destroy()},n.abort=function(){this.loader.abort()},n.load=function(e,r,i){t(e),this.loader.load(e,r,i)},i(e,[{key:"stats",get:function(){return this.loader.stats}},{key:"context",get:function(){return this.loader.context}}])}()},t.createFragmentLoader=function(){var e=this.config.fLoader,t=this.applyFragmentData,r=e||this.config.loader;return function(){function e(e){this.loader=void 0,this.loader=new r(e)}var n=e.prototype;return n.destroy=function(){this.loader.destroy()},n.abort=function(){this.loader.abort()},n.load=function(e,r,i){t(e),this.loader.load(e,r,i)},i(e,[{key:"stats",get:function(){return this.loader.stats}},{key:"context",get:function(){return this.loader.context}}])}()},e}(),as=function(e){function t(t){var r;return(r=e.call(this,"content-steering",t.logger)||this).hls=void 0,r.loader=null,r.uri=null,r.pathwayId=".",r._pathwayPriority=null,r.timeToLoad=300,r.reloadTimer=-1,r.updated=0,r.started=!1,r.enabled=!0,r.levels=null,r.audioTracks=null,r.subtitleTracks=null,r.penalizedPathways={},r.hls=t,r.registerListeners(),r}o(t,e);var r=t.prototype;return r.registerListeners=function(){var e=this.hls;e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.MANIFEST_LOADED,this.onManifestLoaded,this),e.on(b.MANIFEST_PARSED,this.onManifestParsed,this),e.on(b.ERROR,this.onError,this)},r.unregisterListeners=function(){var e=this.hls;e&&(e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.MANIFEST_LOADED,this.onManifestLoaded,this),e.off(b.MANIFEST_PARSED,this.onManifestParsed,this),e.off(b.ERROR,this.onError,this))},r.pathways=function(){return(this.levels||[]).reduce((function(e,t){return-1===e.indexOf(t.pathwayId)&&e.push(t.pathwayId),e}),[])},r.startLoad=function(){if(this.started=!0,this.clearTimeout(),this.enabled&&this.uri){if(this.updated){var e=1e3*this.timeToLoad-(performance.now()-this.updated);if(e>0)return void this.scheduleRefresh(this.uri,e)}this.loadSteeringManifest(this.uri)}},r.stopLoad=function(){this.started=!1,this.loader&&(this.loader.destroy(),this.loader=null),this.clearTimeout()},r.clearTimeout=function(){-1!==this.reloadTimer&&(self.clearTimeout(this.reloadTimer),this.reloadTimer=-1)},r.destroy=function(){this.unregisterListeners(),this.stopLoad(),this.hls=null,this.levels=this.audioTracks=this.subtitleTracks=null},r.removeLevel=function(e){var t=this.levels;t&&(this.levels=t.filter((function(t){return t!==e})))},r.onManifestLoading=function(){this.stopLoad(),this.enabled=!0,this.timeToLoad=300,this.updated=0,this.uri=null,this.pathwayId=".",this.levels=this.audioTracks=this.subtitleTracks=null},r.onManifestLoaded=function(e,t){var r=t.contentSteering;null!==r&&(this.pathwayId=r.pathwayId,this.uri=r.uri,this.started&&this.startLoad())},r.onManifestParsed=function(e,t){this.audioTracks=t.audioTracks,this.subtitleTracks=t.subtitleTracks},r.onError=function(e,t){var r=t.errorAction;if((null==r?void 0:r.action)===bt&&r.flags===Ct){var i=this.levels,n=this._pathwayPriority,a=this.pathwayId;if(t.context){var s=t.context,o=s.groupId,l=s.pathwayId,u=s.type;o&&i?a=this.getPathwayForGroupId(o,u,a):l&&(a=l)}a in this.penalizedPathways||(this.penalizedPathways[a]=performance.now()),!n&&i&&(n=this.pathways()),n&&n.length>1&&(this.updatePathwayPriority(n),r.resolved=this.pathwayId!==a),t.details!==k.BUFFER_APPEND_ERROR||t.fatal?r.resolved||this.warn("Could not resolve "+t.details+' ("'+t.error.message+'") with content-steering for Pathway: '+a+" levels: "+(i?i.length:i)+" priorities: "+st(n)+" penalized: "+st(this.penalizedPathways)):r.resolved=!0}},r.filterParsedLevels=function(e){this.levels=e;var t=this.getLevelsForPathway(this.pathwayId);if(0===t.length){var r=e[0].pathwayId;this.log("No levels found in Pathway "+this.pathwayId+'. Setting initial Pathway to "'+r+'"'),t=this.getLevelsForPathway(r),this.pathwayId=r}return t.length!==e.length&&this.log("Found "+t.length+"/"+e.length+' levels in Pathway "'+this.pathwayId+'"'),t},r.getLevelsForPathway=function(e){return null===this.levels?[]:this.levels.filter((function(t){return e===t.pathwayId}))},r.updatePathwayPriority=function(e){var t;this._pathwayPriority=e;var r=this.penalizedPathways,i=performance.now();Object.keys(r).forEach((function(e){i-r[e]>3e5&&delete r[e]}));for(var n=0;n0){this.log('Setting Pathway to "'+a+'"'),this.pathwayId=a,fi(t),this.hls.trigger(b.LEVELS_UPDATED,{levels:t});var l=this.hls.levels[s];o&&l&&this.levels&&(l.attrs["STABLE-VARIANT-ID"]!==o.attrs["STABLE-VARIANT-ID"]&&l.bitrate!==o.bitrate&&this.log("Unstable Pathways change from bitrate "+o.bitrate+" to "+l.bitrate),this.hls.nextLoadLevel=s);break}}}},r.getPathwayForGroupId=function(e,t,r){for(var i=this.getLevelsForPathway(r).concat(this.levels||[]),n=0;n tenc");s=new Uint8Array(d.subarray(8,24)),o=Sr.FAIRPLAY}catch(e){return void i.warn(n+" Failed to parse sinf: "+e)}}else{if(l!==Sr.WIDEVINE&&l!==Sr.PLAYREADY)return void i.warn('Ignoring unexpected "'+e.type+'" event with init data type: "'+t+'" for selected key-system '+l);var h=function(e){var t=[];if(e instanceof ArrayBuffer)for(var r=e.byteLength,i=0;i+321&&i.warn(n+" Using first of "+f.length+" pssh found for selected key-system "+l);var c=f[0];if(!c)return void(0===h.length||h.some((function(e){return!e.systemId}))?i.warn(n+" contains incomplete or invalid pssh data"):i.log("ignoring "+n+" for "+h.map((function(e){return Cr(e.systemId)})).join(",")+" pssh data in favor of playlist keys"));if(o=Cr(c.systemId),0===c.version&&c.data)if(o===Sr.WIDEVINE){var g=c.data.length-22;s=new Uint8Array(c.data.subarray(g,g+16))}else o===Sr.PLAYREADY&&(s=Fr(c.data))}if(o&&s){for(var v,m=X.hexDump(s),p=i,y=p.keyIdToKeySessionPromise,E=p.mediaKeySessions,T=y[m],S=function(){var e=E[A],n=e.decryptdata;if(!n.keyId)return 0;var a=X.hexDump(n.keyId);return m===a||-1!==n.uri.replace(/-/g,"").indexOf(m)?(T=y[a],n.pssh||(delete y[a],n.pssh=new Uint8Array(r),n.keyId=s,(T=y[m]=T.then((function(){return i.generateRequestWithPreferredKeySession(e,t,r,"encrypted-event-key-match")}))).catch((function(e){return i.handleError(e)}))),1):void 0},A=0;A0)for(var a,s=0,o=n.length;s in key message");return yr(atob(c))},r.setupLicenseXHR=function(e,t,r,i){var n=this,a=this.config.licenseXhrSetup;return a?Promise.resolve().then((function(){if(!r.decryptdata)throw new Error("Key removed");return a.call(n.hls,e,t,r,i)})).catch((function(s){if(!r.decryptdata)throw s;return e.open("POST",t,!0),a.call(n.hls,e,t,r,i)})).then((function(r){return e.readyState||e.open("POST",t,!0),{xhr:e,licenseChallenge:r||i}})):(e.open("POST",t,!0),Promise.resolve({xhr:e,licenseChallenge:i}))},r.requestLicense=function(e,t){var r=this,i=this.config.keyLoadPolicy.default;return new Promise((function(n,a){var s=r.getLicenseServerUrlOrThrow(e.keySystem);r.log("Sending license request to URL: "+s);var o=new XMLHttpRequest;o.responseType="arraybuffer",o.onreadystatechange=function(){if(!r.hls||!e.mediaKeysSession)return a(new Error("invalid state"));if(4===o.readyState)if(200===o.status){r._requestLicenseFailureCount=0;var l=o.response;r.log("License received "+(l instanceof ArrayBuffer?l.byteLength:l));var u=r.config.licenseResponseCallback;if(u)try{l=u.call(r.hls,o,s,e)}catch(e){r.error(e)}n(l)}else{var d=i.errorRetry,h=d?d.maxNumRetry:0;if(r._requestLicenseFailureCount++,r._requestLicenseFailureCount>h||o.status>=400&&o.status<500)a(new hs({type:I.KEY_SYSTEM_ERROR,details:k.KEY_SYSTEM_LICENSE_REQUEST_FAILED,fatal:!0,networkDetails:o,response:{url:s,data:void 0,code:o.status,text:o.statusText}},"License Request XHR failed ("+s+"). Status: "+o.status+" ("+o.statusText+")"));else{var f=h-r._requestLicenseFailureCount+1;r.warn("Retrying license request, "+f+" attempts left"),r.requestLicense(e,t).then(n,a)}}},e.licenseXhr&&e.licenseXhr.readyState!==XMLHttpRequest.DONE&&e.licenseXhr.abort(),e.licenseXhr=o,r.setupLicenseXHR(o,s,e,t).then((function(t){var i=t.xhr,n=t.licenseChallenge;e.keySystem==Sr.PLAYREADY&&(n=r.unpackPlayReadyKeyMessage(i,n)),i.send(n)}))}))},r.onDestroying=function(){this.unregisterListeners(),this._clear()},r.onMediaAttached=function(e,t){if(this.config.emeEnabled){var r=t.media;this.media=r,ls(r,"encrypted",this.onMediaEncrypted),ls(r,"waitingforkey",this.onWaitingForKey)}},r.onMediaDetached=function(){var e=this.media;e&&(us(e,"encrypted",this.onMediaEncrypted),us(e,"waitingforkey",this.onWaitingForKey),this.media=null,this.mediaKeys=null)},r._clear=function(){var e,r=this;if(this._requestLicenseFailureCount=0,this.keyIdToKeySessionPromise={},this.mediaKeys||this.mediaKeySessions.length){var i=this.media,n=this.mediaKeySessions.slice();this.mediaKeySessions=[],this.mediaKeys=null,Ur.clearKeyUriToKeyIdMap();var a=n.length;t.CDMCleanupPromise=Promise.all(n.map((function(e){return r.removeSession(e)})).concat(null==i||null==(e=i.setMediaKeys(null))?void 0:e.catch((function(e){var t;r.log("Could not clear media keys: "+e),null==(t=r.hls)||t.trigger(b.ERROR,{type:I.OTHER_ERROR,details:k.KEY_SYSTEM_DESTROY_MEDIA_KEYS_ERROR,fatal:!1,error:new Error("Could not clear media keys: "+e)})})))).catch((function(e){var t;r.log("Could not close sessions and clear media keys: "+e),null==(t=r.hls)||t.trigger(b.ERROR,{type:I.OTHER_ERROR,details:k.KEY_SYSTEM_DESTROY_CLOSE_SESSION_ERROR,fatal:!1,error:new Error("Could not close sessions and clear media keys: "+e)})})).then((function(){a&&r.log("finished closing key sessions and clearing media keys")}))}},r.onManifestLoading=function(){this.keyFormatPromise=null},r.onManifestLoaded=function(e,t){var r=t.sessionKeys;if(r&&this.config.emeEnabled&&!this.keyFormatPromise){var i=r.reduce((function(e,t){return-1===e.indexOf(t.keyFormat)&&e.push(t.keyFormat),e}),[]);this.log("Selecting key-system from session-keys "+i.join(", ")),this.keyFormatPromise=this.getKeyFormatPromise(i)}},r.removeSession=function(e){var t=this,r=e.mediaKeysSession,i=e.licenseXhr;if(r){this.log("Remove licenses and keys and close session "+r.sessionId),e._onmessage&&(r.removeEventListener("message",e._onmessage),e._onmessage=void 0),e._onkeystatuseschange&&(r.removeEventListener("keystatuseschange",e._onkeystatuseschange),e._onkeystatuseschange=void 0),i&&i.readyState!==XMLHttpRequest.DONE&&i.abort(),e.mediaKeysSession=e.decryptdata=e.licenseXhr=void 0;var n=this.mediaKeySessions.indexOf(e);n>-1&&this.mediaKeySessions.splice(n,1);var a=function(e){var t;return"persistent-license"===e.sessionType||!(null==(t=e.sessionTypes)||!t.some((function(e){return"persistent-license"===e})))}(this.config.drmSystemOptions)?new Promise((function(e,t){self.setTimeout((function(){return t(new Error("MediaKeySession.remove() timeout"))}),8e3),r.remove().then(e)})):Promise.resolve();return a.catch((function(e){var r;t.log("Could not remove session: "+e),null==(r=t.hls)||r.trigger(b.ERROR,{type:I.OTHER_ERROR,details:k.KEY_SYSTEM_DESTROY_REMOVE_SESSION_ERROR,fatal:!1,error:new Error("Could not remove session: "+e)})})).then((function(){return r.close()})).catch((function(e){var r;t.log("Could not close session: "+e),null==(r=t.hls)||r.trigger(b.ERROR,{type:I.OTHER_ERROR,details:k.KEY_SYSTEM_DESTROY_CLOSE_SESSION_ERROR,fatal:!1,error:new Error("Could not close session: "+e)})}))}},t}(N);ds.CDMCleanupPromise=void 0;var hs=function(e){function t(t,r){var i;return(i=e.call(this,r)||this).data=void 0,t.error||(t.error=new Error(r)),i.data=t,t.err=t.error,i}return o(t,e),t}(c(Error)),fs=function(){function e(e){this.hls=void 0,this.isVideoPlaybackQualityAvailable=!1,this.timer=void 0,this.media=null,this.lastTime=void 0,this.lastDroppedFrames=0,this.lastDecodedFrames=0,this.streamController=void 0,this.hls=e,this.registerListeners()}var t=e.prototype;return t.setStreamController=function(e){this.streamController=e},t.registerListeners=function(){this.hls.on(b.MEDIA_ATTACHING,this.onMediaAttaching,this),this.hls.on(b.MEDIA_DETACHING,this.onMediaDetaching,this)},t.unregisterListeners=function(){this.hls.off(b.MEDIA_ATTACHING,this.onMediaAttaching,this),this.hls.off(b.MEDIA_DETACHING,this.onMediaDetaching,this)},t.destroy=function(){this.timer&&clearInterval(this.timer),this.unregisterListeners(),this.isVideoPlaybackQualityAvailable=!1,this.media=null},t.onMediaAttaching=function(e,t){var r=this.hls.config;if(r.capLevelOnFPSDrop){var i=t.media instanceof self.HTMLVideoElement?t.media:null;this.media=i,i&&"function"==typeof i.getVideoPlaybackQuality&&(this.isVideoPlaybackQualityAvailable=!0),self.clearInterval(this.timer),this.timer=self.setInterval(this.checkFPSInterval.bind(this),r.fpsDroppedMonitoringPeriod)}},t.onMediaDetaching=function(){this.media=null},t.checkFPS=function(e,t,r){var i=performance.now();if(t){if(this.lastTime){var n=i-this.lastTime,a=r-this.lastDroppedFrames,s=t-this.lastDecodedFrames,o=1e3*a/n,l=this.hls;if(l.trigger(b.FPS_DROP,{currentDropped:a,currentDecoded:s,totalDroppedFrames:r}),o>0&&a>l.config.fpsDroppedMonitoringThreshold*s){var u=l.currentLevel;l.logger.warn("drop FPS ratio greater than max allowed value for currentLevel: "+u),u>0&&(-1===l.autoLevelCapping||l.autoLevelCapping>=u)&&(u-=1,l.trigger(b.FPS_DROP_LEVEL_CAPPING,{level:u,droppedLevel:l.currentLevel}),l.autoLevelCapping=u,this.streamController.nextLevelSwitch())}}this.lastTime=i,this.lastDroppedFrames=r,this.lastDecodedFrames=t}},t.checkFPSInterval=function(){var e=this.media;if(e)if(this.isVideoPlaybackQualityAvailable){var t=e.getVideoPlaybackQuality();this.checkFPS(e,t.totalVideoFrames,t.droppedVideoFrames)}else this.checkFPS(e,e.webkitDecodedFrameCount,e.webkitDroppedFrameCount)},e}();function cs(e){for(var t=5381,r=e.length;r;)t=33*t^e.charCodeAt(--r);return(t>>>0).toString()}var gs=.025,vs=function(e){return e[e.Point=0]="Point",e[e.Range=1]="Range",e}({});function ms(e,t,r){return e.identifier+"-"+(r+1)+"-"+cs(t)}var ps=function(){function e(e,t){this.base=void 0,this._duration=null,this._timelineStart=null,this.appendInPlaceDisabled=void 0,this.appendInPlaceStarted=void 0,this.dateRange=void 0,this.hasPlayed=!1,this.cumulativeDuration=0,this.resumeOffset=NaN,this.playoutLimit=NaN,this.restrictions={skip:!1,jump:!1},this.snapOptions={out:!1,in:!1},this.assetList=[],this.assetListLoader=void 0,this.assetListResponse=null,this.resumeAnchor=void 0,this.error=void 0,this.resetOnResume=void 0,this.base=t,this.dateRange=e,this.setDateRange(e)}var t=e.prototype;return t.setDateRange=function(e){this.dateRange=e,this.resumeOffset=e.attr.optionalFloat("X-RESUME-OFFSET",this.resumeOffset),this.playoutLimit=e.attr.optionalFloat("X-PLAYOUT-LIMIT",this.playoutLimit),this.restrictions=e.attr.enumeratedStringList("X-RESTRICT",this.restrictions),this.snapOptions=e.attr.enumeratedStringList("X-SNAP",this.snapOptions)},t.reset=function(){var e;this.appendInPlaceStarted=!1,null==(e=this.assetListLoader)||e.destroy(),this.assetListLoader=void 0,this.supplementsPrimary||(this.assetListResponse=null,this.assetList=[],this._duration=null)},t.isAssetPastPlayoutLimit=function(e){var t;if(e>0&&e>=this.assetList.length)return!0;var r=this.playoutLimit;return!(e<=0||isNaN(r))&&(0===r||((null==(t=this.assetList[e])?void 0:t.startOffset)||0)>r)},t.findAssetIndex=function(e){return this.assetList.indexOf(e)},t.toString=function(){return'["'+(e=this).identifier+'" '+(e.cue.pre?"
":e.cue.post?"":"")+e.timelineStart.toFixed(2)+"-"+e.resumeTime.toFixed(2)+"]";var e},i(e,[{key:"identifier",get:function(){return this.dateRange.id}},{key:"startDate",get:function(){return this.dateRange.startDate}},{key:"startTime",get:function(){var e=this.dateRange.startTime;if(this.snapOptions.out){var t=this.dateRange.tagAnchor;if(t)return ys(e,t)}return e}},{key:"startOffset",get:function(){return this.cue.pre?0:this.startTime}},{key:"startIsAligned",get:function(){if(0===this.startTime||this.snapOptions.out)return!0;var e=this.dateRange.tagAnchor;if(e){var t=this.dateRange.startTime;return t-ys(t,e)<.1}return!1}},{key:"resumptionOffset",get:function(){var e=this.resumeOffset,t=A(e)?e:this.duration;return this.cumulativeDuration+t}},{key:"resumeTime",get:function(){var e=this.startOffset+this.resumptionOffset;if(this.snapOptions.in){var t=this.resumeAnchor;if(t)return ys(e,t)}return e}},{key:"appendInPlace",get:function(){return!!this.appendInPlaceStarted||!this.appendInPlaceDisabled&&!(this.cue.once||this.cue.pre||!this.startIsAligned||!(isNaN(this.playoutLimit)&&isNaN(this.resumeOffset)||this.resumeOffset&&this.duration&&Math.abs(this.resumeOffset-this.duration)0||null!==this.assetListResponse}}])}();function ys(e,t){return e-t.start=this._bufferedEosTime-.02},t.reachedPlayout=function(e){var t=this.interstitial.playoutLimit;return this.startOffset+e>=t},t.getAssetTime=function(e){var t=this.timelineOffset,r=this.duration;return Math.min(Math.max(0,e-t),r)},t.removeMediaListeners=function(){var e=this.mediaAttached;e&&(this._currentTime=e.currentTime,this.bufferSnapShot(),e.removeEventListener("timeupdate",this.checkPlayout))},t.bufferSnapShot=function(){var e;this.mediaAttached&&null!=(e=this.hls)&&e.bufferedToEnd&&(this._bufferedEosTime=this.bufferedEnd)},t.destroy=function(){this.removeMediaListeners(),this.hls.destroy(),this.hls=this.interstitial=null,this.tracks=this.mediaAttached=this.checkPlayout=null},t.attachMedia=function(e){this.hls.attachMedia(e)},t.detachMedia=function(){this.removeMediaListeners(),this.mediaAttached=null,this.hls.detachMedia()},t.resumeBuffering=function(){this.hls.resumeBuffering()},t.pauseBuffering=function(){this.hls.pauseBuffering()},t.transferMedia=function(){return this.bufferSnapShot(),this.hls.transferMedia()},t.resetDetails=function(){var e=this.hls;if(this.hasDetails){e.stopLoad();var t=function(e){return delete e.details};e.levels.forEach(t),e.allAudioTracks.forEach(t),e.allSubtitleTracks.forEach(t),this.hasDetails=!1}},t.on=function(e,t,r){this.hls.on(e,t)},t.once=function(e,t,r){this.hls.once(e,t)},t.off=function(e,t,r){this.hls.off(e,t)},t.toString=function(){var e;return"HlsAssetPlayer: "+Ss(this.assetItem)+" "+(null==(e=this.hls)?void 0:e.sessionId)+" "+(this.appendInPlace?"append-in-place":"")},i(e,[{key:"appendInPlace",get:function(){var e;return(null==(e=this.interstitial)?void 0:e.appendInPlace)||!1}},{key:"destroyed",get:function(){var e;return!(null!=(e=this.hls)&&e.userConfig)}},{key:"assetId",get:function(){return this.assetItem.identifier}},{key:"interstitialId",get:function(){return this.assetItem.parentIdentifier}},{key:"media",get:function(){var e;return(null==(e=this.hls)?void 0:e.media)||null}},{key:"bufferedEnd",get:function(){var e=this.media||this.mediaAttached;if(!e)return this._bufferedEosTime?this._bufferedEosTime:this.currentTime;var t=ir.bufferInfo(e,e.currentTime,.001);return this.getAssetTime(t.end)}},{key:"currentTime",get:function(){var e=this.media||this.mediaAttached;return e?this.getAssetTime(e.currentTime):this._currentTime||0}},{key:"duration",get:function(){var e=this.assetItem.duration;return e||0}},{key:"remaining",get:function(){var e=this.duration;return e?Math.max(0,e-this.currentTime):0}},{key:"startOffset",get:function(){return this.assetItem.startOffset}},{key:"timelineOffset",get:function(){var e;return(null==(e=this.hls)?void 0:e.config.timelineOffset)||0},set:function(e){var t=this.timelineOffset;if(e!==t){var r=e-t;if(Math.abs(r)>1/9e4){if(this.hasDetails)throw new Error("Cannot set timelineOffset after playlists are loaded");this.hls.config.timelineOffset=e}}}}])}(),Ls=function(e){function t(t,r){var i;return(i=e.call(this,"interstitials-sched",r)||this).onScheduleUpdate=void 0,i.eventMap={},i.events=null,i.items=null,i.durations={primary:0,playout:0,integrated:0},i.onScheduleUpdate=t,i}o(t,e);var r=t.prototype;return r.destroy=function(){this.reset(),this.onScheduleUpdate=null},r.reset=function(){this.eventMap={},this.setDurations(0,0,0),this.events&&this.events.forEach((function(e){return e.reset()})),this.events=this.items=null},r.resetErrorsInRange=function(e,t){return this.events?this.events.reduce((function(r,i){return e<=i.startOffset&&t>i.startOffset?(delete i.error,r+1):r}),0):0},r.getEvent=function(e){return e&&this.eventMap[e]||null},r.hasEvent=function(e){return e in this.eventMap},r.findItemIndex=function(e,t){if(e.event)return this.findEventIndex(e.event.identifier);var r=-1;e.nextEvent?r=this.findEventIndex(e.nextEvent.identifier)-1:e.previousEvent&&(r=this.findEventIndex(e.previousEvent.identifier)+1);var i=this.items;if(i)for(i[r]||(void 0===t&&(t=e.start),r=this.findItemIndexAtTime(t));r>=0&&null!=(n=i[r])&&n.event;){var n;r--}return r},r.findItemIndexAtTime=function(e,t){var r=this.items;if(r)for(var i=0;in.start&&e1)for(var n=0;ns&&t.005||Math.abs(e.playout.end-i[t].playout.end)>.005})))&&(this.items=n,this.onScheduleUpdate(t,i))}},r.parseDateRanges=function(e,t,r){for(var i=[],n=Object.keys(e),a=0;a.033){var A=s,L=o;o+=S;var R=a;a+=S;var I={previousEvent:e[i-1]||null,nextEvent:t,start:A,end:A+S,playout:{start:R,end:a},integrated:{start:L,end:o}};r.push(I)}else S>0&&d&&(d.cumulativeDuration+=S,r[r.length-1].end=f)}u&&(y=p),t.timelineStart=p;var k=o;o+=g;var b=a;a+=c,r.push({event:t,start:p,end:y,playout:{start:b,end:a},integrated:{start:k,end:o}})}var D=t.resumeTime;s=u||D>n?n:D})),sgs?(this.log('"'+e.identifier+'" resumption '+i+" not aligned with estimated timeline end "+n),!1):t?!Object.keys(t).some((function(n){var a=t[n].details,s=a.edge;if(i>=s)return r.log('"'+e.identifier+'" resumption '+i+" past "+n+" playlist end "+s),!1;var o=pt(null,a.fragments,i);if(!o)return r.log('"'+e.identifier+'" resumption '+i+" does not align with any fragments in "+n+" playlist ("+a.fragStart+"-"+a.fragmentEnd+")"),!0;var l="audio"===n?.175:0;return!(Math.abs(o.start-i)=n.end){var a,s=i.schedule.findItemIndexAtTime(i.timelinePos);if(!i.isInterstitial(n)&&null!=(a=i.media)&&a.paused&&(i.shouldPlay=!1),!r){var o=i.findItemIndex(n);if(s>o){var l=i.schedule.findJumpRestrictedIndex(o+1,s);if(l>o)return void i.setSchedulePosition(l)}}i.setSchedulePosition(s)}else{var u=i.playingAsset;if(u){var d=u.timelineStart,h=u.duration||0;(r&&e=d+h)&&i.setScheduleToAssetAtTime(e,u)}else if(i.playingLastItem&&i.isInterstitial(n)){var f=n.event.assetList[0];f&&(i.endedItem=i.playingItem,i.playingItem=null,i.setScheduleToAssetAtTime(e,f))}}else i.checkBuffer()}}},i.onTimeupdate=function(){var e=i.currentTime;if(void 0!==e&&!i.playbackDisabled&&e>i.timelinePos){i.timelinePos=e,e>i.bufferedPos&&i.checkBuffer();var t=i.playingItem;if(t&&!i.playingLastItem){if(e>=t.end){i.timelinePos=t.end;var r=i.findItemIndex(t);i.setSchedulePosition(r+1)}var n=i.playingAsset;n&&e>=n.timelineStart+(n.duration||0)&&i.setScheduleToAssetAtTime(e,n)}}},i.onScheduleUpdate=function(e,t){var r=i.schedule,n=i.playingItem,a=r.events||[],s=r.items||[],o=r.durations,l=e.map((function(e){return e.identifier})),u=!(!a.length&&!l.length);(u||t)&&i.log("INTERSTITIALS_UPDATED ("+a.length+"): "+a+"\nSchedule: "+s.map((function(e){return Rs(e)}))+" pos: "+i.timelinePos),l.length&&i.log("Removed events "+l),i.playerQueue.forEach((function(e){if(e.interstitial.appendInPlace){var t=e.assetItem.timelineStart,r=e.timelineOffset-t;if(r)try{e.timelineOffset=t}catch(n){Math.abs(r)>gs&&i.warn(n+' ("'+e.assetId+'" '+e.timelineOffset+"->"+t+")")}}}));var d=null;if(n){var h=i.updateItem(n,i.timelinePos);i.itemsMatch(n,h)&&(i.playingItem=h,i.waitingItem=i.endedItem=null,d=function(){return i.trimInPlace(h,n)})}else i.waitingItem=i.updateItem(i.waitingItem),i.endedItem=i.updateItem(i.endedItem);var f=i.bufferingItem;if(f){var c=i.updateItem(f,i.bufferedPos);i.itemsMatch(f,c)?(i.bufferingItem=c,d||(d=function(){return i.trimInPlace(c,f)})):f.event&&(i.bufferingItem=i.playingItem,i.clearInterstitial(f.event,null))}if(e.forEach((function(e){e.assetList.forEach((function(e){i.clearAssetPlayer(e.identifier,null)}))})),u||t){if(i.hls.trigger(b.INTERSTITIALS_UPDATED,{events:a.slice(0),schedule:s.slice(0),durations:o,removedIds:l}),i.isInterstitial(n)&&l.includes(n.event.identifier))return i.warn('Interstitial "'+n.event.identifier+'" removed while playing'),void i.primaryFallback(n.event);d&&d(),i.checkBuffer()}},i.hls=t,i.HlsPlayerClass=r,i.assetListLoader=new Is(t),i.schedule=new Ls(i.onScheduleUpdate,t.logger),i.registerListeners(),i}o(t,e);var r=t.prototype;return r.registerListeners=function(){var e=this.hls;e.on(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.on(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.on(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.LEVEL_UPDATED,this.onLevelUpdated,this),e.on(b.AUDIO_TRACK_SWITCHING,this.onAudioTrackSwitching,this),e.on(b.AUDIO_TRACK_UPDATED,this.onAudioTrackUpdated,this),e.on(b.SUBTITLE_TRACK_SWITCH,this.onSubtitleTrackSwitch,this),e.on(b.SUBTITLE_TRACK_UPDATED,this.onSubtitleTrackUpdated,this),e.on(b.EVENT_CUE_ENTER,this.onInterstitialCueEnter,this),e.on(b.ASSET_LIST_LOADED,this.onAssetListLoaded,this),e.on(b.BUFFER_APPENDED,this.onBufferAppended,this),e.on(b.BUFFER_FLUSHED,this.onBufferFlushed,this),e.on(b.BUFFERED_TO_END,this.onBufferedToEnd,this),e.on(b.MEDIA_ENDED,this.onMediaEnded,this),e.on(b.ERROR,this.onError,this),e.on(b.DESTROYING,this.onDestroying,this)},r.unregisterListeners=function(){var e=this.hls;e&&(e.off(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.off(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.off(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.LEVEL_UPDATED,this.onLevelUpdated,this),e.off(b.AUDIO_TRACK_SWITCHING,this.onAudioTrackSwitching,this),e.off(b.AUDIO_TRACK_UPDATED,this.onAudioTrackUpdated,this),e.off(b.SUBTITLE_TRACK_SWITCH,this.onSubtitleTrackSwitch,this),e.off(b.SUBTITLE_TRACK_UPDATED,this.onSubtitleTrackUpdated,this),e.off(b.EVENT_CUE_ENTER,this.onInterstitialCueEnter,this),e.off(b.ASSET_LIST_LOADED,this.onAssetListLoaded,this),e.off(b.BUFFER_CODECS,this.onBufferCodecs,this),e.off(b.BUFFER_APPENDED,this.onBufferAppended,this),e.off(b.BUFFER_FLUSHED,this.onBufferFlushed,this),e.off(b.BUFFERED_TO_END,this.onBufferedToEnd,this),e.off(b.MEDIA_ENDED,this.onMediaEnded,this),e.off(b.ERROR,this.onError,this),e.off(b.DESTROYING,this.onDestroying,this))},r.startLoad=function(){this.resumeBuffering()},r.stopLoad=function(){this.pauseBuffering()},r.resumeBuffering=function(){var e;null==(e=this.getBufferingPlayer())||e.resumeBuffering()},r.pauseBuffering=function(){var e;null==(e=this.getBufferingPlayer())||e.pauseBuffering()},r.destroy=function(){this.unregisterListeners(),this.stopLoad(),this.assetListLoader&&this.assetListLoader.destroy(),this.emptyPlayerQueue(),this.clearScheduleState(),this.schedule&&this.schedule.destroy(),this.media=this.detachedData=this.mediaSelection=this.requiredTracks=this.altSelection=this.manager=null,this.hls=this.HlsPlayerClass=this.schedule=this.log=null,this.assetListLoader=null,this.onPlay=this.onPause=this.onSeeking=this.onTimeupdate=null,this.onScheduleUpdate=null},r.onDestroying=function(){var e=this.primaryMedia||this.media;e&&this.removeMediaListeners(e)},r.removeMediaListeners=function(e){us(e,"play",this.onPlay),us(e,"pause",this.onPause),us(e,"seeking",this.onSeeking),us(e,"timeupdate",this.onTimeupdate)},r.onMediaAttaching=function(e,t){var r=this.media=t.media;ls(r,"seeking",this.onSeeking),ls(r,"timeupdate",this.onTimeupdate),ls(r,"play",this.onPlay),ls(r,"pause",this.onPause)},r.onMediaAttached=function(e,t){var r=this.effectivePlayingItem,i=this.detachedData;if(this.detachedData=null,null===r)this.checkStart();else if(!i){this.clearScheduleState();var n=this.findItemIndex(r);this.setSchedulePosition(n)}},r.clearScheduleState=function(){this.playingItem=this.bufferingItem=this.waitingItem=this.endedItem=this.playingAsset=this.endedAsset=this.bufferingAsset=null},r.onMediaDetaching=function(e,t){var r=!!t.transferMedia,i=this.media;if(this.media=null,!r&&(i&&this.removeMediaListeners(i),this.detachedData)){var n=this.getBufferingPlayer();n&&(this.playingAsset=this.endedAsset=this.bufferingAsset=this.bufferingItem=this.waitingItem=this.detachedData=null,n.detachMedia()),this.shouldPlay=!1}},r.isInterstitial=function(e){return!(null==e||!e.event)},r.retreiveMediaSource=function(e,t){var r=this.getAssetPlayer(e);r&&this.transferMediaFromPlayer(r,t)},r.transferMediaFromPlayer=function(e,t){var r=e.interstitial.appendInPlace,i=e.media;if(r&&i===this.primaryMedia){if(this.bufferingAsset=null,(!t||this.isInterstitial(t)&&!t.event.appendInPlace)&&t&&i)return void(this.detachedData={media:i});var n=e.transferMedia();this.log("transfer MediaSource from "+e+" "+st(n)),this.detachedData=n}else t&&i&&(this.shouldPlay||(this.shouldPlay=!i.paused))},r.transferMediaTo=function(e,t){var r,i,n=this;if(e.media!==t){var a,s=null,o=this.hls,l=e!==o,u=l&&e.interstitial.appendInPlace,d=null==(r=this.detachedData)?void 0:r.mediaSource;if(o.media)u&&(s=o.transferMedia(),this.detachedData=s),a="Primary";else if(d){var h=this.getBufferingPlayer();h?(s=h.transferMedia(),a=""+h):a="detached MediaSource"}else a="detached media";if(!s)if(d)s=this.detachedData,this.log("using detachedData: MediaSource "+st(s));else if(!this.detachedData||o.media===t){var f=this.playerQueue;f.length>1&&f.forEach((function(e){if(l&&e.interstitial.appendInPlace!==u){var t=e.interstitial;n.clearInterstitial(e.interstitial,null),t.appendInPlace=!1,t.appendInPlace&&n.warn("Could not change append strategy for queued assets "+t)}})),this.hls.detachMedia(),this.detachedData={media:t}}var c=s&&"mediaSource"in s&&"closed"!==(null==(i=s.mediaSource)?void 0:i.readyState),g=c&&s?s:t;if(this.log((c?"transfering MediaSource":"attaching media")+" to "+(l?e:"Primary")+" from "+a),g===s){var v=l&&e.assetId===this.schedule.assetIdAtEnd;g.overrides={duration:this.schedule.duration,endOfStream:!l||v,cueRemoval:!l}}e.attachMedia(g)}},r.onInterstitialCueEnter=function(){this.onTimeupdate()},r.checkStart=function(){var e=this.schedule,t=e.events;if(t&&!this.playbackDisabled&&this.media){-1===this.bufferedPos&&(this.bufferedPos=0);var r=this.timelinePos,i=this.effectivePlayingItem;if(-1===r){var n=this.hls.startPosition;if(this.timelinePos=n,t.length&&t[0].cue.pre){var a=e.findEventIndex(t[0].identifier);this.setSchedulePosition(a)}else if(n>=0||!this.primaryLive){var s=this.timelinePos=n>0?n:0,o=e.findItemIndexAtTime(s);this.setSchedulePosition(o)}}else if(i&&!this.playingItem){var l=e.findItemIndex(i);this.setSchedulePosition(l)}}},r.advanceAfterAssetEnded=function(e,t,r){var i=Ts(e,r);if(e.isAssetPastPlayoutLimit(i)){var n=this.schedule.items;if(n){var a=t+1;if(a>=n.length)return void this.setSchedulePosition(-1);var s=e.resumeTime;this.timelinePos=0?r[e]:null,n=this.playingItem,a=this.playingLastItem;if(this.isInterstitial(n)){var s,o=n.event,l=this.playingAsset,u=null==l?void 0:l.identifier,d=u?this.getAssetPlayer(u):null;if(d&&u&&(!this.eventItemsMatch(n,i)||void 0!==t&&u!==(null==(s=o.assetList)?void 0:s[t].identifier))){var h,f=o.findAssetIndex(l);if(this.log("INTERSTITIAL_ASSET_ENDED "+(f+1)+"/"+o.assetList.length+" "+Ss(l)),this.endedAsset=l,this.playingAsset=null,this.hls.trigger(b.INTERSTITIAL_ASSET_ENDED,{asset:l,assetListIndex:f,event:o,schedule:r.slice(0),scheduleIndex:e,player:d}),n!==this.playingItem)return void(this.itemsMatch(n,this.playingItem)&&!this.playingAsset&&this.advanceAfterAssetEnded(o,this.findItemIndex(this.playingItem),f));this.retreiveMediaSource(u,i),!d.media||null!=(h=this.detachedData)&&h.mediaSource||d.detachMedia()}if(!this.eventItemsMatch(n,i)&&(this.endedItem=n,this.playingItem=null,this.log("INTERSTITIAL_ENDED "+o+" "+Rs(n)),o.hasPlayed=!0,this.hls.trigger(b.INTERSTITIAL_ENDED,{event:o,schedule:r.slice(0),scheduleIndex:e}),o.cue.once)){this.updateSchedule();var c=this.schedule.items;if(i&&c){var g=this.findItemIndex(i);this.advanceSchedule(g,c,t,n,a)}return}}this.advanceSchedule(e,r,t,n,a)}},r.advanceSchedule=function(e,t,r,i,n){var a=this,s=e>=0?t[e]:null,o=this.primaryMedia,l=this.playerQueue;if(l.length&&l.forEach((function(t){var r=t.interstitial,i=a.schedule.findEventIndex(r.identifier);(ie+1)&&a.clearInterstitial(r,s)})),this.isInterstitial(s)){this.timelinePos=Math.min(Math.max(this.timelinePos,s.start),s.end);var u=s.event;if(void 0===r){var d=Ts(u,(r=this.schedule.findAssetIndex(u,this.timelinePos))-1);if(u.isAssetPastPlayoutLimit(d))return void this.advanceAfterAssetEnded(u,e,r);r=d}var h=this.waitingItem;this.assetsBuffered(s,o)||this.setBufferingItem(s);var f=this.preloadAssets(u,r);if(this.eventItemsMatch(s,h||i)||(this.waitingItem=s,this.log("INTERSTITIAL_STARTED "+Rs(s)+" "+(u.appendInPlace?"append in place":"")),this.hls.trigger(b.INTERSTITIAL_STARTED,{event:u,schedule:t.slice(0),scheduleIndex:e})),!u.assetListLoaded)return void this.log("Waiting for ASSET-LIST to complete loading "+u);if(u.assetListLoader&&(u.assetListLoader.destroy(),u.assetListLoader=void 0),!o)return void this.log("Waiting for attachMedia to start Interstitial "+u);this.waitingItem=this.endedItem=null,this.playingItem=s;var c=u.assetList[r];if(!c){var g=t[e+1],v=this.media;return g&&v&&!this.isInterstitial(g)&&v.currentTime=e.end)&&(n=this.getPrimaryResumption(e,t),this.timelinePos=n),this.attachPrimary(n,e)}if(r){var a=this.schedule.items;a&&(this.log("INTERSTITIALS_PRIMARY_RESUMED "+Rs(e)),this.hls.trigger(b.INTERSTITIALS_PRIMARY_RESUMED,{schedule:a.slice(0),scheduleIndex:t}),this.checkBuffer())}},r.getPrimaryResumption=function(e,t){var r=e.start;if(this.primaryLive){var i=this.primaryDetails;if(0===t)return this.hls.startPosition;if(i&&(ri.edge))return this.hls.liveSyncPosition||-1}return r},r.isAssetBuffered=function(e){var t=this.getAssetPlayer(e.identifier);return null!=t&&t.hls?t.hls.bufferedToEnd:ir.bufferInfo(this.primaryMedia,this.timelinePos,0).end+1>=e.timelineStart+(e.duration||0)},r.attachPrimary=function(e,t,r){t?this.setBufferingItem(t):this.bufferingItem=this.playingItem,this.bufferingAsset=null;var i=this.primaryMedia;if(i){var n=this.hls;n.media?this.checkBuffer():(this.transferMediaTo(n,i),r&&this.startLoadingPrimaryAt(e,r)),r||(this.timelinePos=e,this.startLoadingPrimaryAt(e,r))}},r.startLoadingPrimaryAt=function(e,t){var r,i=this.hls;!i.loadingEnabled||!i.media||Math.abs(((null==(r=i.mainForwardBufferInfo)?void 0:r.start)||i.media.currentTime)-e)>.5?i.startLoad(e,t):i.bufferingEnabled||i.resumeBuffering()},r.onManifestLoading=function(){this.stopLoad(),this.schedule.reset(),this.emptyPlayerQueue(),this.clearScheduleState(),this.shouldPlay=!1,this.bufferedPos=this.timelinePos=-1,this.mediaSelection=this.altSelection=this.manager=this.requiredTracks=null,this.hls.off(b.BUFFER_CODECS,this.onBufferCodecs,this),this.hls.on(b.BUFFER_CODECS,this.onBufferCodecs,this)},r.onLevelUpdated=function(e,t){if(-1!==t.level){var r=this.hls.levels[t.level],i=d(d({},this.mediaSelection||this.altSelection),{},{main:r});this.mediaSelection=i,this.schedule.parseInterstitialDateRanges(i,this.hls.config.interstitialAppendInPlace),!this.effectivePlayingItem&&this.schedule.items&&this.checkStart()}},r.onAudioTrackUpdated=function(e,t){var r=this.hls.audioTracks[t.id],i=this.mediaSelection;if(i){var n=d(d({},i),{},{audio:r});this.mediaSelection=n}else this.altSelection=d(d({},this.altSelection),{},{audio:r})},r.onSubtitleTrackUpdated=function(e,t){var r=this.hls.subtitleTracks[t.id],i=this.mediaSelection;if(i){var n=d(d({},i),{},{subtitles:r});this.mediaSelection=n}else this.altSelection=d(d({},this.altSelection),{},{subtitles:r})},r.onAudioTrackSwitching=function(e,t){var r=ut(t);this.playerQueue.forEach((function(e){return e.hls.setAudioOption(t)||e.hls.setAudioOption(r)}))},r.onSubtitleTrackSwitch=function(e,t){var r=ut(t);this.playerQueue.forEach((function(e){return e.hls.setSubtitleOption(t)||-1!==t.id&&e.hls.setSubtitleOption(r)}))},r.onBufferCodecs=function(e,t){var r=t.tracks;r&&(this.requiredTracks=r)},r.onBufferAppended=function(e,t){this.checkBuffer()},r.onBufferFlushed=function(e,t){var r=this.playingItem;if(r&&!this.itemsMatch(r,this.bufferingItem)&&!this.isInterstitial(r)){var i=this.timelinePos;this.bufferedPos=i,this.checkBuffer()}},r.onBufferedToEnd=function(e){var t=this.schedule.events;if(this.bufferedPos.25){e.event.assetList.forEach((function(t,i){e.event.isAssetPastPlayoutLimit(i)&&r.clearAssetPlayer(t.identifier,null)}));var i=e.end+.25,n=ir.bufferInfo(this.primaryMedia,i,0);(n.end>i||(n.nextStart||0)>i)&&(this.attachPrimary(i,null),this.flushFrontBuffer(i))}},r.itemsMatch=function(e,t){return!!t&&(e===t||e.event&&t.event&&this.eventItemsMatch(e,t)||!e.event&&!t.event&&this.findItemIndex(e)===this.findItemIndex(t))},r.eventItemsMatch=function(e,t){var r;return!!t&&(e===t||e.event.identifier===(null==(r=t.event)?void 0:r.identifier))},r.findItemIndex=function(e,t){return e?this.schedule.findItemIndex(e,t):-1},r.updateSchedule=function(){var e=this.mediaSelection;e&&this.schedule.updateSchedule(e,[])},r.checkBuffer=function(e){var t=this.schedule.items;if(t){var r=ir.bufferInfo(this.primaryMedia,this.timelinePos,0);e&&(this.bufferedPos=this.timelinePos),e||(e=r.len<1),this.updateBufferedPos(r.end,t,e)}},r.updateBufferedPos=function(e,t,r){var i=this.schedule,n=this.bufferingItem;if(!(this.bufferedPos>e))if(1===t.length&&this.itemsMatch(t[0],n))this.bufferedPos=e;else{var a=this.playingItem,s=this.findItemIndex(a),o=i.findItemIndexAtTime(e);if(this.bufferedPos=n.end||null!=(l=f.event)&&l.appendInPlace&&e+.01>=f.start)&&(o=h),h-s>1&&!1===(null==n||null==(u=n.event)?void 0:u.appendInPlace))return;if(this.bufferedPos=e,o>d&&o>s)this.bufferedToItem(f);else{var c=this.primaryDetails;this.primaryLive&&c&&e>c.edge-c.targetduration&&f.start0&&(s=Math.round(1e3*h)/1e3)}if(this.log("Load interstitial asset "+(t+1)+"/"+(r?1:i)+" "+e+(s?" live-start: "+d+" start-offset: "+s:"")),r)return this.createAsset(e,0,0,o,e.duration,r);var f=this.assetListLoader.loadAssetList(e,s);f&&(e.assetListLoader=f)}else if(!a&&i){for(var c=t;c1){var g=t.duration;g&&cl)&&(i.log('Interstitial asset "'+v+'" duration change '+l+" > "+o),t.duration=o,i.updateSchedule())}};y.on(b.LEVEL_UPDATED,(function(e,t){var r=t.details;return E(r)})),y.on(b.LEVEL_PTS_UPDATED,(function(e,t){var r=t.details;return E(r)}));var T=function(e,t){var r=i.getAssetPlayer(v);if(r&&t.tracks){r.off(b.BUFFER_CODECS,T),r.tracks=t.tracks;var n=i.primaryMedia;i.bufferingAsset===r.assetItem&&n&&!r.media&&i.bufferAssetPlayer(r,n)}};y.on(b.BUFFER_CODECS,T);var S=function(){var r,n=i.getAssetPlayer(v);if(i.log("buffered to end of asset "+n),n){var a=i.schedule.findEventIndex(e.identifier),s=null==(r=i.schedule.items)?void 0:r[a];if(i.isInterstitial(s)){var o=e.findAssetIndex(t),l=Ts(e,o);if(e.isAssetPastPlayoutLimit(l)){var u,d=null==(u=i.schedule.items)?void 0:u[a+1];d&&i.bufferedToItem(d)}else i.bufferedToItem(s,l)}}};y.on(b.BUFFERED_TO_END,S);var A=function(t){return function(){if(i.getAssetPlayer(v)){i.shouldPlay=!0;var r=i.schedule.findEventIndex(e.identifier);i.advanceAfterAssetEnded(e,r,t)}}};return y.once(b.MEDIA_ENDED,A(r)),y.once(b.PLAYOUT_LIMIT_REACHED,A(1/0)),y.on(b.ERROR,(function(t,n){var a=i.getAssetPlayer(v);if(n.details!==k.BUFFER_STALLED_ERROR)i.handleAssetItemError(n,e,i.schedule.findEventIndex(e.identifier),r,"Asset player error "+n.error+" "+e);else if(null!=a&&a.media){var s=a.currentTime,o=a.duration-s;s&&e.appendInPlace&&o/a.media.playbackRate<.5?(i.log("Advancing buffer past end of asset "+v+" "+e+" at "+a.media.currentTime),S()):(i.warn("Stalled at "+s+" of "+(s+o)+" in asset "+v+" "+e),i.onTimeupdate(),i.checkBuffer(!0))}})),y.on(b.DESTROYING,(function(){if(i.getAssetPlayer(v)){var t=new Error("Asset player destroyed unexpectedly "+v),n={fatal:!0,type:I.OTHER_ERROR,details:k.INTERSTITIAL_ASSET_ITEM_ERROR,error:t};i.handleAssetItemError(n,e,i.schedule.findEventIndex(e.identifier),r,t.message)}})),this.log("INTERSTITIAL_ASSET_PLAYER_CREATED "+Ss(t)),this.hls.trigger(b.INTERSTITIAL_ASSET_PLAYER_CREATED,{asset:t,assetListIndex:r,event:e,player:y}),y},r.clearInterstitial=function(e,t){var r=this;e.assetList.forEach((function(e){r.clearAssetPlayer(e.identifier,t)})),e.reset()},r.resetAssetPlayer=function(e){var t=this.getAssetPlayerQueueIndex(e);if(-1!==t){this.log('reset asset player "'+e+'" after error');var r=this.playerQueue[t];this.transferMediaFromPlayer(r,null),r.resetDetails()}},r.clearAssetPlayer=function(e,t){var r=this.getAssetPlayerQueueIndex(e);if(-1!==r){this.log('clear asset player "'+e+'" toSegment: '+(t?Rs(t):t));var i=this.playerQueue[r];this.transferMediaFromPlayer(i,t),this.playerQueue.splice(r,1),i.destroy()}},r.emptyPlayerQueue=function(){for(var e;e=this.playerQueue.pop();)e.destroy();this.playerQueue=[]},r.startAssetPlayer=function(e,t,r,i,n){var a=e.interstitial,s=e.assetItem,o=e.assetId,l=a.assetList.length,u=this.playingAsset;this.endedAsset=null,this.playingAsset=s,u&&u.identifier===o||(u&&(this.clearAssetPlayer(u.identifier,r[i]),delete u.error),this.log("INTERSTITIAL_ASSET_STARTED "+(t+1)+"/"+l+" "+Ss(s)),this.hls.trigger(b.INTERSTITIAL_ASSET_STARTED,{asset:s,assetListIndex:t,event:a,schedule:r.slice(0),scheduleIndex:i,player:e})),this.bufferAssetPlayer(e,n)},r.bufferAssetPlayer=function(e,t){var r,i,n=e.interstitial,a=e.assetItem,s=this.schedule.findEventIndex(n.identifier),o=null==(r=this.schedule.items)?void 0:r[s];if(o){this.setBufferingItem(o),this.bufferingAsset=a;var l=this.getBufferingPlayer();if(l!==e){var u=n.appendInPlace;if(!u||!1!==(null==l?void 0:l.interstitial.appendInPlace)){var d=(null==l?void 0:l.tracks)||(null==(i=this.detachedData)?void 0:i.tracks)||this.requiredTracks;if(u&&a!==this.playingAsset){if(!e.tracks)return;if(d&&!j(d,e.tracks)){var h=new Error("Asset "+Ss(a)+" SourceBuffer tracks ('"+Object.keys(e.tracks)+"') are not compatible with primary content tracks ('"+Object.keys(d)+"')"),f={fatal:!0,type:I.OTHER_ERROR,details:k.INTERSTITIAL_ASSET_ITEM_ERROR,error:h},c=n.findAssetIndex(a);return void this.handleAssetItemError(f,n,s,c,h.message)}}this.transferMediaTo(e,t)}}}},r.handleAssetItemError=function(e,t,r,i,n){if(e.details!==k.BUFFER_STALLED_ERROR){var s=t.assetList[i];this.warn("INTERSTITIAL_ASSET_ERROR "+(s?Ss(s):s)+" "+e.error);var o=null==s?void 0:s.identifier,l=this.getAssetPlayerQueueIndex(o),u=this.playerQueue[l]||null,d=this.schedule.items,h=a({},e,{fatal:!1,errorAction:xt(!0),asset:s,assetListIndex:i,event:t,schedule:d,scheduleIndex:r,player:u});if(this.hls.trigger(b.INTERSTITIAL_ASSET_ERROR,h),e.fatal){var f=this.playingAsset,c=new Error(n);if(s&&(this.clearAssetPlayer(o,null),s.error=c),t.assetList.some((function(e){return!e.error}))){for(var g=i;g")+" error: "+e.error);var i=this.timelinePos;-1===i&&(i=this.hls.startPosition);var n=this.updateItem(r,i);this.itemsMatch(r,n)&&this.clearInterstitial(e,null),e.appendInPlace&&(this.attachPrimary(t,null),this.flushFrontBuffer(t));var a=this.schedule.findItemIndexAtTime(i);this.setSchedulePosition(a)}else this.checkStart()},r.onAssetListLoaded=function(e,t){var r,i=this,n=t.event,a=n.identifier,s=t.assetListResponse.ASSETS;if(this.schedule.hasEvent(a)){var o=n.timelineStart,l=n.duration,u=0;s.forEach((function(e,t){var r=parseFloat(e.DURATION);i.createAsset(n,t,u,o+u,r,e.URI),u+=r})),n.duration=u,this.log("Loaded asset-list with duration: "+u+" (was: "+l+") "+n);var d=this.waitingItem,h=(null==d?void 0:d.event.identifier)===a;this.updateSchedule();var f=null==(r=this.bufferingItem)?void 0:r.event;if(h){var c,g=this.schedule.findEventIndex(a),v=null==(c=this.schedule.items)?void 0:c[g];if(v){if(!this.playingItem&&this.timelinePos>v.end&&this.schedule.findItemIndexAtTime(this.timelinePos)!==g)return n.error=new Error("Interstitial no longer within playback range "+this.timelinePos+" "+n),void this.primaryFallback(n);this.setBufferingItem(v)}this.setSchedulePosition(g)}else if((null==f?void 0:f.identifier)===a&&f.appendInPlace){var m=n.assetList[0],p=this.getAssetPlayer(m.identifier),y=this.primaryMedia;m&&p&&y&&this.bufferAssetPlayer(p,y)}}},r.onError=function(e,t){switch(t.details){case k.ASSET_LIST_PARSING_ERROR:case k.ASSET_LIST_LOAD_ERROR:case k.ASSET_LIST_LOAD_TIMEOUT:var r=t.interstitial;r&&this.primaryFallback(r);break;case k.BUFFER_STALLED_ERROR:this.onTimeupdate(),this.checkBuffer(!0)}},i(t,[{key:"interstitialsManager",get:function(){if(!this.manager){if(!this.hls)return null;var e=this,t=function(){return e.bufferingItem||e.waitingItem},r=function(t){return t?e.getAssetPlayer(t.identifier):t},i=function(t,i,a,s,o){if(t){var l=t[i].start,u=t.event;if(u){if("playout"===i||u.timelineOccupancy!==vs.Point){var d=r(a);(null==d?void 0:d.interstitial)===u&&(l+=d.assetItem.startOffset+d[o])}}else l+=("bufferedPos"===s?n():e[s])-t.start;return l}return 0},n=function(){var t=e.bufferedPos;return t===Number.MAX_VALUE?a("primary"):Math.max(t,0)},a=function(t){var r;return null!=(r=e.primaryDetails)&&r.live?e.primaryDetails.edge:e.schedule.durations[t]},s=function(t,n){var a,s,o=e.effectivePlayingItem;if(null==o||null==(a=o.event)||!a.restrictions.skip){e.log("seek to "+t+' "'+n+'"');var l=e.effectivePlayingItem,u=e.schedule.findItemIndexAtTime(t,n),d=null==(s=e.schedule.items)?void 0:s[u],h=e.getBufferingPlayer(),f=null==h?void 0:h.interstitial,c=null==f?void 0:f.appendInPlace,g=l&&e.itemsMatch(l,d);if(l&&(c||g)){var v=r(e.playingAsset),m=(null==v?void 0:v.media)||e.primaryMedia;if(m){var p="primary"===n?m.currentTime:i(l,n,e.playingAsset,"timelinePos","currentTime"),y=t-p,E=(c?p:m.currentTime)+y;if(E>=0&&(!v||c||E<=v.duration))return void(m.currentTime=E)}}if(d){var T=t;if("primary"!==n){var S=t-d[n].start;T=d.start+S}var A=!e.isInterstitial(d);if(e.isInterstitial(l)&&!l.event.appendInPlace||!A&&!d.event.appendInPlace){if(l){var L=e.findItemIndex(l);if(u>L){var R=e.schedule.findJumpRestrictedIndex(L+1,u);if(R>L)return void e.setSchedulePosition(R)}var I=0;if(A)e.timelinePos=T,e.checkBuffer();else{var k,b=null==d||null==(k=d.event)?void 0:k.assetList;if(b)for(var D=t-(d[n]||d).start,_=b.length;_--;){var P=b[_];if(P.duration&&D>=P.startOffset&&D0?t:0},set currentTime(e){s(e,"primary")},get duration(){return a("primary")},get seekableStart(){var t;return(null==(t=e.primaryDetails)?void 0:t.fragmentStart)||0}},integrated:{get bufferedEnd(){return i(t(),"integrated",e.bufferingAsset,"bufferedPos","bufferedEnd")},get currentTime(){return i(e.effectivePlayingItem,"integrated",e.effectivePlayingAsset,"timelinePos","currentTime")},set currentTime(e){s(e,"integrated")},get duration(){return a("integrated")},get seekableStart(){var t;return function(t,r){if(0!==t&&"primary"!==r&&e.schedule.length){var i,n=e.schedule.findItemIndexAtTime(t),a=null==(i=e.schedule.items)?void 0:i[n];if(a)return t+(a[r].start-a.start)}return t}((null==(t=e.primaryDetails)?void 0:t.fragmentStart)||0,"integrated")}},skip:function(){var t=e.effectivePlayingItem,r=null==t?void 0:t.event;if(r&&!r.restrictions.skip){var i=e.findItemIndex(t);if(r.appendInPlace){var n=t.playout.start+t.event.duration;s(n+.001,"playout")}else e.advanceAfterAssetEnded(r,i,1/0)}}}}return this.manager}},{key:"effectivePlayingItem",get:function(){return this.waitingItem||this.playingItem||this.endedItem}},{key:"effectivePlayingAsset",get:function(){return this.playingAsset||this.endedAsset}},{key:"playingLastItem",get:function(){var e,t=this.playingItem,r=null==(e=this.schedule)?void 0:e.items;return!!(this.playbackStarted&&t&&r)&&this.findItemIndex(t)===r.length-1}},{key:"playbackStarted",get:function(){return null!==this.effectivePlayingItem}},{key:"currentTime",get:function(){var e,t,r;if(null!==this.mediaSelection){var i=this.waitingItem||this.playingItem;if(!this.isInterstitial(i)||i.event.appendInPlace){var n=this.media;!n&&null!=(e=this.bufferingItem)&&null!=(t=e.event)&&t.appendInPlace&&(n=this.primaryMedia);var a=null==(r=n)?void 0:r.currentTime;if(void 0!==a&&A(a))return a}}}},{key:"primaryMedia",get:function(){var e;return this.media||(null==(e=this.detachedData)?void 0:e.media)||null}},{key:"playbackDisabled",get:function(){return!1===this.hls.config.enableInterstitialPlayback}},{key:"primaryDetails",get:function(){var e,t;return null==(e=this.mediaSelection)||null==(t=e.main)?void 0:t.details}},{key:"primaryLive",get:function(){var e;return!(null==(e=this.primaryDetails)||!e.live)}}])}(N),Ds=function(e){function t(t,r,i){var n;return(n=e.call(this,t,r,i,"subtitle-stream-controller",x)||this).currentTrackId=-1,n.tracksBuffered=[],n.mainDetails=null,n.registerListeners(),n}o(t,e);var r=t.prototype;return r.onHandlerDestroying=function(){this.unregisterListeners(),e.prototype.onHandlerDestroying.call(this),this.mainDetails=null},r.registerListeners=function(){e.prototype.registerListeners.call(this);var t=this.hls;t.on(b.LEVEL_LOADED,this.onLevelLoaded,this),t.on(b.SUBTITLE_TRACKS_UPDATED,this.onSubtitleTracksUpdated,this),t.on(b.SUBTITLE_TRACK_SWITCH,this.onSubtitleTrackSwitch,this),t.on(b.SUBTITLE_TRACK_LOADED,this.onSubtitleTrackLoaded,this),t.on(b.SUBTITLE_FRAG_PROCESSED,this.onSubtitleFragProcessed,this),t.on(b.BUFFER_FLUSHING,this.onBufferFlushing,this)},r.unregisterListeners=function(){e.prototype.unregisterListeners.call(this);var t=this.hls;t.off(b.LEVEL_LOADED,this.onLevelLoaded,this),t.off(b.SUBTITLE_TRACKS_UPDATED,this.onSubtitleTracksUpdated,this),t.off(b.SUBTITLE_TRACK_SWITCH,this.onSubtitleTrackSwitch,this),t.off(b.SUBTITLE_TRACK_LOADED,this.onSubtitleTrackLoaded,this),t.off(b.SUBTITLE_FRAG_PROCESSED,this.onSubtitleFragProcessed,this),t.off(b.BUFFER_FLUSHING,this.onBufferFlushing,this)},r.startLoad=function(e,t){this.stopLoad(),this.state=Ei.IDLE,this.setInterval(500),this.nextLoadPosition=this.lastCurrentTime=e+this.timelineOffset,this.startPosition=t?-1:e,this.tick()},r.onManifestLoading=function(){e.prototype.onManifestLoading.call(this),this.mainDetails=null},r.onMediaDetaching=function(t,r){this.tracksBuffered=[],e.prototype.onMediaDetaching.call(this,t,r)},r.onLevelLoaded=function(e,t){this.mainDetails=t.details},r.onSubtitleFragProcessed=function(e,t){var r=t.frag,i=t.success;if(this.fragContextChanged(r)||(ee(r)&&(this.fragPrevious=r),this.state=Ei.IDLE),i){var n=this.tracksBuffered[this.currentTrackId];if(n){for(var a,s=r.start,o=0;o=n[o].start&&s<=n[o].end){a=n[o];break}var l=r.start+r.duration;a?a.end=l:(a={start:s,end:l},n.push(a)),this.fragmentTracker.fragBuffered(r),this.fragBufferedComplete(r,null),this.media&&this.tick()}}},r.onBufferFlushing=function(e,t){var r=t.startOffset,i=t.endOffset;if(0===r&&i!==Number.POSITIVE_INFINITY){var n=i-1;if(n<=0)return;t.endOffsetSubtitles=Math.max(0,n),this.tracksBuffered.forEach((function(e){for(var t=0;t=n.length)&&o){this.log("Subtitle track "+s+" loaded ["+a.startSN+","+a.endSN+"]"+(a.lastPartSn?"[part-"+a.lastPartSn+"-"+a.lastPartIndex+"]":"")+",duration:"+a.totalduration),this.mediaBuffer=this.mediaBufferTimeRanges;var l=0;if(a.live||null!=(r=o.details)&&r.live){if(a.deltaUpdateFailed)return;var u=this.mainDetails;if(!u)return void(this.startFragRequested=!1);var d,h=u.fragments[0];o.details?0===(l=this.alignPlaylists(a,o.details,null==(d=this.levelLastLoaded)?void 0:d.details))&&h&&oi(a,l=h.start):a.hasProgramDateTime&&u.hasProgramDateTime?(pi(a,u),l=a.fragmentStart):h&&oi(a,l=h.start),u&&!this.startFragRequested&&this.setStartPosition(u,l)}o.details=a,this.levelLastLoaded=o,s===i&&(this.hls.trigger(b.SUBTITLE_TRACK_UPDATED,{details:a,id:s,groupId:t.groupId}),this.tick(),a.live&&!this.fragCurrent&&this.media&&this.state===Ei.IDLE&&(pt(null,a.fragments,this.media.currentTime,0)||(this.warn("Subtitle playlist not aligned with playback"),o.details=void 0)))}}else this.warn("Subtitle tracks were reset while loading level "+s)},r._handleFragmentLoadComplete=function(e){var t=this,r=e.frag,i=e.payload,n=r.decryptdata,a=this.hls;if(!this.fragContextChanged(r)&&i&&i.byteLength>0&&null!=n&&n.key&&n.iv&&vr(n.method)){var s=performance.now();this.decrypter.decrypt(new Uint8Array(i),n.key.buffer,n.iv.buffer,mr(n.method)).catch((function(e){throw a.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.FRAG_DECRYPT_ERROR,fatal:!1,error:e,reason:e.message,frag:r}),e})).then((function(e){var t=performance.now();a.trigger(b.FRAG_DECRYPTED,{frag:r,payload:e,stats:{tstart:s,tdecrypt:t}})})).catch((function(e){t.warn(e.name+": "+e.message),t.state=Ei.IDLE}))}},r.doTick=function(){if(this.media){if(this.state===Ei.IDLE){var e=this.currentTrackId,t=this.levels,r=null==t?void 0:t[e];if(!r||!t.length||!r.details)return;if(this.waitForLive(r))return;var i=this.config,n=this.getLoadPosition(),a=ir.bufferedInfo(this.tracksBuffered[this.currentTrackId]||[],n,i.maxBufferHole),s=a.end,o=a.len,l=r.details;if(o>this.hls.maxBufferLength+l.levelTargetDuration)return;var u=l.fragments,d=u.length,h=l.edge,f=null,c=this.fragPrevious;if(sh-g?0:g;!(f=pt(c,u,Math.max(u[0].start,s),v))&&c&&c.start>>=0)>i-1)throw new DOMException("Failed to execute '"+t+"' on 'TimeRanges': The index provided ("+r+") is greater than the maximum bound ("+i+")");return e[r][t]};this.buffered={get length(){return e.length},end:function(r){return t("end",r,e.length)},start:function(r){return t("start",r,e.length)}}};function Ps(e,t){var r;try{r=new Event("addtrack")}catch(e){(r=document.createEvent("Event")).initEvent("addtrack",!1,!1)}r.track=e,t.dispatchEvent(r)}function Cs(e,t){var r=e.mode;if("disabled"===r&&(e.mode="hidden"),e.cues&&!e.cues.getCueById(t.id))try{if(e.addCue(t),!e.cues.getCueById(t.id))throw new Error("addCue is failed for: "+t)}catch(r){Y.debug("[texttrack-utils]: "+r);try{var i=new self.TextTrackCue(t.startTime,t.endTime,t.text);i.id=t.id,e.addCue(i)}catch(e){Y.debug("[texttrack-utils]: Legacy TextTrackCue fallback failed: "+e)}}"disabled"===r&&(e.mode=r)}function ws(e,t){var r=e.mode;if("disabled"===r&&(e.mode="hidden"),e.cues)for(var i=e.cues.length;i--;)t&&e.cues[i].removeEventListener("enter",t),e.removeCue(e.cues[i]);"disabled"===r&&(e.mode=r)}function Os(e,t,r,i){var n=e.mode;if("disabled"===n&&(e.mode="hidden"),e.cues&&e.cues.length>0)for(var a=function(e,t,r){var i=[],n=function(e,t){if(t<=e[0].startTime)return 0;var r=e.length-1;if(t>e[r].endTime)return-1;for(var i,n=0,a=r;n<=a;)if(te[i].startTime&&n-1)for(var a=n,s=e.length;a=t&&o.endTime<=r)i.push(o);else if(o.startTime>r)return i}return i}(e.cues,t,r),s=0;s-1&&(this.subtitleTrack=this.queuedDefaultTrack,this.queuedDefaultTrack=-1),this.useTextTrackPolling=!(this.media.textTracks&&"onchange"in this.media.textTracks),this.useTextTrackPolling?this.pollTrackChange(500):this.media.textTracks.addEventListener("change",this.asyncPollTrackChange))},r.pollTrackChange=function(e){self.clearInterval(this.subtitlePollingInterval),this.subtitlePollingInterval=self.setInterval(this.onTextTracksChanged,e)},r.onMediaDetaching=function(e,t){var r=this.media;if(r){var i=!!t.transferMedia;self.clearInterval(this.subtitlePollingInterval),this.useTextTrackPolling||r.textTracks.removeEventListener("change",this.asyncPollTrackChange),this.trackId>-1&&(this.queuedDefaultTrack=this.trackId),this.subtitleTrack=-1,this.media=null,i||xs(r.textTracks).forEach((function(e){ws(e)}))}},r.onManifestLoading=function(){this.tracks=[],this.groupIds=null,this.tracksInGroup=[],this.trackId=-1,this.currentTrack=null,this.selectDefaultTrack=!0},r.onManifestParsed=function(e,t){this.tracks=t.subtitleTracks},r.onSubtitleTrackLoaded=function(e,t){var r=t.id,i=t.groupId,n=t.details,a=this.tracksInGroup[r];if(a&&a.groupId===i){var s=a.details;a.details=t.details,this.log("Subtitle track "+r+' "'+a.name+'" lang:'+a.lang+" group:"+i+" loaded ["+n.startSN+"-"+n.endSN+"]"),r===this.trackId&&this.playlistLoaded(r,t,s)}else this.warn("Subtitle track with id:"+r+" and group:"+i+" not found in active group "+(null==a?void 0:a.groupId))},r.onLevelLoading=function(e,t){this.switchLevel(t.level)},r.onLevelSwitching=function(e,t){this.switchLevel(t.level)},r.switchLevel=function(e){var t=this.hls.levels[e];if(t){var r=t.subtitleGroups||null,i=this.groupIds,n=this.currentTrack;if(!r||(null==i?void 0:i.length)!==(null==r?void 0:r.length)||null!=r&&r.some((function(e){return-1===(null==i?void 0:i.indexOf(e))}))){this.groupIds=r,this.trackId=-1,this.currentTrack=null;var a=this.tracks.filter((function(e){return!r||-1!==r.indexOf(e.groupId)}));if(a.length)this.selectDefaultTrack&&!a.some((function(e){return e.default}))&&(this.selectDefaultTrack=!1),a.forEach((function(e,t){e.id=t}));else if(!n&&!this.tracksInGroup.length)return;this.tracksInGroup=a;var s=this.hls.config.subtitlePreference;if(!n&&s){this.selectDefaultTrack=!1;var o=dt(s,a);if(o>-1)n=a[o];else{var l=dt(s,this.tracks);n=this.tracks[l]}}var u=this.findTrackId(n);-1===u&&n&&(u=this.findTrackId(null));var d={subtitleTracks:a};this.log("Updating subtitle tracks, "+a.length+' track(s) found in "'+(null==r?void 0:r.join(","))+'" group-id'),this.hls.trigger(b.SUBTITLE_TRACKS_UPDATED,d),-1!==u&&-1===this.trackId&&this.setSubtitleTrack(u)}}},r.findTrackId=function(e){for(var t=this.tracksInGroup,r=this.selectDefaultTrack,i=0;i-1){var n=this.tracksInGroup[i];return this.setSubtitleTrack(i),n}if(r)return null;var a=dt(e,t);if(a>-1)return t[a]}}return null},r.loadPlaylist=function(t){e.prototype.loadPlaylist.call(this),this.shouldLoadPlaylist(this.currentTrack)&&this.scheduleLoading(this.currentTrack,t)},r.loadingPlaylist=function(t,r){e.prototype.loadingPlaylist.call(this,t,r);var i=t.id,n=t.groupId,a=this.getUrlWithDirectives(t.url,r),s=t.details,o=null==s?void 0:s.age;this.log("Loading subtitle "+i+' "'+t.name+'" lang:'+t.lang+" group:"+n+(void 0!==(null==r?void 0:r.msn)?" at sn "+r.msn+" part "+r.part:"")+(o&&s.live?" age "+o.toFixed(1)+(s.type&&" "+s.type||""):"")+" "+a),this.hls.trigger(b.SUBTITLE_TRACK_LOADING,{url:a,id:i,groupId:n,deliveryDirectives:r||null,track:t})},r.toggleTrackModes=function(){var e=this.media;if(e){var t,r=xs(e.textTracks),i=this.currentTrack;if(i&&((t=r.filter((function(e){return da(i,e)}))[0])||this.warn('Unable to find subtitle TextTrack with name "'+i.name+'" and language "'+i.lang+'"')),[].slice.call(r).forEach((function(e){"disabled"!==e.mode&&e!==t&&(e.mode="disabled")})),t){var n=this.subtitleDisplay?"showing":"hidden";t.mode!==n&&(t.mode=n)}}},r.setSubtitleTrack=function(e){var t=this.tracksInGroup;if(this.media)if(e<-1||e>=t.length||!A(e))this.warn("Invalid subtitle track id: "+e);else{this.selectDefaultTrack=!1;var r=this.currentTrack,i=t[e]||null;if(this.trackId=e,this.currentTrack=i,this.toggleTrackModes(),i){var n=!!i.details&&!i.details.live;if(e!==this.trackId||i!==r||!n){this.log("Switching to subtitle-track "+e+(i?' "'+i.name+'" lang:'+i.lang+" group:"+i.groupId:""));var a=i.id,s=i.groupId,o=void 0===s?"":s,l=i.name,u=i.type,d=i.url;this.hls.trigger(b.SUBTITLE_TRACK_SWITCH,{id:a,groupId:o,name:l,type:u,url:d});var h=this.switchParams(i.url,null==r?void 0:r.details,i.details);this.loadPlaylist(h)}}else this.hls.trigger(b.SUBTITLE_TRACK_SWITCH,{id:e})}else this.queuedDefaultTrack=e},i(t,[{key:"subtitleDisplay",get:function(){return this._subtitleDisplay},set:function(e){this._subtitleDisplay=e,this.trackId>-1&&this.toggleTrackModes()}},{key:"allSubtitleTracks",get:function(){return this.tracks}},{key:"subtitleTracks",get:function(){return this.tracksInGroup}},{key:"subtitleTrack",get:function(){return this.trackId},set:function(e){this.selectDefaultTrack=!1,this.setSubtitleTrack(e)}}])}(oa),Fs={42:225,92:233,94:237,95:243,96:250,123:231,124:247,125:209,126:241,127:9608,128:174,129:176,130:189,131:191,132:8482,133:162,134:163,135:9834,136:224,137:32,138:232,139:226,140:234,141:238,142:244,143:251,144:193,145:201,146:211,147:218,148:220,149:252,150:8216,151:161,152:42,153:8217,154:9473,155:169,156:8480,157:8226,158:8220,159:8221,160:192,161:194,162:199,163:200,164:202,165:203,166:235,167:206,168:207,169:239,170:212,171:217,172:249,173:219,174:171,175:187,176:195,177:227,178:205,179:204,180:236,181:210,182:242,183:213,184:245,185:123,186:125,187:92,188:94,189:95,190:124,191:8764,192:196,193:228,194:214,195:246,196:223,197:165,198:164,199:9475,200:197,201:229,202:216,203:248,204:9487,205:9491,206:9495,207:9499},Ns=function(e){return String.fromCharCode(Fs[e]||e)},Us=15,Bs=100,Gs={17:1,18:3,21:5,22:7,23:9,16:11,19:12,20:14},Ks={17:2,18:4,21:6,22:8,23:10,19:13,20:15},Vs={25:1,26:3,29:5,30:7,31:9,24:11,27:12,28:14},Hs={25:2,26:4,29:6,30:8,31:10,27:13,28:15},Ys=["white","green","blue","cyan","red","yellow","magenta","black","transparent"],Ws=function(){function e(){this.time=null,this.verboseLevel=0}return e.prototype.log=function(e,t){if(this.verboseLevel>=e){var r="function"==typeof t?t():t;Y.log(this.time+" ["+e+"] "+r)}},e}(),js=function(e){for(var t=[],r=0;rBs&&(this.logger.log(3,"Too large cursor position "+this.pos),this.pos=Bs)},t.moveCursor=function(e){var t=this.pos+e;if(e>1)for(var r=this.pos+1;r=144&&this.backSpace();var r=Ns(e);this.pos>=Bs?this.logger.log(0,(function(){return"Cannot insert "+e.toString(16)+" ("+r+") at position "+t.pos+". Skipping it!"})):(this.chars[this.pos].setChar(r,this.currPenState),this.moveCursor(1))},t.clearFromPos=function(e){var t;for(t=e;t0&&(r=e?"["+t.join(" | ")+"]":t.join("\n")),r},t.getTextAndFormat=function(){return this.rows},e}(),$s=function(){function e(e,t,r){this.chNr=void 0,this.outputFilter=void 0,this.mode=void 0,this.verbose=void 0,this.displayedMemory=void 0,this.nonDisplayedMemory=void 0,this.lastOutputScreen=void 0,this.currRollUpRow=void 0,this.writeScreen=void 0,this.cueStartTime=void 0,this.logger=void 0,this.chNr=e,this.outputFilter=t,this.mode=null,this.verbose=0,this.displayedMemory=new zs(r),this.nonDisplayedMemory=new zs(r),this.lastOutputScreen=new zs(r),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null,this.logger=r}var t=e.prototype;return t.reset=function(){this.mode=null,this.displayedMemory.reset(),this.nonDisplayedMemory.reset(),this.lastOutputScreen.reset(),this.outputFilter.reset(),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null},t.getHandler=function(){return this.outputFilter},t.setHandler=function(e){this.outputFilter=e},t.setPAC=function(e){this.writeScreen.setPAC(e)},t.setBkgData=function(e){this.writeScreen.setBkgData(e)},t.setMode=function(e){e!==this.mode&&(this.mode=e,this.logger.log(2,(function(){return"MODE="+e})),"MODE_POP-ON"===this.mode?this.writeScreen=this.nonDisplayedMemory:(this.writeScreen=this.displayedMemory,this.writeScreen.reset()),"MODE_ROLL-UP"!==this.mode&&(this.displayedMemory.nrRollUpRows=null,this.nonDisplayedMemory.nrRollUpRows=null),this.mode=e)},t.insertChars=function(e){for(var t=this,r=0;r=46,t.italics)t.foreground="white";else{var r=Math.floor(e/2)-16;t.foreground=["white","green","blue","cyan","red","yellow","magenta"][r]}this.logger.log(2,"MIDROW: "+st(t)),this.writeScreen.setPen(t)},t.outputDataUpdate=function(e){void 0===e&&(e=!1);var t=this.logger.time;null!==t&&this.outputFilter&&(null!==this.cueStartTime||this.displayedMemory.isEmpty()?this.displayedMemory.equals(this.lastOutputScreen)||(this.outputFilter.newCue(this.cueStartTime,t,this.lastOutputScreen),e&&this.outputFilter.dispatchCue&&this.outputFilter.dispatchCue(),this.cueStartTime=this.displayedMemory.isEmpty()?null:t):this.cueStartTime=t,this.lastOutputScreen.copy(this.displayedMemory))},t.cueSplitAtTime=function(e){this.outputFilter&&(this.displayedMemory.isEmpty()||(this.outputFilter.newCue&&this.outputFilter.newCue(this.cueStartTime,e,this.displayedMemory),this.cueStartTime=e))},e}(),Js=function(){function e(e,t,r){this.channels=void 0,this.currentChannel=0,this.cmdHistory={a:null,b:null},this.logger=void 0;var i=this.logger=new Ws;this.channels=[null,new $s(e,t,i),new $s(e+1,r,i)]}var t=e.prototype;return t.getHandler=function(e){return this.channels[e].getHandler()},t.setHandler=function(e,t){this.channels[e].setHandler(t)},t.addData=function(e,t){var r=this;this.logger.time=e;for(var i=function(e){var i=127&t[e],n=127&t[e+1],a=!1,s=null;if(0===i&&0===n)return 0;r.logger.log(3,(function(){return"["+js([t[e],t[e+1]])+"] -> ("+js([i,n])+")"}));var o=r.cmdHistory;if(i>=16&&i<=31){if(function(e,t,r){return r.a===e&&r.b===t}(i,n,o))return Zs(null,null,o),r.logger.log(3,(function(){return"Repeated command ("+js([i,n])+") is dropped"})),0;Zs(i,n,r.cmdHistory),(a=r.parseCmd(i,n))||(a=r.parseMidrow(i,n)),a||(a=r.parsePAC(i,n)),a||(a=r.parseBackgroundAttributes(i,n))}else Zs(null,null,o);if(!a&&(s=r.parseChars(i,n))){var l=r.currentChannel;l&&l>0?r.channels[l].insertChars(s):r.logger.log(2,"No channel found yet. TEXT-MODE?")}a||s||r.logger.log(2,(function(){return"Couldn't parse cleaned data "+js([i,n])+" orig: "+js([t[e],t[e+1]])}))},n=0;n=32&&t<=47||(23===e||31===e)&&t>=33&&t<=35))return!1;var r=20===e||21===e||23===e?1:2,i=this.channels[r];return 20===e||21===e||28===e||29===e?32===t?i.ccRCL():33===t?i.ccBS():34===t?i.ccAOF():35===t?i.ccAON():36===t?i.ccDER():37===t?i.ccRU(2):38===t?i.ccRU(3):39===t?i.ccRU(4):40===t?i.ccFON():41===t?i.ccRDC():42===t?i.ccTR():43===t?i.ccRTD():44===t?i.ccEDM():45===t?i.ccCR():46===t?i.ccENM():47===t&&i.ccEOC():i.ccTO(t-32),this.currentChannel=r,!0},t.parseMidrow=function(e,t){var r=0;if((17===e||25===e)&&t>=32&&t<=47){if((r=17===e?1:2)!==this.currentChannel)return this.logger.log(0,"Mismatch channel in midrow parsing"),!1;var i=this.channels[r];return!!i&&(i.ccMIDROW(t),this.logger.log(3,(function(){return"MIDROW ("+js([e,t])+")"})),!0)}return!1},t.parsePAC=function(e,t){var r;if(!((e>=17&&e<=23||e>=25&&e<=31)&&t>=64&&t<=127||(16===e||24===e)&&t>=64&&t<=95))return!1;var i=e<=23?1:2;r=t>=64&&t<=95?1===i?Gs[e]:Vs[e]:1===i?Ks[e]:Hs[e];var n=this.channels[i];return!!n&&(n.setPAC(this.interpretPAC(r,t)),this.currentChannel=i,!0)},t.interpretPAC=function(e,t){var r,i={color:null,italics:!1,indent:null,underline:!1,row:e};return r=t>95?t-96:t-64,i.underline=1==(1&r),r<=13?i.color=["white","green","blue","cyan","red","yellow","magenta","white"][Math.floor(r/2)]:r<=15?(i.italics=!0,i.color="white"):i.indent=4*Math.floor((r-16)/2),i},t.parseChars=function(e,t){var r,i,n=null,a=null;return e>=25?(r=2,a=e-8):(r=1,a=e),a>=17&&a<=19?(i=17===a?t+80:18===a?t+112:t+144,this.logger.log(2,(function(){return"Special char '"+Ns(i)+"' in channel "+r})),n=[i]):e>=32&&e<=127&&(n=0===t?[e]:[e,t]),n&&this.logger.log(3,(function(){return"Char codes =  "+js(n).join(",")})),n},t.parseBackgroundAttributes=function(e,t){var r;if(!((16===e||24===e)&&t>=32&&t<=47||(23===e||31===e)&&t>=45&&t<=47))return!1;var i={};16===e||24===e?(r=Math.floor((t-32)/2),i.background=Ys[r],t%2==1&&(i.background=i.background+"_semi")):45===t?i.background="transparent":(i.foreground="black",47===t&&(i.underline=!0));var n=e<=23?1:2;return this.channels[n].setBkgData(i),!0},t.reset=function(){for(var e=0;e1?t-1:0),i=1;i100)throw new Error("Position must be between 0 and 100.");E=e,this.hasBeenReset=!0}})),Object.defineProperty(o,"positionAlign",n({},l,{get:function(){return T},set:function(e){var t=i(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");T=t,this.hasBeenReset=!0}})),Object.defineProperty(o,"size",n({},l,{get:function(){return S},set:function(e){if(e<0||e>100)throw new Error("Size must be between 0 and 100.");S=e,this.hasBeenReset=!0}})),Object.defineProperty(o,"align",n({},l,{get:function(){return A},set:function(e){var t=i(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");A=t,this.hasBeenReset=!0}})),o.displayState=void 0}return a.prototype.getCueAsHTML=function(){return self.WebVTT.convertCueToDOMTree(self,this.text)},a}(),to=function(){function e(){}return e.prototype.decode=function(e,t){if(!e)return"";if("string"!=typeof e)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(e))},e}();function ro(e){function t(e,t,r,i){return 3600*(0|e)+60*(0|t)+(0|r)+parseFloat(i||0)}var r=e.match(/^(?:(\d+):)?(\d{2}):(\d{2})(\.\d+)?/);return r?parseFloat(r[2])>59?t(r[2],r[3],0,r[4]):t(r[1],r[2],r[3],r[4]):null}var io=function(){function e(){this.values=Object.create(null)}var t=e.prototype;return t.set=function(e,t){this.get(e)||""===t||(this.values[e]=t)},t.get=function(e,t,r){return r?this.has(e)?this.values[e]:t[r]:this.has(e)?this.values[e]:t},t.has=function(e){return e in this.values},t.alt=function(e,t,r){for(var i=0;i=0&&r<=100)return this.set(e,r),!0}return!1},e}();function no(e,t,r,i){var n=i?e.split(i):[e];for(var a in n)if("string"==typeof n[a]){var s=n[a].split(r);2===s.length&&t(s[0],s[1])}}var ao=new eo(0,0,""),so="middle"===ao.align?"middle":"center";function oo(e,t,r){var i=e;function n(){var t=ro(e);if(null===t)throw new Error("Malformed timestamp: "+i);return e=e.replace(/^[^\sa-zA-Z-]+/,""),t}function a(){e=e.replace(/^\s+/,"")}if(a(),t.startTime=n(),a(),"--\x3e"!==e.slice(0,3))throw new Error("Malformed time stamp (time stamps must be separated by '--\x3e'): "+i);e=e.slice(3),a(),t.endTime=n(),a(),function(e,t){var i=new io;no(e,(function(e,t){var n;switch(e){case"region":for(var a=r.length-1;a>=0;a--)if(r[a].id===t){i.set(e,r[a].region);break}break;case"vertical":i.alt(e,t,["rl","lr"]);break;case"line":n=t.split(","),i.integer(e,n[0]),i.percent(e,n[0])&&i.set("snapToLines",!1),i.alt(e,n[0],["auto"]),2===n.length&&i.alt("lineAlign",n[1],["start",so,"end"]);break;case"position":n=t.split(","),i.percent(e,n[0]),2===n.length&&i.alt("positionAlign",n[1],["start",so,"end","line-left","line-right","auto"]);break;case"size":i.percent(e,t);break;case"align":i.alt(e,t,["start",so,"end","left","right"])}}),/:/,/\s/),t.region=i.get("region",null),t.vertical=i.get("vertical","");var n=i.get("line","auto");"auto"===n&&-1===ao.line&&(n=-1),t.line=n,t.lineAlign=i.get("lineAlign","start"),t.snapToLines=i.get("snapToLines",!0),t.size=i.get("size",100),t.align=i.get("align",so);var a=i.get("position","auto");"auto"===a&&50===ao.position&&(a="start"===t.align||"left"===t.align?0:"end"===t.align||"right"===t.align?100:50),t.position=a}(e,t)}function lo(e){return e.replace(//gi,"\n")}var uo=function(){function e(){this.state="INITIAL",this.buffer="",this.decoder=new to,this.regionList=[],this.cue=null,this.oncue=void 0,this.onparsingerror=void 0,this.onflush=void 0}var t=e.prototype;return t.parse=function(e){var t=this;function r(){var e=t.buffer,r=0;for(e=lo(e);r0&&f.push(e)},d.onparsingerror=function(e){u=e},d.onflush=function(){u?s(u):a(f)},h.forEach((function(e){if(p){if(fo(e,"X-TIMESTAMP-MAP=")){p=!1,e.slice(16).split(",").forEach((function(e){fo(e,"LOCAL:")?g=e.slice(6):fo(e,"MPEGTS:")&&(v=parseInt(e.slice(7)))}));try{m=function(e){var t=parseInt(e.slice(-3)),r=parseInt(e.slice(-6,-4)),i=parseInt(e.slice(-9,-7)),n=e.length>9?parseInt(e.substring(0,e.indexOf(":"))):0;if(!(A(t)&&A(r)&&A(i)&&A(n)))throw Error("Malformed X-TIMESTAMP-MAP: Local:"+e);return t+=1e3*r,(t+=6e4*i)+36e5*n}(g)/1e3}catch(e){u=e}return}""===e&&(p=!1)}d.parse(e+"\n")})),d.flush()}var vo="stpp.ttml.im1t",mo=/^(\d{2,}):(\d{2}):(\d{2}):(\d{2})\.?(\d+)?$/,po=/^(\d*(?:\.\d*)?)(h|m|s|ms|f|t)$/,yo={left:"start",center:"center",right:"end",start:"start",end:"end"};function Eo(e,t,r,i){var n=fe(new Uint8Array(e),["mdat"]);if(0!==n.length){var s,o,l,u,d=n.map((function(e){return q(e)})),h=(s=t.baseTime,o=1,void 0===(l=t.timescale)&&(l=1),void 0===u&&(u=!1),wn(s,o,1/l,u));try{d.forEach((function(e){return r(function(e,t){var r=(new DOMParser).parseFromString(e,"text/xml"),i=r.getElementsByTagName("tt")[0];if(!i)throw new Error("Invalid ttml");var n={frameRate:30,subFrameRate:1,frameRateMultiplier:0,tickRate:0},s=Object.keys(n).reduce((function(e,t){return e[t]=i.getAttribute("ttp:"+t)||n[t],e}),{}),o="preserve"!==i.getAttribute("xml:space"),l=So(To(i,"styling","style")),u=So(To(i,"layout","region")),d=To(i,"body","[begin]");return[].map.call(d,(function(e){var r=Ao(e,o);if(!r||!e.hasAttribute("begin"))return null;var i=Io(e.getAttribute("begin"),s),n=Io(e.getAttribute("dur"),s),d=Io(e.getAttribute("end"),s);if(null===i)throw Ro(e);if(null===d){if(null===n)throw Ro(e);d=i+n}var h=new eo(i-t,d-t,r);h.id=co(h.startTime,h.endTime,h.text);var f=function(e,t,r){var i="http://www.w3.org/ns/ttml#styling",n=null,a=["displayAlign","textAlign","color","backgroundColor","fontSize","fontFamily"],s=null!=e&&e.hasAttribute("style")?e.getAttribute("style"):null;return s&&r.hasOwnProperty(s)&&(n=r[s]),a.reduce((function(r,a){var s=Lo(t,i,a)||Lo(e,i,a)||Lo(n,i,a);return s&&(r[a]=s),r}),{})}(u[e.getAttribute("region")],l[e.getAttribute("style")],l),c=f.textAlign;if(c){var g=yo[c];g&&(h.lineAlign=g),h.align=c}return a(h,f),h})).filter((function(e){return null!==e}))}(e,h))}))}catch(e){i(e)}}else i(new Error("Could not parse IMSC1 mdat"))}function To(e,t,r){var i=e.getElementsByTagName(t)[0];return i?[].slice.call(i.querySelectorAll(r)):[]}function So(e){return e.reduce((function(e,t){var r=t.getAttribute("xml:id");return r&&(e[r]=t),e}),{})}function Ao(e,t){return[].slice.call(e.childNodes).reduce((function(e,r,i){var n;return"br"===r.nodeName&&i?e+"\n":null!=(n=r.childNodes)&&n.length?Ao(r,t):t?e+r.textContent.trim().replace(/\s+/g," "):e+r.textContent}),"")}function Lo(e,t,r){return e&&e.hasAttributeNS(t,r)?e.getAttributeNS(t,r):null}function Ro(e){return new Error("Could not parse ttml timestamp "+e)}function Io(e,t){if(!e)return null;var r=ro(e);return null===r&&(mo.test(e)?r=function(e,t){var r=mo.exec(e),i=(0|r[4])+(0|r[5])/t.subFrameRate;return 3600*(0|r[1])+60*(0|r[2])+(0|r[3])+i/t.frameRate}(e,t):po.test(e)&&(r=function(e,t){var r=po.exec(e),i=Number(r[1]);switch(r[2]){case"h":return 3600*i;case"m":return 60*i;case"ms":return 1e3*i;case"f":return i/t.frameRate;case"t":return i/t.tickRate}return i}(e,t))),r}var ko=function(){function e(e,t){this.timelineController=void 0,this.cueRanges=[],this.trackName=void 0,this.startTime=null,this.endTime=null,this.screen=null,this.timelineController=e,this.trackName=t}var t=e.prototype;return t.dispatchCue=function(){null!==this.startTime&&(this.timelineController.addCues(this.trackName,this.startTime,this.endTime,this.screen,this.cueRanges),this.startTime=null)},t.newCue=function(e,t,r){(null===this.startTime||this.startTime>e)&&(this.startTime=e),this.endTime=t,this.screen=r,this.timelineController.createCaptionsTrack(this.trackName)},t.reset=function(){this.cueRanges=[],this.startTime=null},e}(),bo=function(){function e(e){this.hls=void 0,this.media=null,this.config=void 0,this.enabled=!0,this.Cues=void 0,this.textTracks=[],this.tracks=[],this.initPTS=[],this.unparsedVttFrags=[],this.captionsTracks={},this.nonNativeCaptionsTracks={},this.cea608Parser1=void 0,this.cea608Parser2=void 0,this.lastCc=-1,this.lastSn=-1,this.lastPartIndex=-1,this.prevCC=-1,this.vttCCs={ccOffset:0,presentationOffset:0,0:{start:0,prevCC:-1,new:!0}},this.captionsProperties=void 0,this.hls=e,this.config=e.config,this.Cues=e.config.cueHandler,this.captionsProperties={textTrack1:{label:this.config.captionsTextTrack1Label,languageCode:this.config.captionsTextTrack1LanguageCode},textTrack2:{label:this.config.captionsTextTrack2Label,languageCode:this.config.captionsTextTrack2LanguageCode},textTrack3:{label:this.config.captionsTextTrack3Label,languageCode:this.config.captionsTextTrack3LanguageCode},textTrack4:{label:this.config.captionsTextTrack4Label,languageCode:this.config.captionsTextTrack4LanguageCode}},e.on(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.on(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.MANIFEST_LOADED,this.onManifestLoaded,this),e.on(b.SUBTITLE_TRACKS_UPDATED,this.onSubtitleTracksUpdated,this),e.on(b.FRAG_LOADING,this.onFragLoading,this),e.on(b.FRAG_LOADED,this.onFragLoaded,this),e.on(b.FRAG_PARSING_USERDATA,this.onFragParsingUserdata,this),e.on(b.FRAG_DECRYPTED,this.onFragDecrypted,this),e.on(b.INIT_PTS_FOUND,this.onInitPtsFound,this),e.on(b.SUBTITLE_TRACKS_CLEARED,this.onSubtitleTracksCleared,this),e.on(b.BUFFER_FLUSHING,this.onBufferFlushing,this)}var t=e.prototype;return t.destroy=function(){var e=this.hls;e.off(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.off(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.MANIFEST_LOADED,this.onManifestLoaded,this),e.off(b.SUBTITLE_TRACKS_UPDATED,this.onSubtitleTracksUpdated,this),e.off(b.FRAG_LOADING,this.onFragLoading,this),e.off(b.FRAG_LOADED,this.onFragLoaded,this),e.off(b.FRAG_PARSING_USERDATA,this.onFragParsingUserdata,this),e.off(b.FRAG_DECRYPTED,this.onFragDecrypted,this),e.off(b.INIT_PTS_FOUND,this.onInitPtsFound,this),e.off(b.SUBTITLE_TRACKS_CLEARED,this.onSubtitleTracksCleared,this),e.off(b.BUFFER_FLUSHING,this.onBufferFlushing,this),this.hls=this.config=this.media=null,this.cea608Parser1=this.cea608Parser2=void 0},t.initCea608Parsers=function(){var e=new ko(this,"textTrack1"),t=new ko(this,"textTrack2"),r=new ko(this,"textTrack3"),i=new ko(this,"textTrack4");this.cea608Parser1=new Js(1,e,t),this.cea608Parser2=new Js(3,r,i)},t.addCues=function(e,t,r,i,n){for(var a,s,o,l,u=!1,d=n.length;d--;){var h=n[d],f=(a=h[0],s=h[1],o=t,l=r,Math.min(s,l)-Math.max(a,o));if(f>=0&&(h[0]=Math.min(h[0],t),h[1]=Math.max(h[1],r),u=!0,f/(r-t)>.5))return}if(u||n.push([t,r]),this.config.renderTextTracksNatively){var c=this.captionsTracks[e];this.Cues.newCue(c,t,r,i)}else{var g=this.Cues.newCue(null,t,r,i);this.hls.trigger(b.CUES_PARSED,{type:"captions",cues:g,track:e})}},t.onInitPtsFound=function(e,t){var r=this,i=t.frag,n=t.id,a=t.initPTS,s=t.timescale,o=this.unparsedVttFrags;n===w&&(this.initPTS[i.cc]={baseTime:a,timescale:s}),o.length&&(this.unparsedVttFrags=[],o.forEach((function(e){r.initPTS[e.frag.cc]?r.onFragLoaded(b.FRAG_LOADED,e):r.hls.trigger(b.SUBTITLE_FRAG_PROCESSED,{success:!1,frag:e.frag,error:new Error("Subtitle discontinuity domain does not match main")})})))},t.getExistingTrack=function(e,t){var r=this.media;if(r)for(var i=0;ii.cc||l.trigger(b.SUBTITLE_FRAG_PROCESSED,{success:!1,frag:i,error:t})}))}else s.push(e)},t._fallbackToIMSC1=function(e,t){var r=this,i=this.tracks[e.level];i.textCodec||Eo(t,this.initPTS[e.cc],(function(){i.textCodec=vo,r._parseIMSC1(e,t)}),(function(){i.textCodec="wvtt"}))},t._appendCues=function(e,t){var r=this.hls;if(this.config.renderTextTracksNatively){var i=this.textTracks[t];if(!i||"disabled"===i.mode)return;e.forEach((function(e){return Cs(i,e)}))}else{var n=this.tracks[t];if(!n)return;var a=n.default?"default":"subtitles"+t;r.trigger(b.CUES_PARSED,{type:"subtitles",cues:e,track:a})}},t.onFragDecrypted=function(e,t){t.frag.type===x&&this.onFragLoaded(b.FRAG_LOADED,t)},t.onSubtitleTracksCleared=function(){this.tracks=[],this.captionsTracks={}},t.onFragParsingUserdata=function(e,t){if(this.enabled&&this.config.enableCEA708Captions){var r=t.frag,i=t.samples;if(r.type!==w||"NONE"!==this.closedCaptionsForLevel(r))for(var n=0;n=16?o--:o++;var g=lo(l.trim()),v=co(t,r,g);null!=e&&null!=(f=e.cues)&&f.getCueById(v)||((a=new d(t,r,g)).id=v,a.line=h+1,a.align="left",a.position=10+Math.min(80,10*Math.floor(8*o/32)),u.push(a))}return e&&u.length&&(u.sort((function(e,t){return"auto"===e.line||"auto"===t.line?0:e.line>8&&t.line>8?t.line-e.line:e.line-t.line})),u.forEach((function(t){return Cs(e,t)}))),u}},wo=/(\d+)-(\d+)\/(\d+)/,Oo=function(){function e(e){this.fetchSetup=void 0,this.requestTimeout=void 0,this.request=null,this.response=null,this.controller=void 0,this.context=null,this.config=null,this.callbacks=null,this.stats=void 0,this.loader=null,this.fetchSetup=e.fetchSetup||xo,this.controller=new self.AbortController,this.stats=new Q}var t=e.prototype;return t.destroy=function(){this.loader=this.callbacks=this.context=this.config=this.request=null,this.abortInternal(),this.response=null,this.fetchSetup=this.controller=this.stats=null},t.abortInternal=function(){this.controller&&!this.stats.loading.end&&(this.stats.aborted=!0,this.controller.abort())},t.abort=function(){var e;this.abortInternal(),null!=(e=this.callbacks)&&e.onAbort&&this.callbacks.onAbort(this.stats,this.context,this.response)},t.load=function(e,t,r){var i=this,n=this.stats;if(n.loading.start)throw new Error("Loader can only be used once.");n.loading.start=self.performance.now();var s=function(e,t){var r={method:"GET",mode:"cors",credentials:"same-origin",signal:t,headers:new self.Headers(a({},e.headers))};return e.rangeEnd&&r.headers.set("Range","bytes="+e.rangeStart+"-"+String(e.rangeEnd-1)),r}(e,this.controller.signal),o="arraybuffer"===e.responseType,l=o?"byteLength":"length",u=t.loadPolicy,d=u.maxTimeToFirstByteMs,h=u.maxLoadTimeMs;this.context=e,this.config=t,this.callbacks=r,this.request=this.fetchSetup(e,s),self.clearTimeout(this.requestTimeout),t.timeout=d&&A(d)?d:h,this.requestTimeout=self.setTimeout((function(){i.callbacks&&(i.abortInternal(),i.callbacks.onTimeout(n,e,i.response))}),t.timeout),(Xn(this.request)?this.request.then(self.fetch):self.fetch(this.request)).then((function(r){var a;i.response=i.loader=r;var s=Math.max(self.performance.now(),n.loading.start);if(self.clearTimeout(i.requestTimeout),t.timeout=h,i.requestTimeout=self.setTimeout((function(){i.callbacks&&(i.abortInternal(),i.callbacks.onTimeout(n,e,i.response))}),h-(s-n.loading.start)),!r.ok){var l=r.status,u=r.statusText;throw new Mo(u||"fetch, bad network response",l,r)}n.loading.first=s,n.total=function(e){var t=e.get("Content-Range");if(t){var r=function(e){var t=wo.exec(e);if(t)return parseInt(t[2])-parseInt(t[1])+1}(t);if(A(r))return r}var i=e.get("Content-Length");if(i)return parseInt(i)}(r.headers)||n.total;var d=null==(a=i.callbacks)?void 0:a.onProgress;return d&&A(t.highWaterMark)?i.loadProgressively(r,n,e,t.highWaterMark,d):o?r.arrayBuffer():"json"===e.responseType?r.json():r.text()})).then((function(r){var a,s,o=i.response;if(!o)throw new Error("loader destroyed");self.clearTimeout(i.requestTimeout),n.loading.end=Math.max(self.performance.now(),n.loading.first);var u=r[l];u&&(n.loaded=n.total=u);var d={url:o.url,data:r,code:o.status},h=null==(a=i.callbacks)?void 0:a.onProgress;h&&!A(t.highWaterMark)&&h(n,e,r,o),null==(s=i.callbacks)||s.onSuccess(d,n,e,o)})).catch((function(t){var r;if(self.clearTimeout(i.requestTimeout),!n.aborted){var a=t&&t.code||0,s=t?t.message:null;null==(r=i.callbacks)||r.onError({code:a,text:s},e,t?t.details:null,n)}}))},t.getCacheAge=function(){var e=null;if(this.response){var t=this.response.headers.get("age");e=t?parseFloat(t):null}return e},t.getResponseHeader=function(e){return this.response?this.response.headers.get(e):null},t.loadProgressively=function(e,t,r,i,n){void 0===i&&(i=0);var a=new Ai,s=e.body.getReader(),o=function(){return s.read().then((function(s){if(s.done)return a.dataLength&&n(t,r,a.flush().buffer,e),Promise.resolve(new ArrayBuffer(0));var l=s.value,u=l.length;return t.loaded+=u,u=i&&n(t,r,a.flush().buffer,e)):n(t,r,l.buffer,e),o()})).catch((function(){return Promise.reject()}))};return o()},e}();function xo(e,t){return new self.Request(e.url,t)}var Mo=function(e){function t(t,r,i){var n;return(n=e.call(this,t)||this).code=void 0,n.details=void 0,n.code=r,n.details=i,n}return o(t,e),t}(c(Error)),Fo=/^age:\s*[\d.]+\s*$/im,No=function(){function e(e){this.xhrSetup=void 0,this.requestTimeout=void 0,this.retryTimeout=void 0,this.retryDelay=void 0,this.config=null,this.callbacks=null,this.context=null,this.loader=null,this.stats=void 0,this.xhrSetup=e&&e.xhrSetup||null,this.stats=new Q,this.retryDelay=0}var t=e.prototype;return t.destroy=function(){this.callbacks=null,this.abortInternal(),this.loader=null,this.config=null,this.context=null,this.xhrSetup=null},t.abortInternal=function(){var e=this.loader;self.clearTimeout(this.requestTimeout),self.clearTimeout(this.retryTimeout),e&&(e.onreadystatechange=null,e.onprogress=null,4!==e.readyState&&(this.stats.aborted=!0,e.abort()))},t.abort=function(){var e;this.abortInternal(),null!=(e=this.callbacks)&&e.onAbort&&this.callbacks.onAbort(this.stats,this.context,this.loader)},t.load=function(e,t,r){if(this.stats.loading.start)throw new Error("Loader can only be used once.");this.stats.loading.start=self.performance.now(),this.context=e,this.config=t,this.callbacks=r,this.loadInternal()},t.loadInternal=function(){var e=this,t=this.config,r=this.context;if(t&&r){var i=this.loader=new self.XMLHttpRequest,n=this.stats;n.loading.first=0,n.loaded=0,n.aborted=!1;var a=this.xhrSetup;a?Promise.resolve().then((function(){if(e.loader===i&&!e.stats.aborted)return a(i,r.url)})).catch((function(t){if(e.loader===i&&!e.stats.aborted)return i.open("GET",r.url,!0),a(i,r.url)})).then((function(){e.loader!==i||e.stats.aborted||e.openAndSendXhr(i,r,t)})).catch((function(t){var a;null==(a=e.callbacks)||a.onError({code:i.status,text:t.message},r,i,n)})):this.openAndSendXhr(i,r,t)}},t.openAndSendXhr=function(e,t,r){e.readyState||e.open("GET",t.url,!0);var i=t.headers,n=r.loadPolicy,a=n.maxTimeToFirstByteMs,s=n.maxLoadTimeMs;if(i)for(var o in i)e.setRequestHeader(o,i[o]);t.rangeEnd&&e.setRequestHeader("Range","bytes="+t.rangeStart+"-"+(t.rangeEnd-1)),e.onreadystatechange=this.readystatechange.bind(this),e.onprogress=this.loadprogress.bind(this),e.responseType=t.responseType,self.clearTimeout(this.requestTimeout),r.timeout=a&&A(a)?a:s,this.requestTimeout=self.setTimeout(this.loadtimeout.bind(this),r.timeout),e.send()},t.readystatechange=function(){var e=this.context,t=this.loader,r=this.stats;if(e&&t){var i=t.readyState,n=this.config;if(!r.aborted&&i>=2&&(0===r.loading.first&&(r.loading.first=Math.max(self.performance.now(),r.loading.start),n.timeout!==n.loadPolicy.maxLoadTimeMs&&(self.clearTimeout(this.requestTimeout),n.timeout=n.loadPolicy.maxLoadTimeMs,this.requestTimeout=self.setTimeout(this.loadtimeout.bind(this),n.loadPolicy.maxLoadTimeMs-(r.loading.first-r.loading.start)))),4===i)){self.clearTimeout(this.requestTimeout),t.onreadystatechange=null,t.onprogress=null;var a=t.status,s="text"===t.responseType?t.responseText:null;if(a>=200&&a<300){var o=null!=s?s:t.response;if(null!=o){var l,u;r.loading.end=Math.max(self.performance.now(),r.loading.first);var d="arraybuffer"===t.responseType?o.byteLength:o.length;r.loaded=r.total=d,r.bwEstimate=8e3*r.total/(r.loading.end-r.loading.first);var h=null==(l=this.callbacks)?void 0:l.onProgress;h&&h(r,e,o,t);var f={url:t.responseURL,data:o,code:a};return void(null==(u=this.callbacks)||u.onSuccess(f,r,e,t))}}var c,g=n.loadPolicy.errorRetry;It(g,r.retry,!1,{url:e.url,data:void 0,code:a})?this.retry(g):(Y.error(a+" while loading "+e.url),null==(c=this.callbacks)||c.onError({code:a,text:t.statusText},e,t,r))}}},t.loadtimeout=function(){if(this.config){var e=this.config.loadPolicy.timeoutRetry;if(It(e,this.stats.retry,!0))this.retry(e);else{var t;Y.warn("timeout while loading "+(null==(t=this.context)?void 0:t.url));var r=this.callbacks;r&&(this.abortInternal(),r.onTimeout(this.stats,this.context,this.loader))}}},t.retry=function(e){var t=this.context,r=this.stats;this.retryDelay=Lt(e,r.retry),r.retry++,Y.warn((status?"HTTP Status "+status:"Timeout")+" while loading "+(null==t?void 0:t.url)+", retrying "+r.retry+"/"+e.maxNumRetry+" in "+this.retryDelay+"ms"),this.abortInternal(),this.loader=null,self.clearTimeout(this.retryTimeout),this.retryTimeout=self.setTimeout(this.loadInternal.bind(this),this.retryDelay)},t.loadprogress=function(e){var t=this.stats;t.loaded=e.loaded,e.lengthComputable&&(t.total=e.total)},t.getCacheAge=function(){var e=null;if(this.loader&&Fo.test(this.loader.getAllResponseHeaders())){var t=this.loader.getResponseHeader("age");e=t?parseFloat(t):null}return e},t.getResponseHeader=function(e){return this.loader&&new RegExp("^"+e+":\\s*[\\d.]+\\s*$","im").test(this.loader.getAllResponseHeaders())?this.loader.getResponseHeader(e):null},e}(),Uo=d(d({autoStartLoad:!0,startPosition:-1,defaultAudioCodec:void 0,debug:!1,capLevelOnFPSDrop:!1,capLevelToPlayerSize:!1,ignoreDevicePixelRatio:!1,maxDevicePixelRatio:Number.POSITIVE_INFINITY,preferManagedMediaSource:!0,initialLiveManifestSize:1,maxBufferLength:30,backBufferLength:1/0,frontBufferFlushThreshold:1/0,startOnSegmentBoundary:!1,maxBufferSize:6e7,maxFragLookUpTolerance:.25,maxBufferHole:.1,detectStallWithCurrentTimeMs:1250,highBufferWatchdogPeriod:2,nudgeOffset:.1,nudgeMaxRetry:3,nudgeOnVideoHole:!0,liveSyncMode:"edge",liveSyncDurationCount:3,liveSyncOnStallIncrease:1,liveMaxLatencyDurationCount:1/0,liveSyncDuration:void 0,liveMaxLatencyDuration:void 0,maxLiveSyncPlaybackRate:1,liveDurationInfinity:!1,liveBackBufferLength:null,maxMaxBufferLength:600,enableWorker:!0,workerPath:null,enableSoftwareAES:!0,startLevel:void 0,startFragPrefetch:!1,fpsDroppedMonitoringPeriod:5e3,fpsDroppedMonitoringThreshold:.2,appendErrorMaxRetry:3,ignorePlaylistParsingErrors:!1,loader:No,fLoader:void 0,pLoader:void 0,xhrSetup:void 0,licenseXhrSetup:void 0,licenseResponseCallback:void 0,abrController:vt,bufferController:ma,capLevelController:Ta,errorController:Ot,fpsController:fs,stretchShortVideoTrack:!1,maxAudioFramesDrift:1,forceKeyFrameOnDiscontinuity:!0,abrEwmaFastLive:3,abrEwmaSlowLive:9,abrEwmaFastVoD:3,abrEwmaSlowVoD:9,abrEwmaDefaultEstimate:5e5,abrEwmaDefaultEstimateMax:5e6,abrBandWidthFactor:.95,abrBandWidthUpFactor:.7,abrMaxWithRealBitrate:!1,maxStarvationDelay:4,maxLoadingDelay:4,minAutoBitrate:0,emeEnabled:!1,widevineLicenseUrl:void 0,drmSystems:{},drmSystemOptions:{},requestMediaKeySystemAccessFunc:Mr,requireKeySystemAccessOnStart:!1,testBandwidth:!0,progressive:!1,lowLatencyMode:!0,cmcd:void 0,enableDateRangeMetadataCues:!0,enableEmsgMetadataCues:!0,enableEmsgKLVMetadata:!1,enableID3MetadataCues:!0,enableInterstitialPlayback:!0,interstitialAppendInPlace:!0,interstitialLiveLookAhead:10,useMediaCapabilities:!0,preserveManualLevelOnError:!1,certLoadPolicy:{default:{maxTimeToFirstByteMs:8e3,maxLoadTimeMs:2e4,timeoutRetry:null,errorRetry:null}},keyLoadPolicy:{default:{maxTimeToFirstByteMs:8e3,maxLoadTimeMs:2e4,timeoutRetry:{maxNumRetry:1,retryDelayMs:1e3,maxRetryDelayMs:2e4,backoff:"linear"},errorRetry:{maxNumRetry:8,retryDelayMs:1e3,maxRetryDelayMs:2e4,backoff:"linear"}}},manifestLoadPolicy:{default:{maxTimeToFirstByteMs:1/0,maxLoadTimeMs:2e4,timeoutRetry:{maxNumRetry:2,retryDelayMs:0,maxRetryDelayMs:0},errorRetry:{maxNumRetry:1,retryDelayMs:1e3,maxRetryDelayMs:8e3}}},playlistLoadPolicy:{default:{maxTimeToFirstByteMs:1e4,maxLoadTimeMs:2e4,timeoutRetry:{maxNumRetry:2,retryDelayMs:0,maxRetryDelayMs:0},errorRetry:{maxNumRetry:2,retryDelayMs:1e3,maxRetryDelayMs:8e3}}},fragLoadPolicy:{default:{maxTimeToFirstByteMs:1e4,maxLoadTimeMs:12e4,timeoutRetry:{maxNumRetry:4,retryDelayMs:0,maxRetryDelayMs:0},errorRetry:{maxNumRetry:6,retryDelayMs:1e3,maxRetryDelayMs:8e3}}},steeringManifestLoadPolicy:{default:{maxTimeToFirstByteMs:1e4,maxLoadTimeMs:2e4,timeoutRetry:{maxNumRetry:2,retryDelayMs:0,maxRetryDelayMs:0},errorRetry:{maxNumRetry:1,retryDelayMs:1e3,maxRetryDelayMs:8e3}}},interstitialAssetListLoadPolicy:{default:{maxTimeToFirstByteMs:1e4,maxLoadTimeMs:3e4,timeoutRetry:{maxNumRetry:0,retryDelayMs:0,maxRetryDelayMs:0},errorRetry:{maxNumRetry:0,retryDelayMs:1e3,maxRetryDelayMs:8e3}}},manifestLoadingTimeOut:1e4,manifestLoadingMaxRetry:1,manifestLoadingRetryDelay:1e3,manifestLoadingMaxRetryTimeout:64e3,levelLoadingTimeOut:1e4,levelLoadingMaxRetry:4,levelLoadingRetryDelay:1e3,levelLoadingMaxRetryTimeout:64e3,fragLoadingTimeOut:2e4,fragLoadingMaxRetry:6,fragLoadingRetryDelay:1e3,fragLoadingMaxRetryTimeout:64e3},{cueHandler:Co,enableWebVTT:!0,enableIMSC1:!0,enableCEA708Captions:!0,captionsTextTrack1Label:"English",captionsTextTrack1LanguageCode:"en",captionsTextTrack2Label:"Spanish",captionsTextTrack2LanguageCode:"es",captionsTextTrack3Label:"Unknown CC",captionsTextTrack3LanguageCode:"",captionsTextTrack4Label:"Unknown CC",captionsTextTrack4LanguageCode:"",renderTextTracksNatively:!0}),{},{subtitleStreamController:Ds,subtitleTrackController:Ms,timelineController:bo,audioStreamController:sa,audioTrackController:ha,emeController:ds,cmcdController:ns,contentSteeringController:as,interstitialsController:bs});function Bo(e){return e&&"object"==typeof e?Array.isArray(e)?e.map(Bo):Object.keys(e).reduce((function(t,r){return t[r]=Bo(e[r]),t}),{}):e}function Go(e,t){var r=e.loader;r!==Oo&&r!==No?(t.log("[config]: Custom loader detected, cannot enable progressive streaming"),e.progressive=!1):function(){if(self.fetch&&self.AbortController&&self.ReadableStream&&self.Request)try{return new self.ReadableStream({}),!0}catch(e){}return!1}()&&(e.loader=Oo,e.progressive=!0,e.enableSoftwareAES=!0,t.log("[config]: Progressive streaming enabled, using FetchLoader"))}var Ko=function(e){function t(t,r){var i;return(i=e.call(this,"gap-controller",t.logger)||this).hls=null,i.fragmentTracker=null,i.media=null,i.mediaSource=void 0,i.nudgeRetry=0,i.stallReported=!1,i.stalled=null,i.moved=!1,i.seeking=!1,i.buffered={},i.lastCurrentTime=0,i.ended=0,i.waiting=0,i.onMediaPlaying=function(){i.ended=0,i.waiting=0},i.onMediaWaiting=function(){var e;null!=(e=i.media)&&e.seeking||(i.waiting=self.performance.now(),i.tick())},i.onMediaEnded=function(){var e;i.hls&&(i.ended=(null==(e=i.media)?void 0:e.currentTime)||1,i.hls.trigger(b.MEDIA_ENDED,{stalled:!1}))},i.hls=t,i.fragmentTracker=r,i.registerListeners(),i}o(t,e);var r=t.prototype;return r.registerListeners=function(){var e=this.hls;e&&(e.on(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.on(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.on(b.BUFFER_APPENDED,this.onBufferAppended,this))},r.unregisterListeners=function(){var e=this.hls;e&&(e.off(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.off(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.off(b.BUFFER_APPENDED,this.onBufferAppended,this))},r.destroy=function(){e.prototype.destroy.call(this),this.unregisterListeners(),this.media=this.hls=this.fragmentTracker=null,this.mediaSource=void 0},r.onMediaAttached=function(e,t){this.setInterval(100),this.mediaSource=t.mediaSource;var r=this.media=t.media;ls(r,"playing",this.onMediaPlaying),ls(r,"waiting",this.onMediaWaiting),ls(r,"ended",this.onMediaEnded)},r.onMediaDetaching=function(e,t){this.clearInterval();var r=this.media;r&&(us(r,"playing",this.onMediaPlaying),us(r,"waiting",this.onMediaWaiting),us(r,"ended",this.onMediaEnded),this.media=null),this.mediaSource=void 0},r.onBufferAppended=function(e,t){this.buffered=t.timeRanges},r.tick=function(){var e;if(null!=(e=this.media)&&e.readyState&&this.hasBuffered){var t=this.media.currentTime;this.poll(t,this.lastCurrentTime),this.lastCurrentTime=t}},r.poll=function(e,t){var r,i,n=null==(r=this.hls)?void 0:r.config;if(n){var a=this.media;if(a){var s=a.seeking,o=this.seeking&&!s,l=!this.seeking&&s,u=a.paused&&!s||a.ended||0===a.playbackRate;if(this.seeking=s,e!==t)return t&&(this.ended=0),this.moved=!0,s||(this.nudgeRetry=0,n.nudgeOnVideoHole&&!u&&e>t&&this.nudgeOnVideoHole(e,t)),void(0===this.waiting&&this.stallResolved(e));if(l||o)o&&this.stallResolved(e);else{if(u)return this.nudgeRetry=0,this.stallResolved(e),void(!this.ended&&a.ended&&this.hls&&(this.ended=e||1,this.hls.trigger(b.MEDIA_ENDED,{stalled:!1})));if(ir.getBuffered(a).length){var d=ir.bufferInfo(a,e,0),h=d.nextStart||0,f=this.fragmentTracker;if(s&&f&&this.hls){var c=Vo(this.hls.inFlightFragments,e),g=d.len>2,v=!h||c||h-e>2&&!f.getPartialFragment(e);if(g||v)return;this.moved=!1}var m=null==(i=this.hls)?void 0:i.latestLevelDetails;if(!this.moved&&null!==this.stalled&&f){if(!(d.len>0||h))return;var p=Math.max(h,d.start||0)-e,y=null!=m&&m.live?2*m.targetduration:2,E=f.getPartialFragment(e);if(p>0&&(p<=y||E))return void(a.paused||this._trySkipBufferHole(E))}var T=n.detectStallWithCurrentTimeMs,S=self.performance.now(),A=this.waiting,L=this.stalled;if(null===L){if(!(A>0&&S-A=T||A)&&this.hls){var I;if("ended"===(null==(I=this.mediaSource)?void 0:I.readyState)&&(null==m||!m.live)&&Math.abs(e-((null==m?void 0:m.edge)||0))<1){if(this.ended)return;return this.ended=e||1,void this.hls.trigger(b.MEDIA_ENDED,{stalled:!0})}if(this._reportStall(d),!this.media||!this.hls)return}var k=ir.bufferInfo(a,e,n.maxBufferHole);this._tryFixBufferStall(k,R,e)}else this.nudgeRetry=0}}}},r.stallResolved=function(e){var t=this.stalled;if(t&&this.hls&&(this.stalled=null,this.stallReported)){var r=self.performance.now()-t;this.log("playback not stuck anymore @"+e+", after "+Math.round(r)+"ms"),this.stallReported=!1,this.waiting=0,this.hls.trigger(b.STALL_RESOLVED,{})}},r.nudgeOnVideoHole=function(e,t){var r,i=this.buffered.video;if(this.hls&&this.media&&this.fragmentTracker&&null!=(r=this.buffered.audio)&&r.length&&i&&i.length>1&&e>i.end(0)){var n=ir.bufferedInfo(ir.timeRangesToArray(this.buffered.audio),e,0);if(n.len>1&&t>=n.start){var a=ir.timeRangesToArray(i),s=ir.bufferedInfo(a,t,0).bufferedIndex;if(s>-1&&ss)&&u-l<1&&e-l<2){var d=new Error("nudging playhead to flush pipeline after video hole. currentTime: "+e+" hole: "+l+" -> "+u+" buffered index: "+o);this.warn(d.message),this.media.currentTime+=1e-6;var h=this.fragmentTracker.getPartialFragment(e)||void 0,f=ir.bufferInfo(this.media,e,0);this.hls.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.BUFFER_SEEK_OVER_HOLE,fatal:!1,error:d,reason:d.message,frag:h,buffer:f.len,bufferInfo:f})}}}}},r._tryFixBufferStall=function(e,t,r){var i,n,a=this.fragmentTracker,s=this.media,o=null==(i=this.hls)?void 0:i.config;if(s&&a&&o){var l=null==(n=this.hls)?void 0:n.latestLevelDetails,u=a.getPartialFragment(r);if((u||null!=l&&l.live&&r1&&e.len>o.maxBufferHole||e.nextStart&&(e.nextStart-r1e3*o.highBufferWatchdogPeriod||this.waiting)&&(this.warn("Trying to nudge playhead over buffer-hole"),this._tryNudgeBuffer(e))}},r.adjacentTraversal=function(e,t){var r=this.fragmentTracker,i=e.nextStart;if(r&&i){var n=r.getFragAtPos(t,w),a=r.getFragAtPos(i,w);if(n&&a)return a.sn-n.sn<2}return!1},r._reportStall=function(e){var t=this.hls,r=this.media,i=this.stallReported,n=this.stalled;if(!i&&null!==n&&r&&t){this.stallReported=!0;var a=new Error("Playback stalling at @"+r.currentTime+" due to low buffer ("+st(e)+")");this.warn(a.message),t.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.BUFFER_STALLED_ERROR,fatal:!1,error:a,buffer:e.len,bufferInfo:e,stalled:{start:n}})}},r._trySkipBufferHole=function(e){var t,r=this.fragmentTracker,i=this.media,n=null==(t=this.hls)?void 0:t.config;if(!i||!r||!n)return 0;var a=i.currentTime,s=ir.bufferInfo(i,a,0),o=a0&&s.len<1&&i.readyState<3,d=o-a;if(d>0&&(l||u)){if(d>n.maxBufferHole){var h=!1;if(0===a){var f=r.getAppendedFrag(0,w);f&&o0}}])}(er);function Vo(e,t){var r=Ho(e.main);if(r&&r.start<=t)return r;var i=Ho(e.audio);return i&&i.start<=t?i:null}function Ho(e){if(!e)return null;switch(e.state){case Ei.IDLE:case Ei.STOPPED:case Ei.ENDED:case Ei.ERROR:return null}return e.frag}function Yo(){if("undefined"!=typeof self)return self.VTTCue||self.TextTrackCue}function Wo(e,t,r,i,n){var a=new e(t,r,"");try{a.value=i,n&&(a.type=n)}catch(s){a=new e(t,r,st(n?d({type:n},i):i))}return a}var jo=function(){var e=Yo();try{e&&new e(0,Number.POSITIVE_INFINITY,"")}catch(e){return Number.MAX_VALUE}return Number.POSITIVE_INFINITY}(),qo=function(){function e(e){var t=this;this.hls=void 0,this.id3Track=null,this.media=null,this.dateRangeCuesAppended={},this.removeCues=!0,this.onEventCueEnter=function(){t.hls&&t.hls.trigger(b.EVENT_CUE_ENTER,{})},this.hls=e,this._registerListeners()}var t=e.prototype;return t.destroy=function(){this._unregisterListeners(),this.id3Track=null,this.media=null,this.dateRangeCuesAppended={},this.hls=this.onEventCueEnter=null},t._registerListeners=function(){var e=this.hls;e.on(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.on(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.on(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.FRAG_PARSING_METADATA,this.onFragParsingMetadata,this),e.on(b.BUFFER_FLUSHING,this.onBufferFlushing,this),e.on(b.LEVEL_UPDATED,this.onLevelUpdated,this),e.on(b.LEVEL_PTS_UPDATED,this.onLevelPtsUpdated,this)},t._unregisterListeners=function(){var e=this.hls;e.off(b.MEDIA_ATTACHING,this.onMediaAttaching,this),e.off(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.off(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.FRAG_PARSING_METADATA,this.onFragParsingMetadata,this),e.off(b.BUFFER_FLUSHING,this.onBufferFlushing,this),e.off(b.LEVEL_UPDATED,this.onLevelUpdated,this),e.off(b.LEVEL_PTS_UPDATED,this.onLevelPtsUpdated,this)},t.onMediaAttaching=function(e,t){var r;this.media=t.media,!1===(null==(r=t.overrides)?void 0:r.cueRemoval)&&(this.removeCues=!1)},t.onMediaAttached=function(){var e=this.hls.latestLevelDetails;e&&this.updateDateRangeCues(e)},t.onMediaDetaching=function(e,t){this.media=null,t.transferMedia||(this.id3Track&&(this.removeCues&&ws(this.id3Track,this.onEventCueEnter),this.id3Track=null),this.dateRangeCuesAppended={})},t.onManifestLoading=function(){this.dateRangeCuesAppended={}},t.createTrack=function(e){var t=this.getID3Track(e.textTracks);return t.mode="hidden",t},t.getID3Track=function(e){if(this.media){for(var t=0;tjo&&(h=jo),h-d<=0&&(h=d+.25);for(var f=0;f.01&&this.updateDateRangeCues(t.details)},t.updateDateRangeCues=function(e,t){var r=this;if(this.media&&e.hasProgramDateTime&&this.hls.config.enableDateRangeMetadataCues){var i,n=this.id3Track,a=e.dateRanges,s=Object.keys(a),o=this.dateRangeCuesAppended;if(n&&t)if(null!=(i=n.cues)&&i.length)for(var l=Object.keys(o).filter((function(e){return!s.includes(e)})),u=function(){var e=l[d],t=o[e].cues;delete o[e],Object.keys(t).forEach((function(e){try{var i=t[e];i.removeEventListener("enter",r.onEventCueEnter),n.removeCue(i)}catch(e){}}))},d=l.length;d--;)u();else o=this.dateRangeCuesAppended={};var h=e.fragments[e.fragments.length-1];if(0!==s.length&&A(null==h?void 0:h.programDateTime)){this.id3Track||(this.id3Track=this.createTrack(this.media));for(var f=Yo(),c=function(){var e=s[g],t=a[e],i=t.startTime,n=o[e],l=(null==n?void 0:n.cues)||{},u=(null==n?void 0:n.durationKnown)||!1,d=jo,h=t.duration;if(t.endDate&&null!==h)d=i+h,u=!0;else if(t.endOnNext&&!u){var c=s.reduce((function(e,r){if(r!==t.id){var i=a[r];if(i.class===t.class&&i.startDate>t.startDate&&(!e||t.startDate.01&&(T.startTime=i,T.endTime=d);else if(f){var S=t.attr[E];fr(E)&&(v=S,S=Uint8Array.from(v.replace(/^0x/,"").replace(/([\da-fA-F]{2}) ?/g,"0x$1 ").replace(/ +$/,"").split(" ")).buffer);var A=Wo(f,i,d,{key:E,data:S},ji.dateRange);A&&(A.id=e,r.id3Track.addCue(A),l[E]=A,r.hls.config.interstitialsController&&("X-ASSET-LIST"!==E&&"X-ASSET-URL"!==E||A.addEventListener("enter",r.onEventCueEnter)))}}}o[e]={cues:l,dateRange:t,durationKnown:u}},g=0;g.05&&t.forwardBufferLength>1){var u=Math.min(2,Math.max(1,s)),d=Math.round(2/(1+Math.exp(-.75*l-t.edgeStalled))*20)/20,h=Math.min(u,Math.max(1,d));t.changeMediaPlaybackRate(e,h)}else 1!==e.playbackRate&&0!==e.playbackRate&&t.changeMediaPlaybackRate(e,1)}}}}},this.hls=e,this.config=e.config,this.registerListeners()}var t=e.prototype;return t.destroy=function(){this.unregisterListeners(),this.onMediaDetaching(),this.hls=null},t.registerListeners=function(){var e=this.hls;e&&(e.on(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.on(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.LEVEL_UPDATED,this.onLevelUpdated,this),e.on(b.ERROR,this.onError,this))},t.unregisterListeners=function(){var e=this.hls;e&&(e.off(b.MEDIA_ATTACHED,this.onMediaAttached,this),e.off(b.MEDIA_DETACHING,this.onMediaDetaching,this),e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.LEVEL_UPDATED,this.onLevelUpdated,this),e.off(b.ERROR,this.onError,this))},t.onMediaAttached=function(e,t){this.media=t.media,this.media.addEventListener("timeupdate",this.onTimeupdate)},t.onMediaDetaching=function(){this.media&&(this.media.removeEventListener("timeupdate",this.onTimeupdate),this.media=null)},t.onManifestLoading=function(){this._latency=null,this.stallCount=0},t.onLevelUpdated=function(e,t){var r=t.details;r.advanced&&this.onTimeupdate(),!r.live&&this.media&&this.media.removeEventListener("timeupdate",this.onTimeupdate)},t.onError=function(e,t){var r;t.details===k.BUFFER_STALLED_ERROR&&(this.stallCount++,this.hls&&null!=(r=this.levelDetails)&&r.live&&this.hls.logger.warn("[latency-controller]: Stall detected, adjusting target latency"))},t.changeMediaPlaybackRate=function(e,t){var r,i;e.playbackRate!==t&&(null==(r=this.hls)||r.logger.debug("[latency-controller]: latency="+this.latency.toFixed(3)+", targetLatency="+(null==(i=this.targetLatency)?void 0:i.toFixed(3))+", forwardBufferLength="+this.forwardBufferLength.toFixed(3)+": adjusting playback rate from "+e.playbackRate+" to "+t),e.playbackRate=t)},t.estimateLiveEdge=function(){var e=this.levelDetails;return null===e?null:e.edge+e.age},t.computeLatency=function(){var e=this.estimateLiveEdge();return null===e?null:e-this.currentTime},i(e,[{key:"levelDetails",get:function(){var e;return(null==(e=this.hls)?void 0:e.latestLevelDetails)||null}},{key:"latency",get:function(){return this._latency||0}},{key:"maxLatency",get:function(){var e=this.config;if(void 0!==e.liveMaxLatencyDuration)return e.liveMaxLatencyDuration;var t=this.levelDetails;return t?e.liveMaxLatencyDurationCount*t.targetduration:0}},{key:"targetLatency",get:function(){var e=this.levelDetails;if(null===e||null===this.hls)return null;var t=e.holdBack,r=e.partHoldBack,i=e.targetduration,n=this.config,a=n.liveSyncDuration,s=n.liveSyncDurationCount,o=n.lowLatencyMode,l=this.hls.userConfig,u=o&&r||t;(this._targetLatencyUpdated||l.liveSyncDuration||l.liveSyncDurationCount||0===u)&&(u=void 0!==a?a:s*i);var d=i;return u+Math.min(this.stallCount*this.config.liveSyncOnStallIncrease,d)},set:function(e){this.stallCount=0,this.config.liveSyncDuration=e,this._targetLatencyUpdated=!0}},{key:"liveSyncPosition",get:function(){var e=this.estimateLiveEdge(),t=this.targetLatency;if(null===e||null===t)return null;var r=this.levelDetails;if(null===r)return null;var i=r.edge,n=e-t-this.edgeStalled,a=i-r.totalduration,s=i-(this.config.lowLatencyMode&&r.partTarget||r.targetduration);return Math.min(Math.max(a,n),s)}},{key:"drift",get:function(){var e=this.levelDetails;return null===e?1:e.drift}},{key:"edgeStalled",get:function(){var e=this.levelDetails;if(null===e)return 0;var t=3*(this.config.lowLatencyMode&&e.partTarget||e.targetduration);return Math.max(e.age-t,0)}},{key:"forwardBufferLength",get:function(){var e=this.media,t=this.levelDetails;if(!e||!t)return 0;var r=e.buffered.length;return(r?e.buffered.end(r-1):t.edge)-this.currentTime}}])}(),Qo=function(e){function t(t,r){var i;return(i=e.call(this,t,"level-controller")||this)._levels=[],i._firstLevel=-1,i._maxAutoLevel=-1,i._startLevel=void 0,i.currentLevel=null,i.currentLevelIndex=-1,i.manualLevelIndex=-1,i.steering=void 0,i.onParsedComplete=void 0,i.steering=r,i._registerListeners(),i}o(t,e);var r=t.prototype;return r._registerListeners=function(){var e=this.hls;e.on(b.MANIFEST_LOADING,this.onManifestLoading,this),e.on(b.MANIFEST_LOADED,this.onManifestLoaded,this),e.on(b.LEVEL_LOADED,this.onLevelLoaded,this),e.on(b.LEVELS_UPDATED,this.onLevelsUpdated,this),e.on(b.FRAG_BUFFERED,this.onFragBuffered,this),e.on(b.ERROR,this.onError,this)},r._unregisterListeners=function(){var e=this.hls;e.off(b.MANIFEST_LOADING,this.onManifestLoading,this),e.off(b.MANIFEST_LOADED,this.onManifestLoaded,this),e.off(b.LEVEL_LOADED,this.onLevelLoaded,this),e.off(b.LEVELS_UPDATED,this.onLevelsUpdated,this),e.off(b.FRAG_BUFFERED,this.onFragBuffered,this),e.off(b.ERROR,this.onError,this)},r.destroy=function(){this._unregisterListeners(),this.steering=null,this.resetLevels(),e.prototype.destroy.call(this)},r.stopLoad=function(){this._levels.forEach((function(e){e.loadError=0,e.fragmentError=0})),e.prototype.stopLoad.call(this)},r.resetLevels=function(){this._startLevel=void 0,this.manualLevelIndex=-1,this.currentLevelIndex=-1,this.currentLevel=null,this._levels=[],this._maxAutoLevel=-1},r.onManifestLoading=function(e,t){this.resetLevels()},r.onManifestLoaded=function(e,t){var r=this,i=this.hls.config.preferManagedMediaSource,n=[],a={},s={},o=!1,l=!1,u=!1;t.levels.forEach((function(e){var t=e.attrs,d=e.audioCodec,h=e.videoCodec;d&&(e.audioCodec=d=Be(d,i)||void 0),h&&(h=e.videoCodec=function(e){for(var t=e.split(","),r=0;r2&&"avc1"===i[0]&&(t[r]="avc1."+parseInt(i[1]).toString(16)+("000"+parseInt(i[2]).toString(16)).slice(-4))}return t.join(",")}(h));var f=e.width,c=e.height,g=e.unknownCodecs,v=g?g.length:0;if(g)for(var m=v;m--;){var p=g[m];r.isAudioSupported(p)?(e.audioCodec=d=d?d+","+p:p,v--,Pe.audio[d.substring(0,4)]=2):r.isVideoSupported(p)&&(e.videoCodec=h=h?h+","+p:p,v--,Pe.video[h.substring(0,4)]=2)}if(o||(o=!(!f||!c)),l||(l=!!h),u||(u=!!d),v||d&&!r.isAudioSupported(d)||h&&!r.isVideoSupported(h))r.log('Some or all CODECS not supported "'+t.CODECS+'"');else{var y=t.CODECS,E=t["FRAME-RATE"],T=t["HDCP-LEVEL"],S=t["PATHWAY-ID"],A=t.RESOLUTION,L=t["VIDEO-RANGE"],R=(S||".")+"-"+e.bitrate+"-"+A+"-"+E+"-"+y+"-"+L+"-"+T;if(a[R])if(a[R].uri===e.url||e.attrs["PATHWAY-ID"])a[R].addGroupId("audio",t.AUDIO),a[R].addGroupId("text",t.SUBTITLES);else{var I=s[R]+=1;e.attrs["PATHWAY-ID"]=new Array(I+1).join(".");var k=r.createLevel(e);a[R]=k,n.push(k)}else{var b=r.createLevel(e);a[R]=b,s[R]=1,n.push(b)}}})),this.filterAndSortMediaOptions(n,t,o,l,u)},r.createLevel=function(e){var t=new it(e),r=e.supplemental;if(null!=r&&r.videoCodec&&!this.isVideoSupported(r.videoCodec)){var i=new Error('SUPPLEMENTAL-CODECS not supported "'+r.videoCodec+'"');this.log(i.message),t.supportedResult=je(i,[])}return t},r.isAudioSupported=function(e){return we(e,"audio",this.hls.config.preferManagedMediaSource)},r.isVideoSupported=function(e){return we(e,"video",this.hls.config.preferManagedMediaSource)},r.filterAndSortMediaOptions=function(e,t,r,i,n){var a=this,s=[],o=[],l=e;if((r||i)&&n&&(l=l.filter((function(e){var t,r=e.videoCodec,i=e.videoRange,n=e.width,a=e.height;return(!!r||!(!n||!a))&&!!(t=i)&&$e.indexOf(t)>-1}))),0!==l.length){t.audioTracks&&zo(s=t.audioTracks.filter((function(e){return!e.audioCodec||a.isAudioSupported(e.audioCodec)}))),t.subtitles&&zo(o=t.subtitles);var u=l.slice(0);l.sort((function(e,t){if(e.attrs["HDCP-LEVEL"]!==t.attrs["HDCP-LEVEL"])return(e.attrs["HDCP-LEVEL"]||"")>(t.attrs["HDCP-LEVEL"]||"")?1:-1;if(r&&e.height!==t.height)return e.height-t.height;if(e.frameRate!==t.frameRate)return e.frameRate-t.frameRate;if(e.videoRange!==t.videoRange)return $e.indexOf(e.videoRange)-$e.indexOf(t.videoRange);if(e.videoCodec!==t.videoCodec){var i=Me(e.videoCodec),n=Me(t.videoCodec);if(i!==n)return n-i}if(e.uri===t.uri&&e.codecSet!==t.codecSet){var a=Fe(e.codecSet),s=Fe(t.codecSet);if(a!==s)return s-a}return e.averageBitrate!==t.averageBitrate?e.averageBitrate-t.averageBitrate:0}));var d=u[0];if(this.steering&&(l=this.steering.filterParsedLevels(l)).length!==u.length)for(var h=0;hv&&v===this.hls.abrEwmaDefaultEstimate&&(this.hls.bandwidthEstimate=m)}break}var p=n&&!i,y=this.hls.config,E=!(!y.audioStreamController||!y.audioTrackController),T={levels:l,audioTracks:s,subtitleTracks:o,sessionData:t.sessionData,sessionKeys:t.sessionKeys,firstLevel:this._firstLevel,stats:t.stats,audio:n,video:i,altAudio:E&&!p&&s.some((function(e){return!!e.url}))};this.hls.trigger(b.MANIFEST_PARSED,T)}else Promise.resolve().then((function(){if(a.hls){var e="no level with compatible codecs found in manifest",r=e;t.levels.length&&(r="one or more CODECS in variant not supported: "+st(t.levels.map((function(e){return e.attrs.CODECS})).filter((function(e,t,r){return r.indexOf(e)===t}))),a.warn(r),e+=" ("+r+")");var i=new Error(e);a.hls.trigger(b.ERROR,{type:I.MEDIA_ERROR,details:k.MANIFEST_INCOMPATIBLE_CODECS_ERROR,fatal:!0,url:t.url,error:i,reason:r})}}))},r.onError=function(e,t){!t.fatal&&t.context&&t.context.type===_&&t.context.level===this.level&&this.checkRetry(t)},r.onFragBuffered=function(e,t){var r=t.frag;if(void 0!==r&&r.type===w){var i=r.elementaryStreams;if(!Object.keys(i).some((function(e){return!!i[e]})))return;var n=this._levels[r.level];null!=n&&n.loadError&&(this.log("Resetting level error count of "+n.loadError+" on frag buffered"),n.loadError=0)}},r.onLevelLoaded=function(e,t){var r,i,n=t.level,a=t.details,s=t.levelInfo;if(!s)return this.warn("Invalid level index "+n),void(null!=(i=t.deliveryDirectives)&&i.skip&&(a.deltaUpdateFailed=!0));if(s===this.currentLevel||t.withoutMultiVariant){0===s.fragmentError&&(s.loadError=0);var o=s.details;o===t.details&&o.advanced&&(o=void 0),this.playlistLoaded(n,t,o)}else null!=(r=t.deliveryDirectives)&&r.skip&&(a.deltaUpdateFailed=!0)},r.loadPlaylist=function(t){e.prototype.loadPlaylist.call(this),this.shouldLoadPlaylist(this.currentLevel)&&this.scheduleLoading(this.currentLevel,t)},r.loadingPlaylist=function(t,r){e.prototype.loadingPlaylist.call(this,t,r);var i=this.getUrlWithDirectives(t.uri,r),n=this.currentLevelIndex,a=t.attrs["PATHWAY-ID"],s=t.details,o=null==s?void 0:s.age;this.log("Loading level index "+n+(void 0!==(null==r?void 0:r.msn)?" at sn "+r.msn+" part "+r.part:"")+(a?" Pathway "+a:"")+(o&&s.live?" age "+o.toFixed(1)+(s.type&&" "+s.type||""):"")+" "+i),this.hls.trigger(b.LEVEL_LOADING,{url:i,level:n,levelInfo:t,pathwayId:t.attrs["PATHWAY-ID"],id:0,deliveryDirectives:r||null})},r.removeLevel=function(e){var t,r=this;if(1!==this._levels.length){var i=this._levels.filter((function(t,i){return i!==e||(r.steering&&r.steering.removeLevel(t),t===r.currentLevel&&(r.currentLevel=null,r.currentLevelIndex=-1,t.details&&t.details.fragments.forEach((function(e){return e.level=-1}))),!1)}));fi(i),this._levels=i,this.currentLevelIndex>-1&&null!=(t=this.currentLevel)&&t.details&&(this.currentLevelIndex=this.currentLevel.details.fragments[0].level),this.manualLevelIndex>-1&&(this.manualLevelIndex=this.currentLevelIndex);var n=i.length-1;this._firstLevel=Math.min(this._firstLevel,n),this._startLevel&&(this._startLevel=Math.min(this._startLevel,n)),this.hls.trigger(b.LEVELS_UPDATED,{levels:i})}},r.onLevelsUpdated=function(e,t){var r=t.levels;this._levels=r},r.checkMaxAutoUpdated=function(){var e=this.hls,t=e.autoLevelCapping,r=e.maxAutoLevel,i=e.maxHdcpLevel;this._maxAutoLevel!==r&&(this._maxAutoLevel=r,this.hls.trigger(b.MAX_AUTO_LEVEL_UPDATED,{autoLevelCapping:t,levels:this.levels,maxAutoLevel:r,minAutoLevel:this.hls.minAutoLevel,maxHdcpLevel:i}))},i(t,[{key:"levels",get:function(){return 0===this._levels.length?null:this._levels}},{key:"loadLevelObj",get:function(){return this.currentLevel}},{key:"level",get:function(){return this.currentLevelIndex},set:function(e){var t=this._levels;if(0!==t.length){if(e<0||e>=t.length){var r=new Error("invalid level idx"),i=e<0;if(this.hls.trigger(b.ERROR,{type:I.OTHER_ERROR,details:k.LEVEL_SWITCH_ERROR,level:e,fatal:i,error:r,reason:r.message}),i)return;e=Math.min(e,t.length-1)}var n=this.currentLevelIndex,a=this.currentLevel,s=a?a.attrs["PATHWAY-ID"]:void 0,o=t[e],l=o.attrs["PATHWAY-ID"];if(this.currentLevelIndex=e,this.currentLevel=o,n!==e||!a||s!==l){this.log("Switching to level "+e+" ("+(o.height?o.height+"p ":"")+(o.videoRange?o.videoRange+" ":"")+(o.codecSet?o.codecSet+" ":"")+"@"+o.bitrate+")"+(l?" with Pathway "+l:"")+" from level "+n+(s?" with Pathway "+s:""));var u={level:e,attrs:o.attrs,details:o.details,bitrate:o.bitrate,averageBitrate:o.averageBitrate,maxBitrate:o.maxBitrate,realBitrate:o.realBitrate,width:o.width,height:o.height,codecSet:o.codecSet,audioCodec:o.audioCodec,videoCodec:o.videoCodec,audioGroups:o.audioGroups,subtitleGroups:o.subtitleGroups,loaded:o.loaded,loadError:o.loadError,fragmentError:o.fragmentError,name:o.name,id:o.id,uri:o.uri,url:o.url,urlId:0,audioGroupIds:o.audioGroupIds,textGroupIds:o.textGroupIds};this.hls.trigger(b.LEVEL_SWITCHING,u);var d=o.details;if(!d||d.live){var h=this.switchParams(o.uri,null==a?void 0:a.details,d);this.loadPlaylist(h)}}}}},{key:"manualLevel",get:function(){return this.manualLevelIndex},set:function(e){this.manualLevelIndex=e,void 0===this._startLevel&&(this._startLevel=e),-1!==e&&(this.level=e)}},{key:"firstLevel",get:function(){return this._firstLevel},set:function(e){this._firstLevel=e}},{key:"startLevel",get:function(){if(void 0===this._startLevel){var e=this.hls.config.startLevel;return void 0!==e?e:this.hls.firstAutoLevel}return this._startLevel},set:function(e){this._startLevel=e}},{key:"pathways",get:function(){return this.steering?this.steering.pathways():[]}},{key:"pathwayPriority",get:function(){return this.steering?this.steering.pathwayPriority:null},set:function(e){if(this.steering){var t=this.steering.pathways(),r=e.filter((function(e){return-1!==t.indexOf(e)}));if(e.length<1)return void this.warn("pathwayPriority "+e+" should contain at least one pathway from list: "+t);this.steering.pathwayPriority=r}}},{key:"nextLoadLevel",get:function(){return-1!==this.manualLevelIndex?this.manualLevelIndex:this.hls.nextAutoLevel},set:function(e){this.level=e,-1===this.manualLevelIndex&&(this.hls.nextAutoLevel=e)}}])}(oa);function zo(e){var t={};e.forEach((function(e){var r=e.groupId||"";e.id=t[r]=t[r]||0,t[r]++}))}function $o(){return self.SourceBuffer||self.WebKitSourceBuffer}function Jo(){if(!W())return!1;var e=$o();return!e||e.prototype&&"function"==typeof e.prototype.appendBuffer&&"function"==typeof e.prototype.remove}var Zo=function(e){function t(t,r,i){var n;return(n=e.call(this,t,r,i,"stream-controller",w)||this).audioCodecSwap=!1,n.level=-1,n._forceStartLoad=!1,n._hasEnoughToStart=!1,n.altAudio=0,n.audioOnly=!1,n.fragPlaying=null,n.fragLastKbps=0,n.couldBacktrack=!1,n.backtrackFragment=null,n.audioCodecSwitch=!1,n.videoBuffer=null,n.onMediaPlaying=function(){n.tick()},n.onMediaSeeked=function(){var e=n.media,t=e?e.currentTime:null;if(null!==t&&A(t)&&(n.log("Media seeked to "+t.toFixed(3)),n.getBufferedFrag(t))){var r=n.getFwdBufferInfoAtPos(e,t,w,0);null!==r&&0!==r.len?n.tick():n.warn("Main forward buffer length at "+t+' on "seeked" event '+(r?r.len:"empty")+")")}},n.registerListeners(),n}o(t,e);var r=t.prototype;return r.registerListeners=function(){e.prototype.registerListeners.call(this);var t=this.hls;t.on(b.MANIFEST_PARSED,this.onManifestParsed,this),t.on(b.LEVEL_LOADING,this.onLevelLoading,this),t.on(b.LEVEL_LOADED,this.onLevelLoaded,this),t.on(b.FRAG_LOAD_EMERGENCY_ABORTED,this.onFragLoadEmergencyAborted,this),t.on(b.AUDIO_TRACK_SWITCHING,this.onAudioTrackSwitching,this),t.on(b.AUDIO_TRACK_SWITCHED,this.onAudioTrackSwitched,this),t.on(b.BUFFER_CREATED,this.onBufferCreated,this),t.on(b.BUFFER_FLUSHED,this.onBufferFlushed,this),t.on(b.LEVELS_UPDATED,this.onLevelsUpdated,this),t.on(b.FRAG_BUFFERED,this.onFragBuffered,this)},r.unregisterListeners=function(){e.prototype.unregisterListeners.call(this);var t=this.hls;t.off(b.MANIFEST_PARSED,this.onManifestParsed,this),t.off(b.LEVEL_LOADED,this.onLevelLoaded,this),t.off(b.FRAG_LOAD_EMERGENCY_ABORTED,this.onFragLoadEmergencyAborted,this),t.off(b.AUDIO_TRACK_SWITCHING,this.onAudioTrackSwitching,this),t.off(b.AUDIO_TRACK_SWITCHED,this.onAudioTrackSwitched,this),t.off(b.BUFFER_CREATED,this.onBufferCreated,this),t.off(b.BUFFER_FLUSHED,this.onBufferFlushed,this),t.off(b.LEVELS_UPDATED,this.onLevelsUpdated,this),t.off(b.FRAG_BUFFERED,this.onFragBuffered,this)},r.onHandlerDestroying=function(){this.onMediaPlaying=this.onMediaSeeked=null,this.unregisterListeners(),e.prototype.onHandlerDestroying.call(this)},r.startLoad=function(e,t){if(this.levels){var r=this.lastCurrentTime,i=this.hls;if(this.stopLoad(),this.setInterval(100),this.level=-1,!this.startFragRequested){var n=i.startLevel;-1===n&&(i.config.testBandwidth&&this.levels.length>1?(n=0,this.bitrateTest=!0):n=i.firstAutoLevel),i.nextLoadLevel=n,this.level=i.loadLevel,this._hasEnoughToStart=!!t}r>0&&-1===e&&!t&&(this.log("Override startPosition with lastCurrentTime @"+r.toFixed(3)),e=r),this.state=Ei.IDLE,this.nextLoadPosition=this.lastCurrentTime=e+this.timelineOffset,this.startPosition=t?-1:e,this.tick()}else this._forceStartLoad=!0,this.state=Ei.STOPPED},r.stopLoad=function(){this._forceStartLoad=!1,e.prototype.stopLoad.call(this)},r.doTick=function(){switch(this.state){case Ei.WAITING_LEVEL:var e=this.levels,t=this.level,r=null==e?void 0:e[t],i=null==r?void 0:r.details;if(i&&(!i.live||this.levelLastLoaded===r&&!this.waitForLive(r))){if(this.waitForCdnTuneIn(i))break;this.state=Ei.IDLE;break}if(this.hls.nextLoadLevel!==this.level){this.state=Ei.IDLE;break}break;case Ei.FRAG_LOADING_WAITING_RETRY:var n,a=self.performance.now(),s=this.retryDate;if(!s||a>=s||null!=(n=this.media)&&n.seeking){var o=this.levels,l=this.level,u=null==o?void 0:o[l];this.resetStartWhenNotLoaded(u||null),this.state=Ei.IDLE}}this.state===Ei.IDLE&&this.doTickIdle(),this.onTickEnd()},r.onTickEnd=function(){var t;e.prototype.onTickEnd.call(this),null!=(t=this.media)&&t.readyState&&!1===this.media.seeking&&(this.lastCurrentTime=this.media.currentTime),this.checkFragmentChanged()},r.doTickIdle=function(){var e=this.hls,t=this.levelLastLoaded,r=this.levels,i=this.media;if(null!==t&&(i||this.primaryPrefetch||!this.startFragRequested&&e.config.startFragPrefetch)&&(!this.altAudio||!this.audioOnly)){var n=this.buffering?e.nextLoadLevel:e.loadLevel;if(null!=r&&r[n]){var a=r[n],s=this.getMainFwdBufferInfo();if(null!==s){var o=this.getLevelDetails();if(o&&this._streamEnded(s,o)){var l={};return 2===this.altAudio&&(l.type="video"),this.hls.trigger(b.BUFFER_EOS,l),void(this.state=Ei.ENDED)}if(this.buffering){e.loadLevel!==n&&-1===e.manualLevel&&this.log("Adapting to level "+n+" from level "+this.level),this.level=e.nextLoadLevel=n;var u=a.details;if(!u||this.state===Ei.WAITING_LEVEL||this.waitForLive(a))return this.level=n,this.state=Ei.WAITING_LEVEL,void(this.startFragRequested=!1);var d=s.len,h=this.getMaxBufferLength(a.maxBitrate);if(!(d>=h)){this.backtrackFragment&&this.backtrackFragment.start>s.end&&(this.backtrackFragment=null);var f=this.backtrackFragment?this.backtrackFragment.start:s.end,c=this.getNextFragment(f,u);if(this.couldBacktrack&&!this.fragPrevious&&c&&ee(c)&&this.fragmentTracker.getState(c)!==Ut){var g,v=(null!=(g=this.backtrackFragment)?g:c).sn-u.startSN,m=u.fragments[v-1];m&&c.cc===m.cc&&(c=m,this.fragmentTracker.removeFragment(m))}else this.backtrackFragment&&s.len&&(this.backtrackFragment=null);if(c&&this.isLoopLoading(c,f)){if(!c.gap){var p=this.audioOnly&&!this.altAudio?z:$,y=(p===$?this.videoBuffer:this.mediaBuffer)||this.media;y&&this.afterBufferFlushed(y,p,w)}c=this.getNextFragmentLoopLoading(c,u,s,w,h)}c&&(!c.initSegment||c.initSegment.data||this.bitrateTest||(c=c.initSegment),this.loadFragment(c,a,f))}}}}}},r.loadFragment=function(t,r,i){var n=this.fragmentTracker.getState(t);n===Mt||n===Nt?ee(t)?this.bitrateTest?(this.log("Fragment "+t.sn+" of level "+t.level+" is being downloaded to test bitrate and will not be buffered"),this._loadBitrateTestFrag(t,r)):e.prototype.loadFragment.call(this,t,r,i):this._loadInitSegment(t,r):this.clearTrackerIfNeeded(t)},r.getBufferedFrag=function(e){return this.fragmentTracker.getBufferedFrag(e,w)},r.followingBufferedFrag=function(e){return e?this.getBufferedFrag(e.end+.5):null},r.immediateLevelSwitch=function(){this.abortCurrentFrag(),this.flushMainBuffer(0,Number.POSITIVE_INFINITY)},r.nextLevelSwitch=function(){var e=this.levels,t=this.media;if(null!=t&&t.readyState){var r,i=this.getAppendedFrag(t.currentTime);i&&i.start>1&&this.flushMainBuffer(0,i.start-1);var n=this.getLevelDetails();if(null!=n&&n.live){var a=this.getMainFwdBufferInfo();if(!a||a.len<2*n.targetduration)return}if(!t.paused&&e){var s=e[this.hls.nextLoadLevel],o=this.fragLastKbps;r=o&&this.fragCurrent?this.fragCurrent.duration*s.maxBitrate/(1e3*o)+1:0}else r=0;var l=this.getBufferedFrag(t.currentTime+r);if(l){var u=this.followingBufferedFrag(l);if(u){this.abortCurrentFrag();var d=u.maxStartPTS?u.maxStartPTS:u.start,h=u.duration,f=Math.max(l.end,d+Math.min(Math.max(h-this.config.maxFragLookUpTolerance,h*(this.couldBacktrack?.5:.125)),h*(this.couldBacktrack?.75:.25)));this.flushMainBuffer(f,Number.POSITIVE_INFINITY)}}}},r.abortCurrentFrag=function(){var e=this.fragCurrent;switch(this.fragCurrent=null,this.backtrackFragment=null,e&&(e.abortRequests(),this.fragmentTracker.removeFragment(e)),this.state){case Ei.KEY_LOADING:case Ei.FRAG_LOADING:case Ei.FRAG_LOADING_WAITING_RETRY:case Ei.PARSING:case Ei.PARSED:this.state=Ei.IDLE}this.nextLoadPosition=this.getLoadPosition()},r.flushMainBuffer=function(t,r){e.prototype.flushMainBuffer.call(this,t,r,2===this.altAudio?"video":null)},r.onMediaAttached=function(t,r){e.prototype.onMediaAttached.call(this,t,r);var i=r.media;ls(i,"playing",this.onMediaPlaying),ls(i,"seeked",this.onMediaSeeked)},r.onMediaDetaching=function(t,r){var i=this.media;i&&(us(i,"playing",this.onMediaPlaying),us(i,"seeked",this.onMediaSeeked)),this.videoBuffer=null,this.fragPlaying=null,e.prototype.onMediaDetaching.call(this,t,r),r.transferMedia||(this._hasEnoughToStart=!1)},r.onManifestLoading=function(){e.prototype.onManifestLoading.call(this),this.log("Trigger BUFFER_RESET"),this.hls.trigger(b.BUFFER_RESET,void 0),this.couldBacktrack=!1,this.fragLastKbps=0,this.fragPlaying=this.backtrackFragment=null,this.altAudio=0,this.audioOnly=!1},r.onManifestParsed=function(e,t){var r,i,n=!1,a=!1;t.levels.forEach((function(e){var t=e.audioCodec;t&&(n=n||-1!==t.indexOf("mp4a.40.2"),a=a||-1!==t.indexOf("mp4a.40.5"))})),this.audioCodecSwitch=n&&a&&!("function"==typeof(null==(i=$o())||null==(r=i.prototype)?void 0:r.changeType)),this.audioCodecSwitch&&this.log("Both AAC/HE-AAC audio found in levels; declaring level codec as HE-AAC"),this.levels=t.levels,this.startFragRequested=!1},r.onLevelLoading=function(e,t){if(this.levels&&this.state===Ei.IDLE){var r=t.levelInfo;(!r.details||r.details.live&&(this.levelLastLoaded!==r||r.details.expired)||this.waitForCdnTuneIn(r.details))&&(this.state=Ei.WAITING_LEVEL)}},r.onLevelLoaded=function(e,t){var r,i=this.levels,n=this.startFragRequested,a=t.level,s=t.details,o=s.totalduration;if(i){this.log("Level "+a+" loaded ["+s.startSN+","+s.endSN+"]"+(s.lastPartSn?"[part-"+s.lastPartSn+"-"+s.lastPartIndex+"]":"")+", cc ["+s.startCC+", "+s.endCC+"] duration:"+o);var l=t.levelInfo,u=this.fragCurrent;!u||this.state!==Ei.FRAG_LOADING&&this.state!==Ei.FRAG_LOADING_WAITING_RETRY||u.level!==t.level&&u.loader&&this.abortCurrentFrag();var d=0;if(s.live||null!=(r=l.details)&&r.live){var h;if(this.checkLiveUpdate(s),s.deltaUpdateFailed)return;d=this.alignPlaylists(s,l.details,null==(h=this.levelLastLoaded)?void 0:h.details)}if(l.details=s,this.levelLastLoaded=l,n||this.setStartPosition(s,d),this.hls.trigger(b.LEVEL_UPDATED,{details:s,level:a}),this.state===Ei.WAITING_LEVEL){if(this.waitForCdnTuneIn(s))return;this.state=Ei.IDLE}n&&s.live&&this.synchronizeToLiveEdge(s),this.tick()}else this.warn("Levels were reset while loading level "+a)},r.synchronizeToLiveEdge=function(e){var t=this.config,r=this.media;if(r){var i=this.hls.liveSyncPosition,n=this.getLoadPosition(),a=e.fragmentStart,s=e.edge,o=n>=a-t.maxFragLookUpTolerance&&n<=s;if(null!==i&&r.duration>i&&(n-1&&this.fragCurrent&&(this.level=this.fragCurrent.level,-1===this.level&&this.resetWhenMissingContext(this.fragCurrent)),this.levels=t.levels},r.swapAudioCodec=function(){this.audioCodecSwap=!this.audioCodecSwap},r.seekToStartPos=function(){var e=this.media;if(e){var t=e.currentTime,r=this.startPosition;if(r>=0&&t0&&(oT.cc;if(!1!==n.independent){var R=d.startPTS,I=d.endPTS,k=d.startDTS,D=d.endDTS;if(l)l.elementaryStreams[d.type]={startPTS:R,endPTS:I,startDTS:k,endDTS:D};else if(d.firstKeyFrame&&d.independent&&1===a.id&&!L&&(this.couldBacktrack=!0),d.dropped&&d.independent){var _=this.getMainFwdBufferInfo(),P=(_?_.end:this.getLoadPosition())+this.config.maxBufferHole,C=d.firstKeyFramePTS?d.firstKeyFramePTS:R;if(!S&&P2&&(o.gap=!0);o.setElementaryStreamInfo(d.type,R,I,k,D),this.backtrackFragment&&(this.backtrackFragment=o),this.bufferFragmentData(d,o,l,a,S||L)}else{if(!S&&!L)return void this.backtrack(o);o.gap=!0}}if(v){var w=v.startPTS,O=v.endPTS,x=v.startDTS,M=v.endDTS;l&&(l.elementaryStreams[z]={startPTS:w,endPTS:O,startDTS:x,endDTS:M}),o.setElementaryStreamInfo(z,w,O,x,M),this.bufferFragmentData(v,o,l,a)}if(g&&null!=f&&null!=(t=f.samples)&&t.length){var F={id:r,frag:o,details:g,samples:f.samples};i.trigger(b.FRAG_PARSING_METADATA,F)}if(g&&h){var N={id:r,frag:o,details:g,samples:h.samples};i.trigger(b.FRAG_PARSING_USERDATA,N)}}}else this.resetWhenMissingContext(a)},r.logMuxedErr=function(e){this.warn((ee(e)?"Media":"Init")+" segment with muxed audiovideo where only video expected: "+e.url)},r._bufferInitSegment=function(e,t,r,i){var n=this;if(this.state===Ei.PARSING){this.audioOnly=!!t.audio&&!t.video,this.altAudio&&!this.audioOnly&&(delete t.audio,t.audiovideo&&this.logMuxedErr(r));var a=t.audio,s=t.video,o=t.audiovideo;if(a){var l=e.audioCodec,u=Ge(a.codec,l);"mp4a"===u&&(u="mp4a.40.5");var d=navigator.userAgent.toLowerCase();if(this.audioCodecSwitch){u&&(u=-1!==u.indexOf("mp4a.40.5")?"mp4a.40.2":"mp4a.40.5");var h=a.metadata;h&&"channelCount"in h&&1!==(h.channelCount||1)&&-1===d.indexOf("firefox")&&(u="mp4a.40.5")}u&&-1!==u.indexOf("mp4a.40.5")&&-1!==d.indexOf("android")&&"audio/mpeg"!==a.container&&(u="mp4a.40.2",this.log("Android: force audio codec to "+u)),l&&l!==u&&this.log('Swapping manifest audio codec "'+l+'" for "'+u+'"'),a.levelCodec=u,a.id=w,this.log("Init audio buffer, container:"+a.container+", codecs[selected/level/parsed]=["+(u||"")+"/"+(l||"")+"/"+a.codec+"]"),delete t.audiovideo}if(s){s.levelCodec=e.videoCodec,s.id=w;var f=s.codec;if(4===(null==f?void 0:f.length))switch(f){case"hvc1":case"hev1":s.codec="hvc1.1.6.L120.90";break;case"av01":s.codec="av01.0.04M.08";break;case"avc1":s.codec="avc1.42e01e"}this.log("Init video buffer, container:"+s.container+", codecs[level/parsed]=["+(e.videoCodec||"")+"/"+f+"]"+(s.codec!==f?" parsed-corrected="+s.codec:"")+(s.supplemental?" supplemental="+s.supplemental:"")),delete t.audiovideo}o&&(this.log("Init audiovideo buffer, container:"+o.container+", codecs[level/parsed]=["+e.codecs+"/"+o.codec+"]"),delete t.video,delete t.audio);var c=Object.keys(t);if(c.length){if(this.hls.trigger(b.BUFFER_CODECS,t),!this.hls)return;c.forEach((function(e){var a=t[e].initSegment;null!=a&&a.byteLength&&n.hls.trigger(b.BUFFER_APPENDING,{type:e,data:a,frag:r,part:null,chunkMeta:i,parent:r.type})}))}this.tickImmediate()}},r.getMainFwdBufferInfo=function(){var e=this.mediaBuffer&&2===this.altAudio?this.mediaBuffer:this.media;return this.getFwdBufferInfo(e,w)},r.backtrack=function(e){this.couldBacktrack=!0,this.backtrackFragment=e,this.resetTransmuxer(),this.flushBufferGap(e),this.fragmentTracker.removeFragment(e),this.fragPrevious=null,this.nextLoadPosition=e.start,this.state=Ei.IDLE},r.checkFragmentChanged=function(){var e=this.media,t=null;if(e&&e.readyState>1&&!1===e.seeking){var r=e.currentTime;if(ir.isBuffered(e,r)?t=this.getAppendedFrag(r):ir.isBuffered(e,r+.1)&&(t=this.getAppendedFrag(r+.1)),t){this.backtrackFragment=null;var i=this.fragPlaying,n=t.level;i&&t.sn===i.sn&&i.level===n||(this.fragPlaying=t,this.hls.trigger(b.FRAG_CHANGED,{frag:t}),i&&i.level===n||this.hls.trigger(b.LEVEL_SWITCHED,{level:n}))}}},i(t,[{key:"hasEnoughToStart",get:function(){return this._hasEnoughToStart}},{key:"maxBufferLength",get:function(){var e=this.levels,t=this.level,r=null==e?void 0:e[t];return r?this.getMaxBufferLength(r.maxBitrate):this.config.maxBufferLength}},{key:"nextLevel",get:function(){var e=this.nextBufferedFrag;return e?e.level:-1}},{key:"currentFrag",get:function(){var e;if(this.fragPlaying)return this.fragPlaying;var t=(null==(e=this.media)?void 0:e.currentTime)||this.lastCurrentTime;return A(t)?this.getAppendedFrag(t):null}},{key:"currentProgramDateTime",get:function(){var e,t=(null==(e=this.media)?void 0:e.currentTime)||this.lastCurrentTime;if(A(t)){var r=this.getLevelDetails(),i=this.currentFrag||(r?pt(null,r.fragments,t):null);if(i){var n=i.programDateTime;if(null!==n){var a=n+1e3*(t-i.start);return new Date(a)}}}return null}},{key:"currentLevel",get:function(){var e=this.currentFrag;return e?e.level:-1}},{key:"nextBufferedFrag",get:function(){var e=this.currentFrag;return e?this.followingBufferedFrag(e):null}},{key:"forceStartLoad",get:function(){return this._forceStartLoad}}])}(Ti),el=function(){function e(e){this.config=void 0,this.keyUriToKeyInfo={},this.emeController=null,this.config=e}var t=e.prototype;return t.abort=function(e){for(var t in this.keyUriToKeyInfo){var r=this.keyUriToKeyInfo[t].loader;if(r){var i;if(e&&e!==(null==(i=r.context)?void 0:i.frag.type))return;r.abort()}}},t.detach=function(){for(var e in this.keyUriToKeyInfo){var t=this.keyUriToKeyInfo[e];(t.mediaKeySessionContext||t.decryptdata.isCommonEncryption)&&delete this.keyUriToKeyInfo[e]}},t.destroy=function(){for(var e in this.detach(),this.keyUriToKeyInfo){var t=this.keyUriToKeyInfo[e].loader;t&&t.destroy()}this.keyUriToKeyInfo={}},t.createKeyLoadError=function(e,t,r,i,n){return void 0===t&&(t=k.KEY_LOAD_ERROR),new Zt({type:I.NETWORK_ERROR,details:t,fatal:!1,frag:e,response:n,error:r,networkDetails:i})},t.loadClear=function(e,t){var r=this;if(this.emeController&&this.config.emeEnabled&&!this.emeController.getSelectedKeySystemFormats().length)if(t.length){for(var i,n=e.sn,a=e.cc,s=function(){var e=t[o];if(a<=e.cc&&("initSegment"===n||"initSegment"===e.sn||n":"")+")"),this.started=!0,this.resumeBuffering();for(var r=0;r-1?this.abrController.forcedAutoLevel:e},set:function(e){this.logger.log("set startLevel:"+e),-1!==e&&(e=Math.max(e,this.minAutoLevel)),this.levelController.startLevel=e}},{key:"capLevelToPlayerSize",get:function(){return this.config.capLevelToPlayerSize},set:function(e){var t=!!e;t!==this.config.capLevelToPlayerSize&&(t?this.capLevelController.startCapping():(this.capLevelController.stopCapping(),this.autoLevelCapping=-1,this.streamController.nextLevelSwitch()),this.config.capLevelToPlayerSize=t)}},{key:"autoLevelCapping",get:function(){return this._autoLevelCapping},set:function(e){this._autoLevelCapping!==e&&(this.logger.log("set autoLevelCapping:"+e),this._autoLevelCapping=e,this.levelController.checkMaxAutoUpdated())}},{key:"bandwidthEstimate",get:function(){var e=this.abrController.bwEstimator;return e?e.getEstimate():NaN},set:function(e){this.abrController.resetEstimator(e)}},{key:"abrEwmaDefaultEstimate",get:function(){var e=this.abrController.bwEstimator;return e?e.defaultEstimate:NaN}},{key:"ttfbEstimate",get:function(){var e=this.abrController.bwEstimator;return e?e.getEstimateTTFB():NaN}},{key:"maxHdcpLevel",get:function(){return this._maxHdcpLevel},set:function(e){(function(e){return ze.indexOf(e)>-1})(e)&&this._maxHdcpLevel!==e&&(this._maxHdcpLevel=e,this.levelController.checkMaxAutoUpdated())}},{key:"autoLevelEnabled",get:function(){return-1===this.levelController.manualLevel}},{key:"manualLevel",get:function(){return this.levelController.manualLevel}},{key:"minAutoLevel",get:function(){var e=this.levels,t=this.config.minAutoBitrate;if(!e)return 0;for(var r=e.length,i=0;i=t)return i;return 0}},{key:"maxAutoLevel",get:function(){var e,t=this.levels,r=this.autoLevelCapping,i=this.maxHdcpLevel;if(e=-1===r&&null!=t&&t.length?t.length-1:r,i)for(var n=e;n--;){var a=t[n].attrs["HDCP-LEVEL"];if(a&&a<=i)return n}return e}},{key:"firstAutoLevel",get:function(){return this.abrController.firstAutoLevel}},{key:"nextAutoLevel",get:function(){return this.abrController.nextAutoLevel},set:function(e){this.abrController.nextAutoLevel=e}},{key:"playingDate",get:function(){return this.streamController.currentProgramDateTime}},{key:"mainForwardBufferInfo",get:function(){return this.streamController.getMainFwdBufferInfo()}},{key:"maxBufferLength",get:function(){return this.streamController.maxBufferLength}},{key:"allAudioTracks",get:function(){var e=this.audioTrackController;return e?e.allAudioTracks:[]}},{key:"audioTracks",get:function(){var e=this.audioTrackController;return e?e.audioTracks:[]}},{key:"audioTrack",get:function(){var e=this.audioTrackController;return e?e.audioTrack:-1},set:function(e){var t=this.audioTrackController;t&&(t.audioTrack=e)}},{key:"allSubtitleTracks",get:function(){var e=this.subtitleTrackController;return e?e.allSubtitleTracks:[]}},{key:"subtitleTracks",get:function(){var e=this.subtitleTrackController;return e?e.subtitleTracks:[]}},{key:"subtitleTrack",get:function(){var e=this.subtitleTrackController;return e?e.subtitleTrack:-1},set:function(e){var t=this.subtitleTrackController;t&&(t.subtitleTrack=e)}},{key:"media",get:function(){return this._media}},{key:"subtitleDisplay",get:function(){var e=this.subtitleTrackController;return!!e&&e.subtitleDisplay},set:function(e){var t=this.subtitleTrackController;t&&(t.subtitleDisplay=e)}},{key:"lowLatencyMode",get:function(){return this.config.lowLatencyMode},set:function(e){this.config.lowLatencyMode=e}},{key:"liveSyncPosition",get:function(){return this.latencyController.liveSyncPosition}},{key:"latency",get:function(){return this.latencyController.latency}},{key:"maxLatency",get:function(){return this.latencyController.maxLatency}},{key:"targetLatency",get:function(){return this.latencyController.targetLatency},set:function(e){this.latencyController.targetLatency=e}},{key:"drift",get:function(){return this.latencyController.drift}},{key:"forceStartLoad",get:function(){return this.streamController.forceStartLoad}},{key:"pathways",get:function(){return this.levelController.pathways}},{key:"pathwayPriority",get:function(){return this.levelController.pathwayPriority},set:function(e){this.levelController.pathwayPriority=e}},{key:"bufferedToEnd",get:function(){var e;return!(null==(e=this.bufferController)||!e.bufferedToEnd)}},{key:"interstitialsManager",get:function(){var e;return(null==(e=this.interstitialsController)?void 0:e.interstitialsManager)||null}}],[{key:"version",get:function(){return ra}},{key:"Events",get:function(){return b}},{key:"MetadataSchema",get:function(){return ji}},{key:"ErrorTypes",get:function(){return I}},{key:"ErrorDetails",get:function(){return k}},{key:"DefaultConfig",get:function(){return e.defaultConfig?e.defaultConfig:Uo},set:function(t){e.defaultConfig=t}}])}();return nl.defaultConfig=void 0,nl},"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(r="undefined"!=typeof globalThis?globalThis:r||self).Hls=i()}(!1);
+//# sourceMappingURL=hls.min.js.map
diff --git a/dragonpilot/dashy/web/dist/pages/player.html b/dragonpilot/dashy/web/dist/pages/player.html
new file mode 100644
index 000000000..3fa81afa0
--- /dev/null
+++ b/dragonpilot/dashy/web/dist/pages/player.html
@@ -0,0 +1 @@
+HLS Player
\ No newline at end of file
diff --git a/dragonpilot/selfdrive/controls/lib/acm.py b/dragonpilot/selfdrive/controls/lib/acm.py
new file mode 100644
index 000000000..d2121e586
--- /dev/null
+++ b/dragonpilot/selfdrive/controls/lib/acm.py
@@ -0,0 +1,85 @@
+"""
+Copyright (c) 2025, Rick Lan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, and/or sublicense, 
+for non-commercial purposes only, subject to the following conditions:
+
+- The above copyright notice and this permission notice shall be included in 
+  all copies or substantial portions of the Software.
+- Commercial use (e.g. use in a product, service, or activity intended to 
+  generate revenue) is prohibited without explicit written permission from 
+  the copyright holder.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+
+import numpy as np
+
+SLOPE = -0.04
+RATIO = 0.9
+
+TTC = 3.5
+TTC_BP = [TTC, 2.5]
+MIN_BRAKE_ALLOW_VALS = [0., -0.5]
+
+class ACM:
+  def __init__(self):
+    self.enabled = False
+    self.downhill_only = False
+    self._is_downhill = False
+    self._is_speed_over_cruise = False
+    self._has_lead = False
+    self._active_prev = False
+
+    self.active = False
+    self.just_disabled = False
+    self.allowed_brake_val = 0.
+
+  def update_states(self, cs, rs, user_ctrl_lon, v_ego, v_cruise):
+    self.lead_ttc = float('inf')  # Default if no lead
+
+    if not self.enabled:
+      self.active = False
+      return
+
+    if len(cs.orientationNED) != 3:
+      self.active = False
+      return
+
+    pitch_rad = cs.orientationNED[1]
+    self._is_downhill = np.sin(pitch_rad) < SLOPE
+    self._is_speed_over_cruise = v_ego > (v_cruise * RATIO)
+
+    lead = rs.leadOne
+    if lead and lead.status:
+      self.lead_ttc = lead.dRel / v_ego if v_ego > 0 else float('inf')
+      self._has_lead = self.lead_ttc < TTC
+    else:
+      self._has_lead = False
+
+    self.active = not user_ctrl_lon and not self._has_lead and self._is_speed_over_cruise and (self._is_downhill if self.downhill_only else True)
+
+    self.just_disabled = self._active_prev and not self.active
+    self._active_prev = self.active
+
+  def update_a_desired_trajectory(self, a_desired_trajectory):
+    if not self.active:
+      return a_desired_trajectory
+
+    # Suppress all braking to allow smooth coasting
+    for i in range(len(a_desired_trajectory)):
+      if a_desired_trajectory[i] < 0 and a_desired_trajectory[i] > self.allowed_brake_val:
+        a_desired_trajectory[i] = 0.0
+    return a_desired_trajectory
+
+  def update_output_a_target(self, output_a_target):
+    if not self.active:
+      return output_a_target
+
+    # Suppress braking
+    if output_a_target < 0 and output_a_target > self.allowed_brake_val:
+      output_a_target = 0.0
+    return output_a_target
diff --git a/dragonpilot/selfdrive/controls/lib/aem.py b/dragonpilot/selfdrive/controls/lib/aem.py
new file mode 100644
index 000000000..5a8c3b295
--- /dev/null
+++ b/dragonpilot/selfdrive/controls/lib/aem.py
@@ -0,0 +1,389 @@
+"""
+Copyright (c) 2025, Rick Lan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, and/or sublicense,
+for non-commercial purposes only, subject to the following conditions:
+
+- The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+- Commercial use (e.g. use in a product, service, or activity intended to
+  generate revenue) is prohibited without explicit written permission from
+  the copyright holder.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+
+from openpilot.common.filter_simple import FirstOrderFilter
+from openpilot.common.realtime import DT_MDL
+import numpy as np
+from cereal import log
+
+class AEM:
+    # --- Configuration Constants ---
+    # Speed thresholds (m/s)
+    SPEED_THRESHOLD_HIGHWAY = 22.23  # m/s (approx. 80 kph)
+    SPEED_THRESHOLD_CITY = 15.27     # m/s (approx. 55 kph)
+    SPEED_THRESHOLD_LOW = 5.56       # m/s (approx. 20 kph)
+    SPEED_THRESHOLD_CREEP = 2.23     # m/s (approx. 8 kph)
+
+    # Lead related thresholds
+    LEAD_TTC_CRITICAL = 1.75        # seconds, time to collision
+    LEAD_TTC_CAUTION = 3.0
+    LEAD_DIST_VERY_CLOSE = 10.0    # meters
+    LEAD_DIST_FAR_HIGHWAY = 85.0   # meters, for considering lead far enough on highway
+    LEAD_DIST_DEFAULT_NO_LEAD = 150.0 # Default distance for EMA when no lead
+
+    LEAD_ACCEL_HARD_BRAKE = -3.0   # m/s^2
+    LEAD_ACCEL_MILD_BRAKE = -2.0   # m/s^2
+    LEAD_ACCEL_PULLING_AWAY = 0.5  # m/s^2
+
+    # Steering thresholds
+    STEERING_ANGLE_ABS_HIGH_CURVATURE = 45.0  # degrees (EMA value)
+
+    # Hysteresis & Timers
+    HYSTERESIS_FRAMES_TO_SWITCH = 10  # Approx 0.5s at 20Hz
+    LEAD_LOST_FRAMES_TO_FALLBACK_BASE = 40 # Approx 2s at 20Hz
+
+    # EMA filter time constants (seconds) - THESE ARE DESIGN PARAMETERS
+    EMA_TC_V_EGO = 1.0
+    EMA_TC_LEAD_DREL = 0.5
+    EMA_TC_LEAD_V_ABS = 0.5 # Filters absolute lead speed
+    EMA_TC_LEAD_ALEAD = 0.5
+    EMA_TC_STEERING_ANGLE_ABS = 0.8
+    EMA_TC_V_MODEL_ERROR = 1.0
+
+    # Model & Planner Related Thresholds
+    MODEL_VEL_ERROR_THRESHOLD = 2.0 # m/s (EMA value)
+    MIN_VISION_LEAD_PROB_ACTION = 0.5 # Min modelProb for acting on vision-only leads
+
+    # Other
+    REL_SPEED_SIGNIFICANT_DIFFERENCE = 2.5 # m/s
+
+    def __init__(self, debug=False):
+        self.enabled = False
+        self._current_mode = 'acc' # Default to ACC
+        self._target_mode_suggestion = None
+        self._mode_switch_counter = 0
+        self.debug = debug
+        self._lead_id_prev = -1
+        self._lead_absence_frames = 0
+        self.personality = log.LongitudinalPersonality.standard
+
+        # --- Calculate alpha values from time constants (tau) ---
+        def get_alpha(tau, dt):
+            """Calculates EMA alpha from time constant and time step."""
+            # Ensure tau > 0 to avoid division by zero if dt=0 somehow
+            # Also handle potential case where dt is zero
+            return dt / (tau + dt) if tau > 1e-5 and dt > 1e-5 else 1.0 # Default to alpha=1 (no filtering) if tau or dt is invalid/zero
+
+        alpha_v_ego = get_alpha(AEM.EMA_TC_V_EGO, DT_MDL)
+        alpha_lead_drel = get_alpha(AEM.EMA_TC_LEAD_DREL, DT_MDL)
+        alpha_lead_v_abs = get_alpha(AEM.EMA_TC_LEAD_V_ABS, DT_MDL)
+        alpha_lead_alead = get_alpha(AEM.EMA_TC_LEAD_ALEAD, DT_MDL)
+        alpha_steering_angle_abs = get_alpha(AEM.EMA_TC_STEERING_ANGLE_ABS, DT_MDL)
+        alpha_v_model_error = get_alpha(AEM.EMA_TC_V_MODEL_ERROR, DT_MDL)
+
+        # --- Initialize EMA Filters using alpha ---
+        # Ensure FirstOrderFilter takes 'alpha' as keyword arg
+        try:
+            self._v_ego_ema = FirstOrderFilter(0.0, alpha=alpha_v_ego, dt=DT_MDL)
+            self._lead_drel_ema = FirstOrderFilter(AEM.LEAD_DIST_DEFAULT_NO_LEAD, alpha=alpha_lead_drel, dt=DT_MDL)
+            self._lead_v_ema = FirstOrderFilter(0.0, alpha=alpha_lead_v_abs, dt=DT_MDL) # Filters absolute V_lead
+            self._lead_alead_ema = FirstOrderFilter(0.0, alpha=alpha_lead_alead, dt=DT_MDL)
+            self._steering_angle_abs_ema = FirstOrderFilter(0.0, alpha=alpha_steering_angle_abs, dt=DT_MDL)
+            # self._v_model_error_ema = FirstOrderFilter(0.0, alpha=alpha_v_model_error, dt=DT_MDL)
+        except TypeError:
+            # Fallback if the specific FirstOrderFilter expects positional args differently
+            print("Warning: FirstOrderFilter init failed with keyword 'alpha', attempting positional.")
+            self._v_ego_ema = FirstOrderFilter(0.0, alpha_v_ego, DT_MDL)
+            self._lead_drel_ema = FirstOrderFilter(AEM.LEAD_DIST_DEFAULT_NO_LEAD, alpha_lead_drel, DT_MDL)
+            self._lead_v_ema = FirstOrderFilter(0.0, alpha_lead_v_abs, DT_MDL)
+            self._lead_alead_ema = FirstOrderFilter(0.0, alpha_lead_alead, DT_MDL)
+            self._steering_angle_abs_ema = FirstOrderFilter(0.0, alpha_steering_angle_abs, DT_MDL)
+            # self._v_model_error_ema = FirstOrderFilter(0.0, alpha_v_model_error, DT_MDL)
+
+
+        self._log(f"AEM Initialized. Alphas: v_ego={alpha_v_ego:.3f}, dRel={alpha_lead_drel:.3f}, vLead={alpha_lead_v_abs:.3f}, aLead={alpha_lead_alead:.3f}, steer={alpha_steering_angle_abs:.3f}, v_err={alpha_v_model_error:.3f}")
+
+    def _log(self, msg: str):
+        """Logs debug messages if debug is enabled."""
+        if self.debug:
+            # Consider using cloudlog for persistent logs during testing
+            # from openpilot.common.swaglog import cloudlog
+            # cloudlog.debug(f"[AEM]: {msg}")
+            print(f"[AEM]: {msg}")
+
+    def _calculate_ttc(self, dist: float, ego_speed: float, lead_speed: float) -> float:
+        """Calculates Time To Collision (TTC), returns infinity if collision is not imminent."""
+        relative_speed = ego_speed - lead_speed
+        if dist > 0.1 and relative_speed > 0.3: # Thresholds to avoid noise and division issues
+            # Avoid division by zero or very small numbers
+            return max(0.0, dist / relative_speed) # Return non-negative TTC
+        return float('inf') # Return infinity if no collision course or relative speed is too low
+
+    def _reset_lead_emas(self, d_lead_raw, v_lead_raw, a_lead_raw):
+        """Helper to reset/initialize lead EMAs' state."""
+        # This assumes direct state access/setting via '.x' is the correct method
+        # for the FirstOrderFilter implementation being used.
+        try:
+            self._lead_drel_ema.x = float(d_lead_raw)
+            self._lead_v_ema.x = float(v_lead_raw)
+            self._lead_alead_ema.x = float(a_lead_raw)
+            # Ensure filter knows it's 'initialized' if it uses that flag internally
+            self._lead_drel_ema.initialized = True
+            self._lead_v_ema.initialized = True
+            self._lead_alead_ema.initialized = True
+            self._log(f"Reset lead EMAs with raw values: d={d_lead_raw:.2f}, v={v_lead_raw:.2f}, a={a_lead_raw:.2f}")
+        except AttributeError:
+            self._log("Warning: Could not directly set '.x' on FirstOrderFilter. Reset may not be immediate.")
+            # If direct access fails, update might be the only way, causing a slight delay in reset
+            self._lead_drel_ema.update(d_lead_raw)
+            self._lead_v_ema.update(v_lead_raw)
+            self._lead_alead_ema.update(a_lead_raw)
+
+    def set_personality(self, v_ego, personality):
+        self.personality = personality
+        if self.enabled:
+            self.personality = log.LongitudinalPersonality.aggressive if v_ego > 16.67 else self.personality
+        return self.personality
+
+    # Note: Removed 'model_predicted_max_curvature_upcoming_raw' from signature
+    def get_mode(self, v_ego_raw: float, lead_one_data_raw, steering_angle_deg_raw: float, standstill_raw: bool,
+                 long_personality: int, allow_throttle_planner: bool,
+                 model_path_plan_raw: dict, a_target_from_prev_cycle: float, model_predicts_stop_prev: bool,
+                 fcw_active_prev: bool) -> str:
+        """
+        Determines the appropriate MPC mode ('acc' or 'blended') based on current conditions.
+        ACC is primary, Blended is assist.
+        """
+        if not self.enabled:
+            # Should not be called if not enabled, but return primary mode as safeguard
+            return 'acc'
+
+        # 0. Initialize suggested mode with AEM's current internal state
+        suggested_mode = self._current_mode
+
+        # 1. Update common EMA filters
+        self._v_ego_ema.update(v_ego_raw)
+        self._steering_angle_abs_ema.update(abs(steering_angle_deg_raw))
+        # Use absolute value of model error for thresholding
+        # self._v_model_error_ema.update(abs(v_model_error_raw))
+
+        # 2. Process Lead Data & Update Lead EMAs
+        lead_status = lead_one_data_raw.status
+        current_lead_id = lead_one_data_raw.radarTrackId if lead_status else -1
+        d_lead_raw = lead_one_data_raw.dRel if lead_status else AEM.LEAD_DIST_DEFAULT_NO_LEAD
+        v_lead_raw = lead_one_data_raw.vLead if lead_status else self._v_ego_ema.x # Default to filtered ego if no lead
+        a_lead_raw = lead_one_data_raw.aLeadK if lead_status else 0.0
+        model_prob_lead = lead_one_data_raw.modelProb if lead_status else 0.0
+
+        if lead_status:
+            # Reset EMA if lead ID changes significantly (from a valid previous ID)
+            if current_lead_id != self._lead_id_prev and self._lead_id_prev != -1:
+                self._log(f"Lead ID changed: {self._lead_id_prev} -> {current_lead_id}.")
+                self._reset_lead_emas(d_lead_raw, v_lead_raw, a_lead_raw)
+            # Reset EMA if acquiring lead from no-lead state
+            elif self._lead_id_prev == -1 and current_lead_id != -1:
+                 self._log(f"Lead acquired: ID {current_lead_id}.")
+                 self._reset_lead_emas(d_lead_raw, v_lead_raw, a_lead_raw)
+
+            # Update filters with current raw data
+            self._lead_drel_ema.update(d_lead_raw)
+            self._lead_v_ema.update(v_lead_raw)
+            self._lead_alead_ema.update(a_lead_raw)
+            self._lead_absence_frames = 0
+        else: # No lead currently
+            self._lead_absence_frames += 1
+            # If lead was just lost, reset EMAs to default values
+            if self._lead_id_prev != -1:
+                 self._log(f"Lead lost (Prev ID: {self._lead_id_prev}). Resetting lead EMAs to defaults.")
+                 # Reset using the helper function ensures consistency
+                 self._reset_lead_emas(AEM.LEAD_DIST_DEFAULT_NO_LEAD, self._v_ego_ema.x, 0.0)
+            else: # Still no lead, continue updating towards defaults
+                 self._lead_drel_ema.update(AEM.LEAD_DIST_DEFAULT_NO_LEAD)
+                 self._lead_v_ema.update(self._v_ego_ema.x) # Update towards filtered ego speed
+                 self._lead_alead_ema.update(0.0) # Update towards zero accel
+
+        # Update previous lead ID for next cycle comparison *after* using it
+        self._lead_id_prev = current_lead_id
+
+        # 3. Get Filtered Values for decision making
+        v_ego = self._v_ego_ema.x
+        d_lead = self._lead_drel_ema.x
+        v_lead = self._lead_v_ema.x # Filtered absolute lead speed
+        a_lead = self._lead_alead_ema.x
+        steering_angle_abs = self._steering_angle_abs_ema.x
+        # v_model_error = self._v_model_error_ema.x
+
+        ttc = self._calculate_ttc(d_lead, v_ego, v_lead)
+        is_lead_one_vision_only = lead_status and current_lead_id == -1
+
+        # 4. Infer Current Model Intentions from raw plan
+        raw_model_stop_intention_current_cycle = False
+        if model_path_plan_raw and 'v' in model_path_plan_raw:
+            model_v_traj = model_path_plan_raw['v']
+            if len(model_v_traj) >= 5:
+                avg_final_model_v = np.mean(model_v_traj[-5:])
+                final_model_v = model_v_traj[-1]
+                # Consider stop if avg end speed is near creep and final point is very low
+                raw_model_stop_intention_current_cycle = avg_final_model_v < AEM.SPEED_THRESHOLD_CREEP and \
+                                                         final_model_v < AEM.SPEED_THRESHOLD_CREEP * 0.7
+            elif len(model_v_traj) > 0: # Fallback for shorter trajectories
+                raw_model_stop_intention_current_cycle = np.isclose(model_v_traj[-1], 0.0, atol=0.3)
+
+
+        # --- 5. Mode Selection Logic ---
+        min_prob_for_action = AEM.MIN_VISION_LEAD_PROB_ACTION if is_lead_one_vision_only else 0.0
+
+        # A. Evaluate conditions to switch TO BLENDED (from ACC)
+        if self._current_mode == 'acc':
+            needs_blended_assist = False
+            reason = "None" # Default reason
+
+            # Scenario 1: Emergency/Dangerous Lead Situation
+            if lead_status and ttc < AEM.LEAD_TTC_CRITICAL and v_ego > AEM.SPEED_THRESHOLD_LOW and model_prob_lead >= min_prob_for_action:
+                needs_blended_assist, reason = True, f"Critical TTC ({ttc:.2f}s)"
+            elif lead_status and a_lead < AEM.LEAD_ACCEL_HARD_BRAKE and d_lead < (v_ego * 2.5) and model_prob_lead >= min_prob_for_action:
+                needs_blended_assist, reason = True, f"Hard lead brake ({a_lead:.2f}), d={d_lead:.1f}"
+            elif fcw_active_prev:
+                needs_blended_assist, reason = True, "FCW previously active"
+
+            # Scenario 2: Sudden Lead Cut-in/Appearance
+            # Check only if not already triggered by emergency
+            if not needs_blended_assist and lead_status and current_lead_id != self._lead_id_prev and self._lead_id_prev != -1 and \
+               ttc < AEM.LEAD_TTC_CAUTION and d_lead < (AEM.LEAD_DIST_VERY_CLOSE * 2.5) and model_prob_lead >= min_prob_for_action:
+                needs_blended_assist, reason = True, f"Sudden cut-in (TTC={ttc:.2f}, d={d_lead:.1f})"
+
+            # Scenario 3: Low-Speed/Urban/Congestion (Lead)
+            if not needs_blended_assist and lead_status and v_ego < AEM.SPEED_THRESHOLD_LOW and \
+               d_lead < (AEM.LEAD_DIST_VERY_CLOSE * 1.8) and model_prob_lead >= min_prob_for_action:
+                needs_blended_assist, reason = True, f"Low speed ({v_ego:.1f}) close lead ({d_lead:.1f})"
+
+            # Scenario 4: Model Predicts Stop
+            if not needs_blended_assist and \
+               (raw_model_stop_intention_current_cycle or model_predicts_stop_prev) and \
+               v_ego > AEM.SPEED_THRESHOLD_CREEP:
+                needs_blended_assist, reason = True, f"Model predicts stop (curr={raw_model_stop_intention_current_cycle}, prev={model_predicts_stop_prev})"
+
+            # Scenario 5: High Curvature/Urban Turns (Curvature input removed)
+            if not needs_blended_assist and \
+               steering_angle_abs > AEM.STEERING_ANGLE_ABS_HIGH_CURVATURE and \
+               v_ego < AEM.SPEED_THRESHOLD_CITY:
+                needs_blended_assist, reason = True, f"High steering angle ({steering_angle_abs:.1f})"
+
+            # Scenario 6: Planner Already Braking (Prev Cycle)
+            if not needs_blended_assist and \
+               a_target_from_prev_cycle < AEM.LEAD_ACCEL_MILD_BRAKE and \
+               not standstill_raw and v_ego > AEM.SPEED_THRESHOLD_CREEP:
+                needs_blended_assist, reason = True, f"Planner prev brake ({a_target_from_prev_cycle:.2f})"
+
+            # Scenario 7: MPC Favored E2E (Prev Cycle) & still complex
+            # if not needs_blended_assist and mpc_source_prev == 'e2e':
+            #     is_complex = (v_ego < AEM.SPEED_THRESHOLD_CITY or \
+            #                  (lead_status and ttc < AEM.LEAD_TTC_CAUTION and model_prob_lead >= min_prob_for_action) or \
+            #                  (steering_angle_abs > AEM.STEERING_ANGLE_ABS_HIGH_CURVATURE * 0.6)) # Removed curvature check
+            #     if is_complex:
+            #         needs_blended_assist, reason = True, "Prev E2E source & ongoing complexity"
+
+            # Scenario 8: High Gas Disengage Prob. (Model)
+            if not needs_blended_assist and not allow_throttle_planner and \
+               (not lead_status or (lead_status and v_ego < (v_lead + AEM.REL_SPEED_SIGNIFICANT_DIFFERENCE * 0.5))):
+                 needs_blended_assist, reason = True, "Model advises against throttle"
+
+            if needs_blended_assist:
+                suggested_mode = 'blended'
+                self._log(f"ACC->BLENDED Trigger: {reason}")
+
+
+        # B. Evaluate conditions to switch TO ACC (from Blended)
+        elif self._current_mode == 'blended':
+            # Assume staying in blended unless conditions strongly favor returning to ACC
+            suggested_mode = 'blended'
+
+            # Check if any critical Blended-triggering condition is still fundamentally active
+            blended_condition_still_active = False
+            active_blended_reason = "None"
+            if lead_status and ttc < AEM.LEAD_TTC_CRITICAL and v_ego > AEM.SPEED_THRESHOLD_LOW and model_prob_lead >= min_prob_for_action: blended_condition_still_active, active_blended_reason = True, "Critical TTC"
+            elif lead_status and a_lead < AEM.LEAD_ACCEL_HARD_BRAKE and model_prob_lead >= min_prob_for_action: blended_condition_still_active, active_blended_reason = True, "Hard Lead Brake"
+            elif fcw_active_prev: blended_condition_still_active, active_blended_reason = True, "Prev FCW"
+            elif (raw_model_stop_intention_current_cycle or model_predicts_stop_prev) and v_ego > AEM.SPEED_THRESHOLD_CREEP: blended_condition_still_active, active_blended_reason = True, "Model Predicts Stop"
+            elif steering_angle_abs > AEM.STEERING_ANGLE_ABS_HIGH_CURVATURE and v_ego < AEM.SPEED_THRESHOLD_CITY: blended_condition_still_active, active_blended_reason = True, "High Steering Angle"
+            elif a_target_from_prev_cycle < AEM.LEAD_ACCEL_MILD_BRAKE and not standstill_raw and v_ego > AEM.SPEED_THRESHOLD_CREEP: blended_condition_still_active, active_blended_reason = True, "Prev Planner Brake"
+            elif not allow_throttle_planner and (not lead_status or (lead_status and v_ego < (v_lead + AEM.REL_SPEED_SIGNIFICANT_DIFFERENCE * 0.5))): blended_condition_still_active, active_blended_reason = True, "Gas Disengage Prob"
+            elif lead_status and v_ego < AEM.SPEED_THRESHOLD_LOW and \
+                 d_lead < (AEM.LEAD_DIST_VERY_CLOSE * 1.8) and \
+                 model_prob_lead >= min_prob_for_action: # Using filtered values (v_ego, d_lead) as in other checks
+                blended_condition_still_active, active_blended_reason = True, f"Persisting Low speed ({v_ego:.1f}) close lead ({d_lead:.1f})"
+            # Low speed congestion is implicitly handled by other checks usually involving TTC or stops
+
+            if not blended_condition_still_active:
+                safe_to_return_to_acc = False
+                reason = ""
+                # Scenario 10: Highway Cruising - Excellent Conditions
+                if v_ego > AEM.SPEED_THRESHOLD_HIGHWAY and \
+                   steering_angle_abs < (AEM.STEERING_ANGLE_ABS_HIGH_CURVATURE * 0.3) and \
+                   (not lead_status or d_lead > (AEM.LEAD_DIST_FAR_HIGHWAY * 0.8) or ttc > (AEM.LEAD_TTC_CAUTION * 1.5)):
+                    safe_to_return_to_acc, reason = True, "Highway cruise, clear path"
+                # Scenario 11: Stable Following - Safe Distance Achieved
+                elif lead_status and v_ego > AEM.SPEED_THRESHOLD_LOW and \
+                     ttc > AEM.LEAD_TTC_CAUTION and \
+                     d_lead > (AEM.LEAD_DIST_VERY_CLOSE * 2.0) and \
+                     abs(a_lead) < (AEM.LEAD_ACCEL_PULLING_AWAY * 0.8) and \
+                     abs(v_ego - v_lead) < (AEM.REL_SPEED_SIGNIFICANT_DIFFERENCE * 0.75) and \
+                     steering_angle_abs < (AEM.STEERING_ANGLE_ABS_HIGH_CURVATURE * 0.5):
+                    safe_to_return_to_acc, reason = True, f"Stable following (TTC={ttc:.2f}, d={d_lead:.1f})"
+                # Scenario 12: Prolonged Lead Absence
+                elif not lead_status:
+                    personality_factor = 1.3 if long_personality == 0 else (0.7 if long_personality == 2 else 1.0)
+                    fallback_frames = AEM.LEAD_LOST_FRAMES_TO_FALLBACK_BASE * personality_factor
+                    if self._lead_absence_frames > fallback_frames and v_ego > AEM.SPEED_THRESHOLD_LOW:
+                       safe_to_return_to_acc, reason = True, f"Prolonged lead absence ({self._lead_absence_frames} frames)"
+                # Scenario 13: Persistent High Model Velocity Error
+                # elif v_model_error > AEM.MODEL_VEL_ERROR_THRESHOLD:
+                #     safe_to_return_to_acc, reason = True, f"High model vel error ({v_model_error:.2f})"
+                # Default fallback if no active blended condition and no specific ACC condition met
+                elif not safe_to_return_to_acc:
+                    safe_to_return_to_acc, reason = True, "No active Blended condition found"
+
+                if safe_to_return_to_acc:
+                    suggested_mode = 'acc'
+                    self._log(f"BLENDED->ACC Trigger: {reason}")
+            else:
+                 self._log(f"Staying BLENDED due to active condition: {active_blended_reason}")
+
+
+        # --- 6. Apply Hysteresis ---
+        if suggested_mode != self._current_mode:
+            # If target mode changes, reset counter
+            if self._target_mode_suggestion != suggested_mode:
+                self._target_mode_suggestion = suggested_mode
+                self._mode_switch_counter = 1
+                self._log(f"Target mode suggestion: {self._target_mode_suggestion}. Counter: {self._mode_switch_counter}")
+            # If target mode remains the same, increment counter
+            else:
+                self._mode_switch_counter += 1
+                # Log counter increment for debugging flapping
+                # self._log(f"Target mode {self._target_mode_suggestion} persists. Counter: {self._mode_switch_counter}")
+
+
+            # Check if threshold is met to execute switch
+            if self._mode_switch_counter >= AEM.HYSTERESIS_FRAMES_TO_SWITCH:
+                self._log(f"\n-----------------------\nExecuting switch from {self._current_mode} to {self._target_mode_suggestion}\n-----------------------")
+                self._current_mode = self._target_mode_suggestion
+                # Reset hysteresis state after switch
+                self._mode_switch_counter = 0
+                self._target_mode_suggestion = None
+            # else: remain in _current_mode until counter threshold met
+        else: # Suggested mode is the same as current mode
+            # If there was a pending switch suggestion, cancel it
+            if self._target_mode_suggestion is not None:
+                 self._log(f"Mode suggestion {suggested_mode} matches current mode {self._current_mode}, cancelling pending switch to {self._target_mode_suggestion}")
+            # Reset hysteresis state
+            self._target_mode_suggestion = None
+            self._mode_switch_counter = 0
+
+        # Return the potentially updated current mode
+        return self._current_mode
diff --git a/dragonpilot/selfdrive/controls/lib/road_edge_detector.py b/dragonpilot/selfdrive/controls/lib/road_edge_detector.py
new file mode 100644
index 000000000..7dda57848
--- /dev/null
+++ b/dragonpilot/selfdrive/controls/lib/road_edge_detector.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+"""
+Copyright (c) 2019, rav4kumar, Rick Lan, dragonpilot community, and a number of other of contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, and/or sublicense, 
+for non-commercial purposes only, subject to the following conditions:
+
+- The above copyright notice and this permission notice shall be included in 
+  all copies or substantial portions of the Software.
+- Commercial use (e.g. use in a product, service, or activity intended to 
+  generate revenue) is prohibited without explicit written permission from 
+  the copyright holder.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+
+import numpy as np
+
+NEARSIDE_PROB = 0.2
+EDGE_PROB = 0.35
+
+class RoadEdgeDetector:
+  def __init__(self, enabled = False):
+    self._is_enabled = enabled
+    self.left_edge_detected = False
+    self.right_edge_detected = False
+
+  def update(self, road_edge_stds, lane_line_probs):
+    if not self._is_enabled:
+      return
+
+    left_road_edge_prob = np.clip(1.0 - road_edge_stds[0], 0.0, 1.0)
+    left_lane_nearside_prob = lane_line_probs[0]
+
+    right_road_edge_prob = np.clip(1.0 - road_edge_stds[1], 0.0, 1.0)
+    right_lane_nearside_prob = lane_line_probs[3]
+
+    self.left_edge_detected = bool(
+      left_road_edge_prob > EDGE_PROB and
+      left_lane_nearside_prob < NEARSIDE_PROB and
+      right_lane_nearside_prob >= left_lane_nearside_prob
+    )
+
+    self.right_edge_detected = bool(
+      right_road_edge_prob > EDGE_PROB and
+      right_lane_nearside_prob < NEARSIDE_PROB and
+      left_lane_nearside_prob >= right_lane_nearside_prob
+    )
+
+  def set_enabled(self, enabled):
+    self._is_enabled = enabled
+
+  def is_enabled(self):
+    return self._is_enabled
diff --git a/dragonpilot/selfdrive/ui/beepd.py b/dragonpilot/selfdrive/ui/beepd.py
new file mode 100644
index 000000000..100f2ad70
--- /dev/null
+++ b/dragonpilot/selfdrive/ui/beepd.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python3
+"""
+Copyright (c) 2025, Rick Lan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, and/or sublicense, 
+for non-commercial purposes only, subject to the following conditions:
+
+- The above copyright notice and this permission notice shall be included in 
+  all copies or substantial portions of the Software.
+- Commercial use (e.g. use in a product, service, or activity intended to 
+  generate revenue) is prohibited without explicit written permission from 
+  the copyright holder.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+
+import subprocess
+import time
+from cereal import car, messaging
+from openpilot.common.realtime import Ratekeeper
+import threading
+
+AudibleAlert = car.CarControl.HUDControl.AudibleAlert
+
+class Beepd:
+  def __init__(self):
+    self.current_alert = AudibleAlert.none
+    self.enable_gpio()
+
+  def enable_gpio(self):
+    try:
+      subprocess.run("echo 42 | sudo tee /sys/class/gpio/export",
+                     shell=True,
+                     stderr=subprocess.DEVNULL,
+                     stdout=subprocess.DEVNULL,
+                     encoding='utf8')
+    except Exception:
+      pass
+    subprocess.run("echo \"out\" | sudo tee /sys/class/gpio/gpio42/direction",
+                   shell=True,
+                   stderr=subprocess.DEVNULL,
+                   stdout=subprocess.DEVNULL,
+                   encoding='utf8')
+
+  def _beep(self, on):
+    val = "1" if on else "0"
+    subprocess.run(f"echo \"{val}\" | sudo tee /sys/class/gpio/gpio42/value",
+                   shell=True,
+                   stderr=subprocess.DEVNULL,
+                   stdout=subprocess.DEVNULL,
+                   encoding='utf8')
+
+  def engage(self):
+    self._beep(True)
+    time.sleep(0.05)
+    self._beep(False)
+
+  def disengage(self):
+    for _ in range(2):
+      self._beep(True)
+      time.sleep(0.01)
+      self._beep(False)
+      time.sleep(0.01)
+
+  def warning(self):
+    for _ in range(3):
+      self._beep(True)
+      time.sleep(0.01)
+      self._beep(False)
+      time.sleep(0.01)
+
+  def warning_immediate(self):
+    for _ in range(5):
+      self._beep(True)
+      time.sleep(0.01)
+      self._beep(False)
+      time.sleep(0.01)
+
+  def dispatch_beep(self, func):
+    threading.Thread(target=func, daemon=True).start()
+
+  def update_alert(self, new_alert):
+    current_alert_played_once = self.current_alert == AudibleAlert.none
+    if self.current_alert != new_alert and (new_alert != AudibleAlert.none or current_alert_played_once):
+      self.current_alert = new_alert
+      # if new_alert == AudibleAlert.engage:
+      #   self.dispatch_beep(self.engage)
+      # if new_alert == AudibleAlert.disengage:
+      #   self.dispatch_beep(self.disengage)
+      if new_alert == AudibleAlert.warningImmediate:
+        self.dispatch_beep(self.warning_immediate)
+
+  def get_audible_alert(self, sm):
+    if sm.updated['selfdriveState']:
+      new_alert = sm['selfdriveState'].alertSound.raw
+      self.update_alert(new_alert)
+
+  def test_beepd_thread(self):
+    frame = 0
+    rk = Ratekeeper(20)
+    pm = messaging.PubMaster(['selfdriveState'])
+    while True:
+      cs = messaging.new_message('selfdriveState')
+      if frame == 20:
+        cs.selfdriveState.alertSound = AudibleAlert.engage
+      if frame == 40:
+        cs.selfdriveState.alertSound = AudibleAlert.disengage
+      if frame == 60:
+        cs.selfdriveState.alertSound = AudibleAlert.prompt
+      if frame == 80:
+        cs.selfdriveState.alertSound = AudibleAlert.disengage
+      if frame == 85:
+        cs.selfdriveState.alertSound = AudibleAlert.prompt
+
+      pm.send("selfdriveState", cs)
+      frame += 1
+      rk.keep_time()
+
+  def beepd_thread(self, test=False):
+    if test:
+      threading.Thread(target=self.test_beepd_thread, daemon=True).start()
+
+    sm = messaging.SubMaster(['selfdriveState'])
+    rk = Ratekeeper(20)
+
+    while True:
+      sm.update(0)
+      self.get_audible_alert(sm)
+      rk.keep_time()
+
+def main():
+  s = Beepd()
+  s.beepd_thread(test=False)
+
+if __name__ == "__main__":
+  main()
diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh
index d4689aae5..c3ad76f70 100755
--- a/launch_chffrplus.sh
+++ b/launch_chffrplus.sh
@@ -27,6 +27,25 @@ function agnos_init {
   fi
 }
 
+no_amp() {
+  output=$(i2cget -y 0 0x10 0x00 2>/dev/null)
+  if [ -z "$output" ]; then
+    return 0
+  else
+    return 1
+  fi
+}
+
+function check_device_mode {
+  if no_amp; then
+    echo "O3 Lite Mode"
+    export LITE=1
+    export DISABLE_DRIVER=1
+  else
+    echo "C3 Mode"
+  fi
+}
+
 function launch {
   # Remove orphaned git lock if it exists on boot
   [ -f "$DIR/.git/index.lock" ] && rm -f $DIR/.git/index.lock
@@ -71,6 +90,7 @@ function launch {
 
   # hardware specific init
   if [ -f /AGNOS ]; then
+    check_device_mode
     agnos_init
   fi
 
diff --git a/launch_env.sh b/launch_env.sh
index 4c011c6ac..bf8e46510 100755
--- a/launch_env.sh
+++ b/launch_env.sh
@@ -5,6 +5,9 @@ export MKL_NUM_THREADS=1
 export NUMEXPR_NUM_THREADS=1
 export OPENBLAS_NUM_THREADS=1
 export VECLIB_MAXIMUM_THREADS=1
+if [ -s /data/params/d/dp_device_model_selected ]; then
+  export FINGERPRINT="$(cat /data/params/d/dp_device_model_selected)"
+fi
 
 if [ -z "$AGNOS_VERSION" ]; then
   export AGNOS_VERSION="12.8"
diff --git a/opendbc_repo/opendbc/car/nissan/carcontroller.py b/opendbc_repo/opendbc/car/nissan/carcontroller.py
index 16f990a82..d488cd973 100644
--- a/opendbc_repo/opendbc/car/nissan/carcontroller.py
+++ b/opendbc_repo/opendbc/car/nissan/carcontroller.py
@@ -61,7 +61,7 @@ class CarController(CarControllerBase):
     # Below are the HUD messages. We copy the stock message and modify
     if self.CP.carFingerprint != CAR.NISSAN_ALTIMA:
       if self.frame % 2 == 0:
-        can_sends.append(nissancan.create_lkas_hud_msg(self.packer, CS.lkas_hud_msg, CC.enabled, hud_control.leftLaneVisible, hud_control.rightLaneVisible,
+        can_sends.append(nissancan.create_lkas_hud_msg(self.packer, CS.lkas_hud_msg, CC.latActive, hud_control.leftLaneVisible, hud_control.rightLaneVisible,
                                                        hud_control.leftLaneDepart, hud_control.rightLaneDepart))
 
       if self.frame % 50 == 0:
diff --git a/opendbc_repo/opendbc/car/radar_interface.py b/opendbc_repo/opendbc/car/radar_interface.py
new file mode 100644
index 000000000..86095db05
--- /dev/null
+++ b/opendbc_repo/opendbc/car/radar_interface.py
@@ -0,0 +1,173 @@
+"""
+Copyright (c) 2025, Rick Lan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, and/or sublicense,
+for non-commercial purposes only, subject to the following conditions:
+
+- The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+- Commercial use (e.g. use in a product, service, or activity intended to
+  generate revenue) is prohibited without explicit written permission from
+  the copyright holder.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+
+from opendbc.car.interfaces import RadarInterfaceBase
+from opendbc.can.parser import CANParser
+from opendbc.car.structs import RadarData
+from typing import List, Tuple
+
+# car head to radar
+DREL_OFFSET = -1.35
+
+# max object amount will process
+MAX_OBJECTS = 100
+
+# lat distance, typically max lane width is 3.7m
+MAX_LAT_DIST = 3.6
+
+# objects to ignore thats really close to the vehicle (after DREL_OFFSET applied)
+MIN_DIST = 2.5
+
+# when a object has really large negative v_rel means its stationary / standstill
+# so with the values below (v_rel = -10, lat_dist = 2.), we are trying to ignore:
+# when the ego vehicle is driving above 36 km/h (22.37 mph), we will ignore objects that lateral distance is above 2m on left or right.
+STATIONARY_OBJ_VREL = -10.
+STATIONARY_OBJ_LAT_DIST = 2.
+
+# when we detect an object that's really closed to the ego vehicle
+# we ignore the objects that's away from left or right
+CLOSED_OBJ_DREL = 10
+CLOSED_OBJ_YREL = 2.
+
+# ignore objects that has small radar cross sections (-64 ~ 63.5)
+MIN_RCS = -5.
+
+# ignore oncoming objects
+IGNORE_OBJ_STATE = 2
+
+# ignore objects that we haven't seen for 5 secs
+NOT_SEEN_INIT = 33*5
+
+def _create_radar_parser():
+  messages = [("Status", float('nan')), ("ObjectData", float('nan'))]
+  messages += [(f"ObjectData_{i}", float('nan')) for i in range(MAX_OBJECTS)]
+  return CANParser('u_radar', messages, 1)
+
+class RadarInterface(RadarInterfaceBase):
+  def __init__(self, CP):
+    super().__init__(CP)
+
+    self.updated_messages = set()
+
+    self.rcp = _create_radar_parser()
+
+    self._pts_cache = dict()
+    self._pts_not_seen = {key: 0 for key in range(255)}
+    self._should_clear_cache = False
+
+  def _create_parsable_object_can_strings(self, can_strings: List[Tuple]) -> Tuple[List[Tuple], int]:
+    """Optimized object string parsing with minimal allocations."""
+    if not can_strings or not isinstance(can_strings[0], tuple) or len(can_strings[0]) < 2:
+      return [], 0
+
+    # Pre-allocate list with known maximum size
+    new_list = []
+    new_list_append = new_list.append  # Local reference for faster access
+
+    records = can_strings[0][1]
+    id_num = 1
+
+    for record in records:
+      if id_num > MAX_OBJECTS:
+        break
+
+      if record[0] == 0x60B:
+        new_list_append((id_num + 383, record[1], record[2]))
+        id_num += 1
+
+    return [(can_strings[0][0], new_list)], len(new_list)
+
+  # called by card.py, 100hz
+  def update(self, can_strings):
+    vls = self.rcp.update(can_strings)
+    self.updated_messages.update(vls)
+
+    if 1546 in self.updated_messages:
+      self._should_clear_cache = True
+
+    if 1547 in self.updated_messages:
+      parsable_can_string, size = self._create_parsable_object_can_strings(can_strings)
+      self.rcp.update(parsable_can_string)
+
+      # clean cache when we see a 0x60a then a 0x60b
+      if self._should_clear_cache:
+        self._pts_cache.clear()
+        self._should_clear_cache = False
+
+      for i in range(size):
+        cpt = self.rcp.vl[f'ObjectData_{i}']
+        track_id = int(cpt['ID'])
+
+        d_rel = float(cpt['DistLong']) + DREL_OFFSET
+        y_rel = -float(cpt['DistLat'])
+        obj_class = int(cpt['Class'])
+
+        # ignore oncoming objects
+        if int(cpt['DynProp']) == IGNORE_OBJ_STATE:
+          continue
+
+        # only apply filters below when object is a point (0) not a vehicle (1)
+        if obj_class == 0:
+          # ignore really closed objects
+          if d_rel < MIN_DIST:
+            continue
+
+          # ignore objects with really small radar cross sections
+          if float(cpt['RCS']) < MIN_RCS:
+            continue
+
+          # ignore far left/right objects
+          if abs(y_rel) > MAX_LAT_DIST:
+            continue
+
+          # ignore closed left/right objects when closed
+          if d_rel < CLOSED_OBJ_DREL and abs(y_rel) > CLOSED_OBJ_YREL:
+            continue
+
+        # add to cache
+        if track_id not in self._pts_cache:
+          self._pts_cache[track_id] = RadarData.RadarPoint()
+          self._pts_cache[track_id].trackId = track_id
+
+        self._pts_not_seen[track_id] = NOT_SEEN_INIT
+        self._pts_cache[track_id].yvRel = float(cpt['VRelLat'])
+        self._pts_cache[track_id].dRel = d_rel
+        self._pts_cache[track_id].yRel = y_rel
+        self._pts_cache[track_id].vRel = float(cpt['VRelLong'])
+        self._pts_cache[track_id].aRel = float('nan')
+        self._pts_cache[track_id].measured = True
+
+    self.updated_messages.clear()
+
+    if self.frame % 2 == 0:
+      keys_to_remove = [key for key in self.pts if key not in self._pts_cache]
+      for key in keys_to_remove:
+        self._pts_not_seen[key] -= 1
+        if self._pts_not_seen[key] <= 0:
+          del self.pts[key]
+
+      self.pts.update(self._pts_cache)
+
+      ret = RadarData()
+      if not self.rcp.can_valid:
+        ret.errors.canError = True
+
+      ret.points = list(self.pts.values())
+      return ret
+
+    return None
diff --git a/opendbc_repo/opendbc/car/structs.py b/opendbc_repo/opendbc/car/structs.py
index 0959d5c75..7389cec8b 100644
--- a/opendbc_repo/opendbc/car/structs.py
+++ b/opendbc_repo/opendbc/car/structs.py
@@ -20,4 +20,6 @@ CarControlT = capnp.lib.capnp._StructModule
 CarParamsT = capnp.lib.capnp._StructModule
 
 class DPFlags:
+  LateralALKA = 1
+  ExtRadar = 2
   pass
diff --git a/opendbc_repo/opendbc/car/toyota/carcontroller.py b/opendbc_repo/opendbc/car/toyota/carcontroller.py
index 6f0738585..79a65f5e8 100644
--- a/opendbc_repo/opendbc/car/toyota/carcontroller.py
+++ b/opendbc_repo/opendbc/car/toyota/carcontroller.py
@@ -266,7 +266,7 @@ class CarController(CarControllerBase):
       if self.frame % 20 == 0 or send_ui:
         can_sends.append(toyotacan.create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, hud_control.leftLaneVisible,
                                                      hud_control.rightLaneVisible, hud_control.leftLaneDepart,
-                                                     hud_control.rightLaneDepart, CC.enabled, CS.lkas_hud))
+                                                     hud_control.rightLaneDepart, lat_active, CS.lkas_hud))
 
       if (self.frame % 100 == 0 or send_ui) and (self.CP.enableDsu or self.CP.flags & ToyotaFlags.DISABLE_RADAR.value):
         can_sends.append(toyotacan.create_fcw_command(self.packer, fcw_alert))
diff --git a/opendbc_repo/opendbc/car/toyota/values.py b/opendbc_repo/opendbc/car/toyota/values.py
index fa6f96e73..20115a920 100644
--- a/opendbc_repo/opendbc/car/toyota/values.py
+++ b/opendbc_repo/opendbc/car/toyota/values.py
@@ -77,6 +77,8 @@ class ToyotaFlags(IntFlag):
   RAISED_ACCEL_LIMIT = 1024
   SECOC = 2048
 
+  ALKA = 2 ** 12
+
 
 def dbc_dict(pt, radar):
   return {Bus.pt: pt, Bus.radar: radar}
diff --git a/opendbc_repo/opendbc/dbc/u_radar.dbc b/opendbc_repo/opendbc/dbc/u_radar.dbc
new file mode 100644
index 000000000..101c35c55
--- /dev/null
+++ b/opendbc_repo/opendbc/dbc/u_radar.dbc
@@ -0,0 +1,1486 @@
+
+
+VERSION ""
+
+
+NS_ :
+	NS_DESC_
+	CM_
+	BA_DEF_
+	BA_
+	VAL_
+	CAT_DEF_
+	CAT_
+	FILTER
+	BA_DEF_DEF_
+	EV_DATA_
+	ENVVAR_DATA_
+	SGTYPE_
+	SGTYPE_VAL_
+	BA_DEF_SGTYPE_
+	BA_SGTYPE_
+	SIG_TYPE_REF_
+	VAL_TABLE_
+	SIG_GROUP_
+	SIG_VALTYPE_
+	SIGTYPE_VALTYPE_
+	BO_TX_BU_
+	BA_DEF_REL_
+	BA_REL_
+	BA_DEF_DEF_REL_
+	BU_SG_REL_
+	BU_EV_REL_
+	BU_BO_REL_
+	SG_MUL_VAL_
+
+BS_:
+
+BU_: RADAR
+
+BO_ 513 RadarState: 8 XXX
+ SG_ NVMReadStatus : 6|1@0+ (1,0) [0|1] "" XXX
+ SG_ NVMWriteStatus : 7|1@0+ (1,0) [0|1] "" XXX
+ SG_ MaxDistanceCfg : 15|10@0+ (2,0) [0|2046] "m" XXX
+ SG_ RadarPowerCfg : 25|3@0+ (1,0) [0|7] "" XXX
+ SG_ SensorID : 34|3@0+ (1,0) [0|7] "" XXX
+ SG_ SortIndex : 38|3@0+ (1,0) [0|7] "" XXX
+ SG_ CtrlRelayCfg : 41|1@0+ (1,0) [0|1] "" XXX
+ SG_ OutputTypeCfg : 43|2@0+ (1,0) [0|3] "" XXX
+ SG_ QualityInfoCfg : 44|1@0+ (1,0) [0|1] "" XXX
+ SG_ ExtInfoCfg : 45|1@0+ (1,0) [0|1] "" XXX
+ SG_ CANBaudRate : 55|3@0+ (1,0) [0|7] "" XXX
+ SG_ InterfaceType : 57|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCSThreshold : 58|3@1+ (1,0) [0|7] "" XXX
+ SG_ CalibrationEnabled : 63|2@0+ (1,0) [0|3] "" XXX
+
+VAL_ 513 NVMReadStatus 0 "Failed" 1 "Successful";
+VAL_ 513 NVMWriteStatus 0 "Failed" 1 "Successful";
+VAL_ 513 RadarPowerCfg 0 "Standard" 1 "-3dB Gain" 2 "-6dB Gain" 3 "-9dB Gain";
+VAL_ 513 SortIndex 0 "No Sorting" 1 "Sort By Range" 2 "Sort By RCS";
+VAL_ 513 CtrlRelayCfg 0 "Off" 1 "On";
+VAL_ 513 OutputTypeCfg 0 "None" 1 "Objects" 2 "Clusters";
+VAL_ 513 QualityInfoCfg 0 "Off" 1 "On";
+VAL_ 513 ExtInfoCfg 0 "Off" 1 "On";
+VAL_ 513 CANBaudRate 0 "500K" 1 "250K" 2 "1M";
+VAL_ 513 RCSThreshold 0 "Standard" 1 "High Sensitivity";
+VAL_ 513 CalibrationEnabled 1 "Enabled" 2 "Initial Recovery";
+
+BO_ 1546 Status: 8 RADAR
+ SG_ NoOfObjects : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ MeasCount : 15|16@0+ (1,0) [0|65535] "" XXX
+ SG_ InterfaceVersion : 31|4@0+ (1,0) [0|15] "" XXX
+
+BO_ 1547 ObjectData: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 1547 "Object detection and tracking information";
+VAL_ 1547 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 1547 Class 0 "point" 1 "vehicle";
+
+BO_ 383 ObjectData_0: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 383 "Object detection and tracking information";
+VAL_ 383 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 383 Class 0 "point" 1 "vehicle";
+        
+BO_ 384 ObjectData_1: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 384 "Object detection and tracking information";
+VAL_ 384 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 384 Class 0 "point" 1 "vehicle";
+        
+BO_ 385 ObjectData_2: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 385 "Object detection and tracking information";
+VAL_ 385 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 385 Class 0 "point" 1 "vehicle";
+        
+BO_ 386 ObjectData_3: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 386 "Object detection and tracking information";
+VAL_ 386 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 386 Class 0 "point" 1 "vehicle";
+        
+BO_ 387 ObjectData_4: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 387 "Object detection and tracking information";
+VAL_ 387 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 387 Class 0 "point" 1 "vehicle";
+        
+BO_ 388 ObjectData_5: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 388 "Object detection and tracking information";
+VAL_ 388 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 388 Class 0 "point" 1 "vehicle";
+        
+BO_ 389 ObjectData_6: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 389 "Object detection and tracking information";
+VAL_ 389 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 389 Class 0 "point" 1 "vehicle";
+        
+BO_ 390 ObjectData_7: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 390 "Object detection and tracking information";
+VAL_ 390 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 390 Class 0 "point" 1 "vehicle";
+        
+BO_ 391 ObjectData_8: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 391 "Object detection and tracking information";
+VAL_ 391 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 391 Class 0 "point" 1 "vehicle";
+        
+BO_ 392 ObjectData_9: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 392 "Object detection and tracking information";
+VAL_ 392 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 392 Class 0 "point" 1 "vehicle";
+        
+BO_ 393 ObjectData_10: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 393 "Object detection and tracking information";
+VAL_ 393 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 393 Class 0 "point" 1 "vehicle";
+        
+BO_ 394 ObjectData_11: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 394 "Object detection and tracking information";
+VAL_ 394 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 394 Class 0 "point" 1 "vehicle";
+        
+BO_ 395 ObjectData_12: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 395 "Object detection and tracking information";
+VAL_ 395 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 395 Class 0 "point" 1 "vehicle";
+        
+BO_ 396 ObjectData_13: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 396 "Object detection and tracking information";
+VAL_ 396 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 396 Class 0 "point" 1 "vehicle";
+        
+BO_ 397 ObjectData_14: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 397 "Object detection and tracking information";
+VAL_ 397 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 397 Class 0 "point" 1 "vehicle";
+        
+BO_ 398 ObjectData_15: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 398 "Object detection and tracking information";
+VAL_ 398 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 398 Class 0 "point" 1 "vehicle";
+        
+BO_ 399 ObjectData_16: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 399 "Object detection and tracking information";
+VAL_ 399 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 399 Class 0 "point" 1 "vehicle";
+        
+BO_ 400 ObjectData_17: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 400 "Object detection and tracking information";
+VAL_ 400 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 400 Class 0 "point" 1 "vehicle";
+        
+BO_ 401 ObjectData_18: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 401 "Object detection and tracking information";
+VAL_ 401 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 401 Class 0 "point" 1 "vehicle";
+        
+BO_ 402 ObjectData_19: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 402 "Object detection and tracking information";
+VAL_ 402 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 402 Class 0 "point" 1 "vehicle";
+        
+BO_ 403 ObjectData_20: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 403 "Object detection and tracking information";
+VAL_ 403 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 403 Class 0 "point" 1 "vehicle";
+        
+BO_ 404 ObjectData_21: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 404 "Object detection and tracking information";
+VAL_ 404 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 404 Class 0 "point" 1 "vehicle";
+        
+BO_ 405 ObjectData_22: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 405 "Object detection and tracking information";
+VAL_ 405 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 405 Class 0 "point" 1 "vehicle";
+        
+BO_ 406 ObjectData_23: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 406 "Object detection and tracking information";
+VAL_ 406 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 406 Class 0 "point" 1 "vehicle";
+        
+BO_ 407 ObjectData_24: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 407 "Object detection and tracking information";
+VAL_ 407 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 407 Class 0 "point" 1 "vehicle";
+        
+BO_ 408 ObjectData_25: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 408 "Object detection and tracking information";
+VAL_ 408 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 408 Class 0 "point" 1 "vehicle";
+        
+BO_ 409 ObjectData_26: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 409 "Object detection and tracking information";
+VAL_ 409 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 409 Class 0 "point" 1 "vehicle";
+        
+BO_ 410 ObjectData_27: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 410 "Object detection and tracking information";
+VAL_ 410 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 410 Class 0 "point" 1 "vehicle";
+        
+BO_ 411 ObjectData_28: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 411 "Object detection and tracking information";
+VAL_ 411 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 411 Class 0 "point" 1 "vehicle";
+        
+BO_ 412 ObjectData_29: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 412 "Object detection and tracking information";
+VAL_ 412 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 412 Class 0 "point" 1 "vehicle";
+        
+BO_ 413 ObjectData_30: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 413 "Object detection and tracking information";
+VAL_ 413 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 413 Class 0 "point" 1 "vehicle";
+        
+BO_ 414 ObjectData_31: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 414 "Object detection and tracking information";
+VAL_ 414 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 414 Class 0 "point" 1 "vehicle";
+        
+BO_ 415 ObjectData_32: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 415 "Object detection and tracking information";
+VAL_ 415 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 415 Class 0 "point" 1 "vehicle";
+        
+BO_ 416 ObjectData_33: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 416 "Object detection and tracking information";
+VAL_ 416 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 416 Class 0 "point" 1 "vehicle";
+        
+BO_ 417 ObjectData_34: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 417 "Object detection and tracking information";
+VAL_ 417 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 417 Class 0 "point" 1 "vehicle";
+        
+BO_ 418 ObjectData_35: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 418 "Object detection and tracking information";
+VAL_ 418 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 418 Class 0 "point" 1 "vehicle";
+        
+BO_ 419 ObjectData_36: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 419 "Object detection and tracking information";
+VAL_ 419 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 419 Class 0 "point" 1 "vehicle";
+        
+BO_ 420 ObjectData_37: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 420 "Object detection and tracking information";
+VAL_ 420 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 420 Class 0 "point" 1 "vehicle";
+        
+BO_ 421 ObjectData_38: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 421 "Object detection and tracking information";
+VAL_ 421 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 421 Class 0 "point" 1 "vehicle";
+        
+BO_ 422 ObjectData_39: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 422 "Object detection and tracking information";
+VAL_ 422 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 422 Class 0 "point" 1 "vehicle";
+        
+BO_ 423 ObjectData_40: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 423 "Object detection and tracking information";
+VAL_ 423 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 423 Class 0 "point" 1 "vehicle";
+        
+BO_ 424 ObjectData_41: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 424 "Object detection and tracking information";
+VAL_ 424 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 424 Class 0 "point" 1 "vehicle";
+        
+BO_ 425 ObjectData_42: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 425 "Object detection and tracking information";
+VAL_ 425 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 425 Class 0 "point" 1 "vehicle";
+        
+BO_ 426 ObjectData_43: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 426 "Object detection and tracking information";
+VAL_ 426 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 426 Class 0 "point" 1 "vehicle";
+        
+BO_ 427 ObjectData_44: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 427 "Object detection and tracking information";
+VAL_ 427 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 427 Class 0 "point" 1 "vehicle";
+        
+BO_ 428 ObjectData_45: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 428 "Object detection and tracking information";
+VAL_ 428 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 428 Class 0 "point" 1 "vehicle";
+        
+BO_ 429 ObjectData_46: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 429 "Object detection and tracking information";
+VAL_ 429 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 429 Class 0 "point" 1 "vehicle";
+        
+BO_ 430 ObjectData_47: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 430 "Object detection and tracking information";
+VAL_ 430 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 430 Class 0 "point" 1 "vehicle";
+        
+BO_ 431 ObjectData_48: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 431 "Object detection and tracking information";
+VAL_ 431 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 431 Class 0 "point" 1 "vehicle";
+        
+BO_ 432 ObjectData_49: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 432 "Object detection and tracking information";
+VAL_ 432 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 432 Class 0 "point" 1 "vehicle";
+        
+BO_ 433 ObjectData_50: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 433 "Object detection and tracking information";
+VAL_ 433 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 433 Class 0 "point" 1 "vehicle";
+        
+BO_ 434 ObjectData_51: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 434 "Object detection and tracking information";
+VAL_ 434 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 434 Class 0 "point" 1 "vehicle";
+        
+BO_ 435 ObjectData_52: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 435 "Object detection and tracking information";
+VAL_ 435 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 435 Class 0 "point" 1 "vehicle";
+        
+BO_ 436 ObjectData_53: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 436 "Object detection and tracking information";
+VAL_ 436 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 436 Class 0 "point" 1 "vehicle";
+        
+BO_ 437 ObjectData_54: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 437 "Object detection and tracking information";
+VAL_ 437 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 437 Class 0 "point" 1 "vehicle";
+        
+BO_ 438 ObjectData_55: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 438 "Object detection and tracking information";
+VAL_ 438 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 438 Class 0 "point" 1 "vehicle";
+        
+BO_ 439 ObjectData_56: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 439 "Object detection and tracking information";
+VAL_ 439 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 439 Class 0 "point" 1 "vehicle";
+        
+BO_ 440 ObjectData_57: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 440 "Object detection and tracking information";
+VAL_ 440 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 440 Class 0 "point" 1 "vehicle";
+        
+BO_ 441 ObjectData_58: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 441 "Object detection and tracking information";
+VAL_ 441 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 441 Class 0 "point" 1 "vehicle";
+        
+BO_ 442 ObjectData_59: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 442 "Object detection and tracking information";
+VAL_ 442 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 442 Class 0 "point" 1 "vehicle";
+        
+BO_ 443 ObjectData_60: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 443 "Object detection and tracking information";
+VAL_ 443 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 443 Class 0 "point" 1 "vehicle";
+        
+BO_ 444 ObjectData_61: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 444 "Object detection and tracking information";
+VAL_ 444 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 444 Class 0 "point" 1 "vehicle";
+        
+BO_ 445 ObjectData_62: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 445 "Object detection and tracking information";
+VAL_ 445 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 445 Class 0 "point" 1 "vehicle";
+        
+BO_ 446 ObjectData_63: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 446 "Object detection and tracking information";
+VAL_ 446 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 446 Class 0 "point" 1 "vehicle";
+        
+BO_ 447 ObjectData_64: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 447 "Object detection and tracking information";
+VAL_ 447 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 447 Class 0 "point" 1 "vehicle";
+        
+BO_ 448 ObjectData_65: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 448 "Object detection and tracking information";
+VAL_ 448 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 448 Class 0 "point" 1 "vehicle";
+        
+BO_ 449 ObjectData_66: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 449 "Object detection and tracking information";
+VAL_ 449 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 449 Class 0 "point" 1 "vehicle";
+        
+BO_ 450 ObjectData_67: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 450 "Object detection and tracking information";
+VAL_ 450 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 450 Class 0 "point" 1 "vehicle";
+        
+BO_ 451 ObjectData_68: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 451 "Object detection and tracking information";
+VAL_ 451 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 451 Class 0 "point" 1 "vehicle";
+        
+BO_ 452 ObjectData_69: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 452 "Object detection and tracking information";
+VAL_ 452 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 452 Class 0 "point" 1 "vehicle";
+        
+BO_ 453 ObjectData_70: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 453 "Object detection and tracking information";
+VAL_ 453 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 453 Class 0 "point" 1 "vehicle";
+        
+BO_ 454 ObjectData_71: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 454 "Object detection and tracking information";
+VAL_ 454 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 454 Class 0 "point" 1 "vehicle";
+        
+BO_ 455 ObjectData_72: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 455 "Object detection and tracking information";
+VAL_ 455 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 455 Class 0 "point" 1 "vehicle";
+        
+BO_ 456 ObjectData_73: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 456 "Object detection and tracking information";
+VAL_ 456 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 456 Class 0 "point" 1 "vehicle";
+        
+BO_ 457 ObjectData_74: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 457 "Object detection and tracking information";
+VAL_ 457 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 457 Class 0 "point" 1 "vehicle";
+        
+BO_ 458 ObjectData_75: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 458 "Object detection and tracking information";
+VAL_ 458 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 458 Class 0 "point" 1 "vehicle";
+        
+BO_ 459 ObjectData_76: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 459 "Object detection and tracking information";
+VAL_ 459 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 459 Class 0 "point" 1 "vehicle";
+        
+BO_ 460 ObjectData_77: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 460 "Object detection and tracking information";
+VAL_ 460 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 460 Class 0 "point" 1 "vehicle";
+        
+BO_ 461 ObjectData_78: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 461 "Object detection and tracking information";
+VAL_ 461 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 461 Class 0 "point" 1 "vehicle";
+        
+BO_ 462 ObjectData_79: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 462 "Object detection and tracking information";
+VAL_ 462 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 462 Class 0 "point" 1 "vehicle";
+        
+BO_ 463 ObjectData_80: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 463 "Object detection and tracking information";
+VAL_ 463 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 463 Class 0 "point" 1 "vehicle";
+        
+BO_ 464 ObjectData_81: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 464 "Object detection and tracking information";
+VAL_ 464 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 464 Class 0 "point" 1 "vehicle";
+        
+BO_ 465 ObjectData_82: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 465 "Object detection and tracking information";
+VAL_ 465 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 465 Class 0 "point" 1 "vehicle";
+        
+BO_ 466 ObjectData_83: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 466 "Object detection and tracking information";
+VAL_ 466 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 466 Class 0 "point" 1 "vehicle";
+        
+BO_ 467 ObjectData_84: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 467 "Object detection and tracking information";
+VAL_ 467 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 467 Class 0 "point" 1 "vehicle";
+        
+BO_ 468 ObjectData_85: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 468 "Object detection and tracking information";
+VAL_ 468 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 468 Class 0 "point" 1 "vehicle";
+        
+BO_ 469 ObjectData_86: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 469 "Object detection and tracking information";
+VAL_ 469 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 469 Class 0 "point" 1 "vehicle";
+        
+BO_ 470 ObjectData_87: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 470 "Object detection and tracking information";
+VAL_ 470 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 470 Class 0 "point" 1 "vehicle";
+        
+BO_ 471 ObjectData_88: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 471 "Object detection and tracking information";
+VAL_ 471 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 471 Class 0 "point" 1 "vehicle";
+        
+BO_ 472 ObjectData_89: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 472 "Object detection and tracking information";
+VAL_ 472 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 472 Class 0 "point" 1 "vehicle";
+        
+BO_ 473 ObjectData_90: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 473 "Object detection and tracking information";
+VAL_ 473 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 473 Class 0 "point" 1 "vehicle";
+        
+BO_ 474 ObjectData_91: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 474 "Object detection and tracking information";
+VAL_ 474 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 474 Class 0 "point" 1 "vehicle";
+        
+BO_ 475 ObjectData_92: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 475 "Object detection and tracking information";
+VAL_ 475 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 475 Class 0 "point" 1 "vehicle";
+        
+BO_ 476 ObjectData_93: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 476 "Object detection and tracking information";
+VAL_ 476 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 476 Class 0 "point" 1 "vehicle";
+        
+BO_ 477 ObjectData_94: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 477 "Object detection and tracking information";
+VAL_ 477 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 477 Class 0 "point" 1 "vehicle";
+        
+BO_ 478 ObjectData_95: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 478 "Object detection and tracking information";
+VAL_ 478 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 478 Class 0 "point" 1 "vehicle";
+        
+BO_ 479 ObjectData_96: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 479 "Object detection and tracking information";
+VAL_ 479 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 479 Class 0 "point" 1 "vehicle";
+        
+BO_ 480 ObjectData_97: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 480 "Object detection and tracking information";
+VAL_ 480 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 480 Class 0 "point" 1 "vehicle";
+        
+BO_ 481 ObjectData_98: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 481 "Object detection and tracking information";
+VAL_ 481 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 481 Class 0 "point" 1 "vehicle";
+        
+BO_ 482 ObjectData_99: 8 RADAR
+ SG_ ID : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ DistLong : 15|13@0+ (0.2,-500) [-500|1138.2] "m" XXX
+ SG_ DistLat : 18|11@0+ (0.2,-204.6) [-204.6|204.8] "m" XXX
+ SG_ VRelLong : 39|10@0+ (0.25,-128) [-128|127.75] "m/s" XXX
+ SG_ VRelLat : 45|9@0+ (0.25,-64) [-64|63.75] "m/s" XXX
+ SG_ DynProp : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ Class : 52|2@0+ (1,0) [0|3] "" XXX
+ SG_ RCS : 63|8@0+ (0.5,-64) [-64|63.75] "dBm2" XXX
+
+CM_ BO_ 482 "Object detection and tracking information";
+VAL_ 482 DynProp 0 "moving" 1 "stationary" 2 "oncoming" 3 "crossing_left" 4 "crossing_right" 5 "unknown" 6 "stopped";
+VAL_ 482 Class 0 "point" 1 "vehicle";
+        
\ No newline at end of file
diff --git a/opendbc_repo/opendbc/safety/__init__.py b/opendbc_repo/opendbc/safety/__init__.py
index 4ce0cd5f0..2e2933ac2 100644
--- a/opendbc_repo/opendbc/safety/__init__.py
+++ b/opendbc_repo/opendbc/safety/__init__.py
@@ -8,3 +8,5 @@ class ALTERNATIVE_EXPERIENCE:
   DISABLE_STOCK_AEB = 2
   RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX = 8
   ALLOW_AEB = 16
+
+  ALKA = 2 ** 10
diff --git a/opendbc_repo/opendbc/safety/lateral.h b/opendbc_repo/opendbc/safety/lateral.h
index f842eaa47..86122cf55 100644
--- a/opendbc_repo/opendbc/safety/lateral.h
+++ b/opendbc_repo/opendbc/safety/lateral.h
@@ -60,8 +60,9 @@ static bool rt_torque_rate_limit_check(int val, int val_last, const int MAX_RT_D
 bool steer_torque_cmd_checks(int desired_torque, int steer_req, const TorqueSteeringLimits limits) {
   bool violation = false;
   uint32_t ts = microsecond_timer_get();
+  bool alka = (alternative_experience & ALT_EXP_ALKA) != 0;
 
-  if (controls_allowed) {
+  if (controls_allowed || alka) {
     // Some safety models support variable torque limit based on vehicle speed
     int max_torque = limits.max_torque;
     if (limits.dynamic_max_torque) {
@@ -96,7 +97,7 @@ bool steer_torque_cmd_checks(int desired_torque, int steer_req, const TorqueStee
   }
 
   // no torque if controls is not allowed
-  if (!controls_allowed && (desired_torque != 0)) {
+  if (!(controls_allowed || alka) && (desired_torque != 0)) {
     violation = true;
   }
 
@@ -138,7 +139,7 @@ bool steer_torque_cmd_checks(int desired_torque, int steer_req, const TorqueStee
   }
 
   // reset to 0 if either controls is not allowed or there's a violation
-  if (violation || !controls_allowed) {
+  if (violation || !(controls_allowed || alka)) {
     valid_steer_req_count = 0;
     invalid_steer_req_count = 0;
     desired_torque_last = 0;
@@ -176,7 +177,9 @@ static bool rt_angle_rate_limit_check(AngleSteeringLimits limits) {
 bool steer_angle_cmd_checks(int desired_angle, bool steer_control_enabled, const AngleSteeringLimits limits) {
   bool violation = false;
 
-  if (controls_allowed && steer_control_enabled) {
+  bool alka = (alternative_experience & ALT_EXP_ALKA) != 0;
+
+  if ((controls_allowed || alka) && steer_control_enabled) {
     // convert floating point angle rate limits to integers in the scale of the desired angle on CAN,
     // add 1 to not false trigger the violation. also fudge the speed by 1 m/s so rate limits are
     // always slightly above openpilot's in case we read an updated speed in between angle commands
@@ -262,12 +265,12 @@ bool steer_angle_cmd_checks(int desired_angle, bool steer_control_enabled, const
   }
 
   // No angle control allowed when controls are not allowed
-  if (!controls_allowed) {
+  if (!(controls_allowed || alka)) {
     violation |= steer_control_enabled;
   }
 
   // reset to current angle if either controls is not allowed or there's a violation
-  if (violation || !controls_allowed) {
+  if (violation || !(controls_allowed || alka)) {
     if (limits.inactive_angle_is_zero) {
       desired_angle_last = 0;
     } else {
@@ -304,7 +307,10 @@ bool steer_angle_cmd_checks_vm(int desired_angle, bool steer_control_enabled, co
 
   bool violation = false;
 
-  if (controls_allowed && steer_control_enabled) {
+  bool alka = (alternative_experience & ALT_EXP_ALKA) != 0;
+
+
+  if ((controls_allowed || alka) && steer_control_enabled) {
     // *** ISO lateral jerk limit ***
     // calculate maximum angle rate per second
     const float max_curvature_rate_sec = MAX_LATERAL_JERK / (fudged_speed * fudged_speed);
@@ -340,12 +346,12 @@ bool steer_angle_cmd_checks_vm(int desired_angle, bool steer_control_enabled, co
   }
 
   // No angle control allowed when controls are not allowed
-  if (!controls_allowed) {
+  if (!(controls_allowed || alka)) {
     violation |= steer_control_enabled;
   }
 
   // reset to current angle if either controls is not allowed or there's a violation
-  if (violation || !controls_allowed) {
+  if (violation || !(controls_allowed || alka)) {
     desired_angle_last = CLAMP(angle_meas.values[0], -limits.max_angle, limits.max_angle);
   }
 
diff --git a/opendbc_repo/opendbc/safety/modes/honda.h b/opendbc_repo/opendbc/safety/modes/honda.h
index c7fe76b2d..ec182811c 100644
--- a/opendbc_repo/opendbc/safety/modes/honda.h
+++ b/opendbc_repo/opendbc/safety/modes/honda.h
@@ -238,7 +238,8 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
 
   // STEER: safety check
   if ((msg->addr == 0xE4U) || (msg->addr == 0x194U)) {
-    if (!controls_allowed) {
+    bool alka = (alternative_experience & ALT_EXP_ALKA) != 0;
+    if (!(controls_allowed || alka)) {
       bool steer_applied = msg->data[0] | msg->data[1];
       if (steer_applied) {
         tx = false;
diff --git a/opendbc_repo/opendbc/safety/safety_declarations.h b/opendbc_repo/opendbc/safety/safety_declarations.h
index e759656cb..6704c094b 100644
--- a/opendbc_repo/opendbc/safety/safety_declarations.h
+++ b/opendbc_repo/opendbc/safety/safety_declarations.h
@@ -303,6 +303,8 @@ extern struct sample_t angle_meas;         // last 6 steer angles/curvatures
 // This flag allows AEB to be commanded from openpilot.
 #define ALT_EXP_ALLOW_AEB 16
 
+#define ALT_EXP_ALKA 1024
+
 extern int alternative_experience;
 
 // time since safety mode has been changed
diff --git a/panda/board/stm32f4/board.h b/panda/board/stm32f4/board.h
index 455f7c3c6..e5386c9d8 100644
--- a/panda/board/stm32f4/board.h
+++ b/panda/board/stm32f4/board.h
@@ -18,6 +18,11 @@ void detect_board_type(void) {
   if (!detect_with_pull(GPIOB, 1, PULL_UP) && !detect_with_pull(GPIOB, 7, PULL_UP)) {
     hw_type = HW_TYPE_DOS;
     current_board = &board_dos;
+  // rick - for Lite, it detected as UNO before 0.9.9
+  // Confirmed with mr. one, we are safe to do so for Lite
+  } else if(!detect_with_pull(GPIOB, 15, PULL_UP)) {
+    hw_type = HW_TYPE_DOS;
+    current_board = &board_dos;
   }
 
   // Return A13 to the alt mode to fix SWD
diff --git a/panda/python/__init__.py b/panda/python/__init__.py
index 72c4f8dba..671157e71 100644
--- a/panda/python/__init__.py
+++ b/panda/python/__init__.py
@@ -643,6 +643,9 @@ class Panda:
   def get_type(self):
     ret = self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40)
 
+    # rick - UNO to DOS for lite
+    if ret == bytearray(b'\x05'):
+      ret = bytearray(b'\x06')
     # old bootstubs don't implement this endpoint, see comment in Panda.device
     if self._bcd_hw_type is not None and (ret is None or len(ret) != 1):
       ret = self._bcd_hw_type
diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py
index 00be61362..9262ebee4 100755
--- a/selfdrive/car/card.py
+++ b/selfdrive/car/card.py
@@ -20,6 +20,7 @@ from opendbc.car.interfaces import CarInterfaceBase, RadarInterfaceBase
 from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp
 from openpilot.selfdrive.car.cruise import VCruiseHelper
 from openpilot.selfdrive.car.car_specific import MockCarState
+from opendbc.safety import ALTERNATIVE_EXPERIENCE
 
 REPLAY = "REPLAY" in os.environ
 
@@ -101,6 +102,9 @@ class Car:
         with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
           cached_params = _cached_params
 
+      if self.params.get_bool("dp_lat_alka"):
+        dp_params |= structs.DPFlags.LateralALKA
+
       self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, dp_params, cached_params)
       self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP)
       self.CP = self.CI.CP
@@ -111,7 +115,14 @@ class Car:
       self.CI, self.CP = CI, CI.CP
       self.RI = RI
 
+    if self.params.get_bool("dp_lon_ext_radar"):
+      from opendbc.car.radar_interface import RadarInterface
+      self.RI = RadarInterface(self.CI.CP)
+
     self.CP.alternativeExperience = 0
+    if dp_params & structs.DPFlags.LateralALKA:
+      self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ALKA
+
     openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
     controller_available = self.CI.CC is not None and openpilot_enabled_toggle and not self.CP.dashcamOnly
     self.CP.passive = not controller_available or self.CP.dashcamOnly
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index dd7968b73..e29bca9a8 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -38,7 +38,7 @@ class Controls:
     self.sm = messaging.SubMaster(['liveParameters', 'liveTorqueParameters', 'modelV2', 'selfdriveState',
                                    'liveCalibration', 'livePose', 'longitudinalPlan', 'carState', 'carOutput',
                                    'driverMonitoringState', 'onroadEvents', 'driverAssistance'], poll='selfdriveState')
-    self.pm = messaging.PubMaster(['carControl', 'controlsState'])
+    self.pm = messaging.PubMaster(['carControl', 'controlsState', 'dpControlsState'])
 
     self.steer_limited_by_controls = False
     self.curvature = 0.0
@@ -57,6 +57,9 @@ class Controls:
     elif self.CP.lateralTuning.which() == 'torque':
       self.LaC = LatControlTorque(self.CP, self.CI)
 
+    self.alka_enabled = self.params.get_bool("dp_lat_alka")
+    self.alka_active = False
+
   def update(self):
     self.sm.update(15)
     if self.sm.updated["liveCalibration"]:
@@ -92,7 +95,9 @@ class Controls:
 
     # Check which actuators can be enabled
     standstill = abs(CS.vEgo) <= max(self.CP.minSteerSpeed, 0.3) or CS.standstill
-    CC.latActive = self.sm['selfdriveState'].active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
+    self.alka_active = self.alka_enabled and CS.cruiseState.available and not standstill and CS.gearShifter != car.CarState.GearShifter.reverse
+    lat_active = self.sm['selfdriveState'].active or self.alka_active
+    CC.latActive = lat_active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
                    (not standstill or self.CP.steerAtStandstill)
     CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and self.CP.openpilotLongitudinalControl
 
@@ -175,6 +180,13 @@ class Controls:
     # TODO: both controlsState and carControl valids should be set by
     #       sm.all_checks(), but this creates a circular dependency
 
+    # dpControlsState
+    dat = messaging.new_message('dpControlsState')
+    dat.valid = True
+    ncs = dat.dpControlsState
+    ncs.alkaActive = self.alka_active
+    self.pm.send('dpControlsState', dat)
+
     # controlsState
     dat = messaging.new_message('controlsState')
     dat.valid = CS.canValid
diff --git a/selfdrive/controls/lib/desire_helper.py b/selfdrive/controls/lib/desire_helper.py
index 730aaeb8f..a1519679f 100644
--- a/selfdrive/controls/lib/desire_helper.py
+++ b/selfdrive/controls/lib/desire_helper.py
@@ -1,6 +1,7 @@
 from cereal import log
 from openpilot.common.constants import CV
 from openpilot.common.realtime import DT_MDL
+import time
 
 LaneChangeState = log.LaneChangeState
 LaneChangeDirection = log.LaneChangeDirection
@@ -31,7 +32,7 @@ DESIRES = {
 
 
 class DesireHelper:
-  def __init__(self):
+  def __init__(self, dp_lat_lca_speed=LANE_CHANGE_SPEED_MIN, dp_lat_lca_auto_sec=0.):
     self.lane_change_state = LaneChangeState.off
     self.lane_change_direction = LaneChangeDirection.none
     self.lane_change_timer = 0.0
@@ -39,20 +40,26 @@ class DesireHelper:
     self.keep_pulse_timer = 0.0
     self.prev_one_blinker = False
     self.desire = log.Desire.none
+    self.dp_lat_lca_speed = float(dp_lat_lca_speed * CV.MPH_TO_MS)
+    self.dp_lat_lca_auto_sec = dp_lat_lca_auto_sec
+    self.dp_lat_lca_auto_sec_start = 0.
 
-  def update(self, carstate, lateral_active, lane_change_prob):
+  def update(self, carstate, lateral_active, lane_change_prob, left_edge_detected, right_edge_detected):
     v_ego = carstate.vEgo
     one_blinker = carstate.leftBlinker != carstate.rightBlinker
-    below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
+    below_lane_change_speed = True if self.dp_lat_lca_speed == 0. else v_ego < self.dp_lat_lca_speed
 
     if not lateral_active or self.lane_change_timer > LANE_CHANGE_TIME_MAX:
       self.lane_change_state = LaneChangeState.off
       self.lane_change_direction = LaneChangeDirection.none
     else:
       # LaneChangeState.off
+      c_time = time.monotonic()
       if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed:
         self.lane_change_state = LaneChangeState.preLaneChange
         self.lane_change_ll_prob = 1.0
+        if self.dp_lat_lca_auto_sec > 0.:
+          self.dp_lat_lca_auto_sec_start = c_time
 
       # LaneChangeState.preLaneChange
       elif self.lane_change_state == LaneChangeState.preLaneChange:
@@ -64,8 +71,16 @@ class DesireHelper:
                          ((carstate.steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or
                           (carstate.steeringTorque < 0 and self.lane_change_direction == LaneChangeDirection.right))
 
-        blindspot_detected = ((carstate.leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or
-                              (carstate.rightBlindspot and self.lane_change_direction == LaneChangeDirection.right))
+        blindspot_detected = (((carstate.leftBlindspot or left_edge_detected) and self.lane_change_direction == LaneChangeDirection.left) or
+                              ((carstate.rightBlindspot or right_edge_detected) and self.lane_change_direction == LaneChangeDirection.right))
+
+        # reset timer
+        if self.dp_lat_lca_auto_sec > 0.:
+          if blindspot_detected:
+            self.dp_lat_lca_auto_sec_start = c_time
+          else:
+            if (c_time - self.dp_lat_lca_auto_sec_start) >= self.dp_lat_lca_auto_sec:
+              torque_applied = True
 
         if not one_blinker or below_lane_change_speed:
           self.lane_change_state = LaneChangeState.off
diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py
index 94b63290c..d3a008b60 100755
--- a/selfdrive/controls/lib/longitudinal_planner.py
+++ b/selfdrive/controls/lib/longitudinal_planner.py
@@ -14,6 +14,8 @@ from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDX
 from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, get_accel_from_plan
 from openpilot.selfdrive.car.cruise import V_CRUISE_MAX, V_CRUISE_UNSET
 from openpilot.common.swaglog import cloudlog
+from dragonpilot.selfdrive.controls.lib.acm import ACM
+from dragonpilot.selfdrive.controls.lib.aem import AEM
 
 LON_MPC_STEP = 0.2  # first step is 0.2s
 A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6]
@@ -27,6 +29,9 @@ _A_TOTAL_MAX_V = [1.7, 3.2]
 _A_TOTAL_MAX_BP = [20., 40.]
 
 class DPFlags:
+  ACM = 1
+  ACM_DOWNHILL = 2 ** 1
+  AEM = 2 ** 2
   pass
 
 def get_max_accel(v_ego):
@@ -70,6 +75,8 @@ class LongitudinalPlanner:
     self.a_desired_trajectory = np.zeros(CONTROL_N)
     self.j_desired_trajectory = np.zeros(CONTROL_N)
     self.solverExecutionTime = 0.0
+    self.acm = ACM()
+    self.aem = AEM()
 
   @staticmethod
   def parse_model(model_msg):
@@ -92,7 +99,39 @@ class LongitudinalPlanner:
     return x, v, a, j, throttle_prob
 
   def update(self, sm, dp_flags = 0):
-    mode = 'blended' if sm['selfdriveState'].experimentalMode else 'acc'
+    v_ego = sm['carState'].vEgo
+
+    # --- Calculate current cycle variables needed by AEM ---
+    x, v, a, j, throttle_prob = self.parse_model(sm['modelV2'])
+    # Don't clip at low speeds since throttle_prob doesn't account for creep
+    self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED
+
+    # --- AEM Logic: Determine MPC mode ---
+    if sm['selfdriveState'].experimentalMode:
+      mode = 'blended'
+    else:
+      mode = 'acc'
+
+      if (dp_flags & DPFlags.AEM) and not self.aem.enabled:
+        self.aem.enabled = True
+
+      if self.aem.enabled:
+        steer_angle_without_offset = sm['carState'].steeringAngleDeg - sm['liveParameters'].angleOffsetDeg
+        model_path_plan_for_aem = {'x': x, 'v': v, 'a': a, 'j': j}
+
+        current_cycle_mode = self.aem.get_mode(
+            v_ego_raw=v_ego,
+            lead_one_data_raw=sm['radarState'].leadOne,
+            steering_angle_deg_raw=steer_angle_without_offset,
+            standstill_raw=sm['carState'].standstill,
+            long_personality=self.aem.personality,
+            allow_throttle_planner=self.allow_throttle,
+            model_path_plan_raw=model_path_plan_for_aem,
+            a_target_from_prev_cycle=self.output_a_target,
+            model_predicts_stop_prev=self.output_should_stop,
+            fcw_active_prev=self.fcw,
+        )
+        mode = current_cycle_mode
 
     if len(sm['carControl'].orientationNED) == 3:
       accel_coast = get_coast_accel(sm['carControl'].orientationNED[1])
@@ -112,6 +151,20 @@ class LongitudinalPlanner:
     # PCM cruise speed may be updated a few cycles later, check if initialized
     reset_state = reset_state or not v_cruise_initialized
 
+    # Update ACM status
+    if not sm['selfdriveState'].experimentalMode:
+      if not self.acm.enabled and dp_flags & DPFlags.ACM:
+        self.acm.enabled = True
+        self.acm.downhill_only = bool(dp_flags & DPFlags.ACM_DOWNHILL)
+    else:
+      self.acm.enabled = False
+
+    user_control = long_control_off if self.CP.openpilotLongitudinalControl else not sm['selfdriveState'].enabled
+    self.acm.update_states(sm['carControl'], sm['radarState'], user_control, v_ego, v_cruise)
+
+    if self.acm.just_disabled:
+      reset_state = True
+
     # No change cost when user is controlling the speed, or when standstill
     prev_accel_constraint = not (reset_state or sm['carState'].standstill)
 
@@ -129,9 +182,10 @@ class LongitudinalPlanner:
 
     # Prevent divergence, smooth in current v_ego
     self.v_desired_filter.x = max(0.0, self.v_desired_filter.update(v_ego))
-    x, v, a, j, throttle_prob = self.parse_model(sm['modelV2'])
-    # Don't clip at low speeds since throttle_prob doesn't account for creep
-    self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED
+    # AEM - move to top so it can access them
+    # x, v, a, j, throttle_prob = self.parse_model(sm['modelV2'])
+    # # Don't clip at low speeds since throttle_prob doesn't account for creep
+    # self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED
 
     if not self.allow_throttle:
       clipped_accel_coast = max(accel_coast, accel_clip[0])
@@ -141,14 +195,18 @@ class LongitudinalPlanner:
     if force_slow_decel:
       v_cruise = 0.0
 
-    self.mpc.set_weights(prev_accel_constraint, personality=sm['selfdriveState'].personality)
+    self.aem.set_personality(v_ego, sm['selfdriveState'].personality)
+    self.mpc.set_weights(prev_accel_constraint, personality=self.aem.personality)
     self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired)
-    self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=sm['selfdriveState'].personality)
+    self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=self.aem.personality)
 
     self.v_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.v_solution)
     self.a_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.a_solution)
     self.j_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC[:-1], self.mpc.j_solution)
 
+    # Apply ACM post-processing to the acceleration trajectory if active
+    self.a_desired_trajectory = self.acm.update_a_desired_trajectory(self.a_desired_trajectory)
+
     # TODO counter is only needed because radar is glitchy, remove once radar is gone
     self.fcw = self.mpc.crash_cnt > 2 and not sm['carState'].standstill
     if self.fcw:
@@ -172,6 +230,9 @@ class LongitudinalPlanner:
       output_a_target = min(output_a_target_mpc, output_a_target_e2e)
       self.output_should_stop = output_should_stop_e2e or output_should_stop_mpc
 
+    # Apply ACM to the final output acceleration target as well
+    output_a_target = self.acm.update_output_a_target(output_a_target)
+
     for idx in range(2):
       accel_clip[idx] = np.clip(accel_clip[idx], self.prev_accel_clip[idx] - 0.05, self.prev_accel_clip[idx] + 0.05)
     self.output_a_target = np.clip(output_a_target, accel_clip[0], accel_clip[1])
diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py
index dc3d5d231..bd5d065fa 100755
--- a/selfdrive/controls/plannerd.py
+++ b/selfdrive/controls/plannerd.py
@@ -23,7 +23,12 @@ def main():
                            poll='modelV2')
 
   dp_flags = 0
-
+  if params.get_bool("dp_lon_acm"):
+    dp_flags |= DPFlags.ACM
+    if params.get_bool("dp_lon_acm_downhill"):
+      dp_flags |= DPFlags.ACM_DOWNHILL
+  if params.get_bool("dp_lon_aem"):
+    dp_flags |= DPFlags.AEM
   while True:
     sm.update()
     if sm.updated['modelV2']:
diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py
index 707b221bb..14c7c40d9 100755
--- a/selfdrive/modeld/modeld.py
+++ b/selfdrive/modeld/modeld.py
@@ -30,6 +30,7 @@ from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_
 from openpilot.selfdrive.modeld.constants import ModelConstants, Plan
 from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
 from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
+from dragonpilot.selfdrive.controls.lib.road_edge_detector import RoadEdgeDetector
 
 
 PROCESS_NAME = "selfdrive.modeld.modeld"
@@ -220,7 +221,7 @@ def main(demo=False):
     cloudlog.warning(f"connected extra cam with buffer size: {vipc_client_extra.buffer_len} ({vipc_client_extra.width} x {vipc_client_extra.height})")
 
   # messaging
-  pm = PubMaster(["modelV2", "drivingModelData", "cameraOdometry"])
+  pm = PubMaster(["modelV2", "drivingModelData", "cameraOdometry", "modelExt"])
   sm = SubMaster(["deviceState", "carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "carControl", "liveDelay"])
 
   publish_state = PublishState()
@@ -251,7 +252,10 @@ def main(demo=False):
   long_delay = CP.longitudinalActuatorDelay + LONG_SMOOTH_SECONDS
   prev_action = log.ModelDataV2.Action()
 
-  DH = DesireHelper()
+  dp_lat_lca_speed = int(params.get("dp_lat_lca_speed"))
+  dp_lat_lca_auto_sec = float(params.get("dp_lat_lca_auto_sec"))
+  DH = DesireHelper(dp_lat_lca_speed=dp_lat_lca_speed, dp_lat_lca_auto_sec=dp_lat_lca_auto_sec)
+  RED = RoadEdgeDetector(params.get_bool("dp_lat_road_edge_detection"))
 
   while True:
     # Keep receiving frames until we are at least 1 frame ahead of previous extra frame
@@ -337,6 +341,7 @@ def main(demo=False):
       modelv2_send = messaging.new_message('modelV2')
       drivingdata_send = messaging.new_message('drivingModelData')
       posenet_send = messaging.new_message('cameraOdometry')
+      model_ext_send = messaging.new_message('modelExt')
 
       action = get_action_from_model(model_output, prev_action, lat_delay + DT_MDL, long_delay + DT_MDL, v_ego)
       prev_action = action
@@ -348,7 +353,10 @@ def main(demo=False):
       l_lane_change_prob = desire_state[log.Desire.laneChangeLeft]
       r_lane_change_prob = desire_state[log.Desire.laneChangeRight]
       lane_change_prob = l_lane_change_prob + r_lane_change_prob
-      DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob)
+      RED.update(modelv2_send.modelV2.roadEdgeStds, modelv2_send.modelV2.laneLineProbs)
+      model_ext_send.modelExt.leftEdgeDetected = RED.left_edge_detected
+      model_ext_send.modelExt.rightEdgeDetected = RED.right_edge_detected
+      DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob, RED.left_edge_detected, RED.right_edge_detected)
       modelv2_send.modelV2.meta.laneChangeState = DH.lane_change_state
       modelv2_send.modelV2.meta.laneChangeDirection = DH.lane_change_direction
       drivingdata_send.drivingModelData.meta.laneChangeState = DH.lane_change_state
@@ -358,6 +366,7 @@ def main(demo=False):
       pm.send('modelV2', modelv2_send)
       pm.send('drivingModelData', drivingdata_send)
       pm.send('cameraOdometry', posenet_send)
+      pm.send('modelExt', model_ext_send)
     last_vipc_frame_id = meta_main.frame_id
 
 
diff --git a/selfdrive/monitoring/dpmonitoringd.py b/selfdrive/monitoring/dpmonitoringd.py
new file mode 100644
index 000000000..668782d01
--- /dev/null
+++ b/selfdrive/monitoring/dpmonitoringd.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+import time
+import cereal.messaging as messaging
+from openpilot.common.params import Params
+from openpilot.common.realtime import config_realtime_process, Ratekeeper, DT_DMON
+from cereal import log
+
+EventName = log.OnroadEvent.EventName
+
+class SimpleDriverMonitoring:
+  def __init__(self):
+    # Timing configuration (in seconds)
+    self.FIRST_WARNING_TIME = 45.0
+    self.SECOND_WARNING_TIME = 60.0
+    self.THIRD_WARNING_TIME = 75.0
+
+    # State variables
+    self.awareness = 1.0  # Full awareness
+    self.current_events = []
+    # self.last_interaction_time = 0
+    self.hands_on_steering = False
+
+    # Warning thresholds (normalized to 0-1 scale)
+    self.threshold_prompt = self.FIRST_WARNING_TIME / self.THIRD_WARNING_TIME  # ~0.643 for first warning
+    self.threshold_critical = self.SECOND_WARNING_TIME / self.THIRD_WARNING_TIME  # ~0.857 for second warning
+
+    # Step change (how much awareness decreases per step)
+    self.step_change = DT_DMON / self.THIRD_WARNING_TIME
+
+    params = Params()
+    self.is_rhd = params.get_bool("dp_device_is_rhd")
+    self.monitoring_disabled = params.get_bool("dp_device_monitoring_disabled")
+
+  def update_events(self, reset_condition, op_engaged):
+    self.current_events = []
+
+    if self.monitoring_disabled:
+      return
+
+    # If not engaged, reset awareness and return
+    if not op_engaged:
+      self.awareness = 1.0
+      return
+
+    # Reset awareness on any reset condition (standstill, any input)
+    if reset_condition:
+      self.awareness = 1.0
+      return
+
+    # Only decrease awareness if we're not detecting hands on steering
+    self.awareness = max(self.awareness - self.step_change, 0.0)
+
+    # Determine alert level based on awareness
+    if self.awareness <= 0.0:
+      # Third warning (red alert) at 70 seconds
+      self.current_events.append(EventName.driverUnresponsive)
+    elif self.awareness <= (1.0 - self.threshold_critical):
+      # Second warning (orange alert) at 60 seconds
+      self.current_events.append(EventName.promptDriverUnresponsive)
+    elif self.awareness <= (1.0 - self.threshold_prompt):
+      # First warning (green alert) at 45 seconds
+      self.current_events.append(EventName.preDriverUnresponsive)
+
+  def get_state_packet(self, valid=True):
+    # Create driver monitoring state message
+    dat = messaging.new_message('driverMonitoringState', valid=valid)
+    events = []
+
+    for event_name in self.current_events:
+      event = log.OnroadEvent.new_message()
+      event.name = event_name
+      events.append(event)
+
+    dat.driverMonitoringState = {
+      "events": events,
+      "faceDetected": False,  # Not using face detection
+      "isDistracted": self.awareness <= (1.0 - self.threshold_prompt),
+      "distractedType": 0,  # Not using distraction types
+      "awarenessStatus": 1.0, #self.awareness, (always 1.0 so no decel)
+      "posePitchOffset": 0.0,
+      "posePitchValidCount": 0,
+      "poseYawOffset": 0.0,
+      "poseYawValidCount": 0,
+      "stepChange": self.step_change,
+      "awarenessActive": self.awareness,
+      "awarenessPassive": self.awareness,
+      "isLowStd": True,
+      "hiStdCount": 0,
+      "isActiveMode": True,
+      "isRHD": self.is_rhd,
+    }
+    return dat
+
+def dmonitoringd_thread():
+  # Configure process priority
+  config_realtime_process([0, 1, 2, 3], 5)
+
+  # Initialize parameters and messaging
+  pm = messaging.PubMaster(['driverMonitoringState'])
+  sm = messaging.SubMaster(['carState', 'selfdriveState'])
+
+  # Initialize driver monitoring system
+  DM = SimpleDriverMonitoring()
+
+  # Create ratekeeper for 20Hz operation
+  rk = Ratekeeper(20, None)
+
+  # Main loop running at 20Hz
+  while True:
+    sm.update()
+
+    # Check if steering is touched (only monitoring steering for hands-on)
+
+    # Reset conditions: not engaged, standstill, or any input
+    reset_condition = (
+      sm['carState'].standstill or
+      sm['carState'].steeringPressed or
+      sm['carState'].gasPressed or
+      sm['carState'].brakePressed or
+      sm['carState'].leftBlinker or
+      sm['carState'].rightBlinker
+    )
+
+    # Process driver monitoring - monitoring only steering for hands-on
+    # but resetting on any input
+    DM.update_events(
+      reset_condition=reset_condition,
+      op_engaged=sm['selfdriveState'].enabled
+    )
+
+    # Publish driver monitoring state
+    dat = DM.get_state_packet()
+    pm.send('driverMonitoringState', dat)
+
+    # Maintain 20Hz
+    rk.keep_time()
+
+def main():
+  dmonitoringd_thread()
+
+if __name__ == '__main__':
+  main()
diff --git a/selfdrive/pandad/pandad.cc b/selfdrive/pandad/pandad.cc
index faaeb1531..3d48541e6 100644
--- a/selfdrive/pandad/pandad.cc
+++ b/selfdrive/pandad/pandad.cc
@@ -372,6 +372,7 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control)
   static uint16_t prev_fan_speed = 999;
   static int ir_pwr = 0;
   static int prev_ir_pwr = 999;
+  const bool lite = getenv("LITE");
 
   static FirstOrderFilter integ_lines_filter(0, 30.0, 0.05);
 
@@ -386,7 +387,7 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control)
       }
     }
 
-    if (sm.updated("driverCameraState")) {
+    if (!lite && sm.updated("driverCameraState")) {
       auto event = sm["driverCameraState"];
       int cur_integ_lines = event.getDriverCameraState().getIntegLines();
 
@@ -403,14 +404,14 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control)
     }
 
     // Disable IR on input timeout
-    if (nanos_since_boot() - last_driver_camera_t > 1e9) {
+    if (!lite && nanos_since_boot() - last_driver_camera_t > 1e9) {
       ir_pwr = 0;
     }
 
     if (ir_pwr != prev_ir_pwr || sm.frame % 100 == 0) {
-      int16_t ir_panda = util::map_val(ir_pwr, 0, 100, 0, MAX_IR_PANDA_VAL); 
+      int16_t ir_panda = util::map_val(ir_pwr, 0, 100, 0, MAX_IR_PANDA_VAL);
       panda->set_ir_pwr(ir_panda);
-      Hardware::set_ir_power(ir_pwr); 
+      Hardware::set_ir_power(ir_pwr);
       prev_ir_pwr = ir_pwr;
     }
   }
diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py
index d783b2b67..e02029994 100755
--- a/selfdrive/selfdrived/selfdrived.py
+++ b/selfdrive/selfdrived/selfdrived.py
@@ -23,6 +23,7 @@ from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroa
 
 from openpilot.system.hardware import HARDWARE
 from openpilot.system.version import get_build_metadata
+from opendbc.safety import ALTERNATIVE_EXPERIENCE
 
 REPLAY = "REPLAY" in os.environ
 SIMULATION = "SIMULATION" in os.environ
@@ -58,6 +59,8 @@ class SelfdriveD:
 
     self.car_events = CarSpecificEvents(self.CP)
 
+    self.alka = bool(self.CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALKA)
+
     self.pose_calibrator = PoseCalibrator()
     self.calibrated_pose: Pose | None = None
     self.excessive_actuation_check = ExcessiveActuationCheck()
@@ -74,16 +77,18 @@ class SelfdriveD:
     # TODO: de-couple selfdrived with card/conflate on carState without introducing controls mismatches
     self.car_state_sock = messaging.sub_sock('carState', timeout=20)
 
-    ignore = self.sensor_packets + self.gps_packets + ['alertDebug']
+    ignore = self.sensor_packets + self.gps_packets + ['alertDebug'] + ['modelExt']
     if SIMULATION:
       ignore += ['driverCameraState', 'managerState']
     if REPLAY:
       # no vipc in replay will make them ignored anyways
       ignore += ['roadCameraState', 'wideRoadCameraState']
+    if os.getenv("DISABLE_DRIVER") or os.getenv("LITE"):
+      ignore += ['driverCameraState']
     self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
                                    'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose', 'liveDelay',
                                    'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
-                                   'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userBookmark', 'audioFeedback'] + \
+                                   'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userBookmark', 'audioFeedback', 'modelExt'] + \
                                    self.camera_packets + self.sensor_packets + self.gps_packets,
                                   ignore_alive=ignore, ignore_avg_freq=ignore,
                                   ignore_valid=ignore, frequency=int(1/DT_CTRL))
@@ -119,7 +124,7 @@ class SelfdriveD:
     self.experimental_mode = False
     self.personality = self.params.get("LongitudinalPersonality", return_default=True)
     self.recalibrating_seen = False
-    self.state_machine = StateMachine()
+    self.state_machine = StateMachine(self.alka)
     self.rk = Ratekeeper(100, print_delay_threshold=None)
 
     # some comma three with NVMe experience NVMe dropouts mid-drive that
@@ -261,8 +266,8 @@ class SelfdriveD:
     # Handle lane change
     if self.sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange:
       direction = self.sm['modelV2'].meta.laneChangeDirection
-      if (CS.leftBlindspot and direction == LaneChangeDirection.left) or \
-         (CS.rightBlindspot and direction == LaneChangeDirection.right):
+      if ((CS.leftBlindspot or self.sm['modelExt'].leftEdgeDetected) and direction == LaneChangeDirection.left) or \
+         ((CS.rightBlindspot or self.sm['modelExt'].rightEdgeDetected) and direction == LaneChangeDirection.right):
         self.events.add(EventName.laneChangeBlocked)
       else:
         if direction == LaneChangeDirection.left:
diff --git a/selfdrive/selfdrived/state.py b/selfdrive/selfdrived/state.py
index 073ddb56e..940fcb029 100644
--- a/selfdrive/selfdrived/state.py
+++ b/selfdrive/selfdrived/state.py
@@ -9,10 +9,11 @@ ACTIVE_STATES = (State.enabled, State.softDisabling, State.overriding)
 ENABLED_STATES = (State.preEnabled, *ACTIVE_STATES)
 
 class StateMachine:
-  def __init__(self):
+  def __init__(self, alka = False):
     self.current_alert_types = [ET.PERMANENT]
     self.state = State.disabled
     self.soft_disable_timer = 0
+    self.alka = alka
 
   def update(self, events: Events):
     # decrement the soft disable timer at every step, as it's reset on
@@ -92,7 +93,7 @@ class StateMachine:
     # Check if openpilot is engaged and actuators are enabled
     enabled = self.state in ENABLED_STATES
     active = self.state in ACTIVE_STATES
-    if active:
+    if active or self.alka:
       self.current_alert_types.append(ET.WARNING)
     return enabled, active
 
diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript
index 751e7a032..471544553 100644
--- a/selfdrive/ui/SConscript
+++ b/selfdrive/ui/SConscript
@@ -26,6 +26,7 @@ Export('widgets')
 qt_libs = [widgets, qt_util] + base_libs
 
 qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc",
+          "qt/offroad/model_selector.cc",
           "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
           "qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc", "qt/offroad/dp_panel.cc",
           "qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", "qt/offroad/firehose.cc",
diff --git a/selfdrive/ui/qt/offroad/dp_panel.cc b/selfdrive/ui/qt/offroad/dp_panel.cc
index 548b02be5..278adae1c 100644
--- a/selfdrive/ui/qt/offroad/dp_panel.cc
+++ b/selfdrive/ui/qt/offroad/dp_panel.cc
@@ -106,7 +106,19 @@ void DPPanel::add_lateral_toggles() {
       QString::fromUtf8("🐉 ") + tr("Lateral Ctrl"),
       "",
     },
+    {
+      "dp_lat_alka",
+      tr("Always-on Lane Keeping Assist (ALKA)"),
+      "",
+    },
+    {
+      "dp_lat_road_edge_detection",
+      tr("Road Edge Detection (RED)"),
+      tr("Block lane change assist when the system detects the road edge.\nNOTE: This will show 'Car Detected in Blindspot' warning.")
+    },
   };
+  auto lca_speed_toggle = new ParamSpinBoxControl("dp_lat_lca_speed", tr("LCA Speed:"), tr("Off = Disable LCA\n1 mph ≈ 1.2 km/h"), "", 0, 100, 5, tr(" mph"), tr("Off"));
+  lca_sec_toggle = new ParamDoubleSpinBoxControl("dp_lat_lca_auto_sec", QString::fromUtf8(" ") + tr("Auto Lane Change after:"), tr("Off = Disable Auto Lane Change."), "", 0, 5.0, 0.5, tr(" sec"), tr("Off"));
 
   QWidget *label = nullptr;
   bool has_toggle = false;
@@ -115,6 +127,9 @@ void DPPanel::add_lateral_toggles() {
     if (param.isEmpty()) {
       label = new LabelControl(title, "");
       addItem(label);
+      addItem(lca_speed_toggle);
+      addItem(lca_sec_toggle);
+      has_toggle = true;
       continue;
     }
 
@@ -139,6 +154,26 @@ void DPPanel::add_longitudinal_toggles() {
       QString::fromUtf8("🐉 ") + tr("Longitudinal Ctrl"),
       "",
     },
+    {
+      "dp_lon_ext_radar",
+      tr("Use External Radar"),
+      tr("See https://github.com/eFiniLan/openpilot-ext-radar-addon for more information."),
+    },
+    {
+      "dp_lon_acm",
+      QString::fromUtf8("🚧 ") + tr("Enable Adaptive Coasting Mode (ACM)"),
+      tr("Adaptive Coasting Mode (ACM) reduces braking to allow smoother coasting when appropriate.\nDOES NOT WORK with Experimental Mode enabled."),
+    },
+    {
+      "dp_lon_acm_downhill",
+      QString::fromUtf8(" ") + tr("Downhill Only"),
+      tr("Limited to downhill driving."),
+    },
+    {
+      "dp_lon_aem",
+      QString::fromUtf8("🚧 ") + tr("Adaptive Experimental Mode (AEM)"),
+      tr("Adaptive mode switcher between ACC and Blended based on driving context."),
+    },
   };
 
   QWidget *label = nullptr;
@@ -150,6 +185,15 @@ void DPPanel::add_longitudinal_toggles() {
       addItem(label);
       continue;
     }
+    if (param == "dp_lon_ext_radar" && !vehicle_has_radar_unavailable) {
+      continue;
+    }
+    if ((param == "dp_lon_acm" || param == "dp_lon_acm_downhill") && !vehicle_has_long_ctrl) {
+      continue;
+    }
+    if (param == "dp_lon_aem" && !vehicle_has_long_ctrl) {
+      continue;
+    }
 
     has_toggle = true;
     auto toggle = new ParamControl(param, title, desc, "", this);
@@ -172,7 +216,23 @@ void DPPanel::add_ui_toggles() {
       QString::fromUtf8("🐉 ") + tr("UI"),
       "",
     },
+    {
+      "dp_ui_radar_tracks",
+      tr("Display Radar Tracks"),
+      "",
+    },
+    {
+      "dp_ui_rainbow",
+      tr("Rainbow Driving Path like Tesla"),
+      tr("Why not?"),
+    },
   };
+  std::vector display_off_mode_texts{tr("Std."), tr("MAIN+"), tr("OP+"), tr("MAIN-"), tr("OP-")};
+  ButtonParamControl* display_off_mode_setting = new ButtonParamControl("dp_ui_display_mode", tr("Display Mode"),
+                                          tr("Std. - Stock behavior.\nMAIN+ - ACC MAIN on = Display ON.\nOP+ - OP enabled = Display ON.\nMAIN- - ACC MAIN on = Display OFF\nOP- - OP enabled = Display OFF."),
+                                          "",
+                                          display_off_mode_texts, 200);
+  auto hide_hud = new ParamSpinBoxControl("dp_ui_hide_hud_speed_kph", tr("Hide HUD When Moves above:"), tr("To prevent screen burn-in, hide Speed, MAX Speed, and Steering/DM Icons when the car moves.\nOff = Stock Behavior\n1 km/h ≈ 0.6 mph"), "", 0, 120, 5, tr(" km/h"), tr("Off"));
 
   QWidget *label = nullptr;
   bool has_toggle = false;
@@ -181,6 +241,13 @@ void DPPanel::add_ui_toggles() {
     if (param.isEmpty()) {
       label = new LabelControl(title, "");
       addItem(label);
+      addItem(display_off_mode_setting);
+      has_toggle = true;
+      addItem(hide_hud);
+      has_toggle = true;
+      continue;
+    }
+    if (param == "dp_ui_radar_tracks" && !vehicle_has_long_ctrl) {
       continue;
     }
 
@@ -205,15 +272,56 @@ void DPPanel::add_device_toggles() {
       QString::fromUtf8("🐉 ") + tr("Device"),
       "",
     },
+    {
+      "dp_device_is_rhd",
+      tr("Enable Right-Hand Drive Mode"),
+      tr("Allow openpilot to obey right-hand traffic conventions on right driver seat."),
+    },
+    {
+      "dp_device_monitoring_disabled",
+      tr("Disable Driver Monitoring"),
+      "",
+    },
+    {
+      "dp_device_beep",
+      tr("Enable Beep (Warning)"),
+      "",
+    }
   };
+  std::vector audible_alert_mode_texts{tr("Std."), tr("Warning"), tr("Off")};
+  ButtonParamControl* audible_alert_mode_setting = new ButtonParamControl("dp_device_audible_alert_mode", tr("Audible Alert Mode"),
+                                          tr("Warning - Only emits sound when there is a warning.\nOff - Does not emit any sound at all."),
+                                          "",
+                                          audible_alert_mode_texts);
+
+  auto auto_shutdown_toggle = new ParamSpinBoxControl("dp_device_auto_shutdown_in", tr("Auto Shutdown In:"), tr("0 mins = Immediately"), "", -5, 300, 5, tr(" mins"), tr("Off"));
+
+  std::vector dashy_mode_texts{tr("Off"), tr("Lite"), tr("Full")};
+  ButtonParamControl* dashy_mode_settings = new ButtonParamControl("dp_dev_dashy", tr("dashy"),
+                                          tr("dashy - dragonpilot's all-in-one system hub for you.\n\nVisit http://:5088 to access.\n\nOff - Turn off dashy completely.\nLite: File Manager only.\nFull: File Manager + Live Stream."),
+                                          "",
+                                          dashy_mode_texts);
+
+
+  auto delay_loggerd_toggle = new ParamSpinBoxControl("dp_dev_delay_loggerd", tr("Delay Starting Loggerd for:"), tr("Delays the startup of loggerd and its related processes when the device goes on-road.\nThis prevents the initial moments of a drive from being recorded, protecting location privacy at the start of a trip."), "", 0, 300, 5, tr(" secs"), tr("Off"));
 
   QWidget *label = nullptr;
   bool has_toggle = false;
 
+  const bool lite = getenv("LITE");
   for (auto &[param, title, desc] : toggle_defs) {
     if (param.isEmpty()) {
       label = new LabelControl(title, "");
       addItem(label);
+      addItem(auto_shutdown_toggle);
+      has_toggle = true;
+      addItem(dashy_mode_settings);
+      has_toggle = true;
+      addItem(delay_loggerd_toggle);
+      has_toggle = true;
+      continue;
+    }
+    if ((param == "dp_device_is_rhd" || param == "dp_device_monitoring_disabled" || param == "dp_device_beep") && !lite) {
       continue;
     }
 
@@ -224,6 +332,10 @@ void DPPanel::add_device_toggles() {
     addItem(toggle);
     toggles[param.toStdString()] = toggle;
   }
+  if (!getenv("DISABLE_DRIVER")) { // lite check
+    addItem(audible_alert_mode_setting);
+    has_toggle = true;
+  }
 
   // If no toggles were added, hide the label
   if (!has_toggle && label) {
@@ -281,12 +393,19 @@ void DPPanel::showEvent(QShowEvent *event) {
 
 void DPPanel::updateStates() {
   // do fs_watch here
+  fs_watch->addParam("dp_lat_lca_speed");
+  fs_watch->addParam("dp_lon_ext_radar");
+  fs_watch->addParam("dp_lon_acm");
 
   if (!isVisible()) {
     return;
   }
 
   // do state change logic here
+  lca_sec_toggle->setVisible(std::atoi(params.get("dp_lat_lca_speed").c_str()) > 0);
+  if (vehicle_has_long_ctrl) {
+    toggles["dp_lon_acm_downhill"]->setVisible(params.getBool("dp_lon_acm"));
+  }
 
 }
 
diff --git a/selfdrive/ui/qt/offroad/dp_panel.h b/selfdrive/ui/qt/offroad/dp_panel.h
index 87095c73b..2e5889fe1 100644
--- a/selfdrive/ui/qt/offroad/dp_panel.h
+++ b/selfdrive/ui/qt/offroad/dp_panel.h
@@ -28,4 +28,6 @@ private:
   void add_device_toggles();
   void updateStates();
   void showEvent(QShowEvent *event) override;
+
+  ParamDoubleSpinBoxControl* lca_sec_toggle;
 };
diff --git a/selfdrive/ui/qt/offroad/model_selector.cc b/selfdrive/ui/qt/offroad/model_selector.cc
new file mode 100644
index 000000000..f78aa79b4
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/model_selector.cc
@@ -0,0 +1,230 @@
+/*
+Copyright (c) 2025 Rick Lan
+
+This software is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0).
+You are free to share and adapt this work for non-commercial purposes, provided you give appropriate credit and distribute any modifications under the same license.
+
+To view a copy of this license, visit:
+http://creativecommons.org/licenses/by-nc-sa/4.0/
+
+---
+
+**Commercial Licensing:**
+Use of this software for commercial purposes is strictly prohibited without a separate, paid license.
+To purchase a commercial license, please contact ricklan@gmail.com.
+*/
+
+#include "selfdrive/ui/qt/offroad/model_selector.h"
+
+// Define style constants to improve maintainability
+namespace {
+    const QString SELECTOR_BTN_STYLE = "background-color: #00309a; font-size: 48px;";
+    const QString MODEL_LIST_STYLE = "font-size: 64px;";
+    const QString SCROLLBAR_STYLE = "width: 96px;";
+    const QString GROUP_HEADER_BG_COLOR = "#c8c8c8"; // Light gray
+    const QString GROUP_HEADER_TEXT_COLOR = "#000000"; // Black
+
+    // Role for storing the actual model name without indentation
+    const int ModelNameRole = Qt::UserRole;
+}
+
+ModelSelector::ModelSelector(QWidget *parent) : QWidget(parent) {
+    setupUI();
+    setupModelListPanel();
+    connectSignals();
+}
+
+QWidget* ModelSelector::setupUI() {
+    QVBoxLayout* main_layout = new QVBoxLayout(this);
+    main_layout->addSpacing(10);
+
+    // Selector button
+    QWidget* model_selector_btn_widget = new QWidget;
+    QHBoxLayout* model_selector_btn_layout = new QHBoxLayout();
+    QLabel* vehicle_model_label = new QLabel(tr("Vehicle Model:"));
+    vehicle_model_label->setStyleSheet("margin-right: 2px; font-size: 48px;");
+    model_selector_btn_layout->addWidget(vehicle_model_label);
+
+    QString model_selected = QString::fromUtf8(Params().get("dp_device_model_selected").c_str());
+    model_selector_btn = new QPushButton(model_selected.isEmpty() ? tr("[AUTO DETECT]") : model_selected);
+    model_selector_btn->setObjectName("ModelSelectorBtn");
+    model_selector_btn->setStyleSheet(SELECTOR_BTN_STYLE);
+    model_selector_btn_layout->addWidget(model_selector_btn);
+    model_selector_btn_layout->setAlignment(Qt::AlignCenter);
+    model_selector_btn_layout->setStretch(1, 1);
+
+    model_selector_btn_widget->setLayout(model_selector_btn_layout);
+    main_layout->addWidget(model_selector_btn_widget);
+    main_layout->addSpacing(10);
+    main_layout->addStretch(); // Add stretch to push everything to the top
+
+    setLayout(main_layout);
+    return model_selector_btn_widget;
+}
+
+void ModelSelector::setupModelListPanel() {
+    // Create model list panel
+    model_list_panel = new QWidget();
+    QVBoxLayout* model_list_layout = new QVBoxLayout(model_list_panel);
+    model_list_layout->setContentsMargins(50, 25, 50, 25);
+
+    model_list = new QListWidget(model_list_panel);
+
+    // Set styles using the constants
+    QString listStyle = QString("QListWidget { %1 } QScrollBar:vertical { %2 }")
+                        .arg(MODEL_LIST_STYLE)
+                        .arg(SCROLLBAR_STYLE);
+    model_list->setStyleSheet(listStyle);
+
+    model_list->setFixedHeight(750);
+    model_list_layout->addWidget(model_list);
+
+    model_list_frame = new ScrollView(model_list_panel, nullptr);
+}
+
+void ModelSelector::loadModelList() {
+    if (model_list->count() > 0) {
+        // If list is already populated, just update the selection
+        updateCurrentSelection();
+        return;
+    }
+
+    // Add auto-detect option
+    QListWidgetItem* autoDetectItem = new QListWidgetItem(tr("[AUTO DETECT]"));
+    autoDetectItem->setData(ModelNameRole, tr("[AUTO DETECT]"));
+    model_list->addItem(autoDetectItem);
+
+    Params params;
+    QString model_list_str = QString::fromStdString(params.get("dp_device_model_list"));
+
+    QJsonDocument document = QJsonDocument::fromJson(model_list_str.toUtf8());
+    if (document.isArray()) {
+        QJsonArray models = document.array();
+
+        for (const auto& groupValue : models) {
+            QJsonObject group = groupValue.toObject();
+            QString groupName = group["group"].toString();
+
+            // Add group header item
+            QListWidgetItem* groupHeader = new QListWidgetItem(groupName);
+            groupHeader->setFlags(Qt::NoItemFlags); // Make non-selectable
+            groupHeader->setBackground(QColor(GROUP_HEADER_BG_COLOR));
+            groupHeader->setForeground(QColor(GROUP_HEADER_TEXT_COLOR));
+            groupHeader->setTextAlignment(Qt::AlignCenter);
+            model_list->addItem(groupHeader);
+
+            // Add models in this group
+            QJsonArray groupModels = group["models"].toArray();
+            for (const auto& model : groupModels) {
+                QString modelName = model.toString();
+                // Create item with visual indentation
+                QListWidgetItem* modelItem = new QListWidgetItem("  " + modelName);
+                // Store actual model name without indentation in user role
+                modelItem->setData(ModelNameRole, modelName);
+                model_list->addItem(modelItem);
+            }
+        }
+    }
+
+    // Set the current selection after loading
+    updateCurrentSelection();
+}
+
+// New helper method to update the selection
+void ModelSelector::updateCurrentSelection() {
+    // Get the currently selected model from params
+    Params params;
+    QString currentModel = QString::fromStdString(params.get("dp_device_model_selected"));
+
+    // If empty, select the AUTO DETECT option
+    if (currentModel.isEmpty()) {
+        model_list->setCurrentRow(0); // AUTO DETECT is the first item
+        return;
+    }
+
+    // Otherwise, find and select the matching model
+    for (int i = 0; i < model_list->count(); i++) {
+        QListWidgetItem* item = model_list->item(i);
+        // Only check selectable items (not group headers)
+        if (item->flags() & Qt::ItemIsSelectable) {
+            QString modelName = item->data(ModelNameRole).toString();
+            if (modelName == currentModel) {
+                model_list->setCurrentItem(item);
+                break;
+            }
+        }
+    }
+}
+
+void ModelSelector::clearModelList() {
+    model_list->clear();
+}
+
+void ModelSelector::updateButtonText(const QString& text) {
+    model_selector_btn->setText(text);
+}
+
+QWidget* ModelSelector::getModelListPanel() {
+    return model_list_frame;
+}
+
+void ModelSelector::setPanelWidget(QStackedWidget* panel) {
+    panel_widget = panel;
+    if (panel_widget && model_list_frame->parent() != panel_widget) {
+        model_list_frame->setParent(panel_widget);
+        panel_widget->addWidget(model_list_frame);
+    }
+}
+
+void ModelSelector::setNavButtonGroup(QButtonGroup* buttons) {
+    nav_btns = buttons;
+}
+
+void ModelSelector::connectSignals() {
+    connect(model_selector_btn, &QPushButton::clicked, [this]() {
+        if (panel_widget) {
+            // Load the model list when needed
+            loadModelList();
+            panel_widget->setCurrentWidget(model_list_frame);
+        }
+        emit buttonClicked();
+    });
+
+    connect(model_list, &QListWidget::itemClicked, [this](QListWidgetItem* item) {
+        // Only process clicks on selectable items (not group headers)
+        if (item->flags() & Qt::ItemIsSelectable) {
+            // Get model name from the data role rather than trimming text
+            QString model_name = item->data(ModelNameRole).toString();
+            QString param_value = (model_name == tr("[AUTO DETECT]")) ? QString() : model_name;
+
+            // Update param and button text
+            Params().put("dp_device_model_selected", param_value.toStdString());
+            updateButtonText(param_value.isEmpty() ? tr("[AUTO DETECT]") : model_name);
+
+            // Emit signal that model was selected
+            emit modelSelected(model_name);
+
+            // Go back to the previous panel
+            if (nav_btns && nav_btns->checkedButton()) {
+                nav_btns->checkedButton()->click();
+            } else if (nav_btns && nav_btns->buttons().size() > 0) {
+                // Default to first panel if none selected
+                nav_btns->buttons().first()->click();
+            }
+        }
+    });
+
+    if (model_list_frame) {
+        model_list_frame->installEventFilter(this);
+    }
+}
+
+
+bool ModelSelector::eventFilter(QObject *obj, QEvent *event) {
+    if (obj == model_list_frame) {
+        if (event->type() == QEvent::Hide) {
+            clearModelList();
+        }
+    }
+    return QWidget::eventFilter(obj, event);
+}
diff --git a/selfdrive/ui/qt/offroad/model_selector.h b/selfdrive/ui/qt/offroad/model_selector.h
new file mode 100644
index 000000000..dcc0eb2a2
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/model_selector.h
@@ -0,0 +1,73 @@
+/*
+Copyright (c) 2025 Rick Lan
+
+This software is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0).
+You are free to share and adapt this work for non-commercial purposes, provided you give appropriate credit and distribute any modifications under the same license.
+
+To view a copy of this license, visit:
+http://creativecommons.org/licenses/by-nc-sa/4.0/
+
+---
+
+**Commercial Licensing:**
+Use of this software for commercial purposes is strictly prohibited without a separate, paid license.
+To purchase a commercial license, please contact ricklan@gmail.com.
+*/
+
+#pragma once
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include   // Add this include for QButtonGroup
+#include 
+#include "common/params.h"
+#include "selfdrive/ui/qt/widgets/scrollview.h"
+
+class ModelSelector : public QWidget {
+    Q_OBJECT
+
+public:
+    explicit ModelSelector(QWidget *parent = nullptr);
+
+    // Get the model list panel widget
+    QWidget* getModelListPanel();
+
+    // Set the panel widget to switch to when selecting models
+    void setPanelWidget(QStackedWidget* panel);
+
+    // Set the button group to return to after model selection
+    void setNavButtonGroup(QButtonGroup* nav_btns);
+
+signals:
+    void buttonClicked();
+    void modelSelected(const QString& model_name);
+
+private:
+    QPushButton* model_selector_btn;
+    QListWidget* model_list;
+    QWidget* model_list_panel;
+    ScrollView* model_list_frame;
+    QStackedWidget* panel_widget = nullptr;
+    QButtonGroup* nav_btns = nullptr;
+
+    QWidget* setupUI();
+    void setupModelListPanel();
+    void loadModelList();
+    void updateCurrentSelection();
+    void clearModelList();
+    void connectSignals();
+    void updateButtonText(const QString& text);
+
+protected:
+    bool eventFilter(QObject *obj, QEvent *event) override;
+};
diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc
index 7f37241de..fbaf83711 100644
--- a/selfdrive/ui/qt/offroad/settings.cc
+++ b/selfdrive/ui/qt/offroad/settings.cc
@@ -16,6 +16,7 @@
 #include "selfdrive/ui/qt/offroad/developer_panel.h"
 #include "selfdrive/ui/qt/offroad/firehose.h"
 #include "selfdrive/ui/qt/offroad/dp_panel.h"
+#include "selfdrive/ui/qt/offroad/model_selector.h"
 
 TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
   // param, title, desc, icon, restart needed
@@ -103,8 +104,11 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
 
   // set up uiState update for personality setting
   QObject::connect(uiState(), &UIState::uiUpdate, this, &TogglesPanel::updateState);
-
+  const bool lite = getenv("LITE");
   for (auto &[param, title, desc, icon, needs_restart] : toggle_defs) {
+    if ((param == "AlwaysOnDM" || param == "RecordFront" || param == "RecordAudio" || param == "RecordAudioFeedback") && lite) {
+      continue;
+    }
     auto toggle = new ParamControl(param, title, desc, icon, this);
 
     bool locked = params.getBool((param + "Lock").toStdString());
@@ -223,6 +227,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
   addItem(new LabelControl(tr("Dongle ID"), getDongleId().value_or(tr("N/A"))));
   addItem(new LabelControl(tr("Serial"), params.get("HardwareSerial").c_str()));
 
+  const bool lite = getenv("LITE");
   pair_device = new ButtonControl(tr("Pair Device"), tr("PAIR"),
                                   tr("Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer."));
   connect(pair_device, &ButtonControl::clicked, [=]() {
@@ -232,12 +237,12 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
   addItem(pair_device);
 
   // offroad-only buttons
-
+  if (!lite) {
   auto dcamBtn = new ButtonControl(tr("Driver Camera"), tr("PREVIEW"),
                                    tr("Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off)"));
   connect(dcamBtn, &ButtonControl::clicked, [=]() { emit showDriverView(); });
   addItem(dcamBtn);
-
+  }
   resetCalibBtn = new ButtonControl(tr("Reset Calibration"), tr("RESET"), "");
   connect(resetCalibBtn, &ButtonControl::showDescriptionEvent, this, &DevicePanel::updateCalibDescription);
   connect(resetCalibBtn, &ButtonControl::clicked, [&]() {
@@ -535,7 +540,26 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
 
   sidebar_widget->setFixedWidth(500);
   main_layout->addWidget(sidebar_widget);
-  main_layout->addWidget(panel_widget);
+
+  // Create right column with model selector on top and panel_widget below
+  QWidget* right_column = new QWidget(this);
+  QVBoxLayout* right_layout = new QVBoxLayout(right_column);
+  right_layout->setContentsMargins(0, 0, 0, 0);
+  right_layout->setSpacing(20); // Space between model selector and panel
+
+  // Create the ModelSelector button at the top of right column
+  ModelSelector* model_selector = new ModelSelector(this);
+  right_layout->addWidget(model_selector);
+
+  // Set up panel widget and nav button references
+  model_selector->setPanelWidget(panel_widget);
+  model_selector->setNavButtonGroup(nav_btns);
+
+  // Add panel_widget below the model selector
+  right_layout->addWidget(panel_widget, 1); // Give panel_widget stretch priority
+
+  // Add right column to main layout
+  main_layout->addWidget(right_column);
 
   setStyleSheet(R"(
     * {
diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h
index d52cf16bb..3a65b198d 100644
--- a/selfdrive/ui/qt/offroad/settings.h
+++ b/selfdrive/ui/qt/offroad/settings.h
@@ -95,6 +95,7 @@ private:
   QLabel *onroadLbl;
   LabelControl *versionLbl;
   ButtonControl *installBtn;
+  ButtonControl *onOffRoadBtn;
   ButtonControl *downloadBtn;
   ButtonControl *targetBranchBtn;
 
diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc
index 43358ad72..e2a333068 100644
--- a/selfdrive/ui/qt/offroad/software_settings.cc
+++ b/selfdrive/ui/qt/offroad/software_settings.cc
@@ -29,6 +29,16 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
   versionLbl = new LabelControl(tr("Current Version"), "");
   addItem(versionLbl);
 
+  // on/off road mode switch
+  onOffRoadBtn = new ButtonControl(tr("Onroad/Offroad Mode"), tr("Go Offroad"));
+  connect(onOffRoadBtn, &ButtonControl::clicked, [&]() {
+    if (ConfirmationDialog::confirm(tr("Are you sure you want to switch mode?"), tr("CONFIRM"), this)) {
+      bool val = params.getBool("dp_device_go_off_road");
+      params.putBool("dp_device_go_off_road", !val);
+    }
+  });
+  addItem(onOffRoadBtn);
+
   // download update btn
   downloadBtn = new ButtonControl(tr("Download"), tr("CHECK"));
   connect(downloadBtn, &ButtonControl::clicked, [=]() {
@@ -111,6 +121,7 @@ void SoftwarePanel::updateLabels() {
   fs_watch->addParam("UpdateFailedCount");
   fs_watch->addParam("UpdaterState");
   fs_watch->addParam("UpdateAvailable");
+  fs_watch->addParam("dp_device_go_off_road");
 
   if (!isVisible()) {
     return;
@@ -120,6 +131,13 @@ void SoftwarePanel::updateLabels() {
   onroadLbl->setVisible(is_onroad);
   downloadBtn->setVisible(!is_onroad);
 
+  // on/off road text change
+  if (params.getBool("dp_device_go_off_road")) {
+    onOffRoadBtn->setText(tr("Go Onroad"));
+  } else {
+    onOffRoadBtn->setText(tr("Go Offroad"));
+  }
+
   // download update
   QString updater_state = QString::fromStdString(params.get("UpdaterState"));
   bool failed = std::atoi(params.get("UpdateFailedCount").c_str()) > 0;
diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc
index f504ad69f..408fbd73d 100644
--- a/selfdrive/ui/qt/onroad/annotated_camera.cc
+++ b/selfdrive/ui/qt/onroad/annotated_camera.cc
@@ -24,7 +24,9 @@ AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget *par
 void AnnotatedCameraWidget::updateState(const UIState &s) {
   // update engageability/experimental mode button
   experimental_btn->updateState(s);
-  dmon.updateState(s);
+  if (!s.scene.lite) {
+    dmon.updateState(s);
+  }
 }
 
 void AnnotatedCameraWidget::initializeGL() {
@@ -130,9 +132,17 @@ void AnnotatedCameraWidget::paintGL() {
   painter.setPen(Qt::NoPen);
 
   model.draw(painter, rect());
-  dmon.draw(painter, rect());
-  hud.updateState(*s);
-  hud.draw(painter, rect());
+  bool hide_hud = s->scene.dp_ui_hide_hud_speed_kph > 0 && sm["carState"].getCarState().getVEgo() > s->scene.dp_ui_hide_hud_speed_kph * 0.278;
+  if (!hide_hud) {
+    if (!s->scene.lite) {
+      dmon.draw(painter, rect());
+    }
+    hud.updateState(*s);
+    hud.draw(painter, rect());
+    experimental_btn->setVisible(true);
+  } else {
+    experimental_btn->setVisible(false);
+  }
 
   double cur_draw_t = millis_since_boot();
   double dt = cur_draw_t - prev_draw_t;
diff --git a/selfdrive/ui/qt/onroad/model.cc b/selfdrive/ui/qt/onroad/model.cc
index 52902abdc..d012aeda9 100644
--- a/selfdrive/ui/qt/onroad/model.cc
+++ b/selfdrive/ui/qt/onroad/model.cc
@@ -48,6 +48,11 @@ void ModelRenderer::draw(QPainter &painter, const QRect &surface_rect) {
     }
   }
 
+  if (s->scene.dp_ui_radar_tracks) {
+    const auto &live_tracks = sm["liveTracks"].getLiveTracks();
+    drawLiveTracks(painter, live_tracks, model, surface_rect);
+  }
+
   painter.restore();
 }
 
@@ -107,7 +112,39 @@ void ModelRenderer::drawLaneLines(QPainter &painter) {
 
 void ModelRenderer::drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height) {
   QLinearGradient bg(0, height, 0, 0);
-  if (experimental_mode) {
+
+  auto *s = uiState();
+  if (s->scene.dp_ui_rainbow) {
+    constexpr int NUM_COLORS = 25;
+    constexpr int ALPHA = 128;
+
+    float v_ego = (*uiState()->sm)["carState"].getCarState().getVEgo();
+
+    if (!dp_rainbow_init) {
+      dp_rainbow_color_list.reserve(NUM_COLORS);
+      for (int i = 0; i < NUM_COLORS; ++i) {
+        qreal t = static_cast(i) / (NUM_COLORS - 1);
+        dp_rainbow_color_list.append(QColor::fromHsvF(t, 1.0, 1.0, ALPHA / 255.0));
+      }
+      dp_rainbow_init = true;
+    }
+    bg.setSpread(QGradient::RepeatSpread);
+    // bigger = faster, however it is still limited to the global UI_FREQ (refresh rate)
+    // only way to make it move faster is to reduce NUM_COLORS, but that will also reduce the color smoothness.
+    qreal rotation_speed = std::max(0.01f, v_ego) / UI_FREQ;
+    dp_rainbow_rotation -= rotation_speed;
+
+    if (dp_rainbow_rotation < 0.0) {
+      dp_rainbow_rotation += 1.0;
+      dp_rainbow_color_list.append(dp_rainbow_color_list.takeFirst());
+    }
+    // fill color
+    const qreal step = 1.0 / (NUM_COLORS - 1);
+    for (int i = 0; i < NUM_COLORS; ++i) {
+      bg.setColorAt(i * step, dp_rainbow_color_list.at(i));
+    }
+
+  } else if (experimental_mode) {
     // The first half of track_vertices are the points for the right side of the path
     const auto &acceleration = model.getAcceleration().getX();
     const int max_len = std::min(track_vertices.length() / 2, acceleration.size());
@@ -186,6 +223,56 @@ QColor ModelRenderer::blendColors(const QColor &start, const QColor &end, float
       (1 - t) * start.alphaF() + t * end.alphaF());
 }
 
+void ModelRenderer::drawLiveTracks(QPainter &painter,
+  const cereal::RadarData::Reader &live_tracks,
+  const cereal::ModelDataV2::Reader &model_data,
+  const QRect &surface_rect) {
+
+  // Get the model's predicted path for Z-coordinate calculation
+  const auto& model_path_position = model_data.getPosition();
+
+  // Set text properties
+  painter.setPen(Qt::white);
+  painter.setFont(QFont("Inter", 24, QFont::Bold));
+
+  // Iterate through each radar point from live_tracks
+  for (const auto& point : live_tracks.getPoints()) {
+    float dRel = point.getDRel();
+    float yRel = point.getYRel();
+    float yvRel = point.getYvRel();
+    float vRel = point.getVRel();
+
+    // Calculate Z-coordinate using the model's path
+    float z_on_path = path_offset_z; // Default base offset
+
+    // Ensure dRel is non-negative for indexing
+    if (dRel >= 0) {
+      z_on_path += model_path_position.getZ()[get_path_length_idx(model_path_position, dRel)];
+    }
+
+    QPointF screen_pos;
+    // mapToScreen projects a point from car space to screen space
+    if (mapToScreen(dRel, -yRel, z_on_path, &screen_pos)) { // yRel is negated as in update_leads
+      // Basic drawing: Draw a small circle for the point
+      painter.setBrush(QColor(255, 0, 0, 200)); // Cyan color for live tracks
+      painter.drawEllipse(screen_pos, 10, 10); // Draw a small circle of radius 5
+
+      // Prepare text to display
+      QString infoText = QString("ID: %1\nd: %2 m\ny: %3 m\ndV: %4 m/s\nyV: %5 m/s")
+                           .arg(point.getTrackId())
+                           .arg(dRel, 0, 'f', 2)
+                           .arg(yRel, 0, 'f', 2)
+                           .arg(vRel, 0, 'f', 2)
+                           .arg(yvRel, 0, 'f', 2);
+
+      // Draw text near the point
+      // Adjust text position for better visibility (e.g., slightly offset from the point)
+      QRectF textRect(screen_pos.x() + 10, screen_pos.y() - 20, 250, 250); // Adjust size as needed
+      painter.drawText(textRect, Qt::AlignLeft, infoText);
+    }
+  }
+}
+
 void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data,
                              const QPointF &vd, const QRect &surface_rect) {
   const float speedBuff = 10.;
diff --git a/selfdrive/ui/qt/onroad/model.h b/selfdrive/ui/qt/onroad/model.h
index 79547e4b8..944e1fed7 100644
--- a/selfdrive/ui/qt/onroad/model.h
+++ b/selfdrive/ui/qt/onroad/model.h
@@ -15,6 +15,7 @@ private:
   bool mapToScreen(float in_x, float in_y, float in_z, QPointF *out);
   void mapLineToPolygon(const cereal::XYZTData::Reader &line, float y_off, float z_off,
                         QPolygonF *pvd, int max_idx, bool allow_invert = true);
+  void drawLiveTracks(QPainter &painter, const cereal::RadarData::Reader &live_tracks, const cereal::ModelDataV2::Reader &model_data, const QRect &surface_rect);
   void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, const QRect &surface_rect);
   void update_leads(const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line);
   void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead);
@@ -36,4 +37,7 @@ private:
   QPointF lead_vertices[2] = {};
   Eigen::Matrix3f car_space_transform = Eigen::Matrix3f::Zero();
   QRectF clip_region;
+  QVector dp_rainbow_color_list;
+  qreal dp_rainbow_rotation = 0;
+  bool dp_rainbow_init = false;
 };
diff --git a/selfdrive/ui/qt/onroad/onroad_home.cc b/selfdrive/ui/qt/onroad/onroad_home.cc
index 080f9bd50..6e606d1f4 100644
--- a/selfdrive/ui/qt/onroad/onroad_home.cc
+++ b/selfdrive/ui/qt/onroad/onroad_home.cc
@@ -39,16 +39,48 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
   QObject::connect(uiState(), &UIState::offroadTransition, this, &OnroadWindow::offroadTransition);
 }
 
+void OnroadWindow::updateDpIndicatorSideState(bool blinker_state, bool bsm_state, bool &show, bool &show_prev, int &count, QColor &color) {
+  if (!blinker_state && !bsm_state) {
+    show = false;
+    count = 0;
+  } else {
+    count += 1;
+  }
+  if (bsm_state && blinker_state) {
+    show = count % DP_INDICATOR_BLINK_RATE_FAST == 0? !show : show;
+    color = DP_INDICATOR_COLOR_BSM;
+  } else if (blinker_state) {
+    show = count % DP_INDICATOR_BLINK_RATE_STD == 0? !show : show;
+    color = DP_INDICATOR_COLOR_BLINKER;
+  } else if (bsm_state) {
+    show = true;
+    color = DP_INDICATOR_COLOR_BSM;
+  } else {
+    show = false;
+  }
+}
+
+void OnroadWindow::updateDpIndicatorStates(const UIState &s) {
+  const auto cs = (*s.sm)["carState"].getCarState();
+  updateDpIndicatorSideState(cs.getLeftBlinker(), cs.getLeftBlindspot(), dp_indicator_show_left, dp_indicator_show_left_prev, dp_indicator_count_left, dp_indicator_color_left);
+  updateDpIndicatorSideState(cs.getRightBlinker(), cs.getRightBlindspot(), dp_indicator_show_right, dp_indicator_show_right_prev, dp_indicator_count_right, dp_indicator_color_right);
+}
+
 void OnroadWindow::updateState(const UIState &s) {
   if (!s.scene.started) {
     return;
   }
 
+  dp_indicator_show_left_prev = dp_indicator_show_left;
+  dp_indicator_show_right_prev = dp_indicator_show_right;
+  updateDpIndicatorStates(s);
+  bool indicator_states_changed = dp_indicator_show_left != dp_indicator_show_left_prev || dp_indicator_show_right != dp_indicator_show_right_prev;
+
   alerts->updateState(s);
   nvg->updateState(s);
 
-  QColor bgColor = bg_colors[s.status];
-  if (bg != bgColor) {
+  QColor bgColor = bg_colors[s.scene.alka_active && s.status == STATUS_DISENGAGED? STATUS_ALKA : s.status];
+  if (bg != bgColor || indicator_states_changed) {
     // repaint border
     bg = bgColor;
     update();
@@ -61,5 +93,7 @@ void OnroadWindow::offroadTransition(bool offroad) {
 
 void OnroadWindow::paintEvent(QPaintEvent *event) {
   QPainter p(this);
-  p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 255));
+  p.fillRect(rect(), QColor(bg.red(), bg.green(), bg.blue(), 180));
+  if (dp_indicator_show_left) p.fillRect(QRect(0, 0, width() * 0.2, height()), dp_indicator_color_left);
+  if (dp_indicator_show_right) p.fillRect(QRect(width() * 0.8, 0, width() * 0.2, height()), dp_indicator_color_right);
 }
diff --git a/selfdrive/ui/qt/onroad/onroad_home.h b/selfdrive/ui/qt/onroad/onroad_home.h
index c321d2d44..dc4eb81b3 100644
--- a/selfdrive/ui/qt/onroad/onroad_home.h
+++ b/selfdrive/ui/qt/onroad/onroad_home.h
@@ -1,11 +1,18 @@
 #pragma once
 
+#include 
+
 #include "selfdrive/ui/qt/onroad/alerts.h"
 #include "selfdrive/ui/qt/onroad/annotated_camera.h"
 
 class OnroadWindow : public QWidget {
   Q_OBJECT
 
+  const int DP_INDICATOR_BLINK_RATE_STD = 8;
+  const int DP_INDICATOR_BLINK_RATE_FAST = 4;
+  const QColor DP_INDICATOR_COLOR_BLINKER = QColor(0, 0xff, 0, 255);
+  const QColor DP_INDICATOR_COLOR_BSM = QColor(0xff, 0xff, 0, 255);
+
 public:
   OnroadWindow(QWidget* parent = 0);
 
@@ -16,6 +23,19 @@ private:
   QColor bg = bg_colors[STATUS_DISENGAGED];
   QHBoxLayout* split;
 
+  void updateDpIndicatorSideState(bool blinker_state, bool bsm_state, bool &show, bool &show_prev, int &count, QColor &color);
+  void updateDpIndicatorStates(const UIState &s);
+  // left
+  int dp_indicator_count_left = 0;
+  QColor dp_indicator_color_left = DP_INDICATOR_COLOR_BLINKER;
+  bool dp_indicator_show_left = false;
+  bool dp_indicator_show_left_prev = false;
+  // right
+  int dp_indicator_count_right = 0;
+  QColor dp_indicator_color_right = DP_INDICATOR_COLOR_BLINKER;
+  bool dp_indicator_show_right = false;
+  bool dp_indicator_show_right_prev = false;
+
 private slots:
   void offroadTransition(bool offroad);
   void updateState(const UIState &s);
diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc
index 0a55b00f7..02dfd299b 100644
--- a/selfdrive/ui/qt/util.cc
+++ b/selfdrive/ui/qt/util.cc
@@ -27,7 +27,8 @@ QString getVersion() {
 }
 
 QString getBrand() {
-  return QObject::tr("dragonpilot");
+  const bool lite = getenv("LITE");
+  return QObject::tr("dragonpilot") + (lite ? QString::fromStdString(" - Lite") : QString(""));
 }
 
 QString getUserAgent() {
diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py
index 13f3b2209..53a256ffc 100644
--- a/selfdrive/ui/soundd.py
+++ b/selfdrive/ui/soundd.py
@@ -10,6 +10,7 @@ from openpilot.common.filter_simple import FirstOrderFilter
 from openpilot.common.realtime import Ratekeeper
 from openpilot.common.retry import retry
 from openpilot.common.swaglog import cloudlog
+from openpilot.common.params import Params
 
 from openpilot.system import micd
 
@@ -62,6 +63,11 @@ class Soundd:
 
     self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False)
 
+    try:
+      self._dp_device_audible_alert_mode = int(Params().get("dp_device_audible_alert_mode"))
+    except:
+      self._dp_device_audible_alert_mode = 0
+
   def load_sounds(self):
     self.loaded_sounds: dict[int, np.ndarray] = {}
 
@@ -96,6 +102,10 @@ class Soundd:
         written_frames += frames_to_write
         self.current_sound_frame += frames_to_write
 
+      # dp - set vol to 0 instead
+      if self._dp_device_audible_alert_mode == 2 or (self._dp_device_audible_alert_mode == 1 and self.current_alert in [AudibleAlert.engage, AudibleAlert.disengage]):
+        self.current_volume = 0
+
     return ret * self.current_volume
 
   def callback(self, data_out: np.ndarray, frames: int, time, status) -> None:
diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc
index 4f8bd7ddf..084d89aaa 100644
--- a/selfdrive/ui/ui.cc
+++ b/selfdrive/ui/ui.cc
@@ -60,6 +60,7 @@ static void update_state(UIState *s) {
     scene.light_sensor = -1;
   }
   scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition;
+  scene.alka_active = sm["dpControlsState"].getDpControlsState().getAlkaActive();
 
   auto params = Params();
   scene.recording_audio = params.getBool("RecordAudio") && scene.started;
@@ -68,6 +69,11 @@ static void update_state(UIState *s) {
 void ui_update_params(UIState *s) {
   auto params = Params();
   s->scene.is_metric = params.getBool("IsMetric");
+  s->scene.lite = getenv("LITE");
+  s->scene.display_mode = std::atoi(params.get("dp_ui_display_mode").c_str());
+  s->scene.dp_ui_hide_hud_speed_kph = std::atoi(params.get("dp_ui_hide_hud_speed_kph").c_str());
+  s->scene.dp_ui_rainbow = params.getBool("dp_ui_rainbow");
+  s->scene.dp_ui_radar_tracks = params.getBool("dp_ui_radar_tracks");
 }
 
 void UIState::updateStatus() {
@@ -102,6 +108,8 @@ UIState::UIState(QObject *parent) : QObject(parent) {
     "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState",
     "pandaStates", "carParams", "driverMonitoringState", "carState", "driverStateV2",
     "wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan",
+    "dpControlsState",
+    "liveTracks",
   });
   prime_state = new PrimeState(this);
   language = QString::fromStdString(Params().get("LanguageSetting"));
@@ -180,6 +188,62 @@ void Device::updateBrightness(const UIState &s) {
   }
 }
 
+// Display Mode
+// 0 Std. - Stock behavior.
+// 1 MAIN+ - ACC MAIN on = Display ON
+// 2 OP+ - OP enabled = Display ON
+// 3 MAIN- - ACC MAIN on = Display OFF
+// 4 OP- - OP enabled = Display OFF
+bool Device::applyDisplayMode(const UIState &s, int timeout) {
+  // standard
+  if (s.scene.display_mode == 0 || !s.scene.ignition) {
+    return (s.scene.ignition || timeout > 0);
+  }
+
+  bool cruise_available = false;
+  bool cruise_enabled = false;
+
+  auto &sm = *(s.sm);
+  if (sm.updated("carState")) {
+    auto cs = sm["carState"].getCarState().getCruiseState();
+    cruise_available = cs.getAvailable();
+    cruise_enabled = cs.getEnabled();
+  }
+
+  if (sm["selfdriveState"].getSelfdriveState().getAlertSize() != cereal::SelfdriveState::AlertSize::NONE) {
+    resetInteractiveTimeout(5);
+    return true;
+  }
+
+  // 1 MAIN+ - ACC MAIN on = Display ON
+  if (s.scene.display_mode == 1 && cruise_available) {
+    return s.scene.ignition;
+  }
+
+  // 2 OP+ - OP enabled = Display ON
+  if (s.scene.display_mode == 2 && cruise_enabled) {
+    return s.scene.ignition;
+  }
+
+  // 3 MAIN- - ACC MAIN on = Display OFF
+  if (s.scene.display_mode == 3 && cruise_available) {
+    return false;
+  }
+
+  // 4 OP- - OP enabled = Display OFF
+  if (s.scene.display_mode == 4 && cruise_enabled) {
+    return false;
+  }
+
+  if (s.scene.display_mode >= 3) {
+    // 3,4
+    return s.scene.ignition;
+  } else {
+    // 1,2
+    return false;
+  }
+}
+
 void Device::updateWakefulness(const UIState &s) {
   bool ignition_just_turned_off = !s.scene.ignition && ignition_on;
   ignition_on = s.scene.ignition;
@@ -190,7 +254,7 @@ void Device::updateWakefulness(const UIState &s) {
     emit interactiveTimeout();
   }
 
-  setAwake(s.scene.ignition || interactive_timeout > 0);
+  setAwake(applyDisplayMode(s, interactive_timeout));
 }
 
 UIState *uiState() {
diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h
index b3c482aaf..2fb0d87ce 100644
--- a/selfdrive/ui/ui.h
+++ b/selfdrive/ui/ui.h
@@ -42,12 +42,14 @@ typedef enum UIStatus {
   STATUS_DISENGAGED,
   STATUS_OVERRIDE,
   STATUS_ENGAGED,
+  STATUS_ALKA,
 } UIStatus;
 
 const QColor bg_colors [] = {
   [STATUS_DISENGAGED] = QColor(0x17, 0x33, 0x49, 0xc8),
   [STATUS_OVERRIDE] = QColor(0x91, 0x9b, 0x95, 0xf1),
   [STATUS_ENGAGED] = QColor(0x17, 0x86, 0x44, 0xf1),
+  [STATUS_ALKA] = QColor(0x22, 0xa0, 0xdc, 0xf1),
 };
 
 typedef struct UIScene {
@@ -60,6 +62,12 @@ typedef struct UIScene {
   float light_sensor = -1;
   bool started, ignition, is_metric, recording_audio;
   uint64_t started_frame;
+  bool lite = false;
+  bool alka_active = false;
+  int display_mode = 0;
+  int dp_ui_hide_hud_speed_kph = 0;
+  bool dp_ui_rainbow = false;
+  bool dp_ui_radar_tracks = false;
 } UIScene;
 
 class UIState : public QObject {
@@ -115,6 +123,7 @@ private:
   FirstOrderFilter brightness_filter;
   QFuture brightness_future;
 
+  bool applyDisplayMode(const UIState &s, int timeout);
   void updateBrightness(const UIState &s);
   void updateWakefulness(const UIState &s);
   void setAwake(bool on);
diff --git a/system/athena/registration.py b/system/athena/registration.py
index 80c087188..eace25313 100755
--- a/system/athena/registration.py
+++ b/system/athena/registration.py
@@ -12,6 +12,7 @@ from openpilot.selfdrive.selfdrived.alertmanager import set_offroad_alert
 from openpilot.system.hardware import HARDWARE, PC
 from openpilot.system.hardware.hw import Paths
 from openpilot.common.swaglog import cloudlog
+import os
 
 
 UNREGISTERED_DONGLE_ID = "UnregisteredDevice"
@@ -48,6 +49,9 @@ def register(show_spinner=False) -> str | None:
       spinner = Spinner()
       spinner.update("registering device")
 
+    if os.getenv("LITE"):
+      params.put("DongleId", UNREGISTERED_DONGLE_ID)
+      return dongle_id
     # Create registration token, in the future, this key will make JWTs directly
     with open(Paths.persist_root()+"/comma/id_rsa.pub") as f1, open(Paths.persist_root()+"/comma/id_rsa") as f2:
       public_key = f1.read()
@@ -74,7 +78,7 @@ def register(show_spinner=False) -> str | None:
       try:
         register_token = jwt.encode({'register': True, 'exp': datetime.now(UTC).replace(tzinfo=None) + timedelta(hours=1)}, private_key, algorithm='RS256')
         cloudlog.info("getting pilotauth")
-        resp = api_get("v2/pilotauth/", method='POST', timeout=15,
+        resp = api_get("v2/pilotauth/", method='POST', timeout=5,
                        imei=imei1, imei2=imei2, serial=serial, public_key=public_key, register_token=register_token)
 
         if resp.status_code in (402, 403):
diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc
index 8c4602bb3..d6ace8d76 100644
--- a/system/camerad/cameras/camera_qcom2.cc
+++ b/system/camerad/cameras/camera_qcom2.cc
@@ -270,6 +270,7 @@ void camerad_thread() {
   // *** per-cam init ***
   std::vector> cams;
   for (const auto &config : ALL_CAMERA_CONFIGS) {
+    if (!config.enabled) continue;
     auto cam = std::make_unique(&m, config);
     cam->init(&v, device_id, ctx);
     cams.emplace_back(std::move(cam));
diff --git a/system/camerad/cameras/hw.h b/system/camerad/cameras/hw.h
index d299627ce..c8cabf734 100644
--- a/system/camerad/cameras/hw.h
+++ b/system/camerad/cameras/hw.h
@@ -59,7 +59,7 @@ const CameraConfig DRIVER_CAMERA_CONFIG = {
   .focal_len = 1.71,
   .publish_name = "driverCameraState",
   .init_camera_state = &cereal::Event::Builder::initDriverCameraState,
-  .enabled = !getenv("DISABLE_DRIVER"),
+  .enabled = (!getenv("DISABLE_DRIVER") && !getenv("LITE")),
   .phy = CAM_ISP_IFE_IN_RES_PHY_2,
   .vignetting_correction = false,
   .output_type = ISP_BPS_PROCESSED,
diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py
index fad93601d..2c831684b 100755
--- a/system/hardware/hardwared.py
+++ b/system/hardware/hardwared.py
@@ -210,6 +210,8 @@ def hardware_thread(end_event, hw_queue) -> None:
 
   fan_controller = None
 
+  dp_device_go_off_road = False
+
   while not end_event.is_set():
     sm.update(PANDA_STATES_TIMEOUT)
 
@@ -335,13 +337,15 @@ def hardware_thread(end_event, hw_queue) -> None:
       startup_conditions["registered_device"] = PC or (params.get("DongleId") != UNREGISTERED_DONGLE_ID)
 
     # TODO: this should move to TICI.initialize_hardware, but we currently can't import params there
-    if TICI and HARDWARE.get_device_type() == "tici":
+    if TICI and HARDWARE.get_device_type() == "tici" and not os.getenv("LITE"):
       if not os.path.isfile("/persist/comma/living-in-the-moment"):
         if not Path("/data/media").is_mount():
           set_offroad_alert_if_changed("Offroad_StorageMissing", True)
 
     # Handle offroad/onroad transition
-    should_start = all(onroad_conditions.values())
+    if count % 6 == 0:
+      dp_device_go_off_road = params.get_bool("dp_device_go_off_road")
+    should_start = not dp_device_go_off_road and all(onroad_conditions.values())
     if started_ts is None:
       should_start = should_start and all(startup_conditions.values())
 
diff --git a/system/hardware/power_monitoring.py b/system/hardware/power_monitoring.py
index f8b0e8b62..35b309a91 100644
--- a/system/hardware/power_monitoring.py
+++ b/system/hardware/power_monitoring.py
@@ -28,6 +28,8 @@ class PowerMonitoring:
     self.car_voltage_mV = 12e3                  # Low-passed version of peripheralState voltage
     self.car_voltage_instant_mV = 12e3          # Last value of peripheralState voltage
     self.integration_lock = threading.Lock()
+    self.dp_device_auto_shutdown_in = int(self.params.get("dp_device_auto_shutdown_in") or -5) * 60
+    self.dp_device_auto_shutdown = self.dp_device_auto_shutdown_in >= 0
 
     car_battery_capacity_uWh = self.params.get("CarBatteryCapacity") or 0
 
@@ -112,6 +114,8 @@ class PowerMonitoring:
     now = time.monotonic()
     should_shutdown = False
     offroad_time = (now - offroad_timestamp)
+    if started_seen and self.dp_device_auto_shutdown and offroad_time > self.dp_device_auto_shutdown_in:
+      return True
     low_voltage_shutdown = (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3) and
                             offroad_time > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S)
     should_shutdown |= offroad_time > MAX_TIME_OFFROAD_S
diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py
index 35f9916c3..224f19ef2 100644
--- a/system/hardware/tici/hardware.py
+++ b/system/hardware/tici/hardware.py
@@ -94,7 +94,7 @@ class Tici(HardwareBase):
 
   @cached_property
   def amplifier(self):
-    if self.get_device_type() == "mici":
+    if self.get_device_type() == "mici" or os.getenv("LITE"):
       return None
     return Amplifier()
 
@@ -190,7 +190,7 @@ class Tici(HardwareBase):
     return str(self.get_modem().Get(MM_MODEM, 'EquipmentIdentifier', dbus_interface=DBUS_PROPS, timeout=TIMEOUT))
 
   def get_network_info(self):
-    if self.get_device_type() == "mici":
+    if self.get_device_type() == "mici" or os.getenv("LITE"):
       return None
     try:
       modem = self.get_modem()
@@ -282,6 +282,8 @@ class Tici(HardwareBase):
       return None
 
   def get_modem_temperatures(self):
+    if os.getenv("LITE"):
+      return []
     timeout = 0.2  # Default timeout is too short
     try:
       modem = self.get_modem()
diff --git a/system/loggerd/encoder/ffmpeg_encoder.cc b/system/loggerd/encoder/ffmpeg_encoder.cc
index 4d6be4718..99e6a1936 100644
--- a/system/loggerd/encoder/ffmpeg_encoder.cc
+++ b/system/loggerd/encoder/ffmpeg_encoder.cc
@@ -22,6 +22,8 @@ extern "C" {
 
 const int env_debug_encoder = (getenv("DEBUG_ENCODER") != NULL) ? atoi(getenv("DEBUG_ENCODER")) : 0;
 
+const int env_dashy = (getenv("DASHY") != NULL) ? atoi(getenv("DASHY")) : 0;
+
 FfmpegEncoder::FfmpegEncoder(const EncoderInfo &encoder_info, int in_width, int in_height)
     : VideoEncoder(encoder_info, in_width, in_height) {
   frame = av_frame_alloc();
@@ -57,7 +59,13 @@ void FfmpegEncoder::encoder_open() {
   this->codec_ctx->height = frame->height;
   this->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
   this->codec_ctx->time_base = (AVRational){ 1, encoder_info.fps };
-  int err = avcodec_open2(this->codec_ctx, codec, NULL);
+  AVDictionary *opts = NULL;
+  if (env_dashy && codec_id == AV_CODEC_ID_H264) {
+    av_dict_set(&opts, "preset", "ultrafast", 0);
+    av_dict_set(&opts, "tune", "zerolatency", 0);
+  }
+  int err = avcodec_open2(this->codec_ctx, codec, &opts);
+  av_dict_free(&opts);
   assert(err >= 0);
 
   is_open = true;
diff --git a/system/loggerd/loggerd.cc b/system/loggerd/loggerd.cc
index 21de1ff33..355e31ebe 100644
--- a/system/loggerd/loggerd.cc
+++ b/system/loggerd/loggerd.cc
@@ -230,8 +230,25 @@ void loggerd_thread() {
   std::unique_ptr ctx(Context::create());
   std::unique_ptr poller(Poller::create());
 
+  const bool lite = getenv("LITE");
+  const std::set lite_skip_names = {
+    "driverCameraState",
+    "driverEncodeIdx",
+    "driverStateV2",
+    "driverMonitoringState",
+    "driverEncodeData",
+    "livestreamDriverEncodeIdx",
+    "livestreamDriverEncodeData",
+    // audio logs
+    "userBookmark",
+    "soundPressure",
+    "rawAudioData",
+    "audioFeedback",
+  };
+
   // subscribe to all socks
   for (const auto& [_, it] : services) {
+    if (lite && lite_skip_names.count(it.name)) continue;
     const bool encoder = util::ends_with(it.name, "EncodeData");
     const bool livestream_encoder = util::starts_with(it.name, "livestream");
     const bool record_audio = (it.name == "rawAudioData") && Params().getBool("RecordAudio");
@@ -261,7 +278,9 @@ void loggerd_thread() {
   std::vector encoders_with_audio;
   for (const auto &cam : cameras_logged) {
     for (const auto &encoder_info : cam.encoder_infos) {
-      encoder_infos_dict[encoder_info.publish_name] = encoder_info;
+      const std::string &name = encoder_info.publish_name;
+      if (lite && lite_skip_names.count(name)) continue;
+      encoder_infos_dict[name] = encoder_info;
       s.max_waiting++;
     }
   }
diff --git a/system/loggerd/loggerd.h b/system/loggerd/loggerd.h
index 967caec86..3c2e6c6a5 100644
--- a/system/loggerd/loggerd.h
+++ b/system/loggerd/loggerd.h
@@ -93,7 +93,7 @@ const EncoderInfo main_wide_road_encoder_info = {
 const EncoderInfo main_driver_encoder_info = {
   .publish_name = "driverEncodeData",
   .filename = "dcamera.hevc",
-  .record = Params().getBool("RecordFront"),
+  .record = !getenv("LITE") && Params().getBool("RecordFront"),
   .get_settings = [](int in_width){return EncoderSettings::MainEncoderSettings(in_width);},
   INIT_ENCODE_FUNCTIONS(DriverEncode),
 };
diff --git a/system/manager/manager.py b/system/manager/manager.py
index 504cfc9a2..25a941550 100755
--- a/system/manager/manager.py
+++ b/system/manager/manager.py
@@ -19,6 +19,8 @@ from openpilot.system.athena.registration import register, UNREGISTERED_DONGLE_I
 from openpilot.common.swaglog import cloudlog, add_file_handler
 from openpilot.system.version import get_build_metadata, terms_version, training_version
 from openpilot.system.hardware.hw import Paths
+from openpilot.system.manager.vehicle_model_collector import VehicleModelCollector
+import time
 
 
 def manager_init() -> None:
@@ -42,6 +44,7 @@ def manager_init() -> None:
     default_value = params.get_default_value(k)
     if default_value is not None and params.get(k) is None:
       params.put(k, default_value)
+  params.put("dp_device_model_list", VehicleModelCollector().get())
 
   # Create folders needed for msgq
   try:
@@ -69,7 +72,8 @@ def manager_init() -> None:
   if reg_res:
     dongle_id = reg_res
   else:
-    raise Exception(f"Registration failed for device {serial}")
+    dongle_id = "UnregisteredDevice"
+    # raise Exception(f"Registration failed for device {serial}")
   os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog
   os.environ['GIT_ORIGIN'] = build_metadata.openpilot.git_normalized_origin # Needed for swaglog
   os.environ['GIT_BRANCH'] = build_metadata.channel # Needed for swaglog
@@ -126,6 +130,15 @@ def manager_thread() -> None:
   ensure_running(managed_processes.values(), False, params=params, CP=sm['carParams'], not_run=ignore)
 
   started_prev = False
+
+  dp_dev_delay_time_started: float = 0.
+  dp_dev_delay_loggerd = int(params.get('dp_dev_delay_loggerd') or 0)
+
+  # Dictionary of processes to be delayed [process_name: delay_seconds]
+  dp_dev_delay_start_times: dict[str, float] = {
+    'loggerd': dp_dev_delay_loggerd,
+    'encoderd': dp_dev_delay_loggerd
+  }
   ignition_prev = False
 
   while True:
@@ -146,10 +159,22 @@ def manager_thread() -> None:
     if started != started_prev:
       write_onroad_params(started, params)
 
+    dp_ignore: list[str] = []
+    if started and not started_prev:
+      dp_dev_delay_time_started = time.monotonic()
+    elif not started and started_prev:
+      dp_dev_delay_time_started = 0.
+
+    if dp_dev_delay_time_started > 0.:
+      cur_time = time.monotonic()
+      for name, delay_time in dp_dev_delay_start_times.items():
+        if cur_time - dp_dev_delay_time_started < delay_time: # type: ignore
+          dp_ignore.append(name)
+
     started_prev = started
     ignition_prev = ignition
 
-    ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=ignore)
+    ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=list(set(ignore) | set(dp_ignore)))
 
     running = ' '.join("{}{}\u001b[0m".format("\u001b[32m" if p.proc.is_alive() else "\u001b[31m", p.name)
                        for p in managed_processes.values() if p.proc)
diff --git a/system/manager/process_config.py b/system/manager/process_config.py
index 679d4754b..defa18ab3 100644
--- a/system/manager/process_config.py
+++ b/system/manager/process_config.py
@@ -55,6 +55,12 @@ def only_onroad(started: bool, params: Params, CP: car.CarParams) -> bool:
 def only_offroad(started: bool, params: Params, CP: car.CarParams) -> bool:
   return not started
 
+def dashy(started: bool, params: Params, CP: car.CarParams) -> bool:
+  return int(params.get("dp_dev_dashy") or 0) > 0
+
+def dashy_with_video(started: bool, params: Params, CP: car.CarParams) -> bool:
+  return int(params.get("dp_dev_dashy") or 0) == 2
+
 def or_(*fns):
   return lambda *args: operator.or_(*(fn(*args) for fn in fns))
 
@@ -66,23 +72,24 @@ procs = [
 
   NativeProcess("loggerd", "system/loggerd", ["./loggerd"], logging),
   NativeProcess("encoderd", "system/loggerd", ["./encoderd"], only_onroad),
-  NativeProcess("stream_encoderd", "system/loggerd", ["./encoderd", "--stream"], notcar),
+  NativeProcess("stream_encoderd", "system/loggerd", ["./encoderd", "--stream"], or_(notcar, and_(dashy_with_video, only_onroad))),
   PythonProcess("logmessaged", "system.logmessaged", always_run),
 
   NativeProcess("camerad", "system/camerad", ["./camerad"], driverview, enabled=not WEBCAM),
   PythonProcess("webcamerad", "tools.webcam.camerad", driverview, enabled=WEBCAM),
   NativeProcess("logcatd", "system/logcatd", ["./logcatd"], only_onroad, platform.system() != "Darwin"),
   NativeProcess("proclogd", "system/proclogd", ["./proclogd"], only_onroad, platform.system() != "Darwin"),
-  PythonProcess("micd", "system.micd", iscar),
+  PythonProcess("micd", "system.micd", iscar, enabled=not os.getenv("LITE")),
   PythonProcess("timed", "system.timed", always_run, enabled=not PC),
 
   PythonProcess("modeld", "selfdrive.modeld.modeld", only_onroad),
-  PythonProcess("dmonitoringmodeld", "selfdrive.modeld.dmonitoringmodeld", driverview, enabled=(WEBCAM or not PC)),
+  PythonProcess("dmonitoringmodeld", "selfdrive.modeld.dmonitoringmodeld", driverview, enabled=(WEBCAM or not PC) and not os.getenv("LITE")),
 
   PythonProcess("sensord", "system.sensord.sensord", only_onroad, enabled=not PC),
   NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None)),
   PythonProcess("raylib_ui", "selfdrive.ui.ui", always_run, enabled=False, watchdog_max_dt=(5 if not PC else None)),
-  PythonProcess("soundd", "selfdrive.ui.soundd", only_onroad),
+  PythonProcess("soundd", "selfdrive.ui.soundd", only_onroad, enabled=not os.getenv("LITE")),
+  PythonProcess("beepd", "dragonpilot.selfdrive.ui.beepd", only_onroad, enabled=(Params().get_bool("dp_device_beep") and os.getenv("LITE"))),
   PythonProcess("locationd", "selfdrive.locationd.locationd", only_onroad),
   NativeProcess("_pandad", "selfdrive/pandad", ["./pandad"], always_run, enabled=False),
   PythonProcess("calibrationd", "selfdrive.locationd.calibrationd", only_onroad),
@@ -92,7 +99,8 @@ procs = [
   PythonProcess("selfdrived", "selfdrive.selfdrived.selfdrived", only_onroad),
   PythonProcess("card", "selfdrive.car.card", only_onroad),
   PythonProcess("deleter", "system.loggerd.deleter", always_run),
-  PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", driverview, enabled=(WEBCAM or not PC)),
+  PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", driverview, enabled=(WEBCAM or not PC) and not os.getenv("LITE")),
+  PythonProcess("dpmonitoringd", "selfdrive.monitoring.dpmonitoringd", only_onroad, enabled=os.getenv("LITE")),
   PythonProcess("qcomgpsd", "system.qcomgpsd.qcomgpsd", qcomgps, enabled=TICI),
   PythonProcess("pandad", "selfdrive.pandad.pandad", always_run),
   PythonProcess("paramsd", "selfdrive.locationd.paramsd", only_onroad),
@@ -107,13 +115,14 @@ procs = [
   PythonProcess("updated", "system.updated.updated", only_offroad, enabled=not PC),
   PythonProcess("uploader", "system.loggerd.uploader", always_run),
   PythonProcess("statsd", "system.statsd", always_run),
-  PythonProcess("feedbackd", "selfdrive.ui.feedback.feedbackd", only_onroad),
+  PythonProcess("feedbackd", "selfdrive.ui.feedback.feedbackd", only_onroad, enabled=not os.getenv("LITE")),
 
   # debug procs
-  NativeProcess("bridge", "cereal/messaging", ["./bridge"], notcar),
-  PythonProcess("webrtcd", "system.webrtc.webrtcd", notcar),
+  NativeProcess("bridge", "cereal/messaging", ["./bridge"], or_(notcar, and_(dashy_with_video, only_onroad))),
+  PythonProcess("webrtcd", "system.webrtc.webrtcd", or_(notcar, and_(dashy_with_video, only_onroad))),
   PythonProcess("webjoystick", "tools.bodyteleop.web", notcar),
   PythonProcess("joystick", "tools.joystick.joystick_control", and_(joystick, iscar)),
+  PythonProcess("dashy", "dragonpilot.dashy.backend.server", dashy),
 ]
 
 managed_processes = {p.name: p for p in procs}
diff --git a/system/manager/vehicle_model_collector.py b/system/manager/vehicle_model_collector.py
new file mode 100755
index 000000000..8f109eeeb
--- /dev/null
+++ b/system/manager/vehicle_model_collector.py
@@ -0,0 +1,163 @@
+"""
+Copyright (c) 2025 Rick Lan
+
+This software is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0).
+You are free to share and adapt this work for non-commercial purposes, provided you give appropriate credit and distribute any modifications under the same license.
+
+To view a copy of this license, visit:
+http://creativecommons.org/licenses/by-nc-sa/4.0/
+
+---
+
+**Commercial Licensing:**
+Use of this software for commercial purposes is strictly prohibited without a separate, paid license.
+To purchase a commercial license, please contact ricklan@gmail.com.
+"""
+
+import os
+import importlib
+import json
+from openpilot.common.basedir import BASEDIR
+from openpilot.common.params import Params
+
+
+class VehicleModelCollector:
+  def __init__(self):
+    self.base_package = "opendbc.car"
+    self.base_path = f"{BASEDIR}/opendbc/car"
+    self.exclude_brands = ['body', 'mock']
+
+    # Define the lookup dictionary for brand-to-group mappings
+    self.brand_to_group_map = {
+      "chrysler": [
+        {"prefix": "DODGE_", "group": "Dodge"},
+        {"prefix": "RAM_", "group": "Ram"},
+        {"prefix": "JEEP_", "group": "Jeep"},
+      ],
+      "gm": [
+        {"prefix": "BUICK_", "group": "Buick"},
+        {"prefix": "CADILLAC_", "group": "Cadillac"},
+        {"prefix": "CHEVROLET_", "group": "Chevrolet"},
+        {"prefix": "HOLDEN_", "group": "Holden"},
+      ],
+      "honda": {"prefix": "ACURA_", "group": "Acura"},
+      "toyota": {"prefix": "LEXUS_", "group": "Lexus"},
+      "hyundai": [
+        {"prefix": "KIA_", "group": "Kia"},
+        {"prefix": "GENESIS_", "group": "Genesis"}
+      ],
+      "volkswagen": [
+        {"prefix": "AUDI_", "group": "Audi"},
+        {"prefix": "SKODA_", "group": "Skoda"},
+        {"prefix": "SEAT_", "group": "Seat"}
+      ]
+    }
+
+    # Define exceptions for group names
+    self.group_name_exceptions = {
+      "gm": "GM",
+    }
+
+  @staticmethod
+  def is_car_model(car_class, attr):
+    """Check if the attribute is a car model (not callable and not a dunder attribute)"""
+    return not callable(getattr(car_class, attr)) and not attr.startswith("__")
+
+  @staticmethod
+  def move_to_proper_group(models, prefix):
+    """
+    Moves models with a certain prefix to their respective group.
+    Example: Models starting with 'LEXUS_' should go to 'Lexus' group.
+    """
+    moved_models = []
+    for model in models[:]:  # Iterate over a copy to avoid modifying during iteration
+      if model.startswith(prefix):
+        moved_models.append(model)
+        models.remove(model)  # Remove from the original group
+    return moved_models
+
+  def format_group_name(self, group_name):
+    """
+    Formats group names according to the exceptions dictionary.
+    Groups in the exceptions dictionary are returned in all caps, others are title cased.
+    """
+    return self.group_name_exceptions.get(group_name, group_name.title())
+
+  def collect_models(self):
+    """Collect all car models and organize them by brand/group"""
+    # List all subdirectories (car brands)
+    car_brands = sorted([
+      name for name in os.listdir(self.base_path)
+      if os.path.isdir(os.path.join(self.base_path, name)) and not name.startswith("__")
+    ])
+
+    grouped_models = {}
+
+    # Import CAR from each subdirectory and group models by brand
+    for brand in car_brands:
+      if brand in self.exclude_brands:
+        continue
+
+      module_name = f"{self.base_package}.{brand}.values"
+      try:
+        module = importlib.import_module(module_name)
+        if hasattr(module, "CAR"):
+          car_class = getattr(module, "CAR")
+          models = sorted([attr for attr in dir(car_class) if self.is_car_model(car_class, attr)])
+
+          # Check if the brand has a special group in the lookup map
+          if brand in self.brand_to_group_map:
+            group_info = self.brand_to_group_map[brand]
+
+            if isinstance(group_info, list):  # If multiple prefixes for the brand
+              for prefix_info in group_info:
+                moved_models = self.move_to_proper_group(models, prefix_info["prefix"])
+                if moved_models:
+                  if prefix_info["group"] not in grouped_models:
+                    grouped_models[prefix_info["group"]] = []
+                  grouped_models[prefix_info["group"]].extend(moved_models)
+            else:  # Single prefix for the brand
+              moved_models = self.move_to_proper_group(models, group_info["prefix"])
+              if moved_models:
+                if group_info["group"] not in grouped_models:
+                  grouped_models[group_info["group"]] = []
+                grouped_models[group_info["group"]].extend(moved_models)
+
+          # Add remaining models to the respective brand
+          if models:
+            grouped_models[brand] = models
+      except ModuleNotFoundError:
+        pass
+
+    # Sort the groups alphabetically
+    sorted_grouped_models = sorted(grouped_models.items(), key=lambda x: x[0])
+
+    # Convert to the desired output structure, ensuring models are sorted within each group
+    output = [{"group": self.format_group_name(group), "models": sorted(models)}
+              for group, models in sorted_grouped_models]
+
+    return output
+
+  # def save_to_params(self, output=None):
+  #   """Save the collected model list to Params"""
+  #   if output is None:
+  #     output = self.collect_models()
+  #   Params().put("dp_device_model_list", json.dumps(output))
+  #   return output
+  #
+  # def run(self):
+  #   """Collect models and save to params"""
+  #   models = self.collect_models()
+  #   self.save_to_params(models)
+  #   return models
+
+  def get_json(self):
+    return self.collect_models()
+
+  def get(self):
+    return json.dumps(self.collect_models())
+
+# Allow running as a script
+if __name__ == "__main__":
+  collector = VehicleModelCollector()
+  print(collector.get())
diff --git a/system/ubloxd/pigeond.py b/system/ubloxd/pigeond.py
index e458a9d65..3f7a77fcc 100755
--- a/system/ubloxd/pigeond.py
+++ b/system/ubloxd/pigeond.py
@@ -266,7 +266,8 @@ def init(pigeon: TTYPigeon) -> None:
   set_power(False)
   time.sleep(0.1)
   set_power(True)
-  time.sleep(0.5)
+  # rick - make sleep twice long, give LITE more time.
+  time.sleep(1.0)
 
   init_baudrate(pigeon)
   init_pigeon(pigeon)
diff --git a/system/webrtc/webrtcd.py b/system/webrtc/webrtcd.py
index fb93e565f..19c3386cc 100755
--- a/system/webrtc/webrtcd.py
+++ b/system/webrtc/webrtcd.py
@@ -42,7 +42,7 @@ class CerealOutgoingMessageProxy:
 
     return msg_dict
 
-  def update(self):
+  async def update(self):
     # this is blocking in async context...
     self.sm.update(0)
     for service, updated in self.sm.updated.items():
@@ -53,7 +53,10 @@ class CerealOutgoingMessageProxy:
       outgoing_msg = {"type": service, "logMonoTime": mono_time, "valid": valid, "data": msg_dict}
       encoded_msg = json.dumps(outgoing_msg).encode()
       for channel in self.channels:
-        channel.send(encoded_msg)
+        if isinstance(channel, web.WebSocketResponse):
+          await channel.send_bytes(encoded_msg)
+        else:
+          channel.send(encoded_msg)
 
 
 class CerealIncomingMessageProxy:
@@ -94,7 +97,7 @@ class CerealProxyRunner:
 
     while True:
       try:
-        self.proxy.update()
+        await self.proxy.update()
       except InvalidStateError:
         self.logger.warning("Cereal outgoing proxy invalid state (connection closed)")
         break
@@ -229,7 +232,7 @@ async def get_stream(request: 'web.Request'):
 
   stream_dict[session.identifier] = session
 
-  return web.json_response({"sdp": answer.sdp, "type": answer.type})
+  return web.json_response({"sdp": answer.sdp, "type": answer.type}, headers={'Access-Control-Allow-Origin': '*'})
 
 
 async def get_schema(request: 'web.Request'):
@@ -246,23 +249,47 @@ async def on_shutdown(app: 'web.Application'):
   del app['streams']
 
 
+
+@web.middleware
+async def cors_middleware(request, handler):
+    response = await handler(request)
+    response.headers['Access-Control-Allow-Origin'] = '*'
+    response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
+    response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
+    return response
+
+async def handle_cors_preflight(request):
+    if request.method == 'OPTIONS':
+        headers = {
+            'Access-Control-Allow-Origin': '*',
+            'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
+            'Access-Control-Allow-Headers': 'Content-Type, Authorization',
+            'Access-Control-Max-Age': '86400',
+        }
+        return web.Response(status=200, headers=headers)
+    return await request.app['handler'](request)
+
 def webrtcd_thread(host: str, port: int, debug: bool):
   logging.basicConfig(level=logging.CRITICAL, handlers=[logging.StreamHandler()])
   logging_level = logging.DEBUG if debug else logging.INFO
   logging.getLogger("WebRTCStream").setLevel(logging_level)
   logging.getLogger("webrtcd").setLevel(logging_level)
 
-  app = web.Application()
+  app = web.Application(middlewares=[cors_middleware])
 
   app['streams'] = dict()
   app['debug'] = debug
   app.on_shutdown.append(on_shutdown)
   app.router.add_post("/stream", get_stream)
   app.router.add_get("/schema", get_schema)
+  app.router.add_route('OPTIONS', '/{tail:.*}', handle_cors_preflight)
 
   web.run_app(app, host=host, port=port)
 
 
+
+
+
 def main():
   parser = argparse.ArgumentParser(description="WebRTC daemon")
   parser.add_argument("--host", type=str, default="0.0.0.0", help="Host to listen on")