mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-27 19:38:32 +03:00
1 line
No EOL
566 KiB
Text
1 line
No EOL
566 KiB
Text
{"version":3,"sources":["common/img/ShlinkLogo.tsx","servers/helpers/withSelectedServer.tsx","common/NotFound.tsx","servers/ServersListGroup.tsx","utils/helpers/hooks.ts","common/services/provideServices.ts","common/ScrollToTop.tsx","common/ErrorHandler.tsx","common/services/ImageDownloader.ts","utils/services/provideServices.ts","utils/services/LocalStorage.ts","utils/services/ColorGenerator.ts","servers/data/index.ts","common/ShlinkVersions.tsx","common/ShlinkVersionsContainer.tsx","common/MainHeader.tsx","common/Home.tsx","common/MenuLayout.tsx","common/AsideMenu.tsx","utils/utils.ts","utils/SimpleCard.tsx","utils/helpers/features.ts","utils/theme/index.ts","utils/helpers/query.ts","utils/Message.tsx","utils/SearchField.tsx","utils/helpers/ordering.ts","api/services/ShlinkApiClient.ts","api/services/ShlinkApiClientBuilder.ts","api/services/provideServices.ts","tags/helpers/Tag.tsx","utils/DropdownBtn.tsx","utils/helpers/date.ts","utils/dates/types/index.ts","utils/DateInput.tsx","utils/dates/DateRangeRow.tsx","utils/dates/DateIntervalDropdownItems.tsx","utils/dates/DateRangeSelector.tsx","short-urls/helpers/hooks.ts","short-urls/ShortUrlsFilteringBar.tsx","utils/OrderingDropdown.tsx","mercure/helpers/boundToMercureHub.tsx","mercure/helpers/index.ts","mercure/helpers/Topics.ts","utils/table/TableOrderIcon.tsx","visits/VisitsStats.tsx","utils/helpers/redux.ts","settings/reducers/settings.ts","utils/helpers/numbers.ts","utils/helpers/pagination.ts","short-urls/Paginator.tsx","short-urls/data/index.ts","short-urls/ShortUrlsList.tsx","utils/CopyToClipboardIcon.tsx","utils/Time.tsx","short-urls/helpers/ShortUrlDetailLink.tsx","short-urls/helpers/ShortUrlVisitsCount.tsx","short-urls/helpers/ShortUrlsRow.tsx","utils/DropdownBtnMenu.tsx","short-urls/helpers/ShortUrlsRowMenu.tsx","short-urls/CreateShortUrl.tsx","utils/Result.tsx","api/utils/index.ts","api/ShlinkApiError.tsx","short-urls/helpers/DeleteShortUrlModal.tsx","short-urls/helpers/CreateShortUrlResult.tsx","short-urls/helpers/index.ts","visits/reducers/visitCreation.ts","short-urls/reducers/shortUrlDeletion.ts","short-urls/reducers/shortUrlCreation.ts","short-urls/reducers/shortUrlEdition.ts","short-urls/reducers/shortUrlsList.ts","short-urls/ShortUrlsTable.tsx","short-urls/helpers/qr-codes/QrFormatDropdown.tsx","short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx","short-urls/helpers/QrCodeModal.tsx","utils/helpers/qrCodes.ts","utils/BooleanControl.tsx","utils/Checkbox.tsx","short-urls/UseExistingIfFoundInfoIcon.tsx","utils/InfoTooltip.tsx","short-urls/helpers/ShortUrlFormCheckboxGroup.tsx","short-urls/ShortUrlForm.tsx","short-urls/EditShortUrl.tsx","short-urls/reducers/shortUrlDetail.ts","short-urls/services/provideServices.ts","utils/FormGroupContainer.tsx","servers/helpers/ServerForm.tsx","servers/helpers/DuplicatedServersModal.tsx","servers/CreateServer.tsx","servers/ServersDropdown.tsx","servers/DeleteServerModal.tsx","servers/DeleteServerButton.tsx","servers/EditServer.tsx","servers/helpers/ImportServersBtn.tsx","servers/reducers/selectedServer.ts","servers/reducers/servers.ts","servers/reducers/remoteServers.ts","servers/helpers/ForServerVersion.tsx","servers/helpers/ServerError.tsx","servers/helpers/HighlightCard.tsx","servers/Overview.tsx","servers/ManageServers.tsx","servers/ManageServersRow.tsx","servers/ManageServersRowDropdown.tsx","servers/services/ServersImporter.ts","servers/services/ServersExporter.ts","servers/services/provideServices.ts","visits/helpers/MapModal.tsx","visits/VisitsHeader.tsx","visits/ShortUrlVisitsHeader.tsx","utils/helpers/visits.ts","utils/ToggleSwitch.tsx","utils/helpers/charts.ts","visits/charts/LineChartCard.tsx","common/SimplePaginator.tsx","visits/VisitsTable.tsx","visits/helpers/OpenMapModalBtn.tsx","visits/types/helpers.ts","visits/services/VisitsParser.ts","visits/helpers/VisitsFilterDropdown.tsx","visits/charts/DoughnutChartLegend.tsx","visits/charts/DoughnutChart.tsx","visits/charts/ChartCard.tsx","visits/charts/DoughnutChartCard.tsx","utils/PaginationDropdown.tsx","visits/charts/HorizontalBarChart.tsx","visits/charts/SortableBarChartCard.tsx","visits/ShortUrlVisits.tsx","visits/TagVisitsHeader.tsx","visits/TagVisits.tsx","visits/OrphanVisitsHeader.tsx","visits/OrphanVisits.tsx","visits/NonOrphanVisitsHeader.tsx","visits/NonOrphanVisits.tsx","visits/reducers/common.ts","visits/reducers/shortUrlVisits.ts","visits/reducers/tagVisits.ts","visits/reducers/orphanVisits.ts","visits/reducers/nonOrphanVisits.ts","visits/reducers/visitsOverview.ts","visits/services/VisitsExporter.ts","visits/services/provideServices.ts","tags/helpers/TagBullet.tsx","tags/helpers/TagsSelector.tsx","tags/TagCard.tsx","tags/helpers/DeleteTagConfirmModal.tsx","tags/helpers/EditTagModal.tsx","tags/data/TagsListChildrenProps.ts","tags/TagsModeDropdown.tsx","tags/TagsList.tsx","tags/reducers/tagDelete.ts","tags/reducers/tagEdit.ts","tags/reducers/tagsList.ts","tags/TagsCards.tsx","tags/TagsTable.tsx","tags/TagsTableRow.tsx","tags/services/provideServices.ts","mercure/reducers/mercureInfo.ts","mercure/services/provideServices.ts","settings/RealTimeUpdatesSettings.tsx","settings/Settings.tsx","settings/ShortUrlCreationSettings.tsx","settings/UserInterfaceSettings.tsx","utils/dates/DateIntervalSelector.tsx","settings/VisitsSettings.tsx","settings/TagsSettings.tsx","settings/ShortUrlsListSettings.tsx","settings/services/provideServices.ts","utils/helpers/uri.ts","domains/reducers/domainRedirects.ts","domains/reducers/domainsList.ts","domains/DomainSelector.tsx","domains/helpers/EditDomainRedirectsModal.tsx","domains/helpers/DomainStatusIcon.tsx","domains/DomainRow.tsx","domains/ManageDomains.tsx","domains/services/provideServices.ts","app/reducers/appUpdates.ts","common/AppUpdateBanner.tsx","utils/helpers/sw.ts","app/App.tsx","app/services/provideServices.ts","container/index.ts","reducers/index.ts","container/store.ts","settings/helpers/index.ts","serviceWorkerRegistration.ts","utils/helpers/leaflet.ts","index.tsx","common/NoMenuLayout.tsx","utils/helpers/version.ts","servers/helpers/withoutSelectedServer.tsx","utils/helpers/files.ts"],"names":["ShlinkLogo","color","MAIN_COLOR","className","viewBox","version","xmlns","fill","d","withSelectedServer","WrappedComponent","ServerError","props","params","useParams","selectServer","selectedServer","useEffect","serverId","isNotFoundServer","loading","NotFound","to","children","ServerListItem","id","name","ListGroupItem","tag","Link","icon","chevronIcon","ServersListGroup","servers","embedded","length","ListGroup","classNames","map","useStateFlagTimeout","setTimeout","clearTimeout","initialValue","delay","useState","flag","setFlag","timeout","useRef","undefined","callback","current","useToggle","useSwipeable","showSidebar","hideSidebar","swipeMenuIfNoModalExists","e","event","composedPath","some","classList","contains","document","querySelector","useReactSwipeable","delta","onSwipedLeft","onSwipedRight","useQueryState","paramName","initialState","value","setValue","window","location","history","query","parseQuery","search","pushState","pathname","stringifyQuery","useEffectExceptFirstTime","deps","isFirstLoad","useGoBack","navigate","useNavigate","provideServices","bottle","connect","constant","global","console","axios","service","ImageDownloader","serviceFactory","ScrollToTop","MainHeader","Home","decorator","withoutSelectedServer","MenuLayout","AsideMenu","ShlinkVersionsContainer","ErrorHandler","useLocation","scrollTo","error","state","hasError","this","outline","onClick","reload","Component","imgUrl","filename","get","responseType","data","url","URL","createObjectURL","saveUrl","localStorage","LocalStorage","ColorGenerator","buildPath","path","key","item","getItem","JSON","parse","set","setItem","stringify","HEX_DIGITS","floor","Math","random","sqrt","round","normalizeKey","toLowerCase","trim","perceivedLightness","r","g","b","storage","colors","lights","getColorForKey","normalizedKey","setColorForKey","rangeOf","join","isColorLightForKey","colorHex","substring","isNil","rgb","match","hex","parseInt","hexColorToRgbArray","hasServerData","server","apiKey","isServerWithId","hasOwnProperty","isReachableServer","getServerId","serverWithIdToServerData","omit","normalizeVersion","pipe","versionToSemVer","versionToPrintable","VersionLink","project","href","ShlinkVersions","clientVersion","normalizedClientVersion","printableVersion","classes","ServersDropdown","isOpen","toggleOpen","close","settingsPath","toggleClass","Navbar","dark","fixed","expand","NavbarBrand","NavbarToggler","arrowIcon","Collapse","navbar","Nav","NavItem","NavLink","active","cogsIcon","serversList","values","hasServers","isEmpty","autoConnectServer","find","autoConnect","Card","Row","noGutters","faPlus","faExternalLinkAlt","TagsList","ShortUrlsList","CreateShortUrl","ShortUrlVisits","TagVisits","OrphanVisits","NonOrphanVisits","Overview","EditShortUrl","ManageDomains","sidebarVisible","toggleSidebar","addOrphanVisitsRoute","supportsOrphanVisits","addNonOrphanVisitsRoute","supportsNonOrphanVisits","addManageDomainsRoute","supportsDomainRedirects","burgerClasses","swipeableProps","burgerIcon","showOnMobile","index","element","replace","AsideMenuItem","rest","isActive","DeleteServerButton","hasId","addManageDomainsLink","asideClass","suffix","fixedWidth","overviewIcon","listIcon","createIcon","flip","tagsIcon","domainsIcon","editIcon","textClassName","size","mappingFn","startAt","range","hasValue","handleEventPreventingDefault","handler","preventDefault","nonEmptyValueOrNull","capitalize","charAt","toUpperCase","slice","SimpleCard","title","bodyClassName","serverMatchesVersions","versions","versionMatch","supportsQrCodeSizeInQuery","minVersion","supportsShortUrlTitle","supportsQrCodeMargin","supportsTagsInPatch","supportsBotVisits","supportsCrawlableVisits","supportsQrErrorCorrection","supportsForwardQuery","supportsDefaultDomainRedirectsEdition","MAIN_COLOR_ALPHA","HIGHLIGHTED_COLOR","HIGHLIGHTED_COLOR_ALPHA","PRIMARY_LIGHT_COLOR","PRIMARY_DARK_COLOR","changeThemeInMarkup","theme","html","getElementsByTagName","setAttribute","isDarkThemeEnabled","getAttribute","qs","ignoreQueryPrefix","arrayFormat","getClassForType","type","default","getTextClassForType","Message","fullWidth","body","preloader","spin","timer","determineOrderDir","currentField","newField","currentOrderDir","ASC","DESC","sortList","list","field","dir","sort","a","greaterThan","smallerThan","orderToString","order","stringToOrder","split","buildShlinkBaseUrl","rejectNilProps","reject","normalizeOrderByInParams","orderBy","ShlinkApiClient","baseUrl","listShortUrls","performRequest","then","shortUrls","createShortUrl","options","filteredOptions","resp","getShortUrlVisits","shortCode","visits","getTagVisits","getOrphanVisits","getNonOrphanVisits","getVisitsOverview","getShortUrl","domain","deleteShortUrl","updateShortUrlTags","tags","updateShortUrl","listTags","withStats","stats","deleteTags","editTag","oldName","newName","health","mercureInfo","listDomains","domains","editDomainRedirects","domainRedirects","method","headers","paramsSerializer","apiClients","buildShlinkApiClient","getStateOrSelectedServer","getState","isGetState","prop","Error","clientKey","SearchField","onChange","large","noBorder","searchTerm","setSearchTerm","resetTimer","searchTermChanged","newSearchTerm","placeholder","target","searchIcon","hidden","Tag","text","clearable","colorGenerator","onClose","style","backgroundColor","cursor","DropdownBtn","disabled","dropdownClassName","right","minWidth","toggle","toggleClasses","Dropdown","DropdownToggle","caret","DropdownMenu","isDateObject","date","formatDateFromFormat","theFormat","format","formatISO","formatIsoDate","formatInternational","formatDate","parseISO","stdParseISO","isBetween","start","end","isWithinInterval","isBeforeOrEqual","dateToCompare","isEqual","isBefore","dateRangeIsEmpty","dateRange","filter","Boolean","rangeIsInterval","INTERVAL_TO_STRING_MAP","today","yesterday","last7Days","last30Days","last90Days","last180Days","last365Days","all","DATE_INTERVALS","Object","keys","rangeOrIntervalToString","startDate","endDate","dateRangeToString","startOfDaysAgo","daysAgo","startOfDay","subDays","Date","endingToday","endOfDay","intervalToDateRange","dateInterval","dateToMatchingInterval","theDate","cond","T","DateInput","isClearable","selected","showCalendarIcon","ref","dateFormat","calendarIcon","input","focus","DateRangeRow","onStartDateChange","onEndDateChange","placeholderText","maxDate","minDate","DateIntervalDropdownItems","allText","DropdownItem","divider","interval","DateRangeSelector","onDatesChange","initialDateRange","defaultText","updatable","initialIntervalIsRange","activeInterval","setActiveInterval","activeDateRange","setActiveDateRange","updateDateRange","updateInterval","isDateInterval","header","useShortUrlsQuery","useMemo","extra","mergedQuery","normalizedQuery","evolvedQuery","queryString","dateOrNull","ShortUrlsFilteringBar","toFirstPage","selectedTags","setDates","setSearch","removeTag","selectedTag","tagsList","OrderingDropdown","items","isButton","handleItemClick","fieldKey","newOrderDir","UncontrolledDropdown","toPairs","fieldValue","sortAscIcon","sortDescIcon","boundToMercureHub","getTopicsForProps","pendingUpdates","Set","createNewVisits","loadMercureInfo","topics","closeEventSource","onMessage","onTokenExpired","mercureHubUrl","token","onEventSourceMessage","onEventSourceError","status","subscriptions","topic","hubUrl","searchParams","append","es","EventSource","Authorization","onmessage","onerror","forEach","bindToMercureTopic","visit","add","setInterval","clear","clearInterval","Topics","TableOrderIcon","currentOrder","caretUpIcon","caretDownIcon","orphanVisits","shortUrlVisits","selectedBar","buildReducer","action","actionHandler","currentState","buildActionCreator","SET_SETTINGS","DEFAULT_SHORT_URLS_ORDERING","realTimeUpdates","enabled","shortUrlCreation","validateUrls","ui","defaultInterval","shortUrlsList","defaultOrdering","mergeDeepRight","dissoc","toggleRealTimeUpdates","setRealTimeUpdatesInterval","setShortUrlCreationSettings","settings","setShortUrlsListSettings","setUiSettings","setVisitsSettings","setTagsSettings","ceil","formatter","Intl","NumberFormat","prettify","number","Number","ELLIPSIS","progressivePagination","currentPage","pageCount","pages","max","min","unshift","push","pageIsEllipsis","pageNumber","prettifyPageNumber","keyForPage","Paginator","paginator","currentQueryString","pagesCount","urlForPage","Pagination","listClassName","PaginationItem","PaginationLink","previous","next","SHORT_URLS_ORDERABLE_FIELDS","dateCreated","longUrl","ShortUrlsTable","page","actualOrderBy","setActualOrderBy","pagination","handleOrderBy","addTag","newTag","orderByColumn","renderOrderIcon","onTagClick","CopyToClipboardIcon","onCopy","copyIcon","Time","relative","dateObject","dateTime","getUnixTime","formatDistance","buildUrl","ShortUrlDetailLink","shortUrl","ShortUrlVisitsCount","visitsCount","maxVisits","meta","visitsLink","prettifiedMaxVisits","tooltipRef","el","infoIcon","UncontrolledTooltip","placement","ShortUrlsRow","ShortUrlsRowMenu","copiedToClipboard","setCopiedToClipboard","setActive","isFirstRun","data-th","DropdownBtnMenu","ButtonDropdown","menuIcon","DeleteShortUrlModal","QrCodeModal","isQrModalOpen","toggleQrCode","isDeleteModalOpen","toggleDelete","pieChartIcon","qrIcon","deleteIcon","ShortUrlForm","CreateShortUrlResult","shortUrlCreationResult","resetCreateShortUrl","basicMode","shortUrlCreationSettings","customSlug","shortCodeLength","validSince","validUntil","findIfExists","validateUrl","forwardQuery","getInitialState","saving","mode","onSave","canBeClosed","Result","small","parseApiError","response","isInvalidDeletionError","ShlinkApiError","errorData","fallbackMessage","detail","invalidElements","shortUrlDeletion","resetDeleteShortUrl","inputValue","setInputValue","handleDeleteUrl","catch","identity","Modal","centered","onSubmit","ModalHeader","ModalBody","ModalFooter","result","showCopyTooltip","setShowCopyTooltip","closeIcon","Tooltip","shortUrlMatches","CREATE_VISITS","createdVisits","DELETE_SHORT_URL_START","DELETE_SHORT_URL_ERROR","SHORT_URL_DELETED","RESET_DELETE_SHORT_URL","dispatch","CREATE_SHORT_URL_START","CREATE_SHORT_URL_ERROR","CREATE_SHORT_URL","RESET_CREATE_SHORT_URL","_","EDIT_SHORT_URL_START","EDIT_SHORT_URL_ERROR","SHORT_URL_EDITED","editShortUrl","sendTagsSeparately","Promise","LIST_SHORT_URLS_START","LIST_SHORT_URLS_ERROR","LIST_SHORT_URLS","assocPath","totalItems","currentShortUrl","lastVisit","last","assoc","ITEMS_IN_OVERVIEW_PAGE","editedShortUrl","actionableFieldClasses","orderableColumnsClasses","tableClasses","supportsTitle","colSpan","QrFormatDropdown","setFormat","QrErrorCorrectionDropdown","errorCorrection","setErrorCorrection","imageDownloader","ForServerVersion","setSize","margin","setMargin","capabilities","useSizeInPath","marginIsSupported","errorCorrectionIsSupported","willRenderThreeControls","qrCodeUrl","buildQrCodeUrl","totalSize","modalSize","step","src","alt","Button","block","saveImage","downloadIcon","BooleanControl","checked","inline","uuid","typeClasses","display","htmlFor","Checkbox","InfoModal","UseExistingIfFoundInfoIcon","isModalOpen","toggleModal","InfoTooltip","ShortUrlFormCheckboxGroup","infoTooltip","normalizeTag","toDate","dynamicColClasses","TagsSelector","DomainSelector","shortUrlData","setShortUrlData","isEdit","isBasicMode","hadTitleOriginally","resolveNewTitle","hasNewTitle","matcher","submit","renderOptionalInput","fromGroupProps","Input","renderDateInput","basicComponents","bsSize","required","showCustomizeCard","limitAccessCardClasses","showCrawlableControl","showForwardQueryControl","showBehaviorCard","extraChecksCardClasses","crawlable","shortUrlDetail","getShortUrlDetail","shortUrlEdition","goBack","savingError","savingErrorData","savingSucceeded","isSuccessful","isNotSuccessful","faArrowLeft","GET_SHORT_URL_DETAIL_START","GET_SHORT_URL_DETAIL_ERROR","GET_SHORT_URL_DETAIL","FormGroupContainer","labelClassName","forId","FormGroup","ServerForm","initialValues","setName","setUrl","setApiKey","handleSubmit","DuplicatedServersModal","duplicatedServers","onDiscard","hasMultipleServers","ImportResult","CreateServer","ImportServersBtn","createServer","serversImported","setServersImported","errorImporting","setErrorImporting","isConfirmModalOpen","toggleConfirmModal","serverData","setServerData","save","NoMenuLayout","tooltipPlacement","onImport","onImportError","nav","inNavbar","serverIcon","plusIcon","DeleteServerModal","deleteServer","redirectHome","showModal","hideModal","EditServer","editServer","serversFiltering","importServersFromFile","createServers","fileRef","serversToCreate","setServersToCreate","setDuplicatedServers","create","createAllServers","createNonDuplicatedServers","complement","onFile","files","existingServers","hasDuplicatedServers","click","importIcon","accept","SELECT_SERVER","RESET_SELECTED_SERVER","toSemVer","getServerVersion","memoizeWith","_serverId","resetSelectedServer","serverNotFound","serverNotReachable","EDIT_SERVER","DELETE_SERVER","CREATE_SERVERS","SET_AUTO_CONNECT","newServers","fromPairs","evaluatedServerId","serversListToMap","reduce","acc","setAutoConnect","responseToServersList","Array","isArray","fetchServers","homepage","remoteList","maxVersion","HighlightCard","link","buildExtraProps","linkIcon","CardTitle","CardText","loadVisitsOverview","visitsOverview","loadingTags","loadingVisits","orphanVisitsCount","linkToOrphanVisits","linkToNonOrphanVisits","itemsPerPage","CardHeader","CardBody","encodeURIComponent","ManageServers","serversExporter","ManageServersRow","allServers","setServersList","hasAutoConnect","exportServers","exportIcon","width","ManageServersRowDropdown","checkIcon","isMenuOpen","toggleMenu","serverUrl","isAutoConnect","autoConnectIcon","toggleOffIcon","toggleOnIcon","connectIcon","validateServer","validateServers","every","ServersImporter","csvJson","fileReaderFactory","file","reader","resolve","addEventListener","content","toString","toObject","readAsText","ServersExporter","csvjson","csv","toCSV","saveCsv","FileReader","OpenStreetMapTile","TileLayer","attribution","calculateMapProps","locations","bounds","zoom","center","latLong","MapModal","contentClassName","MapContainer","cityName","count","Marker","position","Popup","VisitsHeader","ShortUrlVisitsHeader","shortLink","longLink","visitsStatsTitle","DEFAULT","BROWSERS_WHITELIST","extractDomain","includes","fillTheGaps","labels","zipObj","ToggleSwitch","pointerOnHover","native","firstElement","renderChartLabel","dataset","formattedValue","label","renderPieChartLabel","STEPS_MAP","monthly","weekly","daily","hourly","STEP_TO_DURATION_MAP","hours","days","weeks","months","STEP_TO_DIFF_FUNC_MAP","differenceInHours","differenceInDays","differenceInWeeks","differenceInMonths","STEP_TO_DATE_FORMAT","firstWeekDay","startOfISOWeek","lastWeekDay","endOfISOWeek","groupVisitsByStep","countBy","generateLabelsAndGroupedVisits","groupedVisitsWithGaps","skipNoElements","diffFunc","newerDate","oldestDate","duration","num","generateLabels","generateDataset","tension","borderColor","selectedLabel","chartElementAtEvent","datasetsByPoint","setSelectedVisits","chart","LineChartCard","highlightedVisits","highlightedLabel","oldestVisitDate","now","always","determineInitialStep","setStep","skipNoVisits","toggleSkipNoVisits","visitsToDatasetGroups","reverse","groupedVisits","groupedHighlighted","generateChartDatasets","mainDataset","maintainAspectRatio","plugins","legend","tooltip","intersect","axis","callbacks","scales","y","beginAtZero","ticks","precision","x","onHover","renderLineChart","datasets","getElementAtEvent","entries","menuText","SimplePaginator","setCurrentPage","searchVisits","browser","os","referer","country","city","visitedUrl","visitMatchesSearch","calculateVisits","allVisits","sortedVisits","sortVisits","total","visitsGroups","splitEvery","VisitsTable","selectedVisits","matchMedia","isOrphanVisits","headerCellsClass","matchMobile","matches","isMobileDevice","setIsMobileDevice","setOrder","resultSet","setPage","supportsBots","fullSizeColSpan","listener","removeEventListener","flat","botIcon","isSelected","v","potentialBot","OpenMapModalBtn","modalTitle","activeCities","mapIsOpened","openMap","closeMap","dropdownIsOpened","toggleDropdown","openDropdown","locationsToShow","setLocationsToShow","buttonRef","openMapWithLocations","filtered","mapIcon","isOrphanVisit","groupNewVisitsByType","groupBy","newVisit","regularVisits","highlightedVisitsToStats","property","toApiParams","excludeBots","visitHasProperty","propertyName","optionalNumericToNumber","numeric","parseFloat","updateLocationsStatsForVisit","updateCountriesStatsForVisit","updateCitiesStatsForVisit","processStatsFromVisits","osStats","updateOsStatsForVisit","browsersStats","updateBrowsersStatsForVisit","browsers","referrersStats","updateReferrersStatsForVisit","referrers","countries","cities","citiesForMapStats","latitude","longitude","currentCity","updateCitiesForMapForVisit","citiesForMap","visitedUrlsStats","isNormalizedOrphanVisit","updateVisitedUrlsForVisit","visitedUrls","normalizeVisits","userAgent","visitLocation","common","bowser","parseUserAgent","countryName","VisitsFilterDropdown","botsSupported","orphanVisitsType","propsForOrphanVisitsTypeItem","DoughnutChartLegend","config","defaultColor","borderWidth","DoughnutChart","memo","chartRef","setChartRef","chartData","generateChartData","height","ChartCard","footer","CardFooter","DoughnutChartCard","PaginationDropdown","toggleClassName","ranges","Infinity","dropLabelIfHidden","startsWith","highlightedData","HorizontalBarChart","highlightedStats","statsAreDefined","highlightedKey","stacked","indexAxis","determineHeight","renderChartComponent","customKey","toLowerIfString","toLower","pickKeyFromPair","pickValueFromPair","SortableBarChartCard","sortingItems","extraHeaderContent","withPagination","setItemsPerPage","determineCurrentPagePairs","firstPageLength","i","sortedPairs","pairs","sortBy","getSortedPairsForStats","sortedKeys","sortedHighlightedPairs","currentPageStats","currentPageHighlightedStats","highlightedPages","determineStats","sections","byTime","subPath","faCalendarAlt","byContext","faChartPie","byLocation","faMapMarkedAlt","faList","VisitsNavLink","RouterNavLink","endsWith","VisitsStats","visitsInfo","getVisits","cancelGetVisits","exportCsv","loadingLarge","progress","fallbackInterval","initialInterval","setInitialInterval","setDateRange","setHighlightedVisits","setHighlightedLabel","visitsFilter","setVisitsFilter","buildSectionUrl","normalizedVisits","mapLocations","highlightVisitsForProp","newSelectedBar","propEq","faFileDownload","Progress","striped","pills","section","amount","exportVisits","cancelGetShortUrlVisits","doIntervalFallback","TagVisitsHeader","tagVisits","cancelGetTagVisits","OrphanVisitsHeader","cancelGetOrphanVisits","NonOrphanVisitsHeader","nonOrphanVisits","cancelGetNonOrphanVisits","ITEMS_PER_PAGE","isLastPage","calcProgress","getVisitsWithLoader","visitsLoader","lastVisitLoader","extraFinishActionData","actionMap","shouldCancel","loadVisitsInParallel","flatten","loadPagesBlocks","pagesBlocks","concat","loadVisits","pagesRange","fallbackToInterval","finish","lastVisitLoaderForLoader","loader","GET_SHORT_URL_VISITS_START","GET_SHORT_URL_VISITS_ERROR","GET_SHORT_URL_VISITS","GET_SHORT_URL_VISITS_LARGE","GET_SHORT_URL_VISITS_CANCEL","GET_SHORT_URL_VISITS_PROGRESS_CHANGED","GET_SHORT_URL_VISITS_FALLBACK_TO_INTERVAL","cancelLoad","newVisits","GET_TAG_VISITS_START","GET_TAG_VISITS_ERROR","GET_TAG_VISITS","GET_TAG_VISITS_LARGE","GET_TAG_VISITS_CANCEL","GET_TAG_VISITS_PROGRESS_CHANGED","GET_TAG_VISITS_FALLBACK_TO_INTERVAL","GET_ORPHAN_VISITS_START","GET_ORPHAN_VISITS_ERROR","GET_ORPHAN_VISITS","GET_ORPHAN_VISITS_LARGE","GET_ORPHAN_VISITS_CANCEL","GET_ORPHAN_VISITS_PROGRESS_CHANGED","GET_ORPHAN_VISITS_FALLBACK_TO_INTERVAL","matchesType","GET_NON_ORPHAN_VISITS_START","GET_NON_ORPHAN_VISITS_ERROR","GET_NON_ORPHAN_VISITS","GET_NON_ORPHAN_VISITS_LARGE","GET_NON_ORPHAN_VISITS_CANCEL","GET_NON_ORPHAN_VISITS_PROGRESS_CHANGED","GET_NON_ORPHAN_VISITS_FALLBACK_TO_INTERVAL","GET_OVERVIEW_START","GET_OVERVIEW_ERROR","GET_OVERVIEW","VisitsExporter","visitsParser","TagBullet","toComponentTag","searchMode","tagFilteringMode","tagComponent","onDelete","suggestions","suggestionComponent","allowNew","addOnBlur","minQueryLength","delimiters","suggestionsTransform","removedTagIndex","tagsCopy","splice","onAddition","TagCard","DeleteTagConfirmModal","EditTagModal","displayed","isEditModalOpen","toggleEdit","hasTitle","displayTitle","titleRef","scrollWidth","clientWidth","faLink","faEye","deleteTag","tagDelete","tagDeleted","deleting","doDelete","tagEdited","tagEdit","newTagName","setNewTagName","setColor","showColorPicker","toggleColorPicker","hideColorPicker","editing","saveTag","onClosed","colorIcon","Popover","disableAlpha","TAGS_ORDERABLE_FIELDS","TagsModeDropdown","renderTitle","cardsIcon","TagsCards","TagsTable","filterTags","forceListTags","defaultMode","setMode","resolveSortedTags","filteredTags","shortUrlsCount","normalizedTags","sortedTags","renderContent","DELETE_TAG_START","DELETE_TAG_ERROR","DELETE_TAG","TAG_DELETED","EDIT_TAG_START","EDIT_TAG_ERROR","EDIT_TAG","TAG_EDITED","pick","LIST_TAGS_START","LIST_TAGS_ERROR","LIST_TAGS","FILTER_TAGS","renameTag","rejectTag","tagToReject","calculateVisitsPerTag","increase","tagStats","stateTags","displayedTag","setDisplayedTag","tagsCount","tagsGroups","group","TagsTableRow","pageFromQuery","showPaginator","isDropdownOpen","listTagsActionFactory","force","processedStats","factory","GET_MERCURE_INFO_START","GET_MERCURE_INFO_ERROR","GET_MERCURE_INFO","info","RealTimeUpdatesSettings","SettingsSections","child","subChild","subIndex","Settings","RealTimeUpdates","ShortUrlCreation","UserInterface","Visits","Tags","tagFilteringModeText","ShortUrlCreationSettings","changeTagsFilteringMode","UserInterfaceSettings","faMoon","faSun","useDarkTheme","DateIntervalSelector","VisitsSettings","TagsSettings","tagsMode","ShortUrlsListSettings","replaceAuthorityFromUri","uri","newAuthority","schema","pathParts","normalizedPath","EDIT_DOMAIN_REDIRECTS","redirects","LIST_DOMAINS_START","LIST_DOMAINS_ERROR","LIST_DOMAINS","FILTER_DOMAINS","VALIDATE_DOMAIN","filteredDomains","replaceRedirectsOnDomain","replaceStatusOnDomain","defaultRedirects","filterDomains","checkDomainHealth","domainsList","inputDisplayed","showInput","hideInput","valueIsEmpty","unselectDomain","InputGroup","InputGroupAddon","addonType","faUndo","trigger","isDefault","isLast","EditDomainRedirectsModal","baseUrlRedirect","setBaseUrlRedirect","regular404Redirect","setRegular404Redirect","invalidShortUrlRedirect","setInvalidShortUrlRedirect","DomainStatusIcon","matchesMobile","isMobile","setIsMobile","loadingStatusIcon","invalidIcon","autohide","Nr","fallback","DefaultDomain","defaultDomainIcon","DomainRow","authority","canEditDomain","forbiddenIcon","resolvedDefaultRedirects","column","APP_UPDATE_AVAILABLE","RESET_APP_UPDATE","appUpdateAvailable","resetAppUpdate","AppUpdateBanner","forceUpdate","isUpdating","setUpdating","Alert","reloadIcon","navigator","serviceWorker","getRegistrations","registrations","registration","waiting","postMessage","App","appUpdated","isHome","Bottle","container","mapActionService","actionName","serviceName","lazyService","propsFromState","actionServiceNames","reduxConnect","provideAppServices","provideCommonServices","provideApiServices","provideShortUrlsServices","provideServersServices","provideTagsServices","provideVisitsServices","provideUtilsServices","provideMercureServices","provideSettingsServices","provideDomainsServices","combineReducers","serversReducer","selectedServerReducer","shortUrlsListReducer","shortUrlCreationReducer","shortUrlDeletionReducer","shortUrlEditionReducer","shortUrlVisitsReducer","tagVisitsReducer","orphanVisitsReducer","nonOrphanVisitsReducer","shortUrlDetailReducer","tagsListReducer","tagDeleteReducer","tagEditReducer","mercureInfoReducer","settingsReducer","domainsListReducer","visitsOverviewReducer","appUpdatesReducer","composeEnhancers","__REDUX_DEVTOOLS_EXTENSION_COMPOSE__","compose","localStorageConfig","states","namespace","namespaceSeparator","debounce","preloadedState","migrateDeprecatedSettings","load","store","createStore","reducers","applyMiddleware","ReduxThunk","isLocalhost","hostname","registerValidSW","swUrl","register","onupdatefound","installingWorker","installing","onstatechange","controller","log","onUpdate","onSuccess","L","Icon","Default","prototype","_getIconUrl","mergeOptions","iconRetinaUrl","marker2x","iconUrl","marker","shadowUrl","markerShadow","render","basename","getElementById","process","origin","fetch","contentType","indexOf","ready","unregister","checkValidServiceWorker","registerServiceWorker","versionToMatch","matchesMinVersion","compare","versionIsValidSemVer","defaultValue","createElement","visibility","appendChild","removeChild","blob","Blob"],"mappings":"oPAOaA,EAAa,SAAC,GAAD,QAAGC,aAAH,MAAWC,IAAX,EAAuBC,EAAvB,EAAuBA,UAAvB,OACxB,qBAAKA,UAAWA,EAAWC,QAAQ,cAAcC,QAAQ,MAAMC,MAAM,6BAArE,SACE,oBAAGC,KAAMN,EAAT,UACE,sBACEO,EAAE,6lBAEJ,sBACEA,EAAE,uiBAEJ,sBACEA,EAAE,uiBAEJ,sBACEA,EAAE,8X,4HCTH,SAASC,EAA2BC,EAAmDC,GAC5F,OAAO,SAACC,GACN,IAAMC,EAASC,cACPC,EAAiCH,EAAjCG,aAAcC,EAAmBJ,EAAnBI,eAMtB,OAJAC,qBAAU,WACRJ,EAAOK,UAAYH,EAAaF,EAAOK,YACtC,CAAEL,EAAOK,WAEPF,EAQDG,YAAiBH,GACZ,cAACL,EAAD,IAGF,cAACD,EAAD,eAAsBE,IAVzB,cAAC,IAAD,UACE,cAAC,IAAD,CAASQ,SAAO,S,4DCDXC,IAdqB,SAAC,GAAD,QAAGC,UAAH,MAAQ,IAAR,MAAaC,gBAAb,MAAwB,OAAxB,SAClC,qBAAKpB,UAAU,OAAf,SACE,eAAC,IAAD,CAAYA,UAAU,MAAtB,UACE,0EACA,iJAIA,uBACA,cAAC,IAAD,CAAMmB,GAAIA,EAAInB,UAAU,iCAAxB,SAA0DoB,W,sGCH1DC,EAAiB,SAAC,GAAD,IAAGC,EAAH,EAAGA,GAAIC,EAAP,EAAOA,KAAP,OACrB,eAACC,EAAA,EAAD,CAAeC,IAAKC,IAAMP,GAAE,kBAAaG,GAAMtB,UAAU,4BAAzD,UACGuB,EACD,cAAC,IAAD,CAAiBI,KAAMC,IAAa5B,UAAU,uCAiBnC6B,IAbqC,SAAC,GAAD,IAAGC,EAAH,EAAGA,QAASV,EAAZ,EAAYA,SAAZ,IAAsBW,gBAAtB,gBAClD,qCACGX,GAAY,oBAAIpB,UAAU,UAAd,SAAyBoB,IACrCU,EAAQE,OAAS,GAChB,cAACC,EAAA,EAAD,CACEjC,UAAWkC,IAAW,2BAA4B,CAAE,qCAAsCH,IAD5F,SAGGD,EAAQK,KAAI,gBAAGb,EAAH,EAAGA,GAAIC,EAAP,EAAOA,KAAP,OAAkB,cAAC,EAAD,CAAyBD,GAAIA,EAAIC,KAAMA,GAAlBD,a,uRCnB/Cc,EAAsB,SACjCC,EACAC,GAFiC,OAGZ,WAAkD,IAAjDC,EAAgD,wDAA1BC,EAA0B,uDAPlD,IAOkD,EAC5CC,mBAAkBF,GAD0B,mBAC9DG,EAD8D,KACxDC,EADwD,KAEhEC,EAAUC,sBAA2BC,GACrCC,EAAW,WACfJ,GAASJ,GAELK,EAAQI,SACVV,EAAaM,EAAQI,SAGvBJ,EAAQI,QAAUX,GAAW,kBAAMM,EAAQJ,KAAeC,IAG5D,MAAO,CAAEE,EAAMK,KAKJE,EAAY,WAAyC,IAAxCV,EAAuC,0DACrCE,mBAAkBF,GADmB,mBACvDG,EADuD,KACjDC,EADiD,KAG/D,MAAO,CAAED,EAAM,kBAAMC,GAASD,IAAO,kBAAMC,GAAQ,IAAO,kBAAMA,GAAQ,MAG7DO,EAAe,SAACC,EAAyBC,GACpD,IAAMC,EAA2B,SAACN,GAAD,OAA0B,SAACO,GAC5BA,EAAEC,MAAMC,eAAiCC,MACrE,gBAAGC,EAAH,EAAGA,UAAH,cAAmBA,QAAnB,IAAmBA,OAAnB,EAAmBA,EAAWC,SAAS,oBAGbC,SAASC,cAAc,WAInDd,MAGF,OAAOe,uBAAkB,CACvBC,MAAO,GACPC,aAAcX,EAAyBD,GACvCa,cAAeZ,EAAyBF,MAI/Be,EAAgB,SAAIC,EAAmBC,GAAmD,IAAD,EACxE3B,mBAAS2B,GAD+D,mBAC5FC,EAD4F,KACrFC,EADqF,KAWpG,MAAO,CAAED,EAToB,SAACA,GAAc,IAAD,EACXE,OAAtBC,EADiC,EACjCA,SAAUC,EADuB,EACvBA,QACZC,EAAQC,YAAgBH,EAASI,QAEvCF,EAAMP,GAAaE,EACnBI,EAAQI,UAAU,KAAM,GAAxB,UAA+BL,EAASM,SAAxC,YAAoDC,YAAeL,KACnEJ,EAASD,MAMAW,EAA2B,SAACjC,EAA0BkC,GACjE,IAAMC,EAAcrC,kBAAO,GAE3B/B,qBAAU,YACPoE,EAAYlC,SAAWD,IACxBmC,EAAYlC,SAAU,IACrBiC,IAGQE,EAAY,WACvB,IAAMC,EAAWC,cAEjB,OAAO,kBAAMD,GAAU,M,kCClFzB,kHAwDeE,IA3CS,SAACC,EAAgBC,GAEvCD,EAAOE,SAAS,SAAWC,EAAenB,QAC1CgB,EAAOE,SAAS,UAAWC,EAAOC,SAClCJ,EAAOE,SAAS,QAASG,KAEzBL,EAAOM,QAAQ,kBAAmBC,IAAiB,QAAS,UAG5DP,EAAOQ,eAAe,cAAeC,KAErCT,EAAOQ,eAAe,aAAcE,IAAY,mBAEhDV,EAAOQ,eAAe,QAAQ,kBAAMG,OACpCX,EAAOY,UAAU,OAAQC,KACzBb,EAAOY,UAAU,OAAQX,EAAQ,CAAE,WAAa,CAAE,yBAElDD,EAAOQ,eACL,aACAM,IACA,WACA,gBACA,YACA,iBACA,iBACA,YACA,eACA,kBACA,cACA,WACA,eACA,iBAEFd,EAAOY,UAAU,aAAcX,EAAQ,CAAE,kBAAoB,CAAE,kBAE/DD,EAAOQ,eAAe,YAAaO,IAAW,sBAE9Cf,EAAOQ,eAAe,2BAA2B,kBAAMQ,OACvDhB,EAAOY,UAAU,0BAA2BX,EAAQ,CAAE,oBAEtDD,EAAOQ,eAAe,eAAgBS,IAAc,SAAU,c,6ECxCjDR,IAVK,kBAAU,YAAmB,IAAhB5E,EAAe,EAAfA,SACzBoD,EAAWiC,cAMjB,OAJA3F,qBAAU,WACR4F,SAAS,EAAG,KACX,CAAElC,IAEE,mCAAGpD,O,oGCmCGoF,IArCM,SAAC,EAAD,OACjBhC,EADiB,EACjBA,SACAmC,EAFiB,EAEjBA,MAFiB,yDAInB,WAAmBlG,GAAgB,IAAD,8BAChC,cAAMA,IACDmG,MAAQ,CAAEC,UAAU,GAFO,EAJf,8DAaMvD,GAErBqD,EAAMrD,KAfS,+BAoBjB,OAAIwD,KAAKF,MAAMC,SAEX,qBAAK7G,UAAU,OAAf,SACE,eAAC,IAAD,CAAYA,UAAU,MAAtB,UACE,0DACA,uHACA,uBACA,cAAC,IAAD,CAAQ+G,SAAO,EAACjH,MAAM,UAAUkH,QAAS,kBAAMxC,EAASyC,UAAxD,+BAMDH,KAAKrG,MAAMW,YAjCD,kDAUjB,MAAO,CAAEyF,UAAU,OAVF,GAGWK,e,uHCRnBpB,EAAb,WACE,WAAoCF,EAAuCrB,GAAiB,yBAAxDqB,QAAuD,KAAhBrB,SAD7E,+FAGyB4C,EAAgBC,GAHzC,2FAI2BN,KAAKlB,MAAMyB,IAAIF,EAAQ,CAAEG,aAAc,SAJlE,gBAIYC,EAJZ,EAIYA,KACFC,EAAMC,IAAIC,gBAAgBH,GAEhCI,YAAQb,KAAKvC,OAAQiD,EAAKJ,GAP9B,iH,kCCFA,0CAce9B,IAVS,SAACC,GACvBA,EAAOE,SAAS,eAAiBC,EAAekC,cAChDrC,EAAOM,QAAQ,UAAWgC,IAAc,gBACxCtC,EAAOM,QAAQ,iBAAkBiC,IAAgB,WAEjDvC,EAAOE,SAAS,aAAcC,EAAOrD,YACrCkD,EAAOE,SAAS,eAAgBC,EAAOpD,cACvCiD,EAAOQ,eAAe,sBAAuB3D,IAAqB,aAAc,mB,iGCX5E2F,EAAY,SAACC,GAAD,gBADH,SACG,YAA+BA,IAE5BH,EACnB,WAAoCD,GAAwB,IAAD,gCAAvBA,eAAuB,KAE3CP,IAAM,SAAIY,GACxB,IAAMC,EAAO,EAAKN,aAAaO,QAAQJ,EAAUE,IAEjD,OAAOC,EAAOE,KAAKC,MAAMH,QAAapF,GALmB,KAQ3CwF,IAAM,SAACL,EAAa5D,GAAd,OAA6B,EAAKuD,aAAaW,QAAQR,EAAUE,GAAMG,KAAKI,UAAUnE,O,wGCPxGoE,EAAa,mBAGXC,EAA+BC,KAA/BD,MAAOE,EAAwBD,KAAxBC,OAAQC,EAAgBF,KAAhBE,KAAMC,EAAUH,KAAVG,MAGvBC,EAAe,SAACd,GAAD,OAAiBA,EAAIe,cAAcC,QAIlDC,EAAqB,eAACC,EAAD,uDAAK,EAAGC,EAAR,uDAAY,EAAGC,EAAf,uDAAmB,EAAnB,OAAyBP,EAAMD,EAAK,cAAQM,EAAK,GAAI,cAAQC,EAAK,GAAI,cAAQC,EAAK,MAEzFvB,EAInB,WAAoCwB,GAAwB,IAAD,kCAAvBA,UAAuB,KAH1CC,YAG0C,OAF1CC,YAE0C,OAK3CC,eAAiB,SAACxB,GAChC,IAAMyB,EAAgBX,EAAad,GAC7BnI,EAAQ,EAAKyJ,OAAOG,GAG1B,OAAK5J,GACI,EAAK6J,eAAeD,EAvBR,WACnBE,YANmB,GAMO,kBAAMnB,EAAWC,EAAME,IAAWH,EAAWzG,YAAU6H,KAAK,OAW/B,KAiB3CF,eAAiB,SAAC1B,EAAanI,GAC7C,IAAM4J,EAAgBX,EAAad,GAKnC,OAHA,EAAKsB,OAAOG,GAAiB5J,EAC7B,EAAKwJ,QAAQhB,IAAI,SAAU,EAAKiB,QAEzBzJ,GAvBkD,KA0B3CgK,mBAAqB,SAAC7B,GACpC,IAAM8B,EAAW,EAAKN,eAAexB,GAAK+B,UAAU,GAEpD,GAAIC,YAAM,EAAKT,OAAOO,IAAY,CAChC,IAAMG,EAvCe,SAACH,GAAD,aACzB,UAACA,EAASI,MAAM,cAAhB,QAA0B,IAAIhI,KAAI,SAACiI,GAAD,OAASC,SAASD,EAAK,KAAO,KAsChDE,CAAmBP,GAE/B,EAAKP,OAAOO,GAAYb,EAAkB,WAAlB,cAAsBgB,KA/CvB,IAkDzB,OAAO,EAAKV,OAAOO,IAlCnBjD,KAAKyC,OAAL,UAAczC,KAAKwC,QAAQjC,IAA4B,iBAAvD,QAAoE,GACpEP,KAAK0C,OAAS,K,gCCvBlB,yNAiCae,EAAgB,SAACC,GAAD,QAC1B,OAAEA,QAAF,IAAEA,MAAuBhD,QAAQ,OAAEgD,QAAF,IAAEA,MAAuBC,SAEhDC,EAAiB,SAACF,GAAD,QAC3B,OAACA,QAAD,IAACA,MAAQG,eAAe,QAEdC,EAAoB,SAACJ,GAAD,QAC9B,OAACA,QAAD,IAACA,MAAQG,eAAe,aAEd3J,EAAmB,SAACwJ,GAAD,QAC7B,OAACA,QAAD,IAACA,MAAQG,eAAe,oBAEdE,EAAc,SAACL,GAAD,OAA4BE,EAAeF,GAAUA,EAAOlJ,GAAK,IAE/EwJ,EAA2B,SAACN,GAAD,OACtCO,YAAyC,CAAE,KAAM,eAAiBP,K,6FCzC9DQ,EAAmBC,YAAKC,cAAmBC,KAM3CC,EAAc,SAAC,GAAD,IAAGC,EAAH,EAAGA,QAASnL,EAAZ,EAAYA,QAAZ,OAClB,cAAC,IAAD,CAAcoL,KAAI,sCAAiCD,EAAjC,qBAAqDnL,GAAWF,UAAU,aAA5F,SACE,4BAAIE,OAiBOqL,EAbQ,SAAC,GAAwF,IAAtF1K,EAAqF,EAArFA,eAAqF,IAArE2K,cAClCC,EAA0BT,OAD6E,MAb7E,cAa6E,GAG7G,OACE,wBAAOhL,UAAU,aAAjB,UACG4K,YAAkB/J,IACjB,gDAAU,cAAC,EAAD,CAAawK,QAAQ,SAASnL,QAASW,EAAe6K,mBAAhE,SAFJ,WAIU,cAAC,EAAD,CAAaL,QAAQ,oBAAoBnL,QAASuL,QCNjDlF,IAZiB,SAAC,GAAsD,IAApD1F,EAAmD,EAAnDA,eAC3B8K,EAAUzJ,IAAW,cAAe,CACxC,yCAA0C0I,YAAkB/J,KAG9D,OACE,qBAAKb,UAAW2L,EAAhB,SACE,cAAC,EAAD,CAAgB9K,eAAgBA,Q,0LC4BvBoF,IAlCI,SAAC2F,GAAD,OAAyB,WAAO,IAAD,EACR3I,cADQ,mBACxC4I,EADwC,KAChCC,EADgC,KAClBC,EADkB,KAE1CvH,EAAWiC,cACT3B,EAAaN,EAAbM,SAERhE,oBAAUiL,EAAO,CAAEvH,IAEnB,IAAMwH,EAAe,YACfC,EAAc/J,IAAW,2BAA4B,CAAE,mCAAoC2J,IAEjG,OACE,eAACK,EAAA,EAAD,CAAQpM,MAAM,UAAUqM,MAAI,EAACC,MAAM,MAAMpM,UAAU,cAAcqM,OAAO,KAAxE,UACE,eAACC,EAAA,EAAD,CAAa7K,IAAKC,IAAMP,GAAG,IAA3B,UACE,cAACtB,EAAA,EAAD,CAAYG,UAAU,0BAA0BF,MAAM,UADxD,aAIA,cAACyM,EAAA,EAAD,CAAevF,QAAS8E,EAAxB,SACE,cAAC,IAAD,CAAiBnK,KAAM6K,IAAWxM,UAAWiM,MAG/C,cAACQ,EAAA,EAAD,CAAUC,QAAM,EAACb,OAAQA,EAAzB,SACE,eAACc,EAAA,EAAD,CAAKD,QAAM,EAAC1M,UAAU,UAAtB,UACE,cAAC4M,EAAA,EAAD,UACE,eAACC,EAAA,EAAD,CAASpL,IAAKC,IAAMP,GAAI6K,EAAcc,OAAQhI,IAAakH,EAA3D,UACE,cAAC,IAAD,CAAiBrK,KAAMoL,MADzB,qBAIF,cAACnB,EAAD,e,iJCgCK1F,IArDF,SAAC,GAA4B,IAA1BpE,EAAyB,EAAzBA,QACRsD,EAAWC,cACX2H,EAAcC,YAAOnL,GACrBoL,GAAcC,YAAQH,GAS5B,OAPAlM,qBAAU,WAER,IAAMsM,EAAoBJ,EAAYK,MAAK,qBAAGC,eAE9CF,GAAqBhI,EAAS,WAAD,OAAYgI,EAAkB9L,OAC1D,IAGD,qBAAKtB,UAAU,OAAf,SACE,cAACuN,EAAA,EAAD,CAAMvN,UAAU,kBAAhB,SACE,eAACwN,EAAA,EAAD,CAAKC,WAAS,EAAd,UACE,qBAAKzN,UAAU,6BAAf,SACE,qBAAKA,UAAU,qBAAf,SACE,qBAAKA,UAAU,aAAf,SACE,cAACH,EAAA,EAAD,UAIN,sBAAKG,UAAU,mCAAf,UACE,qBAAKA,UAAU,sBAAf,SACE,oBAAIA,UAAU,cAAd,wBAEF,cAAC6B,EAAA,EAAD,CAAkBE,UAAQ,EAACD,QAASkL,EAApC,UACIE,GACA,sBAAKlN,UAAU,kBAAf,UACE,mBAAGA,UAAU,OAAb,wEACA,4BACE,eAAC,IAAD,CAAMmB,GAAG,iBAAiBnB,UAAU,sCAApC,UACE,cAAC,IAAD,CAAiB2B,KAAM+L,MADzB,IACoC,sBAAM1N,UAAU,OAAhB,+BAGtC,mBAAGA,UAAU,YAAb,SACE,cAAC,IAAD,CAAcsL,KAAK,kCAAnB,SACE,kCACE,sBAAMtL,UAAU,OAAhB,qCADF,IACwD,cAAC,IAAD,CAAiB2B,KAAMgM,8B,mJCqBtFtH,IA/DI,SACjBuH,EACAC,EACAvH,EACAwH,EACAC,EACAC,EACAC,EACAC,EACA1N,EACA2N,EACAC,EACAC,GAZiB,OAad/N,aAAmB,YAAyB,IAAtBO,EAAqB,EAArBA,eACnB2D,EAAWiC,cAD6B,EAEsBxD,cAFtB,mBAEtCqL,EAFsC,KAEtBC,EAFsB,KAEPpL,EAFO,KAEMC,EAFN,KAM9C,GAFAtC,qBAAU,kBAAMsC,MAAe,CAAEoB,KAE5BoG,YAAkB/J,GACrB,OAAO,cAACL,EAAD,IAGT,IAAMgO,EAAuBC,YAAqB5N,GAC5C6N,EAA0BC,YAAwB9N,GAClD+N,EAAwBC,YAAwBhO,GAChDiO,EAAgB5M,IAAW,2BAA4B,CAAE,mCAAoCoM,IAC7FS,EAAiB7L,YAAaC,EAAaC,GAEjD,OACE,qCACE,cAAC,IAAD,CAAiBzB,KAAMqN,IAAYhP,UAAW8O,EAAe9H,QAASuH,IAEtE,+CAASQ,GAAT,IAAyB/O,UAAU,yBAAnC,SACE,sBAAKA,UAAU,+BAAf,UACE,cAACsG,EAAD,CAAWzF,eAAgBA,EAAgBoO,aAAcX,IACzD,qBAAKtO,UAAU,yBAAyBgH,QAAS,kBAAM5D,KAAvD,SACE,qBAAKpD,UAAU,eAAf,SACE,eAAC,IAAD,WACE,cAAC,IAAD,CAAOkP,OAAK,EAACC,QAAS,cAAC,IAAD,CAAUC,SAAO,EAACjO,GAAG,eAC3C,cAAC,IAAD,CAAO6G,KAAK,YAAYmH,QAAS,cAAChB,EAAD,MACjC,cAAC,IAAD,CAAOnG,KAAK,yBAAyBmH,QAAS,cAACtB,EAAD,MAC9C,cAAC,IAAD,CAAO7F,KAAK,oBAAoBmH,QAAS,cAACrB,EAAD,MACzC,cAAC,IAAD,CAAO9F,KAAK,kCAAkCmH,QAAS,cAACpB,EAAD,MACvD,cAAC,IAAD,CAAO/F,KAAK,8BAA8BmH,QAAS,cAACf,EAAD,MACnD,cAAC,IAAD,CAAOpG,KAAK,qBAAqBmH,QAAS,cAACnB,EAAD,MACzCQ,GAAwB,cAAC,IAAD,CAAOxG,KAAK,mBAAmBmH,QAAS,cAAClB,EAAD,MAChES,GAA2B,cAAC,IAAD,CAAO1G,KAAK,uBAAuBmH,QAAS,cAACjB,EAAD,MACxE,cAAC,IAAD,CAAOlG,KAAK,eAAemH,QAAS,cAACvB,EAAD,MACnCgB,GAAyB,cAAC,IAAD,CAAO5G,KAAK,kBAAkBmH,QAAS,cAACd,EAAD,MACjE,cAAC,IAAD,CACErG,KAAK,IACLmH,QAAS,cAACjO,EAAA,EAAD,CAAUC,GAAE,kBAAaN,EAAeS,GAA5B,sBAAZ,iDASxBd,K,2HC/CG6O,EAAwC,SAAC,GAAD,IAAGjO,EAAH,EAAGA,SAAUD,EAAb,EAAaA,GAAInB,EAAjB,EAAiBA,UAAcsP,EAA/B,oDAC5C,cAAC,IAAD,yBACEtP,UAAW,gBAAGuP,EAAH,EAAGA,SAAH,OAAkBrN,IAAW,mBAAoBlC,EAAW,CAAE,6BAA8BuP,KACvGpO,GAAIA,GACAmO,GAHN,aAKGlO,MA4DUkF,IAxDG,SAACkJ,GAAD,OAAqD,YAEjE,IADF3O,EACC,EADDA,eACC,IADeoO,oBACf,SACGQ,EAAQ/E,YAAe7J,GACvBE,EAAW0O,EAAQ5O,EAAeS,GAAK,GACrCwD,EAAa2B,cAAb3B,SACF4K,EAAuBb,YAAwBhO,GAC/C8O,EAAazN,IAAW,aAAc,CAC1C,sBAAuB+M,IAEnBlH,EAAY,SAAC6H,GAAD,wBAA+B7O,GAA/B,OAA0C6O,IAE5D,OACE,uBAAO5P,UAAW2P,EAAlB,SACE,sBAAK3P,UAAU,kCAAf,UACE,eAAC,EAAD,CAAemB,GAAI4G,EAAU,aAA7B,UACE,cAAC,IAAD,CAAiB8H,YAAU,EAAClO,KAAMmO,MAClC,sBAAM9P,UAAU,wBAAhB,yBAEF,eAAC,EAAD,CACEmB,GAAI4G,EAAU,sBACd/H,UAAWkC,IAAW,CAAE,6BAAqE,OAAvC4C,EAASqF,MAAM,sBAFvE,UAIE,cAAC,IAAD,CAAiB0F,YAAU,EAAClO,KAAMoO,MAClC,sBAAM/P,UAAU,wBAAhB,gCAEF,eAAC,EAAD,CAAemB,GAAI4G,EAAU,qBAA7B,UACE,cAAC,IAAD,CAAiB8H,YAAU,EAAClO,KAAMqO,IAAYC,KAAK,eACnD,sBAAMjQ,UAAU,wBAAhB,iCAEF,eAAC,EAAD,CAAemB,GAAI4G,EAAU,gBAA7B,UACE,cAAC,IAAD,CAAiB8H,YAAU,EAAClO,KAAMuO,MAClC,sBAAMlQ,UAAU,wBAAhB,4BAED0P,GACC,eAAC,EAAD,CAAevO,GAAI4G,EAAU,mBAA7B,UACE,cAAC,IAAD,CAAiB8H,YAAU,EAAClO,KAAMwO,MAClC,sBAAMnQ,UAAU,wBAAhB,+BAGJ,eAAC,EAAD,CAAemB,GAAI4G,EAAU,SAAU/H,UAAU,yBAAjD,UACE,cAAC,IAAD,CAAiB6P,YAAU,EAAClO,KAAMyO,MAClC,sBAAMpQ,UAAU,wBAAhB,iCAEDyP,GACC,cAACD,EAAD,CACExP,UAAU,4CACVqQ,cAAc,wBACd7F,OAAQ3J,Y,sECrFpB,kNAGa+I,EAAU,SAAI0G,EAAcC,GAAlB,IAAmDC,EAAnD,uDAA6D,EAA7D,OACrBC,YAAMD,EAASF,EAAO,GAAGnO,IAAIoO,IAIlBG,EAAW,SAAIrM,GAAJ,OAAsC4F,YAAM5F,KAAW8I,YAAQ9I,IAE1EsM,EAA+B,SAAIC,GAAJ,OAAyB3F,aACnE,SAAC3H,GAAD,OAAuBA,EAAEuN,mBACzBD,IAeWE,EAAsB,SAAIzM,GAAJ,OAA2B8I,YAAQ9I,GAAS,KAAOA,GAEzE0M,EAAa,SAAmB1M,GAAnB,gBAA2CA,EAAM2M,OAAO,GAAGC,eAA3D,OAA2E5M,EAAM6M,MAAM,M,uHCpBpGC,EAAa,SAAC,GAAD,IAAGC,EAAH,EAAGA,MAAOhQ,EAAV,EAAUA,SAAUiQ,EAApB,EAAoBA,cAAkB/B,EAAtC,2DACxB,eAAC,IAAD,2BAAUA,GAAV,cACG8B,GAAS,cAAC,IAAD,UAAaA,IACvB,cAAC,IAAD,CAAUpR,UAAWqR,EAArB,SAAqCjQ,U,gCCZzC,4aAGMkQ,EAAwB,SAACC,GAAD,OAAwB,SAAC1Q,GAAD,OACpD+J,YAAkB/J,IAAmB2Q,YAAa3Q,EAAeX,QAASqR,KAE/DE,EAA4BH,EAAsB,CAAEI,WAAY,UAEhEC,EAAwBL,EAAsB,CAAEI,WAAY,UAE5DjD,EAAuBkD,EAEvBC,EAAuBD,EAEvBE,EAAsBF,EAEtBG,EAAoBR,EAAsB,CAAEI,WAAY,UAExDK,EAA0BD,EAE1BE,EAA4BV,EAAsB,CAAEI,WAAY,UAEhE7C,EAA0BmD,EAE1BC,EAAuBX,EAAsB,CAAEI,WAAY,UAE3DQ,EAAwCZ,EAAsB,CAAEI,WAAY,WAE5E/C,EAA0B2C,EAAsB,CAAEI,WAAY,W,wEC5B3E,gRAAO,IAAM3R,EAAa,UAEboS,EAAmB,0BAEnBC,EAAoB,UAEpBC,EAA0B,0BAE1BC,EAAsB,QAEtBC,EAAqB,UAIrBC,EAAsB,SAACC,GAAkB,IAAD,EAC7CC,EAAO9O,SAAS+O,qBAAqB,QAEvC,OAAJD,QAAI,IAAJA,GAAA,UAAAA,EAAO,UAAP,SAAWE,aAAa,aAAcH,IAG3BI,EAAqB,WAAgB,IAAD,EACzCH,EAAO9O,SAAS+O,qBAAqB,QAE3C,MAAiD,UAAtC,OAAJD,QAAI,IAAJA,GAAA,UAAAA,EAAO,UAAP,eAAWI,aAAa,iB,gCCvBjC,0FAEanO,EAAa,SAAIC,GAAJ,OAAuBmO,IAAG1K,MAAMzD,EAAQ,CAAEoO,mBAAmB,KAE1EjO,EAAiB,SAACL,GAAD,OAAwBqO,IAAGvK,UAAU9D,EAAO,CAAEuO,YAAa,e,6FCInFC,EAAkB,SAACC,GAMvB,MALyC,CACvCxM,MAAO,gBACPyM,QAAS,IAGAD,IAEPE,EAAsB,SAACF,GAM3B,MALyC,CACvCxM,MAAO,cACPyM,QAAS,cAGAD,IA+BEG,IArBmB,SAAC,GAAmF,IAAjFtT,EAAgF,EAAhFA,UAAWoB,EAAqE,EAArEA,SAAqE,IAA3DH,eAA2D,aAA1CkS,YAA0C,MAAnC,UAAmC,MAAxBI,iBAAwB,SAC7G5H,EAAUzJ,IAAW,CACzB,YAAaqR,EACb,yBAA0BA,IAG5B,OACE,cAAC,IAAD,CAAK9F,WAAS,EAACzN,UAAWA,EAA1B,SACE,qBAAKA,UAAW2L,EAAhB,SACE,cAAC,IAAD,CAAM3L,UAAWkT,EAAgBC,GAAOK,MAAI,EAA5C,SACE,qBAAIxT,UAAWkC,IAAW,mBAAoBmR,EAAoBF,IAAlE,UACGlS,GAAW,cAAC,IAAD,CAAiBU,KAAM8R,IAAWC,MAAI,IACjDzS,GAAW,sBAAMjB,UAAU,OAAhB,gBAAwBoB,QAAxB,IAAwBA,IAAY,gBAC9CH,GAAWG,a,qKCtCrBuS,E,6KCASC,EAAoB,SAC/BC,EACAC,EACAC,GAEA,OAAIF,IAAiBC,EACZ,MAQFC,EAL+C,CACpDC,IAAK,OACLC,UAAMnR,GAG6BiR,GAAmB,OAG7CG,EAAW,SAAOC,EAAP,OAAuBC,EAAvB,EAAuBA,MAAOC,EAA9B,EAA8BA,IAA9B,OAAqED,GAAUC,EAEnGF,EAAKG,MAAK,SAACC,EAAGlL,GACd,IAAMmL,EAAsB,QAARH,EAAgB,GAAK,EACnCI,EAAsB,QAARJ,GAAiB,EAAI,EAEzC,OAAOE,EAAEH,GAAS/K,EAAE+K,GAASI,EAAcC,KAL3CN,GAQSO,EAAgB,SAAIC,GAAJ,OAC3BA,EAAMN,IAAN,UAAeM,EAAMP,MAArB,YAA8BO,EAAMN,UAAQvR,GAEjC8R,EAAgB,SAAID,GAA6B,IAAD,EACpCA,EAAME,MAAM,KADwB,mBAG3D,MAAO,CAAET,MAHkD,KAG3CC,IAH2C,OCbvDS,EAAqB,SAACtN,GAAD,OAAiBA,EAAG,UAAMA,EAAN,YAAsB,IAC/DuN,EAAiBC,YAAO/K,KACxBgL,EAA2B,SAACvU,GAA4E,IAAD,EACzEA,EAA1BwU,eADmG,MACzF,GADyF,EAClF5F,EADkF,YACzE5O,EADyE,aAG3G,OAAO,2BAAK4O,GAAZ,IAAkB4F,QAASR,EAAcQ,MAGtBC,EACnB,WACmBvP,EACAwP,EACA3K,GAChB,IAAD,gCAHiB7E,QAGjB,KAFiBwP,UAEjB,KADiB3K,SACjB,KAGc4K,cAHd,sBAG8B,wCAAAd,EAAA,6DAAO7T,EAAP,+BAA2C,GAA3C,kBAC9B,EAAK4U,eAAuD,cAAe,MAAOL,EAAyBvU,IACxG6U,MAAK,qBAAGhO,KAAgBiO,cAFG,2CAH9B,KAOcC,eAPd,uCAO+B,WAAOC,GAAP,eAAAnB,EAAA,6DACzBoB,EAAkBX,aAAO,SAAC3Q,GAAD,OAAW8I,YAAQ9I,IAAU4F,YAAM5F,KAAQqR,GAD3C,kBAGxB,EAAKJ,eAAyB,cAAe,OAAQ,GAAIK,GAC7DJ,MAAK,SAACK,GAAD,OAAUA,EAAKrO,SAJQ,2CAP/B,2DAccsO,kBAdd,uCAckC,WAAOC,EAAmBpR,GAA1B,SAAA6P,EAAA,+EAClC,EAAKe,eAAL,sBAA6DQ,EAA7D,WAAiF,MAAOpR,GACrF6Q,MAAK,qBAAGhO,KAAgBwO,WAFO,2CAdlC,6DAkBcC,aAlBd,uCAkB6B,WAAOvU,EAAaiD,GAApB,SAAA6P,EAAA,+EAC7B,EAAKe,eAAL,gBAAuD7T,EAAvD,WAAqE,MAAOiD,GACzE6Q,MAAK,qBAAGhO,KAAgBwO,WAFE,2CAlB7B,6DAsBcE,gBAtBd,uCAsBgC,WAAOvR,GAAP,SAAA6P,EAAA,+EAChC,EAAKe,eAAyC,iBAAkB,MAAO5Q,GACpE6Q,MAAK,qBAAGhO,KAAgBwO,WAFK,2CAtBhC,2DA0BcG,mBA1Bd,uCA0BmC,WAAOxR,GAAP,SAAA6P,EAAA,+EACnC,EAAKe,eAAyC,qBAAsB,MAAO5Q,GACxE6Q,MAAK,qBAAGhO,KAAgBwO,WAFQ,2CA1BnC,2DA8BcI,kBA9Bd,sBA8BkC,sBAAA5B,EAAA,+EAClC,EAAKe,eAAiD,UAAW,OAC9DC,MAAK,qBAAGhO,KAAgBwO,WAFO,2CA9BlC,KAkCcK,YAlCd,uCAkC4B,WAAON,EAAmBO,GAA1B,SAAA9B,EAAA,+EAC5B,EAAKe,eAAL,sBAA6CQ,GAAa,MAAO,CAAEO,WAChEd,MAAK,qBAAGhO,SAFiB,2CAlC5B,6DAsCc+O,eAtCd,uCAsC+B,WAAOR,EAAmBO,GAA1B,SAAA9B,EAAA,+EAC/B,EAAKe,eAAL,sBAAmCQ,GAAa,SAAU,CAAEO,WACzDd,MAAK,gBAFuB,2CAtC/B,6DA8CcgB,mBA9Cd,uCA8CmC,WACnCT,EACAO,EACAG,GAHmC,SAAAjC,EAAA,+EAKnC,EAAKe,eAAL,sBAAuDQ,EAAvD,SAAyE,MAAO,CAAEO,UAAU,CAAEG,SAC3FjB,MAAK,qBAAGhO,KAAgBiP,SANQ,2CA9CnC,+DAsDcC,eAtDd,uCAsD+B,WAC/BX,EACAO,EACA9O,GAH+B,SAAAgN,EAAA,+EAK/B,EAAKe,eAAL,sBAA6CQ,GAAa,QAAS,CAAEO,UAAU9O,GAC5EgO,MAAK,qBAAGhO,SANoB,2CAtD/B,+DA8DcmP,SA9Dd,sBA8DyB,sBAAAnC,EAAA,+EACzB,EAAKe,eAA6C,QAAS,MAAO,CAAEqB,UAAW,SAC5EpB,MAAK,SAACK,GAAD,OAAUA,EAAKrO,KAAKiP,QACzBjB,MAAK,kBAAsB,CAAEiB,KAAxB,EAAGjP,KAAiCqP,MAApC,EAASA,WAHQ,2CA9DzB,KAmEcC,WAnEd,uCAmE2B,WAAOL,GAAP,SAAAjC,EAAA,+EAC3B,EAAKe,eAAe,QAAS,SAAU,CAAEkB,SACtCjB,MAAK,iBAAO,CAAEiB,YAFU,2CAnE3B,2DAuEcM,QAvEd,uCAuEwB,WAAOC,EAAiBC,GAAxB,SAAAzC,EAAA,+EACxB,EAAKe,eAAe,QAAS,MAAO,GAAI,CAAEyB,UAASC,YAChDzB,MAAK,iBAAO,CAAEwB,UAASC,eAFF,2CAvExB,6DA2EcC,OA3Ed,sBA2EuB,sBAAA1C,EAAA,+EACvB,EAAKe,eAA6B,UAAW,OAC1CC,MAAK,SAACK,GAAD,OAAUA,EAAKrO,SAFA,2CA3EvB,KA+Ec2P,YA/Ed,sBA+E4B,sBAAA3C,EAAA,+EAC5B,EAAKe,eAAkC,gBAAiB,OACrDC,MAAK,SAACK,GAAD,OAAUA,EAAKrO,SAFK,2CA/E5B,KAmFc4P,YAnFd,sBAmF4B,sBAAA5C,EAAA,+EAC5B,EAAKe,eAAmD,WAAY,OAAOC,MAAK,qBAAGhO,KAAgB6P,YADvE,2CAnF5B,KAsFcC,oBAtFd,uCAsFoC,WACpCC,GADoC,SAAA/C,EAAA,+EAGpC,EAAKe,eAAsC,qBAAsB,QAAS,GAAIgC,GAAiB/B,MAAK,qBAAGhO,SAHnE,2CAtFpC,2DA2Fe+N,eA3Ff,uCA2FgC,WAAU9N,GAAV,+BAAA+M,EAAA,6DAAuBgD,EAAvB,+BAAwC,MAAO7S,EAA/C,+BAAuD,GAAI8O,EAA3D,+BAAkE,GAAlE,kBAChC,EAAK5N,MAAM,CACT2R,SACA/P,IAAI,GAAD,OAAKsN,EAAmB,EAAKM,UAA7B,OAAwC5N,GAC3CgQ,QAAS,CAAE,YAAa,EAAK/M,QAC7B/J,OAAQqU,EAAerQ,GACvB6C,KAAMiM,EACNiE,iBAAkB1S,OAPY,2CA3FhC,uDC9BE2S,EAA8C,GA6BrCC,EArBc,SAAC/R,GAAD,OAAkD,SAC7EgS,GAEA,IAPkCC,EAO5BrN,EATW,SAACoN,GAAD,MACmB,oBAA7BA,EAQQE,CAAWF,IAPQC,EAQHD,EAR0CG,YAAK,iBAAkBF,MAS5FD,EAEJ,IAAKrN,YAAcC,GACjB,MAAM,IAAIwN,MAAM,iDANf,IASKxQ,EAAgBgD,EAAhBhD,IAAKiD,EAAWD,EAAXC,OACPwN,EAAS,UAAMzQ,EAAN,YAAaiD,GAM5B,OAJKiN,EAAWO,KACdP,EAAWO,GAAa,IAAI9C,EAAgBvP,EAAO4B,EAAKiD,IAGnDiN,EAAWO,KCzBL3S,EAJS,SAACC,GACvBA,EAAOQ,eAAe,uBAAwB4R,EAAsB,U,kEJwDvDO,EA3CK,SAAC,GAAkG,IAAhGC,EAA+F,EAA/FA,SAAUnY,EAAqF,EAArFA,UAAqF,IAA1EoY,aAA0E,aAA5DC,gBAA4D,aAA1C9V,oBAA0C,MAA3B,GAA2B,IAC9EE,mBAASF,GADqE,mBAC5G+V,EAD4G,KAChGC,EADgG,KAG9GC,EAAa,WACjB7E,GAASrR,aAAaqR,GACtBA,EAAQ,MAEJ8E,EAAoB,SAACC,GAA8D,IAAvC9V,EAAsC,uDAlB1D,IAmB5B2V,EAAcG,GAEdF,IAEA7E,EAAQtR,YAAW,WACjB8V,EAASO,GACTF,MACC5V,IAGL,OACE,sBAAK5C,UAAWkC,IAAW,eAAgBlC,GAA3C,UACE,uBACEmT,KAAK,OACLnT,UAAWkC,IAAW,mCAAoC,CACxD,kBAAmBkW,EACnB,iCAAkCC,IAEpCM,YAAY,YACZtU,MAAOiU,EACPH,SAAU,SAAC7U,GAAD,OAAOmV,EAAkBnV,EAAEsV,OAAOvU,UAE9C,cAAC,IAAD,CAAiB1C,KAAMkX,IAAY7Y,UAAU,uBAC7C,qBACEA,UAAU,4BACV8Y,OAAuB,KAAfR,EACRhX,GAAG,sBACH0F,QAAS,kBAAMyR,EAAkB,GAAI,IAJvC,sBKvBSM,EAXW,SAAC,GAAD,IAAGC,EAAH,EAAGA,KAAM5X,EAAT,EAASA,SAAU6X,EAAnB,EAAmBA,UAAnB,IAA8BjZ,iBAA9B,MAA0C,GAA1C,EAA8CkZ,EAA9C,EAA8CA,eAAgBlS,EAA9D,EAA8DA,QAASmS,EAAvE,EAAuEA,QAAvE,OACxB,uBACEnZ,UAAWkC,IAAW,YAAalC,EAAW,CAAE,gBAAiBkZ,EAAepP,mBAAmBkP,KACnGI,MAAO,CAAEC,gBAAiBH,EAAezP,eAAeuP,GAAOM,OAAQL,IAAcjS,EAAU,OAAS,WACxGA,QAASA,EAHX,iBAKG5F,QALH,IAKGA,IAAY4X,EACZC,GAAa,sBAAMjZ,UAAU,gCAAgCgH,QAASmS,EAAzD,sB,4CCPLI,EAAoC,SAAC,GAE5C,IADFP,EACC,EADDA,KACC,IADKQ,gBACL,aADuBxZ,iBACvB,MADmC,GACnC,EADuCoB,EACvC,EADuCA,SAAUqY,EACjD,EADiDA,kBACjD,IADoEC,aACpE,SADmFC,EACnF,EADmFA,SACnF,EACwB1W,cADxB,mBACK4I,EADL,KACa+N,EADb,KAEGC,EAAa,yCAAqC7Z,GAClDoZ,EAAQ,CAAEO,SAAUA,GAAQ,UAAOA,EAAP,OAElC,OACE,eAACG,EAAA,EAAD,CAAUjO,OAAQA,EAAQ+N,OAAQA,EAAQJ,SAAUA,EAAUxZ,UAAWyZ,EAAzE,UACE,cAACM,EAAA,EAAD,CAAgBC,OAAK,EAACha,UAAW6Z,EAAe/Z,MAAM,UAAtD,SAAiEkZ,IACjE,cAACiB,EAAA,EAAD,CAAcja,UAAU,QAAQ0Z,MAAOA,EAAON,MAAOA,EAArD,SAA6DhY,Q,qHCjBtD8Y,GAAe,SAACC,GAAD,MAAsD,kBAATA,GAEnEC,GAAuB,SAACD,EAAqBE,GACjD,OAAKF,GAASD,GAAaC,GAIpBE,EAAYC,mBAAOH,EAAME,GAAaE,aAAUJ,GAH9CA,GAQEK,GAAgB,SAACL,GAAD,OAAyBC,GAAqBD,OAAMrX,IAEpE2X,GAJa,eAACH,EAAD,uDAAU,aAAV,OAA2B,SAACH,GAAD,OAAyBC,GAAqBD,EAAMG,IAItEI,GAItBC,GAAW,SAACR,GAAD,OAA8BD,GAAaC,GAAQA,EAAOS,kBAAYT,IAEjFU,GAAY,SAACV,EAAoBW,EAAsBC,GAClE,IACE,OAAOC,mBAAiBL,GAASR,GAAO,CAAEW,MAAOH,GAAQ,OAACG,QAAD,IAACA,IAASX,GAAOY,IAAKJ,GAAQ,OAACI,QAAD,IAACA,IAAOZ,KAC/F,MAAO7W,GACP,OAAO,IAIE2X,GAAkB,SAACd,EAAqBe,GAAtB,OAC7BC,mBAAQhB,EAAMe,IAAkBE,mBAASjB,EAAMe,ICzBpCG,GAAmB,SAACC,GAAD,YAAkDxY,IAAdwY,GAC/DnO,YAAQoO,aAAOC,QAASF,KAEhBG,GAAkB,SAAChL,GAAD,MACZ,kBAAVA,GAEHiL,GAAmE,CACvEC,MAAO,QACPC,UAAW,YACXC,UAAW,cACXC,WAAY,eACZC,WAAY,eACZC,YAAa,gBACbC,YAAa,gBACbC,SAAKpZ,GAGMqZ,GAAiBC,OAAOC,KAAKX,IAAwBH,QAAO,SAAClX,GAAD,MAAqB,QAAVA,KAkBvEiY,GAA0B,SAAC7L,GACtC,GAAKA,GAAmB,QAAVA,EAId,OAAKgL,GAAgBhL,GAIdiL,GAAuBjL,GAzBN,SAACA,GACzB,GAAKA,IAAS4K,GAAiB5K,GAI/B,OAAIA,EAAM8L,YAAc9L,EAAM+L,QACtB,SAAN,OAAgB/B,GAAoBhK,EAAM8L,aAGvC9L,EAAM8L,WAAa9L,EAAM+L,QACtB,SAAN,OAAgB/B,GAAoBhK,EAAM+L,UAGtC,GAAN,OAAU/B,GAAoBhK,EAAM8L,WAApC,cAAoD9B,GAAoBhK,EAAM+L,UASrEC,CAAkBhM,IAMvBiM,GAAiB,SAACC,GAAD,OAAqBC,kBAAWC,mBAAQ,IAAIC,KAAQH,KACrEI,GAAc,SAACR,GAAD,MAAiC,CAAEA,YAAWC,QAASQ,mBAAS,IAAIF,QAE3EG,GAAsB,SAACC,GAClC,IAAKA,GAAiC,QAAjBA,EACnB,MAAO,GAGT,OAAQA,GACN,IAAK,QACH,OAAOH,GAAYH,kBAAW,IAAIE,OACpC,IAAK,YACH,MAAO,CAAEP,UAAWG,GAAe,GAAIF,QAASQ,mBAASH,mBAAQ,IAAIC,KAAQ,KAC/E,IAAK,YACH,OAAOC,GAAYL,GAAe,IACpC,IAAK,aACH,OAAOK,GAAYL,GAAe,KACpC,IAAK,aACH,OAAOK,GAAYL,GAAe,KACpC,IAAK,cACH,OAAOK,GAAYL,GAAe,MACpC,IAAK,cACH,OAAOK,GAAYL,GAAe,MAGtC,MAAO,IAGIS,GAAyB,SAAChD,GACrC,IAAMiD,EAAgBzC,GAASR,GAE/B,OAAOkD,aAA0B,CAC/B,CAAE,kBAAMpC,GAAgB2B,kBAAW,IAAIE,MAASM,IAAU,iBAAM,UAChE,CAAE,kBAAMnC,GAAgByB,GAAe,GAAIU,IAAU,iBAAM,cAC3D,CAAE,kBAAMnC,GAAgByB,GAAe,GAAIU,IAAU,iBAAM,cAC3D,CAAE,kBAAMnC,GAAgByB,GAAe,IAAKU,IAAU,iBAAM,eAC5D,CAAE,kBAAMnC,GAAgByB,GAAe,IAAKU,IAAU,iBAAM,eAC5D,CAAE,kBAAMnC,GAAgByB,GAAe,KAAMU,IAAU,iBAAM,gBAC7D,CAAE,kBAAMnC,GAAgByB,GAAe,KAAMU,IAAU,iBAAM,gBAC7D,CAAEE,KAAG,iBAAM,SARND,I,8BCtDME,GAzBG,SAAC9c,GAA2B,IACpCT,EAAqCS,EAArCT,UAAWwd,EAA0B/c,EAA1B+c,YAAaC,EAAahd,EAAbgd,SAC1BC,GAAoBF,GAAevT,YAAMwT,GACzCE,EAAM9a,mBAEZ,OACE,sBAAK7C,UAAU,uBAAf,UACE,cAAC,KAAD,2BACMS,GADN,IAEEmd,WAAW,aACX5d,UAAWkC,IAAW,2CAA4ClC,GAElE2d,IAAKA,KAEND,GACC,cAAC,IAAD,CACE/b,KAAMkc,KACN7d,UAAU,6BACVgH,QAAS,kCAAM2W,EAAI3a,eAAV,aAAM,EAAa8a,MAAMC,eCS7BC,GA5BM,SAAC,GAAD,QACjBzB,iBADiB,MACL,KADK,MACCC,eADD,MACW,KADX,MACiBhD,gBADjB,SACmCyE,EADnC,EACmCA,kBAAmBC,EADtD,EACsDA,gBADtD,OAGnB,sBAAKle,UAAU,MAAf,UACE,qBAAKA,UAAU,WAAf,SACE,cAAC,GAAD,CACEyd,SAAUlB,EACV4B,gBAAgB,WAChBX,aAAW,EACXY,QAAO,OAAE5B,QAAF,IAAEA,SAAW1Z,EACpB0W,SAAUA,EACVrB,SAAU8F,MAGd,qBAAKje,UAAU,WAAf,SACE,cAAC,GAAD,CACEA,UAAU,eACVyd,SAAUjB,EACV2B,gBAAgB,WAChBX,aAAW,EACXa,QAAO,OAAE9B,QAAF,IAAEA,SAAazZ,EACtB0W,SAAUA,EACVrB,SAAU+F,UCrBLI,GAA2D,SAAC,GAAD,IAAGxR,EAAH,EAAGA,OAAQyR,EAAX,EAAWA,QAASpG,EAApB,EAAoBA,SAApB,OACtE,qCACE,cAACqG,EAAA,EAAD,CAAc1R,OAAmB,QAAXA,EAAkB9F,QAAS,kBAAMmR,EAAS,QAAhE,SACGoG,IAEH,cAACC,EAAA,EAAD,CAAcC,SAAO,IACpBtC,GAAeha,KACd,SAACuc,GAAD,OACE,cAACF,EAAA,EAAD,CAA6B1R,OAAQA,IAAW4R,EAAU1X,QAAS,kBAAMmR,EAASuG,IAAlF,SACGpC,GAAwBoC,IADRA,UCKdC,GAAoB,SAAC,GAE5B,IAAD,EADDC,EACC,EADDA,cAAeC,EACd,EADcA,iBAAkBC,EAChC,EADgCA,YAAatF,EAC7C,EAD6CA,SAC7C,IADuDuF,iBACvD,SACGC,EAAyBvD,GAAgBoD,GAD5C,EAE2Cpc,mBAASuc,EAAyBH,OAAmB/b,GAFhG,mBAEKmc,EAFL,KAEqBC,EAFrB,OAG6Czc,mBAASuc,OAAyBlc,EAAY+b,GAH3F,mBAGKM,EAHL,KAGsBC,EAHtB,KAKGC,EAAkB,SAAC/D,GACvB4D,EAAkB7D,GAAiBC,GAAa,WAAQxY,GACxDsc,EAAmB9D,GACnBsD,EAActD,IAEVgE,EAAiB,SAACpC,GACtBgC,EAAkBhC,GAClBkC,OAAmBtc,GACnB8b,EAAc3B,GAAoBC,KAUpC,OAPA6B,GAAa/Z,aAAyB,WACpC,IAAMua,EAAiB9D,GAAgBoD,GAEvCU,GAAkBD,EAAeT,GACjCA,IAAqBU,GAAkBF,EAAgBR,KACtD,CAAEA,IAGH,eAAC,EAAD,CAAarF,SAAUA,EAAUR,KAAI,UAAEsD,GAAuB,OAAC2C,QAAD,IAACA,IAAkBE,UAA5C,QAAgEL,EAArG,UACE,cAAC,GAAD,CAA2BP,QAASO,EAAahS,OAAQmS,EAAgB9G,SAAUmH,IACnF,cAACd,EAAA,EAAD,CAAcC,SAAO,IACrB,cAACD,EAAA,EAAD,CAAcgB,QAAM,EAApB,qBACA,cAAChB,EAAA,EAAD,CAAcxF,MAAI,EAAlB,SACE,cAAC,GAAD,2BACMmG,GADN,IAEElB,kBAAmB,SAAC1B,GAAD,OAAe8C,EAAgB,2BAAKF,GAAN,IAAuB5C,gBACxE2B,gBAAiB,SAAC1B,GAAD,OAAa6C,EAAgB,2BAAKF,GAAN,IAAuB3C,uB,SC5BjEiD,GAAoB,WAC/B,IAAMra,EAAWC,eACXb,EAAWiC,eACX/F,EAASC,eAET+D,EAAQgb,kBACZzU,aACE,kBAAMtG,YAA2BH,EAASI,WAC1C,gBAAGsQ,EAAH,EAAGA,QAAY5F,EAAf,kCAA+D4F,EAAD,2BACzD5F,GADyD,IAE5D4F,QAASN,EAAwCM,KAFsB5F,KAK3E,CAAE9K,EAASI,SAWb,MAAO,CAAEF,EAToB,SAACib,GAAwC,IAAD,6BAC1Bjb,GAAUib,GAA3CzK,EAD2D,EAC3DA,QAAY0K,EAD+C,2BAE7DC,EAA+B,2BAAQD,GAAR,IAAqB1K,QAASA,GAAWR,EAAcQ,KACtF4K,EAAe/a,YAAe8a,GAC9BE,EAAc5S,YAAQ2S,GAAgB,GAAxB,WAAiCA,GAErD1a,EAAS,WAAD,OAAY1E,EAAOK,SAAnB,6BAAgDgf,OCrCtDC,GAAa,SAAC7F,GAAD,OAAmBA,EAAOQ,kBAASR,GAAQ,MAqD/C8F,GAnDe,SAAC/G,GAAD,OAAoC,WAAO,IAAD,IACTuG,KADS,0BAC7D7a,EAD6D,EAC7DA,OAAQ4R,EADqD,EACrDA,KAAM+F,EAD+C,EAC/CA,UAAWC,EADoC,EACpCA,QAAW0D,EADyB,KAEhEC,EAAY,iBAAG3J,QAAH,IAAGA,OAAH,EAAGA,EAAM3B,MAAM,YAAf,QAAuB,GACnCuL,EAAWnV,aACf,oBAAGsR,EAAH,EAAGA,UAAWC,EAAd,EAAcA,QAAd,MAAwC,CACtCD,UAAS,UAAE/B,GAAc+B,UAAhB,aAA8BzZ,EACvC0Z,QAAO,UAAEhC,GAAcgC,UAAhB,aAA4B1Z,KAErCod,GAEIG,EAAYpV,aAChB,SAACqN,GAAD,OAAwBnL,YAAQmL,QAAcxV,EAAYwV,KAC1D,SAAC1T,GAAD,OAAYsb,EAAY,CAAEtb,cAEtB0b,EAAYrV,aAChB,SAACxJ,GAAD,OAAiB0e,EAAa5E,QAAO,SAACgF,GAAD,OAAiBA,IAAgB9e,QACtE,SAAC+e,GAAD,OAAkC,IAApBA,EAASxe,YAAec,EAAY0d,EAAS3W,KAAK,QAChE,SAAC2M,GAAD,OAAU0J,EAAY,CAAE1J,YAG1B,OACE,sBAAKxW,UAAU,qCAAf,UACE,cAAC,EAAD,CAAauC,aAAcqC,EAAQuT,SAAUkI,IAE7C,qBAAKrgB,UAAU,OAAf,SACE,qBAAKA,UAAU,MAAf,SACE,qBAAKA,UAAU,4CAAf,SACE,cAAC,GAAD,CACE8e,YAAY,iBACZD,iBAAkB,CAChBtC,UAAWyD,GAAWzD,GACtBC,QAASwD,GAAWxD,IAEtBoC,cAAewB,UAMtBD,EAAane,OAAS,GACrB,qBAAIhC,UAAU,8CAAd,UACE,cAAC,IAAD,CAAiB2B,KAAMuO,IAAUlQ,UAAU,wCAD7C,OAGGmgB,EAAahe,KAAI,SAACV,GAAD,OAChB,cAAC,EAAD,CAAKyX,eAAgBA,EAA0BF,KAAMvX,EAAKwX,WAAS,EAACE,QAAS,kBAAMmH,EAAU7e,KAAnDA,c,uCC3C/C,SAASgf,GAAT,GAEJ,IAAD,EADEC,EACF,EADEA,MAAO/L,EACT,EADSA,MAAOwD,EAChB,EADgBA,SAChB,IAD0BwI,gBAC1B,aAD2CjH,aAC3C,SACMkH,EAAkB,SAACC,GAAD,OAAiB,WACvC,IAAMC,EAAclN,EAAkBiN,EAAUlM,EAAMP,MAAOO,EAAMN,KAEnE8D,EAAS2I,EAAcD,OAAW/d,EAAWge,KAG/C,OACE,eAACC,GAAA,EAAD,WACE,eAAChH,EAAA,EAAD,CACEC,OAAK,EACLla,MAAO6gB,EAAW,UAAY,OAC9B3gB,UAAWkC,IAAW,CAAE,iCAAkCye,EAAU,cAAeA,IAHrF,WAKIA,GAAY,gDACbA,IAAahM,EAAMP,OAAS,mDAC5BuM,GAAYhM,EAAMP,OAAlB,qBAAyCsM,EAAM/L,EAAMP,OAArD,0BAAmEO,EAAMN,WAAzE,QAAgF,OAAhF,QAEH,eAAC4F,EAAA,EAAD,CACEP,MAAOA,EACP1Z,UAAWkC,IAAW,QAAS,CAAE,iCAAkCye,IAFrE,UAIGK,aAAQN,GAAOve,KAAI,mCAAG0e,EAAH,KAAaI,EAAb,YAClB,eAACzC,EAAA,EAAD,CAA6B1R,OAAQ6H,EAAMP,QAAUyM,EAAU7Z,QAAS4Z,EAAgBC,GAAxF,UACGI,EACAtM,EAAMP,QAAUyM,GACf,cAAC,IAAD,CACElf,KAAoB,QAAdgT,EAAMN,IAAgB6M,IAAcC,IAC1CnhB,UAAU,mCALG6gB,MAUrB,cAACrC,EAAA,EAAD,CAAcC,SAAO,IACrB,cAACD,EAAA,EAAD,CAAchF,UAAW7E,EAAMP,MAAOpN,QAAS,kBAAMmR,KAArD,SACE,wD,cCxCH,SAASiJ,GACd7gB,EACA8gB,GAEA,IAAMC,EAAiB,IAAIC,IAE3B,OAAO,SAAC9gB,GAAkC,IAChC+gB,EAAkD/gB,EAAlD+gB,gBAAiBC,EAAiChhB,EAAjCghB,gBAAiBvK,EAAgBzW,EAAhByW,YAClCwH,EAAaxH,EAAbwH,SACFhe,EAASC,eAmBf,OAjBAG,qBAAU,WACR,IACM4gB,EAASL,EAAkB5gB,EAAOC,GAClCihB,ECxBsB,SAAIzK,EAA0BwK,EAAkBE,EAAiCC,GAA+B,IACxIC,EAAyC5K,EAAzC4K,cAAeC,EAA0B7K,EAA1B6K,MAAO9gB,EAAmBiW,EAAnBjW,QAAS0F,EAAUuQ,EAAVvQ,MAEvC,IAAI1F,IAAW0F,GAAUmb,EAAzB,CAIA,IAAME,EAAuB,SAAC,GAAD,IAAGza,EAAH,EAAGA,KAAH,OAAgCqa,EAAUxZ,KAAKC,MAAMd,KAC5E0a,EAAqB,SAAC,GAAD,OAA+C,MAA/C,EAAGC,QAAmDL,KAE3EM,EAAgBT,EAAOvf,KAAI,SAACigB,GAChC,IAAMC,EAAS,IAAI5a,IAAIqa,GAEvBO,EAAOC,aAAaC,OAAO,QAASH,GACpC,IAAMI,EAAK,IAAIC,uBAAYJ,EAAQ,CACjC7K,QAAS,CACPkL,cAAc,UAAD,OAAYX,MAO7B,OAHAS,EAAGG,UAAYX,EACfQ,EAAGI,QAAUX,EAENO,KAGT,OAAO,kBAAML,EAAcU,SAAQ,SAACL,GAAD,OAAQA,EAAGzW,aDFjB+W,CAAmB5L,EAAawK,GAFvC,SAACqB,GAAD,OAAwBrE,EAAW4C,EAAe0B,IAAID,GAASvB,EAAgB,CAAEuB,MAEvBtB,GAE5E,IAAK/C,EACH,OAAOiD,EAGT,IAAMhO,EAAQsP,aAAY,WACxBzB,EAAgB,aAAKF,IACrBA,EAAe4B,UACH,IAAXxE,EAAkB,IAErB,OAAOzT,aAAK,kBAAMkY,cAAcxP,MAAQ,yBAAMgO,QAAN,IAAMA,OAAN,EAAMA,SAC7C,CAAEzK,IAEE,cAAC3W,EAAD,eAAsBE,KEzC1B,IAAM2iB,GAAb,kCCUO,SAASC,GAAT,GAEJ,IADCC,EACF,EADEA,aAAclP,EAChB,EADgBA,MAChB,IADuBpU,iBACvB,MADmC,OACnC,EACA,OAAKsjB,EAAajP,KAAOiP,EAAalP,QAAUA,EAIzC,cAAC,IAAD,CAAiBzS,KAA2B,QAArB2hB,EAAajP,IAAgBkP,IAAcC,IAAexjB,UAAWA,IAH1F,KDdEojB,GACYrN,OAAS,8BADrBqN,GAGYK,aAAe,qCAH3BL,GAKYM,eAAiB,SAAC5N,GAAD,4CAAsDA,I,yBEkD5F6N,G,qDClDSC,GAAe,SAA2BzhB,EAAkCiC,GAA7D,OAAqF,SAC/GwC,EACAid,GACW,IACH1Q,EAAS0Q,EAAT1Q,KACF2Q,EAAgB3hB,EAAIgR,GACpB4Q,EAAY,OAAGnd,QAAH,IAAGA,IAASxC,EAE9B,OAAO0f,EAAgBA,EAAcC,EAAcF,GAAUE,IAGlDC,GAAqB,SAAmB7Q,GAAnB,OAA+B,iBAAkB,CAAEA,UCPxE8Q,GAAe,sCAEfC,GAA8C,CACzD9P,MAAO,cACPC,IAAK,QAiDDjQ,GAAyB,CAC7B+f,gBAAiB,CACfC,SAAS,GAEXC,iBAAkB,CAChBC,cAAc,GAEhBC,GAAI,CACF9R,MAAO,SAETsD,OAAQ,CACNyO,gBAAiB,cAEnBC,cAAe,CACbC,gBAAiBR,KAQNN,MAAY,eACxBK,IAAe,SAACrd,EAAOid,GAAR,OAAmBc,aAAe/d,EAAOge,aAAO,OAAQf,OACvEzf,IAEUygB,GAAwB,SAACT,GAAD,MAA8C,CACjFjR,KAAM8Q,GACNE,gBAAiB,CAAEC,aAGRU,GAA6B,SAACpG,GAAD,MAA8C,CACtFvL,KAAM8Q,GACNE,gBAAiB,CAAEzF,cAGRqG,GAA8B,SAACC,GAAD,MAAgE,CACzG7R,KAAM8Q,GACNI,iBAAkBW,IAGPC,GAA2B,SAACD,GAAD,MAA6D,CACnG7R,KAAM8Q,GACNQ,cAAeO,IAGJE,GAAgB,SAACF,GAAD,MAAkD,CAC7E7R,KAAM8Q,GACNM,GAAIS,IAGOG,GAAoB,SAACH,GAAD,MAAsD,CACrF7R,KAAM8Q,GACNlO,OAAQiP,IAGGI,GAAkB,SAACJ,GAAD,MAAoD,CACjF7R,KAAM8Q,GACNzN,KAAMwO,I,4DCvHAK,GAAS1c,KAAT0c,KACFC,GAAY,IAAIC,KAAKC,aAAa,SAE3BC,GAAW,SAACC,GAAD,OAA6BJ,GAAUhL,OAAOqL,OAAOD,KCChEE,GAAW,MAMXC,GAAwB,SAACC,EAAqBC,GACzD,IAAMC,EAA4BvV,aAChCwV,aAVU,EAUCH,EAVD,GAWVI,aAAIH,EAAY,EAAGD,EAXT,GAWgC,GAa5C,OAVIA,EAdQ,KAeVE,EAAMG,QAAQP,IAEZE,EAjBQ,EAiBcC,EAAY,GACpCC,EAAMI,KAAKR,IAGbI,EAAMG,QAAQ,GACdH,EAAMI,KAAKL,GAEJC,GAGIK,GAAiB,SAACC,GAAD,OAA0DA,IAAeV,IAE1FW,GAAqB,SAACD,GAAD,OAChCD,GAAeC,GAAcA,EAAab,GAASa,IAExCE,GAAa,SAACF,EAA8BpX,GAA/B,OAAkDmX,GAAeC,GAAhB,UAAmDA,EAAnD,YAAiEpX,GAAjE,UAAiCoX,ICiB7FG,GAnCG,SAAC,GAAsE,IAApEC,EAAmE,EAAnEA,UAAW3lB,EAAwD,EAAxDA,SAAwD,IAA9C4lB,0BAA8C,MAAzB,GAAyB,WAC1CD,QAD0C,IAC1CA,IAAa,GAD6B,IAC9EZ,mBAD8E,MAChE,EADgE,MAC7Dc,kBAD6D,MAChD,EADgD,EAEhFC,EAAa,SAACP,GAAD,wBACNvlB,EADM,4BACsBulB,GADtB,OACmCK,IAEtD,GAAIC,GAAc,EAChB,OAAO,KAgBT,OACE,eAACE,GAAA,EAAD,CAAY9mB,UAAU,wBAAwB+mB,cAAc,wCAA5D,UACE,cAACC,GAAA,EAAD,CAAgBxN,SAA0B,IAAhBsM,EAA1B,SACE,cAACmB,GAAA,EAAD,CAAgBC,UAAQ,EAACzlB,IAAKC,IAAMP,GAAI0lB,EAAWf,EAAc,OAfrED,GAAsBC,EAAac,GAAYzkB,KAAI,SAACmkB,EAAYpX,GAAb,OACjD,cAAC8X,GAAA,EAAD,CAEExN,SAAU6M,GAAeC,GACzBxZ,OAAQgZ,IAAgBQ,EAH1B,SAKE,cAACW,GAAA,EAAD,CAAgBxlB,IAAKC,IAAMP,GAAI0lB,EAAWP,GAA1C,SACGC,GAAmBD,MALjBE,GAAWF,EAAYpX,OAgB9B,cAAC8X,GAAA,EAAD,CAAgBxN,SAAUsM,GAAec,EAAzC,SACE,cAACK,GAAA,EAAD,CAAgBE,MAAI,EAAC1lB,IAAKC,IAAMP,GAAI0lB,EAAWf,EAAc,WCQxDsB,GAA8B,CACzCC,YAAa,aACbvR,UAAW,YACXwR,QAAS,WACTlW,MAAO,QACP2E,OAAQ,UC0BKlI,GA5DO,SAAC0Z,EAAyCtH,GAA1C,OAAwEmB,IAAkB,YAKrF,IAAD,MAJxB/L,EAIwB,EAJxBA,cACAoP,EAGwB,EAHxBA,cACA5jB,EAEwB,EAFxBA,eACAmkB,EACwB,EADxBA,SAEMjkB,EAAW8J,YAAYhK,GACrB2mB,EAAS7mB,eAAT6mB,KACFhjB,EAAWiC,eAHO,EAI8CgZ,KAJ9C,0BAIfjJ,EAJe,EAIfA,KAAM5R,EAJS,EAITA,OAAQ2X,EAJC,EAIDA,UAAWC,EAJV,EAIUA,QAAStH,EAJnB,EAImBA,QAAWgL,EAJ9B,OAKoBzd,mBAAQ,QAAC,EAAD,OAElDyS,QAFkD,IAElDA,IAFkD,UAEvC8P,EAASP,qBAF8B,aAEvC,EAAwBC,uBAFe,QAEIR,IAPhC,mBAKhBuD,EALgB,KAKDC,EALC,KASlBvH,EAAeT,mBAAQ,yCAAMlJ,QAAN,IAAMA,OAAN,EAAMA,EAAM3B,MAAM,YAAlB,QAA0B,KAAI,CAAE2B,IACrDmR,GAVgB,iBAUDlD,QAVC,IAUDA,OAVC,EAUDA,EAAejP,iBAVd,QAU2B,IAA3CmS,WACFC,EAAgB,SAACxT,EAAkCC,GACvD6L,EAAY,CAAEhL,QAAS,CAAEd,QAAOC,SAChCqT,EAAiB,CAAEtT,QAAOC,SAMtBwT,EAAS5c,aACb,SAAC6c,GAAD,OAAoB,aAAK,IAAIvG,IAAJ,uBAAapB,GAAb,CAA2B2H,MAAYje,KAAK,QACrE,SAAC2M,GAAD,OAAU0J,EAAY,CAAE1J,YAc1B,OAXA1V,qBAAU,WACRuU,EAAc,CACZmS,OACAlP,WAAY1T,EACZ4R,KAAM2J,EACN5D,YACAC,UACAtH,QAASuS,MAEV,CAAED,EAAM5iB,EAAQub,EAAc5D,EAAWC,EAASiL,IAGnD,qCACE,qBAAKznB,UAAU,OAAf,SAAsB,cAACigB,EAAD,MACtB,qBAAKjgB,UAAU,yBAAf,SACE,cAACygB,GAAD,CAAkBC,MAAO0G,GAA6BzS,MAAO8S,EAAetP,SAAUyP,MAExF,eAACra,GAAA,EAAD,CAAMiG,MAAI,EAACxT,UAAU,OAArB,UACE,cAACunB,EAAD,CACE1mB,eAAgBA,EAChB4jB,cAAeA,EACfsD,cA9Bc,SAAC3T,GAAD,OAAqC,kBACzDwT,EAAcxT,EAAOR,EAAkBQ,EAAOqT,EAAcrT,MAAOqT,EAAcpT,QA8B3E2T,gBA7BgB,SAAC5T,GAAD,OACtB,cAACiP,GAAD,CAAgBC,aAAcmE,EAAerT,MAAOA,KA6B9C6T,WAAYJ,IAEd,cAAC,GAAD,CAAWnB,UAAWiB,EAAY5mB,SAAUA,EAAU4lB,mBAAoBniB,EAASI,kBAIxF,iBAAM,CAAEwe,GAAOrN,Y,8BCxELmS,GAAoD,SAAC,GAAD,IAAGlP,EAAH,EAAGA,KAAMmP,EAAT,EAASA,OAAT,OAC/D,cAAC,KAAD,CAAiBnP,KAAMA,EAAMmP,OAAQA,EAArC,SACE,cAAC,IAAD,CAAiBxmB,KAAMymB,KAAUpoB,UAAU,mC,oBCJlCqoB,GAAO,SAAC,GAAwE,IAAtElO,EAAqE,EAArEA,KAAqE,IAA/DG,cAA+D,MAAtD,mBAAsD,MAAlCgO,gBAAkC,SACpFC,EAAarO,GAAaC,GAAQA,EAAOQ,kBAASR,GAExD,OACE,sBAAMqO,SAAQ,UAAKC,aAAYF,GAAjB,OAAd,SACGD,EAAQ,UAAMI,aAAe,IAAI5L,KAAQyL,GAAjC,QAAqD7N,mBAAW6N,EAAYjO,M,UCDrFqO,GAAW,SAAC,EAAD,EAAwD/Y,GAAwB,IAA7EtO,EAA4E,EAA5EA,GAAsBwU,EAAsD,EAAtDA,UAAWO,EAA2C,EAA3CA,OAC7C3R,EAAQ2R,EAAM,kBAAcA,GAAW,GAE7C,MAAM,WAAN,OAAkB/U,EAAlB,uBAAmCwU,EAAnC,YAAgDlG,GAAhD,OAAyDlL,IAa5CkkB,GAVwE,SAAC,GAElF,IADF/nB,EACC,EADDA,eAAgBgoB,EACf,EADeA,SAAUjZ,EACzB,EADyBA,OAAQxO,EACjC,EADiCA,SAAakO,EAC9C,iEACH,OAAKzO,GAAmB6J,YAAe7J,IAAoBgoB,EAIpD,cAAC,IAAD,yBAAM1nB,GAAIwnB,GAAS9nB,EAAgBgoB,EAAUjZ,IAAaN,GAA1D,aAAiElO,KAH/D,gDAAUkO,GAAV,aAAiBlO,MCqCb0nB,GA1Ca,SAAC,GAAyF,IAAD,EAAtFC,EAAsF,EAAtFA,YAAaF,EAAyE,EAAzEA,SAAUhoB,EAA+D,EAA/DA,eAA+D,IAA/CiM,cAA+C,SAC7Gkc,EAAS,OAAGH,QAAH,IAAGA,GAAH,UAAGA,EAAUI,YAAb,aAAG,EAAgBD,UAC5BE,EACJ,cAAC,GAAD,CAAoBroB,eAAgBA,EAAgBgoB,SAAUA,EAAUjZ,OAAO,SAA/E,SACE,wBACE5P,UAAWkC,IAAW,iCAAkC,CAAE,sCAAuC4K,IADnG,SAGG2Y,GAASsD,OAKhB,IAAKC,EACH,OAAOE,EAGT,IAAMC,EAAsB1D,GAASuD,GAC/BI,EAAavmB,mBAEnB,OACE,qCACE,uBAAM7C,UAAU,cAAhB,UACGkpB,EACD,wBACElpB,UAAU,8CACV2d,IAAK,SAAC0L,GACJD,EAAWpmB,QAAUqmB,GAHzB,UAMG,IANH,KAMUF,EAAqB,IAC7B,8BACE,cAAC,IAAD,CAAiBxnB,KAAM2nB,cAI7B,eAACC,GAAA,EAAD,CAAqB3Q,OAAS,kBAAMwQ,EAAWpmB,SAAiBwmB,UAAU,SAA1E,sDAC2C,4BAAIL,IAD/C,kBCqCSM,GAtEM,SACnBC,EACAxQ,EACA9W,GAHmB,OAIhB,YAAkE,IAAD,EAKhDoU,EALdqS,EAA8D,EAA9DA,SAAUhoB,EAAoD,EAApDA,eAAgBonB,EAAoC,EAApCA,WAAoC,EAChB7lB,IADgB,mBAC5DunB,EAD4D,KACzCC,EADyC,OAEtCxnB,GAAoB,EAAO,KAFW,mBAE5D0K,EAF4D,KAEpD+c,EAFoD,KAG9DC,EAAajnB,kBAAO,GAyB1B,OARA/B,qBAAU,WACJgpB,EAAW9mB,QACb8mB,EAAW9mB,SAAU,EAErB6mB,MAED,CAAEhB,EAASE,cAGZ,qBAAI/oB,UAAU,wBAAd,UACE,oBAAIA,UAAU,0DAA0D+pB,UAAQ,aAAhF,SACE,cAAC,GAAD,CAAM5P,KAAM0O,EAASxB,gBAEvB,oBAAIrnB,UAAU,8CAA8C+pB,UAAQ,YAApE,SACE,uBAAM/pB,UAAU,6CAAhB,UACE,cAAC,KAAD,CAAcsL,KAAMud,EAASA,WAC7B,cAAC,GAAD,CAAqB7P,KAAM6P,EAASA,SAAUV,OAAQyB,IACtD,sBAAM5pB,UAAU,gDAAgD8Y,QAAS6Q,EAAzE,oCAKJ,oBAAI3pB,UAAU,0EAA0E+pB,UAAA,UAAYlB,EAASzX,MAAQ,QAAU,YAA/H,SACE,cAAC,KAAD,CAAc9F,KAAMud,EAASvB,QAA7B,mBAAuCuB,EAASzX,aAAhD,QAAyDyX,EAASvB,YAEnEuB,EAASzX,OACR,oBAAIpR,UAAU,oFAAoF+pB,UAAQ,WAA1G,SACE,cAAC,KAAD,CAAcze,KAAMud,EAASvB,YAGjC,oBAAItnB,UAAU,8CAA8C+pB,UAAQ,OAApE,UA7CgBvT,EA6CuEqS,EAASrS,KA5C9FrJ,YAAQqJ,GACH,mBAAGxW,UAAU,cAAb,SAA2B,8CAG7BwW,EAAKrU,KAAI,SAACV,GAAD,OACd,cAAC,EAAD,CACEyX,eAAgBA,EAEhBF,KAAMvX,EACNuF,QAAS,yBAAMihB,QAAN,IAAMA,OAAN,EAAMA,EAAaxmB,KAFvBA,SAsCP,oBAAIzB,UAAU,4DAA4D+pB,UAAQ,SAAlF,SACE,cAAC,GAAD,CACEhB,YAAaF,EAASE,YACtBF,SAAUA,EACVhoB,eAAgBA,EAChBiM,OAAQA,MAGZ,oBAAI9M,UAAU,8CAAd,SACE,cAAC0pB,EAAD,CAAkB7oB,eAAgBA,EAAgBgoB,SAAUA,W,UCxEvDmB,GAA4C,SAAC,GAAD,IAAGne,EAAH,EAAGA,OAAQ+N,EAAX,EAAWA,OAAQxY,EAAnB,EAAmBA,SAAnB,IAA6BsY,aAA7B,gBACvD,eAACuQ,GAAA,EAAD,CAAgBrQ,OAAQA,EAAQ/N,OAAQA,EAAxC,UACE,eAACkO,EAAA,EAAD,CAAgBzJ,KAAK,KAAK0J,OAAK,EAACjT,SAAO,EAAC/G,UAAU,qCAAlD,iBACQ,cAAC,IAAD,CAAiB2B,KAAMuoB,MAD/B,UAGA,cAACjQ,EAAA,EAAD,CAAcP,MAAOA,EAArB,SAA6BtY,QCqClBsoB,GAjCU,SACvBS,EACAC,GAFuB,OAGpB,YAA0D,IAAvDvB,EAAsD,EAAtDA,SAAUhoB,EAA4C,EAA5CA,eAA4C,EACjCoC,cADiC,mBACpD4I,EADoD,KAC5C+N,EAD4C,OAEpB3W,cAFoB,mBAEpDonB,EAFoD,KAErCC,EAFqC,OAGhBrnB,cAHgB,mBAGpDsnB,EAHoD,KAGjCC,EAHiC,KAK5D,OACE,eAAC,GAAD,CAAiB5Q,OAAQA,EAAQ/N,OAAQA,EAAzC,UACE,eAAC2S,EAAA,EAAD,CAAc/c,IAAKmnB,GAAoB/nB,eAAgBA,EAAgBgoB,SAAUA,EAAUjZ,OAAO,SAAlG,UACE,cAAC,IAAD,CAAiBjO,KAAM8oB,IAAc5a,YAAU,IADjD,kBAIA,eAAC2O,EAAA,EAAD,CAAc/c,IAAKmnB,GAAoB/nB,eAAgBA,EAAgBgoB,SAAUA,EAAUjZ,OAAO,OAAlG,UACE,cAAC,IAAD,CAAiBjO,KAAMyO,IAAUP,YAAU,IAD7C,qBAIA,eAAC2O,EAAA,EAAD,CAAcxX,QAASsjB,EAAvB,UACE,cAAC,IAAD,CAAiB3oB,KAAM+oB,IAAQ7a,YAAU,IAD3C,cAGA,cAACua,EAAD,CAAavB,SAAUA,EAAUhd,OAAQwe,EAAezQ,OAAQ0Q,IAEhE,cAAC9L,EAAA,EAAD,CAAcC,SAAO,IAErB,eAACD,EAAA,EAAD,CAAcxe,UAAU,wBAAwBgH,QAASwjB,EAAzD,UACE,cAAC,IAAD,CAAiB7oB,KAAMgpB,IAAY9a,YAAU,IAD/C,uBAGA,cAACsa,EAAD,CAAqBtB,SAAUA,EAAUhd,OAAQ0e,EAAmB3Q,OAAQ4Q,SCkBnE1c,GAhCQ,SAAC8c,EAAqCC,GAAtC,OAA8F,YAOlF,IANjCpV,EAMgC,EANhCA,eACAqV,EAKgC,EALhCA,uBACAC,EAIgC,EAJhCA,oBACAlqB,EAGgC,EAHhCA,eAGgC,IAFhCmqB,iBAEgC,SADFC,EACE,EADhCjG,SAAYX,iBAENjgB,EAAesb,mBAAQ,kBAvBP,SAACsF,GAAD,cAAwD,CAC9EsC,QAAS,GACT9Q,KAAM,GACN0U,WAAY,GACZ9Z,WAAOtO,EACPqoB,qBAAiBroB,EACjBuT,OAAQ,GACR+U,gBAAYtoB,EACZuoB,gBAAYvoB,EACZkmB,eAAWlmB,EACXwoB,cAAc,EACdC,YAAW,iBAAEvG,QAAF,IAAEA,OAAF,EAAEA,EAAUV,oBAAZ,SACXkH,aAAY,iBAAExG,QAAF,IAAEA,OAAF,EAAEA,EAAUwG,oBAAZ,UAWuBC,CAAgBR,KAA2B,CAAEA,IAEhF,OACE,qCACE,cAACL,EAAD,CACExmB,aAAcA,EACdsnB,OAAQZ,EAAuBY,OAC/B7qB,eAAgBA,EAChB8qB,KAAMX,EAAY,eAAiB,SACnCY,OAAM,uCAAE,WAAOrkB,GAAP,SAAAgN,EAAA,6DACNwW,IADM,kBAGCtV,EAAelO,IAHhB,2CAAF,wDAMR,cAACsjB,EAAD,2BACMC,GADN,IAEEC,oBAAqBA,EACrBc,YAAab,U,8EChDRc,GAA0B,SAAC,GAAD,IAAG1qB,EAAH,EAAGA,SAAU+R,EAAb,EAAaA,KAAMnT,EAAnB,EAAmBA,UAAnB,IAA8B+rB,aAA9B,gBACrC,cAACve,GAAA,EAAD,CAAKxN,UAAWA,EAAhB,SACE,qBAAKA,UAAWkC,IAAW,CAAE,yBAA0B6pB,EAAO,SAAUA,IAAxE,SACE,cAAC5a,GAAA,EAAD,CACEnR,UAAWkC,IAAW,cAAe,CACnC,UAAoB,YAATiR,EACX,YAAsB,UAATA,EACb,aAAuB,YAATA,EACd,aAAuB,YAATA,IAEhB9B,cAAenP,IAAW,CAAE,MAAO6pB,IAPrC,SASG3qB,SCtBI4qB,GAAgB,SAAC1oB,GAAD,uBAAwCA,EAAE2oB,gBAA1C,aAAwC,EAAY1kB,MAKpE2kB,GAAyB,SAACvlB,GAAD,MACpB,gCAAX,OAALA,QAAK,IAALA,OAAA,EAAAA,EAAOwM,OAAyD,gCAAX,OAALxM,QAAK,IAALA,OAAA,EAAAA,EAAOwM,OCD5CgZ,GAAiB,SAAC,GAAD,MDHSxlB,ECGNylB,EAAH,EAAGA,UAAWC,EAAd,EAAcA,gBAAd,OAC5B,sDACGD,QADH,IACGA,OADH,EACGA,EAAWE,cADd,QACwBD,GDLa1lB,ECMXylB,EDLV,sBAAX,OAALzlB,QAAK,IAALA,OAAA,EAAAA,EAAOwM,OCMH,oBAAGnT,UAAU,OAAb,gCAAwCosB,EAAUG,gBAAgB1iB,KAAK,MAAvE,YC6DSsgB,GAzDa,SAAC,GAEvB,IADFtB,EACC,EADDA,SAAUjP,EACT,EADSA,OAAQ/N,EACjB,EADiBA,OAAQ2gB,EACzB,EADyBA,iBAAkBC,EAC3C,EAD2CA,oBAAqBnW,EAChE,EADgEA,eAChE,EACmC7T,mBAAS,IAD5C,mBACKiqB,EADL,KACiBC,EADjB,KAGH7rB,qBAAU,kBAAM2rB,IAAqB,IAHlC,IAKK9lB,EAAqB6lB,EAArB7lB,MAAOylB,EAAcI,EAAdJ,UACTrgB,EAAQd,YAAKwhB,EAAqB7S,GAClCgT,EAAkBjc,cAA6B,WAAO,IAClDmF,EAAsB+S,EAAtB/S,UAAWO,EAAWwS,EAAXxS,OAEnBC,EAAeR,EAAWO,GACvBd,KAAKqE,GACLiT,MAAMC,SAGX,OACE,cAACC,GAAA,EAAD,CAAOlhB,OAAQA,EAAQ+N,OAAQ7N,EAAOihB,UAAQ,EAA9C,SACE,uBAAMC,SAAUL,EAAhB,UACE,cAACM,GAAA,EAAD,CAAatT,OAAQ7N,EAArB,SACE,sBAAM/L,UAAU,cAAhB,gCAEF,eAACmtB,GAAA,EAAD,WACE,8BAAG,mBAAGntB,UAAU,cAAb,sBAAH,2CACA,2HACA,uCAAS,4BAAI6oB,EAAS/S,YAAtB,2BAEA,uBACE3C,KAAK,OACLnT,UAAU,eACV2Y,YAAW,iCAA4BkQ,EAAS/S,UAArC,KACXzR,MAAOqoB,EACPvU,SAAU,SAAC7U,GAAD,OAAOqpB,EAAcrpB,EAAEsV,OAAOvU,UAGzCsC,GACC,cAAC,GAAD,CAAQwM,KAAM+Y,GAAuBE,GAAa,UAAY,QAASL,OAAK,EAAC/rB,UAAU,OAAvF,SACE,cAAC,GAAD,CAAgBosB,UAAWA,EAAWC,gBAAgB,wDAI5D,eAACe,GAAA,EAAD,WACE,wBAAQja,KAAK,SAASnT,UAAU,eAAegH,QAAS+E,EAAxD,oBACA,wBACEoH,KAAK,SACLnT,UAAU,iBACVwZ,SAAUkT,IAAe7D,EAAS/S,WAAa0W,EAAiBvrB,QAHlE,SAKGurB,EAAiBvrB,QAAU,cAAgB,oB,UCDzC4pB,GA9Cc,SAACzoB,GAAD,OAA2C,YAElE,IADFuE,EACC,EADDA,MAAOylB,EACN,EADMA,UAAWiB,EACjB,EADiBA,OAAQtC,EACzB,EADyBA,oBACzB,IAD8Cc,mBAC9C,WAC6CzpB,IAD7C,mBACKkrB,EADL,KACsBC,EADtB,KAOH,GAJAzsB,qBAAU,WACRiqB,MACC,IAECpkB,EACF,OACE,eAAC,GAAD,CAAQwM,KAAK,QAAQnT,UAAU,OAA/B,UACG6rB,GAAe,cAAC,IAAD,CAAiBlqB,KAAM6rB,IAAWxtB,UAAU,sBAAsBgH,QAAS+jB,IAC3F,cAAC,GAAD,CAAgBqB,UAAWA,EAAWC,gBAAgB,mDAK5D,GAAIpiB,YAAMojB,GACR,OAAO,KAjBN,IAoBKxE,EAAawE,EAAbxE,SAER,OACE,eAAC,GAAD,CAAQ1V,KAAK,UAAUnT,UAAU,OAAjC,UACG6rB,GAAe,cAAC,IAAD,CAAiBlqB,KAAM6rB,IAAWxtB,UAAU,sBAAsBgH,QAAS+jB,IAC3F,uCAFF,qBAEiC,4BAAIlC,IAEnC,cAAC,KAAD,CAAiB7P,KAAM6P,EAAUV,OAAQoF,EAAzC,SACE,yBACEvtB,UAAU,yDACVsB,GAAG,UACH6R,KAAK,SAHP,UAKE,cAAC,IAAD,CAAiBxR,KAAMymB,OALzB,aASF,cAACqF,GAAA,EAAD,CAASjE,UAAU,OAAO3d,OAAQyhB,EAAiB1U,OAAO,UAA1D,0B,8BCrDO8U,GAAkB,SAAC7E,EAAoB/S,EAAmBO,GACrE,OAAIpM,YAAMoM,GACDwS,EAAS/S,YAAcA,IAAc+S,EAASxS,OAGhDwS,EAAS/S,YAAcA,GAAa+S,EAASxS,SAAWA,GCNpDsX,GAAgB,qCAMhBnM,GAAkB,SAACoM,GAAD,MAAuD,CACpFza,KAAMwa,GACNC,kBCFWC,GAAyB,+CACzBC,GAAyB,+CACzBC,GAAoB,0CACpBC,GAAyB,+CAehC5pB,GAAiC,CACrC0R,UAAW,GACX7U,SAAS,EACT0F,OAAO,GAGMid,OAAY,qBACxBiK,IAAyB,SAACjnB,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB3F,SAAS,EAAM0F,OAAO,OAD/C,eAExBmnB,IAAyB,SAAClnB,EAAD,OAAUwlB,EAAV,EAAUA,UAAV,mBAAC,eAA+BxlB,GAAhC,IAAuCwlB,YAAWnrB,SAAS,EAAO0F,OAAO,OAF1E,eAGxBonB,IAAoB,SAACnnB,EAAD,OAAUkP,EAAV,EAAUA,UAAV,mBAAC,eAA+BlP,GAAhC,IAAuCkP,YAAW7U,SAAS,EAAO0F,OAAO,OAHrE,eAIxBqnB,IAAyB,kBAAM5pB,MAJP,IAKxBA,IAEUkS,GAAiB,SAACqB,GAAD,OAAkD,SAC9E7B,EACAO,GAF8E,8CAG3E,WAAO4X,EAAoBpW,GAA3B,iBAAAtD,EAAA,6DACH0Z,EAAS,CAAE9a,KAAM0a,KADd,EAEwBlW,EAAqBE,GAAxCvB,EAFL,EAEKA,eAFL,kBAKKA,EAAeR,EAAWO,GAL/B,OAMD4X,EAA+B,CAAE9a,KAAM4a,GAAmBjY,YAAWO,WANpE,sDAQD4X,EAAyB,CAAE9a,KAAM2a,GAAwB1B,UAAWJ,GAAc,EAAD,MARhF,8DAH2E,0DAiBnES,GAAsBzI,GAAmBgK,IC/CzCE,GAAyB,+CACzBC,GAAyB,+CACzBC,GAAmB,yCACnBC,GAAyB,+CAchCjqB,GAAiC,CACrCipB,OAAQ,KACR3B,QAAQ,EACR/kB,OAAO,GAGMid,OAAY,qBACxBsK,IAAyB,SAACtnB,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB8kB,QAAQ,EAAM/kB,OAAO,OAD9C,eAExBwnB,IAAyB,SAACvnB,EAAD,OAAUwlB,EAAV,EAAUA,UAAV,mBAAC,eAA+BxlB,GAAhC,IAAuC8kB,QAAQ,EAAO/kB,OAAO,EAAMylB,iBAFpE,eAGxBgC,IAAmB,SAACE,EAAD,SAAoB,CAAEjB,OAAtB,EAAMA,OAAwB3B,QAAQ,EAAO/kB,OAAO,MAH/C,eAIxB0nB,IAAyB,kBAAMjqB,MAJP,IAKxBA,IAEUqR,GAAiB,SAACkC,GAAD,OAAkD,SAACpQ,GAAD,8CAAwB,WACtG0mB,EACApW,GAFsG,mBAAAtD,EAAA,6DAItG0Z,EAAS,CAAE9a,KAAM+a,KAJqF,EAK3EvW,EAAqBE,GAAxCpC,EAL8F,EAK9FA,eAL8F,kBAQ/EA,EAAelO,GARgE,OAQ9F8lB,EAR8F,OAUpGY,EAA+B,CAAE9a,KAAMib,GAAkBf,WAV2C,sDAYpGY,EAAyB,CAAE9a,KAAMgb,GAAwB/B,UAAWJ,GAAc,EAAD,MAZmB,8DAAxB,0DAkBnEjB,GAAsB/G,GAAmBqK,I,SC9CzCE,GAAuB,8CACvBC,GAAuB,8CACvBC,GAAmB,0CAmBjB7K,OAAY,qBACxB2K,IAAuB,SAAC3nB,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB8kB,QAAQ,EAAM/kB,OAAO,OAD5C,eAExB6nB,IAAuB,SAAC5nB,EAAD,OAAUwlB,EAAV,EAAUA,UAAV,mBAAC,eAA+BxlB,GAAhC,IAAuC8kB,QAAQ,EAAO/kB,OAAO,EAAMylB,iBAFlE,eAGxBqC,IAAmB,SAACH,EAAD,SAAsB,CAAEzF,SAAxB,EAAMA,SAA4B6C,QAAQ,EAAO/kB,OAAO,MAHnD,IALW,CACpC+kB,QAAQ,EACR/kB,OAAO,IASI+nB,GAAe,SAAC/W,GAAD,OAAkD,SAC5E7B,EACAO,EACA9O,GAH4E,8CAIzE,WAAO0mB,EAAoBpW,GAA3B,+BAAAtD,EAAA,6DACH0Z,EAAS,CAAE9a,KAAMob,KADd,EAGwB1W,IAAnBhX,EAHL,EAGKA,eACF8tB,GAAsB9c,aAAoBhR,GAJ7C,EAK4C8W,EAAqBE,GAA5DpB,EALL,EAKKA,eAAgBF,EALrB,EAKqBA,mBALrB,kBAQ0BqY,QAAQ1S,IAAI,CACrCzF,EAAeX,EAAWO,EAAQ9O,GAClConB,GAAsBpnB,EAAKiP,KAAOD,EAAmBT,EAAWO,EAAQ9O,EAAKiP,WAAQ1T,IAVtF,mCAQO+lB,EARP,KAaDoF,EAA+B,CAAEpF,WAAU1V,KAAMsb,KAbhD,wDAeDR,EAAyB,CAAE9a,KAAMqb,GAAsBpC,UAAWJ,GAAc,EAAD,MAf9E,+DAJyE,0DC1BjE6C,GAAwB,6CACxBC,GAAwB,6CACxBC,GAAkB,uCA4BhBnL,OAAY,qBACxBiL,IAAwB,SAACjoB,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB3F,SAAS,EAAM0F,OAAO,OAD9C,eAExBmoB,IAAwB,iBAAO,CAAE7tB,SAAS,EAAO0F,OAAO,MAFhC,eAGxBooB,IAAkB,SAACT,EAAD,SAAuB,CAAErtB,SAAS,EAAO0F,OAAO,EAAO6O,UAAvD,EAAMA,cAHA,eAIxBuY,GAAoB9iB,aACnB,SAACrE,EAAD,OAAyBkP,EAAzB,EAAyBA,UAAWO,EAApC,EAAoCA,OAApC,OAAwEzP,EAAM4O,UAAoBwZ,aAChG,CAAE,YAAa,QACfha,aAAO,SAAC6T,GAAD,OAAc6E,GAAgB7E,EAAU/S,EAAWO,KAASzP,EAAM4O,UAAUjO,MACnFX,GAHwFA,KAK1F,SAACA,GAAD,OAAYA,EAAM4O,UAAoBwZ,aACpC,CAAE,YAAa,aAAc,cAC7BpoB,EAAM4O,UAAUmS,WAAWsH,WAAa,EACxCroB,GAH4BA,MAVP,eAgBxB+mB,IAAgB,SAAC/mB,EAAD,WAAUgnB,EAAV,EAAUA,cAAV,OAA8BoB,aAC7C,CAAE,YAAa,QADuC,UAEtDpoB,EAAM4O,iBAFgD,iBAEtD,EAAiBjO,YAFqC,aAEtD,EAAuBpF,KACrB,SAAC+sB,GAEC,IAAMC,EAAYC,aAChBxB,EAAcrS,QACZ,gBAAGsN,EAAH,EAAGA,SAAH,OAAkBA,GAAY6E,GAAgBwB,EAAiBrG,EAAS/S,UAAW+S,EAASxS,YAIhG,OAAgB,OAAT8Y,QAAS,IAATA,KAAWtG,SACdwG,aAAM,cAAeF,EAAUtG,SAASE,YAAamG,GACrDA,KAGRtoB,MAhCuB,eAkCxBwnB,GAAmBnjB,aAIlB,SAACrE,EAAD,OAAyBymB,EAAzB,EAAyBA,OAAzB,OAA6DzmB,EAAM4O,UAAoBwZ,aACrF,CAAE,YAAa,QAD+E,CAE5F3B,GAF4F,oBAEjFzmB,EAAM4O,UAAUjO,KAAK2J,MAAM,EAAGoe,KAC3C1oB,GAH6EA,KAK/E,SAACA,GAAD,OAA2BA,EAAM4O,UAAoBwZ,aACnD,CAAE,YAAa,aAAc,cAC7BpoB,EAAM4O,UAAUmS,WAAWsH,WAAa,EACxCroB,GAH2CA,MA3CtB,eAiDxB6nB,IAAmB,SAAC7nB,EAAD,OAAoB2oB,EAApB,EAAU1G,SAAV,OAA0CjiB,EAAM4O,UAAoBwZ,aACtF,CAAE,YAAa,QACfpoB,EAAM4O,UAAUjO,KAAKpF,KAAI,SAAC0mB,GAAc,IAC9B/S,EAAsByZ,EAAtBzZ,UAAWO,EAAWkZ,EAAXlZ,OAEnB,OAAOqX,GAAgB7E,EAAU/S,EAAWO,GAAUkZ,EAAiB1G,KAEzEjiB,GAP8EA,KAjDvD,IALS,CAClC3F,SAAS,EACT0F,OAAO,IA+DI0O,GAAgB,SAACsC,GAAD,OAAkD,eAC7EjX,EAD6E,uDACzC,GADyC,8CAE1E,WAAOutB,EAAoBpW,GAA3B,mBAAAtD,EAAA,6DACH0Z,EAAS,CAAE9a,KAAM0b,KADd,EAEuBlX,EAAqBE,GAAvCxC,EAFL,EAEKA,cAFL,kBAKuBA,EAAc3U,GALrC,OAKK8U,EALL,OAODyY,EAA8B,CAAE9a,KAAM4b,GAAiBvZ,cAPtD,gDASDyY,EAAS,CAAE9a,KAAM2b,KAThB,yDAF0E,0DCpFlEvH,GAAiB,SAACkC,GAAD,OAAyC,YAO3C,IAN1B1B,EAMyB,EANzBA,cACAC,EAKyB,EALzBA,gBACAvD,EAIyB,EAJzBA,cACAwD,EAGyB,EAHzBA,WACApnB,EAEyB,EAFzBA,eACAb,EACyB,EADzBA,UAEQ2G,EAA8B8d,EAA9B9d,MAAO1F,EAAuBwjB,EAAvBxjB,QAASuU,EAAciP,EAAdjP,UAClBga,EAAyBttB,IAAW,CAAE,+CAAgD6lB,IACtF0H,EAA0BvtB,IAAW,gCAAiCstB,GACtEE,EAAextB,IAAW,oBAAqBlC,GAC/C2vB,EAAgBhe,aAAsB9Q,GA+B5C,OACE,wBAAOb,UAAW0vB,EAAlB,UACE,uBAAO1vB,UAAU,oDAAjB,SACE,+BACE,qBAAIA,UAAWyvB,EAAyBzoB,QAAO,OAAE+gB,QAAF,IAAEA,OAAF,EAAEA,EAAgB,eAAjE,+BACcC,QADd,IACcA,OADd,EACcA,EAAkB,kBAEhC,qBAAIhoB,UAAWyvB,EAAyBzoB,QAAO,OAAE+gB,QAAF,IAAEA,OAAF,EAAEA,EAAgB,aAAjE,8BACaC,QADb,IACaA,OADb,EACaA,EAAkB,iBAE7B2H,GACA,qBAAI3vB,UAAWyvB,EAAyBzoB,QAAO,OAAE+gB,QAAF,IAAEA,OAAF,EAAEA,EAAgB,WAAjE,6BACYC,QADZ,IACYA,OADZ,EACYA,EAAkB,eAG9B,qBAAIhoB,UAAU,gCAAd,UACE,uBAAMA,UAAWwvB,EAAwBxoB,QAAO,OAAE+gB,QAAF,IAAEA,OAAF,EAAEA,EAAgB,SAAlE,0BACSC,QADT,IACSA,OADT,EACSA,EAAkB,YAF7B,oBAKE,uBAAMhoB,UAAWwvB,EAAwBxoB,QAAO,OAAE+gB,QAAF,IAAEA,OAAF,EAAEA,EAAgB,WAAlE,UACE,sBAAM/nB,UAAU,cAAhB,sBADF,WACiDgoB,QADjD,IACiDA,OADjD,EACiDA,EAAkB,iBAIvE,oBAAIhoB,UAAU,gCAAd,kBACA,oBAAIA,UAAWyvB,EAAyBzoB,QAAO,OAAE+gB,QAAF,IAAEA,OAAF,EAAEA,EAAgB,UAAjE,SACE,uBAAM/nB,UAAU,cAAhB,2BAAsCgoB,QAAtC,IAAsCA,OAAtC,EAAsCA,EAAkB,eAE1D,oBAAIhoB,UAAU,gCAAd,uBAGJ,gCA5DE2G,EAEA,6BACE,oBAAIipB,QAAS,EAAG5vB,UAAU,qCAA1B,gEAOFiB,EACK,6BAAI,oBAAI2uB,QAAS,EAAG5vB,UAAU,cAA1B,2BAGRiB,GAAWkM,YAAO,OAACqI,QAAD,IAACA,OAAD,EAACA,EAAWjO,MAC1B,6BAAI,oBAAIqoB,QAAS,EAAG5vB,UAAU,cAA1B,gCAGb,OAAOwV,QAAP,IAAOA,OAAP,EAAOA,EAAWjO,KAAKpF,KAAI,SAAC0mB,GAAD,OACzB,cAACY,EAAD,CAEEZ,SAAUA,EACVhoB,eAAgBA,EAChBonB,WAAYA,GAHPY,EAASA,oB,oBC5CTgH,GAA8C,SAAC,GAAD,IAAGvV,EAAH,EAAGA,OAAQwV,EAAX,EAAWA,UAAX,OACzD,eAAC,EAAD,CAAa9W,KAAI,kBAAasB,EAAb,KAAjB,UACE,cAACkE,EAAA,EAAD,CAAc1R,OAAmB,QAAXwN,EAAkBtT,QAAS,kBAAM8oB,EAAU,QAAjE,iBACA,cAACtR,EAAA,EAAD,CAAc1R,OAAmB,QAAXwN,EAAkBtT,QAAS,kBAAM8oB,EAAU,QAAjE,qBCHSC,GAAgE,SAAC,GAAD,IACzEC,EADyE,EACzEA,gBAAiBC,EADwD,EACxDA,mBADwD,OAG3E,eAAC,EAAD,CAAajX,KAAI,4BAAuBgX,EAAvB,KAAjB,UACE,eAACxR,EAAA,EAAD,CAAc1R,OAA4B,MAApBkjB,EAAyBhpB,QAAS,kBAAMipB,EAAmB,MAAjF,UACE,kCADF,QAGA,eAACzR,EAAA,EAAD,CAAc1R,OAA4B,MAApBkjB,EAAyBhpB,QAAS,kBAAMipB,EAAmB,MAAjF,UACE,kCADF,WAGA,eAACzR,EAAA,EAAD,CAAc1R,OAA4B,MAApBkjB,EAAyBhpB,QAAS,kBAAMipB,EAAmB,MAAjF,UACE,kCADF,aAGA,eAACzR,EAAA,EAAD,CAAc1R,OAA4B,MAApBkjB,EAAyBhpB,QAAS,kBAAMipB,EAAmB,MAAjF,UACE,kCADF,aC+FW7F,GA7FK,SAAC8F,EAAkCC,GAAnC,OAAsE,YAEpF,IAAD,IADDtH,SAAYA,EACX,EADWA,SAAU/S,EACrB,EADqBA,UAAa8D,EAClC,EADkCA,OAAQ/N,EAC1C,EAD0CA,OAAQhL,EAClD,EADkDA,eAClD,EACuB4B,mBAAS,KADhC,mBACK6N,EADL,KACW8f,EADX,OAE2B3tB,mBAAS,GAFpC,mBAEK4tB,EAFL,KAEaC,EAFb,OAG2B7tB,mBAAuB,OAHlD,mBAGK6X,EAHL,KAGawV,EAHb,OAI6CrtB,mBAA4B,KAJzE,mBAIKutB,EAJL,KAIsBC,EAJtB,KAKGM,EAAmC7Q,mBAAQ,iBAAO,CACtD8Q,eAAgB/e,aAA0B5Q,GAC1C4vB,kBAAmB7e,aAAqB/Q,GACxC6vB,2BAA4B1e,aAA0BnR,MACpD,CAAEA,IACA8vB,EAA0BJ,EAAaE,oBAAsBF,EAAaG,2BAC1EE,EAAYlR,mBAChB,kBCnB0B,SAC5BmJ,EAD4B,KAIhB,IAFVvY,EAES,EAFTA,KAAMgK,EAEG,EAFHA,OAAQ+V,EAEL,EAFKA,OAAQL,EAEb,EAFaA,gBACtBQ,EACS,EADTA,cAAeC,EACN,EADMA,kBAAmBC,EACzB,EADyBA,2BAE9Btb,EAAO,UAAMyT,EAAN,mBAAyB2H,EAAa,WAAOlgB,GAAS,IAC7D5L,EAAQK,YAAe,CAC3BuL,KAAMkgB,OAAgB1tB,EAAYwN,EAClCgK,SACA+V,OAAQI,GAAqBJ,EAAS,EAAIA,OAASvtB,EACnDktB,gBAAiBU,EAA6BV,OAAkBltB,IAGlE,MAAM,GAAN,OAAUsS,GAAV,OAAoBjI,YAAQzI,GAAS,GAAjB,WAA0BA,IDMtCmsB,CAAehI,EAAU,CAAEvY,OAAMgK,SAAQ+V,SAAQL,mBAAmBO,KAC1E,CAAE1H,EAAUvY,EAAMgK,EAAQ+V,EAAQL,EAAiBO,IAE/CO,EAAYpR,mBAAQ,kBAAMpP,EAAO+f,IAAQ,CAAE/f,EAAM+f,IACjDU,EAAYrR,mBAAQ,WACxB,KAAIoR,EAAY,KAIhB,OAAOA,EAAY,IAAM,KAAO,OAC/B,CAAEA,IAEL,OACE,eAAC/D,GAAA,EAAD,CAAOlhB,OAAQA,EAAQ+N,OAAQA,EAAQoT,UAAQ,EAAC1c,KAAMygB,EAAtD,UACE,eAAC7D,GAAA,EAAD,CAAatT,OAAQA,EAArB,yBACc,cAAC,KAAD,CAActO,KAAMud,EAApB,SAA+BA,OAE7C,eAACsE,GAAA,EAAD,WACE,eAAC3f,GAAA,EAAD,WACE,eAAC,KAAD,CACExN,UAAWkC,IAAW,CAAE,WAAYyuB,EAAyB,YAAaA,IAD5E,UAGE,wBAAO3wB,UAAU,OAAjB,mBAA+BsQ,EAA/B,QACA,uBACE6C,KAAK,QACLnT,UAAU,qBACVqE,MAAOiM,EACP0gB,KAAM,GACN9K,IAAK,GACLD,IAAK,IACL9N,SAAU,SAAC7U,GAAD,OAAO8sB,EAAQzK,OAAOriB,EAAEsV,OAAOvU,cAG5CksB,EAAaE,mBACZ,eAAC,KAAD,CAAWzwB,UAAW2wB,EAA0B,WAAa,WAA7D,UACE,wBAAO3wB,UAAU,OAAjB,qBAAiCqwB,EAAjC,QACA,uBACEld,KAAK,QACLnT,UAAU,qBACVqE,MAAOgsB,EACPW,KAAM,EACN9K,IAAK,EACLD,IAAK,IACL9N,SAAU,SAAC7U,GAAD,OAAOgtB,EAAU3K,OAAOriB,EAAEsV,OAAOvU,cAIjD,cAAC,KAAD,CAAWrE,UAAW2wB,EAA0B,WAAa,WAA7D,SACE,cAAC,GAAD,CAAkBrW,OAAQA,EAAQwV,UAAWA,MAE9CS,EAAaG,4BACZ,cAAC,KAAD,CAAW1wB,UAAU,WAArB,SACE,cAAC,GAAD,CAA2BgwB,gBAAiBA,EAAiBC,mBAAoBA,SAIvF,sBAAKjwB,UAAU,cAAf,UACE,sBAAKA,UAAU,OAAf,UACE,cAAC,KAAD,CAAcsL,KAAMslB,IACpB,cAAC,GAAD,CAAqB5X,KAAM4X,OAE7B,qBAAKK,IAAKL,EAAW5wB,UAAU,qBAAqBkxB,IAAI,YACxD,cAACf,EAAD,CAAkBze,WAAW,QAA7B,SACE,qBAAK1R,UAAU,OAAf,SACE,eAACmxB,GAAA,EAAD,CACEC,OAAK,EACLtxB,MAAM,UACNkH,QAAO,sBAAE,sBAAAuN,EAAA,+EAAY2b,EAAgBmB,UAAUT,EAA1B,UAAwC9a,EAAxC,oBAA6DwE,KAAzE,2CAHX,sBAKW,cAAC,IAAD,CAAiB3Y,KAAM2vB,IAActxB,UAAU,2B,wCEzEzDuxB,GAnByC,SAAC,GAEnD,IAAD,IADDC,eACC,aADgBrZ,gBAChB,MAD2B2U,KAC3B,EADqC9sB,EACrC,EADqCA,UAAWoB,EAChD,EADgDA,SAAU+R,EAC1D,EAD0DA,KAC1D,IADgEse,cAChE,SACcnwB,EAAOuB,iBAAO6uB,gBAAvB1uB,QAEF2uB,EAAc,CAClB,gBAA0B,WAATxe,EACjB,kBAA4B,aAATA,GAEfiG,EAAQqY,EAAS,CAAEG,QAAS,gBAAmB,GAErD,OACE,uBAAM5xB,UAAWkC,IAAW,iBAAkByvB,EAAa3xB,GAAYoZ,MAAOA,EAA9E,UACE,uBAAOjG,KAAK,WAAWnT,UAAU,uBAAuBsB,GAAIA,EAAIkwB,QAASA,EAASrZ,SATpE,SAAC7U,GAAD,OAAsC6U,EAAS7U,EAAEsV,OAAO4Y,QAASluB,MAU/E,uBAAOtD,UAAU,uBAAuB6xB,QAASvwB,EAAjD,SAAsDF,QCzB7C0wB,GAF2B,SAACrxB,GAAD,OAAW,cAAC,GAAD,aAAgB0S,KAAK,YAAe1S,KCGnFsxB,GAAY,SAAC,GAAD,IAAGlmB,EAAH,EAAGA,OAAQ+N,EAAX,EAAWA,OAAX,OAChB,eAACmT,GAAA,EAAD,CAAOlhB,OAAQA,EAAQ+N,OAAQA,EAAQoT,UAAQ,EAAC1c,KAAK,KAArD,UACE,cAAC4c,GAAA,EAAD,CAAatT,OAAQA,EAArB,kBACA,eAACuT,GAAA,EAAD,WACE,6CAEE,4BAAG,8DAFL,0GAKA,4IAGA,+BACE,kKAIA,qPAGE,uBAHF,+EAMA,0OAsBO6E,GAboB,WAAO,IAAD,EACF/uB,cADE,mBAC/BgvB,EAD+B,KAClBC,EADkB,KAGvC,OACE,qCACE,sBAAM9gB,MAAM,uBAAZ,SACE,cAAC,IAAD,CAAiBzP,KAAM2nB,IAAUlQ,MAAO,CAAEE,OAAQ,WAAatS,QAASkrB,MAE1E,cAAC,GAAD,CAAWrmB,OAAQomB,EAAarY,OAAQsY,QCnCjCC,GAAoC,SAAC,GAA6C,IAAD,IAA1CnyB,iBAA0C,MAA9B,GAA8B,EAA1BwpB,EAA0B,EAA1BA,UAAWpoB,EAAe,EAAfA,SACvEuc,EAAM9a,mBAKZ,OACE,qCACE,sBAAM7C,UAAWA,EAAW2d,IANZ,SAAC0L,GACnB1L,EAAI3a,QAAUqmB,GAKZ,SACE,cAAC,IAAD,CAAiB1nB,KAAM2nB,QAEzB,cAACC,GAAA,EAAD,CAAqB3Q,OAAS,kBAAM+E,EAAI3a,SAAiBwmB,UAAWA,EAApE,SAAgFpoB,QCZzEgxB,GAAgE,SAAC,GAAD,IACzEhxB,EADyE,EACzEA,SAAUixB,EAD+D,EAC/DA,YAAab,EADkD,EAClDA,QAASrZ,EADyC,EACzCA,SADyC,OAG3E,8BACE,cAAC,GAAD,CAAUsZ,QAAM,EAACD,QAASA,EAASxxB,UAAWqyB,EAAc,OAAS,GAAIla,SAAUA,EAAnF,SACG/W,IAEFixB,GAAe,cAAC,GAAD,CAAa7I,UAAU,QAAvB,SAAgC6I,QCgB9CC,GAAernB,YAAKhC,KAAMmG,aAAQ,KAAM,MACxCmjB,GAAS,SAACpY,GAAD,MAA4D,kBAATA,EAAoBQ,kBAASR,GAAQA,GACjGqY,GAAoB,SAAC9vB,GAAD,MAAoB,CAAE,WAAYA,EAAM,aAAcA,IAEnEkoB,GAAe,SAC1B6H,EACAC,GAF0B,OAGA,YAA6D,IAAD,EAAzD/G,EAAyD,EAAzDA,KAAMD,EAAmD,EAAnDA,OAAQE,EAA2C,EAA3CA,OAAQxnB,EAAmC,EAAnCA,aAAcvD,EAAqB,EAArBA,eAAqB,EAC5C4B,mBAAS2B,GADmC,mBAC9EuuB,EAD8E,KAChEC,EADgE,KAEhFC,EAAkB,SAATlH,EACTmH,EAAuB,iBAATnH,EACdoH,EAAqBriB,aAAStM,EAAagN,OAG3C4hB,EAAkB,WACtB,IAAMC,EAAcviB,aAASiiB,EAAavhB,OAO1C,OANgBiM,aAA4B,CAC1C,CAAE,kBAAO4V,IAAgBF,GAAoB,cAC7C,CAAE,kBAAOE,GAAeF,GAAoB,kBAAM,OAClD,CAAEzV,KAAG,kBAAMqV,EAAavhB,SAGnB8hB,IAEHC,EAASxiB,aAA4B,sBAAC,8BAAA4D,EAAA,+EAAYqX,EAAO,2BAC1D+G,GADyD,IAE5DvH,WAAU,UAAE5Q,GAAcmY,EAAavH,mBAA7B,QAA4C,KACtDC,WAAU,UAAE7Q,GAAcmY,EAAatH,mBAA7B,QAA4C,KACtDrC,UAAYtY,aAASiiB,EAAa3J,WAAoBrD,OAAOgN,EAAa3J,WAA3B,KAC/C5X,MAAO4hB,OACNzd,MAAK,kBAAOsd,GAjBKD,EAAgBxuB,MAiBFyoB,OAAM,gBANI,4CAQ5C/rB,qBAAU,WACR8xB,EAAgBxuB,KACf,CAAEA,IAEL,IAAMgvB,EAAsB,SAC1B9xB,EACAqX,GAF0B,MAG1BxF,EAH0B,uDAGR,OAClB1S,EAJ0B,uDAIlB,GACR4yB,EAL0B,uDAKT,GALS,OAO1B,cAAC,KAAD,2BAAeA,GAAf,aACE,cAACC,GAAA,EAAD,aACEhyB,GAAIA,EACJ6R,KAAMA,EACNwF,YAAaA,EACbtU,MAAK,UAAEsuB,EAAarxB,UAAf,QAAsB,GAC3B6W,SAAU,SAAC7U,GAAD,OAAOsvB,EAAgB,2BAAKD,GAAN,kBAAqBrxB,EAAKgC,EAAEsV,OAAOvU,WAC/D5D,QAIJ8yB,EAAkB,SAACjyB,EAAgBqX,GAAjB,IAAsClY,EAAtC,uDAAuE,GAAvE,OACtB,qBAAKT,UAAU,aAAf,SACE,cAAC,GAAD,aACEyd,SAAUkV,EAAarxB,GAAMixB,GAAOI,EAAarxB,IAAwB,KACzE6c,gBAAiBxF,EACjB6E,aAAW,EACXrF,SAAU,SAACgC,GAAD,OAAUyY,EAAgB,2BAAKD,GAAN,kBAAqBrxB,EAAK6Y,OACzD1Z,OAIJ+yB,EACJ,qCACE,cAAC,KAAD,UACE,cAACF,GAAA,EAAD,CACEG,OAAO,KACPtgB,KAAK,MACLwF,YAAY,sBACZ+a,UAAQ,EACRrvB,MAAOsuB,EAAarL,QACpBnP,SAAU,SAAC7U,GAAD,OAAOsvB,EAAgB,2BAAKD,GAAN,IAAoBrL,QAAShkB,EAAEsV,OAAOvU,cAG1E,eAACmJ,GAAA,EAAD,WACGslB,GAAeM,EAAoB,aAAc,cAAe,OAAQ,CAAEK,OAAQ,MAAQ,CAAEzzB,UAAW,aACxG,cAAC,KAAD,CAAWA,UAAW8yB,EAAc,WAAa,cAAjD,SACE,cAACL,EAAD,CAActS,aAAY,UAAEwS,EAAanc,YAAf,QAAuB,GAAI2B,SApE1C,SAAC3B,GAAD,OAAoBoc,EAAgB,2BAAKD,GAAN,IAAoBnc,KAAMA,EAAKrU,IAAImwB,kBA0EnF3C,EAAgBhe,aAAsB9Q,GACtC8yB,EAAoBhE,IAAkBkD,EACtCe,EAAyB1xB,IAAW,OAAQswB,GAAkBmB,IAC9DE,EAAuB9hB,aAAwBlR,GAC/CizB,EAA0B7hB,aAAqBpR,GAC/CkzB,EAAmBF,GAAwBC,EAC3CE,EAAyB9xB,IAAW,OAAQswB,GAAkBuB,IAEpE,OACE,uBAAM/zB,UAAU,iBAAiBitB,SAAUkG,EAA3C,UACGL,GAAeU,GACdV,GACA,qCACE,cAAC3hB,GAAA,EAAD,CAAYC,MAAM,gBAAgBpR,UAAU,OAA5C,SACGwzB,IAGH,eAAChmB,GAAA,EAAD,WACGmmB,GACC,qBAAK3zB,UAAU,gBAAf,SACE,eAACmR,GAAA,EAAD,CAAYC,MAAM,0BAAlB,UACGue,GAAiByD,EAAoB,QAAS,UAC7CP,GACA,qCACE,eAACrlB,GAAA,EAAD,WACE,qBAAKxN,UAAU,WAAf,SACGozB,EAAoB,aAAc,cAAe,OAAQ,CACxD5Z,SAAU9I,aAASiiB,EAAaxH,qBAGpC,qBAAKnrB,UAAU,WAAf,SACGozB,EAAoB,kBAAmB,oBAAqB,SAAU,CACrElN,IAAK,EACL1M,SAAU9I,aAASiiB,EAAazH,mBAItC,cAAC,KAAD,UACE,cAACwH,EAAD,CACEruB,MAAOsuB,EAAatc,OACpB8B,SAAU,SAAC9B,GAAD,OAAqBuc,EAAgB,2BAAKD,GAAN,IAAoBtc,yBAShF,qBAAKrW,UAAW4zB,EAAhB,SACE,eAACziB,GAAA,EAAD,CAAYC,MAAM,gCAAlB,UACGgiB,EAAoB,YAAa,mCAAoC,SAAU,CAAElN,IAAK,IACtFqN,EAAgB,aAAc,mBAAoB,CAAEnV,QAASuU,EAAatH,WAAakH,GAAOI,EAAatH,iBAAcvoB,IACzHywB,EAAgB,aAAc,mBAAoB,CAAElV,QAASsU,EAAavH,WAAamH,GAAOI,EAAavH,iBAActoB,YAKhI,eAAC0K,GAAA,EAAD,WACE,qBAAKxN,UAAWg0B,EAAhB,SACE,eAAC7iB,GAAA,EAAD,CAAYC,MAAM,eAAlB,UACE,cAAC,GAAD,CACEihB,YAAY,mGACZb,QAASmB,EAAapH,YACtBpT,SAAU,SAACoT,GAAD,OAAiBqH,EAAgB,2BAAKD,GAAN,IAAoBpH,kBAHhE,2BAOEsH,GACA,8BACE,cAAC,GAAD,CACEpB,QAAM,EACNzxB,UAAU,OACVwxB,QAASmB,EAAarH,aACtBnT,SAAU,SAACmT,GAAD,OAAkBsH,EAAgB,2BAAKD,GAAN,IAAoBrH,mBAJjE,uCAQA,cAAC,GAAD,YAKPyI,GACC,qBAAK/zB,UAAU,gBAAf,SACE,eAACmR,GAAA,EAAD,CAAYC,MAAM,qBAAlB,UACGyiB,GACC,cAAC,GAAD,CACExB,YAAY,+HACZb,QAASmB,EAAasB,UACtB9b,SAAU,SAAC8b,GAAD,OAAerB,EAAgB,2BAAKD,GAAN,IAAoBsB,gBAH9D,+BAQDH,GACC,cAAC,GAAD,CACEzB,YAAY,qGACZb,QAASmB,EAAanH,aACtBrT,SAAU,SAACqT,GAAD,OAAkBoH,EAAgB,2BAAKD,GAAN,IAAoBnH,mBAHjE,yDAed,qBAAKxrB,UAAU,cAAf,SACE,cAACmxB,GAAA,EAAD,CACEpqB,SAAO,EACPjH,MAAM,UACN0Z,SAAUkS,GAAUve,YAAQwlB,EAAarL,SACzCtnB,UAAU,eAJZ,SAMG0rB,EAAS,YAAc,gB,SC5LrBtd,GAAe,SAACwc,GAAD,OAAyC,YAOpC,IAAD,EANAK,EAMA,EAN9BjG,SAAYX,iBACZxjB,EAK8B,EAL9BA,eACAqzB,EAI8B,EAJ9BA,eACAC,EAG8B,EAH9BA,kBACAC,EAE8B,EAF9BA,gBACA1F,EAC8B,EAD9BA,aAEQ9pB,EAAW6B,eAAX7B,OACFlE,EAASC,eACT0zB,EAASlvB,cACPlE,EAAwCizB,EAAxCjzB,QAAS0F,EAA+ButB,EAA/BvtB,MAAOylB,EAAwB8H,EAAxB9H,UAAWvD,EAAaqL,EAAbrL,SAC3B6C,EAA2D0I,EAA3D1I,OAAe4I,EAA4CF,EAAnDztB,MAA+B4tB,EAAoBH,EAA/BhI,UAC5B/V,EAAW1R,YAAgCC,GAA3CyR,OACFjS,EAAesb,mBACnB,kBApCoB,SAACmJ,EAAqB7D,GAAuD,IAAD,YAC5FuG,EAAW,iBAAGvG,QAAH,IAAGA,OAAH,EAAGA,EAAUV,oBAAb,SAEjB,OAAKuE,EAIE,CACLvB,QAASuB,EAASvB,QAClB9Q,KAAMqS,EAASrS,KACfpF,MAAK,UAAEyX,EAASzX,aAAX,aAAoBtO,EACzBuT,OAAM,UAAEwS,EAASxS,cAAX,aAAqBvT,EAC3BsoB,WAAU,UAAEvC,EAASI,KAAKmC,kBAAhB,aAA8BtoB,EACxCuoB,WAAU,UAAExC,EAASI,KAAKoC,kBAAhB,aAA8BvoB,EACxCkmB,UAAS,UAAEH,EAASI,KAAKD,iBAAhB,aAA6BlmB,EACtCmxB,UAAWpL,EAASoL,UACpBzI,aAAc3C,EAAS2C,aACvBD,eAbO,CAAEjE,QAAS,GAAIiE,eAgChBE,CAAgB5C,EAAUoC,KAChC,CAAEpC,EAAUoC,IATgB,EAW8BhoB,cAX9B,mBAWtBuxB,EAXsB,KAWJC,EAXI,KAWUC,EAXV,KAiB9B,OAJA5zB,qBAAU,WACRJ,EAAOoV,WAAaqe,EAAkBzzB,EAAOoV,UAAWO,KACvD,IAECpV,EACK,cAACqS,GAAA,EAAD,CAASrS,SAAO,IAGrB0F,EAEA,cAAC,GAAD,CAAQwM,KAAK,QAAb,SACE,cAAC,GAAD,CAAgBiZ,UAAWA,EAAWC,gBAAgB,0DAM1D,qCACE,wBAAQrsB,UAAU,OAAlB,SACE,cAACuN,GAAA,EAAD,CAAMiG,MAAI,EAAV,SACE,qBAAIxT,UAAU,4DAAd,UACE,cAACmxB,GAAA,EAAD,CAAQrxB,MAAM,OAAOwQ,KAAK,KAAKtQ,UAAU,WAAWgH,QAASqtB,EAA7D,SACE,cAAC,IAAD,CAAiB1yB,KAAMgzB,QAEzB,sBAAM30B,UAAU,cAAhB,SACE,0CAAY,cAAC,KAAD,CAAcsL,KAAI,iBAAEud,QAAF,IAAEA,OAAF,EAAEA,EAAUA,gBAAZ,QAAwB,UAExD,gCAIN,cAAC+B,EAAD,CACExmB,aAAcA,EACdsnB,OAAQA,EACR7qB,eAAgBA,EAChB8qB,KAAK,OACLC,OAAM,uCAAE,WAAO+G,GAAP,SAAApe,EAAA,yDACDsU,EADC,iDAKN6L,IACAhG,EAAa7F,EAAS/S,UAAW+S,EAASxS,OAAQsc,GAC/Cpd,KAAKkf,GACL5H,MAAM6H,GARH,2CAAF,wDAWPJ,GACC,cAAC,GAAD,CAAQnhB,KAAK,QAAQnT,UAAU,OAA/B,SACE,cAAC,GAAD,CAAgBosB,UAAWmI,EAAiBlI,gBAAgB,oDAG/DmI,GAAmB,cAAC,GAAD,CAAQrhB,KAAK,UAAUnT,UAAU,OAAjC,6CC7Gb40B,GAA6B,mDAC7BC,GAA6B,mDAC7BC,GAAuB,6CAc9B1wB,GAA+B,CACnCnD,SAAS,EACT0F,OAAO,GAGMid,OAAY,qBACxBgR,IAA6B,iBAAO,CAAE3zB,SAAS,EAAM0F,OAAO,MADpC,eAExBkuB,IAA6B,SAACvG,EAAD,SAAuB,CAAErtB,SAAS,EAAO0F,OAAO,EAAMylB,UAAtD,EAAMA,cAFX,eAGxB0I,IAAuB,SAACxG,EAAD,OAAMzF,EAAN,EAAMA,SAAN,oBAAwBA,YAAazkB,OAHpC,IAIxBA,IAEU+vB,GAAoB,SAACxc,GAAD,OAAkD,SACjF7B,EACAO,GAFiF,8CAG9E,WAAO4X,EAAoBpW,GAA3B,uBAAAtD,EAAA,yDACH0Z,EAAS,CAAE9a,KAAMyhB,KADd,WAIyB/c,IAAlB4M,EAJP,EAIOA,cAJP,iBAKgBA,QALhB,IAKgBA,GALhB,UAKgBA,EAAejP,iBAL/B,aAKgB,EAA0BjO,KAAK8F,MAC9C,SAACwb,GAAD,OAAc6E,GAAgB7E,EAAU/S,EAAWO,aANpD,oEAOUsB,EAAqBE,GAAUzB,YAAYN,EAAWO,GAPhE,2BAKKwS,EALL,KASDoF,EAA+B,CAAEpF,WAAU1V,KAAM2hB,KAThD,kDAWD7G,EAAyB,CAAE9a,KAAM0hB,GAA4BzI,UAAWJ,GAAc,EAAD,MAXpF,0DAH8E,0DC4BpE1mB,GAhDS,SAACC,EAAgBC,GAEvCD,EAAOQ,eAAe,gBAAiB8H,GAAe,iBAAkB,yBACxEtI,EAAOY,UAAU,gBAAiBX,EAChC,CAAE,iBAAkB,cAAe,gBAAiB,YACpD,CAAE,gBAAiB,kBAAmB,qBAGxCD,EAAOQ,eAAe,iBAAkBwhB,GAAgB,gBACxDhiB,EAAOQ,eAAe,eAAgB0jB,GAAc,mBAAoB,iBAAkB,uBAC1FlkB,EAAOQ,eAAe,mBAAoB2jB,GAAkB,sBAAuB,eACnFnkB,EAAOQ,eAAe,uBAAwB8kB,GAAsB,uBACpEtlB,EAAOQ,eAAe,eAAgB6kB,GAAc,eAAgB,kBAEpErlB,EAAOQ,eAAe,iBAAkB+H,GAAgB,eAAgB,wBACxEvI,EAAOY,UACL,iBACAX,EAAQ,CAAE,yBAA0B,iBAAkB,YAAc,CAAE,iBAAkB,yBAG1FD,EAAOQ,eAAe,eAAgBqI,GAAc,gBACpD7I,EAAOY,UAAU,eAAgBX,EAC/B,CAAE,iBAAkB,kBAAmB,iBAAkB,YACzD,CAAE,oBAAqB,kBAGzBD,EAAOQ,eAAe,uBAAuB,kBAAMokB,MACnD5kB,EAAOY,UAAU,sBAAuBX,EAAQ,CAAE,oBAAsB,CAAE,iBAAkB,yBAE5FD,EAAOQ,eAAe,cAAeqkB,GAAa,kBAAmB,oBACrE7kB,EAAOY,UAAU,cAAeX,EAAQ,CAAE,oBAE1CD,EAAOQ,eAAe,wBAAyBka,GAAuB,kBAGtE1a,EAAOQ,eAAe,gBAAiBsP,GAAe,wBAEtD9P,EAAOQ,eAAe,iBAAkB0P,GAAgB,wBACxDlQ,EAAOQ,eAAe,uBAAuB,kBAAMglB,MAEnDxlB,EAAOQ,eAAe,iBAAkBuQ,GAAgB,wBACxD/Q,EAAOQ,eAAe,uBAAuB,kBAAM0mB,MAEnDlnB,EAAOQ,eAAe,oBAAqBouB,GAAmB,wBAE9D5uB,EAAOQ,eAAe,eAAgB2oB,GAAc,yB,8BChDzCqG,GAAkD,SAAC,GAE1D,IADF3zB,EACC,EADDA,SAAUiD,EACT,EADSA,MAAO8T,EAChB,EADgBA,SAAU7W,EAC1B,EAD0BA,GAAI6R,EAC9B,EAD8BA,KAAMugB,EACpC,EADoCA,SAAU/a,EAC9C,EAD8CA,YAAa3Y,EAC3D,EAD2DA,UAAWg1B,EACtE,EADsEA,eAEnEC,EAAQpyB,iBAAM,OAASvB,QAAT,IAASA,IAAMowB,gBAEnC,OACE,eAAC,KAAD,CAAW1xB,UAAS,OAAEA,QAAF,IAAEA,IAAa,GAAnC,UACE,wBAAO6xB,QAASoD,EAAMjyB,QAAShD,UAAS,OAAEg1B,QAAF,IAAEA,IAAkB,GAA5D,UACG5zB,EADH,OAGA,uBACEpB,UAAU,eACVmT,KAAI,OAAEA,QAAF,IAAEA,IAAQ,OACd7R,GAAI2zB,EAAMjyB,QACVqB,MAAOA,EACPqvB,SAAQ,OAAEA,QAAF,IAAEA,KACV/a,YAAaA,EACbR,SAAU,SAAC7U,GAAD,OAAO6U,EAAS7U,EAAEsV,OAAOvU,cCpBrC6wB,GAAyC,SAACz0B,GAAD,OAC7C,cAAC,GAAD,2BAAwBA,GAAxB,IAA+Bu0B,eAAe,yBAEnCG,GAAkC,SAAC,GAAkD,IAAhDlI,EAA+C,EAA/CA,SAAUmI,EAAqC,EAArCA,cAAeh0B,EAAsB,EAAtBA,SAAUgQ,EAAY,EAAZA,MAAY,EACrE3O,mBAAS,IAD4D,mBACvFlB,EADuF,KACjF8zB,EADiF,OAEvE5yB,mBAAS,IAF8D,mBAEvF+E,EAFuF,KAElF8tB,EAFkF,OAGjE7yB,mBAAS,IAHwD,mBAGvFgI,EAHuF,KAG/E8qB,EAH+E,KAIzFC,EAAe7kB,cAA6B,kBAAMsc,EAAS,CAAE1rB,OAAMiG,MAAKiD,cAQ9E,OANA3J,qBAAU,WACRs0B,GAAiBC,EAAQD,EAAc7zB,MACvC6zB,GAAiBE,EAAOF,EAAc5tB,KACtC4tB,GAAiBG,EAAUH,EAAc3qB,UACxC,CAAE2qB,IAGH,uBAAMp1B,UAAU,cAAcitB,SAAUuI,EAAxC,UACE,eAACrkB,GAAA,EAAD,CAAYnR,UAAU,OAAOoR,MAAOA,EAApC,UACE,cAAC,GAAD,CAAW/M,MAAO9C,EAAM4W,SAAUkd,EAAlC,kBACA,cAAC,GAAD,CAAWliB,KAAK,MAAM9O,MAAOmD,EAAK2Q,SAAUmd,EAA5C,iBACA,cAAC,GAAD,CAAWjxB,MAAOoG,EAAQ0N,SAAUod,EAApC,wBAGF,qBAAKv1B,UAAU,aAAf,SAA6BoB,QCzBtBq0B,GAA0D,SAAC,GAElE,IADF5pB,EACC,EADDA,OAAQ6pB,EACP,EADOA,kBAAmBC,EAC1B,EAD0BA,UAAW/J,EACrC,EADqCA,OAElCgK,EAAqBF,EAAkB1zB,OAAS,EAEtD,OACE,eAAC+qB,GAAA,EAAD,CAAOC,UAAQ,EAACnhB,OAAQA,EAAxB,UACE,eAACqhB,GAAA,EAAD,+BAA+B0I,GAAsB,OACrD,eAACzI,GAAA,EAAD,WACE,4BAAIyI,EAAqB,kCAAoC,oCAC7D,6BACGF,EAAkBvzB,KAAI,WAAkB+M,GAAlB,IAAG1H,EAAH,EAAGA,IAAKiD,EAAR,EAAQA,OAAR,OAA6BmrB,EAKhD,+BAAgB,4BAAIpuB,IAApB,MAA+B,4BAAIiD,MAA1ByE,GAJX,eAAC,WAAD,WACE,uCAAS,4BAAI1H,OACb,2CAAa,4BAAIiD,SAFJyE,QAMnB,iCACG0mB,EAAqB,2CAA6C,yCADrE,UAIF,eAACxI,GAAA,EAAD,WACE,cAAC+D,GAAA,EAAD,CAAQrxB,MAAM,OAAOkH,QAAS2uB,EAA9B,SAA0CC,EAAqB,oBAAsB,YACrF,cAACzE,GAAA,EAAD,CAAQrxB,MAAM,UAAUkH,QAAS4kB,EAAjC,gCChBFiK,GAAe,SAAC,GAAD,IAAG1iB,EAAH,EAAGA,KAAH,OACnB,qBAAKnT,UAAU,OAAf,SACE,eAAC,GAAD,CAAQmT,KAAMA,EAAd,UACY,YAATA,GAAsB,qEACb,UAATA,GAAoB,4EAwDZ2iB,GAnDM,SAACC,EAA6C3zB,GAA9C,OAAwF,YAEvG,IADFN,EACC,EADDA,QAASk0B,EACR,EADQA,aAEL5wB,EAAWC,eACXgvB,EAASlvB,cACT+H,IAAekP,OAAOC,KAAKva,GAASE,OAHvC,EAI6CI,GAAoB,EAtBzC,KAkBxB,mBAIK6zB,EAJL,KAIsBC,EAJtB,OAK2C9zB,GAAoB,EAvBvC,KAkBxB,mBAKK+zB,EALL,KAKqBC,EALrB,OAMgDnzB,cANhD,mBAMKozB,EANL,KAMyBC,EANzB,OAOmC7zB,qBAPnC,mBAOK8zB,EAPL,KAOiBC,EAPjB,KAQGC,EAAO,WACX,GAAKF,EAAL,CAIA,IAAMj1B,EAAKowB,eAEXsE,EAAa,2BAAKO,GAAN,IAAkBj1B,QAC9B8D,EAAS,WAAD,OAAY9D,MAWtB,OARAR,qBAAU,WACasb,OAAOnP,OAAOnL,GAAS2B,MAC1C,gBAAG+D,EAAH,EAAGA,IAAKiD,EAAR,EAAQA,OAAR,OAA+B,OAAV8rB,QAAU,IAAVA,OAAA,EAAAA,EAAY/uB,OAAQA,IAAiB,OAAV+uB,QAAU,IAAVA,OAAA,EAAAA,EAAY9rB,UAAWA,KAG1D6rB,IAAuBG,MACrC,CAAEF,IAGH,eAACG,GAAA,EAAD,WACE,eAAC,GAAD,CAAYtlB,MAAO,oBAAIpR,UAAU,OAAd,4BAA0CitB,SAAUuJ,EAAvE,WACItpB,GACA,cAAC6oB,EAAD,CAAkBY,iBAAiB,MAAMC,SAAUV,EAAoBW,cAAeT,IACvFlpB,GAAc,cAACikB,GAAA,EAAD,CAAQpqB,SAAO,EAACC,QAASqtB,EAAzB,oBACf,cAAClD,GAAA,EAAD,CAAQpqB,SAAO,EAACjH,MAAM,UAAUE,UAAU,OAA1C,8BAGDi2B,GAAmB,cAAC,GAAD,CAAc9iB,KAAK,YACtCgjB,GAAkB,cAAC,GAAD,CAAchjB,KAAK,UAEtC,cAAC,GAAD,CACEtH,OAAQwqB,EACRX,kBAAmBa,EAAa,CAAEA,GAAe,GACjDZ,UAAWtB,EACXzI,OAAQ6K,S,UCxBD7qB,GArCS,SAAC,GAAuD,IAArD9J,EAAoD,EAApDA,QAASjB,EAA2C,EAA3CA,eAC5BmM,EAAcC,aAAOnL,GA0B3B,OACE,eAACif,GAAA,EAAD,CAAsB+V,KAAG,EAACC,UAAQ,EAAlC,UACE,eAAChd,EAAA,EAAD,CAAgB+c,KAAG,EAAC9c,OAAK,EAAzB,UACE,cAAC,IAAD,CAAiBrY,KAAMq1B,MADzB,IACwC,sBAAMh3B,UAAU,OAAhB,wBAExC,cAACia,EAAA,EAAD,CAAcP,OAAK,EAAnB,SA5BEvM,YAAQH,GAER,eAACwR,EAAA,EAAD,CAAc/c,IAAKC,IAAMP,GAAG,iBAA5B,UACE,cAAC,IAAD,CAAiBQ,KAAMs1B,MADzB,IACsC,sBAAMj3B,UAAU,OAAhB,6BAMxC,qCACGgN,EAAY7K,KAAI,gBAAGZ,EAAH,EAAGA,KAAMD,EAAT,EAASA,GAAT,OACf,cAACkd,EAAA,EAAD,CAAuB/c,IAAKC,IAAMP,GAAE,kBAAaG,GAAMwL,OAAQjC,YAAYhK,KAAoBS,EAA/F,SACGC,GADgBD,MAIrB,cAACkd,EAAA,EAAD,CAAcC,SAAO,IACrB,eAACD,EAAA,EAAD,CAAc/c,IAAKC,IAAMP,GAAG,kBAA5B,UACE,cAAC,IAAD,CAAiBQ,KAAMq1B,MADzB,IACwC,sBAAMh3B,UAAU,OAAhB,wCCajCk3B,GA9B8C,SAAC,GAExD,IADF1sB,EACC,EADDA,OAAQoP,EACP,EADOA,OAAQ/N,EACf,EADeA,OAAQsrB,EACvB,EADuBA,aACvB,IADqCC,oBACrC,SACGhyB,EAAWC,eAOjB,OACE,eAAC0nB,GAAA,EAAD,CAAOlhB,OAAQA,EAAQ+N,OAAQA,EAAQoT,UAAQ,EAA/C,UACE,cAACE,GAAA,EAAD,CAAatT,OAAQA,EAArB,SAA6B,sBAAM5Z,UAAU,cAAhB,6BAC7B,eAACmtB,GAAA,EAAD,WACE,iEAAmC,4BAAI3iB,EAASA,EAAOjJ,KAAO,KAA9D,OACA,4BACE,sKAMJ,eAAC6rB,GAAA,EAAD,WACE,wBAAQptB,UAAU,eAAegH,QAAS4S,EAA1C,oBACA,wBAAQ5Z,UAAU,iBAAiBgH,QAAS,kBAnBhDmwB,EAAa3sB,GACboP,SACAwd,GAAgBhyB,EAAS,OAiBrB,2BCVOoK,GAjBY,SAAC0nB,GAAD,OAAgF,YAErG,IADF1sB,EACC,EADDA,OAAQxK,EACP,EADOA,UAAWoB,EAClB,EADkBA,SAAUiP,EAC5B,EAD4BA,cAC5B,EAC6CpN,cAD7C,mBACKgvB,EADL,KACoBoF,EADpB,KAC+BC,EAD/B,KAGH,OACE,qCACE,uBAAMt3B,UAAWA,EAAWgH,QAASqwB,EAArC,WACIj2B,GAAY,cAAC,IAAD,CAAiByO,YAAU,EAAClO,KAAMgpB,MAChD,sBAAM3qB,UAAWqQ,EAAjB,gBAAiCjP,QAAjC,IAAiCA,IAAY,0BAG/C,cAAC81B,EAAD,CAAmB1sB,OAAQA,EAAQqB,OAAQomB,EAAarY,OAAQ0d,S,UCbzDC,GAAa,SAAC/2B,GAAD,OAAqBF,cAAoC,YAAqC,IAAlCk3B,EAAiC,EAAjCA,WAAY32B,EAAqB,EAArBA,eAC1FwzB,EAASlvB,cAEf,IAAKuF,YAAe7J,GAClB,OAAO,KAQT,OACE,cAAC61B,GAAA,EAAD,UACE,eAAC,GAAD,CACEtlB,MAAO,qBAAIpR,UAAU,OAAd,mBAAiCa,EAAeU,KAAhD,OACP6zB,cAAev0B,EACfosB,SAVe,SAACsJ,GACpBiB,EAAW32B,EAAeS,GAAIi1B,GAC9BlC,KAKE,UAKE,cAAClD,GAAA,EAAD,CAAQpqB,SAAO,EAAC/G,UAAU,OAAOgH,QAASqtB,EAA1C,oBACA,cAAClD,GAAA,EAAD,CAAQpqB,SAAO,EAACjH,MAAM,UAAtB,yBAILU,I,UCVGi3B,GAAmB,SAAC31B,GAAD,OACvB,gBAAG0F,EAAH,EAAGA,IAAKiD,EAAR,EAAQA,OAAR,OAAiC3I,EAAQ2B,MAAK,SAAC+G,GAAD,OAAYA,EAAOhD,MAAQA,GAAOgD,EAAOC,SAAWA,OAiErFsrB,GA/DU,SAAC,GAAD,IAAG2B,EAAH,EAAGA,sBAAH,OAAkF,YASpG,IARLC,EAQI,EARJA,cACA71B,EAOI,EAPJA,QACA81B,EAMI,EANJA,QACAx2B,EAKI,EALJA,SAKI,IAJJw1B,gBAII,MAJO,aAIP,MAHJC,qBAGI,MAHY,aAGZ,MAFJF,wBAEI,MAFe,SAEf,MADJ32B,iBACI,MADQ,GACR,EACE2d,EAAG,OAAGia,QAAH,IAAGA,IAAW/0B,mBADnB,EAE4CJ,qBAF5C,mBAEIo1B,EAFJ,KAEqBC,EAFrB,OAGgDr1B,mBAAuB,IAHvE,mBAGIizB,EAHJ,KAGuBqC,EAHvB,OAI2C90B,cAJ3C,mBAIIgvB,EAJJ,KAIkBoF,EAJlB,KAI6BC,EAJ7B,KAKEU,EAAS/sB,YAAK0sB,EAAef,GAC7BqB,EAAmBhtB,aAAK,kBAAM+sB,EAAM,OAACH,QAAD,IAACA,IAAmB,MAAKP,GAC7DY,EAA6BjtB,aACjC,kBAAM+sB,GAAO,OAACH,QAAD,IAACA,IAAmB,IAAItc,OAAO4c,aAAWV,GAAiB/B,QACxE4B,GAEIc,EAAM,uCAAG,+BAAA7jB,EAAA,6DAASqE,EAAT,EAASA,OAAT,kBACb8e,EAAqB,UAAC9e,EAAOyf,aAAR,aAAC,EAAe,IAClC9iB,KAAKuiB,GACLviB,MAAK,WAEHqD,EAAoCvU,MAAQ,QAE9CwoB,MAAMgK,IAPI,2CAAH,sDAsBZ,OAbA/1B,qBAAU,WACR,GAAK+2B,EAAL,CAIA,IAAMS,EAAkBlc,OAAOnP,OAAOnL,GAChC4zB,EAAoBmC,EAAgBtc,OAAOkc,GAAiBa,IAC5DC,IAAyB7C,EAAkB1zB,OAEhDu2B,EAAiDR,EAAqBrC,GAA/CsC,EAAOH,GAC/BU,GAAwBlB,OACvB,CAAEQ,IAGH,qCACE,eAAC1G,GAAA,EAAD,CAAQpqB,SAAO,EAACzF,GAAG,YAAYtB,UAAWA,EAAWgH,QAAS,kCAAM2W,EAAI3a,eAAV,aAAM,EAAaw1B,SAAjF,UACE,cAAC,IAAD,CAAiB72B,KAAM82B,IAAY5oB,YAAU,IAD/C,WACoDzO,QADpD,IACoDA,IAAY,sBAEhE,eAACmoB,GAAA,EAAD,CAAqBC,UAAWmN,EAAkB/d,OAAO,YAAzD,yEAC8D,qCAD9D,KAC2E,uCAD3E,QAC6F,oCAD7F,OAIA,uBAAOzF,KAAK,OAAOulB,OAAO,WAAW14B,UAAU,iCAAiC2d,IAAKA,EAAKxF,SAAUigB,IAEpG,cAAC,GAAD,CACEvsB,OAAQomB,EACRyD,kBAAmBA,EACnBC,UAAWuC,EACXtM,OAAQqM,S,mBC5EHU,GAAgB,sCAChBC,GAAwB,8CAW/B1tB,GAAkBD,aACtB,SAAC/K,GAAD,MARuC,WAQlBA,EATa,cASkDA,IACpF24B,aAXkC,UAc9BC,GAAmBC,aACvBjM,KADkC,uCAElC,WAAOkM,EAAmB/hB,GAA1B,SAAA1C,EAAA,+EAAkE0C,IAAS1B,MAAK,gBAAGrV,EAAH,EAAGA,QAAH,MAAkB,CAChGA,QAASgL,GAAgBhL,GACzBwL,iBAAkBP,aAAmBjL,QAFvC,2CAFkC,yDAUrB0jB,OAAY,qBACxBgV,IAAwB,kBAHU,QAEV,eAExBD,IAAgB,SAACrK,EAAD,YAAMztB,kBAFE,IAFU,MAOxBo4B,GAAsBjV,GAAmB4U,IAEzCh4B,GAAe,SAC1B+W,EACA8J,GAF0B,OAGvB,SACH1gB,GADG,8CAEA,WACHktB,EACApW,GAFG,6BAAAtD,EAAA,yDAIH0Z,EAASgL,MAJN,EAMiBphB,IAAZ/V,EANL,EAMKA,QACFjB,EAAiBiB,EAAQf,GAP5B,uBAUDktB,EAA6B,CAC3B9a,KAAMwlB,GACN93B,eAAgB,CAAEq4B,gBAAgB,KAZnC,4CAmBkBvhB,EAAqB9W,GAAhCoW,EAnBP,EAmBOA,OAnBP,UAoB2C6hB,GAAiB/3B,EAAUkW,GApBtE,iBAoBO/W,EApBP,EAoBOA,QAASwL,EApBhB,EAoBgBA,iBAEjBuiB,EAA6B,CAC3B9a,KAAMwlB,GACN93B,eAAe,2BACVA,GADS,IAEZX,UACAwL,uBAGJuiB,EAASxM,KA9BR,kDAgCDwM,EAA6B,CAC3B9a,KAAMwlB,GACN93B,eAAe,2BAAMA,GAAP,IAAuBs4B,oBAAoB,MAlC1D,0DAFA,0D,8BCxCQC,GAAc,6BACdC,GAAgB,+BAChBC,GAAiB,gCACjBC,GAAmB,kCA0BjB3V,OAAY,qBACxB0V,IAAiB,SAAC1yB,EAAD,OAAU4yB,EAAV,EAAUA,WAAV,mBAAC,eAAgC5yB,GAAU4yB,MADpC,eAExBH,IAAgB,SAACzyB,EAAD,OAAU7F,EAAV,EAAUA,SAAV,OAAyB6jB,aAAO7jB,EAAU6F,MAFlC,eAGxBwyB,IAAc,SAACxyB,EAAD,OAAU7F,EAAV,EAAUA,SAAUw1B,EAApB,EAAoBA,WAApB,OAA2C3vB,EAAM7F,GAE5DsuB,aAAMtuB,EAAD,YAAC,eAAe6F,EAAM7F,IAAcw1B,GAAc3vB,GADvDA,KAJqB,eAMxB2yB,IAAmB,SAAC3yB,EAAD,GAAuC,IAA7B7F,EAA4B,EAA5BA,SAAUuM,EAAkB,EAAlBA,YACtC,OAAK1G,EAAM7F,GAINuM,EAIEmsB,aACLzY,aAAQpa,GAAOzE,KAAI,mCAAGu3B,EAAH,KAAsBlvB,EAAtB,WAAmC,CACpDkvB,EADoD,2BAE/ClvB,GAF+C,IAEvC8C,YAAaosB,IAAsB34B,SAN3CsuB,aAAMtuB,EAAD,YAAC,eAAe6F,EAAM7F,IAAtB,IAAiCuM,gBAAe1G,GAJrDA,KARc,IAVM,IAkC3B+yB,GAAmBC,cAAiC,SAACC,EAAKrvB,GAAN,OAAiB6kB,aAAM7kB,EAAOlJ,GAAIkJ,EAAQqvB,KAAM,IAE7FlC,GAAgB1sB,YAC3B9I,cAnCmB,SAACqI,GACpB,OAAKA,EAAwBlJ,GACpBkJ,EAGF6kB,aAAM,KAAMqC,eAAQlnB,MA+B3BmvB,IACA,SAACH,GAAD,MAA6B,CAAErmB,KAAMmmB,GAAgBE,iBAG1CxD,GAAe,SAACxrB,GAAD,OAA0BmtB,GAAc,CAAEntB,KAEzDgtB,GAAa,SAACz2B,EAAkBw1B,GAAnB,MAAwD,CAChFpjB,KAAMimB,GACNr4B,WACAw1B,eAGWY,GAAe,SAAC,GAAD,IAAG71B,EAAH,EAAGA,GAAH,MAA+C,CAAE6R,KAAMkmB,GAAet4B,SAAUO,IAE/Fw4B,GAAiB,SAAC,EAAsBxsB,GAAvB,IAAGhM,EAAH,EAAGA,GAAH,MAAuE,CACnG6R,KAAMomB,GACNx4B,SAAUO,EACVgM,gBC1EIysB,GAAwB9uB,YAC5B8M,YAAe,SACf,SAACxQ,GAAD,OAA6ByyB,MAAMC,QAAQ1yB,GAAQA,EAAKgU,OAAOhR,KAAiB,MAGrE2vB,GAAe,SAAC,GAAD,IAAG7yB,EAAH,EAAGA,IAAH,OAA4B,yDAAM,WAAO4mB,GAAP,iBAAA1Z,EAAA,sEACzClN,EAAI,GAAD,OAAI8yB,IAAJ,kBADsC,OACtDvkB,EADsD,OAEtDwkB,EAAaL,GAAsBnkB,GAEzCqY,EAAS0J,GAAcyC,IAJqC,2CAAN,wDCWzCjK,GAfqC,SAAC,GAA0D,IAAxDze,EAAuD,EAAvDA,WAAY2oB,EAA2C,EAA3CA,WAAYx5B,EAA+B,EAA/BA,eAAgBO,EAAe,EAAfA,SAC7F,IAAKwJ,YAAkB/J,GACrB,OAAO,KAFmG,IAKpGX,EAAYW,EAAZX,QAGR,OAFuBsR,aAAatR,EAAS,CAAEm6B,aAAY3oB,eAMpD,mCAAGtQ,IAHD,M,UCHEZ,GAAc,SAACgP,GAAD,OAA2E,gBAClG1N,EADkG,EAClGA,QAASjB,EADyF,EACzFA,eADyF,OAGpG,cAAC61B,GAAA,EAAD,UACE,sBAAK12B,UAAU,sCAAf,UACE,eAACsT,GAAA,EAAD,CAAStT,UAAU,qBAAqBmT,KAAK,QAAQI,WAAS,EAA9D,WACI7I,YAAe7J,IAAmB,qCACnC6J,YAAe7J,IACd,qCACE,+EADF,mGAOJ,eAACgB,GAAA,EAAD,CAAkBC,QAASsa,OAAOnP,OAAOnL,GAAzC,sFAEU,cAAC,IAAD,CAAMX,GAAG,iBAAT,2BAFV,OAKCuJ,YAAe7J,IACd,qBAAKb,UAAU,yBAAf,SACE,gHAEM,cAACwP,EAAD,CAAoBhF,OAAQ3J,EAAgBb,UAAU,2BAAtD,uBAFN,UAGE,cAAC,IAAD,CAAMmB,GAAE,kBAAaN,EAAeS,GAA5B,SAAR,qBAHF,gB,iDCtBGg5B,GAAwC,SAAC,GAAD,IAAGl5B,EAAH,EAAGA,SAAUgQ,EAAb,EAAaA,MAAOmpB,EAApB,EAAoBA,KAApB,OACnD,eAAChtB,GAAA,EAAD,yBAAMvN,UAAU,iBAAiBwT,MAAI,GAHf,SAAC+mB,GAAD,OAA4BA,EAAY,CAAE94B,IAAKC,IAAMP,GAAIo5B,GAAtB,GAGfC,CAAgBD,IAA1D,cACGA,GAAQ,cAAC,IAAD,CAAiBjqB,KAAK,KAAKtQ,UAAU,4BAA4B2B,KAAM84B,OAChF,cAACC,GAAA,EAAD,CAAWj5B,IAAI,KAAKzB,UAAU,wBAA9B,SAAuDoR,IACvD,cAACupB,GAAA,EAAD,CAAUl5B,IAAI,KAAd,SAAoBL,SCSX+M,GAAW,SACtBoZ,EACAzZ,EACAqiB,GAHsB,OAInB/O,IAAkB,YAQM,IAAD,EAP1BqD,EAO0B,EAP1BA,cACApP,EAM0B,EAN1BA,cACAqB,EAK0B,EAL1BA,SACA8J,EAI0B,EAJ1BA,SACA3f,EAG0B,EAH1BA,eACA+5B,EAE0B,EAF1BA,mBACAC,EAC0B,EAD1BA,eAEQ55B,EAAuBwjB,EAAvBxjB,QAASuU,EAAciP,EAAdjP,UACAslB,EAAgBta,EAAzBvf,QACS85B,EAAkDF,EAA3D55B,QAAwB8nB,EAAmC8R,EAAnC9R,YAAaiS,EAAsBH,EAAtBG,kBACvCj6B,EAAW8J,YAAYhK,GACvBo6B,EAAqBxsB,aAAqB5N,GAC1Cq6B,EAAwBvsB,aAAwB9N,GAChDuE,EAAWC,eAQjB,OANAvE,qBAAU,WACRuU,EAAc,CAAE8lB,a9B/BkB,E8B+BoBjmB,QAAS,CAAEd,MAAO,cAAeC,IAAK,UAC5FqC,IACAkkB,MACC,IAGD,qCACE,eAACptB,GAAA,EAAD,WACE,qBAAKxN,UAAU,yBAAf,SACE,cAAC,GAAD,CAAeoR,MAAM,SAASmpB,KAAMW,GAAqB,kBAAen6B,EAAf,sBAAzD,SACGg6B,EAAgB,aAAetV,GAASsD,OAG7C,qBAAK/oB,UAAU,yBAAf,SACE,eAAC,GAAD,CAAeoR,MAAM,gBAAgBmpB,KAAMU,GAAkB,kBAAel6B,EAAf,kBAA7D,UACE,cAACovB,EAAD,CAAkBze,WAAW,QAA7B,SACGqpB,EAAgB,aAAetV,GAAQ,OAACuV,QAAD,IAACA,IAAqB,KAEhE,cAAC7K,EAAD,CAAkBkK,WAAW,QAA7B,SACE,uBAAOr6B,UAAU,aAAjB,SAA8B,8DAIpC,qBAAKA,UAAU,yBAAf,SACE,cAAC,GAAD,CAAeoR,MAAM,aAAampB,KAAI,kBAAax5B,EAAb,sBAAtC,SACGE,EAAU,aAAewkB,GAAQ,iBAACjQ,QAAD,IAACA,OAAD,EAACA,EAAWmS,WAAWsH,kBAAvB,QAAqC,OAG3E,qBAAKjvB,UAAU,yBAAf,SACE,cAAC,GAAD,CAAeoR,MAAM,OAAOmpB,KAAI,kBAAax5B,EAAb,gBAAhC,SACG+5B,EAAc,aAAerV,GAASjF,EAAShK,KAAKxU,eAK3D,eAACuL,GAAA,EAAD,CAAMvN,UAAU,OAAhB,UACE,eAACo7B,GAAA,EAAD,WACE,sBAAMp7B,UAAU,YAAhB,gCACA,oBAAIA,UAAU,qBAAd,gCACA,cAAC,IAAD,CAAMA,UAAU,cAAcmB,GAAE,kBAAaJ,EAAb,qBAAhC,sCAEF,cAACs6B,GAAA,EAAD,UACE,cAACvtB,EAAD,CAAgBkd,WAAS,SAG7B,eAACzd,GAAA,EAAD,WACE,eAAC6tB,GAAA,EAAD,WACE,sBAAMp7B,UAAU,YAAhB,mCACA,oBAAIA,UAAU,qBAAd,mCACA,cAAC,IAAD,CAAMA,UAAU,cAAcmB,GAAE,kBAAaJ,EAAb,sBAAhC,6BAEF,cAACs6B,GAAA,EAAD,UACE,cAAC9T,EAAD,CACE9C,cAAeA,EACf5jB,eAAgBA,EAChBb,UAAU,OACVioB,WAAY,SAACxmB,GAAD,OAAS2D,EAAS,WAAD,OAAYrE,EAAZ,mCAA+Cu6B,mBAAmB75B,mBAMxG,iBAAM,CAAE2hB,GAAOrN,OAAQqN,GAAOK,kBC1FpB8X,GAAgB,SAC3BC,EACAzF,EACA3zB,EACAq5B,GAJ2B,OAKA,YAAkB,IAAf35B,EAAc,EAAdA,QACxB45B,EAAatf,OAAOnP,OAAOnL,GADW,EAEJW,mBAASi5B,GAFL,mBAEpC1uB,EAFoC,KAEvB2uB,EAFuB,KAMtCC,EAAiB5uB,EAAYvJ,MAAK,sBAAG6J,eANC,EAOElL,GAAoB,EAdvC,KAOiB,mBAOpC+zB,EAPoC,KAOpBC,EAPoB,KAa5C,OAJAt1B,qBAAU,WACR66B,EAAevf,OAAOnP,OAAOnL,MAC5B,CAAEA,IAGH,eAAC40B,GAAA,EAAD,WACE,cAAC,EAAD,CAAa12B,UAAU,OAAOmY,SAZZ,SAACG,GAAD,OAAwBqjB,EAC5CD,EAAWngB,QAAO,gBAAGha,EAAH,EAAGA,KAAMiG,EAAT,EAASA,IAAT,MAAmB,UAAGjG,EAAH,YAAWiG,GAAM2C,MAAMmO,UAa1D,eAAC9K,GAAA,EAAD,CAAKxN,UAAU,OAAf,UACE,sBAAKA,UAAU,0CAAf,UACE,cAAC+1B,EAAD,CAAkB/1B,UAAU,YAAY62B,cAAeT,EAAvD,4BACCsF,EAAW15B,OAAS,GACnB,eAACmvB,GAAA,EAAD,CAAQpqB,SAAO,EAAC/G,UAAU,iBAAiBgH,QAAO,sBAAE,sBAAAuN,EAAA,+EAAYinB,EAAgBK,iBAA5B,2CAApD,UACE,cAAC,IAAD,CAAiBl6B,KAAMm6B,IAAYjsB,YAAU,IAD/C,wBAKJ,qBAAK7P,UAAU,2CAAf,SACE,eAACmxB,GAAA,EAAD,CAAQpqB,SAAO,EAACjH,MAAM,UAAUE,UAAU,YAAYyB,IAAKC,IAAMP,GAAG,iBAApE,UACE,cAAC,IAAD,CAAiBQ,KAAMs1B,IAAUpnB,YAAU,IAD7C,wBAMJ,cAACsB,GAAA,EAAD,UACE,wBAAOnR,UAAU,yBAAjB,UACE,uBAAOA,UAAU,2BAAjB,SACE,+BACG47B,GAAkB,oBAAIxiB,MAAO,CAAE2iB,MAAO,UACvC,sCACA,0CACA,4BAGJ,mCACI/uB,EAAYhL,QAAU,oBAAIhC,UAAU,cAAd,SAA4B,oBAAI4vB,QAAS,EAAb,iCACnD5iB,EAAY7K,KAAI,SAACqI,GAAD,OACf,cAACixB,EAAD,CAAkCjxB,OAAQA,EAAQoxB,eAAgBA,GAA3CpxB,EAAOlJ,eAMrC60B,GACC,qBAAKn2B,UAAU,OAAf,SACE,cAAC,GAAD,CAAQmT,KAAK,QAAb,wFCnEGsoB,GAAmB,SAC9BO,GAD8B,OAEA,gBAAGxxB,EAAH,EAAGA,OAAQoxB,EAAX,EAAWA,eAAX,OAC9B,qBAAI57B,UAAU,wBAAd,UACG47B,GACC,oBAAI57B,UAAU,yBAAyB+pB,UAAQ,eAA/C,SACGvf,EAAO8C,aACN,qCACE,cAAC,IAAD,CAAiB3L,KAAMs6B,IAAWj8B,UAAU,eAAesB,GAAG,oBAC9D,cAACioB,GAAA,EAAD,CAAqB3Q,OAAO,kBAAkB4Q,UAAU,QAAxD,8CAOR,oBAAIxpB,UAAU,yBAAyB+pB,UAAQ,OAA/C,SACE,cAAC,IAAD,CAAM5oB,GAAE,kBAAaqJ,EAAOlJ,IAA5B,SAAmCkJ,EAAOjJ,SAE5C,oBAAIvB,UAAU,yBAAyB+pB,UAAQ,WAA/C,SAA2Dvf,EAAOhD,MAClE,oBAAIxH,UAAU,oCAAd,SACE,cAACg8B,EAAD,CAA0BxxB,OAAQA,WCV3BwxB,GAA2B,SACtC9E,GADsC,OAEO,YAAiC,IAA9B1sB,EAA6B,EAA7BA,OAAQsvB,EAAqB,EAArBA,eAAqB,EAC1C72B,cAD0C,mBACrEi5B,EADqE,KACzDC,EADyD,OAE9Bl5B,cAF8B,mBAErEgvB,EAFqE,KAEvDoF,EAFuD,KAE5CC,EAF4C,KAGvE8E,EAAS,kBAAc5xB,EAAOlJ,IACf+6B,EAAkB7xB,EAA/B8C,YACFgvB,EAAkBD,EAAgBE,IAAgBC,KAExD,OACE,eAAC,GAAD,CAAiB3wB,OAAQqwB,EAAYtiB,OAAQuiB,EAA7C,UACE,eAAC3d,EAAA,EAAD,CAAc/c,IAAKC,IAAMP,GAAIi7B,EAA7B,UACE,cAAC,IAAD,CAAiBz6B,KAAM86B,IAAa5sB,YAAU,IADhD,cAGA,eAAC2O,EAAA,EAAD,CAAc/c,IAAKC,IAAMP,GAAE,UAAKi7B,EAAL,SAA3B,UACE,cAAC,IAAD,CAAiBz6B,KAAMyO,IAAUP,YAAU,IAD7C,kBAGA,eAAC2O,EAAA,EAAD,CAAcxX,QAAS,kBAAM8yB,EAAetvB,GAASA,EAAO8C,cAA5D,UACE,cAAC,IAAD,CAAiB3L,KAAM26B,EAAiBzsB,YAAU,IADpD,IACyDwsB,EAAgB,WAAa,IADtF,iBAGA,cAAC7d,EAAA,EAAD,CAAcC,SAAO,IACrB,eAACD,EAAA,EAAD,CAAcxe,UAAU,wBAAwBgH,QAASqwB,EAAzD,UACE,cAAC,IAAD,CAAiB11B,KAAMgpB,IAAY9a,YAAU,IAD/C,oBAIA,cAACqnB,EAAD,CAAmBE,cAAc,EAAO5sB,OAAQA,EAAQqB,OAAQomB,EAAarY,OAAQ0d,SC9CrFoF,GAAiB,SAAClyB,GAAD,MACC,kBAAfA,EAAOhD,KAA6C,kBAAlBgD,EAAOC,QAA8C,kBAAhBD,EAAOjJ,MAEjFo7B,GAAkB,SAAC76B,GAAD,OACtBk4B,MAAMC,QAAQn4B,IAAYA,EAAQ86B,MAAMF,KAE7BG,GACX,WAAoCC,EAAmCC,GAAsC,IAAD,gCAAxED,UAAwE,KAArCC,oBAAqC,KAE5FrF,sBAF4F,uCAEpE,WAAOsF,GAAP,eAAAzoB,EAAA,yDACjCyoB,EADiC,sBAE9B,IAAIhlB,MAAM,oBAFoB,cAKhCilB,EAAS,EAAKF,oBALkB,kBAO/B,IAAInO,SAAQ,SAACsO,EAASloB,GAC3BioB,EAAOE,iBAAiB,WAAW,SAAC75B,GAClC,IAAK,IAAD,MAEI85B,EAAO,oBAAG95B,EAAEsV,cAAL,iBAAG,EAAUyU,cAAb,aAAG,EAAkBgQ,kBAArB,QAAmC,GAC1Cv7B,EAAU,EAAKg7B,QAAQQ,SAASF,GAEtC,IAAKT,GAAgB76B,GACnB,MAAM,IAAIkW,MAAM,iDAGlBklB,EAAQp7B,GACR,MAAOwB,GACP0R,EAAO1R,OAGX25B,EAAOM,WAAWP,OAvBkB,2CAFoE,uD,SCFzFQ,GACnB,WACmBl0B,EACA/E,EACAk5B,GAChB,IAAD,gCAHiBn0B,UAGjB,KAFiB/E,SAEjB,KADiBk5B,UACjB,KAEc5B,cAFd,sBAE8B,gCAAAtnB,EAAA,sDACxBzS,EAAUmL,aAAM,UAAC,EAAK3D,QAAQjC,IAAgB,kBAA9B,QAA4C,IAAIlF,IAAI2I,KAE1E,IACQ4yB,EAAM,EAAKD,QAAQE,MAAM77B,EAAS,CAAE0V,QAAS,QAEnDomB,aAAQ,EAAKr5B,OAAQm5B,EAfF,sBAgBnB,MAAOp6B,GAEPqC,QAAQgB,MAAMrD,GATc,4CCwEnBgC,GAjES,SAACC,EAAgBC,GAEvCD,EAAOQ,eACL,gBACAw1B,GACA,kBACA,mBACA,sBACA,oBAEFh2B,EAAOY,UAAU,gBAAiBX,EAAQ,CAAE,aAE5CD,EAAOQ,eAAe,mBAAoB01B,GAAkB,4BAE5Dl2B,EAAOQ,eAAe,2BAA4Bi2B,GAA0B,qBAC5Ez2B,EAAOY,UAAU,2BAA4BX,EAAQ,KAAM,CAAE,oBAE7DD,EAAOQ,eAAe,eAAgB+vB,GAAc,mBAAoB,uBACxEvwB,EAAOY,UAAU,eAAgBC,MACjCb,EAAOY,UAAU,eAAgBX,EAAQ,CAAE,iBAAkB,WAAa,CAAE,eAAgB,yBAE5FD,EAAOQ,eAAe,aAAcwxB,GAAY,eAChDhyB,EAAOY,UAAU,aAAcX,EAAQ,CAAE,kBAAoB,CAAE,aAAc,kBAE7ED,EAAOQ,eAAe,mBAAmB,kBAAM6F,MAC/CrG,EAAOY,UAAU,kBAAmBX,EAAQ,CAAE,UAAW,oBAEzDD,EAAOQ,eAAe,qBAAqB,kBAAMmxB,MACjD3xB,EAAOY,UAAU,oBAAqBX,EAAQ,KAAM,CAAE,kBAEtDD,EAAOQ,eAAe,qBAAsByJ,GAAoB,qBAEhEjK,EAAOQ,eAAe,mBAAoBgwB,GAAkB,mBAC5DxwB,EAAOY,UAAU,mBAAoBX,EAAQ,CAAE,WAAa,CAAE,mBAE9DD,EAAOQ,eAAe,oBAAoB,kBAAMoqB,MAChD5qB,EAAOY,UAAU,mBAAoBX,EAAQ,CAAE,oBAE/CD,EAAOQ,eAAe,cAAevF,GAAa,sBAClD+E,EAAOY,UAAU,cAAeX,EAAQ,CAAE,UAAW,oBAErDD,EAAOQ,eAAe,WAAYoI,GAAU,iBAAkB,iBAAkB,oBAChF5I,EAAOY,UAAU,WAAYX,EAC3B,CAAE,gBAAiB,WAAY,iBAAkB,cAAe,kBAChE,CAAE,gBAAiB,WAAY,kBAAmB,kBAAmB,wBAIvED,EAAOE,SAAS,UAAWg4B,MAC3Bl4B,EAAOE,SAAS,qBAAqB,kBAAM,IAAIo4B,cAC/Ct4B,EAAOM,QAAQ,kBAAmBg3B,GAAiB,UAAW,qBAC9Dt3B,EAAOM,QAAQ,kBAAmB23B,GAAiB,UAAW,SAAU,WAGxEj4B,EAAOQ,eAAe,eAAgBnF,GAAc,uBAAwB,mBAC5E2E,EAAOQ,eAAe,gBAAgB,kBAAMiwB,MAC5CzwB,EAAOQ,eAAe,iBAAiB,kBAAM4xB,MAC7CpyB,EAAOQ,eAAe,gBAAgB,kBAAMoxB,MAC5C5xB,EAAOQ,eAAe,cAAc,kBAAMyxB,MAC1CjyB,EAAOQ,eAAe,kBAAkB,kBAAM+zB,MAC9Cv0B,EAAOQ,eAAe,eAAgBm0B,GAAc,SAEpD30B,EAAOQ,eAAe,uBAAuB,kBAAMkzB,O,wCCtE/C6E,GAAwB,kBAC5B,cAACC,GAAA,EAAD,CACEC,YAAY,0EACZx2B,IAAI,wDAIFy2B,GAAoB,SAACC,GACzB,OAAyB,IAArBA,EAAUl8B,OACL,GAGLk8B,EAAUl8B,OAAS,EACd,CAAEm8B,OAAQD,EAAU/7B,IAAI4V,YAAK,aAO/B,CAAEqmB,KAAM,GAAIC,OAboD,YAWzCH,EAXyC,MAW9DI,UAwBIC,GAnBE,SAAC,GAAD,IAAG3kB,EAAH,EAAGA,OAAQ/N,EAAX,EAAWA,OAAQuF,EAAnB,EAAmBA,MAAnB,IAA0B8sB,iBAA1B,MAAsC,GAAtC,SACf,cAACnR,GAAA,EAAD,CAAOnT,OAAQA,EAAQ/N,OAAQA,EAAQ7L,UAAU,mBAAmBw+B,iBAAiB,2BAArF,SACE,eAACrR,GAAA,EAAD,CAAWntB,UAAU,wBAArB,UACE,qBAAIA,UAAU,yBAAd,UACGoR,EACD,wBAAQ+B,KAAK,SAASnT,UAAU,QAAQgH,QAAS4S,EAAjD,qBAEF,eAAC6kB,GAAA,EAAD,2BAAkBR,GAAkBC,IAApC,cACE,cAAC,GAAD,IACCA,EAAU/7B,KAAI,WAA+B+M,GAA/B,IAAGwvB,EAAH,EAAGA,SAAUJ,EAAb,EAAaA,QAASK,EAAtB,EAAsBA,MAAtB,OACb,cAACC,GAAA,EAAD,CAAoBC,SAAUP,EAA9B,SACE,eAACQ,GAAA,EAAD,WAAO,4BAAIH,IAAX,SAA4BA,EAAQ,EAAI,IAAM,GAA9C,SAAuD,4BAAID,QADhDxvB,gBCRR6vB,GAxB6B,SAAC,GAAD,IAAGhpB,EAAH,EAAGA,OAAQse,EAAX,EAAWA,OAAQxL,EAAnB,EAAmBA,SAAUznB,EAA7B,EAA6BA,SAAUgQ,EAAvC,EAAuCA,MAAvC,OAC1C,iCACE,eAAC7D,GAAA,EAAD,CAAMiG,MAAI,EAAV,UACE,qBAAIxT,UAAU,yDAAd,UACE,cAACmxB,GAAA,EAAD,CAAQrxB,MAAM,OAAOwQ,KAAK,KAAKtQ,UAAU,WAAWgH,QAASqtB,EAA7D,SACE,cAAC,IAAD,CAAiB1yB,KAAMgzB,QAEzB,sBAAM30B,UAAU,gCAAhB,SACE,gCAAQoR,MAEV,uBAAMpR,UAAU,wBAAhB,oBACU,IACR,cAAC,GAAD,CAAqB+oB,YAAahT,EAAO/T,OAAQ6mB,SAAUA,UAG/D,oBAAI7oB,UAAU,0CAAd,SACE,gCAAQoR,MAGThQ,GAAY,qBAAKpB,UAAU,UAAf,SAA0BoB,UCY9B49B,GAhCc,SAAC,GAA2E,IAAD,IAAxE9K,EAAwE,EAAxEA,eAAgBxQ,EAAwD,EAAxDA,eAAgB2Q,EAAwC,EAAxCA,OACtDxL,EAAsBqL,EAAtBrL,SAAU5nB,EAAYizB,EAAZjzB,QACV8U,EAAW2N,EAAX3N,OACFkpB,EAAS,iBAAGpW,QAAH,IAAGA,OAAH,EAAGA,EAAUA,gBAAb,QAAyB,GAClCqW,EAAQ,iBAAGrW,QAAH,IAAGA,OAAH,EAAGA,EAAUvB,eAAb,QAAwB,GAChClW,EAAK,OAAGyX,QAAH,IAAGA,OAAH,EAAGA,EAAUzX,MAYlB+tB,EAAmB,mDAAa,cAAC,KAAD,CAAc7zB,KAAM2zB,OAE1D,OACE,eAAC,GAAD,CAAc7tB,MAAO+tB,EAAkB9K,OAAQA,EAAQte,OAAQA,EAAQ8S,SAAUA,EAAjF,UACE,uBACA,4CAfsBA,EACxB,iCACE,mBAAGvnB,GAAG,UAAUtB,UAAU,sCAA1B,SACE,cAAC,GAAD,CAAMma,KAAM0O,EAASxB,YAAaiB,UAAQ,MAE5C,cAACiB,GAAA,EAAD,CAAqBC,UAAU,SAAS5Q,OAAO,UAA/C,SACE,cAAC,GAAD,CAAMuB,KAAM0O,EAASxB,mBANU,kDAgBjC,0CACMjW,EAAQ,QAAU,WADxB,MAEGnQ,GAAW,gDACVA,GAAW,cAAC,KAAD,CAAcqK,KAAM4zB,EAApB,gBAA+B9tB,QAA/B,IAA+BA,IAAS8tB,W,oLCnCvDE,GAAU,SACVC,GAAqB,CACzB,kBACA,SACA,WACA,UACA,oBACA,iBACA,QACA,SACA,+BACA,UACA,UAaWC,GAAgB,SAAC93B,GAAiC,IAAD,IAC5D,OAAKkJ,aAASlJ,GAId,oBAAOA,EAAIqN,MAAM,KAAKrN,EAAI+3B,SAAS,OAAS,EAAI,UAAhD,aAAO,EAA6C1qB,MAAM,KAAK,UAA/D,QAAqE,GAH5D,UAME2qB,GAAc,SAAC5oB,EAAc6oB,GAAf,OACzBrjB,OAAOnP,OAAPmP,OAAA,IAAAA,QAAA,IAAAA,CAAA,GAAmBsjB,aAAOD,EAAQA,EAAOt9B,KAAI,kBAAM,OAAQyU,KClC9C+oB,GAF+B,SAACl/B,GAAD,OAAW,cAAC,GAAD,aAAgB0S,KAAK,UAAa1S,KCA9Em/B,GAAiB,SAAC,EAAD,GAAgE,IAA7DC,EAA4D,EAA5DA,OAAwBC,EAAoC,oBACvF,OAACD,QAAD,IAACA,KAAQjnB,SAIEinB,EAAOjnB,OAEfQ,MAAME,OAASwmB,EAAe,UAAY,YAGtCC,GAAmB,SAAC,GAAD,IAAGC,EAAH,EAAGA,QAASC,EAAZ,EAAYA,eAAZ,gBAC3BD,EAAQE,MADmB,aACTza,GAASwa,KAEnBE,GAAsB,SAAC,GAAD,IAAGD,EAAH,EAAGA,MAAOD,EAAV,EAAUA,eAAV,gBAC9BC,EAD8B,aACpBza,GAASwa,K,SC2BlBG,GAAkC,CACtCC,QAAS,QACTC,OAAQ,OACRC,MAAO,MACPC,OAAQ,QAGJC,GAAmE,CACvED,OAAQ,SAACE,GAAD,MAAoB,CAAEA,UAC9BH,MAAO,SAACI,GAAD,MAAmB,CAAEA,SAC5BL,OAAQ,SAACM,GAAD,MAAoB,CAAEA,UAC9BP,QAAS,SAACQ,GAAD,MAAqB,CAAEA,YAG5BC,GAAmF,CACvFN,OAAQO,KACRR,MAAOS,KACPV,OAAQW,KACRZ,QAASa,MAGLC,GAA4D,CAChEX,OAAQ,SAACrmB,GAAD,OAAUG,mBAAOH,EAAM,qBAC/BomB,MAAO,SAACpmB,GAAD,OAAUG,mBAAOH,EAAM,eAC9BmmB,OAHgE,SAGzDnmB,GACL,IAAMinB,EAAe9mB,mBAAO+mB,aAAelnB,GAAO,cAC5CmnB,EAAchnB,mBAAOinB,aAAapnB,GAAO,cAE/C,MAAM,GAAN,OAAUinB,EAAV,cAA4BE,IAE9BjB,QAAS,SAAClmB,GAAD,OAAUG,mBAAOH,EAAM,aAe5BqnB,GAAoB,SAACxQ,EAAYjb,GAAb,OAAkD0rB,cAC1E,SAAC1e,GAAD,OAAWoe,GAAoBnQ,GAAMrW,kBAASoI,EAAM5I,SACpDpE,IA8BI2rB,GAAiC,SACrC3rB,EACA4rB,EACA3Q,EACA4Q,GAEA,GAAIA,EACF,MAAO,CAAExlB,OAAOC,KAAKslB,GAAwBvlB,OAAOnP,OAAO00B,IAG7D,IAAMlC,EAxBe,SAACzO,EAAYjb,GAClC,IAAM8rB,EAAWf,GAAsB9P,GACjC1L,EAAY6b,GAAoBnQ,GAChC8Q,EAAYnnB,kBAAS5E,EAAO,GAAGoE,MAC/B4nB,EAAapnB,kBAAS5E,EAAOA,EAAO/T,OAAS,GAAGmY,MAChD7J,EAAOuxB,EAASC,EAAWC,GAC3BC,EAAWvB,GAAqBzP,GAEtC,MAAM,CACJ1L,EAAUyc,IADZ,oBAEKn4B,aAAQ0G,GAAM,SAAC2xB,GAAD,OAAS3c,EAAUtC,aAAI+e,EAAYC,EAASC,UAchDC,CAAelR,EAAMjb,GAEpC,MAAO,CAAE0pB,EAAQD,GAAYmC,EAAuBlC,KAGhD0C,GAAkB,SAAC56B,EAAgB24B,EAAepgC,GAAhC,MAAiE,CACvFogC,QACA34B,OACAnH,MAAM,EACNgiC,QAAS,GACTC,YAAaviC,EACbuZ,gBAAiBvZ,IAGfwiC,GAA+B,KAE7BC,GAAsB,SAC1B9C,EACA+C,EACAC,GAH0B,OAIvB,YAAqC,IAAlCC,EAAiC,oBACvC,GAAKD,GAAsBC,EAA3B,CADuC,IAUhC,EALCxzB,EAAUwzB,EAAVxzB,MAER,GAAIozB,KAAkB7C,EAAOvwB,GAC3BuzB,EAAkB,IAClBH,GAAgB,UAEhBG,EAAkBhD,EAAOvwB,IAAUszB,EAAgB/C,EAAOvwB,KAAW,IACrEozB,GAAa,UAAG7C,EAAOvwB,UAAV,QAAoB,QAqGtByzB,GAjGO,SAAC,GAEjB,IADFvxB,EACC,EADDA,MAAO2E,EACN,EADMA,OAAQ6sB,EACd,EADcA,kBACd,IADiCC,wBACjC,MADoD,WACpD,EADgEJ,EAChE,EADgEA,kBAChE,EACuBhgC,mBACxBsT,EAAO/T,OAAS,EA9FS,SAAC8gC,GAAmC,IAAD,EACxDC,EAAM,IAAIjmB,KACVilB,EAAapnB,kBAASmoB,GAO5B,iBANgBzlB,aAA8B,CAC5C,CAAE,kBAAM2jB,aAAiB+B,EAAKhB,IAAe,GAAGiB,aAAa,WAC7D,CAAE,kBAAM9B,aAAmB6B,EAAKhB,IAAe,GAAGiB,aAAa,UAC/D,CAAE,kBAAM9B,aAAmB6B,EAAKhB,IAAe,GAAGiB,aAAa,YAG1D9P,UAAP,QAAoB,UAqFE+P,CAAqBltB,EAAOA,EAAO/T,OAAS,GAAGmY,MAAQ,WAF1E,mBACK6W,EADL,KACWkS,EADX,OAI0CjgC,aAAU,GAJpD,mBAIKkgC,EAJL,KAImBC,EAJnB,KAMGZ,EAAkB9iB,mBAAQ,kBAjFJ,SAACsR,EAAYjb,GAAb,OAC5BA,EAAO6jB,QACL,SAACC,EAAK9W,GAAW,IAAD,EACR9a,EAAMk5B,GAAoBnQ,GAAMrW,kBAASoI,EAAM5I,OAKrD,OAHA0f,EAAI5xB,GAAJ,UAAW4xB,EAAI5xB,UAAf,QAAuB,GACvB4xB,EAAI5xB,GAAKme,KAAKrD,GAEP8W,IAET,IAuEoCwJ,CAAsBrS,EAAMjb,KAAS,CAAEib,EAAMjb,IAC7E4rB,EAAwBjiB,mBAAQ,kBAAM8hB,GAAkBxQ,EAAMsS,aAAQvtB,MAAU,CAAEib,EAAMjb,IAP3F,EAQ+B2J,mBAChC,kBAAMgiB,GAA+B3rB,EAAQ4rB,EAAuB3Q,EAAMmS,KAC1E,CAAEptB,EAAQib,EAAMmS,IAVf,mBAQK1D,EARL,KAQa8D,EARb,KAYGC,EAAqB9jB,mBACzB,kBAAM8f,GAAYgC,GAAkBxQ,EAAMsS,aAAQV,IAAqBnD,KACvE,CAAEmD,EAAmB5R,EAAMyO,IAEvBgE,EAAwB,WAC5B,IAAMC,EAAcvB,GAAgBoB,EAAe,SAAUxjC,MAE7D,OAAiC,IAA7B6iC,EAAkB5gC,OACb,CAAE0hC,GAKJ,CAAEA,EAFkBvB,GAAgBqB,EAAoBX,EAAkBzwB,QAM7EsD,EAAwB,CAC5BiuB,qBAAqB,EACrBC,QAAS,CACPC,OAAQ,CAAEjS,SAAS,GACnBkS,QAAS,CACPC,WAAW,EACXC,KAAM,IACNC,UAAW,CAAE/D,MAAOH,MAGxBmE,OAAQ,CACNC,EAAG,CACDC,aAAa,EACbC,MAAO,CACLC,UAAW,EACXvhC,SAAU0iB,KAGd8e,EAAG,CACDnzB,MAAO,CAAEwgB,SAAS,EAAM5Y,KAAMonB,GAAUpP,MAG5CwT,QAAS5E,IAEL6E,EAAkB,kBACtB,cAAC,KAAD,CACEl9B,KA5BwC,CAAEk4B,SAAQiF,SAAUjB,KA6B5D/tB,QAASA,EACTivB,kBAAmBpC,GAAoB9C,EAAQ+C,EAAiBC,MAIpE,OACE,eAACl1B,GAAA,EAAD,WACE,eAAC6tB,GAAA,EAAD,WACGhqB,EACD,qBAAKpR,UAAU,cAAf,SACE,eAAC+gB,GAAA,EAAD,WACE,cAAChH,EAAA,EAAD,CAAgBC,OAAK,EAACla,MAAM,OAAOE,UAAU,aAA7C,sBAGA,cAACia,EAAA,EAAD,CAAcP,OAAK,EAAnB,SACG0C,OAAOwoB,QAAQxE,IAAWj+B,KAAI,mCAAGkC,EAAH,KAAUwgC,EAAV,YAC7B,cAACrmB,EAAA,EAAD,CAA0B1R,OAAQkkB,IAAS3sB,EAAO2C,QAAS,kBAAMk8B,EAAQ7+B,IAAzE,SACGwgC,GADgBxgC,aAO3B,qBAAKrE,UAAU,mBAAf,SACE,cAAC,GAAD,CAAcwxB,QAAS2R,EAAchrB,SAAUirB,EAA/C,SACE,qEAIN,eAAC/H,GAAA,EAAD,CAAUr7B,UAAU,wBAApB,UAGG4iC,EAAkB5gC,OAAS,GAAKyiC,IACH,IAA7B7B,EAAkB5gC,QAAgByiC,W,UCnN5BK,GA5BmC,SAAC,GAAkE,IAAhEle,EAA+D,EAA/DA,WAAYd,EAAmD,EAAnDA,YAAaif,EAAsC,EAAtCA,eAAsC,IAAtB/X,gBAAsB,SAClH,GAAIpG,EAAa,EACf,OAAO,KAGT,IAAM5f,EAAU,SAACwgB,GAAD,OAA4B,kBAAOnB,GAAemB,IAASud,EAAevd,KAE1F,OACE,eAACV,GAAA,EAAD,CAAYC,cAAe7kB,IAAW,kCAAmC,CAAE,yBAA0B8qB,IAArG,UACE,cAAChG,GAAA,EAAD,CAAgBxN,SAAUsM,GAAe,EAAzC,SACE,cAACmB,GAAA,EAAD,CAAgBC,UAAQ,EAACzlB,IAAI,OAAOuF,QAASA,EAAQ8e,EAAc,OAEpED,GAAsBC,EAAac,GAAYzkB,KAAI,SAACmkB,EAAYpX,GAAb,OAClD,cAAC8X,GAAA,EAAD,CAEExN,SAAU6M,GAAeC,GACzBxZ,OAAQgZ,IAAgBQ,EAH1B,SAKE,cAACW,GAAA,EAAD,CAAgBxlB,IAAI,OAAOuF,QAASA,EAAQsf,GAA5C,SAA0DC,GAAmBD,MAJxEE,GAAWF,EAAYpX,OAOhC,cAAC8X,GAAA,EAAD,CAAgBxN,SAAUsM,GAAec,EAAzC,SACE,cAACK,GAAA,EAAD,CAAgBE,MAAI,EAAC1lB,IAAI,OAAOuF,QAASA,EAAQ8e,EAAc,WCNjEkf,GAAe,SAAC1sB,EAAoBvC,GAArB,OACnBA,EAAOwF,QAAO,SAACwH,GAAD,OALW,SAAC,EAAmEzK,GAApE,IAAG2sB,EAAH,EAAGA,QAASC,EAAZ,EAAYA,GAAIC,EAAhB,EAAgBA,QAASC,EAAzB,EAAyBA,QAASC,EAAlC,EAAkCA,KAAS/1B,EAA3C,iEACzB,UAAG21B,EAAH,YAAcC,EAAd,YAAoBC,EAApB,YAA+BC,EAA/B,YAA0CC,EAA1C,YAAmD/1B,EAA+Bg2B,YAAat8B,cAAcu2B,SAC3GjnB,EAAWtP,eAGYu8B,CAAmBxiB,EAAOzK,OAE/CktB,GAAkB,SAACC,EAA8BntB,EAAgC3D,GACrF,IACM+wB,EAHW,SAAC/wB,EAAoBoB,GAArB,OAAmD7B,EAA0B6B,EAAQpB,GAGjFgxB,CAAWhxB,EADT2D,EAAa0sB,GAAa1sB,EAAYmtB,GAA5B,aAA8CA,IAEzEG,EAAQF,EAAa1jC,OAG3B,MAAO,CAAE6jC,aAFYC,aAZL,GAY2BJ,GAEpBE,UAmLVG,GAhLK,SAAC,GAOI,IAAD,IANtBhwB,EAMsB,EANtBA,OAMsB,IALtBiwB,sBAKsB,MALL,GAKK,EAJtBvD,EAIsB,EAJtBA,kBACA5hC,EAGsB,EAHtBA,eAGsB,IAFtBolC,kBAEsB,MAFT1hC,OAAO0hC,WAEE,MADtBC,sBACsB,SAChBC,EAAmB,iDACnBC,EAAc,kBAAMH,EAAW,sBAAsBI,SAFrC,EAIwB5jC,mBAAS2jC,KAJjC,mBAIdE,EAJc,KAIEC,EAJF,OAKgB9jC,wBAA6BK,GAL7C,mBAKdwV,EALc,KAKFC,EALE,OAMM9V,mBAAsB,IAN5B,mBAMdkS,EANc,KAMP6xB,EANO,KAOhBC,EAAY/mB,mBAAQ,kBAAM8lB,GAAgBzvB,EAAQuC,EAAY3D,KAAQ,CAAE2D,EAAY3D,IACpFzP,EAAcrC,kBAAO,GARL,EASIJ,mBAAS,GATb,mBASd+kB,EATc,KASRkf,EATQ,KAUhB3rB,EAlCU,GAkCJyM,EACN1M,EAAQC,EAnCE,GAoCV4rB,EAAe70B,aAAkBjR,GACjC+lC,EAAkB,EAAIjhB,OAAOghB,GAAgBhhB,OAAOugB,GAEpDne,EAAgB,SAAC3T,GAAD,OACpB,kBAAMoyB,EAAS,CAAEpyB,QAAOC,IAAKT,EAAkBQ,EAAOO,EAAMP,MAAOO,EAAMN,SACrE2T,EAAkB,SAAC5T,GAAD,OACtB,cAACiP,GAAD,CAAgBC,aAAc3O,EAAOP,MAAOA,EAAOpU,UAAU,+BAgB/D,OAdAc,qBAAU,WACR,IAAM+lC,EAAW,kBAAMN,EAAkBH,MAIzC,OAFA7hC,OAAO44B,iBAAiB,SAAU0J,GAE3B,kBAAMtiC,OAAOuiC,oBAAoB,SAAUD,MACjD,IACH/lC,qBAAU,WACR4lC,EAAQ,IAEPxhC,EAAYlC,SAAWy/B,EAAkB,IAC1Cv9B,EAAYlC,SAAU,IACrB,CAAEsV,IAGH,wBAAOtY,UAAU,6EAAjB,UACE,wBAAOA,UAAU,uBAAjB,UACE,+BACE,oBACEA,UAAS,UAAKmmC,EAAL,gBACTn/B,QAAS,kBAAMy7B,EACbuD,EAAehkC,OAASykC,EAAUb,MAAQa,EAAUZ,aAAakB,OAAS,KAH9E,SAME,cAAC,IAAD,CAAiBplC,KAAMs6B,IAAWj8B,UAAWkC,IAAW,CAAE,eAAgB8jC,EAAehkC,OAAS,QAEnG2kC,GACC,qBAAI3mC,UAAS,UAAKmmC,EAAL,gBAAqCn/B,QAAS+gB,EAAc,gBAAzE,UACE,cAAC,IAAD,CAAiBpmB,KAAMqlC,MACtBhf,EAAgB,mBAGrB,qBAAIhoB,UAAWmmC,EAAkBn/B,QAAS+gB,EAAc,QAAxD,iBAEGC,EAAgB,WAEnB,qBAAIhoB,UAAWmmC,EAAkBn/B,QAAS+gB,EAAc,WAAxD,oBAEGC,EAAgB,cAEnB,qBAAIhoB,UAAWmmC,EAAkBn/B,QAAS+gB,EAAc,QAAxD,iBAEGC,EAAgB,WAEnB,qBAAIhoB,UAAWmmC,EAAkBn/B,QAAS+gB,EAAc,WAAxD,oBAEGC,EAAgB,cAEnB,qBAAIhoB,UAAWmmC,EAAkBn/B,QAAS+gB,EAAc,MAAxD,eAEGC,EAAgB,SAEnB,qBAAIhoB,UAAWmmC,EAAkBn/B,QAAS+gB,EAAc,WAAxD,qBAEGC,EAAgB,cAElBke,GACC,qBAAIlmC,UAAWmmC,EAAkBn/B,QAAS+gB,EAAc,cAAxD,wBAEGC,EAAgB,oBAIvB,6BACE,oBAAI4H,QAASgX,EAAiB5mC,UAAU,MAAxC,SACE,cAAC,EAAD,CAAaqY,UAAQ,EAACD,OAAO,EAAOD,SAAUI,WAIpD,oCACG,UAACkuB,EAAUZ,aAAare,EAAO,UAA/B,OAAC,EAAkCxlB,SAClC,6BACE,oBAAI4tB,QAASgX,EAAiB5mC,UAAU,cAAxC,sDAHN,UAQGymC,EAAUZ,aAAare,EAAO,UARjC,aAQG,EAAkCrlB,KAAI,SAAC4gB,EAAO7T,GAC7C,IAAM+3B,EAAajB,EAAezG,SAASxc,GAE3C,OACE,qBAEE3J,MAAO,CAAEE,OAAQ,WACjBtZ,UAAWkC,IAAW,CAAE,eAAgB+kC,IACxCjgC,QAAS,kBAAMy7B,EACbwE,EAAajB,EAAezqB,QAAO,SAAC2rB,GAAD,OAAOA,IAAMnkB,KAAtC,uBAAoDijB,GAApD,CAAoEjjB,MALlF,UAQE,oBAAI/iB,UAAU,cAAd,SACGinC,GAAc,cAAC,IAAD,CAAiBtlC,KAAMs6B,IAAWj8B,UAAU,mBAE5D2mC,GACC,oBAAI3mC,UAAU,cAAd,SACG+iB,EAAMokB,cACL,qCACE,cAAC,IAAD,CAAiBxlC,KAAMqlC,IAAS1lC,GAAE,iBAAY4N,KAC9C,cAACqa,GAAA,EAAD,CAAqBC,UAAU,QAAQ5Q,OAAM,iBAAY1J,GAAzD,4DAOR,6BAAI,cAAC,GAAD,CAAMiL,KAAM4I,EAAM5I,SACtB,6BAAK4I,EAAMqiB,UACX,6BAAKriB,EAAMsiB,OACX,6BAAKtiB,EAAMkiB,UACX,6BAAKliB,EAAMmiB,KACX,6BAAKniB,EAAMoiB,UACVe,GAAkB,6BAAMnjB,EAAgCuiB,eA5BpDp2B,SAiCZu3B,EAAUb,MA/JC,IAgKV,gCACE,6BACE,oBAAIhW,QAASgX,EAAiB5mC,UAAU,iDAAxC,SACE,sBAAKA,UAAU,MAAf,UACE,qBAAKA,UAAU,WAAf,SACE,cAAC,GAAD,CACE4mB,WAAYje,KAAK0c,KAAKohB,EAAUb,MAtKlC,IAuKE9f,YAAa0B,EACbud,eAAgB2B,EAChB1Z,SAAUsZ,MAGd,qBACEtmC,UAAWkC,IAAW,WAAY,CAChC,8CAA+CokC,EAC/C,mBAAoBA,IAHxB,SAME,0CACS,4BAAI7gB,GAAS3K,EAAQ,KAD9B,MACyC,IACvC,4BAAI2K,GAASS,aAAInL,EAAK0rB,EAAUb,UAFlC,MAEkD,IAChD,4BAAIngB,GAASghB,EAAUb,2BC7J5BwB,GAvCS,SAAC,GAAwE,IAAtEC,EAAqE,EAArEA,WAAYC,EAAyD,EAAzDA,aAAyD,IAA3CpJ,iBAA2C,MAA/B,GAA+B,IACjDj7B,cADiD,mBACtFskC,EADsF,KACvEC,EADuE,KAC9DC,EAD8D,OAEnCxkC,cAFmC,mBAEtFykC,EAFsF,KAEpEC,EAFoE,KAEpDC,EAFoD,OAG9CnlC,mBAAsB,IAHwB,mBAGtFolC,EAHsF,KAGrEC,EAHqE,KAIxFC,EAAYllC,mBAaZmlC,EAAuB,SAACC,GAAD,OAAuB,WAClDH,EAAmBG,EAA2B/J,EAZQ3iB,QAAO,gBAAGmjB,EAAH,EAAGA,SAAH,OAAkB4I,EAAa/H,SAASb,MAY1CR,GAC3DsJ,MAGF,OACE,qCACE,wBAAQxnC,UAAU,uCAAuC2d,IAAKoqB,EAAkB/gC,QAjBpE,WACd,IAAKsgC,EAIH,OAHAQ,EAAmB5J,QACnBsJ,IAKFI,KASE,SACE,cAAC,IAAD,CAAiBjmC,KAAMumC,QAEzB,cAAC3e,GAAA,EAAD,CAAqBC,UAAU,OAAO5Q,OAAS,kBAAMmvB,EAAU/kC,SAA/D,yBACA,cAAC8W,EAAA,EAAD,CAAUjO,OAAQ67B,EAAkB9tB,OAAQ+tB,EAAgB5Q,UAAQ,EAApE,SACE,eAAC9c,EAAA,EAAD,CAAcP,OAAK,EAAnB,UACE,cAAC8E,EAAA,EAAD,CAAcxX,QAASghC,GAAqB,GAA5C,gCACA,cAACxpB,EAAA,EAAD,CAAcxX,QAASghC,GAAqB,GAA5C,iDAGJ,cAAC,GAAD,CAAUpuB,OAAQ6tB,EAAU57B,OAAQ07B,EAAan2B,MAAOi2B,EAAYnJ,UAAW2J,Q,UC5CxEM,GAAgB,SAACplB,GAAD,OAAwCA,EAAMpY,eAAe,eAU7Ey9B,GAAuBn9B,YAClCo9B,cAAQ,SAACC,GAAD,OAA2BH,GAAcG,EAASvlB,OAAS,eAAiB,oBAEpF,SAACsK,GAAD,oBAAiC5J,aAAc,GAAI8kB,cAAe,IAAOlb,MAO9Dmb,GAA2B,SACtC5F,EACA6F,GAFsC,OAG5BhH,aAAQ1pB,YAAK0wB,GAAkB7F,IAE9B8F,GAAc,SAAC,GAAiF,IAAD,IAA9ElhB,EAA8E,EAA9EA,KAAM2T,EAAwE,EAAxEA,aAAc5f,EAA0D,EAA1DA,OAAQD,EAAkD,EAAlDA,UAKxD,MAAO,CAAEkM,OAAM2T,eAAc5e,UAJd,WAAa,OAATjB,QAAS,IAATA,OAAA,EAAAA,EAAWiB,YAAa/B,GAAa,OAACc,QAAD,IAACA,OAAD,EAACA,EAAWiB,kBAArD,aAAoEzZ,EAI3C0Z,QAH3B,WAAa,OAATlB,QAAS,IAATA,OAAA,EAAAA,EAAWkB,UAAWhC,GAAa,OAACc,QAAD,IAACA,OAAD,EAACA,EAAWkB,gBAAnD,aAAgE1Z,EAG5B6lC,aAFvB,OAANptB,QAAM,IAANA,OAAA,EAAAA,EAAQotB,mBAAe7lC,IC3BvC8lC,GAAmB,SAAC7lB,EAAwB8lB,GAAzB,OACtB5+B,YAAM8Y,IAAUrS,aAASqS,EAAM8lB,KAE5BC,GAA0B,SAACC,GAC/B,MAAuB,kBAAZA,EACFA,EAGFA,EAAUC,WAAWD,GAAW,GAenCE,GAA+B,SAACJ,GAAD,OAAsC,SAACjyB,EAAcmM,GACxF,IACM1e,EADsBukC,GAAiB7lB,EAAO8lB,GAChB9lB,EAAM8lB,GAAgB,UAE1DjyB,EAAMvS,IAAUuS,EAAMvS,IAAU,GAAK,IAGjC6kC,GAA+BD,GAA6B,WAC5DE,GAA4BF,GAA6B,QA6BlDG,GAAyB,SAACrzB,GAAD,OAA+BA,EAAO6jB,QAC1E,SAAChjB,EAAoBmM,GAUnB,OA5D0B,SAACsmB,EAAD,GAA8C,IAA3BnE,EAA0B,EAA1BA,GAC/CmE,EAAQnE,IAAOmE,EAAQnE,IAAO,GAAK,EAmDjCoE,CAAsB1yB,EAAMsuB,GAAIniB,GAhDA,SAACwmB,EAAD,GAAyD,IAAhCtE,EAA+B,EAA/BA,QAC3DsE,EAActE,IAAYsE,EAActE,IAAY,GAAK,EAgDvDuE,CAA4B5yB,EAAM6yB,SAAU1mB,GA7CX,SAAC2mB,EAAD,GAAkE,IAA/BrzB,EAA8B,EAAvC8uB,QAC7DuE,EAAerzB,IAAWqzB,EAAerzB,IAAW,GAAK,EA6CvDszB,CAA6B/yB,EAAMgzB,UAAW7mB,GAC9CmmB,GAA6BtyB,EAAMizB,UAAW9mB,GAC9ComB,GAA0BvyB,EAAMkzB,OAAQ/mB,GAlCT,SAACgnB,EAA8ChnB,GAChF,GAAK6lB,GAAiB7lB,EAAO,SAA0B,YAAfA,EAAMsiB,KAA9C,CAD2G,IAKnGA,EAA8BtiB,EAA9BsiB,KAAM2E,EAAwBjnB,EAAxBinB,SAAUC,EAAclnB,EAAdknB,UAClBC,EAAcH,EAAkB1E,IAAS,CAC7C3G,SAAU2G,EACV1G,MAAO,EACPL,QAAS,CAAEwK,GAAwBkB,GAAWlB,GAAwBmB,KAGxEC,EAAYvL,QAEZoL,EAAkB1E,GAAQ6E,GAqBxBC,CAA2BvzB,EAAMwzB,aAAcrnB,GAlBjB,SAACsnB,EAAyBtnB,GAC1D,GDlDqC,SAACA,GAAD,OACrCA,EAAMpY,eAAe,cCiDhB2/B,CAAwBvnB,GAA7B,CADqF,IAK7EuiB,EAAeviB,EAAfuiB,WAER+E,EAAiB/E,IAAe+E,EAAiB/E,IAAe,GAAK,GAYnEiF,CAA0B3zB,EAAM4zB,YAAaznB,GAEtCnM,IAET,CAAEsuB,GAAI,GAAIuE,SAAU,GAAIG,UAAW,GAAIC,UAAW,GAAIC,OAAQ,GAAIM,aAAc,GAAII,YAAa,MAGtFC,GAAkBtoC,cAAI,SAAC4gB,GAAmC,IAC7D2nB,EAAkE3nB,EAAlE2nB,UAAWvwB,EAAuD4I,EAAvD5I,KAAMgrB,EAAiDpiB,EAAjDoiB,QAASwF,EAAwC5nB,EAAxC4nB,cADkC,EACM5nB,EAAzBokB,oBADmB,SAE9DyD,EAAM,yBACVzwB,OACAgtB,gBRlE0B,SAACuD,GAC7B,IAAKh6B,aAASg6B,GACZ,MAAO,CAAEzF,QAAS7F,GAAS8F,GAAI9F,IAFqC,MAKbyL,KAAOxiC,MAAMqiC,GAA7CzF,EAL6C,EAK9DA,QAAW1jC,KAA6B2jC,EALsB,EAKlCA,GAAM3jC,KAE1C,MAAO,CAAE2jC,GAAE,OAAEA,QAAF,IAAEA,IAAM9F,GAAS6F,QAASA,GAAW5F,GAAmBE,SAAS0F,GAAWA,EAAU7F,IQ4D5F0L,CAAeJ,IAHR,IAIVvF,QAAS7F,GAAc6F,GACvBC,SAAsB,OAAbuF,QAAa,IAAbA,OAAA,EAAAA,EAAeI,cAAe,UACvC1F,MAAmB,OAAbsF,QAAa,IAAbA,OAAA,EAAAA,EAAejM,WAAY,UACjCsL,SAAQ,OAAEW,QAAF,IAAEA,OAAF,EAAEA,EAAeX,SACzBC,UAAS,OAAEU,QAAF,IAAEA,OAAF,EAAEA,EAAeV,YAG5B,OAAK9B,GAAcplB,GAIZ,2BAAK6nB,GAAZ,IAAoBz3B,KAAM4P,EAAM5P,KAAMmyB,WAAYviB,EAAMuiB,aAH/CsF,KCnFEI,GAAuB,SAAC,GAE/B,IADF7yB,EACC,EADDA,SACC,IADSsF,gBACT,MADoB,GACpB,EADwBzd,EACxB,EADwBA,UAAWkmC,EACnC,EADmCA,eAAgB+E,EACnD,EADmDA,cAEtD,IAAKA,IAAkB/E,EACrB,OAAO,KAFN,IAKKgF,EAA0CztB,EAA1CytB,iBALL,EAK+CztB,EAAxBkrB,mBALvB,SAMGwC,EAA+B,SAACh4B,GAAD,MAA+C,CAClFrG,OAAQo+B,IAAqB/3B,EAC7BnM,QAAS,kBAAMmR,EAAS,2BAAKsF,GAAN,IAAgBytB,iBAAkB/3B,KAAI,OAAKsK,QAAL,IAAKA,OAAL,EAAKA,EAAUytB,uBAAmBpoC,EAAYqQ,QAI7G,OACE,eAAC,EAAD,CAAa6F,KAAK,UAAUS,kBAAmBzZ,EAAWA,UAAU,OAAO0Z,OAAK,EAACC,SAAU,IAA3F,UACGsxB,GACC,qCACE,cAACzsB,EAAA,EAAD,CAAcgB,QAAM,EAApB,mBACA,cAAChB,EAAA,EAAD,CAAc1R,OAAQ67B,EAAa3hC,QAPvB,kBAAMmR,EAAS,2BAAKsF,GAAN,IAAgBkrB,cAAa,OAAClrB,QAAD,IAACA,KAAUkrB,iBAOlE,uCAIHsC,GAAiB/E,GAAkB,cAAC1nB,EAAA,EAAD,CAAcC,SAAO,IAExDynB,GACC,qCACE,cAAC1nB,EAAA,EAAD,CAAcgB,QAAM,EAApB,iCACA,cAAChB,EAAA,EAAD,2BAAkB2sB,EAA6B,aAA/C,2BACA,cAAC3sB,EAAA,EAAD,2BAAkB2sB,EAA6B,sBAA/C,oCACA,cAAC3sB,EAAA,EAAD,2BAAkB2sB,EAA6B,gBAA/C,iCAIJ,cAAC3sB,EAAA,EAAD,CAAcC,SAAO,IACrB,cAACD,EAAA,EAAD,CAAchF,UAAW9I,aAAS+M,GAAWzW,QAAS,kBAAMmR,EAAS,KAArE,SAA0E,oD,SCxCnEizB,GAAoD,SAAC,GAAe,IAAD,IACtEC,EADsE,EAAZ3I,MAC1D2I,OADsE,YAEvCA,EAAO9jC,YAFgC,QAExB,GAFwB,IAEtEk4B,cAFsE,MAE7D,GAF6D,MAEzDiF,gBAFyD,MAE9C,GAF8C,EAGpDn7B,EAHoD,YAGxCm7B,EAHwC,MAGrErrB,gBACDiyB,GAJsE,UAIrDD,EAAO31B,eAJ8C,QAInC,IAAnC41B,aAER,OACE,oBAAItrC,UAAU,wBAAd,SACIy/B,EAAoBt9B,KAAI,SAAC+9B,EAAOhxB,GAAR,aACxB,qBAAgBlP,UAAU,qCAA1B,UACE,qBACEA,UAAU,oCACVoZ,MAAO,CAAEC,gBAAe,UAAG9P,EAAoB2F,UAAvB,QAAiCo8B,KAE3D,uBAAOtrC,UAAU,6CAAjB,SAA+DkgC,MALxDA,SCJXuD,GAAwB,SAACl8B,GAAD,MAAoC,CAChE,CACEA,OACA8R,gBAAiB,CACf,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,WAEFgpB,YAAaxvB,eAAuBN,KAAqBD,KACzDi5B,YAAa,KAQJC,GAAwCC,gBAAK,YAAgB,IAAb70B,EAAY,EAAZA,MAAY,EACrCnU,qBADqC,mBAC/DipC,EAD+D,KACrDC,EADqD,KAEjElM,EAASpjB,aAAKzF,GACdrP,EAAO0F,aAAO2J,GAEdlB,EAAwB,CAC5BkuB,QAAS,CACPC,OAAQ,CAAEjS,SAAS,GACnBkS,QAAS,CACPC,WAAW,EACXE,UAAW,CAAE/D,MAAOC,OAIpByL,EAnBkB,SAACnM,EAAkBl4B,GAAnB,MAAkD,CAC1Ek4B,SACAiF,SAAUjB,GAAsBl8B,IAiBdskC,CAAkBpM,EAAQl4B,GAE5C,OACE,sBAAKvH,UAAU,MAAf,UACE,qBAAKA,UAAU,qBAAf,SACE,cAAC,KAAD,CACE8rC,OAAQ,IACRvkC,KAAMqkC,EACNl2B,QAASA,EACTiI,IAAK,SAACxO,GACJw8B,EAAW,OAACx8B,QAAD,IAACA,SAAWrM,QAI7B,qBAAK9C,UAAU,qBAAf,SACG0rC,GAAY,cAAC,GAAD,CAAqBhJ,MAAOgJ,Y,UC1DpCK,GAAgC,SAAC,GAAD,IAAG36B,EAAH,EAAGA,MAAO46B,EAAV,EAAUA,OAAQ5qC,EAAlB,EAAkBA,SAAlB,OAC3C,eAACmM,GAAA,EAAD,WACE,cAAC6tB,GAAA,EAAD,CAAYp7B,UAAU,qBAAtB,SAA6D,oBAAVoR,EAAuBA,IAAUA,IACpF,cAACiqB,GAAA,EAAD,UAAWj6B,IACV4qC,GAAU,cAACC,GAAA,EAAD,CAAYjsC,UAAU,6BAAtB,SAAoDgsC,QCHtDE,GAAgD,SAAC,GAAD,IAAG96B,EAAH,EAAGA,MAAOwF,EAAV,EAAUA,MAAV,OAC3D,cAAC,GAAD,CAAWxF,MAAOA,EAAlB,SACE,cAACo6B,GAAD,CAAe50B,MAAOA,O,8BCgBXu1B,GAnBY,SAAC,GAAD,IAAGC,EAAH,EAAGA,gBAAiBC,EAApB,EAAoBA,OAAQhoC,EAA5B,EAA4BA,MAAOC,EAAnC,EAAmCA,SAAnC,OACzB,eAACyc,GAAA,EAAD,WACE,cAAChH,EAAA,EAAD,CAAgBC,OAAK,EAACla,MAAM,OAAOE,UAAWosC,EAA9C,sBAGA,eAACnyB,EAAA,EAAD,CAAcP,OAAK,EAAnB,UACG2yB,EAAOlqC,KAAI,SAACg5B,GAAD,OACV,eAAC3c,EAAA,EAAD,CAAiC1R,OAAQquB,IAAiB92B,EAAO2C,QAAS,kBAAM1C,EAAS62B,IAAzF,UACE,4BAAIA,IADN,oBAAmBA,MAIrB,cAAC3c,EAAA,EAAD,CAAcC,SAAO,IACrB,cAACD,EAAA,EAAD,CAAchF,SAAUnV,IAAUioC,IAAUtlC,QAAS,kBAAM1C,EAASgoC,MAApE,SACE,0DCJFC,GAAoB,SAACrM,GAAD,OAAmBA,EAAMsM,WAAW,UAAY,GAAKtM,GAIzEuD,GAAwB,SAC5Bl8B,EACAklC,EACA5J,GAEA,IAAMa,EAA4B,CAChCn8B,OACA24B,MAAO2C,EAAmB,eAAiB,SAC3CxpB,gBAAiBlH,KACjBkwB,YAAatiC,KACbwrC,YAAa,GAGf,OAAIkB,EAAgB7P,OAAM,SAACv4B,GAAD,OAAqB,IAAVA,KAC5B,CAAEq/B,GAWJ,CAAEA,EARgC,CACvCxD,MAAK,OAAE2C,QAAF,IAAEA,IAAoB,WAC3Bt7B,KAAMklC,EACNpzB,gBAAiBhH,KACjBgwB,YAAajwB,KACbm5B,YAAa,KAgBXhJ,GAAsB,SAAC9C,EAAkBz4B,GAAnB,OAAyD,YAA+B,IAA5B07B,EAA2B,oBAC5G17B,GAAY07B,GAIjB17B,EAAQy4B,EAAOiD,EAAMxzB,UAGVw9B,GAAkD,SAAC,GAE1D,IADF91B,EACC,EADDA,MAAO+1B,EACN,EADMA,iBAAkB9J,EACxB,EADwBA,iBAAkB77B,EAC1C,EAD0CA,QAASif,EACnD,EADmDA,IAEhDwZ,EAASpjB,aAAKzF,GAAOzU,IAAIoqC,IACzBhlC,EAAO0F,aArDS,SAAC2J,GAAD,QAAgDA,GAASwF,OAAOC,KAAKzF,GAAO5U,OAAS,EAsDxG4qC,CAAgBD,GAA4BtwB,aAAKswB,GAAkB/S,QAAO,SAACC,EAAKgT,GAK/E,OAJIhT,EAAIgT,KACNhT,EAAIgT,IAAmBF,EAAiBE,IAGnChT,IALoC,eAMrCjjB,IAN6BA,GAQjC61B,EAAkBjN,GAAW,OAACmN,QAAD,IAACA,IAAoB,GAAIlN,GAEtD/pB,EAAwB,CAC5BkuB,QAAS,CACPC,OAAQ,CAAEjS,SAAS,GACnBkS,QAAS,CACPnY,KAAM,IAENpQ,OAAQ,kBAAyB,KAAzB,EAAG2kB,OACX+D,UAAW,CAAE/D,MAAOH,MAGxBmE,OAAQ,CACNK,EAAG,CACDH,aAAa,EACb0I,SAAS,EACT7mB,MACAoe,MAAO,CACLC,UAAW,EACXvhC,SAAU0iB,KAGd0e,EAAG,CAAE2I,SAAS,IAEhBtI,QAAS5E,GACTmN,UAAW,KAEPnB,EA3DkB,SACxBnM,EACAl4B,EACAklC,EACA5J,GAJwB,MAKT,CACfpD,SACAiF,SAAUjB,GAAsBl8B,EAAMklC,EAAiB5J,IAoDrCgJ,CAAkBpM,EAAQl4B,EAAMklC,EAAiB5J,GAC7DiJ,EAzFgB,SAACrM,GAAD,OAA0CA,EAAOz9B,OAAS,GAAqB,GAAhBy9B,EAAOz9B,YAAcc,EAyF3FkqC,CAAgBvN,GAGzBwN,EAAuB,SAACC,GAAD,OAC3B,cAAC,KAAD,CAEE3lC,KAAMqkC,EACNl2B,QAASA,EACTo2B,OAAQA,EACRnH,kBAAmBpC,GAAoB9C,EAAQz4B,IALjD,UACU8kC,EADV,YACoBoB,KAQtB,OACE,0CAGwBpqC,IAArB6pC,GAAkCM,EAAqB,mBAClCnqC,IAArB6pC,GAAkCM,EAAqB,qBC5GxDE,GAAkB,SAAC9oC,GAAD,MAAgC,WAAhB8O,aAAK9O,GAAsB+oC,aAAQ/oC,GAASA,GAC9EgpC,GAAkB,SAAC,GAAD,4BAClBC,GAAoB,SAAC,GAAD,4BAEbC,GAAsD,SAAC,GAQ7D,IAPL32B,EAOI,EAPJA,MACA+1B,EAMI,EANJA,iBACAv7B,EAKI,EALJA,MACAo8B,EAII,EAJJA,aACAC,EAGI,EAHJA,mBAGI,IAFJC,sBAEI,SADDp+B,EACC,2GACwB7M,mBAAwB,IADhD,mBACIkS,EADJ,KACW6xB,EADX,OAEoC/jC,mBAAS,GAF7C,mBAEIqjB,EAFJ,KAEiBif,EAFjB,OAGsCtiC,mBAAS,IAH/C,mBAGI04B,EAHJ,KAGkBwS,EAHlB,KAiBEC,EAA4B,SAAC5nB,GACjC,IAAMwB,EAAOxB,EAAMF,EAAc,GAEjC,GAAIA,EAAcE,EAAMhkB,OACtB,OAAOwlB,EAGT,IAAMqmB,EAAkB7nB,EAAM,GAAGhkB,OAGjC,MAAM,GAAN,oBAAYwlB,GAAZ,aAAqB5d,aAAQikC,EAAkBrmB,EAAKxlB,QAAQ,SAAC8rC,GAAD,MAAiB,CAAC,UAAD,OAAYA,GAAK,SA3B5F,EA+BmB,SAACl3B,EAAc+1B,EAAqCa,GACzE,IAAMO,EA3BuB,SAACn3B,EAAc42B,GAC5C,IAAMQ,EAAQhtB,aAAQpK,GAChBm3B,EAAep5B,EAAMP,MAAgB65B,aACzChjC,YACE0J,EAAMP,QAAUgI,OAAOC,KAAKmxB,GAAc,GAAKH,GAAkBC,GACjEH,IAEFa,GALiCA,EAQnC,OAAQr5B,EAAMN,KAAqB,QAAdM,EAAMN,IAA8BivB,aAAQyK,GAAtBA,EAiBvBG,CAAuBt3B,EAAO42B,GAC5CW,EAAaJ,EAAY5rC,IAAIkrC,IAE7Be,EAAyBzB,GAAoB3rB,aAAQ,2BACpD0e,aAAOyO,EAAYA,EAAWhsC,KAAI,kBAAM,OAAQwqC,IAGvD,GAAIoB,EAAY/rC,QAAUm5B,EACxB,MAAO,CACLkT,iBAAkB5U,aAAUsU,GAC5BO,4BAA6BF,GAA0B3U,aAAU2U,IAIrE,I/EvEqB1oB,E+EsDGkB,EAiBlBZ,EAAQ8f,aAAW3K,EAAc4S,GACjCQ,EAAmBH,GAA0BtI,aAAW3K,EAAciT,GAE5E,MAAO,CACLC,iBAAkB5U,aAAUmU,EAA0B5nB,IACtDsoB,4BAA6BC,GAAoB9U,aAAUmU,EAA0BW,IACrF5mB,YAvBsBf,EAuBOZ,EAAMhkB,OAtBrC,cAAC,GAAD,CAAiB8jB,YAAaA,EAAac,WAAYA,EAAYme,eAAgBA,KAuBjF9e,K/E9EmBP,E+E8EL/c,KAAKsd,IAAL,MAAAtd,KAAI,aAAQolC,EAAY5rC,IAAImrC,M/EpFpB,GAMgBjoB,GAAKK,EANrB,M+EwFiD8oB,CACzE53B,EACA+1B,GAAoBvwB,OAAOC,KAAKswB,GAAkB3qC,OAAS,EAAI2qC,OAAmB7pC,EAClF0qC,GAHMa,EAzDJ,EAyDIA,iBAAkBC,EAzDtB,EAyDsBA,4BAA6B3mB,EAzDnD,EAyDmDA,WAAY1B,EAzD/D,EAyD+DA,IAK7DqhB,EAAelrB,OAAOC,KAAKgyB,GAqCjC,OACE,cAAC,GAAD,CACEj9B,MAtCiB,kBACnB,qCACGA,EACD,qBAAKpR,UAAU,cAAf,SACE,cAACygB,GAAD,CACEE,UAAU,EACVjH,OAAK,EACLgH,MAAO8sB,EACP74B,MAAOA,EACPwD,SAAU,SAAC/D,EAAOC,GAChBmyB,EAAS,CAAEpyB,QAAOC,QAClB0wB,EAAe,QAIpB2I,GAAkBtxB,OAAOC,KAAKzF,GAAO5U,OAAS,IAC7C,qBAAKhC,UAAU,cAAf,SACE,cAAC,GAAD,CACEosC,gBAAgB,kBAChBC,OAAQ,CAAE,GAAI,IAAK,IAAK,KACxBhoC,MAAO82B,EACP72B,SAAU,SAAC62B,GACTwS,EAAgBxS,GAChB4J,EAAe,QAKtB0I,GACC,qBAAKztC,UAAU,cAAf,SACGytC,EAAmB9lB,EAAa2f,OAAexkC,SASpDkpC,OAAQrkB,EAFV,SAIE,cAAC,GAAD,aAAoB/Q,MAAOy3B,EAAkB1B,iBAAkB2B,EAA6BroB,IAAKA,GAAS3W,OlFvF1Gm/B,GAAgD,CACpDC,OAAQ,CAAEt9B,MAAO,UAAWu9B,QAAS,UAAWhtC,KAAMitC,KACtDC,UAAW,CAAEz9B,MAAO,aAAcu9B,QAAS,aAAchtC,KAAMmtC,KAC/DC,WAAY,CAAE39B,MAAO,cAAeu9B,QAAS,cAAehtC,KAAMqtC,KAClE76B,KAAM,CAAE/C,MAAO,OAAQu9B,QAAS,OAAQhtC,KAAMstC,MAK1CC,GAAyD,SAAC,GAAD,IAAGP,EAAH,EAAGA,QAASv9B,EAAZ,EAAYA,MAAOzP,EAAnB,EAAmBA,KAAMR,EAAzB,EAAyBA,GAAzB,OAC7D,eAAC0L,GAAA,EAAD,CACEpL,IAAK0tC,IACLnvC,UAAU,yBACVmB,GAAIA,EACJoO,SAAU,SAAC+e,EAAD,YAAYxpB,SAAkCsqC,SAAT,gBAA2BT,KAC1Ev/B,SAAO,EALT,UAOE,cAAC,IAAD,CAAiBzN,KAAMA,IACvB,sBAAM3B,UAAU,0BAAhB,SAA2CoR,QAqRhCi+B,GAjR2B,SAAC,GAUpC,IAAD,IATJjuC,EASI,EATJA,SACAkuC,EAQI,EARJA,WACAC,EAOI,EAPJA,UACAC,EAMI,EANJA,gBACAn5B,EAKI,EALJA,OACA2O,EAII,EAJJA,SACAyqB,EAGI,EAHJA,UACA5uC,EAEI,EAFJA,eAEI,IADJqlC,sBACI,SACInwB,EAAgFu5B,EAAhFv5B,OAAQ9U,EAAwEquC,EAAxEruC,QAASyuC,EAA+DJ,EAA/DI,aAAc/oC,EAAiD2oC,EAAjD3oC,MAAOylB,EAA0CkjB,EAA1CljB,UAAWujB,EAA+BL,EAA/BK,SAAUC,EAAqBN,EAArBM,iBAD/D,EAE4CntC,mBAAQ,iBACtDmtC,QADsD,IACtDA,IADsD,UAClC5qB,EAASjP,cADyB,aAClC,EAAiByO,uBADiB,QACE,cAHtD,mBAEIqrB,EAFJ,KAEqBC,EAFrB,OAKgCrtC,mBAAoBwa,GAAoB4yB,IALxE,mBAKIv0B,EALJ,KAKey0B,EALf,OAMgDttC,mBAA4B,IAN5E,mBAMImgC,EANJ,KAMuBoN,EANvB,OAO8CvtC,qBAP9C,mBAOIogC,EAPJ,KAOsBoN,EAPtB,OAQsCxtC,mBAAuB,IAR7D,mBAQIytC,EARJ,KAQkBC,EARlB,KASElF,EAAgBn5B,aAAkBjR,GAClCqE,EAAcrC,kBAAO,GAErButC,EAAkB,SAACzB,GACvB,IAAMjqC,EAAQ2R,EAAM,kBAAcA,GAAW,GAE7C,OAAQs4B,EAAD,UAA2BA,GAA3B,OAAqCjqC,GAArC,UAAcA,IAEjB2rC,EAAmB3wB,mBAAQ,kBAAM+qB,GAAgB10B,KAAS,CAAEA,IAjB9D,EAkB8E2J,mBAChF,kBAAM0pB,GAAuBiH,KAC7B,CAAEA,IAFInL,EAlBJ,EAkBIA,GAAIuE,GAlBR,EAkBQA,SAAUG,GAlBlB,EAkBkBA,UAAWC,GAlB7B,EAkB6BA,UAAWC,GAlBxC,EAkBwCA,OAAQM,GAlBhD,EAkBgDA,aAAcI,GAlB9D,EAkB8DA,YAI5D8F,GAAerjC,aAAOm9B,IAEtB3H,GAAoB,SAACuD,GACzBriB,QAAc7gB,EACdktC,EAAqBhK,IAEjBuK,GAAyB,SAACx4B,GAAD,OAAqD,SAAC1T,GACnF,IAAMmsC,EAAc,UAAMz4B,EAAN,YAAc1T,GAE9Bsf,KAAgB6sB,GAClBR,EAAqB,IACrBC,OAAoBntC,GACpB6gB,QAAc7gB,IAEdktC,EAAsBK,EAA6C90B,OAAOk1B,aAAO14B,EAAM1T,KACvF4rC,EAAoB5rC,GACpBsf,GAAc6sB,KAIlB1vC,qBAAU,kBAAM0uC,IAAiB,IACjC1uC,qBAAU,WACRyuC,EAAU,CAAEj0B,YAAWC,OAAQ20B,GAAgBhrC,EAAYlC,SAC3DkC,EAAYlC,SAAU,IACrB,CAAEsY,EAAW40B,IAChBpvC,qBAAU,WACR8uC,GAAoBE,EAAmBF,KACtC,CAAEA,IA4JL,OACE,qCACGxuC,EAED,yBAASpB,UAAU,OAAnB,SACE,sBAAKA,UAAU,0BAAf,UACE,qBAAKA,UAAU,oBAAf,SACE,sBAAKA,UAAU,YAAf,UACE,qBAAKA,UAAU,YAAf,SACE,cAAC,GAAD,CACE+e,WAAS,EACTvF,SAAUvY,EACV4d,iBAAkBgxB,EAClB/wB,YAAY,aACZF,cAAemxB,MAGnB,cAAC,GAAD,CACE/vC,UAAU,4BACVkmC,eAAgBA,EAChB+E,cAAeA,EACfxtB,SAAUyyB,EACV/3B,SAAUg4B,SAIfp6B,EAAO/T,OAAS,GACf,qBAAKhC,UAAU,iCAAf,SACE,sBAAKA,UAAU,SAAf,UACE,eAACmxB,GAAA,EAAD,CACEpqB,SAAO,EACPyS,SAAuC,IAA7BopB,EAAkB5gC,OAC5BhC,UAAU,oBACVgH,QAAS,kBAAMy7B,GAAkB,KAJnC,6BAMmBG,EAAkB5gC,OAAS,GAAK,yCAAIyjB,GAASmd,EAAkB5gC,QAA/B,UAEnD,eAACmvB,GAAA,EAAD,CACEpqB,SAAO,EACPjH,MAAM,UACNE,UAAU,eACVgH,QAAS,kBAAMyoC,EAAUY,IAJ3B,UAME,cAAC,IAAD,CAAiB1uC,KAAM+uC,MANzB,YAMqDjrB,GAAS4qB,EAAiBruC,QAN/E,iBAcV,yBAAShC,UAAU,OAAnB,SA5ME0vC,EAEA,eAACp8B,GAAA,EAAD,CAASrS,SAAO,EAAhB,gDAEE,cAAC0vC,GAAA,EAAD,CAAUtsC,MAAOsrC,EAAUiB,QAAsB,MAAbjB,EAAkB3vC,UAAU,YAKlEiB,EACK,cAACqS,GAAA,EAAD,CAASrS,SAAO,IAGrB0F,EAEA,cAAC,GAAD,CAAQwM,KAAK,QAAb,SACE,cAAC,GAAD,CAAgBiZ,UAAWA,EAAWC,gBAAgB,gDAKxDlf,YAAQ4I,GACH,cAACzC,GAAA,EAAD,8DAIP,qCACE,cAAC/F,GAAA,EAAD,CAAMvN,UAAU,wCAAwCwT,MAAI,EAA5D,SACE,cAAC7G,GAAA,EAAD,CAAKkkC,OAAK,EAACzwC,MAAI,EAAf,SACGgc,OAAOwoB,QAAQ6J,IAAUtsC,KAAI,mCAAG2uC,EAAH,KAAYrwC,EAAZ,YAC5B,cAAC,GAAD,2BAAiCA,GAAjC,IAAwCU,GAAIivC,EAAgB3vC,EAAMkuC,WAA9CmC,UAG1B,cAACtjC,GAAA,EAAD,UACE,eAAC,KAAD,WACE,cAAC,KAAD,CACExF,KAAMymC,GAASC,OAAOC,QACtBx/B,QACE,qBAAKnP,UAAU,cAAf,SACE,cAAC,GAAD,CACEoR,MAAM,qBACN2E,OAAQs6B,EACRzN,kBAAmBA,EACnBC,iBAAkBA,EAClBJ,kBAAmBA,SAM3B,cAAC,KAAD,CACEz6B,KAAMymC,GAASI,UAAUF,QACzBx/B,QACE,qCACE,qBAAKnP,UAAWkC,IAAW,gBAAiB,CAAE,YAAagkC,IAA3D,SACE,cAAC,GAAD,CAAmB90B,MAAM,oBAAoBwF,MAAOsuB,MAEtD,qBAAKllC,UAAWkC,IAAW,gBAAiB,CAAE,YAAagkC,IAA3D,SACE,cAAC,GAAD,CAAmB90B,MAAM,WAAWwF,MAAO6yB,OAE7C,qBAAKzpC,UAAWkC,IAAW,OAAQ,CAAE,YAAagkC,EAAgB,WAAYA,IAA9E,SACE,cAAC,GAAD,CACE90B,MAAM,YACNwF,MAAOgzB,GACP8D,gBAAgB,EAChBf,iBAAkBnE,GAAyB5F,EAAmB,WAC9DC,iBAAkBA,EAClB2K,aAAc,CACZjsC,KAAM,gBACNwvC,OAAQ,iBAEV/pC,QAASupC,GAAuB,eAGnCrK,GACC,qBAAKlmC,UAAU,gBAAf,SACE,cAAC,GAAD,CACEoR,MAAM,eACNwF,MAAO4zB,GACP3H,iBAAkBA,EAClB8J,iBAAkBnE,GAAyB5F,EAAmB,cAC9D4K,aAAc,CACZlI,WAAY,cACZyL,OAAQ,iBAEV/pC,QAASupC,GAAuB,uBAQ5C,cAAC,KAAD,CACEvoC,KAAMymC,GAASM,WAAWJ,QAC1Bx/B,QACE,qCACE,qBAAKnP,UAAU,gBAAf,SACE,cAAC,GAAD,CACEoR,MAAM,YACNwF,MAAOizB,GACP8C,iBAAkBnE,GAAyB5F,EAAmB,WAC9DC,iBAAkBA,EAClB2K,aAAc,CACZjsC,KAAM,eACNwvC,OAAQ,iBAEV/pC,QAASupC,GAAuB,eAGpC,qBAAKvwC,UAAU,gBAAf,SACE,cAAC,GAAD,CACEoR,MAAM,SACNwF,MAAOkzB,GACP6C,iBAAkBnE,GAAyB5F,EAAmB,QAC9DC,iBAAkBA,EAClB4K,mBAAoB,SAACnG,GAAD,OAClBgJ,GAAatuC,OAAS,GACtB,cAAC,GAAD,CAAiBqlC,WAAW,SAASnJ,UAAWoS,GAAchJ,aAAcA,KAE9EkG,aAAc,CACZjsC,KAAM,YACNwvC,OAAQ,iBAEV/pC,QAASupC,GAAuB,iBAO1C,cAAC,KAAD,CACEvoC,KAAMymC,GAASt6B,KAAKw6B,QACpBx/B,QACE,qBAAKnP,UAAU,SAAf,SACE,cAAC,GAAD,CACE+V,OAAQs6B,EACRrK,eAAgBpD,EAChBH,kBAAmBA,GACnByD,eAAgBA,EAChBrlC,eAAgBA,QAMxB,cAAC,KAAD,CAAOmH,KAAK,IAAImH,QAAS,cAAC,KAAD,CAAUC,SAAO,EAACjO,GAAIivC,EAAgB3B,GAASC,OAAOC,2BmFvN5E5gC,GAvCQ,SAAC,GAAD,IAAGijC,EAAH,EAAGA,aAAH,OAAsC5vB,IAAkB,YAQnD,IAP1BsC,EAOyB,EAPzBA,eACAwQ,EAMyB,EANzBA,eACAre,EAKyB,EALzBA,kBACAse,EAIyB,EAJzBA,kBACA8c,EAGyB,EAHzBA,wBACAjsB,EAEyB,EAFzBA,SACAnkB,EACyB,EADzBA,eACyB,EACEF,eAAnBmV,iBADiB,MACL,GADK,EAEjBlR,EAAW6B,eAAX7B,OACFyvB,EAASlvB,cACPkR,EAAW1R,YAAgCC,GAA3CyR,OAYR,OAJAvV,qBAAU,WACRqzB,EAAkBre,EAAWO,KAC5B,IAGD,cAAC,GAAD,CACEk5B,UAbe,SAAC7uC,EAAsBwwC,GAAvB,OACjBr7B,EAAkBC,EAAD,YAAC,eAAgB4yB,GAAYhoC,IAA7B,IAAsC2V,WAAU66B,IAa/D1B,gBAAiByB,EACjB3B,WAAY5rB,EACZrN,OAAQA,EACR2O,SAAUA,EACVyqB,UAhBc,SAAC15B,GAAD,aAA+Bi7B,EAAa,aAAD,iBAC9C9c,EAAerL,gBAD+B,aAC9C,EAAyBA,SAASzZ,QAAQ,eAAgB,IADZ,eAE3D2G,IAeElV,eAAgBA,EAPlB,SASE,cAAC,GAAD,CAAsBqzB,eAAgBA,EAAgBxQ,eAAgBA,EAAgB2Q,OAAQA,SAGjG,SAAC/F,EAAG5tB,GAAJ,MAAe,CAAE0iB,GAAOM,eAAehjB,EAAOoV,gBCpClCq7B,GAbS,SAAC,GAAiE,IAA/DC,EAA8D,EAA9DA,UAAW/c,EAAmD,EAAnDA,OAAQnb,EAA2C,EAA3CA,eACpCnD,EAAgBq7B,EAAhBr7B,OAAQtU,EAAQ2vC,EAAR3vC,IAEV09B,EACJ,uBAAMn/B,UAAU,mDAAhB,UACE,sBAAMA,UAAU,OAAhB,wBACA,cAAC,EAAD,CAAKgZ,KAAMvX,EAAKyX,eAAgBA,OAIpC,OAAO,cAAC,GAAD,CAAc9H,MAAO+tB,EAAkB9K,OAAQA,EAAQte,OAAQA,KCyBzD/H,GA3BG,SAACkL,EAAD,OAAmC83B,EAAnC,EAAmCA,aAAnC,OAAsE5vB,IAAkB,YAMnF,IALrBpL,EAKoB,EALpBA,aACAo7B,EAIoB,EAJpBA,UACAC,EAGoB,EAHpBA,mBACArsB,EAEoB,EAFpBA,SACAnkB,EACoB,EADpBA,eAEMwzB,EAASlvB,cADK,EAECxE,eAAbc,WAFY,MAEN,GAFM,EAOpB,OACE,cAAC,GAAD,CACE8tC,UANe,SAAC7uC,EAA4BwwC,GAA7B,OACjBl7B,EAAavU,EAAKinC,GAAYhoC,GAASwwC,IAMrC1B,gBAAiB6B,EACjB/B,WAAY8B,EACZpsB,SAAUA,EACVyqB,UARc,SAAC15B,GAAD,OAA+Bi7B,EAAa,OAAD,OAAQvvC,EAAR,eAA0BsU,IASnFlV,eAAgBA,EANlB,SAQE,cAAC,GAAD,CAAiBuwC,UAAWA,EAAW/c,OAAQA,EAAQnb,eAAgBA,SAG1E,iBAAM,CAAEkK,GAAOrN,YCpCLu7B,GAAqB,SAAC,GAAuD,IAArD7tB,EAAoD,EAApDA,aAAc4Q,EAAsC,EAAtCA,OACzCte,EAAW0N,EAAX1N,OAER,OAAO,cAAC,GAAD,CAAc3E,MAAM,gBAAgBijB,OAAQA,EAAQte,OAAQA,KCSxD9H,GAAe,SAAC,GAAD,IAAG+iC,EAAH,EAAGA,aAAH,OAAsC5vB,IAAkB,YAM1D,IALxBnL,EAKuB,EALvBA,gBACAwN,EAIuB,EAJvBA,aACA8tB,EAGuB,EAHvBA,sBACAvsB,EAEuB,EAFvBA,SACAnkB,EACuB,EADvBA,eAEMwzB,EAASlvB,cAKf,OACE,cAAC,GAAD,CACEoqC,UALe,SAAC7uC,EAAsBwwC,GAAvB,aACjBj7B,EAAgByyB,GAAYhoC,GAAb,UAAsBA,EAAO6a,cAA7B,aAAsB,EAAe2vB,iBAAkBgG,IAKpE1B,gBAAiB+B,EACjBjC,WAAY7rB,EACZuB,SAAUA,EACVyqB,UAVc,SAAC15B,GAAD,OAA+Bi7B,EAAa,oBAAqBj7B,IAW/ElV,eAAgBA,EAChBqlC,gBAAc,EAPhB,SASE,cAAC,GAAD,CAAoBziB,aAAcA,EAAc4Q,OAAQA,SAG3D,iBAAM,CAAEjR,GAAOK,kBCrCL+tB,GAAwB,SAAC,GAA6D,IAA3DC,EAA0D,EAA1DA,gBAAiBpd,EAAyC,EAAzCA,OAC/Cte,EAAW07B,EAAX17B,OAER,OAAO,cAAC,GAAD,CAAc3E,MAAM,oBAAoBijB,OAAQA,EAAQte,OAAQA,KCK5D7H,GAAkB,SAAC,GAAD,IAAG8iC,EAAH,EAAGA,aAAH,OAAsC5vB,IAAkB,YAM1D,IAL3BlL,EAK0B,EAL1BA,mBACAu7B,EAI0B,EAJ1BA,gBACAC,EAG0B,EAH1BA,yBACA1sB,EAE0B,EAF1BA,SACAnkB,EAC0B,EAD1BA,eAEMwzB,EAASlvB,cAKf,OACE,cAAC,GAAD,CACEoqC,UALe,SAAC7uC,EAAsBwwC,GAAvB,OACjBh7B,EAAmBwyB,GAAYhoC,GAASwwC,IAKtC1B,gBAAiBkC,EACjBpC,WAAYmC,EACZzsB,SAAUA,EACVyqB,UAVc,SAAC15B,GAAD,OAA+Bi7B,EAAa,wBAAyBj7B,IAWnFlV,eAAgBA,EANlB,SAQE,cAAC,GAAD,CAAuB4wC,gBAAiBA,EAAiBpd,OAAQA,SAGpE,iBAAM,CAAEjR,GAAOrN,Y,UCjCZ47B,GAAiB,IAIjBC,GAAa,SAAC,GAAD,SAAG9rB,aAAH,EAAgBc,YAC7BirB,GAAe,SAACjM,EAAe5iC,GAAhB,OAAsD,IAAVA,EAAgB4iC,GAapEkM,GAAmB,uCAAG,WACjCC,EACAC,EACAC,EACAC,EACAjkB,EACAkkB,GANiC,2BAAA59B,EAAA,6DAQjC0Z,EAAS,CAAE9a,KAAM++B,EAAUp3B,QAErBs3B,EAV2B,+BAAA79B,EAAA,MAUJ,WAAOyR,GAAP,SAAAzR,EAAA,+EAC3Bqa,QAAQ1S,IAAI8J,EAAM7jB,IAAN,uCAAU,WAAOqlB,GAAP,SAAAjT,EAAA,+EAAgBw9B,EAAavqB,EAAMmqB,IAAgBp8B,KAAKwC,YAAK,UAA7D,2CAAV,wDAAkFxC,KAAK88B,OADxE,2CAVI,sDAa3BC,EAb2B,+BAAA/9B,EAAA,MAaT,WAAOg+B,GAAP,6BAAAh+B,EAAA,yDAAgCrF,EAAhC,+BAAwC,GAC1DijC,IADkB,yCAEb,IAFa,uBAKHC,EAAqBG,EAAYrjC,IAL9B,UAKhB3H,EALgB,OAOtB0mB,EAAS,CAAE9a,KAAM++B,EAAUvC,SAAUA,SAAUkC,GAAaU,EAAYvwC,OAAQkN,EApCrD,OAsCvBA,EAAQqjC,EAAYvwC,OAAS,GATX,6BAUbuF,EAVa,UAUK+qC,EAAgBC,EAAarjC,EAAQ,GAV1C,kDAURsjC,OAVQ,kDAafjrC,GAbe,4CAbS,sDA6B3BkrC,EA7B2B,+BAAAl+B,EAAA,MA6Bd,kDAAAA,EAAA,6DAAOiT,EAAP,+BAAc,EAAd,SACkBuqB,EAAavqB,EAAMmqB,IADrC,mBACThqB,EADS,EACTA,WAAYpgB,EADH,EACGA,KAGfogB,IAAciqB,GAAWjqB,GAJb,yCAKRpgB,GALQ,cASXmrC,EAAajiC,aAtDQ,EAsDsBkX,EAAWf,WAAa,GACnE2rB,EAAczM,aAxDQ,EAwD4B4M,GAEpD/qB,EAAWf,WAAa,EA1DA,GA2D1BqH,EAAS,CAAE9a,KAAM++B,EAAU95B,QAbZ,KAgBV7Q,EAhBU,UAgBQ+qC,EAAgBC,GAhBxB,kDAgBLC,OAhBK,6DA7Bc,uEAiDK5jB,QAAQ1S,IAAI,CAAEu2B,IAAcT,MAjDjC,mCAiDvBj8B,EAjDuB,KAiDfoZ,EAjDe,KAmD/BlB,GACGlY,EAAO/T,QAAUmtB,EACd,CAAEhc,KAAM++B,EAAUS,mBAAoB/C,iBAAkBzyB,GAAuBgS,EAAUhV,OAD7F,2BAES83B,GAFT,IAEgCl8B,SAAQ5C,KAAM++B,EAAUU,UAtD3B,kDAyD/B3kB,EAAyB,CAAE9a,KAAM++B,EAAUvrC,MAAOylB,UAAWJ,GAAc,EAAD,MAzD3C,0DAAH,gEA6DnB6mB,GAA2B,SACtC3B,EACA4B,GAEA,OAAK5B,EAIL,sBAAO,sBAAA38B,EAAA,+EAAYu+B,EAAO,CAAEtrB,KAAM,EAAG2T,aAAc,IAAK5lB,MAAK,SAAC8X,GAAD,OAAYA,EAAO9lB,KAAK,OAA9E,2CAHL,sBAAO,sBAAAgN,EAAA,+EAAYqa,QAAQsO,aAAQp6B,IAA5B,4CC9EEiwC,GAA6B,mDAC7BC,GAA6B,mDAC7BC,GAAuB,6CACvBC,GAA6B,mDAC7BC,GAA8B,oDAC9BC,GAAwC,8DACxCC,GAA4C,kEAgBnDjvC,GAA+B,CACnC2R,OAAQ,GACRD,UAAW,GACXO,YAAQvT,EACR7B,SAAS,EACTyuC,cAAc,EACd/oC,OAAO,EACP2sC,YAAY,EACZ3D,SAAU,GAGG/rB,OAAY,qBACxBmvB,IAA6B,8BAAC,eAAW3uC,IAAZ,IAA0BnD,SAAS,OADxC,eAExB+xC,IAA6B,SAAC1kB,EAAD,OAAMlC,EAAN,EAAMA,UAAN,mBAAC,eAA2BhoB,IAA5B,IAA0CuC,OAAO,EAAMylB,iBAF5D,eAGxB6mB,IAAuB,SAACrsC,EAAD,OAAUmP,EAAV,EAAUA,OAAQrR,EAAlB,EAAkBA,MAAOoR,EAAzB,EAAyBA,UAAWO,EAApC,EAAoCA,OAApC,mBAAC,eACpBzP,GADmB,IAEtBmP,SACAD,YACAO,SACA3R,QACAzD,SAAS,EACT0F,OAAO,OAVgB,eAYxBusC,IAA6B,SAACtsC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB8oC,cAAc,OAZ3C,eAaxByD,IAA8B,SAACvsC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB0sC,YAAY,OAb1C,eAcxBF,IAAwC,SAACxsC,EAAD,OAAU+oC,EAAV,EAAUA,SAAV,mBAAC,eAA8B/oC,GAA/B,IAAsC+oC,gBAdtD,eAexB0D,IAA4C,SAACzsC,EAAD,OAAUgpC,EAAV,EAAUA,iBAAV,mBAAC,eAAsChpC,GAAvC,IAA8CgpC,wBAflE,eAgBxBjiB,IAAgB,SAAC/mB,EAAD,GAA+B,IAArBgnB,EAAoB,EAApBA,cACjB9X,EAA0ClP,EAA1CkP,UAAWO,EAA+BzP,EAA/ByP,OAAQN,EAAuBnP,EAAvBmP,OADkB,EACKnP,EAAflC,aADU,MACF,GADE,EAErC6X,EAAuB7X,EAAvB6X,UAAWC,EAAY9X,EAAZ8X,QACb+2B,EAAY3lB,EACfrS,QACC,gBAAGsN,EAAH,EAAGA,SAAU9F,EAAb,EAAaA,MAAb,OACE8F,GAAY6E,GAAgB7E,EAAU/S,EAAWO,IAAWwE,GAAUkI,EAAM5I,KAAMoC,EAAWC,MAEhGra,KAAI,qBAAG4gB,SAEV,OAA4B,IAArBwwB,EAAUvxC,OAAe4E,EAAzB,2BAAsCA,GAAtC,IAA6CmP,OAAO,GAAD,oBAAOw9B,GAAP,aAAqBx9B,SA1BxD,IA4BxB3R,IAEUyR,GAAoB,SAAC8B,GAAD,OAAkD,SACjF7B,GADiF,IAEjFpR,EAFiF,uDAErD,GAC5BwsC,EAHiF,sGAI9E,WAAOjjB,EAAoBpW,GAA3B,2BAAAtD,EAAA,+DAC2BoD,EAAqBE,GAA3ChC,EADL,EACKA,kBACFk8B,EAFH,+BAAAx9B,EAAA,MAEkB,WAAOiT,EAAc2T,GAArB,SAAA5mB,EAAA,+EAA8CsB,EACjEC,EADkF,YAAC,eAE9EpR,GAF6E,IAEtE8iB,OAAM2T,mBAFC,2CAFlB,wDAMG6W,EAAkBa,GACtB3B,EAD8C,uCAE9C,WAAOxwC,GAAP,SAAA6T,EAAA,+EAAkBsB,EAAkBC,EAAD,YAAC,eAAgBpV,GAAjB,IAAyB2V,OAAQ3R,EAAM2R,WAA1E,2CAF8C,uDAI1C87B,EAAe,kBAAMt6B,IAAW6L,eAAe4vB,YAC/CrB,EAAuD,CAAEn8B,YAAWpR,QAAO2R,OAAQ3R,EAAM2R,QACzF67B,EAAY,CAChBp3B,MAAOi4B,GACP36B,MAAO86B,GACPN,OAAQK,GACRtsC,MAAOqsC,GACPrD,SAAUyD,GACVT,mBAAoBU,IAlBnB,kBAqBIvB,GAAoBC,EAAcC,EAAiBC,EAAuBC,EAAWjkB,EAAUkkB,IArBnG,2CAJ8E,0DA4BtElB,GAA0BjtB,GAAmBmvB,IC7F7CK,GAAuB,wCACvBC,GAAuB,wCACvBC,GAAiB,kCACjBC,GAAuB,wCACvBC,GAAwB,yCACxBC,GAAkC,mDAClCC,GAAsC,uDAmB7C1vC,GAA0B,CAC9B2R,OAAQ,GACRtU,IAAK,GACLR,SAAS,EACTyuC,cAAc,EACd/oC,OAAO,EACP2sC,YAAY,EACZ3D,SAAU,GAGG/rB,OAAY,qBACxB4vB,IAAuB,8BAAC,eAAWpvC,IAAZ,IAA0BnD,SAAS,OADlC,eAExBwyC,IAAuB,SAACnlB,EAAD,OAAMlC,EAAN,EAAMA,UAAN,mBAAC,eAA2BhoB,IAA5B,IAA0CuC,OAAO,EAAMylB,iBAFtD,eAGxBsnB,IAAiB,SAAC9sC,EAAD,OAAUmP,EAAV,EAAUA,OAAQtU,EAAlB,EAAkBA,IAAKiD,EAAvB,EAAuBA,MAAvB,mBAAC,eAAwCkC,GAAzC,IAAgDmP,SAAQtU,MAAKiD,QAAOzD,SAAS,EAAO0F,OAAO,OAHpF,eAIxBgtC,IAAuB,SAAC/sC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB8oC,cAAc,OAJrC,eAKxBkE,IAAwB,SAAChtC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB0sC,YAAY,OALpC,eAMxBO,IAAkC,SAACjtC,EAAD,OAAU+oC,EAAV,EAAUA,SAAV,mBAAC,eAA8B/oC,GAA/B,IAAsC+oC,gBANhD,eAOxBmE,IAAsC,SAACltC,EAAD,OAAUgpC,EAAV,EAAUA,iBAAV,mBAAC,eAAsChpC,GAAvC,IAA8CgpC,wBAP5D,eAQxBjiB,IAAgB,SAAC/mB,EAAD,GAA+B,IAArBgnB,EAAoB,EAApBA,cACjBnsB,EAA4BmF,EAA5BnF,IAAKsU,EAAuBnP,EAAvBmP,OADgC,EACTnP,EAAflC,aADwB,MAChB,GADgB,EAErC6X,EAAuB7X,EAAvB6X,UAAWC,EAAY9X,EAAZ8X,QACb+2B,EAAY3lB,EACfrS,QAAO,gBAAGsN,EAAH,EAAGA,SAAU9F,EAAb,EAAaA,MAAb,OAAiC,OAAR8F,QAAQ,IAARA,OAAA,EAAAA,EAAUrS,KAAK+oB,SAAS99B,KAAQoZ,GAAUkI,EAAM5I,KAAMoC,EAAWC,MACjGra,KAAI,qBAAG4gB,SAEV,OAAO,2BAAKnc,GAAZ,IAAmBmP,OAAO,GAAD,oBAAOw9B,GAAP,aAAqBx9B,SAfvB,IAiBxB3R,IAEU4R,GAAe,SAAC2B,GAAD,OAAkD,SAC5ElW,GAD4E,IAE5EiD,EAF4E,uDAEhD,GAC5BwsC,EAH4E,sGAIzE,WAAOjjB,EAAoBpW,GAA3B,2BAAAtD,EAAA,+DACsBoD,EAAqBE,GAAtC7B,EADL,EACKA,aACF+7B,EAFH,+BAAAx9B,EAAA,MAEkB,WAAOiT,EAAc2T,GAArB,SAAA5mB,EAAA,+EAA8CyB,EACjEvU,EAD6E,YAAC,eAEzEiD,GAFwE,IAEjE8iB,OAAM2T,mBAFC,2CAFlB,wDAMG6W,EAAkBa,GAAyB3B,EAAD,uCAAqB,WAAOxwC,GAAP,SAAA6T,EAAA,+EAAkByB,EAAavU,EAAKf,IAApC,2CAArB,uDAC1CyxC,EAAe,kBAAMt6B,IAAWu5B,UAAUkC,YAC1CrB,EAAkD,CAAExwC,MAAKiD,SACzDwtC,EAAY,CAChBp3B,MAAO04B,GACPp7B,MAAOu7B,GACPf,OAAQc,GACR/sC,MAAO8sC,GACP9D,SAAUkE,GACVlB,mBAAoBmB,IAfnB,kBAkBIhC,GAAoBC,EAAcC,EAAiBC,EAAuBC,EAAWjkB,EAAUkkB,IAlBnG,2CAJyE,0DAyBjEd,GAAqBrtB,GAAmB4vB,ICvExCG,GAA0B,8CAC1BC,GAA0B,8CAC1BC,GAAoB,wCACpBC,GAA0B,8CAC1BC,GAA2B,+CAC3BC,GAAqC,yDACrCC,GAAyC,6DAchDjwC,GAA2B,CAC/B2R,OAAQ,GACR9U,SAAS,EACTyuC,cAAc,EACd/oC,OAAO,EACP2sC,YAAY,EACZ3D,SAAU,GAGG/rB,OAAY,qBACxBmwB,IAA0B,8BAAC,eAAW3vC,IAAZ,IAA0BnD,SAAS,OADrC,eAExB+yC,IAA0B,SAAC1lB,EAAD,OAAMlC,EAAN,EAAMA,UAAN,mBAAC,eAA2BhoB,IAA5B,IAA0CuC,OAAO,EAAMylB,iBAFzD,eAGxB6nB,IAAoB,SAACrtC,EAAD,OAAUmP,EAAV,EAAUA,OAAQrR,EAAlB,EAAkBA,MAAlB,mBAAC,eAAmCkC,GAApC,IAA2CmP,SAAQrR,QAAOzD,SAAS,EAAO0F,OAAO,OAH7E,eAIxButC,IAA0B,SAACttC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB8oC,cAAc,OAJxC,eAKxByE,IAA2B,SAACvtC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB0sC,YAAY,OALvC,eAMxBc,IAAqC,SAACxtC,EAAD,OAAU+oC,EAAV,EAAUA,SAAV,mBAAC,eAA8B/oC,GAA/B,IAAsC+oC,gBANnD,eAOxB0E,IAAyC,SAACztC,EAAD,OAAUgpC,EAAV,EAAUA,iBAAV,mBAAC,eAAsChpC,GAAvC,IAA8CgpC,wBAP/D,eAQxBjiB,IAAgB,SAAC/mB,EAAD,GAA+B,IAArBgnB,EAAoB,EAApBA,cACjB7X,EAAuBnP,EAAvBmP,OADqC,EACdnP,EAAflC,aAD6B,MACrB,GADqB,EAErC6X,EAAuB7X,EAAvB6X,UAAWC,EAAY9X,EAAZ8X,QACb+2B,EAAY3lB,EACfrS,QAAO,gBAAGwH,EAAH,EAAGA,MAAH,SAAU8F,UAA4BhO,GAAUkI,EAAM5I,KAAMoC,EAAWC,MAC9Era,KAAI,qBAAG4gB,SAEV,OAAO,2BAAKnc,GAAZ,IAAmBmP,OAAO,GAAD,oBAAOw9B,GAAP,aAAqBx9B,SAfvB,IAiBxB3R,IAEGkwC,GAAc,SAACvxB,EAAoBmoB,GAArB,OACjBA,GAAoBA,IAAqBnoB,EAAM5P,MAErC8C,GAAkB,SAAC0B,GAAD,OAAkD,eAC/EjT,EAD+E,uDACnD,GAC5BwmC,EAF+E,uCAG/EgG,EAH+E,sGAI5E,WAAOjjB,EAAoBpW,GAA3B,2BAAAtD,EAAA,+DACyBoD,EAAqBE,GAAzC5B,EADL,EACKA,gBACF87B,EAFH,+BAAAx9B,EAAA,MAEkB,WAAOiT,EAAc2T,GAArB,SAAA5mB,EAAA,+EAA8C0B,EAAgB,2BAAKvR,GAAN,IAAa8iB,OAAM2T,kBAClG5lB,MAAK,SAAC8X,GACL,IAAMtX,EAASsX,EAAO9lB,KAAKgU,QAAO,SAACwH,GAAD,OAAWolB,GAAcplB,IAAUuxB,GAAYvxB,EAAOmoB,MAExF,OAAO,2BAAK7d,GAAZ,IAAoB9lB,KAAMwO,QAJT,2CAFlB,wDAQGi8B,EAAkBa,GAAyB3B,EAAoBj7B,GAC/Dk8B,EAAe,kBAAMt6B,IAAW4L,aAAa6vB,YAC7CrB,EAAqD,CAAEvtC,SACvDwtC,EAAY,CAChBp3B,MAAOi5B,GACP37B,MAAO87B,GACPtB,OAAQqB,GACRttC,MAAOqtC,GACPrE,SAAUyE,GACVzB,mBAAoB0B,IAjBnB,kBAoBIvC,GAAoBC,EAAcC,EAAiBC,EAAuBC,EAAWjkB,EAAUkkB,IApBnG,2CAJ4E,0DA2BpEZ,GAAwBvtB,GAAmBmwB,ICjF3CI,GAA8B,kDAC9BC,GAA8B,kDAC9BC,GAAwB,4CACxBC,GAA8B,kDAC9BC,GAA+B,mDAC/BC,GAAyC,6DACzCC,GAA6C,iEAcpDzwC,GAA2B,CAC/B2R,OAAQ,GACR9U,SAAS,EACTyuC,cAAc,EACd/oC,OAAO,EACP2sC,YAAY,EACZ3D,SAAU,GAGG/rB,OAAY,qBACxB2wB,IAA8B,8BAAC,eAAWnwC,IAAZ,IAA0BnD,SAAS,OADzC,eAExBuzC,IAA8B,SAAClmB,EAAD,OAAMlC,EAAN,EAAMA,UAAN,mBAAC,eAA2BhoB,IAA5B,IAA0CuC,OAAO,EAAMylB,iBAF7D,eAGxBqoB,IAAwB,SAAC7tC,EAAD,OAAUmP,EAAV,EAAUA,OAAQrR,EAAlB,EAAkBA,MAAlB,mBAAC,eAAmCkC,GAApC,IAA2CmP,SAAQrR,QAAOzD,SAAS,EAAO0F,OAAO,OAHjF,eAIxB+tC,IAA8B,SAAC9tC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB8oC,cAAc,OAJ5C,eAKxBiF,IAA+B,SAAC/tC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB0sC,YAAY,OAL3C,eAMxBsB,IAAyC,SAAChuC,EAAD,OAAU+oC,EAAV,EAAUA,SAAV,mBAAC,eAA8B/oC,GAA/B,IAAsC+oC,gBANvD,eAOxBkF,IAA6C,SAACjuC,EAAD,OAAUgpC,EAAV,EAAUA,iBAAV,mBAAC,eAAsChpC,GAAvC,IAA8CgpC,wBAPnE,eAQxBjiB,IAAgB,SAAC/mB,EAAD,GAA+B,IAArBgnB,EAAoB,EAApBA,cACjB7X,EAAuBnP,EAAvBmP,OADqC,EACdnP,EAAflC,aAD6B,MACrB,GADqB,EAErC6X,EAAuB7X,EAAvB6X,UAAWC,EAAY9X,EAAZ8X,QACb+2B,EAAY3lB,EACfrS,QAAO,gBAAGwH,EAAH,EAAGA,MAAH,OAAelI,GAAUkI,EAAM5I,KAAMoC,EAAWC,MACvDra,KAAI,qBAAG4gB,SAEV,OAAO,2BAAKnc,GAAZ,IAAmBmP,OAAO,GAAD,oBAAOw9B,GAAP,aAAqBx9B,SAfvB,IAiBxB3R,IAEU8R,GAAqB,SAACyB,GAAD,OAAkD,eAClFjT,EADkF,uDACtD,GAC5BwsC,EAFkF,sGAG/E,WAAOjjB,EAAoBpW,GAA3B,2BAAAtD,EAAA,+DAC4BoD,EAAqBE,GAA5C3B,EADL,EACKA,mBACF67B,EAFH,+BAAAx9B,EAAA,MAEkB,WAAOiT,EAAc2T,GAArB,SAAA5mB,EAAA,+EACnB2B,EAAmB,2BAAKxR,GAAN,IAAa8iB,OAAM2T,mBADlB,2CAFlB,wDAIG6W,EAAkBa,GAAyB3B,EAAoBh7B,GAC/Di8B,EAAe,kBAAMt6B,IAAW4L,aAAa6vB,YAC7CrB,EAAwD,CAAEvtC,SAC1DwtC,EAAY,CAChBp3B,MAAOy5B,GACPn8B,MAAOs8B,GACP9B,OAAQ6B,GACR9tC,MAAO6tC,GACP7E,SAAUiF,GACVjC,mBAAoBkC,IAbnB,kBAgBI/C,GAAoBC,EAAcC,EAAiBC,EAAuBC,EAAWjkB,EAAUkkB,IAhBnG,2CAH+E,0DAsBvET,GAA2B1tB,GAAmB2wB,IC9E9CG,GAAqB,2CACrBC,GAAqB,2CACrBC,GAAe,qCAYtB5wC,GAA+B,CACnC2kB,YAAa,EACbiS,kBAAmB,EACnB/5B,SAAS,EACT0F,OAAO,GAGMid,OAAY,qBACxBkxB,IAAqB,8BAAC,eAAW1wC,IAAZ,IAA0BnD,SAAS,OADhC,eAExB8zC,IAAqB,8BAAC,eAAW3wC,IAAZ,IAA0BuC,OAAO,OAF9B,eAGxBquC,IAAe,SAAC1mB,EAAD,OAAMvF,EAAN,EAAMA,YAAaiS,EAAnB,EAAmBA,kBAAnB,mBAAC,eAAgD52B,IAAjD,IAA+D2kB,cAAaiS,yBAHnE,eAIxBrN,IAAgB,cAAyE,IAAtE5E,EAAqE,EAArEA,YAAqE,IAAxDiS,yBAAwD,MAApC,EAAoC,EAA9B1rB,EAA8B,mDAApBse,EAAoB,EAApBA,cAAoB,EAC/Cwa,GAAqBxa,GAArD2a,EAD+E,EAC/EA,cAAe9kB,EADgE,EAChEA,aAEvB,OAAO,2BACFnU,GADL,IAEEyZ,YAAaA,EAAcwf,EAAcvmC,OACzCg5B,kBAAmBA,EAAoBvX,EAAazhB,YAV/B,IAaxBoC,IAEUw2B,GAAqB,SAACjjB,GAAD,OAAkD,yDAAM,WACxFsW,EACApW,GAFwF,mBAAAtD,EAAA,6DAIxF0Z,EAAS,CAAE9a,KAAM2hC,KAJuE,WAOxDn9B,EAAqBE,GAA3C1B,EAP8E,EAO9EA,kBAP8E,SAQjEA,IARiE,OAQhFkX,EARgF,OAUtFY,EAAS,aAAE9a,KAAM6hC,IAAiB3nB,IAVoD,gDAYtFY,EAAS,CAAE9a,KAAM4hC,KAZqE,yDAAN,0DCzCvEE,GACX,WACmB1wC,EACAk5B,GAChB,IAAD,gCAFiBl5B,SAEjB,KADiBk5B,UACjB,KAEcuT,aAAe,SAAC5pC,EAAkB2O,GAChD,GAAKA,EAAO/T,OAAZ,CAIA,IAAM07B,EAAM,EAAKD,QAAQE,MAAM5nB,EAAQ,CAAEyB,QAAS,QAElDomB,aAAQ,EAAKr5B,OAAQm5B,EAAKt2B,MCgDf9B,GAjDS,SAACC,EAAgBC,GAEvCD,EAAOQ,eAAe,YAAY,kBAAMw4B,MAExCh5B,EAAOQ,eAAe,iBAAkBgI,GAAgB,kBACxDxI,EAAOY,UAAU,iBAAkBX,EACjC,CAAE,iBAAkB,iBAAkB,cAAe,WAAY,kBACjE,CAAE,oBAAqB,oBAAqB,0BAA2B,kBAAmB,qBAG5FD,EAAOQ,eAAe,YAAaiI,GAAW,iBAAkB,kBAChEzI,EAAOY,UAAU,YAAaX,EAC5B,CAAE,YAAa,cAAe,WAAY,kBAC1C,CAAE,eAAgB,qBAAsB,kBAAmB,qBAG7DD,EAAOQ,eAAe,eAAgBkI,GAAc,kBACpD1I,EAAOY,UAAU,eAAgBX,EAC/B,CAAE,eAAgB,cAAe,WAAY,kBAC7C,CAAE,kBAAmB,wBAAyB,kBAAmB,qBAGnED,EAAOQ,eAAe,kBAAmBmI,GAAiB,kBAC1D3I,EAAOY,UAAU,kBAAmBX,EAClC,CAAE,kBAAmB,cAAe,WAAY,kBAChD,CAAE,qBAAsB,2BAA4B,kBAAmB,qBAIzED,EAAOQ,eAAe,gBAAgB,kBAAMmvC,KAC5C3vC,EAAOM,QAAQ,iBAAkBovC,GAAgB,SAAU,WAG3D1vC,EAAOQ,eAAe,oBAAqB8P,GAAmB,wBAC9DtQ,EAAOQ,eAAe,2BAA2B,kBAAMkrC,MAEvD1rC,EAAOQ,eAAe,eAAgBiQ,GAAc,wBACpDzQ,EAAOQ,eAAe,sBAAsB,kBAAMsrC,MAElD9rC,EAAOQ,eAAe,kBAAmBkQ,GAAiB,wBAC1D1Q,EAAOQ,eAAe,yBAAyB,kBAAMwrC,MAErDhsC,EAAOQ,eAAe,qBAAsBmQ,GAAoB,wBAChE3Q,EAAOQ,eAAe,4BAA4B,kBAAM2rC,MAExDnsC,EAAOQ,eAAe,mBAAmB,kBAAMyb,MAC/Cjc,EAAOQ,eAAe,qBAAsB60B,GAAoB,yB,qBC/CnDua,GAPG,SAAC,GAAD,IAAG1zC,EAAH,EAAGA,IAAKyX,EAAR,EAAQA,eAAR,OAChB,qBACEE,MAAO,CAAEC,gBAAiBH,EAAezP,eAAehI,IACxDzB,UAAU,gBCSRo1C,GAAiB,SAAC3zC,GAAD,MAAkB,CAAEH,GAAIG,EAAKF,KAAME,IAkD3CgxB,GAhDM,SAACvZ,GAAD,OAAoC,YAEnD,IAAD,IADDiH,EACC,EADDA,aAAchI,EACb,EADaA,SAAUQ,EACvB,EADuBA,YAAajC,EACpC,EADoCA,SAAU8J,EAC9C,EAD8CA,SAAUwE,EACxD,EADwDA,SAE3DlkB,qBAAU,WACR4V,MACC,IAEH,IAAM2+B,EAAU,oBAAGrwB,EAASX,wBAAZ,aAAG,EAA2BixB,wBAA9B,QAAkD,aAUlE,OACE,cAAC,KAAD,CACE9+B,KAAM2J,EAAahe,IAAIizC,IACvBG,aAZiB,SAAC,GAAD,IAAG9zC,EAAH,EAAGA,IAAK+zC,EAAR,EAAQA,SAAR,OACnB,cAAC,EAAD,CAAKt8B,eAAgBA,EAAgBF,KAAMvX,EAAIF,KAAM0X,WAAS,EAACjZ,UAAU,kBAAkBmZ,QAASq8B,KAYlGC,YAAaj1B,EAAShK,KAAK+E,QAAO,SAAC9Z,GAAD,OAAU0e,EAAaof,SAAS99B,MAAMU,IAAIizC,IAC5EM,oBAZwB,SAAC,GAAD,IAAGxtC,EAAH,EAAGA,KAAH,OAC1B,qCACE,cAAC,GAAD,CAAWzG,IAAG,UAAKyG,EAAK3G,MAAQ2X,eAAgBA,IAC/ChR,EAAK3G,SAUNo0C,UAAQ,EACRC,WAAS,EACTz3B,gBAAe,OAAExF,QAAF,IAAEA,IAAe,sBAChCk9B,eAAgB,EAChBC,WAAY,CAAE,QAAS,MAAO,KAC9BC,qBACiB,aAAfV,EACI,SAAC3wC,EAAO+wC,GAAR,OAAwBA,EAAYl6B,QAAO,qBAAGha,KAAgBg+B,SAAS76B,YACvE5B,EAEN0yC,SAAU,SAACQ,GACT,IAAMC,EAAQ,aAAQ91B,GAEtB81B,EAASC,OAAOF,EAAiB,GACjC79B,EAAS89B,IAEXE,WAAY,gBAASruB,EAAT,EAAGvmB,KAAH,OAAsB4W,EAAQ,aAGnC,IAAIoJ,IAAJ,uBAAapB,GAAb,aAA8B2H,EAAO9e,cAAc6L,MAAM,e,UCqBvDuhC,GA/DC,SACdC,EACAC,EACAp9B,GAHc,OAIX,YAA+D,IAA5DzX,EAA2D,EAA3DA,IAAKZ,EAAsD,EAAtDA,eAAgB01C,EAAsC,EAAtCA,UAAW38B,EAA2B,EAA3BA,OAA2B,EACrB3W,cADqB,mBACzDsnB,EADyD,KACtCC,EADsC,OAEzBvnB,cAFyB,mBAEzDuzC,EAFyD,KAExCC,EAFwC,OAG7BxzC,cAH6B,mBAGzDyzC,EAHyD,KAG9CC,EAH8C,KAI3DC,EAAW/zC,mBACX9B,EAAW8J,YAAYhK,GAQ7B,OANAC,qBAAU,WAbQ,IAACuoB,KAcDutB,EAAS5zC,UAdyCqmB,EAAGwtB,YAAcxtB,EAAGytB,aAepFH,MAED,CAAEC,EAAS5zC,UAGZ,eAACuK,GAAA,EAAD,CAAMvN,UAAU,WAAhB,UACE,eAACo7B,GAAA,EAAD,CAAYp7B,UAAU,mBAAtB,UACE,cAACmxB,GAAA,EAAD,CAAQrxB,MAAM,OAAOwQ,KAAK,KAAKtQ,UAAU,oCAAoCgH,QAASwjB,EAAtF,SACE,cAAC,IAAD,CAAiB7oB,KAAMgpB,QAEzB,cAACwG,GAAA,EAAD,CAAQrxB,MAAM,OAAOwQ,KAAK,KAAKtQ,UAAU,gBAAgBgH,QAASyvC,EAAlE,SACE,cAAC,IAAD,CAAiB90C,KAAMyO,QAEzB,qBACEpQ,UAAU,oCACVoR,MAAOslC,EAAWj1C,EAAIA,SAAMqB,EAC5B6a,IAAK,SAAC0L,GACJutB,EAAS5zC,QAAT,OAAmBqmB,QAAnB,IAAmBA,SAAMvmB,GAJ7B,UAOE,cAAC,GAAD,CAAWrB,IAAKA,EAAIA,IAAKyX,eAAgBA,IACzC,sBAAMlZ,UAAU,qBAAqBgH,QAAS4S,EAA9C,SAAuDnY,EAAIA,YAI/D,cAACgL,GAAA,EAAD,CAAUZ,OAAQ0qC,EAAlB,SACE,eAAClb,GAAA,EAAD,CAAUr7B,UAAU,iBAApB,UACE,eAAC,IAAD,CACEmB,GAAE,kBAAaJ,EAAb,mCAAgDu6B,mBAAmB75B,EAAIA,MACzEzB,UAAU,6FAFZ,UAIE,uBAAMA,UAAU,gBAAhB,UAAgC,cAAC,IAAD,CAAiB2B,KAAMo1C,IAAQ/2C,UAAU,SAAzE,gBACA,4BAAIylB,GAAShkB,EAAI+T,gBAEnB,eAAC,IAAD,CACErU,GAAE,kBAAaJ,EAAb,gBAA6BU,EAAIA,IAAjC,WACFzB,UAAU,wFAFZ,UAIE,uBAAMA,UAAU,gBAAhB,UAAgC,cAAC,IAAD,CAAiB2B,KAAMq1C,IAAOh3C,UAAU,SAAxE,YACA,4BAAIylB,GAAShkB,EAAIsU,kBAKvB,cAACsgC,EAAD,CAAuB50C,IAAKA,EAAIA,IAAKmY,OAAQ4Q,EAAc3e,OAAQ0e,IACnE,cAAC+rB,EAAD,CAAc70C,IAAKA,EAAIA,IAAKmY,OAAQ68B,EAAY5qC,OAAQ2qC,SCnC/CH,GAjCe,SAAC,GAEzB,IADF50C,EACC,EADDA,IAAKmY,EACJ,EADIA,OAAQ/N,EACZ,EADYA,OAAQorC,EACpB,EADoBA,UAAWC,EAC/B,EAD+BA,UAAWC,EAC1C,EAD0CA,WAErCC,EAA+BF,EAA/BE,SAAUzwC,EAAqBuwC,EAArBvwC,MAAOylB,EAAc8qB,EAAd9qB,UACnBirB,EAAQ,uCAAG,sBAAA9iC,EAAA,sEACT0iC,EAAUx1C,GADD,OAEf01C,EAAW11C,GACXmY,IAHe,2CAAH,qDAMd,OACE,eAACmT,GAAA,EAAD,CAAOnT,OAAQA,EAAQ/N,OAAQA,EAAQmhB,UAAQ,EAA/C,UACE,cAACE,GAAA,EAAD,CAAatT,OAAQA,EAArB,SACE,sBAAM5Z,UAAU,cAAhB,0BAEF,eAACmtB,GAAA,EAAD,kDACsC,4BAAI1rB,IAD1C,IAEGkF,GACC,cAAC,GAAD,CAAQwM,KAAK,QAAQ4Y,OAAK,EAAC/rB,UAAU,OAArC,SACE,cAAC,GAAD,CAAgBosB,UAAWA,EAAWC,gBAAgB,wDAI5D,eAACe,GAAA,EAAD,WACE,wBAAQptB,UAAU,eAAegH,QAAS4S,EAA1C,oBACA,wBAAQ5Z,UAAU,iBAAiBwZ,SAAU49B,EAAUpwC,QAASqwC,EAAhE,SACGD,EAAW,kBAAoB,sB,oBCoC3Bd,GAtDM,SAAC,GAAD,IAAG7sC,EAAH,EAAGA,eAAH,OAAwC,YAEvD,IADFhI,EACC,EADDA,IAAKqV,EACJ,EADIA,QAAS8C,EACb,EADaA,OAAQ09B,EACrB,EADqBA,UAAWzrC,EAChC,EADgCA,OAAQ0rC,EACxC,EADwCA,QACxC,EACmC90C,mBAAShB,GAD5C,mBACK+1C,EADL,KACiBC,EADjB,OAEyBh1C,mBAASgH,EAAehI,IAFjD,mBAEK3B,EAFL,KAEY43C,EAFZ,OAG+Dz0C,cAH/D,mBAGK00C,EAHL,KAGsBC,EAHtB,KAG2CC,EAH3C,KAIKC,EAA8BP,EAA9BO,QAASnxC,EAAqB4wC,EAArB5wC,MAAOylB,EAAcmrB,EAAdnrB,UAClB2rB,EAAUpnC,aAA4B,sBAC1C,sBAAA4D,EAAA,+EAAYuC,EAAQrV,EAAK+1C,EAAY13C,GAClCyV,MAAK,kBAAM+hC,EAAU71C,EAAK+1C,EAAY13C,MACtCyV,KAAKqE,GACLiT,OAAM,gBAHT,4CAMF,OACE,cAACE,GAAA,EAAD,CAAOlhB,OAAQA,EAAQ+N,OAAQA,EAAQoT,UAAQ,EAACgrB,SAAUH,EAA1D,SACE,uBAAM5qB,SAAU8qB,EAAhB,UACE,cAAC7qB,GAAA,EAAD,CAAatT,OAAQA,EAArB,sBACA,eAACuT,GAAA,EAAD,WACE,sBAAKntB,UAAU,cAAf,UACE,qBAAKA,UAAU,sBAAsBsB,GAAG,iBAAiB0F,QAAS4wC,EAAlE,SACE,qBACE53C,UAAU,uDACVoZ,MAAO,CAAEC,gBAAiBvZ,EAAOuiC,YAAaviC,GAFhD,SAIE,cAAC,IAAD,CAAiB6B,KAAMs2C,IAAWj4C,UAAU,mCAGhD,cAACk4C,GAAA,EAAD,CAASrsC,OAAQ8rC,EAAiB/9B,OAAQg+B,EAAmBh/B,OAAO,iBAAiB4Q,UAAU,QAA/F,SACE,cAAC,KAAD,CAAc1pB,MAAOA,EAAOq4C,cAAY,EAAChgC,SAAU,gBAAG/N,EAAH,EAAGA,IAAH,OAAastC,EAASttC,QAE3E,cAACkpB,GAAA,EAAD,CACEjvB,MAAOmzC,EACP7+B,YAAY,MACZ+a,UAAQ,EACRvb,SAAU,gBAAGS,EAAH,EAAGA,OAAH,OAAgB6+B,EAAc7+B,EAAOvU,aAIlDsC,GACC,cAAC,GAAD,CAAQwM,KAAK,QAAQ4Y,OAAK,EAAC/rB,UAAU,OAArC,SACE,cAAC,GAAD,CAAgBosB,UAAWA,EAAWC,gBAAgB,uDAI5D,eAACe,GAAA,EAAD,WACE,cAAC+D,GAAA,EAAD,CAAQhe,KAAK,SAASrT,MAAM,OAAOkH,QAAS4S,EAA5C,oBACA,cAACuX,GAAA,EAAD,CAAQrxB,MAAM,UAAU0Z,SAAUs+B,EAAlC,SAA4CA,EAAU,YAAc,mBC/DjEM,GAAwB,CACnC32C,IAAK,MACL+T,UAAW,aACXO,OAAQ,UCMGsiC,GAA8C,SAAC,GAAD,MAAG1sB,EAAH,EAAGA,KAAMxT,EAAT,EAASA,SAAUmgC,EAAnB,EAAmBA,YAAnB,OACzD,eAAC,EAAD,CAAat/B,KAAI,iBAAEs/B,QAAF,IAAEA,OAAF,EAAEA,EAAc3sB,UAAhB,gCAA0CA,GAA3D,UACE,eAACnN,EAAA,EAAD,CAAc1R,OAAiB,UAAT6e,EAAkB3kB,QAAS,kBAAMmR,EAAS,UAAhE,UACE,cAAC,IAAD,CAAiBxW,KAAM42C,IAAW1oC,YAAU,EAAC7P,UAAU,SADzD,YAGA,eAACwe,EAAA,EAAD,CAAc1R,OAAiB,SAAT6e,EAAiB3kB,QAAS,kBAAMmR,EAAS,SAA/D,UACE,cAAC,IAAD,CAAiBxW,KAAMoO,IAAUF,YAAU,EAAC7P,UAAU,SADxD,eCyFW4N,GA3EE,SAAC4qC,EAAsCC,GAAvC,OAAyEr3B,IAAkB,YAEtG,IAAD,QADDs3B,EACC,EADDA,WAAYC,EACX,EADWA,cAAen4B,EAC1B,EAD0BA,SAAU3f,EACpC,EADoCA,eAAgBmkB,EACpD,EADoDA,SACpD,EACuBviB,mBAAQ,oBAAWuiB,EAASxO,YAApB,aAAW,EAAeoiC,mBAA1B,QAAyC,SADxE,mBACKjtB,EADL,KACWktB,EADX,OAEyBp2C,mBAAQ,oBAAYuiB,EAASxO,YAArB,aAAY,EAAekO,uBAA3B,QAA8C,IAF/E,mBAEK/P,EAFL,KAEY6xB,EAFZ,KAGGsS,EAAoB7tC,aACxB,kBAAMuV,EAASu4B,aAAa52C,KAAI,SAACV,GAAD,kBAAyB,CACvDA,MACA+T,UAAS,oBAAEgL,EAAS5J,MAAMnV,UAAjB,aAAE,EAAqBu3C,sBAAvB,QAAyC,EAClDjjC,OAAM,oBAAEyK,EAAS5J,MAAMnV,UAAjB,aAAE,EAAqBsnB,mBAAvB,QAAsC,SAE9C,SAACkwB,GAAD,OAAoB/kC,EAAwB+kC,EAAgBtkC,MAO9D,GAJA7T,qBAAU,WACR63C,MACC,IAECn4B,EAASvf,QACX,OAAO,cAACqS,GAAA,EAAD,CAASrS,SAAO,IAGzB,GAAIuf,EAAS7Z,MACX,OACE,cAAC,GAAD,CAAQwM,KAAK,QAAb,SACE,cAAC,GAAD,CAAgBiZ,UAAW5L,EAAS4L,UAAWC,gBAAgB,4BAKrE,IAAMtE,EAAgB,SAAC3T,GAAD,OAAgC,WACpD,IAAMC,EAAMT,EAAkBQ,EAAOO,EAAMP,MAAOO,EAAMN,KAExDmyB,EAAS,CAAEpyB,MAAOC,EAAMD,OAAQtR,EAAWuR,UAsB7C,OACE,qCACE,cAAC,EAAD,CAAarU,UAAU,OAAOmY,SAAUugC,IACxC,eAAClrC,GAAA,EAAD,CAAKxN,UAAU,OAAf,UACE,qBAAKA,UAAU,WAAf,SACE,cAAC,GAAD,CAAkB2rB,KAAMA,EAAMxT,SAAU0gC,MAE1C,qBAAK74C,UAAU,wBAAf,SACE,cAACygB,GAAD,CACEC,MAAO03B,GACPzjC,MAAOA,EACPwD,SAAU,SAAC/D,EAAOC,GAAR,OAAgBmyB,EAAS,CAAEpyB,QAAOC,gBA9BhC,WACpB,GAAImM,EAASu4B,aAAa/2C,OAAS,EACjC,OAAO,cAACsR,GAAA,EAAD,4BAGT,IAAM4lC,EAAaJ,IAEnB,MAAgB,UAATntB,EACH,cAAC6sB,EAAD,CAAWU,WAAYA,EAAYr4C,eAAgBA,IAEnD,cAAC43C,EAAD,CACES,WAAYA,EACZr4C,eAAgBA,EAChByiB,aAAc3O,EACdoT,cAAeA,IAoBlBoxB,SAGJ,iBAAM,CAAE/1B,GAAOrN,YChGLqjC,GAAmB,oCACnBC,GAAmB,oCACnBC,GAAa,8BACbC,GAAc,+BAkBZ31B,OAAY,qBACxBw1B,IAAmB,iBAAO,CAAEhC,UAAU,EAAMzwC,OAAO,MAD3B,eAExB0yC,IAAmB,SAAC/qB,EAAD,SAAuB,CAAE8oB,UAAU,EAAOzwC,OAAO,EAAMylB,UAAvD,EAAMA,cAFD,eAGxBktB,IAAa,iBAAO,CAAElC,UAAU,EAAOzwC,OAAO,MAHtB,IALO,CAChCywC,UAAU,EACVzwC,OAAO,IASIswC,GAAY,SAACt/B,GAAD,OAAkD,SAAClW,GAAD,8CAAiB,WAC1FwsB,EACApW,GAF0F,iBAAAtD,EAAA,6DAI1F0Z,EAAS,CAAE9a,KAAMimC,KAJyE,EAKnEzhC,EAAqBE,GAApChB,EALkF,EAKlFA,WALkF,kBAQlFA,EAAW,CAAEpV,IARqE,OASxFwsB,EAAS,CAAE9a,KAAMmmC,KATuE,sDAWxFrrB,EAAyB,CAAE9a,KAAMkmC,GAAkBjtB,UAAWJ,GAAc,EAAD,MAXa,8DAAjB,0DAiB9DmrB,GAAa,SAAC11C,GAAD,MAAmC,CAAE0R,KAAMomC,GAAa93C,QC1CrE+3C,GAAiB,gCACjBC,GAAiB,gCACjBC,GAAW,0BAGXC,GAAa,4BAuBX/1B,OAAY,qBACxB41B,IAAiB,SAAC5yC,GAAD,mBAAC,eAAgBA,GAAjB,IAAwBkxC,SAAS,EAAMnxC,OAAO,OADvC,eAExB8yC,IAAiB,SAAC7yC,EAAD,OAAUwlB,EAAV,EAAUA,UAAV,mBAAC,eAA+BxlB,GAAhC,IAAuCkxC,SAAS,EAAOnxC,OAAO,EAAMylB,iBAF7D,eAGxBstB,IAAW,SAACprB,EAAGzK,GAAJ,mBAAC,eACR+1B,YAAK,CAAE,UAAW,WAAa/1B,IADxB,IAEVi0B,SAAS,EACTnxC,OAAO,OANgB,IAPM,CAC/BoQ,QAAS,GACTC,QAAS,GACT8gC,SAAS,EACTnxC,OAAO,IAaImQ,GAAU,SAACa,EAA8CuB,GAA/C,OAAkF,SACvGnC,EACAC,EACAlX,GAHuG,8CAIpG,WAAOmuB,EAAoBpW,GAA3B,iBAAAtD,EAAA,6DACH0Z,EAAS,CAAE9a,KAAMqmC,KADd,EAEiB7hC,EAAqBE,GAAjCf,EAFL,EAEKA,QAFL,kBAKKA,EAAQC,EAASC,GALtB,OAMDkC,EAAevP,eAAeqN,EAASlX,GACvCmuB,EAAS,CAAE9a,KAAMumC,GAAU3iC,UAASC,YAPnC,sDASDiX,EAAyB,CAAE9a,KAAMsmC,GAAgBrtB,UAAWJ,GAAc,EAAD,MATxE,8DAJoG,0DAmB5FsrB,GAAY,SAACvgC,EAAiBC,EAAiBlX,GAAnC,MAAqE,CAC5FqT,KAAMwmC,GACN5iC,UACAC,UACAlX,UCxDW+5C,GAAkB,kCAClBC,GAAkB,kCAClBC,GAAY,4BACZC,GAAc,8BA+BrB51C,GAAe,CACnBoS,KAAM,GACNuiC,aAAc,GACdniC,MAAO,GACP3V,SAAS,EACT0F,OAAO,GAKHszC,GAAY,SAACljC,EAAiBC,GAAlB,OAAsC,SAACvV,GAAD,OAAiBA,IAAQsV,EAAUC,EAAUvV,IAC/Fy4C,GAAY,SAAC1jC,EAAgB2jC,GAAjB,OAAyCnlC,aAAO,SAACvT,GAAD,OAASA,IAAQ04C,IAAa3jC,IAa1F4jC,GAAwB,SAACxsB,GAAD,OAAiDxR,OAAOwoB,QACpFhX,EAAcgM,QAAc,SAACC,EAAD,GAAwB,IAAhBhR,EAAe,EAAfA,SAKlC,OAJQ,OAARA,QAAQ,IAARA,KAAUrS,KAAKqM,SAAQ,SAACphB,GACtBo4B,EAAIp4B,IAAQo4B,EAAIp4B,IAAQ,GAAK,KAGxBo4B,IACN,MAGUjW,OAAY,qBACxBi2B,IAAkB,8BAAC,eAAWz1C,IAAZ,IAA0BnD,SAAS,OAD7B,eAExB64C,IAAkB,SAACxrB,EAAD,OAAMlC,EAAN,EAAMA,UAAN,mBAAC,eAA2BhoB,IAA5B,IAA0CuC,OAAO,EAAMylB,iBAFjD,eAGxB2tB,IAAY,SAACzrB,EAAD,OAAM9X,EAAN,EAAMA,KAAMI,EAAZ,EAAYA,MAAZ,mBAAC,eAA6BxS,IAA9B,IAA4CwS,QAAOJ,OAAMuiC,aAAcviC,OAH3D,eAIxB+iC,IAAc,SAAC3yC,EAAD,OAAUnF,EAAV,EAAUA,IAAV,mBAAC,eACXmF,GADU,IAEb4P,KAAM0jC,GAAUtzC,EAAM4P,KAAM/U,GAC5Bs3C,aAAcmB,GAAUtzC,EAAMmyC,aAAct3C,QAPrB,eASxBk4C,IAAa,SAAC/yC,EAAD,OAAUmQ,EAAV,EAAUA,QAASC,EAAnB,EAAmBA,QAAnB,mBAAC,eACVpQ,GADS,IAEZ4P,KAAM5P,EAAM4P,KAAKrU,IAAI83C,GAAUljC,EAASC,IAAU1C,OAClDykC,aAAcnyC,EAAMmyC,aAAa52C,IAAI83C,GAAUljC,EAASC,IAAU1C,YAZ3C,eAcxB0lC,IAAc,SAACpzC,EAAD,OAAU0R,EAAV,EAAUA,WAAV,mBAAC,eACX1R,GADU,IAEbmyC,aAAcnyC,EAAM4P,KAAK+E,QAAO,SAAC9Z,GAAD,OAASA,EAAIuH,cAAcmB,MAAMmO,WAhB1C,eAkBxBqV,IAAgB,SAAC/mB,EAAD,OAxCY4P,EAAqBI,EAwCvBgX,EAAV,EAAUA,cAAV,mBAAC,eACbhnB,GADY,IAEfgQ,OA1C2BJ,EA0CE4jC,GAAsBxsB,GA1CHhX,EA0CmBhQ,EAAMgQ,MA1CDJ,EAAKojB,QAAO,SAAChjB,EAAD,GAA+B,IAAD,mBAApBnV,EAAoB,KAAf44C,EAAe,KACpH,IAAKzjC,EAAMnV,GACT,OAAOmV,EAGT,IAAM0jC,EAAW1jC,EAAMnV,GAKvB,OAHA64C,EAASvxB,YAAcuxB,EAASvxB,YAAcsxB,EAC9CzjC,EAAMnV,GAAO64C,EAEN1jC,IAVmE,eAWpEA,UAWmB,eAsBxBwX,IAAmB,kBAASmsB,EAAT,EAAG/jC,KAAoBlH,EAAvB,wBAAiC+d,EAAjC,EAAiCA,OAAjC,mBAAC,eAChB/d,GADe,IAElBkH,KAAM+jC,EAAU/H,OAAOnlB,EAAO7W,KAAK+E,QAAO,SAAC9Z,GAAD,OAAU84C,EAAUhb,SAAS99B,YAxBhD,IA0BxB2C,IA6BUs0C,GAAa,SAACpgC,GAAD,MAA2C,CAAEnF,KAAM6mC,GAAa1hC,eCrIlF+M,GAAS1c,KAAT0c,KAGKmzB,GAAY,SAACpC,GAAD,OAA0D,YAAqC,IAAlC8C,EAAiC,EAAjCA,WAAYr4C,EAAqB,EAArBA,eAAqB,EAC3E4B,qBAD2E,mBAC7G+3C,EAD6G,KAC/FC,EAD+F,KAE/GC,EAAYxB,EAAWl3C,OACvB24C,EAAa7U,aAAWzgB,GAAKq1B,EALV,GAK2CxB,GAEpE,OACE,cAAC1rC,GAAA,EAAD,UACGmtC,EAAWx4C,KAAI,SAACy4C,EAAO1rC,GAAR,OACd,qBAAiBlP,UAAU,oBAA3B,SACG46C,EAAMz4C,KAAI,SAACV,GAAD,OACT,cAAC20C,EAAD,CAEE30C,IAAKA,EACLZ,eAAgBA,EAChB01C,UAAWiE,IAAiB/4C,EAAIA,IAChCmY,OAAQ,kBAAM6gC,EAAgBD,IAAiB/4C,EAAIA,IAAMA,EAAIA,SAAMqB,KAJ9DrB,EAAIA,SAHLyN,UCELupC,GAAY,SAACoC,GAAD,OAAyC,YAE5D,IAAD,EADD3B,EACC,EADDA,WAAYr4C,EACX,EADWA,eAAgBknB,EAC3B,EAD2BA,cAAezE,EAC1C,EAD0CA,aAEvCpe,EAAcrC,kBAAO,GACnB+B,EAAW6B,eAAX7B,OAFL,EAGiCD,YAAuCC,GAAnE4iB,KAAMszB,OAHX,MAG2B,EAH3B,IAIuB52C,YAAsB,OAAQyhB,OAAOm1B,IAJ5D,mBAIKtzB,EAJL,KAIWkf,EAJX,KAKG1gB,EAAQ8f,aATM,GASoBoT,GAClC6B,EAAgB/0B,EAAMhkB,OAAS,EAC/B8jB,EAAW,UAAGE,EAAMwB,EAAO,UAAhB,QAAsB,GAUvC,OARA1mB,qBAAU,YACPoE,EAAYlC,SAAW0jC,EAAQ,GAChCxhC,EAAYlC,SAAU,IACrB,CAAEk2C,IACLp4C,qBAAU,WACR4F,SAAS,EAAG,KACX,CAAE8gB,IAGH,eAACrW,GAAA,EAAD,CAAuBE,cAAe0pC,EAAgB,OAAS,GAA/D,UACE,wBAAO/6C,UAAU,yBAAjB,UACE,wBAAOA,UAAU,2BAAjB,UACE,+BACE,qBAAIA,UAAU,0BAA0BgH,QAAS+gB,EAAc,OAA/D,iBACM,cAAC1E,GAAD,CAAgBC,aAAcA,EAAclP,MAAM,WAExD,qBAAIpU,UAAU,wCAAwCgH,QAAS+gB,EAAc,aAA7E,wBACa,cAAC1E,GAAD,CAAgBC,aAAcA,EAAclP,MAAM,iBAE/D,qBAAIpU,UAAU,wCAAwCgH,QAAS+gB,EAAc,UAA7E,oBACS,cAAC1E,GAAD,CAAgBC,aAAcA,EAAclP,MAAM,cAE3D,oBAAIpU,UAAU,+BAEhB,6BAAI,oBAAI4vB,QAAS,EAAG5vB,UAAU,0BAEhC,kCAC0B,IAAvB8lB,EAAY9jB,QAAgB,6BAAI,oBAAI4tB,QAAS,EAAG5vB,UAAU,cAA1B,gCAChC8lB,EAAY3jB,KAAI,SAACV,GAAD,OAAS,cAACo5C,EAAD,CAA4Bp5C,IAAKA,EAAKZ,eAAgBA,GAAnCY,EAAIA,cAIpDs5C,GACC,qBAAK/6C,UAAU,wBAAf,SACE,cAAC,GAAD,CAAiB4mB,WAAYZ,EAAMhkB,OAAQ8jB,YAAa0B,EAAMud,eAAgB2B,QAzBnElf,KCrBRqzB,GAAe,SAC1BxE,EACAC,EACAp9B,GAH0B,OAIvB,YAAiD,IAA9CzX,EAA6C,EAA7CA,IAAKZ,EAAwC,EAAxCA,eAAwC,EACPoC,cADO,mBAC3CsnB,EAD2C,KACxBC,EADwB,OAEXvnB,cAFW,mBAE3CuzC,EAF2C,KAE1BC,EAF0B,OAGRxzC,cAHQ,mBAG3C+3C,EAH2C,KAG3BrT,EAH2B,KAI7C5mC,EAAW8J,YAAYhK,GAE7B,OACE,qBAAIb,UAAU,wBAAd,UACE,qBAAIA,UAAU,yBAAyB+pB,UAAQ,MAA/C,UACE,cAAC,GAAD,CAAWtoB,IAAKA,EAAIA,IAAKyX,eAAgBA,IAD3C,IAC+DzX,EAAIA,OAEnE,oBAAIzB,UAAU,uCAAuC+pB,UAAQ,aAA7D,SACE,cAAC,IAAD,CAAM5oB,GAAE,kBAAaJ,EAAb,mCAAgDu6B,mBAAmB75B,EAAIA,MAA/E,SACGgkB,GAAShkB,EAAI+T,eAGlB,oBAAIxV,UAAU,uCAAuC+pB,UAAQ,SAA7D,SACE,cAAC,IAAD,CAAM5oB,GAAE,kBAAaJ,EAAb,gBAA6BU,EAAIA,IAAjC,WAAR,SACGgkB,GAAShkB,EAAIsU,YAGlB,oBAAI/V,UAAU,uCAAd,SACE,eAAC,GAAD,CAAiB4Z,OAAQ+tB,EAAgB97B,OAAQmvC,EAAjD,UACE,eAACx8B,EAAA,EAAD,CAAcxX,QAASyvC,EAAvB,UACE,cAAC,IAAD,CAAiB90C,KAAMyO,IAAUP,YAAU,EAAC7P,UAAU,SADxD,WAGA,eAACwe,EAAA,EAAD,CAAcxX,QAASwjB,EAAvB,UACE,cAAC,IAAD,CAAiB7oB,KAAMgpB,IAAY9a,YAAU,EAAC7P,UAAU,SAD1D,kBAMJ,cAACs2C,EAAD,CAAc70C,IAAKA,EAAIA,IAAKmY,OAAQ68B,EAAY5qC,OAAQ2qC,IACxD,cAACH,EAAD,CAAuB50C,IAAKA,EAAIA,IAAKmY,OAAQ4Q,EAAc3e,OAAQ0e,SCH1DjlB,GAtCS,SAACC,EAAgBC,GAEvCD,EAAOQ,eAAe,eAAgB0sB,GAAc,kBACpDltB,EAAOY,UAAU,eAAgBX,EAAQ,CAAE,WAAY,YAAc,CAAE,cAEvED,EAAOQ,eAAe,UAAWqwC,GAAS,wBAAyB,eAAgB,kBAEnF7wC,EAAOQ,eAAe,yBAAyB,kBAAMswC,MACrD9wC,EAAOY,UAAU,wBAAyBX,EAAQ,CAAE,aAAe,CAAE,YAAa,gBAElFD,EAAOQ,eAAe,eAAgBuwC,GAAc,kBACpD/wC,EAAOY,UAAU,eAAgBX,EAAQ,CAAE,WAAa,CAAE,UAAW,eAErED,EAAOQ,eAAe,YAAayyC,GAAW,WAC9CjzC,EAAOQ,eAAe,eAAgB80C,GAAc,wBAAyB,eAAgB,kBAE7Ft1C,EAAOQ,eAAe,YAAa0yC,GAAW,gBAE9ClzC,EAAOQ,eAAe,WAAY6H,GAAU,YAAa,aACzDrI,EAAOY,UAAU,WAAYX,EAC3B,CAAE,WAAY,iBAAkB,cAAe,YAC/C,CAAE,gBAAiB,aAAc,kBAAmB,qBAItD,IAAMy1C,EAAwB,SAACC,GAAD,OAC5B,mBJwEoB,SAACvjC,GAAD,IAA+CujC,IAA/C,gEAAgE,yDAAM,WAC5FjtB,EACApW,GAF4F,6BAAAtD,EAAA,2DAIvEsD,IAAb2I,EAJoF,EAIpFA,SAEH06B,IAAU16B,EAASvf,SAAYkM,YAAQqT,EAAShK,MANuC,wDAU5FyX,EAAS,CAAE9a,KAAM0mC,KAV2E,WAarEliC,EAAqBE,GAAlCnB,EAbkF,EAalFA,SAbkF,SAc3CA,IAd2C,gBAclFF,EAdkF,EAclFA,KAdkF,IAc5EI,MACRukC,QAfoF,MAcpE,GAdoE,GAe7DvhB,QAAqB,SAACC,EAAD,GAAgD,IAAxCp4B,EAAuC,EAAvCA,IAAKu3C,EAAkC,EAAlCA,eAAgBjwB,EAAkB,EAAlBA,YAG7E,OAFA8Q,EAAIp4B,GAAO,CAAEu3C,iBAAgBjwB,eAEtB8Q,IACN,IAEH5L,EAAyB,CAAEzX,OAAMI,MAAOukC,EAAgBhoC,KAAM4mC,KArB4B,kDAuB1F9rB,EAAyB,CAAE9a,KAAM2mC,GAAiB1tB,UAAWJ,GAAc,EAAD,MAvBgB,0DAAN,yDIxE1CtV,CAA1C,EAAGiB,qBAAsEujC,KAE3E31C,EAAO61C,QAAQ,WAAYH,GAAsB,IACjD11C,EAAO61C,QAAQ,gBAAiBH,GAAsB,IACtD11C,EAAOQ,eAAe,cAAc,kBAAM2yC,MAC1CnzC,EAAOQ,eAAe,cAAc,kBAAMoxC,MAC1C5xC,EAAOQ,eAAe,aAAa,kBAAMuxC,MAEzC/xC,EAAOQ,eAAe,YAAakxC,GAAW,wBAC9C1xC,EAAOQ,eAAe,UAAW+Q,GAAS,uBAAwB,mB,UC1CvDukC,GAAyB,wCACzBC,GAAyB,wCACzBC,GAAmB,kCAkBjB33B,OAAY,qBACxBy3B,IAAyB,SAACz0C,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB3F,SAAS,EAAM0F,OAAO,OAD/C,eAExB20C,IAAyB,SAAC10C,GAAD,mBAAC,eAAgBA,GAAjB,IAAwB3F,SAAS,EAAO0F,OAAO,OAFhD,eAGxB40C,IAAmB,SAACjtB,EAAGzK,GAAJ,mBAAC,eAAoBA,GAArB,IAA6B5iB,SAAS,EAAO0F,OAAO,OAH/C,IALO,CAChC1F,SAAS,EACT0F,OAAO,IASI8a,GAAkB,SAAC9J,GAAD,OAC7B,yDAAM,WAAOsW,EAAoBpW,GAA3B,uBAAAtD,EAAA,yDACJ0Z,EAAS,CAAE9a,KAAMkoC,KADb,EAGiBxjC,IAAbmN,EAHJ,EAGIA,SAHJ,EAIoBrN,EAAqBE,GAArCX,EAJJ,EAIIA,YAEH8N,EAASb,gBAAgBC,QAN1B,uBAOF6J,EAAS,CAAE9a,KAAMmoC,KAPf,mDAaiBpkC,IAbjB,OAaIskC,EAbJ,OAeFvtB,EAAQ,aAAyB9a,KAAMooC,GAAkB78B,SAAUsG,EAASb,gBAAgBzF,UAAa88B,IAfvG,kDAiBFvtB,EAAS,CAAE9a,KAAMmoC,KAjBf,0DAAN,0DC1Bah2C,GALS,SAACC,GAEvBA,EAAOQ,eAAe,kBAAmB0b,GAAiB,yBC+C7Cg6B,GAtCiB,SAAC,GAAD,IAFT/8B,EAGPyF,EADgB,EAC5Ba,SAAYb,gBAAmBU,EADH,EACGA,sBAAuBC,EAD1B,EAC0BA,2BAD1B,OAG9B,eAAC3T,GAAA,EAAD,CAAYC,MAAM,oBAAoBpR,UAAU,QAAhD,UACE,cAAC,KAAD,UACE,eAAC,GAAD,CAAcwxB,QAASrN,EAAgBC,QAASjM,SAAU0M,EAA1D,iDAEE,wBAAO7kB,UAAU,uBAAjB,mDACwC,4BAAImkB,EAAgBC,QAAU,YAAc,YADpF,YAKJ,eAAC,KAAD,CAAWpkB,UAAU,OAArB,UACE,uBAAOA,UAAWkC,IAAW,CAAE,cAAeiiB,EAAgBC,UAA9D,uDAGA,cAACkP,GAAA,EAAD,CACEngB,KAAK,SACL+S,IAAK,EACLvN,YAAY,YACZa,UAAW2K,EAAgBC,QAC3B/f,OAvBeqa,EAuBMyF,EAAgBzF,SAvBCA,EAAD,UAAoBA,GAAR,IAwBjDvG,SAAU,gBAAGS,EAAH,EAAGA,OAAH,OAAgBkM,EAA2Ba,OAAO/M,EAAOvU,WAEpE8f,EAAgBC,SACf,wBAAOpkB,UAAU,uBAAjB,eACgC8C,IAA7BqhB,EAAgBzF,UAA0ByF,EAAgBzF,SAAW,GACpE,8EAC4C,4BAAIyF,EAAgBzF,WADhE,UACqFyF,EAAgBzF,SAAW,GAAK,IADrH,QAIAyF,EAAgBzF,UAAY,wECzClCg9B,GAAiD,SAAC,GAAD,IAAGh7B,EAAH,EAAGA,MAAH,OACrD,mCACGA,EAAMve,KAAI,SAACw5C,EAAOzsC,GAAR,OACT,cAAC1B,GAAA,EAAD,UACGmuC,EAAMx5C,KAAI,SAACy5C,EAAUC,GAAX,OACT,qBAAoB77C,UAAS,iBAAY,GAAK27C,EAAM35C,OAAvB,SAA7B,SACG45C,GADOC,OAFJ3sC,SA8BD4sC,GAnBE,SACfC,EACAC,EACAnuC,EACAouC,EACAC,EACAC,GANe,OAOZ,kBACH,cAACzlB,GAAA,EAAD,UACE,cAAC,GAAD,CACEhW,MAAO,CACL,CAAE,cAACu7B,EAAD,IAAmB,cAACC,EAAD,KACrB,CAAE,cAACF,EAAD,IAAsB,cAACnuC,EAAD,KACxB,CAAE,cAACsuC,EAAD,IAAU,cAACJ,EAAD,YCnBdK,GAAuB,SAAC9G,GAAD,MACN,aAArBA,EAAkC,+BAAiC,oCAMxD+G,GAAsD,SAAC,GAA+C,IAAD,QALpF/G,EAKwCtwB,EAA4C,EAA5CA,SAAUD,EAAkC,EAAlCA,4BACxEV,EAAmC,UAAGW,EAASX,wBAAZ,QAAgC,CAAEC,cAAc,GACnFg4B,EAA0B,SAAChH,GAAD,OAAwC,kBAAMvwB,EAA4B,2BAAD,OAClGV,QADkG,IAClGA,IAAoB,CAAEC,cAAc,IAD8D,IACrDgxB,wBAGpD,OACE,eAACnkC,GAAA,EAAD,CAAYC,MAAM,kBAAkBpR,UAAU,QAA9C,UACE,cAAC,KAAD,UACE,eAAC,GAAD,CACEwxB,QAAO,UAAEnN,EAAiBC,oBAAnB,SACPnM,SAAU,SAACmM,GAAD,OAAkBS,EAA4B,2BAAKV,GAAN,IAAwBC,mBAFjF,0EAKE,wBAAOtkB,UAAU,uBAAjB,sCAC2B,6CAD3B,qBAEK,4BAAIqkB,EAAiBC,aAAe,UAAY,cAFrD,YAMJ,cAAC,KAAD,UACE,eAAC,GAAD,CACEkN,QAAO,UAAEnN,EAAiBmH,oBAAnB,SACPrT,SAAU,SAACqT,GAAD,OAAkBzG,EAA4B,2BAAKV,GAAN,IAAwBmH,mBAFjF,gFAKE,wBAAOxrB,UAAU,uBAAjB,sCAC2B,iEAD3B,qBAEK,4BAAI,UAAAqkB,EAAiBmH,oBAAjB,SAAwC,UAAY,cAF7D,YAMJ,eAAC,KAAD,CAAWxrB,UAAU,OAArB,UACE,iEACA,eAAC,EAAD,CAAagZ,KAAMojC,GAAqB/3B,EAAiBixB,kBAAzD,UACE,cAAC92B,EAAA,EAAD,CACE1R,QAASuX,EAAiBixB,kBAA0D,eAAtCjxB,EAAiBixB,iBAC/DtuC,QAASs1C,EAAwB,cAFnC,SAIGF,GAAqB,gBAExB,cAAC59B,EAAA,EAAD,CACE1R,OAA8C,aAAtCuX,EAAiBixB,iBACzBtuC,QAASs1C,EAAwB,YAFnC,SAIGF,GAAqB,iBAG1B,uBAAOp8C,UAAU,uBAAjB,UArDsBs1C,EAsDEjxB,EAAiBixB,iBArD1B,aAArBA,EACI,sFAAgD,0CAAhD,sBACA,sFAAgD,8CAAhD,gCCFOiH,GAAgD,SAAC,GAAD,IAAeh4B,EAAf,EAAGS,SAAYT,GAAMW,EAArB,EAAqBA,cAArB,OAC3D,cAAC/T,GAAA,EAAD,CAAYC,MAAM,iBAAiBpR,UAAU,QAA7C,SACE,eAAC,KAAD,WACE,cAAC,IAAD,CAAiB2B,KAAoB,UAAZ,OAAF4iB,QAAE,IAAFA,OAAA,EAAAA,EAAI9R,OAAmB+pC,IAASC,IAAOz8C,UAAU,+BACxE,cAAC,GAAD,CACEwxB,QAAuB,UAAZ,OAAFjN,QAAE,IAAFA,OAAA,EAAAA,EAAI9R,OACb0F,SAAU,SAACukC,GACT,IAAMjqC,EAAeiqC,EAAe,OAAS,QAE7Cx3B,EAAc,2BAAKX,GAAN,IAAU9R,WACvBD,aAAoBC,IANxB,mCCdOkqC,GAAsD,SAAC,GAAD,MAAGxkC,EAAH,EAAGA,SAAUrL,EAAb,EAAaA,OAAQyR,EAArB,EAAqBA,QAArB,OACjE,cAAC,EAAD,CAAavF,KAAI,UAAEsD,GAAwBxP,UAA1B,QAAqCyR,EAAtD,SACE,cAAC,GAAD,CAA2BA,QAASA,EAASzR,OAAQA,EAAQqL,SAAUA,OCI9DykC,GAAkC,SAAC,GAAD,QAAG53B,EAAH,EAAGA,SAAUG,EAAb,EAAaA,kBAAb,OAC7C,cAAChU,GAAA,EAAD,CAAYC,MAAM,SAASpR,UAAU,QAArC,SACE,eAAC,KAAD,CAAWA,UAAU,OAArB,UACE,iFACA,cAAC,GAAD,CACEue,QAAQ,aACRzR,OAAM,oBAAEkY,EAASjP,cAAX,aAAE,EAAiByO,uBAAnB,QAAsC,aAC5CrM,SAAU,SAACqM,GAAD,OAAqBW,EAAkB,CAAEX,6BCJ9Cq4B,GAA8B,SAAC,GAAD,UAAermC,EAAf,EAAGwO,SAAYxO,KAAQ4O,EAAvB,EAAuBA,gBAAvB,OACzC,eAACjU,GAAA,EAAD,CAAYC,MAAM,OAAOpR,UAAU,QAAnC,UACE,eAAC,KAAD,WACE,6EACA,cAAC,GAAD,CACE2rB,KAAI,iBAAEnV,QAAF,IAAEA,OAAF,EAAEA,EAAMoiC,mBAAR,QAAuB,QAC3BN,YAAa,SAACwE,GAAD,OAAc/rC,aAAW+rC,IACtC3kC,SAAU,SAACygC,GAAD,OAAiBxzB,EAAgB,2BAAK5O,GAAN,IAAYoiC,oBAExD,wBAAO54C,UAAU,uBAAjB,uCAAkE,6CAAIwW,QAAJ,IAAIA,OAAJ,EAAIA,EAAMoiC,mBAAV,QAAyB,UAA3F,UAEF,eAAC,KAAD,CAAW54C,UAAU,OAArB,UACE,oEACA,cAACygB,GAAD,CACEC,MAAO03B,GACPzjC,MAAK,iBAAE6B,QAAF,IAAEA,OAAF,EAAEA,EAAMkO,uBAAR,QAA2B,GAChCvM,SAAU,SAAC/D,EAAOC,GAAR,OAAgB+Q,EAAgB,2BAAK5O,GAAN,IAAYkO,gBAAiB,CAAEtQ,QAAOC,oBClB1E0oC,GAAgD,SAAC,GAAD,MAC7Ct4B,EAD6C,EACzDO,SAAYP,cAAiBQ,EAD4B,EAC5BA,yBAD4B,OAG3D,cAAC9T,GAAA,EAAD,CAAYC,MAAM,kBAAkBpR,UAAU,QAA9C,SACE,eAAC,KAAD,CAAWA,UAAU,OAArB,UACE,0EACA,cAACygB,GAAD,CACEC,MAAO0G,GACPzS,MAAK,iBAAE8P,QAAF,IAAEA,OAAF,EAAEA,EAAeC,uBAAjB,QAAoCR,GACzC/L,SAAU,SAAC/D,EAAOC,GAAR,OAAgB4Q,EAAyB,CAAEP,gBAAiB,CAAEtQ,QAAOC,kBC6CxE/O,GA9CS,SAACC,EAAgBC,GAEvCD,EAAOQ,eACL,WACA+1C,GACA,0BACA,2BACA,wBACA,wBACA,iBACA,gBAEFv2C,EAAOY,UAAU,WAAYC,MAC7Bb,EAAOY,UAAU,WAAYX,EAAQ,KAAM,CAAE,yBAE7CD,EAAOQ,eAAe,2BAA2B,kBAAM01C,MACvDl2C,EAAOY,UACL,0BACAX,EAAQ,CAAE,YAAc,CAAE,wBAAyB,gCAGrDD,EAAOQ,eAAe,4BAA4B,kBAAMs2C,MACxD92C,EAAOY,UAAU,2BAA4BX,EAAQ,CAAE,YAAc,CAAE,iCAEvED,EAAOQ,eAAe,yBAAyB,kBAAMw2C,MACrDh3C,EAAOY,UAAU,wBAAyBX,EAAQ,CAAE,YAAc,CAAE,mBAEpED,EAAOQ,eAAe,kBAAkB,kBAAM62C,MAC9Cr3C,EAAOY,UAAU,iBAAkBX,EAAQ,CAAE,YAAc,CAAE,uBAE7DD,EAAOQ,eAAe,gBAAgB,kBAAM82C,MAC5Ct3C,EAAOY,UAAU,eAAgBX,EAAQ,CAAE,YAAc,CAAE,qBAE3DD,EAAOQ,eAAe,yBAAyB,kBAAMg3C,MACrDx3C,EAAOY,UAAU,wBAAyBX,EAAQ,CAAE,YAAc,CAAE,8BAGpED,EAAOQ,eAAe,yBAAyB,kBAAM8e,MACrDtf,EAAOQ,eAAe,8BAA8B,kBAAM+e,MAC1Dvf,EAAOQ,eAAe,+BAA+B,kBAAMgf,MAC3Dxf,EAAOQ,eAAe,4BAA4B,kBAAMkf,MACxD1f,EAAOQ,eAAe,iBAAiB,kBAAMmf,MAC7C3f,EAAOQ,eAAe,qBAAqB,kBAAMof,MACjD5f,EAAOQ,eAAe,mBAAmB,kBAAMqf,O,UC/DpC43B,GAA0B,SAACC,EAAaC,GAAkC,IAAD,EAC3DD,EAAIpoC,MAAM,OADiD,mBAC5EsoC,EAD4E,YAEpDtoC,MAAM,KAAzBuoC,EAFuE,yBAG9EC,EAAiBD,EAAUp7C,OAAV,WAAuBo7C,EAAUvzC,KAAK,MAAS,GAEtE,MAAM,GAAN,OAAUszC,EAAV,cAAsBD,GAAtB,OAAqCG,ICK1BC,GAAwB,+CAQxBjmC,GAAsB,SAACM,GAAD,OAAkD,SACnFtB,EACAiB,GAFmF,8CAGhF,WAAO2W,EAAoBpW,GAA3B,mBAAAtD,EAAA,6DACH0Z,EAAS,CAAE9a,KAd8B,uDAatC,EAE6BwE,EAAqBE,GAA7CR,EAFL,EAEKA,oBAFL,kBAKuBA,EAAoB,aAAEhB,UAAWiB,IALxD,OAKKimC,EALL,OAODtvB,EAAoC,CAAE9a,KAAMmqC,GAAuBjnC,SAAQknC,cAP1E,gDASDtvB,EAAyB,CAAE9a,KArBY,qDAqBuBiZ,UAAWJ,GAAc,EAAD,MATrF,yDAHgF,0DCLxEwxB,GAAqB,wCACrBC,GAAqB,wCACrBC,GAAe,kCACfC,GAAiB,oCACjBC,GAAkB,qCA0BzBx5C,GAA4B,CAChCgT,QAAS,GACTymC,gBAAiB,GACjB58C,SAAS,EACT0F,OAAO,GASIm3C,GAA2B,SAACznC,EAAgBknC,GAAjB,OACtC,SAACl9C,GAAD,OAAuBA,EAAEgW,SAAWA,EAAShW,EAAtB,2BAA+BA,GAA/B,IAAkCk9C,gBAE9CQ,GAAwB,SAAC1nC,EAAgB6L,GAAjB,OACnC,SAAC7hB,GAAD,OAAuBA,EAAEgW,SAAWA,EAAShW,EAAtB,2BAA+BA,GAA/B,IAAkC6hB,aAE5C0B,OAAY,qBACxB45B,IAAqB,8BAAC,eAAWp5C,IAAZ,IAA0BnD,SAAS,OADhC,eAExBw8C,IAAqB,gBAAGrxB,EAAH,EAAGA,UAAH,mBAAC,eAAwBhoB,IAAzB,IAAuCuC,OAAO,EAAMylB,iBAFjD,eAGxBsxB,IAAe,SAACpvB,EAAD,OAAMlX,EAAN,EAAMA,QAAS4mC,EAAf,EAAeA,iBAAf,mBAAC,eACT55C,IADQ,IACMgT,UAASymC,gBAAiBzmC,EAAS4mC,wBAJhC,eAKxBL,IAAiB,SAAC/2C,EAAD,OAAU0R,EAAV,EAAUA,WAAV,mBAAC,eACd1R,GADa,IAEhBi3C,gBAAiBj3C,EAAMwQ,QAAQmE,QAAO,qBAAGlF,OAAoBrN,cAAcmB,MAAMmO,WAP1D,eASxBglC,IAAwB,SAAC12C,EAAD,OAAUyP,EAAV,EAAUA,OAAQknC,EAAlB,EAAkBA,UAAlB,mBAAC,eACrB32C,GADoB,IAEvBwQ,QAASxQ,EAAMwQ,QAAQjV,IAAI27C,GAAyBznC,EAAQknC,IAC5DM,gBAAiBj3C,EAAMi3C,gBAAgB17C,IAAI27C,GAAyBznC,EAAQknC,SAZrD,eAcxBK,IAAkB,SAACh3C,EAAD,OAAUyP,EAAV,EAAUA,OAAQ6L,EAAlB,EAAkBA,OAAlB,mBAAC,eACftb,GADc,IAEjBwQ,QAASxQ,EAAMwQ,QAAQjV,IAAI47C,GAAsB1nC,EAAQ6L,IACzD27B,gBAAiBj3C,EAAMi3C,gBAAgB17C,IAAI47C,GAAsB1nC,EAAQ6L,SAjBlD,IAmBxB9d,IAEU+S,GAAc,SAACQ,GAAD,OAAkD,yDAAM,WACjFsW,EACApW,GAFiF,uBAAAtD,EAAA,6DAIjF0Z,EAAS,CAAE9a,KAAMqqC,KAJgE,EAKzD7lC,EAAqBE,GAArCV,EALyE,EAKzEA,YALyE,kBAQnCA,IAAc5B,MAAK,gBAAGhO,EAAH,EAAGA,KAAMy2C,EAAT,EAASA,iBAAT,MAAiC,CAC9F5mC,QAAS7P,EAAKpF,KAAI,SAACkU,GAAD,mBAAC,eAAyBA,GAA1B,IAAkC6L,OAAQ,kBAC5D87B,uBAV6E,gBAQvE5mC,EARuE,EAQvEA,QAAS4mC,EAR8D,EAQ9DA,iBAKjB/vB,EAA4B,CAAE9a,KAAMuqC,GAActmC,UAAS4mC,qBAboB,kDAe/E/vB,EAAyB,CAAE9a,KAAMsqC,GAAoBrxB,UAAWJ,GAAc,EAAD,MAfE,0DAAN,0DAmBhEiyB,GAAgB,SAAC3lC,GAAD,MAA8C,CAAEnF,KAAMwqC,GAAgBrlC,eAEtF4lC,GAAoB,SAACvmC,GAAD,OAAkD,SAACtB,GAAD,8CAAoB,WACrG4X,EACApW,GAFqG,6BAAAtD,EAAA,2DAI1EsD,IAAnBhX,EAJ6F,EAI7FA,eAEH0J,YAAc1J,GANkF,uBAOnGotB,EAAyB,CAAE9a,KAAMyqC,GAAiBvnC,SAAQ6L,OAAQ,YAPiC,0CAa3F1a,EAAiB3G,EAAjB2G,IAAQ8H,EAbmF,YAa1EzO,EAb0E,WAchF8W,EAAqB,2BACnCrI,GADkC,IAErC9H,IAAKw1C,GAAwBx1C,EAAK6O,MAF5BY,EAd2F,EAc3FA,OAd2F,SAmB1EA,IAnB0E,gBAmB3FiL,EAnB2F,EAmB3FA,OAER+L,EAAyB,CAAE9a,KAAMyqC,GAAiBvnC,SAAQ6L,OAAmB,SAAXA,EAAoB,QAAU,YArBG,kDAuBnG+L,EAAyB,CAAE9a,KAAMyqC,GAAiBvnC,SAAQ6L,OAAQ,YAvBiC,0DAApB,0D,oBCnFtEwQ,GAAiB,SAAC,GAA+E,IAA7Evb,EAA4E,EAA5EA,YAAa9S,EAA+D,EAA/DA,MAAO85C,EAAwD,EAAxDA,YAAahmC,EAA2C,EAA3CA,SAA2C,EACzDlV,cADyD,mBACnGm7C,EADmG,KAClFC,EADkF,KACvEC,EADuE,KAEnGlnC,EAAY+mC,EAAZ/mC,QACFmnC,EAAepxC,YAAQ9I,GACvBm6C,EAAiB,kBAAMrmC,EAAS,KAMtC,OAJArX,qBAAU,WACRqW,MACC,IAEIinC,EACL,eAACK,GAAA,EAAD,WACE,cAACnrB,GAAA,EAAD,CACEjvB,MAAOA,EACPsU,YAAY,SACZR,SAAU,SAAC7U,GAAD,OAAO6U,EAAS7U,EAAEsV,OAAOvU,UAErC,eAACq6C,GAAA,EAAD,CAAiBC,UAAU,SAA3B,UACE,cAACxtB,GAAA,EAAD,CACE7vB,GAAG,iBACHyF,SAAO,EACPoM,KAAK,SACLnT,UAAU,6BACVgH,QAASiE,YAAKuzC,EAAgBF,GALhC,SAOE,cAAC,IAAD,CAAiB38C,KAAMi9C,QAEzB,cAACr1B,GAAA,EAAD,CAAqB3Q,OAAO,iBAAiB4Q,UAAU,OAAOq1B,QAAQ,QAAtE,oCAMJ,eAAC,EAAD,CACE7lC,KAAMulC,EAAe,SAAH,kBAAyBl6C,GAC3CrE,UAAYu+C,EAAwD,+BAAzC,uCAF7B,UAIGnnC,EAAQjV,KAAI,gBAAGkU,EAAH,EAAGA,OAAQyoC,EAAX,EAAWA,UAAX,OACX,eAACtgC,EAAA,EAAD,CAEE1R,OAAQzI,IAAUgS,GAAUyoC,GAAaP,EACzCv3C,QAAS,kBAAMmR,EAAS9B,IAH1B,UAKGA,EACAyoC,GAAa,sBAAM9+C,UAAU,yBAAhB,uBALTqW,MAQT,cAACmI,EAAA,EAAD,CAAcC,SAAO,IACrB,cAACD,EAAA,EAAD,CAAcxX,QAASiE,YAAKuzC,EAAgBH,GAA5C,SACE,iDCxDFnpB,GAAgE,SAAC,GAAD,IAAG6pB,EAAH,EAAGA,OAAWzvC,EAAd,iCACpE,cAAC,GAAD,2BACMA,GADN,IAEEokB,UAAU,EACVvgB,KAAK,MACLwF,YAAY,cACZ3Y,UAAW++C,EAAS,OAAS,OAIpBC,GAA8D,SAAC,GAEtE,IAAD,YADDnzC,EACC,EADDA,OAAQ+N,EACP,EADOA,OAAQvD,EACf,EADeA,OAAQgB,EACvB,EADuBA,oBACvB,EAC6C5U,mBAAQ,oBAAC4T,EAAOknC,iBAAR,aAAC,EAAkB0B,uBAAnB,QAAsC,IAD3F,mBACKA,EADL,KACsBC,EADtB,OAEmDz8C,mBAAQ,oBAAC4T,EAAOknC,iBAAR,aAAC,EAAkB4B,0BAAnB,QAAyC,IAFpG,mBAEKA,EAFL,KAEyBC,EAFzB,OAG6D38C,mBAAQ,oBACtE4T,EAAOknC,iBAD+D,aACtE,EAAkB8B,+BADoD,QACzB,IAJ5C,mBAGKA,EAHL,KAG8BC,EAH9B,KAMG9pB,EAAe7kB,aAA4B,sBAAC,sBAAA4D,EAAA,+EAAY8C,EAAoBhB,EAAOA,OAAQ,CAC/F4oC,gBAAiBnuC,aAAoBmuC,GACrCE,mBAAoBruC,aAAoBquC,GACxCE,wBAAyBvuC,aAAoBuuC,KAC5C9pC,KAAKqE,IAJ0C,4CAMlD,OACE,cAACmT,GAAA,EAAD,CAAOlhB,OAAQA,EAAQ+N,OAAQA,EAAQoT,UAAQ,EAA/C,SACE,uBAAMC,SAAUuI,EAAhB,UACE,eAACtI,GAAA,EAAD,CAAatT,OAAQA,EAArB,gCAAgD,4BAAIvD,EAAOA,YAC3D,eAAC8W,GAAA,EAAD,WACE,eAAC,GAAD,CAAW9oB,MAAO46C,EAAiB9mC,SAAU+mC,EAA7C,UACE,eAAC,GAAD,CAAal/C,UAAU,OAAOwpB,UAAU,SAAxC,oDACyC,yCAAYnT,EAAOA,OAAnB,OADzC,uCADF,cAMA,eAAC,GAAD,CAAWhS,MAAO86C,EAAoBhnC,SAAUinC,EAAhD,UACE,eAAC,GAAD,CAAap/C,UAAU,OAAOwpB,UAAU,SAAxC,8EACmE,yCAAYnT,EAAOA,OAAnB,gBADnE,uCADF,iBAOA,eAAC,GAAD,CAAWhS,MAAOg7C,EAAyBN,QAAM,EAAC5mC,SAAUmnC,EAA5D,UACE,cAAC,GAAD,CAAat/C,UAAU,OAAOwpB,UAAU,SAAxC,6IADF,0BAQF,eAAC4D,GAAA,EAAD,WACE,cAAC+D,GAAA,EAAD,CAAQrxB,MAAM,OAAOqT,KAAK,SAASnM,QAAS4S,EAA5C,oBACA,cAACuX,GAAA,EAAD,CAAQrxB,MAAM,UAAd,2BCjDGy/C,GAA8C,SAAC,GAAgD,IAA9Cr9B,EAA6C,EAA7CA,OAA6C,IAArC+jB,kBAAqC,MAAxB1hC,OAAO0hC,WAAiB,EACnGtoB,EAAM9a,mBACN28C,EAAgB,kBAAMvZ,EAAW,sBAAsBI,SAF4C,EAGvE5jC,mBAAkB+8C,KAHqD,mBAGjGC,EAHiG,KAGvFC,EAHuF,KAazG,OARA5+C,qBAAU,WACR,IAAM+lC,EAAW,kBAAM6Y,EAAYF,MAInC,OAFAj7C,OAAO44B,iBAAiB,SAAU0J,GAE3B,kBAAMtiC,OAAOuiC,oBAAoB,SAAUD,MACjD,IAEY,eAAX3kB,EACK,cAAC,IAAD,CAAiBrS,YAAU,EAAClO,KAAMg+C,IAAmBjsC,MAAI,IAIhE,qCACE,sBACEiK,IAAK,SAAC0L,GACJ1L,EAAI3a,QAAUqmB,GAFlB,SAKc,UAAXnH,EACG,cAAC,IAAD,CAAiBrS,YAAU,EAAClO,KAAMs6B,IAAWj8B,UAAU,eACvD,cAAC,IAAD,CAAiB6P,YAAU,EAAClO,KAAMi+C,IAAa5/C,UAAU,kBAE/D,cAACupB,GAAA,EAAD,CACE3Q,OAAS,kBAAM+E,EAAI3a,SACnBwmB,UAAWi2B,EAAW,YAAc,OACpCI,SAAqB,UAAX39B,EAHZ,SAKc,UAAXA,EAAqB,uDACpB,oIAEE,uBAFF,aAGY,cAAC,KAAD,CAAc5W,KAAK,oCAAnB,2BAHZ,kDC1BJw0C,GAAuC,SAAC,GAAD,IAAGC,EAAH,EAAGA,SAAH,OAC3C,uBAAM//C,UAAU,aAAhB,WACI+/C,GAAY,gDACbA,GAAY,qCAAGA,EAAH,IAAa,yDAGxBC,GAAoB,kBACxB,qCACE,cAAC,IAAD,CAAiBnwC,YAAU,EAAClO,KAAMs+C,IAAmBjgD,UAAU,eAAesB,GAAG,sBACjF,cAACioB,GAAA,EAAD,CAAqB3Q,OAAO,oBAAoB4Q,UAAU,QAA1D,gCAIS02B,GAAgC,SAAC,GAExC,IAAD,MADD7pC,EACC,EADDA,OAAQgB,EACP,EADOA,oBAAqB6mC,EAC5B,EAD4BA,kBAAmBF,EAC/C,EAD+CA,iBAAkBn9C,EACjE,EADiEA,eACjE,EACwBoC,cADxB,mBACK4I,EADL,KACa+N,EADb,KAEaumC,EAA4C9pC,EAApDA,OAAmByoC,EAAiCzoC,EAAjCyoC,UAAWvB,EAAsBlnC,EAAtBknC,UAAWr7B,EAAW7L,EAAX6L,OAC3Ck+B,GAAiBtB,GAAa5sC,aAAsCrR,GAM1E,OAJAC,qBAAU,WACRo9C,EAAkB7nC,EAAOA,UACxB,IAGD,qBAAIrW,UAAU,wBAAd,UACE,oBAAIA,UAAU,yBAAyB+pB,UAAQ,oBAA/C,SAAoE+0B,GAAa,cAAC,GAAD,MACjF,oBAAI9+C,UAAU,yBAAyB+pB,UAAQ,SAA/C,SAAyDo2B,IACzD,oBAAIngD,UAAU,yBAAyB+pB,UAAQ,qBAA/C,0BACGwzB,QADH,IACGA,OADH,EACGA,EAAW0B,uBADd,QACiC,cAAC,GAAD,CAAIc,SAAQ,OAAE/B,QAAF,IAAEA,OAAF,EAAEA,EAAkBiB,oBAEjE,oBAAIj/C,UAAU,yBAAyB+pB,UAAQ,uBAA/C,0BACGwzB,QADH,IACGA,OADH,EACGA,EAAW4B,0BADd,QACoC,cAAC,GAAD,CAAIY,SAAQ,OAAE/B,QAAF,IAAEA,OAAF,EAAEA,EAAkBmB,uBAEpE,oBAAIn/C,UAAU,yBAAyB+pB,UAAQ,6BAA/C,0BACGwzB,QADH,IACGA,OADH,EACGA,EAAW8B,+BADd,QACyC,cAAC,GAAD,CAAIU,SAAQ,OAAE/B,QAAF,IAAEA,OAAF,EAAEA,EAAkBqB,4BAEzE,oBAAIr/C,UAAU,wCAAwC+pB,UAAQ,SAA9D,SACE,cAAC,GAAD,CAAkB7H,OAAQA,MAE5B,qBAAIliB,UAAU,oCAAd,UACE,sBAAMsB,GAAK8+C,OAAqCt9C,EAArB,mBAA3B,SACE,cAACquB,GAAA,EAAD,CAAQpqB,SAAO,EAACuJ,KAAK,KAAKkJ,UAAW4mC,EAAep5C,QAAUo5C,EAA4BxmC,OAAZ9W,EAA9E,SACE,cAAC,IAAD,CAAiB+M,YAAU,EAAClO,KAAOy+C,EAAgChwC,IAAhBiwC,WAGrDD,GACA,eAAC72B,GAAA,EAAD,CAAqB3Q,OAAO,mBAAmB4Q,UAAU,OAAzD,gEAEE,uBAFF,+DAOJ,cAAC,GAAD,CACEnT,OAAQA,EACRxK,OAAQA,EACR+N,OAAQA,EACRvC,oBAAqBA,QC/DvBG,GAAU,CAAE,GAAI,SAAU,qBAAsB,uBAAwB,6BAA8B,GAAI,IAEnGnJ,GAAwC,SAAC,GAEhD,IAAD,EADD8I,EACC,EADDA,YAAagnC,EACZ,EADYA,YAAaF,EACzB,EADyBA,cAAe5mC,EACxC,EADwCA,oBAAqB6mC,EAC7D,EAD6DA,kBAAmBr9C,EAChF,EADgFA,eAE1DuW,EAAyD+mC,EAA1EN,gBAA0BG,EAAgDG,EAAhDH,iBAAkB/8C,EAA8Bk9C,EAA9Bl9C,QAAS0F,EAAqBw3C,EAArBx3C,MAAOylB,EAAc+xB,EAAd/xB,UAC9Dk0B,EAAwB,OAAGtC,QAAH,IAAGA,IAAH,UAAuB5mC,EAAQ/J,MAAK,qBAAGyxC,oBAAvC,aAAuB,EAA4CvB,UAMjG,GAJAz8C,qBAAU,WACRqW,MACC,IAEClW,EACF,OAAO,cAACqS,GAAA,EAAD,CAASrS,SAAO,IAoCzB,OACE,qCACE,cAAC,EAAD,CAAajB,UAAU,OAAOmY,SAAU8lC,IAlCtCt3C,EAEA,cAAC,GAAD,CAAQwM,KAAK,QAAb,SACE,cAAC,GAAD,CAAgBiZ,UAAWA,EAAWC,gBAAgB,+BAM1D,cAAClb,GAAA,EAAD,UACE,wBAAOnR,UAAU,yBAAjB,UACE,uBAAOA,UAAU,2BAAjB,SACE,6BAAKwX,GAAQrV,KAAI,SAACo+C,EAAQrxC,GAAT,OAAmB,6BAAiBqxC,GAARrxC,UAE/C,kCACGkI,EAAQpV,OAAS,GAAK,6BAAI,oBAAI4tB,QAASpY,GAAQxV,OAAQhC,UAAU,cAAvC,gCAC1BoX,EAAQjV,KAAI,SAACkU,GAAD,OACX,cAAC,GAAD,CAEEA,OAAQA,EACRgB,oBAAqBA,EACrB6mC,kBAAmBA,EACnBF,iBAAkBsC,EAClBz/C,eAAgBA,GALXwV,EAAOA,uBC9Bb/Q,GAlBS,SAACC,EAAgBC,GAEvCD,EAAOQ,eAAe,kBAAkB,kBAAM2sB,MAC9CntB,EAAOY,UAAU,iBAAkBX,EAAQ,CAAE,eAAiB,CAAE,iBAEhED,EAAOQ,eAAe,iBAAiB,kBAAMsI,MAC7C9I,EAAOY,UAAU,gBAAiBX,EAChC,CAAE,cAAe,kBACjB,CAAE,cAAe,gBAAiB,sBAAuB,uBAI3DD,EAAOQ,eAAe,cAAeoR,GAAa,wBAClD5R,EAAOQ,eAAe,iBAAiB,kBAAMk4C,MAC7C14C,EAAOQ,eAAe,sBAAuBsR,GAAqB,wBAClE9R,EAAOQ,eAAe,oBAAqBm4C,GAAmB,yBClBnDsC,GAAuB,yCACvBC,GAAmB,qCAKjB78B,OAAY,qBACxB48B,IAAuB,kBAAM,KADL,eAExBC,IAAmB,kBAAM,KAFD,KAFN,GAORC,GAAqB18B,GAAmBw8B,IAExCG,GAAiB38B,GAAmBy8B,I,oBCHpCG,GAA4C,SAAC,GAAqC,IAAnC/0C,EAAkC,EAAlCA,OAAQ+N,EAA0B,EAA1BA,OAAQinC,EAAkB,EAAlBA,YAAkB,EACvD59C,cADuD,mBACpF69C,EADoF,KACvEC,EADuE,KAO5F,OACE,eAACC,GAAA,EAAD,CAAOhhD,UAAU,oBAAoB6L,OAAQA,EAAQ+N,OAAQA,EAAQnY,IAAK0P,KAAYrR,MAAM,YAA5F,UACE,oBAAIE,UAAU,OAAd,6CACA,oBAAGA,UAAU,OAAb,kDAEE,eAACmxB,GAAA,EAAD,CAAQ3X,SAAUsnC,EAAY9gD,UAAU,OAAOF,MAAM,YAAYwQ,KAAK,KAAKtJ,QAVlE,WACb+5C,IACAF,KAQI,WACIC,GAAc,oDAAc,cAAC,IAAD,CAAiBn/C,KAAMs/C,IAAYjhD,UAAU,YAC1E8gD,GAAc,+D,SC5BZD,GAAW,uCAAG,wCAAAtsC,EAAA,gFACG2sC,UAAUC,qBADb,aACG,EAAyBC,mBAD5B,oJACkD,GADlD,QACnBC,EADmB,oBAGEA,GAHF,IAGzB,2BAAWC,EAA+B,QAGjC,QAFCC,EAAYD,EAAZC,eAED,IAAPA,KAASpkB,iBAAiB,eAAe,SAAC55B,GAAW,IAAD,EACb,eAAjC,UAACA,EAAMqV,cAAP,eAAuBhS,QACzBrC,OAAOC,SAASyC,YAKb,OAAPs6C,QAAO,IAAPA,KAASC,YAAY,CAAEruC,KAAM,iBAbN,0EAAH,qDCoETsuC,GAjDH,SACVx7C,EACAC,EACAG,EACAyvB,EACAyB,EACAukB,EACAvgB,EACAh1B,GARU,OASP,YAAgF,IAA7E2zB,EAA4E,EAA5EA,aAAcp4B,EAA8D,EAA9DA,QAASkjB,EAAqD,EAArDA,SAAU08B,EAA2C,EAA3CA,WAAYf,EAA+B,EAA/BA,eAE7CgB,EAA+B,MADpBl7C,eACO3B,SAWxB,OATAhE,qBAAU,WAAO,IAAD,IAEsB,IAAhCsb,OAAOC,KAAKva,GAASE,QACvBk4B,IAGF1nB,aAAmB,oBAACwS,EAAST,UAAV,aAAC,EAAa9R,aAAd,QAAuB,WACzC,IAGD,sBAAKzS,UAAU,gCAAf,UACE,cAACiG,EAAD,IAEA,sBAAKjG,UAAU,MAAf,UACE,qBAAKA,UAAWkC,IAAW,iBAAkB,CAAE,uCAAwCy/C,IAAvF,SACE,eAAC,KAAD,WACE,cAAC,KAAD,CAAOzyC,OAAK,EAACC,QAAS,cAACjJ,EAAD,MACtB,cAAC,KAAD,CAAO8B,KAAK,YAAYmH,QAAS,cAAC2sC,EAAD,MACjC,cAAC,KAAD,CAAO9zC,KAAK,kBAAkBmH,QAAS,cAACosB,EAAD,MACvC,cAAC,KAAD,CAAOvzB,KAAK,iBAAiBmH,QAAS,cAAC2mB,EAAD,MACtC,cAAC,KAAD,CAAO9tB,KAAK,yBAAyBmH,QAAS,cAACooB,EAAD,MAC9C,cAAC,KAAD,CAAOvvB,KAAK,sBAAsBmH,QAAS,cAAC9I,EAAD,MAC3C,cAAC,KAAD,CAAO2B,KAAK,IAAImH,QAAS,cAACjO,GAAA,EAAD,WAI7B,qBAAKlB,UAAU,gBAAf,SACE,cAACuG,EAAD,SAIJ,cAAC,GAAD,CAAiBsF,OAAQ61C,EAAY9nC,OAAQ+mC,EAAgBE,YAAaA,UCrCjEv7C,GArBS,SAACC,EAAgBC,GAEvCD,EAAOQ,eACL,MACA07C,GACA,aACA,OACA,aACA,eACA,aACA,WACA,gBACA,2BAEFl8C,EAAOY,UAAU,MAAOX,EAAQ,CAAE,UAAW,WAAY,cAAgB,CAAE,eAAgB,oBAG3FD,EAAOQ,eAAe,sBAAsB,kBAAM26C,MAClDn7C,EAAOQ,eAAe,kBAAkB,kBAAM46C,OCL1Cp7C,GAAS,IAAIq8C,IAEJC,GAAct8C,GAAds8C,UAITC,GAAmB,SAAC3/C,EAAoB4/C,GAArB,mBAAC,eACrB5/C,GADoB,kBAGtB4/C,EALiB,SAAwBF,EAAuBG,GAA/C,OAClB,kBAAqBH,EAAUG,GAAX,MAACH,EAAD,YAINI,CAAYJ,GAAWE,MAEjCv8C,GAA4B,SAAC08C,GAAD,IAAkCC,EAAlC,uDAAiE,GAAjE,OAChCC,YACEF,EAAiBtI,YAAKsI,GAAkB,KACxCC,EAAmBvoB,OAAOkoB,GAAkB,MAGhDO,GAAmB98C,GAAQC,IAC3B88C,YAAsB/8C,GAAQC,IAC9B+8C,EAAmBh9C,IACnBi9C,GAAyBj9C,GAAQC,IACjCi9C,GAAuBl9C,GAAQC,IAC/Bk9C,GAAoBn9C,GAAQC,IAC5Bm9C,GAAsBp9C,GAAQC,IAC9Bo9C,aAAqBr9C,IACrBs9C,GAAuBt9C,IACvBu9C,GAAwBv9C,GAAQC,IAChCu9C,GAAuBx9C,GAAQC,I,iCCvBhBw9C,gBAA6B,CAC1ClhD,QAASmhD,GACTpiD,eAAgBqiD,GAChBz+B,cAAe0+B,GACfr4B,uBAAwBs4B,GACxB52B,iBAAkB62B,GAClBjvB,gBAAiBkvB,GACjB5/B,eAAgB6/B,GAChBnS,UAAWoS,GACX//B,aAAcggC,GACdhS,gBAAiBiS,GACjBxvB,eAAgByvB,GAChBnjC,SAAUojC,GACV1M,UAAW2M,GACXtM,QAASuM,GACT5sC,YAAa6sC,GACb/+B,SAAUg/B,GACV7F,YAAa8F,GACbppB,eAAgBqpB,GAChBxC,WAAYyC,KCjCRC,GAA+C7/C,OAAe8/C,sCAAwCC,KAEtGC,GAAiC,CACrCC,OAAQ,CAAE,WAAY,WACtBC,UAAW,SACXC,mBAAoB,IACpBC,SAAU,KAENC,GCdmC,SAACh+C,GAAuD,IAAD,QAC9F,OAAKA,EAAMoe,UAK6C,iBAApD,UAACpe,EAAMoe,SAASjP,cAAhB,aAAC,EAAuByO,kBAC1B5d,EAAMoe,SAASjP,SAAWnP,EAAMoe,SAASjP,OAAOyO,gBAAkB,eAIpE5d,EAAMoe,SAASxO,KAAf,2BACK5P,EAAMoe,SAASxO,MADpB,IAEEoiC,YAAW,oBAAEhyC,EAAMoe,SAASxO,YAAjB,aAAE,EAAqBoiC,mBAAvB,kBAAuChyC,EAAMoe,SAAST,UAAtD,aAAsC,EAA4Bu4B,WAE/El2C,EAAMoe,SAAST,WAAc3d,EAAMoe,SAAST,GAAWu4B,SAEhDl2C,GAfEA,EDYYi+C,CAA0BC,gBAAKP,KAEzCQ,GAAQC,aAAYC,GAAUL,GAAgBR,GACzDc,aAAgBzuB,gBAAK8tB,IAAqBY,Q,kDEPtCC,GAAc5pC,QACW,cAA7BjX,OAAOC,SAAS6gD,UAEe,UAA7B9gD,OAAOC,SAAS6gD,UAEhB9gD,OAAOC,SAAS6gD,SAASl7C,MAAM,2DA0CnC,SAASm7C,GAAgBC,EAAela,GACtC6V,UAAUC,cACPqE,SAASD,GACThwC,MAAK,SAAC+rC,GACLA,EAAamE,cAAgB,WAC3B,IAAMC,EAAmBpE,EAAaqE,WACd,MAApBD,IAGJA,EAAiBE,cAAgB,WACA,cAA3BF,EAAiB9+C,QACfs6C,UAAUC,cAAc0E,YAI1BlgD,QAAQmgD,IACN,+GAKEza,GAAUA,EAAO0a,UACnB1a,EAAO0a,SAASzE,KAMlB37C,QAAQmgD,IAAI,sCAGRza,GAAUA,EAAO2a,WACnB3a,EAAO2a,UAAU1E,WAO5Bz0B,OAAM,SAAClmB,GACNhB,QAAQgB,MAAM,4CAA6CA,M,qBC7FvDs/C,KAAEC,KAAKC,QAAQC,UAAkBC,YAEzCJ,KAAEC,KAAKC,QAAQG,aAAa,CAC1BC,cAAeC,KACfC,QAASC,KACTC,UAAWC,O,ICIPnF,GAAuDI,GAAvDJ,IAAKz7C,GAAkD67C,GAAlD77C,YAAaQ,GAAqCq7C,GAArCr7C,aAAck6C,GAAuBmB,GAAvBnB,mBAExCmG,iBACE,cAAC,IAAD,CAAU9B,MAAOA,GAAjB,SACE,cAAC,IAAD,CAAe+B,SAAU3sB,IAAzB,SACE,cAAC3zB,GAAD,UACE,cAACR,GAAD,UACE,cAAC,GAAD,YAKRpC,SAASmjD,eAAe,SFFnB,SAAkB1b,GACvB,GAA6C,kBAAmB6V,UAAW,CAAC,IAAD,EAGzE,GADkB,IAAIz5C,IAAJ,UAAQu/C,uDAAR,EAAkC,GAAIziD,OAAOC,SAAS8G,MAC1D27C,SAAW1iD,OAAOC,SAASyiD,OAIvC,OAGF1iD,OAAO44B,iBAAiB,QAAQ,WAC9B,IAAMooB,EAAK,UAAMyB,sDAAN,sBAEP5B,KAgEV,SAAiCG,EAAela,GAE9C6b,MAAM3B,EAAO,CACX/tC,QAAS,CAAE,iBAAkB,YAE5BjC,MAAK,SAAC0W,GAEL,IAAMk7B,EAAcl7B,EAASzU,QAAQnQ,IAAI,gBAEnB,MAApB4kB,EAAS/J,QACO,MAAfilC,IAA8D,IAAvCA,EAAYC,QAAQ,cAG5ClG,UAAUC,cAAckG,MAAM9xC,MAAK,SAAC+rC,GAClCA,EAAagG,aAAa/xC,MAAK,WAC7BhR,OAAOC,SAASyC,eAKpBq+C,GAAgBC,EAAOla,MAG1Bxe,OAAM,WACLlnB,QAAQmgD,IAAI,oEAtFVyB,CAAwBhC,EAAOla,GAI/B6V,UAAUC,cAAckG,MAAM9xC,MAAK,WACjC5P,QAAQmgD,IACN,+GAMJR,GAAgBC,EAAOla,OEpB/Bmc,CAAsB,CACpBzB,SADoB,WAElBhB,GAAM92B,SAASyyB,U,6EChCNhqB,EAAmB,SAAC,GAAD,IAAGt1B,EAAH,EAAGA,SAAH,OAAkB,qBAAKpB,UAAU,+BAAf,SAA+CoB,M,gCCHjG,6IAiBaoQ,EAAe,SAACi2C,EAAD,GAAoF,IAAjDptB,EAAgD,EAAhDA,WAAY3oB,EAAoC,EAApCA,WACzE,IAAKhB,YAAS+2C,GACZ,OAAO,EAGT,IAAMC,GAAqBh2C,GAAci2C,kBAAQF,EAAgB/1C,EAAY,MAG7E,QAF2B2oB,GAAcstB,kBAAQF,EAAgBptB,EAAY,QAEjDqtB,GAGxBE,EAAuB7uB,YAAYjM,KAAU,SAAC5sB,GAClD,IACE,OAAOynD,kBAAQznD,EAASA,EAAS,KACjC,MAAOoD,GACP,OAAO,MAIE6H,EAAqB,SAACjL,GAAD,OAAsB0nD,EAAqB1nD,GAAtB,WAA+CA,GAAdA,GAE3EgL,EAAkB,eAAC28C,EAAD,uDAAwB,SAAxB,OAC7B,SAAC3nD,GAAD,OAA6B0nD,EAAqB1nD,GAAWA,EAAU2nD,K,2FCjClE,SAASzhD,EAA8B7F,GAC5C,OAAO,SAACE,GAKN,OAJAK,qBAAU,WACRL,EAAMw4B,wBACL,IAEI,cAAC14B,EAAD,eAAsBE,O,gCCZjC,oEAAO,IAAMkH,EAAU,SAAC,EAAsBH,EAAaJ,GAAsB,IAAvDxD,EAAsD,EAAtDA,SAClB22B,EAAO32B,EAASkkD,cAAc,KAEpCvtB,EAAK3nB,aAAa,OAAQpL,GAC1B+yB,EAAK3nB,aAAa,WAAYxL,GAC9BmzB,EAAKnhB,MAAM2uC,WAAa,SACxBnkD,EAAS4P,KAAKw0C,YAAYztB,GAC1BA,EAAK/B,QACL50B,EAAS4P,KAAKy0C,YAAY1tB,IAGfqD,EAAU,SAACr5B,EAAgBm5B,EAAat2B,GACnD,IAAM8gD,EAAO,IAAIC,KAAK,CAAEzqB,GAAO,CAAEvqB,KAAM,4BACjC3L,EAAMC,IAAIC,gBAAgBwgD,GAEhCvgD,EAAQpD,EAAQiD,EAAKJ,M","file":"static/js/main.1e59b24f.chunk.js","sourcesContent":["import { MAIN_COLOR } from '../../utils/theme';\n\nexport interface ShlinkLogoProps {\n color?: string;\n className?: string;\n}\n\nexport const ShlinkLogo = ({ color = MAIN_COLOR, className }: ShlinkLogoProps) => (\n <svg className={className} viewBox=\"0 0 512 512\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n <g fill={color}>\n <path\n d=\" M 23.71 85.08 C 17.22 49.81 49.44 14.86 85.08 18.12 C 118.83 19.21 145.72 53.33 139.45 86.37 C 155.64 102.30 171.32 118.83 187.87 134.36 C 198.32 111.73 208.84 89.12 219.57 66.62 C 226.05 53.84 243.47 48.74 255.73 56.27 C 263.76 62.10 270.34 69.69 277.25 76.75 C 286.28 86.61 285.72 102.89 276.31 112.31 C 223.38 165.37 170.38 218.37 117.35 271.34 C 107.72 280.99 91.01 281.25 81.11 271.86 C 74.39 264.94 66.82 258.69 61.24 250.77 C 53.72 238.52 58.85 221.07 71.64 214.62 C 94.11 203.87 116.72 193.38 139.33 182.91 C 123.81 166.36 107.30 150.68 91.37 134.49 C 60.20 140.28 27.37 116.78 23.71 85.08 Z\"\n />\n <path\n d=\" M 205.21 201.23 C 225.32 181.36 260.88 181.11 281.14 200.86 C 299.25 218.75 317.37 236.65 335.10 254.93 C 356.73 278.01 352.01 318.70 326.03 336.56 C 320.07 330.47 313.73 324.65 308.12 318.28 C 323.86 309.39 328.76 286.18 316.63 272.39 C 301.73 256.95 286.30 242.03 271.24 226.75 C 264.49 219.65 256.80 212.00 246.37 211.52 C 224.65 208.64 205.52 233.36 214.49 253.58 C 221.09 266.81 234.22 275.12 243.62 286.24 C 240.43 295.96 238.09 306.13 238.29 316.46 C 225.55 304.29 213.16 291.73 200.89 279.09 C 180.97 257.57 183.10 220.45 205.21 201.23 Z\"\n />\n <path\n d=\" M 273.90 352.07 C 252.28 328.99 256.98 288.31 282.96 270.46 C 288.93 276.54 295.26 282.36 300.88 288.72 C 285.14 297.62 280.23 320.82 292.38 334.61 C 307.27 350.05 322.70 364.96 337.75 380.25 C 344.51 387.35 352.20 395.00 362.64 395.48 C 384.35 398.37 403.49 373.64 394.51 353.42 C 387.92 340.18 374.78 331.88 365.38 320.76 C 368.56 311.04 370.91 300.86 370.71 290.54 C 383.45 302.70 395.84 315.27 408.11 327.91 C 428.03 349.43 425.90 386.55 403.78 405.77 C 383.68 425.64 348.13 425.89 327.86 406.14 C 309.75 388.25 291.60 370.37 273.90 352.07 Z\"\n />\n <path\n d=\" M 422.11 403.83 C 431.96 394.07 441.60 384.06 451.66 374.51 C 460.90 383.74 471.89 392.70 474.89 406.11 C 480.16 429.97 484.08 454.13 488.76 478.12 C 490.00 483.41 484.47 488.29 479.35 486.63 C 454.66 481.52 429.55 478.12 405.14 471.84 C 393.17 467.97 385.20 457.75 376.55 449.27 C 386.39 439.49 396.13 429.60 406.06 419.91 C 416.37 433.45 435.74 414.00 422.11 403.83 Z\"\n />\n </g>\n </svg>\n);\n","import { FC, useEffect } from 'react';\nimport { useParams } from 'react-router-dom';\nimport Message from '../../utils/Message';\nimport { isNotFoundServer, SelectedServer } from '../data';\nimport { NoMenuLayout } from '../../common/NoMenuLayout';\n\ninterface WithSelectedServerProps {\n selectServer: (serverId: string) => void;\n selectedServer: SelectedServer;\n}\n\nexport function withSelectedServer<T = {}>(WrappedComponent: FC<WithSelectedServerProps & T>, ServerError: FC) {\n return (props: WithSelectedServerProps & T) => {\n const params = useParams<{ serverId: string }>();\n const { selectServer, selectedServer } = props;\n\n useEffect(() => {\n params.serverId && selectServer(params.serverId);\n }, [ params.serverId ]);\n\n if (!selectedServer) {\n return (\n <NoMenuLayout>\n <Message loading />\n </NoMenuLayout>\n );\n }\n\n if (isNotFoundServer(selectedServer)) {\n return <ServerError />;\n }\n\n return <WrappedComponent {...props} />;\n };\n}\n","import { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport { SimpleCard } from '../utils/SimpleCard';\n\ninterface NotFoundProps {\n to?: string;\n}\n\nconst NotFound: FC<NotFoundProps> = ({ to = '/', children = 'Home' }) => (\n <div className=\"home\">\n <SimpleCard className=\"p-4\">\n <h2>Oops! We could not find requested route.</h2>\n <p>\n Use your browser's back button to navigate to the page you have previously come from, or just press this\n button.\n </p>\n <br />\n <Link to={to} className=\"btn btn-outline-primary btn-lg\">{children}</Link>\n </SimpleCard>\n </div>\n);\n\nexport default NotFound;\n","import { FC } from 'react';\nimport { ListGroup, ListGroupItem } from 'reactstrap';\nimport { Link } from 'react-router-dom';\nimport classNames from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronRight as chevronIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ServerWithId } from './data';\nimport './ServersListGroup.scss';\n\ninterface ServersListGroupProps {\n servers: ServerWithId[];\n embedded?: boolean;\n}\n\nconst ServerListItem = ({ id, name }: { id: string; name: string }) => (\n <ListGroupItem tag={Link} to={`/server/${id}`} className=\"servers-list__server-item\">\n {name}\n <FontAwesomeIcon icon={chevronIcon} className=\"servers-list__server-item-icon\" />\n </ListGroupItem>\n);\n\nconst ServersListGroup: FC<ServersListGroupProps> = ({ servers, children, embedded = false }) => (\n <>\n {children && <h5 className=\"mb-md-3\">{children}</h5>}\n {servers.length > 0 && (\n <ListGroup\n className={classNames('servers-list__list-group', { 'servers-list__list-group--embedded': embedded })}\n >\n {servers.map(({ id, name }) => <ServerListItem key={id} id={id} name={name} />)}\n </ListGroup>\n )}\n </>\n);\n\nexport default ServersListGroup;\n","import { useState, useRef, EffectCallback, DependencyList, useEffect } from 'react';\nimport { useSwipeable as useReactSwipeable } from 'react-swipeable';\nimport { useNavigate } from 'react-router-dom';\nimport { parseQuery, stringifyQuery } from './query';\n\nconst DEFAULT_DELAY = 2000;\n\nexport type StateFlagTimeout = (initialValue?: boolean, delay?: number) => [ boolean, () => void ];\n\nexport const useStateFlagTimeout = (\n setTimeout: (callback: Function, timeout: number) => number,\n clearTimeout: (timer: number) => void,\n): StateFlagTimeout => (initialValue = false, delay = DEFAULT_DELAY) => {\n const [ flag, setFlag ] = useState<boolean>(initialValue);\n const timeout = useRef<number | undefined>(undefined);\n const callback = () => {\n setFlag(!initialValue);\n\n if (timeout.current) {\n clearTimeout(timeout.current);\n }\n\n timeout.current = setTimeout(() => setFlag(initialValue), delay);\n };\n\n return [ flag, callback ];\n};\n\ntype ToggleResult = [ boolean, () => void, () => void, () => void ];\n\nexport const useToggle = (initialValue = false): ToggleResult => {\n const [ flag, setFlag ] = useState<boolean>(initialValue);\n\n return [ flag, () => setFlag(!flag), () => setFlag(true), () => setFlag(false) ];\n};\n\nexport const useSwipeable = (showSidebar: () => void, hideSidebar: () => void) => {\n const swipeMenuIfNoModalExists = (callback: () => void) => (e: any) => {\n const swippedOnVisitsTable = (e.event.composedPath() as HTMLElement[]).some( // eslint-disable-line @typescript-eslint/no-unsafe-call\n ({ classList }) => classList?.contains('visits-table'),\n );\n\n if (swippedOnVisitsTable || document.querySelector('.modal')) {\n return;\n }\n\n callback();\n };\n\n return useReactSwipeable({\n delta: 40,\n onSwipedLeft: swipeMenuIfNoModalExists(hideSidebar),\n onSwipedRight: swipeMenuIfNoModalExists(showSidebar),\n });\n};\n\nexport const useQueryState = <T>(paramName: string, initialState: T): [ T, (newValue: T) => void ] => {\n const [ value, setValue ] = useState(initialState);\n const setValueWithLocation = (value: T) => {\n const { location, history } = window;\n const query = parseQuery<any>(location.search);\n\n query[paramName] = value;\n history.pushState(null, '', `${location.pathname}?${stringifyQuery(query)}`);\n setValue(value);\n };\n\n return [ value, setValueWithLocation ];\n};\n\nexport const useEffectExceptFirstTime = (callback: EffectCallback, deps: DependencyList): void => {\n const isFirstLoad = useRef(true);\n\n useEffect(() => {\n !isFirstLoad.current && callback();\n isFirstLoad.current = false;\n }, deps);\n};\n\nexport const useGoBack = () => {\n const navigate = useNavigate();\n\n return () => navigate(-1);\n};\n","import axios from 'axios';\nimport Bottle from 'bottlejs';\nimport ScrollToTop from '../ScrollToTop';\nimport MainHeader from '../MainHeader';\nimport Home from '../Home';\nimport MenuLayout from '../MenuLayout';\nimport AsideMenu from '../AsideMenu';\nimport ErrorHandler from '../ErrorHandler';\nimport ShlinkVersionsContainer from '../ShlinkVersionsContainer';\nimport { ConnectDecorator } from '../../container/types';\nimport { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';\nimport { ImageDownloader } from './ImageDownloader';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Services\n bottle.constant('window', (global as any).window);\n bottle.constant('console', global.console);\n bottle.constant('axios', axios);\n\n bottle.service('ImageDownloader', ImageDownloader, 'axios', 'window');\n\n // Components\n bottle.serviceFactory('ScrollToTop', ScrollToTop);\n\n bottle.serviceFactory('MainHeader', MainHeader, 'ServersDropdown');\n\n bottle.serviceFactory('Home', () => Home);\n bottle.decorator('Home', withoutSelectedServer);\n bottle.decorator('Home', connect([ 'servers' ], [ 'resetSelectedServer' ]));\n\n bottle.serviceFactory(\n 'MenuLayout',\n MenuLayout,\n 'TagsList',\n 'ShortUrlsList',\n 'AsideMenu',\n 'CreateShortUrl',\n 'ShortUrlVisits',\n 'TagVisits',\n 'OrphanVisits',\n 'NonOrphanVisits',\n 'ServerError',\n 'Overview',\n 'EditShortUrl',\n 'ManageDomains',\n );\n bottle.decorator('MenuLayout', connect([ 'selectedServer' ], [ 'selectServer' ]));\n\n bottle.serviceFactory('AsideMenu', AsideMenu, 'DeleteServerButton');\n\n bottle.serviceFactory('ShlinkVersionsContainer', () => ShlinkVersionsContainer);\n bottle.decorator('ShlinkVersionsContainer', connect([ 'selectedServer' ]));\n\n bottle.serviceFactory('ErrorHandler', ErrorHandler, 'window', 'console');\n};\n\nexport default provideServices;\n","import { FC, useEffect } from 'react';\nimport { useLocation } from 'react-router-dom';\n\nconst ScrollToTop = (): FC => ({ children }) => {\n const location = useLocation();\n\n useEffect(() => {\n scrollTo(0, 0);\n }, [ location ]);\n\n return <>{children}</>;\n};\n\nexport default ScrollToTop;\n","import { Component, ReactNode } from 'react';\nimport { Button } from 'reactstrap';\nimport { SimpleCard } from '../utils/SimpleCard';\n\ninterface ErrorHandlerState {\n hasError: boolean;\n}\n\nconst ErrorHandler = (\n { location }: Window,\n { error }: Console,\n) => class ErrorHandler extends Component<any, ErrorHandlerState> {\n public constructor(props: object) {\n super(props);\n this.state = { hasError: false };\n }\n\n public static getDerivedStateFromError(): ErrorHandlerState {\n return { hasError: true };\n }\n\n public componentDidCatch(e: Error): void {\n if (process.env.NODE_ENV !== 'development') {\n error(e);\n }\n }\n\n public render(): ReactNode {\n if (this.state.hasError) {\n return (\n <div className=\"home\">\n <SimpleCard className=\"p-4\">\n <h1>Oops! This is awkward :S</h1>\n <p>It seems that something went wrong. Try refreshing the page or just click this button.</p>\n <br />\n <Button outline color=\"primary\" onClick={() => location.reload()}>Take me back</Button>\n </SimpleCard>\n </div>\n );\n }\n\n return this.props.children;\n }\n};\n\nexport default ErrorHandler;\n","import { AxiosInstance } from 'axios';\nimport { saveUrl } from '../../utils/helpers/files';\n\nexport class ImageDownloader {\n public constructor(private readonly axios: AxiosInstance, private readonly window: Window) {}\n\n public async saveImage(imgUrl: string, filename: string): Promise<void> {\n const { data } = await this.axios.get(imgUrl, { responseType: 'blob' });\n const url = URL.createObjectURL(data);\n\n saveUrl(this.window, url, filename);\n }\n}\n","import Bottle from 'bottlejs';\nimport { useStateFlagTimeout } from '../helpers/hooks';\nimport LocalStorage from './LocalStorage';\nimport ColorGenerator from './ColorGenerator';\n\nconst provideServices = (bottle: Bottle) => {\n bottle.constant('localStorage', (global as any).localStorage);\n bottle.service('Storage', LocalStorage, 'localStorage');\n bottle.service('ColorGenerator', ColorGenerator, 'Storage');\n\n bottle.constant('setTimeout', global.setTimeout);\n bottle.constant('clearTimeout', global.clearTimeout);\n bottle.serviceFactory('useStateFlagTimeout', useStateFlagTimeout, 'setTimeout', 'clearTimeout');\n};\n\nexport default provideServices;\n","const PREFIX = 'shlink';\nconst buildPath = (path: string) => `${PREFIX}.${path}`;\n\nexport default class LocalStorage {\n public constructor(private readonly localStorage: Storage) {}\n\n public readonly get = <T>(key: string): T | undefined => {\n const item = this.localStorage.getItem(buildPath(key));\n\n return item ? JSON.parse(item) as T : undefined;\n };\n\n public readonly set = (key: string, value: any) => this.localStorage.setItem(buildPath(key), JSON.stringify(value));\n}\n","import { isNil } from 'ramda';\nimport { rangeOf } from '../utils';\nimport LocalStorage from './LocalStorage';\n\nconst HEX_COLOR_LENGTH = 6;\nconst HEX_DIGITS = '0123456789ABCDEF';\nconst LIGHTNESS_BREAKPOINT = 128;\n\nconst { floor, random, sqrt, round } = Math;\nconst buildRandomColor = () =>\n `#${rangeOf(HEX_COLOR_LENGTH, () => HEX_DIGITS[floor(random() * HEX_DIGITS.length)]).join('')}`;\nconst normalizeKey = (key: string) => key.toLowerCase().trim();\nconst hexColorToRgbArray = (colorHex: string): number[] =>\n (colorHex.match(/../g) ?? []).map((hex) => parseInt(hex, 16) || 0);\n// HSP by Darel Rex Finley https://alienryderflex.com/hsp.html\nconst perceivedLightness = (r = 0, g = 0, b = 0) => round(sqrt(0.299 * r ** 2 + 0.587 * g ** 2 + 0.114 * b ** 2));\n\nexport default class ColorGenerator {\n private readonly colors: Record<string, string>;\n private readonly lights: Record<string, boolean>;\n\n public constructor(private readonly storage: LocalStorage) {\n this.colors = this.storage.get<Record<string, string>>('colors') ?? {};\n this.lights = {};\n }\n\n public readonly getColorForKey = (key: string) => {\n const normalizedKey = normalizeKey(key);\n const color = this.colors[normalizedKey];\n\n // If a color has not been set yet, generate a random one and save it\n if (!color) {\n return this.setColorForKey(normalizedKey, buildRandomColor());\n }\n\n return color;\n };\n\n public readonly setColorForKey = (key: string, color: string) => {\n const normalizedKey = normalizeKey(key);\n\n this.colors[normalizedKey] = color;\n this.storage.set('colors', this.colors);\n\n return color;\n };\n\n public readonly isColorLightForKey = (key: string): boolean => {\n const colorHex = this.getColorForKey(key).substring(1);\n\n if (isNil(this.lights[colorHex])) {\n const rgb = hexColorToRgbArray(colorHex);\n\n this.lights[colorHex] = perceivedLightness(...rgb) >= LIGHTNESS_BREAKPOINT;\n }\n\n return this.lights[colorHex];\n };\n}\n","import { omit } from 'ramda';\nimport { SemVer } from '../../utils/helpers/version';\n\nexport interface ServerData {\n name: string;\n url: string;\n apiKey: string;\n}\n\nexport interface ServerWithId extends ServerData {\n id: string;\n autoConnect?: boolean;\n}\n\nexport interface ReachableServer extends ServerWithId {\n version: SemVer;\n printableVersion: string;\n}\n\nexport interface NonReachableServer extends ServerWithId {\n serverNotReachable: true;\n}\n\nexport interface NotFoundServer {\n serverNotFound: true;\n}\n\nexport type RegularServer = ReachableServer | NonReachableServer;\n\nexport type SelectedServer = RegularServer | NotFoundServer | null;\n\nexport type ServersMap = Record<string, ServerWithId>;\n\nexport const hasServerData = (server: SelectedServer | ServerData): server is ServerData =>\n !!(server as ServerData)?.url && !!(server as ServerData)?.apiKey;\n\nexport const isServerWithId = (server: SelectedServer | ServerWithId): server is ServerWithId =>\n !!server?.hasOwnProperty('id');\n\nexport const isReachableServer = (server: SelectedServer): server is ReachableServer =>\n !!server?.hasOwnProperty('version');\n\nexport const isNotFoundServer = (server: SelectedServer): server is NotFoundServer =>\n !!server?.hasOwnProperty('serverNotFound');\n\nexport const getServerId = (server: SelectedServer) => isServerWithId(server) ? server.id : '';\n\nexport const serverWithIdToServerData = (server: ServerWithId): ServerData =>\n omit<ServerWithId, 'id' | 'autoConnect'>([ 'id', 'autoConnect' ], server);\n","import { pipe } from 'ramda';\nimport { ExternalLink } from 'react-external-link';\nimport { versionToPrintable, versionToSemVer } from '../utils/helpers/version';\nimport { isReachableServer } from '../servers/data';\nimport { ShlinkVersionsContainerProps } from './ShlinkVersionsContainer';\n\nconst SHLINK_WEB_CLIENT_VERSION = '%_VERSION_%';\nconst normalizeVersion = pipe(versionToSemVer(), versionToPrintable);\n\nexport interface ShlinkVersionsProps extends ShlinkVersionsContainerProps {\n clientVersion?: string;\n}\n\nconst VersionLink = ({ project, version }: { project: 'shlink' | 'shlink-web-client'; version: string }) => (\n <ExternalLink href={`https://github.com/shlinkio/${project}/releases/${version}`} className=\"text-muted\">\n <b>{version}</b>\n </ExternalLink>\n);\n\nconst ShlinkVersions = ({ selectedServer, clientVersion = SHLINK_WEB_CLIENT_VERSION }: ShlinkVersionsProps) => {\n const normalizedClientVersion = normalizeVersion(clientVersion);\n\n return (\n <small className=\"text-muted\">\n {isReachableServer(selectedServer) &&\n <>Server: <VersionLink project=\"shlink\" version={selectedServer.printableVersion} /> - </>\n }\n Client: <VersionLink project=\"shlink-web-client\" version={normalizedClientVersion} />\n </small>\n );\n};\n\nexport default ShlinkVersions;\n","import classNames from 'classnames';\nimport { isReachableServer, SelectedServer } from '../servers/data';\nimport ShlinkVersions from './ShlinkVersions';\nimport './ShlinkVersionsContainer.scss';\n\nexport interface ShlinkVersionsContainerProps {\n selectedServer: SelectedServer;\n}\n\nconst ShlinkVersionsContainer = ({ selectedServer }: ShlinkVersionsContainerProps) => {\n const classes = classNames('text-center', {\n 'shlink-versions-container--with-server': isReachableServer(selectedServer),\n });\n\n return (\n <div className={classes}>\n <ShlinkVersions selectedServer={selectedServer} />\n </div>\n );\n};\n\nexport default ShlinkVersionsContainer;\n","import { faChevronDown as arrowIcon, faCogs as cogsIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { FC, useEffect } from 'react';\nimport { Link, useLocation } from 'react-router-dom';\nimport { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';\nimport classNames from 'classnames';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { ShlinkLogo } from './img/ShlinkLogo';\nimport './MainHeader.scss';\n\nconst MainHeader = (ServersDropdown: FC) => () => {\n const [ isOpen, toggleOpen, , close ] = useToggle();\n const location = useLocation();\n const { pathname } = location;\n\n useEffect(close, [ location ]);\n\n const settingsPath = '/settings';\n const toggleClass = classNames('main-header__toggle-icon', { 'main-header__toggle-icon--opened': isOpen });\n\n return (\n <Navbar color=\"primary\" dark fixed=\"top\" className=\"main-header\" expand=\"md\">\n <NavbarBrand tag={Link} to=\"/\">\n <ShlinkLogo className=\"main-header__brand-logo\" color=\"white\" /> Shlink\n </NavbarBrand>\n\n <NavbarToggler onClick={toggleOpen}>\n <FontAwesomeIcon icon={arrowIcon} className={toggleClass} />\n </NavbarToggler>\n\n <Collapse navbar isOpen={isOpen}>\n <Nav navbar className=\"ml-auto\">\n <NavItem>\n <NavLink tag={Link} to={settingsPath} active={pathname === settingsPath}>\n <FontAwesomeIcon icon={cogsIcon} /> Settings\n </NavLink>\n </NavItem>\n <ServersDropdown />\n </Nav>\n </Collapse>\n </Navbar>\n );\n};\n\nexport default MainHeader;\n","import { useEffect } from 'react';\nimport { isEmpty, values } from 'ramda';\nimport { Link, useNavigate } from 'react-router-dom';\nimport { Card, Row } from 'reactstrap';\nimport { ExternalLink } from 'react-external-link';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faExternalLinkAlt, faPlus } from '@fortawesome/free-solid-svg-icons';\nimport ServersListGroup from '../servers/ServersListGroup';\nimport { ServersMap } from '../servers/data';\nimport { ShlinkLogo } from './img/ShlinkLogo';\nimport './Home.scss';\n\nexport interface HomeProps {\n servers: ServersMap;\n}\n\nconst Home = ({ servers }: HomeProps) => {\n const navigate = useNavigate();\n const serversList = values(servers);\n const hasServers = !isEmpty(serversList);\n\n useEffect(() => {\n // Try to redirect to the first server marked as auto-connect\n const autoConnectServer = serversList.find(({ autoConnect }) => autoConnect);\n\n autoConnectServer && navigate(`/server/${autoConnectServer.id}`);\n }, []);\n\n return (\n <div className=\"home\">\n <Card className=\"home__main-card\">\n <Row noGutters>\n <div className=\"col-md-5 d-none d-md-block\">\n <div className=\"home__logo-wrapper\">\n <div className=\"home__logo\">\n <ShlinkLogo />\n </div>\n </div>\n </div>\n <div className=\"col-md-7 home__servers-container\">\n <div className=\"home__title-wrapper\">\n <h1 className=\"home__title\">Welcome!</h1>\n </div>\n <ServersListGroup embedded servers={serversList}>\n {!hasServers && (\n <div className=\"p-4 text-center\">\n <p className=\"mb-5\">This application will help you manage your Shlink servers.</p>\n <p>\n <Link to=\"/server/create\" className=\"btn btn-outline-primary btn-lg mr-2\">\n <FontAwesomeIcon icon={faPlus} /> <span className=\"ml-1\">Add a server</span>\n </Link>\n </p>\n <p className=\"mb-0 mt-5\">\n <ExternalLink href=\"https://shlink.io/documentation\">\n <small>\n <span className=\"mr-1\">Learn more about Shlink</span> <FontAwesomeIcon icon={faExternalLinkAlt} />\n </small>\n </ExternalLink>\n </p>\n </div>\n )}\n </ServersListGroup>\n </div>\n </Row>\n </Card>\n </div>\n );\n};\n\nexport default Home;\n","import { FC, useEffect } from 'react';\nimport { Navigate, Route, Routes, useLocation } from 'react-router-dom';\nimport { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport classNames from 'classnames';\nimport { withSelectedServer } from '../servers/helpers/withSelectedServer';\nimport { useSwipeable, useToggle } from '../utils/helpers/hooks';\nimport { supportsDomainRedirects, supportsNonOrphanVisits, supportsOrphanVisits } from '../utils/helpers/features';\nimport { isReachableServer } from '../servers/data';\nimport NotFound from './NotFound';\nimport { AsideMenuProps } from './AsideMenu';\nimport './MenuLayout.scss';\n\nconst MenuLayout = (\n TagsList: FC,\n ShortUrlsList: FC,\n AsideMenu: FC<AsideMenuProps>,\n CreateShortUrl: FC,\n ShortUrlVisits: FC,\n TagVisits: FC,\n OrphanVisits: FC,\n NonOrphanVisits: FC,\n ServerError: FC,\n Overview: FC,\n EditShortUrl: FC,\n ManageDomains: FC,\n) => withSelectedServer(({ selectedServer }) => {\n const location = useLocation();\n const [ sidebarVisible, toggleSidebar, showSidebar, hideSidebar ] = useToggle();\n\n useEffect(() => hideSidebar(), [ location ]);\n\n if (!isReachableServer(selectedServer)) {\n return <ServerError />;\n }\n\n const addOrphanVisitsRoute = supportsOrphanVisits(selectedServer);\n const addNonOrphanVisitsRoute = supportsNonOrphanVisits(selectedServer);\n const addManageDomainsRoute = supportsDomainRedirects(selectedServer);\n const burgerClasses = classNames('menu-layout__burger-icon', { 'menu-layout__burger-icon--active': sidebarVisible });\n const swipeableProps = useSwipeable(showSidebar, hideSidebar);\n\n return (\n <>\n <FontAwesomeIcon icon={burgerIcon} className={burgerClasses} onClick={toggleSidebar} />\n\n <div {...swipeableProps} className=\"menu-layout__swipeable\">\n <div className=\"menu-layout__swipeable-inner\">\n <AsideMenu selectedServer={selectedServer} showOnMobile={sidebarVisible} />\n <div className=\"menu-layout__container\" onClick={() => hideSidebar()}>\n <div className=\"container-xl\">\n <Routes>\n <Route index element={<Navigate replace to=\"overview\" />} />\n <Route path=\"/overview\" element={<Overview />} />\n <Route path=\"/list-short-urls/:page\" element={<ShortUrlsList />} />\n <Route path=\"/create-short-url\" element={<CreateShortUrl />} />\n <Route path=\"/short-code/:shortCode/visits/*\" element={<ShortUrlVisits />} />\n <Route path=\"/short-code/:shortCode/edit\" element={<EditShortUrl />} />\n <Route path=\"/tag/:tag/visits/*\" element={<TagVisits />} />\n {addOrphanVisitsRoute && <Route path=\"/orphan-visits/*\" element={<OrphanVisits />} />}\n {addNonOrphanVisitsRoute && <Route path=\"/non-orphan-visits/*\" element={<NonOrphanVisits />} />}\n <Route path=\"/manage-tags\" element={<TagsList />} />\n {addManageDomainsRoute && <Route path=\"/manage-domains\" element={<ManageDomains />} />}\n <Route\n path=\"*\"\n element={<NotFound to={`/server/${selectedServer.id}/list-short-urls/1`}>List short URLs</NotFound>}\n />\n </Routes>\n </div>\n </div>\n </div>\n </div>\n </>\n );\n}, ServerError);\n\nexport default MenuLayout;\n","import {\n faList as listIcon,\n faLink as createIcon,\n faTags as tagsIcon,\n faPen as editIcon,\n faHome as overviewIcon,\n faGlobe as domainsIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { FC } from 'react';\nimport { NavLink, NavLinkProps, useLocation } from 'react-router-dom';\nimport classNames from 'classnames';\nimport { DeleteServerButtonProps } from '../servers/DeleteServerButton';\nimport { isServerWithId, SelectedServer } from '../servers/data';\nimport { supportsDomainRedirects } from '../utils/helpers/features';\nimport './AsideMenu.scss';\n\nexport interface AsideMenuProps {\n selectedServer: SelectedServer;\n className?: string;\n showOnMobile?: boolean;\n}\n\ninterface AsideMenuItemProps extends NavLinkProps {\n to: string;\n}\n\nconst AsideMenuItem: FC<AsideMenuItemProps> = ({ children, to, className, ...rest }) => (\n <NavLink\n className={({ isActive }) => classNames('aside-menu__item', className, { 'aside-menu__item--selected': isActive })}\n to={to}\n {...rest}\n >\n {children}\n </NavLink>\n);\n\nconst AsideMenu = (DeleteServerButton: FC<DeleteServerButtonProps>) => (\n { selectedServer, showOnMobile = false }: AsideMenuProps,\n) => {\n const hasId = isServerWithId(selectedServer);\n const serverId = hasId ? selectedServer.id : '';\n const { pathname } = useLocation();\n const addManageDomainsLink = supportsDomainRedirects(selectedServer);\n const asideClass = classNames('aside-menu', {\n 'aside-menu--hidden': !showOnMobile,\n });\n const buildPath = (suffix: string) => `/server/${serverId}${suffix}`;\n\n return (\n <aside className={asideClass}>\n <nav className=\"nav flex-column aside-menu__nav\">\n <AsideMenuItem to={buildPath('/overview')}>\n <FontAwesomeIcon fixedWidth icon={overviewIcon} />\n <span className=\"aside-menu__item-text\">Overview</span>\n </AsideMenuItem>\n <AsideMenuItem\n to={buildPath('/list-short-urls/1')}\n className={classNames({ 'aside-menu__item--selected': pathname.match('/list-short-urls') !== null })}\n >\n <FontAwesomeIcon fixedWidth icon={listIcon} />\n <span className=\"aside-menu__item-text\">List short URLs</span>\n </AsideMenuItem>\n <AsideMenuItem to={buildPath('/create-short-url')}>\n <FontAwesomeIcon fixedWidth icon={createIcon} flip=\"horizontal\" />\n <span className=\"aside-menu__item-text\">Create short URL</span>\n </AsideMenuItem>\n <AsideMenuItem to={buildPath('/manage-tags')}>\n <FontAwesomeIcon fixedWidth icon={tagsIcon} />\n <span className=\"aside-menu__item-text\">Manage tags</span>\n </AsideMenuItem>\n {addManageDomainsLink && (\n <AsideMenuItem to={buildPath('/manage-domains')}>\n <FontAwesomeIcon fixedWidth icon={domainsIcon} />\n <span className=\"aside-menu__item-text\">Manage domains</span>\n </AsideMenuItem>\n )}\n <AsideMenuItem to={buildPath('/edit')} className=\"aside-menu__item--push\">\n <FontAwesomeIcon fixedWidth icon={editIcon} />\n <span className=\"aside-menu__item-text\">Edit this server</span>\n </AsideMenuItem>\n {hasId && (\n <DeleteServerButton\n className=\"aside-menu__item aside-menu__item--danger\"\n textClassName=\"aside-menu__item-text\"\n server={selectedServer}\n />\n )}\n </nav>\n </aside>\n );\n};\n\nexport default AsideMenu;\n","import { isEmpty, isNil, pipe, range } from 'ramda';\nimport { SyntheticEvent } from 'react';\n\nexport const rangeOf = <T>(size: number, mappingFn: (value: number) => T, startAt = 1): T[] =>\n range(startAt, size + 1).map(mappingFn);\n\nexport type Empty = null | undefined | '' | never[];\n\nexport const hasValue = <T>(value: T | Empty): value is T => !isNil(value) && !isEmpty(value);\n\nexport const handleEventPreventingDefault = <T>(handler: () => T) => pipe(\n (e: SyntheticEvent) => e.preventDefault(),\n handler,\n);\n\nexport type Nullable<T> = {\n [P in keyof T]: T[P] | null\n};\n\ntype Optional<T> = T | null | undefined;\n\nexport type OptionalString = Optional<string>;\n\nexport type RecursivePartial<T> = {\n [P in keyof T]?: RecursivePartial<T[P]>;\n};\n\nexport const nonEmptyValueOrNull = <T>(value: T): T | null => isEmpty(value) ? null : value;\n\nexport const capitalize = <T extends string>(value: T): string => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;\n","import { CardProps } from 'reactstrap/lib/Card';\nimport { Card, CardBody, CardHeader } from 'reactstrap';\nimport { ReactNode } from 'react';\n\ninterface SimpleCardProps extends Omit<CardProps, 'title'> {\n title?: ReactNode;\n bodyClassName?: string;\n}\n\nexport const SimpleCard = ({ title, children, bodyClassName, ...rest }: SimpleCardProps) => (\n <Card {...rest}>\n {title && <CardHeader>{title}</CardHeader>}\n <CardBody className={bodyClassName}>{children}</CardBody>\n </Card>\n);\n","import { isReachableServer, SelectedServer } from '../../servers/data';\nimport { versionMatch, Versions } from './version';\n\nconst serverMatchesVersions = (versions: Versions) => (selectedServer: SelectedServer): boolean =>\n isReachableServer(selectedServer) && versionMatch(selectedServer.version, versions);\n\nexport const supportsQrCodeSizeInQuery = serverMatchesVersions({ minVersion: '2.5.0' });\n\nexport const supportsShortUrlTitle = serverMatchesVersions({ minVersion: '2.6.0' });\n\nexport const supportsOrphanVisits = supportsShortUrlTitle;\n\nexport const supportsQrCodeMargin = supportsShortUrlTitle;\n\nexport const supportsTagsInPatch = supportsShortUrlTitle;\n\nexport const supportsBotVisits = serverMatchesVersions({ minVersion: '2.7.0' });\n\nexport const supportsCrawlableVisits = supportsBotVisits;\n\nexport const supportsQrErrorCorrection = serverMatchesVersions({ minVersion: '2.8.0' });\n\nexport const supportsDomainRedirects = supportsQrErrorCorrection;\n\nexport const supportsForwardQuery = serverMatchesVersions({ minVersion: '2.9.0' });\n\nexport const supportsDefaultDomainRedirectsEdition = serverMatchesVersions({ minVersion: '2.10.0' });\n\nexport const supportsNonOrphanVisits = serverMatchesVersions({ minVersion: '3.0.0' });\n","export const MAIN_COLOR = '#4696e5';\n\nexport const MAIN_COLOR_ALPHA = 'rgba(70, 150, 229, 0.4)';\n\nexport const HIGHLIGHTED_COLOR = '#f77f28';\n\nexport const HIGHLIGHTED_COLOR_ALPHA = 'rgba(247, 127, 40, 0.4)';\n\nexport const PRIMARY_LIGHT_COLOR = 'white';\n\nexport const PRIMARY_DARK_COLOR = '#161b22';\n\nexport type Theme = 'dark' | 'light';\n\nexport const changeThemeInMarkup = (theme: Theme) => {\n const html = document.getElementsByTagName('html');\n\n html?.[0]?.setAttribute('data-theme', theme);\n};\n\nexport const isDarkThemeEnabled = (): boolean => {\n const html = document.getElementsByTagName('html');\n\n return html?.[0]?.getAttribute('data-theme') === 'dark';\n};\n","import qs from 'qs';\n\nexport const parseQuery = <T>(search: string) => qs.parse(search, { ignoreQueryPrefix: true }) as unknown as T;\n\nexport const stringifyQuery = (query: any): string => qs.stringify(query, { arrayFormat: 'brackets' });\n","import { FC } from 'react';\nimport { Card, Row } from 'reactstrap';\nimport classNames from 'classnames';\nimport { faCircleNotch as preloader } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\n\ntype MessageType = 'default' | 'error';\n\nconst getClassForType = (type: MessageType) => {\n const map: Record<MessageType, string> = {\n error: 'border-danger',\n default: '',\n };\n\n return map[type];\n};\nconst getTextClassForType = (type: MessageType) => {\n const map: Record<MessageType, string> = {\n error: 'text-danger',\n default: 'text-muted',\n };\n\n return map[type];\n};\n\nexport interface MessageProps {\n className?: string;\n loading?: boolean;\n fullWidth?: boolean;\n type?: MessageType;\n}\n\nconst Message: FC<MessageProps> = ({ className, children, loading = false, type = 'default', fullWidth = false }) => {\n const classes = classNames({\n 'col-md-12': fullWidth,\n 'col-md-10 offset-md-1': !fullWidth,\n });\n\n return (\n <Row noGutters className={className}>\n <div className={classes}>\n <Card className={getClassForType(type)} body>\n <h3 className={classNames('text-center mb-0', getTextClassForType(type))}>\n {loading && <FontAwesomeIcon icon={preloader} spin />}\n {loading && <span className=\"ml-2\">{children ?? 'Loading...'}</span>}\n {!loading && children}\n </h3>\n </Card>\n </div>\n </Row>\n );\n};\n\nexport default Message;\n","import { useState } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faSearch as searchIcon } from '@fortawesome/free-solid-svg-icons';\nimport classNames from 'classnames';\nimport './SearchField.scss';\n\nconst DEFAULT_SEARCH_INTERVAL = 500;\nlet timer: NodeJS.Timeout | null;\n\ninterface SearchFieldProps {\n onChange: (value: string) => void;\n className?: string;\n large?: boolean;\n noBorder?: boolean;\n initialValue?: string;\n}\n\nconst SearchField = ({ onChange, className, large = true, noBorder = false, initialValue = '' }: SearchFieldProps) => {\n const [ searchTerm, setSearchTerm ] = useState(initialValue);\n\n const resetTimer = () => {\n timer && clearTimeout(timer);\n timer = null;\n };\n const searchTermChanged = (newSearchTerm: string, timeout = DEFAULT_SEARCH_INTERVAL) => {\n setSearchTerm(newSearchTerm);\n\n resetTimer();\n\n timer = setTimeout(() => {\n onChange(newSearchTerm);\n resetTimer();\n }, timeout);\n };\n\n return (\n <div className={classNames('search-field', className)}>\n <input\n type=\"text\"\n className={classNames('form-control search-field__input', {\n 'form-control-lg': large,\n 'search-field__input--no-border': noBorder,\n })}\n placeholder=\"Search...\"\n value={searchTerm}\n onChange={(e) => searchTermChanged(e.target.value)}\n />\n <FontAwesomeIcon icon={searchIcon} className=\"search-field__icon\" />\n <div\n className=\"close search-field__close\"\n hidden={searchTerm === ''}\n id=\"search-field__close\"\n onClick={() => searchTermChanged('', 0)}\n >\n ×\n </div>\n </div>\n );\n};\n\nexport default SearchField;\n","export type OrderDir = 'ASC' | 'DESC' | undefined;\n\nexport interface Order<Fields> {\n field?: Fields;\n dir?: OrderDir;\n}\n\nexport const determineOrderDir = <T extends string = string>(\n currentField: T,\n newField?: T,\n currentOrderDir?: OrderDir,\n): OrderDir => {\n if (currentField !== newField) {\n return 'ASC';\n }\n\n const newOrderMap: Record<'ASC' | 'DESC', OrderDir> = {\n ASC: 'DESC',\n DESC: undefined,\n };\n\n return currentOrderDir ? newOrderMap[currentOrderDir] : 'ASC';\n};\n\nexport const sortList = <List>(list: List[], { field, dir }: Order<Partial<keyof List>>) => !field || !dir\n ? list\n : list.sort((a, b) => {\n const greaterThan = dir === 'ASC' ? 1 : -1;\n const smallerThan = dir === 'ASC' ? -1 : 1;\n\n return a[field] > b[field] ? greaterThan : smallerThan;\n });\n\nexport const orderToString = <T>(order: Order<T>): string | undefined =>\n order.dir ? `${order.field}-${order.dir}` : undefined;\n\nexport const stringToOrder = <T>(order: string): Order<T> => {\n const [ field, dir ] = order.split('-') as [ T | undefined, OrderDir | undefined ];\n\n return { field, dir };\n};\n","import { isEmpty, isNil, reject } from 'ramda';\nimport { AxiosInstance, AxiosResponse, Method } from 'axios';\nimport { ShortUrl, ShortUrlData } from '../../short-urls/data';\nimport { OptionalString } from '../../utils/utils';\nimport {\n ShlinkHealth,\n ShlinkMercureInfo,\n ShlinkShortUrlsResponse,\n ShlinkTags,\n ShlinkTagsResponse,\n ShlinkVisits,\n ShlinkVisitsParams,\n ShlinkShortUrlData,\n ShlinkDomainsResponse,\n ShlinkVisitsOverview,\n ShlinkEditDomainRedirects,\n ShlinkDomainRedirects,\n ShlinkShortUrlsListParams,\n ShlinkShortUrlsListNormalizedParams,\n} from '../types';\nimport { stringifyQuery } from '../../utils/helpers/query';\nimport { orderToString } from '../../utils/helpers/ordering';\n\nconst buildShlinkBaseUrl = (url: string) => url ? `${url}/rest/v2` : '';\nconst rejectNilProps = reject(isNil);\nconst normalizeOrderByInParams = (params: ShlinkShortUrlsListParams): ShlinkShortUrlsListNormalizedParams => {\n const { orderBy = {}, ...rest } = params;\n\n return { ...rest, orderBy: orderToString(orderBy) };\n};\n\nexport default class ShlinkApiClient {\n public constructor(\n private readonly axios: AxiosInstance,\n private readonly baseUrl: string,\n private readonly apiKey: string,\n ) {\n }\n\n public readonly listShortUrls = async (params: ShlinkShortUrlsListParams = {}): Promise<ShlinkShortUrlsResponse> =>\n this.performRequest<{ shortUrls: ShlinkShortUrlsResponse }>('/short-urls', 'GET', normalizeOrderByInParams(params))\n .then(({ data }) => data.shortUrls);\n\n public readonly createShortUrl = async (options: ShortUrlData): Promise<ShortUrl> => {\n const filteredOptions = reject((value) => isEmpty(value) || isNil(value), options as any);\n\n return this.performRequest<ShortUrl>('/short-urls', 'POST', {}, filteredOptions)\n .then((resp) => resp.data);\n };\n\n public readonly getShortUrlVisits = async (shortCode: string, query?: ShlinkVisitsParams): Promise<ShlinkVisits> =>\n this.performRequest<{ visits: ShlinkVisits }>(`/short-urls/${shortCode}/visits`, 'GET', query)\n .then(({ data }) => data.visits);\n\n public readonly getTagVisits = async (tag: string, query?: Omit<ShlinkVisitsParams, 'domain'>): Promise<ShlinkVisits> =>\n this.performRequest<{ visits: ShlinkVisits }>(`/tags/${tag}/visits`, 'GET', query)\n .then(({ data }) => data.visits);\n\n public readonly getOrphanVisits = async (query?: Omit<ShlinkVisitsParams, 'domain'>): Promise<ShlinkVisits> =>\n this.performRequest<{ visits: ShlinkVisits }>('/visits/orphan', 'GET', query)\n .then(({ data }) => data.visits);\n\n public readonly getNonOrphanVisits = async (query?: Omit<ShlinkVisitsParams, 'domain'>): Promise<ShlinkVisits> =>\n this.performRequest<{ visits: ShlinkVisits }>('/visits/non-orphan', 'GET', query)\n .then(({ data }) => data.visits);\n\n public readonly getVisitsOverview = async (): Promise<ShlinkVisitsOverview> =>\n this.performRequest<{ visits: ShlinkVisitsOverview }>('/visits', 'GET')\n .then(({ data }) => data.visits);\n\n public readonly getShortUrl = async (shortCode: string, domain?: OptionalString): Promise<ShortUrl> =>\n this.performRequest<ShortUrl>(`/short-urls/${shortCode}`, 'GET', { domain })\n .then(({ data }) => data);\n\n public readonly deleteShortUrl = async (shortCode: string, domain?: OptionalString): Promise<void> =>\n this.performRequest(`/short-urls/${shortCode}`, 'DELETE', { domain })\n .then(() => {});\n\n // eslint-disable-next-line valid-jsdoc\n /**\n * @deprecated. If using Shlink 2.6.0 or greater, use updateShortUrl instead\n */\n public readonly updateShortUrlTags = async (\n shortCode: string,\n domain: OptionalString,\n tags: string[],\n ): Promise<string[]> =>\n this.performRequest<{ tags: string[] }>(`/short-urls/${shortCode}/tags`, 'PUT', { domain }, { tags })\n .then(({ data }) => data.tags);\n\n public readonly updateShortUrl = async (\n shortCode: string,\n domain: OptionalString,\n data: ShlinkShortUrlData,\n ): Promise<ShortUrl> =>\n this.performRequest<ShortUrl>(`/short-urls/${shortCode}`, 'PATCH', { domain }, data)\n .then(({ data }) => data);\n\n public readonly listTags = async (): Promise<ShlinkTags> =>\n this.performRequest<{ tags: ShlinkTagsResponse }>('/tags', 'GET', { withStats: 'true' })\n .then((resp) => resp.data.tags)\n .then(({ data, stats }) => ({ tags: data, stats }));\n\n public readonly deleteTags = async (tags: string[]): Promise<{ tags: string[] }> =>\n this.performRequest('/tags', 'DELETE', { tags })\n .then(() => ({ tags }));\n\n public readonly editTag = async (oldName: string, newName: string): Promise<{ oldName: string; newName: string }> =>\n this.performRequest('/tags', 'PUT', {}, { oldName, newName })\n .then(() => ({ oldName, newName }));\n\n public readonly health = async (): Promise<ShlinkHealth> =>\n this.performRequest<ShlinkHealth>('/health', 'GET')\n .then((resp) => resp.data);\n\n public readonly mercureInfo = async (): Promise<ShlinkMercureInfo> =>\n this.performRequest<ShlinkMercureInfo>('/mercure-info', 'GET')\n .then((resp) => resp.data);\n\n public readonly listDomains = async (): Promise<ShlinkDomainsResponse> =>\n this.performRequest<{ domains: ShlinkDomainsResponse }>('/domains', 'GET').then(({ data }) => data.domains);\n\n public readonly editDomainRedirects = async (\n domainRedirects: ShlinkEditDomainRedirects,\n ): Promise<ShlinkDomainRedirects> =>\n this.performRequest<ShlinkDomainRedirects>('/domains/redirects', 'PATCH', {}, domainRedirects).then(({ data }) => data);\n\n private readonly performRequest = async <T>(url: string, method: Method = 'GET', query = {}, body = {}): Promise<AxiosResponse<T>> =>\n this.axios({\n method,\n url: `${buildShlinkBaseUrl(this.baseUrl)}${url}`,\n headers: { 'X-Api-Key': this.apiKey },\n params: rejectNilProps(query),\n data: body,\n paramsSerializer: stringifyQuery,\n });\n}\n","import { AxiosInstance } from 'axios';\nimport { prop } from 'ramda';\nimport { hasServerData, SelectedServer, ServerWithId } from '../../servers/data';\nimport { GetState } from '../../container/types';\nimport ShlinkApiClient from './ShlinkApiClient';\n\nconst apiClients: Record<string, ShlinkApiClient> = {};\n\nconst isGetState = (getStateOrSelectedServer: GetState | ServerWithId): getStateOrSelectedServer is GetState =>\n typeof getStateOrSelectedServer === 'function';\nconst getSelectedServerFromState = (getState: GetState): SelectedServer => prop('selectedServer', getState());\n\nexport type ShlinkApiClientBuilder = (getStateOrSelectedServer: GetState | ServerWithId) => ShlinkApiClient;\n\nconst buildShlinkApiClient = (axios: AxiosInstance): ShlinkApiClientBuilder => (\n getStateOrSelectedServer: GetState | ServerWithId,\n) => {\n const server = isGetState(getStateOrSelectedServer)\n ? getSelectedServerFromState(getStateOrSelectedServer)\n : getStateOrSelectedServer;\n\n if (!hasServerData(server)) {\n throw new Error('There\\'s no selected server or it is not found');\n }\n\n const { url, apiKey } = server;\n const clientKey = `${url}_${apiKey}`;\n\n if (!apiClients[clientKey]) {\n apiClients[clientKey] = new ShlinkApiClient(axios, url, apiKey);\n }\n\n return apiClients[clientKey];\n};\n\nexport default buildShlinkApiClient;\n","import Bottle from 'bottlejs';\nimport buildShlinkApiClient from './ShlinkApiClientBuilder';\n\nconst provideServices = (bottle: Bottle) => {\n bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'axios');\n};\n\nexport default provideServices;\n","import { FC, MouseEventHandler } from 'react';\nimport classNames from 'classnames';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport './Tag.scss';\n\ninterface TagProps {\n colorGenerator: ColorGenerator;\n text: string;\n className?: string;\n clearable?: boolean;\n onClick?: MouseEventHandler;\n onClose?: MouseEventHandler;\n}\n\nconst Tag: FC<TagProps> = ({ text, children, clearable, className = '', colorGenerator, onClick, onClose }) => (\n <span\n className={classNames('badge tag', className, { 'tag--light-bg': colorGenerator.isColorLightForKey(text) })}\n style={{ backgroundColor: colorGenerator.getColorForKey(text), cursor: clearable || !onClick ? 'auto' : 'pointer' }}\n onClick={onClick}\n >\n {children ?? text}\n {clearable && <span className=\"close tag__close-selected-tag\" onClick={onClose}>×</span>}\n </span>\n);\n\nexport default Tag;\n","import { FC } from 'react';\nimport { Dropdown, DropdownMenu, DropdownToggle } from 'reactstrap';\nimport { useToggle } from './helpers/hooks';\nimport './DropdownBtn.scss';\n\nexport interface DropdownBtnProps {\n text: string;\n disabled?: boolean;\n className?: string;\n dropdownClassName?: string;\n right?: boolean;\n minWidth?: number;\n}\n\nexport const DropdownBtn: FC<DropdownBtnProps> = (\n { text, disabled = false, className = '', children, dropdownClassName, right = false, minWidth },\n) => {\n const [ isOpen, toggle ] = useToggle();\n const toggleClasses = `dropdown-btn__toggle btn-block ${className}`;\n const style = { minWidth: minWidth && `${minWidth}px` };\n\n return (\n <Dropdown isOpen={isOpen} toggle={toggle} disabled={disabled} className={dropdownClassName}>\n <DropdownToggle caret className={toggleClasses} color=\"primary\">{text}</DropdownToggle>\n <DropdownMenu className=\"w-100\" right={right} style={style}>{children}</DropdownMenu>\n </Dropdown>\n );\n};\n","import { format, formatISO, isBefore, isEqual, isWithinInterval, parse, parseISO as stdParseISO } from 'date-fns';\nimport { OptionalString } from '../utils';\n\nexport type DateOrString = Date | string;\n\ntype NullableDate = DateOrString | null;\n\nexport const isDateObject = (date: DateOrString): date is Date => typeof date !== 'string';\n\nconst formatDateFromFormat = (date?: NullableDate, theFormat?: string): OptionalString => {\n if (!date || !isDateObject(date)) {\n return date;\n }\n\n return theFormat ? format(date, theFormat) : formatISO(date);\n};\n\nexport const formatDate = (format = 'yyyy-MM-dd') => (date?: NullableDate) => formatDateFromFormat(date, format);\n\nexport const formatIsoDate = (date?: NullableDate) => formatDateFromFormat(date, undefined);\n\nexport const formatInternational = formatDate();\n\nexport const parseDate = (date: string, format: string) => parse(date, format, new Date());\n\nexport const parseISO = (date: DateOrString): Date => isDateObject(date) ? date : stdParseISO(date);\n\nexport const isBetween = (date: DateOrString, start?: DateOrString, end?: DateOrString): boolean => {\n try {\n return isWithinInterval(parseISO(date), { start: parseISO(start ?? date), end: parseISO(end ?? date) });\n } catch (e) {\n return false;\n }\n};\n\nexport const isBeforeOrEqual = (date: Date | number, dateToCompare: Date | number) =>\n isEqual(date, dateToCompare) || isBefore(date, dateToCompare);\n","import { subDays, startOfDay, endOfDay } from 'date-fns';\nimport { cond, filter, isEmpty, T } from 'ramda';\nimport { DateOrString, formatInternational, isBeforeOrEqual, parseISO } from '../../helpers/date';\n\nexport interface DateRange {\n startDate?: Date | null;\n endDate?: Date | null;\n}\n\nexport type DateInterval = 'all' | 'today' | 'yesterday' | 'last7Days' | 'last30Days' | 'last90Days' | 'last180Days' | 'last365Days';\n\nexport const dateRangeIsEmpty = (dateRange?: DateRange): boolean => dateRange === undefined\n || isEmpty(filter(Boolean, dateRange as any));\n\nexport const rangeIsInterval = (range?: DateRange | DateInterval): range is DateInterval =>\n typeof range === 'string';\n\nconst INTERVAL_TO_STRING_MAP: Record<DateInterval, string | undefined> = {\n today: 'Today',\n yesterday: 'Yesterday',\n last7Days: 'Last 7 days',\n last30Days: 'Last 30 days',\n last90Days: 'Last 90 days',\n last180Days: 'Last 180 days',\n last365Days: 'Last 365 days',\n all: undefined,\n};\n\nexport const DATE_INTERVALS = Object.keys(INTERVAL_TO_STRING_MAP).filter((value) => value !== 'all') as DateInterval[];\n\nconst dateRangeToString = (range?: DateRange): string | undefined => {\n if (!range || dateRangeIsEmpty(range)) {\n return undefined;\n }\n\n if (range.startDate && !range.endDate) {\n return `Since ${formatInternational(range.startDate)}`;\n }\n\n if (!range.startDate && range.endDate) {\n return `Until ${formatInternational(range.endDate)}`;\n }\n\n return `${formatInternational(range.startDate)} - ${formatInternational(range.endDate)}`;\n};\n\nexport const rangeOrIntervalToString = (range?: DateRange | DateInterval): string | undefined => {\n if (!range || range === 'all') {\n return undefined;\n }\n\n if (!rangeIsInterval(range)) {\n return dateRangeToString(range);\n }\n\n return INTERVAL_TO_STRING_MAP[range];\n};\n\nconst startOfDaysAgo = (daysAgo: number) => startOfDay(subDays(new Date(), daysAgo));\nconst endingToday = (startDate: Date): DateRange => ({ startDate, endDate: endOfDay(new Date()) });\n\nexport const intervalToDateRange = (dateInterval?: DateInterval): DateRange => {\n if (!dateInterval || dateInterval === 'all') {\n return {};\n }\n\n switch (dateInterval) {\n case 'today':\n return endingToday(startOfDay(new Date()));\n case 'yesterday':\n return { startDate: startOfDaysAgo(1), endDate: endOfDay(subDays(new Date(), 1)) };\n case 'last7Days':\n return endingToday(startOfDaysAgo(7));\n case 'last30Days':\n return endingToday(startOfDaysAgo(30));\n case 'last90Days':\n return endingToday(startOfDaysAgo(90));\n case 'last180Days':\n return endingToday(startOfDaysAgo(180));\n case 'last365Days':\n return endingToday(startOfDaysAgo(365));\n }\n\n return {};\n};\n\nexport const dateToMatchingInterval = (date: DateOrString): DateInterval => {\n const theDate: Date = parseISO(date);\n\n return cond<never, DateInterval>([\n [ () => isBeforeOrEqual(startOfDay(new Date()), theDate), () => 'today' ],\n [ () => isBeforeOrEqual(startOfDaysAgo(1), theDate), () => 'yesterday' ],\n [ () => isBeforeOrEqual(startOfDaysAgo(7), theDate), () => 'last7Days' ],\n [ () => isBeforeOrEqual(startOfDaysAgo(30), theDate), () => 'last30Days' ],\n [ () => isBeforeOrEqual(startOfDaysAgo(90), theDate), () => 'last90Days' ],\n [ () => isBeforeOrEqual(startOfDaysAgo(180), theDate), () => 'last180Days' ],\n [ () => isBeforeOrEqual(startOfDaysAgo(365), theDate), () => 'last365Days' ],\n [ T, () => 'all' ],\n ])();\n};\n","import { useRef } from 'react';\nimport { isNil } from 'ramda';\nimport DatePicker, { ReactDatePickerProps } from 'react-datepicker';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faCalendarAlt as calendarIcon } from '@fortawesome/free-regular-svg-icons';\nimport classNames from 'classnames';\nimport './DateInput.scss';\n\nexport type DateInputProps = ReactDatePickerProps;\n\nconst DateInput = (props: DateInputProps) => {\n const { className, isClearable, selected } = props;\n const showCalendarIcon = !isClearable || isNil(selected);\n const ref = useRef<{ input: HTMLInputElement }>();\n\n return (\n <div className=\"date-input-container\">\n <DatePicker\n {...props}\n dateFormat=\"yyyy-MM-dd\"\n className={classNames('date-input-container__input form-control', className)}\n // @ts-expect-error The DatePicker type definition is wrong. It has a ref prop\n ref={ref}\n />\n {showCalendarIcon && (\n <FontAwesomeIcon\n icon={calendarIcon}\n className=\"date-input-container__icon\"\n onClick={() => ref.current?.input.focus()}\n />\n )}\n </div>\n );\n};\n\nexport default DateInput;\n","import DateInput from '../DateInput';\nimport { DateRange } from './types';\n\ninterface DateRangeRowProps extends DateRange {\n onStartDateChange: (date: Date | null) => void;\n onEndDateChange: (date: Date | null) => void;\n disabled?: boolean;\n}\n\nconst DateRangeRow = (\n { startDate = null, endDate = null, disabled = false, onStartDateChange, onEndDateChange }: DateRangeRowProps,\n) => (\n <div className=\"row\">\n <div className=\"col-md-6\">\n <DateInput\n selected={startDate}\n placeholderText=\"Since...\"\n isClearable\n maxDate={endDate ?? undefined}\n disabled={disabled}\n onChange={onStartDateChange}\n />\n </div>\n <div className=\"col-md-6\">\n <DateInput\n className=\"mt-2 mt-md-0\"\n selected={endDate}\n placeholderText=\"Until...\"\n isClearable\n minDate={startDate ?? undefined}\n disabled={disabled}\n onChange={onEndDateChange}\n />\n </div>\n </div>\n);\n\nexport default DateRangeRow;\n","import { DropdownItem } from 'reactstrap';\nimport { FC } from 'react';\nimport { DATE_INTERVALS, DateInterval, rangeOrIntervalToString } from './types';\n\nexport interface DateIntervalDropdownProps {\n active?: DateInterval;\n allText: string;\n onChange: (interval: DateInterval) => void;\n}\n\nexport const DateIntervalDropdownItems: FC<DateIntervalDropdownProps> = ({ active, allText, onChange }) => (\n <>\n <DropdownItem active={active === 'all'} onClick={() => onChange('all')}>\n {allText}\n </DropdownItem>\n <DropdownItem divider />\n {DATE_INTERVALS.map(\n (interval) => (\n <DropdownItem key={interval} active={active === interval} onClick={() => onChange(interval)}>\n {rangeOrIntervalToString(interval)}\n </DropdownItem>\n ),\n )}\n </>\n);\n","import { useState } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { DropdownBtn } from '../DropdownBtn';\nimport { useEffectExceptFirstTime } from '../helpers/hooks';\nimport {\n DateInterval,\n DateRange,\n rangeOrIntervalToString,\n intervalToDateRange,\n rangeIsInterval,\n dateRangeIsEmpty,\n} from './types';\nimport DateRangeRow from './DateRangeRow';\nimport { DateIntervalDropdownItems } from './DateIntervalDropdownItems';\n\nexport interface DateRangeSelectorProps {\n initialDateRange?: DateInterval | DateRange;\n disabled?: boolean;\n onDatesChange: (dateRange: DateRange) => void;\n defaultText: string;\n updatable?: boolean;\n}\n\nexport const DateRangeSelector = (\n { onDatesChange, initialDateRange, defaultText, disabled, updatable = false }: DateRangeSelectorProps,\n) => {\n const initialIntervalIsRange = rangeIsInterval(initialDateRange);\n const [ activeInterval, setActiveInterval ] = useState(initialIntervalIsRange ? initialDateRange : undefined);\n const [ activeDateRange, setActiveDateRange ] = useState(initialIntervalIsRange ? undefined : initialDateRange);\n\n const updateDateRange = (dateRange: DateRange) => {\n setActiveInterval(dateRangeIsEmpty(dateRange) ? 'all' : undefined);\n setActiveDateRange(dateRange);\n onDatesChange(dateRange);\n };\n const updateInterval = (dateInterval: DateInterval) => {\n setActiveInterval(dateInterval);\n setActiveDateRange(undefined);\n onDatesChange(intervalToDateRange(dateInterval));\n };\n\n updatable && useEffectExceptFirstTime(() => {\n const isDateInterval = rangeIsInterval(initialDateRange);\n\n isDateInterval && updateInterval(initialDateRange);\n initialDateRange && !isDateInterval && updateDateRange(initialDateRange);\n }, [ initialDateRange ]);\n\n return (\n <DropdownBtn disabled={disabled} text={rangeOrIntervalToString(activeInterval ?? activeDateRange) ?? defaultText}>\n <DateIntervalDropdownItems allText={defaultText} active={activeInterval} onChange={updateInterval} />\n <DropdownItem divider />\n <DropdownItem header>Custom:</DropdownItem>\n <DropdownItem text>\n <DateRangeRow\n {...activeDateRange}\n onStartDateChange={(startDate) => updateDateRange({ ...activeDateRange, startDate })}\n onEndDateChange={(endDate) => updateDateRange({ ...activeDateRange, endDate })}\n />\n </DropdownItem>\n </DropdownBtn>\n );\n};\n","import { useParams, useLocation, useNavigate } from 'react-router-dom';\nimport { useMemo } from 'react';\nimport { isEmpty, pipe } from 'ramda';\nimport { parseQuery, stringifyQuery } from '../../utils/helpers/query';\nimport { ShortUrlsOrder, ShortUrlsOrderableFields } from '../data';\nimport { orderToString, stringToOrder } from '../../utils/helpers/ordering';\n\ntype ToFirstPage = (extra: Partial<ShortUrlsFiltering>) => void;\n\nexport interface ShortUrlListRouteParams {\n page: string;\n serverId: string;\n}\n\ninterface ShortUrlsQueryCommon {\n tags?: string;\n search?: string;\n startDate?: string;\n endDate?: string;\n}\n\ninterface ShortUrlsQuery extends ShortUrlsQueryCommon {\n orderBy?: string;\n}\n\ninterface ShortUrlsFiltering extends ShortUrlsQueryCommon {\n orderBy?: ShortUrlsOrder;\n}\n\nexport const useShortUrlsQuery = (): [ShortUrlsFiltering, ToFirstPage] => {\n const navigate = useNavigate();\n const location = useLocation();\n const params = useParams<{ serverId: string }>();\n\n const query = useMemo(\n pipe(\n () => parseQuery<ShortUrlsQuery>(location.search),\n ({ orderBy, ...rest }: ShortUrlsQuery): ShortUrlsFiltering => !orderBy ? rest : {\n ...rest,\n orderBy: stringToOrder<ShortUrlsOrderableFields>(orderBy),\n },\n ),\n [ location.search ],\n );\n const toFirstPageWithExtra = (extra: Partial<ShortUrlsFiltering>) => {\n const { orderBy, ...mergedQuery } = { ...query, ...extra };\n const normalizedQuery: ShortUrlsQuery = { ...mergedQuery, orderBy: orderBy && orderToString(orderBy) };\n const evolvedQuery = stringifyQuery(normalizedQuery);\n const queryString = isEmpty(evolvedQuery) ? '' : `?${evolvedQuery}`;\n\n navigate(`/server/${params.serverId}/list-short-urls/1${queryString}`);\n };\n\n return [ query, toFirstPageWithExtra ];\n};\n","import { faTags as tagsIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { isEmpty, pipe } from 'ramda';\nimport { parseISO } from 'date-fns';\nimport SearchField from '../utils/SearchField';\nimport Tag from '../tags/helpers/Tag';\nimport { DateRangeSelector } from '../utils/dates/DateRangeSelector';\nimport { formatIsoDate } from '../utils/helpers/date';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport { DateRange } from '../utils/dates/types';\nimport { useShortUrlsQuery } from './helpers/hooks';\nimport './ShortUrlsFilteringBar.scss';\n\nconst dateOrNull = (date?: string) => date ? parseISO(date) : null;\n\nconst ShortUrlsFilteringBar = (colorGenerator: ColorGenerator) => () => {\n const [{ search, tags, startDate, endDate }, toFirstPage ] = useShortUrlsQuery();\n const selectedTags = tags?.split(',') ?? [];\n const setDates = pipe(\n ({ startDate, endDate }: DateRange) => ({\n startDate: formatIsoDate(startDate) ?? undefined,\n endDate: formatIsoDate(endDate) ?? undefined,\n }),\n toFirstPage,\n );\n const setSearch = pipe(\n (searchTerm: string) => isEmpty(searchTerm) ? undefined : searchTerm,\n (search) => toFirstPage({ search }),\n );\n const removeTag = pipe(\n (tag: string) => selectedTags.filter((selectedTag) => selectedTag !== tag),\n (tagsList) => tagsList.length === 0 ? undefined : tagsList.join(','),\n (tags) => toFirstPage({ tags }),\n );\n\n return (\n <div className=\"short-urls-filtering-bar-container\">\n <SearchField initialValue={search} onChange={setSearch} />\n\n <div className=\"mt-3\">\n <div className=\"row\">\n <div className=\"col-lg-8 offset-lg-4 col-xl-6 offset-xl-6\">\n <DateRangeSelector\n defaultText=\"All short URLs\"\n initialDateRange={{\n startDate: dateOrNull(startDate),\n endDate: dateOrNull(endDate),\n }}\n onDatesChange={setDates}\n />\n </div>\n </div>\n </div>\n\n {selectedTags.length > 0 && (\n <h4 className=\"short-urls-filtering-bar__selected-tag mt-3\">\n <FontAwesomeIcon icon={tagsIcon} className=\"short-urls-filtering-bar__tags-icon\" />\n \n {selectedTags.map((tag) =>\n <Tag colorGenerator={colorGenerator} key={tag} text={tag} clearable onClose={() => removeTag(tag)} />)}\n </h4>\n )}\n </div>\n );\n};\n\nexport default ShortUrlsFilteringBar;\n","import { UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';\nimport { toPairs } from 'ramda';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faSortAmountUp as sortAscIcon, faSortAmountDown as sortDescIcon } from '@fortawesome/free-solid-svg-icons';\nimport classNames from 'classnames';\nimport { determineOrderDir, Order, OrderDir } from './helpers/ordering';\nimport './OrderingDropdown.scss';\n\nexport interface OrderingDropdownProps<T extends string = string> {\n items: Record<T, string>;\n order: Order<T>;\n onChange: (orderField?: T, orderDir?: OrderDir) => void;\n isButton?: boolean;\n right?: boolean;\n}\n\nexport function OrderingDropdown<T extends string = string>(\n { items, order, onChange, isButton = true, right = false }: OrderingDropdownProps<T>,\n) {\n const handleItemClick = (fieldKey: T) => () => {\n const newOrderDir = determineOrderDir(fieldKey, order.field, order.dir);\n\n onChange(newOrderDir ? fieldKey : undefined, newOrderDir);\n };\n\n return (\n <UncontrolledDropdown>\n <DropdownToggle\n caret\n color={isButton ? 'primary' : 'link'}\n className={classNames({ 'dropdown-btn__toggle btn-block': isButton, 'btn-sm p-0': !isButton })}\n >\n {!isButton && <>Order by</>}\n {isButton && !order.field && <>Order by...</>}\n {isButton && order.field && `Order by: \"${items[order.field]}\" - \"${order.dir ?? 'DESC'}\"`}\n </DropdownToggle>\n <DropdownMenu\n right={right}\n className={classNames('w-100', { 'ordering-dropdown__menu--link': !isButton })}\n >\n {toPairs(items).map(([ fieldKey, fieldValue ]) => (\n <DropdownItem key={fieldKey} active={order.field === fieldKey} onClick={handleItemClick(fieldKey as T)}>\n {fieldValue}\n {order.field === fieldKey && (\n <FontAwesomeIcon\n icon={order.dir === 'ASC' ? sortAscIcon : sortDescIcon}\n className=\"ordering-dropdown__sort-icon\"\n />\n )}\n </DropdownItem>\n ))}\n <DropdownItem divider />\n <DropdownItem disabled={!order.field} onClick={() => onChange()}>\n <i>Clear selection</i>\n </DropdownItem>\n </DropdownMenu>\n </UncontrolledDropdown>\n );\n}\n","import { FC, useEffect } from 'react';\nimport { pipe } from 'ramda';\nimport { useParams } from 'react-router-dom';\nimport { CreateVisit } from '../../visits/types';\nimport { MercureInfo } from '../reducers/mercureInfo';\nimport { bindToMercureTopic } from './index';\n\nexport interface MercureBoundProps {\n createNewVisits: (createdVisits: CreateVisit[]) => void;\n loadMercureInfo: () => void;\n mercureInfo: MercureInfo;\n}\n\nexport function boundToMercureHub<T = {}>(\n WrappedComponent: FC<MercureBoundProps & T>,\n getTopicsForProps: (props: T, routeParams: any) => string[],\n) {\n const pendingUpdates = new Set<CreateVisit>();\n\n return (props: MercureBoundProps & T) => {\n const { createNewVisits, loadMercureInfo, mercureInfo } = props;\n const { interval } = mercureInfo;\n const params = useParams();\n\n useEffect(() => {\n const onMessage = (visit: CreateVisit) => interval ? pendingUpdates.add(visit) : createNewVisits([ visit ]);\n const topics = getTopicsForProps(props, params);\n const closeEventSource = bindToMercureTopic(mercureInfo, topics, onMessage, loadMercureInfo);\n\n if (!interval) {\n return closeEventSource;\n }\n\n const timer = setInterval(() => {\n createNewVisits([ ...pendingUpdates ]);\n pendingUpdates.clear();\n }, interval * 1000 * 60);\n\n return pipe(() => clearInterval(timer), () => closeEventSource?.());\n }, [ mercureInfo ]);\n\n return <WrappedComponent {...props} />;\n };\n}\n","import { EventSourcePolyfill as EventSource } from 'event-source-polyfill';\nimport { MercureInfo } from '../reducers/mercureInfo';\n\nexport const bindToMercureTopic = <T>(mercureInfo: MercureInfo, topics: string[], onMessage: (message: T) => void, onTokenExpired: () => void) => { // eslint-disable-line max-len\n const { mercureHubUrl, token, loading, error } = mercureInfo;\n\n if (loading || error || !mercureHubUrl) {\n return undefined;\n }\n\n const onEventSourceMessage = ({ data }: { data: string }) => onMessage(JSON.parse(data) as T);\n const onEventSourceError = ({ status }: { status: number }) => status === 401 && onTokenExpired();\n\n const subscriptions = topics.map((topic) => {\n const hubUrl = new URL(mercureHubUrl);\n\n hubUrl.searchParams.append('topic', topic);\n const es = new EventSource(hubUrl, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n es.onmessage = onEventSourceMessage;\n es.onerror = onEventSourceError;\n\n return es;\n });\n\n return () => subscriptions.forEach((es) => es.close());\n};\n","export class Topics {\n public static readonly visits = 'https://shlink.io/new-visit';\n\n public static readonly orphanVisits = 'https://shlink.io/new-orphan-visit';\n\n public static readonly shortUrlVisits = (shortCode: string) => `https://shlink.io/new-visit/${shortCode}`;\n}\n","import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faCaretDown as caretDownIcon, faCaretUp as caretUpIcon } from '@fortawesome/free-solid-svg-icons';\nimport { Order } from '../helpers/ordering';\n\ninterface TableOrderIconProps<T> {\n currentOrder: Order<T>;\n field: T;\n className?: string;\n}\n\nexport function TableOrderIcon<T extends string = string>(\n { currentOrder, field, className = 'ml-1' }: TableOrderIconProps<T>,\n) {\n if (!currentOrder.dir || currentOrder.field !== field) {\n return null;\n }\n\n return <FontAwesomeIcon icon={currentOrder.dir === 'ASC' ? caretUpIcon : caretDownIcon} className={className} />;\n}\n","import { isEmpty, propEq, values } from 'ramda';\nimport { useState, useEffect, useMemo, FC, useRef } from 'react';\nimport { Button, Card, Nav, NavLink, Progress, Row } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faCalendarAlt, faMapMarkedAlt, faList, faChartPie, faFileDownload } from '@fortawesome/free-solid-svg-icons';\nimport { IconDefinition } from '@fortawesome/fontawesome-common-types';\nimport { Route, Routes, NavLink as RouterNavLink, Navigate } from 'react-router-dom';\nimport { Location } from 'history';\nimport classNames from 'classnames';\nimport { DateRangeSelector } from '../utils/dates/DateRangeSelector';\nimport Message from '../utils/Message';\nimport { DateInterval, DateRange, intervalToDateRange } from '../utils/dates/types';\nimport { Result } from '../utils/Result';\nimport { ShlinkApiError } from '../api/ShlinkApiError';\nimport { Settings } from '../settings/reducers/settings';\nimport { SelectedServer } from '../servers/data';\nimport { supportsBotVisits } from '../utils/helpers/features';\nimport { prettify } from '../utils/helpers/numbers';\nimport LineChartCard from './charts/LineChartCard';\nimport VisitsTable from './VisitsTable';\nimport { NormalizedOrphanVisit, NormalizedVisit, VisitsFilter, VisitsInfo, VisitsParams } from './types';\nimport OpenMapModalBtn from './helpers/OpenMapModalBtn';\nimport { normalizeVisits, processStatsFromVisits } from './services/VisitsParser';\nimport { VisitsFilterDropdown } from './helpers/VisitsFilterDropdown';\nimport { HighlightableProps, highlightedVisitsToStats } from './types/helpers';\nimport { DoughnutChartCard } from './charts/DoughnutChartCard';\nimport { SortableBarChartCard } from './charts/SortableBarChartCard';\nimport './VisitsStats.scss';\n\nexport interface VisitsStatsProps {\n getVisits: (params: VisitsParams, doIntervalFallback?: boolean) => void;\n visitsInfo: VisitsInfo;\n settings: Settings;\n selectedServer: SelectedServer;\n cancelGetVisits: () => void;\n domain?: string;\n exportCsv: (visits: NormalizedVisit[]) => void;\n isOrphanVisits?: boolean;\n}\n\ninterface VisitsNavLinkProps {\n title: string;\n subPath: string;\n icon: IconDefinition;\n}\n\ntype Section = 'byTime' | 'byContext' | 'byLocation' | 'list';\n\nconst sections: Record<Section, VisitsNavLinkProps> = {\n byTime: { title: 'By time', subPath: 'by-time', icon: faCalendarAlt },\n byContext: { title: 'By context', subPath: 'by-context', icon: faChartPie },\n byLocation: { title: 'By location', subPath: 'by-location', icon: faMapMarkedAlt },\n list: { title: 'List', subPath: 'list', icon: faList },\n};\n\nlet selectedBar: string | undefined;\n\nconst VisitsNavLink: FC<VisitsNavLinkProps & { to: string }> = ({ subPath, title, icon, to }) => (\n <NavLink\n tag={RouterNavLink}\n className=\"visits-stats__nav-link\"\n to={to}\n isActive={(_: null, { pathname }: Location) => pathname.endsWith(`visits${subPath}`)}\n replace\n >\n <FontAwesomeIcon icon={icon} />\n <span className=\"ml-2 d-none d-sm-inline\">{title}</span>\n </NavLink>\n);\n\nconst VisitsStats: FC<VisitsStatsProps> = ({\n children,\n visitsInfo,\n getVisits,\n cancelGetVisits,\n domain,\n settings,\n exportCsv,\n selectedServer,\n isOrphanVisits = false,\n}) => {\n const { visits, loading, loadingLarge, error, errorData, progress, fallbackInterval } = visitsInfo;\n const [ initialInterval, setInitialInterval ] = useState<DateInterval>(\n fallbackInterval ?? settings.visits?.defaultInterval ?? 'last30Days',\n );\n const [ dateRange, setDateRange ] = useState<DateRange>(intervalToDateRange(initialInterval));\n const [ highlightedVisits, setHighlightedVisits ] = useState<NormalizedVisit[]>([]);\n const [ highlightedLabel, setHighlightedLabel ] = useState<string | undefined>();\n const [ visitsFilter, setVisitsFilter ] = useState<VisitsFilter>({});\n const botsSupported = supportsBotVisits(selectedServer);\n const isFirstLoad = useRef(true);\n\n const buildSectionUrl = (subPath?: string) => {\n const query = domain ? `?domain=${domain}` : '';\n\n return !subPath ? `${query}` : `${subPath}${query}`;\n };\n const normalizedVisits = useMemo(() => normalizeVisits(visits), [ visits ]);\n const { os, browsers, referrers, countries, cities, citiesForMap, visitedUrls } = useMemo(\n () => processStatsFromVisits(normalizedVisits),\n [ normalizedVisits ],\n );\n const mapLocations = values(citiesForMap);\n\n const setSelectedVisits = (selectedVisits: NormalizedVisit[]) => {\n selectedBar = undefined;\n setHighlightedVisits(selectedVisits);\n };\n const highlightVisitsForProp = (prop: HighlightableProps<NormalizedOrphanVisit>) => (value: string) => {\n const newSelectedBar = `${prop}_${value}`;\n\n if (selectedBar === newSelectedBar) {\n setHighlightedVisits([]);\n setHighlightedLabel(undefined);\n selectedBar = undefined;\n } else {\n setHighlightedVisits((normalizedVisits as NormalizedOrphanVisit[]).filter(propEq(prop, value)));\n setHighlightedLabel(value);\n selectedBar = newSelectedBar;\n }\n };\n\n useEffect(() => cancelGetVisits, []);\n useEffect(() => {\n getVisits({ dateRange, filter: visitsFilter }, isFirstLoad.current);\n isFirstLoad.current = false;\n }, [ dateRange, visitsFilter ]);\n useEffect(() => {\n fallbackInterval && setInitialInterval(fallbackInterval);\n }, [ fallbackInterval ]);\n\n const renderVisitsContent = () => {\n if (loadingLarge) {\n return (\n <Message loading>\n This is going to take a while... :S\n <Progress value={progress} striped={progress === 100} className=\"mt-3\" />\n </Message>\n );\n }\n\n if (loading) {\n return <Message loading />;\n }\n\n if (error) {\n return (\n <Result type=\"error\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"An error occurred while loading visits :(\" />\n </Result>\n );\n }\n\n if (isEmpty(visits)) {\n return <Message>There are no visits matching current filter :(</Message>;\n }\n\n return (\n <>\n <Card className=\"visits-stats__nav p-0 overflow-hidden\" body>\n <Nav pills fill>\n {Object.entries(sections).map(([ section, props ]) =>\n <VisitsNavLink key={section} {...props} to={buildSectionUrl(props.subPath)} />)}\n </Nav>\n </Card>\n <Row>\n <Routes>\n <Route\n path={sections.byTime.subPath}\n element={(\n <div className=\"col-12 mt-3\">\n <LineChartCard\n title=\"Visits during time\"\n visits={normalizedVisits}\n highlightedVisits={highlightedVisits}\n highlightedLabel={highlightedLabel}\n setSelectedVisits={setSelectedVisits}\n />\n </div>\n )}\n />\n\n <Route\n path={sections.byContext.subPath}\n element={(\n <>\n <div className={classNames('mt-3 col-lg-6', { 'col-xl-4': !isOrphanVisits })}>\n <DoughnutChartCard title=\"Operating systems\" stats={os} />\n </div>\n <div className={classNames('mt-3 col-lg-6', { 'col-xl-4': !isOrphanVisits })}>\n <DoughnutChartCard title=\"Browsers\" stats={browsers} />\n </div>\n <div className={classNames('mt-3', { 'col-xl-4': !isOrphanVisits, 'col-lg-6': isOrphanVisits })}>\n <SortableBarChartCard\n title=\"Referrers\"\n stats={referrers}\n withPagination={false}\n highlightedStats={highlightedVisitsToStats(highlightedVisits, 'referer')}\n highlightedLabel={highlightedLabel}\n sortingItems={{\n name: 'Referrer name',\n amount: 'Visits amount',\n }}\n onClick={highlightVisitsForProp('referer')}\n />\n </div>\n {isOrphanVisits && (\n <div className=\"mt-3 col-lg-6\">\n <SortableBarChartCard\n title=\"Visited URLs\"\n stats={visitedUrls}\n highlightedLabel={highlightedLabel}\n highlightedStats={highlightedVisitsToStats(highlightedVisits, 'visitedUrl')}\n sortingItems={{\n visitedUrl: 'Visited URL',\n amount: 'Visits amount',\n }}\n onClick={highlightVisitsForProp('visitedUrl')}\n />\n </div>\n )}\n </>\n )}\n />\n\n <Route\n path={sections.byLocation.subPath}\n element={(\n <>\n <div className=\"col-lg-6 mt-3\">\n <SortableBarChartCard\n title=\"Countries\"\n stats={countries}\n highlightedStats={highlightedVisitsToStats(highlightedVisits, 'country')}\n highlightedLabel={highlightedLabel}\n sortingItems={{\n name: 'Country name',\n amount: 'Visits amount',\n }}\n onClick={highlightVisitsForProp('country')}\n />\n </div>\n <div className=\"col-lg-6 mt-3\">\n <SortableBarChartCard\n title=\"Cities\"\n stats={cities}\n highlightedStats={highlightedVisitsToStats(highlightedVisits, 'city')}\n highlightedLabel={highlightedLabel}\n extraHeaderContent={(activeCities: string[]) =>\n mapLocations.length > 0 &&\n <OpenMapModalBtn modalTitle=\"Cities\" locations={mapLocations} activeCities={activeCities} />\n }\n sortingItems={{\n name: 'City name',\n amount: 'Visits amount',\n }}\n onClick={highlightVisitsForProp('city')}\n />\n </div>\n </>\n )}\n />\n\n <Route\n path={sections.list.subPath}\n element={(\n <div className=\"col-12\">\n <VisitsTable\n visits={normalizedVisits}\n selectedVisits={highlightedVisits}\n setSelectedVisits={setSelectedVisits}\n isOrphanVisits={isOrphanVisits}\n selectedServer={selectedServer}\n />\n </div>\n )}\n />\n\n <Route path=\"*\" element={<Navigate replace to={buildSectionUrl(sections.byTime.subPath)} />} />\n </Routes>\n </Row>\n </>\n );\n };\n\n return (\n <>\n {children}\n\n <section className=\"mt-3\">\n <div className=\"row flex-md-row-reverse\">\n <div className=\"col-lg-7 col-xl-6\">\n <div className=\"d-md-flex\">\n <div className=\"flex-fill\">\n <DateRangeSelector\n updatable\n disabled={loading}\n initialDateRange={initialInterval}\n defaultText=\"All visits\"\n onDatesChange={setDateRange}\n />\n </div>\n <VisitsFilterDropdown\n className=\"ml-0 ml-md-2 mt-3 mt-md-0\"\n isOrphanVisits={isOrphanVisits}\n botsSupported={botsSupported}\n selected={visitsFilter}\n onChange={setVisitsFilter}\n />\n </div>\n </div>\n {visits.length > 0 && (\n <div className=\"col-lg-5 col-xl-6 mt-3 mt-lg-0\">\n <div className=\"d-flex\">\n <Button\n outline\n disabled={highlightedVisits.length === 0}\n className=\"btn-md-block mr-2\"\n onClick={() => setSelectedVisits([])}\n >\n Clear selection {highlightedVisits.length > 0 && <>({prettify(highlightedVisits.length)})</>}\n </Button>\n <Button\n outline\n color=\"primary\"\n className=\"btn-md-block\"\n onClick={() => exportCsv(normalizedVisits)}\n >\n <FontAwesomeIcon icon={faFileDownload} /> Export ({prettify(normalizedVisits.length)})\n </Button>\n </div>\n </div>\n )}\n </div>\n </section>\n\n <section className=\"mt-3\">\n {renderVisitsContent()}\n </section>\n </>\n );\n};\n\nexport default VisitsStats;\n","import { Action } from 'redux';\n\ntype ActionHandler<State, AT> = (currentState: State, action: AT) => State;\ntype ActionHandlerMap<State, AT> = Record<string, ActionHandler<State, AT>>;\n\nexport const buildReducer = <State, AT extends Action>(map: ActionHandlerMap<State, AT>, initialState: State) => (\n state: State | undefined,\n action: AT,\n): State => {\n const { type } = action;\n const actionHandler = map[type];\n const currentState = state ?? initialState;\n\n return actionHandler ? actionHandler(currentState, action) : currentState;\n};\n\nexport const buildActionCreator = <T extends string>(type: T) => (): Action<T> => ({ type });\n","import { Action } from 'redux';\nimport { dissoc, mergeDeepRight } from 'ramda';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { RecursivePartial } from '../../utils/utils';\nimport { Theme } from '../../utils/theme';\nimport { DateInterval } from '../../utils/dates/types';\nimport { TagsOrder } from '../../tags/data/TagsListChildrenProps';\nimport { ShortUrlsOrder } from '../../short-urls/data';\n\nexport const SET_SETTINGS = 'shlink/realTimeUpdates/SET_SETTINGS';\n\nexport const DEFAULT_SHORT_URLS_ORDERING: ShortUrlsOrder = {\n field: 'dateCreated',\n dir: 'DESC',\n};\n\n/**\n * Important! When adding new props in the main Settings interface or any of the nested props, they have to be set as\n * optional, as old instances of the app will load partial objects from local storage until it is saved again.\n */\n\nexport interface RealTimeUpdatesSettings {\n enabled: boolean;\n interval?: number;\n}\n\nexport type TagFilteringMode = 'startsWith' | 'includes';\n\nexport interface ShortUrlCreationSettings {\n validateUrls: boolean;\n tagFilteringMode?: TagFilteringMode;\n forwardQuery?: boolean;\n}\n\nexport type TagsMode = 'cards' | 'list';\n\nexport interface UiSettings {\n theme: Theme;\n}\n\nexport interface VisitsSettings {\n defaultInterval: DateInterval;\n}\n\nexport interface TagsSettings {\n defaultOrdering?: TagsOrder;\n defaultMode?: TagsMode;\n}\n\nexport interface ShortUrlsListSettings {\n defaultOrdering?: ShortUrlsOrder;\n}\n\nexport interface Settings {\n realTimeUpdates: RealTimeUpdatesSettings;\n shortUrlCreation?: ShortUrlCreationSettings;\n shortUrlsList?: ShortUrlsListSettings;\n ui?: UiSettings;\n visits?: VisitsSettings;\n tags?: TagsSettings;\n}\n\nconst initialState: Settings = {\n realTimeUpdates: {\n enabled: true,\n },\n shortUrlCreation: {\n validateUrls: false,\n },\n ui: {\n theme: 'light',\n },\n visits: {\n defaultInterval: 'last30Days',\n },\n shortUrlsList: {\n defaultOrdering: DEFAULT_SHORT_URLS_ORDERING,\n },\n};\n\ntype SettingsAction = Action & Settings;\n\ntype PartialSettingsAction = Action & RecursivePartial<Settings>;\n\nexport default buildReducer<Settings, SettingsAction>({\n [SET_SETTINGS]: (state, action) => mergeDeepRight(state, dissoc('type', action)),\n}, initialState);\n\nexport const toggleRealTimeUpdates = (enabled: boolean): PartialSettingsAction => ({\n type: SET_SETTINGS,\n realTimeUpdates: { enabled },\n});\n\nexport const setRealTimeUpdatesInterval = (interval: number): PartialSettingsAction => ({\n type: SET_SETTINGS,\n realTimeUpdates: { interval },\n});\n\nexport const setShortUrlCreationSettings = (settings: ShortUrlCreationSettings): PartialSettingsAction => ({\n type: SET_SETTINGS,\n shortUrlCreation: settings,\n});\n\nexport const setShortUrlsListSettings = (settings: ShortUrlsListSettings): PartialSettingsAction => ({\n type: SET_SETTINGS,\n shortUrlsList: settings,\n});\n\nexport const setUiSettings = (settings: UiSettings): PartialSettingsAction => ({\n type: SET_SETTINGS,\n ui: settings,\n});\n\nexport const setVisitsSettings = (settings: VisitsSettings): PartialSettingsAction => ({\n type: SET_SETTINGS,\n visits: settings,\n});\n\nexport const setTagsSettings = (settings: TagsSettings): PartialSettingsAction => ({\n type: SET_SETTINGS,\n tags: settings,\n});\n","const TEN_ROUNDING_NUMBER = 10;\nconst { ceil } = Math;\nconst formatter = new Intl.NumberFormat('en-US');\n\nexport const prettify = (number: number | string) => formatter.format(Number(number));\n\nexport const roundTen = (number: number) => ceil(number / TEN_ROUNDING_NUMBER) * TEN_ROUNDING_NUMBER;\n","import { max, min, range } from 'ramda';\nimport { prettify } from './numbers';\n\nconst DELTA = 2;\n\nexport const ELLIPSIS = '...';\n\ntype Ellipsis = typeof ELLIPSIS;\n\nexport type NumberOrEllipsis = number | Ellipsis;\n\nexport const progressivePagination = (currentPage: number, pageCount: number): NumberOrEllipsis[] => {\n const pages: NumberOrEllipsis[] = range(\n max(DELTA, currentPage - DELTA),\n min(pageCount - 1, currentPage + DELTA) + 1,\n );\n\n if (currentPage - DELTA > DELTA) {\n pages.unshift(ELLIPSIS);\n }\n if (currentPage + DELTA < pageCount - 1) {\n pages.push(ELLIPSIS);\n }\n\n pages.unshift(1);\n pages.push(pageCount);\n\n return pages;\n};\n\nexport const pageIsEllipsis = (pageNumber: NumberOrEllipsis): pageNumber is Ellipsis => pageNumber === ELLIPSIS;\n\nexport const prettifyPageNumber = (pageNumber: NumberOrEllipsis): string =>\n pageIsEllipsis(pageNumber) ? pageNumber : prettify(pageNumber);\n\nexport const keyForPage = (pageNumber: NumberOrEllipsis, index: number) => !pageIsEllipsis(pageNumber) ? `${pageNumber}` : `${pageNumber}_${index}`;\n","import { Link } from 'react-router-dom';\nimport { Pagination, PaginationItem, PaginationLink } from 'reactstrap';\nimport {\n pageIsEllipsis,\n keyForPage,\n progressivePagination,\n prettifyPageNumber,\n NumberOrEllipsis,\n} from '../utils/helpers/pagination';\nimport { ShlinkPaginator } from '../api/types';\n\ninterface PaginatorProps {\n paginator?: ShlinkPaginator;\n serverId: string;\n currentQueryString?: string;\n}\n\nconst Paginator = ({ paginator, serverId, currentQueryString = '' }: PaginatorProps) => {\n const { currentPage = 0, pagesCount = 0 } = paginator ?? {};\n const urlForPage = (pageNumber: NumberOrEllipsis) =>\n `/server/${serverId}/list-short-urls/${pageNumber}${currentQueryString}`;\n\n if (pagesCount <= 1) {\n return null;\n }\n\n const renderPages = () =>\n progressivePagination(currentPage, pagesCount).map((pageNumber, index) => (\n <PaginationItem\n key={keyForPage(pageNumber, index)}\n disabled={pageIsEllipsis(pageNumber)}\n active={currentPage === pageNumber}\n >\n <PaginationLink tag={Link} to={urlForPage(pageNumber)}>\n {prettifyPageNumber(pageNumber)}\n </PaginationLink>\n </PaginationItem>\n ));\n\n return (\n <Pagination className=\"sticky-card-paginator\" listClassName=\"flex-wrap justify-content-center mb-0\">\n <PaginationItem disabled={currentPage === 1}>\n <PaginationLink previous tag={Link} to={urlForPage(currentPage - 1)} />\n </PaginationItem>\n {renderPages()}\n <PaginationItem disabled={currentPage >= pagesCount}>\n <PaginationLink next tag={Link} to={urlForPage(currentPage + 1)} />\n </PaginationItem>\n </Pagination>\n );\n};\n\nexport default Paginator;\n","import { Nullable, OptionalString } from '../../utils/utils';\nimport { Order } from '../../utils/helpers/ordering';\n\nexport interface EditShortUrlData {\n longUrl?: string;\n tags?: string[];\n title?: string | null;\n validSince?: Date | string | null;\n validUntil?: Date | string | null;\n maxVisits?: number | null;\n validateUrl?: boolean;\n crawlable?: boolean;\n forwardQuery?: boolean;\n}\n\nexport interface ShortUrlData extends EditShortUrlData {\n longUrl: string;\n customSlug?: string;\n shortCodeLength?: number;\n domain?: string;\n findIfExists?: boolean;\n}\n\nexport interface ShortUrl {\n shortCode: string;\n shortUrl: string;\n longUrl: string;\n dateCreated: string;\n visitsCount: number;\n meta: Required<Nullable<ShortUrlMeta>>;\n tags: string[];\n domain: string | null;\n title?: string | null;\n crawlable?: boolean;\n forwardQuery?: boolean;\n}\n\nexport interface ShortUrlMeta {\n validSince?: string;\n validUntil?: string;\n maxVisits?: number;\n}\n\nexport interface ShortUrlModalProps {\n shortUrl: ShortUrl;\n isOpen: boolean;\n toggle: () => void;\n}\n\nexport interface ShortUrlIdentifier {\n shortCode: string;\n domain: OptionalString;\n}\n\nexport const SHORT_URLS_ORDERABLE_FIELDS = {\n dateCreated: 'Created at',\n shortCode: 'Short URL',\n longUrl: 'Long URL',\n title: 'Title',\n visits: 'Visits',\n};\n\nexport type ShortUrlsOrderableFields = keyof typeof SHORT_URLS_ORDERABLE_FIELDS;\n\nexport type ShortUrlsOrder = Order<ShortUrlsOrderableFields>;\n","import { pipe } from 'ramda';\nimport { FC, useEffect, useMemo, useState } from 'react';\nimport { Card } from 'reactstrap';\nimport { useLocation, useParams } from 'react-router-dom';\nimport { OrderingDropdown } from '../utils/OrderingDropdown';\nimport { determineOrderDir, OrderDir } from '../utils/helpers/ordering';\nimport { getServerId, SelectedServer } from '../servers/data';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { TableOrderIcon } from '../utils/table/TableOrderIcon';\nimport { ShlinkShortUrlsListParams } from '../api/types';\nimport { DEFAULT_SHORT_URLS_ORDERING, Settings } from '../settings/reducers/settings';\nimport { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';\nimport { ShortUrlsTableProps } from './ShortUrlsTable';\nimport Paginator from './Paginator';\nimport { useShortUrlsQuery } from './helpers/hooks';\nimport { ShortUrlsOrderableFields, SHORT_URLS_ORDERABLE_FIELDS } from './data';\n\ninterface ShortUrlsListProps {\n selectedServer: SelectedServer;\n shortUrlsList: ShortUrlsListState;\n listShortUrls: (params: ShlinkShortUrlsListParams) => void;\n settings: Settings;\n}\n\nconst ShortUrlsList = (ShortUrlsTable: FC<ShortUrlsTableProps>, ShortUrlsFilteringBar: FC) => boundToMercureHub(({\n listShortUrls,\n shortUrlsList,\n selectedServer,\n settings,\n}: ShortUrlsListProps) => {\n const serverId = getServerId(selectedServer);\n const { page } = useParams();\n const location = useLocation();\n const [{ tags, search, startDate, endDate, orderBy }, toFirstPage ] = useShortUrlsQuery();\n const [ actualOrderBy, setActualOrderBy ] = useState(\n // This separated state handling is needed to be able to fall back to settings value, but only once when loaded\n orderBy ?? settings.shortUrlsList?.defaultOrdering ?? DEFAULT_SHORT_URLS_ORDERING,\n );\n const selectedTags = useMemo(() => tags?.split(',') ?? [], [ tags ]);\n const { pagination } = shortUrlsList?.shortUrls ?? {};\n const handleOrderBy = (field?: ShortUrlsOrderableFields, dir?: OrderDir) => {\n toFirstPage({ orderBy: { field, dir } });\n setActualOrderBy({ field, dir });\n };\n const orderByColumn = (field: ShortUrlsOrderableFields) => () =>\n handleOrderBy(field, determineOrderDir(field, actualOrderBy.field, actualOrderBy.dir));\n const renderOrderIcon = (field: ShortUrlsOrderableFields) =>\n <TableOrderIcon currentOrder={actualOrderBy} field={field} />;\n const addTag = pipe(\n (newTag: string) => [ ...new Set([ ...selectedTags, newTag ]) ].join(','),\n (tags) => toFirstPage({ tags }),\n );\n\n useEffect(() => {\n listShortUrls({\n page,\n searchTerm: search,\n tags: selectedTags,\n startDate,\n endDate,\n orderBy: actualOrderBy,\n });\n }, [ page, search, selectedTags, startDate, endDate, actualOrderBy ]);\n\n return (\n <>\n <div className=\"mb-3\"><ShortUrlsFilteringBar /></div>\n <div className=\"d-block d-lg-none mb-3\">\n <OrderingDropdown items={SHORT_URLS_ORDERABLE_FIELDS} order={actualOrderBy} onChange={handleOrderBy} />\n </div>\n <Card body className=\"pb-1\">\n <ShortUrlsTable\n selectedServer={selectedServer}\n shortUrlsList={shortUrlsList}\n orderByColumn={orderByColumn}\n renderOrderIcon={renderOrderIcon}\n onTagClick={addTag}\n />\n <Paginator paginator={pagination} serverId={serverId} currentQueryString={location.search} />\n </Card>\n </>\n );\n}, () => [ Topics.visits ]);\n\nexport default ShortUrlsList;\n","import { FC } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faCopy as copyIcon } from '@fortawesome/free-regular-svg-icons';\nimport CopyToClipboard from 'react-copy-to-clipboard';\nimport './CopyToClipboardIcon.scss';\n\ninterface CopyToClipboardIconProps {\n text: string;\n onCopy?: (text: string, result: boolean) => void;\n}\n\nexport const CopyToClipboardIcon: FC<CopyToClipboardIconProps> = ({ text, onCopy }) => (\n <CopyToClipboard text={text} onCopy={onCopy}>\n <FontAwesomeIcon icon={copyIcon} className=\"ml-2 copy-to-clipboard-icon\" />\n </CopyToClipboard>\n);\n","import { parseISO, format as formatDate, getUnixTime, formatDistance } from 'date-fns';\nimport { isDateObject } from './helpers/date';\n\nexport interface DateProps {\n date: Date | string;\n format?: string;\n relative?: boolean;\n}\n\nexport const Time = ({ date, format = 'yyyy-MM-dd HH:mm', relative = false }: DateProps) => {\n const dateObject = isDateObject(date) ? date : parseISO(date);\n\n return (\n <time dateTime={`${getUnixTime(dateObject)}000`}>\n {relative ? `${formatDistance(new Date(), dateObject)} ago` : formatDate(dateObject, format)}\n </time>\n );\n};\n","import { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport { isServerWithId, SelectedServer, ServerWithId } from '../../servers/data';\nimport { ShortUrl } from '../data';\n\nexport type LinkSuffix = 'visits' | 'edit';\n\nexport interface ShortUrlDetailLinkProps {\n shortUrl?: ShortUrl | null;\n selectedServer?: SelectedServer;\n suffix: LinkSuffix;\n}\n\nconst buildUrl = ({ id }: ServerWithId, { shortCode, domain }: ShortUrl, suffix: LinkSuffix) => {\n const query = domain ? `?domain=${domain}` : '';\n\n return `/server/${id}/short-code/${shortCode}/${suffix}${query}`;\n};\n\nconst ShortUrlDetailLink: FC<ShortUrlDetailLinkProps & Record<string | number, any>> = (\n { selectedServer, shortUrl, suffix, children, ...rest },\n) => {\n if (!selectedServer || !isServerWithId(selectedServer) || !shortUrl) {\n return <span {...rest}>{children}</span>;\n }\n\n return <Link to={buildUrl(selectedServer, shortUrl, suffix)} {...rest}>{children}</Link>;\n};\n\nexport default ShortUrlDetailLink;\n","import { useRef } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';\nimport { UncontrolledTooltip } from 'reactstrap';\nimport classNames from 'classnames';\nimport { prettify } from '../../utils/helpers/numbers';\nimport { ShortUrl } from '../data';\nimport { SelectedServer } from '../../servers/data';\nimport ShortUrlDetailLink from './ShortUrlDetailLink';\nimport './ShortUrlVisitsCount.scss';\n\ninterface ShortUrlVisitsCountProps {\n shortUrl?: ShortUrl | null;\n selectedServer?: SelectedServer;\n visitsCount: number;\n active?: boolean;\n}\n\nconst ShortUrlVisitsCount = ({ visitsCount, shortUrl, selectedServer, active = false }: ShortUrlVisitsCountProps) => {\n const maxVisits = shortUrl?.meta?.maxVisits;\n const visitsLink = (\n <ShortUrlDetailLink selectedServer={selectedServer} shortUrl={shortUrl} suffix=\"visits\">\n <strong\n className={classNames('short-url-visits-count__amount', { 'short-url-visits-count__amount--big': active })}\n >\n {prettify(visitsCount)}\n </strong>\n </ShortUrlDetailLink>\n );\n\n if (!maxVisits) {\n return visitsLink;\n }\n\n const prettifiedMaxVisits = prettify(maxVisits);\n const tooltipRef = useRef<HTMLElement | null>();\n\n return (\n <>\n <span className=\"indivisible\">\n {visitsLink}\n <small\n className=\"short-urls-visits-count__max-visits-control\"\n ref={(el) => {\n tooltipRef.current = el;\n }}\n >\n {' '}/ {prettifiedMaxVisits}{' '}\n <sup>\n <FontAwesomeIcon icon={infoIcon} />\n </sup>\n </small>\n </span>\n <UncontrolledTooltip target={(() => tooltipRef.current) as any} placement=\"bottom\">\n This short URL will not accept more than <b>{prettifiedMaxVisits}</b> visits.\n </UncontrolledTooltip>\n </>\n );\n};\n\nexport default ShortUrlVisitsCount;\n","import { FC, useEffect, useRef } from 'react';\nimport { isEmpty } from 'ramda';\nimport { ExternalLink } from 'react-external-link';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport { StateFlagTimeout } from '../../utils/helpers/hooks';\nimport Tag from '../../tags/helpers/Tag';\nimport { SelectedServer } from '../../servers/data';\nimport { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon';\nimport { ShortUrl } from '../data';\nimport { Time } from '../../utils/Time';\nimport ShortUrlVisitsCount from './ShortUrlVisitsCount';\nimport { ShortUrlsRowMenuProps } from './ShortUrlsRowMenu';\nimport './ShortUrlsRow.scss';\n\nexport interface ShortUrlsRowProps {\n onTagClick?: (tag: string) => void;\n selectedServer: SelectedServer;\n shortUrl: ShortUrl;\n}\n\nconst ShortUrlsRow = (\n ShortUrlsRowMenu: FC<ShortUrlsRowMenuProps>,\n colorGenerator: ColorGenerator,\n useStateFlagTimeout: StateFlagTimeout,\n) => ({ shortUrl, selectedServer, onTagClick }: ShortUrlsRowProps) => {\n const [ copiedToClipboard, setCopiedToClipboard ] = useStateFlagTimeout();\n const [ active, setActive ] = useStateFlagTimeout(false, 500);\n const isFirstRun = useRef(true);\n\n const renderTags = (tags: string[]) => {\n if (isEmpty(tags)) {\n return <i className=\"indivisible\"><small>No tags</small></i>;\n }\n\n return tags.map((tag) => (\n <Tag\n colorGenerator={colorGenerator}\n key={tag}\n text={tag}\n onClick={() => onTagClick?.(tag)}\n />\n ));\n };\n\n useEffect(() => {\n if (isFirstRun.current) {\n isFirstRun.current = false;\n } else {\n setActive();\n }\n }, [ shortUrl.visitsCount ]);\n\n return (\n <tr className=\"responsive-table__row\">\n <td className=\"indivisible short-urls-row__cell responsive-table__cell\" data-th=\"Created at\">\n <Time date={shortUrl.dateCreated} />\n </td>\n <td className=\"responsive-table__cell short-urls-row__cell\" data-th=\"Short URL\">\n <span className=\"indivisible short-urls-row__cell--relative\">\n <ExternalLink href={shortUrl.shortUrl} />\n <CopyToClipboardIcon text={shortUrl.shortUrl} onCopy={setCopiedToClipboard} />\n <span className=\"badge badge-warning short-urls-row__copy-hint\" hidden={!copiedToClipboard}>\n Copied short URL!\n </span>\n </span>\n </td>\n <td className=\"responsive-table__cell short-urls-row__cell short-urls-row__cell--break\" data-th={`${shortUrl.title ? 'Title' : 'Long URL'}`}>\n <ExternalLink href={shortUrl.longUrl}>{shortUrl.title ?? shortUrl.longUrl}</ExternalLink>\n </td>\n {shortUrl.title && (\n <td className=\"short-urls-row__cell responsive-table__cell short-urls-row__cell--break d-lg-none\" data-th=\"Long URL\">\n <ExternalLink href={shortUrl.longUrl} />\n </td>\n )}\n <td className=\"responsive-table__cell short-urls-row__cell\" data-th=\"Tags\">{renderTags(shortUrl.tags)}</td>\n <td className=\"responsive-table__cell short-urls-row__cell text-lg-right\" data-th=\"Visits\">\n <ShortUrlVisitsCount\n visitsCount={shortUrl.visitsCount}\n shortUrl={shortUrl}\n selectedServer={selectedServer}\n active={active}\n />\n </td>\n <td className=\"responsive-table__cell short-urls-row__cell\">\n <ShortUrlsRowMenu selectedServer={selectedServer} shortUrl={shortUrl} />\n </td>\n </tr>\n );\n};\n\nexport default ShortUrlsRow;\n","import { FC } from 'react';\nimport { ButtonDropdown, DropdownMenu, DropdownToggle } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faEllipsisV as menuIcon } from '@fortawesome/free-solid-svg-icons';\nimport './DropdownBtnMenu.scss';\n\nexport interface DropdownBtnMenuProps {\n isOpen: boolean;\n toggle: () => void;\n right?: boolean;\n}\n\nexport const DropdownBtnMenu: FC<DropdownBtnMenuProps> = ({ isOpen, toggle, children, right = true }) => (\n <ButtonDropdown toggle={toggle} isOpen={isOpen}>\n <DropdownToggle size=\"sm\" caret outline className=\"dropdown-btn-menu__dropdown-toggle\">\n <FontAwesomeIcon icon={menuIcon} /> \n </DropdownToggle>\n <DropdownMenu right={right}>{children}</DropdownMenu>\n </ButtonDropdown>\n);\n","import {\n faChartPie as pieChartIcon,\n faQrcode as qrIcon,\n faMinusCircle as deleteIcon,\n faEdit as editIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { ShortUrl, ShortUrlModalProps } from '../data';\nimport { SelectedServer } from '../../servers/data';\nimport { DropdownBtnMenu } from '../../utils/DropdownBtnMenu';\nimport ShortUrlDetailLink from './ShortUrlDetailLink';\n\nexport interface ShortUrlsRowMenuProps {\n selectedServer: SelectedServer;\n shortUrl: ShortUrl;\n}\ntype ShortUrlModal = FC<ShortUrlModalProps>;\n\nconst ShortUrlsRowMenu = (\n DeleteShortUrlModal: ShortUrlModal,\n QrCodeModal: ShortUrlModal,\n) => ({ shortUrl, selectedServer }: ShortUrlsRowMenuProps) => {\n const [ isOpen, toggle ] = useToggle();\n const [ isQrModalOpen, toggleQrCode ] = useToggle();\n const [ isDeleteModalOpen, toggleDelete ] = useToggle();\n\n return (\n <DropdownBtnMenu toggle={toggle} isOpen={isOpen}>\n <DropdownItem tag={ShortUrlDetailLink} selectedServer={selectedServer} shortUrl={shortUrl} suffix=\"visits\">\n <FontAwesomeIcon icon={pieChartIcon} fixedWidth /> Visit stats\n </DropdownItem>\n\n <DropdownItem tag={ShortUrlDetailLink} selectedServer={selectedServer} shortUrl={shortUrl} suffix=\"edit\">\n <FontAwesomeIcon icon={editIcon} fixedWidth /> Edit short URL\n </DropdownItem>\n\n <DropdownItem onClick={toggleQrCode}>\n <FontAwesomeIcon icon={qrIcon} fixedWidth /> QR code\n </DropdownItem>\n <QrCodeModal shortUrl={shortUrl} isOpen={isQrModalOpen} toggle={toggleQrCode} />\n\n <DropdownItem divider />\n\n <DropdownItem className=\"dropdown-item--danger\" onClick={toggleDelete}>\n <FontAwesomeIcon icon={deleteIcon} fixedWidth /> Delete short URL\n </DropdownItem>\n <DeleteShortUrlModal shortUrl={shortUrl} isOpen={isDeleteModalOpen} toggle={toggleDelete} />\n </DropdownBtnMenu>\n );\n};\n\nexport default ShortUrlsRowMenu;\n","import { FC, useMemo } from 'react';\nimport { SelectedServer } from '../servers/data';\nimport { Settings, ShortUrlCreationSettings } from '../settings/reducers/settings';\nimport { ShortUrlData } from './data';\nimport { ShortUrlCreation } from './reducers/shortUrlCreation';\nimport { CreateShortUrlResultProps } from './helpers/CreateShortUrlResult';\nimport { ShortUrlFormProps } from './ShortUrlForm';\n\nexport interface CreateShortUrlProps {\n basicMode?: boolean;\n}\n\ninterface CreateShortUrlConnectProps extends CreateShortUrlProps {\n settings: Settings;\n shortUrlCreationResult: ShortUrlCreation;\n selectedServer: SelectedServer;\n createShortUrl: (data: ShortUrlData) => Promise<void>;\n resetCreateShortUrl: () => void;\n}\n\nconst getInitialState = (settings?: ShortUrlCreationSettings): ShortUrlData => ({\n longUrl: '',\n tags: [],\n customSlug: '',\n title: undefined,\n shortCodeLength: undefined,\n domain: '',\n validSince: undefined,\n validUntil: undefined,\n maxVisits: undefined,\n findIfExists: false,\n validateUrl: settings?.validateUrls ?? false,\n forwardQuery: settings?.forwardQuery ?? true,\n});\n\nconst CreateShortUrl = (ShortUrlForm: FC<ShortUrlFormProps>, CreateShortUrlResult: FC<CreateShortUrlResultProps>) => ({\n createShortUrl,\n shortUrlCreationResult,\n resetCreateShortUrl,\n selectedServer,\n basicMode = false,\n settings: { shortUrlCreation: shortUrlCreationSettings },\n}: CreateShortUrlConnectProps) => {\n const initialState = useMemo(() => getInitialState(shortUrlCreationSettings), [ shortUrlCreationSettings ]);\n\n return (\n <>\n <ShortUrlForm\n initialState={initialState}\n saving={shortUrlCreationResult.saving}\n selectedServer={selectedServer}\n mode={basicMode ? 'create-basic' : 'create'}\n onSave={async (data: ShortUrlData) => {\n resetCreateShortUrl();\n\n return createShortUrl(data);\n }}\n />\n <CreateShortUrlResult\n {...shortUrlCreationResult}\n resetCreateShortUrl={resetCreateShortUrl}\n canBeClosed={basicMode}\n />\n </>\n );\n};\n\nexport default CreateShortUrl;\n","import { FC } from 'react';\nimport { Row } from 'reactstrap';\nimport classNames from 'classnames';\nimport { SimpleCard } from './SimpleCard';\n\nexport type ResultType = 'success' | 'error' | 'warning';\n\nexport interface ResultProps {\n type: ResultType;\n className?: string;\n small?: boolean;\n}\n\nexport const Result: FC<ResultProps> = ({ children, type, className, small = false }) => (\n <Row className={className}>\n <div className={classNames({ 'col-md-10 offset-md-1': !small, 'col-12': small })}>\n <SimpleCard\n className={classNames('text-center', {\n 'bg-main': type === 'success',\n 'bg-danger': type === 'error',\n 'bg-warning': type === 'warning',\n 'text-white': type !== 'warning',\n })}\n bodyClassName={classNames({ 'p-2': small })}\n >\n {children}\n </SimpleCard>\n </div>\n </Row>\n);\n","import { AxiosError } from 'axios';\nimport { InvalidArgumentError, InvalidShortUrlDeletion, ProblemDetailsError } from '../types';\n\nexport const parseApiError = (e: AxiosError<ProblemDetailsError>) => e.response?.data;\n\nexport const isInvalidArgumentError = (error?: ProblemDetailsError): error is InvalidArgumentError =>\n error?.type === 'INVALID_ARGUMENT';\n\nexport const isInvalidDeletionError = (error?: ProblemDetailsError): error is InvalidShortUrlDeletion =>\n error?.type === 'INVALID_SHORTCODE_DELETION' || error?.type === 'INVALID_SHORT_URL_DELETION';\n","import { ProblemDetailsError } from './types';\nimport { isInvalidArgumentError } from './utils';\n\nexport interface ShlinkApiErrorProps {\n errorData?: ProblemDetailsError;\n fallbackMessage?: string;\n}\n\nexport const ShlinkApiError = ({ errorData, fallbackMessage }: ShlinkApiErrorProps) => (\n <>\n {errorData?.detail ?? fallbackMessage}\n {isInvalidArgumentError(errorData) &&\n <p className=\"mb-0\">Invalid elements: [{errorData.invalidElements.join(', ')}]</p>\n }\n </>\n);\n","import { useEffect, useState } from 'react';\nimport { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { identity, pipe } from 'ramda';\nimport { ShortUrlDeletion } from '../reducers/shortUrlDeletion';\nimport { ShortUrlModalProps } from '../data';\nimport { handleEventPreventingDefault, OptionalString } from '../../utils/utils';\nimport { Result } from '../../utils/Result';\nimport { isInvalidDeletionError } from '../../api/utils';\nimport { ShlinkApiError } from '../../api/ShlinkApiError';\n\ninterface DeleteShortUrlModalConnectProps extends ShortUrlModalProps {\n shortUrlDeletion: ShortUrlDeletion;\n deleteShortUrl: (shortCode: string, domain: OptionalString) => Promise<void>;\n resetDeleteShortUrl: () => void;\n}\n\nconst DeleteShortUrlModal = (\n { shortUrl, toggle, isOpen, shortUrlDeletion, resetDeleteShortUrl, deleteShortUrl }: DeleteShortUrlModalConnectProps,\n) => {\n const [ inputValue, setInputValue ] = useState('');\n\n useEffect(() => resetDeleteShortUrl, []);\n\n const { error, errorData } = shortUrlDeletion;\n const close = pipe(resetDeleteShortUrl, toggle);\n const handleDeleteUrl = handleEventPreventingDefault(() => {\n const { shortCode, domain } = shortUrl;\n\n deleteShortUrl(shortCode, domain)\n .then(toggle)\n .catch(identity);\n });\n\n return (\n <Modal isOpen={isOpen} toggle={close} centered>\n <form onSubmit={handleDeleteUrl}>\n <ModalHeader toggle={close}>\n <span className=\"text-danger\">Delete short URL</span>\n </ModalHeader>\n <ModalBody>\n <p><b className=\"text-danger\">Caution!</b> You are about to delete a short URL.</p>\n <p>This action cannot be undone. Once you have deleted it, all the visits stats will be lost.</p>\n <p>Write <b>{shortUrl.shortCode}</b> to confirm deletion.</p>\n\n <input\n type=\"text\"\n className=\"form-control\"\n placeholder={`Insert the short code (${shortUrl.shortCode})`}\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n />\n\n {error && (\n <Result type={isInvalidDeletionError(errorData) ? 'warning' : 'error'} small className=\"mt-2\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"Something went wrong while deleting the URL :(\" />\n </Result>\n )}\n </ModalBody>\n <ModalFooter>\n <button type=\"button\" className=\"btn btn-link\" onClick={close}>Cancel</button>\n <button\n type=\"submit\"\n className=\"btn btn-danger\"\n disabled={inputValue !== shortUrl.shortCode || shortUrlDeletion.loading}\n >\n {shortUrlDeletion.loading ? 'Deleting...' : 'Delete'}\n </button>\n </ModalFooter>\n </form>\n </Modal>\n );\n};\n\nexport default DeleteShortUrlModal;\n","import { faCopy as copyIcon } from '@fortawesome/free-regular-svg-icons';\nimport { faTimes as closeIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { isNil } from 'ramda';\nimport { useEffect } from 'react';\nimport CopyToClipboard from 'react-copy-to-clipboard';\nimport { Tooltip } from 'reactstrap';\nimport { ShortUrlCreation } from '../reducers/shortUrlCreation';\nimport { StateFlagTimeout } from '../../utils/helpers/hooks';\nimport { Result } from '../../utils/Result';\nimport './CreateShortUrlResult.scss';\nimport { ShlinkApiError } from '../../api/ShlinkApiError';\n\nexport interface CreateShortUrlResultProps extends ShortUrlCreation {\n resetCreateShortUrl: () => void;\n canBeClosed?: boolean;\n}\n\nconst CreateShortUrlResult = (useStateFlagTimeout: StateFlagTimeout) => (\n { error, errorData, result, resetCreateShortUrl, canBeClosed = false }: CreateShortUrlResultProps,\n) => {\n const [ showCopyTooltip, setShowCopyTooltip ] = useStateFlagTimeout();\n\n useEffect(() => {\n resetCreateShortUrl();\n }, []);\n\n if (error) {\n return (\n <Result type=\"error\" className=\"mt-3\">\n {canBeClosed && <FontAwesomeIcon icon={closeIcon} className=\"float-right pointer\" onClick={resetCreateShortUrl} />}\n <ShlinkApiError errorData={errorData} fallbackMessage=\"An error occurred while creating the URL :(\" />\n </Result>\n );\n }\n\n if (isNil(result)) {\n return null;\n }\n\n const { shortUrl } = result;\n\n return (\n <Result type=\"success\" className=\"mt-3\">\n {canBeClosed && <FontAwesomeIcon icon={closeIcon} className=\"float-right pointer\" onClick={resetCreateShortUrl} />}\n <b>Great!</b> The short URL is <b>{shortUrl}</b>\n\n <CopyToClipboard text={shortUrl} onCopy={setShowCopyTooltip}>\n <button\n className=\"btn btn-light btn-sm create-short-url-result__copy-btn\"\n id=\"copyBtn\"\n type=\"button\"\n >\n <FontAwesomeIcon icon={copyIcon} /> Copy\n </button>\n </CopyToClipboard>\n\n <Tooltip placement=\"left\" isOpen={showCopyTooltip} target=\"copyBtn\">\n Copied!\n </Tooltip>\n </Result>\n );\n};\n\nexport default CreateShortUrlResult;\n","import { isNil } from 'ramda';\nimport { ShortUrl } from '../data';\nimport { OptionalString } from '../../utils/utils';\n\nexport const shortUrlMatches = (shortUrl: ShortUrl, shortCode: string, domain: OptionalString): boolean => {\n if (isNil(domain)) {\n return shortUrl.shortCode === shortCode && !shortUrl.domain;\n }\n\n return shortUrl.shortCode === shortCode && shortUrl.domain === domain;\n};\n","import { Action } from 'redux';\nimport { CreateVisit } from '../types';\n\nexport const CREATE_VISITS = 'shlink/visitCreation/CREATE_VISITS';\n\nexport interface CreateVisitsAction extends Action<typeof CREATE_VISITS> {\n createdVisits: CreateVisit[];\n}\n\nexport const createNewVisits = (createdVisits: CreateVisit[]): CreateVisitsAction => ({\n type: CREATE_VISITS,\n createdVisits,\n});\n","import { Action, Dispatch } from 'redux';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ProblemDetailsError } from '../../api/types';\nimport { GetState } from '../../container/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START';\nexport const DELETE_SHORT_URL_ERROR = 'shlink/deleteShortUrl/DELETE_SHORT_URL_ERROR';\nexport const SHORT_URL_DELETED = 'shlink/deleteShortUrl/SHORT_URL_DELETED';\nexport const RESET_DELETE_SHORT_URL = 'shlink/deleteShortUrl/RESET_DELETE_SHORT_URL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlDeletion {\n shortCode: string;\n loading: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface DeleteShortUrlAction extends Action<string> {\n shortCode: string;\n domain?: string | null;\n}\n\nconst initialState: ShortUrlDeletion = {\n shortCode: '',\n loading: false,\n error: false,\n};\n\nexport default buildReducer<ShortUrlDeletion, DeleteShortUrlAction & ApiErrorAction>({\n [DELETE_SHORT_URL_START]: (state) => ({ ...state, loading: true, error: false }),\n [DELETE_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, errorData, loading: false, error: true }),\n [SHORT_URL_DELETED]: (state, { shortCode }) => ({ ...state, shortCode, loading: false, error: false }),\n [RESET_DELETE_SHORT_URL]: () => initialState,\n}, initialState);\n\nexport const deleteShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n shortCode: string,\n domain?: string | null,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: DELETE_SHORT_URL_START });\n const { deleteShortUrl } = buildShlinkApiClient(getState);\n\n try {\n await deleteShortUrl(shortCode, domain);\n dispatch<DeleteShortUrlAction>({ type: SHORT_URL_DELETED, shortCode, domain });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: DELETE_SHORT_URL_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n\nexport const resetDeleteShortUrl = buildActionCreator(RESET_DELETE_SHORT_URL);\n","import { Action, Dispatch } from 'redux';\nimport { GetState } from '../../container/types';\nimport { ShortUrl, ShortUrlData } from '../data';\nimport { buildReducer, buildActionCreator } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START';\nexport const CREATE_SHORT_URL_ERROR = 'shlink/createShortUrl/CREATE_SHORT_URL_ERROR';\nexport const CREATE_SHORT_URL = 'shlink/createShortUrl/CREATE_SHORT_URL';\nexport const RESET_CREATE_SHORT_URL = 'shlink/createShortUrl/RESET_CREATE_SHORT_URL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlCreation {\n result: ShortUrl | null;\n saving: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface CreateShortUrlAction extends Action<string> {\n result: ShortUrl;\n}\n\nconst initialState: ShortUrlCreation = {\n result: null,\n saving: false,\n error: false,\n};\n\nexport default buildReducer<ShortUrlCreation, CreateShortUrlAction & ApiErrorAction>({\n [CREATE_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }),\n [CREATE_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, saving: false, error: true, errorData }),\n [CREATE_SHORT_URL]: (_, { result }) => ({ result, saving: false, error: false }),\n [RESET_CREATE_SHORT_URL]: () => initialState,\n}, initialState);\n\nexport const createShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (data: ShortUrlData) => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch({ type: CREATE_SHORT_URL_START });\n const { createShortUrl } = buildShlinkApiClient(getState);\n\n try {\n const result = await createShortUrl(data);\n\n dispatch<CreateShortUrlAction>({ type: CREATE_SHORT_URL, result });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: CREATE_SHORT_URL_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n\nexport const resetCreateShortUrl = buildActionCreator(RESET_CREATE_SHORT_URL);\n","import { Action, Dispatch } from 'redux';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { GetState } from '../../container/types';\nimport { OptionalString } from '../../utils/utils';\nimport { EditShortUrlData, ShortUrl } from '../data';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { supportsTagsInPatch } from '../../utils/helpers/features';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const EDIT_SHORT_URL_START = 'shlink/shortUrlEdition/EDIT_SHORT_URL_START';\nexport const EDIT_SHORT_URL_ERROR = 'shlink/shortUrlEdition/EDIT_SHORT_URL_ERROR';\nexport const SHORT_URL_EDITED = 'shlink/shortUrlEdition/SHORT_URL_EDITED';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlEdition {\n shortUrl?: ShortUrl;\n saving: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface ShortUrlEditedAction extends Action<string> {\n shortUrl: ShortUrl;\n}\n\nconst initialState: ShortUrlEdition = {\n saving: false,\n error: false,\n};\n\nexport default buildReducer<ShortUrlEdition, ShortUrlEditedAction & ApiErrorAction>({\n [EDIT_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }),\n [EDIT_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, saving: false, error: true, errorData }),\n [SHORT_URL_EDITED]: (_, { shortUrl }) => ({ shortUrl, saving: false, error: false }),\n}, initialState);\n\nexport const editShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n shortCode: string,\n domain: OptionalString,\n data: EditShortUrlData,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: EDIT_SHORT_URL_START });\n\n const { selectedServer } = getState();\n const sendTagsSeparately = !supportsTagsInPatch(selectedServer);\n const { updateShortUrl, updateShortUrlTags } = buildShlinkApiClient(getState);\n\n try {\n const [ shortUrl ] = await Promise.all([\n updateShortUrl(shortCode, domain, data as any), // FIXME Parse dates\n sendTagsSeparately && data.tags ? updateShortUrlTags(shortCode, domain, data.tags) : undefined,\n ]);\n\n dispatch<ShortUrlEditedAction>({ shortUrl, type: SHORT_URL_EDITED });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: EDIT_SHORT_URL_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n","import { assoc, assocPath, last, pipe, reject } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { shortUrlMatches } from '../helpers';\nimport { CREATE_VISITS, CreateVisitsAction } from '../../visits/reducers/visitCreation';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { GetState } from '../../container/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ShlinkShortUrlsListParams, ShlinkShortUrlsResponse } from '../../api/types';\nimport { DeleteShortUrlAction, SHORT_URL_DELETED } from './shortUrlDeletion';\nimport { CREATE_SHORT_URL, CreateShortUrlAction } from './shortUrlCreation';\nimport { SHORT_URL_EDITED, ShortUrlEditedAction } from './shortUrlEdition';\n\n/* eslint-disable padding-line-between-statements */\nexport const LIST_SHORT_URLS_START = 'shlink/shortUrlsList/LIST_SHORT_URLS_START';\nexport const LIST_SHORT_URLS_ERROR = 'shlink/shortUrlsList/LIST_SHORT_URLS_ERROR';\nexport const LIST_SHORT_URLS = 'shlink/shortUrlsList/LIST_SHORT_URLS';\n/* eslint-enable padding-line-between-statements */\n\nexport const ITEMS_IN_OVERVIEW_PAGE = 5;\n\nexport interface ShortUrlsList {\n shortUrls?: ShlinkShortUrlsResponse;\n loading: boolean;\n error: boolean;\n}\n\nexport interface ListShortUrlsAction extends Action<string> {\n shortUrls: ShlinkShortUrlsResponse;\n}\n\nexport type ListShortUrlsCombinedAction = (\n ListShortUrlsAction\n & CreateVisitsAction\n & CreateShortUrlAction\n & DeleteShortUrlAction\n & ShortUrlEditedAction\n);\n\nconst initialState: ShortUrlsList = {\n loading: true,\n error: false,\n};\n\nexport default buildReducer<ShortUrlsList, ListShortUrlsCombinedAction>({\n [LIST_SHORT_URLS_START]: (state) => ({ ...state, loading: true, error: false }),\n [LIST_SHORT_URLS_ERROR]: () => ({ loading: false, error: true }),\n [LIST_SHORT_URLS]: (_, { shortUrls }) => ({ loading: false, error: false, shortUrls }),\n [SHORT_URL_DELETED]: pipe(\n (state: ShortUrlsList, { shortCode, domain }: DeleteShortUrlAction) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'data' ],\n reject((shortUrl) => shortUrlMatches(shortUrl, shortCode, domain), state.shortUrls.data),\n state,\n ),\n (state) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'pagination', 'totalItems' ],\n state.shortUrls.pagination.totalItems - 1,\n state,\n ),\n ),\n [CREATE_VISITS]: (state, { createdVisits }) => assocPath(\n [ 'shortUrls', 'data' ],\n state.shortUrls?.data?.map(\n (currentShortUrl) => {\n // Find the last of the new visit for this short URL, and pick the amount of visits from it\n const lastVisit = last(\n createdVisits.filter(\n ({ shortUrl }) => shortUrl && shortUrlMatches(currentShortUrl, shortUrl.shortCode, shortUrl.domain),\n ),\n );\n\n return lastVisit?.shortUrl\n ? assoc('visitsCount', lastVisit.shortUrl.visitsCount, currentShortUrl)\n : currentShortUrl;\n },\n ),\n state,\n ),\n [CREATE_SHORT_URL]: pipe(\n // The only place where the list and the creation form coexist is the overview page.\n // There we can assume we are displaying page 1, and therefore, we can safely prepend the new short URL.\n // We can also remove the items above the amount that is displayed there.\n (state: ShortUrlsList, { result }: CreateShortUrlAction) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'data' ],\n [ result, ...state.shortUrls.data.slice(0, ITEMS_IN_OVERVIEW_PAGE - 1) ],\n state,\n ),\n (state: ShortUrlsList) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'pagination', 'totalItems' ],\n state.shortUrls.pagination.totalItems + 1,\n state,\n ),\n ),\n [SHORT_URL_EDITED]: (state, { shortUrl: editedShortUrl }) => !state.shortUrls ? state : assocPath(\n [ 'shortUrls', 'data' ],\n state.shortUrls.data.map((shortUrl) => {\n const { shortCode, domain } = editedShortUrl;\n\n return shortUrlMatches(shortUrl, shortCode, domain) ? editedShortUrl : shortUrl;\n }),\n state,\n ),\n}, initialState);\n\nexport const listShortUrls = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n params: ShlinkShortUrlsListParams = {},\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: LIST_SHORT_URLS_START });\n const { listShortUrls } = buildShlinkApiClient(getState);\n\n try {\n const shortUrls = await listShortUrls(params);\n\n dispatch<ListShortUrlsAction>({ type: LIST_SHORT_URLS, shortUrls });\n } catch (e) {\n dispatch({ type: LIST_SHORT_URLS_ERROR });\n }\n};\n","import { FC, ReactNode } from 'react';\nimport { isEmpty } from 'ramda';\nimport classNames from 'classnames';\nimport { SelectedServer } from '../servers/data';\nimport { supportsShortUrlTitle } from '../utils/helpers/features';\nimport { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';\nimport { ShortUrlsRowProps } from './helpers/ShortUrlsRow';\nimport { ShortUrlsOrderableFields } from './data';\nimport './ShortUrlsTable.scss';\n\nexport interface ShortUrlsTableProps {\n orderByColumn?: (column: ShortUrlsOrderableFields) => () => void;\n renderOrderIcon?: (column: ShortUrlsOrderableFields) => ReactNode;\n shortUrlsList: ShortUrlsListState;\n selectedServer: SelectedServer;\n onTagClick?: (tag: string) => void;\n className?: string;\n}\n\nexport const ShortUrlsTable = (ShortUrlsRow: FC<ShortUrlsRowProps>) => ({\n orderByColumn,\n renderOrderIcon,\n shortUrlsList,\n onTagClick,\n selectedServer,\n className,\n}: ShortUrlsTableProps) => {\n const { error, loading, shortUrls } = shortUrlsList;\n const actionableFieldClasses = classNames({ 'short-urls-table__header-cell--with-action': !!orderByColumn });\n const orderableColumnsClasses = classNames('short-urls-table__header-cell', actionableFieldClasses);\n const tableClasses = classNames('table table-hover', className);\n const supportsTitle = supportsShortUrlTitle(selectedServer);\n\n const renderShortUrls = () => {\n if (error) {\n return (\n <tr>\n <td colSpan={6} className=\"text-center table-danger text-dark\">\n Something went wrong while loading short URLs :(\n </td>\n </tr>\n );\n }\n\n if (loading) {\n return <tr><td colSpan={6} className=\"text-center\">Loading...</td></tr>;\n }\n\n if (!loading && isEmpty(shortUrls?.data)) {\n return <tr><td colSpan={6} className=\"text-center\">No results found</td></tr>;\n }\n\n return shortUrls?.data.map((shortUrl) => (\n <ShortUrlsRow\n key={shortUrl.shortUrl}\n shortUrl={shortUrl}\n selectedServer={selectedServer}\n onTagClick={onTagClick}\n />\n ));\n };\n\n return (\n <table className={tableClasses}>\n <thead className=\"responsive-table__header short-urls-table__header\">\n <tr>\n <th className={orderableColumnsClasses} onClick={orderByColumn?.('dateCreated')}>\n Created at {renderOrderIcon?.('dateCreated')}\n </th>\n <th className={orderableColumnsClasses} onClick={orderByColumn?.('shortCode')}>\n Short URL {renderOrderIcon?.('shortCode')}\n </th>\n {!supportsTitle && (\n <th className={orderableColumnsClasses} onClick={orderByColumn?.('longUrl')}>\n Long URL {renderOrderIcon?.('longUrl')}\n </th>\n ) || (\n <th className=\"short-urls-table__header-cell\">\n <span className={actionableFieldClasses} onClick={orderByColumn?.('title')}>\n Title {renderOrderIcon?.('title')}\n </span>\n / \n <span className={actionableFieldClasses} onClick={orderByColumn?.('longUrl')}>\n <span className=\"indivisible\">Long URL</span> {renderOrderIcon?.('longUrl')}\n </span>\n </th>\n )}\n <th className=\"short-urls-table__header-cell\">Tags</th>\n <th className={orderableColumnsClasses} onClick={orderByColumn?.('visits')}>\n <span className=\"indivisible\">Visits {renderOrderIcon?.('visits')}</span>\n </th>\n <th className=\"short-urls-table__header-cell\"> </th>\n </tr>\n </thead>\n <tbody>\n {renderShortUrls()}\n </tbody>\n </table>\n );\n};\n","import { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { DropdownBtn } from '../../../utils/DropdownBtn';\nimport { QrCodeFormat } from '../../../utils/helpers/qrCodes';\n\ninterface QrFormatDropdownProps {\n format: QrCodeFormat;\n setFormat: (format: QrCodeFormat) => void;\n}\n\nexport const QrFormatDropdown: FC<QrFormatDropdownProps> = ({ format, setFormat }) => (\n <DropdownBtn text={`Format (${format})`}>\n <DropdownItem active={format === 'png'} onClick={() => setFormat('png')}>PNG</DropdownItem>\n <DropdownItem active={format === 'svg'} onClick={() => setFormat('svg')}>SVG</DropdownItem>\n </DropdownBtn>\n);\n","import { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { DropdownBtn } from '../../../utils/DropdownBtn';\nimport { QrErrorCorrection } from '../../../utils/helpers/qrCodes';\n\ninterface QrErrorCorrectionDropdownProps {\n errorCorrection: QrErrorCorrection;\n setErrorCorrection: (errorCorrection: QrErrorCorrection) => void;\n}\n\nexport const QrErrorCorrectionDropdown: FC<QrErrorCorrectionDropdownProps> = (\n { errorCorrection, setErrorCorrection },\n) => (\n <DropdownBtn text={`Error correction (${errorCorrection})`}>\n <DropdownItem active={errorCorrection === 'L'} onClick={() => setErrorCorrection('L')}>\n <b>L</b>ow\n </DropdownItem>\n <DropdownItem active={errorCorrection === 'M'} onClick={() => setErrorCorrection('M')}>\n <b>M</b>edium\n </DropdownItem>\n <DropdownItem active={errorCorrection === 'Q'} onClick={() => setErrorCorrection('Q')}>\n <b>Q</b>uartile\n </DropdownItem>\n <DropdownItem active={errorCorrection === 'H'} onClick={() => setErrorCorrection('H')}>\n <b>H</b>igh\n </DropdownItem>\n </DropdownBtn>\n);\n","import { FC, useMemo, useState } from 'react';\nimport { Modal, FormGroup, ModalBody, ModalHeader, Row, Button } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faFileDownload as downloadIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ExternalLink } from 'react-external-link';\nimport classNames from 'classnames';\nimport { ShortUrlModalProps } from '../data';\nimport { SelectedServer } from '../../servers/data';\nimport { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon';\nimport { buildQrCodeUrl, QrCodeCapabilities, QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes';\nimport {\n supportsQrCodeSizeInQuery,\n supportsQrCodeMargin,\n supportsQrErrorCorrection,\n} from '../../utils/helpers/features';\nimport { ImageDownloader } from '../../common/services/ImageDownloader';\nimport { Versions } from '../../utils/helpers/version';\nimport { QrFormatDropdown } from './qr-codes/QrFormatDropdown';\nimport './QrCodeModal.scss';\nimport { QrErrorCorrectionDropdown } from './qr-codes/QrErrorCorrectionDropdown';\n\ninterface QrCodeModalConnectProps extends ShortUrlModalProps {\n selectedServer: SelectedServer;\n}\n\nconst QrCodeModal = (imageDownloader: ImageDownloader, ForServerVersion: FC<Versions>) => ( // eslint-disable-line\n { shortUrl: { shortUrl, shortCode }, toggle, isOpen, selectedServer }: QrCodeModalConnectProps,\n) => {\n const [ size, setSize ] = useState(300);\n const [ margin, setMargin ] = useState(0);\n const [ format, setFormat ] = useState<QrCodeFormat>('png');\n const [ errorCorrection, setErrorCorrection ] = useState<QrErrorCorrection>('L');\n const capabilities: QrCodeCapabilities = useMemo(() => ({\n useSizeInPath: !supportsQrCodeSizeInQuery(selectedServer),\n marginIsSupported: supportsQrCodeMargin(selectedServer),\n errorCorrectionIsSupported: supportsQrErrorCorrection(selectedServer),\n }), [ selectedServer ]);\n const willRenderThreeControls = capabilities.marginIsSupported !== capabilities.errorCorrectionIsSupported;\n const qrCodeUrl = useMemo(\n () => buildQrCodeUrl(shortUrl, { size, format, margin, errorCorrection }, capabilities),\n [ shortUrl, size, format, margin, errorCorrection, capabilities ],\n );\n const totalSize = useMemo(() => size + margin, [ size, margin ]);\n const modalSize = useMemo(() => {\n if (totalSize < 500) {\n return undefined;\n }\n\n return totalSize < 800 ? 'lg' : 'xl';\n }, [ totalSize ]);\n\n return (\n <Modal isOpen={isOpen} toggle={toggle} centered size={modalSize}>\n <ModalHeader toggle={toggle}>\n QR code for <ExternalLink href={shortUrl}>{shortUrl}</ExternalLink>\n </ModalHeader>\n <ModalBody>\n <Row>\n <FormGroup\n className={classNames({ 'col-md-4': willRenderThreeControls, 'col-md-6': !willRenderThreeControls })}\n >\n <label className=\"mb-0\">Size: {size}px</label>\n <input\n type=\"range\"\n className=\"form-control-range\"\n value={size}\n step={10}\n min={50}\n max={1000}\n onChange={(e) => setSize(Number(e.target.value))}\n />\n </FormGroup>\n {capabilities.marginIsSupported && (\n <FormGroup className={willRenderThreeControls ? 'col-md-4' : 'col-md-6'}>\n <label className=\"mb-0\">Margin: {margin}px</label>\n <input\n type=\"range\"\n className=\"form-control-range\"\n value={margin}\n step={1}\n min={0}\n max={100}\n onChange={(e) => setMargin(Number(e.target.value))}\n />\n </FormGroup>\n )}\n <FormGroup className={willRenderThreeControls ? 'col-md-4' : 'col-md-6'}>\n <QrFormatDropdown format={format} setFormat={setFormat} />\n </FormGroup>\n {capabilities.errorCorrectionIsSupported && (\n <FormGroup className=\"col-md-6\">\n <QrErrorCorrectionDropdown errorCorrection={errorCorrection} setErrorCorrection={setErrorCorrection} />\n </FormGroup>\n )}\n </Row>\n <div className=\"text-center\">\n <div className=\"mb-3\">\n <ExternalLink href={qrCodeUrl} />\n <CopyToClipboardIcon text={qrCodeUrl} />\n </div>\n <img src={qrCodeUrl} className=\"qr-code-modal__img\" alt=\"QR code\" />\n <ForServerVersion minVersion=\"2.9.0\">\n <div className=\"mt-3\">\n <Button\n block\n color=\"primary\"\n onClick={async () => imageDownloader.saveImage(qrCodeUrl, `${shortCode}-qr-code.${format}`)}\n >\n Download <FontAwesomeIcon icon={downloadIcon} className=\"ml-1\" />\n </Button>\n </div>\n </ForServerVersion>\n </div>\n </ModalBody>\n </Modal>\n );\n};\n\nexport default QrCodeModal;\n","import { isEmpty } from 'ramda';\nimport { stringifyQuery } from './query';\n\nexport interface QrCodeCapabilities {\n useSizeInPath: boolean;\n marginIsSupported: boolean;\n errorCorrectionIsSupported: boolean;\n}\n\nexport type QrCodeFormat = 'svg' | 'png';\n\nexport type QrErrorCorrection = 'L' | 'M' | 'Q' | 'H';\n\nexport interface QrCodeOptions {\n size: number;\n format: QrCodeFormat;\n margin: number;\n errorCorrection: QrErrorCorrection;\n}\n\nexport const buildQrCodeUrl = (\n shortUrl: string,\n { size, format, margin, errorCorrection }: QrCodeOptions,\n { useSizeInPath, marginIsSupported, errorCorrectionIsSupported }: QrCodeCapabilities,\n): string => {\n const baseUrl = `${shortUrl}/qr-code${useSizeInPath ? `/${size}` : ''}`;\n const query = stringifyQuery({\n size: useSizeInPath ? undefined : size,\n format,\n margin: marginIsSupported && margin > 0 ? margin : undefined,\n errorCorrection: errorCorrectionIsSupported ? errorCorrection : undefined,\n });\n\n return `${baseUrl}${isEmpty(query) ? '' : `?${query}`}`;\n};\n","import { ChangeEvent, FC, useRef } from 'react';\nimport classNames from 'classnames';\nimport { v4 as uuid } from 'uuid';\nimport { identity } from 'ramda';\n\nexport interface BooleanControlProps {\n checked?: boolean;\n onChange?: (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void;\n className?: string;\n inline?: boolean;\n}\n\ninterface BooleanControlWithTypeProps extends BooleanControlProps {\n type: 'switch' | 'checkbox';\n}\n\nconst BooleanControl: FC<BooleanControlWithTypeProps> = (\n { checked = false, onChange = identity, className, children, type, inline = false },\n) => {\n const { current: id } = useRef(uuid());\n const onChecked = (e: ChangeEvent<HTMLInputElement>) => onChange(e.target.checked, e);\n const typeClasses = {\n 'custom-switch': type === 'switch',\n 'custom-checkbox': type === 'checkbox',\n };\n const style = inline ? { display: 'inline-block' } : {};\n\n return (\n <span className={classNames('custom-control', typeClasses, className)} style={style}>\n <input type=\"checkbox\" className=\"custom-control-input\" id={id} checked={checked} onChange={onChecked} />\n <label className=\"custom-control-label\" htmlFor={id}>{children}</label>\n </span>\n );\n};\n\nexport default BooleanControl;\n","import { FC } from 'react';\nimport BooleanControl, { BooleanControlProps } from './BooleanControl';\n\nconst Checkbox: FC<BooleanControlProps> = (props) => <BooleanControl type=\"checkbox\" {...props} />;\n\nexport default Checkbox;\n","import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';\nimport { Modal, ModalBody, ModalHeader } from 'reactstrap';\nimport { useToggle } from '../utils/helpers/hooks';\nimport './UseExistingIfFoundInfoIcon.scss';\n\nconst InfoModal = ({ isOpen, toggle }: { isOpen: boolean; toggle: () => void }) => (\n <Modal isOpen={isOpen} toggle={toggle} centered size=\"lg\">\n <ModalHeader toggle={toggle}>Info</ModalHeader>\n <ModalBody>\n <p>\n When the \n <b><i>"Use existing URL if found"</i></b>\n checkbox is checked, the server will return an existing short URL if it matches provided params.\n </p>\n <p>\n These are the checks performed by Shlink in order to determine if an existing short URL should be returned:\n </p>\n <ul>\n <li>\n When only the long URL is provided: The most recent match will be returned, or a new short URL will be created\n if none is found.\n </li>\n <li>\n When long URL and custom slug and/or domain are provided: Same as in previous case, but it will try to match\n the short URL using both the long URL and the slug, the long URL and the domain, or the three of them.\n <br />\n If the slug is being used by another long URL, an error will be returned.\n </li>\n <li>\n When other params are provided: Same as in previous cases, but it will try to match existing short URLs with\n all provided data. If any of them does not match, a new short URL will be created\n </li>\n </ul>\n </ModalBody>\n </Modal>\n);\n\nconst UseExistingIfFoundInfoIcon = () => {\n const [ isModalOpen, toggleModal ] = useToggle();\n\n return (\n <>\n <span title=\"What does this mean?\">\n <FontAwesomeIcon icon={infoIcon} style={{ cursor: 'pointer' }} onClick={toggleModal} />\n </span>\n <InfoModal isOpen={isModalOpen} toggle={toggleModal} />\n </>\n );\n};\n\nexport default UseExistingIfFoundInfoIcon;\n","import { FC, useRef } from 'react';\nimport * as Popper from 'popper.js';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';\nimport { UncontrolledTooltip } from 'reactstrap';\n\ninterface InfoTooltipProps {\n className?: string;\n placement: Popper.Placement;\n}\n\nexport const InfoTooltip: FC<InfoTooltipProps> = ({ className = '', placement, children }) => {\n const ref = useRef<HTMLSpanElement | null>();\n const refCallback = (el: HTMLSpanElement) => {\n ref.current = el;\n };\n\n return (\n <>\n <span className={className} ref={refCallback}>\n <FontAwesomeIcon icon={infoIcon} />\n </span>\n <UncontrolledTooltip target={(() => ref.current) as any} placement={placement}>{children}</UncontrolledTooltip>\n </>\n );\n};\n","import { ChangeEvent, FC } from 'react';\nimport Checkbox from '../../utils/Checkbox';\nimport { InfoTooltip } from '../../utils/InfoTooltip';\n\ninterface ShortUrlFormCheckboxGroupProps {\n checked?: boolean;\n onChange?: (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void;\n infoTooltip?: string;\n}\n\nexport const ShortUrlFormCheckboxGroup: FC<ShortUrlFormCheckboxGroupProps> = (\n { children, infoTooltip, checked, onChange },\n) => (\n <p>\n <Checkbox inline checked={checked} className={infoTooltip ? 'mr-2' : ''} onChange={onChange}>\n {children}\n </Checkbox>\n {infoTooltip && <InfoTooltip placement=\"right\">{infoTooltip}</InfoTooltip>}\n </p>\n);\n","import { FC, useEffect, useState } from 'react';\nimport { InputType } from 'reactstrap/lib/Input';\nimport { Button, FormGroup, Input, Row } from 'reactstrap';\nimport { cond, isEmpty, pipe, replace, trim, T } from 'ramda';\nimport classNames from 'classnames';\nimport { parseISO } from 'date-fns';\nimport DateInput, { DateInputProps } from '../utils/DateInput';\nimport { supportsCrawlableVisits, supportsForwardQuery, supportsShortUrlTitle } from '../utils/helpers/features';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { handleEventPreventingDefault, hasValue, OptionalString } from '../utils/utils';\nimport Checkbox from '../utils/Checkbox';\nimport { SelectedServer } from '../servers/data';\nimport { TagsSelectorProps } from '../tags/helpers/TagsSelector';\nimport { DomainSelectorProps } from '../domains/DomainSelector';\nimport { formatIsoDate } from '../utils/helpers/date';\nimport UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon';\nimport { ShortUrlData } from './data';\nimport { ShortUrlFormCheckboxGroup } from './helpers/ShortUrlFormCheckboxGroup';\nimport './ShortUrlForm.scss';\n\nexport type Mode = 'create' | 'create-basic' | 'edit';\n\ntype DateFields = 'validSince' | 'validUntil';\ntype NonDateFields = 'longUrl' | 'customSlug' | 'shortCodeLength' | 'domain' | 'maxVisits' | 'title';\n\nexport interface ShortUrlFormProps {\n mode: Mode;\n saving: boolean;\n initialState: ShortUrlData;\n onSave: (shortUrlData: ShortUrlData) => Promise<unknown>;\n selectedServer: SelectedServer;\n}\n\nconst normalizeTag = pipe(trim, replace(/ /g, '-'));\nconst toDate = (date?: string | Date): Date | undefined => typeof date === 'string' ? parseISO(date) : date;\nconst dynamicColClasses = (flag: boolean) => ({ 'col-sm-6': flag, 'col-sm-12': !flag });\n\nexport const ShortUrlForm = (\n TagsSelector: FC<TagsSelectorProps>,\n DomainSelector: FC<DomainSelectorProps>,\n): FC<ShortUrlFormProps> => ({ mode, saving, onSave, initialState, selectedServer }) => {\n const [ shortUrlData, setShortUrlData ] = useState(initialState);\n const isEdit = mode === 'edit';\n const isBasicMode = mode === 'create-basic';\n const hadTitleOriginally = hasValue(initialState.title);\n const changeTags = (tags: string[]) => setShortUrlData({ ...shortUrlData, tags: tags.map(normalizeTag) });\n const reset = () => setShortUrlData(initialState);\n const resolveNewTitle = (): OptionalString => {\n const hasNewTitle = hasValue(shortUrlData.title);\n const matcher = cond<never, OptionalString>([\n [ () => !hasNewTitle && !hadTitleOriginally, () => undefined ],\n [ () => !hasNewTitle && hadTitleOriginally, () => null ],\n [ T, () => shortUrlData.title ],\n ]);\n\n return matcher();\n };\n const submit = handleEventPreventingDefault(async () => onSave({\n ...shortUrlData,\n validSince: formatIsoDate(shortUrlData.validSince) ?? null,\n validUntil: formatIsoDate(shortUrlData.validUntil) ?? null,\n maxVisits: !hasValue(shortUrlData.maxVisits) ? null : Number(shortUrlData.maxVisits),\n title: resolveNewTitle(),\n }).then(() => !isEdit && reset()).catch(() => {}));\n\n useEffect(() => {\n setShortUrlData(initialState);\n }, [ initialState ]);\n\n const renderOptionalInput = (\n id: NonDateFields,\n placeholder: string,\n type: InputType = 'text',\n props = {},\n fromGroupProps = {},\n ) => (\n <FormGroup {...fromGroupProps}>\n <Input\n id={id}\n type={type}\n placeholder={placeholder}\n value={shortUrlData[id] ?? ''}\n onChange={(e) => setShortUrlData({ ...shortUrlData, [id]: e.target.value })}\n {...props}\n />\n </FormGroup>\n );\n const renderDateInput = (id: DateFields, placeholder: string, props: Partial<DateInputProps> = {}) => (\n <div className=\"form-group\">\n <DateInput\n selected={shortUrlData[id] ? toDate(shortUrlData[id] as string | Date) : null}\n placeholderText={placeholder}\n isClearable\n onChange={(date) => setShortUrlData({ ...shortUrlData, [id]: date })}\n {...props}\n />\n </div>\n );\n const basicComponents = (\n <>\n <FormGroup>\n <Input\n bsSize=\"lg\"\n type=\"url\"\n placeholder=\"URL to be shortened\"\n required\n value={shortUrlData.longUrl}\n onChange={(e) => setShortUrlData({ ...shortUrlData, longUrl: e.target.value })}\n />\n </FormGroup>\n <Row>\n {isBasicMode && renderOptionalInput('customSlug', 'Custom slug', 'text', { bsSize: 'lg' }, { className: 'col-lg-6' })}\n <FormGroup className={isBasicMode ? 'col-lg-6' : 'col-12 mb-0'}>\n <TagsSelector selectedTags={shortUrlData.tags ?? []} onChange={changeTags} />\n </FormGroup>\n </Row>\n </>\n );\n\n const supportsTitle = supportsShortUrlTitle(selectedServer);\n const showCustomizeCard = supportsTitle || !isEdit;\n const limitAccessCardClasses = classNames('mb-3', dynamicColClasses(showCustomizeCard));\n const showCrawlableControl = supportsCrawlableVisits(selectedServer);\n const showForwardQueryControl = supportsForwardQuery(selectedServer);\n const showBehaviorCard = showCrawlableControl || showForwardQueryControl;\n const extraChecksCardClasses = classNames('mb-3', dynamicColClasses(showBehaviorCard));\n\n return (\n <form className=\"short-url-form\" onSubmit={submit}>\n {isBasicMode && basicComponents}\n {!isBasicMode && (\n <>\n <SimpleCard title=\"Basic options\" className=\"mb-3\">\n {basicComponents}\n </SimpleCard>\n\n <Row>\n {showCustomizeCard && (\n <div className=\"col-sm-6 mb-3\">\n <SimpleCard title=\"Customize the short URL\">\n {supportsTitle && renderOptionalInput('title', 'Title')}\n {!isEdit && (\n <>\n <Row>\n <div className=\"col-lg-6\">\n {renderOptionalInput('customSlug', 'Custom slug', 'text', {\n disabled: hasValue(shortUrlData.shortCodeLength),\n })}\n </div>\n <div className=\"col-lg-6\">\n {renderOptionalInput('shortCodeLength', 'Short code length', 'number', {\n min: 4,\n disabled: hasValue(shortUrlData.customSlug),\n })}\n </div>\n </Row>\n <FormGroup>\n <DomainSelector\n value={shortUrlData.domain}\n onChange={(domain?: string) => setShortUrlData({ ...shortUrlData, domain })}\n />\n </FormGroup>\n </>\n )}\n </SimpleCard>\n </div>\n )}\n\n <div className={limitAccessCardClasses}>\n <SimpleCard title=\"Limit access to the short URL\">\n {renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}\n {renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlData.validUntil ? toDate(shortUrlData.validUntil) : undefined })}\n {renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlData.validSince ? toDate(shortUrlData.validSince) : undefined })}\n </SimpleCard>\n </div>\n </Row>\n\n <Row>\n <div className={extraChecksCardClasses}>\n <SimpleCard title=\"Extra checks\">\n <ShortUrlFormCheckboxGroup\n infoTooltip=\"If checked, Shlink will try to reach the long URL, failing in case it's not publicly accessible.\"\n checked={shortUrlData.validateUrl}\n onChange={(validateUrl) => setShortUrlData({ ...shortUrlData, validateUrl })}\n >\n Validate URL\n </ShortUrlFormCheckboxGroup>\n {!isEdit && (\n <p>\n <Checkbox\n inline\n className=\"mr-2\"\n checked={shortUrlData.findIfExists}\n onChange={(findIfExists) => setShortUrlData({ ...shortUrlData, findIfExists })}\n >\n Use existing URL if found\n </Checkbox>\n <UseExistingIfFoundInfoIcon />\n </p>\n )}\n </SimpleCard>\n </div>\n {showBehaviorCard && (\n <div className=\"col-sm-6 mb-3\">\n <SimpleCard title=\"Configure behavior\">\n {showCrawlableControl && (\n <ShortUrlFormCheckboxGroup\n infoTooltip=\"This short URL will be included in the robots.txt for your Shlink instance, allowing web crawlers (like Google) to index it.\"\n checked={shortUrlData.crawlable}\n onChange={(crawlable) => setShortUrlData({ ...shortUrlData, crawlable })}\n >\n Make it crawlable\n </ShortUrlFormCheckboxGroup>\n )}\n {showForwardQueryControl && (\n <ShortUrlFormCheckboxGroup\n infoTooltip=\"When this short URL is visited, any query params appended to it will be forwarded to the long URL.\"\n checked={shortUrlData.forwardQuery}\n onChange={(forwardQuery) => setShortUrlData({ ...shortUrlData, forwardQuery })}\n >\n Forward query params on redirect\n </ShortUrlFormCheckboxGroup>\n )}\n </SimpleCard>\n </div>\n )}\n </Row>\n </>\n )}\n\n <div className=\"text-center\">\n <Button\n outline\n color=\"primary\"\n disabled={saving || isEmpty(shortUrlData.longUrl)}\n className=\"btn-xs-block\"\n >\n {saving ? 'Saving...' : 'Save'}\n </Button>\n </div>\n </form>\n );\n};\n","import { FC, useEffect, useMemo } from 'react';\nimport { Button, Card } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faArrowLeft } from '@fortawesome/free-solid-svg-icons';\nimport { ExternalLink } from 'react-external-link';\nimport { useLocation, useParams } from 'react-router-dom';\nimport { SelectedServer } from '../servers/data';\nimport { Settings, ShortUrlCreationSettings } from '../settings/reducers/settings';\nimport { OptionalString } from '../utils/utils';\nimport { parseQuery } from '../utils/helpers/query';\nimport Message from '../utils/Message';\nimport { Result } from '../utils/Result';\nimport { ShlinkApiError } from '../api/ShlinkApiError';\nimport { useGoBack, useToggle } from '../utils/helpers/hooks';\nimport { ShortUrlFormProps } from './ShortUrlForm';\nimport { ShortUrlDetail } from './reducers/shortUrlDetail';\nimport { EditShortUrlData, ShortUrl, ShortUrlData } from './data';\nimport { ShortUrlEdition } from './reducers/shortUrlEdition';\n\ninterface EditShortUrlConnectProps {\n settings: Settings;\n selectedServer: SelectedServer;\n shortUrlDetail: ShortUrlDetail;\n shortUrlEdition: ShortUrlEdition;\n getShortUrlDetail: (shortCode: string, domain: OptionalString) => void;\n editShortUrl: (shortUrl: string, domain: OptionalString, data: EditShortUrlData) => Promise<void>;\n}\n\nconst getInitialState = (shortUrl?: ShortUrl, settings?: ShortUrlCreationSettings): ShortUrlData => {\n const validateUrl = settings?.validateUrls ?? false;\n\n if (!shortUrl) {\n return { longUrl: '', validateUrl };\n }\n\n return {\n longUrl: shortUrl.longUrl,\n tags: shortUrl.tags,\n title: shortUrl.title ?? undefined,\n domain: shortUrl.domain ?? undefined,\n validSince: shortUrl.meta.validSince ?? undefined,\n validUntil: shortUrl.meta.validUntil ?? undefined,\n maxVisits: shortUrl.meta.maxVisits ?? undefined,\n crawlable: shortUrl.crawlable,\n forwardQuery: shortUrl.forwardQuery,\n validateUrl,\n };\n};\n\nexport const EditShortUrl = (ShortUrlForm: FC<ShortUrlFormProps>) => ({\n settings: { shortUrlCreation: shortUrlCreationSettings },\n selectedServer,\n shortUrlDetail,\n getShortUrlDetail,\n shortUrlEdition,\n editShortUrl,\n}: EditShortUrlConnectProps) => {\n const { search } = useLocation();\n const params = useParams<{ shortCode: string }>();\n const goBack = useGoBack();\n const { loading, error, errorData, shortUrl } = shortUrlDetail;\n const { saving, error: savingError, errorData: savingErrorData } = shortUrlEdition;\n const { domain } = parseQuery<{ domain?: string }>(search);\n const initialState = useMemo(\n () => getInitialState(shortUrl, shortUrlCreationSettings),\n [ shortUrl, shortUrlCreationSettings ],\n );\n const [ savingSucceeded,, isSuccessful, isNotSuccessful ] = useToggle();\n\n useEffect(() => {\n params.shortCode && getShortUrlDetail(params.shortCode, domain);\n }, []);\n\n if (loading) {\n return <Message loading />;\n }\n\n if (error) {\n return (\n <Result type=\"error\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"An error occurred while loading short URL detail :(\" />\n </Result>\n );\n }\n\n return (\n <>\n <header className=\"mb-3\">\n <Card body>\n <h2 className=\"d-sm-flex justify-content-between align-items-center mb-0\">\n <Button color=\"link\" size=\"lg\" className=\"p-0 mr-3\" onClick={goBack}>\n <FontAwesomeIcon icon={faArrowLeft} />\n </Button>\n <span className=\"text-center\">\n <small>Edit <ExternalLink href={shortUrl?.shortUrl ?? ''} /></small>\n </span>\n <span />\n </h2>\n </Card>\n </header>\n <ShortUrlForm\n initialState={initialState}\n saving={saving}\n selectedServer={selectedServer}\n mode=\"edit\"\n onSave={async (shortUrlData) => {\n if (!shortUrl) {\n return;\n }\n\n isNotSuccessful();\n editShortUrl(shortUrl.shortCode, shortUrl.domain, shortUrlData)\n .then(isSuccessful)\n .catch(isNotSuccessful);\n }}\n />\n {savingError && (\n <Result type=\"error\" className=\"mt-3\">\n <ShlinkApiError errorData={savingErrorData} fallbackMessage=\"An error occurred while updating short URL :(\" />\n </Result>\n )}\n {savingSucceeded && <Result type=\"success\" className=\"mt-3\">Short URL properly edited.</Result>}\n </>\n );\n};\n","import { Action, Dispatch } from 'redux';\nimport { ShortUrl } from '../data';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { OptionalString } from '../../utils/utils';\nimport { GetState } from '../../container/types';\nimport { shortUrlMatches } from '../helpers';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_SHORT_URL_DETAIL_START = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL_START';\nexport const GET_SHORT_URL_DETAIL_ERROR = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL_ERROR';\nexport const GET_SHORT_URL_DETAIL = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlDetail {\n shortUrl?: ShortUrl;\n loading: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface ShortUrlDetailAction extends Action<string> {\n shortUrl: ShortUrl;\n}\n\nconst initialState: ShortUrlDetail = {\n loading: false,\n error: false,\n};\n\nexport default buildReducer<ShortUrlDetail, ShortUrlDetailAction & ApiErrorAction>({\n [GET_SHORT_URL_DETAIL_START]: () => ({ loading: true, error: false }),\n [GET_SHORT_URL_DETAIL_ERROR]: (_, { errorData }) => ({ loading: false, error: true, errorData }),\n [GET_SHORT_URL_DETAIL]: (_, { shortUrl }) => ({ shortUrl, ...initialState }),\n}, initialState);\n\nexport const getShortUrlDetail = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n shortCode: string,\n domain: OptionalString,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: GET_SHORT_URL_DETAIL_START });\n\n try {\n const { shortUrlsList } = getState();\n const shortUrl = shortUrlsList?.shortUrls?.data.find(\n (shortUrl) => shortUrlMatches(shortUrl, shortCode, domain),\n ) ?? await buildShlinkApiClient(getState).getShortUrl(shortCode, domain);\n\n dispatch<ShortUrlDetailAction>({ shortUrl, type: GET_SHORT_URL_DETAIL });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: GET_SHORT_URL_DETAIL_ERROR, errorData: parseApiError(e) });\n }\n};\n","import Bottle from 'bottlejs';\nimport ShortUrlsFilteringBar from '../ShortUrlsFilteringBar';\nimport ShortUrlsList from '../ShortUrlsList';\nimport ShortUrlsRow from '../helpers/ShortUrlsRow';\nimport ShortUrlsRowMenu from '../helpers/ShortUrlsRowMenu';\nimport CreateShortUrl from '../CreateShortUrl';\nimport DeleteShortUrlModal from '../helpers/DeleteShortUrlModal';\nimport CreateShortUrlResult from '../helpers/CreateShortUrlResult';\nimport { listShortUrls } from '../reducers/shortUrlsList';\nimport { createShortUrl, resetCreateShortUrl } from '../reducers/shortUrlCreation';\nimport { deleteShortUrl, resetDeleteShortUrl } from '../reducers/shortUrlDeletion';\nimport { editShortUrl } from '../reducers/shortUrlEdition';\nimport { ConnectDecorator } from '../../container/types';\nimport { ShortUrlsTable } from '../ShortUrlsTable';\nimport QrCodeModal from '../helpers/QrCodeModal';\nimport { ShortUrlForm } from '../ShortUrlForm';\nimport { EditShortUrl } from '../EditShortUrl';\nimport { getShortUrlDetail } from '../reducers/shortUrlDetail';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('ShortUrlsList', ShortUrlsList, 'ShortUrlsTable', 'ShortUrlsFilteringBar');\n bottle.decorator('ShortUrlsList', connect(\n [ 'selectedServer', 'mercureInfo', 'shortUrlsList', 'settings' ],\n [ 'listShortUrls', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n bottle.serviceFactory('ShortUrlsTable', ShortUrlsTable, 'ShortUrlsRow');\n bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator', 'useStateFlagTimeout');\n bottle.serviceFactory('ShortUrlsRowMenu', ShortUrlsRowMenu, 'DeleteShortUrlModal', 'QrCodeModal');\n bottle.serviceFactory('CreateShortUrlResult', CreateShortUrlResult, 'useStateFlagTimeout');\n bottle.serviceFactory('ShortUrlForm', ShortUrlForm, 'TagsSelector', 'DomainSelector');\n\n bottle.serviceFactory('CreateShortUrl', CreateShortUrl, 'ShortUrlForm', 'CreateShortUrlResult');\n bottle.decorator(\n 'CreateShortUrl',\n connect([ 'shortUrlCreationResult', 'selectedServer', 'settings' ], [ 'createShortUrl', 'resetCreateShortUrl' ]),\n );\n\n bottle.serviceFactory('EditShortUrl', EditShortUrl, 'ShortUrlForm');\n bottle.decorator('EditShortUrl', connect(\n [ 'shortUrlDetail', 'shortUrlEdition', 'selectedServer', 'settings' ],\n [ 'getShortUrlDetail', 'editShortUrl' ],\n ));\n\n bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal);\n bottle.decorator('DeleteShortUrlModal', connect([ 'shortUrlDeletion' ], [ 'deleteShortUrl', 'resetDeleteShortUrl' ]));\n\n bottle.serviceFactory('QrCodeModal', QrCodeModal, 'ImageDownloader', 'ForServerVersion');\n bottle.decorator('QrCodeModal', connect([ 'selectedServer' ]));\n\n bottle.serviceFactory('ShortUrlsFilteringBar', ShortUrlsFilteringBar, 'ColorGenerator');\n\n // Actions\n bottle.serviceFactory('listShortUrls', listShortUrls, 'buildShlinkApiClient');\n\n bottle.serviceFactory('createShortUrl', createShortUrl, 'buildShlinkApiClient');\n bottle.serviceFactory('resetCreateShortUrl', () => resetCreateShortUrl);\n\n bottle.serviceFactory('deleteShortUrl', deleteShortUrl, 'buildShlinkApiClient');\n bottle.serviceFactory('resetDeleteShortUrl', () => resetDeleteShortUrl);\n\n bottle.serviceFactory('getShortUrlDetail', getShortUrlDetail, 'buildShlinkApiClient');\n\n bottle.serviceFactory('editShortUrl', editShortUrl, 'buildShlinkApiClient');\n};\n\nexport default provideServices;\n","import { FC, useRef } from 'react';\nimport { v4 as uuid } from 'uuid';\nimport { InputType } from 'reactstrap/lib/Input';\nimport { FormGroup } from 'reactstrap';\n\nexport interface FormGroupContainerProps {\n value: string;\n onChange: (newValue: string) => void;\n id?: string;\n type?: InputType;\n required?: boolean;\n placeholder?: string;\n className?: string;\n labelClassName?: string;\n}\n\nexport const FormGroupContainer: FC<FormGroupContainerProps> = (\n { children, value, onChange, id, type, required, placeholder, className, labelClassName },\n) => {\n const forId = useRef<string>(id ?? uuid());\n\n return (\n <FormGroup className={className ?? ''}>\n <label htmlFor={forId.current} className={labelClassName ?? ''}>\n {children}:\n </label>\n <input\n className=\"form-control\"\n type={type ?? 'text'}\n id={forId.current}\n value={value}\n required={required ?? true}\n placeholder={placeholder}\n onChange={(e) => onChange(e.target.value)}\n />\n </FormGroup>\n );\n};\n","import { FC, ReactNode, useEffect, useState } from 'react';\nimport { FormGroupContainer, FormGroupContainerProps } from '../../utils/FormGroupContainer';\nimport { handleEventPreventingDefault } from '../../utils/utils';\nimport { ServerData } from '../data';\nimport { SimpleCard } from '../../utils/SimpleCard';\nimport './ServerForm.scss';\n\ninterface ServerFormProps {\n onSubmit: (server: ServerData) => void;\n initialValues?: ServerData;\n title?: ReactNode;\n}\n\nconst FormGroup: FC<FormGroupContainerProps> = (props) =>\n <FormGroupContainer {...props} labelClassName=\"server-form__label\" />;\n\nexport const ServerForm: FC<ServerFormProps> = ({ onSubmit, initialValues, children, title }) => {\n const [ name, setName ] = useState('');\n const [ url, setUrl ] = useState('');\n const [ apiKey, setApiKey ] = useState('');\n const handleSubmit = handleEventPreventingDefault(() => onSubmit({ name, url, apiKey }));\n\n useEffect(() => {\n initialValues && setName(initialValues.name);\n initialValues && setUrl(initialValues.url);\n initialValues && setApiKey(initialValues.apiKey);\n }, [ initialValues ]);\n\n return (\n <form className=\"server-form\" onSubmit={handleSubmit}>\n <SimpleCard className=\"mb-3\" title={title}>\n <FormGroup value={name} onChange={setName}>Name</FormGroup>\n <FormGroup type=\"url\" value={url} onChange={setUrl}>URL</FormGroup>\n <FormGroup value={apiKey} onChange={setApiKey}>API key</FormGroup>\n </SimpleCard>\n\n <div className=\"text-right\">{children}</div>\n </form>\n );\n};\n","import { FC, Fragment } from 'react';\nimport { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { ServerData } from '../data';\n\ninterface DuplicatedServersModalProps {\n duplicatedServers: ServerData[];\n isOpen: boolean;\n onDiscard: () => void;\n onSave: () => void;\n}\n\nexport const DuplicatedServersModal: FC<DuplicatedServersModalProps> = (\n { isOpen, duplicatedServers, onDiscard, onSave },\n) => {\n const hasMultipleServers = duplicatedServers.length > 1;\n\n return (\n <Modal centered isOpen={isOpen}>\n <ModalHeader>Duplicated server{hasMultipleServers && 's'}</ModalHeader>\n <ModalBody>\n <p>{hasMultipleServers ? 'The next servers already exist:' : 'There is already a server with:'}</p>\n <ul>\n {duplicatedServers.map(({ url, apiKey }, index) => !hasMultipleServers ? (\n <Fragment key={index}>\n <li>URL: <b>{url}</b></li>\n <li>API key: <b>{apiKey}</b></li>\n </Fragment>\n ) : <li key={index}><b>{url}</b> - <b>{apiKey}</b></li>)}\n </ul>\n <span>\n {hasMultipleServers ? 'Do you want to ignore duplicated servers' : 'Do you want to save this server anyway'}?\n </span>\n </ModalBody>\n <ModalFooter>\n <Button color=\"link\" onClick={onDiscard}>{hasMultipleServers ? 'Ignore duplicated' : 'Discard'}</Button>\n <Button color=\"primary\" onClick={onSave}>Save anyway</Button>\n </ModalFooter>\n </Modal>\n );\n};\n","import { FC, useEffect, useState } from 'react';\nimport { v4 as uuid } from 'uuid';\nimport { Button } from 'reactstrap';\nimport { useNavigate } from 'react-router-dom';\nimport { Result } from '../utils/Result';\nimport { NoMenuLayout } from '../common/NoMenuLayout';\nimport { StateFlagTimeout, useGoBack, useToggle } from '../utils/helpers/hooks';\nimport { ServerForm } from './helpers/ServerForm';\nimport { ImportServersBtnProps } from './helpers/ImportServersBtn';\nimport { ServerData, ServersMap, ServerWithId } from './data';\nimport { DuplicatedServersModal } from './helpers/DuplicatedServersModal';\n\nconst SHOW_IMPORT_MSG_TIME = 4000;\n\ninterface CreateServerProps {\n createServer: (server: ServerWithId) => void;\n servers: ServersMap;\n}\n\nconst ImportResult = ({ type }: { type: 'error' | 'success' }) => (\n <div className=\"mt-3\">\n <Result type={type}>\n {type === 'success' && 'Servers properly imported. You can now select one from the list :)'}\n {type === 'error' && 'The servers could not be imported. Make sure the format is correct.'}\n </Result>\n </div>\n);\n\nconst CreateServer = (ImportServersBtn: FC<ImportServersBtnProps>, useStateFlagTimeout: StateFlagTimeout) => (\n { servers, createServer }: CreateServerProps,\n) => {\n const navigate = useNavigate();\n const goBack = useGoBack();\n const hasServers = !!Object.keys(servers).length;\n const [ serversImported, setServersImported ] = useStateFlagTimeout(false, SHOW_IMPORT_MSG_TIME);\n const [ errorImporting, setErrorImporting ] = useStateFlagTimeout(false, SHOW_IMPORT_MSG_TIME);\n const [ isConfirmModalOpen, toggleConfirmModal ] = useToggle();\n const [ serverData, setServerData ] = useState<ServerData | undefined>();\n const save = () => {\n if (!serverData) {\n return;\n }\n\n const id = uuid();\n\n createServer({ ...serverData, id });\n navigate(`/server/${id}`);\n };\n\n useEffect(() => {\n const serverExists = Object.values(servers).some(\n ({ url, apiKey }) => serverData?.url === url && serverData?.apiKey === apiKey,\n );\n\n serverExists ? toggleConfirmModal() : save();\n }, [ serverData ]);\n\n return (\n <NoMenuLayout>\n <ServerForm title={<h5 className=\"mb-0\">Add new server</h5>} onSubmit={setServerData}>\n {!hasServers &&\n <ImportServersBtn tooltipPlacement=\"top\" onImport={setServersImported} onImportError={setErrorImporting} />}\n {hasServers && <Button outline onClick={goBack}>Cancel</Button>}\n <Button outline color=\"primary\" className=\"ml-2\">Create server</Button>\n </ServerForm>\n\n {serversImported && <ImportResult type=\"success\" />}\n {errorImporting && <ImportResult type=\"error\" />}\n\n <DuplicatedServersModal\n isOpen={isConfirmModalOpen}\n duplicatedServers={serverData ? [ serverData ] : []}\n onDiscard={goBack}\n onSave={save}\n />\n </NoMenuLayout>\n );\n};\n\nexport default CreateServer;\n","import { isEmpty, values } from 'ramda';\nimport { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';\nimport { Link } from 'react-router-dom';\nimport { faPlus as plusIcon, faServer as serverIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { getServerId, SelectedServer, ServersMap } from './data';\n\nexport interface ServersDropdownProps {\n servers: ServersMap;\n selectedServer: SelectedServer;\n}\n\nconst ServersDropdown = ({ servers, selectedServer }: ServersDropdownProps) => {\n const serversList = values(servers);\n\n const renderServers = () => {\n if (isEmpty(serversList)) {\n return (\n <DropdownItem tag={Link} to=\"/server/create\">\n <FontAwesomeIcon icon={plusIcon} /> <span className=\"ml-1\">Add a server</span>\n </DropdownItem>\n );\n }\n\n return (\n <>\n {serversList.map(({ name, id }) => (\n <DropdownItem key={id} tag={Link} to={`/server/${id}`} active={getServerId(selectedServer) === id}>\n {name}\n </DropdownItem>\n ))}\n <DropdownItem divider />\n <DropdownItem tag={Link} to=\"/manage-servers\">\n <FontAwesomeIcon icon={serverIcon} /> <span className=\"ml-1\">Manage servers</span>\n </DropdownItem>\n </>\n );\n };\n\n return (\n <UncontrolledDropdown nav inNavbar>\n <DropdownToggle nav caret>\n <FontAwesomeIcon icon={serverIcon} /> <span className=\"ml-1\">Servers</span>\n </DropdownToggle>\n <DropdownMenu right>{renderServers()}</DropdownMenu>\n </UncontrolledDropdown>\n );\n};\n\nexport default ServersDropdown;\n","import { FC } from 'react';\nimport { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { useNavigate } from 'react-router-dom';\nimport { ServerWithId } from './data';\n\nexport interface DeleteServerModalProps {\n server: ServerWithId;\n toggle: () => void;\n isOpen: boolean;\n redirectHome?: boolean;\n}\n\ninterface DeleteServerModalConnectProps extends DeleteServerModalProps {\n deleteServer: (server: ServerWithId) => void;\n}\n\nconst DeleteServerModal: FC<DeleteServerModalConnectProps> = (\n { server, toggle, isOpen, deleteServer, redirectHome = true },\n) => {\n const navigate = useNavigate();\n const closeModal = () => {\n deleteServer(server);\n toggle();\n redirectHome && navigate('/');\n };\n\n return (\n <Modal isOpen={isOpen} toggle={toggle} centered>\n <ModalHeader toggle={toggle}><span className=\"text-danger\">Remove server</span></ModalHeader>\n <ModalBody>\n <p>Are you sure you want to remove <b>{server ? server.name : ''}</b>?</p>\n <p>\n <i>\n No data will be deleted, only the access to this server will be removed from this device.\n You can create it again at any moment.\n </i>\n </p>\n </ModalBody>\n <ModalFooter>\n <button className=\"btn btn-link\" onClick={toggle}>Cancel</button>\n <button className=\"btn btn-danger\" onClick={() => closeModal()}>Delete</button>\n </ModalFooter>\n </Modal>\n );\n};\n\nexport default DeleteServerModal;\n","import { FC } from 'react';\nimport { faMinusCircle as deleteIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { DeleteServerModalProps } from './DeleteServerModal';\nimport { ServerWithId } from './data';\n\nexport interface DeleteServerButtonProps {\n server: ServerWithId;\n className?: string;\n textClassName?: string;\n}\n\nconst DeleteServerButton = (DeleteServerModal: FC<DeleteServerModalProps>): FC<DeleteServerButtonProps> => (\n { server, className, children, textClassName },\n) => {\n const [ isModalOpen, , showModal, hideModal ] = useToggle();\n\n return (\n <>\n <span className={className} onClick={showModal}>\n {!children && <FontAwesomeIcon fixedWidth icon={deleteIcon} />}\n <span className={textClassName}>{children ?? 'Remove this server'}</span>\n </span>\n\n <DeleteServerModal server={server} isOpen={isModalOpen} toggle={hideModal} />\n </>\n );\n};\n\nexport default DeleteServerButton;\n","import { FC } from 'react';\nimport { Button } from 'reactstrap';\nimport { NoMenuLayout } from '../common/NoMenuLayout';\nimport { useGoBack } from '../utils/helpers/hooks';\nimport { ServerForm } from './helpers/ServerForm';\nimport { withSelectedServer } from './helpers/withSelectedServer';\nimport { isServerWithId, ServerData } from './data';\n\ninterface EditServerProps {\n editServer: (serverId: string, serverData: ServerData) => void;\n}\n\nexport const EditServer = (ServerError: FC) => withSelectedServer<EditServerProps>(({ editServer, selectedServer }) => {\n const goBack = useGoBack();\n\n if (!isServerWithId(selectedServer)) {\n return null;\n }\n\n const handleSubmit = (serverData: ServerData) => {\n editServer(selectedServer.id, serverData);\n goBack();\n };\n\n return (\n <NoMenuLayout>\n <ServerForm\n title={<h5 className=\"mb-0\">Edit "{selectedServer.name}"</h5>}\n initialValues={selectedServer}\n onSubmit={handleSubmit}\n >\n <Button outline className=\"mr-2\" onClick={goBack}>Cancel</Button>\n <Button outline color=\"primary\">Save</Button>\n </ServerForm>\n </NoMenuLayout>\n );\n}, ServerError);\n","import { useRef, RefObject, ChangeEvent, MutableRefObject, FC, useState, useEffect } from 'react';\nimport { Button, UncontrolledTooltip } from 'reactstrap';\nimport { complement, pipe } from 'ramda';\nimport { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { ServersImporter } from '../services/ServersImporter';\nimport { ServerData, ServersMap } from '../data';\nimport { DuplicatedServersModal } from './DuplicatedServersModal';\nimport './ImportServersBtn.scss';\n\ntype Ref<T> = RefObject<T> | MutableRefObject<T>;\n\nexport interface ImportServersBtnProps {\n onImport?: () => void;\n onImportError?: (error: Error) => void;\n tooltipPlacement?: 'top' | 'bottom';\n className?: string;\n}\n\ninterface ImportServersBtnConnectProps extends ImportServersBtnProps {\n createServers: (servers: ServerData[]) => void;\n servers: ServersMap;\n fileRef: Ref<HTMLInputElement>;\n}\n\nconst serversFiltering = (servers: ServerData[]) =>\n ({ url, apiKey }: ServerData) => servers.some((server) => server.url === url && server.apiKey === apiKey);\n\nconst ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC<ImportServersBtnConnectProps> => ({\n createServers,\n servers,\n fileRef,\n children,\n onImport = () => {},\n onImportError = () => {},\n tooltipPlacement = 'bottom',\n className = '',\n}) => {\n const ref = fileRef ?? useRef<HTMLInputElement>();\n const [ serversToCreate, setServersToCreate ] = useState<ServerData[] | undefined>();\n const [ duplicatedServers, setDuplicatedServers ] = useState<ServerData[]>([]);\n const [ isModalOpen,, showModal, hideModal ] = useToggle();\n const create = pipe(createServers, onImport);\n const createAllServers = pipe(() => create(serversToCreate ?? []), hideModal);\n const createNonDuplicatedServers = pipe(\n () => create((serversToCreate ?? []).filter(complement(serversFiltering(duplicatedServers)))),\n hideModal,\n );\n const onFile = async ({ target }: ChangeEvent<HTMLInputElement>) =>\n importServersFromFile(target.files?.[0])\n .then(setServersToCreate)\n .then(() => {\n // Reset input after processing file\n (target as { value: string | null }).value = null;\n })\n .catch(onImportError);\n\n useEffect(() => {\n if (!serversToCreate) {\n return;\n }\n\n const existingServers = Object.values(servers);\n const duplicatedServers = serversToCreate.filter(serversFiltering(existingServers));\n const hasDuplicatedServers = !!duplicatedServers.length;\n\n !hasDuplicatedServers ? create(serversToCreate) : setDuplicatedServers(duplicatedServers);\n hasDuplicatedServers && showModal();\n }, [ serversToCreate ]);\n\n return (\n <>\n <Button outline id=\"importBtn\" className={className} onClick={() => ref.current?.click()}>\n <FontAwesomeIcon icon={importIcon} fixedWidth /> {children ?? 'Import from file'}\n </Button>\n <UncontrolledTooltip placement={tooltipPlacement} target=\"importBtn\">\n You can create servers by importing a CSV file with columns <b>name</b>, <b>apiKey</b> and <b>url</b>.\n </UncontrolledTooltip>\n\n <input type=\"file\" accept=\"text/csv\" className=\"import-servers-btn__csv-select\" ref={ref} onChange={onFile} />\n\n <DuplicatedServersModal\n isOpen={isModalOpen}\n duplicatedServers={duplicatedServers}\n onDiscard={createNonDuplicatedServers}\n onSave={createAllServers}\n />\n </>\n );\n};\n\nexport default ImportServersBtn;\n","import { identity, memoizeWith, pipe } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version';\nimport { SelectedServer } from '../data';\nimport { GetState } from '../../container/types';\nimport { ShlinkHealth } from '../../api/types';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\n\n/* eslint-disable padding-line-between-statements */\nexport const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER';\nexport const RESET_SELECTED_SERVER = 'shlink/selectedServer/RESET_SELECTED_SERVER';\n\nexport const MIN_FALLBACK_VERSION = '1.0.0';\nexport const MAX_FALLBACK_VERSION = '999.999.999';\nexport const LATEST_VERSION_CONSTRAINT = 'latest';\n/* eslint-enable padding-line-between-statements */\n\nexport interface SelectServerAction extends Action<string> {\n selectedServer: SelectedServer;\n}\n\nconst versionToSemVer = pipe(\n (version: string) => version === LATEST_VERSION_CONSTRAINT ? MAX_FALLBACK_VERSION : version,\n toSemVer(MIN_FALLBACK_VERSION),\n);\n\nconst getServerVersion = memoizeWith(\n identity,\n async (_serverId: string, health: () => Promise<ShlinkHealth>) => health().then(({ version }) => ({\n version: versionToSemVer(version),\n printableVersion: versionToPrintable(version),\n })),\n);\n\nconst initialState: SelectedServer = null;\n\nexport default buildReducer<SelectedServer, SelectServerAction>({\n [RESET_SELECTED_SERVER]: () => initialState,\n [SELECT_SERVER]: (_, { selectedServer }) => selectedServer,\n}, initialState);\n\nexport const resetSelectedServer = buildActionCreator(RESET_SELECTED_SERVER);\n\nexport const selectServer = (\n buildShlinkApiClient: ShlinkApiClientBuilder,\n loadMercureInfo: () => Action,\n) => (\n serverId: string,\n) => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch(resetSelectedServer());\n\n const { servers } = getState();\n const selectedServer = servers[serverId];\n\n if (!selectedServer) {\n dispatch<SelectServerAction>({\n type: SELECT_SERVER,\n selectedServer: { serverNotFound: true },\n });\n\n return;\n }\n\n try {\n const { health } = buildShlinkApiClient(selectedServer);\n const { version, printableVersion } = await getServerVersion(serverId, health);\n\n dispatch<SelectServerAction>({\n type: SELECT_SERVER,\n selectedServer: {\n ...selectedServer,\n version,\n printableVersion,\n },\n });\n dispatch(loadMercureInfo());\n } catch (e) {\n dispatch<SelectServerAction>({\n type: SELECT_SERVER,\n selectedServer: { ...selectedServer, serverNotReachable: true },\n });\n }\n};\n","import { assoc, dissoc, fromPairs, map, pipe, reduce, toPairs } from 'ramda';\nimport { v4 as uuid } from 'uuid';\nimport { Action } from 'redux';\nimport { ServerData, ServersMap, ServerWithId } from '../data';\nimport { buildReducer } from '../../utils/helpers/redux';\n\n/* eslint-disable padding-line-between-statements */\nexport const EDIT_SERVER = 'shlink/servers/EDIT_SERVER';\nexport const DELETE_SERVER = 'shlink/servers/DELETE_SERVER';\nexport const CREATE_SERVERS = 'shlink/servers/CREATE_SERVERS';\nexport const SET_AUTO_CONNECT = 'shlink/servers/SET_AUTO_CONNECT';\n/* eslint-enable padding-line-between-statements */\n\nexport interface CreateServersAction extends Action<string> {\n newServers: ServersMap;\n}\n\ninterface DeleteServerAction extends Action<string> {\n serverId: string;\n}\n\ninterface SetAutoConnectAction extends Action<string> {\n serverId: string;\n autoConnect: boolean;\n}\n\nconst initialState: ServersMap = {};\n\nconst serverWithId = (server: ServerWithId | ServerData): ServerWithId => {\n if ((server as ServerWithId).id) {\n return server as ServerWithId;\n }\n\n return assoc('id', uuid(), server);\n};\n\nexport default buildReducer<ServersMap, CreateServersAction & DeleteServerAction & SetAutoConnectAction>({\n [CREATE_SERVERS]: (state, { newServers }) => ({ ...state, ...newServers }),\n [DELETE_SERVER]: (state, { serverId }) => dissoc(serverId, state),\n [EDIT_SERVER]: (state, { serverId, serverData }: any) => !state[serverId]\n ? state\n : assoc(serverId, { ...state[serverId], ...serverData }, state),\n [SET_AUTO_CONNECT]: (state, { serverId, autoConnect }) => {\n if (!state[serverId]) {\n return state;\n }\n\n if (!autoConnect) {\n return assoc(serverId, { ...state[serverId], autoConnect }, state);\n }\n\n return fromPairs(\n toPairs(state).map(([ evaluatedServerId, server ]) => [\n evaluatedServerId,\n { ...server, autoConnect: evaluatedServerId === serverId },\n ]),\n );\n },\n}, initialState);\n\nconst serversListToMap = reduce<ServerWithId, ServersMap>((acc, server) => assoc(server.id, server, acc), {});\n\nexport const createServers = pipe(\n map(serverWithId),\n serversListToMap,\n (newServers: ServersMap) => ({ type: CREATE_SERVERS, newServers }),\n);\n\nexport const createServer = (server: ServerWithId) => createServers([ server ]);\n\nexport const editServer = (serverId: string, serverData: Partial<ServerData>) => ({\n type: EDIT_SERVER,\n serverId,\n serverData,\n});\n\nexport const deleteServer = ({ id }: ServerWithId): DeleteServerAction => ({ type: DELETE_SERVER, serverId: id });\n\nexport const setAutoConnect = ({ id }: ServerWithId, autoConnect: boolean): SetAutoConnectAction => ({\n type: SET_AUTO_CONNECT,\n serverId: id,\n autoConnect,\n});\n","import { pipe, prop } from 'ramda';\nimport { AxiosInstance } from 'axios';\nimport { Dispatch } from 'redux';\nimport { homepage } from '../../../package.json';\nimport { hasServerData, ServerData } from '../data';\nimport { createServers } from './servers';\n\nconst responseToServersList = pipe(\n prop<any, any>('data'),\n (data: any): ServerData[] => Array.isArray(data) ? data.filter(hasServerData) : [],\n);\n\nexport const fetchServers = ({ get }: AxiosInstance) => () => async (dispatch: Dispatch) => {\n const resp = await get(`${homepage}/servers.json`);\n const remoteList = responseToServersList(resp);\n\n dispatch(createServers(remoteList));\n};\n","import { FC } from 'react';\nimport { versionMatch, Versions } from '../../utils/helpers/version';\nimport { isReachableServer, SelectedServer } from '../data';\n\ninterface ForServerVersionProps extends Versions {\n selectedServer: SelectedServer;\n}\n\nconst ForServerVersion: FC<ForServerVersionProps> = ({ minVersion, maxVersion, selectedServer, children }) => {\n if (!isReachableServer(selectedServer)) {\n return null;\n }\n\n const { version } = selectedServer;\n const matchesVersion = versionMatch(version, { maxVersion, minVersion });\n\n if (!matchesVersion) {\n return null;\n }\n\n return <>{children}</>;\n};\n\nexport default ForServerVersion;\n","import { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport Message from '../../utils/Message';\nimport ServersListGroup from '../ServersListGroup';\nimport { DeleteServerButtonProps } from '../DeleteServerButton';\nimport { isServerWithId, SelectedServer, ServersMap } from '../data';\nimport { NoMenuLayout } from '../../common/NoMenuLayout';\nimport './ServerError.scss';\n\ninterface ServerErrorProps {\n servers: ServersMap;\n selectedServer: SelectedServer;\n}\n\nexport const ServerError = (DeleteServerButton: FC<DeleteServerButtonProps>): FC<ServerErrorProps> => (\n { servers, selectedServer },\n) => (\n <NoMenuLayout>\n <div className=\"server-error__container flex-column\">\n <Message className=\"w-100 mb-3 mb-md-5\" type=\"error\" fullWidth>\n {!isServerWithId(selectedServer) && 'Could not find this Shlink server.'}\n {isServerWithId(selectedServer) && (\n <>\n <p>Oops! Could not connect to this Shlink server.</p>\n Make sure you have internet connection, and the server is properly configured and on-line.\n </>\n )}\n </Message>\n\n <ServersListGroup servers={Object.values(servers)}>\n These are the Shlink servers currently configured. Choose one of\n them or <Link to=\"/server/create\">add a new one</Link>.\n </ServersListGroup>\n\n {isServerWithId(selectedServer) && (\n <div className=\"container mt-3 mt-md-5\">\n <h5>\n Alternatively, if you think you may have miss-configured this server, you\n can <DeleteServerButton server={selectedServer} className=\"server-error__delete-btn\">remove it</DeleteServerButton> or \n <Link to={`/server/${selectedServer.id}/edit`}>edit it</Link>.\n </h5>\n </div>\n )}\n </div>\n </NoMenuLayout>\n);\n","import { FC } from 'react';\nimport { Card, CardText, CardTitle } from 'reactstrap';\nimport { Link } from 'react-router-dom';\nimport { faArrowAltCircleRight as linkIcon } from '@fortawesome/free-regular-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport './HighlightCard.scss';\n\nexport interface HighlightCardProps {\n title: string;\n link?: string | false;\n}\n\nconst buildExtraProps = (link?: string | false) => !link ? {} : { tag: Link, to: link };\n\nexport const HighlightCard: FC<HighlightCardProps> = ({ children, title, link }) => (\n <Card className=\"highlight-card\" body {...buildExtraProps(link)}>\n {link && <FontAwesomeIcon size=\"3x\" className=\"highlight-card__link-icon\" icon={linkIcon} />}\n <CardTitle tag=\"h5\" className=\"highlight-card__title\">{title}</CardTitle>\n <CardText tag=\"h2\">{children}</CardText>\n </Card>\n);\n","import { FC, useEffect } from 'react';\nimport { Card, CardBody, CardHeader, Row } from 'reactstrap';\nimport { Link, useNavigate } from 'react-router-dom';\nimport { ITEMS_IN_OVERVIEW_PAGE, ShortUrlsList as ShortUrlsListState } from '../short-urls/reducers/shortUrlsList';\nimport { prettify } from '../utils/helpers/numbers';\nimport { TagsList } from '../tags/reducers/tagsList';\nimport { ShortUrlsTableProps } from '../short-urls/ShortUrlsTable';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { CreateShortUrlProps } from '../short-urls/CreateShortUrl';\nimport { VisitsOverview } from '../visits/reducers/visitsOverview';\nimport { Versions } from '../utils/helpers/version';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { ShlinkShortUrlsListParams } from '../api/types';\nimport { supportsNonOrphanVisits, supportsOrphanVisits } from '../utils/helpers/features';\nimport { getServerId, SelectedServer } from './data';\nimport { HighlightCard } from './helpers/HighlightCard';\n\ninterface OverviewConnectProps {\n shortUrlsList: ShortUrlsListState;\n listShortUrls: (params: ShlinkShortUrlsListParams) => void;\n listTags: Function;\n tagsList: TagsList;\n selectedServer: SelectedServer;\n visitsOverview: VisitsOverview;\n loadVisitsOverview: Function;\n}\n\nexport const Overview = (\n ShortUrlsTable: FC<ShortUrlsTableProps>,\n CreateShortUrl: FC<CreateShortUrlProps>,\n ForServerVersion: FC<Versions>,\n) => boundToMercureHub(({\n shortUrlsList,\n listShortUrls,\n listTags,\n tagsList,\n selectedServer,\n loadVisitsOverview,\n visitsOverview,\n}: OverviewConnectProps) => {\n const { loading, shortUrls } = shortUrlsList;\n const { loading: loadingTags } = tagsList;\n const { loading: loadingVisits, visitsCount, orphanVisitsCount } = visitsOverview;\n const serverId = getServerId(selectedServer);\n const linkToOrphanVisits = supportsOrphanVisits(selectedServer);\n const linkToNonOrphanVisits = supportsNonOrphanVisits(selectedServer);\n const navigate = useNavigate();\n\n useEffect(() => {\n listShortUrls({ itemsPerPage: ITEMS_IN_OVERVIEW_PAGE, orderBy: { field: 'dateCreated', dir: 'DESC' } });\n listTags();\n loadVisitsOverview();\n }, []);\n\n return (\n <>\n <Row>\n <div className=\"col-lg-6 col-xl-3 mb-3\">\n <HighlightCard title=\"Visits\" link={linkToNonOrphanVisits && `/server/${serverId}/non-orphan-visits`}>\n {loadingVisits ? 'Loading...' : prettify(visitsCount)}\n </HighlightCard>\n </div>\n <div className=\"col-lg-6 col-xl-3 mb-3\">\n <HighlightCard title=\"Orphan visits\" link={linkToOrphanVisits && `/server/${serverId}/orphan-visits`}>\n <ForServerVersion minVersion=\"2.6.0\">\n {loadingVisits ? 'Loading...' : prettify(orphanVisitsCount ?? 0)}\n </ForServerVersion>\n <ForServerVersion maxVersion=\"2.5.*\">\n <small className=\"text-muted\"><i>Shlink 2.6 is needed</i></small>\n </ForServerVersion>\n </HighlightCard>\n </div>\n <div className=\"col-lg-6 col-xl-3 mb-3\">\n <HighlightCard title=\"Short URLs\" link={`/server/${serverId}/list-short-urls/1`}>\n {loading ? 'Loading...' : prettify(shortUrls?.pagination.totalItems ?? 0)}\n </HighlightCard>\n </div>\n <div className=\"col-lg-6 col-xl-3 mb-3\">\n <HighlightCard title=\"Tags\" link={`/server/${serverId}/manage-tags`}>\n {loadingTags ? 'Loading...' : prettify(tagsList.tags.length)}\n </HighlightCard>\n </div>\n </Row>\n\n <Card className=\"mb-3\">\n <CardHeader>\n <span className=\"d-sm-none\">Create a short URL</span>\n <h5 className=\"d-none d-sm-inline\">Create a short URL</h5>\n <Link className=\"float-right\" to={`/server/${serverId}/create-short-url`}>Advanced options »</Link>\n </CardHeader>\n <CardBody>\n <CreateShortUrl basicMode />\n </CardBody>\n </Card>\n <Card>\n <CardHeader>\n <span className=\"d-sm-none\">Recently created URLs</span>\n <h5 className=\"d-none d-sm-inline\">Recently created URLs</h5>\n <Link className=\"float-right\" to={`/server/${serverId}/list-short-urls/1`}>See all »</Link>\n </CardHeader>\n <CardBody>\n <ShortUrlsTable\n shortUrlsList={shortUrlsList}\n selectedServer={selectedServer}\n className=\"mb-0\"\n onTagClick={(tag) => navigate(`/server/${serverId}/list-short-urls/1?tags=${encodeURIComponent(tag)}`)}\n />\n </CardBody>\n </Card>\n </>\n );\n}, () => [ Topics.visits, Topics.orphanVisits ]);\n","import { FC, useEffect, useState } from 'react';\nimport { Button, Row } from 'reactstrap';\nimport { faFileDownload as exportIcon, faPlus as plusIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { Link } from 'react-router-dom';\nimport { NoMenuLayout } from '../common/NoMenuLayout';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport SearchField from '../utils/SearchField';\nimport { Result } from '../utils/Result';\nimport { StateFlagTimeout } from '../utils/helpers/hooks';\nimport { ImportServersBtnProps } from './helpers/ImportServersBtn';\nimport { ServersMap } from './data';\nimport { ManageServersRowProps } from './ManageServersRow';\nimport ServersExporter from './services/ServersExporter';\n\ninterface ManageServersProps {\n servers: ServersMap;\n}\n\nconst SHOW_IMPORT_MSG_TIME = 4000;\n\nexport const ManageServers = (\n serversExporter: ServersExporter,\n ImportServersBtn: FC<ImportServersBtnProps>,\n useStateFlagTimeout: StateFlagTimeout,\n ManageServersRow: FC<ManageServersRowProps>,\n): FC<ManageServersProps> => ({ servers }) => {\n const allServers = Object.values(servers);\n const [ serversList, setServersList ] = useState(allServers);\n const filterServers = (searchTerm: string) => setServersList(\n allServers.filter(({ name, url }) => `${name} ${url}`.match(searchTerm)),\n );\n const hasAutoConnect = serversList.some(({ autoConnect }) => !!autoConnect);\n const [ errorImporting, setErrorImporting ] = useStateFlagTimeout(false, SHOW_IMPORT_MSG_TIME);\n\n useEffect(() => {\n setServersList(Object.values(servers));\n }, [ servers ]);\n\n return (\n <NoMenuLayout>\n <SearchField className=\"mb-3\" onChange={filterServers} />\n\n <Row className=\"mb-3\">\n <div className=\"col-md-6 d-flex d-md-block mb-2 mb-md-0\">\n <ImportServersBtn className=\"flex-fill\" onImportError={setErrorImporting}>Import servers</ImportServersBtn>\n {allServers.length > 0 && (\n <Button outline className=\"ml-2 flex-fill\" onClick={async () => serversExporter.exportServers()}>\n <FontAwesomeIcon icon={exportIcon} fixedWidth /> Export servers\n </Button>\n )}\n </div>\n <div className=\"col-md-6 text-md-right d-flex d-md-block\">\n <Button outline color=\"primary\" className=\"flex-fill\" tag={Link} to=\"/server/create\">\n <FontAwesomeIcon icon={plusIcon} fixedWidth /> Add a server\n </Button>\n </div>\n </Row>\n\n <SimpleCard>\n <table className=\"table table-hover mb-0\">\n <thead className=\"responsive-table__header\">\n <tr>\n {hasAutoConnect && <th style={{ width: '50px' }} />}\n <th>Name</th>\n <th>Base URL</th>\n <th />\n </tr>\n </thead>\n <tbody>\n {!serversList.length && <tr className=\"text-center\"><td colSpan={4}>No servers found.</td></tr>}\n {serversList.map((server) =>\n <ManageServersRow key={server.id} server={server} hasAutoConnect={hasAutoConnect} />)\n }\n </tbody>\n </table>\n </SimpleCard>\n\n {errorImporting && (\n <div className=\"mt-3\">\n <Result type=\"error\">The servers could not be imported. Make sure the format is correct.</Result>\n </div>\n )}\n </NoMenuLayout>\n );\n};\n","import { FC } from 'react';\nimport { UncontrolledTooltip } from 'reactstrap';\nimport { Link } from 'react-router-dom';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faCheck as checkIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ServerWithId } from './data';\nimport { ManageServersRowDropdownProps } from './ManageServersRowDropdown';\n\nexport interface ManageServersRowProps {\n server: ServerWithId;\n hasAutoConnect: boolean;\n}\n\nexport const ManageServersRow = (\n ManageServersRowDropdown: FC<ManageServersRowDropdownProps>,\n): FC<ManageServersRowProps> => ({ server, hasAutoConnect }) => (\n <tr className=\"responsive-table__row\">\n {hasAutoConnect && (\n <td className=\"responsive-table__cell\" data-th=\"Auto-connect\">\n {server.autoConnect && (\n <>\n <FontAwesomeIcon icon={checkIcon} className=\"text-primary\" id=\"autoConnectIcon\" />\n <UncontrolledTooltip target=\"autoConnectIcon\" placement=\"right\">\n Auto-connect to this server\n </UncontrolledTooltip>\n </>\n )}\n </td>\n )}\n <th className=\"responsive-table__cell\" data-th=\"Name\">\n <Link to={`/server/${server.id}`}>{server.name}</Link>\n </th>\n <td className=\"responsive-table__cell\" data-th=\"Base URL\">{server.url}</td>\n <td className=\"responsive-table__cell text-right\">\n <ManageServersRowDropdown server={server} />\n </td>\n </tr>\n);\n","import { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { Link } from 'react-router-dom';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faBan as toggleOffIcon,\n faEdit as editIcon,\n faMinusCircle as deleteIcon,\n faPlug as connectIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { faCircle as toggleOnIcon } from '@fortawesome/free-regular-svg-icons';\nimport { DropdownBtnMenu } from '../utils/DropdownBtnMenu';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { DeleteServerModalProps } from './DeleteServerModal';\nimport { ServerWithId } from './data';\n\nexport interface ManageServersRowDropdownProps {\n server: ServerWithId;\n}\n\ninterface ManageServersRowDropdownConnectProps extends ManageServersRowDropdownProps {\n setAutoConnect: (server: ServerWithId, autoConnect: boolean) => void;\n}\n\nexport const ManageServersRowDropdown = (\n DeleteServerModal: FC<DeleteServerModalProps>,\n): FC<ManageServersRowDropdownConnectProps> => ({ server, setAutoConnect }) => {\n const [ isMenuOpen, toggleMenu ] = useToggle();\n const [ isModalOpen,, showModal, hideModal ] = useToggle();\n const serverUrl = `/server/${server.id}`;\n const { autoConnect: isAutoConnect } = server;\n const autoConnectIcon = isAutoConnect ? toggleOffIcon : toggleOnIcon;\n\n return (\n <DropdownBtnMenu isOpen={isMenuOpen} toggle={toggleMenu}>\n <DropdownItem tag={Link} to={serverUrl}>\n <FontAwesomeIcon icon={connectIcon} fixedWidth /> Connect\n </DropdownItem>\n <DropdownItem tag={Link} to={`${serverUrl}/edit`}>\n <FontAwesomeIcon icon={editIcon} fixedWidth /> Edit server\n </DropdownItem>\n <DropdownItem onClick={() => setAutoConnect(server, !server.autoConnect)}>\n <FontAwesomeIcon icon={autoConnectIcon} fixedWidth /> {isAutoConnect ? 'Do not a' : 'A'}uto-connect\n </DropdownItem>\n <DropdownItem divider />\n <DropdownItem className=\"dropdown-item--danger\" onClick={showModal}>\n <FontAwesomeIcon icon={deleteIcon} fixedWidth /> Remove server\n </DropdownItem>\n\n <DeleteServerModal redirectHome={false} server={server} isOpen={isModalOpen} toggle={hideModal} />\n </DropdownBtnMenu>\n );\n};\n","import { CsvJson } from 'csvjson';\nimport { ServerData } from '../data';\n\nconst validateServer = (server: any): server is ServerData =>\n typeof server.url === 'string' && typeof server.apiKey === 'string' && typeof server.name === 'string';\n\nconst validateServers = (servers: any): servers is ServerData[] =>\n Array.isArray(servers) && servers.every(validateServer);\n\nexport class ServersImporter {\n public constructor(private readonly csvJson: CsvJson, private readonly fileReaderFactory: () => FileReader) {}\n\n public readonly importServersFromFile = async (file?: File | null): Promise<ServerData[]> => {\n if (!file) {\n throw new Error('No file provided');\n }\n\n const reader = this.fileReaderFactory();\n\n return new Promise((resolve, reject) => {\n reader.addEventListener('loadend', (e: ProgressEvent<FileReader>) => {\n try {\n // TODO Read as stream, otherwise, if the file is too big, this will block the browser tab\n const content = e.target?.result?.toString() ?? '';\n const servers = this.csvJson.toObject(content);\n\n if (!validateServers(servers)) {\n throw new Error('Provided file does not have the right format.');\n }\n\n resolve(servers);\n } catch (e) {\n reject(e);\n }\n });\n reader.readAsText(file);\n });\n };\n}\n","import { values } from 'ramda';\nimport { CsvJson } from 'csvjson';\nimport LocalStorage from '../../utils/services/LocalStorage';\nimport { ServersMap, serverWithIdToServerData } from '../data';\nimport { saveCsv } from '../../utils/helpers/files';\n\nconst SERVERS_FILENAME = 'shlink-servers.csv';\n\nexport default class ServersExporter {\n public constructor(\n private readonly storage: LocalStorage,\n private readonly window: Window,\n private readonly csvjson: CsvJson,\n ) {}\n\n public readonly exportServers = async () => {\n const servers = values(this.storage.get<ServersMap>('servers') ?? {}).map(serverWithIdToServerData);\n\n try {\n const csv = this.csvjson.toCSV(servers, { headers: 'key' });\n\n saveCsv(this.window, csv, SERVERS_FILENAME);\n } catch (e) {\n // FIXME Handle error\n console.error(e); // eslint-disable-line no-console\n }\n };\n}\n","import csvjson from 'csvjson';\nimport Bottle from 'bottlejs';\nimport CreateServer from '../CreateServer';\nimport ServersDropdown from '../ServersDropdown';\nimport DeleteServerModal from '../DeleteServerModal';\nimport DeleteServerButton from '../DeleteServerButton';\nimport { EditServer } from '../EditServer';\nimport ImportServersBtn from '../helpers/ImportServersBtn';\nimport { resetSelectedServer, selectServer } from '../reducers/selectedServer';\nimport { createServer, createServers, deleteServer, editServer, setAutoConnect } from '../reducers/servers';\nimport { fetchServers } from '../reducers/remoteServers';\nimport ForServerVersion from '../helpers/ForServerVersion';\nimport { ServerError } from '../helpers/ServerError';\nimport { ConnectDecorator } from '../../container/types';\nimport { withoutSelectedServer } from '../helpers/withoutSelectedServer';\nimport { Overview } from '../Overview';\nimport { ManageServers } from '../ManageServers';\nimport { ManageServersRow } from '../ManageServersRow';\nimport { ManageServersRowDropdown } from '../ManageServersRowDropdown';\nimport { ServersImporter } from './ServersImporter';\nimport ServersExporter from './ServersExporter';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory(\n 'ManageServers',\n ManageServers,\n 'ServersExporter',\n 'ImportServersBtn',\n 'useStateFlagTimeout',\n 'ManageServersRow',\n );\n bottle.decorator('ManageServers', connect([ 'servers' ]));\n\n bottle.serviceFactory('ManageServersRow', ManageServersRow, 'ManageServersRowDropdown');\n\n bottle.serviceFactory('ManageServersRowDropdown', ManageServersRowDropdown, 'DeleteServerModal');\n bottle.decorator('ManageServersRowDropdown', connect(null, [ 'setAutoConnect' ]));\n\n bottle.serviceFactory('CreateServer', CreateServer, 'ImportServersBtn', 'useStateFlagTimeout');\n bottle.decorator('CreateServer', withoutSelectedServer);\n bottle.decorator('CreateServer', connect([ 'selectedServer', 'servers' ], [ 'createServer', 'resetSelectedServer' ]));\n\n bottle.serviceFactory('EditServer', EditServer, 'ServerError');\n bottle.decorator('EditServer', connect([ 'selectedServer' ], [ 'editServer', 'selectServer' ]));\n\n bottle.serviceFactory('ServersDropdown', () => ServersDropdown);\n bottle.decorator('ServersDropdown', connect([ 'servers', 'selectedServer' ]));\n\n bottle.serviceFactory('DeleteServerModal', () => DeleteServerModal);\n bottle.decorator('DeleteServerModal', connect(null, [ 'deleteServer' ]));\n\n bottle.serviceFactory('DeleteServerButton', DeleteServerButton, 'DeleteServerModal');\n\n bottle.serviceFactory('ImportServersBtn', ImportServersBtn, 'ServersImporter');\n bottle.decorator('ImportServersBtn', connect([ 'servers' ], [ 'createServers' ]));\n\n bottle.serviceFactory('ForServerVersion', () => ForServerVersion);\n bottle.decorator('ForServerVersion', connect([ 'selectedServer' ]));\n\n bottle.serviceFactory('ServerError', ServerError, 'DeleteServerButton');\n bottle.decorator('ServerError', connect([ 'servers', 'selectedServer' ]));\n\n bottle.serviceFactory('Overview', Overview, 'ShortUrlsTable', 'CreateShortUrl', 'ForServerVersion');\n bottle.decorator('Overview', connect(\n [ 'shortUrlsList', 'tagsList', 'selectedServer', 'mercureInfo', 'visitsOverview' ],\n [ 'listShortUrls', 'listTags', 'createNewVisits', 'loadMercureInfo', 'loadVisitsOverview' ],\n ));\n\n // Services\n bottle.constant('csvjson', csvjson);\n bottle.constant('fileReaderFactory', () => new FileReader());\n bottle.service('ServersImporter', ServersImporter, 'csvjson', 'fileReaderFactory');\n bottle.service('ServersExporter', ServersExporter, 'Storage', 'window', 'csvjson');\n\n // Actions\n bottle.serviceFactory('selectServer', selectServer, 'buildShlinkApiClient', 'loadMercureInfo');\n bottle.serviceFactory('createServer', () => createServer);\n bottle.serviceFactory('createServers', () => createServers);\n bottle.serviceFactory('deleteServer', () => deleteServer);\n bottle.serviceFactory('editServer', () => editServer);\n bottle.serviceFactory('setAutoConnect', () => setAutoConnect);\n bottle.serviceFactory('fetchServers', fetchServers, 'axios');\n\n bottle.serviceFactory('resetSelectedServer', () => resetSelectedServer);\n};\n\nexport default provideServices;\n","import { FC } from 'react';\nimport { Modal, ModalBody } from 'reactstrap';\nimport { MapContainer, TileLayer, Marker, Popup, MapContainerProps } from 'react-leaflet';\nimport { prop } from 'ramda';\nimport { CityStats } from '../types';\nimport './MapModal.scss';\n\ninterface MapModalProps {\n toggle: () => void;\n isOpen: boolean;\n title: string;\n locations?: CityStats[];\n}\n\nconst OpenStreetMapTile: FC = () => (\n <TileLayer\n attribution='&copy <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors'\n url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"\n />\n);\n\nconst calculateMapProps = (locations: CityStats[]): MapContainerProps => {\n if (locations.length === 0) {\n return {};\n }\n\n if (locations.length > 1) {\n return { bounds: locations.map(prop('latLong')) };\n }\n\n // When there's only one location, an error is thrown if trying to calculate the bounds.\n // When that happens, we use zoom and center as a workaround\n const [{ latLong: center }] = locations;\n\n return { zoom: 10, center };\n};\n\nconst MapModal = ({ toggle, isOpen, title, locations = [] }: MapModalProps) => (\n <Modal toggle={toggle} isOpen={isOpen} className=\"map-modal__modal\" contentClassName=\"map-modal__modal-content\">\n <ModalBody className=\"map-modal__modal-body\">\n <h3 className=\"map-modal__modal-title\">\n {title}\n <button type=\"button\" className=\"close\" onClick={toggle}>×</button>\n </h3>\n <MapContainer {...calculateMapProps(locations)}>\n <OpenStreetMapTile />\n {locations.map(({ cityName, latLong, count }, index) => (\n <Marker key={index} position={latLong}>\n <Popup><b>{count}</b> visit{count > 1 ? 's' : ''} from <b>{cityName}</b></Popup>\n </Marker>\n ))}\n </MapContainer>\n </ModalBody>\n </Modal>\n);\n\nexport default MapModal;\n","import { Button, Card } from 'reactstrap';\nimport { FC, ReactNode } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faArrowLeft } from '@fortawesome/free-solid-svg-icons';\nimport ShortUrlVisitsCount from '../short-urls/helpers/ShortUrlVisitsCount';\nimport { ShortUrl } from '../short-urls/data';\nimport { Visit } from './types';\n\ninterface VisitsHeaderProps {\n visits: Visit[];\n goBack: () => void;\n title: ReactNode;\n shortUrl?: ShortUrl;\n}\n\nconst VisitsHeader: FC<VisitsHeaderProps> = ({ visits, goBack, shortUrl, children, title }) => (\n <header>\n <Card body>\n <h2 className=\"d-flex justify-content-between align-items-center mb-0\">\n <Button color=\"link\" size=\"lg\" className=\"p-0 mr-3\" onClick={goBack}>\n <FontAwesomeIcon icon={faArrowLeft} />\n </Button>\n <span className=\"text-center d-none d-sm-block\">\n <small>{title}</small>\n </span>\n <span className=\"badge badge-main ml-3\">\n Visits:{' '}\n <ShortUrlVisitsCount visitsCount={visits.length} shortUrl={shortUrl} />\n </span>\n </h2>\n <h3 className=\"text-center d-block d-sm-none mb-0 mt-3\">\n <small>{title}</small>\n </h3>\n\n {children && <div className=\"mt-md-2\">{children}</div>}\n </Card>\n </header>\n);\n\nexport default VisitsHeader;\n","import { UncontrolledTooltip } from 'reactstrap';\nimport { ExternalLink } from 'react-external-link';\nimport { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail';\nimport { Time } from '../utils/Time';\nimport { ShortUrlVisits } from './reducers/shortUrlVisits';\nimport VisitsHeader from './VisitsHeader';\nimport './ShortUrlVisitsHeader.scss';\n\ninterface ShortUrlVisitsHeaderProps {\n shortUrlDetail: ShortUrlDetail;\n shortUrlVisits: ShortUrlVisits;\n goBack: () => void;\n}\n\nconst ShortUrlVisitsHeader = ({ shortUrlDetail, shortUrlVisits, goBack }: ShortUrlVisitsHeaderProps) => {\n const { shortUrl, loading } = shortUrlDetail;\n const { visits } = shortUrlVisits;\n const shortLink = shortUrl?.shortUrl ?? '';\n const longLink = shortUrl?.longUrl ?? '';\n const title = shortUrl?.title;\n\n const renderDate = () => !shortUrl ? <small>Loading...</small> : (\n <span>\n <b id=\"created\" className=\"short-url-visits-header__created-at\">\n <Time date={shortUrl.dateCreated} relative />\n </b>\n <UncontrolledTooltip placement=\"bottom\" target=\"created\">\n <Time date={shortUrl.dateCreated} />\n </UncontrolledTooltip>\n </span>\n );\n const visitsStatsTitle = <>Visits for <ExternalLink href={shortLink} /></>;\n\n return (\n <VisitsHeader title={visitsStatsTitle} goBack={goBack} visits={visits} shortUrl={shortUrl}>\n <hr />\n <div>Created: {renderDate()}</div>\n <div>\n {`${title ? 'Title' : 'Long URL'}: `}\n {loading && <small>Loading...</small>}\n {!loading && <ExternalLink href={longLink}>{title ?? longLink}</ExternalLink>}\n </div>\n </VisitsHeader>\n );\n};\n\nexport default ShortUrlVisitsHeader;\n","import bowser from 'bowser';\nimport { zipObj } from 'ramda';\nimport { Empty, hasValue } from '../utils';\nimport { Stats, UserAgent } from '../../visits/types';\n\nconst DEFAULT = 'Others';\nconst BROWSERS_WHITELIST = [\n 'Android Browser',\n 'Chrome',\n 'Chromium',\n 'Firefox',\n 'Internet Explorer',\n 'Microsoft Edge',\n 'Opera',\n 'Safari',\n 'Samsung Internet for Android',\n 'Vivaldi',\n 'WeChat',\n];\n\nexport const parseUserAgent = (userAgent: string | Empty): UserAgent => {\n if (!hasValue(userAgent)) {\n return { browser: DEFAULT, os: DEFAULT };\n }\n\n const { browser: { name: browser }, os: { name: os } } = bowser.parse(userAgent);\n\n return { os: os ?? DEFAULT, browser: browser && BROWSERS_WHITELIST.includes(browser) ? browser : DEFAULT };\n};\n\nexport const extractDomain = (url: string | Empty): string => {\n if (!hasValue(url)) {\n return 'Direct';\n }\n\n return url.split('/')[url.includes('://') ? 2 : 0]?.split(':')[0] ?? '';\n};\n\nexport const fillTheGaps = (stats: Stats, labels: string[]): number[] =>\n Object.values({ ...zipObj(labels, labels.map(() => 0)), ...stats });\n","import { FC } from 'react';\nimport BooleanControl, { BooleanControlProps } from './BooleanControl';\n\nconst ToggleSwitch: FC<BooleanControlProps> = (props) => <BooleanControl type=\"switch\" {...props} />;\n\nexport default ToggleSwitch;\n","import { ActiveElement, ChartEvent, ChartType, TooltipItem } from 'chart.js';\nimport { prettify } from './numbers';\n\nexport const pointerOnHover = ({ native }: ChartEvent, [ firstElement ]: ActiveElement[]) => {\n if (!native?.target) {\n return;\n }\n\n const canvas = native.target as HTMLCanvasElement;\n\n canvas.style.cursor = firstElement ? 'pointer' : 'default';\n};\n\nexport const renderChartLabel = ({ dataset, formattedValue }: TooltipItem<ChartType>) =>\n `${dataset.label}: ${prettify(formattedValue)}`;\n\nexport const renderPieChartLabel = ({ label, formattedValue }: TooltipItem<ChartType>) =>\n `${label}: ${prettify(formattedValue)}`;\n","import { useState, useMemo } from 'react';\nimport {\n Card,\n CardHeader,\n CardBody,\n UncontrolledDropdown,\n DropdownToggle,\n DropdownMenu,\n DropdownItem,\n} from 'reactstrap';\nimport { Line } from 'react-chartjs-2';\nimport { always, cond, countBy, reverse } from 'ramda';\nimport {\n add,\n differenceInDays,\n differenceInHours,\n differenceInMonths,\n differenceInWeeks,\n parseISO,\n format,\n startOfISOWeek,\n endOfISOWeek,\n} from 'date-fns';\nimport { ChartData, ChartDataset, ChartOptions } from 'chart.js';\nimport { NormalizedVisit, Stats } from '../types';\nimport { fillTheGaps } from '../../utils/helpers/visits';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { rangeOf } from '../../utils/utils';\nimport ToggleSwitch from '../../utils/ToggleSwitch';\nimport { prettify } from '../../utils/helpers/numbers';\nimport { pointerOnHover, renderChartLabel } from '../../utils/helpers/charts';\nimport { HIGHLIGHTED_COLOR, MAIN_COLOR } from '../../utils/theme';\nimport './LineChartCard.scss';\n\ninterface LineChartCardProps {\n title: string;\n highlightedLabel?: string;\n visits: NormalizedVisit[];\n highlightedVisits: NormalizedVisit[];\n setSelectedVisits?: (visits: NormalizedVisit[]) => void;\n}\n\ntype Step = 'monthly' | 'weekly' | 'daily' | 'hourly';\n\nconst STEPS_MAP: Record<Step, string> = {\n monthly: 'Month',\n weekly: 'Week',\n daily: 'Day',\n hourly: 'Hour',\n};\n\nconst STEP_TO_DURATION_MAP: Record<Step, (amount: number) => Duration> = {\n hourly: (hours: number) => ({ hours }),\n daily: (days: number) => ({ days }),\n weekly: (weeks: number) => ({ weeks }),\n monthly: (months: number) => ({ months }),\n};\n\nconst STEP_TO_DIFF_FUNC_MAP: Record<Step, (dateLeft: Date, dateRight: Date) => number> = {\n hourly: differenceInHours,\n daily: differenceInDays,\n weekly: differenceInWeeks,\n monthly: differenceInMonths,\n};\n\nconst STEP_TO_DATE_FORMAT: Record<Step, (date: Date) => string> = {\n hourly: (date) => format(date, 'yyyy-MM-dd HH:00'),\n daily: (date) => format(date, 'yyyy-MM-dd'),\n weekly(date) {\n const firstWeekDay = format(startOfISOWeek(date), 'yyyy-MM-dd');\n const lastWeekDay = format(endOfISOWeek(date), 'yyyy-MM-dd');\n\n return `${firstWeekDay} - ${lastWeekDay}`;\n },\n monthly: (date) => format(date, 'yyyy-MM'),\n};\n\nconst determineInitialStep = (oldestVisitDate: string): Step => {\n const now = new Date();\n const oldestDate = parseISO(oldestVisitDate);\n const matcher = cond<never, Step | undefined>([\n [ () => differenceInDays(now, oldestDate) <= 2, always<Step>('hourly') ], // Less than 2 days\n [ () => differenceInMonths(now, oldestDate) <= 1, always<Step>('daily') ], // Between 2 days and 1 month\n [ () => differenceInMonths(now, oldestDate) <= 6, always<Step>('weekly') ], // Between 1 and 6 months\n ]);\n\n return matcher() ?? 'monthly';\n};\n\nconst groupVisitsByStep = (step: Step, visits: NormalizedVisit[]): Stats => countBy(\n (visit) => STEP_TO_DATE_FORMAT[step](parseISO(visit.date)),\n visits,\n);\n\nconst visitsToDatasetGroups = (step: Step, visits: NormalizedVisit[]) =>\n visits.reduce<Record<string, NormalizedVisit[]>>(\n (acc, visit) => {\n const key = STEP_TO_DATE_FORMAT[step](parseISO(visit.date));\n\n acc[key] = acc[key] ?? [];\n acc[key].push(visit);\n\n return acc;\n },\n {},\n );\n\nconst generateLabels = (step: Step, visits: NormalizedVisit[]): string[] => {\n const diffFunc = STEP_TO_DIFF_FUNC_MAP[step];\n const formatter = STEP_TO_DATE_FORMAT[step];\n const newerDate = parseISO(visits[0].date);\n const oldestDate = parseISO(visits[visits.length - 1].date);\n const size = diffFunc(newerDate, oldestDate);\n const duration = STEP_TO_DURATION_MAP[step];\n\n return [\n formatter(oldestDate),\n ...rangeOf(size, (num) => formatter(add(oldestDate, duration(num)))),\n ];\n};\n\nconst generateLabelsAndGroupedVisits = (\n visits: NormalizedVisit[],\n groupedVisitsWithGaps: Stats,\n step: Step,\n skipNoElements: boolean,\n): [string[], number[]] => {\n if (skipNoElements) {\n return [ Object.keys(groupedVisitsWithGaps), Object.values(groupedVisitsWithGaps) ];\n }\n\n const labels = generateLabels(step, visits);\n\n return [ labels, fillTheGaps(groupedVisitsWithGaps, labels) ];\n};\n\nconst generateDataset = (data: number[], label: string, color: string): ChartDataset => ({\n label,\n data,\n fill: false,\n tension: 0.2,\n borderColor: color,\n backgroundColor: color,\n});\n\nlet selectedLabel: string | null = null;\n\nconst chartElementAtEvent = (\n labels: string[],\n datasetsByPoint: Record<string, NormalizedVisit[]>,\n setSelectedVisits?: (visits: NormalizedVisit[]) => void,\n) => ([ chart ]: [{ index: number }]) => {\n if (!setSelectedVisits || !chart) {\n return;\n }\n\n const { index } = chart;\n\n if (selectedLabel === labels[index]) {\n setSelectedVisits([]);\n selectedLabel = null;\n } else {\n setSelectedVisits(labels[index] && datasetsByPoint[labels[index]] || []);\n selectedLabel = labels[index] ?? null;\n }\n};\n\nconst LineChartCard = (\n { title, visits, highlightedVisits, highlightedLabel = 'Selected', setSelectedVisits }: LineChartCardProps,\n) => {\n const [ step, setStep ] = useState<Step>(\n visits.length > 0 ? determineInitialStep(visits[visits.length - 1].date) : 'monthly',\n );\n const [ skipNoVisits, toggleSkipNoVisits ] = useToggle(true);\n\n const datasetsByPoint = useMemo(() => visitsToDatasetGroups(step, visits), [ step, visits ]);\n const groupedVisitsWithGaps = useMemo(() => groupVisitsByStep(step, reverse(visits)), [ step, visits ]);\n const [ labels, groupedVisits ] = useMemo(\n () => generateLabelsAndGroupedVisits(visits, groupedVisitsWithGaps, step, skipNoVisits),\n [ visits, step, skipNoVisits ],\n );\n const groupedHighlighted = useMemo(\n () => fillTheGaps(groupVisitsByStep(step, reverse(highlightedVisits)), labels),\n [ highlightedVisits, step, labels ],\n );\n const generateChartDatasets = (): ChartDataset[] => {\n const mainDataset = generateDataset(groupedVisits, 'Visits', MAIN_COLOR);\n\n if (highlightedVisits.length === 0) {\n return [ mainDataset ];\n }\n\n const highlightedDataset = generateDataset(groupedHighlighted, highlightedLabel, HIGHLIGHTED_COLOR);\n\n return [ mainDataset, highlightedDataset ];\n };\n const generateChartData = (): ChartData => ({ labels, datasets: generateChartDatasets() });\n\n const options: ChartOptions = {\n maintainAspectRatio: false,\n plugins: {\n legend: { display: false },\n tooltip: {\n intersect: false,\n axis: 'x',\n callbacks: { label: renderChartLabel },\n },\n },\n scales: {\n y: {\n beginAtZero: true,\n ticks: {\n precision: 0,\n callback: prettify,\n },\n },\n x: {\n title: { display: true, text: STEPS_MAP[step] },\n },\n },\n onHover: pointerOnHover,\n };\n const renderLineChart = () => (\n <Line\n data={generateChartData()}\n options={options}\n getElementAtEvent={chartElementAtEvent(labels, datasetsByPoint, setSelectedVisits) as any}\n />\n );\n\n return (\n <Card>\n <CardHeader>\n {title}\n <div className=\"float-right\">\n <UncontrolledDropdown>\n <DropdownToggle caret color=\"link\" className=\"btn-sm p-0\">\n Group by\n </DropdownToggle>\n <DropdownMenu right>\n {Object.entries(STEPS_MAP).map(([ value, menuText ]) => (\n <DropdownItem key={value} active={step === value} onClick={() => setStep(value as Step)}>\n {menuText}\n </DropdownItem>\n ))}\n </DropdownMenu>\n </UncontrolledDropdown>\n </div>\n <div className=\"float-right mr-2\">\n <ToggleSwitch checked={skipNoVisits} onChange={toggleSkipNoVisits}>\n <small>Skip dates with no visits</small>\n </ToggleSwitch>\n </div>\n </CardHeader>\n <CardBody className=\"line-chart-card__body\">\n {/* It's VERY IMPORTANT to render two different components here, as one has 1 dataset and the other has 2 */}\n {/* Using the same component causes a crash when switching from 1 to 2 datasets, and then back to 1 dataset */}\n {highlightedVisits.length > 0 && renderLineChart()}\n {highlightedVisits.length === 0 && renderLineChart()}\n </CardBody>\n </Card>\n );\n};\n\nexport default LineChartCard;\n","import { FC } from 'react';\nimport classNames from 'classnames';\nimport { Pagination, PaginationItem, PaginationLink } from 'reactstrap';\nimport {\n pageIsEllipsis,\n keyForPage,\n NumberOrEllipsis,\n progressivePagination,\n prettifyPageNumber,\n} from '../utils/helpers/pagination';\nimport './SimplePaginator.scss';\n\ninterface SimplePaginatorProps {\n pagesCount: number;\n currentPage: number;\n setCurrentPage: (currentPage: number) => void;\n centered?: boolean;\n}\n\nconst SimplePaginator: FC<SimplePaginatorProps> = ({ pagesCount, currentPage, setCurrentPage, centered = true }) => {\n if (pagesCount < 2) {\n return null;\n }\n\n const onClick = (page: NumberOrEllipsis) => () => !pageIsEllipsis(page) && setCurrentPage(page);\n\n return (\n <Pagination listClassName={classNames('flex-wrap mb-0 simple-paginator', { 'justify-content-center': centered })}>\n <PaginationItem disabled={currentPage <= 1}>\n <PaginationLink previous tag=\"span\" onClick={onClick(currentPage - 1)} />\n </PaginationItem>\n {progressivePagination(currentPage, pagesCount).map((pageNumber, index) => (\n <PaginationItem\n key={keyForPage(pageNumber, index)}\n disabled={pageIsEllipsis(pageNumber)}\n active={currentPage === pageNumber}\n >\n <PaginationLink tag=\"span\" onClick={onClick(pageNumber)}>{prettifyPageNumber(pageNumber)}</PaginationLink>\n </PaginationItem>\n ))}\n <PaginationItem disabled={currentPage >= pagesCount}>\n <PaginationLink next tag=\"span\" onClick={onClick(currentPage + 1)} />\n </PaginationItem>\n </Pagination>\n );\n};\n\nexport default SimplePaginator;\n","import { useEffect, useMemo, useState, useRef } from 'react';\nimport classNames from 'classnames';\nimport { min, splitEvery } from 'ramda';\nimport { faCheck as checkIcon, faRobot as botIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { UncontrolledTooltip } from 'reactstrap';\nimport SimplePaginator from '../common/SimplePaginator';\nimport SearchField from '../utils/SearchField';\nimport { determineOrderDir, Order, sortList } from '../utils/helpers/ordering';\nimport { prettify } from '../utils/helpers/numbers';\nimport { supportsBotVisits } from '../utils/helpers/features';\nimport { SelectedServer } from '../servers/data';\nimport { Time } from '../utils/Time';\nimport { TableOrderIcon } from '../utils/table/TableOrderIcon';\nimport { MediaMatcher } from '../utils/types';\nimport { NormalizedOrphanVisit, NormalizedVisit } from './types';\nimport './VisitsTable.scss';\n\nexport interface VisitsTableProps {\n visits: NormalizedVisit[];\n selectedVisits?: NormalizedVisit[];\n setSelectedVisits: (visits: NormalizedVisit[]) => void;\n matchMedia?: MediaMatcher;\n isOrphanVisits?: boolean;\n selectedServer: SelectedServer;\n}\n\ntype OrderableFields = 'date' | 'country' | 'city' | 'browser' | 'os' | 'referer' | 'visitedUrl' | 'potentialBot';\ntype VisitsOrder = Order<OrderableFields>;\n\nconst PAGE_SIZE = 20;\nconst visitMatchesSearch = ({ browser, os, referer, country, city, ...rest }: NormalizedVisit, searchTerm: string) =>\n `${browser} ${os} ${referer} ${country} ${city} ${(rest as NormalizedOrphanVisit).visitedUrl}`.toLowerCase().includes(\n searchTerm.toLowerCase(),\n );\nconst searchVisits = (searchTerm: string, visits: NormalizedVisit[]) =>\n visits.filter((visit) => visitMatchesSearch(visit, searchTerm));\nconst sortVisits = (order: VisitsOrder, visits: NormalizedVisit[]) => sortList<NormalizedVisit>(visits, order as any);\nconst calculateVisits = (allVisits: NormalizedVisit[], searchTerm: string | undefined, order: VisitsOrder) => {\n const filteredVisits = searchTerm ? searchVisits(searchTerm, allVisits) : [ ...allVisits ];\n const sortedVisits = sortVisits(order, filteredVisits);\n const total = sortedVisits.length;\n const visitsGroups = splitEvery(PAGE_SIZE, sortedVisits);\n\n return { visitsGroups, total };\n};\n\nconst VisitsTable = ({\n visits,\n selectedVisits = [],\n setSelectedVisits,\n selectedServer,\n matchMedia = window.matchMedia,\n isOrphanVisits = false,\n}: VisitsTableProps) => {\n const headerCellsClass = 'visits-table__header-cell visits-table__sticky';\n const matchMobile = () => matchMedia('(max-width: 767px)').matches;\n\n const [ isMobileDevice, setIsMobileDevice ] = useState(matchMobile());\n const [ searchTerm, setSearchTerm ] = useState<string | undefined>(undefined);\n const [ order, setOrder ] = useState<VisitsOrder>({});\n const resultSet = useMemo(() => calculateVisits(visits, searchTerm, order), [ searchTerm, order ]);\n const isFirstLoad = useRef(true);\n const [ page, setPage ] = useState(1);\n const end = page * PAGE_SIZE;\n const start = end - PAGE_SIZE;\n const supportsBots = supportsBotVisits(selectedServer);\n const fullSizeColSpan = 7 + Number(supportsBots) + Number(isOrphanVisits);\n\n const orderByColumn = (field: OrderableFields) =>\n () => setOrder({ field, dir: determineOrderDir(field, order.field, order.dir) });\n const renderOrderIcon = (field: OrderableFields) =>\n <TableOrderIcon currentOrder={order} field={field} className=\"visits-table__header-icon\" />;\n\n useEffect(() => {\n const listener = () => setIsMobileDevice(matchMobile());\n\n window.addEventListener('resize', listener);\n\n return () => window.removeEventListener('resize', listener);\n }, []);\n useEffect(() => {\n setPage(1);\n\n !isFirstLoad.current && setSelectedVisits([]);\n isFirstLoad.current = false;\n }, [ searchTerm ]);\n\n return (\n <table className=\"table table-bordered table-hover table-sm table-responsive-sm visits-table\">\n <thead className=\"visits-table__header\">\n <tr>\n <th\n className={`${headerCellsClass} text-center`}\n onClick={() => setSelectedVisits(\n selectedVisits.length < resultSet.total ? resultSet.visitsGroups.flat() : [],\n )}\n >\n <FontAwesomeIcon icon={checkIcon} className={classNames({ 'text-primary': selectedVisits.length > 0 })} />\n </th>\n {supportsBots && (\n <th className={`${headerCellsClass} text-center`} onClick={orderByColumn('potentialBot')}>\n <FontAwesomeIcon icon={botIcon} />\n {renderOrderIcon('potentialBot')}\n </th>\n )}\n <th className={headerCellsClass} onClick={orderByColumn('date')}>\n Date\n {renderOrderIcon('date')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('country')}>\n Country\n {renderOrderIcon('country')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('city')}>\n City\n {renderOrderIcon('city')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('browser')}>\n Browser\n {renderOrderIcon('browser')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('os')}>\n OS\n {renderOrderIcon('os')}\n </th>\n <th className={headerCellsClass} onClick={orderByColumn('referer')}>\n Referrer\n {renderOrderIcon('referer')}\n </th>\n {isOrphanVisits && (\n <th className={headerCellsClass} onClick={orderByColumn('visitedUrl')}>\n Visited URL\n {renderOrderIcon('visitedUrl')}\n </th>\n )}\n </tr>\n <tr>\n <td colSpan={fullSizeColSpan} className=\"p-0\">\n <SearchField noBorder large={false} onChange={setSearchTerm} />\n </td>\n </tr>\n </thead>\n <tbody>\n {!resultSet.visitsGroups[page - 1]?.length && (\n <tr>\n <td colSpan={fullSizeColSpan} className=\"text-center\">\n No visits found with current filtering\n </td>\n </tr>\n )}\n {resultSet.visitsGroups[page - 1]?.map((visit, index) => {\n const isSelected = selectedVisits.includes(visit);\n\n return (\n <tr\n key={index}\n style={{ cursor: 'pointer' }}\n className={classNames({ 'table-active': isSelected })}\n onClick={() => setSelectedVisits(\n isSelected ? selectedVisits.filter((v) => v !== visit) : [ ...selectedVisits, visit ],\n )}\n >\n <td className=\"text-center\">\n {isSelected && <FontAwesomeIcon icon={checkIcon} className=\"text-primary\" />}\n </td>\n {supportsBots && (\n <td className=\"text-center\">\n {visit.potentialBot && (\n <>\n <FontAwesomeIcon icon={botIcon} id={`botIcon${index}`} />\n <UncontrolledTooltip placement=\"right\" target={`botIcon${index}`}>\n Potentially a visit from a bot or crawler\n </UncontrolledTooltip>\n </>\n )}\n </td>\n )}\n <td><Time date={visit.date} /></td>\n <td>{visit.country}</td>\n <td>{visit.city}</td>\n <td>{visit.browser}</td>\n <td>{visit.os}</td>\n <td>{visit.referer}</td>\n {isOrphanVisits && <td>{(visit as NormalizedOrphanVisit).visitedUrl}</td>}\n </tr>\n );\n })}\n </tbody>\n {resultSet.total > PAGE_SIZE && (\n <tfoot>\n <tr>\n <td colSpan={fullSizeColSpan} className=\"visits-table__footer-cell visits-table__sticky\">\n <div className=\"row\">\n <div className=\"col-md-6\">\n <SimplePaginator\n pagesCount={Math.ceil(resultSet.total / PAGE_SIZE)}\n currentPage={page}\n setCurrentPage={setPage}\n centered={isMobileDevice}\n />\n </div>\n <div\n className={classNames('col-md-6', {\n 'd-flex align-items-center flex-row-reverse': !isMobileDevice,\n 'text-center mt-3': isMobileDevice,\n })}\n >\n <div>\n Visits <b>{prettify(start + 1)}</b> to{' '}\n <b>{prettify(min(end, resultSet.total))}</b> of{' '}\n <b>{prettify(resultSet.total)}</b>\n </div>\n </div>\n </div>\n </td>\n </tr>\n </tfoot>\n )}\n </table>\n );\n};\n\nexport default VisitsTable;\n","import { useRef, useState } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faMapMarkedAlt as mapIcon } from '@fortawesome/free-solid-svg-icons';\nimport { Dropdown, DropdownItem, DropdownMenu, UncontrolledTooltip } from 'reactstrap';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { CityStats } from '../types';\nimport MapModal from './MapModal';\nimport './OpenMapModalBtn.scss';\n\ninterface OpenMapModalBtnProps {\n modalTitle: string;\n activeCities: string[];\n locations?: CityStats[];\n}\n\nconst OpenMapModalBtn = ({ modalTitle, activeCities, locations = [] }: OpenMapModalBtnProps) => {\n const [ mapIsOpened, , openMap, closeMap ] = useToggle();\n const [ dropdownIsOpened, toggleDropdown, openDropdown ] = useToggle();\n const [ locationsToShow, setLocationsToShow ] = useState<CityStats[]>([]);\n const buttonRef = useRef<HTMLElement>();\n\n const filterLocations = (cities: CityStats[]) => cities.filter(({ cityName }) => activeCities.includes(cityName));\n const onClick = () => {\n if (!activeCities) {\n setLocationsToShow(locations);\n openMap();\n\n return;\n }\n\n openDropdown();\n };\n const openMapWithLocations = (filtered: boolean) => () => {\n setLocationsToShow(filtered ? filterLocations(locations) : locations);\n openMap();\n };\n\n return (\n <>\n <button className=\"btn btn-link open-map-modal-btn__btn\" ref={buttonRef as any} onClick={onClick}>\n <FontAwesomeIcon icon={mapIcon} />\n </button>\n <UncontrolledTooltip placement=\"left\" target={(() => buttonRef.current) as any}>Show in map</UncontrolledTooltip>\n <Dropdown isOpen={dropdownIsOpened} toggle={toggleDropdown} inNavbar>\n <DropdownMenu right>\n <DropdownItem onClick={openMapWithLocations(false)}>Show all locations</DropdownItem>\n <DropdownItem onClick={openMapWithLocations(true)}>Show locations in current page</DropdownItem>\n </DropdownMenu>\n </Dropdown>\n <MapModal toggle={closeMap} isOpen={mapIsOpened} title={modalTitle} locations={locationsToShow} />\n </>\n );\n};\n\nexport default OpenMapModalBtn;\n","import { countBy, groupBy, pipe, prop } from 'ramda';\nimport { formatIsoDate } from '../../utils/helpers/date';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { CreateVisit, NormalizedOrphanVisit, NormalizedVisit, OrphanVisit, Stats, Visit, VisitsParams } from './index';\n\nexport const isOrphanVisit = (visit: Visit): visit is OrphanVisit => visit.hasOwnProperty('visitedUrl');\n\nexport const isNormalizedOrphanVisit = (visit: NormalizedVisit): visit is NormalizedOrphanVisit =>\n visit.hasOwnProperty('visitedUrl');\n\nexport interface GroupedNewVisits {\n orphanVisits: CreateVisit[];\n regularVisits: CreateVisit[];\n}\n\nexport const groupNewVisitsByType = pipe(\n groupBy((newVisit: CreateVisit) => isOrphanVisit(newVisit.visit) ? 'orphanVisits' : 'regularVisits'),\n // @ts-expect-error Type declaration on groupBy is not correct. It can return undefined props\n (result): GroupedNewVisits => ({ orphanVisits: [], regularVisits: [], ...result }),\n);\n\nexport type HighlightableProps<T extends NormalizedVisit> = T extends NormalizedOrphanVisit\n ? ('referer' | 'country' | 'city' | 'visitedUrl')\n : ('referer' | 'country' | 'city');\n\nexport const highlightedVisitsToStats = <T extends NormalizedVisit>(\n highlightedVisits: T[],\n property: HighlightableProps<T>,\n): Stats => countBy(prop(property) as any, highlightedVisits);\n\nexport const toApiParams = ({ page, itemsPerPage, filter, dateRange }: VisitsParams): ShlinkVisitsParams => {\n const startDate = (dateRange?.startDate && formatIsoDate(dateRange?.startDate)) ?? undefined;\n const endDate = (dateRange?.endDate && formatIsoDate(dateRange?.endDate)) ?? undefined;\n const excludeBots = filter?.excludeBots || undefined; // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing\n\n return { page, itemsPerPage, startDate, endDate, excludeBots };\n};\n","import { isNil, map } from 'ramda';\nimport { extractDomain, parseUserAgent } from '../../utils/helpers/visits';\nimport { hasValue } from '../../utils/utils';\nimport { CityStats, NormalizedVisit, Stats, Visit, VisitsStats } from '../types';\nimport { isNormalizedOrphanVisit, isOrphanVisit } from '../types/helpers';\n\nconst visitHasProperty = (visit: NormalizedVisit, propertyName: keyof NormalizedVisit) =>\n !isNil(visit) && hasValue(visit[propertyName]);\n\nconst optionalNumericToNumber = (numeric: string | number | null | undefined): number => {\n if (typeof numeric === 'number') {\n return numeric;\n }\n\n return numeric ? parseFloat(numeric) : 0;\n};\n\nconst updateOsStatsForVisit = (osStats: Stats, { os }: NormalizedVisit) => {\n osStats[os] = (osStats[os] || 0) + 1;\n};\n\nconst updateBrowsersStatsForVisit = (browsersStats: Stats, { browser }: NormalizedVisit) => {\n browsersStats[browser] = (browsersStats[browser] || 0) + 1;\n};\n\nconst updateReferrersStatsForVisit = (referrersStats: Stats, { referer: domain }: NormalizedVisit) => {\n referrersStats[domain] = (referrersStats[domain] || 0) + 1;\n};\n\nconst updateLocationsStatsForVisit = (propertyName: 'country' | 'city') => (stats: Stats, visit: NormalizedVisit) => {\n const hasLocationProperty = visitHasProperty(visit, propertyName);\n const value = hasLocationProperty ? visit[propertyName] : 'Unknown';\n\n stats[value] = (stats[value] || 0) + 1;\n};\n\nconst updateCountriesStatsForVisit = updateLocationsStatsForVisit('country');\nconst updateCitiesStatsForVisit = updateLocationsStatsForVisit('city');\n\nconst updateCitiesForMapForVisit = (citiesForMapStats: Record<string, CityStats>, visit: NormalizedVisit) => {\n if (!visitHasProperty(visit, 'city') || visit.city === 'Unknown') {\n return;\n }\n\n const { city, latitude, longitude } = visit;\n const currentCity = citiesForMapStats[city] || {\n cityName: city,\n count: 0,\n latLong: [ optionalNumericToNumber(latitude), optionalNumericToNumber(longitude) ],\n };\n\n currentCity.count++;\n\n citiesForMapStats[city] = currentCity;\n};\n\nconst updateVisitedUrlsForVisit = (visitedUrlsStats: Stats, visit: NormalizedVisit) => {\n if (!isNormalizedOrphanVisit(visit)) {\n return;\n }\n\n const { visitedUrl } = visit;\n\n visitedUrlsStats[visitedUrl] = (visitedUrlsStats[visitedUrl] || 0) + 1;\n};\n\nexport const processStatsFromVisits = (visits: NormalizedVisit[]) => visits.reduce(\n (stats: VisitsStats, visit: NormalizedVisit) => {\n // We mutate the original object because it has a big performance impact when large data sets are processed\n updateOsStatsForVisit(stats.os, visit);\n updateBrowsersStatsForVisit(stats.browsers, visit);\n updateReferrersStatsForVisit(stats.referrers, visit);\n updateCountriesStatsForVisit(stats.countries, visit);\n updateCitiesStatsForVisit(stats.cities, visit);\n updateCitiesForMapForVisit(stats.citiesForMap, visit);\n updateVisitedUrlsForVisit(stats.visitedUrls, visit);\n\n return stats;\n },\n { os: {}, browsers: {}, referrers: {}, countries: {}, cities: {}, citiesForMap: {}, visitedUrls: {} },\n);\n\nexport const normalizeVisits = map((visit: Visit): NormalizedVisit => {\n const { userAgent, date, referer, visitLocation, potentialBot = false } = visit;\n const common = {\n date,\n potentialBot,\n ...parseUserAgent(userAgent),\n referer: extractDomain(referer),\n country: visitLocation?.countryName || 'Unknown', // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing\n city: visitLocation?.cityName || 'Unknown', // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing\n latitude: visitLocation?.latitude,\n longitude: visitLocation?.longitude,\n };\n\n if (!isOrphanVisit(visit)) {\n return common;\n }\n\n return { ...common, type: visit.type, visitedUrl: visit.visitedUrl };\n});\n\nexport interface VisitsParser {\n processStatsFromVisits: (normalizedVisits: NormalizedVisit[]) => VisitsStats;\n normalizeVisits: (visits: Visit[]) => NormalizedVisit[];\n}\n","import { DropdownItem, DropdownItemProps } from 'reactstrap'; // eslint-disable-line import/named\nimport { OrphanVisitType, VisitsFilter } from '../types';\nimport { DropdownBtn } from '../../utils/DropdownBtn';\nimport { hasValue } from '../../utils/utils';\n\ninterface VisitsFilterDropdownProps {\n onChange: (filters: VisitsFilter) => void;\n selected?: VisitsFilter;\n className?: string;\n isOrphanVisits: boolean;\n botsSupported: boolean;\n}\n\nexport const VisitsFilterDropdown = (\n { onChange, selected = {}, className, isOrphanVisits, botsSupported }: VisitsFilterDropdownProps,\n) => {\n if (!botsSupported && !isOrphanVisits) {\n return null;\n }\n\n const { orphanVisitsType, excludeBots = false } = selected;\n const propsForOrphanVisitsTypeItem = (type: OrphanVisitType): DropdownItemProps => ({\n active: orphanVisitsType === type,\n onClick: () => onChange({ ...selected, orphanVisitsType: type === selected?.orphanVisitsType ? undefined : type }),\n });\n const onBotsClick = () => onChange({ ...selected, excludeBots: !selected?.excludeBots });\n\n return (\n <DropdownBtn text=\"Filters\" dropdownClassName={className} className=\"mr-3\" right minWidth={250}>\n {botsSupported && (\n <>\n <DropdownItem header>Bots:</DropdownItem>\n <DropdownItem active={excludeBots} onClick={onBotsClick}>Exclude potential bots</DropdownItem>\n </>\n )}\n\n {botsSupported && isOrphanVisits && <DropdownItem divider />}\n\n {isOrphanVisits && (\n <>\n <DropdownItem header>Orphan visits type:</DropdownItem>\n <DropdownItem {...propsForOrphanVisitsTypeItem('base_url')}>Base URL</DropdownItem>\n <DropdownItem {...propsForOrphanVisitsTypeItem('invalid_short_url')}>Invalid short URL</DropdownItem>\n <DropdownItem {...propsForOrphanVisitsTypeItem('regular_404')}>Regular 404</DropdownItem>\n </>\n )}\n\n <DropdownItem divider />\n <DropdownItem disabled={!hasValue(selected)} onClick={() => onChange({})}><i>Clear filters</i></DropdownItem>\n </DropdownBtn>\n );\n};\n","import { FC } from 'react';\nimport { Chart } from 'chart.js';\nimport './DoughnutChartLegend.scss';\n\ninterface DoughnutChartLegendProps {\n chart: Chart;\n}\n\nexport const DoughnutChartLegend: FC<DoughnutChartLegendProps> = ({ chart }) => {\n const { config } = chart;\n const { labels = [], datasets = [] } = config.data ?? {};\n const [{ backgroundColor: colors }] = datasets;\n const { defaultColor } = config.options ?? {} as any;\n\n return (\n <ul className=\"doughnut-chart-legend\">\n {(labels as string[]).map((label, index) => (\n <li key={label} className=\"doughnut-chart-legend__item d-flex\">\n <div\n className=\"doughnut-chart-legend__item-color\"\n style={{ backgroundColor: (colors as string[])[index] ?? defaultColor }}\n />\n <small className=\"doughnut-chart-legend__item-text flex-fill\">{label}</small>\n </li>\n ))}\n </ul>\n );\n};\n","import { FC, useState, memo } from 'react';\nimport { Chart, ChartData, ChartDataset, ChartOptions } from 'chart.js';\nimport { keys, values } from 'ramda';\nimport { Doughnut } from 'react-chartjs-2';\nimport { renderPieChartLabel } from '../../utils/helpers/charts';\nimport { isDarkThemeEnabled, PRIMARY_DARK_COLOR, PRIMARY_LIGHT_COLOR } from '../../utils/theme';\nimport { Stats } from '../types';\nimport { DoughnutChartLegend } from './DoughnutChartLegend';\n\ninterface DoughnutChartProps {\n stats: Stats;\n}\n\nconst generateChartDatasets = (data: number[]): ChartDataset[] => [\n {\n data,\n backgroundColor: [\n '#97BBCD',\n '#F7464A',\n '#46BFBD',\n '#FDB45C',\n '#949FB1',\n '#57A773',\n '#414066',\n '#08B2E3',\n '#B6C454',\n '#DCDCDC',\n '#463730',\n ],\n borderColor: isDarkThemeEnabled() ? PRIMARY_DARK_COLOR : PRIMARY_LIGHT_COLOR,\n borderWidth: 2,\n },\n];\nconst generateChartData = (labels: string[], data: number[]): ChartData => ({\n labels,\n datasets: generateChartDatasets(data),\n});\n\nexport const DoughnutChart: FC<DoughnutChartProps> = memo(({ stats }) => {\n const [ chartRef, setChartRef ] = useState<Chart | undefined>(); // Cannot use useRef here\n const labels = keys(stats);\n const data = values(stats);\n\n const options: ChartOptions = {\n plugins: {\n legend: { display: false },\n tooltip: {\n intersect: true,\n callbacks: { label: renderPieChartLabel },\n },\n },\n };\n const chartData = generateChartData(labels, data);\n\n return (\n <div className=\"row\">\n <div className=\"col-sm-12 col-md-7\">\n <Doughnut\n height={300}\n data={chartData}\n options={options}\n ref={(element) => {\n setChartRef(element ?? undefined);\n }}\n />\n </div>\n <div className=\"col-sm-12 col-md-5\">\n {chartRef && <DoughnutChartLegend chart={chartRef} />}\n </div>\n </div>\n );\n});\n","import { Card, CardHeader, CardBody, CardFooter } from 'reactstrap';\nimport { FC, ReactNode } from 'react';\nimport './ChartCard.scss';\n\ninterface ChartCardProps {\n title: Function | string;\n footer?: ReactNode;\n}\n\nexport const ChartCard: FC<ChartCardProps> = ({ title, footer, children }) => (\n <Card>\n <CardHeader className=\"chart-card__header\">{typeof title === 'function' ? title() : title}</CardHeader>\n <CardBody>{children}</CardBody>\n {footer && <CardFooter className=\"chart-card__footer--sticky\">{footer}</CardFooter>}\n </Card>\n);\n","import { FC } from 'react';\nimport { Stats } from '../types';\nimport { DoughnutChart } from './DoughnutChart';\nimport { ChartCard } from './ChartCard';\n\ninterface DoughnutChartCardProps {\n title: string;\n stats: Stats;\n}\n\nexport const DoughnutChartCard: FC<DoughnutChartCardProps> = ({ title, stats }) => (\n <ChartCard title={title}>\n <DoughnutChart stats={stats} />\n </ChartCard>\n);\n","import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';\n\ninterface PaginationDropdownProps {\n ranges: number[];\n value: number;\n setValue: (newValue: number) => void;\n toggleClassName?: string;\n}\n\nconst PaginationDropdown = ({ toggleClassName, ranges, value, setValue }: PaginationDropdownProps) => (\n <UncontrolledDropdown>\n <DropdownToggle caret color=\"link\" className={toggleClassName}>\n Paginate\n </DropdownToggle>\n <DropdownMenu right>\n {ranges.map((itemsPerPage) => (\n <DropdownItem key={itemsPerPage} active={itemsPerPage === value} onClick={() => setValue(itemsPerPage)}>\n <b>{itemsPerPage}</b> items per page\n </DropdownItem>\n ))}\n <DropdownItem divider />\n <DropdownItem disabled={value === Infinity} onClick={() => setValue(Infinity)}>\n <i>Clear pagination</i>\n </DropdownItem>\n </DropdownMenu>\n </UncontrolledDropdown>\n);\n\nexport default PaginationDropdown;\n","import { FC } from 'react';\nimport { ChartData, ChartDataset, ChartOptions } from 'chart.js';\nimport { keys, values } from 'ramda';\nimport { Bar } from 'react-chartjs-2';\nimport { fillTheGaps } from '../../utils/helpers/visits';\nimport { pointerOnHover, renderChartLabel } from '../../utils/helpers/charts';\nimport { prettify } from '../../utils/helpers/numbers';\nimport { Stats } from '../types';\nimport { HIGHLIGHTED_COLOR, HIGHLIGHTED_COLOR_ALPHA, MAIN_COLOR, MAIN_COLOR_ALPHA } from '../../utils/theme';\n\nexport interface HorizontalBarChartProps {\n stats: Stats;\n max?: number;\n highlightedStats?: Stats;\n highlightedLabel?: string;\n onClick?: (label: string) => void;\n}\n\nconst dropLabelIfHidden = (label: string) => label.startsWith('hidden') ? '' : label;\nconst statsAreDefined = (stats: Stats | undefined): stats is Stats => !!stats && Object.keys(stats).length > 0;\nconst determineHeight = (labels: string[]): number | undefined => labels.length > 20 ? labels.length * 10 : undefined;\n\nconst generateChartDatasets = (\n data: number[],\n highlightedData: number[],\n highlightedLabel?: string,\n): ChartDataset[] => {\n const mainDataset: ChartDataset = {\n data,\n label: highlightedLabel ? 'Non-selected' : 'Visits',\n backgroundColor: MAIN_COLOR_ALPHA,\n borderColor: MAIN_COLOR,\n borderWidth: 2,\n };\n\n if (highlightedData.every((value) => value === 0)) {\n return [ mainDataset ];\n }\n\n const highlightedDataset: ChartDataset = {\n label: highlightedLabel ?? 'Selected',\n data: highlightedData,\n backgroundColor: HIGHLIGHTED_COLOR_ALPHA,\n borderColor: HIGHLIGHTED_COLOR,\n borderWidth: 2,\n };\n\n return [ mainDataset, highlightedDataset ];\n};\nconst generateChartData = (\n labels: string[],\n data: number[],\n highlightedData: number[],\n highlightedLabel?: string,\n): ChartData => ({\n labels,\n datasets: generateChartDatasets(data, highlightedData, highlightedLabel),\n});\n\ntype ClickedCharts = [{ index: number }] | [];\nconst chartElementAtEvent = (labels: string[], onClick?: (label: string) => void) => ([ chart ]: ClickedCharts) => {\n if (!onClick || !chart) {\n return;\n }\n\n onClick(labels[chart.index]);\n};\n\nexport const HorizontalBarChart: FC<HorizontalBarChartProps> = (\n { stats, highlightedStats, highlightedLabel, onClick, max },\n) => {\n const labels = keys(stats).map(dropLabelIfHidden);\n const data = values(\n !statsAreDefined(highlightedStats) ? stats : keys(highlightedStats).reduce((acc, highlightedKey) => {\n if (acc[highlightedKey]) {\n acc[highlightedKey] -= highlightedStats[highlightedKey];\n }\n\n return acc;\n }, { ...stats }),\n );\n const highlightedData = fillTheGaps(highlightedStats ?? {}, labels);\n\n const options: ChartOptions = {\n plugins: {\n legend: { display: false },\n tooltip: {\n mode: 'y',\n // Do not show tooltip on items with empty label when in a bar chart\n filter: ({ label }) => label !== '',\n callbacks: { label: renderChartLabel },\n },\n },\n scales: {\n x: {\n beginAtZero: true,\n stacked: true,\n max,\n ticks: {\n precision: 0,\n callback: prettify,\n },\n },\n y: { stacked: true },\n },\n onHover: pointerOnHover,\n indexAxis: 'y',\n };\n const chartData = generateChartData(labels, data, highlightedData, highlightedLabel);\n const height = determineHeight(labels);\n\n // Provide a key based on the height, to force re-render every time the dataset changes (example, due to pagination)\n const renderChartComponent = (customKey: string) => (\n <Bar\n key={`${height}_${customKey}`}\n data={chartData}\n options={options}\n height={height}\n getElementAtEvent={chartElementAtEvent(labels, onClick) as any}\n />\n );\n\n return (\n <>\n {/* It's VERY IMPORTANT to render two different components here, as one has 1 dataset and the other has 2 */}\n {/* Using the same component causes a crash when switching from 1 to 2 datasets, and then back to 1 dataset */}\n {highlightedStats !== undefined && renderChartComponent('with_stats')}\n {highlightedStats === undefined && renderChartComponent('without_stats')}\n </>\n );\n};\n","import { FC, useState } from 'react';\nimport { fromPairs, pipe, reverse, sortBy, splitEvery, toLower, toPairs, type, zipObj } from 'ramda';\nimport { rangeOf } from '../../utils/utils';\nimport { Order } from '../../utils/helpers/ordering';\nimport SimplePaginator from '../../common/SimplePaginator';\nimport { roundTen } from '../../utils/helpers/numbers';\nimport { OrderingDropdown } from '../../utils/OrderingDropdown';\nimport PaginationDropdown from '../../utils/PaginationDropdown';\nimport { Stats, StatsRow } from '../types';\nimport { HorizontalBarChart, HorizontalBarChartProps } from './HorizontalBarChart';\nimport { ChartCard } from './ChartCard';\n\ninterface SortableBarChartCardProps extends Omit<HorizontalBarChartProps, 'max'> {\n title: Function | string;\n sortingItems: Record<string, string>;\n withPagination?: boolean;\n extraHeaderContent?: Function;\n}\n\nconst toLowerIfString = (value: any) => type(value) === 'String' ? toLower(value) : value; // eslint-disable-line @typescript-eslint/no-unsafe-return\nconst pickKeyFromPair = ([ key ]: StatsRow) => key;\nconst pickValueFromPair = ([ , value ]: StatsRow) => value;\n\nexport const SortableBarChartCard: FC<SortableBarChartCardProps> = ({\n stats,\n highlightedStats,\n title,\n sortingItems,\n extraHeaderContent,\n withPagination = true,\n ...rest\n}) => {\n const [ order, setOrder ] = useState<Order<string>>({});\n const [ currentPage, setCurrentPage ] = useState(1);\n const [ itemsPerPage, setItemsPerPage ] = useState(50);\n\n const getSortedPairsForStats = (stats: Stats, sortingItems: Record<string, string>) => {\n const pairs = toPairs(stats);\n const sortedPairs = !order.field ? pairs : sortBy(\n pipe<StatsRow, string | number, string | number>(\n order.field === Object.keys(sortingItems)[0] ? pickKeyFromPair : pickValueFromPair,\n toLowerIfString,\n ),\n pairs,\n );\n\n return !order.dir || order.dir === 'ASC' ? sortedPairs : reverse(sortedPairs);\n };\n const determineCurrentPagePairs = (pages: StatsRow[][]): StatsRow[] => {\n const page = pages[currentPage - 1];\n\n if (currentPage < pages.length) {\n return page;\n }\n\n const firstPageLength = pages[0].length;\n\n // Using the \"hidden\" key, the chart will just replace the label by an empty string\n return [ ...page, ...rangeOf(firstPageLength - page.length, (i): StatsRow => [ `hidden_${i}`, 0 ]) ];\n };\n const renderPagination = (pagesCount: number) =>\n <SimplePaginator currentPage={currentPage} pagesCount={pagesCount} setCurrentPage={setCurrentPage} />;\n const determineStats = (stats: Stats, highlightedStats: Stats | undefined, sortingItems: Record<string, string>) => {\n const sortedPairs = getSortedPairsForStats(stats, sortingItems);\n const sortedKeys = sortedPairs.map(pickKeyFromPair);\n // The highlighted stats have to be ordered based on the regular stats, not on its own values\n const sortedHighlightedPairs = highlightedStats && toPairs(\n { ...zipObj(sortedKeys, sortedKeys.map(() => 0)), ...highlightedStats },\n );\n\n if (sortedPairs.length <= itemsPerPage) {\n return {\n currentPageStats: fromPairs(sortedPairs),\n currentPageHighlightedStats: sortedHighlightedPairs && fromPairs(sortedHighlightedPairs),\n };\n }\n\n const pages = splitEvery(itemsPerPage, sortedPairs);\n const highlightedPages = sortedHighlightedPairs && splitEvery(itemsPerPage, sortedHighlightedPairs);\n\n return {\n currentPageStats: fromPairs(determineCurrentPagePairs(pages)),\n currentPageHighlightedStats: highlightedPages && fromPairs(determineCurrentPagePairs(highlightedPages)),\n pagination: renderPagination(pages.length),\n max: roundTen(Math.max(...sortedPairs.map(pickValueFromPair))),\n };\n };\n\n const { currentPageStats, currentPageHighlightedStats, pagination, max } = determineStats(\n stats,\n highlightedStats && Object.keys(highlightedStats).length > 0 ? highlightedStats : undefined,\n sortingItems,\n );\n const activeCities = Object.keys(currentPageStats);\n const computeTitle = () => (\n <>\n {title}\n <div className=\"float-right\">\n <OrderingDropdown\n isButton={false}\n right\n items={sortingItems}\n order={order}\n onChange={(field, dir) => {\n setOrder({ field, dir });\n setCurrentPage(1);\n }}\n />\n </div>\n {withPagination && Object.keys(stats).length > 50 && (\n <div className=\"float-right\">\n <PaginationDropdown\n toggleClassName=\"btn-sm p-0 mr-3\"\n ranges={[ 50, 100, 200, 500 ]}\n value={itemsPerPage}\n setValue={(itemsPerPage) => {\n setItemsPerPage(itemsPerPage);\n setCurrentPage(1);\n }}\n />\n </div>\n )}\n {extraHeaderContent && (\n <div className=\"float-right\">\n {extraHeaderContent(pagination ? activeCities : undefined)}\n </div>\n )}\n </>\n );\n\n return (\n <ChartCard\n title={computeTitle}\n footer={pagination}\n >\n <HorizontalBarChart stats={currentPageStats} highlightedStats={currentPageHighlightedStats} max={max} {...rest} />\n </ChartCard>\n );\n};\n","import { useEffect } from 'react';\nimport { useLocation, useParams } from 'react-router-dom';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { ShlinkVisitsParams } from '../api/types';\nimport { parseQuery } from '../utils/helpers/query';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail';\nimport { useGoBack } from '../utils/helpers/hooks';\nimport { ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits';\nimport ShortUrlVisitsHeader from './ShortUrlVisitsHeader';\nimport VisitsStats from './VisitsStats';\nimport { VisitsExporter } from './services/VisitsExporter';\nimport { NormalizedVisit, VisitsParams } from './types';\nimport { CommonVisitsProps } from './types/CommonVisitsProps';\nimport { toApiParams } from './types/helpers';\n\nexport interface ShortUrlVisitsProps extends CommonVisitsProps {\n getShortUrlVisits: (shortCode: string, query?: ShlinkVisitsParams, doIntervalFallback?: boolean) => void;\n shortUrlVisits: ShortUrlVisitsState;\n getShortUrlDetail: Function;\n shortUrlDetail: ShortUrlDetail;\n cancelGetShortUrlVisits: () => void;\n}\n\nconst ShortUrlVisits = ({ exportVisits }: VisitsExporter) => boundToMercureHub(({\n shortUrlVisits,\n shortUrlDetail,\n getShortUrlVisits,\n getShortUrlDetail,\n cancelGetShortUrlVisits,\n settings,\n selectedServer,\n}: ShortUrlVisitsProps) => {\n const { shortCode = '' } = useParams<{ shortCode: string }>();\n const { search } = useLocation();\n const goBack = useGoBack();\n const { domain } = parseQuery<{ domain?: string }>(search);\n const loadVisits = (params: VisitsParams, doIntervalFallback?: boolean) =>\n getShortUrlVisits(shortCode, { ...toApiParams(params), domain }, doIntervalFallback);\n const exportCsv = (visits: NormalizedVisit[]) => exportVisits(\n `short-url_${shortUrlDetail.shortUrl?.shortUrl.replace(/https?:\\/\\//g, '')}_visits.csv`,\n visits,\n );\n\n useEffect(() => {\n getShortUrlDetail(shortCode, domain);\n }, []);\n\n return (\n <VisitsStats\n getVisits={loadVisits}\n cancelGetVisits={cancelGetShortUrlVisits}\n visitsInfo={shortUrlVisits}\n domain={domain}\n settings={settings}\n exportCsv={exportCsv}\n selectedServer={selectedServer}\n >\n <ShortUrlVisitsHeader shortUrlDetail={shortUrlDetail} shortUrlVisits={shortUrlVisits} goBack={goBack} />\n </VisitsStats>\n );\n}, (_, params) => [ Topics.shortUrlVisits(params.shortCode) ]);\n\nexport default ShortUrlVisits;\n","import Tag from '../tags/helpers/Tag';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport VisitsHeader from './VisitsHeader';\nimport { TagVisits } from './reducers/tagVisits';\nimport './ShortUrlVisitsHeader.scss';\n\ninterface TagVisitsHeaderProps {\n tagVisits: TagVisits;\n goBack: () => void;\n colorGenerator: ColorGenerator;\n}\n\nconst TagVisitsHeader = ({ tagVisits, goBack, colorGenerator }: TagVisitsHeaderProps) => {\n const { visits, tag } = tagVisits;\n\n const visitsStatsTitle = (\n <span className=\"d-flex align-items-center justify-content-center\">\n <span className=\"mr-2\">Visits for</span>\n <Tag text={tag} colorGenerator={colorGenerator} />\n </span>\n );\n\n return <VisitsHeader title={visitsStatsTitle} goBack={goBack} visits={visits} />;\n};\n\nexport default TagVisitsHeader;\n","import { useParams } from 'react-router-dom';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport { ShlinkVisitsParams } from '../api/types';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { useGoBack } from '../utils/helpers/hooks';\nimport { TagVisits as TagVisitsState } from './reducers/tagVisits';\nimport TagVisitsHeader from './TagVisitsHeader';\nimport VisitsStats from './VisitsStats';\nimport { VisitsExporter } from './services/VisitsExporter';\nimport { NormalizedVisit } from './types';\nimport { CommonVisitsProps } from './types/CommonVisitsProps';\nimport { toApiParams } from './types/helpers';\n\nexport interface TagVisitsProps extends CommonVisitsProps {\n getTagVisits: (tag: string, query?: ShlinkVisitsParams, doIntervalFallback?: boolean) => void;\n tagVisits: TagVisitsState;\n cancelGetTagVisits: () => void;\n}\n\nconst TagVisits = (colorGenerator: ColorGenerator, { exportVisits }: VisitsExporter) => boundToMercureHub(({\n getTagVisits,\n tagVisits,\n cancelGetTagVisits,\n settings,\n selectedServer,\n}: TagVisitsProps) => {\n const goBack = useGoBack();\n const { tag = '' } = useParams();\n const loadVisits = (params: ShlinkVisitsParams, doIntervalFallback?: boolean) =>\n getTagVisits(tag, toApiParams(params), doIntervalFallback);\n const exportCsv = (visits: NormalizedVisit[]) => exportVisits(`tag_${tag}_visits.csv`, visits);\n\n return (\n <VisitsStats\n getVisits={loadVisits}\n cancelGetVisits={cancelGetTagVisits}\n visitsInfo={tagVisits}\n settings={settings}\n exportCsv={exportCsv}\n selectedServer={selectedServer}\n >\n <TagVisitsHeader tagVisits={tagVisits} goBack={goBack} colorGenerator={colorGenerator} />\n </VisitsStats>\n );\n}, () => [ Topics.visits ]);\n\nexport default TagVisits;\n","import VisitsHeader from './VisitsHeader';\nimport { VisitsInfo } from './types';\nimport './ShortUrlVisitsHeader.scss';\n\ninterface OrphanVisitsHeaderProps {\n orphanVisits: VisitsInfo;\n goBack: () => void;\n}\n\nexport const OrphanVisitsHeader = ({ orphanVisits, goBack }: OrphanVisitsHeaderProps) => {\n const { visits } = orphanVisits;\n\n return <VisitsHeader title=\"Orphan visits\" goBack={goBack} visits={visits} />;\n};\n","import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { ShlinkVisitsParams } from '../api/types';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { useGoBack } from '../utils/helpers/hooks';\nimport VisitsStats from './VisitsStats';\nimport { OrphanVisitsHeader } from './OrphanVisitsHeader';\nimport { NormalizedVisit, OrphanVisitType, VisitsInfo, VisitsParams } from './types';\nimport { VisitsExporter } from './services/VisitsExporter';\nimport { CommonVisitsProps } from './types/CommonVisitsProps';\nimport { toApiParams } from './types/helpers';\n\nexport interface OrphanVisitsProps extends CommonVisitsProps {\n getOrphanVisits: (\n params?: ShlinkVisitsParams,\n orphanVisitsType?: OrphanVisitType,\n doIntervalFallback?: boolean,\n ) => void;\n orphanVisits: VisitsInfo;\n cancelGetOrphanVisits: () => void;\n}\n\nexport const OrphanVisits = ({ exportVisits }: VisitsExporter) => boundToMercureHub(({\n getOrphanVisits,\n orphanVisits,\n cancelGetOrphanVisits,\n settings,\n selectedServer,\n}: OrphanVisitsProps) => {\n const goBack = useGoBack();\n const exportCsv = (visits: NormalizedVisit[]) => exportVisits('orphan_visits.csv', visits);\n const loadVisits = (params: VisitsParams, doIntervalFallback?: boolean) =>\n getOrphanVisits(toApiParams(params), params.filter?.orphanVisitsType, doIntervalFallback);\n\n return (\n <VisitsStats\n getVisits={loadVisits}\n cancelGetVisits={cancelGetOrphanVisits}\n visitsInfo={orphanVisits}\n settings={settings}\n exportCsv={exportCsv}\n selectedServer={selectedServer}\n isOrphanVisits\n >\n <OrphanVisitsHeader orphanVisits={orphanVisits} goBack={goBack} />\n </VisitsStats>\n );\n}, () => [ Topics.orphanVisits ]);\n","import VisitsHeader from './VisitsHeader';\nimport { VisitsInfo } from './types';\nimport './ShortUrlVisitsHeader.scss';\n\ninterface NonOrphanVisitsHeaderProps {\n nonOrphanVisits: VisitsInfo;\n goBack: () => void;\n}\n\nexport const NonOrphanVisitsHeader = ({ nonOrphanVisits, goBack }: NonOrphanVisitsHeaderProps) => {\n const { visits } = nonOrphanVisits;\n\n return <VisitsHeader title=\"Non-orphan visits\" goBack={goBack} visits={visits} />;\n};\n","import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { ShlinkVisitsParams } from '../api/types';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { useGoBack } from '../utils/helpers/hooks';\nimport VisitsStats from './VisitsStats';\nimport { NormalizedVisit, VisitsInfo, VisitsParams } from './types';\nimport { VisitsExporter } from './services/VisitsExporter';\nimport { CommonVisitsProps } from './types/CommonVisitsProps';\nimport { toApiParams } from './types/helpers';\nimport { NonOrphanVisitsHeader } from './NonOrphanVisitsHeader';\n\nexport interface NonOrphanVisitsProps extends CommonVisitsProps {\n getNonOrphanVisits: (params?: ShlinkVisitsParams, doIntervalFallback?: boolean) => void;\n nonOrphanVisits: VisitsInfo;\n cancelGetNonOrphanVisits: () => void;\n}\n\nexport const NonOrphanVisits = ({ exportVisits }: VisitsExporter) => boundToMercureHub(({\n getNonOrphanVisits,\n nonOrphanVisits,\n cancelGetNonOrphanVisits,\n settings,\n selectedServer,\n}: NonOrphanVisitsProps) => {\n const goBack = useGoBack();\n const exportCsv = (visits: NormalizedVisit[]) => exportVisits('non_orphan_visits.csv', visits);\n const loadVisits = (params: VisitsParams, doIntervalFallback?: boolean) =>\n getNonOrphanVisits(toApiParams(params), doIntervalFallback);\n\n return (\n <VisitsStats\n getVisits={loadVisits}\n cancelGetVisits={cancelGetNonOrphanVisits}\n visitsInfo={nonOrphanVisits}\n settings={settings}\n exportCsv={exportCsv}\n selectedServer={selectedServer}\n >\n <NonOrphanVisitsHeader nonOrphanVisits={nonOrphanVisits} goBack={goBack} />\n </VisitsStats>\n );\n}, () => [ Topics.visits ]);\n","import { flatten, prop, range, splitEvery } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { ShlinkPaginator, ShlinkVisits, ShlinkVisitsParams } from '../../api/types';\nimport { Visit } from '../types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { dateToMatchingInterval } from '../../utils/dates/types';\n\nconst ITEMS_PER_PAGE = 5000;\nconst PARALLEL_REQUESTS_COUNT = 4;\nconst PARALLEL_STARTING_PAGE = 2;\n\nconst isLastPage = ({ currentPage, pagesCount }: ShlinkPaginator): boolean => currentPage >= pagesCount;\nconst calcProgress = (total: number, current: number): number => current * 100 / total;\n\ntype VisitsLoader = (page: number, itemsPerPage: number) => Promise<ShlinkVisits>;\ntype LastVisitLoader = () => Promise<Visit | undefined>;\ninterface ActionMap {\n start: string;\n large: string;\n finish: string;\n error: string;\n progress: string;\n fallbackToInterval: string;\n}\n\nexport const getVisitsWithLoader = async <T extends Action<string> & { visits: Visit[] }>(\n visitsLoader: VisitsLoader,\n lastVisitLoader: LastVisitLoader,\n extraFinishActionData: Partial<T>,\n actionMap: ActionMap,\n dispatch: Dispatch,\n shouldCancel: () => boolean,\n) => {\n dispatch({ type: actionMap.start });\n\n const loadVisitsInParallel = async (pages: number[]): Promise<Visit[]> =>\n Promise.all(pages.map(async (page) => visitsLoader(page, ITEMS_PER_PAGE).then(prop('data')))).then(flatten);\n\n const loadPagesBlocks = async (pagesBlocks: number[][], index = 0): Promise<Visit[]> => {\n if (shouldCancel()) {\n return [];\n }\n\n const data = await loadVisitsInParallel(pagesBlocks[index]);\n\n dispatch({ type: actionMap.progress, progress: calcProgress(pagesBlocks.length, index + PARALLEL_STARTING_PAGE) });\n\n if (index < pagesBlocks.length - 1) {\n return data.concat(await loadPagesBlocks(pagesBlocks, index + 1));\n }\n\n return data;\n };\n\n const loadVisits = async (page = 1) => {\n const { pagination, data } = await visitsLoader(page, ITEMS_PER_PAGE);\n\n // If pagination was not returned, then this is an old shlink version. Just return data\n if (!pagination || isLastPage(pagination)) {\n return data;\n }\n\n // If there are more pages, make requests in blocks of 4\n const pagesRange = range(PARALLEL_STARTING_PAGE, pagination.pagesCount + 1);\n const pagesBlocks = splitEvery(PARALLEL_REQUESTS_COUNT, pagesRange);\n\n if (pagination.pagesCount - 1 > PARALLEL_REQUESTS_COUNT) {\n dispatch({ type: actionMap.large });\n }\n\n return data.concat(await loadPagesBlocks(pagesBlocks));\n };\n\n try {\n const [ visits, lastVisit ] = await Promise.all([ loadVisits(), lastVisitLoader() ]);\n\n dispatch(\n !visits.length && lastVisit\n ? { type: actionMap.fallbackToInterval, fallbackInterval: dateToMatchingInterval(lastVisit.date) }\n : { ...extraFinishActionData, visits, type: actionMap.finish },\n );\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: actionMap.error, errorData: parseApiError(e) });\n }\n};\n\nexport const lastVisitLoaderForLoader = (\n doIntervalFallback: boolean,\n loader: (params: ShlinkVisitsParams) => Promise<ShlinkVisits>,\n): LastVisitLoader => {\n if (!doIntervalFallback) {\n return async () => Promise.resolve(undefined);\n }\n\n return async () => loader({ page: 1, itemsPerPage: 1 }).then((result) => result.data[0]);\n};\n","import { Action, Dispatch } from 'redux';\nimport { shortUrlMatches } from '../../short-urls/helpers';\nimport { Visit, VisitsFallbackIntervalAction, VisitsInfo, VisitsLoadProgressChangedAction } from '../types';\nimport { ShortUrlIdentifier } from '../../short-urls/data';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { isBetween } from '../../utils/helpers/date';\nimport { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_SHORT_URL_VISITS_START = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_START';\nexport const GET_SHORT_URL_VISITS_ERROR = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_ERROR';\nexport const GET_SHORT_URL_VISITS = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS';\nexport const GET_SHORT_URL_VISITS_LARGE = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_LARGE';\nexport const GET_SHORT_URL_VISITS_CANCEL = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_CANCEL';\nexport const GET_SHORT_URL_VISITS_PROGRESS_CHANGED = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_PROGRESS_CHANGED';\nexport const GET_SHORT_URL_VISITS_FALLBACK_TO_INTERVAL = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_FALLBACK_TO_INTERVAL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface ShortUrlVisits extends VisitsInfo, ShortUrlIdentifier {}\n\ninterface ShortUrlVisitsAction extends Action<string>, ShortUrlIdentifier {\n visits: Visit[];\n query?: ShlinkVisitsParams;\n}\n\ntype ShortUrlVisitsCombinedAction = ShortUrlVisitsAction\n& VisitsLoadProgressChangedAction\n& VisitsFallbackIntervalAction\n& CreateVisitsAction\n& ApiErrorAction;\n\nconst initialState: ShortUrlVisits = {\n visits: [],\n shortCode: '',\n domain: undefined, // Deprecated. Value from query params can be used instead\n loading: false,\n loadingLarge: false,\n error: false,\n cancelLoad: false,\n progress: 0,\n};\n\nexport default buildReducer<ShortUrlVisits, ShortUrlVisitsCombinedAction>({\n [GET_SHORT_URL_VISITS_START]: () => ({ ...initialState, loading: true }),\n [GET_SHORT_URL_VISITS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [GET_SHORT_URL_VISITS]: (state, { visits, query, shortCode, domain }) => ({\n ...state,\n visits,\n shortCode,\n domain,\n query,\n loading: false,\n error: false,\n }),\n [GET_SHORT_URL_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),\n [GET_SHORT_URL_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),\n [GET_SHORT_URL_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),\n [GET_SHORT_URL_VISITS_FALLBACK_TO_INTERVAL]: (state, { fallbackInterval }) => ({ ...state, fallbackInterval }),\n [CREATE_VISITS]: (state, { createdVisits }) => {\n const { shortCode, domain, visits, query = {} } = state;\n const { startDate, endDate } = query;\n const newVisits = createdVisits\n .filter(\n ({ shortUrl, visit }) =>\n shortUrl && shortUrlMatches(shortUrl, shortCode, domain) && isBetween(visit.date, startDate, endDate),\n )\n .map(({ visit }) => visit);\n\n return newVisits.length === 0 ? state : { ...state, visits: [ ...newVisits, ...visits ] };\n },\n}, initialState);\n\nexport const getShortUrlVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n shortCode: string,\n query: ShlinkVisitsParams = {},\n doIntervalFallback = false,\n) => async (dispatch: Dispatch, getState: GetState) => {\n const { getShortUrlVisits } = buildShlinkApiClient(getState);\n const visitsLoader = async (page: number, itemsPerPage: number) => getShortUrlVisits(\n shortCode,\n { ...query, page, itemsPerPage },\n );\n const lastVisitLoader = lastVisitLoaderForLoader(\n doIntervalFallback,\n async (params) => getShortUrlVisits(shortCode, { ...params, domain: query.domain }),\n );\n const shouldCancel = () => getState().shortUrlVisits.cancelLoad;\n const extraFinishActionData: Partial<ShortUrlVisitsAction> = { shortCode, query, domain: query.domain };\n const actionMap = {\n start: GET_SHORT_URL_VISITS_START,\n large: GET_SHORT_URL_VISITS_LARGE,\n finish: GET_SHORT_URL_VISITS,\n error: GET_SHORT_URL_VISITS_ERROR,\n progress: GET_SHORT_URL_VISITS_PROGRESS_CHANGED,\n fallbackToInterval: GET_SHORT_URL_VISITS_FALLBACK_TO_INTERVAL,\n };\n\n return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, actionMap, dispatch, shouldCancel);\n};\n\nexport const cancelGetShortUrlVisits = buildActionCreator(GET_SHORT_URL_VISITS_CANCEL);\n","import { Action, Dispatch } from 'redux';\nimport { Visit, VisitsFallbackIntervalAction, VisitsInfo, VisitsLoadProgressChangedAction } from '../types';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { isBetween } from '../../utils/helpers/date';\nimport { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_TAG_VISITS_START = 'shlink/tagVisits/GET_TAG_VISITS_START';\nexport const GET_TAG_VISITS_ERROR = 'shlink/tagVisits/GET_TAG_VISITS_ERROR';\nexport const GET_TAG_VISITS = 'shlink/tagVisits/GET_TAG_VISITS';\nexport const GET_TAG_VISITS_LARGE = 'shlink/tagVisits/GET_TAG_VISITS_LARGE';\nexport const GET_TAG_VISITS_CANCEL = 'shlink/tagVisits/GET_TAG_VISITS_CANCEL';\nexport const GET_TAG_VISITS_PROGRESS_CHANGED = 'shlink/tagVisits/GET_TAG_VISITS_PROGRESS_CHANGED';\nexport const GET_TAG_VISITS_FALLBACK_TO_INTERVAL = 'shlink/tagVisits/GET_TAG_VISITS_FALLBACK_TO_INTERVAL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface TagVisits extends VisitsInfo {\n tag: string;\n}\n\nexport interface TagVisitsAction extends Action<string> {\n visits: Visit[];\n tag: string;\n query?: ShlinkVisitsParams;\n}\n\ntype TagsVisitsCombinedAction = TagVisitsAction\n& VisitsLoadProgressChangedAction\n& VisitsFallbackIntervalAction\n& CreateVisitsAction\n& ApiErrorAction;\n\nconst initialState: TagVisits = {\n visits: [],\n tag: '',\n loading: false,\n loadingLarge: false,\n error: false,\n cancelLoad: false,\n progress: 0,\n};\n\nexport default buildReducer<TagVisits, TagsVisitsCombinedAction>({\n [GET_TAG_VISITS_START]: () => ({ ...initialState, loading: true }),\n [GET_TAG_VISITS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [GET_TAG_VISITS]: (state, { visits, tag, query }) => ({ ...state, visits, tag, query, loading: false, error: false }),\n [GET_TAG_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),\n [GET_TAG_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),\n [GET_TAG_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),\n [GET_TAG_VISITS_FALLBACK_TO_INTERVAL]: (state, { fallbackInterval }) => ({ ...state, fallbackInterval }),\n [CREATE_VISITS]: (state, { createdVisits }) => {\n const { tag, visits, query = {} } = state;\n const { startDate, endDate } = query;\n const newVisits = createdVisits\n .filter(({ shortUrl, visit }) => shortUrl?.tags.includes(tag) && isBetween(visit.date, startDate, endDate))\n .map(({ visit }) => visit);\n\n return { ...state, visits: [ ...newVisits, ...visits ] };\n },\n}, initialState);\n\nexport const getTagVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n tag: string,\n query: ShlinkVisitsParams = {},\n doIntervalFallback = false,\n) => async (dispatch: Dispatch, getState: GetState) => {\n const { getTagVisits } = buildShlinkApiClient(getState);\n const visitsLoader = async (page: number, itemsPerPage: number) => getTagVisits(\n tag,\n { ...query, page, itemsPerPage },\n );\n const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, async (params) => getTagVisits(tag, params));\n const shouldCancel = () => getState().tagVisits.cancelLoad;\n const extraFinishActionData: Partial<TagVisitsAction> = { tag, query };\n const actionMap = {\n start: GET_TAG_VISITS_START,\n large: GET_TAG_VISITS_LARGE,\n finish: GET_TAG_VISITS,\n error: GET_TAG_VISITS_ERROR,\n progress: GET_TAG_VISITS_PROGRESS_CHANGED,\n fallbackToInterval: GET_TAG_VISITS_FALLBACK_TO_INTERVAL,\n };\n\n return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, actionMap, dispatch, shouldCancel);\n};\n\nexport const cancelGetTagVisits = buildActionCreator(GET_TAG_VISITS_CANCEL);\n","import { Action, Dispatch } from 'redux';\nimport {\n OrphanVisit,\n OrphanVisitType,\n Visit,\n VisitsFallbackIntervalAction,\n VisitsInfo,\n VisitsLoadProgressChangedAction,\n} from '../types';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { isOrphanVisit } from '../types/helpers';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { isBetween } from '../../utils/helpers/date';\nimport { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_ORPHAN_VISITS_START = 'shlink/orphanVisits/GET_ORPHAN_VISITS_START';\nexport const GET_ORPHAN_VISITS_ERROR = 'shlink/orphanVisits/GET_ORPHAN_VISITS_ERROR';\nexport const GET_ORPHAN_VISITS = 'shlink/orphanVisits/GET_ORPHAN_VISITS';\nexport const GET_ORPHAN_VISITS_LARGE = 'shlink/orphanVisits/GET_ORPHAN_VISITS_LARGE';\nexport const GET_ORPHAN_VISITS_CANCEL = 'shlink/orphanVisits/GET_ORPHAN_VISITS_CANCEL';\nexport const GET_ORPHAN_VISITS_PROGRESS_CHANGED = 'shlink/orphanVisits/GET_ORPHAN_VISITS_PROGRESS_CHANGED';\nexport const GET_ORPHAN_VISITS_FALLBACK_TO_INTERVAL = 'shlink/orphanVisits/GET_ORPHAN_VISITS_FALLBACK_TO_INTERVAL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface OrphanVisitsAction extends Action<string> {\n visits: Visit[];\n query?: ShlinkVisitsParams;\n}\n\ntype OrphanVisitsCombinedAction = OrphanVisitsAction\n& VisitsLoadProgressChangedAction\n& VisitsFallbackIntervalAction\n& CreateVisitsAction\n& ApiErrorAction;\n\nconst initialState: VisitsInfo = {\n visits: [],\n loading: false,\n loadingLarge: false,\n error: false,\n cancelLoad: false,\n progress: 0,\n};\n\nexport default buildReducer<VisitsInfo, OrphanVisitsCombinedAction>({\n [GET_ORPHAN_VISITS_START]: () => ({ ...initialState, loading: true }),\n [GET_ORPHAN_VISITS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [GET_ORPHAN_VISITS]: (state, { visits, query }) => ({ ...state, visits, query, loading: false, error: false }),\n [GET_ORPHAN_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),\n [GET_ORPHAN_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),\n [GET_ORPHAN_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),\n [GET_ORPHAN_VISITS_FALLBACK_TO_INTERVAL]: (state, { fallbackInterval }) => ({ ...state, fallbackInterval }),\n [CREATE_VISITS]: (state, { createdVisits }) => {\n const { visits, query = {} } = state;\n const { startDate, endDate } = query;\n const newVisits = createdVisits\n .filter(({ visit, shortUrl }) => !shortUrl && isBetween(visit.date, startDate, endDate))\n .map(({ visit }) => visit);\n\n return { ...state, visits: [ ...newVisits, ...visits ] };\n },\n}, initialState);\n\nconst matchesType = (visit: OrphanVisit, orphanVisitsType?: OrphanVisitType) =>\n !orphanVisitsType || orphanVisitsType === visit.type;\n\nexport const getOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n query: ShlinkVisitsParams = {},\n orphanVisitsType?: OrphanVisitType,\n doIntervalFallback = false,\n) => async (dispatch: Dispatch, getState: GetState) => {\n const { getOrphanVisits } = buildShlinkApiClient(getState);\n const visitsLoader = async (page: number, itemsPerPage: number) => getOrphanVisits({ ...query, page, itemsPerPage })\n .then((result) => {\n const visits = result.data.filter((visit) => isOrphanVisit(visit) && matchesType(visit, orphanVisitsType));\n\n return { ...result, data: visits };\n });\n const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, getOrphanVisits);\n const shouldCancel = () => getState().orphanVisits.cancelLoad;\n const extraFinishActionData: Partial<OrphanVisitsAction> = { query };\n const actionMap = {\n start: GET_ORPHAN_VISITS_START,\n large: GET_ORPHAN_VISITS_LARGE,\n finish: GET_ORPHAN_VISITS,\n error: GET_ORPHAN_VISITS_ERROR,\n progress: GET_ORPHAN_VISITS_PROGRESS_CHANGED,\n fallbackToInterval: GET_ORPHAN_VISITS_FALLBACK_TO_INTERVAL,\n };\n\n return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, actionMap, dispatch, shouldCancel);\n};\n\nexport const cancelGetOrphanVisits = buildActionCreator(GET_ORPHAN_VISITS_CANCEL);\n","import { Action, Dispatch } from 'redux';\nimport {\n Visit,\n VisitsFallbackIntervalAction,\n VisitsInfo,\n VisitsLoadProgressChangedAction,\n} from '../types';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { ShlinkVisitsParams } from '../../api/types';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { isBetween } from '../../utils/helpers/date';\nimport { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_NON_ORPHAN_VISITS_START = 'shlink/orphanVisits/GET_NON_ORPHAN_VISITS_START';\nexport const GET_NON_ORPHAN_VISITS_ERROR = 'shlink/orphanVisits/GET_NON_ORPHAN_VISITS_ERROR';\nexport const GET_NON_ORPHAN_VISITS = 'shlink/orphanVisits/GET_NON_ORPHAN_VISITS';\nexport const GET_NON_ORPHAN_VISITS_LARGE = 'shlink/orphanVisits/GET_NON_ORPHAN_VISITS_LARGE';\nexport const GET_NON_ORPHAN_VISITS_CANCEL = 'shlink/orphanVisits/GET_NON_ORPHAN_VISITS_CANCEL';\nexport const GET_NON_ORPHAN_VISITS_PROGRESS_CHANGED = 'shlink/orphanVisits/GET_NON_ORPHAN_VISITS_PROGRESS_CHANGED';\nexport const GET_NON_ORPHAN_VISITS_FALLBACK_TO_INTERVAL = 'shlink/orphanVisits/GET_NON_ORPHAN_VISITS_FALLBACK_TO_INTERVAL';\n/* eslint-enable padding-line-between-statements */\n\nexport interface NonOrphanVisitsAction extends Action<string> {\n visits: Visit[];\n query?: ShlinkVisitsParams;\n}\n\ntype NonOrphanVisitsCombinedAction = NonOrphanVisitsAction\n& VisitsLoadProgressChangedAction\n& VisitsFallbackIntervalAction\n& CreateVisitsAction\n& ApiErrorAction;\n\nconst initialState: VisitsInfo = {\n visits: [],\n loading: false,\n loadingLarge: false,\n error: false,\n cancelLoad: false,\n progress: 0,\n};\n\nexport default buildReducer<VisitsInfo, NonOrphanVisitsCombinedAction>({\n [GET_NON_ORPHAN_VISITS_START]: () => ({ ...initialState, loading: true }),\n [GET_NON_ORPHAN_VISITS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [GET_NON_ORPHAN_VISITS]: (state, { visits, query }) => ({ ...state, visits, query, loading: false, error: false }),\n [GET_NON_ORPHAN_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),\n [GET_NON_ORPHAN_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),\n [GET_NON_ORPHAN_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),\n [GET_NON_ORPHAN_VISITS_FALLBACK_TO_INTERVAL]: (state, { fallbackInterval }) => ({ ...state, fallbackInterval }),\n [CREATE_VISITS]: (state, { createdVisits }) => {\n const { visits, query = {} } = state;\n const { startDate, endDate } = query;\n const newVisits = createdVisits\n .filter(({ visit }) => isBetween(visit.date, startDate, endDate))\n .map(({ visit }) => visit);\n\n return { ...state, visits: [ ...newVisits, ...visits ] };\n },\n}, initialState);\n\nexport const getNonOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n query: ShlinkVisitsParams = {},\n doIntervalFallback = false,\n) => async (dispatch: Dispatch, getState: GetState) => {\n const { getNonOrphanVisits } = buildShlinkApiClient(getState);\n const visitsLoader = async (page: number, itemsPerPage: number) =>\n getNonOrphanVisits({ ...query, page, itemsPerPage });\n const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, getNonOrphanVisits);\n const shouldCancel = () => getState().orphanVisits.cancelLoad;\n const extraFinishActionData: Partial<NonOrphanVisitsAction> = { query };\n const actionMap = {\n start: GET_NON_ORPHAN_VISITS_START,\n large: GET_NON_ORPHAN_VISITS_LARGE,\n finish: GET_NON_ORPHAN_VISITS,\n error: GET_NON_ORPHAN_VISITS_ERROR,\n progress: GET_NON_ORPHAN_VISITS_PROGRESS_CHANGED,\n fallbackToInterval: GET_NON_ORPHAN_VISITS_FALLBACK_TO_INTERVAL,\n };\n\n return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, actionMap, dispatch, shouldCancel);\n};\n\nexport const cancelGetNonOrphanVisits = buildActionCreator(GET_NON_ORPHAN_VISITS_CANCEL);\n","import { Action, Dispatch } from 'redux';\nimport { ShlinkVisitsOverview } from '../../api/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { groupNewVisitsByType } from '../types/helpers';\nimport { CREATE_VISITS, CreateVisitsAction } from './visitCreation';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_OVERVIEW_START = 'shlink/visitsOverview/GET_OVERVIEW_START';\nexport const GET_OVERVIEW_ERROR = 'shlink/visitsOverview/GET_OVERVIEW_ERROR';\nexport const GET_OVERVIEW = 'shlink/visitsOverview/GET_OVERVIEW';\n/* eslint-enable padding-line-between-statements */\n\nexport interface VisitsOverview {\n visitsCount: number;\n orphanVisitsCount?: number;\n loading: boolean;\n error: boolean;\n}\n\nexport type GetVisitsOverviewAction = ShlinkVisitsOverview & Action<string>;\n\nconst initialState: VisitsOverview = {\n visitsCount: 0,\n orphanVisitsCount: 0,\n loading: false,\n error: false,\n};\n\nexport default buildReducer<VisitsOverview, GetVisitsOverviewAction & CreateVisitsAction>({\n [GET_OVERVIEW_START]: () => ({ ...initialState, loading: true }),\n [GET_OVERVIEW_ERROR]: () => ({ ...initialState, error: true }),\n [GET_OVERVIEW]: (_, { visitsCount, orphanVisitsCount }) => ({ ...initialState, visitsCount, orphanVisitsCount }),\n [CREATE_VISITS]: ({ visitsCount, orphanVisitsCount = 0, ...rest }, { createdVisits }) => {\n const { regularVisits, orphanVisits } = groupNewVisitsByType(createdVisits);\n\n return {\n ...rest,\n visitsCount: visitsCount + regularVisits.length,\n orphanVisitsCount: orphanVisitsCount + orphanVisits.length,\n };\n },\n}, initialState);\n\nexport const loadVisitsOverview = (buildShlinkApiClient: ShlinkApiClientBuilder) => () => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch({ type: GET_OVERVIEW_START });\n\n try {\n const { getVisitsOverview } = buildShlinkApiClient(getState);\n const result = await getVisitsOverview();\n\n dispatch({ type: GET_OVERVIEW, ...result });\n } catch (e) {\n dispatch({ type: GET_OVERVIEW_ERROR });\n }\n};\n","import { CsvJson } from 'csvjson';\nimport { NormalizedVisit } from '../types';\nimport { saveCsv } from '../../utils/helpers/files';\n\nexport class VisitsExporter {\n public constructor(\n private readonly window: Window,\n private readonly csvjson: CsvJson,\n ) {}\n\n public readonly exportVisits = (filename: string, visits: NormalizedVisit[]) => {\n if (!visits.length) {\n return;\n }\n\n const csv = this.csvjson.toCSV(visits, { headers: 'key' });\n\n saveCsv(this.window, csv, filename);\n };\n}\n","import Bottle from 'bottlejs';\nimport MapModal from '../helpers/MapModal';\nimport { createNewVisits } from '../reducers/visitCreation';\nimport ShortUrlVisits from '../ShortUrlVisits';\nimport TagVisits from '../TagVisits';\nimport { OrphanVisits } from '../OrphanVisits';\nimport { NonOrphanVisits } from '../NonOrphanVisits';\nimport { cancelGetShortUrlVisits, getShortUrlVisits } from '../reducers/shortUrlVisits';\nimport { cancelGetTagVisits, getTagVisits } from '../reducers/tagVisits';\nimport { cancelGetOrphanVisits, getOrphanVisits } from '../reducers/orphanVisits';\nimport { cancelGetNonOrphanVisits, getNonOrphanVisits } from '../reducers/nonOrphanVisits';\nimport { ConnectDecorator } from '../../container/types';\nimport { loadVisitsOverview } from '../reducers/visitsOverview';\nimport * as visitsParser from './VisitsParser';\nimport { VisitsExporter } from './VisitsExporter';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('MapModal', () => MapModal);\n\n bottle.serviceFactory('ShortUrlVisits', ShortUrlVisits, 'VisitsExporter');\n bottle.decorator('ShortUrlVisits', connect(\n [ 'shortUrlVisits', 'shortUrlDetail', 'mercureInfo', 'settings', 'selectedServer' ],\n [ 'getShortUrlVisits', 'getShortUrlDetail', 'cancelGetShortUrlVisits', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n bottle.serviceFactory('TagVisits', TagVisits, 'ColorGenerator', 'VisitsExporter');\n bottle.decorator('TagVisits', connect(\n [ 'tagVisits', 'mercureInfo', 'settings', 'selectedServer' ],\n [ 'getTagVisits', 'cancelGetTagVisits', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n bottle.serviceFactory('OrphanVisits', OrphanVisits, 'VisitsExporter');\n bottle.decorator('OrphanVisits', connect(\n [ 'orphanVisits', 'mercureInfo', 'settings', 'selectedServer' ],\n [ 'getOrphanVisits', 'cancelGetOrphanVisits', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n bottle.serviceFactory('NonOrphanVisits', NonOrphanVisits, 'VisitsExporter');\n bottle.decorator('NonOrphanVisits', connect(\n [ 'nonOrphanVisits', 'mercureInfo', 'settings', 'selectedServer' ],\n [ 'getNonOrphanVisits', 'cancelGetNonOrphanVisits', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n // Services\n bottle.serviceFactory('VisitsParser', () => visitsParser);\n bottle.service('VisitsExporter', VisitsExporter, 'window', 'csvjson');\n\n // Actions\n bottle.serviceFactory('getShortUrlVisits', getShortUrlVisits, 'buildShlinkApiClient');\n bottle.serviceFactory('cancelGetShortUrlVisits', () => cancelGetShortUrlVisits);\n\n bottle.serviceFactory('getTagVisits', getTagVisits, 'buildShlinkApiClient');\n bottle.serviceFactory('cancelGetTagVisits', () => cancelGetTagVisits);\n\n bottle.serviceFactory('getOrphanVisits', getOrphanVisits, 'buildShlinkApiClient');\n bottle.serviceFactory('cancelGetOrphanVisits', () => cancelGetOrphanVisits);\n\n bottle.serviceFactory('getNonOrphanVisits', getNonOrphanVisits, 'buildShlinkApiClient');\n bottle.serviceFactory('cancelGetNonOrphanVisits', () => cancelGetNonOrphanVisits);\n\n bottle.serviceFactory('createNewVisits', () => createNewVisits);\n bottle.serviceFactory('loadVisitsOverview', loadVisitsOverview, 'buildShlinkApiClient');\n};\n\nexport default provideServices;\n","import ColorGenerator from '../../utils/services/ColorGenerator';\nimport './TagBullet.scss';\n\ninterface TagBulletProps {\n tag: string;\n colorGenerator: ColorGenerator;\n}\n\nconst TagBullet = ({ tag, colorGenerator }: TagBulletProps) => (\n <div\n style={{ backgroundColor: colorGenerator.getColorForKey(tag) }}\n className=\"tag-bullet\"\n />\n);\n\nexport default TagBullet;\n","import { useEffect } from 'react';\nimport ReactTags, { SuggestionComponentProps, TagComponentProps } from 'react-tag-autocomplete';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport { Settings } from '../../settings/reducers/settings';\nimport { TagsList } from '../reducers/tagsList';\nimport TagBullet from './TagBullet';\nimport Tag from './Tag';\n\nexport interface TagsSelectorProps {\n selectedTags: string[];\n onChange: (tags: string[]) => void;\n placeholder?: string;\n}\n\ninterface TagsSelectorConnectProps extends TagsSelectorProps {\n listTags: Function;\n tagsList: TagsList;\n settings: Settings;\n}\n\nconst toComponentTag = (tag: string) => ({ id: tag, name: tag });\n\nconst TagsSelector = (colorGenerator: ColorGenerator) => (\n { selectedTags, onChange, placeholder, listTags, tagsList, settings }: TagsSelectorConnectProps,\n) => {\n useEffect(() => {\n listTags();\n }, []);\n\n const searchMode = settings.shortUrlCreation?.tagFilteringMode ?? 'startsWith';\n const ReactTagsTag = ({ tag, onDelete }: TagComponentProps) =>\n <Tag colorGenerator={colorGenerator} text={tag.name} clearable className=\"react-tags__tag\" onClose={onDelete} />;\n const ReactTagsSuggestion = ({ item }: SuggestionComponentProps) => (\n <>\n <TagBullet tag={`${item.name}`} colorGenerator={colorGenerator} />\n {item.name}\n </>\n );\n\n return (\n <ReactTags\n tags={selectedTags.map(toComponentTag)}\n tagComponent={ReactTagsTag}\n suggestions={tagsList.tags.filter((tag) => !selectedTags.includes(tag)).map(toComponentTag)}\n suggestionComponent={ReactTagsSuggestion}\n allowNew\n addOnBlur\n placeholderText={placeholder ?? 'Add tags to the URL'}\n minQueryLength={1}\n delimiters={[ 'Enter', 'Tab', ',' ]}\n suggestionsTransform={\n searchMode === 'includes'\n ? (query, suggestions) => suggestions.filter(({ name }) => name.includes(query))\n : undefined\n }\n onDelete={(removedTagIndex) => {\n const tagsCopy = [ ...selectedTags ];\n\n tagsCopy.splice(removedTagIndex, 1);\n onChange(tagsCopy);\n }}\n onAddition={({ name: newTag }) => onChange(\n // * Avoid duplicated tags (thanks to the Set),\n // * Split any of the new tags by comma, allowing to paste multiple comma-separated tags at once.\n [ ...new Set([ ...selectedTags, ...newTag.toLowerCase().split(',') ]) ],\n )}\n />\n );\n};\n\nexport default TagsSelector;\n","import { Card, CardHeader, CardBody, Button, Collapse } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faTrash as deleteIcon, faPencilAlt as editIcon, faLink, faEye } from '@fortawesome/free-solid-svg-icons';\nimport { FC, useEffect, useRef } from 'react';\nimport { Link } from 'react-router-dom';\nimport { prettify } from '../utils/helpers/numbers';\nimport { useToggle } from '../utils/helpers/hooks';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport { getServerId, SelectedServer } from '../servers/data';\nimport TagBullet from './helpers/TagBullet';\nimport { NormalizedTag, TagModalProps } from './data';\nimport './TagCard.scss';\n\nexport interface TagCardProps {\n tag: NormalizedTag;\n selectedServer: SelectedServer;\n displayed: boolean;\n toggle: () => void;\n}\n\nconst isTruncated = (el: HTMLElement | undefined): boolean => !!el && el.scrollWidth > el.clientWidth;\n\nconst TagCard = (\n DeleteTagConfirmModal: FC<TagModalProps>,\n EditTagModal: FC<TagModalProps>,\n colorGenerator: ColorGenerator,\n) => ({ tag, selectedServer, displayed, toggle }: TagCardProps) => {\n const [ isDeleteModalOpen, toggleDelete ] = useToggle();\n const [ isEditModalOpen, toggleEdit ] = useToggle();\n const [ hasTitle,, displayTitle ] = useToggle();\n const titleRef = useRef<HTMLElement>();\n const serverId = getServerId(selectedServer);\n\n useEffect(() => {\n if (isTruncated(titleRef.current)) {\n displayTitle();\n }\n }, [ titleRef.current ]);\n\n return (\n <Card className=\"tag-card\">\n <CardHeader className=\"tag-card__header\">\n <Button color=\"link\" size=\"sm\" className=\"tag-card__btn tag-card__btn--last\" onClick={toggleDelete}>\n <FontAwesomeIcon icon={deleteIcon} />\n </Button>\n <Button color=\"link\" size=\"sm\" className=\"tag-card__btn\" onClick={toggleEdit}>\n <FontAwesomeIcon icon={editIcon} />\n </Button>\n <h5\n className=\"tag-card__tag-title text-ellipsis\"\n title={hasTitle ? tag.tag : undefined}\n ref={(el) => {\n titleRef.current = el ?? undefined;\n }}\n >\n <TagBullet tag={tag.tag} colorGenerator={colorGenerator} />\n <span className=\"tag-card__tag-name\" onClick={toggle}>{tag.tag}</span>\n </h5>\n </CardHeader>\n\n <Collapse isOpen={displayed}>\n <CardBody className=\"tag-card__body\">\n <Link\n to={`/server/${serverId}/list-short-urls/1?tags=${encodeURIComponent(tag.tag)}`}\n className=\"btn btn-outline-secondary btn-block d-flex justify-content-between align-items-center mb-1\"\n >\n <span className=\"text-ellipsis\"><FontAwesomeIcon icon={faLink} className=\"mr-2\" />Short URLs</span>\n <b>{prettify(tag.shortUrls)}</b>\n </Link>\n <Link\n to={`/server/${serverId}/tag/${tag.tag}/visits`}\n className=\"btn btn-outline-secondary btn-block d-flex justify-content-between align-items-center\"\n >\n <span className=\"text-ellipsis\"><FontAwesomeIcon icon={faEye} className=\"mr-2\" />Visits</span>\n <b>{prettify(tag.visits)}</b>\n </Link>\n </CardBody>\n </Collapse>\n\n <DeleteTagConfirmModal tag={tag.tag} toggle={toggleDelete} isOpen={isDeleteModalOpen} />\n <EditTagModal tag={tag.tag} toggle={toggleEdit} isOpen={isEditModalOpen} />\n </Card>\n );\n};\n\nexport default TagCard;\n","import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { TagDeletion } from '../reducers/tagDelete';\nimport { TagModalProps } from '../data';\nimport { Result } from '../../utils/Result';\nimport { ShlinkApiError } from '../../api/ShlinkApiError';\n\ninterface DeleteTagConfirmModalProps extends TagModalProps {\n deleteTag: (tag: string) => Promise<void>;\n tagDeleted: (tag: string) => void;\n tagDelete: TagDeletion;\n}\n\nconst DeleteTagConfirmModal = (\n { tag, toggle, isOpen, deleteTag, tagDelete, tagDeleted }: DeleteTagConfirmModalProps,\n) => {\n const { deleting, error, errorData } = tagDelete;\n const doDelete = async () => {\n await deleteTag(tag);\n tagDeleted(tag);\n toggle();\n };\n\n return (\n <Modal toggle={toggle} isOpen={isOpen} centered>\n <ModalHeader toggle={toggle}>\n <span className=\"text-danger\">Delete tag</span>\n </ModalHeader>\n <ModalBody>\n Are you sure you want to delete tag <b>{tag}</b>?\n {error && (\n <Result type=\"error\" small className=\"mt-2\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"Something went wrong while deleting the tag :(\" />\n </Result>\n )}\n </ModalBody>\n <ModalFooter>\n <button className=\"btn btn-link\" onClick={toggle}>Cancel</button>\n <button className=\"btn btn-danger\" disabled={deleting} onClick={doDelete}>\n {deleting ? 'Deleting tag...' : 'Delete tag'}\n </button>\n </ModalFooter>\n </Modal>\n );\n};\n\nexport default DeleteTagConfirmModal;\n","import { useState } from 'react';\nimport { Button, Input, Modal, ModalBody, ModalFooter, ModalHeader, Popover } from 'reactstrap';\nimport { ChromePicker } from 'react-color';\nimport { faPalette as colorIcon } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { useToggle } from '../../utils/helpers/hooks';\nimport { handleEventPreventingDefault } from '../../utils/utils';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport { TagModalProps } from '../data';\nimport { TagEdition } from '../reducers/tagEdit';\nimport { Result } from '../../utils/Result';\nimport { ShlinkApiError } from '../../api/ShlinkApiError';\nimport './EditTagModal.scss';\n\ninterface EditTagModalProps extends TagModalProps {\n tagEdit: TagEdition;\n editTag: (oldName: string, newName: string, color: string) => Promise<void>;\n tagEdited: (oldName: string, newName: string, color: string) => void;\n}\n\nconst EditTagModal = ({ getColorForKey }: ColorGenerator) => (\n { tag, editTag, toggle, tagEdited, isOpen, tagEdit }: EditTagModalProps,\n) => {\n const [ newTagName, setNewTagName ] = useState(tag);\n const [ color, setColor ] = useState(getColorForKey(tag));\n const [ showColorPicker, toggleColorPicker, , hideColorPicker ] = useToggle();\n const { editing, error, errorData } = tagEdit;\n const saveTag = handleEventPreventingDefault(\n async () => editTag(tag, newTagName, color)\n .then(() => tagEdited(tag, newTagName, color))\n .then(toggle)\n .catch(() => {}),\n );\n\n return (\n <Modal isOpen={isOpen} toggle={toggle} centered onClosed={hideColorPicker}>\n <form onSubmit={saveTag}>\n <ModalHeader toggle={toggle}>Edit tag</ModalHeader>\n <ModalBody>\n <div className=\"input-group\">\n <div className=\"input-group-prepend\" id=\"colorPickerBtn\" onClick={toggleColorPicker}>\n <div\n className=\"input-group-text edit-tag-modal__color-picker-toggle\"\n style={{ backgroundColor: color, borderColor: color }}\n >\n <FontAwesomeIcon icon={colorIcon} className=\"edit-tag-modal__color-icon\" />\n </div>\n </div>\n <Popover isOpen={showColorPicker} toggle={toggleColorPicker} target=\"colorPickerBtn\" placement=\"right\">\n <ChromePicker color={color} disableAlpha onChange={({ hex }) => setColor(hex)} />\n </Popover>\n <Input\n value={newTagName}\n placeholder=\"Tag\"\n required\n onChange={({ target }) => setNewTagName(target.value)}\n />\n </div>\n\n {error && (\n <Result type=\"error\" small className=\"mt-2\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"Something went wrong while editing the tag :(\" />\n </Result>\n )}\n </ModalBody>\n <ModalFooter>\n <Button type=\"button\" color=\"link\" onClick={toggle}>Cancel</Button>\n <Button color=\"primary\" disabled={editing}>{editing ? 'Saving...' : 'Save'}</Button>\n </ModalFooter>\n </form>\n </Modal>\n );\n};\n\nexport default EditTagModal;\n","import { SelectedServer } from '../../servers/data';\nimport { Order } from '../../utils/helpers/ordering';\nimport { NormalizedTag } from './index';\n\nexport const TAGS_ORDERABLE_FIELDS = {\n tag: 'Tag',\n shortUrls: 'Short URLs',\n visits: 'Visits',\n};\n\nexport type TagsOrderableFields = keyof typeof TAGS_ORDERABLE_FIELDS;\n\nexport type TagsOrder = Order<TagsOrderableFields>;\n\nexport interface TagsListChildrenProps {\n sortedTags: NormalizedTag[];\n selectedServer: SelectedServer;\n}\n","import { FC } from 'react';\nimport { DropdownItem } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faBars as listIcon, faThLarge as cardsIcon } from '@fortawesome/free-solid-svg-icons';\nimport { DropdownBtn } from '../utils/DropdownBtn';\nimport { TagsMode } from '../settings/reducers/settings';\n\ninterface TagsModeDropdownProps {\n mode: TagsMode;\n onChange: (newMode: TagsMode) => void;\n renderTitle?: (mode: TagsMode) => string;\n}\n\nexport const TagsModeDropdown: FC<TagsModeDropdownProps> = ({ mode, onChange, renderTitle }) => (\n <DropdownBtn text={renderTitle?.(mode) ?? `Display mode: ${mode}`}>\n <DropdownItem active={mode === 'cards'} onClick={() => onChange('cards')}>\n <FontAwesomeIcon icon={cardsIcon} fixedWidth className=\"mr-1\" /> Cards\n </DropdownItem>\n <DropdownItem active={mode === 'list'} onClick={() => onChange('list')}>\n <FontAwesomeIcon icon={listIcon} fixedWidth className=\"mr-1\" /> List\n </DropdownItem>\n </DropdownBtn>\n);\n","import { FC, useEffect, useState } from 'react';\nimport { Row } from 'reactstrap';\nimport { pipe } from 'ramda';\nimport Message from '../utils/Message';\nimport SearchField from '../utils/SearchField';\nimport { SelectedServer } from '../servers/data';\nimport { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';\nimport { Result } from '../utils/Result';\nimport { ShlinkApiError } from '../api/ShlinkApiError';\nimport { Topics } from '../mercure/helpers/Topics';\nimport { Settings, TagsMode } from '../settings/reducers/settings';\nimport { determineOrderDir, sortList } from '../utils/helpers/ordering';\nimport { OrderingDropdown } from '../utils/OrderingDropdown';\nimport { TagsList as TagsListState } from './reducers/tagsList';\nimport {\n TagsOrderableFields,\n TAGS_ORDERABLE_FIELDS,\n TagsListChildrenProps,\n TagsOrder,\n} from './data/TagsListChildrenProps';\nimport { TagsModeDropdown } from './TagsModeDropdown';\nimport { NormalizedTag } from './data';\nimport { TagsTableProps } from './TagsTable';\n\nexport interface TagsListProps {\n filterTags: (searchTerm: string) => void;\n forceListTags: Function;\n tagsList: TagsListState;\n selectedServer: SelectedServer;\n settings: Settings;\n}\n\nconst TagsList = (TagsCards: FC<TagsListChildrenProps>, TagsTable: FC<TagsTableProps>) => boundToMercureHub((\n { filterTags, forceListTags, tagsList, selectedServer, settings }: TagsListProps,\n) => {\n const [ mode, setMode ] = useState<TagsMode>(settings.tags?.defaultMode ?? 'cards');\n const [ order, setOrder ] = useState<TagsOrder>(settings.tags?.defaultOrdering ?? {});\n const resolveSortedTags = pipe(\n () => tagsList.filteredTags.map((tag): NormalizedTag => ({\n tag,\n shortUrls: tagsList.stats[tag]?.shortUrlsCount ?? 0,\n visits: tagsList.stats[tag]?.visitsCount ?? 0,\n })),\n (normalizedTags) => sortList<NormalizedTag>(normalizedTags, order),\n );\n\n useEffect(() => {\n forceListTags();\n }, []);\n\n if (tagsList.loading) {\n return <Message loading />;\n }\n\n if (tagsList.error) {\n return (\n <Result type=\"error\">\n <ShlinkApiError errorData={tagsList.errorData} fallbackMessage=\"Error loading tags :(\" />\n </Result>\n );\n }\n\n const orderByColumn = (field: TagsOrderableFields) => () => {\n const dir = determineOrderDir(field, order.field, order.dir);\n\n setOrder({ field: dir ? field : undefined, dir });\n };\n\n const renderContent = () => {\n if (tagsList.filteredTags.length < 1) {\n return <Message>No tags found</Message>;\n }\n\n const sortedTags = resolveSortedTags();\n\n return mode === 'cards'\n ? <TagsCards sortedTags={sortedTags} selectedServer={selectedServer} />\n : (\n <TagsTable\n sortedTags={sortedTags}\n selectedServer={selectedServer}\n currentOrder={order}\n orderByColumn={orderByColumn}\n />\n );\n };\n\n return (\n <>\n <SearchField className=\"mb-3\" onChange={filterTags} />\n <Row className=\"mb-3\">\n <div className=\"col-lg-6\">\n <TagsModeDropdown mode={mode} onChange={setMode} />\n </div>\n <div className=\"col-lg-6 mt-3 mt-lg-0\">\n <OrderingDropdown\n items={TAGS_ORDERABLE_FIELDS}\n order={order}\n onChange={(field, dir) => setOrder({ field, dir })}\n />\n </div>\n </Row>\n {renderContent()}\n </>\n );\n}, () => [ Topics.visits ]);\n\nexport default TagsList;\n","import { Action, Dispatch } from 'redux';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { GetState } from '../../container/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const DELETE_TAG_START = 'shlink/deleteTag/DELETE_TAG_START';\nexport const DELETE_TAG_ERROR = 'shlink/deleteTag/DELETE_TAG_ERROR';\nexport const DELETE_TAG = 'shlink/deleteTag/DELETE_TAG';\nexport const TAG_DELETED = 'shlink/deleteTag/TAG_DELETED';\n/* eslint-enable padding-line-between-statements */\n\nexport interface TagDeletion {\n deleting: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface DeleteTagAction extends Action<string> {\n tag: string;\n}\n\nconst initialState: TagDeletion = {\n deleting: false,\n error: false,\n};\n\nexport default buildReducer<TagDeletion, ApiErrorAction>({\n [DELETE_TAG_START]: () => ({ deleting: true, error: false }),\n [DELETE_TAG_ERROR]: (_, { errorData }) => ({ deleting: false, error: true, errorData }),\n [DELETE_TAG]: () => ({ deleting: false, error: false }),\n}, initialState);\n\nexport const deleteTag = (buildShlinkApiClient: ShlinkApiClientBuilder) => (tag: string) => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch({ type: DELETE_TAG_START });\n const { deleteTags } = buildShlinkApiClient(getState);\n\n try {\n await deleteTags([ tag ]);\n dispatch({ type: DELETE_TAG });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: DELETE_TAG_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n\nexport const tagDeleted = (tag: string): DeleteTagAction => ({ type: TAG_DELETED, tag });\n","import { pick } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { GetState } from '../../container/types';\nimport ColorGenerator from '../../utils/services/ColorGenerator';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ProblemDetailsError } from '../../api/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\n\n/* eslint-disable padding-line-between-statements */\nexport const EDIT_TAG_START = 'shlink/editTag/EDIT_TAG_START';\nexport const EDIT_TAG_ERROR = 'shlink/editTag/EDIT_TAG_ERROR';\nexport const EDIT_TAG = 'shlink/editTag/EDIT_TAG';\n/* eslint-enable padding-line-between-statements */\n\nexport const TAG_EDITED = 'shlink/editTag/TAG_EDITED';\n\nexport interface TagEdition {\n oldName: string;\n newName: string;\n editing: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface EditTagAction extends Action<string> {\n oldName: string;\n newName: string;\n color: string;\n}\n\nconst initialState: TagEdition = {\n oldName: '',\n newName: '',\n editing: false,\n error: false,\n};\n\nexport default buildReducer<TagEdition, EditTagAction & ApiErrorAction>({\n [EDIT_TAG_START]: (state) => ({ ...state, editing: true, error: false }),\n [EDIT_TAG_ERROR]: (state, { errorData }) => ({ ...state, editing: false, error: true, errorData }),\n [EDIT_TAG]: (_, action) => ({\n ...pick([ 'oldName', 'newName' ], action),\n editing: false,\n error: false,\n }),\n}, initialState);\n\nexport const editTag = (buildShlinkApiClient: ShlinkApiClientBuilder, colorGenerator: ColorGenerator) => (\n oldName: string,\n newName: string,\n color: string,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: EDIT_TAG_START });\n const { editTag } = buildShlinkApiClient(getState);\n\n try {\n await editTag(oldName, newName);\n colorGenerator.setColorForKey(newName, color);\n dispatch({ type: EDIT_TAG, oldName, newName });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: EDIT_TAG_ERROR, errorData: parseApiError(e) });\n\n throw e;\n }\n};\n\nexport const tagEdited = (oldName: string, newName: string, color: string): EditTagAction => ({\n type: TAG_EDITED,\n oldName,\n newName,\n color,\n});\n","import { isEmpty, reject } from 'ramda';\nimport { Action, Dispatch } from 'redux';\nimport { CREATE_VISITS, CreateVisitsAction } from '../../visits/reducers/visitCreation';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { ProblemDetailsError, ShlinkTags } from '../../api/types';\nimport { GetState } from '../../container/types';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { CreateVisit, Stats } from '../../visits/types';\nimport { parseApiError } from '../../api/utils';\nimport { TagStats } from '../data';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { CREATE_SHORT_URL, CreateShortUrlAction } from '../../short-urls/reducers/shortUrlCreation';\nimport { DeleteTagAction, TAG_DELETED } from './tagDelete';\nimport { EditTagAction, TAG_EDITED } from './tagEdit';\n\n/* eslint-disable padding-line-between-statements */\nexport const LIST_TAGS_START = 'shlink/tagsList/LIST_TAGS_START';\nexport const LIST_TAGS_ERROR = 'shlink/tagsList/LIST_TAGS_ERROR';\nexport const LIST_TAGS = 'shlink/tagsList/LIST_TAGS';\nexport const FILTER_TAGS = 'shlink/tagsList/FILTER_TAGS';\n/* eslint-enable padding-line-between-statements */\n\ntype TagsStatsMap = Record<string, TagStats>;\n\nexport interface TagsList {\n tags: string[];\n filteredTags: string[];\n stats: TagsStatsMap;\n loading: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\ninterface ListTagsAction extends Action<string> {\n tags: string[];\n stats: TagsStatsMap;\n}\n\ninterface FilterTagsAction extends Action<string> {\n searchTerm: string;\n}\n\ntype TagsCombinedAction = ListTagsAction\n& DeleteTagAction\n& CreateVisitsAction\n& CreateShortUrlAction\n& EditTagAction\n& FilterTagsAction\n& ApiErrorAction;\n\nconst initialState = {\n tags: [],\n filteredTags: [],\n stats: {},\n loading: false,\n error: false,\n};\n\ntype TagIncrease = [string, number];\n\nconst renameTag = (oldName: string, newName: string) => (tag: string) => tag === oldName ? newName : tag;\nconst rejectTag = (tags: string[], tagToReject: string) => reject((tag) => tag === tagToReject, tags);\nconst increaseVisitsForTags = (tags: TagIncrease[], stats: TagsStatsMap) => tags.reduce((stats, [ tag, increase ]) => {\n if (!stats[tag]) {\n return stats;\n }\n\n const tagStats = stats[tag];\n\n tagStats.visitsCount = tagStats.visitsCount + increase;\n stats[tag] = tagStats;\n\n return stats;\n}, { ...stats });\nconst calculateVisitsPerTag = (createdVisits: CreateVisit[]): TagIncrease[] => Object.entries(\n createdVisits.reduce<Stats>((acc, { shortUrl }) => {\n shortUrl?.tags.forEach((tag) => {\n acc[tag] = (acc[tag] || 0) + 1;\n });\n\n return acc;\n }, {}),\n);\n\nexport default buildReducer<TagsList, TagsCombinedAction>({\n [LIST_TAGS_START]: () => ({ ...initialState, loading: true }),\n [LIST_TAGS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),\n [LIST_TAGS]: (_, { tags, stats }) => ({ ...initialState, stats, tags, filteredTags: tags }),\n [TAG_DELETED]: (state, { tag }) => ({\n ...state,\n tags: rejectTag(state.tags, tag),\n filteredTags: rejectTag(state.filteredTags, tag),\n }),\n [TAG_EDITED]: (state, { oldName, newName }) => ({\n ...state,\n tags: state.tags.map(renameTag(oldName, newName)).sort(),\n filteredTags: state.filteredTags.map(renameTag(oldName, newName)).sort(),\n }),\n [FILTER_TAGS]: (state, { searchTerm }) => ({\n ...state,\n filteredTags: state.tags.filter((tag) => tag.toLowerCase().match(searchTerm)),\n }),\n [CREATE_VISITS]: (state, { createdVisits }) => ({\n ...state,\n stats: increaseVisitsForTags(calculateVisitsPerTag(createdVisits), state.stats),\n }),\n [CREATE_SHORT_URL]: ({ tags: stateTags, ...rest }, { result }) => ({\n ...rest,\n tags: stateTags.concat(result.tags.filter((tag) => !stateTags.includes(tag))), // More performant than [ ...new Set(...) ]\n }),\n}, initialState);\n\nexport const listTags = (buildShlinkApiClient: ShlinkApiClientBuilder, force = true) => () => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n const { tagsList } = getState();\n\n if (!force && (tagsList.loading || !isEmpty(tagsList.tags))) {\n return;\n }\n\n dispatch({ type: LIST_TAGS_START });\n\n try {\n const { listTags } = buildShlinkApiClient(getState);\n const { tags, stats = [] }: ShlinkTags = await listTags();\n const processedStats = stats.reduce<TagsStatsMap>((acc, { tag, shortUrlsCount, visitsCount }) => {\n acc[tag] = { shortUrlsCount, visitsCount };\n\n return acc;\n }, {});\n\n dispatch<ListTagsAction>({ tags, stats: processedStats, type: LIST_TAGS });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: LIST_TAGS_ERROR, errorData: parseApiError(e) });\n }\n};\n\nexport const filterTags = (searchTerm: string): FilterTagsAction => ({ type: FILTER_TAGS, searchTerm });\n","import { FC, useState } from 'react';\nimport { splitEvery } from 'ramda';\nimport { Row } from 'reactstrap';\nimport { TagCardProps } from './TagCard';\nimport { TagsListChildrenProps } from './data/TagsListChildrenProps';\n\nconst { ceil } = Math;\nconst TAGS_GROUPS_AMOUNT = 4;\n\nexport const TagsCards = (TagCard: FC<TagCardProps>): FC<TagsListChildrenProps> => ({ sortedTags, selectedServer }) => {\n const [ displayedTag, setDisplayedTag ] = useState<string | undefined>();\n const tagsCount = sortedTags.length;\n const tagsGroups = splitEvery(ceil(tagsCount / TAGS_GROUPS_AMOUNT), sortedTags);\n\n return (\n <Row>\n {tagsGroups.map((group, index) => (\n <div key={index} className=\"col-md-6 col-xl-3\">\n {group.map((tag) => (\n <TagCard\n key={tag.tag}\n tag={tag}\n selectedServer={selectedServer}\n displayed={displayedTag === tag.tag}\n toggle={() => setDisplayedTag(displayedTag !== tag.tag ? tag.tag : undefined)}\n />\n ))}\n </div>\n ))}\n </Row>\n );\n};\n","import { FC, useEffect, useRef } from 'react';\nimport { splitEvery } from 'ramda';\nimport { useLocation } from 'react-router-dom';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport SimplePaginator from '../common/SimplePaginator';\nimport { useQueryState } from '../utils/helpers/hooks';\nimport { parseQuery } from '../utils/helpers/query';\nimport { TableOrderIcon } from '../utils/table/TableOrderIcon';\nimport { TagsOrderableFields, TagsListChildrenProps, TagsOrder } from './data/TagsListChildrenProps';\nimport { TagsTableRowProps } from './TagsTableRow';\nimport './TagsTable.scss';\n\nexport interface TagsTableProps extends TagsListChildrenProps {\n orderByColumn: (field: TagsOrderableFields) => () => void;\n currentOrder: TagsOrder;\n}\n\nconst TAGS_PER_PAGE = 20; // TODO Allow customizing this value in settings\n\nexport const TagsTable = (TagsTableRow: FC<TagsTableRowProps>) => (\n { sortedTags, selectedServer, orderByColumn, currentOrder }: TagsTableProps,\n) => {\n const isFirstLoad = useRef(true);\n const { search } = useLocation();\n const { page: pageFromQuery = 1 } = parseQuery<{ page?: number | string }>(search);\n const [ page, setPage ] = useQueryState<number>('page', Number(pageFromQuery));\n const pages = splitEvery(TAGS_PER_PAGE, sortedTags);\n const showPaginator = pages.length > 1;\n const currentPage = pages[page - 1] ?? [];\n\n useEffect(() => {\n !isFirstLoad.current && setPage(1);\n isFirstLoad.current = false;\n }, [ sortedTags ]);\n useEffect(() => {\n scrollTo(0, 0);\n }, [ page ]);\n\n return (\n <SimpleCard key={page} bodyClassName={showPaginator ? 'pb-1' : ''}>\n <table className=\"table table-hover mb-0\">\n <thead className=\"responsive-table__header\">\n <tr>\n <th className=\"tags-table__header-cell\" onClick={orderByColumn('tag')}>\n Tag <TableOrderIcon currentOrder={currentOrder} field=\"tag\" />\n </th>\n <th className=\"tags-table__header-cell text-lg-right\" onClick={orderByColumn('shortUrls')}>\n Short URLs <TableOrderIcon currentOrder={currentOrder} field=\"shortUrls\" />\n </th>\n <th className=\"tags-table__header-cell text-lg-right\" onClick={orderByColumn('visits')}>\n Visits <TableOrderIcon currentOrder={currentOrder} field=\"visits\" />\n </th>\n <th className=\"tags-table__header-cell\" />\n </tr>\n <tr><th colSpan={4} className=\"p-0 border-top-0\" /></tr>\n </thead>\n <tbody>\n {currentPage.length === 0 && <tr><td colSpan={4} className=\"text-center\">No results found</td></tr>}\n {currentPage.map((tag) => <TagsTableRow key={tag.tag} tag={tag} selectedServer={selectedServer} />)}\n </tbody>\n </table>\n\n {showPaginator && (\n <div className=\"sticky-card-paginator\">\n <SimplePaginator pagesCount={pages.length} currentPage={page} setCurrentPage={setPage} />\n </div>\n )}\n </SimpleCard>\n );\n};\n","import { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport { DropdownItem } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faTrash as deleteIcon, faPencilAlt as editIcon } from '@fortawesome/free-solid-svg-icons';\nimport { getServerId, SelectedServer } from '../servers/data';\nimport ColorGenerator from '../utils/services/ColorGenerator';\nimport { prettify } from '../utils/helpers/numbers';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { DropdownBtnMenu } from '../utils/DropdownBtnMenu';\nimport TagBullet from './helpers/TagBullet';\nimport { NormalizedTag, TagModalProps } from './data';\n\nexport interface TagsTableRowProps {\n tag: NormalizedTag;\n selectedServer: SelectedServer;\n}\n\nexport const TagsTableRow = (\n DeleteTagConfirmModal: FC<TagModalProps>,\n EditTagModal: FC<TagModalProps>,\n colorGenerator: ColorGenerator,\n) => ({ tag, selectedServer }: TagsTableRowProps) => {\n const [ isDeleteModalOpen, toggleDelete ] = useToggle();\n const [ isEditModalOpen, toggleEdit ] = useToggle();\n const [ isDropdownOpen, toggleDropdown ] = useToggle();\n const serverId = getServerId(selectedServer);\n\n return (\n <tr className=\"responsive-table__row\">\n <th className=\"responsive-table__cell\" data-th=\"Tag\">\n <TagBullet tag={tag.tag} colorGenerator={colorGenerator} /> {tag.tag}\n </th>\n <td className=\"responsive-table__cell text-lg-right\" data-th=\"Short URLs\">\n <Link to={`/server/${serverId}/list-short-urls/1?tags=${encodeURIComponent(tag.tag)}`}>\n {prettify(tag.shortUrls)}\n </Link>\n </td>\n <td className=\"responsive-table__cell text-lg-right\" data-th=\"Visits\">\n <Link to={`/server/${serverId}/tag/${tag.tag}/visits`}>\n {prettify(tag.visits)}\n </Link>\n </td>\n <td className=\"responsive-table__cell text-lg-right\">\n <DropdownBtnMenu toggle={toggleDropdown} isOpen={isDropdownOpen}>\n <DropdownItem onClick={toggleEdit}>\n <FontAwesomeIcon icon={editIcon} fixedWidth className=\"mr-1\" /> Edit\n </DropdownItem>\n <DropdownItem onClick={toggleDelete}>\n <FontAwesomeIcon icon={deleteIcon} fixedWidth className=\"mr-1\" /> Delete\n </DropdownItem>\n </DropdownBtnMenu>\n </td>\n\n <EditTagModal tag={tag.tag} toggle={toggleEdit} isOpen={isEditModalOpen} />\n <DeleteTagConfirmModal tag={tag.tag} toggle={toggleDelete} isOpen={isDeleteModalOpen} />\n </tr>\n );\n};\n","import Bottle, { IContainer } from 'bottlejs';\nimport TagsSelector from '../helpers/TagsSelector';\nimport TagCard from '../TagCard';\nimport DeleteTagConfirmModal from '../helpers/DeleteTagConfirmModal';\nimport EditTagModal from '../helpers/EditTagModal';\nimport TagsList from '../TagsList';\nimport { filterTags, listTags } from '../reducers/tagsList';\nimport { deleteTag, tagDeleted } from '../reducers/tagDelete';\nimport { editTag, tagEdited } from '../reducers/tagEdit';\nimport { ConnectDecorator } from '../../container/types';\nimport { TagsCards } from '../TagsCards';\nimport { TagsTable } from '../TagsTable';\nimport { TagsTableRow } from '../TagsTableRow';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('TagsSelector', TagsSelector, 'ColorGenerator');\n bottle.decorator('TagsSelector', connect([ 'tagsList', 'settings' ], [ 'listTags' ]));\n\n bottle.serviceFactory('TagCard', TagCard, 'DeleteTagConfirmModal', 'EditTagModal', 'ColorGenerator');\n\n bottle.serviceFactory('DeleteTagConfirmModal', () => DeleteTagConfirmModal);\n bottle.decorator('DeleteTagConfirmModal', connect([ 'tagDelete' ], [ 'deleteTag', 'tagDeleted' ]));\n\n bottle.serviceFactory('EditTagModal', EditTagModal, 'ColorGenerator');\n bottle.decorator('EditTagModal', connect([ 'tagEdit' ], [ 'editTag', 'tagEdited' ]));\n\n bottle.serviceFactory('TagsCards', TagsCards, 'TagCard');\n bottle.serviceFactory('TagsTableRow', TagsTableRow, 'DeleteTagConfirmModal', 'EditTagModal', 'ColorGenerator');\n\n bottle.serviceFactory('TagsTable', TagsTable, 'TagsTableRow');\n\n bottle.serviceFactory('TagsList', TagsList, 'TagsCards', 'TagsTable');\n bottle.decorator('TagsList', connect(\n [ 'tagsList', 'selectedServer', 'mercureInfo', 'settings' ],\n [ 'forceListTags', 'filterTags', 'createNewVisits', 'loadMercureInfo' ],\n ));\n\n // Actions\n const listTagsActionFactory = (force: boolean) =>\n ({ buildShlinkApiClient }: IContainer) => listTags(buildShlinkApiClient, force);\n\n bottle.factory('listTags', listTagsActionFactory(false));\n bottle.factory('forceListTags', listTagsActionFactory(true));\n bottle.serviceFactory('filterTags', () => filterTags);\n bottle.serviceFactory('tagDeleted', () => tagDeleted);\n bottle.serviceFactory('tagEdited', () => tagEdited);\n\n bottle.serviceFactory('deleteTag', deleteTag, 'buildShlinkApiClient');\n bottle.serviceFactory('editTag', editTag, 'buildShlinkApiClient', 'ColorGenerator');\n};\n\nexport default provideServices;\n","import { Action, Dispatch } from 'redux';\nimport { ShlinkMercureInfo } from '../../api/types';\nimport { GetState } from '../../container/types';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\n\n/* eslint-disable padding-line-between-statements */\nexport const GET_MERCURE_INFO_START = 'shlink/mercure/GET_MERCURE_INFO_START';\nexport const GET_MERCURE_INFO_ERROR = 'shlink/mercure/GET_MERCURE_INFO_ERROR';\nexport const GET_MERCURE_INFO = 'shlink/mercure/GET_MERCURE_INFO';\n/* eslint-enable padding-line-between-statements */\n\nexport interface MercureInfo {\n token?: string;\n mercureHubUrl?: string;\n interval?: number;\n loading: boolean;\n error: boolean;\n}\n\nexport type GetMercureInfoAction = Action<string> & ShlinkMercureInfo & { interval?: number };\n\nconst initialState: MercureInfo = {\n loading: true,\n error: false,\n};\n\nexport default buildReducer<MercureInfo, GetMercureInfoAction>({\n [GET_MERCURE_INFO_START]: (state) => ({ ...state, loading: true, error: false }),\n [GET_MERCURE_INFO_ERROR]: (state) => ({ ...state, loading: false, error: true }),\n [GET_MERCURE_INFO]: (_, action) => ({ ...action, loading: false, error: false }),\n}, initialState);\n\nexport const loadMercureInfo = (buildShlinkApiClient: ShlinkApiClientBuilder) =>\n () => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: GET_MERCURE_INFO_START });\n\n const { settings } = getState();\n const { mercureInfo } = buildShlinkApiClient(getState);\n\n if (!settings.realTimeUpdates.enabled) {\n dispatch({ type: GET_MERCURE_INFO_ERROR });\n\n return;\n }\n\n try {\n const info = await mercureInfo();\n\n dispatch<GetMercureInfoAction>({ type: GET_MERCURE_INFO, interval: settings.realTimeUpdates.interval, ...info });\n } catch (e) {\n dispatch({ type: GET_MERCURE_INFO_ERROR });\n }\n };\n","import Bottle from 'bottlejs';\nimport { loadMercureInfo } from '../reducers/mercureInfo';\n\nconst provideServices = (bottle: Bottle) => {\n // Actions\n bottle.serviceFactory('loadMercureInfo', loadMercureInfo, 'buildShlinkApiClient');\n};\n\nexport default provideServices;\n","import { FormGroup, Input } from 'reactstrap';\nimport classNames from 'classnames';\nimport ToggleSwitch from '../utils/ToggleSwitch';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { Settings } from './reducers/settings';\n\ninterface RealTimeUpdatesProps {\n settings: Settings;\n toggleRealTimeUpdates: (enabled: boolean) => void;\n setRealTimeUpdatesInterval: (interval: number) => void;\n}\n\nconst intervalValue = (interval?: number) => !interval ? '' : `${interval}`;\n\nconst RealTimeUpdatesSettings = (\n { settings: { realTimeUpdates }, toggleRealTimeUpdates, setRealTimeUpdatesInterval }: RealTimeUpdatesProps,\n) => (\n <SimpleCard title=\"Real-time updates\" className=\"h-100\">\n <FormGroup>\n <ToggleSwitch checked={realTimeUpdates.enabled} onChange={toggleRealTimeUpdates}>\n Enable or disable real-time updates.\n <small className=\"form-text text-muted\">\n Real-time updates are currently being <b>{realTimeUpdates.enabled ? 'processed' : 'ignored'}</b>.\n </small>\n </ToggleSwitch>\n </FormGroup>\n <FormGroup className=\"mb-0\">\n <label className={classNames({ 'text-muted': !realTimeUpdates.enabled })}>\n Real-time updates frequency (in minutes):\n </label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"Immediate\"\n disabled={!realTimeUpdates.enabled}\n value={intervalValue(realTimeUpdates.interval)}\n onChange={({ target }) => setRealTimeUpdatesInterval(Number(target.value))}\n />\n {realTimeUpdates.enabled && (\n <small className=\"form-text text-muted\">\n {realTimeUpdates.interval !== undefined && realTimeUpdates.interval > 0 && (\n <span>\n Updates will be reflected in the UI every <b>{realTimeUpdates.interval}</b> minute{realTimeUpdates.interval > 1 && 's'}.\n </span>\n )}\n {!realTimeUpdates.interval && 'Updates will be reflected in the UI as soon as they happen.'}\n </small>\n )}\n </FormGroup>\n </SimpleCard>\n);\n\nexport default RealTimeUpdatesSettings;\n","import { FC, ReactNode } from 'react';\nimport { Row } from 'reactstrap';\nimport { NoMenuLayout } from '../common/NoMenuLayout';\n\nconst SettingsSections: FC<{ items: ReactNode[][] }> = ({ items }) => (\n <>\n {items.map((child, index) => (\n <Row key={index}>\n {child.map((subChild, subIndex) => (\n <div key={subIndex} className={`col-lg-${12 / child.length} mb-3`}>\n {subChild}\n </div>\n ))}\n </Row>\n ))}\n </>\n);\n\nconst Settings = (\n RealTimeUpdates: FC,\n ShortUrlCreation: FC,\n ShortUrlsList: FC,\n UserInterface: FC,\n Visits: FC,\n Tags: FC,\n) => () => (\n <NoMenuLayout>\n <SettingsSections\n items={[\n [ <UserInterface />, <Visits /> ], // eslint-disable-line react/jsx-key\n [ <ShortUrlCreation />, <ShortUrlsList /> ], // eslint-disable-line react/jsx-key\n [ <Tags />, <RealTimeUpdates /> ], // eslint-disable-line react/jsx-key\n ]}\n />\n </NoMenuLayout>\n);\n\nexport default Settings;\n","import { FC, ReactNode } from 'react';\nimport { DropdownItem, FormGroup } from 'reactstrap';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport ToggleSwitch from '../utils/ToggleSwitch';\nimport { DropdownBtn } from '../utils/DropdownBtn';\nimport { Settings, ShortUrlCreationSettings as ShortUrlsSettings, TagFilteringMode } from './reducers/settings';\n\ninterface ShortUrlCreationProps {\n settings: Settings;\n setShortUrlCreationSettings: (settings: ShortUrlsSettings) => void;\n}\n\nconst tagFilteringModeText = (tagFilteringMode: TagFilteringMode | undefined): string =>\n tagFilteringMode === 'includes' ? 'Suggest tags including input' : 'Suggest tags starting with input';\nconst tagFilteringModeHint = (tagFilteringMode: TagFilteringMode | undefined): ReactNode =>\n tagFilteringMode === 'includes'\n ? <>The list of suggested tags will contain those <b>including</b> provided input.</>\n : <>The list of suggested tags will contain those <b>starting with</b> provided input.</>;\n\nexport const ShortUrlCreationSettings: FC<ShortUrlCreationProps> = ({ settings, setShortUrlCreationSettings }) => {\n const shortUrlCreation: ShortUrlsSettings = settings.shortUrlCreation ?? { validateUrls: false };\n const changeTagsFilteringMode = (tagFilteringMode: TagFilteringMode) => () => setShortUrlCreationSettings(\n { ...shortUrlCreation ?? { validateUrls: false }, tagFilteringMode },\n );\n\n return (\n <SimpleCard title=\"Short URLs form\" className=\"h-100\">\n <FormGroup>\n <ToggleSwitch\n checked={shortUrlCreation.validateUrls ?? false}\n onChange={(validateUrls) => setShortUrlCreationSettings({ ...shortUrlCreation, validateUrls })}\n >\n Request validation on long URLs when creating new short URLs.\n <small className=\"form-text text-muted\">\n The initial state of the <b>Validate URL</b> checkbox will\n be <b>{shortUrlCreation.validateUrls ? 'checked' : 'unchecked'}</b>.\n </small>\n </ToggleSwitch>\n </FormGroup>\n <FormGroup>\n <ToggleSwitch\n checked={shortUrlCreation.forwardQuery ?? true}\n onChange={(forwardQuery) => setShortUrlCreationSettings({ ...shortUrlCreation, forwardQuery })}\n >\n Make all new short URLs forward their query params to the long URL.\n <small className=\"form-text text-muted\">\n The initial state of the <b>Forward query params on redirect</b> checkbox will\n be <b>{shortUrlCreation.forwardQuery ?? true ? 'checked' : 'unchecked'}</b>.\n </small>\n </ToggleSwitch>\n </FormGroup>\n <FormGroup className=\"mb-0\">\n <label>Tag suggestions search mode:</label>\n <DropdownBtn text={tagFilteringModeText(shortUrlCreation.tagFilteringMode)}>\n <DropdownItem\n active={!shortUrlCreation.tagFilteringMode || shortUrlCreation.tagFilteringMode === 'startsWith'}\n onClick={changeTagsFilteringMode('startsWith')}\n >\n {tagFilteringModeText('startsWith')}\n </DropdownItem>\n <DropdownItem\n active={shortUrlCreation.tagFilteringMode === 'includes'}\n onClick={changeTagsFilteringMode('includes')}\n >\n {tagFilteringModeText('includes')}\n </DropdownItem>\n </DropdownBtn>\n <small className=\"form-text text-muted\">\n {tagFilteringModeHint(shortUrlCreation.tagFilteringMode)}\n </small>\n </FormGroup>\n </SimpleCard>\n );\n};\n","import { FC } from 'react';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faSun, faMoon } from '@fortawesome/free-solid-svg-icons';\nimport { FormGroup } from 'reactstrap';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport ToggleSwitch from '../utils/ToggleSwitch';\nimport { changeThemeInMarkup, Theme } from '../utils/theme';\nimport { Settings, UiSettings } from './reducers/settings';\nimport './UserInterfaceSettings.scss';\n\ninterface UserInterfaceProps {\n settings: Settings;\n setUiSettings: (settings: UiSettings) => void;\n}\n\nexport const UserInterfaceSettings: FC<UserInterfaceProps> = ({ settings: { ui }, setUiSettings }) => (\n <SimpleCard title=\"User interface\" className=\"h-100\">\n <FormGroup>\n <FontAwesomeIcon icon={ui?.theme === 'dark' ? faMoon : faSun} className=\"user-interface__theme-icon\" />\n <ToggleSwitch\n checked={ui?.theme === 'dark'}\n onChange={(useDarkTheme) => {\n const theme: Theme = useDarkTheme ? 'dark' : 'light';\n\n setUiSettings({ ...ui, theme });\n changeThemeInMarkup(theme);\n }}\n >\n Use dark theme.\n </ToggleSwitch>\n </FormGroup>\n </SimpleCard>\n);\n","import { FC } from 'react';\nimport { DropdownBtn } from '../DropdownBtn';\nimport { rangeOrIntervalToString } from './types';\nimport { DateIntervalDropdownItems, DateIntervalDropdownProps } from './DateIntervalDropdownItems';\n\nexport const DateIntervalSelector: FC<DateIntervalDropdownProps> = ({ onChange, active, allText }) => (\n <DropdownBtn text={rangeOrIntervalToString(active) ?? allText}>\n <DateIntervalDropdownItems allText={allText} active={active} onChange={onChange} />\n </DropdownBtn>\n);\n","import { FormGroup } from 'reactstrap';\nimport { FC } from 'react';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { DateIntervalSelector } from '../utils/dates/DateIntervalSelector';\nimport { Settings, VisitsSettings as VisitsSettingsConfig } from './reducers/settings';\n\ninterface VisitsProps {\n settings: Settings;\n setVisitsSettings: (settings: VisitsSettingsConfig) => void;\n}\n\nexport const VisitsSettings: FC<VisitsProps> = ({ settings, setVisitsSettings }) => (\n <SimpleCard title=\"Visits\" className=\"h-100\">\n <FormGroup className=\"mb-0\">\n <label>Default interval to load on visits sections:</label>\n <DateIntervalSelector\n allText=\"All visits\"\n active={settings.visits?.defaultInterval ?? 'last30Days'}\n onChange={(defaultInterval) => setVisitsSettings({ defaultInterval })}\n />\n </FormGroup>\n </SimpleCard>\n);\n","import { FC } from 'react';\nimport { FormGroup } from 'reactstrap';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { TagsModeDropdown } from '../tags/TagsModeDropdown';\nimport { capitalize } from '../utils/utils';\nimport { OrderingDropdown } from '../utils/OrderingDropdown';\nimport { TAGS_ORDERABLE_FIELDS } from '../tags/data/TagsListChildrenProps';\nimport { Settings, TagsSettings as TagsSettingsOptions } from './reducers/settings';\n\ninterface TagsProps {\n settings: Settings;\n setTagsSettings: (settings: TagsSettingsOptions) => void;\n}\n\nexport const TagsSettings: FC<TagsProps> = ({ settings: { tags }, setTagsSettings }) => (\n <SimpleCard title=\"Tags\" className=\"h-100\">\n <FormGroup>\n <label>Default display mode when managing tags:</label>\n <TagsModeDropdown\n mode={tags?.defaultMode ?? 'cards'}\n renderTitle={(tagsMode) => capitalize(tagsMode)}\n onChange={(defaultMode) => setTagsSettings({ ...tags, defaultMode })}\n />\n <small className=\"form-text text-muted\">Tags will be displayed as <b>{tags?.defaultMode ?? 'cards'}</b>.</small>\n </FormGroup>\n <FormGroup className=\"mb-0\">\n <label>Default ordering for tags list:</label>\n <OrderingDropdown\n items={TAGS_ORDERABLE_FIELDS}\n order={tags?.defaultOrdering ?? {}}\n onChange={(field, dir) => setTagsSettings({ ...tags, defaultOrdering: { field, dir } })}\n />\n </FormGroup>\n </SimpleCard>\n);\n","import { FC } from 'react';\nimport { FormGroup } from 'reactstrap';\nimport { OrderingDropdown } from '../utils/OrderingDropdown';\nimport { SHORT_URLS_ORDERABLE_FIELDS } from '../short-urls/data';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { DEFAULT_SHORT_URLS_ORDERING, Settings, ShortUrlsListSettings as ShortUrlsSettings } from './reducers/settings';\n\ninterface ShortUrlsListProps {\n settings: Settings;\n setShortUrlsListSettings: (settings: ShortUrlsSettings) => void;\n}\n\nexport const ShortUrlsListSettings: FC<ShortUrlsListProps> = (\n { settings: { shortUrlsList }, setShortUrlsListSettings },\n) => (\n <SimpleCard title=\"Short URLs list\" className=\"h-100\">\n <FormGroup className=\"mb-0\">\n <label>Default ordering for short URLs list:</label>\n <OrderingDropdown\n items={SHORT_URLS_ORDERABLE_FIELDS}\n order={shortUrlsList?.defaultOrdering ?? DEFAULT_SHORT_URLS_ORDERING}\n onChange={(field, dir) => setShortUrlsListSettings({ defaultOrdering: { field, dir } })}\n />\n </FormGroup>\n </SimpleCard>\n);\n","import Bottle from 'bottlejs';\nimport RealTimeUpdatesSettings from '../RealTimeUpdatesSettings';\nimport Settings from '../Settings';\nimport {\n setRealTimeUpdatesInterval,\n setShortUrlCreationSettings,\n setShortUrlsListSettings,\n setTagsSettings,\n setUiSettings,\n setVisitsSettings,\n toggleRealTimeUpdates,\n} from '../reducers/settings';\nimport { ConnectDecorator } from '../../container/types';\nimport { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';\nimport { ShortUrlCreationSettings } from '../ShortUrlCreationSettings';\nimport { UserInterfaceSettings } from '../UserInterfaceSettings';\nimport { VisitsSettings } from '../VisitsSettings';\nimport { TagsSettings } from '../TagsSettings';\nimport { ShortUrlsListSettings } from '../ShortUrlsListSettings';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory(\n 'Settings',\n Settings,\n 'RealTimeUpdatesSettings',\n 'ShortUrlCreationSettings',\n 'ShortUrlsListSettings',\n 'UserInterfaceSettings',\n 'VisitsSettings',\n 'TagsSettings',\n );\n bottle.decorator('Settings', withoutSelectedServer);\n bottle.decorator('Settings', connect(null, [ 'resetSelectedServer' ]));\n\n bottle.serviceFactory('RealTimeUpdatesSettings', () => RealTimeUpdatesSettings);\n bottle.decorator(\n 'RealTimeUpdatesSettings',\n connect([ 'settings' ], [ 'toggleRealTimeUpdates', 'setRealTimeUpdatesInterval' ]),\n );\n\n bottle.serviceFactory('ShortUrlCreationSettings', () => ShortUrlCreationSettings);\n bottle.decorator('ShortUrlCreationSettings', connect([ 'settings' ], [ 'setShortUrlCreationSettings' ]));\n\n bottle.serviceFactory('UserInterfaceSettings', () => UserInterfaceSettings);\n bottle.decorator('UserInterfaceSettings', connect([ 'settings' ], [ 'setUiSettings' ]));\n\n bottle.serviceFactory('VisitsSettings', () => VisitsSettings);\n bottle.decorator('VisitsSettings', connect([ 'settings' ], [ 'setVisitsSettings' ]));\n\n bottle.serviceFactory('TagsSettings', () => TagsSettings);\n bottle.decorator('TagsSettings', connect([ 'settings' ], [ 'setTagsSettings' ]));\n\n bottle.serviceFactory('ShortUrlsListSettings', () => ShortUrlsListSettings);\n bottle.decorator('ShortUrlsListSettings', connect([ 'settings' ], [ 'setShortUrlsListSettings' ]));\n\n // Actions\n bottle.serviceFactory('toggleRealTimeUpdates', () => toggleRealTimeUpdates);\n bottle.serviceFactory('setRealTimeUpdatesInterval', () => setRealTimeUpdatesInterval);\n bottle.serviceFactory('setShortUrlCreationSettings', () => setShortUrlCreationSettings);\n bottle.serviceFactory('setShortUrlsListSettings', () => setShortUrlsListSettings);\n bottle.serviceFactory('setUiSettings', () => setUiSettings);\n bottle.serviceFactory('setVisitsSettings', () => setVisitsSettings);\n bottle.serviceFactory('setTagsSettings', () => setTagsSettings);\n};\n\nexport default provideServices;\n","export const replaceAuthorityFromUri = (uri: string, newAuthority: string): string => {\n const [ schema, rest ] = uri.split('://');\n const [ , ...pathParts ] = rest.split('/');\n const normalizedPath = pathParts.length ? `/${pathParts.join('/')}` : '';\n\n return `${schema}://${newAuthority}${normalizedPath}`;\n};\n","import { Action, Dispatch } from 'redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { ShlinkDomainRedirects } from '../../api/types';\nimport { GetState } from '../../container/types';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { parseApiError } from '../../api/utils';\n\n/* eslint-disable padding-line-between-statements */\nexport const EDIT_DOMAIN_REDIRECTS_START = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS_START';\nexport const EDIT_DOMAIN_REDIRECTS_ERROR = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS_ERROR';\nexport const EDIT_DOMAIN_REDIRECTS = 'shlink/domainRedirects/EDIT_DOMAIN_REDIRECTS';\n/* eslint-enable padding-line-between-statements */\n\nexport interface EditDomainRedirectsAction extends Action<string> {\n domain: string;\n redirects: ShlinkDomainRedirects;\n}\n\nexport const editDomainRedirects = (buildShlinkApiClient: ShlinkApiClientBuilder) => (\n domain: string,\n domainRedirects: Partial<ShlinkDomainRedirects>,\n) => async (dispatch: Dispatch, getState: GetState) => {\n dispatch({ type: EDIT_DOMAIN_REDIRECTS_START });\n const { editDomainRedirects } = buildShlinkApiClient(getState);\n\n try {\n const redirects = await editDomainRedirects({ domain, ...domainRedirects });\n\n dispatch<EditDomainRedirectsAction>({ type: EDIT_DOMAIN_REDIRECTS, domain, redirects });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: EDIT_DOMAIN_REDIRECTS_ERROR, errorData: parseApiError(e) });\n }\n};\n","import { Action, Dispatch } from 'redux';\nimport { ProblemDetailsError, ShlinkDomainRedirects } from '../../api/types';\nimport { buildReducer } from '../../utils/helpers/redux';\nimport { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';\nimport { GetState } from '../../container/types';\nimport { parseApiError } from '../../api/utils';\nimport { ApiErrorAction } from '../../api/types/actions';\nimport { Domain, DomainStatus } from '../data';\nimport { hasServerData } from '../../servers/data';\nimport { replaceAuthorityFromUri } from '../../utils/helpers/uri';\nimport { EDIT_DOMAIN_REDIRECTS, EditDomainRedirectsAction } from './domainRedirects';\n\n/* eslint-disable padding-line-between-statements */\nexport const LIST_DOMAINS_START = 'shlink/domainsList/LIST_DOMAINS_START';\nexport const LIST_DOMAINS_ERROR = 'shlink/domainsList/LIST_DOMAINS_ERROR';\nexport const LIST_DOMAINS = 'shlink/domainsList/LIST_DOMAINS';\nexport const FILTER_DOMAINS = 'shlink/domainsList/FILTER_DOMAINS';\nexport const VALIDATE_DOMAIN = 'shlink/domainsList/VALIDATE_DOMAIN';\n/* eslint-enable padding-line-between-statements */\n\nexport interface DomainsList {\n domains: Domain[];\n filteredDomains: Domain[];\n defaultRedirects?: ShlinkDomainRedirects;\n loading: boolean;\n error: boolean;\n errorData?: ProblemDetailsError;\n}\n\nexport interface ListDomainsAction extends Action<string> {\n domains: Domain[];\n defaultRedirects?: ShlinkDomainRedirects;\n}\n\ninterface FilterDomainsAction extends Action<string> {\n searchTerm: string;\n}\n\ninterface ValidateDomain extends Action<string> {\n domain: string;\n status: DomainStatus;\n}\n\nconst initialState: DomainsList = {\n domains: [],\n filteredDomains: [],\n loading: false,\n error: false,\n};\n\nexport type DomainsCombinedAction = ListDomainsAction\n& ApiErrorAction\n& FilterDomainsAction\n& EditDomainRedirectsAction\n& ValidateDomain;\n\nexport const replaceRedirectsOnDomain = (domain: string, redirects: ShlinkDomainRedirects) =>\n (d: Domain): Domain => d.domain !== domain ? d : { ...d, redirects };\n\nexport const replaceStatusOnDomain = (domain: string, status: DomainStatus) =>\n (d: Domain): Domain => d.domain !== domain ? d : { ...d, status };\n\nexport default buildReducer<DomainsList, DomainsCombinedAction>({\n [LIST_DOMAINS_START]: () => ({ ...initialState, loading: true }),\n [LIST_DOMAINS_ERROR]: ({ errorData }) => ({ ...initialState, error: true, errorData }),\n [LIST_DOMAINS]: (_, { domains, defaultRedirects }) =>\n ({ ...initialState, domains, filteredDomains: domains, defaultRedirects }),\n [FILTER_DOMAINS]: (state, { searchTerm }) => ({\n ...state,\n filteredDomains: state.domains.filter(({ domain }) => domain.toLowerCase().match(searchTerm)),\n }),\n [EDIT_DOMAIN_REDIRECTS]: (state, { domain, redirects }) => ({\n ...state,\n domains: state.domains.map(replaceRedirectsOnDomain(domain, redirects)),\n filteredDomains: state.filteredDomains.map(replaceRedirectsOnDomain(domain, redirects)),\n }),\n [VALIDATE_DOMAIN]: (state, { domain, status }) => ({\n ...state,\n domains: state.domains.map(replaceStatusOnDomain(domain, status)),\n filteredDomains: state.filteredDomains.map(replaceStatusOnDomain(domain, status)),\n }),\n}, initialState);\n\nexport const listDomains = (buildShlinkApiClient: ShlinkApiClientBuilder) => () => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n dispatch({ type: LIST_DOMAINS_START });\n const { listDomains } = buildShlinkApiClient(getState);\n\n try {\n const { domains, defaultRedirects } = await listDomains().then(({ data, defaultRedirects }) => ({\n domains: data.map((domain): Domain => ({ ...domain, status: 'validating' })),\n defaultRedirects,\n }));\n\n dispatch<ListDomainsAction>({ type: LIST_DOMAINS, domains, defaultRedirects });\n } catch (e: any) {\n dispatch<ApiErrorAction>({ type: LIST_DOMAINS_ERROR, errorData: parseApiError(e) });\n }\n};\n\nexport const filterDomains = (searchTerm: string): FilterDomainsAction => ({ type: FILTER_DOMAINS, searchTerm });\n\nexport const checkDomainHealth = (buildShlinkApiClient: ShlinkApiClientBuilder) => (domain: string) => async (\n dispatch: Dispatch,\n getState: GetState,\n) => {\n const { selectedServer } = getState();\n\n if (!hasServerData(selectedServer)) {\n dispatch<ValidateDomain>({ type: VALIDATE_DOMAIN, domain, status: 'invalid' });\n\n return;\n }\n\n try {\n const { url, ...rest } = selectedServer;\n const { health } = buildShlinkApiClient({\n ...rest,\n url: replaceAuthorityFromUri(url, domain),\n });\n\n const { status } = await health();\n\n dispatch<ValidateDomain>({ type: VALIDATE_DOMAIN, domain, status: status === 'pass' ? 'valid' : 'invalid' });\n } catch (e) {\n dispatch<ValidateDomain>({ type: VALIDATE_DOMAIN, domain, status: 'invalid' });\n }\n};\n","import { useEffect } from 'react';\nimport { Button, DropdownItem, Input, InputGroup, InputGroupAddon, UncontrolledTooltip } from 'reactstrap';\nimport { InputProps } from 'reactstrap/lib/Input';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faUndo } from '@fortawesome/free-solid-svg-icons';\nimport { isEmpty, pipe } from 'ramda';\nimport { DropdownBtn } from '../utils/DropdownBtn';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { DomainsList } from './reducers/domainsList';\nimport './DomainSelector.scss';\n\nexport interface DomainSelectorProps extends Omit<InputProps, 'onChange'> {\n value?: string;\n onChange: (domain: string) => void;\n}\n\ninterface DomainSelectorConnectProps extends DomainSelectorProps {\n listDomains: Function;\n domainsList: DomainsList;\n}\n\nexport const DomainSelector = ({ listDomains, value, domainsList, onChange }: DomainSelectorConnectProps) => {\n const [ inputDisplayed,, showInput, hideInput ] = useToggle();\n const { domains } = domainsList;\n const valueIsEmpty = isEmpty(value);\n const unselectDomain = () => onChange('');\n\n useEffect(() => {\n listDomains();\n }, []);\n\n return inputDisplayed ? (\n <InputGroup>\n <Input\n value={value}\n placeholder=\"Domain\"\n onChange={(e) => onChange(e.target.value)}\n />\n <InputGroupAddon addonType=\"append\">\n <Button\n id=\"backToDropdown\"\n outline\n type=\"button\"\n className=\"domains-dropdown__back-btn\"\n onClick={pipe(unselectDomain, hideInput)}\n >\n <FontAwesomeIcon icon={faUndo} />\n </Button>\n <UncontrolledTooltip target=\"backToDropdown\" placement=\"left\" trigger=\"hover\">\n Existing domains\n </UncontrolledTooltip>\n </InputGroupAddon>\n </InputGroup>\n ) : (\n <DropdownBtn\n text={valueIsEmpty ? 'Domain' : `Domain: ${value}`}\n className={!valueIsEmpty ? 'domains-dropdown__toggle-btn--active' : 'domains-dropdown__toggle-btn'}\n >\n {domains.map(({ domain, isDefault }) => (\n <DropdownItem\n key={domain}\n active={value === domain || isDefault && valueIsEmpty}\n onClick={() => onChange(domain)}\n >\n {domain}\n {isDefault && <span className=\"float-right text-muted\">default</span>}\n </DropdownItem>\n ))}\n <DropdownItem divider />\n <DropdownItem onClick={pipe(unselectDomain, showInput)}>\n <i>New domain</i>\n </DropdownItem>\n </DropdownBtn>\n );\n};\n","import { FC, useState } from 'react';\nimport { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';\nimport { ShlinkDomain, ShlinkDomainRedirects } from '../../api/types';\nimport { FormGroupContainer, FormGroupContainerProps } from '../../utils/FormGroupContainer';\nimport { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/utils';\nimport { InfoTooltip } from '../../utils/InfoTooltip';\n\ninterface EditDomainRedirectsModalProps {\n domain: ShlinkDomain;\n isOpen: boolean;\n toggle: () => void;\n editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;\n}\n\nconst FormGroup: FC<FormGroupContainerProps & { isLast?: boolean }> = ({ isLast, ...rest }) => (\n <FormGroupContainer\n {...rest}\n required={false}\n type=\"url\"\n placeholder=\"No redirect\"\n className={isLast ? 'mb-0' : ''}\n />\n);\n\nexport const EditDomainRedirectsModal: FC<EditDomainRedirectsModalProps> = (\n { isOpen, toggle, domain, editDomainRedirects },\n) => {\n const [ baseUrlRedirect, setBaseUrlRedirect ] = useState(domain.redirects?.baseUrlRedirect ?? '');\n const [ regular404Redirect, setRegular404Redirect ] = useState(domain.redirects?.regular404Redirect ?? '');\n const [ invalidShortUrlRedirect, setInvalidShortUrlRedirect ] = useState(\n domain.redirects?.invalidShortUrlRedirect ?? '',\n );\n const handleSubmit = handleEventPreventingDefault(async () => editDomainRedirects(domain.domain, {\n baseUrlRedirect: nonEmptyValueOrNull(baseUrlRedirect),\n regular404Redirect: nonEmptyValueOrNull(regular404Redirect),\n invalidShortUrlRedirect: nonEmptyValueOrNull(invalidShortUrlRedirect),\n }).then(toggle));\n\n return (\n <Modal isOpen={isOpen} toggle={toggle} centered>\n <form onSubmit={handleSubmit}>\n <ModalHeader toggle={toggle}>Edit redirects for <b>{domain.domain}</b></ModalHeader>\n <ModalBody>\n <FormGroup value={baseUrlRedirect} onChange={setBaseUrlRedirect}>\n <InfoTooltip className=\"mr-2\" placement=\"bottom\">\n Visitors accessing the base url, as in <b>https://{domain.domain}/</b>, will be redirected to this URL.\n </InfoTooltip>\n Base URL\n </FormGroup>\n <FormGroup value={regular404Redirect} onChange={setRegular404Redirect}>\n <InfoTooltip className=\"mr-2\" placement=\"bottom\">\n Visitors accessing a url not matching a short URL pattern, as in <b>https://{domain.domain}/???/[...]</b>,\n will be redirected to this URL.\n </InfoTooltip>\n Regular 404\n </FormGroup>\n <FormGroup value={invalidShortUrlRedirect} isLast onChange={setInvalidShortUrlRedirect}>\n <InfoTooltip className=\"mr-2\" placement=\"bottom\">\n Visitors accessing a url matching a short URL pattern, but not matching an existing short code, will be\n redirected to this URL.\n </InfoTooltip>\n Invalid short URL\n </FormGroup>\n </ModalBody>\n <ModalFooter>\n <Button color=\"link\" type=\"button\" onClick={toggle}>Cancel</Button>\n <Button color=\"primary\">Save</Button>\n </ModalFooter>\n </form>\n </Modal>\n );\n};\n","import { FC, useEffect, useRef, useState } from 'react';\nimport { UncontrolledTooltip } from 'reactstrap';\nimport { ExternalLink } from 'react-external-link';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faTimes as invalidIcon,\n faCheck as checkIcon,\n faCircleNotch as loadingStatusIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { MediaMatcher } from '../../utils/types';\nimport { DomainStatus } from '../data';\n\ninterface DomainStatusIconProps {\n status: DomainStatus;\n matchMedia?: MediaMatcher;\n}\n\nexport const DomainStatusIcon: FC<DomainStatusIconProps> = ({ status, matchMedia = window.matchMedia }) => {\n const ref = useRef<HTMLSpanElement>();\n const matchesMobile = () => matchMedia('(max-width: 991px)').matches;\n const [ isMobile, setIsMobile ] = useState<boolean>(matchesMobile());\n\n useEffect(() => {\n const listener = () => setIsMobile(matchesMobile());\n\n window.addEventListener('resize', listener);\n\n return () => window.removeEventListener('resize', listener);\n }, []);\n\n if (status === 'validating') {\n return <FontAwesomeIcon fixedWidth icon={loadingStatusIcon} spin />;\n }\n\n return (\n <>\n <span\n ref={(el: HTMLSpanElement) => {\n ref.current = el;\n }}\n >\n {status === 'valid'\n ? <FontAwesomeIcon fixedWidth icon={checkIcon} className=\"text-muted\" />\n : <FontAwesomeIcon fixedWidth icon={invalidIcon} className=\"text-danger\" />}\n </span>\n <UncontrolledTooltip\n target={(() => ref.current) as any}\n placement={isMobile ? 'top-start' : 'left'}\n autohide={status === 'valid'}\n >\n {status === 'valid' ? 'Congratulations! This domain is properly configured.' : (\n <span>\n Oops! There is some missing configuration, and short URLs shared with this domain will not work.\n <br />\n Check the <ExternalLink href=\"https://slnk.to/multi-domain-docs\">documentation</ExternalLink> in order to\n find out what is missing.\n </span>\n )}\n </UncontrolledTooltip>\n </>\n );\n};\n","import { FC, useEffect } from 'react';\nimport { Button, UncontrolledTooltip } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faBan as forbiddenIcon,\n faDotCircle as defaultDomainIcon,\n faEdit as editIcon,\n} from '@fortawesome/free-solid-svg-icons';\nimport { ShlinkDomainRedirects } from '../api/types';\nimport { useToggle } from '../utils/helpers/hooks';\nimport { OptionalString } from '../utils/utils';\nimport { SelectedServer } from '../servers/data';\nimport { supportsDefaultDomainRedirectsEdition } from '../utils/helpers/features';\nimport { EditDomainRedirectsModal } from './helpers/EditDomainRedirectsModal';\nimport { Domain } from './data';\nimport { DomainStatusIcon } from './helpers/DomainStatusIcon';\n\ninterface DomainRowProps {\n domain: Domain;\n defaultRedirects?: ShlinkDomainRedirects;\n editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;\n checkDomainHealth: (domain: string) => void;\n selectedServer: SelectedServer;\n}\n\nconst Nr: FC<{ fallback: OptionalString }> = ({ fallback }) => (\n <span className=\"text-muted\">\n {!fallback && <small>No redirect</small>}\n {fallback && <>{fallback} <small>(as fallback)</small></>}\n </span>\n);\nconst DefaultDomain: FC = () => (\n <>\n <FontAwesomeIcon fixedWidth icon={defaultDomainIcon} className=\"text-primary\" id=\"defaultDomainIcon\" />\n <UncontrolledTooltip target=\"defaultDomainIcon\" placement=\"right\">Default domain</UncontrolledTooltip>\n </>\n);\n\nexport const DomainRow: FC<DomainRowProps> = (\n { domain, editDomainRedirects, checkDomainHealth, defaultRedirects, selectedServer },\n) => {\n const [ isOpen, toggle ] = useToggle();\n const { domain: authority, isDefault, redirects, status } = domain;\n const canEditDomain = !isDefault || supportsDefaultDomainRedirectsEdition(selectedServer);\n\n useEffect(() => {\n checkDomainHealth(domain.domain);\n }, []);\n\n return (\n <tr className=\"responsive-table__row\">\n <td className=\"responsive-table__cell\" data-th=\"Is default domain\">{isDefault && <DefaultDomain />}</td>\n <th className=\"responsive-table__cell\" data-th=\"Domain\">{authority}</th>\n <td className=\"responsive-table__cell\" data-th=\"Base path redirect\">\n {redirects?.baseUrlRedirect ?? <Nr fallback={defaultRedirects?.baseUrlRedirect} />}\n </td>\n <td className=\"responsive-table__cell\" data-th=\"Regular 404 redirect\">\n {redirects?.regular404Redirect ?? <Nr fallback={defaultRedirects?.regular404Redirect} />}\n </td>\n <td className=\"responsive-table__cell\" data-th=\"Invalid short URL redirect\">\n {redirects?.invalidShortUrlRedirect ?? <Nr fallback={defaultRedirects?.invalidShortUrlRedirect} />}\n </td>\n <td className=\"responsive-table__cell text-lg-center\" data-th=\"Status\">\n <DomainStatusIcon status={status} />\n </td>\n <td className=\"responsive-table__cell text-right\">\n <span id={!canEditDomain ? 'defaultDomainBtn' : undefined}>\n <Button outline size=\"sm\" disabled={!canEditDomain} onClick={!canEditDomain ? undefined : toggle}>\n <FontAwesomeIcon fixedWidth icon={!canEditDomain ? forbiddenIcon : editIcon} />\n </Button>\n </span>\n {!canEditDomain && (\n <UncontrolledTooltip target=\"defaultDomainBtn\" placement=\"left\">\n Redirects for default domain cannot be edited here.\n <br />\n Use config options or env vars directly on the server.\n </UncontrolledTooltip>\n )}\n </td>\n <EditDomainRedirectsModal\n domain={domain}\n isOpen={isOpen}\n toggle={toggle}\n editDomainRedirects={editDomainRedirects}\n />\n </tr>\n );\n};\n","import { FC, useEffect } from 'react';\nimport Message from '../utils/Message';\nimport { Result } from '../utils/Result';\nimport { ShlinkApiError } from '../api/ShlinkApiError';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport SearchField from '../utils/SearchField';\nimport { ShlinkDomainRedirects } from '../api/types';\nimport { SelectedServer } from '../servers/data';\nimport { DomainsList } from './reducers/domainsList';\nimport { DomainRow } from './DomainRow';\n\ninterface ManageDomainsProps {\n listDomains: Function;\n filterDomains: (searchTerm: string) => void;\n editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;\n checkDomainHealth: (domain: string) => void;\n domainsList: DomainsList;\n selectedServer: SelectedServer;\n}\n\nconst headers = [ '', 'Domain', 'Base path redirect', 'Regular 404 redirect', 'Invalid short URL redirect', '', '' ];\n\nexport const ManageDomains: FC<ManageDomainsProps> = (\n { listDomains, domainsList, filterDomains, editDomainRedirects, checkDomainHealth, selectedServer },\n) => {\n const { filteredDomains: domains, defaultRedirects, loading, error, errorData } = domainsList;\n const resolvedDefaultRedirects = defaultRedirects ?? domains.find(({ isDefault }) => isDefault)?.redirects;\n\n useEffect(() => {\n listDomains();\n }, []);\n\n if (loading) {\n return <Message loading />;\n }\n\n const renderContent = () => {\n if (error) {\n return (\n <Result type=\"error\">\n <ShlinkApiError errorData={errorData} fallbackMessage=\"Error loading domains :(\" />\n </Result>\n );\n }\n\n return (\n <SimpleCard>\n <table className=\"table table-hover mb-0\">\n <thead className=\"responsive-table__header\">\n <tr>{headers.map((column, index) => <th key={index}>{column}</th>)}</tr>\n </thead>\n <tbody>\n {domains.length < 1 && <tr><td colSpan={headers.length} className=\"text-center\">No results found</td></tr>}\n {domains.map((domain) => (\n <DomainRow\n key={domain.domain}\n domain={domain}\n editDomainRedirects={editDomainRedirects}\n checkDomainHealth={checkDomainHealth}\n defaultRedirects={resolvedDefaultRedirects}\n selectedServer={selectedServer}\n />\n ))}\n </tbody>\n </table>\n </SimpleCard>\n );\n };\n\n return (\n <>\n <SearchField className=\"mb-3\" onChange={filterDomains} />\n {renderContent()}\n </>\n );\n};\n","import Bottle from 'bottlejs';\nimport { ConnectDecorator } from '../../container/types';\nimport { checkDomainHealth, filterDomains, listDomains } from '../reducers/domainsList';\nimport { DomainSelector } from '../DomainSelector';\nimport { ManageDomains } from '../ManageDomains';\nimport { editDomainRedirects } from '../reducers/domainRedirects';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory('DomainSelector', () => DomainSelector);\n bottle.decorator('DomainSelector', connect([ 'domainsList' ], [ 'listDomains' ]));\n\n bottle.serviceFactory('ManageDomains', () => ManageDomains);\n bottle.decorator('ManageDomains', connect(\n [ 'domainsList', 'selectedServer' ],\n [ 'listDomains', 'filterDomains', 'editDomainRedirects', 'checkDomainHealth' ],\n ));\n\n // Actions\n bottle.serviceFactory('listDomains', listDomains, 'buildShlinkApiClient');\n bottle.serviceFactory('filterDomains', () => filterDomains);\n bottle.serviceFactory('editDomainRedirects', editDomainRedirects, 'buildShlinkApiClient');\n bottle.serviceFactory('checkDomainHealth', checkDomainHealth, 'buildShlinkApiClient');\n};\n\nexport default provideServices;\n","import { Action } from 'redux';\nimport { buildActionCreator, buildReducer } from '../../utils/helpers/redux';\n\n/* eslint-disable padding-line-between-statements */\nexport const APP_UPDATE_AVAILABLE = 'shlink/appUpdates/APP_UPDATE_AVAILABLE';\nexport const RESET_APP_UPDATE = 'shlink/appUpdates/RESET_APP_UPDATE';\n/* eslint-enable padding-line-between-statements */\n\nconst initialState = false;\n\nexport default buildReducer<boolean, Action<string>>({\n [APP_UPDATE_AVAILABLE]: () => true,\n [RESET_APP_UPDATE]: () => false,\n}, initialState);\n\nexport const appUpdateAvailable = buildActionCreator(APP_UPDATE_AVAILABLE);\n\nexport const resetAppUpdate = buildActionCreator(RESET_APP_UPDATE);\n","import { FC, MouseEventHandler } from 'react';\nimport { Alert, Button } from 'reactstrap';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faSyncAlt as reloadIcon } from '@fortawesome/free-solid-svg-icons';\nimport { SimpleCard } from '../utils/SimpleCard';\nimport { useToggle } from '../utils/helpers/hooks';\nimport './AppUpdateBanner.scss';\n\ninterface AppUpdateBannerProps {\n isOpen: boolean;\n toggle: MouseEventHandler<any>;\n forceUpdate: Function;\n}\n\nexport const AppUpdateBanner: FC<AppUpdateBannerProps> = ({ isOpen, toggle, forceUpdate }) => {\n const [ isUpdating,, setUpdating ] = useToggle();\n const update = () => {\n setUpdating();\n forceUpdate();\n };\n\n return (\n <Alert className=\"app-update-banner\" isOpen={isOpen} toggle={toggle} tag={SimpleCard} color=\"secondary\">\n <h4 className=\"mb-4\">This app has just been updated!</h4>\n <p className=\"mb-0\">\n Restart it to enjoy the new features.\n <Button disabled={isUpdating} className=\"ml-2\" color=\"secondary\" size=\"sm\" onClick={update}>\n {!isUpdating && <>Restart now <FontAwesomeIcon icon={reloadIcon} className=\"ml-1\" /></>}\n {isUpdating && <>Restarting...</>}\n </Button>\n </p>\n </Alert>\n );\n};\n","export const forceUpdate = async () => {\n const registrations = await navigator.serviceWorker?.getRegistrations() ?? [];\n\n for (const registration of registrations) {\n const { waiting } = registration;\n\n waiting?.addEventListener('statechange', (event) => {\n if ((event.target as any)?.state === 'activated') {\n window.location.reload();\n }\n });\n\n // The logic that makes skipWaiting to be called when this message is posted is in service-worker.ts\n waiting?.postMessage({ type: 'SKIP_WAITING' });\n }\n};\n","import { useEffect, FC } from 'react';\nimport { Route, Routes, useLocation } from 'react-router-dom';\nimport classNames from 'classnames';\nimport NotFound from '../common/NotFound';\nimport { ServersMap } from '../servers/data';\nimport { Settings } from '../settings/reducers/settings';\nimport { changeThemeInMarkup } from '../utils/theme';\nimport { AppUpdateBanner } from '../common/AppUpdateBanner';\nimport { forceUpdate } from '../utils/helpers/sw';\nimport './App.scss';\n\ninterface AppProps {\n fetchServers: () => void;\n servers: ServersMap;\n settings: Settings;\n resetAppUpdate: () => void;\n appUpdated: boolean;\n}\n\nconst App = (\n MainHeader: FC,\n Home: FC,\n MenuLayout: FC,\n CreateServer: FC,\n EditServer: FC,\n Settings: FC,\n ManageServers: FC,\n ShlinkVersionsContainer: FC,\n) => ({ fetchServers, servers, settings, appUpdated, resetAppUpdate }: AppProps) => {\n const location = useLocation();\n const isHome = location.pathname === '/';\n\n useEffect(() => {\n // On first load, try to fetch the remote servers if the list is empty\n if (Object.keys(servers).length === 0) {\n fetchServers();\n }\n\n changeThemeInMarkup(settings.ui?.theme ?? 'light');\n }, []);\n\n return (\n <div className=\"container-fluid app-container\">\n <MainHeader />\n\n <div className=\"app\">\n <div className={classNames('shlink-wrapper', { 'd-flex d-md-block align-items-center': isHome })}>\n <Routes>\n <Route index element={<Home />} />\n <Route path=\"/settings\" element={<Settings />} />\n <Route path=\"/manage-servers\" element={<ManageServers />} />\n <Route path=\"/server/create\" element={<CreateServer />} />\n <Route path=\"/server/:serverId/edit\" element={<EditServer />} />\n <Route path=\"/server/:serverId/*\" element={<MenuLayout />} />\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </div>\n\n <div className=\"shlink-footer\">\n <ShlinkVersionsContainer />\n </div>\n </div>\n\n <AppUpdateBanner isOpen={appUpdated} toggle={resetAppUpdate} forceUpdate={forceUpdate} />\n </div>\n );\n};\n\nexport default App;\n","import Bottle from 'bottlejs';\nimport { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates';\nimport App from '../App';\nimport { ConnectDecorator } from '../../container/types';\n\nconst provideServices = (bottle: Bottle, connect: ConnectDecorator) => {\n // Components\n bottle.serviceFactory(\n 'App',\n App,\n 'MainHeader',\n 'Home',\n 'MenuLayout',\n 'CreateServer',\n 'EditServer',\n 'Settings',\n 'ManageServers',\n 'ShlinkVersionsContainer',\n );\n bottle.decorator('App', connect([ 'servers', 'settings', 'appUpdated' ], [ 'fetchServers', 'resetAppUpdate' ]));\n\n // Actions\n bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);\n bottle.serviceFactory('resetAppUpdate', () => resetAppUpdate);\n};\n\nexport default provideServices;\n","import Bottle, { IContainer } from 'bottlejs';\nimport { connect as reduxConnect } from 'react-redux';\nimport { pick } from 'ramda';\nimport provideApiServices from '../api/services/provideServices';\nimport provideCommonServices from '../common/services/provideServices';\nimport provideShortUrlsServices from '../short-urls/services/provideServices';\nimport provideServersServices from '../servers/services/provideServices';\nimport provideVisitsServices from '../visits/services/provideServices';\nimport provideTagsServices from '../tags/services/provideServices';\nimport provideUtilsServices from '../utils/services/provideServices';\nimport provideMercureServices from '../mercure/services/provideServices';\nimport provideSettingsServices from '../settings/services/provideServices';\nimport provideDomainsServices from '../domains/services/provideServices';\nimport provideAppServices from '../app/services/provideServices';\nimport { ConnectDecorator } from './types';\n\ntype LazyActionMap = Record<string, Function>;\n\nconst bottle = new Bottle();\n\nexport const { container } = bottle;\n\nconst lazyService = <T extends Function, K>(container: IContainer, serviceName: string) =>\n (...args: any[]) => (container[serviceName] as T)(...args) as K;\nconst mapActionService = (map: LazyActionMap, actionName: string): LazyActionMap => ({\n ...map,\n // Wrap actual action service in a function so that it is lazily created the first time it is called\n [actionName]: lazyService(container, actionName),\n});\nconst connect: ConnectDecorator = (propsFromState: string[] | null, actionServiceNames: string[] = []) =>\n reduxConnect(\n propsFromState ? pick(propsFromState) : null,\n actionServiceNames.reduce(mapActionService, {}),\n );\n\nprovideAppServices(bottle, connect);\nprovideCommonServices(bottle, connect);\nprovideApiServices(bottle);\nprovideShortUrlsServices(bottle, connect);\nprovideServersServices(bottle, connect);\nprovideTagsServices(bottle, connect);\nprovideVisitsServices(bottle, connect);\nprovideUtilsServices(bottle);\nprovideMercureServices(bottle);\nprovideSettingsServices(bottle, connect);\nprovideDomainsServices(bottle, connect);\n","import { combineReducers } from 'redux';\nimport serversReducer from '../servers/reducers/servers';\nimport selectedServerReducer from '../servers/reducers/selectedServer';\nimport shortUrlsListReducer from '../short-urls/reducers/shortUrlsList';\nimport shortUrlCreationReducer from '../short-urls/reducers/shortUrlCreation';\nimport shortUrlDeletionReducer from '../short-urls/reducers/shortUrlDeletion';\nimport shortUrlEditionReducer from '../short-urls/reducers/shortUrlEdition';\nimport shortUrlVisitsReducer from '../visits/reducers/shortUrlVisits';\nimport tagVisitsReducer from '../visits/reducers/tagVisits';\nimport orphanVisitsReducer from '../visits/reducers/orphanVisits';\nimport nonOrphanVisitsReducer from '../visits/reducers/nonOrphanVisits';\nimport shortUrlDetailReducer from '../short-urls/reducers/shortUrlDetail';\nimport tagsListReducer from '../tags/reducers/tagsList';\nimport tagDeleteReducer from '../tags/reducers/tagDelete';\nimport tagEditReducer from '../tags/reducers/tagEdit';\nimport mercureInfoReducer from '../mercure/reducers/mercureInfo';\nimport settingsReducer from '../settings/reducers/settings';\nimport domainsListReducer from '../domains/reducers/domainsList';\nimport visitsOverviewReducer from '../visits/reducers/visitsOverview';\nimport appUpdatesReducer from '../app/reducers/appUpdates';\nimport { ShlinkState } from '../container/types';\n\nexport default combineReducers<ShlinkState>({\n servers: serversReducer,\n selectedServer: selectedServerReducer,\n shortUrlsList: shortUrlsListReducer,\n shortUrlCreationResult: shortUrlCreationReducer,\n shortUrlDeletion: shortUrlDeletionReducer,\n shortUrlEdition: shortUrlEditionReducer,\n shortUrlVisits: shortUrlVisitsReducer,\n tagVisits: tagVisitsReducer,\n orphanVisits: orphanVisitsReducer,\n nonOrphanVisits: nonOrphanVisitsReducer,\n shortUrlDetail: shortUrlDetailReducer,\n tagsList: tagsListReducer,\n tagDelete: tagDeleteReducer,\n tagEdit: tagEditReducer,\n mercureInfo: mercureInfoReducer,\n settings: settingsReducer,\n domainsList: domainsListReducer,\n visitsOverview: visitsOverviewReducer,\n appUpdated: appUpdatesReducer,\n});\n","import ReduxThunk from 'redux-thunk';\nimport { applyMiddleware, compose, createStore } from 'redux';\nimport { save, load, RLSOptions } from 'redux-localstorage-simple';\nimport reducers from '../reducers';\nimport { migrateDeprecatedSettings } from '../settings/helpers';\nimport { ShlinkState } from './types';\n\nconst isProduction = process.env.NODE_ENV !== 'production';\nconst composeEnhancers: Function = !isProduction && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\n\nconst localStorageConfig: RLSOptions = {\n states: [ 'settings', 'servers' ],\n namespace: 'shlink',\n namespaceSeparator: '.',\n debounce: 300,\n};\nconst preloadedState = migrateDeprecatedSettings(load(localStorageConfig) as ShlinkState);\n\nexport const store = createStore(reducers, preloadedState, composeEnhancers(\n applyMiddleware(save(localStorageConfig), ReduxThunk),\n));\n","import { ShlinkState } from '../../container/types';\n\nexport const migrateDeprecatedSettings = (state: Partial<ShlinkState>): Partial<ShlinkState> => {\n if (!state.settings) {\n return state;\n }\n\n // The \"last180Days\" interval had a typo, with a lowercase d\n if ((state.settings.visits?.defaultInterval as any) === 'last180days') {\n state.settings.visits && (state.settings.visits.defaultInterval = 'last180Days');\n }\n\n // The \"tags display mode\" option has been moved from \"ui\" to \"tags\"\n state.settings.tags = {\n ...state.settings.tags,\n defaultMode: state.settings.tags?.defaultMode ?? (state.settings.ui as any)?.tagsMode,\n };\n state.settings.ui && delete (state.settings.ui as any).tagsMode;\n\n return state;\n};\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://cra.link/PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.0/8 are considered localhost for IPv4.\n window.location.hostname.match(/^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)\n);\n\ntype Config = {\n onSuccess?: (registration: ServiceWorkerRegistration) => void;\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\n};\n\nexport function register(config?: Config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL ?? '', window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://cra.link/PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl: string, config?: Config) {\n navigator.serviceWorker\n .register(swUrl)\n .then((registration) => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See https://cra.link/PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch((error) => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl: string, config?: Config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl, {\n headers: { 'Service-Worker': 'script' },\n })\n .then((response) => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then((registration) => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log('No internet connection found. App is running in offline mode.');\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready\n .then((registration) => {\n registration.unregister();\n })\n .catch((error) => {\n console.error(error.message);\n });\n }\n}\n","import L from 'leaflet';\nimport marker2x from 'leaflet/dist/images/marker-icon-2x.png';\nimport marker from 'leaflet/dist/images/marker-icon.png';\nimport markerShadow from 'leaflet/dist/images/marker-shadow.png';\n\nexport const fixLeafletIcons = () => {\n delete (L.Icon.Default.prototype as any)._getIconUrl;\n\n L.Icon.Default.mergeOptions({\n iconRetinaUrl: marker2x,\n iconUrl: marker,\n shadowUrl: markerShadow,\n });\n};\n","import { render } from 'react-dom';\nimport { Provider } from 'react-redux';\nimport { BrowserRouter } from 'react-router-dom';\nimport { homepage } from '../package.json';\nimport { container } from './container';\nimport { store } from './container/store';\nimport { fixLeafletIcons } from './utils/helpers/leaflet';\nimport { register as registerServiceWorker } from './serviceWorkerRegistration';\nimport 'react-datepicker/dist/react-datepicker.css';\nimport 'leaflet/dist/leaflet.css';\nimport './index.scss';\n\n// This overwrites icons used for leaflet maps, fixing some issues caused by webpack while processing the CSS\nfixLeafletIcons();\n\nconst { App, ScrollToTop, ErrorHandler, appUpdateAvailable } = container;\n\nrender(\n <Provider store={store}>\n <BrowserRouter basename={homepage}>\n <ErrorHandler>\n <ScrollToTop>\n <App />\n </ScrollToTop>\n </ErrorHandler>\n </BrowserRouter>\n </Provider>,\n document.getElementById('root'),\n);\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://cra.link/PWA\nregisterServiceWorker({\n onUpdate() {\n store.dispatch(appUpdateAvailable()); // eslint-disable-line @typescript-eslint/no-unsafe-call\n },\n});\n","import { FC } from 'react';\nimport './NoMenuLayout.scss';\n\nexport const NoMenuLayout: FC = ({ children }) => <div className=\"no-menu-wrapper container-xl\">{children}</div>;\n","import { compare } from 'compare-versions';\nimport { identity, memoizeWith } from 'ramda';\nimport { Empty, hasValue } from '../utils';\n\ntype SemVerPatternFragment = `${bigint | '*'}`;\n\nexport type SemVerPattern = SemVerPatternFragment\n| `${SemVerPatternFragment}.${SemVerPatternFragment}`\n| `${SemVerPatternFragment}.${SemVerPatternFragment}.${SemVerPatternFragment}`;\n\nexport interface Versions {\n maxVersion?: SemVerPattern;\n minVersion?: SemVerPattern;\n}\n\nexport type SemVer = `${bigint}.${bigint}.${bigint}` | 'latest';\n\nexport const versionMatch = (versionToMatch: SemVer | Empty, { maxVersion, minVersion }: Versions): boolean => {\n if (!hasValue(versionToMatch)) {\n return false;\n }\n\n const matchesMinVersion = !minVersion || compare(versionToMatch, minVersion, '>=');\n const matchesMaxVersion = !maxVersion || compare(versionToMatch, maxVersion, '<=');\n\n return matchesMaxVersion && matchesMinVersion;\n};\n\nconst versionIsValidSemVer = memoizeWith(identity, (version: string): version is SemVer => {\n try {\n return compare(version, version, '=');\n } catch (e) {\n return false;\n }\n});\n\nexport const versionToPrintable = (version: string) => !versionIsValidSemVer(version) ? version : `v${version}`;\n\nexport const versionToSemVer = (defaultValue: SemVer = 'latest') =>\n (version: string): SemVer => versionIsValidSemVer(version) ? version : defaultValue;\n","import { FC, useEffect } from 'react';\n\ninterface WithoutSelectedServerProps {\n resetSelectedServer: Function;\n}\n\nexport function withoutSelectedServer<T = {}>(WrappedComponent: FC<WithoutSelectedServerProps & T>) {\n return (props: WithoutSelectedServerProps & T) => {\n useEffect(() => {\n props.resetSelectedServer();\n }, []);\n\n return <WrappedComponent {...props} />;\n };\n}\n","export const saveUrl = ({ document }: Window, url: string, filename: string) => {\n const link = document.createElement('a');\n\n link.setAttribute('href', url);\n link.setAttribute('download', filename);\n link.style.visibility = 'hidden';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n};\n\nexport const saveCsv = (window: Window, csv: string, filename: string) => {\n const blob = new Blob([ csv ], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n\n saveUrl(window, url, filename);\n};\n"],"sourceRoot":""} |