We’re hiring!

A quick look at our tools

Our philosophy is simple — hire a team of diverse, passionate people and foster a culture that empowers you to do your best work.
If you're a lineholder, BidGrid is built for you.
Design
This is an incredibly powerful bidding tool.

BidGrid compares your bid against past awards and upcoming pairings to predict what you can hold.
‍
1. Research - Look at the past to get a picture of what you could have held.
2. Bid - Input your bid into BidGrid.
3. Sort - Use advance filtering to find the best of what you can hold.
4. Tag - Tag your favorites.
5. Batch Bid - Bid your favorites in one click.
Remote
Full-time
This tool is for the reserve guys.
Design
We’re looking for someone motivated and experienced to join our team.
Remote
Full-time
Product Designer
Design
We’re looking for someone motivated and experienced to join our team.
Remote
Full-time
Bid your Pairing IDs on Date in one click
Design
We’re looking for someone motivated and experienced to join our team.
Remote
Full-time
Vacation Pay Calculator
Design
We’re looking for someone motivated and experienced to join our team. We’re looking for someone motivated and experienced to join our team. We’re looking for someone motivated and experienced to join our team.
Remote
Full-time
Batch Bid
Design
We’re looking for someone motivated and experienced to join our team. We’re looking for someone motivated and experienced to join our team.We’re looking for someone motivated and experienced to join our team.We’re looking for someone motivated and experienced to join our team.We’re looking for someone motivated and experienced to join our team.
Remote
Full-time
Product Designer
Design
We’re looking for someone motivated and experienced to join our team.
Remote
Full-time
Product Designer
Design
We’re looking for someone motivated and experienced to join our team.
Remote
Full-time

Member Updates

September pairings are live!

September pairings are now live in BidGrid and ready for you to start building your bid.

Maintenance Notification

The system is under maintenance, sorry for the inconvenience.

NEW Tool Launch: Batch Bid

Zap your favorite Pairing IDs on Date that you tagged in BidGrid straight into PBS with one click. Learn how it works and watch a video here.

Reserve Legality Checker 2.0 (beta)

In this new beta version, you simply input how many days off you need (anywhere from 1 to 12) and we'll generate up to 50 legal solutions across three categories: weekend-off, short work-block, and long work-block. Check it out here.

Help Us Grow — Tell a Pilot

Every new pilot helps us build the next tool faster. If Bidliner's made your life easier, a quick mention to your copilot goes a long way and we really appreciate it.

We use third-party cookies in order to personalise your experience
Read our Cookie Policy.
Mockup

Lineholder pilots

Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.
Mockup

Reserve pilots

An all-in-one customer service platform that helps you balance everything your customers need to be happy.

Lineholder pilots,

Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.
Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.
Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.
Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.
Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.
An all-in-one customer service platform that helps you balance everything your customers need to be happy.

Reserve pilots,

An all-in-one customer service platform that helps you balance everything your customers need to be happy.
An all-in-one customer service platform that helps you balance everything your customers need to be happy.
An all-in-one customer service platform that helps you balance everything your customers need to be happy.
An all-in-one customer service platform that helps you balance everything your customers need to be happy.
An all-in-one customer service platform that helps you balance everything your customers need to be happy.
An all-in-one customer service platform that helps you balance everything your customers need to be happy.

All Pilots

Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.

Share team inboxes

Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.

Deliver instant answers

An all-in-one customer service platform that helps you balance everything your customers need to be happy.

Manage your team

Measure what matters with Untitled’s easy-to-use reports. You can filter, export, and drilldown on the data.

Connect with customers

Solve a problem or close a sale in real-time with chat. If no one is available, customers are seamlessly routed to email without confusion.
BidGrid™

Turn clear data into better bids with BidGrid

Ever wished for a crystal ball to predict your bidding success? BidGrid is your next best thing. It compares your practice bid against historic awards and upcoming pairings to predict what you can hold and find the best of what you can hold.

You don't like to fly blind so don't bid that way either. BidGrid crunches over 40 million data points to answer to the question, "Can I hold that pairing with my seniority?" Check out our latest update here!
40 million
Past awards segments analyzed
100%
Current pairings analyzed each month
Dashboard mockup
Credit card mockups

Share team inboxes

Whether you have a team of 2 or 200, our shared team inboxes keep everyone on the same page and in the loop.

Deliver instant answers

An all-in-one customer service platform that helps you balance everything your customers need to be happy.

Manage your team with reports

Measure what matters with Untitled’s easy-to-use reports. You can filter, export, and drilldown on the data in a couple clicks.
Resource library

Video resources

Learn new tips, strategies, property details and more for your bid. Created by an AA Pilot and PBS Helpdesk instructor who has reviewed 10,000+ bids.
BidGrid 101
2:44 min

10. Tagged Pairing Stats

Explore new features in tagged pairings.
Watch video
BidGrid 101
2:45 min

4. Browsing the Bid Sheet

Learn how to browse the upcoming month's bid pairings.
Watch video

Don’t just take our word for it

Hear from other AA pilots using the tools for their PBS bid.
"Bidliner is one of the BEST tools for any type of Pilot, whether you are junior or senior. This product allows you to see in real time a more in-depth understanding of what you are bidding along with some of the 'gotchas' PBS can be know for."
Barbara
AA First Officer
"Good system. User friendly. Works well on RSV trying to figure out if it’ll solve with your days off/on ratio and catch any gotchas. As for lineholder it does a good job showing me what's worth bidding for, and what I should not waste a bid layer on. I use it to show me my seniority and what I could hold 1 month ago, the last 3 months, the last 12 months, and the same month the previous year. Average those out and you have an idea of what trips are worth bidding. Used the videos a few times to help improve my bidding strategies. Overall I recommend it."
Alex
AA Pilot
"I wanted to let you know the batch bid worked perfectly. Pretty incredible tool for the way I bid"
Chad
AA Pilot
"I just want to say thank you to the entire team for making bidding so much easier. I am running the batch run now. This is amazing."
Larry
AA First Officer
"I was a help desk instructor for 8yrs. Bidliner is a solid product and BidGrid is a game changer and a must have."
Nick
737 Captain, PBS Help Desk Instructor
"Bidliner has been pretty helpful for me. Great for pbs bidding knowledge."
James
AA First Officer
"Hello Eric, I wanted to share a quick update on my April PBS award. I used the Sharp Shooting method you described in your videos. While I was initially hesitant to change my bidding strategy, I trusted your guidance and watched your video explanations repeatedly to fully understand the requirements. I'm happy to say I was awarded my Layer 1 bid, I couldn't believe it at first! I'll definitely be exploring ways to make my May bid even more tailored to my preferred flying. What you have created is a true innovation and game-changer for managing PBS. Thank you, Joe."
Joe
American Airlines Pilot
"Hi, I just used your product for the first time and it seems like it was spot on. I got pretty much what I was expecting thanks to your BidGrid tool!"
John
AA Pilot

What is Bidliner? Hear from our founder, former PBS Helpdesk instructor for 7+ years, and retired Captain.

Learn more about Bidliner in this 1:35 min video below.

Reserve pilots, check and build your bid with the Reserve Legality Checker.

Check for errors in your reserve bid. Know instantly if your bid contains errors and what those errors are. No more guessing.

Superior bids. Superior awards.

Powerful tools for American Airlines pilots bidding with PBS.

Batch Bid all your pairings in one click.

Tag your favorite trips by layer and send them directly into PBS with a one click.

No more spending 40–75 minutes searching for pairings and manually entering them into PBS. Batch Bid automates the process, saving time and making it easier to build a smarter bid.
Use advanced filters to find your favorite pairings.
Simply tag your favorites by layer.
Send them directly into PBS with a single click.
Use advanced filters to find your favorite pairings.
Tag your favorites by layer.
Send them all into PBS in one click.
const state={defMin:3,defMax:6,activeLayer:1,layers:{},entries:{},focusedDate:null,selectedCode:null,inputMode:"advance",month:null,labelYear:null};function defaultLayer(){return{line:"S",min:null,max:null,flyThrough:"",waive4off:!1,allowSingle:!1,waiveFirstDFP:!1}}function effectiveLayer(e){return null!=e.min&&null!=e.max?e:{...e,min:e.min??state.defMin,max:e.max??state.defMax}}function currentLayer(){return state.layers[state.activeLayer]}state.layers[1]=defaultLayer();const defMinRange=document.getElementById("defMinRange"),defMaxRange=document.getElementById("defMaxRange"),defMinNum=document.getElementById("defMinNum"),defMaxNum=document.getElementById("defMaxNum");function syncSetup(e){let t=parseInt(defMinRange.value),n=parseInt(defMaxRange.value);"minNum"===e&&(t=parseInt(defMinNum.value)||1),"maxNum"===e&&(n=parseInt(defMaxNum.value)||1),"minRange"===e&&(t=parseInt(defMinRange.value)),"maxRange"===e&&(n=parseInt(defMaxRange.value)),t=Math.min(Math.max(t,1),10),n=Math.min(Math.max(n,1),10),defMinRange.value=t,defMinNum.value=t,defMaxRange.value=n,defMaxNum.value=n,state.defMin=t,state.defMax=n;const o=state.layers[1];null!=o.min&&(o.min=Math.min(Math.max(o.min,t),n)),null!=o.max&&(o.max=Math.min(Math.max(o.max,t),n)),null!=o.min&&null!=o.max&&o.min>o.max&&(o.min=o.max),populateMinMaxSelects(),loadLayerIntoPanel(),document.getElementById("wbsLabel").textContent=`Work Block Size (Default: ${t}–${n})`}[["minRange",defMinRange],["maxRange",defMaxRange],["minNum",defMinNum],["maxNum",defMaxNum]].forEach(([e,t])=>t.addEventListener("input",()=>syncSetup(e))),document.querySelectorAll(".collapse-btn").forEach(e=>{e.addEventListener("click",()=>{const t=document.getElementById(e.dataset.target);t.classList.toggle("collapsed"),e.textContent=t.classList.contains("collapsed")?"+":"−"})}),document.getElementById("btnStartOver").addEventListener("click",()=>{confirm("Start over? This clears your bid and resets all settings to defaults.")&&(state.entries={},state.focusedDate=null,state.selectedCode=null,state.inputMode="advance",state.defMin=3,state.defMax=6,state.layers[1]=defaultLayer(),state.activeLayer=1,state.lastBidContext=null,document.getElementById("defMinRange").value=3,document.getElementById("defMinNum").value=3,document.getElementById("defMaxRange").value=6,document.getElementById("defMaxNum").value=6,document.querySelector('input[name="inputMode"][value="advance"]').checked=!0,document.querySelectorAll(".code-btn").forEach(e=>e.classList.remove("selected")),resetSolutionPools(),loadLayerIntoPanel(),syncSetup(),renderCalendar(),updateGlance(),hideErrors())});const panels={help:document.getElementById("helpPanel"),faq:document.getElementById("faqPanel")};function togglePanel(e){const t=panels[e],n="none"===t.style.display||""===t.style.display;Object.values(panels).forEach(e=>e.style.display="none"),t.style.display=n?"block":"none"}function renderPalette(){const e=document.getElementById("codePalette");e.innerHTML="",RLC_PALETTE.forEach(t=>{const n=document.createElement("div");n.className="code-btn cc-"+t.colorGroup,setDayCodeLabel(n,t.code),n.dataset.code=t.code,n.addEventListener("click",()=>onPaletteClick(t.code)),e.appendChild(n)})}function setDayCodeLabel(e,t){"OFFMUST"===t||"OFFPREFER"===t?(e.classList.add("stacked"),e.innerHTML=`${"OFFMUST"===t?"MUST":"PREFER"}OFF`):e.textContent=t}function onPaletteClick(e){state.selectedCode=e,document.querySelectorAll(".code-btn").forEach(t=>{t.classList.toggle("selected",t.dataset.code===e)}),state.focusedDate&&applyCodeToFocused(e)}function isExplicitOffCode(e){return e&&!isDutyCode(e)&&!isProratedCode(e)}function countExplicitDaysOff(){const e=(state.gridDates||[]).filter(e=>"month"===e.zone);let t=0,n=0;e.forEach(e=>{effectiveProratedAt(e.iso)&&t++;const o=getCode(e.iso);o&&isExplicitOffCode(o)&&n++});const o=e.length-t,{daysOff:a}=prorationLookup(o);return{daysOff:a,offCount:n}}function applyCodeToFocused(e){const t=state.focusedDate;if(!t)return;const n=(state.gridDates||[]).find(e=>e.iso===t);if(n&&"month"===n.zone&&isExplicitOffCode(e)){const e=getCode(t);if(!e||!isExplicitOffCode(e)){const{daysOff:e,offCount:t}=countExplicitDaysOff();if(t>=e)return void alert(`You've reached the maximum of ${e} days off for this month. Remove a day off before adding another.`)}}state.entries[t]={code:e,solved:!1},"advance"===state.inputMode&&advanceFocus(),renderCalendar(),updateGlance()}function advanceFocus(){const e=state.gridDates||[],t=e.findIndex(e=>e.iso===state.focusedDate);if(-1!==t){for(let n=t+1;n—',t.innerHTML='';for(let n=state.defMin;n<=state.defMax;n++){const o=document.createElement("option");o.value=n,o.textContent=n,e.appendChild(o);const a=document.createElement("option");a.value=n,a.textContent=n,t.appendChild(a)}}function loadLayerIntoPanel(){const e=currentLayer();populateMinMaxSelects(),document.querySelectorAll("#lineSeg button").forEach(t=>{t.classList.toggle("active",t.dataset.val===e.line)}),document.getElementById("layerMin").value=e.min??"",document.getElementById("layerMax").value=e.max??"",document.getElementById("flyThrough").value=e.flyThrough,document.getElementById("waive4off").checked=e.waive4off,document.getElementById("allowSingle").checked=e.allowSingle,document.getElementById("waiveFirstDFP").checked=e.waiveFirstDFP}function updateRestrictiveCaution(){const e=document.getElementById("layerMin").value,t=document.getElementById("layerMax").value,n=""!==e||""!==t;document.getElementById("restrictiveBidCaution").style.display=n?"block":"none"}function onWaiverChange(){Object.keys(state.entries).forEach(e=>{const t=state.entries[e];t&&"object"==typeof t&&"OFFPREFER"===t.code&&!1===t.solved&&delete state.entries[e]}),state.gridDates.forEach(e=>{const t=state.entries[e.iso];t&&t.solved&&delete state.entries[e.iso]}),solutionPools.weekends=null,solutionPools.longoff=null,solutionPools.balanced=null,state.lastBidContext=null,renderCalendar(),updateGlance()}function isoDate(e){return e.getFullYear()+"-"+String(e.getMonth()+1).padStart(2,"0")+"-"+String(e.getDate()).padStart(2,"0")}function addDays(e,t){const n=new Date(e);return n.setDate(n.getDate()+t),n}function fmtShort(e){return e.getMonth()+1+"/"+e.getDate()}function buildGrid(){const e=contractMonthStart(state.month,state.labelYear),t=addDays(e,contractMonthLength(state.month,state.labelYear)-1),n=addDays(e,-7),o=addDays(t,7),a=addDays(n,-n.getDay()),s=6-o.getDay(),l=addDays(o,s),i=[];let d=new Date(a);for(;d<=l;){const a=isoDate(d);let s;s=do?"outside":dt?"post-buffer":"month",i.push({date:new Date(d),iso:a,zone:s,editable:"outside"!==s}),d=addDays(d,1)}return state.gridDates=i,state.monthStart=e,state.monthEnd=t,state.monthIsoSet=new Set(i.filter(e=>"month"===e.zone).map(e=>e.iso)),i}function codeMeta(e){return MASTER_CODES[e]||null}function codeCategoryClass(e){const t=codeMeta(e);return t?"cc-"+(t.colorGroup||"nonProratedDuty"):""}document.getElementById("btnHelp").addEventListener("click",()=>togglePanel("help")),document.getElementById("btnFAQ").addEventListener("click",()=>togglePanel("faq")),document.querySelectorAll("#lineSeg button").forEach(e=>{e.addEventListener("click",()=>{currentLayer().line=e.dataset.val,document.querySelectorAll("#lineSeg button").forEach(t=>t.classList.toggle("active",t===e))})}),document.getElementById("layerMin").addEventListener("change",e=>{const t=currentLayer();t.min=""!==e.target.value?parseInt(e.target.value):null,null!=t.min&&null!=t.max&&t.min>t.max&&(t.max=t.min,document.getElementById("layerMax").value=t.max),updateRestrictiveCaution()}),document.getElementById("layerMax").addEventListener("change",e=>{const t=currentLayer();t.max=""!==e.target.value?parseInt(e.target.value):null,null!=t.min&&null!=t.max&&t.max{currentLayer().flyThrough=e.target.value}),document.getElementById("waive4off").addEventListener("change",e=>{currentLayer().waive4off=e.target.checked,onWaiverChange()}),document.getElementById("allowSingle").addEventListener("change",e=>{currentLayer().allowSingle=e.target.checked,onWaiverChange()}),document.getElementById("waiveFirstDFP").addEventListener("change",e=>{currentLayer().waiveFirstDFP=e.target.checked,onWaiverChange()});const MONTH_NAMES=["January","February","March","April","May","June","July","August","September","October","November","December"];function renderCalendar(){const e=buildGrid(),t=addDays(state.monthStart,7);document.getElementById("calMonthName").textContent=MONTH_NAMES[t.getMonth()],document.getElementById("calRange").textContent=fmtShort(state.monthStart)+" – "+fmtShort(state.monthEnd);const n=document.getElementById("calendarBody");n.innerHTML="";for(let t=0;t{state.focusedDate=a.iso,renderCalendar()}),o.appendChild(s)}n.appendChild(o)}}function shiftMonth(e){let t=state.month+e,n=state.labelYear;t<1&&(t=12,n-=1),t>12&&(t=1,n+=1),state.month=t,state.labelYear=n,state.focusedDate=null,renderCalendar(),updateGlance(),hideErrors()}function initTool(){renderPalette(),loadLayerIntoPanel();const e=new Date;let t=e.getMonth()+2,n=e.getFullYear();t>12&&(t-=12,n+=1),state.month=t,state.labelYear=n,renderCalendar(),updateGlance()}document.getElementById("navPrev").addEventListener("click",()=>{shiftMonth(-1)}),document.getElementById("navNext").addEventListener("click",()=>{shiftMonth(1)}),document.querySelectorAll('input[name="inputMode"]').forEach(e=>{e.addEventListener("change",()=>{state.inputMode=e.value})}),document.getElementById("btnCheckBid").addEventListener("click",()=>{const e=document.getElementById("btnCheckBid");e.disabled=!0,e.innerHTML='Thinking…',setTimeout(()=>{runCheckBid(),e.disabled=!1,e.textContent="Check Bid"},0)});const SOLUTION_COUNT_CAP=50,solutionPools={weekends:null,longoff:null,balanced:null},SOLVE_META={weekends:{label:"Weekends Off",navId:"navWeekends",posId:"posWeekends",prevId:"btnWkPrev",nextId:"btnWkNext"},longoff:{label:"Long Blocks of Days Off",navId:"navLongOff",posId:"posLongOff",prevId:"btnLoPrev",nextId:"btnLoNext"},balanced:{label:"Balanced (Short Work Blocks)",navId:"navBalanced",posId:"posBalanced",prevId:"btnBalPrev",nextId:"btnBalNext"}};function resetSolutionPools(){solutionPools.weekends=null,solutionPools.longoff=null,solutionPools.balanced=null;const e=document.getElementById("solutionMessage");e&&(e.style.display="none",e.textContent="");const t=document.getElementById("btnSolveDone");t&&(t.style.display="none"),Object.values(SOLVE_META).forEach(e=>{const t=document.getElementById(e.navId);t&&(t.style.display="none")});const n=document.getElementById("solveRows");n&&(n.style.display="none");const o=document.getElementById("solveSpinnerRow");o&&(o.style.display="none")}function scoreWeekends(e){return e.filter(e=>{const t=new Date(e+"T12:00:00");return 0===t.getDay()||6===t.getDay()}).length}function isNonDutyDay(e,t){return!(!t||!t.has(e))||!!getCode(e)&&!effectiveDutyAt(e)}function scoreLongOff(e){const t=new Set(e),n=state.gridDates.filter(e=>"month"===e.zone),o=[];let a=0;return n.forEach(e=>{isNonDutyDay(e.iso,t)?(a>0&&o.push(a),a=0):a++}),a>0&&o.push(a),0===o.length?0:o.reduce((e,t)=>e+t*t,0)}function scoreBalanced(e){const t=new Set(e),n=state.gridDates.filter(e=>"month"===e.zone),o=[];let a=0;if(n.forEach(e=>{isNonDutyDay(e.iso,t)?(a>0&&o.push(a),a=0):a++}),a>0&&o.push(a),0===o.length)return 0;const s=o.reduce((e,t)=>e+t,0)/o.length,l=o.reduce((e,t)=>e+(t-s)**2,0)/o.length;return-(s+Math.sqrt(l))}function collectAndSortSolutions(e,t){const n=[],o=[],a=state.lastBidContext,s=effectiveLayer(a.L);for(;n.length=t,i="weekends"===e?scoreWeekends:"longoff"===e?scoreLongOff:scoreBalanced;return n.sort((e,t)=>{const n=i(t)-i(e);return 0!==n?n:scoreWeekends(t)-scoreWeekends(e)}),{solutions:n,count:n.length,capped:l}}function updateNavUI(e){const t=solutionPools[e],n=SOLVE_META[e];if(!t)return;const o=document.getElementById(n.navId),a=document.getElementById(n.posId),s=document.getElementById(n.prevId),l=document.getElementById(n.nextId);if(!o)return;o.style.display="flex";const i=t.capped?"50+":String(t.count);a.textContent=t.index>=0?`${t.index+1} / ${i}`:`0 / ${i}`,s.disabled=t.index<=0,l.disabled=t.index>=t.solutions.length-1}function applyPoolSolution(e,t){Object.keys(state.entries).forEach(e=>{const t=state.entries[e];t&&"object"==typeof t&&"OFFPREFER"===t.code&&!1===t.solved&&delete state.entries[e]}),t.forEach(e=>{state.entries[e]={code:"OFFPREFER",solved:!1}}),runSolver(),renderCalendar(),document.getElementById("btnSolveDone").style.display="inline-block",updateNavUI(e);const n=document.getElementById("solutionMessage");n&&(n.style.display="none")}function rebuildPoolIfNeeded(e){if(solutionPools[e])return;if(state.lastBidContext)state.lastBidContext.L=currentLayer();else{const e=currentLayer(),t=state.gridDates.filter(e=>"month"===e.zone);let n=0,o=0;t.forEach(e=>{effectiveProratedAt(e.iso)&&n++,effectiveDutyAt(e.iso)&&o++});const a=t.length-n,{daysOff:s,fourDay:l}=prorationLookup(a);state.lastBidContext={L:e,fourDay:l,available:a,daysOff:s,actualOff:t.length-n-o}}const{solutions:t,count:n,capped:o}=collectAndSortSolutions(e,50);solutionPools[e]={solutions:t,index:-1,count:n,capped:o},updateNavUI(e)}function stepSolution(e,t){rebuildPoolIfNeeded(e);const n=solutionPools[e],o=SOLVE_META[e],a=document.getElementById("solutionMessage");if(!n||0===n.solutions.length)return void(a&&(a.style.display="block",a.textContent=`No "${o.label}" solution found with current settings. Try a different style or adjust your waivers.`));const s=n.index+t;s<0||s>=n.solutions.length?a&&s>=n.solutions.length&&(a.style.display="block",a.textContent=`You've seen all ${n.solutions.length} "${o.label}" solution${1===n.solutions.length?"":"s"}. Try a different style or press Done.`):(n.index=s,applyPoolSolution(e,n.solutions[n.index]))}function initSolveUI(){const e=document.getElementById("solveSpinnerRow"),t=document.getElementById("solveRows");e.style.display="flex",t.style.display="none",setTimeout(()=>{["weekends","longoff","balanced"].forEach(e=>{const{solutions:t,count:n,capped:o}=collectAndSortSolutions(e,50);solutionPools[e]={solutions:t,index:-1,count:n,capped:o},updateNavUI(e)}),e.style.display="none",t.style.display="block"},0)}function getCode(e,t){const n=state.entries[e];return n?n.code:state.monthIsoSet&&state.monthIsoSet.has(e)?"RSV":null}function isDutyCode(e){if(!e)return!1;const t=MASTER_CODES[e];return!!t&&!!t.duty}function isProratedCode(e){if(!e)return!1;const t=MASTER_CODES[e];return!!t&&!!t.prorated}function classify15(e){const t=state.gridDates,n=t.findIndex(t=>t.iso===e);if(n<=0)return null;const o=t[n-1].iso,a=getCode(o);return"CQT"===a?"travel":"15"===a&&"travel"===classify15(o)?"dutyfree":null}function effectiveDutyAt(e){const t=getCode(e);if("15"===t){const t=classify15(e);if("travel"===t)return!0;if("dutyfree"===t)return!1}return isDutyCode(t)}function effectiveProratedAt(e){const t=getCode(e);if("15"===t){const t=classify15(e);if("travel"===t||"dutyfree"===t)return!1}return isProratedCode(t)}function resolveLineCode(e){switch(e){case"L":case"L-S":return"TRL";default:return"TRS"}}function runSolver(){const e=[],t=effectiveLayer(currentLayer()),n=state.gridDates;n.forEach(e=>{const t=state.entries[e.iso];t&&t.solved&&delete state.entries[e.iso]});const o=n.findIndex(e=>isoDate(state.monthEnd)===e.iso);if(-1===o)return e;let a=0;for(let e=o;e>=0&&effectiveDutyAt(n[e].iso);e--)a++;if(0===a||a>=t.min)return e;const s=t.min-a,l=""===t.flyThrough?1/0:parseInt(t.flyThrough);if(0===l)return e;const i=Math.min(s,l,n.length-o-1),d=resolveLineCode(t.line);for(let e=1;e<=i;e++){const t=n[o+e];if(!t||"post-buffer"!==t.zone)break;state.entries[t.iso]={code:d,solved:!0}}return i"outside"!==e.zone),t=[];let n=null,o=0,a=!1;return e.forEach((s,l)=>{const i=effectiveDutyAt(s.iso);i&&(0===o&&(n=l),o++,"month"===s.zone&&(a=!0)),i&&l!==e.length-1||(o>0&&a&&t.push({startIso:e[n].iso,endIso:e[l===e.length-1&&i?l:l-1].iso,length:o}),o=0,a=!1)}),t}function checkBufferGaps(){const e=[],t=e=>{const t=new Date(e+"T00:00:00");return t.getMonth()+1+"/"+t.getDate()+"/"+t.getFullYear()},n=isoDate(state.monthStart),o=isoDate(state.monthEnd),a=effectiveDutyAt(n),s=effectiveDutyAt(o),l=state.gridDates.filter(e=>"pre-buffer"===e.zone),i=l.findIndex(e=>null!==getCode(e.iso));if(a&&-1!==i){const n=l.slice(i);n.some(e=>null===getCode(e.iso))&&e.push(`You entered a code on ${t(n[0].iso)}, in the month before your bid month, but left other days blank between ${t(n[0].iso)} and ${t(l[l.length-1].iso)} (the last day of that month). Because a Work Block that crosses into your bid month is evaluated as one continuous block, please enter a code (duty or day off) for every day from ${t(n[0].iso)} through ${t(l[l.length-1].iso)}.`)}const d=state.gridDates.filter(e=>"post-buffer"===e.zone);let r=-1;for(let e=d.length-1;e>=0;e--)if(null!==getCode(d[e].iso)){r=e;break}return s&&-1!==r&&d.slice(0,r+1).some(e=>null===getCode(e.iso))&&e.push(`You entered a code on ${t(d[r].iso)}, in the month after your bid month, but left other days blank between ${t(d[0].iso)} and ${t(d[r].iso)}. Because a Work Block that crosses out of your bid month is evaluated as one continuous block, please enter a code (duty or day off) for every day from ${t(d[0].iso)} through ${t(d[r].iso)}.`),e}function countSingleDaysOff(){const e=state.gridDates.filter(e=>"outside"!==e.zone),t=isoDate(state.monthStart),n=isoDate(state.monthEnd);let o=0;const a=[];for(let s=0;s0&&effectiveDutyAt(e[s-1].iso),d=s0&&!effectiveDutyAt(e[s-1].iso)&&null!==getCode(e[s-1].iso),c=s=t&&l.iso<=n))continue;const u=i||d,f=l.iso===n;l.iso===t&&s>0&&getCode(e[s-1].iso)&&!effectiveDutyAt(e[s-1].iso)&&!u||(f||u)&&(o++,a.push(l.iso))}return{count:o,isos:a}}function longestOffBlock(){const e=state.gridDates.filter(e=>"month"===e.zone);let t=0,n=0;return e.forEach(e=>{effectiveDutyAt(e.iso)||effectiveProratedAt(e.iso)?n=0:(n++,t=Math.max(t,n))}),t}function checkFirstDayDFP(){const e=state.gridDates,t=isoDate(state.monthStart),n=e.findIndex(e=>e.iso===t);if(n<=0)return!1;const o=e[n-1].iso,a=null!==getCode(o)&&!effectiveDutyAt(o),s=n>=2&&effectiveDutyAt(e[n-2].iso);return!(!a||!s||null!==getCode(t)&&!effectiveDutyAt(t))}function checkScheduleRules(e,t,n){e=effectiveLayer(e);const o=[];findWorkBlocks().forEach(t=>{const n=new Date(t.endIso+"T00:00:00"),a=n.getMonth()+1+"/"+n.getDate()+"/"+n.getFullYear();if(t.length>e.max)o.push(`You have a 'Work Block' ending on ${a} that is ${t.length} days long which is longer than allowed by the dashboard or your user preferences.`);else if(t.length8&&!e.waive4off&&longestOffBlock()<4&&o.push("You must bid 4 consecutive days off or check the 'Waive Reserve Block of 4 Days Off' box.");const a=countSingleDaysOff(),s=e.allowSingle?1:0;if(a.count>s){const t=a.isos.map(e=>{const t=new Date(e+"T00:00:00");return t.getMonth()+1+"/"+t.getDate()+"/"+t.getFullYear()}),n=a.isos.length>1,l=t.join(", ");let i;i=e.allowSingle||1!==a.count?` Adjust your bid on ${l} so ${n?"those days off are":"that day off is"} part of a longer block of days off (or ${n?"they are":"it is"} converted to duty/RSV day${n?"s":""}).`:` This could be fixed by checking the 'Allow 1 Single Reserve Day Off' waiver, or by adjusting your bid on ${l} so that day off is part of a longer block of days off (or is converted to a duty/RSV day).`,o.push(`You are only allowed ${1===s?"1 instance":"0 instances"} of a Single Reserve Day Off.${i}`)}return!e.waiveFirstDFP&&checkFirstDayDFP()&&o.push("Based on your indicated duty and single day off at the end of last month, you need to select 'Waive First Day of Month DFP'."),o}document.getElementById("btnSolveWeekends").addEventListener("click",()=>stepSolution("weekends",1)),document.getElementById("btnSolveLongOff").addEventListener("click",()=>stepSolution("longoff",1)),document.getElementById("btnSolveBalanced").addEventListener("click",()=>stepSolution("balanced",1)),document.getElementById("btnWkPrev").addEventListener("click",()=>stepSolution("weekends",-1)),document.getElementById("btnWkNext").addEventListener("click",()=>stepSolution("weekends",1)),document.getElementById("btnLoPrev").addEventListener("click",()=>stepSolution("longoff",-1)),document.getElementById("btnLoNext").addEventListener("click",()=>stepSolution("longoff",1)),document.getElementById("btnBalPrev").addEventListener("click",()=>stepSolution("balanced",-1)),document.getElementById("btnBalNext").addEventListener("click",()=>stepSolution("balanced",1)),document.getElementById("btnSolveDone").addEventListener("click",()=>{document.getElementById("suggestionBox").style.display="none",runCheckBid()}),document.getElementById("btnClearCalendar").addEventListener("click",()=>{confirm("Clear the calendar? This removes all entered codes for this layer's view.")&&(state.entries={},state.focusedDate=null,state.selectedCode=null,document.querySelectorAll(".code-btn").forEach(e=>e.classList.remove("selected")),renderCalendar(),updateGlance(),hideErrors())});const FEASIBILITY_NODE_LIMIT=1e5,FEASIBILITY_OFF_CODE="OFF";function checkPrefixStreaks(e,t,n,o){n=effectiveLayer(n);let a=0,s=!1;for(let l=0;l<=o;l++)if(void 0===t[l]?effectiveDutyAt(e[l].iso):t[l]){if(a++,"month"===e[l].zone&&(s=!0),s&&a>n.max)return!1}else{if(s&&a>0&&a=0;o--)return!1===(void 0!==t[o]?t[o]:effectiveDutyAt(e[o].iso));return!1}return!0}function searchFeasibleCompletion(e,t,n,o,a,s={}){const l=s.bias||"default",i=s.exclude||[],d=state.gridDates.filter(e=>"outside"!==e.zone),r=[];d.forEach((e,t)=>{"month"===e.zone&&void 0===state.entries[e.iso]&&r.push(t)});const c=o-a;if(c<0||c>r.length)return{feasible:!1,reason:"impossible"};const u=new Array(d.length);let f=0,y=null;return function o(a,s){if(y||f++>FEASIBILITY_NODE_LIMIT)return;if(s>c)return;if(s+(r.length-a)!1===u[e]).map(e=>d[e].iso));if(i.some(t=>t.size===e.size&&[...t].every(t=>e.has(t))))return}return void(function(){const o=[];r.forEach(e=>{!1===u[e]&&(state.entries[d[e].iso]={code:FEASIBILITY_OFF_CODE,solved:!1},o.push(d[e].iso))});const a=0===checkScheduleRules(e,t,n).length;return o.forEach(e=>delete state.entries[e]),a}()&&(y=u.slice()))}const m=r[a],h=preferOffAt(d,u,m,l)?[!1,!0]:[!0,!1];for(const t of h){if(y)return;!1===t&&s+1>c||(u[m]=t,checkPrefixStreaks(d,u,e,m)&&o(a+1,s+(!1===t?1:0)))}u[m]=void 0}(0,0),y?{feasible:!0,isos:r.filter(e=>!1===y[e]).map(e=>d[e].iso)}:{feasible:!1,reason:f>FEASIBILITY_NODE_LIMIT?"search_limit":"infeasible"}}function findFeasibleCompletion(e,t,n,o,a){return searchFeasibleCompletion(e,t,n,o,a)}function findBiasedSolution(e,t=[]){const n=state.lastBidContext;if(!n)return{feasible:!1,reason:"no_context"};const{L:o,fourDay:a,available:s,daysOff:l,actualOff:i}=n;if("weekends"===e)return searchFeasibleCompletion(o,a,s,l,i,{bias:"weekends",exclude:t});if("longoff"===e)return searchFeasibleCompletion(o,a,s,l,i,{bias:"continuation",exclude:t});if("balanced"===e){const e=effectiveLayer(o);let n={feasible:!1,reason:"infeasible"};for(let o=Math.max(3,e.min);o<=e.max;o++)if(n=searchFeasibleCompletion(o===e.max?e:{...e,max:o},a,s,l,i,{bias:"default",exclude:t}),n.feasible)return n;return n}return{feasible:!1,reason:"unknown_type"}}function runCheckBid(){resetSolutionPools();const e=currentLayer(),t=[];t.push(...runSolver()),renderCalendar();const n=state.gridDates.filter(e=>"month"===e.zone),o=n.length;let a=0,s=0,l=0;n.forEach(e=>{const t=getCode(e.iso);effectiveProratedAt(e.iso)&&a++,effectiveDutyAt(e.iso)&&(s++,"RSV"!==t&&"TRS"!==t&&"TRL"!==t||l++)});const i=o-a,{daysOff:d,fourDay:r}=prorationLookup(i),c=i-d,u=o-a-s;if(state.lastStats={requiredRSV:c,rsvDays:l,daysOff:d,actualOff:u,proratedDays:a,available:i},t.push(...checkBufferGaps()),state.lastBidContext=null,u>d)t.push(`You need to bid ${d} days off.`);else if(u{const t=document.createElement("li");"object"==typeof e&&null!==e?(t.textContent=e.text,"warning"===e.level&&t.classList.add("warning")):t.textContent=e,n.appendChild(t)}));const s=document.getElementById("suggestionBox");if(s){s.style.display=state.lastBidContext?"block":"none";const e=document.getElementById("solutionMessage");e&&(e.style.display="none"),state.lastBidContext&&initSolveUI()}}function hideErrors(){document.getElementById("errorPanel").style.display="none"}function updateGlance(){const e=state.gridDates.filter(e=>"month"===e.zone),t=e.length;let n=0,o=0,a=0;e.forEach(e=>{const t=getCode(e.iso);effectiveProratedAt(e.iso)&&n++,effectiveDutyAt(e.iso)&&(o++,"RSV"!==t&&"TRS"!==t&&"TRL"!==t||a++)});const s=t-n,{daysOff:l}=prorationLookup(s),i=s-l,d=t-n-o;document.getElementById("gl-required").textContent=i,document.getElementById("gl-actual").textContent=a,document.getElementById("gl-off").textContent=`${d} / ${l}`,document.getElementById("gl-prorated").textContent=n}initTool(); const RLC_PALETTE=[{code:"FLY",label:"FLY",category:"duty",colorGroup:"nonProratedDuty",duty:!0,prorated:!1,pay:"5:15",paid:!0},{code:"VC",label:"VC",category:"duty",colorGroup:"proratedLeave",duty:!1,prorated:!0,pay:"4:35",paid:!0},{code:"TRL",label:"TRL",category:"duty",colorGroup:"nonProratedDuty",duty:!0,prorated:!1,pay:"4:03",paid:!0},{code:"VS",label:"VS",category:"duty",colorGroup:"proratedLeave",duty:!1,prorated:!0,pay:null,paid:!0},{code:"TRS",label:"TRS",category:"duty",colorGroup:"nonProratedDuty",duty:!0,prorated:!1,pay:"4:13",paid:!0},{code:"RT",label:"RT",category:"duty",colorGroup:"nonProratedDuty",duty:!0,prorated:!1,pay:null,paid:!0},{code:"RSV",label:"RSV",category:"rsv",colorGroup:"rsv",duty:!0,prorated:!1,pay:null,paid:!0},{code:"OFFMUST",label:"OFF Must",category:"offmust",colorGroup:"daysOff",duty:!1,prorated:!1,pay:"0:00",paid:!1},{code:"CQT",label:"CQT",category:"duty",colorGroup:"nonProratedDuty",duty:!0,prorated:!1,pay:"4:00",paid:!0},{code:"OFFPREFER",label:"OFF Prefer",category:"offprefer",colorGroup:"offprefer",duty:!1,prorated:!1,pay:"0:00",paid:!1},{code:"SA",label:"SA",category:"duty",colorGroup:"nonProratedDuty",duty:!0,prorated:!1,pay:null,paid:!0},{code:"MIL",label:"MIL",category:"duty",colorGroup:"proratedLeave",duty:!1,prorated:!0,pay:"0:00",paid:!1},{code:"R2",label:"R2",category:"duty",colorGroup:"nonProratedDuty",duty:!0,prorated:!1,pay:null,paid:!0},{code:"OE",label:"OE",category:"duty",colorGroup:"proratedTraining",duty:!1,prorated:!0,pay:null,paid:!0},{code:"TNG",label:"TNG",category:"duty",colorGroup:"proratedTraining",duty:!0,prorated:!0,pay:"4:00",paid:!0},{code:"AT",label:"AT",category:"duty",colorGroup:"proratedTraining",duty:!1,prorated:!0,pay:null,paid:!0},{code:"DFP",label:"DFP",category:"duty",colorGroup:"daysOff",duty:!1,prorated:!1,pay:"0:00",paid:!1},{code:"2Q",label:"2Q",category:"duty",colorGroup:"nonProratedDuty",duty:!0,prorated:!1,pay:null,paid:!0},{code:"15",label:"15",category:"duty",colorGroup:"daysOff",duty:!1,prorated:!0,pay:null,paid:null},{code:"VEX",label:"VEX",category:"duty",colorGroup:"daysOff",duty:!1,prorated:!1,pay:"0:00",paid:!1},{code:"OFF",label:"OFF",category:"duty",colorGroup:"daysOff",duty:!1,prorated:!1,pay:"0:00",paid:!1}],ABSENCE_CODE_ROWS=[["05","TYPE 5",!1,!0,null],["0A","AAMP",!0,!1,!0],["0D","CA UPGD",!0,!1,!0],["0G","GPS GS",!0,!1,!0],["0I","INITTR",!0,!1,!0],["0M","MEX GS",!0,!1,!0],["0O","OTHERTR",!0,!1,!0],["0P","TRAINING",!0,!1,!0],["0Q","REQ6MORE",!0,!1,!0],["0T","TRANSTR",!1,!0,!0],["0U","UPGRADTR",!1,!0,!0],["0V","OBSRIDE",!1,!0,!0],["11","117.11",!1,!0,null],["13","PAID ADJ",!1,!1,!0],["17","117.17",!1,!0,null],["19","117.19A2",!1,!0,null],["1I","INITREM",!1,!0,!0],["1R","CRRETRNG",!0,!1,!0],["1T","TRANSREM",!1,!0,!0],["1U","UPGRDREM",!1,!0,!0],["25","117.25",!1,!0,null],["27","117.27",!1,!0,null],["2I","INITTR",!1,!0,!0],["2N","INT5LESS",!0,!1,!0],["2R","RECURRNT",!0,!1,!0],["2T","FR TRNG",!0,!1,!0],["2U","UPGRADTR",!0,!1,!0],["30","30 HRS",!1,!0,null],["31","777INST",!1,!1,!0],["32","INST SCH",!1,!1,!0],["35","S80INST",!1,!1,!0],["38","300INST",!1,!1,!0],["3B","117.23B",!1,!0,null],["3C","117.23C",!1,!0,null],["5B","117.25B",!1,!0,null],["6B","V6BUYBCK",!1,!0,!1],["6G","REGFL V6",!1,!0,!0],["6M","REGFL V6",!1,!0,!0],["70","TEMPFS",!1,!1,!0],["72","TEMPCA",!1,!1,!0],["7D","7 DAYS",!1,!0,!1],["85","SECURITY",!0,!1,!0],["AA","APPEND A",!1,!0,null],["AE","AWT OE",!1,!0,!0],["AF","ADDFLY",!1,!0,null],["AI","AWT NHTR",!1,!0,!0],["AL","UN LV",!1,!0,!1],["AM","ALTMONTH",!1,!0,!1],["AN","PSP2RTN",!1,!0,!1],["AQ","AWT SCTR",!1,!0,!0],["AS","ASAP",!0,!1,!0],["AT2","AWT LCTR",!1,!0,!0],["AW","AWTGPT",!1,!0,!0],["BR","BEREAVEM",!1,!1,!0],["C7","ROILGLTY",!1,!0,null],["CD","DISPDC/A",!1,!0,null],["CH","CHG OVR",!1,!0,null],["CL","CLEANUP",!1,!0,null],["CM","COM TM",!1,!0,!1],["CO","CONFLICT",!1,!0,null],["CS","CASICKPD",!1,!0,!0],["CT","CTL TRNG",!0,!1,!0],["DB","117.15",!1,!0,null],["DC","DIRCON",!1,!0,null],["DE","DECEASED",!1,!0,!1],["DI","DOM-INTL",!0,!1,!0],["DL","RSTDTYL",!1,!0,!0],["DM","RSTDTYM2",!1,!0,!0],["DN","DISPIENC",!1,!0,null],["DO","DAY OFF",!1,!1,!0],["DP","DISPD",!1,!0,null],["DR","RSTDTY",!1,!0,!0],["DT","DISPD IE",!1,!0,null],["DU","FMDL",!1,!0,!1],["EE","EMP RQST",!1,!0,!1],["EF","ERLY FUR",!1,!0,!1],["EM","ACTOFGOD",!1,!0,!1],["EO","ER NOCR",!1,!0,!1],["ES","ESB RMV",!1,!0,!0],["F6","REGFL V6",!1,!0,!0],["FC","FARLIMIT",!1,!0,null],["FG","INTFL UP",!1,!0,!1],["FL","REGFL UP",!1,!0,!1],["FM","REGFL UP",!1,!0,!1],["FR","FURLOUGH",!1,!0,!1],["FS","REGFL SK",!1,!0,!0],["FT","FATIGUED",!1,!0,!0],["FV","REGFL VC",!1,!0,!0],["G6","REGFL V6",!1,!0,!0],["GF","REGFL UP",!1,!0,!1],["GM","INTFL UP",!1,!0,!1],["GS","TRNRSIM",!1,!0,!1],["GV","REGFL VC",!1,!0,!0],["HR","EMPORIEN",!0,!1,!0],["I6","REGFL V6",!1,!0,!0],["IE","INOPTEXP",!1,!0,null],["IF","PUIFNDED",!1,!0,!0],["IH","PARPYIOD",!1,!0,!0],["IP","CP IOD",!1,!0,!0],["IS","REGFL SK",!1,!0,!0],["IU","UNPD IOD",!1,!0,!0],["IV","REGFL VC",!1,!0,!0],["JD","JURYDUTY",!1,!1,!0],["LB","ILGLBK",!1,!0,null],["LC2","AWTGDIVC",!1,!0,!1],["LE","IOEPAID",!1,!1,!0],["LF","INTFL UP",!1,!0,!1],["LK","DODSRD",!1,!0,null],["LL","LLREMOVL",!1,!0,null],["LP","PARENTLV",!1,!0,!0],["LS","LOSAUDIT",!0,!1,!0],["LV","VOLLEAVE",!1,!0,!1],["M1","ADPLOA",!1,!0,!1],["M2","SKLONG",!1,!0,!0],["M3","UPMTY",!1,!0,!0],["M4","ULOA",!1,!0,!1],["MA","MISDASMT",!1,!0,!1],["MC","MISCON",!1,!0,null],["MD","MDSB",!1,!0,!0],["MF","IMTFL UP",!1,!0,!1],["MG","REGFL UP",!1,!0,!1],["MI","MEDIND",!1,!0,null],["ML","CRMLOA",!1,!0,!1],["MN","RSVUMLOA",!1,!0,!1],["MO","MLTYLV",!1,!0,!1],["MR","MLTYWKND",!1,!0,!1],["MS","MLSKSHRT",!1,!0,!0],["MT","MISSED",!1,!0,!1],["MV","MIL PVD",!1,!0,!0],["MX","UNCRMLOA",!1,!0,!1],["MY","MLTYLV17",!1,!0,!1],["ND","NEED T O",!1,!1,!0],["NE","117.19NO",!1,!0,!1],["NF","NOTFIT",!1,!0,!0],["NS","NO SHOW",!1,!0,!1],["OE2","OEBLOCK",!1,!0,!0],["ON","ON DUTY",!1,!0,null],["OP","OVRPROJ",!1,!0,null],["OT","TTOTTRAD",!1,!0,null],["OX","DISPD OE",!1,!0,null],["P6","V6 PE",!1,!0,!0],["PD","PD DISPD",!1,!0,null],["PI","INSTR PI",!0,!1,!0],["PL","PLOA",!1,!0,!1],["PP","PAYPROT",!1,!0,null],["PR","PROB",!0,!1,!0],["PT","LOA10-02",!1,!0,!1],["PU","PDUNLV",!1,!1,!0],["PW","PDWITHLD",!1,!0,!0],["PX","PAID TFR",!1,!1,!0],["QD","NEEDSDOC",!1,!0,null],["QE","QUALEXPR",!1,!0,!0],["QI","NOT QUAL",!1,!0,!0],["R6","XTRAVCDY",!1,!0,!0],["RA","TYPE 1",!1,!0,null],["RD","RPL DFP",!1,!0,null],["RE","RESIGNED",!1,!0,!1],["RI","RCURIOD",!1,!0,!0],["RL","RELEASED",!1,!0,!1],["RM","RMVUNPD",!1,!0,null],["RT2","RETIRED",!1,!0,!1],["S2","C19 SHOT",!1,!1,!0],["S6","SCHL PVD",!1,!0,!0],["SA2","SPCASSGN",!0,!1,!0],["SD","SEQDROP",!1,!0,null],["SF","SIM FILL",!0,!1,!0],["SI","SKIFNDED",!1,!0,!1],["SK","SICK",!1,!0,!0],["SL","SLOA",!1,!0,!0],["SN","SCHLUNPD",!1,!0,!1],["ST","SHRDTRIP",!1,!0,null],["SU","SUSPEND",!1,!0,!1],["SV","SCHOOLPD",!1,!0,!0],["T6","TTOTPVD",!1,!0,!0],["TC","COM MT",!1,!0,!1],["TE","TRNGOFF",!1,!0,!0],["TI","TRNGOFF",!1,!0,!0],["TM","MISSTRIP",!1,!0,!1],["TO","TRFF",!1,!0,!0],["TQ","TRFF OE",!1,!0,!0],["TT","TRIPTRAD",!1,!0,null],["TW","TWA MTG",!1,!1,!0],["TX","UNPD TFR",!1,!0,!1],["U8","U8",!1,!0,!0],["UA","UNPLOA",!1,!0,!1],["UD","UCMENTOR",!1,!0,!0],["UI","RECUR IU",!1,!0,!0],["UL","PDUNLVNC",!0,!1,!0],["UM","UPSMTNY",!1,!0,!0],["UR","UNABLRPT",!1,!0,!1],["US","UNPD SK",!1,!0,!0],["V1","CUR VC",!1,!0,!0],["V2","ACCRU VC",!1,!0,!0],["V6","P VACDAY",!1,!0,!0],["V8","8 IN 24",!1,!0,null],["VA","V6HURCAN",!1,!0,!0],["VB","VCBANK",!1,!0,!0],["VC2","VACATION",!1,!0,!0],["VG","REGFL VC",!1,!0,!0],["VL","VELOA",!1,!0,!1],["VM","REGFL VC",!1,!0,!0],["VO","12MVEOP",!1,!0,!1],["VP","VPLOA",!1,!0,!1],["VS2","VAC SLID",!1,!0,!0],["VT","VSTLOA",!1,!0,!1],["VU","UNPD 48",!1,!0,null],["VV","REGFL VC",!1,!0,!0],["VW","XTRA VC",!1,!0,!0],["W6","WINGSV6",!1,!0,!0],["WG","WINGS",!1,!1,!0],["WP","WITNESSP",!1,!1,!0],["WS","WH SVC",!1,!0,!1],["WU","WITNESSU",!1,!0,!1],["X6","TEX PVD",!1,!0,!0],["XR","CXDRMVL",!1,!0,null]],ABSENCE_CODES=ABSENCE_CODE_ROWS.map(([o,a,r,l,T])=>({code:o,description:a,category:"absence",duty:r,prorated:l,pay:null,paid:T})),MASTER_CODES={};ABSENCE_CODES.forEach(o=>MASTER_CODES[o.code]=o),RLC_PALETTE.forEach(o=>MASTER_CODES[o.code]=o);const CONTRACT_MONTH_DAY_START={1:"-01-01",2:"-01-31",3:"-03-02",4:"-04-01",5:"-05-02",6:"-06-02",7:"-07-02",8:"-08-01",9:"-08-31",10:"-10-01",11:"-11-01",12:"-12-02"};function isLeapYear(o){return o%4==0&&o%100!=0||o%400==0}function contractMonthLength(o,a){return{1:30,2:isLeapYear(a)?31:30,3:30,4:31,5:31,6:30,7:30,8:30,9:31,10:31,11:31,12:30}[o]}function contractMonthStart(o,a){return new Date(a+CONTRACT_MONTH_DAY_START[o]+"T00:00:00")}function prorationLookup(o){return o>=31?{daysOff:13,fourDay:!0,twoDay:!0}:o>=30?{daysOff:12,fourDay:!0,twoDay:!0}:o>=28?{daysOff:11,fourDay:!0,twoDay:!0}:o>=26?{daysOff:10,fourDay:!0,twoDay:!0}:o>=23?{daysOff:9,fourDay:!0,twoDay:!0}:o>=20?{daysOff:8,fourDay:!0,twoDay:!0}:o>=17?{daysOff:7,fourDay:!0,twoDay:!0}:o>=14?{daysOff:6,fourDay:!0,twoDay:!0}:o>=11?{daysOff:5,fourDay:!0,twoDay:!1}:o>=9?{daysOff:4,fourDay:!0,twoDay:!1}:o>=7?{daysOff:3,fourDay:!1,twoDay:!1}:o>=5?{daysOff:2,fourDay:!1,twoDay:!1}:o>=3?{daysOff:1,fourDay:!1,twoDay:!1}:{daysOff:0,fourDay:!1,twoDay:!1}}