{"version":3,"sources":["webpack:///./src/components/buttons.tsx","webpack:///./src/components/dialogTools/DialogManager.tsx","webpack:///./src/components/JustOkDialog.tsx","webpack:///./src/components/dialogTools/snackbars.tsx","webpack:///./src/measure.ts","webpack:///./src/components/ColumnContainer.tsx","webpack:///./src/components/Hider.tsx","webpack:///./src/components/RowContainer.tsx","webpack:///./src/app/spell/components/SpellAnswers.tsx","webpack:///./src/components/NotificationManager.tsx","webpack:///./src/domain/types.ts","webpack:///./src/app/play/url.ts","webpack:///./src/app/play/globalPlayData.ts","webpack:///./src/app/play/localStorage.ts","webpack:///./src/domain/AppError.ts","webpack:///./src/http/http.ts","webpack:///./src/app/play/components/ShareProgressComponent.tsx","webpack:///./src/app/play/requests/shareGame.ts","webpack:///./src/app/spell/components/GuessInputComponent.tsx","webpack:///./src/app/play/components/InputButtonComponent.tsx","webpack:///./src/app/spell/components/LettersComponent.tsx","webpack:///./src/app/spell/components/ProgressComponent.tsx","webpack:///./src/app/spell/components/SpellRulesComponent.tsx","webpack:///./src/utilities.ts","webpack:///./src/components/ToolbarTitle.tsx","webpack:///./src/components/dialogTools/ConfirmationDialogBase.tsx","webpack:///./src/components/ConfirmationDialog.tsx","webpack:///./src/app/play/components/TopAppBarComponent.tsx","webpack:///./src/app/spell/components/SpellGameComponent.tsx","webpack:///./src/app/play/PlayPrivacy.tsx","webpack:///./src/app/play/PlayTerms.tsx","webpack:///./src/domain/compute_types.ts","webpack:///./src/hooks/useFreshState.ts","webpack:///./src/app/compute/components/ComputeRulesComponent.tsx","webpack:///./src/app/compute/components/GuessNumberInputComponent.tsx","webpack:///./src/app/play/components/KeypadComponent.tsx","webpack:///./src/app/play/components/ProgressComponent.tsx","webpack:///./src/app/compute/components/ComputeGameComponent.tsx","webpack:///./src/app/twist/components/GuessDisplayComponent.tsx","webpack:///./src/app/twist/components/GuessInputButtonComponent.tsx","webpack:///./src/app/twist/components/GuessInputComponent.tsx","webpack:///./src/app/twist/components/TwistRulesComponent.tsx","webpack:///./src/app/twist/components/TwistGameComponent.tsx","webpack:///./src/app/twist/components/TwistAnswers.tsx","webpack:///./src/app/play/components/GamePageComponent.tsx","webpack:///./src/app/play/requests/getGame.ts","webpack:///./src/app/spell/index.tsx"],"names":["useStyles","makeStyles","theme","createStyles","primaryButton","margin","secondaryButton","backgroundColor","strongGuidingButton","palette","secondary","main","mildGuidingButton","subtleButton","PrimaryButton","props","classes","onClick","Button","className","variant","color","disabled","type","autoFocus","children","SecondaryButton","StrongGuidingButton","SubtleButton","dialogTable","Object","create","dialogIndex","dialogMethodsLocal","getDialogMethods","DialogManagerContext","Defer","renderer","document","getElementById","makeDialog","args","name","componentRenderer","undefined","toString","dialog","isOpen","register","event","stopPropagation","JustOkDialog","onClose","open","okayText","title","handleClose","addEventListener","removeEventListener","maxWidth","DialogTitle","id","DialogContent","dividers","DialogActions","inlineJustOkDialogInternal","openJustOkDialog","makeJustOkDialog","close","content","elevation","CommonSnackbar","setOpen","reason","closeFunc","message","Snackbar","anchorOrigin","vertical","horizontal","severity","useClientRect","rect","setRect","height","width","x","y","node","getBoundingClientRect","container","display","flexWrap","flexDirection","ColumnContainer","style","justifyContent","center","alignItems","hidden","unmount","RowContainer","answersDialogInternal","makeSpellAnswersDialogComponent","dialogRenderProps","answerKey","setAnswerKey","propsAnswerKey","toLowerCase","foundAll","answers","length","foundWords","TextField","value","label","InputLabelProps","shrink","onChange","currentTarget","filter","answer","indexOf","word","sort","a","b","map","AnswerItem","score","key","marginRight","notifyError","notifySuccess","notifyErrorTransient","notifySuccessTransient","nullCallback","NotifySnackbarComponent","show","onShow","autoHideDuration","Alert","AutoScoringMethod","getLevelFromScore","levels","reverseIndex","reverse","findIndex","level","getGameRefFromLocation","tokens","getGamePathFromLocation","split","window","location","pathname","shift","join","getBaseUrl","origin","getGameType","localStorageAvailable","localStorage","setItem","removeItem","_e","clearLocalStorageForGame","gameRef","storeProgressLocally","mutator","isSharingProgress","ls","readStateFromLocalStorageInternal","lastModifiedTime","lastShareTime","progress","unmodified","localStorageData","newData","sharedGameRef","Date","JSON","stringify","writeStateToLocalStorage","readStateFromLocalStorage","gameStateText","getItem","parse","AppError","Error","code","isExpected","super","this","AppErrorCode","post","path","body","method","request","response","fetch","parsedBody","json","ex","ok","statusText","http","Request","makeRequest","serverResponse","errorMessage","errorCode","isExpectedError","payload","timestamp","ShareProgressComponent","showShareProgressUrl","shareUrlRef","element","current","s","getSelection","r","createRange","selectNodeContents","removeAllRanges","addRange","Container","Box","boxShadow","m","padding","flexGrow","ref","overflowWrap","userSelect","execCommand","navigator","clipboard","writeText","shareProgress","localState","getTime","now","shareGameRequest","shareGame","data","GuessInputComponent","requiredLetters","optionalLetters","appState","dispatchPopAction","guess","setGuessState","setGuess","inputRef","insertPositionState","setInsertPositionState","insertPosition","pendingAction","selectionStart","setInsertPosition","newInsertPosition","inputElement","focus","selectionEnd","DispatchType","Delete","slice","Add","letter","Clear","InputProps","readOnly","fontFamily","spellCheck","endAdornment","InputAdornment","position","IconButton","newGuess","target","substring","badLetter","find","requiredLetter","optionalLetter","trim","InputButtonComponent","isRequired","zIndex","RadioButtonUncheckedOutlined","fontSize","LettersComponent","letters","index","ProgressComponent","gameAnswerCount","foundAnswers","newKey","setNewKey","levelName","setLevelName","levelNameFromScore","highestLevelScore","progressMarkerX","vw","isLevelChanged","animatedLevelName","viewBox","xmlns","x1","y1","vh","x2","ladderX","y2","stroke","strokeWidth","levelCount","cx","cy","fill","textAnchor","fontWeight","attributeName","values","dur","Grid","direction","foundWordsCount","wordCountMessage","wordForm","pointForm","item","justify","mr","Typography","sortedAnswerComponent","SpellRulesComponent","playSpec","gameInfo","rulesPrologue","rulesPrologueComponent","marginTop","RequiredLettersInfoComponent","canReuseLetters","minLength","pangramCount","maxPoints","highestLevel","list","reduce","result","push","makeSeparatedElementStringFromList","toUpperCase","sum","n","pluralize","count","shuffle","array","newArray","i","j","Math","floor","random","ToolbarTitle","ConfirmationDialogBase","handleCancel","history","listen","disableBackdropClick","inlineConfirmationDialogInternal","openConfirmationDialog","isOkay","ShareProgressContext","RulesContext","shareProgressHandler","setShareProgressHandler","handler","rulesHandler","setRulesHandler","menuButton","spacing","TopAppBarComponent","anchorEl","setAnchorEl","menuOpen","Boolean","AppBar","Toolbar","edge","Menu","gameType","gameTypeUsesMenuRestart","MenuItem","reload","clear","getGameTypeLabel","gameTypeHasAnswers","Provider","overflowY","initialAppState","reducer","_state","action","Pop","getCanReuseLetters","Array","from","letterCount","getPangramCount","answerLetters","answerLetterCount","pangrams","includes","SpellGameComponent","dispatch","gameState","setGameState","currentGuess","makeStateFromProps","firstTime","setFirstTime","setCurrentProgress","items","displayRules","setScore","answerWord","found","setLevel","submitHandler","missingLetters","makeSeparatedStringFromList","newGameState","nextLevel","keyUpHandler","keyCode","progressComponent","subtitle","PlayPrivacy","Paper","PlayTerms","Op","getOpChar","op","Mul","Div","Sub","solve","c","lhs","rhs","validSingle","RegExp","String","raw","validRange","hyphenWithWhitespace","whitespace","compile","t","replace","test","convertOperandToNumber","start","end","ts","Number","createChallenges","od","challenges","forEach","lhsRange","loperand","rhsRange","roperand","challenge","useFreshState","f","currentState","_reactState","setReactState","initialValue","ComputeRulesComponent","opList","add","addChallenges","opLabel","opCount","sub","subChallenges","mul","mulChallenges","div","divChallenges","opsText","challengeCount","timeLimit","mustSolve","GuessNumberInputComponent","KeypadComponent","digit","statusCell","minWidth","chasers","elapsedSeconds","ComputeGameComponent","starting","setStarting","finished","setFinished","challengeCounter","setChallengeCounter","startingElapsedTime","setStartingElapsedTime","elapsedIntervals","setElapsedIntervals","elapsedTime","startTimeRef","intervalIdRef","currentChallenge","setCurrentChallenge","challengesRef","createAllChallenges","splice","chaser","skipped","startResume","setInterval","round","gs","clearInterval","cell","textTransform","typography","button","lineHeight","GuessDisplayComponent","isMutable","disableRipple","GuessInputButtonComponent","isAvailable","letterContainers","cursor","primary","animation","opacity","Cursor","visible","firstMutableSlotIndexRef","lastMutableSlotIndexRef","slotCursorPosRef","slotsRef","tokensRef","challengeRef","fixed","solution","firstMutableSlotIndex","lastMutableSlotIndex","slotCursorPos","slots","fixedLetter","token","fillin","computeGuess","slot","setCurrentGuess","insertTokenAtCursor","nextCursorPosition","getNextCursorPosition","deleteTokenLeftOfCursor","getPrevCursorPosition","deleteSlot","keyDownHandler","onSubmit","caseSensitive","alignContent","clue","Divider","TwistRulesComponent","extraLetterChallengeCount","TwistGameComponent","words","setNextChallenge","currentChallengeIndex","firstUnsolvedChallenge","nextChallenge","thisChallenge","solved","remainingChallengeCount","makeTwistAnswersDialogComponent","solutions","getGameFromGamePath","isFirstPlay","storedGameState","persistentStorageGameState","getProgress","getGame","e","_theme","bottomAppBar","top","bottom","createMuiTheme","CssBaseline","setShow","setMessage","setSeverity","callback","setCallback","setAutoHideDuration","notify","console","error","stateIndex","setStateIndex","dialogOpen","Promise","resolve","reject","dialogMethods","openByName","dialogTableItem","setGameRef","setErrorMessage","storableGameState","snackBar","dataPresent","getProgressRef","gameComponent","openSpellAnswersDialog","openTwistAnswersDialog","Copyright"],"mappings":"sSAGA,MAAMA,EAAY,OAAAC,EAAA,GAAYC,GACrB,OAAAC,EAAA,GAAa,CAClBC,cAAe,CACbC,OAAQ,+BAEVC,gBAAiB,CACfD,OAAQ,8BACRE,gBAAiB,aAEnBC,oBAAqB,CACnBH,OAAQ,8BACRE,gBAAiBL,EAAMO,QAAQC,UAAUC,MAE3CC,kBAAmB,CACjBP,OAAQ,+BAEVQ,aAAc,CACZR,OAAQ,kCAaDS,EAAuDC,I,QAClE,MAAMC,EAAUhB,IACViB,EAAUF,EAAME,QAAUF,EAAME,QAAU,OAChD,OAEE,2BACE,gBAACC,EAAA,EAAM,CACLC,UAAWH,EAAQZ,cACnBgB,QAAQ,YACRC,MAAkB,QAAb,EAAEN,EAAMM,aAAK,QAAI,UAAS,aACnBN,EAAM,cAClBO,SAAUP,EAAMO,SAChBL,QAASA,EACTM,KAAgB,QAAZ,EAAER,EAAMQ,YAAI,QAAI,SACpBC,UAAWT,EAAMS,WAEhBT,EAAMU,YAMFC,EACXX,I,QAEA,MAAMC,EAAUhB,IAChB,OACE,gBAACkB,EAAA,EAAM,CACLC,UAAWH,EAAQV,gBACnBc,QAAQ,YACRC,MAAkB,QAAb,EAAEN,EAAMM,aAAK,QAAI,UAAS,aACnBN,EAAM,cAClBO,SAAUP,EAAMO,SAChBL,QAAS,IAAMF,EAAME,SAAWF,EAAME,UACtCM,KAAgB,QAAZ,EAAER,EAAMQ,YAAI,QAAI,SACpBC,UAAWT,EAAMS,WAEhBT,EAAMU,WAKAE,EACXZ,I,QAEA,MAAMC,EAAUhB,IAChB,OACE,gBAACkB,EAAA,EAAM,CACLC,UAAWH,EAAQR,oBACnBY,QAAQ,WACRC,MAAkB,QAAb,EAAEN,EAAMM,aAAK,QAAI,UAAS,aACnBN,EAAM,cAClBO,SAAUP,EAAMO,SAChBL,QAAS,IAAMF,EAAME,SAAWF,EAAME,UACtCM,KAAgB,QAAZ,EAAER,EAAMQ,YAAI,QAAI,SACpBC,UAAWT,EAAMS,WAEhBT,EAAMU,WAyBAG,EAAsDb,I,QACjE,MAAMC,EAAUhB,IAChB,OACE,gBAACkB,EAAA,EAAM,CACLC,UAAWH,EAAQH,aACnBQ,MAAkB,QAAb,EAAEN,EAAMM,aAAK,QAAI,UAAS,aACnBN,EAAM,cAClBO,SAAUP,EAAMO,SAChBL,QAAS,IAAMF,EAAME,SAAWF,EAAME,UACtCM,KAAgB,QAAZ,EAAER,EAAMQ,YAAI,QAAI,SACpBC,UAAWT,EAAMS,WAEhBT,EAAMU,WC5FPI,EAGFC,OAAOC,OAAO,MAClB,IAAIC,EAAc,EAkBlB,IAAIC,EACG,MAAMC,EAAmB,IAAMD,EAEzBE,EAAuB,wBAA6B,MAyD3DC,EAASrB,GACN,eACLA,EAAMsB,WACNC,SAASC,eAAe,WAIfC,EAA+BC,IAI1C,MAAM,KAAEC,EAAI,kBAAEC,GAAsBF,EACpC,MAxFe,CAAkBA,IAIjC,MAAM,kBAAEE,GAAsBF,EAC9B,IAAIC,EAAOD,EAAKC,UACHE,IAATF,IAEFV,IACAU,EAAO,gBAAkBV,EAAYa,YAEvC,MAAMC,EAAS,CAAEJ,OAAMC,oBAAmBI,QAAQ,GAElD,OADAlB,EAAYa,GAAQ,CAAEI,UACfA,GA2EAE,CAAS,CACdN,OACAC,uBChHE,EAAkBM,IAEtBA,EAAMC,mBAGKC,EACXpC,IAEA,MAAM,QAAEqC,EAAO,KAAEC,EAAI,SAAEC,EAAQ,MAAEC,GAAUxC,EACrCyC,EAAc,KAClBJ,KAUF,OAPA,oBAAU,KACRd,SAASmB,iBAAiB,UAAW,GAAgB,GAC9C,KACLnB,SAASoB,oBAAoB,UAAW,GAAgB,MAK1D,gBAAC,IAAS,CACRC,SAAS,KAAI,kBACG,sBAChBN,KAAMA,EACND,QAASI,GAET,gBAACI,EAAA,EAAW,CAACC,GAAG,uBAAuBN,GACvC,gBAACO,EAAA,EAAa,CAACC,UAAQ,GAAEhD,EAAMU,UAC/B,gBAACuC,EAAA,EAAa,KACZ,gBAACpC,EAAY,CAACX,QAASuC,GAAcF,UAAY,SAYzD,IAAIW,EAEG,MAAMC,EAAoBnD,IAC1BkD,IACHA,EAA6BE,KAExBjC,IAAmBmB,KAAKY,EAA4BlD,IAGvDoD,EAAmB,IACR3B,EAA6C,CAC1DE,KAAM,2BACNC,kBAAoB5B,GAEhB,gBAACoC,EAAY,CACXC,QAAS,KACPrC,EAAMqD,OAAM,GAAM,IAEpBf,MAAM,EACNE,MAAOxC,EAAMA,MAAMwC,MACnBD,SAAUvC,EAAMA,MAAMuC,UAErBvC,EAAMA,MAAMsD,W,4BChFvB,SAAS,EAAMtD,GACb,OAAO,gBAAC,IAAQ,eAACuD,UAAW,EAAGlD,QAAQ,UAAaL,IAI/C,SAASwD,EAAexD,GAK7B,MAAOsC,EAAMmB,GAAW,YAAe,GACjChB,EAAc,CAACP,EAA8BwB,KAClC,cAAXA,IAGJ1D,EAAM2D,YACNF,GAAQ,KAOV,OAJA,YAAgB,KACVzD,EAAM4D,SAASH,GAAQ,KAI3B,gBAACI,EAAA,EAAQ,CACPvB,KAAMA,EACND,QAASI,EACTqB,aAAc,CAAEC,SAAU,MAAOC,WAAY,WAE7C,gBAAC,EAAK,CAAC3B,QAASI,EAAawB,SAAUjE,EAAMiE,eACxBpC,IAAlB7B,EAAM4D,QAAwB,KAAO5D,EAAM4D,UChC7C,SAASM,IACd,MAAOC,EAAMC,GAAW,mBAAS,MAMjC,MAAO,CAACD,UAAQ,CAAEE,OAAQ,EAAGC,MAAO,EAAGC,EAAG,EAAGC,EAAG,GALpC,sBAAaC,IACV,OAATA,GACFL,EAAQK,EAAKC,0BAEd,K,4BCJL,MAAM,EAAY,OAAAxF,EAAA,GAAYC,GACrB,OAAAC,EAAA,GAAa,CAClBuF,UAAW,CACTC,QAAS,OACTC,SAAU,OACVC,cAAe,aASRC,EACX/E,IAEA,MAAMC,EAAU,IAChB,OACE,uBACEG,UAAW,YAAKH,EAAQ0E,UAAW3E,EAAMI,WACzC4E,MAAO,CACLC,eAAgBjF,EAAMkF,OAAS,SAAW,SAC1CC,WAAYnF,EAAMkF,OAAS,SAAW,WAGvClF,EAAMU,WCbE,MARqCV,GAC9CA,EAAMoF,QAAUpF,EAAMqF,QAAgB,KAExC,uBAAKL,MAAO,CAAEJ,QAAS5E,EAAMoF,OAAS,OAAS,QAC3CpF,EAAMoF,QAAUpF,EAAMU,UCR9B,MAAM,EAAY,OAAAxB,EAAA,GAAYC,GACrB,OAAAC,EAAA,GAAa,CAClBuF,UAAW,CACTC,QAAS,OACTC,SAAU,OACVC,cAAe,MACfK,WAAY,aAULG,EACXtF,I,MAEA,MAAMC,EAAU,IAChB,OACE,uBACEG,UAAW,YAAKH,EAAQ0E,UAAW3E,EAAMI,WACzC4E,MAAO,CACLC,eAAgBjF,EAAMkF,OAAS,SAAW,SAC1CZ,MAAkB,QAAb,EAAEtE,EAAMsE,aAAK,QAAI,SAGvBtE,EAAMU,WCZb,IAAI6E,EAEG,MAOMC,EAAkC,IACtC/D,EAAqC,CAC1CG,kBAAoB6D,I,MAClB,MAAOC,EAAWC,GAAgB,mBAAS,IACrC3F,EAAQyF,EAAkBzF,MAC1B4F,EAAgC,QAAlB,EAAG5F,EAAM0F,iBAAS,eAAEG,cAClCC,EAAW9F,EAAM+F,QAAQC,SAAWhG,EAAMiG,WAAWD,OAC3D,OACE,gBAAC5D,EAAY,CACXC,QAAS,KACPoD,EAAkBpC,OAAM,IAE1Bf,MAAM,EACNE,MAAO,WAEP,gBAACuC,EAAe,CAACG,QAAM,GACrB,gBAAC,EAAK,CAACE,QAASU,GAAQ,gDAGxB,gBAAC,EAAK,CAACV,OAAQU,GACb,gBAACf,EAAe,CAACG,QAAM,G,kDAErB,gBAACgB,EAAA,EAAS,CACR7F,QAAQ,WACR8F,MAAOT,EACPU,MAAO,aACP9G,OAAO,SACP+G,gBAAiB,CACfC,QAAQ,GAEV9F,KAAK,OACL+F,SAAWrE,IACTyD,EAAazD,EAAMsE,cAAcL,YAKzC,gBAAC,EAAK,CACJf,OACEU,GACAJ,EAAUG,gBAAkBD,GACV,MAAlBA,GAGF,gBAACb,EAAe,CAACG,QAAM,GACrB,gBAAC,EAAK,CAACE,OAAoC,IAA5BpF,EAAMiG,WAAWD,QAC9B,gBAACjB,EAAe,CAACG,QAAM,GACrB,yCACA,gBAACI,EAAY,KACVtF,EAAM+F,QACJU,OACEC,GAAW1G,EAAMiG,WAAWU,QAAQD,EAAOE,OAAS,GAEtDC,KAAK,CAACC,EAAGC,IACRD,EAAEF,KAAOG,EAAEH,MAAQ,EAAIE,EAAEF,KAAOG,EAAEH,KAAO,EAAI,GAE9CI,IAAKN,GAAWO,EAAWP,EAAOE,KAAMF,EAAOQ,WAIxD,0CACA,gBAAC5B,EAAY,KACVtF,EAAM+F,QACJU,OACEC,GAAW1G,EAAMiG,WAAWU,QAAQD,EAAOE,MAAQ,GAErDC,KAAK,CAACC,EAAGC,IACRD,EAAEF,KAAOG,EAAEH,MAAQ,EAAIE,EAAEF,KAAOG,EAAEH,KAAO,EAAI,GAE9CI,IAAKN,GAAWO,EAAWP,EAAOE,KAAMF,EAAOQ,gBAW9DD,EAAa,CAACL,EAAcM,IAE9B,uBAAKC,IAAKP,EAAM5B,MAAO,CAAEJ,QAAS,OAAQC,SAAU,SAClD,wBAAMG,MAAO,CAAEoC,YAAa,WAC1B,yBAAIR,IAEN,wBAAM5B,MAAO,CAAEoC,YAAa,WAAaF,I,4BC7GxC,IAAIG,EAEAC,GAEAC,GAKAC,GAKX,MAAMC,GAAe,OAqDrB,SAASC,GAAwB1H,GAQ/B,MAAOsC,EAAMmB,GAAW,YAAe,GAavC,OANA,YAAgB,KACVzD,EAAM2H,OACRlE,GAAQ,GACRzD,EAAM4H,YAIR,gBAAC/D,EAAA,EAAQ,CACPvB,KAAMA,EACND,QAdgB,CAACH,EAA8BwB,KACjDD,GAAQ,GACRzD,EAAMqC,SAAWrC,EAAMqC,WAarByB,aAAc,CAAEC,SAAU,MAAOC,WAAY,UAC7C6D,iBAC6B,IAA3B7H,EAAM6H,iBAAyB,KAAO7H,EAAM6H,kBAG9C,gBAACC,EAAA,EAAK,CAAC7D,SAAUjE,EAAMiE,UAAWjE,EAAM4D,U,8BC9B9C,IAAYmE,IAAZ,SAAYA,GACV,WACA,aACA,WAHF,CAAYA,QAAiB,KAiCtB,MAAMC,GAAoB,CAACC,EAAsBf,KACtD,MAAMgB,EAAe,IAAID,GACtBE,UACAC,UAAWC,IAAS,MAAC,OAAY,QAAZ,EAACA,EAAMnB,aAAK,QAAI,IAAMA,IAC9C,OAAOe,EAAOA,EAAOjC,OAAS,EAAIkC,I,iBCtG7B,MAAMI,GAAyB,KACpC,MACMC,EADWC,KACOC,MAAM,KAE9B,OADcF,EAAOvC,OACN,EAAIuC,EAAO,QAAK1G,GAG3B2G,GAA0B,KAE9B,IAAID,EADSG,OAAOC,SAASC,SACXH,MAAM,KAKxB,OAFAF,EAAOM,QACPN,EAAOM,QACAN,EAAOO,KAAK,MAGRC,GAAa,KAExB,IAAIR,EADSG,OAAOC,SAASC,SACXH,MAAM,KAExB,MAAO,CACLC,OAAOC,SAASK,OAChBT,EAAO,IACPO,KAAK,MC9BT,IAAI,GAIG,SAASG,KACd,OAAO,GCSF,SAASC,KACd,IAIE,OAFAC,aAAaC,QADL,SAERD,aAAaE,WAFL,MAGD,EACP,MAAOC,GACP,OAAO,GAUJ,SAASC,KACd,MAAMC,EAAUlB,KACZY,MACFC,aAAaE,WAAWJ,KAAgB,IAAMO,GAI3C,SAASC,GACdD,EACAE,EACAC,GAEA,IAAKT,GAAuB,OAC5B,IAAIU,EAAKC,GAAkCL,GACtCI,IAEHA,EAAK,CACHJ,UACAM,sBAAkBjI,EAClBkI,mBAAelI,EACfmI,cAAUnI,EACVoI,YAAY,IAGhBP,EAAQE,GAIV,SACEM,EACAP,GAEA,GAAIT,KAAyB,CAE3B,MAAMU,EAAKC,GAAkCK,EAAiBV,SACxDW,EAAO,6BACXC,cAAeR,aAAE,EAAFA,EAAIQ,eAChBF,GAAgB,CACnBJ,iBAAkB,IAAIO,KACtBN,cAAeJ,EAAoB,IAAIU,KAAST,aAAE,EAAFA,EAAIG,gBAEtDZ,aAAaC,QACXH,KAAgB,IAAMkB,EAAQX,QAC9Bc,KAAKC,UAAUJ,KAlBnBK,CAAyBZ,EAAID,GAuBxB,SAASc,GAAqCjB,GAEnD,OADiBK,GAAkCL,GAIrD,SAASK,GAA6CL,GACpD,GAAIN,KAAyB,CAC3B,MAAMwB,EAAgBvB,aAAawB,QAAQ1B,KAAgB,IAAMO,GACjE,IAIE,OAHiCc,KAAKM,MACpCF,GAGF,MAAOpB,GACP,SC/FC,MAAMuB,WAAiBC,MAC5B,YACElH,EACOmH,EACAC,GAEPC,MAAMrH,GAHC,KAAAmH,OACA,KAAAC,aAGPE,KAAKvJ,KAAO,YAIhB,IAAYwJ,IAAZ,SAAYA,GACV,qDADF,CAAYA,QAAY,K,2SCWjB,SAAeC,GACpBC,EACAC,EACA5J,EAAoB,CAAE6J,OAAQ,OAAQD,KAAMhB,KAAKC,UAAUe,K,0CAE3D,aApBK,SAAuBE,G,0CAC5B,MAAMC,QAAkCC,MAAMF,GAC9C,IAIEC,EAASE,iBAAmBF,EAASG,OACrC,MAAOC,IAET,IAAKJ,EAASK,GACZ,MAAM,IAAIhB,MAAMW,EAASM,YAE3B,OAAON,KAQMO,CAAQ,IAAIC,QAAQZ,EAAM3J,OAElC,SAAewK,GACpBV,EACAH,G,0CAEA,MAAMc,QAAuBf,GAAkBpC,OAASqC,EAAMG,GACxDF,EAAOa,EAAeR,WAC5B,GAAIL,EAAKc,aACP,MAAM,IAAIvB,GAASS,EAAKc,aAAcd,EAAKe,UAAWf,EAAKgB,iBAE7D,MAAMb,EAAWU,EAAeR,WAChC,OAAO,+BAAKF,EAASc,SAAO,CAAEC,UAAWf,EAASe,e,slBCxB7C,MAAMC,GAA0BzM,IACrC,MAAM,qBAAE0M,GAAyB1M,EAC3B2M,EAAc,iBAAO,MAY3B,OAXA,oBAAU,KAER,GAA6B,KAAzBD,EAA6B,OACjC,IAAIE,EAA2BD,EAAYE,QAC3C,GAAgB,OAAZD,EAAkB,OACtB,MAAME,EAAIpE,OAAOqE,eACXC,EAAIzL,SAAS0L,cACnBD,EAAEE,mBAAmBN,GACrBE,EAAEK,kBACFL,EAAEM,SAASJ,KAGX,gBAACK,GAAA,EAAS,K,yOAKR,gBAACC,EAAA,EAAG,CAACC,UAAW,EAAGC,EAAG,GACpB,uBACExI,MAAO,CACLJ,QAAS,OACTC,SAAU,OACVM,WAAY,SACZsI,QAAS,WAGX,uBAAKzI,MAAO,CAAE0I,SAAU,IACtB,wBACE5K,GAAG,gBACH6K,IAAKhB,EACL3H,MAAO,CAAE4I,aAAc,WAAYC,WAAY,QAE9CnB,IAGL,2BACE,gBAACY,EAAA,EAAG,CAACE,EAAG,GACN,gBAACrN,EAAA,EAAM,CACLE,QAAQ,YACRC,MAAM,UACNJ,QAAgBgC,GAAU,qCACxBX,SAASuM,YAAY,QACjBC,UAAUC,kBACND,UAAUC,UAAUC,UAAUvB,IAEtCpF,GAAc,cACf,2BAYJ4G,GAAgB,CAAO1E,EAAiBQ,IAAsB,qC,MAGzE,MAAMmE,EAAa1D,GAA0BjB,GAG7C,IAAIY,EAAwC,QAA3B,EAAG+D,EAAW/D,qBAAa,QAAI+D,EAAW3E,QAC3D,IAC4B,IAA1B2E,EAAWlE,YACiB,MAA5BkE,EAAWpE,eACXoE,EAAWpE,cAAcqE,UAAY/D,KAAKgE,MAAQ,KAClD,CACA,MAAMC,EAAqC,CACzC9E,QAASA,EACTQ,YAGFI,SC/EG,SAAyBoB,G,0CAC9B,aAAaU,GAA8BV,EAAS,sBD6E3B+C,CAAUD,IACR9E,QACzBC,GACEW,EACCoE,GAAUA,EAAKvE,YAAa,GAC7B,GAGJ9G,EAAiB,CACfG,QACE,gBAACmJ,GAAsB,CACrBC,qBAAsB3D,KAAe,IAAMqB,IAG/C5H,MAAO,sB,wDE3FJ,MAAMiM,GAAuBzO,I,QAClC,MAAM,SACJuG,EAAQ,gBACRmI,EAAe,gBACfC,EAAe,SACfC,EAAQ,kBACRC,GACE7O,GAEG8O,EAAOC,GAAiB,mBAAS,IAClCC,EAAYF,IAChBC,EAAcD,GACdvI,EAASuI,IAELG,EAAW,iBAAO,OACjBC,EAAqBC,GAA0B,mBAAS,GAEzDC,EACJR,EAASS,gBAA8B,IAAb,YACW,QAAlC,EAAkB,QAAlB,EAACJ,aAAQ,EAARA,EAAUpC,eAAO,eAAEyC,sBAAc,QAAI,EACrCJ,EAEAK,EAAqBC,IACzBL,EAAuBK,EAAoB,EAAIA,EAAoB,IA0CrE,OAvCA,oBAAU,KACR,MAAMC,EAAiCR,EAASpC,QAChD4C,EAAaC,QACT,aACFD,EAAaH,eAAiBL,EAASpC,QAAQ1G,MAAMH,OACrDyJ,EAAaE,aAAeV,EAASpC,QAAQ1G,MAAMH,SAEnDyJ,EAAaH,eAAiBF,EAC9BK,EAAaE,aAAeP,KAIhC,oBAAU,K,MACR,OAA8B,QAA9B,EAAQR,EAASS,qBAAa,eAAE7O,MAC9B,KAAKoP,GAAaC,OAEhB,GADAhB,IACuB,IAAnBO,EAAsB,OAC1BJ,EACEF,EAAMgB,MAAM,EAAGV,EAAiB,GAAKN,EAAMgB,MAAMV,IAEnDG,EAAkBH,EAAiB,GACnC,MACF,KAAKQ,GAAaG,IAChBf,EACEF,EAAMgB,MAAM,EAAGV,GACbR,EAASS,cAAcW,OACvBlB,EAAMgB,MAAMV,IAEhBG,EAAkBH,EAAiB,GACnCP,IACA,MACF,KAAKe,GAAaK,MAChBjB,EAAS,IACTO,EAAkB,GAClBV,OAMJ,gBAAC3I,EAAA,EAAS,CACR7F,QAAQ,SACR+F,MAAM,aACN6I,SAAUA,EACViB,WAAY,CACVC,SAAU,YACVnL,MAAO,CACLoL,WAAY,uDAEdC,YAAY,EACZC,aACE,gBAACC,GAAA,EAAc,CAACC,SAAS,OACvB,gBAACC,GAAA,EAAU,cACE,oBACXvQ,QAAS,KACP8O,EAAS,IACTO,EAAkB,KAGpB,gBAACU,GAAA,EAAK,SAKd9J,MAAO2I,GAAS,YAAW,IAAM,IACjCvI,SAAWrE,IACT,IAAIwO,EAAWxO,EAAMyO,OAAOxK,MAAMN,cAC9B,cAAU6K,EAAWA,EAASE,UAAU,EAAGF,EAAS1K,OAAS,IACjE,MAAM6K,EAAY,IAAIH,GAAUI,KAAMd,IAIpC,QAAuBnO,IAHA,IAAK6M,UAAmB,IAAKoC,KACjDC,GAAmBA,IAAmBf,GAEP,OAIlC,YAAuBnO,IAHA,IAAK8M,UAAmB,IAAKmC,KACjDE,GAAmBA,IAAmBhB,GAGlCA,OADP,SAIgBnO,IAAdgP,GACF7B,EAAS0B,GACTnB,EAAkBrN,EAAMyO,OAAOrB,kBAE/BC,EAAkBrN,EAAMyO,OAAOrB,eAAiB,GAChB,IAA5BuB,EAAUI,OAAOjL,QACnBuB,GACKsJ,EAAH,8C,iBCrHP,MAAMK,GAAwBlR,IACnC,MAAM,WAAEmR,EAAU,OAAEnB,EAAM,QAAE9P,GAAYF,EAExC,OACE,gBAACG,EAAA,EAAM,CACLE,QAAQ,YACRC,MAAO6Q,EAAa,YAAc,UAClCjR,QAAS,KACPA,MAGF,uBACE8E,MAAO,CACLJ,QAAS,OACTK,eAAgB,SAChBE,WAAY,WAGd,2BAAM6K,GACLmB,GACC,uBACEnM,MAAO,CACLwL,SAAU,WACVY,OAAQ,GACRxM,QAAS,OACTK,eAAgB,WAGlB,gBAACoM,GAAA,EAA4B,CAACrM,MAAO,CAAEsM,SAAU,cC9BhDC,GAAoBvR,IAC/B,MAAM,QAAEwR,EAAO,gBAAE9C,EAAe,QAAExO,GAAYF,EAE9C,OACE,gCACGwR,EAAQxK,IAAI,CAACgJ,EAAQyB,IAElB,gBAACnE,EAAA,EAAG,CAACnG,IAAKsK,EAAOjE,EAAG,GAClB,gBAAC0D,GAAoB,CACnBhR,QAAS,KACPA,EAAQ8P,IAEVA,OAAQA,EACRmB,aACI,IAAKzC,UAAmB,IAAKoC,KAC5BC,GAAmBA,IAAmBf,SCyB5C0B,GAAqB1R,IAChC,MAAM,WAAEiG,EAAU,QAAEF,EAAO,gBAAE4L,EAAe,OAAE1J,EAAM,MAAEf,GAAUlH,EAEhE,GAAkB,MAAdiG,EAAoB,OAAO,KAE/B,MAAM2L,EAAe3L,EAAWe,IAAKJ,GACnCb,EAAQ+K,KAAMpK,GAAWA,EAAOE,OAASA,KAGpCiL,EAAQC,GAAa,mBAAS,IAC9BC,EAAWC,GAAgB,mBAAS,IACrCC,EAAqBjK,GAAkBC,EAAQf,GAAOvF,KACtDuQ,EAAoBjK,EAAOA,EAAOjC,OAAS,GAAGkB,MAC9CiL,EA1BW,EA0BkBjL,EAAQgL,EAxBxBE,IA0BbC,EAAiBJ,IAAuBF,EAC1CM,GAAgBP,EAAUD,EAAS,GACvC,MAAMS,EAAoBD,EAAiB,KACzC,gBAAC/E,EAAA,EAAG,KACF,uBACEnG,IAAK0K,EACLU,QAAS,aACTjO,MAxCG,IAyCHD,OAxCG,GAyCHmO,MAAM,8BAEN,wBACEC,GAxCS,EAyCTC,GAAIC,GACJC,GAAIC,IACJC,GAAIH,GACJI,OAAO,QACPC,YAAY,MAEb,MAEC,MAAMC,EAAahL,EAAOjC,OAE1B,OAAOiC,EAAOjB,IAAI,CAACqB,EAAOoJ,KACxB,IAAInR,EArDQ,QA8DZ,OARiB4G,GAASmB,EAAMnB,QAG5B5G,EADEmR,IAAUwB,EAAa,GAAKhL,EAAOwJ,EAAQ,GAAGvK,MAAQA,EA9DrD,UADF,WAsEH,0BACEC,IAAKsK,EAELyB,GAjEG,EAmEAjL,EAAOwJ,GAAOvK,MAAQgL,EAjEpBE,IAmELe,GAAIR,GACJ3F,EAtEG,EAuEHoG,KAAM9S,OAxBb,GA6BD,wBACEmS,GAAIN,EACJS,GAAIT,EACJO,GAAIC,GACJG,GAAIH,GACJI,OAxFS,UAyFTC,YAAY,MAEd,wBACEzO,EAAE,MACFC,EAAE,KACF6O,WAAW,SACX/B,SAAS,KACTgC,WAAY,IACZF,KAjGS,WAmGRpL,GAAkBC,EAAQf,GAAOvF,KAClC,2BAAS4R,cAAc,YAAYC,OAAO,WAAWC,IAAI,OACzD,2BACEF,cAAc,OACdC,OAAQ,kBACRC,IAAI,UAQd,OADIpB,GAAgBL,EAAaC,GAE/B,gBAACyB,EAAA,EAAI,CAAC/O,WAAS,EAACgP,UAAU,SAASxO,WAAW,UAC5C,gBAACmI,EAAA,EAAG,CAACE,EAAG,KACP,MACC,MAAMoG,EAAkB3N,EAAWD,OACnC,IAAI6N,EACJ,MAAMC,EAA+B,IAApBF,EAAwB,OAAS,QAC5CG,EAAsB,IAAV7M,EAAc,QAAU,SAC1C,OAAQ0M,GACN,KAAK,EACHC,EAAmB,YAAYlC,KAAmBmC,aAClD,MACF,KAAKnC,EAEDkC,EADsB,IAApBD,EACiB,uCAEA,kCAAkCA,KAAmBE,KAE1E,MACF,QACED,EAAmB,aAAaD,KAAmBE,SAAgB5M,KAAS6M,KAGhF,OACE,gBAACL,EAAA,EAAI,CAAC/O,WAAS,EAACgP,UAAU,SAASxO,WAAW,UAC3CmN,EACD,gBAACoB,EAAA,EAAI,CAACM,MAAI,GAAEH,KAvBjB,GA2BD,gBAACH,EAAA,EAAI,CAAC/O,WAAS,EAACsP,QAAQ,UArKA,CAAClO,GAC7BA,EACGc,KAAK,CAACC,EAAGC,IACJD,EAAEF,KAAOG,EAAEH,MACL,EAENE,EAAEF,KAAOG,EAAEH,KACN,EAGF,GAERI,IAAI,CAACN,EAAQ+K,IAEV,gBAACnE,EAAA,EAAG,CAACnG,IAAKsK,EAAOyC,GAAI,GACnB,gBAACC,EAAA,EAAU,KACT,yBAAIzN,EAAOE,M,IAAWF,EAAOQ,SAsJhCkN,CAAsBxC,MCnKlByC,GAAuBrU,IAClC,MAAM,SAAEsU,EAAQ,SAAEC,GAAavU,EACzBwU,EAAgBF,EAASE,cACzBC,EAA0BD,EAC9B,gBAACnH,GAAA,EAAS,KAAEmH,GADkC,KAGhD,OACE,gBAAClH,EAAA,EAAG,KACDmH,EACD,gBAACnH,EAAA,EAAG,CAACE,EAAG,IACR,gBAACH,GAAA,EAAS,K,0CAER,sBAAIrI,MAAO,CAAE0P,UAAW,IACtB,gBAACC,GAA4B,CAC3BjG,gBAAiB4F,EAAS5F,kBAE5B,0BACE,yBAAI,eACF6F,EAASK,gBAAkB,GAAK,sBAGpC,0B,yBAA2BL,EAASM,U,aACpC,0B,QACQ,IACqB,IAA1BN,EAASO,aACN,cACA,OAAOP,EAASO,qBAAsB,I,WACP,IAA1BP,EAASO,aAAqB,IAAM,G,wBAE/C,0BACG,+BACTR,EAASvO,QAAQC,+BAA+BuO,EAASQ,wBAEhDR,EAASS,aAAa9N,OAASqN,EAASQ,UACrC,GACA,wEAIV,gBAACzH,EAAA,EAAG,CAACE,EAAG,IACR,gBAACH,GAAA,EAAS,K,2EACiE,IACxErN,EAAMsU,SAASrM,OAAOjB,IAAI,CAACqB,EAAOoJ,IACjC,wBAAMtK,IAAKsK,GACRA,EAAQ,EAAI,KAAO,GACpB,yBAAIpJ,EAAM1G,M,IAAW0G,EAAMnB,Q,KAKjC,gBAACoG,EAAA,EAAG,CAACE,EAAG,MAgBRmH,GAAgC3U,IAGpC,MAAM,gBAAE0O,GAAoB1O,EAC5B,OAAK0O,aAAe,EAAfA,EAAiB1I,QAEpB,0B,6CAE8B,IAA3B0I,EAAgB1I,OAAe,KAAO,MAnBK,CAChDiP,IAEA,QAAapT,IAAToT,EACJ,OAAOA,EAAKC,OAAO,CAACC,EAAQnB,EAAMvC,KAClB,IAAVA,GAAa0D,EAAOC,KAAK,wBAAMjO,IAAK,EAAIsK,GAAK,OACjD0D,EAAOC,KAAK,qBAAGjO,IAAK,EAAIsK,EAAQ,GAAIuC,IAC7BmB,GACN,KAYEE,CACC,IAAK3G,UAAmB,IAAK1H,IAAKgN,GAASA,EAAKsB,gB,KANjB,MC7D1BC,GAAOzO,GAAgBA,EAAEoO,OAAO,CAACK,EAAKC,IAAOD,EAAOC,EAAI,GAqB9D,MAqEMC,GAAY,CAACC,EAAe9O,IACzB,IAAV8O,EAAoB,GAAGA,KAAS9O,IAC7B,GAAG8O,KAAS9O,KAGR+O,GAAWC,IACtB,MAAMC,EAAW,IAAID,GACrB,IAAIF,EAAQ,EACZ,OAAa,CACX,IAAK,IAAII,EAAID,EAAS7P,OAAS,EAAG8P,EAAI,EAAGA,IAAK,CAC5C,MAAMC,EAAIC,KAAKC,MAAMD,KAAKE,UAAYJ,EAAI,KACzCD,EAASC,GAAID,EAASE,IAAM,CAACF,EAASE,GAAIF,EAASC,IAKtD,GADAJ,IAEEG,EAAS7P,OAAS,GAClB6P,EAAS/M,KAAK,MAAQ8M,EAAM9M,KAAK,KACvB,KAAV4M,EAEA,OAAOG,I,2CC9Hb,MAAM,GAAY,OAAA3W,EAAA,GAAYC,GACrB,OAAAC,EAAA,GAAa,CAClBoD,MAAO,CACLkL,SAAU,MAMHyI,GACXnW,IAEA,MAAMC,EAAU,KAChB,OACE,gBAACkU,EAAA,EAAU,CAAC9T,QAAQ,KAAKD,UAAWH,EAAQuC,OACzCxC,EAAMU,WAKE,I,aCNR,MAAM0V,GACXpW,IAEA,MAAM,QAAEqC,EAAO,KAAEC,EAAI,SAAEC,EAAQ,MAAEC,GAAUxC,EAErCqW,EAAe,KACnBhU,GAAQ,IAMJiU,EAAU,eAUhB,OATA,oBAAU,KAER,GAAKA,EAEL,OAAOA,EAAQC,OAAO,KACpBlU,GAAQ,MAET,IAGD,gBAAC,IAAS,CACRmU,sBAAoB,EAEpB5T,SAAS,KAAI,kBACG,4BAChBN,KAAMA,EACND,QAASgU,GAET,gBAACxT,EAAA,EAAW,CAACC,GAAG,6BAA6BN,GAC7C,gBAACO,EAAA,EAAa,CAACC,UAAQ,GAAEhD,EAAMU,UAC/B,gBAACuC,EAAA,EAAa,KACZ,gBAACpC,EAAY,CAACJ,WAAS,EAACP,QAASmW,GAAY,UAG7C,gBAACxV,EAAY,CAACX,QA5BH,KACfmC,GAAQ,KA2B8BE,UAAY,SCnBtD,IAAIkU,GAIG,MAAMC,GACX1W,IAEKyW,KACHA,GA5BahV,EAAmD,CAChEE,KAAM,2BACNC,kBAAoB5B,GAEhB,gBAACoW,GAAsB,CACrB/T,QAAUsU,IACR3W,EAAMqD,MAAMsT,OAAQ9U,IAEtBS,MAAM,EACNE,MAAOxC,EAAMA,MAAMwC,MACnBD,SAAUvC,EAAMA,MAAMuC,UAErBvC,EAAMA,MAAMsD,YAkBdnC,IAAmBmB,KAAKmU,GAAkCzW,I,2SClB5D,MAAM4W,GAAuB,gBAAoB,MAC3CC,GAAe,gBAAoB,MAClB,gBAAoB,MAElD,IAAIC,GAAuB,OAC3B,MAAMC,GAA2BC,IAC/BF,GAAuBE,GAGzB,IAAIC,GAAe,OACnB,MAAMC,GAAmBF,IACvBC,GAAeD,GAGX,GAAY,OAAA9X,EAAA,GAAYC,GACrB,OAAAC,EAAA,GAAa,CAClBoD,MAAO,CACLkL,SAAU,GAEZyJ,WAAY,CACV/P,YAAajI,EAAMiY,QAAQ,OAKpBC,GACXrX,IAEA,MAAOmE,EAAMwJ,GAAOzJ,KACboT,EAAUC,GAAe,WAAmC,MAC7DtX,EAAU,KAMVwC,EAAc,KAClB8U,EAAY,OAERC,EAAWC,QAAQH,GACzB,OACE,gCACE,gBAACI,EAAA,EAAM,CAAClH,SAAS,SAAS7C,IAAKA,GAC7B,gBAACgK,EAAA,EAAO,KACN,2BACE,gBAAClH,GAAA,EAAU,CACTmH,KAAK,QACLxX,UAAWH,EAAQkX,WACnB7W,MAAM,UAAS,aACJ,OAAM,gBACH,cAAa,gBACb,OACdJ,QApBQgC,IAClBqV,EAAYrV,EAAMsE,iBAqBR,gBAAC,KAAQ,QAGb,gBAACqR,GAAA,EAAI,CAACvV,KAAMkV,EAAUnV,QAASI,EAAa6U,SAAUA,GjB5BzB,CAACQ,IACtC,OAAQA,GACN,IAAK,IACH,OAAO,EACT,IAAK,IACH,OAAO,EACT,IAAK,IACH,OAAO,EAEX,MAAM,IAAIhN,MAAM,oBAAsBgN,IiBoB3BC,CAAwB9O,OACvB,gBAAC+O,GAAA,EAAQ,CACP9X,QAAS,IAAY,qCACnBuC,WACqBiU,GAAuB,CAC1CpT,QACE,gBAAC+J,GAAA,EAAS,sLAOZ7K,MAAO,eACPD,SAAU,oBAGVgH,KACAZ,SAASsP,cAEZ,WAKL,gBAACD,GAAA,EAAQ,CACP9X,QAAS,IAAY,qCACnBuC,WACqBiU,GAAuB,CAC1CpT,QACE,gBAAC+J,GAAA,EAAS,2NAOZ7K,MAAO,QACPD,SAAU,qBd/FtB2G,MACFC,aAAa+O,QckGCvP,SAASsP,cAEZ,kBAKL,gBAAC9B,GAAY,KjBlHS,CAAC2B,IAC/B,OAAQA,GACN,IAAK,IACH,MAAO,QACT,IAAK,IACH,MAAO,UACT,IAAK,IACH,MAAO,QAEX,MAAM,IAAIhN,MAAM,oBAAsBgN,IiByGfK,CAAiBlP,OjB1FR,CAAC6O,IACjC,OAAQA,GACN,IAAK,IACH,OAAO,EACT,IAAK,IACH,OAAO,EACT,IAAK,IACH,OAAO,EAEX,MAAM,IAAIhN,MAAM,oBAAsBgN,IiBkF7BM,CAAmBnP,OAClB,gBAAC9I,EAAA,EAAM,CAACG,MAAM,UAAUJ,QAAS,IAAMF,EAAM+F,WAAS,WAIxD,gBAAC5F,EAAA,EAAM,CAACG,MAAM,UAAUJ,QAAS,IAAM4W,MAAsB,SAG7D,gBAAC3W,EAAA,EAAM,CAACG,MAAM,UAAUJ,QAAS,IAAM+W,MAAc,WAKzD,gBAACL,GAAqByB,SAAQ,CAAClS,MAAO4Q,IACpC,gBAACF,GAAawB,SAAQ,CAAClS,MAAO+Q,IAC5B,uBACEpU,GAAG,YACHkC,MAAO,CACLsT,UAAW,OACXjU,OAAQ,gBAAgB,EAAIF,EAAKE,cAGlCrE,EAAMU,cC9HnB,IAAYkP,IAAZ,SAAYA,GACV,iBACA,uBACA,qBACA,iBAJF,CAAYA,QAAY,KAgBxB,MAAM2I,GAA4B,CAAElJ,mBAAexN,GAEnD,SAAS2W,GAAQC,EAAkBC,GACjC,OAAQA,EAAOlY,MACb,KAAKoP,GAAaG,IAElB,KAAKH,GAAaC,OAElB,KAAKD,GAAaK,MAChB,MAAO,CAAEZ,cAAeqJ,GAC1B,KAAK9I,GAAa+I,IAChB,OAAOJ,GACT,QACE,MAAM,IAAIzN,OA0BhB,MAca8N,GAAsBtE,QAE/BzS,IACAyS,EAASvO,QAAQ+K,KAAMpK,IACrB,MAAM8K,EAAUqH,MAAMC,KAAKpS,EAAOE,MAC5BmS,EAAcvH,EAAQxL,OAI5B,IAAK,IAAI8P,EAAI,EAAGA,EAAIiD,EAAc,EAAGjD,IACnC,IAAK,IAAIC,EAAID,EAAI,EAAGC,EAAIgD,EAAahD,IACnC,GAAIvE,EAAQsE,KAAOtE,EAAQuE,GAAI,OAAO,EAG1C,OAAO,IAKAiD,GAAmB1E,I,UAC9B,MAAM2E,EAAgB,IACQ,QAAzB,EAAC3E,EAAS5F,uBAAe,QAAI,MACJ,QAAzB,EAAC4F,EAAS3F,uBAAe,QAAI,IAE5BuK,EAAoBD,EAAcjT,OAClCmT,EAAW7E,EAASvO,QAAQU,OAAQC,IACxC,GAAIA,EAAOE,KAAKZ,OAASkT,EAAmB,OAAO,EACnD,IAAK,IAAIpD,EAAI,EAAGA,EAAIoD,EAAmBpD,IACrC,IAAKpP,EAAOE,KAAKwS,SAASH,EAAcnD,IAAK,OAAO,EAEtD,OAAO,IAET,OAAuB,QAAvB,EAAOqD,aAAQ,EAARA,EAAUnT,cAAM,QAAI,GAOhBqT,GAAsBrZ,IACjC,MAAO4O,EAAU0K,GAAY,qBAAWd,GAASD,KAC1CgB,EAAWC,GAAgB,mBAvDT,CACzBxZ,I,UAEA,MAAO,CACLwR,QAAS,IAC2B,QAA/B,EAACxR,EAAMsU,SAAS5F,uBAAe,QAAI,MACJ,QAA/B,EAAC1O,EAAMsU,SAAS3F,uBAAe,QAAI,IAExC1I,WAA0B,QAAhB,EAAEjG,EAAMgK,gBAAQ,QAAK,GAC/ByP,aAAc,GACdjQ,QAASxJ,EAAMwJ,UA6C0BkQ,CAAmB1Z,KACvD2Z,EAAWC,GAAgB,oBAAS,GAC3C5Z,EAAM6Z,mBAAmB,IAAMN,EAAUtT,YACzC,MAAOsO,GAAY,mBACjB,KACE,MAAO,CACLM,WAZqBP,EAYGtU,EAAMsU,ULnJfwF,EKwIVxF,EAASvO,QAAQiB,IAAKN,GAAWA,EAAOE,KAAKZ,SLtI3CkP,OAAO,CAACC,EAAQnB,KAC3B,QAAanS,IAATmS,QAAiCnS,IAAXsT,EAC1B,OAAInB,EAAOmB,EAAenB,EACnBmB,GACN2E,EAAM,KK8IH/E,UAAWQ,GAAIvV,EAAMsU,SAASvO,QAAQiB,IAAKN,GAAWA,EAAOQ,QAC7D8N,aAAchV,EAAMsU,SAASrM,OAAOjI,EAAMsU,SAASrM,OAAOjC,OAAS,GACnE8O,aAAckE,GAAgBhZ,EAAMsU,UACpCM,gBAAiBgE,GAAmB5Y,EAAMsU,WAhBtB,IAACA,ELvINwF,IK4JfC,EAAe,KACnB5W,EAAiB,CACfG,QACE,gBAAC+Q,GAAmB,CAACE,SAAUA,EAAUD,SAAUtU,EAAMsU,WAE3D9R,MAAO,WAIX,qBAAWoU,GAAX,CAAiC,IAC/B1I,GAAcqL,EAAU/P,QAAS+P,EAAUtT,aAG7C,qBAAW4Q,GAAX,CAAyBkD,GAEzB,oBAAU,KAIJJ,EACFC,GAAa,GAGfnQ,GACE8P,EAAU/P,QACTgF,IACCA,EAAKxE,SAAWuP,EAAUtT,WAC1BuI,EAAKvE,YAAa,IAEpB,IAED,CAACsP,EAAUtT,aAEd,MAAOiB,EAAO8S,GAAY,mBAAS,GACnC,oBAAU,KAER,MAAMjU,EAAU/F,EAAMsU,SAASvO,QACzBmB,EAAQqO,GACZgE,EAAUtT,WAAWe,IAAKiT,I,MACxB,MAAMC,EAAQnU,EAAQ+K,KAAMpK,GAAWA,EAAOE,OAASqT,GACvD,OAAmB,QAAnB,EAAOC,aAAK,EAALA,EAAOhT,aAAK,QAAI,KAG3B8S,EAAS9S,GACK,IAAVA,GAAa6S,KAChB,CAACR,EAAUtT,aAEd,MAAOoC,EAAO8R,GAAY,mBAASna,EAAMsU,SAASrM,OAAO,IAEnDmS,EAAgB,K,QACpB,GAA+B,KAA3Bb,EAAUE,aAAqB,OACnC,GAAIzZ,EAAMsU,SAASvO,QAAQC,SAAWuT,EAAUtT,WAAWD,OAIzD,YAHAsB,GACE,yBAAyBtH,EAAMsU,SAASvO,QAAQC,iBAKpD,GAAIuT,EAAUtT,WAAW6K,KAAMlK,GAASA,IAAS2S,EAAUE,cAEzD,YADAlS,GAAwBgS,EAAUE,aAAb,sBAIvB,IAAI/S,EAAS1G,EAAMsU,SAASvO,QAAQ+K,KACjCpK,GAAWA,EAAOE,OAAS2S,EAAUE,cAExC,MAAMQ,EAAavT,aAAM,EAANA,EAAQE,KACrBX,OACWpE,IAAfoY,EACIV,EAAUtT,WACV,IAAIsT,EAAUtT,WAAYgU,GAChC,QAAmBpY,IAAfoY,EAA0B,CAC5B,GAAIV,EAAUE,aAAazT,OAASuO,EAASM,UAE3C,YADAtN,GAAwBgS,EAAUE,aAAb,iBAGvB,IAAkC,QAA9B,EAAAzZ,EAAMsU,SAAS5F,uBAAe,eAAE1I,QAAS,EAAG,CAE9C,MAAMqU,EAAiB,IACa,QAA/B,EAACra,EAAMsU,SAAS5F,uBAAe,QAAI,IACtCjI,OACCsK,IACqD,IAApDwI,EAAUE,aAAaL,SAASrI,IAEpC,GAAIsJ,EAAerU,OAAS,EAC1B,OAA8B,IAA1BqU,EAAerU,YACjBuB,GACE,GAAGgS,EAAUE,gDAAgDY,EAAe,WAIhF9S,GACE,GACEgS,EAAUE,mDLrOmB,CAACxE,IAC1C,QAAapT,IAAToT,EACJ,OAAOA,EAAKC,OAAO,CAACC,EAAQnB,EAAMvC,IAClB,IAAVA,EAAoBuC,EACjBmB,EAAS,KAAOnB,EACtB,KKiO8CsG,CACrCD,MASR,YAHA9S,GACKgS,EAAUE,aAAb,8BAKJ,MAAMc,EAAe,OAAH,wBACbhB,GAAS,CACZE,aAAc,GACdxT,eAEFuT,EAAae,GACbjB,EAAS,CAAE9Y,KAAMoP,GAAaK,QAE9B,MAAMuK,EAAYxS,GAChBhI,EAAMsU,SAASrM,OACff,EAAQR,EAAOQ,OAEEsT,EAAUtT,MAAUmB,EAAMnB,MAK7CM,GACE,GAAGd,EAAOE,iBAAiBF,EAAOQ,mBAEpCiT,EAASK,IAGLC,EAAgBvY,IACE,KAAlBA,EAAMwY,SAERN,KAIJ,oBAAU,KACR7Y,SAASmB,iBAAiB,QAAS+X,GAAc,GAC1C,KACLlZ,SAASoB,oBAAoB,QAAS8X,GAAc,MAIxD,MAAME,EACJ,gBAACjJ,GAAiB,CAChBzL,WAAYsT,EAAUtT,WACtBF,QAAS/F,EAAMsU,SAASvO,QACxB4L,gBAAiB3R,EAAMsU,SAASvO,QAAQC,OACxCiC,OAAQjI,EAAMsU,SAASrM,OACvBf,MAAOA,IAIX,OACE,gBAACwM,EAAA,EAAI,CAAC/O,WAAS,EAACgP,UAAU,OACxB,gBAACD,EAAA,EAAI,CAAC/O,WAAS,EAACgP,UAAU,SAASxO,WAAW,UAC5C,gBAACgP,EAAA,EAAU,CAAC9T,QAAQ,aAAaL,EAAMsU,SAAS9R,OAChD,gBAAC2R,EAAA,EAAU,CAAC9T,QAAQ,aAAaL,EAAMsU,SAASsG,UAChD,gBAACtN,EAAA,EAAG,CAACE,EAAG,KACR,gBAACiB,GAAmB,CAClBG,SAAUA,EACVC,kBAAmB,KACjByK,EAAS,CAAE9Y,KAAMoP,GAAa+I,OAEhCjK,gBAAiB1O,EAAMsU,SAAS5F,gBAChCC,gBAAiB3O,EAAMsU,SAAS3F,gBAChCpI,SAAWuI,IACT0K,EAAa,OAAD,wBACPD,GAAS,CACZE,aAAc3K,QAKpB,gBAACxB,EAAA,EAAG,CAACE,EAAG,IACR,gBAACkG,EAAA,EAAI,CAAC/O,WAAS,EAACsP,QAAQ,UACtB,gBAAC9T,EAAA,EAAM,CACLE,QAAQ,WACRC,MAAM,UACNJ,QAAS,KACPoZ,EAAS,CAAE9Y,KAAMoP,GAAaC,WAC/B,UAIH,gBAACvC,EAAA,EAAG,CAACE,EAAG,IACR,gBAACrN,EAAA,EAAM,CAACE,QAAQ,WAAWC,MAAM,UAAUJ,QAASka,GAAa,WAInE,gBAAC9M,EAAA,EAAG,CAACE,EAAG,IACR,gBAACkG,EAAA,EAAI,CAAC/O,WAAS,EAACsP,QAAQ,UACtB,gBAAC1C,GAAgB,CACfC,QAAS+H,EAAU/H,QACnB9C,gBAAiB1O,EAAMsU,SAAS5F,gBAChCxO,QAAU8P,IACRsJ,EAAS,CAAE9Y,KAAMoP,GAAaG,IAAKC,eAIzC,gBAAC1C,EAAA,EAAG,CAACE,EAAG,IACR,gBAACrN,EAAA,EAAM,CACLE,QAAQ,WACRC,MAAM,UACNJ,QAAS,KACP,MAAMqa,EAAe,OAAH,wBACbhB,GAAS,CACZ/H,QAASmE,GAAQ4D,EAAU/H,WAE7BgI,EAAae,KACd,YAKJI,I,iBCjXA,MAAME,GAAc,IAEvB,gBAACvN,EAAA,EAAG,CAACE,EAAG,GACN,gBAACsN,GAAA,EAAK,KACJ,gBAACxN,EAAA,EAAG,CAACE,EAAG,G,oMAIN,0BACE,2QAMA,qNAKA,oJAIA,0B,iGAGE,0BACE,sWAQA,mFCpCHuN,GAAY,IAErB,gBAACzN,EAAA,EAAG,CAACE,EAAG,GACN,gBAACsN,GAAA,EAAK,KACJ,gBAACxN,EAAA,EAAG,CAACE,EAAG,G,8MAKN,0BACE,0B,+BAEE,0BACE,iFACA,oEACA,oFAGJ,0B,2BAEE,0BACE,6N,2SC6BhB,IAAYwN,IAAZ,SAAYA,GACV,UACA,UACA,UACA,UAJF,CAAYA,QAAE,KAOP,MAAMC,GAAaC,IACxB,OAAQA,GACN,KAAKF,GAAGjL,IACN,MAAO,IACT,KAAKiL,GAAGG,IACN,MAAO,IACT,KAAKH,GAAGI,IACN,MAAO,IACT,KAAKJ,GAAGK,IACN,MAAO,MA0BN,SAASC,GAAMC,GACpB,OAAQA,EAAEL,IACR,KAAKF,GAAGG,IACN,OAAOI,EAAEC,IAAMD,EAAEE,IACnB,KAAKT,GAAGI,IACN,OAAOG,EAAEC,IAAMD,EAAEE,IACnB,KAAKT,GAAGjL,IACN,OAAOwL,EAAEC,IAAMD,EAAEE,IACnB,KAAKT,GAAGK,IACN,OAAOE,EAAEC,IAAMD,EAAEE,KAQvB,MAAMC,GAAc,IAAIC,OAAOC,OAAOC,GAAG,YACnCC,GAAa,IAAIH,OAAOC,OAAOC,GAAG,mBAClCE,GAAuB,IAAIJ,OAAOC,OAAOC,GAAG,UAAW,KACvDG,GAAa,IAAIL,OAAOC,OAAOC,GAAG,MAAO,KAkB/C,SAASI,GAAQC,GAIf,IAAIpP,EAAIoP,EAAEjL,OAAOkL,QAAQJ,GAAsB,KAG/CjP,EAAIA,EAAEqP,QAAQH,GAAY,KAE1B,MAAMzT,EAASuE,EAAErE,MAAM,KACjBuE,EAAoB,GAC1B,IAAK,IAAI8I,EAAI,EAAGA,EAAIvN,EAAOvC,OAAQ8P,IACjC,GAAI4F,GAAYU,KAAK7T,EAAOuN,IAAK,CAC/B,MAAMN,EAAI6G,GAAuB9T,EAAOuN,IACxC9I,EAAEoI,KAAK,CAAEkH,MAAO9G,EAAG+G,IAAK/G,SACnB,GAAIsG,GAAWM,KAAK7T,EAAOuN,IAAK,CACrC,MAAM0G,EAAKjU,EAAOuN,GAAGrN,MAAM,KACrB+M,EAAI6G,GAAuBG,EAAG,IAC9BhP,EAAI6O,GAAuBG,EAAG,IAChChH,GAAKhI,EACPR,EAAEoI,KAAK,CAAEkH,MAAO9G,EAAG+G,IAAK/O,IAExBR,EAAEoI,KAAK,CAAEkH,MAAO9O,EAAG+O,IAAK/G,IAI9B,OAAOxI,EAGT,SAASqP,GAAuBvP,GAC9B,MAAM0I,EAAIiH,OAAO3P,GACjB,GAAI0I,EAAI,IACN,MAAM,IAAI1K,MAAM,qCAElB,OAAO0K,EAqBF,SAASkH,GAAiBxB,EAAQyB,GACvC,MAAMnB,EAAMS,GAAQU,EAAGnB,KACjBC,EAAMQ,GAAQU,EAAGlB,KACjBmB,EAAwC7b,OAAOC,OAAO,MAuB5D,OAtBAwa,EAAIqB,QAASC,IACX,IAAK,IAAIC,EAAWD,EAASR,MAAOS,GAAYD,EAASP,IAAKQ,IAC5DtB,EAAIoB,QAASG,IACX,IACE,IAAIC,EAAWD,EAASV,MACxBW,GAAYD,EAAST,IACrBU,IACA,CACA,MAAMC,EAAuB,CAAEhC,KAAIM,IAAKuB,EAAUtB,IAAKwB,GACvD,OAAQ/B,GACN,KAAKF,GAAGI,IACN,GAAIE,GAAM4B,GAAa,GAAM,EAAG,SAChC,MACF,KAAKlC,GAAGK,IACN,GAAIC,GAAM4B,GAAa,EAAG,SAG9BN,EAAW1B,EAAK6B,EAAW,IAAME,GAAYC,OAK9Cnc,OAAOyS,OAAOoJ,GCjNhB,MAAMO,GACXC,IAEA,MAAMC,EAAe,sBAAexb,IAC7Byb,EAAaC,GAAiB,mBAAS,KAC5C,MAAMC,EAAeJ,IAErB,OADAC,EAAaxQ,QAAU2Q,EAChBA,IAST,MAAO,CAHQ,IACNH,EAAaxQ,QALNC,IACduQ,EAAaxQ,QAAUC,EACvByQ,EAAczQ,MCDL2Q,GAAyBzd,IACpC,MAAM,SAAEsU,EAAQ,SAAEC,GAAavU,EACzBwU,EAAgBF,EAASE,cACzBC,EAA0BD,EAC9B,gBAACnH,GAAA,EAAS,KAAEmH,GADkC,KAI1CkJ,EAAiD,GACvD,GAAIpJ,EAASqJ,IAAK,CAChB,MAAMC,EAAgBlB,GAAiB1B,GAAGjL,IAAKuE,EAASqJ,KACpDC,EAAc5X,OAAS,GACzB0X,EAAOtI,KAAK,CAAEyI,QAAS,WAAYC,QAASF,EAAc5X,SAE9D,GAAIsO,EAASyJ,IAAK,CAChB,MAAMC,EAAgBtB,GAAiB1B,GAAGK,IAAK/G,EAASyJ,KACpDC,EAAchY,OAAS,GACzB0X,EAAOtI,KAAK,CAAEyI,QAAS,cAAeC,QAASE,EAAchY,SAEjE,GAAIsO,EAAS2J,IAAK,CAChB,MAAMC,EAAgBxB,GAAiB1B,GAAGG,IAAK7G,EAAS2J,KACpDC,EAAclY,OAAS,GACzB0X,EAAOtI,KAAK,CAAEyI,QAAS,iBAAkBC,QAASI,EAAclY,SAEpE,GAAIsO,EAAS6J,IAAK,CAChB,MAAMC,EAAgB1B,GAAiB1B,GAAGI,IAAK9G,EAAS6J,KACpDC,EAAcpY,OAAS,GACzB0X,EAAOtI,KAAK,CAAEyI,QAAS,WAAYC,QAASM,EAAcpY,SAE9D,IAAIqY,EA0BJ,OAzBsB,IAAlBX,EAAO1X,OACTqY,EAAU,GAAGX,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,UACjB,IAAlBH,EAAO1X,OAChBqY,EACE,GAAGX,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,eAE/BH,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,UACT,IAAlBH,EAAO1X,OAChBqY,EACE,GAAGX,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,YAE/BH,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,gBAE/BH,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,UACT,IAAlBH,EAAO1X,SAChBqY,EACE,GAAGX,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,YAE/BH,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,YAE/BH,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,gBAE/BH,EAAO,GAAGI,WAAWJ,EAAO,GAAGG,WAIpC,gBAACvQ,EAAA,EAAG,KACDmH,EACD,gBAACnH,EAAA,EAAG,CAACE,EAAG,IACR,gBAACH,GAAA,EAAS,KACR,oEACA,sBAAIrI,MAAO,CAAE0P,UAAW,IACtB,0BACG,gBAAgBe,GACfnB,EAASgK,eACT,kCACqB7I,GACrBnB,EAASgK,eACT,YAED/J,EAASS,aAAa9N,OAASqN,EAASQ,UACrC,GACA,4EAEN,0B,OACOU,GAAUnB,EAASgK,eAAgB,a,+BACzBD,E,cAEjB,gBAAC,EAAK,CAAChZ,SAAO,EAACD,QAASkP,EAASiK,WAC/B,0B,0BAC0B9I,GAAUnB,EAASiK,UAAW,UAAW,I,sDAIrE,gBAAC,EAAK,CAAClZ,SAAO,EAACD,SAAUkP,EAASiK,WAChC,8FAIF,gBAAC,EAAK,CAAClZ,SAAO,EAACD,QAASkP,EAASkK,WAC/B,kIAKF,8FAKJ,gBAAClR,EAAA,EAAG,CAACE,EAAG,IACR,gBAACH,GAAA,EAAS,K,2EACiE,IACxErN,EAAMsU,SAASrM,OAAOjB,IAAI,CAACqB,EAAOoJ,IACjC,wBAAMtK,IAAKsK,GACRA,EAAQ,EAAI,KAAO,GACpB,yBAAIpJ,EAAM1G,M,IAAW0G,EAAMnB,Q,KAKjC,gBAACoG,EAAA,EAAG,CAACE,EAAG,MCjHDiR,GACXze,I,QAEA,MAAM,SAAEuG,EAAQ,SAAEqI,EAAQ,kBAAEC,GAAsB7O,GAE3C8O,EAAOC,GAAiB,mBAAS,IAClCC,EAAYF,IAChBC,EAAcD,GACdvI,EAASuI,IAELG,EAAW,iBAAO,OACjBC,EAAqBC,GAA0B,mBAAS,GAEzDC,EACJR,EAASS,gBAA8B,IAAb,YACW,QAAlC,EAAkB,QAAlB,EAACJ,aAAQ,EAARA,EAAUpC,eAAO,eAAEyC,sBAAc,QAAI,EACrCJ,EAEAK,EAAqBC,IACzBL,EAAuBK,EAAoB,EAAIA,EAAoB,IA0CrE,OAvCA,oBAAU,KACR,MAAMC,EAAiCR,EAASpC,QAChD4C,EAAaC,QACT,aACFD,EAAaH,eAAiBL,EAASpC,QAAQ1G,MAAMH,OACrDyJ,EAAaE,aAAeV,EAASpC,QAAQ1G,MAAMH,SAEnDyJ,EAAaH,eAAiBF,EAC9BK,EAAaE,aAAeP,KAIhC,oBAAU,K,MACR,OAA8B,QAA9B,EAAQR,EAASS,qBAAa,eAAE7O,MAC9B,KAAK,GAAaqP,OAEhB,GADAhB,IACuB,IAAnBO,EAAsB,OAC1BJ,EACEF,EAAMgB,MAAM,EAAGV,EAAiB,GAAKN,EAAMgB,MAAMV,IAEnDG,EAAkBH,EAAiB,GACnC,MACF,KAAK,GAAaW,IAChBf,EACEF,EAAMgB,MAAM,EAAGV,GACbR,EAASS,cAAcW,OACvBlB,EAAMgB,MAAMV,IAEhBG,EAAkBH,EAAiB,GACnCP,IACA,MACF,KAAK,GAAaoB,MAChBjB,EAAS,IACTO,EAAkB,GAClBV,OAMJ,gBAAC3I,EAAA,EAAS,CACR7F,QAAQ,SACR+F,MAAM,aACN6I,SAAUA,EACViB,WAAY,CACVC,SAAU,YACVnL,MAAO,CACLoL,WAAY,uDAEdC,YAAY,EACZC,aACE,gBAACC,GAAA,EAAc,CAACC,SAAS,OACvB,gBAACC,GAAA,EAAU,cACE,oBACXvQ,QAAS,KACP8O,EAAS,IACTO,EAAkB,KAGpB,gBAACU,GAAA,EAAK,SAKd9J,MAAO2I,GAAS,YAAW,IAAM,IACjCvI,SAAWrE,IACT,IAAIwO,EAAWxO,EAAMyO,OAAOxK,MAC5B,GAAIuK,EAAS1K,OAAS,GAAI,OACtB,cAAU0K,EAAWA,EAASE,UAAU,EAAGF,EAAS1K,OAAS,SAK/CnE,IAJA,IAAI6O,GAAUI,KAAMd,KAChC,aAAarJ,QAAQqJ,IAAW,IAC7BA,IAGPhB,EAAS0B,GACTnB,EAAkBrN,EAAMyO,OAAOrB,iBAE/BC,EAAkBrN,EAAMyO,OAAOrB,eAAiB,OCtG7CoP,GAAmB1e,IAC9B,MAAM,QAAEE,GAAYF,EACpB,OACE,gBAAC+E,EAAe,CAACG,QAAM,GACrB,gBAACI,EAAY,CAACJ,QAAM,GACjB,CAAC,EAAG,EAAG,GAAG8B,IAAK2X,GAEZ,gBAACrR,EAAA,EAAG,CAACnG,IAAKwX,EAAOnR,EAAG,GAClB,gBAAC0D,GAAoB,CACnBhR,QAAS,KACPA,EAAQye,EAAM7c,aAEhBkO,OAAQ2O,EAAM7c,WACdqP,YAAY,OAMtB,gBAAC7L,EAAY,CAACJ,QAAM,GACjB,CAAC,EAAG,EAAG,GAAG8B,IAAK2X,GAEZ,gBAACrR,EAAA,EAAG,CAACnG,IAAKwX,EAAOnR,EAAG,GAClB,gBAAC0D,GAAoB,CACnBhR,QAAS,KACPA,EAAQye,EAAM7c,aAEhBkO,OAAQ2O,EAAM7c,WACdqP,YAAY,OAMtB,gBAAC7L,EAAY,CAACJ,QAAM,GACjB,CAAC,EAAG,EAAG,GAAG8B,IAAK2X,GAEZ,gBAACrR,EAAA,EAAG,CAACnG,IAAKwX,EAAOnR,EAAG,GAClB,gBAAC0D,GAAoB,CACnBhR,QAAS,KACPA,EAAQye,EAAM7c,aAEhBkO,OAAQ2O,EAAM7c,WACdqP,YAAY,OAMtB,gBAAC7L,EAAY,CAACJ,QAAM,GACjB,CAAC,GAAG8B,IAAK2X,GAEN,gBAACrR,EAAA,EAAG,CAACnG,IAAKwX,EAAOnR,EAAG,GAClB,gBAAC0D,GAAoB,CACnBhR,QAAS,KACPA,EAAQye,EAAM7c,aAEhBkO,OAAQ2O,EAAM7c,WACdqP,YAAY,SC5Cf,GAAqBnR,I,MAChC,MAAMiI,EAASjI,EAAMiI,OACff,EAAmB,QAAd,EAAGlH,EAAMkH,aAAK,QAAI,GAEtB2K,EAAQC,GAAa,mBAAS,IAC9BC,EAAWC,GAAgB,mBAAS,IACrCC,EAAqBjK,GAAkBC,EAAQf,GAAOvF,KACtDuQ,EAAoBjK,EAAOA,EAAOjC,OAAS,GAAGkB,MAC9CiL,EAlBW,EAkBkBjL,EAAQgL,EAhBxB,IAiBbG,EAAiBJ,IAAuBF,EAC1CM,GAAgBP,EAAUD,EAAS,GACvC,MAAMS,EAAoBD,EAAiB,KACzC,gBAAC/E,EAAA,EAAG,KACF,uBACEnG,IAAK0K,EACLU,QAAS,aACTjO,MA/BG,IAgCHD,OA/BG,GAgCHmO,MAAM,8BAEN,wBACEC,GA/BS,EAgCTC,GAAI,GACJE,GAAI,IACJE,GAAI,GACJC,OAAO,QACPC,YAAY,MAEb,MAEC,MAAMC,EAAahL,EAAOjC,OAC1B,OAAOiC,EAAOjB,IAAI,CAACqB,EAAOoJ,KACxB,IAAInR,EA3CQ,QAoDZ,OARiB4G,GAASmB,EAAMnB,QAG5B5G,EADEmR,IAAUwB,EAAa,GAAKhL,EAAOwJ,EAAQ,GAAGvK,MAAQA,EApDrD,UADF,WA4DH,0BACEC,IAAKsK,EACLyB,GAtDG,EAwDAjL,EAAOwJ,GAAOvK,MAAQgL,EAtDpB,IAwDLiB,GAAI,GACJnG,EA3DG,EA4DHoG,KAAM9S,OAtBb,GA2BD,wBACEmS,GAAIN,EACJS,GAAIT,EACJO,GAAI,GACJI,GAAI,GACJC,OA7ES,UA8ETC,YAAY,MAEd,wBACEzO,EAAE,MACFC,EAAE,KACF6O,WAAW,SACX/B,SAAS,KACTgC,WAAY,IACZF,KAtFS,WAwFRpL,GAAkBC,EAAQf,GAAOvF,KAClC,2BAAS4R,cAAc,YAAYC,OAAO,WAAWC,IAAI,OACzD,2BACEF,cAAc,OACdC,OAAQ,kBACRC,IAAI,UAQd,OADIpB,GAAgBL,EAAaC,GAC1BK,GCjEH,GAAY,OAAApT,EAAA,GAAW,IACpB,OAAAE,EAAA,GAAa,CAClBwf,WAAY,CACVnR,QAAS,MACTjO,gBAAiB,YACjBqf,SAAU,QACVvf,OAAQ,kBAOd,IAAY,IAAZ,SAAYsQ,GACV,iBACA,uBACA,qBACA,iBAJF,CAAY,QAAY,KAgBxB,MAAM,GAA4B,CAAEP,mBAAexN,GAEnD,SAAS,GAAQ4W,EAAkBC,GACjC,OAAQA,EAAOlY,MACb,KAAK,GAAauP,IAElB,KAAK,GAAaF,OAElB,KAAK,GAAaI,MAChB,MAAO,CAAEZ,cAAeqJ,GAC1B,KAAK,GAAaC,IAChB,OAAO,GACT,QACE,MAAM,IAAI7N,OAsBhB,MAAM,GACJ9K,I,UAEA,MAAO,CACLgK,SAAwB,QAAhB,EAAEhK,EAAMgK,gBAAQ,QAAI,CAC1B8U,QAAS,GACTC,eAA8C,QAAhC,EAAgB,QAAhB,EAAE/e,EAAMgK,gBAAQ,eAAE+U,sBAAc,QAAI,GAEpDvV,QAASxJ,EAAMwJ,QACfiQ,aAAc,KAILuF,GAAwBhf,I,cACnC,MAAO4O,EAAU0K,GAAY,qBAAW,GAAS,KAC1CC,EAAWC,GAAgB2D,GAAc,IAC9C,GAAmBnd,KAEd2Z,EAAWC,GAAgB,oBAAS,IAEpCqF,EAAUC,GAAe,oBAAS,IAClCC,EAAUC,GAAejC,GAAc,KAAM,IAC7CkC,EAAkBC,GAAuB,mBACf,QADuB,EAC/B,QAD+B,EACxC,QADwC,EACtDtf,EAAMgK,gBAAQ,eAAE8U,eAAO,eAAE9Y,cAAM,QAAI,IAE9BuZ,EAAqBC,GAA0BrC,GACpD,KAAK,eAA+B,QAA/B,EAAe,QAAf,EAACnd,EAAMgK,gBAAQ,eAAE+U,sBAAc,QAAI,KAEnCU,EAAkBC,GAAuBvC,GAAc,IAAM,GAC9DwC,EAAc,IAAMJ,IAAwBE,IAG5CG,EAAe,iBAAevV,KAAKgE,OACnCwR,EAAgB,sBAAuBhe,IACtCie,EAAkBC,GAAuB,wBAC9Cle,GAEI5B,EAAU,KAEhB,oBAAU,KACR,MAAMmd,EACHpd,EAAMsU,SAASiK,UAAY,GAC1BoB,KAAiB3f,EAAMsU,SAASiK,WAClCve,EAAMsU,SAASgK,iBAAmB/E,IAAYvP,SAAS8U,QAAQ9Y,OAC7DoX,GAAK+B,KAAYC,EAAYhC,KAGnCpd,EAAM6Z,mBAAmB,IAAMN,IAAYvP,UAC3C,MAAOuK,GAAY,mBACjB,KACS,CACLQ,UAAW/U,EAAMsU,SAASgK,eAC1BtJ,aAAchV,EAAMsU,SAASrM,OAAOjI,EAAMsU,SAASrM,OAAOjC,OAAS,MAOnEga,EAAgB,iBNKjB,SAA6B1L,GAClC,MAAMsI,EAA0B,GAahC,OAZItI,EAASqJ,KACXf,EAAWxH,QAAQsH,GAAiB1B,GAAGjL,IAAKuE,EAASqJ,MAEnDrJ,EAASyJ,KACXnB,EAAWxH,QAAQsH,GAAiB1B,GAAGK,IAAK/G,EAASyJ,MAEnDzJ,EAAS2J,KACXrB,EAAWxH,QAAQsH,GAAiB1B,GAAGG,IAAK7G,EAAS2J,MAEnD3J,EAAS6J,KACXvB,EAAWxH,QAAQsH,GAAiB1B,GAAGI,IAAK9G,EAAS6J,MAEhDvB,EMnBsBqD,CAAoBjgB,EAAMsU,WAGvD,oBAAU,KACR,MAAMwB,EAAIE,KAAKC,MACbD,KAAKE,SAAWF,KAAKC,MAAM+J,EAAcnT,QAAQ7G,SAEnD+Z,EAAoBC,EAAcnT,QAAQiJ,IACtC9V,EAAMsU,SAASgK,gBAAkB0B,EAAcnT,QAAQ7G,QAGzDga,EAAcnT,QAAQqT,OAAOpK,EAAG,IAEjC,CAACuJ,EAAkBJ,IAEtB,MAAMlF,EAAe,KACnB5W,EAAiB,CACfG,QACE,gBAACma,GAAqB,CAAClJ,SAAUA,EAAUD,SAAUtU,EAAMsU,WAE7D9R,MAAO,WAIX,oBAAU,KACiB,IAArB6c,GAAwBtF,KAC3B,IAEH,qBAAWnD,GAAX,CAAiC,IAC/B1I,GAAcqL,IAAY/P,QAAS+P,IAAYvP,WAGjD,qBAAW6M,GAAX,CAAyBkD,GAEzB,oBAAU,KAIJJ,EACFC,GAAa,GAGfnQ,GACE8P,IAAY/P,QACXgF,IACCA,EAAKxE,SAAWuP,IAAYvP,SAC5BwE,EAAKvE,YAAa,IAEpB,IAED,CAACsP,IAAYvP,WAEhB,MAAO9C,EAAO8S,GAAY,mBAAS,GACnC,oBAAU,KAER,MAAM9S,EAAQqO,GACZgE,IAAYvP,SAAS8U,QAAQ9X,IAAKmZ,GAChC7E,GAAM6E,EAAOjD,aAAeiD,EAAOzZ,OAAS,EAAI,IAGpDsT,EAAS9S,IACR,CAACqS,IAAYvP,SAAS8U,UAEzB,MAAOzW,EAAO8R,GAAY,mBAASna,EAAMsU,SAASrM,OAAO,IAEnDmS,EAAgB,KACpB,GAAiC,KAA7Bb,IAAYE,aAAqB,OACrC,GAAI0F,IAEF,YADA3X,GAAuB,yBAGzB,MAAMd,EAAS+V,OAAOlD,IAAYE,cAElC,GADkB/S,IAAW4U,GAAMwE,GAEjCtY,GAAuB,oBAGvB,GADAD,GAAwBgS,IAAYE,aAAf,mBACjBzZ,EAAMsU,SAASkK,UAEjB,YADAlF,EAAS,CAAE9Y,KAAM,GAAayP,QAIlC,MAAMkQ,EAAiB,CACrBzZ,SACAwW,UAAW4C,EACXM,SAAS,GAEL7F,EAAe,OAAH,wBACbhB,KAAW,CACdE,aAAc,GACdzP,SAAU,CACR8U,QAAS,IAAIvF,IAAYvP,SAAS8U,QAASqB,GAC3CpB,eAAgBY,OAGpBnG,EAAae,GACbjB,EAAS,CAAE9Y,KAAM,GAAayP,QAE9B,MAAMuK,EAAYxS,GAAkBhI,EAAMsU,SAASrM,OAAQf,EAAQ,GAChDsT,EAAUtT,MAAUmB,EAAMnB,MAM7CiT,EAASK,GACT8E,EAAoBD,EAAmB,IAGnC5E,EAAgBvY,IACpB,GAAsB,KAAlBA,EAAMwY,QAAgB,CAExB,GAAIuE,EAEF,YADAoB,IAGFjG,MAIJ,oBAAU,KACR7Y,SAASmB,iBAAiB,QAAS+X,GAAc,GAC1C,KACLlZ,SAASoB,oBAAoB,QAAS8X,GAAc,MAIxD,MAAM4F,EAAc,KAClBT,EAAa/S,QAAUxC,KAAKgE,MAC5B6Q,GAAY,GACZW,EAAchT,QAAUyT,YAAY,KAClC,GAAInB,IAAY,OAChB,MAAMJ,EAAiB/I,KAAKuK,OACzBlW,KAAKgE,MAAQuR,EAAa/S,SAAW,KAExC6S,EAAoBX,GACpB,MAAMyB,EAA2B,CAC/B/G,aAAcF,IAAYE,aAC1BjQ,QAAS+P,IAAY/P,QACrBQ,SAAU,CACR8U,QAASvF,IAAYvP,SAAS8U,QAC9BC,eAAgBY,MAGpBnG,EAAagH,IACZ,MAGL,OACE,gBAAClb,EAAY,CAACJ,QAAM,GAClB,gBAACH,EAAe,CAACG,QAAM,GACrB,gBAACiP,EAAA,EAAU,CAAC9T,QAAQ,aAAaL,EAAMsU,SAAS9R,OAChD,gBAAC2R,EAAA,EAAU,CAAC9T,QAAQ,aAAaL,EAAMsU,SAASsG,UAChD,gBAACtN,EAAA,EAAG,CAACE,EAAG,KACPyR,IAAaE,KACZ,gBAACve,EAAmB,CAACV,QAASmgB,GACN,IAArBhB,GAA4C,IAAlBM,IACvB,iBACA,mBAGR,gBAAC,EAAK,CAACva,QAAS+Z,KACd,gBAAChL,EAAA,EAAU,CAAC9T,QAAQ,KAAKC,MAAM,aAAW,WAI1C2e,GACA,gBAACla,EAAe,CAACG,QAAM,GACrB,gBAACoI,EAAA,EAAG,CAACE,EAAG,KACR,gBAAC,EAAK,CAACnI,SAAO,EAACD,OAAQ+Z,KAAkC,MAApBW,GACnC,gBAAC/a,EAAe,CAACG,QAAM,GACrB,gBAACI,EAAY,CAACJ,QAAM,GAClB,gBAACiP,EAAA,EAAU,CAAC9T,QAAQ,MAAMyf,aAAgB,EAAhBA,EAAkBtE,KAC5C,gBAACrH,EAAA,EAAU,CAAC9T,QAAQ,MACjB4a,GAAU6E,aAAgB,EAAhBA,EAAkB5E,KAE/B,gBAAC/G,EAAA,EAAU,CAAC9T,QAAQ,MAAMyf,aAAgB,EAAhBA,EAAkBrE,MAG9C,gBAACgD,GAAyB,CACxB7P,SAAUA,EACVC,kBAAmB,KACjByK,EAAS,CAAE9Y,KAAM,GAAamY,OAEhCpS,SAAWuI,IACT0K,EAAa,OAAD,wBACPD,KAAW,CACdE,aAAc3K,QAKpB,gBAACxB,EAAA,EAAG,CAACE,EAAG,IACR,gBAAClI,EAAY,CAACJ,QAAM,GAClB,gBAAC/E,EAAA,EAAM,CACLE,QAAQ,WACRC,MAAM,UACNJ,QAAS,KACPoZ,EAAS,CAAE9Y,KAAM,GAAaqP,WAC/B,UAIH,gBAACvC,EAAA,EAAG,CAACE,EAAG,IACR,gBAACrN,EAAA,EAAM,CACLE,QAAQ,WACRC,MAAM,UACNJ,QAASka,GAAa,WAK1B,gBAAC9M,EAAA,EAAG,CAACE,EAAG,IACR,gBAAClI,EAAY,CAACJ,QAAM,GAClB,gBAACwZ,GAAe,CACdxe,QAAU8P,IACRsJ,EAAS,CAAE9Y,KAAM,GAAauP,IAAKC,kBAQjD,gBAAC1K,EAAY,CAACJ,QAAM,GAClB,gBAACH,EAAe,CAAC3E,UAAWH,EAAQ2e,WAAY1Z,QAAM,GACpD,2BAAMlF,EAAMsU,SAASgK,eAAiBe,GACtC,oDAEmC,KAAX,QAAzB,EAACrf,EAAMsU,SAASiK,iBAAS,QAAI,IAC5B,gBAACxZ,EAAe,CAAC3E,UAAWH,EAAQ2e,WAAY1Z,QAAM,GACpD,2BAAMya,KACN,6CAGsB,QAAzB,EAAC3f,EAAMsU,SAASiK,iBAAS,QAAI,GAAK,GACjC,gBAACxZ,EAAe,CAAC3E,UAAWH,EAAQ2e,WAAY1Z,QAAM,GACpD,4BdzYS4U,Ec0YF,CAAC,EAAG9Z,EAAMsU,SAASiK,UAAYoB,MdxYrCzK,OAAO,CAACC,EAAQnB,KAC3B,QAAanS,IAATmS,QAAiCnS,IAAXsT,EAC1B,OAAInB,EAAOmB,EAAenB,EACnBmB,GACN2E,EAAM,IcqYM,QAEH,+CAIN,gBAAC,GAAiB,CAAC7R,OAAQjI,EAAMsU,SAASrM,OAAQf,MAAOA,IACzD,2B,YACYuO,GAAUvO,EAAO,kB,OAAuB,IACjDuO,GAAUvO,EAAO,UAEpB,gBAAC5B,EAAY,CAACJ,QAAM,GACjBqU,IACEvP,SAAS8U,QAAQrY,OACf0Z,GAAW7E,GAAM6E,EAAOjD,aAAeiD,EAAOzZ,QAEhDM,IAAI,CAACmZ,EAAQrK,IAEV,uBAAK9Q,MAAO,CAAE1F,OAAQ,cAAgB6H,IAAK2O,GACxCqK,EAAOjD,UAAU1B,IACjBP,GAAUkF,EAAOjD,UAAUhC,IAC3BiF,EAAOjD,UAAUzB,I,IAAM0E,EAAOzZ,UAKzC,gBAAC,EAAK,CAACrB,SAAO,EAACD,OAAQpF,EAAMsU,SAASkK,WACpC,gBAACzZ,EAAe,CAACG,QAAM,GACrB,2B,kBAAqBma,EAAmBnY,GACxC,gBAAC5B,EAAY,CAACJ,QAAM,GACjBqU,IACEvP,SAAS8U,QAAQrY,OACf0Z,GAAW7E,GAAM6E,EAAOjD,aAAeiD,EAAOzZ,QAEhDM,IAAI,CAACmZ,EAAQrK,IAEV,uBAAK9Q,MAAO,CAAE1F,OAAQ,cAAgB6H,IAAK2O,GACxCqK,EAAOjD,UAAU1B,IACjBP,GAAUkF,EAAOjD,UAAUhC,IAC3BiF,EAAOjD,UAAUzB,I,IAAM0E,EAAOzZ,YAO7C,gBAAC3G,EAAa,CACZG,QAAS,KACPqJ,KACIsW,EAAchT,SAAS4T,cAAcZ,EAAchT,SACvDgT,EAAchT,aAAUhL,EACxB2X,EAAa,OAAD,wBACP,GAAmBxZ,IAAM,CAC5BgK,SAAU,CAAE8U,QAAS,GAAIC,eAAgB,MAE3CG,GAAY,GACZE,GAAY,GACZE,EAAoB,GACpBS,OAAoBle,GACpB2d,EAAuB,GACvBE,EAAoB,KACrB,gBdxcQ,IAAI5F,G,iBeNvB,MAAM,GAAY,OAAA5a,EAAA,GAAYC,GACrB,OAAAC,EAAA,GAAa,CAClBshB,KAAM,CACJphB,OAAQ,kBACRqhB,cAAe,OACftc,OAAQ,QAEV2L,OAAQ,CACN3L,OAAQlF,EAAMyhB,WAAWC,OAAOC,WAAa,UActCC,IALD,aAAiB,CAAC/gB,EAAO2N,IACnC,uBAAKA,IAAKA,GAAa3N,EAAMU,WAIOV,IACpC,MAAMC,EAAU,MACV,UAAE+gB,EAAS,OAAEhR,GAAWhQ,EAC9B,OACE,gBAACG,EAAA,EAAM,CACLC,UAAWH,EAAQygB,KACnBrgB,QAAmB,MAAV2P,EAAiB,WAAa,YACvC1P,MAAO0gB,EAAuB,MAAVhR,EAAiB,UAAY,YAAe,UAChEiR,eAAa,GAEb,uBACEjc,MAAO,CACLJ,QAAS,OACTK,eAAgB,SAChBE,WAAY,WAGd,2BAAM6K,UAAU,QCvClB,GAAY,OAAA9Q,EAAA,GAAW,IACpB,OAAAE,EAAA,GAAa,CAClBshB,KAAM,CACJphB,OAAQ,kBACRqhB,cAAe,OACftc,OAAQ,WAWD6c,GACXlhB,IAEA,MAAMC,EAAU,MACV,YAAEkhB,EAAW,OAAEnR,EAAM,QAAE9P,GAAYF,EACzC,OACE,gBAACG,EAAA,EAAM,CACLC,UAAWH,EAAQygB,KACnBrgB,QAAQ,YACRC,MAAO6gB,EAAc,UAAY,YACjCjhB,QAAS,KACPA,MAGF,uBACE8E,MAAO,CACLJ,QAAS,OACTK,eAAgB,SAChBE,WAAY,WAGd,2BAAM6K,MC7BR,GAAY,OAAA9Q,EAAA,GAAYC,GACrB,OAAAC,EAAA,GAAa,CAClBgiB,iBAAkB,CAChBvc,SAAU,QAEZwc,OAAQ,CACN/gB,MAAOnB,EAAMO,QAAQ4hB,QAAQ1hB,KAC7B0R,SAAU,OACViQ,UAAW,iCAEb,qBAAsB,CACpB,MAAO,CACLC,QAAS,OAMXC,GAAUzhB,GAEZ,uBACEI,UAAW,KAAYihB,OACvBrc,MAAO,CAAEJ,QAAS5E,EAAM0hB,QAAU,QAAU,SAAQ,KAyB7C,GAAuB1hB,IAClC,MAAM,UAAEkd,GAAcld,EAEhB2hB,EAA2B,kBAAgB,GAC3CC,EAA0B,kBAAgB,GAC1CC,EAAmB,kBAAgB,GAEnCC,EAAW,iBAAe,MAC1BC,EAAY,iBAAgB,MAC5BC,EAAe,iBAAkB,MACnC9E,IAAc8E,EAAanV,UAE7BiV,EAASjV,QAAU,KACnBkV,EAAUlV,QAAU,KACpB8U,EAAyB9U,QAAU,IAAIqQ,EAAU+E,OAAO7Z,UACrD4H,GAAsB,MAAXA,GAEd4R,EAAwB/U,QACtBqQ,EAAUgF,SAASlc,OACnB,EACA,IAAIkX,EAAU+E,OAAO9Z,UAAUC,UAAW4H,GAAsB,MAAXA,GACvD6R,EAAiBhV,QAAU8U,EAAyB9U,QACpDmV,EAAanV,QAAUqQ,GAEzB,MAAMiF,EAAwBR,EAAyB9U,QACjDuV,EAAuBR,EAAwB/U,QAC/CwV,EAAgBR,EAAiBhV,QAcjCyV,GALqB,OAArBR,EAASjV,UACXiV,EAASjV,QAPX,IAAIqQ,EAAU+E,OAAOjb,IAAI,CAACgJ,EAAQyB,IACrB,MAAXzB,EACI,CAAEuS,iBAAa1gB,EAAW2gB,WAAO3gB,GACjC,CAAE0gB,YAAavS,EAAQwS,WAAO3gB,KAM7BigB,EAASjV,SAcZtE,GALsB,OAAtBwZ,EAAUlV,UACZkV,EAAUlV,QALZ,IAAIqQ,EAAUuF,QAAQzb,IAAI,CAACgJ,EAAQyB,KAC1B,CAAE0P,aAAa,EAAMnR,SAAQyB,YAM/BsQ,EAAUlV,SAKb6V,EAAe,IACnBJ,EACGtb,IAAK2b,IAAQ,QACZ,OAAAA,EAAKJ,YAAcI,EAAKJ,YAAgC,QAAnB,EAAW,QAAX,EAACI,EAAKH,aAAK,eAAExS,cAAM,QAAI,KAE7DlH,KAAK,KACH2Q,EAAcmJ,GAAmB,mBAAiBF,GAEzD,oBAAU,KACRE,EAAgBF,MACf,CAACxF,EAAUgF,WAGd,MAiBMW,EAAuBL,IAC3B,GAAIH,EAAgBD,EAAsB,OAC1C,IAAKI,EAAMrB,YAAa,MAAM,IAAIrW,MAAM,uBACxC,MAAM6X,EAAOL,EAAMD,GACnB,GAAkB,MAAdM,EAAKH,MAAe,MAAM,IAAI1X,MAAM,uBACxC0X,EAAMrB,aAAc,EACpBwB,EAAKH,MAAQA,EACb,MAAMM,EAxBsB,MAC5B,IAAIA,EAAqBR,EAAMla,UAC7B,CAACua,EAAMlR,IAA8B,MAApBkR,EAAKJ,aAAuB9Q,EAAQ4Q,GAEvD,OAAOS,GAAsB,EACzBA,EACAV,EAAuB,GAkBAW,GACvBD,IAAuBT,IACzBR,EAAiBhV,QAAUiW,GAE7BF,EAAgBF,MAGZM,EAA0B,KAC9B,GAAIX,IAAkBF,EAAuB,OAC7C,MAAMW,EAvBsB,MAC5B,IAAK,IAAIhN,EAAIuM,EAAgB,EAAGvM,GAAKqM,EAAuBrM,IAC1D,GAA4B,MAAxBwM,EAAMxM,GAAGyM,YAAqB,OAAOzM,EAE3C,OAAOuM,GAmBoBY,GACrBC,EAAaZ,EAAMQ,GACLI,EAAWV,MACnBrB,aAAc,EAC1B+B,EAAWV,WAAQ3gB,EACnBggB,EAAiBhV,QAAUiW,EAC3BF,EAAgBF,MAGZS,EAAkBjhB,IACtB,OAAQA,EAAMiF,KACZ,IAAK,YACL,IAAK,SACH6b,IACA,MACF,IAAK,QACHhjB,EAAMojB,SAASV,KACf,MACF,QACE,IAAIF,EAEFA,EADExiB,EAAMqjB,cACA9a,EAAOuI,KACZ0R,GAAUA,EAAMrB,aAAeqB,EAAMxS,SAAW9N,EAAMiF,KAGjDoB,EAAOuI,KACZ0R,GACCA,EAAMrB,aACNqB,EAAMxS,OAAOnK,gBAAkB3D,EAAMiF,IAAItB,eAG3C2c,GAAOK,EAAoBL,KAYrC,OAPA,oBAAU,KACRjhB,SAASmB,iBAAiB,UAAWygB,GAAgB,GAC9C,KACL5hB,SAASoB,oBAAoB,UAAWwgB,GAAgB,MAK1D,gBAACpe,EAAe,CAACG,QAAM,GACrB,gBAACI,EAAY,CAACJ,QAAM,GACjBod,EAAMtb,IAAI,CAAC2b,EAAM7M,K,MAChB,OACE,uBACE3O,IAAK2O,EACL9Q,MAAO,CACLJ,QAAS,OACT0e,aAAc,SACdne,WAAY,SACZF,eAAgB,WAGlB,gBAACwc,GAAM,CAACC,QAASW,IAAkBvM,IACnC,gBAACiL,GAAqB,CACpBC,UAA+B,MAApB2B,EAAKJ,YAChBvS,OAAQ2S,EAAKJ,cAAyB,QAAd,EAAII,EAAKH,aAAK,eAAExS,UAE1C,gBAACyR,GAAM,CACLC,QACEW,IAAkBC,EAAMtc,QAAU8P,IAAMuM,EAAgB,QAOpE,gBAAC/c,EAAY,CAACJ,QAAM,GAAEgY,EAAUqG,MAChC,gBAACC,GAAA,EAAO,CACNnjB,QAAQ,SACR2E,MAAO,CACL1F,OAAQ,oBACR+E,OAAQ,MACRwa,SAAU,WAGd,gBAACvZ,EAAY,CAACJ,QAAM,GACjBqD,EAAOvB,IAAI,CAACwb,EAAO1M,IAEhB,gBAACoL,GAAyB,CACxB/Z,IAAK2O,EACLqL,YAAaqB,EAAMrB,YACnBnR,OAAQwS,EAAMxS,OACd9P,QAAS,KACPsiB,EAAMrB,aAAe0B,EAAoBL,QAMnD,gBAACld,EAAY,CAACJ,QAAM,GAClB,gBAACvE,EAAe,CACdT,QAAS,KACP8iB,MACD,UAIH,gBAACriB,EAAe,CACdT,QAAS,KACPF,EAAMojB,SAASV,OAChB,aC9PEe,GAAuBzjB,I,QAClC,MAAM,SAAEsU,EAAQ,SAAEC,GAAavU,EACzBwU,EAAgBF,EAASE,cACzBC,EAA0BD,EAC9B,gBAACnH,GAAA,EAAS,KAAEmH,GADkC,KAG1C8J,EAA4C,QAA9B,EAAsB,QAAtB,EAAGhK,EAASsI,kBAAU,eAAE5W,cAAM,QAAI,EAChD0d,EAA4BpP,EAASsI,WAAWnW,OACnDyW,GACCA,EAAUuF,OAAOzc,OACjBkX,EAAU+E,MAAMxZ,MAAM,IAAIhC,OAAQuJ,GAAsB,MAAXA,GAAgBhK,QAC/DA,OACF,OACE,gBAACsH,EAAA,EAAG,KACDmH,EACD,gBAACnH,EAAA,EAAG,CAACE,EAAG,IACR,gBAACH,GAAA,EAAS,KACR,oEACA,sBAAIrI,MAAO,CAAE0P,UAAW,IACtB,8GAIA,0B,oBACoBJ,EAAS+O,cAAgB,IAAM,Q,mBAGnD,0BACG,gBAAgB5N,GACf6I,EACA,kCACqB7I,GAAU6I,EAAgB,YAChD/J,EAASS,aAAa9N,OAASqN,EAASQ,UACrC,GACA,4EAEN,8JAIC2O,IAA8BpF,GAC7B,mHAKDoF,EAA4B,GAC3BA,EAA4BpF,GAC1B,0BACG7I,GAAUiO,EAA2B,cACP,IAA9BA,EAAkC,MAAQ,O,sEAIjD,6FAGJ,gBAACpW,EAAA,EAAG,CAACE,EAAG,IACR,gBAACH,GAAA,EAAS,K,2EACiE,IACxErN,EAAMsU,SAASrM,OAAOjB,IAAI,CAACqB,EAAOoJ,IACjC,wBAAMtK,IAAKsK,GACRA,EAAQ,EAAI,KAAO,GACpB,yBAAIpJ,EAAM1G,M,IAAW0G,EAAMnB,Q,KAKjC,gBAACoG,EAAA,EAAG,CAACE,EAAG,MC/CR,GAAY,OAAAtO,EAAA,GAAW,IACpB,OAAAE,EAAA,GAAa,CAClBwf,WAAY,CACVnR,QAAS,MACTjO,gBAAiB,YACjBqf,SAAU,QACVvf,OAAQ,kBAOd,IAAY,IAAZ,SAAYsQ,GACV,iBACA,uBACA,qBACA,iBAJF,CAAY,QAAY,KAgBxB,MAAM,GAA4B,CAAEP,mBAAexN,GAEnD,SAAS,GAAQ4W,EAAkBC,GACjC,OAAQA,EAAOlY,MACb,KAAK,GAAauP,IAElB,KAAK,GAAaF,OAElB,KAAK,GAAaI,MAChB,MAAO,CAAEZ,cAAeqJ,GAC1B,KAAK,GAAaC,IAChB,OAAO,GACT,QACE,MAAM,IAAI7N,OAsBhB,MAYa6Y,GAAsB3jB,IACjC,MAAO4O,EAAU0K,GAAY,qBAAW,GAAS,KAC1CC,EAAWC,GAAgB2D,GAAc,IAdvB,CACzBnd,I,MAEA,MAAO,CACLgK,SAAwB,QAAhB,EAAEhK,EAAMgK,gBAAQ,QAAI,CAC1B4Z,MAAO,IAETpa,QAASxJ,EAAMwJ,QACfiQ,aAAc,KAOd,CAAmBzZ,KAEd2Z,EAAWC,GAAgB,oBAAS,IAEpCuF,EAAUC,GAAejC,GAAc,KAAM,IAE7C2C,EAAkBC,GAAuB,wBAC9Cle,GAEI5B,EAAU,KAEhBD,EAAM6Z,mBAAmB,IAAMN,IAAYvP,UAC3C,MAAOuK,GAAY,mBACjB,KACS,CACLQ,UAAW/U,EAAMsU,SAASsI,WAAW5W,OACrCgP,aAAchV,EAAMsU,SAASrM,OAAOjI,EAAMsU,SAASrM,OAAOjC,OAAS,MAKzE,oBAAU,KAER6d,KACC,IACH,MAAMA,EAAmB,K,MAGvB,MAAMC,EACgB,MAApBhE,GACK,EACD9f,EAAMsU,SAASsI,WAAWxU,UACvBmT,GAAMA,EAAE2G,WAAapC,EAAiBoC,UAE/C,IAAI6B,OAAoCliB,EACpCmiB,OAA2BniB,EAC/B,IAAK,IAAIiU,EAAI,EAAGA,EAAI9V,EAAMsU,SAASsI,WAAW5W,OAAQ8P,IAAK,CACzD,MAAMmO,EAAgBjkB,EAAMsU,SAASsI,WAAW9G,GAC1CoO,EACuD,QADjD,EACV3K,IAAYvP,SAAS4Z,MAAMxK,SAAS6K,EAAc/B,iBAAS,SAI7D,QAH+BrgB,IAA3BkiB,GAAyCG,IAC3CH,EAAyBE,IAEtBC,GAAUpO,EAAIgO,EAAuB,CACxCE,EAAgBC,EAChB,OAGJD,EAAgBA,UAAiBD,EACZ,MAAjBC,GACF5E,GAAY,GAEdW,EAAoBiE,IAQhBG,EACJnkB,EAAMsU,SAASsI,WAAW5W,OAASuT,IAAYvP,SAAS4Z,MAAM5d,OAE1D+T,EAAe,KACnB5W,EAAiB,CACfG,QACE,gBAACmgB,GAAmB,CAAClP,SAAUA,EAAUD,SAAUtU,EAAMsU,WAE3D9R,MAAO,WAIX,oBAAU,UACiBX,IAArBie,GAAmCX,KAAYpF,KAClD,IAEH,qBAAWnD,GAAX,CAAiC,IAC/B1I,GAAcqL,IAAY/P,QAAS+P,IAAYvP,WAGjD,qBAAW6M,GAAX,CAAyBkD,GAEzB,oBAAU,KAIJJ,EACFC,GAAa,GAGfnQ,GACE8P,IAAY/P,QACXgF,IACCA,EAAKxE,SAAWuP,IAAYvP,SAC5BwE,EAAKvE,YAAa,IAEpB,IAED,CAACsP,IAAYvP,WAEhB,MAAO9C,EAAO8S,GAAY,mBAAS,GACnC,oBAAU,KAER,MAAM9S,EAAQqS,IAAYvP,SAAS4Z,MAAM5d,OACzCgU,EAAS9S,IACR,CAACqS,IAAYvP,SAAS4Z,QAEzB,MAAOvb,EAAO8R,GAAY,mBAASna,EAAMsU,SAASrM,OAAO,IAsCzD,OACE,gBAAC3C,EAAY,CAACJ,QAAM,GAClB,gBAACH,EAAe,CAACG,QAAM,GACrB,gBAACiP,EAAA,EAAU,CAAC9T,QAAQ,aAAaL,EAAMsU,SAAS9R,OAChD,gBAAC2R,EAAA,EAAU,CAAC9T,QAAQ,aAAaL,EAAMsU,SAASsG,UAChD,gBAACtN,EAAA,EAAG,CAACE,EAAG,KACR,gBAAC,EAAK,CAACpI,QAAS+Z,KACd,gBAAChL,EAAA,EAAU,CAAC9T,QAAQ,KAAKC,MAAM,aAAW,UAK5C,gBAACgN,EAAA,EAAG,CAACE,EAAG,KACR,gBAAC,EAAK,CAACnI,SAAO,EAACD,OAAQ+Z,KAAkC,MAApBW,GACnC,gBAAC/a,EAAe,CAACG,QAAM,GACrB,gBAAC,GAAmB,CAClBgY,UAAW4C,EACXuD,cAAerjB,EAAMsU,SAAS+O,cAC9BD,SAAWtU,IAtDD,CAACA,IACrB,GAAc,KAAVA,EAAc,OAClB,GAAIqQ,IAEF,YADA3X,GAAuB,yBAMzB,KAHkBxH,EAAMsU,SAAS+O,cAC7BvD,EAAiBoC,WAAapT,EAC9BgR,EAAiBoC,SAASrc,gBAAkBiJ,EAAMjJ,eAKpD,YADA0B,GAAwBuH,EAAH,mBAFrBtH,GAAuB,eAKzB,MAAM+S,EAAe,OAAH,wBACbhB,KAAW,CACdE,aAAc,GACdzP,SAAU,CACR4Z,MAAO,IAAIrK,IAAYvP,SAAS4Z,MAAO9D,EAAiBoC,aAG5D1I,EAAae,GACbjB,EAAS,CAAE9Y,KAAM,GAAayP,QAE9B,MAAMuK,EAAYxS,GAAkBhI,EAAMsU,SAASrM,OAAQf,EAAQ,GAChDsT,EAAUtT,MAAUmB,EAAMnB,MAM7CiT,EAASK,GACTqJ,KAsBYzJ,CAActL,MAGlB,gBAACxB,EAAA,EAAG,CAACE,EAAG,IACR,gBAAC7M,EAAe,CACdJ,SAAU4jB,GAA2B,EACrCjkB,QAAS,IAAM2jB,KAAkB,UAOvC,gBAAC9e,EAAe,CAAC3E,UAAWH,EAAQ2e,WAAY1Z,QAAM,GACpD,2BAAMif,GACN,oDAGF,gBAAC,GAAiB,CAAClc,OAAQjI,EAAMsU,SAASrM,OAAQf,MAAOA,IACzD,2B,YACYuO,GAAUvO,EAAO,kB,OAAuB,IACjDuO,GAAUvO,EAAO,UAEpB,gBAAC5B,EAAY,CAACJ,QAAM,GACjBqU,IAAYvP,SAAS4Z,MAAM5c,IAAI,CAACJ,EAAMkP,IAEnC,uBAAK9Q,MAAO,CAAE1F,OAAQ,cAAgB6H,IAAK2O,GACxClP,QCxRjB,IAAI,GAEG,MAOMwd,GAAkC,IACtC3iB,EAAqC,CAC1CG,kBAAoB6D,I,MAClB,MAAOC,EAAWC,GAAgB,mBAAS,IACrC3F,EAAQyF,EAAkBzF,MAC1B4F,EAAgC,QAAlB,EAAG5F,EAAM0F,iBAAS,eAAEG,cAClCC,EAAW9F,EAAMqkB,UAAUre,SAAWhG,EAAM+F,QAAQ6d,MAAM5d,OAChE,OACE,gBAAC5D,EAAY,CACXC,QAAS,KACPoD,EAAkBpC,OAAM,IAE1Bf,MAAM,EACNE,MAAO,WAEP,gBAACuC,EAAe,CAACG,QAAM,GACrB,gBAAC,EAAK,CAACE,QAASU,GAAQ,sDAGxB,gBAAC,EAAK,CAACV,OAAQU,GACb,gBAACf,EAAe,CAACG,QAAM,G,kDAErB,gBAACgB,EAAA,EAAS,CACR7F,QAAQ,WACR8F,MAAOT,EACPU,MAAO,aACP9G,OAAO,SACP+G,gBAAiB,CACfC,QAAQ,GAEV9F,KAAK,OACL+F,SAAWrE,IACTyD,EAAazD,EAAMsE,cAAcL,YAKzC,gBAAC,EAAK,CACJf,OACEU,GACAJ,EAAUG,gBAAkBD,GACV,MAAlBA,GAGF,gBAACb,EAAe,CAACG,QAAM,GACrB,gBAAC,EAAK,CAACE,OAAuC,IAA/BpF,EAAM+F,QAAQ6d,MAAM5d,QACjC,gBAACjB,EAAe,CAACG,QAAM,GACrB,0CACA,gBAACI,EAAY,KACVtF,EAAMqkB,UACJ5d,OACEC,GACC1G,EAAM+F,QAAQ6d,MAAMjd,QAAQD,EAAOwb,WAAa,GAEnDlb,IAAKN,GAAW,GAAWA,EAAOwb,cAI3C,0CACA,gBAAC5c,EAAY,KACVtF,EAAMqkB,UACJ5d,OACEC,GACC1G,EAAM+F,QAAQ6d,MAAMjd,QAAQD,EAAOwb,UAAY,GAElDlb,IAAKN,GAAW,GAAWA,EAAOwb,mBAWjD,GAActb,GAEhB,uBAAKO,IAAKP,EAAM5B,MAAO,CAAEJ,QAAS,OAAQC,SAAU,SAClD,wBAAMG,MAAO,CAAEoC,YAAa,WAC1B,yBAAIR,K,2SClEZ,MAAM0d,GAAsB,IAAsC,qCAChE,MAAM9a,EAAUlB,KAChB,IAAI0B,EACAua,GAAc,EAClB,GAAIrb,KACF,IACE,MAAMsb,EAAkB/Z,GAAmCjB,GACnC,OAApBgb,GAA4BA,EAAgBhb,UAAYA,IAC1DQ,EAAWwa,EAAgBxa,SAC3Bua,GAAc,GAEhB,MAAOjb,IAEX,IAEE,IAAImb,QCxCD,SACLjb,EACAkb,EACAH,G,0CAEA,MAAM/Y,EAA0B,CAAEhC,UAASkb,cAAaH,eAClD9Y,QAAiBS,GACrBV,EACA,iBAUF,OALAC,EAAS6I,SAASrM,OAASwD,EAAS6I,SAASrM,OAC1CjB,IAAKqB,I,MACJ,MAAO,CAAE1G,KAAM0G,EAAM1G,KAAMuF,MAAkB,QAAb,EAAEmB,EAAMnB,aAAK,QAAI,KAElDL,KAAK,CAACC,EAAGC,IAAOD,EAAEI,MAAQH,EAAEG,OAAS,EAAIJ,EAAEI,MAAQH,EAAEG,MAAQ,EAAI,GAC7DuE,KDsBkCkZ,CACrCnb,EACY3H,MAAZmI,EACAua,GAiBF,OAdIva,IACFya,EAA6B,OAAH,wBACrBA,GAA0B,CAC7Bza,cAGJP,GACED,EACCgF,IACMxE,IAAUwE,EAAKxE,SAAWya,EAA2Bza,UAC1DwE,EAAKvE,YAAa,IAEpB,GAEKwa,EACP,MAAOG,GACP,MAAM,IAAI9Z,MAAM8Z,OAId,GAAY,OAAA1lB,EAAA,GAAY2lB,GAC5B,OAAAzlB,EAAA,GAAa,CACX0lB,aAAc,CACZC,IAAK,OACLC,OAAQ,ME3ER,GAAQ,OAAAC,EAAA,GAAe,CAC3BvlB,QAAS,CACP4hB,QAAS,CAEP1hB,KAAM,WAGRD,UAAW,CACTC,KAAM,clClBV,GkCsBU,IACZ,SACE,uBAAKoF,MAAO,CAAEX,OAAQ,UACpB,gBAAC6gB,EAAA,EAAW,MACZ,gBrCNFllB,IAEA,MAAO2H,EAAMwd,GAAW,oBAAS,IAC1BvhB,EAASwhB,GAAc,mBAAS,KAChCnhB,EAAUohB,GAAe,wBAAmBxjB,IAC5CyjB,EAAUC,GAAe,wBAAqB1jB,IAC9CgG,EAAkB2d,GAAuB,mBAAS,GACnDC,EAAS,CACb7hB,EACAK,EACAqhB,EACAzd,K,MAEuB,iBAAZjE,IAEgC,iBAAd,QAAvB,EAAQA,SAAe,eAAEA,WAC3B8hB,QAAQC,MAAM,sCAAwC/hB,EAASA,GAC/DwhB,EAAW,mBAEbxhB,EAAWA,EAAgBA,SAE7BwhB,EAAWxhB,GACX2hB,EAAYD,UAAY7d,IACxB4d,EAAYphB,GACZuhB,EAAoB3d,GACpBsd,GAAQ,IAYV,OATA9d,EAAc,CAACzD,EAAiB0hB,IAC9BG,EAAO7hB,EAAS,QAAS0hB,EAAU,GACrChe,GAAgB,CAAC1D,EAAiB0hB,IAChCG,EAAO7hB,EAAS,UAAW0hB,EAAU,GACvC/d,GAAuB,CAAC3D,EAAiB0hB,IACvCG,EAAO7hB,EAAS,QAAS0hB,EAAU,KACrC9d,GAAyB,CAAC5D,EAAiB0hB,IACzCG,EAAO7hB,EAAS,UAAW0hB,EAAU,KAGrC,gBAAC5d,GAAuB,CACtBzD,SAAUA,EACVL,QAASA,EACT+D,KAAMA,EACNC,OAAQ,IAAMud,GAAQ,GACtB9iB,QAASijB,EACTzd,iBAAkBA,KqCtCA,MACpB,gBAAC,IAAgB,CAAC1I,MAAO,IACvB,gB7C+BJa,IAEA,MAAO4lB,EAAYC,GAAiB,mBAAS,GAEvCC,EAAa,CACjB/jB,EACA/B,KAEA+B,EAAOC,QAAS,EAChBlB,EAAYiB,EAAOJ,MAAM3B,MAAQA,EACjC6lB,EAAcD,EAAa,GACpB,IAAIG,QAAiC,CAACC,EAASC,KACpDlkB,EAAOikB,QAAUA,KAGfE,EAA+B,CACnC5jB,KAAMwjB,EACNK,WAAY,CAAUxkB,EAAc3B,IAC3B8lB,EAAWhlB,EAAYa,GAAMI,OAAQ/B,IAIhD,OADAkB,EAAqBglB,EAEnB,gBAAC9kB,EAAqBiX,SAAQ,CAAClS,MAAO+f,GACnCnlB,OAAOyS,OAAO1S,GAAakG,IAAI,CAACof,EAAiB3U,KAChD,GAAI2U,EAAgBrkB,OAAOC,OAAQ,CACjC,MAAMqB,EAAQ,CAAWsT,EAAiBxB,KACxCiR,EAAgBrkB,OAAOC,QAAS,EAChCokB,EAAgBrkB,OAAOikB,QAAQ,CAAErP,SAAQxB,WACzC0Q,EAAcD,EAAa,IAE7B,OACE,gBAAC,WAAc,CAACze,IAAKsK,GACnB,gBAACpQ,EAAK,CACJC,SAAU,IACR8kB,EAAgBrkB,OAAOH,kBAAkB,CACvCyB,QACArD,MAAOomB,EAAgBpmB,WAOnC,OAAO,OAET,gCAAGA,EAAMU,Y6C7EK,KACZ,gBF8D0BV,IAChC,MAAOuZ,EAAWC,GAAgB,sBAI3BhQ,EAAS6c,GAAc,sBACvBja,EAAcka,GAAmB,wBAASzkB,GAEjD,oBAAU,KACRwkB,EAAW/d,MACmB,qCAC5B,IACE,MAAMie,QAA0BjC,KAChC9K,EAAa,CACXlF,SAAUiS,EAAkBjS,SAC5BtK,SAAUuc,EAAkBvc,WAE9B,MAAO4a,GACP0B,EAAgB1B,EAAEhhB,cAIrB,CAAC5D,IAEJ,MAAMC,EAAU,KAEVumB,EACY,MAAhBpa,EAAuB,KACrB,gBAAC5I,EAAc,CACbS,SAAS,QACTL,QAASwI,EACTzI,UAAW,IAAM2iB,OAAgBzkB,KAGjC4kB,OAA4B5kB,IAAd0X,EAEdmN,EAAiB,mBAEvB,IAAIC,EAA6B,KAEjC,GAAIF,EACF,OAAQxd,MACN,IAAK,IACH0d,EACE,gBAACtN,GAAkB,CACjB7P,QAASA,EACT8K,SAAUiF,EAAUjF,SACpBtK,SAAUuP,EAAUvP,SACpB6P,mBAAqB6K,IACnBgC,EAAe7Z,QAAU6X,KAI/B,MACF,IAAK,IACHiC,EACE,gBAAC3H,GAAoB,CACnBxV,QAASA,EACT8K,SAAUiF,EAAUjF,SACpBtK,SAAUuP,EAAUvP,SACpB6P,mBAAqB6K,IACnBgC,EAAe7Z,QAAU6X,KAI/B,MACF,IAAK,IACHiC,EACE,gBAAChD,GAAkB,CACjBna,QAASA,EACT8K,SAAUiF,EAAUjF,SACpBtK,SAAUuP,EAAUvP,SACpB6P,mBAAqB6K,IACnBgC,EAAe7Z,QAAU6X,KAOrC,MAAOvgB,EAAMwJ,GAAOzJ,IACpB,OACE,gCACE,gBAACmT,GAAkB,CACjBtR,QAAS,KACP,OAAQkD,MACN,IAAK,IpC/JqB,CAACjJ,IAChCuF,IACHA,EAAwBC,KAEnBrE,IAAmBmB,KAAKiD,EAAuBvF,IoC4J1C4mB,CAAuB,CACrBlhB,UAAW6T,EAAUjF,SAAS5O,UAC9BO,WAAYygB,EAAe7Z,UAC3B9G,QAAUwT,EAAUjF,SAA2BvO,UAEjD,MACF,IAAK,IDrKqB,CAAC/F,IAChC,KACH,GAAwBokB,MAEnBjjB,IAAmBmB,KAAK,GAAuBtC,ICkK1C6mB,CAAuB,CACrBnhB,UAAW6T,EAAUjF,SAAS5O,UAC9BK,QAAS2gB,EAAe7Z,UACxBwX,UAAY9K,EAAUjF,SACnBsI,gBAMV+J,EACAH,GAGH,gBAAC9O,EAAA,EAAM,CAACtX,UAAWH,EAAQ6kB,aAAcnX,IAAKA,GAC5C,gBAACgK,EAAA,EAAO,KACN,gBAACjE,EAAA,EAAI,CAAC/O,WAAS,EAACQ,WAAW,UACzB,gBAAC2hB,EAAA,EAAS,CAACxV,SAAS,Y,oBAGtB,gBAACnR,EAAA,EAAM,CACLG,MAAM,UACNJ,QAAS,IACPiD,EAAiB,CACfG,QAAS,gBAACuX,GAAW,MACrBrY,MAAO,aACP,WAKN,gBAACrC,EAAA,EAAM,CACLG,MAAM,UACNJ,QAAS,IACPiD,EAAiB,CACfG,QAAS,gBAACyX,GAAS,MACnBvY,MAAO,sBACP,aEjMU,SAIxBjB,SAASC,eAAe,W","file":"main.726a0b660c22da7fa0ec.js","sourcesContent":["import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport Button from \"@material-ui/core/Button\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n primaryButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n },\n secondaryButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n backgroundColor: \"lightgray\",\n },\n strongGuidingButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n backgroundColor: theme.palette.secondary.main,\n },\n mildGuidingButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n },\n subtleButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n },\n });\n});\ninterface ButtonProps {\n onClick?: () => void;\n disabled?: boolean;\n \"aria-label\"?: string;\n type?: \"submit\" | \"button\";\n autoFocus?: boolean;\n color?: \"inherit\" | \"primary\" | \"secondary\" | \"default\";\n}\n\nexport const PrimaryButton: React.FunctionComponent = (props) => {\n const classes = useStyles();\n const onClick = props.onClick ? props.onClick : () => {};\n return (\n // wrap in div to prevent button from expanding to full width in wide components\n
\n \n {props.children}\n \n
\n );\n};\n\nexport const SecondaryButton: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n props.onClick && props.onClick()}\n type={props.type ?? \"button\"}\n autoFocus={props.autoFocus}\n >\n {props.children}\n \n );\n};\n\nexport const StrongGuidingButton: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n props.onClick && props.onClick()}\n type={props.type ?? \"button\"}\n autoFocus={props.autoFocus}\n >\n {props.children}\n \n );\n};\n\nexport const MildGuidingButton: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n props.onClick && props.onClick()}\n type={props.type ?? \"button\"}\n autoFocus={props.autoFocus}\n >\n {props.children}\n \n );\n};\n\nexport const SubtleButton: React.FunctionComponent = (props) => {\n const classes = useStyles();\n return (\n props.onClick && props.onClick()}\n type={props.type ?? \"button\"}\n autoFocus={props.autoFocus}\n >\n {props.children}\n \n );\n};\n","import * as React from \"react\";\nimport { createContext, useState } from \"react\";\nimport * as ReactDOM from \"react-dom\";\n\nexport interface DialogResponse {\n isOkay: boolean;\n result: TResult;\n}\n\ninterface DialogComponentRenderer {\n (renderProps: {\n close: (isOkay: boolean, result: TResult) => void;\n props: TProps;\n }): JSX.Element;\n}\nexport interface Dialog {\n name: string;\n componentRenderer: DialogComponentRenderer;\n isOpen: boolean;\n result?: TResult;\n resolve?: (result: DialogResponse) => void;\n}\n\ninterface DialogManagerProps {}\ninterface DialogMethods {\n open: (\n dialog: Dialog,\n props?: TProps\n ) => Promise>;\n openByName: (\n dialogName: string,\n props?: TProps\n ) => Promise>;\n}\n\nconst dialogTable: Record<\n string,\n { dialog: Dialog; props?: unknown }\n> = Object.create(null);\nlet dialogIndex = 0;\n\nconst register = (args: {\n name: string;\n componentRenderer: DialogComponentRenderer;\n}) => {\n const { componentRenderer } = args;\n let name = args.name;\n if (name === undefined) {\n // auto-assign name\n dialogIndex++;\n name = \"__autonamed__\" + dialogIndex.toString();\n }\n const dialog = { name, componentRenderer, isOpen: false };\n dialogTable[name] = { dialog };\n return dialog;\n};\n\nlet dialogMethodsLocal: DialogMethods;\nexport const getDialogMethods = () => dialogMethodsLocal;\n\nexport const DialogManagerContext = createContext(null);\n\nexport const DialogManager: React.FunctionComponent = (\n props\n) => {\n const [stateIndex, setStateIndex] = useState(0);\n\n const dialogOpen = (\n dialog: Dialog,\n props: TProps\n ) => {\n dialog.isOpen = true;\n dialogTable[dialog.name].props = props;\n setStateIndex(stateIndex + 1);\n return new Promise>((resolve, reject) => {\n dialog.resolve = resolve;\n });\n };\n const dialogMethods: DialogMethods = {\n open: dialogOpen,\n openByName: (name: string, props: TProps) => {\n return dialogOpen(dialogTable[name].dialog, props);\n },\n };\n dialogMethodsLocal = dialogMethods;\n return (\n \n {Object.values(dialogTable).map((dialogTableItem, index) => {\n if (dialogTableItem.dialog.isOpen) {\n const close = (isOkay: boolean, result: TResult) => {\n dialogTableItem.dialog.isOpen = false;\n dialogTableItem.dialog.resolve({ isOkay, result });\n setStateIndex(stateIndex + 1);\n };\n return (\n \n \n dialogTableItem.dialog.componentRenderer({\n close,\n props: dialogTableItem.props,\n })\n }\n />\n \n );\n }\n return null;\n })}\n <>{props.children}\n \n );\n};\n\n// Defer so that hooks are called when dialog is rendered as a child,\n// not as part of parent render.\n// Otherwise the parent calls different hooks at different times.\nconst Defer = (props: { renderer: () => JSX.Element }) => {\n return ReactDOM.createPortal(\n props.renderer(),\n document.getElementById(\"dialog\")\n );\n};\n\nexport const makeDialog = (args: {\n name?: string;\n componentRenderer: DialogComponentRenderer;\n}) => {\n const { name, componentRenderer } = args;\n return register({\n name,\n componentRenderer,\n });\n};\n","import MuiDialog from \"@material-ui/core/Dialog\";\nimport DialogActions from \"@material-ui/core/DialogActions\";\nimport DialogContent from \"@material-ui/core/DialogContent\";\nimport DialogTitle from \"@material-ui/core/DialogTitle\";\nimport * as React from \"react\";\nimport { SubtleButton } from \"./buttons\";\nimport {\n getDialogMethods,\n makeDialog,\n Dialog,\n} from \"./dialogTools/DialogManager\";\nimport { useEffect } from \"react\";\n\nexport interface JustOkDialogProps {\n open: boolean;\n onClose: () => void;\n title: string;\n okayText?: string;\n}\nconst keyDownHandler = (event: KeyboardEvent) => {\n // Prevent keys from being handled in the underlying page.\n event.stopPropagation();\n};\n\nexport const JustOkDialog: React.FunctionComponent = (\n props\n) => {\n const { onClose, open, okayText, title } = props;\n const handleClose = () => {\n onClose();\n };\n\n useEffect(() => {\n document.addEventListener(\"keydown\", keyDownHandler, true);\n return () => {\n document.removeEventListener(\"keydown\", keyDownHandler, true);\n };\n });\n\n return (\n \n {title}\n {props.children}\n \n {okayText ?? \"Ok\"}\n \n \n );\n};\n\ninterface InlineJustOkDialogProps {\n title: string;\n okayText?: string;\n content: string | JSX.Element;\n}\n\nlet inlineJustOkDialogInternal: Dialog;\n\nexport const openJustOkDialog = (props: InlineJustOkDialogProps) => {\n if (!inlineJustOkDialogInternal) {\n inlineJustOkDialogInternal = makeJustOkDialog();\n }\n return getDialogMethods().open(inlineJustOkDialogInternal, props);\n};\n\nconst makeJustOkDialog = () => {\n const dialog = makeDialog({\n name: \"JustOkConfirmationDialog\",\n componentRenderer: (props) => {\n return (\n {\n props.close(true, true);\n }}\n open={true}\n title={props.props.title}\n okayText={props.props.okayText}\n >\n {props.props.content}\n \n );\n },\n });\n return dialog;\n};\n","import Snackbar from \"@material-ui/core/Snackbar\";\nimport MuiAlert, { AlertProps } from \"@material-ui/lab/Alert\";\nimport * as React from \"react\";\nfunction Alert(props: AlertProps) {\n return ;\n}\n\nexport type SnackbarSeverity = \"error\" | \"success\" | \"warning\" | \"info\";\nexport function CommonSnackbar(props: {\n message: JSX.Element | string;\n closeFunc: () => void;\n severity: SnackbarSeverity;\n}) {\n const [open, setOpen] = React.useState(false);\n const handleClose = (event?: React.SyntheticEvent, reason?: string) => {\n if (reason === \"clickaway\") {\n return;\n }\n props.closeFunc();\n setOpen(false);\n };\n\n React.useEffect(() => {\n if (props.message) setOpen(true);\n });\n\n return (\n \n \n {props.message === undefined ? null : props.message}\n \n \n );\n}\n\nexport function QuickSnackbar(props: {\n message: JSX.Element | string;\n closeFunc: () => void;\n severity: SnackbarSeverity;\n autoClose?: boolean;\n}) {\n const [open, setOpen] = React.useState(false);\n const handleClose = (event?: React.SyntheticEvent, reason?: string) => {\n props.closeFunc();\n setOpen(false);\n };\n\n React.useEffect(() => {\n if (props.message) setOpen(true);\n });\n\n if (props.message === undefined) return null;\n return (\n \n {props.message}\n \n );\n}\n\nexport function ErrorSnackbar(props: {\n message: JSX.Element | string;\n show: boolean;\n onShow: () => void;\n}) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = (event?: React.SyntheticEvent, reason?: string) => {\n setOpen(false);\n };\n\n React.useEffect(() => {\n if (props.show) {\n setOpen(true);\n props.onShow();\n }\n });\n\n return (\n \n {props.message}\n \n );\n}\n","import { useState, useCallback } from \"react\";\nexport function useClientRect() {\n const [rect, setRect] = useState(null);\n const ref = useCallback((node) => {\n if (node !== null) {\n setRect(node.getBoundingClientRect());\n }\n }, []);\n return [rect ?? { height: 0, width: 0, x: 0, y: 0 }, ref];\n}\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport clsx from \"clsx\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n container: {\n display: \"flex\",\n flexWrap: \"wrap\",\n flexDirection: \"column\",\n },\n });\n});\ninterface ColumnContainerProps {\n center?: boolean;\n className?: string;\n}\n\nexport const ColumnContainer: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n","import * as React from \"react\";\n\ninterface HiderProps {\n hidden: boolean;\n // unomunt = true means unmount when hidden\n unmount?: boolean;\n}\n\nconst Hider: React.FunctionComponent = (props) => {\n if (props.hidden && props.unmount) return null;\n return (\n
\n {!props.hidden && props.children}\n
\n );\n};\nexport default Hider;\n","import * as React from \"react\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport clsx from \"clsx\";\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n container: {\n display: \"flex\",\n flexWrap: \"wrap\",\n flexDirection: \"row\",\n alignItems: \"center\",\n },\n });\n});\ninterface RowContainerProps {\n center?: boolean;\n width?: string;\n className?: string;\n}\n\nexport const RowContainer: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n","import { TextField } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../components/dialogTools/DialogManager\";\nimport Hider from \"../../../components/Hider\";\nimport { JustOkDialog } from \"../../../components/JustOkDialog\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport { Answer } from \"../spell_types\";\n\nexport interface AnswersDialogProps {\n answerKey: string;\n foundWords: string[];\n answers: Answer[];\n}\n\nlet answersDialogInternal: Dialog;\n\nexport const openSpellAnswersDialog = (props: AnswersDialogProps) => {\n if (!answersDialogInternal) {\n answersDialogInternal = makeSpellAnswersDialogComponent();\n }\n return getDialogMethods().open(answersDialogInternal, props);\n};\n\nexport const makeSpellAnswersDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const [answerKey, setAnswerKey] = useState(\"\");\n const props = dialogRenderProps.props;\n const propsAnswerKey = props.answerKey?.toLowerCase();\n const foundAll = props.answers.length === props.foundWords.length;\n return (\n {\n dialogRenderProps.close(true);\n }}\n open={true}\n title={\"Answers\"}\n >\n \n \n \n \n \n );\n },\n });\n};\n\nconst AnswerItem = (word: string, score: number) => {\n return (\n
\n \n {word}\n \n {score}\n
\n );\n};\n","import Snackbar from \"@material-ui/core/Snackbar\";\nimport Alert from \"@material-ui/lab/Alert\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\ntype Severity = \"error\" | \"info\" | \"success\" | \"warning\";\n\nexport let notifyError: (message: string, callback?: () => void) => void;\n\nexport let notifySuccess: (message: string, callback?: () => void) => void;\n\nexport let notifyErrorTransient: (\n message: string,\n callback?: () => void\n) => void;\n\nexport let notifySuccessTransient: (\n message: string,\n callback?: () => void\n) => void;\n\nconst nullCallback = () => {};\n\ninterface NotificationManagerProps {}\nexport const NotificationManager: React.FunctionComponent = (\n props\n) => {\n const [show, setShow] = useState(false);\n const [message, setMessage] = useState(\"\");\n const [severity, setSeverity] = useState(undefined);\n const [callback, setCallback] = useState<() => void>(undefined);\n const [autoHideDuration, setAutoHideDuration] = useState(0);\n const notify = (\n message: string,\n severity: Severity,\n callback: () => void,\n autoHideDuration: number\n ) => {\n if (typeof message !== \"string\") {\n // try message.message\n if (typeof (message as any)?.message !== \"string\") {\n console.error(\"notify expected string, got \" + typeof message, message);\n setMessage(\"Error detected\");\n }\n message = (message as any).message;\n }\n setMessage(message);\n setCallback(callback ?? nullCallback);\n setSeverity(severity);\n setAutoHideDuration(autoHideDuration);\n setShow(true);\n };\n\n notifyError = (message: string, callback?: () => void) =>\n notify(message, \"error\", callback, 0);\n notifySuccess = (message: string, callback?: () => void) =>\n notify(message, \"success\", callback, 0);\n notifyErrorTransient = (message: string, callback?: () => void) =>\n notify(message, \"error\", callback, 2000);\n notifySuccessTransient = (message: string, callback?: () => void) =>\n notify(message, \"success\", callback, 2000);\n\n return (\n setShow(false)}\n onClose={callback}\n autoHideDuration={autoHideDuration}\n />\n );\n};\n\nfunction NotifySnackbarComponent(props: {\n message: JSX.Element | string;\n show: boolean;\n onShow: () => void;\n severity: Severity;\n onClose: () => void;\n autoHideDuration: number;\n}) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = (event?: React.SyntheticEvent, reason?: string) => {\n setOpen(false);\n props.onClose && props.onClose();\n };\n\n React.useEffect(() => {\n if (props.show) {\n setOpen(true);\n props.onShow();\n }\n });\n return (\n \n {props.message}\n \n );\n}\n","import { SpellIcon } from \"../components/icons/SpellIcon\";\nimport * as React from \"react\";\nimport { ComputeIcon } from \"../components/icons/ComputeIcon\";\nimport { TwistIcon } from \"../components/icons/TwistIcon\";\n\nexport interface UserGameSettings {\n modifiedtime: Date;\n templategameid: string;\n hiddenwords: string[];\n extrawords: string[];\n}\n\nexport interface UserProfile {\n modifiedtime?: Date; // Optional so it doesn't need to be sent in server requests\n initials: string;\n displayName: string;\n isSuperAdmin?: boolean;\n}\n\nexport type GameType = \"s\" | \"c\" | \"t\";\nexport const getGameTypeLabel = (gameType: GameType) => {\n switch (gameType) {\n case \"s\":\n return \"Spell\";\n case \"c\":\n return \"Compute\";\n case \"t\":\n return \"Twist\";\n }\n throw new Error(\"Invalid gametype:\" + gameType);\n};\n\nexport const getGameTypeIcon = (gameType: GameType) => {\n switch (gameType) {\n case \"s\":\n return React.createElement(SpellIcon, null);\n case \"c\":\n return React.createElement(ComputeIcon, null);\n case \"t\":\n return React.createElement(TwistIcon, null);\n }\n throw new Error(\"Invalid gametype:\" + gameType);\n};\n\nexport const gameTypeHasAnswers = (gameType: GameType) => {\n switch (gameType) {\n case \"s\":\n return true;\n case \"c\":\n return false;\n case \"t\":\n return true;\n }\n throw new Error(\"Invalid gametype:\" + gameType);\n};\n\nexport const gameTypeUsesMenuRestart = (gameType: GameType) => {\n switch (gameType) {\n case \"s\":\n return true;\n case \"c\":\n return false;\n case \"t\":\n return true;\n }\n throw new Error(\"Invalid gametype:\" + gameType);\n};\n\nexport interface GameSpec {\n playSpec: PlaySpec;\n authorSpec: AuthorSpec;\n}\n\nexport enum AutoScoringMethod {\n Slow = \"s\",\n Medium = \"m\",\n Fast = \"f\",\n}\nexport interface AuthorSpec {\n autoScoring: boolean;\n autoScoringMethod: AutoScoringMethod;\n description: string;\n}\n// GameRecord is the layout in the database.\n// Edited games are saved in Draft.\n// Publishing copies Draft to Prod.\n// We keep name unique in the database.\nexport interface GameRecord {\n gameType: GameType;\n draft: GameSpec;\n prod: GameSpec;\n}\n\nexport interface PlaySpec {\n title: string;\n subtitle: string;\n levels: Array;\n rulesPrologue: string;\n answerKey: string;\n}\n\nexport interface Level {\n name: string;\n score: number; // min score for this level\n}\n\nexport const getLevelFromScore = (levels: Array, score: number) => {\n const reverseIndex = [...levels]\n .reverse()\n .findIndex((level) => (level.score ?? 0) <= score);\n return levels[levels.length - 1 - reverseIndex];\n};\n\n// g = game, p=progress\nexport type GameRefType = \"g\" | \"p\";\n\nexport interface GameRef {\n id: string; // key into either game collection or progess collection\n refType: GameRefType;\n}\n","// URL structure\n// gameUrl: URL for game itself:\n// /run/\n// progress URL: URL for game + progress:\n// Same as above, except the gameRef starts with \"p-\"\n// baseUrl refers to the string /rull\n\n// gamePath is /\nexport const getGameRefFromLocation = (): string => {\n const gamePath = getGamePathFromLocation();\n const tokens = gamePath.split(\"/\");\n const count = tokens.length;\n return count > 0 ? tokens[0] : undefined;\n};\n\nconst getGamePathFromLocation = () => {\n const path = window.location.pathname;\n let tokens = path.split(\"/\");\n // Get rid of /run/\n // token[0] is length 0, since first char is /\n tokens.shift();\n tokens.shift();\n return tokens.join(\"/\");\n};\n\nexport const getBaseUrl = () => {\n const path = window.location.pathname;\n let tokens = path.split(\"/\");\n // token[0] is length 0, since first char is /\n return [\n window.location.origin,\n tokens[1], // run\n ].join(\"/\");\n};\n","import { GameType } from \"../../domain/types\";\n\nlet gameType: GameType;\nexport function setGameType(gt: GameType) {\n gameType = gt;\n}\nexport function getGameType() {\n return gameType;\n}\n","import { getGameRefFromLocation } from \"./url\";\nimport { getGameType } from \"./globalPlayData\";\n\ninterface LocalStorageData {\n progress: TProgress;\n gameRef: string;\n sharedGameRef?: string;\n unmodified: boolean; // true if a copy from server, false if locally modified\n lastShareTime: Date;\n}\n\ninterface LocalStorageDataInternal\n extends LocalStorageData {\n lastModifiedTime: Date;\n}\n\nexport function localStorageAvailable() {\n try {\n var t = \"t\";\n localStorage.setItem(t, t);\n localStorage.removeItem(t);\n return true;\n } catch (_e) {\n return false;\n }\n}\n\nexport function clearLocalStorage() {\n if (localStorageAvailable()) {\n localStorage.clear();\n }\n}\n\nexport function clearLocalStorageForGame() {\n const gameRef = getGameRefFromLocation();\n if (localStorageAvailable()) {\n localStorage.removeItem(getGameType() + \"/\" + gameRef);\n }\n}\n\nexport function storeProgressLocally(\n gameRef: string,\n mutator: (localStorageData: LocalStorageData) => void,\n isSharingProgress: boolean\n) {\n if (!localStorageAvailable) return;\n let ls = readStateFromLocalStorageInternal(gameRef);\n if (!ls) {\n // Nothing stored yet\n ls = {\n gameRef,\n lastModifiedTime: undefined,\n lastShareTime: undefined,\n progress: undefined,\n unmodified: true,\n };\n }\n mutator(ls);\n writeStateToLocalStorage(ls, isSharingProgress);\n}\n\nfunction writeStateToLocalStorage(\n localStorageData: LocalStorageData,\n isSharingProgress: boolean\n) {\n if (localStorageAvailable()) {\n // If no sharedGameRef is supplied, then we keep it as it was.\n const ls = readStateFromLocalStorageInternal(localStorageData.gameRef);\n const newData: LocalStorageDataInternal = {\n sharedGameRef: ls?.sharedGameRef,\n ...localStorageData,\n lastModifiedTime: new Date(),\n lastShareTime: isSharingProgress ? new Date() : ls?.lastShareTime,\n };\n localStorage.setItem(\n getGameType() + \"/\" + newData.gameRef,\n JSON.stringify(newData)\n );\n }\n}\n\nexport function readStateFromLocalStorage(gameRef: string) {\n const internal = readStateFromLocalStorageInternal(gameRef);\n return internal as LocalStorageData;\n}\n\nfunction readStateFromLocalStorageInternal(gameRef: string) {\n if (localStorageAvailable()) {\n const gameStateText = localStorage.getItem(getGameType() + \"/\" + gameRef);\n try {\n const localStorageDataInternal = JSON.parse(\n gameStateText\n ) as LocalStorageDataInternal;\n return localStorageDataInternal;\n } catch (_e) {\n return undefined;\n }\n }\n}\n","export class AppError extends Error {\n constructor(\n message: string,\n public code: string,\n public isExpected: boolean\n ) {\n super(message);\n this.name = \"AppError\";\n }\n}\n\nexport enum AppErrorCode {\n ErrAbstractNotCurrent,\n}\n","import { AppError } from \"../domain/AppError\";\nimport { ApiRequest, ApiResponse, Payload } from \"../domain/serverContract\";\n\ninterface HttpResponse extends Response {\n parsedBody?: T;\n}\n\nexport async function http(request: RequestInfo): Promise> {\n const response: HttpResponse = await fetch(request);\n try {\n // may error if there is no body\n // const text = await response.text();\n\n response.parsedBody = await response.json();\n } catch (ex) {}\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n return response;\n}\n\nexport async function post(\n path: string,\n body: any,\n args: RequestInit = { method: \"post\", body: JSON.stringify(body) }\n): Promise> {\n return await http(new Request(path, args));\n}\nexport async function makeRequest(\n request: ApiRequest,\n path: string\n) {\n const serverResponse = await post(origin + path, request);\n const body = serverResponse.parsedBody;\n if (body.errorMessage) {\n throw new AppError(body.errorMessage, body.errorCode, body.isExpectedError);\n }\n const response = serverResponse.parsedBody as ApiResponse;\n return { ...response.payload, timestamp: response.timestamp } as TResponse;\n}\n","import * as React from \"react\";\nimport { Container, Box, Button } from \"@material-ui/core\";\nimport { useEffect, useRef } from \"react\";\nimport {\n readStateFromLocalStorage,\n storeProgressLocally,\n} from \"../localStorage\";\nimport { ShareGameRequest, shareGame } from \"../requests/shareGame\";\nimport { openJustOkDialog } from \"../../../components/JustOkDialog\";\nimport { getBaseUrl } from \"../url\";\nimport { notifySuccess } from \"../../../components/NotificationManager\";\n\nexport interface ShareProgressComponentProps {\n showShareProgressUrl: string;\n}\nexport const ShareProgressComponent = (props: ShareProgressComponentProps) => {\n const { showShareProgressUrl } = props;\n const shareUrlRef = useRef(null);\n useEffect(() => {\n // Preselect the URL so that the copy will copy the entire URL\n if (showShareProgressUrl === \"\") return;\n let element: HTMLSpanElement = shareUrlRef.current;\n if (element === null) return;\n const s = window.getSelection();\n const r = document.createRange();\n r.selectNodeContents(element);\n s.removeAllRanges();\n s.addRange(r);\n });\n return (\n \n To share your progress, copy the link below to the clipboard and send it\n (for example, using email or chat). If you want to resume this game later\n on another device, then send it to yourself. Shared progress is saved for\n ten days.\n \n \n
\n \n {showShareProgressUrl}\n \n
\n
\n \n {\n document.execCommand(\"copy\");\n if (navigator.clipboard) {\n await navigator.clipboard.writeText(showShareProgressUrl);\n }\n notifySuccess(\"Copied\");\n }}\n >\n Copy to Clipboard\n \n \n
\n \n
\n
\n );\n};\n\nexport const shareProgress = async (gameRef: string, progress: unknown) => {\n // If the version in local storage is the same as what is on the server, then no need to create a new game\n // Unless it is old\n const localState = readStateFromLocalStorage(gameRef);\n // If there has been no sharing on this device/tab, then the sharedGameRef will be undefined.\n // In that case, we use the gameRef, which should be the same as the ref in the window location.\n let sharedGameRef = localState.sharedGameRef ?? localState.gameRef;\n if (\n localState.unmodified === false ||\n localState.lastShareTime == null ||\n localState.lastShareTime.getTime() - Date.now() > 7200 // Definition of old in ms\n ) {\n const shareGameRequest: ShareGameRequest = {\n gameRef: gameRef,\n progress,\n };\n const response = await shareGame(shareGameRequest);\n sharedGameRef = response.gameRef;\n storeProgressLocally(\n sharedGameRef,\n (data) => (data.unmodified = true),\n true // this is an update to shared progress\n );\n }\n openJustOkDialog({\n content: (\n \n ),\n title: \"Share Progress\",\n });\n};\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { ErrorResponse } from \"../serverContract\";\nimport { makeRequest } from \"../../../http/http\";\n\nexport interface ShareGameRequest {\n gameRef: string;\n progress: unknown;\n}\nexport interface ShareGameResponse extends ApiResponseHeader {\n gameRef: string;\n}\n\ninterface ResponseInternal extends ErrorResponse, ShareGameResponse {}\n\nexport async function shareGame(request: ShareGameRequest) {\n return await makeRequest(request, \"/api/share_game\");\n}\n","import { IconButton, InputAdornment, TextField } from \"@material-ui/core\";\nimport { Clear } from \"@material-ui/icons\";\nimport * as React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { isMobile } from \"react-device-detect\";\nimport { AppState, DispatchType } from \"./SpellGameComponent\";\nimport { notifyErrorTransient } from \"../../../components/NotificationManager\";\n\nexport interface GuessInputComponentProps {\n onChange: (guess: string) => void;\n requiredLetters: string;\n optionalLetters: string;\n appState: AppState;\n dispatchPopAction: () => void;\n}\nexport const GuessInputComponent = (props: GuessInputComponentProps) => {\n const {\n onChange,\n requiredLetters,\n optionalLetters,\n appState,\n dispatchPopAction,\n } = props;\n\n const [guess, setGuessState] = useState(\"\");\n const setGuess = (guess: string) => {\n setGuessState(guess);\n onChange(guess);\n };\n const inputRef = useRef(null);\n const [insertPositionState, setInsertPositionState] = useState(0);\n\n const insertPosition =\n appState.pendingAction && isMobile === false\n ? inputRef?.current?.selectionStart ?? 0\n : insertPositionState;\n\n const setInsertPosition = (newInsertPosition: number) => {\n setInsertPositionState(newInsertPosition > 0 ? newInsertPosition : 0);\n };\n\n useEffect(() => {\n const inputElement: HTMLInputElement = inputRef.current;\n inputElement.focus();\n if (isMobile) {\n inputElement.selectionStart = inputRef.current.value.length;\n inputElement.selectionEnd = inputRef.current.value.length;\n } else {\n inputElement.selectionStart = insertPosition;\n inputElement.selectionEnd = insertPosition;\n }\n });\n\n useEffect(() => {\n switch (appState.pendingAction?.type) {\n case DispatchType.Delete:\n dispatchPopAction();\n if (insertPosition === 0) return;\n setGuess(\n guess.slice(0, insertPosition - 1) + guess.slice(insertPosition)\n );\n setInsertPosition(insertPosition - 1);\n break;\n case DispatchType.Add:\n setGuess(\n guess.slice(0, insertPosition) +\n appState.pendingAction.letter +\n guess.slice(insertPosition)\n );\n setInsertPosition(insertPosition + 1);\n dispatchPopAction();\n break;\n case DispatchType.Clear:\n setGuess(\"\");\n setInsertPosition(0);\n dispatchPopAction();\n break;\n }\n });\n\n return (\n \n {\n setGuess(\"\");\n setInsertPosition(0);\n }}\n >\n \n \n \n ),\n }}\n value={guess + (isMobile ? \"|\" : \"\")}\n onChange={(event) => {\n let newGuess = event.target.value.toLowerCase();\n if (isMobile) newGuess = newGuess.substring(0, newGuess.length - 1);\n const badLetter = [...newGuess].find((letter) => {\n const requiredLetter = [...(requiredLetters ?? [])].find(\n (requiredLetter) => requiredLetter === letter\n );\n if (requiredLetter !== undefined) return undefined;\n const optionalLetter = [...(optionalLetters ?? [])].find(\n (optionalLetter) => optionalLetter === letter\n );\n if (optionalLetter !== undefined) return undefined;\n return letter;\n });\n\n if (badLetter === undefined) {\n setGuess(newGuess);\n setInsertPosition(event.target.selectionStart);\n } else {\n setInsertPosition(event.target.selectionStart - 1);\n if (badLetter.trim().length !== 0)\n notifyErrorTransient(\n `${badLetter} is not one of the acceptable letters`\n );\n }\n }}\n />\n );\n};\n","import { Button } from \"@material-ui/core\";\nimport { RadioButtonUncheckedOutlined } from \"@material-ui/icons\";\nimport * as React from \"react\";\n\nexport interface InputButtonComponentProps {\n letter: string;\n isRequired: boolean;\n onClick: () => void;\n}\n\n// InputButtonComponent presents a button in a custom keyboard.\nexport const InputButtonComponent = (props: InputButtonComponentProps) => {\n const { isRequired, letter, onClick } = props;\n\n return (\n {\n onClick();\n }}\n >\n \n
{letter}
\n {isRequired && (\n \n \n \n )}\n \n \n );\n};\n","import { Box } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { InputButtonComponent } from \"../../play/components/InputButtonComponent\";\n\nexport interface LettersComponentProps {\n letters: Array;\n requiredLetters: string;\n onClick: (letter: string) => void;\n}\nexport const LettersComponent = (props: LettersComponentProps) => {\n const { letters, requiredLetters, onClick } = props;\n\n return (\n <>\n {letters.map((letter, index) => {\n return (\n \n {\n onClick(letter);\n }}\n letter={letter}\n isRequired={\n !![...(requiredLetters ?? [])].find(\n (requiredLetter) => requiredLetter === letter\n )\n }\n />\n \n );\n })}\n \n );\n};\n","import { Box, Grid, Typography } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { getLevelFromScore, Level } from \"../../../domain/types\";\nimport { Answer } from \"../spell_types\";\n\nconst sortedAnswerComponent = (answers: Array) =>\n answers\n .sort((a, b) => {\n if (a.word < b.word) {\n return -1;\n }\n if (a.word > b.word) {\n return 1;\n }\n // a must be equal to b\n return 0;\n })\n .map((answer, index) => {\n return (\n \n \n {answer.word} {answer.score}\n \n \n );\n });\n\nconst logoBlue = \"#0055aa\";\nconst logoYellow = \"#FFCB05\";\n\nconst vw = 400;\nconst vh = 60;\nconst achievedColor = logoBlue;\nconst highestAchievedColor = logoYellow;\nconst unachievedColor = \"black\"; //\"#9a9ea1\";\nconst rungRadius = 5;\nconst progressMarkRadius = rungRadius + 2;\nconst ladderLength = vw - 2 * rungRadius;\nconst ladderX = rungRadius;\nconst ladderY = progressMarkRadius;\n\nexport interface ProgressComponentProps {\n foundWords: string[];\n answers: Answer[];\n gameAnswerCount: number;\n levels: Level[];\n score: number;\n}\nexport const ProgressComponent = (props: ProgressComponentProps) => {\n const { foundWords, answers, gameAnswerCount, levels, score } = props;\n\n if (foundWords == null) return null;\n // Create array with only the found answers\n const foundAnswers = foundWords.map((word) =>\n answers.find((answer) => answer.word === word)\n );\n\n const [newKey, setNewKey] = useState(0);\n const [levelName, setLevelName] = useState(\"\");\n const levelNameFromScore = getLevelFromScore(levels, score).name;\n const highestLevelScore = levels[levels.length - 1].score;\n const progressMarkerX = ladderX + (score / highestLevelScore) * ladderLength;\n\n const isLevelChanged = levelNameFromScore !== levelName;\n if (isLevelChanged) setNewKey(newKey + 1);\n const animatedLevelName = isLevelChanged ? null : (\n \n \n \n {(() => {\n // Generate a point for each level\n const levelCount = levels.length;\n const rungSpace = ladderLength / (levelCount - 1);\n return levels.map((level, index) => {\n let color = unachievedColor;\n const achieved = score >= level.score;\n if (achieved) {\n if (index === levelCount - 1 || levels[index + 1].score > score) {\n color = highestAchievedColor;\n } else {\n color = achievedColor;\n }\n }\n return (\n \n );\n });\n })()}\n \n \n {getLevelFromScore(levels, score).name}\n \n \n \n \n \n );\n\n if (isLevelChanged) setLevelName(levelNameFromScore);\n return (\n \n \n {(() => {\n const foundWordsCount = foundWords.length;\n let wordCountMessage: string;\n const wordForm = foundWordsCount === 1 ? \"word\" : \"words\";\n const pointForm = score === 1 ? \"point\" : \"points\";\n switch (foundWordsCount) {\n case 0:\n wordCountMessage = `You have ${gameAnswerCount} ${wordForm} to find.`;\n break;\n case gameAnswerCount:\n if (foundWordsCount === 1) {\n wordCountMessage = `Congratulations! You found the word:`;\n } else {\n wordCountMessage = `Congratulations! You found all ${foundWordsCount} ${wordForm}:`;\n }\n break;\n default:\n wordCountMessage = `You found ${foundWordsCount} ${wordForm} for ${score} ${pointForm}:`;\n break;\n }\n return (\n \n {animatedLevelName}\n {wordCountMessage}\n \n );\n })()}\n \n {sortedAnswerComponent(foundAnswers)}\n \n \n );\n};\n","import { Box, Container } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { SpellPlaySpec } from \"../spell_types\";\nimport { GameInfo } from \"./SpellGameComponent\";\n\nexport interface SpellRulesComponentProps {\n playSpec: SpellPlaySpec;\n gameInfo: GameInfo;\n}\nexport const SpellRulesComponent = (props: SpellRulesComponentProps) => {\n const { playSpec, gameInfo } = props;\n const rulesPrologue = playSpec.rulesPrologue;\n const rulesPrologueComponent = !rulesPrologue ? null : (\n {rulesPrologue}\n );\n return (\n \n {rulesPrologueComponent}\n \n \n The following rules apply to this game:\n
    \n \n
  • \n {`Letters may ${\n gameInfo.canReuseLetters ? \"\" : \"not \"\n } be reused.`}\n
  • \n
  • The shortest word has {gameInfo.minLength} letters.
  • \n
  • \n There{\" \"}\n {gameInfo.pangramCount === 1\n ? \"is one word\"\n : `are ${gameInfo.pangramCount} words`}{\" \"}\n that use{gameInfo.pangramCount === 1 ? \"s\" : \"\"} all of the letters.\n
  • \n
  • \n {`This game has a total of\n ${playSpec.answers.length} possible words worth ${gameInfo.maxPoints} points.\n `}\n {gameInfo.highestLevel.score >= gameInfo.maxPoints\n ? \"\"\n : \" You don't need to find all of the words to achieve the top level.\"}\n
  • \n
\n
\n \n \n The game levels and the number of points needed to reach each level are:{\" \"}\n {props.playSpec.levels.map((level, index) => (\n \n {index > 0 ? \", \" : \"\"}\n {level.name} {level.score}\n \n ))}\n .\n \n \n \n );\n};\n\nexport const makeSeparatedElementStringFromList = (\n list: string[]\n): JSX.Element[] => {\n if (list === undefined) return undefined;\n return list.reduce((result, item, index) => {\n if (index !== 0) result.push(, );\n result.push({item});\n return result;\n }, [] as JSX.Element[]);\n};\n\nconst RequiredLettersInfoComponent = (props: {\n requiredLetters: string;\n}): JSX.Element => {\n const { requiredLetters } = props;\n if (!requiredLetters?.length) return null;\n return (\n
  • \n Each word must include the required letter\n {requiredLetters.length === 1 ? \": \" : \"s: \"}\n {makeSeparatedElementStringFromList(\n [...(requiredLetters ?? [])].map((item) => item.toUpperCase())\n )}\n .\n
  • \n );\n};\n","export const min = (items: T[]): T => {\n // undefined is min\n return items.reduce((result, item) => {\n if (item === undefined || result === undefined) return undefined;\n if (item < result) return item;\n return result;\n }, items[0]);\n};\n\nexport const max = (items: T[]): T => {\n // undefined is max\n return items.reduce((result, item) => {\n if (item === undefined || result === undefined) return undefined;\n if (item > result) return item;\n return result;\n }, items[0]);\n};\n\nexport const sum = (a: number[]) => a.reduce((sum, n) => (sum += n), 0);\n\nexport const makeSeparatedStringFromList = (list: string[]): string => {\n if (list === undefined) return undefined;\n return list.reduce((result, item, index) => {\n if (index === 0) return item;\n return result + \", \" + item;\n }, \"\");\n};\n\nexport const round = (x: number) => Math.round(x);\n\nexport function uuidv4() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n var r = (Math.random() * 16) | 0,\n v = c == \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nlet serialIdCounter = -1;\nexport const serialId = () => ++serialIdCounter;\n\n// pickout removes pickLetters from the source.\n// Any letter in pickLetters is removed from the source.\nexport const pickout = (pickLetters: string, source: string) => {\n if (source == null || source.length === 0) return source;\n return [...(source ?? [])].reduce((result, letter) => {\n if (pickLetters.indexOf(letter) >= 0) return result;\n return result + letter;\n }, \"\");\n};\n\nexport const delay = (promise: Promise, ms: number) => {\n return new Promise((resolve) => setTimeout(resolve, ms)).then(() => promise);\n};\n\nexport const delay2 = (ms: number) => {\n return new Promise((resolve) => setTimeout(resolve, ms));\n};\n\n// Assumes no duplicates in either list\n// Merges without additional duplication\nexport const mergeWordLists = (lista: string[], listb: string[]) => {\n lista = lista ?? [];\n listb = listb ?? [];\n return listb.reduce((result, wordb) => {\n if (lista.includes(wordb)) return result;\n result.push(wordb);\n return result;\n }, lista);\n};\n\n// Assumes no duplicates in either list\nexport const intersection = (lista: string[], listb: string[]) => {\n lista = lista ?? [];\n listb = listb ?? [];\n return listb.reduce((result, wordb) => {\n if (lista.includes(wordb)) {\n result.push(wordb);\n return result;\n }\n return result;\n }, [] as string[]);\n};\n\n// eliminates duplicates\nexport const union = (lista: string[], listb: string[]) => {\n lista = lista ?? [];\n listb = listb ?? [];\n const dict: Record = Object.create(null);\n lista.forEach((item) => (dict[item] = true));\n listb.forEach((item) => (dict[item] = true));\n return Object.keys(dict);\n};\n\n// Much faster to use loops with indices\n// Returns list of duplicates\nexport const findDuplicates = (list: string[]) => {\n const lista = [...(list ?? [])];\n return list.reduce((result, word) => {\n lista.shift();\n if (lista.includes(word)) {\n result.push(word);\n return result;\n }\n return result;\n }, []);\n};\n\nexport const pluralize = (count: number, word: string) => {\n if (count === 1) return `${count} ${word}`;\n return `${count} ${word}s`;\n};\n\nexport const shuffle = (array: Array) => {\n const newArray = [...array];\n let count = 0;\n while (true) {\n for (let i = newArray.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [newArray[i], newArray[j]] = [newArray[j], newArray[i]];\n }\n // Don't return the items in the same order.\n // Stop at 10 tries since some letter combinations are problematic (such as a string consisting of exactly 2 of the same letter)\n count++;\n if (\n newArray.length < 2 ||\n newArray.join(\"\") !== array.join(\"\") ||\n count === 10\n )\n return newArray;\n }\n};\n\nexport const shuffleString = (text: string) => {\n return shuffle(text.split(\"\")).join(\"\");\n};\n\n// isAnagramOf returns true if a is an anagram of b.\nexport const isAnagramOf = (a: string, b: string) => {\n if (a == null || b == null) return false;\n return [...a].sort().join(\"\") === [...b].sort().join(\"\");\n};\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n flexGrow: 1,\n },\n });\n});\nexport interface ToolbarTitleProps {}\n\nexport const ToolbarTitle: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n\nexport default ToolbarTitle;\n","import MuiDialog from \"@material-ui/core/Dialog\";\nimport DialogActions from \"@material-ui/core/DialogActions\";\nimport DialogContent from \"@material-ui/core/DialogContent\";\nimport DialogTitle from \"@material-ui/core/DialogTitle\";\nimport * as React from \"react\";\nimport { useEffect } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { SubtleButton } from \"../buttons\";\nimport { getDialogMethods, makeDialog, Dialog } from \"./DialogManager\";\n\nexport interface ConfirmationDialogBaseProps {\n open: boolean;\n onClose: (isOk: boolean) => void;\n title: string;\n okayText?: string;\n}\n\nexport const ConfirmationDialogBase: React.FunctionComponent = (\n props\n) => {\n const { onClose, open, okayText, title } = props;\n\n const handleCancel = () => {\n onClose(false);\n };\n\n const handleOk = () => {\n onClose(true);\n };\n const history = useHistory();\n useEffect(() => {\n // Some apps may not use router.\n if (!history) return;\n // To start listening for location changes...\n return history.listen(() => {\n onClose(false);\n });\n }, []);\n\n return (\n \n {title}\n {props.children}\n \n \n Cancel\n \n {okayText ?? \"Ok\"}\n \n \n );\n};\n","import * as React from \"react\";\nimport { ConfirmationDialogBase } from \"./dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"./dialogTools/DialogManager\";\n\ninterface InlineConfirmationDialogProps {\n title: string;\n okayText?: string;\n content: string | JSX.Element;\n}\n\nexport const makeInlineConfirmationDialog = () => {\n const dialog = makeDialog({\n name: \"InlineConfirmationDialog\",\n componentRenderer: (props) => {\n return (\n {\n props.close(isOkay, undefined);\n }}\n open={true}\n title={props.props.title}\n okayText={props.props.okayText}\n >\n {props.props.content}\n \n );\n },\n });\n return dialog;\n};\n\nlet inlineConfirmationDialogInternal: Dialog<\n boolean,\n InlineConfirmationDialogProps\n>;\nexport const openConfirmationDialog = (\n props: InlineConfirmationDialogProps\n) => {\n if (!inlineConfirmationDialogInternal) {\n inlineConfirmationDialogInternal = makeInlineConfirmationDialog();\n }\n return getDialogMethods().open(inlineConfirmationDialogInternal, props);\n};\n","import {\n AppBar,\n Button,\n Container,\n IconButton,\n Menu,\n MenuItem,\n Toolbar,\n} from \"@material-ui/core\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport { Menu as MenuIcon, ReplayOutlined } from \"@material-ui/icons\";\nimport * as React from \"react\";\nimport { useClientRect } from \"../../../measure\";\nimport { clearLocalStorageForGame, clearLocalStorage } from \"../localStorage\";\nimport { ToolbarTitle } from \"../../../components/ToolbarTitle\";\nimport { openConfirmationDialog } from \"../../../components/ConfirmationDialog\";\nimport {\n getGameTypeLabel,\n gameTypeHasAnswers,\n gameTypeUsesMenuRestart,\n} from \"../../../domain/types\";\nimport { getGameType } from \"../globalPlayData\";\n\nexport interface TopAppBarProps {\n answers: () => void;\n}\n\nexport const ShareProgressContext = React.createContext(null);\nexport const RulesContext = React.createContext(null);\nexport const RestartContext = React.createContext(null);\n\nlet shareProgressHandler = () => {};\nconst setShareProgressHandler = (handler: () => {}) => {\n shareProgressHandler = handler;\n};\n\nlet rulesHandler = () => {};\nconst setRulesHandler = (handler: () => {}) => {\n rulesHandler = handler;\n};\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n flexGrow: 1,\n },\n menuButton: {\n marginRight: theme.spacing(2),\n },\n });\n});\n\nexport const TopAppBarComponent: React.FunctionComponent = (\n props\n) => {\n const [rect, ref] = useClientRect();\n const [anchorEl, setAnchorEl] = React.useState(null);\n const classes = useStyles();\n\n const handleMenu = (event: React.MouseEvent) => {\n setAnchorEl(event.currentTarget);\n };\n\n const handleClose = () => {\n setAnchorEl(null);\n };\n const menuOpen = Boolean(anchorEl);\n return (\n <>\n \n \n
    \n \n \n \n
    \n \n {gameTypeUsesMenuRestart(getGameType()) && (\n {\n handleClose();\n const isOkay = await openConfirmationDialog({\n content: (\n \n If you restart the game, all of your answers for this\n game will be deleted from this device. Your shared\n progress will not be deleted. nor will your answers for\n other games.\n \n ),\n title: \"Restart Game\",\n okayText: \"Restart Game\",\n });\n if (isOkay) {\n clearLocalStorageForGame();\n location.reload();\n }\n }}\n >\n Restart\n \n )}\n {\n handleClose();\n const isOkay = await openConfirmationDialog({\n content: (\n \n If you reset the game, all of your answers for all of your\n Cortex games will be deleted from this device. Your shared\n progress will not be deleted. Only use this if you are\n having trouble getting games to work.\n \n ),\n title: \"title\",\n okayText: \"Factory Reset\",\n });\n if (isOkay) {\n clearLocalStorage();\n location.reload();\n }\n }}\n >\n Factory Reset\n \n \n {getGameTypeLabel(getGameType())}\n {gameTypeHasAnswers(getGameType()) && (\n \n )}\n \n \n
    \n
    \n \n \n \n {props.children}\n \n \n \n \n );\n};\n","import { Box, Button, Grid, Typography } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { useContext, useEffect, useReducer, useState } from \"react\";\nimport { openJustOkDialog } from \"../../../components/JustOkDialog\";\nimport {\n notifyErrorTransient,\n notifySuccess,\n notifySuccessTransient,\n} from \"../../../components/NotificationManager\";\nimport { getLevelFromScore, Level } from \"../../../domain/types\";\nimport { shareProgress } from \"../../play/components/ShareProgressComponent\";\n\nimport { storeProgressLocally } from \"../../play/localStorage\";\nimport { SpellPlaySpec, SpellProgress } from \"../spell_types\";\nimport { GuessInputComponent } from \"./GuessInputComponent\";\nimport { LettersComponent } from \"./LettersComponent\";\nimport { ProgressComponent } from \"./ProgressComponent\";\nimport { SpellRulesComponent } from \"./SpellRulesComponent\";\nimport {\n makeSeparatedStringFromList,\n min,\n sum,\n shuffle,\n} from \"../../../utilities\";\nimport {\n ShareProgressContext,\n RulesContext,\n} from \"../../play/components/TopAppBarComponent\";\n\nconst smile = \"\\u{1F600}\";\n\nexport enum DispatchType {\n Add,\n Delete,\n Clear,\n Pop,\n}\n\nexport interface Action {\n type: DispatchType;\n letter?: string;\n}\n\nexport interface AppState {\n pendingAction: Action | undefined;\n}\n\nconst initialAppState: AppState = { pendingAction: undefined };\n\nfunction reducer(_state: AppState, action: Action): AppState {\n switch (action.type) {\n case DispatchType.Add:\n return { pendingAction: action };\n case DispatchType.Delete:\n return { pendingAction: action };\n case DispatchType.Clear:\n return { pendingAction: action };\n case DispatchType.Pop:\n return initialAppState;\n default:\n throw new Error();\n }\n}\n\nexport interface SpellGameComponentProps {\n gameRef: string;\n playSpec: SpellPlaySpec;\n progress: SpellProgress;\n setCurrentProgress: (getProgress: () => SpellProgress) => void;\n}\n\nexport interface GameInfo {\n minLength: number;\n maxPoints: number;\n highestLevel: Level;\n canReuseLetters: boolean;\n pangramCount: number;\n}\n\ninterface InteractiveGameState {\n gameRef: string;\n letters: Array;\n foundWords: string[];\n currentGuess: string;\n}\n\nconst makeStateFromProps = (\n props: SpellGameComponentProps\n): InteractiveGameState => {\n return {\n letters: [\n ...(props.playSpec.requiredLetters ?? []),\n ...(props.playSpec.optionalLetters ?? []),\n ],\n foundWords: props.progress ?? ([] as SpellProgress),\n currentGuess: \"\",\n gameRef: props.gameRef,\n };\n};\n\nexport const getCanReuseLetters = (playSpec: SpellPlaySpec) => {\n return (\n undefined !==\n playSpec.answers.find((answer) => {\n const letters = Array.from(answer.word);\n const letterCount = letters.length;\n // Compare first letter to all following\n // Compare second letter to all following\n // ...stop at next to last letter\n for (let i = 0; i < letterCount - 1; i++) {\n for (let j = i + 1; j < letterCount; j++) {\n if (letters[i] === letters[j]) return true;\n }\n }\n return false;\n })\n );\n};\n\nexport const getPangramCount = (playSpec: SpellPlaySpec) => {\n const answerLetters = [\n ...(playSpec.requiredLetters ?? []),\n ...(playSpec.optionalLetters ?? []),\n ];\n const answerLetterCount = answerLetters.length;\n const pangrams = playSpec.answers.filter((answer) => {\n if (answer.word.length < answerLetterCount) return false; // too short\n for (let i = 0; i < answerLetterCount; i++) {\n if (!answer.word.includes(answerLetters[i])) return false;\n }\n return true;\n });\n return pangrams?.length ?? 0;\n};\n\nexport const getMinLength = (playSpec: SpellPlaySpec) => {\n return min(playSpec.answers.map((answer) => answer.word.length));\n};\n\nexport const SpellGameComponent = (props: SpellGameComponentProps) => {\n const [appState, dispatch] = useReducer(reducer, initialAppState);\n const [gameState, setGameState] = useState(makeStateFromProps(props));\n const [firstTime, setFirstTime] = useState(true);\n props.setCurrentProgress(() => gameState.foundWords);\n const [gameInfo] = useState(\n (): GameInfo => {\n return {\n minLength: getMinLength(props.playSpec),\n maxPoints: sum(props.playSpec.answers.map((answer) => answer.score)),\n highestLevel: props.playSpec.levels[props.playSpec.levels.length - 1],\n pangramCount: getPangramCount(props.playSpec),\n canReuseLetters: getCanReuseLetters(props.playSpec),\n };\n }\n );\n\n const displayRules = () => {\n openJustOkDialog({\n content: (\n \n ),\n title: \"Rules\",\n });\n };\n\n useContext(ShareProgressContext)(() =>\n shareProgress(gameState.gameRef, gameState.foundWords)\n );\n\n useContext(RulesContext)(displayRules);\n\n useEffect(() => {\n // Save state to local storage\n // Only when the correct answers have changed\n // Don't write the first time, because we already either read or wrote the state\n if (firstTime) {\n setFirstTime(false);\n return;\n }\n storeProgressLocally(\n gameState.gameRef,\n (data) => {\n data.progress = gameState.foundWords;\n data.unmodified = false;\n },\n false // means not updated shared progress\n );\n }, [gameState.foundWords]);\n\n const [score, setScore] = useState(0);\n useEffect(() => {\n // Update score when answers change\n const answers = props.playSpec.answers;\n const score = sum(\n gameState.foundWords.map((answerWord) => {\n const found = answers.find((answer) => answer.word === answerWord);\n return found?.score ?? 0;\n })\n );\n setScore(score);\n if (score === 0) displayRules();\n }, [gameState.foundWords]);\n\n const [level, setLevel] = useState(props.playSpec.levels[0]);\n\n const submitHandler = () => {\n if (gameState.currentGuess === \"\") return;\n if (props.playSpec.answers.length === gameState.foundWords.length) {\n notifySuccess(\n `You already found all ${props.playSpec.answers.length} words!`\n );\n return;\n }\n\n if (gameState.foundWords.find((word) => word === gameState.currentGuess)) {\n notifyErrorTransient(`${gameState.currentGuess} was already found`);\n return;\n }\n\n let answer = props.playSpec.answers.find(\n (answer) => answer.word === gameState.currentGuess\n );\n const answerWord = answer?.word;\n const foundWords =\n answerWord === undefined\n ? gameState.foundWords\n : [...gameState.foundWords, answerWord];\n if (answerWord === undefined) {\n if (gameState.currentGuess.length < gameInfo.minLength) {\n notifyErrorTransient(`${gameState.currentGuess} is too short`);\n return;\n }\n if (props.playSpec.requiredLetters?.length > 0) {\n // Find which letters are missing\n const missingLetters = [\n ...(props.playSpec.requiredLetters ?? []),\n ].filter(\n (requiredLetter) =>\n gameState.currentGuess.includes(requiredLetter) === false\n );\n if (missingLetters.length > 0) {\n if (missingLetters.length === 1) {\n notifyErrorTransient(\n `${gameState.currentGuess} is missing one required letter: ${missingLetters[0]}`\n );\n return;\n }\n notifyErrorTransient(\n `${\n gameState.currentGuess\n } is missing these required letters: ${makeSeparatedStringFromList(\n missingLetters\n )}`\n );\n return;\n }\n }\n notifyErrorTransient(\n `${gameState.currentGuess} is not one of the answers`\n );\n return;\n }\n\n const newGameState = {\n ...gameState,\n currentGuess: \"\",\n foundWords,\n };\n setGameState(newGameState);\n dispatch({ type: DispatchType.Clear });\n\n const nextLevel = getLevelFromScore(\n props.playSpec.levels,\n score + answer.score\n );\n const isNewLevel = nextLevel.score !== level.score;\n if (isNewLevel) {\n // openJustOkDialog({content: achievementLevelElement, title: \"Congrats!\"})\n //setShowAchievementLevel(true); //********************************************\n }\n notifySuccessTransient(\n `${answer.word} is worth ${answer.score} points ${smile}`\n );\n setLevel(nextLevel);\n };\n\n const keyUpHandler = (event: KeyboardEvent) => {\n if (event.keyCode === 13) {\n //Enter key\n submitHandler();\n }\n };\n\n useEffect(() => {\n document.addEventListener(\"keyup\", keyUpHandler, false);\n return () => {\n document.removeEventListener(\"keyup\", keyUpHandler, false);\n };\n });\n\n const progressComponent = (\n \n );\n\n return (\n \n \n {props.playSpec.title}\n {props.playSpec.subtitle}\n \n {\n dispatch({ type: DispatchType.Pop });\n }}\n requiredLetters={props.playSpec.requiredLetters}\n optionalLetters={props.playSpec.optionalLetters}\n onChange={(guess: string) => {\n setGameState({\n ...gameState,\n currentGuess: guess,\n });\n }}\n />\n\n \n \n {\n dispatch({ type: DispatchType.Delete });\n }}\n >\n Delete\n \n \n \n \n \n \n {\n dispatch({ type: DispatchType.Add, letter });\n }}\n />\n \n \n {\n const newGameState = {\n ...gameState,\n letters: shuffle(gameState.letters),\n };\n setGameState(newGameState);\n }}\n >\n Shuffle\n \n \n {progressComponent}\n \n );\n};\n","import { Box, Paper } from \"@material-ui/core\";\nimport * as React from \"react\";\n\nexport const PlayPrivacy = () => {\n return (\n \n \n \n This privacy policy describes what we do with your data when you play\n this game. It is effective as of 13 August 2020. Questions about this\n policy should be emailed to privacy @ cortexplay.com.\n
      \n
    • \n We do not ask for or store any information about who you are, such\n as your name, age, email address, gender. This game is designed to\n be played without a user account, specifically to avoid collecting\n personally-identifiable information.\n
    • \n
    • \n We do collect information that helps us provide a reliable\n service, such as the type of device and browser you use to play\n the game, and the IP address from which you access the game.\n
    • \n
    • \n We do collect information that helps us improve the quality of the\n game, such as which features you use when you play.\n
    • \n
    • \n We do store information on your computer about the games you play.\n We do that for two reasons:\n
        \n
      • \n No user has an account, so we cannot store game progress on\n our server in a way that is associated with a user. We store\n game progress on your computer so that you can continue a game\n at a later time without losing your progress. You can store\n your progress on our servers, but that is not stored with any\n information about you.\n
      • \n
      • Storing some data locally improves performance.
      • \n
      \n
    • \n
    \n
    \n
    \n
    \n );\n};\n","import { Box, Paper } from \"@material-ui/core\";\nimport * as React from \"react\";\n\nexport const PlayTerms = () => {\n return (\n \n \n \n These terms describes what you can expect from us (Cortex Play) and\n what we expect from you. It is effective as of 13 August 2020.\n Questions about this policy should be emailed to terms @\n cortexplay.com.\n
      \n
    • \n What you can expect from us:\n
        \n
      • games designed to be both enjoyable and educational
      • \n
      • good game performance and availability
      • \n
      • no advertising or collection of personal information
      • \n
      \n
    • \n
    • \n What we expect from you:\n
        \n
      • \n not to use the game for any purpose other than playing. For\n example, you may not attempt to disrupt the game for other\n users by starting a denial of service attack on the game web\n site.\n
      • \n
      \n
    • \n
    \n
    \n
    \n
    \n );\n};\n","import { PlaySpec, GameType, AuthorSpec } from \"./types\";\n\nexport interface Answer {\n word: string;\n score: number;\n}\n\nexport interface OperationDomain {\n // The lhs is the text entered by the author to describe the range of the Lhs operands.\n lhs: string;\n // The rhs is the text entered by the author to describe the range of the Rhs operands.\n rhs: string;\n}\n\nexport const NewOperationDomain = (): OperationDomain => {\n return {\n lhs: \"\",\n rhs: \"\",\n };\n};\n\nexport interface ComputePlaySpec extends PlaySpec {\n add: OperationDomain;\n sub: OperationDomain;\n mul: OperationDomain;\n div: OperationDomain;\n // timeLimit is the number of seconds until the game ends.\n // If undefined, then there is no time limit.\n timeLimit: number;\n // ChallengeCount is the number of challenges in a game.\n challengeCount: number;\n // MustSolve true means each challenge must be solved before the next challenge is presented.\n mustSolve: boolean;\n}\n\n// GameAuthorSpec has the data needed to author a game\nexport interface ComputeAuthorSpec extends AuthorSpec {}\n\nexport interface ComputeSpec {\n playSpec: ComputePlaySpec;\n authorSpec: ComputeAuthorSpec;\n}\n\n// ComputeRecord is the layout in the database.\n// Edited games are saved in Draft.\n// Publishing copies Draft to Prod.\n// We keep name unique in the database.\nexport interface ComputeRecord {\n gameType: GameType;\n draft: ComputeSpec;\n prod: ComputeSpec;\n}\n\nexport enum Op {\n Add = \"+\",\n Sub = \"-\",\n Mul = \"*\",\n Div = \"/\",\n}\n\nexport const getOpChar = (op: Op) => {\n switch (op) {\n case Op.Add:\n return \"+\";\n case Op.Mul:\n return \"×\";\n case Op.Div:\n return \"÷\";\n case Op.Sub:\n return \"-\";\n }\n};\n\n// Challenge is a problem.\nexport interface Challenge {\n op: Op;\n lhs: number;\n rhs: number;\n}\n\n// Chaser is short for ChallengeAnswer.\n// It holds the challenge and the player's answer (which could be right or wrong).\n// Skipped is true if the user skipped the challenge.\nexport interface Chaser {\n challenge: Challenge;\n answer: number;\n skipped: boolean;\n}\n\nexport interface ComputeProgress {\n chasers: Chaser[];\n elapsedSeconds: number;\n}\n\n// solve returns the correct answer for a challenge.\nexport function solve(c: Challenge) {\n switch (c.op) {\n case Op.Mul:\n return c.lhs * c.rhs;\n case Op.Div:\n return c.lhs / c.rhs;\n case Op.Add:\n return c.lhs + c.rhs;\n case Op.Sub:\n return c.lhs - c.rhs;\n }\n}\n\nexport interface OperandRange {\n start: number;\n end: number;\n}\nconst validSingle = new RegExp(String.raw`^[0-9]+$`);\nconst validRange = new RegExp(String.raw`^[0-9]+-[0-9]+$`);\nconst hyphenWithWhitespace = new RegExp(String.raw`\\s*-\\s*`, \"g\");\nconst whitespace = new RegExp(String.raw`\\s+`, \"g\");\n\n// Compile compiles a text list of possible operand values into an OperandRange structure.\n// Lists consist of one or more comma-separated or whitespace-separated tokens.\n// Each token may be a decimal number, or two decimal numbers separated by a asterisk.\n// Asterisk-separated numbers translate to ranges that start with the smaller number and end with the larger,\n// meaning that order doesn't matter. Specifying the same start and end is identical to specifying a single number.\n// Decimal numbers may not exceed 1000.\n// There are equivalent:\n// * 1-2,4,6-10\n// * 1 - 2,4 6-10\n// * 1-2 4 6-10\n\n// Generously interpret operand ranges:\n// * Ignore duplicates, including overlapping ranges\n// * Allow ranges to go backwards\n// * Preserve range list as typed by user.\n\nfunction compile(t: string): OperandRange[] {\n // * 1 - 2,4 6-10\n // Replace asterisk surrounded by whitespace with just a hyphen\n // After trimming whitespace\n let s = t.trim().replace(hyphenWithWhitespace, \"-\");\n // * 1-2,4 6-10\n // Replace whitespace with a single comma\n s = s.replace(whitespace, \",\");\n // * 1-2,4,6-10\n const tokens = s.split(\",\");\n const r: OperandRange[] = [];\n for (let i = 0; i < tokens.length; i++) {\n if (validSingle.test(tokens[i])) {\n const n = convertOperandToNumber(tokens[i]);\n r.push({ start: n, end: n });\n } else if (validRange.test(tokens[i])) {\n const ts = tokens[i].split(\"-\");\n const n = convertOperandToNumber(ts[0]);\n const m = convertOperandToNumber(ts[1]);\n if (n <= m) {\n r.push({ start: n, end: m });\n } else {\n r.push({ start: m, end: n });\n }\n }\n }\n return r;\n}\n\nfunction convertOperandToNumber(s: string) {\n const n = Number(s);\n if (n > 1000) {\n throw new Error(\"Range value is greater than 1000.\");\n }\n return n;\n}\n\nexport function createAllChallenges(playSpec: ComputePlaySpec) {\n const challenges: Challenge[] = [];\n if (playSpec.add) {\n challenges.push(...createChallenges(Op.Add, playSpec.add));\n }\n if (playSpec.sub) {\n challenges.push(...createChallenges(Op.Sub, playSpec.sub));\n }\n if (playSpec.mul) {\n challenges.push(...createChallenges(Op.Mul, playSpec.mul));\n }\n if (playSpec.div) {\n challenges.push(...createChallenges(Op.Div, playSpec.div));\n }\n return challenges;\n}\n\n// createChallenges returns an array of all of the challenges given an operation and a domain.\nexport function createChallenges(op: Op, od: OperationDomain) {\n const lhs = compile(od.lhs);\n const rhs = compile(od.rhs);\n const challenges: Record = Object.create(null);\n lhs.forEach((lhsRange) => {\n for (let loperand = lhsRange.start; loperand <= lhsRange.end; loperand++) {\n rhs.forEach((rhsRange) => {\n for (\n let roperand = rhsRange.start;\n roperand <= rhsRange.end;\n roperand++\n ) {\n const challenge: Challenge = { op, lhs: loperand, rhs: roperand };\n switch (op) {\n case Op.Div:\n if (solve(challenge) % 1 !== 0) continue;\n break;\n case Op.Sub:\n if (solve(challenge) < 0) continue;\n break;\n }\n challenges[op + loperand + \"|\" + roperand] = challenge;\n }\n });\n }\n });\n return Object.values(challenges);\n}\n","import { useState, useRef } from \"react\";\n\n// Fresh means:\n// * value not captured by closure\n// * value is gettable syncronously\nexport const useFreshState = (\n f: () => TState\n): [() => TState, (s: TState) => void] => {\n const currentState = useRef(undefined);\n const [_reactState, setReactState] = useState(() => {\n const initialValue = f();\n currentState.current = initialValue;\n return initialValue;\n });\n const setter = (s: TState) => {\n currentState.current = s;\n setReactState(s);\n };\n const getter = () => {\n return currentState.current;\n };\n return [getter, setter];\n};\n","import { Box, Container } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport Hider from \"../../../components/Hider\";\nimport {\n ComputePlaySpec,\n createChallenges,\n Op,\n} from \"../../../domain/compute_types\";\nimport { pluralize } from \"../../../utilities\";\nimport { GameInfo } from \"./ComputeGameComponent\";\n\nexport interface ComputeRulesComponentProps {\n playSpec: ComputePlaySpec;\n gameInfo: GameInfo;\n}\nexport const ComputeRulesComponent = (props: ComputeRulesComponentProps) => {\n const { playSpec, gameInfo } = props;\n const rulesPrologue = playSpec.rulesPrologue;\n const rulesPrologueComponent = !rulesPrologue ? null : (\n {rulesPrologue}\n );\n\n const opList: { opLabel: string; opCount: number }[] = [];\n if (playSpec.add) {\n const addChallenges = createChallenges(Op.Add, playSpec.add);\n if (addChallenges.length > 0)\n opList.push({ opLabel: \"addition\", opCount: addChallenges.length });\n }\n if (playSpec.sub) {\n const subChallenges = createChallenges(Op.Sub, playSpec.sub);\n if (subChallenges.length > 0)\n opList.push({ opLabel: \"subtraction\", opCount: subChallenges.length });\n }\n if (playSpec.mul) {\n const mulChallenges = createChallenges(Op.Mul, playSpec.mul);\n if (mulChallenges.length > 0)\n opList.push({ opLabel: \"multiplication\", opCount: mulChallenges.length });\n }\n if (playSpec.div) {\n const divChallenges = createChallenges(Op.Div, playSpec.div);\n if (divChallenges.length > 0)\n opList.push({ opLabel: \"division\", opCount: divChallenges.length });\n }\n let opsText: string;\n if (opList.length === 1) {\n opsText = `${opList[0].opCount} ${opList[0].opLabel}`;\n } else if (opList.length === 2) {\n opsText =\n `${opList[0].opCount} ${opList[0].opLabel}` +\n \" and \" +\n `${opList[1].opCount} ${opList[1].opLabel}`;\n } else if (opList.length === 3) {\n opsText =\n `${opList[0].opCount} ${opList[0].opLabel}` +\n \", \" +\n `${opList[1].opCount} ${opList[1].opLabel}` +\n \", and \" +\n `${opList[2].opCount} ${opList[2].opLabel}`;\n } else if (opList.length === 4) {\n opsText =\n `${opList[0].opCount} ${opList[0].opLabel}` +\n \", \" +\n `${opList[1].opCount} ${opList[1].opLabel}` +\n \", \" +\n `${opList[2].opCount} ${opList[2].opLabel}` +\n \", and \" +\n `${opList[3].opCount} ${opList[3].opLabel}`;\n }\n\n return (\n \n {rulesPrologueComponent}\n \n \n

    The following rules apply to this game:

    \n
      \n
    • \n {`The game has ${pluralize(\n playSpec.challengeCount,\n \"challenge\"\n )} worth a total of ${pluralize(\n playSpec.challengeCount,\n \"point\"\n )}.`}\n {gameInfo.highestLevel.score >= gameInfo.maxPoints\n ? \"\"\n : \" You don't need to solve all of the challenges to achieve the top level.\"}\n
    • \n
    • \n The {pluralize(playSpec.challengeCount, \"challenge\")} are randomly\n selected from {opsText} problems.\n
    • \n \n \n \n
    • \n You can play as many times as you want by clicking PLAY AGAIN.\n
    • \n
    \n
    \n \n \n The game levels and the number of points needed to reach each level are:{\" \"}\n {props.playSpec.levels.map((level, index) => (\n \n {index > 0 ? \", \" : \"\"}\n {level.name} {level.score}\n \n ))}\n .\n \n \n \n );\n};\n","import { IconButton, InputAdornment, TextField } from \"@material-ui/core\";\nimport { Clear } from \"@material-ui/icons\";\nimport * as React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { isMobile } from \"react-device-detect\";\nimport { AppState, DispatchType } from \"./ComputeGameComponent\";\n\nexport interface GuessNumberInputComponentProps {\n onChange: (guess: string) => void;\n appState: AppState;\n dispatchPopAction: () => void;\n}\nexport const GuessNumberInputComponent = (\n props: GuessNumberInputComponentProps\n) => {\n const { onChange, appState, dispatchPopAction } = props;\n\n const [guess, setGuessState] = useState(\"\");\n const setGuess = (guess: string) => {\n setGuessState(guess);\n onChange(guess);\n };\n const inputRef = useRef(null);\n const [insertPositionState, setInsertPositionState] = useState(0);\n\n const insertPosition =\n appState.pendingAction && isMobile === false\n ? inputRef?.current?.selectionStart ?? 0\n : insertPositionState;\n\n const setInsertPosition = (newInsertPosition: number) => {\n setInsertPositionState(newInsertPosition > 0 ? newInsertPosition : 0);\n };\n\n useEffect(() => {\n const inputElement: HTMLInputElement = inputRef.current;\n inputElement.focus();\n if (isMobile) {\n inputElement.selectionStart = inputRef.current.value.length;\n inputElement.selectionEnd = inputRef.current.value.length;\n } else {\n inputElement.selectionStart = insertPosition;\n inputElement.selectionEnd = insertPosition;\n }\n });\n\n useEffect(() => {\n switch (appState.pendingAction?.type) {\n case DispatchType.Delete:\n dispatchPopAction();\n if (insertPosition === 0) return;\n setGuess(\n guess.slice(0, insertPosition - 1) + guess.slice(insertPosition)\n );\n setInsertPosition(insertPosition - 1);\n break;\n case DispatchType.Add:\n setGuess(\n guess.slice(0, insertPosition) +\n appState.pendingAction.letter +\n guess.slice(insertPosition)\n );\n setInsertPosition(insertPosition + 1);\n dispatchPopAction();\n break;\n case DispatchType.Clear:\n setGuess(\"\");\n setInsertPosition(0);\n dispatchPopAction();\n break;\n }\n });\n\n return (\n \n {\n setGuess(\"\");\n setInsertPosition(0);\n }}\n >\n \n \n \n ),\n }}\n value={guess + (isMobile ? \"|\" : \"\")}\n onChange={(event) => {\n let newGuess = event.target.value;\n if (newGuess.length > 10) return;\n if (isMobile) newGuess = newGuess.substring(0, newGuess.length - 1);\n const badLetter = [...newGuess].find((letter) => {\n if (\"1234567890\".indexOf(letter) >= 0) return false;\n return letter;\n });\n if (badLetter === undefined) {\n setGuess(newGuess);\n setInsertPosition(event.target.selectionStart);\n } else {\n setInsertPosition(event.target.selectionStart - 1);\n }\n }}\n />\n );\n};\n","import { Box } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { InputButtonComponent } from \"./InputButtonComponent\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport { RowContainer } from \"../../../components/RowContainer\";\n\nexport interface KeypadComponentProps {\n onClick: (digit: string) => void;\n}\nexport const KeypadComponent = (props: KeypadComponentProps) => {\n const { onClick } = props;\n return (\n \n \n {[7, 8, 9].map((digit) => {\n return (\n \n {\n onClick(digit.toString());\n }}\n letter={digit.toString()}\n isRequired={false}\n />\n \n );\n })}\n \n \n {[4, 5, 6].map((digit) => {\n return (\n \n {\n onClick(digit.toString());\n }}\n letter={digit.toString()}\n isRequired={false}\n />\n \n );\n })}\n \n \n {[1, 2, 3].map((digit) => {\n return (\n \n {\n onClick(digit.toString());\n }}\n letter={digit.toString()}\n isRequired={false}\n />\n \n );\n })}\n \n \n {[0].map((digit) => {\n return (\n \n {\n onClick(digit.toString());\n }}\n letter={digit.toString()}\n isRequired={false}\n />\n \n );\n })}\n \n \n );\n};\n","import { Box } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { getLevelFromScore, Level } from \"../../../domain/types\";\n\nconst logoBlue = \"#0055aa\";\nconst logoYellow = \"#FFCB05\";\n\nconst vw = 400;\nconst vh = 60;\nconst achievedColor = logoBlue;\nconst highestAchievedColor = logoYellow;\nconst unachievedColor = \"black\"; //\"#9a9ea1\";\nconst rungRadius = 5;\nconst progressMarkRadius = rungRadius + 2;\nconst ladderLength = vw - 2 * rungRadius;\nconst ladderX = rungRadius;\nconst ladderY = progressMarkRadius;\n\nexport interface ProgressComponentProps {\n levels: Level[];\n score: number;\n}\nexport const ProgressComponent = (props: ProgressComponentProps) => {\n const levels = props.levels;\n const score = props.score ?? 0;\n\n const [newKey, setNewKey] = useState(0);\n const [levelName, setLevelName] = useState(\"\");\n const levelNameFromScore = getLevelFromScore(levels, score).name;\n const highestLevelScore = levels[levels.length - 1].score;\n const progressMarkerX = ladderX + (score / highestLevelScore) * ladderLength;\n const isLevelChanged = levelNameFromScore !== levelName;\n if (isLevelChanged) setNewKey(newKey + 1);\n const animatedLevelName = isLevelChanged ? null : (\n \n \n \n {(() => {\n // Generate a mark for each level\n const levelCount = levels.length;\n return levels.map((level, index) => {\n let color = unachievedColor;\n const achieved = score >= level.score;\n if (achieved) {\n if (index === levelCount - 1 || levels[index + 1].score > score) {\n color = highestAchievedColor;\n } else {\n color = achievedColor;\n }\n }\n return (\n \n );\n });\n })()}\n \n \n {getLevelFromScore(levels, score).name}\n \n \n \n \n \n );\n\n if (isLevelChanged) setLevelName(levelNameFromScore);\n return animatedLevelName;\n};\n","import { Box, Button, Typography } from \"@material-ui/core\";\nimport { createStyles, makeStyles } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport { useContext, useEffect, useReducer, useRef, useState } from \"react\";\nimport {\n PrimaryButton,\n StrongGuidingButton,\n} from \"../../../components/buttons\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport Hider from \"../../../components/Hider\";\nimport { openJustOkDialog } from \"../../../components/JustOkDialog\";\nimport {\n notifyErrorTransient,\n notifySuccessTransient,\n} from \"../../../components/NotificationManager\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport {\n Challenge,\n Chaser,\n ComputePlaySpec,\n ComputeProgress,\n createAllChallenges,\n solve,\n getOpChar,\n} from \"../../../domain/compute_types\";\nimport { getLevelFromScore, Level } from \"../../../domain/types\";\nimport { useFreshState } from \"../../../hooks/useFreshState\";\nimport { max, pluralize, sum } from \"../../../utilities\";\nimport { shareProgress } from \"../../play/components/ShareProgressComponent\";\nimport {\n RulesContext,\n ShareProgressContext,\n} from \"../../play/components/TopAppBarComponent\";\nimport {\n clearLocalStorageForGame,\n storeProgressLocally,\n} from \"../../play/localStorage\";\nimport { ComputeRulesComponent } from \"./ComputeRulesComponent\";\nimport { GuessNumberInputComponent } from \"./GuessNumberInputComponent\";\nimport { KeypadComponent } from \"../../play/components/KeypadComponent\";\nimport { ProgressComponent } from \"../../play/components/ProgressComponent\";\n\nconst useStyles = makeStyles(() => {\n return createStyles({\n statusCell: {\n padding: \"5px\",\n backgroundColor: \"lightgray\",\n minWidth: \"12rem\",\n margin: \"4px 0 4px 0\",\n },\n });\n});\n\nconst smile = \"\\u{1F600}\";\n\nexport enum DispatchType {\n Add,\n Delete,\n Clear,\n Pop,\n}\n\nexport interface Action {\n type: DispatchType;\n letter?: string;\n}\n\nexport interface AppState {\n pendingAction: Action | undefined;\n}\n\nconst initialAppState: AppState = { pendingAction: undefined };\n\nfunction reducer(_state: AppState, action: Action): AppState {\n switch (action.type) {\n case DispatchType.Add:\n return { pendingAction: action };\n case DispatchType.Delete:\n return { pendingAction: action };\n case DispatchType.Clear:\n return { pendingAction: action };\n case DispatchType.Pop:\n return initialAppState;\n default:\n throw new Error();\n }\n}\n\nexport interface ComputeGameComponentProps {\n gameRef: string;\n playSpec: ComputePlaySpec;\n progress: ComputeProgress;\n setCurrentProgress: (getProgress: () => ComputeProgress) => void;\n}\n\nexport interface GameInfo {\n maxPoints: number;\n highestLevel: Level;\n}\n\ninterface InteractiveGameState {\n gameRef: string;\n progress: ComputeProgress;\n currentGuess: string;\n}\n\nconst makeStateFromProps = (\n props: ComputeGameComponentProps\n): InteractiveGameState => {\n return {\n progress: props.progress ?? {\n chasers: [],\n elapsedSeconds: props.progress?.elapsedSeconds ?? 0,\n },\n gameRef: props.gameRef,\n currentGuess: \"\",\n };\n};\n\nexport const ComputeGameComponent = (props: ComputeGameComponentProps) => {\n const [appState, dispatch] = useReducer(reducer, initialAppState);\n const [gameState, setGameState] = useFreshState(() =>\n makeStateFromProps(props)\n );\n const [firstTime, setFirstTime] = useState(true);\n // When starting is true, we display the start button\n const [starting, setStarting] = useState(true);\n const [finished, setFinished] = useFreshState(() => false);\n const [challengeCounter, setChallengeCounter] = useState(\n props.progress?.chasers?.length ?? 0\n );\n const [startingElapsedTime, setStartingElapsedTime] = useFreshState(\n () => props.progress?.elapsedSeconds ?? 0\n );\n const [elapsedIntervals, setElapsedIntervals] = useFreshState(() => 0);\n const elapsedTime = () => startingElapsedTime() + elapsedIntervals();\n\n // start time is now in case the game is mid-stream, in which case the user plays without clicking start\n const startTimeRef = useRef(Date.now());\n const intervalIdRef = useRef(undefined);\n const [currentChallenge, setCurrentChallenge] = useState(\n undefined\n );\n const classes = useStyles();\n\n useEffect(() => {\n const f =\n (props.playSpec.timeLimit > 0 &&\n elapsedTime() >= props.playSpec.timeLimit) ||\n props.playSpec.challengeCount === gameState().progress.chasers.length;\n if (f != finished()) setFinished(f);\n });\n\n props.setCurrentProgress(() => gameState().progress);\n const [gameInfo] = useState(\n (): GameInfo => {\n return {\n maxPoints: props.playSpec.challengeCount,\n highestLevel: props.playSpec.levels[props.playSpec.levels.length - 1],\n };\n }\n );\n\n // The first time through compile the operand ranges and create a list of challenges.\n // The challenges will then be selected at random.\n const challengesRef = useRef(createAllChallenges(props.playSpec));\n\n // Get a new challenge each time the challengeCounter changes.\n useEffect(() => {\n const i = Math.floor(\n Math.random() * Math.floor(challengesRef.current.length)\n );\n setCurrentChallenge(challengesRef.current[i]);\n if (props.playSpec.challengeCount <= challengesRef.current.length) {\n // Remove played challenges as long as there are more challenges in the hopper than\n // challenges per game. This comparision will not change during each game.\n challengesRef.current.splice(i, 1);\n }\n }, [challengeCounter, starting]);\n\n const displayRules = () => {\n openJustOkDialog({\n content: (\n \n ),\n title: \"Rules\",\n });\n };\n\n useEffect(() => {\n if (challengeCounter === 0) displayRules();\n }, []);\n\n useContext(ShareProgressContext)(() =>\n shareProgress(gameState().gameRef, gameState().progress)\n );\n\n useContext(RulesContext)(displayRules);\n\n useEffect(() => {\n // Save state to local storage\n // Only when the correct answers have changed\n // Don't write the first time, because we already either read or wrote the state\n if (firstTime) {\n setFirstTime(false);\n return;\n }\n storeProgressLocally(\n gameState().gameRef,\n (data) => {\n data.progress = gameState().progress;\n data.unmodified = false;\n },\n false // means not updated shared progress\n );\n }, [gameState().progress]);\n\n const [score, setScore] = useState(0);\n useEffect(() => {\n // Update score when answers changes\n const score = sum(\n gameState().progress.chasers.map((chaser) =>\n solve(chaser.challenge) === chaser.answer ? 1 : 0\n )\n );\n setScore(score);\n }, [gameState().progress.chasers]);\n\n const [level, setLevel] = useState(props.playSpec.levels[0]);\n\n const submitHandler = () => {\n if (gameState().currentGuess === \"\") return;\n if (finished()) {\n notifySuccessTransient(`The game is finished.`);\n return;\n }\n const answer = Number(gameState().currentGuess);\n const isCorrect = answer === solve(currentChallenge);\n if (isCorrect) {\n notifySuccessTransient(`Correct! ${smile}`);\n } else {\n notifyErrorTransient(`${gameState().currentGuess} is not correct`);\n if (props.playSpec.mustSolve) {\n dispatch({ type: DispatchType.Clear });\n return;\n }\n }\n const chaser: Chaser = {\n answer,\n challenge: currentChallenge,\n skipped: false,\n };\n const newGameState = {\n ...gameState(),\n currentGuess: \"\",\n progress: {\n chasers: [...gameState().progress.chasers, chaser],\n elapsedSeconds: elapsedTime(),\n },\n };\n setGameState(newGameState);\n dispatch({ type: DispatchType.Clear });\n\n const nextLevel = getLevelFromScore(props.playSpec.levels, score + 1);\n const isNewLevel = nextLevel.score !== level.score;\n if (isNewLevel) {\n // openJustOkDialog({content: achievementLevelElement, title: \"Congrats!\"})\n //setShowAchievementLevel(true); //********************************************\n }\n\n setLevel(nextLevel);\n setChallengeCounter(challengeCounter + 1);\n };\n\n const keyUpHandler = (event: KeyboardEvent) => {\n if (event.keyCode === 13) {\n //Enter key starts, but once started it submits answers.\n if (starting) {\n startResume();\n return;\n }\n submitHandler();\n }\n };\n\n useEffect(() => {\n document.addEventListener(\"keyup\", keyUpHandler, false);\n return () => {\n document.removeEventListener(\"keyup\", keyUpHandler, false);\n };\n });\n\n const startResume = () => {\n startTimeRef.current = Date.now();\n setStarting(false);\n intervalIdRef.current = setInterval(() => {\n if (finished()) return;\n const elapsedSeconds = Math.round(\n (Date.now() - startTimeRef.current) / 1000\n );\n setElapsedIntervals(elapsedSeconds);\n const gs: InteractiveGameState = {\n currentGuess: gameState().currentGuess,\n gameRef: gameState().gameRef,\n progress: {\n chasers: gameState().progress.chasers,\n elapsedSeconds: elapsedTime(),\n },\n };\n setGameState(gs);\n }, 1000);\n };\n\n return (\n \n \n {props.playSpec.title}\n {props.playSpec.subtitle}\n \n {starting && !finished() && (\n \n {challengeCounter === 0 && elapsedTime() === 0\n ? \"Click to Start\"\n : \"Click to Resume\"}\n \n )}\n \n {!starting && (\n \n \n \n \n )}\n \n \n
    {props.playSpec.challengeCount - challengeCounter}
    \n
    Challenges Remaining
    \n
    \n {(props.playSpec.timeLimit ?? 0) === 0 && (\n \n
    {elapsedTime()}
    \n
    Elapsed Time
    \n
    \n )}\n {(props.playSpec.timeLimit ?? 0) > 0 && (\n \n
    \n {max([0, props.playSpec.timeLimit - elapsedTime()])}\n {\" sec\"}\n
    \n
    Time Remaining
    \n
    \n )}\n
    \n \n
    \n You have {pluralize(score, \"correct answer\")} for{\" \"}\n {pluralize(score, \"point\")}\n
    \n \n {gameState()\n .progress.chasers.filter(\n (chaser) => solve(chaser.challenge) === chaser.answer\n )\n .map((chaser, i) => {\n return (\n
    \n {chaser.challenge.lhs}\n {getOpChar(chaser.challenge.op)}\n {chaser.challenge.rhs}={chaser.answer}\n
    \n );\n })}\n
    \n \n {\n clearLocalStorageForGame();\n if (intervalIdRef.current) clearInterval(intervalIdRef.current);\n intervalIdRef.current = undefined;\n setGameState({\n ...makeStateFromProps(props),\n progress: { chasers: [], elapsedSeconds: 0 },\n });\n setStarting(true);\n setFinished(false);\n setChallengeCounter(0);\n setCurrentChallenge(undefined);\n setStartingElapsedTime(0);\n setElapsedIntervals(0);\n }}\n >\n Play Again\n \n
    \n
    \n );\n};\n","import { Button } from \"@material-ui/core\";\nimport { createStyles, makeStyles } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme) => {\n return createStyles({\n cell: {\n margin: \"4px 4px 4px 4px\",\n textTransform: \"none\",\n height: \"2rem\",\n },\n letter: {\n height: theme.typography.button.lineHeight + \"rem\",\n },\n });\n});\nexport interface GuessDisplayComponentProps {\n letter: string;\n isMutable: boolean;\n}\n\nconst Div = React.forwardRef((props, ref) => (\n
    {props.children}
    \n));\n\n// InputButtonComponent presents a button in a custom keyboard.\nexport const GuessDisplayComponent = (props: GuessDisplayComponentProps) => {\n const classes = useStyles();\n const { isMutable, letter } = props;\n return (\n \n \n
    {letter ?? \"\"}
    \n \n \n );\n};\n","import { Button } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { createStyles, makeStyles } from \"@material-ui/core/styles\";\nconst useStyles = makeStyles(() => {\n return createStyles({\n cell: {\n margin: \"4px 4px 4px 4px\",\n textTransform: \"none\",\n height: \"2rem\",\n },\n });\n});\nexport interface GuessInputButtonComponentProps {\n letter: string;\n isAvailable: boolean;\n onClick: () => void;\n}\n\n// InputButtonComponent presents a button in a custom keyboard.\nexport const GuessInputButtonComponent = (\n props: GuessInputButtonComponentProps\n) => {\n const classes = useStyles();\n const { isAvailable, letter, onClick } = props;\n return (\n {\n onClick();\n }}\n >\n \n
    {letter}
    \n \n \n );\n};\n","import { Divider } from \"@material-ui/core\";\nimport { createStyles, makeStyles } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { SecondaryButton } from \"../../../components/buttons\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport { Challenge } from \"../../../domain/twist_types\";\nimport { GuessDisplayComponent } from \"./GuessDisplayComponent\";\nimport { GuessInputButtonComponent } from \"./GuessInputButtonComponent\";\n\nconst useStyles = makeStyles((theme) => {\n return createStyles({\n letterContainers: {\n flexWrap: \"wrap\",\n },\n cursor: {\n color: theme.palette.primary.main,\n fontSize: \"200%\",\n animation: \"$blinker 1.5s linear infinite\",\n },\n \"@keyframes blinker\": {\n \"50%\": {\n opacity: 0,\n },\n },\n });\n});\n\nconst Cursor = (props: { visible: boolean }) => {\n return (\n \n |\n \n );\n};\n\nexport interface Slot {\n // fixedLetter is undefined if slot is mutable\n fixedLetter: string;\n token: Token; // current content; disregard if not mutable\n}\n\nexport interface Token {\n // index is the token's position in the fill-in array\n index: number;\n isAvailable: boolean;\n letter: string;\n}\n\nexport interface GuessInputComponentProps {\n onSubmit: (guess: string) => void;\n challenge: Challenge;\n caseSensitive: boolean;\n}\nexport const GuessInputComponent = (props: GuessInputComponentProps) => {\n const { challenge } = props;\n\n const firstMutableSlotIndexRef = useRef(-1);\n const lastMutableSlotIndexRef = useRef(-1);\n const slotCursorPosRef = useRef(-1);\n\n const slotsRef = useRef(null);\n const tokensRef = useRef(null);\n const challengeRef = useRef(null);\n if (challenge !== challengeRef.current) {\n // There's a new challenge. Bust the refs!\n slotsRef.current = null;\n tokensRef.current = null;\n firstMutableSlotIndexRef.current = [...challenge.fixed].findIndex(\n (letter) => letter === \"*\"\n );\n lastMutableSlotIndexRef.current =\n challenge.solution.length -\n 1 -\n [...challenge.fixed].reverse().findIndex((letter) => letter === \"*\");\n slotCursorPosRef.current = firstMutableSlotIndexRef.current;\n challengeRef.current = challenge;\n }\n const firstMutableSlotIndex = firstMutableSlotIndexRef.current;\n const lastMutableSlotIndex = lastMutableSlotIndexRef.current;\n const slotCursorPos = slotCursorPosRef.current;\n\n const initSlots = (): Slot[] =>\n [...challenge.fixed].map((letter, index) =>\n letter === \"*\"\n ? { fixedLetter: undefined, token: undefined }\n : { fixedLetter: letter, token: undefined }\n );\n const getSlots = () => {\n if (slotsRef.current === null) {\n slotsRef.current = initSlots();\n }\n return slotsRef.current;\n };\n const slots = getSlots();\n\n const initTokens = (): Token[] =>\n [...challenge.fillin].map((letter, index) => {\n return { isAvailable: true, letter, index };\n });\n const getTokens = () => {\n if (tokensRef.current === null) {\n tokensRef.current = initTokens();\n }\n return tokensRef.current;\n };\n const tokens = getTokens();\n\n // currentGuess will be too short unless mutable slots are filled\n const computeGuess = () =>\n slots\n .map((slot) =>\n slot.fixedLetter ? slot.fixedLetter : slot.token?.letter ?? \"\"\n )\n .join(\"\");\n const [currentGuess, setCurrentGuess] = useState(computeGuess);\n\n useEffect(() => {\n setCurrentGuess(computeGuess());\n }, [challenge.solution]);\n\n // getNextCursorPosition gets next cur pos to right\n const getNextCursorPosition = () => {\n let nextCursorPosition = slots.findIndex(\n (slot, index) => slot.fixedLetter == null && index > slotCursorPos\n );\n return nextCursorPosition >= 0\n ? nextCursorPosition\n : lastMutableSlotIndex + 1;\n };\n\n // getPrevCursorPosition gets next cur pos to left -- or returns same pos if nothing to left\n const getPrevCursorPosition = () => {\n for (let i = slotCursorPos - 1; i >= firstMutableSlotIndex; i--) {\n if (slots[i].fixedLetter == null) return i;\n }\n return slotCursorPos;\n };\n\n const insertTokenAtCursor = (token: Token) => {\n if (slotCursorPos > lastMutableSlotIndex) return;\n if (!token.isAvailable) throw new Error(\"token not available\");\n const slot = slots[slotCursorPos];\n if (slot.token != null) throw new Error(\"slot already filled\");\n token.isAvailable = false;\n slot.token = token;\n const nextCursorPosition = getNextCursorPosition();\n if (nextCursorPosition !== slotCursorPos) {\n slotCursorPosRef.current = nextCursorPosition;\n }\n setCurrentGuess(computeGuess());\n };\n\n const deleteTokenLeftOfCursor = () => {\n if (slotCursorPos === firstMutableSlotIndex) return;\n const nextCursorPosition = getPrevCursorPosition();\n const deleteSlot = slots[nextCursorPosition];\n const deleteToken = deleteSlot.token;\n deleteToken.isAvailable = true;\n deleteSlot.token = undefined;\n slotCursorPosRef.current = nextCursorPosition;\n setCurrentGuess(computeGuess());\n };\n\n const keyDownHandler = (event: KeyboardEvent) => {\n switch (event.key) {\n case \"Backspace\":\n case \"Delete\":\n deleteTokenLeftOfCursor();\n break;\n case \"Enter\":\n props.onSubmit(computeGuess());\n break;\n default:\n let token: Token;\n if (props.caseSensitive) {\n token = tokens.find(\n (token) => token.isAvailable && token.letter === event.key\n );\n } else {\n token = tokens.find(\n (token) =>\n token.isAvailable &&\n token.letter.toLowerCase() === event.key.toLowerCase()\n );\n }\n if (token) insertTokenAtCursor(token);\n break;\n }\n };\n\n useEffect(() => {\n document.addEventListener(\"keydown\", keyDownHandler, false);\n return () => {\n document.removeEventListener(\"keydown\", keyDownHandler, false);\n };\n });\n\n return (\n \n \n {slots.map((slot, i) => {\n return (\n \n \n \n \n \n );\n })}\n \n {challenge.clue}\n \n \n {tokens.map((token, i) => {\n return (\n {\n token.isAvailable && insertTokenAtCursor(token);\n }}\n />\n );\n })}\n \n \n {\n deleteTokenLeftOfCursor();\n }}\n >\n Delete\n \n {\n props.onSubmit(computeGuess());\n }}\n >\n Submit\n \n \n \n );\n};\n","import { Box, Container } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { TwistPlaySpec } from \"../../../domain/twist_types\";\nimport { pluralize } from \"../../../utilities\";\nimport { GameInfo } from \"./TwistGameComponent\";\n\nexport interface TwistRulesComponentProps {\n playSpec: TwistPlaySpec;\n gameInfo: GameInfo;\n}\nexport const TwistRulesComponent = (props: TwistRulesComponentProps) => {\n const { playSpec, gameInfo } = props;\n const rulesPrologue = playSpec.rulesPrologue;\n const rulesPrologueComponent = !rulesPrologue ? null : (\n {rulesPrologue}\n );\n const challengeCount = playSpec.challenges?.length ?? 0;\n const extraLetterChallengeCount = playSpec.challenges.filter(\n (challenge) =>\n challenge.fillin.length >\n challenge.fixed.split(\"\").filter((letter) => letter === \"*\").length\n ).length;\n return (\n \n {rulesPrologueComponent}\n \n \n

    The following rules apply to this game:

    \n
      \n
    • \n Fill in the missing letters in the top row, using the letters in the\n bottom row.\n
    • \n
    • \n The solutions are{playSpec.caseSensitive ? \" \" : \" not \"}\n case-sensitive.\n
    • \n
    • \n {`The game has ${pluralize(\n challengeCount,\n \"challenge\"\n )} worth a total of ${pluralize(challengeCount, \"point\")}.`}\n {gameInfo.highestLevel.score >= gameInfo.maxPoints\n ? \"\"\n : \" You don't need to solve all of the challenges to achieve the top level.\"}\n
    • \n
    • \n Click a letter in the bottom row to use that letter in the top row.\n Each letter in the bottom row can be used no more than once.\n
    • \n {extraLetterChallengeCount === challengeCount && (\n
    • \n All challenges have extra letters, meaning some letters are not\n used in the solution.\n
    • \n )}\n {extraLetterChallengeCount > 0 &&\n extraLetterChallengeCount < challengeCount && (\n
    • \n {pluralize(extraLetterChallengeCount, \"challenge \")}\n {extraLetterChallengeCount === 1 ? \"has\" : \"have\"} extra\n letters, meaning some letters are not used in the solution.\n
    • \n )}\n
    • The game is over after you have solved all of the challenges.
    • \n
    \n
    \n \n \n The game levels and the number of points needed to reach each level are:{\" \"}\n {props.playSpec.levels.map((level, index) => (\n \n {index > 0 ? \", \" : \"\"}\n {level.name} {level.score}\n \n ))}\n .\n \n \n \n );\n};\n","import { Box, Typography } from \"@material-ui/core\";\nimport { createStyles, makeStyles } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport { useContext, useEffect, useReducer, useState } from \"react\";\nimport { SecondaryButton } from \"../../../components/buttons\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport Hider from \"../../../components/Hider\";\nimport { openJustOkDialog } from \"../../../components/JustOkDialog\";\nimport {\n notifyErrorTransient,\n notifySuccessTransient,\n} from \"../../../components/NotificationManager\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport {\n Challenge,\n TwistPlaySpec,\n TwistProgress,\n} from \"../../../domain/twist_types\";\nimport { getLevelFromScore, Level } from \"../../../domain/types\";\nimport { useFreshState } from \"../../../hooks/useFreshState\";\nimport { pluralize } from \"../../../utilities\";\nimport { ProgressComponent } from \"../../play/components/ProgressComponent\";\nimport { shareProgress } from \"../../play/components/ShareProgressComponent\";\nimport {\n RulesContext,\n ShareProgressContext,\n} from \"../../play/components/TopAppBarComponent\";\nimport { storeProgressLocally } from \"../../play/localStorage\";\nimport { GuessInputComponent } from \"./GuessInputComponent\";\nimport { TwistRulesComponent } from \"./TwistRulesComponent\";\n\nconst useStyles = makeStyles(() => {\n return createStyles({\n statusCell: {\n padding: \"5px\",\n backgroundColor: \"lightgray\",\n minWidth: \"12rem\",\n margin: \"4px 0 4px 0\",\n },\n });\n});\n\nconst smile = \"\\u{1F600}\";\n\nexport enum DispatchType {\n Add,\n Delete,\n Clear,\n Pop,\n}\n\nexport interface Action {\n type: DispatchType;\n letter?: string;\n}\n\nexport interface AppState {\n pendingAction: Action | undefined;\n}\n\nconst initialAppState: AppState = { pendingAction: undefined };\n\nfunction reducer(_state: AppState, action: Action): AppState {\n switch (action.type) {\n case DispatchType.Add:\n return { pendingAction: action };\n case DispatchType.Delete:\n return { pendingAction: action };\n case DispatchType.Clear:\n return { pendingAction: action };\n case DispatchType.Pop:\n return initialAppState;\n default:\n throw new Error();\n }\n}\n\nexport interface TwistGameComponentProps {\n gameRef: string;\n playSpec: TwistPlaySpec;\n progress: TwistProgress;\n setCurrentProgress: (getProgress: () => TwistProgress) => void;\n}\n\nexport interface GameInfo {\n maxPoints: number;\n highestLevel: Level;\n}\n\ninterface InteractiveGameState {\n gameRef: string;\n progress: TwistProgress;\n currentGuess: string;\n}\n\nconst makeStateFromProps = (\n props: TwistGameComponentProps\n): InteractiveGameState => {\n return {\n progress: props.progress ?? {\n words: [],\n },\n gameRef: props.gameRef,\n currentGuess: \"\",\n };\n};\n\nexport const TwistGameComponent = (props: TwistGameComponentProps) => {\n const [appState, dispatch] = useReducer(reducer, initialAppState);\n const [gameState, setGameState] = useFreshState(() =>\n makeStateFromProps(props)\n );\n const [firstTime, setFirstTime] = useState(true);\n // When starting is true, we display the start button\n const [finished, setFinished] = useFreshState(() => false);\n\n const [currentChallenge, setCurrentChallenge] = useState(\n undefined\n );\n const classes = useStyles();\n\n props.setCurrentProgress(() => gameState().progress);\n const [gameInfo] = useState(\n (): GameInfo => {\n return {\n maxPoints: props.playSpec.challenges.length,\n highestLevel: props.playSpec.levels[props.playSpec.levels.length - 1],\n };\n }\n );\n\n useEffect(() => {\n // Sets up first challenge.\n setNextChallenge();\n }, []);\n const setNextChallenge = () => {\n // Find the next unsolved challenge after the current challenge.\n // Save the first unsolved challenge in case the player skipped a challenge.\n const currentChallengeIndex =\n currentChallenge == null\n ? -1\n : props.playSpec.challenges.findIndex(\n (c) => c.solution === currentChallenge.solution\n );\n let firstUnsolvedChallenge: Challenge = undefined;\n let nextChallenge: Challenge = undefined;\n for (let i = 0; i < props.playSpec.challenges.length; i++) {\n const thisChallenge = props.playSpec.challenges[i];\n const solved =\n gameState().progress.words.includes(thisChallenge.solution) ?? false;\n if (firstUnsolvedChallenge === undefined && !solved) {\n firstUnsolvedChallenge = thisChallenge;\n }\n if (!solved && i > currentChallengeIndex) {\n nextChallenge = thisChallenge;\n break;\n }\n }\n nextChallenge = nextChallenge ?? firstUnsolvedChallenge;\n if (nextChallenge == null) {\n setFinished(true);\n }\n setCurrentChallenge(nextChallenge);\n };\n\n // // Get a new challenge each time the challengeCounter changes.\n // useEffect(() => {\n // setNextChallenge();\n // }, [challengeCounter, starting]);\n\n const remainingChallengeCount =\n props.playSpec.challenges.length - gameState().progress.words.length;\n\n const displayRules = () => {\n openJustOkDialog({\n content: (\n \n ),\n title: \"Rules\",\n });\n };\n\n useEffect(() => {\n if (currentChallenge === undefined && !finished()) displayRules();\n }, []);\n\n useContext(ShareProgressContext)(() =>\n shareProgress(gameState().gameRef, gameState().progress)\n );\n\n useContext(RulesContext)(displayRules);\n\n useEffect(() => {\n // Save state to local storage\n // Only when the correct answers have changed\n // Don't write the first time, because we already either read or wrote the state\n if (firstTime) {\n setFirstTime(false);\n return;\n }\n storeProgressLocally(\n gameState().gameRef,\n (data) => {\n data.progress = gameState().progress;\n data.unmodified = false;\n },\n false // means not updated shared progress\n );\n }, [gameState().progress]);\n\n const [score, setScore] = useState(0);\n useEffect(() => {\n // Update score when answers changes\n const score = gameState().progress.words.length;\n setScore(score);\n }, [gameState().progress.words]);\n\n const [level, setLevel] = useState(props.playSpec.levels[0]);\n\n const submitHandler = (guess: string) => {\n if (guess === \"\") return;\n if (finished()) {\n notifySuccessTransient(\"The game is finished.\");\n return;\n }\n const isCorrect = props.playSpec.caseSensitive\n ? currentChallenge.solution === guess\n : currentChallenge.solution.toLowerCase() === guess.toLowerCase();\n if (isCorrect) {\n notifySuccessTransient(`Correct! ${smile}`);\n } else {\n notifyErrorTransient(`${guess} is not correct`);\n return;\n }\n const newGameState = {\n ...gameState(),\n currentGuess: \"\",\n progress: {\n words: [...gameState().progress.words, currentChallenge.solution],\n },\n };\n setGameState(newGameState);\n dispatch({ type: DispatchType.Clear });\n\n const nextLevel = getLevelFromScore(props.playSpec.levels, score + 1);\n const isNewLevel = nextLevel.score !== level.score;\n if (isNewLevel) {\n // openJustOkDialog({content: achievementLevelElement, title: \"Congrats!\"})\n //setShowAchievementLevel(true); //********************************************\n }\n\n setLevel(nextLevel);\n setNextChallenge();\n };\n\n return (\n \n \n {props.playSpec.title}\n {props.playSpec.subtitle}\n \n \n\n \n \n\n \n
    {remainingChallengeCount}
    \n
    Challenges Remaining
    \n
    \n\n \n
    \n You have {pluralize(score, \"correct answer\")} for{\" \"}\n {pluralize(score, \"point\")}\n
    \n \n {gameState().progress.words.map((word, i) => {\n return (\n
    \n {word}\n
    \n );\n })}\n
    \n
    \n
    \n );\n};\n","import { TextField } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../components/dialogTools/DialogManager\";\nimport Hider from \"../../../components/Hider\";\nimport { JustOkDialog } from \"../../../components/JustOkDialog\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport { Challenge } from \"../../../domain/twist_types\";\nimport { FmTextField } from \"../../../formManager/FmField\";\n\nexport interface AnswersDialogProps {\n answerKey: string;\n answers: { words: string[] };\n solutions: Challenge[];\n}\n\nlet answersDialogInternal: Dialog;\n\nexport const openTwistAnswersDialog = (props: AnswersDialogProps) => {\n if (!answersDialogInternal) {\n answersDialogInternal = makeTwistAnswersDialogComponent();\n }\n return getDialogMethods().open(answersDialogInternal, props);\n};\n\nexport const makeTwistAnswersDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const [answerKey, setAnswerKey] = useState(\"\");\n const props = dialogRenderProps.props;\n const propsAnswerKey = props.answerKey?.toLowerCase();\n const foundAll = props.solutions.length === props.answers.words.length;\n return (\n {\n dialogRenderProps.close(true);\n }}\n open={true}\n title={\"Answers\"}\n >\n \n \n \n \n \n );\n },\n });\n};\n\nconst AnswerItem = (word: string) => {\n return (\n
    \n \n {word}\n \n
    \n );\n};\n","import {\n AppBar,\n Button,\n createStyles,\n Grid,\n makeStyles,\n Theme,\n Toolbar,\n} from \"@material-ui/core\";\nimport { Copyright } from \"@material-ui/icons\";\nimport * as React from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { openJustOkDialog } from \"../../../components/JustOkDialog\";\nimport { CommonSnackbar } from \"../../../components/dialogTools/snackbars\";\nimport { PlaySpec } from \"../../../domain/types\";\nimport { useClientRect } from \"../../../measure\";\nimport { Answer } from \"../../author/games/spell/spellTypes\";\nimport { openSpellAnswersDialog } from \"../../spell/components/SpellAnswers\";\nimport { SpellGameComponent } from \"../../spell/components/SpellGameComponent\";\nimport { SpellPlaySpec, SpellProgress } from \"../../spell/spell_types\";\nimport {\n localStorageAvailable,\n readStateFromLocalStorage,\n storeProgressLocally,\n} from \"../localStorage\";\nimport { PlayPrivacy } from \"../PlayPrivacy\";\nimport { PlayTerms } from \"../PlayTerms\";\nimport { getGame, GetGameResponse } from \"../requests/getGame\";\nimport { getGameRefFromLocation } from \"../url\";\nimport { getGameType } from \"../globalPlayData\";\nimport { ComputeGameComponent } from \"../../compute/components/ComputeGameComponent\";\nimport {\n ComputePlaySpec,\n ComputeProgress,\n} from \"../../../domain/compute_types\";\nimport { TopAppBarComponent } from \"./TopAppBarComponent\";\nimport { TwistGameComponent } from \"../../twist/components/TwistGameComponent\";\nimport {\n TwistPlaySpec,\n TwistProgress,\n Challenge,\n} from \"../../../domain/twist_types\";\nimport { openTwistAnswersDialog } from \"../../twist/components/TwistAnswers\";\n\nconst getGameFromGamePath = async (): Promise => {\n const gameRef = getGameRefFromLocation();\n let progress: unknown;\n let isFirstPlay = true;\n if (localStorageAvailable()) {\n try {\n const storedGameState = readStateFromLocalStorage(gameRef);\n if (storedGameState !== null && storedGameState.gameRef === gameRef) {\n progress = storedGameState.progress;\n isFirstPlay = false;\n }\n } catch (_e) {} // fall through to get from server\n }\n try {\n // If we already have gameProgress, then we don't need to ask for it\n let persistentStorageGameState = await getGame(\n gameRef,\n progress == undefined,\n isFirstPlay\n );\n // Use local progress if we have it\n if (progress) {\n persistentStorageGameState = {\n ...persistentStorageGameState,\n progress,\n };\n }\n storeProgressLocally(\n gameRef,\n (data) => {\n if (!progress) data.progress = persistentStorageGameState.progress;\n data.unmodified = true;\n },\n false // means not updated shared progress\n );\n return persistentStorageGameState;\n } catch (e) {\n throw new Error(e);\n }\n};\n\nconst useStyles = makeStyles((_theme: Theme) =>\n createStyles({\n bottomAppBar: {\n top: \"auto\",\n bottom: 0,\n },\n })\n);\n\ninterface GamePageComponentProps {}\nexport const GamePageComponent = (props: GamePageComponentProps) => {\n const [gameState, setGameState] = useState<{\n playSpec: PlaySpec;\n progress: unknown;\n }>();\n const [gameRef, setGameRef] = useState();\n const [errorMessage, setErrorMessage] = useState(undefined as string);\n // Run only if any props change\n useEffect(() => {\n setGameRef(getGameRefFromLocation());\n const asyncFunc = async () => {\n try {\n const storableGameState = await getGameFromGamePath();\n setGameState({\n playSpec: storableGameState.playSpec,\n progress: storableGameState.progress,\n });\n } catch (e) {\n setErrorMessage(e.message);\n }\n };\n asyncFunc();\n }, [props]);\n\n const classes = useStyles();\n\n const snackBar =\n errorMessage == null ? null : (\n setErrorMessage(undefined)}\n />\n );\n const dataPresent = gameState !== undefined;\n\n const getProgressRef = useRef<() => unknown>();\n\n let gameComponent: JSX.Element = null;\n\n if (dataPresent) {\n switch (getGameType()) {\n case \"s\":\n gameComponent = (\n unknown) => {\n getProgressRef.current = getProgress;\n }}\n />\n );\n break;\n case \"c\":\n gameComponent = (\n unknown) => {\n getProgressRef.current = getProgress;\n }}\n />\n );\n break;\n case \"t\":\n gameComponent = (\n unknown) => {\n getProgressRef.current = getProgress;\n }}\n />\n );\n break;\n }\n }\n const [rect, ref] = useClientRect();\n return (\n <>\n {\n switch (getGameType()) {\n case \"s\":\n openSpellAnswersDialog({\n answerKey: gameState.playSpec.answerKey,\n foundWords: getProgressRef.current() as string[],\n answers: (gameState.playSpec as SpellPlaySpec).answers,\n });\n break;\n case \"t\":\n openTwistAnswersDialog({\n answerKey: gameState.playSpec.answerKey,\n answers: getProgressRef.current() as { words: string[] },\n solutions: (gameState.playSpec as TwistPlaySpec)\n .challenges as Challenge[],\n });\n break;\n }\n }}\n >\n {gameComponent}\n {snackBar}\n \n\n \n \n \n \n 2020 Cortex Play\n \n \n openJustOkDialog({\n content: ,\n title: \"Privacy\",\n })\n }\n >\n Privacy\n \n \n openJustOkDialog({\n content: ,\n title: \"Terms of Service\",\n })\n }\n >\n Terms\n \n \n \n \n );\n};\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { PlaySpec } from \"../../../domain/types\";\nimport { makeRequest } from \"../../../http/http\";\nimport { ErrorResponse } from \"../serverContract\";\n\nexport interface GetGameRequest {\n gameRef: string;\n getProgress: boolean;\n // If game is in local storage already, then this is not the first play.\n isFirstPlay: boolean;\n}\n\nexport interface GetGameResponse extends ApiResponseHeader {\n playSpec: PlaySpec;\n progress: unknown;\n}\n\ninterface ResponseInternal extends ErrorResponse, GetGameResponse {}\n\nexport async function getGame(\n gameRef: string,\n getProgress: boolean,\n isFirstPlay: boolean\n) {\n const request: GetGameRequest = { gameRef, getProgress, isFirstPlay };\n const response = await makeRequest(\n request,\n \"/api/get_game\"\n );\n // if (response.foundWords == null) response.foundWords = [] as Array;\n // Make sure scoring levels are in order from bottom to top.\n // Also, fill zero for undefined scores.\n response.playSpec.levels = response.playSpec.levels\n .map((level) => {\n return { name: level.name, score: level.score ?? 0 };\n })\n .sort((a, b) => (a.score < b.score ? -1 : a.score > b.score ? 1 : 0));\n return response;\n}\n","import CssBaseline from \"@material-ui/core/CssBaseline\";\r\nimport { createMuiTheme, MuiThemeProvider } from \"@material-ui/core/styles\";\r\nimport * as React from \"react\";\r\nimport * as ReactDOM from \"react-dom\";\r\nimport { GamePageComponent } from \"../play/components/GamePageComponent\";\r\nimport { DialogManager } from \"../../components/dialogTools/DialogManager\";\r\nimport { NotificationManager } from \"../../components/NotificationManager\";\r\nimport { setGameType } from \"../play/globalPlayData\";\r\n\r\nconst logoBlue = \"#0055aa\";\r\nconst logoYellow = \"#FFCB05\";\r\nconst logoFontSize = 110;\r\nconst logoFontName = \"Assistant\";\r\n\r\nconst theme = createMuiTheme({\r\n palette: {\r\n primary: {\r\n // light: \"#fff\",\r\n main: \"#0055aa\",\r\n // dark: \"#000\",\r\n },\r\n secondary: {\r\n main: \"#FFCB05\",\r\n },\r\n },\r\n});\r\nsetGameType(\"s\");\r\nReactDOM.render(\r\n
    \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
    ,\r\n document.getElementById(\"main\")\r\n);\r\n"],"sourceRoot":""}