
/* /web/static/src/module_loader.js */
(function(odoo){"use strict";if(odoo.loader){return;}
class ModuleLoader{bus=new EventTarget();checkErrorProm=null;factories=new Map();failed=new Set();jobs=new Set();modules=new Map();constructor(root){this.root=root;const strDebug=new URLSearchParams(location.search).get("debug");this.debug=Boolean(strDebug&&strDebug!=="0");}
addJob(name){this.jobs.add(name);this.startModules();}
define(name,deps,factory,lazy=false){if(typeof name!=="string"){throw new Error(`Module name should be a string, got: ${String(name)}`);}
if(!Array.isArray(deps)){throw new Error(`Module dependencies should be a list of strings, got: ${String(deps)}`);}
if(typeof factory!=="function"){throw new Error(`Module factory should be a function, got: ${String(factory)}`);}
if(this.factories.has(name)){return;}
this.factories.set(name,{deps,fn:factory,ignoreMissingDeps:globalThis.__odooIgnoreMissingDependencies,});if(!lazy){this.addJob(name);this.checkErrorProm||=Promise.resolve().then(()=>{this.checkErrorProm=null;this.reportErrors(this.findErrors());});}}
findErrors(moduleNames){const findCycle=(currentModuleNames,visited)=>{for(const name of currentModuleNames||[]){if(visited.has(name)){const cycleModuleNames=[...visited,name];return cycleModuleNames.slice(cycleModuleNames.indexOf(name)).map((j)=>`"${j}"`).join(" => ");}
const cycle=findCycle(dependencyGraph[name],new Set(visited).add(name));if(cycle){return cycle;}}
return null;};moduleNames||=this.jobs;const dependencyGraph=Object.create(null);const missing=new Set();const unloaded=new Set();for(const moduleName of moduleNames){const{deps,ignoreMissingDeps}=this.factories.get(moduleName);dependencyGraph[moduleName]=deps;if(ignoreMissingDeps){continue;}
unloaded.add(moduleName);for(const dep of deps){if(!this.factories.has(dep)){missing.add(dep);}}}
const cycle=findCycle(moduleNames,new Set());const errors={};if(cycle){errors.cycle=cycle;}
if(this.failed.size){errors.failed=this.failed;}
if(missing.size){errors.missing=missing;}
if(unloaded.size){errors.unloaded=unloaded;}
return errors;}
findJob(){for(const job of this.jobs){if(this.factories.get(job).deps.every((dep)=>this.modules.has(dep))){return job;}}
return null;}
async reportErrors(errors){if(!Object.keys(errors).length){return;}
if(errors.failed){console.error("The following modules failed to load because of an error:",[...errors.failed,]);}
if(errors.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:",[...errors.missing]);}
if(errors.cycle){console.error("The following modules could not be loaded because they form a dependency cycle:",errors.cycle);}
if(errors.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:",[...errors.unloaded]);}
const document=this.root?.ownerDocument||globalThis.document;if(document.readyState==="loading"){await new Promise((resolve)=>document.addEventListener("DOMContentLoaded",resolve));}
if(this.debug){const style=document.createElement("style");style.className="o_module_error_banner";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);}}
startModules(){let job;while((job=this.findJob())){this.startModule(job);}}
startModule(name){const require=(dependency)=>this.modules.get(dependency);this.jobs.delete(name);const factory=this.factories.get(name);let module=null;try{module=factory.fn(require);}catch(error){this.failed.add(name);throw new Error(`Error while loading "${name}":\n${error}`);}
this.modules.set(name,module);this.bus.dispatchEvent(new CustomEvent("module-started",{detail:{moduleName:name,module},}));return module;}}
const loader=new ModuleLoader();odoo.define=loader.define.bind(loader);odoo.loader=loader;if(odoo.debug&&!loader.debug){odoo.debug="";}})((globalThis.odoo||={}));;

/* /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,CLOSING_HANDSHAKE_ABORTED:4004,});const WORKER_STATE=__exports.WORKER_STATE=Object.freeze({CONNECTED:"CONNECTED",DISCONNECTED:"DISCONNECTED",IDLE:"IDLE",CONNECTING:"CONNECTING",});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.state=WORKER_STATE.IDLE;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){this._logDebug("broadcast",type,data);for(const client of this.channelsByClient.keys()){client.postMessage({type,data:data?JSON.parse(JSON.stringify(data)):undefined});}}
registerClient(messagePort){messagePort.onmessage=(ev)=>{this._onClientMessage(messagePort,ev.data);};this.channelsByClient.set(messagePort,[]);}
sendToClient(client,type,data){this._logDebug("sendToClient",type,data);client.postMessage({type,data:data?JSON.parse(JSON.stringify(data)):undefined});}
_onClientMessage(client,{action,data}){this._logDebug("_onClientMessage",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=[...this.debugModeByClient.values()].some(Boolean);this._debouncedUpdateChannels();}
_initializeConnection(client,{db,debug,lastNotificationId,uid,websocketURL,startTs}){if(this.newestStartTs&&this.newestStartTs>startTs){this.debugModeByClient.set(client,debug);this.isDebug=[...this.debugModeByClient.values()].some(Boolean);this.sendToClient(client,"worker_state_updated",this.state);this.sendToClient(client,"initialized");return;}
this.newestStartTs=startTs;this.websocketURL=websocketURL;this.lastNotificationId=lastNotificationId;this.debugModeByClient.set(client,debug);this.isDebug=[...this.debugModeByClient.values()].some(Boolean);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,"worker_state_updated",this.state);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}){clearInterval(this._connectionCheckInterval);this._logDebug("_onWebsocketClose",code,reason);this._updateState(WORKER_STATE.DISCONNECTED);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([WEBSOCKET_CLOSE_CODES.KEEP_ALIVE_TIMEOUT,WEBSOCKET_CLOSE_CODES.CLOSING_HANDSHAKE_ABORTED,].includes(code)){this.connectRetryDelay=0;}
if(code===WEBSOCKET_CLOSE_CODES.SESSION_EXPIRED){this.isWaitingForNewUID=true;}
this._retryConnectionWithDelay();}
_onWebsocketError(){this._logDebug("_onWebsocketError");this._retryConnectionWithDelay();}
_onWebsocketMessage(messageEv){this._restartConnectionCheckInterval();const notifications=JSON.parse(messageEv.data);this._logDebug("_onWebsocketMessage",notifications);this.lastNotificationId=notifications[notifications.length-1].id;this.broadcast("notification",notifications);}
_logDebug(title,...args){const clientsInDebug=[...this.debugModeByClient.keys()].filter((client)=>this.debugModeByClient.get(client));for(const client of clientsInDebug){client.postMessage({type:"log_debug",data:[`%c${new Date().toLocaleString()} - [${title}]`,"color: #c6e; font-weight: bold;",...args,],});}}
_onWebsocketOpen(){this._logDebug("_onWebsocketOpen");this._updateState(WORKER_STATE.CONNECTED);this.broadcast(this.isReconnecting?"reconnect":"connect");this._debouncedUpdateChannels();this.connectRetryDelay=this.INITIAL_RECONNECT_DELAY;this.connectTimeout=null;this.isReconnecting=false;this.firstSubscribeDeferred.then(()=>{if(!this.websocket){return;}
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._logDebug("_retryConnectionWithDelay",this.connectRetryDelay);this.connectTimeout=setTimeout(this._start.bind(this),this.connectRetryDelay);}
_sendToServer(message){this._logDebug("_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();}}
_removeWebsocketListeners(){this.websocket?.removeEventListener("open",this._onWebsocketOpen);this.websocket?.removeEventListener("message",this._onWebsocketMessage);this.websocket?.removeEventListener("error",this._onWebsocketError);this.websocket?.removeEventListener("close",this._onWebsocketClose);}
_start(){this._logDebug("_start");if(!this.active||this._isWebsocketConnected()||this._isWebsocketConnecting()){return;}
this._removeWebsocketListeners();if(this._isWebsocketClosing()){this._onWebsocketClose(new CloseEvent("close",{code:WEBSOCKET_CLOSE_CODES.CLOSING_HANDSHAKE_ABORTED}));this.websocket=null;return;}
this._updateState(WORKER_STATE.CONNECTING);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(){this._logDebug("_stop");clearTimeout(this.connectTimeout);this.connectRetryDelay=this.INITIAL_RECONNECT_DELAY;this.isReconnecting=false;this.lastChannelSubscription=null;const shouldBroadcastClose=this.websocket&&this.websocket.readyState!==WebSocket.CLOSED;this.websocket?.close();this._removeWebsocketListeners();this.websocket=null;if(shouldBroadcastClose){this.broadcast("disconnect",{code:WEBSOCKET_CLOSE_CODES.CLEAN});}}
_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();}}
_updateState(newState){this.state=newState;this.broadcast("worker_state_updated",newState);}}
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;});