
/* /web_tour/static/src/tour_pointer/tour_pointer.js */
odoo.define('@web_tour/tour_pointer/tour_pointer',['@odoo/owl','@web/core/position_hook'],function(require){'use strict';let __exports={};const{Component,useEffect,useRef}=require("@odoo/owl");const{usePosition}=require("@web/core/position_hook");const TourPointer=__exports.TourPointer=class TourPointer extends Component{static props={pointerState:{type:Object,shape:{anchor:{type:HTMLElement,optional:true},content:{type:String,optional:true},isOpen:{type:Boolean,optional:true},isVisible:{type:Boolean,optional:true},onClick:{type:[Function,{value:null}],optional:true},onMouseEnter:{type:[Function,{value:null}],optional:true},onMouseLeave:{type:[Function,{value:null}],optional:true},position:{type:[{value:"left"},{value:"right"},{value:"top"},{value:"bottom"},],optional:true,},rev:{type:Number,optional:true},},},bounce:{type:Boolean,optional:true},};static defaultProps={bounce:true,};static template="web_tour.TourPointer";static width=28;static height=28;setup(){const positionOptions={margin:6,onPositioned:(pointer,position)=>{const popperRect=pointer.getBoundingClientRect();const{top,left,direction}=position;if(direction==="top"){pointer.style.bottom=`${window.innerHeight - top - popperRect.height}px`;pointer.style.removeProperty("top");}else if(direction==="left"){pointer.style.right=`${window.innerWidth - left - popperRect.width}px`;pointer.style.removeProperty("left");}},};Object.defineProperty(positionOptions,"position",{get:()=>this.position,enumerable:true});const position=usePosition("pointer",()=>this.props.pointerState.anchor,positionOptions);const rootRef=useRef("pointer");let dimensions=null;let lastMeasuredContent=null;let lastOpenState=this.isOpen;let lastAnchor;let[anchorX,anchorY]=[0,0];useEffect(()=>{const{el:pointer}=rootRef;if(pointer){const hasContentChanged=lastMeasuredContent!==this.content;const hasOpenStateChanged=lastOpenState!==this.isOpen;lastOpenState=this.isOpen;if(hasContentChanged){lastMeasuredContent=this.content;pointer.style.removeProperty("width");pointer.style.removeProperty("height");dimensions=pointer.getBoundingClientRect();}
if(hasContentChanged||hasOpenStateChanged){const[width,height]=this.isOpen?[dimensions.width,dimensions.height]:[this.constructor.width,this.constructor.height];if(this.isOpen){pointer.style.removeProperty("transition");}else{pointer.style.setProperty("transition","none");}
pointer.style.setProperty("width",`${width}px`);pointer.style.setProperty("height",`${height}px`);}
if(!this.isOpen){const{anchor}=this.props.pointerState;if(anchor===lastAnchor){const{x,y,width}=anchor.getBoundingClientRect();const[lastAnchorX,lastAnchorY]=[anchorX,anchorY];[anchorX,anchorY]=[x,y];const delta=Math.sqrt(Math.pow(x-lastAnchorX,2)+Math.pow(y-lastAnchorY,2));if(delta<1){position.lock();return;}
const wouldOverflow=window.innerWidth-x-width/2<dimensions?.width;pointer.classList.toggle("o_expand_left",wouldOverflow);}
lastAnchor=anchor;pointer.style.bottom="";pointer.style.right="";position.unlock();}}else{lastMeasuredContent=null;lastOpenState=false;lastAnchor=null;dimensions=null;}});}
get content(){return this.props.pointerState.content||"";}
get isOpen(){return this.props.pointerState.isOpen;}
get position(){return this.props.pointerState.position||"top";}}
return __exports;});;

/* /web_tour/static/src/tour_service/tour_compilers.js */
odoo.define('@web_tour/tour_service/tour_compilers',['@web/core/browser/browser','@web/core/utils/timing','@web/core/utils/ui','@web_tour/tour_service/tour_state','@web_tour/tour_service/tour_utils'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{debounce}=require("@web/core/utils/timing");const{isVisible}=require("@web/core/utils/ui");const{tourState}=require("@web_tour/tour_service/tour_state");const{callWithUnloadCheck,getConsumeEventType,getFirstVisibleElement,getJQueryElementFromSelector,getScrollParent,RunningTourActionHelper,}=require("@web_tour/tour_service/tour_utils");function findTrigger(selector,inModal,shadowDOM){const $target=$(shadowDOM?document.querySelector(shadowDOM)?.shadowRoot:document);const $visibleModal=$target.find(".modal:visible").last();let $el;if(inModal!==false&&$visibleModal.length){$el=$visibleModal.find(selector);}else{$el=getJQueryElementFromSelector(selector,$target);}
return getFirstVisibleElement($el).get(0);}
function findExtraTrigger(selector,shadowDOM){const $target=$(shadowDOM?document.querySelector(shadowDOM)?.shadowRoot:document);const $el=getJQueryElementFromSelector(selector,$target);return getFirstVisibleElement($el).get(0);}
function findStepTriggers(step){const triggerEl=findTrigger(step.trigger,step.in_modal,step.shadow_dom);const altEl=findTrigger(step.alt_trigger,step.in_modal,step.shadow_dom);const skipEl=findTrigger(step.skip_trigger,step.in_modal,step.shadow_dom);const extraTriggerOkay=step.extra_trigger?findExtraTrigger(step.extra_trigger,step.shadow_dom):true;return{triggerEl,altEl,extraTriggerOkay,skipEl};}
function describeStep(step){return step.content?`${step.content} (trigger: ${step.trigger})`:step.trigger;}
function describeFailedStepSimple(step,tour){return`Tour ${tour.name} failed at step ${describeStep(step)}`;}
function describeFailedStepDetailed(step,tour){const offset=3;const stepIndex=tour.steps.findIndex((s)=>s===step);const start=stepIndex-offset>=0?stepIndex-offset:0;const end=stepIndex+offset+1<=tour.steps.length?stepIndex+offset+1:tour.steps.length;let result="";for(let i=start;i<end;i++){const highlight=i===stepIndex;const stepString=JSON.stringify(tour.steps[i],(_key,value)=>{if(typeof value==="function"){return"[function]";}else{return value;}},2);result+=`\n${highlight ? "----- FAILING STEP -----\n" : ""}${stepString},${
            highlight ? "\n-----------------------" : ""
        }`;}
return`${describeFailedStepSimple(step, tour)}\n\n${result.trim()}`;}
function getAnchorEl(el,consumeEvent){if(consumeEvent==="drag"){return el.closest(".ui-draggable, .o_draggable");}
if(consumeEvent==="input"&&!["textarea","input"].includes(el.tagName.toLowerCase())){return el.closest("[contenteditable='true']");}
if(consumeEvent==="sort"){return el.closest(".ui-sortable, .o_sortable");}
return el;}
function canContinue(el,step){const rootNode=el.getRootNode();const isInDoc=rootNode instanceof ShadowRoot?el.ownerDocument.contains(rootNode.host):el.ownerDocument.contains(el);const isElement=el instanceof el.ownerDocument.defaultView.Element||el instanceof Element;const isBlocked=document.body.classList.contains("o_ui_blocked")||document.querySelector(".o_blockUI");return(isInDoc&&isElement&&!isBlocked&&(!step.allowInvisible?isVisible(el):true)&&(!el.disabled||step.isCheck));}
function setupListeners({anchorEl,consumeEvent,onMouseEnter,onMouseLeave,onScroll,onConsume,}){anchorEl.addEventListener(consumeEvent,onConsume);anchorEl.addEventListener("mouseenter",onMouseEnter);anchorEl.addEventListener("mouseleave",onMouseLeave);const cleanups=[()=>{anchorEl.removeEventListener(consumeEvent,onConsume);anchorEl.removeEventListener("mouseenter",onMouseEnter);anchorEl.removeEventListener("mouseleave",onMouseLeave);},];const scrollEl=getScrollParent(anchorEl);if(scrollEl){const debouncedOnScroll=debounce(onScroll,50);scrollEl.addEventListener("scroll",debouncedOnScroll);cleanups.push(()=>scrollEl.removeEventListener("scroll",debouncedOnScroll));}
return()=>{while(cleanups.length){cleanups.pop()();}};}
__exports.compileStepManual=compileStepManual;function compileStepManual(stepIndex,step,options){const{tour,pointer,onStepConsummed}=options;let proceedWith=null;let removeListeners=()=>{};return[{action:()=>console.log(step.trigger),},{trigger:()=>{removeListeners();if(proceedWith){return proceedWith;}
const{triggerEl,altEl,extraTriggerOkay,skipEl}=findStepTriggers(step);if(skipEl){return skipEl;}
const stepEl=extraTriggerOkay&&(triggerEl||altEl);if(stepEl&&canContinue(stepEl,step)){const consumeEvent=step.consumeEvent||getConsumeEventType(stepEl,step.run);const anchorEl=getAnchorEl(stepEl,consumeEvent);const debouncedToggleOpen=debounce(pointer.showContent,50,true);const updatePointer=()=>{pointer.setState({onMouseEnter:()=>debouncedToggleOpen(true),onMouseLeave:()=>debouncedToggleOpen(false),});pointer.pointTo(anchorEl,step);};removeListeners=setupListeners({anchorEl,consumeEvent,onMouseEnter:()=>pointer.showContent(true),onMouseLeave:()=>pointer.showContent(false),onScroll:updatePointer,onConsume:()=>{proceedWith=stepEl;pointer.hide();},});updatePointer();}else{pointer.hide();}},action:()=>{tourState.set(tour.name,"currentIndex",stepIndex+1);pointer.hide();proceedWith=null;onStepConsummed(tour,step);},},];}
let tourTimeout;__exports.compileStepAuto=compileStepAuto;function compileStepAuto(stepIndex,step,options){const{tour,pointer,stepDelay,keepWatchBrowser,showPointerDuration,onStepConsummed}=options;let skipAction=false;return[{action:async()=>{await new Promise(resolve=>requestAnimationFrame(resolve))},},{action:async()=>{skipAction=false;console.log(`Tour ${tour.name} on step: '${describeStep(step)}'`);if(!keepWatchBrowser){browser.clearTimeout(tourTimeout);tourTimeout=browser.setTimeout(()=>{console.warn(describeFailedStepDetailed(step,tour));console.error(describeFailedStepSimple(step,tour));},(step.timeout||10000)+stepDelay);}
await new Promise((resolve)=>browser.setTimeout(resolve,stepDelay));},},{trigger:()=>{const{triggerEl,altEl,extraTriggerOkay,skipEl}=findStepTriggers(step);let stepEl=extraTriggerOkay&&(triggerEl||altEl);if(skipEl){skipAction=true;stepEl=skipEl;}
if(!stepEl){return false;}
return canContinue(stepEl,step)&&stepEl;},action:async(stepEl)=>{tourState.set(tour.name,"currentIndex",stepIndex+1);if(skipAction){return;}
const consumeEvent=step.consumeEvent||getConsumeEventType(stepEl,step.run);const $anchorEl=$(stepEl);if(showPointerDuration>0){pointer.pointTo($anchorEl.get(0),step);await new Promise((r)=>browser.setTimeout(r,showPointerDuration));pointer.hide();}
const actionHelper=new RunningTourActionHelper({consume_event:consumeEvent,$anchor:$anchorEl,});let result;if(typeof step.run==="function"){const willUnload=await callWithUnloadCheck(()=>step.run.call({$anchor:$anchorEl},actionHelper));result=willUnload&&"will unload";}else if(step.run!==undefined){const m=step.run.match(/^([a-zA-Z0-9_]+) *(?:\(? *(.+?) *\)?)?$/);actionHelper[m[1]](m[2]);}else if(!step.isCheck){if(stepIndex===tour.steps.length-1){console.warn('Tour %s: ignoring action (auto) of last step',tour.name);}else{actionHelper.auto();}}
return result;},},{action:()=>{onStepConsummed(tour,step);},},];}
__exports.compileTourToMacro=compileTourToMacro;function compileTourToMacro(tour,options){const{filteredSteps,stepCompiler,pointer,stepDelay,keepWatchBrowser,showPointerDuration,checkDelay,onStepConsummed,onTourEnd,}=options;const currentStepIndex=tourState.get(tour.name,"currentIndex");return{...tour,checkDelay,steps:filteredSteps.reduce((newSteps,step,i)=>{if(i<currentStepIndex){return newSteps;}else{return[...newSteps,...stepCompiler(i,step,{tour,pointer,stepDelay,keepWatchBrowser,showPointerDuration,onStepConsummed,}),];}},[]).concat([{action(){tourState.clear(tour.name);onTourEnd(tour);clearTimeout(tourTimeout);},},]),};}
return __exports;});;

/* /web_tour/static/src/tour_service/tour_pointer_state.js */
odoo.define('@web_tour/tour_service/tour_pointer_state',['@odoo/owl','@web/core/l10n/translation','@web_tour/tour_pointer/tour_pointer','@web_tour/tour_service/tour_utils'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{_t}=require("@web/core/l10n/translation");const{TourPointer}=require("@web_tour/tour_pointer/tour_pointer");const{getScrollParent}=require("@web_tour/tour_service/tour_utils");class Intersection{constructor(){this.currentTarget=null;this.rootBounds=null;this._targetPosition="unknown";this._observer=new IntersectionObserver((observations)=>this._handleObservations(observations));}
_handleObservations(observations){if(observations.length<1){return;}
const observation=observations[observations.length-1];this.rootBounds=observation.rootBounds;if(this.rootBounds&&this.currentTarget){if(observation.isIntersecting){this._targetPosition="in";}else{const targetBounds=this.currentTarget.getBoundingClientRect();if(targetBounds.bottom<this.rootBounds.height/2){this._targetPosition="out-above";}else if(targetBounds.top>this.rootBounds.height/2){this._targetPosition="out-below";}}}else{this._targetPosition="unknown";}}
get targetPosition(){if(!this.rootBounds){return this.currentTarget?"in":"unknown";}else{return this._targetPosition;}}
setTarget(newTarget){if(this.currentTarget!==newTarget){if(this.currentTarget){this._observer.unobserve(this.currentTarget);}
if(newTarget){this._observer.observe(newTarget);}
this.currentTarget=newTarget;}}
stop(){this._observer.disconnect();}}
__exports.createPointerState=createPointerState;function createPointerState(){const setState=(newState)=>{Object.assign(state,newState);};const pointTo=(anchor,step)=>{intersection.setTarget(anchor);if(anchor){let{position,content}=step;switch(intersection.targetPosition){case"unknown":{break;}
case"in":{if(document.body.contains(floatingAnchor)){floatingAnchor.remove();}
setState({anchor,content,onClick:null,position,isVisible:true});break;}
default:{const onClick=()=>{anchor.scrollIntoView({behavior:"smooth",block:"nearest"});hide();};const scrollParent=getScrollParent(anchor);if(!scrollParent){setState({anchor,content,onClick:null,position,isVisible:true});return;}
let{x,y,width,height}=scrollParent.getBoundingClientRect();const iframeEl=scrollParent.ownerDocument.defaultView.frameElement;if(iframeEl){const iframeOffset=iframeEl.getBoundingClientRect();x+=iframeOffset.x;y+=iframeOffset.y;}
floatingAnchor.style.left=`${x + width / 2}px`;if(intersection.targetPosition==="out-below"){position="top";content=_t("Scroll down to reach the next step.");floatingAnchor.style.top=`${y + height - TourPointer.height}px`;}else if(intersection.targetPosition==="out-above"){position="bottom";content=_t("Scroll up to reach the next step.");floatingAnchor.style.top=`${y + TourPointer.height}px`;}
if(!document.contains(floatingAnchor)){document.body.appendChild(floatingAnchor);}
setState({anchor:floatingAnchor,content,onClick,position,isVisible:true,});}}}else{hide();}};function hide(){setState({content:"",isVisible:false,isOpen:false});}
function showContent(isOpen){setState({isOpen});}
function destroy(){intersection.stop();if(document.body.contains(floatingAnchor)){floatingAnchor.remove();}}
const state=reactive({});const intersection=new Intersection();const floatingAnchor=document.createElement("div");floatingAnchor.className="position-fixed";return{state,methods:{setState,showContent,pointTo,hide,destroy}};}
return __exports;});;

/* /web_tour/static/src/tour_service/tour_service.js */
odoo.define('@web_tour/tour_service/tour_service',['@odoo/owl','@web/core/browser/browser','@web/core/l10n/translation','@web/core/macro','@web/core/registry','@web/core/transition','@web/session','@web_tour/tour_pointer/tour_pointer','@web_tour/tour_service/tour_compilers','@web_tour/tour_service/tour_pointer_state','@web_tour/tour_service/tour_state','@web_tour/tour_service/tour_utils'],function(require){'use strict';let __exports={};const{EventBus,markup,whenReady,reactive}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{_t}=require("@web/core/l10n/translation");const{MacroEngine}=require("@web/core/macro");const{registry}=require("@web/core/registry");const{config:transitionConfig}=require("@web/core/transition");const{session}=require("@web/session");const{TourPointer}=require("@web_tour/tour_pointer/tour_pointer");const{compileStepAuto,compileStepManual,compileTourToMacro}=require("@web_tour/tour_service/tour_compilers");const{createPointerState}=require("@web_tour/tour_service/tour_pointer_state");const{tourState}=require("@web_tour/tour_service/tour_state");const{callWithUnloadCheck}=require("@web_tour/tour_service/tour_utils");const tourService=__exports.tourService={dependencies:["orm","effect","ui","overlay","localization"],start:async(_env,{orm,effect,ui,overlay})=>{await whenReady();const toursEnabled="tour_disable"in session&&!session.tour_disable;const consumedTours=new Set(session.web_tours);const tours={};const tourRegistry=registry.category("web_tour.tours");function register(name,tour){name=tour.saveAs||name;const wait_for=tour.wait_for||Promise.resolve();let steps;tours[name]={wait_for,name,get steps(){if(typeof tour.steps!=="function"){throw new Error(`tour.steps has to be a function that returns TourStep[]`);}
if(!steps){steps=tour.steps().map((step)=>{step.shadow_dom=step.shadow_dom??tour.shadow_dom;return step;});}
return steps;},shadow_dom:tour.shadow_dom,url:tour.url,rainbowMan:tour.rainbowMan===undefined?true:!!tour.rainbowMan,rainbowManMessage:tour.rainbowManMessage,fadeout:tour.fadeout||"medium",sequence:tour.sequence||1000,test:tour.test,checkDelay:tour.checkDelay,};wait_for.then(()=>{if(!tour.test&&toursEnabled&&!consumedTours.has(name)&&!tourState.getActiveTourNames().includes(name)){startTour(name,{mode:"manual",redirect:false});}});}
for(const[name,tour]of tourRegistry.getEntries()){register(name,tour);}
tourRegistry.addEventListener("UPDATE",({detail:{key,value}})=>{if(tourRegistry.contains(key)){register(key,value);if(tourState.getActiveTourNames().includes(key)&&(toursEnabled||tourState.get(key,"mode")==="auto")){resumeTour(key);}}else{delete tours[value];}});const bus=new EventBus();const macroEngine=new MacroEngine({target:document});const pointers=reactive({});const runningTours=new Set();const possiblePointTos=[];function createPointer(tourName,config){const{state:pointerState,methods}=createPointerState();let remove;return{start(){pointers[tourName]={methods,id:tourName,component:TourPointer,props:{pointerState,...config},};remove=overlay.add(pointers[tourName].component,pointers[tourName].props);},stop(){remove?.();delete pointers[tourName];methods.destroy();},...methods,async pointTo(anchor,step){possiblePointTos.push([tourName,()=>methods.pointTo(anchor,step)]);await Promise.resolve();if(!possiblePointTos.length){return;}
const toursByPriority=Object.fromEntries(getSortedTours().map((t,i)=>[t.name,i]));const sortedPointTos=possiblePointTos.slice(0).sort(([a],[b])=>toursByPriority[a]-toursByPriority[b]);possiblePointTos.splice(0);const active=sortedPointTos[0];const[activeId,enablePointer]=active||[];for(const{id,methods}of Object.values(pointers)){if(id===activeId){enablePointer();}else{methods.hide();}}},};}
function shouldOmit(step,mode){const isDefined=(key,obj)=>key in obj&&obj[key]!==undefined;const getEdition=()=>(session.server_version_info||[]).at(-1)==="e"?"enterprise":"community";const correctEdition=isDefined("edition",step)?step.edition===getEdition():true;const correctDevice=isDefined("mobile",step)?step.mobile===ui.isSmall:true;return(!correctEdition||!correctDevice||(mode==="manual"&&step.auto));}
function convertToMacro(tour,pointer,{mode,stepDelay,keepWatchBrowser,showPointerDuration}){const stepCompiler=mode==="auto"?compileStepAuto:compileStepManual;const checkDelay=mode==="auto"?tour.checkDelay:100;const filteredSteps=tour.steps.filter((step)=>!shouldOmit(step,mode));return compileTourToMacro(tour,{filteredSteps,stepCompiler,pointer,stepDelay,keepWatchBrowser,showPointerDuration,checkDelay,onStepConsummed(tour,step){bus.trigger("STEP-CONSUMMED",{tour,step});},onTourEnd({name,rainbowManMessage,fadeout}){if(mode==="auto"){transitionConfig.disabled=false;}
let message;if(typeof rainbowManMessage==="function"){message=rainbowManMessage({isTourConsumed:(name)=>consumedTours.has(name),});}else if(typeof rainbowManMessage==="string"){message=rainbowManMessage;}else{message=markup(_t("<strong><b>Good job!</b> You went through all steps of this tour.</strong>"));}
effect.add({type:"rainbow_man",message,fadeout});if(mode==="manual"){consumedTours.add(name);orm.call("web_tour.tour","consume",[[name]]);}
pointer.stop();browser.console.log("test successful");runningTours.delete(name);},});}
function observeShadows(shadowHostSelectors){const observer=new MutationObserver(()=>{const shadowRoots=[];for(const selector of shadowHostSelectors){const shadowHost=document.querySelector(selector);if(shadowHost){shadowRoots.push(shadowHost.shadowRoot);shadowHostSelectors.delete(selector);}}
for(const shadowRoot of shadowRoots){macroEngine.observer.observe(shadowRoot,macroEngine.observerOptions);}
if(shadowHostSelectors.size===0){observer.disconnect();}});observer.observe(macroEngine.target,{childList:true,subtree:true});}
function setupShadowObservers(tour){const shadowDOMs=new Set(tour.steps.filter((step)=>step.shadow_dom).map((step)=>step.shadow_dom));if(shadowDOMs.size>0){observeShadows(shadowDOMs);}}
function activateMacro(macro,mode){if(mode==="auto"){transitionConfig.disabled=true;}
macroEngine.activate(macro,mode==="auto");}
function startTour(tourName,options={}){if(runningTours.has(tourName)&&options.mode==="manual"){return;}
runningTours.add(tourName);const defaultOptions={stepDelay:0,keepWatchBrowser:false,mode:"auto",startUrl:"",showPointerDuration:0,redirect:true,};options=Object.assign(defaultOptions,options);const tour=tours[tourName];if(!tour){throw new Error(`Tour '${tourName}' is not found.`);}
tourState.set(tourName,"currentIndex",0);tourState.set(tourName,"stepDelay",options.stepDelay);tourState.set(tourName,"keepWatchBrowser",options.keepWatchBrowser);tourState.set(tourName,"showPointerDuration",options.showPointerDuration);tourState.set(tourName,"mode",options.mode);tourState.set(tourName,"sequence",tour.sequence);const pointer=createPointer(tourName,{bounce:!(options.mode==="auto"&&options.keepWatchBrowser),});const macro=convertToMacro(tour,pointer,options);const willUnload=callWithUnloadCheck(()=>{if(tour.url&&tour.url!==options.startUrl&&options.redirect){window.location.href=window.location.origin+tour.url;}});if(!willUnload){setupShadowObservers(tour);pointer.start();activateMacro(macro,options.mode);}}
function resumeTour(tourName){if(runningTours.has(tourName)){return;}
runningTours.add(tourName);const tour=tours[tourName];const stepDelay=tourState.get(tourName,"stepDelay");const keepWatchBrowser=tourState.get(tourName,"keepWatchBrowser");const showPointerDuration=tourState.get(tourName,"showPointerDuration");const mode=tourState.get(tourName,"mode");const pointer=createPointer(tourName,{bounce:!(mode==="auto"&&keepWatchBrowser),});const macro=convertToMacro(tour,pointer,{mode,stepDelay,keepWatchBrowser,showPointerDuration,});setupShadowObservers(tour);pointer.start();activateMacro(macro,mode);}
function getSortedTours(){return Object.values(tours).sort((t1,t2)=>{return t1.sequence-t2.sequence||(t1.name<t2.name?-1:1);});}
if(!window.frameElement){for(const tourName of tourState.getActiveTourNames()){if(tourName in tours){resumeTour(tourName);}}}
odoo.startTour=startTour;odoo.isTourReady=(tourName)=>tours[tourName].wait_for.then(()=>true);return{bus,startTour,getSortedTours,};},};registry.category("services").add("tour_service",tourService);return __exports;});;

/* /web_tour/static/src/tour_service/tour_state.js */
odoo.define('@web_tour/tour_service/tour_state',['@web/core/browser/browser'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const BOOLEAN={toLocalStorage:(val)=>(val?"1":"0"),fromLocalStorage:(val)=>(val==="1"?true:false),};const INTEGER={toLocalStorage:(val)=>val.toString(),fromLocalStorage:(val)=>parseInt(val,10),};const STRING={toLocalStorage:(x)=>x,fromLocalStorage:(x)=>x,};const ALLOWED_KEYS={keepWatchBrowser:BOOLEAN,showPointerDuration:INTEGER,currentIndex:INTEGER,stepDelay:INTEGER,mode:STRING,sequence:INTEGER,};function getPrefixedName(tourName,key){return`tour__${tourName}__${key}`;}
function destructurePrefixedName(prefixedName){const match=prefixedName.match(/tour__([.\w]+)__([\w]+)/);return match?[match[1],match[2]]:null;}
const tourState=__exports.tourState={get(tourName,key){if(!(key in ALLOWED_KEYS)){throw new Error(`Invalid key: '${key}' (tourName = '${tourName}')`);}
const prefixedName=getPrefixedName(tourName,key);const savedValue=browser.localStorage.getItem(prefixedName);return ALLOWED_KEYS[key].fromLocalStorage(savedValue);},set(tourName,key,value){if(!(key in ALLOWED_KEYS)){throw new Error(`Invalid key: '${key}' (tourName = '${tourName}')`);}
const prefixedName=getPrefixedName(tourName,key);browser.localStorage.setItem(prefixedName,ALLOWED_KEYS[key].toLocalStorage(value));},clear(tourName){for(const key in ALLOWED_KEYS){const prefixedName=getPrefixedName(tourName,key);browser.localStorage.removeItem(prefixedName);}},getActiveTourNames(){const tourNames=new Set();for(const key of Object.keys(browser.localStorage)){const[tourName]=destructurePrefixedName(key)||[false];if(tourName){tourNames.add(tourName);}}
return[...tourNames].sort((a,b)=>this.get(a,"sequence")-this.get(b,"sequence"));},};return __exports;});;

/* /web_tour/static/src/tour_service/tour_utils.js */
odoo.define('@web_tour/tour_service/tour_utils',['@odoo/owl','@web/core/l10n/translation','@web/core/ui/ui_service','@web/core/utils/ui'],function(require){'use strict';let __exports={};const{markup}=require("@odoo/owl");const{_t}=require("@web/core/l10n/translation");const{utils}=require("@web/core/ui/ui_service");const{_legacyIsVisible}=require("@web/core/utils/ui");const TourError=__exports.TourError=class TourError extends Error{constructor(message,...args){super(message,...args);this.message=`(TourError) ${message}`;}}
__exports.callWithUnloadCheck=callWithUnloadCheck;function callWithUnloadCheck(func,...args){let willUnload=false;const beforeunload=()=>(willUnload=true);window.addEventListener("beforeunload",beforeunload);const result=func(...args);if(result instanceof Promise){return result.then(()=>{window.removeEventListener("beforeunload",beforeunload);return willUnload;});}else{window.removeEventListener("beforeunload",beforeunload);return willUnload;}}
__exports.getFirstVisibleElement=getFirstVisibleElement;function getFirstVisibleElement($elements){for(var i=0;i<$elements.length;i++){var $i=$elements.eq(i);if(_legacyIsVisible($i[0])){return $i;}}
return $();}
__exports.getJQueryElementFromSelector=getJQueryElementFromSelector;function getJQueryElementFromSelector(selector,$target){$target=$target||$(document);const iframeSplit=typeof selector==="string"&&selector.match(/(.*\biframe[^ ]*)(.*)/);if(iframeSplit&&iframeSplit[2]){var $iframe=$target.find(`${iframeSplit[1]}:not(.o_ignore_in_tour)`);if($iframe.is('[is-ready="false"]')){return $();}
var $el=$iframe.contents().find(iframeSplit[2]);$el.iframeContainer=$iframe[0];return $el;}else if(typeof selector==="string"){return $target.find(selector);}else{return $(selector);}}
__exports.getConsumeEventType=getConsumeEventType;function getConsumeEventType(element,runCommand){if(!element){return"click";}
const{classList,tagName,type}=element;const tag=tagName.toLowerCase();if(classList.contains("o_field_many2one")){return"autocompleteselect";}
if(tag==="textarea"||(tag==="input"&&(!type||["email","number","password","search","tel","text","url"].includes(type)))){if(utils.isSmall()&&element.closest(".o_field_widget")?.matches(".o_field_many2one, .o_field_many2many")){return"click";}
return"input";}
if(classList.contains("ui-draggable-handle")){return"mousedown";}
if(typeof runCommand==="string"&&/^drag_and_drop/.test(runCommand)){if(element.closest(".ui-sortable")){return"sort";}
if((/^drag_and_drop_native/.test(runCommand)&&classList.contains("o_draggable"))||element.closest(".o_draggable")){return"pointerdown";}}
return"click";}
__exports.getDifferentParents=getDifferentParents;function getDifferentParents(n1,n2){const parents=[n2];while(parents[0].parentNode){const parent=parents[0].parentNode;if(parent.contains(n1)){break;}
parents.unshift(parent);}
return parents;}
__exports.getScrollParent=getScrollParent;function getScrollParent(element){if(!element){return null;}
if(element.scrollHeight>element.clientHeight){return element;}else{return getScrollParent(element.parentNode);}}
const triggerPointerEvent=__exports.triggerPointerEvent=(el,type,canBubbleAndBeCanceled,additionalParams)=>{const eventInit={bubbles:canBubbleAndBeCanceled,cancelable:canBubbleAndBeCanceled,view:window,...additionalParams,};el.dispatchEvent(new PointerEvent(type,eventInit));if(type.startsWith("pointer")){el.dispatchEvent(new MouseEvent(type.replace("pointer","mouse"),eventInit));}};const RunningTourActionHelper=__exports.RunningTourActionHelper=class RunningTourActionHelper{constructor(tip_widget){this.tip_widget=tip_widget;}
click(element){this._click(this._get_action_values(element));}
dblclick(element){this._click(this._get_action_values(element),2);}
tripleclick(element){this._click(this._get_action_values(element),3);}
clicknoleave(element){this._click(this._get_action_values(element),1,false);}
text(text,element){this._text(this._get_action_values(element),text);}
remove_text(text,element){this._text(this._get_action_values(element),"\n");}
text_blur(text,element){this._text_blur(this._get_action_values(element),text);}
range(text,element){this._range(this._get_action_values(element),text);}
drag_and_drop(to,element){this._drag_and_drop_jquery(this._get_action_values(element),to);}
drag_and_drop_native(toSel,element){const to=getJQueryElementFromSelector(toSel)[0];this._drag_and_drop(this._get_action_values(element).$element[0],to);}
keydown(keyCodes,element){this._keydown(this._get_action_values(element),keyCodes.split(/[,\s]+/));}
auto(element){var values=this._get_action_values(element);if(values.consume_event==="input"){this._text(values);}else{this._click(values);}}
_get_action_values(element){var $e=getJQueryElementFromSelector(element);var $element=element?getFirstVisibleElement($e):this.tip_widget.$anchor;if($element.length===0){$element=$e.first();}
var consume_event=element?getConsumeEventType($element[0]):this.tip_widget.consume_event;return{$element:$element,consume_event:consume_event,};}
_click(values,nb,leave){const target=values.$element[0];triggerPointerEvent(target,"pointerover",true);triggerPointerEvent(target,"pointerenter",false);triggerPointerEvent(target,"pointermove",true);for(let i=1;i<=(nb||1);i++){triggerPointerEvent(target,"pointerdown",true);triggerPointerEvent(target,"pointerup",true);triggerPointerEvent(target,"click",true,{detail:i});if(i%2===0){triggerPointerEvent(target,"dblclick",true);}}
if(leave!==false){triggerPointerEvent(target,"pointerout",true);triggerPointerEvent(target,"pointerleave",false);}}
_text(values,text){this._click(values);text=text||"Test";if(values.consume_event==="input"){values.$element.trigger({type:"keydown",key:text[text.length-1]}).val(text).trigger({type:"keyup",key:text[text.length-1]});values.$element[0].dispatchEvent(new InputEvent("input",{bubbles:true,}));}else if(values.$element.is("select")){var $options=values.$element.find("option");$options.prop("selected",false).removeProp("selected");var $selectedOption=$options.filter(function(){return $(this).val()===text;});if($selectedOption.length===0){$selectedOption=$options.filter(function(){return $(this).text().trim()===text;});}
const regex=/option\s+([0-9]+)/;if($selectedOption.length===0&&regex.test(text)){const position=parseInt(regex.exec(text)[1]);$selectedOption=$options.eq(position-1);}
$selectedOption.prop("selected",true);this._click(values);values.$element.trigger("input");}else{values.$element.focusIn();values.$element.trigger($.Event("keydown",{key:"_"}));values.$element.text(text).trigger("input");values.$element.focusInEnd();values.$element.trigger($.Event("keyup",{key:"_"}));}
values.$element[0].dispatchEvent(new Event("change",{bubbles:true,cancelable:false}));}
_text_blur(values,text){this._text(values,text);values.$element.trigger("focusout");values.$element.trigger("blur");}
_range(values,text){values.$element[0].value=text;values.$element[0].dispatchEvent(new Event('change',{bubbles:true,cancelable:false}));}
_calculateCenter($el,selector){const center=$el.offset();if(selector&&selector.indexOf("iframe")!==-1){const iFrameOffset=$("iframe").offset();center.left+=iFrameOffset.left;center.top+=iFrameOffset.top;}
center.left+=$el.outerWidth()/2;center.top+=$el.outerHeight()/2;return center;}
_drag_and_drop_jquery(values,to){var $to;const elementCenter=this._calculateCenter(values.$element);if(to){$to=getJQueryElementFromSelector(to);}else{$to=$(document.body);}
values.$element.trigger($.Event("mouseenter"));values.$element.trigger($.Event("mousedown",{which:1,pageX:elementCenter.left+1,pageY:elementCenter.top,}));if(!$to.length){values.$element.trigger($.Event("mousemove",{which:1,pageX:elementCenter.left+1,pageY:elementCenter.top,}));$to=getJQueryElementFromSelector(to);}
let toCenter=this._calculateCenter($to,to);values.$element.trigger($.Event("mousemove",{which:1,pageX:toCenter.left,pageY:toCenter.top}));toCenter=this._calculateCenter($to,to);values.$element.trigger($.Event("mouseup",{which:1,pageX:toCenter.left,pageY:toCenter.top}));}
_drag_and_drop(source,target){const sourceRect=source.getBoundingClientRect();const sourcePosition={clientX:sourceRect.x+sourceRect.width/2,clientY:sourceRect.y+sourceRect.height/2,};const targetRect=target.getBoundingClientRect();const targetPosition={clientX:targetRect.x+targetRect.width/2,clientY:targetRect.y+targetRect.height/2,};triggerPointerEvent(source,"pointerdown",true,sourcePosition);triggerPointerEvent(source,"pointermove",true,targetPosition);for(const parent of getDifferentParents(source,target)){triggerPointerEvent(parent,"pointerenter",false,targetPosition);}
triggerPointerEvent(target,"pointerup",true,targetPosition);}
_keydown(values,keyCodes){while(keyCodes.length){const eventOptions={};const keyCode=keyCodes.shift();let insertedText=null;if(isNaN(keyCode)){eventOptions.key=keyCode;}else{const code=parseInt(keyCode,10);if(code===32||(code>47&&code<58)||(code>64&&code<91)||(code>95&&code<112)||(code>185&&code<193)||(code>218&&code<223)){insertedText=String.fromCharCode(code);}}
values.$element.trigger(Object.assign({type:"keydown"},eventOptions));if(insertedText){values.$element[0].ownerDocument.execCommand("insertText",0,insertedText);}
values.$element.trigger(Object.assign({type:"keyup"},eventOptions));}}}
const stepUtils=__exports.stepUtils={_getHelpMessage(functionName,...args){return`Generated by function tour utils ${functionName}(${args.join(", ")})`;},addDebugHelp(helpMessage,step){if(typeof step.debugHelp==="string"){step.debugHelp=step.debugHelp+"\n"+helpMessage;}else{step.debugHelp=helpMessage;}
return step;},editionEnterpriseModifier(step){step.edition="enterprise";return step;},mobileModifier(step){step.mobile=true;return step;},showAppsMenuItem(){return{edition:"community",trigger:".o_navbar_apps_menu button",auto:true,position:"bottom",};},toggleHomeMenu(){return{edition:"enterprise",trigger:".o_main_navbar .o_menu_toggle",content:markup(_t("Click on the <i>Home icon</i> to navigate across apps.")),position:"bottom",};},autoExpandMoreButtons(extra_trigger){return{trigger:".o-form-buttonbox",extra_trigger:extra_trigger,auto:true,run:(actions)=>{const $more=$(".o-form-buttonbox .o_button_more");if($more.length){actions.click($more);}},};},goBackBreadcrumbsMobile(description,...extraTrigger){return extraTrigger.map((element)=>({mobile:true,trigger:".o_back_button",extra_trigger:element,content:description,position:"bottom",debugHelp:this._getHelpMessage("goBackBreadcrumbsMobile",description,...extraTrigger),}));},goToAppSteps(dataMenuXmlid,description){return[this.showAppsMenuItem(),{trigger:`.o_app[data-menu-xmlid="${dataMenuXmlid}"]`,content:description,position:"right",edition:"community",},{trigger:`.o_app[data-menu-xmlid="${dataMenuXmlid}"]`,content:description,position:"bottom",edition:"enterprise",},].map((step)=>this.addDebugHelp(this._getHelpMessage("goToApp",dataMenuXmlid,description),step));},openBurgerMenu(extraTrigger){return{mobile:true,trigger:".o_mobile_menu_toggle",extra_trigger:extraTrigger,content:_t("Open bugger menu."),position:"bottom",debugHelp:this._getHelpMessage("openBurgerMenu",extraTrigger),};},statusbarButtonsSteps(innerTextButton,description,extraTrigger){return[{mobile:true,auto:true,trigger:".o_statusbar_buttons",extra_trigger:extraTrigger,run:(actions)=>{const $action=$(".o_statusbar_buttons .btn.dropdown-toggle:contains(Action)");if($action.length){actions.click($action);}},},{trigger:`.o_statusbar_buttons button:enabled:contains('${innerTextButton}')`,content:description,position:"bottom",},].map((step)=>this.addDebugHelp(this._getHelpMessage("statusbarButtonsSteps",innerTextButton,description,extraTrigger),step));},simulateEnterKeyboardInSearchModal(){return{mobile:true,trigger:".o_searchview_input",extra_trigger:".modal:not(.o_inactive_modal) .dropdown-menu.o_searchview_autocomplete",position:"bottom",run:(action)=>{const keyEventEnter=new KeyboardEvent("keydown",{bubbles:true,cancelable:true,key:"Enter",code:"Enter",});action.tip_widget.$anchor[0].dispatchEvent(keyEventEnter);},debugHelp:this._getHelpMessage("simulateEnterKeyboardInSearchModal"),};},mobileKanbanSearchMany2X(modalTitle,valueSearched){return[{mobile:true,trigger:`.o_control_panel_navigation .btn .fa-search`,position:"bottom",},{mobile:true,trigger:".o_searchview_input",extra_trigger:`.modal:not(.o_inactive_modal) .modal-title:contains('${modalTitle}')`,position:"bottom",run:`text ${valueSearched}`,},this.simulateEnterKeyboardInSearchModal(),{mobile:true,trigger:`.o_kanban_record .o_kanban_record_title :contains('${valueSearched}')`,position:"bottom",},].map((step)=>this.addDebugHelp(this._getHelpMessage("mobileKanbanSearchMany2X",modalTitle,valueSearched),step));},saveForm(options={}){return[{content:options.content||"save form",trigger:".o_form_button_save",extra_trigger:options.extra_trigger,run:"click",auto:true,},{content:"wait for save completion",trigger:".o_form_readonly, .o_form_saved",run(){},auto:true,},];},discardForm(options={}){return[{content:options.content||"exit the form",trigger:".o_form_button_cancel",extra_trigger:options.extra_trigger,run:"click",auto:true,},{content:"wait for cancellation to complete",trigger:".o_view_controller.o_list_view, .o_form_view > div > div > .o_form_readonly, .o_form_view > div > div > .o_form_saved",run(){},auto:true,},];},};return __exports;});;

/* /web/static/tests/helpers/cleanup.js */
odoo.define('@web/../tests/helpers/cleanup',[],function(require){'use strict';let __exports={};const cleanups=[];__exports.registerCleanup=registerCleanup;function registerCleanup(callback){cleanups.push(callback);}
if(window.QUnit){QUnit.on("OdooAfterTestHook",(info)=>{if(QUnit.config.debug){return;}
let cleanup;while((cleanup=cleanups.pop())){try{cleanup(info);}catch(error){console.error(error);}}});const validElements=[{tagName:"DIV",attr:"id",value:"qunit",keep:true},{tagName:"DIV",attr:"id",value:"qunit-fixture",keep:true},{tagName:"SCRIPT",attr:"id",value:""},{tagName:"DIV",attr:"class",value:"o_notification_manager"},{tagName:"DIV",attr:"class",value:"tooltip fade bs-tooltip-auto"},{tagName:"DIV",attr:"class",value:"tooltip fade bs-tooltip-auto show"},{tagName:"DIV",attr:"class",value:"tooltip tooltip-field-info fade bs-tooltip-auto"},{tagName:"DIV",attr:"class",value:"tooltip tooltip-field-info fade bs-tooltip-auto show",},{tagName:"SPAN",attr:"class",value:"select2-hidden-accessible"},{tagName:"DIV",attr:"class",value:"ui-helper-hidden-accessible"},{tagName:"UL",attr:"class",value:"ui-menu ui-widget ui-widget-content ui-autocomplete ui-front",},{tagName:"UL",attr:"class",value:"ui-menu ui-widget ui-widget-content ui-autocomplete dropdown-menu ui-front",},];QUnit.on("OdooAfterTestHook",function(info){if(QUnit.config.debug){return;}
const failed=info.testReport.getStatus()==="failed";const toRemove=[];for(const bodyChild of document.body.children){const tolerated=validElements.find((e)=>e.tagName===bodyChild.tagName&&bodyChild.getAttribute(e.attr)===e.value);if(!failed&&!tolerated){QUnit.pushFailure(`Body still contains undesirable elements:\n${bodyChild.outerHTML}`);}
if(!tolerated||!tolerated.keep){toRemove.push(bodyChild);}}
const qunitFixture=document.getElementById("qunit-fixture");if(qunitFixture.children.length){toRemove.push(...qunitFixture.children);}
for(const el of toRemove){el.remove();}
document.body.classList.remove("modal-open");});}
return __exports;});;

/* /web/static/tests/helpers/utils.js */
odoo.define('@web/../tests/helpers/utils',['@web/core/assets','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/network/download','@web/core/utils/concurrency','@web/core/utils/patch','@web/core/utils/ui','@web/core/l10n/translation','@web/../tests/helpers/cleanup','@odoo/owl'],function(require){'use strict';let __exports={};const{templates}=require("@web/core/assets");const{browser}=require("@web/core/browser/browser");const{isMacOS}=require("@web/core/browser/feature_detection");const{download}=require("@web/core/network/download");const{Deferred}=require("@web/core/utils/concurrency");const{patch}=require("@web/core/utils/patch");const{isVisible}=require("@web/core/utils/ui");const{_t}=require("@web/core/l10n/translation");const{registerCleanup}=require("@web/../tests/helpers/cleanup");const{App,onError,onMounted,onPatched,onRendered,onWillDestroy,onWillPatch,onWillRender,onWillStart,onWillUnmount,onWillUpdateProps,useComponent,}=require("@odoo/owl");__exports.patchDate=patchDate;function patchDate(year,month,day,hours,minutes,seconds,ms=0){var RealDate=window.Date;var actualDate=new RealDate();var fakeDate=new RealDate(year,month,day,hours,minutes,seconds,ms);if(!(luxon.Settings.defaultZone instanceof luxon.FixedOffsetZone)){throw new Error("luxon.Settings.defaultZone must be a FixedOffsetZone");}
const browserOffset=-fakeDate.getTimezoneOffset();const patchedOffset=luxon.Settings.defaultZone.offset();const offsetDiff=patchedOffset-browserOffset;const correctedMinutes=fakeDate.getMinutes()-offsetDiff;fakeDate.setMinutes(correctedMinutes);var timeInterval=actualDate.getTime()-fakeDate.getTime();window.Date=(function(NativeDate){function Date(Y,M,D,h,m,s,ms){var length=arguments.length;let date;if(arguments.length>0){date=length==1&&String(Y)===Y?new NativeDate(Date.parse(Y)):length>=7?new NativeDate(Y,M,D,h,m,s,ms):length>=6?new NativeDate(Y,M,D,h,m,s):length>=5?new NativeDate(Y,M,D,h,m):length>=4?new NativeDate(Y,M,D,h):length>=3?new NativeDate(Y,M,D):length>=2?new NativeDate(Y,M):length>=1?new NativeDate(Y):new NativeDate();date.constructor=Date;return date;}else{date=new NativeDate();var time=date.getTime();time-=timeInterval;date.setTime(time);return date;}}
for(var key in NativeDate){Date[key]=NativeDate[key];}
Date.now=function(){var date=new NativeDate();var time=date.getTime();time-=timeInterval;return time;};Date.UTC=NativeDate.UTC;Date.prototype=NativeDate.prototype;Date.prototype.constructor=Date;Date.parse=NativeDate.parse;return Date;})(Date);registerCleanup(()=>{window.Date=RealDate;});}
__exports.patchTimeZone=patchTimeZone;function patchTimeZone(offset){patchWithCleanup(luxon.Settings,{defaultZone:luxon.FixedOffsetZone.instance(offset)});}
__exports.patchWithCleanup=patchWithCleanup;function patchWithCleanup(obj,patchValue){const unpatch=patch(obj,patchValue);registerCleanup(()=>{unpatch();});}
__exports.getFixture=getFixture;function getFixture(){if(!window.QUnit){return document;}
if(QUnit.config.debug){return document.body;}else{return document.getElementById("qunit-fixture");}}
__exports.nextTick=nextTick;async function nextTick(){await new Promise((resolve)=>window.requestAnimationFrame(resolve));await new Promise((resolve)=>setTimeout(resolve));}
__exports.makeDeferred=makeDeferred;function makeDeferred(){return new Deferred();}
__exports.findElement=findElement;function findElement(el,selector){let target=el;if(selector){const els=el.querySelectorAll(selector);if(els.length===0){throw new Error(`No element found (selector: ${selector})`);}
if(els.length>1){throw new Error(`Found ${els.length} elements, instead of 1 (selector: ${selector})`);}
target=els[0];}
return target;}
const mapBubblingEvent=(args)=>({...args,bubbles:true});const mapNonBubblingEvent=(args)=>({...args,bubbles:false});const mapBubblingPointerEvent=(args={})=>({clientX:args.pageX,clientY:args.pageY,...args,bubbles:true,cancelable:true,view:window,});const mapNonBubblingPointerEvent=(args)=>({...mapBubblingPointerEvent(args),bubbles:false,cancelable:false,});const mapCancelableTouchEvent=(args={})=>({...args,bubbles:true,cancelable:true,composed:true,rotation:0.0,touches:args.touches?[...args.touches.map((e)=>new Touch(e))]:undefined,view:window,zoom:1.0,});const mapNonCancelableTouchEvent=(args)=>({...mapCancelableTouchEvent(args),cancelable:false,});const mapKeyboardEvent=(args)=>({...args,bubbles:true,cancelable:true,});const getEventConstructor=(eventType)=>{switch(eventType){case"auxclick":case"click":case"contextmenu":case"dblclick":case"mousedown":case"mouseup":case"mousemove":case"mouseover":case"mouseout":{return[MouseEvent,mapBubblingPointerEvent];}
case"mouseenter":case"mouseleave":{return[MouseEvent,mapNonBubblingPointerEvent];}
case"pointerdown":case"pointerup":case"pointermove":case"pointerover":case"pointerout":{return[PointerEvent,mapBubblingPointerEvent];}
case"pointerenter":case"pointerleave":{return[PointerEvent,mapNonBubblingPointerEvent];}
case"focusin":{return[FocusEvent,mapBubblingEvent];}
case"focus":case"blur":{return[FocusEvent,mapNonBubblingEvent];}
case"cut":case"copy":case"paste":{return[ClipboardEvent,mapBubblingEvent];}
case"keydown":case"keypress":case"keyup":{return[KeyboardEvent,mapKeyboardEvent];}
case"drag":case"dragend":case"dragenter":case"dragstart":case"dragleave":case"dragover":case"drop":{return[DragEvent,mapBubblingEvent];}
case"input":{return[InputEvent,mapBubblingEvent];}
case"compositionstart":case"compositionend":{return[CompositionEvent,mapBubblingEvent];}
case"scroll":{return[UIEvent,mapNonBubblingEvent];}
case"touchstart":case"touchend":case"touchmove":{return[TouchEvent,mapCancelableTouchEvent];}
case"touchcancel":{return[TouchEvent,mapNonCancelableTouchEvent];}
default:{return[Event,mapBubblingEvent];}}};__exports.triggerEvent=triggerEvent;function triggerEvent(el,selector,eventType,eventInit,options={}){const errors=[];const target=findElement(el,selector);if(typeof eventType!=="string"){errors.push("event type must be a string");}
if(!target){errors.push("cannot find target");}else if(!options.skipVisibilityCheck&&!isVisible(target)){errors.push("target is not visible");}
if(errors.length){throw new Error(`Cannot trigger event${eventType ? `"${eventType}"` : ""}${
                selector ? `(with selector"${selector}")` : ""
            }: ${errors.join(" and ")}`);}
const[Constructor,processParams]=getEventConstructor(eventType);const event=new Constructor(eventType,processParams(eventInit));target.dispatchEvent(event);if(window.QUnit&&QUnit.config.debug){const group=`%c[${event.type.toUpperCase()}]`;console.groupCollapsed(group,"color: #b52c9b");console.log(target,event);console.groupEnd(group,"color: #b52c9b");}
if(options.sync){return event;}else{return nextTick().then(()=>event);}}
__exports.triggerEvents=triggerEvents;function triggerEvents(el,selector,eventDefs,options={}){const events=[...eventDefs].map((eventDef)=>{const[eventType,eventInit]=Array.isArray(eventDef)?eventDef:[eventDef,{}];return triggerEvent(el,selector,eventType,eventInit,options);});if(options.sync){return events;}else{return nextTick().then(()=>events);}}
__exports.triggerScroll=triggerScroll;async function triggerScroll(target,coordinates={left:null,top:null},canPropagate=true){const isScrollable=(target.scrollHeight>target.clientHeight&&target.clientHeight>0)||(target.scrollWidth>target.clientWidth&&target.clientWidth>0);if(!isScrollable&&!canPropagate){return;}
if(isScrollable){const canScrollFrom={left:coordinates.left>target.scrollLeft?target.scrollLeft+target.clientWidth<target.scrollWidth:target.scrollLeft>0,top:coordinates.top>target.scrollTop?target.scrollTop+target.clientHeight<target.scrollHeight:target.scrollTop>0,};const scrollCoordinates={};Object.entries(coordinates).forEach(([key,value])=>{if(value!==null&&canScrollFrom[key]){scrollCoordinates[key]=value;delete coordinates[key];}});target.scrollTo(scrollCoordinates);await triggerEvent(target,null,"scroll");if(!canPropagate||!Object.entries(coordinates).length){return;}}
target.parentElement?triggerScroll(target.parentElement,coordinates):triggerEvent(window,null,"scroll");await nextTick();}
__exports.click=click;function click(el,selector,{mouseEventInit={},skipDisabledCheck=false,skipVisibilityCheck=false}={}){if(!skipDisabledCheck&&el.disabled){throw new Error("Can't click on a disabled button");}
return triggerEvents(el,selector,["pointerdown","mousedown","focus","pointerup","mouseup",["click",mouseEventInit]],{skipVisibilityCheck});}
__exports.clickCreate=clickCreate;function clickCreate(htmlElement){if(htmlElement.querySelectorAll(".o_control_panel_main_buttons .d-none.d-xl-inline-flex .o_form_button_create").length){return click(htmlElement,".o_control_panel_main_buttons .d-none.d-xl-inline-flex .o_form_button_create");}else if(htmlElement.querySelectorAll(".o_control_panel_main_buttons .d-none.d-xl-inline-flex .o_list_button_create").length){return click(htmlElement,".o_control_panel_main_buttons .d-none.d-xl-inline-flex .o_list_button_create");}else{throw new Error("No edit button found to be clicked.");}}
__exports.clickEdit=clickEdit;function clickEdit(htmlElement){if(htmlElement.querySelectorAll(".o_list_button_edit").length){return click(htmlElement,".o_list_button_edit");}else{throw new Error("No edit button found to be clicked.");}}
__exports.clickSave=clickSave;async function clickSave(htmlElement){if(htmlElement.querySelectorAll(".o_form_status_indicator").length){await mouseEnter(htmlElement,".o_form_status_indicator");}
if(htmlElement.querySelectorAll(".o_form_button_save").length){return click(htmlElement,".o_form_button_save");}
const listSaveButtons=htmlElement.querySelectorAll(".o_list_button_save");if(listSaveButtons.length){return listSaveButtons.length>=2?click(listSaveButtons[1]):click(listSaveButtons[0]);}else{throw new Error("No save button found to be clicked.");}}
__exports.clickDiscard=clickDiscard;async function clickDiscard(htmlElement){if(htmlElement.querySelectorAll(".o_form_status_indicator").length){await mouseEnter(htmlElement,".o_form_status_indicator");}
if(htmlElement.querySelectorAll(".o_form_button_cancel").length){return click(htmlElement,".o_form_button_cancel");}else if($(htmlElement).find(".o_list_button_discard:visible").length){return click($(htmlElement).find(".o_list_button_discard:visible").get(0));}else{throw new Error("No discard button found to be clicked.");}}
__exports.mouseEnter=mouseEnter;async function mouseEnter(el,selector,coordinates){const target=el.querySelector(selector)||el;const atPos=coordinates||{clientX:target.getBoundingClientRect().left+target.getBoundingClientRect().width/2,clientY:target.getBoundingClientRect().top+target.getBoundingClientRect().height/2,};return triggerEvents(target,null,["pointerenter","mouseenter"],atPos);}
__exports.mouseLeave=mouseLeave;async function mouseLeave(el,selector){const target=el.querySelector(selector)||el;return triggerEvents(target,null,["pointerleave","mouseleave"]);}
__exports.editInput=editInput;async function editInput(el,selector,value){const input=findElement(el,selector);if(!(input instanceof HTMLInputElement||input instanceof HTMLTextAreaElement)){throw new Error("Only 'input' and 'textarea' elements can be edited with 'editInput'.");}
if(!["text","textarea","email","search","color","number","file","tel"].includes(input.type)){throw new Error(`Type "${input.type}" not supported by 'editInput'.`);}
const eventOpts={};if(input.type==="file"){const files=Array.isArray(value)?value:[value];const dataTransfer=new DataTransfer();for(const file of files){if(!(file instanceof File)){throw new Error(`File input value should be one or several File objects.`);}
dataTransfer.items.add(file);}
input.files=dataTransfer.files;eventOpts.skipVisibilityCheck=true;}else{input.value=value;}
await triggerEvents(input,null,["input","change"],eventOpts);if(input.type==="file"){await nextTick();await nextTick();}}
__exports.editSelect=editSelect;function editSelect(el,selector,value){const select=findElement(el,selector);if(select.tagName!=="SELECT"){throw new Error("Only select tag can be edited with selectInput.");}
select.value=value;return triggerEvent(select,null,"change");}
__exports.editSelectMenu=editSelectMenu;async function editSelectMenu(el,selector,value){const dropdown=el.querySelector(selector);await click(dropdown.querySelector(".dropdown-toggle"));for(const item of Array.from(dropdown.querySelectorAll(".dropdown-item"))){if(item.textContent===value){return click(item);}}}
__exports.triggerHotkey=triggerHotkey;async function triggerHotkey(hotkey,addOverlayModParts=false,eventAttrs={}){eventAttrs.key=hotkey.split("+").pop();if(/shift/i.test(hotkey)){eventAttrs.shiftKey=true;}
if(/control/i.test(hotkey)){if(isMacOS()){eventAttrs.metaKey=true;}else{eventAttrs.ctrlKey=true;}}
if(/alt/i.test(hotkey)||addOverlayModParts){if(isMacOS()){eventAttrs.ctrlKey=true;}else{eventAttrs.altKey=true;}}
if(!("bubbles"in eventAttrs)){eventAttrs.bubbles=true;}
const[keydownEvent,keyupEvent]=await triggerEvents(document.activeElement,null,[["keydown",eventAttrs],["keyup",eventAttrs],],{skipVisibilityCheck:true});return{keydownEvent,keyupEvent};}
__exports.mockDownload=mockDownload;function mockDownload(cb){patchWithCleanup(download,{_download:cb});}
const hushConsole=__exports.hushConsole=Object.create(null);for(const propName of Object.keys(window.console)){hushConsole[propName]=()=>{};}
__exports.mockSendBeacon=mockSendBeacon;function mockSendBeacon(mock){patchWithCleanup(navigator,{sendBeacon:(url,blob)=>{return mock(url,blob)!==false;},});}
__exports.mockTimeout=mockTimeout;function mockTimeout(){const timeouts=new Map();let currentTime=0;let id=1;patchWithCleanup(browser,{setTimeout(fn,delay=0){timeouts.set(id,{fn,scheduledFor:delay+currentTime,id});return id++;},clearTimeout(id){timeouts.delete(id);},});return{execRegisteredTimeouts(){for(const{fn}of timeouts.values()){fn();}
timeouts.clear();},async advanceTime(duration){await nextTick();currentTime+=duration;for(const{fn,scheduledFor,id}of timeouts.values()){if(scheduledFor<=currentTime){fn();timeouts.delete(id);}}
await nextTick();},};}
__exports.mockAnimationFrame=mockAnimationFrame;function mockAnimationFrame(){const callbacks=new Map();let currentTime=0;let id=1;patchWithCleanup(browser,{requestAnimationFrame(fn){callbacks.set(id,{fn,scheduledFor:16+currentTime,id});return id++;},cancelAnimationFrame(id){callbacks.delete(id);},performance:{now:()=>currentTime},});return{execRegisteredAnimationFrames(){for(const{fn}of callbacks.values()){fn(currentTime);}
callbacks.clear();},async advanceFrame(count=1){await nextTick();currentTime+=16*count;for(const{fn,scheduledFor,id}of callbacks.values()){if(scheduledFor<=currentTime){fn(currentTime);callbacks.delete(id);}}
await nextTick();},};}
__exports.mount=mount;async function mount(Comp,target,config={}){let{props,env}=config;env=env||{};const configuration={env,templates,test:true,props,};if(env.services&&"localization"in env.services){configuration.translateFn=_t;}
const app=new App(Comp,configuration);registerCleanup(()=>app.destroy());return app.mount(target);}
__exports.destroy=destroy;function destroy(comp){comp.__owl__.app.destroy();}
__exports.findChildren=findChildren;function findChildren(comp,predicate=(e)=>e){const queue=[];[].unshift.apply(queue,Object.values(comp.__owl__.children));while(queue.length>0){const curNode=queue.pop();if(predicate(curNode)){return curNode;}
[].unshift.apply(queue,Object.values(curNode.component.__owl__.children));}}
__exports.useChild=useChild;function useChild(){const node=useComponent().__owl__;const setChild=()=>{const componentNode=Object.values(node.children)[0];node.component.child=componentNode.component;};onMounted(setChild);onPatched(setChild);}
__exports.useLogLifeCycle=useLogLifeCycle;function useLogLifeCycle(logFn,name=""){const component=useComponent();let loggedName=`${component.constructor.name}`;if(name){loggedName=`${component.constructor.name} ${name}`;}
onError(()=>{logFn(`onError ${loggedName}`);});onMounted(()=>{logFn(`onMounted ${loggedName}`);});onPatched(()=>{logFn(`onPatched ${loggedName}`);});onRendered(()=>{logFn(`onRendered ${loggedName}`);});onWillDestroy(()=>{logFn(`onWillDestroy ${loggedName}`);});onWillPatch(()=>{logFn(`onWillPatch ${loggedName}`);});onWillRender(()=>{logFn(`onWillRender ${loggedName}`);});onWillStart(()=>{logFn(`onWillStart ${loggedName}`);});onWillUnmount(()=>{logFn(`onWillUnmount ${loggedName}`);});onWillUpdateProps(()=>{logFn(`onWillUpdateProps ${loggedName}`);});}
function getDifferentParents(n1,n2){const parents=[n2];while(parents[0].parentNode){const parent=parents[0].parentNode;if(parent.contains(n1)){break;}
parents.unshift(parent);}
return parents;}
__exports.dragAndDrop=dragAndDrop;async function dragAndDrop(from,to,position){const{drop}=await drag(from);await drop(to,position);}
__exports.drag=drag;async function drag(from,pointerType="mouse"){const assertIsDragging=(fn,endDrag)=>{return{async[fn.name](...args){if(dragEndReason){throw new Error(`Cannot execute drag helper '${fn.name}': drag sequence has been ended by '${dragEndReason}'.`);}
await fn(...args);if(endDrag){dragEndReason=fn.name;}},}[fn.name];};const cancel=assertIsDragging(async function cancel(){await triggerEvent(window,null,"keydown",{key:"Escape"});},true);const drop=assertIsDragging(async function drop(to,position){if(to){await moveTo(to,position);}
await triggerEvent(target||source,null,"pointerup",targetPosition);},true);const getEl=(selector)=>selector instanceof Element?selector:fixture.querySelector(selector);const getTargetPosition=(position)=>{const tRect=target.getBoundingClientRect();const tPos={clientX:Math.floor(tRect.x),clientY:Math.floor(tRect.y),};if(position&&typeof position==="object"){tPos.clientX+=position.x||0;tPos.clientY+=position.y||0;}else{const positions=typeof position==="string"?position.split("-"):[];if(positions.includes("left")){tPos.clientX-=1;}else if(positions.includes("right")){tPos.clientX+=Math.ceil(tRect.width)+1;}else{tPos.clientX+=Math.floor(tRect.width/2);}
if(positions.includes("top")){tPos.clientY-=1;}else if(positions.includes("bottom")){tPos.clientY+=Math.ceil(tRect.height)+1;}else{tPos.clientY+=Math.floor(tRect.height/2);}}
return tPos;};const moveTo=assertIsDragging(async function moveTo(to,position){target=getEl(to);if(!target){return;}
targetPosition=getTargetPosition(position);await triggerEvent(source,null,"pointermove",targetPosition);for(const parent of getDifferentParents(source,target)){triggerEvent(parent,null,"pointerenter",targetPosition);}
await nextTick();return dragHelpers;},false);const dragHelpers={cancel,drop,moveTo};const fixture=getFixture();const source=getEl(from instanceof Element?from:fixture.querySelector(from));const sourceRect=source.getBoundingClientRect();let dragEndReason=null;let target;let targetPosition;await triggerEvent(source,null,"pointerdown",{pointerType,clientX:sourceRect.x+sourceRect.width/2,clientY:sourceRect.y+sourceRect.height/2,});return dragHelpers;}
__exports.clickDropdown=clickDropdown;async function clickDropdown(target,fieldName){const dropdownInput=target.querySelector(`[name='${fieldName}'] .dropdown input`);dropdownInput.focus();await nextTick();await click(dropdownInput);}
__exports.clickOpenedDropdownItem=clickOpenedDropdownItem;async function clickOpenedDropdownItem(target,fieldName,itemContent){const dropdowns=target.querySelectorAll(`[name='${fieldName}'] .dropdown .dropdown-menu`);if(dropdowns.length===0){throw new Error(`No dropdown found for field ${fieldName}`);}else if(dropdowns.length>1){throw new Error(`Found ${dropdowns.length} dropdowns for field ${fieldName}`);}
const dropdownItems=dropdowns[0].querySelectorAll("li");const indexToClick=Array.from(dropdownItems).map((html)=>html.textContent).indexOf(itemContent);if(indexToClick===-1){throw new Error(`The element '${itemContent}' does not exist in the dropdown`);}
await click(dropdownItems[indexToClick]);}
__exports.selectDropdownItem=selectDropdownItem;async function selectDropdownItem(target,fieldName,itemContent){await clickDropdown(target,fieldName);await clickOpenedDropdownItem(target,fieldName,itemContent);}
__exports.getNodesTextContent=getNodesTextContent;function getNodesTextContent(nodes){return Array.from(nodes).map((n)=>n.textContent);}
__exports.clickOpenM2ODropdown=clickOpenM2ODropdown;async function clickOpenM2ODropdown(el,fieldName,selector){const m2oSelector=`${selector || ""} .o_field_many2one[name=${fieldName}] input`;const matches=el.querySelectorAll(m2oSelector);if(matches.length!==1){throw new Error(`cannot open m2o: selector ${selector} has been found ${matches.length} instead of 1`);}
await click(matches[0]);return matches[0];}
__exports.clickM2OHighlightedItem=clickM2OHighlightedItem;async function clickM2OHighlightedItem(el,fieldName,selector){const m2oSelector=`${selector || ""} .o_field_many2one[name=${fieldName}] input`;const matches=el.querySelectorAll(m2oSelector);if(matches.length!==1){throw new Error(`cannot open m2o: selector ${selector} has been found ${matches.length} instead of 1`);}
return click(matches[0].parentElement.querySelector("li"));}
__exports.addRow=addRow;async function addRow(target,selector){await click(target.querySelector(`${selector ? selector : ""} .o_field_x2many_list_row_add a`));}
__exports.removeRow=removeRow;async function removeRow(target,index){await click(target.querySelectorAll(".o_list_record_remove")[index]);}
return __exports;});;

/* /web/static/tests/utils.js */
odoo.define('@web/../tests/utils',['@web/core/utils/ui','@web/../tests/helpers/cleanup','@web/../tests/helpers/utils'],function(require){'use strict';let __exports={};const{isVisible}=require("@web/core/utils/ui");const{registerCleanup}=require("@web/../tests/helpers/cleanup");const{click:webClick,getFixture,makeDeferred,triggerEvents:webTriggerEvents,}=require("@web/../tests/helpers/utils");__exports.createFile=createFile;function createFile(data){return new Promise(function(resolve,reject){var requestFileSystem=window.requestFileSystem||window.webkitRequestFileSystem;if(!requestFileSystem){throw new Error("FileSystem API is not supported");}
requestFileSystem(window.TEMPORARY,1024*1024,function(fileSystem){fileSystem.root.getFile(data.name,{create:true},function(fileEntry){fileEntry.createWriter(function(fileWriter){fileWriter.onwriteend=function(e){fileSystem.root.getFile(data.name,{},function(fileEntry){fileEntry.file(function(file){resolve(file);});});};fileWriter.write(new Blob([data.content],{type:data.contentType}));});});});});}
function createFakeDataTransfer(files){return{dropEffect:"all",effectAllowed:"all",files,items:[],types:["Files"],};}
__exports.click=click;async function click(selector,options={}){const{shiftKey}=options;delete options.shiftKey;await contains(selector,{click:{shiftKey},...options});}
__exports.dragenterFiles=dragenterFiles;async function dragenterFiles(selector,files,options){await contains(selector,{dragenterFiles:files,...options});}
__exports.dragoverFiles=dragoverFiles;async function dragoverFiles(selector,files,options){await contains(selector,{dragoverFiles:files,...options});}
__exports.dropFiles=dropFiles;async function dropFiles(selector,files,options){await contains(selector,{dropFiles:files,...options});}
__exports.inputFiles=inputFiles;async function inputFiles(selector,files,options){await contains(selector,{inputFiles:files,...options});}
__exports.pasteFiles=pasteFiles;async function pasteFiles(selector,files,options){await contains(selector,{pasteFiles:files,...options});}
__exports.focus=focus;async function focus(selector,options){await contains(selector,{setFocus:true,...options});}
__exports.insertText=insertText;async function insertText(selector,content,options={}){const{replace=false}=options;delete options.replace;await contains(selector,{...options,insertText:{content,replace}});}
__exports.scroll=scroll;async function scroll(selector,scrollTop,options){await contains(selector,{setScroll:scrollTop,...options});}
__exports.triggerEvents=triggerEvents;async function triggerEvents(selector,events,options){await contains(selector,{triggerEvents:events,...options});}
function log(ok,message){if(window.QUnit){QUnit.assert.ok(ok,message);}else{if(ok){console.log(message);}else{console.error(message);}}}
let hasUsedContainsPositively=false;if(window.QUnit){QUnit.testStart(()=>(hasUsedContainsPositively=false));}
class Contains{constructor(selector,options={}){this.selector=selector;this.options=options;this.options.count??=1;this.options.targetParam=this.options.target;this.options.target??=getFixture();let selectorMessage=`${this.options.count} of "${this.selector}"`;if(this.options.visible!==undefined){selectorMessage=`${selectorMessage} ${
                this.options.visible ? "visible" : "invisible"
            }`;}
if(this.options.targetParam){selectorMessage=`${selectorMessage} inside a specific target`;}
if(this.options.parent){selectorMessage=`${selectorMessage} inside a specific parent`;}
if(this.options.contains){selectorMessage=`${selectorMessage} with a specified sub-contains`;}
if(this.options.text!==undefined){selectorMessage=`${selectorMessage} with text "${this.options.text}"`;}
if(this.options.textContent!==undefined){selectorMessage=`${selectorMessage} with textContent "${this.options.textContent}"`;}
if(this.options.value!==undefined){selectorMessage=`${selectorMessage} with value "${this.options.value}"`;}
if(this.options.scroll!==undefined){selectorMessage=`${selectorMessage} with scroll "${this.options.scroll}"`;}
if(this.options.after!==undefined){selectorMessage=`${selectorMessage} after a specified element`;}
if(this.options.before!==undefined){selectorMessage=`${selectorMessage} before a specified element`;}
this.selectorMessage=selectorMessage;if(this.options.contains&&!Array.isArray(this.options.contains[0])){this.options.contains=[this.options.contains];}
if(this.options.count){hasUsedContainsPositively=true;}else if(!hasUsedContainsPositively){throw new Error(`Starting a test with "contains" of count 0 for selector "${this.selector}" is useless because it might immediately resolve. Start the test by checking that an expected element actually exists.`);}
this.successMessage=undefined;this.executeError=undefined;}
run(){this.done=false;this.def=makeDeferred();this.scrollListeners=new Set();this.onScroll=()=>this.runOnce("after scroll");if(!this.runOnce("immediately")){this.timer=setTimeout(()=>this.runOnce("Timeout of 5 seconds",{crashOnFail:true}),5000);this.observer=new MutationObserver((mutations)=>{try{this.runOnce("after mutations");}catch(e){this.def.reject(e);}});this.observer.observe(this.options.target,{attributes:true,childList:true,subtree:true,});registerCleanup(()=>{if(!this.done){this.runOnce("Test ended",{crashOnFail:true});}});}
return this.def;}
runOnce(whenMessage,{crashOnFail=false,executeOnSuccess=true}={}){const res=this.select();if(res?.length===this.options.count||crashOnFail){this.observer?.disconnect();clearTimeout(this.timer);for(const el of this.scrollListeners??[]){el.removeEventListener("scroll",this.onScroll);}
this.done=true;}
if(res?.length===this.options.count){this.successMessage=`Found ${this.selectorMessage} (${whenMessage})`;if(executeOnSuccess){this.executeAction(res[0]);}
return res;}else{this.executeError=()=>{let message=`Failed to find ${this.selectorMessage} (${whenMessage}).`;message=res?`${message} Found ${res.length} instead.`:`${message} Parent not found.`;if(this.parentContains){if(this.parentContains.successMessage){log(true,this.parentContains.successMessage);}else{this.parentContains.executeError();}}
log(false,message);this.def?.reject(new Error(message));for(const childContains of this.childrenContains||[]){if(childContains.successMessage){log(true,childContains.successMessage);}else{childContains.executeError();}}};if(crashOnFail){this.executeError();}}}
executeAction(el){let message=this.successMessage;if(this.options.click){message=`${message} and clicked it`;webClick(el,undefined,{mouseEventInit:this.options.click,skipDisabledCheck:true,skipVisibilityCheck:true,});}
if(this.options.dragenterFiles){message=`${message} and dragentered ${this.options.dragenterFiles.length} file(s)`;const ev=new Event("dragenter",{bubbles:true});Object.defineProperty(ev,"dataTransfer",{value:createFakeDataTransfer(this.options.dragenterFiles),});el.dispatchEvent(ev);}
if(this.options.dragoverFiles){message=`${message} and dragovered ${this.options.dragoverFiles.length} file(s)`;const ev=new Event("dragover",{bubbles:true});Object.defineProperty(ev,"dataTransfer",{value:createFakeDataTransfer(this.options.dragoverFiles),});el.dispatchEvent(ev);}
if(this.options.dropFiles){message=`${message} and dropped ${this.options.dropFiles.length} file(s)`;const ev=new Event("drop",{bubbles:true});Object.defineProperty(ev,"dataTransfer",{value:createFakeDataTransfer(this.options.dropFiles),});el.dispatchEvent(ev);}
if(this.options.inputFiles){message=`${message} and inputted ${this.options.inputFiles.length} file(s)`;const dataTransfer=new window.DataTransfer();for(const file of this.options.inputFiles){dataTransfer.items.add(file);}
el.files=dataTransfer.files;const versionRaw=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);const chromeVersion=versionRaw?parseInt(versionRaw[2],10):false;if(!chromeVersion||chromeVersion>=73){el.dispatchEvent(new Event("change"));}}
if(this.options.insertText!==undefined){message=`${message} and inserted text "${this.options.insertText.content}" (replace: ${this.options.insertText.replace})`;el.focus();if(this.options.insertText.replace){el.value="";el.dispatchEvent(new window.KeyboardEvent("keydown",{key:"Backspace"}));el.dispatchEvent(new window.KeyboardEvent("keyup",{key:"Backspace"}));el.dispatchEvent(new window.InputEvent("input"));}
for(const char of this.options.insertText.content){el.value+=char;el.dispatchEvent(new window.KeyboardEvent("keydown",{key:char}));el.dispatchEvent(new window.KeyboardEvent("keyup",{key:char}));el.dispatchEvent(new window.InputEvent("input"));}
el.dispatchEvent(new window.InputEvent("change"));}
if(this.options.pasteFiles){message=`${message} and pasted ${this.options.pasteFiles.length} file(s)`;const ev=new Event("paste",{bubbles:true});Object.defineProperty(ev,"clipboardData",{value:createFakeDataTransfer(this.options.pasteFiles),});el.dispatchEvent(ev);}
if(this.options.setFocus){message=`${message} and focused it`;el.focus();}
if(this.options.setScroll!==undefined){message=`${message} and set scroll to "${this.options.setScroll}"`;el.scrollTop=this.options.setScroll==="bottom"?el.scrollHeight:this.options.setScroll;}
if(this.options.triggerEvents){message=`${message} and triggered "${this.options.triggerEvents.join(", ")}" events`;webTriggerEvents(el,null,this.options.triggerEvents,{skipVisibilityCheck:true,});}
if(this.parentContains){log(true,this.parentContains.successMessage);}
log(true,message);for(const childContains of this.childrenContains){log(true,childContains.successMessage);}
this.def?.resolve();}
select(){const target=this.selectParent();if(!target){return;}
const baseRes=[...target.querySelectorAll(this.selector)].map((el)=>(this.options.shadowRoot?el.shadowRoot:el)).filter((el)=>el);this.childrenContains=[];const res=baseRes.filter((el,currentIndex)=>{let condition=(this.options.textContent===undefined||el.textContent.trim()===this.options.textContent)&&(this.options.value===undefined||el.value===this.options.value)&&(this.options.scroll===undefined||(this.options.scroll==="bottom"?Math.abs(el.scrollHeight-el.clientHeight-el.scrollTop)<=1:Math.abs(el.scrollTop-this.options.scroll)<=1));if(condition&&this.options.text!==undefined){if(el.textContent.trim()!==this.options.text&&[...el.querySelectorAll("*")].every((el)=>el.textContent.trim()!==this.options.text)){condition=false;}}
if(condition&&this.options.contains){for(const param of this.options.contains){const childContains=new Contains(param[0],{...param[1],target:el});if(!childContains.runOnce(`as child of el ${currentIndex + 1})`,{executeOnSuccess:false,})){condition=false;}
this.childrenContains.push(childContains);}}
if(condition&&this.options.visible!==undefined){if(isVisible(el)!==this.options.visible){condition=false;}}
if(condition&&this.options.after){const afterContains=new Contains(this.options.after[0],{...this.options.after[1],target,});const afterEl=afterContains.runOnce(`as "after"`,{executeOnSuccess:false,})?.[0];if(!afterEl||!(el.compareDocumentPosition(afterEl)&Node.DOCUMENT_POSITION_PRECEDING)){condition=false;}
this.childrenContains.push(afterContains);}
if(condition&&this.options.before){const beforeContains=new Contains(this.options.before[0],{...this.options.before[1],target,});const beforeEl=beforeContains.runOnce(`as "before"`,{executeOnSuccess:false,})?.[0];if(!beforeEl||!(el.compareDocumentPosition(beforeEl)&Node.DOCUMENT_POSITION_FOLLOWING)){condition=false;}
this.childrenContains.push(beforeContains);}
return condition;});if(this.options.scroll!==undefined&&this.scrollListeners&&baseRes.length===this.options.count&&res.length!==this.options.count){for(const el of baseRes){if(!this.scrollListeners.has(el)){this.scrollListeners.add(el);el.addEventListener("scroll",this.onScroll);}}}
return res;}
selectParent(){if(this.options.parent){this.parentContains=new Contains(this.options.parent[0],{...this.options.parent[1],target:this.options.target,});return this.parentContains.runOnce(`as parent`,{executeOnSuccess:false})?.[0];}
return this.options.target;}}
__exports.contains=contains;async function contains(selector,options){await new Contains(selector,options).run();}
const stepState={expectedSteps:null,deferred:null,timeout:null,currentSteps:[],clear(){clearTimeout(this.timeout);this.timeout=null;this.deferred=null;this.currentSteps=[];this.expectedSteps=null;},check({crashOnFail=false}={}){const success=this.expectedSteps.length===this.currentSteps.length&&this.expectedSteps.every((s,i)=>s===this.currentSteps[i]);if(!success&&!crashOnFail){return;}
QUnit.config.current.assert.verifySteps(this.expectedSteps);if(success){this.deferred.resolve();}else{this.deferred.reject(new Error("Steps do not match."));}
this.clear();},};if(window.QUnit){QUnit.testStart(()=>registerCleanup(()=>{if(stepState.expectedSteps){stepState.check({crashOnFail:true});}else{stepState.clear();}}));}
__exports.step=step;function step(step){stepState.currentSteps.push(step);QUnit.config.current.assert.step(step);if(stepState.expectedSteps){stepState.check();}}
__exports.assertSteps=assertSteps;function assertSteps(steps){if(stepState.expectedSteps){stepState.check({crashOnFail:true});}
stepState.expectedSteps=steps;stepState.deferred=makeDeferred();stepState.timeout=setTimeout(()=>stepState.check({crashOnFail:true}),2000);stepState.check();return stepState.deferred;}
return __exports;});;

/* /mail/static/tests/tours/discuss_channel_public_tour.js */
odoo.define('@mail/../tests/tours/discuss_channel_public_tour',['@web/core/registry','@web/../tests/utils'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{click,contains,createFile,inputFiles}=require("@web/../tests/utils");registry.category("web_tour.tours").add("discuss_channel_public_tour.js",{test:true,steps:()=>[{trigger:".o-mail-DiscussPublic",extraTrigger:".o-mail-Thread",run(){},},{content:"Check that we are on channel page",trigger:".o-mail-Thread",run(){if(!window.location.pathname.startsWith("/discuss/channel")){console.error("Channel secret token is still present in URL.");}
const{missing,failed,unloaded}=odoo.loader.findErrors();if([missing,failed,unloaded].some((arr)=>arr.length)){console.error("Couldn't load all JS modules.",JSON.stringify({missing,failed,unloaded}));}
document.body.classList.add("o_discuss_channel_public_modules_loaded");},extraTrigger:".o_discuss_channel_public_modules_loaded",},{content:"Wait for all modules loaded check in previous step",trigger:".o_discuss_channel_public_modules_loaded",run(){},},{content:"Write something in composer",trigger:".o-mail-Composer-input",run:"text cheese",},{content:"Add one file in composer",trigger:".o-mail-Composer button[aria-label='Attach files']",async run(){await inputFiles(".o-mail-Composer-coreMain .o_input_file",[await createFile({content:"hello, world",contentType:"text/plain",name:"text.txt",}),]);},},{content:"Check the earlier provided attachment is listed",trigger:'.o-mail-AttachmentCard[title="text.txt"]',extra_trigger:".o-mail-AttachmentCard:not(.o-isUploading)",run(){},},{content:"Send message",trigger:".o-mail-Composer-send:enabled",},{content:"Check message is shown",trigger:'.o-mail-Message-body:contains("cheese")',run(){},},{content:"Check message contains the attachment",trigger:'.o-mail-Message .o-mail-AttachmentCard:contains("text.txt")',run(){},},{content:"Click on more menu",trigger:".o-mail-Message [title='Expand']",},{content:"Click on edit",trigger:".o-mail-Message [title='Edit']",},{content:"Edit message",trigger:".o-mail-Message .o-mail-Composer-input",run:"text vegetables",},{content:"Add one more file in composer",trigger:".o-mail-Message .o-mail-Composer button[aria-label='Attach files']",async run(){inputFiles(".o-mail-Message .o-mail-Composer-coreMain .o_input_file",[await createFile({content:"hello 2",contentType:"text/plain",name:"extra.txt",}),]);},},{content:"Check the earlier provided extra attachment is listed",trigger:'.o-mail-Message .o-mail-Composer .o-mail-AttachmentCard[title="extra.txt"]',extra_trigger:".o-mail-Message .o-mail-Composer .o-mail-AttachmentCard:not(.o-isUploading)",run(){},},{content:"Save edited message",trigger:".o-mail-Message a:contains(save)",},{content:"Check message is edited",trigger:'.o-mail-Message-body:contains("vegetables")',run(){},},{content:"Check edited message contains the first attachment",trigger:'.o-mail-Message .o-mail-AttachmentCard:contains("text.txt")',run(){},},{content:"Check edited message contains the extra attachment",trigger:'.o-mail-Message .o-mail-AttachmentCard:contains("extra.txt")',async run(){await click(".o-mail-AttachmentCard-unlink",{parent:[".o-mail-AttachmentCard",{text:"extra.txt"}],});await click(".btn",{text:"Ok",parent:[".modal",{text:"Confirmation"}]});await contains(".o-mail-AttachmentCard",{text:"extra.txt",count:0});},},{content:"Open search panel",trigger:"button[title='Search Messages']",},{content:"Search for the attachment name",trigger:".o_searchview_input",run:"text text.txt",},{content:"Trigger the search",trigger:"button[aria-label='Search button']",},{content:"Check that searched message contains the attachment",trigger:'.o-mail-SearchMessagesPanel .o-mail-Message .o-mail-AttachmentCard:contains("text.txt")',run(){},},],});return __exports;});;

/* /mail/static/tests/tours/discuss_channel_as_guest_tour.js */
odoo.define('@mail/../tests/tours/discuss_channel_as_guest_tour',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");registry.category("web_tour.tours").add("discuss_channel_as_guest_tour.js",{test:true,steps:()=>[{content:"Channel secret token has been hidden on welcome page",trigger:".o-mail-WelcomePage",run(){if(!window.location.pathname.startsWith("/discuss/channel")){console.error("Channel secret token is still present in URL.");}},},{content:"Click join",trigger:"button[title='Join Channel']",extraTrigger:".o-mail-Thread",},{content:"Check that we are on channel page",trigger:".o-mail-Thread",run(){},},],});return __exports;});

                    /*******************************************
                    *  Templates                               *
                    *******************************************/

                    odoo.define('mail.assets_discuss_public_test_tours.bundle.xml', ['@web/core/registry'], function(require){
                        'use strict';
                        const { registry } = require('@web/core/registry');
                        registry.category(`xml_templates`).add(`mail.assets_discuss_public_test_tours`, `<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="web_tour.TourPointer">
        <div t-if="props.pointerState.isVisible" t-ref="pointer" t-attf-class="                 o_tour_pointer                 o_{{ position }}                 {{ isOpen ? 'o_open' : (props.bounce ? 'o_bouncing' : '') }}                 {{ props.pointerState.onClick ? 'cursor-pointer' : '' }}             " t-attf-style="                 --TourPointer__width: {{ constructor.width }}px;                 --TourPointer__height: {{ constructor.height }}px;             " t-on-mouseenter="props.pointerState.onMouseEnter or (() =&gt; {})" t-on-mouseleave="props.pointerState.onMouseLeave or (() =&gt; {})" t-on-click="props.pointerState.onClick or (() =&gt; {})">
            <div class="o_tour_pointer_tip position-absolute"/>
            <div class="o_tour_pointer_content rounded overflow-hidden px-3 py-2 w-100 h-100 position-relative" t-att-class="{ invisible: content and !isOpen }">
                <t t-out="content"/>
            </div>
        </div>
    </t>

</templates>`);
                    });