
/* /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||={}));;

/* /web/static/lib/luxon/luxon.js */
var luxon=(function(exports){'use strict';class LuxonError extends Error{}
class InvalidDateTimeError extends LuxonError{constructor(reason){super(`Invalid DateTime: ${reason.toMessage()}`);}}
class InvalidIntervalError extends LuxonError{constructor(reason){super(`Invalid Interval: ${reason.toMessage()}`);}}
class InvalidDurationError extends LuxonError{constructor(reason){super(`Invalid Duration: ${reason.toMessage()}`);}}
class ConflictingSpecificationError extends LuxonError{}
class InvalidUnitError extends LuxonError{constructor(unit){super(`Invalid unit ${unit}`);}}
class InvalidArgumentError extends LuxonError{}
class ZoneIsAbstractError extends LuxonError{constructor(){super("Zone is an abstract class");}}
const n="numeric",s="short",l="long";const DATE_SHORT={year:n,month:n,day:n,};const DATE_MED={year:n,month:s,day:n,};const DATE_MED_WITH_WEEKDAY={year:n,month:s,day:n,weekday:s,};const DATE_FULL={year:n,month:l,day:n,};const DATE_HUGE={year:n,month:l,day:n,weekday:l,};const TIME_SIMPLE={hour:n,minute:n,};const TIME_WITH_SECONDS={hour:n,minute:n,second:n,};const TIME_WITH_SHORT_OFFSET={hour:n,minute:n,second:n,timeZoneName:s,};const TIME_WITH_LONG_OFFSET={hour:n,minute:n,second:n,timeZoneName:l,};const TIME_24_SIMPLE={hour:n,minute:n,hourCycle:"h23",};const TIME_24_WITH_SECONDS={hour:n,minute:n,second:n,hourCycle:"h23",};const TIME_24_WITH_SHORT_OFFSET={hour:n,minute:n,second:n,hourCycle:"h23",timeZoneName:s,};const TIME_24_WITH_LONG_OFFSET={hour:n,minute:n,second:n,hourCycle:"h23",timeZoneName:l,};const DATETIME_SHORT={year:n,month:n,day:n,hour:n,minute:n,};const DATETIME_SHORT_WITH_SECONDS={year:n,month:n,day:n,hour:n,minute:n,second:n,};const DATETIME_MED={year:n,month:s,day:n,hour:n,minute:n,};const DATETIME_MED_WITH_SECONDS={year:n,month:s,day:n,hour:n,minute:n,second:n,};const DATETIME_MED_WITH_WEEKDAY={year:n,month:s,day:n,weekday:s,hour:n,minute:n,};const DATETIME_FULL={year:n,month:l,day:n,hour:n,minute:n,timeZoneName:s,};const DATETIME_FULL_WITH_SECONDS={year:n,month:l,day:n,hour:n,minute:n,second:n,timeZoneName:s,};const DATETIME_HUGE={year:n,month:l,day:n,weekday:l,hour:n,minute:n,timeZoneName:l,};const DATETIME_HUGE_WITH_SECONDS={year:n,month:l,day:n,weekday:l,hour:n,minute:n,second:n,timeZoneName:l,};class Zone{get type(){throw new ZoneIsAbstractError();}
get name(){throw new ZoneIsAbstractError();}
get ianaName(){return this.name;}
get isUniversal(){throw new ZoneIsAbstractError();}
offsetName(ts,opts){throw new ZoneIsAbstractError();}
formatOffset(ts,format){throw new ZoneIsAbstractError();}
offset(ts){throw new ZoneIsAbstractError();}
equals(otherZone){throw new ZoneIsAbstractError();}
get isValid(){throw new ZoneIsAbstractError();}}
let singleton$1=null;class SystemZone extends Zone{static get instance(){if(singleton$1===null){singleton$1=new SystemZone();}
return singleton$1;}
get type(){return"system";}
get name(){return new Intl.DateTimeFormat().resolvedOptions().timeZone;}
get isUniversal(){return false;}
offsetName(ts,{format,locale}){return parseZoneInfo(ts,format,locale);}
formatOffset(ts,format){return formatOffset(this.offset(ts),format);}
offset(ts){return-new Date(ts).getTimezoneOffset();}
equals(otherZone){return otherZone.type==="system";}
get isValid(){return true;}}
let dtfCache={};function makeDTF(zone){if(!dtfCache[zone]){dtfCache[zone]=new Intl.DateTimeFormat("en-US",{hour12:false,timeZone:zone,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",era:"short",});}
return dtfCache[zone];}
const typeToPos={year:0,month:1,day:2,era:3,hour:4,minute:5,second:6,};function hackyOffset(dtf,date){const formatted=dtf.format(date).replace(/\u200E/g,""),parsed=/(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted),[,fMonth,fDay,fYear,fadOrBc,fHour,fMinute,fSecond]=parsed;return[fYear,fMonth,fDay,fadOrBc,fHour,fMinute,fSecond];}
function partsOffset(dtf,date){const formatted=dtf.formatToParts(date);const filled=[];for(let i=0;i<formatted.length;i++){const{type,value}=formatted[i];const pos=typeToPos[type];if(type==="era"){filled[pos]=value;}else if(!isUndefined(pos)){filled[pos]=parseInt(value,10);}}
return filled;}
let ianaZoneCache={};class IANAZone extends Zone{static create(name){if(!ianaZoneCache[name]){ianaZoneCache[name]=new IANAZone(name);}
return ianaZoneCache[name];}
static resetCache(){ianaZoneCache={};dtfCache={};}
static isValidSpecifier(s){return this.isValidZone(s);}
static isValidZone(zone){if(!zone){return false;}
try{new Intl.DateTimeFormat("en-US",{timeZone:zone}).format();return true;}catch(e){return false;}}
constructor(name){super();this.zoneName=name;this.valid=IANAZone.isValidZone(name);}
get type(){return"iana";}
get name(){return this.zoneName;}
get isUniversal(){return false;}
offsetName(ts,{format,locale}){return parseZoneInfo(ts,format,locale,this.name);}
formatOffset(ts,format){return formatOffset(this.offset(ts),format);}
offset(ts){const date=new Date(ts);if(isNaN(date))return NaN;const dtf=makeDTF(this.name);let[year,month,day,adOrBc,hour,minute,second]=dtf.formatToParts?partsOffset(dtf,date):hackyOffset(dtf,date);if(adOrBc==="BC"){year=-Math.abs(year)+1;}
const adjustedHour=hour===24?0:hour;const asUTC=objToLocalTS({year,month,day,hour:adjustedHour,minute,second,millisecond:0,});let asTS=+date;const over=asTS%1000;asTS-=over>=0?over:1000+over;return(asUTC-asTS)/(60*1000);}
equals(otherZone){return otherZone.type==="iana"&&otherZone.name===this.name;}
get isValid(){return this.valid;}}
let intlLFCache={};function getCachedLF(locString,opts={}){const key=JSON.stringify([locString,opts]);let dtf=intlLFCache[key];if(!dtf){dtf=new Intl.ListFormat(locString,opts);intlLFCache[key]=dtf;}
return dtf;}
let intlDTCache={};function getCachedDTF(locString,opts={}){const key=JSON.stringify([locString,opts]);let dtf=intlDTCache[key];if(!dtf){dtf=new Intl.DateTimeFormat(locString,opts);intlDTCache[key]=dtf;}
return dtf;}
let intlNumCache={};function getCachedINF(locString,opts={}){const key=JSON.stringify([locString,opts]);let inf=intlNumCache[key];if(!inf){inf=new Intl.NumberFormat(locString,opts);intlNumCache[key]=inf;}
return inf;}
let intlRelCache={};function getCachedRTF(locString,opts={}){const{base,...cacheKeyOpts}=opts;const key=JSON.stringify([locString,cacheKeyOpts]);let inf=intlRelCache[key];if(!inf){inf=new Intl.RelativeTimeFormat(locString,opts);intlRelCache[key]=inf;}
return inf;}
let sysLocaleCache=null;function systemLocale(){if(sysLocaleCache){return sysLocaleCache;}else{sysLocaleCache=new Intl.DateTimeFormat().resolvedOptions().locale;return sysLocaleCache;}}
let weekInfoCache={};function getCachedWeekInfo(locString){let data=weekInfoCache[locString];if(!data){const locale=new Intl.Locale(locString);data="getWeekInfo"in locale?locale.getWeekInfo():locale.weekInfo;weekInfoCache[locString]=data;}
return data;}
function parseLocaleString(localeStr){const xIndex=localeStr.indexOf("-x-");if(xIndex!==-1){localeStr=localeStr.substring(0,xIndex);}
const uIndex=localeStr.indexOf("-u-");if(uIndex===-1){return[localeStr];}else{let options;let selectedStr;try{options=getCachedDTF(localeStr).resolvedOptions();selectedStr=localeStr;}catch(e){const smaller=localeStr.substring(0,uIndex);options=getCachedDTF(smaller).resolvedOptions();selectedStr=smaller;}
const{numberingSystem,calendar}=options;return[selectedStr,numberingSystem,calendar];}}
function intlConfigString(localeStr,numberingSystem,outputCalendar){if(outputCalendar||numberingSystem){if(!localeStr.includes("-u-")){localeStr+="-u";}
if(outputCalendar){localeStr+=`-ca-${outputCalendar}`;}
if(numberingSystem){localeStr+=`-nu-${numberingSystem}`;}
return localeStr;}else{return localeStr;}}
function mapMonths(f){const ms=[];for(let i=1;i<=12;i++){const dt=DateTime.utc(2009,i,1);ms.push(f(dt));}
return ms;}
function mapWeekdays(f){const ms=[];for(let i=1;i<=7;i++){const dt=DateTime.utc(2016,11,13+i);ms.push(f(dt));}
return ms;}
function listStuff(loc,length,englishFn,intlFn){const mode=loc.listingMode();if(mode==="error"){return null;}else if(mode==="en"){return englishFn(length);}else{return intlFn(length);}}
function supportsFastNumbers(loc){if(loc.numberingSystem&&loc.numberingSystem!=="latn"){return false;}else{return(loc.numberingSystem==="latn"||!loc.locale||loc.locale.startsWith("en")||new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem==="latn");}}
class PolyNumberFormatter{constructor(intl,forceSimple,opts){this.padTo=opts.padTo||0;this.floor=opts.floor||false;const{padTo,floor,...otherOpts}=opts;if(!forceSimple||Object.keys(otherOpts).length>0){const intlOpts={useGrouping:false,...opts};if(opts.padTo>0)intlOpts.minimumIntegerDigits=opts.padTo;this.inf=getCachedINF(intl,intlOpts);}}
format(i){if(this.inf){const fixed=this.floor?Math.floor(i):i;return this.inf.format(fixed);}else{const fixed=this.floor?Math.floor(i):roundTo(i,3);return padStart(fixed,this.padTo);}}}
class PolyDateFormatter{constructor(dt,intl,opts){this.opts=opts;this.originalZone=undefined;let z=undefined;if(this.opts.timeZone){this.dt=dt;}else if(dt.zone.type==="fixed"){const gmtOffset=-1*(dt.offset/60);const offsetZ=gmtOffset>=0?`Etc/GMT+${gmtOffset}`:`Etc/GMT${gmtOffset}`;if(dt.offset!==0&&IANAZone.create(offsetZ).valid){z=offsetZ;this.dt=dt;}else{z="UTC";this.dt=dt.offset===0?dt:dt.setZone("UTC").plus({minutes:dt.offset});this.originalZone=dt.zone;}}else if(dt.zone.type==="system"){this.dt=dt;}else if(dt.zone.type==="iana"){this.dt=dt;z=dt.zone.name;}else{z="UTC";this.dt=dt.setZone("UTC").plus({minutes:dt.offset});this.originalZone=dt.zone;}
const intlOpts={...this.opts};intlOpts.timeZone=intlOpts.timeZone||z;this.dtf=getCachedDTF(intl,intlOpts);}
format(){if(this.originalZone){return this.formatToParts().map(({value})=>value).join("");}
return this.dtf.format(this.dt.toJSDate());}
formatToParts(){const parts=this.dtf.formatToParts(this.dt.toJSDate());if(this.originalZone){return parts.map((part)=>{if(part.type==="timeZoneName"){const offsetName=this.originalZone.offsetName(this.dt.ts,{locale:this.dt.locale,format:this.opts.timeZoneName,});return{...part,value:offsetName,};}else{return part;}});}
return parts;}
resolvedOptions(){return this.dtf.resolvedOptions();}}
class PolyRelFormatter{constructor(intl,isEnglish,opts){this.opts={style:"long",...opts};if(!isEnglish&&hasRelative()){this.rtf=getCachedRTF(intl,opts);}}
format(count,unit){if(this.rtf){return this.rtf.format(count,unit);}else{return formatRelativeTime(unit,count,this.opts.numeric,this.opts.style!=="long");}}
formatToParts(count,unit){if(this.rtf){return this.rtf.formatToParts(count,unit);}else{return[];}}}
const fallbackWeekSettings={firstDay:1,minimalDays:4,weekend:[6,7],};class Locale{static fromOpts(opts){return Locale.create(opts.locale,opts.numberingSystem,opts.outputCalendar,opts.weekSettings,opts.defaultToEN);}
static create(locale,numberingSystem,outputCalendar,weekSettings,defaultToEN=false){const specifiedLocale=locale||Settings.defaultLocale;const localeR=specifiedLocale||(defaultToEN?"en-US":systemLocale());const numberingSystemR=numberingSystem||Settings.defaultNumberingSystem;const outputCalendarR=outputCalendar||Settings.defaultOutputCalendar;const weekSettingsR=validateWeekSettings(weekSettings)||Settings.defaultWeekSettings;return new Locale(localeR,numberingSystemR,outputCalendarR,weekSettingsR,specifiedLocale);}
static resetCache(){sysLocaleCache=null;intlDTCache={};intlNumCache={};intlRelCache={};}
static fromObject({locale,numberingSystem,outputCalendar,weekSettings}={}){return Locale.create(locale,numberingSystem,outputCalendar,weekSettings);}
constructor(locale,numbering,outputCalendar,weekSettings,specifiedLocale){const[parsedLocale,parsedNumberingSystem,parsedOutputCalendar]=parseLocaleString(locale);this.locale=parsedLocale;this.numberingSystem=numbering||parsedNumberingSystem||null;this.outputCalendar=outputCalendar||parsedOutputCalendar||null;this.weekSettings=weekSettings;this.intl=intlConfigString(this.locale,this.numberingSystem,this.outputCalendar);this.weekdaysCache={format:{},standalone:{}};this.monthsCache={format:{},standalone:{}};this.meridiemCache=null;this.eraCache={};this.specifiedLocale=specifiedLocale;this.fastNumbersCached=null;}
get fastNumbers(){if(this.fastNumbersCached==null){this.fastNumbersCached=supportsFastNumbers(this);}
return this.fastNumbersCached;}
listingMode(){const isActuallyEn=this.isEnglish();const hasNoWeirdness=(this.numberingSystem===null||this.numberingSystem==="latn")&&(this.outputCalendar===null||this.outputCalendar==="gregory");return isActuallyEn&&hasNoWeirdness?"en":"intl";}
clone(alts){if(!alts||Object.getOwnPropertyNames(alts).length===0){return this;}else{return Locale.create(alts.locale||this.specifiedLocale,alts.numberingSystem||this.numberingSystem,alts.outputCalendar||this.outputCalendar,validateWeekSettings(alts.weekSettings)||this.weekSettings,alts.defaultToEN||false);}}
redefaultToEN(alts={}){return this.clone({...alts,defaultToEN:true});}
redefaultToSystem(alts={}){return this.clone({...alts,defaultToEN:false});}
months(length,format=false){return listStuff(this,length,months,()=>{const intl=format?{month:length,day:"numeric"}:{month:length},formatStr=format?"format":"standalone";if(!this.monthsCache[formatStr][length]){this.monthsCache[formatStr][length]=mapMonths((dt)=>this.extract(dt,intl,"month"));}
return this.monthsCache[formatStr][length];});}
weekdays(length,format=false){return listStuff(this,length,weekdays,()=>{const intl=format?{weekday:length,year:"numeric",month:"long",day:"numeric"}:{weekday:length},formatStr=format?"format":"standalone";if(!this.weekdaysCache[formatStr][length]){this.weekdaysCache[formatStr][length]=mapWeekdays((dt)=>this.extract(dt,intl,"weekday"));}
return this.weekdaysCache[formatStr][length];});}
meridiems(){return listStuff(this,undefined,()=>meridiems,()=>{if(!this.meridiemCache){const intl={hour:"numeric",hourCycle:"h12"};this.meridiemCache=[DateTime.utc(2016,11,13,9),DateTime.utc(2016,11,13,19)].map((dt)=>this.extract(dt,intl,"dayperiod"));}
return this.meridiemCache;});}
eras(length){return listStuff(this,length,eras,()=>{const intl={era:length};if(!this.eraCache[length]){this.eraCache[length]=[DateTime.utc(-40,1,1),DateTime.utc(2017,1,1)].map((dt)=>this.extract(dt,intl,"era"));}
return this.eraCache[length];});}
extract(dt,intlOpts,field){const df=this.dtFormatter(dt,intlOpts),results=df.formatToParts(),matching=results.find((m)=>m.type.toLowerCase()===field);return matching?matching.value:null;}
numberFormatter(opts={}){return new PolyNumberFormatter(this.intl,opts.forceSimple||this.fastNumbers,opts);}
dtFormatter(dt,intlOpts={}){return new PolyDateFormatter(dt,this.intl,intlOpts);}
relFormatter(opts={}){return new PolyRelFormatter(this.intl,this.isEnglish(),opts);}
listFormatter(opts={}){return getCachedLF(this.intl,opts);}
isEnglish(){return(this.locale==="en"||this.locale.toLowerCase()==="en-us"||new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us"));}
getWeekSettings(){if(this.weekSettings){return this.weekSettings;}else if(!hasLocaleWeekInfo()){return fallbackWeekSettings;}else{return getCachedWeekInfo(this.locale);}}
getStartOfWeek(){return this.getWeekSettings().firstDay;}
getMinDaysInFirstWeek(){return this.getWeekSettings().minimalDays;}
getWeekendDays(){return this.getWeekSettings().weekend;}
equals(other){return(this.locale===other.locale&&this.numberingSystem===other.numberingSystem&&this.outputCalendar===other.outputCalendar);}}
let singleton=null;class FixedOffsetZone extends Zone{static get utcInstance(){if(singleton===null){singleton=new FixedOffsetZone(0);}
return singleton;}
static instance(offset){return offset===0?FixedOffsetZone.utcInstance:new FixedOffsetZone(offset);}
static parseSpecifier(s){if(s){const r=s.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i);if(r){return new FixedOffsetZone(signedOffset(r[1],r[2]));}}
return null;}
constructor(offset){super();this.fixed=offset;}
get type(){return"fixed";}
get name(){return this.fixed===0?"UTC":`UTC${formatOffset(this.fixed, "narrow")}`;}
get ianaName(){if(this.fixed===0){return"Etc/UTC";}else{return`Etc/GMT${formatOffset(-this.fixed, "narrow")}`;}}
offsetName(){return this.name;}
formatOffset(ts,format){return formatOffset(this.fixed,format);}
get isUniversal(){return true;}
offset(){return this.fixed;}
equals(otherZone){return otherZone.type==="fixed"&&otherZone.fixed===this.fixed;}
get isValid(){return true;}}
class InvalidZone extends Zone{constructor(zoneName){super();this.zoneName=zoneName;}
get type(){return"invalid";}
get name(){return this.zoneName;}
get isUniversal(){return false;}
offsetName(){return null;}
formatOffset(){return"";}
offset(){return NaN;}
equals(){return false;}
get isValid(){return false;}}
function normalizeZone(input,defaultZone){if(isUndefined(input)||input===null){return defaultZone;}else if(input instanceof Zone){return input;}else if(isString(input)){const lowered=input.toLowerCase();if(lowered==="default")return defaultZone;else if(lowered==="local"||lowered==="system")return SystemZone.instance;else if(lowered==="utc"||lowered==="gmt")return FixedOffsetZone.utcInstance;else return FixedOffsetZone.parseSpecifier(lowered)||IANAZone.create(input);}else if(isNumber(input)){return FixedOffsetZone.instance(input);}else if(typeof input==="object"&&"offset"in input&&typeof input.offset==="function"){return input;}else{return new InvalidZone(input);}}
let now=()=>Date.now(),defaultZone="system",defaultLocale=null,defaultNumberingSystem=null,defaultOutputCalendar=null,twoDigitCutoffYear=60,throwOnInvalid,defaultWeekSettings=null;class Settings{static get now(){return now;}
static set now(n){now=n;}
static set defaultZone(zone){defaultZone=zone;}
static get defaultZone(){return normalizeZone(defaultZone,SystemZone.instance);}
static get defaultLocale(){return defaultLocale;}
static set defaultLocale(locale){defaultLocale=locale;}
static get defaultNumberingSystem(){return defaultNumberingSystem;}
static set defaultNumberingSystem(numberingSystem){defaultNumberingSystem=numberingSystem;}
static get defaultOutputCalendar(){return defaultOutputCalendar;}
static set defaultOutputCalendar(outputCalendar){defaultOutputCalendar=outputCalendar;}
static get defaultWeekSettings(){return defaultWeekSettings;}
static set defaultWeekSettings(weekSettings){defaultWeekSettings=validateWeekSettings(weekSettings);}
static get twoDigitCutoffYear(){return twoDigitCutoffYear;}
static set twoDigitCutoffYear(cutoffYear){twoDigitCutoffYear=cutoffYear%100;}
static get throwOnInvalid(){return throwOnInvalid;}
static set throwOnInvalid(t){throwOnInvalid=t;}
static resetCaches(){Locale.resetCache();IANAZone.resetCache();}}
class Invalid{constructor(reason,explanation){this.reason=reason;this.explanation=explanation;}
toMessage(){if(this.explanation){return`${this.reason}: ${this.explanation}`;}else{return this.reason;}}}
const nonLeapLadder=[0,31,59,90,120,151,181,212,243,273,304,334],leapLadder=[0,31,60,91,121,152,182,213,244,274,305,335];function unitOutOfRange(unit,value){return new Invalid("unit out of range",`you specified ${value} (of type ${typeof value}) as a ${unit}, which is invalid`);}
function dayOfWeek(year,month,day){const d=new Date(Date.UTC(year,month-1,day));if(year<100&&year>=0){d.setUTCFullYear(d.getUTCFullYear()-1900);}
const js=d.getUTCDay();return js===0?7:js;}
function computeOrdinal(year,month,day){return day+(isLeapYear(year)?leapLadder:nonLeapLadder)[month-1];}
function uncomputeOrdinal(year,ordinal){const table=isLeapYear(year)?leapLadder:nonLeapLadder,month0=table.findIndex((i)=>i<ordinal),day=ordinal-table[month0];return{month:month0+1,day};}
function isoWeekdayToLocal(isoWeekday,startOfWeek){return((isoWeekday-startOfWeek+7)%7)+1;}
function gregorianToWeek(gregObj,minDaysInFirstWeek=4,startOfWeek=1){const{year,month,day}=gregObj,ordinal=computeOrdinal(year,month,day),weekday=isoWeekdayToLocal(dayOfWeek(year,month,day),startOfWeek);let weekNumber=Math.floor((ordinal-weekday+14-minDaysInFirstWeek)/7),weekYear;if(weekNumber<1){weekYear=year-1;weekNumber=weeksInWeekYear(weekYear,minDaysInFirstWeek,startOfWeek);}else if(weekNumber>weeksInWeekYear(year,minDaysInFirstWeek,startOfWeek)){weekYear=year+1;weekNumber=1;}else{weekYear=year;}
return{weekYear,weekNumber,weekday,...timeObject(gregObj)};}
function weekToGregorian(weekData,minDaysInFirstWeek=4,startOfWeek=1){const{weekYear,weekNumber,weekday}=weekData,weekdayOfJan4=isoWeekdayToLocal(dayOfWeek(weekYear,1,minDaysInFirstWeek),startOfWeek),yearInDays=daysInYear(weekYear);let ordinal=weekNumber*7+weekday-weekdayOfJan4-7+minDaysInFirstWeek,year;if(ordinal<1){year=weekYear-1;ordinal+=daysInYear(year);}else if(ordinal>yearInDays){year=weekYear+1;ordinal-=daysInYear(weekYear);}else{year=weekYear;}
const{month,day}=uncomputeOrdinal(year,ordinal);return{year,month,day,...timeObject(weekData)};}
function gregorianToOrdinal(gregData){const{year,month,day}=gregData;const ordinal=computeOrdinal(year,month,day);return{year,ordinal,...timeObject(gregData)};}
function ordinalToGregorian(ordinalData){const{year,ordinal}=ordinalData;const{month,day}=uncomputeOrdinal(year,ordinal);return{year,month,day,...timeObject(ordinalData)};}
function usesLocalWeekValues(obj,loc){const hasLocaleWeekData=!isUndefined(obj.localWeekday)||!isUndefined(obj.localWeekNumber)||!isUndefined(obj.localWeekYear);if(hasLocaleWeekData){const hasIsoWeekData=!isUndefined(obj.weekday)||!isUndefined(obj.weekNumber)||!isUndefined(obj.weekYear);if(hasIsoWeekData){throw new ConflictingSpecificationError("Cannot mix locale-based week fields with ISO-based week fields");}
if(!isUndefined(obj.localWeekday))obj.weekday=obj.localWeekday;if(!isUndefined(obj.localWeekNumber))obj.weekNumber=obj.localWeekNumber;if(!isUndefined(obj.localWeekYear))obj.weekYear=obj.localWeekYear;delete obj.localWeekday;delete obj.localWeekNumber;delete obj.localWeekYear;return{minDaysInFirstWeek:loc.getMinDaysInFirstWeek(),startOfWeek:loc.getStartOfWeek(),};}else{return{minDaysInFirstWeek:4,startOfWeek:1};}}
function hasInvalidWeekData(obj,minDaysInFirstWeek=4,startOfWeek=1){const validYear=isInteger(obj.weekYear),validWeek=integerBetween(obj.weekNumber,1,weeksInWeekYear(obj.weekYear,minDaysInFirstWeek,startOfWeek)),validWeekday=integerBetween(obj.weekday,1,7);if(!validYear){return unitOutOfRange("weekYear",obj.weekYear);}else if(!validWeek){return unitOutOfRange("week",obj.weekNumber);}else if(!validWeekday){return unitOutOfRange("weekday",obj.weekday);}else return false;}
function hasInvalidOrdinalData(obj){const validYear=isInteger(obj.year),validOrdinal=integerBetween(obj.ordinal,1,daysInYear(obj.year));if(!validYear){return unitOutOfRange("year",obj.year);}else if(!validOrdinal){return unitOutOfRange("ordinal",obj.ordinal);}else return false;}
function hasInvalidGregorianData(obj){const validYear=isInteger(obj.year),validMonth=integerBetween(obj.month,1,12),validDay=integerBetween(obj.day,1,daysInMonth(obj.year,obj.month));if(!validYear){return unitOutOfRange("year",obj.year);}else if(!validMonth){return unitOutOfRange("month",obj.month);}else if(!validDay){return unitOutOfRange("day",obj.day);}else return false;}
function hasInvalidTimeData(obj){const{hour,minute,second,millisecond}=obj;const validHour=integerBetween(hour,0,23)||(hour===24&&minute===0&&second===0&&millisecond===0),validMinute=integerBetween(minute,0,59),validSecond=integerBetween(second,0,59),validMillisecond=integerBetween(millisecond,0,999);if(!validHour){return unitOutOfRange("hour",hour);}else if(!validMinute){return unitOutOfRange("minute",minute);}else if(!validSecond){return unitOutOfRange("second",second);}else if(!validMillisecond){return unitOutOfRange("millisecond",millisecond);}else return false;}
function isUndefined(o){return typeof o==="undefined";}
function isNumber(o){return typeof o==="number";}
function isInteger(o){return typeof o==="number"&&o%1===0;}
function isString(o){return typeof o==="string";}
function isDate(o){return Object.prototype.toString.call(o)==="[object Date]";}
function hasRelative(){try{return typeof Intl!=="undefined"&&!!Intl.RelativeTimeFormat;}catch(e){return false;}}
function hasLocaleWeekInfo(){try{return(typeof Intl!=="undefined"&&!!Intl.Locale&&("weekInfo"in Intl.Locale.prototype||"getWeekInfo"in Intl.Locale.prototype));}catch(e){return false;}}
function maybeArray(thing){return Array.isArray(thing)?thing:[thing];}
function bestBy(arr,by,compare){if(arr.length===0){return undefined;}
return arr.reduce((best,next)=>{const pair=[by(next),next];if(!best){return pair;}else if(compare(best[0],pair[0])===best[0]){return best;}else{return pair;}},null)[1];}
function pick(obj,keys){return keys.reduce((a,k)=>{a[k]=obj[k];return a;},{});}
function hasOwnProperty(obj,prop){return Object.prototype.hasOwnProperty.call(obj,prop);}
function validateWeekSettings(settings){if(settings==null){return null;}else if(typeof settings!=="object"){throw new InvalidArgumentError("Week settings must be an object");}else{if(!integerBetween(settings.firstDay,1,7)||!integerBetween(settings.minimalDays,1,7)||!Array.isArray(settings.weekend)||settings.weekend.some((v)=>!integerBetween(v,1,7))){throw new InvalidArgumentError("Invalid week settings");}
return{firstDay:settings.firstDay,minimalDays:settings.minimalDays,weekend:Array.from(settings.weekend),};}}
function integerBetween(thing,bottom,top){return isInteger(thing)&&thing>=bottom&&thing<=top;}
function floorMod(x,n){return x-n*Math.floor(x/n);}
function padStart(input,n=2){const isNeg=input<0;let padded;if(isNeg){padded="-"+(""+-input).padStart(n,"0");}else{padded=(""+input).padStart(n,"0");}
return padded;}
function parseInteger(string){if(isUndefined(string)||string===null||string===""){return undefined;}else{return parseInt(string,10);}}
function parseFloating(string){if(isUndefined(string)||string===null||string===""){return undefined;}else{return parseFloat(string);}}
function parseMillis(fraction){if(isUndefined(fraction)||fraction===null||fraction===""){return undefined;}else{const f=parseFloat("0."+fraction)*1000;return Math.floor(f);}}
function roundTo(number,digits,towardZero=false){const factor=10**digits,rounder=towardZero?Math.trunc:Math.round;return rounder(number*factor)/factor;}
function isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0);}
function daysInYear(year){return isLeapYear(year)?366:365;}
function daysInMonth(year,month){const modMonth=floorMod(month-1,12)+1,modYear=year+(month-modMonth)/12;if(modMonth===2){return isLeapYear(modYear)?29:28;}else{return[31,null,31,30,31,30,31,31,30,31,30,31][modMonth-1];}}
function objToLocalTS(obj){let d=Date.UTC(obj.year,obj.month-1,obj.day,obj.hour,obj.minute,obj.second,obj.millisecond);if(obj.year<100&&obj.year>=0){d=new Date(d);d.setUTCFullYear(obj.year,obj.month-1,obj.day);}
return+d;}
function firstWeekOffset(year,minDaysInFirstWeek,startOfWeek){const fwdlw=isoWeekdayToLocal(dayOfWeek(year,1,minDaysInFirstWeek),startOfWeek);return-fwdlw+minDaysInFirstWeek-1;}
function weeksInWeekYear(weekYear,minDaysInFirstWeek=4,startOfWeek=1){const weekOffset=firstWeekOffset(weekYear,minDaysInFirstWeek,startOfWeek);const weekOffsetNext=firstWeekOffset(weekYear+1,minDaysInFirstWeek,startOfWeek);return(daysInYear(weekYear)-weekOffset+weekOffsetNext)/7;}
function untruncateYear(year){if(year>99){return year;}else return year>Settings.twoDigitCutoffYear?1900+year:2000+year;}
function parseZoneInfo(ts,offsetFormat,locale,timeZone=null){const date=new Date(ts),intlOpts={hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",};if(timeZone){intlOpts.timeZone=timeZone;}
const modified={timeZoneName:offsetFormat,...intlOpts};const parsed=new Intl.DateTimeFormat(locale,modified).formatToParts(date).find((m)=>m.type.toLowerCase()==="timezonename");return parsed?parsed.value:null;}
function signedOffset(offHourStr,offMinuteStr){let offHour=parseInt(offHourStr,10);if(Number.isNaN(offHour)){offHour=0;}
const offMin=parseInt(offMinuteStr,10)||0,offMinSigned=offHour<0||Object.is(offHour,-0)?-offMin:offMin;return offHour*60+offMinSigned;}
function asNumber(value){const numericValue=Number(value);if(typeof value==="boolean"||value===""||Number.isNaN(numericValue))
throw new InvalidArgumentError(`Invalid unit value ${value}`);return numericValue;}
function normalizeObject(obj,normalizer){const normalized={};for(const u in obj){if(hasOwnProperty(obj,u)){const v=obj[u];if(v===undefined||v===null)continue;normalized[normalizer(u)]=asNumber(v);}}
return normalized;}
function formatOffset(offset,format){const hours=Math.trunc(Math.abs(offset/60)),minutes=Math.trunc(Math.abs(offset%60)),sign=offset>=0?"+":"-";switch(format){case"short":return`${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;case"narrow":return`${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;case"techie":return`${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;default:throw new RangeError(`Value format ${format} is out of range for property format`);}}
function timeObject(obj){return pick(obj,["hour","minute","second","millisecond"]);}
const monthsLong=["January","February","March","April","May","June","July","August","September","October","November","December",];const monthsShort=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",];const monthsNarrow=["J","F","M","A","M","J","J","A","S","O","N","D"];function months(length){switch(length){case"narrow":return[...monthsNarrow];case"short":return[...monthsShort];case"long":return[...monthsLong];case"numeric":return["1","2","3","4","5","6","7","8","9","10","11","12"];case"2-digit":return["01","02","03","04","05","06","07","08","09","10","11","12"];default:return null;}}
const weekdaysLong=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday",];const weekdaysShort=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"];const weekdaysNarrow=["M","T","W","T","F","S","S"];function weekdays(length){switch(length){case"narrow":return[...weekdaysNarrow];case"short":return[...weekdaysShort];case"long":return[...weekdaysLong];case"numeric":return["1","2","3","4","5","6","7"];default:return null;}}
const meridiems=["AM","PM"];const erasLong=["Before Christ","Anno Domini"];const erasShort=["BC","AD"];const erasNarrow=["B","A"];function eras(length){switch(length){case"narrow":return[...erasNarrow];case"short":return[...erasShort];case"long":return[...erasLong];default:return null;}}
function meridiemForDateTime(dt){return meridiems[dt.hour<12?0:1];}
function weekdayForDateTime(dt,length){return weekdays(length)[dt.weekday-1];}
function monthForDateTime(dt,length){return months(length)[dt.month-1];}
function eraForDateTime(dt,length){return eras(length)[dt.year<0?0:1];}
function formatRelativeTime(unit,count,numeric="always",narrow=false){const units={years:["year","yr."],quarters:["quarter","qtr."],months:["month","mo."],weeks:["week","wk."],days:["day","day","days"],hours:["hour","hr."],minutes:["minute","min."],seconds:["second","sec."],};const lastable=["hours","minutes","seconds"].indexOf(unit)===-1;if(numeric==="auto"&&lastable){const isDay=unit==="days";switch(count){case 1:return isDay?"tomorrow":`next ${units[unit][0]}`;case-1:return isDay?"yesterday":`last ${units[unit][0]}`;case 0:return isDay?"today":`this ${units[unit][0]}`;}}
const isInPast=Object.is(count,-0)||count<0,fmtValue=Math.abs(count),singular=fmtValue===1,lilUnits=units[unit],fmtUnit=narrow?singular?lilUnits[1]:lilUnits[2]||lilUnits[1]:singular?units[unit][0]:unit;return isInPast?`${fmtValue} ${fmtUnit} ago`:`in ${fmtValue} ${fmtUnit}`;}
function stringifyTokens(splits,tokenToString){let s="";for(const token of splits){if(token.literal){s+=token.val;}else{s+=tokenToString(token.val);}}
return s;}
const macroTokenToFormatOpts={D:DATE_SHORT,DD:DATE_MED,DDD:DATE_FULL,DDDD:DATE_HUGE,t:TIME_SIMPLE,tt:TIME_WITH_SECONDS,ttt:TIME_WITH_SHORT_OFFSET,tttt:TIME_WITH_LONG_OFFSET,T:TIME_24_SIMPLE,TT:TIME_24_WITH_SECONDS,TTT:TIME_24_WITH_SHORT_OFFSET,TTTT:TIME_24_WITH_LONG_OFFSET,f:DATETIME_SHORT,ff:DATETIME_MED,fff:DATETIME_FULL,ffff:DATETIME_HUGE,F:DATETIME_SHORT_WITH_SECONDS,FF:DATETIME_MED_WITH_SECONDS,FFF:DATETIME_FULL_WITH_SECONDS,FFFF:DATETIME_HUGE_WITH_SECONDS,};class Formatter{static create(locale,opts={}){return new Formatter(locale,opts);}
static parseFormat(fmt){let current=null,currentFull="",bracketed=false;const splits=[];for(let i=0;i<fmt.length;i++){const c=fmt.charAt(i);if(c==="'"){if(currentFull.length>0){splits.push({literal:bracketed||/^\s+$/.test(currentFull),val:currentFull});}
current=null;currentFull="";bracketed=!bracketed;}else if(bracketed){currentFull+=c;}else if(c===current){currentFull+=c;}else{if(currentFull.length>0){splits.push({literal:/^\s+$/.test(currentFull),val:currentFull});}
currentFull=c;current=c;}}
if(currentFull.length>0){splits.push({literal:bracketed||/^\s+$/.test(currentFull),val:currentFull});}
return splits;}
static macroTokenToFormatOpts(token){return macroTokenToFormatOpts[token];}
constructor(locale,formatOpts){this.opts=formatOpts;this.loc=locale;this.systemLoc=null;}
formatWithSystemDefault(dt,opts){if(this.systemLoc===null){this.systemLoc=this.loc.redefaultToSystem();}
const df=this.systemLoc.dtFormatter(dt,{...this.opts,...opts});return df.format();}
dtFormatter(dt,opts={}){return this.loc.dtFormatter(dt,{...this.opts,...opts});}
formatDateTime(dt,opts){return this.dtFormatter(dt,opts).format();}
formatDateTimeParts(dt,opts){return this.dtFormatter(dt,opts).formatToParts();}
formatInterval(interval,opts){const df=this.dtFormatter(interval.start,opts);return df.dtf.formatRange(interval.start.toJSDate(),interval.end.toJSDate());}
resolvedOptions(dt,opts){return this.dtFormatter(dt,opts).resolvedOptions();}
num(n,p=0){if(this.opts.forceSimple){return padStart(n,p);}
const opts={...this.opts};if(p>0){opts.padTo=p;}
return this.loc.numberFormatter(opts).format(n);}
formatDateTimeFromString(dt,fmt){const knownEnglish=this.loc.listingMode()==="en",useDateTimeFormatter=this.loc.outputCalendar&&this.loc.outputCalendar!=="gregory",string=(opts,extract)=>this.loc.extract(dt,opts,extract),formatOffset=(opts)=>{if(dt.isOffsetFixed&&dt.offset===0&&opts.allowZ){return"Z";}
return dt.isValid?dt.zone.formatOffset(dt.ts,opts.format):"";},meridiem=()=>knownEnglish?meridiemForDateTime(dt):string({hour:"numeric",hourCycle:"h12"},"dayperiod"),month=(length,standalone)=>knownEnglish?monthForDateTime(dt,length):string(standalone?{month:length}:{month:length,day:"numeric"},"month"),weekday=(length,standalone)=>knownEnglish?weekdayForDateTime(dt,length):string(standalone?{weekday:length}:{weekday:length,month:"long",day:"numeric"},"weekday"),maybeMacro=(token)=>{const formatOpts=Formatter.macroTokenToFormatOpts(token);if(formatOpts){return this.formatWithSystemDefault(dt,formatOpts);}else{return token;}},era=(length)=>knownEnglish?eraForDateTime(dt,length):string({era:length},"era"),tokenToString=(token)=>{switch(token){case"S":return this.num(dt.millisecond);case"u":case"SSS":return this.num(dt.millisecond,3);case"s":return this.num(dt.second);case"ss":return this.num(dt.second,2);case"uu":return this.num(Math.floor(dt.millisecond/10),2);case"uuu":return this.num(Math.floor(dt.millisecond/100));case"m":return this.num(dt.minute);case"mm":return this.num(dt.minute,2);case"h":return this.num(dt.hour%12===0?12:dt.hour%12);case"hh":return this.num(dt.hour%12===0?12:dt.hour%12,2);case"H":return this.num(dt.hour);case"HH":return this.num(dt.hour,2);case"Z":return formatOffset({format:"narrow",allowZ:this.opts.allowZ});case"ZZ":return formatOffset({format:"short",allowZ:this.opts.allowZ});case"ZZZ":return formatOffset({format:"techie",allowZ:this.opts.allowZ});case"ZZZZ":return dt.zone.offsetName(dt.ts,{format:"short",locale:this.loc.locale});case"ZZZZZ":return dt.zone.offsetName(dt.ts,{format:"long",locale:this.loc.locale});case"z":return dt.zoneName;case"a":return meridiem();case"d":return useDateTimeFormatter?string({day:"numeric"},"day"):this.num(dt.day);case"dd":return useDateTimeFormatter?string({day:"2-digit"},"day"):this.num(dt.day,2);case"c":return this.num(dt.weekday);case"ccc":return weekday("short",true);case"cccc":return weekday("long",true);case"ccccc":return weekday("narrow",true);case"E":return this.num(dt.weekday);case"EEE":return weekday("short",false);case"EEEE":return weekday("long",false);case"EEEEE":return weekday("narrow",false);case"L":return useDateTimeFormatter?string({month:"numeric",day:"numeric"},"month"):this.num(dt.month);case"LL":return useDateTimeFormatter?string({month:"2-digit",day:"numeric"},"month"):this.num(dt.month,2);case"LLL":return month("short",true);case"LLLL":return month("long",true);case"LLLLL":return month("narrow",true);case"M":return useDateTimeFormatter?string({month:"numeric"},"month"):this.num(dt.month);case"MM":return useDateTimeFormatter?string({month:"2-digit"},"month"):this.num(dt.month,2);case"MMM":return month("short",false);case"MMMM":return month("long",false);case"MMMMM":return month("narrow",false);case"y":return useDateTimeFormatter?string({year:"numeric"},"year"):this.num(dt.year);case"yy":return useDateTimeFormatter?string({year:"2-digit"},"year"):this.num(dt.year.toString().slice(-2),2);case"yyyy":return useDateTimeFormatter?string({year:"numeric"},"year"):this.num(dt.year,4);case"yyyyyy":return useDateTimeFormatter?string({year:"numeric"},"year"):this.num(dt.year,6);case"G":return era("short");case"GG":return era("long");case"GGGGG":return era("narrow");case"kk":return this.num(dt.weekYear.toString().slice(-2),2);case"kkkk":return this.num(dt.weekYear,4);case"W":return this.num(dt.weekNumber);case"WW":return this.num(dt.weekNumber,2);case"n":return this.num(dt.localWeekNumber);case"nn":return this.num(dt.localWeekNumber,2);case"ii":return this.num(dt.localWeekYear.toString().slice(-2),2);case"iiii":return this.num(dt.localWeekYear,4);case"o":return this.num(dt.ordinal);case"ooo":return this.num(dt.ordinal,3);case"q":return this.num(dt.quarter);case"qq":return this.num(dt.quarter,2);case"X":return this.num(Math.floor(dt.ts/1000));case"x":return this.num(dt.ts);default:return maybeMacro(token);}};return stringifyTokens(Formatter.parseFormat(fmt),tokenToString);}
formatDurationFromString(dur,fmt){const tokenToField=(token)=>{switch(token[0]){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":return"hour";case"d":return"day";case"w":return"week";case"M":return"month";case"y":return"year";default:return null;}},tokenToString=(lildur)=>(token)=>{const mapped=tokenToField(token);if(mapped){return this.num(lildur.get(mapped),token.length);}else{return token;}},tokens=Formatter.parseFormat(fmt),realTokens=tokens.reduce((found,{literal,val})=>(literal?found:found.concat(val)),[]),collapsed=dur.shiftTo(...realTokens.map(tokenToField).filter((t)=>t));return stringifyTokens(tokens,tokenToString(collapsed));}}
const ianaRegex=/[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;function combineRegexes(...regexes){const full=regexes.reduce((f,r)=>f+r.source,"");return RegExp(`^${full}$`);}
function combineExtractors(...extractors){return(m)=>extractors.reduce(([mergedVals,mergedZone,cursor],ex)=>{const[val,zone,next]=ex(m,cursor);return[{...mergedVals,...val},zone||mergedZone,next];},[{},null,1]).slice(0,2);}
function parse(s,...patterns){if(s==null){return[null,null];}
for(const[regex,extractor]of patterns){const m=regex.exec(s);if(m){return extractor(m);}}
return[null,null];}
function simpleParse(...keys){return(match,cursor)=>{const ret={};let i;for(i=0;i<keys.length;i++){ret[keys[i]]=parseInteger(match[cursor+i]);}
return[ret,null,cursor+i];};}
const offsetRegex=/(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/;const isoExtendedZone=`(?:${offsetRegex.source}?(?:\\[(${ianaRegex.source})\\])?)?`;const isoTimeBaseRegex=/(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/;const isoTimeRegex=RegExp(`${isoTimeBaseRegex.source}${isoExtendedZone}`);const isoTimeExtensionRegex=RegExp(`(?:T${isoTimeRegex.source})?`);const isoYmdRegex=/([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;const isoWeekRegex=/(\d{4})-?W(\d\d)(?:-?(\d))?/;const isoOrdinalRegex=/(\d{4})-?(\d{3})/;const extractISOWeekData=simpleParse("weekYear","weekNumber","weekDay");const extractISOOrdinalData=simpleParse("year","ordinal");const sqlYmdRegex=/(\d{4})-(\d\d)-(\d\d)/;const sqlTimeRegex=RegExp(`${isoTimeBaseRegex.source} ?(?:${offsetRegex.source}|(${ianaRegex.source}))?`);const sqlTimeExtensionRegex=RegExp(`(?: ${sqlTimeRegex.source})?`);function int(match,pos,fallback){const m=match[pos];return isUndefined(m)?fallback:parseInteger(m);}
function extractISOYmd(match,cursor){const item={year:int(match,cursor),month:int(match,cursor+1,1),day:int(match,cursor+2,1),};return[item,null,cursor+3];}
function extractISOTime(match,cursor){const item={hours:int(match,cursor,0),minutes:int(match,cursor+1,0),seconds:int(match,cursor+2,0),milliseconds:parseMillis(match[cursor+3]),};return[item,null,cursor+4];}
function extractISOOffset(match,cursor){const local=!match[cursor]&&!match[cursor+1],fullOffset=signedOffset(match[cursor+1],match[cursor+2]),zone=local?null:FixedOffsetZone.instance(fullOffset);return[{},zone,cursor+3];}
function extractIANAZone(match,cursor){const zone=match[cursor]?IANAZone.create(match[cursor]):null;return[{},zone,cursor+1];}
const isoTimeOnly=RegExp(`^T?${isoTimeBaseRegex.source}$`);const isoDuration=/^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/;function extractISODuration(match){const[s,yearStr,monthStr,weekStr,dayStr,hourStr,minuteStr,secondStr,millisecondsStr]=match;const hasNegativePrefix=s[0]==="-";const negativeSeconds=secondStr&&secondStr[0]==="-";const maybeNegate=(num,force=false)=>num!==undefined&&(force||(num&&hasNegativePrefix))?-num:num;return[{years:maybeNegate(parseFloating(yearStr)),months:maybeNegate(parseFloating(monthStr)),weeks:maybeNegate(parseFloating(weekStr)),days:maybeNegate(parseFloating(dayStr)),hours:maybeNegate(parseFloating(hourStr)),minutes:maybeNegate(parseFloating(minuteStr)),seconds:maybeNegate(parseFloating(secondStr),secondStr==="-0"),milliseconds:maybeNegate(parseMillis(millisecondsStr),negativeSeconds),},];}
const obsOffsets={GMT:0,EDT:-4*60,EST:-5*60,CDT:-5*60,CST:-6*60,MDT:-6*60,MST:-7*60,PDT:-7*60,PST:-8*60,};function fromStrings(weekdayStr,yearStr,monthStr,dayStr,hourStr,minuteStr,secondStr){const result={year:yearStr.length===2?untruncateYear(parseInteger(yearStr)):parseInteger(yearStr),month:monthsShort.indexOf(monthStr)+1,day:parseInteger(dayStr),hour:parseInteger(hourStr),minute:parseInteger(minuteStr),};if(secondStr)result.second=parseInteger(secondStr);if(weekdayStr){result.weekday=weekdayStr.length>3?weekdaysLong.indexOf(weekdayStr)+1:weekdaysShort.indexOf(weekdayStr)+1;}
return result;}
const rfc2822=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;function extractRFC2822(match){const[,weekdayStr,dayStr,monthStr,yearStr,hourStr,minuteStr,secondStr,obsOffset,milOffset,offHourStr,offMinuteStr,]=match,result=fromStrings(weekdayStr,yearStr,monthStr,dayStr,hourStr,minuteStr,secondStr);let offset;if(obsOffset){offset=obsOffsets[obsOffset];}else if(milOffset){offset=0;}else{offset=signedOffset(offHourStr,offMinuteStr);}
return[result,new FixedOffsetZone(offset)];}
function preprocessRFC2822(s){return s.replace(/\([^()]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").trim();}
const rfc1123=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,rfc850=/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,ascii=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;function extractRFC1123Or850(match){const[,weekdayStr,dayStr,monthStr,yearStr,hourStr,minuteStr,secondStr]=match,result=fromStrings(weekdayStr,yearStr,monthStr,dayStr,hourStr,minuteStr,secondStr);return[result,FixedOffsetZone.utcInstance];}
function extractASCII(match){const[,weekdayStr,monthStr,dayStr,hourStr,minuteStr,secondStr,yearStr]=match,result=fromStrings(weekdayStr,yearStr,monthStr,dayStr,hourStr,minuteStr,secondStr);return[result,FixedOffsetZone.utcInstance];}
const isoYmdWithTimeExtensionRegex=combineRegexes(isoYmdRegex,isoTimeExtensionRegex);const isoWeekWithTimeExtensionRegex=combineRegexes(isoWeekRegex,isoTimeExtensionRegex);const isoOrdinalWithTimeExtensionRegex=combineRegexes(isoOrdinalRegex,isoTimeExtensionRegex);const isoTimeCombinedRegex=combineRegexes(isoTimeRegex);const extractISOYmdTimeAndOffset=combineExtractors(extractISOYmd,extractISOTime,extractISOOffset,extractIANAZone);const extractISOWeekTimeAndOffset=combineExtractors(extractISOWeekData,extractISOTime,extractISOOffset,extractIANAZone);const extractISOOrdinalDateAndTime=combineExtractors(extractISOOrdinalData,extractISOTime,extractISOOffset,extractIANAZone);const extractISOTimeAndOffset=combineExtractors(extractISOTime,extractISOOffset,extractIANAZone);function parseISODate(s){return parse(s,[isoYmdWithTimeExtensionRegex,extractISOYmdTimeAndOffset],[isoWeekWithTimeExtensionRegex,extractISOWeekTimeAndOffset],[isoOrdinalWithTimeExtensionRegex,extractISOOrdinalDateAndTime],[isoTimeCombinedRegex,extractISOTimeAndOffset]);}
function parseRFC2822Date(s){return parse(preprocessRFC2822(s),[rfc2822,extractRFC2822]);}
function parseHTTPDate(s){return parse(s,[rfc1123,extractRFC1123Or850],[rfc850,extractRFC1123Or850],[ascii,extractASCII]);}
function parseISODuration(s){return parse(s,[isoDuration,extractISODuration]);}
const extractISOTimeOnly=combineExtractors(extractISOTime);function parseISOTimeOnly(s){return parse(s,[isoTimeOnly,extractISOTimeOnly]);}
const sqlYmdWithTimeExtensionRegex=combineRegexes(sqlYmdRegex,sqlTimeExtensionRegex);const sqlTimeCombinedRegex=combineRegexes(sqlTimeRegex);const extractISOTimeOffsetAndIANAZone=combineExtractors(extractISOTime,extractISOOffset,extractIANAZone);function parseSQL(s){return parse(s,[sqlYmdWithTimeExtensionRegex,extractISOYmdTimeAndOffset],[sqlTimeCombinedRegex,extractISOTimeOffsetAndIANAZone]);}
const INVALID$2="Invalid Duration";const lowOrderMatrix={weeks:{days:7,hours:7*24,minutes:7*24*60,seconds:7*24*60*60,milliseconds:7*24*60*60*1000,},days:{hours:24,minutes:24*60,seconds:24*60*60,milliseconds:24*60*60*1000,},hours:{minutes:60,seconds:60*60,milliseconds:60*60*1000},minutes:{seconds:60,milliseconds:60*1000},seconds:{milliseconds:1000},},casualMatrix={years:{quarters:4,months:12,weeks:52,days:365,hours:365*24,minutes:365*24*60,seconds:365*24*60*60,milliseconds:365*24*60*60*1000,},quarters:{months:3,weeks:13,days:91,hours:91*24,minutes:91*24*60,seconds:91*24*60*60,milliseconds:91*24*60*60*1000,},months:{weeks:4,days:30,hours:30*24,minutes:30*24*60,seconds:30*24*60*60,milliseconds:30*24*60*60*1000,},...lowOrderMatrix,},daysInYearAccurate=146097.0/400,daysInMonthAccurate=146097.0/4800,accurateMatrix={years:{quarters:4,months:12,weeks:daysInYearAccurate/7,days:daysInYearAccurate,hours:daysInYearAccurate*24,minutes:daysInYearAccurate*24*60,seconds:daysInYearAccurate*24*60*60,milliseconds:daysInYearAccurate*24*60*60*1000,},quarters:{months:3,weeks:daysInYearAccurate/28,days:daysInYearAccurate/4,hours:(daysInYearAccurate*24)/4,minutes:(daysInYearAccurate*24*60)/4,seconds:(daysInYearAccurate*24*60*60)/4,milliseconds:(daysInYearAccurate*24*60*60*1000)/4,},months:{weeks:daysInMonthAccurate/7,days:daysInMonthAccurate,hours:daysInMonthAccurate*24,minutes:daysInMonthAccurate*24*60,seconds:daysInMonthAccurate*24*60*60,milliseconds:daysInMonthAccurate*24*60*60*1000,},...lowOrderMatrix,};const orderedUnits$1=["years","quarters","months","weeks","days","hours","minutes","seconds","milliseconds",];const reverseUnits=orderedUnits$1.slice(0).reverse();function clone$1(dur,alts,clear=false){const conf={values:clear?alts.values:{...dur.values,...(alts.values||{})},loc:dur.loc.clone(alts.loc),conversionAccuracy:alts.conversionAccuracy||dur.conversionAccuracy,matrix:alts.matrix||dur.matrix,};return new Duration(conf);}
function durationToMillis(matrix,vals){let sum=vals.milliseconds??0;for(const unit of reverseUnits.slice(1)){if(vals[unit]){sum+=vals[unit]*matrix[unit]["milliseconds"];}}
return sum;}
function normalizeValues(matrix,vals){const factor=durationToMillis(matrix,vals)<0?-1:1;orderedUnits$1.reduceRight((previous,current)=>{if(!isUndefined(vals[current])){if(previous){const previousVal=vals[previous]*factor;const conv=matrix[current][previous];const rollUp=Math.floor(previousVal/conv);vals[current]+=rollUp*factor;vals[previous]-=rollUp*conv*factor;}
return current;}else{return previous;}},null);orderedUnits$1.reduce((previous,current)=>{if(!isUndefined(vals[current])){if(previous){const fraction=vals[previous]%1;vals[previous]-=fraction;vals[current]+=fraction*matrix[previous][current];}
return current;}else{return previous;}},null);}
function removeZeroes(vals){const newVals={};for(const[key,value]of Object.entries(vals)){if(value!==0){newVals[key]=value;}}
return newVals;}
class Duration{constructor(config){const accurate=config.conversionAccuracy==="longterm"||false;let matrix=accurate?accurateMatrix:casualMatrix;if(config.matrix){matrix=config.matrix;}
this.values=config.values;this.loc=config.loc||Locale.create();this.conversionAccuracy=accurate?"longterm":"casual";this.invalid=config.invalid||null;this.matrix=matrix;this.isLuxonDuration=true;}
static fromMillis(count,opts){return Duration.fromObject({milliseconds:count},opts);}
static fromObject(obj,opts={}){if(obj==null||typeof obj!=="object"){throw new InvalidArgumentError(`Duration.fromObject: argument expected to be an object, got ${
          obj === null ? "null" : typeof obj
        }`);}
return new Duration({values:normalizeObject(obj,Duration.normalizeUnit),loc:Locale.fromObject(opts),conversionAccuracy:opts.conversionAccuracy,matrix:opts.matrix,});}
static fromDurationLike(durationLike){if(isNumber(durationLike)){return Duration.fromMillis(durationLike);}else if(Duration.isDuration(durationLike)){return durationLike;}else if(typeof durationLike==="object"){return Duration.fromObject(durationLike);}else{throw new InvalidArgumentError(`Unknown duration argument ${durationLike} of type ${typeof durationLike}`);}}
static fromISO(text,opts){const[parsed]=parseISODuration(text);if(parsed){return Duration.fromObject(parsed,opts);}else{return Duration.invalid("unparsable",`the input "${text}" can't be parsed as ISO 8601`);}}
static fromISOTime(text,opts){const[parsed]=parseISOTimeOnly(text);if(parsed){return Duration.fromObject(parsed,opts);}else{return Duration.invalid("unparsable",`the input "${text}" can't be parsed as ISO 8601`);}}
static invalid(reason,explanation=null){if(!reason){throw new InvalidArgumentError("need to specify a reason the Duration is invalid");}
const invalid=reason instanceof Invalid?reason:new Invalid(reason,explanation);if(Settings.throwOnInvalid){throw new InvalidDurationError(invalid);}else{return new Duration({invalid});}}
static normalizeUnit(unit){const normalized={year:"years",years:"years",quarter:"quarters",quarters:"quarters",month:"months",months:"months",week:"weeks",weeks:"weeks",day:"days",days:"days",hour:"hours",hours:"hours",minute:"minutes",minutes:"minutes",second:"seconds",seconds:"seconds",millisecond:"milliseconds",milliseconds:"milliseconds",}[unit?unit.toLowerCase():unit];if(!normalized)throw new InvalidUnitError(unit);return normalized;}
static isDuration(o){return(o&&o.isLuxonDuration)||false;}
get locale(){return this.isValid?this.loc.locale:null;}
get numberingSystem(){return this.isValid?this.loc.numberingSystem:null;}
toFormat(fmt,opts={}){const fmtOpts={...opts,floor:opts.round!==false&&opts.floor!==false,};return this.isValid?Formatter.create(this.loc,fmtOpts).formatDurationFromString(this,fmt):INVALID$2;}
toHuman(opts={}){if(!this.isValid)return INVALID$2;const l=orderedUnits$1.map((unit)=>{const val=this.values[unit];if(isUndefined(val)){return null;}
return this.loc.numberFormatter({style:"unit",unitDisplay:"long",...opts,unit:unit.slice(0,-1)}).format(val);}).filter((n)=>n);return this.loc.listFormatter({type:"conjunction",style:opts.listStyle||"narrow",...opts}).format(l);}
toObject(){if(!this.isValid)return{};return{...this.values};}
toISO(){if(!this.isValid)return null;let s="P";if(this.years!==0)s+=this.years+"Y";if(this.months!==0||this.quarters!==0)s+=this.months+this.quarters*3+"M";if(this.weeks!==0)s+=this.weeks+"W";if(this.days!==0)s+=this.days+"D";if(this.hours!==0||this.minutes!==0||this.seconds!==0||this.milliseconds!==0)
s+="T";if(this.hours!==0)s+=this.hours+"H";if(this.minutes!==0)s+=this.minutes+"M";if(this.seconds!==0||this.milliseconds!==0)
s+=roundTo(this.seconds+this.milliseconds/1000,3)+"S";if(s==="P")s+="T0S";return s;}
toISOTime(opts={}){if(!this.isValid)return null;const millis=this.toMillis();if(millis<0||millis>=86400000)return null;opts={suppressMilliseconds:false,suppressSeconds:false,includePrefix:false,format:"extended",...opts,includeOffset:false,};const dateTime=DateTime.fromMillis(millis,{zone:"UTC"});return dateTime.toISOTime(opts);}
toJSON(){return this.toISO();}
toString(){return this.toISO();}
[Symbol.for("nodejs.util.inspect.custom")](){if(this.isValid){return`Duration { values: ${JSON.stringify(this.values)} }`;}else{return`Duration { Invalid, reason: ${this.invalidReason} }`;}}
toMillis(){if(!this.isValid)return NaN;return durationToMillis(this.matrix,this.values);}
valueOf(){return this.toMillis();}
plus(duration){if(!this.isValid)return this;const dur=Duration.fromDurationLike(duration),result={};for(const k of orderedUnits$1){if(hasOwnProperty(dur.values,k)||hasOwnProperty(this.values,k)){result[k]=dur.get(k)+this.get(k);}}
return clone$1(this,{values:result},true);}
minus(duration){if(!this.isValid)return this;const dur=Duration.fromDurationLike(duration);return this.plus(dur.negate());}
mapUnits(fn){if(!this.isValid)return this;const result={};for(const k of Object.keys(this.values)){result[k]=asNumber(fn(this.values[k],k));}
return clone$1(this,{values:result},true);}
get(unit){return this[Duration.normalizeUnit(unit)];}
set(values){if(!this.isValid)return this;const mixed={...this.values,...normalizeObject(values,Duration.normalizeUnit)};return clone$1(this,{values:mixed});}
reconfigure({locale,numberingSystem,conversionAccuracy,matrix}={}){const loc=this.loc.clone({locale,numberingSystem});const opts={loc,matrix,conversionAccuracy};return clone$1(this,opts);}
as(unit){return this.isValid?this.shiftTo(unit).get(unit):NaN;}
normalize(){if(!this.isValid)return this;const vals=this.toObject();normalizeValues(this.matrix,vals);return clone$1(this,{values:vals},true);}
rescale(){if(!this.isValid)return this;const vals=removeZeroes(this.normalize().shiftToAll().toObject());return clone$1(this,{values:vals},true);}
shiftTo(...units){if(!this.isValid)return this;if(units.length===0){return this;}
units=units.map((u)=>Duration.normalizeUnit(u));const built={},accumulated={},vals=this.toObject();let lastUnit;for(const k of orderedUnits$1){if(units.indexOf(k)>=0){lastUnit=k;let own=0;for(const ak in accumulated){own+=this.matrix[ak][k]*accumulated[ak];accumulated[ak]=0;}
if(isNumber(vals[k])){own+=vals[k];}
const i=Math.trunc(own);built[k]=i;accumulated[k]=(own*1000-i*1000)/1000;}else if(isNumber(vals[k])){accumulated[k]=vals[k];}}
for(const key in accumulated){if(accumulated[key]!==0){built[lastUnit]+=key===lastUnit?accumulated[key]:accumulated[key]/this.matrix[lastUnit][key];}}
normalizeValues(this.matrix,built);return clone$1(this,{values:built},true);}
shiftToAll(){if(!this.isValid)return this;return this.shiftTo("years","months","weeks","days","hours","minutes","seconds","milliseconds");}
negate(){if(!this.isValid)return this;const negated={};for(const k of Object.keys(this.values)){negated[k]=this.values[k]===0?0:-this.values[k];}
return clone$1(this,{values:negated},true);}
get years(){return this.isValid?this.values.years||0:NaN;}
get quarters(){return this.isValid?this.values.quarters||0:NaN;}
get months(){return this.isValid?this.values.months||0:NaN;}
get weeks(){return this.isValid?this.values.weeks||0:NaN;}
get days(){return this.isValid?this.values.days||0:NaN;}
get hours(){return this.isValid?this.values.hours||0:NaN;}
get minutes(){return this.isValid?this.values.minutes||0:NaN;}
get seconds(){return this.isValid?this.values.seconds||0:NaN;}
get milliseconds(){return this.isValid?this.values.milliseconds||0:NaN;}
get isValid(){return this.invalid===null;}
get invalidReason(){return this.invalid?this.invalid.reason:null;}
get invalidExplanation(){return this.invalid?this.invalid.explanation:null;}
equals(other){if(!this.isValid||!other.isValid){return false;}
if(!this.loc.equals(other.loc)){return false;}
function eq(v1,v2){if(v1===undefined||v1===0)return v2===undefined||v2===0;return v1===v2;}
for(const u of orderedUnits$1){if(!eq(this.values[u],other.values[u])){return false;}}
return true;}}
const INVALID$1="Invalid Interval";function validateStartEnd(start,end){if(!start||!start.isValid){return Interval.invalid("missing or invalid start");}else if(!end||!end.isValid){return Interval.invalid("missing or invalid end");}else if(end<start){return Interval.invalid("end before start",`The end of an interval must be after its start, but you had start=${start.toISO()} and end=${end.toISO()}`);}else{return null;}}
class Interval{constructor(config){this.s=config.start;this.e=config.end;this.invalid=config.invalid||null;this.isLuxonInterval=true;}
static invalid(reason,explanation=null){if(!reason){throw new InvalidArgumentError("need to specify a reason the Interval is invalid");}
const invalid=reason instanceof Invalid?reason:new Invalid(reason,explanation);if(Settings.throwOnInvalid){throw new InvalidIntervalError(invalid);}else{return new Interval({invalid});}}
static fromDateTimes(start,end){const builtStart=friendlyDateTime(start),builtEnd=friendlyDateTime(end);const validateError=validateStartEnd(builtStart,builtEnd);if(validateError==null){return new Interval({start:builtStart,end:builtEnd,});}else{return validateError;}}
static after(start,duration){const dur=Duration.fromDurationLike(duration),dt=friendlyDateTime(start);return Interval.fromDateTimes(dt,dt.plus(dur));}
static before(end,duration){const dur=Duration.fromDurationLike(duration),dt=friendlyDateTime(end);return Interval.fromDateTimes(dt.minus(dur),dt);}
static fromISO(text,opts){const[s,e]=(text||"").split("/",2);if(s&&e){let start,startIsValid;try{start=DateTime.fromISO(s,opts);startIsValid=start.isValid;}catch(e){startIsValid=false;}
let end,endIsValid;try{end=DateTime.fromISO(e,opts);endIsValid=end.isValid;}catch(e){endIsValid=false;}
if(startIsValid&&endIsValid){return Interval.fromDateTimes(start,end);}
if(startIsValid){const dur=Duration.fromISO(e,opts);if(dur.isValid){return Interval.after(start,dur);}}else if(endIsValid){const dur=Duration.fromISO(s,opts);if(dur.isValid){return Interval.before(end,dur);}}}
return Interval.invalid("unparsable",`the input "${text}" can't be parsed as ISO 8601`);}
static isInterval(o){return(o&&o.isLuxonInterval)||false;}
get start(){return this.isValid?this.s:null;}
get end(){return this.isValid?this.e:null;}
get isValid(){return this.invalidReason===null;}
get invalidReason(){return this.invalid?this.invalid.reason:null;}
get invalidExplanation(){return this.invalid?this.invalid.explanation:null;}
length(unit="milliseconds"){return this.isValid?this.toDuration(...[unit]).get(unit):NaN;}
count(unit="milliseconds",opts){if(!this.isValid)return NaN;const start=this.start.startOf(unit,opts);let end;if(opts?.useLocaleWeeks){end=this.end.reconfigure({locale:start.locale});}else{end=this.end;}
end=end.startOf(unit,opts);return Math.floor(end.diff(start,unit).get(unit))+(end.valueOf()!==this.end.valueOf());}
hasSame(unit){return this.isValid?this.isEmpty()||this.e.minus(1).hasSame(this.s,unit):false;}
isEmpty(){return this.s.valueOf()===this.e.valueOf();}
isAfter(dateTime){if(!this.isValid)return false;return this.s>dateTime;}
isBefore(dateTime){if(!this.isValid)return false;return this.e<=dateTime;}
contains(dateTime){if(!this.isValid)return false;return this.s<=dateTime&&this.e>dateTime;}
set({start,end}={}){if(!this.isValid)return this;return Interval.fromDateTimes(start||this.s,end||this.e);}
splitAt(...dateTimes){if(!this.isValid)return[];const sorted=dateTimes.map(friendlyDateTime).filter((d)=>this.contains(d)).sort((a,b)=>a.toMillis()-b.toMillis()),results=[];let{s}=this,i=0;while(s<this.e){const added=sorted[i]||this.e,next=+added>+this.e?this.e:added;results.push(Interval.fromDateTimes(s,next));s=next;i+=1;}
return results;}
splitBy(duration){const dur=Duration.fromDurationLike(duration);if(!this.isValid||!dur.isValid||dur.as("milliseconds")===0){return[];}
let{s}=this,idx=1,next;const results=[];while(s<this.e){const added=this.start.plus(dur.mapUnits((x)=>x*idx));next=+added>+this.e?this.e:added;results.push(Interval.fromDateTimes(s,next));s=next;idx+=1;}
return results;}
divideEqually(numberOfParts){if(!this.isValid)return[];return this.splitBy(this.length()/numberOfParts).slice(0,numberOfParts);}
overlaps(other){return this.e>other.s&&this.s<other.e;}
abutsStart(other){if(!this.isValid)return false;return+this.e===+other.s;}
abutsEnd(other){if(!this.isValid)return false;return+other.e===+this.s;}
engulfs(other){if(!this.isValid)return false;return this.s<=other.s&&this.e>=other.e;}
equals(other){if(!this.isValid||!other.isValid){return false;}
return this.s.equals(other.s)&&this.e.equals(other.e);}
intersection(other){if(!this.isValid)return this;const s=this.s>other.s?this.s:other.s,e=this.e<other.e?this.e:other.e;if(s>=e){return null;}else{return Interval.fromDateTimes(s,e);}}
union(other){if(!this.isValid)return this;const s=this.s<other.s?this.s:other.s,e=this.e>other.e?this.e:other.e;return Interval.fromDateTimes(s,e);}
static merge(intervals){const[found,final]=intervals.sort((a,b)=>a.s-b.s).reduce(([sofar,current],item)=>{if(!current){return[sofar,item];}else if(current.overlaps(item)||current.abutsStart(item)){return[sofar,current.union(item)];}else{return[sofar.concat([current]),item];}},[[],null]);if(final){found.push(final);}
return found;}
static xor(intervals){let start=null,currentCount=0;const results=[],ends=intervals.map((i)=>[{time:i.s,type:"s"},{time:i.e,type:"e"},]),flattened=Array.prototype.concat(...ends),arr=flattened.sort((a,b)=>a.time-b.time);for(const i of arr){currentCount+=i.type==="s"?1:-1;if(currentCount===1){start=i.time;}else{if(start&&+start!==+i.time){results.push(Interval.fromDateTimes(start,i.time));}
start=null;}}
return Interval.merge(results);}
difference(...intervals){return Interval.xor([this].concat(intervals)).map((i)=>this.intersection(i)).filter((i)=>i&&!i.isEmpty());}
toString(){if(!this.isValid)return INVALID$1;return`[${this.s.toISO()} – ${this.e.toISO()})`;}
[Symbol.for("nodejs.util.inspect.custom")](){if(this.isValid){return`Interval { start: ${this.s.toISO()}, end: ${this.e.toISO()} }`;}else{return`Interval { Invalid, reason: ${this.invalidReason} }`;}}
toLocaleString(formatOpts=DATE_SHORT,opts={}){return this.isValid?Formatter.create(this.s.loc.clone(opts),formatOpts).formatInterval(this):INVALID$1;}
toISO(opts){if(!this.isValid)return INVALID$1;return`${this.s.toISO(opts)}/${this.e.toISO(opts)}`;}
toISODate(){if(!this.isValid)return INVALID$1;return`${this.s.toISODate()}/${this.e.toISODate()}`;}
toISOTime(opts){if(!this.isValid)return INVALID$1;return`${this.s.toISOTime(opts)}/${this.e.toISOTime(opts)}`;}
toFormat(dateFormat,{separator=" – "}={}){if(!this.isValid)return INVALID$1;return`${this.s.toFormat(dateFormat)}${separator}${this.e.toFormat(dateFormat)}`;}
toDuration(unit,opts){if(!this.isValid){return Duration.invalid(this.invalidReason);}
return this.e.diff(this.s,unit,opts);}
mapEndpoints(mapFn){return Interval.fromDateTimes(mapFn(this.s),mapFn(this.e));}}
class Info{static hasDST(zone=Settings.defaultZone){const proto=DateTime.now().setZone(zone).set({month:12});return!zone.isUniversal&&proto.offset!==proto.set({month:6}).offset;}
static isValidIANAZone(zone){return IANAZone.isValidZone(zone);}
static normalizeZone(input){return normalizeZone(input,Settings.defaultZone);}
static getStartOfWeek({locale=null,locObj=null}={}){return(locObj||Locale.create(locale)).getStartOfWeek();}
static getMinimumDaysInFirstWeek({locale=null,locObj=null}={}){return(locObj||Locale.create(locale)).getMinDaysInFirstWeek();}
static getWeekendWeekdays({locale=null,locObj=null}={}){return(locObj||Locale.create(locale)).getWeekendDays().slice();}
static months(length="long",{locale=null,numberingSystem=null,locObj=null,outputCalendar="gregory"}={}){return(locObj||Locale.create(locale,numberingSystem,outputCalendar)).months(length);}
static monthsFormat(length="long",{locale=null,numberingSystem=null,locObj=null,outputCalendar="gregory"}={}){return(locObj||Locale.create(locale,numberingSystem,outputCalendar)).months(length,true);}
static weekdays(length="long",{locale=null,numberingSystem=null,locObj=null}={}){return(locObj||Locale.create(locale,numberingSystem,null)).weekdays(length);}
static weekdaysFormat(length="long",{locale=null,numberingSystem=null,locObj=null}={}){return(locObj||Locale.create(locale,numberingSystem,null)).weekdays(length,true);}
static meridiems({locale=null}={}){return Locale.create(locale).meridiems();}
static eras(length="short",{locale=null}={}){return Locale.create(locale,null,"gregory").eras(length);}
static features(){return{relative:hasRelative(),localeWeek:hasLocaleWeekInfo()};}}
function dayDiff(earlier,later){const utcDayStart=(dt)=>dt.toUTC(0,{keepLocalTime:true}).startOf("day").valueOf(),ms=utcDayStart(later)-utcDayStart(earlier);return Math.floor(Duration.fromMillis(ms).as("days"));}
function highOrderDiffs(cursor,later,units){const differs=[["years",(a,b)=>b.year-a.year],["quarters",(a,b)=>b.quarter-a.quarter+(b.year-a.year)*4],["months",(a,b)=>b.month-a.month+(b.year-a.year)*12],["weeks",(a,b)=>{const days=dayDiff(a,b);return(days-(days%7))/7;},],["days",dayDiff],];const results={};const earlier=cursor;let lowestOrder,highWater;for(const[unit,differ]of differs){if(units.indexOf(unit)>=0){lowestOrder=unit;results[unit]=differ(cursor,later);highWater=earlier.plus(results);if(highWater>later){results[unit]--;cursor=earlier.plus(results);if(cursor>later){highWater=cursor;results[unit]--;cursor=earlier.plus(results);}}else{cursor=highWater;}}}
return[cursor,results,highWater,lowestOrder];}
function diff(earlier,later,units,opts){let[cursor,results,highWater,lowestOrder]=highOrderDiffs(earlier,later,units);const remainingMillis=later-cursor;const lowerOrderUnits=units.filter((u)=>["hours","minutes","seconds","milliseconds"].indexOf(u)>=0);if(lowerOrderUnits.length===0){if(highWater<later){highWater=cursor.plus({[lowestOrder]:1});}
if(highWater!==cursor){results[lowestOrder]=(results[lowestOrder]||0)+remainingMillis/(highWater-cursor);}}
const duration=Duration.fromObject(results,opts);if(lowerOrderUnits.length>0){return Duration.fromMillis(remainingMillis,opts).shiftTo(...lowerOrderUnits).plus(duration);}else{return duration;}}
const numberingSystems={arab:"[\u0660-\u0669]",arabext:"[\u06F0-\u06F9]",bali:"[\u1B50-\u1B59]",beng:"[\u09E6-\u09EF]",deva:"[\u0966-\u096F]",fullwide:"[\uFF10-\uFF19]",gujr:"[\u0AE6-\u0AEF]",hanidec:"[〇|一|二|三|四|五|六|七|八|九]",khmr:"[\u17E0-\u17E9]",knda:"[\u0CE6-\u0CEF]",laoo:"[\u0ED0-\u0ED9]",limb:"[\u1946-\u194F]",mlym:"[\u0D66-\u0D6F]",mong:"[\u1810-\u1819]",mymr:"[\u1040-\u1049]",orya:"[\u0B66-\u0B6F]",tamldec:"[\u0BE6-\u0BEF]",telu:"[\u0C66-\u0C6F]",thai:"[\u0E50-\u0E59]",tibt:"[\u0F20-\u0F29]",latn:"\\d",};const numberingSystemsUTF16={arab:[1632,1641],arabext:[1776,1785],bali:[6992,7001],beng:[2534,2543],deva:[2406,2415],fullwide:[65296,65303],gujr:[2790,2799],khmr:[6112,6121],knda:[3302,3311],laoo:[3792,3801],limb:[6470,6479],mlym:[3430,3439],mong:[6160,6169],mymr:[4160,4169],orya:[2918,2927],tamldec:[3046,3055],telu:[3174,3183],thai:[3664,3673],tibt:[3872,3881],};const hanidecChars=numberingSystems.hanidec.replace(/[\[|\]]/g,"").split("");function parseDigits(str){let value=parseInt(str,10);if(isNaN(value)){value="";for(let i=0;i<str.length;i++){const code=str.charCodeAt(i);if(str[i].search(numberingSystems.hanidec)!==-1){value+=hanidecChars.indexOf(str[i]);}else{for(const key in numberingSystemsUTF16){const[min,max]=numberingSystemsUTF16[key];if(code>=min&&code<=max){value+=code-min;}}}}
return parseInt(value,10);}else{return value;}}
function digitRegex({numberingSystem},append=""){return new RegExp(`${numberingSystems[numberingSystem || "latn"]}${append}`);}
const MISSING_FTP="missing Intl.DateTimeFormat.formatToParts support";function intUnit(regex,post=(i)=>i){return{regex,deser:([s])=>post(parseDigits(s))};}
const NBSP=String.fromCharCode(160);const spaceOrNBSP=`[ ${NBSP}]`;const spaceOrNBSPRegExp=new RegExp(spaceOrNBSP,"g");function fixListRegex(s){return s.replace(/\./g,"\\.?").replace(spaceOrNBSPRegExp,spaceOrNBSP);}
function stripInsensitivities(s){return s.replace(/\./g,"").replace(spaceOrNBSPRegExp," ").toLowerCase();}
function oneOf(strings,startIndex){if(strings===null){return null;}else{return{regex:RegExp(strings.map(fixListRegex).join("|")),deser:([s])=>strings.findIndex((i)=>stripInsensitivities(s)===stripInsensitivities(i))+startIndex,};}}
function offset(regex,groups){return{regex,deser:([,h,m])=>signedOffset(h,m),groups};}
function simple(regex){return{regex,deser:([s])=>s};}
function escapeToken(value){return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");}
function unitForToken(token,loc){const one=digitRegex(loc),two=digitRegex(loc,"{2}"),three=digitRegex(loc,"{3}"),four=digitRegex(loc,"{4}"),six=digitRegex(loc,"{6}"),oneOrTwo=digitRegex(loc,"{1,2}"),oneToThree=digitRegex(loc,"{1,3}"),oneToSix=digitRegex(loc,"{1,6}"),oneToNine=digitRegex(loc,"{1,9}"),twoToFour=digitRegex(loc,"{2,4}"),fourToSix=digitRegex(loc,"{4,6}"),literal=(t)=>({regex:RegExp(escapeToken(t.val)),deser:([s])=>s,literal:true}),unitate=(t)=>{if(token.literal){return literal(t);}
switch(t.val){case"G":return oneOf(loc.eras("short"),0);case"GG":return oneOf(loc.eras("long"),0);case"y":return intUnit(oneToSix);case"yy":return intUnit(twoToFour,untruncateYear);case"yyyy":return intUnit(four);case"yyyyy":return intUnit(fourToSix);case"yyyyyy":return intUnit(six);case"M":return intUnit(oneOrTwo);case"MM":return intUnit(two);case"MMM":return oneOf(loc.months("short",true),1);case"MMMM":return oneOf(loc.months("long",true),1);case"L":return intUnit(oneOrTwo);case"LL":return intUnit(two);case"LLL":return oneOf(loc.months("short",false),1);case"LLLL":return oneOf(loc.months("long",false),1);case"d":return intUnit(oneOrTwo);case"dd":return intUnit(two);case"o":return intUnit(oneToThree);case"ooo":return intUnit(three);case"HH":return intUnit(two);case"H":return intUnit(oneOrTwo);case"hh":return intUnit(two);case"h":return intUnit(oneOrTwo);case"mm":return intUnit(two);case"m":return intUnit(oneOrTwo);case"q":return intUnit(oneOrTwo);case"qq":return intUnit(two);case"s":return intUnit(oneOrTwo);case"ss":return intUnit(two);case"S":return intUnit(oneToThree);case"SSS":return intUnit(three);case"u":return simple(oneToNine);case"uu":return simple(oneOrTwo);case"uuu":return intUnit(one);case"a":return oneOf(loc.meridiems(),0);case"kkkk":return intUnit(four);case"kk":return intUnit(twoToFour,untruncateYear);case"W":return intUnit(oneOrTwo);case"WW":return intUnit(two);case"E":case"c":return intUnit(one);case"EEE":return oneOf(loc.weekdays("short",false),1);case"EEEE":return oneOf(loc.weekdays("long",false),1);case"ccc":return oneOf(loc.weekdays("short",true),1);case"cccc":return oneOf(loc.weekdays("long",true),1);case"Z":case"ZZ":return offset(new RegExp(`([+-]${oneOrTwo.source})(?::(${two.source}))?`),2);case"ZZZ":return offset(new RegExp(`([+-]${oneOrTwo.source})(${two.source})?`),2);case"z":return simple(/[a-z_+-/]{1,256}?/i);case" ":return simple(/[^\S\n\r]/);default:return literal(t);}};const unit=unitate(token)||{invalidReason:MISSING_FTP,};unit.token=token;return unit;}
const partTypeStyleToTokenVal={year:{"2-digit":"yy",numeric:"yyyyy",},month:{numeric:"M","2-digit":"MM",short:"MMM",long:"MMMM",},day:{numeric:"d","2-digit":"dd",},weekday:{short:"EEE",long:"EEEE",},dayperiod:"a",dayPeriod:"a",hour12:{numeric:"h","2-digit":"hh",},hour24:{numeric:"H","2-digit":"HH",},minute:{numeric:"m","2-digit":"mm",},second:{numeric:"s","2-digit":"ss",},timeZoneName:{long:"ZZZZZ",short:"ZZZ",},};function tokenForPart(part,formatOpts,resolvedOpts){const{type,value}=part;if(type==="literal"){const isSpace=/^\s+$/.test(value);return{literal:!isSpace,val:isSpace?" ":value,};}
const style=formatOpts[type];let actualType=type;if(type==="hour"){if(formatOpts.hour12!=null){actualType=formatOpts.hour12?"hour12":"hour24";}else if(formatOpts.hourCycle!=null){if(formatOpts.hourCycle==="h11"||formatOpts.hourCycle==="h12"){actualType="hour12";}else{actualType="hour24";}}else{actualType=resolvedOpts.hour12?"hour12":"hour24";}}
let val=partTypeStyleToTokenVal[actualType];if(typeof val==="object"){val=val[style];}
if(val){return{literal:false,val,};}
return undefined;}
function buildRegex(units){const re=units.map((u)=>u.regex).reduce((f,r)=>`${f}(${r.source})`,"");return[`^${re}$`,units];}
function match(input,regex,handlers){const matches=input.match(regex);if(matches){const all={};let matchIndex=1;for(const i in handlers){if(hasOwnProperty(handlers,i)){const h=handlers[i],groups=h.groups?h.groups+1:1;if(!h.literal&&h.token){all[h.token.val[0]]=h.deser(matches.slice(matchIndex,matchIndex+groups));}
matchIndex+=groups;}}
return[matches,all];}else{return[matches,{}];}}
function dateTimeFromMatches(matches){const toField=(token)=>{switch(token){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":case"H":return"hour";case"d":return"day";case"o":return"ordinal";case"L":case"M":return"month";case"y":return"year";case"E":case"c":return"weekday";case"W":return"weekNumber";case"k":return"weekYear";case"q":return"quarter";default:return null;}};let zone=null;let specificOffset;if(!isUndefined(matches.z)){zone=IANAZone.create(matches.z);}
if(!isUndefined(matches.Z)){if(!zone){zone=new FixedOffsetZone(matches.Z);}
specificOffset=matches.Z;}
if(!isUndefined(matches.q)){matches.M=(matches.q-1)*3+1;}
if(!isUndefined(matches.h)){if(matches.h<12&&matches.a===1){matches.h+=12;}else if(matches.h===12&&matches.a===0){matches.h=0;}}
if(matches.G===0&&matches.y){matches.y=-matches.y;}
if(!isUndefined(matches.u)){matches.S=parseMillis(matches.u);}
const vals=Object.keys(matches).reduce((r,k)=>{const f=toField(k);if(f){r[f]=matches[k];}
return r;},{});return[vals,zone,specificOffset];}
let dummyDateTimeCache=null;function getDummyDateTime(){if(!dummyDateTimeCache){dummyDateTimeCache=DateTime.fromMillis(1555555555555);}
return dummyDateTimeCache;}
function maybeExpandMacroToken(token,locale){if(token.literal){return token;}
const formatOpts=Formatter.macroTokenToFormatOpts(token.val);const tokens=formatOptsToTokens(formatOpts,locale);if(tokens==null||tokens.includes(undefined)){return token;}
return tokens;}
function expandMacroTokens(tokens,locale){return Array.prototype.concat(...tokens.map((t)=>maybeExpandMacroToken(t,locale)));}
function explainFromTokens(locale,input,format){const tokens=expandMacroTokens(Formatter.parseFormat(format),locale),units=tokens.map((t)=>unitForToken(t,locale)),disqualifyingUnit=units.find((t)=>t.invalidReason);if(disqualifyingUnit){return{input,tokens,invalidReason:disqualifyingUnit.invalidReason};}else{const[regexString,handlers]=buildRegex(units),regex=RegExp(regexString,"i"),[rawMatches,matches]=match(input,regex,handlers),[result,zone,specificOffset]=matches?dateTimeFromMatches(matches):[null,null,undefined];if(hasOwnProperty(matches,"a")&&hasOwnProperty(matches,"H")){throw new ConflictingSpecificationError("Can't include meridiem when specifying 24-hour format");}
return{input,tokens,regex,rawMatches,matches,result,zone,specificOffset};}}
function parseFromTokens(locale,input,format){const{result,zone,specificOffset,invalidReason}=explainFromTokens(locale,input,format);return[result,zone,specificOffset,invalidReason];}
function formatOptsToTokens(formatOpts,locale){if(!formatOpts){return null;}
const formatter=Formatter.create(locale,formatOpts);const df=formatter.dtFormatter(getDummyDateTime());const parts=df.formatToParts();const resolvedOpts=df.resolvedOptions();return parts.map((p)=>tokenForPart(p,formatOpts,resolvedOpts));}
const INVALID="Invalid DateTime";const MAX_DATE=8.64e15;function unsupportedZone(zone){return new Invalid("unsupported zone",`the zone "${zone.name}" is not supported`);}
function possiblyCachedWeekData(dt){if(dt.weekData===null){dt.weekData=gregorianToWeek(dt.c);}
return dt.weekData;}
function possiblyCachedLocalWeekData(dt){if(dt.localWeekData===null){dt.localWeekData=gregorianToWeek(dt.c,dt.loc.getMinDaysInFirstWeek(),dt.loc.getStartOfWeek());}
return dt.localWeekData;}
function clone(inst,alts){const current={ts:inst.ts,zone:inst.zone,c:inst.c,o:inst.o,loc:inst.loc,invalid:inst.invalid,};return new DateTime({...current,...alts,old:current});}
function fixOffset(localTS,o,tz){let utcGuess=localTS-o*60*1000;const o2=tz.offset(utcGuess);if(o===o2){return[utcGuess,o];}
utcGuess-=(o2-o)*60*1000;const o3=tz.offset(utcGuess);if(o2===o3){return[utcGuess,o2];}
return[localTS-Math.min(o2,o3)*60*1000,Math.max(o2,o3)];}
function tsToObj(ts,offset){ts+=offset*60*1000;const d=new Date(ts);return{year:d.getUTCFullYear(),month:d.getUTCMonth()+1,day:d.getUTCDate(),hour:d.getUTCHours(),minute:d.getUTCMinutes(),second:d.getUTCSeconds(),millisecond:d.getUTCMilliseconds(),};}
function objToTS(obj,offset,zone){return fixOffset(objToLocalTS(obj),offset,zone);}
function adjustTime(inst,dur){const oPre=inst.o,year=inst.c.year+Math.trunc(dur.years),month=inst.c.month+Math.trunc(dur.months)+Math.trunc(dur.quarters)*3,c={...inst.c,year,month,day:Math.min(inst.c.day,daysInMonth(year,month))+
Math.trunc(dur.days)+
Math.trunc(dur.weeks)*7,},millisToAdd=Duration.fromObject({years:dur.years-Math.trunc(dur.years),quarters:dur.quarters-Math.trunc(dur.quarters),months:dur.months-Math.trunc(dur.months),weeks:dur.weeks-Math.trunc(dur.weeks),days:dur.days-Math.trunc(dur.days),hours:dur.hours,minutes:dur.minutes,seconds:dur.seconds,milliseconds:dur.milliseconds,}).as("milliseconds"),localTS=objToLocalTS(c);let[ts,o]=fixOffset(localTS,oPre,inst.zone);if(millisToAdd!==0){ts+=millisToAdd;o=inst.zone.offset(ts);}
return{ts,o};}
function parseDataToDateTime(parsed,parsedZone,opts,format,text,specificOffset){const{setZone,zone}=opts;if((parsed&&Object.keys(parsed).length!==0)||parsedZone){const interpretationZone=parsedZone||zone,inst=DateTime.fromObject(parsed,{...opts,zone:interpretationZone,specificOffset,});return setZone?inst:inst.setZone(zone);}else{return DateTime.invalid(new Invalid("unparsable",`the input "${text}" can't be parsed as ${format}`));}}
function toTechFormat(dt,format,allowZ=true){return dt.isValid?Formatter.create(Locale.create("en-US"),{allowZ,forceSimple:true,}).formatDateTimeFromString(dt,format):null;}
function toISODate(o,extended){const longFormat=o.c.year>9999||o.c.year<0;let c="";if(longFormat&&o.c.year>=0)c+="+";c+=padStart(o.c.year,longFormat?6:4);if(extended){c+="-";c+=padStart(o.c.month);c+="-";c+=padStart(o.c.day);}else{c+=padStart(o.c.month);c+=padStart(o.c.day);}
return c;}
function toISOTime(o,extended,suppressSeconds,suppressMilliseconds,includeOffset,extendedZone){let c=padStart(o.c.hour);if(extended){c+=":";c+=padStart(o.c.minute);if(o.c.millisecond!==0||o.c.second!==0||!suppressSeconds){c+=":";}}else{c+=padStart(o.c.minute);}
if(o.c.millisecond!==0||o.c.second!==0||!suppressSeconds){c+=padStart(o.c.second);if(o.c.millisecond!==0||!suppressMilliseconds){c+=".";c+=padStart(o.c.millisecond,3);}}
if(includeOffset){if(o.isOffsetFixed&&o.offset===0&&!extendedZone){c+="Z";}else if(o.o<0){c+="-";c+=padStart(Math.trunc(-o.o/60));c+=":";c+=padStart(Math.trunc(-o.o%60));}else{c+="+";c+=padStart(Math.trunc(o.o/60));c+=":";c+=padStart(Math.trunc(o.o%60));}}
if(extendedZone){c+="["+o.zone.ianaName+"]";}
return c;}
const defaultUnitValues={month:1,day:1,hour:0,minute:0,second:0,millisecond:0,},defaultWeekUnitValues={weekNumber:1,weekday:1,hour:0,minute:0,second:0,millisecond:0,},defaultOrdinalUnitValues={ordinal:1,hour:0,minute:0,second:0,millisecond:0,};const orderedUnits=["year","month","day","hour","minute","second","millisecond"],orderedWeekUnits=["weekYear","weekNumber","weekday","hour","minute","second","millisecond",],orderedOrdinalUnits=["year","ordinal","hour","minute","second","millisecond"];function normalizeUnit(unit){const normalized={year:"year",years:"year",month:"month",months:"month",day:"day",days:"day",hour:"hour",hours:"hour",minute:"minute",minutes:"minute",quarter:"quarter",quarters:"quarter",second:"second",seconds:"second",millisecond:"millisecond",milliseconds:"millisecond",weekday:"weekday",weekdays:"weekday",weeknumber:"weekNumber",weeksnumber:"weekNumber",weeknumbers:"weekNumber",weekyear:"weekYear",weekyears:"weekYear",ordinal:"ordinal",}[unit.toLowerCase()];if(!normalized)throw new InvalidUnitError(unit);return normalized;}
function normalizeUnitWithLocalWeeks(unit){switch(unit.toLowerCase()){case"localweekday":case"localweekdays":return"localWeekday";case"localweeknumber":case"localweeknumbers":return"localWeekNumber";case"localweekyear":case"localweekyears":return"localWeekYear";default:return normalizeUnit(unit);}}
function quickDT(obj,opts){const zone=normalizeZone(opts.zone,Settings.defaultZone),loc=Locale.fromObject(opts),tsNow=Settings.now();let ts,o;if(!isUndefined(obj.year)){for(const u of orderedUnits){if(isUndefined(obj[u])){obj[u]=defaultUnitValues[u];}}
const invalid=hasInvalidGregorianData(obj)||hasInvalidTimeData(obj);if(invalid){return DateTime.invalid(invalid);}
const offsetProvis=zone.offset(tsNow);[ts,o]=objToTS(obj,offsetProvis,zone);}else{ts=tsNow;}
return new DateTime({ts,zone,loc,o});}
function diffRelative(start,end,opts){const round=isUndefined(opts.round)?true:opts.round,format=(c,unit)=>{c=roundTo(c,round||opts.calendary?0:2,true);const formatter=end.loc.clone(opts).relFormatter(opts);return formatter.format(c,unit);},differ=(unit)=>{if(opts.calendary){if(!end.hasSame(start,unit)){return end.startOf(unit).diff(start.startOf(unit),unit).get(unit);}else return 0;}else{return end.diff(start,unit).get(unit);}};if(opts.unit){return format(differ(opts.unit),opts.unit);}
for(const unit of opts.units){const count=differ(unit);if(Math.abs(count)>=1){return format(count,unit);}}
return format(start>end?-0:0,opts.units[opts.units.length-1]);}
function lastOpts(argList){let opts={},args;if(argList.length>0&&typeof argList[argList.length-1]==="object"){opts=argList[argList.length-1];args=Array.from(argList).slice(0,argList.length-1);}else{args=Array.from(argList);}
return[opts,args];}
class DateTime{constructor(config){const zone=config.zone||Settings.defaultZone;let invalid=config.invalid||(Number.isNaN(config.ts)?new Invalid("invalid input"):null)||(!zone.isValid?unsupportedZone(zone):null);this.ts=isUndefined(config.ts)?Settings.now():config.ts;let c=null,o=null;if(!invalid){const unchanged=config.old&&config.old.ts===this.ts&&config.old.zone.equals(zone);if(unchanged){[c,o]=[config.old.c,config.old.o];}else{const ot=zone.offset(this.ts);c=tsToObj(this.ts,ot);invalid=Number.isNaN(c.year)?new Invalid("invalid input"):null;c=invalid?null:c;o=invalid?null:ot;}}
this._zone=zone;this.loc=config.loc||Locale.create();this.invalid=invalid;this.weekData=null;this.localWeekData=null;this.c=c;this.o=o;this.isLuxonDateTime=true;}
static now(){return new DateTime({});}
static local(){const[opts,args]=lastOpts(arguments),[year,month,day,hour,minute,second,millisecond]=args;return quickDT({year,month,day,hour,minute,second,millisecond},opts);}
static utc(){const[opts,args]=lastOpts(arguments),[year,month,day,hour,minute,second,millisecond]=args;opts.zone=FixedOffsetZone.utcInstance;return quickDT({year,month,day,hour,minute,second,millisecond},opts);}
static fromJSDate(date,options={}){const ts=isDate(date)?date.valueOf():NaN;if(Number.isNaN(ts)){return DateTime.invalid("invalid input");}
const zoneToUse=normalizeZone(options.zone,Settings.defaultZone);if(!zoneToUse.isValid){return DateTime.invalid(unsupportedZone(zoneToUse));}
return new DateTime({ts:ts,zone:zoneToUse,loc:Locale.fromObject(options),});}
static fromMillis(milliseconds,options={}){if(!isNumber(milliseconds)){throw new InvalidArgumentError(`fromMillis requires a numerical input, but received a ${typeof milliseconds} with value ${milliseconds}`);}else if(milliseconds<-MAX_DATE||milliseconds>MAX_DATE){return DateTime.invalid("Timestamp out of range");}else{return new DateTime({ts:milliseconds,zone:normalizeZone(options.zone,Settings.defaultZone),loc:Locale.fromObject(options),});}}
static fromSeconds(seconds,options={}){if(!isNumber(seconds)){throw new InvalidArgumentError("fromSeconds requires a numerical input");}else{return new DateTime({ts:seconds*1000,zone:normalizeZone(options.zone,Settings.defaultZone),loc:Locale.fromObject(options),});}}
static fromObject(obj,opts={}){obj=obj||{};const zoneToUse=normalizeZone(opts.zone,Settings.defaultZone);if(!zoneToUse.isValid){return DateTime.invalid(unsupportedZone(zoneToUse));}
const loc=Locale.fromObject(opts);const normalized=normalizeObject(obj,normalizeUnitWithLocalWeeks);const{minDaysInFirstWeek,startOfWeek}=usesLocalWeekValues(normalized,loc);const tsNow=Settings.now(),offsetProvis=!isUndefined(opts.specificOffset)?opts.specificOffset:zoneToUse.offset(tsNow),containsOrdinal=!isUndefined(normalized.ordinal),containsGregorYear=!isUndefined(normalized.year),containsGregorMD=!isUndefined(normalized.month)||!isUndefined(normalized.day),containsGregor=containsGregorYear||containsGregorMD,definiteWeekDef=normalized.weekYear||normalized.weekNumber;if((containsGregor||containsOrdinal)&&definiteWeekDef){throw new ConflictingSpecificationError("Can't mix weekYear/weekNumber units with year/month/day or ordinals");}
if(containsGregorMD&&containsOrdinal){throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day");}
const useWeekData=definiteWeekDef||(normalized.weekday&&!containsGregor);let units,defaultValues,objNow=tsToObj(tsNow,offsetProvis);if(useWeekData){units=orderedWeekUnits;defaultValues=defaultWeekUnitValues;objNow=gregorianToWeek(objNow,minDaysInFirstWeek,startOfWeek);}else if(containsOrdinal){units=orderedOrdinalUnits;defaultValues=defaultOrdinalUnitValues;objNow=gregorianToOrdinal(objNow);}else{units=orderedUnits;defaultValues=defaultUnitValues;}
let foundFirst=false;for(const u of units){const v=normalized[u];if(!isUndefined(v)){foundFirst=true;}else if(foundFirst){normalized[u]=defaultValues[u];}else{normalized[u]=objNow[u];}}
const higherOrderInvalid=useWeekData?hasInvalidWeekData(normalized,minDaysInFirstWeek,startOfWeek):containsOrdinal?hasInvalidOrdinalData(normalized):hasInvalidGregorianData(normalized),invalid=higherOrderInvalid||hasInvalidTimeData(normalized);if(invalid){return DateTime.invalid(invalid);}
const gregorian=useWeekData?weekToGregorian(normalized,minDaysInFirstWeek,startOfWeek):containsOrdinal?ordinalToGregorian(normalized):normalized,[tsFinal,offsetFinal]=objToTS(gregorian,offsetProvis,zoneToUse),inst=new DateTime({ts:tsFinal,zone:zoneToUse,o:offsetFinal,loc,});if(normalized.weekday&&containsGregor&&obj.weekday!==inst.weekday){return DateTime.invalid("mismatched weekday",`you can't specify both a weekday of ${normalized.weekday} and a date of ${inst.toISO()}`);}
if(!inst.isValid){return DateTime.invalid(inst.invalid);}
return inst;}
static fromISO(text,opts={}){const[vals,parsedZone]=parseISODate(text);return parseDataToDateTime(vals,parsedZone,opts,"ISO 8601",text);}
static fromRFC2822(text,opts={}){const[vals,parsedZone]=parseRFC2822Date(text);return parseDataToDateTime(vals,parsedZone,opts,"RFC 2822",text);}
static fromHTTP(text,opts={}){const[vals,parsedZone]=parseHTTPDate(text);return parseDataToDateTime(vals,parsedZone,opts,"HTTP",opts);}
static fromFormat(text,fmt,opts={}){if(isUndefined(text)||isUndefined(fmt)){throw new InvalidArgumentError("fromFormat requires an input string and a format");}
const{locale=null,numberingSystem=null}=opts,localeToUse=Locale.fromOpts({locale,numberingSystem,defaultToEN:true,}),[vals,parsedZone,specificOffset,invalid]=parseFromTokens(localeToUse,text,fmt);if(invalid){return DateTime.invalid(invalid);}else{return parseDataToDateTime(vals,parsedZone,opts,`format ${fmt}`,text,specificOffset);}}
static fromString(text,fmt,opts={}){return DateTime.fromFormat(text,fmt,opts);}
static fromSQL(text,opts={}){const[vals,parsedZone]=parseSQL(text);return parseDataToDateTime(vals,parsedZone,opts,"SQL",text);}
static invalid(reason,explanation=null){if(!reason){throw new InvalidArgumentError("need to specify a reason the DateTime is invalid");}
const invalid=reason instanceof Invalid?reason:new Invalid(reason,explanation);if(Settings.throwOnInvalid){throw new InvalidDateTimeError(invalid);}else{return new DateTime({invalid});}}
static isDateTime(o){return(o&&o.isLuxonDateTime)||false;}
static parseFormatForOpts(formatOpts,localeOpts={}){const tokenList=formatOptsToTokens(formatOpts,Locale.fromObject(localeOpts));return!tokenList?null:tokenList.map((t)=>(t?t.val:null)).join("");}
static expandFormat(fmt,localeOpts={}){const expanded=expandMacroTokens(Formatter.parseFormat(fmt),Locale.fromObject(localeOpts));return expanded.map((t)=>t.val).join("");}
get(unit){return this[unit];}
get isValid(){return this.invalid===null;}
get invalidReason(){return this.invalid?this.invalid.reason:null;}
get invalidExplanation(){return this.invalid?this.invalid.explanation:null;}
get locale(){return this.isValid?this.loc.locale:null;}
get numberingSystem(){return this.isValid?this.loc.numberingSystem:null;}
get outputCalendar(){return this.isValid?this.loc.outputCalendar:null;}
get zone(){return this._zone;}
get zoneName(){return this.isValid?this.zone.name:null;}
get year(){return this.isValid?this.c.year:NaN;}
get quarter(){return this.isValid?Math.ceil(this.c.month/3):NaN;}
get month(){return this.isValid?this.c.month:NaN;}
get day(){return this.isValid?this.c.day:NaN;}
get hour(){return this.isValid?this.c.hour:NaN;}
get minute(){return this.isValid?this.c.minute:NaN;}
get second(){return this.isValid?this.c.second:NaN;}
get millisecond(){return this.isValid?this.c.millisecond:NaN;}
get weekYear(){return this.isValid?possiblyCachedWeekData(this).weekYear:NaN;}
get weekNumber(){return this.isValid?possiblyCachedWeekData(this).weekNumber:NaN;}
get weekday(){return this.isValid?possiblyCachedWeekData(this).weekday:NaN;}
get isWeekend(){return this.isValid&&this.loc.getWeekendDays().includes(this.weekday);}
get localWeekday(){return this.isValid?possiblyCachedLocalWeekData(this).weekday:NaN;}
get localWeekNumber(){return this.isValid?possiblyCachedLocalWeekData(this).weekNumber:NaN;}
get localWeekYear(){return this.isValid?possiblyCachedLocalWeekData(this).weekYear:NaN;}
get ordinal(){return this.isValid?gregorianToOrdinal(this.c).ordinal:NaN;}
get monthShort(){return this.isValid?Info.months("short",{locObj:this.loc})[this.month-1]:null;}
get monthLong(){return this.isValid?Info.months("long",{locObj:this.loc})[this.month-1]:null;}
get weekdayShort(){return this.isValid?Info.weekdays("short",{locObj:this.loc})[this.weekday-1]:null;}
get weekdayLong(){return this.isValid?Info.weekdays("long",{locObj:this.loc})[this.weekday-1]:null;}
get offset(){return this.isValid?+this.o:NaN;}
get offsetNameShort(){if(this.isValid){return this.zone.offsetName(this.ts,{format:"short",locale:this.locale,});}else{return null;}}
get offsetNameLong(){if(this.isValid){return this.zone.offsetName(this.ts,{format:"long",locale:this.locale,});}else{return null;}}
get isOffsetFixed(){return this.isValid?this.zone.isUniversal:null;}
get isInDST(){if(this.isOffsetFixed){return false;}else{return(this.offset>this.set({month:1,day:1}).offset||this.offset>this.set({month:5}).offset);}}
getPossibleOffsets(){if(!this.isValid||this.isOffsetFixed){return[this];}
const dayMs=86400000;const minuteMs=60000;const localTS=objToLocalTS(this.c);const oEarlier=this.zone.offset(localTS-dayMs);const oLater=this.zone.offset(localTS+dayMs);const o1=this.zone.offset(localTS-oEarlier*minuteMs);const o2=this.zone.offset(localTS-oLater*minuteMs);if(o1===o2){return[this];}
const ts1=localTS-o1*minuteMs;const ts2=localTS-o2*minuteMs;const c1=tsToObj(ts1,o1);const c2=tsToObj(ts2,o2);if(c1.hour===c2.hour&&c1.minute===c2.minute&&c1.second===c2.second&&c1.millisecond===c2.millisecond){return[clone(this,{ts:ts1}),clone(this,{ts:ts2})];}
return[this];}
get isInLeapYear(){return isLeapYear(this.year);}
get daysInMonth(){return daysInMonth(this.year,this.month);}
get daysInYear(){return this.isValid?daysInYear(this.year):NaN;}
get weeksInWeekYear(){return this.isValid?weeksInWeekYear(this.weekYear):NaN;}
get weeksInLocalWeekYear(){return this.isValid?weeksInWeekYear(this.localWeekYear,this.loc.getMinDaysInFirstWeek(),this.loc.getStartOfWeek()):NaN;}
resolvedLocaleOptions(opts={}){const{locale,numberingSystem,calendar}=Formatter.create(this.loc.clone(opts),opts).resolvedOptions(this);return{locale,numberingSystem,outputCalendar:calendar};}
toUTC(offset=0,opts={}){return this.setZone(FixedOffsetZone.instance(offset),opts);}
toLocal(){return this.setZone(Settings.defaultZone);}
setZone(zone,{keepLocalTime=false,keepCalendarTime=false}={}){zone=normalizeZone(zone,Settings.defaultZone);if(zone.equals(this.zone)){return this;}else if(!zone.isValid){return DateTime.invalid(unsupportedZone(zone));}else{let newTS=this.ts;if(keepLocalTime||keepCalendarTime){const offsetGuess=zone.offset(this.ts);const asObj=this.toObject();[newTS]=objToTS(asObj,offsetGuess,zone);}
return clone(this,{ts:newTS,zone});}}
reconfigure({locale,numberingSystem,outputCalendar}={}){const loc=this.loc.clone({locale,numberingSystem,outputCalendar});return clone(this,{loc});}
setLocale(locale){return this.reconfigure({locale});}
set(values){if(!this.isValid)return this;const normalized=normalizeObject(values,normalizeUnitWithLocalWeeks);const{minDaysInFirstWeek,startOfWeek}=usesLocalWeekValues(normalized,this.loc);const settingWeekStuff=!isUndefined(normalized.weekYear)||!isUndefined(normalized.weekNumber)||!isUndefined(normalized.weekday),containsOrdinal=!isUndefined(normalized.ordinal),containsGregorYear=!isUndefined(normalized.year),containsGregorMD=!isUndefined(normalized.month)||!isUndefined(normalized.day),containsGregor=containsGregorYear||containsGregorMD,definiteWeekDef=normalized.weekYear||normalized.weekNumber;if((containsGregor||containsOrdinal)&&definiteWeekDef){throw new ConflictingSpecificationError("Can't mix weekYear/weekNumber units with year/month/day or ordinals");}
if(containsGregorMD&&containsOrdinal){throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day");}
let mixed;if(settingWeekStuff){mixed=weekToGregorian({...gregorianToWeek(this.c,minDaysInFirstWeek,startOfWeek),...normalized},minDaysInFirstWeek,startOfWeek);}else if(!isUndefined(normalized.ordinal)){mixed=ordinalToGregorian({...gregorianToOrdinal(this.c),...normalized});}else{mixed={...this.toObject(),...normalized};if(isUndefined(normalized.day)){mixed.day=Math.min(daysInMonth(mixed.year,mixed.month),mixed.day);}}
const[ts,o]=objToTS(mixed,this.o,this.zone);return clone(this,{ts,o});}
plus(duration){if(!this.isValid)return this;const dur=Duration.fromDurationLike(duration);return clone(this,adjustTime(this,dur));}
minus(duration){if(!this.isValid)return this;const dur=Duration.fromDurationLike(duration).negate();return clone(this,adjustTime(this,dur));}
startOf(unit,{useLocaleWeeks=false}={}){if(!this.isValid)return this;const o={},normalizedUnit=Duration.normalizeUnit(unit);switch(normalizedUnit){case"years":o.month=1;case"quarters":case"months":o.day=1;case"weeks":case"days":o.hour=0;case"hours":o.minute=0;case"minutes":o.second=0;case"seconds":o.millisecond=0;break;}
if(normalizedUnit==="weeks"){if(useLocaleWeeks){const startOfWeek=this.loc.getStartOfWeek();const{weekday}=this;if(weekday<startOfWeek){o.weekNumber=this.weekNumber-1;}
o.weekday=startOfWeek;}else{o.weekday=1;}}
if(normalizedUnit==="quarters"){const q=Math.ceil(this.month/3);o.month=(q-1)*3+1;}
return this.set(o);}
endOf(unit,opts){return this.isValid?this.plus({[unit]:1}).startOf(unit,opts).minus(1):this;}
toFormat(fmt,opts={}){return this.isValid?Formatter.create(this.loc.redefaultToEN(opts)).formatDateTimeFromString(this,fmt):INVALID;}
toLocaleString(formatOpts=DATE_SHORT,opts={}){return this.isValid?Formatter.create(this.loc.clone(opts),formatOpts).formatDateTime(this):INVALID;}
toLocaleParts(opts={}){return this.isValid?Formatter.create(this.loc.clone(opts),opts).formatDateTimeParts(this):[];}
toISO({format="extended",suppressSeconds=false,suppressMilliseconds=false,includeOffset=true,extendedZone=false,}={}){if(!this.isValid){return null;}
const ext=format==="extended";let c=toISODate(this,ext);c+="T";c+=toISOTime(this,ext,suppressSeconds,suppressMilliseconds,includeOffset,extendedZone);return c;}
toISODate({format="extended"}={}){if(!this.isValid){return null;}
return toISODate(this,format==="extended");}
toISOWeekDate(){return toTechFormat(this,"kkkk-'W'WW-c");}
toISOTime({suppressMilliseconds=false,suppressSeconds=false,includeOffset=true,includePrefix=false,extendedZone=false,format="extended",}={}){if(!this.isValid){return null;}
let c=includePrefix?"T":"";return(c+
toISOTime(this,format==="extended",suppressSeconds,suppressMilliseconds,includeOffset,extendedZone));}
toRFC2822(){return toTechFormat(this,"EEE, dd LLL yyyy HH:mm:ss ZZZ",false);}
toHTTP(){return toTechFormat(this.toUTC(),"EEE, dd LLL yyyy HH:mm:ss 'GMT'");}
toSQLDate(){if(!this.isValid){return null;}
return toISODate(this,true);}
toSQLTime({includeOffset=true,includeZone=false,includeOffsetSpace=true}={}){let fmt="HH:mm:ss.SSS";if(includeZone||includeOffset){if(includeOffsetSpace){fmt+=" ";}
if(includeZone){fmt+="z";}else if(includeOffset){fmt+="ZZ";}}
return toTechFormat(this,fmt,true);}
toSQL(opts={}){if(!this.isValid){return null;}
return`${this.toSQLDate()} ${this.toSQLTime(opts)}`;}
toString(){return this.isValid?this.toISO():INVALID;}
[Symbol.for("nodejs.util.inspect.custom")](){if(this.isValid){return`DateTime { ts: ${this.toISO()}, zone: ${this.zone.name}, locale: ${this.locale} }`;}else{return`DateTime { Invalid, reason: ${this.invalidReason} }`;}}
valueOf(){return this.toMillis();}
toMillis(){return this.isValid?this.ts:NaN;}
toSeconds(){return this.isValid?this.ts/1000:NaN;}
toUnixInteger(){return this.isValid?Math.floor(this.ts/1000):NaN;}
toJSON(){return this.toISO();}
toBSON(){return this.toJSDate();}
toObject(opts={}){if(!this.isValid)return{};const base={...this.c};if(opts.includeConfig){base.outputCalendar=this.outputCalendar;base.numberingSystem=this.loc.numberingSystem;base.locale=this.loc.locale;}
return base;}
toJSDate(){return new Date(this.isValid?this.ts:NaN);}
diff(otherDateTime,unit="milliseconds",opts={}){if(!this.isValid||!otherDateTime.isValid){return Duration.invalid("created by diffing an invalid DateTime");}
const durOpts={locale:this.locale,numberingSystem:this.numberingSystem,...opts};const units=maybeArray(unit).map(Duration.normalizeUnit),otherIsLater=otherDateTime.valueOf()>this.valueOf(),earlier=otherIsLater?this:otherDateTime,later=otherIsLater?otherDateTime:this,diffed=diff(earlier,later,units,durOpts);return otherIsLater?diffed.negate():diffed;}
diffNow(unit="milliseconds",opts={}){return this.diff(DateTime.now(),unit,opts);}
until(otherDateTime){return this.isValid?Interval.fromDateTimes(this,otherDateTime):this;}
hasSame(otherDateTime,unit,opts){if(!this.isValid)return false;const inputMs=otherDateTime.valueOf();const adjustedToZone=this.setZone(otherDateTime.zone,{keepLocalTime:true});return(adjustedToZone.startOf(unit,opts)<=inputMs&&inputMs<=adjustedToZone.endOf(unit,opts));}
equals(other){return(this.isValid&&other.isValid&&this.valueOf()===other.valueOf()&&this.zone.equals(other.zone)&&this.loc.equals(other.loc));}
toRelative(options={}){if(!this.isValid)return null;const base=options.base||DateTime.fromObject({},{zone:this.zone}),padding=options.padding?(this<base?-options.padding:options.padding):0;let units=["years","months","days","hours","minutes","seconds"];let unit=options.unit;if(Array.isArray(options.unit)){units=options.unit;unit=undefined;}
return diffRelative(base,this.plus(padding),{...options,numeric:"always",units,unit,});}
toRelativeCalendar(options={}){if(!this.isValid)return null;return diffRelative(options.base||DateTime.fromObject({},{zone:this.zone}),this,{...options,numeric:"auto",units:["years","months","days"],calendary:true,});}
static min(...dateTimes){if(!dateTimes.every(DateTime.isDateTime)){throw new InvalidArgumentError("min requires all arguments be DateTimes");}
return bestBy(dateTimes,(i)=>i.valueOf(),Math.min);}
static max(...dateTimes){if(!dateTimes.every(DateTime.isDateTime)){throw new InvalidArgumentError("max requires all arguments be DateTimes");}
return bestBy(dateTimes,(i)=>i.valueOf(),Math.max);}
static fromFormatExplain(text,fmt,options={}){const{locale=null,numberingSystem=null}=options,localeToUse=Locale.fromOpts({locale,numberingSystem,defaultToEN:true,});return explainFromTokens(localeToUse,text,fmt);}
static fromStringExplain(text,fmt,options={}){return DateTime.fromFormatExplain(text,fmt,options);}
static get DATE_SHORT(){return DATE_SHORT;}
static get DATE_MED(){return DATE_MED;}
static get DATE_MED_WITH_WEEKDAY(){return DATE_MED_WITH_WEEKDAY;}
static get DATE_FULL(){return DATE_FULL;}
static get DATE_HUGE(){return DATE_HUGE;}
static get TIME_SIMPLE(){return TIME_SIMPLE;}
static get TIME_WITH_SECONDS(){return TIME_WITH_SECONDS;}
static get TIME_WITH_SHORT_OFFSET(){return TIME_WITH_SHORT_OFFSET;}
static get TIME_WITH_LONG_OFFSET(){return TIME_WITH_LONG_OFFSET;}
static get TIME_24_SIMPLE(){return TIME_24_SIMPLE;}
static get TIME_24_WITH_SECONDS(){return TIME_24_WITH_SECONDS;}
static get TIME_24_WITH_SHORT_OFFSET(){return TIME_24_WITH_SHORT_OFFSET;}
static get TIME_24_WITH_LONG_OFFSET(){return TIME_24_WITH_LONG_OFFSET;}
static get DATETIME_SHORT(){return DATETIME_SHORT;}
static get DATETIME_SHORT_WITH_SECONDS(){return DATETIME_SHORT_WITH_SECONDS;}
static get DATETIME_MED(){return DATETIME_MED;}
static get DATETIME_MED_WITH_SECONDS(){return DATETIME_MED_WITH_SECONDS;}
static get DATETIME_MED_WITH_WEEKDAY(){return DATETIME_MED_WITH_WEEKDAY;}
static get DATETIME_FULL(){return DATETIME_FULL;}
static get DATETIME_FULL_WITH_SECONDS(){return DATETIME_FULL_WITH_SECONDS;}
static get DATETIME_HUGE(){return DATETIME_HUGE;}
static get DATETIME_HUGE_WITH_SECONDS(){return DATETIME_HUGE_WITH_SECONDS;}}
function friendlyDateTime(dateTimeish){if(DateTime.isDateTime(dateTimeish)){return dateTimeish;}else if(dateTimeish&&dateTimeish.valueOf&&isNumber(dateTimeish.valueOf())){return DateTime.fromJSDate(dateTimeish);}else if(dateTimeish&&typeof dateTimeish==="object"){return DateTime.fromObject(dateTimeish);}else{throw new InvalidArgumentError(`Unknown datetime argument: ${dateTimeish}, of type ${typeof dateTimeish}`);}}
const VERSION="3.4.4";exports.DateTime=DateTime;exports.Duration=Duration;exports.FixedOffsetZone=FixedOffsetZone;exports.IANAZone=IANAZone;exports.Info=Info;exports.Interval=Interval;exports.InvalidZone=InvalidZone;exports.Settings=Settings;exports.SystemZone=SystemZone;exports.VERSION=VERSION;exports.Zone=Zone;Object.defineProperty(exports,'__esModule',{value:true});return exports;})({});luxon.DateTime.prototype[Symbol.toStringTag]="LuxonDateTime";luxon.Duration.prototype[Symbol.toStringTag]="LuxonDuration";luxon.Interval.prototype[Symbol.toStringTag]="LuxonInterval";luxon.Settings.prototype[Symbol.toStringTag]="LuxonSettings";luxon.Info.prototype[Symbol.toStringTag]="LuxonInfo";luxon.Zone.prototype[Symbol.toStringTag]="LuxonZone";;

/* /web/static/lib/owl/owl.js */
(function(exports){'use strict';function filterOutModifiersFromData(dataList){dataList=dataList.slice();const modifiers=[];let elm;while((elm=dataList[0])&&typeof elm==="string"){modifiers.push(dataList.shift());}
return{modifiers,data:dataList};}
const config={shouldNormalizeDom:true,mainEventHandler:(data,ev,currentTarget)=>{if(typeof data==="function"){data(ev);}
else if(Array.isArray(data)){data=filterOutModifiersFromData(data).data;data[0](data[1],ev);}
return false;},};class VToggler{constructor(key,child){this.key=key;this.child=child;}
mount(parent,afterNode){this.parentEl=parent;this.child.mount(parent,afterNode);}
moveBeforeDOMNode(node,parent){this.child.moveBeforeDOMNode(node,parent);}
moveBeforeVNode(other,afterNode){this.moveBeforeDOMNode((other&&other.firstNode())||afterNode);}
patch(other,withBeforeRemove){if(this===other){return;}
let child1=this.child;let child2=other.child;if(this.key===other.key){child1.patch(child2,withBeforeRemove);}
else{child2.mount(this.parentEl,child1.firstNode());if(withBeforeRemove){child1.beforeRemove();}
child1.remove();this.child=child2;this.key=other.key;}}
beforeRemove(){this.child.beforeRemove();}
remove(){this.child.remove();}
firstNode(){return this.child.firstNode();}
toString(){return this.child.toString();}}
function toggler(key,child){return new VToggler(key,child);}
class OwlError extends Error{}
const{setAttribute:elemSetAttribute,removeAttribute}=Element.prototype;const tokenList=DOMTokenList.prototype;const tokenListAdd=tokenList.add;const tokenListRemove=tokenList.remove;const isArray=Array.isArray;const{split,trim}=String.prototype;const wordRegexp=/\s+/;function setAttribute(key,value){switch(value){case false:case undefined:removeAttribute.call(this,key);break;case true:elemSetAttribute.call(this,key,"");break;default:elemSetAttribute.call(this,key,value);}}
function createAttrUpdater(attr){return function(value){setAttribute.call(this,attr,value);};}
function attrsSetter(attrs){if(isArray(attrs)){if(attrs[0]==="class"){setClass.call(this,attrs[1]);}
else{setAttribute.call(this,attrs[0],attrs[1]);}}
else{for(let k in attrs){if(k==="class"){setClass.call(this,attrs[k]);}
else{setAttribute.call(this,k,attrs[k]);}}}}
function attrsUpdater(attrs,oldAttrs){if(isArray(attrs)){const name=attrs[0];const val=attrs[1];if(name===oldAttrs[0]){if(val===oldAttrs[1]){return;}
if(name==="class"){updateClass.call(this,val,oldAttrs[1]);}
else{setAttribute.call(this,name,val);}}
else{removeAttribute.call(this,oldAttrs[0]);setAttribute.call(this,name,val);}}
else{for(let k in oldAttrs){if(!(k in attrs)){if(k==="class"){updateClass.call(this,"",oldAttrs[k]);}
else{removeAttribute.call(this,k);}}}
for(let k in attrs){const val=attrs[k];if(val!==oldAttrs[k]){if(k==="class"){updateClass.call(this,val,oldAttrs[k]);}
else{setAttribute.call(this,k,val);}}}}}
function toClassObj(expr){const result={};switch(typeof expr){case"string":const str=trim.call(expr);if(!str){return{};}
let words=split.call(str,wordRegexp);for(let i=0,l=words.length;i<l;i++){result[words[i]]=true;}
return result;case"object":for(let key in expr){const value=expr[key];if(value){key=trim.call(key);if(!key){continue;}
const words=split.call(key,wordRegexp);for(let word of words){result[word]=value;}}}
return result;case"undefined":return{};case"number":return{[expr]:true};default:return{[expr]:true};}}
function setClass(val){val=val===""?{}:toClassObj(val);const cl=this.classList;for(let c in val){tokenListAdd.call(cl,c);}}
function updateClass(val,oldVal){oldVal=oldVal===""?{}:toClassObj(oldVal);val=val===""?{}:toClassObj(val);const cl=this.classList;for(let c in oldVal){if(!(c in val)){tokenListRemove.call(cl,c);}}
for(let c in val){if(!(c in oldVal)){tokenListAdd.call(cl,c);}}}
function batched(callback){let scheduled=false;return async(...args)=>{if(!scheduled){scheduled=true;await Promise.resolve();scheduled=false;callback(...args);}};}
function inOwnerDocument(el){if(!el){return false;}
if(el.ownerDocument.contains(el)){return true;}
const rootNode=el.getRootNode();return rootNode instanceof ShadowRoot&&el.ownerDocument.contains(rootNode.host);}
function isAttachedToDocument(element,documentElement){let current=element;const shadowRoot=documentElement.defaultView.ShadowRoot;while(current){if(current===documentElement){return true;}
if(current.parentNode){current=current.parentNode;}
else if(current instanceof shadowRoot&&current.host){current=current.host;}
else{return false;}}
return false;}
function validateTarget(target){const document=target&&target.ownerDocument;if(document){if(!document.defaultView){throw new OwlError("Cannot mount a component: the target document is not attached to a window (defaultView is missing)");}
const HTMLElement=document.defaultView.HTMLElement;if(target instanceof HTMLElement||target instanceof ShadowRoot){if(!isAttachedToDocument(target,document)){throw new OwlError("Cannot mount a component on a detached dom node");}
return;}}
throw new OwlError("Cannot mount component: the target is not a valid DOM element");}
class EventBus extends EventTarget{trigger(name,payload){this.dispatchEvent(new CustomEvent(name,{detail:payload}));}}
function whenReady(fn){return new Promise(function(resolve){if(document.readyState!=="loading"){resolve(true);}
else{document.addEventListener("DOMContentLoaded",resolve,false);}}).then(fn||function(){});}
async function loadFile(url){const result=await fetch(url);if(!result.ok){throw new OwlError("Error while fetching xml templates");}
return await result.text();}
class Markup extends String{}
function htmlEscape(str){if(str instanceof Markup){return str;}
if(str===undefined){return markup("");}
if(typeof str==="number"){return markup(String(str));}
[["&","&amp;"],["<","&lt;"],[">","&gt;"],["'","&#x27;"],['"',"&quot;"],["`","&#x60;"],].forEach((pairs)=>{str=String(str).replace(new RegExp(pairs[0],"g"),pairs[1]);});return markup(str);}
function markup(valueOrStrings,...placeholders){if(!Array.isArray(valueOrStrings)){return new Markup(valueOrStrings);}
const strings=valueOrStrings;let acc="";let i=0;for(;i<placeholders.length;++i){acc+=strings[i]+htmlEscape(placeholders[i]);}
acc+=strings[i];return new Markup(acc);}
function createEventHandler(rawEvent){const eventName=rawEvent.split(".")[0];const capture=rawEvent.includes(".capture");if(rawEvent.includes(".synthetic")){return createSyntheticHandler(eventName,capture);}
else{return createElementHandler(eventName,capture);}}
let nextNativeEventId=1;function createElementHandler(evName,capture=false){let eventKey=`__event__${evName}_${nextNativeEventId++}`;if(capture){eventKey=`${eventKey}_capture`;}
function listener(ev){const currentTarget=ev.currentTarget;if(!currentTarget||!inOwnerDocument(currentTarget))
return;const data=currentTarget[eventKey];if(!data)
return;config.mainEventHandler(data,ev,currentTarget);}
function setup(data){this[eventKey]=data;this.addEventListener(evName,listener,{capture});}
function remove(){delete this[eventKey];this.removeEventListener(evName,listener,{capture});}
function update(data){this[eventKey]=data;}
return{setup,update,remove};}
let nextSyntheticEventId=1;function createSyntheticHandler(evName,capture=false){let eventKey=`__event__synthetic_${evName}`;if(capture){eventKey=`${eventKey}_capture`;}
setupSyntheticEvent(evName,eventKey,capture);const currentId=nextSyntheticEventId++;function setup(data){const _data=this[eventKey]||{};_data[currentId]=data;this[eventKey]=_data;}
function remove(){delete this[eventKey];}
return{setup,update:setup,remove};}
function nativeToSyntheticEvent(eventKey,event){let dom=event.target;while(dom!==null){const _data=dom[eventKey];if(_data){for(const data of Object.values(_data)){const stopped=config.mainEventHandler(data,event,dom);if(stopped)
return;}}
dom=dom.parentNode;}}
const CONFIGURED_SYNTHETIC_EVENTS={};function setupSyntheticEvent(evName,eventKey,capture=false){if(CONFIGURED_SYNTHETIC_EVENTS[eventKey]){return;}
document.addEventListener(evName,(event)=>nativeToSyntheticEvent(eventKey,event),{capture,});CONFIGURED_SYNTHETIC_EVENTS[eventKey]=true;}
const getDescriptor$3=(o,p)=>Object.getOwnPropertyDescriptor(o,p);const nodeProto$4=Node.prototype;const nodeInsertBefore$3=nodeProto$4.insertBefore;const nodeSetTextContent$1=getDescriptor$3(nodeProto$4,"textContent").set;const nodeRemoveChild$3=nodeProto$4.removeChild;class VMulti{constructor(children){this.children=children;}
mount(parent,afterNode){const children=this.children;const l=children.length;const anchors=new Array(l);for(let i=0;i<l;i++){let child=children[i];if(child){child.mount(parent,afterNode);}
else{const childAnchor=document.createTextNode("");anchors[i]=childAnchor;nodeInsertBefore$3.call(parent,childAnchor,afterNode);}}
this.anchors=anchors;this.parentEl=parent;}
moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;const children=this.children;const anchors=this.anchors;for(let i=0,l=children.length;i<l;i++){let child=children[i];if(child){child.moveBeforeDOMNode(node,parent);}
else{const anchor=anchors[i];nodeInsertBefore$3.call(parent,anchor,node);}}}
moveBeforeVNode(other,afterNode){if(other){const next=other.children[0];afterNode=(next?next.firstNode():other.anchors[0])||null;}
const children=this.children;const parent=this.parentEl;const anchors=this.anchors;for(let i=0,l=children.length;i<l;i++){let child=children[i];if(child){child.moveBeforeVNode(null,afterNode);}
else{const anchor=anchors[i];nodeInsertBefore$3.call(parent,anchor,afterNode);}}}
patch(other,withBeforeRemove){if(this===other){return;}
const children1=this.children;const children2=other.children;const anchors=this.anchors;const parentEl=this.parentEl;for(let i=0,l=children1.length;i<l;i++){const vn1=children1[i];const vn2=children2[i];if(vn1){if(vn2){vn1.patch(vn2,withBeforeRemove);}
else{const afterNode=vn1.firstNode();const anchor=document.createTextNode("");anchors[i]=anchor;nodeInsertBefore$3.call(parentEl,anchor,afterNode);if(withBeforeRemove){vn1.beforeRemove();}
vn1.remove();children1[i]=undefined;}}
else if(vn2){children1[i]=vn2;const anchor=anchors[i];vn2.mount(parentEl,anchor);nodeRemoveChild$3.call(parentEl,anchor);}}}
beforeRemove(){const children=this.children;for(let i=0,l=children.length;i<l;i++){const child=children[i];if(child){child.beforeRemove();}}}
remove(){const parentEl=this.parentEl;if(this.isOnlyChild){nodeSetTextContent$1.call(parentEl,"");}
else{const children=this.children;const anchors=this.anchors;for(let i=0,l=children.length;i<l;i++){const child=children[i];if(child){child.remove();}
else{nodeRemoveChild$3.call(parentEl,anchors[i]);}}}}
firstNode(){const child=this.children[0];return child?child.firstNode():this.anchors[0];}
toString(){return this.children.map((c)=>(c?c.toString():"")).join("");}}
function multi(children){return new VMulti(children);}
const getDescriptor$2=(o,p)=>Object.getOwnPropertyDescriptor(o,p);const nodeProto$3=Node.prototype;const characterDataProto$1=CharacterData.prototype;const nodeInsertBefore$2=nodeProto$3.insertBefore;const characterDataSetData$1=getDescriptor$2(characterDataProto$1,"data").set;const nodeRemoveChild$2=nodeProto$3.removeChild;class VSimpleNode{constructor(text){this.text=text;}
mountNode(node,parent,afterNode){this.parentEl=parent;nodeInsertBefore$2.call(parent,node,afterNode);this.el=node;}
moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;nodeInsertBefore$2.call(parent,this.el,node);}
moveBeforeVNode(other,afterNode){nodeInsertBefore$2.call(this.parentEl,this.el,other?other.el:afterNode);}
beforeRemove(){}
remove(){nodeRemoveChild$2.call(this.parentEl,this.el);}
firstNode(){return this.el;}
toString(){return this.text;}}
class VText$1 extends VSimpleNode{mount(parent,afterNode){this.mountNode(document.createTextNode(toText(this.text)),parent,afterNode);}
patch(other){const text2=other.text;if(this.text!==text2){characterDataSetData$1.call(this.el,toText(text2));this.text=text2;}}}
class VComment extends VSimpleNode{mount(parent,afterNode){this.mountNode(document.createComment(toText(this.text)),parent,afterNode);}
patch(){}}
function text(str){return new VText$1(str);}
function comment(str){return new VComment(str);}
function toText(value){switch(typeof value){case"string":return value;case"number":return String(value);case"boolean":return value?"true":"false";default:return value||"";}}
const getDescriptor$1=(o,p)=>Object.getOwnPropertyDescriptor(o,p);const nodeProto$2=Node.prototype;const elementProto=Element.prototype;const characterDataProto=CharacterData.prototype;const characterDataSetData=getDescriptor$1(characterDataProto,"data").set;const nodeGetFirstChild=getDescriptor$1(nodeProto$2,"firstChild").get;const nodeGetNextSibling=getDescriptor$1(nodeProto$2,"nextSibling").get;const NO_OP=()=>{};function makePropSetter(name){return function setProp(value){this[name]=value===0?0:value?value.valueOf():"";};}
const cache$1={};function createBlock(str){if(str in cache$1){return cache$1[str];}
const doc=new DOMParser().parseFromString(`<t>${str}</t>`,"text/xml");const node=doc.firstChild.firstChild;if(config.shouldNormalizeDom){normalizeNode(node);}
const tree=buildTree(node);const context=buildContext(tree);const template=tree.el;const Block=buildBlock(template,context);cache$1[str]=Block;return Block;}
function normalizeNode(node){if(node.nodeType===Node.TEXT_NODE){if(!/\S/.test(node.textContent)){node.remove();return;}}
if(node.nodeType===Node.ELEMENT_NODE){if(node.tagName==="pre"){return;}}
for(let i=node.childNodes.length-1;i>=0;--i){normalizeNode(node.childNodes.item(i));}}
function buildTree(node,parent=null,domParentTree=null){switch(node.nodeType){case Node.ELEMENT_NODE:{let currentNS=domParentTree&&domParentTree.currentNS;const tagName=node.tagName;let el=undefined;const info=[];if(tagName.startsWith("block-text-")){const index=parseInt(tagName.slice(11),10);info.push({type:"text",idx:index});el=document.createTextNode("");}
if(tagName.startsWith("block-child-")){if(!domParentTree.isRef){addRef(domParentTree);}
const index=parseInt(tagName.slice(12),10);info.push({type:"child",idx:index});el=document.createTextNode("");}
currentNS||(currentNS=node.namespaceURI);if(!el){el=currentNS?document.createElementNS(currentNS,tagName):document.createElement(tagName);}
if(el instanceof Element){if(!domParentTree){const fragment=document.createElement("template").content;fragment.appendChild(el);}
const attrs=node.attributes;for(let i=0;i<attrs.length;i++){const attrName=attrs[i].name;const attrValue=attrs[i].value;if(attrName.startsWith("block-handler-")){const idx=parseInt(attrName.slice(14),10);info.push({type:"handler",idx,event:attrValue,});}
else if(attrName.startsWith("block-attribute-")){const idx=parseInt(attrName.slice(16),10);info.push({type:"attribute",idx,name:attrValue,tag:tagName,});}
else if(attrName.startsWith("block-property-")){const idx=parseInt(attrName.slice(15),10);info.push({type:"property",idx,name:attrValue,tag:tagName,});}
else if(attrName==="block-attributes"){info.push({type:"attributes",idx:parseInt(attrValue,10),});}
else if(attrName==="block-ref"){info.push({type:"ref",idx:parseInt(attrValue,10),});}
else{el.setAttribute(attrs[i].name,attrValue);}}}
const tree={parent,firstChild:null,nextSibling:null,el,info,refN:0,currentNS,};if(node.firstChild){const childNode=node.childNodes[0];if(node.childNodes.length===1&&childNode.nodeType===Node.ELEMENT_NODE&&childNode.tagName.startsWith("block-child-")){const tagName=childNode.tagName;const index=parseInt(tagName.slice(12),10);info.push({idx:index,type:"child",isOnlyChild:true});}
else{tree.firstChild=buildTree(node.firstChild,tree,tree);el.appendChild(tree.firstChild.el);let curNode=node.firstChild;let curTree=tree.firstChild;while((curNode=curNode.nextSibling)){curTree.nextSibling=buildTree(curNode,curTree,tree);el.appendChild(curTree.nextSibling.el);curTree=curTree.nextSibling;}}}
if(tree.info.length){addRef(tree);}
return tree;}
case Node.TEXT_NODE:case Node.COMMENT_NODE:{const el=node.nodeType===Node.TEXT_NODE?document.createTextNode(node.textContent):document.createComment(node.textContent);return{parent:parent,firstChild:null,nextSibling:null,el,info:[],refN:0,currentNS:null,};}}
throw new OwlError("boom");}
function addRef(tree){tree.isRef=true;do{tree.refN++;}while((tree=tree.parent));}
function parentTree(tree){let parent=tree.parent;while(parent&&parent.nextSibling===tree){tree=parent;parent=parent.parent;}
return parent;}
function buildContext(tree,ctx,fromIdx){if(!ctx){const children=new Array(tree.info.filter((v)=>v.type==="child").length);ctx={collectors:[],locations:[],children,cbRefs:[],refN:tree.refN,refList:[]};fromIdx=0;}
if(tree.refN){const initialIdx=fromIdx;const isRef=tree.isRef;const firstChild=tree.firstChild?tree.firstChild.refN:0;const nextSibling=tree.nextSibling?tree.nextSibling.refN:0;if(isRef){for(let info of tree.info){info.refIdx=initialIdx;}
tree.refIdx=initialIdx;updateCtx(ctx,tree);fromIdx++;}
if(nextSibling){const idx=fromIdx+firstChild;ctx.collectors.push({idx,prevIdx:initialIdx,getVal:nodeGetNextSibling});buildContext(tree.nextSibling,ctx,idx);}
if(firstChild){ctx.collectors.push({idx:fromIdx,prevIdx:initialIdx,getVal:nodeGetFirstChild});buildContext(tree.firstChild,ctx,fromIdx);}}
return ctx;}
function updateCtx(ctx,tree){for(let info of tree.info){switch(info.type){case"text":ctx.locations.push({idx:info.idx,refIdx:info.refIdx,setData:setText,updateData:setText,});break;case"child":if(info.isOnlyChild){ctx.children[info.idx]={parentRefIdx:info.refIdx,isOnlyChild:true,};}
else{ctx.children[info.idx]={parentRefIdx:parentTree(tree).refIdx,afterRefIdx:info.refIdx,};}
break;case"property":{const refIdx=info.refIdx;const setProp=makePropSetter(info.name);ctx.locations.push({idx:info.idx,refIdx,setData:setProp,updateData:setProp,});break;}
case"attribute":{const refIdx=info.refIdx;let updater;let setter;if(info.name==="class"){setter=setClass;updater=updateClass;}
else{setter=createAttrUpdater(info.name);updater=setter;}
ctx.locations.push({idx:info.idx,refIdx,setData:setter,updateData:updater,});break;}
case"attributes":ctx.locations.push({idx:info.idx,refIdx:info.refIdx,setData:attrsSetter,updateData:attrsUpdater,});break;case"handler":{const{setup,update}=createEventHandler(info.event);ctx.locations.push({idx:info.idx,refIdx:info.refIdx,setData:setup,updateData:update,});break;}
case"ref":const index=ctx.cbRefs.push(info.idx)-1;ctx.locations.push({idx:info.idx,refIdx:info.refIdx,setData:makeRefSetter(index,ctx.refList),updateData:NO_OP,});}}}
function buildBlock(template,ctx){let B=createBlockClass(template,ctx);if(ctx.cbRefs.length){const cbRefs=ctx.cbRefs;const refList=ctx.refList;let cbRefsNumber=cbRefs.length;B=class extends B{mount(parent,afterNode){refList.push(new Array(cbRefsNumber));super.mount(parent,afterNode);for(let cbRef of refList.pop()){cbRef();}}
remove(){super.remove();for(let cbRef of cbRefs){let fn=this.data[cbRef];fn(null);}}};}
if(ctx.children.length){B=class extends B{constructor(data,children){super(data);this.children=children;}};B.prototype.beforeRemove=VMulti.prototype.beforeRemove;return(data,children=[])=>new B(data,children);}
return(data)=>new B(data);}
function createBlockClass(template,ctx){const{refN,collectors,children}=ctx;const colN=collectors.length;ctx.locations.sort((a,b)=>a.idx-b.idx);const locations=ctx.locations.map((loc)=>({refIdx:loc.refIdx,setData:loc.setData,updateData:loc.updateData,}));const locN=locations.length;const childN=children.length;const childrenLocs=children;const isDynamic=refN>0;const nodeCloneNode=nodeProto$2.cloneNode;const nodeInsertBefore=nodeProto$2.insertBefore;const elementRemove=elementProto.remove;class Block{constructor(data){this.data=data;}
beforeRemove(){}
remove(){elementRemove.call(this.el);}
firstNode(){return this.el;}
moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;nodeInsertBefore.call(parent,this.el,node);}
moveBeforeVNode(other,afterNode){nodeInsertBefore.call(this.parentEl,this.el,other?other.el:afterNode);}
toString(){const div=document.createElement("div");this.mount(div,null);return div.innerHTML;}
mount(parent,afterNode){const el=nodeCloneNode.call(template,true);nodeInsertBefore.call(parent,el,afterNode);this.el=el;this.parentEl=parent;}
patch(other,withBeforeRemove){}}
if(isDynamic){Block.prototype.mount=function mount(parent,afterNode){const el=nodeCloneNode.call(template,true);const refs=new Array(refN);this.refs=refs;refs[0]=el;for(let i=0;i<colN;i++){const w=collectors[i];refs[w.idx]=w.getVal.call(refs[w.prevIdx]);}
if(locN){const data=this.data;for(let i=0;i<locN;i++){const loc=locations[i];loc.setData.call(refs[loc.refIdx],data[i]);}}
nodeInsertBefore.call(parent,el,afterNode);if(childN){const children=this.children;for(let i=0;i<childN;i++){const child=children[i];if(child){const loc=childrenLocs[i];const afterNode=loc.afterRefIdx?refs[loc.afterRefIdx]:null;child.isOnlyChild=loc.isOnlyChild;child.mount(refs[loc.parentRefIdx],afterNode);}}}
this.el=el;this.parentEl=parent;};Block.prototype.patch=function patch(other,withBeforeRemove){if(this===other){return;}
const refs=this.refs;if(locN){const data1=this.data;const data2=other.data;for(let i=0;i<locN;i++){const val1=data1[i];const val2=data2[i];if(val1!==val2){const loc=locations[i];loc.updateData.call(refs[loc.refIdx],val2,val1);}}
this.data=data2;}
if(childN){let children1=this.children;const children2=other.children;for(let i=0;i<childN;i++){const child1=children1[i];const child2=children2[i];if(child1){if(child2){child1.patch(child2,withBeforeRemove);}
else{if(withBeforeRemove){child1.beforeRemove();}
child1.remove();children1[i]=undefined;}}
else if(child2){const loc=childrenLocs[i];const afterNode=loc.afterRefIdx?refs[loc.afterRefIdx]:null;child2.mount(refs[loc.parentRefIdx],afterNode);children1[i]=child2;}}}};}
return Block;}
function setText(value){characterDataSetData.call(this,toText(value));}
function makeRefSetter(index,refs){return function setRef(fn){refs[refs.length-1][index]=()=>fn(this);};}
const getDescriptor=(o,p)=>Object.getOwnPropertyDescriptor(o,p);const nodeProto$1=Node.prototype;const nodeInsertBefore$1=nodeProto$1.insertBefore;const nodeAppendChild=nodeProto$1.appendChild;const nodeRemoveChild$1=nodeProto$1.removeChild;const nodeSetTextContent=getDescriptor(nodeProto$1,"textContent").set;class VList{constructor(children){this.children=children;}
mount(parent,afterNode){const children=this.children;const _anchor=document.createTextNode("");this.anchor=_anchor;nodeInsertBefore$1.call(parent,_anchor,afterNode);const l=children.length;if(l){const mount=children[0].mount;for(let i=0;i<l;i++){mount.call(children[i],parent,_anchor);}}
this.parentEl=parent;}
moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;const children=this.children;for(let i=0,l=children.length;i<l;i++){children[i].moveBeforeDOMNode(node,parent);}
parent.insertBefore(this.anchor,node);}
moveBeforeVNode(other,afterNode){if(other){const next=other.children[0];afterNode=(next?next.firstNode():other.anchor)||null;}
const children=this.children;for(let i=0,l=children.length;i<l;i++){children[i].moveBeforeVNode(null,afterNode);}
this.parentEl.insertBefore(this.anchor,afterNode);}
patch(other,withBeforeRemove){if(this===other){return;}
const ch1=this.children;const ch2=other.children;if(ch2.length===0&&ch1.length===0){return;}
this.children=ch2;const proto=ch2[0]||ch1[0];const{mount:cMount,patch:cPatch,remove:cRemove,beforeRemove,moveBeforeVNode:cMoveBefore,firstNode:cFirstNode,}=proto;const _anchor=this.anchor;const isOnlyChild=this.isOnlyChild;const parent=this.parentEl;if(ch2.length===0&&isOnlyChild){if(withBeforeRemove){for(let i=0,l=ch1.length;i<l;i++){beforeRemove.call(ch1[i]);}}
nodeSetTextContent.call(parent,"");nodeAppendChild.call(parent,_anchor);return;}
let startIdx1=0;let startIdx2=0;let startVn1=ch1[0];let startVn2=ch2[0];let endIdx1=ch1.length-1;let endIdx2=ch2.length-1;let endVn1=ch1[endIdx1];let endVn2=ch2[endIdx2];let mapping=undefined;while(startIdx1<=endIdx1&&startIdx2<=endIdx2){if(startVn1===null){startVn1=ch1[++startIdx1];continue;}
if(endVn1===null){endVn1=ch1[--endIdx1];continue;}
let startKey1=startVn1.key;let startKey2=startVn2.key;if(startKey1===startKey2){cPatch.call(startVn1,startVn2,withBeforeRemove);ch2[startIdx2]=startVn1;startVn1=ch1[++startIdx1];startVn2=ch2[++startIdx2];continue;}
let endKey1=endVn1.key;let endKey2=endVn2.key;if(endKey1===endKey2){cPatch.call(endVn1,endVn2,withBeforeRemove);ch2[endIdx2]=endVn1;endVn1=ch1[--endIdx1];endVn2=ch2[--endIdx2];continue;}
if(startKey1===endKey2){cPatch.call(startVn1,endVn2,withBeforeRemove);ch2[endIdx2]=startVn1;const nextChild=ch2[endIdx2+1];cMoveBefore.call(startVn1,nextChild,_anchor);startVn1=ch1[++startIdx1];endVn2=ch2[--endIdx2];continue;}
if(endKey1===startKey2){cPatch.call(endVn1,startVn2,withBeforeRemove);ch2[startIdx2]=endVn1;const nextChild=ch1[startIdx1];cMoveBefore.call(endVn1,nextChild,_anchor);endVn1=ch1[--endIdx1];startVn2=ch2[++startIdx2];continue;}
mapping=mapping||createMapping(ch1,startIdx1,endIdx1);let idxInOld=mapping[startKey2];if(idxInOld===undefined){cMount.call(startVn2,parent,cFirstNode.call(startVn1)||null);}
else{const elmToMove=ch1[idxInOld];cMoveBefore.call(elmToMove,startVn1,null);cPatch.call(elmToMove,startVn2,withBeforeRemove);ch2[startIdx2]=elmToMove;ch1[idxInOld]=null;}
startVn2=ch2[++startIdx2];}
if(startIdx1<=endIdx1||startIdx2<=endIdx2){if(startIdx1>endIdx1){const nextChild=ch2[endIdx2+1];const anchor=nextChild?cFirstNode.call(nextChild)||null:_anchor;for(let i=startIdx2;i<=endIdx2;i++){cMount.call(ch2[i],parent,anchor);}}
else{for(let i=startIdx1;i<=endIdx1;i++){let ch=ch1[i];if(ch){if(withBeforeRemove){beforeRemove.call(ch);}
cRemove.call(ch);}}}}}
beforeRemove(){const children=this.children;const l=children.length;if(l){const beforeRemove=children[0].beforeRemove;for(let i=0;i<l;i++){beforeRemove.call(children[i]);}}}
remove(){const{parentEl,anchor}=this;if(this.isOnlyChild){nodeSetTextContent.call(parentEl,"");}
else{const children=this.children;const l=children.length;if(l){const remove=children[0].remove;for(let i=0;i<l;i++){remove.call(children[i]);}}
nodeRemoveChild$1.call(parentEl,anchor);}}
firstNode(){const child=this.children[0];return child?child.firstNode():undefined;}
toString(){return this.children.map((c)=>c.toString()).join("");}}
function list(children){return new VList(children);}
function createMapping(ch1,startIdx1,endIdx2){let mapping={};for(let i=startIdx1;i<=endIdx2;i++){mapping[ch1[i].key]=i;}
return mapping;}
const nodeProto=Node.prototype;const nodeInsertBefore=nodeProto.insertBefore;const nodeRemoveChild=nodeProto.removeChild;class VHtml{constructor(html){this.content=[];this.html=html;}
mount(parent,afterNode){this.parentEl=parent;const template=document.createElement("template");template.innerHTML=this.html;this.content=[...template.content.childNodes];for(let elem of this.content){nodeInsertBefore.call(parent,elem,afterNode);}
if(!this.content.length){const textNode=document.createTextNode("");this.content.push(textNode);nodeInsertBefore.call(parent,textNode,afterNode);}}
moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;for(let elem of this.content){nodeInsertBefore.call(parent,elem,node);}}
moveBeforeVNode(other,afterNode){const target=other?other.content[0]:afterNode;this.moveBeforeDOMNode(target);}
patch(other){if(this===other){return;}
const html2=other.html;if(this.html!==html2){const parent=this.parentEl;const afterNode=this.content[0];const template=document.createElement("template");template.innerHTML=html2;const content=[...template.content.childNodes];for(let elem of content){nodeInsertBefore.call(parent,elem,afterNode);}
if(!content.length){const textNode=document.createTextNode("");content.push(textNode);nodeInsertBefore.call(parent,textNode,afterNode);}
this.remove();this.content=content;this.html=other.html;}}
beforeRemove(){}
remove(){const parent=this.parentEl;for(let elem of this.content){nodeRemoveChild.call(parent,elem);}}
firstNode(){return this.content[0];}
toString(){return this.html;}}
function html(str){return new VHtml(str);}
function createCatcher(eventsSpec){const n=Object.keys(eventsSpec).length;class VCatcher{constructor(child,handlers){this.handlerFns=[];this.afterNode=null;this.child=child;this.handlerData=handlers;}
mount(parent,afterNode){this.parentEl=parent;this.child.mount(parent,afterNode);this.afterNode=document.createTextNode("");parent.insertBefore(this.afterNode,afterNode);this.wrapHandlerData();for(let name in eventsSpec){const index=eventsSpec[name];const handler=createEventHandler(name);this.handlerFns[index]=handler;handler.setup.call(parent,this.handlerData[index]);}}
wrapHandlerData(){for(let i=0;i<n;i++){let handler=this.handlerData[i];let idx=handler.length-2;let origFn=handler[idx];const self=this;handler[idx]=function(ev){const target=ev.target;let currentNode=self.child.firstNode();const afterNode=self.afterNode;while(currentNode&&currentNode!==afterNode){if(currentNode.contains(target)){return origFn.call(this,ev);}
currentNode=currentNode.nextSibling;}};}}
moveBeforeDOMNode(node,parent=this.parentEl){this.parentEl=parent;this.child.moveBeforeDOMNode(node,parent);parent.insertBefore(this.afterNode,node);}
moveBeforeVNode(other,afterNode){if(other){afterNode=other.firstNode()||afterNode;}
this.child.moveBeforeVNode(other?other.child:null,afterNode);this.parentEl.insertBefore(this.afterNode,afterNode);}
patch(other,withBeforeRemove){if(this===other){return;}
this.handlerData=other.handlerData;this.wrapHandlerData();for(let i=0;i<n;i++){this.handlerFns[i].update.call(this.parentEl,this.handlerData[i]);}
this.child.patch(other.child,withBeforeRemove);}
beforeRemove(){this.child.beforeRemove();}
remove(){for(let i=0;i<n;i++){this.handlerFns[i].remove.call(this.parentEl);}
this.child.remove();this.afterNode.remove();}
firstNode(){return this.child.firstNode();}
toString(){return this.child.toString();}}
return function(child,handlers){return new VCatcher(child,handlers);};}
function mount$1(vnode,fixture,afterNode=null){vnode.mount(fixture,afterNode);}
function patch(vnode1,vnode2,withBeforeRemove=false){vnode1.patch(vnode2,withBeforeRemove);}
function remove(vnode,withBeforeRemove=false){if(withBeforeRemove){vnode.beforeRemove();}
vnode.remove();}
const fibersInError=new WeakMap();const nodeErrorHandlers=new WeakMap();function _handleError(node,error){if(!node){return false;}
const fiber=node.fiber;if(fiber){fibersInError.set(fiber,error);}
const errorHandlers=nodeErrorHandlers.get(node);if(errorHandlers){let handled=false;for(let i=errorHandlers.length-1;i>=0;i--){try{errorHandlers[i](error);handled=true;break;}
catch(e){error=e;}}
if(handled){return true;}}
return _handleError(node.parent,error);}
function handleError(params){let{error}=params;if(!(error instanceof OwlError)){error=Object.assign(new OwlError(`An error occured in the owl lifecycle (see this Error's "cause" property)`),{cause:error});}
const node="node"in params?params.node:params.fiber.node;const fiber="fiber"in params?params.fiber:node.fiber;if(fiber){let current=fiber;do{current.node.fiber=current;current=current.parent;}while(current);fibersInError.set(fiber.root,error);}
const handled=_handleError(node,error);if(!handled){console.warn(`[Owl] Unhandled error. Destroying the root component`);try{node.app.destroy();}
catch(e){console.error(e);}
throw error;}}
function makeChildFiber(node,parent){let current=node.fiber;if(current){cancelFibers(current.children);current.root=null;}
return new Fiber(node,parent);}
function makeRootFiber(node){let current=node.fiber;if(current){let root=current.root;root.locked=true;root.setCounter(root.counter+1-cancelFibers(current.children));root.locked=false;current.children=[];current.childrenMap={};current.bdom=null;if(fibersInError.has(current)){fibersInError.delete(current);fibersInError.delete(root);current.appliedToDom=false;if(current instanceof RootFiber){current.mounted=current instanceof MountFiber?[current]:[];}}
return current;}
const fiber=new RootFiber(node,null);if(node.willPatch.length){fiber.willPatch.push(fiber);}
if(node.patched.length){fiber.patched.push(fiber);}
return fiber;}
function throwOnRender(){throw new OwlError("Attempted to render cancelled fiber");}
function cancelFibers(fibers){let result=0;for(let fiber of fibers){let node=fiber.node;fiber.render=throwOnRender;if(node.status===0){node.cancel();}
node.fiber=null;if(fiber.bdom){node.forceNextRender=true;}
else{result++;}
result+=cancelFibers(fiber.children);}
return result;}
class Fiber{constructor(node,parent){this.bdom=null;this.children=[];this.appliedToDom=false;this.deep=false;this.childrenMap={};this.node=node;this.parent=parent;if(parent){this.deep=parent.deep;const root=parent.root;root.setCounter(root.counter+1);this.root=root;parent.children.push(this);}
else{this.root=this;}}
render(){let prev=this.root.node;let scheduler=prev.app.scheduler;let current=prev.parent;while(current){if(current.fiber){let root=current.fiber.root;if(root.counter===0&&prev.parentKey in current.fiber.childrenMap){current=root.node;}
else{scheduler.delayedRenders.push(this);return;}}
prev=current;current=current.parent;}
this._render();}
_render(){const node=this.node;const root=this.root;if(root){try{this.bdom=true;this.bdom=node.renderFn();}
catch(e){node.app.handleError({node,error:e});}
root.setCounter(root.counter-1);}}}
class RootFiber extends Fiber{constructor(){super(...arguments);this.counter=1;this.willPatch=[];this.patched=[];this.mounted=[];this.locked=false;}
complete(){const node=this.node;this.locked=true;let current=undefined;let mountedFibers=this.mounted;try{for(current of this.willPatch){let node=current.node;if(node.fiber===current){const component=node.component;for(let cb of node.willPatch){cb.call(component);}}}
current=undefined;node._patch();this.locked=false;while((current=mountedFibers.pop())){current=current;if(current.appliedToDom){for(let cb of current.node.mounted){cb();}}}
let patchedFibers=this.patched;while((current=patchedFibers.pop())){current=current;if(current.appliedToDom){for(let cb of current.node.patched){cb();}}}}
catch(e){for(let fiber of mountedFibers){fiber.node.willUnmount=[];}
this.locked=false;node.app.handleError({fiber:current||this,error:e});}}
setCounter(newValue){this.counter=newValue;if(newValue===0){this.node.app.scheduler.flush();}}}
class MountFiber extends RootFiber{constructor(node,target,options={}){super(node,null);this.target=target;this.position=options.position||"last-child";}
complete(){let current=this;try{const node=this.node;node.children=this.childrenMap;node.app.constructor.validateTarget(this.target);if(node.bdom){node.updateDom();}
else{node.bdom=this.bdom;if(this.position==="last-child"||this.target.childNodes.length===0){mount$1(node.bdom,this.target);}
else{const firstChild=this.target.childNodes[0];mount$1(node.bdom,this.target,firstChild);}}
node.fiber=null;node.status=1;this.appliedToDom=true;let mountedFibers=this.mounted;while((current=mountedFibers.pop())){if(current.appliedToDom){for(let cb of current.node.mounted){cb();}}}}
catch(e){this.node.app.handleError({fiber:current,error:e});}}}
const KEYCHANGES=Symbol("Key changes");const NO_CALLBACK=()=>{throw new Error("Called NO_CALLBACK. Owl is broken, please report this to the maintainers.");};const objectToString=Object.prototype.toString;const objectHasOwnProperty=Object.prototype.hasOwnProperty;const SUPPORTED_RAW_TYPES=["Object","Array","Set","Map","WeakMap"];const COLLECTION_RAW_TYPES=["Set","Map","WeakMap"];function rawType(obj){return objectToString.call(toRaw(obj)).slice(8,-1);}
function canBeMadeReactive(value){if(typeof value!=="object"){return false;}
return SUPPORTED_RAW_TYPES.includes(rawType(value));}
function possiblyReactive(val,cb){return canBeMadeReactive(val)?reactive(val,cb):val;}
const skipped=new WeakSet();function markRaw(value){skipped.add(value);return value;}
function toRaw(value){return targets.has(value)?targets.get(value):value;}
const targetToKeysToCallbacks=new WeakMap();function observeTargetKey(target,key,callback){if(callback===NO_CALLBACK){return;}
if(!targetToKeysToCallbacks.get(target)){targetToKeysToCallbacks.set(target,new Map());}
const keyToCallbacks=targetToKeysToCallbacks.get(target);if(!keyToCallbacks.get(key)){keyToCallbacks.set(key,new Set());}
keyToCallbacks.get(key).add(callback);if(!callbacksToTargets.has(callback)){callbacksToTargets.set(callback,new Set());}
callbacksToTargets.get(callback).add(target);}
function notifyReactives(target,key){const keyToCallbacks=targetToKeysToCallbacks.get(target);if(!keyToCallbacks){return;}
const callbacks=keyToCallbacks.get(key);if(!callbacks){return;}
for(const callback of[...callbacks]){clearReactivesForCallback(callback);callback();}}
const callbacksToTargets=new WeakMap();function clearReactivesForCallback(callback){const targetsToClear=callbacksToTargets.get(callback);if(!targetsToClear){return;}
for(const target of targetsToClear){const observedKeys=targetToKeysToCallbacks.get(target);if(!observedKeys){continue;}
for(const[key,callbacks]of observedKeys.entries()){callbacks.delete(callback);if(!callbacks.size){observedKeys.delete(key);}}}
targetsToClear.clear();}
function getSubscriptions(callback){const targets=callbacksToTargets.get(callback)||[];return[...targets].map((target)=>{const keysToCallbacks=targetToKeysToCallbacks.get(target);let keys=[];if(keysToCallbacks){for(const[key,cbs]of keysToCallbacks){if(cbs.has(callback)){keys.push(key);}}}
return{target,keys};});}
const targets=new WeakMap();const reactiveCache=new WeakMap();function reactive(target,callback=NO_CALLBACK){if(!canBeMadeReactive(target)){throw new OwlError(`Cannot make the given value reactive`);}
if(skipped.has(target)){return target;}
if(targets.has(target)){return reactive(targets.get(target),callback);}
if(!reactiveCache.has(target)){reactiveCache.set(target,new WeakMap());}
const reactivesForTarget=reactiveCache.get(target);if(!reactivesForTarget.has(callback)){const targetRawType=rawType(target);const handler=COLLECTION_RAW_TYPES.includes(targetRawType)?collectionsProxyHandler(target,callback,targetRawType):basicProxyHandler(callback);const proxy=new Proxy(target,handler);reactivesForTarget.set(callback,proxy);targets.set(proxy,target);}
return reactivesForTarget.get(callback);}
function basicProxyHandler(callback){return{get(target,key,receiver){const desc=Object.getOwnPropertyDescriptor(target,key);if(desc&&!desc.writable&&!desc.configurable){return Reflect.get(target,key,receiver);}
observeTargetKey(target,key,callback);return possiblyReactive(Reflect.get(target,key,receiver),callback);},set(target,key,value,receiver){const hadKey=objectHasOwnProperty.call(target,key);const originalValue=Reflect.get(target,key,receiver);const ret=Reflect.set(target,key,toRaw(value),receiver);if(!hadKey&&objectHasOwnProperty.call(target,key)){notifyReactives(target,KEYCHANGES);}
if(originalValue!==Reflect.get(target,key,receiver)||(key==="length"&&Array.isArray(target))){notifyReactives(target,key);}
return ret;},deleteProperty(target,key){const ret=Reflect.deleteProperty(target,key);notifyReactives(target,KEYCHANGES);notifyReactives(target,key);return ret;},ownKeys(target){observeTargetKey(target,KEYCHANGES,callback);return Reflect.ownKeys(target);},has(target,key){observeTargetKey(target,KEYCHANGES,callback);return Reflect.has(target,key);},};}
function makeKeyObserver(methodName,target,callback){return(key)=>{key=toRaw(key);observeTargetKey(target,key,callback);return possiblyReactive(target[methodName](key),callback);};}
function makeIteratorObserver(methodName,target,callback){return function*(){observeTargetKey(target,KEYCHANGES,callback);const keys=target.keys();for(const item of target[methodName]()){const key=keys.next().value;observeTargetKey(target,key,callback);yield possiblyReactive(item,callback);}};}
function makeForEachObserver(target,callback){return function forEach(forEachCb,thisArg){observeTargetKey(target,KEYCHANGES,callback);target.forEach(function(val,key,targetObj){observeTargetKey(target,key,callback);forEachCb.call(thisArg,possiblyReactive(val,callback),possiblyReactive(key,callback),possiblyReactive(targetObj,callback));},thisArg);};}
function delegateAndNotify(setterName,getterName,target){return(key,value)=>{key=toRaw(key);const hadKey=target.has(key);const originalValue=target[getterName](key);const ret=target[setterName](key,value);const hasKey=target.has(key);if(hadKey!==hasKey){notifyReactives(target,KEYCHANGES);}
if(originalValue!==target[getterName](key)){notifyReactives(target,key);}
return ret;};}
function makeClearNotifier(target){return()=>{const allKeys=[...target.keys()];target.clear();notifyReactives(target,KEYCHANGES);for(const key of allKeys){notifyReactives(target,key);}};}
const rawTypeToFuncHandlers={Set:(target,callback)=>({has:makeKeyObserver("has",target,callback),add:delegateAndNotify("add","has",target),delete:delegateAndNotify("delete","has",target),keys:makeIteratorObserver("keys",target,callback),values:makeIteratorObserver("values",target,callback),entries:makeIteratorObserver("entries",target,callback),[Symbol.iterator]:makeIteratorObserver(Symbol.iterator,target,callback),forEach:makeForEachObserver(target,callback),clear:makeClearNotifier(target),get size(){observeTargetKey(target,KEYCHANGES,callback);return target.size;},}),Map:(target,callback)=>({has:makeKeyObserver("has",target,callback),get:makeKeyObserver("get",target,callback),set:delegateAndNotify("set","get",target),delete:delegateAndNotify("delete","has",target),keys:makeIteratorObserver("keys",target,callback),values:makeIteratorObserver("values",target,callback),entries:makeIteratorObserver("entries",target,callback),[Symbol.iterator]:makeIteratorObserver(Symbol.iterator,target,callback),forEach:makeForEachObserver(target,callback),clear:makeClearNotifier(target),get size(){observeTargetKey(target,KEYCHANGES,callback);return target.size;},}),WeakMap:(target,callback)=>({has:makeKeyObserver("has",target,callback),get:makeKeyObserver("get",target,callback),set:delegateAndNotify("set","get",target),delete:delegateAndNotify("delete","has",target),}),};function collectionsProxyHandler(target,callback,targetRawType){const specialHandlers=rawTypeToFuncHandlers[targetRawType](target,callback);return Object.assign(basicProxyHandler(callback),{get(target,key){if(objectHasOwnProperty.call(specialHandlers,key)){return specialHandlers[key];}
observeTargetKey(target,key,callback);return possiblyReactive(target[key],callback);},});}
let currentNode=null;function saveCurrent(){let n=currentNode;return()=>{currentNode=n;};}
function getCurrent(){if(!currentNode){throw new OwlError("No active component (a hook function should only be called in 'setup')");}
return currentNode;}
function useComponent(){return currentNode.component;}
function applyDefaultProps(props,defaultProps){for(let propName in defaultProps){if(props[propName]===undefined){props[propName]=defaultProps[propName];}}}
const batchedRenderFunctions=new WeakMap();function useState(state){const node=getCurrent();let render=batchedRenderFunctions.get(node);if(!render){render=batched(node.render.bind(node,false));batchedRenderFunctions.set(node,render);node.willDestroy.push(clearReactivesForCallback.bind(null,render));}
return reactive(state,render);}
class ComponentNode{constructor(C,props,app,parent,parentKey){this.fiber=null;this.bdom=null;this.status=0;this.forceNextRender=false;this.nextProps=null;this.children=Object.create(null);this.refs={};this.willStart=[];this.willUpdateProps=[];this.willUnmount=[];this.mounted=[];this.willPatch=[];this.patched=[];this.willDestroy=[];currentNode=this;this.app=app;this.parent=parent;this.props=props;this.parentKey=parentKey;const defaultProps=C.defaultProps;props=Object.assign({},props);if(defaultProps){applyDefaultProps(props,defaultProps);}
const env=(parent&&parent.childEnv)||app.env;this.childEnv=env;for(const key in props){const prop=props[key];if(prop&&typeof prop==="object"&&targets.has(prop)){props[key]=useState(prop);}}
this.component=new C(props,env,this);const ctx=Object.assign(Object.create(this.component),{this:this.component});this.renderFn=app.getTemplate(C.template).bind(this.component,ctx,this);this.component.setup();currentNode=null;}
mountComponent(target,options){const fiber=new MountFiber(this,target,options);this.app.scheduler.addFiber(fiber);this.initiateRender(fiber);}
async initiateRender(fiber){this.fiber=fiber;if(this.mounted.length){fiber.root.mounted.push(fiber);}
const component=this.component;try{await Promise.all(this.willStart.map((f)=>f.call(component)));}
catch(e){this.app.handleError({node:this,error:e});return;}
if(this.status===0&&this.fiber===fiber){fiber.render();}}
async render(deep){if(this.status>=2){return;}
let current=this.fiber;if(current&&(current.root.locked||current.bdom===true)){await Promise.resolve();current=this.fiber;}
if(current){if(!current.bdom&&!fibersInError.has(current)){if(deep){current.deep=deep;}
return;}
deep=deep||current.deep;}
else if(!this.bdom){return;}
const fiber=makeRootFiber(this);fiber.deep=deep;this.fiber=fiber;this.app.scheduler.addFiber(fiber);await Promise.resolve();if(this.status>=2){return;}
if(this.fiber===fiber&&(current||!fiber.parent)){fiber.render();}}
cancel(){this._cancel();delete this.parent.children[this.parentKey];this.app.scheduler.scheduleDestroy(this);}
_cancel(){this.status=2;const children=this.children;for(let childKey in children){children[childKey]._cancel();}}
destroy(){let shouldRemove=this.status===1;this._destroy();if(shouldRemove){this.bdom.remove();}}
_destroy(){const component=this.component;if(this.status===1){for(let cb of this.willUnmount){cb.call(component);}}
for(let child of Object.values(this.children)){child._destroy();}
if(this.willDestroy.length){try{for(let cb of this.willDestroy){cb.call(component);}}
catch(e){this.app.handleError({error:e,node:this});}}
this.status=3;}
async updateAndRender(props,parentFiber){this.nextProps=props;props=Object.assign({},props);const fiber=makeChildFiber(this,parentFiber);this.fiber=fiber;const component=this.component;const defaultProps=component.constructor.defaultProps;if(defaultProps){applyDefaultProps(props,defaultProps);}
currentNode=this;for(const key in props){const prop=props[key];if(prop&&typeof prop==="object"&&targets.has(prop)){props[key]=useState(prop);}}
currentNode=null;const prom=Promise.all(this.willUpdateProps.map((f)=>f.call(component,props)));await prom;if(fiber!==this.fiber){return;}
component.props=props;fiber.render();const parentRoot=parentFiber.root;if(this.willPatch.length){parentRoot.willPatch.push(fiber);}
if(this.patched.length){parentRoot.patched.push(fiber);}}
updateDom(){if(!this.fiber){return;}
if(this.bdom===this.fiber.bdom){for(let k in this.children){const child=this.children[k];child.updateDom();}}
else{this.bdom.patch(this.fiber.bdom,false);this.fiber.appliedToDom=true;this.fiber=null;}}
setRef(name,el){if(el){this.refs[name]=el;}}
firstNode(){const bdom=this.bdom;return bdom?bdom.firstNode():undefined;}
mount(parent,anchor){const bdom=this.fiber.bdom;this.bdom=bdom;bdom.mount(parent,anchor);this.status=1;this.fiber.appliedToDom=true;this.children=this.fiber.childrenMap;this.fiber=null;}
moveBeforeDOMNode(node,parent){this.bdom.moveBeforeDOMNode(node,parent);}
moveBeforeVNode(other,afterNode){this.bdom.moveBeforeVNode(other?other.bdom:null,afterNode);}
patch(){if(this.fiber&&this.fiber.parent){this._patch();this.props=this.nextProps;}}
_patch(){let hasChildren=false;for(let _k in this.children){hasChildren=true;break;}
const fiber=this.fiber;this.children=fiber.childrenMap;this.bdom.patch(fiber.bdom,hasChildren);fiber.appliedToDom=true;this.fiber=null;}
beforeRemove(){this._destroy();}
remove(){this.bdom.remove();}
get name(){return this.component.constructor.name;}
get subscriptions(){const render=batchedRenderFunctions.get(this);return render?getSubscriptions(render):[];}}
const TIMEOUT=Symbol("timeout");const HOOK_TIMEOUT={onWillStart:3000,onWillUpdateProps:3000,};function wrapError(fn,hookName){const error=new OwlError();const timeoutError=new OwlError();const node=getCurrent();return(...args)=>{const onError=(cause)=>{error.cause=cause;error.message=cause instanceof Error?`The following error occurred in ${hookName}: "${cause.message}"`:`Something that is not an Error was thrown in ${hookName} (see this Error's "cause" property)`;throw error;};let result;try{result=fn(...args);}
catch(cause){onError(cause);}
if(!(result instanceof Promise)){return result;}
const timeout=HOOK_TIMEOUT[hookName];if(timeout){const fiber=node.fiber;Promise.race([result.catch(()=>{}),new Promise((resolve)=>setTimeout(()=>resolve(TIMEOUT),timeout)),]).then((res)=>{if(res===TIMEOUT&&node.fiber===fiber&&node.status<=2){timeoutError.message=`${hookName}'s promise hasn't resolved after ${timeout / 1000} seconds`;console.log(timeoutError);}});}
return result.catch(onError);};}
function onWillStart(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willStart.push(decorate(fn.bind(node.component),"onWillStart"));}
function onWillUpdateProps(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willUpdateProps.push(decorate(fn.bind(node.component),"onWillUpdateProps"));}
function onMounted(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.mounted.push(decorate(fn.bind(node.component),"onMounted"));}
function onWillPatch(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willPatch.unshift(decorate(fn.bind(node.component),"onWillPatch"));}
function onPatched(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.patched.push(decorate(fn.bind(node.component),"onPatched"));}
function onWillUnmount(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willUnmount.unshift(decorate(fn.bind(node.component),"onWillUnmount"));}
function onWillDestroy(fn){const node=getCurrent();const decorate=node.app.dev?wrapError:(fn)=>fn;node.willDestroy.push(decorate(fn.bind(node.component),"onWillDestroy"));}
function onWillRender(fn){const node=getCurrent();const renderFn=node.renderFn;const decorate=node.app.dev?wrapError:(fn)=>fn;fn=decorate(fn.bind(node.component),"onWillRender");node.renderFn=()=>{fn();return renderFn();};}
function onRendered(fn){const node=getCurrent();const renderFn=node.renderFn;const decorate=node.app.dev?wrapError:(fn)=>fn;fn=decorate(fn.bind(node.component),"onRendered");node.renderFn=()=>{const result=renderFn();fn();return result;};}
function onError(callback){const node=getCurrent();let handlers=nodeErrorHandlers.get(node);if(!handlers){handlers=[];nodeErrorHandlers.set(node,handlers);}
handlers.push(callback.bind(node.component));}
class Component{constructor(props,env,node){this.props=props;this.env=env;this.__owl__=node;}
setup(){}
render(deep=false){this.__owl__.render(deep===true);}}
Component.template="";const VText=text("").constructor;class VPortal extends VText{constructor(selector,content){super("");this.target=null;this.selector=selector;this.content=content;}
mount(parent,anchor){super.mount(parent,anchor);this.target=document.querySelector(this.selector);if(this.target){this.content.mount(this.target,null);}
else{this.content.mount(parent,anchor);}}
beforeRemove(){this.content.beforeRemove();}
remove(){if(this.content){super.remove();this.content.remove();this.content=null;}}
patch(other){super.patch(other);if(this.content){this.content.patch(other.content,true);}
else{this.content=other.content;this.content.mount(this.target,null);}}}
function portalTemplate(app,bdom,helpers){let{callSlot}=helpers;return function template(ctx,node,key=""){return new VPortal(ctx.props.target,callSlot(ctx,node,key,"default",false,null));};}
class Portal extends Component{setup(){const node=this.__owl__;onMounted(()=>{const portal=node.bdom;if(!portal.target){const target=document.querySelector(this.props.target);if(target){portal.content.moveBeforeDOMNode(target.firstChild,target);}
else{throw new OwlError("invalid portal target");}}});onWillUnmount(()=>{const portal=node.bdom;portal.remove();});}}
Portal.template="__portal__";Portal.props={target:{type:String,},slots:true,};const isUnionType=(t)=>Array.isArray(t);const isBaseType=(t)=>typeof t!=="object";const isValueType=(t)=>typeof t==="object"&&t&&"value"in t;function isOptional(t){return typeof t==="object"&&"optional"in t?t.optional||false:false;}
function describeType(type){return type==="*"||type===true?"value":type.name.toLowerCase();}
function describe(info){if(isBaseType(info)){return describeType(info);}
else if(isUnionType(info)){return info.map(describe).join(" or ");}
else if(isValueType(info)){return String(info.value);}
if("element"in info){return`list of ${describe({ type: info.element, optional: false })}s`;}
if("shape"in info){return`object`;}
return describe(info.type||"*");}
function toSchema(spec){return Object.fromEntries(spec.map((e)=>e.endsWith("?")?[e.slice(0,-1),{optional:true}]:[e,{type:"*",optional:false}]));}
function validate(obj,spec){let errors=validateSchema(obj,spec);if(errors.length){throw new OwlError("Invalid object: "+errors.join(", "));}}
function validateSchema(obj,schema){if(Array.isArray(schema)){schema=toSchema(schema);}
obj=toRaw(obj);let errors=[];for(let key in obj){if(key in schema){let result=validateType(key,obj[key],schema[key]);if(result){errors.push(result);}}
else if(!("*"in schema)){errors.push(`unknown key '${key}'`);}}
for(let key in schema){const spec=schema[key];if(key!=="*"&&!isOptional(spec)&&!(key in obj)){const isObj=typeof spec==="object"&&!Array.isArray(spec);const isAny=spec==="*"||(isObj&&"type"in spec?spec.type==="*":isObj);let detail=isAny?"":` (should be a ${describe(spec)})`;errors.push(`'${key}' is missing${detail}`);}}
return errors;}
function validateBaseType(key,value,type){if(typeof type==="function"){if(typeof value==="object"){if(!(value instanceof type)){return`'${key}' is not a ${describeType(type)}`;}}
else if(typeof value!==type.name.toLowerCase()){return`'${key}' is not a ${describeType(type)}`;}}
return null;}
function validateArrayType(key,value,descr){if(!Array.isArray(value)){return`'${key}' is not a list of ${describe(descr)}s`;}
for(let i=0;i<value.length;i++){const error=validateType(`${key}[${i}]`,value[i],descr);if(error){return error;}}
return null;}
function validateType(key,value,descr){if(value===undefined){return isOptional(descr)?null:`'${key}' is undefined (should be a ${describe(descr)})`;}
else if(isBaseType(descr)){return validateBaseType(key,value,descr);}
else if(isValueType(descr)){return value===descr.value?null:`'${key}' is not equal to '${descr.value}'`;}
else if(isUnionType(descr)){let validDescr=descr.find((p)=>!validateType(key,value,p));return validDescr?null:`'${key}' is not a ${describe(descr)}`;}
let result=null;if("element"in descr){result=validateArrayType(key,value,descr.element);}
else if("shape"in descr){if(typeof value!=="object"||Array.isArray(value)){result=`'${key}' is not an object`;}
else{const errors=validateSchema(value,descr.shape);if(errors.length){result=`'${key}' doesn't have the correct shape (${errors.join(", ")})`;}}}
else if("values"in descr){if(typeof value!=="object"||Array.isArray(value)){result=`'${key}' is not an object`;}
else{const errors=Object.entries(value).map(([key,value])=>validateType(key,value,descr.values)).filter(Boolean);if(errors.length){result=`some of the values in '${key}' are invalid (${errors.join(", ")})`;}}}
if("type"in descr&&!result){result=validateType(key,value,descr.type);}
if("validate"in descr&&!result){result=!descr.validate(value)?`'${key}' is not valid`:null;}
return result;}
const ObjectCreate=Object.create;function withDefault(value,defaultValue){return value===undefined||value===null||value===false?defaultValue:value;}
function callSlot(ctx,parent,key,name,dynamic,extra,defaultContent){key=key+"__slot_"+name;const slots=ctx.props.slots||{};const{__render,__ctx,__scope}=slots[name]||{};const slotScope=ObjectCreate(__ctx||{});if(__scope){slotScope[__scope]=extra;}
const slotBDom=__render?__render(slotScope,parent,key):null;if(defaultContent){let child1=undefined;let child2=undefined;if(slotBDom){child1=dynamic?toggler(name,slotBDom):slotBDom;}
else{child2=defaultContent(ctx,parent,key);}
return multi([child1,child2]);}
return slotBDom||text("");}
function capture(ctx){const result=ObjectCreate(ctx);for(let k in ctx){result[k]=ctx[k];}
return result;}
function withKey(elem,k){elem.key=k;return elem;}
function prepareList(collection){let keys;let values;if(Array.isArray(collection)){keys=collection;values=collection;}
else if(collection instanceof Map){keys=[...collection.keys()];values=[...collection.values()];}
else if(Symbol.iterator in Object(collection)){keys=[...collection];values=keys;}
else if(collection&&typeof collection==="object"){values=Object.values(collection);keys=Object.keys(collection);}
else{throw new OwlError(`Invalid loop expression: "${collection}" is not iterable`);}
const n=values.length;return[keys,values,n,new Array(n)];}
const isBoundary=Symbol("isBoundary");function setContextValue(ctx,key,value){const ctx0=ctx;while(!ctx.hasOwnProperty(key)&&!ctx.hasOwnProperty(isBoundary)){const newCtx=ctx.__proto__;if(!newCtx){ctx=ctx0;break;}
ctx=newCtx;}
ctx[key]=value;}
function toNumber(val){const n=parseFloat(val);return isNaN(n)?val:n;}
function shallowEqual(l1,l2){for(let i=0,l=l1.length;i<l;i++){if(l1[i]!==l2[i]){return false;}}
return true;}
class LazyValue{constructor(fn,ctx,component,node,key){this.fn=fn;this.ctx=capture(ctx);this.component=component;this.node=node;this.key=key;}
evaluate(){return this.fn.call(this.component,this.ctx,this.node,this.key);}
toString(){return this.evaluate().toString();}}
function safeOutput(value,defaultValue){if(value===undefined||value===null){return defaultValue?toggler("default",defaultValue):toggler("undefined",text(""));}
let safeKey;let block;switch(typeof value){case"object":if(value instanceof Markup){safeKey=`string_safe`;block=html(value);}
else if(value instanceof LazyValue){safeKey=`lazy_value`;block=value.evaluate();}
else if(value instanceof String){safeKey="string_unsafe";block=text(value);}
else{safeKey="block_safe";block=value;}
break;case"string":safeKey="string_unsafe";block=text(value);break;default:safeKey="string_unsafe";block=text(String(value));}
return toggler(safeKey,block);}
function validateProps(name,props,comp){const ComponentClass=typeof name!=="string"?name:comp.constructor.components[name];if(!ComponentClass){return;}
const schema=ComponentClass.props;if(!schema){if(comp.__owl__.app.warnIfNoStaticProps){console.warn(`Component '${ComponentClass.name}' does not have a static props description`);}
return;}
const defaultProps=ComponentClass.defaultProps;if(defaultProps){let isMandatory=(name)=>Array.isArray(schema)?schema.includes(name):name in schema&&!("*"in schema)&&!isOptional(schema[name]);for(let p in defaultProps){if(isMandatory(p)){throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);}}}
const errors=validateSchema(props,schema);if(errors.length){throw new OwlError(`Invalid props for component '${ComponentClass.name}': `+errors.join(", "));}}
function makeRefWrapper(node){let refNames=new Set();return(name,fn)=>{if(refNames.has(name)){throw new OwlError(`Cannot set the same ref more than once in the same component, ref "${name}" was set multiple times in ${node.name}`);}
refNames.add(name);return fn;};}
const helpers={withDefault,zero:Symbol("zero"),isBoundary,callSlot,capture,withKey,prepareList,setContextValue,shallowEqual,toNumber,validateProps,LazyValue,safeOutput,createCatcher,markRaw,OwlError,makeRefWrapper,};function parseXML(xml){const parser=new DOMParser();const doc=parser.parseFromString(xml,"text/xml");if(doc.getElementsByTagName("parsererror").length){let msg="Invalid XML in template.";const parsererrorText=doc.getElementsByTagName("parsererror")[0].textContent;if(parsererrorText){msg+="\nThe parser has produced the following error message:\n"+parsererrorText;const re=/\d+/g;const firstMatch=re.exec(parsererrorText);if(firstMatch){const lineNumber=Number(firstMatch[0]);const line=xml.split("\n")[lineNumber-1];const secondMatch=re.exec(parsererrorText);if(line&&secondMatch){const columnIndex=Number(secondMatch[0])-1;if(line[columnIndex]){msg+=`\nThe error might be located at xml line ${lineNumber} column ${columnIndex}\n`+`${line}\n${"-".repeat(columnIndex - 1)}^`;}}}}
throw new OwlError(msg);}
return doc;}
const bdom={text,createBlock,list,multi,html,toggler,comment};class TemplateSet{constructor(config={}){this.rawTemplates=Object.create(globalTemplates);this.templates={};this.Portal=Portal;this.dev=config.dev||false;this.translateFn=config.translateFn;this.translatableAttributes=config.translatableAttributes;if(config.templates){if(config.templates instanceof Document||typeof config.templates==="string"){this.addTemplates(config.templates);}
else{for(const name in config.templates){this.addTemplate(name,config.templates[name]);}}}
this.getRawTemplate=config.getTemplate;this.customDirectives=config.customDirectives||{};this.runtimeUtils={...helpers,__globals__:config.globalValues||{}};this.hasGlobalValues=Boolean(config.globalValues&&Object.keys(config.globalValues).length);}
static registerTemplate(name,fn){globalTemplates[name]=fn;}
addTemplate(name,template){if(name in this.rawTemplates){if(!this.dev){return;}
const rawTemplate=this.rawTemplates[name];const currentAsString=typeof rawTemplate==="string"?rawTemplate:rawTemplate instanceof Element?rawTemplate.outerHTML:rawTemplate.toString();const newAsString=typeof template==="string"?template:template.outerHTML;if(currentAsString===newAsString){return;}
throw new OwlError(`Template ${name} already defined with different content`);}
this.rawTemplates[name]=template;}
addTemplates(xml){if(!xml){return;}
xml=xml instanceof Document?xml:parseXML(xml);for(const template of xml.querySelectorAll("[t-name]")){const name=template.getAttribute("t-name");this.addTemplate(name,template);}}
getTemplate(name){var _a;if(!(name in this.templates)){const rawTemplate=((_a=this.getRawTemplate)===null||_a===void 0?void 0:_a.call(this,name))||this.rawTemplates[name];if(rawTemplate===undefined){let extraInfo="";try{const componentName=getCurrent().component.constructor.name;extraInfo=` (for component "${componentName}")`;}
catch{}
throw new OwlError(`Missing template: "${name}"${extraInfo}`);}
const isFn=typeof rawTemplate==="function"&&!(rawTemplate instanceof Element);const templateFn=isFn?rawTemplate:this._compileTemplate(name,rawTemplate);const templates=this.templates;this.templates[name]=function(context,parent){return templates[name].call(this,context,parent);};const template=templateFn(this,bdom,this.runtimeUtils);this.templates[name]=template;}
return this.templates[name];}
_compileTemplate(name,template){throw new OwlError(`Unable to compile a template. Please use owl full build instead`);}
callTemplate(owner,subTemplate,ctx,parent,key){const template=this.getTemplate(subTemplate);return toggler(subTemplate,template.call(owner,ctx,parent,key+subTemplate));}}
const globalTemplates={};function xml(...args){const name=`__template__${xml.nextId++}`;const value=String.raw(...args);globalTemplates[name]=value;return name;}
xml.nextId=1;TemplateSet.registerTemplate("__portal__",portalTemplate);const RESERVED_WORDS="true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,eval,void,Math,RegExp,Array,Object,Date,__globals__".split(",");const WORD_REPLACEMENT=Object.assign(Object.create(null),{and:"&&",or:"||",gt:">",gte:">=",lt:"<",lte:"<=",});const STATIC_TOKEN_MAP=Object.assign(Object.create(null),{"{":"LEFT_BRACE","}":"RIGHT_BRACE","[":"LEFT_BRACKET","]":"RIGHT_BRACKET",":":"COLON",",":"COMMA","(":"LEFT_PAREN",")":"RIGHT_PAREN",});const OPERATORS="...,.,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=,;,in ,new ,|,&,^,~".split(",");let tokenizeString=function(expr){let s=expr[0];let start=s;if(s!=="'"&&s!=='"'&&s!=="`"){return false;}
let i=1;let cur;while(expr[i]&&expr[i]!==start){cur=expr[i];s+=cur;if(cur==="\\"){i++;cur=expr[i];if(!cur){throw new OwlError("Invalid expression");}
s+=cur;}
i++;}
if(expr[i]!==start){throw new OwlError("Invalid expression");}
s+=start;if(start==="`"){return{type:"TEMPLATE_STRING",value:s,replace(replacer){return s.replace(/\$\{(.*?)\}/g,(match,group)=>{return"${"+replacer(group)+"}";});},};}
return{type:"VALUE",value:s};};let tokenizeNumber=function(expr){let s=expr[0];if(s&&s.match(/[0-9]/)){let i=1;while(expr[i]&&expr[i].match(/[0-9]|\./)){s+=expr[i];i++;}
return{type:"VALUE",value:s};}
else{return false;}};let tokenizeSymbol=function(expr){let s=expr[0];if(s&&s.match(/[a-zA-Z_\$]/)){let i=1;while(expr[i]&&expr[i].match(/\w/)){s+=expr[i];i++;}
if(s in WORD_REPLACEMENT){return{type:"OPERATOR",value:WORD_REPLACEMENT[s],size:s.length};}
return{type:"SYMBOL",value:s};}
else{return false;}};const tokenizeStatic=function(expr){const char=expr[0];if(char&&char in STATIC_TOKEN_MAP){return{type:STATIC_TOKEN_MAP[char],value:char};}
return false;};const tokenizeOperator=function(expr){for(let op of OPERATORS){if(expr.startsWith(op)){return{type:"OPERATOR",value:op};}}
return false;};const TOKENIZERS=[tokenizeString,tokenizeNumber,tokenizeOperator,tokenizeSymbol,tokenizeStatic,];function tokenize(expr){const result=[];let token=true;let error;let current=expr;try{while(token){current=current.trim();if(current){for(let tokenizer of TOKENIZERS){token=tokenizer(current);if(token){result.push(token);current=current.slice(token.size||token.value.length);break;}}}
else{token=false;}}}
catch(e){error=e;}
if(current.length||error){throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);}
return result;}
const isLeftSeparator=(token)=>token&&(token.type==="LEFT_BRACE"||token.type==="COMMA");const isRightSeparator=(token)=>token&&(token.type==="RIGHT_BRACE"||token.type==="COMMA");function compileExprToArray(expr){const localVars=new Set();const tokens=tokenize(expr);let i=0;let stack=[];while(i<tokens.length){let token=tokens[i];let prevToken=tokens[i-1];let nextToken=tokens[i+1];let groupType=stack[stack.length-1];switch(token.type){case"LEFT_BRACE":case"LEFT_BRACKET":case"LEFT_PAREN":stack.push(token.type);break;case"RIGHT_BRACE":case"RIGHT_BRACKET":case"RIGHT_PAREN":stack.pop();}
let isVar=token.type==="SYMBOL"&&!RESERVED_WORDS.includes(token.value);if(token.type==="SYMBOL"&&!RESERVED_WORDS.includes(token.value)){if(prevToken){if(groupType==="LEFT_BRACE"&&isLeftSeparator(prevToken)&&isRightSeparator(nextToken)){tokens.splice(i+1,0,{type:"COLON",value:":"},{...token});nextToken=tokens[i+1];}
if(prevToken.type==="OPERATOR"&&prevToken.value==="."){isVar=false;}
else if(prevToken.type==="LEFT_BRACE"||prevToken.type==="COMMA"){if(nextToken&&nextToken.type==="COLON"){isVar=false;}}}}
if(token.type==="TEMPLATE_STRING"){token.value=token.replace((expr)=>compileExpr(expr));}
if(nextToken&&nextToken.type==="OPERATOR"&&nextToken.value==="=>"){if(token.type==="RIGHT_PAREN"){let j=i-1;while(j>0&&tokens[j].type!=="LEFT_PAREN"){if(tokens[j].type==="SYMBOL"&&tokens[j].originalValue){tokens[j].value=tokens[j].originalValue;localVars.add(tokens[j].value);}
j--;}}
else{localVars.add(token.value);}}
if(isVar){token.varName=token.value;if(!localVars.has(token.value)){token.originalValue=token.value;token.value=`ctx['${token.value}']`;}}
i++;}
for(const token of tokens){if(token.type==="SYMBOL"&&token.varName&&localVars.has(token.value)){token.originalValue=token.value;token.value=`_${token.value}`;token.isLocal=true;}}
return tokens;}
const paddedValues=new Map([["in "," in "]]);function compileExpr(expr){return compileExprToArray(expr).map((t)=>paddedValues.get(t.value)||t.value).join("");}
const INTERP_REGEXP=/\{\{.*?\}\}|\#\{.*?\}/g;function replaceDynamicParts(s,replacer){let matches=s.match(INTERP_REGEXP);if(matches&&matches[0].length===s.length){return`(${replacer(s.slice(2, matches[0][0] === "{" ? -2 : -1))})`;}
let r=s.replace(INTERP_REGEXP,(s)=>"${"+replacer(s.slice(2,s[0]==="{"?-2:-1))+"}");return"`"+r+"`";}
function interpolate(s){return replaceDynamicParts(s,compileExpr);}
const whitespaceRE=/\s+/g;const xmlDoc=document.implementation.createDocument(null,null,null);const MODS=new Set(["stop","capture","prevent","self","synthetic"]);let nextDataIds={};function generateId(prefix=""){nextDataIds[prefix]=(nextDataIds[prefix]||0)+1;return prefix+nextDataIds[prefix];}
function isProp(tag,key){switch(tag){case"input":return(key==="checked"||key==="indeterminate"||key==="value"||key==="readonly"||key==="readOnly"||key==="disabled");case"option":return key==="selected"||key==="disabled";case"textarea":return key==="value"||key==="readonly"||key==="readOnly"||key==="disabled";case"select":return key==="value"||key==="disabled";case"button":case"optgroup":return key==="disabled";}
return false;}
function toStringExpression(str){return`\`${str.replace(/\\/g, "\\\\").replace(/`/g,"\\`").replace(/\$\{/,"\\${")}\``;}
class BlockDescription{constructor(target,type){this.dynamicTagName=null;this.isRoot=false;this.hasDynamicChildren=false;this.children=[];this.data=[];this.childNumber=0;this.parentVar="";this.id=BlockDescription.nextBlockId++;this.varName="b"+this.id;this.blockName="block"+this.id;this.target=target;this.type=type;}
insertData(str,prefix="d"){const id=generateId(prefix);this.target.addLine(`let ${id} = ${str};`);return this.data.push(id)-1;}
insert(dom){if(this.currentDom){this.currentDom.appendChild(dom);}
else{this.dom=dom;}}
generateExpr(expr){if(this.type==="block"){const hasChildren=this.children.length;let params=this.data.length?`[${this.data.join(", ")}]`:hasChildren?"[]":"";if(hasChildren){params+=", ["+this.children.map((c)=>c.varName).join(", ")+"]";}
if(this.dynamicTagName){return`toggler(${this.dynamicTagName}, ${this.blockName}(${this.dynamicTagName})(${params}))`;}
return`${this.blockName}(${params})`;}
else if(this.type==="list"){return`list(c_block${this.id})`;}
return expr;}
asXmlString(){const t=xmlDoc.createElement("t");t.appendChild(this.dom);return t.innerHTML;}}
BlockDescription.nextBlockId=1;function createContext(parentCtx,params){return Object.assign({block:null,index:0,forceNewBlock:true,translate:parentCtx.translate,translationCtx:parentCtx.translationCtx,tKeyExpr:null,nameSpace:parentCtx.nameSpace,tModelSelectedExpr:parentCtx.tModelSelectedExpr,},params);}
class CodeTarget{constructor(name,on){this.indentLevel=0;this.loopLevel=0;this.code=[];this.hasRoot=false;this.hasCache=false;this.shouldProtectScope=false;this.hasRefWrapper=false;this.name=name;this.on=on||null;}
addLine(line,idx){const prefix=new Array(this.indentLevel+2).join("  ");if(idx===undefined){this.code.push(prefix+line);}
else{this.code.splice(idx,0,prefix+line);}}
generateCode(){let result=[];result.push(`function ${this.name}(ctx, node, key = "") {`);if(this.shouldProtectScope){result.push(`  ctx = Object.create(ctx);`);result.push(`  ctx[isBoundary] = 1`);}
if(this.hasRefWrapper){result.push(`  let refWrapper = makeRefWrapper(this.__owl__);`);}
if(this.hasCache){result.push(`  let cache = ctx.cache || {};`);result.push(`  let nextCache = ctx.cache = {};`);}
for(let line of this.code){result.push(line);}
if(!this.hasRoot){result.push(`return text('');`);}
result.push(`}`);return result.join("\n  ");}
currentKey(ctx){let key=this.loopLevel?`key${this.loopLevel}`:"key";if(ctx.tKeyExpr){key=`${ctx.tKeyExpr} + ${key}`;}
return key;}}
const TRANSLATABLE_ATTRS=["alt","aria-label","aria-placeholder","aria-roledescription","aria-valuetext","label","placeholder","title",];const translationRE=/^(\s*)([\s\S]+?)(\s*)$/;class CodeGenerator{constructor(ast,options){this.blocks=[];this.nextBlockId=1;this.isDebug=false;this.targets=[];this.target=new CodeTarget("template");this.translatableAttributes=TRANSLATABLE_ATTRS;this.staticDefs=[];this.slotNames=new Set();this.helpers=new Set();this.translateFn=options.translateFn||((s)=>s);if(options.translatableAttributes){const attrs=new Set(TRANSLATABLE_ATTRS);for(let attr of options.translatableAttributes){if(attr.startsWith("-")){attrs.delete(attr.slice(1));}
else{attrs.add(attr);}}
this.translatableAttributes=[...attrs];}
this.hasSafeContext=options.hasSafeContext||false;this.dev=options.dev||false;this.ast=ast;this.templateName=options.name;if(options.hasGlobalValues){this.helpers.add("__globals__");}}
generateCode(){const ast=this.ast;this.isDebug=ast.type===12;BlockDescription.nextBlockId=1;nextDataIds={};this.compileAST(ast,{block:null,index:0,forceNewBlock:false,isLast:true,translate:true,translationCtx:"",tKeyExpr:null,});let mainCode=[`  let { text, createBlock, list, multi, html, toggler, comment } = bdom;`];if(this.helpers.size){mainCode.push(`let { ${[...this.helpers].join(", ")} } = helpers;`);}
if(this.templateName){mainCode.push(`// Template name: "${this.templateName}"`);}
for(let{id,expr}of this.staticDefs){mainCode.push(`const ${id} = ${expr};`);}
if(this.blocks.length){mainCode.push(``);for(let block of this.blocks){if(block.dom){let xmlString=toStringExpression(block.asXmlString());if(block.dynamicTagName){xmlString=xmlString.replace(/^`<\w+/,`\`<\${tag || '${block.dom.nodeName}'}`);xmlString=xmlString.replace(/\w+>`$/,`\${tag || '${block.dom.nodeName}'}>\``);mainCode.push(`let ${block.blockName} = tag => createBlock(${xmlString});`);}
else{mainCode.push(`let ${block.blockName} = createBlock(${xmlString});`);}}}}
if(this.targets.length){for(let fn of this.targets){mainCode.push("");mainCode=mainCode.concat(fn.generateCode());}}
mainCode.push("");mainCode=mainCode.concat("return "+this.target.generateCode());const code=mainCode.join("\n  ");if(this.isDebug){const msg=`[Owl Debug]\n${code}`;console.log(msg);}
return code;}
compileInNewTarget(prefix,ast,ctx,on){const name=generateId(prefix);const initialTarget=this.target;const target=new CodeTarget(name,on);this.targets.push(target);this.target=target;this.compileAST(ast,createContext(ctx));this.target=initialTarget;return name;}
addLine(line,idx){this.target.addLine(line,idx);}
define(varName,expr){this.addLine(`const ${varName} = ${expr};`);}
insertAnchor(block,index=block.children.length){const tag=`block-child-${index}`;const anchor=xmlDoc.createElement(tag);block.insert(anchor);}
createBlock(parentBlock,type,ctx){const hasRoot=this.target.hasRoot;const block=new BlockDescription(this.target,type);if(!hasRoot){this.target.hasRoot=true;block.isRoot=true;}
if(parentBlock){parentBlock.children.push(block);if(parentBlock.type==="list"){block.parentVar=`c_block${parentBlock.id}`;}}
return block;}
insertBlock(expression,block,ctx){let blockExpr=block.generateExpr(expression);if(block.parentVar){let key=this.target.currentKey(ctx);this.helpers.add("withKey");this.addLine(`${block.parentVar}[${ctx.index}] = withKey(${blockExpr}, ${key});`);return;}
if(ctx.tKeyExpr){blockExpr=`toggler(${ctx.tKeyExpr}, ${blockExpr})`;}
if(block.isRoot){if(this.target.on){blockExpr=this.wrapWithEventCatcher(blockExpr,this.target.on);}
this.addLine(`return ${blockExpr};`);}
else{this.define(block.varName,blockExpr);}}
captureExpression(expr,forceCapture=false){if(!forceCapture&&!expr.includes("=>")){return compileExpr(expr);}
const tokens=compileExprToArray(expr);const mapping=new Map();return tokens.map((tok)=>{if(tok.varName&&!tok.isLocal){if(!mapping.has(tok.varName)){const varId=generateId("v");mapping.set(tok.varName,varId);this.define(varId,tok.value);}
tok.value=mapping.get(tok.varName);}
return tok.value;}).join("");}
translate(str,translationCtx){const match=translationRE.exec(str);return match[1]+this.translateFn(match[2],translationCtx)+match[3];}
compileAST(ast,ctx){switch(ast.type){case 1:return this.compileComment(ast,ctx);case 0:return this.compileText(ast,ctx);case 2:return this.compileTDomNode(ast,ctx);case 4:return this.compileTEsc(ast,ctx);case 8:return this.compileTOut(ast,ctx);case 5:return this.compileTIf(ast,ctx);case 9:return this.compileTForeach(ast,ctx);case 10:return this.compileTKey(ast,ctx);case 3:return this.compileMulti(ast,ctx);case 7:return this.compileTCall(ast,ctx);case 15:return this.compileTCallBlock(ast,ctx);case 6:return this.compileTSet(ast,ctx);case 11:return this.compileComponent(ast,ctx);case 12:return this.compileDebug(ast,ctx);case 13:return this.compileLog(ast,ctx);case 14:return this.compileTSlot(ast,ctx);case 16:return this.compileTTranslation(ast,ctx);case 17:return this.compileTTranslationContext(ast,ctx);case 18:return this.compileTPortal(ast,ctx);}}
compileDebug(ast,ctx){this.addLine(`debugger;`);if(ast.content){return this.compileAST(ast.content,ctx);}
return null;}
compileLog(ast,ctx){this.addLine(`console.log(${compileExpr(ast.expr)});`);if(ast.content){return this.compileAST(ast.content,ctx);}
return null;}
compileComment(ast,ctx){let{block,forceNewBlock}=ctx;const isNewBlock=!block||forceNewBlock;if(isNewBlock){block=this.createBlock(block,"comment",ctx);this.insertBlock(`comment(${toStringExpression(ast.value)})`,block,{...ctx,forceNewBlock:forceNewBlock&&!block,});}
else{const text=xmlDoc.createComment(ast.value);block.insert(text);}
return block.varName;}
compileText(ast,ctx){let{block,forceNewBlock}=ctx;let value=ast.value;if(value&&ctx.translate!==false){value=this.translate(value,ctx.translationCtx);}
if(!ctx.inPreTag){value=value.replace(whitespaceRE," ");}
if(!block||forceNewBlock){block=this.createBlock(block,"text",ctx);this.insertBlock(`text(${toStringExpression(value)})`,block,{...ctx,forceNewBlock:forceNewBlock&&!block,});}
else{const createFn=ast.type===0?xmlDoc.createTextNode:xmlDoc.createComment;block.insert(createFn.call(xmlDoc,value));}
return block.varName;}
generateHandlerCode(rawEvent,handler){const modifiers=rawEvent.split(".").slice(1).map((m)=>{if(!MODS.has(m)){throw new OwlError(`Unknown event modifier: '${m}'`);}
return`"${m}"`;});let modifiersCode="";if(modifiers.length){modifiersCode=`${modifiers.join(",")}, `;}
return`[${modifiersCode}${this.captureExpression(handler)}, ctx]`;}
compileTDomNode(ast,ctx){var _a;let{block,forceNewBlock}=ctx;const isNewBlock=!block||forceNewBlock||ast.dynamicTag!==null||ast.ns;let codeIdx=this.target.code.length;if(isNewBlock){if((ast.dynamicTag||ctx.tKeyExpr||ast.ns)&&ctx.block){this.insertAnchor(ctx.block);}
block=this.createBlock(block,"block",ctx);this.blocks.push(block);if(ast.dynamicTag){const tagExpr=generateId("tag");this.define(tagExpr,compileExpr(ast.dynamicTag));block.dynamicTagName=tagExpr;}}
const attrs={};for(let key in ast.attrs){let expr,attrName;if(key.startsWith("t-attf")){expr=interpolate(ast.attrs[key]);const idx=block.insertData(expr,"attr");attrName=key.slice(7);attrs["block-attribute-"+idx]=attrName;}
else if(key.startsWith("t-att")){attrName=key==="t-att"?null:key.slice(6);expr=compileExpr(ast.attrs[key]);if(attrName&&isProp(ast.tag,attrName)){if(attrName==="readonly"){attrName="readOnly";}
if(attrName==="value"){expr=`new String((${expr}) === 0 ? 0 : ((${expr}) || ""))`;}
else{expr=`new Boolean(${expr})`;}
const idx=block.insertData(expr,"prop");attrs[`block-property-${idx}`]=attrName;}
else{const idx=block.insertData(expr,"attr");if(key==="t-att"){attrs[`block-attributes`]=String(idx);}
else{attrs[`block-attribute-${idx}`]=attrName;}}}
else if(this.translatableAttributes.includes(key)){const attrTranslationCtx=((_a=ast.attrsTranslationCtx)===null||_a===void 0?void 0:_a[key])||ctx.translationCtx;attrs[key]=this.translateFn(ast.attrs[key],attrTranslationCtx);}
else{expr=`"${ast.attrs[key]}"`;attrName=key;attrs[key]=ast.attrs[key];}
if(attrName==="value"&&ctx.tModelSelectedExpr){let selectedId=block.insertData(`${ctx.tModelSelectedExpr} === ${expr}`,"attr");attrs[`block-attribute-${selectedId}`]="selected";}}
let tModelSelectedExpr;if(ast.model){const{hasDynamicChildren,baseExpr,expr,eventType,shouldNumberize,shouldTrim,targetAttr,specialInitTargetAttr,}=ast.model;const baseExpression=compileExpr(baseExpr);const bExprId=generateId("bExpr");this.define(bExprId,baseExpression);const expression=compileExpr(expr);const exprId=generateId("expr");this.define(exprId,expression);const fullExpression=`${bExprId}[${exprId}]`;let idx;if(specialInitTargetAttr){let targetExpr=targetAttr in attrs&&`'${attrs[targetAttr]}'`;if(!targetExpr&&ast.attrs){const dynamicTgExpr=ast.attrs[`t-att-${targetAttr}`];if(dynamicTgExpr){targetExpr=compileExpr(dynamicTgExpr);}}
idx=block.insertData(`${fullExpression} === ${targetExpr}`,"prop");attrs[`block-property-${idx}`]=specialInitTargetAttr;}
else if(hasDynamicChildren){const bValueId=generateId("bValue");tModelSelectedExpr=`${bValueId}`;this.define(tModelSelectedExpr,fullExpression);}
else{idx=block.insertData(`${fullExpression}`,"prop");attrs[`block-property-${idx}`]=targetAttr;}
this.helpers.add("toNumber");let valueCode=`ev.target.${targetAttr}`;valueCode=shouldTrim?`${valueCode}.trim()`:valueCode;valueCode=shouldNumberize?`toNumber(${valueCode})`:valueCode;const handler=`[(ev) => { ${fullExpression} = ${valueCode}; }]`;idx=block.insertData(handler,"hdlr");attrs[`block-handler-${idx}`]=eventType;}
for(let ev in ast.on){const name=this.generateHandlerCode(ev,ast.on[ev]);const idx=block.insertData(name,"hdlr");attrs[`block-handler-${idx}`]=ev;}
if(ast.ref){if(this.dev){this.helpers.add("makeRefWrapper");this.target.hasRefWrapper=true;}
const isDynamic=INTERP_REGEXP.test(ast.ref);let name=`\`${ast.ref}\``;if(isDynamic){name=replaceDynamicParts(ast.ref,(expr)=>this.captureExpression(expr,true));}
let setRefStr=`(el) => this.__owl__.setRef((${name}), el)`;if(this.dev){setRefStr=`refWrapper(${name}, ${setRefStr})`;}
const idx=block.insertData(setRefStr,"ref");attrs["block-ref"]=String(idx);}
const nameSpace=ast.ns||ctx.nameSpace;const dom=nameSpace?xmlDoc.createElementNS(nameSpace,ast.tag):xmlDoc.createElement(ast.tag);for(const[attr,val]of Object.entries(attrs)){if(!(attr==="class"&&val==="")){dom.setAttribute(attr,val);}}
block.insert(dom);if(ast.content.length){const initialDom=block.currentDom;block.currentDom=dom;const children=ast.content;for(let i=0;i<children.length;i++){const child=ast.content[i];const subCtx=createContext(ctx,{block,index:block.childNumber,forceNewBlock:false,isLast:ctx.isLast&&i===children.length-1,tKeyExpr:ctx.tKeyExpr,nameSpace,tModelSelectedExpr,inPreTag:ctx.inPreTag||ast.tag==="pre",});this.compileAST(child,subCtx);}
block.currentDom=initialDom;}
if(isNewBlock){this.insertBlock(`${block.blockName}(ddd)`,block,ctx);if(block.children.length&&block.hasDynamicChildren){const code=this.target.code;const children=block.children.slice();let current=children.shift();for(let i=codeIdx;i<code.length;i++){if(code[i].trimStart().startsWith(`const ${current.varName} `)){code[i]=code[i].replace(`const ${current.varName}`,current.varName);current=children.shift();if(!current)
break;}}
this.addLine(`let ${block.children.map((c) => c.varName).join(", ")};`,codeIdx);}}
return block.varName;}
compileTEsc(ast,ctx){let{block,forceNewBlock}=ctx;let expr;if(ast.expr==="0"){this.helpers.add("zero");expr=`ctx[zero]`;}
else{expr=compileExpr(ast.expr);if(ast.defaultValue){this.helpers.add("withDefault");expr=`withDefault(${expr}, ${toStringExpression(ast.defaultValue)})`;}}
if(!block||forceNewBlock){block=this.createBlock(block,"text",ctx);this.insertBlock(`text(${expr})`,block,{...ctx,forceNewBlock:forceNewBlock&&!block});}
else{const idx=block.insertData(expr,"txt");const text=xmlDoc.createElement(`block-text-${idx}`);block.insert(text);}
return block.varName;}
compileTOut(ast,ctx){let{block}=ctx;if(block){this.insertAnchor(block);}
block=this.createBlock(block,"html",ctx);let blockStr;if(ast.expr==="0"){this.helpers.add("zero");blockStr=`ctx[zero]`;}
else if(ast.body){let bodyValue=null;bodyValue=BlockDescription.nextBlockId;const subCtx=createContext(ctx);this.compileAST({type:3,content:ast.body},subCtx);this.helpers.add("safeOutput");blockStr=`safeOutput(${compileExpr(ast.expr)}, b${bodyValue})`;}
else{this.helpers.add("safeOutput");blockStr=`safeOutput(${compileExpr(ast.expr)})`;}
this.insertBlock(blockStr,block,ctx);return block.varName;}
compileTIfBranch(content,block,ctx){this.target.indentLevel++;let childN=block.children.length;this.compileAST(content,createContext(ctx,{block,index:ctx.index}));if(block.children.length>childN){this.insertAnchor(block,childN);}
this.target.indentLevel--;}
compileTIf(ast,ctx,nextNode){let{block,forceNewBlock}=ctx;const codeIdx=this.target.code.length;const isNewBlock=!block||(block.type!=="multi"&&forceNewBlock);if(block){block.hasDynamicChildren=true;}
if(!block||(block.type!=="multi"&&forceNewBlock)){block=this.createBlock(block,"multi",ctx);}
this.addLine(`if (${compileExpr(ast.condition)}) {`);this.compileTIfBranch(ast.content,block,ctx);if(ast.tElif){for(let clause of ast.tElif){this.addLine(`} else if (${compileExpr(clause.condition)}) {`);this.compileTIfBranch(clause.content,block,ctx);}}
if(ast.tElse){this.addLine(`} else {`);this.compileTIfBranch(ast.tElse,block,ctx);}
this.addLine("}");if(isNewBlock){if(block.children.length){const code=this.target.code;const children=block.children.slice();let current=children.shift();for(let i=codeIdx;i<code.length;i++){if(code[i].trimStart().startsWith(`const ${current.varName} `)){code[i]=code[i].replace(`const ${current.varName}`,current.varName);current=children.shift();if(!current)
break;}}
this.addLine(`let ${block.children.map((c) => c.varName).join(", ")};`,codeIdx);}
const args=block.children.map((c)=>c.varName).join(", ");this.insertBlock(`multi([${args}])`,block,ctx);}
return block.varName;}
compileTForeach(ast,ctx){let{block}=ctx;if(block){this.insertAnchor(block);}
block=this.createBlock(block,"list",ctx);this.target.loopLevel++;const loopVar=`i${this.target.loopLevel}`;this.addLine(`ctx = Object.create(ctx);`);const vals=`v_block${block.id}`;const keys=`k_block${block.id}`;const l=`l_block${block.id}`;const c=`c_block${block.id}`;this.helpers.add("prepareList");this.define(`[${keys}, ${vals}, ${l}, ${c}]`,`prepareList(${compileExpr(ast.collection)});`);if(this.dev){this.define(`keys${block.id}`,`new Set()`);}
this.addLine(`for (let ${loopVar} = 0; ${loopVar} < ${l}; ${loopVar}++) {`);this.target.indentLevel++;this.addLine(`ctx[\`${ast.elem}\`] = ${keys}[${loopVar}];`);if(!ast.hasNoFirst){this.addLine(`ctx[\`${ast.elem}_first\`] = ${loopVar} === 0;`);}
if(!ast.hasNoLast){this.addLine(`ctx[\`${ast.elem}_last\`] = ${loopVar} === ${keys}.length - 1;`);}
if(!ast.hasNoIndex){this.addLine(`ctx[\`${ast.elem}_index\`] = ${loopVar};`);}
if(!ast.hasNoValue){this.addLine(`ctx[\`${ast.elem}_value\`] = ${vals}[${loopVar}];`);}
this.define(`key${this.target.loopLevel}`,ast.key?compileExpr(ast.key):loopVar);if(this.dev){this.helpers.add("OwlError");this.addLine(`if (keys${block.id}.has(String(key${this.target.loopLevel}))) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);this.addLine(`keys${block.id}.add(String(key${this.target.loopLevel}));`);}
let id;if(ast.memo){this.target.hasCache=true;id=generateId();this.define(`memo${id}`,compileExpr(ast.memo));this.define(`vnode${id}`,`cache[key${this.target.loopLevel}];`);this.addLine(`if (vnode${id}) {`);this.target.indentLevel++;this.addLine(`if (shallowEqual(vnode${id}.memo, memo${id})) {`);this.target.indentLevel++;this.addLine(`${c}[${loopVar}] = vnode${id};`);this.addLine(`nextCache[key${this.target.loopLevel}] = vnode${id};`);this.addLine(`continue;`);this.target.indentLevel--;this.addLine("}");this.target.indentLevel--;this.addLine("}");}
const subCtx=createContext(ctx,{block,index:loopVar});this.compileAST(ast.body,subCtx);if(ast.memo){this.addLine(`nextCache[key${this.target.loopLevel}] = Object.assign(${c}[${loopVar}], {memo: memo${id}});`);}
this.target.indentLevel--;this.target.loopLevel--;this.addLine(`}`);if(!ctx.isLast){this.addLine(`ctx = ctx.__proto__;`);}
this.insertBlock("l",block,ctx);return block.varName;}
compileTKey(ast,ctx){const tKeyExpr=generateId("tKey_");this.define(tKeyExpr,compileExpr(ast.expr));ctx=createContext(ctx,{tKeyExpr,block:ctx.block,index:ctx.index,});return this.compileAST(ast.content,ctx);}
compileMulti(ast,ctx){let{block,forceNewBlock}=ctx;const isNewBlock=!block||forceNewBlock;let codeIdx=this.target.code.length;if(isNewBlock){const n=ast.content.filter((c)=>!c.hasNoRepresentation).length;let result=null;if(n<=1){for(let child of ast.content){const blockName=this.compileAST(child,ctx);result=result||blockName;}
return result;}
block=this.createBlock(block,"multi",ctx);}
let index=0;for(let i=0,l=ast.content.length;i<l;i++){const child=ast.content[i];const forceNewBlock=!child.hasNoRepresentation;const subCtx=createContext(ctx,{block,index,forceNewBlock,isLast:ctx.isLast&&i===l-1,});this.compileAST(child,subCtx);if(forceNewBlock){index++;}}
if(isNewBlock){if(block.hasDynamicChildren&&block.children.length){const code=this.target.code;const children=block.children.slice();let current=children.shift();for(let i=codeIdx;i<code.length;i++){if(code[i].trimStart().startsWith(`const ${current.varName} `)){code[i]=code[i].replace(`const ${current.varName}`,current.varName);current=children.shift();if(!current)
break;}}
this.addLine(`let ${block.children.map((c) => c.varName).join(", ")};`,codeIdx);}
const args=block.children.map((c)=>c.varName).join(", ");this.insertBlock(`multi([${args}])`,block,ctx);}
return block.varName;}
compileTCall(ast,ctx){let{block,forceNewBlock}=ctx;let ctxVar=ctx.ctxVar||"ctx";if(ast.context){ctxVar=generateId("ctx");this.addLine(`let ${ctxVar} = ${compileExpr(ast.context)};`);}
const isDynamic=INTERP_REGEXP.test(ast.name);const subTemplate=isDynamic?interpolate(ast.name):"`"+ast.name+"`";if(block&&!forceNewBlock){this.insertAnchor(block);}
block=this.createBlock(block,"multi",ctx);if(ast.body){this.addLine(`${ctxVar} = Object.create(${ctxVar});`);this.addLine(`${ctxVar}[isBoundary] = 1;`);this.helpers.add("isBoundary");const subCtx=createContext(ctx,{ctxVar});const bl=this.compileMulti({type:3,content:ast.body},subCtx);if(bl){this.helpers.add("zero");this.addLine(`${ctxVar}[zero] = ${bl};`);}}
const key=this.generateComponentKey();if(isDynamic){const templateVar=generateId("template");if(!this.staticDefs.find((d)=>d.id==="call")){this.staticDefs.push({id:"call",expr:`app.callTemplate.bind(app)`});}
this.define(templateVar,subTemplate);this.insertBlock(`call(this, ${templateVar}, ${ctxVar}, node, ${key})`,block,{...ctx,forceNewBlock:!block,});}
else{const id=generateId(`callTemplate_`);this.staticDefs.push({id,expr:`app.getTemplate(${subTemplate})`});this.insertBlock(`${id}.call(this, ${ctxVar}, node, ${key})`,block,{...ctx,forceNewBlock:!block,});}
if(ast.body&&!ctx.isLast){this.addLine(`${ctxVar} = ${ctxVar}.__proto__;`);}
return block.varName;}
compileTCallBlock(ast,ctx){let{block,forceNewBlock}=ctx;if(block){if(!forceNewBlock){this.insertAnchor(block);}}
block=this.createBlock(block,"multi",ctx);this.insertBlock(compileExpr(ast.name),block,{...ctx,forceNewBlock:!block});return block.varName;}
compileTSet(ast,ctx){this.target.shouldProtectScope=true;this.helpers.add("isBoundary").add("withDefault");const expr=ast.value?compileExpr(ast.value||""):"null";if(ast.body){this.helpers.add("LazyValue");const bodyAst={type:3,content:ast.body};const name=this.compileInNewTarget("value",bodyAst,ctx);let key=this.target.currentKey(ctx);let value=`new LazyValue(${name}, ctx, this, node, ${key})`;value=ast.value?(value?`withDefault(${expr}, ${value})`:expr):value;this.addLine(`ctx[\`${ast.name}\`] = ${value};`);}
else{let value;if(ast.defaultValue){const defaultValue=toStringExpression(ctx.translate?this.translate(ast.defaultValue,ctx.translationCtx):ast.defaultValue);if(ast.value){value=`withDefault(${expr}, ${defaultValue})`;}
else{value=defaultValue;}}
else{value=expr;}
this.helpers.add("setContextValue");this.addLine(`setContextValue(${ctx.ctxVar || "ctx"}, "${ast.name}", ${value});`);}
return null;}
generateComponentKey(currentKey="key"){const parts=[generateId("__")];for(let i=0;i<this.target.loopLevel;i++){parts.push(`\${key${i + 1}}`);}
return`${currentKey} + \`${parts.join("__")}\``;}
formatProp(name,value,attrsTranslationCtx,translationCtx){if(name.endsWith(".translate")){const attrTranslationCtx=(attrsTranslationCtx===null||attrsTranslationCtx===void 0?void 0:attrsTranslationCtx[name])||translationCtx;value=toStringExpression(this.translateFn(value,attrTranslationCtx));}
else{value=this.captureExpression(value);}
if(name.includes(".")){let[_name,suffix]=name.split(".");name=_name;switch(suffix){case"bind":value=`(${value}).bind(this)`;break;case"alike":case"translate":break;default:throw new OwlError(`Invalid prop suffix: ${suffix}`);}}
name=/^[a-z_]+$/i.test(name)?name:`'${name}'`;return`${name}: ${value || undefined}`;}
formatPropObject(obj,attrsTranslationCtx,translationCtx){return Object.entries(obj).map(([k,v])=>this.formatProp(k,v,attrsTranslationCtx,translationCtx));}
getPropString(props,dynProps){let propString=`{${props.join(",")}}`;if(dynProps){propString=`Object.assign({}, ${compileExpr(dynProps)}${props.length ? ", " + propString : ""})`;}
return propString;}
compileComponent(ast,ctx){let{block}=ctx;const hasSlotsProp="slots"in(ast.props||{});const props=ast.props?this.formatPropObject(ast.props,ast.propsTranslationCtx,ctx.translationCtx):[];let slotDef="";if(ast.slots){let ctxStr="ctx";if(this.target.loopLevel||!this.hasSafeContext){ctxStr=generateId("ctx");this.helpers.add("capture");this.define(ctxStr,`capture(ctx)`);}
let slotStr=[];for(let slotName in ast.slots){const slotAst=ast.slots[slotName];const params=[];if(slotAst.content){const name=this.compileInNewTarget("slot",slotAst.content,ctx,slotAst.on);params.push(`__render: ${name}.bind(this), __ctx: ${ctxStr}`);}
const scope=ast.slots[slotName].scope;if(scope){params.push(`__scope: "${scope}"`);}
if(ast.slots[slotName].attrs){params.push(...this.formatPropObject(ast.slots[slotName].attrs,ast.slots[slotName].attrsTranslationCtx,ctx.translationCtx));}
const slotInfo=`{${params.join(", ")}}`;slotStr.push(`'${slotName}': ${slotInfo}`);}
slotDef=`{${slotStr.join(", ")}}`;}
if(slotDef&&!(ast.dynamicProps||hasSlotsProp)){this.helpers.add("markRaw");props.push(`slots: markRaw(${slotDef})`);}
let propString=this.getPropString(props,ast.dynamicProps);let propVar;if((slotDef&&(ast.dynamicProps||hasSlotsProp))||this.dev){propVar=generateId("props");this.define(propVar,propString);propString=propVar;}
if(slotDef&&(ast.dynamicProps||hasSlotsProp)){this.helpers.add("markRaw");this.addLine(`${propVar}.slots = markRaw(Object.assign(${slotDef}, ${propVar}.slots))`);}
let expr;if(ast.isDynamic){expr=generateId("Comp");this.define(expr,compileExpr(ast.name));}
else{expr=`\`${ast.name}\``;}
if(this.dev){this.addLine(`helpers.validateProps(${expr}, ${propVar}, this);`);}
if(block&&(ctx.forceNewBlock===false||ctx.tKeyExpr)){this.insertAnchor(block);}
let keyArg=this.generateComponentKey();if(ctx.tKeyExpr){keyArg=`${ctx.tKeyExpr} + ${keyArg}`;}
let id=generateId("comp");const propList=[];for(let p in ast.props||{}){let[name,suffix]=p.split(".");if(!suffix){propList.push(`"${name}"`);}}
this.staticDefs.push({id,expr:`app.createComponent(${ast.isDynamic ? null : expr}, ${!ast.isDynamic}, ${!!ast.slots}, ${!!ast.dynamicProps}, [${propList}])`,});if(ast.isDynamic){keyArg=`(${expr}).name + ${keyArg}`;}
let blockExpr=`${id}(${propString}, ${keyArg}, node, this, ${ast.isDynamic ? expr : null})`;if(ast.isDynamic){blockExpr=`toggler(${expr}, ${blockExpr})`;}
if(ast.on){blockExpr=this.wrapWithEventCatcher(blockExpr,ast.on);}
block=this.createBlock(block,"multi",ctx);this.insertBlock(blockExpr,block,ctx);return block.varName;}
wrapWithEventCatcher(expr,on){this.helpers.add("createCatcher");let name=generateId("catcher");let spec={};let handlers=[];for(let ev in on){let handlerId=generateId("hdlr");let idx=handlers.push(handlerId)-1;spec[ev]=idx;const handler=this.generateHandlerCode(ev,on[ev]);this.define(handlerId,handler);}
this.staticDefs.push({id:name,expr:`createCatcher(${JSON.stringify(spec)})`});return`${name}(${expr}, [${handlers.join(",")}])`;}
compileTSlot(ast,ctx){this.helpers.add("callSlot");let{block}=ctx;let blockString;let slotName;let dynamic=false;let isMultiple=false;if(ast.name.match(INTERP_REGEXP)){dynamic=true;isMultiple=true;slotName=interpolate(ast.name);}
else{slotName="'"+ast.name+"'";isMultiple=isMultiple||this.slotNames.has(ast.name);this.slotNames.add(ast.name);}
const attrs={...ast.attrs};const dynProps=attrs["t-props"];delete attrs["t-props"];let key=this.target.loopLevel?`key${this.target.loopLevel}`:"key";if(isMultiple){key=this.generateComponentKey(key);}
const props=ast.attrs?this.formatPropObject(attrs,ast.attrsTranslationCtx,ctx.translationCtx):[];const scope=this.getPropString(props,dynProps);if(ast.defaultContent){const name=this.compileInNewTarget("defaultContent",ast.defaultContent,ctx);blockString=`callSlot(ctx, node, ${key}, ${slotName}, ${dynamic}, ${scope}, ${name}.bind(this))`;}
else{if(dynamic){let name=generateId("slot");this.define(name,slotName);blockString=`toggler(${name}, callSlot(ctx, node, ${key}, ${name}, ${dynamic}, ${scope}))`;}
else{blockString=`callSlot(ctx, node, ${key}, ${slotName}, ${dynamic}, ${scope})`;}}
if(ast.on){blockString=this.wrapWithEventCatcher(blockString,ast.on);}
if(block){this.insertAnchor(block);}
block=this.createBlock(block,"multi",ctx);this.insertBlock(blockString,block,{...ctx,forceNewBlock:false});return block.varName;}
compileTTranslation(ast,ctx){if(ast.content){return this.compileAST(ast.content,Object.assign({},ctx,{translate:false}));}
return null;}
compileTTranslationContext(ast,ctx){if(ast.content){return this.compileAST(ast.content,Object.assign({},ctx,{translationCtx:ast.translationCtx}));}
return null;}
compileTPortal(ast,ctx){if(!this.staticDefs.find((d)=>d.id==="Portal")){this.staticDefs.push({id:"Portal",expr:`app.Portal`});}
let{block}=ctx;const name=this.compileInNewTarget("slot",ast.content,ctx);let ctxStr="ctx";if(this.target.loopLevel||!this.hasSafeContext){ctxStr=generateId("ctx");this.helpers.add("capture");this.define(ctxStr,`capture(ctx)`);}
let id=generateId("comp");this.staticDefs.push({id,expr:`app.createComponent(null, false, true, false, false)`,});const target=compileExpr(ast.target);const key=this.generateComponentKey();const blockString=`${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, ${key}, node, ctx, Portal)`;if(block){this.insertAnchor(block);}
block=this.createBlock(block,"multi",ctx);this.insertBlock(blockString,block,{...ctx,forceNewBlock:false});return block.varName;}}
const cache=new WeakMap();function parse(xml,customDir){const ctx={inPreTag:false,customDirectives:customDir,};if(typeof xml==="string"){const elem=parseXML(`<t>${xml}</t>`).firstChild;return _parse(elem,ctx);}
let ast=cache.get(xml);if(!ast){ast=_parse(xml.cloneNode(true),ctx);cache.set(xml,ast);}
return ast;}
function _parse(xml,ctx){normalizeXML(xml);return parseNode(xml,ctx)||{type:0,value:""};}
function parseNode(node,ctx){if(!(node instanceof Element)){return parseTextCommentNode(node,ctx);}
return(parseTCustom(node,ctx)||parseTDebugLog(node,ctx)||parseTForEach(node,ctx)||parseTIf(node,ctx)||parseTPortal(node,ctx)||parseTCall(node,ctx)||parseTCallBlock(node)||parseTTranslation(node,ctx)||parseTTranslationContext(node,ctx)||parseTKey(node,ctx)||parseTEscNode(node,ctx)||parseTOutNode(node,ctx)||parseTSlot(node,ctx)||parseComponent(node,ctx)||parseDOMNode(node,ctx)||parseTSetNode(node,ctx)||parseTNode(node,ctx));}
function parseTNode(node,ctx){if(node.tagName!=="t"){return null;}
return parseChildNodes(node,ctx);}
const lineBreakRE=/[\r\n]/;function parseTextCommentNode(node,ctx){if(node.nodeType===Node.TEXT_NODE){let value=node.textContent||"";if(!ctx.inPreTag&&lineBreakRE.test(value)&&!value.trim()){return null;}
return{type:0,value};}
else if(node.nodeType===Node.COMMENT_NODE){return{type:1,value:node.textContent||""};}
return null;}
function parseTCustom(node,ctx){if(!ctx.customDirectives){return null;}
const nodeAttrsNames=node.getAttributeNames();for(let attr of nodeAttrsNames){if(attr==="t-custom"||attr==="t-custom-"){throw new OwlError("Missing custom directive name with t-custom directive");}
if(attr.startsWith("t-custom-")){const directiveName=attr.split(".")[0].slice(9);const customDirective=ctx.customDirectives[directiveName];if(!customDirective){throw new OwlError(`Custom directive "${directiveName}" is not defined`);}
const value=node.getAttribute(attr);const modifiers=attr.split(".").slice(1);node.removeAttribute(attr);try{customDirective(node,value,modifiers);}
catch(error){throw new OwlError(`Custom directive "${directiveName}" throw the following error: ${error}`);}
return parseNode(node,ctx);}}
return null;}
function parseTDebugLog(node,ctx){if(node.hasAttribute("t-debug")){node.removeAttribute("t-debug");const content=parseNode(node,ctx);const ast={type:12,content,};if(content===null||content===void 0?void 0:content.hasNoRepresentation){ast.hasNoRepresentation=true;}
return ast;}
if(node.hasAttribute("t-log")){const expr=node.getAttribute("t-log");node.removeAttribute("t-log");const content=parseNode(node,ctx);const ast={type:13,expr,content,};if(content===null||content===void 0?void 0:content.hasNoRepresentation){ast.hasNoRepresentation=true;}
return ast;}
return null;}
const hasDotAtTheEnd=/\.[\w_]+\s*$/;const hasBracketsAtTheEnd=/\[[^\[]+\]\s*$/;const ROOT_SVG_TAGS=new Set(["svg","g","path"]);function parseDOMNode(node,ctx){const{tagName}=node;const dynamicTag=node.getAttribute("t-tag");node.removeAttribute("t-tag");if(tagName==="t"&&!dynamicTag){return null;}
if(tagName.startsWith("block-")){throw new OwlError(`Invalid tag name: '${tagName}'`);}
ctx=Object.assign({},ctx);if(tagName==="pre"){ctx.inPreTag=true;}
let ns=!ctx.nameSpace&&ROOT_SVG_TAGS.has(tagName)?"http://www.w3.org/2000/svg":null;const ref=node.getAttribute("t-ref");node.removeAttribute("t-ref");const nodeAttrsNames=node.getAttributeNames();let attrs=null;let attrsTranslationCtx=null;let on=null;let model=null;for(let attr of nodeAttrsNames){const value=node.getAttribute(attr);if(attr==="t-on"||attr==="t-on-"){throw new OwlError("Missing event name with t-on directive");}
if(attr.startsWith("t-on-")){on=on||{};on[attr.slice(5)]=value;}
else if(attr.startsWith("t-model")){if(!["input","select","textarea"].includes(tagName)){throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");}
let baseExpr,expr;if(hasDotAtTheEnd.test(value)){const index=value.lastIndexOf(".");baseExpr=value.slice(0,index);expr=`'${value.slice(index + 1)}'`;}
else if(hasBracketsAtTheEnd.test(value)){const index=value.lastIndexOf("[");baseExpr=value.slice(0,index);expr=value.slice(index+1,-1);}
else{throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);}
const typeAttr=node.getAttribute("type");const isInput=tagName==="input";const isSelect=tagName==="select";const isCheckboxInput=isInput&&typeAttr==="checkbox";const isRadioInput=isInput&&typeAttr==="radio";const hasTrimMod=attr.includes(".trim");const hasLazyMod=hasTrimMod||attr.includes(".lazy");const hasNumberMod=attr.includes(".number");const eventType=isRadioInput?"click":isSelect||hasLazyMod?"change":"input";model={baseExpr,expr,targetAttr:isCheckboxInput?"checked":"value",specialInitTargetAttr:isRadioInput?"checked":null,eventType,hasDynamicChildren:false,shouldTrim:hasTrimMod,shouldNumberize:hasNumberMod,};if(isSelect){ctx=Object.assign({},ctx);ctx.tModelInfo=model;}}
else if(attr.startsWith("block-")){throw new OwlError(`Invalid attribute: '${attr}'`);}
else if(attr==="xmlns"){ns=value;}
else if(attr.startsWith("t-translation-context-")){const attrName=attr.slice(22);attrsTranslationCtx=attrsTranslationCtx||{};attrsTranslationCtx[attrName]=value;}
else if(attr!=="t-name"){if(attr.startsWith("t-")&&!attr.startsWith("t-att")){throw new OwlError(`Unknown QWeb directive: '${attr}'`);}
const tModel=ctx.tModelInfo;if(tModel&&["t-att-value","t-attf-value"].includes(attr)){tModel.hasDynamicChildren=true;}
attrs=attrs||{};attrs[attr]=value;}}
if(ns){ctx.nameSpace=ns;}
const children=parseChildren(node,ctx);return{type:2,tag:tagName,dynamicTag,attrs,attrsTranslationCtx,on,ref,content:children,model,ns,};}
function parseTEscNode(node,ctx){if(!node.hasAttribute("t-esc")){return null;}
const escValue=node.getAttribute("t-esc");node.removeAttribute("t-esc");const tesc={type:4,expr:escValue,defaultValue:node.textContent||"",};let ref=node.getAttribute("t-ref");node.removeAttribute("t-ref");const ast=parseNode(node,ctx);if(!ast){return tesc;}
if(ast.type===2){return{...ast,ref,content:[tesc],};}
return tesc;}
function parseTOutNode(node,ctx){if(!node.hasAttribute("t-out")&&!node.hasAttribute("t-raw")){return null;}
if(node.hasAttribute("t-raw")){console.warn(`t-raw has been deprecated in favor of t-out. If the value to render is not wrapped by the "markup" function, it will be escaped`);}
const expr=(node.getAttribute("t-out")||node.getAttribute("t-raw"));node.removeAttribute("t-out");node.removeAttribute("t-raw");const tOut={type:8,expr,body:null};const ref=node.getAttribute("t-ref");node.removeAttribute("t-ref");const ast=parseNode(node,ctx);if(!ast){return tOut;}
if(ast.type===2){tOut.body=ast.content.length?ast.content:null;return{...ast,ref,content:[tOut],};}
return tOut;}
function parseTForEach(node,ctx){if(!node.hasAttribute("t-foreach")){return null;}
const html=node.outerHTML;const collection=node.getAttribute("t-foreach");node.removeAttribute("t-foreach");const elem=node.getAttribute("t-as")||"";node.removeAttribute("t-as");const key=node.getAttribute("t-key");if(!key){throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);}
node.removeAttribute("t-key");const memo=node.getAttribute("t-memo")||"";node.removeAttribute("t-memo");const body=parseNode(node,ctx);if(!body){return null;}
const hasNoTCall=!html.includes("t-call");const hasNoFirst=hasNoTCall&&!html.includes(`${elem}_first`);const hasNoLast=hasNoTCall&&!html.includes(`${elem}_last`);const hasNoIndex=hasNoTCall&&!html.includes(`${elem}_index`);const hasNoValue=hasNoTCall&&!html.includes(`${elem}_value`);return{type:9,collection,elem,body,memo,key,hasNoFirst,hasNoLast,hasNoIndex,hasNoValue,};}
function parseTKey(node,ctx){if(!node.hasAttribute("t-key")){return null;}
const key=node.getAttribute("t-key");node.removeAttribute("t-key");const content=parseNode(node,ctx);if(!content){return null;}
const ast={type:10,expr:key,content,};if(content.hasNoRepresentation){ast.hasNoRepresentation=true;}
return ast;}
function parseTCall(node,ctx){if(!node.hasAttribute("t-call")){return null;}
const subTemplate=node.getAttribute("t-call");const context=node.getAttribute("t-call-context");node.removeAttribute("t-call");node.removeAttribute("t-call-context");if(node.tagName!=="t"){const ast=parseNode(node,ctx);const tcall={type:7,name:subTemplate,body:null,context};if(ast&&ast.type===2){ast.content=[tcall];return ast;}
if(ast&&ast.type===11){return{...ast,slots:{default:{content:tcall,scope:null,on:null,attrs:null,attrsTranslationCtx:null,},},};}}
const body=parseChildren(node,ctx);return{type:7,name:subTemplate,body:body.length?body:null,context,};}
function parseTCallBlock(node,ctx){if(!node.hasAttribute("t-call-block")){return null;}
const name=node.getAttribute("t-call-block");return{type:15,name,};}
function parseTIf(node,ctx){if(!node.hasAttribute("t-if")){return null;}
const condition=node.getAttribute("t-if");node.removeAttribute("t-if");const content=parseNode(node,ctx)||{type:0,value:""};let nextElement=node.nextElementSibling;const tElifs=[];while(nextElement&&nextElement.hasAttribute("t-elif")){const condition=nextElement.getAttribute("t-elif");nextElement.removeAttribute("t-elif");const tElif=parseNode(nextElement,ctx);const next=nextElement.nextElementSibling;nextElement.remove();nextElement=next;if(tElif){tElifs.push({condition,content:tElif});}}
let tElse=null;if(nextElement&&nextElement.hasAttribute("t-else")){nextElement.removeAttribute("t-else");tElse=parseNode(nextElement,ctx);nextElement.remove();}
return{type:5,condition,content,tElif:tElifs.length?tElifs:null,tElse,};}
function parseTSetNode(node,ctx){if(!node.hasAttribute("t-set")){return null;}
const name=node.getAttribute("t-set");const value=node.getAttribute("t-value")||null;const defaultValue=node.innerHTML===node.textContent?node.textContent||null:null;let body=null;if(node.textContent!==node.innerHTML){body=parseChildren(node,ctx);}
return{type:6,name,value,defaultValue,body,hasNoRepresentation:true};}
const directiveErrorMap=new Map([["t-ref","t-ref is no longer supported on components. Consider exposing only the public part of the component's API through a callback prop.",],["t-att","t-att makes no sense on component: props are already treated as expressions"],["t-attf","t-attf is not supported on components: use template strings for string interpolation in props",],]);function parseComponent(node,ctx){let name=node.tagName;const firstLetter=name[0];let isDynamic=node.hasAttribute("t-component");if(isDynamic&&name!=="t"){throw new OwlError(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);}
if(!(firstLetter===firstLetter.toUpperCase()||isDynamic)){return null;}
if(isDynamic){name=node.getAttribute("t-component");node.removeAttribute("t-component");}
const dynamicProps=node.getAttribute("t-props");node.removeAttribute("t-props");const defaultSlotScope=node.getAttribute("t-slot-scope");node.removeAttribute("t-slot-scope");let on=null;let props=null;let propsTranslationCtx=null;for(let name of node.getAttributeNames()){const value=node.getAttribute(name);if(name.startsWith("t-translation-context-")){const attrName=name.slice(22);propsTranslationCtx=propsTranslationCtx||{};propsTranslationCtx[attrName]=value;}
else if(name.startsWith("t-")){if(name.startsWith("t-on-")){on=on||{};on[name.slice(5)]=value;}
else{const message=directiveErrorMap.get(name.split("-").slice(0,2).join("-"));throw new OwlError(message||`unsupported directive on Component: ${name}`);}}
else{props=props||{};props[name]=value;}}
let slots=null;if(node.hasChildNodes()){const clone=node.cloneNode(true);const slotNodes=Array.from(clone.querySelectorAll("[t-set-slot]"));for(let slotNode of slotNodes){if(slotNode.tagName!=="t"){throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);}
const name=slotNode.getAttribute("t-set-slot");let el=slotNode.parentElement;let isInSubComponent=false;while(el&&el!==clone){if(el.hasAttribute("t-component")||el.tagName[0]===el.tagName[0].toUpperCase()){isInSubComponent=true;break;}
el=el.parentElement;}
if(isInSubComponent||!el){continue;}
slotNode.removeAttribute("t-set-slot");slotNode.remove();const slotAst=parseNode(slotNode,ctx);let on=null;let attrs=null;let attrsTranslationCtx=null;let scope=null;for(let attributeName of slotNode.getAttributeNames()){const value=slotNode.getAttribute(attributeName);if(attributeName==="t-slot-scope"){scope=value;continue;}
else if(attributeName.startsWith("t-translation-context-")){const attrName=attributeName.slice(22);attrsTranslationCtx=attrsTranslationCtx||{};attrsTranslationCtx[attrName]=value;}
else if(attributeName.startsWith("t-on-")){on=on||{};on[attributeName.slice(5)]=value;}
else{attrs=attrs||{};attrs[attributeName]=value;}}
slots=slots||{};slots[name]={content:slotAst,on,attrs,attrsTranslationCtx,scope};}
const defaultContent=parseChildNodes(clone,ctx);slots=slots||{};if(defaultContent&&!slots.default){slots.default={content:defaultContent,on,attrs:null,attrsTranslationCtx:null,scope:defaultSlotScope,};}}
return{type:11,name,isDynamic,dynamicProps,props,propsTranslationCtx,slots,on,};}
function parseTSlot(node,ctx){if(!node.hasAttribute("t-slot")){return null;}
const name=node.getAttribute("t-slot");node.removeAttribute("t-slot");let attrs=null;let attrsTranslationCtx=null;let on=null;for(let attributeName of node.getAttributeNames()){const value=node.getAttribute(attributeName);if(attributeName.startsWith("t-on-")){on=on||{};on[attributeName.slice(5)]=value;}
else if(attributeName.startsWith("t-translation-context-")){const attrName=attributeName.slice(22);attrsTranslationCtx=attrsTranslationCtx||{};attrsTranslationCtx[attrName]=value;}
else{attrs=attrs||{};attrs[attributeName]=value;}}
return{type:14,name,attrs,attrsTranslationCtx,on,defaultContent:parseChildNodes(node,ctx),};}
function wrapInTTranslationAST(r){const ast={type:16,content:r};if(r===null||r===void 0?void 0:r.hasNoRepresentation){ast.hasNoRepresentation=true;}
return ast;}
function parseTTranslation(node,ctx){if(node.getAttribute("t-translation")!=="off"){return null;}
node.removeAttribute("t-translation");const result=parseNode(node,ctx);if((result===null||result===void 0?void 0:result.type)===3){const children=result.content.map(wrapInTTranslationAST);return makeASTMulti(children);}
return wrapInTTranslationAST(result);}
function wrapInTTranslationContextAST(r,translationCtx){const ast={type:17,content:r,translationCtx,};if(r===null||r===void 0?void 0:r.hasNoRepresentation){ast.hasNoRepresentation=true;}
return ast;}
function parseTTranslationContext(node,ctx){const translationCtx=node.getAttribute("t-translation-context");if(!translationCtx){return null;}
node.removeAttribute("t-translation-context");const result=parseNode(node,ctx);if((result===null||result===void 0?void 0:result.type)===3){const children=result.content.map((c)=>wrapInTTranslationContextAST(c,translationCtx));return makeASTMulti(children);}
return wrapInTTranslationContextAST(result,translationCtx);}
function parseTPortal(node,ctx){if(!node.hasAttribute("t-portal")){return null;}
const target=node.getAttribute("t-portal");node.removeAttribute("t-portal");const content=parseNode(node,ctx);if(!content){return{type:0,value:"",};}
return{type:18,target,content,};}
function parseChildren(node,ctx){const children=[];for(let child of node.childNodes){const childAst=parseNode(child,ctx);if(childAst){if(childAst.type===3){children.push(...childAst.content);}
else{children.push(childAst);}}}
return children;}
function makeASTMulti(children){const ast={type:3,content:children};if(children.every((c)=>c.hasNoRepresentation)){ast.hasNoRepresentation=true;}
return ast;}
function parseChildNodes(node,ctx){const children=parseChildren(node,ctx);switch(children.length){case 0:return null;case 1:return children[0];default:return makeASTMulti(children);}}
function normalizeTIf(el){let tbranch=el.querySelectorAll("[t-elif], [t-else]");for(let i=0,ilen=tbranch.length;i<ilen;i++){let node=tbranch[i];let prevElem=node.previousElementSibling;let pattr=(name)=>prevElem.getAttribute(name);let nattr=(name)=>+!!node.getAttribute(name);if(prevElem&&(pattr("t-if")||pattr("t-elif"))){if(pattr("t-foreach")){throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");}
if(["t-if","t-elif","t-else"].map(nattr).reduce(function(a,b){return a+b;})>1){throw new OwlError("Only one conditional branching directive is allowed per node");}
let textNode;while((textNode=node.previousSibling)!==prevElem){if(textNode.nodeValue.trim().length&&textNode.nodeType!==8){throw new OwlError("text is not allowed between branching directives");}
textNode.remove();}}
else{throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");}}}
function normalizeTEscTOut(el){for(const d of["t-esc","t-out"]){const elements=[...el.querySelectorAll(`[${d}]`)].filter((el)=>el.tagName[0]===el.tagName[0].toUpperCase()||el.hasAttribute("t-component"));for(const el of elements){if(el.childNodes.length){throw new OwlError(`Cannot have ${d} on a component that already has content`);}
const value=el.getAttribute(d);el.removeAttribute(d);const t=el.ownerDocument.createElement("t");if(value!=null){t.setAttribute(d,value);}
el.appendChild(t);}}}
function normalizeXML(el){normalizeTIf(el);normalizeTEscTOut(el);}
function compile(template,options={hasGlobalValues:false,}){const ast=parse(template,options.customDirectives);const hasSafeContext=template instanceof Node?!(template instanceof Element)||template.querySelector("[t-set], [t-call]")===null:!template.includes("t-set")&&!template.includes("t-call");const codeGenerator=new CodeGenerator(ast,{...options,hasSafeContext});const code=codeGenerator.generateCode();try{return new Function("app, bdom, helpers",code);}
catch(originalError){const{name}=options;const nameStr=name?`template "${name}"`:"anonymous template";const err=new OwlError(`Failed to compile ${nameStr}: ${originalError.message}\n\ngenerated code:\nfunction(app, bdom, helpers) {\n${code}\n}`);err.cause=originalError;throw err;}}
const version="2.8.1";class Scheduler{constructor(){this.tasks=new Set();this.frame=0;this.delayedRenders=[];this.cancelledNodes=new Set();this.processing=false;this.requestAnimationFrame=Scheduler.requestAnimationFrame;}
addFiber(fiber){this.tasks.add(fiber.root);}
scheduleDestroy(node){this.cancelledNodes.add(node);if(this.frame===0){this.frame=this.requestAnimationFrame(()=>this.processTasks());}}
flush(){if(this.delayedRenders.length){let renders=this.delayedRenders;this.delayedRenders=[];for(let f of renders){if(f.root&&f.node.status!==3&&f.node.fiber===f){f.render();}}}
if(this.frame===0){this.frame=this.requestAnimationFrame(()=>this.processTasks());}}
processTasks(){if(this.processing){return;}
this.processing=true;this.frame=0;for(let node of this.cancelledNodes){node._destroy();}
this.cancelledNodes.clear();for(let task of this.tasks){this.processFiber(task);}
for(let task of this.tasks){if(task.node.status===3){this.tasks.delete(task);}}
this.processing=false;}
processFiber(fiber){if(fiber.root!==fiber){this.tasks.delete(fiber);return;}
const hasError=fibersInError.has(fiber);if(hasError&&fiber.counter!==0){this.tasks.delete(fiber);return;}
if(fiber.node.status===3){this.tasks.delete(fiber);return;}
if(fiber.counter===0){if(!hasError){fiber.complete();}
if(fiber.appliedToDom){this.tasks.delete(fiber);}}}}
Scheduler.requestAnimationFrame=window.requestAnimationFrame.bind(window);let hasBeenLogged=false;const apps=new Set();window.__OWL_DEVTOOLS__||(window.__OWL_DEVTOOLS__={apps,Fiber,RootFiber,toRaw,reactive});class App extends TemplateSet{constructor(Root,config={}){super(config);this.scheduler=new Scheduler();this.subRoots=new Set();this.root=null;this.name=config.name||"";this.Root=Root;apps.add(this);if(config.test){this.dev=true;}
this.warnIfNoStaticProps=config.warnIfNoStaticProps||false;if(this.dev&&!config.test&&!hasBeenLogged){console.info(`Owl is running in 'dev' mode.`);hasBeenLogged=true;}
const env=config.env||{};const descrs=Object.getOwnPropertyDescriptors(env);this.env=Object.freeze(Object.create(Object.getPrototypeOf(env),descrs));this.props=config.props||{};}
mount(target,options){const root=this.createRoot(this.Root,{props:this.props});this.root=root.node;this.subRoots.delete(root.node);return root.mount(target,options);}
createRoot(Root,config={}){const props=config.props||{};const env=this.env;if(config.env){this.env=config.env;}
const restore=saveCurrent();const node=this.makeNode(Root,props);restore();if(config.env){this.env=env;}
this.subRoots.add(node);return{node,mount:(target,options)=>{App.validateTarget(target);if(this.dev){validateProps(Root,props,{__owl__:{app:this}});}
const prom=this.mountNode(node,target,options);return prom;},destroy:()=>{this.subRoots.delete(node);node.destroy();this.scheduler.processTasks();},};}
makeNode(Component,props){return new ComponentNode(Component,props,this,null,null);}
mountNode(node,target,options){const promise=new Promise((resolve,reject)=>{let isResolved=false;node.mounted.push(()=>{resolve(node.component);isResolved=true;});let handlers=nodeErrorHandlers.get(node);if(!handlers){handlers=[];nodeErrorHandlers.set(node,handlers);}
handlers.unshift((e)=>{if(!isResolved){reject(e);}
throw e;});});node.mountComponent(target,options);return promise;}
destroy(){if(this.root){for(let subroot of this.subRoots){subroot.destroy();}
this.root.destroy();this.scheduler.processTasks();}
apps.delete(this);}
createComponent(name,isStatic,hasSlotsProp,hasDynamicPropList,propList){const isDynamic=!isStatic;let arePropsDifferent;const hasNoProp=propList.length===0;if(hasSlotsProp){arePropsDifferent=(_1,_2)=>true;}
else if(hasDynamicPropList){arePropsDifferent=function(props1,props2){for(let k in props1){if(props1[k]!==props2[k]){return true;}}
return Object.keys(props1).length!==Object.keys(props2).length;};}
else if(hasNoProp){arePropsDifferent=(_1,_2)=>false;}
else{arePropsDifferent=function(props1,props2){for(let p of propList){if(props1[p]!==props2[p]){return true;}}
return false;};}
const updateAndRender=ComponentNode.prototype.updateAndRender;const initiateRender=ComponentNode.prototype.initiateRender;return(props,key,ctx,parent,C)=>{let children=ctx.children;let node=children[key];if(isDynamic&&node&&node.component.constructor!==C){node=undefined;}
const parentFiber=ctx.fiber;if(node){if(arePropsDifferent(node.props,props)||parentFiber.deep||node.forceNextRender){node.forceNextRender=false;updateAndRender.call(node,props,parentFiber);}}
else{if(isStatic){const components=parent.constructor.components;if(!components){throw new OwlError(`Cannot find the definition of component "${name}", missing static components key in parent`);}
C=components[name];if(!C){throw new OwlError(`Cannot find the definition of component "${name}"`);}
else if(!(C.prototype instanceof Component)){throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);}}
node=new ComponentNode(C,props,this,ctx,key);children[key]=node;initiateRender.call(node,new Fiber(node,parentFiber));}
parentFiber.childrenMap[key]=node;return node;};}
handleError(...args){return handleError(...args);}}
App.validateTarget=validateTarget;App.apps=apps;App.version=version;async function mount(C,target,config={}){return new App(C,config).mount(target,config);}
const mainEventHandler=(data,ev,currentTarget)=>{const{data:_data,modifiers}=filterOutModifiersFromData(data);data=_data;let stopped=false;if(modifiers.length){let selfMode=false;const isSelf=ev.target===currentTarget;for(const mod of modifiers){switch(mod){case"self":selfMode=true;if(isSelf){continue;}
else{return stopped;}
case"prevent":if((selfMode&&isSelf)||!selfMode)
ev.preventDefault();continue;case"stop":if((selfMode&&isSelf)||!selfMode)
ev.stopPropagation();stopped=true;continue;}}}
if(Object.hasOwnProperty.call(data,0)){const handler=data[0];if(typeof handler!=="function"){throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);}
let node=data[1]?data[1].__owl__:null;if(node?node.status===1:true){handler.call(node?node.component:null,ev);}}
return stopped;};function status(component){switch(component.__owl__.status){case 0:return"new";case 2:return"cancelled";case 1:return"mounted";case 3:return"destroyed";}}
function useRef(name){const node=getCurrent();const refs=node.refs;return{get el(){const el=refs[name];return inOwnerDocument(el)?el:null;},};}
function useEnv(){return getCurrent().component.env;}
function extendEnv(currentEnv,extension){const env=Object.create(currentEnv);const descrs=Object.getOwnPropertyDescriptors(extension);return Object.freeze(Object.defineProperties(env,descrs));}
function useSubEnv(envExtension){const node=getCurrent();node.component.env=extendEnv(node.component.env,envExtension);useChildSubEnv(envExtension);}
function useChildSubEnv(envExtension){const node=getCurrent();node.childEnv=extendEnv(node.childEnv,envExtension);}
function useEffect(effect,computeDependencies=()=>[NaN]){let cleanup;let dependencies;onMounted(()=>{dependencies=computeDependencies();cleanup=effect(...dependencies);});onPatched(()=>{const newDeps=computeDependencies();const shouldReapply=newDeps.some((val,i)=>val!==dependencies[i]);if(shouldReapply){dependencies=newDeps;if(cleanup){cleanup();}
cleanup=effect(...dependencies);}});onWillUnmount(()=>cleanup&&cleanup());}
function useExternalListener(target,eventName,handler,eventParams){const node=getCurrent();const boundHandler=handler.bind(node.component);onMounted(()=>target.addEventListener(eventName,boundHandler,eventParams));onWillUnmount(()=>target.removeEventListener(eventName,boundHandler,eventParams));}
config.shouldNormalizeDom=false;config.mainEventHandler=mainEventHandler;const blockDom={config,mount:mount$1,patch,remove,list,multi,text,toggler,createBlock,html,comment,};const __info__={version:App.version,};TemplateSet.prototype._compileTemplate=function _compileTemplate(name,template){return compile(template,{name,dev:this.dev,translateFn:this.translateFn,translatableAttributes:this.translatableAttributes,customDirectives:this.customDirectives,hasGlobalValues:this.hasGlobalValues,});};exports.App=App;exports.Component=Component;exports.EventBus=EventBus;exports.OwlError=OwlError;exports.__info__=__info__;exports.batched=batched;exports.blockDom=blockDom;exports.htmlEscape=htmlEscape;exports.loadFile=loadFile;exports.markRaw=markRaw;exports.markup=markup;exports.mount=mount;exports.onError=onError;exports.onMounted=onMounted;exports.onPatched=onPatched;exports.onRendered=onRendered;exports.onWillDestroy=onWillDestroy;exports.onWillPatch=onWillPatch;exports.onWillRender=onWillRender;exports.onWillStart=onWillStart;exports.onWillUnmount=onWillUnmount;exports.onWillUpdateProps=onWillUpdateProps;exports.reactive=reactive;exports.status=status;exports.toRaw=toRaw;exports.useChildSubEnv=useChildSubEnv;exports.useComponent=useComponent;exports.useEffect=useEffect;exports.useEnv=useEnv;exports.useExternalListener=useExternalListener;exports.useRef=useRef;exports.useState=useState;exports.useSubEnv=useSubEnv;exports.validate=validate;exports.validateType=validateType;exports.whenReady=whenReady;exports.xml=xml;Object.defineProperty(exports,'__esModule',{value:true});__info__.date='2025-09-23T07:17:45.055Z';__info__.hash='5211116';__info__.url='https://github.com/odoo/owl';})(this.owl=this.owl||{});;

/* /web/static/lib/owl/odoo_module.js */
odoo.define("@odoo/owl",[],function(){"use strict";return owl;});;

/* /web/static/src/env.js */
odoo.define('@web/env',['@odoo/owl','@web/core/utils/hooks','@web/core/registry','@web/core/templates','@web/core/l10n/translation','@web/session'],function(require){'use strict';let __exports={};const{App,EventBus}=require("@odoo/owl");const{SERVICES_METADATA}=require("@web/core/utils/hooks");const{registry}=require("@web/core/registry");const{getTemplate}=require("@web/core/templates");const{_t}=require("@web/core/l10n/translation");const{session}=require("@web/session");__exports.makeEnv=makeEnv;function makeEnv(){return{bus:new EventBus(),services:{},debug:odoo.debug,get isSmall(){throw new Error("UI service not initialized!");},};}
const serviceRegistry=registry.category("services");serviceRegistry.addValidation({start:Function,dependencies:{type:Array,element:String,optional:true},async:{type:[{type:Array,element:String},{value:true}],optional:true},"*":true,});let startServicesPromise=null;__exports.startServices=startServices;async function startServices(env){await Promise.resolve();const toStart=new Map();serviceRegistry.addEventListener("UPDATE",async(ev)=>{await Promise.resolve();const{operation,key:name,value:service}=ev.detail;if(operation==="delete"){return;}
if(toStart.size){const namedService=Object.assign(Object.create(service),{name});toStart.set(name,namedService);}else{await _startServices(env,toStart);}});await _startServices(env,toStart);}
async function _startServices(env,toStart){if(startServicesPromise){return startServicesPromise.then(()=>_startServices(env,toStart));}
const services=env.services;for(const[name,service]of serviceRegistry.getEntries()){if(!(name in services)){const namedService=Object.assign(Object.create(service),{name});toStart.set(name,namedService);}}
async function start(){let service=null;const proms=[];while((service=findNext())){const name=service.name;toStart.delete(name);const entries=(service.dependencies||[]).map((dep)=>[dep,services[dep]]);const dependencies=Object.fromEntries(entries);if(name in services){continue;}
const value=service.start(env,dependencies);if("async"in service){SERVICES_METADATA[name]=service.async;}
proms.push(Promise.resolve(value).then((val)=>{services[name]=val||null;}));}
await Promise.all(proms);if(proms.length){return start();}}
startServicesPromise=start().finally(()=>{startServicesPromise=null;});await startServicesPromise;if(toStart.size){const missingDeps=new Set();for(const service of toStart.values()){for(const dependency of service.dependencies){if(!(dependency in services)&&!toStart.has(dependency)){missingDeps.add(dependency);}}}
const depNames=[...missingDeps].join(", ");throw new Error(`Some services could not be started: ${[
                ...toStart.keys(),
            ]}. Missing dependencies: ${depNames}`);}
function findNext(){for(const s of toStart.values()){if(s.dependencies){if(s.dependencies.every((d)=>d in services)){return s;}}else{return s;}}
return null;}}
__exports.mountComponent=mountComponent;async function mountComponent(component,target,appConfig={}){let{env}=appConfig;const isRoot=!env;if(isRoot){env=await makeEnv();await startServices(env);}
const app=new App(component,{env,getTemplate,dev:env.debug||session.test_mode,warnIfNoStaticProps:!session.test_mode,name:component.constructor.name,translatableAttributes:["data-tooltip"],translateFn:_t,...appConfig,});const root=await app.mount(target);if(isRoot){odoo.__WOWL_DEBUG__={root};}
return app;}
return __exports;});;

/* /web/static/src/session.js */
odoo.define('@web/session',[],function(require){'use strict';let __exports={};const session=__exports.session=odoo.__session_info__||{};delete odoo.__session_info__;return __exports;});;

/* /web/static/src/core/action_swiper/action_swiper.js */
odoo.define('@web/core/action_swiper/action_swiper',['@web/core/browser/browser','@web/core/l10n/localization','@web/core/utils/numbers','@odoo/owl','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{localization}=require("@web/core/l10n/localization");const{clamp}=require("@web/core/utils/numbers");const{Component,onMounted,onWillUnmount,useRef,useState}=require("@odoo/owl");const{Deferred}=require("@web/core/utils/concurrency");const isScrollSwipable=(scrollables)=>{return{left:!scrollables.filter((e)=>e.scrollLeft!==0).length,right:!scrollables.filter((e)=>e.scrollLeft+Math.round(e.getBoundingClientRect().width)!==e.scrollWidth).length,};};const ActionSwiper=__exports.ActionSwiper=class ActionSwiper extends Component{static template="web.ActionSwiper";static props={onLeftSwipe:{type:Object,args:{action:Function,icon:String,bgColor:String,},optional:true,},onRightSwipe:{type:Object,args:{action:Function,icon:String,bgColor:String,},optional:true,},slots:Object,animationOnMove:{type:Boolean,optional:true},animationType:{type:String,optional:true},swipeDistanceRatio:{type:Number,optional:true},swipeInvalid:{type:Function,optional:true},};static defaultProps={onLeftSwipe:undefined,onRightSwipe:undefined,animationOnMove:true,animationType:"bounce",swipeDistanceRatio:2,};setup(){this.actionTimeoutId=null;this.resetTimeoutId=null;this.defaultState={containerStyle:"",isSwiping:false,width:undefined,};this.root=useRef("root");this.targetContainer=useRef("targetContainer");this.state=useState({...this.defaultState});this.scrollables=undefined;this.startX=undefined;this.swipedDistance=0;this.isScrollValidated=false;onMounted(()=>{if(this.targetContainer.el){this.state.width=this.targetContainer.el.getBoundingClientRect().width;}
if(this.props.onLeftSwipe||this.props.onRightSwipe){const classes=new Set(this.root.el.classList);classes.delete("o_actionswiper");for(const className of classes){this.targetContainer.el.firstChild.classList.add(className);this.root.el.classList.remove(className);}}});onWillUnmount(()=>{browser.clearTimeout(this.actionTimeoutId);browser.clearTimeout(this.resetTimeoutId);});}
get localizedProps(){return{onLeftSwipe:localization.direction==="rtl"?this.props.onRightSwipe:this.props.onLeftSwipe,onRightSwipe:localization.direction==="rtl"?this.props.onLeftSwipe:this.props.onRightSwipe,};}
_onTouchEndSwipe(){if(this.state.isSwiping){this.state.isSwiping=false;if(this.localizedProps.onRightSwipe&&this.swipedDistance>this.state.width/this.props.swipeDistanceRatio){this.swipedDistance=this.state.width;this.handleSwipe(this.localizedProps.onRightSwipe.action);}else if(this.localizedProps.onLeftSwipe&&this.swipedDistance<-this.state.width/this.props.swipeDistanceRatio){this.swipedDistance=-this.state.width;this.handleSwipe(this.localizedProps.onLeftSwipe.action);}else{this.state.containerStyle="";}}}
_onTouchMoveSwipe(ev){if(this.state.isSwiping){if(this.props.swipeInvalid&&this.props.swipeInvalid()){this.state.isSwiping=false;return;}
const{onLeftSwipe,onRightSwipe}=this.localizedProps;this.swipedDistance=clamp(ev.touches[0].clientX-this.startX,onLeftSwipe?-this.state.width:0,onRightSwipe?this.state.width:0);if(Math.abs(this.swipedDistance)>40){ev.preventDefault();}
if(!this.isScrollValidated&&this.scrollables&&!isScrollSwipable(this.scrollables)[this.swipedDistance>0?"left":"right"]){return this._reset();}
this.isScrollValidated=true;if(this.props.animationOnMove){this.state.containerStyle=`transform: translateX(${this.swipedDistance}px)`;}}}
_onTouchStartSwipe(ev){this.scrollables=ev.composedPath().filter((e)=>e.nodeType===1&&this.targetContainer.el.contains(e)&&e.scrollWidth>e.getBoundingClientRect().width&&["auto","scroll"].includes(window.getComputedStyle(e)["overflow-x"]));if(!this.state.width){this.state.width=this.targetContainer&&this.targetContainer.el.getBoundingClientRect().width;}
this.state.isSwiping=true;this.isScrollValidated=false;this.startX=ev.touches[0].clientX;}
_reset(){Object.assign(this.state,{...this.defaultState});this.scrollables=undefined;this.startX=undefined;this.swipedDistance=0;this.isScrollValidated=false;}
handleSwipe(action){if(this.props.animationType==="bounce"){this.state.containerStyle=`transform: translateX(${this.swipedDistance}px)`;this.actionTimeoutId=browser.setTimeout(async()=>{await action(Promise.resolve());this._reset();},500);}else if(this.props.animationType==="forwards"){this.state.containerStyle=`transform: translateX(${this.swipedDistance}px)`;this.actionTimeoutId=browser.setTimeout(async()=>{const prom=new Deferred();await action(prom);this.state.isSwiping=true;this.state.containerStyle=`transform: translateX(${-this.swipedDistance}px)`;this.resetTimeoutId=browser.setTimeout(()=>{prom.resolve();this._reset();},100);},100);}else{return action(Promise.resolve());}}}
return __exports;});;

/* /web/static/src/core/anchor_scroll_prevention.js */
odoo.define('@web/core/anchor_scroll_prevention',['@web/core/browser/browser'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");browser.addEventListener("click",(ev)=>{const href=ev.target.closest("a")?.getAttribute("href");if(href&&href==="#"){ev.preventDefault();return;}});return __exports;});;

/* /web/static/src/core/assets.js */
odoo.define('@web/core/assets',['@odoo/owl','@web/session','@web/core/registry'],function(require){'use strict';let __exports={};const{Component,onWillStart,whenReady,xml}=require("@odoo/owl");const{session}=require("@web/session");const{registry}=require("@web/core/registry");const computeCacheMap=()=>{for(const script of document.head.querySelectorAll("script[src]")){cacheMap.set(script.getAttribute("src"),Promise.resolve());}
for(const link of document.head.querySelectorAll("link[rel=stylesheet][href]")){cacheMap.set(link.getAttribute("href"),Promise.resolve());}};const onLoadAndError=(el,onLoad,onError)=>{const onLoadListener=(event)=>{removeListeners();onLoad(event);};const onErrorListener=(error)=>{removeListeners();onError(error);};const removeListeners=()=>{el.removeEventListener("load",onLoadListener);el.removeEventListener("error",onErrorListener);};el.addEventListener("load",onLoadListener);el.addEventListener("error",onErrorListener);};const cacheMap=new Map();whenReady(computeCacheMap);__exports.getBundle=getBundle;function getBundle(){return assets.getBundle(...arguments);}
__exports.loadBundle=loadBundle;function loadBundle(){return assets.loadBundle(...arguments);}
__exports.loadJS=loadJS;function loadJS(){return assets.loadJS(...arguments);}
__exports.loadCSS=loadCSS;function loadCSS(){return assets.loadCSS(...arguments);}
const AssetsLoadingError=__exports.AssetsLoadingError=class AssetsLoadingError extends Error{}
const LazyComponent=__exports.LazyComponent=class LazyComponent extends Component{static template=xml`<t t-component="Component" t-props="props.props"/>`;static props={Component:String,bundle:String,props:{type:Object,optional:true},};setup(){onWillStart(async()=>{await loadBundle(this.props.bundle);this.Component=registry.category("lazy_components").get(this.props.Component);});}}
const assets=__exports.assets={retries:{count:3,delay:5000,extraDelay:2500,},getBundle(bundleName){if(cacheMap.has(bundleName)){return cacheMap.get(bundleName);}
const url=new URL(`/web/bundle/${bundleName}`,location.origin);for(const[key,value]of Object.entries(session.bundle_params||{})){url.searchParams.set(key,value);}
const promise=fetch(url).then(async(response)=>{const cssLibs=[];const jsLibs=[];if(!response.bodyUsed){const result=await response.json();for(const{src,type}of Object.values(result)){if(type==="link"&&src){cssLibs.push(src);}else if(type==="script"&&src){jsLibs.push(src);}}}
return{cssLibs,jsLibs};}).catch((reason)=>{cacheMap.delete(bundleName);throw reason;});cacheMap.set(bundleName,promise);return promise;},loadBundle(bundleName){if(typeof bundleName!=="string"){throw new Error(`loadBundle(bundleName:string) accepts only bundleName argument as a string ! Not ${JSON.stringify(
                    bundleName
                )} as ${typeof bundleName}`);}
return getBundle(bundleName).then(({cssLibs,jsLibs})=>Promise.all([...cssLibs.map(loadCSS),...jsLibs.map(loadJS)]));},loadCSS(url,retryCount=0){if(cacheMap.has(url)){return cacheMap.get(url);}
const linkEl=document.createElement("link");linkEl.setAttribute("href",url);linkEl.type="text/css";linkEl.rel="stylesheet";const promise=new Promise((resolve,reject)=>onLoadAndError(linkEl,resolve,async()=>{cacheMap.delete(url);if(retryCount<assets.retries.count){const delay=assets.retries.delay+assets.retries.extraDelay*retryCount;await new Promise((res)=>setTimeout(res,delay));linkEl.remove();loadCSS(url,retryCount+1).then(resolve).catch((reason)=>{cacheMap.delete(url);reject(reason);});}else{reject(new AssetsLoadingError(`The loading of ${url} failed`));}}));cacheMap.set(url,promise);document.head.appendChild(linkEl);return promise;},loadJS(url){if(cacheMap.has(url)){return cacheMap.get(url);}
const scriptEl=document.createElement("script");scriptEl.setAttribute("src",url);scriptEl.type=url.includes("web/static/lib/pdfjs/")?"module":"text/javascript";const promise=new Promise((resolve,reject)=>onLoadAndError(scriptEl,resolve,()=>{cacheMap.delete(url);reject(new AssetsLoadingError(`The loading of ${url} failed`));}));cacheMap.set(url,promise);document.head.appendChild(scriptEl);return promise;},};return __exports;});;

/* /web/static/src/core/autocomplete/autocomplete.js */
odoo.define('@web/core/autocomplete/autocomplete',['@web/core/utils/concurrency','@web/core/utils/hooks','@web/core/utils/scrolling','@web/core/utils/timing','@web/core/hotkeys/hotkey_service','@web/core/position/position_hook','@odoo/owl'],function(require){'use strict';let __exports={};const{Deferred}=require("@web/core/utils/concurrency");const{useAutofocus,useForwardRefToParent,useService}=require("@web/core/utils/hooks");const{isScrollableY,scrollTo}=require("@web/core/utils/scrolling");const{useDebounced}=require("@web/core/utils/timing");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{usePosition}=require("@web/core/position/position_hook");const{Component,onWillUpdateProps,useExternalListener,useRef,useState}=require("@odoo/owl");const AutoComplete=__exports.AutoComplete=class AutoComplete extends Component{static template="web.AutoComplete";static props={value:{type:String,optional:true},id:{type:String,optional:true},onSelect:{type:Function},sources:{type:Array,element:{type:Object,shape:{placeholder:{type:String,optional:true},optionTemplate:{type:String,optional:true},options:[Array,Function],},},},placeholder:{type:String,optional:true},autoSelect:{type:Boolean,optional:true},resetOnSelect:{type:Boolean,optional:true},onInput:{type:Function,optional:true},onCancel:{type:Function,optional:true},onChange:{type:Function,optional:true},onBlur:{type:Function,optional:true},onFocus:{type:Function,optional:true},input:{type:Function,optional:true},dropdown:{type:Boolean,optional:true},autofocus:{type:Boolean,optional:true},class:{type:String,optional:true},};static defaultProps={value:"",placeholder:"",autoSelect:false,dropdown:true,onInput:()=>{},onCancel:()=>{},onChange:()=>{},onBlur:()=>{},onFocus:()=>{},};setup(){this.nextSourceId=0;this.nextOptionId=0;this.sources=[];this.inEdition=false;this.timeout=250;this.state=useState({navigationRev:0,optionsRev:0,open:false,activeSourceOption:null,value:this.props.value,});this.inputRef=useForwardRefToParent("input");this.listRef=useRef("sourcesList");if(this.props.autofocus){useAutofocus({refName:"input"});}
this.root=useRef("root");this.debouncedProcessInput=useDebounced(async()=>{const currentPromise=this.pendingPromise;this.pendingPromise=null;this.props.onInput({inputValue:this.inputRef.el.value,});try{await this.open(true);currentPromise.resolve();}catch{currentPromise.reject();}finally{if(currentPromise===this.loadingPromise){this.loadingPromise=null;}}},this.timeout);useExternalListener(window,"scroll",this.externalClose,true);useExternalListener(window,"pointerdown",this.externalClose,true);this.hotkey=useService("hotkey");this.hotkeysToRemove=[];onWillUpdateProps((nextProps)=>{if(this.props.value!==nextProps.value||this.forceValFromProp){this.forceValFromProp=false;if(!this.inEdition){this.state.value=nextProps.value;this.inputRef.el.value=nextProps.value;}
this.close();}});if(this.props.dropdown){usePosition("sourcesList",()=>this.targetDropdown,this.dropdownOptions);}else{this.open(false);}}
get targetDropdown(){return this.inputRef.el;}
get activeSourceOptionId(){if(!this.isOpened||!this.state.activeSourceOption){return undefined;}
const[sourceIndex,optionIndex]=this.state.activeSourceOption;const source=this.sources[sourceIndex];return`${this.props.id || "autocomplete"}_${sourceIndex}_${
            source.isLoading ? "loading" : optionIndex
        }`;}
get dropdownOptions(){return{position:"bottom-start",};}
get isOpened(){return this.state.open;}
get hasOptions(){for(const source of this.sources){if(source.isLoading||source.options.length){return true;}}
return false;}
get activeOption(){const[sourceIndex,optionIndex]=this.state.activeSourceOption;return this.sources[sourceIndex].options[optionIndex];}
open(useInput=false){this.state.open=true;return this.loadSources(useInput);}
close(){this.state.open=false;this.state.activeSourceOption=null;}
cancel(){if(this.inputRef.el.value.length){if(this.props.autoSelect){this.inputRef.el.value=this.props.value;this.props.onCancel();}}
this.close();}
async loadSources(useInput){this.sources=[];this.state.activeSourceOption=null;const proms=[];for(const pSource of this.props.sources){const source=this.makeSource(pSource);this.sources.push(source);const options=this.loadOptions(pSource.options,useInput?this.inputRef.el.value.trim():"");if(options instanceof Promise){source.isLoading=true;const prom=options.then((options)=>{source.options=options.map((option)=>this.makeOption(option));source.isLoading=false;this.state.optionsRev++;});proms.push(prom);}else{source.options=options.map((option)=>this.makeOption(option));}}
await Promise.all(proms);this.navigate(0);}
get displayOptions(){return!this.props.dropdown||(this.isOpened&&this.hasOptions);}
loadOptions(options,request){if(typeof options==="function"){return options(request);}else{return options;}}
makeOption(option){return Object.assign(Object.create(option),{id:++this.nextOptionId,});}
makeSource(source){return{id:++this.nextSourceId,options:[],isLoading:false,placeholder:source.placeholder,optionTemplate:source.optionTemplate,};}
isActiveSourceOption([sourceIndex,optionIndex]){return(this.state.activeSourceOption&&this.state.activeSourceOption[0]===sourceIndex&&this.state.activeSourceOption[1]===optionIndex);}
selectOption(option,params={}){this.inEdition=false;if(option.unselectable){this.inputRef.el.value="";this.close();return;}
if(this.props.resetOnSelect){this.inputRef.el.value="";}
this.forceValFromProp=true;this.props.onSelect(option,{...params,input:this.inputRef.el,});this.close();}
navigate(direction){let step=Math.sign(direction);if(!step){this.state.activeSourceOption=null;step=1;}else{this.state.navigationRev++;}
if(this.state.activeSourceOption){let[sourceIndex,optionIndex]=this.state.activeSourceOption;let source=this.sources[sourceIndex];optionIndex+=step;if(0>optionIndex||optionIndex>=source.options.length){sourceIndex+=step;source=this.sources[sourceIndex];while(source&&source.isLoading){sourceIndex+=step;source=this.sources[sourceIndex];}
if(source){optionIndex=step<0?source.options.length-1:0;}}
this.state.activeSourceOption=source?[sourceIndex,optionIndex]:null;}else{let sourceIndex=step<0?this.sources.length-1:0;let source=this.sources[sourceIndex];while(source&&source.isLoading){sourceIndex+=step;source=this.sources[sourceIndex];}
if(source){const optionIndex=step<0?source.options.length-1:0;if(optionIndex<source.options.length){this.state.activeSourceOption=[sourceIndex,optionIndex];}}}}
onInputBlur(){if(this.ignoreBlur){this.ignoreBlur=false;return;}
this.props.onBlur({inputValue:this.inputRef.el.value,});this.inEdition=false;}
onInputClick(){if(!this.isOpened){this.open(this.inputRef.el.value.trim()!==this.props.value.trim());}else{this.close();}}
onInputChange(ev){if(this.ignoreBlur){ev.stopImmediatePropagation();}
this.props.onChange({inputValue:this.inputRef.el.value,});}
async onInput(){this.inEdition=true;this.pendingPromise=this.pendingPromise||new Deferred();this.loadingPromise=this.pendingPromise;this.debouncedProcessInput();}
onInputFocus(ev){this.inputRef.el.setSelectionRange(0,this.inputRef.el.value.length);this.props.onFocus(ev);}
get autoCompleteRootClass(){let classList="";if(this.props.class){classList+=this.props.class;}
if(this.props.dropdown){classList+=" dropdown";}
return classList;}
get ulDropdownClass(){let classList="";if(this.props.dropdown){classList+=" dropdown-menu ui-autocomplete";}else{classList+=" list-group";}
return classList;}
async onInputKeydown(ev){const hotkey=getActiveHotkey(ev);const isSelectKey=hotkey==="enter"||hotkey==="tab";if(this.loadingPromise&&isSelectKey){if(hotkey==="enter"){ev.stopPropagation();ev.preventDefault();}
await this.loadingPromise;}
switch(hotkey){case"enter":if(!this.isOpened||!this.state.activeSourceOption){return;}
this.selectOption(this.activeOption);break;case"escape":if(!this.isOpened){return;}
this.cancel();break;case"tab":case"shift+tab":if(!this.isOpened){return;}
if(this.props.autoSelect&&this.state.activeSourceOption&&(this.state.navigationRev>0||this.inputRef.el.value.length>0)){this.selectOption(this.activeOption);}
this.close();return;case"arrowup":this.navigate(-1);if(!this.isOpened){this.open(true);}
this.scroll();break;case"arrowdown":this.navigate(+1);if(!this.isOpened){this.open(true);}
this.scroll();break;default:return;}
ev.stopPropagation();ev.preventDefault();}
onOptionMouseEnter(indices){this.state.activeSourceOption=indices;}
onOptionMouseLeave(){this.state.activeSourceOption=null;}
onOptionClick(option){this.selectOption(option);this.inputRef.el.focus();}
externalClose(ev){if(this.isOpened&&!this.root.el.contains(ev.target)){this.cancel();}}
scroll(){if(!this.activeSourceOptionId){return;}
if(isScrollableY(this.listRef.el)){scrollTo(this.listRef.el.querySelector(`#${this.activeSourceOptionId}`));}}}
return __exports;});;

/* /web/static/src/core/barcode/ZXingBarcodeDetector.js */
odoo.define('@web/core/barcode/ZXingBarcodeDetector',[],function(require){'use strict';let __exports={};__exports.buildZXingBarcodeDetector=buildZXingBarcodeDetector;function buildZXingBarcodeDetector(ZXing){const ZXingFormats=new Map([["aztec",ZXing.BarcodeFormat.AZTEC],["code_39",ZXing.BarcodeFormat.CODE_39],["code_128",ZXing.BarcodeFormat.CODE_128],["data_matrix",ZXing.BarcodeFormat.DATA_MATRIX],["ean_8",ZXing.BarcodeFormat.EAN_8],["ean_13",ZXing.BarcodeFormat.EAN_13],["itf",ZXing.BarcodeFormat.ITF],["pdf417",ZXing.BarcodeFormat.PDF_417],["qr_code",ZXing.BarcodeFormat.QR_CODE],["upc_a",ZXing.BarcodeFormat.UPC_A],["upc_e",ZXing.BarcodeFormat.UPC_E],]);const allSupportedFormats=Array.from(ZXingFormats.keys());ZXing.HTMLCanvasElementLuminanceSource.toGrayscaleBuffer=function(imageBuffer,width,height){const grayscaleBuffer=new Uint8ClampedArray(width*height);for(let i=0,j=0,length=imageBuffer.length;i<length;i+=4,j++){let gray;const alpha=imageBuffer[i+3];if(alpha===0){gray=0xff;}else{const pixelR=imageBuffer[i];const pixelG=imageBuffer[i+1];const pixelB=imageBuffer[i+2];gray=(306*pixelR+601*pixelG+117*pixelB+0x200)>>10;}
grayscaleBuffer[j]=gray;}
return grayscaleBuffer;};class ZXingBarcodeDetector{constructor(opts={}){const formats=opts.formats||allSupportedFormats;const hints=new Map([[ZXing.DecodeHintType.POSSIBLE_FORMATS,formats.map((format)=>ZXingFormats.get(format)),],[ZXing.DecodeHintType.TRY_HARDER,true],]);this.reader=new ZXing.MultiFormatReader();this.reader.setHints(hints);}
async detect(video){if(!(video instanceof HTMLVideoElement)){throw new DOMException("imageDataFrom() requires an HTMLVideoElement","InvalidArgumentError");}
if(!isVideoElementReady(video)){throw new DOMException("HTMLVideoElement is not ready","InvalidStateError");}
const canvas=document.createElement("canvas");let barcodeArea;if(this.cropArea&&(this.cropArea.x||this.cropArea.y)){barcodeArea=this.cropArea;}else{barcodeArea={x:0,y:0,width:video.videoWidth,height:video.videoHeight,};}
canvas.width=barcodeArea.width;canvas.height=barcodeArea.height;const ctx=canvas.getContext("2d");ctx.drawImage(video,barcodeArea.x,barcodeArea.y,barcodeArea.width,barcodeArea.height,0,0,barcodeArea.width,barcodeArea.height);const luminanceSource=new ZXing.HTMLCanvasElementLuminanceSource(canvas);const binaryBitmap=new ZXing.BinaryBitmap(new ZXing.HybridBinarizer(luminanceSource));try{const result=this.reader.decodeWithState(binaryBitmap);const{resultPoints}=result;const boundingBox=DOMRectReadOnly.fromRect({x:resultPoints[0].x,y:resultPoints[0].y,height:Math.max(1,Math.abs(resultPoints[1].y-resultPoints[0].y)),width:Math.max(1,Math.abs(resultPoints[1].x-resultPoints[0].x)),});const cornerPoints=resultPoints;const format=Array.from(ZXingFormats).find(([k,val])=>val===result.getBarcodeFormat());const rawValue=result.getText();return[{boundingBox,cornerPoints,format,rawValue,},];}catch(err){if(err.name==="NotFoundException"){return[];}
throw err;}}
setCropArea(cropArea){this.cropArea=cropArea;}}
ZXingBarcodeDetector.getSupportedFormats=async()=>allSupportedFormats;return ZXingBarcodeDetector;}
const HAVE_NOTHING=0;const HAVE_METADATA=1;__exports.isVideoElementReady=isVideoElementReady;function isVideoElementReady(video){return![HAVE_NOTHING,HAVE_METADATA].includes(video.readyState);}
return __exports;});;

/* /web/static/src/core/barcode/barcode_dialog.js */
odoo.define('@web/core/barcode/barcode_dialog',['@web/core/l10n/translation','@web/core/dialog/dialog','@odoo/owl','@web/core/barcode/barcode_video_scanner'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{Dialog}=require("@web/core/dialog/dialog");const{Component,useState}=require("@odoo/owl");const{BarcodeVideoScanner,isBarcodeScannerSupported}=require("@web/core/barcode/barcode_video_scanner");const BarcodeDialog=__exports.BarcodeDialog=class BarcodeDialog extends Component{static template="web.BarcodeDialog";static components={BarcodeVideoScanner,Dialog,};static props=["facingMode","close","onResult","onError"];setup(){this.state=useState({barcodeScannerSupported:isBarcodeScannerSupported(),errorMessage:_t("Check your browser permissions"),});}
onResult(result){this.props.close();this.props.onResult(result);}
onError(error){this.state.barcodeScannerSupported=false;this.state.errorMessage=error.message;}}
__exports.scanBarcode=scanBarcode;async function scanBarcode(env,facingMode="environment"){let res;let rej;const promise=new Promise((resolve,reject)=>{res=resolve;rej=reject;});env.services.dialog.add(BarcodeDialog,{facingMode,onResult:(result)=>res(result),onError:(error)=>rej(error),});return promise;}
return __exports;});;

/* /web/static/src/core/barcode/barcode_video_scanner.js */
odoo.define('@web/core/barcode/barcode_video_scanner',['@web/core/browser/browser','@web/core/utils/concurrency','@web/core/assets','@web/core/barcode/ZXingBarcodeDetector','@web/core/barcode/crop_overlay','@odoo/owl','@web/core/l10n/translation','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{delay}=require("@web/core/utils/concurrency");const{loadJS}=require("@web/core/assets");const{isVideoElementReady,buildZXingBarcodeDetector}=require("@web/core/barcode/ZXingBarcodeDetector");const{CropOverlay}=require("@web/core/barcode/crop_overlay");const{Component,onMounted,onWillStart,onWillUnmount,status,useRef,useState}=require("@odoo/owl");const{_t}=require("@web/core/l10n/translation");const{pick}=require("@web/core/utils/objects");const BarcodeVideoScanner=__exports.BarcodeVideoScanner=class BarcodeVideoScanner extends Component{static template="web.BarcodeVideoScanner";static components={CropOverlay,};static props={cssClass:{type:String,optional:true},facingMode:{type:String,validate:(fm)=>["environment","left","right","user"].includes(fm),},close:{type:Function,optional:true},onReady:{type:Function,optional:true},onResult:Function,onError:Function,delayBetweenScan:{type:Number,optional:true},};static defaultProps={cssClass:"w-100 h-100",};setup(){this.videoPreviewRef=useRef("videoPreview");this.detectorTimeout=null;this.stream=null;this.detector=null;this.overlayInfo={};this.zoomRatio=1;this.scanPaused=false;this.state=useState({isReady:false,});onWillStart(async()=>{let DetectorClass;if("BarcodeDetector"in window){DetectorClass=BarcodeDetector;}else{await loadJS("/web/static/lib/zxing-library/zxing-library.js");DetectorClass=buildZXingBarcodeDetector(window.ZXing);}
const formats=await DetectorClass.getSupportedFormats();this.detector=new DetectorClass({formats});});onMounted(async()=>{const constraints={video:{facingMode:this.props.facingMode},audio:false,};try{this.stream=await browser.navigator.mediaDevices.getUserMedia(constraints);}catch(err){const errors={NotFoundError:_t("No device can be found."),NotAllowedError:_t("Odoo needs your authorization first."),};const errorMessage=_t("Could not start scanning. %(message)s",{message:errors[err.name]||err.message,});this.props.onError(new Error(errorMessage));return;}
if(!this.videoPreviewRef.el){this.cleanStreamAndTimeout();const errorMessage=_t("Barcode Video Scanner could not be mounted properly.");this.props.onError(new Error(errorMessage));return;}
this.videoPreviewRef.el.srcObject=this.stream;const ready=await this.isVideoReady();if(!ready){return;}
const{height,width}=getComputedStyle(this.videoPreviewRef.el);const divWidth=width.slice(0,-2);const divHeight=height.slice(0,-2);const tracks=this.stream.getVideoTracks();if(tracks.length){const[track]=tracks;const settings=track.getSettings();this.zoomRatio=Math.min(divWidth/settings.width,divHeight/settings.height);}
this.detectorTimeout=setTimeout(this.detectCode.bind(this),100);});onWillUnmount(()=>this.cleanStreamAndTimeout());}
cleanStreamAndTimeout(){clearTimeout(this.detectorTimeout);this.detectorTimeout=null;if(this.stream){this.stream.getTracks().forEach((track)=>track.stop());this.stream=null;}}
isZXingBarcodeDetector(){return this.detector&&this.detector.__proto__.constructor.name==="ZXingBarcodeDetector";}
async isVideoReady(){while(!isVideoElementReady(this.videoPreviewRef.el)){await delay(10);if(status(this)==="destroyed"){return false;}}
this.state.isReady=true;if(this.props.onReady){this.props.onReady();}
return true;}
onResize(overlayInfo){this.overlayInfo=overlayInfo;if(this.isZXingBarcodeDetector()){this.detector.setCropArea(this.adaptValuesWithRatio(this.overlayInfo,true));}}
async detectCode(){let barcodeDetected=false;let codes=[];try{codes=await this.detector.detect(this.videoPreviewRef.el);}catch(err){this.props.onError(err);}
for(const code of codes){if(!this.isZXingBarcodeDetector()&&this.overlayInfo.x!==undefined&&this.overlayInfo.y!==undefined){const{x,y,width,height}=this.adaptValuesWithRatio(code.boundingBox);if(x<this.overlayInfo.x||x+width>this.overlayInfo.x+this.overlayInfo.width||y<this.overlayInfo.y||y+height>this.overlayInfo.y+this.overlayInfo.height){continue;}}
barcodeDetected=true;this.barcodeDetected(code.rawValue);break;}
if(this.stream&&(!barcodeDetected||!this.props.delayBetweenScan)){this.detectorTimeout=setTimeout(this.detectCode.bind(this),100);}}
barcodeDetected(barcode){if(this.props.delayBetweenScan&&!this.scanPaused){this.scanPaused=true;this.detectorTimeout=setTimeout(()=>{this.scanPaused=false;this.detectorTimeout=setTimeout(this.detectCode.bind(this),100);},this.props.delayBetweenScan);}
this.props.onResult(barcode);}
adaptValuesWithRatio(domRect,dividerRatio=false){const newObject=pick(domRect,"x","y","width","height");for(const key of Object.keys(newObject)){if(dividerRatio){newObject[key]/=this.zoomRatio;}else{newObject[key]*=this.zoomRatio;}}
return newObject;}}
__exports.isBarcodeScannerSupported=isBarcodeScannerSupported;function isBarcodeScannerSupported(){return Boolean(browser.navigator.mediaDevices&&browser.navigator.mediaDevices.getUserMedia);}
return __exports;});;

/* /web/static/src/core/barcode/crop_overlay.js */
odoo.define('@web/core/barcode/crop_overlay',['@odoo/owl','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/utils/numbers'],function(require){'use strict';let __exports={};const{Component,useRef,onPatched}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{isIOS}=require("@web/core/browser/feature_detection");const{clamp}=require("@web/core/utils/numbers");const CropOverlay=__exports.CropOverlay=class CropOverlay extends Component{static template="web.CropOverlay";static props={onResize:Function,isReady:Boolean,slots:{type:Object,shape:{default:{},},},};setup(){this.localStorageKey="o-barcode-scanner-overlay";this.cropContainerRef=useRef("crop-container");this.isMoving=false;this.boundaryOverlay={};this.relativePosition={x:0,y:0,};onPatched(()=>{this.setupCropRect();});this.isIOS=isIOS();}
setupCropRect(){if(!this.props.isReady){return;}
this.computeDefaultPoint();this.computeOverlayPosition();this.calculateAndSetTransparentRect();this.executeOnResizeCallback();}
boundPoint(pointValue,boundaryRect){return{x:clamp(pointValue.x,boundaryRect.left,boundaryRect.left+boundaryRect.width),y:clamp(pointValue.y,boundaryRect.top,boundaryRect.top+boundaryRect.height),};}
calculateAndSetTransparentRect(){const cropTransparentRect=this.getTransparentRec(this.relativePosition,this.boundaryOverlay);this.setCropValue(cropTransparentRect,this.relativePosition);}
computeOverlayPosition(){const cropOverlayElement=this.cropContainerRef.el.querySelector(".o_crop_overlay");this.boundaryOverlay=cropOverlayElement.getBoundingClientRect();}
executeOnResizeCallback(){const transparentRec=this.getTransparentRec(this.relativePosition,this.boundaryOverlay);browser.localStorage.setItem(this.localStorageKey,JSON.stringify(transparentRec));this.props.onResize({...transparentRec,width:this.boundaryOverlay.width-2*transparentRec.x,height:this.boundaryOverlay.height-2*transparentRec.y,});}
computeDefaultPoint(){const firstChildComputedStyle=getComputedStyle(this.cropContainerRef.el.firstChild);const elementWidth=firstChildComputedStyle.width.slice(0,-2);const elementHeight=firstChildComputedStyle.height.slice(0,-2);const stringSavedPoint=browser.localStorage.getItem(this.localStorageKey);if(stringSavedPoint){const savedPoint=JSON.parse(stringSavedPoint);this.relativePosition={x:clamp(savedPoint.x,0,elementWidth),y:clamp(savedPoint.y,0,elementHeight),};}else{const stepWidth=elementWidth/10;const width=stepWidth*8;const height=width/4;const startY=elementHeight/2-height/2;this.relativePosition={x:stepWidth+width,y:startY+height,};}}
getTransparentRec(point,rect){const middleX=rect.width/2;const middleY=rect.height/2;const newDeltaX=Math.abs(point.x-middleX);const newDeltaY=Math.abs(point.y-middleY);return{x:middleX-newDeltaX,y:middleY-newDeltaY,};}
setCropValue(point,iconPoint){if(!iconPoint){iconPoint=point;}
this.cropContainerRef.el.style.setProperty("--o-crop-x",`${point.x}px`);this.cropContainerRef.el.style.setProperty("--o-crop-y",`${point.y}px`);this.cropContainerRef.el.style.setProperty("--o-crop-icon-x",`${iconPoint.x}px`);this.cropContainerRef.el.style.setProperty("--o-crop-icon-y",`${iconPoint.y}px`);}
pointerDown(event){event.preventDefault();if(event.target.matches(".o_crop_icon")){this.computeOverlayPosition();this.isMoving=true;}}
pointerMove(event){if(!this.isMoving){return;}
let eventPosition;if(event.touches&&event.touches.length){eventPosition=event.touches[0];}else{eventPosition=event;}
const{clientX,clientY}=eventPosition;const restrictedPosition=this.boundPoint({x:clientX,y:clientY,},this.boundaryOverlay);this.relativePosition={x:restrictedPosition.x-this.boundaryOverlay.left,y:restrictedPosition.y-this.boundaryOverlay.top,};this.calculateAndSetTransparentRect(this.relativePosition);}
pointerUp(event){this.isMoving=false;this.executeOnResizeCallback();}}
return __exports;});;

/* /web/static/src/core/browser/browser.js */
odoo.define('@web/core/browser/browser',[],function(require){'use strict';let __exports={};let sessionStorage;let localStorage;try{sessionStorage=window.sessionStorage;localStorage=window.localStorage;localStorage.setItem("__localStorage__","true");localStorage.removeItem("__localStorage__");}catch{localStorage=makeRAMLocalStorage();sessionStorage=makeRAMLocalStorage();}
const browser=__exports.browser={addEventListener:window.addEventListener.bind(window),dispatchEvent:window.dispatchEvent.bind(window),AnalyserNode:window.AnalyserNode,Audio:window.Audio,AudioBufferSourceNode:window.AudioBufferSourceNode,AudioContext:window.AudioContext,AudioWorkletNode:window.AudioWorkletNode,BeforeInstallPromptEvent:window.BeforeInstallPromptEvent?.bind(window),GainNode:window.GainNode,MediaStreamAudioSourceNode:window.MediaStreamAudioSourceNode,removeEventListener:window.removeEventListener.bind(window),setTimeout:window.setTimeout.bind(window),clearTimeout:window.clearTimeout.bind(window),setInterval:window.setInterval.bind(window),clearInterval:window.clearInterval.bind(window),performance:window.performance,requestAnimationFrame:window.requestAnimationFrame.bind(window),cancelAnimationFrame:window.cancelAnimationFrame.bind(window),console:window.console,history:window.history,matchMedia:window.matchMedia.bind(window),navigator,Notification:window.Notification,open:window.open.bind(window),SharedWorker:window.SharedWorker,Worker:window.Worker,XMLHttpRequest:window.XMLHttpRequest,localStorage,sessionStorage,fetch:window.fetch.bind(window),innerHeight:window.innerHeight,innerWidth:window.innerWidth,ontouchstart:window.ontouchstart,BroadcastChannel:window.BroadcastChannel,};Object.defineProperty(browser,"location",{set(val){window.location=val;},get(){return window.location;},configurable:true,});Object.defineProperty(browser,"innerHeight",{get:()=>window.innerHeight,configurable:true,});Object.defineProperty(browser,"innerWidth",{get:()=>window.innerWidth,configurable:true,});__exports.makeRAMLocalStorage=makeRAMLocalStorage;function makeRAMLocalStorage(){let store={};return{setItem(key,value){const newValue=String(value);store[key]=newValue;window.dispatchEvent(new StorageEvent("storage",{key,newValue}));},getItem(key){return store[key]??null;},clear(){store={};},removeItem(key){delete store[key];window.dispatchEvent(new StorageEvent("storage",{key,newValue:null}));},get length(){return Object.keys(store).length;},key(){return"";},};}
return __exports;});;

/* /web/static/src/core/browser/cookie.js */
odoo.define('@web/core/browser/cookie',[],function(require){'use strict';let __exports={};const COOKIE_TTL=24*60*60*365;const cookie=__exports.cookie={get _cookieMonster(){return document.cookie;},set _cookieMonster(value){document.cookie=value;},get(str){const parts=this._cookieMonster.split("; ");for(const part of parts){const[key,value]=part.split(/=(.*)/);if(key===str){return value||"";}}},set(key,value,ttl=COOKIE_TTL){let fullCookie=[];if(value!==undefined){fullCookie.push(`${key}=${value}`);}
fullCookie=fullCookie.concat(["path=/",`max-age=${Math.floor(ttl)}`]);this._cookieMonster=fullCookie.join("; ");},delete(key){this.set(key,"kill",0);},};return __exports;});;

/* /web/static/src/core/browser/feature_detection.js */
odoo.define('@web/core/browser/feature_detection',['@web/core/browser/browser'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");__exports.isBrowserChrome=isBrowserChrome;function isBrowserChrome(){return/Chrome/i.test(browser.navigator.userAgent);}
__exports.isBrowserFirefox=isBrowserFirefox;function isBrowserFirefox(){return/Firefox/i.test(browser.navigator.userAgent);}
__exports.isBrowserMicrosoftEdge=isBrowserMicrosoftEdge;function isBrowserMicrosoftEdge(){return/Edg/i.test(browser.navigator.userAgent);}
__exports.isBrowserSafari=isBrowserSafari;function isBrowserSafari(){return!isBrowserChrome()&&browser.navigator.userAgent?.includes("Safari");}
__exports.isAndroid=isAndroid;function isAndroid(){return/Android/i.test(browser.navigator.userAgent);}
__exports.isIOS=isIOS;function isIOS(){let isIOSPlatform=false;if("platform"in browser.navigator){isIOSPlatform=browser.navigator.platform==="MacIntel";}
return(/(iPad|iPhone|iPod)/i.test(browser.navigator.userAgent)||(isIOSPlatform&&maxTouchPoints()>1));}
__exports.isOtherMobileOS=isOtherMobileOS;function isOtherMobileOS(){return/(webOS|BlackBerry|Windows Phone)/i.test(browser.navigator.userAgent);}
__exports.isMacOS=isMacOS;function isMacOS(){return/Mac/i.test(browser.navigator.userAgent);}
__exports.isMobileOS=isMobileOS;function isMobileOS(){return isAndroid()||isIOS()||isOtherMobileOS();}
__exports.isIosApp=isIosApp;function isIosApp(){return/OdooMobile \(iOS\)/i.test(browser.navigator.userAgent);}
__exports.isAndroidApp=isAndroidApp;function isAndroidApp(){return/OdooMobile.+Android/i.test(browser.navigator.userAgent);}
__exports.isDisplayStandalone=isDisplayStandalone;function isDisplayStandalone(){return browser.matchMedia("(display-mode: standalone)").matches;}
__exports.hasTouch=hasTouch;function hasTouch(){return browser.ontouchstart!==undefined||browser.matchMedia("(pointer:coarse)").matches;}
__exports.maxTouchPoints=maxTouchPoints;function maxTouchPoints(){return browser.navigator.maxTouchPoints||1;}
return __exports;});;

/* /web/static/src/core/browser/title_service.js */
odoo.define('@web/core/browser/title_service',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const titleService=__exports.titleService={start(){const titleCounters={};const titleParts={};function getParts(){return Object.assign({},titleParts);}
function setCounters(counters){for(const key in counters){const val=counters[key];if(!val){delete titleCounters[key];}else{titleCounters[key]=val;}}
updateTitle();}
function setParts(parts){for(const key in parts){const val=parts[key];if(!val){delete titleParts[key];}else{titleParts[key]=val;}}
updateTitle();}
function updateTitle(){const counter=Object.values(titleCounters).reduce((acc,count)=>acc+count,0);const name=Object.values(titleParts).join(" - ")||"Odoo";if(!counter){document.title=name;}else{document.title=`(${counter}) ${name}`;}}
return{get current(){return document.title;},getParts,setCounters,setParts,};},};registry.category("services").add("title",titleService);return __exports;});;

/* /web/static/src/core/checkbox/checkbox.js */
odoo.define('@web/core/checkbox/checkbox',['@web/core/hotkeys/hotkey_hook','@odoo/owl'],function(require){'use strict';let __exports={};const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{Component,useRef}=require("@odoo/owl");const CheckBox=__exports.CheckBox=class CheckBox extends Component{static template="web.CheckBox";static nextId=1;static defaultProps={onChange:()=>{},};static props={id:{type:true,optional:true,},disabled:{type:Boolean,optional:true,},value:{type:Boolean,optional:true,},slots:{type:Object,optional:true,},onChange:{type:Function,optional:true,},className:{type:String,optional:true,},name:{type:String,optional:true,},};setup(){this.id=`checkbox-comp-${CheckBox.nextId++}`;this.rootRef=useRef("root");useHotkey("Enter",({area})=>{const oldValue=area.querySelector("input").checked;this.props.onChange(!oldValue);},{area:()=>this.rootRef.el,bypassEditableProtection:true});}
onClick(ev){if(ev.composedPath().find((el)=>["INPUT","LABEL"].includes(el.tagName))){ev.stopPropagation();return;}
const input=this.rootRef.el.querySelector("input");input.focus();if(!this.props.disabled){ev.stopPropagation();input.checked=!input.checked;this.props.onChange(input.checked);}}
onChange(ev){if(!this.props.disabled){this.props.onChange(ev.target.checked);}}}
return __exports;});;

/* /web/static/src/core/code_editor/code_editor.js */
odoo.define('@web/core/code_editor/code_editor',['@odoo/owl','@web/core/assets','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillDestroy,onWillStart,status,useEffect,useRef,useState,}=require("@odoo/owl");const{loadBundle}=require("@web/core/assets");const{useDebounced}=require("@web/core/utils/timing");function onResized(ref,callback){const _ref=typeof ref==="string"?useRef(ref):ref;const resizeObserver=new ResizeObserver(callback);useEffect((el)=>{if(el){resizeObserver.observe(el);return()=>resizeObserver.unobserve(el);}},()=>[_ref.el]);onWillDestroy(()=>{resizeObserver.disconnect();});}
const CodeEditor=__exports.CodeEditor=class CodeEditor extends Component{static template="web.CodeEditor";static components={};static props={mode:{type:String,optional:true,validate:(mode)=>CodeEditor.MODES.includes(mode),},value:{validate:(v)=>typeof v==="string",optional:true},readonly:{type:Boolean,optional:true},onChange:{type:Function,optional:true},onBlur:{type:Function,optional:true},class:{type:String,optional:true},theme:{type:String,optional:true,validate:(theme)=>CodeEditor.THEMES.includes(theme),},maxLines:{type:Number,optional:true},sessionId:{type:[Number,String],optional:true},initialCursorPosition:{type:Object,optional:true},};static defaultProps={readonly:false,value:"",onChange:()=>{},class:"",theme:"",sessionId:1,};static MODES=["javascript","xml","qweb","scss","python"];static THEMES=["","monokai"];setup(){this.editorRef=useRef("editorRef");this.state=useState({activeMode:undefined,});onWillStart(async()=>await loadBundle("web.ace_lib"));const sessions={};let ignoredAceChange=false;useEffect((el)=>{if(!el){return;}
const aceEditor=window.ace.edit(el);this.aceEditor=aceEditor;this.aceEditor.setOptions({maxLines:this.props.maxLines,showPrintMargin:false,useWorker:false,});this.aceEditor.$blockScrolling=true;this.aceEditor.on("changeMode",()=>{this.state.activeMode=this.aceEditor.getSession().$modeId.split("/").at(-1);});const session=aceEditor.getSession();if(!sessions[this.props.sessionId]){sessions[this.props.sessionId]=session;}
session.setValue(this.props.value);session.on("change",()=>{if(this.props.onChange&&!ignoredAceChange){this.props.onChange(this.aceEditor.getValue(),this.aceEditor.getCursorPosition());}});this.aceEditor.on("blur",()=>{if(this.props.onBlur){this.props.onBlur();}});return()=>{aceEditor.destroy();};},()=>[this.editorRef.el]);useEffect((theme)=>this.aceEditor.setTheme(theme?`ace/theme/${theme}`:""),()=>[this.props.theme]);useEffect((readonly)=>{this.aceEditor.setOptions({readOnly:readonly,highlightActiveLine:!readonly,highlightGutterLine:!readonly,});this.aceEditor.renderer.setOptions({displayIndentGuides:!readonly,showGutter:!readonly,});this.aceEditor.renderer.$cursorLayer.element.style.display=readonly?"none":"block";},()=>[this.props.readonly]);useEffect((sessionId,mode,value)=>{let session=sessions[sessionId];if(session){if(session.getValue()!==value){ignoredAceChange=true;session.setValue(value);ignoredAceChange=false;}}else{session=new window.ace.EditSession(value);session.setUndoManager(new window.ace.UndoManager());session.setOptions({useWorker:false,tabSize:2,useSoftTabs:true,});session.on("change",()=>{if(this.props.onChange&&!ignoredAceChange){this.props.onChange(this.aceEditor.getValue(),this.aceEditor.getCursorPosition());}});sessions[sessionId]=session;}
session.setMode(mode?`ace/mode/${mode}`:"");this.aceEditor.setSession(session);},()=>[this.props.sessionId,this.props.mode,this.props.value]);const debouncedResize=useDebounced(()=>{if(this.aceEditor){this.aceEditor.resize();}},250);onResized(this.editorRef,debouncedResize);const initialCursorPosition=this.props.initialCursorPosition;if(initialCursorPosition){onMounted(()=>{window.requestAnimationFrame(()=>{if(status(this)!="destroyed"&&this.aceEditor){this.aceEditor.focus();const{row,column}=initialCursorPosition;const pos={row:row||0,column:column||0,};this.aceEditor.selection.moveToPosition(pos);this.aceEditor.renderer.scrollCursorIntoView(pos,0.5);}});});}}}
return __exports;});;

/* /web/static/src/core/colorlist/colorlist.js */
odoo.define('@web/core/colorlist/colorlist',['@web/core/l10n/translation','@odoo/owl'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{Component,useRef,useState,useExternalListener}=require("@odoo/owl");const ColorList=__exports.ColorList=class ColorList extends Component{static COLORS=[_t("No color"),_t("Red"),_t("Orange"),_t("Yellow"),_t("Cyan"),_t("Purple"),_t("Almond"),_t("Teal"),_t("Blue"),_t("Raspberry"),_t("Green"),_t("Violet"),];static template="web.ColorList";static defaultProps={forceExpanded:false,isExpanded:false,};static props={canToggle:{type:Boolean,optional:true},colors:Array,forceExpanded:{type:Boolean,optional:true},isExpanded:{type:Boolean,optional:true},onColorSelected:Function,selectedColor:{type:Number,optional:true},};setup(){this.colorlistRef=useRef("colorlist");this.state=useState({isExpanded:this.props.isExpanded});useExternalListener(window,"click",this.onOutsideClick);}
get colors(){return this.constructor.COLORS;}
onColorSelected(id){this.props.onColorSelected(id);if(!this.props.forceExpanded){this.state.isExpanded=false;}}
onOutsideClick(ev){if(this.colorlistRef.el.contains(ev.target)||this.props.forceExpanded){return;}
this.state.isExpanded=false;}
onToggle(ev){if(this.props.canToggle){ev.preventDefault();ev.stopPropagation();this.state.isExpanded=!this.state.isExpanded;this.colorlistRef.el.firstElementChild.focus();}}}
return __exports;});;

/* /web/static/src/core/colorpicker/colorpicker.js */
odoo.define('@web/core/colorpicker/colorpicker',['@web/core/utils/colors','@web/core/utils/functions','@web/core/utils/numbers','@web/core/utils/timing','@odoo/owl'],function(require){'use strict';let __exports={};const{convertCSSColorToRgba,convertHslToRgb,convertRgbaToCSSColor,convertRgbToHsl,normalizeCSSColor,}=require("@web/core/utils/colors");const{uniqueId}=require("@web/core/utils/functions");const{clamp}=require("@web/core/utils/numbers");const{debounce,useThrottleForAnimation}=require("@web/core/utils/timing");const{Component,onMounted,onWillUpdateProps,useExternalListener,useRef}=require("@odoo/owl");const DEFAULT_COLOR="#FF0000";const Colorpicker=__exports.Colorpicker=class Colorpicker extends Component{static template="web.Colorpicker";static props={document:{type:true,optional:true},defaultColor:{type:String,optional:true},selectedColor:{type:String,optional:true},noTransparency:{type:Boolean,optional:true},stopClickPropagation:{type:Boolean,optional:true},onColorSelect:{type:Function,optional:true},onColorPreview:{type:Function,optional:true},onInputEnter:{type:Function,optional:true},};static defaultProps={document:window.document,defaultColor:DEFAULT_COLOR,noTransparency:false,stopClickPropagation:false,onColorSelect:()=>{},onColorPreview:()=>{},onInputEnter:()=>{},};setup(){this.pickerFlag=false;this.sliderFlag=false;this.opacitySliderFlag=false;this.colorComponents={};this.uniqueId=uniqueId("colorpicker");this.selectedHexValue="";this.debouncedOnChangeInputs=debounce(this.onChangeInputs.bind(this),10,true);this.elRef=useRef("el");this.colorPickerAreaRef=useRef("colorPickerArea");this.colorPickerPointerRef=useRef("colorPickerPointer");this.colorSliderRef=useRef("colorSlider");this.colorSliderPointerRef=useRef("colorSliderPointer");this.opacitySliderRef=useRef("opacitySlider");this.opacitySliderPointerRef=useRef("opacitySliderPointer");const documents=[window.top,...Array.from(window.top.frames).filter((frame)=>{try{const document=frame.document;return!!document;}catch{return false;}}),].map((w)=>w.document);this.throttleOnMouseMove=useThrottleForAnimation((ev)=>{this.onMouseMovePicker(ev);this.onMouseMoveSlider(ev);this.onMouseMoveOpacitySlider(ev);});for(const doc of documents){useExternalListener(doc,"mousemove",this.throttleOnMouseMove);useExternalListener(doc,"mouseup",this.onMouseUp.bind(this));}
onMounted(async()=>{const defaultCssColor=this.props.selectedColor?this.props.selectedColor:this.props.defaultColor;const rgba=convertCSSColorToRgba(defaultCssColor)||convertCSSColorToRgba(DEFAULT_COLOR);if(rgba){this._updateRgba(rgba.red,rgba.green,rgba.blue,rgba.opacity);}
this.previewActive=true;this._updateUI();});onWillUpdateProps((newProps)=>{const newSelectedColor=newProps.selectedColor?newProps.selectedColor:newProps.defaultColor;if(normalizeCSSColor(newSelectedColor)!==this.colorComponents.cssColor){this.setSelectedColor(newSelectedColor);}});}
setSelectedColor(color){const rgba=convertCSSColorToRgba(color);if(rgba){const oldPreviewActive=this.previewActive;this.previewActive=false;this._updateRgba(rgba.red,rgba.green,rgba.blue,rgba.opacity);this.previewActive=oldPreviewActive;this._updateUI();}}
get el(){return this.elRef.el;}
_updateUI(){for(const[color,value]of Object.entries(this.colorComponents)){const input=this.el.querySelector(`.o_${color}_input`);if(input){input.value=value;}}
const colorPickerArea=this.colorPickerAreaRef.el;colorPickerArea.style.backgroundColor=`hsl(${this.colorComponents.hue}, 100%, 50%)`;const top=((100-this.colorComponents.lightness)*colorPickerArea.clientHeight)/100;const left=(this.colorComponents.saturation*colorPickerArea.clientWidth)/100;const colorpickerPointer=this.colorPickerPointerRef.el;colorpickerPointer.style.top=top-5+"px";colorpickerPointer.style.left=left-5+"px";const colorSlider=this.colorSliderRef.el;const height=colorSlider.clientHeight;const y=(this.colorComponents.hue*height)/360;this.colorSliderPointerRef.el.style.top=`${Math.round(y - 2)}px`;if(!this.props.noTransparency){const opacitySlider=this.opacitySliderRef.el;const heightOpacity=opacitySlider.clientHeight;const z=heightOpacity*(1-this.colorComponents.opacity/100.0);this.opacitySliderPointerRef.el.style.top=`${Math.round(z - 2)}px`;opacitySlider.style.background=`linear-gradient(${this.colorComponents.hex} 0%, transparent 100%)`;}}
_updateHex(hex){const rgb=convertCSSColorToRgba(hex);if(!rgb){return;}
Object.assign(this.colorComponents,{hex:hex},rgb,convertRgbToHsl(rgb.red,rgb.green,rgb.blue));this._updateCssColor();}
_updateRgba(r,g,b,a){const opacity=a||this.colorComponents.opacity;if(opacity<0.1&&(r>0.1||g>0.1||b>0.1)){a=100;}
const hex=convertRgbaToCSSColor(r,g,b);if(!hex){return;}
Object.assign(this.colorComponents,{red:r,green:g,blue:b},a===undefined?{}:{opacity:a},{hex:hex},convertRgbToHsl(r,g,b));this._updateCssColor();}
_updateHsl(h,s,l){let a=this.colorComponents.opacity;if(a<0.1&&l>0.1){a=100;}
const rgb=convertHslToRgb(h,s,l);if(!rgb){return;}
const hex=convertRgbaToCSSColor(rgb.red,rgb.green,rgb.blue);Object.assign(this.colorComponents,{hue:h,saturation:s,lightness:l},rgb,{hex:hex},{opacity:a});this._updateCssColor();}
_updateOpacity(a){if(a<0||a>100){return;}
Object.assign(this.colorComponents,{opacity:a});this._updateCssColor();}
_colorSelected(){this.props.onColorSelect(this.colorComponents);}
_updateCssColor(){const r=this.colorComponents.red;const g=this.colorComponents.green;const b=this.colorComponents.blue;const a=this.colorComponents.opacity;Object.assign(this.colorComponents,{cssColor:convertRgbaToCSSColor(r,g,b,a)});if(this.previewActive){this.props.onColorPreview(this.colorComponents);}}
onKeydown(ev){if(ev.key==="Enter"){if(ev.target.tagName==="INPUT"){this.onChangeInputs(ev);}
ev.preventDefault();this.props.onInputEnter(ev);}}
onClick(ev){if(this.props.stopClickPropagation){ev.stopPropagation();}
ev.__isColorpickerClick=true;if(ev.target.dataset.colorMethod==="hex"&&!this.selectedHexValue){ev.target.select();this.selectedHexValue=ev.target.value;return;}
this.selectedHexValue="";}
onMouseUp(){if(this.pickerFlag||this.sliderFlag||this.opacitySliderFlag){this._colorSelected();}
this.pickerFlag=false;this.sliderFlag=false;this.opacitySliderFlag=false;}
onMouseDownPicker(ev){this.pickerFlag=true;ev.preventDefault();this.onMouseMovePicker(ev);}
onMouseMovePicker(ev){if(!this.pickerFlag){return;}
const colorPickerArea=this.colorPickerAreaRef.el;const rect=colorPickerArea.getClientRects()[0];const top=ev.pageY-rect.top;const left=ev.pageX-rect.left;let saturation=Math.round((100*left)/colorPickerArea.clientWidth);let lightness=Math.round((100*(colorPickerArea.clientHeight-top))/colorPickerArea.clientHeight);saturation=clamp(saturation,0,100);lightness=clamp(lightness,0,100);this._updateHsl(this.colorComponents.hue,saturation,lightness);this._updateUI();}
onMouseDownSlider(ev){this.sliderFlag=true;ev.preventDefault();this.onMouseMoveSlider(ev);}
onMouseMoveSlider(ev){if(!this.sliderFlag){return;}
const colorSlider=this.colorSliderRef.el;const y=ev.pageY-colorSlider.getClientRects()[0].top;let hue=Math.round((360*y)/colorSlider.clientHeight);hue=clamp(hue,0,360);this._updateHsl(hue,this.colorComponents.saturation,this.colorComponents.lightness);this._updateUI();}
onMouseDownOpacitySlider(ev){this.opacitySliderFlag=true;ev.preventDefault();this.onMouseMoveOpacitySlider(ev);}
onMouseMoveOpacitySlider(ev){if(!this.opacitySliderFlag||this.props.noTransparency){return;}
const opacitySlider=this.opacitySliderRef.el;const y=ev.pageY-opacitySlider.getClientRects()[0].top;let opacity=Math.round(100*(1-y/opacitySlider.clientHeight));opacity=clamp(opacity,0,100);this._updateOpacity(opacity);this._updateUI();}
onChangeInputs(ev){switch(ev.target.dataset.colorMethod){case"hex":return;case"rgb":this._updateRgba(parseInt(this.el.querySelector(".o_red_input").value),parseInt(this.el.querySelector(".o_green_input").value),parseInt(this.el.querySelector(".o_blue_input").value));break;case"hsl":this._updateHsl(parseInt(this.el.querySelector(".o_hue_input").value),parseInt(this.el.querySelector(".o_saturation_input").value),parseInt(this.el.querySelector(".o_lightness_input").value));break;case"opacity":this._updateOpacity(parseInt(this.el.querySelector(".o_opacity_input").value));break;}
this._updateUI();this._colorSelected();}
onHexColorInput(ev){const hexColorValue=ev.target.value.replaceAll("#","");if(hexColorValue.length===6){this._updateHex(`#${hexColorValue}`);this._updateUI();this._colorSelected();}}}
return __exports;});;

/* /web/static/src/core/colors/colors.js */
odoo.define('@web/core/colors/colors',['@web/core/utils/numbers'],function(require){'use strict';let __exports={};const{clamp}=require("@web/core/utils/numbers");const COLORS_ENT_BRIGHT=["#875A7B","#A5D8D7","#DCD0D9"];const COLORS_ENT_DARK=["#6B3E66","#147875","#5A395A"];const COLORS_SM=["#4EA7F2","#EA6175","#43C5B1","#F4A261","#8481DD","#FFD86D",];const COLORS_MD=["#4EA7F2","#3188E6","#43C5B1","#00A78D","#EA6175","#CE4257","#F4A261","#F48935","#8481DD","#5752D1","#FFD86D","#FFBC2C",];const COLORS_LG=["#4EA7F2","#3188E6","#056BD9","#A76DBC","#7F4295","#6D2387","#EA6175","#CE4257","#982738","#43C5B1","#00A78D","#0E8270","#F4A261","#F48935","#BE5D10","#8481DD","#5752D1","#3A3580","#A4A8B6","#7E8290","#545B70","#FFD86D","#FFBC2C","#C08A16",];const COLORS_XL=["#4EA7F2","#3188E6","#056BD9","#155193","#A76DBC","#7F4295","#6D2387","#4F1565","#EA6175","#CE4257","#982738","#791B29","#43C5B1","#00A78D","#0E8270","#105F53","#F4A261","#F48935","#BE5D10","#7D380D","#8481DD","#5752D1","#3A3580","#26235F","#A4A8B6","#7E8290","#545B70","#3F4250","#FFD86D","#FFBC2C","#C08A16","#936A12",];__exports.getColors=getColors;function getColors(colorScheme,paletteName){switch(paletteName){case"odoo":return colorScheme==="dark"?COLORS_ENT_DARK:COLORS_ENT_BRIGHT;case"sm":return COLORS_SM;case"md":return COLORS_MD;case"lg":return COLORS_LG;default:return COLORS_XL;}}
__exports.getColor=getColor;function getColor(index,colorScheme,paletteSizeOrName){let paletteName;if(paletteSizeOrName==="odoo"){paletteName="odoo";}else if(paletteSizeOrName<=6||paletteSizeOrName==="sm"){paletteName="sm";}else if(paletteSizeOrName<=12||paletteSizeOrName==="md"){paletteName="md";}else if(paletteSizeOrName<=24||paletteSizeOrName==="lg"){paletteName="lg";}else{paletteName="xl";}
const colors=getColors(colorScheme,paletteName);return colors[index%colors.length];}
const DEFAULT_BG=__exports.DEFAULT_BG="#d3d3d3";__exports.getBorderWhite=getBorderWhite;function getBorderWhite(colorScheme){return colorScheme==="dark"?"rgba(38, 42, 54, .2)":"rgba(249,250,251, .2)";}
const RGB_REGEX=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;__exports.hexToRGBA=hexToRGBA;function hexToRGBA(hex,opacity){const rgb=RGB_REGEX.exec(hex).slice(1,4).map((n)=>parseInt(n,16)).join(",");return`rgba(${rgb},${opacity})`;}
__exports.getCustomColor=getCustomColor;function getCustomColor(colorScheme,brightModeColor,darkModeColor){if(darkModeColor===undefined){return brightModeColor;}else{return colorScheme==="dark"?darkModeColor:brightModeColor;}}
__exports.lightenColor=lightenColor;function lightenColor(color,factor){factor=clamp(factor,0,1);let r=parseInt(color.substring(1,3),16);let g=parseInt(color.substring(3,5),16);let b=parseInt(color.substring(5,7),16);r=Math.round(r+(255-r)*factor);g=Math.round(g+(255-g)*factor);b=Math.round(b+(255-b)*factor);r=r.toString(16).padStart(2,"0");g=g.toString(16).padStart(2,"0");b=b.toString(16).padStart(2,"0");return`#${r}${g}${b}`;}
__exports.darkenColor=darkenColor;function darkenColor(color,factor){factor=clamp(factor,0,1);let r=parseInt(color.substring(1,3),16);let g=parseInt(color.substring(3,5),16);let b=parseInt(color.substring(5,7),16);r=Math.round(r*(1-factor));g=Math.round(g*(1-factor));b=Math.round(b*(1-factor));r=r.toString(16).padStart(2,"0");g=g.toString(16).padStart(2,"0");b=b.toString(16).padStart(2,"0");return`#${r}${g}${b}`;}
return __exports;});;

/* /web/static/src/core/commands/command_category.js */
odoo.define('@web/core/commands/command_category',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const commandCategoryRegistry=registry.category("command_categories");commandCategoryRegistry.add("app",{},{sequence:10}).add("smart_action",{},{sequence:15}).add("actions",{},{sequence:30}).add("default",{},{sequence:50}).add("view_switcher",{},{sequence:100}).add("debug",{},{sequence:110}).add("disabled",{});return __exports;});;

/* /web/static/src/core/commands/command_hook.js */
odoo.define('@web/core/commands/command_hook',['@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{useEffect}=require("@odoo/owl");__exports.useCommand=useCommand;function useCommand(name,action,options={}){const commandService=useService("command");useEffect(()=>commandService.add(name,action,options),()=>[]);}
return __exports;});;

/* /web/static/src/core/commands/command_palette.js */
odoo.define('@web/core/commands/command_palette',['@web/core/dialog/dialog','@web/core/hotkeys/hotkey_hook','@web/core/l10n/translation','@web/core/utils/concurrency','@web/core/utils/hooks','@web/core/utils/scrolling','@web/core/utils/search','@web/core/utils/timing','@web/core/browser/feature_detection','@web/core/utils/strings','@odoo/owl'],function(require){'use strict';let __exports={};const{Dialog}=require("@web/core/dialog/dialog");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{_t}=require("@web/core/l10n/translation");const{KeepLast,Race}=require("@web/core/utils/concurrency");const{useAutofocus,useService}=require("@web/core/utils/hooks");const{scrollTo}=require("@web/core/utils/scrolling");const{fuzzyLookup}=require("@web/core/utils/search");const{debounce}=require("@web/core/utils/timing");const{isMacOS,isMobileOS}=require("@web/core/browser/feature_detection");const{escapeRegExp}=require("@web/core/utils/strings");const{Component,onWillStart,onWillDestroy,EventBus,useRef,useState,markRaw,useExternalListener,}=require("@odoo/owl");const DEFAULT_PLACEHOLDER=_t("Search...");const DEFAULT_EMPTY_MESSAGE=_t("No result found");const FUZZY_NAMESPACES=["default"];function commandsWithinCategory(categoryName,categories){return(cmd)=>{const inCurrentCategory=categoryName===cmd.category;const fallbackCategory=categoryName==="default"&&!categories.includes(cmd.category);return inCurrentCategory||fallbackCategory;};}
__exports.splitCommandName=splitCommandName;function splitCommandName(name,searchValue){if(name){const splitName=name.split(new RegExp(`(${escapeRegExp(searchValue)})`,"ig"));return searchValue.length&&splitName.length>1?splitName:[name];}
return[];}
const DefaultCommandItem=__exports.DefaultCommandItem=class DefaultCommandItem extends Component{static template="web.DefaultCommandItem";static props={slots:{type:Object,optional:true},hotkey:{type:String,optional:true},hotkeyOptions:{type:String,optional:true},name:{type:String,optional:true},searchValue:{type:String,optional:true},executeCommand:{type:Function,optional:true},};}
const CommandPalette=__exports.CommandPalette=class CommandPalette extends Component{static template="web.CommandPalette";static components={Dialog};static lastSessionId=0;static props={bus:{type:EventBus,optional:true},close:Function,config:Object,closeMe:{type:Function,optional:true},};setup(){if(this.props.bus){const setConfig=({detail})=>this.setCommandPaletteConfig(detail);this.props.bus.addEventListener(`SET-CONFIG`,setConfig);onWillDestroy(()=>this.props.bus.removeEventListener(`SET-CONFIG`,setConfig));}
this.keyId=1;this.race=new Race();this.keepLast=new KeepLast();this._sessionId=CommandPalette.lastSessionId++;this.DefaultCommandItem=DefaultCommandItem;this.activeElement=useService("ui").activeElement;this.inputRef=useAutofocus();useHotkey("Enter",()=>this.executeSelectedCommand(),{bypassEditableProtection:true});useHotkey("Control+Enter",()=>this.executeSelectedCommand(true),{bypassEditableProtection:true,});useHotkey("ArrowUp",()=>this.selectCommandAndScrollTo("PREV"),{bypassEditableProtection:true,allowRepeat:true,});useHotkey("ArrowDown",()=>this.selectCommandAndScrollTo("NEXT"),{bypassEditableProtection:true,allowRepeat:true,});useExternalListener(window,"mousedown",this.onWindowMouseDown);this.state=useState({});this.root=useRef("root");this.listboxRef=useRef("listbox");onWillStart(()=>this.setCommandPaletteConfig(this.props.config));}
get commandsByCategory(){const categories=[];for(const category of this.categoryKeys){const commands=this.state.commands.filter(commandsWithinCategory(category,this.categoryKeys));if(commands.length){categories.push({commands,name:this.categoryNames[category],keyId:category,});}}
return categories;}
async setCommandPaletteConfig(config){this.configByNamespace=config.configByNamespace||{};this.state.FooterComponent=config.FooterComponent;this.providersByNamespace={default:[]};for(const provider of config.providers){const namespace=provider.namespace||"default";if(namespace in this.providersByNamespace){this.providersByNamespace[namespace].push(provider);}else{this.providersByNamespace[namespace]=[provider];}}
const{namespace,searchValue}=this.processSearchValue(config.searchValue||"");this.switchNamespace(namespace);this.state.searchValue=searchValue;await this.race.add(this.search(searchValue));}
async setCommands(namespace,options={}){this.categoryKeys=["default"];this.categoryNames={};const proms=this.providersByNamespace[namespace].map((provider)=>{const{provide}=provider;const result=provide(this.env,options);return result;});let commands=(await this.keepLast.add(Promise.all(proms))).flat();const namespaceConfig=this.configByNamespace[namespace]||{};if(options.searchValue&&FUZZY_NAMESPACES.includes(namespace)){commands=fuzzyLookup(options.searchValue,commands,(c)=>c.name);}else{if(namespaceConfig.categories){let commandsSorted=[];this.categoryKeys=namespaceConfig.categories;this.categoryNames=namespaceConfig.categoryNames||{};if(!this.categoryKeys.includes("default")){this.categoryKeys.push("default");}
for(const category of this.categoryKeys){commandsSorted=commandsSorted.concat(commands.filter(commandsWithinCategory(category,this.categoryKeys)));}
commands=commandsSorted;}}
this.state.commands=markRaw(commands.slice(0,100).map((command)=>({...command,keyId:this.keyId++,splitName:splitCommandName(command.name,options.searchValue),})));this.selectCommand(this.state.commands.length?0:-1);this.mouseSelectionActive=false;this.state.emptyMessage=(namespaceConfig.emptyMessage||DEFAULT_EMPTY_MESSAGE).toString();}
selectCommand(index){if(index===-1||index>=this.state.commands.length){this.state.selectedCommand=null;return;}
this.state.selectedCommand=markRaw(this.state.commands[index]);}
selectCommandAndScrollTo(type){this.mouseSelectionActive=false;const index=this.state.commands.indexOf(this.state.selectedCommand);if(index===-1){return;}
let nextIndex;if(type==="NEXT"){nextIndex=index<this.state.commands.length-1?index+1:0;}else if(type==="PREV"){nextIndex=index>0?index-1:this.state.commands.length-1;}
this.selectCommand(nextIndex);const command=this.listboxRef.el.querySelector(`#o_command_${nextIndex}`);scrollTo(command,{scrollable:this.listboxRef.el});}
onCommandClicked(event,index){event.preventDefault();this.selectCommand(index);const ctrlKey=isMacOS()?event.metaKey:event.ctrlKey;this.executeSelectedCommand(ctrlKey);}
async executeCommand(command){const config=await command.action();if(config){this.setCommandPaletteConfig(config);}else{this.props.close();}}
async executeSelectedCommand(ctrlKey){await this.searchValuePromise;const selectedCommand=this.state.selectedCommand;if(selectedCommand){if(!ctrlKey){this.executeCommand(selectedCommand);}else if(selectedCommand.href){window.open(selectedCommand.href,"_blank");}}}
onCommandMouseEnter(index){if(this.mouseSelectionActive){this.selectCommand(index);}else{this.mouseSelectionActive=true;}}
async search(searchValue){this.state.isLoading=true;try{await this.setCommands(this.state.namespace,{searchValue,activeElement:this.activeElement,sessionId:this._sessionId,});}finally{this.state.isLoading=false;}
if(this.inputRef.el){this.inputRef.el.focus();}}
debounceSearch(value){const{namespace,searchValue}=this.processSearchValue(value);if(namespace!=="default"&&this.state.namespace!==namespace){this.switchNamespace(namespace);}
this.state.searchValue=searchValue;this.searchValuePromise=this.lastDebounceSearch(searchValue).catch(()=>{this.searchValuePromise=null;});}
onSearchInput(ev){this.debounceSearch(ev.target.value);}
onKeyDown(ev){if(ev.key.toLowerCase()==="backspace"&&!ev.target.value.length&&!ev.repeat){this.switchNamespace("default");this.state.searchValue="";this.searchValuePromise=this.lastDebounceSearch("").catch(()=>{this.searchValuePromise=null;});}}
onWindowMouseDown(ev){if(!this.root.el.contains(ev.target)){this.props.close();}}
switchNamespace(namespace){if(this.lastDebounceSearch){this.lastDebounceSearch.cancel();}
const namespaceConfig=this.configByNamespace[namespace]||{};this.lastDebounceSearch=debounce((value)=>this.search(value),namespaceConfig.debounceDelay||0);this.state.namespace=namespace;this.state.placeholder=namespaceConfig.placeholder||DEFAULT_PLACEHOLDER.toString();}
processSearchValue(searchValue){let namespace="default";if(searchValue.length&&this.providersByNamespace[searchValue[0]]){namespace=searchValue[0];searchValue=searchValue.slice(1);}
return{namespace,searchValue};}
get isMacOS(){return isMacOS();}
get isMobileOS(){return isMobileOS();}}
return __exports;});;

/* /web/static/src/core/commands/command_service.js */
odoo.define('@web/core/commands/command_service',['@web/core/registry','@web/core/commands/command_palette','@odoo/owl'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{CommandPalette}=require("@web/core/commands/command_palette");const{Component,EventBus}=require("@odoo/owl");const commandCategoryRegistry=registry.category("command_categories");const commandProviderRegistry=registry.category("command_provider");const commandSetupRegistry=registry.category("command_setup");class DefaultFooter extends Component{static template="web.DefaultFooter";static props={switchNamespace:{type:Function},};setup(){this.elements=commandSetupRegistry.getEntries().map((el)=>({namespace:el[0],name:el[1].name})).filter((el)=>el.name);}
onClick(namespace){this.props.switchNamespace(namespace);}}
const commandService=__exports.commandService={dependencies:["dialog","hotkey","ui"],start(env,{dialog,hotkey:hotkeyService,ui}){const registeredCommands=new Map();let nextToken=0;let isPaletteOpened=false;const bus=new EventBus();hotkeyService.add("control+k",openMainPalette,{bypassEditableProtection:true,global:true,});function openMainPalette(config={},onClose){const configByNamespace={};for(const provider of commandProviderRegistry.getAll()){const namespace=provider.namespace||"default";if(!configByNamespace[namespace]){configByNamespace[namespace]={categories:[],categoryNames:{},};}}
for(const[category,el]of commandCategoryRegistry.getEntries()){const namespace=el.namespace||"default";const name=el.name;if(namespace in configByNamespace){configByNamespace[namespace].categories.push(category);configByNamespace[namespace].categoryNames[category]=name;}}
for(const[namespace,{emptyMessage,debounceDelay,placeholder},]of commandSetupRegistry.getEntries()){if(namespace in configByNamespace){if(emptyMessage){configByNamespace[namespace].emptyMessage=emptyMessage;}
if(debounceDelay!==undefined){configByNamespace[namespace].debounceDelay=debounceDelay;}
if(placeholder){configByNamespace[namespace].placeholder=placeholder;}}}
config=Object.assign({configByNamespace,FooterComponent:DefaultFooter,providers:commandProviderRegistry.getAll(),},config);return openPalette(config,onClose);}
function openPalette(config,onClose){if(isPaletteOpened){bus.trigger("SET-CONFIG",config);return;}
isPaletteOpened=true;dialog.add(CommandPalette,{config,bus,},{onClose:()=>{isPaletteOpened=false;if(onClose){onClose();}},});}
function registerCommand(command,options){if(!command.name||!command.action||typeof command.action!=="function"){throw new Error("A Command must have a name and an action function.");}
const registration=Object.assign({},command,options);if(registration.identifier){const commandsArray=Array.from(registeredCommands.values());const sameName=commandsArray.find((com)=>com.name===registration.name);if(sameName){if(registration.identifier!==sameName.identifier){registration.name+=` (${registration.identifier})`;sameName.name+=` (${sameName.identifier})`;}}else{const sameFullName=commandsArray.find((com)=>com.name===registration.name+`(${registration.identifier})`);if(sameFullName){registration.name+=` (${registration.identifier})`;}}}
if(registration.hotkey){const action=async()=>{const commandService=env.services.command;const config=await command.action();if(!isPaletteOpened&&config){commandService.openPalette(config);}};registration.removeHotkey=hotkeyService.add(registration.hotkey,action,{...options.hotkeyOptions,global:registration.global,isAvailable:(...args)=>{let available=true;if(registration.isAvailable){available=registration.isAvailable(...args);}
if(available&&options.hotkeyOptions?.isAvailable){available=options.hotkeyOptions?.isAvailable(...args);}
return available;},});}
const token=nextToken++;registeredCommands.set(token,registration);if(!options.activeElement){Promise.resolve().then(()=>{registration.activeElement=ui.activeElement;});}
return token;}
function unregisterCommand(token){const cmd=registeredCommands.get(token);if(cmd&&cmd.removeHotkey){cmd.removeHotkey();}
registeredCommands.delete(token);}
return{add(name,action,options={}){const token=registerCommand({name,action},options);return()=>{unregisterCommand(token);};},getCommands(activeElement){return[...registeredCommands.values()].filter((command)=>command.activeElement===activeElement||command.global);},openMainPalette,openPalette,};},};registry.category("services").add("command",commandService);return __exports;});;

/* /web/static/src/core/commands/default_providers.js */
odoo.define('@web/core/commands/default_providers',['@web/core/browser/feature_detection','@web/core/hotkeys/hotkey_hook','@web/core/l10n/translation','@web/core/registry','@web/core/utils/strings','@web/core/utils/ui','@web/core/commands/command_palette','@odoo/owl'],function(require){'use strict';let __exports={};const{isMacOS}=require("@web/core/browser/feature_detection");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{_t}=require("@web/core/l10n/translation");const{registry}=require("@web/core/registry");const{capitalize}=require("@web/core/utils/strings");const{getVisibleElements}=require("@web/core/utils/ui");const{DefaultCommandItem}=require("@web/core/commands/command_palette");const{Component}=require("@odoo/owl");const commandSetupRegistry=registry.category("command_setup");commandSetupRegistry.add("default",{emptyMessage:_t("No command found"),placeholder:_t("Search for a command..."),});const HotkeyCommandItem=__exports.HotkeyCommandItem=class HotkeyCommandItem extends Component{static template="web.HotkeyCommandItem";static props=["hotkey","hotkeyOptions?","name?","searchValue?","executeCommand","slots"];setup(){useHotkey(this.props.hotkey,this.props.executeCommand);}
getKeysToPress(command){const{hotkey}=command;let result=hotkey.split("+");if(isMacOS()){result=result.map((x)=>x.replace("control","command")).map((x)=>x.replace("alt","control"));}
return result.map((key)=>key.toUpperCase());}}
const commandCategoryRegistry=registry.category("command_categories");const commandProviderRegistry=registry.category("command_provider");commandProviderRegistry.add("command",{provide:(env,options={})=>{const commands=env.services.command.getCommands(options.activeElement).map((cmd)=>{cmd.category=commandCategoryRegistry.contains(cmd.category)?cmd.category:"default";return cmd;}).filter((command)=>command.isAvailable===undefined||command.isAvailable());const uniqueCommands=commands.filter((obj,index)=>{return(index===commands.findIndex((o)=>obj.name===o.name&&obj.category===o.category));});return uniqueCommands.map((command)=>({Component:command.hotkey?HotkeyCommandItem:DefaultCommandItem,action:command.action,category:command.category,name:command.name,props:{hotkey:command.hotkey,hotkeyOptions:command.hotkeyOptions,},}));},});commandProviderRegistry.add("data-hotkeys",{provide:(env,options={})=>{const commands=[];const overlayModifier=registry.category("services").get("hotkey").overlayModifier;for(const el of getVisibleElements(options.activeElement,"[data-hotkey]:not(:disabled)")){const closest=el.closest("[data-command-category]");const category=closest?closest.dataset.commandCategory:"default";if(category==="disabled"){continue;}
const description=el.title||el.dataset.bsOriginalTitle||el.dataset.tooltip||el.placeholder||(el.innerText&&`${el.innerText.slice(0, 50)}${el.innerText.length > 50 ? "..." : ""}`)||_t("no description provided");commands.push({Component:HotkeyCommandItem,action:()=>{el.focus();el.click();},category,name:capitalize(description.trim().toLowerCase()),props:{hotkey:`${overlayModifier}+${el.dataset.hotkey}`,},});}
return commands;},});return __exports;});;

/* /web/static/src/core/confirmation_dialog/confirmation_dialog.js */
odoo.define('@web/core/confirmation_dialog/confirmation_dialog',['@web/core/dialog/dialog','@web/core/l10n/translation','@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{Dialog}=require("@web/core/dialog/dialog");const{_t}=require("@web/core/l10n/translation");const{useChildRef}=require("@web/core/utils/hooks");const{Component}=require("@odoo/owl");const deleteConfirmationMessage=__exports.deleteConfirmationMessage=_t(`Ready to make your record disappear into thin air? Are you sure?
It will be gone forever!

Think twice before you click that 'Delete' button!`);const ConfirmationDialog=__exports.ConfirmationDialog=class ConfirmationDialog extends Component{static template="web.ConfirmationDialog";static components={Dialog};static props={close:Function,title:{validate:(m)=>{return(typeof m==="string"||(typeof m==="object"&&typeof m.toString==="function"));},optional:true,},body:{type:String,optional:true},confirm:{type:Function,optional:true},confirmLabel:{type:String,optional:true},confirmClass:{type:String,optional:true},cancel:{type:Function,optional:true},cancelLabel:{type:String,optional:true},dismiss:{type:Function,optional:true},};static defaultProps={confirmLabel:_t("Ok"),cancelLabel:_t("Cancel"),confirmClass:"btn-primary",title:_t("Confirmation"),};setup(){this.env.dialogData.dismiss=()=>this._dismiss();this.modalRef=useChildRef();this.isProcess=false;}
async _cancel(){return this.execButton(this.props.cancel);}
async _confirm(){return this.execButton(this.props.confirm);}
async _dismiss(){return this.execButton(this.props.dismiss||this.props.cancel);}
setButtonsDisabled(disabled){this.isProcess=disabled;if(!this.modalRef.el){return;}
for(const button of[...this.modalRef.el.querySelectorAll(".modal-footer button")]){button.disabled=disabled;}}
async execButton(callback){if(this.isProcess){return;}
this.setButtonsDisabled(true);if(callback){let shouldClose;try{shouldClose=await callback();}catch(e){this.props.close();throw e;}
if(shouldClose===false){this.setButtonsDisabled(false);return;}}
this.props.close();}}
const AlertDialog=__exports.AlertDialog=class AlertDialog extends ConfirmationDialog{static template="web.AlertDialog";static props={...ConfirmationDialog.props,contentClass:{type:String,optional:true},};static defaultProps={...ConfirmationDialog.defaultProps,title:_t("Alert"),};}
return __exports;});;

/* /web/static/src/core/context.js */
odoo.define('@web/core/context',['@web/core/py_js/py','@web/core/py_js/py_builtin','@web/core/py_js/py_interpreter'],function(require){'use strict';let __exports={};const{evaluateExpr,parseExpr}=require("@web/core/py_js/py");const{BUILTINS}=require("@web/core/py_js/py_builtin");const{evaluate}=require("@web/core/py_js/py_interpreter");__exports.makeContext=makeContext;function makeContext(contexts,initialEvaluationContext){const evaluationContext=Object.assign({},initialEvaluationContext);const context={};for(let ctx of contexts){if(ctx!==""){ctx=typeof ctx==="string"?evaluateExpr(ctx,evaluationContext):ctx;Object.assign(context,ctx);Object.assign(evaluationContext,context);}}
return context;}
function getPartialNames(ast){if(ast.type===5){return[ast.value];}
if(ast.type===6){return getPartialNames(ast.right);}
if(ast.type===14||ast.type===7){return getPartialNames(ast.left).concat(getPartialNames(ast.right));}
if(ast.type===15){return getPartialNames(ast.obj);}
return[];}
__exports.evalPartialContext=evalPartialContext;function evalPartialContext(_context,evaluationContext={}){const ast=parseExpr(_context);const context={};for(const key in ast.value){const value=ast.value[key];if(getPartialNames(value).some((name)=>!(name in evaluationContext||name in BUILTINS))){continue;}
try{context[key]=evaluate(value,evaluationContext);}catch{}}
return context;}
return __exports;});;

/* /web/static/src/core/copy_button/copy_button.js */
odoo.define('@web/core/copy_button/copy_button',['@web/core/browser/browser','@web/core/tooltip/tooltip','@web/core/popover/popover_hook','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Tooltip}=require("@web/core/tooltip/tooltip");const{usePopover}=require("@web/core/popover/popover_hook");const{Component,useRef}=require("@odoo/owl");const CopyButton=__exports.CopyButton=class CopyButton extends Component{static template="web.CopyButton";static props={className:{type:String,optional:true},copyText:{type:String,optional:true},disabled:{type:Boolean,optional:true},successText:{type:String,optional:true},icon:{type:String,optional:true},content:{type:[String,Object],optional:true},};setup(){this.button=useRef("button");this.popover=usePopover(Tooltip);}
showTooltip(){this.popover.open(this.button.el,{tooltip:this.props.successText});browser.setTimeout(this.popover.close,800);}
async onClick(){let write;if(typeof this.props.content==="string"||this.props.content instanceof String){write=(value)=>browser.navigator.clipboard.writeText(value);}else{write=(value)=>browser.navigator.clipboard.write(value);}
try{await write(this.props.content);}catch(error){return browser.console.warn(error);}
this.showTooltip();}}
return __exports;});;

/* /web/static/src/core/currency.js */
odoo.define('@web/core/currency',['@web/core/utils/numbers','@web/session','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{formatFloat,humanNumber}=require("@web/core/utils/numbers");const{session}=require("@web/session");const{nbsp}=require("@web/core/utils/strings");const currencies=__exports.currencies=session.currencies||{};delete session.currencies;__exports.getCurrency=getCurrency;function getCurrency(id){return currencies[id];}
__exports.formatCurrency=formatCurrency;function formatCurrency(amount,currencyId,options={}){const currency=getCurrency(currencyId);const digits=options.digits||(currency&&currency.digits);let formattedAmount;if(options.humanReadable){formattedAmount=humanNumber(amount,{decimals:digits?digits[1]:2});}else{formattedAmount=formatFloat(amount,{digits});}
if(!currency||options.noSymbol){return formattedAmount;}
const formatted=[currency.symbol,formattedAmount];if(currency.position==="after"){formatted.reverse();}
return formatted.join(nbsp);}
return __exports;});;

/* /web/static/src/core/datetime/datetime_hook.js */
odoo.define('@web/core/datetime/datetime_hook',['@odoo/owl','@web/core/popover/popover_hook','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{onPatched,onWillRender,useEffect,useRef}=require("@odoo/owl");const{usePopover}=require("@web/core/popover/popover_hook");const{useService}=require("@web/core/utils/hooks");__exports.useDateTimePicker=useDateTimePicker;function useDateTimePicker(hookParams){const datetimePicker=useService("datetime_picker");if(typeof hookParams.target==="string"){const target=useRef(hookParams.target);Object.defineProperty(hookParams,"target",{get(){return target.el;},});}
const inputRefs=[useRef("start-date"),useRef("end-date")];if(!hookParams.createPopover){hookParams.createPopover=usePopover;}
const getInputs=()=>inputRefs.map((ref)=>ref?.el);const{computeBasePickerProps,state,open,focusIfNeeded,enable}=datetimePicker.create(hookParams,getInputs);onWillRender(computeBasePickerProps);useEffect(enable,getInputs);onPatched(focusIfNeeded);return{state,open};}
return __exports;});;

/* /web/static/src/core/datetime/datetime_input.js */
odoo.define('@web/core/datetime/datetime_input',['@odoo/owl','@web/core/utils/objects','@web/core/datetime/datetime_hook','@web/core/datetime/datetime_picker'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{omit}=require("@web/core/utils/objects");const{useDateTimePicker}=require("@web/core/datetime/datetime_hook");const{DateTimePicker}=require("@web/core/datetime/datetime_picker");const dateTimeInputOwnProps={format:{type:String,optional:true},id:{type:String,optional:true},onChange:{type:Function,optional:true},onApply:{type:Function,optional:true},placeholder:{type:String,optional:true},};const DateTimeInput=__exports.DateTimeInput=class DateTimeInput extends Component{static props={...DateTimePicker.props,...dateTimeInputOwnProps,};static template="web.DateTimeInput";setup(){const getPickerProps=()=>omit(this.props,...Object.keys(dateTimeInputOwnProps));useDateTimePicker({format:this.props.format,get pickerProps(){return getPickerProps();},onApply:(...args)=>this.props.onApply?.(...args),onChange:(...args)=>this.props.onChange?.(...args),});}}
return __exports;});;

/* /web/static/src/core/datetime/datetime_picker.js */
odoo.define('@web/core/datetime/datetime_picker',['@odoo/owl','@web/core/l10n/translation','@web/core/l10n/dates','@web/core/l10n/localization','@web/core/utils/arrays'],function(require){'use strict';let __exports={};const{Component,onWillRender,onWillUpdateProps,useState}=require("@odoo/owl");const{_t}=require("@web/core/l10n/translation");const{MAX_VALID_DATE,MIN_VALID_DATE,clampDate,is24HourFormat,isInRange,isMeridiemFormat,today,}=require("@web/core/l10n/dates");const{localization}=require("@web/core/l10n/localization");const{ensureArray}=require("@web/core/utils/arrays");const{DateTime,Info}=luxon;const getStartOfDecade=(date)=>Math.floor(date.year/10)*10;const getStartOfCentury=(date)=>Math.floor(date.year/100)*100;const getStartOfWeek=(date)=>{const{weekStart}=localization;return date.set({weekday:date.weekday<weekStart?weekStart-7:weekStart});};const numberRange=(min,max)=>[...Array(max-min)].map((_,i)=>i+min);const parseLimitDate=(value,defaultValue)=>clampDate(value==="today"?today():value||defaultValue,MIN_VALID_DATE,MAX_VALID_DATE);const toDateItem=({isOutOfRange=false,isValid=true,label,range,extraClass})=>({id:range[0].toISODate(),includesToday:isInRange(today(),range),isOutOfRange,isValid,label:String(range[0][label]),range,extraClass,});const toWeekItem=(weekDayItems)=>({number:weekDayItems[3].range[0].weekNumber,days:weekDayItems,});const HOURS=numberRange(0,24).map((hour)=>[hour,String(hour)]);const MINUTES=numberRange(0,60).map((minute)=>[minute,String(minute||0).padStart(2,"0")]);const SECONDS=[...MINUTES];const MERIDIEMS=["AM","PM"];const PRECISION_LEVELS=new Map().set("days",{mainTitle:_t("Select month"),nextTitle:_t("Next month"),prevTitle:_t("Previous month"),step:{month:1},getTitle:(date,{additionalMonth})=>{const titles=[`${date.monthLong} ${date.year}`];if(additionalMonth){const next=date.plus({month:1});titles.push(`${next.monthLong} ${next.year}`);}
return titles;},getItems:(date,{additionalMonth,maxDate,minDate,showWeekNumbers,isDateValid,dayCellClass})=>{const startDates=[date];if(additionalMonth){startDates.push(date.plus({month:1}));}
const lastWeeks=[];let shouldAddLastWeek=false;const dayItems=startDates.map((date,i)=>{const monthRange=[date.startOf("month"),date.endOf("month")];const weeks=[];let startOfNextWeek=getStartOfWeek(monthRange[0]);for(let w=0;w<WEEKS_PER_MONTH;w++){const weekDayItems=[];for(let d=0;d<DAYS_PER_WEEK;d++){const day=startOfNextWeek.plus({day:d});const range=[day,day.endOf("day")];const dayItem=toDateItem({isOutOfRange:!isInRange(day,monthRange),isValid:isInRange(range,[minDate,maxDate])&&isDateValid?.(day),label:"day",range,extraClass:dayCellClass?.(day)||"",});weekDayItems.push(dayItem);if(d===DAYS_PER_WEEK-1){startOfNextWeek=day.plus({day:1});}
if(w===WEEKS_PER_MONTH-1){shouldAddLastWeek||=!dayItem.isOutOfRange;}}
const weekItem=toWeekItem(weekDayItems);if(w===WEEKS_PER_MONTH-1){lastWeeks.push(weekItem);}else{weeks.push(weekItem);}}
const daysOfWeek=weeks[0].days.map((d)=>[d.range[0].weekdayShort,d.range[0].weekdayLong,Info.weekdays("narrow",{locale:d.range[0].locale})[d.range[0].weekday-1],]);if(showWeekNumbers){daysOfWeek.unshift(["#",_t("Week numbers"),"#"]);}
return{id:`__month__${i}`,number:monthRange[0].month,daysOfWeek,weeks,};});if(shouldAddLastWeek){for(let i=0;i<dayItems.length;i++){dayItems[i].weeks.push(lastWeeks[i]);}}
return dayItems;},}).set("months",{mainTitle:_t("Select year"),nextTitle:_t("Next year"),prevTitle:_t("Previous year"),step:{year:1},getTitle:(date)=>String(date.year),getItems:(date,{maxDate,minDate})=>{const startOfYear=date.startOf("year");return numberRange(0,12).map((i)=>{const startOfMonth=startOfYear.plus({month:i});const range=[startOfMonth,startOfMonth.endOf("month")];return toDateItem({isValid:isInRange(range,[minDate,maxDate]),label:"monthShort",range,});});},}).set("years",{mainTitle:_t("Select decade"),nextTitle:_t("Next decade"),prevTitle:_t("Previous decade"),step:{year:10},getTitle:(date)=>`${getStartOfDecade(date) - 1} - ${getStartOfDecade(date) + 10}`,getItems:(date,{maxDate,minDate})=>{const startOfDecade=date.startOf("year").set({year:getStartOfDecade(date)});return numberRange(-GRID_MARGIN,GRID_COUNT+GRID_MARGIN).map((i)=>{const startOfYear=startOfDecade.plus({year:i});const range=[startOfYear,startOfYear.endOf("year")];return toDateItem({isOutOfRange:i<0||i>=GRID_COUNT,isValid:isInRange(range,[minDate,maxDate]),label:"year",range,});});},}).set("decades",{mainTitle:_t("Select century"),nextTitle:_t("Next century"),prevTitle:_t("Previous century"),step:{year:100},getTitle:(date)=>`${getStartOfCentury(date) - 10} - ${getStartOfCentury(date) + 100}`,getItems:(date,{maxDate,minDate})=>{const startOfCentury=date.startOf("year").set({year:getStartOfCentury(date)});return numberRange(-GRID_MARGIN,GRID_COUNT+GRID_MARGIN).map((i)=>{const startOfDecade=startOfCentury.plus({year:i*10});const range=[startOfDecade,startOfDecade.plus({year:10,millisecond:-1})];return toDateItem({label:"year",isOutOfRange:i<0||i>=GRID_COUNT,isValid:isInRange(range,[minDate,maxDate]),range,});});},});const GRID_COUNT=10;const GRID_MARGIN=1;const NULLABLE_DATETIME_PROPERTY=[DateTime,{value:false},{value:null}];const DAYS_PER_WEEK=7;const WEEKS_PER_MONTH=6;const DateTimePicker=__exports.DateTimePicker=class DateTimePicker extends Component{static props={focusedDateIndex:{type:Number,optional:true},showWeekNumbers:{type:Boolean,optional:true},daysOfWeekFormat:{type:String,optional:true},maxDate:{type:[NULLABLE_DATETIME_PROPERTY,{value:"today"}],optional:true},maxPrecision:{type:[...PRECISION_LEVELS.keys()].map((value)=>({value})),optional:true,},minDate:{type:[NULLABLE_DATETIME_PROPERTY,{value:"today"}],optional:true},minPrecision:{type:[...PRECISION_LEVELS.keys()].map((value)=>({value})),optional:true,},onSelect:{type:Function,optional:true},range:{type:Boolean,optional:true},rounding:{type:Number,optional:true},slots:{type:Object,shape:{bottom_left:{type:Object,optional:true},buttons:{type:Object,optional:true},},optional:true,},type:{type:[{value:"date"},{value:"datetime"}],optional:true},value:{type:[NULLABLE_DATETIME_PROPERTY,{type:Array,element:NULLABLE_DATETIME_PROPERTY},],optional:true,},isDateValid:{type:Function,optional:true},dayCellClass:{type:Function,optional:true},tz:{type:String,optional:true},};static defaultProps={focusedDateIndex:0,daysOfWeekFormat:"short",maxPrecision:"decades",minPrecision:"days",rounding:5,type:"datetime",};static template="web.DateTimePicker";get activePrecisionLevel(){return PRECISION_LEVELS.get(this.state.precision);}
get isLastPrecisionLevel(){return(this.allowedPrecisionLevels.indexOf(this.state.precision)===this.allowedPrecisionLevels.length-1);}
get titles(){return ensureArray(this.title);}
setup(){this.availableHours=HOURS;this.availableMinutes=MINUTES;this.allowedPrecisionLevels=[];this.items=[];this.title="";this.shouldAdjustFocusDate=false;this.state=useState({focusDate:null,hoveredDate:null,timeValues:[],precision:this.props.minPrecision,});this.onPropsUpdated(this.props);onWillUpdateProps((nextProps)=>this.onPropsUpdated(nextProps));onWillRender(()=>this.onWillRender());}
onPropsUpdated(props){this.values=ensureArray(props.value).map((value)=>value&&!value.isValid?null:value);this.availableHours=HOURS;this.availableMinutes=MINUTES.filter((minute)=>!(minute[0]%props.rounding));this.availableSeconds=props.rounding?[]:SECONDS;this.allowedPrecisionLevels=this.filterPrecisionLevels(props.minPrecision,props.maxPrecision);this.additionalMonth=props.range&&!this.env.isSmall;this.maxDate=parseLimitDate(props.maxDate,MAX_VALID_DATE);this.minDate=parseLimitDate(props.minDate,MIN_VALID_DATE);if(this.props.type==="date"){this.maxDate=this.maxDate.endOf("day");this.minDate=this.minDate.startOf("day");}
if(this.maxDate<this.minDate){throw new Error(`DateTimePicker error: given "maxDate" comes before "minDate".`);}
const timeValues=this.values.map((val,index)=>[index===1&&!this.values[1]?(val||DateTime.local()).hour+1:(val||DateTime.local()).hour,val?.minute||0,val?.second||0,]);if(props.range){this.state.timeValues=timeValues;}else{this.state.timeValues=[];this.state.timeValues[props.focusedDateIndex]=timeValues[props.focusedDateIndex];}
this.shouldAdjustFocusDate=!props.range;this.adjustFocus(this.values,props.focusedDateIndex);this.handle12HourSystem();this.state.timeValues=this.state.timeValues.map((timeValue)=>timeValue.map(String));}
onWillRender(){const{dayCellClass,focusedDateIndex,isDateValid,range,showWeekNumbers}=this.props;const{focusDate,hoveredDate}=this.state;const precision=this.activePrecisionLevel;const getterParams={additionalMonth:this.additionalMonth,maxDate:this.maxDate,minDate:this.minDate,showWeekNumbers:showWeekNumbers??!range,isDateValid,dayCellClass,};this.title=precision.getTitle(focusDate,getterParams);this.items=precision.getItems(focusDate,getterParams);this.selectedRange=[...this.values];if(range&&focusedDateIndex>0&&(!this.values[1]||hoveredDate>this.values[0])){this.selectedRange[1]=hoveredDate;}}
adjustFocus(values,focusedDateIndex){if(!this.shouldAdjustFocusDate&&this.state.focusDate){return;}
let dateToFocus=values[focusedDateIndex]||values[focusedDateIndex===1?0:1]||today();if(this.additionalMonth&&focusedDateIndex===1&&values[0]&&values[1]&&values[0].month!==values[1].month){dateToFocus=dateToFocus.minus({month:1});}
this.shouldAdjustFocusDate=false;this.state.focusDate=this.clamp(dateToFocus.startOf("month"));}
clamp(value){return clampDate(value,this.minDate,this.maxDate);}
filterPrecisionLevels(minPrecision,maxPrecision){const levels=[...PRECISION_LEVELS.keys()];return levels.slice(levels.indexOf(minPrecision),levels.indexOf(maxPrecision)+1);}
getActiveRangeInfo({isOutOfRange,range}){const result={isSelected:!isOutOfRange&&isInRange(this.selectedRange,range),isSelectStart:false,isSelectEnd:false,isHighlighted:isInRange(this.state.hoveredDate,range),isCurrent:false,};if(this.props.range){if(result.isSelected){const[selectStart,selectEnd]=this.selectedRange;result.isSelectStart=!selectStart||isInRange(selectStart,range);result.isSelectEnd=!selectEnd||isInRange(selectEnd,range);}
result.isCurrent=!isOutOfRange&&(isInRange(this.values[0],range)||isInRange(this.values[1],range));}else{result.isSelectStart=result.isSelectEnd=result.isSelected;}
return result;}
getTimeValues(valueIndex){let[hour,minute,second]=this.state.timeValues[valueIndex].map(Number);if(this.is12HourFormat&&this.meridiems&&this.state.timeValues[valueIndex][3]==="PM"){hour+=12;}
return[hour,minute,second];}
handle12HourSystem(){if(isMeridiemFormat()){this.meridiems=MERIDIEMS.map((m)=>[m,m]);for(const timeValues of this.state.timeValues){if(timeValues){timeValues.push(MERIDIEMS[Math.floor(timeValues[0]/12)||0]);}}}
this.is12HourFormat=!is24HourFormat();if(this.is12HourFormat){this.availableHours=[[0,HOURS[12][1]],...HOURS.slice(1,12)];for(const timeValues of this.state.timeValues){if(timeValues){timeValues[0]%=12;}}}}
isSelectedDate({range}){return this.values.some((value)=>isInRange(value,range));}
next(ev){ev.preventDefault();const{step}=this.activePrecisionLevel;this.state.focusDate=this.clamp(this.state.focusDate.plus(step));}
previous(ev){ev.preventDefault();const{step}=this.activePrecisionLevel;this.state.focusDate=this.clamp(this.state.focusDate.minus(step));}
selectTime(valueIndex){const value=this.values[valueIndex]||today();this.validateAndSelect(value,valueIndex,"time");}
validateAndSelect(value,valueIndex,unit){if(!this.props.onSelect){return false;}
const result=[...this.values];result[valueIndex]=value;if(this.props.type==="datetime"){const[hour,minute,second]=this.getTimeValues(valueIndex);result[valueIndex]=result[valueIndex].set({hour,minute,second});}
if(!isInRange(result[valueIndex],[this.minDate,this.maxDate])){return false;}
this.props.onSelect(result.length===2?result:result[0],unit);return true;}
zoomIn(date){const index=this.allowedPrecisionLevels.indexOf(this.state.precision)-1;if(index in this.allowedPrecisionLevels){this.state.focusDate=this.clamp(date);this.state.precision=this.allowedPrecisionLevels[index];return true;}
return false;}
zoomOut(){const index=this.allowedPrecisionLevels.indexOf(this.state.precision)+1;if(index in this.allowedPrecisionLevels){this.state.precision=this.allowedPrecisionLevels[index];return true;}
return false;}
zoomOrSelect(dateItem){if(!dateItem.isValid){return;}
if(this.zoomIn(dateItem.range[0])){return;}
const[value]=dateItem.range;const valueIndex=this.props.focusedDateIndex;const isValid=this.validateAndSelect(value,valueIndex,"date");this.shouldAdjustFocusDate=isValid&&!this.props.range;}}
return __exports;});;

/* /web/static/src/core/datetime/datetime_picker_popover.js */
odoo.define('@web/core/datetime/datetime_picker_popover',['@odoo/owl','@web/core/hotkeys/hotkey_hook','@web/core/datetime/datetime_picker'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{DateTimePicker}=require("@web/core/datetime/datetime_picker");const DateTimePickerPopover=__exports.DateTimePickerPopover=class DateTimePickerPopover extends Component{static components={DateTimePicker};static props={close:Function,pickerProps:{type:Object,shape:DateTimePicker.props},};static template="web.DateTimePickerPopover";get isDateTimeRange(){return(this.props.pickerProps.type==="datetime"||Array.isArray(this.props.pickerProps.value));}
setup(){useHotkey("enter",()=>this.props.close());}}
return __exports;});;

/* /web/static/src/core/datetime/datetimepicker_service.js */
odoo.define('@web/core/datetime/datetimepicker_service',['@odoo/owl','@web/core/l10n/dates','@web/core/popover/popover_hook','@web/core/registry','@web/core/utils/arrays','@web/core/utils/objects','@web/core/datetime/datetime_picker','@web/core/datetime/datetime_picker_popover'],function(require){'use strict';let __exports={};const{markRaw,reactive}=require("@odoo/owl");const{areDatesEqual,formatDate,formatDateTime,parseDate,parseDateTime}=require("@web/core/l10n/dates");const{makePopover}=require("@web/core/popover/popover_hook");const{registry}=require("@web/core/registry");const{ensureArray,zip,zipWith}=require("@web/core/utils/arrays");const{deepCopy,shallowEqual}=require("@web/core/utils/objects");const{DateTimePicker}=require("@web/core/datetime/datetime_picker");const{DateTimePickerPopover}=require("@web/core/datetime/datetime_picker_popover");const arePropsEqual=(obj1,obj2)=>shallowEqual(obj1,obj2,(a,b)=>areDatesEqual(a,b)||shallowEqual(a,b));const FOCUS_CLASSNAME="text-primary";const formatters={date:formatDate,datetime:formatDateTime,};const listenedElements=new WeakSet();const parsers={date:parseDate,datetime:parseDateTime,};const datetimePickerService=__exports.datetimePickerService={dependencies:["popover"],start(env,{popover:popoverService}){return{create:(hookParams,getInputs=()=>[hookParams.target,null])=>{const createPopover=hookParams.createPopover??((...args)=>makePopover(popoverService.add,...args));const ensureVisibility=hookParams.ensureVisibility??(()=>env.isSmall);const popover=createPopover(DateTimePickerPopover,{onClose:()=>{if(!allowOnClose){return;}
updateValueFromInputs();apply();setFocusClass(null);if(restoreTargetMargin){restoreTargetMargin();restoreTargetMargin=null;}},});const apply=async()=>{const valueCopy=deepCopy(pickerProps.value);if(areDatesEqual(lastInitialProps.value,valueCopy)){return;}
inputsChanged=ensureArray(pickerProps.value).map(()=>false);await hookParams.onApply?.(pickerProps.value);lastInitialProps.value=valueCopy;};const computeBasePickerProps=()=>{const nextInitialProps=markValuesRaw(hookParams.pickerProps);const propsCopy=deepCopy(nextInitialProps);if(arePropsEqual(lastInitialProps,propsCopy)){return;}
lastInitialProps=propsCopy;inputsChanged=ensureArray(lastInitialProps.value).map(()=>false);for(const[key,value]of Object.entries(nextInitialProps)){if(pickerProps[key]!==value&&!areDatesEqual(pickerProps[key],value)){pickerProps[key]=value;}}};const focusActiveInput=()=>{const inputEl=getInput(pickerProps.focusedDateIndex);if(!inputEl){shouldFocus=true;return;}
const{activeElement}=inputEl.ownerDocument;if(activeElement!==inputEl){inputEl.focus();}
setInputFocus(inputEl);};const getInput=(valueIndex)=>{const el=getInputs()[valueIndex];if(el&&document.body.contains(el)){return el;}
return null;};const getPopoverTarget=()=>{if(hookParams.target){return hookParams.target;}
if(pickerProps.range){let parentElement=getInput(0).parentElement;const inputEls=getInputs();while(parentElement&&!inputEls.every((inputEl)=>parentElement.contains(inputEl))){parentElement=parentElement.parentElement;}
return parentElement||getInput(0);}else{return getInput(0);}};const markValuesRaw=(obj)=>{const copy={};for(const[key,value]of Object.entries(obj)){if(value&&typeof value==="object"){copy[key]=markRaw(value);}else{copy[key]=value;}}
return copy;};const onInputChange=(ev)=>{updateValueFromInputs();inputsChanged[ev.target===getInput(1)?1:0]=true;if(!popover.isOpen||inputsChanged.every(Boolean)){saveAndClose();}};const onInputClick=({target})=>{openPicker(target===getInput(1)?1:0);};const onInputFocus=({target})=>{pickerProps.focusedDateIndex=target===getInput(1)?1:0;setInputFocus(target);};const onInputKeydown=(ev)=>{if(ev.key=="Enter"&&ev.ctrlKey){ev.preventDefault();updateValueFromInputs();return openPicker(ev.target===getInput(1)?1:0);}
switch(ev.key){case"Enter":case"Escape":{return saveAndClose();}
case"Tab":{if(!getInput(0)||!getInput(1)||ev.target!==getInput(ev.shiftKey?1:0)){return saveAndClose();}}}};const openPicker=(inputIndex)=>{pickerProps.focusedDateIndex=inputIndex;if(!popover.isOpen){const popoverTarget=getPopoverTarget();if(ensureVisibility()){const{marginBottom}=popoverTarget.style;popoverTarget.style.marginBottom=`100vh`;popoverTarget.scrollIntoView(true);restoreTargetMargin=async()=>{popoverTarget.style.marginBottom=marginBottom;};}
popover.open(popoverTarget,{pickerProps});}
focusActiveInput();};const safeConvert=(operation,value)=>{const{type}=pickerProps;const convertFn=(operation==="format"?formatters:parsers)[type];const options={tz:pickerProps.tz,format:hookParams.format};if(operation==="format"){options.showSeconds=hookParams.showSeconds??true;options.condensed=hookParams.condensed||false;}
try{return[convertFn(value,options),null];}catch(error){if(error?.name==="ConversionError"){return[null,error];}else{throw error;}}};const saveAndClose=()=>{if(popover.isOpen){popover.close();}else{apply();}};const setFocusClass=(input)=>{for(const el of getInputs()){if(el){el.classList.toggle(FOCUS_CLASSNAME,popover.isOpen&&el===input);}}};const setInputFocus=(inputEl)=>{inputEl.selectionStart=0;inputEl.selectionEnd=inputEl.value.length;setFocusClass(inputEl);shouldFocus=false;};const updateInput=(el,value)=>{if(!el){return;}
const[formattedValue]=safeConvert("format",value);el.value=formattedValue||"";};const updateValue=(value,unit,source)=>{const previousValue=pickerProps.value;pickerProps.value=value;if(source==="input"&&areDatesEqual(previousValue,pickerProps.value)){return;}
if(unit!=="time"){if(pickerProps.range&&source==="picker"){if(pickerProps.focusedDateIndex===0||(value[0]&&value[1]&&value[1]<value[0])){const{year,month,day}=value[pickerProps.focusedDateIndex];for(let i=0;i<value.length;i++){value[i]=value[i]&&value[i].set({year,month,day});}
pickerProps.focusedDateIndex=1;}else{pickerProps.focusedDateIndex=pickerProps.focusedDateIndex===1?0:1;}}}
hookParams.onChange?.(value);};const updateValueFromInputs=()=>{const values=zipWith(getInputs(),ensureArray(pickerProps.value),(el,currentValue)=>{if(!el){return currentValue;}
const[parsedValue,error]=safeConvert("parse",el.value);if(error){updateInput(el,currentValue);return currentValue;}else{return parsedValue;}});updateValue(values.length===2?values:values[0],"date","input");};const rawPickerProps={...DateTimePicker.defaultProps,onSelect:(value,unit)=>{value&&=markRaw(value);updateValue(value,unit,"picker");if(!pickerProps.range&&pickerProps.type==="date"){saveAndClose();}},...markValuesRaw(hookParams.pickerProps),};const pickerProps=reactive(rawPickerProps,()=>{const currentIsRange=pickerProps.range;if(popover.isOpen&&lastIsRange!==currentIsRange){allowOnClose=false;popover.open(getPopoverTarget(),{pickerProps});allowOnClose=true;}
lastIsRange=currentIsRange;for(const[el,value]of zip(getInputs(),ensureArray(pickerProps.value),true)){if(el){updateInput(el,value);}}
shouldFocus=true;});let allowOnClose=true;let inputsChanged=[];let lastInitialProps={};let lastIsRange=pickerProps.range;let restoreTargetMargin=null;let shouldFocus=false;return{state:pickerProps,open:openPicker,computeBasePickerProps,focusIfNeeded(){if(popover.isOpen&&shouldFocus){focusActiveInput();}},enable(){let editableInputs=0;for(const[el,value]of zip(getInputs(),ensureArray(pickerProps.value),true)){updateInput(el,value);if(el&&!el.disabled&&!el.readOnly&&!listenedElements.has(el)){listenedElements.add(el);el.addEventListener("change",onInputChange);el.addEventListener("click",onInputClick);el.addEventListener("focus",onInputFocus);el.addEventListener("keydown",onInputKeydown);editableInputs++;}}
const calendarIconGroupEl=getInput(0)?.parentElement.querySelector(".o_input_group_date_icon");if(calendarIconGroupEl){calendarIconGroupEl.classList.add("cursor-pointer");calendarIconGroupEl.addEventListener("click",()=>openPicker(0));}
if(!editableInputs&&popover.isOpen){saveAndClose();}
return()=>{};},get isOpen(){return popover.isOpen;},};},};},};registry.category("services").add("datetime_picker",datetimePickerService);return __exports;});;

/* /web/static/src/core/dialog/dialog.js */
odoo.define('@web/core/dialog/dialog',['@web/core/hotkeys/hotkey_hook','@web/core/ui/ui_service','@web/core/utils/hooks','@odoo/owl','@web/core/utils/timing','@web/core/utils/draggable_hook_builder_owl'],function(require){'use strict';let __exports={};const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{useActiveElement}=require("@web/core/ui/ui_service");const{useForwardRefToParent}=require("@web/core/utils/hooks");const{Component,onWillDestroy,useChildSubEnv,useExternalListener,useState}=require("@odoo/owl");const{throttleForAnimation}=require("@web/core/utils/timing");const{makeDraggableHook}=require("@web/core/utils/draggable_hook_builder_owl");const useDialogDraggable=makeDraggableHook({name:"useDialogDraggable",onWillStartDrag({ctx,addCleanup,addStyle,getRect}){const{height,width}=getRect(ctx.current.element);ctx.current.container=document.createElement("div");addStyle(ctx.current.container,{position:"fixed",top:"0",bottom:`${70 - height}px`,left:`${70 - width}px`,right:`${70 - width}px`,});ctx.current.element.after(ctx.current.container);addCleanup(()=>ctx.current.container.remove());},onDrop({ctx,getRect}){const{top,left}=getRect(ctx.current.element);return{left:left-ctx.current.elementRect.left,top:top-ctx.current.elementRect.top,};},});const Dialog=__exports.Dialog=class Dialog extends Component{static template="web.Dialog";static props={contentClass:{type:String,optional:true},bodyClass:{type:String,optional:true},fullscreen:{type:Boolean,optional:true},footer:{type:Boolean,optional:true},header:{type:Boolean,optional:true},size:{type:String,optional:true,validate:(s)=>["sm","md","lg","xl","fs","fullscreen"].includes(s),},technical:{type:Boolean,optional:true},title:{type:String,optional:true},modalRef:{type:Function,optional:true},slots:{type:Object,shape:{default:Object,header:{type:Object,optional:true},footer:{type:Object,optional:true},},},withBodyPadding:{type:Boolean,optional:true},onExpand:{type:Function,optional:true},};static defaultProps={contentClass:"",bodyClass:"",fullscreen:false,footer:true,header:true,size:"lg",technical:true,title:"Odoo",withBodyPadding:true,};setup(){this.modalRef=useForwardRefToParent("modalRef");useActiveElement("modalRef");this.data=useState(this.env.dialogData);useHotkey("escape",()=>this.onEscape());useHotkey("control+enter",()=>{const btns=document.querySelectorAll(".o_dialog:not(.o_inactive_modal) .modal-footer button");const firstVisibleBtn=Array.from(btns).find((btn)=>{const styles=getComputedStyle(btn);return styles.display!=="none";});if(firstVisibleBtn){firstVisibleBtn.click();}},{bypassEditableProtection:true});this.id=`dialog_${this.data.id}`;useChildSubEnv({inDialog:true,dialogId:this.id});this.isMovable=this.props.header;if(this.isMovable){this.position=useState({left:0,top:0});useDialogDraggable({enable:()=>!this.env.isSmall,ref:this.modalRef,elements:".modal-content",handle:".modal-header",ignore:"button, input",edgeScrolling:{enabled:false},onDrop:({top,left})=>{this.position.left+=left;this.position.top+=top;},});const throttledResize=throttleForAnimation(this.onResize.bind(this));useExternalListener(window,"resize",throttledResize);}
onWillDestroy(()=>{if(this.env.isSmall){this.data.scrollToOrigin();}});}
get isFullscreen(){return this.props.fullscreen||this.env.isSmall;}
get contentStyle(){if(this.isMovable){return`top: ${this.position.top}px; left: ${this.position.left}px;`;}
return"";}
onResize(){this.position.left=0;this.position.top=0;}
onEscape(){return this.dismiss();}
async dismiss(){if(this.data.dismiss){await this.data.dismiss();}
return this.data.close();}}
return __exports;});;

/* /web/static/src/core/dialog/dialog_service.js */
odoo.define('@web/core/dialog/dialog_service',['@odoo/owl','@web/core/registry'],function(require){'use strict';let __exports={};const{Component,markRaw,reactive,useChildSubEnv,xml}=require("@odoo/owl");const{registry}=require("@web/core/registry");class DialogWrapper extends Component{static template=xml`<t t-component="props.subComponent" t-props="props.subProps" />`;static props=["*"];setup(){useChildSubEnv({dialogData:this.props.subEnv});}}
const dialogService=__exports.dialogService={dependencies:["overlay"],start(env,{overlay}){const stack=[];let nextId=0;const deactivate=()=>{for(const subEnv of stack){subEnv.isActive=false;}};const add=(dialogClass,props,options={})=>{const id=nextId++;const close=()=>remove();const subEnv=reactive({id,close,isActive:true,});deactivate();stack.push(subEnv);document.body.classList.add("modal-open");const scrollOrigin={top:window.scrollY,left:window.scrollX};subEnv.scrollToOrigin=()=>{if(!stack.length){window.scrollTo(scrollOrigin);}};const remove=overlay.add(DialogWrapper,{subComponent:dialogClass,subProps:markRaw({...props,close}),subEnv,},{onRemove:()=>{stack.pop();deactivate();if(stack.length){stack.at(-1).isActive=true;}else{document.body.classList.remove("modal-open");}
options.onClose?.();},rootId:options.context?.root?.el.getRootNode()?.host?.id,});return remove;};function closeAll(){for(const dialog of[...stack].reverse()){dialog.close();}}
return{add,closeAll};},};registry.category("services").add("dialog",dialogService);return __exports;});;

/* /web/static/src/core/domain.js */
odoo.define('@web/core/domain',['@web/core/utils/arrays','@web/core/py_js/py','@web/core/py_js/py_utils','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{shallowEqual}=require("@web/core/utils/arrays");const{evaluate,formatAST,parseExpr}=require("@web/core/py_js/py");const{toPyValue}=require("@web/core/py_js/py_utils");const{escapeRegExp}=require("@web/core/utils/strings");const InvalidDomainError=__exports.InvalidDomainError=class InvalidDomainError extends Error{}
const Domain=__exports.Domain=class Domain{static combine(domains,operator){if(domains.length===0){return new Domain([]);}
const domain1=domains[0]instanceof Domain?domains[0]:new Domain(domains[0]);if(domains.length===1){return domain1;}
const domain2=Domain.combine(domains.slice(1),operator);const result=new Domain([]);const astValues1=domain1.ast.value;const astValues2=domain2.ast.value;const op=operator==="AND"?"&":"|";const combinedAST={type:4,value:astValues1.concat(astValues2)};result.ast=normalizeDomainAST(combinedAST,op);return result;}
static and(domains){return Domain.combine(domains,"AND");}
static or(domains){return Domain.combine(domains,"OR");}
static not(domain){const result=new Domain(domain);result.ast.value.unshift({type:1,value:"!"});return result;}
static removeDomainLeaves(domain,keysToRemove){function processLeaf(elements,idx,operatorCtx,newDomain){const leaf=elements[idx];if(leaf.type===10){if(keysToRemove.includes(leaf.value[0].value)){if(operatorCtx==="&"){newDomain.ast.value.push(...Domain.TRUE.ast.value);}else if(operatorCtx==="|"){newDomain.ast.value.push(...Domain.FALSE.ast.value);}}else{newDomain.ast.value.push(leaf);}
return 1;}else if(leaf.type===1){if(leaf.value==="|"&&elements[idx+1].type===10&&elements[idx+2].type===10&&keysToRemove.includes(elements[idx+1].value[0].value)&&keysToRemove.includes(elements[idx+2].value[0].value)){newDomain.ast.value.push(...Domain.TRUE.ast.value);return 3;}
newDomain.ast.value.push(leaf);if(leaf.value==="!"){return 1+processLeaf(elements,idx+1,"&",newDomain);}
const firstLeafSkip=processLeaf(elements,idx+1,leaf.value,newDomain);const secondLeafSkip=processLeaf(elements,idx+1+firstLeafSkip,leaf.value,newDomain);return 1+firstLeafSkip+secondLeafSkip;}
return 0;}
domain=new Domain(domain);if(domain.ast.value.length===0){return domain;}
const newDomain=new Domain([]);processLeaf(domain.ast.value,0,"&",newDomain);return newDomain;}
constructor(descr=[]){if(descr instanceof Domain){return new Domain(descr.toString());}else{let rawAST;try{rawAST=typeof descr==="string"?parseExpr(descr):toAST(descr);}catch(error){throw new InvalidDomainError(`Invalid domain representation: ${descr.toString()}`,{cause:error,});}
this.ast=normalizeDomainAST(rawAST);}}
contains(record){const expr=evaluate(this.ast,record);return matchDomain(record,expr);}
toString(){return formatAST(this.ast);}
toList(context){return evaluate(this.ast,context);}
toJson(){try{const evaluatedAsList=this.toList({});const evaluatedDomain=new Domain(evaluatedAsList);if(evaluatedDomain.toString()===this.toString()){return evaluatedAsList;}
return this.toString();}catch{return this.toString();}}}
__exports.evalDomain=evalDomain;function evalDomain(modifier,evalContext){if(modifier&&typeof modifier!=="boolean"){modifier=new Domain(modifier).contains(evalContext);}
return Boolean(modifier);}
const TRUE_LEAF=[1,"=",1];const FALSE_LEAF=[0,"=",1];const TRUE_DOMAIN=new Domain([TRUE_LEAF]);const FALSE_DOMAIN=new Domain([FALSE_LEAF]);Domain.TRUE=TRUE_DOMAIN;Domain.FALSE=FALSE_DOMAIN;function toAST(domain){const elems=domain.map((elem)=>{switch(elem){case"!":case"&":case"|":return{type:1,value:elem};default:return{type:10,value:elem.map(toPyValue),};}});return{type:4,value:elems};}
function normalizeDomainAST(domain,op="&"){if(domain.type!==4){if(domain.type===10){const value=domain.value;if(value.findIndex((e)=>e.type===10)===-1||!value.every((e)=>e.type===10||e.type===1)){throw new InvalidDomainError("Invalid domain AST");}}else{throw new InvalidDomainError("Invalid domain AST");}}
if(domain.value.length===0){return domain;}
let expected=1;for(const child of domain.value){switch(child.type){case 1:if(child.value==="&"||child.value==="|"){expected++;}else if(child.value!=="!"){throw new InvalidDomainError("Invalid domain AST");}
break;case 4:case 10:if(child.value.length===3){expected--;break;}
throw new InvalidDomainError("Invalid domain AST");default:throw new InvalidDomainError("Invalid domain AST");}}
const values=domain.value.slice();while(expected<0){expected++;values.unshift({type:1,value:op});}
if(expected>0){throw new InvalidDomainError(`invalid domain ${formatAST(domain)} (missing ${expected} segment(s))`);}
return{type:4,value:values};}
function matchCondition(record,condition){if(typeof condition==="boolean"){return condition;}
const[field,operator,value]=condition;if(typeof field==="string"){const names=field.split(".");if(names.length>=2){return matchCondition(record[names[0]],[names.slice(1).join("."),operator,value]);}}
let likeRegexp,ilikeRegexp;if(["like","not like","ilike","not ilike"].includes(operator)){likeRegexp=new RegExp(`(.*)${escapeRegExp(value).replaceAll("%", "(.*)")}(.*)`,"g");ilikeRegexp=new RegExp(`(.*)${escapeRegExp(value).replaceAll("%", "(.*)")}(.*)`,"gi");}
const fieldValue=typeof field==="number"?field:record[field];switch(operator){case"=?":if([false,null].includes(value)){return true;}
case"=":case"==":if(Array.isArray(fieldValue)&&Array.isArray(value)){return shallowEqual(fieldValue,value);}
return fieldValue===value;case"!=":case"<>":return!matchCondition(record,[field,"==",value]);case"<":return fieldValue<value;case"<=":return fieldValue<=value;case">":return fieldValue>value;case">=":return fieldValue>=value;case"in":{const val=Array.isArray(value)?value:[value];const fieldVal=Array.isArray(fieldValue)?fieldValue:[fieldValue];return fieldVal.some((fv)=>val.includes(fv));}
case"not in":{const val=Array.isArray(value)?value:[value];const fieldVal=Array.isArray(fieldValue)?fieldValue:[fieldValue];return!fieldVal.some((fv)=>val.includes(fv));}
case"like":if(fieldValue===false){return false;}
return Boolean(fieldValue.match(likeRegexp));case"not like":if(fieldValue===false){return false;}
return Boolean(!fieldValue.match(likeRegexp));case"=like":if(fieldValue===false){return false;}
return new RegExp(escapeRegExp(value).replace(/%/g,".*")).test(fieldValue);case"ilike":if(fieldValue===false){return false;}
return Boolean(fieldValue.match(ilikeRegexp));case"not ilike":if(fieldValue===false){return false;}
return Boolean(!fieldValue.match(ilikeRegexp));case"=ilike":if(fieldValue===false){return false;}
return new RegExp(escapeRegExp(value).replace(/%/g,".*"),"i").test(fieldValue);case"any":case"not_any":return true;case"child_of":case"parent_of":return true;}
throw new InvalidDomainError("could not match domain");}
function makeOperators(record){const match=matchCondition.bind(null,record);return{"!":(x)=>!match(x),"&":(a,b)=>match(a)&&match(b),"|":(a,b)=>match(a)||match(b),};}
function matchDomain(record,domain){if(domain.length===0){return true;}
const operators=makeOperators(record);const reversedDomain=Array.from(domain).reverse();const condStack=[];for(const item of reversedDomain){const operator=typeof item==="string"&&operators[item];if(operator){const operands=condStack.splice(-operator.length);condStack.push(operator(...operands));}else{condStack.push(item);}}
return matchCondition(record,condStack.pop());}
return __exports;});;

/* /web/static/src/core/domain_selector/domain_selector.js */
odoo.define('@web/core/domain_selector/domain_selector',['@odoo/owl','@web/core/domain','@web/core/tree_editor/tree_editor','@web/core/tree_editor/condition_tree','@web/core/model_field_selector/utils','@web/core/checkbox/checkbox','@web/core/utils/objects','@web/core/domain_selector/domain_selector_operator_editor','@web/core/tree_editor/tree_editor_operator_editor','@web/core/l10n/translation','@web/core/model_field_selector/model_field_selector','@web/core/utils/hooks','@web/core/tree_editor/utils','@web/core/domain_selector/utils'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{Domain}=require("@web/core/domain");const{TreeEditor}=require("@web/core/tree_editor/tree_editor");const{domainFromTree,treeFromDomain,formatValue,condition,}=require("@web/core/tree_editor/condition_tree");const{useLoadFieldInfo}=require("@web/core/model_field_selector/utils");const{CheckBox}=require("@web/core/checkbox/checkbox");const{deepEqual}=require("@web/core/utils/objects");const{getDomainDisplayedOperators}=require("@web/core/domain_selector/domain_selector_operator_editor");const{getOperatorEditorInfo}=require("@web/core/tree_editor/tree_editor_operator_editor");const{_t}=require("@web/core/l10n/translation");const{ModelFieldSelector}=require("@web/core/model_field_selector/model_field_selector");const{useService}=require("@web/core/utils/hooks");const{useMakeGetFieldDef}=require("@web/core/tree_editor/utils");const{getDefaultCondition}=require("@web/core/domain_selector/utils");const ARCHIVED_CONDITION=condition("active","in",[true,false]);const ARCHIVED_DOMAIN=`[("active", "in", [True, False])]`;const DomainSelector=__exports.DomainSelector=class DomainSelector extends Component{static template="web.DomainSelector";static components={TreeEditor,CheckBox};static props={domain:String,resModel:String,className:{type:String,optional:true},defaultConnector:{type:[{value:"&"},{value:"|"}],optional:true},isDebugMode:{type:Boolean,optional:true},allowExpressions:{type:Boolean,optional:true},readonly:{type:Boolean,optional:true},update:{type:Function,optional:true},debugUpdate:{type:Function,optional:true},};static defaultProps={isDebugMode:false,allowExpressions:true,readonly:true,update:()=>{},};setup(){this.fieldService=useService("field");this.loadFieldInfo=useLoadFieldInfo(this.fieldService);this.makeGetFieldDef=useMakeGetFieldDef(this.fieldService);this.tree=null;this.showArchivedCheckbox=false;this.includeArchived=false;onWillStart(()=>this.onPropsUpdated(this.props));onWillUpdateProps((np)=>this.onPropsUpdated(np));}
async onPropsUpdated(p){let domain;let isSupported=true;try{domain=new Domain(p.domain);}catch{isSupported=false;}
if(!isSupported){this.tree=null;this.showArchivedCheckbox=false;this.includeArchived=false;return;}
const tree=treeFromDomain(domain);const getFieldDef=await this.makeGetFieldDef(p.resModel,tree,["active"]);this.tree=treeFromDomain(domain,{getFieldDef,distributeNot:!p.isDebugMode,});this.showArchivedCheckbox=this.getShowArchivedCheckBox(Boolean(getFieldDef("active")),p);this.includeArchived=false;if(this.showArchivedCheckbox){if(this.tree.type==="connector"&&this.tree.value==="&"){this.tree.children=this.tree.children.filter((child)=>{if(deepEqual(child,ARCHIVED_CONDITION)){this.includeArchived=true;return false;}
return true;});if(this.tree.children.length===1){this.tree=this.tree.children[0];}}else if(deepEqual(this.tree,ARCHIVED_CONDITION)){this.includeArchived=true;this.tree=treeFromDomain(`[]`);}}}
getShowArchivedCheckBox(hasActiveField,props){return hasActiveField;}
getDefaultCondition(fieldDefs){return getDefaultCondition(fieldDefs);}
getDefaultOperator(fieldDef){return getDomainDisplayedOperators(fieldDef,{allowExpressions:this.props.allowExpressions,})[0];}
getOperatorEditorInfo(fieldDef){const operators=getDomainDisplayedOperators(fieldDef,{allowExpressions:this.props.allowExpressions,});return getOperatorEditorInfo(operators,fieldDef);}
getPathEditorInfo(resModel,defaultCondition){const{isDebugMode}=this.props;return{component:ModelFieldSelector,extractProps:({update,value:path})=>{return{path,update,resModel,isDebugMode,readonly:false,};},isSupported:(path)=>[0,1].includes(path)||typeof path==="string",defaultValue:()=>defaultCondition.path,stringify:(path)=>formatValue(path),message:_t("Invalid field chain"),};}
toggleIncludeArchived(){this.includeArchived=!this.includeArchived;this.update(this.tree);}
resetDomain(){this.props.update("[]");}
onDomainInput(domain){if(this.props.debugUpdate){this.props.debugUpdate(domain);}}
onDomainChange(domain){this.props.update(domain,true);}
update(tree){const archiveDomain=this.includeArchived?ARCHIVED_DOMAIN:`[]`;const domain=tree?Domain.and([domainFromTree(tree),archiveDomain]).toString():archiveDomain;this.props.update(domain);}}
return __exports;});;

/* /web/static/src/core/domain_selector/domain_selector_operator_editor.js */
odoo.define('@web/core/domain_selector/domain_selector_operator_editor',[],function(require){'use strict';let __exports={};__exports.getDomainDisplayedOperators=getDomainDisplayedOperators;function getDomainDisplayedOperators(fieldDef,params={}){if(!fieldDef){fieldDef={};}
const{type,is_property}=fieldDef;if(is_property){switch(type){case"many2many":case"tags":return["in","not in","set","not_set"];case"many2one":case"selection":return["=","!=","set","not_set"];}}
const hierarchyOperators=fieldDef.allow_hierachy_operators?["child_of","parent_of"]:[];switch(type){case"boolean":return["is","is_not"];case"selection":return["=","!=","in","not in","set","not_set"];case"char":case"text":case"html":return["=","!=","ilike","not ilike","in","not in","set","not_set","starts_with","ends_with",];case"date":case"datetime":return["=","!=",">",">=","<","<=","between",...("allowExpressions"in params&&!params.allowExpressions?[]:["within"]),"set","not_set",];case"integer":case"float":case"monetary":return["=","!=",">",">=","<","<=","between","ilike","not ilike","set","not_set",];case"many2one":case"many2many":case"one2many":return["in","not in","=","!=","ilike","not ilike",...hierarchyOperators,"set","not_set","starts_with","ends_with","any","not any",];case"json":return["=","!=","ilike","not ilike","set","not_set"];case"binary":case"properties":return["set","not_set"];case undefined:return["="];default:return["=","!=",">",">=","<","<=","ilike","not ilike","like","not like","=like","=ilike","in","not in","set","not_set",];}}
return __exports;});;

/* /web/static/src/core/domain_selector/utils.js */
odoo.define('@web/core/domain_selector/utils',['@web/core/tree_editor/tree_editor_value_editors','@web/core/domain_selector/domain_selector_operator_editor','@web/core/utils/hooks','@web/core/tree_editor/condition_tree','@web/core/tree_editor/utils'],function(require){'use strict';let __exports={};const{getDefaultValue}=require("@web/core/tree_editor/tree_editor_value_editors");const{getDomainDisplayedOperators}=require("@web/core/domain_selector/domain_selector_operator_editor");const{useService}=require("@web/core/utils/hooks");const{domainFromTree,condition}=require("@web/core/tree_editor/condition_tree");const{getDefaultPath}=require("@web/core/tree_editor/utils");__exports.getDefaultCondition=getDefaultCondition;function getDefaultCondition(fieldDefs){const defaultPath=getDefaultPath(fieldDefs);const fieldDef=fieldDefs[defaultPath];const operator=getDomainDisplayedOperators(fieldDef)[0];const value=getDefaultValue(fieldDef,operator);return condition(fieldDef.name,operator,value);}
__exports.getDefaultDomain=getDefaultDomain;function getDefaultDomain(fieldDefs){return domainFromTree(getDefaultCondition(fieldDefs));}
__exports.useGetDefaultLeafDomain=useGetDefaultLeafDomain;function useGetDefaultLeafDomain(){const fieldService=useService("field");return async(resModel)=>{const fieldDefs=await fieldService.loadFields(resModel);return getDefaultDomain(fieldDefs);};}
return __exports;});;

/* /web/static/src/core/domain_selector_dialog/domain_selector_dialog.js */
odoo.define('@web/core/domain_selector_dialog/domain_selector_dialog',['@web/core/l10n/translation','@odoo/owl','@web/core/dialog/dialog','@web/core/domain','@web/core/domain_selector/domain_selector','@web/core/network/rpc','@web/core/utils/hooks','@web/core/user'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{Component,useRef,useState}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{Domain}=require("@web/core/domain");const{DomainSelector}=require("@web/core/domain_selector/domain_selector");const{rpc}=require("@web/core/network/rpc");const{useService}=require("@web/core/utils/hooks");const{user}=require("@web/core/user");const DomainSelectorDialog=__exports.DomainSelectorDialog=class DomainSelectorDialog extends Component{static template="web.DomainSelectorDialog";static components={Dialog,DomainSelector,};static props={close:Function,onConfirm:Function,resModel:String,className:{type:String,optional:true},defaultConnector:{type:[{value:"&"},{value:"|"}],optional:true},domain:String,isDebugMode:{type:Boolean,optional:true},readonly:{type:Boolean,optional:true},text:{type:String,optional:true},confirmButtonText:{type:String,optional:true},disableConfirmButton:{type:Function,optional:true},discardButtonText:{type:String,optional:true},title:{type:String,optional:true},context:{type:Object,optional:true},};static defaultProps={isDebugMode:false,readonly:false,context:{},};setup(){this.notification=useService("notification");this.orm=useService("orm");this.state=useState({domain:this.props.domain});this.confirmButtonRef=useRef("confirm");}
get confirmButtonText(){return this.props.confirmButtonText||_t("Confirm");}
get dialogTitle(){return this.props.title||_t("Domain");}
get disabled(){if(this.props.disableConfirmButton){return this.props.disableConfirmButton(this.state.domain);}
return false;}
get discardButtonText(){return this.props.discardButtonText||_t("Discard");}
get domainSelectorProps(){return{className:this.props.className,resModel:this.props.resModel,readonly:this.props.readonly,isDebugMode:this.props.isDebugMode,defaultConnector:this.props.defaultConnector,domain:this.state.domain,update:(domain)=>{this.state.domain=domain;},};}
async onConfirm(){this.confirmButtonRef.el.disabled=true;let domain;let isValid;try{const evalContext={...user.context,...this.props.context};domain=new Domain(this.state.domain).toList(evalContext);}catch{isValid=false;}
if(isValid===undefined){isValid=await rpc("/web/domain/validate",{model:this.props.resModel,domain,});}
if(!isValid){if(this.confirmButtonRef.el){this.confirmButtonRef.el.disabled=false;}
this.notification.add(_t("Domain is invalid. Please correct it"),{type:"danger",});return;}
this.props.onConfirm(this.state.domain);this.props.close();}
onDiscard(){this.props.close();}}
return __exports;});;

/* /web/static/src/core/dropdown/_behaviours/dropdown_group_hook.js */
odoo.define('@web/core/dropdown/_behaviours/dropdown_group_hook',['@odoo/owl','@web/core/dropdown/dropdown_group'],function(require){'use strict';let __exports={};const{useComponent,useEffect,useEnv}=require("@odoo/owl");const{DROPDOWN_GROUP}=require("@web/core/dropdown/dropdown_group");__exports.useDropdownGroup=useDropdownGroup;function useDropdownGroup(){const env=useEnv();const group={isInGroup:DROPDOWN_GROUP in env,get isOpen(){return this.isInGroup&&[...env[DROPDOWN_GROUP]].some((dropdown)=>dropdown.isOpen);},};if(group.isInGroup){const dropdown=useComponent();useEffect(()=>{env[DROPDOWN_GROUP].add(dropdown.state);return()=>env[DROPDOWN_GROUP].delete(dropdown.state);});}
return group;}
return __exports;});;

/* /web/static/src/core/dropdown/_behaviours/dropdown_nesting.js */
odoo.define('@web/core/dropdown/_behaviours/dropdown_nesting',['@odoo/owl','@web/core/l10n/localization','@web/core/utils/hooks','@web/core/utils/reactive'],function(require){'use strict';let __exports={};const{EventBus,onWillDestroy,useChildSubEnv,useEffect,useEnv}=require("@odoo/owl");const{localization}=require("@web/core/l10n/localization");const{useBus,useService}=require("@web/core/utils/hooks");const{effect}=require("@web/core/utils/reactive");const DROPDOWN_NESTING=__exports.DROPDOWN_NESTING=Symbol("dropdownNesting");const BUS=new EventBus();class DropdownNestingState{constructor({parent,close}){this._isOpen=false;this.parent=parent;this.children=new Set();this.close=close;parent?.children.add(this);}
set isOpen(value){this._isOpen=value;if(this._isOpen){BUS.trigger("dropdown-opened",this);}}
get isOpen(){return this._isOpen;}
remove(){this.parent?.children.delete(this);}
closeAllParents(){this.close();if(this.parent){this.parent.closeAllParents();}}
closeChildren(){this.children.forEach((child)=>child.close());}
shouldIgnoreChanges(other){return(other===this||other.activeEl!==this.activeEl||[...this.children].some((child)=>child.shouldIgnoreChanges(other)));}
handleChange(other){if(this.shouldIgnoreChanges(other)){return;}
if(other.isOpen&&this.isOpen){this.close();}}}
__exports.useDropdownNesting=useDropdownNesting;function useDropdownNesting(state){const env=useEnv();const current=new DropdownNestingState({parent:env[DROPDOWN_NESTING],close:()=>state.close(),});const uiService=useService("ui");useEffect(()=>{Promise.resolve().then(()=>{current.activeEl=uiService.activeElement;});},()=>[]);useChildSubEnv({[DROPDOWN_NESTING]:current});useBus(BUS,"dropdown-opened",({detail:other})=>current.handleChange(other));effect((state)=>{current.isOpen=state.isOpen;},[state]);onWillDestroy(()=>{current.remove();});return{get hasParent(){return Boolean(current.parent);},navigationOptions:{onEnabled:(items)=>{if(current.parent){items[0]?.focus();}},onMouseEnter:(item)=>{if(item.target.classList.contains("o-dropdown")){item.select();}},hotkeys:{escape:()=>current.close(),arrowleft:(index,items)=>{if(localization.direction==="rtl"&&items[index]?.target.classList.contains("o-dropdown")){items[index]?.select();}else if(current.parent){current.close();}},arrowright:(index,items)=>{if(localization.direction==="rtl"&&current.parent){current.close();}else if(items[index]?.target.classList.contains("o-dropdown")){items[index]?.select();}},},},};}
return __exports;});;

/* /web/static/src/core/dropdown/_behaviours/dropdown_popover.js */
odoo.define('@web/core/dropdown/_behaviours/dropdown_popover',['@odoo/owl','@web/core/dropdown/dropdown_item'],function(require){'use strict';let __exports={};const{Component,onMounted,onRendered,onWillDestroy,onWillStart,xml}=require("@odoo/owl");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const DropdownPopover=__exports.DropdownPopover=class DropdownPopover extends Component{static components={DropdownItem};static template=xml`
        <t t-if="this.props.items">
            <t t-foreach="this.props.items" t-as="item" t-key="this.getKey(item, item_index)">
                <DropdownItem class="item.class" onSelected="() => item.onSelected()" t-out="item.label"/>
            </t>
        </t>
        <t t-slot="content" />
    `;static props={close:{type:Function,optional:true},beforeOpen:{type:Function,optional:true},onOpened:{type:Function,optional:true},onClosed:{type:Function,optional:true},refresher:Object,slots:Object,items:{type:Array,optional:true},};setup(){onRendered(()=>{this.props.refresher.token;});onWillStart(async()=>{await this.props.beforeOpen?.();});onMounted(()=>{this.props.onOpened?.();});onWillDestroy(()=>{this.props.onClosed?.();});}
getKey(item,index){return"id"in item?item.id:index;}}
return __exports;});;

/* /web/static/src/core/dropdown/accordion_item.js */
odoo.define('@web/core/dropdown/accordion_item',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onPatched,useState}=require("@odoo/owl");const ACCORDION=__exports.ACCORDION=Symbol("Accordion");const AccordionItem=__exports.AccordionItem=class AccordionItem extends Component{static template="web.AccordionItem";static components={};static props={slots:{type:Object,shape:{default:{},},},description:String,selected:{type:Boolean,optional:true,},class:{type:String,optional:true,},};static defaultProps={class:"",selected:false,};setup(){this.state=useState({open:false,});this.parentComponent=this.env[ACCORDION];onPatched(()=>{this.parentComponent?.accordionStateChanged?.();});}}
return __exports;});;

/* /web/static/src/core/dropdown/checkbox_item.js */
odoo.define('@web/core/dropdown/checkbox_item',['@web/core/dropdown/dropdown_item'],function(require){'use strict';let __exports={};const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const CheckboxItem=__exports.CheckboxItem=class CheckboxItem extends DropdownItem{static template="web.CheckboxItem";static props={...DropdownItem.props,checked:{type:Boolean,optional:false,},};}
return __exports;});;

/* /web/static/src/core/dropdown/dropdown.js */
odoo.define('@web/core/dropdown/dropdown',['@odoo/owl','@web/core/dropdown/_behaviours/dropdown_group_hook','@web/core/dropdown/_behaviours/dropdown_nesting','@web/core/dropdown/_behaviours/dropdown_popover','@web/core/dropdown/dropdown_hooks','@web/core/navigation/navigation','@web/core/popover/popover_hook','@web/core/utils/classname','@web/core/utils/hooks','@web/core/utils/objects','@web/core/utils/reactive'],function(require){'use strict';let __exports={};const{Component,onMounted,onRendered,onWillUpdateProps,reactive,status,useEffect,xml,}=require("@odoo/owl");const{useDropdownGroup}=require("@web/core/dropdown/_behaviours/dropdown_group_hook");const{useDropdownNesting}=require("@web/core/dropdown/_behaviours/dropdown_nesting");const{DropdownPopover}=require("@web/core/dropdown/_behaviours/dropdown_popover");const{useDropdownState}=require("@web/core/dropdown/dropdown_hooks");const{useNavigation}=require("@web/core/navigation/navigation");const{usePopover}=require("@web/core/popover/popover_hook");const{mergeClasses}=require("@web/core/utils/classname");const{useChildRef,useService}=require("@web/core/utils/hooks");const{deepMerge}=require("@web/core/utils/objects");const{effect}=require("@web/core/utils/reactive");function getFirstElementOfNode(node){if(!node){return null;}
if(node.el){return node.el.nodeType===Node.ELEMENT_NODE?node.el:null;}
if(node.bdom||node.child){return getFirstElementOfNode(node.bdom||node.child);}
if(node.children){for(const child of node.children){const el=getFirstElementOfNode(child);if(el){return el;}}}
return null;}
const Dropdown=__exports.Dropdown=class Dropdown extends Component{static template=xml`<t t-slot="default"/>`;static components={};static props={arrow:{optional:true},menuClass:{optional:true},position:{type:String,optional:true},slots:{type:Object,shape:{default:{optional:true},content:{optional:true},},},items:{optional:true,type:Array,elements:{type:Object,shape:{label:String,onSelected:Function,class:{optional:true},"*":true,},},},menuRef:{type:Function,optional:true},disabled:{type:Boolean,optional:true},holdOnHover:{type:Boolean,optional:true},beforeOpen:{type:Function,optional:true},onOpened:{type:Function,optional:true},onStateChanged:{type:Function,optional:true},state:{type:Object,shape:{isOpen:Boolean,close:Function,open:Function,"*":true,},optional:true,},manual:{type:Boolean,optional:true},navigationOptions:{type:Object,optional:true},};static defaultProps={arrow:false,disabled:false,holdOnHover:false,menuClass:"",state:undefined,navigationOptions:{},};setup(){this.menuRef=this.props.menuRef||useChildRef();this.state=this.props.state||useDropdownState();this.nesting=useDropdownNesting(this.state);this.group=useDropdownGroup();this.navigation=useNavigation(this.menuRef,{focusInitialElementOnDisabled:()=>!this.group.isInGroup,itemsSelector:":scope .o-navigable, :scope .o-dropdown",...deepMerge(this.nesting.navigationOptions,this.props.navigationOptions),});let activeEl;this.uiService=useService("ui");useEffect(()=>{Promise.resolve().then(()=>{activeEl=this.uiService.activeElement;});},()=>[]);this.popover=usePopover(DropdownPopover,{animation:false,arrow:this.props.arrow,closeOnClickAway:(target)=>{return this.popoverCloseOnClickAway(target,activeEl);},closeOnEscape:false,env:this.__owl__.childEnv,holdOnHover:this.props.holdOnHover,onClose:()=>this.state.close(),onPositioned:(el,{direction})=>this.setTargetDirectionClass(direction),popoverClass:mergeClasses("o-dropdown--menu dropdown-menu mx-0",{"o-dropdown--menu-submenu":this.hasParent},this.props.menuClass),popoverRole:"menu",position:this.position,ref:this.menuRef,setActiveElement:false,});onRendered(()=>(this.popoverRefresher?this.popoverRefresher.token++:null));onMounted(()=>this.onStateChanged(this.state));effect((state)=>this.onStateChanged(state),[this.state]);useEffect((target)=>this.setTargetElement(target),()=>[this.target]);onWillUpdateProps(({disabled})=>{if(disabled){this.closePopover();}});}
get position(){return this.props.position||(this.hasParent?"right-start":"bottom-start");}
get hasParent(){return this.nesting.hasParent;}
get target(){const target=getFirstElementOfNode(this.__owl__.bdom);if(!target){throw new Error("Could not find a valid dropdown toggler, prefer a single html element and put any dynamic content inside of it.");}
return target;}
handleClick(event){if(this.props.disabled){return;}
event.stopPropagation();if(this.state.isOpen&&!this.hasParent){this.state.close();}else{this.state.open();}}
handleMouseEnter(){if(this.props.disabled){return;}
if(this.hasParent||this.group.isOpen){this.target.focus();this.state.open();}}
onStateChanged(state){if(state.isOpen){this.openPopover();}else{this.closePopover();}}
popoverCloseOnClickAway(target,activeEl){const rootNode=target.getRootNode();if(rootNode instanceof ShadowRoot){target=rootNode.host;}
return this.uiService.getActiveElementOf(target)===activeEl;}
setTargetElement(target){if(!target){return;}
target.ariaExpanded=false;target.classList.add("o-dropdown");if(this.hasParent){target.classList.add("o-dropdown--has-parent");}
const tagName=target.tagName.toLowerCase();if(!["input","textarea","table","thead","tbody","tr","th","td"].includes(tagName)){target.classList.add("dropdown-toggle");if(this.hasParent){target.classList.add("o-dropdown-item","o-navigable","dropdown-item");if(!target.classList.contains("o-dropdown--no-caret")){target.classList.add("o-dropdown-caret");}}}
this.defaultDirection=this.position.split("-")[0];this.setTargetDirectionClass(this.defaultDirection);if(!this.props.manual){target.addEventListener("click",this.handleClick.bind(this));target.addEventListener("mouseenter",this.handleMouseEnter.bind(this));return()=>{target.removeEventListener("click",this.handleClick.bind(this));target.removeEventListener("mouseenter",this.handleMouseEnter.bind(this));};}}
setTargetDirectionClass(direction){if(!this.target){return;}
const directionClasses={bottom:"dropdown",top:"dropup",left:"dropstart",right:"dropend",};this.target.classList.remove(...Object.values(directionClasses));this.target.classList.add(directionClasses[direction]);}
openPopover(){if(this.popover.isOpen||status(this)!=="mounted"){return;}
if(!this.target||!this.target.isConnected){this.state.close();return;}
this.popoverRefresher=reactive({token:0});const props={beforeOpen:()=>this.props.beforeOpen?.(),onOpened:()=>this.onOpened(),onClosed:()=>this.onClosed(),refresher:this.popoverRefresher,items:this.props.items,slots:this.props.slots,};this.popover.open(this.target,props);}
closePopover(){this.popover.close();this.navigation.disable();}
onOpened(){this.navigation.enable();this.props.onOpened?.();this.props.onStateChanged?.(true);if(this.target){this.target.ariaExpanded=true;this.target.classList.add("show");}}
onClosed(){this.props.onStateChanged?.(false);if(this.target){this.target.ariaExpanded=false;this.target.classList.remove("show");this.setTargetDirectionClass(this.defaultDirection);}}}
return __exports;});;

/* /web/static/src/core/dropdown/dropdown_group.js */
odoo.define('@web/core/dropdown/dropdown_group',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onWillDestroy,useChildSubEnv,xml}=require("@odoo/owl");const GROUPS=new Map();function getGroup(id){if(!GROUPS.has(id)){GROUPS.set(id,{group:new Set(),count:0,});}
GROUPS.get(id).count++;return GROUPS.get(id).group;}
function removeGroup(id){const groupData=GROUPS.get(id);groupData.count--;if(groupData.count<=0){GROUPS.delete(id);}}
const DROPDOWN_GROUP=__exports.DROPDOWN_GROUP=Symbol("dropdownGroup");const DropdownGroup=__exports.DropdownGroup=class DropdownGroup extends Component{static template=xml`<t t-slot="default"/>`;static props={group:{type:String,optional:true},slots:Object,};setup(){if(this.props.group){const group=getGroup(this.props.group);onWillDestroy(()=>removeGroup(this.props.group));useChildSubEnv({[DROPDOWN_GROUP]:group});}else{useChildSubEnv({[DROPDOWN_GROUP]:new Set()});}}}
return __exports;});;

/* /web/static/src/core/dropdown/dropdown_hooks.js */
odoo.define('@web/core/dropdown/dropdown_hooks',['@odoo/owl','@web/core/dropdown/_behaviours/dropdown_nesting'],function(require){'use strict';let __exports={};const{useEnv,useState}=require("@odoo/owl");const{DROPDOWN_NESTING}=require("@web/core/dropdown/_behaviours/dropdown_nesting");__exports.useDropdownState=useDropdownState;function useDropdownState({onOpen,onClose}={}){const state=useState({isOpen:false,open:()=>{state.isOpen=true;onOpen?.();},close:()=>{state.isOpen=false;onClose?.();},});return state;}
__exports.useDropdownCloser=useDropdownCloser;function useDropdownCloser(){const env=useEnv();const dropdown=env[DROPDOWN_NESTING];return{close:()=>dropdown?.close(),closeChildren:()=>dropdown?.closeChildren(),closeAll:()=>dropdown?.closeAllParents(),};}
return __exports;});;

/* /web/static/src/core/dropdown/dropdown_item.js */
odoo.define('@web/core/dropdown/dropdown_item',['@odoo/owl','@web/core/dropdown/dropdown_hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{useDropdownCloser}=require("@web/core/dropdown/dropdown_hooks");const ClosingMode={None:"none",ClosestParent:"closest",AllParents:"all",};const DropdownItem=__exports.DropdownItem=class DropdownItem extends Component{static template="web.DropdownItem";static props={class:{type:[String,Object],optional:true,},onSelected:{type:Function,optional:true,},closingMode:{type:ClosingMode,optional:true,},attrs:{type:Object,optional:true,},slots:{Object,optional:true},};static defaultProps={closingMode:ClosingMode.AllParents,attrs:{},};setup(){this.dropdownControl=useDropdownCloser();}
onClick(ev){if(this.props.attrs&&this.props.attrs.href){ev.preventDefault();}
this.props.onSelected?.();switch(this.props.closingMode){case ClosingMode.ClosestParent:this.dropdownControl.close();break;case ClosingMode.AllParents:this.dropdownControl.closeAll();break;}}}
return __exports;});;

/* /web/static/src/core/dropzone/dropzone.js */
odoo.define('@web/core/dropzone/dropzone',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,useEffect,useRef,useState}=require("@odoo/owl");const Dropzone=__exports.Dropzone=class Dropzone extends Component{static props={extraClass:{type:String,optional:true},onDrop:{type:Function,optional:true},ref:Object,slots:{type:Object,optional:true},};static template="web.Dropzone";setup(){super.setup();this.root=useRef("root");this.state=useState({isDraggingInside:false,});useEffect(()=>{const{top,left,width,height}=this.props.ref.el.getBoundingClientRect();this.root.el.style=`top:${top}px;left:${left}px;width:${width}px;height:${height}px;`;});}}
return __exports;});;

/* /web/static/src/core/dropzone/dropzone_hook.js */
odoo.define('@web/core/dropzone/dropzone_hook',['@web/core/dropzone/dropzone','@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Dropzone}=require("@web/core/dropzone/dropzone");const{useEffect,useExternalListener}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");__exports.useCustomDropzone=useCustomDropzone;function useCustomDropzone(targetRef,dropzoneComponent,dropzoneComponentProps,isDropzoneEnabled=()=>true){const overlayService=useService("overlay");const uiService=useService("ui");let dragCount=0;let hasTarget=false;let removeDropzone=false;useExternalListener(document,"dragenter",onDragEnter,{capture:true});useExternalListener(document,"dragleave",onDragLeave,{capture:true});useExternalListener(window,"dragover",(ev)=>{if(ev.dataTransfer&&ev.dataTransfer.types.includes("Files")){ev.preventDefault();}});useExternalListener(window,"drop",(ev)=>{if(ev.dataTransfer&&ev.dataTransfer.types.includes("Files")){ev.preventDefault();}
dragCount=0;updateDropzone();},{capture:true});function updateDropzone(){const hasDropzone=!!removeDropzone;const isTargetInActiveElement=uiService.activeElement.contains(targetRef.el);const shouldDisplayDropzone=dragCount&&hasTarget&&isTargetInActiveElement&&isDropzoneEnabled();if(shouldDisplayDropzone&&!hasDropzone){removeDropzone=overlayService.add(dropzoneComponent,{ref:targetRef,...dropzoneComponentProps});}
if(!shouldDisplayDropzone&&hasDropzone){removeDropzone();removeDropzone=false;}}
function onDragEnter(ev){if(dragCount||(ev.dataTransfer&&ev.dataTransfer.types.includes("Files"))){dragCount++;updateDropzone();}}
function onDragLeave(){if(dragCount){dragCount--;updateDropzone();}}
useEffect((el)=>{hasTarget=!!el;updateDropzone();},()=>[targetRef.el]);}
__exports.useDropzone=useDropzone;function useDropzone(targetRef,onDrop,extraClass,isDropzoneEnabled=()=>true){const dropzoneComponent=Dropzone;const dropzoneComponentProps={extraClass,onDrop};useCustomDropzone(targetRef,dropzoneComponent,dropzoneComponentProps,isDropzoneEnabled);}
return __exports;});;

/* /web/static/src/core/effects/effect_service.js */
odoo.define('@web/core/effects/effect_service',['@web/core/l10n/translation','@web/core/registry','@web/core/user','@web/core/effects/rainbow_man'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{registry}=require("@web/core/registry");const{user}=require("@web/core/user");const{RainbowMan}=require("@web/core/effects/rainbow_man");const effectRegistry=registry.category("effects");function rainbowMan(env,params={}){let message=params.message;if(message instanceof Element){console.log("Providing an HTML element to an effect is deprecated. Note that all event handlers will be lost.");message=message.outerHTML;}else if(!message){message=_t("Well Done!");}
if(user.showEffect){const props={imgUrl:params.img_url||"/web/static/img/smile.svg",fadeout:params.fadeout||"medium",message,Component:params.Component,props:params.props,};return{Component:RainbowMan,props};}
env.services.notification.add(message);}
effectRegistry.add("rainbow_man",rainbowMan);const effectService=__exports.effectService={dependencies:["overlay"],start(env,{overlay}){const add=(params={})=>{const type=params.type||"rainbow_man";const effect=effectRegistry.get(type);const{Component,props}=effect(env,params)||{};if(Component){const remove=overlay.add(Component,{...props,close:()=>remove(),});}};return{add};},};registry.category("services").add("effect",effectService);return __exports;});;

/* /web/static/src/core/effects/rainbow_man.js */
odoo.define('@web/core/effects/rainbow_man',['@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Component,useEffect,useExternalListener,useState}=require("@odoo/owl");const RainbowMan=__exports.RainbowMan=class RainbowMan extends Component{static template="web.RainbowMan";static rainbowFadeouts={slow:4500,medium:3500,fast:2000,no:false};static props={fadeout:String,close:Function,message:String,imgUrl:String,Component:{type:Function,optional:true},props:{type:Object,optional:true},};setup(){useExternalListener(document.body,"click",this.closeRainbowMan);this.state=useState({isFading:false});this.delay=RainbowMan.rainbowFadeouts[this.props.fadeout];if(this.delay){useEffect(()=>{const timeout=browser.setTimeout(()=>{this.state.isFading=true;},this.delay);return()=>browser.clearTimeout(timeout);},()=>[]);}}
onAnimationEnd(ev){if(this.delay&&ev.animationName==="reward-fading-reverse"){ev.stopPropagation();this.closeRainbowMan();}}
closeRainbowMan(){this.props.close();}}
return __exports;});;

/* /web/static/src/core/emoji_picker/emoji_picker.js */
odoo.define('@web/core/emoji_picker/emoji_picker',['@web/core/utils/misc','@odoo/owl','@web/core/assets','@web/core/browser/browser','@web/core/l10n/translation','@web/core/popover/popover_hook','@web/core/utils/search','@web/core/utils/hooks','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{markEventHandled}=require("@web/core/utils/misc");const{Component,onMounted,onPatched,onWillDestroy,onWillPatch,onWillStart,onWillUnmount,useEffect,useRef,useState,}=require("@odoo/owl");const{loadBundle}=require("@web/core/assets");const{browser}=require("@web/core/browser/browser");const{_t}=require("@web/core/l10n/translation");const{usePopover}=require("@web/core/popover/popover_hook");const{fuzzyLookup}=require("@web/core/utils/search");const{useAutofocus,useService}=require("@web/core/utils/hooks");const{isMobileOS}=require("@web/core/browser/feature_detection");__exports.useEmojiPicker=useEmojiPicker;function useEmojiPicker(ref,props,options={}){const targets=[];const state=useState({isOpen:false});const newOptions={...options,onClose:()=>{state.isOpen=false;options.onClose?.();},};const popover=usePopover(EmojiPicker,{...newOptions,animation:false,popoverClass:"border-secondary",});props.storeScroll={scrollValue:0,set:(value)=>{props.storeScroll.scrollValue=value;},get:()=>{return props.storeScroll.scrollValue;},};function add(ref,onSelect,{show=false}={}){const toggler=()=>toggle(ref,onSelect);targets.push([ref,toggler]);if(!ref.el){return;}
ref.el.addEventListener("click",toggler);ref.el.addEventListener("mouseenter",loadEmoji);if(show){ref.el.click();}}
function toggle(ref,onSelect=props.onSelect){if(popover.isOpen){popover.close();}else{state.isOpen=true;popover.open(ref.el,{...props,onSelect});}}
if(ref){add(ref);}
onMounted(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;}
ref.el.addEventListener("click",toggle);ref.el.addEventListener("mouseenter",loadEmoji);}});onWillPatch(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;}
ref.el.removeEventListener("click",toggle);ref.el.removeEventListener("mouseenter",loadEmoji);}});onPatched(()=>{for(const[ref,toggle]of targets){if(!ref.el){continue;}
ref.el.addEventListener("click",toggle);ref.el.addEventListener("mouseenter",loadEmoji);}});Object.assign(state,{add});return state;}
const loadingListeners=[];const loader=__exports.loader={loadEmoji:()=>loadBundle("web.assets_emoji"),loaded:undefined,onEmojiLoaded(cb){loadingListeners.push(cb);},};__exports.loadEmoji=loadEmoji;async function loadEmoji(){const res={categories:[],emojis:[]};try{await loader.loadEmoji();const{getCategories,getEmojis}=odoo.loader.modules.get("@web/core/emoji_picker/emoji_data");res.categories=getCategories();res.emojis=getEmojis();return res;}catch{return res;}finally{if(!loader.loaded){loader.loaded={emojiValueToShortcode:{}};for(const emoji of res.emojis){const value=emoji.codepoints;const shortcode=emoji.shortcodes[0];loader.loaded.emojiValueToShortcode[value]=shortcode;for(const listener of loadingListeners){listener();}
loadingListeners.length=0;}}}}
const EMOJI_PICKER_PROPS=__exports.EMOJI_PICKER_PROPS=["close?","onClose?","onSelect","state?","storeScroll?"];const EmojiPicker=__exports.EmojiPicker=class EmojiPicker extends Component{static props=EMOJI_PICKER_PROPS;static template="web.EmojiPicker";categories=null;emojis=null;shouldScrollElem=null;lastSearchTerm;keyboardNavigated=false;setup(){this.gridRef=useRef("emoji-grid");this.navbarRef=useRef("navbar");this.ui=useState(useService("ui"));this.isMobileOS=isMobileOS();this.state=useState({activeEmojiIndex:0,categoryId:null,recent:JSON.parse(browser.localStorage.getItem("web.emoji.frequent")||"{}"),searchTerm:"",});const onStorage=(ev)=>{if(ev.key==="web.emoji.frequent"){this.state.recent=ev.newValue?JSON.parse(ev.newValue):{};}else if(ev.key===null){this.state.recent={};}};browser.addEventListener("storage",onStorage);onWillDestroy(()=>{browser.removeEventListener("storage",onStorage);});useAutofocus();onWillStart(async()=>{const{categories,emojis}=await loadEmoji();this.categories=categories;this.emojis=emojis;this.emojiByCodepoints=Object.fromEntries(this.emojis.map((emoji)=>[emoji.codepoints,emoji]));this.recentCategory={name:"Frequently used",displayName:_t("Frequently used"),title:"🕓",sortId:0,};this.state.categoryId=this.recentEmojis.length?this.recentCategory.sortId:this.categories[0].sortId;});onMounted(()=>{if(this.emojis.length===0){return;}
this.navbarResizeObserver=new ResizeObserver(()=>this.adaptNavbar());this.navbarResizeObserver.observe(this.navbarRef.el);this.adaptNavbar();this.highlightActiveCategory();if(this.props.storeScroll){this.gridRef.el.scrollTop=this.props.storeScroll.get();}});onPatched(()=>{if(this.emojis.length===0){return;}
if(this.shouldScrollElem){this.shouldScrollElem=false;const getElement=()=>this.gridRef.el.querySelector(`.o-EmojiPicker-category[data-category="${this.state.categoryId}"`);const elem=getElement();if(elem){elem.scrollIntoView();}else{this.shouldScrollElem=getElement;}}});useEffect(()=>this.updateEmojiPickerRepr(),()=>[this.state.categoryId,this.state.searchTerm]);useEffect((el)=>{const gridEl=this.gridRef?.el;const activeEl=gridEl?.querySelector(".o-Emoji.o-active");if(gridEl&&activeEl&&this.keyboardNavigated&&!isElementVisible(activeEl,gridEl)){activeEl.scrollIntoView({block:"center",behavior:"instant"});this.keyboardNavigated=false;}},()=>[this.state.activeEmojiIndex,this.gridRef?.el]);useEffect(()=>{if(this.searchTerm){this.gridRef.el.scrollTop=0;this.state.categoryId=null;}else{if(this.lastSearchTerm){this.gridRef.el.scrollTop=0;}
this.highlightActiveCategory();}
this.lastSearchTerm=this.searchTerm;},()=>[this.searchTerm]);onWillUnmount(()=>{this.navbarResizeObserver?.disconnect();if(!this.gridRef.el){return;}
if(this.props.storeScroll){this.props.storeScroll.set(this.gridRef.el.scrollTop);}});}
adaptNavbar(){const computedStyle=getComputedStyle(this.navbarRef.el);const availableWidth=this.navbarRef.el.getBoundingClientRect().width-
parseInt(computedStyle.paddingLeft)-
parseInt(computedStyle.marginLeft)-
parseInt(computedStyle.paddingLeft)-
parseInt(computedStyle.marginLeft);const itemWidth=this.navbarRef.el.querySelector(".o-Emoji").getBoundingClientRect().width;const gapWidth=parseInt(computedStyle.gap);const maxAvailableNavbarItemAmountAtOnce=Math.floor(availableWidth/(itemWidth+gapWidth));const repr=[];let panel=[];const allCategories=this.getAllCategories();for(const category of allCategories){if(panel.length===maxAvailableNavbarItemAmountAtOnce-1&&category!==allCategories.at(-1)){panel.push("next");repr.push(panel);panel=[];panel.push("previous");}
panel.push(category.sortId);}
if(panel.length>0){if(repr.length>0){panel.push(...[...Array(maxAvailableNavbarItemAmountAtOnce-panel.length)].map((_,idx)=>"empty_"+idx));}
repr.push(panel);}
this.state.emojiNavbarRepr=repr;}
get currentNavbarPanel(){if(!this.state.emojiNavbarRepr){return this.getAllCategories().map((c)=>c.sortId);}
if(this.state.categoryId===null||Number.isNaN(this.state.categoryId)){return this.state.emojiNavbarRepr[0];}
return this.state.emojiNavbarRepr.find((panel)=>panel.includes(this.state.categoryId));}
get searchTerm(){return this.props.state?this.props.state.searchTerm:this.state.searchTerm;}
set searchTerm(value){if(this.props.state){this.props.state.searchTerm=value;}else{this.state.searchTerm=value;}}
get itemsNumber(){return this.recentEmojis.length+this.getEmojis().length;}
get recentEmojis(){const recent=Object.entries(this.state.recent).sort(([,usage_1],[,usage_2])=>usage_2-usage_1).map(([codepoints])=>this.emojiByCodepoints[codepoints]);if(this.searchTerm&&recent.length>0){return fuzzyLookup(this.searchTerm,recent,(emoji)=>[emoji.name,...emoji.keywords,...emoji.emoticons,...emoji.shortcodes,]);}
return recent.slice(0,42);}
onClick(ev){markEventHandled(ev,"emoji.selectEmoji");}
onClickToNextCategories(){const panelIndex=this.state.emojiNavbarRepr.findIndex((p)=>p.includes(this.state.categoryId));this.selectCategory(this.state.emojiNavbarRepr[panelIndex+1][1]);}
onClickToPreviousCategories(){const panelIndex=this.state.emojiNavbarRepr.findIndex((p)=>p.includes(this.state.categoryId));this.selectCategory(this.state.emojiNavbarRepr[panelIndex-1].at(-2));}
updateEmojiPickerRepr(){if(this.emojis.length===0){return;}
const emojiEls=Array.from(this.gridRef.el.querySelectorAll(".o-Emoji"));const emojiRects=emojiEls.map((el)=>el.getBoundingClientRect());this.emojiMatrix=[];for(const[index,pos]of emojiRects.entries()){const emojiIndex=emojiEls[index].dataset.index;if(this.emojiMatrix.length===0||pos.top>emojiRects[index-1].top){this.emojiMatrix.push([]);}
this.emojiMatrix.at(-1).push(parseInt(emojiIndex));}}
handleNavigation(key){const currentIdx=this.state.activeEmojiIndex;let currentRow=-1;let currentCol=-1;const rowIdx=this.emojiMatrix.findIndex((row)=>row.includes(currentIdx));if(rowIdx!==-1){currentRow=rowIdx;currentCol=this.emojiMatrix[currentRow].indexOf(currentIdx);}
let newIdx;switch(key){case"ArrowDown":{const rowBelow=this.emojiMatrix[currentRow+1];const rowBelowBelow=this.emojiMatrix[currentRow+2];if(rowBelow?.length<=currentCol&&rowBelowBelow?.length>=currentCol){newIdx=rowBelowBelow?.[currentCol];}else{newIdx=rowBelow?.[Math.min(currentCol,rowBelow.length-1)];}
break;}
case"ArrowUp":{const rowAbove=this.emojiMatrix[currentRow-1];const rowAboveAbove=this.emojiMatrix[currentRow-2];if(rowAbove?.length<=currentCol&&rowAboveAbove?.length>=currentCol){newIdx=rowAboveAbove?.[currentCol];}else{newIdx=rowAbove?.[Math.min(currentCol,rowAbove.length-1)];}
break;}
case"ArrowRight":{const colRight=currentCol+1;if(colRight===this.emojiMatrix[currentRow].length){const rowBelowRight=this.emojiMatrix[currentRow+1];newIdx=rowBelowRight?.[0];}else{newIdx=this.emojiMatrix[currentRow][colRight];}
break;}
case"ArrowLeft":{const colLeft=currentCol-1;if(colLeft<0){const rowAboveLeft=this.emojiMatrix[currentRow-1];newIdx=rowAboveLeft?.[rowAboveLeft.length-1]??this.state.activeEmojiIndex;}else{newIdx=this.emojiMatrix[currentRow][colLeft];}
break;}}
this.state.activeEmojiIndex=newIdx??this.state.activeEmojiIndex;}
onKeydown(ev){switch(ev.key){case"ArrowDown":case"ArrowUp":case"ArrowRight":case"ArrowLeft":this.handleNavigation(ev.key);this.keyboardNavigated=true;break;case"Enter":ev.preventDefault();this.gridRef.el.querySelector(`.o-EmojiPicker-content .o-Emoji[data-index="${this.state.activeEmojiIndex}"]`)?.click();break;case"Escape":this.props.close?.();this.props.onClose?.();ev.stopPropagation();}}
getAllCategories(){const res=[...this.categories];if(this.recentEmojis.length>0){res.unshift(this.recentCategory);}
return res;}
getEmojis(){let emojisToDisplay=[...this.emojis];const recentEmojis=this.recentEmojis;if(recentEmojis.length>0&&this.searchTerm){emojisToDisplay=emojisToDisplay.filter((emoji)=>!recentEmojis.includes(emoji));}
if(this.searchTerm.length>0){return fuzzyLookup(this.searchTerm,emojisToDisplay,(emoji)=>[emoji.name,...emoji.keywords,...emoji.emoticons,...emoji.shortcodes,]);}
return emojisToDisplay;}
getEmojisFromSearch(){return[...this.recentEmojis,...this.getEmojis()];}
selectCategory(categoryId){this.searchTerm="";this.state.categoryId=categoryId;this.shouldScrollElem=true;}
selectEmoji(ev){const codepoints=ev.currentTarget.dataset.codepoints;const resetOnSelect=!ev.shiftKey&&!this.ui.isSmall;this.props.onSelect(codepoints,resetOnSelect);this.state.recent[codepoints]??=0;this.state.recent[codepoints]++;browser.localStorage.setItem("web.emoji.frequent",JSON.stringify(this.state.recent));if(resetOnSelect){this.gridRef.el.scrollTop=0;this.props.close?.();this.props.onClose?.();}}
highlightActiveCategory(){if(!this.gridRef||!this.gridRef.el){return;}
const coords=this.gridRef.el.getBoundingClientRect();const res=document.elementFromPoint(coords.x+10,coords.y+10);if(!res){return;}
this.state.categoryId=parseInt(res.dataset.category);}}
function isElementVisible(el,holder){const offset=20;holder=holder||document.body;const{top,bottom,height}=el.getBoundingClientRect();let{top:holderTop,bottom:holderBottom}=holder.getBoundingClientRect();holderTop+=offset*2;holderBottom-=offset;return top-offset<=holderTop?holderTop-top<=height:bottom-holderBottom<=height;}
return __exports;});;

/* /web/static/src/core/ensure_jquery.js */
odoo.define('@web/core/ensure_jquery',['@web/core/assets'],function(require){'use strict';let __exports={};const{loadBundle,loadJS}=require("@web/core/assets");__exports.ensureJQuery=ensureJQuery;async function ensureJQuery(){if(!window.jQuery){await loadBundle("web._assets_jquery");const BTS_CLASSES=["Carousel","Dropdown","Modal","Popover","Tooltip","Collapse"];const $=window.jQuery;for(const CLS of BTS_CLASSES){const plugin=window[CLS];if(plugin){const name=plugin.NAME;const JQUERY_NO_CONFLICT=$.fn[name];$.fn[name]=plugin.jQueryInterface;$.fn[name].Constructor=plugin;$.fn[name].noConflict=()=>{$.fn[name]=JQUERY_NO_CONFLICT;return plugin.jQueryInterface;};}}}else if(!window.jQuery.fn.getScrollingElement){await loadJS("/web/static/src/legacy/js/libs/jquery.js");}}
return __exports;});;

/* /web/static/src/core/errors/error_dialogs.js */
odoo.define('@web/core/errors/error_dialogs',['@web/core/browser/browser','@web/core/dialog/dialog','@web/core/l10n/translation','@web/core/registry','@web/core/tooltip/tooltip','@web/core/popover/popover_hook','@web/core/utils/hooks','@web/core/utils/strings','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Dialog}=require("@web/core/dialog/dialog");const{_t}=require("@web/core/l10n/translation");const{registry}=require("@web/core/registry");const{Tooltip}=require("@web/core/tooltip/tooltip");const{usePopover}=require("@web/core/popover/popover_hook");const{useService}=require("@web/core/utils/hooks");const{capitalize}=require("@web/core/utils/strings");const{Component,useRef,useState,markup}=require("@odoo/owl");const{DateTime}=luxon;const standardErrorDialogProps=__exports.standardErrorDialogProps={traceback:{type:[String,{value:null}],optional:true},message:{type:String,optional:true},name:{type:String,optional:true},exceptionName:{type:[String,{value:null}],optional:true},data:{type:[Object,{value:null}],optional:true},subType:{type:[String,{value:null}],optional:true},code:{type:[Number,String,{value:null}],optional:true},type:{type:[String,{value:null}],optional:true},serverHost:{type:[String,{value:null}],optional:true},id:{type:[Number,{value:null}],optional:true},model:{type:[String,{value:null}],optional:true},close:Function,};const odooExceptionTitleMap=__exports.odooExceptionTitleMap=new Map(Object.entries({"odoo.addons.base.models.ir_mail_server.MailDeliveryException":_t("MailDeliveryException"),"odoo.exceptions.AccessDenied":_t("Access Denied"),"odoo.exceptions.MissingError":_t("Missing Record"),"odoo.addons.web.controllers.action.MissingActionError":_t("Missing Action"),"odoo.exceptions.UserError":_t("Invalid Operation"),"odoo.exceptions.ValidationError":_t("Validation Error"),"odoo.exceptions.AccessError":_t("Access Error"),"odoo.exceptions.Warning":_t("Warning"),}));const ErrorDialog=__exports.ErrorDialog=class ErrorDialog extends Component{static template="web.ErrorDialog";static components={Dialog};static title=_t("Odoo Error");static showTracebackButtonText=_t("See technical details");static hideTracebackButtonText=_t("Hide technical details");static props={...standardErrorDialogProps};setup(){this.state=useState({showTraceback:false,});this.copyButtonRef=useRef("copyButton");this.popover=usePopover(Tooltip);this.contextDetails="Occured ";if(this.props.serverHost){this.contextDetails+=`on ${this.props.serverHost} `;}
if(this.props.model){this.contextDetails+=`on model ${this.props.model} `;}
this.contextDetails+=`on ${DateTime.now()
            .setZone("UTC")
            .toFormat("yyyy-MM-dd HH:mm:ss")} GMT`;}
showTooltip(){this.popover.open(this.copyButtonRef.el,{tooltip:_t("Copied")});browser.setTimeout(this.popover.close,800);}
onClickClipboard(){browser.navigator.clipboard.writeText(`${this.props.name}\n\n${this.props.message}\n\n${this.contextDetails}\n\n${this.props.traceback}`);this.showTooltip();}}
const ClientErrorDialog=__exports.ClientErrorDialog=class ClientErrorDialog extends ErrorDialog{}
ClientErrorDialog.title=_t("Odoo Client Error");const NetworkErrorDialog=__exports.NetworkErrorDialog=class NetworkErrorDialog extends ErrorDialog{}
NetworkErrorDialog.title=_t("Odoo Network Error");const RPCErrorDialog=__exports.RPCErrorDialog=class RPCErrorDialog extends ErrorDialog{setup(){super.setup();this.inferTitle();this.traceback=this.props.traceback;if(this.props.data&&this.props.data.debug){this.traceback=`${this.props.data.debug}\nThe above server error caused the following client error:\n${this.traceback}`;}}
inferTitle(){if(this.props.exceptionName&&odooExceptionTitleMap.has(this.props.exceptionName)){this.title=odooExceptionTitleMap.get(this.props.exceptionName).toString();return;}
if(!this.props.type){return;}
switch(this.props.type){case"server":this.title=_t("Odoo Server Error");break;case"script":this.title=_t("Odoo Client Error");break;case"network":this.title=_t("Odoo Network Error");break;}}
onClickClipboard(){browser.navigator.clipboard.writeText(`${this.props.name}\n\n${this.props.message}\n\n${this.contextDetails}\n\n${this.traceback}`);this.showTooltip();}}
const WarningDialog=__exports.WarningDialog=class WarningDialog extends Component{static template="web.WarningDialog";static components={Dialog};static props={...standardErrorDialogProps,title:{type:String,optional:true},};setup(){this.title=this.inferTitle();const{data,message}=this.props;if(data&&data.arguments&&data.arguments.length>0){this.message=data.arguments[0];}else{this.message=message;}}
inferTitle(){if(this.props.exceptionName&&odooExceptionTitleMap.has(this.props.exceptionName)){return odooExceptionTitleMap.get(this.props.exceptionName).toString();}
return this.props.title||_t("Odoo Warning");}}
const RedirectWarningDialog=__exports.RedirectWarningDialog=class RedirectWarningDialog extends Component{static template="web.RedirectWarningDialog";static components={Dialog};static props={...standardErrorDialogProps};setup(){this.actionService=useService("action");const{data,subType}=this.props;const[message,actionId,buttonText,additionalContext]=data.arguments;this.title=capitalize(subType)||_t("Odoo Warning");this.message=message;this.actionId=actionId;this.buttonText=buttonText;this.additionalContext=additionalContext;}
async onClick(){const options={};if(this.additionalContext){options.additionalContext=this.additionalContext;}
if(this.actionId.help){this.actionId.help=markup(this.actionId.help);}
await this.actionService.doAction(this.actionId,options);this.props.close();}}
const Error504Dialog=__exports.Error504Dialog=class Error504Dialog extends Component{static template="web.Error504Dialog";static components={Dialog};static props={...standardErrorDialogProps};}
const SessionExpiredDialog=__exports.SessionExpiredDialog=class SessionExpiredDialog extends Component{static template="web.SessionExpiredDialog";static components={Dialog};static props={...standardErrorDialogProps};onClick(){browser.location.reload();}}
registry.category("error_dialogs").add("odoo.exceptions.AccessDenied",WarningDialog).add("odoo.exceptions.AccessError",WarningDialog).add("odoo.exceptions.MissingError",WarningDialog).add("odoo.addons.web.controllers.action.MissingActionError",WarningDialog).add("odoo.exceptions.UserError",WarningDialog).add("odoo.exceptions.ValidationError",WarningDialog).add("odoo.exceptions.RedirectWarning",RedirectWarningDialog).add("odoo.http.SessionExpiredException",SessionExpiredDialog).add("werkzeug.exceptions.Forbidden",SessionExpiredDialog).add("504",Error504Dialog);return __exports;});;

/* /web/static/src/core/errors/error_handlers.js */
odoo.define('@web/core/errors/error_handlers',['@web/core/l10n/translation','@web/core/browser/browser','@web/core/network/rpc','@web/core/registry','@web/session','@web/core/user','@web/core/errors/error_dialogs','@web/core/errors/error_service'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{browser}=require("@web/core/browser/browser");const{ConnectionLostError,RPCError,rpc}=require("@web/core/network/rpc");const{registry}=require("@web/core/registry");const{session}=require("@web/session");const{user}=require("@web/core/user");const{ClientErrorDialog,ErrorDialog,NetworkErrorDialog,RPCErrorDialog,}=require("@web/core/errors/error_dialogs");const{UncaughtClientError,ThirdPartyScriptError,UncaughtPromiseError}=require("@web/core/errors/error_service");const errorHandlerRegistry=registry.category("error_handlers");const errorDialogRegistry=registry.category("error_dialogs");const errorNotificationRegistry=registry.category("error_notifications");__exports.rpcErrorHandler=rpcErrorHandler;function rpcErrorHandler(env,error,originalError){if(!(error instanceof UncaughtPromiseError)){return false;}
if(originalError instanceof RPCError){error.unhandledRejectionEvent.preventDefault();const exceptionName=originalError.exceptionName;let ErrorComponent=originalError.Component;if(!ErrorComponent&&exceptionName){if(errorNotificationRegistry.contains(exceptionName)){const notif=errorNotificationRegistry.get(exceptionName);env.services.notification.add(notif.message||originalError.data.message,notif);return true;}
if(errorDialogRegistry.contains(exceptionName)){ErrorComponent=errorDialogRegistry.get(exceptionName);}}
if(!ErrorComponent&&originalError.data.context){const exceptionClass=originalError.data.context.exception_class;if(errorDialogRegistry.contains(exceptionClass)){ErrorComponent=errorDialogRegistry.get(exceptionClass);}}
env.services.dialog.add(ErrorComponent||RPCErrorDialog,{traceback:error.traceback,message:originalError.message,name:originalError.name,exceptionName:originalError.exceptionName,data:originalError.data,subType:originalError.subType,code:originalError.code,type:originalError.type,serverHost:error.event?.target?.location.host,id:originalError.id,model:originalError.model,});return true;}}
errorHandlerRegistry.add("rpcErrorHandler",rpcErrorHandler,{sequence:97});let connectionLostNotifRemove=null;__exports.lostConnectionHandler=lostConnectionHandler;function lostConnectionHandler(env,error,originalError){if(!(error instanceof UncaughtPromiseError)){return false;}
if(originalError instanceof ConnectionLostError){if(connectionLostNotifRemove){return true;}
connectionLostNotifRemove=env.services.notification.add(_t("Connection lost. Trying to reconnect..."),{sticky:true});let delay=2000;browser.setTimeout(function checkConnection(){rpc("/web/webclient/version_info",{}).then(function(){if(connectionLostNotifRemove){connectionLostNotifRemove();connectionLostNotifRemove=null;}
env.services.notification.add(_t("Connection restored. You are back online."),{type:"info",});}).catch(()=>{delay=delay*1.5+500*Math.random();browser.setTimeout(checkConnection,delay);});},delay);return true;}}
errorHandlerRegistry.add("lostConnectionHandler",lostConnectionHandler,{sequence:98});const defaultDialogs=new Map([[UncaughtClientError,ClientErrorDialog],[UncaughtPromiseError,ClientErrorDialog],[ThirdPartyScriptError,NetworkErrorDialog],]);__exports.defaultHandler=defaultHandler;function defaultHandler(env,error){const DialogComponent=defaultDialogs.get(error.constructor)||ErrorDialog;env.services.dialog.add(DialogComponent,{traceback:error.traceback,message:error.message,name:error.name,serverHost:error.event?.target?.location.host,});return true;}
errorHandlerRegistry.add("defaultHandler",defaultHandler,{sequence:100});__exports.swallowAllVisitorErrors=swallowAllVisitorErrors;function swallowAllVisitorErrors(env,error,originalError){if(!user.isInternalUser&&!odoo.debug&&!session.test_mode){return true;}}
if(user.isInternalUser===undefined){if(session.is_frontend){console.warn("isInternalUser information is required for this handler to work. It must be available in the page.");}}else{registry.category("error_handlers").add("swallowAllVisitorErrors",swallowAllVisitorErrors,{sequence:0});}
return __exports;});;

/* /web/static/src/core/errors/error_service.js */
odoo.define('@web/core/errors/error_service',['@web/core/browser/browser','@web/core/registry','@web/core/errors/error_utils','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{completeUncaughtError,getErrorTechnicalName}=require("@web/core/errors/error_utils");const{isBrowserFirefox,isBrowserChrome}=require("@web/core/browser/feature_detection");const HTMLElementLoadingError=__exports.HTMLElementLoadingError=class HTMLElementLoadingError extends Error{static message="Error loading an HTML Element";constructor(message=HTMLElementLoadingError.message,event){super(message);this.event=event;}}
const UncaughtError=__exports.UncaughtError=class UncaughtError extends Error{constructor(message){super(message);this.name=getErrorTechnicalName(this);this.traceback=null;}}
const UncaughtClientError=__exports.UncaughtClientError=class UncaughtClientError extends UncaughtError{constructor(message="Uncaught Javascript Error"){super(message);}}
const UncaughtPromiseError=__exports.UncaughtPromiseError=class UncaughtPromiseError extends UncaughtError{constructor(message="Uncaught Promise"){super(message);this.unhandledRejectionEvent=null;}}
const ThirdPartyScriptError=__exports.ThirdPartyScriptError=class ThirdPartyScriptError extends UncaughtError{constructor(message="Third-Party Script Error"){super(message);}}
const errorService=__exports.errorService={start(env){function handleError(uncaughtError,retry=true){function shouldLogError(){return(uncaughtError.event&&!uncaughtError.event.defaultPrevented&&uncaughtError.traceback);}
let originalError=uncaughtError;while(originalError instanceof Error&&"cause"in originalError){originalError=originalError.cause;}
for(const[name,handler]of registry.category("error_handlers").getEntries()){try{if(handler(env,uncaughtError,originalError)){break;}}catch(e){if(shouldLogError()){uncaughtError.event.preventDefault();console.error(`@web/core/error_service: handler "${name}" failed with "${
                                e.cause || e
                            }" while trying to handle:\n`+uncaughtError.traceback);}
return;}}
if(shouldLogError()){uncaughtError.event.preventDefault();console.error(uncaughtError.traceback);}}
browser.addEventListener("error",async(ev)=>{const{colno,error,filename,lineno,message}=ev;const errorsToIgnore=["ResizeObserver loop completed with undelivered notifications.","ResizeObserver loop limit exceeded",];if(!(error instanceof Error)&&errorsToIgnore.includes(message)){ev.preventDefault();return;}
const isRedactedError=!filename&&!lineno&&!colno;const isThirdPartyScriptError=isRedactedError||(isBrowserFirefox()&&new URL(filename).origin!==window.location.origin);if(isThirdPartyScriptError&&!odoo.debug){return;}
let uncaughtError;if(isRedactedError){uncaughtError=new ThirdPartyScriptError();uncaughtError.traceback=`An error whose details cannot be accessed by the Odoo framework has occurred.\n`+`The error probably originates from a JavaScript file served from a different origin.\n`+`The full error is available in the browser console.`;}else{uncaughtError=new UncaughtClientError();uncaughtError.event=ev;if(error instanceof Error){error.errorEvent=ev;const annotated=env.debug&&env.debug.includes("assets");await completeUncaughtError(uncaughtError,error,annotated);}}
uncaughtError.cause=error;handleError(uncaughtError);});browser.addEventListener("unhandledrejection",async(ev)=>{let error=ev.reason;if(error&&error.type==="error"&&"eventPhase"in error){if(!error.bubbles){ev.preventDefault();return;}
let message;if(error.target){message=`${HTMLElementLoadingError.message}: ${error.target.nodeName}`;}
error=new HTMLElementLoadingError(message,error);}
let traceback;if(isBrowserChrome()&&ev instanceof CustomEvent&&error===undefined){if(!odoo.debug){return;}
traceback=`Uncaught unknown Error\n`+`An unknown error occured. This may be due to a Chrome extension meddling with Odoo.\n`+`(Opening your browser console might give you a hint on the error.)`;}
const uncaughtError=new UncaughtPromiseError();uncaughtError.unhandledRejectionEvent=ev;uncaughtError.event=ev;uncaughtError.traceback=traceback;if(error instanceof Error){error.errorEvent=ev;const annotated=env.debug&&env.debug.includes("assets");await completeUncaughtError(uncaughtError,error,annotated);}
uncaughtError.cause=error;handleError(uncaughtError);});},};registry.category("services").add("error",errorService,{sequence:1});return __exports;});;

/* /web/static/src/core/errors/error_utils.js */
odoo.define('@web/core/errors/error_utils',['@web/core/assets'],function(require){'use strict';let __exports={};const{loadJS}=require("@web/core/assets");function combineErrorNames(uncaughtError,originalError){const originalErrorName=getErrorTechnicalName(originalError);const uncaughtErrorName=getErrorTechnicalName(uncaughtError);if(originalErrorName===Error.name){return uncaughtErrorName;}else{return`${uncaughtErrorName} > ${originalErrorName}`;}}
__exports.fullTraceback=fullTraceback;function fullTraceback(error){let traceback=formatTraceback(error);let current=error.cause;while(current){traceback+=`\n\nCaused by: ${
            current instanceof Error ? formatTraceback(current) : current
        }`;current=current.cause;}
return traceback;}
__exports.fullAnnotatedTraceback=fullAnnotatedTraceback;async function fullAnnotatedTraceback(error){if(error.annotatedTraceback){return error.annotatedTraceback;}
if(error.errorEvent){error.errorEvent.preventDefault();}
let traceback;try{traceback=await annotateTraceback(error);let current=error.cause;while(current){traceback+=`\n\nCaused by: ${
                current instanceof Error ? await annotateTraceback(current) : current
            }`;current=current.cause;}}catch(e){console.warn("Failed to annotate traceback for error:",error,"failure reason:",e);traceback=fullTraceback(error);}
error.annotatedTraceback=traceback;if(error.errorEvent){throw error;}
return traceback;}
__exports.completeUncaughtError=completeUncaughtError;async function completeUncaughtError(uncaughtError,originalError,annotated=false){uncaughtError.name=combineErrorNames(uncaughtError,originalError);if(annotated){uncaughtError.traceback=await fullAnnotatedTraceback(originalError);}else{uncaughtError.traceback=fullTraceback(originalError);}
if(originalError.message){uncaughtError.message=`${uncaughtError.message} > ${originalError.message}`;}
uncaughtError.cause=originalError;}
__exports.getErrorTechnicalName=getErrorTechnicalName;function getErrorTechnicalName(error){return error.name!==Error.name?error.name:error.constructor.name;}
__exports.formatTraceback=formatTraceback;function formatTraceback(error){let traceback=error.stack;const errorName=getErrorTechnicalName(error);const descriptionLine=`${errorName}: ${error.message}`;if(error.stack.split("\n")[0].trim()!==descriptionLine){traceback=`${descriptionLine}\n${error.stack}`.replace(/\n/g,"\n    ");}
return traceback;}
__exports.annotateTraceback=annotateTraceback;async function annotateTraceback(error){const traceback=formatTraceback(error);try{await loadJS("/web/static/lib/stacktracejs/stacktrace.js");}catch{return traceback;}
if(error.stack){const regex=/ line (\d*) > (Function):(\d*)/gm;const subst=`:$1`;error.stack=error.stack.replace(regex,subst);}
let frames;try{frames=await StackTrace.fromError(error);}catch(e){console.warn("The following error could not be annotated:",error,e);return traceback;}
const lines=traceback.split("\n");if(lines[lines.length-1].trim()===""){lines.splice(-1);}
let lineIndex=0;let frameIndex=0;while(frameIndex<frames.length){const line=lines[lineIndex];if(!line.match(/:\d+:\d+\)?$/)){lineIndex++;continue;}
const frame=frames[frameIndex];const info=` (${frame.fileName}:${frame.lineNumber})`;lines[lineIndex]=line+info;lineIndex++;frameIndex++;}
return lines.join("\n");}
return __exports;});;

/* /web/static/src/core/errors/scss_error_dialog.js */
odoo.define('@web/core/errors/scss_error_dialog',['@web/core/browser/browser','@web/core/registry','@web/core/l10n/translation','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{_t,translationIsReady}=require("@web/core/l10n/translation");const{getOrigin}=require("@web/core/utils/urls");const scssErrorNotificationService={dependencies:["notification"],start(env,{notification}){const origin=getOrigin();const assets=[...document.styleSheets].filter((sheet)=>{return(sheet.href?.includes("/web")&&sheet.href?.includes("/assets/")&&new URL(sheet.href,browser.location.origin).origin===origin);});translationIsReady.then(()=>{for(const asset of assets){let cssRules;try{cssRules=asset.cssRules;}catch{continue;}
const lastRule=cssRules?.[cssRules?.length-1];if(lastRule?.selectorText==="css_error_message"){const message=_t("The style compilation failed. This is an administrator or developer error that must be fixed for the entire database before continuing working. See browser console or server logs for details.");notification.add(message,{title:_t("Style error"),sticky:true,type:"danger",});console.log(lastRule.style.content.replaceAll("\\a","\n").replaceAll("\\*","*").replaceAll(`\\"`,`"`));}}});},};registry.category("services").add("scss_error_display",scssErrorNotificationService);return __exports;});;

/* /web/static/src/core/expression_editor/expression_editor.js */
odoo.define('@web/core/expression_editor/expression_editor',['@odoo/owl','@web/core/expression_editor/expression_editor_operator_editor','@web/core/tree_editor/condition_tree','@web/core/tree_editor/tree_editor','@web/core/tree_editor/tree_editor_operator_editor','@web/core/tree_editor/tree_editor_value_editors','@web/core/tree_editor/utils','@web/core/model_field_selector/model_field_selector','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{getExpressionDisplayedOperators}=require("@web/core/expression_editor/expression_editor_operator_editor");const{condition,expressionFromTree,treeFromExpression,}=require("@web/core/tree_editor/condition_tree");const{TreeEditor}=require("@web/core/tree_editor/tree_editor");const{getOperatorEditorInfo}=require("@web/core/tree_editor/tree_editor_operator_editor");const{getDefaultValue}=require("@web/core/tree_editor/tree_editor_value_editors");const{getDefaultPath}=require("@web/core/tree_editor/utils");const{ModelFieldSelector}=require("@web/core/model_field_selector/model_field_selector");const{_t}=require("@web/core/l10n/translation");const ExpressionEditor=__exports.ExpressionEditor=class ExpressionEditor extends Component{static template="web.ExpressionEditor";static components={TreeEditor};static props={resModel:String,fields:Object,expression:String,update:Function,};setup(){onWillStart(()=>this.onPropsUpdated(this.props));onWillUpdateProps((nextProps)=>this.onPropsUpdated(nextProps));}
async onPropsUpdated(props){this.filteredFields=Object.fromEntries(Object.entries(props.fields).filter(([_,fieldDef])=>fieldDef.type!=="properties"));try{this.tree=treeFromExpression(props.expression,{getFieldDef:(name)=>this.getFieldDef(name,props),distributeNot:!this.isDebugMode,});}catch{this.tree=null;}}
getFieldDef(name,props=this.props){if(typeof name==="string"){return props.fields[name]||null;}
return null;}
getDefaultCondition(){const defaultPath=getDefaultPath(this.filteredFields);const fieldDef=this.filteredFields[defaultPath];const operator=getExpressionDisplayedOperators(fieldDef)[0];const value=getDefaultValue(fieldDef,operator);return condition(fieldDef.name,operator,value);}
getDefaultOperator(fieldDef){return getExpressionDisplayedOperators(fieldDef)[0];}
getOperatorEditorInfo(fieldDef){const operators=getExpressionDisplayedOperators(fieldDef);return getOperatorEditorInfo(operators,fieldDef);}
getPathEditorInfo(resModel,defaultCondition){if(resModel!==this.props.resModel){throw new Error(`Expression editor doesn't support tree as value so resModel has to be props.resModel`);}
return{component:ModelFieldSelector,extractProps:({value,update})=>({path:value,update,resModel:this.props.resModel,readonly:false,filter:(fieldDef)=>fieldDef.name in this.filteredFields,showDebugInput:false,followRelations:false,isDebugMode:this.isDebugMode,}),isSupported:(value)=>[0,1].includes(value)||value in this.filteredFields,stringify:(value)=>this.props.fields[value].string,defaultValue:()=>defaultCondition.path,message:_t("Field properties not supported"),};}
get isDebugMode(){return!!this.env.debug;}
onExpressionChange(expression){this.props.update(expression);}
resetExpression(){this.props.update("True");}
update(tree){const expression=expressionFromTree(tree,{getFieldDef:(name)=>this.getFieldDef(name),});this.props.update(expression);}}
return __exports;});;

/* /web/static/src/core/expression_editor/expression_editor_operator_editor.js */
odoo.define('@web/core/expression_editor/expression_editor_operator_editor',['@web/core/domain_selector/domain_selector_operator_editor'],function(require){'use strict';let __exports={};const{getDomainDisplayedOperators}=require("@web/core/domain_selector/domain_selector_operator_editor");const EXPRESSION_VALID_OPERATORS=["<","<=",">",">=","between","within","in","not in","=","!=","set","not_set","is","is_not",];__exports.getExpressionDisplayedOperators=getExpressionDisplayedOperators;function getExpressionDisplayedOperators(fieldDef){const operators=getDomainDisplayedOperators(fieldDef);return operators.filter((operator)=>EXPRESSION_VALID_OPERATORS.includes(operator));}
return __exports;});;

/* /web/static/src/core/expression_editor_dialog/expression_editor_dialog.js */
odoo.define('@web/core/expression_editor_dialog/expression_editor_dialog',['@odoo/owl','@web/core/dialog/dialog','@web/core/expression_editor/expression_editor','@web/core/py_js/py','@web/core/utils/hooks','@web/core/l10n/translation','@web/core/user'],function(require){'use strict';let __exports={};const{Component,useRef,useState}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{ExpressionEditor}=require("@web/core/expression_editor/expression_editor");const{evaluateExpr}=require("@web/core/py_js/py");const{useService}=require("@web/core/utils/hooks");const{_t}=require("@web/core/l10n/translation");const{user}=require("@web/core/user");const ExpressionEditorDialog=__exports.ExpressionEditorDialog=class ExpressionEditorDialog extends Component{static components={Dialog,ExpressionEditor};static template="web.ExpressionEditorDialog";static props={close:Function,resModel:String,fields:Object,expression:String,onConfirm:Function,};setup(){this.notification=useService("notification");this.state=useState({expression:this.props.expression,});this.confirmButtonRef=useRef("confirm");}
get expressionEditorProps(){return{resModel:this.props.resModel,fields:this.props.fields,expression:this.state.expression,update:(expression)=>{this.state.expression=expression;},};}
makeDefaultRecord(){const record={};for(const[name,{type}]of Object.entries(this.props.fields)){switch(type){case"integer":case"float":case"monetary":record[name]=name==="id"?false:0;break;case"one2many":case"many2many":record[name]=[];break;default:record[name]=false;}}
return record;}
async onConfirm(){this.confirmButtonRef.el.disabled=true;const record=this.makeDefaultRecord();const evalContext={...user.context,...record};try{evaluateExpr(this.state.expression,evalContext);}catch{if(this.confirmButtonRef.el){this.confirmButtonRef.el.disabled=false;}
this.notification.add(_t("Expression is invalid. Please correct it"),{type:"danger",});return;}
this.props.onConfirm(this.state.expression);this.props.close();}
onDiscard(){this.props.close();}}
return __exports;});;

/* /web/static/src/core/field_service.js */
odoo.define('@web/core/field_service',['@web/core/utils/cache','@web/core/domain','@web/core/registry'],function(require){'use strict';let __exports={};const{Cache}=require("@web/core/utils/cache");const{Domain}=require("@web/core/domain");const{registry}=require("@web/core/registry");const fieldService=__exports.fieldService={dependencies:["orm"],async:["loadFields","loadPath","loadPropertyDefinitions"],start(env,{orm}){const cache=new Cache((resModel,options)=>{return orm.call(resModel,"fields_get",[options.fieldNames,options.attributes]).catch((error)=>{cache.clear(resModel,options);return Promise.reject(error);});},(resModel,options)=>JSON.stringify([resModel,options.fieldNames,options.attributes]));env.bus.addEventListener("CLEAR-CACHES",()=>cache.invalidate());async function loadFields(resModel,options={}){if(typeof resModel!=="string"||!resModel){throw new Error(`Invalid model name: ${resModel}`);}
return cache.read(resModel,options);}
async function _loadPropertyDefinitions(fieldDefs,name,domain=[]){const{definition_record:definitionRecord,definition_record_field:definitionRecordField,}=fieldDefs[name];const definitionRecordModel=fieldDefs[definitionRecord].relation;domain=Domain.and([[[definitionRecordField,"!=",false]],domain]).toList();const result=await orm.webSearchRead(definitionRecordModel,domain,{specification:{display_name:{},[definitionRecordField]:{},},});const definitions={};for(const record of result.records){for(const definition of record[definitionRecordField]){definitions[definition.name]={is_property:true,searchable:true,record_id:record.id,record_name:record.display_name,...definition,};}}
return definitions;}
async function loadPropertyDefinitions(resModel,fieldName,domain){const fieldDefs=await loadFields(resModel);return _loadPropertyDefinitions(fieldDefs,fieldName,domain);}
async function _loadPath(resModel,fieldDefs,names){if(!fieldDefs){return{isInvalid:"path",names,modelsInfo:[]};}
const[name,...remainingNames]=names;const modelsInfo=[{resModel,fieldDefs}];if(resModel==="*"&&remainingNames.length){return{isInvalid:"path",names,modelsInfo};}
const fieldDef=fieldDefs[name];if((name!=="*"&&!fieldDef)||(name==="*"&&remainingNames.length)){return{isInvalid:"path",names,modelsInfo};}
if(!remainingNames.length){return{names,modelsInfo};}
let subResult;if(fieldDef.relation){subResult=await _loadPath(fieldDef.relation,await loadFields(fieldDef.relation),remainingNames);}else if(fieldDef.type==="properties"){subResult=await _loadPath("*",await _loadPropertyDefinitions(fieldDefs,name),remainingNames);}
if(subResult){const result={names,modelsInfo:[...modelsInfo,...subResult.modelsInfo],};if(subResult.isInvalid){result.isInvalid="path";}
return result;}
return{isInvalid:"path",names,modelsInfo};}
async function loadPath(resModel,path="*"){const fieldDefs=await loadFields(resModel);if(typeof path!=="string"||!path){throw new Error(`Invalid path: ${path}`);}
return _loadPath(resModel,fieldDefs,path.split("."));}
return{loadFields,loadPath,loadPropertyDefinitions};},};registry.category("services").add("field",fieldService);return __exports;});;

/* /web/static/src/core/file_input/file_input.js */
odoo.define('@web/core/file_input/file_input',['@odoo/owl','@web/core/utils/files'],function(require){'use strict';let __exports={};const{Component,onMounted,useRef,useState}=require("@odoo/owl");const{useFileUploader}=require("@web/core/utils/files");const FileInput=__exports.FileInput=class FileInput extends Component{static template="web.FileInput";static defaultProps={acceptedFileExtensions:"*",hidden:false,multiUpload:false,onUpload:()=>{},route:"/web/binary/upload_attachment",beforeOpen:async()=>true,};static props={acceptedFileExtensions:{type:String,optional:true},autoOpen:{type:Boolean,optional:true},hidden:{type:Boolean,optional:true},multiUpload:{type:Boolean,optional:true},onUpload:{type:Function,optional:true},beforeOpen:{type:Function,optional:true},resId:{type:Number,optional:true},resModel:{type:String,optional:true},route:{type:String,optional:true},"*":true,};setup(){this.uploadFiles=useFileUploader();this.fileInputRef=useRef("file-input");this.state=useState({isDisable:false,});onMounted(()=>{if(this.props.autoOpen){this.onTriggerClicked();}});}
get httpParams(){const{resId,resModel}=this.props;const params={csrf_token:odoo.csrf_token,ufile:[...this.fileInputRef.el.files],};if(resModel){params.model=resModel;}
if(resId!==undefined){params.id=resId;}
return params;}
async onFileInputChange(){this.state.isDisable=true;const httpParams=this.httpParams;if(this.props.onWillUploadFiles){try{const files=await this.props.onWillUploadFiles(httpParams.ufile);httpParams.ufile=files;}catch(e){this.state.isDisable=false;throw e;}}
const parsedFileData=await this.uploadFiles(this.props.route,httpParams);if(parsedFileData){this.props.onUpload(parsedFileData,this.fileInputRef.el?this.fileInputRef.el.files:[]);this.fileInputRef.el.value=null;}
this.state.isDisable=false;}
async onTriggerClicked(){if(await this.props.beforeOpen()){this.fileInputRef.el.click();}}}
return __exports;});;

/* /web/static/src/core/file_upload/file_upload_progress_bar.js */
odoo.define('@web/core/file_upload/file_upload_progress_bar',['@web/core/l10n/translation','@web/core/utils/hooks','@web/core/confirmation_dialog/confirmation_dialog','@odoo/owl'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{useService}=require("@web/core/utils/hooks");const{ConfirmationDialog}=require("@web/core/confirmation_dialog/confirmation_dialog");const{Component}=require("@odoo/owl");const FileUploadProgressBar=__exports.FileUploadProgressBar=class FileUploadProgressBar extends Component{static template="web.FileUploadProgressBar";static props={fileUpload:{type:Object},};setup(){this.dialogService=useService("dialog");}
onCancel(){if(!this.props.fileUpload.xhr){return;}
this.dialogService.add(ConfirmationDialog,{body:_t("Do you really want to cancel the upload of %s?",this.props.fileUpload.title),confirm:()=>{this.props.fileUpload.xhr.abort();},});}}
return __exports;});;

/* /web/static/src/core/file_upload/file_upload_progress_container.js */
odoo.define('@web/core/file_upload/file_upload_progress_container',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const FileUploadProgressContainer=__exports.FileUploadProgressContainer=class FileUploadProgressContainer extends Component{static template="web.FileUploadProgressContainer";static props={Component:{optional:false},shouldDisplay:{type:Function,optional:true},fileUploads:{type:Object},};}
return __exports;});;

/* /web/static/src/core/file_upload/file_upload_progress_record.js */
odoo.define('@web/core/file_upload/file_upload_progress_record',['@web/core/l10n/translation','@web/core/file_upload/file_upload_progress_bar','@odoo/owl'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{FileUploadProgressBar}=require("@web/core/file_upload/file_upload_progress_bar");const{Component}=require("@odoo/owl");const FileUploadProgressRecord=__exports.FileUploadProgressRecord=class FileUploadProgressRecord extends Component{static template="";static components={FileUploadProgressBar,};static props={fileUpload:Object,selector:{type:String,optional:true},};getProgressTexts(){const fileUpload=this.props.fileUpload;const percent=Math.round(fileUpload.progress*100);if(percent===100){return{left:_t("Processing..."),right:"",};}else{const mbLoaded=Math.round(fileUpload.loaded/1000000);const mbTotal=Math.round(fileUpload.total/1000000);return{left:_t("Uploading... (%s%)",percent),right:_t("(%(mbLoaded)s/%(mbTotal)sMB)",{mbLoaded,mbTotal}),};}}}
const FileUploadProgressKanbanRecord=__exports.FileUploadProgressKanbanRecord=class FileUploadProgressKanbanRecord extends FileUploadProgressRecord{static template="web.FileUploadProgressKanbanRecord";}
const FileUploadProgressDataRow=__exports.FileUploadProgressDataRow=class FileUploadProgressDataRow extends FileUploadProgressRecord{static template="web.FileUploadProgressDataRow";}
return __exports;});;

/* /web/static/src/core/file_upload/file_upload_service.js */
odoo.define('@web/core/file_upload/file_upload_service',['@web/core/l10n/translation','@web/core/registry','@odoo/owl'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{registry}=require("@web/core/registry");const{EventBus,reactive}=require("@odoo/owl");const fileUploadService=__exports.fileUploadService={dependencies:["notification"],createXhr(){return new window.XMLHttpRequest();},start(env,{notification:notificationService}){const uploads=reactive({});let nextId=1;const bus=new EventBus();const upload=async(route,files,params={})=>{const xhr=this.createXhr();xhr.open("POST",route);const formData=new FormData();formData.append("csrf_token",odoo.csrf_token);for(const file of files){formData.append("ufile",file);}
if(params.buildFormData){params.buildFormData(formData);}
const upload=reactive({id:nextId++,xhr,data:formData,progress:0,loaded:0,total:0,state:"pending",title:files.length===1?files[0].name:_t("%s Files",files.length),type:files.length===1?files[0].type:undefined,});uploads[upload.id]=upload;xhr.upload.addEventListener("progress",async(ev)=>{upload.progress=ev.loaded/ev.total;upload.loaded=ev.loaded;upload.total=ev.total;upload.state="loading";});xhr.addEventListener("load",()=>{try{handleResponse();}catch(e){onError(e);return;}
delete uploads[upload.id];upload.state="loaded";bus.trigger("FILE_UPLOAD_LOADED",{upload});});function handleResponse(){const resp=xhr.responseText??xhr.response;let error;let errorMessage="";if(!(xhr.status>=200&&xhr.status<300)){error=true;}
if(resp){let content=resp;if(typeof content==="string"){try{content=JSON.parse(content);}catch{try{content=new DOMParser().parseFromString(content,"text/html");}catch{}}}
if(error&&content instanceof Document){errorMessage=content.body.textContent;}else if(content instanceof Object){if(content.error){error=true;if(content.error.data){errorMessage=`${content.error.data.name}: ${content.error.data.message}`;}else{errorMessage=content.error.message||errorMessage;}}}}
if(error){throw new Error(errorMessage);}
return true;}
function onError(error){const defaultErrorMessage=_t("An error occured while uploading.");delete uploads[upload.id];upload.state="error";const displayError=params.displayErrorNotification??true;if(displayError){notificationService.add(error?.message||defaultErrorMessage,{title:_t("Error"),sticky:true,});}
bus.trigger("FILE_UPLOAD_ERROR",{upload});}
xhr.addEventListener("error",(ev)=>onError(ev.error));xhr.addEventListener("abort",async()=>{delete uploads[upload.id];upload.state="abort";bus.trigger("FILE_UPLOAD_ERROR",{upload});});xhr.send(formData);bus.trigger("FILE_UPLOAD_ADDED",{upload});return upload;};return{bus,upload,uploads};},};registry.category("services").add("file_upload",fileUploadService);return __exports;});;

/* /web/static/src/core/file_viewer/file_model.js */
odoo.define('@web/core/file_viewer/file_model',['@web/core/utils/urls'],function(require){'use strict';let __exports={};const{url}=require("@web/core/utils/urls");const FileModelMixin=__exports.FileModelMixin=(T)=>class extends T{access_token;checksum;extension;filename;id;mimetype;name;type;tmpUrl;url;uploading;get defaultSource(){const route=url(this.urlRoute,this.urlQueryParams);const encodedRoute=encodeURIComponent(route);if(this.isPdf){return`/web/static/lib/pdfjs/web/viewer.html?file=${encodedRoute}#pagemode=none`;}
if(this.isUrlYoutube){const urlArr=this.url.split("/");let token=urlArr[urlArr.length-1];if(token.includes("watch")){token=token.split("v=")[1];const amp=token.indexOf("&");if(amp!==-1){token=token.substring(0,amp);}}
return`https://www.youtube.com/embed/${token}`;}
return route;}
get displayName(){return this.name||this.filename;}
get downloadUrl(){return url(this.urlRoute,{...this.urlQueryParams,download:true});}
get isImage(){const imageMimetypes=["image/bmp","image/gif","image/jpeg","image/png","image/svg+xml","image/tiff","image/x-icon","image/webp",];return imageMimetypes.includes(this.mimetype);}
get isPdf(){return this.mimetype&&this.mimetype.startsWith("application/pdf");}
get isText(){const textMimeType=["application/javascript","application/json","text/css","text/html","text/plain",];return textMimeType.includes(this.mimetype);}
get isUrl(){return this.type==="url"&&this.url;}
get isUrlYoutube(){return!!this.url&&this.url.includes("youtu");}
get isVideo(){const videoMimeTypes=["audio/mpeg","video/x-matroska","video/mp4","video/webm"];return videoMimeTypes.includes(this.mimetype);}
get isViewable(){return((this.isText||this.isImage||this.isVideo||this.isPdf||this.isUrlYoutube)&&!this.uploading);}
get urlQueryParams(){if(this.uploading&&this.tmpUrl){return{};}
const params={access_token:this.access_token,filename:this.name,unique:this.checksum,};for(const prop in params){if(!params[prop]){delete params[prop];}}
return params;}
get urlRoute(){if(this.uploading&&this.tmpUrl){return this.tmpUrl;}
return this.isImage?`/web/image/${this.id}`:`/web/content/${this.id}`;}};const FileModel=__exports.FileModel=class FileModel extends FileModelMixin(Object){}
return __exports;});;

/* /web/static/src/core/file_viewer/file_viewer.js */
odoo.define('@web/core/file_viewer/file_viewer',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,useRef,useState}=require("@odoo/owl");const{useAutofocus,useService}=require("@web/core/utils/hooks");const FileViewer=__exports.FileViewer=class FileViewer extends Component{static template="web.FileViewer";static components={};static props=["files","startIndex","close?","modal?"];static defaultProps={modal:true,};setup(){useAutofocus();this.imageRef=useRef("image");this.zoomerRef=useRef("zoomer");this.isDragging=false;this.dragStartX=0;this.dragStartY=0;this.scrollZoomStep=0.1;this.zoomStep=0.5;this.minScale=0.5;this.translate={dx:0,dy:0,x:0,y:0,};this.state=useState({index:this.props.startIndex,file:this.props.files[this.props.startIndex],imageLoaded:false,scale:1,angle:0,});this.ui=useState(useService("ui"));}
onImageLoaded(){this.state.imageLoaded=true;}
close(){this.props.close&&this.props.close();}
next(){const last=this.props.files.length-1;this.activateFile(this.state.index===last?0:this.state.index+1);}
previous(){const last=this.props.files.length-1;this.activateFile(this.state.index===0?last:this.state.index-1);}
activateFile(index){this.state.index=index;this.state.file=this.props.files[index];}
onKeydown(ev){switch(ev.key){case"ArrowRight":this.next();break;case"ArrowLeft":this.previous();break;case"Escape":this.close();break;case"q":this.close();break;}
if(this.state.file.isImage){switch(ev.key){case"r":this.rotate();break;case"+":this.zoomIn();break;case"-":this.zoomOut();break;case"0":this.resetZoom();break;}}}
onWheelImage(ev){if(ev.deltaY>0){this.zoomOut({scroll:true});}else{this.zoomIn({scroll:true});}}
onMousedownImage(ev){if(this.isDragging){return;}
if(ev.button!==0){return;}
this.isDragging=true;this.dragStartX=ev.clientX;this.dragStartY=ev.clientY;}
onMouseupImage(){if(!this.isDragging){return;}
this.isDragging=false;this.translate.x+=this.translate.dx;this.translate.y+=this.translate.dy;this.translate.dx=0;this.translate.dy=0;this.updateZoomerStyle();}
onMousemoveView(ev){if(!this.isDragging){return;}
this.translate.dx=ev.clientX-this.dragStartX;this.translate.dy=ev.clientY-this.dragStartY;this.updateZoomerStyle();}
resetZoom(){this.state.scale=1;this.updateZoomerStyle();}
rotate(){this.state.angle+=90;}
zoomIn({scroll=false}={}){this.state.scale=this.state.scale+(scroll?this.scrollZoomStep:this.zoomStep);this.updateZoomerStyle();}
zoomOut({scroll=false}={}){if(this.state.scale===this.minScale){return;}
const unflooredAdaptedScale=this.state.scale-(scroll?this.scrollZoomStep:this.zoomStep);this.state.scale=Math.max(this.minScale,unflooredAdaptedScale);this.updateZoomerStyle();}
updateZoomerStyle(){const tx=this.imageRef.el.offsetWidth*this.state.scale>this.zoomerRef.el.offsetWidth?this.translate.x+this.translate.dx:0;const ty=this.imageRef.el.offsetHeight*this.state.scale>this.zoomerRef.el.offsetHeight?this.translate.y+this.translate.dy:0;if(tx===0){this.translate.x=0;}
if(ty===0){this.translate.y=0;}
this.zoomerRef.el.style="transform: "+`translate(${tx}px, ${ty}px)`;}
get imageStyle(){let style="transform: "+`scale3d(${this.state.scale}, ${this.state.scale}, 1) `+`rotate(${this.state.angle}deg);`;if(this.state.angle%180!==0){style+=`max-height: ${window.innerWidth}px; max-width: ${window.innerHeight}px;`;}else{style+="max-height: 100%; max-width: 100%;";}
return style;}
onClickPrint(){const printWindow=window.open("about:blank","_new");printWindow.document.open();printWindow.document.write(`
                <html>
                    <head>
                        <script>
                            function onloadImage() {
                                setTimeout('printImage()', 10);
                            }
                            function printImage() {
                                window.print();
                                window.close();
                            }
                        </script>
                    </head>
                    <body onload='onloadImage()'>
                        <img src="${this.state.file.defaultSource}" alt=""/>
                    </body>
                </html>`);printWindow.document.close();}}
return __exports;});;

/* /web/static/src/core/file_viewer/file_viewer_hook.js */
odoo.define('@web/core/file_viewer/file_viewer_hook',['@odoo/owl','@web/core/registry','@web/core/file_viewer/file_viewer'],function(require){'use strict';let __exports={};const{onWillDestroy}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{FileViewer}=require("@web/core/file_viewer/file_viewer");let id=1;__exports.createFileViewer=createFileViewer;function createFileViewer(){const fileViewerId=`web.file_viewer${id++}`;function open(file,files=[file]){close();if(!file.isViewable){return;}
if(files.length>0){const viewableFiles=files.filter((file)=>file.isViewable);const index=viewableFiles.indexOf(file);registry.category("main_components").add(fileViewerId,{Component:FileViewer,props:{files:viewableFiles,startIndex:index,close},});}}
function close(){registry.category("main_components").remove(fileViewerId);}
return{open,close};}
__exports.useFileViewer=useFileViewer;function useFileViewer(){const{open,close}=createFileViewer();onWillDestroy(close);return{open,close};}
return __exports;});;

/* /web/static/src/core/hotkeys/hotkey_hook.js */
odoo.define('@web/core/hotkeys/hotkey_hook',['@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{useEffect}=require("@odoo/owl");__exports.useHotkey=useHotkey;function useHotkey(hotkey,callback,options={}){const hotkeyService=useService("hotkey");useEffect(()=>hotkeyService.add(hotkey,callback,options),()=>[]);}
return __exports;});;

/* /web/static/src/core/hotkeys/hotkey_service.js */
odoo.define('@web/core/hotkeys/hotkey_service',['@web/core/browser/feature_detection','@web/core/registry','@web/core/browser/browser','@web/core/utils/ui'],function(require){'use strict';let __exports={};const{isMacOS}=require("@web/core/browser/feature_detection");const{registry}=require("@web/core/registry");const{browser}=require("@web/core/browser/browser");const{getVisibleElements}=require("@web/core/utils/ui");const ALPHANUM_KEYS="abcdefghijklmnopqrstuvwxyz0123456789".split("");const NAV_KEYS=["arrowleft","arrowright","arrowup","arrowdown","pageup","pagedown","home","end","backspace","enter","tab","delete","space",];const MODIFIERS=["alt","control","shift"];const AUTHORIZED_KEYS=[...ALPHANUM_KEYS,...NAV_KEYS,"escape"];__exports.getActiveHotkey=getActiveHotkey;function getActiveHotkey(ev){if(!ev.key){return"";}
if(ev.isComposing){return"";}
const hotkey=[];if(isMacOS()?ev.ctrlKey:ev.altKey){hotkey.push("alt");}
if(isMacOS()?ev.metaKey:ev.ctrlKey){hotkey.push("control");}
if(ev.shiftKey){hotkey.push("shift");}
let key=ev.key.toLowerCase();if(key===" "){key="space";}
if(ev.code&&ev.code.indexOf("Digit")===0){key=ev.code.slice(-1);}
if(!AUTHORIZED_KEYS.includes(key)&&ev.code&&ev.code.indexOf("Key")===0){key=ev.code.slice(-1).toLowerCase();}
if(!MODIFIERS.includes(key)){hotkey.push(key);}
return hotkey.join("+");}
const hotkeyService=__exports.hotkeyService={dependencies:["ui"],overlayModifier:"alt",start(env,{ui}){const registrations=new Map();let nextToken=0;let overlaysVisible=false;addListeners(browser);function addListeners(target){target.addEventListener("keydown",onKeydown);target.addEventListener("keyup",removeHotkeyOverlays);target.addEventListener("blur",removeHotkeyOverlays);target.addEventListener("click",removeHotkeyOverlays);}
function onKeydown(event){if(event.code&&event.code.indexOf("Numpad")===0&&/^\d$/.test(event.key)){return;}
const hotkey=getActiveHotkey(event);if(!hotkey){return;}
const{activeElement,isBlocked}=ui;if(isBlocked){return;}
const elementsWithAccessKey=document.querySelectorAll("[accesskey]");for(const el of elementsWithAccessKey){if(el instanceof HTMLElement){el.dataset.hotkey=el.accessKey;el.removeAttribute("accesskey");}}
if(!overlaysVisible&&hotkey===hotkeyService.overlayModifier){addHotkeyOverlays(activeElement);event.preventDefault();return;}
const singleKey=hotkey.split("+").pop();if(!AUTHORIZED_KEYS.includes(singleKey)){return;}
const targetIsEditable=event.target instanceof HTMLElement&&(/input|textarea/i.test(event.target.tagName)||event.target.isContentEditable)&&!event.target.matches("input[type=checkbox], input[type=radio]");const shouldProtectEditable=targetIsEditable&&!event.target.dataset.allowHotkeys&&singleKey!=="escape";const infos={activeElement,hotkey,isRepeated:event.repeat,target:event.target,shouldProtectEditable,};const dispatched=dispatch(infos);if(dispatched){event.preventDefault();event.stopImmediatePropagation();}
if(overlaysVisible){removeHotkeyOverlays();event.preventDefault();}}
function dispatch(infos){const{activeElement,hotkey,isRepeated,target,shouldProtectEditable}=infos;const reversedRegistrations=Array.from(registrations.values()).reverse();const domRegistrations=getDomRegistrations(hotkey,activeElement);const allRegistrations=reversedRegistrations.concat(domRegistrations);const candidates=allRegistrations.filter((reg)=>reg.hotkey===hotkey&&(reg.allowRepeat||!isRepeated)&&(reg.bypassEditableProtection||!shouldProtectEditable)&&(reg.global||reg.activeElement===activeElement)&&(!reg.isAvailable||reg.isAvailable())&&(!reg.area||(target&&reg.area()&&reg.area().contains(target))));let winner=candidates.shift();if(winner&&winner.area){for(const candidate of candidates.filter((c)=>Boolean(c.area))){if(candidate.area()&&winner.area().contains(candidate.area())){winner=candidate;}}}
if(winner){winner.callback({area:winner.area&&winner.area(),target,});return true;}
return false;}
function getDomRegistrations(hotkey,activeElement){const overlayModParts=hotkeyService.overlayModifier.split("+");if(!overlayModParts.every((el)=>hotkey.includes(el))){return[];}
const cleanHotkey=hotkey.split("+").filter((key)=>!overlayModParts.includes(key)).join("+");const elems=getVisibleElements(activeElement,`[data-hotkey='${cleanHotkey}' i]`);return elems.map((el)=>({hotkey,activeElement,bypassEditableProtection:true,callback:()=>{if(document.activeElement){document.activeElement.blur();}
el.focus();setTimeout(()=>el.click());},}));}
function addHotkeyOverlays(activeElement){const hotkeysFromHookToHighlight=[];for(const[,registration]of registrations){const overlayElement=registration.withOverlay?.();if(overlayElement){hotkeysFromHookToHighlight.push({hotkey:registration.hotkey.replace(`${hotkeyService.overlayModifier}+`,""),el:overlayElement,});}}
const hotkeysFromDomToHighlight=getVisibleElements(activeElement,"[data-hotkey]:not(:disabled)").map((el)=>({hotkey:el.dataset.hotkey,el}));const items=[...hotkeysFromDomToHighlight,...hotkeysFromHookToHighlight];for(const item of items){const hotkey=item.hotkey;const overlay=document.createElement("div");overlay.classList.add("o_web_hotkey_overlay","position-absolute","top-0","bottom-0","start-0","end-0","d-flex","justify-content-center","align-items-center","m-0","bg-black-50","h6");overlay.style.zIndex=1;const overlayKbd=document.createElement("kbd");overlayKbd.className="small";overlayKbd.appendChild(document.createTextNode(hotkey.toUpperCase()));overlay.appendChild(overlayKbd);let overlayParent;if(item.el.tagName.toUpperCase()==="INPUT"){overlayParent=item.el.parentElement;}else{overlayParent=item.el;}
if(overlayParent.style.position!=="absolute"){overlayParent.style.position="relative";}
overlayParent.appendChild(overlay);}
overlaysVisible=true;}
function removeHotkeyOverlays(){for(const overlay of document.querySelectorAll(".o_web_hotkey_overlay")){overlay.remove();}
overlaysVisible=false;}
function registerHotkey(hotkey,callback,options={}){if(!hotkey||hotkey.length===0){throw new Error("You must specify an hotkey when registering a registration.");}
if(!callback||typeof callback!=="function"){throw new Error("You must specify a callback function when registering a registration.");}
const keys=hotkey.toLowerCase().split("+").filter((k)=>!MODIFIERS.includes(k));if(keys.some((k)=>!AUTHORIZED_KEYS.includes(k))){throw new Error(`You are trying to subscribe for an hotkey ('${hotkey}')
            that contains parts not whitelisted: ${keys.join(", ")}`);}else if(keys.length>1){throw new Error(`You are trying to subscribe for an hotkey ('${hotkey}')
            that contains more than one single key part: ${keys.join("+")}`);}
const token=nextToken++;const registration={hotkey:hotkey.toLowerCase(),callback,activeElement:null,allowRepeat:options&&options.allowRepeat,bypassEditableProtection:options&&options.bypassEditableProtection,global:options&&options.global,area:options&&options.area,isAvailable:options&&options.isAvailable,withOverlay:options&&options.withOverlay,};Promise.resolve().then(()=>{registration.activeElement=ui.activeElement;});registrations.set(token,registration);return token;}
function unregisterHotkey(token){registrations.delete(token);}
return{add(hotkey,callback,options={}){const token=registerHotkey(hotkey,callback,options);return()=>{unregisterHotkey(token);};},registerIframe(iframe){addListeners(iframe.contentWindow);},};},};registry.category("services").add("hotkey",hotkeyService);return __exports;});;

/* /web/static/src/core/install_scoped_app/install_scoped_app.js */
odoo.define('@web/core/install_scoped_app/install_scoped_app',['@web/core/browser/browser','@web/core/registry','@odoo/owl','@web/core/browser/feature_detection','@web/core/utils/hooks','@web/core/dropdown/dropdown'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{Component,onMounted,useState}=require("@odoo/owl");const{isDisplayStandalone}=require("@web/core/browser/feature_detection");const{useService}=require("@web/core/utils/hooks");const{Dropdown}=require("@web/core/dropdown/dropdown");const InstallScopedApp=__exports.InstallScopedApp=class InstallScopedApp extends Component{static props={};static template="web.InstallScopedApp";static components={Dropdown};setup(){this.pwa=useState(useService("pwa"));this.state=useState({manifest:{},showInstallUI:false});this.isDisplayStandalone=isDisplayStandalone();this.isInstallationPossible=browser.BeforeInstallPromptEvent!==undefined;onMounted(async()=>{this.state.manifest=await this.pwa.getManifest();this.state.showInstallUI=true;});}
onChangeName(ev){const value=ev.target.value;if(value!==this.state.manifest.name){const url=new URL(document.location.href);url.searchParams.set("app_name",encodeURIComponent(value));browser.location.replace(url);}}
onInstall(){this.state.showInstallUI=false;this.pwa.show({onDone:(res)=>{if(res.outcome==="accepted"){browser.location.replace(this.state.manifest.start_url);}else{this.state.showInstallUI=true;}},});}}
registry.category("public_components").add("web.install_scoped_app",InstallScopedApp);return __exports;});;

/* /web/static/src/core/l10n/dates.js */
odoo.define('@web/core/l10n/dates',['@web/core/l10n/localization','@web/core/l10n/translation','@web/core/utils/functions','@web/core/utils/arrays'],function(require){'use strict';let __exports={};const{localization}=require("@web/core/l10n/localization");const{_t}=require("@web/core/l10n/translation");const{memoize}=require("@web/core/utils/functions");const{ensureArray}=require("@web/core/utils/arrays");const{DateTime,Settings}=luxon;const MIN_VALID_DATE=__exports.MIN_VALID_DATE=DateTime.fromObject({year:1000});const MAX_VALID_DATE=__exports.MAX_VALID_DATE=DateTime.fromObject({year:9999}).endOf("year");const SERVER_DATE_FORMAT="yyyy-MM-dd";const SERVER_TIME_FORMAT="HH:mm:ss";const SERVER_DATETIME_FORMAT=`${SERVER_DATE_FORMAT} ${SERVER_TIME_FORMAT}`;const nonAlphaRegex=/[^a-z]/gi;const nonDigitRegex=/[^\d]/g;const normalizeFormatTable={a:"ccc",A:"cccc",b:"MMM",B:"MMMM",d:"dd",H:"HH",I:"hh",j:"o",m:"MM",M:"mm",p:"a",S:"ss",W:"WW",w:"c",y:"yy",Y:"yyyy",c:"ccc MMM d HH:mm:ss yyyy",x:"MM/dd/yy",X:"HH:mm:ss",};const smartDateUnits={d:"days",m:"months",w:"weeks",y:"years",};const smartDateRegex=new RegExp(["^","([+-])","(\\d+)",`([${Object.keys(smartDateUnits).join("")}]?)`,"$"].join("\\s*"),"i");const dateCache=new WeakMap();const dateTimeCache=new WeakMap();const ConversionError=__exports.ConversionError=class ConversionError extends Error{name="ConversionError";}
__exports.areDatesEqual=areDatesEqual;function areDatesEqual(d1,d2){if(Array.isArray(d1)||Array.isArray(d2)){d1=ensureArray(d1);d2=ensureArray(d2);return d1.length===d2.length&&d1.every((d1Val,i)=>areDatesEqual(d1Val,d2[i]));}
if(d1 instanceof DateTime&&d2 instanceof DateTime&&d1!==d2){return d1.equals(d2);}else{return d1===d2;}}
__exports.clampDate=clampDate;function clampDate(desired,minDate,maxDate){if(maxDate<desired){return maxDate;}
if(minDate>desired){return minDate;}
return desired;}
__exports.getLocalWeekNumber=getLocalWeekNumber;function getLocalWeekNumber(date){return getLocalYearAndWeek(date).week;}
__exports.getLocalYearAndWeek=getLocalYearAndWeek;function getLocalYearAndWeek(date){if(!date.isLuxonDateTime){date=DateTime.fromJSDate(date);}
const{weekStart}=localization;date=date.minus({days:(date.weekday+7-weekStart)%7});date=weekStart>1&&weekStart<5?date.minus({days:(date.weekday+6)%7}):date.plus({days:(8-date.weekday)%7});date=date.plus({days:6});const jan4=DateTime.local(date.year,1,4);const diffDays=date<jan4?date.diff(jan4.minus({years:1}),"day").days:date.diff(jan4,"day").days;return{year:date.year,week:Math.trunc(diffDays/7)+1};}
__exports.getStartOfLocalWeek=getStartOfLocalWeek;function getStartOfLocalWeek(date){const{weekStart}=localization;const weekday=date.weekday<weekStart?weekStart-7:weekStart;return date.set({weekday}).startOf("day");}
__exports.getEndOfLocalWeek=getEndOfLocalWeek;function getEndOfLocalWeek(date){return getStartOfLocalWeek(date).plus({days:6}).endOf("day");}
__exports.is24HourFormat=is24HourFormat;function is24HourFormat(format){return/H/.test(format||localization.timeFormat);}
__exports.isInRange=isInRange;function isInRange(value,range){if(!value||!range){return false;}
if(Array.isArray(value)){const actualValues=value.filter(Boolean);if(actualValues.length<2){return isInRange(actualValues[0],range);}
return((value[0]<=range[0]&&range[0]<=value[1])||(range[0]<=value[0]&&value[0]<=range[1]));}else{return range[0]<=value&&value<=range[1];}}
__exports.isMeridiemFormat=isMeridiemFormat;function isMeridiemFormat(format){return/a/.test(format||localization.timeFormat);}
function isValidDate(date){return date&&date.isValid&&isInRange(date,[MIN_VALID_DATE,MAX_VALID_DATE]);}
function parseSmartDateInput(value){const match=value.match(smartDateRegex);if(match){let date=DateTime.local();const offset=parseInt(match[2],10);const unit=smartDateUnits[(match[3]||"d").toLowerCase()];if(match[1]==="+"){date=date.plus({[unit]:offset});}else{date=date.minus({[unit]:offset});}
return date;}
return false;}
const stripAlphaDupes=memoize(function stripAlphaDupes(str){return str.replace(/[a-z]/gi,(letter,index,str)=>letter===str[index-1]?"":letter);});const strftimeToLuxonFormat=__exports.strftimeToLuxonFormat=memoize(function strftimeToLuxonFormat(format){const output=[];let inToken=false;for(let index=0;index<format.length;++index){let character=format[index];if(character==="%"&&!inToken){inToken=true;continue;}
if(/[a-z]/gi.test(character)){if(inToken&&normalizeFormatTable[character]!==undefined){character=normalizeFormatTable[character];}else{character=`'${character}'`;}}
output.push(character);inToken=false;}
return output.join("");});__exports.today=today;function today(){return DateTime.local().startOf("day");}
const condensedFormats={};function getCondensedFormat(format){const originalFormat=format;if(!condensedFormats[originalFormat]){format=format.replace(/(^|[^M])M{2}([^M]|$)/,"$1M$2");format=format.replace(/(^|[^d])d{2}([^d]|$)/,"$1d$2");format=format.replace(/(^|[^H])H{2}([^H]|$)/,"$1H$2");condensedFormats[originalFormat]=format;}
return condensedFormats[originalFormat];}
__exports.formatDate=formatDate;function formatDate(value,options={}){if(!value){return"";}
let format=options.format;if(!format){format=localization.dateFormat;if(options.condensed){format=getCondensedFormat(format);}}
return value.toFormat(format);}
__exports.formatDateTime=formatDateTime;function formatDateTime(value,options={}){if(!value){return"";}
let format=options.format;if(!format){if(options.showSeconds===false){format=`${localization.dateFormat} ${localization.shortTimeFormat}`;}else{format=localization.dateTimeFormat;}
if(options.condensed){format=getCondensedFormat(format);}}
return value.setZone(options.tz||"default").toFormat(format);}
__exports.formatDuration=formatDuration;function formatDuration(seconds,showFullDuration){const displayStyle=showFullDuration?"long":"narrow";const numberOfValuesToDisplay=showFullDuration?2:1;const durationKeys=["years","months","days","hours","minutes"];if(seconds<60){seconds=60;}
seconds-=seconds%60;let duration=luxon.Duration.fromObject({seconds:seconds}).shiftTo(...durationKeys);duration=duration.shiftTo(...durationKeys.filter((key)=>duration.get(key)));const durationSplit=duration.toHuman({unitDisplay:displayStyle}).split(",");if(!showFullDuration&&duration.loc.locale.includes("en")&&duration.months>0){durationSplit[0]=durationSplit[0].replace("m","M");}
return durationSplit.slice(0,numberOfValuesToDisplay).join(",");}
__exports.serializeDate=serializeDate;function serializeDate(value){if(!dateCache.has(value)){dateCache.set(value,value.toFormat(SERVER_DATE_FORMAT,{numberingSystem:"latn"}));}
return dateCache.get(value);}
__exports.serializeDateTime=serializeDateTime;function serializeDateTime(value){if(!dateTimeCache.has(value)){dateTimeCache.set(value,value.setZone("utc").toFormat(SERVER_DATETIME_FORMAT,{numberingSystem:"latn"}));}
return dateTimeCache.get(value);}
__exports.parseDate=parseDate;function parseDate(value,options={}){const parsed=parseDateTime(value,{...options,format:options.format||localization.dateFormat,});return parsed&&parsed.startOf("day");}
__exports.parseDateTime=parseDateTime;function parseDateTime(value,options={}){if(!value){return false;}
const fmt=options.format||localization.dateTimeFormat;const parseOpts={setZone:true,zone:options.tz||"default",};const switchToLatin=Settings.defaultNumberingSystem!=="latn"&&/[0-9]/.test(value);if(switchToLatin){parseOpts.numberingSystem="latn";}
let result=DateTime.fromFormat(value,fmt,parseOpts);if(!isValidDate(result)){result=parseSmartDateInput(value);}
if(!isValidDate(result)){const fmtWoZero=stripAlphaDupes(fmt);result=DateTime.fromFormat(value,fmtWoZero,parseOpts);}
if(!isValidDate(result)){const digitList=value.split(nonDigitRegex).filter(Boolean);const fmtList=fmt.split(nonAlphaRegex).filter(Boolean);const valWoSeps=digitList.join("");let carry=0;const fmtWoSeps=fmtList.map((part,i)=>{const digitLength=(digitList[i]||"").length;const actualPart=part.slice(0,digitLength+carry);carry+=digitLength-actualPart.length;return actualPart;}).join("");result=DateTime.fromFormat(valWoSeps,fmtWoSeps,parseOpts);}
if(!isValidDate(result)){const valueDigits=value.replace(nonDigitRegex,"");if(valueDigits.length>4){result=DateTime.fromISO(value,parseOpts);if(!isValidDate(result)){result=DateTime.fromSQL(value,parseOpts);}}}
if(!isValidDate(result)){throw new ConversionError(_t("'%s' is not a correct date or datetime",value));}
if(switchToLatin){result=result.reconfigure({numberingSystem:Settings.defaultNumberingSystem,});}
return result.setZone(options.tz||"default");}
__exports.deserializeDate=deserializeDate;function deserializeDate(value,options={}){options={numberingSystem:"latn",zone:"default",...options};return DateTime.fromSQL(value,options).reconfigure({numberingSystem:Settings.defaultNumberingSystem,});}
__exports.deserializeDateTime=deserializeDateTime;function deserializeDateTime(value,options={}){return DateTime.fromSQL(value,{numberingSystem:"latn",zone:"utc"}).setZone(options?.tz||"default").reconfigure({numberingSystem:Settings.defaultNumberingSystem,});}
return __exports;});;

/* /web/static/src/core/l10n/localization.js */
odoo.define('@web/core/l10n/localization',[],function(require){'use strict';let __exports={};const localization=__exports.localization=new Proxy({},{get:(target,p)=>{if(p in target||p==="then"){return Reflect.get(target,p);}
throw new Error(`could not access localization parameter "${p}": parameters are not ready yet. Maybe add 'localization' to your dependencies?`);},});return __exports;});;

/* /web/static/src/core/l10n/localization_service.js */
odoo.define('@web/core/l10n/localization_service',['@web/session','@web/core/l10n/utils','@web/core/user','@web/core/browser/browser','@web/core/registry','@web/core/l10n/dates','@web/core/l10n/localization','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{session}=require("@web/session");const{jsToPyLocale}=require("@web/core/l10n/utils");const{user}=require("@web/core/user");const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{strftimeToLuxonFormat}=require("@web/core/l10n/dates");const{localization}=require("@web/core/l10n/localization");const{translatedTerms,translationLoaded,translationIsReady}=require("@web/core/l10n/translation");const{Settings}=luxon;const NUMBERING_SYSTEMS=[[/^ar-(sa|sy|001)$/i,"arab"],[/^bn/i,"beng"],[/^bo/i,"tibt"],[/^pa-in/i,"guru"],[/^ta/i,"tamldec"],[/.*/i,"latn"],];const localizationService=__exports.localizationService={start:async()=>{const cacheHashes=session.cache_hashes||{};const translationsHash=cacheHashes.translations||new Date().getTime().toString();const lang=jsToPyLocale(user.lang||document.documentElement.getAttribute("lang"));const translationURL=session.translationURL||"/web/webclient/translations";let url=`${translationURL}/${translationsHash}`;if(lang){url+=`?lang=${lang}`;}
const response=await browser.fetch(url);if(!response.ok){throw new Error("Error while fetching translations");}
const{lang_parameters:userLocalization,modules:modules,multi_lang:multiLang,}=await response.json();const terms={};for(const addon of Object.keys(modules)){for(const message of modules[addon].messages){terms[message.id]=message.string;}}
Object.assign(translatedTerms,terms);translatedTerms[translationLoaded]=true;translationIsReady.resolve(true);const locale=user.lang||browser.navigator.language;Settings.defaultLocale=locale;for(const[re,numberingSystem]of NUMBERING_SYSTEMS){if(re.test(locale)){Settings.defaultNumberingSystem=numberingSystem;break;}}
const dateFormat=strftimeToLuxonFormat(userLocalization.date_format);const timeFormat=strftimeToLuxonFormat(userLocalization.time_format);const shortTimeFormat=strftimeToLuxonFormat(userLocalization.short_time_format);const dateTimeFormat=`${dateFormat} ${timeFormat}`;const grouping=JSON.parse(userLocalization.grouping);Object.assign(localization,{dateFormat,timeFormat,shortTimeFormat,dateTimeFormat,decimalPoint:userLocalization.decimal_point,direction:userLocalization.direction,grouping,multiLang,thousandsSep:userLocalization.thousands_sep,weekStart:userLocalization.week_start,code:jsToPyLocale(locale),});return localization;},};registry.category("services").add("localization",localizationService);return __exports;});;

/* /web/static/src/core/l10n/translation.js */
odoo.define('@web/core/l10n/translation',['@odoo/owl','@web/core/utils/concurrency','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{markup}=require("@odoo/owl");const{Deferred}=require("@web/core/utils/concurrency");const{escape,sprintf}=require("@web/core/utils/strings");const translationLoaded=__exports.translationLoaded=Symbol("translationLoaded");const translatedTerms=__exports.translatedTerms={[translationLoaded]:false,};const translationIsReady=__exports.translationIsReady=new Deferred();const Markup=markup().constructor;__exports._t=_t;function _t(term,...values){if(translatedTerms[translationLoaded]){const translation=translatedTerms[term]??term;if(values.length===0){return translation;}
return _safeSprintf(translation,...values);}else{return new LazyTranslatedString(term,values);}}
class LazyTranslatedString extends String{constructor(term,values){super(term);this.values=values;}
valueOf(){const term=super.valueOf();if(translatedTerms[translationLoaded]){const translation=translatedTerms[term]??term;if(this.values.length===0){return translation;}
return _safeSprintf(translation,...this.values);}else{throw new Error(`translation error`);}}
toString(){return this.valueOf();}}
_t("less than a minute ago");_t("about a minute ago");_t("%d minutes ago");_t("about an hour ago");_t("%d hours ago");_t("a day ago");_t("%d days ago");_t("about a month ago");_t("%d months ago");_t("about a year ago");_t("%d years ago");__exports.loadLanguages=loadLanguages;async function loadLanguages(orm){if(!loadLanguages.installedLanguages){loadLanguages.installedLanguages=await orm.call("res.lang","get_installed");}
return loadLanguages.installedLanguages;}
function _safeSprintf(str,...values){let hasMarkup;if(values.length===1&&Object.prototype.toString.call(values[0])==="[object Object]"){hasMarkup=Object.values(values[0]).some((v)=>v instanceof Markup);}else{hasMarkup=values.some((v)=>v instanceof Markup);}
if(hasMarkup){return markup(sprintf(escape(str),..._escapeNonMarkup(values)));}
return sprintf(str,...values);}
function _escapeNonMarkup(values){if(Object.prototype.toString.call(values[0])==="[object Object]"){const sanitized={};for(const[key,value]of Object.entries(values[0])){sanitized[key]=value instanceof Markup?value:escape(value);}
return[sanitized];}
return values.map((x)=>(x instanceof Markup?x:escape(x)));}
return __exports;});;

/* /web/static/src/core/l10n/utils.js */
odoo.define('@web/core/l10n/utils',['@web/core/l10n/utils/format_list','@web/core/l10n/utils/locales'],function(require){'use strict';let __exports={};Object.assign(__exports,require("@web/core/l10n/utils/format_list"));Object.assign(__exports,require("@web/core/l10n/utils/locales"));return __exports;});;

/* /web/static/src/core/l10n/utils/format_list.js */
odoo.define('@web/core/l10n/utils/format_list',['@web/core/user'],function(require){'use strict';let __exports={};const{user}=require("@web/core/user");const LIST_STYLES={standard:{type:"conjunction",style:"long",},"standard-short":{type:"conjunction",style:"short",},or:{type:"disjunction",style:"long",},"or-short":{type:"disjunction",style:"short",},unit:{type:"unit",style:"long",},"unit-short":{type:"unit",style:"short",},"unit-narrow":{type:"unit",style:"narrow",},};__exports.formatList=formatList;function formatList(list,{localeCode="",style="standard"}={}){const locale=localeCode||user.lang||"en-US";const formatter=new Intl.ListFormat(locale,LIST_STYLES[style]);return formatter.format(list);}
return __exports;});;

/* /web/static/src/core/l10n/utils/locales.js */
odoo.define('@web/core/l10n/utils/locales',[],function(require){'use strict';let __exports={};__exports.jsToPyLocale=jsToPyLocale;function jsToPyLocale(locale){if(!locale){return"";}
try{var{language,script,region}=new Intl.Locale(locale);if(language==="fil"){language="tl";}}catch{return locale;}
let xpgLocale=language;if(region){xpgLocale+=`_${region}`;}
switch(script){case"Cyrl":xpgLocale+="@Cyrl";break;case"Latn":xpgLocale+="@latin";break;}
return xpgLocale;}
__exports.pyToJsLocale=pyToJsLocale;function pyToJsLocale(locale){if(!locale){return"";}
const regex=/^([a-z]+)(_[A-Z\d]+)?(@.+)?$/;const match=locale.match(regex);if(!match){return locale;}
const[,language,territory,modifier]=match;const subtags=[language];switch(modifier){case"@Cyrl":subtags.push("Cyrl");break;case"@latin":subtags.push("Latn");break;}
if(territory){subtags.push(territory.slice(1));}
return subtags.join("-");}
return __exports;});;

/* /web/static/src/core/macro.js */
odoo.define('@web/core/macro',['@web/core/utils/ui','@web/core/utils/concurrency','@odoo/owl'],function(require){'use strict';let __exports={};const{isVisible}=require("@web/core/utils/ui");const{delay}=require("@web/core/utils/concurrency");const{validate}=require("@odoo/owl");const macroSchema={name:{type:String,optional:true},timeout:{type:Number,optional:true},steps:{type:Array,element:{type:Object,shape:{action:{type:[Function,String],optional:true},timeout:{type:Number,optional:true},trigger:{type:[Function,String],optional:true},},validate:(step)=>step.action||step.trigger,},},onComplete:{type:Function,optional:true},onStep:{type:Function,optional:true},onError:{type:Function,optional:true},};class MacroError extends Error{constructor(type,message,options){super(message,options);this.type=type;}}
async function performAction(trigger,action){if(!action){return;}
try{return await action(trigger);}catch(error){throw new MacroError("Action",error.stack||`ERROR during perform action: ${error.message}`,{cause:error});}}
__exports.waitForStable=waitForStable;async function waitForStable(target=document,timeout=1000/16){return new Promise((resolve)=>{let observer;let timer;const mutationList=[];function onMutation(mutations){mutationList.push(...(mutations||[]));clearTimeout(timer);timer=setTimeout(()=>{observer.disconnect();resolve(mutationList);},timeout);}
observer=new MacroMutationObserver(onMutation);observer.observe(target);onMutation([]);});}
async function waitForTrigger(trigger){if(!trigger){return;}
try{await delay(50);return await waitUntil(()=>{if(typeof trigger==="function"){return trigger();}else if(typeof trigger==="string"){const triggerEl=document.querySelector(trigger);return isVisible(triggerEl)&&triggerEl;}});}catch(error){throw new MacroError("Trigger",`ERROR during find trigger:\n${error.message}`,{cause:error,});}}
async function waitUntil(predicate){const result=predicate();if(result){return Promise.resolve(result);}
let handle;return new Promise((resolve)=>{const runCheck=()=>{const result=predicate();if(result){resolve(result);}
handle=requestAnimationFrame(runCheck);};handle=requestAnimationFrame(runCheck);}).finally(()=>{cancelAnimationFrame(handle);});}
const Macro=__exports.Macro=class Macro{currentIndex=0;isComplete=false;constructor(descr){try{validate(descr,macroSchema);}catch(error){throw new Error(`Error in schema for Macro ${JSON.stringify(descr, null, 4)}\n${error.message}`);}
Object.assign(this,descr);this.onComplete=this.onComplete||(()=>{});this.onStep=this.onStep||(()=>{});this.onError=this.onError||((error,step,index)=>{console.error(error.message,step,index);});}
async start(){await this.advance();}
async advance(){if(this.isComplete||this.currentIndex>=this.steps.length){this.stop();return;}
try{const currentStep=this.steps[this.currentIndex];const executeStep=async()=>{const trigger=await waitForTrigger(currentStep.trigger);await this.onStep(currentStep,trigger,this.currentIndex);return await performAction(trigger,currentStep.action);};const launchTimer=async()=>{const timeout_delay=currentStep.timeout||this.timeout||10000;await delay(timeout_delay);throw new MacroError("Timeout",`TIMEOUT step failed to complete within ${timeout_delay} ms.`);};const actionResult=await Promise.race([executeStep(),launchTimer()]);if(actionResult){this.stop();return;}}catch(error){this.stop(error);return;}
this.currentIndex++;await this.advance();}
stop(error){if(this.isComplete){return;}
this.isComplete=true;if(error){this.onError(error,this.steps[this.currentIndex],this.currentIndex);}else if(this.currentIndex===this.steps.length){this.onComplete();}}}
const MacroMutationObserver=__exports.MacroMutationObserver=class MacroMutationObserver{observerOptions={attributes:true,childList:true,subtree:true,characterData:true,};constructor(callback){this.callback=callback;this.observer=new MutationObserver((mutationList,observer)=>{callback(mutationList);mutationList.forEach((mutationRecord)=>Array.from(mutationRecord.addedNodes).forEach((node)=>{let iframes=[];if(String(node.tagName).toLowerCase()==="iframe"){iframes=[node];}else if(node instanceof HTMLElement){iframes=Array.from(node.querySelectorAll("iframe"));}
iframes.forEach((iframeEl)=>this.observeIframe(iframeEl,observer,()=>callback()));this.findAllShadowRoots(node).forEach((shadowRoot)=>observer.observe(shadowRoot,this.observerOptions));}));});}
disconnect(){this.observer.disconnect();}
findAllShadowRoots(node,shadowRoots=[]){if(node.shadowRoot){shadowRoots.push(node.shadowRoot);this.findAllShadowRoots(node.shadowRoot,shadowRoots);}
node.childNodes.forEach((child)=>{this.findAllShadowRoots(child,shadowRoots);});return shadowRoots;}
observe(target){this.observer.observe(target,this.observerOptions);target.querySelectorAll("iframe").forEach((el)=>this.observeIframe(el,this.observer,()=>this.callback()));this.findAllShadowRoots(target).forEach((shadowRoot)=>{this.observer.observe(shadowRoot,this.observerOptions);});}
observeIframe(iframeEl,observer,callback){const observerOptions={attributes:true,childList:true,subtree:true,characterData:true,};const observeIframeContent=()=>{if(iframeEl.contentDocument){iframeEl.contentDocument.addEventListener("load",(event)=>{callback();observer.observe(event.target,observerOptions);});if(!iframeEl.src||iframeEl.contentDocument.readyState==="complete"){callback();observer.observe(iframeEl.contentDocument,observerOptions);}}};observeIframeContent();iframeEl.addEventListener("load",observeIframeContent);}}
return __exports;});;

/* /web/static/src/core/main_components_container.js */
odoo.define('@web/core/main_components_container',['@odoo/owl','@web/core/registry','@web/core/registry_hook','@web/core/utils/components'],function(require){'use strict';let __exports={};const{Component,xml}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{useRegistry}=require("@web/core/registry_hook");const{ErrorHandler}=require("@web/core/utils/components");const mainComponents=registry.category("main_components");mainComponents.addValidation({Component:{validate:(c)=>c.prototype instanceof Component},props:{type:Object,optional:true}});const MainComponentsContainer=__exports.MainComponentsContainer=class MainComponentsContainer extends Component{static components={ErrorHandler};static props={};static template=xml`
    <div class="o-main-components-container">
        <t t-foreach="Components.entries" t-as="C" t-key="C[0]">
            <ErrorHandler onError="error => this.handleComponentError(error, C)">
                <t t-component="C[1].Component" t-props="C[1].props"/>
            </ErrorHandler>
        </t>
    </div>
    `;setup(){this.Components=useRegistry(mainComponents);}
handleComponentError(error,C){this.Components.entries.splice(this.Components.entries.indexOf(C),1);this.render();Promise.resolve().then(()=>{throw error;});}}
return __exports;});;

/* /web/static/src/core/model_field_selector/model_field_selector.js */
odoo.define('@web/core/model_field_selector/model_field_selector',['@odoo/owl','@web/core/utils/concurrency','@web/core/model_field_selector/model_field_selector_popover','@web/core/model_field_selector/utils','@web/core/popover/popover_hook'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps,useState}=require("@odoo/owl");const{KeepLast}=require("@web/core/utils/concurrency");const{ModelFieldSelectorPopover}=require("@web/core/model_field_selector/model_field_selector_popover");const{useLoadFieldInfo,useLoadPathDescription}=require("@web/core/model_field_selector/utils");const{usePopover}=require("@web/core/popover/popover_hook");const ModelFieldSelector=__exports.ModelFieldSelector=class ModelFieldSelector extends Component{static template="web._ModelFieldSelector";static components={Popover:ModelFieldSelectorPopover,};static props={resModel:String,path:{optional:true},allowEmpty:{type:Boolean,optional:true},readonly:{type:Boolean,optional:true},showSearchInput:{type:Boolean,optional:true},isDebugMode:{type:Boolean,optional:true},update:{type:Function,optional:true},filter:{type:Function,optional:true},followRelations:{type:Boolean,optional:true},showDebugInput:{type:Boolean,optional:true},};static defaultProps={readonly:true,allowEmpty:false,isDebugMode:false,showSearchInput:true,update:()=>{},followRelations:true,};setup(){this.loadPathDescription=useLoadPathDescription();const loadFieldInfo=useLoadFieldInfo();this.popover=usePopover(this.constructor.components.Popover,{popoverClass:"o_popover_field_selector",onClose:async()=>{if(this.newPath!==null){const fieldInfo=await loadFieldInfo(this.props.resModel,this.newPath);this.props.update(this.newPath,fieldInfo);}},});this.keepLast=new KeepLast();this.state=useState({isInvalid:false,displayNames:[]});onWillStart(()=>this.updateState(this.props));onWillUpdateProps((nextProps)=>this.updateState(nextProps));}
openPopover(currentTarget){if(this.props.readonly){return;}
this.newPath=null;this.popover.open(currentTarget,{resModel:this.props.resModel,path:this.props.path,update:(path,_fieldInfo,debug=false)=>{this.newPath=path;if(!debug){this.updateState({...this.props,path},true);}},showSearchInput:this.props.showSearchInput,isDebugMode:this.props.isDebugMode,filter:this.props.filter,followRelations:this.props.followRelations,showDebugInput:this.props.showDebugInput,});}
async updateState(params,isConcurrent){const{resModel,path,allowEmpty}=params;let prom=this.loadPathDescription(resModel,path,allowEmpty);if(isConcurrent){prom=this.keepLast.add(prom);}
const state=await prom;Object.assign(this.state,state);}
clear(){if(this.popover.isOpen){this.newPath="";this.popover.close();return;}
this.props.update("",{resModel:this.props.resModel,fieldDef:null});}}
return __exports;});;

/* /web/static/src/core/model_field_selector/model_field_selector_popover.js */
odoo.define('@web/core/model_field_selector/model_field_selector_popover',['@odoo/owl','@web/core/utils/timing','@web/core/l10n/translation','@web/core/utils/search','@web/core/utils/concurrency','@web/core/utils/arrays','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,onWillStart,useEffect,useRef,useState}=require("@odoo/owl");const{debounce}=require("@web/core/utils/timing");const{_t}=require("@web/core/l10n/translation");const{fuzzyLookup}=require("@web/core/utils/search");const{KeepLast}=require("@web/core/utils/concurrency");const{sortBy}=require("@web/core/utils/arrays");const{useService}=require("@web/core/utils/hooks");class Page{constructor(resModel,fieldDefs,options={}){this.resModel=resModel;this.fieldDefs=fieldDefs;const{previousPage=null,selectedName=null,isDebugMode}=options;this.previousPage=previousPage;this.selectedName=selectedName;this.isDebugMode=isDebugMode;this.sortedFieldNames=sortBy(Object.keys(fieldDefs),(key)=>fieldDefs[key].string);this.fieldNames=this.sortedFieldNames;this.query="";this.focusedFieldName=null;this.resetFocusedFieldName();}
get path(){const previousPath=this.previousPage?.path||"";if(this.selectedName){if(previousPath){return`${previousPath}.${this.selectedName}`;}else{return this.selectedName;}}
return previousPath;}
get selectedField(){return this.fieldDefs[this.selectedName];}
get title(){const prefix=this.previousPage?.previousPage?"... > ":"";const title=this.previousPage?.selectedField?.string||"";if(prefix.length||title.length){return`${prefix}${title}`;}
return _t("Select a field");}
focus(direction){if(!this.fieldNames.length){return;}
const index=this.fieldNames.indexOf(this.focusedFieldName);if(direction==="previous"){if(index===0){this.focusedFieldName=this.fieldNames[this.fieldNames.length-1];}else{this.focusedFieldName=this.fieldNames[index-1];}}else{if(index===this.fieldNames.length-1){this.focusedFieldName=this.fieldNames[0];}else{this.focusedFieldName=this.fieldNames[index+1];}}}
resetFocusedFieldName(){if(this.selectedName&&this.fieldNames.includes(this.selectedName)){this.focusedFieldName=this.selectedName;}else{this.focusedFieldName=this.fieldNames.length?this.fieldNames[0]:null;}}
searchFields(query=""){this.query=query;this.fieldNames=this.sortedFieldNames;if(query){this.fieldNames=fuzzyLookup(query,this.fieldNames,(key)=>{const vals=[this.fieldDefs[key].string];if(this.isDebugMode){vals.push(key);}
return vals;});}
this.resetFocusedFieldName();}}
const ModelFieldSelectorPopover=__exports.ModelFieldSelectorPopover=class ModelFieldSelectorPopover extends Component{static template="web.ModelFieldSelectorPopover";static props={close:Function,filter:{type:Function,optional:true},followRelations:{type:Boolean,optional:true},showDebugInput:{type:Boolean,optional:true},isDebugMode:{type:Boolean,optional:true},path:{optional:true},resModel:String,showSearchInput:{type:Boolean,optional:true},update:Function,};static defaultProps={filter:(value)=>value.searchable&&value.type!="json"&&value.type!=="separator",isDebugMode:false,followRelations:true,};setup(){this.fieldService=useService("field");this.state=useState({page:null});this.keepLast=new KeepLast();this.debouncedSearchFields=debounce(this.searchFields.bind(this),250);onWillStart(async()=>{this.state.page=await this.loadPages(this.props.resModel,this.props.path);});const rootRef=useRef("root");useEffect(()=>{const focusedElement=rootRef.el.querySelector(".o_model_field_selector_popover_item.active");if(focusedElement){focusedElement.scrollIntoView({block:"center"});}});useEffect(()=>{if(this.props.showSearchInput){const searchInput=rootRef.el.querySelector(".o_model_field_selector_popover_search .o_input");searchInput.focus();}},()=>[this.state.page]);}
get showDebugInput(){return this.props.showDebugInput??this.props.isDebugMode;}
filter(fieldDefs,path){const filteredKeys=Object.keys(fieldDefs).filter((k)=>this.props.filter(fieldDefs[k],path));return Object.fromEntries(filteredKeys.map((k)=>[k,fieldDefs[k]]));}
async followRelation(fieldDef){const{modelsInfo}=await this.keepLast.add(this.fieldService.loadPath(this.state.page.resModel,`${fieldDef.name}.*`));this.state.page.selectedName=fieldDef.name;const{resModel,fieldDefs}=modelsInfo.at(-1);this.openPage(new Page(resModel,this.filter(fieldDefs,this.state.page.path),{previousPage:this.state.page,isDebugMode:this.props.isDebugMode,}));}
goToPreviousPage(){this.keepLast.add(Promise.resolve());this.openPage(this.state.page.previousPage);}
async loadNewPath(path){const newPage=await this.keepLast.add(this.loadPages(this.props.resModel,path));this.openPage(newPage);}
async loadPages(resModel,path){if(typeof path!=="string"||!path.length){const fieldDefs=await this.fieldService.loadFields(resModel);return new Page(resModel,this.filter(fieldDefs,path),{isDebugMode:this.props.isDebugMode,});}
const{isInvalid,modelsInfo,names}=await this.fieldService.loadPath(resModel,path);switch(isInvalid){case"model":throw new Error(`Invalid model name: ${resModel}`);case"path":{const{resModel,fieldDefs}=modelsInfo[0];return new Page(resModel,this.filter(fieldDefs,path),{selectedName:path,isDebugMode:this.props.isDebugMode,});}
default:{let page=null;for(let index=0;index<names.length;index++){const name=names[index];const{resModel,fieldDefs}=modelsInfo[index];page=new Page(resModel,this.filter(fieldDefs,path),{previousPage:page,selectedName:name,isDebugMode:this.props.isDebugMode,});}
return page;}}}
openPage(page){this.state.page=page;this.state.page.searchFields();this.props.update(page.path);}
searchFields(query){this.state.page.searchFields(query);}
selectField(field){if(field.type==="properties"){return this.followRelation(field);}
this.keepLast.add(Promise.resolve());this.state.page.selectedName=field.name;this.props.update(this.state.page.path,field);this.props.close(true);}
onDebugInputKeydown(ev){switch(ev.key){case"Enter":{ev.preventDefault();ev.stopPropagation();this.loadNewPath(ev.currentTarget.value);break;}}}
async onInputKeydown(ev){const{page}=this.state;switch(ev.key){case"ArrowUp":{if(ev.target.selectionStart===0){page.focus("previous");}
break;}
case"ArrowDown":{if(ev.target.selectionStart===page.query.length){page.focus("next");}
break;}
case"ArrowLeft":{if(ev.target.selectionStart===0&&page.previousPage){this.goToPreviousPage();}
break;}
case"ArrowRight":{if(ev.target.selectionStart===page.query.length){const focusedFieldName=this.state.page.focusedFieldName;if(focusedFieldName){const fieldDef=this.state.page.fieldDefs[focusedFieldName];if(fieldDef.relation||fieldDef.type==="properties"){this.followRelation(fieldDef);}}}
break;}
case"Enter":{const focusedFieldName=this.state.page.focusedFieldName;if(focusedFieldName){const fieldDef=this.state.page.fieldDefs[focusedFieldName];this.selectField(fieldDef);}else{ev.preventDefault();ev.stopPropagation();}
break;}
case"Escape":{ev.preventDefault();ev.stopPropagation();this.props.close();break;}}}}
return __exports;});;

/* /web/static/src/core/model_field_selector/utils.js */
odoo.define('@web/core/model_field_selector/utils',['@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");function makeString(value){return String(value??"-");}
__exports.useLoadFieldInfo=useLoadFieldInfo;function useLoadFieldInfo(fieldService){fieldService||=useService("field");return async(resModel,path)=>{if(typeof path!=="string"||!path){return{resModel,fieldDef:null};}
const{isInvalid,names,modelsInfo}=await fieldService.loadPath(resModel,path);if(isInvalid){return{resModel,fieldDef:null};}
const name=names.at(-1);const modelInfo=modelsInfo.at(-1);return{resModel:modelInfo.resModel,fieldDef:modelInfo.fieldDefs[name]};};}
__exports.useLoadPathDescription=useLoadPathDescription;function useLoadPathDescription(fieldService){fieldService||=useService("field");return async(resModel,path,allowEmpty)=>{if([0,1].includes(path)){return{isInvalid:false,displayNames:[makeString(path)]};}
if(allowEmpty&&!path){return{isInvalid:false,displayNames:[]};}
if(typeof path!=="string"||!path){return{isInvalid:true,displayNames:[makeString()]};}
const{isInvalid,modelsInfo,names}=await fieldService.loadPath(resModel,path);const result={isInvalid:!!isInvalid,displayNames:[]};if(!isInvalid){const lastName=names.at(-1);const lastFieldDef=modelsInfo.at(-1).fieldDefs[lastName];if(["properties","properties_definition"].includes(lastFieldDef.type)){result.isInvalid=true;}}
for(let index=0;index<names.length;index++){const name=names[index];const fieldDef=modelsInfo[index]?.fieldDefs[name];result.displayNames.push(fieldDef?.string||makeString(name));}
return result;};}
return __exports;});;

/* /web/static/src/core/model_selector/model_selector.js */
odoo.define('@web/core/model_selector/model_selector',['@web/core/autocomplete/autocomplete','@web/core/utils/hooks','@web/core/utils/search','@web/core/l10n/translation','@odoo/owl'],function(require){'use strict';let __exports={};const{AutoComplete}=require("@web/core/autocomplete/autocomplete");const{useService}=require("@web/core/utils/hooks");const{fuzzyLookup}=require("@web/core/utils/search");const{_t}=require("@web/core/l10n/translation");const{Component,onWillStart}=require("@odoo/owl");const ModelSelector=__exports.ModelSelector=class ModelSelector extends Component{static template="web.ModelSelector";static components={AutoComplete};static props={onModelSelected:Function,id:{type:String,optional:true},value:{type:String,optional:true},models:{type:Array,optional:true},};setup(){this.orm=useService("orm");onWillStart(async()=>{if(!this.props.models){this.models=await this._fetchAvailableModels();}else{this.models=await this.orm.call("ir.model","display_name_for",[this.props.models,]);}
this.models=this.models.map((record)=>({label:record.display_name,technical:record.model,classList:{[`o_model_selector_${record.model}`]:1,},}));});}
get sources(){return[this.optionsSource];}
get optionsSource(){return{placeholder:_t("Loading..."),options:this.loadOptionsSource.bind(this),};}
onSelect(option){this.props.onModelSelected({label:option.label,technical:option.technical,});}
filterModels(name){if(!name){const visibleModels=this.models.slice(0,8);if(this.models.length-visibleModels.length>0){visibleModels.push({label:_t("Start typing..."),unselectable:true,classList:"o_m2o_start_typing",});}
return visibleModels;}
return fuzzyLookup(name,this.models,(model)=>model.technical+model.label);}
loadOptionsSource(request){const options=this.filterModels(request);if(!options.length){options.push({label:_t("No records"),classList:"o_m2o_no_result",unselectable:true,});}
return options;}
async _fetchAvailableModels(){const result=await this.orm.call("ir.model","get_available_models");return result||[];}}
return __exports;});;

/* /web/static/src/core/name_service.js */
odoo.define('@web/core/name_service',['@web/core/registry','@web/core/utils/arrays','@web/core/utils/concurrency'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{unique,zip}=require("@web/core/utils/arrays");const{Deferred}=require("@web/core/utils/concurrency");const ERROR_INACCESSIBLE_OR_MISSING=__exports.ERROR_INACCESSIBLE_OR_MISSING=Symbol("INACCESSIBLE OR MISSING RECORD ID");function isId(val){return Number.isInteger(val)&&val>=1;}
const nameService=__exports.nameService={dependencies:["orm"],async:["loadDisplayNames"],start(env,{orm}){let cache={};const batches={};function clearCache(){cache={};}
env.bus.addEventListener("ACTION_MANAGER:UPDATE",clearCache);function getMapping(resModel){if(!cache[resModel]){cache[resModel]={};}
return cache[resModel];}
function addDisplayNames(resModel,displayNames){const mapping=getMapping(resModel);for(const resId in displayNames){mapping[resId]=new Deferred();mapping[resId].resolve(displayNames[resId]);}}
async function loadDisplayNames(resModel,resIds){const mapping=getMapping(resModel);const proms=[];const resIdsToFetch=[];for(const resId of unique(resIds)){if(!isId(resId)){throw new Error(`Invalid ID: ${resId}`);}
if(!(resId in mapping)){mapping[resId]=new Deferred();resIdsToFetch.push(resId);}
proms.push(mapping[resId]);}
if(resIdsToFetch.length){if(batches[resModel]){batches[resModel].push(...resIdsToFetch);}else{batches[resModel]=resIdsToFetch;await Promise.resolve();const idsInBatch=unique(batches[resModel]);delete batches[resModel];const specification={display_name:{}};orm.silent.webSearchRead(resModel,[["id","in",idsInBatch]],{specification}).then(({records})=>{const displayNames=Object.fromEntries(records.map((rec)=>[rec.id,rec.display_name]));for(const resId of idsInBatch){mapping[resId].resolve(resId in displayNames?displayNames[resId]:ERROR_INACCESSIBLE_OR_MISSING);}});}}
const names=await Promise.all(proms);return Object.fromEntries(zip(resIds,names));}
return{addDisplayNames,clearCache,loadDisplayNames};},};registry.category("services").add("name",nameService);return __exports;});;

/* /web/static/src/core/navigation/navigation.js */
odoo.define('@web/core/navigation/navigation',['@odoo/owl','@web/core/utils/hooks','@web/core/utils/scrolling','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{useEffect,useRef}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{scrollTo}=require("@web/core/utils/scrolling");const{debounce,throttleForAnimation}=require("@web/core/utils/timing");const ACTIVE_ELEMENT_CLASS="focus";const throttledElementFocus=throttleForAnimation((el)=>el?.focus());function focusElement(el){throttledElementFocus.cancel();throttledElementFocus(el);}
class NavigationItem{constructor({index,el,setActiveItem,options}){this.index=index;this.options=options;this.setActiveItem=setActiveItem;this.el=el;if(options.shouldFocusChildInput){const subInput=el.querySelector(":scope input, :scope button, :scope textarea");this.target=subInput||el;}else{this.target=el;}
const focus=()=>this.focus(true);const onMouseEnter=(ev)=>this.onMouseEnter(ev);this.target.addEventListener("focus",focus);this.target.addEventListener("mouseenter",onMouseEnter);this.removeListeners=()=>{this.target.removeEventListener("focus",focus);this.target.removeEventListener("mouseenter",onMouseEnter);};}
select(){this.focus();this.target.click();}
focus(skipRealFocus=false){scrollTo(this.target);this.setActiveItem(this.index,this);this.target.classList.add(ACTIVE_ELEMENT_CLASS);if(!skipRealFocus&&!this.options.virtualFocus){focusElement(this.target);}}
defocus(){this.target.classList.remove(ACTIVE_ELEMENT_CLASS);}
onMouseEnter(){this.focus(true);this.options.onMouseEnter?.(this);}}
class Navigator{constructor(containerRef,options,hotkeyService){this.enabled=false;this.containerRef=containerRef;const focusAt=(increment)=>{const isFocused=this.activeItem?.el.isConnected;const index=this.currentActiveIndex+increment;if(isFocused&&index>=0){return this.items[index%this.items.length]?.focus();}else if(!isFocused&&increment>=0){return this.items[0]?.focus();}else{return this.items.at(-1)?.focus();}};this.options={shouldFocusChildInput:true,virtualFocus:false,itemsSelector:":scope .o-navigable",focusInitialElementOnDisabled:()=>true,...options,hotkeys:{home:(index,items)=>items[0]?.focus(),end:(index,items)=>items.at(-1)?.focus(),tab:()=>focusAt(+1),"shift+tab":()=>focusAt(-1),arrowdown:()=>focusAt(+1),arrowup:()=>focusAt(-1),enter:(index,items)=>{const item=items[index]||items[0];item?.select();},...(options?.hotkeys||{}),},};this.items=[];this.activeItem=undefined;this.currentActiveIndex=-1;this.initialFocusElement=undefined;this.debouncedUpdate=debounce(()=>this.update(),100);this.hotkeyRemoves=[];this.hotkeyService=hotkeyService;this.allowedInEditableHotkeys=["arrowup","arrowdown","enter","tab","shift+tab"];}
enable(){if(!this.containerRef.el||this.targetObserver){return;}
for(const[hotkey,callback]of Object.entries(this.options.hotkeys)){if(!callback){continue;}
this.hotkeyRemoves.push(this.hotkeyService.add(hotkey,()=>callback(this.currentActiveIndex,this.items),{allowRepeat:true,bypassEditableProtection:this.allowedInEditableHotkeys.includes(hotkey),}));}
this.targetObserver=new MutationObserver(()=>this.debouncedUpdate());this.targetObserver.observe(this.containerRef.el,{childList:true,subtree:true,});this.initialFocusElement=document.activeElement;this.currentActiveIndex=-1;this.update();if(this.options.onEnabled){this.options.onEnabled(this.items);}else if(this.items.length>0){this.items[0]?.focus();}
this.enabled=true;}
disable(){if(!this.enabled){return;}
if(this.targetObserver){this.targetObserver.disconnect();this.targetObserver=undefined;}
this.clearItems();for(const removeHotkey of this.hotkeyRemoves){removeHotkey();}
this.hotkeyRemoves=[];if(this.options.focusInitialElementOnDisabled()){focusElement(this.initialFocusElement);}
this.enabled=false;}
update(){if(!this.containerRef.el){return;}
const oldItemsLength=this.items.length;this.clearItems();const elements=[...this.containerRef.el.querySelectorAll(this.options.itemsSelector)];this.items=elements.map((el,index)=>{return new NavigationItem({index,el,options:this.options,setActiveItem:(index,el)=>this.setActiveItem(index,el),});});if(oldItemsLength!=this.items.length&&this.currentActiveIndex>=this.items.length){this.items.at(-1)?.focus();}}
setActiveItem(index,item){if(this.activeItem){this.activeItem.el.classList.remove(ACTIVE_ELEMENT_CLASS);}
this.activeItem=item;this.currentActiveIndex=index;}
clearItems(){for(const item of this.items){item.removeListeners();}
this.items=[];}}
__exports.useNavigation=useNavigation;function useNavigation(containerRef,options={}){const hotkeyService=useService("hotkey");containerRef=typeof containerRef==="string"?useRef(containerRef):containerRef;const navigator=new Navigator(containerRef,options,hotkeyService);useEffect((container)=>{if(container){navigator.enable();}else if(navigator){navigator.disable();}},()=>[containerRef.el]);return{enable:()=>navigator.enable(),disable:()=>navigator.disable(),};}
return __exports;});;

/* /web/static/src/core/network/download.js */
odoo.define('@web/core/network/download',['@web/core/l10n/translation','@web/core/network/rpc','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{makeErrorFromResponse,ConnectionLostError}=require("@web/core/network/rpc");const{browser}=require("@web/core/browser/browser");const HEX_ESCAPE_REPLACE_REGEXP=/%([0-9A-Fa-f]{2})/g;const NON_LATIN1_REGEXP=/[^\x20-\x7e\xa0-\xff]/g;const QESC_REGEXP=/\\([\u0000-\u007f])/g;const PARAM_REGEXP=/;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g;const EXT_VALUE_REGEXP=/^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/;const DISPOSITION_TYPE_REGEXP=/^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*(?:$|;)/;function decodefield(str){const match=EXT_VALUE_REGEXP.exec(str);if(!match){throw new TypeError("invalid extended field value");}
const charset=match[1].toLowerCase();const encoded=match[2];switch(charset){case"iso-8859-1":return encoded.replace(HEX_ESCAPE_REPLACE_REGEXP,pdecode).replace(NON_LATIN1_REGEXP,"?");case"utf-8":return decodeURIComponent(encoded);default:throw new TypeError("unsupported charset in extended field");}}
__exports.parse=parse;function parse(string){if(!string||typeof string!=="string"){throw new TypeError("argument string is required");}
let match=DISPOSITION_TYPE_REGEXP.exec(string);if(!match){throw new TypeError("invalid type format");}
let index=match[0].length;const type=match[1].toLowerCase();let key;const names=[];const params={};let value;index=PARAM_REGEXP.lastIndex=match[0].substr(-1)===";"?index-1:index;while((match=PARAM_REGEXP.exec(string))){if(match.index!==index){throw new TypeError("invalid parameter format");}
index+=match[0].length;key=match[1].toLowerCase();value=match[2];if(names.indexOf(key)!==-1){throw new TypeError("invalid duplicate parameter");}
names.push(key);if(key.indexOf("*")+1===key.length){key=key.slice(0,-1);value=decodefield(value);params[key]=value;continue;}
if(typeof params[key]==="string"){continue;}
if(value[0]==='"'){value=value.substr(1,value.length-2).replace(QESC_REGEXP,"$1");}
params[key]=value;}
if(index!==-1&&index!==string.length){throw new TypeError("invalid parameter format");}
return new ContentDisposition(type,params);}
function pdecode(str,hex){return String.fromCharCode(parseInt(hex,16));}
function ContentDisposition(type,parameters){this.type=type;this.parameters=parameters;}
function _download(data,filename,mimetype){let self=window,defaultMime="application/octet-stream",mimeType=mimetype||defaultMime,payload=data,url=!filename&&!mimetype&&payload,anchor=document.createElement("a"),toString=function(a){return String(a);},myBlob=self.Blob||self.MozBlob||self.WebKitBlob||toString,fileName=filename||"download",blob,reader;myBlob=myBlob.call?myBlob.bind(self):Blob;if(String(this)==="true"){payload=[payload,mimeType];mimeType=payload[0];payload=payload[1];}
if(url&&url.length<2048){fileName=url.split("/").pop().split("?")[0];anchor.href=url;if(anchor.href.indexOf(url)!==-1){return new Promise((resolve,reject)=>{let xhr=new browser.XMLHttpRequest();xhr.open("GET",url,true);configureBlobDownloadXHR(xhr,{onSuccess:resolve,onFailure:reject,url});xhr.send();});}}
if(/^data:[\w+\-]+\/[\w+\-]+[,;]/.test(payload)){if(payload.length>1024*1024*1.999&&myBlob!==toString){payload=dataUrlToBlob(payload);mimeType=payload.type||defaultMime;}else{return navigator.msSaveBlob?navigator.msSaveBlob(dataUrlToBlob(payload),fileName):saver(payload);}}
blob=payload instanceof myBlob?payload:new myBlob([payload],{type:mimeType});function dataUrlToBlob(strUrl){let parts=strUrl.split(/[:;,]/),type=parts[1],decoder=parts[2]==="base64"?atob:decodeURIComponent,binData=decoder(parts.pop()),mx=binData.length,i=0,uiArr=new Uint8Array(mx);for(i;i<mx;++i){uiArr[i]=binData.charCodeAt(i);}
return new myBlob([uiArr],{type});}
function saver(url,winMode){if("download"in anchor){anchor.href=url;anchor.setAttribute("download",fileName);anchor.className="download-js-link";anchor.innerText=_t("downloading...");anchor.style.display="none";anchor.target="_blank";document.body.appendChild(anchor);setTimeout(()=>{anchor.click();document.body.removeChild(anchor);if(winMode===true){setTimeout(()=>{self.URL.revokeObjectURL(anchor.href);},250);}},66);return true;}
if(/(Version)\/(\d+)\.(\d+)(?:\.(\d+))?.*Safari\//.test(navigator.userAgent)){url=url.replace(/^data:([\w\/\-+]+)/,defaultMime);if(!window.open(url)){if(confirm("Displaying New Document\n\nUse Save As... to download, then click back to return to this page.")){location.href=url;}}
return true;}
let f=document.createElement("iframe");document.body.appendChild(f);if(!winMode){url=`data:${url.replace(/^data:([\w\/\-+]+)/, defaultMime)}`;}
f.src=url;setTimeout(()=>{document.body.removeChild(f);},333);}
if(navigator.msSaveBlob){return navigator.msSaveBlob(blob,fileName);}
if(self.URL){saver(self.URL.createObjectURL(blob),true);}else{if(typeof blob==="string"||blob.constructor===toString){try{return saver(`data:${mimeType};base64,${self.btoa(blob)}`);}catch{return saver(`data:${mimeType},${encodeURIComponent(blob)}`);}}
reader=new FileReader();reader.onload=function(){saver(this.result);};reader.readAsDataURL(blob);}
return true;}
__exports.downloadFile=downloadFile;function downloadFile(data,filename,mimetype){return downloadFile._download(data,filename,mimetype);}
downloadFile._download=_download;__exports.download=download;function download(options){return download._download(options);}
download._download=(options)=>{return new Promise((resolve,reject)=>{const xhr=new browser.XMLHttpRequest();let data;if(Object.prototype.hasOwnProperty.call(options,"form")){xhr.open(options.form.method,options.form.action);data=new FormData(options.form);}else{xhr.open("POST",options.url);data=new FormData();Object.entries(options.data).forEach((entry)=>{const[key,value]=entry;data.append(key,value);});}
data.append("token","dummy-because-api-expects-one");if(odoo.csrf_token){data.append("csrf_token",odoo.csrf_token);}
configureBlobDownloadXHR(xhr,{onSuccess:resolve,onFailure:reject,url:options.url,});xhr.send(data);});};__exports.configureBlobDownloadXHR=configureBlobDownloadXHR;function configureBlobDownloadXHR(xhr,{onSuccess=()=>{},onFailure=()=>{},url}={}){xhr.responseType="blob";xhr.onload=()=>{const mimetype=xhr.response.type;const header=(xhr.getResponseHeader("Content-Disposition")||"").replace(/;$/,"");const filename=header?parse(header).parameters.filename:null;if(xhr.status===200&&(mimetype!=="text/html"||filename)){_download(xhr.response,filename,mimetype);onSuccess(filename);}else if(xhr.status===502){onFailure(new ConnectionLostError(url));}else{const decoder=new FileReader();decoder.onload=()=>{const contents=decoder.result;const doc=new DOMParser().parseFromString(contents,"text/html");const nodes=doc.body.children.length===0?[doc.body]:doc.body.children;let error;try{const node=nodes[1]||nodes[0];error=JSON.parse(node.textContent);}catch{error={message:"Arbitrary Uncaught Python Exception",data:{debug:`${xhr.status}`+`\n`+`${nodes.length > 0 ? nodes[0].textContent : ""}
                                ${nodes.length > 1 ? nodes[1].textContent : ""}`,},};}
error=makeErrorFromResponse(error);onFailure(error);};decoder.readAsText(xhr.response);}};xhr.onerror=()=>{onFailure(new ConnectionLostError(url));};}
return __exports;});;

/* /web/static/src/core/network/http_service.js */
odoo.define('@web/core/network/http_service',['@web/core/browser/browser','@web/core/registry'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");function checkResponseStatus(response){if(response.status===502){throw new Error("Failed to fetch");}}
__exports.get=get;async function get(route,readMethod="json"){const response=await browser.fetch(route,{method:"GET"});checkResponseStatus(response);return response[readMethod]();}
__exports.post=post;async function post(route,params={},readMethod="json"){let formData=params;if(!(formData instanceof FormData)){formData=new FormData();for(const key in params){const value=params[key];if(Array.isArray(value)&&value.length){for(const val of value){formData.append(key,val);}}else{formData.append(key,value);}}}
const response=await browser.fetch(route,{body:formData,method:"POST",});checkResponseStatus(response);return response[readMethod]();}
const httpService=__exports.httpService={start(){return{get,post};},};registry.category("services").add("http",httpService);return __exports;});;

/* /web/static/src/core/network/rpc.js */
odoo.define('@web/core/network/rpc',['@odoo/owl','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{EventBus}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const rpcBus=__exports.rpcBus=new EventBus();const RPCError=__exports.RPCError=class RPCError extends Error{constructor(){super(...arguments);this.name="RPC_ERROR";this.type="server";this.code=null;this.data=null;this.exceptionName=null;this.subType=null;}}
const ConnectionLostError=__exports.ConnectionLostError=class ConnectionLostError extends Error{constructor(url,...args){super(`Connection to "${url}" couldn't be established or was interrupted`,...args);this.url=url;}}
const ConnectionAbortedError=__exports.ConnectionAbortedError=class ConnectionAbortedError extends Error{}
__exports.makeErrorFromResponse=makeErrorFromResponse;function makeErrorFromResponse(response){const{code,data:errorData,message,type:subType}=response;const error=new RPCError();error.exceptionName=errorData?.name;error.subType=subType;error.data=errorData;error.message=message;error.code=code;return error;}
let rpcId=0;__exports.rpc=rpc;function rpc(url,params={},settings={}){return rpc._rpc(url,params,settings);}
rpc._rpc=function(url,params,settings){const XHR=browser.XMLHttpRequest;const data={id:rpcId++,jsonrpc:"2.0",method:"call",params:params,};const request=settings.xhr||new XHR();let rejectFn;const promise=new Promise((resolve,reject)=>{rejectFn=reject;rpcBus.trigger("RPC:REQUEST",{data,url,settings});request.addEventListener("load",()=>{if(request.status===502){const error=new ConnectionLostError(url);rpcBus.trigger("RPC:RESPONSE",{data,settings,error});reject(error);return;}
let params;try{params=JSON.parse(request.response);}catch{const error=new ConnectionLostError(url);rpcBus.trigger("RPC:RESPONSE",{data,settings,error});return reject(error);}
const{error:responseError,result:responseResult}=params;if(!params.error){rpcBus.trigger("RPC:RESPONSE",{data,settings,result:params.result});return resolve(responseResult);}
const error=makeErrorFromResponse(responseError);error.id=data.id;error.model=data.params.model;rpcBus.trigger("RPC:RESPONSE",{data,settings,error});reject(error);});request.addEventListener("error",()=>{const error=new ConnectionLostError(url);rpcBus.trigger("RPC:RESPONSE",{data,settings,error});reject(error);});request.open("POST",url);const headers=settings.headers||{};headers["Content-Type"]="application/json";for(const[header,value]of Object.entries(headers)){request.setRequestHeader(header,value);}
request.send(JSON.stringify(data));});promise.abort=function(rejectError=true){if(request.abort){request.abort();}
const error=new ConnectionAbortedError("XmlHttpRequestError abort");rpcBus.trigger("RPC:RESPONSE",{data,settings,error});if(rejectError){rejectFn(error);}};return promise;};return __exports;});;

/* /web/static/src/core/notebook/notebook.js */
odoo.define('@web/core/notebook/notebook',['@web/core/utils/scrolling','@odoo/owl','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{scrollTo}=require("@web/core/utils/scrolling");const{Component,onWillUpdateProps,useEffect,useExternalListener,useRef,useState,}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const Notebook=__exports.Notebook=class Notebook extends Component{static template="web.Notebook";static defaultProps={className:"",orientation:"horizontal",onPageUpdate:()=>{},};static props={slots:{type:Object,optional:true},pages:{type:Object,optional:true},class:{optional:true},className:{type:String,optional:true},anchors:{type:Object,optional:true},defaultPage:{type:String,optional:true},orientation:{type:String,optional:true},icons:{type:Object,optional:true},onPageUpdate:{type:Function,optional:true},};setup(){this.activePane=useRef("activePane");this.anchorTarget=null;this.pages=this.computePages(this.props);this.state=useState({currentPage:null});this.state.currentPage=this.computeActivePage(this.props.defaultPage,true);useExternalListener(browser,"click",this.onAnchorClicked);useEffect(()=>{this.props.onPageUpdate(this.state.currentPage);if(this.anchorTarget){const matchingEl=this.activePane.el.querySelector(`#${this.anchorTarget}`);scrollTo(matchingEl,{isAnchor:true});this.anchorTarget=null;}
this.activePane.el?.classList.add("show");},()=>[this.state.currentPage]);onWillUpdateProps((nextProps)=>{const activateDefault=this.props.defaultPage!==nextProps.defaultPage||!this.defaultVisible;this.pages=this.computePages(nextProps);this.state.currentPage=this.computeActivePage(nextProps.defaultPage,activateDefault);});}
get navItems(){return this.pages.filter((e)=>e[1].isVisible);}
get page(){const page=this.pages.find((e)=>e[0]===this.state.currentPage)[1];return page.Component&&page;}
onAnchorClicked(ev){if(!this.props.anchors){return;}
const href=ev.target.closest("a")?.getAttribute("href");if(!href){return;}
const id=href.substring(1);if(this.props.anchors[id]){if(this.state.currentPage!==this.props.anchors[id].target){ev.preventDefault();this.anchorTarget=id;this.state.currentPage=this.props.anchors[id].target;}}}
activatePage(pageIndex){if(!this.disabledPages.includes(pageIndex)&&this.state.currentPage!==pageIndex){this.activePane.el?.classList.remove("show");this.state.currentPage=pageIndex;}}
computePages(props){if(!props.slots&&!props.pages){return[];}
if(props.pages){for(const page of props.pages){page.isVisible=true;}}
this.disabledPages=[];const pages=[];const pagesWithIndex=[];for(const[k,v]of Object.entries({...props.slots,...props.pages})){const id=v.id||k;if(v.index){pagesWithIndex.push([id,v]);}else{pages.push([id,v]);}
if(v.isDisabled){this.disabledPages.push(k);}}
for(const page of pagesWithIndex){pages.splice(page[1].index,0,page);}
return pages;}
computeActivePage(defaultPage,activateDefault){if(!this.pages.length){return null;}
const pages=this.pages.filter((e)=>e[1].isVisible).map((e)=>e[0]);if(defaultPage){if(!pages.includes(defaultPage)){this.defaultVisible=false;}else{this.defaultVisible=true;if(activateDefault){return defaultPage;}}}
const current=this.state.currentPage;if(!current||(current&&!pages.includes(current))){return pages[0];}
return current;}}
return __exports;});;

/* /web/static/src/core/notifications/notification.js */
odoo.define('@web/core/notifications/notification',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const Notification=__exports.Notification=class Notification extends Component{static template="web.NotificationWowl";static props={message:{validate:(m)=>{return(typeof m==="string"||(typeof m==="object"&&typeof m.toString==="function"));},},title:{type:[String,Boolean,{toString:Function}],optional:true},type:{type:String,optional:true,validate:(t)=>["warning","danger","success","info"].includes(t),},className:{type:String,optional:true},buttons:{type:Array,element:{type:Object,shape:{name:{type:String},icon:{type:String,optional:true},primary:{type:Boolean,optional:true},onClick:Function,},},optional:true,},close:{type:Function},refresh:{type:Function},freeze:{type:Function},};static defaultProps={buttons:[],className:"",type:"warning",};}
return __exports;});;

/* /web/static/src/core/notifications/notification_container.js */
odoo.define('@web/core/notifications/notification_container',['@web/core/notifications/notification','@web/core/transition','@odoo/owl'],function(require){'use strict';let __exports={};const{Notification}=require("@web/core/notifications/notification");const{Transition}=require("@web/core/transition");const{Component,xml,useState}=require("@odoo/owl");const NotificationContainer=__exports.NotificationContainer=class NotificationContainer extends Component{static props={notifications:Object,};static template=xml`
        <div class="o_notification_manager">
            <t t-foreach="notifications" t-as="notification" t-key="notification">
                <Transition leaveDuration="0" immediate="true" name="'o_notification_fade'" t-slot-scope="transition">
                    <Notification t-props="notification_value.props" className="(notification_value.props.className || '') + ' ' + transition.className"/>
                </Transition>
            </t>
        </div>`;static components={Notification,Transition};setup(){this.notifications=useState(this.props.notifications);}}
return __exports;});;

/* /web/static/src/core/notifications/notification_service.js */
odoo.define('@web/core/notifications/notification_service',['@web/core/browser/browser','@web/core/registry','@web/core/notifications/notification_container','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{NotificationContainer}=require("@web/core/notifications/notification_container");const{reactive}=require("@odoo/owl");const AUTOCLOSE_DELAY=4000;const notificationService=__exports.notificationService={notificationContainer:NotificationContainer,start(){let notifId=0;const notifications=reactive({});registry.category("main_components").add(this.notificationContainer.name,{Component:this.notificationContainer,props:{notifications},},{sequence:100});function add(message,options={}){const id=++notifId;const closeFn=()=>close(id);const props=Object.assign({},options,{message,close:closeFn});const autocloseDelay=options.autocloseDelay??AUTOCLOSE_DELAY;const sticky=props.sticky;delete props.sticky;delete props.onClose;delete props.autocloseDelay;let closeTimeout;const refresh=sticky?()=>{}:()=>{closeTimeout=browser.setTimeout(closeFn,autocloseDelay);};const freeze=sticky?()=>{}:()=>{browser.clearTimeout(closeTimeout);};props.refresh=refreshAll;props.freeze=freezeAll;const notification={id,props,onClose:options.onClose,refresh,freeze,};notifications[id]=notification;if(!sticky){closeTimeout=browser.setTimeout(closeFn,autocloseDelay);}
return closeFn;}
function refreshAll(){for(const id in notifications){notifications[id].refresh();}}
function freezeAll(){for(const id in notifications){notifications[id].freeze();}}
function close(id){if(notifications[id]){const notification=notifications[id];if(notification.onClose){notification.onClose();}
delete notifications[id];}}
return{add};},};registry.category("services").add("notification",notificationService);return __exports;});;

/* /web/static/src/core/orm_service.js */
odoo.define('@web/core/orm_service',['@web/core/registry','@web/core/network/rpc','@web/core/user'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{rpc}=require("@web/core/network/rpc");const{user}=require("@web/core/user");const x2ManyCommands=__exports.x2ManyCommands={CREATE:0,create(virtualID,values){delete values.id;return[x2ManyCommands.CREATE,virtualID||false,values];},UPDATE:1,update(id,values){delete values.id;return[x2ManyCommands.UPDATE,id,values];},DELETE:2,delete(id){return[x2ManyCommands.DELETE,id,false];},UNLINK:3,unlink(id){return[x2ManyCommands.UNLINK,id,false];},LINK:4,link(id){return[x2ManyCommands.LINK,id,false];},CLEAR:5,clear(){return[x2ManyCommands.CLEAR,false,false];},SET:6,set(ids){return[x2ManyCommands.SET,false,ids];},};function validateModel(value){if(typeof value!=="string"||value.length===0){throw new Error(`Invalid model name: ${value}`);}}
function validatePrimitiveList(name,type,value){if(!Array.isArray(value)||value.some((val)=>typeof val!==type)){throw new Error(`Invalid ${name} list: ${value}`);}}
function validateObject(name,obj){if(typeof obj!=="object"||obj===null||Array.isArray(obj)){throw new Error(`${name} should be an object`);}}
function validateArray(name,array){if(!Array.isArray(array)){throw new Error(`${name} should be an array`);}}
const UPDATE_METHODS=__exports.UPDATE_METHODS=["unlink","create","write","web_save","action_archive","action_unarchive",];const ORM=__exports.ORM=class ORM{constructor(){this.rpc=rpc;this._silent=false;}
get silent(){return Object.assign(Object.create(this),{_silent:true});}
call(model,method,args=[],kwargs={}){validateModel(model);const url=`/web/dataset/call_kw/${model}/${method}`;const fullContext=Object.assign({},user.context,kwargs.context||{});const fullKwargs=Object.assign({},kwargs,{context:fullContext});const params={model,method,args,kwargs:fullKwargs,};return this.rpc(url,params,{silent:this._silent});}
create(model,records,kwargs={}){validateArray("records",records);for(const record of records){validateObject("record",record);}
return this.call(model,"create",[records],kwargs);}
read(model,ids,fields,kwargs={}){validatePrimitiveList("ids","number",ids);if(fields){validatePrimitiveList("fields","string",fields);}
if(!ids.length){return Promise.resolve([]);}
return this.call(model,"read",[ids,fields],kwargs);}
readGroup(model,domain,fields,groupby,kwargs={}){validateArray("domain",domain);validatePrimitiveList("fields","string",fields);validatePrimitiveList("groupby","string",groupby);groupby=[...new Set(groupby)];return this.call(model,"read_group",[],{...kwargs,domain,fields,groupby});}
search(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"search",[domain],kwargs);}
searchRead(model,domain,fields,kwargs={}){validateArray("domain",domain);if(fields){validatePrimitiveList("fields","string",fields);}
return this.call(model,"search_read",[],{...kwargs,domain,fields});}
searchCount(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"search_count",[domain],kwargs);}
unlink(model,ids,kwargs={}){validatePrimitiveList("ids","number",ids);if(!ids.length){return Promise.resolve(true);}
return this.call(model,"unlink",[ids],kwargs);}
webReadGroup(model,domain,fields,groupby,kwargs={}){validateArray("domain",domain);validatePrimitiveList("fields","string",fields);validatePrimitiveList("groupby","string",groupby);return this.call(model,"web_read_group",[],{...kwargs,groupby,domain,fields,});}
webRead(model,ids,kwargs={}){validatePrimitiveList("ids","number",ids);return this.call(model,"web_read",[ids],kwargs);}
webSearchRead(model,domain,kwargs={}){validateArray("domain",domain);return this.call(model,"web_search_read",[],{...kwargs,domain});}
write(model,ids,data,kwargs={}){validatePrimitiveList("ids","number",ids);validateObject("data",data);return this.call(model,"write",[ids,data],kwargs);}
webSave(model,ids,data,kwargs={}){validatePrimitiveList("ids","number",ids);validateObject("data",data);return this.call(model,"web_save",[ids,data],kwargs);}}
const ormService=__exports.ormService={async:["call","create","nameGet","read","readGroup","search","searchRead","unlink","webSearchRead","write",],start(){return new ORM();},};registry.category("services").add("orm",ormService);return __exports;});;

/* /web/static/src/core/overlay/overlay_container.js */
odoo.define('@web/core/overlay/overlay_container',['@odoo/owl','@web/core/utils/arrays','@web/core/utils/components'],function(require){'use strict';let __exports={};const{Component,onWillDestroy,useChildSubEnv,useEffect,useRef,useState}=require("@odoo/owl");const{sortBy}=require("@web/core/utils/arrays");const{ErrorHandler}=require("@web/core/utils/components");const OVERLAY_ITEMS=[];const OVERLAY_SYMBOL=__exports.OVERLAY_SYMBOL=Symbol("Overlay");class OverlayItem extends Component{static template="web.OverlayContainer.Item";static components={};static props={component:{type:Function},props:{type:Object},env:{type:Object,optional:true},};setup(){this.rootRef=useRef("rootRef");OVERLAY_ITEMS.push(this);onWillDestroy(()=>{const index=OVERLAY_ITEMS.indexOf(this);OVERLAY_ITEMS.splice(index,1);});if(this.props.env){this.__owl__.childEnv=this.props.env;}
useChildSubEnv({[OVERLAY_SYMBOL]:{contains:(target)=>this.contains(target),},});}
get subOverlays(){return OVERLAY_ITEMS.slice(OVERLAY_ITEMS.indexOf(this));}
contains(target){return(this.rootRef.el?.contains(target)||this.subOverlays.some((oi)=>oi.rootRef.el?.contains(target)));}}
const OverlayContainer=__exports.OverlayContainer=class OverlayContainer extends Component{static template="web.OverlayContainer";static components={ErrorHandler,OverlayItem};static props={overlays:Object};setup(){this.root=useRef("root");this.state=useState({rootEl:null});useEffect(()=>{this.state.rootEl=this.root.el;},()=>[this.root.el]);}
get sortedOverlays(){return sortBy(Object.values(this.props.overlays),(overlay)=>overlay.sequence);}
isVisible(overlay){return overlay.rootId===this.state.rootEl?.getRootNode()?.host?.id;}
handleError(overlay,error){overlay.remove();Promise.resolve().then(()=>{throw error;});}}
return __exports;});;

/* /web/static/src/core/overlay/overlay_service.js */
odoo.define('@web/core/overlay/overlay_service',['@odoo/owl','@web/core/registry','@web/core/overlay/overlay_container'],function(require){'use strict';let __exports={};const{markRaw,reactive}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{OverlayContainer}=require("@web/core/overlay/overlay_container");const mainComponents=registry.category("main_components");const services=registry.category("services");const overlayService=__exports.overlayService={start(){let nextId=0;const overlays=reactive({});mainComponents.add("OverlayContainer",{Component:OverlayContainer,props:{overlays},});const remove=(id,onRemove=()=>{})=>{if(id in overlays){onRemove();delete overlays[id];}};const add=(component,props,options={})=>{const id=++nextId;const removeCurrentOverlay=()=>remove(id,options.onRemove);overlays[id]={id,component,env:options.env&&markRaw(options.env),props,remove:removeCurrentOverlay,sequence:options.sequence??50,rootId:options.rootId,};return removeCurrentOverlay;};return{add,overlays};},};services.add("overlay",overlayService);return __exports;});;

/* /web/static/src/core/pager/pager.js */
odoo.define('@web/core/pager/pager',['@web/core/utils/hooks','@web/core/utils/numbers','@odoo/owl'],function(require){'use strict';let __exports={};const{useAutofocus}=require("@web/core/utils/hooks");const{clamp}=require("@web/core/utils/numbers");const{Component,EventBus,useEffect,useExternalListener,useState}=require("@odoo/owl");const PAGER_UPDATED_EVENT=__exports.PAGER_UPDATED_EVENT="PAGER:UPDATED";const pagerBus=__exports.pagerBus=new EventBus();const Pager=__exports.Pager=class Pager extends Component{static template="web.Pager";static defaultProps={isEditable:true,withAccessKey:true,};static props={offset:Number,limit:Number,total:Number,onUpdate:Function,isEditable:{type:Boolean,optional:true},withAccessKey:{type:Boolean,optional:true},updateTotal:{type:Function,optional:true},};setup(){this.state=useState({isEditing:false,isDisabled:false,});this.inputRef=useAutofocus();useExternalListener(document,"mousedown",this.onClickAway,{capture:true});let firstMount=true;useEffect(()=>{if(!firstMount&&this.env.isSmall){pagerBus.trigger(PAGER_UPDATED_EVENT,{value:this.value,total:this.props.total,});}
firstMount=false;},()=>[this.props.offset,this.props.limit,this.props.total]);}
get minimum(){return this.props.offset+1;}
get maximum(){return Math.min(this.props.offset+this.props.limit,this.props.total);}
get value(){const parts=[this.minimum];if(this.props.limit>1){parts.push(this.maximum);}
return parts.join("-");}
get isSinglePage(){return!this.props.updateTotal&&this.minimum===1&&this.maximum===this.props.total;}
async navigate(direction){let minimum=this.props.offset+this.props.limit*direction;let total=this.props.total;if(this.props.updateTotal&&minimum<0){total=await this.props.updateTotal();}
if(minimum>=total){if(!this.props.updateTotal){minimum=0;}}else if(minimum<0&&this.props.limit===1){minimum=total-1;}else if(minimum<0&&this.props.limit>1){minimum=total-(total%this.props.limit||this.props.limit);}
this.update(minimum,this.props.limit,true);}
async parse(value){let[minimum,maximum]=value.trim().split(/\s*[-\s,;]\s*/);minimum=parseInt(minimum,10);maximum=maximum?parseInt(maximum,10):minimum;if(this.props.updateTotal){return{minimum:minimum-1,maximum};}
return{minimum:clamp(minimum,1,this.props.total)-1,maximum:clamp(maximum,1,this.props.total),};}
async setValue(value){const{minimum,maximum}=await this.parse(value);if(!isNaN(minimum)&&!isNaN(maximum)&&minimum<maximum){this.update(minimum,maximum-minimum);}}
async update(offset,limit,hasNavigated){this.state.isDisabled=true;try{await this.props.onUpdate({offset,limit},hasNavigated);}finally{this.state.isDisabled=false;this.state.isEditing=false;}}
async updateTotal(){if(!this.state.isDisabled){this.state.isDisabled=true;await this.props.updateTotal();this.state.isDisabled=false;}}
onClickAway(ev){if(ev.target!==this.inputRef.el){this.state.isEditing=false;}}
onInputBlur(){this.state.isEditing=false;}
onInputChange(ev){this.setValue(ev.target.value);if(!this.state.isDisabled){ev.preventDefault();}}
onInputKeydown(ev){switch(ev.key){case"Enter":ev.preventDefault();ev.stopPropagation();this.setValue(ev.currentTarget.value);break;case"Escape":ev.preventDefault();ev.stopPropagation();this.state.isEditing=false;break;}}
onValueClick(){if(this.props.isEditable&&!this.state.isEditing&&!this.state.isDisabled){if(this.inputRef.el){this.inputRef.el.focus();}
this.state.isEditing=true;}}}
return __exports;});;

/* /web/static/src/core/pager/pager_indicator.js */
odoo.define('@web/core/pager/pager_indicator',['@web/core/browser/browser','@web/core/registry','@web/core/transition','@web/core/utils/hooks','@odoo/owl','@web/core/pager/pager'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{Transition}=require("@web/core/transition");const{useBus}=require("@web/core/utils/hooks");const{Component,useState}=require("@odoo/owl");const{PAGER_UPDATED_EVENT,pagerBus}=require("@web/core/pager/pager");const PagerIndicator=__exports.PagerIndicator=class PagerIndicator extends Component{static template="web.PagerIndicator";static components={Transition};static props={};setup(){this.state=useState({show:false,value:"-",total:0,});this.startShowTimer=null;useBus(pagerBus,PAGER_UPDATED_EVENT,this.pagerUpdate);}
pagerUpdate({detail}){this.state.value=detail.value;this.state.total=detail.total;browser.clearTimeout(this.startShowTimer);this.state.show=true;this.startShowTimer=browser.setTimeout(()=>{this.state.show=false;},1400);}}
registry.category("main_components").add("PagerIndicator",{Component:PagerIndicator,});return __exports;});;

/* /web/static/src/core/popover/popover.js */
odoo.define('@web/core/popover/popover',['@odoo/owl','@web/core/hotkeys/hotkey_hook','@web/core/overlay/overlay_container','@web/core/position/position_hook','@web/core/ui/ui_service','@web/core/utils/classname','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillDestroy,useComponent,useRef}=require("@odoo/owl");const{useHotkey}=require("@web/core/hotkeys/hotkey_hook");const{OVERLAY_SYMBOL}=require("@web/core/overlay/overlay_container");const{usePosition}=require("@web/core/position/position_hook");const{useActiveElement}=require("@web/core/ui/ui_service");const{addClassesToElement,mergeClasses}=require("@web/core/utils/classname");const{useForwardRefToParent}=require("@web/core/utils/hooks");function useEarlyExternalListener(target,eventName,handler,eventParams){const component=useComponent();const boundHandler=handler.bind(component);target.addEventListener(eventName,boundHandler,eventParams);onWillDestroy(()=>target.removeEventListener(eventName,boundHandler,eventParams));}
function useClickAway(callback){const pointerDownHandler=(event)=>{callback(event.composedPath()[0]);};const blurHandler=(ev)=>{const target=ev.relatedTarget||document.activeElement;if(target?.tagName==="IFRAME"){callback(target);}};useEarlyExternalListener(window,"pointerdown",pointerDownHandler,{capture:true});useEarlyExternalListener(window,"blur",blurHandler,{capture:true});}
const POPOVERS=new WeakMap();__exports.getPopoverForTarget=getPopoverForTarget;function getPopoverForTarget(target){return POPOVERS.get(target);}
const Popover=__exports.Popover=class Popover extends Component{static template="web.Popover";static defaultProps={animation:true,arrow:true,class:"",closeOnClickAway:()=>true,closeOnEscape:true,componentProps:{},fixedPosition:false,position:"bottom",setActiveElement:false,};static props={component:{type:Function},componentProps:{optional:true,type:Object},target:{validate:(target)=>{const Element=target?.ownerDocument?.defaultView?.Element;return((Boolean(Element)&&(target instanceof Element||target instanceof window.Element))||(typeof target==="object"&&target?.constructor?.name?.endsWith("Element")));},},animation:{optional:true,type:Boolean},arrow:{optional:true,type:Boolean},class:{optional:true},role:{optional:true,type:String},fixedPosition:{optional:true,type:Boolean},holdOnHover:{optional:true,type:Boolean},onPositioned:{optional:true,type:Function},position:{optional:true,type:String,validate:(p)=>{const[d,v="middle"]=p.split("-");return(["top","bottom","left","right"].includes(d)&&["start","middle","end","fit"].includes(v));},},close:{optional:true,type:Function},closeOnClickAway:{optional:true,type:Function},closeOnEscape:{optional:true,type:Boolean},setActiveElement:{optional:true,type:Boolean},ref:{optional:true,type:Function},slots:{optional:true,type:Object},};static animationTime=200;setup(){if(this.props.setActiveElement){useActiveElement("ref");}
useForwardRefToParent("ref");this.popoverRef=useRef("ref");let shouldAnimate=this.props.animation;this.position=usePosition("ref",()=>this.props.target,{onPositioned:(el,solution)=>{(this.props.onPositioned||this.onPositioned.bind(this))(el,solution);if(this.props.arrow&&this.props.onPositioned){this.onPositioned.bind(this)(el,solution);}
if(shouldAnimate){shouldAnimate=false;const transform={top:["translateY(-5%)","translateY(0)"],right:["translateX(5%)","translateX(0)"],bottom:["translateY(5%)","translateY(0)"],left:["translateX(-5%)","translateX(0)"],}[solution.direction];this.position.lock();const animation=el.animate({opacity:[0,1],transform},this.constructor.animationTime);animation.finished.then(this.position.unlock);}
if(this.props.fixedPosition){this.position.lock();}},position:this.props.position,});onMounted(()=>POPOVERS.set(this.props.target,this.popoverRef.el));onWillDestroy(()=>POPOVERS.delete(this.props.target));if(!this.props.close){return;}
if(this.props.target.isConnected){useClickAway((target)=>this.onClickAway(target));if(this.props.closeOnEscape){useHotkey("escape",()=>this.props.close());}
const targetObserver=new MutationObserver(this.onTargetMutate.bind(this));targetObserver.observe(this.props.target.parentElement,{childList:true});onWillDestroy(()=>targetObserver.disconnect());}else{this.props.close();}}
get defaultClassObj(){return mergeClasses("o_popover popover mw-100",{"o-popover--with-arrow":this.props.arrow},this.props.class);}
isInside(target){return(this.props.target?.contains(target)||this.popoverRef?.el?.contains(target)||this.env[OVERLAY_SYMBOL]?.contains(target));}
onClickAway(target){if(this.props.closeOnClickAway(target)&&!this.isInside(target)){this.props.close();}}
onTargetMutate(){if(!this.props.target.isConnected){this.props.close();}}
onPositioned(el,{direction,variant}){const position=`${direction[0]}${variant[0]}`;el.classList=[];const directionMap={top:"top",bottom:"bottom",left:"start",right:"end",};addClassesToElement(el,this.defaultClassObj,`bs-popover-${directionMap[direction]}`,`o-popover-${direction}`,`o-popover--${position}`);if(this.props.arrow){const arrowEl=el.querySelector(":scope > .popover-arrow");arrowEl.className="popover-arrow";switch(position){case"tm":case"bm":case"tf":case"bf":arrowEl.classList.add("start-0","end-0","mx-auto");break;case"lm":case"rm":case"lf":case"rf":arrowEl.classList.add("top-0","bottom-0","my-auto");break;case"ts":case"bs":arrowEl.classList.add("end-auto");break;case"te":case"be":arrowEl.classList.add("start-auto");break;case"ls":case"rs":arrowEl.classList.add("bottom-auto");break;case"le":case"re":arrowEl.classList.add("top-auto");break;}}}}
return __exports;});;

/* /web/static/src/core/popover/popover_hook.js */
odoo.define('@web/core/popover/popover_hook',['@odoo/owl','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{onWillUnmount,status,useComponent}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");__exports.makePopover=makePopover;function makePopover(addFn,component,options){let removeFn=null;function close(){removeFn?.();}
return{open(target,props){close();const newOptions=Object.create(options);newOptions.onClose=()=>{removeFn=null;options.onClose?.();};removeFn=addFn(target,component,props,newOptions);},close,get isOpen(){return Boolean(removeFn);},};}
__exports.usePopover=usePopover;function usePopover(component,options={}){const popoverService=useService("popover");const owner=useComponent();const newOptions=Object.create(options);newOptions.onClose=()=>{if(status(owner)!=="destroyed"){options.onClose?.();}};const popover=makePopover(popoverService.add,component,newOptions);onWillUnmount(popover.close);return popover;}
return __exports;});;

/* /web/static/src/core/popover/popover_service.js */
odoo.define('@web/core/popover/popover_service',['@odoo/owl','@web/core/popover/popover','@web/core/registry'],function(require){'use strict';let __exports={};const{markRaw}=require("@odoo/owl");const{Popover}=require("@web/core/popover/popover");const{registry}=require("@web/core/registry");const popoverService=__exports.popoverService={dependencies:["overlay"],start(_,{overlay}){const add=(target,component,props={},options={})=>{const closeOnClickAway=typeof options.closeOnClickAway==="function"?options.closeOnClickAway:()=>options.closeOnClickAway??true;const remove=overlay.add(Popover,{target,close:()=>remove(),closeOnClickAway,closeOnEscape:options.closeOnEscape,component,componentProps:markRaw(props),ref:options.ref,class:options.popoverClass,animation:options.animation,arrow:options.arrow,role:options.popoverRole,position:options.position,onPositioned:options.onPositioned,fixedPosition:options.fixedPosition,holdOnHover:options.holdOnHover,setActiveElement:options.setActiveElement??true,},{env:options.env,onRemove:options.onClose,rootId:target.getRootNode()?.host?.id,});return remove;};return{add};},};registry.category("services").add("popover",popoverService);return __exports;});;

/* /web/static/src/core/position/position_hook.js */
odoo.define('@web/core/position/position_hook',['@web/core/position/utils','@web/core/utils/objects','@web/core/utils/timing','@odoo/owl'],function(require){'use strict';let __exports={};const{reposition}=require("@web/core/position/utils");const{omit}=require("@web/core/utils/objects");const{useThrottleForAnimation}=require("@web/core/utils/timing");const{EventBus,onWillDestroy,useChildSubEnv,useComponent,useEffect,useRef,}=require("@odoo/owl");const DEFAULTS={margin:0,position:"bottom",};const POSITION_BUS=Symbol("position-bus");__exports.usePosition=usePosition;function usePosition(refName,getTarget,options={}){const ref=useRef(refName);let lock=false;const update=()=>{const targetEl=getTarget();if(!ref.el||!targetEl?.isConnected||lock){return;}
const repositionOptions={...DEFAULTS,...omit(options,"onPositioned")};const solution=reposition(ref.el,targetEl,repositionOptions);options.onPositioned?.(ref.el,solution);};const component=useComponent();const bus=component.env[POSITION_BUS]||new EventBus();let executingUpdate=false;const batchedUpdate=async()=>{if(!executingUpdate){executingUpdate=true;update();await Promise.resolve();executingUpdate=false;}};bus.addEventListener("update",batchedUpdate);onWillDestroy(()=>bus.removeEventListener("update",batchedUpdate));const isTopmost=!(POSITION_BUS in component.env);if(isTopmost){useChildSubEnv({[POSITION_BUS]:bus});}
const throttledUpdate=useThrottleForAnimation(()=>bus.trigger("update"));useEffect(()=>{bus.trigger("update");if(isTopmost){const scrollListener=(e)=>{if(ref.el?.contains(e.target)){return;}
throttledUpdate();};const targetDocument=getTarget()?.ownerDocument;targetDocument?.addEventListener("scroll",scrollListener,{capture:true});targetDocument?.addEventListener("load",throttledUpdate,{capture:true});window.addEventListener("resize",throttledUpdate);return()=>{targetDocument?.removeEventListener("scroll",scrollListener,{capture:true});targetDocument?.removeEventListener("load",throttledUpdate,{capture:true});window.removeEventListener("resize",throttledUpdate);};}});return{lock:()=>{lock=true;},unlock:()=>{lock=false;bus.trigger("update");},};}
return __exports;});;

/* /web/static/src/core/position/utils.js */
odoo.define('@web/core/position/utils',['@web/core/l10n/localization'],function(require){'use strict';let __exports={};const{localization}=require("@web/core/l10n/localization");const DIRECTIONS={t:"top",r:"right",b:"bottom",l:"left"};const VARIANTS={s:"start",m:"middle",e:"end",f:"fit"};const DIRECTION_FLIP_ORDER={top:"tbrl",right:"rltb",bottom:"btrl",left:"lrbt"};const VARIANT_FLIP_ORDER={start:"sme",middle:"mse",end:"ems",fit:"f"};const FIT_FLIP_ORDER={top:"tb",right:"rl",bottom:"bt",left:"lr"};function getIFrame(popperEl,targetEl){return[...popperEl.ownerDocument.getElementsByTagName("iframe")].find((iframe)=>iframe.contentDocument?.contains(targetEl));}
function computePosition(popper,target,{container,margin,position}){let[direction,variant="middle"]=position.split("-");if(localization.direction==="rtl"){if(["left","right"].includes(direction)){direction=direction==="left"?"right":"left";}else if(["start","end"].includes(variant)){variant=variant==="start"?"end":"start";}}
const directions=variant==="fit"?FIT_FLIP_ORDER[direction]:DIRECTION_FLIP_ORDER[direction];const variants=VARIANT_FLIP_ORDER[variant];if(!container){container=popper.ownerDocument.documentElement;}else if(typeof container==="function"){container=container();}
const popperStyle=getComputedStyle(popper);const{marginTop,marginLeft,marginRight,marginBottom}=popperStyle;const popMargins={top:parseFloat(marginTop),left:parseFloat(marginLeft),right:parseFloat(marginRight),bottom:parseFloat(marginBottom),};const shouldAccountForIFrame=popper.ownerDocument!==target.ownerDocument;const iframe=shouldAccountForIFrame?getIFrame(popper,target):null;const popBox=popper.getBoundingClientRect();const targetBox=target.getBoundingClientRect();const contBox=container.getBoundingClientRect();const iframeBox=iframe?.getBoundingClientRect()??{top:0,left:0};const containerIsHTMLNode=container===container.ownerDocument.firstElementChild;const directionsData={t:iframeBox.top+targetBox.top-popMargins.bottom-margin-popBox.height,b:iframeBox.top+targetBox.bottom+popMargins.top+margin,r:iframeBox.left+targetBox.right+popMargins.left+margin,l:iframeBox.left+targetBox.left-popMargins.right-margin-popBox.width,};const variantsData={vf:iframeBox.left+targetBox.left,vs:iframeBox.left+targetBox.left+popMargins.left,vm:iframeBox.left+targetBox.left+targetBox.width/2-popBox.width/2,ve:iframeBox.left+targetBox.right-popMargins.right-popBox.width,hf:iframeBox.top+targetBox.top,hs:iframeBox.top+targetBox.top+popMargins.top,hm:iframeBox.top+targetBox.top+targetBox.height/2-popBox.height/2,he:iframeBox.top+targetBox.bottom-popMargins.bottom-popBox.height,};function getPositioningData(d=directions[0],v=variants[0],containerRestricted=false){const result={direction:DIRECTIONS[d],variant:VARIANTS[v]};const vertical=["t","b"].includes(d);const variantPrefix=vertical?"v":"h";const directionValue=directionsData[d];let variantValue=variantsData[variantPrefix+v];let malus=null;if(containerRestricted){const[directionSize,variantSize]=vertical?[popBox.height,popBox.width]:[popBox.width,popBox.height];let[directionMin,directionMax]=vertical?[contBox.top,contBox.bottom]:[contBox.left,contBox.right];let[variantMin,variantMax]=vertical?[contBox.left,contBox.right]:[contBox.top,contBox.bottom];if(containerIsHTMLNode){if(vertical){directionMin+=container.scrollTop;directionMax+=container.scrollTop;}else{variantMin+=container.scrollTop;variantMax+=container.scrollTop;}}
let directionOverflow=0;if(Math.floor(directionValue)<Math.ceil(directionMin)){directionOverflow=Math.floor(directionValue)-Math.ceil(directionMin);}else if(Math.ceil(directionValue+directionSize)>Math.floor(directionMax)){directionOverflow=Math.ceil(directionValue+directionSize)-Math.floor(directionMax);}
let variantOverflow=0;if(Math.floor(variantValue)<Math.ceil(variantMin)){variantOverflow=Math.floor(variantValue)-Math.ceil(variantMin);}else if(Math.ceil(variantValue+variantSize)>Math.floor(variantMax)){variantOverflow=Math.ceil(variantValue+variantSize)-Math.floor(variantMax);}
malus=Math.abs(directionOverflow)+(variantOverflow&&1);variantValue-=variantOverflow;result.variantOffset=-variantOverflow;}
const positioning=vertical?{top:directionValue,left:variantValue}:{top:variantValue,left:directionValue};result.top=positioning.top-popBox.top;result.left=positioning.left-popBox.left;return{result,malus};}
const matches=[];for(const d of directions){for(const v of variants){const match=getPositioningData(d,v,true);if(!match.malus){return match.result;}
matches.push(match);}}
return matches.sort((a,b)=>a.malus-b.malus)[0].result;}
__exports.reposition=reposition;function reposition(popper,target,options){popper.style.position="fixed";popper.style.top="0px";popper.style.left="0px";const solution=computePosition(popper,target,options);const{top,left,direction,variant}=solution;popper.style.top=`${top}px`;popper.style.left=`${left}px`;if(variant==="fit"){const styleProperty=["top","bottom"].includes(direction)?"width":"height";popper.style[styleProperty]=target.getBoundingClientRect()[styleProperty]+"px";}
return solution;}
return __exports;});;

/* /web/static/src/core/pwa/install_prompt.js */
odoo.define('@web/core/pwa/install_prompt',['@odoo/owl','@web/core/dialog/dialog','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{isIOS}=require("@web/core/browser/feature_detection");const InstallPrompt=__exports.InstallPrompt=class InstallPrompt extends Component{static props={close:true,onClose:{type:Function},};static components={Dialog,};static template="web.InstallPrompt";get isMobileSafari(){return isIOS();}
onClose(){this.props.close();this.props.onClose();}}
return __exports;});;

/* /web/static/src/core/pwa/pwa_service.js */
odoo.define('@web/core/pwa/pwa_service',['@odoo/owl','@web/core/browser/browser','@web/core/browser/feature_detection','@web/core/network/http_service','@web/core/registry','@web/core/pwa/install_prompt'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");const{isDisplayStandalone,isIOS,isMacOS,isBrowserSafari,}=require("@web/core/browser/feature_detection");const{get}=require("@web/core/network/http_service");const{registry}=require("@web/core/registry");const{InstallPrompt}=require("@web/core/pwa/install_prompt");const serviceRegistry=registry.category("services");let BEFOREINSTALLPROMPT_EVENT;let REGISTER_BEFOREINSTALLPROMPT_EVENT;browser.addEventListener("beforeinstallprompt",(ev)=>{if(REGISTER_BEFOREINSTALLPROMPT_EVENT){return REGISTER_BEFOREINSTALLPROMPT_EVENT(ev);}else{BEFOREINSTALLPROMPT_EVENT=ev;}});const pwaService={dependencies:["dialog"],start(env,{dialog}){let _manifest;let nativePrompt;const state=reactive({canPromptToInstall:false,isAvailable:false,isScopedApp:browser.location.href.includes("/scoped_app"),isSupportedOnBrowser:false,startUrl:"/odoo",decline,getManifest,hasScopeBeenInstalled,show,});function _getInstallationState(scope=state.startUrl){const installationState=browser.localStorage.getItem("pwaService.installationState");return installationState?JSON.parse(installationState)[scope]:"";}
function _setInstallationState(value){const ls=JSON.parse(browser.localStorage.getItem("pwaService.installationState")||"{}");ls[state.startUrl]=value;browser.localStorage.setItem("pwaService.installationState",JSON.stringify(ls));}
function _removeInstallationState(){const ls=JSON.parse(browser.localStorage.getItem("pwaService.installationState"));delete ls[state.startUrl];browser.localStorage.setItem("pwaService.installationState",JSON.stringify(ls));}
if(state.isScopedApp){if(browser.location.pathname==="/scoped_app"){state.startUrl="/"+new URL(browser.location.href).searchParams.get("path");}else{state.startUrl=browser.location.pathname;}}
state.isSupportedOnBrowser=browser.BeforeInstallPromptEvent!==undefined||(isBrowserSafari()&&!isDisplayStandalone()&&(isIOS()||(isMacOS()&&browser.navigator.userAgent.match(/Version\/(\d+)/)[1]>=17)));const installationState=_getInstallationState();if(state.isSupportedOnBrowser){if(BEFOREINSTALLPROMPT_EVENT){_handleBeforeInstallPrompt(BEFOREINSTALLPROMPT_EVENT,installationState);BEFOREINSTALLPROMPT_EVENT=null;}
REGISTER_BEFOREINSTALLPROMPT_EVENT=(ev)=>{_handleBeforeInstallPrompt(ev,installationState);};if(isBrowserSafari()){state.canPromptToInstall=installationState!=="dismissed";state.isAvailable=true;}}
function _handleBeforeInstallPrompt(ev,installationState){nativePrompt=ev;if(installationState==="accepted"){if(!isDisplayStandalone()){_removeInstallationState();}}
state.canPromptToInstall=installationState!=="dismissed";state.isAvailable=true;}
async function getManifest(){if(!_manifest){const manifest=await get(document.querySelector("link[rel=manifest")?.getAttribute("href"),"text");_manifest=JSON.parse(manifest);}
return _manifest;}
function hasScopeBeenInstalled(scope){return _getInstallationState(scope)==="accepted";}
async function show({onDone}={}){if(!state.isAvailable){return;}
if(nativePrompt){const res=await nativePrompt.prompt();_setInstallationState(res.outcome);state.canPromptToInstall=false;if(onDone){onDone(res);}}else if(isBrowserSafari()){dialog.add(InstallPrompt,{onClose:()=>{if(onDone){onDone({});}
this.decline();},});}}
function decline(){_setInstallationState("dismissed");state.canPromptToInstall=false;}
return state;},};serviceRegistry.add("pwa",pwaService);return __exports;});;

/* /web/static/src/core/py_js/py.js */
odoo.define('@web/core/py_js/py',['@web/core/py_js/py_interpreter','@web/core/py_js/py_parser','@web/core/py_js/py_tokenizer','@web/core/py_js/py_utils'],function(require){'use strict';let __exports={};const{evaluate}=require("@web/core/py_js/py_interpreter");const{parse}=require("@web/core/py_js/py_parser");const{tokenize}=require("@web/core/py_js/py_tokenizer");{const{evaluate}=require("@web/core/py_js/py_interpreter");Object.assign(__exports,{evaluate})};{const{parse}=require("@web/core/py_js/py_parser");Object.assign(__exports,{parse})};{const{tokenize}=require("@web/core/py_js/py_tokenizer");Object.assign(__exports,{tokenize})};{const{formatAST}=require("@web/core/py_js/py_utils");Object.assign(__exports,{formatAST})};__exports.parseExpr=parseExpr;function parseExpr(expr){const tokens=tokenize(expr);return parse(tokens);}
__exports.evaluateExpr=evaluateExpr;function evaluateExpr(expr,context={}){let ast;try{ast=parseExpr(expr);}catch(error){throw new EvalError(`Can not parse python expression: (${expr})\nError: ${error.message}`);}
try{return evaluate(ast,context);}catch(error){throw new EvalError(`Can not evaluate python expression: (${expr})\nError: ${error.message}`);}}
__exports.evaluateBooleanExpr=evaluateBooleanExpr;function evaluateBooleanExpr(expr,context={}){if(!expr||expr==='False'||expr==='0'){return false;}
if(expr==='True'||expr==='1'){return true;}
return evaluateExpr(`bool(${expr})`,context);}
return __exports;});;

/* /web/static/src/core/py_js/py_builtin.js */
odoo.define('@web/core/py_js/py_builtin',['@web/core/py_js/py_date'],function(require){'use strict';let __exports={};const{PyDate,PyDateTime,PyRelativeDelta,PyTime,PyTimeDelta}=require("@web/core/py_js/py_date");const EvaluationError=__exports.EvaluationError=class EvaluationError extends Error{}
__exports.execOnIterable=execOnIterable;function execOnIterable(iterable,func){if(iterable===null){throw new EvaluationError(`value not iterable`);}
if(typeof iterable==="object"&&!Array.isArray(iterable)&&!(iterable instanceof Set)){iterable=Object.keys(iterable);}
if(typeof iterable?.[Symbol.iterator]!=="function"){throw new EvaluationError(`value not iterable`);}
return func(iterable);}
const BUILTINS=__exports.BUILTINS={bool(value){switch(typeof value){case"number":return value!==0;case"string":return value!=="";case"boolean":return value;case"object":if(value===null||value===undefined){return false;}
if(value.isTrue){return value.isTrue();}
if(value instanceof Array){return!!value.length;}
if(value instanceof Set){return!!value.size;}
return Object.keys(value).length!==0;}
return true;},set(iterable){if(arguments.length>2){throw new EvaluationError(`set expected at most 1 argument, got (${arguments.length - 1}`);}
return execOnIterable(iterable,(iterable)=>{return new Set(iterable);});},max(...args){return Math.max(...args.slice(0,-1));},min(...args){return Math.min(...args.slice(0,-1));},time:{strftime(format){return PyDateTime.now().strftime(format);},},context_today(){return PyDate.today();},get current_date(){return this.today;},get today(){return PyDate.today().strftime("%Y-%m-%d");},get now(){return PyDateTime.now().strftime("%Y-%m-%d %H:%M:%S");},datetime:{time:PyTime,timedelta:PyTimeDelta,datetime:PyDateTime,date:PyDate,},relativedelta:PyRelativeDelta,true:true,false:false,};return __exports;});;

/* /web/static/src/core/py_js/py_date.js */
odoo.define('@web/core/py_js/py_date',['@web/core/py_js/py_parser'],function(require){'use strict';let __exports={};const{parseArgs}=require("@web/core/py_js/py_parser");const AssertionError=__exports.AssertionError=class AssertionError extends Error{}
const ValueError=__exports.ValueError=class ValueError extends Error{}
const NotSupportedError=__exports.NotSupportedError=class NotSupportedError extends Error{}
function fmt2(n){return String(n).padStart(2,"0");}
function fmt4(n){return String(n).padStart(4,"0");}
function divmod(a,b,fn){let mod=a%b;if((mod>0&&b<0)||(mod<0&&b>0)){mod+=b;}
return fn(Math.floor(a/b),mod);}
function assert(bool,message="AssertionError"){if(!bool){throw new AssertionError(message);}}
const DAYS_IN_MONTH=[null,31,28,31,30,31,30,31,31,30,31,30,31];const DAYS_BEFORE_MONTH=[null];for(let dbm=0,i=1;i<DAYS_IN_MONTH.length;++i){DAYS_BEFORE_MONTH.push(dbm);dbm+=DAYS_IN_MONTH[i];}
function daysInMonth(year,month){if(month===2&&isLeap(year)){return 29;}
return DAYS_IN_MONTH[month];}
function isLeap(year){return year%4===0&&(year%100!==0||year%400===0);}
function daysBeforeYear(year){const y=year-1;return y*365+Math.floor(y/4)-Math.floor(y/100)+Math.floor(y/400);}
function daysBeforeMonth(year,month){const postLeapFeb=month>2&&isLeap(year);return DAYS_BEFORE_MONTH[month]+(postLeapFeb?1:0);}
function ymd2ord(year,month,day){const dim=daysInMonth(year,month);if(!(1<=day&&day<=dim)){throw new ValueError(`day must be in 1..${dim}`);}
return daysBeforeYear(year)+daysBeforeMonth(year,month)+day;}
const DI400Y=daysBeforeYear(401);const DI100Y=daysBeforeYear(101);const DI4Y=daysBeforeYear(5);function ord2ymd(n){--n;let n400,n100,n4,n1,n0;divmod(n,DI400Y,function(_n400,n){n400=_n400;divmod(n,DI100Y,function(_n100,n){n100=_n100;divmod(n,DI4Y,function(_n4,n){n4=_n4;divmod(n,365,function(_n1,n){n1=_n1;n0=n;});});});});n=n0;const year=n400*400+1+n100*100+n4*4+n1;if(n1==4||n100==100){assert(n0===0);return{year:year-1,month:12,day:31,};}
const leapyear=n1===3&&(n4!==24||n100==3);assert(leapyear==isLeap(year));let month=(n+50)>>5;let preceding=DAYS_BEFORE_MONTH[month]+(month>2&&leapyear?1:0);if(preceding>n){--month;preceding-=DAYS_IN_MONTH[month]+(month===2&&leapyear?1:0);}
n-=preceding;return{year:year,month:month,day:n+1,};}
function tmxxx(year,month,day,hour,minute,second,microsecond){hour=hour||0;minute=minute||0;second=second||0;microsecond=microsecond||0;if(microsecond<0||microsecond>999999){divmod(microsecond,1000000,function(carry,ms){microsecond=ms;second+=carry;});}
if(second<0||second>59){divmod(second,60,function(carry,s){second=s;minute+=carry;});}
if(minute<0||minute>59){divmod(minute,60,function(carry,m){minute=m;hour+=carry;});}
if(hour<0||hour>23){divmod(hour,24,function(carry,h){hour=h;day+=carry;});}
if(month<1||month>12){divmod(month-1,12,function(carry,m){month=m+1;year+=carry;});}
const dim=daysInMonth(year,month);if(day<1||day>dim){if(day===0){--month;if(month>0){day=daysInMonth(year,month);}else{--year;month=12;day=31;}}else if(day==dim+1){++month;day=1;if(month>12){month=1;++year;}}else{const r=ord2ymd(ymd2ord(year,month,1)+(day-1));year=r.year;month=r.month;day=r.day;}}
return{year:year,month:month,day:day,hour:hour,minute:minute,second:second,microsecond:microsecond,};}
const PyDate=__exports.PyDate=class PyDate{static today(){return this.convertDate(new Date());}
static convertDate(date){const year=date.getFullYear();const month=date.getMonth()+1;const day=date.getDate();return new PyDate(year,month,day);}
constructor(year,month,day){this.year=year;this.month=month;this.day=day;}
static create(...args){const{year,month,day}=parseArgs(args,["year","month","day"]);return new PyDate(year,month,day);}
add(timedelta){const s=tmxxx(this.year,this.month,this.day+timedelta.days);return new PyDate(s.year,s.month,s.day);}
isEqual(other){if(!(other instanceof PyDate)){return false;}
return this.year===other.year&&this.month===other.month&&this.day===other.day;}
strftime(format){return format.replace(/%([A-Za-z])/g,(m,c)=>{switch(c){case"Y":return fmt4(this.year);case"m":return fmt2(this.month);case"d":return fmt2(this.day);}
throw new ValueError(`No known conversion for ${m}`);});}
substract(other){if(other instanceof PyTimeDelta){return this.add(other.negate());}
if(other instanceof PyDate){return PyTimeDelta.create(this.toordinal()-other.toordinal());}
throw new NotSupportedError();}
toJSON(){return this.strftime("%Y-%m-%d");}
toordinal(){return ymd2ord(this.year,this.month,this.day);}}
const PyDateTime=__exports.PyDateTime=class PyDateTime{static now(){return this.convertDate(new Date());}
static convertDate(date){const year=date.getFullYear();const month=date.getMonth()+1;const day=date.getDate();const hour=date.getHours();const minute=date.getMinutes();const second=date.getSeconds();return new PyDateTime(year,month,day,hour,minute,second,0);}
static create(...args){const namedArgs=parseArgs(args,["year","month","day","hour","minute","second","microsecond",]);const year=namedArgs.year;const month=namedArgs.month;const day=namedArgs.day;const hour=namedArgs.hour||0;const minute=namedArgs.minute||0;const second=namedArgs.second||0;const ms=namedArgs.micro/1000||0;return new PyDateTime(year,month,day,hour,minute,second,ms);}
static combine(...args){const{date,time}=parseArgs(args,["date","time"]);return PyDateTime.create(date.year,date.month,date.day,time.hour,time.minute,time.second);}
constructor(year,month,day,hour,minute,second,microsecond){this.year=year;this.month=month;this.day=day;this.hour=hour;this.minute=minute;this.second=second;this.microsecond=microsecond;}
add(timedelta){const s=tmxxx(this.year,this.month,this.day+timedelta.days,this.hour,this.minute,this.second+timedelta.seconds,this.microsecond+timedelta.microseconds);return new PyDateTime(s.year,s.month,s.day,s.hour,s.minute,s.second,s.microsecond);}
isEqual(other){if(!(other instanceof PyDateTime)){return false;}
return(this.year===other.year&&this.month===other.month&&this.day===other.day&&this.hour===other.hour&&this.minute===other.minute&&this.second===other.second&&this.microsecond===other.microsecond);}
strftime(format){return format.replace(/%([A-Za-z])/g,(m,c)=>{switch(c){case"Y":return fmt4(this.year);case"m":return fmt2(this.month);case"d":return fmt2(this.day);case"H":return fmt2(this.hour);case"M":return fmt2(this.minute);case"S":return fmt2(this.second);}
throw new ValueError(`No known conversion for ${m}`);});}
substract(timedelta){return this.add(timedelta.negate());}
toJSON(){return this.strftime("%Y-%m-%d %H:%M:%S");}
to_utc(){const d=new Date(this.year,this.month-1,this.day,this.hour,this.minute,this.second);const timedelta=PyTimeDelta.create({minutes:d.getTimezoneOffset()});return this.add(timedelta);}}
const PyTime=__exports.PyTime=class PyTime extends PyDate{static create(...args){const namedArgs=parseArgs(args,["hour","minute","second"]);const hour=namedArgs.hour||0;const minute=namedArgs.minute||0;const second=namedArgs.second||0;return new PyTime(hour,minute,second);}
constructor(hour,minute,second){const now=new Date();const year=now.getFullYear();const month=now.getMonth();const day=now.getDate();super(year,month,day);this.hour=hour;this.minute=minute;this.second=second;}
strftime(format){return format.replace(/%([A-Za-z])/g,(m,c)=>{switch(c){case"Y":return fmt4(this.year);case"m":return fmt2(this.month+1);case"d":return fmt2(this.day);case"H":return fmt2(this.hour);case"M":return fmt2(this.minute);case"S":return fmt2(this.second);}
throw new ValueError(`No known conversion for ${m}`);});}
toJSON(){return this.strftime("%H:%M:%S");}}
const DAYS_IN_YEAR=[31,59,90,120,151,181,212,243,273,304,334,366];const TIME_PERIODS=["hour","minute","second"];const PERIODS=["year","month","day",...TIME_PERIODS];const RELATIVE_KEYS="years months weeks days hours minutes seconds microseconds leapdays".split(" ");const ABSOLUTE_KEYS="year month day hour minute second microsecond weekday nlyearday yearday".split(" ");const argsSpec=["dt1","dt2"];const PyRelativeDelta=__exports.PyRelativeDelta=class PyRelativeDelta{static create(...args){const params=parseArgs(args,argsSpec);if("dt1"in params){throw new Error("relativedelta(dt1, dt2) is not supported for now");}
for(const period of PERIODS){if(period in params){const val=params[period];assert(val>=0,`${period} ${val} is out of range`);}}
for(const key of RELATIVE_KEYS){params[key]=params[key]||0;}
for(const key of ABSOLUTE_KEYS){params[key]=key in params?params[key]:null;}
params.days+=7*params.weeks;let yearDay=0;if(params.nlyearday){yearDay=params.nlyearday;}else if(params.yearday){yearDay=params.yearday;if(yearDay>59){params.leapDays=-1;}}
if(yearDay){for(let monthIndex=0;monthIndex<DAYS_IN_YEAR.length;monthIndex++){if(yearDay<=DAYS_IN_YEAR[monthIndex]){params.month=monthIndex+1;if(monthIndex===0){params.day=yearDay;}else{params.day=yearDay-DAYS_IN_YEAR[monthIndex-1];}
break;}}}
return new PyRelativeDelta(params);}
static add(date,delta){if(!(date instanceof PyDate||date instanceof PyDateTime)){throw new NotSupportedError();}
const s=tmxxx((delta.year||date.year)+delta.years,(delta.month||date.month)+delta.months,delta.day||date.day,delta.hour||date.hour||0,delta.minute||date.minute||0,delta.second||date.seconds||0,delta.microseconds||date.microseconds||0);const newDateTime=new PyDateTime(s.year,s.month,s.day,s.hour,s.minute,s.second,s.microsecond);let leapDays=0;if(delta.leapDays&&newDateTime.month>2&&isLeap(newDateTime.year)){leapDays=delta.leapDays;}
const temp=newDateTime.add(PyTimeDelta.create({days:delta.days+leapDays,hours:delta.hours,minutes:delta.minutes,seconds:delta.seconds,microseconds:delta.microseconds,}));const hasTime=Boolean(temp.hour||temp.minute||temp.second||temp.microsecond);const returnDate=!hasTime&&date instanceof PyDate?new PyDate(temp.year,temp.month,temp.day):temp;if(delta.weekday!==null){const wantedDow=delta.weekday+1;const _date=new Date(returnDate.year,returnDate.month-1,returnDate.day);const days=(7-_date.getDay()+wantedDow)%7;return returnDate.add(new PyTimeDelta(days,0,0));}
return returnDate;}
static substract(date,delta){return PyRelativeDelta.add(date,delta.negate());}
constructor(params={},sign=+1){this.years=sign*params.years;this.months=sign*params.months;this.days=sign*params.days;this.hours=sign*params.hours;this.minutes=sign*params.minutes;this.seconds=sign*params.seconds;this.microseconds=sign*params.microseconds;this.leapDays=params.leapDays;this.year=params.year;this.month=params.month;this.day=params.day;this.hour=params.hour;this.minute=params.minute;this.second=params.second;this.microsecond=params.microsecond;this.weekday=params.weekday;}
negate(){return new PyRelativeDelta(this,-1);}
isEqual(other){throw new NotSupportedError();}}
const TIME_DELTA_KEYS="weeks days hours minutes seconds milliseconds microseconds".split(" ");function modf(x){const mod=x%1;return[mod<0?mod+1:mod,Math.floor(x)];}
const PyTimeDelta=__exports.PyTimeDelta=class PyTimeDelta{static create(...args){const namedArgs=parseArgs(args,["days","seconds","microseconds"]);for(const key of TIME_DELTA_KEYS){namedArgs[key]=namedArgs[key]||0;}
let d=0;let s=0;let us=0;const days=namedArgs.days+namedArgs.weeks*7;let seconds=namedArgs.seconds+60*namedArgs.minutes+3600*namedArgs.hours;let microseconds=namedArgs.microseconds+1000*namedArgs.milliseconds;const[dFrac,dInt]=modf(days);d=dInt;let daysecondsfrac=0;if(dFrac){const[dsFrac,dsInt]=modf(dFrac*24*3600);s=dsInt;daysecondsfrac=dsFrac;}
const[sFrac,sInt]=modf(seconds);seconds=sInt;const secondsfrac=sFrac+daysecondsfrac;divmod(seconds,24*3600,(days,seconds)=>{d+=days;s+=seconds;});microseconds+=secondsfrac*1e6;divmod(microseconds,1000000,(seconds,microseconds)=>{divmod(seconds,24*3600,(days,seconds)=>{d+=days;s+=seconds;us+=Math.round(microseconds);});});return new PyTimeDelta(d,s,us);}
constructor(days,seconds,microseconds){this.days=days;this.seconds=seconds;this.microseconds=microseconds;}
add(other){return PyTimeDelta.create({days:this.days+other.days,seconds:this.seconds+other.seconds,microseconds:this.microseconds+other.microseconds,});}
divide(n){const us=(this.days*24*3600+this.seconds)*1e6+this.microseconds;return PyTimeDelta.create({microseconds:Math.floor(us/n)});}
isEqual(other){if(!(other instanceof PyTimeDelta)){return false;}
return(this.days===other.days&&this.seconds===other.seconds&&this.microseconds===other.microseconds);}
isTrue(){return this.days!==0||this.seconds!==0||this.microseconds!==0;}
multiply(n){return PyTimeDelta.create({days:n*this.days,seconds:n*this.seconds,microseconds:n*this.microseconds,});}
negate(){return PyTimeDelta.create({days:-this.days,seconds:-this.seconds,microseconds:-this.microseconds,});}
substract(other){return PyTimeDelta.create({days:this.days-other.days,seconds:this.seconds-other.seconds,microseconds:this.microseconds-other.microseconds,});}
total_seconds(){return this.days*86400+this.seconds+this.microseconds/1000000;}}
return __exports;});;

/* /web/static/src/core/py_js/py_interpreter.js */
odoo.define('@web/core/py_js/py_interpreter',['@web/core/py_js/py_builtin','@web/core/py_js/py_date','@web/core/py_js/py_utils','@web/core/py_js/py_parser'],function(require){'use strict';let __exports={};const{BUILTINS,EvaluationError,execOnIterable}=require("@web/core/py_js/py_builtin");const{NotSupportedError,PyDate,PyDateTime,PyRelativeDelta,PyTime,PyTimeDelta,}=require("@web/core/py_js/py_date");const{PY_DICT,toPyDict}=require("@web/core/py_js/py_utils");const{parseArgs}=require("@web/core/py_js/py_parser");const isTrue=BUILTINS.bool;function applyUnaryOp(ast,context){const value=evaluate(ast.right,context);switch(ast.op){case"-":if(value instanceof Object&&value.negate){return value.negate();}
return-value;case"+":return value;case"not":return!isTrue(value);}
throw new EvaluationError(`Unknown unary operator: ${ast.op}`);}
function pytypeIndex(val){switch(typeof val){case"object":return val===null?1:Array.isArray(val)?5:3;case"number":return 2;case"string":return 4;}
throw new EvaluationError(`Unknown type: ${typeof val}`);}
function isConstructor(obj){return!!obj.prototype&&!!obj.prototype.constructor.name;}
function isLess(left,right){if(typeof left==="number"&&typeof right==="number"){return left<right;}
if(typeof left==="boolean"){left=left?1:0;}
if(typeof right==="boolean"){right=right?1:0;}
const leftIndex=pytypeIndex(left);const rightIndex=pytypeIndex(right);if(leftIndex===rightIndex){return left<right;}
return leftIndex<rightIndex;}
function isEqual(left,right){if(typeof left!==typeof right){if(typeof left==="boolean"&&typeof right==="number"){return right===(left?1:0);}
if(typeof left==="number"&&typeof right==="boolean"){return left===(right?1:0);}
return false;}
if(left instanceof Object&&left.isEqual){return left.isEqual(right);}
return left===right;}
function isIn(left,right){if(Array.isArray(right)){return right.includes(left);}
if(typeof right==="string"&&typeof left==="string"){return right.includes(left);}
if(typeof right==="object"){return left in right;}
return false;}
function applyBinaryOp(ast,context){const left=evaluate(ast.left,context);const right=evaluate(ast.right,context);switch(ast.op){case"+":{const relativeDeltaOnLeft=left instanceof PyRelativeDelta;const relativeDeltaOnRight=right instanceof PyRelativeDelta;if(relativeDeltaOnLeft||relativeDeltaOnRight){const date=relativeDeltaOnLeft?right:left;const delta=relativeDeltaOnLeft?left:right;return PyRelativeDelta.add(date,delta);}
const timeDeltaOnLeft=left instanceof PyTimeDelta;const timeDeltaOnRight=right instanceof PyTimeDelta;if(timeDeltaOnLeft&&timeDeltaOnRight){return left.add(right);}
if(timeDeltaOnLeft){if(right instanceof PyDate||right instanceof PyDateTime){return right.add(left);}else{throw new NotSupportedError();}}
if(timeDeltaOnRight){if(left instanceof PyDate||left instanceof PyDateTime){return left.add(right);}else{throw new NotSupportedError();}}
if(left instanceof Array&&right instanceof Array){return[...left,...right];}
return left+right;}
case"-":{const isRightDelta=right instanceof PyRelativeDelta;if(isRightDelta){return PyRelativeDelta.substract(left,right);}
const timeDeltaOnRight=right instanceof PyTimeDelta;if(timeDeltaOnRight){if(left instanceof PyTimeDelta){return left.substract(right);}else if(left instanceof PyDate||left instanceof PyDateTime){return left.substract(right);}else{throw new NotSupportedError();}}
if(left instanceof PyDate){return left.substract(right);}
return left-right;}
case"*":{const timeDeltaOnLeft=left instanceof PyTimeDelta;const timeDeltaOnRight=right instanceof PyTimeDelta;if(timeDeltaOnLeft||timeDeltaOnRight){const number=timeDeltaOnLeft?right:left;const delta=timeDeltaOnLeft?left:right;return delta.multiply(number);}
return left*right;}
case"/":return left/right;case"%":return left%right;case"//":if(left instanceof PyTimeDelta){return left.divide(right);}
return Math.floor(left/right);case"**":return left**right;case"==":return isEqual(left,right);case"<>":case"!=":return!isEqual(left,right);case"<":return isLess(left,right);case">":return isLess(right,left);case">=":return isEqual(left,right)||isLess(right,left);case"<=":return isEqual(left,right)||isLess(left,right);case"in":return isIn(left,right);case"not in":return!isIn(left,right);}
throw new EvaluationError(`Unknown binary operator: ${ast.op}`);}
const DICT={get(...args){const{key,defValue}=parseArgs(args,["key","defValue"]);if(key in this){return this[key];}else if(defValue){return defValue;}
return null;},};const STRING={lower(){return this.toLowerCase();},upper(){return this.toUpperCase();},};function applyFunc(key,func,set,...args){if(args.length===1){return new Set(set);}
if(args.length>2){throw new EvaluationError(`${key}: py_js supports at most 1 argument, got (${args.length - 1})`);}
return execOnIterable(args[0],func);}
const SET={intersection(...args){return applyFunc("intersection",(iterable)=>{const intersection=new Set();for(const i of iterable){if(this.has(i)){intersection.add(i);}}
return intersection;},this,...args);},difference(...args){return applyFunc("difference",(iterable)=>{iterable=new Set(iterable);const difference=new Set();for(const e of this){if(!iterable.has(e)){difference.add(e);}}
return difference;},this,...args);},union(...args){return applyFunc("union",(iterable)=>{return new Set([...this,...iterable]);},this,...args);},};function methods(_class){return Object.getOwnPropertyNames(_class.prototype).map((prop)=>_class.prototype[prop]);}
const allowedFns=__exports.allowedFns=new Set([BUILTINS.time.strftime,BUILTINS.set,BUILTINS.bool,BUILTINS.min,BUILTINS.max,BUILTINS.context_today,BUILTINS.datetime.datetime.now,BUILTINS.datetime.datetime.combine,BUILTINS.datetime.date.today,...methods(BUILTINS.relativedelta),...Object.values(BUILTINS.datetime).flatMap((obj)=>methods(obj)),...Object.values(SET),...Object.values(DICT),...Object.values(STRING),]);const unboundFn=Symbol("unbound function");__exports.evaluate=evaluate;function evaluate(ast,context={}){const dicts=new Set();let pyContext;const evalContext=Object.create(context);if(!evalContext.context){Object.defineProperty(evalContext,"context",{get(){if(!pyContext){pyContext=toPyDict(context);}
return pyContext;},});}
function _innerEvaluate(ast){switch(ast.type){case 0:case 1:return ast.value;case 5:if(ast.value in evalContext){return evalContext[ast.value];}else if(ast.value in BUILTINS){return BUILTINS[ast.value];}else{throw new EvaluationError(`Name '${ast.value}' is not defined`);}
case 3:return null;case 2:return ast.value;case 6:return applyUnaryOp(ast,evalContext);case 7:return applyBinaryOp(ast,evalContext);case 14:{const left=_evaluate(ast.left);if(ast.op==="and"){return isTrue(left)?_evaluate(ast.right):left;}else{return isTrue(left)?left:_evaluate(ast.right);}}
case 4:case 10:return ast.value.map(_evaluate);case 11:{const dict={};for(const key in ast.value){dict[key]=_evaluate(ast.value[key]);}
dicts.add(dict);return dict;}
case 8:{const fnValue=_evaluate(ast.fn);const args=ast.args.map(_evaluate);const kwargs={};for(const kwarg in ast.kwargs){kwargs[kwarg]=_evaluate(ast.kwargs[kwarg]);}
if(fnValue===PyDate||fnValue===PyDateTime||fnValue===PyTime||fnValue===PyRelativeDelta||fnValue===PyTimeDelta){return fnValue.create(...args,kwargs);}
return fnValue(...args,kwargs);}
case 12:{const dict=_evaluate(ast.target);const key=_evaluate(ast.key);return dict[key];}
case 13:{if(isTrue(_evaluate(ast.condition))){return _evaluate(ast.ifTrue);}else{return _evaluate(ast.ifFalse);}}
case 15:{let left=_evaluate(ast.obj);let result;if(dicts.has(left)||Object.isPrototypeOf.call(PY_DICT,left)){result=DICT[ast.key];}else if(typeof left==="string"){result=STRING[ast.key];}else if(left instanceof Set){result=SET[ast.key];}else if(ast.key=="get"&&typeof left==="object"){result=DICT[ast.key];left=toPyDict(left);}else{result=left[ast.key];}
if(typeof result==="function"){if(!isConstructor(result)){const bound=result.bind(left);bound[unboundFn]=result;return bound;}}
return result;}}
throw new EvaluationError(`AST of type ${ast.type} cannot be evaluated`);}
function _evaluate(ast){const val=_innerEvaluate(ast);if(typeof val==="function"&&!allowedFns.has(val)&&!allowedFns.has(val[unboundFn])){throw new Error("Invalid Function Call");}
return val;}
return _evaluate(ast);}
return __exports;});;

/* /web/static/src/core/py_js/py_parser.js */
odoo.define('@web/core/py_js/py_parser',['@web/core/py_js/py_tokenizer'],function(require){'use strict';let __exports={};const{binaryOperators,comparators}=require("@web/core/py_js/py_tokenizer");const ParserError=__exports.ParserError=class ParserError extends Error{}
const chainedOperators=new Set(comparators);const infixOperators=new Set(binaryOperators.concat(comparators));__exports.bp=bp;function bp(symbol){switch(symbol){case"=":return 10;case"if":return 20;case"in":case"not in":case"is":case"is not":case"<":case"<=":case">":case">=":case"<>":case"==":case"!=":return 60;case"or":return 30;case"and":return 40;case"not":return 50;case"|":return 70;case"^":return 80;case"&":return 90;case"<<":case">>":return 100;case"+":case"-":return 110;case"*":case"/":case"//":case"%":return 120;case"**":return 140;case".":case"(":case"[":return 150;}
return 0;}
function bindingPower(token){return token.type===2?bp(token.value):0;}
function isSymbol(token,value){return token.type===2&&token.value===value;}
function parsePrefix(current,tokens){switch(current.type){case 0:return{type:0,value:current.value};case 1:return{type:1,value:current.value};case 4:if(current.value==="None"){return{type:3};}else{return{type:2,value:current.value==="True"};}
case 3:return{type:5,value:current.value};case 2:switch(current.value){case"-":case"+":case"~":return{type:6,op:current.value,right:_parse(tokens,130),};case"not":return{type:6,op:current.value,right:_parse(tokens,50),};case"(":{const content=[];let isTuple=false;while(tokens[0]&&!isSymbol(tokens[0],")")){content.push(_parse(tokens,0));if(tokens[0]){if(tokens[0]&&isSymbol(tokens[0],",")){isTuple=true;tokens.shift();}else if(!isSymbol(tokens[0],")")){throw new ParserError("parsing error");}}else{throw new ParserError("parsing error");}}
if(!tokens[0]||!isSymbol(tokens[0],")")){throw new ParserError("parsing error");}
tokens.shift();isTuple=isTuple||content.length===0;return isTuple?{type:10,value:content}:content[0];}
case"[":{const value=[];while(tokens[0]&&!isSymbol(tokens[0],"]")){value.push(_parse(tokens,0));if(tokens[0]){if(isSymbol(tokens[0],",")){tokens.shift();}else if(!isSymbol(tokens[0],"]")){throw new ParserError("parsing error");}}}
if(!tokens[0]||!isSymbol(tokens[0],"]")){throw new ParserError("parsing error");}
tokens.shift();return{type:4,value};}
case"{":{const dict={};while(tokens[0]&&!isSymbol(tokens[0],"}")){const key=_parse(tokens,0);if((key.type!==1&&key.type!==0)||!tokens[0]||!isSymbol(tokens[0],":")){throw new ParserError("parsing error");}
tokens.shift();const value=_parse(tokens,0);dict[key.value]=value;if(isSymbol(tokens[0],",")){tokens.shift();}}
if(!tokens.shift()){throw new ParserError("parsing error");}
return{type:11,value:dict};}}}
throw new ParserError("Token cannot be parsed");}
function parseInfix(left,current,tokens){switch(current.type){case 2:if(infixOperators.has(current.value)){let right=_parse(tokens,bindingPower(current));if(current.value==="and"||current.value==="or"){return{type:14,op:current.value,left,right,};}else if(current.value==="."){if(right.type===5){return{type:15,obj:left,key:right.value,};}else{throw new ParserError("invalid obj lookup");}}
let op={type:7,op:current.value,left,right,};while(chainedOperators.has(current.value)&&tokens[0]&&tokens[0].type===2&&chainedOperators.has(tokens[0].value)){const nextToken=tokens.shift();op={type:14,op:"and",left:op,right:{type:7,op:nextToken.value,left:right,right:_parse(tokens,bindingPower(nextToken)),},};right=op.right.right;}
return op;}
switch(current.value){case"(":{const args=[];const kwargs={};while(tokens[0]&&!isSymbol(tokens[0],")")){const arg=_parse(tokens,0);if(arg.type===9){kwargs[arg.name.value]=arg.value;}else{args.push(arg);}
if(tokens[0]&&isSymbol(tokens[0],",")){tokens.shift();}}
if(!tokens[0]||!isSymbol(tokens[0],")")){throw new ParserError("parsing error");}
tokens.shift();return{type:8,fn:left,args,kwargs};}
case"=":if(left.type===5){return{type:9,name:left,value:_parse(tokens,10),};}
break;case"[":{const key=_parse(tokens);if(!tokens[0]||!isSymbol(tokens[0],"]")){throw new ParserError("parsing error");}
tokens.shift();return{type:12,target:left,key:key,};}
case"if":{const condition=_parse(tokens);if(!tokens[0]||!isSymbol(tokens[0],"else")){throw new ParserError("parsing error");}
tokens.shift();const ifFalse=_parse(tokens);return{type:13,condition,ifTrue:left,ifFalse,};}}}
throw new ParserError("Token cannot be parsed");}
function _parse(tokens,bp=0){const token=tokens.shift();let expr=parsePrefix(token,tokens);while(tokens[0]&&bindingPower(tokens[0])>bp){expr=parseInfix(expr,tokens.shift(),tokens);}
return expr;}
__exports.parse=parse;function parse(tokens){if(tokens.length){const ast=_parse(tokens,0);if(tokens.length){throw new ParserError("Token(s) unused");}
return ast;}
throw new ParserError("Missing token");}
__exports.parseArgs=parseArgs;function parseArgs(args,spec){const last=args[args.length-1];const unnamedArgs=typeof last==="object"?args.slice(0,-1):args;const kwargs=typeof last==="object"?last:{};for(const[index,val]of unnamedArgs.entries()){kwargs[spec[index]]=val;}
return kwargs;}
return __exports;});;

/* /web/static/src/core/py_js/py_tokenizer.js */
odoo.define('@web/core/py_js/py_tokenizer',[],function(require){'use strict';let __exports={};const TokenizerError=__exports.TokenizerError=class TokenizerError extends Error{}
const directMap={"\\":"\\",'"':'"',"'":"'",a:"\x07",b:"\x08",f:"\x0c",n:"\n",r:"\r",t:"\t",v:"\v",};function decodeStringLiteral(str,unicode){const out=[];let code;for(var i=0;i<str.length;++i){if(str[i]!=="\\"){out.push(str[i]);continue;}
var escape=str[i+1];if(escape in directMap){out.push(directMap[escape]);++i;continue;}
switch(escape){case"\n":++i;continue;case"N":if(!unicode){break;}
throw new TokenizerError("SyntaxError: \\N{} escape not implemented");case"u":if(!unicode){break;}
var uni=str.slice(i+2,i+6);if(!/[0-9a-f]{4}/i.test(uni)){throw new TokenizerError(["SyntaxError: (unicode error) 'unicodeescape' codec"," can't decode bytes in position ",i,"-",i+4,": truncated \\uXXXX escape",].join(""));}
code=parseInt(uni,16);out.push(String.fromCharCode(code));i+=5;continue;case"U":if(!unicode){break;}
throw new TokenizerError("SyntaxError: \\U escape not implemented");case"x":var hex=str.slice(i+2,i+4);if(!/[0-9a-f]{2}/i.test(hex)){if(!unicode){throw new TokenizerError("ValueError: invalid \\x escape");}
throw new TokenizerError(["SyntaxError: (unicode error) 'unicodeescape'"," codec can't decode bytes in position ",i,"-",i+2,": truncated \\xXX escape",].join(""));}
code=parseInt(hex,16);out.push(String.fromCharCode(code));i+=3;continue;default:if(!/[0-8]/.test(escape)){break;}
var r=/[0-8]{1,3}/g;r.lastIndex=i+1;var m=r.exec(str);var oct=m[0];code=parseInt(oct,8);out.push(String.fromCharCode(code));i+=oct.length;continue;}
out.push("\\");}
return out.join("");}
const constants=new Set(["None","False","True"]);const comparators=__exports.comparators=["in","not","not in","is","is not","<","<=",">",">=","<>","!=","==",];const binaryOperators=__exports.binaryOperators=["or","and","|","^","&","<<",">>","+","-","*","/","//","%","~","**",".",];const unaryOperators=__exports.unaryOperators=["-"];const symbols=new Set([...["(",")","[","]","{","}",":",","],...["if","else","lambda","="],...comparators,...binaryOperators,...unaryOperators,]);function group(...args){return"("+args.join("|")+")";}
const Name="[a-zA-Z_]\\w*";const Whitespace="[ \\f\\t]*";const DecNumber="\\d+(L|l)?";const IntNumber=DecNumber;const Exponent="[eE][+-]?\\d+";const PointFloat=group(`\\d+\\.\\d*(${Exponent})?`,`\\.\\d+(${Exponent})?`);const FloatNumber=group(PointFloat,`\\d+${Exponent}`);const Number=group(FloatNumber,IntNumber);const Operator=group("\\*\\*=?",">>=?","<<=?","<>","!=","//=?","[+\\-*/%&|^=<>]=?","~");const Bracket="[\\[\\]\\(\\)\\{\\}]";const Special="[:;.,`@]";const Funny=group(Operator,Bracket,Special);const ContStr=group("([uU])?'([^\n'\\\\]*(?:\\\\.[^\n'\\\\]*)*)'",'([uU])?"([^\n"\\\\]*(?:\\\\.[^\n"\\\\]*)*)"');const PseudoToken=Whitespace+group(Number,Funny,ContStr,Name);const NumberPattern=new RegExp("^"+Number+"$");const StringPattern=new RegExp("^"+ContStr+"$");const NamePattern=new RegExp("^"+Name+"$");const strip=new RegExp("^"+Whitespace);__exports.tokenize=tokenize;function tokenize(str){const tokens=[];const max=str.length;let start=0;let end=0;const pseudoprog=new RegExp(PseudoToken,"g");while(pseudoprog.lastIndex<max){const pseudomatch=pseudoprog.exec(str);if(!pseudomatch){if(/^\s+$/.test(str.slice(end))){break;}
throw new TokenizerError("Failed to tokenize <<"+
str+">> at index "+
(end||0)+"; parsed so far: "+
tokens);}
if(pseudomatch.index>end){if(str.slice(end,pseudomatch.index).trim()){throw new TokenizerError("Invalid expression");}}
start=pseudomatch.index;end=pseudoprog.lastIndex;let token=str.slice(start,end).replace(strip,"");if(NumberPattern.test(token)){tokens.push({type:0,value:parseFloat(token),});}else if(StringPattern.test(token)){var m=StringPattern.exec(token);tokens.push({type:1,value:decodeStringLiteral(m[3]!==undefined?m[3]:m[5],!!(m[2]||m[4])),});}else if(symbols.has(token)){if(token==="in"&&tokens.length>0&&tokens[tokens.length-1].value==="not"){token="not in";tokens.pop();}else if(token==="not"&&tokens.length>0&&tokens[tokens.length-1].value==="is"){token="is not";tokens.pop();}
tokens.push({type:2,value:token,});}else if(constants.has(token)){tokens.push({type:4,value:token,});}else if(NamePattern.test(token)){tokens.push({type:3,value:token,});}else{throw new TokenizerError("Invalid expression");}}
return tokens;}
return __exports;});;

/* /web/static/src/core/py_js/py_utils.js */
odoo.define('@web/core/py_js/py_utils',['@web/core/py_js/py_parser','@web/core/py_js/py_date'],function(require){'use strict';let __exports={};const{bp}=require("@web/core/py_js/py_parser");const{PyDate,PyDateTime}=require("@web/core/py_js/py_date");__exports.toPyValue=toPyValue;function toPyValue(value){switch(typeof value){case"string":return{type:1,value};case"number":return{type:0,value};case"boolean":return{type:2,value};case"object":if(Array.isArray(value)){return{type:4,value:value.map(toPyValue)};}else if(value===null){return{type:3};}else if(value instanceof Date){return{type:1,value:PyDateTime.convertDate(value)};}else if(value instanceof PyDate||value instanceof PyDateTime){return{type:1,value};}else{const content={};for(const key in value){content[key]=toPyValue(value[key]);}
return{type:11,value:content};}
default:throw new Error("Invalid type");}}
__exports.formatAST=formatAST;function formatAST(ast,lbp=0){switch(ast.type){case 3:return"None";case 1:return JSON.stringify(ast.value);case 0:return String(ast.value);case 2:return ast.value?"True":"False";case 4:return`[${ast.value.map(formatAST).join(", ")}]`;case 6:if(ast.op==="not"){return`not `+formatAST(ast.right,50);}
return ast.op+formatAST(ast.right,130);case 7:{const abp=bp(ast.op);const str=`${formatAST(ast.left, abp)} ${ast.op} ${formatAST(ast.right, abp)}`;return abp<lbp?`(${str})`:str;}
case 11:{const pairs=[];for(const k in ast.value){pairs.push(`"${k}": ${formatAST(ast.value[k])}`);}
return`{`+pairs.join(", ")+`}`;}
case 10:return`(${ast.value.map(formatAST).join(", ")})`;case 5:return ast.value;case 12:{return`${formatAST(ast.target)}[${formatAST(ast.key)}]`;}
case 13:{const{ifTrue,condition,ifFalse}=ast;return`${formatAST(ifTrue)} if ${formatAST(condition)} else ${formatAST(ifFalse)}`;}
case 14:{const abp=bp(ast.op);const str=`${formatAST(ast.left, abp)} ${ast.op} ${formatAST(ast.right, abp)}`;return abp<lbp?`(${str})`:str;}
case 15:return`${formatAST(ast.obj, 150)}.${ast.key}`;case 8:{const args=ast.args.map(formatAST);const kwargs=[];for(const kwarg in ast.kwargs){kwargs.push(`${kwarg} = ${formatAST(ast.kwargs[kwarg])}`);}
const argStr=args.concat(kwargs).join(", ");return`${formatAST(ast.fn)}(${argStr})`;}}
throw new Error("invalid expression: "+ast);}
const PY_DICT=__exports.PY_DICT=Object.create(null);__exports.toPyDict=toPyDict;function toPyDict(obj){return new Proxy(obj,{getPrototypeOf(){return PY_DICT;},});}
return __exports;});;

/* /web/static/src/core/record_selectors/multi_record_selector.js */
odoo.define('@web/core/record_selectors/multi_record_selector',['@odoo/owl','@web/core/tags_list/tags_list','@web/core/utils/hooks','@web/core/record_selectors/record_autocomplete','@web/core/l10n/translation','@web/core/record_selectors/tag_navigation_hook'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{TagsList}=require("@web/core/tags_list/tags_list");const{useService}=require("@web/core/utils/hooks");const{RecordAutocomplete}=require("@web/core/record_selectors/record_autocomplete");const{_t}=require("@web/core/l10n/translation");const{useTagNavigation}=require("@web/core/record_selectors/tag_navigation_hook");const MultiRecordSelector=__exports.MultiRecordSelector=class MultiRecordSelector extends Component{static props={resIds:{type:Array,element:Number},resModel:String,update:Function,domain:{type:Array,optional:true},context:{type:Object,optional:true},fieldString:{type:String,optional:true},placeholder:{type:String,optional:true},};static components={RecordAutocomplete,TagsList};static template="web.MultiRecordSelector";setup(){this.nameService=useService("name");this.onTagKeydown=useTagNavigation("multiRecordSelector",this.deleteTag.bind(this));onWillStart(()=>this.computeDerivedParams());onWillUpdateProps((nextProps)=>this.computeDerivedParams(nextProps));}
async computeDerivedParams(props=this.props){const displayNames=await this.getDisplayNames(props);this.tags=this.getTags(props,displayNames);}
async getDisplayNames(props){const ids=this.getIds(props);return this.nameService.loadDisplayNames(props.resModel,ids);}
get placeholder(){return this.getIds().length?"":this.props.placeholder;}
getIds(props=this.props){return props.resIds;}
getTags(props,displayNames){return props.resIds.map((id,index)=>{const text=typeof displayNames[id]==="string"?displayNames[id]:_t("Inaccessible/missing record ID: %s",id);return{text,onDelete:()=>{this.deleteTag(index);},onKeydown:this.onTagKeydown,};});}
deleteTag(index){this.props.update([...this.props.resIds.slice(0,index),...this.props.resIds.slice(index+1),]);}
update(resIds){this.props.update([...this.props.resIds,...resIds]);}}
return __exports;});;

/* /web/static/src/core/record_selectors/record_autocomplete.js */
odoo.define('@web/core/record_selectors/record_autocomplete',['@odoo/owl','@web/core/autocomplete/autocomplete','@web/core/l10n/translation','@web/core/domain','@web/core/registry','@web/core/utils/hooks'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{AutoComplete}=require("@web/core/autocomplete/autocomplete");const{_t}=require("@web/core/l10n/translation");const{Domain}=require("@web/core/domain");const{registry}=require("@web/core/registry");const{useOwnedDialogs,useService}=require("@web/core/utils/hooks");const SEARCH_LIMIT=7;const SEARCH_MORE_LIMIT=320;const RecordAutocomplete=__exports.RecordAutocomplete=class RecordAutocomplete extends Component{static props={resModel:String,update:Function,multiSelect:Boolean,getIds:Function,value:String,domain:{type:Array,optional:true},context:{type:Object,optional:true},className:{type:String,optional:true},fieldString:{type:String,optional:true},placeholder:{type:String,optional:true},};static components={AutoComplete};static template="web.RecordAutocomplete";setup(){this.orm=useService("orm");this.nameService=useService("name");this.addDialog=useOwnedDialogs();this.sources=[{placeholder:_t("Loading..."),options:this.loadOptionsSource.bind(this),},];}
addNames(options){const displayNames=Object.fromEntries(options);this.nameService.addDisplayNames(this.props.resModel,displayNames);}
getIds(){return this.props.getIds();}
async loadOptionsSource(name){if(this.lastProm){this.lastProm.abort(false);}
this.lastProm=this.search(name,SEARCH_LIMIT+1);const nameGets=(await this.lastProm).map(([id,label])=>([id,label?label.split("\n")[0]:_t("Unnamed")]));this.addNames(nameGets);const options=nameGets.map(([value,label])=>({value,label}));if(SEARCH_LIMIT<nameGets.length){options.push({label:_t("Search More..."),action:this.onSearchMore.bind(this,name),classList:"o_m2o_dropdown_option",});}
if(options.length===0){options.push({label:_t("(no result)"),unselectable:true});}
return options;}
async onSearchMore(name){const{fieldString,multiSelect,resModel}=this.props;let operator;const ids=[];if(name){const nameGets=await this.search(name,SEARCH_MORE_LIMIT);this.addNames(nameGets);operator="in";ids.push(...nameGets.map((nameGet)=>nameGet[0]));}else{operator="not in";ids.push(...this.getIds());}
const dynamicFilters=ids.length?[{description:_t("Quick search: %s",name),domain:[["id",operator,ids]],},]:undefined;const SelectCreateDialog=registry.category("dialogs").get("select_create");this.addDialog(SelectCreateDialog,{title:_t("Search: %s",fieldString),dynamicFilters,domain:this.getDomain(),resModel,noCreate:true,multiSelect,context:this.props.context||{},onSelected:(resId)=>{const resIds=Array.isArray(resId)?resId:[resId];this.props.update([...resIds]);},});}
getDomain(){const domainIds=Domain.not([["id","in",this.getIds()]]);if(this.props.domain){return Domain.and([this.props.domain,domainIds]).toList();}
return domainIds.toList();}
onSelect({value:resId,action},params){if(action){return action(params);}
this.props.update([resId]);}
search(name,limit){const domain=this.getDomain();return this.orm.call(this.props.resModel,"name_search",[],{name,args:domain,limit,context:this.props.context||{},});}
onChange({inputValue}){if(!inputValue.length){this.props.update([]);}}}
return __exports;});;

/* /web/static/src/core/record_selectors/record_selector.js */
odoo.define('@web/core/record_selectors/record_selector',['@odoo/owl','@web/core/utils/hooks','@web/core/record_selectors/record_autocomplete','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{RecordAutocomplete}=require("@web/core/record_selectors/record_autocomplete");const{_t}=require("@web/core/l10n/translation");const RecordSelector=__exports.RecordSelector=class RecordSelector extends Component{static props={resId:[Number,{value:false}],resModel:String,update:Function,domain:{type:Array,optional:true},context:{type:Object,optional:true},fieldString:{type:String,optional:true},placeholder:{type:String,optional:true},};static components={RecordAutocomplete};static template="web.RecordSelector";setup(){this.nameService=useService("name");onWillStart(()=>this.computeDerivedParams());onWillUpdateProps((nextProps)=>this.computeDerivedParams(nextProps));}
async computeDerivedParams(props=this.props){const displayNames=await this.getDisplayNames(props);this.displayName=this.getDisplayName(props,displayNames);}
async getDisplayNames(props){const ids=this.getIds(props);return this.nameService.loadDisplayNames(props.resModel,ids);}
getDisplayName(props=this.props,displayNames){const{resId}=props;if(resId===false){return"";}
return typeof displayNames[resId]==="string"?displayNames[resId]:_t("Inaccessible/missing record ID: %s",resId);}
getIds(props=this.props){if(props.resId){return[props.resId];}
return[];}
update(resIds){this.props.update(resIds[0]||false);this.render(true);}}
return __exports;});;

/* /web/static/src/core/record_selectors/tag_navigation_hook.js */
odoo.define('@web/core/record_selectors/tag_navigation_hook',['@web/core/hotkeys/hotkey_service','@odoo/owl'],function(require){'use strict';let __exports={};const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{useEffect,useRef}=require("@odoo/owl");__exports.useTagNavigation=useTagNavigation;function useTagNavigation(refName,deleteTag){const ref=useRef(refName);useEffect((autocomplete)=>{if(!autocomplete){return;}
autocomplete.addEventListener("keydown",onAutoCompleteKeydown);return()=>{autocomplete.removeEventListener("keydown",onAutoCompleteKeydown);};},()=>[ref.el?.querySelector(".o-autocomplete")]);function focusTag(index){const tags=ref.el.getElementsByClassName("o_tag");if(tags.length){if(index===undefined){tags[tags.length-1].focus();}else{tags[index].focus();}}}
function onAutoCompleteKeydown(ev){if(ev.isComposing){return;}
const hotkey=getActiveHotkey(ev);const input=ev.target.closest(".o-autocomplete--input");const autoCompleteMenuOpened=!!ref.el.querySelector(".o-autocomplete--dropdown-menu");switch(hotkey){case"arrowleft":{if(input.selectionStart||autoCompleteMenuOpened){return;}
focusTag();break;}
case"arrowright":{if(input.selectionStart!==input.value.length||autoCompleteMenuOpened){return;}
focusTag(0);break;}
case"backspace":{if(input.value){return;}
const tags=ref.el.getElementsByClassName("o_tag");if(tags.length){deleteTag(tags.length-1);}
break;}
default:return;}
ev.preventDefault();ev.stopPropagation();}
function onTagKeydown(ev){const hotkey=getActiveHotkey(ev);const tags=[...ref.el.getElementsByClassName("o_tag")];const closestTag=ev.target.closest(".o_tag");const tagIndex=tags.indexOf(closestTag);const input=ref.el.querySelector(".o-autocomplete--input");switch(hotkey){case"arrowleft":{if(tagIndex===0){input.focus();}else{focusTag(tagIndex-1);}
break;}
case"arrowright":{if(tagIndex===tags.length-1){input.focus();}else{focusTag(tagIndex+1);}
break;}
case"backspace":{input.focus();deleteTag(tagIndex);break;}
default:return;}
ev.preventDefault();ev.stopPropagation();}
return onTagKeydown;}
return __exports;});;

/* /web/static/src/core/registry.js */
odoo.define('@web/core/registry',['@odoo/owl'],function(require){'use strict';let __exports={};const{EventBus,validate}=require("@odoo/owl");const KeyNotFoundError=__exports.KeyNotFoundError=class KeyNotFoundError extends Error{}
const DuplicatedKeyError=__exports.DuplicatedKeyError=class DuplicatedKeyError extends Error{}
const validateSchema=(value,schema)=>{if(!odoo.debug){return;}
validate(value,schema);}
const Registry=__exports.Registry=class Registry extends EventBus{constructor(name){super();this.content={};this.subRegistries={};this.elements=null;this.entries=null;this.name=name;this.validationSchema=null;this.addEventListener("UPDATE",()=>{this.elements=null;this.entries=null;});}
add(key,value,{force,sequence}={}){if(this.validationSchema){validateSchema(value,this.validationSchema);}
if(!force&&key in this.content){throw new DuplicatedKeyError(`Cannot add key "${key}" in the "${this.name}" registry: it already exists`);}
let previousSequence;if(force){const elem=this.content[key];previousSequence=elem&&elem[0];}
sequence=sequence===undefined?previousSequence||50:sequence;this.content[key]=[sequence,value];const payload={operation:"add",key,value};this.trigger("UPDATE",payload);return this;}
get(key,defaultValue){if(arguments.length<2&&!(key in this.content)){throw new KeyNotFoundError(`Cannot find key "${key}" in the "${this.name}" registry`);}
const info=this.content[key];return info?info[1]:defaultValue;}
contains(key){return key in this.content;}
getAll(){if(!this.elements){const content=Object.values(this.content).sort((el1,el2)=>el1[0]-el2[0]);this.elements=content.map((elem)=>elem[1]);}
return this.elements.slice();}
getEntries(){if(!this.entries){const entries=Object.entries(this.content).sort((el1,el2)=>el1[1][0]-el2[1][0]);this.entries=entries.map(([str,elem])=>[str,elem[1]]);}
return this.entries.slice();}
remove(key){const value=this.content[key];delete this.content[key];const payload={operation:"delete",key,value};this.trigger("UPDATE",payload);}
category(subcategory){if(!(subcategory in this.subRegistries)){this.subRegistries[subcategory]=new Registry(subcategory);}
return this.subRegistries[subcategory];}
addValidation(schema){if(this.validationSchema){throw new Error("Validation schema already set on this registry");}
this.validationSchema=schema;for(const value of this.getAll()){validateSchema(value,schema);}}}
const registry=__exports.registry=new Registry();return __exports;});;

/* /web/static/src/core/registry_hook.js */
odoo.define('@web/core/registry_hook',['@odoo/owl'],function(require){'use strict';let __exports={};const{useState,onWillStart,onWillDestroy}=require("@odoo/owl");__exports.useRegistry=useRegistry;function useRegistry(registry){const state=useState({entries:registry.getEntries()});const listener=({detail})=>{const index=state.entries.findIndex(([k])=>k===detail.key);if(detail.operation==="add"&&index===-1){const newEntries=registry.getEntries();const newEntry=newEntries.find(([k])=>k===detail.key);const newIndex=newEntries.indexOf(newEntry);if(newIndex===newEntries.length-1){state.entries.push(newEntry);}else{state.entries.splice(newIndex,0,newEntry);}}else if(detail.operation==="delete"&&index>=0){state.entries.splice(index,1);}};onWillStart(()=>registry.addEventListener("UPDATE",listener));onWillDestroy(()=>registry.removeEventListener("UPDATE",listener));return state;}
return __exports;});;

/* /web/static/src/core/resizable_panel/resizable_panel.js */
odoo.define('@web/core/resizable_panel/resizable_panel',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onMounted,onWillUpdateProps,onWillUnmount,useEffect,useExternalListener,useRef,useComponent,}=require("@odoo/owl");function useResizable({containerRef,handleRef,initialWidth=400,getMinWidth=()=>400,onResize=()=>{},getResizeSide=()=>"end",}){containerRef=typeof containerRef=="string"?useRef(containerRef):containerRef;handleRef=typeof handleRef=="string"?useRef(handleRef):handleRef;const props=useComponent().props;let minWidth=getMinWidth(props);let resizeSide=getResizeSide(props);let isChangingSize=false;useExternalListener(document,"mouseup",()=>onMouseUp());useExternalListener(document,"mousemove",(ev)=>onMouseMove(ev));useExternalListener(window,"resize",()=>{const limit=getLimitWidth();if(getContainerRect().width>=limit){resize(computeFinalWidth(limit));}});let docDirection;useEffect((container)=>{if(container){docDirection=getComputedStyle(container).direction;}},()=>[containerRef.el]);onMounted(()=>{if(handleRef.el){resize(initialWidth);handleRef.el.addEventListener("mousedown",onMouseDown);}});onWillUpdateProps((nextProps)=>{minWidth=getMinWidth(nextProps);resizeSide=getResizeSide(nextProps);});onWillUnmount(()=>{if(handleRef.el){handleRef.el.removeEventListener("mousedown",onMouseDown);}});function onMouseDown(){isChangingSize=true;document.body.classList.add("pe-none","user-select-none");}
function onMouseUp(){isChangingSize=false;document.body.classList.remove("pe-none","user-select-none");}
function onMouseMove(ev){if(!isChangingSize||!containerRef.el){return;}
const direction=(docDirection==="ltr"&&resizeSide==="end")||(docDirection==="rtl"&&resizeSide==="start")?1:-1;const fixedSide=direction===1?"left":"right";const containerRect=getContainerRect();const newWidth=(ev.clientX-containerRect[fixedSide])*direction;resize(computeFinalWidth(newWidth));}
function computeFinalWidth(targetContainerWidth){const handlerSpacing=handleRef.el?handleRef.el.offsetWidth/2:10;const w=Math.max(minWidth,targetContainerWidth+handlerSpacing);const limit=getLimitWidth();return Math.min(w,limit-handlerSpacing);}
function getContainerRect(){const container=containerRef.el;const offsetParent=container.offsetParent;let containerRect={};if(!offsetParent){containerRect=container.getBoundingClientRect();}else{containerRect.left=container.offsetLeft;containerRect.right=container.offsetLeft+container.offsetWidth;containerRect.width=container.offsetWidth;}
return containerRect;}
function getLimitWidth(){const offsetParent=containerRef.el.offsetParent;return offsetParent?offsetParent.offsetWidth:window.innerWidth;}
function resize(width){containerRef.el.style.setProperty("width",`${width}px`);onResize(width);}}
const ResizablePanel=__exports.ResizablePanel=class ResizablePanel extends Component{static template="web_studio.ResizablePanel";static components={};static props={onResize:{type:Function,optional:true},initialWidth:{type:Number,optional:true},minWidth:{type:Number,optional:true},class:{type:String,optional:true},slots:{type:Object},handleSide:{validate:(val)=>["start","end"].includes(val),optional:true,},};static defaultProps={onResize:()=>{},width:400,minWidth:400,class:"",handleSide:"end",};setup(){useResizable({containerRef:"containerRef",handleRef:"handleRef",onResize:this.props.onResize,initialWidth:this.props.initialWidth,getMinWidth:(props)=>props.minWidth,getResizeSide:(props)=>props.handleSide,});}
get class(){const classes=this.props.class.split(" ");if(!classes.some((cls)=>cls.startsWith("position-"))){classes.push("position-relative");}
return classes.join(" ");}}
return __exports;});;

/* /web/static/src/core/select_menu/select_menu.js */
odoo.define('@web/core/select_menu/select_menu',['@odoo/owl','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/l10n/translation','@web/core/tags_list/tags_list','@web/core/utils/classname','@web/core/utils/hooks','@web/core/utils/scrolling','@web/core/utils/search','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{Component,onWillUpdateProps,useEffect,useRef,useState}=require("@odoo/owl");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{_t}=require("@web/core/l10n/translation");const{TagsList}=require("@web/core/tags_list/tags_list");const{mergeClasses}=require("@web/core/utils/classname");const{useAutofocus,useChildRef}=require("@web/core/utils/hooks");const{scrollTo}=require("@web/core/utils/scrolling");const{fuzzyLookup}=require("@web/core/utils/search");const{useDebounced}=require("@web/core/utils/timing");const SelectMenu=__exports.SelectMenu=class SelectMenu extends Component{static template="web.SelectMenu";static choiceItemTemplate="web.SelectMenu.ChoiceItem";static components={Dropdown,DropdownItem,TagsList};static defaultProps={value:undefined,class:"",togglerClass:"",multiSelect:false,onSelect:()=>{},required:false,searchable:true,autoSort:true,searchPlaceholder:_t("Search..."),choices:[],groups:[],disabled:false,fuzzyLookupFn:(choice)=>choice.label,};static props={choices:{optional:true,type:Array,element:{type:Object,shape:{value:true,label:{type:String},"*":true,},},},groups:{type:Array,optional:true,element:{type:Object,shape:{label:{type:String,optional:true},choices:{type:Array,element:{type:Object,shape:{value:true,label:{type:String},"*":true,},},},},},},class:{type:String,optional:true},menuClass:{type:String,optional:true},togglerClass:{type:String,optional:true},required:{type:Boolean,optional:true},searchable:{type:Boolean,optional:true},autoSort:{type:Boolean,optional:true},placeholder:{type:String,optional:true},searchPlaceholder:{type:String,optional:true},value:{optional:true},multiSelect:{type:Boolean,optional:true},onInput:{type:Function,optional:true},onSelect:{type:Function,optional:true},slots:{type:Object,optional:true},disabled:{type:Boolean,optional:true},fuzzyLookupFn:{type:Function,optional:true},};static SCROLL_SETTINGS={defaultCount:500,increaseAmount:300,distanceBeforeReload:500,};setup(){this.state=useState({choices:[],displayedOptions:[],searchValue:"",});this.inputRef=useRef("inputRef");this.menuRef=useChildRef();this.debouncedOnInput=useDebounced(()=>this.onInput(this.inputRef.el?this.inputRef.el.value.trim():""),250);this.isOpen=false;this.selectedChoice=this.getSelectedChoice(this.props);onWillUpdateProps((nextProps)=>{if(this.state.choices!==nextProps.choices){this.state.choices=nextProps.choices;}
if(this.props.value!==nextProps.value){this.selectedChoice=this.getSelectedChoice(nextProps);}});useEffect(()=>{if(this.isOpen){const groups=[{choices:this.props.choices},...this.props.groups];this.filterOptions(this.state.searchValue,groups);}},()=>[this.props.choices,this.props.groups]);useAutofocus({refName:"inputRef"});}
get displayValue(){return this.selectedChoice?this.selectedChoice.label:"";}
get canDeselect(){return!this.props.required&&this.selectedChoice!==undefined;}
get multiSelectChoices(){return this.selectedChoice.map((c)=>{return{id:c.value,text:c.label,onDelete:()=>{const values=[...this.props.value];values.splice(values.indexOf(c.value),1);this.props.onSelect(values);},};});}
get menuClass(){return mergeClasses({"o_select_menu_menu border bg-light":true,"py-0":this.props.searchable,o_select_menu_multi_select:this.props.multiSelect,},this.props.menuClass);}
async onBeforeOpen(){if(this.state.searchValue.length){this.state.searchValue="";if(this.props.onInput){await this.executeOnInput("");}}
this.filterOptions();}
onStateChanged(open){this.isOpen=open;if(open){this.menuRef.el?.addEventListener("scroll",(ev)=>this.onScroll(ev));const selectedElement=this.menuRef.el?.querySelectorAll(".o_select_active")[0];if(selectedElement){scrollTo(selectedElement);}}}
isOptionSelected(choice){if(this.props.multiSelect){return this.props.value.includes(choice.value);}
return this.props.value===choice.value;}
getItemClass(choice){if(this.isOptionSelected(choice)){return"o_select_menu_item p-2 o_select_active bg-primary fw-bolder fst-italic";}else{return"o_select_menu_item p-2";}}
async executeOnInput(searchString){await this.props.onInput(searchString);}
onInput(searchString){this.filterOptions(searchString);this.state.searchValue=searchString;const inputEl=this.inputRef.el;if(inputEl&&inputEl.parentNode){inputEl.parentNode.scrollTo(0,0);}
if(this.props.onInput){this.executeOnInput(searchString);}}
getSelectedChoice(props){const choices=[...props.choices,...props.groups.flatMap((g)=>g.choices)];if(!this.props.multiSelect){return choices.find((c)=>c.value===props.value);}
const valueSet=new Set(props.value);return[...(this.selectedChoice||[]),...choices].filter((c,index,self)=>valueSet.has(c.value)&&self.findIndex((t)=>t.value===c.value)===index);}
onItemSelected(value){if(this.props.multiSelect){const values=[...this.props.value];const valueIndex=values.indexOf(value);if(valueIndex!==-1){values.splice(valueIndex,1);this.props.onSelect(values);}else{this.props.onSelect([...this.props.value,value]);}}else if(!this.selectedChoice||this.selectedChoice.value!==value){this.props.onSelect(value);}
if(this.inputRef.el){this.inputRef.el.value="";this.state.searchValue="";}}
filterOptions(searchString="",groups){const groupsList=groups||[{choices:this.props.choices},...this.props.groups];this.state.choices=[];for(const group of groupsList){let filteredOptions=[];if(searchString){filteredOptions=fuzzyLookup(searchString,group.choices,this.props.fuzzyLookupFn);}else{filteredOptions=group.choices;if(this.props.autoSort){filteredOptions.sort((optionA,optionB)=>optionA.label.localeCompare(optionB.label));}}
if(filteredOptions.length===0){continue;}
if(group.label){this.state.choices.push({...group,isGroup:true});}
this.state.choices.push(...filteredOptions);}
this.sliceDisplayedOptions();}
onScroll(event){const el=event.target;const hasReachMax=this.state.displayedOptions.length>=this.state.choices.length;const remainingDistance=el.scrollHeight-el.scrollTop;const distanceToReload=el.clientHeight+this.constructor.SCROLL_SETTINGS.distanceBeforeReload;if(!hasReachMax&&remainingDistance<distanceToReload){const displayCount=this.state.displayedOptions.length+
this.constructor.SCROLL_SETTINGS.increaseAmount;this.state.displayedOptions=this.state.choices.slice(0,displayCount);}}
sliceDisplayedOptions(){const selectedIndex=this.getSelectedOptionIndex();const defaultCount=this.constructor.SCROLL_SETTINGS.defaultCount;if(selectedIndex===-1){this.state.displayedOptions=this.state.choices.slice(0,defaultCount);}else{const endIndex=Math.max(selectedIndex+this.constructor.SCROLL_SETTINGS.increaseAmount,defaultCount);this.state.displayedOptions=this.state.choices.slice(0,endIndex);}}
getSelectedOptionIndex(){let selectedIndex=-1;for(let i=0;i<this.state.choices.length;i++){if(this.isOptionSelected(this.state.choices[i])){selectedIndex=i;}}
return selectedIndex;}}
return __exports;});;

/* /web/static/src/core/signature/name_and_signature.js */
odoo.define('@web/core/signature/name_and_signature',['@web/core/assets','@web/core/browser/feature_detection','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/network/rpc','@web/core/utils/hooks','@web/core/utils/render','@web/core/utils/urls','@odoo/owl'],function(require){'use strict';let __exports={};const{loadJS}=require("@web/core/assets");const{isMobileOS}=require("@web/core/browser/feature_detection");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{rpc}=require("@web/core/network/rpc");const{useAutofocus}=require("@web/core/utils/hooks");const{renderToString}=require("@web/core/utils/render");const{getDataURLFromFile}=require("@web/core/utils/urls");const{Component,useState,onWillStart,useRef,useEffect}=require("@odoo/owl");let htmlId=0;const NameAndSignature=__exports.NameAndSignature=class NameAndSignature extends Component{static template="web.NameAndSignature";static components={Dropdown,DropdownItem};static props={signature:{type:Object},defaultFont:{type:String,optional:true},displaySignatureRatio:{type:Number,optional:true},fontColor:{type:String,optional:true},signatureType:{type:String,optional:true},noInputName:{type:Boolean,optional:true},mode:{type:String,optional:true},onSignatureChange:{type:Function,optional:true},};static defaultProps={defaultFont:"",displaySignatureRatio:3.0,fontColor:"DarkBlue",signatureType:"signature",noInputName:false,onSignatureChange:()=>{},};setup(){this.htmlId=htmlId++;this.defaultName=this.props.signature.name||"";this.currentFont=0;this.drawTimeout=null;this.state=useState({signMode:this.props.mode||(this.props.noInputName&&!this.defaultName?"draw":"auto"),showSignatureArea:!!(this.props.noInputName||this.defaultName),showFontList:false,});this.signNameInputRef=useRef("signNameInput");this.signInputLoad=useRef("signInputLoad");useAutofocus({refName:"signNameInput"});useEffect((el)=>{if(el){el.click();}},()=>[this.signInputLoad.el]);onWillStart(async()=>{this.fonts=await rpc(`/web/sign/get_fonts/${this.props.defaultFont}`);});onWillStart(async()=>{await loadJS("/web/static/lib/signature_pad/signature_pad.umd.js");});this.signatureRef=useRef("signature");useEffect((el)=>{if(el){this.signaturePad=new SignaturePad(el,{penColor:this.props.fontColor,backgroundColor:"rgba(255,255,255,0)",minWidth:2,maxWidth:2,});this.signaturePad.addEventListener("endStroke",()=>{this.props.signature.isSignatureEmpty=this.isSignatureEmpty;this.props.onSignatureChange(this.state.signMode);});this.resetSignature();this.props.signature.getSignatureImage=()=>this.signaturePad.toDataURL();this.props.signature.resetSignature=()=>this.resetSignature();if(this.state.signMode==="auto"){this.drawCurrentName();}
if(this.props.signature.signatureImage){this.clear();this.fromDataURL(this.props.signature.signatureImage);}}},()=>[this.signatureRef.el]);}
async drawCurrentName(){const font=this.fonts[this.currentFont];const text=this.getCleanedName();const canvas=this.signatureRef.el;const img=this.getSVGText(font,text,canvas.width,canvas.height);await this.printImage(img);}
focusName(){if(!isMobileOS()&&this.signNameInputRef.el){this.signNameInputRef.el.focus();}}
clear(){this.signaturePad.clear();this.props.signature.isSignatureEmpty=this.isSignatureEmpty;}
async fromDataURL(){await this.signaturePad.fromDataURL(...arguments);this.props.signature.isSignatureEmpty=this.isSignatureEmpty;this.props.onSignatureChange(this.state.signMode);}
getCleanedName(){const text=this.props.signature.name.replace(/ /g," ");if(this.props.signatureType==="initial"&&text){return(text.split(" ").map(function(w){return w[0];}).join(".")+".");}
return text;}
getSVGText(font,text,width,height){const svg=renderToString("web.sign_svg_text",{width:width,height:height,font:font,text:text,type:this.props.signatureType,color:this.props.fontColor,});return"data:image/svg+xml,"+encodeURI(svg);}
getSVGTextFont(font){const height=100;const width=parseInt(height*this.props.displaySignatureRatio);return this.getSVGText(font,this.getCleanedName(),width,height);}
uploadFile(){this.signInputLoad.el?.click();}
async onChangeSignLoadInput(ev){var file=ev.target.files[0];if(file===undefined){return false;}
if(file.type.substr(0,5)!=="image"){this.clear();this.state.loadIsInvalid=true;return false;}
this.state.loadIsInvalid=false;const result=await getDataURLFromFile(file);await this.printImage(result);}
onClickSignAutoSelectStyle(){this.state.showFontList=true;}
onClickSignDrawClear(){this.clear();this.props.onSignatureChange(this.state.signMode);}
onClickSignLoad(){this.setMode("load");}
onClickSignAuto(){this.setMode("auto");}
onInputSignName(ev){this.props.signature.name=ev.target.value;if(!this.state.showSignatureArea&&this.getCleanedName()){this.state.showSignatureArea=true;return;}
if(this.state.signMode==="auto"){this.drawCurrentName();}}
onSelectFont(index){this.currentFont=index;this.drawCurrentName();}
async printImage(imgSrc){this.clear();const c=this.signaturePad.canvas;const img=new Image();img.onload=()=>{const ctx=c.getContext("2d");var ratio=((img.width/img.height)>(c.width/c.height))?c.width/img.width:c.height/img.height;ctx.drawImage(img,(c.width/2)-(img.width*ratio/2),(c.height/2)-(img.height*ratio/2),img.width*ratio,img.height*ratio);this.props.signature.isSignatureEmpty=this.isSignatureEmpty;this.props.onSignatureChange(this.state.signMode);};img.src=imgSrc;this.signaturePad._isEmpty=false;}
resetSignature(){this.resizeSignature();this.clear();this.setMode(this.state.signMode,true);this.focusName();}
resizeSignature(){const width=this.signatureRef.el.clientWidth;const height=parseInt(width/this.props.displaySignatureRatio);Object.assign(this.signatureRef.el,{width,height});}
setMode(mode,reset){if(reset!==true&&mode===this.signMode){return;}
this.state.signMode=mode;this.signaturePad[this.state.signMode==="draw"?"on":"off"]();this.clear();if(this.state.signMode==="auto"){this.drawCurrentName();}
this.props.onSignatureChange(this.state.signMode);}
get isSignatureEmpty(){return this.signaturePad.isEmpty();}
get loadIsInvalid(){return this.state.signMode==="load"&&this.state.loadIsInvalid;}}
return __exports;});;

/* /web/static/src/core/signature/signature_dialog.js */
odoo.define('@web/core/signature/signature_dialog',['@web/core/dialog/dialog','@web/core/signature/name_and_signature','@odoo/owl'],function(require){'use strict';let __exports={};const{Dialog}=require("@web/core/dialog/dialog");const{NameAndSignature}=require("@web/core/signature/name_and_signature");const{Component,useState}=require("@odoo/owl");const SignatureDialog=__exports.SignatureDialog=class SignatureDialog extends Component{static template="web.SignatureDialog";static components={Dialog,NameAndSignature};static props={defaultName:{type:String,optional:true},nameAndSignatureProps:Object,uploadSignature:Function,close:Function,};static defaultProps={defaultName:"",};setup(){this.signature=useState({name:this.props.defaultName,isSignatureEmpty:true,});}
onClickConfirm(){this.props.uploadSignature({name:this.signature.name,signatureImage:this.signature.getSignatureImage(),});this.props.close();}
get nameAndSignatureProps(){return{...this.props.nameAndSignatureProps,signature:this.signature,};}}
return __exports;});;

/* /web/static/src/core/tags_list/tags_list.js */
odoo.define('@web/core/tags_list/tags_list',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const TagsList=__exports.TagsList=class TagsList extends Component{static template="web.TagsList";static defaultProps={displayText:true,};static props={displayText:{type:Boolean,optional:true},visibleItemsLimit:{type:Number,optional:true},tags:{type:Object},};get visibleTagsCount(){return this.props.visibleItemsLimit-1;}
get visibleTags(){if(this.props.visibleItemsLimit&&this.props.tags.length>this.props.visibleItemsLimit){return this.props.tags.slice(0,this.visibleTagsCount);}
return this.props.tags;}
get otherTags(){if(!this.props.visibleItemsLimit||this.props.tags.length<=this.props.visibleItemsLimit){return[];}
return this.props.tags.slice(this.visibleTagsCount);}
get tooltipInfo(){return JSON.stringify({tags:this.otherTags.map((tag)=>({text:tag.text,id:tag.id,})),});}}
return __exports;});;

/* /web/static/src/core/template_inheritance.js */
odoo.define('@web/core/template_inheritance',[],function(require){'use strict';let __exports={};const RSTRIP_REGEXP=/(?=\n[ \t]*$)/;function addBefore(target,operation){const nodes=getNodes(target,operation);if(nodes.length===0){return;}
const{previousSibling}=target;target.before(...nodes);if(previousSibling?.nodeType===Node.TEXT_NODE){const[text1,text2]=previousSibling.data.split(RSTRIP_REGEXP);previousSibling.data=text1.trimEnd();if(nodes[0].nodeType===Node.TEXT_NODE){mergeTextNodes(previousSibling,nodes[0]);}
if(text2&&nodes.some((n)=>n.nodeType!==Node.TEXT_NODE)){const textNode=document.createTextNode(text2);target.before(textNode);if(textNode.previousSibling.nodeType===Node.TEXT_NODE){mergeTextNodes(textNode.previousSibling,textNode);}}}}
function getRoot(element){while(element.parentElement){element=element.parentElement;}
return element;}
const HASCLASS_REGEXP=/hasclass\(([^)]*)\)/g;function getXpath(operation){const xpath=operation.getAttribute("expr");return xpath.replaceAll(HASCLASS_REGEXP,(_,capturedGroup)=>{return capturedGroup.split(",").map((c)=>`contains(concat(' ', @class, ' '), ' ${c.trim().slice(1, -1)} ')`).join(" and ");});}
function getNode(element,operation){const root=getRoot(element);const doc=new Document();doc.appendChild(root);if(operation.tagName==="xpath"){const xpath=getXpath(operation);const result=doc.evaluate(xpath,root,null,XPathResult.FIRST_ORDERED_NODE_TYPE);return result.singleNodeValue;}
for(const elem of root.querySelectorAll(operation.tagName)){if([...operation.attributes].every(({name,value})=>name==="position"||elem.getAttribute(name)===value)){return elem;}}
return null;}
function getElement(element,operation){const node=getNode(element,operation);if(!node){throw new Error(`Element '${operation.outerHTML}' cannot be located in element tree`);}
if(!(node instanceof Element)){throw new Error(`Found node ${node} instead of an element`);}
return node;}
function getNodes(element,operation){const nodes=[];for(const childNode of operation.childNodes){if(childNode.tagName==="xpath"&&childNode.getAttribute?.("position")==="move"){const node=getElement(element,childNode);removeNode(node);nodes.push(node);}else{nodes.push(childNode);}}
return nodes;}
function mergeTextNodes(first,second,trimEnd=true){first.data=(trimEnd?first.data.trimEnd():first.data)+second.data;second.remove();}
function splitAndTrim(str,separator){return str.split(separator).map((s)=>s.trim());}
function modifyAttributes(target,operation){for(const child of operation.children){if(child.tagName!=="attribute"){continue;}
const attributeName=child.getAttribute("name");const firstNode=child.childNodes[0];let value=firstNode?.nodeType===Node.TEXT_NODE?firstNode.data:"";const add=child.getAttribute("add")||"";const remove=child.getAttribute("remove")||"";if(add||remove){if(firstNode?.nodeType===Node.TEXT_NODE){throw new Error(`Useless element content ${firstNode.outerHTML}`);}
const separator=child.getAttribute("separator")||",";const toRemove=new Set(splitAndTrim(remove,separator));const values=splitAndTrim(target.getAttribute(attributeName)||"",separator).filter((s)=>!toRemove.has(s));values.push(...splitAndTrim(add,separator).filter((s)=>s));value=values.join(separator);}
if(value){target.setAttribute(attributeName,value);}else{target.removeAttribute(attributeName);}}}
function removeNode(node){const{nextSibling,previousSibling}=node;node.remove();if(nextSibling?.nodeType===Node.TEXT_NODE&&previousSibling?.nodeType===Node.TEXT_NODE){mergeTextNodes(previousSibling,nextSibling,previousSibling.parentElement.firstChild===previousSibling);}}
function replace(root,target,operation){const mode=operation.getAttribute("mode")||"outer";switch(mode){case"outer":{const result=operation.ownerDocument.evaluate(".//*[text()='$0']",operation,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);for(let i=0;i<result.snapshotLength;i++){const loc=result.snapshotItem(i);loc.firstChild.replaceWith(target.cloneNode(true));}
if(target.parentElement){const nodes=getNodes(target,operation);target.replaceWith(...nodes);}else{let operationContent=null;let comment=null;for(const child of operation.childNodes){if(child.nodeType===Node.ELEMENT_NODE){operationContent=child;break;}
if(child.nodeType===Node.COMMENT_NODE){comment=child;}}
root=operationContent.cloneNode(true);if(target.hasAttribute("t-name")){root.setAttribute("t-name",target.getAttribute("t-name"));}
if(comment){root.prepend(comment);}}
break;}
case"inner":while(target.firstChild){target.removeChild(target.lastChild);}
target.append(...operation.childNodes);break;default:throw new Error(`Invalid mode attribute: '${mode}'`);}
return root;}
__exports.applyInheritance=applyInheritance;function applyInheritance(root,operations,url=""){for(const operation of operations.children){const target=getElement(root,operation);const position=operation.getAttribute("position")||"inside";if(odoo.debug&&url){const attributes=[...operation.attributes].map(({name,value})=>`${name}=${JSON.stringify(name === "position" ? position : value)}`);const comment=document.createComment(` From file: ${url} ; ${attributes.join(" ; ")} `);if(position==="attributes"){target.before(comment);}else{operation.prepend(comment);}}
switch(position){case"replace":{root=replace(root,target,operation);break;}
case"attributes":{modifyAttributes(target,operation);break;}
case"inside":{const sentinel=document.createElement("sentinel");target.append(sentinel);addBefore(sentinel,operation);removeNode(sentinel);break;}
case"after":{const sentinel=document.createElement("sentinel");target.after(sentinel);addBefore(sentinel,operation);removeNode(sentinel);break;}
case"before":{addBefore(target,operation);break;}
default:throw new Error(`Invalid position attribute: '${position}'`);}}
return root;}
return __exports;});;

/* /web/static/src/core/templates.js */
odoo.define('@web/core/templates',['@web/core/template_inheritance'],function(require){'use strict';let __exports={};const{applyInheritance}=require("@web/core/template_inheritance");function getClone(template){const c=template.cloneNode(true);new Document().append(c);return c;}
function getParsedTemplate(templateString){const doc=parser.parseFromString(templateString,"text/xml");for(const processor of templateProcessors){processor(doc);}
return doc.firstChild;}
function _getTemplate(name,blockId=null){if(!(name in parsedTemplates)){if(!(name in templates)){return null;}
const templateString=templates[name];parsedTemplates[name]=getParsedTemplate(templateString);}
let processedTemplate=parsedTemplates[name];const inheritFrom=processedTemplate.getAttribute("t-inherit");if(inheritFrom){const parentTemplate=_getTemplate(inheritFrom,blockId||info[name].blockId);if(!parentTemplate){throw new Error(`Constructing template ${name}: template parent ${inheritFrom} not found`);}
const element=getClone(processedTemplate);processedTemplate=applyInheritance(getClone(parentTemplate),element,info[name].url);if(processedTemplate.tagName!==element.tagName){const temp=processedTemplate;processedTemplate=new Document().createElement(element.tagName);processedTemplate.append(...temp.childNodes);}
for(const{name,value}of element.attributes){if(!["t-inherit","t-inherit-mode"].includes(name)){processedTemplate.setAttribute(name,value);}}}
for(const otherBlockId in templateExtensions[name]||{}){if(blockId&&otherBlockId>blockId){break;}
if(!(name in parsedTemplateExtensions)){parsedTemplateExtensions[name]={};}
if(!(otherBlockId in parsedTemplateExtensions[name])){parsedTemplateExtensions[name][otherBlockId]=[];for(const{templateString,url}of templateExtensions[name][otherBlockId]){parsedTemplateExtensions[name][otherBlockId].push({template:getParsedTemplate(templateString),url,});}}
for(const{template,url}of parsedTemplateExtensions[name][otherBlockId]){if(!urlFilters.every((filter)=>filter(url))){continue;}
processedTemplate=applyInheritance(inheritFrom?processedTemplate:getClone(processedTemplate),getClone(template),url);}}
return processedTemplate;}
function isRegistered(...args){const key=JSON.stringify([...args]);if(registered.has(key)){return true;}
registered.add(key);return false;}
const info=Object.create(null);const parsedTemplateExtensions=Object.create(null);const parsedTemplates=Object.create(null);const parser=new DOMParser();const processedTemplates=new Map();const registered=new Set();const templateExtensions=Object.create(null);const templateProcessors=[];const templates=Object.create(null);let blockType=null;let blockId=0;let urlFilters=[];__exports.checkPrimaryTemplateParents=checkPrimaryTemplateParents;function checkPrimaryTemplateParents(namesToCheck){const missing=new Set(namesToCheck.filter((name)=>!(name in templates)));if(missing.size){console.error(`Missing (primary) parent templates: ${[...missing].join(", ")}`);}}
__exports.clearProcessedTemplates=clearProcessedTemplates;function clearProcessedTemplates(){processedTemplates.clear();}
__exports.getTemplate=getTemplate;function getTemplate(name){if(!processedTemplates.has(name)){processedTemplates.set(name,_getTemplate(name));}
return processedTemplates.get(name);}
__exports.registerTemplate=registerTemplate;function registerTemplate(name,url,templateString){if(isRegistered(...arguments)){return;}
if(blockType!=="templates"){blockType="templates";blockId++;}
if(name in templates&&(info[name].url!==url||templates[name]!==templateString)){throw new Error(`Template ${name} already exists`);}
templates[name]=templateString;info[name]={blockId,url};}
__exports.registerTemplateExtension=registerTemplateExtension;function registerTemplateExtension(inheritFrom,url,templateString){if(isRegistered(...arguments)){return;}
if(blockType!=="extensions"){blockType="extensions";blockId++;}
if(!templateExtensions[inheritFrom]){templateExtensions[inheritFrom]=[];}
if(!templateExtensions[inheritFrom][blockId]){templateExtensions[inheritFrom][blockId]=[];}
templateExtensions[inheritFrom][blockId].push({templateString,url,});}
__exports.registerTemplateProcessor=registerTemplateProcessor;function registerTemplateProcessor(processor){templateProcessors.push(processor);}
__exports.setUrlFilters=setUrlFilters;function setUrlFilters(filters){urlFilters=filters;}
return __exports;});;

/* /web/static/src/core/tooltip/tooltip.js */
odoo.define('@web/core/tooltip/tooltip',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const Tooltip=__exports.Tooltip=class Tooltip extends Component{static template="web.Tooltip";static props={close:Function,tooltip:{type:String,optional:true},template:{type:String,optional:true},info:{optional:true},};}
return __exports;});;

/* /web/static/src/core/tooltip/tooltip_hook.js */
odoo.define('@web/core/tooltip/tooltip_hook',['@web/core/utils/hooks','@odoo/owl'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{useEffect,useRef}=require("@odoo/owl");__exports.useTooltip=useTooltip;function useTooltip(refName,params){const tooltip=useService("tooltip");const ref=useRef(refName);useEffect((el)=>tooltip.add(el,params),()=>[ref.el]);}
return __exports;});;

/* /web/static/src/core/tooltip/tooltip_service.js */
odoo.define('@web/core/tooltip/tooltip_service',['@web/core/browser/browser','@web/core/registry','@web/core/tooltip/tooltip','@web/core/browser/feature_detection','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{registry}=require("@web/core/registry");const{Tooltip}=require("@web/core/tooltip/tooltip");const{hasTouch}=require("@web/core/browser/feature_detection");const{whenReady}=require("@odoo/owl");const OPEN_DELAY=__exports.OPEN_DELAY=400;const CLOSE_DELAY=__exports.CLOSE_DELAY=200;const SHOW_AFTER_DELAY=__exports.SHOW_AFTER_DELAY=250;const tooltipService=__exports.tooltipService={dependencies:["popover"],start(env,{popover}){let openTooltipTimeout;let closeTooltip;let showTimer;let target=null;const elementsWithTooltips=new WeakMap();function cleanup(){target=null;browser.clearTimeout(openTooltipTimeout);openTooltipTimeout=null;if(closeTooltip){closeTooltip();closeTooltip=null;}}
function shouldCleanup(){if(!target){return false;}
if(!document.body.contains(target)){return true;}
return false;}
function openTooltip(el,{tooltip="",template,info,position,delay=OPEN_DELAY}){cleanup();if(!tooltip&&!template){return;}
target=el;openTooltipTimeout=browser.setTimeout(()=>{if(target.isConnected){closeTooltip=popover.add(target,Tooltip,{tooltip,template,info},{position});target.title="";}},delay);}
function openElementsTooltip(el){if(el.nodeType===Node.TEXT_NODE){return;}
const element=el.closest("[data-tooltip], [data-tooltip-template]");if(elementsWithTooltips.has(el)){openTooltip(el,elementsWithTooltips.get(el));}else if(element){const dataset=element.dataset;const params={tooltip:dataset.tooltip,template:dataset.tooltipTemplate,position:dataset.tooltipPosition,};if(dataset.tooltipInfo){params.info=JSON.parse(dataset.tooltipInfo);}
if(dataset.tooltipDelay){params.delay=parseInt(dataset.tooltipDelay,10);}
openTooltip(element,params);}}
function onMouseenter(ev){openElementsTooltip(ev.target);}
function cleanupTooltip(ev){if(target===ev.target.closest("[data-tooltip], [data-tooltip-template]")){cleanup();}}
function onTouchStart(ev){cleanup();showTimer=browser.setTimeout(()=>{openElementsTooltip(ev.target);},SHOW_AFTER_DELAY);}
whenReady(()=>{browser.setInterval(()=>{if(shouldCleanup()){cleanup();}},CLOSE_DELAY);if(hasTouch()){document.body.addEventListener("touchstart",onTouchStart);document.body.addEventListener("touchend",(ev)=>{if(ev.target.closest("[data-tooltip], [data-tooltip-template]")){if(!ev.target.dataset.tooltipTouchTapToShow){browser.clearTimeout(showTimer);browser.clearTimeout(openTooltipTimeout);}}});document.body.addEventListener("touchcancel",(ev)=>{if(ev.target.closest("[data-tooltip], [data-tooltip-template]")){if(!ev.target.dataset.tooltipTouchTapToShow){browser.clearTimeout(showTimer);browser.clearTimeout(openTooltipTimeout);}}});}
document.body.addEventListener("mouseenter",onMouseenter,{capture:true});document.body.addEventListener("mouseleave",cleanupTooltip,{capture:true});document.body.addEventListener("click",cleanupTooltip,{capture:true});});return{add(el,params){elementsWithTooltips.set(el,params);return()=>{elementsWithTooltips.delete(el);if(target===el){cleanup();}};},};},};registry.category("services").add("tooltip",tooltipService);return __exports;});;

/* /web/static/src/core/transition.js */
odoo.define('@web/core/transition',['@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{Component,onWillUpdateProps,status,useComponent,useEffect,useState,xml,}=require("@odoo/owl");const config=__exports.config={disabled:false,};__exports.useTransition=useTransition;function useTransition({name,initialVisibility=true,immediate=false,leaveDuration=500,onLeave=()=>{},}){const component=useComponent();const state=useState({shouldMount:initialVisibility,stage:initialVisibility?"enter":"leave",});if(config.disabled){return{get shouldMount(){return state.shouldMount;},set shouldMount(val){state.shouldMount=val;},get className(){return`${name} ${name}-enter-active`;},get stage(){return"enter-active";},};}
let onNextPatch=null;useEffect(()=>{if(onNextPatch){onNextPatch();onNextPatch=null;}});let prevState,timer;const transition={get shouldMount(){return state.shouldMount;},set shouldMount(newState){if(newState===prevState){return;}
browser.clearTimeout(timer);prevState=newState;if(newState){if(status(component)==="mounted"||immediate){state.stage="enter";component.render();onNextPatch=()=>{state.stage="enter-active";};}else{state.stage="enter-active";}
state.shouldMount=true;}else{state.stage="leave";timer=browser.setTimeout(()=>{state.shouldMount=false;onLeave();},leaveDuration);}},get className(){return`${name} ${name}-${state.stage}`;},get stage(){return state.stage;},};transition.shouldMount=initialVisibility;return transition;}
const Transition=__exports.Transition=class Transition extends Component{static template=xml`<t t-slot="default" t-if="transition.shouldMount" className="transition.className"/>`;static props={name:String,visible:{type:Boolean,optional:true},immediate:{type:Boolean,optional:true},leaveDuration:{type:Number,optional:true},onLeave:{type:Function,optional:true},slots:Object,};setup(){const{immediate,visible,leaveDuration,name,onLeave}=this.props;this.transition=useTransition({initialVisibility:visible,immediate,leaveDuration,name,onLeave,});onWillUpdateProps(({visible=true})=>{this.transition.shouldMount=visible;});}}
return __exports;});;

/* /web/static/src/core/tree_editor/condition_tree.js */
odoo.define('@web/core/tree_editor/condition_tree',['@web/core/domain','@web/core/py_js/py','@web/core/py_js/py_utils','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{Domain}=require("@web/core/domain");const{formatAST,parseExpr}=require("@web/core/py_js/py");const{toPyValue}=require("@web/core/py_js/py_utils");const{deepCopy,deepEqual}=require("@web/core/utils/objects");const TERM_OPERATORS_NEGATION=__exports.TERM_OPERATORS_NEGATION={"<":">=",">":"<=","<=":">",">=":"<","=":"!=","!=":"=",in:"not in",like:"not like",ilike:"not ilike","not in":"in","not like":"like","not ilike":"ilike",};const TERM_OPERATORS_NEGATION_EXTENDED={...TERM_OPERATORS_NEGATION,is:"is not","is not":"is","==":"!=","!=":"==",};const EXCHANGE={"<":">","<=":">=",">":"<",">=":"<=","=":"=","!=":"!=",};const COMPARATORS=["<","<=",">",">=","in","not in","==","is","!=","is not"];const DATETIME_TODAY_STRING_EXPRESSION=`datetime.datetime.combine(context_today(), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")`;const DATE_TODAY_STRING_EXPRESSION=`context_today().strftime("%Y-%m-%d")`;const DELTA_DATE_AST=parseExpr(`(context_today() + relativedelta(period=amount)).strftime('%Y-%m-%d')`);const DELTA_DATETIME_AST=parseExpr(`datetime.datetime.combine(context_today() + relativedelta(period=amount), datetime.time(0, 0, 0)).to_utc().strftime("%Y-%m-%d %H:%M:%S")`);function replaceKwargs(ast,fieldType,kwargs={}){const astCopy=deepCopy(ast);if(fieldType==="date"){astCopy.fn.obj.right.kwargs=kwargs;}else{astCopy.fn.obj.fn.obj.args[0].right.kwargs=kwargs;}
return astCopy;}
function getDelta(ast,fieldType){const kwargs=(fieldType==="date"?ast.fn?.obj?.right?.kwargs:ast.fn?.obj?.fn?.obj?.args?.[0]?.right?.kwargs)||{};if(Object.keys(kwargs).length!==1){return null;}
if(!deepEqual(replaceKwargs(ast,fieldType),replaceKwargs(fieldType==="date"?DELTA_DATE_AST:DELTA_DATETIME_AST,fieldType))){return null;}
const[option,amountAST]=Object.entries(kwargs)[0];return[toValue(amountAST),option];}
function getDeltaExpression(value,fieldType){const ast=replaceKwargs(fieldType==="date"?DELTA_DATE_AST:DELTA_DATETIME_AST,fieldType,{[value[1]]:toAST(value[0])});return expression(formatAST(ast));}
function isTodayExpr(val,type){return(val._expr===(type==="date"?DATE_TODAY_STRING_EXPRESSION:DATETIME_TODAY_STRING_EXPRESSION));}
const Couple=__exports.Couple=class Couple{constructor(x,y){this.fst=x;this.snd=y;}}
const Expression=__exports.Expression=class Expression{constructor(ast){if(typeof ast==="string"){ast=parseExpr(ast);}
this._ast=ast;this._expr=formatAST(ast);}
toAST(){return this._ast;}
toString(){return this._expr;}}
__exports.expression=expression;function expression(expr){return new Expression(expr);}
__exports.connector=connector;function connector(value,children=[],negate=false){return{type:"connector",value,children,negate};}
__exports.condition=condition;function condition(path,operator,value,negate=false){return{type:"condition",path,operator,value,negate};}
__exports.complexCondition=complexCondition;function complexCondition(value){parseExpr(value);return{type:"complex_condition",value};}
function treeContainsExpressions(tree){if(tree.type==="condition"){const{path,operator,value}=tree;if(isTree(value)&&treeContainsExpressions(value)){return true;}
return[path,operator,value].some((v)=>v instanceof Expression||(Array.isArray(v)&&v.some((w)=>w instanceof Expression)));}
for(const child of tree.children){if(treeContainsExpressions(child)){return true;}}
return false;}
__exports.domainContainsExpresssions=domainContainsExpresssions;function domainContainsExpresssions(domain){let tree;try{tree=treeFromDomain(domain);}catch{return null;}
return treeContainsExpressions(tree);}
function cloneValue(value){if(value instanceof Expression){return new Expression(value.toAST());}
if(Array.isArray(value)){return value.map(cloneValue);}
return value;}
__exports.cloneTree=cloneTree;function cloneTree(tree){const clone={};for(const key in tree){clone[key]=cloneValue(tree[key]);}
return clone;}
__exports.formatValue=formatValue;function formatValue(value){return formatAST(toAST(value));}
__exports.normalizeValue=normalizeValue;function normalizeValue(value){return toValue(toAST(value));}
__exports.toValue=toValue;function toValue(ast,isWithinArray=false){if([4,10].includes(ast.type)&&!isWithinArray){return ast.value.map((v)=>toValue(v,true));}else if([0,1,2].includes(ast.type)){return ast.value;}else if(ast.type===6&&ast.op==="-"&&ast.right.type===0){return-ast.right.value;}else if(ast.type===5&&["false","true"].includes(ast.value)){return JSON.parse(ast.value);}else{return new Expression(ast);}}
__exports.isTree=isTree;function isTree(value){return(typeof value==="object"&&!(value instanceof Domain)&&!(value instanceof Expression)&&!Array.isArray(value)&&value!==null);}
function toAST(value){if(isTree(value)){const domain=new Domain(domainFromTree(value));return domain.ast;}
if(value instanceof Expression){return value.toAST();}
if(Array.isArray(value)){return{type:4,value:value.map(toAST)};}
return toPyValue(value);}
function addChild(parent,child){if(child.type==="connector"&&!child.negate&&child.value===parent.value){parent.children.push(...child.children);}else{parent.children.push(child);}}
function getNormalizedCondition(condition){let{operator,negate}=condition;if(negate&&typeof operator==="string"&&TERM_OPERATORS_NEGATION[operator]){operator=TERM_OPERATORS_NEGATION[operator];negate=false;}
return{...condition,operator,negate};}
function normalizeCondition(condition){Object.assign(condition,getNormalizedCondition(condition));}
function _construcTree(ASTs,options={},negate=false){const[firstAST,...tailASTs]=ASTs;if(firstAST.type===1&&firstAST.value==="!"){return _construcTree(tailASTs,options,!negate);}
const tree={type:firstAST.type===1?"connector":"condition"};if(tree.type==="connector"){tree.value=firstAST.value;if(options.distributeNot&&negate){tree.value=tree.value==="&"?"|":"&";tree.negate=false;}else{tree.negate=negate;}
tree.children=[];}else{const[pathAST,operatorAST,valueAST]=firstAST.value;tree.path=toValue(pathAST);tree.negate=negate;tree.operator=toValue(operatorAST);tree.value=toValue(valueAST);if(["any","not any"].includes(tree.operator)){try{tree.value=treeFromDomain(formatAST(valueAST),{...options,getFieldDef:(p)=>options.getFieldDef?.(new Couple(tree.path,p))||null,});}catch{tree.value=Array.isArray(tree.value)?tree.value:[tree.value];}}
normalizeCondition(tree);}
let remaimingASTs=tailASTs;if(tree.type==="connector"){for(let i=0;i<2;i++){const{tree:child,remaimingASTs:otherASTs}=_construcTree(remaimingASTs,options,options.distributeNot&&negate);remaimingASTs=otherASTs;addChild(tree,child);}}
return{tree,remaimingASTs};}
function construcTree(initialASTs,options={}){if(!initialASTs.length){return connector("&");}
const{tree}=_construcTree(initialASTs,options);return tree;}
function getASTs(tree){const ASTs=[];if(tree.type==="condition"){if(tree.negate){ASTs.push(toAST("!"));}
ASTs.push({type:10,value:[tree.path,tree.operator,tree.value].map(toAST),});return ASTs;}
const length=tree.children.length;if(length&&tree.negate){ASTs.push(toAST("!"));}
for(let i=0;i<length-1;i++){ASTs.push(toAST(tree.value));}
for(const child of tree.children){ASTs.push(...getASTs(child));}
return ASTs;}
function not(ast){if(isNot(ast)){return ast.right;}
if(ast.type===2){return{...ast,value:!ast.value};}
if(ast.type===7&&COMPARATORS.includes(ast.op)){return{...ast,op:TERM_OPERATORS_NEGATION_EXTENDED[ast.op]};}
return{type:6,op:"not",right:isBool(ast)?ast.args[0]:ast};}
function bool(ast){if(isBool(ast)||isNot(ast)||ast.type===2){return ast;}
return{type:8,fn:{type:5,value:"bool"},args:[ast],kwargs:{}};}
function name(value){return{type:5,value};}
function or(left,right){return{type:14,op:"or",left,right};}
function and(left,right){return{type:14,op:"and",left,right};}
function isNot(ast){return ast.type===6&&ast.op==="not";}
function is(oneParamFunc,ast){return(ast.type===8&&ast.fn.type===5&&ast.fn.value===oneParamFunc&&ast.args.length===1);}
function isSet(ast){return ast.type===8&&ast.fn.type===5&&ast.fn.value==="set"&&ast.args.length<=1;}
function isBool(ast){return is("bool",ast);}
function isValidPath(ast,options){const getFieldDef=options.getFieldDef||(()=>null);if(ast.type===5){return getFieldDef(ast.value)!==null;}
return false;}
function isX2Many(ast,options){if(isValidPath(ast,options)){const fieldDef=options.getFieldDef(ast.value);return["many2many","one2many"].includes(fieldDef.type);}
return false;}
function _getConditionFromComparator(ast,options){if(["is","is not"].includes(ast.op)){return null;}
let operator=ast.op;if(operator==="=="){operator="=";}
let left=ast.left;let right=ast.right;if(isValidPath(left,options)==isValidPath(right,options)){return null;}
if(!isValidPath(left,options)){if(operator in EXCHANGE){const temp=left;left=right;right=temp;operator=EXCHANGE[operator];}else{return null;}}
return condition(left.value,operator,toValue(right));}
function isValidPath2(ast,options){if(!ast){return null;}
if([4,10].includes(ast.type)&&ast.value.length===1){return isValidPath(ast.value[0],options);}
return isValidPath(ast,options);}
function _getConditionFromIntersection(ast,options,negate=false){let left=ast.fn.obj.args[0];let right=ast.args[0];if(!left){return condition(negate?1:0,"=",1);}
if(isValidPath2(left,options)==isValidPath2(right,options)){return null;}
if(!isValidPath2(left,options)){const temp=left;left=right;right=temp;}
if([4,10].includes(left.type)&&left.value.length===1){left=left.value[0];}
if(!right){return condition(left.value,negate?"=":"!=",false);}
if(isSet(right)){if(!right.args[0]){right={type:4,value:[]};}
if([4,10].includes(right.args[0].type)){right=right.args[0];}}
if(![4,10].includes(right.type)){return null;}
return condition(left.value,negate?"not in":"in",toValue(right));}
function _leafFromAST(ast,options,negate=false){if(isNot(ast)){return _treeFromAST(ast.right,options,!negate);}
if(ast.type===5&&isValidPath(ast,options)){return condition(ast.value,negate?"=":"!=",false);}
const astValue=toValue(ast);if(["boolean","number","string"].includes(typeof astValue)){return condition(astValue?1:0,"=",1);}
if(ast.type===8&&ast.fn.type===15&&isSet(ast.fn.obj)&&ast.fn.key==="intersection"){const tree=_getConditionFromIntersection(ast,options,negate);if(tree){return tree;}}
if(ast.type===7&&COMPARATORS.includes(ast.op)){if(negate){return _leafFromAST(not(ast),options);}
const tree=_getConditionFromComparator(ast,options);if(tree){return tree;}}
return complexCondition(formatAST(negate?not(ast):ast));}
function _treeFromAST(ast,options,negate=false){if(isNot(ast)){return _treeFromAST(ast.right,options,!negate);}
if(ast.type===14){const tree=connector(ast.op==="and"?"&":"|");if(options.distributeNot&&negate){tree.value=tree.value==="&"?"|":"&";}else{tree.negate=negate;}
const subASTs=[ast.left,ast.right];for(const subAST of subASTs){const child=_treeFromAST(subAST,options,options.distributeNot&&negate);addChild(tree,child);}
return tree;}
if(ast.type===13){const newAST=or(and(ast.condition,ast.ifTrue),and(not(ast.condition),ast.ifFalse));return _treeFromAST(newAST,options,negate);}
return _leafFromAST(ast,options,negate);}
function _expressionFromTree(tree,options,isRoot=false){if(tree.type==="connector"&&tree.value==="|"&&tree.children.length===2){const isSimpleAnd=(tree)=>tree.type==="connector"&&tree.value==="&"&&tree.children.length===2;if(tree.children.every((c)=>isSimpleAnd(c))){const[c1,c2]=tree.children;for(let i=0;i<2;i++){const c1Child=c1.children[i];const str1=_expressionFromTree({...c1Child},options);for(let j=0;j<2;j++){const c2Child=c2.children[j];const str2=_expressionFromTree(c2Child,options);if(str1===`not ${str2}`||`not ${str1}`===str2){const others=[c1.children[1-i],c2.children[1-j]];const str=_expressionFromTree(c1Child,options);const strs=others.map((c)=>_expressionFromTree(c,options));return`${strs[0]} if ${str} else ${strs[1]}`;}}}}}
if(tree.type==="connector"){const connector=tree.value==="&"?"and":"or";const subExpressions=tree.children.map((c)=>_expressionFromTree(c,options));if(!subExpressions.length){return connector==="and"?"1":"0";}
let expression=subExpressions.join(` ${connector} `);if(!isRoot||tree.negate){expression=`( ${expression} )`;}
if(tree.negate){expression=`not ${expression}`;}
return expression;}
if(tree.type==="complex_condition"){return tree.value;}
tree=getNormalizedCondition(tree);const{path,operator,value}=tree;const op=operator==="="?"==":operator;if(typeof op!=="string"||!COMPARATORS.includes(op)){throw new Error("Invalid operator");}
if([0,1].includes(path)){if(operator!=="="||value!==1){return new Error("Invalid condition");}
return formatAST({type:2,value:Boolean(path)});}
const pathAST=toAST(path);if(typeof path=="string"&&isValidPath(name(path),options)){pathAST.type=5;}
if(value===false&&["=","!="].includes(operator)){return formatAST(operator==="="?not(pathAST):pathAST);}
let valueAST=toAST(value);if(["in","not in"].includes(operator)&&!(value instanceof Expression)&&![4,10].includes(valueAST.type)){valueAST={type:4,value:[valueAST]};}
if(pathAST.type===5&&isX2Many(pathAST,options)&&["in","not in"].includes(operator)){const ast={type:8,fn:{type:15,obj:{args:[pathAST],type:8,fn:{type:5,value:"set",},},key:"intersection",},args:[valueAST],};return formatAST(operator==="not in"?not(ast):ast);}
return formatAST({type:7,op,left:pathAST,right:valueAST,});}
function createBetweenOperators(tree){if(["condition","complex_condition"].includes(tree.type)){return tree;}
const processedChildren=tree.children.map(createBetweenOperators);if(tree.value==="|"){return{...tree,children:processedChildren};}
const children=[];for(let i=0;i<processedChildren.length;i++){const child1=processedChildren[i];const child2=processedChildren[i+1];if(child1.type==="condition"&&child2&&child2.type==="condition"&&formatValue(child1.path)===formatValue(child2.path)&&child1.operator===">="&&child2.operator==="<="){children.push(condition(child1.path,"between",normalizeValue([child1.value,child2.value])));i+=1;}else{children.push(child1);}}
if(children.length===1){return{...children[0]};}
return{...tree,children};}
function createWithinOperators(tree,options={}){if(tree.children){return{...tree,children:tree.children.map((child)=>createWithinOperators(child,options)),};}
const fieldType=options.getFieldDef?.(tree.path)?.type;if(tree.operator!=="between"||!["date","datetime"].includes(fieldType)){return tree;}
function getProcessedDelta(val,periodShouldBePositive=true){const delta=getDelta(toAST(val),fieldType);if(delta){const[amount]=delta;if(Number.isInteger(amount)&&((amount<0&&periodShouldBePositive)||(amount>0&&!periodShouldBePositive))){return null;}}
return delta;}
const newTree={...tree};if(isTodayExpr(newTree.value[0],fieldType)){const delta=getProcessedDelta(newTree.value[1]);if(delta){newTree.operator="within";newTree.value=[...delta,fieldType];}}else if(isTodayExpr(newTree.value[1],fieldType)){const delta=getProcessedDelta(newTree.value[0],false);if(delta){newTree.operator="within";newTree.value=[...delta,fieldType];}}
return newTree;}
__exports.removeBetweenOperators=removeBetweenOperators;function removeBetweenOperators(tree){if(tree.type==="complex_condition"){return tree;}
if(tree.type==="condition"){if(tree.operator!=="between"){return tree;}
const{negate,path,value}=tree;return connector("&",[condition(path,">=",value[0]),condition(path,"<=",value[1])],negate);}
const processedChildren=tree.children.map(removeBetweenOperators);if(tree.value==="|"){return{...tree,children:processedChildren};}
const newTree={...tree,children:[]};for(let i=0;i<processedChildren.length;i++){addChild(newTree,processedChildren[i]);}
return newTree;}
__exports.removeWithinOperators=removeWithinOperators;function removeWithinOperators(tree){if(tree.type==="complex_condition"){return tree;}
if(tree.type==="condition"){if(tree.operator!=="within"){return tree;}
const{negate,path,value}=tree;const fieldType=value[2];const expressions=[expression(fieldType==="date"?DATE_TODAY_STRING_EXPRESSION:DATETIME_TODAY_STRING_EXPRESSION),getDeltaExpression(value,fieldType),];const reverse=Number.isInteger(value[0])&&value[0]>0;return condition(path,"between",reverse?Object.values(expressions):Object.values(expressions).reverse(),negate);}
const processedChildren=tree.children.map(removeWithinOperators);return{...tree,children:processedChildren};}
__exports.createVirtualOperators=createVirtualOperators;function createVirtualOperators(tree,options={}){if(tree.type==="condition"){const{path,operator,value}=tree;if(["=","!="].includes(operator)){const fieldDef=options.getFieldDef?.(path)||null;if(fieldDef){if(fieldDef.type==="boolean"){return{...tree,operator:operator==="="?"is":"is_not"};}else if(!["many2one","date","datetime"].includes(fieldDef?.type)&&value===false){return{...tree,operator:operator==="="?"not_set":"set"};}}}
if(operator==="=ilike"){if(value.endsWith?.("%")){return{...tree,operator:"starts_with",value:value.slice(0,-1)};}
if(value.startsWith?.("%")){return{...tree,operator:"ends_with",value:value.slice(1)};}}
return tree;}
if(tree.type==="complex_condition"){return tree;}
const processedChildren=tree.children.map((c)=>createVirtualOperators(c,options));return{...tree,children:processedChildren};}
__exports.removeVirtualOperators=removeVirtualOperators;function removeVirtualOperators(tree){if(tree.type==="condition"){const{operator,value}=tree;if(["is","is_not"].includes(operator)){return{...tree,operator:operator==="is"?"=":"!="};}
if(["set","not_set"].includes(operator)){return{...tree,operator:operator==="set"?"!=":"="};}
if(["starts_with","ends_with"].includes(operator)){return{...tree,value:operator==="starts_with"?`${value}%`:`%${value}`,operator:"=ilike",};}
return tree;}
if(tree.type==="complex_condition"){return tree;}
const processedChildren=tree.children.map((c)=>removeVirtualOperators(c));return{...tree,children:processedChildren};}
function createComplexConditions(tree){if(tree.type==="condition"){if(tree.path instanceof Expression&&tree.operator==="="&&tree.value===1){return complexCondition(String(tree.path));}
return cloneTree(tree);}
if(tree.type==="complex_condition"){return cloneTree(tree);}
return{...tree,children:tree.children.map((child)=>createComplexConditions(child)),};}
function removeComplexConditions(tree){if(tree.type==="condition"){return cloneTree(tree);}
if(tree.type==="complex_condition"){const ast=parseExpr(tree.value);return condition(new Expression(bool(ast)),"=",1);}
return{...tree,children:tree.children.map((child)=>removeComplexConditions(child)),};}
__exports.treeFromExpression=treeFromExpression;function treeFromExpression(expression,options={}){const ast=parseExpr(expression);const tree=_treeFromAST(ast,options);return createVirtualOperators(createWithinOperators(createBetweenOperators(tree),options),options);}
__exports.expressionFromTree=expressionFromTree;function expressionFromTree(tree,options={}){const simplifiedTree=createComplexConditions(removeBetweenOperators(removeWithinOperators(removeVirtualOperators(tree))));return _expressionFromTree(simplifiedTree,options,true);}
__exports.domainFromTree=domainFromTree;function domainFromTree(tree){const simplifiedTree=removeBetweenOperators(removeWithinOperators(removeVirtualOperators(removeComplexConditions(tree))));const domainAST={type:4,value:getASTs(simplifiedTree),};return formatAST(domainAST);}
__exports.treeFromDomain=treeFromDomain;function treeFromDomain(domain,options={}){domain=new Domain(domain);const domainAST=domain.ast;const tree=construcTree(domainAST.value,options);return createVirtualOperators(createWithinOperators(createBetweenOperators(tree),options),options);}
__exports.expressionFromDomain=expressionFromDomain;function expressionFromDomain(domain,options={}){const tree=treeFromDomain(domain,options);return expressionFromTree(tree,options);}
__exports.domainFromExpression=domainFromExpression;function domainFromExpression(expression,options={}){const tree=treeFromExpression(expression,options);return domainFromTree(tree);}
return __exports;});;

/* /web/static/src/core/tree_editor/tree_editor.js */
odoo.define('@web/core/tree_editor/tree_editor',['@web/core/tree_editor/utils','@odoo/owl','@web/core/utils/hooks','@web/core/dropdown/dropdown','@web/core/dropdown/dropdown_item','@web/core/tree_editor/condition_tree','@web/core/tree_editor/tree_editor_value_editors','@web/core/model_field_selector/model_field_selector','@web/core/model_field_selector/utils','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{getResModel,useMakeGetFieldDef,useMakeGetConditionDescription,}=require("@web/core/tree_editor/utils");const{Component,onWillStart,onWillUpdateProps}=require("@odoo/owl");const{useService}=require("@web/core/utils/hooks");const{Dropdown}=require("@web/core/dropdown/dropdown");const{DropdownItem}=require("@web/core/dropdown/dropdown_item");const{condition,cloneTree,formatValue,removeVirtualOperators,connector,isTree,}=require("@web/core/tree_editor/condition_tree");const{getDefaultValue,getValueEditorInfo,}=require("@web/core/tree_editor/tree_editor_value_editors");const{ModelFieldSelector}=require("@web/core/model_field_selector/model_field_selector");const{useLoadFieldInfo}=require("@web/core/model_field_selector/utils");const{deepEqual,shallowEqual}=require("@web/core/utils/objects");const TRUE_TREE=condition(1,"=",1);function collectDifferences(tree,otherTree){if(tree.type!==otherTree.type){return[{type:"other"}];}
if(tree.negate!==otherTree.negate){return[{type:"other"}];}
if(tree.type==="condition"){if(formatValue(tree.path)!==formatValue(otherTree.path)){return[{type:"other"}];}
if(formatValue(tree.value)!==formatValue(otherTree.value)){return[{type:"other"}];}
if(formatValue(tree.operator)!==formatValue(otherTree.operator)){if(tree.operator==="!="&&otherTree.operator==="set"){return[{type:"replacement",tree,operator:"set"}];}else if(tree.operator==="="&&otherTree.operator==="not_set"){return[{type:"replacement",tree,operator:"not_set"}];}else{return[{type:"other"}];}}
return[];}
if(tree.value!==otherTree.value){return[{type:"other"}];}
if(tree.type==="complex_condition"){return[];}
if(tree.children.length!==otherTree.children.length){return[{type:"other"}];}
const diffs=[];for(let i=0;i<tree.children.length;i++){const child=tree.children[i];const otherChild=otherTree.children[i];const childDiffs=collectDifferences(child,otherChild);if(childDiffs.some((d)=>d.type!=="replacement")){return[{type:"other"}];}
diffs.push(...childDiffs);}
return diffs;}
function restoreVirtualOperators(tree,otherTree){const diffs=collectDifferences(tree,otherTree);if(diffs.some((d)=>d.type!=="replacement")){return;}
for(const{tree,operator}of diffs){tree.operator=operator;}}
const TreeEditor=__exports.TreeEditor=class TreeEditor extends Component{static template="web.TreeEditor";static components={Dropdown,DropdownItem,ModelFieldSelector,TreeEditor,};static props={tree:Object,resModel:String,update:Function,getDefaultCondition:Function,getPathEditorInfo:Function,getOperatorEditorInfo:Function,getDefaultOperator:Function,readonly:{type:Boolean,optional:true},slots:{type:Object,optional:true},isDebugMode:{type:Boolean,optional:true},defaultConnector:{type:[{value:"&"},{value:"|"}],optional:true},isSubTree:{type:Boolean,optional:true},};static defaultProps={defaultConnector:"&",readonly:false,isSubTree:false,};setup(){this.isTree=isTree;this.fieldService=useService("field");this.nameService=useService("name");this.loadFieldInfo=useLoadFieldInfo(this.fieldService);this.makeGetFieldDef=useMakeGetFieldDef(this.fieldService);this.makeGetConditionDescription=useMakeGetConditionDescription(this.fieldService,this.nameService);onWillStart(()=>this.onPropsUpdated(this.props));onWillUpdateProps((nextProps)=>this.onPropsUpdated(nextProps));}
async onPropsUpdated(props){this.tree=cloneTree(props.tree);if(shallowEqual(this.tree,TRUE_TREE)){this.tree=connector(props.defaultConnector);}else if(this.tree.type!=="connector"){this.tree=connector(props.defaultConnector,[this.tree]);}
if(this.previousTree){restoreVirtualOperators(this.tree,this.previousTree);this.previousTree=null;}
const[fieldDefs,getFieldDef]=await Promise.all([this.fieldService.loadFields(props.resModel),this.makeGetFieldDef(props.resModel,this.tree),]);this.getFieldDef=getFieldDef;this.defaultCondition=props.getDefaultCondition(fieldDefs);if(props.readonly){this.getConditionDescription=await this.makeGetConditionDescription(props.resModel,this.tree,this.getFieldDef);}}
get className(){return`${this.props.readonly ? "o_read_mode" : "o_edit_mode"}`;}
get isDebugMode(){return this.props.isDebugMode!==undefined?this.props.isDebugMode:!!this.env.debug;}
notifyChanges(){this.previousTree=cloneTree(this.tree);this.props.update(this.tree);}
updateConnector(node,value){node.value=value;node.negate=false;this.notifyChanges();}
updateComplexCondition(node,value){node.value=value;this.notifyChanges();}
createNewLeaf(){return cloneTree(this.defaultCondition);}
createNewBranch(value){return connector(value,[this.createNewLeaf(),this.createNewLeaf()]);}
insertRootLeaf(parent){parent.children.push(this.createNewLeaf());this.notifyChanges();}
insertLeaf(parent,node){const newNode=node.type!=="connector"?cloneTree(node):this.createNewLeaf();const index=parent.children.indexOf(node);parent.children.splice(index+1,0,newNode);this.notifyChanges();}
insertBranch(parent,node){const nextConnector=parent.value==="&"?"|":"&";const newNode=this.createNewBranch(nextConnector);const index=parent.children.indexOf(node);parent.children.splice(index+1,0,newNode);this.notifyChanges();}
delete(parent,node){const index=parent.children.indexOf(node);parent.children.splice(index,1);this.notifyChanges();}
getResModel(node){const fieldDef=this.getFieldDef(node.path);const resModel=getResModel(fieldDef);return resModel;}
getPathEditorInfo(){return this.props.getPathEditorInfo(this.props.resModel,this.defaultCondition);}
getOperatorEditorInfo(node){const fieldDef=this.getFieldDef(node.path);return this.props.getOperatorEditorInfo(fieldDef);}
getValueEditorInfo(node){const fieldDef=this.getFieldDef(node.path);return getValueEditorInfo(fieldDef,node.operator);}
async updatePath(node,path){const{fieldDef}=await this.loadFieldInfo(this.props.resModel,path);node.path=path;node.negate=false;node.operator=this.props.getDefaultOperator(fieldDef);node.value=getDefaultValue(fieldDef,node.operator);this.notifyChanges();}
updateLeafOperator(node,operator,negate){const previousNode=cloneTree(node);const fieldDef=this.getFieldDef(node.path);node.negate=negate;node.operator=operator;node.value=getDefaultValue(fieldDef,operator,node.value);if(deepEqual(removeVirtualOperators(node),removeVirtualOperators(previousNode))){this.render();}
this.notifyChanges();}
updateLeafValue(node,value){node.value=value;this.notifyChanges();}
highlightNode(target){const nodeEl=target.closest(".o_tree_editor_node");nodeEl.classList.toggle("o_hovered_button");}}
return __exports;});;

/* /web/static/src/core/tree_editor/tree_editor_autocomplete.js */
odoo.define('@web/core/tree_editor/tree_editor_autocomplete',['@web/core/record_selectors/multi_record_selector','@web/core/l10n/translation','@web/core/py_js/py_utils','@web/core/tree_editor/condition_tree','@web/core/record_selectors/record_selector'],function(require){'use strict';let __exports={};const{MultiRecordSelector}=require("@web/core/record_selectors/multi_record_selector");const{_t}=require("@web/core/l10n/translation");const{formatAST,toPyValue}=require("@web/core/py_js/py_utils");const{Expression}=require("@web/core/tree_editor/condition_tree");const{RecordSelector}=require("@web/core/record_selectors/record_selector");const isId=__exports.isId=(val)=>Number.isInteger(val)&&val>=1;const getFormat=__exports.getFormat=(val,displayNames)=>{let text;let colorIndex;if(isId(val)){text=typeof displayNames[val]==="string"?displayNames[val]:_t("Inaccessible/missing record ID: %s",val);colorIndex=typeof displayNames[val]==="string"?0:2;}else{text=val instanceof Expression?String(val):_t("Invalid record ID: %s",formatAST(toPyValue(val)));colorIndex=val instanceof Expression?2:1;}
return{text,colorIndex};};const DomainSelectorAutocomplete=__exports.DomainSelectorAutocomplete=class DomainSelectorAutocomplete extends MultiRecordSelector{static props={...MultiRecordSelector.props,resIds:true,};getIds(props=this.props){return props.resIds.filter((val)=>isId(val));}
getTags(props,displayNames){return props.resIds.map((val,index)=>{const{text,colorIndex}=getFormat(val,displayNames);return{text,colorIndex,onDelete:()=>{this.props.update([...this.props.resIds.slice(0,index),...this.props.resIds.slice(index+1),]);},};});}}
const DomainSelectorSingleAutocomplete=__exports.DomainSelectorSingleAutocomplete=class DomainSelectorSingleAutocomplete extends RecordSelector{static props={...RecordSelector.props,resId:true,};getDisplayName(props=this.props,displayNames){const{resId}=props;if(resId===false){return"";}
const{text}=getFormat(resId,displayNames);return text;}
getIds(props=this.props){if(isId(props.resId)){return[props.resId];}
return[];}}
return __exports;});;

/* /web/static/src/core/tree_editor/tree_editor_components.js */
odoo.define('@web/core/tree_editor/tree_editor_components',['@odoo/owl','@web/core/tags_list/tags_list','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{TagsList}=require("@web/core/tags_list/tags_list");const{_t}=require("@web/core/l10n/translation");const Input=__exports.Input=class Input extends Component{static props=["value","update","startEmpty?"];static template="web.TreeEditor.Input";}
const Select=__exports.Select=class Select extends Component{static props=["value","update","options","addBlankOption?"];static template="web.TreeEditor.Select";deserialize(value){return JSON.parse(value);}
serialize(value){return JSON.stringify(value);}}
const Range=__exports.Range=class Range extends Component{static props=["value","update","editorInfo"];static template="web.TreeEditor.Range";update(index,newValue){const result=[...this.props.value];result[index]=newValue;return this.props.update(result);}}
const Within=__exports.Within=class Within extends Component{static props=["value","update","amountEditorInfo","optionEditorInfo"];static template="web.TreeEditor.Within";static components={Input,Select};static options=[["days",_t("days")],["weeks",_t("weeks")],["months",_t("months")],["years",_t("years")],];update(index,newValue){const result=[...this.props.value];result[index]=newValue;return this.props.update(result);}}
const List=__exports.List=class List extends Component{static components={TagsList};static props=["value","update","editorInfo"];static template="web.TreeEditor.List";get tags(){const{isSupported,stringify}=this.props.editorInfo;return this.props.value.map((val,index)=>({text:stringify(val),colorIndex:isSupported(val)?0:2,onDelete:()=>{this.props.update([...this.props.value.slice(0,index),...this.props.value.slice(index+1),]);},}));}
update(newValue){return this.props.update([...this.props.value,newValue]);}}
return __exports;});;

/* /web/static/src/core/tree_editor/tree_editor_operator_editor.js */
odoo.define('@web/core/tree_editor/tree_editor_operator_editor',['@web/core/l10n/translation','@web/core/tree_editor/condition_tree','@web/core/utils/strings','@web/core/py_js/py','@web/core/tree_editor/tree_editor_components'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{formatValue,TERM_OPERATORS_NEGATION,toValue,}=require("@web/core/tree_editor/condition_tree");const{sprintf}=require("@web/core/utils/strings");const{parseExpr}=require("@web/core/py_js/py");const{Select}=require("@web/core/tree_editor/tree_editor_components");const OPERATOR_DESCRIPTIONS={"=":"=","!=":"!=","<=":"<=","<":"<",">":">",">=":">=","=?":"=?","=like":_t("=like"),"=ilike":_t("=ilike"),like:_t("like"),"not like":_t("not like"),ilike:_t("contains"),"not ilike":_t("does not contain"),in:_t("is in"),"not in":_t("is not in"),child_of:_t("child of"),parent_of:_t("parent of"),is:_t("is"),is_not:_t("is not"),set:_t("is set"),not_set:_t("is not set"),starts_with:_t("starts with"),ends_with:_t("ends with"),between:_t("is between"),within:_t("is within"),any:(fieldDefType)=>{switch(fieldDefType){case"many2one":return _t("matches");default:return _t("match");}},"not any":(fieldDefType)=>{switch(fieldDefType){case"many2one":return _t("matches none of");default:return _t("match none of");}},};function toKey(operator,negate=false){if(!negate&&typeof operator==="string"&&operator in OPERATOR_DESCRIPTIONS){return operator;}
return JSON.stringify([formatValue(operator),negate]);}
function toOperator(key){if(!key.includes("[")){return[key,false];}
const[expr,negate]=JSON.parse(key);return[toValue(parseExpr(expr)),negate];}
function getOperatorDescription(operator,fieldDefType){const description=OPERATOR_DESCRIPTIONS[operator];if(typeof description==="function"&&description.constructor?.name!=="LazyTranslatedString"){return description(fieldDefType);}
return description;}
__exports.getOperatorLabel=getOperatorLabel;function getOperatorLabel(operator,fieldDefType,negate=false){let label;if(typeof operator==="string"&&operator in OPERATOR_DESCRIPTIONS){if(negate&&operator in TERM_OPERATORS_NEGATION){return getOperatorDescription(TERM_OPERATORS_NEGATION[operator],fieldDefType);}
label=getOperatorDescription(operator,fieldDefType);}else{label=formatValue(operator);}
if(negate){return sprintf(`not %s`,label);}
return label;}
function getOperatorInfo(operator,fieldDefType,negate=false){const key=toKey(operator,negate);const label=getOperatorLabel(operator,fieldDefType,negate);return[key,label];}
__exports.getOperatorEditorInfo=getOperatorEditorInfo;function getOperatorEditorInfo(operators,fieldDef){const defaultOperator=operators[0];const operatorsInfo=operators.map((operator)=>getOperatorInfo(operator,fieldDef?.type));return{component:Select,extractProps:({update,value:[operator,negate]})=>{const[operatorKey,operatorLabel]=getOperatorInfo(operator,fieldDef?.type,negate);const options=[...operatorsInfo];if(!options.some(([key])=>key===operatorKey)){options.push([operatorKey,operatorLabel]);}
return{value:operatorKey,update:(operatorKey)=>update(...toOperator(operatorKey)),options,};},defaultValue:()=>defaultOperator,isSupported:([operator])=>typeof operator==="string"&&operator in OPERATOR_DESCRIPTIONS,message:_t("Operator not supported"),stringify:([operator,negate])=>getOperatorLabel(operator,negate),};}
return __exports;});;

/* /web/static/src/core/tree_editor/tree_editor_value_editors.js */
odoo.define('@web/core/tree_editor/tree_editor_value_editors',['@web/core/l10n/dates','@web/core/l10n/translation','@web/core/registry','@web/core/datetime/datetime_input','@web/core/tree_editor/tree_editor_autocomplete','@web/core/utils/arrays','@web/core/tree_editor/tree_editor_components','@web/core/tree_editor/condition_tree','@web/core/tree_editor/utils','@web/core/domain'],function(require){'use strict';let __exports={};const{deserializeDate,deserializeDateTime,serializeDate,serializeDateTime,}=require("@web/core/l10n/dates");const{_t}=require("@web/core/l10n/translation");const{registry}=require("@web/core/registry");const{DateTimeInput}=require("@web/core/datetime/datetime_input");const{DomainSelectorAutocomplete,DomainSelectorSingleAutocomplete,}=require("@web/core/tree_editor/tree_editor_autocomplete");const{unique}=require("@web/core/utils/arrays");const{Input,Select,List,Range,Within}=require("@web/core/tree_editor/tree_editor_components");const{connector,formatValue,isTree}=require("@web/core/tree_editor/condition_tree");const{getResModel,disambiguate,isId}=require("@web/core/tree_editor/utils");const{Domain}=require("@web/core/domain");const{DateTime}=luxon;const formatters=registry.category("formatters");const parsers=registry.category("parsers");function parseValue(fieldType,value){const parser=parsers.get(fieldType,(value)=>value);try{return parser(value);}catch{return value;}}
function isParsable(fieldType,value){const parser=parsers.get(fieldType,(value)=>value);try{parser(value);}catch{return false;}
return true;}
function genericSerializeDate(type,value){return type==="date"?serializeDate(value):serializeDateTime(value);}
function genericDeserializeDate(type,value){return type==="date"?deserializeDate(value):deserializeDateTime(value);}
const STRING_EDITOR={component:Input,extractProps:({value,update})=>({value,update}),isSupported:(value)=>typeof value==="string",defaultValue:()=>"",};function makeSelectEditor(options,params={}){const getOption=(value)=>options.find(([v])=>v===value)||null;return{component:Select,extractProps:({value,update})=>({value,update,options,addBlankOption:params.addBlankOption,}),isSupported:(value)=>Boolean(getOption(value)),defaultValue:()=>options[0]?.[0]??false,stringify:(value,disambiguate)=>{const option=getOption(value);return option?option[1]:disambiguate?formatValue(value):String(value);},message:_t("Value not in selection"),};}
function getDomain(fieldDef){if(fieldDef.type==="many2one"){return[];}
try{return new Domain(fieldDef.domain||[]).toList();}catch{return[];}}
function makeAutoCompleteEditor(fieldDef){return{component:DomainSelectorAutocomplete,extractProps:({value,update})=>{return{resModel:getResModel(fieldDef),fieldString:fieldDef.string,domain:getDomain(fieldDef),update:(value)=>update(unique(value)),resIds:unique(value),};},isSupported:(value)=>Array.isArray(value),defaultValue:()=>[],};}
function getPartialValueEditorInfo(fieldDef,operator,params={}){switch(operator){case"set":case"not_set":return{component:null,extractProps:null,isSupported:(value)=>value===false,defaultValue:()=>false,};case"=like":case"=ilike":case"like":case"not like":case"ilike":case"not ilike":return STRING_EDITOR;case"between":{const editorInfo=getValueEditorInfo(fieldDef,"=");return{component:Range,extractProps:({value,update})=>({value,update,editorInfo,}),isSupported:(value)=>Array.isArray(value)&&value.length===2,defaultValue:()=>{const{defaultValue}=editorInfo;return[defaultValue(),defaultValue()];},};}
case"within":{return{component:Within,extractProps:({value,update})=>({value,update,amountEditorInfo:getValueEditorInfo({type:"integer"},"="),optionEditorInfo:makeSelectEditor(Within.options),}),isSupported:(value)=>Array.isArray(value)&&value.length===3&&typeof value[1]==="string"&&value[2]===fieldDef.type,defaultValue:()=>{return[-1,"months",fieldDef.type];},};}
case"in":case"not in":{switch(fieldDef.type){case"tags":return STRING_EDITOR;case"many2one":case"many2many":case"one2many":return makeAutoCompleteEditor(fieldDef);default:{const editorInfo=getValueEditorInfo(fieldDef,"=",{addBlankOption:true,startEmpty:true,});return{component:List,extractProps:({value,update})=>{if(!disambiguate(value)){const{stringify}=editorInfo;editorInfo.stringify=(val)=>stringify(val,false);}
return{value,update,editorInfo,};},isSupported:(value)=>Array.isArray(value),defaultValue:()=>[],};}}}
case"any":case"not any":{switch(fieldDef.type){case"many2one":case"many2many":case"one2many":{return{component:null,extractProps:null,isSupported:isTree,defaultValue:()=>connector("&"),};}}}}
const{type}=fieldDef;switch(type){case"integer":case"float":case"monetary":{const formatType=type==="integer"?"integer":"float";return{component:Input,extractProps:({value,update})=>({value:String(value),update:(value)=>update(parseValue(formatType,value)),startEmpty:params.startEmpty,}),isSupported:()=>true,defaultValue:()=>1,shouldResetValue:(value)=>parseValue(formatType,value)===value,};}
case"date":case"datetime":return{component:DateTimeInput,extractProps:({value,update})=>({value:params.startEmpty||value===false?false:genericDeserializeDate(type,value),type,onApply:(value)=>{if(!params.startEmpty||value){update(genericSerializeDate(type,value||DateTime.local()));}},}),isSupported:(value)=>value===false||(typeof value==="string"&&isParsable(type,value)),defaultValue:()=>genericSerializeDate(type,DateTime.local()),stringify:(value)=>{if(value===false){return _t("False");}
if(typeof value==="string"&&isParsable(type,value)){const formatter=formatters.get(type,formatValue);return formatter(genericDeserializeDate(type,value));}
return formatValue(value);},message:_t("Not a valid %s",type),};case"char":case"html":case"text":return STRING_EDITOR;case"boolean":{if(["is","is_not"].includes(operator)){const options=[[true,_t("set")],[false,_t("not set")],];return makeSelectEditor(options,params);}
const options=[[true,_t("True")],[false,_t("False")],];return makeSelectEditor(options,params);}
case"many2one":{if(["=","!="].includes(operator)){return{component:DomainSelectorSingleAutocomplete,extractProps:({value,update})=>({resModel:getResModel(fieldDef),fieldString:fieldDef.string,update,resId:value,}),isSupported:()=>true,defaultValue:()=>false,shouldResetValue:(value)=>value!==false&&!isId(value),};}else if(["parent_of","child_of"].includes(operator)){return makeAutoCompleteEditor(fieldDef);}
break;}
case"many2many":case"one2many":if(["=","!="].includes(operator)){return makeAutoCompleteEditor(fieldDef);}
break;case"selection":{const options=fieldDef.selection||[];return makeSelectEditor(options,params);}
case undefined:{const options=[[1,"1"]];return makeSelectEditor(options,params);}}
return{component:Input,extractProps:({value,update})=>({value:String(value),update,}),isSupported:()=>true,defaultValue:()=>"",};}
__exports.getValueEditorInfo=getValueEditorInfo;function getValueEditorInfo(fieldDef,operator,options={}){const info=getPartialValueEditorInfo(fieldDef||{},operator,options);return{extractProps:({value,update})=>({value,update}),message:_t("Value not supported"),stringify:(val,disambiguate=true)=>{if(disambiguate){return formatValue(val);}
return String(val);},...info,};}
__exports.getDefaultValue=getDefaultValue;function getDefaultValue(fieldDef,operator,value=null){const{isSupported,shouldResetValue,defaultValue}=getValueEditorInfo(fieldDef,operator);if(value===null||!isSupported(value)||shouldResetValue?.(value)){return defaultValue();}
return value;}
return __exports;});;

/* /web/static/src/core/tree_editor/utils.js */
odoo.define('@web/core/tree_editor/utils',['@web/core/utils/arrays','@web/core/tree_editor/tree_editor_operator_editor','@web/core/tree_editor/condition_tree','@web/core/utils/hooks','@web/core/l10n/translation','@web/core/l10n/dates','@web/core/model_field_selector/utils','@web/core/tree_editor/tree_editor_components'],function(require){'use strict';let __exports={};const{unique,zip}=require("@web/core/utils/arrays");const{getOperatorLabel}=require("@web/core/tree_editor/tree_editor_operator_editor");const{Expression,condition,createVirtualOperators,normalizeValue,isTree,Couple,}=require("@web/core/tree_editor/condition_tree");const{useService}=require("@web/core/utils/hooks");const{_t}=require("@web/core/l10n/translation");const{deserializeDate,deserializeDateTime,formatDate,formatDateTime,}=require("@web/core/l10n/dates");const{useLoadFieldInfo,useLoadPathDescription}=require("@web/core/model_field_selector/utils");const{Within}=require("@web/core/tree_editor/tree_editor_components");function formatValue(val,disambiguate,fieldDef,displayNames){if(val instanceof Expression){return val.toString();}
if(displayNames&&isId(val)){if(typeof displayNames[val]==="string"){val=displayNames[val];}else{return _t("Inaccessible/missing record ID: %s",val);}}
if(fieldDef?.type==="selection"){const[,label]=(fieldDef.selection||[]).find(([v])=>v===val)||[];if(label!==undefined){val=label;}}
if(typeof val==="string"){if(fieldDef?.type==="datetime"){return formatDateTime(deserializeDateTime(val));}
if(fieldDef?.type==="date"){return formatDate(deserializeDate(val));}}
if(disambiguate&&typeof val==="string"){return JSON.stringify(val);}
return val;}
__exports.isId=isId;function isId(value){return Number.isInteger(value)&&value>=1;}
__exports.disambiguate=disambiguate;function disambiguate(value,displayNames){if(!Array.isArray(value)){return value==="";}
let hasSomeString=false;let hasSomethingElse=false;for(const val of value){if(val===""){return true;}
if(typeof val==="string"||(displayNames&&isId(val))){hasSomeString=true;}else{hasSomethingElse=true;}}
return hasSomeString&&hasSomethingElse;}
__exports.useMakeGetFieldDef=useMakeGetFieldDef;function useMakeGetFieldDef(fieldService){fieldService||=useService("field");const loadFieldInfo=useLoadFieldInfo(fieldService);return async(resModel,tree,additionalsPath=[])=>{const pathsInTree=getPathsInTree(tree,true);const paths=new Set([...pathsInTree,...additionalsPath]);const promises=[];const fieldDefs={};const loadFieldInfoFromMultiplePaths=async(resModel,fieldDefs,path)=>{if(typeof path==="string"&&!(path in fieldDefs)){const prom=loadFieldInfo(resModel,path).then(({fieldDef})=>{fieldDefs[path].fieldDef=fieldDef;return fieldDef?.relation||null;});fieldDefs[path]={prom,pathFieldDefs:{},fieldDef:null};return prom;}
if(path instanceof Couple&&typeof path.fst==="string"&&path.fst in fieldDefs){const resModel=await fieldDefs[path.fst].prom;if(resModel){return loadFieldInfoFromMultiplePaths(resModel,fieldDefs[path.fst].pathFieldDefs,path.snd);}}
return null;};for(const path of paths){promises.push(loadFieldInfoFromMultiplePaths(resModel,fieldDefs,path));}
await Promise.all(promises);const _getFieldDef=(path,fieldDefs)=>{if(typeof path==="string"){return fieldDefs[path].fieldDef;}
if(path instanceof Couple&&typeof path.fst==="string"&&path.fst in fieldDefs){return _getFieldDef(path.snd,fieldDefs[path.fst].pathFieldDefs);}
return null;};return(path)=>_getFieldDef(path,fieldDefs);};}
function useGetTreePathDescription(fieldService){fieldService||=useService("field");const loadPathDescription=useLoadPathDescription(fieldService);return async(resModel,tree)=>{const paths=getPathsInTree(tree);const promises=[];const pathDescriptions=new Map();for(const path of paths){promises.push(loadPathDescription(resModel,path).then(({displayNames})=>{pathDescriptions.set(path,displayNames.join(" \u2794 "));}));}
await Promise.all(promises);return(path)=>pathDescriptions.get(path);};}
async function getDisplayNames(tree,getFieldDef,nameService){const resIdsByModel=extractIdsFromTree(tree,getFieldDef);const proms=[];const resModels=[];for(const[resModel,resIds]of Object.entries(resIdsByModel)){resModels.push(resModel);proms.push(nameService.loadDisplayNames(resModel,resIds));}
return Object.fromEntries(zip(resModels,await Promise.all(proms)));}
__exports.useMakeGetConditionDescription=useMakeGetConditionDescription;function useMakeGetConditionDescription(fieldService,nameService){const makeGetPathDescriptions=useGetTreePathDescription(fieldService);return async(resModel,tree,getFieldDef)=>{tree=simplifyTree(tree);const[displayNames,getPathDescription]=await Promise.all([getDisplayNames(tree,getFieldDef,nameService),makeGetPathDescriptions(resModel,tree),]);return(node)=>_getConditionDescription(node,getFieldDef,getPathDescription,displayNames);};}
function _getConditionDescription(node,getFieldDef,getPathDescription,displayNames){const nodeWithVirtualOperators=createVirtualOperators(node,{getFieldDef});const{operator,negate,value,path}=nodeWithVirtualOperators;const fieldDef=getFieldDef(path);const operatorLabel=getOperatorLabel(operator,fieldDef?.type,negate);const pathDescription=getPathDescription(path);const description={pathDescription,operatorDescription:operatorLabel,valueDescription:null,};if(isTree(node.value)){return description;}
if(["set","not_set"].includes(operator)){return description;}
if(["is","is_not"].includes(operator)){description.valueDescription={values:[value?_t("set"):_t("not set")],join:"",addParenthesis:false,};return description;}
const coModeldisplayNames=displayNames[getResModel(fieldDef)];const dis=disambiguate(value,coModeldisplayNames);const values=operator=="within"?[value[0],Within.options.find((option)=>option[0]===value[1])[1]]:(Array.isArray(value)?value:[value]).slice(0,21).map((val,index)=>index<20?formatValue(val,dis,fieldDef,coModeldisplayNames):"...");let join;let addParenthesis=Array.isArray(value);switch(operator){case"between":join=_t("and");addParenthesis=false;break;case"within":join=" ";addParenthesis=false;break;case"in":case"not in":join=",";break;default:join=_t("or");}
description.valueDescription={values,join,addParenthesis};return description;}
__exports.useGetTreeDescription=useGetTreeDescription;function useGetTreeDescription(fieldService,nameService){fieldService||=useService("field");nameService||=useService("name");const makeGetFieldDef=useMakeGetFieldDef(fieldService);const makeGetConditionDescription=useMakeGetConditionDescription(fieldService,nameService);return async(resModel,tree)=>{async function getTreeDescription(resModel,tree,isSubExpression=false){tree=simplifyTree(tree);if(tree.type==="connector"){const childDescriptions=tree.children.map((node)=>getTreeDescription(resModel,node,true));const separator=tree.value==="&"?_t("and"):_t("or");let description=await Promise.all(childDescriptions);description=description.join(` ${separator} `);if(isSubExpression||tree.negate){description=`( ${description} )`;}
if(tree.negate){description=`! ${description}`;}
return description;}
const getFieldDef=await makeGetFieldDef(resModel,tree);const getConditionDescription=await makeGetConditionDescription(resModel,tree,getFieldDef);const{pathDescription,operatorDescription,valueDescription}=getConditionDescription(tree);const stringDescription=[pathDescription,operatorDescription];if(valueDescription){const{values,join,addParenthesis}=valueDescription;const jointedValues=values.join(` ${join} `);stringDescription.push(addParenthesis?`( ${jointedValues} )`:jointedValues);}else if(isTree(tree.value)){const _fieldDef=getFieldDef(tree.path);const _resModel=getResModel(_fieldDef);const _tree=tree.value;const description=await getTreeDescription(_resModel,_tree);stringDescription.push(`( ${description} )`);}
return stringDescription.join(" ");}
return getTreeDescription(resModel,tree);};}
__exports.getResModel=getResModel;function getResModel(fieldDef){if(fieldDef){return fieldDef.is_property?fieldDef.comodel:fieldDef.relation;}
return null;}
function extractIdsFromTree(tree,getFieldDef){const idsByModel=_extractIdsRecursive(tree,getFieldDef,{});for(const resModel in idsByModel){idsByModel[resModel]=unique(idsByModel[resModel]);}
return idsByModel;}
function _extractIdsRecursive(tree,getFieldDef,idsByModel){if(tree.type==="condition"){const fieldDef=getFieldDef(tree.path);if(["many2one","many2many","one2many"].includes(fieldDef?.type)){const value=tree.value;const values=Array.isArray(value)?value:[value];const ids=values.filter((val)=>isId(val));const resModel=getResModel(fieldDef);if(ids.length){if(!idsByModel[resModel]){idsByModel[resModel]=[];}
idsByModel[resModel].push(...ids);}}}
if(tree.type==="connector"){for(const child of tree.children){_extractIdsRecursive(child,getFieldDef,idsByModel);}}
return idsByModel;}
__exports.getPathsInTree=getPathsInTree;function getPathsInTree(tree,lookInSubTrees=false){const paths=[];if(tree.type==="condition"){paths.push(tree.path);if(lookInSubTrees&&isTree(tree.value)){const subTreePaths=getPathsInTree(tree.value,lookInSubTrees);for(const p of subTreePaths){paths.push(new Couple(tree.path,p));}}}
if(tree.type==="connector"&&tree.children){for(const child of tree.children){paths.push(...getPathsInTree(child,lookInSubTrees));}}
return unique(paths);}
const SPECIAL_FIELDS=["country_id","user_id","partner_id","stage_id","id"];__exports.getDefaultPath=getDefaultPath;function getDefaultPath(fieldDefs){for(const name of SPECIAL_FIELDS){const fieldDef=fieldDefs[name];if(fieldDef){return fieldDef.name;}}
const name=Object.keys(fieldDefs)[0];if(name){return name;}
throw new Error(`No field found`);}
function simplifyTree(tree){if(tree.type==="condition"){return tree;}
const processedChildren=tree.children.map(simplifyTree);if(tree.value==="&"){return{...tree,children:processedChildren};}
const children=[];const childrenByPath={};for(const child of processedChildren){if(child.type==="connector"||typeof child.path!=="string"||!["=","in"].includes(child.operator)){children.push(child);}else{if(!childrenByPath[child.path]){childrenByPath[child.path]=[];}
childrenByPath[child.path].push(child);}}
for(const path in childrenByPath){if(childrenByPath[path].length===1){children.push(childrenByPath[path][0]);continue;}
const value=[];for(const child of childrenByPath[path]){if(child.operator==="="){value.push(child.value);}else{value.push(...child.value);}}
children.push(condition(path,"in",normalizeValue(value)));}
if(children.length===1){return{...children[0]};}
return{...tree,children};}
return __exports;});;

/* /web/static/src/core/ui/block_ui.js */
odoo.define('@web/core/ui/block_ui',['@web/core/l10n/translation','@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");const{browser}=require("@web/core/browser/browser");const{EventBus,Component,useState,xml}=require("@odoo/owl");const BlockUI=__exports.BlockUI=class BlockUI extends Component{static props={bus:EventBus,};static template=xml`
        <t t-if="state.blockState === BLOCK_STATES.UNBLOCKED">
            <div/>
        </t>
        <t t-else="">
            <t t-set="visiblyBlocked" t-value="state.blockState === BLOCK_STATES.VISIBLY_BLOCKED"/>
            <div class="o_blockUI fixed-top d-flex justify-content-center align-items-center flex-column vh-100"
                 t-att-class="visiblyBlocked ? '' : 'o_blockUI_invisible'">
                <t t-if="visiblyBlocked">
                    <div class="o_spinner mb-4">
                        <img src="/web/static/img/spin.svg" alt="Loading..."/>
                    </div>
                    <div class="o_message text-center px-4">
                        <t t-esc="state.line1"/><br/>
                        <t t-esc="state.line2"/>
                    </div>
                </t>
            </div>
        </t>
    `;setup(){this.messagesByDuration=[{time:20,l1:_t("Loading...")},{time:40,l1:_t("Still loading...")},{time:60,l1:_t("Still loading..."),l2:_t("Please be patient."),},{time:180,l1:_t("Don't leave yet,"),l2:_t("it's still loading..."),},{time:120,l1:_t("You may not believe it,"),l2:_t("but the application is actually loading..."),},{time:3180,l1:_t("Take a minute to get a coffee,"),l2:_t("because it's loading..."),},{time:null,l1:_t("Maybe you should consider reloading the application by pressing F5..."),},];this.BLOCK_STATES={UNBLOCKED:0,BLOCKED:1,VISIBLY_BLOCKED:2};this.state=useState({blockState:this.BLOCK_STATES.UNBLOCKED,line1:"",line2:"",});this.props.bus.addEventListener("BLOCK",this.block.bind(this));this.props.bus.addEventListener("UNBLOCK",this.unblock.bind(this));}
replaceMessage(index){const message=this.messagesByDuration[index];this.state.line1=message.l1;this.state.line2=message.l2||"";if(message.time!==null){this.msgTimer=browser.setTimeout(()=>{this.replaceMessage(index+1);},message.time*1000);}}
block(ev){const showBlockedUI=()=>(this.state.blockState=this.BLOCK_STATES.VISIBLY_BLOCKED);const delay=ev.detail?.delay;if(delay){this.state.blockState=this.BLOCK_STATES.BLOCKED;this.showBlockedUITimer=setTimeout(showBlockedUI,delay);}else{showBlockedUI();}
if(ev.detail?.message){this.state.line1=ev.detail.message;}else{this.replaceMessage(0);}}
unblock(){this.state.blockState=this.BLOCK_STATES.UNBLOCKED;clearTimeout(this.showBlockedUITimer);clearTimeout(this.msgTimer);this.state.line1="";this.state.line2="";}}
return __exports;});;

/* /web/static/src/core/ui/ui_service.js */
odoo.define('@web/core/ui/ui_service',['@web/core/utils/hooks','@web/core/registry','@web/core/utils/timing','@web/core/ui/block_ui','@web/core/browser/browser','@web/core/utils/ui','@web/core/hotkeys/hotkey_service','@odoo/owl'],function(require){'use strict';let __exports={};const{useService}=require("@web/core/utils/hooks");const{registry}=require("@web/core/registry");const{throttleForAnimation}=require("@web/core/utils/timing");const{BlockUI}=require("@web/core/ui/block_ui");const{browser}=require("@web/core/browser/browser");const{getTabableElements}=require("@web/core/utils/ui");const{getActiveHotkey}=require("@web/core/hotkeys/hotkey_service");const{EventBus,reactive,useEffect,useRef}=require("@odoo/owl");const SIZES=__exports.SIZES={XS:0,VSM:1,SM:2,MD:3,LG:4,XL:5,XXL:6};function getFirstAndLastTabableElements(el){const tabableEls=getTabableElements(el);return[tabableEls[0],tabableEls[tabableEls.length-1]];}
__exports.useActiveElement=useActiveElement;function useActiveElement(refName){if(!refName){throw new Error("refName not given to useActiveElement");}
const uiService=useService("ui");const ref=useRef(refName);function trapFocus(e){const hotkey=getActiveHotkey(e);if(!["tab","shift+tab"].includes(hotkey)){return;}
const el=e.currentTarget;const[firstTabableEl,lastTabableEl]=getFirstAndLastTabableElements(el);switch(hotkey){case"tab":if(document.activeElement===lastTabableEl){firstTabableEl.focus();e.preventDefault();e.stopPropagation();}
break;case"shift+tab":if(document.activeElement===firstTabableEl){lastTabableEl.focus();e.preventDefault();e.stopPropagation();}
break;}}
useEffect((el)=>{if(el){const[firstTabableEl]=getFirstAndLastTabableElements(el);if(!firstTabableEl){return;}
const oldActiveElement=document.activeElement;uiService.activateElement(el);el.addEventListener("keydown",trapFocus);if(!el.contains(document.activeElement)){firstTabableEl.focus();}
return async()=>{await Promise.resolve();uiService.deactivateElement(el);el.removeEventListener("keydown",trapFocus);if(el.contains(document.activeElement)||document.activeElement===document.body){oldActiveElement.focus();}};}},()=>[ref.el]);}
const MEDIAS_BREAKPOINTS=__exports.MEDIAS_BREAKPOINTS=[{maxWidth:474},{minWidth:475,maxWidth:575},{minWidth:576,maxWidth:767},{minWidth:768,maxWidth:991},{minWidth:992,maxWidth:1199},{minWidth:1200,maxWidth:1533},{minWidth:1534},];__exports.getMediaQueryLists=getMediaQueryLists;function getMediaQueryLists(){return MEDIAS_BREAKPOINTS.map(({minWidth,maxWidth})=>{if(!maxWidth){return window.matchMedia(`(min-width: ${minWidth}px)`);}
if(!minWidth){return window.matchMedia(`(max-width: ${maxWidth}px)`);}
return window.matchMedia(`(min-width: ${minWidth}px) and (max-width: ${maxWidth}px)`);});}
const MEDIAS=getMediaQueryLists();const utils=__exports.utils={getSize(){return MEDIAS.findIndex((media)=>media.matches);},isSmall(ui={}){return(ui.size||utils.getSize())<=SIZES.SM;},};const bus=new EventBus();__exports.listenSizeChange=listenSizeChange;function listenSizeChange(callback){bus.addEventListener("resize",callback);return()=>bus.removeEventListener("resize",callback);}
const uiService=__exports.uiService={start(env){registry.category("main_components").add("BlockUI",{Component:BlockUI,props:{bus}});let blockCount=0;function block(data){blockCount++;if(blockCount===1){bus.trigger("BLOCK",{message:data?.message,delay:data?.delay,});}}
function unblock(){blockCount--;if(blockCount<0){console.warn("Unblock ui was called more times than block, you should only unblock the UI if you have previously blocked it.");blockCount=0;}
if(blockCount===0){bus.trigger("UNBLOCK");}}
let activeElems=[document];function activateElement(el){activeElems.push(el);bus.trigger("active-element-changed",el);}
function deactivateElement(el){activeElems=activeElems.filter((x)=>x!==el);bus.trigger("active-element-changed",ui.activeElement);}
function getActiveElementOf(el){for(const activeElement of[...activeElems].reverse()){if(activeElement.contains(el)){return activeElement;}}}
const ui=reactive({bus,size:utils.getSize(),get activeElement(){return activeElems[activeElems.length-1];},get isBlocked(){return blockCount>0;},isSmall:utils.isSmall(),block,unblock,activateElement,deactivateElement,getActiveElementOf,});const updateSize=()=>{const prevSize=ui.size;ui.size=utils.getSize();if(ui.size!==prevSize){ui.isSmall=utils.isSmall(ui);bus.trigger("resize");}};browser.addEventListener("resize",throttleForAnimation(updateSize));Object.defineProperty(env,"isSmall",{get(){return ui.isSmall;},});return ui;},};registry.category("services").add("ui",uiService);return __exports;});;

/* /web/static/src/core/user.js */
odoo.define('@web/core/user',['@web/core/browser/browser','@web/core/l10n/utils/locales','@web/core/network/rpc','@web/core/utils/cache','@web/session','@web/core/utils/arrays'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{pyToJsLocale}=require("@web/core/l10n/utils/locales");const{rpc}=require("@web/core/network/rpc");const{Cache}=require("@web/core/utils/cache");const{session}=require("@web/session");const{ensureArray}=require("@web/core/utils/arrays");__exports._makeUser=_makeUser;function _makeUser(session){const{home_action_id:homeActionId,is_admin:isAdmin,is_internal_user:isInternalUser,is_system:isSystem,name,partner_id:partnerId,show_effect:showEffect,uid:userId,username:login,user_context:context,user_settings,partner_write_date:writeDate,}=session;const settings=user_settings||{};delete session.home_action_id;delete session.is_admin;delete session.is_internal_user;delete session.is_system;delete session.name;delete session.partner_id;delete session.show_effect;delete session.uid;delete session.username;delete session.user_context;delete session.user_settings;delete session.partner_write_date;const getGroupCacheValue=(group,context)=>{if(!userId){return Promise.resolve(false);}
return rpc("/web/dataset/call_kw/res.users/has_group",{model:"res.users",method:"has_group",args:[userId,group],kwargs:{context},});};const getGroupCacheKey=(group)=>group;const groupCache=new Cache(getGroupCacheValue,getGroupCacheKey);if(isInternalUser!==undefined){groupCache.cache["base.group_user"]=Promise.resolve(isInternalUser);}
if(isSystem!==undefined){groupCache.cache["base.group_system"]=Promise.resolve(isSystem);}
const getAccessRightCacheValue=(model,operation,ids,context)=>{const url=`/web/dataset/call_kw/${model}/has_access`;return rpc(url,{model,method:"has_access",args:[ids,operation],kwargs:{context},});};const getAccessRightCacheKey=(model,operation,ids)=>JSON.stringify([model,operation,ids]);const accessRightCache=new Cache(getAccessRightCacheValue,getAccessRightCacheKey);const lang=pyToJsLocale(context?.lang);const user={name,login,isAdmin,isSystem,isInternalUser,partnerId,homeActionId,showEffect,userId,writeDate,get context(){return Object.assign({},context,{uid:this.userId});},get lang(){return lang;},get tz(){return this.context.tz;},get settings(){return Object.assign({},settings);},updateContext(update){Object.assign(context,update);},hasGroup(group){return groupCache.read(group,this.context);},checkAccessRight(model,operation,ids=[]){return accessRightCache.read(model,operation,ensureArray(ids),this.context);},async setUserSettings(key,value){const model="res.users.settings";const method="set_res_users_settings";const changedSettings=await rpc(`/web/dataset/call_kw/${model}/${method}`,{model,method,args:[[this.settings.id]],kwargs:{new_settings:{[key]:value,},context:this.context,},});Object.assign(settings,changedSettings);},};return user;}
const user=__exports.user=_makeUser(session);const LAST_CONNECTED_USER_KEY="web.lastConnectedUser";const getLastConnectedUsers=__exports.getLastConnectedUsers=()=>{const lastConnectedUsers=browser.localStorage.getItem(LAST_CONNECTED_USER_KEY);return lastConnectedUsers?JSON.parse(lastConnectedUsers):[];};const setLastConnectedUsers=__exports.setLastConnectedUsers=(users)=>{browser.localStorage.setItem(LAST_CONNECTED_USER_KEY,JSON.stringify(users.slice(0,5)));};if(!session.quick_login){browser.localStorage.removeItem(LAST_CONNECTED_USER_KEY);}else if(user.login&&user.login!=="__system__"){const users=getLastConnectedUsers();const lastConnectedUsers=[{login:user.login,name:user.name,partnerId:user.partnerId,partnerWriteDate:user.writeDate,userId:user.userId,},...users.filter((u)=>u.userId!==user.userId),];setLastConnectedUsers(lastConnectedUsers);}
delete session.quick_login;return __exports;});;

/* /web/static/src/core/user_switch/user_switch.js */
odoo.define('@web/core/user_switch/user_switch',['@odoo/owl','@web/core/registry','@web/core/user','@web/core/utils/urls'],function(require){'use strict';let __exports={};const{Component,useRef,useState,useEffect}=require("@odoo/owl");const{registry}=require("@web/core/registry");const{getLastConnectedUsers,setLastConnectedUsers}=require("@web/core/user");const{imageUrl}=require("@web/core/utils/urls");const UserSwitch=__exports.UserSwitch=class UserSwitch extends Component{static template="web.login_user_switch";static props={};setup(){const users=getLastConnectedUsers();this.root=useRef("root");this.state=useState({users,displayUserChoice:users.length>1,});this.form=document.querySelector("form.oe_login_form");this.form.classList.toggle("d-none",users.length>1);this.form.querySelector(":placeholder-shown")?.focus();useEffect((el)=>el?.querySelector("button.list-group-item-action")?.focus(),()=>[this.root.el]);}
toggleFormDisplay(){this.state.displayUserChoice=!this.state.displayUserChoice&&this.state.users.length;this.form.classList.toggle("d-none",this.state.displayUserChoice);this.form.querySelector(":placeholder-shown")?.focus();}
getAvatarUrl({partnerId,partnerWriteDate:unique}){return imageUrl("res.partner",partnerId,"avatar_128",{unique});}
remove(deletedUser){this.state.users=this.state.users.filter((user)=>user!==deletedUser);setLastConnectedUsers(this.state.users);if(!this.state.users.length){this.fillForm();}}
fillForm(login=""){this.form.querySelector("input#login").value=login;this.form.querySelector("input#password").value="";this.toggleFormDisplay();}}
registry.category("public_components").add("web.user_switch",UserSwitch);return __exports;});;

/* /web/static/src/core/utils/arrays.js */
odoo.define('@web/core/utils/arrays',['@web/core/utils/objects'],function(require){'use strict';let __exports={};const{shallowEqual:_shallowEqual}=require("@web/core/utils/objects");function _cartesian(...args){if(args.length===0){return[undefined];}
const firstArray=args.shift().map((elem)=>[elem]);if(args.length===0){return firstArray;}
const result=[];const productOfOtherArrays=_cartesian(...args);for(const array of firstArray){for(const tuple of productOfOtherArrays){result.push([...array,...tuple]);}}
return result;}
function _getExtractorFrom(criterion){if(criterion){switch(typeof criterion){case"string":return(element)=>element[criterion];case"function":return criterion;default:throw new Error(`Expected criterion of type 'string' or 'function' and got '${typeof criterion}'`);}}else{return(element)=>element;}}
__exports.ensureArray=ensureArray;function ensureArray(value){return isIterable(value)?[...value]:[value];}
__exports.intersection=intersection;function intersection(iter1,iter2){const set2=new Set(iter2);return unique(iter1).filter((v)=>set2.has(v));}
__exports.isIterable=isIterable;function isIterable(value){return Boolean(value&&typeof value==="object"&&value[Symbol.iterator]);}
__exports.groupBy=groupBy;function groupBy(iterable,criterion){const extract=_getExtractorFrom(criterion);const groups={};for(const element of iterable){const group=String(extract(element));if(!(group in groups)){groups[group]=[];}
groups[group].push(element);}
return groups;}
__exports.sortBy=sortBy;function sortBy(iterable,criterion,order="asc"){const extract=_getExtractorFrom(criterion);return[...iterable].sort((elA,elB)=>{const a=extract(elA);const b=extract(elB);let result;if(isNaN(a)&&isNaN(b)){result=a>b?1:a<b?-1:0;}else{result=a-b;}
return order==="asc"?result:-result;});}
__exports.symmetricalDifference=symmetricalDifference;function symmetricalDifference(iter1,iter2){const array1=[...iter1];const array2=[...iter2];return[...array1.filter((value)=>!array2.includes(value)),...array2.filter((value)=>!array1.includes(value)),];}
__exports.cartesian=cartesian;function cartesian(...args){if(args.length===0){return[undefined];}else if(args.length===1){return args[0];}else{return _cartesian(...args);}}
const shallowEqual=__exports.shallowEqual=_shallowEqual;__exports.sections=sections;function sections(iterable){const array=[...iterable];const sections=[];for(let i=0;i<array.length+1;i++){sections.push(array.slice(0,i));}
return sections;}
__exports.unique=unique;function unique(iterable){return[...new Set(iterable)];}
__exports.zip=zip;function zip(iter1,iter2,fill=false){const array1=[...iter1];const array2=[...iter2];const result=[];const getLength=fill?Math.max:Math.min;for(let i=0;i<getLength(array1.length,array2.length);i++){result.push([array1[i],array2[i]]);}
return result;}
__exports.zipWith=zipWith;function zipWith(iter1,iter2,mapFn){return zip(iter1,iter2).map(([e1,e2])=>mapFn(e1,e2));}
__exports.slidingWindow=slidingWindow;function slidingWindow(arr,width){const res=[];for(let i=0;i<=arr.length-width;i++){res.push(arr.slice(i,i+width));}
return res;}
__exports.rotate=rotate;function rotate(i,arr,inc=1){return(arr.length+i+inc)%arr.length;}
return __exports;});;

/* /web/static/src/core/utils/autoresize.js */
odoo.define('@web/core/utils/autoresize',['@odoo/owl','@web/core/browser/browser'],function(require){'use strict';let __exports={};const{useEffect}=require("@odoo/owl");const{browser}=require("@web/core/browser/browser");__exports.useAutoresize=useAutoresize;function useAutoresize(ref,options={}){let wasProgrammaticallyResized=false;let resize=null;useEffect((el)=>{if(el){resize=(programmaticResize=false)=>{wasProgrammaticallyResized=programmaticResize;if(el instanceof HTMLInputElement){resizeInput(el,options);}else{resizeTextArea(el,options);}
options.onResize?.(el,options);};el.addEventListener("input",()=>resize(true));const resizeObserver=new ResizeObserver(()=>{if(wasProgrammaticallyResized){wasProgrammaticallyResized=false;return;}
resize();});resizeObserver.observe(el);return()=>{el.removeEventListener("input",resize);resizeObserver.unobserve(el);resizeObserver.disconnect();resize=null;};}},()=>[ref.el]);useEffect(()=>{if(resize){resize(true);}});}
function resizeInput(input){input.style.width="100%";const maxWidth=input.clientWidth;const isSafari16=/Version\/16.+Safari/i.test(browser.navigator.userAgent);input.style.width="10px";if(input.value===""&&input.placeholder!==""){input.style.width="auto";return;}
if(input.scrollWidth+5+(isSafari16?8:0)>maxWidth){input.style.width="100%";return;}
input.style.width=input.scrollWidth+5+(isSafari16?8:0)+"px";}
__exports.resizeTextArea=resizeTextArea;function resizeTextArea(textarea,options={}){const minimumHeight=options.minimumHeight||0;let heightOffset=0;const style=window.getComputedStyle(textarea);if(style.boxSizing==="border-box"){const paddingHeight=parseFloat(style.paddingTop)+parseFloat(style.paddingBottom);const borderHeight=parseFloat(style.borderTopWidth)+parseFloat(style.borderBottomWidth);heightOffset=borderHeight+paddingHeight;}
const previousStyle={borderTopWidth:style.borderTopWidth,borderBottomWidth:style.borderBottomWidth,padding:style.padding,};Object.assign(textarea.style,{height:"auto",borderTopWidth:0,borderBottomWidth:0,paddingTop:0,paddingRight:style.paddingRight,paddingBottom:0,paddingLeft:style.paddingLeft,});textarea.style.height="auto";const height=Math.max(minimumHeight,textarea.scrollHeight+heightOffset);Object.assign(textarea.style,previousStyle,{height:`${height}px`});textarea.parentElement.style.height=`${height}px`;}
return __exports;});;

/* /web/static/src/core/utils/binary.js */
odoo.define('@web/core/utils/binary',['@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{_t}=require("@web/core/l10n/translation");__exports.isBinarySize=isBinarySize;function isBinarySize(value){return/^\d+(\.\d*)? [^0-9]+$/.test(value);}
__exports.toBase64Length=toBase64Length;function toBase64Length(maxBytes){return Math.ceil(maxBytes*4/3);}
__exports.humanSize=humanSize;function humanSize(size){const units=_t("Bytes|Kb|Mb|Gb|Tb|Pb|Eb|Zb|Yb").split("|");let i=0;while(size>=1024){size/=1024;++i;}
return`${size.toFixed(2)} ${units[i].trim()}`;}
return __exports;});;

/* /web/static/src/core/utils/cache.js */
odoo.define('@web/core/utils/cache',[],function(require){'use strict';let __exports={};const Cache=__exports.Cache=class Cache{constructor(getValue,getKey){this.cache={};this.getKey=getKey;this.getValue=getValue;}
_getCacheAndKey(...path){let cache=this.cache;let key;if(this.getKey){key=this.getKey(...path);}else{for(let i=0;i<path.length-1;i++){cache=cache[path[i]]=cache[path[i]]||{};}
key=path[path.length-1];}
return{cache,key};}
clear(...path){const{cache,key}=this._getCacheAndKey(...path);delete cache[key];}
invalidate(){this.cache={};}
read(...path){const{cache,key}=this._getCacheAndKey(...path);if(!(key in cache)){cache[key]=this.getValue(...path);}
return cache[key];}}
return __exports;});;

/* /web/static/src/core/utils/classname.js */
odoo.define('@web/core/utils/classname',[],function(require){'use strict';let __exports={};__exports.addClassesToElement=addClassesToElement;function addClassesToElement(el,...classes){for(const classDefinition of classes){const classObj=toClassObj(classDefinition);for(const className in classObj){if(classObj[className]){el.classList.add(className.trim());}}}}
__exports.mergeClasses=mergeClasses;function mergeClasses(...classes){const classObj={};for(const classDefinition of classes){Object.assign(classObj,toClassObj(classDefinition));}
return classObj;}
function toClassObj(classDefinition){if(!classDefinition){return{};}else if(typeof classDefinition==="object"){return classDefinition;}else if(typeof classDefinition==="string"){const classObj={};classDefinition.trim().split(/\s+/).forEach((s)=>{classObj[s]=true;});return classObj;}else{console.warn(`toClassObj only supports strings, objects and undefined className (got ${typeof classProp})`);return{};}}
return __exports;});;

/* /web/static/src/core/utils/colors.js */
odoo.define('@web/core/utils/colors',[],function(require){'use strict';let __exports={};__exports.convertRgbToHsl=convertRgbToHsl;function convertRgbToHsl(r,g,b){if(typeof(r)!=='number'||isNaN(r)||r<0||r>255||typeof(g)!=='number'||isNaN(g)||g<0||g>255||typeof(b)!=='number'||isNaN(b)||b<0||b>255){return false;}
var red=r/255;var green=g/255;var blue=b/255;var maxColor=Math.max(red,green,blue);var minColor=Math.min(red,green,blue);var delta=maxColor-minColor;var hue=0;var saturation=0;var lightness=(maxColor+minColor)/2;if(delta){if(maxColor===red){hue=(green-blue)/delta;}
if(maxColor===green){hue=2+(blue-red)/delta;}
if(maxColor===blue){hue=4+(red-green)/delta;}
if(maxColor){saturation=delta/(1-Math.abs(2*lightness-1));}}
hue=60*hue;return{hue:hue<0?hue+360:hue,saturation:saturation*100,lightness:lightness*100,};};__exports.convertHslToRgb=convertHslToRgb;function convertHslToRgb(h,s,l){if(typeof(h)!=='number'||isNaN(h)||h<0||h>360||typeof(s)!=='number'||isNaN(s)||s<0||s>100||typeof(l)!=='number'||isNaN(l)||l<0||l>100){return false;}
var huePrime=h/60;var saturation=s/100;var lightness=l/100;var chroma=saturation*(1-Math.abs(2*lightness-1));var secondComponent=chroma*(1-Math.abs(huePrime%2-1));var lightnessAdjustment=lightness-chroma/2;var precision=255;chroma=Math.round((chroma+lightnessAdjustment)*precision);secondComponent=Math.round((secondComponent+lightnessAdjustment)*precision);lightnessAdjustment=Math.round((lightnessAdjustment)*precision);if(huePrime>=0&&huePrime<1){return{red:chroma,green:secondComponent,blue:lightnessAdjustment,};}
if(huePrime>=1&&huePrime<2){return{red:secondComponent,green:chroma,blue:lightnessAdjustment,};}
if(huePrime>=2&&huePrime<3){return{red:lightnessAdjustment,green:chroma,blue:secondComponent,};}
if(huePrime>=3&&huePrime<4){return{red:lightnessAdjustment,green:secondComponent,blue:chroma,};}
if(huePrime>=4&&huePrime<5){return{red:secondComponent,green:lightnessAdjustment,blue:chroma,};}
if(huePrime>=5&&huePrime<=6){return{red:chroma,green:lightnessAdjustment,blue:secondComponent,};}
return false;};__exports.convertRgbaToCSSColor=convertRgbaToCSSColor;function convertRgbaToCSSColor(r,g,b,a){if(typeof(r)!=='number'||isNaN(r)||r<0||r>255||typeof(g)!=='number'||isNaN(g)||g<0||g>255||typeof(b)!=='number'||isNaN(b)||b<0||b>255){return false;}
if(typeof(a)!=='number'||isNaN(a)||a<0||Math.abs(a-100)<Number.EPSILON){const rr=r<16?'0'+r.toString(16):r.toString(16);const gg=g<16?'0'+g.toString(16):g.toString(16);const bb=b<16?'0'+b.toString(16):b.toString(16);return(`#${rr}${gg}${bb}`).toUpperCase();}
return`rgba(${r}, ${g}, ${b}, ${parseFloat((a / 100.0).toFixed(3))})`;};__exports.convertCSSColorToRgba=convertCSSColorToRgba;function convertCSSColorToRgba(cssColor){const rgba=cssColor.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);if(rgba){if(rgba[4]===undefined){rgba[4]=1;}
return{red:parseInt(rgba[1]),green:parseInt(rgba[2]),blue:parseInt(rgba[3]),opacity:Math.round(parseFloat(rgba[4])*100),};}
if(/^#([0-9A-F]{6}|[0-9A-F]{8})$/i.test(cssColor)){return{red:parseInt(cssColor.substr(1,2),16),green:parseInt(cssColor.substr(3,2),16),blue:parseInt(cssColor.substr(5,2),16),opacity:(cssColor.length===9?(parseInt(cssColor.substr(7,2),16)/255):1)*100,};}
if(/color\(.+\)/.test(cssColor)){const canvasEl=document.createElement("canvas");canvasEl.height=1;canvasEl.width=1;const ctx=canvasEl.getContext("2d");ctx.fillStyle=cssColor;ctx.fillRect(0,0,1,1);const data=ctx.getImageData(0,0,1,1).data;return{red:data[0],green:data[1],blue:data[2],opacity:data[3]/2.55,};}
return false;};__exports.normalizeCSSColor=normalizeCSSColor;function normalizeCSSColor(cssColor){const rgba=convertCSSColorToRgba(cssColor);if(!rgba){return cssColor;}
return convertRgbaToCSSColor(rgba.red,rgba.green,rgba.blue,rgba.opacity);};__exports.isCSSColor=isCSSColor;function isCSSColor(cssColor){return convertCSSColorToRgba(cssColor)!==false;};__exports.mixCssColors=mixCssColors;function mixCssColors(cssColor1,cssColor2,weight){const rgba1=convertCSSColorToRgba(cssColor1);const rgba2=convertCSSColorToRgba(cssColor2);const rgb1=[rgba1.red,rgba1.green,rgba1.blue];const rgb2=[rgba2.red,rgba2.green,rgba2.blue];const[r,g,b]=rgb1.map((_,idx)=>Math.round(rgb2[idx]+(rgb1[idx]-rgb2[idx])*weight));return convertRgbaToCSSColor(r,g,b);};return __exports;});;

/* /web/static/src/core/utils/components.js */
odoo.define('@web/core/utils/components',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,onError,xml}=require("@odoo/owl");const ErrorHandler=__exports.ErrorHandler=class ErrorHandler extends Component{static template=xml`<t t-slot="default" />`;static props=["onError","slots"];setup(){onError((error)=>{this.props.onError(error);});}}
return __exports;});;

/* /web/static/src/core/utils/concurrency.js */
odoo.define('@web/core/utils/concurrency',[],function(require){'use strict';let __exports={};__exports.delay=delay;function delay(wait){return new Promise(function(resolve){setTimeout(resolve,wait);});}
const KeepLast=__exports.KeepLast=class KeepLast{constructor(){this._id=0;}
add(promise){this._id++;const currentId=this._id;return new Promise((resolve,reject)=>{promise.then((value)=>{if(this._id===currentId){resolve(value);}}).catch((reason)=>{if(this._id===currentId){reject(reason);}});});}}
const Mutex=__exports.Mutex=class Mutex{constructor(){this._lock=Promise.resolve();this._queueSize=0;this._unlockedProm=undefined;this._unlock=undefined;}
async exec(action){this._queueSize++;if(!this._unlockedProm){this._unlockedProm=new Promise((resolve)=>{this._unlock=()=>{resolve();this._unlockedProm=undefined;};});}
const always=()=>{return Promise.resolve(action()).finally(()=>{if(--this._queueSize===0){this._unlock();}});};this._lock=this._lock.then(always,always);return this._lock;}
getUnlockedDef(){return this._unlockedProm||Promise.resolve();}}
const Race=__exports.Race=class Race{constructor(){this.currentProm=null;this.currentPromResolver=null;this.currentPromRejecter=null;}
add(promise){if(!this.currentProm){this.currentProm=new Promise((resolve,reject)=>{this.currentPromResolver=(value)=>{this.currentProm=null;this.currentPromResolver=null;this.currentPromRejecter=null;resolve(value);};this.currentPromRejecter=(error)=>{this.currentProm=null;this.currentPromResolver=null;this.currentPromRejecter=null;reject(error);};});}
promise.then(this.currentPromResolver).catch(this.currentPromRejecter);return this.currentProm;}
getCurrentProm(){return this.currentProm;}}
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;});;

/* /web/static/src/core/utils/draggable.js */
odoo.define('@web/core/utils/draggable',['@web/core/utils/draggable_hook_builder_owl','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{makeDraggableHook}=require("@web/core/utils/draggable_hook_builder_owl");const{pick}=require("@web/core/utils/objects");const useDraggable=__exports.useDraggable=makeDraggableHook({name:"useDraggable",onWillStartDrag:({ctx})=>pick(ctx.current,"element"),onDragStart:({ctx})=>pick(ctx.current,"element"),onDrag:({ctx})=>pick(ctx.current,"element"),onDragEnd:({ctx})=>pick(ctx.current,"element"),onDrop:({ctx})=>pick(ctx.current,"element"),});return __exports;});;

/* /web/static/src/core/utils/draggable_hook_builder.js */
odoo.define('@web/core/utils/draggable_hook_builder',['@web/core/utils/numbers','@web/core/utils/objects','@web/core/utils/scrolling','@web/core/utils/timing','@web/core/browser/browser','@web/core/browser/feature_detection'],function(require){'use strict';let __exports={};const{clamp}=require("@web/core/utils/numbers");const{omit}=require("@web/core/utils/objects");const{closestScrollableX,closestScrollableY}=require("@web/core/utils/scrolling");const{setRecurringAnimationFrame}=require("@web/core/utils/timing");const{browser}=require("@web/core/browser/browser");const{hasTouch,isBrowserFirefox,isIOS}=require("@web/core/browser/feature_detection");const DRAGGABLE_CLASS="o_draggable";const DRAGGED_CLASS=__exports.DRAGGED_CLASS="o_dragged";const DEFAULT_ACCEPTED_PARAMS={enable:[Boolean,Function],preventDrag:[Function],ref:[Object],elements:[String],handle:[String,Function],ignore:[String,Function],cursor:[String],edgeScrolling:[Object,Function],delay:[Number],tolerance:[Number],touchDelay:[Number],iframeWindow:[Object,Function],};const DEFAULT_DEFAULT_PARAMS={elements:`.${DRAGGABLE_CLASS}`,enable:true,preventDrag:()=>false,edgeScrolling:{speed:10,threshold:30,},delay:0,tolerance:10,touchDelay:300,};const LEFT_CLICK=0;const MANDATORY_PARAMS=["ref"];const WHITE_LISTED_KEYS=["Alt","Control","Meta","Shift"];const elCache={};function camelToKebab(str){return str.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();}
function getReturnValue(valueOrFn){if(typeof valueOrFn==="function"){return valueOrFn();}
return valueOrFn;}
function getScrollParents(el){return[closestScrollableX(el),closestScrollableY(el)];}
function makeCleanupManager(defaultCleanupFn){const add=(cleanupFn)=>typeof cleanupFn==="function"&&cleanups.push(cleanupFn);const cleanup=()=>{while(cleanups.length){cleanups.pop()();}
add(defaultCleanupFn);};const cleanups=[];add(defaultCleanupFn);return{add,cleanup};}
function makeDOMHelpers(cleanup){const addClass=(el,...classNames)=>{if(!el||!classNames.length){return;}
cleanup.add(()=>el.classList.remove(...classNames));el.classList.add(...classNames);};const addListener=(el,event,callback,options={})=>{if(!el||!event||!callback){return;}
const{noAddedStyle}=options;delete options.noAddedStyle;el.addEventListener(event,callback,options);if(!noAddedStyle&&/mouse|pointer|touch/.test(event)){addStyle(el,{pointerEvents:"auto"});}
cleanup.add(()=>el.removeEventListener(event,callback,options));};const addStyle=(el,style)=>{if(!el||!style||!Object.keys(style).length){return;}
cleanup.add(saveAttribute(el,"style"));for(const key in style){const[value,priority]=String(style[key]).split(/\s*!\s*/);el.style.setProperty(camelToKebab(key),value,priority);}};const getRect=(el,options={})=>{if(!el){return{};}
const rect=el.getBoundingClientRect();rect.height=el.offsetHeight;if(options.adjust){const style=getComputedStyle(el);const[pl,pr,pt,pb]=["padding-left","padding-right","padding-top","padding-bottom",].map((prop)=>pixelValueToNumber(style.getPropertyValue(prop)));rect.x+=pl;rect.y+=pt;rect.width-=pl+pr;rect.height-=pt+pb;}
return rect;};const removeAttribute=(el,attribute)=>{if(!el||!attribute){return;}
cleanup.add(saveAttribute(el,attribute));el.removeAttribute(attribute);};const removeClass=(el,...classNames)=>{if(!el||!classNames.length){return;}
cleanup.add(saveAttribute(el,"class"));el.classList.remove(...classNames);};const removeStyle=(el,...properties)=>{if(!el||!properties.length){return;}
cleanup.add(saveAttribute(el,"style"));for(const key of properties){el.style.removeProperty(camelToKebab(key));}};const setAttribute=(el,attribute,value)=>{if(!el||!attribute){return;}
cleanup.add(saveAttribute(el,attribute));el.setAttribute(attribute,String(value));};return{addClass,addListener,addStyle,getRect,removeAttribute,removeClass,removeStyle,setAttribute,};}
function pixelValueToNumber(val){return Number(val.endsWith("px")?val.slice(0,-2):val);}
function safePrevent(ev,{stop}={}){if(ev.cancelable){ev.preventDefault();if(stop){ev.stopPropagation();}}}
function saveAttribute(el,attribute){const restoreAttribute=()=>{cache.delete(el);if(hasAttribute){el.setAttribute(attribute,originalValue);}else{el.removeAttribute(attribute);}};if(!(attribute in elCache)){elCache[attribute]=new Set();}
const cache=elCache[attribute];if(cache.has(el)){return;}
cache.add(el);const hasAttribute=el.hasAttribute(attribute);const originalValue=el.getAttribute(attribute);return restoreAttribute;}
function toFunction(value){return typeof value==="function"?value:()=>value;}
__exports.makeDraggableHook=makeDraggableHook;function makeDraggableHook(hookParams){hookParams=getReturnValue(hookParams);const hookName=hookParams.name||"useAnonymousDraggable";const{setupHooks}=hookParams;const allAcceptedParams={...DEFAULT_ACCEPTED_PARAMS,...hookParams.acceptedParams};const defaultParams={...DEFAULT_DEFAULT_PARAMS,...hookParams.defaultParams};const computeParams=(params)=>{const computedParams={enable:()=>true};for(const prop in allAcceptedParams){if(prop in params){if(prop==="enable"){computedParams[prop]=toFunction(params[prop]);}else if(allAcceptedParams[prop].length===1&&allAcceptedParams[prop][0]===Function){computedParams[prop]=params[prop];}else{computedParams[prop]=getReturnValue(params[prop]);}}}
return Object.entries(computedParams);};const makeError=(reason)=>new Error(`Error in hook ${hookName}: ${reason}.`);let preventClick=false;return{[hookName](params){const callBuildHandler=(hookHandlerName,arg)=>{if(typeof hookParams[hookHandlerName]!=="function"){return;}
const returnValue=hookParams[hookHandlerName]({ctx,...helpers,...arg});if(returnValue){callHandler(hookHandlerName,returnValue);}};const callHandler=(handlerName,arg)=>{if(typeof params[handlerName]!=="function"){return;}
try{params[handlerName]({...dom,...ctx.pointer,...arg});}catch(err){dragEnd(null,true);throw err;}};const canStartDrag=()=>{const{pointer,current:{initialPosition},}=ctx;return(!ctx.tolerance||Math.hypot(pointer.x-initialPosition.x,pointer.y-initialPosition.y)>=ctx.tolerance);};const dragStart=()=>{state.dragging=true;state.willDrag=false;const isDocumentScrollingElement=ctx.current.container===ctx.current.container.ownerDocument.scrollingElement;[ctx.current.scrollParentX,ctx.current.scrollParentY]=isDocumentScrollingElement?[ctx.current.container,ctx.current.container]:getScrollParents(ctx.current.container);updateRects();const{x,y,width,height}=ctx.current.elementRect;ctx.current.offset={x:ctx.current.initialPosition.x-x,y:ctx.current.initialPosition.y-y,};if(ctx.followCursor){dom.addStyle(ctx.current.element,{width:`${width}px`,height:`${height}px`,position:"fixed !important",});updateElementPosition();}
dom.addClass(document.body,"pe-none","user-select-none");if(params.iframeWindow){for(const iframe of document.getElementsByTagName("iframe")){if(iframe.contentWindow===params.iframeWindow){dom.addClass(iframe,"pe-none","user-select-none");}}}
if(ctx.cursor){dom.addStyle(document.body,{cursor:ctx.cursor});}
if((ctx.current.scrollParentX||ctx.current.scrollParentY)&&ctx.edgeScrolling.enabled){const cleanupFn=setRecurringAnimationFrame(handleEdgeScrolling);cleanup.add(cleanupFn);}
dom.addClass(ctx.current.element,DRAGGED_CLASS);callBuildHandler("onDragStart");};const dragEnd=(target,inErrorState)=>{if(state.dragging){preventClick=true;if(!inErrorState){if(target&&ctx.current.element.isConnected){callBuildHandler("onDrop",{target});}
callBuildHandler("onDragEnd");}}
cleanup.cleanup();};const handleEdgeScrolling=(deltaTime)=>{updateRects();const{x:pointerX,y:pointerY}=ctx.pointer;const xRect=ctx.current.scrollParentXRect;const yRect=ctx.current.scrollParentYRect;const scrollParentYEl=ctx.current.scrollParentY;if(scrollParentYEl===ctx.current.container.ownerDocument.scrollingElement){yRect.y+=scrollParentYEl.scrollTop;}
const{direction,speed,threshold}=ctx.edgeScrolling;const correctedSpeed=(speed/16)*deltaTime;const diff={};ctx.current.scrollingEdge=null;if(xRect){const maxWidth=xRect.x+xRect.width;if(pointerX-xRect.x<threshold){diff.x=[pointerX-xRect.x,-1];ctx.current.scrollingEdge="left";}else if(maxWidth-pointerX<threshold){diff.x=[maxWidth-pointerX,1];ctx.current.scrollingEdge="right";}}
if(yRect){const maxHeight=yRect.y+yRect.height;if(pointerY-yRect.y<threshold){diff.y=[pointerY-yRect.y,-1];ctx.current.scrollingEdge="top";}else if(maxHeight-pointerY<threshold){diff.y=[maxHeight-pointerY,1];ctx.current.scrollingEdge="bottom";}}
const diffToScroll=([delta,sign])=>(1-Math.max(delta,0)/threshold)*correctedSpeed*sign;if((!direction||direction==="vertical")&&diff.y){ctx.current.scrollParentY.scrollBy({top:diffToScroll(diff.y)});}
if((!direction||direction==="horizontal")&&diff.x){ctx.current.scrollParentX.scrollBy({left:diffToScroll(diff.x)});}
callBuildHandler("onDrag");};const onClick=(ev)=>{if(preventClick){safePrevent(ev,{stop:true});}};const onKeyDown=(ev)=>{if(!state.dragging||!ctx.enable()){return;}
if(!WHITE_LISTED_KEYS.includes(ev.key)){safePrevent(ev,{stop:true});dragEnd(null);}};const onPointerCancel=()=>{dragEnd(null);};const onPointerDown=(ev)=>{preventClick=false;updatePointerPosition(ev);const initiationDelay=ev.pointerType==="touch"?ctx.touchDelay:ctx.delay;dragEnd(null);const fullSelectorEl=ev.target.closest(ctx.fullSelector);if(ev.button!==LEFT_CLICK||!ctx.enable()||!fullSelectorEl||(ctx.ignoreSelector&&ev.target.closest(ctx.ignoreSelector))||ctx.preventDrag(fullSelectorEl)){return;}
safePrevent(ev);let activeElement=document.activeElement;while(activeElement?.nodeName==="IFRAME"){activeElement=activeElement.contentDocument?.activeElement;}
if(activeElement&&!activeElement.contains(ev.target)){activeElement.blur();}
const{currentTarget,pointerId,target}=ev;ctx.current.initialPosition={...ctx.pointer};if(target.hasPointerCapture(pointerId)){target.releasePointerCapture(pointerId);}
if(initiationDelay){if(hasTouch()){if(ev.pointerType==="touch"){dom.addClass(target.closest(ctx.elementSelector),"o_touch_bounce");}
if(isBrowserFirefox()){const links=[...currentTarget.querySelectorAll("[href]")];if(currentTarget.hasAttribute("href")){links.unshift(currentTarget);}
for(const link of links){dom.removeAttribute(link,"href");}}
if(isIOS()){for(const image of currentTarget.getElementsByTagName("img")){dom.setAttribute(image,"draggable",false);}}}
ctx.current.timeout=browser.setTimeout(()=>{ctx.current.initialPosition={...ctx.pointer};willStartDrag(target);const{x:px,y:py}=ctx.pointer;const{x,y,width,height}=dom.getRect(ctx.current.element);if(px<x||x+width<px||py<y||y+height<py){dragEnd(null);}},initiationDelay);cleanup.add(()=>browser.clearTimeout(ctx.current.timeout));}else{willStartDrag(target);}};const onPointerMove=(ev)=>{updatePointerPosition(ev);if(!ctx.current.element||!ctx.enable()){return;}
safePrevent(ev);if(!state.dragging){if(!canStartDrag()){return;}
dragStart();}else if(!ctx.current.element.isConnected){return dragEnd(null);}
if(ctx.followCursor){updateElementPosition();}
callBuildHandler("onDrag");};const onPointerUp=(ev)=>{updatePointerPosition(ev);dragEnd(ev.target);};const updateElementPosition=()=>{const{containerRect,element,elementRect,offset}=ctx.current;const{width:ew,height:eh}=elementRect;const{x:cx,y:cy,width:cw,height:ch}=containerRect;dom.addStyle(element,{left:`${clamp(ctx.pointer.x - offset.x, cx, cx + cw - ew)}px`,top:`${clamp(ctx.pointer.y - offset.y, cy, cy + ch - eh)}px`,});};const updatePointerPosition=(ev)=>{ctx.pointer.x=ev.clientX;ctx.pointer.y=ev.clientY;};const updateRects=()=>{const{current}=ctx;const{container,element,scrollParentX,scrollParentY}=current;current.containerRect=dom.getRect(container,{adjust:true});let iframeOffsetX=0;let iframeOffsetY=0;const iframeEl=container.ownerDocument.defaultView.frameElement;if(iframeEl&&!iframeEl.contentDocument?.contains(element)){const{x,y}=dom.getRect(iframeEl);iframeOffsetX=x;iframeOffsetY=y;current.containerRect.x+=iframeOffsetX;current.containerRect.y+=iframeOffsetY;}
current.containerRect.width=container.scrollWidth;current.containerRect.height=container.scrollHeight;current.scrollParentXRect=null;current.scrollParentYRect=null;if(ctx.edgeScrolling.enabled){if(scrollParentX){current.scrollParentXRect=dom.getRect(scrollParentX,{adjust:true});current.scrollParentXRect.x+=iframeOffsetX;current.scrollParentXRect.y+=iframeOffsetY;const right=Math.min(current.containerRect.left+container.scrollWidth,current.scrollParentXRect.right);current.containerRect.x=Math.max(current.containerRect.x,current.scrollParentXRect.x);current.containerRect.width=right-current.containerRect.x;}
if(scrollParentY){current.scrollParentYRect=dom.getRect(scrollParentY,{adjust:true});current.scrollParentYRect.x+=iframeOffsetX;current.scrollParentYRect.y+=iframeOffsetY;const bottom=Math.min(current.containerRect.top+container.scrollHeight,current.scrollParentYRect.bottom);current.containerRect.y=Math.max(current.containerRect.y,current.scrollParentYRect.y);current.containerRect.height=bottom-current.containerRect.y;}}
ctx.current.elementRect=dom.getRect(element);};const willStartDrag=(target)=>{ctx.current.element=target.closest(ctx.elementSelector);ctx.current.container=ctx.ref.el;cleanup.add(()=>(ctx.current={}));state.willDrag=true;callBuildHandler("onWillStartDrag");if(hasTouch()){dom.addListener(window,"touchmove",safePrevent,{passive:false,noAddedStyle:true,});if(params.iframeWindow){dom.addListener(params.iframeWindow,"touchmove",safePrevent,{passive:false,noAddedStyle:true,});}}};const cleanup=makeCleanupManager(()=>(state.dragging=false));const effectCleanup=makeCleanupManager();const dom=makeDOMHelpers(cleanup);const helpers={...dom,addCleanup:cleanup.add,addEffectCleanup:effectCleanup.add,callHandler,};const state=setupHooks.wrapState({dragging:false});for(const prop in allAcceptedParams){const type=typeof params[prop];const acceptedTypes=allAcceptedParams[prop].map((t)=>t.name.toLowerCase());if(params[prop]){if(!acceptedTypes.includes(type)){throw makeError(`invalid type for property "${prop}" in parameters: expected { ${acceptedTypes.join(
                                ", "
                            )} } and got ${type}`);}}else if(MANDATORY_PARAMS.includes(prop)&&!defaultParams[prop]){throw makeError(`missing required property "${prop}" in parameters`);}}
const ctx={enable:()=>false,preventDrag:()=>false,ref:params.ref,ignoreSelector:null,fullSelector:null,followCursor:true,cursor:null,pointer:{x:0,y:0},edgeScrolling:{enabled:true},get dragging(){return state.dragging;},get willDrag(){return state.willDrag;},current:{},};setupHooks.setup((...deps)=>{const params=Object.fromEntries(deps);const actualParams={...defaultParams,...omit(params,"edgeScrolling")};if(params.edgeScrolling){actualParams.edgeScrolling={...actualParams.edgeScrolling,...params.edgeScrolling,};}
if(!ctx.ref.el){return;}
ctx.enable=actualParams.enable;if(actualParams.preventDrag){ctx.preventDrag=actualParams.preventDrag;}
ctx.elementSelector=actualParams.elements;if(!ctx.elementSelector){throw makeError(`no value found by "elements" selector: ${ctx.elementSelector}`);}
const allSelectors=[ctx.elementSelector];ctx.cursor=actualParams.cursor||null;if(actualParams.handle){allSelectors.push(actualParams.handle);}
if(actualParams.ignore){ctx.ignoreSelector=actualParams.ignore;}
ctx.fullSelector=allSelectors.join(" ");Object.assign(ctx.edgeScrolling,actualParams.edgeScrolling);ctx.delay=actualParams.delay;ctx.touchDelay=actualParams.delay||actualParams.touchDelay;ctx.tolerance=actualParams.tolerance;callBuildHandler("onComputeParams",{params:actualParams});return effectCleanup.cleanup;},()=>computeParams(params));const useMouseEvents=isBrowserFirefox()&&!hasTouch()&&params.iframeWindow;setupHooks.setup((el)=>{if(el){const{add,cleanup}=makeCleanupManager();const{addListener}=makeDOMHelpers({add});const event=useMouseEvents?"mousedown":"pointerdown";addListener(el,event,onPointerDown,{noAddedStyle:true});addListener(el,"click",onClick);if(hasTouch()){addListener(el,"contextmenu",safePrevent);addListener(el,"touchstart",()=>{},{passive:false,noAddedStyle:true,});}
return cleanup;}},()=>[ctx.ref.el]);const addWindowListener=(type,listener,options)=>{if(params.iframeWindow){setupHooks.addListener(params.iframeWindow,type,listener,options);}
setupHooks.addListener(window,type,listener,options);};const throttledOnPointerMove=setupHooks.throttle(onPointerMove);addWindowListener(useMouseEvents?"mousemove":"pointermove",throttledOnPointerMove,{passive:false});addWindowListener(useMouseEvents?"mouseup":"pointerup",onPointerUp);addWindowListener("pointercancel",onPointerCancel);addWindowListener("keydown",onKeyDown,{capture:true});setupHooks.teardown(()=>dragEnd(null));return state;},}[hookName];}
return __exports;});;

/* /web/static/src/core/utils/draggable_hook_builder_owl.js */
odoo.define('@web/core/utils/draggable_hook_builder_owl',['@odoo/owl','@web/core/utils/timing','@web/core/utils/draggable_hook_builder'],function(require){'use strict';let __exports={};const{onWillUnmount,reactive,useEffect,useExternalListener}=require("@odoo/owl");const{useThrottleForAnimation}=require("@web/core/utils/timing");const{makeDraggableHook:nativeMakeDraggableHook}=require("@web/core/utils/draggable_hook_builder");__exports.makeDraggableHook=makeDraggableHook;function makeDraggableHook(params){return nativeMakeDraggableHook({...params,setupHooks:{addListener:useExternalListener,setup:useEffect,teardown:onWillUnmount,throttle:useThrottleForAnimation,wrapState:reactive,},});}
return __exports;});;

/* /web/static/src/core/utils/files.js */
odoo.define('@web/core/utils/files',['@web/core/utils/numbers','@web/core/utils/hooks','@web/session','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{humanNumber}=require("@web/core/utils/numbers");const{useService}=require("@web/core/utils/hooks");const{session}=require("@web/session");const{_t}=require("@web/core/l10n/translation");const DEFAULT_MAX_FILE_SIZE=__exports.DEFAULT_MAX_FILE_SIZE=128*1024*1024;__exports.checkFileSize=checkFileSize;function checkFileSize(fileSize,notificationService){const maxUploadSize=session.max_file_upload_size||DEFAULT_MAX_FILE_SIZE;if(fileSize>maxUploadSize){notificationService.add(_t("The selected file (%(size)sB) is larger than the maximum allowed file size (%(maxSize)sB).",{size:humanNumber(fileSize),maxSize:humanNumber(maxUploadSize)}),{type:"danger",});return false;}
return true;}
__exports.useFileUploader=useFileUploader;function useFileUploader(){const http=useService("http");const notification=useService("notification");return async(route,params)=>{if((params.ufile&&params.ufile.length)||params.file){const fileSize=(params.ufile&&params.ufile[0].size)||params.file.size;if(!checkFileSize(fileSize,notification)){return null;}}
const fileData=await http.post(route,params,"text");const parsedFileData=JSON.parse(fileData);if(parsedFileData.error){throw new Error(parsedFileData.error);}
return parsedFileData;};}
__exports.resizeBlobImg=resizeBlobImg;function resizeBlobImg(blob,params={}){if(!blob.type||!blob.type.startsWith("image/")){return Promise.reject(new Error(_t("The file is not an image, resizing is not possible")));}
const{width,height,offsetX,offsetY}={width:256,height:256,offsetX:0.5,offsetY:0.5,...params,};return new Promise((resolve,reject)=>{const img=new Image();img.onload=()=>{if(width<img.width||height<img.height){const canvas=document.createElement("canvas");canvas.width=width;canvas.height=height;const ctx=canvas.getContext("2d");ctx.imageSmoothingQuality="high";ctx.mozImageSmoothingEnabled=true;ctx.webkitImageSmoothingEnabled=true;ctx.msImageSmoothingEnabled=true;ctx.imageSmoothingEnabled=true;const srcRatio=img.width/img.height;const dWidth=Math.min(Math.floor(height*srcRatio),width);const dHeight=Math.min(Math.floor(width/srcRatio),height);const dx=Math.round((width-dWidth)*offsetX);const dy=Math.round((height-dHeight)*offsetY);ctx.drawImage(img,0,0,img.width,img.height,dx,dy,dWidth,dHeight);canvas.toBlob(resolve);}else{resolve(blob);}};img.onerror=()=>{reject(new Error(_t("The resizing of the image failed")));};img.src=URL.createObjectURL(blob);});}
return __exports;});;

/* /web/static/src/core/utils/functions.js */
odoo.define('@web/core/utils/functions',[],function(require){'use strict';let __exports={};__exports.memoize=memoize;function memoize(func){const cache=new Map();const funcName=func.name?func.name+" (memoized)":"memoized";return{[funcName](...args){if(!cache.has(args[0])){cache.set(args[0],func(...args));}
return cache.get(...args);},}[funcName];}
__exports.uniqueId=uniqueId;function uniqueId(prefix=""){return`${prefix}${++uniqueId.nextId}`;}
uniqueId.nextId=0;return __exports;});;

/* /web/static/src/core/utils/hooks.js */
odoo.define('@web/core/utils/hooks',['@web/core/browser/feature_detection','@odoo/owl'],function(require){'use strict';let __exports={};const{hasTouch,isMobileOS}=require("@web/core/browser/feature_detection");const{status,useComponent,useEffect,useRef,onWillUnmount}=require("@odoo/owl");__exports.useAutofocus=useAutofocus;function useAutofocus({refName,selectAll,mobile}={}){const ref=useRef(refName||"autofocus");const uiService=useService("ui");if(!mobile&&hasTouch()){return ref;}
if(!mobile&&isMobileOS()){return ref;}
useEffect((el)=>{if(el&&(!uiService.activeElement||uiService.activeElement.contains(el))){el.focus();if(["INPUT","TEXTAREA"].includes(el.tagName)&&el.type!=="number"){el.selectionEnd=el.value.length;el.selectionStart=selectAll?0:el.value.length;}}},()=>[ref.el]);return ref;}
__exports.useBus=useBus;function useBus(bus,eventName,callback){const component=useComponent();useEffect(()=>{const listener=callback.bind(component);bus.addEventListener(eventName,listener);return()=>bus.removeEventListener(eventName,listener);},()=>[]);}
const useServiceProtectMethodHandling=__exports.useServiceProtectMethodHandling={fn(){return this.original();},mocked(){return new Promise(()=>{});},original(){return Promise.reject(new Error("Component is destroyed"));},};function _protectMethod(component,fn){return function(...args){if(status(component)==="destroyed"){return useServiceProtectMethodHandling.fn();}
const prom=Promise.resolve(fn.call(this,...args));const protectedProm=prom.then((result)=>status(component)==="destroyed"?new Promise(()=>{}):result);return Object.assign(protectedProm,{abort:prom.abort,cancel:prom.cancel,});};}
const SERVICES_METADATA=__exports.SERVICES_METADATA={};__exports.useService=useService;function useService(serviceName){const component=useComponent();const{services}=component.env;if(!(serviceName in services)){throw new Error(`Service ${serviceName} is not available`);}
const service=services[serviceName];if(serviceName in SERVICES_METADATA){if(service instanceof Function){return _protectMethod(component,service);}else{const methods=SERVICES_METADATA[serviceName];const result=Object.create(service);for(const method of methods){result[method]=_protectMethod(component,service[method]);}
return result;}}
return service;}
__exports.useSpellCheck=useSpellCheck;function useSpellCheck({refName}={}){const elements=[];const ref=useRef(refName||"spellcheck");function toggleSpellcheck(ev){ev.target.spellcheck=document.activeElement===ev.target;}
useEffect((el)=>{if(el){const inputs=["INPUT","TEXTAREA"].includes(el.nodeName)||el.isContentEditable?[el]:el.querySelectorAll("input, textarea, [contenteditable=true]");inputs.forEach((input)=>{if(input.spellcheck!==false){elements.push(input);input.addEventListener("focus",toggleSpellcheck);input.addEventListener("blur",toggleSpellcheck);}});}
return()=>{elements.forEach((input)=>{input.removeEventListener("focus",toggleSpellcheck);input.removeEventListener("blur",toggleSpellcheck);});};},()=>[ref.el]);}
__exports.useChildRef=useChildRef;function useChildRef(){let defined=false;let value;return function ref(v){value=v;if(defined){return;}
Object.defineProperty(ref,"el",{get(){return value.el;},});defined=true;};}
__exports.useForwardRefToParent=useForwardRefToParent;function useForwardRefToParent(refName){const component=useComponent();const ref=useRef(refName);if(component.props[refName]){component.props[refName](ref);}
return ref;}
__exports.useOwnedDialogs=useOwnedDialogs;function useOwnedDialogs(){const dialogService=useService("dialog");const cbs=[];onWillUnmount(()=>{cbs.forEach((cb)=>cb());});const addDialog=(...args)=>{const close=dialogService.add(...args);cbs.push(close);return close;};return addDialog;}
__exports.useRefListener=useRefListener;function useRefListener(ref,...listener){useEffect((el)=>{el?.addEventListener(...listener);return()=>el?.removeEventListener(...listener);},()=>[ref.el]);}
return __exports;});;

/* /web/static/src/core/utils/html.js */
odoo.define('@web/core/utils/html',['@odoo/owl','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{markup}=require("@odoo/owl");const{escape}=require("@web/core/utils/strings");const Markup=markup().constructor;__exports.htmlEscape=htmlEscape;function htmlEscape(content){return content instanceof Markup?content:markup(escape(content));}
__exports.isHtmlEmpty=isHtmlEmpty;function isHtmlEmpty(content=""){const div=document.createElement("div");setElementContent(div,content);return div.textContent.trim()==="";}
__exports.setElementContent=setElementContent;function setElementContent(element,content){if(content instanceof Markup){element.innerHTML=content;}else{element.textContent=content;}}
return __exports;});;

/* /web/static/src/core/utils/misc.js */
odoo.define('@web/core/utils/misc',[],function(require){'use strict';let __exports={};const eventHandledWeakMap=new WeakMap();__exports.isEventHandled=isEventHandled;function isEventHandled(ev,markName){if(!eventHandledWeakMap.get(ev)){return false;}
return eventHandledWeakMap.get(ev).includes(markName);}
__exports.markEventHandled=markEventHandled;function markEventHandled(ev,markName){if(!eventHandledWeakMap.get(ev)){eventHandledWeakMap.set(ev,[]);}
eventHandledWeakMap.get(ev).push(markName);}
return __exports;});;

/* /web/static/src/core/utils/nested_sortable.js */
odoo.define('@web/core/utils/nested_sortable',['@web/core/l10n/localization','@web/core/utils/draggable_hook_builder_owl'],function(require){'use strict';let __exports={};const{localization}=require("@web/core/l10n/localization");const{makeDraggableHook}=require("@web/core/utils/draggable_hook_builder_owl");const useNestedSortable=__exports.useNestedSortable=makeDraggableHook({name:"useNestedSortable",acceptedParams:{groups:[String,Function],connectGroups:[Boolean,Function],nest:[Boolean],listTagName:[String],nestInterval:[Number],maxLevels:[Number],isAllowed:[Function],useElementSize:[Boolean],},defaultParams:{connectGroups:false,currentGroup:null,cursor:"grabbing",edgeScrolling:{speed:20,threshold:60},elements:"li",groupSelector:null,nest:false,listTagName:"ul",nestInterval:15,maxLevels:0,isAllowed:(ctx)=>true,useElementSize:false,},onComputeParams({ctx,params}){ctx.groupSelector=params.groups||null;if(ctx.groupSelector){ctx.fullSelector=[ctx.groupSelector,ctx.fullSelector].join(" ");}
ctx.connectGroups=params.connectGroups;ctx.nest=params.nest;ctx.listTagName=params.listTagName;ctx.nestInterval=params.nestInterval;ctx.isRTL=localization.direction==="rtl";ctx.maxLevels=params.maxLevels||0;ctx.isAllowed=params.isAllowed??(()=>true);ctx.useElementSize=params.useElementSize;},onWillStartDrag({ctx,addCleanup}){if(ctx.groupSelector){ctx.currentGroup=ctx.current.element.closest(ctx.groupSelector);if(!ctx.connectGroups){ctx.current.container=ctx.currentGroup;}}
if(ctx.nest){ctx.prevNestX=ctx.pointer.x;}
ctx.current.placeHolder=ctx.current.element.cloneNode(false);ctx.current.placeHolder.removeAttribute("id");ctx.current.placeHolder.classList.add("w-100","d-block");if(ctx.useElementSize){ctx.current.placeHolder.style.height=getComputedStyle(ctx.current.element).height;ctx.current.placeHolder.classList.add("o_nested_sortable_placeholder_realsize");}else{ctx.current.placeHolder.classList.add("o_nested_sortable_placeholder");}
addCleanup(()=>ctx.current.placeHolder.remove());},onDragStart({ctx,addStyle}){ctx.selectorX=ctx.isRTL?ctx.current.elementRect.left+1:ctx.current.elementRect.right-1;ctx.current.element.after(ctx.current.placeHolder);addStyle(ctx.current.element,{opacity:0.5});addStyle(document.body,{"pointer-events":"auto"});addStyle(document.querySelector(".o_navbar"),{"pointer-events":"none"});addStyle(document.querySelector(".o_action_manager"),{"pointer-events":"none"});addStyle(ctx.current.container,{"pointer-events":"auto"});return{element:ctx.current.element,group:ctx.currentGroup,};},_getDeepestChildLevel(ctx,node,depth=0){let result=0;const childSelector=`${ctx.listTagName} ${ctx.elementSelector}`;for(const childNode of node.querySelectorAll(childSelector)){result=Math.max(this._getDeepestChildLevel(ctx,childNode,depth+1),result);}
return depth?result+1:result;},_hasReachMaxAllowedLevel(ctx){if(!ctx.nest||ctx.maxLevels<1){return false;}
let level=this._getDeepestChildLevel(ctx,ctx.current.element);let list=ctx.current.placeHolder.closest(ctx.listTagName);while(list){level++;list=list.parentNode.closest(ctx.listTagName);}
return level>ctx.maxLevels;},_isAllowedNodeMove(ctx){return(!this._hasReachMaxAllowedLevel(ctx)&&ctx.isAllowed(ctx.current,ctx.elementSelector));},onDrag({ctx,callHandler}){const onMove=(prevPos)=>{if(!ctx.isAllowed(ctx.current,ctx.elementSelector)){ctx.current.placeHolder.classList.add("d-none");return;}else if(this._hasReachMaxAllowedLevel(ctx)){const previousSiblingEl=ctx.current.placeHolder.closest(ctx.listTagName).closest(ctx.elementSelector);previousSiblingEl.after(ctx.current.placeHolder);return;}
ctx.current.placeHolder.classList.remove("d-none");callHandler("onMove",{element:ctx.current.element,previous:ctx.current.placeHolder.previousElementSibling,next:ctx.current.placeHolder.nextElementSibling,parent:ctx.nest?ctx.current.placeHolder.parentElement.closest(ctx.elementSelector):false,group:ctx.currentGroup,newGroup:ctx.connectGroups?ctx.current.placeHolder.closest(ctx.groupSelector):ctx.currentGroup,prevPos,placeholder:ctx.current.placeHolder,});};const getChildList=(el)=>{let list=el.querySelector(ctx.listTagName);if(!list){list=document.createElement(ctx.listTagName);el.appendChild(list);}
return list;};const getPosition=(el)=>{return{previous:el.previousElementSibling,next:el.nextElementSibling,parent:el.parentElement?.closest(ctx.elementSelector)||null,group:ctx.groupSelector?el.closest(ctx.groupSelector):false,};};const position=getPosition(ctx.current.placeHolder);if(ctx.nest){const xInterval=ctx.prevNestX-ctx.pointer.x;if(ctx.nestInterval-(-1)**ctx.isRTL*xInterval<1){let nextElement=position.next;if(nextElement===ctx.current.element){nextElement=nextElement.nextElementSibling;}
if(!nextElement){const newSibling=position.parent;if(newSibling){newSibling.after(ctx.current.placeHolder);onMove(position);}}
ctx.prevNestX=ctx.pointer.x;return;}else if(ctx.nestInterval+(-1)**ctx.isRTL*xInterval<1){let parent=position.previous;if(parent===ctx.current.element){parent=parent.previousElementSibling;}
if(parent&&parent.matches(ctx.elementSelector)){getChildList(parent).appendChild(ctx.current.placeHolder);onMove(position);}
ctx.prevNestX=ctx.pointer.x;return;}}
const currentTop=ctx.pointer.y-ctx.current.offset.y;const closestEl=document.elementFromPoint(ctx.selectorX,currentTop);if(!closestEl){return;}
const element=closestEl.closest(ctx.elementSelector);if(element&&element!==ctx.current.placeHolder){const elementPosition=getPosition(element);const eRect=element.getBoundingClientRect();const pos=ctx.current.placeHolder.compareDocumentPosition(element);if(currentTop-eRect.y<10){if(pos&Node.DOCUMENT_POSITION_PRECEDING&&(ctx.nest||elementPosition.parent===position.parent)){element.before(ctx.current.placeHolder);onMove(position);ctx.prevNestX=ctx.pointer.x;}}else if(currentTop-eRect.y>15&&pos===Node.DOCUMENT_POSITION_FOLLOWING){if(ctx.nest){const elementChildList=getChildList(element);if(elementChildList.querySelector(ctx.elementSelector)){elementChildList.prepend(ctx.current.placeHolder);onMove(position);}else{element.after(ctx.current.placeHolder);onMove(position);}
ctx.prevNestX=ctx.pointer.x;}else if(elementPosition.parent===position.parent){element.after(ctx.current.placeHolder);onMove(position);}}}else{const group=closestEl.closest(ctx.groupSelector);if(group&&group!==position.group&&(ctx.nest||!position.parent)){if(group.compareDocumentPosition(position.group)===Node.DOCUMENT_POSITION_PRECEDING){getChildList(group).prepend(ctx.current.placeHolder);onMove(position);}else{getChildList(group).appendChild(ctx.current.placeHolder);onMove(position);}
ctx.prevNestX=ctx.pointer.x;callHandler("onGroupEnter",{group,placeholder:ctx.current.placeHolder});callHandler("onGroupLeave",{group:position.group,placeholder:ctx.current.placeHolder,});}}},onDrop({ctx}){if(!this._isAllowedNodeMove(ctx)){return;}
const previous=ctx.current.placeHolder.previousElementSibling;const next=ctx.current.placeHolder.nextElementSibling;if(previous!==ctx.current.element&&next!==ctx.current.element){return{element:ctx.current.element,group:ctx.currentGroup,previous,next,newGroup:ctx.groupSelector&&ctx.current.placeHolder.closest(ctx.groupSelector),parent:ctx.current.placeHolder.parentElement.closest(ctx.elementSelector),placeholder:ctx.current.placeHolder,};}},onDragEnd({ctx}){return{element:ctx.current.element,group:ctx.currentGroup,};},});return __exports;});;

/* /web/static/src/core/utils/numbers.js */
odoo.define('@web/core/utils/numbers',['@web/core/l10n/localization','@web/core/l10n/translation','@web/core/utils/strings'],function(require){'use strict';let __exports={};const{localization:l10n}=require("@web/core/l10n/localization");const{_t}=require("@web/core/l10n/translation");const{intersperse}=require("@web/core/utils/strings");__exports.clamp=clamp;function clamp(num,min,max){return Math.max(Math.min(num,max),min);}
__exports.range=range;function range(start,stop,step=1){const array=[];const nsteps=Math.floor((stop-start)/step);for(let i=0;i<nsteps;i++){array.push(start+step*i);}
return array;}
__exports.roundPrecision=roundPrecision;function roundPrecision(value,precision,method="HALF-UP"){if(!value){return 0;}else if(!precision||precision<0){precision=1;}
let roundingFactor=precision;let normalize=(val)=>val/roundingFactor;let denormalize=(val)=>val*roundingFactor;if(roundingFactor<1){roundingFactor=invertFloat(roundingFactor);[normalize,denormalize]=[denormalize,normalize];}
const normalizedValue=normalize(value);const sign=Math.sign(normalizedValue);const epsilonMagnitude=Math.log2(Math.abs(normalizedValue));const epsilon=Math.pow(2,epsilonMagnitude-50);let roundedValue;switch(method){case"DOWN":{roundedValue=Math.trunc(normalizedValue+sign*epsilon);break;}
case"HALF-DOWN":{roundedValue=Math.round(normalizedValue-sign*epsilon);break;}
case"HALF-UP":{roundedValue=Math.round(normalizedValue+sign*epsilon);break;}
case"HALF-EVEN":{const integral=Math.floor(normalizedValue);const remainder=Math.abs(normalizedValue-integral);const isHalf=Math.abs(0.5-remainder)<epsilon;roundedValue=isHalf?integral+(integral&1):Math.round(normalizedValue);break;}
case"UP":{roundedValue=Math.trunc(normalizedValue+sign*(1-epsilon));break;}
default:{throw new Error(`Unknown rounding method: ${method}`);}}
return denormalize(roundedValue);}
__exports.roundDecimals=roundDecimals;function roundDecimals(value,decimals){return roundPrecision(value,parseFloat("1e"+-decimals));}
__exports.floatIsZero=floatIsZero;function floatIsZero(value,decimals){return value===0||roundDecimals(value,decimals)===0;}
__exports.insertThousandsSep=insertThousandsSep;function insertThousandsSep(number,thousandsSep=",",grouping=[]){const negative=number[0]==="-";number=negative?number.slice(1):number;return(negative?"-":"")+intersperse(number,grouping,thousandsSep);}
__exports.humanNumber=humanNumber;function humanNumber(number,options={decimals:0,minDigits:1}){const decimals=options.decimals||0;const minDigits=options.minDigits||1;const d2=Math.pow(10,decimals);const numberMagnitude=+number.toExponential().split("e+")[1];number=Math.round(number*d2)/d2;if(numberMagnitude>=21){number=Math.round(number*Math.pow(10,decimals-numberMagnitude))/d2;return`${number}e+${numberMagnitude}`;}
const unitSymbols=_t("kMGTPE").toString();const sign=Math.sign(number);number=Math.abs(number);let symbol="";for(let i=unitSymbols.length;i>0;i--){const s=Math.pow(10,i*3);if(s<=number/Math.pow(10,minDigits-1)){number=Math.round((number*d2)/s)/d2;symbol=unitSymbols[i-1];break;}}
const{decimalPoint,grouping,thousandsSep}=l10n;const decimalsToKeep=number>=1000?0:decimals;number=sign*number;const[integerPart,decimalPart]=number.toFixed(decimalsToKeep).split(".");const int=insertThousandsSep(integerPart,thousandsSep,grouping);if(!decimalPart){return int+symbol;}
return int+decimalPoint+decimalPart+symbol;}
__exports.formatFloat=formatFloat;function formatFloat(value,options={}){let precision;if(options.digits&&options.digits[1]!==undefined){precision=options.digits[1];}else{precision=2;}
if(floatIsZero(value,precision)){value=0.0;}
if(options.humanReadable){return humanNumber(value,options);}
const grouping=options.grouping||l10n.grouping;const thousandsSep="thousandsSep"in options?options.thousandsSep:l10n.thousandsSep;const decimalPoint="decimalPoint"in options?options.decimalPoint:l10n.decimalPoint;const formatted=value.toFixed(precision).split(".");formatted[0]=insertThousandsSep(formatted[0],thousandsSep,grouping);if(options.trailingZeros===false&&formatted[1]){formatted[1]=formatted[1].replace(/0+$/,"");}
return formatted[1]?formatted.join(decimalPoint):formatted[0];}
const _INVERTDICT=Object.freeze({1e-1:1e+1,1e-2:1e+2,1e-3:1e+3,1e-4:1e+4,1e-5:1e+5,1e-6:1e+6,1e-7:1e+7,1e-8:1e+8,1e-9:1e+9,1e-10:1e+10,2e-1:5e+0,2e-2:5e+1,2e-3:5e+2,2e-4:5e+3,2e-5:5e+4,2e-6:5e+5,2e-7:5e+6,2e-8:5e+7,2e-9:5e+8,2e-10:5e+9,5e-1:2e+0,5e-2:2e+1,5e-3:2e+2,5e-4:2e+3,5e-5:2e+4,5e-6:2e+5,5e-7:2e+6,5e-8:2e+7,5e-9:2e+8,5e-10:2e+9,});__exports.invertFloat=invertFloat;function invertFloat(value){let res=_INVERTDICT[value];if(res===undefined){const[coeff,expt]=value.toExponential().split("e").map(Number.parseFloat);res=Number.parseFloat(`${coeff}e${-expt}`)/Math.pow(coeff,2);}
return res;}
return __exports;});;

/* /web/static/src/core/utils/objects.js */
odoo.define('@web/core/utils/objects',[],function(require){'use strict';let __exports={};__exports.shallowEqual=shallowEqual;function shallowEqual(obj1,obj2,comparisonFn=(a,b)=>a===b){if(!isObject(obj1)||!isObject(obj2)){return obj1===obj2;}
const obj1Keys=Reflect.ownKeys(obj1);return(obj1Keys.length===Reflect.ownKeys(obj2).length&&obj1Keys.every((key)=>comparisonFn(obj1[key],obj2[key])));}
const deepEqual=__exports.deepEqual=(obj1,obj2)=>shallowEqual(obj1,obj2,deepEqual);__exports.deepCopy=deepCopy;function deepCopy(object){return object&&JSON.parse(JSON.stringify(object));}
__exports.isObject=isObject;function isObject(object){return!!object&&(typeof object==="object"||typeof object==="function");}
__exports.omit=omit;function omit(object,...properties){const result={};const propertiesSet=new Set(properties);for(const key in object){if(!propertiesSet.has(key)){result[key]=object[key];}}
return result;}
__exports.pick=pick;function pick(object,...properties){return Object.fromEntries(properties.filter((prop)=>prop in object).map((prop)=>[prop,object[prop]]));}
__exports.deepMerge=deepMerge;function deepMerge(target,extension){if(!isObject(target)&&!isObject(extension)){return;}
target=target||{};const output=Object.assign({},target);if(isObject(extension)){for(const key of Reflect.ownKeys(extension)){if(key in target&&isObject(extension[key])&&!Array.isArray(extension[key])&&typeof extension[key]!=="function"){output[key]=deepMerge(target[key],extension[key]);}else{Object.assign(output,{[key]:extension[key]});}}}
return output;}
return __exports;});;

/* /web/static/src/core/utils/patch.js */
odoo.define('@web/core/utils/patch',[],function(require){'use strict';let __exports={};const patchDescriptions=new WeakMap();function getPatchDescription(objToPatch){if(!patchDescriptions.has(objToPatch)){patchDescriptions.set(objToPatch,{originalProperties:new Map(),skeleton:Object.create(Object.getPrototypeOf(objToPatch)),extensions:new Set(),});}
return patchDescriptions.get(objToPatch);}
function isClassPrototype(objToPatch){return(Object.hasOwn(objToPatch,"constructor")&&objToPatch.constructor?.prototype===objToPatch);}
function findAncestorPropertyDescriptor(objToPatch,key){let descriptor=null;let prototype=objToPatch;do{descriptor=Object.getOwnPropertyDescriptor(prototype,key);prototype=Object.getPrototypeOf(prototype);}while(!descriptor&&prototype);return descriptor;}
__exports.patch=patch;function patch(objToPatch,extension){if(typeof extension==="string"){throw new Error(`Patch "${extension}": Second argument is not the patch name anymore, it should be the object containing the patched properties`);}
const description=getPatchDescription(objToPatch);description.extensions.add(extension);const properties=Object.getOwnPropertyDescriptors(extension);for(const[key,newProperty]of Object.entries(properties)){const oldProperty=Object.getOwnPropertyDescriptor(objToPatch,key);if(oldProperty){Object.defineProperty(description.skeleton,key,oldProperty);}
if(!description.originalProperties.has(key)){description.originalProperties.set(key,oldProperty);}
if(isClassPrototype(objToPatch)){newProperty.enumerable=false;}
if((newProperty.get&&1)^(newProperty.set&&1)){const ancestorProperty=findAncestorPropertyDescriptor(objToPatch,key);newProperty.get=newProperty.get??ancestorProperty?.get;newProperty.set=newProperty.set??ancestorProperty?.set;}
Object.defineProperty(objToPatch,key,newProperty);}
description.skeleton=Object.setPrototypeOf(extension,description.skeleton);return()=>{patchDescriptions.delete(objToPatch);for(const[key,property]of description.originalProperties){if(property){Object.defineProperty(objToPatch,key,property);}else{delete objToPatch[key];}}
description.extensions.delete(extension);for(const extension of description.extensions){patch(objToPatch,extension);}};}
return __exports;});;

/* /web/static/src/core/utils/reactive.js */
odoo.define('@web/core/utils/reactive',['@odoo/owl'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const Reactive=__exports.Reactive=class Reactive{constructor(){return reactive(this);}}
__exports.effect=effect;function effect(cb,deps){const reactiveDeps=reactive(deps,()=>{cb(...reactiveDeps);});cb(...reactiveDeps);}
__exports.withComputedProperties=withComputedProperties;function withComputedProperties(obj,sources,descriptor){for(const[key,compute]of Object.entries(descriptor)){effect((obj,sources)=>{obj[key]=compute.call(obj,...sources);},[obj,sources]);}
return obj;}
return __exports;});;

/* /web/static/src/core/utils/render.js */
odoo.define('@web/core/utils/render',['@odoo/owl','@web/core/templates','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{App,blockDom,Component,markup}=require("@odoo/owl");const{getTemplate}=require("@web/core/templates");const{_t}=require("@web/core/l10n/translation");__exports.renderToElement=renderToElement;function renderToElement(template,context={}){const el=render(template,context).firstElementChild;if(el?.nextElementSibling){throw new Error(`The rendered template '${template}' contains multiple root `+`nodes that will be ignored using renderToElement, you should `+`consider using renderToFragment or refactoring the template.`);}
el?.remove();return el;}
__exports.renderToFragment=renderToFragment;function renderToFragment(template,context={}){const frag=document.createDocumentFragment();for(const el of[...render(template,context).children]){frag.appendChild(el);}
return frag;}
__exports.renderToString=renderToString;function renderToString(template,context={}){return render(template,context).innerHTML;}
let app;Object.defineProperty(renderToString,"app",{get:()=>{if(!app){app=new App(Component,{name:"renderToString",getTemplate,translatableAttributes:["data-tooltip"],translateFn:_t,});}
return app;},});function render(template,context={}){const app=renderToString.app;const templateFn=app.getTemplate(template);const bdom=templateFn(context,{});const div=document.createElement("div");blockDom.mount(bdom,div);return div;}
__exports.renderToMarkup=renderToMarkup;function renderToMarkup(template,context={}){return markup(renderToString(template,context));}
return __exports;});;

/* /web/static/src/core/utils/scrolling.js */
odoo.define('@web/core/utils/scrolling',[],function(require){'use strict';let __exports={};__exports.isScrollableX=isScrollableX;function isScrollableX(el){if(el.scrollWidth>el.clientWidth&&el.clientWidth>0){return couldBeScrollableX(el);}
return false;}
__exports.couldBeScrollableX=couldBeScrollableX;function couldBeScrollableX(el){if(el){const overflow=getComputedStyle(el).getPropertyValue("overflow-x");if(/\bauto\b|\bscroll\b/.test(overflow)){return true;}}
return false;}
__exports.closestScrollableX=closestScrollableX;function closestScrollableX(el){if(!el){return null;}
if(isScrollableX(el)){return el;}
return closestScrollableX(el.parentElement);}
__exports.isScrollableY=isScrollableY;function isScrollableY(el){if(el&&el.scrollHeight>el.clientHeight&&el.clientHeight>0){return couldBeScrollableY(el);}
return false;}
__exports.couldBeScrollableY=couldBeScrollableY;function couldBeScrollableY(el){if(el){const overflow=getComputedStyle(el).getPropertyValue("overflow-y");if(/\bauto\b|\bscroll\b/.test(overflow)){return true;}}
return false;}
__exports.closestScrollableY=closestScrollableY;function closestScrollableY(el){if(!el){return null;}
if(isScrollableY(el)){return el;}
return closestScrollableY(el.parentElement);}
__exports.scrollTo=scrollTo;function scrollTo(element,options={}){const{behavior="auto",isAnchor=false,offset=0}=options;const scrollable=closestScrollableY(options.scrollable||element.parentElement);if(!scrollable){return;}
const scrollBottom=scrollable.getBoundingClientRect().bottom;const scrollTop=scrollable.getBoundingClientRect().top;const elementBottom=element.getBoundingClientRect().bottom;const elementTop=element.getBoundingClientRect().top;const scrollPromises=[];if(elementBottom>scrollBottom&&!isAnchor){scrollPromises.push(new Promise((resolve)=>{scrollable.addEventListener("scrollend",()=>resolve(),{once:true});}));scrollable.scrollTo({top:scrollable.scrollTop+
elementTop-
scrollBottom+
Math.ceil(element.getBoundingClientRect().height)+
offset,behavior,});}else if(elementTop<scrollTop||isAnchor){scrollPromises.push(new Promise((resolve)=>{scrollable.addEventListener("scrollend",()=>resolve(),{once:true});}));scrollable.scrollTo({top:scrollable.scrollTop-scrollTop+elementTop+offset,behavior,});if(options.isAnchor){const parentScrollable=closestScrollableY(scrollable.parentElement);if(parentScrollable){scrollPromises.push(scrollTo(scrollable,{behavior,isAnchor:true,scrollable:parentScrollable,}));}}}
return Promise.all(scrollPromises);}
__exports.compensateScrollbar=compensateScrollbar;function compensateScrollbar(el,add=true,isScrollElement=true,cssProperty="padding-right"){if(!el){return;}
const scrollableEl=isScrollElement?el:closestScrollableY(el.parentElement);if(!scrollableEl){return;}
const isRTL=scrollableEl.classList.contains(".o_rtl");if(isRTL){cssProperty=cssProperty.replace("right","left");}
el.style.removeProperty(cssProperty);if(!add){return;}
const style=window.getComputedStyle(el);const borderLeftWidth=Math.ceil(parseFloat(style.borderLeftWidth.replace("px","")));const borderRightWidth=Math.ceil(parseFloat(style.borderRightWidth.replace("px","")));const bordersWidth=borderLeftWidth+borderRightWidth;const newValue=parseInt(style[cssProperty])+
scrollableEl.offsetWidth-
scrollableEl.clientWidth-
bordersWidth;el.style.setProperty(cssProperty,`${newValue}px`,"important");}
__exports.getScrollingElement=getScrollingElement;function getScrollingElement(document=window.document){const baseScrollingElement=document.scrollingElement;if(isScrollableY(baseScrollingElement)){return baseScrollingElement;}
const bodyHeight=window.getComputedStyle(document.body).height;for(const el of document.body.children){if(bodyHeight-el.scrollHeight>1.5){continue;}
if(isScrollableY(el)){return el;}}
return baseScrollingElement;}
return __exports;});;

/* /web/static/src/core/utils/search.js */
odoo.define('@web/core/utils/search',['@web/core/utils/strings'],function(require){'use strict';let __exports={};const{unaccent}=require("@web/core/utils/strings");function match(pattern,strs){if(!Array.isArray(strs)){strs=[strs];}
let globalScore=0;for(const str of strs){globalScore=Math.max(globalScore,_match(pattern,str));}
return globalScore;}
function _match(pattern,str){let totalScore=0;let currentScore=0;let patternIndex=0;pattern=unaccent(pattern,false);str=unaccent(str,false);const len=str.length;for(let i=0;i<len;i++){if(str[i]===pattern[patternIndex]){patternIndex++;currentScore+=100+currentScore-i/200;}else{currentScore=0;}
totalScore=totalScore+currentScore;}
return patternIndex===pattern.length?totalScore:0;}
__exports.fuzzyLookup=fuzzyLookup;function fuzzyLookup(pattern,list,fn){const results=[];list.forEach((data)=>{const score=match(pattern,fn(data));if(score>0){results.push({score,elem:data});}});results.sort((a,b)=>b.score-a.score);return results.map((r)=>r.elem);}
__exports.fuzzyTest=fuzzyTest;function fuzzyTest(pattern,string){return _match(pattern,string)!==0;}
return __exports;});;

/* /web/static/src/core/utils/sortable.js */
odoo.define('@web/core/utils/sortable',['@web/core/utils/draggable_hook_builder','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{DRAGGED_CLASS,makeDraggableHook:nativeMakeDraggableHook,}=require("@web/core/utils/draggable_hook_builder");const{pick}=require("@web/core/utils/objects");const hookParams={name:"useSortable",acceptedParams:{groups:[String,Function],connectGroups:[Boolean,Function],clone:[Boolean],placeholderClasses:[Object],applyChangeOnDrop:[Boolean],followingElementClasses:[Object],},defaultParams:{connectGroups:false,edgeScrolling:{speed:20,threshold:60},groupSelector:null,clone:true,placeholderClasses:[],applyChangeOnDrop:false,followingElementClasses:[],},onComputeParams({ctx,params}){ctx.groupSelector=params.groups||null;if(ctx.groupSelector){ctx.fullSelector=[ctx.groupSelector,ctx.fullSelector].join(" ");}
ctx.connectGroups=params.connectGroups;ctx.placeholderClone=params.clone;ctx.placeholderClasses=params.placeholderClasses;ctx.applyChangeOnDrop=params.applyChangeOnDrop;ctx.followingElementClasses=params.followingElementClasses;},onDragStart({ctx,addListener,addStyle,callHandler}){const onElementPointerEnter=(ev)=>{const element=ev.currentTarget;if(connectGroups||!groupSelector||current.group===element.closest(groupSelector)){const pos=current.placeHolder.compareDocumentPosition(element);if(pos===Node.DOCUMENT_POSITION_PRECEDING){element.before(current.placeHolder);}else if(pos===Node.DOCUMENT_POSITION_FOLLOWING){element.after(current.placeHolder);}}
callHandler("onElementEnter",{element});};const onElementPointerLeave=(ev)=>{const element=ev.currentTarget;callHandler("onElementLeave",{element});};const onElementComplexPointerEnter=(ev)=>{if(ctx.haveAlreadyChanged){return;}
const element=ev.currentTarget;const siblingArray=[...element.parentElement.children].filter((el)=>el===current.placeHolder||(el.matches(elementSelector)&&!el.classList.contains(DRAGGED_CLASS)));const elementIndex=siblingArray.indexOf(element);const placeholderIndex=siblingArray.indexOf(current.placeHolder);const isDirectSibling=Math.abs(elementIndex-placeholderIndex)===1;if(connectGroups||!groupSelector||current.group===element.closest(groupSelector)){const pos=current.placeHolder.compareDocumentPosition(element);if(isDirectSibling){if(pos===Node.DOCUMENT_POSITION_PRECEDING){element.before(current.placeHolder);ctx.haveAlreadyChanged=true;}else if(pos===Node.DOCUMENT_POSITION_FOLLOWING){element.after(current.placeHolder);ctx.haveAlreadyChanged=true;}}else{if(pos===Node.DOCUMENT_POSITION_FOLLOWING){element.before(current.placeHolder);ctx.haveAlreadyChanged=true;}else if(pos===Node.DOCUMENT_POSITION_PRECEDING){element.after(current.placeHolder);ctx.haveAlreadyChanged=true;}}}
callHandler("onElementEnter",{element});};const onElementComplexPointerLeave=(ev)=>{if(ctx.haveAlreadyChanged){return;}
const element=ev.currentTarget;const elementRect=element.getBoundingClientRect();const relatedElement=ev.relatedTarget;const relatedElementRect=element.getBoundingClientRect();const siblingArray=[...element.parentElement.children].filter((el)=>el===current.placeHolder||(el.matches(elementSelector)&&!el.classList.contains(DRAGGED_CLASS)));const pointerOnSiblings=siblingArray.indexOf(relatedElement)>-1;const elementIndex=siblingArray.indexOf(element);const isFirst=elementIndex===0;const isAbove=relatedElementRect.top<=elementRect.top;const isLast=elementIndex===siblingArray.length-1;const isBelow=relatedElementRect.bottom>=elementRect.bottom;const pos=current.placeHolder.compareDocumentPosition(element);if(!pointerOnSiblings){if(isFirst&&isAbove&&pos===Node.DOCUMENT_POSITION_PRECEDING){element.before(current.placeHolder);ctx.haveAlreadyChanged=true;}else if(isLast&&isBelow&&pos===Node.DOCUMENT_POSITION_FOLLOWING){element.after(current.placeHolder);ctx.haveAlreadyChanged=true;}}
callHandler("onElementLeave",{element});};const onGroupPointerEnter=(ev)=>{const group=ev.currentTarget;group.appendChild(current.placeHolder);callHandler("onGroupEnter",{group});};const onGroupPointerLeave=(ev)=>{const group=ev.currentTarget;callHandler("onGroupLeave",{group});};const{connectGroups,current,elementSelector,groupSelector,ref}=ctx;if(ctx.placeholderClone){const{width,height}=current.elementRect;addStyle(current.placeHolder,{visibility:"hidden",display:"block",width:`${width}px`,height:`${height}px`,});}
if(connectGroups&&groupSelector){for(const siblingGroup of ref.el.querySelectorAll(groupSelector)){addListener(siblingGroup,"pointerenter",onGroupPointerEnter);addListener(siblingGroup,"pointerleave",onGroupPointerLeave);}}
for(const siblingEl of ref.el.querySelectorAll(elementSelector)){if(siblingEl!==current.element&&siblingEl!==current.placeHolder){if(ctx.placeholderClone){addListener(siblingEl,"pointerenter",onElementPointerEnter);addListener(siblingEl,"pointerleave",onElementPointerLeave);}else{addListener(siblingEl,"pointerenter",onElementComplexPointerEnter);addListener(siblingEl,"pointerleave",onElementComplexPointerLeave);}}}
current.element.after(current.placeHolder);return pick(current,"element","group");},onDrag({ctx}){ctx.haveAlreadyChanged=false;},onDragEnd({ctx}){return pick(ctx.current,"element","group");},onDrop({ctx}){const{current,groupSelector}=ctx;const previous=current.placeHolder.previousElementSibling;const next=current.placeHolder.nextElementSibling;if(previous!==current.element&&next!==current.element){const element=current.element;if(ctx.applyChangeOnDrop){if(previous){previous.after(element);}else if(next){next.before(element);}}
return{element,group:current.group,previous,next,parent:groupSelector&&current.placeHolder.closest(groupSelector),};}},onWillStartDrag({ctx,addCleanup}){const{connectGroups,current,groupSelector}=ctx;if(groupSelector){current.group=current.element.closest(groupSelector);if(!connectGroups){current.container=current.group;}}
if(ctx.placeholderClone){current.placeHolder=current.element.cloneNode(false);}else{current.placeHolder=document.createElement("div");}
current.placeHolder.classList.add(...ctx.placeholderClasses);current.element.classList.add(...ctx.followingElementClasses);addCleanup(()=>current.element.classList.remove(...ctx.followingElementClasses));addCleanup(()=>current.placeHolder.remove());return pick(current,"element","group");},};const useSortable=__exports.useSortable=(sortableParams)=>{const{setupHooks}=sortableParams;delete sortableParams.setupHooks;return nativeMakeDraggableHook({...hookParams,setupHooks})(sortableParams);};return __exports;});;

/* /web/static/src/core/utils/sortable_owl.js */
odoo.define('@web/core/utils/sortable_owl',['@odoo/owl','@web/core/utils/timing','@web/core/utils/sortable'],function(require){'use strict';let __exports={};const{onWillUnmount,reactive,useEffect,useExternalListener}=require("@odoo/owl");const{useThrottleForAnimation}=require("@web/core/utils/timing");const{useSortable:nativeUseSortable}=require("@web/core/utils/sortable");__exports.useSortable=useSortable;function useSortable(params){return nativeUseSortable({...params,setupHooks:{addListener:useExternalListener,setup:useEffect,teardown:onWillUnmount,throttle:useThrottleForAnimation,wrapState:reactive,},});}
return __exports;});;

/* /web/static/src/core/utils/sortable_service.js */
odoo.define('@web/core/utils/sortable_service',['@web/core/registry','@web/core/utils/sortable','@web/core/utils/timing','@odoo/owl'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{useSortable}=require("@web/core/utils/sortable");const{throttleForAnimation}=require("@web/core/utils/timing");const{reactive}=require("@odoo/owl");const DEFAULT_SORTABLE_ID=Symbol.for("defaultSortable");const sortableService=__exports.sortableService={start(){const boundElements=new Map();return{create:(hookParams)=>{const element=hookParams.ref.el;const sortableId=hookParams.sortableId??DEFAULT_SORTABLE_ID;if(boundElements.has(element)){const boundElement=boundElements.get(element);if(sortableId in boundElement){return{enable(){return{cleanup:boundElement[sortableId],};},};}}
const setupFunctions=new Map();const cleanupFunctions=[];const cleanup=()=>{const boundElement=boundElements.get(element);if(sortableId in boundElement){delete boundElement[sortableId];if(boundElement.length===0){boundElements.delete(element);}}
cleanupFunctions.forEach((fn)=>fn());};const setupHooks={wrapState:reactive,throttle:throttleForAnimation,addListener:(el,type,listener)=>{el.addEventListener(type,listener);cleanupFunctions.push(()=>el.removeEventListener(type,listener));},setup:(setupFn,dependenciesFn)=>setupFunctions.set(setupFn,dependenciesFn),teardown:(fn)=>cleanupFunctions.push(fn),};useSortable({setupHooks,...hookParams});const boundElement=boundElements.get(element);if(boundElement){boundElement[sortableId]=cleanup;}else{boundElements.set(element,{[sortableId]:cleanup});}
return{enable(){setupFunctions.forEach((dependenciesFn,setupFn)=>setupFn(...dependenciesFn()));return{cleanup,};},};},};},};registry.category("services").add("sortable",sortableService);return __exports;});;

/* /web/static/src/core/utils/strings.js */
odoo.define('@web/core/utils/strings',[],function(require){'use strict';let __exports={};const nbsp=__exports.nbsp="\u00a0";__exports.escape=escape;function escape(str){if(str===undefined){return"";}
if(typeof str==="number"){return String(str);}
[["&","&amp;"],["<","&lt;"],[">","&gt;"],["'","&#x27;"],['"',"&quot;"],["`","&#x60;"],].forEach((pairs)=>{str=String(str).replaceAll(pairs[0],pairs[1]);});return str;}
__exports.escapeRegExp=escapeRegExp;function escapeRegExp(str){return str.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");}
__exports.intersperse=intersperse;function intersperse(str,indices,separator=""){separator=separator||"";const result=[];let last=str.length;for(let i=0;i<indices.length;++i){let section=indices[i];if(section===-1||last<=0){break;}else if(section===0&&i===0){break;}else if(section===0){section=indices[--i];}
result.push(str.substring(last-section,last));last-=section;}
const s=str.substring(0,last);if(s){result.push(s);}
return result.reverse().join(separator);}
__exports.sprintf=sprintf;function sprintf(s,...values){if(values.length===1&&Object.prototype.toString.call(values[0])==="[object Object]"){const valuesDict=values[0];s=s.replace(/%\(([^)]+)\)s/g,(match,value)=>valuesDict[value]);}else if(values.length>0){s=s.replace(/%s/g,()=>values.shift());}
return s;}
__exports.capitalize=capitalize;function capitalize(s){return s?s[0].toUpperCase()+s.slice(1):"";}
const diacriticsMap={'\u0041':'A','\u24B6':'A','\uFF21':'A','\u00C0':'A','\u00C1':'A','\u00C2':'A','\u1EA6':'A','\u1EA4':'A','\u1EAA':'A','\u1EA8':'A','\u00C3':'A','\u0100':'A','\u0102':'A','\u1EB0':'A','\u1EAE':'A','\u1EB4':'A','\u1EB2':'A','\u0226':'A','\u01E0':'A','\u00C4':'A','\u01DE':'A','\u1EA2':'A','\u00C5':'A','\u01FA':'A','\u01CD':'A','\u0200':'A','\u0202':'A','\u1EA0':'A','\u1EAC':'A','\u1EB6':'A','\u1E00':'A','\u0104':'A','\u023A':'A','\u2C6F':'A','\uA732':'AA','\u00C6':'AE','\u01FC':'AE','\u01E2':'AE','\uA734':'AO','\uA736':'AU','\uA738':'AV','\uA73A':'AV','\uA73C':'AY','\u0042':'B','\u24B7':'B','\uFF22':'B','\u1E02':'B','\u1E04':'B','\u1E06':'B','\u0243':'B','\u0182':'B','\u0181':'B','\u0043':'C','\u24B8':'C','\uFF23':'C','\u0106':'C','\u0108':'C','\u010A':'C','\u010C':'C','\u00C7':'C','\u1E08':'C','\u0187':'C','\u023B':'C','\uA73E':'C','\u0044':'D','\u24B9':'D','\uFF24':'D','\u1E0A':'D','\u010E':'D','\u1E0C':'D','\u1E10':'D','\u1E12':'D','\u1E0E':'D','\u0110':'D','\u018B':'D','\u018A':'D','\u0189':'D','\uA779':'D','\u01F1':'DZ','\u01C4':'DZ','\u01F2':'Dz','\u01C5':'Dz','\u0045':'E','\u24BA':'E','\uFF25':'E','\u00C8':'E','\u00C9':'E','\u00CA':'E','\u1EC0':'E','\u1EBE':'E','\u1EC4':'E','\u1EC2':'E','\u1EBC':'E','\u0112':'E','\u1E14':'E','\u1E16':'E','\u0114':'E','\u0116':'E','\u00CB':'E','\u1EBA':'E','\u011A':'E','\u0204':'E','\u0206':'E','\u1EB8':'E','\u1EC6':'E','\u0228':'E','\u1E1C':'E','\u0118':'E','\u1E18':'E','\u1E1A':'E','\u0190':'E','\u018E':'E','\u0046':'F','\u24BB':'F','\uFF26':'F','\u1E1E':'F','\u0191':'F','\uA77B':'F','\u0047':'G','\u24BC':'G','\uFF27':'G','\u01F4':'G','\u011C':'G','\u1E20':'G','\u011E':'G','\u0120':'G','\u01E6':'G','\u0122':'G','\u01E4':'G','\u0193':'G','\uA7A0':'G','\uA77D':'G','\uA77E':'G','\u0048':'H','\u24BD':'H','\uFF28':'H','\u0124':'H','\u1E22':'H','\u1E26':'H','\u021E':'H','\u1E24':'H','\u1E28':'H','\u1E2A':'H','\u0126':'H','\u2C67':'H','\u2C75':'H','\uA78D':'H','\u0049':'I','\u24BE':'I','\uFF29':'I','\u00CC':'I','\u00CD':'I','\u00CE':'I','\u0128':'I','\u012A':'I','\u012C':'I','\u0130':'I','\u00CF':'I','\u1E2E':'I','\u1EC8':'I','\u01CF':'I','\u0208':'I','\u020A':'I','\u1ECA':'I','\u012E':'I','\u1E2C':'I','\u0197':'I','\u004A':'J','\u24BF':'J','\uFF2A':'J','\u0134':'J','\u0248':'J','\u004B':'K','\u24C0':'K','\uFF2B':'K','\u1E30':'K','\u01E8':'K','\u1E32':'K','\u0136':'K','\u1E34':'K','\u0198':'K','\u2C69':'K','\uA740':'K','\uA742':'K','\uA744':'K','\uA7A2':'K','\u004C':'L','\u24C1':'L','\uFF2C':'L','\u013F':'L','\u0139':'L','\u013D':'L','\u1E36':'L','\u1E38':'L','\u013B':'L','\u1E3C':'L','\u1E3A':'L','\u0141':'L','\u023D':'L','\u2C62':'L','\u2C60':'L','\uA748':'L','\uA746':'L','\uA780':'L','\u01C7':'LJ','\u01C8':'Lj','\u004D':'M','\u24C2':'M','\uFF2D':'M','\u1E3E':'M','\u1E40':'M','\u1E42':'M','\u2C6E':'M','\u019C':'M','\u004E':'N','\u24C3':'N','\uFF2E':'N','\u01F8':'N','\u0143':'N','\u00D1':'N','\u1E44':'N','\u0147':'N','\u1E46':'N','\u0145':'N','\u1E4A':'N','\u1E48':'N','\u0220':'N','\u019D':'N','\uA790':'N','\uA7A4':'N','\u01CA':'NJ','\u01CB':'Nj','\u004F':'O','\u24C4':'O','\uFF2F':'O','\u00D2':'O','\u00D3':'O','\u00D4':'O','\u1ED2':'O','\u1ED0':'O','\u1ED6':'O','\u1ED4':'O','\u00D5':'O','\u1E4C':'O','\u022C':'O','\u1E4E':'O','\u014C':'O','\u1E50':'O','\u1E52':'O','\u014E':'O','\u022E':'O','\u0230':'O','\u00D6':'O','\u022A':'O','\u1ECE':'O','\u0150':'O','\u01D1':'O','\u020C':'O','\u020E':'O','\u01A0':'O','\u1EDC':'O','\u1EDA':'O','\u1EE0':'O','\u1EDE':'O','\u1EE2':'O','\u1ECC':'O','\u1ED8':'O','\u01EA':'O','\u01EC':'O','\u00D8':'O','\u01FE':'O','\u0186':'O','\u019F':'O','\uA74A':'O','\uA74C':'O','\u01A2':'OI','\uA74E':'OO','\u0222':'OU','\u0050':'P','\u24C5':'P','\uFF30':'P','\u1E54':'P','\u1E56':'P','\u01A4':'P','\u2C63':'P','\uA750':'P','\uA752':'P','\uA754':'P','\u0051':'Q','\u24C6':'Q','\uFF31':'Q','\uA756':'Q','\uA758':'Q','\u024A':'Q','\u0052':'R','\u24C7':'R','\uFF32':'R','\u0154':'R','\u1E58':'R','\u0158':'R','\u0210':'R','\u0212':'R','\u1E5A':'R','\u1E5C':'R','\u0156':'R','\u1E5E':'R','\u024C':'R','\u2C64':'R','\uA75A':'R','\uA7A6':'R','\uA782':'R','\u0053':'S','\u24C8':'S','\uFF33':'S','\u1E9E':'S','\u015A':'S','\u1E64':'S','\u015C':'S','\u1E60':'S','\u0160':'S','\u1E66':'S','\u1E62':'S','\u1E68':'S','\u0218':'S','\u015E':'S','\u2C7E':'S','\uA7A8':'S','\uA784':'S','\u0054':'T','\u24C9':'T','\uFF34':'T','\u1E6A':'T','\u0164':'T','\u1E6C':'T','\u021A':'T','\u0162':'T','\u1E70':'T','\u1E6E':'T','\u0166':'T','\u01AC':'T','\u01AE':'T','\u023E':'T','\uA786':'T','\uA728':'TZ','\u0055':'U','\u24CA':'U','\uFF35':'U','\u00D9':'U','\u00DA':'U','\u00DB':'U','\u0168':'U','\u1E78':'U','\u016A':'U','\u1E7A':'U','\u016C':'U','\u00DC':'U','\u01DB':'U','\u01D7':'U','\u01D5':'U','\u01D9':'U','\u1EE6':'U','\u016E':'U','\u0170':'U','\u01D3':'U','\u0214':'U','\u0216':'U','\u01AF':'U','\u1EEA':'U','\u1EE8':'U','\u1EEE':'U','\u1EEC':'U','\u1EF0':'U','\u1EE4':'U','\u1E72':'U','\u0172':'U','\u1E76':'U','\u1E74':'U','\u0244':'U','\u0056':'V','\u24CB':'V','\uFF36':'V','\u1E7C':'V','\u1E7E':'V','\u01B2':'V','\uA75E':'V','\u0245':'V','\uA760':'VY','\u0057':'W','\u24CC':'W','\uFF37':'W','\u1E80':'W','\u1E82':'W','\u0174':'W','\u1E86':'W','\u1E84':'W','\u1E88':'W','\u2C72':'W','\u0058':'X','\u24CD':'X','\uFF38':'X','\u1E8A':'X','\u1E8C':'X','\u0059':'Y','\u24CE':'Y','\uFF39':'Y','\u1EF2':'Y','\u00DD':'Y','\u0176':'Y','\u1EF8':'Y','\u0232':'Y','\u1E8E':'Y','\u0178':'Y','\u1EF6':'Y','\u1EF4':'Y','\u01B3':'Y','\u024E':'Y','\u1EFE':'Y','\u005A':'Z','\u24CF':'Z','\uFF3A':'Z','\u0179':'Z','\u1E90':'Z','\u017B':'Z','\u017D':'Z','\u1E92':'Z','\u1E94':'Z','\u01B5':'Z','\u0224':'Z','\u2C7F':'Z','\u2C6B':'Z','\uA762':'Z','\u0061':'a','\u24D0':'a','\uFF41':'a','\u1E9A':'a','\u00E0':'a','\u00E1':'a','\u00E2':'a','\u1EA7':'a','\u1EA5':'a','\u1EAB':'a','\u1EA9':'a','\u00E3':'a','\u0101':'a','\u0103':'a','\u1EB1':'a','\u1EAF':'a','\u1EB5':'a','\u1EB3':'a','\u0227':'a','\u01E1':'a','\u00E4':'a','\u01DF':'a','\u1EA3':'a','\u00E5':'a','\u01FB':'a','\u01CE':'a','\u0201':'a','\u0203':'a','\u1EA1':'a','\u1EAD':'a','\u1EB7':'a','\u1E01':'a','\u0105':'a','\u2C65':'a','\u0250':'a','\uA733':'aa','\u00E6':'ae','\u01FD':'ae','\u01E3':'ae','\uA735':'ao','\uA737':'au','\uA739':'av','\uA73B':'av','\uA73D':'ay','\u0062':'b','\u24D1':'b','\uFF42':'b','\u1E03':'b','\u1E05':'b','\u1E07':'b','\u0180':'b','\u0183':'b','\u0253':'b','\u0063':'c','\u24D2':'c','\uFF43':'c','\u0107':'c','\u0109':'c','\u010B':'c','\u010D':'c','\u00E7':'c','\u1E09':'c','\u0188':'c','\u023C':'c','\uA73F':'c','\u2184':'c','\u0064':'d','\u24D3':'d','\uFF44':'d','\u1E0B':'d','\u010F':'d','\u1E0D':'d','\u1E11':'d','\u1E13':'d','\u1E0F':'d','\u0111':'d','\u018C':'d','\u0256':'d','\u0257':'d','\uA77A':'d','\u01F3':'dz','\u01C6':'dz','\u0065':'e','\u24D4':'e','\uFF45':'e','\u00E8':'e','\u00E9':'e','\u00EA':'e','\u1EC1':'e','\u1EBF':'e','\u1EC5':'e','\u1EC3':'e','\u1EBD':'e','\u0113':'e','\u1E15':'e','\u1E17':'e','\u0115':'e','\u0117':'e','\u00EB':'e','\u1EBB':'e','\u011B':'e','\u0205':'e','\u0207':'e','\u1EB9':'e','\u1EC7':'e','\u0229':'e','\u1E1D':'e','\u0119':'e','\u1E19':'e','\u1E1B':'e','\u0247':'e','\u025B':'e','\u01DD':'e','\u0066':'f','\u24D5':'f','\uFF46':'f','\u1E1F':'f','\u0192':'f','\uA77C':'f','\u0067':'g','\u24D6':'g','\uFF47':'g','\u01F5':'g','\u011D':'g','\u1E21':'g','\u011F':'g','\u0121':'g','\u01E7':'g','\u0123':'g','\u01E5':'g','\u0260':'g','\uA7A1':'g','\u1D79':'g','\uA77F':'g','\u0068':'h','\u24D7':'h','\uFF48':'h','\u0125':'h','\u1E23':'h','\u1E27':'h','\u021F':'h','\u1E25':'h','\u1E29':'h','\u1E2B':'h','\u1E96':'h','\u0127':'h','\u2C68':'h','\u2C76':'h','\u0265':'h','\u0195':'hv','\u0069':'i','\u24D8':'i','\uFF49':'i','\u00EC':'i','\u00ED':'i','\u00EE':'i','\u0129':'i','\u012B':'i','\u012D':'i','\u00EF':'i','\u1E2F':'i','\u1EC9':'i','\u01D0':'i','\u0209':'i','\u020B':'i','\u1ECB':'i','\u012F':'i','\u1E2D':'i','\u0268':'i','\u0131':'i','\u006A':'j','\u24D9':'j','\uFF4A':'j','\u0135':'j','\u01F0':'j','\u0249':'j','\u006B':'k','\u24DA':'k','\uFF4B':'k','\u1E31':'k','\u01E9':'k','\u1E33':'k','\u0137':'k','\u1E35':'k','\u0199':'k','\u2C6A':'k','\uA741':'k','\uA743':'k','\uA745':'k','\uA7A3':'k','\u006C':'l','\u24DB':'l','\uFF4C':'l','\u0140':'l','\u013A':'l','\u013E':'l','\u1E37':'l','\u1E39':'l','\u013C':'l','\u1E3D':'l','\u1E3B':'l','\u017F':'l','\u0142':'l','\u019A':'l','\u026B':'l','\u2C61':'l','\uA749':'l','\uA781':'l','\uA747':'l','\u01C9':'lj','\u006D':'m','\u24DC':'m','\uFF4D':'m','\u1E3F':'m','\u1E41':'m','\u1E43':'m','\u0271':'m','\u026F':'m','\u006E':'n','\u24DD':'n','\uFF4E':'n','\u01F9':'n','\u0144':'n','\u00F1':'n','\u1E45':'n','\u0148':'n','\u1E47':'n','\u0146':'n','\u1E4B':'n','\u1E49':'n','\u019E':'n','\u0272':'n','\u0149':'n','\uA791':'n','\uA7A5':'n','\u01CC':'nj','\u006F':'o','\u24DE':'o','\uFF4F':'o','\u00F2':'o','\u00F3':'o','\u00F4':'o','\u1ED3':'o','\u1ED1':'o','\u1ED7':'o','\u1ED5':'o','\u00F5':'o','\u1E4D':'o','\u022D':'o','\u1E4F':'o','\u014D':'o','\u1E51':'o','\u1E53':'o','\u014F':'o','\u022F':'o','\u0231':'o','\u00F6':'o','\u022B':'o','\u1ECF':'o','\u0151':'o','\u01D2':'o','\u020D':'o','\u020F':'o','\u01A1':'o','\u1EDD':'o','\u1EDB':'o','\u1EE1':'o','\u1EDF':'o','\u1EE3':'o','\u1ECD':'o','\u1ED9':'o','\u01EB':'o','\u01ED':'o','\u00F8':'o','\u01FF':'o','\u0254':'o','\uA74B':'o','\uA74D':'o','\u0275':'o','\u01A3':'oi','\u0223':'ou','\uA74F':'oo','\u0070':'p','\u24DF':'p','\uFF50':'p','\u1E55':'p','\u1E57':'p','\u01A5':'p','\u1D7D':'p','\uA751':'p','\uA753':'p','\uA755':'p','\u0071':'q','\u24E0':'q','\uFF51':'q','\u024B':'q','\uA757':'q','\uA759':'q','\u0072':'r','\u24E1':'r','\uFF52':'r','\u0155':'r','\u1E59':'r','\u0159':'r','\u0211':'r','\u0213':'r','\u1E5B':'r','\u1E5D':'r','\u0157':'r','\u1E5F':'r','\u024D':'r','\u027D':'r','\uA75B':'r','\uA7A7':'r','\uA783':'r','\u0073':'s','\u24E2':'s','\uFF53':'s','\u00DF':'s','\u015B':'s','\u1E65':'s','\u015D':'s','\u1E61':'s','\u0161':'s','\u1E67':'s','\u1E63':'s','\u1E69':'s','\u0219':'s','\u015F':'s','\u023F':'s','\uA7A9':'s','\uA785':'s','\u1E9B':'s','\u0074':'t','\u24E3':'t','\uFF54':'t','\u1E6B':'t','\u1E97':'t','\u0165':'t','\u1E6D':'t','\u021B':'t','\u0163':'t','\u1E71':'t','\u1E6F':'t','\u0167':'t','\u01AD':'t','\u0288':'t','\u2C66':'t','\uA787':'t','\uA729':'tz','\u0075':'u','\u24E4':'u','\uFF55':'u','\u00F9':'u','\u00FA':'u','\u00FB':'u','\u0169':'u','\u1E79':'u','\u016B':'u','\u1E7B':'u','\u016D':'u','\u00FC':'u','\u01DC':'u','\u01D8':'u','\u01D6':'u','\u01DA':'u','\u1EE7':'u','\u016F':'u','\u0171':'u','\u01D4':'u','\u0215':'u','\u0217':'u','\u01B0':'u','\u1EEB':'u','\u1EE9':'u','\u1EEF':'u','\u1EED':'u','\u1EF1':'u','\u1EE5':'u','\u1E73':'u','\u0173':'u','\u1E77':'u','\u1E75':'u','\u0289':'u','\u0076':'v','\u24E5':'v','\uFF56':'v','\u1E7D':'v','\u1E7F':'v','\u028B':'v','\uA75F':'v','\u028C':'v','\uA761':'vy','\u0077':'w','\u24E6':'w','\uFF57':'w','\u1E81':'w','\u1E83':'w','\u0175':'w','\u1E87':'w','\u1E85':'w','\u1E98':'w','\u1E89':'w','\u2C73':'w','\u0078':'x','\u24E7':'x','\uFF58':'x','\u1E8B':'x','\u1E8D':'x','\u0079':'y','\u24E8':'y','\uFF59':'y','\u1EF3':'y','\u00FD':'y','\u0177':'y','\u1EF9':'y','\u0233':'y','\u1E8F':'y','\u00FF':'y','\u1EF7':'y','\u1E99':'y','\u1EF5':'y','\u01B4':'y','\u024F':'y','\u1EFF':'y','\u007A':'z','\u24E9':'z','\uFF5A':'z','\u017A':'z','\u1E91':'z','\u017C':'z','\u017E':'z','\u1E93':'z','\u1E95':'z','\u01B6':'z','\u0225':'z','\u0240':'z','\u2C6C':'z','\uA763':'z',};__exports.unaccent=unaccent;function unaccent(str,caseSensitive){str=str.replace(/[^\u0000-\u007E]/g,function(accented){return diacriticsMap[accented]||accented;});return caseSensitive?str:str.toLowerCase();}
__exports.isEmail=isEmail;function isEmail(value){const re=/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;return re.test(value);}
__exports.isNumeric=isNumeric;function isNumeric(value){return Boolean(value?.match(/^\d+$/));}
__exports.exprToBoolean=exprToBoolean;function exprToBoolean(str,trueIfEmpty=false){return str?!/^false|0$/i.test(str):trueIfEmpty;}
return __exports;});;

/* /web/static/src/core/utils/timing.js */
odoo.define('@web/core/utils/timing',['@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{onWillUnmount,useComponent}=require("@odoo/owl");__exports.batched=batched;function batched(callback,synchronize=()=>Promise.resolve()){let scheduled=false;return async(...args)=>{if(!scheduled){scheduled=true;await synchronize();scheduled=false;callback(...args);}};}
__exports.debounce=debounce;function debounce(func,delay,options){let handle;const funcName=func.name?func.name+" (debounce)":"debounce";const useAnimationFrame=delay==="animationFrame";const setFnName=useAnimationFrame?"requestAnimationFrame":"setTimeout";const clearFnName=useAnimationFrame?"cancelAnimationFrame":"clearTimeout";let lastArgs;let leading=false;let trailing=true;if(typeof options==="boolean"){leading=options;trailing=!options;}else if(options){leading=options.leading??leading;trailing=options.trailing??trailing;}
return Object.assign({[funcName](...args){return new Promise((resolve)=>{if(leading&&!handle){Promise.resolve(func.apply(this,args)).then(resolve);}else{lastArgs=args;}
browser[clearFnName](handle);handle=browser[setFnName](()=>{handle=null;if(trailing&&lastArgs){Promise.resolve(func.apply(this,lastArgs)).then(resolve);lastArgs=null;}},delay);});},}[funcName],{cancel(execNow=false){browser[clearFnName](handle);if(execNow&&lastArgs){func.apply(this,lastArgs);}},});}
__exports.setRecurringAnimationFrame=setRecurringAnimationFrame;function setRecurringAnimationFrame(callback){const handler=(timestamp)=>{callback(timestamp-lastTimestamp);lastTimestamp=timestamp;handle=browser.requestAnimationFrame(handler);};const stop=()=>{browser.cancelAnimationFrame(handle);};let lastTimestamp=browser.performance.now();let handle=browser.requestAnimationFrame(handler);return stop;}
__exports.throttleForAnimation=throttleForAnimation;function throttleForAnimation(func){let handle=null;const calls=new Set();const funcName=func.name?`${func.name} (throttleForAnimation)`:"throttleForAnimation";const pending=()=>{if(calls.size){handle=browser.requestAnimationFrame(pending);const{args,resolve}=[...calls].pop();calls.clear();Promise.resolve(func.apply(this,args)).then(resolve);}else{handle=null;}};return Object.assign({[funcName](...args){return new Promise((resolve)=>{const isNew=handle===null;if(isNew){handle=browser.requestAnimationFrame(pending);Promise.resolve(func.apply(this,args)).then(resolve);}else{calls.add({args,resolve});}});},}[funcName],{cancel(){browser.cancelAnimationFrame(handle);calls.clear();handle=null;},});}
__exports.useDebounced=useDebounced;function useDebounced(callback,delay,{execBeforeUnmount=false,immediate=false,trailing=!immediate}={}){const component=useComponent();const debounced=debounce(callback.bind(component),delay,{leading:immediate,trailing});onWillUnmount(()=>debounced.cancel(execBeforeUnmount));return debounced;}
__exports.useThrottleForAnimation=useThrottleForAnimation;function useThrottleForAnimation(func){const component=useComponent();const throttledForAnimation=throttleForAnimation(func.bind(component));onWillUnmount(()=>throttledForAnimation.cancel());return throttledForAnimation;}
return __exports;});;

/* /web/static/src/core/utils/ui.js */
odoo.define('@web/core/utils/ui',[],function(require){'use strict';let __exports={};__exports.closest=closest;function closest(elements,targetPos){let closestEl=null;let closestDistance=Infinity;for(const el of elements){const rect=el.getBoundingClientRect();const distance=getQuadrance(rect,targetPos);if(!closestEl||distance<closestDistance){closestEl=el;closestDistance=distance;}}
return closestEl;}
__exports.isVisible=isVisible;function isVisible(el){if(el===document||el===window){return true;}
if(!el){return false;}
let _isVisible=false;if("offsetWidth"in el&&"offsetHeight"in el){_isVisible=el.offsetWidth>0&&el.offsetHeight>0;}else if("getBoundingClientRect"in el){const rect=el.getBoundingClientRect();_isVisible=rect.width>0&&rect.height>0;}
if(!_isVisible&&getComputedStyle(el).display==="contents"){for(const child of el.children){if(isVisible(child)){return true;}}}
return _isVisible;}
__exports.getQuadrance=getQuadrance;function getQuadrance(rect,pos){let q=0;if(pos.x<rect.x){q+=(rect.x-pos.x)**2;}else if(rect.x+rect.width<pos.x){q+=(pos.x-(rect.x+rect.width))**2;}
if(pos.y<rect.y){q+=(rect.y-pos.y)**2;}else if(rect.y+rect.height<pos.y){q+=(pos.y-(rect.y+rect.height))**2;}
return q;}
__exports.getVisibleElements=getVisibleElements;function getVisibleElements(activeElement,selector){const visibleElements=[];const elements=activeElement.querySelectorAll(selector);for(const el of elements){if(isVisible(el)){visibleElements.push(el);}}
return visibleElements;}
__exports.touching=touching;function touching(elements,targetRect){const r1={x:0,y:0,width:0,height:0,...targetRect};return[...elements].filter((el)=>{const r2=el.getBoundingClientRect();return(r2.x+r2.width>=r1.x&&r2.x<=r1.x+r1.width&&r2.y+r2.height>=r1.y&&r2.y<=r1.y+r1.height);});}
const TABABLE_SELECTOR=["[tabindex]","a","area","button","frame","iframe","input","object","select","textarea","details > summary:nth-child(1)",].map((sel)=>`${sel}:not([tabindex="-1"]):not(:disabled)`).join(",");__exports.getTabableElements=getTabableElements;function getTabableElements(container=document.body){const elements=[...container.querySelectorAll(TABABLE_SELECTOR)].filter(isVisible);const byTabIndex={};for(const el of[...elements]){if(!byTabIndex[el.tabIndex]){byTabIndex[el.tabIndex]=[];}
byTabIndex[el.tabIndex].push(el);}
const withTabIndexZero=byTabIndex[0]||[];delete byTabIndex[0];return[...Object.values(byTabIndex).flat(),...withTabIndexZero];}
__exports.getNextTabableElement=getNextTabableElement;function getNextTabableElement(container=document.body){const tabableElements=getTabableElements(container);const index=tabableElements.indexOf(document.activeElement);return index===-1?tabableElements[0]:tabableElements[index+1]||null;}
__exports.getPreviousTabableElement=getPreviousTabableElement;function getPreviousTabableElement(container=document.body){const tabableElements=getTabableElements(container);const index=tabableElements.indexOf(document.activeElement);return index===-1?tabableElements[tabableElements.length-1]:tabableElements[index-1]||null;}
__exports.addLoadingEffect=addLoadingEffect;function addLoadingEffect(btnEl){btnEl.classList.add("o_btn_loading","disabled","pe-none");btnEl.disabled=true;const loaderEl=document.createElement("span");loaderEl.classList.add("fa","fa-refresh","fa-spin","me-2");btnEl.prepend(loaderEl);return()=>{btnEl.classList.remove("o_btn_loading","disabled","pe-none");btnEl.disabled=false;loaderEl.remove();};}
return __exports;});;

/* /web/static/src/core/utils/urls.js */
odoo.define('@web/core/utils/urls',['@web/session','@web/core/browser/browser','@web/core/utils/objects'],function(require){'use strict';let __exports={};const{session}=require("@web/session");const{browser}=require("@web/core/browser/browser");const{shallowEqual}=require("@web/core/utils/objects");const{DateTime}=luxon;const RedirectionError=__exports.RedirectionError=class RedirectionError extends Error{}
__exports.objectToUrlEncodedString=objectToUrlEncodedString;function objectToUrlEncodedString(obj){return Object.entries(obj).map(([k,v])=>`${encodeURIComponent(k)}=${encodeURIComponent(v || "")}`).join("&");}
__exports.getOrigin=getOrigin;function getOrigin(origin){if(origin){origin=origin.replace(/\/+$/,"");}else{const{host,protocol}=browser.location;origin=`${protocol}//${host}`;}
return origin;}
__exports.url=url;function url(route,queryParams,options={}){const origin=getOrigin(options.origin??session.origin);if(!route){return origin;}
let queryString=objectToUrlEncodedString(queryParams||{});queryString=queryString.length>0?`?${queryString}`:queryString;let prefix=["http://","https://","//"].some((el)=>route.length>=el.length&&route.slice(0,el.length)===el);prefix=prefix?"":origin;return`${prefix}${route}${queryString}`;}
__exports.imageUrl=imageUrl;function imageUrl(model,id,field,{access_token,filename,height,unique,width}={}){let route=`/web/image/${model}/${id}/${field}`;if(width&&height){route=`${route}/${width}x${height}`;}
if(filename){route=`${route}/${filename}`;}
const urlParams={};if(access_token){Object.assign(urlParams,{access_token});}
if(unique){if(unique instanceof DateTime){urlParams.unique=unique.ts;}else{const dateTimeFromUnique=DateTime.fromSQL(unique);if(dateTimeFromUnique.isValid){urlParams.unique=dateTimeFromUnique.ts;}else if(typeof unique==="string"&&unique.length>0){urlParams.unique=unique;}}}
return url(route,urlParams);}
__exports.getDataURLFromFile=getDataURLFromFile;function getDataURLFromFile(file){if(!file){return Promise.reject();}
return new Promise((resolve,reject)=>{const reader=new FileReader();reader.addEventListener("load",()=>{if(reader.result==="data:"){resolve(`data:${file.type};base64,`);}else{resolve(reader.result);}});reader.addEventListener("abort",reject);reader.addEventListener("error",reject);reader.readAsDataURL(file);});}
__exports.redirect=redirect;function redirect(url){const{origin,pathname}=browser.location;const _url=new URL(url,`${origin}${pathname}`);if(_url.origin!==origin){throw new RedirectionError("Can't redirect to another origin");}
browser.location.assign(_url.href);}
__exports.compareUrls=compareUrls;function compareUrls(_url1,_url2){const url1=new URL(_url1);const url2=new URL(_url2);return(url1.origin===url2.origin&&url1.pathname===url2.pathname&&shallowEqual(Object.fromEntries(url1.searchParams),Object.fromEntries(url2.searchParams))&&url1.hash===url2.hash);}
return __exports;});;

/* /web/static/src/core/utils/xml.js */
odoo.define('@web/core/utils/xml',['@web/core/utils/arrays'],function(require){'use strict';let __exports={};const{isIterable}=require("@web/core/utils/arrays");const serializer=new XMLSerializer();const parser=new DOMParser();const xmlDocument=parser.parseFromString("<templates/>","text/xml");function hasParsingError(parsedDocument){return parsedDocument.getElementsByTagName("parsererror").length>0;}
__exports.parseXML=parseXML;function parseXML(str){const xml=parser.parseFromString(str,"text/xml");if(hasParsingError(xml)){throw new Error(`An error occured while parsing ${str}: ${xml.getElementsByTagName("parsererror")}`);}
return xml.documentElement;}
__exports.serializeXML=serializeXML;function serializeXML(xml){return serializer.serializeToString(xml);}
__exports.visitXML=visitXML;function visitXML(xml,callback){const visit=(el)=>{if(el){let didVisitChildren=false;const visitChildren=()=>{for(const child of el.children){visit(child);}
didVisitChildren=true;};const shouldVisitChildren=callback(el,visitChildren);if(shouldVisitChildren!==false&&!didVisitChildren){visitChildren();}}};const xmlDoc=typeof xml==="string"?parseXML(xml):xml;visit(xmlDoc);}
__exports.append=append;function append(parent,node){const nodes=Array.isArray(node)?node:[node];parent.append(...nodes.filter(Boolean));return parent;}
__exports.combineAttributes=combineAttributes;function combineAttributes(el,attr,parts,glue=" "){const allValues=[];if(el.hasAttribute(attr)){allValues.push(el.getAttribute(attr));}
parts=Array.isArray(parts)?parts:[parts];parts=parts.filter((part)=>!!part);allValues.push(...parts);el.setAttribute(attr,allValues.join(glue));}
__exports.createElement=createElement;function createElement(tagName,...args){const el=xmlDocument.createElement(tagName);for(const arg of args){if(!arg){continue;}
if(isIterable(arg)){el.append(...arg);}else if(typeof arg==="object"){for(const name in arg){el.setAttribute(name,arg[name]);}}}
return el;}
__exports.createTextNode=createTextNode;function createTextNode(data){return xmlDocument.createTextNode(data);}
__exports.extractAttributes=extractAttributes;function extractAttributes(el,attributes){const attrs=Object.create(null);for(const attr of attributes){attrs[attr]=el.getAttribute(attr)||"";el.removeAttribute(attr);}
return attrs;}
__exports.getTag=getTag;function getTag(node,lower=false){const tag=(node&&node.nodeName)||"";return lower?tag.toLowerCase():tag;}
__exports.setAttributes=setAttributes;function setAttributes(node,attributes){for(const[name,value]of Object.entries(attributes)){node.setAttribute(name,value);}}
return __exports;});;

/* /web/static/src/core/virtual_grid_hook.js */
odoo.define('@web/core/virtual_grid_hook',['@odoo/owl','@web/core/utils/objects','@web/core/utils/timing'],function(require){'use strict';let __exports={};const{useComponent,useEffect,useExternalListener}=require("@odoo/owl");const{pick,shallowEqual}=require("@web/core/utils/objects");const{useThrottleForAnimation}=require("@web/core/utils/timing");const BUFFER_COEFFICIENT=1;function getIndexes({sizes,start,span,prevStartIndex,bufferCoef=BUFFER_COEFFICIENT}){if(!sizes||!sizes.length){return[];}
if(sizes.at(-1)<span){return[0,sizes.length-1];}
const bufferSize=Math.round(span*bufferCoef);const bufferStart=start-bufferSize;const bufferEnd=start+span+bufferSize;let startIndex=prevStartIndex??0;while(startIndex>0&&sizes[startIndex]>bufferStart){startIndex--;}
while(startIndex<sizes.length-1&&sizes[startIndex]<=bufferStart){startIndex++;}
let endIndex=startIndex;while(endIndex<sizes.length-1&&(sizes[endIndex-1]??0)<bufferEnd){endIndex++;}
while(endIndex>startIndex&&(sizes[endIndex-1]??0)>=bufferEnd){endIndex--;}
return[startIndex,endIndex];}
__exports.useVirtualGrid=useVirtualGrid;function useVirtualGrid({scrollableRef,initialScroll,onChange,bufferCoef}){const comp=useComponent();onChange||=()=>comp.render();const current={scroll:{left:0,top:0,...initialScroll}};const computeColumnsIndexes=()=>{return getIndexes({sizes:current.summedColumnsWidths,start:Math.abs(current.scroll.left),span:window.innerWidth,prevStartIndex:current.columnsIndexes?.[0],bufferCoef,});};const computeRowsIndexes=()=>{return getIndexes({sizes:current.summedRowsHeights,start:current.scroll.top,span:window.innerHeight,prevStartIndex:current.rowsIndexes?.[0],bufferCoef,});};const throttledCompute=useThrottleForAnimation(()=>{const changed=[];const columnsVisibleIndexes=computeColumnsIndexes();if(!shallowEqual(columnsVisibleIndexes,current.columnsIndexes)){current.columnsIndexes=columnsVisibleIndexes;changed.push("columnsIndexes");}
const rowsVisibleIndexes=computeRowsIndexes();if(!shallowEqual(rowsVisibleIndexes,current.rowsIndexes)){current.rowsIndexes=rowsVisibleIndexes;changed.push("rowsIndexes");}
if(changed.length){onChange(pick(current,...changed));}});const scrollListener=(ev)=>{current.scroll.left=ev.target.scrollLeft;current.scroll.top=ev.target.scrollTop;throttledCompute();};useEffect((el)=>{el?.addEventListener("scroll",scrollListener);return()=>el?.removeEventListener("scroll",scrollListener);},()=>[scrollableRef.el]);useExternalListener(window,"resize",()=>throttledCompute());return{get columnsIndexes(){return current.columnsIndexes;},get rowsIndexes(){return current.rowsIndexes;},setColumnsWidths(widths){let acc=0;current.summedColumnsWidths=widths.map((w)=>(acc+=w));delete current.columnsIndexes;current.columnsIndexes=computeColumnsIndexes();},setRowsHeights(heights){let acc=0;current.summedRowsHeights=heights.map((h)=>(acc+=h));delete current.rowsIndexes;current.rowsIndexes=computeRowsIndexes();},};}
return __exports;});;

/* /web/static/src/views/fields/formatters.js */
odoo.define('@web/views/fields/formatters',['@web/core/l10n/dates','@web/core/l10n/localization','@web/core/l10n/translation','@web/core/registry','@web/core/utils/binary','@web/core/utils/numbers','@web/core/utils/strings','@odoo/owl','@web/core/currency'],function(require){'use strict';let __exports={};const{formatDate:_formatDate,formatDateTime:_formatDateTime}=require("@web/core/l10n/dates");const{localization:l10n}=require("@web/core/l10n/localization");const{_t}=require("@web/core/l10n/translation");const{registry}=require("@web/core/registry");const{isBinarySize}=require("@web/core/utils/binary");const{formatFloat:formatFloatNumber,humanNumber,insertThousandsSep,}=require("@web/core/utils/numbers");const{escape,exprToBoolean}=require("@web/core/utils/strings");const{markup}=require("@odoo/owl");const{formatCurrency}=require("@web/core/currency");function humanSize(value){if(!value){return"";}
const suffix=value<1024?" "+_t("Bytes"):"b";return(humanNumber(value,{decimals:2,})+suffix);}
__exports.formatBinary=formatBinary;function formatBinary(value){if(!isBinarySize(value)){return humanSize(value.length/1.37);}
return value;}
__exports.formatBoolean=formatBoolean;function formatBoolean(value){return markup(`
        <div class="o-checkbox d-inline-block me-2">
            <input id="boolean_checkbox" type="checkbox" class="form-check-input" disabled ${
                value ? "checked" : ""
            }/>
            <label for="boolean_checkbox" class="form-check-label"/>
        </div>`);}
__exports.formatChar=formatChar;function formatChar(value,options){if(options&&options.isPassword){return"*".repeat(value?value.length:0);}
if(options&&options.escape){value=escape(value);}
return value;}
formatChar.extractOptions=({attrs})=>{return{isPassword:exprToBoolean(attrs.password),};};__exports.formatDate=formatDate;function formatDate(value,options){return _formatDate(value,options);}
formatDate.extractOptions=({options})=>{return{condensed:options.condensed};};__exports.formatDateTime=formatDateTime;function formatDateTime(value,options={}){if(options.showTime===false){return _formatDate(value,options);}
return _formatDateTime(value,options);}
formatDateTime.extractOptions=({attrs,options})=>{return{...formatDate.extractOptions({attrs,options}),showSeconds:exprToBoolean(options.show_seconds??true),showTime:exprToBoolean(options.show_time??true),};};__exports.formatFloat=formatFloat;function formatFloat(value,options={}){if(value===false){return"";}
if(!options.digits&&options.field){options.digits=options.field.digits;}
return formatFloatNumber(value,options);}
formatFloat.extractOptions=({attrs,options})=>{let digits;if(attrs.digits){digits=JSON.parse(attrs.digits);}else if(options.digits){digits=options.digits;}
const humanReadable=!!options.human_readable;const decimals=options.decimals||0;return{decimals,digits,humanReadable};};__exports.formatFloatFactor=formatFloatFactor;function formatFloatFactor(value,options={}){if(value===false){return"";}
const factor=options.factor||1;if(!options.digits&&options.field){options.digits=options.field.digits;}
return formatFloatNumber(value*factor,options);}
formatFloatFactor.extractOptions=({attrs,options})=>{return{...formatFloat.extractOptions({attrs,options}),factor:options.factor,};};__exports.formatFloatTime=formatFloatTime;function formatFloatTime(value,options={}){if(value===false){return"";}
const isNegative=value<0;value=Math.abs(value);let hour=Math.floor(value);const milliSecLeft=Math.round(value*3600000)-hour*3600000;let min=milliSecLeft/60000;if(options.displaySeconds){min=Math.floor(min);}else{min=Math.round(min);}
if(min===60){min=0;hour=hour+1;}
min=String(min).padStart(2,"0");if(!options.noLeadingZeroHour){hour=String(hour).padStart(2,"0");}
let sec="";if(options.displaySeconds){sec=":"+String(Math.floor((milliSecLeft%60000)/1000)).padStart(2,"0");}
return`${isNegative ? "-" : ""}${hour}:${min}${sec}`;}
formatFloatTime.extractOptions=({options})=>{return{displaySeconds:options.displaySeconds,};};__exports.formatInteger=formatInteger;function formatInteger(value,options={}){if(value===false||value===null){return"";}
if(options.isPassword){return"*".repeat(value.length);}
if(options.humanReadable){return humanNumber(value,options);}
const grouping=options.grouping||l10n.grouping;const thousandsSep="thousandsSep"in options?options.thousandsSep:l10n.thousandsSep;return insertThousandsSep(value.toFixed(0),thousandsSep,grouping);}
formatInteger.extractOptions=({attrs,options})=>{return{decimals:options.decimals||0,humanReadable:!!options.human_readable,isPassword:exprToBoolean(attrs.password),};};__exports.formatMany2one=formatMany2one;function formatMany2one(value,options){if(!value){value="";}else if(value[1]){value=value[1];}else{value=_t("Unnamed");}
if(options&&options.escape){value=encodeURIComponent(value);}
return value;}
__exports.formatX2many=formatX2many;function formatX2many(value){const count=value.currentIds.length;if(count===0){return _t("No records");}else if(count===1){return _t("1 record");}else{return _t("%s records",count);}}
__exports.formatMonetary=formatMonetary;function formatMonetary(value,options={}){if(value===false){return"";}
let currencyId=options.currencyId;if(!currencyId&&options.data){const currencyField=options.currencyField||(options.field&&options.field.currency_field)||"currency_id";const dataValue=options.data[currencyField];currencyId=Array.isArray(dataValue)?dataValue[0]:dataValue;}
return formatCurrency(value,currencyId,options);}
formatMonetary.extractOptions=({options})=>{return{noSymbol:options.no_symbol,currencyField:options.currency_field,};};__exports.formatPercentage=formatPercentage;function formatPercentage(value,options={}){value=value||0;options=Object.assign({trailingZeros:false,thousandsSep:""},options);if(!options.digits&&options.field){options.digits=options.field.digits;}
const formatted=formatFloatNumber(value*100,options);return`${formatted}${options.noSymbol ? "" : "%"}`;}
formatPercentage.extractOptions=formatFloat.extractOptions;function formatProperties(value,field){if(!value||!value.length){return"";}
return value.map((property)=>property["string"]).join(", ");}
__exports.formatReference=formatReference;function formatReference(value,options){return formatMany2one(value?[value.resId,value.displayName]:false,options);}
__exports.formatMany2oneReference=formatMany2oneReference;function formatMany2oneReference(value){return value?formatMany2one([value.resId,value.displayName]):"";}
__exports.formatSelection=formatSelection;function formatSelection(value,options={}){const selection=options.selection||(options.field&&options.field.selection)||[];const option=selection.find((option)=>option[0]===value);return option?option[1]:"";}
__exports.formatText=formatText;function formatText(value){return value?value.toString():"";}
__exports.formatHtml=formatHtml;function formatHtml(value){return value;}
__exports.formatJson=formatJson;function formatJson(value){return(value&&JSON.stringify(value))||"";}
registry.category("formatters").add("binary",formatBinary).add("boolean",formatBoolean).add("char",formatChar).add("date",formatDate).add("datetime",formatDateTime).add("float",formatFloat).add("float_factor",formatFloatFactor).add("float_time",formatFloatTime).add("html",formatHtml).add("integer",formatInteger).add("json",formatJson).add("many2one",formatMany2one).add("many2one_reference",formatMany2oneReference).add("one2many",formatX2many).add("many2many",formatX2many).add("monetary",formatMonetary).add("percentage",formatPercentage).add("properties",formatProperties).add("properties_definition",formatProperties).add("reference",formatReference).add("selection",formatSelection).add("text",formatText);return __exports;});;

/* /point_of_sale/static/src/utils.js */
odoo.define('@point_of_sale/utils',['@web/core/l10n/dates','@web/core/utils/numbers'],function(require){'use strict';let __exports={};const{parseDateTime,deserializeDateTime}=require("@web/core/l10n/dates");const{roundDecimals,floatIsZero}=require("@web/core/utils/numbers");__exports.uuidv4=uuidv4;function uuidv4(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){const r=(Math.random()*16)|0,v=c=="x"?r:(r&0x3)|0x8;return v.toString(16);});}
__exports.deduceUrl=deduceUrl;function deduceUrl(url){const{protocol}=window.location;if(!url.includes("//")){url=`${protocol}//${url}`;}
if(url.indexOf(":",6)<0){url+=":"+(protocol==="https:"?443:8069);}
return url;}
__exports.constructFullProductName=constructFullProductName;function constructFullProductName(line){let attributeString="";if(line.attribute_value_ids&&line.attribute_value_ids.length>0){for(const value of line.attribute_value_ids){if(value.is_custom){const customValue=line.custom_attribute_value_ids.find((cus)=>cus.custom_product_template_attribute_value_id?.id==parseInt(value.id));if(customValue){attributeString+=`${value.attribute_id.name}: ${value.name}: ${customValue.custom_value}, `;}}else{attributeString+=`${value.name}, `;}}
attributeString=attributeString.slice(0,-2);attributeString=` (${attributeString})`;}
return`${line?.product_id?.display_name}${attributeString}`;}
__exports.random5Chars=random5Chars;function random5Chars(){let code="";while(code.length!=5){code=Math.random().toString(36).slice(2,7);}
return code;}
__exports.qrCodeSrc=qrCodeSrc;function qrCodeSrc(url,{size=200}={}){return`/report/barcode/QR/${encodeURIComponent(url)}?width=${size}&height=${size}`;}
__exports.getMax=getMax;function getMax(entries,{criterion=(x)=>x,inverted=false}={}){return entries.reduce((prev,current)=>{const res=criterion(prev)>criterion(current);return(inverted?!res:res)?prev:current;});}
__exports.getMin=getMin;function getMin(entries,options){return getMax(entries,{...options,inverted:true});}
__exports.getOnNotified=getOnNotified;function getOnNotified(bus,channel){if(!channel||typeof channel!=="string"){return()=>false;}
bus.addChannel(channel);return(notif,callback)=>bus.subscribe(`${channel}-${notif}`,callback);}
__exports.loadImage=loadImage;function loadImage(url,options={}){return new Promise((resolve,reject)=>{const img=new Image();img.addEventListener("load",()=>resolve(img));img.addEventListener("error",()=>{if(options.onError){options.onError();}
reject(new Error(`Failed to load image at ${url}`));});img.src=url;});}
__exports.loadAllImages=loadAllImages;function loadAllImages(el){if(!el){return Promise.resolve();}
const images=el.querySelectorAll("img");return Promise.all(Array.from(images).map((img)=>loadImage(img.src)));}
__exports.parseUTCString=parseUTCString;function parseUTCString(utcStr){return parseDateTime(utcStr,{format:"yyyy-MM-dd HH:mm:ss",tz:"utc"});}
__exports.floatCompare=floatCompare;function floatCompare(a,b,{decimals}={}){if(decimals===undefined){throw new Error("decimals must be provided");}
a=roundDecimals(a,decimals);b=roundDecimals(b,decimals);const delta=a-b;if(floatIsZero(delta,decimals)){return 0;}
return delta<0?-1:1;}
__exports.gte=gte;function gte(a,b,{decimals}={}){return floatCompare(a,b,{decimals})>=0;}
__exports.gt=gt;function gt(a,b,{decimals}={}){return floatCompare(a,b,{decimals})>0;}
__exports.lte=lte;function lte(a,b,{decimals}={}){return floatCompare(a,b,{decimals})<=0;}
__exports.lt=lt;function lt(a,b,{decimals}={}){return floatCompare(a,b,{decimals})<0;}
__exports.computeProductPricelistCache=computeProductPricelistCache;function computeProductPricelistCache(service,data=[]){const date=luxon.DateTime.now();let pricelistItems=service.models["product.pricelist.item"].getAll();let products=service.models["product.product"].getAll();if(data.length>0){if(data[0].model.modelName==="product.product"){products=data;}
if(data[0].model.modelName==="product.pricelist.item"){pricelistItems=data;const productTmplIds=new Set(data.map((item)=>item.raw.product_tmpl_id));const productIds=new Set(data.map((item)=>item.raw.product_id));products=products.filter((product)=>productTmplIds.has(product.raw.product_tmpl_id)||productIds.has(product.id));}}
const pushItem=(targetArray,key,item)=>{if(!targetArray[key]){targetArray[key]=[];}
targetArray[key].push(item);};const pricelistRules={};for(const item of pricelistItems){if((item.date_start&&deserializeDateTime(item.date_start)>date)||(item.date_end&&deserializeDateTime(item.date_end)<date)){continue;}
const pricelistId=item.pricelist_id.id;if(!pricelistRules[pricelistId]){pricelistRules[pricelistId]={productItems:{},productTmlpItems:{},categoryItems:{},globalItems:[],};}
const productId=item.raw.product_id;if(productId){pushItem(pricelistRules[pricelistId].productItems,productId,item);continue;}
const productTmplId=item.raw.product_tmpl_id;if(productTmplId){pushItem(pricelistRules[pricelistId].productTmlpItems,productTmplId,item);continue;}
const categId=item.raw.categ_id;if(categId){pushItem(pricelistRules[pricelistId].categoryItems,categId,item);}else{pricelistRules[pricelistId].globalItems.push(item);}}
for(const product of products){const applicableRules=product.getApplicablePricelistRules(pricelistRules);for(const pricelistId in applicableRules){if(product.cachedPricelistRules[pricelistId]){const existingRuleIds=product.cachedPricelistRules[pricelistId].map((rule)=>rule.id);const newRules=applicableRules[pricelistId].filter((rule)=>!existingRuleIds.includes(rule.id));product.cachedPricelistRules[pricelistId]=[...newRules,...product.cachedPricelistRules[pricelistId],];}else{product.cachedPricelistRules[pricelistId]=applicableRules[pricelistId];}}}
if(data.length>0&&data[0].model.modelName==="product.product"){service._loadMissingPricelistItems(products);}}
return __exports;});;

/* /bus/static/src/services/bus_service.js */
odoo.define('@bus/services/bus_service',['@web/core/browser/browser','@web/core/l10n/translation','@web/core/utils/concurrency','@web/core/registry','@web/session','@web/core/browser/feature_detection','@odoo/owl','@web/core/user'],function(require){'use strict';let __exports={};const{browser}=require("@web/core/browser/browser");const{_t}=require("@web/core/l10n/translation");const{Deferred}=require("@web/core/utils/concurrency");const{registry}=require("@web/core/registry");const{session}=require("@web/session");const{isIosApp}=require("@web/core/browser/feature_detection");const{EventBus}=require("@odoo/owl");const{user}=require("@web/core/user");const INTERNAL_EVENTS=new Set(["initialized","outdated","log_debug","notification"]);const BACK_ONLINE_RECONNECT_DELAY=__exports.BACK_ONLINE_RECONNECT_DELAY=5000;const busService=__exports.busService={dependencies:["bus.parameters","localization","multi_tab","notification"],start(env,{multi_tab:multiTab,notification,"bus.parameters":params}){const bus=new EventBus();const notificationBus=new EventBus();const subscribeFnToWrapper=new Map();let worker;let workerState;let isActive=false;let isInitialized=false;let lastNotificationId=null;let isUsingSharedWorker=browser.SharedWorker&&!isIosApp();let backOnlineTimeout;const startedAt=luxon.DateTime.now().set({milliseconds:0});const connectionInitializedDeferred=new Deferred();function send(action,data){if(!worker){return;}
const message={action,data};if(isUsingSharedWorker){worker.port.postMessage(message);}else{worker.postMessage(message);}}
function handleMessage(messageEv){const{type,data}=messageEv.data;switch(type){case"notification":{const notifications=data.map(({id,message})=>({id,...message}));lastNotificationId=notifications.at(-1).id;multiTab.setSharedValue("last_notification_id",lastNotificationId);for(const{id,type,payload}of notifications){notificationBus.trigger(type,{id,payload});busService._onMessage(id,type,payload);}
break;}
case"initialized":{isInitialized=true;connectionInitializedDeferred.resolve();break;}
case"worker_state_updated":workerState=data;break;case"log_debug":console.debug(...data);break;case"outdated":{multiTab.unregister();notification.add(_t("Save your work and refresh to get the latest updates and avoid potential issues."),{title:_t("The page is out of date"),type:"warning",sticky:true,buttons:[{name:_t("Refresh"),primary:true,onClick:()=>{browser.location.reload();},},],});break;}}
if(!INTERNAL_EVENTS.has(type)){bus.trigger(type,data);}}
function initializeWorkerConnection(){let uid=Array.isArray(session.user_id)?session.user_id[0]:user.userId;if(!uid&&uid!==undefined){uid=false;}
send("initialize_connection",{websocketURL:`${params.serverURL.replace("http", "ws")}/websocket?version=${
                    session.websocket_worker_version
                }`,db:session.db,debug:odoo.debug,lastNotificationId:multiTab.getSharedValue("last_notification_id",0),uid,startTs:startedAt.valueOf(),});}
function startWorker(){let workerURL=`${params.serverURL}/bus/websocket_worker_bundle?v=${session.websocket_worker_version}`;if(params.serverURL!==window.origin){const source=`importScripts("${workerURL}");`;workerURL="data:application/javascript;base64,"+window.btoa(source);}
const workerClass=isUsingSharedWorker?browser.SharedWorker:browser.Worker;worker=new workerClass(workerURL,{name:isUsingSharedWorker?"odoo:websocket_shared_worker":"odoo:websocket_worker",});worker.addEventListener("error",(e)=>{if(!isInitialized&&workerClass===browser.SharedWorker){console.warn('Error while loading "bus_service" SharedWorker, fallback on Worker.');isUsingSharedWorker=false;startWorker();}else if(!isInitialized){isInitialized=true;connectionInitializedDeferred.resolve();console.warn("Bus service failed to initialized.");}});if(isUsingSharedWorker){worker.port.start();worker.port.addEventListener("message",handleMessage);}else{worker.addEventListener("message",handleMessage);}
initializeWorkerConnection();}
browser.addEventListener("pagehide",({persisted})=>{if(!persisted){send("leave");}});browser.addEventListener("online",()=>{backOnlineTimeout=browser.setTimeout(()=>{if(isActive){send("start");}},BACK_ONLINE_RECONNECT_DELAY);},{capture:true});browser.addEventListener("offline",()=>{clearTimeout(backOnlineTimeout);send("stop");},{capture:true,});return{addEventListener:bus.addEventListener.bind(bus),addChannel:async(channel)=>{if(!worker){startWorker();}
await connectionInitializedDeferred;send("add_channel",channel);send("start");isActive=true;},deleteChannel:(channel)=>send("delete_channel",channel),forceUpdateChannels:()=>send("force_update_channels"),trigger:bus.trigger.bind(bus),removeEventListener:bus.removeEventListener.bind(bus),send:(eventName,data)=>send("send",{event_name:eventName,data}),start:async()=>{if(!worker){startWorker();}
await connectionInitializedDeferred;send("start");isActive=true;},stop:()=>{send("leave");isActive=false;},get isActive(){return isActive;},subscribe(notificationType,callback){const wrapper=({detail})=>{const{id,payload}=detail;callback(payload,{id});};subscribeFnToWrapper.set(callback,wrapper);notificationBus.addEventListener(notificationType,wrapper);},unsubscribe(notificationType,callback){notificationBus.removeEventListener(notificationType,subscribeFnToWrapper.get(callback));subscribeFnToWrapper.delete(callback);},startedAt,get workerState(){return workerState;},get lastNotificationId(){return lastNotificationId;},};},_onMessage(id,type,payload){},};registry.category("services").add("bus_service",busService);return __exports;});;

/* /bus/static/src/bus_parameters_service.js */
odoo.define('@bus/bus_parameters_service',['@web/core/registry'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const busParametersService=__exports.busParametersService={start(){return{serverURL:window.origin,};},};registry.category("services").add("bus.parameters",busParametersService);return __exports;});;

/* /bus/static/src/multi_tab_service.js */
odoo.define('@bus/multi_tab_service',['@web/core/registry','@web/core/browser/browser','@odoo/owl'],function(require){'use strict';let __exports={};const{registry}=require("@web/core/registry");const{browser}=require("@web/core/browser/browser");const{EventBus}=require("@odoo/owl");let multiTabId=0;const multiTabService=__exports.multiTabService={start(){const bus=new EventBus();const TAB_HEARTBEAT_PERIOD=10000;const MAIN_TAB_HEARTBEAT_PERIOD=1500;const HEARTBEAT_OUT_OF_DATE_PERIOD=5000;const HEARTBEAT_KILL_OLD_PERIOD=15000;const PRIVATE_LOCAL_STORAGE_KEYS=["main","heartbeat"];let _isOnMainTab=false;let lastHeartbeat=0;let heartbeatTimeout;const sanitizedOrigin=location.origin.replace(/:\/{0,2}/g,"_");const localStoragePrefix=`${this.name}.${sanitizedOrigin}.`;const now=new Date().getTime();const tabId=`${this.name}${multiTabId++}:${now}`;function generateLocalStorageKey(baseKey){return localStoragePrefix+baseKey;}
function getItemFromStorage(key,defaultValue){const item=browser.localStorage.getItem(generateLocalStorageKey(key));try{return item?JSON.parse(item):defaultValue;}catch{return item;}}
function setItemInStorage(key,value){browser.localStorage.setItem(generateLocalStorageKey(key),JSON.stringify(value));}
function startElection(){if(_isOnMainTab){return;}
const now=new Date().getTime();const lastPresenceByTab=getItemFromStorage("lastPresenceByTab",{});const heartbeatKillOld=now-HEARTBEAT_KILL_OLD_PERIOD;let newMain;for(const[tab,lastPresence]of Object.entries(lastPresenceByTab)){if(lastPresence<heartbeatKillOld){continue;}
newMain=tab;break;}
if(newMain===tabId){lastHeartbeat=now;setItemInStorage("heartbeat",lastHeartbeat);setItemInStorage("main",true);_isOnMainTab=true;bus.trigger("become_main_tab");delete lastPresenceByTab[newMain];setItemInStorage("lastPresenceByTab",lastPresenceByTab);}}
function heartbeat(){const now=new Date().getTime();let heartbeatValue=getItemFromStorage("heartbeat",0);const lastPresenceByTab=getItemFromStorage("lastPresenceByTab",{});if(heartbeatValue+HEARTBEAT_OUT_OF_DATE_PERIOD<now){startElection();heartbeatValue=getItemFromStorage("heartbeat",0);}
if(_isOnMainTab){const cleanedTabs={};for(const[tabId,lastPresence]of Object.entries(lastPresenceByTab)){if(lastPresence+HEARTBEAT_KILL_OLD_PERIOD>now){cleanedTabs[tabId]=lastPresence;}}
if(heartbeatValue!==lastHeartbeat){_isOnMainTab=false;lastHeartbeat=0;lastPresenceByTab[tabId]=now;setItemInStorage("lastPresenceByTab",lastPresenceByTab);bus.trigger("no_longer_main_tab");}else{lastHeartbeat=now;setItemInStorage("heartbeat",now);setItemInStorage("lastPresenceByTab",cleanedTabs);}}else{lastPresenceByTab[tabId]=now;setItemInStorage("lastPresenceByTab",lastPresenceByTab);}
const hbPeriod=_isOnMainTab?MAIN_TAB_HEARTBEAT_PERIOD:TAB_HEARTBEAT_PERIOD;heartbeatTimeout=browser.setTimeout(heartbeat,hbPeriod);}
function onStorage({key,newValue}){if(key===generateLocalStorageKey("main")&&!newValue){startElection();}
if(PRIVATE_LOCAL_STORAGE_KEYS.includes(key)){return;}
if(key&&key.includes(localStoragePrefix)){const baseKey=key.replace(localStoragePrefix,"");bus.trigger("shared_value_updated",{key:baseKey,newValue});}}
function unregister(){clearTimeout(heartbeatTimeout);const lastPresenceByTab=getItemFromStorage("lastPresenceByTab",{});delete lastPresenceByTab[tabId];setItemInStorage("lastPresenceByTab",lastPresenceByTab);if(_isOnMainTab){_isOnMainTab=false;bus.trigger("no_longer_main_tab");browser.localStorage.removeItem(generateLocalStorageKey("main"));}}
browser.addEventListener("pagehide",unregister);browser.addEventListener("storage",onStorage);const lastPresenceByTab=getItemFromStorage("lastPresenceByTab",{});lastPresenceByTab[tabId]=now;setItemInStorage("lastPresenceByTab",lastPresenceByTab);if(!getItemFromStorage("main")){startElection();}
heartbeat();return{bus,get currentTabId(){return tabId;},isOnMainTab(){return _isOnMainTab;},getSharedValue(key,defaultValue){return getItemFromStorage(key,defaultValue);},setSharedValue(key,value){if(value===undefined){return this.removeSharedValue(key);}
setItemInStorage(key,value);},removeSharedValue(key){browser.localStorage.removeItem(generateLocalStorageKey(key));},unregister:unregister,};},};registry.category("services").add("multi_tab",multiTabService);return __exports;});;

/* /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;});;

/* /point_of_sale/static/src/app/generic_components/odoo_logo/odoo_logo.js */
odoo.define('@point_of_sale/app/generic_components/odoo_logo/odoo_logo',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const OdooLogo=__exports.OdooLogo=class OdooLogo extends Component{static template="point_of_sale.OdooLogo";static props={class:{type:String,optional:true},style:{type:String,optional:true},monochrome:{type:Boolean,optional:true},};static defaultProps={class:"",style:"",monochrome:false,};}
return __exports;});;

/* /point_of_sale/static/src/app/generic_components/order_widget/order_widget.js */
odoo.define('@point_of_sale/app/generic_components/order_widget/order_widget',['@odoo/owl','@point_of_sale/app/generic_components/centered_icon/centered_icon','@web/core/l10n/translation','@point_of_sale/app/generic_components/orderline/orderline','@web/views/fields/formatters'],function(require){'use strict';let __exports={};const{Component,useEffect,useRef}=require("@odoo/owl");const{CenteredIcon}=require("@point_of_sale/app/generic_components/centered_icon/centered_icon");const{_t}=require("@web/core/l10n/translation");const{Orderline}=require("@point_of_sale/app/generic_components/orderline/orderline");const{formatMonetary}=require("@web/views/fields/formatters");const OrderWidget=__exports.OrderWidget=class OrderWidget extends Component{static template="point_of_sale.OrderWidget";static props={lines:{type:Array,element:Object,optional:true},slots:{type:Object,optional:true},taxTotals:{type:Object,optional:true},style:{type:String,optional:true},class:{type:String,optional:true},generalNote:{type:String,optional:true},screenName:{type:String,optional:true},};static defaultProps={style:"",class:"",};static components={CenteredIcon,Orderline};setup(){this.scrollableRef=useRef("scrollable");this.formatMonetary=formatMonetary;useEffect(()=>{this.scrollableRef.el?.querySelector(".orderline.selected")?.scrollIntoView({behavior:"smooth",block:"start"});});}
emptyCartText(){return _t("Start adding products");}}
return __exports;});;

/* /point_of_sale/static/src/app/generic_components/orderline/orderline.js */
odoo.define('@point_of_sale/app/generic_components/orderline/orderline',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const Orderline=__exports.Orderline=class Orderline extends Component{static template="point_of_sale.Orderline";static props={class:{type:Object,optional:true},line:{type:Object,shape:{isSelected:{type:Boolean,optional:true},productName:String,price:String,qty:String,unit:{type:String,optional:true},unitPrice:String,discount:{type:String,optional:true},comboParent:{type:String,optional:true},oldUnitPrice:{type:String,optional:true},customerNote:{type:String,optional:true},internalNote:{type:String,optional:true},imageSrc:{type:String,optional:true},packLotLines:{type:Array,optional:true},price_without_discount:{type:String,optional:true},taxGroupLabels:{type:String,optional:true},},},showTaxGroupLabels:{type:Boolean,optional:true},slots:{type:Object,optional:true},basic_receipt:{type:Boolean,optional:true},};static defaultProps={class:{},showTaxGroupLabels:false,basic_receipt:false,};}
return __exports;});;

/* /point_of_sale/static/src/app/generic_components/centered_icon/centered_icon.js */
odoo.define('@point_of_sale/app/generic_components/centered_icon/centered_icon',['@odoo/owl'],function(require){'use strict';let __exports={};const{Component,xml}=require("@odoo/owl");const CenteredIcon=__exports.CenteredIcon=class CenteredIcon extends Component{static props={icon:String,text:{type:String,optional:true},class:{type:String,optional:true},};static defaultProps={class:"",};static template=xml`
        <div t-attf-class="{{props.class}} d-flex flex-column align-items-center justify-content-center">
            <i t-attf-class="fa {{props.icon}}" role="img" />
            <h3 t-if="props.text" t-esc="props.text" class="w-75 mt-2 text-center"/>
        </div>
    `;}
return __exports;});;

/* /point_of_sale/static/src/customer_display/customer_display.js */
odoo.define('@point_of_sale/customer_display/customer_display',['@odoo/owl','@point_of_sale/app/generic_components/odoo_logo/odoo_logo','@point_of_sale/app/generic_components/order_widget/order_widget','@point_of_sale/app/generic_components/orderline/orderline','@web/core/main_components_container','@web/session','@web/core/utils/hooks','@web/env','@point_of_sale/customer_display/customer_facing_qr'],function(require){'use strict';let __exports={};const{Component,useEffect,useState,whenReady}=require("@odoo/owl");const{OdooLogo}=require("@point_of_sale/app/generic_components/odoo_logo/odoo_logo");const{OrderWidget}=require("@point_of_sale/app/generic_components/order_widget/order_widget");const{Orderline}=require("@point_of_sale/app/generic_components/orderline/orderline");const{MainComponentsContainer}=require("@web/core/main_components_container");const{session}=require("@web/session");const{useService}=require("@web/core/utils/hooks");const{mountComponent}=require("@web/env");const{CustomerFacingQR}=require("@point_of_sale/customer_display/customer_facing_qr");function useSingleDialog(){let close=null;const dialog=useService("dialog");return{open(dialogClass,props){if(!close){close=dialog.add(dialogClass,props,{onClose:()=>{close=null;},});}},close(){close?.();},};}
const CustomerDisplay=__exports.CustomerDisplay=class CustomerDisplay extends Component{static template="point_of_sale.CustomerDisplay";static components={OdooLogo,OrderWidget,Orderline,MainComponentsContainer};static props=[];setup(){this.session=session;this.dialog=useService("dialog");this.order=useState(useService("customer_display_data"));const singleDialog=useSingleDialog();useEffect((qrPaymentData)=>{if(qrPaymentData){singleDialog.open(CustomerFacingQR,qrPaymentData);}else{singleDialog.close();}},()=>[this.order.qrPaymentData]);}}
whenReady(()=>mountComponent(CustomerDisplay,document.body));return __exports;});;

/* /point_of_sale/static/src/customer_display/customer_display_data_service.js */
odoo.define('@point_of_sale/customer_display/customer_display_data_service',['@odoo/owl','@point_of_sale/utils','@web/core/registry','@web/session','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{reactive}=require("@odoo/owl");const{getOnNotified}=require("@point_of_sale/utils");const{registry}=require("@web/core/registry");const{session}=require("@web/session");const{_t}=require("@web/core/l10n/translation");const CustomerDisplayDataService=__exports.CustomerDisplayDataService={dependencies:["bus_service","notification"],async start(env,{bus_service,notification}){const data=reactive({});if(session.type==="local"){new BroadcastChannel("UPDATE_CUSTOMER_DISPLAY").onmessage=(event)=>{Object.assign(data,event.data);};}
if(session.type==="remote"){getOnNotified(bus_service,session.access_token)("UPDATE_CUSTOMER_DISPLAY",(payload)=>{Object.assign(data,payload);});}
if(session.proxy_ip){const intervalId=setInterval(async()=>{try{const response=await fetch(`http://localhost:8069/hw_proxy/customer_facing_display`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",},body:JSON.stringify({params:{action:"get",},}),});const payload=await response.json();Object.assign(data,payload.result.data);}catch(error){notification.add(_t("Make sure there is an IoT Box subscription associated with your Odoo database, then restart the IoT Box."),{title:_t("IoT Customer Display Error"),type:"danger",});console.error("Error fetching data for the IoT customer display: %s",error);clearInterval(intervalId);}},1000);}
return data;},};registry.category("services").add("customer_display_data",CustomerDisplayDataService);return __exports;});;

/* /point_of_sale/static/src/customer_display/customer_facing_qr.js */
odoo.define('@point_of_sale/customer_display/customer_facing_qr',['@odoo/owl','@web/core/dialog/dialog','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const{_t}=require("@web/core/l10n/translation");const CustomerFacingQR=__exports.CustomerFacingQR=class CustomerFacingQR extends Component{static template="point_of_sale.CustomerFacingQR";static components={Dialog};static props={qrCode:String,name:String,amount:String,close:Function,};setup(){this.title=_t("Please scan the QR code with %s",this.props.name);}}
return __exports;});;

/* /point_of_sale/static/src/customer_display/utils.js */
odoo.define('@point_of_sale/customer_display/utils',['@point_of_sale/utils','@web/core/l10n/translation'],function(require){'use strict';let __exports={};const{deduceUrl}=require("@point_of_sale/utils");const{_t}=require("@web/core/l10n/translation");__exports.openCustomerDisplay=openCustomerDisplay;function openCustomerDisplay(displayDeviceIp,accessToken,configId,notificationService=undefined){if(!displayDeviceIp){return;}
notificationService?.add(_t("Connecting to the IoT Box"));fetch(`${deduceUrl(displayDeviceIp)}/hw_proxy/customer_facing_display`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",},body:JSON.stringify({params:{action:"open",access_token:accessToken,pos_id:configId,},}),}).then(()=>{notificationService?.add(_t("Connection successful"),{type:"success"});}).catch(()=>{notificationService?.add(_t("Connection failed"),{type:"danger"});});}
return __exports;});;

/* /pos_online_payment/static/src/app/online_payment_popup/online_payment_popup.js */
odoo.define('@pos_online_payment/app/online_payment_popup/online_payment_popup',['@odoo/owl','@web/core/dialog/dialog'],function(require){'use strict';let __exports={};const{Component}=require("@odoo/owl");const{Dialog}=require("@web/core/dialog/dialog");const OnlinePaymentPopup=__exports.OnlinePaymentPopup=class OnlinePaymentPopup extends Component{static template="pos_online_payment.OnlinePaymentPopup";static components={Dialog};static props={qrCode:String,formattedAmount:String,orderName:String,close:Function,};}
return __exports;});;

/* /pos_online_payment/static/src/overrides/customer_display_overrides/customer_display.js */
odoo.define('@pos_online_payment/overrides/customer_display_overrides/customer_display',['@web/core/utils/patch','@web/core/utils/hooks','@pos_online_payment/app/online_payment_popup/online_payment_popup','@odoo/owl','@point_of_sale/customer_display/customer_display'],function(require){'use strict';let __exports={};const{patch}=require("@web/core/utils/patch");const{useService}=require("@web/core/utils/hooks");const{OnlinePaymentPopup}=require("@pos_online_payment/app/online_payment_popup/online_payment_popup");const{useEffect}=require("@odoo/owl");const{CustomerDisplay}=require("@point_of_sale/customer_display/customer_display");patch(CustomerDisplay.prototype,{setup(){super.setup(...arguments);this.dialog=useService("dialog");useEffect((details)=>{if(!details?.formattedAmount){this.qrCodePopupCloser?.();return;}
if(this.qrCodePopupCloser){return;}
this.qrCodePopupCloser=this.dialog.add(OnlinePaymentPopup,details,{onClose:()=>{this.qrCodePopupCloser=null;},});},()=>[this.order.onlinePaymentData]);},});return __exports;});

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

                    odoo.define("point_of_sale.customer_display_assets.bundle.xml", ["@web/core/templates"], function(require) {
                        "use strict";
                        const { checkPrimaryTemplateParents, registerTemplate, registerTemplateExtension } = require("@web/core/templates");
                        /* point_of_sale.customer_display_assets */
                        registerTemplate("web.ActionSwiper", `/web/static/src/core/action_swiper/action_swiper.xml`, `<t t-name="web.ActionSwiper" xml:space="preserve">
        <t t-if="props.onRightSwipe || props.onLeftSwipe">
            <div class="o_actionswiper" t-on-touchend="_onTouchEndSwipe" t-on-touchmove="_onTouchMoveSwipe" t-on-touchstart="_onTouchStartSwipe" t-ref="root">
                <div class="o_actionswiper_overflow_container position-relative overflow-hidden">
                    <div class="o_actionswiper_target_container" t-ref="targetContainer" t-att-style="state.containerStyle" t-att-class="{ o_actionswiper_swiping: state.isSwiping }">
                        <t t-slot="default"/>
                        <t t-if="localizedProps.onRightSwipe and (localizedProps.onRightSwipe.icon or localizedProps.onRightSwipe.bgColor)">
                            <div t-att-style="'max-width: ' + swipedDistance + 'px;'" class="o_actionswiper_right_swipe_area position-absolute overflow-hidden w-100 h-100 d-flex align-items-center justify-content-center rounded-end" t-att-class="localizedProps.onRightSwipe.bgColor">
                                <span><i class="fa fa-2x" t-att-class="localizedProps.onRightSwipe.icon"/></span>
                            </div>
                        </t>
                        <t t-if="localizedProps.onLeftSwipe and (localizedProps.onLeftSwipe.icon or localizedProps.onLeftSwipe.bgColor)">
                            <div t-att-style="'max-width: ' + -swipedDistance + 'px;'" class="o_actionswiper_left_swipe_area position-absolute overflow-hidden w-100 h-100 d-flex align-items-center justify-content-center rounded-start" t-att-class="localizedProps.onLeftSwipe.bgColor">
                                <span><i class="fa fa-2x" t-att-class="localizedProps.onLeftSwipe.icon"/></span>
                            </div>
                        </t>
                    </div>
                </div>
            </div>
        </t>
        <t t-else="">
            <t t-slot="default"/>
        </t>
    </t>
`);
registerTemplate("web.AutoComplete", `/web/static/src/core/autocomplete/autocomplete.xml`, `<t t-name="web.AutoComplete" xml:space="preserve">
        <div class="o-autocomplete" t-ref="root" t-att-class="autoCompleteRootClass">
            <input type="text" t-att-id="props.id" class="o-autocomplete--input o_input pe-3" autocomplete="off" t-att-placeholder="props.placeholder" role="combobox" t-att-aria-activedescendant="activeSourceOptionId" t-att-aria-expanded="displayOptions ? 'true' : 'false'" aria-autocomplete="list" aria-haspopup="listbox" t-model="state.value" t-on-blur="onInputBlur" t-on-click="onInputClick" t-on-change="onInputChange" t-on-input="onInput" t-on-keydown="onInputKeydown" t-on-focus="onInputFocus" t-ref="input"/>
            <t t-if="displayOptions">
                <ul role="menu" class="o-autocomplete--dropdown-menu ui-widget show" t-att-class="ulDropdownClass" t-ref="sourcesList">
                    <t t-foreach="sources" t-as="source" t-key="source.id">
                        <t t-if="source.isLoading">
                            <li class="ui-menu-item" t-att-class="{                                     'o-autocomplete--dropdown-item': props.dropdown,                                     'd-block': !props.dropdown                                 }">
                                <a t-attf-id="{{props.id or 'autocomplete'}}_{{source_index}}_loading" role="option" href="#" class="o_loading dropdown-item ui-menu-item-wrapper" aria-selected="true">
                                    <i class="fa fa-spin fa-circle-o-notch"/> <t t-esc="source.placeholder"/>
                                </a>
                            </li>
                        </t>
                        <t t-else="">
                            <t t-foreach="source.options" t-as="option" t-key="option.id">
                                <li class="o-autocomplete--dropdown-item ui-menu-item d-block" t-att-class="option.classList" t-on-mouseenter="() =&gt; this.onOptionMouseEnter([source_index, option_index])" t-on-mouseleave="() =&gt; this.onOptionMouseLeave([source_index, option_index])" t-on-click="() =&gt; this.onOptionClick(option)" t-on-pointerdown="() =&gt; this.ignoreBlur = true">
                                    <a t-attf-id="{{props.id or 'autocomplete'}}_{{source_index}}_{{option_index}}" role="option" href="#" class="dropdown-item ui-menu-item-wrapper text-truncate" t-att-class="{ 'ui-state-active': isActiveSourceOption([source_index, option_index]) }" t-att-aria-selected="isActiveSourceOption([source_index, option_index]) ? 'true' : 'false'">
                                        <t t-if="source.optionTemplate">
                                            <t t-call="{{ source.optionTemplate }}"/>
                                        </t>
                                        <t t-else="">
                                            <t t-esc="option.label"/>
                                        </t>
                                    </a>
                                </li>
                            </t>
                        </t>
                    </t>
                </ul>
            </t>
        </div>
    </t>

`);
registerTemplate("web.BarcodeDialog", `/web/static/src/core/barcode/barcode_dialog.xml`, `<t t-name="web.BarcodeDialog" xml:space="preserve">
        <Dialog title.translate="Barcode Scanner" fullscreen="true" footer="false" contentClass="'o-barcode-modal'">
            <BarcodeVideoScanner t-if="state.barcodeScannerSupported" t-props="props" onError.bind="onError" onResult.bind="onResult"/>
            <div t-else="" t-ref="videoPreview" class="h-100 d-flex flex-column justify-content-center align-items-center gap-1">
                <i class="fa fa-2x fa-camera text-muted"/>
                <strong>Unable to access camera</strong>
                <span class="text-muted" t-out="state.errorMessage"/>
            </div>
        </Dialog>
    </t>
`);
registerTemplate("web.BarcodeVideoScanner", `/web/static/src/core/barcode/barcode_video_scanner.xml`, `<t t-name="web.BarcodeVideoScanner" xml:space="preserve">
        <CropOverlay onResize.bind="this.onResize" isReady="state.isReady">
            <video t-ref="videoPreview" muted="true" autoplay="true" playsinline="true" t-att-class="props.cssClass"/>
        </CropOverlay>
    </t>
`);
registerTemplate("web.CropOverlay", `/web/static/src/core/barcode/crop_overlay.xml`, `<t t-name="web.CropOverlay" xml:space="preserve">
        <div t-ref="crop-container" t-on-mousedown="pointerDown" t-on-touchstart="pointerDown" t-on-mousemove="pointerMove" t-on-touchmove="pointerMove" t-on-mouseup="pointerUp" t-on-touchend="pointerUp" class="d-grid align-content-center justify-content-center h-100 o_crop_container">
            <t t-slot="default"/>
            <t t-if="props.isReady">
                <div class="o_crop_overlay" t-att-class="{'o_crop_overlay_ios': isIOS}"/>
                <img class="o_crop_icon" src="/web/static/img/transform.svg" draggable="false"/>
            </t>
        </div>
    </t>
`);
registerTemplate("web.CheckBox", `/web/static/src/core/checkbox/checkbox.xml`, `<t t-name="web.CheckBox" xml:space="preserve">
    <div class="o-checkbox form-check" t-attf-class="{{ props.slots ? 'form-check' : '' }}" t-att-class="props.className" t-on-click="onClick" t-ref="root">
        <input t-att-id="props.id or id" type="checkbox" class="form-check-input" t-att-disabled="props.disabled" t-att-checked="props.value" t-att-name="props.name" t-on-change="onChange"/>
        <label t-att-for="props.id or id" class="form-check-label">
            <t t-slot="default"/>
        </label>
    </div>
</t>

`);
registerTemplate("web.CodeEditor", `/web/static/src/core/code_editor/code_editor.xml`, `<t t-name="web.CodeEditor" xml:space="preserve">
        <div t-ref="editorRef" class="w-100" t-att-class="props.class" t-att-data-mode="state.activeMode"/>
    </t>

`);
registerTemplate("web.ColorList", `/web/static/src/core/colorlist/colorlist.xml`, `<t t-name="web.ColorList" xml:space="preserve">
        <div class="o_colorlist d-flex flex-wrap align-items-center mw-100 gap-2" aria-atomic="true" t-ref="colorlist">
            <t t-if="!props.forceExpanded and !state.isExpanded">
                <button t-on-click="onToggle" role="menuitem" t-att-title="colors[props.selectedColor]" t-att-data-color="props.selectedColor" t-att-aria-label="colors[props.selectedColor]" t-attf-class="btn p-0 rounded-0 o_colorlist_toggler o_colorlist_item_color_{{ props.selectedColor }}"/>
            </t>
            <t t-else="" t-foreach="props.colors" t-as="colorId" t-key="colorId">
                <button t-on-click.prevent.stop="() =&gt; this.onColorSelected(colorId)" role="menuitem" t-att-title="colors[colorId]" t-att-data-color="colorId" t-att-aria-label="colors[colorId]" t-attf-class="btn p-0 rounded-0 o_colorlist_item_color_{{ colorId }} {{ colorId === props.selectedColor ? 'o_colorlist_selected' : '' }}"/>
            </t>
        </div>
    </t>

`);
registerTemplate("web.Colorpicker", `/web/static/src/core/colorpicker/colorpicker.xml`, `<t t-name="web.Colorpicker" xml:space="preserve">
    <div class="o_colorpicker_widget" t-ref="el" t-on-click="onClick" t-on-keydown="onKeydown">
        <div class="d-flex justify-content-between align-items-stretch mb-2">
            <div t-ref="colorPickerArea" class="o_color_pick_area position-relative w-75" t-att-style="props.noTransparency ? 'width: 89%;' : None" t-on-mousedown="onMouseDownPicker">
                <div t-ref="colorPickerPointer" class="o_picker_pointer rounded-circle p-1 position-absolute" tabindex="-1"/>
            </div>
            <div t-ref="colorSlider" class="o_color_slider position-relative" t-on-mousedown="onMouseDownSlider">
                <div t-ref="colorSliderPointer" class="o_slider_pointer" tabindex="-1"/>
            </div>
            <div t-ref="opacitySlider" class="o_opacity_slider position-relative" t-if="!props.noTransparency" t-on-mousedown="onMouseDownOpacitySlider">
                <div t-ref="opacitySliderPointer" class="o_opacity_pointer" tabindex="-1"/>
            </div>
        </div>
        <div class="o_color_picker_inputs d-flex justify-content-between mb-2" t-on-change="debouncedOnChangeInputs">
            <t t-set="input_classes" t-value="'p-0 border-0 text-center font-monospace bg-transparent'"/>

            <div class="o_hex_div px-1 d-flex align-items-baseline">
                <input type="text" t-attf-class="o_hex_input {{input_classes}}" data-color-method="hex" size="1" t-on-input="onHexColorInput"/>
                <label class="flex-grow-0 ms-1 mb-0">hex</label>
            </div>
            <div class="o_rgba_div px-1 d-flex align-items-baseline">
                <input type="text" t-attf-class="o_red_input {{input_classes}}" data-color-method="rgb" size="1"/>
                <input type="text" t-attf-class="o_green_input {{input_classes}}" data-color-method="rgb" size="1"/>
                <input type="text" t-attf-class="o_blue_input {{input_classes}}" data-color-method="rgb" size="1"/>
                <t t-if="!props.noTransparency">
                    <input type="text" t-attf-class="o_opacity_input {{input_classes}}" data-color-method="opacity" size="1"/>
                    <label class="flex-grow-0 ms-1 mb-0">
                        RGBA
                    </label>
                </t>
                <label t-else="" class="flex-grow-0 ms-1 mb-0">
                    RGB
                </label>
            </div>
        </div>
    </div>
</t>

`);
registerTemplate("web.DefaultFooter", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.DefaultFooter" owl="1" xml:space="preserve">
    <span>
      <span class="fw-bolder text-primary">TIP</span> — search for
      <t t-foreach="elements" t-as="element" t-key="element.namespace">
          <t t-if="!(element_first || element_last)">, </t>
          <t t-if="element_last and !element_first"> and </t>
          <span class="o_namespace btn-link text-primary cursor-pointer" t-on-click="() =&gt; this.onClick(element.namespace)">
              <span t-out="element.namespace" class="fw-bolder text-primary"/><t t-out="element.name"/>
          </span>
      </t>
    </span>
  </t>

  `);
registerTemplate("web.DefaultCommandItem", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.DefaultCommandItem" xml:space="preserve">
    <div class="o_command_default d-flex align-items-center justify-content-between px-4 py-2 cursor-pointer">
      <t t-slot="name"/>
      <t t-slot="focusMessage"/>
    </div>
  </t>

  `);
registerTemplate("web.HotkeyCommandItem", `/web/static/src/core/commands/command_items.xml`, `<t t-name="web.HotkeyCommandItem" xml:space="preserve">
    <div class="o_command_hotkey d-flex align-items-center justify-content-between px-4 py-2 cursor-pointer">
      <t t-slot="name"/>
      <span>
        <t t-foreach="getKeysToPress(props)" t-as="key" t-key="key_index">
          <kbd t-out="key" class="d-inline-block px-3 py-1"/>
          <span t-if="!key_last"> + </span>
        </t>
      </span>
    </div>
  </t>

`);
registerTemplate("web.CommandPalette", `/web/static/src/core/commands/command_palette.xml`, `<t t-name="web.CommandPalette" xml:space="preserve">
    <Dialog header="false" footer="false" size="'md'" contentClass="'o_command_palette'">
      <div t-ref="root">
        <div class="o_command_palette_search input-group mb-2 px-4 py-3 border-bottom">
          <span t-if="state.namespace !== 'default'" class="o_namespace d-flex align-items-center me-1" t-out="state.namespace"/>
          <input class="form-control border-0 p-0" type="text" data-allow-hotkeys="true" t-att-value="state.searchValue" t-ref="autofocus" t-att-placeholder="state.placeholder" t-on-input="onSearchInput" t-on-keydown="onKeyDown" role="combobox" t-attf-aria-activedescendant="o_command_{{state.commands.length ? state.commands.indexOf(state.selectedCommand) : 'empty'}}" aria-expanded="true" aria-autocomplete="list" aria-haspopup="listbox"/>
          <div class="input-group-text border-0 bg-transparent">
              <i t-if="state.isLoading" title="Loading..." role="img" aria-label="Loading..." class="fa fa-spinner fa-spin"/>
              <i t-else="" t-att-title="state.placeholder" role="img" t-att-aria-label="state.placeholder" class="oi oi-search"/>
          </div>
        </div>

        <div t-ref="listbox" role="listbox" class="o_command_palette_listbox position-relative overflow-auto">
          <div t-if="!state.commands.length" id="o_command_empty" role="option" aria-selected="true" class="o_command_palette_listbox_empty px-4 py-3 fst-italic" t-out="state.emptyMessage"/>
          <t t-if="!isFuzzySearch" t-foreach="commandsByCategory" t-as="category" t-key="category.keyId">
            <div class="o_command_category px-0">
              <span t-if="category.name" class="text-truncate text-uppercase fw-bold fs-6 px-3" t-out="category.name"/>
              <t t-foreach="category.commands" t-as="command" t-key="command.keyId">
                <t t-set="commandIndex" t-value="state.commands.indexOf(command)"/>
                <div t-attf-id="o_command_{{commandIndex}}" class="o_command" role="option" t-att-aria-selected="state.selectedCommand === command ? 'true' : 'false'" t-att-class="{ focused: state.selectedCommand === command }" t-on-click="(event) =&gt; this.onCommandClicked(event, commandIndex)" t-on-mouseenter="() =&gt; this.onCommandMouseEnter(commandIndex)" t-on-close="() =&gt; this.props.closeMe()">
                  <a t-att-href="command.href">
                    <t t-component="command.Component || DefaultCommandItem" name="command.name" searchValue="state.searchValue" t-props="command.props" executeCommand="() =&gt; this.executeCommand(command)">
                      <t t-set-slot="name">
                        <span class="o_command_name text-ellipsis" t-att-title="command.name">
                          <t t-foreach="command.splitName" t-as="name" t-key="name_index">
                            <b t-if="name_index % 2" t-out="name" class="text-primary"/>
                            <t t-else="" t-out="name"/>
                          </t>
                        </span>
                      </t>
                      <t t-set-slot="focusMessage">
                          <small t-if="!isMobileOS and command.href and state.selectedCommand === command" class="o_command_focus text-muted"><kbd><t t-if="isMacOS">CMD</t><t t-else="">CTRL</t></kbd>+<kbd>⏎</kbd><span class="ms-1">new tab</span></small>
                      </t>
                    </t>
                  </a>
                </div>
              </t>
            </div>

            <hr class="my-2 mx-0" t-if="!category_last"/>
          </t>
        </div>

        <div t-if="state.FooterComponent" class="o_command_palette_footer mt-2 px-4 py-2 border-top rounded-bottom bg-100 text-muted">
          <t t-component="state.FooterComponent" switchNamespace="(namespace) =&gt; this.debounceSearch(namespace.concat(this.state.searchValue))"/>
        </div>
      </div>
    </Dialog>
  </t>

`);
registerTemplate("web.ConfirmationDialog", `/web/static/src/core/confirmation_dialog/confirmation_dialog.xml`, `<t t-name="web.ConfirmationDialog" xml:space="preserve">
    <Dialog size="'md'" title="props.title" modalRef="modalRef">
      <p t-out="props.body" class="text-prewrap"/>
      <t t-set-slot="footer">
        <button class="btn" t-att-class="props.confirmClass" t-on-click="_confirm" t-esc="props.confirmLabel"/>
        <button t-if="props.cancel" class="btn btn-secondary" t-on-click="_cancel" t-esc="props.cancelLabel"/>
      </t>
    </Dialog>
  </t>

  `);
registerTemplate("web.AlertDialog", `/web/static/src/core/confirmation_dialog/confirmation_dialog.xml`, `<t t-name="web.AlertDialog" xml:space="preserve">
    <Dialog size="'sm'" title="props.title" contentClass="props.contentClass">
      <p t-out="props.body" class="text-prewrap"/>
      <t t-set-slot="footer">
        <button class="btn" t-att-class="props.confirmClass" t-on-click="_confirm" t-esc="props.confirmLabel"/>
        <button t-if="props.cancel" class="btn btn-secondary" t-on-click="_cancel" t-esc="props.cancelLabel"/>
      </t>
    </Dialog>
  </t>

`);
registerTemplate("web.CopyButton", `/web/static/src/core/copy_button/copy_button.xml`, `<t t-name="web.CopyButton" xml:space="preserve">
        <button class="text-nowrap" t-ref="button" t-att-disabled="props.disabled" t-attf-class="btn o_clipboard_button {{ props.className || '' }}" t-on-click.stop="onClick">
            <span class="mx-1" t-attf-class="fa {{ props.icon || 'fa-clipboard' }}"/>
            <span t-if="props.copyText" t-esc="props.copyText"/>
        </button>
    </t>

`);
registerTemplate("web.DateTimeInput", `/web/static/src/core/datetime/datetime_input.xml`, `<t t-name="web.DateTimeInput" xml:space="preserve">
        <input type="text" t-ref="start-date" t-att-id="props.id" class="o_datetime_input o_input cursor-pointer" autocomplete="off" t-att-placeholder="props.placeholder"/>
    </t>
`);
registerTemplate("web.DateTimePicker.Days", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker.Days" xml:space="preserve">
        <div class="d-flex gap-3">
            <t t-foreach="items" t-as="month" t-key="month.id">
                <div class="o_date_picker d-grid flex-grow-1 bg-view rounded overflow-auto" t-on-pointerleave="() =&gt; (state.hoveredDate = null)">
                    <t t-foreach="month.daysOfWeek" t-as="dayOfWeek" t-key="dayOfWeek[0]">
                        <div class="o_day_of_week_cell o_text_sm o_cell_md fw-bolder bg-100 border-bottom border-2 d-flex align-items-center justify-content-center" t-att-title="dayOfWeek[1]">
                            <div class="text-nowrap overflow-hidden" t-esc="props.daysOfWeekFormat === 'narrow' ? dayOfWeek[2] : dayOfWeek[0]"/>
                        </div>
                    </t>
                    <t t-foreach="month.weeks" t-as="week" t-key="week.number">
                        <t t-if="props.showWeekNumbers ?? !props.range">
                            <div class="o_week_number_cell o_center o_cell_md o_text_sm bg-100 fw-bolder" t-att-class="{ 'border-bottom': !week_last }" t-esc="week.number"/>
                        </t>
                        <t t-foreach="week.days" t-as="itemInfo" t-key="itemInfo.id">
                            <t t-set="arInfo" t-value="getActiveRangeInfo(itemInfo)"/>
                            <t t-if="itemInfo.isOutOfRange">
                                <div class="o_date_item_cell o_out_of_range o_cell_md"/>
                            </t>
                            <t t-else="">
                                <button class="o_date_item_cell o_datetime_button o_center o_cell_md btn p-1 border-0 fw-normal" tabindex="-1" t-att-class="{                                         'o_selected': arInfo.isSelected,                                         o_select_start: arInfo.isSelectStart,                                         o_select_end: arInfo.isSelectEnd,                                         o_highlighted: arInfo.isHighlighted,                                         o_current: arInfo.isCurrent,                                         o_today: itemInfo.includesToday,                                         [itemInfo.extraClass]: true,                                     }" t-att-disabled="!itemInfo.isValid" t-on-pointerenter="() =&gt; (state.hoveredDate = itemInfo.range[0])" t-on-click="() =&gt; this.zoomOrSelect(itemInfo)">
                                    <span t-esc="itemInfo.label" class="z-1"/>
                                </button>
                            </t>
                        </t>
                    </t>
                </div>
            </t>
        </div>
        <div t-attf-class="position-relative d-flex flex-column flex-md-row gap-4 gap-md-3 {{ props.type === 'datetime' ? 'justify-content-center' : 'justify-content-end' }}">
            <div t-attf-class="d-flex gap-3 w-100 {{ props.type === 'datetime' ? 'justify-content-center' : 'd-none' }}">
                <t t-if="props.type === 'datetime'">
                    <t t-foreach="state.timeValues" t-as="timeValue" t-key="timeValue_index">
                        <div t-if="timeValue" class="o_time_picker d-flex align-items-center justify-content-center w-lg-50 w-100 gap-1">
                            <t t-call="web.DateTimePicker.Select">
                                <t t-set="unitIndex" t-value="0"/>
                                <t t-set="unitList" t-value="availableHours"/>
                            </t>
                            <span>:</span>
                            <t t-call="web.DateTimePicker.Select">
                                <t t-set="unitIndex" t-value="1"/>
                                <t t-set="unitList" t-value="availableMinutes"/>
                            </t>
                            <t t-if="availableSeconds.length">
                                <span>:</span>
                                <t t-call="web.DateTimePicker.Select">
                                    <t t-set="unitIndex" t-value="2"/>
                                    <t t-set="unitList" t-value="availableSeconds"/>
                                </t>
                            </t>
                            <t t-if="meridiems">
                                <t t-call="web.DateTimePicker.Select">
                                    <t t-set="unitIndex" t-value="3"/>
                                    <t t-set="unitList" t-value="meridiems"/>
                                </t>
                            </t>
                        </div>
                    </t>
                </t>
            </div>

            <div t-attf-class="o_datetime_buttons {{ props.type === 'datetime' ? 'position-md-absolute h-100 start-0' : '' }}">
                <t t-slot="bottom_left"/>
            </div>
            <div t-attf-class="o_datetime_buttons {{ props.type === 'datetime' ? 'position-md-absolute h-100 end-0' : '' }}">
                <t t-slot="buttons"/>
            </div>
        </div>
    </t>

    `);
registerTemplate("web.DateTimePicker.Grid", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker.Grid" xml:space="preserve">
        <div class="o_date_item_picker d-grid">
            <t t-foreach="items" t-as="itemInfo" t-key="itemInfo.id">
                <t t-set="arInfo" t-value="getActiveRangeInfo(itemInfo)"/>
                <button class="o_date_item_cell o_datetime_button btn o_center o_cell_lg btn p-1 border-0" tabindex="-1" t-att-class="{                         o_selected: arInfo.isSelected,                         o_select_start: arInfo.isSelectStart,                         o_select_end: arInfo.isSelectEnd,                         o_highlighted: arInfo.isHighlighted,                         o_today: itemInfo.includesToday,                     }" t-att-disabled="!itemInfo.isValid" t-on-click="() =&gt; this.zoomOrSelect(itemInfo)">
                    <span t-esc="itemInfo.label" class="z-1"/>
                </button>
            </t>
        </div>
    </t>

    `);
registerTemplate("web.DateTimePicker.Select", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker.Select" xml:space="preserve">

        <select class="o_time_picker_select form-control form-control-sm w-auto" tabindex="-1" t-model="timeValue[unitIndex]" t-on-change="() =&gt; this.selectTime(timeValue_index)">
            <option t-if="unitIndex === 1 and !!(timeValue[unitIndex] % props.rounding)" class="text-center" value="" selected="true"/>
            <t t-foreach="unitList" t-as="unit" t-key="unit[0]">
                <option class="text-center" t-att-value="unit[0]" t-esc="unit[1]" t-att-selected="timeValue[unitIndex] === unit[0].toString()"/>
            </t>
        </select>
    </t>

    `);
registerTemplate("web.DateTimePicker", `/web/static/src/core/datetime/datetime_picker.xml`, `<t t-name="web.DateTimePicker" xml:space="preserve">
        <div class="o_datetime_picker d-flex flex-column gap-2 user-select-none p-2 p-lg-3" t-attf-style="--DateTimePicker__Day-template-columns: {{ props.showWeekNumbers ?? !props.range ? 8 : 7 }}">
            <nav class="o_datetime_picker_header btn-group">
                <button class="o_previous btn btn-light flex-grow-0" t-on-click="previous" tabindex="-1">
                    <i class="oi oi-chevron-left" t-att-title="activePrecisionLevel.prevTitle"/>
                </button>
                <button class="o_zoom_out o_datetime_button btn d-flex align-items-center px-0 text-truncate justify-content-around" tabindex="-1" t-att-class="{ 'btn-light': !isLastPrecisionLevel }" t-att-title="!isLastPrecisionLevel and activePrecisionLevel.mainTitle" t-on-click="zoomOut">
                    <t t-foreach="titles" t-as="title" t-key="title">
                        <strong t-attf-class="o_header_part fs-5 {{ props.range ? 'flex-basis-50' : 'flex-basis-100' }}" t-esc="title"/>
                    </t>
                </button>
                <button class="o_next btn btn-light flex-grow-0" t-on-click="next" tabindex="-1">
                    <i class="oi oi-chevron-right" t-att-title="activePrecisionLevel.nextTitle"/>
                </button>
            </nav>
            <t t-if="state.precision === 'days'">
                <t t-call="web.DateTimePicker.Days"/>
            </t>
            <t t-else="">
                <t t-call="web.DateTimePicker.Grid"/>
            </t>
        </div>
    </t>
`);
registerTemplate("web.DateTimePickerPopover", `/web/static/src/core/datetime/datetime_picker_popover.xml`, `<t t-name="web.DateTimePickerPopover" xml:space="preserve">
        <DateTimePicker t-props="props.pickerProps">
            <t t-set-slot="buttons">
                <t t-if="isDateTimeRange">
                    <button class="o_apply btn btn-primary btn-sm h-100 w-100 w-md-auto d-flex align-items-center justify-content-center gap-1" tabindex="-1" t-on-click="props.close">
                        <i class="fa fa-check"/>
                        <span>Apply</span>
                    </button>
                </t>
            </t>
            <t t-set-slot="bottom_left">
                <t t-if="isDateTimeRange">
                    <button class="btn btn-secondary btn-sm h-100 w-100 w-md-auto d-flex align-items-center justify-content-center" tabindex="-1" t-on-click="props.close">
                        <span>Close</span>
                    </button>
                </t>
            </t>
        </DateTimePicker>
    </t>
`);
registerTemplate("web.Dialog", `/web/static/src/core/dialog/dialog.xml`, `<t t-name="web.Dialog" xml:space="preserve">
        <div class="o_dialog" t-att-id="id" t-att-class="{ o_inactive_modal: !data.isActive }">
            <div role="dialog" class="modal d-block" tabindex="-1" t-att-class="{ o_technical_modal: props.technical, o_modal_full: isFullscreen, o_inactive_modal: !data.isActive }" t-ref="modalRef">
                <div class="modal-dialog modal-dialog-centered" t-attf-class="modal-{{props.size}}">
                    <div class="modal-content" t-att-class="props.contentClass" t-att-style="contentStyle">
                        <header t-if="props.header" class="modal-header">
                            <t t-slot="header" close="data.close" isFullscreen="isFullscreen">
                                <t t-call="web.Dialog.header">
                                    <t t-set="fullscreen" t-value="isFullscreen"/>
                                    <t t-set="onExpand" t-value="props.onExpand"/>
                                </t>
                            </t>
                        </header>
                        <main class="modal-body" t-attf-class="{{ props.bodyClass }} {{ !props.withBodyPadding ? 'p-0': '' }}">
                            <t t-slot="default" close="() =&gt; this.data.close()"/>
                        </main>
                        <footer t-if="props.footer" class="modal-footer justify-content-around justify-content-md-start flex-wrap gap-1 w-100">
                            <t t-slot="footer" close="() =&gt; this.data.close()">
                                <button class="btn btn-primary o-default-button" t-on-click="() =&gt; this.data.close()">
                                    <t>Ok</t>
                                </button>
                            </t>
                        </footer>
                    </div>
                </div>
            </div>
        </div>
    </t>

    `);
registerTemplate("web.Dialog.header", `/web/static/src/core/dialog/dialog.xml`, `<t t-name="web.Dialog.header" xml:space="preserve">
        <t t-if="fullscreen">
            <button class="btn oi oi-arrow-left" data-bs-dismiss="modal" aria-label="Close" t-on-click="dismiss"/>
        </t>
        <h4 class="modal-title text-break flex-grow-1" t-att-class="{ 'me-auto': fullscreen }">
            <t t-esc="props.title"/>
        </h4>
        <t t-if="onExpand">
            <button type="button" class="fa fa-expand btn o_expand_button" aria-label="Expand" tabindex="-1" t-on-click="onExpand"/>
        </t>
        <t t-if="!fullscreen">
            <button type="button" class="btn-close" aria-label="Close" tabindex="-1" t-on-click="dismiss"/>
        </t>
    </t>
`);
registerTemplate("web.DomainSelector", `/web/static/src/core/domain_selector/domain_selector.xml`, `<t t-name="web.DomainSelector" xml:space="preserve">
        <div class="o_domain_selector w-100" aria-atomic="true" t-att-class="props.className">
            <t t-if="tree">
                <TreeEditor resModel="props.resModel" tree="tree" update.bind="update" readonly="props.readonly" isDebugMode="props.isDebugMode" defaultConnector="props.defaultConnector" getDefaultCondition.bind="getDefaultCondition" getOperatorEditorInfo.bind="getOperatorEditorInfo" getDefaultOperator.bind="getDefaultOperator" getPathEditorInfo.bind="getPathEditorInfo">
                    <CheckBox t-if="showArchivedCheckbox" value="includeArchived" disabled="props.readonly" className="'form-switch'" onChange.bind="toggleIncludeArchived">
                        Include archived
                    </CheckBox>
                </TreeEditor>
            </t>
            <t t-else="">
                <div class="o_domain_selector_row d-flex align-items-center">
                    This domain is not supported.
                    <t t-if="!props.readonly">
                        <button class="btn btn-sm btn-primary ms-2" t-on-click="() =&gt; this.resetDomain()">Reset domain</button>
                    </t>
                </div>
            </t>
            <t t-if="props.isDebugMode and (!tree or !props.readonly)">
                <label class="o_domain_selector_debug_container d-block mt-3 border rounded p-3 bg-100 text-muted font-monospace">
                    <span class="small"># Code editor</span>
                    <textarea class="pt-2 border-0 bg-transparent text-body" type="text" t-att-readonly="props.readonly" spellcheck="false" t-att-value="props.domain" t-on-input="(ev) =&gt; this.onDomainInput(ev.target.value)" t-on-change="(ev) =&gt; this.onDomainChange(ev.target.value)"/>
                </label>
            </t>
        </div>
    </t>

`);
registerTemplate("web.DomainSelectorDialog", `/web/static/src/core/domain_selector_dialog/domain_selector_dialog.xml`, `<t t-name="web.DomainSelectorDialog" xml:space="preserve">
        <Dialog title="dialogTitle">
            <div t-if="props.text" class="mb-3" t-out="props.text"/>
            <DomainSelector t-props="domainSelectorProps"/>
            <t t-set-slot="footer">
                <t t-if="props.readonly">
                    <button class="btn btn-secondary" t-on-click="() =&gt; props.close()">Close</button>
                </t>
                <t t-else="">
                    <button class="btn btn-primary" t-att-disabled="disabled" t-on-click="onConfirm" t-ref="confirm"><t t-esc="confirmButtonText"/></button>
                    <button class="btn btn-secondary" t-on-click="onDiscard"><t t-esc="discardButtonText"/></button>
                </t>
            </t>
        </Dialog>
    </t>

`);
registerTemplate("web.AccordionItem", `/web/static/src/core/dropdown/accordion_item.xml`, `<t t-name="web.AccordionItem" xml:space="preserve">
        <div class="o_accordion position-relative">
            <button class="o_menu_item o_accordion_toggle dropdown-item o-navigable" tabindex="0" t-att-class="{'selected': props.selected, 'open': state.open}" t-attf-class="{{ props.class }}" t-att-aria-expanded="state.open ? 'true' : 'false'" t-esc="props.description" t-on-click="() =&gt; state.open = !state.open"/>
            <t t-if="state.open">
                <div class="o_accordion_values ms-4 border-start">
                    <t t-slot="default"/>
                </div>
            </t>
        </div>
    </t>

`);
registerTemplate("web.DropdownItem", `/web/static/src/core/dropdown/dropdown_item.xml`, `<t t-name="web.DropdownItem" xml:space="preserve">
    <t t-tag="props.attrs and props.attrs.href ? 'a' : 'span'" class="o-dropdown-item dropdown-item o-navigable" t-att-class="props.class" t-on-click.stop="onClick" t-on-mouseenter="() =&gt; this.dropdownControl.closeChildren()" role="menuitem" tabindex="0" t-att="props.attrs">
      <t t-slot="default"/>
    </t>
  </t>


  `);
registerTemplate("web.CheckboxItem", `/web/static/src/core/dropdown/dropdown_item.xml`, `<t t-name="web.CheckboxItem" t-inherit="web.DropdownItem" t-inherit-mode="primary" xml:space="preserve">
    <xpath expr="//t[@role='menuitem']" position="attributes">
      <attribute name="role">menuitemcheckbox</attribute>
      <attribute name="t-att-aria-checked">props.checked ? 'true' : 'false'</attribute>
    </xpath>
  </t>

`);
registerTemplate("web.Dropzone", `/web/static/src/core/dropzone/dropzone.xml`, `<t t-name="web.Dropzone" xml:space="preserve">
    <div class="o-Dropzone position-fixed align-items-center justify-content-center d-flex border-primary bg-100 text-primary opacity-75" t-att-class="{ 'o-dragging-inside': state.isDraggingInside }" t-attf-class="{{ props.extraClass }}" t-on-dragenter="() =&gt; state.isDraggingInside = true" t-on-dragleave="() =&gt; state.isDraggingInside = false" t-on-drop="props.onDrop" t-ref="root">
        <t t-slot="default">
            <h4>Drag Files Here <i class="fa fa-download"/></h4>
        </t>
    </div>
</t>

`);
registerTemplate("web.RainbowMan", `/web/static/src/core/effects/rainbow_man.xml`, `<t t-name="web.RainbowMan" xml:space="preserve">
        <div class="o_reward position-fixed top-0 start-0 w-100 h-100" t-att-class="{ o_reward_fading: state.isFading }" t-on-animationend="onAnimationEnd">
            <svg class="o_reward_rainbow_man position-absolute top-0 bottom-0 start-0 end-0 m-auto overflow-visible" viewBox="0 0 400 400">
                <defs>
                    <radialGradient id="o_reward_gradient_bg" cx="200" cy="200" r="200" gradientUnits="userSpaceOnUse">
                        <stop offset="0.3" stop-color="#edeff4"/>
                        <stop offset="1" stop-color="#edeff4" stop-opacity="0"/>
                    </radialGradient>
                    <symbol id="o_reward_star">
                        <path d="M33 15.9C26.3558 13.6951 21.1575 8.4597 19 1.8 19 1.2477 18.5523.8 18 .8 17.4477.8 17 1.2477 17 1.8 14.6431 8.6938 9.0262 13.9736 2 15.9 1.3649 15.9.85 16.4149.85 17.05.85 17.6851 1.3649 18.2 2 18.2 8.6215 20.3845 13.8155 25.5785 16 32.2 16 32.7523 16.4477 33.2 17 33.2 17.5523 33.2 18 32.7523 18 32.2 20.3569 25.3062 25.9738 20.0264 33 18.1 33.6351 18.1 34.15 17.5851 34.15 16.95 34.15 16.3149 33.6351 15.8 33 15.8" fill="#FFFFFF"/>
                    </symbol>
                    <symbol id="o_reward_thumb">
                        <path d="M10 52C6 51 3 48 3 44 2 42 3 39 5 38 3 36 2 34 2 32 2 29 3 27 5 26 3 24 2 21 2 19 2 15 7 12 10 12L23 12C23 11 23 11 23 11L23 10C23 8 24 6 25 4 27 2 29 2 31 2 33 2 35 2 36 4 38 5 39 7 39 10L39 38C39 41 37 45 35 47 32 50 28 51 25 52L10 52 10 52Z" fill="#FBFBFC"/>
                        <polygon fill="#ECF1FF" points="25 11 25 51 5 52 5 12"/>
                        <path d="M31 0C28 0 26 1 24 3 22 5 21 7 21 10L10 10C8 10 6 11 4 12 2 14 1 16 1 19 1 21 1 24 2 26 1 27 1 29 1 32 1 34 1 36 2 38 1 40 0 42 1 45 1 50 5 53 10 54L25 54C29 54 33 52 36 49 39 46 41 42 41 38L41 10C41 4 36 0 31 0M31 4C34 4 37 6 37 10L37 38C37 41 35 44 33 46 31 48 28 49 25 50L10 50C7 49 5 47 5 44 4 41 6 38 9 37L9 37C6 37 5 35 5 32 5 28 6 26 9 26L9 26C6 26 5 22 5 19 5 16 8 14 11 14L23 14C24 14 25 12 25 11L25 10C25 7 28 4 31 4" fill="#A1ACBA"/>
                    </symbol>
                </defs>
                <rect width="400" height="400" fill="url(#o_reward_gradient_bg)"/>
                <g transform="translate(47 45) scale(0.9)" class="o_reward_rainbow">
                    <path d="M270,170a100,100,0,0,0-200,0" class="o_reward_rainbow_line" stroke="#FF9E80" stroke-linecap="round" stroke-width="21" fill="none" stroke-dasharray="600 600" stroke-dashoffset="-600"/>
                    <path d="M290,170a120,120,0,0,0-240,0" class="o_reward_rainbow_line" stroke="#FFE57F" stroke-linecap="round" stroke-width="21" fill="none" stroke-dasharray="600 600" stroke-dashoffset="-600"/>
                    <path d="M310,170a140,140,0,0,0-280,0" class="o_reward_rainbow_line" stroke="#80D8FF" stroke-linecap="round" stroke-width="21" fill="none" stroke-dasharray="600 600" stroke-dashoffset="-600"/>
                    <path d="M330,170a160,160,0,0,0-320,0" class="o_reward_rainbow_line" stroke="#C794BA" stroke-linecap="round" stroke-width="21" fill="none" stroke-dasharray="600 600" stroke-dashoffset="-600"/>
                </g>
                <g transform="translate(80 125)">
                    <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_01"/>
                </g>
                <g transform="translate(140 75)">
                    <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_02"/>
                </g>
                <g transform="translate(230 90)">
                    <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_03"/>
                </g>
                <g transform="translate(275 120)">
                    <use href="#o_reward_star" transform-origin="center" class="o_reward_box o_reward_star_04"/>
                </g>
                <g class="o_reward_face_group o_reward_box" transform-origin="center top">
                    <g class="o_reward_shadow_container o_reward_box">
                        <ellipse class="o_reward_shadow o_reward_box" cx="200" cy="105%" rx="100" ry="6" fill="#000" opacity="0.25" transform-origin="center"/>
                    </g>
                    <g class="o_reward_face_wrap o_reward_box" transform-origin="center">
                        <image class="o_reward_face" x="132" y="125" width="136" height="136" t-attf-href="{{props.imgUrl}}"/>
                    </g>
                    <g transform="translate(258 174)">
                        <use href="#o_reward_thumb" class="o_reward_box o_reward_thumbup" transform-origin="center"/>
                    </g>
                </g>
            </svg>
            <div class="o_reward_rainbow_man o_reward_msg_container position-absolute top-0 bottom-0 start-0 end-0 m-auto">
                <div class="o_reward_face_group h-100 w-75 mx-auto">
                    <svg viewBox="0 0 42 60" preserveAspectRatio="xMinYMax meet" width="37" height="65%" class="overflow-visible position-relative ms-5">
                        <g class="o_reward_box">
                            <use href="#o_reward_thumb" x="-60%" y="0" transform="rotate(-90) scale(1 -1)" transform-origin="center"/>
                        </g>
                    </svg>
                    <div class="o_reward_msg mx-4">
                        <div class="o_reward_msg_card">
                            <div class="o_reward_msg_content text-muted px-3 py-4 bg-view d-inline-block border border-light border-top-0">
                                <t t-if="!props.Component">
                                    <t t-out="props.message"/>
                                </t>
                                <t t-else="" t-component="props.Component" t-props="props.props"/>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </t>
`);
registerTemplate("web.EmojiPicker", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker" xml:space="preserve">
    <div class="o-EmojiPicker d-flex flex-column justify-content-center rounded-3 bg-100" t-att-class="{ 'align-items-center': emojis.length === 0 }" t-on-click="onClick" t-on-keydown="onKeydown">
        <t t-if="emojis.length === 0">
            <span class="o-EmojiPicker-empty">😵‍💫</span>
            <span class="fs-5 text-muted">Failed to load emojis...</span>
        </t>
        <t t-else="">
            <div class="o-EmojiPicker-search d-flex align-items-center mx-2 mt-2 rounded">
                <span class="d-flex mx-1 w-100 rounded o-active align-items-center justify-content-center border border-secondary bg-white">
                    <t t-call="web.EmojiPicker.searchInput">
                        <t t-if="props.state" t-set="localState" t-value="props.state"/>
                        <t t-else="" t-set="localState" t-value="state"/>
                    </t>
                    <i class="oi oi-search px-2 py-1 fs-7 rounded-start-0 rounded-3 o-active opacity-50" title="Search..." role="img" aria-label="Search..."/>
                </span>
            </div>
            <t t-set="itemIndex" t-value="0"/>
            <t t-set="emojisFromSearch" t-value="getEmojisFromSearch()"/>
            <div class="o-EmojiPicker-content overflow-auto d-flex flex-grow-1 w-100 flex-wrap align-items-center user-select-none mt-1" t-att-class="emojisFromSearch.length === 0 ? 'flex-column justify-content-center' : 'align-content-start'" t-ref="emoji-grid" t-on-scroll="highlightActiveCategory">
                <t t-if="searchTerm and emojisFromSearch.length === 0" class="d-flex flex-column">
                    <span class="o-EmojiPicker-empty">😢</span>
                    <span class="fs-5 text-muted">No emoji matches your search</span>
                </t>
                <t t-if="recentEmojis.length &gt; 0">
                    <t t-if="!searchTerm" t-call="web.EmojiPicker.section">
                        <t t-set="category" t-value="recentCategory"/>
                    </t>
                    <t t-foreach="recentEmojis" t-as="emoji" t-key="'recent_' + emoji_index">
                        <t t-call="web.EmojiPicker.emoji">
                            <t t-set="inRecent" t-value="true"/>
                            <t t-set="emoji" t-value="emoji"/>
                        </t>
                        <t t-set="itemIndex" t-value="itemIndex + 1"/>
                    </t>
                </t>
                <t t-set="current" t-value=""/>
                <t t-foreach="getEmojis()" t-as="emoji" t-key="emoji_index">
                    <t t-if="!searchTerm and current !== emoji.category">
                        <t t-set="current" t-value="emoji.category"/>
                        <t t-set="category" t-value="categories.find(c =&gt; c.name === current)"/>
                        <t t-call="web.EmojiPicker.section">
                            <t t-set="category" t-value="category"/>
                        </t>
                    </t>
                    <t t-elif="searchTerm" t-set="categorySortId" t-value="null"/>
                    <t t-call="web.EmojiPicker.emoji">
                        <t t-set="emoji" t-value="emoji"/>
                    </t>
                    <t t-set="itemIndex" t-value="itemIndex + 1"/>
                </t>
            </div>
            <div class="o-EmojiPicker-navbar d-flex flex-shrink-0 w-100 align-items-center justify-content-center overflow-auto px-1 gap-1 border-top border-secondary" t-att-class="{ 'opacity-0': !state.emojiNavbarRepr }" t-ref="navbar">
                <t t-if="currentNavbarPanel">
                    <t t-set="allCategories" t-value="getAllCategories()"/>
                    <t t-foreach="currentNavbarPanel" t-as="navbarItemId" t-key="navbarItemId">
                        <t t-if="navbarItemId === 'next'" t-call="web.EmojiPicker.tabNext"/>
                        <t t-elif="navbarItemId === 'previous'" t-call="web.EmojiPicker.tabPrev"/>
                        <t t-elif="typeof navbarItemId === 'string' and navbarItemId.startsWith('empty')" t-call="web.EmojiPicker.tabEmpty"/>
                        <t t-else="">
                            <t t-set="category" t-value="allCategories.find(cat =&gt; cat.sortId === navbarItemId)"/>
                            <t t-if="category" t-call="web.EmojiPicker.tab">
                                <t t-set="category" t-value="category"/>
                            </t>
                        </t>
                    </t>
                </t>
            </div>
        </t>
    </div>
</t>

`);
registerTemplate("web.EmojiPicker.tab", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tab" xml:space="preserve">
    <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch" t-att-class="{'o-active': category.sortId === state.categoryId}" t-att-title="category.name" t-att-data-id="category.sortId" t-on-click="() =&gt; this.selectCategory(category.sortId)">
        <span t-esc="category.title"/>
    </span>
</t>

`);
registerTemplate("web.EmojiPicker.tabNext", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabNext" xml:space="preserve">
    <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch" title="To previous categories" t-on-click="onClickToNextCategories">
        <span class="position-relative">
            <i class="oi oi-chevron-right fa-fw smaller opacity-0"/>
            <i class="oi oi-chevron-right fa-fw smaller position-absolute opacity-75" style="left: 3px; transform: translateY(75%);"/>
            <i class="oi oi-chevron-right fa-fw smaller position-absolute opacity-75" style="left: -3px; transform: translateY(75%);"/>
        </span>
    </span>
</t>

`);
registerTemplate("web.EmojiPicker.tabPrev", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabPrev" xml:space="preserve">
    <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch" title="To next categories" t-on-click="onClickToPreviousCategories">
        <span class="position-relative">
            <i class="oi oi-chevron-left fa-fw smaller opacity-0"/>
            <i class="oi oi-chevron-left fa-fw smaller position-absolute opacity-75" style="left: 3px; transform: translateY(75%);"/>
            <i class="oi oi-chevron-left fa-fw smaller position-absolute opacity-75" style="left: -3px; transform: translateY(75%);"/>
        </span>
    </span>
</t>

`);
registerTemplate("web.EmojiPicker.tabEmpty", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.tabEmpty" xml:space="preserve">
    <span class="o-Emoji text-center fs-5 rounded-3 cursor-pointer d-flex align-items-center align-self-stretch opacity-0">
        <span>🫥</span>
    </span>
</t>

`);
registerTemplate("web.EmojiPicker.section", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.section" xml:space="preserve">
    <span class="w-100 fs-7 px-2 py-1 position-sticky top-0 bg-100 align-self-stretch" t-att-data-category="category.sortId"><span class="o-EmojiPicker-sectionIcon fs-5 opacity-50" t-esc="category.title"/><span class="ms-2 text-muted text-uppercase fs-7 opacity-50" t-esc="category.displayName"/></span>
    <span class="o-EmojiPicker-category opacity-100 fs-7 py-2" t-att-data-category="category.sortId"/>
</t>

`);
registerTemplate("web.EmojiPicker.emoji", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.emoji" xml:space="preserve">
    <span class="o-Emoji cursor-pointer d-flex justify-content-center rounded-3 align-items-center align-self-stretch" t-att-class="{ 'o-active': state.activeEmojiIndex === itemIndex, 'fs-2': !ui.isSmall, 'fs-1': ui.isSmall }" t-att-title="emoji.name" t-att-data-codepoints="emoji.codepoints" t-att-data-index="itemIndex" t-att-data-category="inRecent ? recentCategory.sortId : categories.find(c =&gt; c.name === emoji.category).sortId" t-on-click="selectEmoji">
        <span t-esc="emoji.codepoints"/>
    </span>
</t>

`);
registerTemplate("web.EmojiPicker.searchInput", `/web/static/src/core/emoji_picker/emoji_picker.xml`, `<t t-name="web.EmojiPicker.searchInput" xml:space="preserve">
    <input class="form-control border-0 flex-grow-1 rounded-3 rounded-end-0 o-active lh-1" placeholder="Search emoji" t-model="localState.searchTerm" t-ref="autofocus" t-att-model="localState.searchTerm" t-on-input="() =&gt; this.state.activeEmojiIndex = 0" t-att-tabindex="isMobileOS ? -1 : 0"/>
</t>

`);
registerTemplate("web.WarningDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.WarningDialog" xml:space="preserve">
        <Dialog title="title" size="'xl'" contentClass="'o_error_dialog'">
            <div role="alert">
                <p t-esc="message" class="text-prewrap"/>
            </div>
            <t t-set-slot="footer">
                <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button>
            </t>
        </Dialog>
    </t>

    `);
registerTemplate("web.RedirectWarningDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.RedirectWarningDialog" xml:space="preserve">
        <Dialog title="title" size="'xl'" contentClass="'o_error_dialog'">
            <div role="alert">
                <p t-esc="message" class="text-prewrap"/>
            </div>
            <t t-set-slot="footer">
                <button class="btn btn-primary" t-on-click="onClick" t-esc="buttonText"/>
                <button class="btn btn-secondary" t-on-click="props.close">Close</button>
            </t>
        </Dialog>
    </t>

    `);
registerTemplate("web.Error504Dialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.Error504Dialog" xml:space="preserve">
        <Dialog title.translate="Request timeout" size="'xl'" contentClass="'o_error_dialog'">
            <div role="alert">
                <p class="text-prewrap">
                    The operation was interrupted. This usually means that the current operation is taking too much time.
                </p>
            </div>
            <t t-set-slot="footer">
                <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button>
            </t>
        </Dialog>
    </t>

    `);
registerTemplate("web.SessionExpiredDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.SessionExpiredDialog" xml:space="preserve">
        <Dialog title.translate="Odoo Session Expired" size="'xl'" contentClass="'o_error_dialog'">
            <div role="alert">
                <p class="text-prewrap">
                    Your Odoo session expired. The current page is about to be refreshed.
                </p>
            </div>
            <t t-set-slot="footer">
                <button class="btn btn-primary o-default-button" t-on-click="onClick">Close</button>
            </t>
        </Dialog>
    </t>

    `);
registerTemplate("web.ErrorDialog", `/web/static/src/core/errors/error_dialogs.xml`, `<t t-name="web.ErrorDialog" xml:space="preserve">
        <Dialog title.translate="Oops!" size="'xl'" contentClass="'o_error_dialog'">
            <div role="alert">
                <p class="text-prewrap">
                    Something went wrong... If you really are stuck, share the report with your friendly support service
                </p>
                <button class="btn btn-link p-0" t-on-click="() =&gt; { state.showTraceback = !state.showTraceback }" t-esc="state.showTraceback ? this.constructor.hideTracebackButtonText : this.constructor.showTracebackButtonText"/>
                <div t-if="state.showTraceback" class="bg-100 mb-0 clearfix mt-3 position-relative o_error_detail">
                    <button class="btn position-absolute bg-100" t-ref="copyButton" t-on-click="onClickClipboard">
                        <span class="fa fa-clone"/>
                    </button>
                    <div class="ps-3 pt-3">
                        <p class="m-0"><b t-esc="title or this.constructor.title"/></p>
                        <code t-if="props.name" t-esc="props.name"/>
                        <p class="m-0" t-if="props.message" t-esc="props.message"/>
                        <p class="m-0" t-if="contextDetails" t-esc="contextDetails"/>
                        <pre class="m-0 p-0 mt-2" t-esc="traceback or props.traceback"/>
                    </div>
                </div>
            </div>
            <t t-set-slot="footer">
                <button class="btn btn-primary o-default-button" t-on-click="props.close">Close</button>
            </t>
        </Dialog>
    </t>

`);
registerTemplate("web.ExpressionEditor", `/web/static/src/core/expression_editor/expression_editor.xml`, `<t t-name="web.ExpressionEditor" xml:space="preserve">
        <div class="o_expression_editor w-100" aria-atomic="true">
            <t t-if="tree">
                <TreeEditor resModel="props.resModel" tree="tree" isDebugMode="isDebugMode" update.bind="update" getDefaultCondition.bind="getDefaultCondition" getDefaultOperator.bind="getDefaultOperator" getOperatorEditorInfo.bind="getOperatorEditorInfo" getPathEditorInfo.bind="getPathEditorInfo"/>
            </t>
            <t t-else="">
                This expression is not supported.
                <button t-on-click="() =&gt; this.resetExpression()">Reset expression</button>
            </t>
            <t t-if="isDebugMode">
                <div class="o_expression_editor_debug_container d-block mt-3 border rounded p-3 bg-100 text-muted font-monospace">
                    <span class="small"># Code editor</span>
                    <textarea class="pt-2 border-0 bg-transparent text-body" type="text" spellcheck="false" t-att-value="props.expression" t-on-change="(ev) =&gt; this.onExpressionChange(ev.target.value)"/>
                </div>
            </t>
        </div>
    </t>

`);
registerTemplate("web.ExpressionEditorDialog", `/web/static/src/core/expression_editor_dialog/expression_editor_dialog.xml`, `<t t-name="web.ExpressionEditorDialog" xml:space="preserve">
        <Dialog title.translate="Edit Condition">
            <ExpressionEditor t-props="expressionEditorProps"/>
            <t t-set-slot="footer">
                <button class="btn btn-primary" t-on-click="onConfirm" t-ref="confirm">Confirm</button>
                <button class="btn btn-secondary" t-on-click="onDiscard">Discard</button>
            </t>
        </Dialog>
    </t>

`);
registerTemplate("web.FileInput", `/web/static/src/core/file_input/file_input.xml`, `<t t-name="web.FileInput" xml:space="preserve">
        <span class="o_file_input" t-att-class="{ 'd-none': props.hidden, 'show opacity-50 pe-none': state.isDisable}" aria-atomic="true">
            <span t-if="!props.hidden" class="o_file_input_trigger" t-on-click.prevent="onTriggerClicked">
                <t t-slot="default">
                    <button class="btn btn-primary">Choose File</button>
                </t>
            </span>
            <input type="file" name="ufile" class="o_input_file d-none" t-att-multiple="props.multiUpload" t-att-accept="props.acceptedFileExtensions" t-ref="file-input" t-att-disabled="state.isDisable" t-on-change="onFileInputChange"/>
        </span>
    </t>

`);
registerTemplate("web.FileUploadProgressBar", `/web/static/src/core/file_upload/file_upload_progress_bar.xml`, `<t t-name="web.FileUploadProgressBar" xml:space="preserve">
        <div class="position-absolute top-0 start-0 h-100 w-100">
            <div class="o-file-upload-progress-bar-value h-100" t-ref="bar" t-att-style="'width: ' + (this.props.fileUpload.progress * 100) + '%;'"/>
            <span class="position-absolute top-0 end-0 cursor-pointer o-file-upload-progress-bar-abort fa fa-times-circle" title="Cancel Upload" aria-label="Cancel Upload" t-on-click.stop.prevent="onCancel"/>
        </div>
    </t>
`);
registerTemplate("web.FileUploadProgressContainer", `/web/static/src/core/file_upload/file_upload_progress_container.xml`, `<t t-name="web.FileUploadProgressContainer" xml:space="preserve">
        <t t-foreach="Object.values(props.fileUploads)" t-as="fileUpload" t-key="fileUpload.id">
            <t t-if="!props.shouldDisplay || props.shouldDisplay(fileUpload)" t-component="props.Component" fileUpload="fileUpload" selector="props.selector"/>
        </t>
    </t>
`);
registerTemplate("web.FileUploadProgressKanbanRecord", `/web/static/src/core/file_upload/file_upload_progress_record.xml`, `<t t-name="web.FileUploadProgressKanbanRecord" xml:space="preserve">
        <t t-set="progressTexts" t-value="getProgressTexts()"/>
        <div class="o_kanban_record d-flex flex-grow-1 flex-md-shrink-1 flex-shrink-0">
            <div class="o_kanban_progress_card o_kanban_attachment position-relative p-0 cursor-pointer">
                <div class="o_kanban_image">
                    <div class="o_kanban_image_wrapper">
                        <div class="o_image o_image_thumbnail" t-att-data-mimetype="props.fileUpload.type"/>
                    </div>
                </div>
                <div class="o_kanban_details">
                    <div class="o_kanban_details_wrapper">
                        <div t-att-title="props.fileUpload.title" t-att-aria-label="props.fileUpload.title" class="o_kanban_record_title">
                            <span t-esc="props.fileUpload.title"/>
                        </div>
                        <div class="o_kanban_record_body"/>
                        <div class="o_kanban_record_bottom">
                            <div class="oe_kanban_bottom_left">
                                <div class="o_file_upload_progress_text_left" t-esc="progressTexts.left"/>
                            </div>
                            <div class="oe_kanban_bottom_right">
                                <span class="o_file_upload_progress_text_right" t-esc="progressTexts.right"/>
                            </div>
                        </div>
                    </div>
                </div>
                <FileUploadProgressBar fileUpload="props.fileUpload"/>
            </div>
        </div>
    </t>

    `);
registerTemplate("web.FileUploadProgressDataRow", `/web/static/src/core/file_upload/file_upload_progress_record.xml`, `<t t-name="web.FileUploadProgressDataRow" xml:space="preserve">
        <t t-set="progressTexts" t-value="getProgressTexts()"/>
        <div class="o_data_row o_list_progress_card position-relative align-middle p-0">
            <span class="o_file_upload_upload_title" t-esc="props.fileUpload.title"/>
            <span class="o_file_upload_progress_text_left" t-esc="progressTexts.left"/>
            <span class="o_file_upload_progress_text_right" t-esc="progressTexts.right"/>
            <FileUploadProgressBar fileUpload="props.fileUpload"/>
        </div>
    </t>

`);
registerTemplate("web.FileViewer", `/web/static/src/core/file_viewer/file_viewer.xml`, `<t t-name="web.FileViewer" xml:space="preserve">
        <div class="d-flex justify-content-center" t-att-class="{ 'modal modal-fullscreen': props.modal }">
            <div class="o-FileViewer flex-column align-items-center d-flex w-100 h-100" tabindex="0" t-ref="autofocus" t-on-keydown.stop="(ev) =&gt; this.onKeydown(ev)">
                <div class="o-FileViewer-header position-absolute top-0 d-flex w-100" t-on-click.stop="">
                    <div t-if="isViewable" class="d-flex align-items-center ms-4 me-2">
                        <i t-if="state.file.isImage" class="fa fa-picture-o" role="img" title="Image"/>
                        <i t-if="state.file.isPdf" class="fa fa-file-text" role="img" title="PDF file"/>
                        <i t-if="state.file.isText" class="fa fa-file-text" role="img" title="Text file"/>
                        <i t-if="state.file.isVideo" class="fa fa-video-camera" role="img" title="Video"/>
                    </div>
                    <div class="d-flex align-items-center ms-4 overflow-auto">
                        <span class="text-truncate" t-out="state.file.displayName"/>
                    </div>
                    <div class="flex-grow-1"/>
                    <div class="o-FileViewer-download o-FileViewer-headerButton d-flex align-items-center px-3 cursor-pointer" role="button" title="Download" t-on-click.stop="">
                        <a t-att-href="state.file.downloadUrl" class="text-reset d-flex align-items-baseline" download="">
                            <i class="fa fa-download fa-fw me-1" role="img"/>
                            <span>Download</span>
                        </a>
                    </div>

                    <div t-on-click.stop="close" class="o-FileViewer-headerButton d-flex align-items-center mb-0 px-3 h4 text-reset cursor-pointer" role="button" title="Close (Esc)" aria-label="Close">
                        <i class="fa fa-fw fa-times" role="img"/>
                    </div>
                </div>
                <div t-on-click.stop="close" t-on-mousemove="onMousemoveView" class="o-FileViewer-main position-absolute top-0 bottom-0 start-0 end-0 align-items-center justify-content-center d-flex" t-att-class="{ 'o_with_img overflow-hidden': state.file.isImage }">
                    <div t-if="state.file.isImage" class="o-FileViewer-zoomer position-absolute align-items-center justify-content-center d-flex w-100 h-100" t-ref="zoomer">
                        <div t-if="!state.imageLoaded" class="position-absolute">
                            <i class="fa fa-3x fa-circle-o-notch fa-fw fa-spin text-white" role="img" title="Loading"/>
                        </div>
                        <img t-on-click.stop="" t-on-load="onImageLoaded" t-on-wheel="onWheelImage" t-on-mousedown.stop="onMousedownImage" t-on-mouseup.stop="onMouseupImage" class="o-FileViewer-view o-FileViewer-viewImage mw-100 mh-100 transition-base" t-att-src="state.file.defaultSource" t-att-style="imageStyle" draggable="false" alt="Viewer" t-ref="image"/>
                    </div>
                    <iframe t-if="state.file.isPdf" class="o-FileViewer-view w-75 h-100 border-0" t-ref="iframeViewerPdf" t-att-class="{ 'w-100': ui.isSmall }" t-att-src="state.file.defaultSource"/>
                    <iframe t-if="state.file.isText" class="o-FileViewer-view o-isText o_text w-75 h-100 border-0" t-att-src="state.file.defaultSource"/>
                    <iframe t-if="state.file.isUrlYoutube" allow="autoplay; encrypted-media" class="o-FileViewer-view w-75 h-100 border-0" t-att-src="state.file.defaultSource" height="315" width="560"/>
                    <video t-if="state.file.isVideo" class="o-FileViewer-view w-75 h-75" t-att-class="{ 'w-100 h-100': ui.isSmall }" t-on-click.stop="" controls="controls">
                        <source t-att-data-type="state.file.mimetype" t-att-src="state.file.defaultSource"/>
                    </video>
                </div>
                <div t-if="state.file.isImage" class="position-absolute bottom-0 d-flex" role="toolbar">
                    <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="zoomIn" title="Zoom In (+)" role="button">
                        <i class="fa fa-fw fa-plus" role="img"/>
                    </div>
                    <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-att-class="{ 'o_disabled opacity-50': state.scale === 1 }" t-on-click.stop="resetZoom" role="button" title="Reset Zoom (0)">
                        <i class="fa fa-fw fa-search" role="img"/>
                    </div>
                    <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-att-class="{ 'o_disabled opacity-50': state.scale === minScale }" t-on-click.stop="zoomOut" title="Zoom Out (-)" role="button">
                        <i class="fa fa-fw fa-minus" role="img"/>
                    </div>
                    <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="rotate" title="Rotate (r)" role="button">
                        <i class="fa fa-fw fa-repeat" role="img"/>
                    </div>
                    <div class="o-FileViewer-toolbarButton p-3 rounded-0" t-on-click.stop="onClickPrint" title="Print" role="button">
                        <i class="fa fa-fw fa-print" role="img"/>
                    </div>
                    <div class="o-FileViewer-download o-FileViewer-toolbarButton p-3 rounded-0 cursor-pointer" title="Download" role="button" t-on-click.stop="">
                        <a t-att-href="state.file.downloadUrl" class="text-reset" download="">
                            <i class="fa fa-download fa-fw" role="img"/>
                        </a>
                    </div>
                </div>
                <t t-if="props.files.length &gt; 1">
                    <div class="o-FileViewer-navigation position-absolute top-0 bottom-0 start-0 align-items-center justify-content-center d-flex my-auto ms-3 rounded-circle bg-dark text-white" t-on-click.stop="previous" title="Previous (Left-Arrow)" aria-label="Previous" role="button">
                        <span class="oi oi-chevron-left" role="img"/>
                    </div>
                    <div class="o-FileViewer-navigation position-absolute top-0 bottom-0 end-0 align-items-center justify-content-center d-flex my-auto me-3 rounded-circle bg-dark text-white" t-on-click.stop="next" title="Next (Right-Arrow)" aria-label="Next" role="button">
                        <span class="oi oi-chevron-right" role="img"/>
                    </div>
                </t>
            </div>
        </div>
    </t>

`);
registerTemplate("web.InstallScopedApp", `/web/static/src/core/install_scoped_app/install_scoped_app.xml`, `<t t-name="web.InstallScopedApp" xml:space="preserve">
        <div class="o_install_scoped_app o_home_menu_background h-100 w-100 d-flex align-items-center justify-content-center user-select-none">
            <button class="btn btn-link m-1 position-absolute start-0 top-0" t-on-click="() =&gt; window.close()">
                <svg xmlns="http://www.w3.org/2000/svg" style="transform:rotate(135deg);" width="28" height="28" viewBox="-7 -7 24 24" preserveAspectRatio="xMinYMin">
                    <path fill="#000" d="M8 8V1a1 1 0 1 1 2 0v8a1 1 0 0 1-1 1H1a1 1 0 1 1 0-2h7z"/>
                </svg>
            </button>
            <i t-if="!state.showInstallUI" class="fa fa-spinner fa-spin fa-2x text-primary position-absolute"/>
            <div t-attf-class="h-100 w-100 d-flex align-items-center justify-content-center flex-column fade {{state.showInstallUI ? 'show': ''}}">
                <div class="d-flex align-items-center justify-content-center flex-wrap gap-3 m-4 mw-75 mw-md-50">
                    <img style="height:100px;width:100px;" class="rounded-4 p-4 bg-white shadow" t-att-src="state.manifest.icons?.[0]?.src"/>
                    <div class="d-inline-block">
                        <div class="d-flex align-items-center">
                            <h1 class="mb-0" t-esc="state.manifest.name"/>
                            <Dropdown t-if="pwa.isAvailable" menuClass="'p-2'">
                                <button class="btn btn-link fa fa-pencil"/>
                                <t t-set-slot="content">
                                    <label class="mb-1">Application name</label>
                                    <input class="form-control" t-att-value="state.manifest.name" t-on-change="onChangeName"/>
                                </t>
                            </Dropdown>
                        </div>
                        <a class="text-primary text-decoration-none" href="https://odoo.com" alt="Odoo" target="_blank">Odoo S.A.</a>
                    </div>
                </div>
                <button t-if="pwa.isAvailable" class="btn btn-primary btn-lg rounded-5 shadow py-2 px-3" t-on-click="onInstall">Install</button>
                <div t-else="" class="p-2 px-4 overflow-hidden rounded-2 mw-75 bg-info text-white">
                    <t t-if="pwa.isSupportedOnBrowser">
                        <span t-if="pwa.hasScopeBeenInstalled()">The app seems to be installed on your device</span>
                        <span t-else="">You can install the app from the browser menu</span>
                    </t>
                    <span t-else="">The app cannot be installed with this browser</span>
                </div>
            </div>
        </div>
    </t>
`);
registerTemplate("web._ModelFieldSelector", `/web/static/src/core/model_field_selector/model_field_selector.xml`, `<t t-name="web._ModelFieldSelector" xml:space="preserve">
        <div class="o_model_field_selector d-flex" aria-atomic="true" t-att-class="props.readonly ? 'o_read_mode' : 'o_edit_mode o_input'" t-on-click="(ev) =&gt; this.openPopover(ev.currentTarget)">
            <div class="o_model_field_selector_value flex-grow-1 h-100" tabindex="0" t-att-data-tooltip="state.displayNames.join(' &gt; ')" data-tooltip-position="top">
                <t t-foreach="state.displayNames" t-as="displayName" t-key="displayName_index">
                    <t t-if="!displayName_first">
                        <i class="oi oi-chevron-right m-1" role="img" aria-label="Followed by" title="Followed by"/>
                    </t>
                    <span t-attf-class="o_model_field_selector_chain_part mb-1 #{props.readonly ? 'border-0 fw-bolder' : 'px-1'} text-nowrap">
                        <t t-esc="displayName"/>
                    </span>
                </t>
            </div>
            <div t-if="!props.readonly and state.isInvalid" class="o_model_field_selector_controls ms-2" tabindex="0">
                <i class="fa fa-exclamation-triangle text-warning o_model_field_selector_warning" role="alert" aria-label="Invalid field chain" title="Invalid field chain"/>
            </div>
            <div t-if="!props.readonly and props.allowEmpty and state.displayNames.length" class="o_model_field_selector_controls ms-2" tabindex="0">
                <i class="fa fa-times" t-on-click.stop="clear" aria-label="Clear" title="Clear"/>
            </div>
        </div>
    </t>

`);
registerTemplate("web.ModelFieldSelectorPopover", `/web/static/src/core/model_field_selector/model_field_selector_popover.xml`, `<t t-name="web.ModelFieldSelectorPopover" xml:space="preserve">
        <div class="o_model_field_selector_popover" tabindex="-1" t-ref="root" t-on-keydown="onInputKeydown">
            <div class="border-bottom p-2 text-dark fw-bolder">
                <div class="d-flex justify-content-between align-items-center">
                    <t t-if="state.page.previousPage">
                        <i class="o_model_field_selector_popover_prev_page btn btn-link oi oi-arrow-left ms-n2 text-dark" title="Previous" role="img" aria-label="Previous" t-on-click="() =&gt; this.goToPreviousPage()"/>
                    </t>
                    <div class="o_model_field_selector_popover_title px-2 text-truncate">
                        <t t-esc="state.page.title"/>
                    </div>
                    <i class="o_model_field_selector_popover_close btn btn-link me-n2 fa fa-times text-dark" title="Close" role="img" aria-label="Close" t-on-click="() =&gt; props.close()"/>
                </div>
                <t t-if="props.showSearchInput">
                    <div class="o_model_field_selector_popover_search mt-1">
                        <input type="text" placeholder="Search..." class="o_input p-1 border rounded-1 bg-view" t-att-value="state.page.query" t-on-input="(ev) =&gt; this.debouncedSearchFields(ev.target.value)"/>
                    </div>
                </t>
            </div>
            <div class="o_model_field_selector_popover_body">
                <ul class="o_model_field_selector_popover_page list-unstyled mb-0 overflow-auto">
                    <t t-foreach="state.page.fieldNames" t-as="fieldName" t-key="fieldName">
                        <t t-set="fieldDef" t-value="state.page.fieldDefs[fieldName]"/>
                        <li class="o_model_field_selector_popover_item d-flex border-bottom" t-att-class="{ 'active': fieldName === state.page.focusedFieldName }" t-att-data-name="fieldName">
                            <button t-attf-class="o_model_field_selector_popover_item_name btn btn-light flex-fill border-0 rounded-0 text-start fw-normal" t-on-click="() =&gt; this.selectField(fieldDef)">
                                <t t-esc="fieldDef.string"/>
                                <t t-if="fieldDef.record_name"> (<t t-esc="fieldDef.record_name"/>)</t>
                                <div t-if="props.isDebugMode" class="o_model_field_selector_popover_item_title text-muted small"><t t-esc="fieldName"/> (<t t-esc="fieldDef.type"/>)</div>
                            </button>
                            <t t-if="(!fieldDef.is_property and fieldDef.relation and props.followRelations) or fieldDef.type === 'properties'">
                                <button class="o_model_field_selector_popover_item_relation btn btn-light border-0 border-start rounded-0" t-on-click.stop="() =&gt; this.followRelation(fieldDef)">
                                    <i class="oi oi-chevron-right o_model_field_selector_popover_relation_icon" role="img" aria-label="Relation to follow" title="Relation to follow"/>
                                </button>
                            </t>
                        </li>
                    </t>
                </ul>
            </div>
            <t t-if="showDebugInput">
                <div class="o_model_field_selector_popover_footer border-top py-1 px-2">
                    <input type="text" class="o_model_field_selector_debug o_input" t-att-value="state.page.path" t-on-change="(ev) =&gt; this.loadNewPath(ev.target.value)" t-on-keydown="onDebugInputKeydown" t-on-input="(ev) =&gt; this.props.update(ev.target.value, null, true)"/>
                </div>
            </t>
        </div>
    </t>

`);
registerTemplate("web.ModelSelector", `/web/static/src/core/model_selector/model_selector.xml`, `<t t-name="web.ModelSelector" xml:space="preserve">
        <div class="o_model_selector" t-ref="autocomplete_container">
            <input t-if="env.isSmall" type="text" class="o_input" readonly="" t-att-id="props.id" t-att-value="props.value"/>
            <AutoComplete t-else="" id="props.id" value="props.value || ''" sources="sources" placeholder.translate="Type a model here..." autoSelect="props.autoSelect" onSelect.bind="onSelect"/>
            <span class="o_dropdown_button"/>
        </div>
    </t>
`);
registerTemplate("web.Notebook", `/web/static/src/core/notebook/notebook.xml`, `<t t-name="web.Notebook" xml:space="preserve">
        <div t-attf-class="o_notebook d-flex w-100 {{ props.orientation === 'horizontal' ? 'horizontal flex-column' : 'vertical flex-row' }} {{ props.className }}" t-if="state.currentPage">
            <div class="o_notebook_headers" t-att-class="{ 'm-0': props.orientation === 'vertical' }">
                <ul t-attf-class="nav nav-tabs {{ props.orientation === 'horizontal' ? 'flex-row flex-nowrap' : 'flex-column p-0' }}">
                    <li t-foreach="navItems" t-as="navItem" t-key="navItem[0]" class="nav-item flex-nowrap cursor-pointer" t-if="navItem[1].isVisible" t-attf-class="{{ navItem[1].isDisabled ? 'disabled' : '' }}">
                        <a class="nav-link" t-attf-class="{{ navItem[0] === state.currentPage ? 'active' : '' }} {{ props.orientation === 'vertical' ? 'p-3 rounded-0' : '' }} {{ navItem[1].className || '' }}" t-att-name="navItem[1].name" t-on-click.prevent="() =&gt; this.activatePage(navItem[0])" href="#" role="tab" tabindex="0">
                            <i t-if="props.icons and props.icons[navItem[0]]" t-attf-class="fa {{ props.icons[navItem[0]] }} me-2"/>
                            <t t-esc="navItem[1].title"/>
                        </a>
                    </li>
                </ul>
            </div>
            <div class="o_notebook_content tab-content">
                <div class="tab-pane active fade" t-ref="activePane">
                    <t t-if="page" t-component="page.Component" t-key="state.currentPage" t-props="page.props"/>
                    <t t-else="" t-slot="{{ state.currentPage }}"/>
                </div>
            </div>
        </div>
    </t>

`);
registerTemplate("web.NotificationWowl", `/web/static/src/core/notifications/notification.xml`, `<t t-name="web.NotificationWowl" xml:space="preserve">
        <div t-on-mouseenter="this.props.freeze" t-on-mouseleave="this.props.refresh" t-attf-class="o_notification {{props.className}} d-flex mb-2 position-relative rounded shadow-lg" role="alert" aria-live="assertive" aria-atomic="true">
            <span t-attf-class="o_notification_bar bg-{{props.type}} rounded-start"/>
            <div class="w-100 py-3 ps-3 pe-5 border border-start-0 rounded-end text-break">
                <h5 t-if="props.title" class="o_notification_title m-0" t-out="props.title"/>
                <button type="button" class="o_notification_close btn-close position-absolute top-0 end-0 mt-3 me-3" aria-label="Close" t-on-click="props.close"/>
                <div class="o_notification_body" t-att-class="{'mt-2' : props.title}">
                    <div t-if="props.message" class="me-auto o_notification_content" t-out="props.message"/>
                    <div t-if="props.buttons.length" class="o_notification_buttons d-flex gap-2 mt-3">
                        <button t-foreach="props.buttons" t-as="button" type="button" t-key="button_index" t-attf-class="btn {{button.primary ? 'btn-primary' : 'btn-secondary'}}" t-on-click="button.onClick">
                            <t t-if="button.icon">
                                <i t-if="button.icon.indexOf('fa-') === 0" role="img" t-att-aria-label="button.name" t-att-title="button.name" t-attf-class="fa fa-fw {{button.icon}} me-1"/>
                                <img t-else="" t-att-src="button.icon" t-att-alt="button.name"/>
                            </t>
                            <span t-esc="button.name"/>
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </t>

`);
registerTemplate("web.OverlayContainer", `/web/static/src/core/overlay/overlay_container.xml`, `<t t-name="web.OverlayContainer" xml:space="preserve">
        <div class="o-overlay-container" t-ref="root">
            <t t-foreach="sortedOverlays" t-as="overlay" t-key="overlay.id">
                <ErrorHandler t-if="isVisible(overlay)" onError="(error) =&gt; this.handleError(overlay, error)">
                    <OverlayItem env="overlay.env" component="overlay.component" props="overlay.props"/>
                </ErrorHandler>
            </t>
        </div>
    </t>

    `);
registerTemplate("web.OverlayContainer.Item", `/web/static/src/core/overlay/overlay_container.xml`, `<t t-name="web.OverlayContainer.Item" xml:space="preserve">
        <div t-ref="rootRef" class="o-overlay-item">
            <t t-component="props.component" t-props="props.props"/>
        </div>
    </t>

`);
registerTemplate("web.Pager", `/web/static/src/core/pager/pager.xml`, `<t t-name="web.Pager" xml:space="preserve">
        <nav class="o_pager d-flex gap-2 h-100" aria-label="Pager">
            <span t-if="!env.isSmall" class="o_pager_counter align-self-center" t-on-click.stop="">
                <t t-if="state.isEditing">
                    <input type="text" class="o_pager_value o_input d-inline-block w-auto text-end mb-n1" size="7" t-ref="autofocus" t-att-value="value" t-on-blur="onInputBlur" t-on-change="onInputChange" t-on-keydown.stop="onInputKeydown"/>
                </t>
                <t t-else="">
                    <span class="o_pager_value d-inline-block border-bottom border-transparent mb-n1" t-esc="value" t-on-click="onValueClick"/>
                </t>
                <span> / </span>
                <t t-if="props.updateTotal">
                    <span class="o_pager_limit o_pager_limit_fetch" t-att-class="{ 'disabled': state.isDisabled }" t-on-click.stop="updateTotal"><t t-esc="props.total"/>+</span>
                </t>
                <t t-else="">
                    <span class="o_pager_limit" t-esc="props.total"/>
                </t>
            </span>
            <span class="btn-group d-print-none" aria-atomic="true">

                <button type="button" class="btn btn-secondary o_pager_previous px-2 rounded-start" aria-label="Previous" data-tooltip="Previous" tabindex="-1" t-att-data-hotkey="props.withAccessKey ? 'p' : false" t-att-disabled="state.isDisabled or isSinglePage" t-on-click.stop="() =&gt; this.navigate(-1)">
                    <i class="oi oi-chevron-left"/>
                </button>
                <button type="button" class="btn btn-secondary o_pager_next px-2 rounded-end" aria-label="Next" data-tooltip="Next" tabindex="-1" t-att-data-hotkey="props.withAccessKey ? 'n' : false" t-att-disabled="state.isDisabled or isSinglePage" t-on-click.stop="() =&gt; this.navigate(1)">
                    <i class="oi oi-chevron-right"/>
                </button>
            </span>
        </nav>
    </t>

`);
registerTemplate("web.PagerIndicator", `/web/static/src/core/pager/pager_indicator.xml`, `<t t-name="web.PagerIndicator" xml:space="preserve">
        <Transition visible="state.show" name="'o-fade'" t-slot-scope="transition" leaveDuration="400">
            <div class="o_pager_indicator position-fixed top-0 end-0 m-1 d-flex" t-att-class="transition.className">
                <span class="o_pager_indicator_inner m-1 px-1 text-center shadow">
                    <span class="o_pager_value" t-esc="state.value"/>
                    <span> / </span>
                    <span class="o_pager_limit" t-esc="state.total"/>
                </span>
            </div>
        </Transition>
    </t>

`);
registerTemplate("web.Popover", `/web/static/src/core/popover/popover.xml`, `<t t-name="web.Popover" xml:space="preserve">
        <div t-ref="ref" t-att-class="defaultClassObj" t-att-role="props.role" t-on-pointerenter="() =&gt; props.holdOnHover and position.lock()" t-on-pointerleave="() =&gt; props.holdOnHover and position.unlock()">
            <t t-component="props.component" t-props="props.componentProps" close="props.close"/>
            <div t-if="props.arrow" class="popover-arrow"/>
        </div>
    </t>

`);
registerTemplate("web.InstallPrompt", `/web/static/src/core/pwa/install_prompt.xml`, `<t t-name="web.InstallPrompt" xml:space="preserve">
        <Dialog contentClass="'o_install_prompt position-fixed px-2 py-3 m-2 user-select-none'" size="'md'" footer="false">
            <t t-set-slot="header">
                <div class="d-flex w-100">
                    <h4>How to get the application</h4>
                    <div t-on-click="onClose" type="button" class="btn-close" aria-label="Close"/>
                </div>
            </t>
            <p>Install the app on your device to access it easily. Here are the steps to follow:</p>
            <t t-call="web.InstallStepsSafari"/>
        </Dialog>
    </t>
    `);
registerTemplate("web.InstallStepsSafari", `/web/static/src/core/pwa/install_prompt.xml`, `<t t-name="web.InstallStepsSafari" xml:space="preserve">
        <t t-if="isMobileSafari">
            <ul class="mb-0">
                <li>
                    Tap on the share icon
                </li>
                <li>
                    Select "Add to home screen"
                </li>
            </ul>
        </t>
        <t t-else="">
            <ul class="mb-0">
                <li>
                    Open "File" menu from your browser
                </li>
                <li>
                    Select "Add to dock"
                </li>
            </ul>
        </t>
    </t>
`);
registerTemplate("web.MultiRecordSelector", `/web/static/src/core/record_selectors/multi_record_selector.xml`, `<t t-name="web.MultiRecordSelector" xml:space="preserve">
        <div class="o_input d-flex flex-wrap gap-1 o_multi_record_selector" t-ref="multiRecordSelector">
            <TagsList tags="tags"/>
            <RecordAutocomplete resModel="props.resModel" value="''" domain="props.domain" context="props.context" className="'o_record_autocomplete_with_caret flex-grow-1'" fieldString="props.fieldString" placeholder="placeholder" multiSelect="true" getIds.bind="getIds" update.bind="update"/>
        </div>
    </t>

`);
registerTemplate("web.RecordAutocomplete", `/web/static/src/core/record_selectors/record_autocomplete.xml`, `<t t-name="web.RecordAutocomplete" xml:space="preserve">
        <AutoComplete placeholder="props.placeholder" value="props.value" autoSelect="true" resetOnSelect="props.multiSelect" class="props.className" sources="sources" onSelect.bind="onSelect" onChange.bind="onChange"/>
    </t>

`);
registerTemplate("web.RecordSelector", `/web/static/src/core/record_selectors/record_selector.xml`, `<t t-name="web.RecordSelector" xml:space="preserve">
        <div class="o_input d-flex flex-wrap gap-1 o_record_selector">
            <RecordAutocomplete resModel="props.resModel" value="displayName" domain="props.domain" context="props.context" className="'h-100 flex-grow-1'" fieldString="props.fieldString" placeholder="props.placeholder" multiSelect="false" getIds="() =&gt; []" update.bind="update"/>
            <span class="o_dropdown_button"/>
        </div>
    </t>

`);
registerTemplate("web_studio.ResizablePanel", `/web/static/src/core/resizable_panel/resizable_panel.xml`, `<t t-name="web_studio.ResizablePanel" xml:space="preserve">
        <div class="o_resizable_panel d-flex flex-column" t-att-class="class" t-ref="containerRef">
            <t t-slot="default"/>
            <div class="o_resizable_panel_handle position-absolute top-0 bottom-0 end-0" t-att-class="props.handleSide === 'start' ? 'start-0' : 'end-0'" t-ref="handleRef"/>
        </div>
    </t>

`);
registerTemplate("web.SelectMenu", `/web/static/src/core/select_menu/select_menu.xml`, `<t t-name="web.SelectMenu" xml:space="preserve">
        <div t-att-class="\`o_select_menu border w-auto rounded-2 overflow-hidden \${props.class || ''}\`">
            <Dropdown menuClass="this.menuClass" menuRef="this.menuRef" position="'bottom-fit'" beforeOpen.bind="onBeforeOpen" onStateChanged.bind="onStateChanged" navigationOptions="{ virtualFocus: this.props.searchable }">
                <button type="button" t-att-class="\`o_select_menu_toggler btn btn-light w-100 bg-light \${props.togglerClass || ''} \${canDeselect ? 'o_can_deselect' : ''}\`" t-att-disabled="props.disabled">
                    <t t-if="props.multiSelect">
                        <div class="text-wrap text-start">
                            <t t-if="props.placeholder and !props.value.length">
                                <span class="text-muted fst-italic" t-out="props.placeholder"/>
                            </t>
                            <t else="">
                                <TagsList tags="multiSelectChoices"/>
                            </t>
                        </div>
                    </t>
                    <t t-else="">
                        <span class="o_select_menu_toggler_slot text-start text-truncate">
                            <span t-if="props.placeholder and !props.value" class="text-muted fst-italic" t-out="props.placeholder"/>
                            <t t-if="!props.slots or !props.slots.default" t-esc="displayValue"/>
                            <t t-else="" t-slot="default"/>
                        </span>
                        <span t-if="canDeselect" t-on-click.stop="() =&gt; this.props.onSelect(null)" class="o_select_menu_toggler_clear p-0 m-0">
                            <i class="fa fa-times"/>
                        </span>
                    </t>
                    <span class="o_select_menu_toggler_caret p-0 m-0">
                        <i class="fa fa-caret-down"/>
                    </span>
                </button>

                <t t-set-slot="content">
                    <input t-if="props.searchable" type="text" class="dropdown-item o_select_menu_sticky px-3 py-3 position-sticky top-0 start-0 border-bottom" t-ref="inputRef" t-on-input="debouncedOnInput" t-att-placeholder="props.searchPlaceholder" autocomplete="selectMenuAutocompleteOff" autocorrect="off" spellcheck="false"/>
                    <t t-if="state.choices.length === 0">
                        <span class="text-muted fst-italic mx-3">No result found</span>
                    </t>
                    <t t-foreach="state.displayedOptions" t-as="choice" t-key="choice_index">
                        <t t-call="{{ this.constructor.choiceItemTemplate }}">
                            <t t-set="choice" t-value="choice"/>
                        </t>
                    </t>
                    <t t-if="props.slots and props.slots.bottomArea" t-slot="bottomArea" data="state"/>
                </t>
            </Dropdown>
        </div>
    </t>

    `);
registerTemplate("web.SelectMenu.ChoiceItem", `/web/static/src/core/select_menu/select_menu.xml`, `<t t-name="web.SelectMenu.ChoiceItem" xml:space="preserve">
        <div t-if="choice.isGroup" class="o_select_menu_group position-sticky bg-light pt-2 px-1 fst-italic fw-bolder user-select-none" t-att-class="{'o_select_menu_searchable_group': props.searchable }">
            <span t-esc="choice.label"/>
            <hr class="mt-2 mb-1"/>
        </div>
        <DropdownItem t-if="!choice.isGroup" onSelected="() =&gt; this.onItemSelected(choice.value)" class="getItemClass(choice) + ' d-flex align-items-center'">
            <t t-if="props.slots and props.slots.choice" t-slot="choice" data="choice"/>
            <t t-else="">
                <div class="o_select_menu_item_label text-wrap" t-esc="choice.label || choice.value"/>
            </t>
        </DropdownItem>
    </t>

`);
registerTemplate("web.sign_svg_text", `/web/static/src/core/signature/name_and_signature.xml`, `<t t-name="web.sign_svg_text" name="SVG Signature Text" xml:space="preserve">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" t-att-width="width" t-att-height="height">
            <defs>
                <style type="text/css">
                    @font-face {
                        font-family: "font";
                        src: url(data:font/ttf;base64,<t t-esc="font"/>) format("woff");
                        font-weight: normal;
                        font-style: normal;
                    }
                </style>
            </defs>

            <text t-esc="text" x="50%" t-att-y="height * 3 / 5" t-att-font-size="height * 3 / 5" t-att-textLength="width * 4 / 5 * (type === 'signature' ? Math.min(1, text.length / 7) : 1)" t-att-lengthAdjust="'spacing' + (type === 'signature' ? 'AndGlyphs' : '')" t-attf-style="font-family:'font'; stroke: none; fill: {{color}};" text-anchor="middle"/>
        </svg>
    </t>


    `);
registerTemplate("web.NameAndSignature", `/web/static/src/core/signature/name_and_signature.xml`, `<t t-name="web.NameAndSignature" xml:space="preserve">
        <div class="o_web_sign_name_and_signature">
            <div t-if="!props.noInputName" class="o_web_sign_name_group">
                <label class="col-form-label" t-att-for="'o_web_sign_name_input_' + htmlId">Full Name</label>
                <input type="text" name="signer" t-att-id="'o_web_sign_name_input_' + htmlId" class="o_web_sign_name_input form-control" t-on-input="onInputSignName" t-att-value="props.signature.name" t-ref="signNameInput" placeholder="Type your name to sign" required=""/>
            </div>


            <div t-if="state.showSignatureArea" class="o_web_sign_signature_group bg-100 card mt-3" style="overflow: hidden;">
                <div class="card-header bg-transparent">
                    <div class="row g-0">
                        <div t-if="!props.noInputName or defaultName" class="col-auto">
                            <a role="button" href="#" t-on-click.prevent="onClickSignAuto" t-attf-class="o_web_sign_auto_button me-2 btn btn-light {{ state.signMode === 'auto' ? 'active': '' }}">
                                Auto
                            </a>
                        </div>
                        <div class="col-auto">
                            <a role="button" href="#" t-on-click.prevent="() =&gt; this.setMode('draw')" t-attf-class="o_web_sign_draw_button me-2 btn btn-light {{ state.signMode === 'draw' ? 'active': '' }}">
                                Draw
                            </a>
                        </div>
                        <div class="col-auto">
                            <a role="button" href="#" t-on-click.prevent="onClickSignLoad" t-attf-class="o_web_sign_load_button me-2 btn btn-light {{ state.signMode === 'load' ? 'active': '' }}">
                                Load
                            </a>
                        </div>

                        <div class="col-auto division ms-auto"/>

                        <div t-if="state.signMode === 'auto'" class="o_web_sign_auto_select_style col-auto">
                            <Dropdown>
                                <button type="button" class="btn btn-link fa fa-font o-dropdown-caret"/>
                                <t t-set-slot="content">
                                    <t t-foreach="fonts" t-as="font" t-key="font_index">
                                        <DropdownItem onSelected="() =&gt; this.onSelectFont(font_index)">
                                            <img class="img-fluid" t-att-src="getSVGTextFont(font)"/>
                                        </DropdownItem>
                                    </t>
                                </t>
                            </Dropdown>
                        </div>

                        <div t-if="state.signMode === 'draw'" t-attf-class="o_web_sign_draw_clear col-auto">
                            <a role="button" href="#" t-on-click.prevent="onClickSignDrawClear" class="btn btn-link fa fa-trash"/>
                        </div>

                        <div t-if="state.signMode === 'load'" class="o_web_sign_load_file col-auto">
                            <button type="button" id="loadFileXml" t-on-click="uploadFile" class="btn btn-link fa fa-upload"/>
                            <input t-ref="signInputLoad" type="file" role="button" name="files[]" class="d-none" t-on-change="onChangeSignLoadInput"/>
                        </div>
                    </div>
                </div>

                <div class="o_web_sign_signature_container position-relative">
                    <div class="o_signature_stroke position-absolute"/>
                    <canvas t-if="state.showSignatureArea" t-ref="signature" class="o_web_sign_signature z-1"/>
                </div>

                <div t-if="loadIsInvalid" t-attf-class="o_web_sign_load_invalid card-footer d-none">
                    <div class="alert alert-danger mb-0" role="alert">
                        This file is invalid. Please select an image.
                    </div>
                </div>
            </div>
        </div>
    </t>
`);
registerTemplate("web.SignatureDialog", `/web/static/src/core/signature/signature_dialog.xml`, `<t t-name="web.SignatureDialog" xml:space="preserve">
      <Dialog title.translate="Adopt Your Signature">
         <div>
            <NameAndSignature t-props="nameAndSignatureProps"/>
            <div class="mt16 small">By clicking Adopt &amp; Sign, I agree that the chosen signature/initials will be a valid electronic representation of my hand-written signature/initials for all purposes when it is used on documents, including legally binding contracts.</div>
        </div>
        <t t-set-slot="footer">
          <button class="btn btn-primary" t-att-disabled="signature.isSignatureEmpty" t-on-click="onClickConfirm">Adopt &amp; Sign</button>
          <button class="btn btn-secondary" t-on-click="props.close">Cancel</button>
        </t>
      </Dialog>
    </t>

`);
registerTemplate("web.TagsList", `/web/static/src/core/tags_list/tags_list.xml`, `<t t-name="web.TagsList" xml:space="preserve">
        <t t-foreach="visibleTags" t-as="tag" t-key="tag.id or tag_index">
            <span class="o_tag position-relative d-inline-flex align-items-center user-select-none mw-100" t-att-class="{                     'o_avatar opacity-trigger-hover' : tag.img,                     'o_badge badge rounded-pill lh-1': !tag.img,                     'cursor-pointer': tag.canEdit,                 }" t-attf-class="{{ !tag.img ? 'o_tag_color_' + (tag.colorIndex ? tag.colorIndex : '0') : '' }}" tabindex="-1" t-att-data-color="tag.colorIndex" t-att-title="tag.text" t-on-click="(ev) =&gt; tag.onClick and tag.onClick(ev)" t-on-keydown="tag.onKeydown">


                <span t-if="tag.img and props.displayText and tag.onDelete" class="o_avatar_backdrop position-absolute top-0 end-0 bottom-0 start-0 ms-n2 mt-n1 mb-n1 bg-view rounded border shadow opacity-0 opacity-100-hover"/>

                <img t-if="tag.img" t-att-src="tag.img" class="o_avatar o_m2m_avatar position-relative rounded" t-att-class="tag.imageClass"/>

                <i t-if="tag.icon" t-attf-class="p-1 fa {{ tag.icon }}" t-att-class="tag.className"/>

                <div t-if="props.displayText" class="o_tag_badge_text text-truncate" t-att-class="{'position-relative ms-1' : tag.img}" t-out="tag.text"/>

                <a t-if="tag.onDelete" t-on-click.stop.prevent="(ev) =&gt; tag.onDelete and tag.onDelete(ev)" class="o_delete d-flex align-items-center opacity-100-hover" t-att-class="{                             'btn btn-link position-relative py-0 px-1 text-danger opacity-0': tag.img,                             'ps-1 opacity-75': !tag.img                         }" title="Delete" aria-label="Delete" tabIndex="-1" href="#">
                        <i class="oi oi-close align-text-top"/>
                </a>
            </span>
        </t>
        <span t-if="props.tags and otherTags.length" class="o_m2m_avatar_empty rounded text-center fw-bold" data-tooltip-template="web.TagsList.Tooltip" data-tooltip-position="right" t-att-data-tooltip-info="tooltipInfo">
            <span t-if="otherTags.length &gt; 9" t-esc="'9+'"/>
            <span t-else="" t-esc="'+' + otherTags.length"/>
        </span>
    </t>

    `);
registerTemplate("web.TagsList.Tooltip", `/web/static/src/core/tags_list/tags_list.xml`, `<t t-name="web.TagsList.Tooltip" xml:space="preserve">
        <t t-foreach="tags" t-as="tag" t-key="tag.id">
            <div t-esc="tag.text"/>
        </t>
    </t>

`);
registerTemplate("web.Tooltip", `/web/static/src/core/tooltip/tooltip.xml`, `<t t-name="web.Tooltip" xml:space="preserve">
        <div class="o-tooltip tooltip-inner d-print-none text-start">
            <t t-if="props.template" t-call="{{props.template}}" t-call-context="{ env, ...props.info }"/>
            <span t-else="" t-esc="props.tooltip"/>
        </div>
    </t>

`);
registerTemplate("web.TreeEditor", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor" xml:space="preserve">
        <div class="o_tree_editor w-100" aria-atomic="true" t-att-class="className">
            <div t-attf-class="o_tree_editor_node d-flex flex-column #{props.readonly ? (props.isSubTree ? 'gap-0' : 'gap-2') : 'gap-1'}">
                <t t-set="node" t-value="tree"/>
                <div class="o_tree_editor_row d-flex align-items-center flex-wrap" t-att-class="{'ps-4': props.isSubTree}">
                    <div class="o_tree_editor_connector d-flex flex-grow-1 align-items-center">
                        <t t-if="node.children.length">
                            <span t-if="!props.isSubTree">Match</span>
                            <t t-if="node.children.length &gt; 1">
                                <t t-call="web.TreeEditor.connector.dropdown"/>
                            </t>
                            <t t-else="">
                                <span class="px-1">
                                    <t t-call="web.TreeEditor.connector.title"/>
                                </span>
                            </t>
                            <span t-if="props.isSubTree">of:</span>
                            <span t-else="">of the following rules:</span>
                        </t>
                        <t t-else="">
                            <span><span t-if="!props.isSubTree">Match </span><strong>all records</strong></span>
                        </t>
                    </div>
                    <t t-slot="default"/>
                </div>
                <t t-if="node.children.length" t-call="web.TreeEditor.connector.children"/>
                <t t-if="!props.readonly">
                    <div class="o_tree_editor_row d-flex align-items-center" t-att-class="{ 'ps-4': addPadding || props.isSubTree }">
                        <a href="#" role="button" t-on-click="() =&gt; this.insertRootLeaf(node)">New Rule</a>
                    </div>
                </t>
            </div>
        </div>
    </t>

    `);
registerTemplate("web.TreeEditor.controls", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.controls" xml:space="preserve">
        <div class="o_tree_editor_node_control_panel d-flex" role="toolbar" aria-label="Domain node">
            <button class="btn px-2 fs-4" role="button" title="Add New Rule" aria-label="Add New Rule" t-on-click="() =&gt; this.insertLeaf(parent, node)" t-on-mouseenter="(ev) =&gt; this.highlightNode(ev.target, true)" t-on-mouseleave="(ev) =&gt; this.highlightNode(ev.target, false)">
                <i class="fa fa-plus"/>
            </button>
            <button class="btn px-2 fs-4" role="button" title="Add branch" aria-label="Add branch" t-on-click="() =&gt; this.insertBranch(parent, node)" t-on-mouseenter="(ev) =&gt; this.highlightNode(ev.target, true)" t-on-mouseleave="(ev) =&gt; this.highlightNode(ev.target, false)">
                <i class="fa fa-sitemap"/>
            </button>
            <button class="btn btn-link px-2 text-danger fs-4" role="button" title="Delete node" aria-label="Delete node" t-on-click="() =&gt; this.delete(parent, node)" t-on-mouseenter="(ev) =&gt; this.highlightNode(ev.target, true)" t-on-mouseleave="(ev) =&gt; this.highlightNode(ev.target, false)">
                <i class="fa fa-trash"/>
            </button>
        </div>
    </t>

    `);
registerTemplate("web.TreeEditor.connector.title", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector.title" xml:space="preserve">
        <t t-set="title">
            <t t-if="node.value === '|'">
                <t t-if="node.negate">none</t>
                <t t-else="">any</t>
            </t>
            <t t-else="">
                <t t-if="node.negate">not all</t>
                <t t-else="">all</t>
            </t>
        </t>
        <t t-esc="title"/>
    </t>

    `);
registerTemplate("web.TreeEditor.connector.dropdown", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector.dropdown" xml:space="preserve">
        <t t-if="props.readonly">
            <strong class="px-1">
                <t t-call="web.TreeEditor.connector.title"/>
            </strong>
        </t>
        <t t-else="">
            <div aria-atomic="true">
                <Dropdown>
                    <button class="btn btn-link btn-primary py-0 px-1 o-dropdown-caret">
                        <t t-call="web.TreeEditor.connector.title"/>
                    </button>
                    <t t-set-slot="content">
                        <DropdownItem onSelected="() =&gt; this.updateConnector(node, '&amp;')">all</DropdownItem>
                        <DropdownItem onSelected="() =&gt; this.updateConnector(node, '|')">any</DropdownItem>
                    </t>
                </Dropdown>
            </div>
        </t>
    </t>

    `);
registerTemplate("web.TreeEditor.connector.children", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector.children" xml:space="preserve">
        <t t-foreach="node.children" t-as="child" t-key="child.type + '_' + child_index">
            <div class="o_tree_editor_node" t-att-class="{ 'ps-4': addPadding || props.isSubTree }">
                <t t-call="web.TreeEditor.{{ child.type }}">
                    <t t-set="parent" t-value="node"/>
                    <t t-set="node" t-value="child"/>
                </t>
            </div>
        </t>
    </t>

    `);
registerTemplate("web.TreeEditor.connector", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.connector" xml:space="preserve">
        <div class="o_tree_editor_row d-flex align-items-center">
            <div class="o_tree_editor_connector d-flex flex-grow-1">
                <t t-call="web.TreeEditor.connector.dropdown"/>
                <span>of:</span>
            </div>
            <t t-if="!props.readonly">
                <t t-call="web.TreeEditor.controls"/>
            </t>
        </div>
        <t t-call="web.TreeEditor.connector.children">
            <t t-set="addPadding" t-value="true"/>
        </t>
    </t>

    `);
registerTemplate("web.TreeEditor.condition", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition" xml:space="preserve">
        <div class="o_tree_editor_row d-flex align-items-center">
            <t t-if="props.readonly">
                <t t-call="web.TreeEditor.condition:readonly"/>
            </t>
            <t t-else="">
                <t t-call="web.TreeEditor.condition:editable"/>
                <t t-call="web.TreeEditor.controls"/>
            </t>
        </div>
        <t t-if="isTree(node.value)">
            <TreeEditor t-props="props" update="(value) =&gt; this.updateLeafValue(node, value)" slots="{}" isSubTree="true" tree="node.value" resModel="getResModel(node)"/>
        </t>
    </t>

    `);
registerTemplate("web.TreeEditor.condition:readonly", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition:readonly" xml:space="preserve">
        <t t-set="description" t-value="getConditionDescription(node)"/>
        <div class="o_tree_editor_condition d-flex gap-1 px-2 border bg-100">
            <div class="fw-bolder text-nowrap" t-esc="description.pathDescription"/>
            <div class="fst-italic text-nowrap" t-esc="description.operatorDescription"/>
            <t t-if="description.valueDescription">
                <t t-set="values" t-value="description.valueDescription.values"/>
                <t t-set="join" t-value="description.valueDescription.join"/>
                <t t-set="addParenthesis" t-value="description.valueDescription.addParenthesis"/>
                <t t-if="addParenthesis">( </t>
                <t t-foreach="values" t-as="val" t-key="val_index">
                    <span class="text-primary fw-bolder"><t t-esc="val"/></span>
                    <t t-if="!val_last"> <t t-esc="join"/> </t>
                </t>
                <t t-if="addParenthesis"> )</t>
            </t>
        </div>
    </t>

    `);
registerTemplate("web.TreeEditor.Editor", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.Editor" xml:space="preserve">
        <t t-if="!info.isSupported(value)">
            <div t-attf-class="o_tree_editor_editor #{_classes}">
                <div class="o_input d-flex align-items-center">
                    <span class="flex-grow-1 text-truncate" t-esc="info.stringify(value)"/>
                    <i role="alert" class="fa fa-exclamation-triangle text-warning mx-2" t-att-title="(typeof info.message === 'function') ? info.message(value) : info.message"/>
                    <i class="fa fa-times" title="Clear" t-on-click="() =&gt; update(info.defaultValue())"/>
                </div>
            </div>
        </t>
        <t t-elif="info.component">
            <div t-attf-class="o_tree_editor_editor #{_classes}">
                <t t-component="info.component" t-props="info.extractProps({ update, value })"/>
            </div>
        </t>
    </t>

    `);
registerTemplate("web.TreeEditor.condition:editable", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.condition:editable" xml:space="preserve">
        <div class="o_tree_editor_condition d-flex flex-grow-1 align-items-end gap-2">
            <t t-call="web.TreeEditor.Editor">
                <t t-set="_classes" t-value="'col col-md-4 pe-0'"/>
                <t t-set="info" t-value="getPathEditorInfo()"/>
                <t t-set="value" t-value="node.path"/>
                <t t-set="update" t-value="(path) =&gt; this.updatePath(node, path)"/>
            </t>
            <t t-call="web.TreeEditor.Editor">
                <t t-set="_classes" t-value="'col col-md-2 px-3'"/>
                <t t-set="info" t-value="getOperatorEditorInfo(node)"/>
                <t t-set="value" t-value="[node.operator, node.negate]"/>
                <t t-set="update" t-value="(operator, negate) =&gt; this.updateLeafOperator(node, operator, negate)"/>
            </t>
            <t t-call="web.TreeEditor.Editor">
                <t t-set="_classes" t-value="'col ps-0 overflow-hidden'"/>
                <t t-set="info" t-value="getValueEditorInfo(node)"/>
                <t t-set="value" t-value="node.value"/>
                <t t-set="update" t-value="(value) =&gt; this.updateLeafValue(node, value)"/>
            </t>
        </div>
    </t>

    `);
registerTemplate("web.TreeEditor.complex_condition", `/web/static/src/core/tree_editor/tree_editor.xml`, `<t t-name="web.TreeEditor.complex_condition" xml:space="preserve">
        <div class="o_tree_editor_row d-flex align-items-center">
            <div class="o_tree_editor_complex_condition flex-grow-1">
                <input class="o_input w-100" t-att-value="node.value" t-att-readonly="props.readonly or !isDebugMode" t-on-change="(ev) =&gt; this.updateComplexCondition(node, ev.target.value)"/>
            </div>
            <t t-call="web.TreeEditor.controls"/>
        </div>
    </t>


`);
registerTemplate("web.TreeEditor.Input", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Input" xml:space="preserve">
        <input type="text" class="o_input" t-att-value="props.startEmpty ? '' : props.value" t-on-change="(ev) =&gt; props.update(ev.target.value)"/>
    </t>

    `);
registerTemplate("web.TreeEditor.Select", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Select" xml:space="preserve">
        <select class="o_input pe-3 text-truncate" t-on-change="(ev) =&gt; props.update(deserialize(ev.target.value))">
            <option t-if="props.addBlankOption" hidden="true"/>
            <t t-foreach="props.options" t-as="option" t-key="serialize(option[0])">
                <option t-att-value="serialize(option[0])" t-att-selected="!props.addBlankOption and option[0] === props.value" t-esc="option[1]"/>
            </t>
        </select>
    </t>

    `);
registerTemplate("web.TreeEditor.Range", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Range" xml:space="preserve">
        <div class="d-flex align-items-center">
            <t t-call="web.TreeEditor.Editor">
                <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/>
                <t t-set="info" t-value="props.editorInfo"/>
                <t t-set="value" t-value="props.value[0]"/>
                <t t-set="update" t-value="(val) =&gt; this.update(0, val)"/>
            </t>
            <i class="fa fa-long-arrow-right mx-2" aria-label="Arrow icon" title="Arrow"/>
            <t t-call="web.TreeEditor.Editor">
                <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/>
                <t t-set="info" t-value="props.editorInfo"/>
                <t t-set="value" t-value="props.value[1]"/>
                <t t-set="update" t-value="(val) =&gt; this.update(1, val)"/>
            </t>
        </div>
    </t>

    `);
registerTemplate("web.TreeEditor.Within", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.Within" xml:space="preserve">
        <div class="d-flex align-items-center gap-2">
            <t t-call="web.TreeEditor.Editor">
                <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/>
                <t t-set="info" t-value="props.amountEditorInfo"/>
                <t t-set="value" t-value="props.value[0]"/>
                <t t-set="update" t-value="(val) =&gt; this.update(0, val)"/>
            </t>
            <t t-call="web.TreeEditor.Editor">
                <t t-set="_classes" t-value="'overflow-hidden flex-grow-1'"/>
                <t t-set="info" t-value="props.optionEditorInfo"/>
                <t t-set="value" t-value="props.value[1]"/>
                <t t-set="update" t-value="(val) =&gt; this.update(1, val)"/>
            </t>
        </div>
    </t>

    `);
registerTemplate("web.TreeEditor.List", `/web/static/src/core/tree_editor/tree_editor_components.xml`, `<t t-name="web.TreeEditor.List" xml:space="preserve">
        <div class="o_input d-flex flex-wrap gap-1">
            <TagsList tags="tags"/>
            <div class="flex-grow-1">
                <t t-call="web.TreeEditor.Editor">
                    <t t-set="info" t-value="props.editorInfo"/>
                    <t t-set="value" t-value="props.editorInfo.defaultValue()"/>
                    <t t-set="update" t-value="(val) =&gt; this.update(val)"/>
                </t>
            </div>
        </div>
    </t>

`);
registerTemplate("web.login_user_switch", `/web/static/src/core/user_switch/user_switch.xml`, `<t t-name="web.login_user_switch" xml:space="preserve">
        <t t-if="state.users.length">
            <t t-if="state.displayUserChoice">
                <div class="oe_login_form o_user_switch user-select-none my-4" t-ref="root">
                    <p>Choose a user</p>
                    <div class="list-group my-3">
                        <t t-foreach="state.users" t-as="user" t-key="user_index">
                            <button type="button" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" t-on-click="() =&gt; this.fillForm(user.login)">
                                <span class="d-flex justify-content-begin align-items-center">
                                    <img class="o_avatar o_user_avatar rounded me-2" t-attf-src="{{getAvatarUrl(user)}}" t-att-alt="user.login"/>
                                    <t t-esc="user.name"/>
                                </span>
                                <i class="fa fa-times" title="Remove user from switcher" t-on-click.stop="() =&gt; this.remove(user)"/>
                            </button>
                        </t>
                    </div>
                    <button type="button" class="btn btn-link btn-sm w-100" t-on-click="() =&gt; this.fillForm()">
                        <i class="fa fa-user-circle-o"/> <span class="ms-1">Use another user</span>
                    </button>
                </div>
            </t>
            <t t-else="" t-portal="'label.form-label'">
                <button type="button" class="o_user_switch_btn btn btn-sm btn-link m-0 p-0" tabindex="1" t-on-click="() =&gt; this.toggleFormDisplay()">
                    Choose a user
                </button>
            </t>
        </t>
    </t>
`);
registerTemplate("point_of_sale.OdooLogo", `/point_of_sale/static/src/app/generic_components/odoo_logo/odoo_logo.xml`, `<t t-name="point_of_sale.OdooLogo" xml:space="preserve">
        <div t-attf-class="{{ props.class }}" t-attf-style="{{ props.style }}">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 919 495">
                <path d="M695,346a75,75,0,1,1,75-75A75,75,0,0,1,695,346Zm0-31a44,44,0,1,0-44-44A44,44,0,0,0,695,315ZM538,346a75,75,0,1,1,75-75A75,75,0,0,1,538,346Zm0-31a44,44,0,1,0-44-44A44,44,0,0,0,538,315Zm-82-45c0,41.9-33.6,76-75,76s-75-34-75-75.9S336.5,196,381,196c16.4,0,31.6,3.5,44,12.6V165.1c0-8.3,7.3-15.1,15.5-15.1s15.5,6.8,15.5,15.1Zm-75,45a44,44,0,1,0-44-44A44,44,0,0,0,381,315Z" t-attf-style="fill:{{ props.monochrome ? '#FFF' : '#8f8f8f' }}"/>
                <path d="M224,346a75,75,0,1,1,75-75A75,75,0,0,1,224,346Zm0-31a44,44,0,1,0-44-44A44,44,0,0,0,224,315Z" t-attf-style="fill:{{ props.monochrome ? '#FFF' : '#714b67' }}"/>
            </svg>
        </div>
    </t>
`);
registerTemplate("point_of_sale.OrderWidget", `/point_of_sale/static/src/app/generic_components/order_widget/order_widget.xml`, `<t t-name="point_of_sale.OrderWidget" xml:space="preserve">
        <t t-if="props.lines?.length">
            <div class="d-flex flex-column flex-grow-1 rounded-3 bg-white overflow-hidden">
                <div t-ref="scrollable" t-att-style="props.style" t-att-class="props.class" class="order-container d-flex flex-column flex-grow-1 overflow-y-auto text-start">
                    <t t-foreach="props.lines" t-as="line" t-key="line_index">
                        <t t-if="props.slots?.default" t-slot="default" line="line"/>
                        <Orderline t-else="" line="line"/>
                    </t>
                    <div class="mt-1 bg-opacity-75" t-attf-class="{{ props.screenName == 'ReceiptScreen' ? 'p-0' : 'p-2 border-bottom border-top border-opacity-75'}}" t-if="props.generalNote">
                        <b class="fw-bolder">General Note</b>
                        <t t-foreach="props.generalNote.split('\\n')" t-as="subNote" t-key="subNote_index">
                            <br/>• <t t-esc="subNote"/>
                        </t>
                    </div>
                </div>
                <t t-set="taxTotals" t-value="props.taxTotals"/>
                <div t-if="taxTotals" class="order-summary d-flex flex-column gap-1 px-3 py-2 border-top fw-bolder lh-sm">
                    <div t-if="taxTotals.has_tax_groups" class="tax-info subentry d-flex justify-content-between w-100 fs-6 text-muted">
                        Taxes
                        <div id="order-widget-taxes">
                            <span t-esc="formatMonetary(taxTotals.order_sign * taxTotals.tax_amount_currency, {currencyId: taxTotals.currency_id})" class="tax"/>
                        </div>
                    </div>
                    <div class="d-flex justify-content-between w-100 fs-2">
                        Total
                        <span t-esc="formatMonetary(taxTotals.order_sign * taxTotals.order_total, {currencyId: taxTotals.currency_id})" class="total"/>
                    </div>
                </div>
            </div>
            <t t-slot="details"/>
        </t>
        <t t-else="">
            <div t-if="!props.slots?.emptyCart" class="d-flex flex-column align-items-center justify-content-center flex-grow-1 bg-100 rounded-3 gap-3">
                <CenteredIcon icon="'fa-shopping-cart fa-4x'" text="emptyCartText()" class="'h-unset'"/>
                <t t-slot="details"/>
            </div>
            <t t-else="" t-slot="emptyCart"/>
        </t>
    </t>
`);
registerTemplate("point_of_sale.Orderline", `/point_of_sale/static/src/app/generic_components/orderline/orderline.xml`, `<t t-name="point_of_sale.Orderline" xml:space="preserve">
        <t t-set="line" t-value="props.line"/>
        <li class="orderline position-relative d-flex align-items-center p-2 lh-sm cursor-pointer" t-attf-class="{{ line.comboParent ? 'orderline-combo ms-4 fst-italic' : '' }}" t-att-class="props.class">
            <div class="product-order"/>
            <div t-if="line.imageSrc" class="o_line_container d-flex align-items-center justify-content-center">
                <img t-attf-style="border-radius: 1rem;" t-att-src="line.imageSrc"/>
            </div>
            <div class="d-flex flex-column w-100 gap-1">
                <div class="d-flex justify-content-between">
                    <div class="product-name d-inline-block flex-grow-1 fw-bolder pe-1 text-truncate">
                        <span class="text-wrap" t-esc="line.productName"/>
                        <t t-slot="product-name"/>
                    </div>
                    <div t-if="!props.basic_receipt" class="product-price price fw-bolder">
                        <t t-if="line.price === 'free'">Free</t>
                        <t t-else="" t-esc="line.price"/>
                    </div>
                    <div t-if="props.showTaxGroupLabels" t-esc="line.taxGroupLabels" class="text-end" style="width: 2rem"/>
                </div>
                <ul class="info-list d-flex flex-column">
                    <li class="price-per-unit">
                        <span class="qty px-1 border rounded text-bg-view fw-bolder me-1" t-esc="line.qty"/>
                        <t t-if="!props.basic_receipt">
                            x
                            <t t-if="line.price !== 0">
                                <s t-esc="line.oldUnitPrice" t-if="line.oldUnitPrice"/>
                                <t t-esc="line.unitPrice"/>
                            </t>
                            /
                        </t>
                        <t t-if="line.unit" t-esc="line.unit"/>
                    </li>
                    <li t-if="line.price !== 0 and line.discount and line.discount !== '0' and !props.basic_receipt">
                        <t t-esc="line.price_without_discount"/> With a <em><t t-esc="line.discount"/>% </em> discount
                    </li>
                    <li t-if="line.customerNote" class="customer-note w-100 p-2 mt-2 rounded text-break text-bg-warning bg-opacity-25">
                        <i class="fa fa-sticky-note me-1" role="img" aria-label="Customer Note" title="Customer Note"/>
                        <t t-esc="line.customerNote"/>
                    </li>
                    <div class="internal-note-container d-flex gap-2">
                        <t t-foreach="line.internalNote?.split?.('\\n') or []" t-as="note" t-key="note_index">
                            <li t-if="note.trim() !== ''" t-esc="note" class="internal-note badge mt-2 p-2 rounded-pill bg-info text-info bg-opacity-25" style="font-size: 0.85rem;"/>
                        </t>
                    </div>
                    <li t-foreach="line.packLotLines or []" t-as="lot" t-key="lot_index" t-esc="lot"/>
                    <t t-slot="default"/>
                </ul>
            </div>
        </li>
    </t>
`);
registerTemplate("point_of_sale.CustomerDisplay", `/point_of_sale/static/src/customer_display/customer_display.xml`, `<t t-name="point_of_sale.CustomerDisplay" xml:space="preserve">
        <t t-set="bgImgSrc" t-value="session.customer_display_bg_img ? 'url(/web/image/pos.config/' + pos.config.id + '/customer_display_bg_img)' : 'none'"/>
        <div class="o_customer_display d-flex h-100">
            <div class="o_customer_display_sidebar d-flex flex-column align-items-center justify-content-center gap-2 p-4 bg-view" t-att-style="session.has_bg_img ? \`background-image: url(/web/image/pos.config/\${session.config_id}/customer_display_bg_img); min-width: 30%; min-height: 15%;\` : \`\`">
                <div t-if="!session.has_bg_img" class="o_customer_display_logo d-flex mw-50 mw-md-100 p-2 rounded-3 bg-white">
                    <img class="img-fluid" t-attf-src="/logo?company={{session.company_id}}"/>
                </div>
                <div class="position-absolute bottom-0 mb-4 d-none d-lg-flex align-items-center ps-3 pe-2 py-1 rounded-3 text-bg-dark small">Powered by <OdooLogo style="'width: 3rem;'" monochrome="true"/></div>
            </div>
            <div class="o_customer_display_main d-flex flex-column flex-grow-1 overflow-auto">
                <OrderWidget t-if="!order.finalized" lines="order.lines" t-slot-scope="scope" class="'gap-0 p-0 mx-2 pb-3 bg-view'" style="'scroll-snap-type: y mandatory;'" generalNote="order.generalNote or ''">
                    <Orderline line="scope.line" class="{                             'o_customer_display_orderline bg-white fs-3 rounded-0': true,                             'selected': scope.line.isSelected                         }"/>
                    <t t-set-slot="emptyCart">
                        <div class="d-flex flex-column align-items-center justify-content-center h-100 w-100">
                            <h1 class="display-2 w-75 mt-2 fw-bold text-center text-muted">Welcome.</h1>
                        </div>
                    </t>
                </OrderWidget>
                <div t-else="" class="d-flex flex-column align-items-center justify-content-center h-100 w-100">
                    <h1 class="display-2 w-75 mt-2 fw-bold text-center text-muted">Thank you.</h1>
                </div>
                <div t-if="order.scaleData">
                    <t t-set-slot="header">
                        <h4 class="modal-title text-break text-center w-100" t-att-class="{ 'me-auto': env.isSmall }">
                            <span class="me-2">Weighing Product:</span>
                            <t t-esc="order.scaleData.product.name"/>
                        </h4>
                    </t>
                    <div class="d-flex flex-column px-3">
                        <div class="d-flex justify-content-between align-items-center mb-2">
                            <div class="w-60 fs-5 me-2 form-control-plaintext">Gross Weight:</div>
                            <div class="weight fs-5 js-weight text-end form-control-plaintext" t-esc="order.scaleData.grossWeight"/>
                        </div>
                        <div class="d-flex justify-content-between align-items-center mb-2">
                            <div class="w-60 fs-5 me-2 form-control-plaintext">Tare Weight:</div>
                            <div class="weight fs-5 js-weight text-end form-control-plaintext" t-esc="order.scaleData.tare"/>
                        </div>
                        <div class="d-flex justify-content-between align-items-center mb-2">
                            <div class="w-60 fs-5 me-2 form-control-plaintext">Net Weight:</div>
                            <div class="text-end fs-5 form-control-plaintext" t-esc="order.scaleData.netWeight"/>
                        </div>
                        <div class="d-flex px-5 flex-row gap-2 m-2 align-items-center">
                            <div class="product-price w-50 fs-5 text-center" t-esc="order.scaleData.unitPrice"/>
                            <div class="computed-price fd-flex flex-grow-1 p-2 rounded text-center text-bg-info bg-opacity-25 text-info fs-5 fw-bold" t-esc="order.scaleData.totalPrice"/>
                        </div>
                    </div>
                </div>

                <div t-if="order.amount and !order.finalized" class="py-3 px-4 bg-view border-top">
                    <div class="d-flex flex-column justify-content-center gap-1 w-100 w-sm-50 ms-auto">
                        <div class="row fs-2 fw-bolder">
                            <div class="col text-end">Total</div>
                            <div class="col text-end" t-esc="order.amount"/>
                        </div>
                        <div t-foreach="order.paymentLines or []" t-as="line" t-key="line_index" class="row">
                            <div class="col text-end" t-esc="line.name"/>
                            <div class="col text-end" t-esc="line.amount"/>
                        </div>
                        <div class="row" t-if="order.change">
                            <div class="col text-end">Change</div>
                            <div class="col text-end" t-esc="order.change"/>
                        </div>
                    </div>
                </div>
                <div class="d-flex justify-content-center" t-att-class="{ 'bg-view': order.amount and !order.finalized }">
                    <div class=" bottom-0 mb-4 d-flex align-items-center ps-3 pe-2 py-1 rounded-3 small">Powered by <OdooLogo style="'width: 3rem;'"/></div>
                </div>
            </div>
        </div>
        <MainComponentsContainer/>
    </t>
`);
registerTemplate("point_of_sale.CustomerFacingQR", `/point_of_sale/static/src/customer_display/customer_facing_qr.xml`, `<t t-name="point_of_sale.CustomerFacingQR" xml:space="preserve">
        <Dialog size="'md'" footer="false" header="false" bodyClass="'w-100 h-100 d-flex flex-column justify-content-center align-items-center'">
            <div class="text-center">
                <p t-out="title"/>
                <img class="pos-customer_payment_qr_code my-1" t-att-src="props.qrCode" alt="QR Code" style="width: 200px; height: 200px;"/>
            </div>
            <div class="text-center">
                <div>
                    <strong>Amount: </strong>
                    <span t-esc="props.amount"/>
                </div>
            </div>
        </Dialog>
    </t>
`);
registerTemplate("pos_online_payment.OnlinePaymentPopup", `/pos_online_payment/static/src/app/online_payment_popup/online_payment_popup.xml`, `<t t-name="pos_online_payment.OnlinePaymentPopup" xml:space="preserve">
        <Dialog title.translate="Scan to pay" footer="false" bodyClass="'w-100 h-100 d-flex flex-column justify-content-center align-items-center'">
            <p>Scan the QR code to pay</p>
            <img class="w-25 pb-3" t-att-src="props.qrCode" alt="QR Code to pay"/>
            <div class="amount">Amount: <t t-esc="props.formattedAmount"/></div>
            <div>Order reference: <t t-esc="props.orderName"/></div>
        </Dialog>
    </t>
`);
                    });
