
/* /web/static/src/module_loader.js */
(function(){"use strict";class ModuleLoader{factories=new Map();jobs=new Set();failed=new Set();modules=new Map();bus=new EventTarget();checkErrorProm=null;define(name,deps,factory){if(typeof name!=="string"){throw new Error(`Invalid name definition: ${name} (should be a string)"`);}
if(!(deps instanceof Array)){throw new Error(`Dependencies should be defined by an array: ${deps}`);}
if(typeof factory!=="function"){throw new Error(`Factory should be defined by a function ${factory}`);}
if(!this.factories.has(name)){this.factories.set(name,{deps,fn:factory,ignoreMissingDeps:globalThis.__odooIgnoreMissingDependencies,});this.addJob(name);this.checkErrorProm||=Promise.resolve().then(()=>{this.checkAndReportErrors();this.checkErrorProm=null;});}}
addJob(name){this.jobs.add(name);this.startModules();}
findJob(){for(const job of this.jobs){if(this.factories.get(job).deps.every((dep)=>this.modules.has(dep))){return job;}}
return null;}
startModules(){let job;while((job=this.findJob())){this.startModule(job);}}
startModule(name){const require=(name)=>this.modules.get(name);this.jobs.delete(name);const factory=this.factories.get(name);let value=null;try{value=factory.fn(require);}catch(error){this.failed.add(name);throw new Error(`Error while loading "${name}":\n${error}`);}
this.modules.set(name,value);this.bus.dispatchEvent(new CustomEvent("module-started",{detail:{moduleName:name,module:value}}));}
findErrors(){const dependencyGraph=new Map();for(const job of this.jobs){dependencyGraph.set(job,this.factories.get(job).deps);}
function visitJobs(jobs,visited=new Set()){for(const job of jobs){const result=visitJob(job,visited);if(result){return result;}}
return null;}
function visitJob(job,visited){if(visited.has(job)){const jobs=Array.from(visited).concat([job]);const index=jobs.indexOf(job);return jobs.slice(index).map((j)=>`"${j}"`).join(" => ");}
const deps=dependencyGraph.get(job);return deps?visitJobs(deps,new Set(visited).add(job)):null;}
const missing=new Set();for(const job of this.jobs){const factory=this.factories.get(job);if(factory.ignoreMissingDeps){continue;}
for(const dep of factory.deps){if(!this.factories.has(dep)){missing.add(dep);}}}
return{failed:[...this.failed],cycle:visitJobs(this.jobs),missing:[...missing],unloaded:[...this.jobs].filter((j)=>!this.factories.get(j).ignoreMissingDeps),};}
async checkAndReportErrors(){const{failed,cycle,missing,unloaded}=this.findErrors();if(!failed.length&&!unloaded.length){return;}
const debug=new URLSearchParams(location.search).get("debug");if(debug&&debug!=="0"){const style=document.createElement("style");style.textContent=`
                    body::before {
                        font-weight: bold;
                        content: "An error occurred while loading javascript modules, you may find more information in the devtools console";
                        position: fixed;
                        left: 0;
                        bottom: 0;
                        z-index: 100000000000;
                        background-color: #C00;
                        color: #DDD;
                    }
                `;document.head.appendChild(style);}
if(failed.length){console.error("The following modules failed to load because of an error:",failed);}
if(missing){console.error("The following modules are needed by other modules but have not been defined, they may not be present in the correct asset bundle:",missing);}
if(cycle){console.error("The following modules could not be loaded because they form a dependency cycle:",cycle);}
if(unloaded){console.error("The following modules could not be loaded because they have unmet dependencies, this is a secondary error which is likely caused by one of the above problems:",unloaded);}}}
if(!globalThis.odoo){globalThis.odoo={};}
const odoo=globalThis.odoo;if(odoo.debug&&!new URLSearchParams(location.search).has("debug")){odoo.debug="";}
const loader=new ModuleLoader();odoo.define=loader.define.bind(loader);odoo.loader=loader;})();;

/* /bus/static/src/workers/websocket_worker.js */
odoo.define('@bus/workers/websocket_worker',['@bus/workers/websocket_worker_utils'],function(require){'use strict';let __exports={};const{debounce,Deferred}=require("@bus/workers/websocket_worker_utils");const WEBSOCKET_CLOSE_CODES=__exports.WEBSOCKET_CLOSE_CODES=Object.freeze({CLEAN:1000,GOING_AWAY:1001,PROTOCOL_ERROR:1002,INCORRECT_DATA:1003,ABNORMAL_CLOSURE:1006,INCONSISTENT_DATA:1007,MESSAGE_VIOLATING_POLICY:1008,MESSAGE_TOO_BIG:1009,EXTENSION_NEGOTIATION_FAILED:1010,SERVER_ERROR:1011,RESTART:1012,TRY_LATER:1013,BAD_GATEWAY:1014,SESSION_EXPIRED:4001,KEEP_ALIVE_TIMEOUT:4002,RECONNECTING:4003,});const WORKER_VERSION=__exports.WORKER_VERSION="17.0-3";const MAXIMUM_RECONNECT_DELAY=60000;const WebsocketWorker=__exports.WebsocketWorker=class WebsocketWorker{INITIAL_RECONNECT_DELAY=1000;RECONNECT_JITTER=1000;CONNECTION_CHECK_DELAY=60_000;constructor(){this.newestStartTs=undefined;this.websocketURL="";this.currentUID=null;this.currentDB=null;this.isWaitingForNewUID=true;this.channelsByClient=new Map();this.connectRetryDelay=this.INITIAL_RECONNECT_DELAY;this.connectTimeout=null;this.debugModeByClient=new Map();this.isDebug=false;this.active=true;this.isReconnecting=false;this.lastChannelSubscription=null;this.firstSubscribeDeferred=new Deferred();this.lastNotificationId=0;this.messageWaitQueue=[];this._forceUpdateChannels=debounce(this._forceUpdateChannels,300);this._debouncedUpdateChannels=debounce(this._updateChannels,300);this._debouncedSendToServer=debounce(this._sendToServer,300);this._onWebsocketClose=this._onWebsocketClose.bind(this);this._onWebsocketError=this._onWebsocketError.bind(this);this._onWebsocketMessage=this._onWebsocketMessage.bind(this);this._onWebsocketOpen=this._onWebsocketOpen.bind(this);}
broadcast(type,data){for(const client of this.channelsByClient.keys()){client.postMessage({type,data});}}
registerClient(messagePort){messagePort.onmessage=(ev)=>{this._onClientMessage(messagePort,ev.data);};this.channelsByClient.set(messagePort,[]);}
sendToClient(client,type,data){client.postMessage({type,data});}
_onClientMessage(client,{action,data}){switch(action){case"send":{if(data["event_name"]==="update_presence"){this._debouncedSendToServer(data);}else{this._sendToServer(data);}
return;}
case"start":return this._start();case"stop":return this._stop();case"leave":return this._unregisterClient(client);case"add_channel":return this._addChannel(client,data);case"delete_channel":return this._deleteChannel(client,data);case"force_update_channels":return this._forceUpdateChannels();case"initialize_connection":return this._initializeConnection(client,data);}}
_addChannel(client,channel){const clientChannels=this.channelsByClient.get(client);if(!clientChannels.includes(channel)){clientChannels.push(channel);this.channelsByClient.set(client,clientChannels);this._debouncedUpdateChannels();}}
_deleteChannel(client,channel){const clientChannels=this.channelsByClient.get(client);if(!clientChannels){return;}
const channelIndex=clientChannels.indexOf(channel);if(channelIndex!==-1){clientChannels.splice(channelIndex,1);this._debouncedUpdateChannels();}}
_forceUpdateChannels(){this._updateChannels({force:true});}
_unregisterClient(client){this.channelsByClient.delete(client);this.debugModeByClient.delete(client);this.isDebug=Object.values(this.debugModeByClient).some((debugValue)=>debugValue!=="");this._debouncedUpdateChannels();}
_initializeConnection(client,{db,debug,lastNotificationId,uid,websocketURL,startTs}){if(this.newestStartTs&&this.newestStartTs>startTs){this.debugModeByClient[client]=debug;this.isDebug=Object.values(this.debugModeByClient).some((debugValue)=>debugValue!=="");this.sendToClient(client,"initialized");return;}
this.newestStartTs=startTs;this.websocketURL=websocketURL;this.lastNotificationId=lastNotificationId;this.debugModeByClient[client]=debug;this.isDebug=Object.values(this.debugModeByClient).some((debugValue)=>debugValue!=="");const isCurrentUserKnown=uid!==undefined;if(this.isWaitingForNewUID&&isCurrentUserKnown){this.isWaitingForNewUID=false;this.currentUID=uid;}
this.currentDB||=db;if((this.currentUID!==uid&&isCurrentUserKnown)||(db&&this.currentDB!==db)){this.currentUID=uid;this.currentDB=db||this.currentDB;if(this.websocket){this.websocket.close(WEBSOCKET_CLOSE_CODES.CLEAN);}
this.channelsByClient.forEach((_,key)=>this.channelsByClient.set(key,[]));}
this.sendToClient(client,"initialized");if(!this.active){this.sendToClient(client,"outdated");}}
_isWebsocketConnected(){return this.websocket&&this.websocket.readyState===1;}
_isWebsocketConnecting(){return this.websocket&&this.websocket.readyState===0;}
_isWebsocketClosing(){return this.websocket&&this.websocket.readyState===2;}
_onWebsocketClose({code,reason}){if(this.isDebug){console.debug(`%c${new Date().toLocaleString()} - [onClose]`,"color: #c6e; font-weight: bold;",code,reason);}
clearInterval(this._connectionCheckInterval);this.lastChannelSubscription=null;this.firstSubscribeDeferred=new Deferred();if(this.isReconnecting){return;}
this.broadcast("disconnect",{code,reason});if(code===WEBSOCKET_CLOSE_CODES.CLEAN){if(reason==="OUTDATED_VERSION"){console.warn("Worker deactivated due to an outdated version.");this.active=false;this.broadcast("outdated");}
return;}
this.broadcast("reconnecting",{closeCode:code});this.isReconnecting=true;if(code===WEBSOCKET_CLOSE_CODES.KEEP_ALIVE_TIMEOUT){this.connectRetryDelay=0;}
if(code===WEBSOCKET_CLOSE_CODES.SESSION_EXPIRED){this.isWaitingForNewUID=true;}
this._retryConnectionWithDelay();}
_onWebsocketError(){if(this.isDebug){console.debug(`%c${new Date().toLocaleString()} - [onError]`,"color: #c6e; font-weight: bold;");}
this._retryConnectionWithDelay();}
_onWebsocketMessage(messageEv){this._restartConnectionCheckInterval();const notifications=JSON.parse(messageEv.data);if(this.isDebug){console.debug(`%c${new Date().toLocaleString()} - [onMessage]`,"color: #c6e; font-weight: bold;",notifications);}
this.lastNotificationId=notifications[notifications.length-1].id;this.broadcast("notification",notifications);}
_onWebsocketOpen(){if(this.isDebug){console.debug(`%c${new Date().toLocaleString()} - [onOpen]`,"color: #c6e; font-weight: bold;");}
this.broadcast(this.isReconnecting?"reconnect":"connect");this._debouncedUpdateChannels();this.connectRetryDelay=this.INITIAL_RECONNECT_DELAY;this.connectTimeout=null;this.isReconnecting=false;this.firstSubscribeDeferred.then(()=>{this.messageWaitQueue.forEach((msg)=>this.websocket.send(msg));this.messageWaitQueue=[];});this._restartConnectionCheckInterval();}
_restartConnectionCheckInterval(){clearInterval(this._connectionCheckInterval);this._connectionCheckInterval=setInterval(()=>{if(this._isWebsocketConnected()){this.websocket.send(new Uint8Array([0x00]));}},this.CONNECTION_CHECK_DELAY);}
_retryConnectionWithDelay(){this.connectRetryDelay=Math.min(this.connectRetryDelay*1.5,MAXIMUM_RECONNECT_DELAY)+
this.RECONNECT_JITTER*Math.random();this.connectTimeout=setTimeout(this._start.bind(this),this.connectRetryDelay);}
_sendToServer(message){const payload=JSON.stringify(message);if(!this._isWebsocketConnected()){if(message["event_name"]==="subscribe"){this.messageWaitQueue=this.messageWaitQueue.filter((msg)=>JSON.parse(msg).event_name!=="subscribe");this.messageWaitQueue.unshift(payload);}else{this.messageWaitQueue.push(payload);}}else{if(message["event_name"]==="subscribe"){this.websocket.send(payload);}else{this.firstSubscribeDeferred.then(()=>this.websocket.send(payload));}
this._restartConnectionCheckInterval();}}
_start(){if(!this.active||this._isWebsocketConnected()||this._isWebsocketConnecting()){return;}
if(this.websocket){this.websocket.removeEventListener("open",this._onWebsocketOpen);this.websocket.removeEventListener("message",this._onWebsocketMessage);this.websocket.removeEventListener("error",this._onWebsocketError);this.websocket.removeEventListener("close",this._onWebsocketClose);}
if(this._isWebsocketClosing()){this.lastChannelSubscription=null;this.broadcast("disconnect",{code:WEBSOCKET_CLOSE_CODES.ABNORMAL_CLOSURE});}
this.websocket=new WebSocket(this.websocketURL);this.websocket.addEventListener("open",this._onWebsocketOpen);this.websocket.addEventListener("error",this._onWebsocketError);this.websocket.addEventListener("message",this._onWebsocketMessage);this.websocket.addEventListener("close",this._onWebsocketClose);}
_stop(){clearTimeout(this.connectTimeout);this.connectRetryDelay=this.INITIAL_RECONNECT_DELAY;this.isReconnecting=false;this.lastChannelSubscription=null;if(this.websocket){this.websocket.close();}}
_updateChannels({force=false}={}){const allTabsChannels=[...new Set([].concat.apply([],[...this.channelsByClient.values()])),].sort();const allTabsChannelsString=JSON.stringify(allTabsChannels);const shouldUpdateChannelSubscription=allTabsChannelsString!==this.lastChannelSubscription;if(force||shouldUpdateChannelSubscription){this.lastChannelSubscription=allTabsChannelsString;this._sendToServer({event_name:"subscribe",data:{channels:allTabsChannels,last:this.lastNotificationId},});this.firstSubscribeDeferred.resolve();}}}
return __exports;});;

/* /bus/static/src/workers/websocket_worker_script.js */
odoo.define('@bus/workers/websocket_worker_script',['@bus/workers/websocket_worker'],function(require){'use strict';let __exports={};const{WebsocketWorker}=require("@bus/workers/websocket_worker");(function(){const websocketWorker=new WebsocketWorker();if(self.name.includes("shared")){onconnect=function(ev){const currentClient=ev.ports[0];websocketWorker.registerClient(currentClient);};}else{websocketWorker.registerClient(self);}})();return __exports;});;

/* /bus/static/src/workers/websocket_worker_utils.js */
odoo.define('@bus/workers/websocket_worker_utils',[],function(require){'use strict';let __exports={};__exports.debounce=debounce;function debounce(func,wait,immediate){let timeout;return function(){const context=this;const args=arguments;function later(){timeout=null;if(!immediate){func.apply(context,args);}}
const callNow=immediate&&!timeout;clearTimeout(timeout);timeout=setTimeout(later,wait);if(callNow){func.apply(context,args);}};}
const Deferred=__exports.Deferred=class Deferred extends Promise{constructor(){let resolve;let reject;const prom=new Promise((res,rej)=>{resolve=res;reject=rej;});return Object.assign(prom,{resolve,reject});}}
return __exports;});