UNPKG

biketag

Version:

The Javascript client API for BikeTag Games

1,115 lines 173 kB
(function(global, factory) { typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("form-data"), require("imgur"), require("@sanity/client"), require("axios"), require("events"), require("axios-cache-adapter"), require("lodash"), require("tinycache")) : typeof define === "function" && define.amd ? define(["exports", "form-data", "imgur", "@sanity/client", "axios", "events", "axios-cache-adapter", "lodash", "tinycache"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.BikeTagClient = {}, null, global.ImgurClient, global.sanityClient, global.axios, global.events, global.axiosCacheAdapter, global.lodash, global.TinyCache)); })(this, function(exports2, FormData, imgur, sanityClient, axios, events, axiosCacheAdapter, lodash, TinyCache) { "use strict"; var AvailableApis = /* @__PURE__ */ ((AvailableApis2) => { AvailableApis2["biketag"] = "biketag"; AvailableApis2["imgur"] = "imgur"; AvailableApis2["sanity"] = "sanity"; return AvailableApis2; })(AvailableApis || {}); var DataTypes = /* @__PURE__ */ ((DataTypes2) => { DataTypes2[DataTypes2["ambassador"] = 0] = "ambassador"; DataTypes2[DataTypes2["game"] = 1] = "game"; DataTypes2[DataTypes2["player"] = 2] = "player"; DataTypes2[DataTypes2["setting"] = 3] = "setting"; DataTypes2[DataTypes2["tag"] = 4] = "tag"; DataTypes2[DataTypes2["queue"] = 5] = "queue"; DataTypes2[DataTypes2["stat"] = 6] = "stat"; DataTypes2[DataTypes2["achievement"] = 7] = "achievement"; return DataTypes2; })(DataTypes || {}); var GameSettingsKeys = /* @__PURE__ */ ((GameSettingsKeys2) => { GameSettingsKeys2["achievementsEnabled"] = "achievements::enabled"; return GameSettingsKeys2; })(GameSettingsKeys || {}); var Errors = /* @__PURE__ */ ((Errors2) => { Errors2["NotImplemented"] = "method not implemented for adapter: "; return Errors2; })(Errors || {}); var HttpStatusCode = /* @__PURE__ */ ((HttpStatusCode2) => { HttpStatusCode2[HttpStatusCode2["Continue"] = 100] = "Continue"; HttpStatusCode2[HttpStatusCode2["SwitchingProtocols"] = 101] = "SwitchingProtocols"; HttpStatusCode2[HttpStatusCode2["Processing"] = 102] = "Processing"; HttpStatusCode2[HttpStatusCode2["Ok"] = 200] = "Ok"; HttpStatusCode2[HttpStatusCode2["Created"] = 201] = "Created"; HttpStatusCode2[HttpStatusCode2["Accepted"] = 202] = "Accepted"; HttpStatusCode2[HttpStatusCode2["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation"; HttpStatusCode2[HttpStatusCode2["NoContent"] = 204] = "NoContent"; HttpStatusCode2[HttpStatusCode2["ResetContent"] = 205] = "ResetContent"; HttpStatusCode2[HttpStatusCode2["PartialContent"] = 206] = "PartialContent"; HttpStatusCode2[HttpStatusCode2["MultiStatus"] = 207] = "MultiStatus"; HttpStatusCode2[HttpStatusCode2["AlreadyReported"] = 208] = "AlreadyReported"; HttpStatusCode2[HttpStatusCode2["ImUsed"] = 226] = "ImUsed"; HttpStatusCode2[HttpStatusCode2["MultipleChoices"] = 300] = "MultipleChoices"; HttpStatusCode2[HttpStatusCode2["MovedPermanently"] = 301] = "MovedPermanently"; HttpStatusCode2[HttpStatusCode2["Found"] = 302] = "Found"; HttpStatusCode2[HttpStatusCode2["SeeOther"] = 303] = "SeeOther"; HttpStatusCode2[HttpStatusCode2["NotModified"] = 304] = "NotModified"; HttpStatusCode2[HttpStatusCode2["UseProxy"] = 305] = "UseProxy"; HttpStatusCode2[HttpStatusCode2["SwitchProxy"] = 306] = "SwitchProxy"; HttpStatusCode2[HttpStatusCode2["TemporaryRedirect"] = 307] = "TemporaryRedirect"; HttpStatusCode2[HttpStatusCode2["PermanentRedirect"] = 308] = "PermanentRedirect"; HttpStatusCode2[HttpStatusCode2["BadRequest"] = 400] = "BadRequest"; HttpStatusCode2[HttpStatusCode2["Unauthorized"] = 401] = "Unauthorized"; HttpStatusCode2[HttpStatusCode2["PaymentRequired"] = 402] = "PaymentRequired"; HttpStatusCode2[HttpStatusCode2["Forbidden"] = 403] = "Forbidden"; HttpStatusCode2[HttpStatusCode2["NotFound"] = 404] = "NotFound"; HttpStatusCode2[HttpStatusCode2["MethodNotAllowed"] = 405] = "MethodNotAllowed"; HttpStatusCode2[HttpStatusCode2["NotAcceptable"] = 406] = "NotAcceptable"; HttpStatusCode2[HttpStatusCode2["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired"; HttpStatusCode2[HttpStatusCode2["RequestTimeout"] = 408] = "RequestTimeout"; HttpStatusCode2[HttpStatusCode2["Conflict"] = 409] = "Conflict"; HttpStatusCode2[HttpStatusCode2["Gone"] = 410] = "Gone"; HttpStatusCode2[HttpStatusCode2["LengthRequired"] = 411] = "LengthRequired"; HttpStatusCode2[HttpStatusCode2["PreconditionFailed"] = 412] = "PreconditionFailed"; HttpStatusCode2[HttpStatusCode2["PayloadTooLarge"] = 413] = "PayloadTooLarge"; HttpStatusCode2[HttpStatusCode2["UriTooLong"] = 414] = "UriTooLong"; HttpStatusCode2[HttpStatusCode2["UnsupportedMediaType"] = 415] = "UnsupportedMediaType"; HttpStatusCode2[HttpStatusCode2["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable"; HttpStatusCode2[HttpStatusCode2["ExpectationFailed"] = 417] = "ExpectationFailed"; HttpStatusCode2[HttpStatusCode2["IAmATeapot"] = 418] = "IAmATeapot"; HttpStatusCode2[HttpStatusCode2["MisdirectedRequest"] = 421] = "MisdirectedRequest"; HttpStatusCode2[HttpStatusCode2["UnprocessableEntity"] = 422] = "UnprocessableEntity"; HttpStatusCode2[HttpStatusCode2["Locked"] = 423] = "Locked"; HttpStatusCode2[HttpStatusCode2["FailedDependency"] = 424] = "FailedDependency"; HttpStatusCode2[HttpStatusCode2["UpgradeRequired"] = 426] = "UpgradeRequired"; HttpStatusCode2[HttpStatusCode2["PreconditionRequired"] = 428] = "PreconditionRequired"; HttpStatusCode2[HttpStatusCode2["TooManyRequests"] = 429] = "TooManyRequests"; HttpStatusCode2[HttpStatusCode2["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge"; HttpStatusCode2[HttpStatusCode2["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons"; HttpStatusCode2[HttpStatusCode2["InternalServerError"] = 500] = "InternalServerError"; HttpStatusCode2[HttpStatusCode2["NotImplemented"] = 501] = "NotImplemented"; HttpStatusCode2[HttpStatusCode2["BadGateway"] = 502] = "BadGateway"; HttpStatusCode2[HttpStatusCode2["ServiceUnavailable"] = 503] = "ServiceUnavailable"; HttpStatusCode2[HttpStatusCode2["GatewayTimeout"] = 504] = "GatewayTimeout"; HttpStatusCode2[HttpStatusCode2["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported"; HttpStatusCode2[HttpStatusCode2["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates"; HttpStatusCode2[HttpStatusCode2["InsufficientStorage"] = 507] = "InsufficientStorage"; HttpStatusCode2[HttpStatusCode2["LoopDetected"] = 508] = "LoopDetected"; HttpStatusCode2[HttpStatusCode2["NotExtended"] = 510] = "NotExtended"; HttpStatusCode2[HttpStatusCode2["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired"; return HttpStatusCode2; })(HttpStatusCode || {}); const cacheKeys = { sanityUrlText: `sanity::`, imageHashText: `hash::`, albumHash: `album::`, hintText: `hint::`, timeText: `time::`, playerText: `player::`, playerData: `playerData::`, playerIdText: `playerId::`, gameIdText: `gameId::`, gameSlugText: `slug::`, gameText: `game::`, locationText: `location::`, discussionText: `discussion::`, mentionText: `mention::`, tagNumberText: `tag::`, imagesText: `images::`, imageUrlText: `imageUrl::`, gpsStringText: `gpsString::`, slugText: `slug::` }; const createTagObject = (tagData = {}, foundTagData = {}) => { return { _id: tagData._id, _type: tagData._type, /// Common Tag Data game: tagData.game ?? "", slug: tagData.slug ?? "", name: tagData.name ?? "", playerId: tagData.playerId ?? "", tagnumber: tagData.tagnumber ?? 0, /// Mystery Tag Data mysteryPlayer: tagData.mysteryPlayer ?? "", mysteryImage: tagData.mysteryImage, mysteryImageUrl: tagData.mysteryImageUrl ?? "", mysteryTime: tagData.mysteryTime ?? 0, hint: tagData.hint ?? "", discussionUrl: tagData.discussionUrl ?? "", mentionUrl: tagData.mentionUrl ?? "", /// Found Tag Data foundPlayer: foundTagData.foundPlayer ?? tagData.foundPlayer ?? "", foundImage: foundTagData.foundImage ?? tagData.foundImage, foundImageUrl: foundTagData.foundImageUrl ?? tagData.foundImageUrl ?? "", foundTime: foundTagData.foundTime ?? tagData.foundTime ?? 0, foundLocation: foundTagData.foundLocation ?? tagData.foundLocation ?? "", confirmedBoundary: foundTagData.confirmedBoundary ?? tagData.confirmedBoundary ?? false, gps: foundTagData.gps ?? tagData.gps ?? "" }; }; const tagDataFields = Object.keys(createTagObject()); const tagDataReferenceFields = ["game", "player"]; const tagDataAssetFields = ["foundImage", "mysteryImage"]; const tagDataObjectFields = { foundImage: "asset->_ref", mysteryImage: "asset->_ref" }; const createGameObject = (gameData = {}) => { return { _id: gameData._id, _type: gameData._type, name: gameData.name ?? gameData.slug ?? "", ambassadors: gameData.ambassadors ?? [], settings: gameData.settings ?? [], boundary: gameData.boundary ?? {}, mainhash: gameData.mainhash ?? "", archivehash: gameData.archivehash ?? "", queuehash: gameData.queuehash ?? "", logo: gameData.logo, region: gameData.region ?? { name: gameData.name }, slug: gameData.slug ?? gameData.name ?? "" }; }; const gameDataReferenceFields = ["region", "settings"]; const gameDataArrayFields = ["ambassadors", "tags", "settings"]; const gameDataCustomFields = { settings: "[]->{key,value}", region: "name,description,zipcode,radius,tz" }; const gameDataFields = Object.keys(createGameObject()); const gameDataObjectFields = { logo: "asset->_ref" }; const createPlayerObject = (playerData = {}) => { return { _id: playerData._id, _type: playerData._type, achievements: playerData.achievements ?? [], bicon: playerData.bicon ?? "", games: playerData.games ?? (playerData.game ? [playerData.game] : []), name: playerData.name ?? "", slug: playerData.slug ?? "", tags: playerData.tags ?? [] }; }; const playerDataFields = Object.keys(createPlayerObject()); const playerDataReferenceFields = ["games", "tags", "achievements"]; const playerDataArrayFields = ["games", "tags", "achievements"]; const playerDataAssetFields = []; const playerDataObjectFields = {}; const createAmbassadorObject = (ambassadorData = {}) => { return { id: ambassadorData._id ?? ambassadorData.id ?? "", address1: ambassadorData.address1 ?? "", address2: ambassadorData.address2 ?? "", city: ambassadorData.city ?? "", country: ambassadorData.country ?? "", email: ambassadorData.email ?? "", name: ambassadorData.name ?? "", phone: ambassadorData.phone ?? "", player: ambassadorData.player ?? "", slug: ambassadorData.slug ?? "", zipcode: ambassadorData.zipcode ?? "" }; }; const ambassadorDataFields = Object.keys(createAmbassadorObject()); const ambassadorDataReferenceFields = ["player"]; const createSettingObject = (settingData = {}) => { return { slug: settingData.slug ?? "", description: settingData.description ?? "", name: settingData.name ?? "", key: settingData.key ?? "", value: settingData.value ?? "" }; }; const settingDataFields = Object.keys(createSettingObject()); const statDataReferenceFields = ["game"]; const statDataArrayFields = []; const createStatObject = (statData = {}) => { return { description: statData.description ?? "", game: statData.game ?? "", name: statData.name ?? "", key: statData.key ?? "", value: statData.value ?? "", updatedAt: statData._updatedAt ?? statData._updatedAt ?? /* @__PURE__ */ new Date() }; }; const statDataFields = [...Object.keys(createStatObject()), "_updatedAt"]; const createAchievementObject = (achievementData = {}) => { return { slug: achievementData.slug ?? "", description: achievementData.description ?? "", name: achievementData.name ?? "", key: achievementData.key ?? "", value: achievementData.value ?? "", group: achievementData.group ?? "" }; }; const achievementDataFields = Object.keys(createAchievementObject()); const putCacheIfExists = (key, value, cache) => { if (cache) cache.put(key, value); }; const getCacheIfExists = (key, cache) => { if (cache) return cache.get(key); return null; }; const hasAccessToken = (arg) => { return arg.accessToken !== void 0; }; const hasClientKey = (arg) => { return arg.clientKey !== void 0; }; const constructTagNumberSlug = (number, game = "") => { return `${game}-tag-${number}`; }; const isImgurCredentials = (credentials) => { return (credentials == null ? void 0 : credentials.clientId) !== void 0 || (credentials == null ? void 0 : credentials.clientSecret) !== void 0 || (credentials == null ? void 0 : credentials.clientId) !== void 0 && (credentials == null ? void 0 : credentials.hash) !== void 0; }; const isImgurApiReady = (credentials) => { if (!(credentials.clientId || credentials.hash)) { return 0; } else if (credentials.accessToken) { return 3; } else if (credentials.clientId && credentials.clientSecret) { return 2; } return 1; }; const isSanityCredentials = (credentials) => { return (credentials == null ? void 0 : credentials.projectId) !== void 0; }; const isSanityApiReady = (credentials) => { if (credentials.projectId !== void 0 && credentials.dataset !== void 0 && credentials.apiVersion !== void 0) { return credentials.token !== void 0 ? 3 : 1; } return 0; }; const isBikeTagCredentials = (credentials) => { return (credentials == null ? void 0 : credentials.game) !== void 0 || (credentials == null ? void 0 : credentials.clientToken) !== void 0 && (credentials == null ? void 0 : credentials.clientKey) !== void 0; }; const isBikeTagApiReady = (credentials) => { return credentials ? 1 : 0; }; const createImgurCredentials = (credentials, defaults = {}) => { var _a, _b, _c, _d, _e, _f, _g, _h, _i; return { hash: ((_a = credentials.hash) == null ? void 0 : _a.length) ? credentials.hash : defaults.hash, queuehash: ((_b = credentials.queuehash) == null ? void 0 : _b.length) ? credentials.queuehash : defaults.queuehash, archivehash: ((_c = credentials.archivehash) == null ? void 0 : _c.length) ? credentials.archivehash : defaults.archivehash, clientId: ((_d = credentials.clientId) == null ? void 0 : _d.length) ? credentials.clientId : defaults.clientId, clientSecret: ((_e = credentials.clientSecret) == null ? void 0 : _e.length) ? credentials.clientSecret : defaults.clientSecret, accessToken: ((_f = credentials.accessToken) == null ? void 0 : _f.length) ? credentials.accessToken : defaults.accessToken, refreshToken: ((_g = credentials.refreshToken) == null ? void 0 : _g.length) ? credentials.refreshToken : defaults.refreshToken, rapidApiHost: ((_h = credentials.rapidApiHost) == null ? void 0 : _h.length) ? credentials.rapidApiHost : defaults.rapidApiHost, rapidApiKey: ((_i = credentials.rapidApiKey) == null ? void 0 : _i.length) ? credentials.rapidApiKey : defaults.rapidApiKey }; }; const assignImgurCredentials = (credentials, defaults = {}) => { const imgurCredentials = isImgurCredentials(credentials) ? createImgurCredentials(credentials, defaults) : defaults; return imgurCredentials; }; const createSanityCredentials = (credentials, defaults = {}) => { var _a, _b, _c, _d, _e, _f, _g; return { useCdn: ((_a = credentials.token) == null ? void 0 : _a.length) ? false : typeof credentials.useCdn !== "undefined" ? credentials.useCdn : typeof defaults.useCdn !== "undefined" ? defaults.useCdn : true, projectId: ((_b = credentials.projectId) == null ? void 0 : _b.length) ? credentials.projectId : defaults.projectId, dataset: ((_c = credentials.dataset) == null ? void 0 : _c.length) ? credentials.dataset : defaults.dataset ?? "development", token: ((_d = credentials.token) == null ? void 0 : _d.length) ? credentials.token : defaults.token ?? "", password: ((_e = credentials.password) == null ? void 0 : _e.length) ? credentials.password : defaults.password, username: ((_f = credentials.username) == null ? void 0 : _f.length) ? credentials.username : defaults.username, apiVersion: ((_g = credentials.apiVersion) == null ? void 0 : _g.length) ? credentials.apiVersion : defaults.apiVersion ?? "2021-10-21" }; }; const assignSanityCredentials = (credentials, defaults) => { const sanityCredentials = isSanityCredentials( credentials ) ? createSanityCredentials(credentials, defaults) : defaults; return sanityCredentials; }; const createBikeTagCredentials = (credentials, defaults = {}) => { var _a, _b, _c, _d, _e, _f; return { game: ((_a = credentials.game) == null ? void 0 : _a.length) ? credentials.game : defaults.game, host: ((_b = credentials.host) == null ? void 0 : _b.length) ? credentials.host : defaults.host, cached: typeof credentials.cached !== "undefined" ? credentials.cached : defaults.cached, source: ((_c = credentials.source) == null ? void 0 : _c.length) ? credentials.source : defaults.source, clientKey: ((_d = credentials.clientKey) == null ? void 0 : _d.length) ? credentials.clientKey : defaults.clientKey, clientToken: ((_e = credentials.clientToken) == null ? void 0 : _e.length) ? credentials.clientToken : defaults.clientToken, accessToken: ((_f = credentials.accessToken) == null ? void 0 : _f.length) ? credentials.accessToken : defaults.accessToken }; }; const assignBikeTagCredentials = (credentials, defaults) => { const biketagCredentials = isBikeTagCredentials(credentials) ? createBikeTagCredentials(credentials, defaults) : defaults; return biketagCredentials; }; const assignBikeTagConfiguration = (config, defaults) => { const configuration = {}; const parsedConfig = { biketag: assignBikeTagCredentials( config, defaults == null ? void 0 : defaults.biketag ), sanity: assignSanityCredentials( config, defaults == null ? void 0 : defaults.sanity ), imgur: assignImgurCredentials( config, defaults == null ? void 0 : defaults.imgur ) }; configuration.biketag = config.biketag ? { ...parsedConfig.biketag, ...createBikeTagCredentials(config.biketag) } : parsedConfig.biketag; configuration.sanity = config.sanity ? { ...parsedConfig.sanity, ...createSanityCredentials(config.sanity) } : parsedConfig.sanity; configuration.imgur = config.imgur ? { ...parsedConfig.imgur, ...createImgurCredentials(config.imgur) } : parsedConfig.imgur; return configuration; }; const sortTags = (tags, sort = "new", limit = 0, time = "all") => { let sorted = tags; switch (sort) { /// Leaderboard? case "top": sorted = tags.sort((a, b) => b.tagnumber - a.tagnumber); break; /// Queue case "relevance": sorted = tags.sort((a, b) => { var _a, _b, _c, _d; const aHasFoundImage = (_a = a == null ? void 0 : a.foundImageUrl) == null ? void 0 : _a.length; const aHasMysteryImage = (_b = a == null ? void 0 : a.mysteryImageUrl) == null ? void 0 : _b.length; const bHasFoundImage = (_c = b == null ? void 0 : b.foundImageUrl) == null ? void 0 : _c.length; const bHasMysteryImage = (_d = b == null ? void 0 : b.mysteryImageUrl) == null ? void 0 : _d.length; const aHasBothImages = aHasFoundImage && aHasMysteryImage; const bHasBothImages = bHasFoundImage && bHasMysteryImage; const bIsBeforeA = -1; const aIsBeforeB = 1; if (!aHasBothImages && !bHasBothImages) { if (aHasFoundImage && bHasFoundImage) { return (a == null ? void 0 : a.foundTime) - (b == null ? void 0 : b.foundTime); } else if (aHasFoundImage) { return aIsBeforeB; } else if (bHasFoundImage) { return aIsBeforeB; } } else if (aHasBothImages && bHasBothImages) { const firstToComplete = (a == null ? void 0 : a.mysteryTime) - (b == null ? void 0 : b.mysteryTime); return firstToComplete; } else if (aHasBothImages && !bHasBothImages) { return bIsBeforeA; } else if (!aHasBothImages && bHasBothImages) { return aIsBeforeB; } return 0; }); break; /// BikeTags case "new": sorted = tags.sort((a, b) => (b == null ? void 0 : b.tagnumber) - (a == null ? void 0 : a.tagnumber)); break; default: sorted = tags.sort((a, b) => (a == null ? void 0 : a.tagnumber) - (b == null ? void 0 : b.tagnumber)); break; } let timeConstraint = 0; switch (time) { case "hour": timeConstraint = 60 * 60 * 1e3; break; case "day": timeConstraint = 60 * 60 * 24 * 1e3; break; case "week": timeConstraint = 60 * 60 * 24 * 7 * 1e3; break; } if (timeConstraint) { const afterDate = Date.now() - timeConstraint; sorted = sorted.filter((t) => t.mysteryTime * 1e3 > afterDate); } return limit !== 0 ? sorted.slice(0, limit) : sorted; }; const sortPlayers = (players, sort = "new", limit = 0) => { let sorted = players; switch (sort) { case "top": sorted = players.sort((a, b) => b.tags.length - a.tags.length); break; case "comments": sorted = players.sort((a, b) => a.name.localeCompare(b.name)); break; case "new": sorted = players.reverse(); break; } return limit !== 0 ? sorted.slice(0, limit) : sorted; }; const sortAmbassadors = (ambassadors, sort = "new", limit = 0) => { const sorter = (a, b) => b.name.localeCompare(a.name); let sorted = ambassadors; switch (sort) { case "top": sorted = ambassadors.sort(sorter); break; case "new": sorted = ambassadors.reverse(); break; } return limit !== 0 ? sorted.slice(0, limit) : sorted; }; const sortSettings = (settings, sort = "new", limit = 0) => { let sorted = settings; switch (sort) { case "comments": sorted = settings.sort((a, b) => a.name.localeCompare(b.name)); break; case "new": sorted = settings.reverse(); break; } return limit !== 0 ? sorted.slice(0, limit) : sorted; }; const sortStats = (stats, sort = "new", limit = 0) => { let sorted = stats; switch (sort) { case "comments": sorted = stats.sort((a, b) => a.name.localeCompare(b.name)); break; case "new": sorted = stats.reverse(); break; } return limit !== 0 ? sorted.slice(0, limit) : sorted; }; const sortAchievements = (achievements, sort = "new", limit = 0) => { let sorted = achievements; switch (sort) { case "comments": sorted = achievements.sort((a, b) => a.name.localeCompare(b.name)); break; case "new": sorted = achievements.reverse(); break; } return limit !== 0 ? sorted.slice(0, limit) : sorted; }; const getGameAlbumFromCache = async (gameAlbumHash, cache, fallback, useCache = true) => { const cacheKey = `imgur::${cacheKeys.albumHash}${gameAlbumHash}`; const existsInCache = getCacheIfExists(cacheKey, useCache ? cache : void 0); if (existsInCache) { return existsInCache; } if (fallback) { const putIntoCache = await fallback(); putCacheIfExists(cacheKey, putIntoCache, cache); return putIntoCache; } }; const getTagDate = (time) => new Date(time * 1e3); const convertMiliseconds = (miliseconds, format) => { const total_seconds = Math.floor(miliseconds / 1e3); const total_minutes = Math.floor(total_seconds / 60); const total_hours = Math.floor(total_minutes / 60); const days = Math.floor(total_hours / 24); const seconds = total_seconds % 60; const minutes = total_minutes % 60; const hours = total_hours % 24; switch (format) { case "s": return total_seconds; case "m": return total_minutes; case "h": return total_hours; case "d": return days; default: return { d: days, h: hours, m: minutes, s: seconds }; } }; const getLongestTimeBetweenTags = (tags) => { let longestTimeBetweenTags = 0; let startDate = null; let endDate = null; let previousTag = null; let staleTagNumber = 0; const sortedTags = [...tags].reverse(); for (const tag of sortedTags) { if (previousTag !== null) { const timeBetweenTags = tag.mysteryTime - previousTag.mysteryTime; if (timeBetweenTags > longestTimeBetweenTags) { longestTimeBetweenTags = timeBetweenTags; startDate = new Date(previousTag.mysteryTime * 1e3); endDate = new Date(tag.mysteryTime * 1e3); staleTagNumber = previousTag.tagnumber; } } previousTag = tag; } return { timeBetweenTagsDays: convertMiliseconds( longestTimeBetweenTags * 1e3, "d" ), startDate, endDate, staleTagNumber }; }; const getPlayersWithLongestDailyTagStreakData = (players) => { let longestStreakDays = 0; let playerRecord; const playersData = []; for (const player of players) { if (player.name === "") { console.log( "Player has no name, and probably no real data. Ignoring player: ", player ); continue; } const playerLongestStreakData = getTagLongestDailyStreakData( player.tags ); if (playerLongestStreakData.longestStreakDaysCount > longestStreakDays) { longestStreakDays = playerLongestStreakData.longestStreakDaysCount; } playerRecord = { playerName: player.name, longestStreakData: playerLongestStreakData }; playersData.push(playerRecord); } const longestStreakPlayersData = []; for (const pd of playersData) { if (pd.longestStreakData.longestStreakDaysCount >= longestStreakDays) { longestStreakPlayersData.push(pd); } } return longestStreakPlayersData; }; const getTagLongestDailyStreakData = (tags) => { const tagDates = getUniqueTagDates(tags); tagDates.sort((a, b) => a.getTime() - b.getTime()); let streakDaysCount = 1; let streakDaysCountLongest = 1; let streakStartDate = null; let streakLongestStartDate = null; let streakEndDate = null; let previousDate = null; const oneDay = 24 * 60 * 60 * 1e3; for (const td of tagDates) { if (previousDate !== null) { const tagDateMinusOneDay = /* @__PURE__ */ new Date(); tagDateMinusOneDay.setTime(td.getTime() - oneDay); if (getIsSameDay(tagDateMinusOneDay, previousDate)) { streakDaysCount++; if (streakDaysCount === 2) { streakStartDate = previousDate; } if (streakDaysCount >= streakDaysCountLongest) { streakLongestStartDate = streakStartDate; streakDaysCountLongest = streakDaysCount; streakEndDate = td; } } else { streakDaysCount = 1; } } else { streakStartDate = td; streakEndDate = td; } previousDate = td; } const streakData = { longestStreakDaysCount: streakDaysCountLongest, longestStreakStartDate: streakDaysCountLongest > 1 ? streakLongestStartDate : null, longestStreakEndDate: streakDaysCountLongest > 1 ? streakEndDate : null }; return streakData; }; const getUniqueTagDates = (tags) => { const uniqueTagDates = []; for (const tag of tags) { if (tag.mysteryTime === 0) { continue; } const tagDate = getTagDate(tag.mysteryTime); if (uniqueTagDates.length === 0) { uniqueTagDates.push(tagDate); } else { const isAlreadyPresent = uniqueTagDates.some( (date) => getIsSameDay(date, tagDate) ); if (!isAlreadyPresent) { uniqueTagDates.push(tagDate); } } } return uniqueTagDates; }; const getIsSameDay = (d1, d2) => { return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate(); }; const getDaysDifference = (d1, d2) => { const timeDiff = Math.abs(d2.getTime() - d1.getTime()); const oneDay = 24 * 60 * 60 * 1e3; const diffDays = Math.ceil(timeDiff / oneDay); return diffDays; }; const getIsWithinDaysRange = (d1, d2, days) => { const diffDays = getDaysDifference(d1, d2); return diffDays <= days; }; const getGameHighestNumberTagsPerNumberDaysData = (tags, days = 1) => { let tagsPerNumberDaysHighest = 1; let previousTagDate = null; let startDate = null; let endDate = null; let tagDatesInRange = []; let tagIsInRange = false; let tagsPerNumberDaysData = { tagCount: tagsPerNumberDaysHighest, dayCount: days, startDate: null, endDate: null }; const oneDay = 24 * 60 * 60 * 1e3; const daysBack = [...Array(days).keys()]; const sortedTags = [...tags].reverse(); for (const tag of sortedTags) { const tagDate = getTagDate(tag.mysteryTime); if (previousTagDate !== null) { if (tagDatesInRange.length === 0) { tagDatesInRange = [previousTagDate]; } const tagDatesInRangeNew = [...tagDatesInRange]; for (const dayBack of daysBack) { const daysBackTime = oneDay * dayBack; const tagDateMinusDayBack = /* @__PURE__ */ new Date(); tagDateMinusDayBack.setTime(tagDate.getTime() - daysBackTime); for (const tagDateInRange of tagDatesInRange) { if (getIsWithinDaysRange(tagDateInRange, tagDateMinusDayBack, days)) { tagDatesInRangeNew.push(tagDate); tagIsInRange = true; break; } else { const indexNotInRangeDate = tagDatesInRangeNew.indexOf(tagDateInRange); tagDatesInRangeNew.splice(indexNotInRangeDate, 1); tagIsInRange = false; } } if (tagIsInRange) { break; } } tagDatesInRange = tagDatesInRangeNew; if (tagDatesInRange.length >= tagsPerNumberDaysHighest) { tagsPerNumberDaysHighest = tagDatesInRange.length; startDate = tagDatesInRange[0]; endDate = tagDatesInRange[tagDatesInRange.length - 1]; } } previousTagDate = tagDate; } tagsPerNumberDaysData = { tagCount: tagsPerNumberDaysHighest, dayCount: days, startDate, endDate }; return tagsPerNumberDaysData; }; const getPlayerHighestNumberTagsPerDayData = (player) => { const tagsPerDayData = { playerName: player.name, tagCount: null, tagDate: null }; let tagsPerDay = 1; let tagsPerDayHighest = 1; let previousTagDate = null; for (const tag of player.tags) { const tagDate = getTagDate(tag.mysteryTime); if (previousTagDate !== null && getIsSameDay(tagDate, previousTagDate)) { tagsPerDay++; } else { tagsPerDay = 1; } if (tagsPerDay > tagsPerDayHighest) { tagsPerDayHighest = tagsPerDay; tagsPerDayData.tagCount = tagsPerDayHighest; tagsPerDayData.tagDate = tagDate; } previousTagDate = tagDate; } return tagsPerDayData; }; const getPlayersWithHighestNumberTagsPerDayData = (players) => { let tagsPerDayHighest = 0; const tagsPerDayData = []; const highestTagsPerDayData = []; for (const player of players) { if (player.name === "") { console.log( "Player has no name, and probably no real data. Ignoring player: ", player ); continue; } const tagsPerDayRecord = getPlayerHighestNumberTagsPerDayData(player); tagsPerDayData.push(tagsPerDayRecord); if (tagsPerDayRecord.tagCount !== null && tagsPerDayRecord.tagCount > tagsPerDayHighest) { tagsPerDayHighest = tagsPerDayRecord.tagCount; } } for (const tpdr of tagsPerDayData) { if (tpdr.tagCount !== null && tpdr.tagCount >= tagsPerDayHighest) { highestTagsPerDayData.push(tpdr); } } return highestTagsPerDayData; }; const getTagNumbersFromTextRegex = new RegExp( /((?:(?:bike\s*)?(?:\s*tag)?)(#|num|number)(\d+)(?:(?:\s*tag)?|(?:\s*proof)?))|((?:bike\s*)?(?:tag\s*)(#|num|number)?\s*(\d+))|((?:(?:found\s*#?)|(?:here'?i?s?\s*))\[?(\d+)\]?)/gi ); const getPlayerFromTextRegex = new RegExp( /((?:proof\s*(?:found\s*at\s*)?(?:\(.*\))?\s*by\s*)(.*?(?= on \[|$)))|((?:tag\s*(?:(?:\(\s*hint:\s*)?.*\))?\s*by\s*)(.+?(?= on \[|\r|\n|$))?)|((?:tag\s*(?:(?:\(\s*hint:\s*)?.*\))?\s*by\s*)(.+?(?= on \[|\r|\n))?)|((?:credit goes to:\s*)(.*)(?:\sfor finding))|(?:tag\s*)(?:number\s*)?(\d*)?(?:\s*by\s*)(.+?(?= on \[|$|\n))/i ); const getFoundLocationFromTextRegex = new RegExp( /(?:is\s*(?:at|the)?\s*?)(.*?)(?=\s*by\s+|\]|$)|(?:found)\s*(?:at)?\s*\(([^()]+(\([^()]+\)[^()]*)*)\)(.*(?:\)|]|$))|(?:found\s*at\s*\()(.*(?:\)))/im ); const getConfirmedBoundaryFromTextRegex = new RegExp( /(\s*\[.*\]✓\s*\(.*\)\s*)/im ); const getPlayerFromInfoFromTextRegex = new RegExp( /(?:\[Player\s*)(.*)(?:]\s*\+\()(.*)(?=\))/i ); const getGameFromInfoFromTextRegex = new RegExp( /(((?:{\s*)(.*)(?:}))((?:\s*\[)(.*)(?=\])\])?((?:\s*@\()(.*)(?=\))\))?)\s*::\s*(((?:\[BikeTag\s*Game\s*)(.*)(?:]))((?:\s*#\()(.*)(?=\))\))?((?:\s*\|)(.*)(?=\|)\|)?)/i ); const getGameSlugFromTextRegex = new RegExp(/((\w*)\s*bike\s*tag!?)/i); const getHintFromTextRegex = new RegExp(/(?:hint:\s*)(.*)\)/i); const getTimeFromTextRegex = new RegExp( /(?:on\s+\[(\d+\/\d+\/\d\d)@(\d+:\d+:\d+)\])/i ); const getGPSLocationFromTextRegex = new RegExp( /(([0-9]{1,2})[:|°]([0-9]{1,2})[:|'|′]?([0-9]{1,2}(?:\.[0-9]+){0,1})?["|″]([N|S]),?\s*([0-9]{1,3})[:|°]([0-9]{1,2})[:|'|′]?([0-9]{1,2}(?:\.[0-9]+){0,1})?["|″]([E|W]))|((-?\d+(\.\d+)?),\s*(-?\d+(\.\d+)?))/ ); const getImageURLsFromTextRegex = new RegExp( /https?:\/\/.*?\.[a-z]{2,4}\/.+?(?=\)|\s|$)/gi ); const getAlbumIdFromTextRegex = new RegExp( /((?:imgur.com\/)(?:(a|album|gallery)\/)(\w+))/i ); const getPlayerIdFromTextRegex = RegExp(/\[(.*)\]/i); const getDiscussionUrlFromTextRegex = RegExp(/{(.*)}/i); const getGPSCoordinatesValueFromTextRegex = RegExp(/\((.*)\)/i); const getTagnumberFromSlugRegex = RegExp(/([^-]*)([^-]*)(\d)/); const getImgurImageHashFromUrlRegex = RegExp( /(?:imgur.com\/)(.*)(?:\.)/i ); const getSanityImageUrlHashFromTextRegex = RegExp( /^(?:image-)(.*?(?=-(-png|-jpg|-jpeg|-gif)))/i ); const getCreditFromBlueskyTextRegex = RegExp( /(?:tag\s*)(?:number\s*)?(\d*)?(?:\s*by\s*)(.+?(?=$|\n))/i ); const BikeTagExpressions = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, getAlbumIdFromTextRegex, getConfirmedBoundaryFromTextRegex, getCreditFromBlueskyTextRegex, getDiscussionUrlFromTextRegex, getFoundLocationFromTextRegex, getGPSCoordinatesValueFromTextRegex, getGPSLocationFromTextRegex, getGameFromInfoFromTextRegex, getGameSlugFromTextRegex, getHintFromTextRegex, getImageURLsFromTextRegex, getImgurImageHashFromUrlRegex, getPlayerFromInfoFromTextRegex, getPlayerFromTextRegex, getPlayerIdFromTextRegex, getSanityImageUrlHashFromTextRegex, getTagNumbersFromTextRegex, getTagnumberFromSlugRegex, getTimeFromTextRegex }, Symbol.toStringTag, { value: "Module" })); const getConfirmedBoundarySymbol = "✓"; const getTagnumberFromSlug = (inputText, fallback, cache) => { if (!inputText.length) return fallback; const cacheKey = `${cacheKeys.slugText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const slugText = getTagnumberFromSlugRegex.exec(inputText); if (!slugText) { putCacheIfExists(cacheKey, fallback, cache); return fallback; } const slug = parseInt((slugText[0] || "").trim()); putCacheIfExists(cacheKey, slug, cache); return slug; }; const getTagNumbersFromText$1 = (inputText, fallback, cache) => { if (!inputText.length) return fallback; const cacheKey = `${cacheKeys.tagNumberText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const tagNumberText = inputText.match(getTagNumbersFromTextRegex); if (!tagNumberText) return fallback || []; const tagNumbers = tagNumberText.reduce((numbers, text) => { if (!text) return numbers; const tagNumberMatches = text.match(/\d+/); const tagNumber = tagNumberMatches && tagNumberMatches.length ? tagNumberMatches[0] : null; if (!tagNumber) return numbers; const number = Number.parseInt(tagNumber); if (numbers.indexOf(number) == -1) numbers.push(number); return numbers; }, []); if (!tagNumbers.length && fallback) { putCacheIfExists(cacheKey, fallback, cache); return fallback; } putCacheIfExists(cacheKey, tagNumbers, cache); return tagNumbers; }; const getPlayerFromText$1 = (inputText, fallback, cache) => { if (!inputText.length) return fallback; const cacheKey = `${cacheKeys.playerText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const playerText = getPlayerFromTextRegex.exec(inputText); if (!playerText) return fallback ?? null; const tagPlayers = playerText.filter( (c) => typeof c === "string" && (c.indexOf("tag ") === -1 || c.indexOf("tag") !== 0) && (c.indexOf("proof ") === -1 || c.indexOf("proof") !== 0) && c.indexOf("to:") === -1 && c.indexOf("hint:") === -1 && Number.isInteger(Number.parseInt(c)) === false && (c.indexOf(" by ") === -1 || c.indexOf(" by ") !== 0) ); if (!tagPlayers.length && fallback) { putCacheIfExists(cacheKey, fallback, cache); return fallback; } const player = tagPlayers[0]; putCacheIfExists(cacheKey, player, cache); return player; }; const getFoundLocationFromText$1 = (inputText, fallback, cache) => { if (!inputText.length) return fallback; const cacheKey = `${cacheKeys.locationText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const foundLocationText = getFoundLocationFromTextRegex.exec(inputText); if (!foundLocationText) { fallback = fallback ?? null; putCacheIfExists(cacheKey, fallback, cache); return fallback; } const foundLocation = (foundLocationText[1] ?? foundLocationText[2] ?? "").trim(); putCacheIfExists(cacheKey, foundLocation, cache); return foundLocation; }; const getHintFromText$1 = (inputText, fallback, cache) => { if (!inputText.length) return fallback; const cacheKey = `${cacheKeys.hintText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const tagNumberText = inputText.match(getHintFromTextRegex); if (!tagNumberText) return fallback ?? null; const tagNumbers = tagNumberText.reduce((numbers, text) => { const tagNumberMatches = text.match(/\d+/); const tagNumber = tagNumberMatches && tagNumberMatches.length ? tagNumberMatches[0] : null; if (!tagNumber) return numbers; const number = Number.parseInt(tagNumber); if (numbers.indexOf(number) == -1) numbers.push(number); return numbers; }, []); if (!tagNumbers.length && fallback) { putCacheIfExists(cacheKey, fallback, cache); return fallback; } putCacheIfExists(cacheKey, tagNumbers, cache); return tagNumbers; }; const getGpsStringLocationFromText = (inputText, fallback, cache) => { if (!(inputText == null ? void 0 : inputText.length)) return fallback; const cacheKey = `${cacheKeys.gpsStringText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; inputText = inputText.replace(/\\/g, ""); inputText.match(getGPSLocationFromTextRegex); const gpsText = getGPSLocationFromTextRegex.exec(inputText); if (!gpsText) { fallback = fallback ?? null; putCacheIfExists(cacheKey, fallback, cache); return fallback; } const gpsString = gpsText[0].split(",").length > 2 ? gpsText[0] : `${gpsText[0]}, 0`; putCacheIfExists(cacheKey, gpsString, cache); return gpsString; }; const getGPSLocationFromText = (inputText, fallback, cache) => { const gpsString = getGpsStringLocationFromText(inputText, "", cache); if (gpsString.length) { const gpsPair = gpsString.split(","); const gpsLocation = { lat: parseFloat(gpsPair[0]), long: parseFloat(gpsPair[1]), alt: parseFloat(gpsPair[2]) }; return gpsLocation; } return fallback ?? { lat: 0, long: 0, alt: 0 }; }; const getImgurAlbumIdFromText = (inputText, fallback, cache) => { if (!inputText.length) return fallback; const cacheKey = `${cacheKeys.imageUrlText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; inputText.match(getAlbumIdFromTextRegex); const albumbIdMatches = getAlbumIdFromTextRegex.exec(inputText); const albumbIds = albumbIdMatches.reduce((ids, id) => { if (id.indexOf("gallery") === -1 && id.indexOf("?") === -1 && id.indexOf("a/") === -1 && id.length > 1) { ids.push(id); } return ids; }, []); if (!albumbIds.length && fallback) { putCacheIfExists(cacheKey, fallback, cache); return fallback; } const albumbId = albumbIds[0]; putCacheIfExists(cacheKey, albumbId, cache); return albumbId; }; const getMentionURLsFromText = (inputText, fallback, cache) => { if (!inputText.length) return fallback; const cacheKey = `${cacheKeys.mentionText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const validImageURLs = ["t.co"]; const selfTextURLs = inputText.match(getImageURLsFromTextRegex); if (selfTextURLs) { const tagImageURLs = selfTextURLs.reduce((urls, url) => { if (!url || !new RegExp(validImageURLs.join("|")).test(url)) return urls; const ext = /[^.]+$/.test(url) ? "." + /[^.]+$/.exec(url) : ""; if ( // ['.jpg', '.jpeg', '.png', '.bmp'].indexOf(ext) === -1 && ext.indexOf(".co") === 0 && url.indexOf("//t.co/") !== -1 && url.length > 2 ) ; urls.push(url); return urls; }, []); if (!tagImageURLs.length && fallback) { putCacheIfExists(cacheKey, fallback, cache); return fallback; } putCacheIfExists(cacheKey, tagImageURLs, cache); return tagImageURLs; } putCacheIfExists(cacheKey, fallback, cache); return fallback; }; const getImageURLsFromText = (inputText, fallback, cache) => { if (!inputText.length) return fallback; const cacheKey = `${cacheKeys.imagesText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const validImageURLs = ["imgur", "t.co"]; const selfTextURLs = inputText.match(getImageURLsFromTextRegex); if (selfTextURLs) { const tagImageURLs = selfTextURLs.reduce((urls, url) => { if (!url || !new RegExp(validImageURLs.join("|")).test(url)) return urls; const ext = /[^.]+$/.test(url) ? "." + /[^.]+$/.exec(url) : ""; if ([".jpg", ".jpeg", ".png", ".webp", ".bmp"].indexOf(ext) === -1 && ext.indexOf(".com/") === 0 && url.indexOf("//imgur.com/") !== -1 && url.indexOf("3/album") === -1 && url.indexOf("/a/") === -1 && url.indexOf(".com/gallery") === -1 && url.length > 2) { url = `${url.replace("//imgur.com", "//i.imgur.com")}.jpg`; } urls.push(url); return urls; }, []); if (!tagImageURLs.length && fallback) { putCacheIfExists(cacheKey, fallback, cache); return fallback; } putCacheIfExists(cacheKey, tagImageURLs, cache); return tagImageURLs; } putCacheIfExists(cacheKey, fallback, cache); return fallback; }; const getDiscussionUrlFromText$1 = (inputText, cache) => { if (!inputText.length) return ""; const cacheKey = `${cacheKeys.discussionText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const tagDiscussionLinkMatches = getDiscussionUrlFromTextRegex.exec(inputText); if (!(tagDiscussionLinkMatches == null ? void 0 : tagDiscussionLinkMatches.length)) { putCacheIfExists(cacheKey, null, cache); return null; } const discussionUrl = (tagDiscussionLinkMatches[1] || "").trim(); putCacheIfExists(cacheKey, discussionUrl, cache); return discussionUrl; }; const getImageHashFromText = (inputText, cache) => { if (!(inputText == null ? void 0 : inputText.length)) return ""; const cacheKey = `${cacheKeys.imageHashText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; inputText.match(getImgurImageHashFromUrlRegex); const imageHashMatches = getImgurImageHashFromUrlRegex.exec(inputText); if (!imageHashMatches || !imageHashMatches.length) { putCacheIfExists(cacheKey, null, cache); return null; } const imageHash = (imageHashMatches[1] || "").trim(); putCacheIfExists(cacheKey, imageHash, cache); return imageHash; }; const getSanityImageUrlHashFromText = (inputText, cache) => { if (!inputText.length) return ""; const cacheKey = `${cacheKeys.sanityUrlText}${inputText}`; const existingParsed = getCacheIfExists(cacheKey, cache); if (existingParsed) return existingParsed; const imageUrlMatches = getSanityImageUrlHashFromTextRegex.exec(inputText); if (!imageUrlMatches || !imageUrlMatches.length) { putCacheIfExists(cacheKey, null, cache); return null; } const imageHash = (imageUrlMatches[1] || "").trim(); putCacheIfExists(cacheKey, imageHash, cache); return imageHash; }; const getImgurFoundImageHashFromBikeTagData = (tag, cache) => { return getImageHashFromText(tag.foundImageUrl, cache); }; const getDateStringForImgurDescription = (isodate) => { if (!isodate) return ""; const date = new Date(isodate * 1e3); const dateString = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear().toString().substring(2)}`; const timeString = `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}`; return ` on [${dateString}@${timeString}]`; }; const getImgurFoundDescriptionFromBikeTagData = (tag, includeCredit = true, includeDate = true) => `#${tag.tagnumber} proof${tag.foundLocation ? ` found at (${tag.foundLocation})` : ""}${includeCredit ? ` by ${tag.foundPlayer}` : ""}${includeDate ? getDateStringForImgurDescription(tag.foundTime) : ""}`; const getImgurFoundTitleFromBikeTagData = (tag, fromCombinedTag = false) => { var _a; return `${!tag.gps || tag.gps.lat === 0 && tag.gps.long === 0 ? "" : `(${tag.gps.lat ?? 0}, ${tag.gps.long ?? 0}, ${tag.gps.alt ?? 0})`} ${!fromCombinedTag && // don't include the player id from a combined tag in the found tag ((_a = tag.playerId) == null ? void 0 : _a.length) ? `[${tag.playerId}]` : ""} ${tag.confirmedBoundary ? getConfirmedBoundarySymbol : ""}`; }; const getImgurMysteryImageHashFromBikeTagData = (tag, cache) => { return getImageHashFromText(tag.mysteryImageUrl, cache); }; const getImgurMysteryTitleFromBikeTagData = (tag, fromCombinedTag = false) => { var _a; return `${!fromCombinedTag && // don't include the gps from a combined tag in the mystery !tag.gps || tag.gps.lat === 0 && tag.gps.long === 0 ? "" : `(${tag.gps.lat ?? 0}, ${tag.gps.long ?? 0}, ${tag.gps.alt ?? 0})`} ${((_a = tag.playerId) == null ? void 0 : _a.length) ? `[${tag.playerId}]` : ""} ${tag.discussionUrl ? `{${tag.discussionUrl}}` : ""}`; }; const getImgurMysteryDescriptionFromBikeTagData = (tag, includeCredit = true, includeHint = true, includeDate = true) => `#${tag.tagnumber} tag ${includeHint && tag.hint ? `(hint: ${tag.hint})` : ""}${includeCredit ? ` by ${tag.mysteryPlayer}` : ""}${includeDate ? getDateStringForImgurDescription(tag.mysteryTime) : ""}`; const getOnlyMysteryTagFromTagData = (tagData) => { const onlyMysteryTagFields = { playerId: tagData.playerId, game: tagData.game, tagnumber: tagData.tagnumber, name: tagData.name, slug: tagData.slug, mysteryImageUrl: tagData.mysteryIm