1(()=>{var __webpack_modules__={"../assets/src/scripts/rudder/bot-patterns.generated.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ CRAWLER_PATTERNS: () => (/* binding */ CRAWLER_PATTERNS)\n/* harmony export */ });\n/* eslint-disable */\n// AUTO-GENERATED â do not edit by hand.\n// Source: https://raw.githubusercontent.com/monperrus/crawler-user-agents/master/crawler-user-agents.json\n// Regenerated by build/scripts/fetch-bot-patterns.js during production builds.\n// Commit this file â it\'s the offline fallback and lets dev builds skip the fetch.\n// eslint-disable at top prevents `npm run watch --fixjs` (autofix) from\n// touching the formatting on every run; also listed in build/.eslintrc.js\n// ignorePatterns as belt-and-suspenders.\n\nvar CRAWLER_PATTERNS = ["Googlebot\\\\/", "Googlebot-Mobile", "Googlebot-Image", "Googlebot-News", "Googlebot-Video", "AdsBot-Google([^-]|$)", "AdsBot-Google-Mobile", "Feedfetcher-Google", "Mediapartners-Google", "Mediapartners \\\\(Googlebot\\\\)", "APIs-Google", "Google-InspectionTool", "Storebot-Google", "GoogleOther", "bingbot", "Slurp", "[wW]get", "LinkedInBot", "Python-urllib", "python-requests", "aiohttp", "httpx", "libwww-perl", "httpunit", "Nutch", "Go-http-client", "phpcrawl", "msnbot", "jyxobot", "FAST-WebCrawler", "FAST Enterprise Crawler", "BIGLOTRON", "Teoma", "convera", "^Seekbot", "Gigabot", "Gigablast", "exabot", "ia_archiver", "GingerCrawler", "webmon ", "HTTrack", "grub\\\\.org", "UsineNouvelleCrawler", "antibot", "netresearchserver", "speedy", "fluffy", "findlink", "msrbot", "panscient", "yacybot", "AISearchBot", "ips-agent", "tagoobot", "MJ12bot", "woriobot", "yanga", "buzzbot", "mlbot", "yandex\\\\.com\\\\/bots", "purebot", "Linguee Bot", "CyberPatrol", "voilabot", "Baiduspider", "citeseerxbot", "spbot", "twengabot", "postrank", "Turnitin", "scribdbot", "page2rss", "sitebot", "linkdex", "Adidxbot", "ezooms", "dotbot", "Mail\\\\.RU_Bot", "discobot", "heritrix", "findthatfile", "europarchive\\\\.org", "NerdByNature\\\\.Bot", "(sistrix|SISTRIX) [cC]rawler", "Ahrefs(Bot|SiteAudit)", "fuelbot", "^CrunchBot", "IndeedBot", "mappydata", "woobot", "ZoominfoBot", "PrivacyAwareBot", "Multiviewbot", "SWIMGBot", "Grobbot", "eright", "Apercite", "semanticbot", "Aboundex", "domaincrawler", "wbsearchbot", "summify", "CCBot", "edisterbot", "SeznamBot", "ec2linkfinder", "gslfbot", "aiHitBot", "intelium_bot", "facebookexternalhit", "Yeti", "RetrevoPageAnalyzer", "lb-spider", "Sogou", "lssbot", "careerbot", "wotbox", "wocbot", "ichiro", "DuckDuckBot", "lssrocketcrawler", "drupact", "webcompanycrawler", "acoonbot", "openindexspider", "gnam gnam spider", "web-archive-net\\\\.com\\\\.bot", "backlinkcrawler", "coccoc", "integromedb", "content crawler spider", "toplistbot", "it2media-domain-crawler", "ip-web-crawler\\\\.com", "siteexplorer\\\\.info", "elisabot", "proximic", "changedetection", "arabot", "WeSEE:Search", "niki-bot", "CrystalSemanticsBot", "rogerbot", "360Spider", "psbot", "InterfaxScanBot", "CC Metadata Scaper", "g00g1e\\\\.net", "GrapeshotCrawler", "urlappendbot", "brainobot", "fr-crawler", "binlar", "SimpleCrawler", "Twitterbot", "cXensebot", "smtbot", "bnf\\\\.fr_bot", "A6-Indexer", "ADmantX", "Facebot", "OrangeBot\\\\/", "memorybot", "AdvBot", "MegaIndex", "SemanticScholarBot", "ltx71", "nerdybot", "xovibot", "BUbiNG", "Qwantify", "archive\\\\.org_bot", "Applebot", "TweetmemeBot", "crawler4j", "findxbot", "S[eE][mM]rushBot", "yoozBot", "lipperhey", "Y!J", "Domain Re-Animator Bot", "AddThis", "Screaming Frog SEO Spider", "MetaURI", "Scrapy", "Livelap[bB]ot", "OpenHoseBot", "CapsuleChecker", "collection@infegy\\\\.com", "IstellaBot", "DeuSu\\\\/", "betaBot", "Cliqzbot\\\\/", "MojeekBot\\\\/", "netEstate NE Crawler", "SafeSearch microdata crawler", "Gluten Free Crawler\\\\/", "Sonic", "Sysomos", "Trove", "deadlinkchecker", "Slack-ImgProxy", "Embedly", "RankActiveLinkBot", "iskanie", "SafeDNSBot", "SkypeUriPreview", "Veoozbot", "Slackbot", "redditbot", "datagnionbot", "Google-Adwords-Instant", "adbeat_bot", "WhatsApp", "contxbot", "pinterest\\\\.com\\\\/bot", "electricmonk", "GarlikCrawler", "BingPreview\\\\/", "vebidoobot", "FemtosearchBot", "Yahoo Link Preview", "MetaJobBot", "DomainStatsBot", "mindUpBot", "Daum\\\\/", "Jugendschutzprogramm-Crawler", "Xenu Link Sleuth", "Pcore-HTTP", "moatbot", "KosmioBot", "[pP]ingdom", "AppInsights", "PhantomJS", "Gowikibot", "PiplBot", "Discordbot", "TelegramBot", "Jetslide", "newsh
1arecounts", "James BOT", "Bark[rR]owler", "TinEye", "SocialRankIOBot", "trendictionbot", "Ocarinabot", "epicbot", "Primalbot", "DuckDuckGo-Favicons-Bot", "GnowitNewsbot", "Leikibot", "LinkArchiver", "YaK\\\\/", "PaperLiBot", "Digg Deeper", "^dcrawl", "Snacktory", "AndersPinkBot", "Fyrebot", "EveryoneSocialBot", "Mediatoolkitbot", "Luminator-robots", "ExtLinksBot", "SurveyBot", "NING\\\\/", "okhttp", "Nuzzel", "omgili", "PocketParser", "YisouSpider", "um-LN", "ToutiaoSpider", "MuckRack", "Jamie\'s Spider", "AHC\\\\/", "NetcraftSurveyAgent", "Laserlikebot", "^Apache-HttpClient", "AppEngine-Google", "Jetty", "Upflow", "Thinklab", "Traackr\\\\.com", "Twurly", "Mastodon", "http_get", "DnyzBot", "botify", "007ac9 Crawler", "BehloolBot", "BrandVerity", "check_http", "BDCbot", "ZumBot", "EZID", "ICC-Crawler", "ArchiveBot", "^LCC ", "filterdb\\\\.iss\\\\.net\\\\/crawler", "BLP_bbot", "BomboraBot", "Buck\\\\/", "Companybook-Crawler", "Genieo", "magpie-crawler", "MeltwaterNews", "Moreover", "newspaper\\\\/", "ScoutJet", "(^| )sentry\\\\/", "StorygizeBot", "UptimeRobot", "OutclicksBot", "seoscanners", "Hatena", "Google Web Preview", "MauiBot", "AlphaBot", "SBL-BOT", "IAS crawler", "adscanner", "Netvibes", "acapbot", "Baidu-YunGuanCe", "bitlybot", "blogmuraBot", "Bot\\\\.AraTurka\\\\.com", "bot-pge\\\\.chlooe\\\\.com", "BoxcarBot", "BTWebClient", "ContextAd Bot", "Digincore bot", "Disqus", "Feedly", "Fetch\\\\/", "Fever", "Flamingo_SearchEngine", "FlipboardProxy", "g2reader-bot", "G2 Web Services", "imrbot", "K7MLWCBot", "Kemvibot", "Landau-Media-Spider", "linkapediabot", "vkShare", "Siteimprove\\\\.com", "BLEXBot\\\\/", "DareBoost", "ZuperlistBot\\\\/", "Miniflux\\\\/", "Feedspot", "Diffbot\\\\/", "SEOkicks", "tracemyfile", "Nimbostratus-Bot", "zgrab", "PR-CY\\\\.RU", "AdsTxtCrawler", "Datafeedwatch", "Zabbix", "TangibleeBot", "google-xrawler", "axios", "Amazon CloudFront", "Pulsepoint ", "CloudFlare-AlwaysOnline", "Cloudflare-Healthchecks", "Cloudflare-Traffic-Manager", "CloudFlare-Prefetch", "Cloudflare-SSLDetector", "https:\\\\/\\\\/developers\\\\.cloudflare\\\\.com\\\\/security-center\\\\/", "Google-Structured-Data-Testing-Tool", "WordupInfoSearch", "WebDataStats", "HttpUrlConnection", "ZoomBot", "VelenPublicWebCrawler", "MoodleBot", "jpg-newsbot", "outbrain", "W3C_Validator", "Validator\\\\.nu", "W3C-checklink", "W3C-mobileOK", "W3C_I18n-Checker", "FeedValidator", "W3C_CSS_Validator", "W3C_Unicorn", "Google-PhysicalWeb", "Blackboard", "ICBot\\\\/", "BazQux", "Twingly", "Rivva", "Experibot", "awesomecrawler", "Dataprovider\\\\.com", "GroupHigh\\\\/", "theoldreader\\\\.com", "AnyEvent", "Uptimebot\\\\.org", "Nmap Scripting Engine", "2ip\\\\.ru", "Clickagy", "Caliperbot", "MBCrawler", "online-webceo-bot", "B2B Bot", "AddSearchBot", "Google Favicon", "HubSpot", "Chrome-Lighthouse", "HeadlessChrome", "CheckMarkNetwork\\\\/", "www\\\\.uptime\\\\.com", "Streamline3Bot\\\\/", "serpstatbot\\\\/", "MixnodeCache\\\\/", "^curl", "SimpleScraper", "RSSingBot", "Jooblebot", "fedoraplanet", "Friendica", "NextCloud", "Tiny Tiny RSS", "RegionStuttgartBot", "Bytespider", "Datanyze", "Google-Site-Verification", "TrendsmapResolver", "tweetedtimes", "NTENTbot", "Gwene", "SimplePie", "SearchAtlas", "Superfeedr", "feedbot", "UT-Dorkbot", "Amazonbot", "AmazonProductDiscovery", "AmazonSellerInitiatedListing", "SerendeputyBot", "Eyeotabot", "officestorebot", "Neticle Crawler", "SurdotlyBot", "LinkisBot", "AwarioSmartBot", "AwarioRssBot", "RyteBot", "FreeWebMonitoring SiteChecker", "AspiegelBot", "NAVER Blog Rssbot", "zenback bot", "SentiBot", "Domains Project\\\\/", "Pandalytics", "VKRobot", "bidswitchbot", "tigerbot", "NIXStatsbot", "Atom Feed Robot", "[Cc]urebot", "PagePeeker\\\\/", "Vigil\\\\/", "rssbot\\\\/", "startmebot\\\\/", "JobboerseBot", "seewithkids", "NINJA bot", "Cutbot", "BublupBot", "BrandONbot", "RidderBot", "Taboolabot", "Dubbotbot", "FindITAnswersbot", "infoobot", "Refindbot", "BlogTraffic\\\\/\\\\d\\\\.\\\\d+ Feed-Fetcher", "SeobilityBot", "Cincraw", "Dragonbot", "VoluumDSP-content-bot", "FreshRSS", "BitBot", "^PHP-Curl-Class", "Google-Certificates-Bridge", "centurybot", "Viber", "e\\\\.ventures Investment Crawler", "evc-batch", "PetalBot", "virustotal", "(^| )PTST\\\\/", "minicrawler", "Cookiebot", "trovitBot", "seostar\\\\.co", "IonCrawl", "Uptime-Kuma", "Seekport", "FreshpingBot", "Feedbin", "CriteoBot", "Snap URL Preview Service", "Better Uptime Bot", "RuxitSynthetic", "Google-Read-Aloud", "Valve\\\\/Steam", "OdklBot\\\\/", "GPTBot", "ChatGPT-User", "OAI-SearchBot", "YandexRenderResourcesBot\\\\/", "LightspeedSystemsCrawler", "ev-crawler\\\\/", "BitSightBot\\\\/", "woorankreview\\\\/", "Google-Safety", "AwarioBot", "DataForSeoBot", "Linespider", "WellKnownBot", "A Patent Crawler", "StractBot", "search\\\\.marginalia\\\\.nu", "YouBot", "Nicecrawler", "Neevabot", "BrightEdge Crawler", "SiteCheckerBotCrawler", "TombaPublicWebCrawler", "CrawlyProjectCrawler", "KomodiaBot", "KStandBot", "CISPA Webcrawler", "MTRobot", "hyscore\\\\.io", "AlexandriaOrgBot", "2ip bot", "Yellowbrandprotectionbot", "SEOlizer", "vuhuvBot", "INETDEX-BOT", "Synapse", "t3versionsBot", "deepnoc", "Cocolyzebot", "hypestat", "ReverseEngineeringBot", "sempi\\\\.tech", "Iframely", "MetaInspector", "node-fetch", "l9explore", "python-opengraph", "OpenGra
1phCheck", "developers\\\\.google\\\\.com\\\\/\\\\+\\\\/web\\\\/snippet", "SenutoBot", "MaCoCu", "NewsBlur", "inoreader", "NetSystemsResearch", "PageThing", "WordPress\\\\/", "PhxBot", "ImagesiftBot", "Expanse", "InternetMeasurement", "^BW\\\\/", "GeedoBot", "Audisto Crawler", "PerplexityBot\\\\/", "[cC]laude[bB]ot", "Monsidobot", "GroupMeBot", "Vercelbot", "vercel-screenshot", "facebookcatalog\\\\/", "meta-externalads\\\\/", "meta-externalagent\\\\/", "meta-externalfetcher\\\\/", "AcademicBotRTU", "KeybaseBot", "Lemmy", "CookieHubScan", "Hydrozen\\\\.io", "HTTP Banner Detection", "SummalyBot", "MicrosoftPreview\\\\/", "GeedoProductSearch", "TikTokSpider", "OnCrawl\\\\/", "sindresorhus\\\\/got", "CensysInspect\\\\/", "SBIntuitionsBot\\\\/", "sitebulb", "YextBot\\\\/", "DatadogSynthetics", "Google-Ads-Conversions", "ObservePoint", "Checkly", "ALittle Client", "AliyunSecBot", "Claude-Web", "anthropic-ai", "Claude-User", "Claude-SearchBot", "Google-Extended", "cohere-ai", "Timpibot", "SERankingBacklinksBot", "CMSChecker", "Wayback", "Playwright", "Puppeteer", "Selenium", "Nikto", "sqlmap", "ZmEu", "masscan", "WPScan", "[aA]cunetix", "Nessus", "[dD]ir[Bb]uster", "StatusCake", "colly", "[mM]echanize", "air\\\\.ai\\\\/scanning", "asnriskscorer", "OICrawler", "l9scan", "SlaccaleBot", "CustomAsyncHttpClient", "^HTTPie\\\\/", "Gemini-Deep-Research", "Perplexity-User", "PerplexityUser", "meta-webindexer", "DuckAssistBot", "MistralAI-User", "webzio", "newsai\\\\/", "^ArenaUnfurlBot", "A360-Search", "AASA-Bot", "AccessStatus", "Acquia optimize", "ActiveComply", "AdkernelTopicCrawler", "AlertSite", "AllAfrica", "Amazing-SearchBot", "Amazon-Bedrock-AgentCore-Browser", "AmazonBuyForMe", "Amzn-SearchBot", "Amzn-User", "Anchor Browser", "Anomura", "AP3A\\\\.240617\\\\.008", "ApifyBot", "ApifyWebsiteContentCrawler", "Archive-It", "artemis web reader", "atlassian-bot", "Attracta", "AudigentAdBot", "Authory", "Automaton|Newsify Feed Fetcher", "AwarioRendererBot", "AzureAI-SearchBot", "BestChange", "bigsur\\\\.ai", "bl\\\\.uk_lddc_bot", "BlingERP", "Blockaid", "Bloglines", "BlogVault", "bluesky-domain-status-classifier", "Bluesky\\\\/", "bne\\\\.es_bot", "Brightbot", "BrowserBot-Observer", "BufferLinkPreviewBot", "Bugsnag", "Buttondown", "CapitalOneBot", "CertChief", "channable", "Channel3Bot", "Chirp|gotosocial", "ClickUpLinkUnfurler", "Cloudflare-AutoRAG", "Cloudflare-Custom-Hostname-Verification", "Cloudflare-Stream-Webhook", "CloudflareRadarURLScanner", "Cloudtrellis", "[cC]ludo", "Code\\\\/1\\\\.", "Collapsify", "ContextualBot[\\\\s\\\\S]*outcomes\\\\.net", "Convermax", "cookie-maestro", "CookieHubVerify", "CookieYesbot", "Crazy Egg", "Current[\\\\s\\\\S]*RSS Reader", "cypex\\\\.ai\\\\/scanning", "DeepCrawl", "DigiCert DCV", "dlvr\\\\.it", "Dotcom-Monitor", "DrataAutopilot", "DreamHost Data Team", "ds9", " DVbot", "EcoVadisSustainabilityBot", "elmah\\\\.io Uptime Monitoring", "EvernoteRichLinkBot", "EzLynx", "EzoicBot", "FacebookBot", "FastDAST", "Feeder \\\\/", "FeedFlow", "FindFiles\\\\.net", "FirecrawlAgent", "FyndSearchEngine-Crawler", "FyndSearchEngine-ReCrawler", "Goodreads", "Google Trust Services", "Google-Agent", "Google-Gemini-CLI", "Google-NotebookLM", "GoogleAgent-Mariner", "Greppr Web Crawler", "Hardenize", "HoneybadgerBot", "IbouBot", "imageSpider", "Innologica", "kagi-fetcher", "Kangaroo Bot", "Known Agent", "KrawlerBot", "laion-huggingface-processor", "LinkCheckerBot", "LinkupBot", "LMArenaUnfurlBot", "lyonl-asset-proxy", "lyonl-crawler", "MagiBot", "MagpieRSS", "mail\\\\.ru", "MailChimp", "Manus-User", "McontextualBot", "Mediumbot-MetaTagFetcher", "MetaIAB Facebook", "MixrankBot", "ModernizeBot", "MontasticMonitor", "NanoInteractive", "NestDaddybot", "Netcraft SSL Server Survey", "Netcraft Web Server Survey", "NetSeer crawler", "Netumo|netumo", "NewRelicSynthetics", "NewsRoom\\\\.BI", "Nitro-", "NitroBot", "Noibu", "NostoCrawlerBot", "OneTrust", "opencode-smartfetch", ";Owler", "ParselySharesBot", "PhindBot", "PodchaserParser", "Podimo", "Poggio-Citations", "productsup\\\\.io\\\\/crawler", "qcbot", "Qualys", "Quora-Bot", "Qwantbot", "Qwarrybot", "RSiteAuditor", "RSS\\\\.Social", "Salesforce\\\\.com", "Scope3", "scraping@nytimes\\\\.com", "Scrubby", "Scrunchbot", "seo4ajax\\\\.com", "SequelWP", "ServerDensity", "ShapBot", "ShortPixel", "Silktide", "SiteLock", "SmarshBot", "SMTnetPMBot", "Software-Security-Research", "SottopopNone", "Spider[\\\\s\\\\
1S]*spider\\\\.com", "Splunk", "StatusNestBacklinkSpider", "stepstoneCrawlBot", "TavilyBot", "ThousandEyes", "Trae\\\\/", "TwinAgent", "uipbot", "um-FC", "um-IC", "UptimeStatistics", "Verispider", "visionheight\\\\.com\\\\/scan", "Watchbot monitoring robot", "Watchful", "weborama-fetcher", "webspidermount", "WepchSearchEngine", "wknd-bot", "WPMU DEV Hub", "WTotem", "XoviOnpageCrawler", "yelpspider", "ZanistaBot", "ZoomInfo-", "7Siters", "Accessible Web Bot", "AtVowBot", "Bibliotheque Nacional de France Crawler", "Bling ERP", "CDSCbot", "Critical CSS Bot", "CybaaBot", "CyberFindCrawler", "Dark Visitor", "Determ", "DNSScanner", "Drupalbot", "eMoney Advisor", "everyfeed-spider", "ExteContextCrawl", "FediDB", "FediIndex", "FediList Agent", "Fedineko", "FedReporter Bot for FFIEC", "Feedsearch Bot", "Feedsearch-Crawler", "fiperbot", "FleebsBot", "Fluid", "Flyriverbot", "Freshbot", "Gaisbot", "GenomeCrawlerd", "HaloBot", "IRLbot", "kaikki\\\\.org-digital-archive", "kb\\\\.dk_bot", "Library Of Congress Web Archiving", "MagnetmeBot", "MatchorySearch", "Minoru\'s Fediverse Crawler", "MirrorWebCrawler", "mithril-crawler", "ModatScanner", "NapBot", "New York Times Newsgathering", "NLUX_IAHarvester", "NoahBot", "PlagAwareBot", "Rakuten Image extraction bot", "ResearchBot", "rss-is-dead\\\\.lol web bot", "seoLyt", "SirdataBot", "SitesOverPagesBot", "SleepBot", "Sosospider", "Termly", "TLS tester", "trafilatura", "UrlBeeBot", "videootv Bot", "vmcrawl", "WadooBot", "Website-info\\\\.net-Robot", "WebZIP", "WikiDo", "WOVN Crawler", "YoudaoBot", "ZyBorg", "Aranet-SearchBot", "crawl4ai", "DeepSeekBot", "iaskspider", "KunatoCrawler", "TerraCotta", "ABEvalBot", "blekkobot", "br-crawler", "BuddyBot", "CapterraBot", "carbon-umbrella-bot", "caveman-hunter", "Centro Ads\\\\.txt Crawler", "WISEbot", "CodaBot", "Corporama matcher", "CyotekWebCopy", "Datadog Agent", "Dazzle BlueSky Bot", "DominicBot", "Dow Jones Searchbot", "Download Ninja", "EmailWolf", "fedistatsCrawler", "GoParserBot", "gsa-crawler", "HanaleiBot", "NicheIndex", "HeadOnlyScraper", "HenkBot", "Impact\\\\.com Agent", "Keydrop\\\\.io", "larbin", "SENTINEL-LinkCheck", "linko", "LinkpadBot", "lwp-trivial", "Magus Bot", "NaverBot", "loopimprovements\\\\.com", "OpenTheBoxBot", "OWLer-W", "peer39_crawler", "Pixalate\\\\.com", "Poduptime", "Pomothy-Bot", "PulsePoint-Crawler", "rawweb-bot", "semantic-visions", "Sindup", "SiteSucker", "SpringserveBot", "SQWatcher", "Supabase Paired Crawler", "sv-watchagent", "Swiftbot", "SynthesiBot", "TaraGroup Intelligent Bot", "Thinkbot", "TSMbot", "TSM-turingos", "UGAResearchAgent", "UrlSuMa\\\\.de crawler", "WanscannerBot", "WebCapture", "WebCopier", "cognitiveseo\\\\.com", "Xing Bot", "XML Sitemaps Generator", "YandoriRSSBot", "Zealbot", "008\\\\/", "monitoring360bot\\\\/", "AdagioBot", "adbeat\\\\.com", "AdminLabs", "advanced_crawler", "Adventurer", "AGAKIDSBOT", "AgencyAnalyticsBot", "AI2Bot", "AkismetBot", "alexa site audit", "Algolia Crawler", "alienfarm", "allOrigins", "AmazonAdBot", "KendraBot", "AppSiteAssociation", "Aragog\\\\/", "Aranea", "ArchiveBox", "ArquivoBot", "Arquivo-web-crawler", "ArtemisBot", "Asana\\\\/", "AudistoBot", "Autoconfig Test from USTC", "tracking-quality-spider", "Bad Neighborhood Header Detector", "BaiduAdsBot", "BDBot\\\\/", "BeeperBot", "BetterUptimeBot", "BnFBot", "BigUpDataBot", "BinaryCanary", "Bitbucket-Webhooks", "bl\\\\.uk_ldfc_bot", "BlackDuck-FD", "Blogtrottr", "BlueskyPreviewBot", "BoardGamePricesBot", "BotPoke", "BDFetch", "Brandwatch", "BraveBot", "brokenlinkcheck\\\\.com", "BW\\\\/", "Bushbaby", "Butterfly", "rss-parser", "CaliberBot", "CapitalOneShopping", "Catchpoint", "centuryb\\\\.o\\\\.t9", "CERT PL", "certytags", "ChargeBeeBot", "Charlotte", "ChatGLM-Spider", "Chatwork LinkPreview", "CheckHost", "Goodzer", "Chrome Privacy Preserving Prefetch Proxy", "CirrusExplorer", "CLASSLA-web", "Clearscopebot", "WorldBot", "Cloudflare-Validator", "cloudflare-csup", "Cloudflare-Custom-Error-Page-Crawler", "Cloudflare-Radar-Scanner", "Cloudflare-SpeedTest", "Cloudflare-Stream-Hook", "cognitiveSEO Bot", "cohere-training-data-crawler", "CommaFeed", "researchscan\\\\.comsys\\\\.rwth-aachen\\\\.de", "contentkingapp", "CookieHub Bot", "Cotoyogi", "Coveobot", "Crawlson", "RepoLookoutBot", "Criticalcss\\\\.com", "cron-job\\\\.org", "DnBCrawler", "DMBrowser", "DomCopBot", "downnotifier\\\\.com", "DowntimeDetector\\\\/", "Dlc\\\\/", "Dratabot", "EasyBib AutoCite", "easybill-ImportManager", "EasyCron\\\\/", "easyDNS Monitoring", "EchoboxBot\\\\/", "Cronless", "crusty\\\\/", "csirt\\\\.cz", "CXK_Bot", "daumoa", "DaspeedBot", "Dead Link Checker", "De
1skyobot", "Detectify", "Devin", "DF Bot", "DingTalkBot-LinkService", "Discourse Forum Onebox", "Dmbot", "SustainabilityCrawler", "edansbot", "EdgeWatch", "Do Not Track Verifier", "elmahio-uptimebot", "eMoneyBot", "EpivozCrawler", "eRepublik\\\\.tools", "EvoUptimeBot", "ExodusMovement", "Ezgif", "factset_spyderbot", "FastmailUA", "FDL Stats Bot", "Fedicabot", "FedReporterDataBot", "Feed Image Audit", "FeedBurner", "feeder\\\\.co", "Feedpresso Content Index Bot", "Feedwind", "fidget-spinner-bot", "FirmoGraph", "FlipboardRSS", "Foregenix", "Freespoke\\\\/", "Friendly testing bot", "friendly-spider", "FriendlyCrawler\\\\/", "FullStoryBot\\\\/", "Funnelback", "FuseonBot\\\\/", "Gabanzabot\\\\/", "gdnplus\\\\.com", "getthit\\\\.com", "GG PeekBot", "Ghost Inspector", "github-camo", "GlobalWebSearch", "Golfe\\\\/", "Google-Apps-Script", "GoogleStackdriverMonitoring", "GoogleAssociationService\\\\/", "GoogleImageProxy", "GoogleProducer", "Googlebot-IA\\\\/", "Google-Trust-Services\\\\/", "Google-Area120", "Google-CloudVertexBot", "GoogleAssociationService$", "GoogleDocs", "GoPay", "GotSiteMonitor\\\\.com", "synthetic-monitoring-agent\\\\/", "Grammarly\\\\/", "gregcrawler", "GroovinaAdsbot\\\\/", "Grover\\\\/", "GTmetrix", "GuestpostsBot\\\\/", "Gulper Web Bot", "Verity\\\\/", "HappyWing", "harsilbot\\\\/", "HawaiiBot", "hCardValidator", "Hello World", "HelloworkJobPostingBot\\\\/", "HetrixTools", "HIFIBot\\\\/", "Hlidam\\\\.to robot", "Honeybadger Uptime Check", "HostTracker\\\\/", "Hotjar", "hstspreload-bot", "Huckabot\\\\/", "Hype Machine\\\\/", "Web Screen Service By hyperhost", "AdsBot-IAB", "iAskBot\\\\/", "IBM Crawler", "IFTTT\\\\/", "ImageFetcher\\\\/", "ImageMind", "img2dataset", "imgproxy\\\\/", "impendoom-bot\\\\/", "IndeedJobBot", "Innguma\\\\/", "Instapaper\\\\/", "Integromat\\\\/", "intelx\\\\.io_bot", "internetVista monitor", "Irokez\\\\.cz monitoring", "IsDownBot\\\\/", "ISSCyberRiskCrawler\\\\/", "iubenda-radar\\\\/", "UptimeBot\\\\/", "jetmon\\\\/", "jobswithgptcom-bot", "Jumio", "Kagibot\\\\/", "KangarooBot\\\\/", "KargoBot-Artemis", "kazbtbot\\\\/", "keycdn-tools\\\\/", "keys-so-bot", "kinsta-bot", "Klaviyo\\\\/", "Kukei\\\\.eu-Bot\\\\/", "LAC_IAHarvester", "LastModBot\\\\/", "LegalMonster", "Let\'s Encrypt", "Level9SearchBot\\\\/", "loc\\\\.gov\\\\/programs\\\\/web-archiving", "LinerBot\\\\/", "LinkTiger", "LinkAce\\\\/", "LinksIndexerBot\\\\/", "LinkWalker\\\\/", "LogicMonitor", "LoomlyBot", "Macrobondbot", "MADBbot\\\\/", "Magellan", "magicsearchdev\\\\/", "Magnet\\\\.me-web\\\\/", "MainWP\\\\/", "Make\\\\/", "ManageWP", "MarketGoo\\\\/", "MarketingMiner", "dbot\\\\)", "Mattermost-Bot\\\\/", "Mavifinds", "MB-LinkChecker", "MedialogiaBot", "MediaMonitoringBot\\\\/", "MediavineMetadataParser\\\\/", "Pywikibot\\\\/", "CentComBot\\\\/", "MergadoBot", "Meta-ExternalHit\\\\/", "Metorik", "MgidBot", "Miniature\\\\.io\\\\/", "mirrorweb\\\\.com", "MissinglettrBot\\\\/", "crawler_eb_germany", "ModularConnector\\\\/", "Mollie HTTP client", "Monibot", "monitis -", "MonitoRSS\\\\/", "MonSpark\\\\/", "montastic-monitor", "MonTools\\\\.com", "MotoMinerBot\\\\/", "MRGbot\\\\/", "MxToolbox", "my-tiny-bot", "MyBot\\\\/", "nbertaupete95", "NetAPI", "NetpeakCheckerBot\\\\/", "NetShelter ContentScan", "NETVIGIE", "NewRelicbot\\\\/", "nyt_scraping", "NewsNow\\\\/", "NLNZ_IAHarvester", "NodePing", "nomore404\\\\.com robot", "noorobot", "Nooshub\\\\/", "Notabot", "Novaact\\\\/", "Novellum", "NsToolsBot\\\\/", "nvdorz", "Odin;", "Offline Explorer", "OhDear\\\\/", "Omnisend\\\\/", "Online Domain Tools", "WebCEO Online\\\\/", "OnlineOrNot\\\\.com_bot", "OpenGraph\\\\.io\\\\/", "OpenRSS", "OpenVAS", "Owler \\\\(ows\\\\.eu", "Operator\\\\/", "Orbbot\\\\/", "zebra-v2-bot", "Orlo-LinkPreview\\\\/", "Cozi-iCalendar-FeedReader", "OutsellURLValidator", "Overcast\\\\/", "PRTGCloudBot\\\\/", "Pagespeed\\\\/", "PanguBot", "Panopta", "Paqlebot\\\\/", "parse\\\\.ly scraper\\\\/", "PayPal\\\\/", "PDF24 URL To PDF", "PingAdmin\\\\.Ru\\\\/", "pingping\\\\.io\\\\/", "PlayStore-Google", "Plesk screenshot bot", "PocketCasts\\\\/", "Potions\\\\/", "PressEngineBot", "PricedroneShoppingBot\\\\/", "PriEcoBot\\\\/", "PrintFriendly\\\\.com", "Pro-Sitemaps\\\\/", "ProbelySPDR\\\\/", "ProjectShield-UrlCheck", "Blackbox Exporter\\\\/", "Protopage\\\\/", "PS_Daily\\\\/", "pulsetic\\\\.com", "PWABuilderHttpAgent", "QualifiedBot\\\\/", "Quantcastbot\\\\/", "Rackspace Monitoring\\\\/", "rakutenusabot-image\\\\/", "top100\\\\.rambler\\\\.ru crawler", "RankurBot\\\\/", "RavenCrawler\\\\/", "Readable\\\\/", "Recurly Webhooks\\\\/", "RED\\\\/", "Reelevant\\\\/", "remove\\\\.bg\\\\/", "Retool\\\\/", "RetroListeCOM\\\\/", "RevvimGort\\\\/", "reward-gateway", "Riddler \\\\(http:\\\\/\\\\/riddler\\\\.io", "RobotsChecker\\\\/", "RSSAPI\\\\/", "rss2tg", "RssReaderBot", "s4a-probe-bot\\\\/", "SFDC-Callout\\\\/", "page-preview-tool", "SandobaCrawler\\\\/", "Sansec Security Monitor\\\\/", "GIFTEDVISITOR SCAN", "Schema-Markup-Validator", "Scoop\\\\.it\\\\/", "ScourRSSBot\\\\/", "ScrapeheroBot\\\\/", "screeenly-bot", "SEBot-WA", "Searcherweb", "Searcherxweb", "SearchExpress", "SecurityHeaders", "semaltbot\\\\/", "SendGrid Event API", "SentryUptimeBot\\\\/", "seo-audit-check-bot\\\\/", "s4a\\\\/", "ClarityBot\\\\/", "SeoSiteCheckup", "SeoulBot", "SERPtimizerBot", "Server Density Service Monitoring", "ServerHunterSpider\\\\/", "SeznamHomepageCrawler\\\\/", "Shopify-Captain-Hook", "Shortwave Image Fetcher", "linkReader\\\\/", "Sidetrade indexer bot", "^Silk\\\\/", "SinceraSyntheticUser\\\\/", "Optimizer\\\\)", "Site24x7", "SiteAuditBot\\\\/", "SiteCheck-sitecrawl", "SiteScoreBot", "SiteSearch360\\\\/", "SiteUptime\\\\.com", "Konturbot\\\\/", "SkroutzBot", "SkyworkSpider", "SlickBot\\\\/", "SmartologyBot\\\\/", "SnapURLPreview\\\\/", "SnapchatAds\\\\/", "Snipcart\\\\/", "solarwinds\\\\/", "Sora POS\\\\/", "SparkShipping", "SparkPost", "Spawning-AI", "IDG\\\\/EU", "Specificfeeds", "Spectate\\\\/", "SpiderLing", "splash Version\\\\/", "Rigor\\\\)", "TwinWaveScanner", "SSL Labs \\\\(https:\\\\/\\\\/www\\\\.ssllabs\\\\.com", "SSSSBot\\\\/", "Stape\\\\/", "StartpagePrivateImageProxy\\\\/", "Statabot\\\\/", "StatistikAustria\\\\/", "StatsDroneBot", "Stripe\\\\/", "Sucuri", "Svix-Webhooks\\\\/", "SwifteqLinkChecker", "Swisscows", "Datadog Synthetic", "TactiScout\\\\/", "tchelebi\\\\/", "bitdiscovery", "Test Certificate Info", "Testcrawler", "test-bot", "TestLocally\\\\/", "TestURI", "TextRazor", "The Knowledge AI", "TheInternetSearchx", "thesis-research-bot", "Trellis-Services", "trentwil\\\\.es", "Trustly\\\\/", "TTD-Content", "Tweakers", "TwilioProxy\\\\/", "UASlinkChecker\\\\/", "hgfAlphaXCrawl\\\\/", "Unshorten\\\\.It\\\\!", "updown\\\\.io", "Uptime\\\\/", "uptimedoctor", "Uptimia", "uptrends", "Urlcheckr\\\\/", "URLSuMaBot", "useeBookChecker\\\\/", "Vagabondo\\\\/", "VaultPress", "videootvBot", "VsuSearchSpider\\\\/", "vu-server-health-scanner\\\\/", "WARDBot\\\\/", "WebsiteOps", "WatchMouse", "Web Measure\\\\/", "Webflow", "webgains-bot", "webprosbot\\\\/", "websitepulse", "WebSniffer\\\\/", "WSM\\\\/", "WebwikiBot\\\\/", "WEDOS OnLine", "WhatsMyIP\\\\.org", "WhatWeb\\\\/", "Wheregoes\\\\.com", "wheresitup\\\\.com\\\\/", "Citoid", "WireReaderBot\\\\/", "ZoteroTranslationServer\\\\/WMF", "wmtips\\\\.com\\\\/", "WordCountBot\\\\/", "Wordup-1", "workona-favicon-service\\\\/", "Indy Library", "WJHRO\\\\/", "WormlyBot", "WovnCrawler\\\\/", "wowLink Crawler\\\\/", "WP Time Capsule", "WPUmbrella", "wpbot\\\\/", "WPMU DEV Broken Link Checker", "WPMUDEV Uptime Monitor", "WPSec\\\\/", "WRTNBot", "abuse\\\\.xmco\\\\.fr", "XY-Archive-Compliance", "Yahoo Ad monitoring", "YahooMailProxy", "YahooCacheSystem", "YLT Chrome", "YokoyGroupAG\\\\/", "Yuuperbot", "Zapier", "Zendesk Webhook", "Zombiebot\\\\/", "zzhbot", "Penthouse Critical Path CSS Generator", "Google-AdWords-Express", "Notion\\\\/", "SSL Labs$", "Skroutz ImageBot", "Tumblr\\\\/", "upday\\\\/", "watchTowr", "PRTG Network Monitor", "GeedoShopProductFinder"];//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ib3QtcGF0dGVybnMuZ2VuZXJhdGVkLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZm9yZWlnbnBvbGljeS1idWlsZC8uLi9hc3NldHMvc3JjL3NjcmlwdHMvcnVkZGVyL2JvdC1wYXR0
1ZXJucy5nZW5lcmF0ZWQuanM/YWRjMCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSAqL1xuLy8gQVVUTy1HRU5FUkFURUQg4oCUIGRvIG5vdCBlZGl0IGJ5IGhhbmQuXG4vLyBTb3VyY2U6IGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9tb25wZXJydXMvY3Jhd2xlci11c2VyLWFnZW50cy9tYXN0ZXIvY3Jhd2xlci11c2VyLWFnZW50cy5qc29uXG4vLyBSZWdlbmVyYXRlZCBieSBidWlsZC9zY3JpcHRzL2ZldGNoLWJvdC1wYXR0ZXJucy5qcyBkdXJpbmcgcHJvZHVjdGlvbiBidWlsZHMuXG4vLyBDb21taXQgdGhpcyBmaWxlIOKAlCBpdCdzIHRoZSBvZmZsaW5lIGZhbGxiYWNrIGFuZCBsZXRzIGRldiBidWlsZHMgc2tpcCB0aGUgZmV0Y2guXG4vLyBlc2xpbnQtZGlzYWJsZSBhdCB0b3AgcHJldmVudHMgYG5wbSBydW4gd2F0Y2ggLS1maXhqc2AgKGF1dG9maXgpIGZyb21cbi8vIHRvdWNoaW5nIHRoZSBmb3JtYXR0aW5nIG9uIGV2ZXJ5IHJ1bjsgYWxzbyBsaXN0ZWQgaW4gYnVpbGQvLmVzbGludHJjLmpzXG4vLyBpZ25vcmVQYXR0ZXJucyBhcyBiZWx0LWFuZC1zdXNwZW5kZXJzLlxuXG5leHBvcnQgY29uc3QgQ1JBV0xFUl9QQVRURVJOUyA9IFtcblx0XCJHb29nbGVib3RcXFxcL1wiLFxuXHRcIkdvb2dsZWJvdC1Nb2JpbGVcIixcblx0XCJHb29nbGVib3QtSW1hZ2VcIixcblx0XCJHb29nbGVib3QtTmV3c1wiLFxuXHRcIkdvb2dsZWJvdC1WaWRlb1wiLFxuXHRcIkFkc0JvdC1Hb29nbGUoW14tXXwkKVwiLFxuXHRcIkFkc0JvdC1Hb29nbGUtTW9iaWxlXCIsXG5cdFwiRmVlZGZldGNoZXItR29vZ2xlXCIsXG5cdFwiTWVkaWFwYXJ0bmVycy1Hb29nbGVcIixcblx0XCJNZWRpYXBhcnRuZXJzIFxcXFwoR29vZ2xlYm90XFxcXClcIixcblx0XCJBUElzLUdvb2dsZVwiLFxuXHRcIkdvb2dsZS1JbnNwZWN0aW9uVG9vbFwiLFxuXHRcIlN0b3JlYm90LUdvb2dsZVwiLFxuXHRcIkdvb2dsZU90aGVyXCIsXG5cdFwiYmluZ2JvdFwiLFxuXHRcIlNsdXJwXCIsXG5cdFwiW3dXXWdldFwiLFxuXHRcIkxpbmtlZEluQm90XCIsXG5cdFwiUHl0aG9uLXVybGxpYlwiLFxuXHRcInB5dGhvbi1yZXF1ZXN0c1wiLFxuXHRcImFpb2h0dHBcIixcblx0XCJodHRweFwiLFxuXHRcImxpYnd3dy1wZXJsXCIsXG5cdFwiaHR0cHVuaXRcIixcblx0XCJOdXRjaFwiLFxuXHRcIkdvLWh0dHAtY2xpZW50XCIsXG5cdFwicGhwY3Jhd2xcIixcblx0XCJtc25ib3RcIixcblx0XCJqeXhvYm90XCIsXG5cdFwiRkFTVC1XZWJDcmF3bGVyXCIsXG5cdFwiRkFTVCBFbnRlcnByaXNlIENyYXdsZXJcIixcblx0XCJCSUdMT1RST05cIixcblx0XCJUZW9tYVwiLFxuXHRcImNvbnZlcmFcIixcblx0XCJeU2Vla2JvdFwiLFxuXHRcIkdpZ2Fib3RcIixcblx0XCJHaWdhYmxhc3RcIixcblx0XCJleGFib3RcIixcblx0XCJpYV9hcmNoaXZlclwiLFxuXHRcIkdpbmdlckNyYXdsZXJcIixcblx0XCJ3ZWJtb24gXCIsXG5cdFwiSFRUcmFja1wiLFxuXHRcImdydWJcXFxcLm9yZ1wiLFxuXHRcIlVzaW5lTm91dmVsbGVDcmF3bGVyXCIsXG5cdFwiYW50aWJvdFwiLFxuXHRcIm5ldHJlc2VhcmNoc2VydmVyXCIsXG5cdFwic3BlZWR5XCIsXG5cdFwiZmx1ZmZ5XCIsXG5cdFwiZmluZGxpbmtcIixcblx0XCJtc3Jib3RcIixcblx0XCJwYW5zY2llbnRcIixcblx0XCJ5YWN5Ym90XCIsXG5cdFwiQUlTZWFyY2hCb3RcIixcblx0XCJpcHMtYWdlbnRcIixcblx0XCJ0YWdvb2JvdFwiLFxuXHRcIk1KMTJib3RcIixcblx0XCJ3b3Jpb2JvdFwiLFxuXHRcInlhbmdhXCIsXG5cdFwiYnV6emJvdFwiLFxuXHRcIm1sYm90XCIsXG5cdFwieWFuZGV4XFxcXC5jb21cXFxcL2JvdHNcIixcblx0XCJwdXJlYm90XCIsXG5cdFwiTGluZ3VlZSBCb3RcIixcblx0XCJDeWJlclBhdHJvbFwiLFxuXHRcInZvaWxhYm90XCIsXG5cdFwiQmFpZHVzcGlkZXJcIixcblx0XCJjaXRlc2Vlcnhib3RcIixcblx0XCJzcGJvdFwiLFxuXHRcInR3ZW5nYWJvdFwiLFxuXHRcInBvc3RyYW5rXCIsXG5cdFwiVHVybml0aW5cIixcblx0XCJzY3JpYmRib3RcIixcblx0XCJwYWdlMnJzc1wiLFxuXHRcInNpdGVib3RcIixcblx0XCJsaW5rZGV4XCIsXG5cdFwiQWRpZHhib3RcIixcblx0XCJlem9vbXNcIixcblx0XCJkb3Rib3RcIixcblx0XCJNYWlsXFxcXC5SVV9Cb3RcIixcblx0XCJkaXNjb2JvdFwiLFxuXHRcImhlcml0cml4XCIsXG5cdFwiZmluZHRoYXRmaWxlXCIsXG5cdFwiZXVyb3BhcmNoaXZlXFxcXC5vcmdcIixcblx0XCJOZXJkQnlOYXR1cmVcXFxcLkJvdFwiLFxuXHRcIihzaXN0cml4fFNJU1RSSVgpIFtjQ11yYXdsZXJcIixcblx0XCJBaHJlZnMoQm90fFNpdGVBdWRpdClcIixcblx0XCJmdWVsYm90XCIsXG5cdFwiXkNydW5jaEJvdFwiLFxuXHRcIkluZGVlZEJvdFwiLFxuXHRcIm1hcHB5ZGF0YVwiLFxuXHRcIndvb2JvdFwiLFxuXHRcIlpvb21pbmZvQm90XCIsXG5cdFwiUHJpdmFjeUF3YXJlQm90XCIsXG5cdFwiTXVsdGl2aWV3Ym90XCIsXG5cdFwiU1dJTUdCb3RcIixcblx0XCJHcm9iYm90XCIsXG5cdFwiZXJpZ2h0XCIsXG5cdFwiQXBlcmNpdGVcIixcblx0XCJzZW1hbnRpY2JvdFwiLFxuXHRcIkFib3VuZGV4XCIsXG5cdFwiZG9tYWluY3Jhd2xlclwiLFxuXHRcIndic2VhcmNoYm90XCIsXG5cdFwic3VtbWlmeVwiLFxuXHRcIkNDQm90XCIsXG5cdFwiZWRpc3RlcmJvdFwiLFxuXHRcIlNlem5hbUJvdFwiLFxuXHRcImVjMmxpbmtmaW5kZXJcIixcblx0XCJnc2xmYm90XCIsXG5cdFwiYWlIaXRCb3RcIixcblx0XCJpbnRlbGl1bV9ib3RcIixcblx0XCJmYWNlYm9va2V4dGVybmFsaGl0XCIsXG5cdFwiWWV0aVwiLFxuXHRcIlJldHJldm9QYWdlQW5hbHl6ZXJcIixcblx0XCJsYi1zcGlkZXJcIixcblx0XCJTb2dvdVwiLFxuXHRcImxzc2JvdFwiLFxuXHRcImNhcmVlcmJvdFwiLFxuXHRcIndvdGJveFwiLFxuXHRcIndvY2JvdFwiLFxuXHRcImljaGlyb1wiLFxuXHRcIkR1Y2tEdWNrQm90XCIsXG5cdFwibHNzcm9ja2V0Y3Jhd2xlclwiLFxuXHRcImRydXBhY3RcIixcblx0XCJ3ZWJjb21wYW55Y3Jhd2xlclwiLFxuXHRcImFjb29uYm90XCIsXG5cdFwib3BlbmluZGV4c3BpZGVyXCIsXG5cdFwiZ25hbSBnbmFtIHNwaWRlclwiLFxuXHRcIndlYi1hcmNoaXZlLW5ldFxcXFwuY29tXFxcXC5ib3RcIixcblx0XCJiYWNrbGlua2NyYXdsZXJcIixcblx0XCJjb2Njb2NcIixcblx0XCJpbnRlZ3JvbWVkYlwiLFxuXHRcImNvbnRlbnQgY3Jhd2xlciBzcGlkZXJcIixcblx0XCJ0b3BsaXN0Ym90XCIsXG5cdFwiaXQybWVkaWEtZG9tYWluLWNyYXdsZXJcIixcblx0XCJpcC13ZWItY3Jhd2xlclxcXFwuY29tXCIsXG5cdFwic2l0ZWV4cGxvcmVyXFxcXC5pbmZvXCIsXG5cdFwiZWxpc2Fib3RcIixcblx0XCJwcm94aW1pY1wiLFxuXHRcImNoYW5nZWRldGVjdGlvblwiLFxuXHRcImFyYWJvdFwiLFxuXHRcIldlU0VFOlNlYXJjaFwiLFxuXHRcIm5p
1a2ktYm90XCIsXG5cdFwiQ3J5c3RhbFNlbWFudGljc0JvdFwiLFxuXHRcInJvZ2VyYm90XCIsXG5cdFwiMzYwU3BpZGVyXCIsXG5cdFwicHNib3RcIixcblx0XCJJbnRlcmZheFNjYW5Cb3RcIixcblx0XCJDQyBNZXRhZGF0YSBTY2FwZXJcIixcblx0XCJnMDBnMWVcXFxcLm5ldFwiLFxuXHRcIkdyYXBlc2hvdENyYXdsZXJcIixcblx0XCJ1cmxhcHBlbmRib3RcIixcblx0XCJicmFpbm9ib3RcIixcblx0XCJmci1jcmF3bGVyXCIsXG5cdFwiYmlubGFyXCIsXG5cdFwiU2ltcGxlQ3Jhd2xlclwiLFxuXHRcIlR3aXR0ZXJib3RcIixcblx0XCJjWGVuc2Vib3RcIixcblx0XCJzbXRib3RcIixcblx0XCJibmZcXFxcLmZyX2JvdFwiLFxuXHRcIkE2LUluZGV4ZXJcIixcblx0XCJBRG1hbnRYXCIsXG5cdFwiRmFjZWJvdFwiLFxuXHRcIk9yYW5nZUJvdFxcXFwvXCIsXG5cdFwibWVtb3J5Ym90XCIsXG5cdFwiQWR2Qm90XCIsXG5cdFwiTWVnYUluZGV4XCIsXG5cdFwiU2VtYW50aWNTY2hvbGFyQm90XCIsXG5cdFwibHR4NzFcIixcblx0XCJuZXJkeWJvdFwiLFxuXHRcInhvdmlib3RcIixcblx0XCJCVWJpTkdcIixcblx0XCJRd2FudGlmeVwiLFxuXHRcImFyY2hpdmVcXFxcLm9yZ19ib3RcIixcblx0XCJBcHBsZWJvdFwiLFxuXHRcIlR3ZWV0bWVtZUJvdFwiLFxuXHRcImNyYXdsZXI0alwiLFxuXHRcImZpbmR4Ym90XCIsXG5cdFwiU1tlRV1bbU1dcnVzaEJvdFwiLFxuXHRcInlvb3pCb3RcIixcblx0XCJsaXBwZXJoZXlcIixcblx0XCJZIUpcIixcblx0XCJEb21haW4gUmUtQW5pbWF0b3IgQm90XCIsXG5cdFwiQWRkVGhpc1wiLFxuXHRcIlNjcmVhbWluZyBGcm9nIFNFTyBTcGlkZXJcIixcblx0XCJNZXRhVVJJXCIsXG5cdFwiU2NyYXB5XCIsXG5cdFwiTGl2ZWxhcFtiQl1vdFwiLFxuXHRcIk9wZW5Ib3NlQm90XCIsXG5cdFwiQ2Fwc3VsZUNoZWNrZXJcIixcblx0XCJjb2xsZWN0aW9uQGluZmVneVxcXFwuY29tXCIsXG5cdFwiSXN0ZWxsYUJvdFwiLFxuXHRcIkRldVN1XFxcXC9cIixcblx0XCJiZXRhQm90XCIsXG5cdFwiQ2xpcXpib3RcXFxcL1wiLFxuXHRcIk1vamVla0JvdFxcXFwvXCIsXG5cdFwibmV0RXN0YXRlIE5FIENyYXdsZXJcIixcblx0XCJTYWZlU2VhcmNoIG1pY3JvZGF0YSBjcmF3bGVyXCIsXG5cdFwiR2x1dGVuIEZyZWUgQ3Jhd2xlclxcXFwvXCIsXG5cdFwiU29uaWNcIixcblx0XCJTeXNvbW9zXCIsXG5cdFwiVHJvdmVcIixcblx0XCJkZWFkbGlua2NoZWNrZXJcIixcblx0XCJTbGFjay1JbWdQcm94eVwiLFxuXHRcIkVtYmVkbHlcIixcblx0XCJSYW5rQWN0aXZlTGlua0JvdFwiLFxuXHRcImlza2FuaWVcIixcblx0XCJTYWZlRE5TQm90XCIsXG5cdFwiU2t5cGVVcmlQcmV2aWV3XCIsXG5cdFwiVmVvb3pib3RcIixcblx0XCJTbGFja2JvdFwiLFxuXHRcInJlZGRpdGJvdFwiLFxuXHRcImRhdGFnbmlvbmJvdFwiLFxuXHRcIkdvb2dsZS1BZHdvcmRzLUluc3RhbnRcIixcblx0XCJhZGJlYXRfYm90XCIsXG5cdFwiV2hhdHNBcHBcIixcblx0XCJjb250eGJvdFwiLFxuXHRcInBpbnRlcmVzdFxcXFwuY29tXFxcXC9ib3RcIixcblx0XCJlbGVjdHJpY21vbmtcIixcblx0XCJHYXJsaWtDcmF3bGVyXCIsXG5cdFwiQmluZ1ByZXZpZXdcXFxcL1wiLFxuXHRcInZlYmlkb29ib3RcIixcblx0XCJGZW10b3NlYXJjaEJvdFwiLFxuXHRcIllhaG9vIExpbmsgUHJldmlld1wiLFxuXHRcIk1ldGFKb2JCb3RcIixcblx0XCJEb21haW5TdGF0c0JvdFwiLFxuXHRcIm1pbmRVcEJvdFwiLFxuXHRcIkRhdW1cXFxcL1wiLFxuXHRcIkp1Z2VuZHNjaHV0enByb2dyYW1tLUNyYXdsZXJcIixcblx0XCJYZW51IExpbmsgU2xldXRoXCIsXG5cdFwiUGNvcmUtSFRUUFwiLFxuXHRcIm1vYXRib3RcIixcblx0XCJLb3NtaW9Cb3RcIixcblx0XCJbcFBdaW5nZG9tXCIsXG5cdFwiQXBwSW5zaWdodHNcIixcblx0XCJQaGFudG9tSlNcIixcblx0XCJHb3dpa2lib3RcIixcblx0XCJQaXBsQm90XCIsXG5cdFwiRGlzY29yZGJvdFwiLFxuXHRcIlRlbGVncmFtQm90XCIsXG5cdFwiSmV0c2xpZGVcIixcblx0XCJuZXdzaGFyZWNvdW50c1wiLFxuXHRcIkphbWVzIEJPVFwiLFxuXHRcIkJhcmtbclJdb3dsZXJcIixcblx0XCJUaW5FeWVcIixcblx0XCJTb2NpYWxSYW5rSU9Cb3RcIixcblx0XCJ0cmVuZGljdGlvbmJvdFwiLFxuXHRcIk9jYXJpbmFib3RcIixcblx0XCJlcGljYm90XCIsXG5cdFwiUHJpbWFsYm90XCIsXG5cdFwiRHVja0R1Y2tHby1GYXZpY29ucy1Cb3RcIixcblx0XCJHbm93aXROZXdzYm90XCIsXG5cdFwiTGVpa2lib3RcIixcblx0XCJMaW5rQXJjaGl2ZXJcIixcblx0XCJZYUtcXFxcL1wiLFxuXHRcIlBhcGVyTGlCb3RcIixcblx0XCJEaWdnIERlZXBlclwiLFxuXHRcIl5kY3Jhd2xcIixcblx0XCJTbmFja3RvcnlcIixcblx0XCJBbmRlcnNQaW5rQm90XCIsXG5cdFwiRnlyZWJvdFwiLFxuXHRcIkV2ZXJ5b25lU29jaWFsQm90XCIsXG5cdFwiTWVkaWF0b29sa2l0Ym90XCIsXG5cdFwiTHVtaW5hdG9yLXJvYm90c1wiLFxuXHRcIkV4dExpbmtzQm90XCIsXG5cdFwiU3VydmV5Qm90XCIsXG5cdFwiTklOR1xcXFwvXCIsXG5cdFwib2todHRwXCIsXG5cdFwiTnV6emVsXCIsXG5cdFwib21naWxpXCIsXG5cdFwiUG9ja2V0UGFyc2VyXCIsXG5cdFwiWWlzb3VTcGlkZXJcIixcblx0XCJ1bS1MTlwiLFxuXHRcIlRvdXRpYW9TcGlkZXJcIixcblx0XCJNdWNrUmFja1wiLFxuXHRcIkphbWllJ3MgU3BpZGVyXCIsXG5cdFwiQUhDXFxcXC9cIixcblx0XCJOZXRjcmFmdFN1cnZleUFnZW50XCIsXG5cdFwiTGFzZXJsaWtlYm90XCIsXG5cdFwiXkFwYWNoZS1IdHRwQ2xpZW50XCIsXG5cdFwiQXBwRW5naW5lLUdvb2dsZVwiLFxuXHRcIkpldHR5XCIsXG5cdFwiVXBmbG93XCIsXG5cdFwiVGhpbmtsYWJcIixcblx0XCJUcmFhY2tyXFxcXC5jb21cIixcblx0XCJUd3VybHlcIixcblx0XCJNYXN0b2RvblwiLFxuXHRcImh0dHBfZ2V0XCIsXG5cdFwiRG55ekJvdFwiLFxuXHRcImJvdGlmeVwiLFxuXHRcIjAwN2FjOSBDcmF3bGVyXCIsXG5cdFwiQmVobG9vbEJvdFwiLFxuXHRcIkJyYW5kVmVyaXR5XCIsXG5cdFwiY2hlY2tfaHR0cFwiLFxuXHRcIkJEQ2JvdFwiLFxuXHRcIlp1bUJvdFwiLFxuXHRcIkVaSURcIixcblx0XCJJQ0MtQ3Jhd2xlclwiLFxuXHRcIkFyY2hpdmVCb3RcIixcblx0XCJeTENDIFwiLFxuXHRcImZpbHRlcmRiXFxcXC5pc3NcXFxcLm5ldFxcXFwvY3Jhd2xlclwiLFxuXHRcIkJMUF9iYm90XCIsXG5cdFwiQm9tYm9yYUJvdFwiLFxuXHRcIkJ1Y2tcXFxcL1wiLFxuXHRcIkNvbXBhbnlib29rLUNyYXdsZXJcIixcblx0XCJHZW5pZW9cIixcblx0XCJtYWdwaWUtY3Jhd2xlclwiLFxuXHRcIk1lbHR3YXRlck5ld3NcIixcblx0XCJNb3Jlb3ZlclwiLFxuXHRcIm5ld3NwYXBlclxcX
1FwvXCIsXG5cdFwiU2NvdXRKZXRcIixcblx0XCIoXnwgKXNlbnRyeVxcXFwvXCIsXG5cdFwiU3RvcnlnaXplQm90XCIsXG5cdFwiVXB0aW1lUm9ib3RcIixcblx0XCJPdXRjbGlja3NCb3RcIixcblx0XCJzZW9zY2FubmVyc1wiLFxuXHRcIkhhdGVuYVwiLFxuXHRcIkdvb2dsZSBXZWIgUHJldmlld1wiLFxuXHRcIk1hdWlCb3RcIixcblx0XCJBbHBoYUJvdFwiLFxuXHRcIlNCTC1CT1RcIixcblx0XCJJQVMgY3Jhd2xlclwiLFxuXHRcImFkc2Nhbm5lclwiLFxuXHRcIk5ldHZpYmVzXCIsXG5cdFwiYWNhcGJvdFwiLFxuXHRcIkJhaWR1LVl1bkd1YW5DZVwiLFxuXHRcImJpdGx5Ym90XCIsXG5cdFwiYmxvZ211cmFCb3RcIixcblx0XCJCb3RcXFxcLkFyYVR1cmthXFxcXC5jb21cIixcblx0XCJib3QtcGdlXFxcXC5jaGxvb2VcXFxcLmNvbVwiLFxuXHRcIkJveGNhckJvdFwiLFxuXHRcIkJUV2ViQ2xpZW50XCIsXG5cdFwiQ29udGV4dEFkIEJvdFwiLFxuXHRcIkRpZ2luY29yZSBib3RcIixcblx0XCJEaXNxdXNcIixcblx0XCJGZWVkbHlcIixcblx0XCJGZXRjaFxcXFwvXCIsXG5cdFwiRmV2ZXJcIixcblx0XCJGbGFtaW5nb19TZWFyY2hFbmdpbmVcIixcblx0XCJGbGlwYm9hcmRQcm94eVwiLFxuXHRcImcycmVhZGVyLWJvdFwiLFxuXHRcIkcyIFdlYiBTZXJ2aWNlc1wiLFxuXHRcImltcmJvdFwiLFxuXHRcIks3TUxXQ0JvdFwiLFxuXHRcIktlbXZpYm90XCIsXG5cdFwiTGFuZGF1LU1lZGlhLVNwaWRlclwiLFxuXHRcImxpbmthcGVkaWFib3RcIixcblx0XCJ2a1NoYXJlXCIsXG5cdFwiU2l0ZWltcHJvdmVcXFxcLmNvbVwiLFxuXHRcIkJMRVhCb3RcXFxcL1wiLFxuXHRcIkRhcmVCb29zdFwiLFxuXHRcIlp1cGVybGlzdEJvdFxcXFwvXCIsXG5cdFwiTWluaWZsdXhcXFxcL1wiLFxuXHRcIkZlZWRzcG90XCIsXG5cdFwiRGlmZmJvdFxcXFwvXCIsXG5cdFwiU0VPa2lja3NcIixcblx0XCJ0cmFjZW15ZmlsZVwiLFxuXHRcIk5pbWJvc3RyYXR1cy1Cb3RcIixcblx0XCJ6Z3JhYlwiLFxuXHRcIlBSLUNZXFxcXC5SVVwiLFxuXHRcIkFkc1R4dENyYXdsZXJcIixcblx0XCJEYXRhZmVlZHdhdGNoXCIsXG5cdFwiWmFiYml4XCIsXG5cdFwiVGFuZ2libGVlQm90XCIsXG5cdFwiZ29vZ2xlLXhyYXdsZXJcIixcblx0XCJheGlvc1wiLFxuXHRcIkFtYXpvbiBDbG91ZEZyb250XCIsXG5cdFwiUHVsc2Vwb2ludCBcIixcblx0XCJDbG91ZEZsYXJlLUFsd2F5c09ubGluZVwiLFxuXHRcIkNsb3VkZmxhcmUtSGVhbHRoY2hlY2tzXCIsXG5cdFwiQ2xvdWRmbGFyZS1UcmFmZmljLU1hbmFnZXJcIixcblx0XCJDbG91ZEZsYXJlLVByZWZldGNoXCIsXG5cdFwiQ2xvdWRmbGFyZS1TU0xEZXRlY3RvclwiLFxuXHRcImh0dHBzOlxcXFwvXFxcXC9kZXZlbG9wZXJzXFxcXC5jbG91ZGZsYXJlXFxcXC5jb21cXFxcL3NlY3VyaXR5LWNlbnRlclxcXFwvXCIsXG5cdFwiR29vZ2xlLVN0cnVjdHVyZWQtRGF0YS1UZXN0aW5nLVRvb2xcIixcblx0XCJXb3JkdXBJbmZvU2VhcmNoXCIsXG5cdFwiV2ViRGF0YVN0YXRzXCIsXG5cdFwiSHR0cFVybENvbm5lY3Rpb25cIixcblx0XCJab29tQm90XCIsXG5cdFwiVmVsZW5QdWJsaWNXZWJDcmF3bGVyXCIsXG5cdFwiTW9vZGxlQm90XCIsXG5cdFwianBnLW5ld3Nib3RcIixcblx0XCJvdXRicmFpblwiLFxuXHRcIlczQ19WYWxpZGF0b3JcIixcblx0XCJWYWxpZGF0b3JcXFxcLm51XCIsXG5cdFwiVzNDLWNoZWNrbGlua1wiLFxuXHRcIlczQy1tb2JpbGVPS1wiLFxuXHRcIlczQ19JMThuLUNoZWNrZXJcIixcblx0XCJGZWVkVmFsaWRhdG9yXCIsXG5cdFwiVzNDX0NTU19WYWxpZGF0b3JcIixcblx0XCJXM0NfVW5pY29yblwiLFxuXHRcIkdvb2dsZS1QaHlzaWNhbFdlYlwiLFxuXHRcIkJsYWNrYm9hcmRcIixcblx0XCJJQ0JvdFxcXFwvXCIsXG5cdFwiQmF6UXV4XCIsXG5cdFwiVHdpbmdseVwiLFxuXHRcIlJpdnZhXCIsXG5cdFwiRXhwZXJpYm90XCIsXG5cdFwiYXdlc29tZWNyYXdsZXJcIixcblx0XCJEYXRhcHJvdmlkZXJcXFxcLmNvbVwiLFxuXHRcIkdyb3VwSGlnaFxcXFwvXCIsXG5cdFwidGhlb2xkcmVhZGVyXFxcXC5jb21cIixcblx0XCJBbnlFdmVudFwiLFxuXHRcIlVwdGltZWJvdFxcXFwub3JnXCIsXG5cdFwiTm1hcCBTY3JpcHRpbmcgRW5naW5lXCIsXG5cdFwiMmlwXFxcXC5ydVwiLFxuXHRcIkNsaWNrYWd5XCIsXG5cdFwiQ2FsaXBlcmJvdFwiLFxuXHRcIk1CQ3Jhd2xlclwiLFxuXHRcIm9ubGluZS13ZWJjZW8tYm90XCIsXG5cdFwiQjJCIEJvdFwiLFxuXHRcIkFkZFNlYXJjaEJvdFwiLFxuXHRcIkdvb2dsZSBGYXZpY29uXCIsXG5cdFwiSHViU3BvdFwiLFxuXHRcIkNocm9tZS1MaWdodGhvdXNlXCIsXG5cdFwiSGVhZGxlc3NDaHJvbWVcIixcblx0XCJDaGVja01hcmtOZXR3b3JrXFxcXC9cIixcblx0XCJ3d3dcXFxcLnVwdGltZVxcXFwuY29tXCIsXG5cdFwiU3RyZWFtbGluZTNCb3RcXFxcL1wiLFxuXHRcInNlcnBzdGF0Ym90XFxcXC9cIixcblx0XCJNaXhub2RlQ2FjaGVcXFxcL1wiLFxuXHRcIl5jdXJsXCIsXG5cdFwiU2ltcGxlU2NyYXBlclwiLFxuXHRcIlJTU2luZ0JvdFwiLFxuXHRcIkpvb2JsZWJvdFwiLFxuXHRcImZlZG9yYXBsYW5ldFwiLFxuXHRcIkZyaWVuZGljYVwiLFxuXHRcIk5leHRDbG91ZFwiLFxuXHRcIlRpbnkgVGlueSBSU1NcIixcblx0XCJSZWdpb25TdHV0dGdhcnRCb3RcIixcblx0XCJCeXRlc3BpZGVyXCIsXG5cdFwiRGF0YW55em
1VcIixcblx0XCJHb29nbGUtU2l0ZS1WZXJpZmljYXRpb25cIixcblx0XCJUcmVuZHNtYXBSZXNvbHZlclwiLFxuXHRcInR3ZWV0ZWR0aW1lc1wiLFxuXHRcIk5URU5UYm90XCIsXG5cdFwiR3dlbmVcIixcblx0XCJTaW1wbGVQaWVcIixcblx0XCJTZWFyY2hBdGxhc1wiLFxuXHRcIlN1cGVyZmVlZHJcIixcblx0XCJmZWVkYm90XCIsXG5cdFwiVVQtRG9ya2JvdFwiLFxuXHRcIkFtYXpvbmJvdFwiLFxuXHRcIkFtYXpvblByb2R1Y3REaXNjb3ZlcnlcIixcblx0XCJBbWF6b25TZWxsZXJJbml0aWF0ZWRMaXN0aW5nXCIsXG5cdFwiU2VyZW5kZXB1dHlCb3RcIixcblx0XCJFeWVvdGFib3RcIixcblx0XCJvZmZpY2VzdG9yZWJvdFwiLFxuXHRcIk5ldGljbGUgQ3Jhd2xlclwiLFxuXHRcIlN1cmRvdGx5Qm90XCIsXG5cdFwiTGlua2lzQm90XCIsXG5cdFwiQXdhcmlvU21hcnRCb3RcIixcblx0XCJBd2FyaW9Sc3NCb3RcIixcblx0XCJSeXRlQm90XCIsXG5cdFwiRnJlZVdlYk1vbml0b3JpbmcgU2l0ZUNoZWNrZXJcIixcblx0XCJBc3BpZWdlbEJvdFwiLFxuXHRcIk5BVkVSIEJsb2cgUnNzYm90XCIsXG5cdFwiemVuYmFjayBib3RcIixcblx0XCJTZW50aUJvdFwiLFxuXHRcIkRvbWFpbnMgUHJvamVjdFxcXFwvXCIsXG5cdFwiUGFuZGFseXRpY3NcIixcblx0XCJWS1JvYm90XCIsXG5cdFwiYmlkc3dpdGNoYm90XCIsXG5cdFwidGlnZXJib3RcIixcblx0XCJOSVhTdGF0c2JvdFwiLFxuXHRcIkF0b20gRmVlZCBSb2JvdFwiLFxuXHRcIltDY111cmVib3RcIixcblx0XCJQYWdlUGVla2VyXFxcXC9cIixcblx0XCJWaWdpbFxcXFwvXCIsXG5cdFwicnNzYm90XFxcXC9cIixcblx0XCJzdGFydG1lYm90XFxcXC9cIixcblx0XCJKb2Jib2Vyc2VCb3RcIixcblx0XCJzZWV3aXRoa2lkc1wiLFxuXHRcIk5JTkpBIGJvdFwiLFxuXHRcIkN1dGJvdFwiLFxuXHRcIkJ1Ymx1cEJvdFwiLFxuXHRcIkJyYW5kT05ib3RcIixcblx0XCJSaWRkZXJCb3RcIixcblx0XCJUYWJvb2xhYm90XCIsXG5cdFwiRHViYm90Ym90XCIsXG5cdFwiRmluZElUQW5zd2Vyc2JvdFwiLFxuXHRcImluZm9vYm90XCIsXG5cdFwiUmVmaW5kYm90XCIsXG5cdFwiQmxvZ1RyYWZmaWNcXFxcL1xcXFxkXFxcXC5cXFxcZCsgRmVlZC1GZXRjaGVyXCIsXG5cdFwiU2VvYmlsaXR5Qm90XCIsXG5cdFwiQ2luY3Jhd1wiLFxuXHRcIkRyYWdvbmJvdFwiLFxuXHRcIlZvbHV1bURTUC1jb250ZW50LWJvdFwiLFxuXHRcIkZyZXNoUlNTXCIsXG5cdFwiQml0Qm90XCIsXG5cdFwiXlBIUC1DdXJsLUNsYXNzXCIsXG5cdFwiR29vZ2xlLUNlcnRpZmljYXRlcy1CcmlkZ2VcIixcblx0XCJjZW50dXJ5Ym90XCIsXG5cdFwiVmliZXJcIixcblx0XCJlXFxcXC52ZW50dXJlcyBJbnZlc3RtZW50IENyYXdsZXJcIixcblx0XCJldmMtYmF0Y2hcIixcblx0XCJQZXRhbEJvdFwiLFxuXHRcInZpcnVzdG90YWxcIixcblx0XCIoXnwgKVBUU1RcXFxcL1wiLFxuXHRcIm1pbmljcmF3bGVyXCIsXG5cdFwiQ29va2llYm90XCIsXG5cdFwidHJvdml0Qm90XCIsXG5cdFwic2Vvc3RhclxcXFwuY29cIixcblx0XCJJb25DcmF3bFwiLFxuXHRcIlVwdGltZS1LdW1hXCIsXG5cdFwiU2Vla3BvcnRcIixcblx0XCJGcmVzaHBpbmdCb3RcIixcblx0XCJGZWVkYmluXCIsXG5cdFwiQ3JpdGVvQm90XCIsXG5cdFwiU25hcCBVUkwgUHJldmlldyBTZXJ2aWNlXCIsXG5cdFwiQmV0dGVyIFVwdGltZSBCb3RcIixcblx0XCJSdXhpdFN5bnRoZXRpY1wiLFxuXHRcIkdvb2dsZS1SZWFkLUFsb3VkXCIsXG5cdFwiVmFsdmVcXFxcL1N0ZWFtXCIsXG5cdFwiT2RrbEJvdFxcXFwvXCIsXG5cdFwiR1BUQm90XCIsXG5cdFwiQ2hhdEdQVC1Vc2VyXCIsXG5cdFwiT0FJLVNlYXJjaEJvdFwiLFxuXHRcIllhbmRleFJlbmRlclJlc291cmNlc0JvdFxcXFwvXCIsXG5cdFwiTGlnaHRzcGVlZFN5c3RlbXNDcmF3bGVyXCIsXG5cdFwiZXYtY3Jhd2xlclxcXFwvXCIsXG5cdFwiQml0U2lnaHRCb3RcXFxcL1wiLFxuXHRcIndvb3JhbmtyZXZpZXdcXFxcL1wiLFxuXHRcIkdvb2dsZS1TYWZldHlcIixcblx0XCJBd2FyaW9Cb3RcIixcblx0XCJEYXRhRm9yU2VvQm90XCIsXG5cdFwiTGluZXNwaWRlclwiLFxuXHRcIldlbGxLbm93bkJvdFwiLFxuXHRcIkEgUGF0ZW50IENyYXdsZXJcIixcblx0XCJTdHJhY3RCb3RcIixcblx0XCJzZWFyY2hcXFxcLm1hcmdpbmFsaWFcXFxcLm51XCIsXG5cdFwiWW91Qm90XCIsXG5cdFwiTmljZWNyYXdsZXJcIixcblx0XCJOZWV2YWJvdFwiLFxuXHRcIkJyaWdodEVkZ2UgQ3Jhd2xlclwiLFxuXHRcIlNpdGVDaGVja2VyQm90Q3Jhd2xlclwiLFxuXHRcIlRvbWJhUHVibGljV2ViQ3Jhd2xlclwiLFxuXHRcIkNyYXdseVByb2plY3RDcmF3bGVyXCIsXG5cdFwiS29tb2RpYUJvdFwiLFxuXHRcIktTdGFuZEJvdFwiLFxuXHRcIkNJU1BBIFdlYmNyYXdsZXJcIixcblx0XCJNVFJvYm90XCIsXG5cdFwiaHlzY29yZVxcXFwuaW9cIixcblx0XCJBbGV4YW5kcmlhT3JnQm90XCIsXG5cdFwiMmlwIGJvdFwiLFxuXHRcIlllbGxvd2JyYW5kcHJvdGVjdGlvbmJvdFwiLFxuXHRcIlNFT2xpemVyXCIsXG5cdFwidnVodXZCb3RcIixcblx0XCJJTkVUREVYLUJPVFwiLFxuXHRcIlN5bmFwc2VcIixcblx0XCJ0M3ZlcnNpb25zQm90XCIsXG5cdFwiZGVlcG5vY1wiLFxuXHRcIkNvY29seXplYm90XCIsXG5cdFwiaHlwZXN0YXRcIixcblx0XCJSZXZlcnNlRW5naW5lZXJpbmdCb3RcIixcblx0XCJzZW1waVxcXFwudGVjaFwiLFxuXHRcIklmcmFtZWx5XCIsXG5cdFwiTWV0YUluc3BlY3RvclwiLFxuXHRcIm5vZGUtZmV0Y2hcIixcblx0XCJsOWV4cGxvcmVcIixcblx0XCJweXRob24tb3BlbmdyYXBoXCIsXG5cdFwiT3BlbkdyYXBoQ2hlY2tcIixcblx0XCJkZXZlbG9wZXJzXFxcXC5nb29nbGVcXFxcLmNvbVxcXFwvXFxcXCtcXFxcL3dlYlxcXFwvc25pcHBldFwiLFxuXHRcIlNlbnV0b0JvdFwiLFxuXHRcIk1hQ29DdVwiLFxuXHRcIk5ld3NCbHVyXCIsXG5cdFwiaW5vcmVhZGVyXCIsXG5cdFwiTmV0U3lzdGVtc1Jlc2VhcmNoXCIsXG5cdFwiUGFnZVRoaW5nXCIsXG5cdFwiV29yZFByZXNzXFxcXC9cIixcblx0XCJQaHhCb3RcIixcblx0XCJJbWFnZXNpZnRCb3RcIixcblx0XCJFeHBhbnNlXCIsXG5cdFwiSW50ZXJuZXRNZWFzdXJlbWVudFwiLFxuXHRcIl5CV1xcXFwvXCIsXG5cdFwiR2VlZG9Cb3RcIixcblx0XCJBdWRpc3RvIENyYXdsZXJcIixcblx0XCJQZXJwbGV4aXR5Qm90XFxcXC9cIixcblx0XCJbY0NdbGF1ZGVbYkJdb3RcIixcblx0XCJNb25zaWRvYm90XCIsXG5cdFwiR3JvdXBNZUJvdFwiLFxuXHRcIlZlcmNlbGJvdFwiLFxuXHRcInZlcmNlbC1zY3JlZW5zaG90XCIsXG5cdFwiZmFjZWJvb2tjYXRhbG9nXFxcXC9cIixcblx0XCJtZXRhLWV4dGVybmFsYWRzXFxcXC9cIixcblx0XCJtZXRhLWV4dGVybmFsYWdlbnRcXFxcL1wiLFxuXHRcIm1ldGEtZXh0ZXJuYWxmZXRjaGVyXFxcXC9cIixcblx0XCJBY2FkZW1pY0JvdFJUVVwiLFxuXHRcIktleWJhc2VCb3RcIixcblx0XCJMZW1teVwiLFxuXHRcIkNvb2tpZUh1YlNjYW5cIixcblx0XCJIeWRyb3plblxcXFwuaW9cIixcblx0XCJIVFRQIEJhbm5lciBEZXRlY3Rpb25cIixcblx0XCJTdW1tYWx5Qm90XCIsXG5cdFwiTWljcm9zb2Z0UHJldmlld1xcXFwvXCIsXG5cdFwiR2VlZG9Qcm9kdWN0U2VhcmNoXCIsXG5cdFwiVGlrVG9rU3BpZGVyXCIsXG5cdFwiT25DcmF3bFxcXFwvXCIsXG5cdFwic2luZHJlc29yaHVzXFxcXC9nb3RcIixcblx0XCJDZW5zeXNJbnNwZWN0XFxcXC9cIixcblx0XCJTQkludHVpdGlvbnNCb3RcXFxcL1wiLFxuXHRcInNpdGVidWxiXCIsXG5cdFwiWWV4dEJvdFxcXFwvXCIsXG5cdFwiRGF0YWRvZ1N5bnRoZXRpY3NcIixcblx0XCJHb29nbGUtQWRzLUNvbnZlcnNpb25zXCIsXG5cdFwiT2JzZXJ2ZVBvaW50XCIsXG5cdFwiQ2hlY2tseVwiLFxuXHRcIkFMaXR0bGUgQ2xpZW50XCIsXG5cdFwiQWxpeXVuU2VjQm90XCIsXG5cdFwiQ2xhdWRlLVdlYlwiLFxuXHRcImFudGhyb3BpYy1haVwiLFxuXHRcIkNsYXVkZS1Vc2VyXCIsXG5cdFwiQ2xhdWRlLVNlYXJjaEJvd
1FwiLFxuXHRcIkdvb2dsZS1FeHRlbmRlZFwiLFxuXHRcImNvaGVyZS1haVwiLFxuXHRcIlRpbXBpYm90XCIsXG5cdFwiU0VSYW5raW5nQmFja2xpbmtzQm90XCIsXG5cdFwiQ01TQ2hlY2tlclwiLFxuXHRcIldheWJhY2tcIixcblx0XCJQbGF5d3JpZ2h0XCIsXG5cdFwiUHVwcGV0ZWVyXCIsXG5cdFwiU2VsZW5pdW1cIixcblx0XCJOaWt0b1wiLFxuXHRcInNxbG1hcFwiLFxuXHRcIlptRXVcIixcblx0XCJtYXNzY2FuXCIsXG5cdFwiV1BTY2FuXCIsXG5cdFwiW2FBXWN1bmV0aXhcIixcblx0XCJOZXNzdXNcIixcblx0XCJbZERdaXJbQmJddXN0ZXJcIixcblx0XCJTdGF0dXNDYWtlXCIsXG5cdFwiY29sbHlcIixcblx0XCJbbU1dZWNoYW5pemVcIixcblx0XCJhaXJcXFxcLmFpXFxcXC9zY2FubmluZ1wiLFxuXHRcImFzbnJpc2tzY29yZXJcIixcblx0XCJPSUNyYXdsZXJcIixcblx0XCJsOXNjYW5cIixcblx0XCJTbGFjY2FsZUJvdFwiLFxuXHRcIkN1c3RvbUFzeW5jSHR0cENsaWVudFwiLFxuXHRcIl5IVFRQaWVcXFxcL1wiLFxuXHRcIkdlbWluaS1EZWVwLVJlc2VhcmNoXCIsXG5cdFwiUGVycGxleGl0eS1Vc2VyXCIsXG5cdFwiUGVycGxleGl0eVVzZXJcIixcblx0XCJtZXRhLXdlYmluZGV4ZXJcIixcblx0XCJEdWNrQXNzaXN0Qm90XCIsXG5cdFwiTWlzdHJhbEFJLVVzZXJcIixcblx0XCJ3ZWJ6aW9cIixcblx0XCJuZXdzYWlcXFxcL1wiLFxuXHRcIl5BcmVuYVVuZnVybEJvdFwiLFxuXHRcIkEzNjAtU2VhcmNoXCIsXG5cdFwiQUFTQS1Cb3RcIixcblx0XCJBY2Nlc3NTdGF0dXNcIixcblx0XCJBY3F1aWEgb3B0aW1pemVcIixcblx0XCJBY3RpdmVDb21wbHlcIixcblx0XCJBZGtlcm5lbFRvcGljQ3Jhd2xlclwiLFxuXHRcIkFsZXJ0U2l0ZVwiLFxuXHRcIkFsbEFmcmljYVwiLFxuXHRcIkFtYXppbmctU2VhcmNoQm90XCIsXG5cdFwiQW1hem9uLUJlZHJvY2stQWdlbnRDb3JlLUJyb3dzZXJcIixcblx0XCJBbWF6b25CdXlGb3JNZVwiLFxuXHRcIkFtem4tU2VhcmNoQm90XCIsXG5cdFwiQW16bi1Vc2VyXCIsXG5cdFwiQW5jaG9yIEJyb3dzZXJcIixcblx0XCJBbm9tdXJhXCIsXG5cdFwiQVAzQVxcXFwuMjQwNjE3XFxcXC4wMDhcIixcblx0XCJBcGlmeUJvdFwiLFxuXHRcIkFwaWZ5V2Vic2l0ZUNvbnRlbnRDcmF3bGVyXCIsXG5cdFwiQXJjaGl2ZS1JdFwiLFxuXHRcImFydGVtaXMgd2ViIHJlYWRlclwiLFxuXHRcImF0bGFzc2lhbi1ib3RcIixcblx0XCJBdHRyYWN0YVwiLFxuXHRcIkF1ZGlnZW50QWRCb3RcIixcblx0XCJBdXRob3J5XCIsXG5cdFwiQXV0b21hdG9ufE5ld3NpZnkgRmVlZCBGZXRjaGVyXCIsXG5cdFwiQXdhcmlvUmVuZGVyZXJCb3RcIixcblx0XCJBenVyZUFJLVNlYXJjaEJvdFwiLFxuXHRcIkJlc3RDaGFuZ2VcIixcblx0XCJiaWdzdXJcXFxcLmFpXCIsXG5cdFwiYmxcXFxcLnVrX2xkZGNfYm90XCIsXG5cdFwiQmxpbmdFUlBcIixcblx0XCJCbG9ja2FpZFwiLFxuXHRcIkJsb2dsaW5lc1wiLFxuXHRcIkJsb2dWYXVsdFwiLFxuXHRcImJsdWVza3ktZG9tYWluLXN0YXR1cy1jbGFzc2lmaWVyXCIsXG5cdFwiQmx1ZXNreVxcXFwvXCIsXG5cdFwiYm5lXFxcXC5lc19ib3RcIixcblx0XCJCcmlnaHRib3RcIixcblx0XCJCcm93c2VyQm90LU9ic2VydmVyXCIsXG5cdFwiQnVmZmVyTGlua1ByZXZpZXdCb3RcIixcblx0XCJCdWdzbmFnXCIsXG5cdFwiQnV0dG9uZG93blwiLFxuXHRcIkNhcGl0YWxPbmVCb3RcIixcblx0XCJDZXJ0Q2hpZWZcIixcblx0XCJjaGFubmFibGVcIixcblx0XCJDaGFubmVsM0JvdFwiLFxuXHRcIkNoaXJwfGdvdG9zb2NpYWxcIixcblx0XCJDbGlja1VwTGlua1VuZnVybGVyXCIsXG5cdFwiQ2xvdWRmbGFyZS1BdXRvUkFHXCIsXG5cdFwiQ2xvdWRmbGFyZS1DdXN0b20tSG9zdG5hbWUtVmVyaWZpY2F0aW9uXCIsXG5cdFwiQ2xvdWRmbGFyZS1TdHJlYW0tV2ViaG9va1wiLFxuXHRcIkNsb3VkZmxhcmVSYWRhclVSTFNjYW5uZXJcIixcblx0XCJDbG91ZHRyZWxsaXNcIixcblx0XCJbY0NdbHVkb1wiLFxuXHRcIkNvZGVcXFxcLzFcXFxcLlwiLFxuXHRcIkNvbGxhcHNpZnlcIixcblx0XCJDb250ZXh0dWFsQm90W1xcXFxzXFxcXFNdKm91dGNvbWVzXFxcXC5uZXRcIixcblx0XCJDb252ZXJtYXhcIixcblx0XCJjb29raWUtbWFlc3Ryb1wiLFxuXHRcIkNvb2tpZUh1YlZlcmlmeVwiLFxuXHRcIkNvb2tpZVllc2JvdFwiLFxuXHRcIkNyYXp5IEVnZ1wiLFxuXHRcIkN1cnJlbnRbXFxcXHNcXFxcU10qUlNTIFJlYWRlclwiLFxuXHRcImN5cGV4XFxcXC5haVxcXFwvc2Nhbm5pbmdcIixcblx0XCJEZWVwQ3Jhd2xcIixcblx0XCJEaWdpQ2VydCBEQ1ZcIixcblx0XCJkbHZyXFxcXC5pdFwiLFxuXHRcIkRvdGNvbS1Nb25pdG9yXCIsXG5cdFwiRHJhdGFBdXRvcGlsb3RcIixcblx0XCJEcmVhbUhvc3QgRGF0YSBUZWFtXCIsXG5cdFwiZHM5XCIsXG5cdFwiIERWYm90XCIsXG5cdFwiRWNvVmFkaXNTdXN0YWluYWJpbGl0eUJvdFwiLFxuXHRcImVsbWFoXFxcXC5pbyBVcHRpbWUgTW9uaXRvcmluZ1wiLFxuXHRcIkV2ZXJub3RlUmljaExpbmtCb3RcIixcblx0XCJFekx5bnhcIixcblx0XCJFem9pY0JvdFwiLFxuXHRcIkZhY2Vib29rQm90XCIsXG5cdFwiRmFzdERBU1RcIixcblx0XCJGZWVkZXIgXFxcXC9cIixcblx0XCJGZWVkRmxvd1wiLFxuXHRcIkZpbmRGaWxlc1xcXFwubmV0XCIsXG5cdFwiRmlyZWNyYXdsQWdlbnRcIixcblx0XCJGeW5kU2VhcmNoRW5naW5lLUNyYXdsZXJcIixcblx0XCJGeW5kU2VhcmNoRW5naW5lLVJlQ3Jhd2xlclwiLFxuXHRcIkdvb2RyZWFkc1wiLFxuXHRcIkdvb2dsZSBUcnVzdCBTZXJ2aWNlc1wiLFxuXHRcIkdvb2dsZS1BZ2VudFwiLFxuXHRcIkdvb2dsZS1HZW1pbmktQ0xJXCIsXG5cdFwiR29vZ2xlLU5vdGVib29rTE1cIixcblx0XCJHb29nbGVBZ2VudC1NYXJpbmVyXCIsXG5cdFwiR3JlcHByIFdlYiBDcmF3bGVyXCIsXG5cdFwiSGFyZGVuaXplXCIsXG5cdFwiSG9uZXliYWRnZXJCb3RcIixcblx0XCJJYm91Qm90XCIsXG5cdFwiaW1hZ2VTcGlkZXJcIixcblx0XCJJbm5vbG9naWNhXCIsXG5cdFwia2FnaS1mZXRjaGVyXCIsXG5cdFwiS2FuZ2Fyb28gQm90XCIsXG5cdFwiS25vd24gQWdlbnRcIixcblx0XCJLcmF3bGVyQm90XCIsXG5cdFwibGFpb24taHVnZ2luZ2ZhY2UtcHJvY2Vzc29yXCIsXG5cdFwiTGlua0NoZWNrZXJCb3RcIixcblx0XCJMaW5rdXBCb3RcIixcblx0XCJMTUFyZW5hVW5mdXJsQm90XCIsXG5cdFwibHlvbmwtYXNzZXQtcHJveHlcIixcblx0XCJseW9ubC1jcmF3bGVyXCIsXG5cdFwiTWFnaUJvd
1FwiLFxuXHRcIk1hZ3BpZVJTU1wiLFxuXHRcIm1haWxcXFxcLnJ1XCIsXG5cdFwiTWFpbENoaW1wXCIsXG5cdFwiTWFudXMtVXNlclwiLFxuXHRcIk1jb250ZXh0dWFsQm90XCIsXG5cdFwiTWVkaXVtYm90LU1ldGFUYWdGZXRjaGVyXCIsXG5cdFwiTWV0YUlBQiBGYWNlYm9va1wiLFxuXHRcIk1peHJhbmtCb3RcIixcblx0XCJNb2Rlcm5pemVCb3RcIixcblx0XCJNb250YXN0aWNNb25pdG9yXCIsXG5cdFwiTmFub0ludGVyYWN0aXZlXCIsXG5cdFwiTmVzdERhZGR5Ym90XCIsXG5cdFwiTmV0Y3JhZnQgU1NMIFNlcnZlciBTdXJ2ZXlcIixcblx0XCJOZXRjcmFmdCBXZWIgU2VydmVyIFN1cnZleVwiLFxuXHRcIk5ldFNlZXIgY3Jhd2xlclwiLFxuXHRcIk5ldHVtb3xuZXR1bW9cIixcblx0XCJOZXdSZWxpY1N5bnRoZXRpY3NcIixcblx0XCJOZXdzUm9vbVxcXFwuQklcIixcblx0XCJOaXRyby1cIixcblx0XCJOaXRyb0JvdFwiLFxuXHRcIk5vaWJ1XCIsXG5cdFwiTm9zdG9DcmF3bGVyQm90XCIsXG5cdFwiT25lVHJ1c3RcIixcblx0XCJvcGVuY29kZS1zbWFydGZldGNoXCIsXG5cdFwiO093bGVyXCIsXG5cdFwiUGFyc2VseVNoYXJlc0JvdFwiLFxuXHRcIlBoaW5kQm90XCIsXG5cdFwiUG9kY2hhc2VyUGFyc2VyXCIsXG5cdFwiUG9kaW1vXCIsXG5cdFwiUG9nZ2lvLUNpdGF0aW9uc1wiLFxuXHRcInByb2R1Y3RzdXBcXFxcLmlvXFxcXC9jcmF3bGVyXCIsXG5cdFwicWNib3RcIixcblx0XCJRdWFseXNcIixcblx0XCJRdW9yYS1Cb3RcIixcblx0XCJRd2FudGJvdFwiLFxuXHRcIlF3YXJyeWJvdFwiLFxuXHRcIlJTaXRlQXVkaXRvclwiLFxuXHRcIlJTU1xcXFwuU29jaWFsXCIsXG5cdFwiU2FsZXNmb3JjZVxcXFwuY29tXCIsXG5cdFwiU2NvcGUzXCIsXG5cdFwic2NyYXBpbmdAbnl0aW1lc1xcXFwuY29tXCIsXG5cdFwiU2NydWJieVwiLFxuXHRcIlNjcnVuY2hib3RcIixcblx0XCJzZW80YWpheFxcXFwuY29tXCIsXG5cdFwiU2VxdWVsV1BcIixcblx0XCJTZXJ2ZXJEZW5zaXR5XCIsXG5cdFwiU2hhcEJvdFwiLFxuXHRcIlNob3J0UGl4ZWxcIixcblx0XCJTaWxrdGlkZVwiLFxuXHRcIlNpdGVMb2NrXCIsXG5cdFwiU21hcnNoQm90XCIsXG5cdFwiU01UbmV0UE1Cb3RcIixcblx0XCJTb2Z0d2FyZS1TZWN1cml0eS1SZXNlYXJjaFwiLFxuXHRcIlNvdHRvcG9wTm9uZVwiLFxuXHRcIlNwaWRlcltcXFxcc1xcXFxTXSpzcGlkZXJcXFxcLmNvbVwiLFxuXHRcIlNwbHVua1wiLFxuXHRcIlN0YXR1c05lc3RCYWNrbGlua1NwaWRlclwiLFxuXHRcInN0ZXBzdG9uZUNyYXdsQm90XCIsXG5cdFwiVGF2aWx5Qm90XCIsXG5cdFwiVGhvdXNhbmRFeWVzXCIsXG5cdFwiVHJhZVxcXFwvXCIsXG5cdFwiVHdpbkFnZW50XCIsXG5cdFwidWlwYm90XCIsXG5cdFwidW0tRkNcIixcblx0XCJ1bS1JQ1wiLFxuXHRcIlVwdGltZVN0YXRpc3RpY3NcIixcblx0XCJWZXJpc3BpZGVyXCIsXG5cdFwidmlzaW9uaGVpZ2h0XFxcXC5jb21cXFxcL3NjYW5cIixcblx0XCJXYXRjaGJvdCBtb25pdG9yaW5nIHJvYm90XCIsXG5cdFwiV2F0Y2hmdWxcIixcblx0XCJ3ZWJvcmFtYS1mZXRjaGVyXCIsXG5cdFwid2Vic3BpZGVybW91bnRcIixcblx0XCJXZXBjaFNlYXJjaEVuZ2luZVwiLFxuXHRcIndrbmQtYm90XCIsXG5cdFwiV1BNVSBERVYgSHViXCIsXG5cdFwiV1RvdGVtXCIsXG5cdFwiWG92aU9ucGFnZUNyYXdsZXJcIixcblx0XCJ5ZWxwc3BpZGVyXCIsXG5cdFwiWmFuaXN0YUJvdFwiLFxuXHRcIlpvb21JbmZvLVwiLFxuXHRcIjdTaXRlcnNcIixcblx0XCJBY2Nlc3NpYmxlIFdlYiBCb3RcIixcblx0XCJBdFZvd0JvdFwiLFxuXHRcIkJpYmxpb3RoZXF1ZSBOYWNpb25hbCBkZSBGcmFuY2UgQ3Jhd2xlclwiLFxuXHRcIkJsaW5nIEVSUFwiLFxuXHRcIkNEU0Nib3RcIixcblx0XCJDcml0aWNhbCBDU1MgQm90XCIsXG5cdFwiQ3liYWFCb3RcIixcblx0XCJDeWJlckZpbmRDcmF3bGVyXCIsXG5cdFwiRGFyayBWaXNpdG9yXCIsXG5cdFwiRGV0ZXJtXCIsXG5cdFwiRE5TU2Nhbm5lclwiLFxuXHRcIkRydXBhbGJvdFwiLFxuXHRcImVNb25leSBBZHZpc29yXCIsXG5cdFwiZXZlcnlmZWVkLXNwaWRlclwiLFxuXHRcIkV4dGVDb250ZXh0Q3Jhd2xcIixcblx0XCJGZWRpREJcIixcblx0XCJGZWRpSW5kZXhcIixcblx0XCJGZWRpTGlzdCBBZ2VudFwiLFxuXHRcIkZlZGluZWtvXCIsXG5cdFwiRmVkUmVwb3J0ZXIgQm90IGZvciBGRklFQ1wiLFxuXHRcIkZlZWRzZWFyY2ggQm90XCIsXG5cdFwiRmVlZHNlYXJjaC1DcmF3bGVyXCIsXG5cdFwiZmlwZXJib3RcIixcblx0XCJGbGVlYnNCb3RcIixcblx0XCJGbHVpZFwiLFxuXHRcIkZseXJpdmVyYm90XCIsXG5cdFwiRnJlc2hib3RcIixcblx0XCJHYWlzYm90XCIsXG5cdFwiR2Vub21lQ3Jhd2xlcmRcIixcblx0XCJIYWxvQm90XCIsXG5cdFwiSVJMYm90XCIsXG5cdFwia2Fpa2tpXFxcXC5vcmctZGlnaXRhbC1hcmNoaXZlXCIsXG5cdFwia2JcXFxcLmRrX2JvdFwiLFxuXHRcIkxpYnJhcnkgT2YgQ29uZ3Jlc3MgV2ViIEFyY2hpdmluZ1wiLFxuXHRcIk1hZ25ldG1lQm90XCIsXG5cdFwiTWF0Y2hvcnlTZWFyY2hcIixcblx0XCJNaW5vcnUncyBGZWRpdmVyc2UgQ3Jhd2xlclwiLFxuXHRcIk1pcnJvcldlYkNyYXdsZXJcIixcblx0XCJtaXRocmlsLWNyYXdsZXJcIixcblx0XCJNb2RhdFNjYW5uZXJcIixcblx0XCJOYXBCb3RcIixcblx0XCJOZXcgWW9yayBUaW1lcyBOZXdzZ2F0aGVyaW5nXCIsXG5cdFwiTkxVWF9JQUhhcnZlc3RlclwiLFxuXHRcIk5vYWhCb3RcIixcblx0XCJQbGFnQXdhcmVCb3RcIixcblx0XCJSYWt1dGVuIEltYWdlIGV4dHJhY3Rpb24gYm90XCIsXG5cdFwiUmVzZWFyY2hCb3RcIixcblx0XCJyc3MtaXMtZGVhZFxcXFwubG9sIHdlYiBib3RcIixcblx0XCJzZW9MeXRcIixcblx0XCJTaXJkYXRhQm90XCIsXG5cdFwiU2l0ZXNPdmVyUGFnZXNCb3RcIixcblx0XCJTbGVlcEJvdFwiLFxuXHRcIlNvc29zcGlkZXJcIixcblx0XCJUZXJtbHlcIixcblx0XCJUTFMgdGVzdGVyXCIsXG5cdFwidHJhZmlsYXR1cmFcIixcblx0XCJVcmxCZWVCb3RcIixcblx0XCJ2aWRlb290diBCb3RcIixcblx0XCJ2bWNyYXdsXCIsXG5cdFwiV2Fkb29Cb3RcIixcblx0XCJXZWJzaXRlLWluZm9cXFxcLm5ldC1Sb2JvdFwiLFxuXHRcIldlYlpJUFwiLFxuXHRcIldpa2lEb1wiLFxuXHRcIldPVk4gQ3Jhd2xlclwiLFxuXHRcIllvdWRhb0JvdFwiLFxuXHRcIlp5Qm9yZ1wiLFxuXHRcIkFyYW5ldC1TZWFyY2hCb3RcIixcblx0XCJjcmF3bDRhaVwiLFxuXHRcIkRlZXBTZWVrQm90XCIsXG5cdFwiaWFza3NwaWRlclwiLFxuXHRcIkt1bmF0b0NyYXdsZXJcIixcblx0XCJUZXJyYUNvdHRhXCIsXG5cdFwiQUJFdmFsQm90XCIsXG5cdFwiYmxla2tvYm90XCIsXG5cdFwiYnItY3Jhd2xlclwiLFxuXHRcIkJ1ZGR5Qm90XCIsXG5cdFwiQ2FwdGVycmFCb3RcIixcblx0XCJjYXJib24tdW1icmVsbGEtYm90XCIsXG5cdFwiY2F2ZW1hbi1odW50ZXJcIixcblx0XCJDZW50cm8gQWRzXFxcXC50eHQgQ3Jhd2xlclwiLFxuXHRcIldJU0Vib3RcIixcblx0XCJDb2RhQm90XCIsXG5cdFwiQ29ycG9yYW1hIG1hdGNoZXJcIixcblx0XCJDeW90ZWtXZWJDb3B5XCIsXG5cdFwiRGF0YWRvZyBBZ2VudFwiLFxuXHRcIkRhenpsZSBCbHVlU2t5IEJvdFwiLFxuXHRcIkRvbWluaWNCb3RcIixcblx0XCJEb3cgSm9uZXMgU2VhcmNoYm90XCIsXG5cdFwiRG93bmxvYWQgTmluamFcIixcblx0XCJFbWFpbFdvbGZcIixcblx0XCJmZWRpc3RhdHNDcmF3bGVyXCIsXG5cdFwiR29QYXJzZXJCb3RcIixcblx0XCJnc2EtY3Jhd2xlclwiLFxuXHRcIkhhbmFsZWlCb3RcIixcblx0XCJOaWNoZUluZGV4XCIsXG5cdFwiSGVhZE9ubHlTY3JhcGVyXCIsXG5cdFwiSGVua0JvdFwiLFxuXHRcIkltcGFjdFxcXFwuY29tIEFnZW50XCIsXG5cdFwiS2V5ZHJvcFxcXFwuaW9cIixcblx0XCJsYXJiaW5cIixcblx0XCJTRU5USU5FTC1MaW5rQ2hlY2tcIixcblx0XCJsaW5rb1wiLFxuXHRcIkxpbmtwYWRCb3RcIixcblx0XCJsd3AtdHJpdmlhbFwiLFxuXHRcIk1hZ3VzIEJvdFwiLFxuXHRcIk5hdmVyQm90XCIsXG5cdFwibG9vcGltcHJvdmVtZW50c1xcXFwuY29tXCIsXG5cdFwiT3BlblRoZUJveEJvdFwiLFxuXHRcIk9XTGVyLVdcIixcblx0XCJwZWVyMzlfY3Jhd2xlclwiLFxuXHRcIlBpeGFsYXRlXFxcXC5jb21cIixcblx0XCJQb2R1cHRpbWVcIixcblx0XCJQb21vdGh5LUJvdFwiLFxuXHRcIlB1bHNlUG9pbnQtQ3Jhd2xlclwiLFxuXHRcInJhd3dlYi1ib3RcIixcblx0XCJzZW1hbnRpYy12aXNpb25zXCIsXG5cdFwiU2luZHVwXCIsXG5cdFwiU2l0ZVN1Y2tlclwiLFxuXHRcIlNwcmluZ3NlcnZlQm90XCIsXG5cdFwiU1FXYXRjaGVyXCIsXG5cdFwiU3VwYWJhc2UgUGFpcmVkIENyYXdsZXJcIixcblx0XCJzdi13YXRjaGFnZW50XCIsXG5cdFwiU3dpZnRib3RcIixcblx0XCJTeW50aGVzaUJvdFwiLFxuXHRcIlRhcmFHcm91cCBJbnRlbGxpZ2VudCBCb3RcIixcblx0XCJUaGlua2JvdFwiLFxuXHRcIlRTTWJvdFwiLFxuXHRcIlRTTS10dXJpbmdvc1wiLFxuXHRcIlVHQVJlc2VhcmNoQWdlbnRcIixcblx0XCJVcmxTdU1hXFxcXC5kZSBjcmF3bGVyXCIsXG5cdFwiV2Fuc2Nhbm5lckJvdFwiLFxuXHRcIldlYkNhcHR1cmVcIixcblx0XCJXZWJDb3BpZXJcIixcblx0XCJjb2duaXRpdmVzZW9cXFxcLmNvbVwiLFxuXHRcIlhpbmcgQm90XCIsXG5cdFwiWE1MIFNpdGVtYXBzIEdlbmVyYXRvclwiLFxuXHRcIllhbmRvcmlSU1NCb3RcIixcblx0XCJaZWFsYm90XCIsXG5cdFwiMDA4XFxcXC9cIixcblx0XCJtb25pdG9yaW5nMzYwYm90XFxcXC9cIixcblx0XCJBZGFnaW9Cb3RcIixcblx0XCJhZGJlYXRcXFxcLmNvbVwiLFxuXHRcIkFkbWluTGFic1wiLFxuXHRcImFkdmFuY2VkX2NyYXdsZXJcIixcblx0XCJBZHZlbnR1cmVyXCIsXG5cdFwiQUdBS0lEU0JPVFwiLFxuXHRcIkFnZW5jeUFuYWx5dGljc0JvdFwiLFxuXHRcIkFJMkJvdFwiLFxuXHRcIkFraXNtZXRCb3RcIixcblx0XCJhbGV4YSBzaXRlIGF1ZGl0XCIsXG5cdFwiQWxnb2xpYSBDcmF3bGVyXCIsXG5cdFwiYWxpZW5mYXJtXCIsXG5cdFwiYWxsT3JpZ2luc1wiLFxuXHRcIkFtYXpvbkFkQm90XCIsXG5cdFwiS2VuZHJhQm90XCIsXG5cdFwiQXBwU2l0ZUFzc29jaWF0aW9uXCIsXG5cdFwiQXJhZ29nXFxcXC9cIixcblx0XCJBcmFuZWFcIixcblx0XCJBcmNoaXZlQm94XCIsXG5cdFwiQXJxdWl2b0JvdFwiLFxuXHRcIkFycXVpdm8td2ViLWNyYXdsZXJcIixcblx0XCJBcnRlbWlzQm90XCIsXG5cdFwiQXNhbmFcXFxcL1wiLFxuXHRcIkF1ZGlzdG9Cb3RcIixcblx0XCJBdXRvY29uZmlnIFRlc3QgZnJvbSBVU1RDXCIsXG5cdFwidHJhY2tpbmctcXVhbGl0eS1zcGlkZXJcIixcblx0XCJCYWQgTmVpZ2hib3Job29kIEhlYWRlciBEZXRlY3RvclwiLFxuXHRcIkJhaWR1QWRzQm90XCIsXG5cdFwiQkRCb3RcXFxcL1wiLFxuXHRcIkJlZXBlckJvdFwiLFxuXHRcIkJldHRlclVwdGltZUJvdFwiLFxuXHRcIkJuRkJvdFwiLFxuXHRcIkJpZ1VwRGF0YUJvdFwiLFxuXHRcIkJpbmFyeUNhbmFyeVwiLFxuXHRcIkJpdGJ1Y2tldC1XZWJob29rc1wiLFxuXHRcImJsXFxcXC51a19sZGZjX2JvdFwiLFxuXHRcIkJsYWNrRHVjay1GRFwiLFxuXHRcIkJsb2d0cm90dHJcIixcblx0XCJCbHVlc2t5UHJldmlld0JvdFwiLFxuXHRcIkJvYXJkR2FtZVByaWNlc0JvdFwiLFxuXHRcIkJvdFBva2VcIixcblx0XCJCREZldGNoXCIsXG5cdFwiQnJhbmR3YXRjaFwiLFxuXHRcIkJyYXZlQm90XCIsXG5cdFwiYnJva2VubGlua2NoZWNrXFxcXC5jb21cIixcblx0XCJCV1xcXFwvXCIsXG5cdFwiQnVzaGJhYnlcIixcblx0XCJCdXR0ZXJmbHlcIixcblx0XCJyc3MtcGFyc2VyXCIsXG5cdFwiQ2FsaWJlckJvdFwiLFxuXHRcIkNhcGl0YWxPbmVTaG9wcGluZ1wiLFxuXHRcIkNhdGNocG9pbnRcIixcblx0XCJjZW50dXJ5YlxcXFwub1xcXFwudDlcIixcblx0XCJDRVJUIFBMXCIsXG5cdFwiY2VydHl0YWdzXCIsXG5cdFwiQ2hhcmdlQmVlQm90XCIsXG5cdFwiQ2hhcmxvdHRlXCIsXG5cdFwiQ2hhdEdMTS1TcGlkZXJcIixcblx0XCJDaGF0d29yayBMaW5rUHJldmlld1wiLFxuXHRcIkNoZWNrSG9zdFwiLFxuXHRcIkdvb2R6ZXJcIixcblx0XCJDaHJvbWUgUHJpdmFjeSBQcmVzZXJ2aW5nIFByZWZldGNoIF
1Byb3h5XCIsXG5cdFwiQ2lycnVzRXhwbG9yZXJcIixcblx0XCJDTEFTU0xBLXdlYlwiLFxuXHRcIkNsZWFyc2NvcGVib3RcIixcblx0XCJXb3JsZEJvdFwiLFxuXHRcIkNsb3VkZmxhcmUtVmFsaWRhdG9yXCIsXG5cdFwiY2xvdWRmbGFyZS1jc3VwXCIsXG5cdFwiQ2xvdWRmbGFyZS1DdXN0b20tRXJyb3ItUGFnZS1DcmF3bGVyXCIsXG5cdFwiQ2xvdWRmbGFyZS1SYWRhci1TY2FubmVyXCIsXG5cdFwiQ2xvdWRmbGFyZS1TcGVlZFRlc3RcIixcblx0XCJDbG91ZGZsYXJlLVN0cmVhbS1Ib29rXCIsXG5cdFwiY29nbml0aXZlU0VPIEJvdFwiLFxuXHRcImNvaGVyZS10cmFpbmluZy1kYXRhLWNyYXdsZXJcIixcblx0XCJDb21tYUZlZWRcIixcblx0XCJyZXNlYXJjaHNjYW5cXFxcLmNvbXN5c1xcXFwucnd0aC1hYWNoZW5cXFxcLmRlXCIsXG5cdFwiY29udGVudGtpbmdhcHBcIixcblx0XCJDb29raWVIdWIgQm90XCIsXG5cdFwiQ290b3lvZ2lcIixcblx0XCJDb3Zlb2JvdFwiLFxuXHRcIkNyYXdsc29uXCIsXG5cdFwiUmVwb0xvb2tvdXRCb3RcIixcblx0XCJDcml0aWNhbGNzc1xcXFwuY29tXCIsXG5cdFwiY3Jvbi1qb2JcXFxcLm9yZ1wiLFxuXHRcIkRuQkNyYXdsZXJcIixcblx0XCJETUJyb3dzZXJcIixcblx0XCJEb21Db3BCb3RcIixcblx0XCJkb3dubm90aWZpZXJcXFxcLmNvbVwiLFxuXHRcIkRvd250aW1lRGV0ZWN0b3JcXFxcL1wiLFxuXHRcIkRsY1xcXFwvXCIsXG5cdFwiRHJhdGFib3RcIixcblx0XCJFYXN5QmliIEF1dG9DaXRlXCIsXG5cdFwiZWFzeWJpbGwtSW1wb3J0TWFuYWdlclwiLFxuXHRcIkVhc3lDcm9uXFxcXC9cIixcblx0XCJlYXN5RE5TIE1vbml0b3JpbmdcIixcblx0XCJFY2hvYm94Qm90XFxcXC9cIixcblx0XCJDcm9ubGVzc1wiLFxuXHRcImNydXN0eVxcXFwvXCIsXG5cdFwiY3NpcnRcXFxcLmN6XCIsXG5cdFwiQ1hLX0JvdFwiLFxuXHRcImRhdW1vYVwiLFxuXHRcIkRhc3BlZWRCb3RcIixcblx0XCJEZWFkIExpbmsgQ2hlY2tlclwiLFxuXHRcIkRlc2t5b2JvdFwiLFxuXHRcIkRldGVjdGlmeVwiLFxuXHRcIkRldmluXCIsXG5cdFwiREYgQm90XCIsXG5cdFwiRGluZ1RhbGtCb3QtTGlua1NlcnZpY2VcIixcblx0XCJEaXNjb3Vyc2UgRm9ydW0gT25lYm94XCIsXG5cdFwiRG1ib3RcIixcblx0XCJTdXN0YWluYWJpbGl0eUNyYXdsZXJcIixcblx0XCJlZGFuc2JvdFwiLFxuXHRcIkVkZ2VXYXRjaFwiLFxuXHRcIkRvIE5vdCBUcmFjayBWZXJpZmllclwiLFxuXHRcImVsbWFoaW8tdXB0aW1lYm90XCIsXG5cdFwiZU1vbmV5Qm90XCIsXG5cdFwiRXBpdm96Q3Jhd2xlclwiLFxuXHRcImVSZXB1Ymxpa1xcXFwudG9vbHNcIixcblx0XCJFdm9VcHRpbWVCb3RcIixcblx0XCJFeG9kdXNNb3ZlbWVudFwiLFxuXHRcIkV6Z2lmXCIsXG5cdFwiZmFjdHNldF9zcHlkZXJib3RcIixcblx0XCJGYXN0bWFpbFVBXCIsXG5cdFwiRkRMIFN0YXRzIEJvdFwiLFxuXHRcIkZlZGljYWJvdFwiLFxuXHRcIkZlZFJlcG9ydGVyRGF0YUJvdFwiLFxuXHRcIkZlZWQgSW1hZ2UgQXVkaXRcIixcblx0XCJGZWVkQnVybmVyXCIsXG5cdFwiZmVlZGVyXFxcXC5jb1wiLFxuXHRcIkZlZWRwcmVzc28gQ29udGVudCBJbmRleCBCb3RcIixcblx0XCJGZWVkd2luZFwiLFxuXHRcImZpZGdldC1zcGlubmVyLWJvdFwiLFxuXHRcIkZpcm1vR3JhcGhcIixcblx0XCJGbGlwYm9hcmRSU1NcIixcblx0XCJGb3JlZ2VuaXhcIixcblx0XCJGcmVlc3Bva2VcXFxcL1wiLFxuXHRcIkZyaWVuZGx5IHRlc3RpbmcgYm90XCIsXG5cdFwiZnJpZW5kbHktc3BpZGVyXCIsXG5cdFwiRnJpZW5kbHlDcmF3bGVyXFxcXC9cIixcblx0XCJGdWxsU3RvcnlCb3RcXFxcL1wiLFxuXHRcIkZ1bm5lbGJhY2tcIixcblx0XCJGdXNlb25Cb3RcXFxcL1wiLFxuXHRcIkdhYmFuemFib3RcXFxcL1wiLFxuXHRcImdkbnBsdXNcXFxcLmNvbVwiLFxuXHRcImdldHRoaXRcXFxcLmNvbVwiLFxuXHRcIkdHIFBlZWtCb3RcIixcblx0XCJHaG9zdCBJbnNwZWN0b3JcIixcblx0XCJnaXRodWItY2Ftb1wiLFxuXHRcIkdsb2JhbFdlYlNlYXJjaFwiLFxuXHRcIkdvbGZlXFxcXC9cIixcblx0XCJHb29nbGUtQXBwcy1TY3JpcHRcIixcblx0XCJHb29nbGVTdGFja2RyaXZlck1vbml0b3JpbmdcIixcblx0XCJHb29nbGVBc3NvY2lhdGlvblNlcnZpY2VcXFxcL1wiLFxuXHRcIkdvb2dsZUltYWdlUHJveHlcIixcblx0XCJHb29nbGVQcm9kdWNlclwiLFxuXHRcIkdvb2dsZWJvdC1JQVxcXFwvXCIsXG5cdFwiR29vZ2xlLVRydXN0LVNlcnZpY2VzXFxcXC9cIixcblx0XCJHb29nbGUtQXJlYTEyMFwiLFxuXHRcIkdvb2dsZS1DbG91ZFZlcnRleEJvdFwiLFxuXHRcIkdvb2dsZUFzc29jaWF0aW9uU2VydmljZSRcIixcblx0XCJHb29nbGVEb2NzXCIsXG5cdFwiR29QYXlcIixcblx0XCJHb3RTaXRlTW9uaXRvclxcXFwuY29tXCIsXG5cdFwic3ludGhldGljLW1vbml0b3JpbmctYWdlbnRcXFxcL1wiLFxuXHRcIkdyYW1tYXJseVxcXFwvXCIsXG5cdFwiZ3JlZ2NyYXdsZXJcIixcblx0XCJHcm9vdmluYUFkc2JvdFxcXFwvXCIsXG5cdFwiR3JvdmVyXFxcXC9cIixcblx0XCJHVG1ldHJpeFwiLFxuXHRcIkd1ZXN0cG9zdHNCb3RcXFxcL1wiLFxuXHRcIkd1bHBlciBXZWIgQm90XCIsXG5cdFwiVmVyaXR5XFxcXC9cIixcblx0XCJIYXBweVdpbmdcIixcblx0XCJoYXJzaWxib3RcXFxcL1wiLFxuXHRcIkhhd2FpaUJvdFwiLFxuXHRcImhDYXJkVmFsaWRhdG9yXCIsXG5cdFwiSGVsbG8gV29ybGRcIixcblx0XCJIZWxsb3dvcmtKb2JQb3N0aW5nQm90XFxcXC9cIixcblx0XCJIZXRyaXhUb29sc1wiLFxuXHRcIkhJRklCb3RcXFxcL1wiLFxuXHRcIkhsaWRhbVxcXFwudG8gcm9ib3RcIixcblx0XCJIb25leWJhZGdlciBVcHRpbWUgQ2hlY2tcIixcblx0XCJIb3N0VHJhY2tlclxcXFwvXCIsXG5cdFwiSG90amFyXCIsXG5cdFwiaHN0c3ByZWxvYWQtYm90XCIsXG5cdFwiSHVja2Fib3RcXFxcL1wiLFxuXHRcIkh5cGUgTWFjaGluZVxcXFwvXCIsXG5cdFwiV2ViIFNjcmVlbiBTZXJ2aWNlIEJ5IGh5cGVyaG9zdFwiLFxuXHRcIkFkc0JvdC1JQUJcIixcblx0XCJpQXNrQm90XFxcXC9cIixcblx0XCJJQk0gQ3Jhd2xlclwiLFxuXHRcIklGVFRUXFxcXC9cIixcblx0XCJJbWFnZUZldGNoZXJcXFxcL1wiLFxuXHRcIkltYWdlTWluZFwiLFxuXHRcImltZzJkYXRhc2V0XCIsXG5cdFwiaW1ncHJveHlcXFxcL1wiLFxuXHRcImltcGVuZG9vbS1ib3RcXFxcL1wiLFxuXHRcIkluZGVlZEpvYkJvdFwiLFxuXHRcIklubmd1bWFcXFxcL1wiLFxuXHRcIkluc3RhcGFwZXJcXFxcL1wiLFxuXHRcIkludGVncm9tYXRcXFxcL1wiLFxuXHRcImludGVseFxcXFwuaW9fYm90XCIsXG5cdFwiaW50ZXJuZXRWaXN0YSBtb25pdG9yXCIsXG5cdFwiSXJva2V6XFxcXC5jeiBtb25pdG9yaW5nXCIsXG5cdFwiSXNEb3duQm90XFxcXC9cIixcblx0XCJJU1NDeWJlclJpc2tDcmF3bGVyXFxcXC9cIixcblx0XCJpdWJlbmRhLXJhZGFyXFxcXC9cIixcblx0XCJVcHRpbWVCb3RcXFxcL1wiLFxuXHRcImpldG1vblxcXFwvXCIsXG5cdFwiam9ic3dpdGhncHRjb20tYm90XCIsXG5cdFwiSnVtaW9cIixcblx0XCJLYWdpYm90XFxcXC9cIixcblx0XCJLYW5nYXJvb0JvdFxcXFwvXCIsXG5cdFwiS2FyZ29Cb3QtQXJ0ZW1pc1wiLFxuXHRcImthemJ0Ym90XFxcXC9cIixcblx0XCJrZXljZG4tdG9vbHNcXFxcL1wiLFxuXHRcImtleXMtc28tYm90XCIsXG5cdFwia2luc3RhLWJvdFwiLFxuXHRcIktsYXZpeW9cXFxcL1wiLFxuXHRcIkt1a2VpXFxcXC5ldS1Cb3RcXFxcL1wiLFxuXHRcIkxBQ19JQUhhcnZlc3RlclwiLFxuXHRcIkxhc3RNb2RCb3RcXFxcL1wiLFxuXHRcIkxlZ2FsTW9uc3RlclwiLFxuXHRcIkxldCdzIEVuY3J5cHRcIixcblx0XCJMZXZlbDlTZWFyY2hCb3RcXFxcL1wiLFxuXHRcImxvY1xcXFwuZ292XFxcXC9wcm9ncmFtc1xcXFwvd2ViLWFyY2hpdmluZ1wiLFxuXHRcIkxpbmVyQm90XFxcXC9cIixcblx0XCJMaW5rVGlnZXJcIixcblx0XCJMaW5rQWNlXFxcXC9cIixcblx0XCJMaW5rc0luZGV4ZXJCb3RcXFxcL1wiLFxuXHRcIkxpbmtXYWxrZXJcXFxcL1wiLFxuXHRcIkxvZ2ljTW9uaXRvclwiLFxuXHRcIkxvb21seUJvdFwiLFxuXHRcIk1hY3JvYm9uZGJvdFwiLFxuXHRcIk1BREJib3RcXFxcL1wiLFxuXHRcIk1hZ2VsbGFuXCIsXG5cdFwibWFnaWNzZWFyY2hkZXZcXFxcL1wiLFxuXHRcIk1hZ25ldFxcXFwubWUtd2ViXFxcXC9cIixcblx0XCJNYWluV1BcXFxcL1wiLFxuXHRcIk1ha2VcXFxcL1wiLFxuXHRcIk1hbmFnZVdQXCIsXG5cdFwiTWFya2V0R29vXFxcXC9cIixcblx0XCJNYXJrZXRpbmdNaW5lclwiLFxuXHRcImRib3RcXFxcKVwiLFxuXHRcIk1hdHRlcm1vc3QtQm90XFxcXC9cIixcblx0XCJNYXZpZmluZHNcIixcblx0XCJNQi1MaW5rQ2hlY2tlclwiLFxuXHRcIk1lZGlhbG9naWFCb3RcIixcblx0XCJNZWRpYU1vbml0b3JpbmdCb3RcXFxcL1wiLFxuXHRcIk1lZGlhdmluZU1ldGFkYXRhUGFyc2VyXFxcXC9cIixcblx0XCJQeXdpa2lib3RcXFxcL1wiLFxuXHRcIkNlbnRDb21Cb3RcXFxcL1wiLFxuXHRcIk1lcmdhZG9Cb3RcIixcblx0XCJNZXRhLUV4dGVybmFsSGl0XFxcXC9cIixcblx0XCJNZXRvcmlrXCIsXG5cdFwiTWdpZEJvdFwiLFxuXHRcIk1pbmlhdHVyZVxcXFwuaW9cXFxcL1wiLFxuXHRcIm1pcnJvcndlYlxcXFwuY29tXCIsXG5cdFwiTWlzc2luZ2xldHRyQm90XFxcXC9cIixcblx0XCJjcmF3bGVyX2ViX2dlcm1hbnlcIixcblx0XCJNb2R1bGFyQ29ubmVjdG9yXFxcXC9cIixcblx0XCJNb2xsaWUgSFRUUCBjbGllbnRcIixcblx0XCJNb25pYm90XCIsXG5cdFwibW9uaXRpcyAtXCIsXG5cdFwiTW9uaXRvUlNTXFxcXC9cIixcblx0XCJNb25TcGFya1xcXFwvXCIsXG5cdFwibW9udGFzdGljLW1vbml0b3JcIixcblx0XCJNb25Ub29sc1xcXFwuY29tXCIsXG5cdFwiTW90b01pbmVyQm90XFxcXC9cIixcblx0XCJNUkdib3RcXFxcL1wiLFxuXHRcIk14VG9vbGJveFwiLFxuXHRcIm15LXRpbnktYm90XCIsXG5cdFwiTXlCb3RcXFxcL1wiLFxuXHRcIm5iZXJ0YXVwZXRlOTVcIixcblx0XCJOZXRBUElcIixcblx0XCJOZXRwZWFrQ2hlY2tlckJvdFxcXFwvXCIsXG5cdFwiTmV0U2hlbHRlciBDb250ZW50U2NhblwiLFxuXHRcIk5FVFZJR0lFXCIsXG5cdFwiTmV3UmVsaWNib3RcXFxcL1wiLFxuXHRcIm55dF9zY3JhcGluZ1wiLFxuXHRcIk5ld3NOb3dcXFxcL1wiLFxuXHRcIk5MTlpfSUFIYXJ2ZXN0ZXJcIixcblx0XCJOb2RlUGluZ1wiLFxuXHRcIm5vbW9yZTQwNFxcXFwuY29tIHJvYm90XCIsXG5cdFwibm9vcm9ib3RcIixcblx0XCJOb29zaHViXFxcXC9cIixcblx0XCJOb3RhYm90XCIsXG5cdFwiTm92YWFjdFxcXFwvXCIsXG5cdFwiTm92ZWxsdW1cIixcblx0XCJOc1Rvb2xzQm90XFxcXC9cIixcblx0XCJudmRvcnpcIixcblx0XCJPZGluO1wiLFxuXHRcIk9mZmxpbmUgRXhwbG9yZXJcIixcblx0XCJPaERlYXJcXFxcL1wiLFxuXHRcIk9tbmlzZW5kXFxcXC9cIixcblx0XCJPbmxpbmUgRG9tYWluIFRvb2xzXCIsXG5cdFwiV2ViQ0VPIE9ubGluZVxcXFwvXCIsXG5cdFwiT25saW5lT3JOb3RcXFxcLmNvbV9ib3RcIixcblx0XCJPcGVuR3JhcGhcXFxcLmlvXFxcXC9cIixcblx0XCJPcGVuUlNTXCIsXG5cdFwiT3BlblZBU1wiLFxuXHRcIk93bGVyIFxcXFwob3dzXFxcXC5ldVwiLFxuXHRcIk9wZXJhdG9yXFxcXC9cIixcblx0XCJPcmJib3RcXFxcL1wiLFxuXHRcInplYnJhLXYyLWJvdFwiLFxuXHRcIk9ybG8tTGlua1ByZXZpZXdcXFxcL1wiLFxuXHRcIkNvemktaUNhbGVuZGFyLUZlZWRSZWFkZXJcIixcblx0XCJPdXRzZWxsVVJMVmFsaWRhdG9yXCIsXG5cdFwiT3ZlcmNhc3RcXFxcL1wiLFxuXHRcIlBSVEdDbG91ZEJvdFxcXFwvXCIsXG5cdFwiUGFnZXNwZWVkXFxcXC9cIixcblx0XCJQYW5ndUJvdFwiLFxuXHRcIlBhbm9wdGFcIixcblx0XCJQYXFsZWJvdFxcXFwvXCIsXG5cdFwicGFyc2VcXFxcLmx5IHNjcmFwZXJcXFxcL1wiLFxuXHRcIlBheVBhbFxcXFwvXCIsXG5cdFwiUERGMjQgVVJMIFRvIFBERlwiLFxuXHRcIlBpbmdBZG1pblxcXFwuUnVcXFxcL1wiLFxuXHRcInBpbmdwaW5nXFxcXC5pb1xcXFwvXCIsXG5cdFwiUGxheVN0b3JlLUdvb2dsZVwiLFxuXHRcIlBsZXNrIHNjcmVlbnNob3QgYm90XCIsXG5cdFwiUG9ja2V0Q2FzdHNcXFxcL1wiLFxuXHRcIlBvdGlvbnNcXFxcL1wiLFxuXHRcIlByZXNzRW5naW5lQm90XCIsXG5cdFwiUHJpY2Vkcm9uZVNob3BwaW5nQm90XFxcXC9cIixcblx0XCJQcmlFY29Cb3RcXFxcL1wiLFxuXHRcIlByaW50RnJpZW5kbHlcXFxcLmNvbVwiLFxuXHRcIlByby1TaXRlbWFwc1xcXFwvXCIsXG5cdFwiUHJvYmVseVNQRFJcXFxcL1wiLFxuXHRcIlByb2plY3RTaGllbGQtVXJsQ2hlY2tcIixcblx0XCJCbGFja2JveCBFeHBvcnRlclxcXFwvXCIsXG5cdFwiUHJvdG9wYWdlXFxcXC9cIixcblx0XCJQU19EYWlseVxcXFwvXCIsXG5cdFwicHVsc2V0aWNcXFxcLmNvbVwiLFxuXHRcIlBXQUJ1aWxkZXJIdHRwQWdlbnRcIixcblx0XCJRdWFsaWZpZWRCb3RcXFxcL1wiLFxuXHRcIlF1YW50Y2FzdGJvdFxcXFwvXCIsXG5cdFwiUmFja3NwYWNlIE1vbml0b3JpbmdcXFxcL1wiLFxuXHRcInJha3V0ZW51c2Fib3QtaW1hZ2VcXFxcL1wiLFxuXHRcInRvcDEwMFxcXFwucmFtYmxlclxcXFwucnUgY3Jhd2xlclwiLFxuXHRcIlJhbmt1ckJvdFxcXFwvXCIsXG5cdFwiUmF2ZW5DcmF3bGVyXFxcXC9cIixcblx0XCJSZWFkYWJsZVxcXFwvXCIsXG5cdFwiUmVjdXJseSBX
1ZWJob29rc1xcXFwvXCIsXG5cdFwiUkVEXFxcXC9cIixcblx0XCJSZWVsZXZhbnRcXFxcL1wiLFxuXHRcInJlbW92ZVxcXFwuYmdcXFxcL1wiLFxuXHRcIlJldG9vbFxcXFwvXCIsXG5cdFwiUmV0cm9MaXN0ZUNPTVxcXFwvXCIsXG5cdFwiUmV2dmltR29ydFxcXFwvXCIsXG5cdFwicmV3YXJkLWdhdGV3YXlcIixcblx0XCJSaWRkbGVyIFxcXFwoaHR0cDpcXFxcL1xcXFwvcmlkZGxlclxcXFwuaW9cIixcblx0XCJSb2JvdHNDaGVja2VyXFxcXC9cIixcblx0XCJSU1NBUElcXFxcL1wiLFxuXHRcInJzczJ0Z1wiLFxuXHRcIlJzc1JlYWRlckJvdFwiLFxuXHRcInM0YS1wcm9iZS1ib3RcXFxcL1wiLFxuXHRcIlNGREMtQ2FsbG91dFxcXFwvXCIsXG5cdFwicGFnZS1wcmV2aWV3LXRvb2xcIixcblx0XCJTYW5kb2JhQ3Jhd2xlclxcXFwvXCIsXG5cdFwiU2Fuc2VjIFNlY3VyaXR5IE1vbml0b3JcXFxcL1wiLFxuXHRcIkdJRlRFRFZJU0lUT1IgU0NBTlwiLFxuXHRcIlNjaGVtYS1NYXJrdXAtVmFsaWRhdG9yXCIsXG5cdFwiU2Nvb3BcXFxcLml0XFxcXC9cIixcblx0XCJTY291clJTU0JvdFxcXFwvXCIsXG5cdFwiU2NyYXBlaGVyb0JvdFxcXFwvXCIsXG5cdFwic2NyZWVlbmx5LWJvdFwiLFxuXHRcIlNFQm90LVdBXCIsXG5cdFwiU2VhcmNoZXJ3ZWJcIixcblx0XCJTZWFyY2hlcnh3ZWJcIixcblx0XCJTZWFyY2hFeHByZXNzXCIsXG5cdFwiU2VjdXJpdHlIZWFkZXJzXCIsXG5cdFwic2VtYWx0Ym90XFxcXC9cIixcblx0XCJTZW5kR3JpZCBFdmVudCBBUElcIixcblx0XCJTZW50cnlVcHRpbWVCb3RcXFxcL1wiLFxuXHRcInNlby1hdWRpdC1jaGVjay1ib3RcXFxcL1wiLFxuXHRcInM0YVxcXFwvXCIsXG5cdFwiQ2xhcml0eUJvdFxcXFwvXCIsXG5cdFwiU2VvU2l0ZUNoZWNrdXBcIixcblx0XCJTZW91bEJvdFwiLFxuXHRcIlNFUlB0aW1pemVyQm90XCIsXG5cdFwiU2VydmVyIERlbnNpdHkgU2VydmljZSBNb25pdG9yaW5nXCIsXG5cdFwiU2VydmVySHVudGVyU3BpZGVyXFxcXC9cIixcblx0XCJTZXpuYW1Ib21lcGFnZUNyYXdsZXJcXFxcL1wiLFxuXHRcIlNob3BpZnktQ2FwdGFpbi1Ib29rXCIsXG5cdFwiU2hvcnR3YXZlIEltYWdlIEZldGNoZXJcIixcblx0XCJsaW5rUmVhZGVyXFxcXC9cIixcblx0XCJTaWRldHJhZGUgaW5kZXhlciBib3RcIixcblx0XCJeU2lsa1xcXFwvXCIsXG5cdFwiU2luY2VyYVN5bnRoZXRpY1VzZXJcXFxcL1wiLFxuXHRcIk9wdGltaXplclxcXFwpXCIsXG5cdFwiU2l0ZTI0eDdcIixcblx0XCJTaXRlQXVkaXRCb3RcXFxcL1wiLFxuXHRcIlNpdGVDaGVjay1zaXRlY3Jhd2xcIixcblx0XCJTaXRlU2NvcmVCb3RcIixcblx0XCJTaXRlU2VhcmNoMzYwXFxcXC9cIixcblx0XCJTaXRlVXB0aW1lXFxcXC5jb21cIixcblx0XCJLb250dXJib3RcXFxcL1wiLFxuXHRcIlNrcm91dHpCb3RcIixcblx0XCJTa3l3b3JrU3BpZGVyXCIsXG5cdFwiU2xpY2tCb3RcXFxcL1wiLFxuXHRcIlNtYXJ0b2xvZ3lCb3RcXFxcL1wiLFxuXHRcIlNuYXBVUkxQcmV2aWV3XFxcXC9cIixcblx0XCJTbmFwY2hhdEFkc1xcXFwvXCIsXG5cdFwiU25pcGNhcnRcXFxcL1wiLFxuXHRcInNvbGFyd2luZHNcXFxcL1wiLFxuXHRcIlNvcmEgUE9TXFxcXC9cIixcblx0XCJTcGFya1NoaXBwaW5nXCIsXG5cdFwiU3BhcmtQb3N0XCIsXG5cdFwiU3Bhd25pbmctQUlcIixcblx0XCJJREdcXFxcL0VVXCIsXG5cdFwiU3BlY2lmaWNmZWVkc1wiLFxuXHRcIlNwZWN0YXRlXFxcXC9cIixcblx0XCJTcGlkZXJMaW5nXCIsXG5cdFwic3BsYXNoIFZlcnNpb25cXFxcL1wiLFxuXHRcIlJpZ29yXFxcXClcIixcblx0XCJUd2luV2F2ZVNjYW5uZXJcIixcblx0XCJTU0wgTGFicyBcXFxcKGh0dHBzOlxcXFwvXFxcXC93d3dcXFxcLnNzbGxhYnNcXFxcLmNvbVwiLFxuXHRcIlNTU1NCb3RcXFxcL1wiLFxuXHRcIlN0YXBlXFxcXC9cIixcblx0XCJTdGFydHBhZ2VQcml2YXRlSW1hZ2VQcm94eVxcXFwvXCIsXG5cdFwiU3RhdGFib3RcXFxcL1wiLFxuXHRcIlN0YXRpc3Rpa0F1c3RyaWFcXFxcL1wiLFxuXHRcIlN0YXRzRHJvbmVCb3RcIixcblx0XCJTdHJpcGVcXFxcL1wiLFxuXHRcIlN1Y3VyaVwiLFxuXHRcIlN2aXgtV2ViaG9va3NcXFxcL1wiLFxuXHRcIlN3aWZ0ZXFMaW5rQ2hlY2tlclwiLFxuXHRcIlN3aXNzY293c1wiLFxuXHRcIkRhdGFkb2cgU3ludGhldGljXCIsXG5cdFwiVGFjdGlTY291dFxcXFwvXCIsXG5cdFwidGNoZWxlYmlcXFxcL1wiLFxuXHRcImJpdGRpc2NvdmVyeVwiLFxuXHRcIlRlc3QgQ2VydGlmaWNhdGUgSW5mb1wiLFxuXHRcIlRlc3RjcmF3bGVyXCIsXG5cdFwidGVzdC1ib3RcIixcblx0XCJUZXN0TG9jYWxseVxcXFwvXCIsXG5cdFwiVGVzdFVSSVwiLFxuXHRcIlRleHRSYXpvclwiLFxuXHRcIlRoZSBLbm93bGVkZ2UgQUlcIixcblx0XCJUaGVJbnRlcm5ldFNlYXJjaHhcIixcblx0XCJ0aGVzaXMtcmVzZWFyY2gtYm90XCIsXG5cdFwiVHJlbGxpcy1TZXJ2aWNlc1wiLFxuXHRcInRyZW50d2lsXFxcXC5lc1wiLFxuXHRcIlRydXN0bHlcXFxcL1wiLFxuXHRcIlRURC1Db250ZW50XCIsXG5cdFwiVHdlYWtlcnNcIixcblx0XCJUd2lsaW9Qcm94eVxcXFwvXCIsXG5cdFwiVUFTbGlua0NoZWNrZXJcXFxcL1wiLFxuXHRcImhnZkFscGhhWENyYXdsXFxcXC9cIixcblx0XCJVbnNob3J0ZW5cX
1FxcLkl0XFxcXCFcIixcblx0XCJ1cGRvd25cXFxcLmlvXCIsXG5cdFwiVXB0aW1lXFxcXC9cIixcblx0XCJ1cHRpbWVkb2N0b3JcIixcblx0XCJVcHRpbWlhXCIsXG5cdFwidXB0cmVuZHNcIixcblx0XCJVcmxjaGVja3JcXFxcL1wiLFxuXHRcIlVSTFN1TWFCb3RcIixcblx0XCJ1c2VlQm9va0NoZWNrZXJcXFxcL1wiLFxuXHRcIlZhZ2Fib25kb1xcXFwvXCIsXG5cdFwiVmF1bHRQcmVzc1wiLFxuXHRcInZpZGVvb3R2Qm90XCIsXG5cdFwiVnN1U2VhcmNoU3BpZGVyXFxcXC9cIixcblx0XCJ2dS1zZXJ2ZXItaGVhbHRoLXNjYW5uZXJcXFxcL1wiLFxuXHRcIldBUkRCb3RcXFxcL1wiLFxuXHRcIldlYnNpdGVPcHNcIixcblx0XCJXYXRjaE1vdXNlXCIsXG5cdFwiV2ViIE1lYXN1cmVcXFxcL1wiLFxuXHRcIldlYmZsb3dcIixcblx0XCJ3ZWJnYWlucy1ib3RcIixcblx0XCJ3ZWJwcm9zYm90XFxcXC9cIixcblx0XCJ3ZWJzaXRlcHVsc2VcIixcblx0XCJXZWJTbmlmZmVyXFxcXC9cIixcblx0XCJXU01cXFxcL1wiLFxuXHRcIldlYndpa2lCb3RcXFxcL1wiLFxuXHRcIldFRE9TIE9uTGluZVwiLFxuXHRcIldoYXRzTXlJUFxcXFwub3JnXCIsXG5cdFwiV2hhdFdlYlxcXFwvXCIsXG5cdFwiV2hlcmVnb2VzXFxcXC5jb21cIixcblx0XCJ3aGVyZXNpdHVwXFxcXC5jb21cXFxcL1wiLFxuXHRcIkNpdG9pZFwiLFxuXHRcIldpcmVSZWFkZXJCb3RcXFxcL1wiLFxuXHRcIlpvdGVyb1RyYW5zbGF0aW9uU2VydmVyXFxcXC9XTUZcIixcblx0XCJ3bXRpcHNcXFxcLmNvbVxcXFwvXCIsXG5cdFwiV29yZENvdW50Qm90XFxcXC9cIixcblx0XCJXb3JkdXAtMVwiLFxuXHRcIndvcmtvbmEtZmF2aWNvbi1zZXJ2aWNlXFxcXC9cIixcblx0XCJJbmR5IExpYnJhcnlcIixcblx0XCJXSkhST1xcXFwvXCIsXG5cdFwiV29ybWx5Qm90XCIsXG5cdFwiV292bkNyYXdsZXJcXFxcL1wiLFxuXHRcIndvd0xpbmsgQ3Jhd2xlclxcXFwvXCIsXG5cdFwiV1AgVGltZSBDYXBzdWxlXCIsXG5cdFwiV1BVbWJyZWxsYVwiLFxuXHRcIndwYm90XFxcXC9cIixcblx0XCJXUE1VIERFViBCcm9rZW4gTGluayBDaGVja2VyXCIsXG5cdFwiV1BNVURFViBVcHRpbWUgTW9uaXRvclwiLFxuXHRcIldQU2VjXFxcXC9cIixcblx0XCJXUlROQm90XCIsXG5cdFwiYWJ1c2VcXFxcLnhtY29cXFxcLmZyXCIsXG5cdFwiWFktQXJjaGl2ZS1Db21wbGlhbmNlXCIsXG5cdFwiWWFob28gQWQgbW9uaXRvcmluZ1wiLFxuXHRcIllhaG9vTWFpbFByb3h5XCIsXG5cdFwiWWFob29DYWNoZVN5c3RlbVwiLFxuXHRcIllMVCBDaHJvbWVcIixcblx0XCJZb2tveUdyb3VwQUdcXFxcL1wiLFxuXHRcIll1dXBlcmJvdFwiLFxuXHRcIlphcGllclwiLFxuXHRcIlplbmRlc2sgV2ViaG9va1wiLFxuXHRcIlpvbWJpZWJvdFxcXFwvXCIsXG5cdFwienpoYm90XCIsXG5cdFwiUGVudGhvdXNlIENyaXRpY2FsIFBhdGggQ1NTIEdlbmVyYXRvclwiLFxuXHRcIkdvb2dsZS1BZFdvcmRzLUV4cHJlc3NcIixcblx0XCJOb3Rpb25cXFxcL1wiLFxuXHRcIlNTTCBMYWJzJFwiLFxuXHRcIlNrcm91dHogSW1hZ2VCb3RcIixcblx0XCJUdW1ibHJcXFxcL1wiLFxuXHRcInVwZGF5XFxcXC9cIixcblx0XCJ3YXRjaFRvd3JcIixcblx0XCJQUlRHIE5ldHdvcmsgTW9uaXRvclwiLFxuXHRcIkdlZWRvU2hvcFByb2R1Y3RGaW5kZXJcIlxuXTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../assets/src/scripts/rudder/bot-patterns.generated.js\n\n}')},"../assets/src/scripts/rudder/main.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _rudderTools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./rudderTools */ "../assets/src/scripts/rudder/rudderTools.js");\n/* harmony import */ var _rudderVideo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./rudderVideo */ "../assets/src/scripts/rudder/rudderVideo.js");\n/* harmony import */ var _rudderNoa__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./rudderNoa */ "../assets/src/scripts/rudder/rudderNoa.js");\n/* harmony import */ var _rudderHtml5Media__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./rudderHtml5Media */ "../assets/src/scripts/rudder/rudderHtml5Media.js");\n\n\n\n\nwindow.rudderTools = new _rudderTools__WEBPACK_IMPORTED_MODULE_0__["default"]();\nwindow.rudderTools.init();\nwindow.rudderVideo = new _rudderVideo__WEBPACK_IMPORTED_MODULE_1__["default"]();\nwindow.rudderVideo.init();\nwindow.rudderNoa = new _rudderNoa__WEBPACK_IMPORTED_MODULE_2__["default"]();\nwindow.rudderNoa.init();\nwindow.rudderHtml5Media = new _rudderHtml5Media__WEBPACK_IMPORTED_MODULE_3__["default"]();\nwindow.rudderHtml5Media.init();//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9tYWluLmpzIiwibWFwcGluZ3MiOiI7Ozs7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZm9yZWlnbnBvbGljeS1idWlsZC8uLi9hc3NldHMvc3JjL3NjcmlwdHMvcnVkZGVyL21haW4uanM/NDBiZSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUnVkZGVyVG9vbHMgZnJvbSAnLi9ydWRkZXJUb29scyc7XG5pbXBvcnQgUnVkZGVyVmlkZW8gZnJvbSAnLi9ydWRkZXJWaWRlbyc7XG5pbXBvcnQgUnVkZGVyTm9hIGZyb20gJy4vcnVkZGVyTm9hJztcbmltcG9ydCBSdWRkZXJIdG1sNU1lZGlhIGZyb20gJy4vcnVkZGVySHRtbDVNZWRpYSc7XG5cbndpbmRvdy5ydWRkZXJUb29scyA9IG5ldyBSdWRkZXJUb29scygpO1xud2luZG93LnJ1ZGRlclRvb2xzLmluaXQoKTtcblxud2luZG93LnJ1ZGRlclZpZGVvID0gbmV3IFJ1ZGRlclZpZGVvKCk7XG53aW5kb3cucnVkZGVyVmlkZW8uaW5pdCgpO1xuXG53aW5kb3cucnVkZGVyTm9hID0gbmV3IFJ1ZGRlck5vYSgpO1xud2luZG93LnJ1ZGRlck5vYS5pbml0KCk7XG5cbndpbmRvdy5ydWRkZXJIdG1sNU1lZGlhID0gbmV3IFJ1ZGRlckh0bWw1TWVkaWEoKTtcbndpbmRvdy5ydWRkZXJIdG1sNU1lZGlhLmluaXQoKTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../assets/src/scripts/rudder/main.js\n\n}')},"../assets/src/scripts/rudder/rudderHtml5Media.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/classCallCheck */ "./node_modules/@babel/runtime/helpers/esm/classCallCheck.js");\n/* harmony import */ var _babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @babel/runtime/helpers/createClass */ "./node_modules/@babel/runtime/helpers/esm/createClass.js");\n/* harmony import */ var _rudderMedia__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./rudderMedia */ "../assets/src/scripts/rudder/rudderMedia.js");\n\n\nfunction _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }\nfunction _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }\nfunction _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }\n/**\n * Native HTML5 media tracking â any <audio>/<video> a template marks with\n * `data-rudder-media-player="html5"`. Discovery is purely attribute-driven: the\n * surface comes from `data-rudder-media-surface`, so one loop serves\n * article podcast embeds, podcast section players rendered as native audio, and\n * FP Live call recordings (`fp_live_audio`) alike â the DOM says what each is.\n *\n * These are plain browser controls, not Plyr â Plyr-wrapped players use\n * attachPlyrTracking instead. Reuses attachMediaTracking for the shared\n * play/finish/milestone loop.\n *\n *
1Late / gated embeds: {@link observeDynamicMedia} (shared with rudderVideo).\n */\n\n\n\n/**\n * Native players opt in with `data-rudder-media-player="html5"` at (or above)\n * the element level. Anything without it â Plyr, NOA, soundcloud/iframe embeds\n * â is handled by its own module and must not be double-tracked here.\n */\nvar HTML5_MEDIA_SELECTOR = \'[data-rudder-media-player="html5"]\';\nvar RudderHtml5Media = /*#__PURE__*/function () {\n function RudderHtml5Media() {\n (0,_babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_0__["default"])(this, RudderHtml5Media);\n this.isInitialized = false;\n /** @type {(() => void)|null} */\n this.unsubscribeDynamic = null;\n }\n\n /**\n * @returns {void}\n */\n return (0,_babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_1__["default"])(RudderHtml5Media, [{\n key: "init",\n value: function init() {\n var _this = this;\n if (this.isInitialized) return;\n this.isInitialized = true;\n if (document.readyState === \'loading\') {\n document.addEventListener(\'DOMContentLoaded\', function () {\n return _this.start();\n }, {\n once: true\n });\n } else {\n this.start();\n }\n }\n\n /**\n * Attach to existing media, then always watch for late/gated ones so the\n * first injected html5 player on an otherwise empty page is still tracked.\n *\n * @returns {void}\n */\n }, {\n key: "start",\n value: function start() {\n var _this2 = this;\n this.attachAll(document);\n // Always subscribe â do not gate on "already has html5" (that missed\n // first late inject). Shared observer is a no-op cost when idle.\n if (!this.unsubscribeDynamic) {\n this.unsubscribeDynamic = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_2__.observeDynamicMedia)(function (nodes) {\n var _iterator = _createForOfIteratorHelper(nodes),\n _step;\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var _node$matches, _node$querySelector;\n var node = _step.value;\n if ((_node$matches = node.matches) !== null && _node$matches !== void 0 && _node$matches.call(node, HTML5_MEDIA_SELECTOR) || (_node$querySelector = node.querySelector) !== null && _node$querySelector !== void 0 && _node$querySelector.call(node, HTML5_MEDIA_SELECTOR)) {\n _this2.attachAll(node);\n }\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n });\n }\n }\n\n /**\n * @param {ParentNode|Element} root\n * @returns {Element[]}\n */\n }, {\n key: "collect",\n value: function collect(root) {\n var _root$matches;\n var out = [];\n if (!root || root.nodeType !== 1 && root.nodeType !== 9) return out;\n if (root.nodeType === 1 && (_root$matches = root.matches) !== null && _root$matches !== void 0 && _root$matches.call(root, HTML5_MEDIA_SELECTOR)) {\n out.push(root);\n }\n if (typeof root.querySelectorAll === \'function\') {\n root.querySelectorAll(HTML5_MEDIA_SELECTOR).forEach(function (el) {\n out.push(el);\n });\n }\n return out;\n }\n\n /**\n * @param {ParentNode} [root=document]\n * @returns {void}\n */\n }, {\n key: "attachAll",\n value: function attachAll() {\n var _this3 = this;\n var root = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;\n var scope = root === document ? document.documentElement : root;\n this.collect(scope).forEach(function (el) {\n try {\n _this3.attach(el);\n } catch (_err) {\n // Tracking must never break playback\n }\n });\n }\n\n /**\n * @param {Element} el the tagged element (usually the media element itself)\n * @returns {void}\n */\n }, {\n key: "attach",\n value: function attach(el) {\n var _el$querySelector, _mediaEl$dataset;\n if (!el) return;\n\n // The attribute normally sits on the media element (player level); allow\n // a wrapper too, and resolve to the actual <audio>/<video> it holds.\n var mediaEl = el.tagName === \'AUDIO\' || el.tagName === \'VIDEO\' ? el : (_el$querySelector = el.querySelector) === null || _el$querySelector === void 0 ? void 0 : _el$querySelector.call(el, \'audio, video\');\n if (!mediaEl || typeof mediaEl.addEventListener !== \'function\') return;\n if (((_mediaEl$dataset = mediaEl.dataset) === null || _mediaEl$dataset === void 0 ? void 0 : _mediaEl$dataset.rudderTracked) === \'html5\') return;\n\n // Surface, player type and context all come from the DOM (data-rudder-*).\n var resolved = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_2__.resolveMetaFromDom)(el);\n var eventName = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_2__.eventNameForSurface)(resolved.surface);\n if (!eventName) return; // untagged / unknown surface â not tracked\n\n mediaEl.dataset.rudderTracked = \'html5\';\n (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_2__.attachMediaTracking)(mediaEl, function (event, cb) {\n return mediaEl.addEventListener(event, cb);\n }, {\n eventName: eventName,\n meta: resolved,\n el: el,\n getPlayIntent: function getPlayIntent() {\n return (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_2__.playIntentFromMeta)(resolved);\n },\n player: resolved.player || \'html5\'\n });\n }\n }]);\n}();\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (RudderHtml5Media);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJIdG1sNU1lZGlhLmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQVFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBR0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUZBO0FBQUE7QUFBQTtBQUdBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUxBO0FBQUE7QUFBQTtBQU1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBSUE7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUhBO0FBQUE7QUFBQTtBQUlBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBSEE7QUFBQTtBQUFBO0FBSUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUhBO0FBQUE7QUFBQTtBQUlBO0FBQ0E7O0F
1BRUE7QUFDQTtBQUNBO0FBSUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUVBO0FBRUE7QUFBQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUFBO0FBQUE7QUFHQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJIdG1sNU1lZGlhLmpzP2I3ZTQiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBOYXRpdmUgSFRNTDUgbWVkaWEgdHJhY2tpbmcg4oCUIGFueSA8YXVkaW8+Lzx2aWRlbz4gYSB0ZW1wbGF0ZSBtYXJrcyB3aXRoXG4gKiBgZGF0YS1ydWRkZXItbWVkaWEtcGxheWVyPVwiaHRtbDVcImAuIERpc2NvdmVyeSBpcyBwdXJlbHkgYXR0cmlidXRlLWRyaXZlbjogdGhlXG4gKiBzdXJmYWNlIGNvbWVzIGZyb20gYGRhdGEtcnVkZGVyLW1lZGlhLXN1cmZhY2VgLCBzbyBvbmUgbG9vcCBzZXJ2ZXNcbiAqIGFydGljbGUgcG9kY2FzdCBlbWJlZHMsIHBvZGNhc3Qgc2VjdGlvbiBwbGF5ZXJzIHJlbmRlcmVkIGFzIG5hdGl2ZSBhdWRpbywgYW5kXG4gKiBGUCBMaXZlIGNhbGwgcmVjb3JkaW5ncyAoYGZwX2xpdmVfYXVkaW9gKSBhbGlrZSDigJQgdGhlIERPTSBzYXlzIHdoYXQgZWFjaCBpcy5cbiAqXG4gKiBUaGVzZSBhcmUgcGxhaW4gYnJvd3NlciBjb250cm9scywgbm90IFBseXIg4oCUIFBseXItd3JhcHBlZCBwbGF5ZXJzIHVzZVxuICogYXR0YWNoUGx5clRyYWNraW5nIGluc3RlYWQuIFJldXNlcyBhdHRhY2hNZWRpYVRyYWNraW5nIGZvciB0aGUgc2hhcmVkXG4gKiBwbGF5L2ZpbmlzaC9taWxlc3RvbmUgbG9vcC5cbiAqXG4gKiBMYXRlIC8gZ2F0ZWQgZW1iZWRzOiB7QGxpbmsgb2JzZXJ2ZUR5bmFtaWNNZWRpYX0gKHNoYXJlZCB3aXRoIHJ1ZGRlclZpZGVvKS5cbiAqL1xuXG5pbXBvcnQge1xuXHRhdHRhY2hNZWRpYVRyYWNraW5nLFxuXHRyZXNvbHZlTWV0YUZyb21Eb20sXG5cdGV2ZW50TmFtZUZvclN1cmZhY2UsXG5cdHBsYXlJbnRlbnRGcm9tTWV0YSxcblx0b2JzZXJ2ZUR5bmFtaWNNZWRpYSxcbn0gZnJvbSAnLi9ydWRkZXJNZWRpYSc7XG5cbi8qKlxuICogTmF0aXZlIHBsYXllcnMgb3B0IGluIHdpdGggYGRhdGEtcnVkZGVyLW1lZGlhLXBsYXllcj1cImh0bWw1XCJgIGF0IChvciBhYm92ZSlcbiAqIHRoZSBlbGVtZW50IGxldmVsLiBBbnl0aGluZyB3aXRob3V0IGl0IOKAlCBQbHlyLCBOT0EsIHNvdW5kY2xvdWQvaWZyYW1lIGVtYmVkc1xuICog4oCUIGlzIGhhbmRsZWQgYnkgaXRzIG93biBtb2R1bGUgYW5kIG11c3Qgbm90IGJlIGRvdWJsZS10cmFja2VkIGhlcmUuXG4gKi9cbmNvbnN0IEhUTUw1X01FRElBX1NFTEVDVE9SID0gJ1tkYXRhLXJ1ZGRlci1tZWRpYS1wbGF5ZXI9XCJodG1sNVwiXSc7XG5cbmNsYXNzIFJ1ZGRlckh0bWw1TWVkaWEge1xuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHR0aGlzLmlzSW5pdGlhbGl6ZWQgPSBmYWxzZTtcblx0XHQvKiogQHR5cGUgeygoKSA9PiB2b2lkKXxudWxsfSAqL1xuXHRcdHRoaXMudW5zdWJzY3JpYmVEeW5hbWljID0gbnVsbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBAcmV0dXJucyB7dm9pZH1cblx0ICovXG5cdGluaXQoKSB7XG5cdFx0aWYgKHRoaXMuaXNJbml0aWFsaXplZCkgcmV0dXJuO1xuXHRcdHRoaXMuaXNJbml0aWFsaXplZCA9IHRydWU7XG5cblx0XHRpZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnKSB7XG5cdFx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgKCkgPT4gdGhpcy5zdGFydCgpLCB7XG5cdFx0XHRcdG9uY2U6IHRydWUsXG5cdFx0XHR9KTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5zdGFydCgpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBBdHRhY2ggdG8gZXhpc3RpbmcgbWVkaWEsIHRoZW4gYWx3YXlzIHdhdGNoIGZvciBsYXRlL2dhdGVkIG9uZXMgc28gdGhlXG5cdCAqIGZpcnN0IGluamVjdGVkIGh0bWw1IHBsYXllciBvbiBhbiBvdGhlcndpc2UgZW1wdHkgcGFnZSBpcyBzdGlsbCB0cmFja2VkLlxuXHQgKlxuXHQgKiBAcmV0dXJucyB7dm9pZH1cblx0ICovXG5cdHN0YXJ0KCkge1xuXHRcdHRoaXMuYXR0YWNoQWxsKGRvY3VtZW50KTtcblx0XHQvLyBBbHdheXMgc3Vic2NyaWJlIOKAlCBkbyBub3QgZ2F0ZSBvbiBcImFscmVhZHkgaGFzIGh0bWw1XCIgKHRoYXQgbWlzc2VkXG5cdFx0Ly8gZmlyc3QgbGF0ZSBpbmplY3QpLiBTaGFyZWQgb2JzZXJ2ZXIgaXMgYSBuby1vcCBjb3N0IHdoZW4gaWRsZS5cblx0XHRpZiAoIXRoaXMudW5zdWJzY3JpYmVEeW5hbWljKSB7XG5cdFx0XHR0aGlzLnVuc3Vic2NyaWJlRHluYW1pYyA9IG9ic2VydmVEeW5hbWljTWVkaWEoKG5vZGVzKSA9PiB7XG5cdFx0XHRcdGZvciAoY29uc3Qgbm9kZSBvZiBub2Rlcykge1xuXHRcdFx0XHRcdGlmIChcblx0XHRcdFx0XHRcdG5vZGUubWF0Y2hlcz8uKEhUTUw1X01FRElBX1NFTEVDVE9SKSB8fFxuXHRcdFx0XHRcdFx0bm9kZS5xdWVyeVNlbGVjdG9yPy4oSFRNTDVfTUVESUFfU0VMRUNUT1IpXG5cdFx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0XHR0aGlzLmF0dGFjaEFsbChub2RlKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBAcGFyYW0ge1BhcmVudE5vZGV8RWxlbWVudH0gcm9vdFxuXHQgKiBAcmV0dXJucyB7RWxlbWVudFtdfVxuXHQgKi9cblx0Y29sbGVjdChyb290KSB7XG5cdFx0Y29uc3Qgb3V0ID0gW107XG5cdFx0aWYgKCFyb290IHx8IChyb290Lm5vZGVUeXBlICE9PSAxICYmIHJvb3Qubm9kZVR5cGUgIT09IDkpKSByZXR1cm4gb3V0O1xuXG5cdFx0aWYgKHJvb3Qubm9kZVR5cGUgPT09IDEgJiYgcm9vdC5tYXRjaGVzPy4oSFRNTDVfTUVESUFfU0VMRUNUT1IpKSB7XG5cdFx0XHRvdXQucHVzaChyb290KTtcblx0XHR9XG5cdFx0aWYgKHR5cGVvZiByb290LnF1ZXJ5U2VsZWN0b3JBbGwgPT09ICdmdW5jdGlvbicpIHtcblx0XHRcdHJvb3QucXVlcnlTZWxlY3RvckFsbChIVE1MNV9NRURJQV9TRUxFQ1RPUikuZm9yRWFjaCgoZWwpID0+IHtcblx0XHRcdFx0b3V0LnB1c2goZWwpO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHRcdHJldHVybi
1BvdXQ7XG5cdH1cblxuXHQvKipcblx0ICogQHBhcmFtIHtQYXJlbnROb2RlfSBbcm9vdD1kb2N1bWVudF1cblx0ICogQHJldHVybnMge3ZvaWR9XG5cdCAqL1xuXHRhdHRhY2hBbGwocm9vdCA9IGRvY3VtZW50KSB7XG5cdFx0Y29uc3Qgc2NvcGUgPSByb290ID09PSBkb2N1bWVudCA/IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCA6IHJvb3Q7XG5cdFx0dGhpcy5jb2xsZWN0KHNjb3BlKS5mb3JFYWNoKChlbCkgPT4ge1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0dGhpcy5hdHRhY2goZWwpO1xuXHRcdFx0fSBjYXRjaCAoX2Vycikge1xuXHRcdFx0XHQvLyBUcmFja2luZyBtdXN0IG5ldmVyIGJyZWFrIHBsYXliYWNrXG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHQvKipcblx0ICogQHBhcmFtIHtFbGVtZW50fSBlbCAgdGhlIHRhZ2dlZCBlbGVtZW50ICh1c3VhbGx5IHRoZSBtZWRpYSBlbGVtZW50IGl0c2VsZilcblx0ICogQHJldHVybnMge3ZvaWR9XG5cdCAqL1xuXHRhdHRhY2goZWwpIHtcblx0XHRpZiAoIWVsKSByZXR1cm47XG5cblx0XHQvLyBUaGUgYXR0cmlidXRlIG5vcm1hbGx5IHNpdHMgb24gdGhlIG1lZGlhIGVsZW1lbnQgKHBsYXllciBsZXZlbCk7IGFsbG93XG5cdFx0Ly8gYSB3cmFwcGVyIHRvbywgYW5kIHJlc29sdmUgdG8gdGhlIGFjdHVhbCA8YXVkaW8+Lzx2aWRlbz4gaXQgaG9sZHMuXG5cdFx0Y29uc3QgbWVkaWFFbCA9XG5cdFx0XHRlbC50YWdOYW1lID09PSAnQVVESU8nIHx8IGVsLnRhZ05hbWUgPT09ICdWSURFTydcblx0XHRcdFx0PyBlbFxuXHRcdFx0XHQ6IGVsLnF1ZXJ5U2VsZWN0b3I/LignYXVkaW8sIHZpZGVvJyk7XG5cdFx0aWYgKCFtZWRpYUVsIHx8IHR5cGVvZiBtZWRpYUVsLmFkZEV2ZW50TGlzdGVuZXIgIT09ICdmdW5jdGlvbicpIHJldHVybjtcblx0XHRpZiAobWVkaWFFbC5kYXRhc2V0Py5ydWRkZXJUcmFja2VkID09PSAnaHRtbDUnKSByZXR1cm47XG5cblx0XHQvLyBTdXJmYWNlLCBwbGF5ZXIgdHlwZSBhbmQgY29udGV4dCBhbGwgY29tZSBmcm9tIHRoZSBET00gKGRhdGEtcnVkZGVyLSopLlxuXHRcdGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZU1ldGFGcm9tRG9tKGVsKTtcblx0XHRjb25zdCBldmVudE5hbWUgPSBldmVudE5hbWVGb3JTdXJmYWNlKHJlc29sdmVkLnN1cmZhY2UpO1xuXHRcdGlmICghZXZlbnROYW1lKSByZXR1cm47IC8vIHVudGFnZ2VkIC8gdW5rbm93biBzdXJmYWNlIOKAlCBub3QgdHJhY2tlZFxuXG5cdFx0bWVkaWFFbC5kYXRhc2V0LnJ1ZGRlclRyYWNrZWQgPSAnaHRtbDUnO1xuXG5cdFx0YXR0YWNoTWVkaWFUcmFja2luZyhcblx0XHRcdG1lZGlhRWwsXG5cdFx0XHQoZXZlbnQsIGNiKSA9PiBtZWRpYUVsLmFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIGNiKSxcblx0XHRcdHtcblx0XHRcdFx0ZXZlbnROYW1lLFxuXHRcdFx0XHRtZXRhOiByZXNvbHZlZCxcblx0XHRcdFx0ZWwsXG5cdFx0XHRcdGdldFBsYXlJbnRlbnQ6ICgpID0+IHBsYXlJbnRlbnRGcm9tTWV0YShyZXNvbHZlZCksXG5cdFx0XHRcdHBsYXllcjogcmVzb2x2ZWQucGxheWVyIHx8ICdodG1sNScsXG5cdFx0XHR9XG5cdFx0KTtcblx0fVxufVxuXG5leHBvcnQgZGVmYXVsdCBSdWRkZXJIdG1sNU1lZGlhO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../assets/src/scripts/rudder/rudderHtml5Media.js\n\n}')},"../assets/src/scripts/rudder/rudderMedia.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){"use strict";eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ attachMediaTracking: () => (/* binding */ attachMediaTracking),\n/* harmony export */ attachPlyrTracking: () => (/* binding */ attachPlyrTracking),\n/* harmony export */ createMediaEvent: () => (/* binding */ createMediaEvent),\n/* harmony export */ eventNameForSurface: () => (/* binding */ eventNameForSurface),\n/* harmony export */ isLiveStreamEl: () => (/* binding */ isLiveStreamEl),\n/* harmony export */ observeDynamicMedia: () => (/* binding */ observeDynamicMedia),\n/* harmony export */ playIntentFromMeta: () => (/* binding */ playIntentFromMeta),\n/* harmony export */ resolveMetaFromDom: () => (/* binding */ resolveMetaFromDom),\n/* harmony export */ resolvePlayerType: () => (/* binding */ resolvePlayerType),\n/* harmony export */ resolveSurface: () => (/* binding */ resolveSurface),\n/* harmony export */ trackMedia: () => (/* binding */ trackMedia)\n/* harmony export */ });\n/* harmony import */ var _babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/defineProperty */ \"./node_modules/@babel/runtime/helpers/esm/defineProperty.js\");\n\nfunction ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {};
1 r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0,_babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nfunction _createForOfIteratorHelper(r, e) { var t = \"undefined\" != typeof Symbol && r[Symbol.iterator] || r[\"@@iterator\"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && \"number\" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t[\"return\"] || t[\"return\"](); } finally { if (u) throw o; } } }; }\nfunction _unsupportedIterableToArray(r, a) { if (r) { if (\"string\" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return \"Object\" === t && r.constructor && (t = r.constructor.name), \"Map\" === t || \"Set\" === t ? Array.from(r) : \"Arguments\" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }\nfunction _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }\n/**\n * Shared Rudder media tracking helpers.\n *\n * Dispatches `rudder:track` CustomEvents only â no SDK import. Safe to call\n * from any component bundle whether or not rudderTools is loaded (events are\n * no-ops when no listener is attached).\n *\n * Emitters â Plyr (`attachPlyrTracking`), native <audio>/<video>\n * (rudderHtml5Media), raw Vimeo (rudderVideo) and NOA (rudderNoa) â all build\n * their payload through {@link createMediaEvent}; Plyr and HTML5 additionally\n * share the {@link attachMediaTracking} play/finish/milestone loop. This keeps\n * `fp_live_videos`, `fp_videos_cpt`, `fp_live_audio`, `fp_podcasts` and `fp_noa`\n * on one property schema so they UNION in the warehouse. See {@link SURFACE_EVENT}.\n *\n * DOM attributes drive discovery and placement: `data-rudder-media-surface` (what\n * it is â event name), `data-rudder-media-player` (how it's wired â html5/plyr/\n * vimeo/noa), `data-rudder-media-context` (where it sits â always emitted), and\n * `data-rudder-media-title` (the asset's title â always emitted so plays on\n * `/` or `/live` don't inherit `document.title` / `context_page_title`).\n *\n * Late-injected embeds share one body MutationObserver via\n * {@link observeDynamicMedia} (html5 + raw Vimeo subscribers).\n */\n\nvar MILESTONES = [25, 50, 75, 95];\n\n// A hover-preview must play at least this long before it counts as a `play`,\n// so mouse-swipes across a video grid don't emit events.\nvar HOVER_PLAY_DELAY_MS = 2000;\nvar SURFACE_EVENT = {\n fp_live: 'fp_live_videos',\n // FP Live videos, wherever they surface (incl. home)\n fp_video: 'fp_videos_cpt',\n // videos housed in the FP Video CPT\n fp_live_audio: 'fp_live_audio',\n // FP Live call recordings (native <audio>)\n podcast: 'fp_podcasts',\n // all podcasts sitewide (sections, articles, archives)\n noa: 'fp_noa' // News Over Audio plays\n};\n\n// Descriptors emitted only when present, so events aren't padded with nulls.\n// (embed_context is always on the payload â see createMediaEvent.)\nvar OPTIONAL_EVENT_KEYS = ['orientation'];\n\n/**\n * @param {*} value\n * @returns {number|null}\n */\nfunction numericOrNull(value) {\n return typeof value === 'number' && !Number.isNaN(value) ? value : null;\n}\n\n/**\n * Build a canonical media-event payload. Callers pass whatever they know; the\n * result always has the same core keys (defaulted to null / sensible values)\n * so downstream schemas stay stable across surfaces.\n *\n * @typedef {Object} MediaEvent\n * @property {'play'|'milestone'|'finish'|null} action\n * @property {'fp_live'|'fp_video'|'fp_live_audio'|'podcast'|'noa'|null} surface\n * @property {'vimeo'|'youtube'|'html5'|'noa'|null} provider\n * @property {'plyr'|'vimeo'|'html5'|'noa'|null} player\n * @property {string|null} media_id content id (Vimeo/YT id, audio filename, NOA id, â¦)\n * @property {string|null} media_title from data-rudder-media-title (the asset, not the page)\n * @property {number|null} current_time seconds\n * @property {number|null} duration seconds\n * @property {number|null} percent 0..1\n * @property {number|null} progress milestone bucket (integer %)\n * @property {boolean|null} muted\n * @property {'user'|'autoplay'|'hover'|'unknown'} play_intent\n * @property {boolean} is_live_stream\n * @property {string|null} embed_context always present (from data-rudder-media-context)\n * @property {string} [orientation] optional, emitted only when present\n *\n * @param {object} [props]\n * @returns {MediaEvent}\n */\nfunction createMediaEvent() {\n var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var event = {\n action: props.action || null,\n surface: props.surface || null,\n provider: props.provider || null,\n player: props.player || null,\n media_id: props.media_id || null,\n // Always present so warehouse columns stay stable. Templates should set\n // data-rudder-media-title; null only means a missing tag (treat as a bug\n // on landing pages, where context_page_title is the page not the asset).\n media_title: props.media_title || null,\n current_time: numericOrNull(props.current_time),\n duration: numericOrNull(props.duration),\n percent: numericOrNull(props.percent),\n progress: props.progress != null ? Number(props.progress) : null,\n muted: props.muted == null ? null : !!props.muted,\n play_intent: props.play_intent || 'unknown',\n is_live_stream: !!props.is_live_stream,\n // Always present so warehouse columns stay stable. Templates should set\n // data-rudder-media-context; null only means a missing tag (treat as a bug).\n embed_context: props.embed_context || null\n };\n var _iterator = _createForOfIteratorHelper(OPTIONAL_EVENT_KEYS),\n _step;\n try {\n for (_iterator.s();
1 !(_step = _iterator.n()).done;) {\n var key = _step.value;\n if (props[key] != null) event[key] = props[key];\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n return event;\n}\n\n/**\n * @param {string} eventName\n * @param {object} properties\n * @returns {void}\n */\nfunction trackMedia(eventName) {\n var properties = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n if (!eventName) return;\n document.dispatchEvent(new CustomEvent('rudder:track', {\n detail: {\n event: eventName,\n properties: _objectSpread({}, properties)\n }\n }));\n}\n\n// ---------------------------------------------------------------------------\n// Shared late-DOM discovery (one body MutationObserver for all media modules)\n// ---------------------------------------------------------------------------\n\n/** @type {Set<(nodes: Element[]) => void>} */\nvar dynamicMediaSubscribers = new Set();\n\n/** @type {MutationObserver|null} */\nvar dynamicMediaObserver = null;\n\n/**\n * Start the shared body observer if needed. Safe to call repeatedly.\n *\n * @returns {void}\n */\nfunction ensureDynamicMediaObserver() {\n if (dynamicMediaObserver || typeof MutationObserver === 'undefined') {\n return;\n }\n var start = function start() {\n if (dynamicMediaObserver || !document.body) return;\n dynamicMediaObserver = new MutationObserver(function (mutations) {\n if (dynamicMediaSubscribers.size === 0) return;\n\n /** @type {Element[]} */\n var added = [];\n var _iterator2 = _createForOfIteratorHelper(mutations),\n _step2;\n try {\n for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {\n var mutation = _step2.value;\n var _iterator4 = _createForOfIteratorHelper(mutation.addedNodes),\n _step4;\n try {\n for (_iterator4.s();
1 !(_step4 = _iterator4.n()).done;) {\n var node = _step4.value;\n if (node.nodeType === 1) added.push(/** @type {Element} */node);\n }\n } catch (err) {\n _iterator4.e(err);\n } finally {\n _iterator4.f();\n }\n }\n } catch (err) {\n _iterator2.e(err);\n } finally {\n _iterator2.f();\n }\n if (!added.length) return;\n var _iterator3 = _createForOfIteratorHelper(dynamicMediaSubscribers),\n _step3;\n try {\n for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {\n var cb = _step3.value;\n try {\n cb(added);\n } catch (_err) {\n // Subscribers must never break discovery for each other\n }\n }\n } catch (err) {\n _iterator3.e(err);\n } finally {\n _iterator3.f();\n }\n });\n dynamicMediaObserver.observe(document.body, {\n childList: true,\n subtree: true\n });\n };\n if (document.body) {\n start();\n } else if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', start, {\n once: true\n });\n }\n}\n\n/**\n * Subscribe to late-injected DOM under `document.body`. All media modules\n * (raw Vimeo, HTML5, â¦) share one MutationObserver so we don't walk the tree\n * twice. The callback receives the batch of Element nodes added in a mutation\n * flush (not individual text nodes).\n *\n * Always safe to call â even when no matching media is on the page yet â so a\n * first late-injected player is still discovered (e.g. gated HTML5 embeds).\n *\n * @param {(nodes: Element[]) => void} onAdded\n * @returns {() => void} unsubscribe\n */\nfunction observeDynamicMedia(onAdded) {\n if (typeof onAdded !== 'function') return function () {};\n dynamicMediaSubscribers.add(onAdded);\n ensureDynamicMediaObserver();\n return function () {\n dynamicMediaSubscribers[\"delete\"](onAdded);\n if (dynamicMediaSubscribers.size === 0 && dynamicMediaObserver) {\n dynamicMediaObserver.disconnect();\n dynamicMediaObserver = null;\n }\n };\n}\n\n/**\n * Map a surface key to the Rudder event name.\n *\n * @param {string} surface\n * @returns {string|null}\n */\nfunction eventNameForSurface(surface) {\n return SURFACE_EVENT[surface] || null;\n}\n\n/**\n * Whether the element sits inside a wrapper flagged as a live stream.\n * Shared so DOM detection stays consistent across the media modules.\n *\n * @param {Element|null} el\n * @returns {boolean}\n */\nfunction isLiveStreamEl(el) {\n var _el$closest;\n var host = el === null || el === void 0 || (_el$closest = el.closest) === null || _el$closest === void 0 ? void 0 : _el$closest.call(el, '[data-fp-video-is-live-stream]');\n return !!host && host.getAttribute('data-fp-video-is-live-stream') === 'true';\n}\n\n/**\n * Resolve a player's surface from an explicit `data-rudder-media-surface` attribute\n * on the element or an ancestor (templates declare it â the PHP knows the type\n * per post). Validated against {@link SURFACE_EVENT}, so an unknown value\n * resolves to null (and the player is left untracked) rather than a bad table.\n *\n * @param {Element|null} el\n * @returns {'fp_live'|'fp_video'|'fp_live_audio'|'podcast'|'noa'|null}\n */\nfunction resolveSurface(el) {\n var _el$closest2;\n var surface = el === null || el === void 0 || (_el$closest2 = el.closest) === null || _el$closest2 === void 0 || (_el$closest2 = _el$closest2.call(el, '[data-rudder-media-surface]')) === null || _el$closest2 === void 0 ? void 0 : _el$closest2.getAttribute('data-rudder-media-surface');\n return surface && SURFACE_EVENT[surface] ? surface : null;\n}\n\n// Player attachment mechanisms. `data-rudder-media-player` names how a player is\n// wired. Discovery is attribute-gated for:\n// - html5 â rudderHtml5Media keys its selector on this value\n// - vimeo â rudderVideo only listens to api=1 iframes tagged \"vimeo\"\n// Plyr and NOA still attach from their own modules (Plyr instance timing,\n// NOA postMessage), but the attr still stamps the emitted `player` field\n// and must be present on the template markup.\nvar PLAYER_TYPES = new Set(['html5', 'plyr', 'vimeo', 'noa']);\n\n/**\n * Resolve a player's attachment type from `data-rudder-media-player` on the element\n * or an ancestor. Validated against {@link PLAYER_TYPES}; unknown/absent â null.\n *\n * @param {Element|null} el\n * @returns {'html5'|'plyr'|'vimeo'|'noa'|null}\n */\nfunction resolvePlayerType(el) {\n var _el$closest3;\n var type = el === null || el === void 0 || (_el$closest3 = el.closest) === null || _el$closest3 === void 0 || (_el$closest3 = _el$closest3.call(el, '[data-rudder-media-player]')) === null || _el$closest3 === void 0 ? void 0 : _el$closest3.getAttribute('data-rudder-media-player');\n return type && PLAYER_TYPES.has(type) ? type : null;\n}\n\n/**\n * Build default meta from a media/Plyr host element.\n *\n * @param {Element} el\n * @param {object} [overrides]\n * @returns {object}\n */\nfunction resolveMetaFromDom(el) {\n var _el$closest4, _el$closest5, _el$closest6, _el$dataset, _el$closest8;\n var overrides = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var isLive = isLiveStreamEl(el);\n var isHover = !!(el !== null && el !== void 0 && (_el$closest4 = el.closest) !== null && _el$closest4 !== void 0 && _el$closest4.call(el, '[data-fp-video-hoverplay=\"true\"]'));\n var isAutoplay = !!(el !== null && el !== void 0 && (_el$closest5 = el.closest) !== null && _el$closest5 !== void 0 && _el$closest5.call(el, '[data-fp-video-autoplay=\"true\"]'));\n var surface = overrides.surface || resolveSurface(el);\n var player = overrides.player || resolvePlayerType(el);\n var provider = overrides.provider || detectProvider(el);\n var mediaId = overrides.media_id || extractMediaId(el, provider);\n // Placement declared by the template (article, section, event_main, â¦).\n // Required on tracked markup â null only if a template forgot the attr.\n var embedContext = (el === null || el === void 0 || (_el$closest6 = el.closest) === null || _el$closest6 === void 0 || (_el$closest6 = _el$closest6.call(el, '[data-rudder-media-context]')) === null || _el$closest6 === void 0 ? void 0 : _el$closest6.getAttribute('data-rudder-media-context')) || null;\n var mediaTitle = function (_el$closest7) {\n if (overrides.media_title) return overrides.media_title;\n var raw = (el === null || el === void 0 || (_el$closest7 = el.closest) === null || _el$closest7 === void 0 || (_el$closest7 = _el$closest7.call(el, '[data-rudder-media-title]')) === null || _el$closest7 === void 0 ? void 0 : _el$closest7.getAttribute('data-rudder-media-title')) || '';\n var trimmed = raw.trim();\n return trimmed || null;\n }();\n var orientation = (el === null || el === void 0 || (_el$dataset = el.dataset) === null || _el$dataset === void 0 ? void 0 : _el$dataset.orientation) || (el === null || el === void 0 || (_el$closest8 = el.closest) === null || _el$closest8 === void 0 || (_el$closest8 = _el$closest8.call(el, '[data-orientation]')) === null || _el$closest8 === void 0 ? void 0 : _el$closest8.getAttribute('data-orientation')) || null;\n return _objectSpread({\n surface: surface,\n player: player,\n provider: provider,\n media_id: mediaId,\n media_title: mediaTitle,\n is_live_stream: isLive,\n is_hover_play: isHover,\n is_autoplay: isAutoplay,\n orientation: orientation,\n embed_context: embedContext\n }, overrides);\n}
1\n\n/**\n * Shared play_intent from DOM flags (hover â autoplay â user).\n * Used by Plyr, HTML5, and raw Vimeo so the field means the same everywhere.\n *\n * @param {object} meta from {@link resolveMetaFromDom}\n * @returns {'user'|'autoplay'|'hover'}\n */\nfunction playIntentFromMeta() {\n var meta = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n if (meta.is_hover_play) return 'hover';\n if (meta.is_autoplay || meta.is_live_stream) return 'autoplay';\n return 'user';\n}\n\n/**\n * @param {Element} el\n * @returns {'vimeo'|'youtube'|'html5'|null}\n */\nfunction detectProvider(el) {\n var _el$getAttribute, _el$dataset2, _el$closest9, _el$querySelector, _iframe$dataset, _el$querySelector2;\n if (!el) return null;\n var providerAttr = ((_el$getAttribute = el.getAttribute) === null || _el$getAttribute === void 0 ? void 0 : _el$getAttribute.call(el, 'data-plyr-provider')) || ((_el$dataset2 = el.dataset) === null || _el$dataset2 === void 0 ? void 0 : _el$dataset2.plyrProvider) || ((_el$closest9 = el.closest) === null || _el$closest9 === void 0 || (_el$closest9 = _el$closest9.call(el, '[data-plyr-provider]')) === null || _el$closest9 === void 0 ? void 0 : _el$closest9.getAttribute('data-plyr-provider'));\n if (providerAttr) return providerAttr;\n var iframe = el.tagName === 'IFRAME' ? el : (_el$querySelector = el.querySelector) === null || _el$querySelector === void 0 ? void 0 : _el$querySelector.call(el, 'iframe');\n var src = (iframe === null || iframe === void 0 ? void 0 : iframe.src) || (iframe === null || iframe === void 0 || (_iframe$dataset = iframe.dataset) === null || _iframe$dataset === void 0 ? void 0 : _iframe$dataset.src) || '';\n if (src.includes('vimeo.com')) return 'vimeo';\n if (src.includes('youtube.com') || src.includes('youtu.be')) return 'youtube';\n if (el.tagName === 'VIDEO' || el.tagName === 'AUDIO' || (_el$querySelector2 = el.querySelector) !== null && _el$querySelector2 !== void 0 && _el$querySelector2.call(el, 'video, audio')) {\n return 'html5';\n }\n return null;\n}\n\n/**\n * @param {Element} el\n * @param {string|null} provider\n * @returns {string|null}\n */\nfunction extractMediaId(el, provider) {\n var _el$getAttribute2, _el$dataset3, _el$closest0, _el$querySelector3, _iframe$dataset2, _el$querySelector4, _media$querySelector, _el$querySelector5, _source$getAttribute, _media$getAttribute;\n if (!el) return null;\n var embedId = ((_el$getAttribute2 = el.getAttribute) === null || _el$getAttribute2 === void 0 ? void 0 : _el$getAttribute2.call(el, 'data-plyr-embed-id')) || ((_el$dataset3 = el.dataset) === null || _el$dataset3 === void 0 ? void 0 : _el$dataset3.plyrEmbedId) || ((_el$closest0 = el.closest) === null || _el$closest0 === void 0 || (_el$closest0 = _el$closest0.call(el, '[data-plyr-embed-id]')) === null || _el$closest0 === void 0 ? void 0 : _el$closest0.getAttribute('data-plyr-embed-id'));\n if (embedId) {\n var match = String(embedId).match(/(\\d{6,})/);\n return match ? match[1] : String(embedId);\n }\n var iframe = el.tagName === 'IFRAME' ? el : (_el$querySelector3 = el.querySelector) === null || _el$querySelector3 === void 0 ? void 0 : _el$querySelector3.call(el, 'iframe');\n var src = (iframe === null || iframe === void 0 ? void 0 : iframe.src) || (iframe === null || iframe === void 0 || (_iframe$dataset2 = iframe.dataset) === null || _iframe$dataset2 === void 0 ? void 0 : _iframe$dataset2.src) || '';\n if (provider === 'vimeo' || src.includes('vimeo.com')) {\n var m = src.match(/video\\/(\\d+)/) || src.match(/vimeo\\.com\\/(\\d+)/);\n if (m) return m[1];\n }\n if (provider === 'youtube' || src.includes('youtube') || src.includes('youtu.be')) {\n var _m = src.match(/embed\\/([^?&/]+)/) || src.match(/v=([^?&]+)/) || src.match(/youtu\\.be\\/([^?&/]+)/);\n if (_m) return _m[1];\n }\n var media = el.tagName === 'AUDIO' || el.tagName === 'VIDEO' ? el : (_el$querySelector4 = el.querySelector) === null || _el$querySelector4 === void 0 ? void 0 : _el$querySelector4.call(el, 'audio, video');\n var source = (media === null || media === void 0 || (_media$querySelector = media.querySelector) === null || _media$querySelector === void 0 ? void 0 : _media$querySelector.call(media, 'source')) || ((_el$querySelector5 = el.querySelector) === null || _el$querySelector5 === void 0 ? void 0 : _el$querySelector5.call(el, 'source'));\n // Prefer currentSrc (resolved after load); fall back to <source src> then\n // the element src attribute. Empty audio[src] often resolves to the page URL.\n var mediaSrc = (media === null || media === void 0 ? void 0 : media.currentSrc) || (source === null || source === void 0 ? void 0 : source.src) || (source === null || source === void 0 || (_source$getAttribute = source.getAttribute) === null || _source$getAttribute === void 0 ? void 0 : _source$getAttribute.call(source, 'src')) || (media === null || media === void 0 || (_media$getAttribute = media.getAttribute) === null || _media$getAttribute === void 0 ? void 0 : _media$getAttribute.call(media, 'src')) || '';\n // Drop page-URL false positives from empty src attributes.\n if (mediaSrc && mediaSrc === window.location.href) mediaSrc = '';\n if (mediaSrc) {\n try {\n var path = new URL(mediaSrc, window.location.href).pathname;
1\n return path.split('/').filter(Boolean).pop() || mediaSrc;\n } catch (_e) {\n return mediaSrc;\n }\n }\n return null;\n}\n\n/**\n * Mark Vimeo iframes under this Plyr instance so rudderVideo skips them.\n * Internal â only attachPlyrTracking uses it.\n *\n * @param {object} plyr Plyr instance\n * @returns {void}\n */\nfunction markPlyrIframesTracked(plyr) {\n var _plyr$elements, _plyr$elements2, _plyr$elements3;\n var media = (plyr === null || plyr === void 0 ? void 0 : plyr.media) || (plyr === null || plyr === void 0 || (_plyr$elements = plyr.elements) === null || _plyr$elements === void 0 ? void 0 : _plyr$elements.container);\n if (!media) return;\n var root = ((_plyr$elements2 = plyr.elements) === null || _plyr$elements2 === void 0 ? void 0 : _plyr$elements2.container) || (media.nodeType === 1 ? media.parentElement : null) || media;\n var iframes = [];\n if (media.tagName === 'IFRAME') iframes.push(media);\n if (root !== null && root !== void 0 && root.querySelectorAll) {\n root.querySelectorAll('iframe').forEach(function (f) {\n return iframes.push(f);\n });\n }\n iframes.forEach(function (iframe) {\n iframe.dataset.rudderTracked = 'plyr';\n });\n if ((_plyr$elements3 = plyr.elements) !== null && _plyr$elements3 !== void 0 && _plyr$elements3.container) {\n plyr.elements.container.dataset.rudderTracked = 'plyr';\n }\n}\n\n/**\n * Shared play/finish/milestone loop for any media source exposing\n * HTMLMediaElement-style `currentTime`/`duration`/`muted`/`volume` plus an\n * `on(event, cb)` binder â a native <audio>/<video> element or a Plyr\n * instance. Keeps the emitted event schema identical across both players.\n * (Note: no standalone `pause` event is emitted â `pause` only cancels the\n * hover debounce below.)\n *\n * @param {object} source Plyr instance or HTMLMediaElement\n * @param {(event: string, cb: Function) => void} on event binder\n * @param {object} options\n * @param {string} options.eventName resolved Rudder event name\n * @param {object} options.meta resolved meta (surface, provider, media_id, â¦)\n * @param {Element|null} [options.el] element used to (re)extract media_id\n * @param {() => string} [options.getPlayIntent] called on the play that counts\n * @param {string} [options.player] resolved player type ('plyr'|'html5'|â¦)\n * @returns {void}\n */\nfunction attachMediaTracking(source, on) {\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var eventName = options.eventName,\n _options$meta = options.meta,\n meta = _options$meta === void 0 ? {} : _options$meta,\n _options$el = options.el,\n el = _options$el === void 0 ? null : _options$el,\n _options$getPlayInten = options.getPlayIntent,\n getPlayIntent = _options$getPlayInten === void 0 ? function () {\n return 'user';\n } : _options$getPlayInten,\n _options$player = options.player,\n player = _options$player === void 0 ? 'html5' : _options$player;\n var firedMilestones = new Set();\n var mediaId = meta.media_id || null;\n var playIntent = 'unknown';\n var playFired = false; // first play only â resumes/replays don't re-fire\n var hoverTimer = null;\n var refreshMediaId = function refreshMediaId() {\n if (!mediaId && el) {\n var refreshed = extractMediaId(el, meta.provider);\n if (refreshed) mediaId = refreshed;\n }\n };
1\n var baseProps = function baseProps() {\n var _numericOrNull;\n var extra = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n refreshMediaId();\n var currentTime = (_numericOrNull = numericOrNull(source.currentTime)) !== null && _numericOrNull !== void 0 ? _numericOrNull : 0;\n var duration = numericOrNull(source.duration);\n var percent = duration && duration > 0 ? currentTime / duration : null;\n return createMediaEvent(_objectSpread({\n surface: meta.surface,\n provider: meta.provider,\n player: player,\n media_id: mediaId,\n media_title: meta.media_title,\n current_time: currentTime,\n duration: duration,\n percent: percent,\n muted: !!(source.muted || source.volume === 0),\n play_intent: playIntent,\n is_live_stream: meta.is_live_stream,\n orientation: meta.orientation,\n embed_context: meta.embed_context\n }, extra));\n };\n var clearHoverTimer = function clearHoverTimer() {\n if (hoverTimer) {\n clearTimeout(hoverTimer);\n hoverTimer = null;\n }\n };\n var firePlay = function firePlay() {\n if (playFired) return;\n playFired = true;\n trackMedia(eventName, baseProps({\n action: 'play'\n }));\n };\n\n // One `play` per media (first play only). Hover-preview plays are debounced,\n // so a swipe across a grid doesn't count â only >= HOVER_PLAY_DELAY_MS of\n // continuous playback does.\n on('play', function () {\n if (playFired || hoverTimer) return;\n playIntent = getPlayIntent();\n if (playIntent === 'hover') {\n hoverTimer = setTimeout(function () {\n hoverTimer = null;\n firePlay();\n }, HOVER_PLAY_DELAY_MS);\n } else {\n firePlay();\n }\n });\n\n // A hover that stops before the debounce elapses never becomes a play.\n // No standalone `pause` event is emitted.\n on('pause', clearHoverTimer);\n on('ended', function () {\n clearHoverTimer();\n if (playFired) {\n trackMedia(eventName, baseProps({\n action: 'finish',\n percent: 1\n }));\n }\n });\n\n // Progress milestones (max reached â % watched). Never for live streams,\n // and never before the play itself has been counted.\n if (!meta.is_live_stream) {\n on('timeupdate', function () {\n var _numericOrNull2;\n if (!playFired) return;\n var currentTime = (_numericOrNull2 = numericOrNull(source.currentTime)) !== null && _numericOrNull2 !== void 0 ? _numericOrNull2 : 0;\n var duration = numericOrNull(source.duration);\n if (!duration || duration <= 0) return;\n var pct = currentTime / duration * 100;\n var _iterator5 = _createForOfIteratorHelper(MILESTONES),\n _step5;\n try {\n for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {\n var milestone = _step5.value;\n if (pct >= milestone && !firedMilestones.has(milestone)) {\n firedMilestones.add(milestone);\n trackMedia(eventName, baseProps({\n action: 'milestone',\n progress: milestone,\n percent: currentTime / duration\n }));\n }\n }\n } catch (err) {\n _iterator5.e(err);\n } finally {\n _iterator5.f();\n }\n });\n }\n}\n\n/**\n * Attach tracking to a Plyr instance (FP Video, on-demand FP Live, podcast\n * section players). Delegates the event loop to attachMediaTracking.\n *\n * @param {object} plyr Plyr instance\n * @param {object} [meta] Optional pre-resolved meta (surface, media_id, â¦)\n * @returns {void}\n */\nfunction attachPlyrTracking(plyr) {\n var _plyr$elements4;\n var meta = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n if (!plyr || typeof plyr.on !== 'function') return;\n\n // Avoid double-attach\n if (plyr.__rudderTracked) return;\n\n // Prefer plyr.media (the element Plyr was initialised on â the .plyr-player)\n // so a data-rudder-media-surface tag on the player element itself is honoured,\n // not just on an ancestor. It also carries data-plyr-embed-id / orientation.\n var hostEl = plyr.media || ((_plyr$elements4 = plyr.elements) === null || _plyr$elements4 === void 0 ? void 0 : _plyr$elements4.container) || null;\n\n // resolveMetaFromDom already resolves the surface (via resolveSurface) and\n // folds `meta` in through its trailing ...overrides.\n var resolved = resolveMetaFromDom(hostEl, meta);\n var eventName = eventNameForSurface(resolved.surface);\n if (!eventName) return;\n\n // Mark only once we've committed to tracking. Bailing above must leave the\n // instance UNmarked, so a later correctly-tagged call can still attach and so\n // its iframes aren't falsely flagged as Plyr-claimed (which would make\n // rudderVideo skip a raw-Vimeo iframe that was never actually tracked).\n plyr.__rudderTracked = true;\n markPlyrIframesTracked(plyr);\n attachMediaTracking(plyr, function (event, cb) {\n return plyr.on(event, cb);\n }, {\n eventName: eventName,\n meta: resolved,\n el: hostEl,\n getPlayIntent: function getPlayIntent() {\n return playIntentFromMeta(resolved);\n },\n player: resolved.player || 'plyr'\n });\n\n // Late-created iframe (Vimeo/YouTube embeds) â re-mark after ready.\n // (media_id is (re)resolved lazily on every emit, so no refresh needed here.)\n plyr.on('ready', function () {\n return markPlyrIframesTracked(plyr);\n });\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJNZWRpYS5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7O0F
1BRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBRUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUVBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFFQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUFBO0FBRUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBRUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFHQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFHQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFJQTtBQUNBO0FBQ0E7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUdBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFNQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFLQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBRUE7QUFNQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBS0E7QUFJQTtBQUNBO0FBRUE7QUFJQTtBQUVBO0FBQ0E7QUFDQTtBQU1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBRUE7QUFLQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBSUE7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQUE7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJNZWRpYS5qcz9kZmQ3Il0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2hhcmVkIFJ1ZGRlciBtZWRpYSB0cmFja2luZyBoZWxwZXJzLlxuICpcbiAqIERpc3BhdGNoZXMgYHJ1ZGRlcjp0cmFja2AgQ3VzdG9tRXZlbnRzIG9ubHkg4oCUIG5vIFNESyBpbXBvcnQuIFNhZmUgdG8gY2FsbFxuICogZnJvbSBhbnkgY29tcG9uZW50IGJ1bmRsZSB3aGV0aGVyIG9yIG5vdCBydWRkZXJUb29scyBpcyBsb2FkZWQgKGV2ZW50cyBhcmVcbiAqIG5vLW9wcyB3aGVuIG5vIGxpc3RlbmVyIGlzIGF0dGFjaGVkKS5cbiAqXG4gKiBFbWl0dGVycyDigJQgUGx5ciAoYGF0dGFjaFBseXJUcmFja2luZ2ApLCBuYXRpdmUgPGF1ZGlvPi88dmlkZW8+XG4gKiAocnVkZGVySHRtbDVNZWRpYSksIHJhdyBWaW1lbyAocnVkZGVyVmlkZW8pIGFuZCBOT0EgKHJ1ZGRlck5vYSkg4oCUIGFsbCBidWlsZFxuICogdGhlaXIgcGF5bG9hZCB0aHJvdWdoIHtAbGluayBjcmVhdGVNZWRpYUV2ZW50fTsgUGx5ciBhbmQgSFRNTDUgYWRkaXRpb25hbGx5XG4gKiBzaGFyZSB0aGUge0BsaW5rIGF0dGFjaE1lZGlhVHJhY2tpbmd9IHBsYXkvZmluaXNoL21pbGVzdG9uZSBsb29wLiBUaGlzIGtlZXBz
1XG4gKiBgZnBfbGl2ZV92aWRlb3NgLCBgZnBfdmlkZW9zX2NwdGAsIGBmcF9saXZlX2F1ZGlvYCwgYGZwX3BvZGNhc3RzYCBhbmQgYGZwX25vYWBcbiAqIG9uIG9uZSBwcm9wZXJ0eSBzY2hlbWEgc28gdGhleSBVTklPTiBpbiB0aGUgd2FyZWhvdXNlLiBTZWUge0BsaW5rIFNVUkZBQ0VfRVZFTlR9LlxuICpcbiAqIERPTSBhdHRyaWJ1dGVzIGRyaXZlIGRpc2NvdmVyeSBhbmQgcGxhY2VtZW50OiBgZGF0YS1ydWRkZXItbWVkaWEtc3VyZmFjZWAgKHdoYXRcbiAqIGl0IGlzIOKGkiBldmVudCBuYW1lKSwgYGRhdGEtcnVkZGVyLW1lZGlhLXBsYXllcmAgKGhvdyBpdCdzIHdpcmVkIOKGkiBodG1sNS9wbHlyL1xuICogdmltZW8vbm9hKSwgYGRhdGEtcnVkZGVyLW1lZGlhLWNvbnRleHRgICh3aGVyZSBpdCBzaXRzIOKAlCBhbHdheXMgZW1pdHRlZCksIGFuZFxuICogYGRhdGEtcnVkZGVyLW1lZGlhLXRpdGxlYCAodGhlIGFzc2V0J3MgdGl0bGUg4oCUIGFsd2F5cyBlbWl0dGVkIHNvIHBsYXlzIG9uXG4gKiBgL2Agb3IgYC9saXZlYCBkb24ndCBpbmhlcml0IGBkb2N1bWVudC50aXRsZWAgLyBgY29udGV4dF9wYWdlX3RpdGxlYCkuXG4gKlxuICogTGF0ZS1pbmplY3RlZCBlbWJlZHMgc2hhcmUgb25lIGJvZHkgTXV0YXRpb25PYnNlcnZlciB2aWFcbiAqIHtAbGluayBvYnNlcnZlRHluYW1pY01lZGlhfSAoaHRtbDUgKyByYXcgVmltZW8gc3Vic2NyaWJlcnMpLlxuICovXG5cbmNvbnN0IE1JTEVTVE9ORVMgPSBbMjUsIDUwLCA3NSwgOTVdO1xuXG4vLyBBIGhvdmVyLXByZXZpZXcgbXVzdCBwbGF5IGF0IGxlYXN0IHRoaXMgbG9uZyBiZWZvcmUgaXQgY291bnRzIGFzIGEgYHBsYXlgLFxuLy8gc28gbW91c2Utc3dpcGVzIGFjcm9zcyBhIHZpZGVvIGdyaWQgZG9uJ3QgZW1pdCBldmVudHMuXG5jb25zdCBIT1ZFUl9QTEFZX0RFTEFZX01TID0gMjAwMDtcblxuY29uc3QgU1VSRkFDRV9FVkVOVCA9IHtcblx0ZnBfbGl2ZTogJ2ZwX2xpdmVfdmlkZW9zJywgLy8gRlAgTGl2ZSB2aWRlb3MsIHdoZXJldmVyIHRoZXkgc3VyZmFjZSAoaW5jbC4gaG9tZSlcblx0ZnBfdmlkZW86ICdmcF92aWRlb3NfY3B0JywgLy8gdmlkZW9zIGhvdXNlZCBpbiB0aGUgRlAgVmlkZW8gQ1BUXG5cdGZwX2xpdmVfYXVkaW86ICdmcF9saXZlX2F1ZGlvJywgLy8gRlAgTGl2ZSBjYWxsIHJlY29yZGluZ3MgKG5hdGl2ZSA8YXVkaW8+KVxuXHRwb2RjYXN0OiAnZnBfcG9kY2FzdHMnLCAvLyBhbGwgcG9kY2FzdHMgc2l0ZXdpZGUgKHNlY3Rpb25zLCBhcnRpY2xlcywgYXJjaGl2ZXMpXG5cdG5vYTogJ2ZwX25vYScsIC8vIE5ld3MgT3ZlciBBdWRpbyBwbGF5c1xufTtcblxuLy8gRGVzY3JpcHRvcnMgZW1pdHRlZCBvbmx5IHdoZW4gcHJlc2VudCwgc28gZXZlbnRzIGFyZW4ndCBwYWRkZWQgd2l0aCBudWxscy5cbi8vIChlbWJlZF9jb250ZXh0IGlzIGFsd2F5cyBvbiB0aGUgcGF5bG9hZCDigJQgc2VlIGNyZWF0ZU1lZGlhRXZlbnQuKVxuY29uc3QgT1BUSU9OQUxfRVZFTlRfS0VZUyA9IFsnb3JpZW50YXRpb24nXTtcblxuLyoqXG4gKiBAcGFyYW0geyp9IHZhbHVlXG4gKiBAcmV0dXJucyB7bnVtYmVyfG51bGx9XG4gKi9cbmZ1bmN0aW9uIG51bWVyaWNPck51bGwodmFsdWUpIHtcblx0cmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgJiYgIU51bWJlci5pc05hTih2YWx1ZSkgPyB2YWx1ZSA6IG51bGw7XG59XG5cbi8qKlxuICogQnVpbGQgYSBjYW5vbmljYWwgbWVkaWEtZXZlbnQgcGF5bG9hZC4gQ2FsbGVycyBwYXNzIHdoYXRldmVyIHRoZXkga25vdzsgdGhlXG4gKiByZXN1bHQgYWx3YXlzIGhhcyB0aGUgc2FtZSBjb3JlIGtleXMgKGRlZmF1bHRlZCB0byBudWxsIC8gc2Vuc2libGUgdmFsdWVzKVxuICogc28gZG93bnN0cmVhbSBzY2hlbWFzIHN0YXkgc3RhYmxlIGFjcm9zcyBzdXJmYWNlcy5cbiAqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBNZWRpYUV2ZW50XG4gKiBAcHJvcGVydHkgeydwbGF5J3wnbWlsZXN0b25lJ3wnZmluaXNoJ3xudWxsfSBhY3Rpb25cbiAqIEBwcm9wZXJ0eSB7J2ZwX2xpdmUnfCdmcF92aWRlbyd8J2ZwX2xpdmVfYXVkaW8nfCdwb2RjYXN0J3wnbm9hJ3xudWxsfSBzdXJmYWNlXG4gKiBAcHJvcGVydHkgeyd2aW1lbyd8J3lvdXR1YmUnfCdodG1sNSd8J25vYSd8bnVsbH0gcHJvdmlkZXJcbiAqIEBwcm9wZXJ0eSB7J3BseXInfCd2aW1lbyd8J2h0bWw1J3wnbm9hJ3xudWxsfSBwbGF5ZXJcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfG51bGx9IG1lZGlhX2lkICBjb250ZW50IGlkIChWaW1lby9ZVCBpZCwgYXVkaW8gZmlsZW5hbWUsIE5PQSBpZCwg4oCmKVxuICogQHByb3BlcnR5IHtzdHJpbmd8bnVsbH0gbWVkaWFfdGl0bGUgIGZyb20gZGF0YS1ydWRkZXItbWVkaWEtdGl0bGUgKHRoZSBhc3NldCwgbm90IHRoZSBwYWdlKVxuICogQHByb3BlcnR5IHtudW1iZXJ8bnVsbH0gY3VycmVudF90aW1lICBzZWNvbmRzXG4gKiBAcHJvcGVydHkge251bWJlcnxudWxsfSBkdXJhdGlvbiAgICAgIHNlY29uZHNcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfG51bGx9IHBlcmNlbnQgICAgICAgMC4uMVxuICogQHByb3BlcnR5IHtudW1iZXJ8bnVsbH0gcHJvZ3Jlc3MgICAgICBtaWxlc3RvbmUgYnVja2V0IChpbnRlZ2VyICUpXG4gKiBAcHJvcGVydHkge2Jvb2xlYW58bnVsbH0gbXV0ZWRcbiAqIEBwcm9wZXJ0eSB7J3VzZXInfCdhdXRvcGxheSd8J2hvdmVyJ3wndW5rbm93bid9IHBsYXlfaW50ZW50XG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGlzX2xpdmVfc3RyZWFtXG4gKiBAcHJvcGVydHkge3N0cmluZ3xudWxsfSBlbWJlZF9jb250ZXh0ICBhbHdheXMgcHJlc2VudCAoZnJvbSBkYXRhLXJ1ZGRlci1tZWRpYS1jb250ZXh0KVxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtvcmllbnRhdGlvbl0gIG9wdGlvbmFsLCBlbWl0dGVkIG9ubHkgd2hlbiBwcmVzZW50XG4gKlxuICogQHBhcmFtIHtvYmplY3R9IFtwcm9wc11cbiAqIEByZXR1cm5zIHtNZWRpYUV2ZW50fVxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTWVkaWFFdmVudChwcm9wcyA9IHt9KSB7XG5cdGNvbnN0IGV2ZW50ID0ge1xuXHRcdGFjdGlvbjogcHJvcHMuYWN0aW9uIHx8IG51bGwsXG5cdFx0c3VyZmFjZTogcHJvcHMuc3VyZmFjZSB8fCBudWxsLFxuXHRcdHByb3ZpZGVyOiBwcm9wcy5wcm92aWRlciB8fCBudWxsLFxuXHRcdHBsYXllcjogcHJvcHMucGxheWVyIHx8IG51bGwsXG5cdFx0bWVkaWFfaWQ6IHByb3BzLm1lZGlhX2lkIHx8IG51bGwsXG5cdFx0Ly8gQWx3YXlzIHByZXNlbnQgc28gd2FyZWhvdXNlIGNvbHVtbnMgc3RheSBzdGFibGUuIFRlbXBsYXRlcyBzaG91bGQgc2V0XG5cdFx0Ly8gZGF0YS1ydWRkZXItbWVkaWEtdGl0bGU7IG51bGwgb25seSBtZWFucyBhIG1pc3NpbmcgdGFnICh0cmVhdCBhcyBh
1IGJ1Z1xuXHRcdC8vIG9uIGxhbmRpbmcgcGFnZXMsIHdoZXJlIGNvbnRleHRfcGFnZV90aXRsZSBpcyB0aGUgcGFnZSBub3QgdGhlIGFzc2V0KS5cblx0XHRtZWRpYV90aXRsZTogcHJvcHMubWVkaWFfdGl0bGUgfHwgbnVsbCxcblx0XHRjdXJyZW50X3RpbWU6IG51bWVyaWNPck51bGwocHJvcHMuY3VycmVudF90aW1lKSxcblx0XHRkdXJhdGlvbjogbnVtZXJpY09yTnVsbChwcm9wcy5kdXJhdGlvbiksXG5cdFx0cGVyY2VudDogbnVtZXJpY09yTnVsbChwcm9wcy5wZXJjZW50KSxcblx0XHRwcm9ncmVzczogcHJvcHMucHJvZ3Jlc3MgIT0gbnVsbCA/IE51bWJlcihwcm9wcy5wcm9ncmVzcykgOiBudWxsLFxuXHRcdG11dGVkOiBwcm9wcy5tdXRlZCA9PSBudWxsID8gbnVsbCA6ICEhcHJvcHMubXV0ZWQsXG5cdFx0cGxheV9pbnRlbnQ6IHByb3BzLnBsYXlfaW50ZW50IHx8ICd1bmtub3duJyxcblx0XHRpc19saXZlX3N0cmVhbTogISFwcm9wcy5pc19saXZlX3N0cmVhbSxcblx0XHQvLyBBbHdheXMgcHJlc2VudCBzbyB3YXJlaG91c2UgY29sdW1ucyBzdGF5IHN0YWJsZS4gVGVtcGxhdGVzIHNob3VsZCBzZXRcblx0XHQvLyBkYXRhLXJ1ZGRlci1tZWRpYS1jb250ZXh0OyBudWxsIG9ubHkgbWVhbnMgYSBtaXNzaW5nIHRhZyAodHJlYXQgYXMgYSBidWcpLlxuXHRcdGVtYmVkX2NvbnRleHQ6IHByb3BzLmVtYmVkX2NvbnRleHQgfHwgbnVsbCxcblx0fTtcblxuXHRmb3IgKGNvbnN0IGtleSBvZiBPUFRJT05BTF9FVkVOVF9LRVlTKSB7XG5cdFx0aWYgKHByb3BzW2tleV0gIT0gbnVsbCkgZXZlbnRba2V5XSA9IHByb3BzW2tleV07XG5cdH1cblxuXHRyZXR1cm4gZXZlbnQ7XG59XG5cbi8qKlxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtIHtvYmplY3R9IHByb3BlcnRpZXNcbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5leHBvcnQgZnVuY3Rpb24gdHJhY2tNZWRpYShldmVudE5hbWUsIHByb3BlcnRpZXMgPSB7fSkge1xuXHRpZiAoIWV2ZW50TmFtZSkgcmV0dXJuO1xuXG5cdGRvY3VtZW50LmRpc3BhdGNoRXZlbnQoXG5cdFx0bmV3IEN1c3RvbUV2ZW50KCdydWRkZXI6dHJhY2snLCB7XG5cdFx0XHRkZXRhaWw6IHtcblx0XHRcdFx0ZXZlbnQ6IGV2ZW50TmFtZSxcblx0XHRcdFx0cHJvcGVydGllczogeyAuLi5wcm9wZXJ0aWVzIH0sXG5cdFx0XHR9LFxuXHRcdH0pXG5cdCk7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gU2hhcmVkIGxhdGUtRE9NIGRpc2NvdmVyeSAob25lIGJvZHkgTXV0YXRpb25PYnNlcnZlciBmb3IgYWxsIG1lZGlhIG1vZHVsZXMpXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqIEB0eXBlIHtTZXQ8KG5vZGVzOiBFbGVtZW50W10pID0+IHZvaWQ+fSAqL1xuY29uc3QgZHluYW1pY01lZGlhU3Vic2NyaWJlcnMgPSBuZXcgU2V0KCk7XG5cbi8qKiBAdHlwZSB7TXV0YXRpb25PYnNlcnZlcnxudWxsfSAqL1xubGV0IGR5bmFtaWNNZWRpYU9ic2VydmVyID0gbnVsbDtcblxuLyoqXG4gKiBTdGFydCB0aGUgc2hhcmVkIGJvZHkgb2JzZXJ2ZXIgaWYgbmVlZGVkLiBTYWZlIHRvIGNhbGwgcmVwZWF0ZWRseS5cbiAqXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gZW5zdXJlRHluYW1pY01lZGlhT2JzZXJ2ZXIoKSB7XG5cdGlmIChkeW5hbWljTWVkaWFPYnNlcnZlciB8fCB0eXBlb2YgTXV0YXRpb25PYnNlcnZlciA9PT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHRjb25zdCBzdGFydCA9ICgpID0+IHtcblx0XHRpZiAoZHluYW1pY01lZGlhT2JzZXJ2ZXIgfHwgIWRvY3VtZW50LmJvZHkpIHJldHVybjtcblxuXHRcdGR5bmFtaWNNZWRpYU9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKG11dGF0aW9ucykgPT4ge1xuXHRcdFx0aWYgKGR5bmFtaWNNZWRpYVN1YnNjcmliZXJzLnNpemUgPT09IDApIHJldHVybjtcblxuXHRcdFx0LyoqIEB0eXBlIHtFbGVtZW50W119ICovXG5cdFx0XHRjb25zdCBhZGRlZCA9IFtdO1xuXHRcdFx0Zm9yIChjb25zdCBtdXRhdGlvbiBvZiBtdXRhdGlvbnMpIHtcblx0XHRcdFx0Zm9yIChjb25zdCBub2RlIG9mIG11dGF0aW9uLmFkZGVkTm9kZXMpIHtcblx0XHRcdFx0XHRpZiAobm9kZS5ub2RlVHlwZSA9PT0gMSlcblx0XHRcdFx0XHRcdGFkZGVkLnB1c2goLyoqIEB0eXBlIHtFbGVtZW50fSAqLyAobm9kZSkpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZiAoIWFkZGVkLmxlbmd0aCkgcmV0dXJuO1xuXG5cdFx0XHRmb3IgKGNvbnN0IGNiIG9mIGR5bmFtaWNNZWRpYVN1YnNjcmliZXJzKSB7XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0Y2IoYWRkZWQpO1xuXHRcdFx0XHR9IGNhdGNoIChfZXJyKSB7XG5cdFx0XHRcdFx0Ly8gU3Vic2NyaWJlcnMgbXVzdCBuZXZlciBicmVhayBkaXNjb3ZlcnkgZm9yIGVhY2ggb3RoZXJcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0ZHluYW1pY01lZGlhT2JzZXJ2ZXIub2JzZXJ2ZShkb2N1bWVudC5ib2R5LCB7XG5cdFx0XHRjaGlsZExpc3Q6IHRydWUsXG5cdFx0XHRzdWJ0cmVlOiB0cnVlLFxuXHRcdH0pO1xuXHR9O1xuXG5cdGlmIChkb2N1bWVudC5ib2R5KSB7XG5cdFx0c3RhcnQoKTtcblx0fSBlbHNlIGlmIChkb2N1bWVudC5yZWFkeVN0YXRlID09PSAnbG9hZGluZycpIHtcblx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgc3RhcnQsIHsgb25jZTogdHJ1ZSB9KTtcblx0fVxufVxuXG4vKipcbiAqIFN1YnNjcmliZSB0byBsYXRlLWluamVjdGVkIERPTSB1bmRlciBgZG9jdW1lbnQuYm9keWAuIEFsbCBtZWRpYSBtb2R1bGVzXG4gKiAocmF3IFZpbWVvLCBIVE1MNSwg4oCmKSBzaGFyZSBvbmUgTXV0YXRpb25PYnNlcnZlciBzbyB3ZSBkb24ndCB3YWxrIHRoZSB0cmVlXG4gKiB0d2ljZS4gVGhlIGNhbGxiYWNrIHJlY2VpdmVzIHRoZSBiYXRjaCBvZiBFbGVtZW50IG5vZGVzIGFkZGVkIGluIGEgbXV0YXRpb25cbiAqIGZsdXNoIChub3QgaW5kaXZpZHVhbCB0ZXh0IG5vZGVzKS5cbiAqXG4gKiBBbHdheXMgc2FmZSB0byBjYWxsIOKAlCBldmVuIHdoZW4gbm8gbWF0Y2hpbmcgbWVkaWEgaXMgb24gdGhlIHBhZ2UgeWV0IOKAlCBzbyBhXG4gKiBmaXJzdCBsYXRlLWluamVjdGVkIHBsYXllciBpcyBzdGlsbCBkaXNjb3ZlcmVkIC
1hlLmcuIGdhdGVkIEhUTUw1IGVtYmVkcykuXG4gKlxuICogQHBhcmFtIHsobm9kZXM6IEVsZW1lbnRbXSkgPT4gdm9pZH0gb25BZGRlZFxuICogQHJldHVybnMgeygpID0+IHZvaWR9IHVuc3Vic2NyaWJlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBvYnNlcnZlRHluYW1pY01lZGlhKG9uQWRkZWQpIHtcblx0aWYgKHR5cGVvZiBvbkFkZGVkICE9PSAnZnVuY3Rpb24nKSByZXR1cm4gKCkgPT4ge307XG5cblx0ZHluYW1pY01lZGlhU3Vic2NyaWJlcnMuYWRkKG9uQWRkZWQpO1xuXHRlbnN1cmVEeW5hbWljTWVkaWFPYnNlcnZlcigpO1xuXG5cdHJldHVybiAoKSA9PiB7XG5cdFx0ZHluYW1pY01lZGlhU3Vic2NyaWJlcnMuZGVsZXRlKG9uQWRkZWQpO1xuXHRcdGlmIChkeW5hbWljTWVkaWFTdWJzY3JpYmVycy5zaXplID09PSAwICYmIGR5bmFtaWNNZWRpYU9ic2VydmVyKSB7XG5cdFx0XHRkeW5hbWljTWVkaWFPYnNlcnZlci5kaXNjb25uZWN0KCk7XG5cdFx0XHRkeW5hbWljTWVkaWFPYnNlcnZlciA9IG51bGw7XG5cdFx0fVxuXHR9O1xufVxuXG4vKipcbiAqIE1hcCBhIHN1cmZhY2Uga2V5IHRvIHRoZSBSdWRkZXIgZXZlbnQgbmFtZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3VyZmFjZVxuICogQHJldHVybnMge3N0cmluZ3xudWxsfVxuICovXG5leHBvcnQgZnVuY3Rpb24gZXZlbnROYW1lRm9yU3VyZmFjZShzdXJmYWNlKSB7XG5cdHJldHVybiBTVVJGQUNFX0VWRU5UW3N1cmZhY2VdIHx8IG51bGw7XG59XG5cbi8qKlxuICogV2hldGhlciB0aGUgZWxlbWVudCBzaXRzIGluc2lkZSBhIHdyYXBwZXIgZmxhZ2dlZCBhcyBhIGxpdmUgc3RyZWFtLlxuICogU2hhcmVkIHNvIERPTSBkZXRlY3Rpb24gc3RheXMgY29uc2lzdGVudCBhY3Jvc3MgdGhlIG1lZGlhIG1vZHVsZXMuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fG51bGx9IGVsXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzTGl2ZVN0cmVhbUVsKGVsKSB7XG5cdGNvbnN0IGhvc3QgPSBlbD8uY2xvc2VzdD8uKCdbZGF0YS1mcC12aWRlby1pcy1saXZlLXN0cmVhbV0nKTtcblx0cmV0dXJuIChcblx0XHQhIWhvc3QgJiYgaG9zdC5nZXRBdHRyaWJ1dGUoJ2RhdGEtZnAtdmlkZW8taXMtbGl2ZS1zdHJlYW0nKSA9PT0gJ3RydWUnXG5cdCk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIHBsYXllcidzIHN1cmZhY2UgZnJvbSBhbiBleHBsaWNpdCBgZGF0YS1ydWRkZXItbWVkaWEtc3VyZmFjZWAgYXR0cmlidXRlXG4gKiBvbiB0aGUgZWxlbWVudCBvciBhbiBhbmNlc3RvciAodGVtcGxhdGVzIGRlY2xhcmUgaXQg4oCUIHRoZSBQSFAga25vd3MgdGhlIHR5cGVcbiAqIHBlciBwb3N0KS4gVmFsaWRhdGVkIGFnYWluc3Qge0BsaW5rIFNVUkZBQ0VfRVZFTlR9LCBzbyBhbiB1bmtub3duIHZhbHVlXG4gKiByZXNvbHZlcyB0byBudWxsIChhbmQgdGhlIHBsYXllciBpcyBsZWZ0IHVudHJhY2tlZCkgcmF0aGVyIHRoYW4gYSBiYWQgdGFibGUuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fG51bGx9IGVsXG4gKiBAcmV0dXJucyB7J2ZwX2xpdmUnfCdmcF92aWRlbyd8J2ZwX2xpdmVfYXVkaW8nfCdwb2RjYXN0J3wnbm9hJ3xudWxsfVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVN1cmZhY2UoZWwpIHtcblx0Y29uc3Qgc3VyZmFjZSA9IGVsXG5cdFx0Py5jbG9zZXN0Py4oJ1tkYXRhLXJ1ZGRlci1tZWRpYS1zdXJmYWNlXScpXG5cdFx0Py5nZXRBdHRyaWJ1dGUoJ2RhdGEtcnVkZGVyLW1lZGlhLXN1cmZhY2UnKTtcblx0cmV0dXJuIHN1cmZhY2UgJiYgU1VSRkFDRV9FVkVOVFtzdXJmYWNlXSA/IHN1cmZhY2UgOiBudWxsO1xufVxuXG4vLyBQbGF5ZXIgYXR0YWNobWVudCBtZWNoYW5pc21zLiBgZGF0YS1ydWRkZXItbWVkaWEtcGxheWVyYCBuYW1lcyBob3cgYSBwbGF5ZXIgaXNcbi8vIHdpcmVkLiBEaXNjb3ZlcnkgaXMgYXR0cmlidXRlLWdhdGVkIGZvcjpcbi8vICAgLSBodG1sNSAg4oaSIHJ1ZGRlckh0bWw1TWVkaWEga2V5cyBpdHMgc2VsZWN0b3Igb24gdGhpcyB2YWx1ZVxuLy8gICAtIHZpbWVvICDihpIgcnVkZGVyVmlkZW8gb25seSBsaXN0ZW5zIHRvIGFwaT0xIGlmcmFtZXMgdGFnZ2VkIFwidmltZW9cIlxuLy8gUGx5ciBhbmQgTk9BIHN0aWxsIGF0dGFjaCBmcm9tIHRoZWlyIG93biBtb2R1bGVzIChQbHlyIGluc3RhbmNlIHRpbWluZyxcbi8vIE5PQSBwb3N0TWVzc2FnZSksIGJ1dCB0aGUgYXR0ciBzdGlsbCBzdGFtcHMgdGhlIGVtaXR0ZWQgYHBsYXllcmAgZmllbGRcbi8vIGFuZCBtdXN0IGJlIHByZXNlbnQgb24gdGhlIHRlbXBsYXRlIG1hcmt1cC5cbmNvbnN0IFBMQVlFUl9UWVBFUyA9IG5ldyBTZXQoWydodG1sNScsICdwbHlyJywgJ3ZpbWVvJywgJ25vYSddKTtcblxuLyoqXG4gKiBSZXNvbHZlIGEgcGxheWVyJ3MgYXR0YWNobWVudCB0eXBlIGZyb20gYGRhdGEtcnVkZGVyLW1lZGlhLXBsYXllcmAgb24gdGhlIGVsZW1lbnRcbiAqIG9yIGFuIGFuY2VzdG9yLiBWYWxpZGF0ZWQgYWdhaW5zdCB7QGxpbmsgUExBWUVSX1RZUEVTfTsgdW5rbm93bi9hYnNlbnQg4oaSIG51bGwuXG4gKlxuICogQHBhcmFtIHtFbGVtZW50fG51bGx9IGVsXG4gKiBAcmV0dXJucyB7J2h0bWw1J3wncGx5cid8J3ZpbWVvJ3wnbm9hJ3xudWxsfVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVBsYXllclR5cGUoZWwpIHtcblx0Y29uc3QgdHlwZSA9IGVsXG5cdFx0Py5jbG9zZXN0Py4oJ1tkYXRhLXJ1ZGRlci1tZWRpYS1wbGF5ZXJdJylcblx0XHQ/LmdldEF0dHJpYnV0ZSgnZGF0YS1ydWRkZXItbWVkaWEtcGxheWVyJyk7XG5cdHJldHVybiB0eXBlICYmIFBMQVlFUl9UWVBFUy5oYXModHlwZSkgPyB0eXBlIDogbnVsbDtcbn1cblxuLyoqXG4gKiBCdWlsZCBkZWZhdWx0IG1ldGEgZnJvbSBhIG1lZGlhL1BseXIgaG9zdCBlbGVtZW50LlxuICpcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWxcbiAqIEBwYXJhbSB7b2JqZWN0fSBbb3ZlcnJpZGVzXVxuICogQHJldHVybnMge29iamVjdH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVNZXRhRnJvbURvbShlbCwgb3ZlcnJpZGVzID0ge30pIHtcblx0Y29uc3QgaXNMaXZlID0gaXNMaXZlU3RyZWFtRWwoZWwpO1xuXHRjb25zdCBpc0hvdmVyID0gISFlbD8uY2xvc2VzdD8uKCdbZGF0YS1mcC12aWRlby1ob3ZlcnBsYXk9XCJ0cnVlXCJdJyk7XG5cdGNvbnN0IGlzQXV0b3BsYXkgPSAhIWVsPy5jbG9zZXN0Py4oJ1tkYXRhLWZwLXZpZGVvLWF1dG9wbGF5PVwidHJ1ZVwiXScpO1xuXG5cdGNvbnN0IHN1cmZhY2UgPSBvdmVycmlkZXMuc3VyZmFjZSB8fCByZXNvbHZlU3VyZmFjZShlbCk7XG5cdGNvbnN0IHBsYXllciA9IG92ZXJyaWRlcy5wbGF5ZXIgfHwgcmVzb2x2ZVBsYXllclR5cGUoZWwpO1xuXHRjb25zdCBwcm92aWRlciA9IG92ZXJyaWRlcy5wcm92aWRlciB8fCBkZXRlY3RQcm92aWRlcihlbCk7XG5cdGNvbnN0IG1lZGlhSWQgPSBvdmVycmlkZXMubWVkaWFfaWQgfHwgZXh0cmFjdE1lZGlhSWQoZWwsIHByb3ZpZGVyKTtcblx0Ly8gUGxhY2VtZW50IGRlY2xhcmVkIGJ5IHRoZSB0ZW1wbGF0ZSAoYXJ0aWNsZSwgc2VjdGlvbiwgZXZlbnRfbWFpbiwg4oCmKS5cblx0Ly8gUmVxdWlyZWQgb24gdHJhY2tlZCBtYXJrdXAg4oCUIG51bGwgb25seSBpZiBhIHRlbXBsYXRlIGZvcmdvdCB0aGUgYXR0ci5cblx0Y29uc3QgZW1iZWRDb250ZXh0ID1cblx0XHRlbFxuXHRcdFx0Py5jbG9zZXN0Py4oJ1tkYXRhLXJ1ZGRlci1tZWRpYS1jb250ZXh0XScpXG5cdFx0XHQ/LmdldEF0dHJpYnV0ZSgnZGF0YS1ydWRkZXItbWVkaWEtY29udGV4dCcpIHx8IG51bGw7XG5cdGNvbnN0IG1lZGlhVGl0bGUgPSAoKCkgPT4ge1xuXHRcdGlmIChvdmVycmlkZXMubWVkaWFfdGl0bGUpIHJldHVybi
1BvdmVycmlkZXMubWVkaWFfdGl0bGU7XG5cdFx0Y29uc3QgcmF3ID1cblx0XHRcdGVsXG5cdFx0XHRcdD8uY2xvc2VzdD8uKCdbZGF0YS1ydWRkZXItbWVkaWEtdGl0bGVdJylcblx0XHRcdFx0Py5nZXRBdHRyaWJ1dGUoJ2RhdGEtcnVkZGVyLW1lZGlhLXRpdGxlJykgfHwgJyc7XG5cdFx0Y29uc3QgdHJpbW1lZCA9IHJhdy50cmltKCk7XG5cdFx0cmV0dXJuIHRyaW1tZWQgfHwgbnVsbDtcblx0fSkoKTtcblx0Y29uc3Qgb3JpZW50YXRpb24gPVxuXHRcdGVsPy5kYXRhc2V0Py5vcmllbnRhdGlvbiB8fFxuXHRcdGVsPy5jbG9zZXN0Py4oJ1tkYXRhLW9yaWVudGF0aW9uXScpPy5nZXRBdHRyaWJ1dGUoJ2RhdGEtb3JpZW50YXRpb24nKSB8fFxuXHRcdG51bGw7XG5cblx0cmV0dXJuIHtcblx0XHRzdXJmYWNlLFxuXHRcdHBsYXllcixcblx0XHRwcm92aWRlcixcblx0XHRtZWRpYV9pZDogbWVkaWFJZCxcblx0XHRtZWRpYV90aXRsZTogbWVkaWFUaXRsZSxcblx0XHRpc19saXZlX3N0cmVhbTogaXNMaXZlLFxuXHRcdGlzX2hvdmVyX3BsYXk6IGlzSG92ZXIsXG5cdFx0aXNfYXV0b3BsYXk6IGlzQXV0b3BsYXksXG5cdFx0b3JpZW50YXRpb24sXG5cdFx0ZW1iZWRfY29udGV4dDogZW1iZWRDb250ZXh0LFxuXHRcdC4uLm92ZXJyaWRlcyxcblx0fTtcbn1cblxuLyoqXG4gKiBTaGFyZWQgcGxheV9pbnRlbnQgZnJvbSBET00gZmxhZ3MgKGhvdmVyIOKGkiBhdXRvcGxheSDihpIgdXNlcikuXG4gKiBVc2VkIGJ5IFBseXIsIEhUTUw1LCBhbmQgcmF3IFZpbWVvIHNvIHRoZSBmaWVsZCBtZWFucyB0aGUgc2FtZSBldmVyeXdoZXJlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBtZXRhICBmcm9tIHtAbGluayByZXNvbHZlTWV0YUZyb21Eb219XG4gKiBAcmV0dXJucyB7J3VzZXInfCdhdXRvcGxheSd8J2hvdmVyJ31cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBsYXlJbnRlbnRGcm9tTWV0YShtZXRhID0ge30pIHtcblx0aWYgKG1ldGEuaXNfaG92ZXJfcGxheSkgcmV0dXJuICdob3Zlcic7XG5cdGlmIChtZXRhLmlzX2F1dG9wbGF5IHx8IG1ldGEuaXNfbGl2ZV9zdHJlYW0pIHJldHVybiAnYXV0b3BsYXknO1xuXHRyZXR1cm4gJ3VzZXInO1xufVxuXG4vKipcbiAqIEBwYXJhbSB7RWxlbWVudH0gZWxcbiAqIEByZXR1cm5zIHsndmltZW8nfCd5b3V0dWJlJ3wnaHRtbDUnfG51bGx9XG4gKi9cbmZ1bmN0aW9uIGRldGVjdFByb3ZpZGVyKGVsKSB7XG5cdGlmICghZWwpIHJldHVybiBudWxsO1xuXHRjb25zdCBwcm92aWRlckF0dHIgPVxuXHRcdGVsLmdldEF0dHJpYnV0ZT8uKCdkYXRhLXBseXItcHJvdmlkZXInKSB8fFxuXHRcdGVsLmRhdGFzZXQ/LnBseXJQcm92aWRlciB8fFxuXHRcdGVsXG5cdFx0XHQuY2xvc2VzdD8uKCdbZGF0YS1wbHlyLXByb3ZpZGVyXScpXG5cdFx0XHQ/LmdldEF0dHJpYnV0ZSgnZGF0YS1wbHlyLXByb3ZpZGVyJyk7XG5cdGlmIChwcm92aWRlckF0dHIpIHJldHVybiBwcm92aWRlckF0dHI7XG5cblx0Y29uc3QgaWZyYW1lID0gZWwudGFnTmFtZSA9PT0gJ0lGUkFNRScgPyBlbCA6IGVsLnF1ZXJ5U2VsZWN0b3I/LignaWZyYW1lJyk7XG5cdGNvbnN0IHNyYyA9IGlmcmFtZT8uc3JjIHx8IGlmcmFtZT8uZGF0YXNldD8uc3JjIHx8ICcnO1xuXHRpZiAoc3JjLmluY2x1ZGVzKCd2aW1lby5jb20nKSkgcmV0dXJuICd2aW1lbyc7XG5cdGlmIChzcmMuaW5jbHVkZXMoJ3lvdXR1YmUuY29tJykgfHwgc3JjLmluY2x1ZGVzKCd5b3V0dS5iZScpKVxuXHRcdHJldHVybiAneW91dHViZSc7XG5cdGlmIChcblx0XHRlbC50YWdOYW1lID09PSAnVklERU8nIHx8XG5cdFx0ZWwudGFnTmFtZSA9PT0gJ0FVRElPJyB8fFxuXHRcdGVsLnF1ZXJ5U2VsZWN0b3I/LigndmlkZW8sIGF1ZGlvJylcblx0KSB7XG5cdFx0cmV0dXJuICdodG1sNSc7XG5cdH1cblx0cmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogQHBhcmFtIHtFbGVtZW50fSBlbFxuICogQHBhcmFtIHtzdHJpbmd8bnVsbH0gcHJvdmlkZXJcbiAqIEByZXR1cm5zIHtzdHJpbmd8bnVsbH1cbiAqL1xuZnVuY3Rpb24gZXh0cmFjdE1lZGlhSWQoZWwsIHByb3ZpZGVyKSB7XG5cdGlmICghZWwpIHJldHVybiBudWxsO1xuXG5cdGNvbnN0IGVtYmVkSWQgPVxuXHRcdGVsLmdldEF0dHJpYnV0ZT8uKCdkYXRhLXBseXItZW1iZWQtaWQnKSB8fFxuXHRcdGVsLmRhdGFzZXQ/LnBseXJFbWJlZElkIHx8XG5cdFx0ZWxcblx0XHRcdC5jbG9zZXN0Py4oJ1tkYXRhLXBseXItZW1iZWQtaWRdJylcblx0XHRcdD8uZ2V0QXR0cmlidXRlKCdkYXRhLXBseXItZW1iZWQtaWQnKTtcblx0aWYgKGVtYmVkSWQpIHtcblx0XHRjb25zdCBtYXRjaCA9IFN0cmluZyhlbWJlZElkKS5tYXRjaCgvKFxcZHs2LH0pLyk7XG5cdFx0cmV0dXJuIG1hdGNoID8gbWF0Y2hbMV0gOiBTdHJpbmcoZW1iZWRJZCk7XG5cdH1cblxuXHRjb25zdCBpZnJhbWUgPSBlbC50YWdOYW1lID09PSAnSUZSQU1FJyA/IGVsIDogZWwucXVlcnlTZWxlY3Rvcj8uKCdpZnJhbWUnKTtcblx0Y29uc3Qgc3JjID0gaWZyYW1lPy5zcmMgfHwgaWZyYW1lPy5kYXRhc2V0Py5zcmMgfHwgJyc7XG5cdGlmIChwcm92aWRlciA9PT0gJ3ZpbWVvJyB8fCBzcmMuaW5jbHVkZXMoJ3ZpbWVvLmNvbScpKSB7XG5cdFx0Y29uc3QgbSA9IHNyYy5tYXRjaCgvdmlkZW9cXC8oXFxkKykvKSB8fCBzcmMubWF0Y2goL3ZpbWVvXFwuY29tXFwvKFxcZCspLyk7XG5cdFx0aWYgKG0pIHJldHVybiBtWzFdO1xuXHR9XG5cdGlmIChcblx0XHRwcm92aWRlciA9PT0gJ3lvdXR1YmUnIHx8XG5cdFx0c3JjLmluY2x1ZGVzKCd5b3V0dWJlJykgfHxcblx0XHRzcmMuaW5jbHVkZXMoJ3lvdXR1LmJlJylcblx0KSB7XG5cdFx0Y29uc3QgbSA9XG5cdFx0XHRzcmMubWF0Y2goL2VtYmVkXFwvKFtePyYvXSspLykgfHxcblx0XHRcdHNyYy5tYXRjaCgvdj0oW14/Jl0rKS8pIHx8XG5cdFx0XHRzcmMubWF0Y2goL3lvdXR1XFwuYmVcXC8oW14/Ji9dKykvKTtcblx0XHRpZiAobSkgcmV0dXJuIG1bMV07XG5cdH1cblxuXHRjb25zdCBtZWRpYSA9XG5cdFx0ZWwudGFnTmFtZSA9PT0gJ0FVRElPJyB8fCBlbC50YWdOYW1lID09PSAnVklERU8nXG5cdFx0XHQ/IGVsXG5cdFx0XHQ6IGVsLnF1ZXJ5U2VsZWN0b3I/LignYXVkaW8sIHZpZGVvJyk7XG5cdGNvbnN0IHNvdXJjZSA9XG5cdFx0bWVkaWE/LnF1ZXJ5U2VsZWN0b3I/Lignc291cmNlJykgfHwgZWwucXVlcnlTZWxlY3Rvcj8uKCdzb3VyY2UnKTtcblx0Ly8gUHJlZmVyIGN1cnJlbnRTcmMgKHJlc29sdmVkIGFmdGVyIGxvYWQpOyBmYWxsIGJhY2sgdG8gPHNvdXJjZSBzcmM+IHRoZW5cblx0Ly8gdGhlIGVsZW1lbnQgc3JjIGF0dHJpYnV0ZS4gRW1wdHkgYXVkaW9bc3JjXSBvZnRlbiByZXNvbHZlcyB0byB0aGUgcGFnZSBVUkwuXG5cdGxldCBtZWRpYVNyYyA9XG5cdFx0bWVkaWE/LmN1cnJlbnRTcmMgfHxcblx0XHRzb3VyY2U/LnNyYyB8fFxuXHRcdHNvdXJjZT8uZ2V0QXR0cmlidXRlPy4oJ3NyYycpIHx8XG5cdFx0bWVkaWE/LmdldEF0dHJpYnV0ZT8uKCdzcmMnKSB8fFxuXHRcdCcnO1xuXHQvLyBEcm9wIHBhZ2UtVVJMIGZhbHNlIHBvc2l0aXZlcyBmcm9tIGVtcHR5IHNyYyBhdHRyaWJ1dGVzLlxuXHRpZiAobWVkaWFTcmMgJiYgbWVkaWFTcmMgPT09IHdpbmRvdy5sb2NhdGlvbi5ocmVmKSBtZWRpYVNyYyA9ICcnO1xuXHRpZiAobWVkaWFTcmMpIHtcblx0XHR0cnkge1xuXHRcdFx0Y29uc3QgcGF0aCA9IG5ldyBVUkwobWVkaWFTcmMsIHdpbmRvdy5sb2NhdGlvbi5ocmVmKS5wYXRobmFtZTtcblx0XHRcdHJldHVybi
1BwYXRoLnNwbGl0KCcvJykuZmlsdGVyKEJvb2xlYW4pLnBvcCgpIHx8IG1lZGlhU3JjO1xuXHRcdH0gY2F0Y2ggKF9lKSB7XG5cdFx0XHRyZXR1cm4gbWVkaWFTcmM7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogTWFyayBWaW1lbyBpZnJhbWVzIHVuZGVyIHRoaXMgUGx5ciBpbnN0YW5jZSBzbyBydWRkZXJWaWRlbyBza2lwcyB0aGVtLlxuICogSW50ZXJuYWwg4oCUIG9ubHkgYXR0YWNoUGx5clRyYWNraW5nIHVzZXMgaXQuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHBseXIgIFBseXIgaW5zdGFuY2VcbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiBtYXJrUGx5cklmcmFtZXNUcmFja2VkKHBseXIpIHtcblx0Y29uc3QgbWVkaWEgPSBwbHlyPy5tZWRpYSB8fCBwbHlyPy5lbGVtZW50cz8uY29udGFpbmVyO1xuXHRpZiAoIW1lZGlhKSByZXR1cm47XG5cblx0Y29uc3Qgcm9vdCA9XG5cdFx0cGx5ci5lbGVtZW50cz8uY29udGFpbmVyIHx8XG5cdFx0KG1lZGlhLm5vZGVUeXBlID09PSAxID8gbWVkaWEucGFyZW50RWxlbWVudCA6IG51bGwpIHx8XG5cdFx0bWVkaWE7XG5cblx0Y29uc3QgaWZyYW1lcyA9IFtdO1xuXHRpZiAobWVkaWEudGFnTmFtZSA9PT0gJ0lGUkFNRScpIGlmcmFtZXMucHVzaChtZWRpYSk7XG5cdGlmIChyb290Py5xdWVyeVNlbGVjdG9yQWxsKSB7XG5cdFx0cm9vdC5xdWVyeVNlbGVjdG9yQWxsKCdpZnJhbWUnKS5mb3JFYWNoKChmKSA9PiBpZnJhbWVzLnB1c2goZikpO1xuXHR9XG5cblx0aWZyYW1lcy5mb3JFYWNoKChpZnJhbWUpID0+IHtcblx0XHRpZnJhbWUuZGF0YXNldC5ydWRkZXJUcmFja2VkID0gJ3BseXInO1xuXHR9KTtcblxuXHRpZiAocGx5ci5lbGVtZW50cz8uY29udGFpbmVyKSB7XG5cdFx0cGx5ci5lbGVtZW50cy5jb250YWluZXIuZGF0YXNldC5ydWRkZXJUcmFja2VkID0gJ3BseXInO1xuXHR9XG59XG5cbi8qKlxuICogU2hhcmVkIHBsYXkvZmluaXNoL21pbGVzdG9uZSBsb29wIGZvciBhbnkgbWVkaWEgc291cmNlIGV4cG9zaW5nXG4gKiBIVE1MTWVkaWFFbGVtZW50LXN0eWxlIGBjdXJyZW50VGltZWAvYGR1cmF0aW9uYC9gbXV0ZWRgL2B2b2x1bWVgIHBsdXMgYW5cbiAqIGBvbihldmVudCwgY2IpYCBiaW5kZXIg4oCUIGEgbmF0aXZlIDxhdWRpbz4vPHZpZGVvPiBlbGVtZW50IG9yIGEgUGx5clxuICogaW5zdGFuY2UuIEtlZXBzIHRoZSBlbWl0dGVkIGV2ZW50IHNjaGVtYSBpZGVudGljYWwgYWNyb3NzIGJvdGggcGxheWVycy5cbiAqIChOb3RlOiBubyBzdGFuZGFsb25lIGBwYXVzZWAgZXZlbnQgaXMgZW1pdHRlZCDigJQgYHBhdXNlYCBvbmx5IGNhbmNlbHMgdGhlXG4gKiBob3ZlciBkZWJvdW5jZSBiZWxvdy4pXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHNvdXJjZSAgUGx5ciBpbnN0YW5jZSBvciBIVE1MTWVkaWFFbGVtZW50XG4gKiBAcGFyYW0geyhldmVudDogc3RyaW5nLCBjYjogRnVuY3Rpb24pID0+IHZvaWR9IG9uICBldmVudCBiaW5kZXJcbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zXG4gKiBAcGFyYW0ge3N0cmluZ30gIG9wdGlvbnMuZXZlbnROYW1lICByZXNvbHZlZCBSdWRkZXIgZXZlbnQgbmFtZVxuICogQHBhcmFtIHtvYmplY3R9ICBvcHRpb25zLm1ldGEgIHJlc29sdmVkIG1ldGEgKHN1cmZhY2UsIHByb3ZpZGVyLCBtZWRpYV9pZCwg4oCmKVxuICogQHBhcmFtIHtFbGVtZW50fG51bGx9IFtvcHRpb25zLmVsXSAgZWxlbWVudCB1c2VkIHRvIChyZSlleHRyYWN0IG1lZGlhX2lkXG4gKiBAcGFyYW0geygpID0+IHN0cmluZ30gW29wdGlvbnMuZ2V0UGxheUludGVudF0gIGNhbGxlZCBvbiB0aGUgcGxheSB0aGF0IGNvdW50c1xuICogQHBhcmFtIHtzdHJpbmd9ICBbb3B0aW9ucy5wbGF5ZXJdICByZXNvbHZlZCBwbGF5ZXIgdHlwZSAoJ3BseXInfCdodG1sNSd84oCmKVxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhdHRhY2hNZWRpYVRyYWNraW5nKHNvdXJjZSwgb24sIG9wdGlvbnMgPSB7fSkge1xuXHRjb25zdCB7XG5cdFx0ZXZlbnROYW1lLFxuXHRcdG1ldGEgPSB7fSxcblx0XHRlbCA9IG51bGwsXG5cdFx0Z2V0UGxheUludGVudCA9ICgpID0+ICd1c2VyJyxcblx0XHRwbGF5ZXIgPSAnaHRtbDUnLFxuXHR9ID0gb3B0aW9ucztcblxuXHRjb25zdCBmaXJlZE1pbGVzdG9uZXMgPSBuZXcgU2V0KCk7XG5cdGxldCBtZWRpYUlkID0gbWV0YS5tZWRpYV9pZCB8fCBudWxsO1xuXHRsZXQgcGxheUludGVudCA9ICd1bmtub3duJztcblx0bGV0IHBsYXlGaXJlZCA9IGZhbHNlOyAvLyBmaXJzdCBwbGF5IG9ubHkg4oCUIHJlc3VtZXMvcmVwbGF5cyBkb24ndCByZS1maXJlXG5cdGxldCBob3ZlclRpbWVyID0gbnVsbDtcblxuXHRjb25zdCByZWZyZXNoTWVkaWFJZCA9ICgpID0+IHtcblx0XHRpZiAoIW1lZGlhSWQgJiYgZWwpIHtcblx0XHRcdGNvbnN0IHJlZnJlc2hlZCA9IGV4dHJhY3RNZWRpYUlkKGVsLCBtZXRhLnByb3ZpZGVyKTtcblx0XHRcdGlmIChyZWZyZXNoZWQpIG1lZGlhSWQgPSByZWZyZXNoZWQ7XG5cdFx0fVxuXHR9O1xuXG5cdGNvbnN0IGJhc2VQcm9wcyA9IChleHRyYSA9IHt9KSA9PiB7XG5cdFx0cmVmcmVzaE1lZGlhSWQoKTtcblx0XHRjb25zdCBjdXJyZW50VGltZSA9IG51bWVyaWNPck51bGwoc291cmNlLmN1cnJlbnRUaW1lKSA/PyAwO1xuXHRcdGNvbnN0IGR1cmF0aW9uID0gbnVtZXJpY09yTnVsbChzb3VyY2UuZHVyYXRpb24pO1xuXHRcdGNvbnN0IHBlcmNlbnQgPVxuXHRcdFx0ZHVyYXRpb24gJiYgZHVyYXRpb24gPiAwID8gY3VycmVudFRpbWUgLyBkdXJhdGlvbiA6IG51bGw7XG5cblx0XHRyZXR1cm4gY3JlYXRlTWVkaWFFdmVudCh7XG5cdFx0XHRzdXJmYWNlOiBtZXRhLnN1cmZhY2UsXG5cdFx0XHRwcm92aWRlcjogbWV0YS5wcm92aWRlcixcblx0XHRcdHBsYXllcixcblx0XHRcdG1lZGlhX2lkOiBtZWRpYUlkLFxuXHRcdFx0bWVkaWFfdGl0bGU6IG1ldGEubWVkaWFfdGl0bGUsXG5cdFx0XHRjdXJyZW50X3RpbWU6IGN1cnJlbnRUaW1lLFxuXHRcdFx0ZHVyYXRpb24sXG5cdFx0XHRwZXJjZW50LFxuXHRcdFx0bXV0ZWQ6ICEhKHNvdXJjZS5tdXRlZCB8fCBzb3VyY2Uudm9sdW1lID09PSAwKSxcblx0XHRcdHBsYXlfaW50ZW50OiBwbGF5SW50ZW50LFxuXHRcdFx0aXNfbGl2ZV9zdHJlYW06IG1ldGEuaXNfbGl2ZV9zdHJlYW0sXG5cdFx0XHRvcmllbnRhdGlvbjogbWV0YS5vcmllbnRhdGlvbixcblx0XHRcdGVtYmVkX2NvbnRleHQ6IG1ldGEuZW1iZWRfY29udGV4dCxcblx0XHRcdC8vIGFjdGlvbiAvIHByb2dyZXNzIC8gcGVyY2VudCBvdmVycmlkZXMgZnJvbSB0aGUgY2FsbGVyLlxuXHRcdFx0Li4uZXh0cmEsXG5cdFx0fSk7XG5cdH07XG5cblx0Y29uc3QgY2xlYXJIb3ZlclRpbWVyID0gKCkgPT4ge1xuXHRcdGlmIChob3ZlclRpbWVyKSB7XG5cdFx0XHRjbGVhclRpbWVvdXQoaG92ZXJUaW1lcik7XG5cdFx0XHRob3ZlclRpbWVyID0gbnVsbDtcblx0XHR9XG5cdH07XG5cblx0Y29uc3QgZmlyZVBsYXkgPSAoKSA9PiB7XG5cdFx0aWYgKHBsYXlGaXJlZCkgcmV0dXJuO1xuXHRcdHBsYXlGaXJlZCA9IHRydWU7XG5cdFx0dHJhY2tNZWRpYShldmVudE5hbWUsIGJhc2VQcm9wcyh7IGFjdGlvbjogJ3BsYXknIH0pKTtcblx0fTtcblxuXHQvLyBPbmUgYHBsYXlgIHBlciBtZWRpYSAoZmlyc3QgcGxheSBvbmx5KS4gSG92ZXItcHJldmlldyBwbGF5cyBhcmUgZGVib3VuY2VkLFxuXHQvLyBzbyBhIHN3aXBlIGFjcm9zcyBhIGdyaWQgZG9lc24ndCBjb3VudCDigJQgb25seSA+PSBIT1ZFUl9QTEFZX0RFTEFZX01TIG9mXG5cdC8vIGNvbnRpbnVvdXMgcGxheWJhY2sgZG9lcy5cblx0b24oJ3BsYXknLCAoKSA9PiB7XG5cdFx0aWYgKHBsYXlGaXJlZCB8fCBob3ZlclRpbWVyKSByZXR1cm47XG5cdFx0cGxheUludGVudCA9IGdldFBsYXlJbnRlbnQoKTtcblx0XHRpZiAocGxheUludGVudCA9PT0gJ2hvdmVyJykge1xuXHRcdFx0aG92ZXJUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0XHRob3ZlclRpbWVyID0gbnVsbDtcblx0XHRcdFx0ZmlyZVBsYXkoKTtcblx0XHRcdH0sIEhPVkVSX1BMQVlfREVMQVlfTVMpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRmaXJlUGxheSgpO1xuXHRcdH1cblx0fSk7XG5cblx0Ly8gQSBob3ZlciB0aGF0IHN0b3BzIGJlZm9yZSB0aGUgZGVib3VuY2UgZWxhcHNlcyBuZXZlciBiZWNvbWVzIGEgcGxheS5cblx0Ly8gTm8gc3RhbmRhbG9uZSBg
1cGF1c2VgIGV2ZW50IGlzIGVtaXR0ZWQuXG5cdG9uKCdwYXVzZScsIGNsZWFySG92ZXJUaW1lcik7XG5cblx0b24oJ2VuZGVkJywgKCkgPT4ge1xuXHRcdGNsZWFySG92ZXJUaW1lcigpO1xuXHRcdGlmIChwbGF5RmlyZWQpIHtcblx0XHRcdHRyYWNrTWVkaWEoZXZlbnROYW1lLCBiYXNlUHJvcHMoeyBhY3Rpb246ICdmaW5pc2gnLCBwZXJjZW50OiAxIH0pKTtcblx0XHR9XG5cdH0pO1xuXG5cdC8vIFByb2dyZXNzIG1pbGVzdG9uZXMgKG1heCByZWFjaGVkIOKJiCAlIHdhdGNoZWQpLiBOZXZlciBmb3IgbGl2ZSBzdHJlYW1zLFxuXHQvLyBhbmQgbmV2ZXIgYmVmb3JlIHRoZSBwbGF5IGl0c2VsZiBoYXMgYmVlbiBjb3VudGVkLlxuXHRpZiAoIW1ldGEuaXNfbGl2ZV9zdHJlYW0pIHtcblx0XHRvbigndGltZXVwZGF0ZScsICgpID0+IHtcblx0XHRcdGlmICghcGxheUZpcmVkKSByZXR1cm47XG5cdFx0XHRjb25zdCBjdXJyZW50VGltZSA9IG51bWVyaWNPck51bGwoc291cmNlLmN1cnJlbnRUaW1lKSA/PyAwO1xuXHRcdFx0Y29uc3QgZHVyYXRpb24gPSBudW1lcmljT3JOdWxsKHNvdXJjZS5kdXJhdGlvbik7XG5cdFx0XHRpZiAoIWR1cmF0aW9uIHx8IGR1cmF0aW9uIDw9IDApIHJldHVybjtcblxuXHRcdFx0Y29uc3QgcGN0ID0gKGN1cnJlbnRUaW1lIC8gZHVyYXRpb24pICogMTAwO1xuXHRcdFx0Zm9yIChjb25zdCBtaWxlc3RvbmUgb2YgTUlMRVNUT05FUykge1xuXHRcdFx0XHRpZiAocGN0ID49IG1pbGVzdG9uZSAmJiAhZmlyZWRNaWxlc3RvbmVzLmhhcyhtaWxlc3RvbmUpKSB7XG5cdFx0XHRcdFx0ZmlyZWRNaWxlc3RvbmVzLmFkZChtaWxlc3RvbmUpO1xuXHRcdFx0XHRcdHRyYWNrTWVkaWEoXG5cdFx0XHRcdFx0XHRldmVudE5hbWUsXG5cdFx0XHRcdFx0XHRiYXNlUHJvcHMoe1xuXHRcdFx0XHRcdFx0XHRhY3Rpb246ICdtaWxlc3RvbmUnLFxuXHRcdFx0XHRcdFx0XHRwcm9ncmVzczogbWlsZXN0b25lLFxuXHRcdFx0XHRcdFx0XHRwZXJjZW50OiBjdXJyZW50VGltZSAvIGR1cmF0aW9uLFxuXHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cbn1cblxuLyoqXG4gKiBBdHRhY2ggdHJhY2tpbmcgdG8gYSBQbHlyIGluc3RhbmNlIChGUCBWaWRlbywgb24tZGVtYW5kIEZQIExpdmUsIHBvZGNhc3RcbiAqIHNlY3Rpb24gcGxheWVycykuIERlbGVnYXRlcyB0aGUgZXZlbnQgbG9vcCB0byBhdHRhY2hNZWRpYVRyYWNraW5nLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBwbHlyICBQbHlyIGluc3RhbmNlXG4gKiBAcGFyYW0ge29iamVjdH0gW21ldGFdICBPcHRpb25hbCBwcmUtcmVzb2x2ZWQgbWV0YSAoc3VyZmFjZSwgbWVkaWFfaWQsIOKApilcbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5leHBvcnQgZnVuY3Rpb24gYXR0YWNoUGx5clRyYWNraW5nKHBseXIsIG1ldGEgPSB7fSkge1xuXHRpZiAoIXBseXIgfHwgdHlwZW9mIHBseXIub24gIT09ICdmdW5jdGlvbicpIHJldHVybjtcblxuXHQvLyBBdm9pZCBkb3VibGUtYXR0YWNoXG5cdGlmIChwbHlyLl9fcnVkZGVyVHJhY2tlZCkgcmV0dXJuO1xuXG5cdC8vIFByZWZlciBwbHlyLm1lZGlhICh0aGUgZWxlbWVudCBQbHlyIHdhcyBpbml0aWFsaXNlZCBvbiDigJQgdGhlIC5wbHlyLXBsYXllcilcblx0Ly8gc28gYSBkYXRhLXJ1ZGRlci1tZWRpYS1zdXJmYWNlIHRhZyBvbiB0aGUgcGxheWVyIGVsZW1lbnQgaXRzZWxmIGlzIGhvbm91cmVkLFxuXHQvLyBub3QganVzdCBvbiBhbiBhbmNlc3Rvci4gSXQgYWxzbyBjYXJyaWVzIGRhdGEtcGx5ci1lbWJlZC1pZCAvIG9yaWVudGF0aW9uLlxuXHRjb25zdCBob3N0RWwgPSBwbHlyLm1lZGlhIHx8IHBseXIuZWxlbWVudHM/LmNvbnRhaW5lciB8fCBudWxsO1xuXG5cdC8vIHJlc29sdmVNZXRhRnJvbURvbSBhbHJlYWR5IHJlc29sdmVzIHRoZSBzdXJmYWNlICh2aWEgcmVzb2x2ZVN1cmZhY2UpIGFuZFxuXHQvLyBmb2xkcyBgbWV0YWAgaW4gdGhyb3VnaCBpdHMgdHJhaWxpbmcgLi4ub3ZlcnJpZGVzLlxuXHRjb25zdCByZXNvbHZlZCA9IHJlc29sdmVNZXRhRnJvbURvbShob3N0RWwsIG1ldGEpO1xuXHRjb25zdCBldmVudE5hbWUgPSBldmVudE5hbWVGb3JTdXJmYWNlKHJlc29sdmVkLnN1cmZhY2UpO1xuXHRpZiAoIWV2ZW50TmFtZSkgcmV0dXJuO1xuXG5cdC8vIE1hcmsgb25seSBvbmNlIHdlJ3ZlIGNvbW1pdHRlZCB0byB0cmFja2luZy4gQmFpbGluZyBhYm92ZSBtdXN0IGxlYXZlIHRoZVxuXHQvLyBpbnN0YW5jZSBVTm1hcmtlZCwgc28gYSBsYXRlciBjb3JyZWN0bHktdGFnZ2VkIGNhbGwgY2FuIHN0aWxsIGF0dGFjaCBhbmQgc29cblx0Ly8gaXRzIGlmcmFtZXMgYXJlbid0IGZhbHNlbHkgZmxhZ2dlZCBhcyBQbHlyLWNsYWltZWQgKHdoaWNoIHdvdWxkIG1ha2Vcblx0Ly8gcnVkZGVyVmlkZW8gc2tpcCBhIHJhdy1WaW1lbyBpZnJhbWUgdGhhdCB3YXMgbmV2ZXIgYWN0dWFsbHkgdHJhY2tlZCkuXG5cdHBseXIuX19ydWRkZXJUcmFja2VkID0gdHJ1ZTtcblx0bWFya1BseXJJZnJhbWVzVHJhY2tlZChwbHlyKTtcblxuXHRhdHRhY2hNZWRpYVRyYWNraW5nKHBseXIsIChldmVudCwgY2IpID0+IHBseXIub24oZXZlbnQsIGNiKSwge1xuXHRcdGV2ZW50TmFtZSxcblx0XHRtZXRhOiByZXNvbHZlZCxcblx0XHRlbDogaG9zdEVsLFxuXHRcdGdldFBsYXlJbnRlbnQ6ICgpID0+IHBsYXlJbnRlbnRGcm9tTWV0YShyZXNvbHZlZCksXG5cdFx0cGxheWVyOiByZXNvbHZlZC5wbGF5ZXIgfHwgJ3BseXInLFxuXHR9KTtcblxuXHQvLyBMYXRlLWNyZWF0ZWQgaWZyYW1lIChWaW1lby9Zb3VUdWJlIGVtYmVkcykg4oCUIHJlLW1hcmsgYWZ0ZXIgcmVhZHkuXG5cdC8vIChtZWRpYV9pZCBpcyAocmUpcmVzb2x2ZWQgbGF6aWx5IG9uIGV2ZXJ5IGVtaXQsIHNvIG5vIHJlZnJlc2ggbmVlZGVkIGhlcmUuKVxuXHRwbHlyLm9uKCdyZWFkeScsICgpID0+IG1hcmtQbHlySWZyYW1lc1RyYWNrZWQocGx5cikpO1xufVxuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../assets/src/scripts/rudder/rudderMedia.js\n\n}")},"../assets/src/scripts/rudder/rudderNoa.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){"use strict";eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _babel_runtime_helpers_typeof__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/typeof */ \"./node_modules/@babel/runtime/helpers/esm/typeof.js\");\n/* harmony import */ var _babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @babel/runtime/helpers/classCallCheck */ \"./node_modules/@babel/runtime/helpers/esm/classCallCheck.js\");\n/* harmony import */ var _babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @babel/runtime/helpers/createClass */ \"./node_modules/@babel/runtime/helpers/esm/createClass.js\");\n/* harmony import */ var _rudderMedia__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./rudderMedia */ \"../assets/src/scripts/rudder/rudderMedia.js\");
1\n\n\n\n/**\n * News Over Audio â Rudder tracking.\n *\n * Listens for postMessage events from the NOA embed player. Payload shape is\n * per NOA's \"postMessage API\" spec:\n * { type, source: 'noa-embed-player', timestamp, data: { currentTime,\n * duration, progress? } }\n * Structured events are only emitted by NOA for allowlisted publisher keys â\n * FP's `fp5d9t` must be allowlisted by NOA before production traffic appears.\n */\n\n\nvar NOA_SOURCE = 'noa-embed-player';\nvar NOA_IFRAME_SELECTOR = '#noa-audio-iframe';\n\n/**\n * First-play + milestones only (see NOA postMessage API for the full catalog).\n * NOA has no `ended` event, so \"listened fully\" is the 95% milestone.\n */\nvar TYPE_TO_ACTION = {\n NOA_AUDIO_PLAY: 'play',\n NOA_AUDIO_INITIAL_PLAY: 'play',\n NOA_AUDIO_MILESTONE_COMPLETE: 'milestone'\n};\nvar RudderNoa = /*#__PURE__*/function () {\n function RudderNoa() {\n (0,_babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(this, RudderNoa);\n this.isInitialized = false;\n this.messageHandler = this.handleMessage.bind(this);\n this.readyHandler = this.handleReady.bind(this);\n this.firedMilestones = new Set();\n this.playFired = false; // first play only â resumes don't re-fire\n this.postId = null; // WP post ID â used as media_id\n }\n return (0,_babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(RudderNoa, [{\n key: \"init\",\n value: function init() {\n if (this.isInitialized) return;\n this.isInitialized = true;\n // Capture the WP post id when our embed resolves (see\n // components/post/noa.js).\n document.addEventListener('noa:ready', this.readyHandler);\n window.addEventListener('message', this.messageHandler);\n }\n\n /**\n * Single lookup for the NOA embed iframe.\n *\n * @returns {HTMLIFrameElement|null}\n */\n }, {\n key: \"getIframe\",\n value: function getIframe() {\n return document.querySelector(NOA_IFRAME_SELECTOR);\n }\n\n /**\n * @param {CustomEvent} event\n * @returns {void}\n */\n }, {\n key: \"handleReady\",\n value: function handleReady(event) {\n var detail = event.detail || {};\n if (detail.post_id != null) this.postId = String(detail.post_id);\n }\n\n /**\n * @param {MessageEvent} event\n * @returns {void}\n */\n }, {\n key: \"handleMessage\",\n value: function handleMessage(event) {\n // Structured payload from NOA sendEventToParent\n var data = event.data;\n if (!data || (0,_babel_runtime_helpers_typeof__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(data) !== 'object') return;\n if (data.source !== NOA_SOURCE) return;\n\n // `source` is spoofable by any script on the page, so the origin is the\n // real trust boundary â require a known NOA host.\n if (!this.isAllowedOrigin(event.origin)) return;\n var type = data.type;\n var action = TYPE_TO_ACTION[type];\n if (!action) return;\n\n // Surface is declared on the NOA iframe (data-rudder-media-surface).\n var surface = this.getSurface();\n var eventName = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_3__.eventNameForSurface)(surface);\n if (!eventName) return;\n\n // First play only â a resume must not re-fire (matches the other players).\n if (action === 'play') {\n if (this.playFired) return;\n this.playFired = true;\n }\n\n // Milestones only after a counted play (matches attachMediaTracking).\n if (action === 'milestone' && !this.playFired) return;\n var payload = data.data || {};\n var properties = this.buildProperties(action, payload, surface);\n\n // Deduplicate milestones within a page session, scoped to the audio id\n // so a second clip's milestones aren't suppressed by the first's.\n if (action === 'milestone') {\n var progress = properties.progress;\n if (progress == null) return;\n var key = \"\".concat(properties.media_id || 'noa', \":\").concat(progress);\n if (this.firedMilestones.has(key)) return;\n this.firedMilestones.add(key);\n }\n (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_3__.trackMedia)(eventName, properties);\n }\n\n /**\n * Surface declared on the NOA iframe via data-rudder-media-surface.\n *\n * @returns {string|null}\n */\n }, {\n key: \"getSurface\",\n value: function getSurface() {\n return (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_3__.resolveSurface)(this.getIframe());\n }\n\n /**\n * @param {string} origin\n * @returns {boolean}\n */\n }, {\n key: \"isAllowedOrigin\",\n value: function isAllowedOrigin(origin) {\n tr
1y {\n var url = new URL(origin);\n return url.hostname === 'newsoveraudio.com' || url.hostname.endsWith('.newsoveraudio.com');\n } catch (_e) {\n return false;\n }\n }\n\n /**\n * @param {string} action\n * @param {object} payload\n * @param {string} surface resolved surface for this player\n * @returns {object}\n */\n }, {\n key: \"buildProperties\",\n value: function buildProperties(action, payload, surface) {\n var currentTime = typeof payload.currentTime === 'number' ? payload.currentTime : null;\n var duration = typeof payload.duration === 'number' ? payload.duration : null;\n var percent = currentTime != null && duration && duration > 0 ? currentTime / duration : null;\n var mediaId = this.getMediaId();\n var iframe = this.getIframe();\n var meta = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_3__.resolveMetaFromDom)(iframe, {\n surface: surface,\n provider: 'noa',\n player: (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_3__.resolvePlayerType)(iframe) || 'noa',\n media_id: mediaId\n });\n return (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_3__.createMediaEvent)({\n action: action,\n surface: meta.surface,\n provider: 'noa',\n player: meta.player || 'noa',\n media_id: mediaId,\n media_title: meta.media_title,\n current_time: currentTime,\n duration: duration,\n percent: percent,\n progress: action === 'milestone' ? payload.progress : null,\n play_intent: (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_3__.playIntentFromMeta)(meta),\n // NOA postMessage doesn't expose mute state.\n muted: null,\n is_live_stream: false,\n orientation: meta.orientation,\n embed_context: meta.embed_context\n });\n }\n\n /**\n * WP post ID for media_id (joins to page() / rudderData.postId).\n *\n * @returns {string|null}\n */\n }, {\n key: \"getMediaId\",\n value: function getMediaId() {\n var _ref, _ref2, _window$fpNoaData$pos, _window$fpNoaData, _window$rudderData, _window$FP;\n if (this.postId) return this.postId;\n var id = (_ref = (_ref2 = (_window$fpNoaData$pos = (_window$fpNoaData = window.fpNoaData) === null || _window$fpNoaData === void 0 ? void 0 : _window$fpNoaData.post_id) !== null && _window$fpNoaData$pos !== void 0 ? _window$fpNoaData$pos : (_window$rudderData = window.rudderData) === null || _window$rudderData === void 0 ? void 0 : _window$rudderData.postId) !== null && _ref2 !== void 0 ? _ref2 : (_window$FP = window.FP) === null || _window$FP === void 0 || (_window$FP = _window$FP.mobileApp) === null || _window$FP === void 0 ? void 0 : _window$FP.postId) !== null && _ref !== void 0 ? _ref : null;\n if (id != null) {\n this.postId = String(id);\n return this.postId;\n }\n return null;\n }\n }]);\n}();\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (RudderNoa);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJOb2EuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQVVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFHQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBSkE7QUFBQTtBQUFBO0FBTUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUhBO0FBQUE7QUFBQTtBQUtBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUhBO0FBQUE7QUFBQTtBQUtBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUpBO0FBQUE7QUFBQTtBQU1BO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFIQTtBQUFBO0FBQUE7QUFLQTtBQUNBO0FBQ0E7QUFJQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFMQTtBQUFBO0FBQUE7QUFPQTtBQUlBO0FBRUE7QUFLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0F
1BRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUpBO0FBQUE7QUFBQTtBQUtBO0FBQ0E7QUFFQTtBQU1BO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUFBO0FBQUE7QUFHQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJOb2EuanM/MDczNiJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE5ld3MgT3ZlciBBdWRpbyDihpIgUnVkZGVyIHRyYWNraW5nLlxuICpcbiAqIExpc3RlbnMgZm9yIHBvc3RNZXNzYWdlIGV2ZW50cyBmcm9tIHRoZSBOT0EgZW1iZWQgcGxheWVyLiBQYXlsb2FkIHNoYXBlIGlzXG4gKiBwZXIgTk9BJ3MgXCJwb3N0TWVzc2FnZSBBUElcIiBzcGVjOlxuICogICB7IHR5cGUsIHNvdXJjZTogJ25vYS1lbWJlZC1wbGF5ZXInLCB0aW1lc3RhbXAsIGRhdGE6IHsgY3VycmVudFRpbWUsXG4gKiAgICAgZHVyYXRpb24sIHByb2dyZXNzPyB9IH1cbiAqIFN0cnVjdHVyZWQgZXZlbnRzIGFyZSBvbmx5IGVtaXR0ZWQgYnkgTk9BIGZvciBhbGxvd2xpc3RlZCBwdWJsaXNoZXIga2V5cyDigJRcbiAqIEZQJ3MgYGZwNWQ5dGAgbXVzdCBiZSBhbGxvd2xpc3RlZCBieSBOT0EgYmVmb3JlIHByb2R1Y3Rpb24gdHJhZmZpYyBhcHBlYXJzLlxuICovXG5cbmltcG9ydCB7XG5cdHRyYWNrTWVkaWEsXG5cdGNyZWF0ZU1lZGlhRXZlbnQsXG5cdGV2ZW50TmFtZUZvclN1cmZhY2UsXG5cdHJlc29sdmVTdXJmYWNlLFxuXHRyZXNvbHZlUGxheWVyVHlwZSxcblx0cmVzb2x2ZU1ldGFGcm9tRG9tLFxuXHRwbGF5SW50ZW50RnJvbU1ldGEsXG59IGZyb20gJy4vcnVkZGVyTWVkaWEnO1xuXG5jb25zdCBOT0FfU09VUkNFID0gJ25vYS1lbWJlZC1wbGF5ZXInO1xuY29uc3QgTk9BX0lGUkFNRV9TRUxFQ1RPUiA9ICcjbm9hLWF1ZGlvLWlmcmFtZSc7XG5cbi8qKlxuICogRmlyc3QtcGxheSArIG1pbGVzdG9uZXMgb25seSAoc2VlIE5PQSBwb3N0TWVzc2FnZSBBUEkgZm9yIHRoZSBmdWxsIGNhdGFsb2cpLlxuICogTk9BIGhhcyBubyBgZW5kZWRgIGV2ZW50LCBzbyBcImxpc3RlbmVkIGZ1bGx5XCIgaXMgdGhlIDk1JSBtaWxlc3RvbmUuXG4gKi9cbmNvbnN0IFRZUEVfVE9fQUNUSU9OID0ge1xuXHROT0FfQVVESU9fUExBWTogJ3BsYXknLFxuXHROT0FfQVVESU9fSU5JVElBTF9QTEFZOiAncGxheScsXG5cdE5PQV9BVURJT19NSUxFU1RPTkVfQ09NUExFVEU6ICdtaWxlc3RvbmUnLFxufTtcblxuY2xhc3MgUnVkZGVyTm9hIHtcblx0Y29uc3RydWN0b3IoKSB7XG5cdFx0dGhpcy5pc0luaXRpYWxpemVkID0gZmFsc2U7XG5cdFx0dGhpcy5tZXNzYWdlSGFuZGxlciA9IHRoaXMuaGFuZGxlTWVzc2FnZS5iaW5kKHRoaXMpO1xuXHRcdHRoaXMucmVhZHlIYW5kbGVyID0gdGhpcy5oYW5kbGVSZWFkeS5iaW5kKHRoaXMpO1xuXHRcdHRoaXMuZmlyZWRNaWxlc3RvbmVzID0gbmV3IFNldCgpO1xuXHRcdHRoaXMucGxheUZpcmVkID0gZmFsc2U7IC8vIGZpcnN0IHBsYXkgb25seSDigJQgcmVzdW1lcyBkb24ndCByZS1maXJlXG5cdFx0dGhpcy5wb3N0SWQgPSBudWxsOyAvLyBXUCBwb3N0IElEIOKAlCB1c2VkIGFzIG1lZGlhX2lkXG5cdH1cblxuXHRpbml0KCkge1xuXHRcdGlmICh0aGlzLmlzSW5pdGlhbGl6ZWQpIHJldHVybjtcblx0XHR0aGlzLmlzSW5pdGlhbGl6ZWQgPSB0cnVlO1xuXHRcdC8vIENhcHR1cmUgdGhlIFdQIHBvc3QgaWQgd2hlbiBvdXIgZW1iZWQgcmVzb2x2ZXMgKHNlZVxuXHRcdC8vIGNvbXBvbmVudHMvcG9zdC9ub2EuanMpLlxuXHRcdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ25vYTpyZWFkeScsIHRoaXMucmVhZHlIYW5kbGVyKTtcblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIHRoaXMubWVzc2FnZUhhbmRsZXIpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNpbmdsZSBsb29rdXAgZm9yIHRoZSBOT0EgZW1iZWQgaWZyYW1lLlxuXHQgKlxuXHQgKiBAcmV0dXJucyB7SFRNTElGcmFtZUVsZW1lbnR8bnVsbH1cblx0ICovXG5cdGdldElmcmFtZSgpIHtcblx0XHRyZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihOT0FfSUZSQU1FX1NFTEVDVE9SKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBAcGFyYW0ge0N1c3RvbUV2ZW50fSBldmVudFxuXHQgKiBAcmV0dXJucyB7dm9pZH1cblx0ICovXG5cdGhhbmRsZVJlYWR5KGV2ZW50KSB7XG5cdFx0Y29uc3QgZGV0YWlsID0gZXZlbnQuZGV0YWlsIHx8IHt9O1xuXHRcdGlmIChkZXRhaWwucG9zdF9pZCAhPSBudWxsKSB0aGlzLnBvc3RJZCA9IFN0cmluZyhkZXRhaWwucG9zdF9pZCk7XG5cdH1cblxuXHQvKipcblx0ICogQHBhcmFtIHtNZXNzYWdlRXZlbnR9IGV2ZW50XG5cdCAqIEByZXR1cm5zIHt2b2lkfVxuXHQgKi9cblx0aGFuZGxlTWVzc2FnZShldmVudCkge1xuXHRcdC8vIFN0cnVjdHVyZWQgcGF5bG9hZCBmcm9tIE5PQSBzZW5kRXZlbnRUb1BhcmVudFxuXHRcdGNvbnN0IGRhdGEgPSBldmVudC5kYXRhO1xuXHRcdGlmICghZGF0YSB8fCB0eXBlb2YgZGF0YSAhPT0gJ29iamVjdCcpIHJldHVybjtcblx0XHRpZiAoZGF0YS5zb3VyY2UgIT09IE5PQV9TT1VSQ0UpIHJldHVybjtcblxuXHRcdC8vIGBzb3VyY2VgIGlzIHNwb29mYWJsZSBieSBhbnkgc2NyaXB0IG9uIHRoZSBwYWdlLCBzbyB0aGUgb3JpZ2luIGlzIHRoZVxuXHRcdC8vIHJlYWwgdHJ1c3QgYm91bmRhcnkg4oCUIHJlcXVpcmUgYSBrbm93biBOT0EgaG9zdC5cblx0XHRpZiAoIXRoaXMuaXNBbGxvd2VkT3JpZ2luKGV2ZW50Lm9yaWdpbikpIHJldHVybjtcblxuXHRcdGNvbnN0IHR5cGUgPSBkYXRhLnR5cGU7XG5cdFx0Y29uc3QgYWN0aW9uID0gVFlQRV9UT19BQ1RJT05bdHlwZV07XG5cdFx0aWYgKCFhY3Rpb24pIHJldHVybjtcblxuXHRcdC8vIFN1cmZhY2UgaXMgZGVjbGFyZWQgb24gdGhlIE5PQSBpZnJhbWUgKGRhdGEtcnVkZGVyLW1lZGlhLXN1cmZhY2UpLlxuXHRcdGNvbnN0IHN1cmZhY2UgPSB0aGlzLmdldFN1cmZhY2UoKTtcblx0XHRjb25zdCBldmVudE5hbWUgPSBldmVudE5hbWVGb3JTdXJmYWNlKHN1cmZhY2UpO1xuXHRcdGlmICghZXZlbnROYW1lKSByZXR1cm47XG5cblx0XHQvLyBGaXJzdCBwbGF5IG9ubHkg4oCUIGEgcmVzdW1lIG11c3Qgbm90IHJlLWZpcmUgKG1hdGNoZXMgdGhlIG90aGVyIHBsYXllcnMpLlxuXHRcdGlmIChhY3Rpb24gPT09ICdwbGF5Jykge1xuXHRcdFx0aWYgKHRoaXMucGxheUZpcmVkKSByZXR1cm47XG5cdFx0XHR0aGlzLnBsYXlGaXJlZCA9IHRydWU7XG5cdFx0fVxuXG5cdFx0Ly8gTWlsZXN0b25lcyBvbmx5IGFmdGVyIGEgY291bnRlZCBwbGF5IChtYXRjaGVzIGF0dGFjaE1lZGlhVHJhY2tpbmcpLlxuXHRcdGlmIChhY3Rpb24gPT09ICdtaWxlc3RvbmUnICYmICF0aGlzLnBsYXlGaXJlZCkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgcGF5bG9hZCA9IGRhdGEuZGF0YSB8fCB7fTtcblx0XHRjb25zdCBwcm9wZXJ0aWVzID0gdGhpcy5idWlsZFByb3BlcnRpZXMoYWN0aW9uLCBwYXlsb2FkLCBzdXJmYWNlKTtcblxuXHRcdC8vIERlZHVwbGljYXRlIG1pbGVzdG9uZXMgd2l0aGluIGEgcGFnZSBzZXNzaW9uLCBzY29wZWQgdG8gdGhlIGF1ZGlvIGlkXG5cdFx0Ly8gc28gYSBzZWNvbmQgY2xpcCdzIG1pbGVzdG9uZXMgYXJlbid0IHN1cHByZXNzZWQgYnkgdGhlIGZpcnN0J3MuXG5cdFx0aWYgKGFjdGlvbiA9PT0gJ21pbGVzdG9uZScpIHtcblx0XHRcdGNvbnN0IHByb2dyZXNzID0gcHJvcGVydGllcy5wcm9ncmVzcztcblx0XHRcdGlmIChwcm9ncmVzcyA9PSBudWxsKSByZXR1cm47XG5cdFx0XHRjb25zdCBrZXkgPSBgJHtwcm9wZXJ0aWVzLm1lZGlhX2lkIHx8ICdub2EnfToke3Byb2dyZXNzfWA7XG5cdFx0XHRpZiAodGhpcy5maXJlZE1pbGVzdG9uZXMuaGFzKGtleSkpIHJldHVybjtcblx0XHRcdHRoaXMuZmlyZWRNaWxlc3RvbmVzLmFkZChrZXkpO1xuXHRcdH1cblxuXHRcdHRyYWNrTWVkaWEoZXZlbnROYW1lLCBwcm9wZXJ0aWVzKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTdXJmYWNlIGRlY2xhcmVkIG9uIHRoZSBOT0EgaWZyYW1lIHZpYSBkYXRhLXJ1ZGRlci1tZWRpYS1zdXJmYWNlLlxuXHQgKlxuXHQgKiBAcmV0dXJucyB7c3RyaW5nfG51bGx9XG5cdCAqL1xuXHRnZXRTdXJmYWNlKCkge1xuXHRcdHJldHVybi
1ByZXNvbHZlU3VyZmFjZSh0aGlzLmdldElmcmFtZSgpKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gb3JpZ2luXG5cdCAqIEByZXR1cm5zIHtib29sZWFufVxuXHQgKi9cblx0aXNBbGxvd2VkT3JpZ2luKG9yaWdpbikge1xuXHRcdHRyeSB7XG5cdFx0XHRjb25zdCB1cmwgPSBuZXcgVVJMKG9yaWdpbik7XG5cdFx0XHRyZXR1cm4gKFxuXHRcdFx0XHR1cmwuaG9zdG5hbWUgPT09ICduZXdzb3ZlcmF1ZGlvLmNvbScgfHxcblx0XHRcdFx0dXJsLmhvc3RuYW1lLmVuZHNXaXRoKCcubmV3c292ZXJhdWRpby5jb20nKVxuXHRcdFx0KTtcblx0XHR9IGNhdGNoIChfZSkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gYWN0aW9uXG5cdCAqIEBwYXJhbSB7b2JqZWN0fSBwYXlsb2FkXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBzdXJmYWNlICByZXNvbHZlZCBzdXJmYWNlIGZvciB0aGlzIHBsYXllclxuXHQgKiBAcmV0dXJucyB7b2JqZWN0fVxuXHQgKi9cblx0YnVpbGRQcm9wZXJ0aWVzKGFjdGlvbiwgcGF5bG9hZCwgc3VyZmFjZSkge1xuXHRcdGNvbnN0IGN1cnJlbnRUaW1lID1cblx0XHRcdHR5cGVvZiBwYXlsb2FkLmN1cnJlbnRUaW1lID09PSAnbnVtYmVyJ1xuXHRcdFx0XHQ/IHBheWxvYWQuY3VycmVudFRpbWVcblx0XHRcdFx0OiBudWxsO1xuXHRcdGNvbnN0IGR1cmF0aW9uID1cblx0XHRcdHR5cGVvZiBwYXlsb2FkLmR1cmF0aW9uID09PSAnbnVtYmVyJyA/IHBheWxvYWQuZHVyYXRpb24gOiBudWxsO1xuXHRcdGNvbnN0IHBlcmNlbnQgPVxuXHRcdFx0Y3VycmVudFRpbWUgIT0gbnVsbCAmJiBkdXJhdGlvbiAmJiBkdXJhdGlvbiA+IDBcblx0XHRcdFx0PyBjdXJyZW50VGltZSAvIGR1cmF0aW9uXG5cdFx0XHRcdDogbnVsbDtcblxuXHRcdGNvbnN0IG1lZGlhSWQgPSB0aGlzLmdldE1lZGlhSWQoKTtcblx0XHRjb25zdCBpZnJhbWUgPSB0aGlzLmdldElmcmFtZSgpO1xuXHRcdGNvbnN0IG1ldGEgPSByZXNvbHZlTWV0YUZyb21Eb20oaWZyYW1lLCB7XG5cdFx0XHRzdXJmYWNlLFxuXHRcdFx0cHJvdmlkZXI6ICdub2EnLFxuXHRcdFx0cGxheWVyOiByZXNvbHZlUGxheWVyVHlwZShpZnJhbWUpIHx8ICdub2EnLFxuXHRcdFx0bWVkaWFfaWQ6IG1lZGlhSWQsXG5cdFx0fSk7XG5cblx0XHRyZXR1cm4gY3JlYXRlTWVkaWFFdmVudCh7XG5cdFx0XHRhY3Rpb24sXG5cdFx0XHRzdXJmYWNlOiBtZXRhLnN1cmZhY2UsXG5cdFx0XHRwcm92aWRlcjogJ25vYScsXG5cdFx0XHRwbGF5ZXI6IG1ldGEucGxheWVyIHx8ICdub2EnLFxuXHRcdFx0bWVkaWFfaWQ6IG1lZGlhSWQsXG5cdFx0XHRtZWRpYV90aXRsZTogbWV0YS5tZWRpYV90aXRsZSxcblx0XHRcdGN1cnJlbnRfdGltZTogY3VycmVudFRpbWUsXG5cdFx0XHRkdXJhdGlvbixcblx0XHRcdHBlcmNlbnQsXG5cdFx0XHRwcm9ncmVzczogYWN0aW9uID09PSAnbWlsZXN0b25lJyA/IHBheWxvYWQucHJvZ3Jlc3MgOiBudWxsLFxuXHRcdFx0cGxheV9pbnRlbnQ6IHBsYXlJbnRlbnRGcm9tTWV0YShtZXRhKSxcblx0XHRcdC8vIE5PQSBwb3N0TWVzc2FnZSBkb2Vzbid0IGV4cG9zZSBtdXRlIHN0YXRlLlxuXHRcdFx0bXV0ZWQ6IG51bGwsXG5cdFx0XHRpc19saXZlX3N0cmVhbTogZmFsc2UsXG5cdFx0XHRvcmllbnRhdGlvbjogbWV0YS5vcmllbnRhdGlvbixcblx0XHRcdGVtYmVkX2NvbnRleHQ6IG1ldGEuZW1iZWRfY29udGV4dCxcblx0XHR9KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBXUCBwb3N0IElEIGZvciBtZWRpYV9pZCAoam9pbnMgdG8gcGFnZSgpIC8gcnVkZGVyRGF0YS5wb3N0SWQpLlxuXHQgKlxuXHQgKiBAcmV0dXJucyB7c3RyaW5nfG51bGx9XG5cdCAqL1xuXHRnZXRNZWRpYUlkKCkge1xuXHRcdGlmICh0aGlzLnBvc3RJZCkgcmV0dXJuIHRoaXMucG9zdElkO1xuXG5cdFx0Y29uc3QgaWQgPVxuXHRcdFx0d2luZG93LmZwTm9hRGF0YT8ucG9zdF9pZCA/P1xuXHRcdFx0d2luZG93LnJ1ZGRlckRhdGE/LnBvc3RJZCA/P1xuXHRcdFx0d2luZG93LkZQPy5tb2JpbGVBcHA/LnBvc3RJZCA/P1xuXHRcdFx0bnVsbDtcblxuXHRcdGlmIChpZCAhPSBudWxsKSB7XG5cdFx0XHR0aGlzLnBvc3RJZCA9IFN0cmluZyhpZCk7XG5cdFx0XHRyZXR1cm4gdGhpcy5wb3N0SWQ7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgUnVkZGVyTm9hO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../assets/src/scripts/rudder/rudderNoa.js\n\n}")},"../assets/src/scripts/rudder/rudderTools.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){"use strict";eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/classCallCheck */ \"./node_modules/@babel/runtime/helpers/esm/classCallCheck.js\");\n/* harmony import */ var _babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @babel/runtime/helpers/createClass */ \"./node_modules/@babel/runtime/helpers/esm/createClass.js\");\n/* harmony import */ var _rudderstack_analytics_js_bundled__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @rudderstack/analytics-js/bundled */ \"./node_modules/@rudderstack/analytics-js/dist/npm/modern/bundled/esm/index.mjs\");
1\n/* harmony import */ var _utils_cookies__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils/cookies */ \"../assets/src/scripts/utils/cookies.js\");\n/* harmony import */ var _utils_cookies__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_utils_cookies__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _utils_jwt__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utils/jwt */ \"../assets/src/scripts/utils/jwt.js\");\n/* harmony import */ var _utils_jwt__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_utils_jwt__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _bot_patterns_generated__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./bot-patterns.generated */ \"../assets/src/scripts/rudder/bot-patterns.generated.js\");\n\n\n\n\n\n\n\n/**\n * Hand-curated UA substring blocklist â fast first-pass filter for the\n * majority of noise (Applebot, HeadlessChrome, cXensebot, YandexBot, etc.).\n * Data-driven from analytics_v1.pages where these produced meaningful\n * volume. Case-insensitive substring match â if any of these appears\n * anywhere in the UA we bail.\n *\n * The community-maintained regex list in `bot-patterns.generated.js`\n * (refreshed by `build/scripts/fetch-bot-patterns.js` on production\n * builds) is checked as a fallback for anything the substring list misses.\n * See isBotUserAgent() below.\n *\n * Deliberately does NOT match social in-app browsers (\"Twitter for iPhone\",\n * \"LinkedInApp\", \"Line/\", etc.) â those are real humans reading links from\n * social apps and belong in the analytics.\n */\nvar BOT_UA_PATTERNS = [\n// Generic identifiers\n'bot', 'crawl', 'spider', 'slurp', 'scrape', 'feed',\n// Named crawlers seen in our data\n'applebot', 'cxensebot', 'yandexbot', 'ahrefsbot', 'amazonadbot', 'abevalbot', 'adsbot-google', 'bingbot', 'bytespider', 'amazon-quick',\n// Amazon Alexa content scraper\n'meta-webindexer', 'webindexer', 'detect-cube', 'contentanalyzer', 'shap-user', 'dataminr', 'semrush', 'mj12', 'screaming', 'dotbot', 'serpstat',\n// Google service crawlers (don't self-identify with 'bot' or 'crawl')\n'mediapartners',\n// AdSense crawler\n'google-read-aloud',\n// screen-reader crawler\n'google-safety',\n// safety scanner\n'playstore-google',\n// Play Store link scraper\n\n// Accessibility / SEO scanners run against our pages\n'levelaccess',\n// AI crawlers (add preemptively â most already blocked upstream in\n// robots.txt, but defense-in-depth). NOTE: this does NOT match\n// `Claude/x.x.x Electron` (the Claude Desktop app, treated as a real\n// human in-app browser like Twitter for iPhone).\n'chatgpt', 'gptbot', 'openai', 'claude-code', 'perplexity', 'anthropic-ai',\n// Social-media link-preview crawlers that don't contain 'bot' in their\
1n// UA. Ones like Twitterbot / LinkedInBot / Slackbot / Discordbot /\n// Facebot / Telegrambot / Redditbot are already caught by the generic\n// 'bot' pattern above â this line is only for the odd ones out.\n// Deliberately does NOT include social in-app browser UAs (Twitter for\n// iPhone, LinkedInApp, Pinterest/iOS, Line, WhatsApp real users) â\n// those are humans reading articles from social apps.\n'facebookexternalhit',\n// Headless / automation runtimes\n'headlesschrome', 'puppeteer', 'playwright', 'selenium', 'phantom', 'prerender', 'lightpanda',\n// Uptime / perf monitors\n'pingdom', 'gtmetrix', 'lighthouse', 'uptimerobot', 'statuscake',\n// HTTP client libraries (mostly server-side scripts)\n'wget', 'curl', 'python-requests', 'axios', 'go-http-client', 'okhttp', 'java/', 'ruby/', 'php/'];\n\n// Compile the community regex list once at module load. ~1,500 patterns â\n// per-page test cost is sub-ms even on mobile, and this only runs once at\n// init() to decide whether to bail before initializing the SDK.\n//\n// Belt-and-suspenders: build-time validator (build/scripts/fetch-bot-patterns.js)\n// already drops patterns that fail Node's RegExp compiler, but browsers can\n// have subtly different regex semantics. Silently skip anything that fails\n// here so a single bad pattern can't nuke tracking init for every user.\nvar CRAWLER_REGEXES = _bot_patterns_generated__WEBPACK_IMPORTED_MODULE_5__.CRAWLER_PATTERNS.map(function (p) {\n try {\n return new RegExp(p, 'i');\n } catch (_e) {\n return null;\n }\n}).filter(Boolean);\nfunction isBotUserAgent(ua) {\n if (!ua) return false;\n var lower = ua.toLowerCase();\n // Fast substring pass first â short-circuits on the majority of hits.\n if (BOT_UA_PATTERNS.some(function (p) {\n return lower.includes(p);\n })) return true;\n // Fallback to the community-maintained regex list for anything the\n // hand-curated substrings miss.\n return CRAWLER_REGEXES.some(function (r) {\n return r.test(ua);\n });\n}\n\n/**\n * Strips empty values out of an identify() trait object.\n *\n * Piano's loginSuccess payload does not always carry every field, and the\n * SDK merges incoming traits into its persisted copy rather than replacing\n * it â so letting an `undefined` through would overwrite a good stored\n * trait with nothing.\n *\n * @param \t{Object} traits\n *\n * @return \t{Object}\n */\nfunction cleanTraits(traits) {\n var cleaned = {};\n Object.keys(traits || {}).forEach(function (key) {\n var value = traits[key];\n if (value !== undefined && value !== null && value !== '') {\n cleaned[key] = value;\n }\n });\n return cleaned;\n}\n\n/**\n * True when every trait we are about to send is already stored in the SDK,\n * i.e. the identify() would tell the warehouse nothing new.\n *\n * @param \t{Object} stored Traits currently held by the SDK.\n * @param \t{Object} next Traits we are about to send.\n *\n * @return \t{boolean}\n */\nfunction traitsAlreadyStored(stored, next) {\n var current = stored || {};\n return Object.keys(next).every(function (key) {\n return current[key] === next[key];\n });\n}\n\n/**\n * RudderTools\n */\nvar RudderTools = /*#__PURE__*/function () {\n /**\n * @description. Sets class constants.\n *\n * @return \t{void}\n */\n function RudderTools() {\n (0,_babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(this, RudderTools);\n this.endpoint = window.rudderConfig.endpoint || null;\n this.writeKey = window.rudderConfig.writeKey || null;\n this.channel = window.rudderConfig.channel || null;\n }\n\n /**\n * @description. Initializes the application, sets up listeners and identifies\n * existing logins. Bails early for known-bot user-agents so no SDK loads\n * and no events fire from that request â cheaper than downstream filtering\n * because the SDK bundle isn't even instantiated.\n *\n * @return \t{void}\n */\n return (0,_babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(RudderTools, [{\n key: \"init\",\n value: function init(
1) {\n var self = this;\n if (isBotUserAgent(navigator.userAgent)) {\n return;\n }\n if (self.endpoint && self.writeKey) {\n self.lib = new _rudderstack_analytics_js_bundled__WEBPACK_IMPORTED_MODULE_2__.RudderAnalytics();\n self.lib.load(self.writeKey, self.endpoint);\n self.addListeners();\n self.lib.ready(function () {\n // Seeded inside ready(): before this fires the SDK has not\n // restored userId/userTraits from storage yet, so the dedupe\n // in the rudder:identify listener would compare against an\n // empty identity and re-identify on every single page load.\n // identify() still runs before trackPage() here, so the page\n // event carries context.traits.\n self.seedIdentityFromPianoToken();\n self.trackPage();\n });\n }\n }\n\n /**\n * @description. Seeds the SDK's identity from Piano's `__utp` cookie\n * before the first page() fires.\n *\n * `__utp` is the Piano auth token and carries `sub`, `email`,\n * `given_name`, `family_name` and `exp`. Reading it here â rather than\n * waiting for setPianoUserData() â buys two things:\n *\n * 1. It is synchronous, so the page() fired from init() already carries\n * context.traits. Piano resolves long after that, which is why the\n * first page view of a browser used to go out with a user_id and an\n * empty context.traits.\n * 2. It does not need tinypass.js, so identity still resolves for\n * readers whose ad/DNS blocker eats Piano. Nothing here gates\n * trackPage(), so a blocked reader still emits their page event.\n *\n * The signature is NOT verified: that needs Piano's shared secret, which\n * must never ship to the browser. Acceptable because this only labels an\n * analytics event â a reader forging their own cookie corrupts one row,\n * their own. Server-side paths that DO make decisions on this token\n * verify it properly via helpers/jwk.php.\n *\n * The raw token is a live Bearer credential (see myfp.js) â only decoded\n * claims leave this function, never the token itself.\n *\n * @return \t{void}\n */\n }, {\n key: \"seedIdentityFromPianoToken\",\n value: function seedIdentityFromPianoToken() {\n var token = _utils_cookies__WEBPACK_IMPORTED_MODULE_3___default().get('__utp');\n var payload = null;\n if (token) {\n try {\n payload = _utils_jwt__WEBPACK_IMPORTED_MODULE_4___default().parse(token);\n } catch (e) {\n // Malformed or truncated cookie â treat as signed out rather\n // than letting a parse error take down tracking init.\n payload = null;\n }\n }\n var signedIn = payload && payload.sub && payload.exp && payload.exp * 1000 > Date.now();\n\n // Absent or expired here is NOT a signed-out signal. Piano re-mints\n // `__utp` a few seconds after our SDK is ready, so resetting on it\n // demoted ~7% of signed-in page views to anonymous (median 4s\n // before Piano re-identified them). Piano is the only authority on\n // \"not signed in\": user-piano.js dispatches rudder:reset from its\n // not-logged-in branches once Piano has evaluated the session.\n if (!signedIn) {\n return;\n }\n document.dispatchEvent(new CustomEvent('rudder:identify', {\n detail: {\n user_id: payload.sub,\n traits: {\n first_name: payload.given_name,\n last_name: payload.family_name,\n email: payload.email\n }\n }\n }));\n }\n\n /**\n * @description. Tracks page views for all users. Skips next page if a\n * session item was set used to avoid duplicate (login/logout) page tracks.\n *\n * @return \t{bool}\n */\n }, {\n key: \"trackPage\",\n value: function trackPage() {\n var self = this;\n try {\n if (sessionStorage.getItem('rudder:skipNextTrackPage')) {\n sessionStorage.removeItem('rudder:skipNextTrackPage');\n return;\n }\n } catch (e) {\n // sessionStorage unavailable (private mode, blocker, etc.) â fall through and track\n }\n if (window.rudderData) {\n self.lib.page(null, null, window.rudderData, self.commonApiOptions());\n }\n }
1\n\n /**\n * @description. Returns an SDK apiOptions object carrying the current\n * request's cross-cutting overrides: `channel` (routed to context.channel\n * â the top-level `channel` field is SDK-reserved for library identity)\n * and `context.groupId/groupTraits` (the SDK only stamps groupId on\n * `group` events by default, so this is how we make it visible on the\n * wider event stream).\n *\n * `channel` always falls back to 'web' when this.channel is unset â\n * defends against the post-deploy cache-invalidation window where a\n * fresh rudderTools bundle can load against a stale inline\n * `window.rudderConfig` (from HTML cache) that predates the `channel`\n * key. wp_localize_script has no independent versioning; the `?ver=`\n * querystring only busts the JS URL, not the inline localized data. In\n * an in-app-browser view the same stale-cache window can misclassify a\n * few events as 'web' instead of 'mobile-browser' â accepted trade\n * because the majority path is web and losing the channel signal\n * entirely is worse than the transient misclassification.\n *\n * @return {Object}\n */\n }, {\n key: \"commonApiOptions\",\n value: function commonApiOptions() {\n var self = this;\n var opts = {\n channel: self.channel || 'web'\n };\n var groupId = self.lib.getGroupId && self.lib.getGroupId();\n if (groupId) {\n var groupTraits = self.lib.getGroupTraits && self.lib.getGroupTraits() || {};\n opts.context = {\n groupId: groupId,\n groupTraits: groupTraits\n };\n }\n return opts;\n }\n\n /**\n * @description. Adds event listeners for various events to track.\n *\n * @return \t{void}\n */\n }, {\n key: \"addListeners\",\n value: function addListeners() {\n var self = this;\n document.addEventListener('rudder:track', function (e) {\n var apiOptions = Object.assign({}, e.detail.apiOptions, self.commonApiOptions());\n self.lib.track(e.detail.event, e.detail.properties || {}, apiOptions);\n });\n document.addEventListener('rudder:page', function (e) {\n var apiOptions = Object.assign({}, e.detail.apiOptions, self.commonApiOptions());\n self.lib.page(e.detail.category || null, e.detail.name || null, e.detail.properties || {}, apiOptions);\n });\n document.addEventListener('rudder:identify', function (e) {\n var current = self.lib.getUserId ? self.lib.getUserId() || null : null;\n var next = e.detail.user_id || null;\n var traits = cleanTraits(e.detail.traits);\n var stored = self.lib.getUserTraits ? self.lib.getUserTraits() : {};\n\n // Dedupe on identity AND traits. Keying on user_id alone made\n // every later identify for the same user a no-op, so a browser\n // that lost its `rl_trait` cookie (Safari caps script-written\n // cookies at 7 days) kept emitting events carrying a user_id\n // with an empty context.traits, and no amount of re-logging-in\n // could repair it. Comparing traits too lets the identify\n // dispatched on every page load by setPianoUserData() restore\n // them once, then stay silent.\n if (current === next && traitsAlreadyStored(stored, traits)) {\n return;\n }\n var apiOptions = Object.assign({}, e.detail.apiOptions, self.commonApiOptions());\n self.lib.identify(next, traits, apiOptions);\n });\n document.addEventListener('rudder:group', function (e) {\n var current = self.lib.getGroupId ? self.lib.getGroupId() || null : null;\n var next = e.detail.group_id || null;\n if (current === next) return;\n if (next === null) {\n self.lib.reset({\n entries: {\n groupId: true,\n groupTraits: true\n }\n });\n return;\n }\n var apiOptions = Object.assign({}, e.detail.apiOptions, self.commonApiOptions());\n self.lib.group(next, e.detail.traits || {}, apiOptions);\n });\n document.addEventListener('rudder:reset', function (e) {\n var options = e.detail.options || {};\n\n // user-piano.js dispatches an identity-scoped reset from its\n // not-logged-in branches, i.e. on every anonymous page load. Skip\n // it when nothing is persisted so it is a true no-op there. A\n // full reset (logout passes `true`) is never short
1-circuited.\n if (options.entries && !(self.lib.getUserId && self.lib.getUserId())) {\n return;\n }\n self.lib.reset(options);\n });\n }\n }]);\n}();\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (RudderTools);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJUb29scy5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBT0E7QUFDQTtBQVNBO0FBQ0E7QUFZQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQUE7O0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQVFBO0FBQ0E7QUFNQTtBQUNBOztBQVdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFGQTtBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQVBBO0FBQUE7QUFBQTtBQVNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBMUJBO0FBQUE7QUFBQTtBQTRCQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFMQTtBQUFBO0FBQUE7QUFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFFQTtBQUNBO0FBTUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFwQkE7QUFBQTtBQUFBO0FBc0JBO0FBQ0E7QUFBQTtBQUFBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUpBO0FBQUE7QUFBQTtBQU1BO0FBRUE7QUFDQTtBQUtBO0FBS0E7QUFFQTtBQUNBO0FBS0E7QUFNQTtBQUVBO0FBQ0E7QUFHQTtBQUNBO0FBQ0E7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBS0E7QUFDQTtBQUVBO0FBQ0E7QUFHQTtBQUVBO0FBRUE7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFLQTtBQUNBO0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBSUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFHQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJUb29scy5qcz9mNWNlIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJ1ZGRlckFuYWx5dGljcyB9IGZyb20gJ0BydWRkZXJzdGFjay9hbmFseXRpY3MtanMvYnVuZGxlZCc7XG5pbXBvcnQgY29va2llcyBmcm9tICcuLi91dGlscy9jb29raWVzJztcbmltcG9ydCBqd3QgZnJvbSAnLi4vdXRpbHMvand0JztcbmltcG9ydCB7IENSQVdMRVJfUEFUVEVSTlMgfSBmcm9tICcuL2JvdC1wYXR0ZXJucy5nZW5lcmF0ZWQnO1xuXG4vKipcbiAqIEhhbmQtY3VyYXRlZCBVQSBzdWJzdHJpbmcgYmxvY2tsaXN0IOKAlCBmYXN0IGZpcnN0LXBhc3MgZmlsdGVyIGZvciB0aGVcbiAqIG1ham9yaXR5IG9mIG5vaXNlIChBcHBsZWJvdCwgSGVhZGxlc3NDaHJvbWUsIGNYZW5zZWJvdCwgWWFuZGV4Qm90LCBldGMuKS5cbiAqIERhdGEtZHJpdmVuIGZyb20gYW5hbHl0aWNzX3YxLnBhZ2VzIHdoZXJlIHRoZXNlIHByb2R1Y2VkIG1lYW5pbmdmdWxcbiAqIHZvbHVtZS4gQ2FzZS1pbnNlbnNpdGl2ZSBzdWJzdHJpbmcgbWF0Y2gg4oCUIGlmIGFueSBvZiB0aGVzZSBhcHBlYXJzXG4gKiBhbnl3aGVyZSBpbiB0aGUgVUEgd2UgYmFpbC5cbiAqXG4gKiBUaGUgY29tbXVuaXR5LW1haW50YWluZWQgcmVnZXggbGlzdCBpbiBgYm90LXBhdHRlcm5zLmdlbmVyYXRlZC5qc2BcbiAqIChyZWZyZXNoZWQgYnkgYGJ1aWxkL3NjcmlwdHMvZmV0Y2gtYm90LXBhdHRlcm5zLmpzYCBvbiBwcm9kdWN0aW9uXG4gKiBidWlsZHMpIGlzIGNoZWNrZWQgYXMgYSBmYWxsYmFjayBmb3IgYW55dGhpbmcgdGhlIHN1YnN0cmluZyBsaXN0IG1pc3Nlcy5cbiAqIFNlZSBpc0JvdFVzZXJBZ2VudCgpIGJlbG93LlxuICpcbiAqIERlbGliZXJhdGVseSBkb2VzIE5PVCBtYXRjaCBzb2NpYWwgaW4tYXBwIGJyb3dzZXJzIChcIlR3aXR0ZXIgZm9yIGlQaG9uZVwiLFxuICogXCJMaW5rZWRJbkFwcFwiLCBcIkxpbmUvXCIsIGV0Yy4pIOKAlCB0aG9zZSBhcmUgcmVhbCBodW1hbnMgcmVhZGluZyBsaW5rcyBmcm9tXG4gKiBzb2NpYWwgYXBwcyBhbmQgYmVsb25nIGluIHRoZSBhbmFseXRpY3MuXG4gKi9cbmNvbnN0IEJPVF9VQV9QQVRURVJOUyA9IFtcblx0Ly8gR2VuZXJpYyBpZGVudGlmaWVyc1xuXHQnYm90Jyxcblx0J2NyYXdsJyxcblx0J3NwaWRlcicsXG5cdCdzbHVycCcsXG5cdCdzY3JhcGUnLFxuXHQnZmVlZCcsXG5cblx0Ly8gTmFtZWQgY3Jhd2xlcnMgc2VlbiBpbiBvdXIgZGF0YVxuXHQnYXBwbGVib3QnLFxuXHQnY3hlbnNlYm90Jyxcblx0J3lhbmRleGJvdCcsXG5cdCdhaHJlZnNib3QnLFxuXHQnYW1hem9uYWRib3QnLFxuXHQnYWJldmFsYm90Jyxcblx0J2Fkc2JvdC1nb29nbGUnLFxuXHQnYmluZ2JvdCcsXG5cdCdieXRlc3BpZGVyJyxcblx0J2FtYXpvbi1xdWljaycsIC8vIEFtYXpvbiBBbGV4YSBjb250ZW50IHNjcmFwZXJcblx0J21ldGEtd2ViaW5kZXhlcicsXG5cdCd3ZWJpbmRleGVyJyxcblx0J2RldGVjdC1jdWJlJyxcblx0J2NvbnRlbn
1RhbmFseXplcicsXG5cdCdzaGFwLXVzZXInLFxuXHQnZGF0YW1pbnInLFxuXHQnc2VtcnVzaCcsXG5cdCdtajEyJyxcblx0J3NjcmVhbWluZycsXG5cdCdkb3Rib3QnLFxuXHQnc2VycHN0YXQnLFxuXG5cdC8vIEdvb2dsZSBzZXJ2aWNlIGNyYXdsZXJzIChkb24ndCBzZWxmLWlkZW50aWZ5IHdpdGggJ2JvdCcgb3IgJ2NyYXdsJylcblx0J21lZGlhcGFydG5lcnMnLCAvLyBBZFNlbnNlIGNyYXdsZXJcblx0J2dvb2dsZS1yZWFkLWFsb3VkJywgLy8gc2NyZWVuLXJlYWRlciBjcmF3bGVyXG5cdCdnb29nbGUtc2FmZXR5JywgLy8gc2FmZXR5IHNjYW5uZXJcblx0J3BsYXlzdG9yZS1nb29nbGUnLCAvLyBQbGF5IFN0b3JlIGxpbmsgc2NyYXBlclxuXG5cdC8vIEFjY2Vzc2liaWxpdHkgLyBTRU8gc2Nhbm5lcnMgcnVuIGFnYWluc3Qgb3VyIHBhZ2VzXG5cdCdsZXZlbGFjY2VzcycsXG5cblx0Ly8gQUkgY3Jhd2xlcnMgKGFkZCBwcmVlbXB0aXZlbHkg4oCUIG1vc3QgYWxyZWFkeSBibG9ja2VkIHVwc3RyZWFtIGluXG5cdC8vIHJvYm90cy50eHQsIGJ1dCBkZWZlbnNlLWluLWRlcHRoKS4gTk9URTogdGhpcyBkb2VzIE5PVCBtYXRjaFxuXHQvLyBgQ2xhdWRlL3gueC54IEVsZWN0cm9uYCAodGhlIENsYXVkZSBEZXNrdG9wIGFwcCwgdHJlYXRlZCBhcyBhIHJlYWxcblx0Ly8gaHVtYW4gaW4tYXBwIGJyb3dzZXIgbGlrZSBUd2l0dGVyIGZvciBpUGhvbmUpLlxuXHQnY2hhdGdwdCcsXG5cdCdncHRib3QnLFxuXHQnb3BlbmFpJyxcblx0J2NsYXVkZS1jb2RlJyxcblx0J3BlcnBsZXhpdHknLFxuXHQnYW50aHJvcGljLWFpJyxcblxuXHQvLyBTb2NpYWwtbWVkaWEgbGluay1wcmV2aWV3IGNyYXdsZXJzIHRoYXQgZG9uJ3QgY29udGFpbiAnYm90JyBpbiB0aG
1VpclxuXHQvLyBVQS4gT25lcyBsaWtlIFR3aXR0ZXJib3QgLyBMaW5rZWRJbkJvdCAvIFNsYWNrYm90IC8gRGlzY29yZGJvdCAvXG5cdC8vIEZhY2Vib3QgLyBUZWxlZ3JhbWJvdCAvIFJlZGRpdGJvdCBhcmUgYWxyZWFkeSBjYXVnaHQgYnkgdGhlIGdlbmVyaWNcblx0Ly8gJ2JvdCcgcGF0dGVybiBhYm92ZSDigJQgdGhpcyBsaW5lIGlzIG9ubHkgZm9yIHRoZSBvZGQgb25lcyBvdXQuXG5cdC8vIERlbGliZXJhdGVseSBkb2VzIE5PVCBpbmNsdWRlIHNvY2lhbCBpbi1hcHAgYnJvd3NlciBVQXMgKFR3aXR0ZXIgZm9yXG5cdC8vIGlQaG9uZSwgTGlua2VkSW5BcHAsIFBpbnRlcmVzdC9pT1MsIExpbmUsIFdoYXRzQXBwIHJlYWwgdXNlcnMpIOKAlFxuXHQvLyB0aG9zZSBhcmUgaHVtYW5zIHJlYWRpbmcgYXJ0aWNsZXMgZnJvbSBzb2NpYWwgYXBwcy5cblx0J2ZhY2Vib29rZXh0ZXJuYWxoaXQnLFxuXG5cdC8vIEhlYWRsZXNzIC8gYXV0b21hdGlvbiBydW50aW1lc1xuXHQnaGVhZGxlc3NjaHJvbWUnLFxuXHQncHVwcGV0ZWVyJyxcblx0J3BsYXl3cmlnaHQnLFxuXHQnc2VsZW5pdW0nLFxuXHQncGhhbnRvbScsXG5cdCdwcmVyZW5kZXInLFxuXHQnbGlnaHRwYW5kYScsXG5cblx0Ly8gVXB0aW1lIC8gcGVyZiBtb25pdG9yc1xuXHQncGluZ2RvbScsXG5cdCdndG1ldHJpeCcsXG5cdCdsaWdodGhvdXNlJyxcblx0J3VwdGltZXJvYm90Jyxcblx0J3N0YXR1c2Nha2UnLFxuXG5cdC8vIEhUVFAgY2xpZW50IGxpYnJhcmllcyAobW9zdGx5IHNlcnZlci1zaWRlIHNjcmlwdHMpXG5cdCd3Z2V0Jyxcblx0J2N1cmwnLFxuXHQncHl0aG9uLXJlcXVlc3RzJyxcblx0J2F4aW9zJyxcblx0J2dvLWh0dHAtY2xpZW50Jyxcblx0J29raHR0cCcsXG5cdCdqYXZhLycsXG5cdCdydWJ5LycsXG5cdCdwaHAvJyxcbl07XG5cbi8vIENvbXBpbGUgdGhlIGNvbW11bml0eSByZWdleCBsaXN0IG9uY2UgYXQgbW9kdWxlIGxvYWQuIH4xLDUwMCBwYXR0ZXJucyDigJRcbi8vIHBlci1wYWdlIHRlc3QgY29zdCBpcyBzdWItbXMgZXZlbiBvbiBtb2JpbGUsIGFuZCB0aGlzIG9ubHkgcnVucyBvbmNlIGF0XG4vLyBpbml0KCkgdG8gZGVjaWRlIHdoZXRoZXIgdG8gYmFpbCBiZWZvcmUgaW5pdGlhbGl6aW5nIHRoZSBTREsuXG4vL1xuLy8gQmVsdC1hbmQtc3VzcGVuZGVyczogYnVpbGQtdGltZSB2YWxpZGF0b3IgKGJ1aWxkL3NjcmlwdHMvZmV0Y2gtYm90LXBhdHRlcm5zLmpzKVxuLy8gYWxyZWFkeSBkcm9wcyBwYXR0ZXJucyB0aGF0IGZhaWwgTm9kZSdzIFJlZ0V4cCBjb21waWxlciwgYnV0IGJyb3dzZXJzIGNhblxuLy8gaGF2ZSBzdWJ0bHkgZGlmZmVyZW50IHJlZ2V4IHNlbWFudGljcy4gU2lsZW50bHkgc2tpcCBhbnl0aGluZyB0aGF0IGZhaWxzXG4vLyBoZXJlIHNvIGEgc2luZ2xlIGJhZCBwYXR0ZXJuIGNhbid0IG51a2UgdHJhY2tpbmcgaW5pdCBmb3IgZXZlcnkgdXNlci5cbmNvbnN0IENSQVdMRVJfUkVHRVhFUyA9IENSQVdMRVJfUEFUVEVSTlMubWFwKChwKSA9PiB7XG5cdHRyeSB7XG5cdFx0cmV0dXJuIG5ldyBSZWdFeHAocCwgJ2knKTtcblx0fSBjYXRjaCAoX2UpIHtcblx0XHRyZXR1cm4gbnVsbDtcblx0fVxufSkuZmlsdGVyKEJvb2xlYW4pO1xuXG5mdW5jdGlvbiBpc0JvdFVzZXJBZ2VudCh1YSkge1xuXHRpZiAoIXVhKSByZXR1cm4gZmFsc2U7XG5cdGNvbnN0IGxvd2VyID0gdWEudG9Mb3dlckNhc2UoKTtcblx0Ly8gRmFzdCBzdWJzdHJpbmcgcGFzcyBmaXJzdCDigJQgc2hvcnQtY2lyY3VpdHMgb24gdGhlIG1ham9yaXR5IG9mIGhpdHMuXG5cdGlmIChCT1RfVUFfUEFUVEVSTlMuc29tZSgocCkgPT4gbG93ZXIuaW5jbHVkZXMocCkpKSByZXR1cm4gdHJ1ZTtcblx0Ly8gRmFsbGJhY2sgdG8gdGhlIGNvbW11bml0eS1tYWludGFpbmVkIHJlZ2V4IGxpc3QgZm9yIGFueXRoaW5nIHRoZVxuXHQvLyBoYW5kLWN1cmF0ZWQgc3Vic3RyaW5ncyBtaXNzLlxuXHRyZXR1cm4gQ1JBV0xFUl9SRUdFWEVTLnNvbWUoKHIpID0+IHIudGVzdCh1YSkpO1xufVxuXG4vKipcbiAqIFN0cmlwcyBlbXB0eSB2YWx1ZXMgb3V0IG9mIGFuIGlkZW50aWZ5KCkgdHJhaXQgb2JqZWN0LlxuICpcbiAqIFBpYW5vJ3MgbG9naW5TdWNjZXNzIHBheWxvYWQgZG9lcyBub3QgYWx3YXlzIGNhcnJ5IGV2ZXJ5IGZpZWxkLCBhbmQgdGhlXG4gKiBTREsgbWVyZ2VzIGluY29taW5nIHRyYWl0cyBpbnRvIGl0cyBwZXJzaXN0ZWQgY29weSByYXRoZXIgdGhhbiByZXBsYWNpbmdcbiAqIGl0IOKAlCBzbyBsZXR0aW5nIGFuIGB1bmRlZmluZWRgIHRocm91Z2ggd291bGQgb3ZlcndyaXRlIGEgZ29vZCBzdG9yZWRcbiAqIHRyYWl0IHdpdGggbm90aGluZy5cbiAqXG4gKiBAcGFyYW0gXHR7T2JqZWN0fSB0cmFpdHNcbiAqXG4gKiBAcmV0dXJuIFx0e09iamVjdH1cbiAqL1xuZnVuY3Rpb24gY2xlYW5UcmFpdHModHJhaXRzKSB7XG5cdGNvbnN0IGNsZWFuZWQgPSB7fTtcblx0T2JqZWN0LmtleXModHJhaXRzIHx8IHt9KS5mb3JFYWNoKChrZXkpID0+IHtcblx0XHRjb25zdCB2YWx1ZSA9IHRyYWl0c1trZXldO1xuXHRcdGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsICYmIHZhbHVlICE9PSAnJykge1xuXHRcdFx0Y2xlYW5lZFtrZXldID0gdmFsdWU7XG5cdFx0fVxuXHR9KTtcblx0cmV0dXJuIGNsZWFuZWQ7XG59XG5cbi8qKlxuICogVHJ1ZSB3aGVuIGV2ZXJ5IHRyYWl0IHdlIGFyZSBhYm91dCB0byBzZW5kIGlzIGFscmVhZHkgc3RvcmVkIGluIHRoZSBTREssXG4gKiBpLmUuIHRoZSBpZGVudGlmeSgpIHdvdWxkIHRlbGwgdGhlIHdhcmVob3VzZSBub3RoaW5nIG5ldy5cbiAqXG4gKiBAcGFyYW0gXHR7T2JqZWN0fSBzdG9yZWQgVHJhaXRzIGN1cnJlbnRseSBoZWxkIGJ5IHRoZSBTREsuXG4gKiBAcGFyYW0gXHR7T2JqZWN0fSBuZXh0ICAgVHJhaXRzIHdlIGFyZSBhYm91dCB0byBzZW5kLlxuICpcbiAqIEByZXR1cm4gXHR7Ym9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gdHJhaXRzQWxyZWFkeVN0b3JlZChzdG9yZWQsIG5leHQpIHtcblx0Y29uc3QgY3VycmVudCA9IHN0b3JlZCB8fCB7fTtcblx0cmV0dXJuIE9iamVjdC5rZXlzKG5leHQpLmV2ZXJ5KChrZXkpID0+IGN1cnJlbnRba2V5XSA9PT0gbmV4dFtrZXldKTtcbn1cblxuLyoqXG4gKiBSdWRkZXJUb29sc1xuICovXG5jbGFzcyBSdWRkZXJUb29scyB7XG5cdC8qKlxuXHQgKiBAZGVzY3JpcHRpb24uIFNldHMgY2xhc3MgY29uc3RhbnRzLlxuXHQgKlxuXHQgKiBAcmV0dXJuIFx0e3ZvaWR9XG5cdCAqL1xuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHR0aGlzLmVuZHBvaW50ID0gd2luZG93LnJ1ZGRlckNvbmZpZy5lbmRwb2ludCB8fCBudWxsO1xuXHRcdHRoaXMud3JpdGVLZXkgPSB3aW5kb3cucnVkZGVyQ29uZmlnLndyaXRlS2V5
1IHx8IG51bGw7XG5cdFx0dGhpcy5jaGFubmVsID0gd2luZG93LnJ1ZGRlckNvbmZpZy5jaGFubmVsIHx8IG51bGw7XG5cdH1cblxuXHQvKipcblx0ICogQGRlc2NyaXB0aW9uLiBJbml0aWFsaXplcyB0aGUgYXBwbGljYXRpb24sIHNldHMgdXAgbGlzdGVuZXJzIGFuZCBpZGVudGlmaWVzXG5cdCAqIGV4aXN0aW5nIGxvZ2lucy4gQmFpbHMgZWFybHkgZm9yIGtub3duLWJvdCB1c2VyLWFnZW50cyBzbyBubyBTREsgbG9hZHNcblx0ICogYW5kIG5vIGV2ZW50cyBmaXJlIGZyb20gdGhhdCByZXF1ZXN0IOKAlCBjaGVhcGVyIHRoYW4gZG93bnN0cmVhbSBmaWx0ZXJpbmdcblx0ICogYmVjYXVzZSB0aGUgU0RLIGJ1bmRsZSBpc24ndCBldmVuIGluc3RhbnRpYXRlZC5cblx0ICpcblx0ICogQHJldHVybiBcdHt2b2lkfVxuXHQgKi9cblx0aW5pdCgpIHtcblx0XHRjb25zdCBzZWxmID0gdGhpcztcblx0XHRpZiAoaXNCb3RVc2VyQWdlbnQobmF2aWdhdG9yLnVzZXJBZ2VudCkpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKHNlbGYuZW5kcG9pbnQgJiYgc2VsZi53cml0ZUtleSkge1xuXHRcdFx0c2VsZi5saWIgPSBuZXcgUnVkZGVyQW5hbHl0aWNzKCk7XG5cdFx0XHRzZWxmLmxpYi5sb2FkKHNlbGYud3JpdGVLZXksIHNlbGYuZW5kcG9pbnQpO1xuXHRcdFx0c2VsZi5hZGRMaXN0ZW5lcnMoKTtcblx0XHRcdHNlbGYubGliLnJlYWR5KCgpID0+IHtcblx0XHRcdFx0Ly8gU2VlZGVkIGluc2lkZSByZWFkeSgpOiBiZWZvcmUgdGhpcyBmaXJlcyB0aGUgU0RLIGhhcyBub3Rcblx0XHRcdFx0Ly8gcmVzdG9yZWQgdXNlcklkL3VzZXJUcmFpdHMgZnJvbSBzdG9yYWdlIHlldCwgc28gdGhlIGRlZHVwZVxuXHRcdFx0XHQvLyBpbiB0aGUgcnVkZGVyOmlkZW50aWZ5IGxpc3RlbmVyIHdvdWxkIGNvbXBhcmUgYWdhaW5zdCBhblxuXHRcdFx0XHQvLyBlbXB0eSBpZGVudGl0eSBhbmQgcmUtaWRlbnRpZnkgb24gZXZlcnkgc2luZ2xlIHBhZ2UgbG9hZC5cblx0XHRcdFx0Ly8gaWRlbnRpZnkoKSBzdGlsbCBydW5zIGJlZm9yZSB0cmFja1BhZ2UoKSBoZXJlLCBzbyB0aGUgcGFnZVxuXHRcdFx0XHQvLyBldmVudCBjYXJyaWVzIGNvbnRleHQudHJhaXRzLlxuXHRcdFx0XHRzZWxmLnNlZWRJZGVudGl0eUZyb21QaWFub1Rva2VuKCk7XG5cdFx0XHRcdHNlbGYudHJhY2tQYWdlKCk7XG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogQGRlc2NyaXB0aW9uLiBTZWVkcyB0aGUgU0RLJ3MgaWRlbnRpdHkgZnJvbSBQaWFubydzIGBfX3V0cGAgY29va2llXG5cdCAqIGJlZm9yZSB0aGUgZmlyc3QgcGFnZSgpIGZpcmVzLlxuXHQgKlxuXHQgKiBgX191dHBgIGlzIHRoZSBQaWFubyBhdXRoIHRva2VuIGFuZCBjYXJyaWVzIGBzdWJgLCBgZW1haWxgLFxuXHQgKiBgZ2l2ZW5fbmFtZWAsIGBmYW1pbHlfbmFtZWAgYW5kIGBleHBgLiBSZWFkaW5nIGl0IGhlcmUg4oCUIHJhdGhlciB0aGFuXG5cdCAqIHdhaXRpbmcgZm9yIHNldFBpYW5vVXNlckRhdGEoKSDigJQgYnV5cyB0d28gdGhpbmdzOlxuXHQgKlxuXHQgKiAgIDEuIEl0IGlzIHN5bmNocm9ub3VzLCBzbyB0aGUgcGFnZSgpIGZpcmVkIGZyb20gaW5pdCgpIGFscmVhZHkgY2Fycmllc1xuXHQgKiAgICAgIGNvbnRleHQudHJhaXRzLiBQaWFubyByZXNvbHZlcyBsb25nIGFmdGVyIHRoYXQsIHdoaWNoIGlzIHdoeSB0aGVcblx0ICogICAgICBmaXJzdCBwYWdlIHZpZXcgb2YgYSBicm93c2VyIHVzZWQgdG8gZ28gb3V0IHdpdGggYSB1c2VyX2lkIGFuZCBhblxuXHQgKiAgICAgIGVtcHR5IGNvbnRleHQudHJhaXRzLlxuXHQgKiAgIDIuIEl0IGRvZXMgbm90IG5lZWQgdGlueXBhc3MuanMsIHNvIGlkZW50aXR5IHN0aWxsIHJlc29sdmVzIGZvclxuXHQgKiAgICAgIHJlYWRlcnMgd2hvc2UgYWQvRE5TIGJsb2NrZXIgZWF0cyBQaWFuby4gTm90aGluZyBoZXJlIGdhdGVzXG5cdCAqICAgICAgdHJhY2tQYWdlKCksIHNvIGEgYmxvY2tlZCByZWFkZXIgc3RpbGwgZW1pdHMgdGhlaXIgcGFnZSBldmVudC5cblx0ICpcblx0ICogVGhlIHNpZ25hdHVyZSBpcyBOT1QgdmVyaWZpZWQ6IHRoYXQgbmVlZHMgUGlhbm8ncyBzaGFyZWQgc2VjcmV0LCB3aGljaFxuXHQgKiBtdXN0IG5ldmVyIHNoaXAgdG8gdGhlIGJyb3dzZXIuIEFjY2VwdGFibGUgYmVjYXVzZSB0aGlzIG9ubHkgbGFiZWxzIGFuXG5cdCAqIGFuYWx5dGljcyBldmVudCDigJQgYSByZWFkZXIgZm9yZ2luZyB0aGVpciBvd24gY29va2llIGNvcnJ1cHRzIG9uZSByb3csXG5cdCAqIHRoZWlyIG93bi4gU2VydmVyLXNpZGUgcGF0aHMgdGhhdCBETyBtYWtlIGRlY2lzaW9ucyBvbiB0aGlzIHRva2VuXG5cdCAqIHZlcmlmeSBpdCBwcm9wZXJseSB2aWEgaGVscGVycy9qd2sucGhwLlxuXHQgKlxuXHQgKiBUaGUgcmF3IHRva2VuIGlzIGEgbGl2ZSBCZWFyZXIgY3JlZGVudGlhbCAoc2VlIG15ZnAuanMpIOKAlCBvbmx5IGRlY29kZWRcblx0ICogY2xhaW1zIGxlYXZlIHRoaXMgZnVuY3Rpb24sIG5ldmVyIHRoZSB0b2tlbiBpdHNlbGYuXG5cdCAqXG5cdCAqIEByZXR1cm4gXHR7dm9pZH1cblx0ICovXG5cdHNlZWRJZGVudGl0eUZyb21QaWFub1Rva2VuKCkge1xuXHRcdGNvbnN0IHRva2VuID0gY29va2llcy5nZXQoJ19fdXRwJyk7XG5cdFx0bGV0IHBheWxvYWQgPSBudWxsO1xuXG5cdFx0aWYgKHRva2VuKSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRwYXlsb2FkID0gand0LnBhcnNlKHRva2VuKTtcblx0XHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdFx0Ly8gTWFsZm9ybWVkIG9yIHRydW5jYXRlZCBjb29raWUg4oCUIHRyZWF0IGFzIHNpZ25lZCBvdXQgcmF0aGVyXG5cdFx0XHRcdC8vIHRoYW4gbGV0dGluZyBhIHBhcnNlIGVycm9yIHRha2UgZG93biB0cmFja2luZyBpbml0LlxuXHRcdFx0XHRwYXlsb2FkID0gbnVsbDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRjb25zdCBzaWduZWRJbiA9XG5cdFx0XHRwYXlsb2FkICYmXG5cdFx0XHRwYXlsb2FkLnN1YiAmJlxuXHRcdFx0cGF5bG9hZC5leHAgJiZcblx0XHRcdHBheWxvYWQuZXhwICogMTAwMCA+IERhdGUubm93KCk7XG5cblx0XHQvLyBBYnNlbnQgb3IgZXhwaXJlZCBoZXJlIGlzIE5PVCBhIHNpZ25lZC1vdXQgc2lnbmFsLiBQaWFubyByZS1taW50c1xuXHRcdC8vIGBfX3V0cGAgYSBmZXcgc2Vjb25kcyBhZnRlciBvdXIgU0RLIGlzIHJlYWR5LCBzbyByZXNldHRpbmcgb24gaXRcblx0XHQvLyBkZW1vdGVkIH43JSBvZiBzaWduZWQtaW4gcGFnZSB2aWV3cyB0byBhbm9ueW1vdXMgKG1lZGlhbiA0c1xuXHRcdC8vIGJlZm9yZSBQaWFubyByZS1pZGVudGlmaWVkIHRoZW0pLiBQaWFubyBpcyB0aGUgb25seSBhdXRob3JpdHkgb25cblx0XHQvLyBcIm5vdCBzaWduZWQgaW5cIjogdXNlci1waWFuby5qcyBkaXNwYXRjaGVzIHJ1ZGRlcjpyZXNldCBmcm9tIGl0c1xuXHRcdC8vIG5vdC1sb2dnZWQtaW4gYnJhbmNoZXMgb25jZSBQaWFubyBoYXMgZXZhbHVhdGVkIHRoZSBzZXNzaW9uLlxuXHRcdGlmICghc2lnbmVkSW4pIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRkb2N1bWVudC5kaXNwYXRjaEV2ZW50KFxuXHRcdFx0bmV3IEN1c3RvbUV2ZW50KCdydWRkZXI6aWRlbnRpZnknLCB7XG5cdFx0XHRcdGRldGFpbDoge1xuXHRcdFx0XHRcdHVzZXJfaWQ6IHBheWxvYWQuc3ViLFxuXHRcdFx0XHRcdHRyYWl0czoge1xuXHRcdFx0XHRcdFx0Zmlyc3RfbmFtZTogcGF5bG9hZC5naXZlbl9uYW1lLFxuXHRcdFx0XHRcdFx0bGFzdF9uYW1lOiBwYXlsb2FkLmZhbWlseV9uYW1lLFxuXHRcdFx0XHRcdFx0ZW1haWw6IHBheWxvYWQuZW1haWwsXG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0fSxcblx0XHRcdH0pXG5cdFx0KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBAZGVzY3JpcHRpb24uIFRyYWNrcyBwYWdlIHZpZXdzIGZvciBhbGwgdXNlcnMuIFNraXBzIG5leHQgcGFn
1ZSBpZiBhXG5cdCAqIHNlc3Npb24gaXRlbSB3YXMgc2V0IHVzZWQgdG8gYXZvaWQgZHVwbGljYXRlIChsb2dpbi9sb2dvdXQpIHBhZ2UgdHJhY2tzLlxuXHQgKlxuXHQgKiBAcmV0dXJuIFx0e2Jvb2x9XG5cdCAqL1xuXHR0cmFja1BhZ2UoKSB7XG5cdFx0Y29uc3Qgc2VsZiA9IHRoaXM7XG5cdFx0dHJ5IHtcblx0XHRcdGlmIChzZXNzaW9uU3RvcmFnZS5nZXRJdGVtKCdydWRkZXI6c2tpcE5leHRUcmFja1BhZ2UnKSkge1xuXHRcdFx0XHRzZXNzaW9uU3RvcmFnZS5yZW1vdmVJdGVtKCdydWRkZXI6c2tpcE5leHRUcmFja1BhZ2UnKTtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdC8vIHNlc3Npb25TdG9yYWdlIHVuYXZhaWxhYmxlIChwcml2YXRlIG1vZGUsIGJsb2NrZXIsIGV0Yy4pIOKAlCBmYWxsIHRocm91Z2ggYW5kIHRyYWNrXG5cdFx0fVxuXHRcdGlmICh3aW5kb3cucnVkZGVyRGF0YSkge1xuXHRcdFx0c2VsZi5saWIucGFnZShcblx0XHRcdFx0bnVsbCxcblx0XHRcdFx0bnVsbCxcblx0XHRcdFx0d2luZG93LnJ1ZGRlckRhdGEsXG5cdFx0XHRcdHNlbGYuY29tbW9uQXBpT3B0aW9ucygpXG5cdFx0XHQpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBAZGVzY3JpcHRpb24uIFJldHVybnMgYW4gU0RLIGFwaU9wdGlvbnMgb2JqZWN0IGNhcnJ5aW5nIHRoZSBjdXJyZW50XG5cdCAqIHJlcXVlc3QncyBjcm9zcy1jdXR0aW5nIG92ZXJyaWRlczogYGNoYW5uZWxgIChyb3V0ZWQgdG8gY29udGV4dC5jaGFubmVsXG5cdCAqIOKAlCB0aGUgdG9wLWxldmVsIGBjaGFubmVsYCBmaWVsZCBpcyBTREstcmVzZXJ2ZWQgZm9yIGxpYnJhcnkgaWRlbnRpdHkpXG5cdCAqIGFuZCBgY29udGV4dC5ncm91cElkL2dyb3VwVHJhaXRzYCAodGhlIFNESyBvbmx5IHN0YW1wcyBncm91cElkIG9uXG5cdCAqIGBncm91cGAgZXZlbnRzIGJ5IGRlZmF1bHQsIHNvIHRoaXMgaXMgaG93IHdlIG1ha2UgaXQgdmlzaWJsZSBvbiB0aGVcblx0ICogd2lkZXIgZXZlbnQgc3RyZWFtKS5cblx0ICpcblx0ICogYGNoYW5uZWxgIGFsd2F5cyBmYWxscyBiYWNrIHRvICd3ZWInIHdoZW4gdGhpcy5jaGFubmVsIGlzIHVuc2V0IOKAlFxuXHQgKiBkZWZlbmRzIGFnYWluc3QgdGhlIHBvc3QtZGVwbG95IGNhY2hlLWludmFsaWRhdGlvbiB3aW5kb3cgd2hlcmUgYVxuXHQgKiBmcmVzaCBydWRkZXJUb29scyBidW5kbGUgY2FuIGxvYWQgYWdhaW5zdCBhIHN0YWxlIGlubGluZVxuXHQgKiBgd2luZG93LnJ1ZGRlckNvbmZpZ2AgKGZyb20gSFRNTCBjYWNoZSkgdGhhdCBwcmVkYXRlcyB0aGUgYGNoYW5uZWxgXG5cdCAqIGtleS4gd3BfbG9jYWxpemVfc2NyaXB0IGhhcyBubyBpbmRlcGVuZGVudCB2ZXJzaW9uaW5nOyB0aGUgYD92ZXI9YFxuXHQgKiBxdWVyeXN0cmluZyBvbmx5IGJ1c3RzIHRoZSBKUyBVUkwsIG5vdCB0aGUgaW5saW5lIGxvY2FsaXplZCBkYXRhLiBJblxuXHQgKiBhbiBpbi1hcHAtYnJvd3NlciB2aWV3IHRoZSBzYW1lIHN0YWxlLWNhY2hlIHdpbmRvdyBjYW4gbWlzY2xhc3NpZnkgYVxuXHQgKiBmZXcgZXZlbnRzIGFzICd3ZWInIGluc3RlYWQgb2YgJ21vYmlsZS1icm93c2VyJyDigJQgYWNjZXB0ZWQgdHJhZGVcblx0ICogYmVjYXVzZSB0aGUgbWFqb3JpdHkgcGF0aCBpcyB3ZWIgYW5kIGxvc2luZyB0aGUgY2hhbm5lbCBzaWduYWxcblx0ICogZW50aXJlbHkgaXMgd29yc2UgdGhhbiB0aGUgdHJhbnNpZW50IG1pc2NsYXNzaWZpY2F0aW9uLlxuXHQgKlxuXHQgKiBAcmV0dXJuIHtPYmplY3R9XG5cdCAqL1xuXHRjb21tb25BcGlPcHRpb25zKCkge1xuXHRcdGNvbnN0IHNlbGYgPSB0aGlzO1xuXHRcdGNvbnN0IG9wdHMgPSB7IGNoYW5uZWw6IHNlbGYuY2hhbm5lbCB8fCAnd2ViJyB9O1xuXG5cdFx0Y29uc3QgZ3JvdXBJZCA9IHNlbGYubGliLmdldEdyb3VwSWQgJiYgc2VsZi5saWIuZ2V0R3JvdXBJZCgpO1xuXHRcdGlmIChncm91cElkKSB7XG5cdFx0XHRjb25zdCBncm91cFRyYWl0cyA9XG5cdFx0XHRcdChzZWxmLmxpYi5nZXRHcm91cFRyYWl0cyAmJiBzZWxmLmxpYi5nZXRHcm91cFRyYWl0cygpKSB8fCB7fTtcblx0XHRcdG9wdHMuY29udGV4dCA9IHsgZ3JvdXBJZCwgZ3JvdXBUcmFpdHMgfTtcblx0XHR9XG5cblx0XHRyZXR1cm4gb3B0cztcblx0fVxuXG5cdC8qKlxuXHQgKiBAZGVzY3JpcHRpb24uIEFkZHMgZXZlbnQgbGlzdGVuZXJzIGZvciB2YXJpb3VzIGV2ZW50cyB0byB0cmFjay5cblx0ICpcblx0ICogQHJldHVybiBcdHt2b2lkfVxuXHQgKi9cblx0YWRkTGlzdGVuZXJzKCkge1xuXHRcdGNvbnN0IHNlbGYgPSB0aGlzO1xuXG5cdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigncnVkZGVyOnRyYWNrJywgKGUpID0+IHtcblx0XHRcdGNvbnN0IGFwaU9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxuXHRcdFx0XHR7fSxcblx0XHRcdFx0ZS5kZXRhaWwuYXBpT3B0aW9ucyxcblx0XHRcdFx0c2VsZi5jb21tb25BcGlPcHRpb25zKClcblx0XHRcdCk7XG5cdFx0XHRzZWxmLmxpYi50cmFjayhcblx0XHRcdFx0ZS5kZXRhaWwuZXZlbnQsXG5cdFx0XHRcdGUuZGV0YWlsLnByb3BlcnRpZXMgfHwge30sXG5cdFx0XHRcdGFwaU9wdGlvbnNcblx0XHRcdCk7XG5cdFx0fSk7XG5cblx0XHRkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdydWRkZXI6cGFnZScsIChlKSA9PiB7XG5cdFx0XHRjb25zdCBhcGlPcHRpb25zID0gT2JqZWN0LmFzc2lnbihcblx0XHRcdFx0e30sXG5cdFx0XHRcdGUuZGV0YWlsLmFwaU9wdGlvbnMsXG5cdFx0XHRcdHNlbGYuY29tbW9uQXBpT3B0aW9ucygpXG5cdFx0XHQpO1xuXHRcdFx0c2VsZi5saWIucGFnZShcblx0XHRcdFx0ZS5kZXRhaWwuY2F0ZWdvcnkgfHwgbnVsbCxcblx0XHRcdFx0ZS5kZXRhaWwubmFtZSB8fCBudWxsLFxuXHRcdFx0XHRlLmRldGFpbC5wcm9wZXJ0aWVzIHx8IHt9LFxuXHRcdFx0XHRhcGlPcHRpb25zXG5cdFx0XHQpO1xuXHRcdH0pO1xuXG5cdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigncnVkZGVyOmlkZW50aWZ5JywgKGUpID0+IHtcblx0XHRcdGNvbnN0IGN1cnJlbnQgPSBzZWxmLmxpYi5nZXRVc2VySWRcblx0XHRcdFx0PyBzZWxmLmxpYi5nZXRVc2VySWQoKSB8fCBudWxsXG5cdFx0XHRcdDogbnVsbDtcblx0XHRcdGNvbnN0IG5leHQgPSBlLmRldGFpbC51c2VyX2lkIHx8IG51bGw7XG5cdFx0XHRjb25zdCB0cmFpdHMgPSBjbGVhblRyYWl0cyhlLmRldGFpbC50cmFpdHMpO1xuXHRcdFx0Y29uc3Qgc3RvcmVkID0gc2VsZi5saWIuZ2V0VXNlclRyYWl0c1xuXHRcdFx0XHQ/IHNlbGYubGliLmdldFVzZXJUcmFpdHMoKVxuXHRcdFx0XHQ6IHt9O1xuXG5cdFx0XHQvLyBEZWR1cGUgb24gaWRlbnRpdHkgQU5EIHRyYWl0cy4gS2V5aW5nIG9uIHVzZXJfaWQgYWxvbmUgbWFkZVxuXHRcdFx0Ly8gZXZlcnkgbGF0ZXIgaWRlbnRpZnkgZm9yIHRoZSBzYW1lIHVzZXIgYSBuby1vcCwgc28gYSBicm93c2VyXG5cdFx0XHQvLyB0aGF0IGxvc3QgaXRzIGBybF90cmFpdGAgY29va2llIChTYWZhcmkgY2FwcyBzY3JpcHQtd3JpdHRlblxuXHRcdFx0Ly8gY29va2llcyBhdCA3IGRheXMpIGtlcHQgZW1pdHRpbmcgZXZlbnRzIGNhcnJ5aW5nIGEgdXNlcl9pZFxuXHRcdFx0Ly8gd2l0aCBhbiBlbXB0eSBjb250ZXh0LnRyYWl0cywgYW5kIG5vIGFtb3VudCBvZiByZS1sb2dnaW5nLWluXG5cdFx0XHQvLyBjb3VsZCByZXBhaXIgaX
1QuIENvbXBhcmluZyB0cmFpdHMgdG9vIGxldHMgdGhlIGlkZW50aWZ5XG5cdFx0XHQvLyBkaXNwYXRjaGVkIG9uIGV2ZXJ5IHBhZ2UgbG9hZCBieSBzZXRQaWFub1VzZXJEYXRhKCkgcmVzdG9yZVxuXHRcdFx0Ly8gdGhlbSBvbmNlLCB0aGVuIHN0YXkgc2lsZW50LlxuXHRcdFx0aWYgKGN1cnJlbnQgPT09IG5leHQgJiYgdHJhaXRzQWxyZWFkeVN0b3JlZChzdG9yZWQsIHRyYWl0cykpIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBhcGlPcHRpb25zID0gT2JqZWN0LmFzc2lnbihcblx0XHRcdFx0e30sXG5cdFx0XHRcdGUuZGV0YWlsLmFwaU9wdGlvbnMsXG5cdFx0XHRcdHNlbGYuY29tbW9uQXBpT3B0aW9ucygpXG5cdFx0XHQpO1xuXHRcdFx0c2VsZi5saWIuaWRlbnRpZnkobmV4dCwgdHJhaXRzLCBhcGlPcHRpb25zKTtcblx0XHR9KTtcblxuXHRcdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3J1ZGRlcjpncm91cCcsIChlKSA9PiB7XG5cdFx0XHRjb25zdCBjdXJyZW50ID0gc2VsZi5saWIuZ2V0R3JvdXBJZFxuXHRcdFx0XHQ/IHNlbGYubGliLmdldEdyb3VwSWQoKSB8fCBudWxsXG5cdFx0XHRcdDogbnVsbDtcblx0XHRcdGNvbnN0IG5leHQgPSBlLmRldGFpbC5ncm91cF9pZCB8fCBudWxsO1xuXG5cdFx0XHRpZiAoY3VycmVudCA9PT0gbmV4dCkgcmV0dXJuO1xuXG5cdFx0XHRpZiAobmV4dCA9PT0gbnVsbCkge1xuXHRcdFx0XHRzZWxmLmxpYi5yZXNldCh7XG5cdFx0XHRcdFx0ZW50cmllczogeyBncm91cElkOiB0cnVlLCBncm91cFRyYWl0czogdHJ1ZSB9LFxuXHRcdFx0XHR9KTtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBhcGlPcHRpb25zID0gT2JqZWN0LmFzc2lnbihcblx0XHRcdFx0e30sXG5cdFx0XHRcdGUuZGV0YWlsLmFwaU9wdGlvbnMsXG5cdFx0XHRcdHNlbGYuY29tbW9uQXBpT3B0aW9ucygpXG5cdFx0XHQpO1xuXHRcdFx0c2VsZi5saWIuZ3JvdXAobmV4dCwgZS5kZXRhaWwudHJhaXRzIHx8IHt9LCBhcGlPcHRpb25zKTtcblx0XHR9KTtcblxuXHRcdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3J1ZGRlcjpyZXNldCcsIChlKSA9PiB7XG5cdFx0XHRjb25zdCBvcHRpb25zID0gZS5kZXRhaWwub3B0aW9ucyB8fCB7fTtcblxuXHRcdFx0Ly8gdXNlci1waWFuby5qcyBkaXNwYXRjaGVzIGFuIGlkZW50aXR5LXNjb3BlZCByZXNldCBmcm9tIGl0c1xuXHRcdFx0Ly8gbm90LWxvZ2dlZC1pbiBicmFuY2hlcywgaS5lLiBvbiBldmVyeSBhbm9ueW1vdXMgcGFnZSBsb2FkLiBTa2lwXG5cdFx0XHQvLyBpdCB3aGVuIG5vdGhpbmcgaXMgcGVyc2lzdGVkIHNvIGl0IGlzIGEgdHJ1ZSBuby1vcCB0aGVyZS4gQVxuXHRcdFx0Ly8gZnVsbCByZXNldCAobG9nb3V0IHBhc3NlcyBgdHJ1ZWApIGlzIG5ldmVyIHNob3J0LWNpcmN1aXRlZC5cblx0XHRcdGlmIChcblx0XHRcdFx0b3B0aW9ucy5lbnRyaWVzICYmXG5cdFx0XHRcdCEoc2VsZi5saWIuZ2V0VXNlcklkICYmIHNlbGYubGliLmdldFVzZXJJZCgpKVxuXHRcdFx0KSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0c2VsZi5saWIucmVzZXQob3B0aW9ucyk7XG5cdFx0fSk7XG5cdH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgUnVkZGVyVG9vbHM7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../assets/src/scripts/rudder/rudderTools.js\n\n}")},"../assets/src/scripts/rudder/rudderVideo.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){"use strict";eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _babel_runtime_helpers_typeof__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/typeof */ \"./node_modules/@babel/runtime/helpers/esm/typeof.js\");\n/* harmony import */ var _babel_runtime_helpers_toConsumableArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @babel/runtime/helpers/toConsumableArray */ \"./node_modules/@babel/runtime/helpers/esm/toConsumableArray.js\");\n/* harmony import */ var _babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @babel/runtime/helpers/classCallCheck */ \"./node_modules/@babel/runtime/helpers/esm/classCallCheck.js\");\n/* harmony import */ var _babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @babel/runtime/helpers/createClass */ \"./node_modules/@babel/runtime/helpers/esm/createClass.js\");\n/* harmony import */ var _rudderMedia__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./rudderMedia */ \"../assets/src/scripts/rudder/rudderMedia.js\");\n\n\n\n\nfunction _createForOfIteratorHelper(r, e) { var t = \"undefined\" != typeof Symbol && r[Symbol.iterator] || r[\"@@iterator\"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && \"number\" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t[\"return\"] || t[\"return\"](); } finally { if (u) throw o; } } }; }\nfunction _unsupportedIterableToArray(r, a) { if (r) { if (\"string\" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return \"Object\" === t && r.constructor && (t = r.constructor.name), \"Map\" === t || \"Set\" === t ? Array.from(r) : \"Arguments\" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }\nfunction _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }\n/**\n * Raw Vimeo postMessage tracking for `api=1` Vimeo iframes that are not owned\n * by an active Plyr instance.\n *\n * Primary case: LIVE FP Live streams tagged `data-rudder-media-player=\"vimeo\"`.\n *\n * Also covers Plyr-tagged embeds that never got Plyr (notably mobile on-demand\n * FP Live: markup says `plyr`, but the webview only loads rudderVideo + HTML5 â\n * the iframe is still a raw Vimeo player). Once Plyr enhances a player it marks\n * `data-rudder-tracked=\"plyr\"` / `.plyr`, and this module backs off so events\n * aren't double-counted.\n *\n * Surface + context come from `data-rudder-media-*` on the iframe/ancestor.\n * Late embeds: {@link observeDynamicMedia} (shared with rudderHtml5Media).\n */\n\n\n\n/** @param {Element|null} el */\nfunction isVimeoIframe(el) {\n var _el$src, _el$dataset;\n if (!el || el.tagName !== 'IFRAME') return false;\n return ((_el$src = el.src) === null || _el$src === void 0 ? void 0 : _el$src.includes('vimeo.com')) || ((_el$dataset = el.dataset) === null || _el$dataset === void 0 || (_el$dataset = _el$dataset.src) === null || _el$dataset === void 0 ? void 0 : _el$dataset.includes('vimeo.com'));\n}\n\n// Progress buckets shared with attachMediaTracking (Plyr/HTML5).\nvar MILESTONES
1= [25, 50, 75, 95];\nvar RudderVideo = /*#__PURE__*/function () {\n function RudderVideo() {\n (0,_babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(this, RudderVideo);\n this.vimeoPlayers = null;\n this.playedSessions = new Set(); // media ids that already fired a `play`\n // mediaId â Set of fired milestone buckets (non-live only)\n this.firedMilestones = new Map();\n this.messageHandler = this.handleMessage.bind(this);\n this.isInitialized = false;\n // playProgress drives milestones; matches Plyr/HTML5 timeupdate path.\n this.vidEvents = ['play', 'finish', 'playProgress'];\n /** @type {(() => void)|null} */\n this.unsubscribeDynamic = null;\n }\n return (0,_babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_3__[\"default\"])(RudderVideo, [{\n key: \"init\",\n value: function init() {\n var _this = this;\n if (this.isInitialized) return;\n if (document.readyState === 'loading') {\n window.addEventListener('DOMContentLoaded', function () {\n return _this.setup();\n }, {\n once: true\n });\n } else {\n this.setup();\n }\n }\n }, {\n key: \"setup\",\n value: function setup() {\n this.refreshPlayers();\n this.addPlayerListeners();\n this.observeDynamicIframes();\n this.isInitialized = true;\n }\n\n /**\n * Whether this iframe is a raw-Vimeo player we should own.\n *\n * Accepts:\n * - `data-rudder-media-player=\"vimeo\"` (explicit raw Vimeo, e.g. live streams)\n * - `data-rudder-media-player=\"plyr\"` when Plyr has NOT enhanced the iframe\n * (mobile on-demand, or any page that renders the markup without Plyr)\n *\n * Skips anything Plyr already claimed.\n *\n * @param {HTMLIFrameElement|null} iframe\n * @returns {boolean}\n */\n }, {\n key: \"isVimeoTrackedPlayer\",\n value: function isVimeoTrackedPlayer(iframe) {\n if (!iframe) return false;\n if (iframe.dataset.rudderTracked === 'plyr') return false;\n if (iframe.closest('[data-rudder-tracked=\"plyr\"]')) return false;\n // Plyr has upgraded the host â its own attachPlyrTracking owns events.\n if (iframe.closest('.plyr')) return false;\n var type = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.resolvePlayerType)(iframe);\n return type === 'vimeo' || type === 'plyr';\n }\n }, {\n key: \"refreshPlayers\",\n value: function refreshPlayers() {\n var _this2 = this;\n // Include iframes whose src is filled later from data-src\n var bySrc = document.querySelectorAll('iframe[src*=\"vimeo.com\"][src*=\"api=1\"]:not([data-rudder-tracked])');\n var byDataSrc = document.querySelectorAll('iframe[data-src*=\"vimeo.com\"][data-src*=\"api=1\"]:not([data-rudder-tracked])');\n var set = new Set([].concat((0,_babel_runtime_helpers_toConsumableArray__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(bySrc), (0,_babel_runtime_helpers_toConsumableArray__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(byDataSrc)));\n this.vimeoPlayers = Array.from(set).filter(function (iframe) {\n return _this2.isVimeoTrackedPlayer(iframe);\n });\n }\n }, {\n key: \"handleMessage\",\n value: function handleMessage(event) {\n if (event.origin !== 'https://player.vimeo.com') {\n return;\n }\n var data;\n try {\n data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;\n } catch (_e) {\n return;\n }\n if (!data || (0,_babel_runtime_helpers_typeof__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(data) !== 'object') return;\n\n // Vimeo posts many messages per player; only rescan the DOM when the\n // sender isn't already known (e.g. an iframe whose src was just filled\n // from data-src, which the childList observer doesn't catch).\n var iframe = this.findSender(event.source);\n if (!iframe) {\n this.refreshPlayers();\n iframe = this.findSender(event.source);\n }\n if (!iframe || !this.isVimeoTrackedPlayer(iframe)) return;\n var playerId = this.getVideoId(iframe);\n if (data.event === 'ready') {\n this.initializePlayer(iframe);\n }\n if (this.isVideoEvent(data)) {\n this.trackVideoEvent(data.event, playerId, data.data, iframe);\n }\n }\n }, {\n key: \"findSender\",\n value: function findSender(source) {\n var _this$vimeoPlayers;\n return ((_this$vimeoPlayers = this.vimeoPlayers) === null || _this$vimeoPlayers === void 0 ? void 0 : _this$vimeoPlayers.find(function (frame) {\n return frame.contentWindow === source;\n })) || null;\n }\n }, {\n key: \"getVideoId\",\n value: function getVideoId(iframe) {\n var _iframe$dataset;
1\n var src = iframe.src || ((_iframe$dataset = iframe.dataset) === null || _iframe$dataset === void 0 ? void 0 : _iframe$dataset.src) || '';\n var match = src.match(/video\\/(\\d+)/);\n return match ? match[1] : src || null;\n }\n }, {\n key: \"initializePlayer\",\n value: function initializePlayer(iframe) {\n var player = iframe.contentWindow;\n this.vidEvents.forEach(function (eventName) {\n player.postMessage(JSON.stringify({\n method: 'addEventListener',\n value: eventName\n }), 'https://player.vimeo.com');\n });\n }\n }, {\n key: \"isVideoEvent\",\n value: function isVideoEvent(data) {\n return this.vidEvents.includes(data.event) && data.data && data.data.percent !== undefined;\n }\n\n /**\n * @param {string} event Vimeo event name\n * @returns {'play'|'finish'|'milestone'|null}\n */\n }, {\n key: \"actionForEvent\",\n value: function actionForEvent(event) {\n if (event === 'play') return 'play';\n if (event === 'finish') return 'finish';\n if (event === 'playProgress') return 'milestone';\n return null;\n }\n }, {\n key: \"trackVideoEvent\",\n value: function trackVideoEvent(event, videoId, data, iframe) {\n // Both attrs required (player gated above; surface still required).\n var surface = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.resolveSurface)(iframe);\n var eventName = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.eventNameForSurface)(surface);\n if (!eventName) return;\n var action = this.actionForEvent(event);\n if (!action) return;\n\n // First play only â a resume must not re-fire (matches the Plyr/HTML5\n // core). Keyed by media id so each stream counts once per page.\n if (action === 'play') {\n if (this.playedSessions.has(videoId)) return;\n this.playedSessions.add(videoId);\n }\n\n // Finish / milestones only after a counted play (matches attachMediaTracking).\n if (action !== 'play' && !this.playedSessions.has(videoId)) return;\n\n // Shared DOM meta (embed_context, orientation, live flags).\n // player stays 'vimeo' â this is the raw postMessage path even when the\n // template declared plyr but Plyr never loaded.\n var meta = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.resolveMetaFromDom)(iframe, {\n surface: surface,\n provider: 'vimeo',\n player: 'vimeo',\n media_id: videoId\n });\n\n // No progress milestones for live streams (matches Plyr/HTML5).\n if (action === 'milestone') {\n if (meta.is_live_stream) return;\n var pct = (typeof (data === null || data === void 0 ? void 0 : data.percent) === 'number' ? data.percent : 0) * 100;\n if (!this.firedMilestones.has(videoId)) {\n this.firedMilestones.set(videoId, new Set());\n }\n var fired = this.firedMilestones.get(videoId);\n\n // Same as attachMediaTracking: emit every newly crossed bucket.\n for (var _i = 0, _MILESTONES = MILESTONES; _i < _MILESTONES.length;
1 _i++) {\n var milestone = _MILESTONES[_i];\n if (pct >= milestone && !fired.has(milestone)) {\n fired.add(milestone);\n (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.trackMedia)(eventName, (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.createMediaEvent)({\n action: 'milestone',\n surface: meta.surface,\n provider: 'vimeo',\n player: 'vimeo',\n media_id: videoId,\n media_title: meta.media_title,\n current_time: data === null || data === void 0 ? void 0 : data.seconds,\n duration: data === null || data === void 0 ? void 0 : data.duration,\n percent: data === null || data === void 0 ? void 0 : data.percent,\n progress: milestone,\n muted: null,\n play_intent: (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.playIntentFromMeta)(meta),\n is_live_stream: meta.is_live_stream,\n orientation: meta.orientation,\n embed_context: meta.embed_context\n }));\n }\n }\n return;\n }\n (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.trackMedia)(eventName, (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.createMediaEvent)({\n action: action,\n surface: meta.surface,\n provider: 'vimeo',\n player: 'vimeo',\n media_id: videoId,\n media_title: meta.media_title,\n current_time: data === null || data === void 0 ? void 0 : data.seconds,\n duration: data === null || data === void 0 ? void 0 : data.duration,\n percent: action === 'finish' ? 1 : data === null || data === void 0 ? void 0 : data.percent,\n // Vimeo postMessage doesn't expose mute state reliably.\n muted: null,\n play_intent: (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.playIntentFromMeta)(meta),\n is_live_stream: meta.is_live_stream,\n orientation: meta.orientation,\n embed_context: meta.embed_context\n }));\n }\n }, {\n key: \"addPlayerListeners\",\n value: function addPlayerListeners() {\n window.addEventListener('message', this.messageHandler);\n }\n\n /**\n * Watch for Vimeo iframes added after load (gated embeds, HTMX swaps).\n * Uses the shared body observer; one refresh per mutation batch is enough.\n *\n * @returns {void}\n */\n }, {\n key: \"observeDynamicIframes\",\n value: function observeDynamicIframes() {\n var _this3 = this;\n if (this.unsubscribeDynamic) return;\n this.unsubscribeDynamic = (0,_rudderMedia__WEBPACK_IMPORTED_MODULE_4__.observeDynamicMedia)(function (nodes) {\n var _iterator = _createForOfIteratorHelper(nodes),\n _step;\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var _node$querySelector;\n var node = _step.value;\n if (isVimeoIframe(node) || (_node$querySelector = node.querySelector) !== null && _node$querySelector !== void 0 && _node$querySelector.call(node, 'iframe[src*=\"vimeo.com\"], iframe[data-src*=\"vimeo.com\"]')) {\n _this3.refreshPlayers();\n return; // one refresh per mutation batch is enough\n }\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n });\n }\n }]);\n}();\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (RudderVideo);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJWaWRlby5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQVdBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFHQTs7QUFFQTtBQUNBO0FBQUE7QUFHQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0F
1BRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFaQTtBQUFBO0FBQUE7QUFjQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBRUE7QUFDQTtBQUNBO0FBR0E7QUFHQTtBQUNBO0FBQUE7QUFDQTtBQUVBO0FBQUE7QUFBQTtBQUFBO0FBR0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBSUE7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBRUE7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUVBO0FBQ0E7QUFFQTtBQUFBO0FBR0E7QUFBQTtBQUFBO0FBQUE7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBR0E7QUFFQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBR0E7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUdBO0FBS0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFIQTtBQUFBO0FBQUE7QUFLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFBQTtBQUFBO0FBQUE7QUFHQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUxBO0FBQUE7QUFBQTtBQU1BO0FBQ0E7QUFFQTtBQUFBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBTUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFHQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3J1ZGRlci9ydWRkZXJWaWRlby5qcz8zOTU5Il0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUmF3IFZpbWVvIHBvc3RNZXNzYWdlIHRyYWNraW5nIGZvciBgYXBpPTFgIFZpbWVvIGlmcmFtZXMgdGhhdCBhcmUgbm90IG93bmVkXG4gKiBieSBhbiBhY3RpdmUgUGx5ciBpbnN0YW5jZS5cbiAqXG4gKiBQcmltYXJ5IGNhc2U6IExJVkUgRlAgTGl2ZSBzdHJlYW1zIHRhZ2dlZCBgZGF0YS1ydWRkZXItbWVkaWEtcGxheWVyPVwidmltZW9cImAuXG4gKlxuICogQWxzbyBjb3ZlcnMgUGx5ci10YWdnZWQgZW1iZWRzIHRoYXQgbmV2ZXIgZ290IFBseXIgKG5vdGFibHkgbW9iaWxlIG9uLWRlbWFuZFxuICogRlAgTGl2ZTogbWFya3VwIHNheXMgYHBseXJgLCBidXQgdGhlIHdlYnZpZXcgb25seSBsb2FkcyBydWRkZXJWaWRlbyArIEhUTUw1IOKAlFxuICogdGhlIGlmcmFtZSBpcyBzdGlsbCBhIHJhdyBWaW1lbyBwbGF5ZXIpLiBPbmNlIFBseXIgZW5oYW5jZXMgYSBwbGF5ZXIgaXQgbWFya3NcbiAqIGBkYXRhLXJ1ZGRlci10cmFja2VkPVwicGx5clwiYCAvIGAucGx5cmAsIGFuZCB0aGlzIG1vZHVsZSBiYWNrcyBvZmYgc28gZXZlbnRzXG4gKiBhcmVuJ3QgZG91YmxlLWNvdW50ZWQuXG4gKlxuICogU3VyZmFjZSArIGNvbnRleHQgY29tZSBmcm9tIGBkYXRhLXJ1ZGRlci1tZWRpYS0qYCBvbiB0aGUgaWZyYW1lL2FuY2VzdG9yLlxuICogTGF0ZSBlbWJlZHM6IHtAbGluayBvYnNlcnZlRHluYW1pY01lZGlhfSAoc2hhcmVkIHdpdGggcnVkZGVySHRtbDVNZWRpYSkuXG4gKi9cblxuaW1wb3J0IHtcblx0dHJhY2tNZWRpYSxcblx0Y3JlYXRlTWVkaWFFdmVudCxcblx0ZXZlbn
1ROYW1lRm9yU3VyZmFjZSxcblx0cmVzb2x2ZVN1cmZhY2UsXG5cdHJlc29sdmVQbGF5ZXJUeXBlLFxuXHRyZXNvbHZlTWV0YUZyb21Eb20sXG5cdHBsYXlJbnRlbnRGcm9tTWV0YSxcblx0b2JzZXJ2ZUR5bmFtaWNNZWRpYSxcbn0gZnJvbSAnLi9ydWRkZXJNZWRpYSc7XG5cbi8qKiBAcGFyYW0ge0VsZW1lbnR8bnVsbH0gZWwgKi9cbmZ1bmN0aW9uIGlzVmltZW9JZnJhbWUoZWwpIHtcblx0aWYgKCFlbCB8fCBlbC50YWdOYW1lICE9PSAnSUZSQU1FJykgcmV0dXJuIGZhbHNlO1xuXHRyZXR1cm4gKFxuXHRcdGVsLnNyYz8uaW5jbHVkZXMoJ3ZpbWVvLmNvbScpIHx8IGVsLmRhdGFzZXQ/LnNyYz8uaW5jbHVkZXMoJ3ZpbWVvLmNvbScpXG5cdCk7XG59XG5cbi8vIFByb2dyZXNzIGJ1Y2tldHMgc2hhcmVkIHdpdGggYXR0YWNoTWVkaWFUcmFja2luZyAoUGx5ci9IVE1MNSkuXG5jb25zdCBNSUxFU1RPTkVTID0gWzI1LCA1MCwgNzUsIDk1XTtcblxuY2xhc3MgUnVkZGVyVmlkZW8ge1xuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHR0aGlzLnZpbWVvUGxheWVycyA9IG51bGw7XG5cdFx0dGhpcy5wbGF5ZWRTZXNzaW9ucyA9IG5ldyBTZXQoKTsgLy8gbWVkaWEgaWRzIHRoYXQgYWxyZWFkeSBmaXJlZCBhIGBwbGF5YFxuXHRcdC8vIG1lZGlhSWQg4oaSIFNldCBvZiBmaXJlZCBtaWxlc3RvbmUgYnVja2V0cyAobm9uLWxpdmUgb25seSlcblx0XHR0aGlzLmZpcmVkTWlsZXN0b25lcyA9IG5ldyBNYXAoKTtcblx0XHR0aGlzLm1lc3NhZ2VIYW5kbGVyID0gdGhpcy5oYW5kbGVNZXNzYWdlLmJpbmQodGhpcyk7XG5cdFx0dGhpcy5pc0luaXRpYWxpemVkID0gZmFsc2U7XG5cdFx0Ly8gcGxheVByb2dyZXNzIGRyaXZlcyBtaWxlc3RvbmVzOyBtYXRjaGVzIFBseXIvSFRNTDUgdGltZXVwZGF0ZSBwYXRoLlxuXHRcdHRoaXMudmlkRXZlbnRzID0gWydwbGF5JywgJ2ZpbmlzaCcsICdwbGF5UHJvZ3Jlc3MnXTtcblx0XHQvKiogQHR5cGUgeygoKSA9PiB2b2lkKXxudWxsfSAqL1xuXHRcdHRoaXMudW5zdWJzY3JpYmVEeW5hbWljID0gbnVsbDtcblx0fVxuXG5cdGluaXQoKSB7XG5cdFx0aWYgKHRoaXMuaXNJbml0aWFsaXplZCkgcmV0dXJuO1xuXG5cdFx0aWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICdsb2FkaW5nJykge1xuXHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCAoKSA9PiB0aGlzLnNldHVwKCksIHtcblx0XHRcdFx0b25jZTogdHJ1ZSxcblx0XHRcdH0pO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLnNldHVwKCk7XG5cdFx0fVxuXHR9XG5cblx0c2V0dXAoKSB7XG5cdFx0dGhpcy5yZWZyZXNoUGxheWVycygpO1xuXHRcdHRoaXMuYWRkUGxheWVyTGlzdGVuZXJzKCk7XG5cdFx0dGhpcy5vYnNlcnZlRHluYW1pY0lmcmFtZXMoKTtcblx0XHR0aGlzLmlzSW5pdGlhbGl6ZWQgPSB0cnVlO1xuXHR9XG5cblx0LyoqXG5cdCAqIFdoZXRoZXIgdGhpcyBpZnJhbWUgaXMgYSByYXctVmltZW8gcGxheWVyIHdlIHNob3VsZCBvd24uXG5cdCAqXG5cdCAqIEFjY2VwdHM6XG5cdCAqICAgLSBgZGF0YS1ydWRkZXItbWVkaWEtcGxheWVyPVwidmltZW9cImAgKGV4cGxpY2l0IHJhdyBWaW1lbywgZS5nLiBsaXZlIHN0cmVhbXMpXG5cdCAqICAgLSBgZGF0YS1ydWRkZXItbWVkaWEtcGxheWVyPVwicGx5clwiYCB3aGVuIFBseXIgaGFzIE5PVCBlbmhhbmNlZCB0aGUgaWZyYW1lXG5cdCAqICAgICAobW9iaWxlIG9uLWRlbWFuZCwgb3IgYW55IHBhZ2UgdGhhdCByZW5kZXJzIHRoZSBtYXJrdXAgd2l0aG91dCBQbHlyKVxuXHQgKlxuXHQgKiBTa2lwcyBhbnl0aGluZyBQbHlyIGFscmVhZHkgY2xhaW1lZC5cblx0ICpcblx0ICogQHBhcmFtIHtIVE1MSUZyYW1lRWxlbWVudHxudWxsfSBpZnJhbWVcblx0ICogQHJldHVybnMge2Jvb2xlYW59XG5cdCAqL1xuXHRpc1ZpbWVvVHJhY2tlZFBsYXllcihpZnJhbWUpIHtcblx0XHRpZiAoIWlmcmFtZSkgcmV0dXJuIGZhbHNlO1xuXHRcdGlmIChpZnJhbWUuZGF0YXNldC5ydWRkZXJUcmFja2VkID09PSAncGx5cicpIHJldHVybiBmYWxzZTtcblx0XHRpZiAoaWZyYW1lLmNsb3Nlc3QoJ1tkYXRhLXJ1ZGRlci10cmFja2VkPVwicGx5clwiXScpKSByZXR1cm4gZmFsc2U7XG5cdFx0Ly8gUGx5ciBoYXMgdXBncmFkZWQgdGhlIGhvc3Qg4oCUIGl0cyBvd24gYXR0YWNoUGx5clRyYWNraW5nIG93bnMgZXZlbnRzLlxuXHRcdGlmIChpZnJhbWUuY2xvc2VzdCgnLnBseXInKSkgcmV0dXJuIGZhbHNlO1xuXG5cdFx0Y29uc3QgdHlwZSA9IHJlc29sdmVQbGF5ZXJUeXBlKGlmcmFtZSk7XG5cdFx0cmV0dXJuIHR5cGUgPT09ICd2aW1lbycgfHwgdHlwZSA9PT0gJ3BseXInO1xuXHR9XG5cblx0cmVmcmVzaFBsYXllcnMoKSB7XG5cdFx0Ly8gSW5jbHVkZSBpZnJhbWVzIHdob3NlIHNyYyBpcyBmaWxsZWQgbGF0ZXIgZnJvbSBkYXRhLXNyY1xuXHRcdGNvbnN0IGJ5U3JjID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChcblx0XHRcdCdpZnJhbWVbc3JjKj1cInZpbWVvLmNvbVwiXVtzcmMqPVwiYXBpPTFcIl06bm90KFtkYXRhLXJ1ZGRlci10cmFja2VkXSknXG5cdFx0KTtcblx0XHRjb25zdCBieURhdGFTcmMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKFxuXHRcdFx0J2lmcmFtZVtkYXRhLXNyYyo9XCJ2aW1lby5jb21cIl1bZGF0YS1zcmMqPVwiYXBpPTFcIl06bm90KFtkYXRhLXJ1ZGRlci10cmFja2VkXSknXG5cdFx0KTtcblx0XHRjb25zdCBzZXQgPSBuZXcgU2V0KFsuLi5ieVNyYywgLi4uYnlEYXRhU3JjXSk7XG5cdFx0dGhpcy52aW1lb1BsYXllcnMgPSBBcnJheS5mcm9tKHNldCkuZmlsdGVyKChpZnJhbWUpID0+XG5cdFx0XHR0aGlzLmlzVmltZW9UcmFja2VkUGxheWVyKGlmcmFtZSlcblx0XHQpO1xuXHR9XG5cblx0aGFuZGxlTWVzc2FnZShldmVudCkge1xuXHRcdGlmIChldmVudC5vcmlnaW4gIT09ICdodHRwczovL3BsYXllci52aW1lby5jb20nKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bGV0IGRhdGE7XG5cdFx0dHJ5IHtcblx0XHRcdGRhdGEgPVxuXHRcdFx0XHR0eXBlb2YgZXZlbnQuZGF0YSA9PT0gJ3N0cmluZydcblx0XHRcdFx0XHQ/IEpTT04ucGFyc2UoZXZlbnQuZGF0YSlcblx0XHRcdFx0XHQ6IGV2ZW50LmRhdGE7XG5cdFx0fSBjYXRjaCAoX2UpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIWRhdGEgfHwgdHlwZW9mIGRhdGEgIT09ICdvYmplY3QnKSByZXR1cm47XG5cblx0XHQvLyBWaW1lbyBwb3N0cyBtYW55IG1lc3NhZ2VzIHBlciBwbGF5ZXI7IG9ubHkgcmVzY2FuIHRoZSBET00gd2hlbiB0aGVcblx0XHQvLyBzZW5kZXIgaXNuJ3QgYWxyZWFkeSBrbm93biAoZS5nLiBhbiBpZnJhbWUgd2hvc2Ugc3JjIHdhcyBqdXN0IGZpbGxlZFxuXHRcdC8vIGZyb20gZGF0YS1zcmMsIHdoaWNoIHRoZSBjaGlsZExpc3Qgb2JzZXJ2ZXIgZG9lc24ndCBjYXRjaCkuXG5cdFx0bGV0IGlmcmFtZSA9IHRoaXMuZmluZFNlbmRlcihldmVudC5zb3VyY2UpO1xuXHRcdGlmICghaWZyYW1lKSB7XG5cdFx0XHR0aGlzLnJlZnJlc2hQbGF5ZXJzKCk7XG5cdFx0XHRpZnJhbWUgPSB0aGlzLmZpbmRTZW5kZXIoZXZlbnQuc291cmNlKTtcblx0XHR9XG5cblx0XHRpZiAoIWlmcmFtZSB8fCAhdGhpcy5pc1ZpbWVvVHJhY2tlZFBsYXllcihpZnJhbWUpKSByZXR1cm47XG5cblx0XHRjb25zdCBwbGF5ZXJJZCA9IHRoaXMuZ2V0VmlkZW9JZChpZnJhbWUpO1xuXG5cdFx0aWYgKGRhdGEuZXZlbnQgPT09ICdyZWFkeScpIHtcblx0XHRcdHRoaXMuaW5pdGlhbGl6ZVBsYXllcihpZnJhbWUpO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLmlzVmlkZW9FdmVudChkYXRhKSkge1xuXHRcdFx0dGhpcy50cmFja1ZpZGVvRXZlbnQoZGF0YS5ldmVudCwgcGxheWVySWQsIGRhdGEuZGF0YSwgaWZyYW1lKTtcblx0XHR9XG5cdH1cblxuXHRmaW5kU2VuZGVyKHNvdXJjZSkge1xuXHRcdHJldHVybiAoXG5cdFx0XHR0aGlzLnZpbWVvUGxheWVycz8uZmluZChcblx0XHRcdFx0KGZyYW1lKSA9PiBmcmFtZS5jb250ZW50V2luZG93ID09PSBzb3VyY2Vcblx0XHRcdCkgfHwgbnVsbFxuXHRcdCk7XG5cdH1cblxuXHRnZXRWaWRlb0lkKGlmcmFtZSkge1xuXHRcdGNvbnN0IHNyYyA9IGlmcmFtZS5zcmMgfHwgaWZyYW1lLmRhdGFzZXQ/LnNyYyB8fCAnJztcblx0XHRjb25zdCBtYXRjaCA9IHNyYy5tYXRjaCgvdmlkZW9cXC8oXFxkKykvKTtcblx0XHRyZXR1cm4gbWF0Y2ggPyBtYXRjaFsxXSA6IHNyYyB8fCBudWxsO1xuXHR9XG5cblx0aW5pdGlhbGl6ZVBsYXllcihpZnJhbWUpIHtcblx0XHRjb25zdCBwbGF5ZXIgPSBpZnJhbWUuY29udGVudFdpbmRvdztcblxuXHRcdHRoaXMudmlkRXZlbnRzLmZvckVhY2goKGV2ZW50TmFtZSkgPT4ge1xuXHRcdFx0cGxheWVyLnBvc3RNZXNzYWdlKFxuXHRcdFx0XHRKU09OLnN0cmluZ2lmeSh7XG5cdFx0XHRcdFx0bWV0aG9kOiAnYWRkRXZlbnRMaXN0ZW5lcicsXG5cdFx0XHRcdFx0dmFsdWU6IGV2ZW50TmFtZSxcblx0XHRcdFx0fSksXG5cdFx0XHRcdCdodHRwczovL3BsYXllci52aW1lby5jb20nXG5cdFx0XHQpO1xuXHRcdH0pO1xuXHR9XG5cblx0aXNWaWRlb0V2ZW50KGRhdGEpIHtcblx0XHRyZXR1cm4gKFxuXHRcdFx0dGhpcy52aWRFdmVudHMuaW5jbHVkZXMoZGF0YS5ldmVudCkgJiZcblx0XHRcdGRhdGEuZGF0YSAmJlxuXHRcdFx0ZGF0YS5kYXRhLnBlcmNlbnQgIT09IHVuZGVmaW5lZFxuXHRcdCk7XG5cdH1cblxuXHQvKipcblx0ICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50ICBWaW1lbyBldmVudCBuYW1lXG5cdCAqIEByZXR1cm5zIHsncGxheSd8J2ZpbmlzaCd8J21pbGVzdG9uZSd8bnVsbH1cblx0ICovXG5cdGFjdGlvbkZvckV2ZW50KGV2ZW50KSB7XG5cdFx0aWYgKGV2ZW50ID09PSAncGxheScpIHJldHVybiAncGxheSc7XG5cdFx0aWYgKGV2ZW50ID09PSAnZmluaXNoJykgcmV0dXJuICdmaW5pc2gnO1xuXHRcdGlmIChldmVudCA9PT0gJ3BsYXlQcm9ncmVzcycpIHJldHVybiAnbWlsZXN0b25lJztcblx0XHRyZXR1cm4gbnVsbDtcblx0fVxuXG5cdHRyYWNrVmlkZW9FdmVudChldmVudCwgdmlkZW9JZCwgZGF0YSwgaWZyYW1lKSB7XG5cdFx0Ly8gQm90aCBhdHRycyByZXF1aXJlZCAocGxheWVyIGdhdGVkIGFib3ZlOyBzdXJmYWNlIHN0aWxsIHJlcXVpcmVkKS5cblx0XHRjb25zdCBzdXJmYWNlID0gcmVzb2x2ZVN1cmZhY2UoaWZyYW1lKTtcblx0XHRjb25zdCBldmVudE5hbWUgPSBldmVudE5hbWVGb3JTdXJmYWNlKHN1cmZhY2UpO1xuXHRcdGlmICghZXZlbnROYW1lKSByZXR1cm47XG5cblx0XHRjb25zdCBhY3Rpb24gPSB0aGlzLmFjdGlvbkZvckV2ZW50KGV2ZW50KTtcblx0XHRpZiAoIWFjdGlvbikgcmV0dXJuO1xuXG5cdFx0Ly8gRmlyc3QgcGxheSBvbmx5IOKAlCBhIHJlc3VtZSBtdXN0IG5vdCByZS1maXJlIChtYXRjaGVzIHRoZSBQbHlyL0hUTUw1XG5cdFx0Ly8gY29yZSkuIEtleWVkIGJ5IG1lZGlhIGlkIHNvIGVhY2ggc3RyZWFtIGNvdW50cyBvbmNlIHBlciBwYWdlLlxuXHRcdGlmIChhY3Rpb24gPT09ICdwbGF5Jykge1xuXHRcdFx0aWYgKHRoaXMucGxheWVkU2Vzc2lvbnMuaGFzKHZpZGVvSWQpKSByZXR1cm47XG5cdFx0XHR0aGlzLnBsYXllZFNlc3Npb25zLmFkZCh2aWRlb0lkKTtcblx0XHR9XG5cblx0XHQvLyBGaW5pc2ggLyBtaWxlc3RvbmVzIG9ubHkgYWZ0ZXIgYSBjb3VudGVkIHBsYXkgKG1hdGNoZXMgYXR0YWNoTWVkaWFUcmFja2luZykuXG5cdFx0aWYgKGFjdGlvbiAhPT0gJ3BsYXknICYmICF0aGlzLnBsYXllZFNlc3Npb25zLmhhcyh2aWRlb0lkKSkgcmV0dXJuO1xuXG5cdFx0Ly8gU2hhcmVkIERPTSBtZXRhIChlbWJlZF9jb250ZXh0LCBvcmllbnRhdGlvbiwgbGl2ZSBmbGFncykuXG5cdFx0Ly8gcGxheWVyIHN0YXlzICd2aW1lbycg4oCUIHRoaXMgaXMgdGhlIHJhdyBwb3N0TWVzc2FnZSBwYXRoIGV2ZW4gd2hlbiB0aGVcblx0XHQvLyB0ZW1wbGF0ZSBkZWNsYXJlZCBwbHlyIGJ1dCBQbHlyIG5ldmVyIGxvYWRlZC5cblx0XHRjb25zdCBtZXRhID0gcmVzb2x2ZU1ldGFGcm9tRG9tKGlmcmFtZSwge1xuXHRcdFx0c3VyZmFjZSxcblx0XHRcdHByb3ZpZGVyOiAndmltZW8nLFxuXHRcdFx0cGxheWVyOiAndmltZW8nLFxuXHRcdFx0bWVkaWFfaWQ6IHZpZGVvSWQsXG5cdFx0fSk7XG5cblx0XHQvLyBObyBwcm9ncmVzcyBtaWxlc3RvbmVzIGZvciBsaXZlIHN0cmVhbXMgKG1hdGNoZXMgUGx5ci9IVE1MNSkuXG5cdFx0aWYgKGFjdGlvbiA9PT0gJ21pbGVzdG9uZScpIHtcblx0XHRcdGlmIChtZXRhLmlzX2xpdmVfc3RyZWFtKSByZXR1cm47XG5cblx0XHRcdGNvbnN0IHBjdCA9XG5cdFx0XHRcdCh0eXBlb2YgZGF0YT8ucGVyY2VudCA9PT0gJ251bWJlcicgPyBkYXRhLnBlcmNlbnQgOiAwKSAqIDEwMDtcblx0XHRcdGlmICghdGhpcy5maXJlZE1pbGVzdG9uZXMuaGFzKHZpZGVvSWQpKSB7XG5cdFx0XHRcdHRoaXMuZmlyZWRNaWxlc3RvbmVzLnNldCh2aWRlb0lkLCBuZXcgU2V0KCkpO1xuXHRcdFx0fVxuXHRcdFx0Y29uc3QgZmlyZWQgPSB0aGlzLmZpcmVkTWlsZXN0b25lcy5nZXQodmlkZW9JZCk7XG5cblx0XHRcdC8vIFNhbWUgYXMgYXR0YWNoTWVkaWFUcmFja2luZzogZW1pdCBldmVyeSBuZXdseSBjcm9zc2VkIGJ1Y2tldC5cblx0XHRcdGZvciAoY29uc3QgbWlsZXN0b25lIG9mIE1JTEVTVE9ORVMpIHtcblx0XHRcdFx0aWYgKHBjdCA+PSBtaWxlc3RvbmUgJiYgIWZpcmVkLmhhcyhtaWxlc3RvbmUpKSB7XG5cdFx0XHRcdFx0ZmlyZWQuYWRkKG1pbGVzdG9uZSk7XG5cdFx0XHRcdFx0dHJhY2tNZWRpYShcblx0XHRcdFx0XHRcdGV2ZW50TmFtZSxcblx0XHRcdFx0XHRcdGNyZWF0ZU1lZGlhRXZlbnQoe1xuXHRcdFx0XHRcdFx0XHRhY3Rpb246ICdtaWxlc3RvbmUnLFxuXHRcdFx0XHRcdFx0XHRzdXJmYWNlOiBtZXRhLnN1cmZhY2UsXG5cdFx0XHRcdFx0XHRcdHByb3ZpZGVyOiAndmltZW8nLFxuXHRcdFx0XHRcdFx0XHRwbGF5ZXI6ICd2aW1lbycsXG5cdFx0XHRcdFx0XHRcdG1lZGlhX2lkOiB2aWRlb0lkLFxuXHRcdFx0XHRcdFx0XHRtZWRpYV90aXRsZTogbWV0YS5tZWRpYV90aXRsZSxcblx0XHRcdFx0XHRcdFx0Y3VycmVudF90aW1lOiBkYXRhPy5zZWNvbmRzLFxuXHRcdFx0XHRcdFx0XHRkdXJhdGlvbj
1ogZGF0YT8uZHVyYXRpb24sXG5cdFx0XHRcdFx0XHRcdHBlcmNlbnQ6IGRhdGE/LnBlcmNlbnQsXG5cdFx0XHRcdFx0XHRcdHByb2dyZXNzOiBtaWxlc3RvbmUsXG5cdFx0XHRcdFx0XHRcdG11dGVkOiBudWxsLFxuXHRcdFx0XHRcdFx0XHRwbGF5X2ludGVudDogcGxheUludGVudEZyb21NZXRhKG1ldGEpLFxuXHRcdFx0XHRcdFx0XHRpc19saXZlX3N0cmVhbTogbWV0YS5pc19saXZlX3N0cmVhbSxcblx0XHRcdFx0XHRcdFx0b3JpZW50YXRpb246IG1ldGEub3JpZW50YXRpb24sXG5cdFx0XHRcdFx0XHRcdGVtYmVkX2NvbnRleHQ6IG1ldGEuZW1iZWRfY29udGV4dCxcblx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRyYWNrTWVkaWEoXG5cdFx0XHRldmVudE5hbWUsXG5cdFx0XHRjcmVhdGVNZWRpYUV2ZW50KHtcblx0XHRcdFx0YWN0aW9uLFxuXHRcdFx0XHRzdXJmYWNlOiBtZXRhLnN1cmZhY2UsXG5cdFx0XHRcdHByb3ZpZGVyOiAndmltZW8nLFxuXHRcdFx0XHRwbGF5ZXI6ICd2aW1lbycsXG5cdFx0XHRcdG1lZGlhX2lkOiB2aWRlb0lkLFxuXHRcdFx0XHRtZWRpYV90aXRsZTogbWV0YS5tZWRpYV90aXRsZSxcblx0XHRcdFx0Y3VycmVudF90aW1lOiBkYXRhPy5zZWNvbmRzLFxuXHRcdFx0XHRkdXJhdGlvbjogZGF0YT8uZHVyYXRpb24sXG5cdFx0XHRcdHBlcmNlbnQ6IGFjdGlvbiA9PT0gJ2ZpbmlzaCcgPyAxIDogZGF0YT8ucGVyY2VudCxcblx0XHRcdFx0Ly8gVmltZW8gcG9zdE1lc3NhZ2UgZG9lc24ndCBleHBvc2UgbXV0ZSBzdGF0ZSByZWxpYWJseS5cblx0XHRcdFx0bXV0ZWQ6IG51bGwsXG5cdFx0XHRcdHBsYXlfaW50ZW50OiBwbGF5SW50ZW50RnJvbU1ldGEobWV0YSksXG5cdFx0XHRcdGlzX2xpdmVfc3RyZWFtOiBtZXRhLmlzX2xpdmVfc3RyZWFtLFxuXHRcdFx0XHRvcmllbnRhdGlvbjogbWV0YS5vcmllbnRhdGlvbixcblx0XHRcdFx0ZW1iZWRfY29udGV4dDogbWV0YS5lbWJlZF9jb250ZXh0LFxuXHRcdFx0fSlcblx0XHQpO1xuXHR9XG5cblx0YWRkUGxheWVyTGlzdGVuZXJzKCkge1xuXHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgdGhpcy5tZXNzYWdlSGFuZGxlcik7XG5cdH1cblxuXHQvKipcblx0ICogV2F0Y2ggZm9yIFZpbWVvIGlmcmFtZXMgYWRkZWQgYWZ0ZXIgbG9hZCAoZ2F0ZWQgZW1iZWRzLCBIVE1YIHN3YXBzKS5cblx0ICogVXNlcyB0aGUgc2hhcmVkIGJvZHkgb2JzZXJ2ZXI7IG9uZSByZWZyZXNoIHBlciBtdXRhdGlvbiBiYXRjaCBpcyBlbm91Z2guXG5cdCAqXG5cdCAqIEByZXR1cm5zIHt2b2lkfVxuXHQgKi9cblx0b2JzZXJ2ZUR5bmFtaWNJZnJhbWVzKCkge1xuXHRcdGlmICh0aGlzLnVuc3Vic2NyaWJlRHluYW1pYykgcmV0dXJuO1xuXG5cdFx0dGhpcy51bnN1YnNjcmliZUR5bmFtaWMgPSBvYnNlcnZlRHluYW1pY01lZGlhKChub2RlcykgPT4ge1xuXHRcdFx0Zm9yIChjb25zdCBub2RlIG9mIG5vZGVzKSB7XG5cdFx0XHRcdGlmIChcblx0XHRcdFx0XHRpc1ZpbWVvSWZyYW1lKG5vZGUpIHx8XG5cdFx0XHRcdFx0bm9kZS5xdWVyeVNlbGVjdG9yPy4oXG5cdFx0XHRcdFx0XHQnaWZyYW1lW3NyYyo9XCJ2aW1lby5jb21cIl0sIGlmcmFtZVtkYXRhLXNyYyo9XCJ2aW1lby5jb21cIl0nXG5cdFx0XHRcdFx0KVxuXHRcdFx0XHQpIHtcblx0XHRcdFx0XHR0aGlzLnJlZnJlc2hQbGF5ZXJzKCk7XG5cdFx0XHRcdFx0cmV0dXJuOyAvLyBvbmUgcmVmcmVzaCBwZXIgbXV0YXRpb24gYmF0Y2ggaXMgZW5vdWdoXG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9KTtcblx0fVxufVxuXG5leHBvcnQgZGVmYXVsdCBSdWRkZXJWaWRlbztcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///../assets/src/scripts/rudder/rudderVideo.js\n\n}")},"../assets/src/scripts/utils/cookies.js"(module){eval("{module.exports = {\n /**\n * Summary. Retrieves a cookie.\n *\n * @param {string} sKey - Cookie key\n * \n * @return {string|null} The cookie value or null on empty.\n */\n get: function get(sKey) {\n return decodeURIComponent(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\\\s*' + encodeURIComponent(sKey).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$'), '$1')) || null;\n },\n /**\n * Summary. Creates a cookie.\n *\n * @param {string} sKey - Cookie key\n * @param {string} sValue - Cookie value\n * @param {Number|String|Date} vEnd - Cookie expiration date\n * @param {string} sPath - Cookie Path\n * @param {string} sDomain - Cookie domain\n * @param {bool} bSecure - Store cookie as secure\n * \n * @return {bool} Whether the cookie was successfully created.\n */\n set: function set(sKey, sValue, vEnd, sPath, sDomain, bSecure) {\n var sExpires = '';\n if (!sKey || /^(?:expires|max\\-age|path|domain|secure)$/i.test(sKey)) {\n return false;\n }\n if (vEnd) {\n switch (vEnd.constructor) {\n case Number:\n sExpires = vEnd === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + vEnd;\n break;\n case String:\n sExpires = '; expires=' + vEnd;\n break;\n case Date:\n sExpires = '; expires=' + vEnd.toUTCString();\n break;\n }\n }\n var cookie = encodeURIComponent(sKey) + '=' + encodeURIComponent(sValue) + sExpires + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '') + (bSecure ? '; secure' : '');\n document.cookie = cookie;\n return true;\n },\n /**\n * Summary. Removes an existing cookie.\n *\n * @param {string} sKey \t\t- Cookie key\n * @param {string} sPath \t\t- Cookie path\n * @param {string} sDomain \t- Cookie domain\n * \n * @return {bool} If cookie was successfully deleted.\n */\n \"delete\": function _delete(sKey, sPath, sDomain) {\n if (!sKey || !this.hasItem(sKey)) {\n return false;\n }\n document.cookie = encodeURIComponent(sKey) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '');\n return true;\n },\n /**\n * Summary. Checks if a cookie exists.\n *\n * @param {string} sKey - Cookie key\n * \n * @return {bool} Whether the cookie exists.\n */\n exists: function exists(sKey) {\n return new RegExp('(?:^|;\\\\s*)' + encodeURIComponent(sKey).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=').test(document.cookie);\n }\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3V0aWxzL2Nvb2tpZXMuanMiLCJuYW1lcyI6WyJtb2R1bGUiLCJleHBvcnRzIiwiZ2V0Iiwic0tleSIsImRlY29kZVVSSUNvbXBvbmVudCIsImRvY3VtZW50IiwiY29va2llIiwicmVwbGFjZSIsIlJlZ0V4cCIsImVuY29kZVVSSUNvbXBvbmVudCIsInNldCIsInNWYWx1ZSIsInZFbmQiLCJzUGF0aCIsInNEb21haW4iLCJiU2VjdXJlIiwic0V4cGlyZXMiLCJ0ZXN0IiwiY29uc3RydWN0b3IiLCJOdW1iZXIiLCJJbmZpbml0eSIsIlN0cmluZyIsIkRhdGUiLCJ0b1VUQ1N0cmluZyIsImRlbGV0ZSIsImhhc0l0ZW0iLCJleGlzdHMiXSwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3V0aWxzL2Nvb2tpZXMuanM/NDM1YiJdLCJzb3VyY2VzQ29udGVudCI6WyJtb2R1bGUuZXhwb3J0cyA9IHtcblx0LyoqXG5cdCAqIFN1bW1hcnkuIFJldHJpZXZlcyBhIGNvb2tpZS5cblx0ICpcblx0ICogQHBhcmFtIHtzdHJpbmd9IHNLZXkgLSBDb29raWUga2V5XG5cdCAqIFxuXHQgKiBAcmV0dXJuIHtzdHJpbmd8bnVsbH0gVGhlIGNvb2tpZSB2YWx1ZSBvciBudWxsIG9uIGVtcHR5LlxuXHQgKi9cblx0Z2V0OiBmdW5jdGlvbihzS2V5KSB7XG5cdFx0cmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudChcblx0XHRcdGRvY3VtZW50LmNvb2tpZS5yZXBsYWNlKG5ldyBSZWdFeHAoJyg/Oig/Ol58Lio7KVxcXFxzKicgXG5cdFx0XHQrIGVuY29kZVVSSUNvbXBvbmVudChzS2V5KS5yZXBsYWNlKC9bXFwtXFwuXFwrXFwqXS9nLCAnXFxcXCQmJ1xuXHRcdFx0KSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQpfF4uKiQnKSwgJyQxJ
1ykpIHx8IG51bGw7XG5cdH0sXG5cblx0LyoqXG5cdCAqIFN1bW1hcnkuIENyZWF0ZXMgYSBjb29raWUuXG5cdCAqXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBzS2V5ICAgICAgICAgICAgIC0gQ29va2llIGtleVxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc1ZhbHVlICAgICAgICAgICAtIENvb2tpZSB2YWx1ZVxuXHQgKiBAcGFyYW0ge051bWJlcnxTdHJpbmd8RGF0ZX0gdkVuZCAtIENvb2tpZSBleHBpcmF0aW9uIGRhdGVcblx0ICogQHBhcmFtIHtzdHJpbmd9IHNQYXRoICAgICAgICAgICAgLSBDb29raWUgUGF0aFxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc0RvbWFpbiAgICAgICAgICAtIENvb2tpZSBkb21haW5cblx0ICogQHBhcmFtIHtib29sfSBiU2VjdXJlICAgICAgICAgICAgLSBTdG9yZSBjb29raWUgYXMgc2VjdXJlXG5cdCAqIFxuXHQgKiBAcmV0dXJuIHtib29sfSBXaGV0aGVyIHRoZSBjb29raWUgd2FzIHN1Y2Nlc3NmdWxseSBjcmVhdGVkLlxuXHQgKi9cblx0c2V0OiBmdW5jdGlvbihzS2V5LCBzVmFsdWUsIHZFbmQsIHNQYXRoLCBzRG9tYWluLCBiU2VjdXJlKSB7XG5cdFx0bGV0IHNFeHBpcmVzID0gJyc7XG5cblx0XHRpZiAoIXNLZXkgfHwgL14oPzpleHBpcmVzfG1heFxcLWFnZXxwYXRofGRvbWFpbnxzZWN1cmUpJC9pLnRlc3Qoc0tleSkpIHsgXG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0aWYgKHZFbmQpIHtcblx0XHRcdHN3aXRjaCAodkVuZC5jb25zdHJ1Y3Rvcikge1xuXHRcdFx0Y2FzZSBOdW1iZXI6XG5cdFx0XHRcdHNFeHBpcmVzID0gdkVuZCA9PT0gSW5maW5pdHkgXG5cdFx0XHRcdFx0PyAnOyBleHBpcmVzPUZyaSwgMzEgRGVjIDk5OTkgMjM6NTk6NTkgR01UJyBcblx0XHRcdFx0XHQ6ICc7IG1heC1hZ2U9JyArIHZFbmQ7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSBTdHJpbmc6XG5cdFx0XHRcdHNFeHBpcmVzID0gJzsgZXhwaXJlcz0nICsgdkVuZDtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIERhdGU6XG5cdFx0XHRcdHNFeHBpcmVzID0gJzsgZXhwaXJlcz0nICsgdkVuZC50b1VUQ1N0cmluZygpO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9XG5cblx0XHRsZXQgY29va2llID0gZW5jb2RlVVJJQ29tcG9uZW50KHNLZXkpIFxuXHRcdFx0KyAnPScgXG5cdFx0XHQrIGVuY29kZVVSSUNvbXBvbmVudChzVmFsdWUpIFxuXHRcdFx0KyBzRXhwaXJlcyBcblx0XHRcdCsgKHNEb21haW4gPyAnOyBkb21haW49JyArIHNEb21haW4gOiAnJykgXG5cdFx0XHQrIChzUGF0aCA/ICc7IHBhdGg9JyArIHNQYXRoIDogJycpIFxuXHRcdFx0KyAoYlNlY3VyZSA/ICc7IHNlY3VyZScgOiAnJyk7XG5cblx0XHRkb2N1bWVudC5jb29raWUgPSBjb29raWU7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0LyoqXG5cdCAqIFN1bW1hcnkuIFJlbW92ZXMgYW4gZXhpc3RpbmcgY29va2llLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc0tleSBcdFx0LSBDb29raWUga2V5XG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBzUGF0aCBcdFx0LSBDb29raWUgcGF0aFxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc0RvbWFpbiBcdC0gQ29va2llIGRvbWFpblxuXHQgKiBcblx0ICogQHJldHVybiB7Ym9vbH0gSWYgY29va2llIHdhcyBzdWNjZXNzZnVsbHkgZGVsZXRlZC5cblx0ICovXG5cdGRlbGV0ZTogZnVuY3Rpb24oc0tleSwgc1BhdGgsIHNEb21haW4pIHtcblx0XHRpZiAoIXNLZXkgfHwgIXRoaXMuaGFzSXRlbShzS2V5KSkgeyByZXR1cm4gZmFsc2U7IH1cblxuXHRcdGRvY3VtZW50LmNvb2tpZSA9IGVuY29kZVVSSUNvbXBvbmVudChzS2V5KSBcblx0XHRcdCsgJz07IGV4cGlyZXM9VGh1LCAwMSBKYW4gMTk3MCAwMDowMDowMCBHTVQnIFxuXHRcdFx0KyAoc0RvbWFpbiA/ICc7IGRvbWFpbj0nICsgc0RvbWFpbiA6ICcnKSBcblx0XHRcdCsgKHNQYXRoID8gJzsgcGF0aD0nICsgc1BhdGggOiAnJyk7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0LyoqXG5cdCAqIFN1bW1hcnkuIENoZWNrcyBpZiBhIGNvb2tpZSBleGlzdHMuXG5cdCAqXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBzS2V5IC0gQ29va2llIGtleVxuXHQgKiBcblx0ICogQHJldHVybiB7Ym9vbH0gV2hldGhlciB0aGUgY29va2llIGV4aXN0cy5cblx0ICovXG5cdGV4aXN0czogZnVuY3Rpb24oc0tleSkge1xuXHRcdHJldHVybiAobmV3IFJlZ0V4cCgnKD86Xnw7XFxcXHMqKScgXG5cdFx0XHQrIGVuY29kZVVSSUNvbXBvbmVudChzS2V5KS5yZXBsYWNlKC9bXFwtXFwuXFwrXFwqXS9nLCAnXFxcXCQmJykgXG5cdFx0XHQrICdcXFxccypcXFxcPScpKS50ZXN0KGRvY3VtZW50LmNvb2tpZSk7XG5cdH0sXG59OyJdLCJtYXBwaW5ncyI6IkFBQUFBLE1BQU0sQ0FBQ0MsT0FBTyxHQUFHO0VBQ2hCO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0NDLEdBQUcsRUFBRSxTQUFMQSxHQUFHQSxDQUFXQyxJQUFJLEVBQUU7SUFDbkIsT0FBT0Msa0JBQWtCLENBQ3hCQyxRQUFRLENBQUNDLE1BQU0sQ0FBQ0MsT0FBTyxDQUFDLElBQUlDLE1BQU0sQ0FBQyxrQkFBa0IsR0FDbkRDLGtCQUFrQixDQUFDTixJQUFJLENBQUMsQ0FBQ0ksT0FBTyxDQUFDLGFBQWEsRUFBRSxNQUNsRCxDQUFDLEdBQUcsNkJBQTZCLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUk7RUFDcEQsQ0FBQztFQUVEO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNDRyxHQUFHLEVBQUUsU0FBTEEsR0FBR0EsQ0FBV1AsSUFBSSxFQUFFUSxNQUFNLEVBQUVDLElBQUksRUFBRUMsS0FBSyxFQUFFQyxPQUFPLEVBQUVDLE9BQU8sRUFBRTtJQUMxRCxJQUFJQyxRQUFRLEdBQUcsRUFBRTtJQUVqQixJQUFJLENBQUNiLElBQUksSUFBSSw0Q0FBNEMsQ0FBQ2MsSUFBSSxDQUFDZCxJQUFJLENBQUMsRUFBRTtNQUNyRSxPQUFPLEtBQUs7SUFDYjtJQUVBLElBQUlTLElBQUksRUFBRTtNQUNULFFBQVFBLElBQUksQ0FBQ00sV0FBVztRQUN4QixLQUFLQyxNQUFNO1VBQ1ZILFFBQVEsR0FBR0osSUFBSSxLQUFLUSxRQUFRLEdBQ3pCLHlDQUF5QyxHQUN6QyxZQUFZLEdBQUdSLElBQUk7VUFDdEI7UUFDRCxLQUFLUyxNQUFNO1VBQ1ZMLFFBQVEsR0FBRyxZQUFZLEd
1BQUdKLElBQUk7VUFDOUI7UUFDRCxLQUFLVSxJQUFJO1VBQ1JOLFFBQVEsR0FBRyxZQUFZLEdBQUdKLElBQUksQ0FBQ1csV0FBVyxDQUFDLENBQUM7VUFDNUM7TUFDRDtJQUNEO0lBRUEsSUFBSWpCLE1BQU0sR0FBR0csa0JBQWtCLENBQUNOLElBQUksQ0FBQyxHQUNsQyxHQUFHLEdBQ0hNLGtCQUFrQixDQUFDRSxNQUFNLENBQUMsR0FDMUJLLFFBQVEsSUFDUEYsT0FBTyxHQUFHLFdBQVcsR0FBR0EsT0FBTyxHQUFHLEVBQUUsQ0FBQyxJQUNyQ0QsS0FBSyxHQUFHLFNBQVMsR0FBR0EsS0FBSyxHQUFHLEVBQUUsQ0FBQyxJQUMvQkUsT0FBTyxHQUFHLFVBQVUsR0FBRyxFQUFFLENBQUM7SUFFOUJWLFFBQVEsQ0FBQ0MsTUFBTSxHQUFHQSxNQUFNO0lBQ3hCLE9BQU8sSUFBSTtFQUNaLENBQUM7RUFFRDtBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDQyxVQUFRLFNBQVJrQixPQUFNQSxDQUFXckIsSUFBSSxFQUFFVSxLQUFLLEVBQUVDLE9BQU8sRUFBRTtJQUN0QyxJQUFJLENBQUNYLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQ3NCLE9BQU8sQ0FBQ3RCLElBQUksQ0FBQyxFQUFFO01BQUUsT0FBTyxLQUFLO0lBQUU7SUFFbERFLFFBQVEsQ0FBQ0MsTUFBTSxHQUFHRyxrQkFBa0IsQ0FBQ04sSUFBSSxDQUFDLEdBQ3ZDLDBDQUEwQyxJQUN6Q1csT0FBTyxHQUFHLFdBQVcsR0FBR0EsT0FBTyxHQUFHLEVBQUUsQ0FBQyxJQUNyQ0QsS0FBSyxHQUFHLFNBQVMsR0FBR0EsS0FBSyxHQUFHLEVBQUUsQ0FBQztJQUNuQyxPQUFPLElBQUk7RUFDWixDQUFDO0VBRUQ7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDQ2EsTUFBTSxFQUFFLFNBQVJBLE1BQU1BLENBQVd2QixJQUFJLEVBQUU7SUFDdEIsT0FBUSxJQUFJSyxNQUFNLENBQUMsYUFBYSxHQUM3QkMsa0JBQWtCLENBQUNOLElBQUksQ0FBQyxDQUFDSSxPQUFPLENBQUMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxHQUN2RCxTQUFTLENBQUMsQ0FBRVUsSUFBSSxDQUFDWixRQUFRLENBQUNDLE1BQU0sQ0FBQztFQUNyQztBQUNELENBQUMiLCJpZ25vcmVMaXN0IjpbXX0=\n//# sourceURL=webpack-internal:///../assets/src/scripts/utils/cookies.js\n\n}")},"../assets/src/scripts/utils/jwt.js"(module){eval("{module.exports = {\n /**\n * @summary. Parses and decodes a JSON web token (JWT).\n *\n * @param {string} sKey - The token string\n * \n * @return {object} The parsed token as JSON\n */\n parse: function parse(token) {\n var base64Url = token.split('.')[1];\n var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');\n var jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\n }).join(''));\n return JSON.parse(jsonPayload);\n }\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3V0aWxzL2p3dC5qcyIsIm5hbWVzIjpbIm1vZHVsZSIsImV4cG9ydHMiLCJwYXJzZSIsInRva2VuIiwiYmFzZTY0VXJsIiwic3BsaXQiLCJiYXNlNjQiLCJyZXBsYWNlIiwianNvblBheWxvYWQiLCJkZWNvZGVVUklDb21wb25lbnQiLCJ3aW5kb3ciLCJhdG9iIiwibWFwIiwiYyIsImNoYXJDb2RlQXQiLCJ0b1N0cmluZyIsInNsaWNlIiwiam9pbiIsIkpTT04iXSwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3V0aWxzL2p3dC5qcz85NzMwIl0sInNvdXJjZXNDb250ZW50IjpbIm1vZHVsZS5leHBvcnRzID0ge1xuXHQvKipcblx0ICogQHN1bW1hcnkuIFBhcnNlcyBhbmQgZGVjb2RlcyBhIEpTT04gd2ViIHRva2VuIChKV1QpLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gc0tleSAtIFRoZSB0b2tlbiBzdHJpbmdcblx0ICogXG5cdCAqIEByZXR1cm4ge29iamVjdH0gVGhlIHBhcnNlZCB0b2tlbiBhcyBKU09OXG5cdCAqL1xuXHRwYXJzZTogZnVuY3Rpb24gKHRva2VuKSB7XG5cdFx0bGV0IGJhc2U2NFVybCA9IHRva2VuLnNwbGl0KCcuJylbMV07XG5cdFx0bGV0IGJhc2U2NCA9IGJhc2U2NFVybC5yZXBsYWNlKC8tL2csICcrJykucmVwbGFjZSgvXy9nLCAnLycpO1xuXHRcdGxldCBqc29uUGF5bG9hZCA9IGRlY29kZVVSSUNvbXBvbmVudCh3aW5kb3cuYXRvYihiYXNlNjQpLnNwbGl0KCcnKS5tYXAoZnVuY3Rpb24oYykge1xuXHRcdFx0cmV0dXJuICclJyArICgnMDAnICsgYy5jaGFyQ29kZUF0KDApLnRvU3RyaW5nKDE2KSkuc2xpY2UoLTIpO1xuXHRcdH0pLmpvaW4oJycpKTtcblxuXHRcdHJldHVybiBKU09OLnBhcnNlKGpzb25QYXlsb2FkKTtcblx0fVxufTsiXSwibWFwcGluZ3MiOiJBQUFBQSxNQUFNLENBQUNDLE9BQU8sR0FBRztFQUNoQjtBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNDQyxLQUFLLEVBQUUsU0FBUEEsS0FBS0EsQ0FBWUMsS0FBSyxFQUFFO0lBQ3ZCLElBQUlDLFNBQVMsR0FBR0QsS0FBSyxDQUFDRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ25DLElBQUlDLE1BQU0sR0FBR0YsU0FBUyxDQUFDRyxPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDQSxPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQztJQUM1RCxJQUFJQyxXQUFXLEdBQUdDLGtCQUFrQixDQUFDQyxNQUFNLENBQUNDLElBQUksQ0FBQ0wsTUFBTSxDQUFDLENBQUNELEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQ08sR0FBRyxDQUFDLFVBQVNDLENBQUMsRUFBRTtNQUNsRixPQUFPLEdBQUcsR0FBRyxDQUFDLElBQUksR0FBR0EsQ0FBQyxDQUFDQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUNDLFFBQVEsQ0FBQyxFQUFFLENBQUMsRUFBRUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdELENBQUMsQ0FBQyxDQUFDQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFWixPQUFPQyxJQUFJLENBQUNoQixLQUFLLENBQUNNLFdBQVcsQ0FBQztFQUMvQjtBQUNELENBQUMiLCJpZ25vcmVMaXN0IjpbXX0=\n//# sourceURL=webpack-internal:///../assets/src/scripts/utils/jwt.js\n\n}")},"./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _arrayLikeToArray)\n/* harmony export */ });\nfunction _arrayLikeToArray(r, a) {\n (null == a || a > r.length) && (a = r.length);\n for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];\n return n;\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vYXJyYXlMaWtlVG9BcnJheS5qcyIsIm1hcHBpbmdzIjoiOzs7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vYXJyYXlMaWtlVG9BcnJheS5qcz9hM
1DM4Il0sInNvdXJjZXNDb250ZW50IjpbImZ1bmN0aW9uIF9hcnJheUxpa2VUb0FycmF5KHIsIGEpIHtcbiAgKG51bGwgPT0gYSB8fCBhID4gci5sZW5ndGgpICYmIChhID0gci5sZW5ndGgpO1xuICBmb3IgKHZhciBlID0gMCwgbiA9IEFycmF5KGEpOyBlIDwgYTsgZSsrKSBuW2VdID0gcltlXTtcbiAgcmV0dXJuIG47XG59XG5leHBvcnQgeyBfYXJyYXlMaWtlVG9BcnJheSBhcyBkZWZhdWx0IH07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _arrayWithoutHoles)\n/* harmony export */ });\n/* harmony import */ var _arrayLikeToArray_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./arrayLikeToArray.js */ "./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js");\n\nfunction _arrayWithoutHoles(r) {\n if (Array.isArray(r)) return (0,_arrayLikeToArray_js__WEBPACK_IMPORTED_MODULE_0__["default"])(r);\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vYXJyYXlXaXRob3V0SG9sZXMuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vYXJyYXlXaXRob3V0SG9sZXMuanM/YmIyOSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXJyYXlMaWtlVG9BcnJheSBmcm9tIFwiLi9hcnJheUxpa2VUb0FycmF5LmpzXCI7XG5mdW5jdGlvbiBfYXJyYXlXaXRob3V0SG9sZXMocikge1xuICBpZiAoQXJyYXkuaXNBcnJheShyKSkgcmV0dXJuIGFycmF5TGlrZVRvQXJyYXkocik7XG59XG5leHBvcnQgeyBfYXJyYXlXaXRob3V0SG9sZXMgYXMgZGVmYXVsdCB9OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/classCallCheck.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _classCallCheck)\n/* harmony export */ });\nfunction _classCallCheck(a, n) {\n if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vY2xhc3NDYWxsQ2hlY2suanMiLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ0E7QUFDQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vY2xhc3NDYWxsQ2hlY2suanM/Njk1MiJdLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBfY2xhc3NDYWxsQ2hlY2soYSwgbikge1xuICBpZiAoIShhIGluc3RhbmNlb2YgbikpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb25cIik7XG59XG5leHBvcnQgeyBfY2xhc3NDYWxsQ2hlY2sgYXMgZGVmYXVsdCB9OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/classCallCheck.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/createClass.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _createClass)\n/* harmony export */ });\n/* harmony import */ var _toPropertyKey_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./toPropertyKey.js */ "./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js");\n\nfunction _defineProperties(e, r) {\n for (var t = 0; t < r.length; t++) {\n var o = r[t];\n o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, (0,_toPropertyKey_js__WEBPACK_IMPORTED_MODULE_0__["default"])(o.key), o);\n }\n}\nfunction _createClass(e, r, t) {\n return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {\n writable: !1\n }), e;\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vY3JlYXRlQ2xhc3MuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL2NyZWF0ZUNsYXNzLmpzPzlhMzYiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHRvUHJv
1cGVydHlLZXkgZnJvbSBcIi4vdG9Qcm9wZXJ0eUtleS5qc1wiO1xuZnVuY3Rpb24gX2RlZmluZVByb3BlcnRpZXMoZSwgcikge1xuICBmb3IgKHZhciB0ID0gMDsgdCA8IHIubGVuZ3RoOyB0KyspIHtcbiAgICB2YXIgbyA9IHJbdF07XG4gICAgby5lbnVtZXJhYmxlID0gby5lbnVtZXJhYmxlIHx8ICExLCBvLmNvbmZpZ3VyYWJsZSA9ICEwLCBcInZhbHVlXCIgaW4gbyAmJiAoby53cml0YWJsZSA9ICEwKSwgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIHRvUHJvcGVydHlLZXkoby5rZXkpLCBvKTtcbiAgfVxufVxuZnVuY3Rpb24gX2NyZWF0ZUNsYXNzKGUsIHIsIHQpIHtcbiAgcmV0dXJuIHIgJiYgX2RlZmluZVByb3BlcnRpZXMoZS5wcm90b3R5cGUsIHIpLCB0ICYmIF9kZWZpbmVQcm9wZXJ0aWVzKGUsIHQpLCBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgXCJwcm90b3R5cGVcIiwge1xuICAgIHdyaXRhYmxlOiAhMVxuICB9KSwgZTtcbn1cbmV4cG9ydCB7IF9jcmVhdGVDbGFzcyBhcyBkZWZhdWx0IH07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/createClass.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/defineProperty.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _defineProperty)\n/* harmony export */ });\n/* harmony import */ var _toPropertyKey_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./toPropertyKey.js */ "./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js");\n\nfunction _defineProperty(e, r, t) {\n return (r = (0,_toPropertyKey_js__WEBPACK_IMPORTED_MODULE_0__["default"])(r)) in e ? Object.defineProperty(e, r, {\n value: t,\n enumerable: !0,\n configurable: !0,\n writable: !0\n }) : e[r] = t, e;\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vZGVmaW5lUHJvcGVydHkuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL2RlZmluZVByb3BlcnR5LmpzP2EyMDgiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHRvUHJvcGVydHlLZXkgZnJvbSBcIi4vdG9Qcm9wZXJ0eUtleS5qc1wiO1xuZnVuY3Rpb24gX2RlZmluZVByb3BlcnR5KGUsIHIsIHQpIHtcbiAgcmV0dXJuIChyID0gdG9Qcm9wZXJ0eUtleShyKSkgaW4gZSA/IE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCByLCB7XG4gICAgdmFsdWU6IHQsXG4gICAgZW51bWVyYWJsZTogITAsXG4gICAgY29uZmlndXJhYmxlOiAhMCxcbiAgICB3cml0YWJsZTogITBcbiAgfSkgOiBlW3JdID0gdCwgZTtcbn1cbmV4cG9ydCB7IF9kZWZpbmVQcm9wZXJ0eSBhcyBkZWZhdWx0IH07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/defineProperty.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/iterableToArray.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _iterableToArray)\n/* harmony export */ });\nfunction _iterableToArray(r) {\n if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vaXRlcmFibGVUb0FycmF5LmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL2l0ZXJhYmxlVG9BcnJheS5qcz8xZGYxIl0sInNvdXJjZXNDb250ZW50IjpbImZ1bmN0aW9uIF9pdGVyYWJsZVRvQXJyYXkocikge1xuICBpZiAoXCJ1bmRlZmluZWRcIiAhPSB0eXBlb2YgU3ltYm9sICYmIG51bGwgIT0gcltTeW1ib2wuaXRlcmF0b3JdIHx8IG51bGwgIT0gcltcIkBAaXRlcmF0b3JcIl0pIHJldHVybiBBcnJheS5mcm9tKHIpO1xufVxuZXhwb3J0IHsgX2l0ZXJhYmxlVG9BcnJheSBhcyBkZWZhdWx0IH07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/iterableToArray.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _nonIterableSpread)\n/* harmony export */ });\nfunction _nonIterableSpread() {\n throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vbm9uSXRlcmFibGVTcHJlYWQuanMiLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ0E7QUFDQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vbm9uSXRlcmFibGVTcHJlYWQuanM/MWQ4YyJdLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBfbm9uSXRlcmFibGVTcHJlYWQoKSB7XG4gIHRocm93IG5ldyBUeXBlRXJyb3IoXCJJbnZhbGlkIGF0dGVtcHQgdG8gc3ByZWFkIG5vbi1pdGVyYWJsZSBpbnN0YW5jZS5cXG5JbiBvcmRlciB0byBiZSBpdGVyYWJsZSwgbm9uLWFycmF5IG9iamVjdHMgbXVzdCBoYXZlIGEgW1N5bWJvbC5pdGVyYXRvcl0oKSBtZXRob2QuXCIpO1xufVxuZXhwb3J0IHsgX25vbkl0ZXJhYmxlU3ByZWFkIGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/toConsumableArray.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _toConsumableArray)\n/* harmony export */ });\n/* harmony import */ var _arrayWithoutHoles_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./arrayWithoutHoles.js */ "./node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js");\n/* harmony import */ var _iterableToArray_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./iterableToArray.js */ "./node_modules/@babel/runtime/helpers/esm/iterableToArray.js");\n/* harmony import */ var _unsupportedIterableToArray_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./unsupportedIterableToArray.js */ "./node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js");\n/* harmony import */ var _nonIterableSpread_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./nonIterableSpread.js */ "./node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js");\n\n\n\n\nfunction _toConsumableArray(r) {\n return (0,_arrayWithoutHoles_js__WEBPACK_IMPORTED_MODULE_0__["default"])(r) || (0,_iterableToArray_js__WEBPACK_IMPORTED_MODULE_1__["default"])(r) || (0,_unsupportedIterableToArray_js__WEBPACK_IMPORTED_MODULE_2__["default"])(r) || (0,_nonIterableSpread_js__WEBPACK_IMPORTED_MODULE_3__["default"])();\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdG9Db25zdW1hYmxlQXJyYXkuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdG9Db25zdW1hYmxlQXJyYXkuanM/NzdkZCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXJyYXlXaXRob3V0SG9sZXMgZnJvbSBcIi4vYXJyYXlXaXRob3V0SG9sZXMuanNcIjtcbmltcG9ydCBpdGVyYWJsZVRvQXJyYXkgZnJvbSBcIi4vaXRlcmFibGVUb0FycmF5LmpzXCI7XG5pbXBvcnQgdW5zdXBwb3J0ZWRJdGVyYWJsZVRvQXJyYXkgZnJvbSBcIi4vdW5zdXBwb3J0ZWRJdGVyYWJsZVRvQXJyYXkuanNcIjtcbmltcG9ydCBub25JdGVyYWJsZVNwcmVhZCBmcm9tIFwiLi9ub25JdGVyYWJsZVNwcmVhZC5qc1wiO1xuZnVuY3Rpb24gX3RvQ29uc3VtYWJsZUFycmF5KHIpIHtcbiAgcmV0dXJuIGFycmF5V2l0aG91dEhvbGVzKHIpIHx8IGl0ZXJhYmxlVG9BcnJheShyKSB8fCB1bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShyKSB8fCBub25JdGVyYWJsZVNwcmVhZCgpO1xufVxuZXhwb3J0IHsgX3RvQ29uc3VtYWJsZUFycmF5IGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/toConsumableArray.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/toPrimitive.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ toPrimitive)\n/* harmony export */ });\n/* harmony import */ var _typeof_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./typeof.js */ "./node_modules/@babel/runtime/helpers/esm/typeof.js");\n\nfunction toPrimitive(t, r) {\n if ("object" != (0,_typeof_js__WEBPACK_IMPORTED_MODULE_0__["default"])(t) || !t) return t;\n var e = t[Symbol.toPrimitive];\n if (void 0 !== e) {\n var i = e.call(t, r || "default");\n if ("object" != (0,_typeof_js__WEBPACK_IMPORTED_MODULE_0__["default"])(i)) return i;\n throw new TypeError("@@toPrimitive must return a primitive value.");\n }\n return ("string" === r ? String : Number)(t);\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdG9QcmltaXRpdmUuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZm9yZWlnbnBvbGljeS1idWlsZC8uL25vZGVfbW9kdWxlcy9AYmFiZWwvcnVudGltZS9oZWxwZXJzL2VzbS90b1ByaW1pdGl2ZS5qcz9lNWEzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfdHlwZW9mIGZyb20gXCIuL3R5cGVvZi5qc1wiO1xuZnVuY3Rpb24gdG9QcmltaXRpdmUodCwgcikge1xuICBpZiAoXCJvYmplY3RcIiAhPSBfdHlwZW9mKHQpIHx8ICF0KSByZXR1cm4gdDtcbiAgdmFyIGUgPSB0W1N5bWJvbC50b1ByaW1pdGl2ZV07XG4gIGlmICh2b2lkIDAgIT09IGUpIHtcbiAgICB2YXIgaSA9IGUuY2FsbCh0LCByIHx8IFwiZGVmYXVsdFwiKTtcbiAgICBpZiAoXCJvYmplY3RcIiAhPSBfdHlwZW9mKGkpKSByZXR1cm4gaTtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQEB0b1ByaW1pdGl2ZSBtdXN0IHJldHVybi
1BhIHByaW1pdGl2ZSB2YWx1ZS5cIik7XG4gIH1cbiAgcmV0dXJuIChcInN0cmluZ1wiID09PSByID8gU3RyaW5nIDogTnVtYmVyKSh0KTtcbn1cbmV4cG9ydCB7IHRvUHJpbWl0aXZlIGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/toPrimitive.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ toPropertyKey)\n/* harmony export */ });\n/* harmony import */ var _typeof_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./typeof.js */ "./node_modules/@babel/runtime/helpers/esm/typeof.js");\n/* harmony import */ var _toPrimitive_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./toPrimitive.js */ "./node_modules/@babel/runtime/helpers/esm/toPrimitive.js");\n\n\nfunction toPropertyKey(t) {\n var i = (0,_toPrimitive_js__WEBPACK_IMPORTED_MODULE_1__["default"])(t, "string");\n return "symbol" == (0,_typeof_js__WEBPACK_IMPORTED_MODULE_0__["default"])(i) ? i : i + "";\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdG9Qcm9wZXJ0eUtleS5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL3RvUHJvcGVydHlLZXkuanM/NGEyZCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgX3R5cGVvZiBmcm9tIFwiLi90eXBlb2YuanNcIjtcbmltcG9ydCB0b1ByaW1pdGl2ZSBmcm9tIFwiLi90b1ByaW1pdGl2ZS5qc1wiO1xuZnVuY3Rpb24gdG9Qcm9wZXJ0eUtleSh0KSB7XG4gIHZhciBpID0gdG9QcmltaXRpdmUodCwgXCJzdHJpbmdcIik7XG4gIHJldHVybiBcInN5bWJvbFwiID09IF90eXBlb2YoaSkgPyBpIDogaSArIFwiXCI7XG59XG5leHBvcnQgeyB0b1Byb3BlcnR5S2V5IGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/typeof.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _typeof)\n/* harmony export */ });\nfunction _typeof(o) {\n "@babel/helpers - typeof";\n\n return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;\n }, _typeof(o);\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdHlwZW9mLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL3R5cGVvZi5qcz80YmY1Il0sInNvdXJjZXNDb250ZW50IjpbImZ1bmN0aW9uIF90eXBlb2Yobykge1xuICBcIkBiYWJlbC9oZWxwZXJzIC0gdHlwZW9mXCI7XG5cbiAgcmV0dXJuIF90eXBlb2YgPSBcImZ1bmN0aW9uXCIgPT0gdHlwZW9mIFN5bWJvbCAmJiBcInN5bWJvbFwiID09IHR5cGVvZiBTeW1ib2wuaXRlcmF0b3IgPyBmdW5jdGlvbiAobykge1xuICAgIHJldHVybiB0eXBlb2YgbztcbiAgfSA6IGZ1bmN0aW9uIChvKSB7XG4gICAgcmV0dXJuIG8gJiYgXCJmdW5jdGlvblwiID09IHR5cGVvZiBTeW1ib2wgJiYgby5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sICYmIG8gIT09IFN5bWJvbC5wcm90b3R5cGUgPyBcInN5bWJvbFwiIDogdHlwZW9mIG87XG4gIH0sIF90eXBlb2Yobyk7XG59XG5leHBvcnQgeyBfdHlwZW9mIGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/typeof.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _unsupportedIterableToArray)\n/* harmony export */ });\n/* harmony import */ var _arrayLikeToArray_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./arrayLikeToArray.js */ "./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js");\n\nfunction _unsupportedIterableToArray(r, a) {\n if (r) {\n if ("string" == typeof r) return (0,_arrayLikeToArray_js__WEBPACK_IMPORTED_MODULE_0__["default"])(r, a);\n var t = {}.toString.call(r).slice(8, -1);\n return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? (0,_arrayLikeToArray_js__WEBPACK_IMPORTED_MODULE_0__["default"])(r, a) : void 0;\n }\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdW5zdXBwb3J0ZWRJdGVyYWJsZVRvQXJyYXkuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZm9yZWlnbnBvbGljeS1idWlsZC8uL25vZGVfbW9kdWxlcy9AYmFiZWwvcnVudGltZS9oZWxwZXJzL2VzbS91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheS5qcz9iYjdiIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhcnJheUxpa2VUb0FycmF5IGZyb20gXCIuL2FycmF5TGlrZVRvQXJyYXkuanNcIjtcbmZ1bmN0aW9uIF91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShyLCBhKSB7XG4gIGlmIChyKSB7XG4gICAgaWYgKFwic3RyaW5nXCIgPT0gdHlwZW9mIHIpIHJldHVybi
1BhcnJheUxpa2VUb0FycmF5KHIsIGEpO1xuICAgIHZhciB0ID0ge30udG9TdHJpbmcuY2FsbChyKS5zbGljZSg4LCAtMSk7XG4gICAgcmV0dXJuIFwiT2JqZWN0XCIgPT09IHQgJiYgci5jb25zdHJ1Y3RvciAmJiAodCA9IHIuY29uc3RydWN0b3IubmFtZSksIFwiTWFwXCIgPT09IHQgfHwgXCJTZXRcIiA9PT0gdCA/IEFycmF5LmZyb20ocikgOiBcIkFyZ3VtZW50c1wiID09PSB0IHx8IC9eKD86VWl8SSludCg/Ojh8MTZ8MzIpKD86Q2xhbXBlZCk/QXJyYXkkLy50ZXN0KHQpID8gYXJyYXlMaWtlVG9BcnJheShyLCBhKSA6IHZvaWQgMDtcbiAgfVxufVxuZXhwb3J0IHsgX3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5IGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js\n\n}')},"./node_modules/@rudderstack/analytics-js/dist/npm/modern/bundled/esm/index.mjs"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){"use strict";eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ RudderAnalytics: () => (/* binding */ RudderAnalytics)\n/* harmony export */ });\nfunction _isPlaceholder(a){return a!=null&&typeof a==='object'&&a['@@functional/placeholder']===true;}\n\n/**\n * Optimized internal one-arity curry function.\n *\n * @private\n * @category Function\n * @param {Function} fn The function to curry.\n * @return {Function} The curried function.\n */function _curry1(fn){return function f1(a){if(arguments.length===0||_isPlaceholder(a)){return f1;}else {return fn.apply(this,arguments);}};}\n\n/**\n * Optimized internal two-arity curry function.\n *\n * @private\n * @category Function\n * @param {Function} fn The function to curry.\n * @return {Function} The curried function.\n */function _curry2(fn){return function f2(a,b){switch(arguments.length){case 0:return f2;case 1:return _isPlaceholder(a)?f2:_curry1(function(_b){return fn(a,_b);});default:return _isPlaceholder(a)&&_isPlaceholder(b)?f2:_isPlaceholder(a)?_curry1(function(_a){return fn(_a,b);}):_isPlaceholder(b)?_curry1(function(_b){return fn(a,_b);}):fn(a,b);}};}\n\n/**\n * Optimized internal three-arity curry function.\n *\n * @private\n * @category Function\n * @param {Function} fn The function to curry.\n * @return {Function} The curried function.\n */function _curry3(fn){return function f3(a,b,c){switch(arguments.length){case 0:return f3;case 1:return _isPlaceholder(a)?f3:_curry2(function(_b,_c){return fn(a,_b,_c);});case 2:return _isPlaceholder(a)&&_isPlaceholder(b)?f3:_isPlaceholder(a)?_curry2(function(_a,_c){return fn(_a,b,_c);}):_isPlaceholder(b)?_curry2(function(_b,_c){return fn(a,_b,_c);}):_curry1(function(_c){return fn(a,b,_c);});default:return _isPlaceholder(a)&&_isPlaceholder(b)&&_isPlaceholder(c)?f3:_isPlaceholder(a)&&_isPlaceholder(b)?_curry2(function(_a,_b){return fn(_a,_b,c);}):_isPlaceholder(a)&&_isPlaceholder(c)?_curry2(function(_a,_c){return fn(_a,b,_c);}):_isPlaceholder(b)&&_isPlaceholder(c)?_curry2(function(_b,_c){return fn(a,_b,_c);}):_isPlaceholder(a)?_curry1(function(_a){return fn(_a,b,c);}):_isPlaceholder(b)?_curry1(function(_b){return fn(a,_b,c);}):_isPlaceholder(c)?_curry1(function(_c){return fn(a,b,_c);}):fn(a,b,c);}};}\n\nfunction _has(prop,obj){return Object.prototype.hasOwnProperty.call(obj,prop);}\n\n/**\n * Gives a single-word string description of the (native) type of a value,\n * returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not\n * attempt to distinguish user Object types any further, reporting them all as\n * 'Object'.\n *\n * @func\n * @memberOf R\n * @since v0.8.0\n * @category Type\n * @sig * -> String\n * @param {*} val The value to test\n * @return {String}\n * @example\n *\n * R.type({}); //=> \"Object\"\n * R.type(new Map); //=> \"Map\"\n * R.type(new Set); //=> \"Set\"\n * R.type(1); //=> \"Number\"\n * R.type(false); //=> \"Boolean\"\n * R.type('s'); //=> \"String\"\n * R.type(null); //=> \"Null\"\n * R.type([]); //=> \"Array\"\n * R.type(/[A-z]/); //=> \"RegExp\"\n * R.type(() => {}); //=> \"Function\"\n * R.type(async () => {}); //=> \"AsyncFunction\"\n * R.type(undefined); //=> \"Undefined\"\n * R.type(BigInt(123)); //=> \"BigInt\"\n */var type=/*#__PURE__*/_curry1(function type(val){return val===null?'Null':val===undefined?'Undefined':Object.prototype.toString.call(val).slice(8,-1);});\n\nfunction _isObject(x){return Object.prototype.toString.call(x)==='[object Object]';}\n\n/**\n * Determine if the passed argument is an integer.\n *\n * @private\n * @param {*} n\n * @category Type\n * @return {Boolean}\n */const _isInteger = Number.isInteger||function _isInteger(n){return n<<0===n;};\n\nfunction _nth(offset,list){var idx=offset<0?list.length+offset:offset;return list[idx];}\n\nfunction _cloneRegExp(pattern){return new RegExp(pattern.source,pattern.flags?pattern.flags:(pattern.global?'g':'')+(pattern.ignoreCase?'i':'')+(pattern.multiline?'m':'')+(pattern.sticky?'y':'')+(pattern.unicode?'u':'')+(pattern.dotAll?'s':''));}\n\n/**\n * Copies an object.\n *\n * @private\n * @param {*} value The value to be copied\n * @param {Boolean} deep Whether or not to perform deep cloning.\n * @return {*} The copied value.\n */function _clone(value,deep,map){map||(map=new _ObjectMap());// this avoids the slower switch with a quick if decision removing some milliseconds in each run.\nif(_isPrimitive(value)){return value;}
1var copy=function copy(copiedValue){// Check for circular and same references on the object graph and return its corresponding clone.\nvar cachedCopy=map.get(value);if(cachedCopy){return cachedCopy;}map.set(value,copiedValue);for(var key in value){if(Object.prototype.hasOwnProperty.call(value,key)){copiedValue[key]=_clone(value[key],true,map);}}return copiedValue;};switch(type(value)){case 'Object':return copy(Object.create(Object.getPrototypeOf(value)));case 'Array':return copy(Array(value.length));case 'Date':return new Date(value.valueOf());case 'RegExp':return _cloneRegExp(value);case 'Int8Array':case 'Uint8Array':case 'Uint8ClampedArray':case 'Int16Array':case 'Uint16Array':case 'Int32Array':case 'Uint32Array':case 'Float32Array':case 'Float64Array':case 'BigInt64Array':case 'BigUint64Array':return value.slice();default:return value;}}function _isPrimitive(param){var type=typeof param;return param==null||type!='object'&&type!='function';}var _ObjectMap=/*#__PURE__*/function(){function _ObjectMap(){this.map={};this.length=0;}_ObjectMap.prototype.set=function(key,value){var hashedKey=this.hash(key);var bucket=this.map[hashedKey];if(!bucket){this.map[hashedKey]=bucket=[];}bucket.push([key,value]);this.length+=1;};_ObjectMap.prototype.hash=function(key){var hashedKey=[];for(var value in key){hashedKey.push(Object.prototype.toString.call(key[value]));}return hashedKey.join();};_ObjectMap.prototype.get=function(key){/**\n * depending on the number of objects to be cloned is faster to just iterate over the items in the map just because the hash function is so costly,\n * on my tests this number is 180, anything above that using the hash function is faster.\n */if(this.length<=180){for(var p in this.map){var bucket=this.map[p];for(var i=0;i<bucket.length;i+=1){var element=bucket[i];if(element[0]===key){return element[1];}}}return;}var hashedKey=this.hash(key);var bucket=this.map[hashedKey];if(!bucket){return;}for(var i=0;i<bucket.length;i+=1){var element=bucket[i];if(element[0]===key){return element[1];}}};return _ObjectMap;}();\n\n/**\n * Creates a deep copy of the source that can be used in place of the source\n * object without retaining any references to it.\n * The source object may contain (nested) `Array`s and `Object`s,\n * `Number`s, `String`s, `Boolean`s and `Date`s.\n * `Function`s are assigned by reference rather than copied.\n *\n * Dispatches to a `clone` method if present.\n *\n * Note that if the source object has multiple nodes that share a reference,\n * the returned object will have the same structure, but the references will\n * be pointed to the location within the cloned value.\n *\n * @func\n * @memberOf R\n * @since v0.1.0\n * @category Object\n * @sig {*} -> {*}\n * @param {*} value The object or array to clone\n * @return {*} A deeply cloned copy of `val`\n * @example\n *\n * const objects = [{}, {}, {}];\n * const objectsClone = R.clone(objects);\n * objects === objectsClone; //=> false\n * objects[0] === objectsClone[0]; //=> false\n */var clone=/*#__PURE__*/_curry1(function clone(value){return value!=null&&typeof value.clone==='function'?value.clone():_clone(value);});\n\nfunction _path(pathAr,obj){var val=obj;for(var i=0;i<pathAr.length;i+=1){if(val==null){return undefined;}var p=pathAr[i];if(_isInteger(p)){val=_nth(p,val);}else {val=val[p];}}return val;}\n\n/**\n * Creates a new object with the own properties of the two provided objects. If\n * a key exists in both objects, the provided function is applied to the key\n * and the values associated with the key in each object, with the result being\n * used as the value associated with the key in the returned object.\n *\n * @func\n * @memberOf R\n * @since v0.19.0\n * @category Object\n * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}\n * @param {Function} fn\n * @param {Object} l\n * @param {Object} r\n * @return {Object}\n * @see R.mergeDeepWithKey, R.mergeWith\n * @example\n *\n * let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r\n * R.mergeWithKey(concatValues,\n * { a: true, thing: 'foo', values: [10, 20] },\n * { b: true, thing: 'bar', values: [15, 35] });\n * //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] }\n * @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 }\n */var mergeWithKey=/*#__PURE__*/_curry3(function mergeWithKey(fn,l,r){var result={};var k;l=l||{};r=r||{};for(k in l){if(_has(k,l)){result[k]=_has(k,r)?fn(k,l[k],r[k]):l[k];}}for(k in r){if(_has(k,r)&&!_has(k,result)){result[k]=r[k];}}return result;});\n\n/**\n * Creates a new object with the own properties of the two provided objects.\n * If a key exists in both objects:\n * - and both associated values are also objects then the values will be\n * recursively merged.\n * - otherwise the provided function is applied to the key and associated values\n * using the resulting value as the new value associated with the key.\n * If a key only exists in one object, the value will be associated with the key\n * of the resulting object.\n *\n * @func\n * @memberOf R\n * @since v0.24.0\n * @category Object\n * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}\n * @param {Function} fn\n * @param {Object} lObj\n * @param {Object} rObj\n * @return {Object}\n * @see R.mergeWithKey, R.mergeDeepWith\n * @example\n *\n * let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r\n * R.mergeDeepWithKey(concatValues,\n * { a: true, c: { thing: 'foo', values: [10, 20] }},\n * { b: true, c: { thing: 'bar', values: [15, 35] }});\n * //=> { a: true, b: true, c: { thing: 'bar', values: [10, 20, 15, 35] }}\n */var mergeDeepWithKey=/*#__PURE__*/_curry3(function mergeDeepWithKey(fn,lObj,rObj){return mergeWithKey(function(k,lV
1al,rVal){if(_isObject(lVal)&&_isObject(rVal)){return mergeDeepWithKey(fn,lVal,rVal);}else {return fn(k,lVal,rVal);}},lObj,rObj);});\n\n/**\n * Creates a new object with the own properties of the two provided objects.\n * If a key exists in both objects:\n * - and both associated values are also objects then the values will be\n * recursively merged.\n * - otherwise the provided function is applied to associated values using the\n * resulting value as the new value associated with the key.\n * If a key only exists in one object, the value will be associated with the key\n * of the resulting object.\n *\n * @func\n * @memberOf R\n * @since v0.24.0\n * @category Object\n * @sig ((a, a) -> a) -> {a} -> {a} -> {a}\n * @param {Function} fn\n * @param {Object} lObj\n * @param {Object} rObj\n * @return {Object}\n * @see R.mergeWith, R.mergeDeepWithKey\n * @example\n *\n * R.mergeDeepWith(R.concat,\n * { a: true, c: { values: [10, 20] }},\n * { b: true, c: { values: [15, 35] }});\n * //=> { a: true, b: true, c: { values: [10, 20, 15, 35] }}\n */var mergeDeepWith=/*#__PURE__*/_curry3(function mergeDeepWith(fn,lObj,rObj){return mergeDeepWithKey(function(k,lVal,rVal){return fn(lVal,rVal);},lObj,rObj);});\n\n/**\n * Retrieves the value at a given path. The nodes of the path can be arbitrary strings or non-negative integers.\n * For anything else, the value is unspecified. Integer paths are meant to index arrays, strings are meant for objects.\n *\n * @func\n * @memberOf R\n * @since v0.2.0\n * @category Object\n * @typedefn Idx = String | Int | Symbol\n * @sig [Idx] -> {a} -> a | Undefined\n * @sig Idx = String | NonNegativeInt\n * @param {Array} path The path to use.\n * @param {Object} obj The object or array to retrieve the nested property from.\n * @return {*} The data at `path`.\n * @see R.prop, R.nth, R.assocPath, R.dissocPath\n * @example\n *\n * R.path(['a', 'b'], {a: {b: 2}}); //=> 2\n * R.path(['a', 'b'], {c: {b: 2}}); //=> undefined\n * R.path(['a', 'b', 0], {a: {b: [1, 2, 3]}}); //=> 1\n * R.path(['a', 'b', -2], {a: {b: [1, 2, 3]}}); //=> 2\n * R.path([2], {'2': 2}); //=> 2\n * R.path([-2], {'-2': 'a'}); //=> undefined\n */var path=/*#__PURE__*/_curry2(_path);\n\n/**\n * Returns a partial copy of an object containing only the keys that satisfy\n * the supplied predicate.\n *\n * @func\n * @memberOf R\n * @since v0.8.0\n * @category Object\n * @sig ((v, k) -> Boolean) -> {k: v} -> {k: v}\n * @param {Function} pred A predicate to determine whether or not a key\n * should be included on the output object.\n * @param {Object} obj The object to copy from\n * @return {Object} A new object with only properties that satisfy `pred`\n * on it.\n * @see R.pick, R.filter\n * @example\n *\n * const isUpperCase = (val, key) => key.toUpperCase() === key;\n * R.pickBy(isUpperCase, {a: 1, b: 2, A: 3, B: 4}); //=> {A: 3, B: 4}\n */var pickBy=/*#__PURE__*/_curry2(function pickBy(test,obj){var result={};for(var prop in obj){if(test(obj[prop],prop,obj)){result[prop]=obj[prop];}}return result;});\n\n/**\n * A function to check given value is a function\n * @param value input value\n * @returns boolean\n */const isFunction=value=>typeof value==='function'&&Boolean(value.constructor&&value.call&&value.apply);/**\n * A function to check given value is a string\n * @param value input value\n * @returns boolean\n */const isString=value=>typeof value==='string';/**\n * A function to check given value is null or not\n * @param value input value\n * @returns boolean\n */const isNull=value=>value===null;/**\n * A function to check given value is undefined\n * @param value input value\n * @returns boolean\n */const isUndefined=value=>typeof value==='undefined';/**\n * A function to check given value is null or undefined\n * @param value input value\n * @returns boolean\n */const isNullOrUndefined=value=>isNull(value)||isUndefined(value);/**\n * Checks if the input is a BigInt\n * @param value input value\n * @returns True if the input is a BigInt\n */const isBigInt=value=>typeof value==='bigint';/**\n * A function to check given value is defined\n * @param value input value\n * @returns boolean\n */const isDefined=value=>!isUndefined(value);/**\n * A function to check given value is defined and not null\
1n * @param value input value\n * @returns boolean\n */const isDefinedAndNotNull=value=>!isNullOrUndefined(value);/**\n * A function to check given value is defined and not null\n * @param value input value\n * @returns boolean\n */const isDefinedNotNullAndNotEmptyString=value=>isDefinedAndNotNull(value)&&value!=='';/**\n * Determines if the input is of type error\n * @param value input value\n * @returns true if the input is of type error else false\n */const isTypeOfError=value=>{switch(Object.prototype.toString.call(value)){case '[object Error]':case '[object Exception]':case '[object DOMException]':return true;default:return value instanceof Error;}};/**\n * A function to check given value is a boolean\n * @param value input value\n * @returns boolean\n */const isBoolean=value=>typeof value==='boolean';\n\nconst getValueByPath=(obj,keyPath)=>{const pathParts=keyPath.split('.');return path(pathParts,obj);};const hasValueByPath=(obj,path)=>Boolean(getValueByPath(obj,path));const isObject=value=>typeof value==='object';/**\n * Checks if the input is an object literal or built-in object type and n
1ot null\n * @param value Input value\n * @returns true if the input is an object and not null\n */const isObjectAndNotNull=value=>!isNull(value)&&isObject(value)&&!Array.isArray(value);/**\n * Checks if the input is an object literal and not null\n * @param value Input value\n * @returns true if the input is an object and not null\n */const isObjectLiteralAndNotNull=value=>!isNull(value)&&Object.prototype.toString.call(value)==='[object Object]';/**\n * Merges two arrays deeply, right-to-left\n * In the case of conflicts, the right array's values replace the left array's values in the\n * same index position\n * @param leftValue - The left array\n * @param rightValue - The right array\n * @returns The merged array\n */const mergeDeepRightObjectArrays=(leftValue,rightValue)=>{if(!Array.isArray(leftValue)||!Array.isArray(rightValue)){return clone(rightValue);}const mergedArray=clone(leftValue);rightValue.forEach((value,index)=>{mergedArray[index]=Array.isArray(value)||isObjectAndNotNull(value)?// eslint-disable-next-line @typescript-eslint/no-use-before-define\nmergeDeepRight(mergedArray[index],value):value;});return mergedArray;};/**\n * Merges two objects deeply, right-to-left.\n * In the case of conflicts, the right object's values take precedence.\n * For arrays, the right array's values replace the left array's values in the\n * same index position keeping the remaining left array's values in the resultant array.\n * @param leftObject - The left object\n * @param rightObject - The right object\n * @returns The merged object\n */const mergeDeepRight=(leftObject,rightObject)=>mergeDeepWith(mergeDeepRightObjectArrays,leftObject,rightObject);/**\n Checks if the input is a non-empty object literal type and not undefined or null\n * @param value input any\n * @returns boolean\n */const isNonEmptyObject=value=>isObjectLiteralAndNotNull(value)&&Object.keys(value).length>0;/**\n * A utility to recursively remove undefined values from an object\n * @param obj input object\n * @returns a new object\n */const removeUndefinedValues=obj=>{const result=pickBy(isDefined,obj);Object.keys(result).forEach(key=>{const value=result[key];if(isObjectLiteralAndNotNull(value)){result[key]=removeUndefinedValues(value);}});return result;};/**\n * A utility to recursively remove undefined and null values from an object\n * @param obj input object\n * @returns a new object\n */const removeUndefinedAndNullValues=obj=>{const result=pickBy(isDefinedAndNotNull,obj);Object.keys(result).forEach(key=>{const value=result[key];if(isObjectLiteralAndNotNull(value)){result[key]=removeUndefinedAndNullValues(value);}});return result;};/**\n * Normalizes an object by removing undefined and null values.\
1n * @param val - The value to normalize\n * @returns The normalized object, or undefined if input is not a non-empty object\n * @example\n * getNormalizedObjectValue({ a: 1, b: null, c: undefined }) // returns { a: 1 }\n * getNormalizedObjectValue({}) // returns undefined\n * getNormalizedObjectValue(null) // returns undefined\n */const getNormalizedObjectValue=val=>{if(!isNonEmptyObject(val)){return undefined;}return removeUndefinedAndNullValues(val);};/**\n * Normalizes a value to a boolean, with support for a default value\n * @param val Input value\n * @param defVal Default value\n * @returns Returns the input value if it is a boolean, otherwise returns the default value\n * @example\n * getNormalizedBooleanValue(true, false) // returns true\n */const getNormalizedBooleanValue=(val,defVal)=>typeof val==='boolean'?val:defVal;const deepFreeze=obj=>{Object.getOwnPropertyNames(obj).forEach(function(prop){if(obj[prop]&&typeof obj[prop]==='object'){deepFreeze(obj[prop]);}});return Object.freeze(obj);};\n\nconst trim=value=>value.replace(/^\\s+|\\s+$/gm,'');
1const removeLeadingPeriod=value=>value.replace(/^\\.+/,'');/**\n * A function to convert values to string\n * @param val input value\n * @returns stringified value\n */const tryStringify=val=>{let retVal=val;if(!isString(val)&&!isNullOrUndefined(val)){try{retVal=JSON.stringify(val);}catch(e){retVal=null;}}return retVal;};// The following text encoding and decoding is done before base64 encoding to prevent\n// https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem\n/**\n * Converts a base64 encoded string to bytes array\n * @param base64Str base64 encoded string\n * @returns bytes array\n */const base64ToBytes=base64Str=>{const binString=globalThis.atob(base64Str);const bytes=binString.split('').map(char=>char.charCodeAt(0));return new Uint8Array(bytes);};/**\n * Converts a bytes array to base64 encoded string\n * @param bytes bytes array to be converted to base64\n * @returns base64 encoded string\n */const bytesToBase64=bytes=>{const binString=Array.from(bytes,x=>String.fromCodePoint(x)).join('');return globalThis.btoa(binString);};/**\n * Encodes a string to base64 even with unicode characters\n * @param value input string\n * @returns base64 encoded string\n */const toBase64=value=>bytesToBase64(new TextEncoder().encode(value));/**\n * Decodes a base64 encoded string\n * @param value base64 encoded string\n * @returns decoded string\n */const fromBase64=value=>new TextDecoder().decode(base64ToBytes(value));\n\n// if yes make them null instead of omitting in overloaded cases\n/*\n * Normalise the overloaded arguments of the page call facade\n */const pageArgumentsToCallOptions=(category,name,properties,options,callback)=>{const payload={category:category,name:name,properties:properties,options:options,callback:undefined};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.category=category;payload.name=name;payload.properties=properties;payload.options=undefined;payload.callback=options;}if(isFunction(properties)){payload.category=category;payload.name=name;payload.properties=undefined;payload.options=undefined;payload.callback=properties;}if(isFunction(name)){payload.category=category;payload.name=undefined;payload.properties=undefined;payload.options=undefined;payload.callback=name;}if(isFunction(category)){payload.category=undefined;payload.name=undefined;payload.properties=undefined;payload.options=undefined;payload.callback=category;}if(isObjectLiteralAndNotNull(category)){payload.name=undefined;payload.category=undefined;payload.properties=category;if(!isFunction(name)){payload.options=name;}else {payload.options=undefined;}}else if(isObjectLiteralAndNotNull(name)){payload.name=undefined;payload.properties=name;if(!isFunction(properties)){payload.options=properties;}else {payload.options=undefined;}}// if the category argument alone is provided b/w category and name,\n// use it as name and set category to undefined\nif(isString(category)&&!isString(name)){payload.category=undefined;payload.name=category;}// Rest of the code is just to clean up undefined values\n// and set some proper defaults\n// Also, to clone the incoming object type arguments\nif(!isDefined(payload.category)){payload.category=undefined;}if(!isDefined(payload.name)){payload.name=undefined;}payload.properties=payload.properties?clone(payload.properties):{};if(isDefined(payload.options)){payload.options=clone(payload.options);}else {payload.options=undefined;}const nameForProperties=isString(payload.name)?payload.name:payload.properties.name;const categoryForProperties=isString(payload.category)?payload.category:payload.properties.category;// add name and category to properties\npayload.properties=mergeDeepRight(isObjectLiteralAndNotNull(payload.properties)?payload.properties:{},{...(nameForProperties&&{name:nameForProperties}),...(categoryForProperties&&{category:categoryForProperties})});return payload;};/*\n * Normalise the overloaded arguments of the track call facade\n */const trackArgumentsToCallOptions=(event,properties,options,callback)=>{const payload={name:event,properties:properties,options:options,callback:undefined};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.properties=properties;payload.options=undefined;payload.callback=options;}if(isFunction(properties)){payload.properties=undefined;payload.options=undefined;payload.callback=properties;}// Rest of the code is just to clean up undefined values\n// and set some proper defaults\n// Also, to clone the incoming object type arguments\npayload.properties=isDefinedAndNotNull(payload.properties)?clone(payload.properties):{};if(isDefined(payload.options)){payload.options=clone(payload.options);}else {payload.options=undefined;}return payload;};/*\n * Normalise the overloaded arguments of the identify call facade\n */const identifyArgumentsToCallOptions=(userId,traits,options,callback)=>{const payload={userId:userId,traits:traits,options:options,callback:undefined};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.userId=userId;payload.traits=traits;payload.options=undefined;payload.callback=options;}if(isFunction(traits)){payload.userId=userId;payload.traits=undefined;payload.options=undefined;payload.callback=traits;}if(isObjectLiteralAndNotNull(userId)||isNull(userId)){// Explicitly set null to prevent resetting the existing value\n// in the Analytics class\npayload.userId=null;payload.traits=userId;if(!isFunction(traits)){payload.options=traits;}else {payload.options=undefined;}}// Rest of the code is just to clean up undefined values\n// and set some proper defaults\n// Also, to clone the incoming object type arguments\npayload.userId=tryStringify(payload.userId);if(isObjectLiteralAndNotNull(payload.traits)){payload.traits=clone(payload.traits);}else {payload.traits=undefined;}if(isDefined(payload.options)){payload.options=clone(payload.options);}else {payload.options=undefined;}return payload;};/*\n * Normalise the overloaded arguments of the alias call facade\n */const al
1iasArgumentsToCallOptions=(to,from,options,callback)=>{const payload={to,from:from,options:options,callback:undefined};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.to=to;payload.from=from;payload.options=undefined;payload.callback=options;}if(isFunction(from)){payload.to=to;payload.from=undefined;payload.options=undefined;payload.callback=from;}else if(isObjectLiteralAndNotNull(from)||isNull(from)){payload.to=to;payload.from=undefined;payload.options=from;}// Rest of the code is just to clean up undefined values\n// and set some proper defaults\n// Also, to clone the incoming object type arguments\nif(isDefined(payload.to)){payload.to=tryStringify(payload.to);}if(isDefined(payload.from)){payload.from=tryStringify(payload.from);}else {payload.from=undefined;}if(isDefined(payload.options)){payload.options=clone(payload.options);}else {payload.options=undefined;}return payload;};/*\n * Normalise the overloaded arguments of the group call facade\n */const groupArgumentsToCallOptions=(groupId,traits,options,callback)=>{const payload={groupId:groupId,traits:traits,options:options,callback:undefined};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.groupId=groupId;payload.traits=traits;payload.options=undefined;payload.callback=options;}if(isFunction(traits)){payload.groupId=groupId;payload.traits=undefined;payload.options=undefined;payload.callback=traits;}if(isObjectLiteralAndNotNull(groupId)||isNull(groupId)){// Explicitly set null to prevent resetting the existing value\n// in the Analytics class\npayload.groupId=null;payload.traits=groupId;if(!isFunction(traits)){payload.options=traits;}else {payload.options=undefined;}}// Rest of the code is just to clean up undefined values\n// and set some proper defaults\n// Also, to clone the incoming object type arguments\npayload.groupId=tryStringify(payload.groupId);if(isObjectLiteralAndNotNull(payload.traits)){payload.traits=clone(payload.traits);}else {payload.traits=undefined;}if(isDefined(payload.options)){payload.options=clone(payload.options);}else {payload.options=undefined;}return payload;};\n\n/**\n * Represents the options parameter for anonymousId\n *//**\n * Represents the beacon queue options parameter in loadOptions type\n *//**\n * Represents the queue options parameter in loadOptions type\n *//**\n * Represents the destinations queue options parameter in loadOptions type\n */let PageLifecycleEvents=/*#__PURE__*/function(PageLifecycleEvents){PageLifecycleEvents[\"UNLOADED\"]=\"Page Unloaded\";return PageLifecycleEvents;}({});/**\n * Represents the source configuration override options for destinations\n *//**\n * Represents the options parameter in the load API\n */\n\nconst API_SUFFIX='API';const CAPABILITIES_MANAGER='CapabilitiesManager';const CONFIG_MANAGER='ConfigManager';const EVENT_MANAGER='EventManager';const PLUGINS_MANAGER='PluginsManager';const USER_SESSION_MANAGER='UserSessionManager';const ERROR_HANDLER='ErrorHandler';const PLUGIN_ENGINE='PluginEngine';const STORE_MANAGER='StoreManager';const READY_API=`Ready${API_SUFFIX}`;const LOAD_API=`Load${API_SUFFIX}`;const HTTP_CLIENT='HttpClient';const RSA='RudderStackAnalytics';const ANALYTICS_CORE='AnalyticsCore';\n\nfunction random(len){return crypto.getRandomValues(new Uint8Array(len));}\n\nvar SIZE=4096,HEX$1=[],IDX$1=0,BUFFER$1;for(;IDX$1<256;IDX$1++){HEX$1[IDX$1]=(IDX$1+256).toString(16).substring(1);}function v4$1(){if(!BUFFER$1||IDX$1+16>SIZE){BUFFER$1=random(SIZE);IDX$1=0;}var i=0,tmp,out='';for(;i<16;i++){tmp=BUFFER$1[IDX$1+i];if(i==6)out+=HEX$1[tmp&15|64];else if(i==8)out+=HEX$1[tmp&63|128];else out+=HEX$1[tmp];if(i&1&&i>1&&i<11)out+='-';}IDX$1+=16;return out;}\n\nvar IDX=256,HEX=[],BUFFER;while(IDX--)HEX[IDX]=(IDX+256).toString(16).substring(1);function v4(){var i=0,num,out='';if(!BUFFER||IDX+16>256){BUFFER=Array(i=256);while(i--)BUFFER[i]=256*Math.random()|0;i=IDX=0;}for(;i<16;i++){num=BUFFER[IDX+i];if(i==6)out+=HEX[num&15|64];else if(i==8)out+=HEX[num&63|128];else out+=HEX[num];if(i&1&&i>1&&i<11)out+='-';}IDX++;return out;}\n\nconst hasCrypto$1=()=>!isNullOrUndefined(globalThis.crypto)&&isFunction(globalThis.crypto.getRandomValues);\n\nconst generateUUID=()=>
1{if(hasCrypto$1()){return v4$1();}return v4();};\n\n/**\n * Determines if the SDK is running inside a chrome extension\n * @returns boolean\n */const isSDKRunningInChromeExtension=()=>!!window.chrome?.runtime?.id;const isIE11=()=>isString(globalThis.navigator.userAgent)&&/Trident.*rv:11\\./.test(globalThis.navigator.userAgent);\n\n/**\n * Registers events to detect page leave scenarios\n * @param callback Callback function\n * @param avoidBfCacheOptimization When `true`, forcefully subscribes to beforeunload event, compromising on the bfcache optimization\n */const onPageLeave=(callback,avoidBfCacheOptimization=false)=>{// To ensure the callback is only called once even if more than one events\n// are fired at once.\nlet pageLeft=false;let isAccessible=false;function handleOnLeave(){if(pageLeft){return;}pageLeft=true;callback(isAccessible);// Reset pageLeft on the next tick\n// to ensure callback executes for other listeners\n// when closing an inactive browser tab.\nsetTimeout(()=>{pageLeft=false;},0);}// Catches the unloading of the page (e.g., closing the tab or navigating away).\n// Includes user actions like clicking a link, entering a new URL,\n// refreshing the page, or closing the browser tab\n// Note that 'pagehide' is not supported in IE.\n// Registering this event conditionally for IE11 also because\n// it affects bfcache optimization on modern browsers otherwise.\n// However, if optimization is disabled, force subscribe the event\nif(avoidBfCacheOptimization||isIE11()){globalThis.addEventListener('beforeunload',()=>{isAccessible=false;handleOnLeave();});}// This is important for iOS Safari browser as it does not\n// fire the regular pagehide and visibilitychange events\n// when user goes to tablist view and closes the tab.\nglobalThis.addEventListener('blur',()=>{isAccessible=true;handleOnLeave();});globalThis.addEventListener('focus',()=>{pageLeft=false;});// Catches the page being hidden, including scenarios like closing the tab.\ndocument.addEventListener('pagehide',()=>{isAccessible=document.visibilityState==='hidden';handleOnLeave();});// Catches visibility changes, such as switching tabs or minimizing the browser.\ndocument.addEventListener('visibilitychange',()=>{isAccessible=true;if(document.visibilityState==='hidden'){handleOnLeave();}else {pageLeft=false;}});};\n\nconst getFormattedTimestamp=date=>date.toISOString();/**\n * To get the current timestamp in ISO string format\n * @returns ISO formatted timestamp string\n */const getCurrentTimeFormatted=()=>getFormattedTimestamp(new Date());\n\nconst LOG_CONTEXT_SEPARATOR=':: ';const SCRIPT_ALREADY_EXISTS_ERROR=id=>`A script with the id \"${id}\" is already loaded. Skipping the loading of this script to prevent conflicts`;const SCRIPT_LOAD_ERROR=(id,url,ev)=>`Unable to load (${isString(ev)?ev:ev.type}) the script with the id \"${id}\" from URL \"${url}\"`;const SCRIPT_LOAD_TIMEOUT_ERROR=(id,url,timeout)=>`A timeout of ${timeout} ms occurred while trying to load the script with id \"${id}\" from URL \"${url}\"`;const CIRCULAR_REFERENCE_WARNING=(context,key)=>`${context}${LOG_CONTEXT_SEPARATOR}A circular reference has been detected in the object and the property \"${key}\" has been dropped from the output.`;const JSON_STRINGIFY_WARNING=`Failed to convert the value to a JSON string.`;const COOKIE_DATA_ENCODING_ERROR=`Failed to encode the cookie data.`;const STORAGE_UNAVAILABILITY_ERROR_PREFIX=(context,storageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The \"${storageType}\" storage type is `;\n\nconst JSON_STRINGIFY='JSONStringify';const BIG_INT_PLACEHOLDER='[BigInt]';const CIRCULAR_REFERENCE_PLACEHOLDER='[Circular Reference]';const getCircularReplacer=(excludeNull,excludeKeys,logger)=>{const ancestors=[];// Here we do not want to use arrow function to use \"this\" in function context\n// eslint-disable-next-line func-names\nreturn function(key,value){if(excludeKeys?.includes(key)){return undefined;}if(excludeNull&&isNullOrUndefined(value)){return undefined;}if(typeof value!=='object'||isNull(value)){return value;}// `this` is the object that value is contained in, i.e., its direct parent.\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore-next-line\nwhile(ancestors.length>0&&ancestors[ancestors.length-1]!==this){ancestors.pop();}if(ancestors.includes(value)){logger?.warn(CIRCULAR_REFERENCE_WARNING(JSON_STRINGIFY,key));return CIRCULAR_REFERENCE_PLACEHOLDER;}ancestors.push(value);return value;};};/**\n * Utility method for JSON stringify object excluding null values & circular references\n *\n * @param {*} value input\n * @param {boolean} excludeNull if it should exclude nul or not\n * @param {function} logger optional logger methods for warning\n * @returns string\n */const stringifyWithoutCircular=(value,excludeNull,excludeKeys,logger)=>{try{return JSON.stringify(value,getCircularReplacer(excludeNull,excludeKeys,logger));}catch(err){logger?.warn(JSON_STRINGIFY_WARNING,err);return null;}};const getReplacer=logger=>{const ancestors=[];// Array to track ancestor objects\n// Using a regular function to use `this` for the parent context\nreturn function replacer(key,value){if(isBigInt(value)){return BIG_INT_PLACEHOLDER;// Replace BigInt values\n}// `this` is the object that value is contained in, i.e., its direct parent.\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore-next-line\nwhile(ancestors.length>0&&ancestors[ancestors.length-1]!==this){ancestors.pop();// Remove ancestors that are no longer part of the chain\n}// Check for circular references (if the value is already in the ancestors)\nif(ancestors.includes(value)){return CIRCULAR_REFERENCE_PLACEHOLDER;}// Add current value to ancestors\nancestors.push(value);return value;};};const traverseWithThis=(obj,replacer)=>{// Create a new result object or array\nconst result=Array.isArray(obj)?[]:{};// Traverse object properties or array elements\n// eslint-disable-next-line no-restricted-syntax\nfor(const key in obj){if(Object.hasOwnProperty.call(obj,key)){const value=obj[key];// Recursively apply the replacer and traversal\nconst sanitizedValue=replacer.call(obj,key,value);// If the value is an object or array, continue traversal\nif(isObjectLiteralAndNotNull(sanitizedValue)||Array.isArray(sanitizedValue)){result[key]=traverseWithThis(sanitizedValue,replacer);}else {result[key]=sanitizedValue;}}}return result;};/**\n * Recursively traverses an object similar to JSON.stringify,\n * sanitizing BigInts and circular references\n * @param value Input object\n * @param logger Logger instance\n * @returns Sanitized value\
1n */const getSanitizedValue=(value,logger)=>{const replacer=getReplacer();// This is needed for registering the first ancestor\nconst newValue=replacer.call(value,'',value);if(isObjectLiteralAndNotNull(value)||Array.isArray(value)){return traverseWithThis(value,replacer);}return newValue;};\n\nconst MANUAL_ERROR_IDENTIFIER='[SDK DISPATCHED ERROR]';const getStacktrace=err=>{const{stack}=err;if(typeof stack==='string'&&stack){return stack;}return undefined;};/**\n * Get mutated error with issue prepended to error message\n * @param err Original error\n * @param issue Issue to prepend to error message\n * @returns Instance of Error with message prepended with issue\n */const getMutatedError=(err,issue)=>{if(!isTypeOfError(err)){return new Error(`${issue}: ${stringifyWithoutCircular(err)}`);}try{// Preserve the specific error type (TypeError, ReferenceError, etc.)\nconst ErrorConstructor=err.constructor;const newError=new ErrorConstructor(`${issue}: ${err.message}`);// Preserve stack trace\nconst stack=getStacktrace(err);if(stack){newError.stack=stack;}// Preserve any other enumerable properties\nObject.getOwnPropertyNames(err).forEach(key=>{if(key!=='message'&&key!=='stack'&&key!=='name'){try{newError[key]=err[key];}catch{// Ignore if property is not writable\n}}});return newError;}catch{return new Error(`${issue}: ${stringifyWithoutCircular(err)}`);}};const dispatchErrorEvent=error=>{if(isTypeOfError(error)){const errStack=getStacktrace(error);if(errStack){// eslint-disable-next-line no-param-reassign\nerror.stack=`${errStack}\\n${MANUAL_ERROR_IDENTIFIER}`;}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};\n\nconst APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.31.4';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const BUILD_VARIANT='bundled';const ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';const ADBLOCK_PAGE_NAME='ad-block page request';const ADBLOCK_PAGE_PATH='/ad-blocked';const GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';const CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';\n\nconst QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';const QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';const QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';const QUERY_PARAM_USER_ID_KEY='ajs_uid';const QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';\n\nconst DEFAULT_XHR_TIMEOUT_MS=10*1000;// 10 seconds\nconst DEFAULT_COOKIE_MAX_AGE_MS=31536000*1000;// 1 year\nconst DEFAULT_SESSION_CUT_OFF_DURATION_MS=12*60*60*1000;// 12 hours\nconst DEFAULT_SESSION_TIMEOUT_MS=30*60*1000;// 30 minutes\nconst MIN_SESSION_TIMEOUT_MS=10*1000;// 10 seconds\nconst DEFAULT_DATA_PLANE_EVENTS_BUFFER_TIMEOUT_MS=10*1000;// 10 seconds\nconst DEBOUNCED_TIMEOUT_MS=250;// 250 milliseconds\n\n/**\n * Create globally accessible RudderStackGlobals object\n */const createExposedGlobals=(analyticsInstanceId='app')=>{if(!globalThis.RudderStackGlobals){globalThis.RudderStackGlobals={};}if(!globalThis.RudderStackGlobals[analyticsInstanceId]){globalThis.RudderStackGlobals[analyticsInstanceId]={};}};/**\n * Add move values to globally accessible RudderStackGlobals object per analytics instance\n */const setExposedGlobal=(keyName,value,analyticsInstanceId='app')=>{createExposedGlobals(analyticsInstanceId);globalThis.RudderStackGlobals[analyticsInstanceId][keyName]=value;};/**\n * Get values from globally accessible RudderStackGlobals object by analytics instance\n */const getExposedGlobal=(keyName,analyticsInstanceId='app')=>{createExposedGlobals(analyticsInstanceId);return globalThis.RudderStackGlobals[analyticsInstanceId][keyName];};function debounce(func,thisArg,delay=DEBOUNCED_TIMEOUT_MS){let timeoutId;return (...args)=>{globalThis.clearTimeout(timeoutId);timeoutId=globalThis.setTimeout(()=>{func.apply(thisArg,args);},delay);};}\n\n/**\n * Parse query string params into object values for keys that start with a defined prefix\n */const getEventDataFromQueryString=(params,dataTypeNamePrefix)=>{const data={};params.forEach((value,key)=>{if(key.startsWith(dataTypeNamePrefix)){// remove prefix from key name\nconst dataKey=key.substring(dataTypeNamePrefix.length);// add new key value pair in generated object\ndata[dataKey]=params.get(key);}});return data;};
1/**\n * Parse query string into preload buffer events & push into existing array before any other events\n */const retrieveEventsFromQueryString=(argumentsArray=[])=>{// Mapping for trait and properties values based on key prefix\nconst eventArgumentToQueryParamMap={trait:QUERY_PARAM_TRAIT_PREFIX,properties:QUERY_PARAM_PROPERTY_PREFIX};const queryObject=new URLSearchParams(globalThis.location.search);// Add track events with name and properties\nif(queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY)){argumentsArray.unshift(['track',queryObject.get(QUERY_PARAM_TRACK_EVENT_NAME_KEY),getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.properties)]);}// Send identify event\nconst userId=queryObject.get(QUERY_PARAM_USER_ID_KEY);const userTraits=getEventDataFromQueryString(queryObject,eventArgumentToQueryParamMap.trait);if(userId||isNonEmptyObject(userTraits)){// In identify API, user ID is optional\nconst identifyApiArgs=[...(userId?[userId]:[]),userTraits];argumentsArray.unshift(['identify',...identifyApiArgs]);}// Set anonymousID\nif(queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)){argumentsArray.unshift(['setAnonymousId',queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)]);}};/**\n * Retrieve an existing buffered load method call and remove from the existing array\n */const getPreloadedLoadEvent=preloadedEventsArray=>{const loadMethodName='load';let loadEvent=[];/**\n * Iterate the buffered API calls until we find load call and process it separately\n */let i=0;while(i<preloadedEventsArray.length){if(preloadedEventsArray[i]&&preloadedEventsArray[i][0]===loadMethodName){loadEvent=clone(preloadedEventsArray[i]);preloadedEventsArray.splice(i,1);break;}i+=1;}return loadEvent;};/**\n * Promote consent events to the top of the preloaded events array\n * @param preloadedEventsArray Preloaded events array\n * @returns None\n */const promotePreloadedConsentEventsToTop=preloadedEventsArray=>{const consentMethodName='consent';const consentEvents=preloadedEventsArray.filter(bufferedEvent=>bufferedEvent[0]===consentMethodName);const nonConsentEvents=preloadedEventsArray.filter(bufferedEvent=>bufferedEvent[0]!==consentMethodName);// Remove all elements and add consent events first followed by non consent events\n// eslint-disable-next-line unicorn/no-useless-spread\npreloadedEventsArray.splice(0,preloadedEventsArray.length,...consentEvents,...nonConsentEvents);};/**\n * Retrieve any existing events that were triggered before SDK load and enqueue in buffer\n */const retrievePreloadBufferEvents=instance=>{const preloadedEventsArray=getExposedGlobal(GLOBAL_PRELOAD_BUFFER)||[];// Get events that are pre-populated via query string params\nretrieveEventsFromQueryString(preloadedEventsArray);// Enqueue the non load events in the buffer of the global rudder analytics singleton\nif(preloadedEventsArray.length>0){instance.enqueuePreloadBufferEvents(preloadedEventsArray);setExposedGlobal(GLOBAL_PRELOAD_BUFFER,[]);}};const consumePreloadBufferedEvent=(event,analyticsInstance)=>{const methodName=event.shift();let callOptions;if(isFunction(analyticsInstance[methodName])){switch(methodName){case 'page':callOptions=pageArgumentsToCallOptions(...event);break;case 'track':callOptions=trackArgumentsToCallOptions(...event);break;case 'identify':callOptions=identifyArgumentsToCallOptions(...event);break;case 'alias':callOptions=aliasArgumentsToCallOptions(...event);break;case 'group':callOptions=groupArgumentsToCallOptions(...event);break;default:analyticsInstance[methodName](...event);break;}if(callOptions){analyticsInstance[methodName](callOptions);}}};\n\nconst DEFAULT_EXT_SRC_LOAD_TIMEOUT_MS=10*1000;// 10 seconds\n\nconst EXTERNAL_SOURCE_LOAD_ORIGIN='RS_JS_SDK';\n\n/**\n * Create the DOM element to load a script marked as RS SDK originated\n *\n * @param {*} url The URL of the script to be loaded\n * @param {*} id ID for the script tag\n * @param {*} async Whether to load the script in async mode. Defaults to `true` [optional]\n * @param {*} onload callback to invoke onload [optional]\n * @param {*} onerror callback to invoke onerror [optional]\n * @param {*} extraAttributes key/value pair with html attributes to add in html tag [optional]\n *\n * @returns HTMLScriptElement\n */const createScriptElement=(url,id,async=true,onload=null,onerror=null,extraAttributes={})=>{const scriptElement=document.createElement('script');scriptElement.type='text/javascript';scriptElement.onload=onload;scriptElement.onerror=onerror;scriptElement.src=url;scriptElement.id=id;scriptElement.async=async;
1Object.keys(extraAttributes).forEach(attributeName=>{scriptElement.setAttribute(attributeName,extraAttributes[attributeName]);});scriptElement.setAttribute('data-loader',EXTERNAL_SOURCE_LOAD_ORIGIN);return scriptElement;};/**\n * Add script DOM element to DOM\n *\n * @param {*} newScriptElement the script element to add\n *\n * @returns\n */const insertScript=newScriptElement=>{// First try to add it to the head\nconst headElements=document.getElementsByTagName('head');if(headElements.length>0){headElements[0]?.insertBefore(newScriptElement,headElements[0]?.firstChild);return;}// Else wise add it before the first script tag\nconst scriptElements=document.getElementsByTagName('script');if(scriptElements.length>0&&scriptElements[0]?.parentNode){scriptElements[0]?.parentNode.insertBefore(newScriptElement,scriptElements[0]);return;}// Create a new head element and add the script as fallback\nconst headElement=document.createElement('head');headElement.appendChild(newScriptElement);const htmlElement=document.getElementsByTagName('html')[0];htmlElement?.insertBefore(headElement,htmlElement.firstChild);};/**\n * Loads external js file as a script html tag\n *\n * @param {*} url The URL of the script to be loaded\n * @param {*} id ID for the script tag\n * @param {*} timeout loading timeout\n * @param {*} async Whether to load the script in async mode. Defaults to `true` [optional]\n * @param {*} extraAttributes key/value pair with html attributes to add in html tag [optional]\n *\n * @returns\n */const jsFileLoader=(url,id,timeout,async=true,extraAttributes)=>new Promise((resolve,reject)=>{const scriptExists=document.getElementById(id);if(scriptExists){reject(new Error(SCRIPT_ALREADY_EXISTS_ERROR(id)));}try{let timeoutID;const onload=()=>{globalThis.clearTimeout(timeoutID);resolve(id);};const onerror=ev=>{globalThis.clearTimeout(timeoutID);reject(new Error(SCRIPT_LOAD_ERROR(id,url,ev)));};// Create the DOM element to load the script and add it to the DOM\ninsertScript(createScriptElement(url,id,async,onload,onerror,extraAttributes));// Reject on timeout\ntimeoutID=globalThis.setTimeout(()=>{reject(new Error(SCRIPT_LOAD_TIMEOUT_ERROR(id,url,timeout)));},timeout);}catch(err){reject(getMutatedError(err,SCRIPT_LOAD_ERROR(id,url,'unknown')));}});\n\n/**\n * Service to load external resources/files\n */class ExternalSrcLoader{constructor(logger,timeout=DEFAULT_EXT_SRC_LOAD_TIMEOUT_MS){this.logger=logger;this.timeout=timeout;}/**\n * Load external resource of type javascript\n */loadJSFile(config){const{url,id,timeout,async,callback,extraAttributes}=config;const isFireAndForget=!isFunction(callback);jsFileLoader(url,id,timeout||this.timeout,async,extraAttributes).then(id=>{if(!isFireAndForget){callback(id);}}).catch(err=>{if(!isFireAndForget){callback(id,err);}});}}\n\nvar i=Symbol.for(\"preact-signals\");function t(){if(!(s>1)){var i,t=false;!function(){var i=c;c=void 0;while(void 0!==i){if(i.S.v===i.v)i.S.i=i.i;i=i.o;}}();while(void 0!==h){var n=h;h=void 0;v++;while(void 0!==n){var r=n.u;n.u=void 0;n.f&=-3;if(!(8&n.f)&&w(n))try{n.c();}catch(n){if(!t){i=n;t=true;}}n=r;}}v=0;s--;if(t)throw i;}else s--;}function n(i){if(s>0)return i();e=++u;s++;try{return i();}finally{t();}}var r=void 0;function o(i){var t=r;r=void 0;try{return i();}finally{r=t;}}var h=void 0,s=0,v=0,u=0,e=0,c=void 0,d$1=0;function a(i){if(void 0!==r){var t=i.n;if(void 0===t||t.t!==r){t={i:0,S:i,p:r.s,n:void 0,t:r,e:void 0,x:void 0,r:t};if(void 0!==r.s)r.s.n=t;r.s=t;i.n=t;if(32&r.f)i.S(t);return t;}else if(-1===t.i){t.i=0;if(void 0!==t.n){t.n.p=t.p;if(void 0!==t.p)t.p.n=t.n;t.p=r.s;t.n=void 0;r.s.n=t;r.s=t;}return t;}}}function l(i,t){this.v=i;this.i=0;this.n=void 0;this.t=void 0;this.l=0;this.W=null==t?void 0:t.watched;this.Z=null==t?void 0:t.unwatched;this.name=null==t?void 0:t.name;}l.prototype.brand=i;l.prototype.h=function(){return true;};l.prototype.S=function(i){var t=this,n=this.t;if(n!==i&&void 0===i.e){i.x=n;this.t=i;if(void 0!==n)n.e=i;else o(function(){var i;null==(i=t.W)||i.call(t);});}};l.prototype.U=function(i){var t=this;if(void 0!==this.t){var n=i.e,r=i.x;
1if(void 0!==n){n.x=r;i.e=void 0;}if(void 0!==r){r.e=n;i.x=void 0;}if(i===this.t){this.t=r;if(void 0===r)o(function(){var i;null==(i=t.Z)||i.call(t);});}}};l.prototype.subscribe=function(i){var t=this;return j(function(){var n=t.value,o=r;r=void 0;try{i(n);}finally{r=o;}},{name:\"sub\"});};l.prototype.valueOf=function(){return this.value;};l.prototype.toString=function(){return this.value+\"\";};l.prototype.toJSON=function(){return this.value;};l.prototype.peek=function(){var i=this;return o(function(){return i.value;});};Object.defineProperty(l.prototype,\"value\",{get:function(){var i=a(this);if(void 0!==i)i.i=this.i;return this.v;},set:function(i){if(i!==this.v){if(v>100)throw new Error(\"Cycle detected\");!function(i){if(0!==s&&0===v)if(i.l!==e){i.l=e;c={S:i,v:i.v,i:i.i,o:c};}}(this);this.v=i;this.i++;d$1++;s++;try{for(var n=this.t;void 0!==n;n=n.x)n.t.N();}finally{t();}}}});function y(i,t){return new l(i,t);}function w(i){for(var t=i.s;void 0!==t;t=t.n)if(t.S.i!==t.i||!t.S.h()||t.S.i!==t.i)return true;return false;}function _(i){for(var t=i.s;void 0!==t;t=t.n){var n=t.S.n;if(void 0!==n)t.r=n;t.S.n=t;t.i=-1;if(void 0===t.n){i.s=t;break;}}}function b(i){var t=i.s,n=void 0;while(void 0!==t){var r=t.p;if(-1===t.i){t.S.U(t);if(void 0!==r)r.n=t.n;if(void 0!==t.n)t.n.p=r;}else n=t;t.S.n=t.r;if(void 0!==t.r)t.r=void 0;t=r;}i.s=n;}function p(i,t){l.call(this,void 0);this.x=i;this.s=void 0;this.g=d$1-1;this.f=4;this.W=null==t?void 0:t.watched;this.Z=null==t?void 0:t.unwatched;this.name=null==t?void 0:t.name;}p.prototype=new l();p.prototype.h=function(){this.f&=-3;if(1&this.f)return false;if(32==(36&this.f))return true;this.f&=-5;if(this.g===d$1)return true;this.g=d$1;this.f|=1;
1if(this.i>0&&!w(this)){this.f&=-2;return true;}var i=r;try{_(this);r=this;var t=this.x();if(16&this.f||this.v!==t||0===this.i){this.v=t;this.f&=-17;this.i++;}}catch(i){this.v=i;this.f|=16;this.i++;}r=i;b(this);this.f&=-2;return true;};p.prototype.S=function(i){if(void 0===this.t){this.f|=36;for(var t=this.s;void 0!==t;t=t.n)t.S.S(t);}l.prototype.S.call(this,i);};p.prototype.U=function(i){if(void 0!==this.t){l.prototype.U.call(this,i);if(void 0===this.t){this.f&=-33;for(var t=this.s;void 0!==t;t=t.n)t.S.U(t);}}};p.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var i=this.t;void 0!==i;i=i.x)i.t.N();}};Object.defineProperty(p.prototype,\"value\",{get:function(){if(1&this.f)throw new Error(\"Cycle detected\");var i=a(this);this.h();if(void 0!==i)i.i=this.i;if(16&this.f)throw this.v;return this.v;}});function S(i){var n=i.m;i.m=void 0;if(\"function\"==typeof n){s++;var o=r;r=void 0;try{n();}catch(t){i.f&=-2;i.f|=8;m(i);throw t;}finally{r=o;t();}}}function m(i){for(var t=i.s;void 0!==t;t=t.n)t.S.U(t);i.x=void 0;i.s=void 0;S(i);}function x$1(i){if(r!==this)throw new Error(\"Out-of-order effect\");b(this);r=i;this.f&=-2;if(8&this.f)m(this);t();}function E(i,t){this.x=i;this.m=void 0;this.s=void 0;this.u=void 0;this.f=32;this.name=null==t?void 0:t.name;}E.prototype.c=function(){var i=this.S();try{if(8&this.f)return;if(void 0===this.x)return;var t=this.x();if(\"function\"==typeof t)this.m=t;}finally{i();}};E.prototype.S=function(){if(1&this.f)throw new Error(\"Cycle detected\");this.f|=1;this.f&=-9;S(this);_(this);s++;var i=r;r=this;return x$1.bind(this,i);};E.prototype.N=function(){if(!(2&this.f)){this.f|=2;this.u=h;h=this;}};E.prototype.d=function(){this.f|=8;if(!(1&this.f))m(this);};E.prototype.dispose=function(){this.d();};function j(i,t){var n=new E(i,t);try{n.c();}catch(i){n.d();throw i;}var r=n.d.bind(n);r[Symbol.dispose]=r;return r;}\n\n/**\n * A buffer queue to serve as a store for any type of data\n */class BufferQueue{constructor(){this.items=[];}enqueue(item){this.items.push(item);}dequeue(){if(this.items.length===0){return null;}return this.items.shift();}isEmpty(){return this.items.length===0;}size(){return this.items.length;}clear(){this.items=[];}}\n\nconst LOG_LEVEL_MAP={LOG:0,INFO:1,DEBUG:2,WARN:3,ERROR:4,NONE:5};const DEFAULT_LOG_LEVEL='LOG';const POST_LOAD_LOG_LEVEL='ERROR';const LOG_MSG_PREFIX='RS SDK';const LOG_MSG_PREFIX_STYLE='font-weight: bold; background: black; color: white;';const LOG_MSG_STYLE='font-weight: normal;';/**\n * Service to log messages/data to output provider, default is console\n */class Logger{constructor(minLogLevel=DEFAULT_LOG_LEVEL,scope='',logProvider=console){this.minLogLevel=LOG_LEVEL_MAP[minLogLevel];this.scope=scope;this.logProvider=logProvider;}log(...data){this.outputLog('LOG',data);}info(...data){this.outputLog('INFO',data);}debug(...data){this.outputLog('DEBUG',data);}warn(...data){this.outputLog('WARN',data);}error(...data){this.outputLog('ERROR',data);}outputLog(logMethod,data){if(this.minLogLevel<=LOG_LEVEL_MAP[logMethod]){this.logProvider[logMethod.toLowerCase()]?.(...this.formatLogData(data));}}setScope(scopeVal){this.scope=scopeVal||this.scope;}// TODO: should we allow to change the level via global variable on run time\n// to assist on the fly debugging?\nsetMinLogLevel(logLevel){this.minLogLevel=LOG_LEVEL_MAP[logLevel];if(isUndefined(this.minLogLevel)){this.minLogLevel=LOG_LEVEL_MAP[DEFAULT_LOG_LEVEL];}}/**\n * Formats the console message using `scope` and styles\n */formatLogData(data){if(Array.isArray(data)&&data.length>0){// prefix SDK identifier\nlet msg=`%c ${LOG_MSG_PREFIX}`;// format the log message using `scope`\nif(this.scope){msg=`${msg} - ${this.scope}`;}// trim whitespaces for original message\nconst originalMsg=isString(data[0])?data[0].trim():'';// prepare the final message\nmsg=`${msg} %c ${originalMsg}`;const styledLogArgs=[msg,LOG_MSG_PREFIX_STYLE,// add style for the prefix\nLOG_MSG_STYLE// reset the style for the actual message\n];// add first it if it was not a string msg\nif(!isString(data[0])){styledLogArgs.push(data[0]);}// append rest of the original arguments\nstyledLogArgs.push(...data.slice(1));return styledLogArgs;}return data;}}const defaultLogger=new Logger();\n\nlet ErrorType=/*#__PURE__*/function(ErrorType){ErrorType[\"HANDLEDEXCEPTION\"]=\"handledException\";ErrorType[\"UNHANDLEDEXCEPTION\"]=\"unhandledException\";ErrorType[\"UNHANDLEDREJECTION\"]=\"unhandledPromiseRejection\";return ErrorType;}({});\n\n// default is v3\nconst SUPPORTED_STORAGE_TYPES=['localStorage','memoryStorage','cookieStorage','sessionStorage','none'];const DEFAULT_STORAGE_TYPE='cookieStorage';\n\nconst SOURCE_CONFIG_RESOLUTION_ERROR=`Unable to process/parse source configuration response`;
1const SOURCE_DISABLED_ERROR=`The source is disabled. Please enable the source in the dashboard to send events.`;const XHR_PAYLOAD_PREP_ERROR=`Failed to prepare data for the request.`;const PLUGIN_EXT_POINT_MISSING_ERROR=`Failed to invoke plugin because the extension point name is missing.`;const PLUGIN_EXT_POINT_INVALID_ERROR=`Failed to invoke plugin because the extension point name is invalid.`;const SOURCE_CONFIG_OPTION_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The \"getSourceConfig\" load API option must be a function that returns valid source configuration data.`;const COMPONENT_BASE_URL_ERROR=(context,component,url)=>`${context}${LOG_CONTEXT_SEPARATOR}The base URL \"${url}\" for ${component} is not valid.`;// ERROR\nconst UNSUPPORTED_CONSENT_MANAGER_ERROR=(context,selectedConsentManager,consentManagersToPluginNameMap)=>`${context}${LOG_CONTEXT_SEPARATOR}The consent manager \"${selectedConsentManager}\" is not supported. Please choose one of the following supported consent managers: \"${Object.keys(consentManagersToPluginNameMap)}\".`;const NON_ERROR_WARNING=(context,errStr)=>`${context}${LOG_CONTEXT_SEPARATOR}Ignoring a non-error: ${errStr}.`;const BREADCRUMB_ERROR=`Failed to log breadcrumb`;const HANDLE_ERROR_FAILURE=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to handle the error.`;const PLUGIN_NAME_MISSING_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin name is missing.`;const PLUGIN_ALREADY_EXISTS_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin \"${pluginName}\" already exists.`;const PLUGIN_NOT_FOUND_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin \"${pluginName}\" not found.`;const PLUGIN_ENGINE_BUG_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin \"${pluginName}\" not found in plugins but found in byName. This indicates a bug in the plugin engine. Please report this issue to the development team.`;const PLUGIN_DEPS_ERROR=(context,pluginName,notExistDeps)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin \"${pluginName}\" could not be loaded because some of its dependencies \"${notExistDeps}\" do not exist.`;const PLUGIN_INVOCATION_ERROR=(context,extPoint,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to invoke the \"${extPoint}\" extension point of plugin \"${pluginName}\".`;const SOURCE_CONFIG_FETCH_ERROR='Failed to fetch the source config';const WRITE_KEY_VALIDATION_ERROR=(context,writeKey)=>`${context}${LOG_CONTEXT_SEPARATOR}The write key \"${writeKey}\" is invalid. It must be a non-empty string. Please check that the write key is correct and try again.`;const DATA_PLANE_URL_VALIDATION_ERROR=(context,dataPlaneUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The data plane URL \"${dataPlaneUrl}\" is invalid. It must be a valid URL string. Please check that the data plane URL is correct and try again.`;const INVALID_CALLBACK_FN_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The provided callback parameter is not a function.`;const XHR_DELIVERY_ERROR=(prefix,status,statusText,url,response)=>`${prefix} with status ${status} (${statusText}) for URL: ${url}. Response: ${response.trim()}`;const XHR_REQUEST_ERROR=(prefix,e,url)=>`${prefix} due to timeout or no connection (${e?e.type:''}) at the client side for URL: ${url}`;const XHR_SEND_ERROR=(prefix,url)=>`${prefix} for URL: ${url}`;const STORE_DATA_SAVE_ERROR=key=>`Failed to save the value for \"${key}\" to storage`;const STORE_DATA_FETCH_ERROR=key=>`Failed to retrieve or parse data for \"${key}\" from storage`;const DATA_SERVER_REQUEST_FAIL_ERROR=status=>`The server responded with status ${status} while setting the cookies. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_ERROR=key=>`The server failed to set the ${key} cookie. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR=`Failed to set/remove cookies via server. As a fallback, the cookies will be managed client side.`;// WARNING\nconst STORAGE_TYPE_VALIDATION_WARNING=(context,storageType,defaultStorageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage type \"${storageType}\" is not supported. Please choose one of the following supported types: \"${SUPPORTED_STORAGE_TYPES}\". The default type \"${defaultStorageType}\" will be used instead.`;const UNSUPPORTED_STORAGE_ENCRYPTION_VERSION_WARNING=(context,selectedStorageEncryptionVersion,storageEncryptionVersionsToPluginNameMap,defaultVersion)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage encryption version \"${selectedStorageEncryptionVersion}\" is not supported. Please choose one of the following supported versions: \"${Object.keys(storageEncryptionVersionsToPluginNameMap)}\". The default version \"${defaultVersion}\" will be used instead.`;const STORAGE_DATA_MIGRATION_OVERRIDE_WARNING=(context,storageEncryptionVersion,defaultVersion)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage data migration has been disabled because the configured storage encryption version (${storageEncryptionVersion}) is not the latest (${defaultVersion}). To enable storage data migration, please update the storage encryption version to the latest version.`;const SERVER_SIDE_COOKIE_FEATURE_OVERRIDE_WARNING=(context,providedCookieDomain,currentCookieDomain)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided cookie domain (${providedCookieDomain}) does not match the current webpage's domain (${currentCookieDomain}). Hence, the cookies will be set client-side.`;const RESERVED_KEYWORD_WARNING=(context,property,parentKeyPath,reservedElements)=>`${context}${LOG_CONTEXT_SEPARATOR}The \"${property}\" property defined under \"${parentKeyPath}\" is a reserved keyword. Please choose a different property name to avoid conflicts with reserved keywords (${reservedElements}).`;
1const INVALID_CONTEXT_OBJECT_WARNING=logContext=>`${logContext}${LOG_CONTEXT_SEPARATOR}Please make sure that the \"context\" property in the event API's \"options\" argument is a valid object literal with key-value pairs.`;const UNSUPPORTED_BEACON_API_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The Beacon API is not supported by your browser. The events will be sent using XHR instead.`;const TIMEOUT_NOT_NUMBER_WARNING=(context,timeout,defaultValue)=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value \"${timeout}\" is not a number. The default timeout of ${defaultValue} ms will be used instead.`;const CUT_OFF_DURATION_NOT_NUMBER_WARNING=(context,cutOffDuration,defaultValue)=>`${context}${LOG_CONTEXT_SEPARATOR}The session cut off duration value \"${cutOffDuration}\" is not a number. The default cut off duration of ${defaultValue} ms will be used instead.`;const CUT_OFF_DURATION_LESS_THAN_TIMEOUT_WARNING=(context,cutOffDuration,timeout)=>`${context}${LOG_CONTEXT_SEPARATOR}The session cut off duration value \"${cutOffDuration}\" ms is less than the session timeout value \"${timeout}\" ms. The cut off functionality will be disabled.`;const TIMEOUT_ZERO_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value is 0, which disables the automatic session tracking feature. If you want to enable session tracking, please provide a positive integer value for the timeout.`;const TIMEOUT_NOT_RECOMMENDED_WARNING=(context,timeout,minTimeout)=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value ${timeout} ms is less than the recommended minimum of ${minTimeout} ms. Please consider increasing the timeout value to ensure optimal performance and reliability.`;const INVALID_SESSION_ID_WARNING=(context,sessionId,minSessionIdLength)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided session ID (${sessionId}) is either invalid, not a positive integer, or not at least \"${minSessionIdLength}\" digits long. A new session ID will be auto-generated instead.`;const STORAGE_QUOTA_EXCEEDED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The storage is either full or unavailable, so the data will not be persisted. Switching to in-memory storage.`;const STORAGE_UNAVAILABLE_WARNING=(context,entry,selectedStorageType,finalStorageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage type \"${selectedStorageType}\" is not available for entry \"${entry}\". The SDK will initialize the entry with \"${finalStorageType}\" storage type instead.`;const CALLBACK_INVOKE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The callback threw an exception`;const INVALID_CONFIG_URL_WARNING=(context,configUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided source config URL \"${configUrl}\" is invalid. Using the default source config URL instead.`;const POLYFILL_SCRIPT_LOAD_ERROR=(scriptId,url)=>`Failed to load the polyfill script with ID \"${scriptId}\" from URL ${url}.`;const UNSUPPORTED_PRE_CONSENT_STORAGE_STRATEGY=(context,selectedStrategy,defaultStrategy)=>`${context}${LOG_CONTEXT_SEPARATOR}The pre-consent storage strategy \"${selectedStrategy}\" is not supported. Please choose one of the following supported strategies: \"none, session, anonymousId\". The default strategy \"${defaultStrategy}\" will be used instead.`;const UNSUPPORTED_PRE_CONSENT_EVENTS_DELIVERY_TYPE=(context,selectedDeliveryType,defaultDeliveryType)=>`${context}${LOG_CONTEXT_SEPARATOR}The pre-consent events delivery type \"${selectedDeliveryType}\" is not supported. Please choose one of the following supported types: \"immediate, buffer\". The default type \"${defaultDeliveryType}\" will be used instead.`;const DEPRECATED_PLUGIN_WARNING=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}${pluginName} plugin is deprecated. Please exclude it from the load API options.`;const generateMisconfiguredPluginsWarning=(context,configurationStatus,missingPlugins,shouldAddMissingPlugins)=>{const isSinglePlugin=missingPlugins.length===1;const pluginsString=isSinglePlugin?` '${missingPlugins[0]}' plugin was`:` ['${missingPlugins.join(\"', '\")}'] plugins were`;const baseWarning=`${context}${LOG_CONTEXT_SEPARATOR}${configurationStatus}, but${pluginsString} not configured to load.`;if(shouldAddMissingPlugins){return `${baseWarning} So, ${isSinglePlugin?'the plugin':'those plugins'} will be loaded automatically.`;}return `${baseWarning} Ignore if this was intentional. Otherwise, consider adding ${isSinglePlugin?'it':'them'} to the 'plugins' load API option.`;};const INVALID_POLYFILL_URL_WARNING=(context,customPolyfillUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided polyfill URL \"${customPolyfillUrl}
1\" is invalid. The default polyfill URL will be used instead.`;const PAGE_UNLOAD_ON_BEACON_DISABLED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}Page Unloaded event can only be tracked when the Beacon transport is active. Please enable \"useBeacon\" load API option.`;const UNKNOWN_PLUGINS_WARNING=(context,unknownPlugins)=>`${context}${LOG_CONTEXT_SEPARATOR}Ignoring unknown plugins: ${unknownPlugins.join(', ')}.`;const UNAVAILABLE_PLUGINS_ERROR=(context,unavailablePlugins)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to load the following unavailable local plugins: ${unavailablePlugins.join(', ')}. Some features of the SDK may not work as expected. Make sure you are using the correct SDK bundle variant.`;const CUSTOM_INTEGRATION_CANNOT_BE_ADDED_ERROR=(context,destinationId)=>`${context}${LOG_CONTEXT_SEPARATOR}Cannot add custom integration for destination ID \"${destinationId}\" after the SDK is loaded.`;\n\nconst DEFAULT_INTEGRATIONS_CONFIG={All:true};\n\nconst CDN_INT_DIR='js-integrations';const CDN_PLUGINS_DIR='plugins';const URL_PATTERN=new RegExp('^(https?:\\\\/\\\\/)'+// protocol\n'('+'((([a-zA-Z\\\\d]([a-zA-Z\\\\d-]*[a-zA-Z\\\\d])*)\\\\.)+[a-zA-Z]{2,}|'+// domain name\n'localhost|'+// localhost\n'((25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9]?)\\\\.){3}'+// OR IP (v4) address first 3 octets\n'(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9]?))'+// last octet of IP address\n')'+'(\\\\:\\\\d+)?'+// port\n'(\\\\/[-a-zA-Z\\\\d%_.~+]*)*'+// path\n'(\\\\?[;&a-zA-Z\\\\d%_.~+=-]*)?'+// query string\n'(\\\\#[-a-zA-Z\\\\d_]*)?$')// fragment locator\n;\n\nconst BUILD_TYPE='modern';const SDK_CDN_BASE_URL='https://cdn.rudderlabs.com';const CDN_ARCH_VERSION_DIR='v3';const DEFAULT_INTEGRATION_SDKS_URL=`${SDK_CDN_BASE_URL}/${CDN_ARCH_VERSION_DIR}/${BUILD_TYPE}/${CDN_INT_DIR}`;const DEFAULT_PLUGINS_URL=`${SDK_CDN_BASE_URL}/${CDN_ARCH_VERSION_DIR}/${BUILD_TYPE}/${CDN_PLUGINS_DIR}`;const DEFAULT_CONFIG_BE_URL='https://api.rudderstack.com';\n\nconst DEFAULT_STORAGE_ENCRYPTION_VERSION='v3';const DEFAULT_DATA_PLANE_EVENTS_TRANSPORT='xhr';const ConsentManagersToPluginNameMap={iubenda:'IubendaConsentManager',oneTrust:'OneTrustConsentManager',ketch:'KetchConsentManager',custom:'CustomConsentManager'};const StorageEncryptionVersionsToPluginNameMap={[DEFAULT_STORAGE_ENCRYPTION_VERSION]:'StorageEncryption',legacy:'StorageEncryptionLegacy'};const DataPlaneEventsTransportToPluginNameMap={[DEFAULT_DATA_PLANE_EVENTS_TRANSPORT]:'XhrQueue',beacon:'BeaconQueue'};const DEFAULT_DATA_SERVICE_ENDPOINT='rsaRequest';const METRICS_SERVICE_ENDPOINT='rsaMetrics';const CUSTOM_DEVICE_MODE_DESTINATION_DISPLAY_NAME='Custom Device Mode';\n\nconst defaultLoadOptions={configUrl:DEFAULT_CONFIG_BE_URL,loadIntegration:true,sessions:{autoTrack:true,timeout:DEFAULT_SESSION_TIMEOUT_MS,cutOff:{enabled:false}},sameSiteCookie:'Lax',polyfillIfRequired:true,integrations:DEFAULT_INTEGRATIONS_CONFIG,useBeacon:false,beaconQueueOptions:{},destinationsQueueOptions:{},queueOptions:{},lockIntegrationsVersion:true,lockPluginsVersion:true,uaChTrackLevel:'none',plugins:[],useGlobalIntegrationsConfigInEvents:false,bufferDataPlaneEventsUntilReady:false,dataPlaneEventsBufferTimeout:DEFAULT_DATA_PLANE_EVENTS_BUFFER_TIMEOUT_MS,storage:{encryption:{version:DEFAULT_STORAGE_ENCRYPTION_VERSION},migrate:true,cookie:{}},sendAdblockPage:false,sameDomainCookiesOnly:false,secureCookie:false,sendAdblockPageOptions:{},useServerSideCookies:false};const loadOptionsState=y(clone(defaultLoadOptions));\n\nconst DEFAULT_USER_SESSION_VALUES=deepFreeze({userId:'',userTraits:{},anonymousId:'',groupId:'',groupTraits:{},initialReferrer:'',initialReferringDomain:'',sessionInfo:{},authToken:null});const DEFAULT_RESET_OPTIONS=deepFreeze({entries:{userId:true,userTraits:true,groupId:true,groupTraits:true,sessionInfo:true,authToken:true,// These are not reset by default\nanonymousId:false,initialReferrer:false,initialReferringDomain:false}});const SERVER_SIDE_COOKIES_DEBOUNCE_TIME=10;// milliseconds\n\nconst sessionState={userId:y(DEFAULT_USER_SESSION_VALUES.userId),userTraits:y(DEFAULT_USER_SESSION_VALUES.userTraits),anonymousId:y(DEFAULT_USER_SESSION_VALUES.anonymousId),groupId:y(DEFAULT_USER_SESSION_VALUES.groupId),groupTraits:y(DEFAULT_USER_SESSION_VALUES.groupTraits),initialReferrer:y(DEFAULT_USER_SESSION_VALUES.initialReferrer),initialReferringDomain:y(DEFAULT_USER_SESSION_VALUES.initialReferringDomain),sessionInfo:y(DEFAULT_USER_SESSION_VALUES.sessionInfo),authToken:y(DEFAULT_USER_SESSION_VALUES.authToken)};\n\nconst capabilitiesState={isOnline:y(true),storage:{isLocalStorageAvailable:y(false),isCookieStorageAvailable:y(false),isSessionStorageAvailable:y(false)},isBeaconAvailable:y(false),isLegacyDOM:y(false),isUaCHAvailable:y(false),isCryptoAvailable:y(false),isAdBlockerDetectionInProgress:y(false),isAdBlocked:y(undefined),cspBlockedURLs:y([])};\n\nconst reportingState={isErrorReportingEnabled:y(false),isMetricsReportingEnabled:y(false),breadcrumbs:y([])};\n\nconst sourceConfigState=y(undefined);\n\nconst lifecycleState={activeDataplaneUrl:y(undefined),integrationsCDNPath:y(DEFAULT_INTEGRATION_SDKS_URL),pluginsCDNPath:y(DEFAULT_PLUGINS_URL),sourceConfigUrl:y(undefined),status:y(undefined),initialized:y(false),logLevel:y(POST_LOAD_LOG_LEVEL),loaded:y(false),readyCallbacks:y([]),writeKey:y(undefined),dataPlaneUrl:y(undefined),safeAnalyticsInstance:y(undefined)};\n\nconst consentsState={enabled:y(false),initialized:y(false),data:y({}),activeConsentManagerPluginName:y(undefined),preConsent:y({enabled:false}),postConsent:y({}),resolutionStrategy:y('and'),provider:y(undefined),metadata:y(undefined)};\n\nconst metricsState={retries:y(0),dropped:y(0),sent:y(0),queued:y(0),triggered:y(0),metricsServiceUrl:y(undefined)};\n\nconst getVariantValue=()=>{// For CDN builds, use runtime window.rudderAnalyticsBuildType\nreturn BUILD_VARIANT;};const contextState={app:y({name:APP_NAME,namespace:APP_NAMESPACE,version:APP_VERSION,installType:MODULE_TYPE}),traits:y(null),library:y({name:APP_NAME,version:APP_VERSION,snippetVersion:globalThis.RudderSnippetVersion,variant:getVariantValue()}
1),userAgent:y(null),device:y(null),network:y(null),os:y({name:'',version:''}),locale:y(null),screen:y({density:0,width:0,height:0,innerWidth:0,innerHeight:0}),'ua-ch':y(undefined),timezone:y(undefined)};\n\nconst nativeDestinationsState={configuredDestinations:y([]),activeDestinations:y([]),loadOnlyIntegrations:y({}),failedDestinations:y([]),loadIntegration:y(true),initializedDestinations:y([]),clientDestinationsReady:y(false),integrationsConfig:y({})};\n\nconst eventBufferState={toBeProcessedArray:y([]),readyCallbacksArray:y([])};\n\nconst pluginsState={ready:y(false),loadedPlugins:y([]),failedPlugins:y([]),pluginsToLoadFromConfig:y([]),activePlugins:y([]),totalPluginsToLoad:y(0)};\n\nconst storageState={encryptionPluginName:y(undefined),migrate:y(false),type:y(undefined),cookie:y(undefined),entries:y({}),trulyAnonymousTracking:y(false)};\n\nconst serverSideCookiesState={isEnabledServerSideCookies:y(false),dataServiceUrl:y(undefined)};\n\nconst dataPlaneEventsState={eventsQueuePluginName:y(undefined),deliveryEnabled:y(true)// Delivery should always happen\n};\n\nconst autoTrackState={enabled:y(false),pageLifecycle:{enabled:y(false),pageViewId:y(undefined),pageLoadedTimestamp:y(undefined)}};\n\nconst defaultStateValues={capabilities:capabilitiesState,consents:consentsState,context:contextState,eventBuffer:eventBufferState,lifecycle:lifecycleState,loadOptions:loadOptionsState,metrics:metricsState,nativeDestinations:nativeDestinationsState,plugins:pluginsState,reporting:reportingState,session:sessionState,source:sourceConfigState,storage:storageState,serverCookies:serverSideCookiesState,dataPlaneEvents:dataPlaneEventsState,autoTrack:autoTrackState};const state={...clone(defaultStateValues)};\n\nconst CHROME_STACK_LINE_RE=/^\\s*at /;const SAFARI_NATIVE_RE=/^(eval@)?(\\[native code])?$/;const LOCATION_RE=/(.+?)(?::(\\d+))?(?::(\\d+))?$/;function extractLocation(urlLike){if(!urlLike?.includes(':')){return [urlLike||undefined,undefined,undefined];}const normalizedUrlLike=urlLike.startsWith('(')&&urlLike.endsWith(')')?urlLike.slice(1,-1):urlLike;const parts=LOCATION_RE.exec(normalizedUrlLike);if(!parts){return [undefined,undefined,undefined];}return [parts[1]||undefined,parts[2]===undefined?undefined:Number(parts[2]),parts[3]===undefined?undefined:Number(parts[3])];}function parseV8Line(line){if(!CHROME_STACK_LINE_RE.test(line)){return null;}if(line.includes('(eval ')){line=line.replaceAll('eval code','eval').replaceAll(/(\\(eval at [^()]*)|(,.*$)/g,'');}const sanitized=line.replace(/^\\s+/,'').replaceAll('(eval code','(').replace(/^.*?\\s+/,'');const parenLoc=/ (\\(.+\\)$)/.exec(sanitized);const withoutLoc=parenLoc?sanitized.replace(parenLoc[0],''):sanitized;const[rawFile,lineNumber,columnNumber]=extractLocation(parenLoc?parenLoc[1]:sanitized);const functionName=parenLoc&&withoutLoc||undefined;const fileName=rawFile==='eval'||rawFile==='<anonymous>'?undefined:rawFile;return {functionName,fileName,lineNumber,columnNumber};}function parseFFSafariLine(line){if(SAFARI_NATIVE_RE.test(line)){return null;}if(line.includes(' > eval')){line=line.replaceAll(/ line (\\d+)(?: > eval line \\d+)* > eval:\\d+:\\d+/g,':$1');}if(!line.includes('@')&&!line.includes(':')){return {functionName:line,fileName:undefined,lineNumber:undefined,columnNumber:undefined};}const atIndex=line.lastIndexOf('@');const functionName=atIndex>0?line.slice(0,atIndex):undefined;const[fileName,lineNumber,columnNumber]=extractLocation(line.slice(atIndex+1));return {functionName,fileName,lineNumber,columnNumber};}/**\n * Parses an Error object's stack trace into structured frames.\n * Supports V8/Chromium (Chrome, Edge, Node) and SpiderMonkey/WebKit (Firefox, Safari) formats.\n * Throws if the error has no stack property.\n */function parseStackTrace(error){if(!error.stack){throw new Error('Cannot parse given Error object');}const lines=error.stack.split('\\n');if(lines.some(l=>CHROME_STACK_LINE_RE.test(l))){return lines.map(parseV8Line).filter(f=>f!==null);}return lines.map(parseFFSafariLine).filter(f=>f!==null);}\n\nconst GLOBAL_CODE='global code';const normalizeFunctionName=name=>{if(isDefined(name)){return /^global code$/i.test(name)?GLOBAL_CODE:name;}return name;};const formatStackframe=frame=>{const f={file:frame.fileName,method:normalizeFunctionName(frame.functionName),lineNumber:frame.lineNumber,columnNumber:frame.columnNumber};// Some instances result in no file:\n// - non-error exception thrown from global code in FF\n// This adds one.\nif(f.lineNumber&&f.lineNumber>-1&&!f.file&&!f.method){f.file=GLOBAL_CODE;}return f;};const ensureString=str=>isString(str)?str:'';function createException(errorClass,errorMessage,msgPrefix,stacktrace){return {errorClass:ensureString(errorClass),message:`${msgPrefix}${ensureString(errorMessage)}`,type:'browserjs',stacktrace:stacktrace.reduce((accum,frame)=>{const f=formatStackframe(frame);// don't include a stackframe if none of its properties are defined\ntry{if(JSON.stringify(f)==='{}')return accum;return accum.concat(f);}catch{return accum;}},[])};}const normalizeError=(maybeError,logger)=>{let error;if(isTypeOfError(maybeError)&&isString(getStacktrace(maybeError))){error=maybeError;}else {logger.warn(NON_ERROR_WARNING(ERROR_HANDLER,stringifyWithoutCircular(maybeError)));error=undefined;}return error;};const createBugsnagException=(error,msgPrefix)=>{try{const stacktrace=parseStackTrace(error);return createException(error.name,error.message,msgPrefix,stacktrace);}catch{return createException(error.name,error.message,msgPrefix,[]);}};\n\n/**\n * Utility to parse XHR JSON response\n */const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');onError(error);}return undefined;};\n\nconst FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const PLUGINS_LOAD_FAILURE_MESSAGES=[/Failed to fetch dynamically imported module: .*/];const INTEGRATIONS_LOAD_FAILURE_MESSAGES=[/Unable to load \\(.*\\) the script with the id .*/,/A timeout of \\d+ ms occurred while trying to load the script with id .*/];const ERROR_MESSAGES_TO_BE_FILTERED=[new RegExp(`${FAILED_REQUEST_ERR_MSG_PREFIX}.*`),/A script with the id .* is already loaded\\./];const SCRIPT_LOAD_FAILURE_MESSAGES=[...PLUGINS_LOAD_FAILURE_MESSAGES,...INTEGRATIONS_LOAD_FAILURE_MESSAGES];const INTEGRATIONS_ERROR_CATEGORY='integrations';const SDK_ERROR_CATEGORY='sdk';const DEFAULT_ERROR_CATEGORY=SDK_ERROR_CATEGORY;\n\nconst DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**\n * Utility to create request configuration based on default options\n */const createXhrRequestOptions=(url,options,basicAuthHeader)=>{const requestOptions=mergeDeepRight(DEFAULT_XHR_REQUEST_OPTIONS,options||{});if(basicAuthHeader){requestOptions.headers=mergeDeepRight(requestOptions.headers,{Authorization:basicAuthHeader});}requestOptions.url=url;return requestOptions;};/**\n * Utility implementation of XHR, fetch cannot be used as it requires explicit\n * origin allowed values and not wildcard for CORS requests with credentials and\n * this is not supported by our sourceConfig API\n */const xhrRequest=(options,timeout=DEFAULT_XHR_TIMEOUT_MS,logger)=>new Promise((resolve,reject)=>{let payload;if(options.sendRawData===true){payload=options.data;}else {payload=stringifyWithoutCircular(options.data,false,[],logger);if(isNull(payload)){reject({error:new Error(XHR_PAYLOAD_PREP_ERROR),undefined,options});// return and don't process further if the payload could not be stringified\nreturn;}}const xhr=new XMLHttpRequest();// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst xhrReject=e=>{reject({error:new Error(XHR_DELIVERY_ERROR(FAILED_REQUEST_ERR_MSG_PREFIX,xhr.status,xhr.statusText,options.url,xhr.responseText)),xhr,options});};const xhrError=e=>{reject({error:new Error(XHR_REQUEST_ERROR(FAILED_REQUEST_ERR_MSG_PREFIX,e,options.url)),xhr,options,...(e?.type==='timeout'?{timedOut:true}:{})});};xhr.ontimeout=xhrError;xhr.onerror=xhrError;xhr.onload=()=>
1{if(xhr.status>=200&&xhr.status<400){resolve({response:xhr.responseText,xhr,options});}else {xhrReject();}};xhr.open(options.method,options.url,true);if(options.withCredentials===true){xhr.withCredentials=true;}// The timeout property may be set only in the time interval between a call to the open method\n// and the first call to the send method in legacy browsers\nxhr.timeout=timeout;Object.keys(options.headers).forEach(headerName=>{if(options.headers[headerName]){xhr.setRequestHeader(headerName,options.headers[headerName]);}});try{xhr.send(payload);}catch(err){reject({error:getMutatedError(err,XHR_SEND_ERROR(FAILED_REQUEST_ERR_MSG_PREFIX,options.url)),xhr,options});}});\n\n/**\n * Service to handle data communication with APIs\n */class HttpClient{constructor(logger){this.logger=logger;this.onError=this.onError.bind(this);}init(errorHandler){this.errorHandler=errorHandler;}/**\n * Implement requests in a blocking way\n */async getData(config){const{url,options,timeout,isRawResponse}=config;try{const data=await xhrRequest(createXhrRequestOptions(url,options,this.basicAuthHeader),timeout,this.logger);return {data:isRawResponse?data.response:responseTextToJson(data.response,this.onError),details:data};}catch(reason){return {data:undefined,details:reason};}}/**\n * Implement requests in a non-blocking way\n */getAsyncData(config){const{callback,url,options,timeout,isRawResponse}=config;const isFireAndForget=!isFunction(callback);xhrRequest(createXhrRequestOptions(url,options,this.basicAuthHeader),timeout,this.logger).then(data=>{if(!isFireAndForget){callback(isRawResponse?data.response:responseTextToJson(data.response,this.onError),data);}}).catch(data=>{if(!isFireAndForget){callback(undefined,data);}});}/**\n * Handle errors\n */onError(error,groupingHash){this.errorHandler?.onError({error,context:HTTP_CLIENT,groupingHash});}/**\n * Set basic authentication header (eg writekey)\n */setAuthHeader(value,noBtoa=false){const authVal=noBtoa?value:toBase64(`${value}:`);this.basicAuthHeader=`Basic ${authVal}`;}/**\n * Clear basic authentication header\n */resetAuthHeader(){this.basicAuthHeader=undefined;}}const defaultHttpClient=new HttpClient(defaultLogger);\n\nconst METRICS_PAYLOAD_VERSION='1';\n\n// Errors from the below scripts are NOT allowed to reach Bugsnag\nconst SDK_FILE_NAME_PREFIXES=()=>['rsa'// Prefix for all the SDK scripts including plugins and module federated chunks\n];const DEV_HOSTS=['www.test-host.com','localhost','127.0.0.1','[::1]'];// List of keys to exclude from the metadata\n// Potential PII or sensitive data\nconst APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','integration',// integration instance objects\n'eventBuffer',// pre-load event buffer (may contain PII)\n'traits','authToken'];const NOTIFIER_NAME='RudderStack JavaScript SDK';const SDK_GITHUB_URL='git+https://github.com/rudderlabs/rudder-sdk-js.git';const SOURCE_NAME='js';\n\nconst detectAdBlockers=httpClient=>{state.capabilities.isAdBlockerDetectionInProgress.value=true;try{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers\n// Use source config URL here as it is very unlikely to be blocked by adblockers\n// Only the extra query param should make it vulnerable to adblockers\n// This will work even if the users proxies it.\n// The edge case where this doesn't work is when HEAD method is not allowed by the server (user's)\nconst baseUrl=new URL(state.lifecycle.sourceConfigUrl.value);const url=`${baseUrl.origin}${baseUrl.pathname}?view=ad`;httpClient.getAsyncData({url,options:{// We actually don't need the response from the request, so we are using HEAD\nmethod:'HEAD',headers:{'Content-Type':undefined}},isRawResponse:true,callback:(result,details)=>{state.capabilities.isAdBlockerDetectionInProgress.value=false;// not ad blocked if the request is successful or it is not internally redirected on the client side\n// Often adblockers instead of blocking the request, they redirect it to an internal URL\nstate.capabilities.isAdBlocked.value=details?.error!==undefined||details?.xhr?.responseURL!==url;}});}catch(err){// Reset the flag to prevent blocking future detection attempts\nstate.capabilities.isAdBlockerDetectionInProgress.value=false;// Re-throw the error to be handled by the caller\nthrow err;}};\n\nconst getErrInstance=(err,errorType)=>{switch(errorType){case ErrorType.UNHANDLEDEXCEPTION:{const{error}=err;return error||err;}case ErrorType.UNHANDLEDREJECTION:{return err.reason;}case ErrorType.HANDLEDEXCEPTION:default:return err;}};const createNewBreadcrumb=message=>({type:'manual',name:message,timestamp:new Date(),metaData:{}});/**\n * A function to get the Bugsnag release stage for the current environment\n * @param getHostName Optional function to get the hostname (primarily for testing)\n * @returns 'development' if the host is empty (for file:// protocol etc.) or a dev host (localhost, 127.0.0.1, etc.), otherwise ''production'' (it'll be replaced with the actual release stage during the build)\n */const getReleaseStage=(getHostName=()=>window.location.hostname)=>{const host=getHostName();return !host||host&&DEV_HOSTS.includes(host)?'development':'production';};const getAppStateForMetadata=state=>{const stateStr=stringifyWithoutCircular(state,false,APP_STATE_EXCLUDE_KEYS);return stateStr!==null?JSON.parse(stateStr):{};};const getURLWithoutQueryString=()=>{const url=globalThis.location.href.split('?');return url[0];};const getUserDetails=(source,session,lifecycle,autoTrack)=>({id:`${source.value?.id??lifecycle.writeKey.value}..${session.sessionInfo.value.id??'NA'}..${autoTrack.pageLifecycle.pageViewId.value??'NA'}`,name:source.value?.name??'NA'});const getDeviceDetails=(locale,userAgent)=>({locale:locale.value??'NA',userAgent:userAgent.value??'NA',time:new Date()});const getBugsnagErrorEvent=(exception,errorState,state,groupingHash)=>{const{context,lifecycle,session,source,reporting,autoTrack}=state;
1const{app,locale,userAgent,timezone,screen,library}=context;return {payloadVersion:'5',notifier:{name:NOTIFIER_NAME,version:app.value.version,url:SDK_GITHUB_URL},events:[{exceptions:[clone(exception)],severity:errorState.severity,unhandled:errorState.unhandled,severityReason:errorState.severityReason,app:{version:app.value.version,releaseStage:getReleaseStage(),type:app.value.installType},device:getDeviceDetails(locale,userAgent),request:{url:getURLWithoutQueryString(),clientIp:'[NOT COLLECTED]'},breadcrumbs:clone(reporting.breadcrumbs.value),context:exception.message,groupingHash,metaData:{app:{snippetVersion:library.value.snippetVersion},device:{...screen.value,timezone:timezone.value},// Add rest of the state groups as metadata\n// so that they show up as separate tabs in the dashboard\n...getAppStateForMetadata(state)},user:getUserDetails(source,session,lifecycle,autoTrack)}]};};/**\n * A function to check if adblockers are active. The promise's resolve function\n * is invoked with true if adblockers are not detected and false otherwise.\n * @param {ApplicationState} state The application state\n * @param {IHttpClient} httpClient The HTTP client instance\n * @param {Function} resolve The promise's resolve function\n */const checkIfAdBlockersAreActive=(state,httpClient,resolve)=>{// Initiate ad blocker detection if not done previously and not already in progress.\nif(isUndefined(state.capabilities.isAdBlocked.value)){if(state.capabilities.isAdBlockerDetectionInProgress.value===false){detectAdBlockers(httpClient);}// Wait for the detection to complete.\nconst detectionDisposer=j(()=>{if(isDefined(state.capabilities.isAdBlocked.value)){// If ad blocker is not detected, notify.\nresolve(state.capabilities.isAdBlocked.value===false);// Cleanup the effect.\ndetectionDisposer();}});}else {// If ad blocker is not detected, notify.\nresolve(state.capabilities.isAdBlocked.value===false);}};/**\n * A function to determine whether the error should be promoted to notify or not.\n * For plugin and integration errors from RS CDN, if it is due to CSP blocked URLs or AdBlockers,\n * it will not be promoted to notify.\n * If it is due to other reasons, it will be promoted to notify.\n * @param {Error} exception The error object\n * @param {ApplicationState} state The application state\n * @param {IHttpClient} httpClient The HTTP client instance\n * @returns A promise that resolves to a boolean indicating whether the error should be promoted to notify or not\n */const checkIfAllowedToBeNotified=(exception,state,httpClient)=>{const errMsg=exception.message;return new Promise(resolve=>{// Filter out script load failures that are not from the RS CDN.\nif(SCRIPT_LOAD_FAILURE_MESSAGES.some(regex=>regex.test(errMsg))){const extractedURL=/https?:\\/\\/[^\\s\"'(),;<>[\\]{}]+/.exec(errMsg)?.[0];if(isString(extractedURL)){if(extractedURL.startsWith(SDK_CDN_BASE_URL)){// Filter out errors that are from CSP blocked URLs.\nif(state.capabilities.cspBlockedURLs.value.includes(extractedURL)){resolve(false);}else {// Filter out errors if adblockers are detected.\ncheckIfAdBlockersAreActive(state,httpClient,resolve);}}else {// Filter out errors that are not from the RS CDN.\nresolve(false);}}else {// Allow the error to be notified if no URL could be extracted from the error message\nresolve(true);}}else {resolve(!ERROR_MESSAGES_TO_BE_FILTERED.some(e=>e.test(errMsg)));}});};/**\n * A function to get the directory name from a file path.\n * @param {string} filePath The file path\n * @returns The directory name or undefined if the file path is invalid\n */const getDirectoryName=filePath=>{if(!filePath){return undefined;}const paths=filePath.split('/');return paths.at(-2);};/**\n * A function to get the top stack path from the exception.\n * @param {Exception} exception The exception object\n * @returns The top stack path or undefined if the exception is invalid\n */const getTopStackPath=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return undefined;}return errorOrigin;};/**\n * A function to determine if the error is from Rudder SDK\n * @param {Error} exception\n * @returns\n */const isSDKError=exception=>{const errorOrigin=getTopStackPath(exception);if(!errorOrigin){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);
1const parentFolderName=getDirectoryName(errorOrigin);return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorCategory=(exception,category)=>{if(category){return category;}const errorOrigin=getTopStackPath(exception);const directoryName=getDirectoryName(errorOrigin);if(directoryName===CDN_INT_DIR){return INTEGRATIONS_ERROR_CATEGORY;}return DEFAULT_ERROR_CATEGORY;};const getErrorDeliveryPayload=(payload,state,category)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType,category},errors:payload};return stringifyWithoutCircular(data);};/**\n * A function to get the grouping hash value to be used for the error event.\n * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.\n * If the grouping hash is an empty string or not specified, the default grouping hash is used.\n * If the grouping hash is a string, it is used as is.\n * @param curErrGroupingHash The grouping hash value part of the error event\n * @param defaultGroupingHash The default grouping hash value. It is the error message.\n * @param logger The logger instance\n * @returns The final grouping hash value to be used for the error event\n */const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,logger)=>{let normalizedGroupingHash;if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};\n\n/**\n * A service to handle errors\n */class ErrorHandler{initialized=false;// If no logger is passed errors will be thrown as unhandled error\nconstructor(httpClient,logger){this.httpClient=httpClient;this.logger=logger;}/**\n * Initializes the error handler by attaching global error listeners.\n * This method should be called once after construction.\n */init(){if(this.initialized){return;}this.attachErrorListeners();this.initialized=true;}/**\n * Attach error listeners to the global window object\n */attachErrorListeners(){globalThis.addEventListener('error',event=>{this.onError({error:event,context:ERROR_HANDLER,errorType:ErrorType.UNHANDLEDEXCEPTION});});globalThis.addEventListener('unhandledrejection',event=>{this.onError({error:event,context:ERROR_HANDLER,errorType:ErrorType.UNHANDLEDREJECTION});});// Listen to CSP violations and add the blocked URL to the state\n// if those URLs are from RS CDN.\ndocument.addEventListener('securitypolicyviolation',event=>{const blockedURL=isString(event.blockedURI)?event.blockedURI:'';if(event.disposition==='enforce'&&blockedURL.startsWith(SDK_CDN_BASE_URL)&&!state.capabilities.cspBlockedURLs.value.includes(blockedURL)){state.capabilities.cspBlockedURLs.value=[...state.capabilities.cspBlockedURLs.value,blockedURL];}});}/**\n * Handle errors\n * @param errorInfo - The error information\n * @param errorInfo.error - The error to handle\n * @param errorInfo.context - The context of where the error occurred\n * @param errorInfo.customMessage - The custom message of the error\n * @param errorInfo.errorType - The type of the error (handled or unhandled)\n * @param errorInfo.groupingHash - The grouping hash of the error\n * @param errorInfo.category - The category of the error (sdk or integrations)\n */async onError(errorInfo){try{const{error,context,customMessage,groupingHash,category}=errorInfo;const errorType=errorInfo.errorType??ErrorType.HANDLEDEXCEPTION;const errInstance=getErrInstance(error,errorType);const normalizedError=normalizeError(errInstance,this.logger);if(isUndefined(normalizedError)){return;}const customMsgVal=customMessage?`${customMessage} - `:'';const errorMsgPrefix=`${context}${LOG_CONTEXT_SEPARATOR}${customMsgVal}`;const bsException=createBugsnagException(normalizedError,errorMsgPrefix);const stacktrace=getStacktrace(normalizedError);const isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.\n// In case of NPM installations, the unhandled errors from the SDK cannot be identified\n// and will NOT be reported unless they occur in plugins or integrations.\nif(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value){const isAllowed=await checkIfAllowedToBeNotified(bsException,state,this.httpClient);if(isAllowed){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};
1// This will allow custom grouping of errors.\n// In case of NPM installations, the default grouping by surrounding code\n// does not make sense as each user application is different and will create a lot of noise in the alerts.\n// References:\n// https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash\n// https://docs.bugsnag.com/product/error-grouping/#user_defined\nconst normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,this.logger);// Get the final payload to be sent to the metrics service\nconst bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);const errorCategory=getErrorCategory(bsException,category);// send it to metrics service\nthis.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state,errorCategory),sendRawData:true},isRawResponse:true});}}// Log handled errors and errors dispatched by the SDK\nif(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it\nthis.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**\n * Add breadcrumbs to add insight of a user's journey before an error\n * occurred and send to external error monitoring service via a plugin\n *\n * @param {string} breadcrumb breadcrumbs message\n */leaveBreadcrumb(breadcrumb){try{state.reporting.breadcrumbs.value=[...state.reporting.breadcrumbs.value,createNewBreadcrumb(breadcrumb)];}catch(err){this.onError({error:err,context:ERROR_HANDLER,customMessage:BREADCRUMB_ERROR,groupingHash:BREADCRUMB_ERROR});}}}// Note: Remember to call defaultErrorHandler.init() before using it\nconst defaultErrorHandler=new ErrorHandler(defaultHttpClient,defaultLogger);\n\n// to next or return the value if it is the last one instead of an array per\n// plugin that is the normal invoke\n// TODO: add invoke method for extension point that we know only one plugin can be used. add invokeMultiple and invokeSingle methods\nclass PluginEngine{plugins=[];byName={};cache={};config={throws:true};constructor(logger,options={}){this.config={throws:true,...options};this.logger=logger;}register(plugin,state){if(!plugin.name){const errorMessage=PLUGIN_NAME_MISSING_ERROR(PLUGIN_ENGINE);if(this.config.throws){throw new Error(errorMessage);}else {this.logger.error(errorMessage,plugin);return;}}if(this.byName[plugin.name]){const errorMessage=PLUGIN_ALREADY_EXISTS_ERROR(PLUGIN_ENGINE,plugin.name);if(this.config.throws){throw new Error(errorMessage);}else {this.logger.error(errorMessage);return;}}this.cache={};this.plugins=this.plugins.slice();let pos=this.plugins.length;this.plugins.forEach((pluginItem,index)=>{if(pluginItem.deps?.includes(plugin.name)){pos=Math.min(pos,index);}});this.plugins.splice(pos,0,plugin);this.byName[plugin.name]=plugin;if(isFunction(plugin.initialize)){plugin.initialize(state);}}unregister(name){const plugin=this.byName[name];if(!plugin){const errorMessage=PLUGIN_NOT_FOUND_ERROR(PLUGIN_ENGINE,name);if(this.config.throws){throw new Error(errorMessage);}else {this.logger.error(errorMessage);return;}}const index=this.plugins.indexOf(plugin);if(index===-1){const errorMessage=PLUGIN_ENGINE_BUG_ERROR(PLUGIN_ENGINE,name);if(this.config.throws){throw new Error(errorMessage);}else {this.logger.error(errorMessage);return;}}this.cache={};delete this.byName[name];this.plugins=this.plugins.slice();this.plugins.splice(index,1);}getPlugin(name){return this.byName[name];}getPlugins(extPoint){const lifeCycleName=extPoint??'.';if(!this.cache[lifeCycleName]){this.cache[lifeCycleName]=this.plugins.filter(plugin=>{if(plugin.deps?.some(dependency=>!this.byName[dependency])){// If deps not exist, then not load it.\nconst notExistDeps=plugin.deps.filter(dependency=>!this.byName[dependency]);this.logger.error(PLUGIN_DEPS_ERROR(PLUGIN_ENGINE,plugin.name,notExistDeps));return false;}return lifeCycleName==='.'?true:hasValueByPath(plugin,lifeCycleName);});}return this.cache[lifeCycleName];}// This method allows to process this.plugins so that it could\n// do some unified pre-process before application starts.\nprocessRawPlugins(callback){callback(this.plugins);this.cache={};}invoke(extPoint,allowMultiple=true,...args){let extensionPointName=extPoint;if(!extensionPointName){throw new Error(PLUGIN_EXT_POINT_MISSING_ERROR);}const noCall=extensionPointName.startsWith('!');const throws=this.config.throws??extensionPointName.endsWith('!');// eslint-disable-next-line unicorn/better-regex\nextensionPointName=extensionPointName.replace(/(^!|!$)/g,'');if(!extensionPointName){throw new Error(PLUGIN_EXT_POINT_INVALID_ERROR);}const extensionPointNameParts=extensionPointName.split('.');extensionPointNameParts.pop();const pluginMethodPath=extensionPointNameParts.join('.');const pluginsToInvoke=allowMultiple?this.getPlugins(extensionPointName):[this.getPlugins(extensionPointName)[0]];return pluginsToInvoke.map(plugin=>{const method=getValueByPath(plugin,extensionPointName);if(!isFunction(method)||noCall){return method;}try{return method.apply(getValueByPath(plugin,pluginMethodPath),args);}catch(err){// When a plugin failed, doesn't break the app\nif(throws){throw err;}else {this.logger.error(PLUGIN_INVOCATION_ERROR(PLUGIN_ENGINE,extensionPointName,plugin.name),err);}}return null;});}invokeSingle(extPoint,...args){return this.invoke(extPoint,false,...args)[0];}invokeMultiple(extPoint,...args){return this.invoke(extPoint,true,...args);}}const defaultPluginEngine=new PluginEngine(defaultLogger,{throws:true});\n\n/**\n * A function to filter and return non cloud mode destinations\n * A destination is considered non cloud mode if it is not a cloud mode destination or if it is a hybrid mode destination\n * @param destination\n *\n * @returns boolean\n */const isNonCloudDestination=destination=>Boolean(destination.config.connectionMode!=='cloud'||destination.config.useNativeSDKToSend===true||// this is the older flag for hybrid mode destinations\ndestination.config.useNativeSDK===true);const isHybridModeDestination=destination=>Boolean(destination.config.connectionMode==='hybrid'||destination.config.useNativeSDKToSend===true);/**\n * A function to filter and return non cloud mode destinations\n * @param destinations\n *\n * @returns destinations\n */const getNonCloudDestinations=destinations=>destinations.filter(isNonCloudDestination);/**\n * A function to get the user friendly id for a destination\n * Replaces all spaces with hyphens and appends the id to the display name\n * @param displayName The display name of the destination\n * @param id The id of the destination\n *\n * @returns the user friendly id\n */const getDestinationUserFriendlyId=(displayName,id)=>`${displayName.replaceAll(' ','-')}___${id}`;\n\n/**\n * List of plugin names that are loaded as dynamic imports in modern builds\n */const pluginNamesList=['BeaconQueue','CustomConsentManager','DeviceModeDestinations','DeviceModeTransformation','ExternalAnonymousId','GoogleLinker','IubendaConsentManager','KetchConsentManager','NativeDestinationQueue','OneTrustConsentManager','StorageEncryption','StorageEncryptionLegacy','StorageMigrator','XhrQueue'];const deprecatedPluginsList=['Bugsnag','ErrorReporting'];\n\nconst COOKIE_STORAGE='cookieStorage';const LOCAL_STORAGE='localStorage';const SESSION_STORAGE='sessionStorage';const MEMORY_STORAGE='memoryStorage';const NO_STORAGE='none';const STORAGE_TEST_COOKIE='test_rudder_cookie';const STORAGE_TEST_LOCAL_STORAGE='test_rudder_ls';const STORAGE_TEST_SESSION_STORAGE='test_rudder_ss';\n\nconst removeDuplicateSlashes=str=>str.replace(/\\/{2,}/g,'/');/**\n * Checks if provided url is valid or not\n * @param url\n * @returns true if `url` is valid and false otherwise\n */const isValidURL=url=>{if(!isString(url)){return false;}try{// If URL is supported by the browser, we can use it to validate the URL\n// Otherwise, we can at least check if the URL matches the pattern\nif(isFunction(globalThis.URL)){// eslint-disable-next-line no-new\nnew URL(url);}return URL_PATTERN.test(url);}catch(e){return false;}};\n\n/**\n * This function is used to determine if the input status code is retryable.\n * @param status - The status code.\n * @returns True if the status code is not 4xx (except 429), false otherwise.\n */const isErrRetryable=status=>{if(status===429){return true;}return !(status>=400&&status<500);};\n\n/**\n * Encode.\n */const encode=(value,logger)=>{try{return encodeURIComponent(value);}catch(err){logger?.error(COOKIE_DATA_ENCODING_ERROR,err);return undefined;}};/**\n * Decode\n */const decode$1=value=>{try{return decodeURIComponent(value);}catch(err){// Do nothing as non-RS SDK cookies may not be URI encoded\nreturn undefined;}};/**\n * Parse cookie `str`\n */const parse=str=>{const obj={};const pairs=str.split(/\\s*;\\s*/);let pair;if(!pairs[0]){return obj;}// TODO: Decode only the cookies that are needed by the SDK\npairs.forEac
1h(pairItem=>{pair=pairItem.split('=');const keyName=pair[0]?decode$1(pair[0]):undefined;if(keyName){obj[keyName]=pair[1]?decode$1(pair[1]):undefined;}});return obj;};/**\n * Set cookie `name` to `value`\n */const set=(name,value,optionsConfig,logger)=>{const options={...(optionsConfig||{})};let cookieString=`${encode(name,logger)}=${encode(value,logger)}`;if(isNull(value)){options.maxage=-1;}if(options.maxage){options.expires=new Date(+new Date()+options.maxage);}if(options.path){cookieString+=`; path=${options.path}`;}if(options.domain){cookieString+=`; domain=${options.domain}`;}if(options.expires){cookieString+=`; expires=${options.expires.toUTCString()}`;}if(options.samesite){cookieString+=`; samesite=${options.samesite}`;}if(options.secure){cookieString+=`; secure`;}globalThis.document.cookie=cookieString;};/**\n * Return all cookies\n */const all=()=>{const cookieStringValue=globalThis.document.cookie;return parse(cookieStringValue);};/**\n * Get cookie `name`\n */const get=name=>all()[name];/**\n * Set or get cookie `name` with `value` and `options` object\n */// eslint-disable-next-line func-names\nconst cookie=function(name,value,options,logger){switch(arguments.length){case 4:case 3:case 2:return set(name,value,options,logger);case 1:if(name){return get(name);}return all();default:return all();}};\n\nconst userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserIdKey='rl_anonymous_id';const groupIdKey='rl_group_id';const groupTraitsKey='rl_group_trait';const pageInitialReferrerKey='rl_page_init_referrer';const pageInitialReferringDomainKey='rl_page_init_referring_domain';const sessionInfoKey='rl_session';const authTokenKey='rl_auth_token';const COOKIE_KEYS={userId:userIdKey,userTraits:userTraitsKey,anonymousId:anonymousUserIdKey,groupId:groupIdKey,groupTraits:groupTraitsKey,initialReferrer:pageInitialReferrerKey,initialReferringDomain:pageInitialReferringDomainKey,sessionInfo:sessionInfoKey,authToken:authTokenKey};const ENCRYPTION_PREFIX_V3='RS_ENC_v3_';\n\nconst encryptBrowser=value=>`${ENCRYPTION_PREFIX_V3}${toBase64(value)}`;const decryptBrowser=value=>{if(value?.startsWith(ENCRYPTION_PREFIX_V3)){return fromBase64(value.substring(ENCRYPTION_PREFIX_V3.length));}return value;};\n\nconst EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB\nconst RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;\n\nconst isStorageQuotaExceeded=e=>{const matchingNames=['QuotaExceededError','NS_ERROR_DOM_QUOTA_REACHED'];// Everything except Firefox, Firefox\nconst matchingCodes=[22,1014];if(e instanceof DOMException){return matchingNames.includes(e.name)||matchingCodes.includes(e.code);}return false;};// TODO: also check for SecurityErrors\n// https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage#exceptions\nconst isStorageAvailable=(type=LOCAL_STORAGE,storageInstance,logger)=>{let storage;let testData;const msgPrefix=STORAGE_UNAVAILABILITY_ERROR_PREFIX(CAPABILITIES_MANAGER,type);let reason='unavailable';let isAccessible=true;let errObj;try{switch(type){case MEMORY_STORAGE:return true;case COOKIE_STORAGE:storage=storageInstance;testData=STORAGE_TEST_COOKIE;break;case LOCAL_STORAGE:storage=storageInstance??globalThis.localStorage;testData=STORAGE_TEST_LOCAL_STORAGE;// was STORAGE_TEST_LOCAL_STORAGE in ours and generateUUID() in segment retry one\nbreak;case SESSION_STORAGE:storage=storageInstance??globalThis.sessionStorage;testData=STORAGE_TEST_SESSION_STORAGE;break;default:return false;}if(storage){storage.setItem(testData,'true');if(storage.getItem(testData)){storage.removeItem(testData);return true;}}isAccessible=false;}catch(err){isAccessible=false;errObj=err;if(isStorageQuotaExceeded(err)){reason='full';}}if(!isAccessible){logger?.warn(`${msgPrefix}${reason}.`,errObj);}// if we've have reached here, it means the storage is not available\nreturn false;};\n\nconst EVENT_PAYLOAD_SIZE_CHECK_FAIL_WARNING=(context,payloadSize,sizeLimit)=>`${context}${LOG_CONTEXT_SEPARATOR}The size of the event payload (${payloadSize} bytes) exceeds the maximum limit of ${sizeLimit} bytes. Events with large payloads may be dropped in the future. Please review your instrumentation to ensure that event payloads are within the size limit.`;
1const EVENT_PAYLOAD_SIZE_VALIDATION_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to validate event payload size. Please make sure that the event payload is within the size limit and is a valid JSON object.`;const QUEUE_UTILITIES='QueueUtilities';/**\n * Utility to get the stringified event payload\n * @param event RudderEvent object\n * @param logger Logger instance\n * @returns stringified event payload. Empty string if error occurs.\n */const getDeliveryPayload=(event,logger)=>stringifyWithoutCircular(event,true,undefined,logger);const getDMTDeliveryPayload=(dmtRequestPayload,logger)=>stringifyWithoutCircular(dmtRequestPayload,true,undefined,logger);/**\n * Utility to validate final payload size before sending to server\n * @param event RudderEvent object\n * @param logger Logger instance\n */const validateEventPayloadSize=(event,logger)=>{const payloadStr=getDeliveryPayload(event,logger);if(payloadStr){const payloadSize=payloadStr.length;if(payloadSize>EVENT_PAYLOAD_SIZE_BYTES_LIMIT){logger?.warn(EVENT_PAYLOAD_SIZE_CHECK_FAIL_WARNING(QUEUE_UTILITIES,payloadSize,EVENT_PAYLOAD_SIZE_BYTES_LIMIT));}}else {logger?.warn(EVENT_PAYLOAD_SIZE_VALIDATION_WARNING(QUEUE_UTILITIES));}};/**\n * Mutates the event and return final event for delivery\n * Updates certain parameters like sentAt timestamp, integrations config etc.\n * @param event RudderEvent object\n * @returns Final event ready to be delivered\n */const getFinalEventForDeliveryMutator=(event,currentTime)=>{const finalEvent=clone(event);// Update sentAt timestamp to the latest timestamp\nfinalEvent.sentAt=currentTime;return finalEvent;};/**\n * Utility to get the storage type for events persistence\n * If local storage is available, use it; else, fall back to session storage; else, fall back to memory storage.\n * On some browsers, persistence storage is blocked for the JS SDK that is loaded from RS domains.\n * In such cases, we need to verify all the storage types and use the first one that is available.\n * @param logger Logger instance for logging storage availability warnings\n * @returns StorageType\n */const getStorageTypeForEventsPersistence=logger=>{if(isStorageAvailable(LOCAL_STORAGE,undefined,logger)){return LOCAL_STORAGE;}if(isStorageAvailable(SESSION_STORAGE,undefined,logger)){return SESSION_STORAGE;}// Don't use cookie storage as it can potentially cause overhead with the network requests.\n// Note that events will not be persisted across page reloads in this case.\nreturn MEMORY_STORAGE;};\n\nconst QueueStatuses={IN_PROGRESS:'inProgress',QUEUE:'queue',RECLAIM_START:'reclaimStart',RECLAIM_END:'reclaimEnd',ACK:'ack',BATCH_QUEUE:'batchQueue'};\n\nconst BEACON_PLUGIN_EVENTS_QUEUE_DEBUG=context=>`${context}${LOG_CONTEXT_SEPARATOR}Sending events to data plane.`;const BEACON_QUEUE_STRING_CONVERSION_FAILURE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to convert events batch object to string.`;const BEACON_QUEUE_BLOB_CONVERSION_FAILURE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to convert events batch object to Blob.`;const BEACON_QUEUE_SEND_ERROR=(context,url)=>`${context}${LOG_CONTEXT_SEPARATOR}${BEACON_QUEUE_DELIVERY_ERROR(url)}`;const BEACON_QUEUE_DELIVERY_ERROR=url=>`Failed to send events batch data to the browser's beacon queue for URL ${url}.`;\n\nconst DEFAULT_BEACON_QUEUE_MAX_SIZE=10;const DEFAULT_BEACON_QUEUE_FLUSH_INTERVAL_MS=10*60*1000;// 10 minutes\n// Limit of the Beacon transfer mechanism on the browsers\nconst MAX_BATCH_PAYLOAD_SIZE_BYTES=64*1024;// 64 KB\nconst DEFAULT_BEACON_QUEUE_OPTIONS={maxItems:DEFAULT_BEACON_QUEUE_MAX_SIZE,flushQueueInterval:DEFAULT_BEACON_QUEUE_FLUSH_INTERVAL_MS};const DATA_PLANE_API_VERSION$1='v1';const QUEUE_NAME$3='rudder_beacon';const BEACON_QUEUE_PLUGIN='BeaconQueuePlugin';\n\n/**\n * Utility to get the stringified event payload as Blob\n * @param events RudderEvent object array\n * @param logger Logger instance\n * @returns stringified events payload as Blob, undefined if error occurs.\n */const getBatchDeliveryPayload$1=(events,currentTime,logger)=>{const data={batch:events,sentAt:currentTime};try{const blobPayload=stringifyWithoutCircular(data,true);const blobOptions={type:'text/plain'};if(blobPayload){return new Blob([blobPayload],blobOptions);}logger?.error(BEACON_QUEUE_STRING_CONVERSION_FAILURE_ERROR(BEACON_QUEUE_PLUGIN));}catch(err){logger?.error(BEACON_QUEUE_BLOB_CONVERSION_FAILURE_ERROR(BEACON_QUEUE_PLUGIN),err);}return undefined;};const getNormalizedBeaconQueueOptions=queueOpts=>mergeDeepRight(DEFAULT_BEACON_QUEUE_OPTIONS,queueOpts);const getDeliveryUrl$1=(dataplaneUrl,writeKey)=>{const dpUrl=new URL(dataplaneUrl);return new URL(removeDuplicateSlashes([dpUrl.pathname,'/','beacon','/',DATA_PLANE_API_VERSION$1,'/',`batch?writeKey=${writeKey}`].join('')),dpUrl).href;};\n\nlet ScheduleModes=/*#__PURE__*/function(ScheduleModes){ScheduleModes[ScheduleModes[\"ASAP\"]=1]=\"ASAP\";ScheduleModes[ScheduleModes[\"RESCHEDULE\"]=2]=\"RESCHEDULE\";ScheduleModes[ScheduleModes[\"ABANDON\"]=3]=\"ABANDON\";return ScheduleModes;}({});const DEFAULT_CLOCK_LATE_FACTOR=2;const DEFAULT_CLOCK={setTimeout(fn,ms){return globalThis.setTimeout(fn,ms);},clearTimeout(id){return globalThis.clearTimeout(id);}
1,Date:globalThis.Date,clockLateFactor:DEFAULT_CLOCK_LATE_FACTOR};class Schedule{constructor(){this.tasks={};this.nextId=1;this.clock=DEFAULT_CLOCK;}now(){return +new this.clock.Date();}run(task,timeout,mode){if(this.nextId===Number.MAX_SAFE_INTEGER){this.nextId=1;}const id=(this.nextId++).toString();this.tasks[id]=this.clock.setTimeout(this.handle(id,task,timeout,mode||ScheduleModes.ASAP),timeout);return id;}handle(id,callback,timeout,mode){const start=this.now();return ()=>{delete this.tasks[id];const elapsedTimeoutTime=start+timeout*(this.clock.clockLateFactor||DEFAULT_CLOCK_LATE_FACTOR);const currentTime=this.now();const notCompletedOrTimedOut=mode>=ScheduleModes.RESCHEDULE&&elapsedTimeoutTime<currentTime;if(notCompletedOrTimedOut){if(mode===ScheduleModes.RESCHEDULE){this.run(callback,timeout,mode);}return undefined;}return callback();};}cancel(id){if(this.tasks[id]){this.clock.clearTimeout(this.tasks[id]);delete this.tasks[id];}}cancelAll(){Object.values(this.tasks).forEach(this.clock.clearTimeout);this.tasks={};}}\n\nconst RETRY_QUEUE_PROCESS_ERROR=(context,errMsg)=>`${context}${LOG_CONTEXT_SEPARATOR}An unknown error occurred while processing the queue item. ${errMsg}`;const RETRY_QUEUE_ENTRY_REMOVE_ERROR=(context,entry,attempt)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to remove local storage entry \"${entry}\" (attempt: ${attempt}.`;\n\nconst DEFAULT_MIN_RETRY_DELAY_MS=1000;const DEFAULT_MAX_RETRY_DELAY_MS=30000;const DEFAULT_BACKOFF_FACTOR=2;const DEFAULT_BACKOFF_JITTER=0;const DEFAULT_MAX_RETRY_ATTEMPTS=Infinity;const DEFAULT_MAX_ITEMS=Infinity;const DEFAULT_ACK_TIMER_MS=1000;const DEFAULT_RECLAIM_TIMER_MS=3000;const DEFAULT_RECLAIM_TIMEOUT_MS=10000;const DEFAULT_RECLAIM_WAIT_MS=500;const MIN_TIMER_SCALE_FACTOR=1;const MAX_TIMER_SCALE_FACTOR=10;const DEFAULT_MAX_BATCH_SIZE_BYTES=512*1024;// 512 KB; this is also the max size of a batch\nconst DEFAULT_MAX_BATCH_ITEMS=100;const DEFAULT_BATCH_FLUSH_INTERVAL_MS=60*1000;// 1 minutes\nconst BATCH_QUEUE_ITEM_TYPE='Batch';const SINGLE_QUEUE_ITEM_TYPE='Single';\n\nconst sortByTime=(a,b)=>a.time-b.time;const RETRY_QUEUE='RetryQueue';class RetryQueue{/**\n * Constructs a RetryQueue backed by localStorage\n *\n * @param {String} name The name of the queue. Will be used to find abandoned queues and retry their items\n * @param {QueueOpts} [options] Optional argument to override `maxItems`, `maxAttempts`, `minRetryDelay, `maxRetryDelay`, `backoffFactor` and `backoffJitter`.\n * @param {QueueProcessCallback} queueProcessCb The function to call in order to process an item added to the queue\n * @param {IStoreManager} storeManager The store manager instance to use\n * @param {StorageType} [storageType] The storage type to use. Defaults to LOCAL_STORAGE\n * @param {ILogger} [logger] The logger to use\n * @param {QueueBatchItemsSizeCalculatorCallback} [queueBatchItemsSizeCalculatorCb] The callback to use to calculate the size of items in the batch queue\n */constructor(name,options,queueProcessCb,storeManager,storageType=LOCAL_STORAGE,logger,queueBatchItemsSizeCalculatorCb){this.storeManager=storeManager;this.logger=logger;this.name=name;this.id=generateUUID();this.processQueueCb=queueProcessCb;this.batchSizeCalcCb=queueBatchItemsSizeCalculatorCb;this.maxItems=options.maxItems||DEFAULT_MAX_ITEMS;this.maxAttempts=options.maxAttempts||DEFAULT_MAX_RETRY_ATTEMPTS;this.batch={enabled:false};this.configureBatchMode(options);this.backoff={minRetryDelay:options.minRetryDelay||DEFAULT_MIN_RETRY_DELAY_MS,maxRetryDelay:options.maxRetryDelay||DEFAULT_MAX_RETRY_DELAY_MS,factor:options.backoffFactor||DEFAULT_BACKOFF_FACTOR,jitter:options.backoffJitter||DEFAULT_BACKOFF_JITTER};// Limit the timer scale factor to the minimum value\nlet timerScaleFactor=Math.max(options.timerScaleFactor??MIN_TIMER_SCALE_FACTOR,MIN_TIMER_SCALE_FACTOR);// Limit the timer scale factor to the maximum value\ntimerScaleFactor=Math.min(timerScaleFactor,MAX_TIMER_SCALE_FACTOR);// painstakingly tuned. that's why they're not \"easily\" configurable\nthis.timeouts={ackTimer:Math.round(timerScaleFactor*DEFAULT_ACK_TIMER_MS),reclaimTimer:Math.round(timerScaleFactor*DEFAULT_RECLAIM_TIMER_MS),reclaimTimeout:Math.round(timerScaleFactor*DEFAULT_RECLAIM_TIMEOUT_MS),reclaimWait:Math.round(timerScaleFactor*DEFAULT_RECLAIM_WAIT_MS)};this.schedule=new Schedule();this.processId='0';// Set up our empty queues\nthis.store=this.storeManager.setStore({id:this.id,name:this.name,validKeys:QueueStatuses,type:storageType,errorHandler:this.storeManager.errorHandler,logger:this.storeManager.logger});this.setDefaultQueueEntries();// bind recurring tasks for ease of use\nthis.ack=this.ack.bind(this);this.checkReclaim=this.checkReclaim.bind(this);this.processHead=this.processHead.bind(this);this.flushBatch=this.flushBatch.bind(this);this.isPageAccessible=true;// Flush the queue on page leave\nthis.flushBatchOnPageLeave();this.scheduleTimeoutActive=false;}setDefaultQueueEntries(){this.setStorageEntry(QueueStatuses.IN_PROGRESS,{});this.setStorageEntry(QueueStatuses.QUEUE,[]);this.setStorageEntry(QueueStatuses.BATCH_QUEUE,[]);}configureBatchMode(options){this.batchingInProgress=false;if(!isObjectLiteralAndNotNull(options.batch)){return;}const batchOptions=options.batch;this.batch.enabled=batchOptions.enabled===true;
1if(this.batch.enabled){// Set upper cap on the batch payload size\nthis.batch.maxSize=Math.min(batchOptions.maxSize??DEFAULT_MAX_BATCH_SIZE_BYTES,DEFAULT_MAX_BATCH_SIZE_BYTES);this.batch.maxItems=batchOptions.maxItems??DEFAULT_MAX_BATCH_ITEMS;this.batch.flushInterval=batchOptions.flushInterval??DEFAULT_BATCH_FLUSH_INTERVAL_MS;}}flushBatchOnPageLeave(){if(this.batch.enabled){onPageLeave(this.flushBatch);}}getStorageEntry(name){return this.store.get(name);}// TODO: fix the type of different queues to be the same if possible\nsetStorageEntry(name,value){if(isNullOrUndefined(value)){this.store.remove(name);}else {this.store.set(name,value);}}/**\n * Stops processing the queue\n */stop(){this.schedule.cancelAll();this.scheduleTimeoutActive=false;}/**\n * Starts processing the queue\n */start(){if(this.scheduleTimeoutActive){this.stop();}this.scheduleTimeoutActive=true;this.scheduleFlushBatch();this.ack();this.checkReclaim();this.processHead();}/**\n * Configures the timeout handler for flushing the batch queue\n */scheduleFlushBatch(){if(this.batch.enabled&&this.batch?.flushInterval){if(this.flushBatchTaskId){this.schedule.cancel(this.flushBatchTaskId);}this.flushBatchTaskId=this.schedule.run(this.flushBatch,this.batch.flushInterval,ScheduleModes.ASAP);}}/**\n * Flushes the batch queue\n */flushBatch(isAccessible=true){if(!this.batchingInProgress){this.isPageAccessible=isAccessible;this.batchingInProgress=true;let batchQueue=this.getStorageEntry(QueueStatuses.BATCH_QUEUE)??[];if(batchQueue.length>0){batchQueue=batchQueue.slice(-batchQueue.length);const batchEntry=this.genQueueItem(batchQueue.map(queueItem=>queueItem.item),BATCH_QUEUE_ITEM_TYPE);this.setStorageEntry(QueueStatuses.BATCH_QUEUE,[]);this.pushToMainQueue(batchEntry);}this.batchingInProgress=false;// Re-schedule the flush task\nthis.scheduleFlushBatch();}}/**\n * Decides whether to retry. Overridable.\n *\n * @param {Object} item The item being processed\n * @param {Number} attemptNumber The attemptNumber (1 for first retry)\n * @return {Boolean} Whether to requeue the message\n */shouldRetry(item,attemptNumber){return attemptNumber<=this.maxAttempts;}/**\n * Calculates the delay (in ms) for a retry attempt\n *\n * @param {Number} attemptNumber The attemptNumber (1 for first retry)\n * @return {Number} The delay in milliseconds to wait before attempting a retry\n */getDelay(attemptNumber){let ms=this.backoff.minRetryDelay*this.backoff.factor**attemptNumber;if(this.backoff.jitter){const rand=Math.random();const deviation=Math.floor(rand*this.backoff.jitter*ms);if(Math.floor(rand*10)<5){ms-=deviation;}else {ms+=deviation;}}return Number(Math.min(ms,this.backoff.maxRetryDelay).toPrecision(1));}enqueue(entry){let curEntry;if(this.batch.enabled&&entry.type===SINGLE_QUEUE_ITEM_TYPE){curEntry=this.handleNewItemForBatch(entry);}else {curEntry=entry;}// when batching is enabled, `curEntry` could be `undefined` if the batch criteria is not met\nif(curEntry){this.pushToMainQueue(curEntry);}}/**\n * Handles a new item added to the retry queue when batching is enabled\n * @param entry New item added to the retry queue\n * @returns Undefined or batch entry object\n */handleNewItemForBatch(entry){let curEntry;let batchQueue=this.getStorageEntry(QueueStatuses.BATCH_QUEUE)??[];if(!this.batchingInProgress){this.batchingInProgress=true;batchQueue=batchQueue.slice(-batchQueue.length);batchQueue.push(entry);const batchDispatchInfo=this.getBatchDispatchInfo(batchQueue);// if batch criteria is met, queue the batch events to the main queue and clear batch queue\nif(batchDispatchInfo.criteriaMet||batchDispatchInfo.criteriaExceeded){let batchEntries;if(batchDispatchInfo.criteriaExceeded){batchEntries=batchQueue.slice(0,batchQueue.length-1);batchQueue=[entry];}else {batchEntries=batchQueue;batchQueue=[];}// Don't make any batch request if there are no items\nif(batchEntries.length>0){const isReclaimed=batchEntries.every(queueItem=>queueItem.reclaimed);const batchItems=batchEntries.map(queueItem=>queueItem.item);if(isReclaimed){curEntry=this.genQueueItem(batchItems,BATCH_QUEUE_ITEM_TYPE,true);}else {curEntry=this.genQueueItem(batchItems,BATCH_QUEUE_ITEM_TYPE);}}
1// re-attach the timeout handler\nthis.scheduleFlushBatch();}this.batchingInProgress=false;}else {batchQueue.push(entry);}// update the batch queue\nthis.setStorageEntry(QueueStatuses.BATCH_QUEUE,batchQueue);return curEntry;}pushToMainQueue(curEntry){let queue=this.getStorageEntry(QueueStatuses.QUEUE)??[];if(this.maxItems>1){queue=queue.slice(-(this.maxItems-1));}else {queue=[];}queue.push(curEntry);queue=queue.sort(sortByTime);this.setStorageEntry(QueueStatuses.QUEUE,queue);if(this.scheduleTimeoutActive){this.processHead();}}/**\n * Adds an item to the queue\n *\n * @param {Object} itemData The item to process\n */addItem(itemData){this.enqueue(this.genQueueItem(itemData));}/**\n * Generates a queue item\n * @param itemData Queue item data\n * @returns Queue item\n */genQueueItem(itemData,type=SINGLE_QUEUE_ITEM_TYPE,reclaimed){return {item:itemData,attemptNumber:0,time:this.schedule.now(),id:generateUUID(),type,...(isDefined(reclaimed)?{reclaimed}:{})};}/**\n * Adds an item to the retry queue\n *\n * @param {Object} qItem The item to process\n */requeue(qItem){const{attemptNumber,item,type,id,firstAttemptedAt,lastAttemptedAt,reclaimed,retryReason}=qItem;// Increment the attempt number as we're about to retry\nconst attemptNumberToUse=attemptNumber+1;if(this.shouldRetry(item,attemptNumberToUse)){this.enqueue({item,attemptNumber:attemptNumberToUse,time:this.schedule.now()+this.getDelay(attemptNumberToUse),id:id??generateUUID(),type,firstAttemptedAt,lastAttemptedAt,reclaimed,retryReason});}}/**\n * Returns the information about whether the batch criteria is met or exceeded\n * @param batchItems Prospective batch items\n * @returns Batch dispatch info\n */getBatchDispatchInfo(batchItems){let lengthCriteriaMet=false;let lengthCriteriaExceeded=false;const configuredBatchMaxItems=this.batch?.maxItems;if(isDefined(configuredBatchMaxItems)){lengthCriteriaMet=batchItems.length===configuredBatchMaxItems;lengthCriteriaExceeded=batchItems.length>configuredBatchMaxItems;}if(lengthCriteriaMet||lengthCriteriaExceeded){return {criteriaMet:lengthCriteriaMet,criteriaExceeded:lengthCriteriaExceeded};}let sizeCriteriaMet=false;let sizeCriteriaExceeded=false;const configuredBatchMaxSize=this.batch?.maxSize;if(isDefined(configuredBatchMaxSize)&&isDefined(this.batchSizeCalcCb)){const curBatchSize=this.batchSizeCalcCb(batchItems.map(queueItem=>queueItem.item));sizeCriteriaMet=curBatchSize===configuredBatchMaxSize;sizeCriteriaExceeded=curBatchSize>configuredBatchMaxSize;}return {criteriaMet:sizeCriteriaMet,criteriaExceeded:sizeCriteriaExceeded};}processHead(){// cancel the scheduled task if it exists\nthis.schedule.cancel(this.processId);// Pop the head off the queue\nlet queue=this.getStorageEntry(QueueStatuses.QUEUE)??[];const now=this.schedule.now();const toRun=[];// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst processItemCallback=(el,id)=>(err,res)=>{const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};const inProgressItem=inProgress[id];const firstAttemptedAt=inProgressItem?.firstAttemptedAt;const lastAttemptedAt=inProgressItem?.lastAttemptedAt;delete inProgress[id];this.setStorageEntry(QueueStatuses.IN_PROGRESS,inProgress);if(err){this.requeue({...el,firstAttemptedAt,lastAttemptedAt,retryReason:res?.retryReason??DEFAULT_RETRY_REASON});}};const enqueueItem=(el,id)=>{toRun.push({id,item:el.item,done:processItemCallback(el,id),attemptNumber:el.attemptNumber});};const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};let inProgressSize=Object.keys(inProgress).length;// eslint-disable-next-line no-plusplus\nwhile(queue.length>0&&queue[0].time<=now&&inProgressSize++<this.maxItems){const el=queue.shift();if(el){const id=generateUUID();// Save this to the in progress map\ninProgress[id]={item:el.item,attemptNumber:el.attemptNumber,time:this.schedule.now(),type:el.type,firstAttemptedAt:el.firstAttemptedAt,lastAttemptedAt:el.lastAttemptedAt,reclaimed:el.reclaimed};enqueueItem(el,id);}}this.setStorageEntry(QueueStatuses.QUEUE,queue);this.setStorageEntry(QueueStatuses.IN_PROGRESS,inProgress);
1toRun.forEach(el=>{// TODO: handle processQueueCb timeout\ntry{const now=this.schedule.now();const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};const inProgressItem=inProgress[el.id];let firstAttemptedAt=now;let lastAttemptedAt=now;let reclaimed=false;let retryReason=DEFAULT_RETRY_REASON;if(inProgressItem){retryReason=inProgressItem.retryReason??retryReason;firstAttemptedAt=inProgressItem.firstAttemptedAt??firstAttemptedAt;lastAttemptedAt=inProgressItem.lastAttemptedAt??lastAttemptedAt;// Indicates if the item has been reclaimed from local storage\nreclaimed=inProgressItem.reclaimed??reclaimed;// Update the first attempted at timestamp for the in progress item\ninProgressItem.firstAttemptedAt=firstAttemptedAt;// Update the last attempted at to current timestamp for the in progress item\ninProgressItem.lastAttemptedAt=now;inProgress[el.id]=inProgressItem;this.setStorageEntry(QueueStatuses.IN_PROGRESS,inProgress);}// A decimal integer representing the milliseconds since the first attempt\nconst timeSinceFirstAttempt=now-firstAttemptedAt;// A decimal integer representing the milliseconds since the last attempt\nconst timeSinceLastAttempt=now-lastAttemptedAt;const willBeRetried=this.shouldRetry(el.item,el.attemptNumber+1);this.processQueueCb(el.item,el.done,{retryAttemptNumber:el.attemptNumber,maxRetryAttempts:this.maxAttempts,willBeRetried,timeSinceFirstAttempt,timeSinceLastAttempt,reclaimed,isPageAccessible:this.isPageAccessible,retryReason});}catch(err){let errMsg='';if(el.attemptNumber<this.maxAttempts){errMsg='The item will be requeued.';if(el.attemptNumber>0){errMsg=`${errMsg} Retry attempt ${el.attemptNumber} of ${this.maxAttempts}.`;}// requeue the item to be retried\nel.done(err);}else {errMsg=`Retries exhausted (${this.maxAttempts}). The item will be dropped.`;// drop the event as we're unable to process it\n// after the max attempts are exhausted\nel.done();}this.logger?.error(RETRY_QUEUE_PROCESS_ERROR(RETRY_QUEUE,errMsg),err);}});// re-read the queue in case the process function finished immediately or added another item\nqueue=this.getStorageEntry(QueueStatuses.QUEUE)??[];this.schedule.cancel(this.processId);if(queue.length>0){const nextProcessExecutionTime=queue[0].time-now;this.processId=this.schedule.run(this.processHead,nextProcessExecutionTime,ScheduleModes.ASAP);}}// Ack continuously to prevent other tabs from claiming our queue\nack(){this.setStorageEntry(QueueStatuses.ACK,this.schedule.now());if(this.reclaimStartVal!=null){this.reclaimStartVal=null;this.setStorageEntry(QueueStatuses.RECLAIM_START,null);}if(this.reclaimEndVal!=null){this.reclaimEndVal=null;this.setStorageEntry(QueueStatuses.RECLAIM_END,null);}this.schedule.run(this.ack,this.timeouts.ackTimer,ScheduleModes.ASAP);}reclaim(id){const other=this.storeManager.setStore({id,name:this.name,validKeys:QueueStatuses,type:LOCAL_STORAGE,errorHandler:this.storeManager.errorHandler,logger:this.storeManager.logger});const our={queue:this.getStorageEntry(QueueStatuses.QUEUE)??[]};const their={inProgress:other.get(QueueStatuses.IN_PROGRESS)??{},batchQueue:other.get(QueueStatuses.BATCH_QUEUE)??[],queue:other.get(QueueStatuses.QUEUE)??[]};const trackMessageIds=[];const addConcatQueue=(queue,incrementAttemptNumberBy)=>{const concatIterator=el=>{const id=el.id??generateUUID();if(trackMessageIds.includes(id));else {// Hack to determine the item type by the contents of the entry\n// After some point, we can remove this hack as most of the stale data will have been processed\n// and the new entries will have the type field set\nconst type=Array.isArray(el.item)?BATCH_QUEUE_ITEM_TYPE:SINGLE_QUEUE_ITEM_TYPE;our.queue.push({item:el.item,attemptNumber:el.attemptNumber+incrementAttemptNumberBy,time:this.schedule.now(),id,type:el.type??type,firstAttemptedAt:el.firstAttemptedAt,lastAttemptedAt:el.lastAttemptedAt,retryReason:el.retryReason,// Mark the item as reclaimed from local storage\nreclaimed:true});trackMessageIds.push(id);}};if(Array.isArray(queue)){queue.forEach(concatIterator);}else if(queue){Object.values(queue).forEach(concatIterator);}};// add their queue to ours, resetting run-time to immediate and copying the attempt#\naddConcatQueue(their.queue,0);// Process batch queue items\nif(this.batch.enabled){their.batchQueue.forEach(el=>{const id=el.id??generateUUID();if(trackMessageIds.includes(id));else {this.enqueue({...el,id,retryReason:el.retryReason,// Mark the item as re
1claimed from local storage\nreclaimed:true,type:el.type??SINGLE_QUEUE_ITEM_TYPE,time:this.schedule.now()});trackMessageIds.push(id);}});}else {// if batching is not enabled in the current instance, add those items to the main queue directly\naddConcatQueue(their.batchQueue,0);}// if the queue is abandoned, all the in-progress are failed. retry them immediately and increment the attempt#\naddConcatQueue(their.inProgress,1);our.queue.sort(sortByTime);this.setStorageEntry(QueueStatuses.QUEUE,our.queue);// remove all keys one by on next tick to avoid NS_ERROR_STORAGE_BUSY error\nthis.clearQueueEntries(other,1);// process the new items we claimed\nthis.processHead();}clearQueueEntries(other,localStorageBackoff){this.removeStorageEntry(other,0,localStorageBackoff);}removeStorageEntry(store,entryIdx,backoff,attempt=1){const maxAttempts=2;const queueEntryKeys=Object.keys(QueueStatuses);const entry=QueueStatuses[queueEntryKeys[entryIdx]];globalThis.setTimeout(()=>{try{store.remove(entry);// clear the next entry\nif(entryIdx+1<queueEntryKeys.length){this.removeStorageEntry(store,entryIdx+1,backoff);}}catch(err){const storageBusyErr='NS_ERROR_STORAGE_BUSY';const isLocalStorageBusy=err.name===storageBusyErr||err.code===storageBusyErr||err.code===0x80630001;if(isLocalStorageBusy&&attempt<maxAttempts){// Try clearing the same entry again with some extra delay\nthis.removeStorageEntry(store,entryIdx,backoff+40,attempt+1);}else {this.logger?.error(RETRY_QUEUE_ENTRY_REMOVE_ERROR(RETRY_QUEUE,entry,attempt),err);}// clear the next entry after we've exhausted our attempts\nif(attempt===maxAttempts&&entryIdx+1<queueEntryKeys.length){this.removeStorageEntry(store,entryIdx+1,backoff);}}},backoff);}checkReclaim(){const createReclaimStartTask=store=>()=>{if(store.get(QueueStatuses.RECLAIM_END)!==this.id){return;}if(store.get(QueueStatuses.RECLAIM_START)!==this.id){return;}this.reclaim(store.id);};const createReclaimEndTask=store=>()=>{if(store.get(QueueStatuses.RECLAIM_START)!==this.id){return;}store.set(QueueStatuses.RECLAIM_END,this.id);this.schedule.run(createReclaimStartTask(store),this.timeouts.reclaimWait,ScheduleModes.ABANDON);};const tryReclaim=store=>{store.set(QueueStatuses.RECLAIM_START,this.id);store.set(QueueStatuses.ACK,this.schedule.now());this.schedule.run(createReclaimEndTask(store),this.timeouts.reclaimWait,ScheduleModes.ABANDON);};const findOtherQueues=name=>{const res=[];const storageEngine=this.store.getOriginalEngine();let storageKeys=[];// 'keys' API is not supported by all the core SDK versions\n// Hence, we need this backward compatibility check\nif(isFunction(storageEngine.keys)){storageKeys=storageEngine.keys();}else {for(let i=0;i<storageEngine.length;i++){const key=storageEngine.key(i);if(key){storageKeys.push(key);}}}storageKeys.forEach(k=>{const keyParts=k?k.split('.'):[];if(keyParts.length>=3&&keyParts[0]===name&&keyParts[1]!==this.id&&keyParts[2]===QueueStatuses.ACK){res.push(this.storeManager.setStore({id:keyParts[1],name,validKeys:QueueStatuses,type:LOCAL_STORAGE,errorHandler:this.storeManager.errorHandler,logger:this.storeManager.logger}));}});return res;};findOtherQueues(this.name).forEach(store=>{if(this.schedule.now()-store.get(QueueStatuses.ACK)<this.timeouts.reclaimTimeout){return;}tryReclaim(store);});this.schedule.run(this.checkReclaim,this.timeouts.reclaimTimer,ScheduleModes.RESCHEDULE);}clear(){this.schedule.cancelAll();this.setDefaultQueueEntries();}}\n\nconst pluginName$d='BeaconQueue';const BeaconQueue=()=>({name:pluginName$d,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$d];},dataplaneEventsQueue:{/**\n * Initialize the queue for delivery\n * @param state Application state\n * @param httpClient http client instance\n * @param storeManager Store Manager instance\n * @param errorHandler Error handler instance\n * @param logger Logger instance\n * @returns BeaconItemsQueue instance\n */init(state,httpClient,storeManager,errorHandler,logger){const writeKey=state.lifecycle.writeKey.value;const dataplaneUrl=state.lifecycle.activeDataplaneUrl.value;const url=getDeliveryUrl$1(dataplaneUrl,writeKey);const finalQOpts=getNormalizedBeaconQueueOptions(state.loadOptions.value.beaconQueueOptions??{});const queueProcessCallback=(itemData,done,info)=>{const{isPageAccessible}=info;logger?.debug(BEACON_PLUGIN_EVENTS_QUEUE_DEBUG(BEACON_QUEUE_PLUGIN));const currentTime=getCurrentTimeFormatted();const finalEvents=itemData.map(queueItemData=>getFinalEventForDeliveryMutator(queueItemData.event,currentTime));const data=getBatchDeliveryPayload$1(finalEvents,currentTime,logger);if(!data){// Mark the item as done so that it can be removed from the queue\ndone(null);return;}
1try{if(!navigator.sendBeacon(url,data)){if(isPageAccessible){logger?.error(`${BEACON_QUEUE_SEND_ERROR(BEACON_QUEUE_PLUGIN,url)} The event(s) will be dropped.`);// Remove the item from queue\ndone(null);}else {// Note: We're not removing the item from the queue as we want to retry the request\nlogger?.warn(`${BEACON_QUEUE_SEND_ERROR(BEACON_QUEUE_PLUGIN,url)} The event(s) will be retried as the current page is being unloaded.`);}}else {// Remove the item from queue as the request was successful\ndone(null);}}catch(err){errorHandler?.onError({error:err,context:BEACON_QUEUE_PLUGIN,customMessage:BEACON_QUEUE_DELIVERY_ERROR(url)});// Remove the item from queue\ndone(null);}};const eventsQueue=new RetryQueue(`${QUEUE_NAME$3}_${writeKey}`,{batch:{enabled:true,flushInterval:finalQOpts.flushQueueInterval,maxSize:MAX_BATCH_PAYLOAD_SIZE_BYTES,// set the hard limit\nmaxItems:finalQOpts.maxItems}},queueProcessCallback,storeManager,getStorageTypeForEventsPersistence(logger),logger,itemData=>{const currentTime=getCurrentTimeFormatted();const events=itemData.map(queueItemData=>queueItemData.event);// type casting to Blob as we know that the event has already been validated prior to enqueue\nreturn getBatchDeliveryPayload$1(events,currentTime,logger).size;});return eventsQueue;},/**\n * Add event to the queue for delivery\n * @param state Application state\n * @param eventsQueue IQueue instance\n * @param event RudderEvent object\n * @param errorHandler Error handler instance\n * @param logger Logger instance\n * @returns none\n */enqueue(state,eventsQueue,event,errorHandler,logger){// sentAt is only added here for the validation step\n// It'll be updated to the latest timestamp during actual delivery\nevent.sentAt=getCurrentTimeFormatted();validateEventPayloadSize(event,logger);eventsQueue.addItem({event});}}});\n\nconst CUSTOM_CONSENT_MANAGER_PLUGIN='CustomConsentManagerPlugin';\n\nconst DESTINATION_CONSENT_STATUS_ERROR$3=`Failed to determine the consent status for the destination. Please check the destination configuration and try again.`;\n\nconst pluginName$c='CustomConsentManager';const CustomConsentManager=()=>({name:pluginName$c,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$c];},consentManager:{init(state,logger){// Nothing to initialize\n},updateConsentsInfo(state,storeManager,logger){// Nothing to update. Already provided by the user\n},isDestinationConsented(state,destConfig,errorHandler,logger){if(!state.consents.initialized.value){return true;}const allowedConsentIds=state.consents.data.value.allowedConsentIds;try{const{consentManagement}=destConfig;// If the destination does not have consent management config, events should be sent.\nif(!consentManagement){return true;}// Get the corresponding consents for the destination\nconst cmpConfig=consentManagement.find(c=>c.provider===state.consents.provider.value);// If there are no consents configured for the destination for the current provider, events should be sent.\nif(!cmpConfig?.consents){return true;}const configuredConsents=cmpConfig.consents.map(c=>c.consent.trim()).filter(n=>n);const resolutionStrategy=cmpConfig.resolutionStrategy??state.consents.resolutionStrategy.value;// match the configured consents with user provided consents as per\n// the configured resolution strategy\nconst matchPredicate=consent=>allowedConsentIds.includes(consent);switch(resolutionStrategy){case 'or':return configuredConsents.some(matchPredicate)||configuredConsents.length===0;case 'and':default:return configuredConsents.every(matchPredicate);}}catch(err){errorHandler?.onError({error:err,context:CUSTOM_CONSENT_MANAGER_PLUGIN,customMessage:DESTINATION_CONSENT_STATUS_ERROR$3});return true;}}}});\n\nconst READY_CHECK_TIMEOUT_MS=11*1000;// 11 seconds\nconst SCRIPT_LOAD_TIMEOUT_MS=10*1000;// 10 seconds\nconst READY_CHECK_INTERVAL_MS=100;// 100 milliseconds\nconst DEVICE_MODE_DESTINATIONS_PLUGIN='DeviceModeDestinationsPlugin';\n\nconst INTEGRATION_NOT_SUPPORTED_ERROR=destDisplayName=>`Integration for destination \"${destDisplayName}\" is not supported.`;const INTEGRATION_SDK_LOAD_ERROR=destDisplayName=>`Failed to load integration SDK for destination \"${destDisplayName}\"`;const INTEGRATION_INIT_ERROR=destUserFriendlyId=>`Failed to initialize integration for destination \"${destUserFriendlyId}\".`;const INTEGRATIONS_DATA_ERROR=destUserFriendlyId=>`Failed to get integrations data for destination \"${destUserFriendlyId}\".`;const INTEGRATION_READY_TIMEOUT_ERROR=timeout=>`A timeout of ${timeout} ms occurred`;const INTEGRATION_READY_CHECK_ERROR=id=>`Failed to get the ready status from integration for destination \"${id}\"`;
1const CUSTOM_INTEGRATION_INVALID_DESTINATION_ID_ERROR=(context,destinationId)=>`${context}${LOG_CONTEXT_SEPARATOR}The destination ID \"${destinationId}\" does not correspond to a custom device mode destination.`;const CUSTOM_INTEGRATION_ALREADY_EXISTS_ERROR=(context,destinationId)=>`${context}${LOG_CONTEXT_SEPARATOR}A custom integration with destination ID \"${destinationId}\" was already added.`;const INVALID_CUSTOM_INTEGRATION_ERROR=(context,destinationId)=>`${context}${LOG_CONTEXT_SEPARATOR}The custom integration added for destination ID \"${destinationId}\" does not match the expected implementation format.`;const INTEGRATION_NOT_ADDED_TO_CUSTOM_DESTINATION_WARNING=(context,destinationId)=>`${context}${LOG_CONTEXT_SEPARATOR}No valid custom integration was added for destination ID \"${destinationId}\". Ignoring it.`;\n\nconst isDestIntgConfigTruthy=destIntgConfig=>!isUndefined(destIntgConfig)&&Boolean(destIntgConfig)===true;const isDestIntgConfigFalsy=destIntgConfig=>!isUndefined(destIntgConfig)&&Boolean(destIntgConfig)===false;/**\n * Filters the destinations that should not be loaded or forwarded events to based on the integration options (load or events API)\n * @param intgOpts Integration options object\n * @param destinations Destinations array\n * @returns Destinations array filtered based on the integration options\n */const filterDestinations=(intgOpts,destinations)=>{const allOptVal=intgOpts.All??true;return destinations.filter(dest=>{const destDisplayName=dest.displayName;let isDestEnabled;if(allOptVal){isDestEnabled=true;if(isDestIntgConfigFalsy(intgOpts[destDisplayName])){isDestEnabled=false;}}else {isDestEnabled=false;if(isDestIntgConfigTruthy(intgOpts[destDisplayName])){isDestEnabled=true;}}return isDestEnabled;});};\n\nconst ACTIVE_CAMPAIGN_DISPLAY_NAME='ActiveCampaign';const ADOBE_ANALYTICS_DISPLAY_NAME='Adobe Analytics';const ADROLL_DISPLAY_NAME='Adroll';const AM_DISPLAY_NAME='Amplitude';const APPCUES_DISPLAY_NAME='Appcues';const AXEPTIO_DISPLAY_NAME='Axeptio';const BINGADS_DISPLAY_NAME='Bing Ads';const BRAZE_DISPLAY_NAME='Braze';const BUGSNAG_DISPLAY_NAME='Bugsnag';const CHARTBEAT_DISPLAY_NAME='Chartbeat';const CLEVERTAP_DISPLAY_NAME='CleverTap';const COMMANDBAR_DISPLAY_NAME='CommandBar';const COMSCORE_DISPLAY_NAME='Comscore';const CONVERTFLOW_DISPLAY_NAME='Convertflow';const CRITEO_DISPLAY_NAME='Criteo';const CUSTOMERIO_DISPLAY_NAME='Customer IO';const DCM_FLOODLIGHT_DISPLAY_NAME='DCM Floodlight';const DRIP_DISPLAY_NAME='Drip';const ENGAGE_DISPLAY_NAME='Engage';const FACEBOOK_PIXEL_DISPLAY_NAME='Facebook Pixel';const FULLSTORY_DISPLAY_NAME='Fullstory';const GA_DISPLAY_NAME='Google Analytics';const GA360_DISPLAY_NAME='Google Analytics 360';const GA4_DISPLAY_NAME='Google Analytics 4 (GA4)';const GA4_V2_DISPLAY_NAME='Google Analytics 4 (GA4) V2';const GAINSIGHT_PX_DISPLAY_NAME='Gainsight PX';const GOOGLE_OPTIMIZE_DISPLAY_NAME='Google Optimize';const GOOGLEADS_DISPLAY_NAME='Google Ads';const GTM_DISPLAY_NAME='Google Tag Manager';const HEAP_DISPLAY_NAME='Heap.io';const HOTJAR_DISPLAY_NAME='Hotjar';const HS_DISPLAY_NAME='HubSpot';const INTERCOM_DISPLAY_NAME='Intercom';const ITERABLE_DISPLAY_NAME='Iterable';const JUNE_DISPLAY_NAME='JUNE';const KEEN_DISPLAY_NAME='Keen';const KISSMETRICS_DISPLAY_NAME='Kiss Metrics';const KLAVIYO_DISPLAY_NAME='Klaviyo';const LAUNCHDARKLY_DISPLAY_NAME='LaunchDarkly';const LEMNISK_DISPLAY_NAME='Lemnisk Marketing Automation';const LINKEDIN_INSIGHT_TAG_DISPLAY_NAME='Linkedin Insight Tag';const LIVECHAT_DISPLAY_NAME='livechat';const LOTAME_DISPLAY_NAME='Lotame';const LYTICS_DISPLAY_NAME='Lytics';const MATOMO_DISPLAY_NAME='Matomo';const MICROSOFT_CLARITY_DISPLAY_NAME='Microsoft Clarity';const MOENGAGE_DISPLAY_NAME='MoEngage';const MOUSEFLOW_DISPLAY_NAME='Mouseflow';const MP_DISPLAY_NAME='Mixpanel';const NINETAILED_DISPLAY_NAME='Ninetailed';const OLARK_DISPLAY_NAME='Olark';const OPTIMIZELY_DISPLAY_NAME='Optimizely Web';const PENDO_DISPLAY_NAME='Pendo';const PINTEREST_TAG_DISPLAY_NAME='Pinterest Tag';const PODSIGHTS_DISPLAY_NAME='Podsights';
1const POST_AFFILIATE_PRO_DISPLAY_NAME='Post Affiliate Pro';const POSTHOG_DISPLAY_NAME='PostHog';const PROFITWELL_DISPLAY_NAME='ProfitWell';const QUALAROO_DISPLAY_NAME='Qualaroo';const QUALTRICS_DISPLAY_NAME='Qualtrics';const QUANTUMMETRIC_DISPLAY_NAME='Quantum Metric';const QUORA_PIXEL_DISPLAY_NAME='Quora Pixel';const REDDIT_PIXEL_DISPLAY_NAME='Reddit Pixel';const REFINER_DISPLAY_NAME='Refiner';const ROCKERBOX_DISPLAY_NAME='Rockerbox';const ROLLBAR_DISPLAY_NAME='rollbar';const SATISMETER_DISPLAY_NAME='SatisMeter';const SENDINBLUE_DISPLAY_NAME='Sendinblue';const SENTRY_DISPLAY_NAME='Sentry';const SHYNET_DISPLAY_NAME='Shynet';const SNAP_PIXEL_DISPLAY_NAME='Snap Pixel';const SNAPENGAGE_DISPLAY_NAME='SnapEngage';const SPOTIFYPIXEL_DISPLAY_NAME='Spotify Pixel';const SPRIG_DISPLAY_NAME='Sprig';const TIKTOK_ADS_DISPLAY_NAME='TikTok Ads';const TVSQUARED_DISPLAY_NAME='TVSquared';const USERPILOT_DISPLAY_NAME='Userpilot';const VERO_DISPLAY_NAME='Vero';const VWO_DISPLAY_NAME='VWO';const WOOPRA_DISPLAY_NAME='WOOPRA';const XPIXEL_DISPLAY_NAME='XPixel';const YANDEX_METRICA_DISPLAY_NAME='Yandex.Metrica';\n\nconst DIR_NAME$1h='HubSpot';\n\nconst DIR_NAME$1g='GA';\n\nconst DIR_NAME$1f='Hotjar';\n\nconst DIR_NAME$1e='GoogleAds';\n\nconst DIR_NAME$1d='VWO';\n\nconst DIR_NAME$1c='GoogleTagManager';\n\nconst DIR_NAME$1b='Braze';\n\nconst DIR_NAME$1a='INTERCOM';\n\nconst DIR_NAME$19='Keen';\n\nconst DIR_NAME$18='Kissmetrics';\n\nconst DIR_NAME$17='CustomerIO';\n\nconst DIR_NAME$16='Chartbeat';\n\nconst DIR_NAME$15='FacebookPixel';\n\nconst DIR_NAME$14='Lotame';\n\nconst DIR_NAME$13='Optimizely';\n\nconst DIR_NAME$12='Bugsnag';\n\nconst DIR_NAME$11='Fullstory';\n\nconst DIR_NAME$10='TVSquared';\n\nconst DIR_NAME$$='GA4';\n\nconst DIR_NAME$_='GA4_V2';\n\nconst DIR_NAME$Z='MoEngage';\n\nconst DIR_NAME$Y='Amplitude';\n\nconst DIR_NAME$X='Pendo';\n\nconst DIR_NAME$W='Lytics';\n\nconst DIR_NAME$V='Appcues';\n\nconst DIR_NAME$U='Posthog';\n\nconst DIR_NAME$T='Klaviyo';\n\nconst DIR_NAME$S='Clevertap';\n\nconst DIR_NAME$R='BingAds';\n\nconst DIR_NAME$Q='PinterestTag';\n\nconst DIR_NAME$P='AdobeAnalytics';\n\nconst DIR_NAME$O='LinkedInInsightTag';\n\nconst DIR_NAME$N='RedditPixel';\n\nconst DIR_NAME$M='Drip';\n\nconst DIR_NAME$L='Heap';\n\nconst DIR_NAME$K='Criteo';\n\nconst DIR_NAME$J='Mixpanel';\n\nconst DIR_NAME$I='Qualtrics';\n\nconst DIR_NAME$H='ProfitWell';\n\nconst DIR_NAME$G='Sentry';\n\nconst DIR_NAME$F='QuantumMetric';\n\nconst DIR_NAME$E='SnapPixel';\n\nconst DIR_NAME$D='PostAffiliatePro';\n\nconst DIR_NAME$C='GoogleOptimize';\n\nconst DIR_NAME$B='LaunchDarkly';\n\nconst DIR_NAME$A='GA360';\n\nconst DIR_NAME$z='Adroll';\n\nconst DIR_NAME$y='DCMFloodlight';\n\nconst DIR_NAME$x='Matomo';\n\nconst DIR_NAME$w='Vero';\n\nconst DIR_NAME$v='Mouseflow';\n\nconst DIR_NAME$u='Rockerbox';\n\nconst DIR_NAME$t='ConvertFlow';\n\nconst DIR_NAME$s='SnapEngage';\n\nconst DIR_NAME$r='LiveChat';\n\nconst DIR_NAME$q='Shynet';\n\nconst DIR_NAME$p='Woopra';\n\nconst DIR_NAME$o='RollBar';\n\nconst DIR_NAME$n='QuoraPixel';\n\nconst DIR_NAME$m='June';\n\nconst DIR_NAME$l='Engage';\n\nconst DIR_NAME$k='Iterable';\n\nconst DIR_NAME$j='YandexMetrica';\n\nconst DIR_NAME$i='Refiner';\n\nconst DIR_NAME$h='Qualaroo';\n\nconst DIR_NAME$g='Podsights';\n\nconst DIR_NAME$f='Axeptio';\n\nconst DIR_NAME$e='Satismeter';\n\nconst DIR_NAME$d='MicrosoftClarity';\n\nconst DIR_NAME$c='Sendinblue';\n\nconst DIR_NAME$b='Olark';\n\nconst DIR_NAME$a='Lemnisk';\n\nconst DIR_NAME$9='TiktokAds';\n\nconst DIR_NAME$8='ActiveCampaign';\n\nconst DIR_NAME$7='Sprig';\n\nconst DIR_NAME$6='SpotifyPixel';\n\nconst DIR_NAME$5='CommandBar';\n\nconst DIR_NAME$4='Ninetailed';\n\nconst DIR_NAME$3='Gainsight_PX';\n\nconst DIR_NAME$2='XPixel';\n\nconst DIR_NAME$1='Userpilot';\n\nconst DIR_NAME='Comscore';\n\n// map of the destination display names to the destination directory names\n// Import display names and directory names from analytics-js-integrations\nconst destDisplayNamesToFileNamesMap={[HS_DISPLAY_NAME]:DIR_NAME$1h,[GA_DISPLAY_NAME]:DIR_NAME$1g,[HOTJAR_DISPLAY_NAME]:DIR_NAME$1f,[GOOGLEADS_DISPLAY_NAME]:DIR_NAME$1e,[VWO_DISPLAY_NAME]:DIR_NAME$1d,[GTM_DISPLAY_NAME]:DIR_NAME$1c,[BRAZE_DISPLAY_NAME]:DIR_NAME$1b,[INTERCOM_DISPLAY_NAME]:DIR_NAME$1a,[KEEN_DISPLAY_NAME]:DIR_NAME$19,[KISSMETRICS_DISPLAY_NAME]:DIR_NAME$18,[CUSTOMERIO_DISPLAY_NAME]:DIR_NAME$17,[CHARTBEAT_DISPLAY_NAME]:DIR_NAME$16,[FACEBOOK_PIXEL_DISPLAY_NAME]:DIR_NAME$15,[LOTAME_DISPLAY_NAME]:DIR_NAME$14,[OPTIMIZELY_DISPLAY_NAME]:DIR_NAME$13,[BUGSNAG_DISPLAY_NAME]:DIR_NAME$12,[FULLSTORY_DISPLAY_NAME]:DIR_NAME$11,[TVSQUARED_DISPLAY_NAME]:DIR_NAME$10,[GA4_DISPLAY_NAME]:DIR_NAME$$,[GA4_V2_DISPLAY_NAME]:DIR_NAME$_,[MOENGAGE_DISPLAY_NAME]:DIR_NAME$Z,[AM_DISPLAY_NAME]:DIR_NAME$Y,[PENDO_DISPLAY_NAME]:DIR_NAME$X,[LYTICS_DISPLAY_NAME]:DIR_NAME$W,[APPCUES_DISPLAY_NAME]:DIR_NAME$V,[POSTHOG_DISPLAY_NAME]:DIR_NAME$U,[KLAVIYO_DISPLAY_NAME]:DIR_NAME$T,[CLEVERTAP_DISPLAY_NAME]:DIR_NAME$S,[BINGADS_DISPLAY_NAME]:DIR_NAME$R,[PINTEREST_TAG_DISPLAY_NAME]:DIR_NAME$Q,[ADOBE_ANALYTICS_DISPLAY_NAME]:DIR_NAME$P,[LINKEDIN_INSIGHT_TAG_DISPLAY_NAME]:DIR_NAME$O,[REDDIT_PIXEL_DISPLAY_NAME]:DIR_NAME$N,[DRIP_DISPLAY_NAME]:DIR_NAME$M,[HEAP_DISPLAY_NAME]:DIR_NAME$L,[CRITEO_DISPLAY_NAME]:DIR_NAME$K,[MP_DISPLAY_NAME]:DIR_NAME$J,[QUALTRICS_DISPLAY_NAME]:DIR_NAME$I,[PROFITWELL_DISPLAY_NAME]:DIR_NAME$H,[SENTRY_DISPLAY_NAME]:DIR_NAME$G,[QUANTUMMETRIC_DISPLAY_NAME]:DIR_NAME$F,[SNAP_PIXEL_DISPLAY_NAME]:DIR_NAME$E,[POST_AFFILIATE_PRO_DISPLAY_NAME]:DIR_NAME$D,[GOOGLE_OPTIMIZE_DISPLAY_NAME]:DIR_NAME$C,[LAUNCHDARKLY_DISPLAY_NAME]:DIR_NAME$B,[GA360_DISPLAY_NAME]:DIR_NAME$A,[ADROLL_DISPLAY_NAME]:DIR_NAME$z,[DCM_FLOODLIGHT_DISPLAY_NAME]:DIR_NAME$y,[MATOMO_DISPLAY_NAME]:DIR_NAME$x,[VERO_DISPLAY_NAME]:DIR_NAME$w,[MOUSEFLOW_DISPLAY_NAME]:DIR_NAME$v,[ROCKERBOX_DISPLAY_NAME]:DIR_NAME$u,[CONVERTFLOW_DISPLAY_NAME]:DIR_NAME$t,[SNAPENGAGE_DISPLAY_NAME]:DIR_NAME$s,[LIVECHAT_DISPLAY_NAME]:DIR_NAME$r,[SHYNET_DISPLAY_NAME]:DIR_NAME$q,[WOOPRA_DISPLAY_NAME]:DIR_NAME$p,[ROLLBAR_DISPLAY_NAME]:DIR_NAME$o,[QUORA_PIXEL_DISPLAY_NAME]:DIR_NAME$n,[JUNE_DISPLAY_NAME]:DIR_NAME$m,[ENGAGE_DISPLAY_NAME]:DIR_NAME$l,[ITERABLE_DISPLAY_NAME]:DIR_NAME$k,[YANDEX_METRICA_DISPLAY_NAME]:DIR_NAME$j,[REFINER_DISPLAY_NAME]:DIR_NAME$i,[QUALAROO_DISPLAY_NAME]:DIR_NAME$h,[PODSIGHTS_DISPLAY_NAME]:DIR_NAME$g,[AXEPTIO_DISPLAY_NAME]:DIR_NAME$f,[SATISMETER_DISPLAY_NAME]:DIR_NAME$e,[MICROSOFT_CLARITY_DISPLAY_NAME]:DIR_NAME$d,[SENDINBLUE_DISPLAY_NAME]:DIR_NAME$c,[OLARK_DISPLAY_NAME]:DIR_NAME$b,[LEMNISK_DISPLAY_NAME]:DIR_NAME$a,[TIKTOK_ADS_DISPLAY_NAME]:DIR_NAME$9,[ACTIVE_CAMPAIGN_DISPLAY_NAME]:DIR_NAME$8,[SPRIG_DISPLAY_NAME]:DIR_NAME$7,[SPOTIFYPIXEL_DISPLAY_NAME]:DIR_NAME$6,[COMMANDBAR_DISPLAY_NAME]:DIR_NAME$5,[NINETAILED_DISPLAY_NAME]:DIR_NAME$4,[GAINSIGHT_PX_DISPLAY_NAME]:DIR_NAME$3,[XPIXEL_DISPLAY_NAME]:DIR_NAME$2,[USERPILOT_DISPLAY_NAME]:DIR_NAME$1,[COMSCORE_DISPLAY_NAME]:DIR_NAME};\n\n/**\n * Determines if the destination SDK code is evaluated\n * @param destSDKIdentifier The name of the global globalThis object that contains the destination SDK\n * @param sdkTypeName The name of the destination SDK type\n * @param logger Logger instance\n * @returns true if the destination SDK code is evaluated, false otherwise\n */const isDestinationSDKMounted=(destSDKIdentifier,sdkTypeName,logger)=>Boolean(globalThis[destSDKIdentifier]?.[sdkTypeName]?.prototype&&typeof globalThis[destSDKIdentifier][sdkTypeName].prototype.constructor!=='undefined');const wait=time=>new Promise(resolve=>{globalThis.setTimeout(resolve,time);});const createIntegrationInstance=(destSDKIdentifier,sdkTypeName,dest,state)=>{const analyticsInstance={loadIntegration:state.nativeDestinations.loadIntegration.value,logLevel:state.lifecycle.logLevel.value,loadOnlyIntegrations:state.consents.postConsent.value?.integrations??state.nativeDestinations.loadOnlyIntegrations.value,...state.lifecycle.safeAnalyticsInstance.value};const integration=new globalThis[destSDKIdentifier][sdkTypeName](clone(dest.config),analyticsInstance,{shouldApplyDeviceModeTransformation:dest.shouldApplyDeviceModeTransformation,prop
1agateEventsUntransformedOnError:dest.propagateEventsUntransformedOnError,destinationId:dest.id});return integration;};const isDestinationReady=(dest,time=0)=>new Promise((resolve,reject)=>{if(dest.integration?.isReady()){resolve(true);}else if(time>=READY_CHECK_TIMEOUT_MS){reject(new Error(INTEGRATION_READY_TIMEOUT_ERROR(READY_CHECK_TIMEOUT_MS)));}else {const curTime=Date.now();wait(READY_CHECK_INTERVAL_MS).then(()=>{const elapsedTime=Date.now()-curTime;isDestinationReady(dest,time+elapsedTime).then(resolve).catch(err=>reject(err));});}});/**\n * Extracts the integration config, if any, from the given destination\n * and merges it with the current integrations config\n * @param dest Destination object\n * @param curDestIntgConfig Current destinations integration config\n * @param logger Logger object\n * @returns Combined destinations integrations config\n */const getCumulativeIntegrationsConfig=(dest,curDestIntgConfig,errorHandler)=>{let integrationsConfig=curDestIntgConfig;if(isFunction(dest.integration?.getDataForIntegrationsObject)){try{integrationsConfig={...curDestIntgConfig,...getSanitizedValue(dest.integration.getDataForIntegrationsObject())};}catch(err){errorHandler?.onError({error:err,context:DEVICE_MODE_DESTINATIONS_PLUGIN,customMessage:INTEGRATIONS_DATA_ERROR(dest.userFriendlyId),groupingHash:INTEGRATIONS_DATA_ERROR(dest.displayName),category:INTEGRATIONS_ERROR_CATEGORY});}}return integrationsConfig;};const initializeDestination=(dest,state,destSDKIdentifier,sdkTypeName,errorHandler,logger)=>{try{const initializedDestination=clone(dest);let integration=initializedDestination.integration;if(isUndefined(integration)){integration=createIntegrationInstance(destSDKIdentifier,sdkTypeName,dest,state);initializedDestination.integration=integration;}integration.init?.();isDestinationReady(initializedDestination).then(()=>{// Collect the integrations data for the hybrid mode destinations\nif(isHybridModeDestination(initializedDestination)){state.nativeDestinations.integrationsConfig.value=getCumulativeIntegrationsConfig(initializedDestination,state.nativeDestinations.integrationsConfig.value,errorHandler);}state.nativeDestinations.initializedDestinations.value=[...state.nativeDestinations.initializedDestinations.value,initializedDestination];}).catch(err=>{state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];errorHandler?.onError({error:err,context:DEVICE_MODE_DESTINATIONS_PLUGIN,customMessage:INTEGRATION_READY_CHECK_ERROR(dest.userFriendlyId),groupingHash:INTEGRATION_READY_CHECK_ERROR(dest.displayName),category:INTEGRATIONS_ERROR_CATEGORY});});}catch(err){state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];errorHandler?.onError({error:err,context:DEVICE_MODE_DESTINATIONS_PLUGIN,customMessage:INTEGRATION_INIT_ERROR(dest.userFriendlyId),groupingHash:INTEGRATION_INIT_ERROR(dest.displayName),category:INTEGRATIONS_ERROR_CATEGORY});}};/**\n * Applies source configuration overrides to destinations\n * @param destinations Array of destinations to process\n * @param sourceConfigOverride Source configuration override options\n * @param logger Logger instance for warnings\n * @returns Array of destinations with overrides applied\n */const applySourceConfigurationOverrides=(destinations,sourceConfigOverride,logger)=>{if(!sourceConfigOverride?.destinations?.length){return filterDisabledDestinations(destinations);}const destIds=destinations.map(dest=>dest.id);// Group overrides by destination ID to support future cloning\n// When cloning is implemented, multiple overrides with same ID will create multiple destination instances\nconst overridesByDestId={};sourceConfigOverride.destinations.forEach(override=>{const existing=overridesByDestId[override.id]||[];existing.push(override);overridesByDestId[override.id]=existing;});// Find unmatched destination IDs and log warning\nconst unmatchedIds=Object.keys(overridesByDestId).filter(id=>!destIds.includes(id));if(unmatchedIds.length>0){logger?.warn(`${DEVICE_MODE_DESTINATIONS_PLUGIN}:: Source configuration override - Unable to identify the destinations with the following IDs: \"${unmatchedIds.join(', ')}\"`);}// Process overrides and apply them to destinations\nconst processedDestinations=[];destinations.forEach(dest=>{const overrides=overridesByDestId[dest.id];if(!overrides||overrides.length===0){// No override for this destination, keep original\nprocessedDestinations.push(dest);return;}if(overrides.length>1){// Multiple overrides for the same destination, create clones\noverrides.forEac
1h((override,index)=>{const overriddenDestination=applyOverrideToDestination(dest,override,`${index+1}`);overriddenDestination.cloned=true;overriddenDestination.originalId=dest.id;processedDestinations.push(overriddenDestination);});}else {const overriddenDestination=applyOverrideToDestination(dest,overrides[0]);processedDestinations.push(overriddenDestination);}});return filterDisabledDestinations(processedDestinations);};/**\n * This function filters out disabled destinations from the provided array.\n * @param destinations Array of destinations to filter\n * @returns Filtered destinations to only include enabled ones\n */const filterDisabledDestinations=destinations=>destinations.filter(dest=>dest.enabled);/**\n * Applies a single override configuration to a destination\n * @param destination Original destination\n * @param override Override configuration\n * @param cloneId Unique identifier for the clone,\n * if provided, the value is appended to the id and userFriendlyId of the destination\n * @returns Modified destination with override applied\n */const applyOverrideToDestination=(destination,override,cloneId)=>{// Check if any changes are needed\nconst isEnabledStatusChanged=isBoolean(override.enabled)&&override.enabled!==destination.enabled;// Check if config is provided\nconst isConfigChanged=isNonEmptyObject(override.config);// Determine the final enabled status after applying overrides\nconst finalEnabledStatus=isBoolean(override.enabled)?override.enabled:destination.enabled;// Check if config will actually be applied (only for enabled destinations)\nconst willApplyConfig=isConfigChanged&&finalEnabledStatus;// If no changes needed and no cloneId, return original destination\nif(!isEnabledStatusChanged&&!willApplyConfig&&!cloneId){return destination;}// Clone destination and apply overrides\nconst clonedDest=clone(destination);if(cloneId){clonedDest.id=`${destination.id}_${cloneId}`;clonedDest.userFriendlyId=`${destination.userFriendlyId}_${cloneId}`;}// Apply enabled status override if provided and different\nif(isEnabledStatusChanged){clonedDest.enabled=override.enabled;// Mark as overridden\nclonedDest.overridden=true;}// Apply config overrides if provided for enabled destination\nif(willApplyConfig){// Override the config with the new config and remove undefined and null values\nclonedDest.config=removeUndefinedAndNullValues({...clonedDest.config,...override.config});clonedDest.overridden=true;}return clonedDest;};/**\n * Validates if the destination ID and custom integration are valid\n * @param destinationId - The destination ID to validate\n * @param integration - The custom integration instance\n * @param state - Application state\n * @param logger - Logger instance\n * @returns Destination object if the integration is valid, undefined otherwise\n */const validateCustomIntegration=(destinationId,integration,state,logger)=>{const configuredDestinations=state.nativeDestinations.configuredDestinations.value;const destination=configuredDestinations.find(dest=>dest.id===destinationId&&dest.isCustomIntegration===true);if(!destination){logger.error(CUSTOM_INTEGRATION_INVALID_DESTINATION_ID_ERROR(DEVICE_MODE_DESTINATIONS_PLUGIN,destinationId));return;}// Check if a custom integration is already added for the destination ID\nif(isDefined(destination.integration)){logger.error(CUSTOM_INTEGRATION_ALREADY_EXISTS_ERROR(DEVICE_MODE_DESTINATIONS_PLUGIN,destinationId));return;}// Check if the integration is correctly implemented\nif(isNullOrUndefined(integration)||!isFunction(integration.isReady)||isDefined(integration.init)&&!isFunction(integration.init)||isDefined(integration.track)&&!isFunction(integration.track)||isDefined(integration.page)&&!isFunction(integration.page)||isDefined(integration.identify)&&!isFunction(integration.identify)||isDefined(integration.group)&&!isFunction(integration.group)||isDefined(integration.alias)&&!isFunction(integration.alias)){logger.error(INVALID_CUSTOM_INTEGRATION_ERROR(DEVICE_MODE_DESTINATIONS_PLUGIN,destinationId));return;}return destination;};
1/**\n * Updates destination object with the custom integration\n * @param destination - The destination object\n * @param integration - The custom integration instance\n * @param state - Application state\n * @param logger - Logger instance\n * @returns\n */const addIntegrationToDestination=(destination,integration,state,logger)=>{const analyticsInstance=state.lifecycle.safeAnalyticsInstance.value;// Create a new logger object for the custom integration\n// to avoid conflicts with the main logger\nconst integrationLogger=clone(logger);// Set the scope to the custom integration name\n// for easy identification in the logs\nintegrationLogger.setScope(destination.displayName);// Bind only the necessary methods to the new logger object\nconst safeLogger={log:integrationLogger.log.bind(integrationLogger),info:integrationLogger.info.bind(integrationLogger),debug:integrationLogger.debug.bind(integrationLogger),warn:integrationLogger.warn.bind(integrationLogger),error:integrationLogger.error.bind(integrationLogger),setMinLogLevel:integrationLogger.setMinLogLevel.bind(integrationLogger)};// Create configuration object for the custom integration\n// to pass to the init method\nconst customDestinationConfig=clone(destination.config);// Create a wrapper around the custom integration APIs\n// to make them consistent with the standard device mode integrations\ndestination.integration={...(integration.init&&{init:()=>integration.init(customDestinationConfig,analyticsInstance,safeLogger)}),...(integration.track&&{track:event=>integration.track(analyticsInstance,safeLogger,event)}),...(integration.page&&{page:event=>integration.page(analyticsInstance,safeLogger,event)}),...(integration.identify&&{identify:event=>integration.identify(analyticsInstance,safeLogger,event)}),...(integration.group&&{group:event=>integration.group(analyticsInstance,safeLogger,event)}),...(integration.alias&&{alias:event=>integration.alias(analyticsInstance,safeLogger,event)}),isReady:()=>integration.isReady(analyticsInstance,safeLogger)};};\n\nconst pluginName$b='DeviceModeDestinations';const DeviceModeDestinations=()=>({name:pluginName$b,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$b];},nativeDestinations:{addCustomIntegration(destinationId,integration,state,logger){const destination=validateCustomIntegration(destinationId,integration,state,logger);if(!destination){return;}addIntegrationToDestination(destination,integration,state,logger);// Refresh the state value to trigger any effects that depend on it\nstate.nativeDestinations.configuredDestinations.value=[...state.nativeDestinations.configuredDestinations.value];},setActiveDestinations(state,pluginsManager,errorHandler,logger){state.nativeDestinations.loadIntegration.value=state.loadOptions.value.loadIntegration;// Filter destination that doesn't have mapping config--\x3eIntegration names\nconst configSupportedDestinations=state.nativeDestinations.configuredDestinations.value.filter(configDest=>{// Filter enabled or disabled custom destinations that don't have an integration added to them\nif(configDest.isCustomIntegration&&isUndefined(configDest.integration)){if(configDest.enabled){logger?.warn(INTEGRATION_NOT_ADDED_TO_CUSTOM_DESTINATION_WARNING(DEVICE_MODE_DESTINATIONS_PLUGIN,configDest.id));}return false;}// Ensure the destination is supported by the SDK\n// or it is a custom integration\nif(configDest.isCustomIntegration||destDisplayNamesToFileNamesMap[configDest.displayName]){return true;}const errMessage=INTEGRATION_NOT_SUPPORTED_ERROR(configDest.displayName);errorHandler?.onError({error:new Error(errMessage),context:DEVICE_MODE_DESTINATIONS_PLUGIN,category:INTEGRATIONS_ERROR_CATEGORY});return false;});// Apply source configuration overrides if provided\nconst configuredDestinations=state.loadOptions.value.sourceConfigurationOverride?applySourceConfigurationOverrides(configSupportedDestinations,state.loadOptions.value.sourceConfigurationOverride,logger):filterDisabledDestinations(configSupportedDestinations);// Filter destinations that are disabled through load or consent API options\nconst destinationsToLoad=filterDestinations(state.consents.postConsent.value?.integrations??state.nativeDestinations.loadOnlyIntegrations.value,configuredDestinations);const consentedDestinations=destinationsToLoad.filter(dest=>// if consent manager is not configured, then default to load the destination\npluginsManager.invokeSingle(`consentManager.isDestinationConsented`,state,dest.config,errorHandler,logger)??true);// Add the distilled destinations to the active destinations list\nstate.nativeDestinations.activeDestinations.value=[...state.nativeDestinations.activeDestinations.value,...consentedDestinations];},load(state,externalSrcLoader,errorHandler,logger,externalScriptOnLoad){const integrationsCDNPath=state.lifecycle.integrationsCDNPath.value;const activeDestinations=state.nativeDestinations.activeDestinations.value;activeDestinations.forEach(dest=>{const sdkName=destDisplayNamesToFileNamesMap[dest.displayName];const destSDKIdentifier=`${sdkName}_RS`;// this is the name of the object loaded on the window\nconst sdkTypeName=sdkName;if(sdkTypeName&&!isDestinationSDKMounted(destSDKIdentifier,sdkTypeName)){const destSdkURL=`${integrationsCDNPath}/${sdkName}.min.js`;externalSrcLoader.loadJSFile({url:destSdkURL,id:dest.userFriendlyId,callback:externalScriptOnLoad??((id,err)=>{if(err){const customMessage=INTEGRATION_SDK_LOAD_ERROR(dest.displayName);errorHandler?.onError({error:err,context:DEVICE_MODE_DESTINATIONS_PLUGIN,customMessage,groupingHash:customMessage,category:INTEGRATIONS_ERROR_CATEGORY});state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];}else {initializeDestination(dest,state,destSDKIdentifier,sdkTypeName,errorHandler);}}),timeout:SCRIPT_LOAD_TIMEOUT_MS});}else {initializeDestination(dest,state,destSDKIdentifier,sdkTypeName,errorHandler);}});}}});\n\nconst DEFAULT_TRANSFORMATION_QUEUE_OPTIONS={minRetryDelay:500,backoffFactor:2,maxAttempts:3};const REQUEST_TIMEOUT_MS$1=10*1000;// 10 seconds\nconst QUEUE_NAME$2='rudder';const DMT_PLUGIN='DeviceModeTransformationPlugin';\n\nconst DMT_TRANSFORMATION_UNSUCCESSFUL_ERROR=(context,displayName,id,reason,action)=>`${context}${LOG_CONTEXT_SEPARATOR}Event transformation unsuccessful for destination \"${displayName}
1\" with id \"${id}\". Reason: ${reason}. ${action}.`;const DMT_REQUEST_FAILED_ERROR=(context,displayName,id,status,action)=>`${context}${LOG_CONTEXT_SEPARATOR}[Destination: ${displayName} with id \"${id}\"].Transformation request failed with status: ${status}. Retries exhausted. ${action}.`;const DMT_EXCEPTION=(displayName,id)=>`Transformation failed for destination \"${displayName}\" with id \"${id}\"`;const DMT_SERVER_ACCESS_DENIED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}Transformation server access is denied. The configuration data seems to be out of sync. Sending untransformed event to the destination.`;\n\n/**\n * A helper function that will take rudderEvent and generate\n * a batch payload that will be sent to transformation server\n *\n */const createPayload=(event,destinationIds,token)=>{const orderNo=Date.now();const payload={metadata:{'Custom-Authorization':token},batch:[{orderNo,destinationIds,event}]};return payload;};/**\n * Helper function to get destination identifier consistently\n */const getDestinationId=dest=>dest.originalId??dest.id;/**\n * Helper function to log once per destination to avoid duplicate messages\n */const logOncePerDestination=(destinationId,loggedDestinations,logFn)=>{if(!loggedDestinations.includes(destinationId)){loggedDestinations.push(destinationId);logFn();}};const sendTransformedEventToDestinations=(state,pluginsManager,destinationIds,result,status,event,errorHandler,logger)=>{const NATIVE_DEST_EXT_POINT='destinationsEventsQueue.enqueueEventToDestination';const ACTION_TO_SEND_UNTRANSFORMED_EVENT='Sending untransformed event';const ACTION_TO_DROP_EVENT='Dropping the event';const destinations=state.nativeDestinations.initializedDestinations.value.filter(d=>d&&destinationIds.includes(getDestinationId(d)));const loggedDestinations=[];destinations.forEach(dest=>{try{const eventsToSend=[];const destinationId=getDestinationId(dest);switch(status){case 200:{const response=JSON.parse(result);const destTransformedResult=response.transformedBatch.find(e=>e.id===destinationId);destTransformedResult?.payload.forEach(tEvent=>{if(tEvent.status==='200'){eventsToSend.push(tEvent.event);}else {let reason='Unknown';if(tEvent.status==='410'){reason='Transformation is not available';}let action=ACTION_TO_DROP_EVENT;if(dest.propagateEventsUntransformedOnError===true){action=ACTION_TO_SEND_UNTRANSFORMED_EVENT;eventsToSend.push(event);logOncePerDestination(destinationId,loggedDestinations,()=>{logger?.warn(DMT_TRANSFORMATION_UNSUCCESSFUL_ERROR(DMT_PLUGIN,dest.displayName,destinationId,reason,action));});}else {logOncePerDestination(destinationId,loggedDestinations,()=>{logger?.error(DMT_TRANSFORMATION_UNSUCCESSFUL_ERROR(DMT_PLUGIN,dest.displayName,destinationId,reason,action));});}}});break;}// Transformation server access denied\ncase 404:{logOncePerDestination(destinationId,loggedDestinations,()=>{logger?.warn(DMT_SERVER_ACCESS_DENIED_WARNING(DMT_PLUGIN));});eventsToSend.push(event);break;}default:{if(dest.propagateEventsUntransformedOnError===true){logOncePerDestination(destinationId,loggedDestinations,()=>{logger?.warn(DMT_REQUEST_FAILED_ERROR(DMT_PLUGIN,dest.displayName,destinationId,status,ACTION_TO_SEND_UNTRANSFORMED_EVENT));});eventsToSend.push(event);}else {logOncePerDestination(destinationId,loggedDestinations,()=>{logger?.error(DMT_REQUEST_FAILED_ERROR(DMT_PLUGIN,dest.displayName,destinationId,status,ACTION_TO_DROP_EVENT));});}break;}}eventsToSend?.forEach(tEvent=>{if(isNonEmptyObject(tEvent)){pluginsManager.invokeSingle(NATIVE_DEST_EXT_POINT,state,tEvent,dest,errorHandler,logger);}});}catch(err){errorHandler?.onError({error:err,context:DMT_PLUGIN,customMessage:DMT_EXCEPTION(dest.displayName,dest.id)});}});};\n\nconst pluginName$a='DeviceModeTransformation';const DeviceModeTransformation=()=>({name:pluginName$a,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$a];},transformEvent:{init(state,pluginsManager,httpClient,storeManager,errorHandler,logger){const writeKey=state.lifecycle.writeKey.value;httpClient.setAuthHeader(writeKey);const eventsQueue=new RetryQueue(// adding write key to the queue name to avoid conflicts\n`${QUEUE_NAME$2}_${writeKey}`,DEFAULT_TRANSFORMATION_QUEUE_OPTIONS,(item,done,qItemProcessInfo)=>{const payload=createPayload(item.event,item.destinationIds,item.token);httpClient.getAsyncData({url:`${state.lifecycle.activeDataplaneUrl.value}/transform`,options:{method:'POST',data:getDMTDeliveryPayload(payload),sendRawData:true},isRawResponse:true,timeout:REQUEST_TIMEOUT_MS$1,callback:(result,details)=>{const isRetryable=isErrRetryable(details?.xhr?.status??0);// If there is no error, or the error is not retryable, or the attempt number is the max retry attempts, then attempt send the event to the destinations\nif(isUndefined(details?.error)||!isRetryable||qItemProcessInfo.retryAttemptNumber===qItemProcessInfo.maxRetryAttempts){sendTransformedEventToDestinations(state,pluginsManager,item.destinationIds,result,details?.xhr?.status,item.event,errorHandler,logger);done(null);}else {// Requeue the item as the error is retryable.\ndone(details);}}});},storeManager,MEMORY_STORAGE);return eventsQueue;},enqueue(state,eventsQueue,event,destinations){// Collect unique destination IDs for transformation\n// For cloned destinations, getDestinationId returns originalId to ensure uniqueness\nconst destinationIds=[];destinations.forEach(d=>{const id=getDestinationId(d);if(!destinationIds.includes(id)){destinationIds.push(id);}}
1);eventsQueue.addItem({event,destinationIds,token:state.session.authToken.value});}}});\n\nconst externallyLoadedSessionStorageKeys={segment:'ajs_anonymous_id'};\n\nconst getSegmentAnonymousId=getStorageEngine=>{let anonymousId;/**\n * First check the local storage for anonymousId\n * Ref: https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/#identify\n */const lsEngine=getStorageEngine(LOCAL_STORAGE);if(lsEngine?.isEnabled){anonymousId=lsEngine.getItem(externallyLoadedSessionStorageKeys.segment);}// If anonymousId is not present in local storage and find it in cookies\nconst csEngine=getStorageEngine(COOKIE_STORAGE);if(!anonymousId&&csEngine?.isEnabled){anonymousId=csEngine.getItem(externallyLoadedSessionStorageKeys.segment);}return anonymousId;};\n\nconst pluginName$9='ExternalAnonymousId';const ExternalAnonymousId=()=>({name:pluginName$9,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$9];},storage:{getAnonymousId(getStorageEngine,options){let anonymousId;if(options?.autoCapture?.enabled&&options.autoCapture.source){const source=options.autoCapture.source.toLowerCase();if(!Object.keys(externallyLoadedSessionStorageKeys).includes(source)){return anonymousId;}// eslint-disable-next-line sonarjs/no-small-switch\nswitch(source){case 'segment':anonymousId=getSegmentAnonymousId(getStorageEngine);break;}}return anonymousId;}}});\n\nconst AMP_LINKER_ANONYMOUS_ID_KEY='rs_amp_id';\n\n/* eslint-disable no-bitwise *//**\n * generate crc table\n *\n * @params none\n * @returns array of CRC table\n */const makeCRCTable=()=>{const crcTable=[];let c;for(let n=0;n<256;n++){c=n;for(let k=0;k<8;k++){c=c&1?0xedb88320^c>>>1:c>>>1;}crcTable[n]=c;}return crcTable;};/**\n * This is utility function for crc32 algorithm\n *\n * @param {string} str\n * @returns {number} crc32\n */const crc32=str=>{const crcTable=makeCRCTable();let crc=0^-1;for(let i=0;i<str.length;i++){// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\ncrc=crc>>>8^crcTable[(crc^str.charCodeAt(i))&0xff];}return (crc^-1)>>>0;};\n\n/**\n * An interface to fetch user device details.\n */const USER_INTERFACE={/**\n * @returns {string} user language\n */getUserLanguage:()=>navigator?.language,/**\n * @returns {string} userAgent\n */getUserAgent:()=>navigator?.userAgent};\n\n/**\n * This is utility function for decoding from base 64 to utf8\n *\n * @param {string} str base64\n *\n * @returns {string} utf8\n */const b64DecodeUnicode=str=>// Going backwards: from bytestream, to percent-encoding, to original string.\ndecodeURIComponent(globalThis.atob(str).split('').map(c=>{const percentEncodingChar=`00${c.charCodeAt(0).toString(16)}`;return `%${percentEncodingChar.slice(-2)}`;}).join(''));/**\n * This is utility function for decoding from base 64 to utf8\n *\n * @param {string} data\n *\n * @return {string}\n */const decode=(data='')=>{const decodedData=data.endsWith('..')?data.substring(0,data.length-2):data;return b64DecodeUnicode(decodedData);};\n\nconst KEY_VALIDATOR=/^[\\w.-]+$/;const CHECKSUM_OFFSET_MAX_MIN=1;const VALID_VERSION=1;const DELIMITER='*';/**\n * Parse the linker param value to version checksum and serializedParams\n *\n * @param {string} value\n *\n * @return {?Object}\n */const parseLinkerParamValue=value=>{const parts=value.split(DELIMITER);const isEven=parts.length%2===0;if(parts.length<4||!isEven){// Format <version>*<checksum>*<key1>*<value1>\n// Note: linker makes sure there's at least one pair of non empty key value\n// Make sure there is at least three delimiters.\nreturn null;}const version=Number(parts.shift());if(version!==VALID_VERSION){return null;}const checksum=parts.shift();const serializedIds=parts.join(DELIMITER);return {checksum:checksum??'',serializedIds};};/**\n * Deserialize the serializedIds and return keyValue pairs.\n *\n * @param {string} serializedIds\n *\n * @return {!Object<string, string>}\n */const deserialize=serializedIds=>{if(!serializedIds){return {};}const keyValuePairs={};const params=serializedIds.split(DELIMITER);for(let i=0;i<params.length;i+=2){const key=params[i];const valid=KEY_VALIDATOR.test(key);if(valid){keyValuePairs[key]=decode(params[i+1]);}}return keyValuePairs;};/**\n * Generates a semi-unique value for page visitor.\n *\n * @return {string}\n */const getFingerprint=(userAgent,language)=>{const date=new Date();const timezone=date.getTimezoneOffset();
1return [userAgent,timezone,language].join(DELIMITER);};/**\n * Rounded time used to check if t2 - t1 is within our time tolerance.\n * Timestamp in minutes, floored.\n *\n * @return {number}\n */const getMinSinceEpoch=()=>Math.floor(Date.now()/60000);/**\n * Create a unique checksum hashing the fingerprint and a few other values.\n *\n * @param {string} serializedIds\n * @param {number=} optOffsetMin\n * @param {string} userAgent\n * @param {string} language\n *\n * @return {string}\n */const getCheckSum=(serializedIds,optOffsetMin,userAgent,language)=>{const fingerprint=getFingerprint(userAgent,language);const offset=optOffsetMin||0;const timestamp=getMinSinceEpoch()-offset;const crc=crc32([fingerprint,timestamp,serializedIds].join(DELIMITER));// Encoded to base36 for fewer bytes.\nreturn crc.toString(36);};/**\n * Check if the checksum is valid with time offset tolerance.\n *\n * @param {string} serializedIds\n * @param {string} checksum\n *\n * @return {boolean}\n */const isCheckSumValid=(serializedIds,checksum)=>{const userAgent=USER_INTERFACE.getUserAgent();const language=USER_INTERFACE.getUserLanguage();for(let i=0;i<=CHECKSUM_OFFSET_MAX_MIN;i+=1){const calculateCheckSum=getCheckSum(serializedIds,i,userAgent,language);if(calculateCheckSum===checksum){return true;}}return false;};/**\n * AMP Linker Parser (works for Rudder, GA or any other linker created by following Google's linker standard.)\n *\n * @param {string} value\n *\n * @return {?Object<string, string>}\n */const parseLinker=value=>{const linkerObj=parseLinkerParamValue(value);if(!linkerObj){return null;}const{checksum,serializedIds}=linkerObj;if(!serializedIds||!checksum||!isCheckSumValid(serializedIds,checksum)){return null;}return deserialize(serializedIds);};\n\nconst pluginName$8='GoogleLinker';const GoogleLinker=()=>({name:pluginName$8,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$8];},userSession:{anonymousIdGoogleLinker(rudderAmpLinkerParam){if(!rudderAmpLinkerParam){return null;}const parsedAnonymousIdObj=rudderAmpLinkerParam?parseLinker(rudderAmpLinkerParam):null;return parsedAnonymousIdObj?parsedAnonymousIdObj[AMP_LINKER_ANONYMOUS_ID_KEY]:null;}}});\n\nconst IUBENDA_CONSENT_COOKIE_READ_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to read the consent cookie.`;const IUBENDA_CONSENT_COOKIE_PARSE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to parse the consent cookie.`;const DESTINATION_CONSENT_STATUS_ERROR$2=`Failed to determine the consent status for the destination. Please check the destination configuration and try again.`;\n\nconst IUBENDA_CONSENT_MANAGER_PLUGIN='IubendaConsentManagerPlugin';const IUBENDA_CONSENT_COOKIE_NAME_PATTERN=/^_iub_cs-\\d+$/;\n\nconst getIubendaCookieName=logger=>{try{// Retrieve cookies as a string and split them into an array\nconst cookies=document.cookie.split('; ');// Find the cookie that matches the iubenda cookie pattern\nconst matchedCookie=cookies.find(cookie=>{const[name]=cookie.split('=');return IUBENDA_CONSENT_COOKIE_NAME_PATTERN.test((name||'').trim());});if(!matchedCookie){throw new Error('Iubenda Cookie not found with the specified pattern.');}// Extract and return the cookie name\nconst[name]=matchedCookie.split('=');return name||'';}catch(err){logger?.error(IUBENDA_CONSENT_COOKIE_READ_ERROR(IUBENDA_CONSENT_MANAGER_PLUGIN),err);return '';}};/**\n * Gets the consent data from the Iubenda's consent cookie\n * @param storeManager Store manager instance\n * @param logger Logger instance\n * @returns Consent data from the consent cookie\n */const getIubendaConsentData=(storeManager,logger)=>{let rawConsentCookieData=null;try{const dataStore=storeManager?.setStore({id:IUBENDA_CONSENT_MANAGER_PLUGIN,name:IUBENDA_CONSENT_MANAGER_PLUGIN,type:COOKIE_STORAGE,errorHandler:storeManager?.errorHandler,logger:storeManager?.logger});rawConsentCookieData=dataStore?.engine.getItem(getIubendaCookieName(logger));}catch(err){logger?.error(IUBENDA_CONSENT_COOKIE_READ_ERROR(IUBENDA_CONSENT_MANAGER_PLUGIN),err);return undefined;}if(isNullOrUndefined(rawConsentCookieData)){return undefined;}// Decode and parse the cookie data to JSON\nlet consentCookieData;try{consentCookieData=JSON.parse(decodeURIComponent(rawConsentCookieData));}catch(err){logger?.error(IUBENDA_CONSENT_COOKIE_PARSE_ERROR(IUBENDA_CONSENT_MANAGER_PLUGIN),err);return undefined;}if(!consentCookieData){return undefined;}// Convert the cookie data to consent data\nconst consentPurposes=consentCookieData.purposes;return consentPurposes;};/**\n * Gets the consent data in the format expected by the application state\n * @param iubendaConsentData Consent data derived from the consent cookie\n * @returns Consent data\n */const getConsentData$1=iubendaConsentData=>{const allowedConsentIds=[];const deniedConsentIds=[];if(iubendaConsentData){Object.entries(iubendaConsentData).forEac
1h(e=>{const purposeId=e[0];const isConsented=e[1];if(isConsented){allowedConsentIds.push(purposeId);}else {deniedConsentIds.push(purposeId);}});}return {allowedConsentIds,deniedConsentIds};};const updateConsentStateFromData$1=(state,iubendaConsentData)=>{const consentData=getConsentData$1(iubendaConsentData);state.consents.initialized.value=isDefined(iubendaConsentData);state.consents.data.value=consentData;};\n\nconst pluginName$7='IubendaConsentManager';const IubendaConsentManager=()=>({name:pluginName$7,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$7];},consentManager:{init(state,logger){// getIubendaUserConsentedPurposes returns current iubenda opted-in purposes\n// This will be helpful for debugging\nglobalThis.getIubendaUserConsentedPurposes=()=>state.consents.data.value.allowedConsentIds?.slice();// getIubendaUserDeniedPurposes returns current Iubenda opted-out purposes\n// This will be helpful for debugging\nglobalThis.getIubendaUserDeniedPurposes=()=>state.consents.data.value.deniedConsentIds?.slice();// updateIubendaConsent callback function to update current consent purpose state\nglobalThis.updateIubendaConsent=iubendaConsentData=>{updateConsentStateFromData$1(state,iubendaConsentData);};},updateConsentsInfo(state,storeManager,logger){// retrieve consent data and update the state\nlet iubendaConsentData;// From window\nif(!isUndefined(globalThis._iub.cs.consent.purposes)){iubendaConsentData=globalThis._iub.cs.consent.purposes;// From cookie\n}else {iubendaConsentData=getIubendaConsentData(storeManager,logger);}updateConsentStateFromData$1(state,iubendaConsentData);},isDestinationConsented(state,destConfig,errorHandler,logger){if(!state.consents.initialized.value){return true;}const allowedConsentIds=state.consents.data.value.allowedConsentIds;const matchPredicate=consent=>allowedConsentIds.includes(consent);try{const{consentManagement}=destConfig;// If the destination does not have consent management config, events should be sent.\nif(consentManagement){// Get the corresponding consents for the destination\nconst cmpConfig=consentManagement.find(c=>c.provider===state.consents.provider.value);// If there are no consents configured for the destination for the current provider, events should be sent.\nif(!cmpConfig?.consents){return true;}const configuredConsents=cmpConfig.consents.map(c=>c.consent.trim()).filter(n=>n);const resolutionStrategy=cmpConfig.resolutionStrategy??state.consents.resolutionStrategy.value;// match the configured consents with user provided consents as per\n// the configured resolution strategy\nswitch(resolutionStrategy){case 'or':return configuredConsents.some(matchPredicate)||configuredConsents.length===0;case 'and':default:return configuredConsents.every(matchPredicate);}}return true;}catch(err){errorHandler?.onError({error:err,context:IUBENDA_CONSENT_MANAGER_PLUGIN,customMessage:DESTINATION_CONSENT_STATUS_ERROR$2});return true;}}}});\n\nconst KETCH_CONSENT_COOKIE_READ_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to read the consent cookie.`;const KETCH_CONSENT_COOKIE_PARSE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to parse the consent cookie.`;const DESTINATION_CONSENT_STATUS_ERROR$1=`Failed to determine the consent status for the destination. Please check the destination configuration and try again.`;\n\nconst KETCH_CONSENT_MANAGER_PLUGIN='KetchConsentManagerPlugin';const KETCH_CONSENT_COOKIE_NAME_V1='_ketch_consent_v1_';\n\n/**\n * Gets the consent data from the Ketch's consent cookie\n * @param storeManager Store manager instance\n * @param logger Logger instance\n * @returns Consent data from the consent cookie\n */const getKetchConsentData=(storeManager,logger)=>{let rawConsentCookieData=null;try{// Create a data store instance to read the consent cookie\nconst dataStore=storeManager?.setStore({id:KETCH_CONSENT_MANAGER_PLUGIN,name:KETCH_CONSENT_MANAGER_PLUGIN,type:COOKIE_STORAGE,errorHandler:storeManager?.errorHandler,logger:storeManager?.logger});rawConsentCookieData=dataStore?.engine.getItem(KETCH_CONSENT_COOKIE_NAME_V1);}
1catch(err){logger?.error(KETCH_CONSENT_COOKIE_READ_ERROR(KETCH_CONSENT_MANAGER_PLUGIN),err);return undefined;}if(isNullOrUndefined(rawConsentCookieData)){return undefined;}// Decode and parse the cookie data to JSON\nlet consentCookieData;try{consentCookieData=JSON.parse(fromBase64(rawConsentCookieData));}catch(err){logger?.error(KETCH_CONSENT_COOKIE_PARSE_ERROR(KETCH_CONSENT_MANAGER_PLUGIN),err);return undefined;}if(!consentCookieData){return undefined;}// Convert the cookie data to consent data\nconst consentPurposes={};Object.entries(consentCookieData).forEach(pEntry=>{const purposeCode=pEntry[0];const purposeValue=pEntry[1];consentPurposes[purposeCode]=purposeValue?.status==='granted';});return consentPurposes;};/**\n * Gets the consent data in the format expected by the application state\n * @param ketchConsentData Consent data derived from the consent cookie\n * @returns Consent data\n */const getConsentData=ketchConsentData=>{const allowedConsentIds=[];const deniedConsentIds=[];if(ketchConsentData){Object.entries(ketchConsentData).forEach(e=>{const purposeCode=e[0];const isConsented=e[1];if(isConsented){allowedConsentIds.push(purposeCode);}else {deniedConsentIds.push(purposeCode);}});}return {allowedConsentIds,deniedConsentIds};};const updateConsentStateFromData=(state,ketchConsentData)=>{const consentData=getConsentData(ketchConsentData);state.consents.initialized.value=isDefined(ketchConsentData);state.consents.data.value=consentData;};\n\nconst pluginName$6='KetchConsentManager';const KetchConsentManager=()=>({name:pluginName$6,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$6];},consentManager:{init(state,logger){// getKetchUserConsentedPurposes returns current ketch opted-in purposes\n// This will be helpful for debugging\nglobalThis.getKetchUserConsentedPurposes=()=>state.consents.data.value.allowedConsentIds?.slice();// getKetchUserDeniedPurposes returns current ketch opted-out purposes\n// This will be helpful for debugging\nglobalThis.getKetchUserDeniedPurposes=()=>state.consents.data.value.deniedConsentIds?.slice();// updateKetchConsent callback function to update current consent purpose state\n// this will be called from ketch rudderstack plugin\nglobalThis.updateKetchConsent=ketchConsentData=>{updateConsentStateFromData(state,ketchConsentData);};},updateConsentsInfo(state,storeManager,logger){// retrieve consent data and update the state\nlet ketchConsentData;if(!isUndefined(globalThis.ketchConsent)){ketchConsentData=globalThis.ketchConsent;}else {ketchConsentData=getKetchConsentData(storeManager,logger);}updateConsentStateFromData(state,ketchConsentData);},isDestinationConsented(state,destConfig,errorHandler,logger){if(!state.consents.initialized.value){return true;}const allowedConsentIds=state.consents.data.value.allowedConsentIds;try{const{ketchConsentPurposes,consentManagement}=destConfig;const matchPredicate=consent=>allowedConsentIds.includes(consent);// Generic consent management\nif(consentManagement){// Get the corresponding consents for the destination\nconst cmpConsents=consentManagement.find(c=>c.provider===state.consents.provider.value)?.consents;// If there are no consents configured for the destination for the current provider, events should be sent.\nif(!cmpConsents){return true;}const configuredConsents=cmpConsents.map(c=>c.consent.trim()).filter(n=>n);// match the configured consents with user provided consents as per\n// the configured resolution strategy\nswitch(state.consents.resolutionStrategy.value){case 'or':return configuredConsents.some(matchPredicate)||configuredConsents.length===0;case 'and':default:return configuredConsents.every(matchPredicate);}// Legacy cookie consent management\n// TODO: To be removed once the source config API is updated to support generic consent management\n}else if(ketchConsentPurposes){const configuredConsents=ketchConsentPurposes.map(p=>p.purpose.trim()).filter(n=>n);// Check if any of the destination's mapped ketch purposes are consented by the user in the browser.\nreturn configuredConsents.some(matchPredicate)||configuredConsents.length===0;}// If there are no consents configured for the destination for the current provider, events should be sent.\nreturn true;}catch(err){errorHandler?.onError({error:err,context:KETCH_CONSENT_MANAGER_PLUGIN,customMessage:DESTINATION_CONSENT_STATUS_ERROR$1});return true;}}}});\n\nconst DEFAULT_QUEUE_OPTIONS={maxItems:100};const QUEUE_NAME$1='rudder_destinations_events';const NATIVE_DESTINATION_QUEUE_PLUGIN='NativeDestinationQueuePlugin';\n\nconst DESTINATION_EVENT_FILTERING_WARNING=(context,eventName,destUserFriendlyId)=>`${context}${LOG_CONTEXT_SEPARATOR}The \"${eventName}\" track event has been filtered for the \"${destUserFriendlyId}\" destination.`;const INTEGRATION_EVENT_FORWARDING_ERROR=(type,id,name)=>`Failed to send \"${type}\" event ${name?`\"${name}\" `:''}to integration for destination \"${id}\".`;\n\nconst getNormalizedQueueOptions$1=queueOpts=>mergeDeepRight(DEFAULT_QUEUE_OPTIONS,queueOpts);const isValidEventName=eventName=>eventName&&typeof eventName==='string';const isEventDenyListed=(eventType,eventName,dest)=>{if(eventType!=='track'){return false;}
1const{blacklistedEvents,whitelistedEvents,eventFilteringOption}=dest.config;switch(eventFilteringOption){// Blacklist is chosen for filtering events\ncase 'blacklistedEvents':{if(!isValidEventName(eventName)){return false;}const trimmedEventName=eventName.trim();if(Array.isArray(blacklistedEvents)){return blacklistedEvents.some(eventObj=>eventObj.eventName.trim()===trimmedEventName);}return false;}// Whitelist is chosen for filtering events\ncase 'whitelistedEvents':{if(!isValidEventName(eventName)){return true;}const trimmedEventName=eventName.trim();if(Array.isArray(whitelistedEvents)){return !whitelistedEvents.some(eventObj=>eventObj.eventName.trim()===trimmedEventName);}return true;}case 'disable':default:return false;}};const sendEventToDestination=(item,dest,errorHandler,logger)=>{const methodName=item.type.toString();try{// Destinations expect the event to be wrapped under the `message` key\nconst integrationEvent={message:item};dest.integration[methodName]?.(integrationEvent);}catch(err){errorHandler?.onError({error:err,context:NATIVE_DESTINATION_QUEUE_PLUGIN,customMessage:INTEGRATION_EVENT_FORWARDING_ERROR(methodName,dest.userFriendlyId,item.event),groupingHash:INTEGRATION_EVENT_FORWARDING_ERROR(methodName,dest.displayName,item.event),category:INTEGRATIONS_ERROR_CATEGORY});}};/**\n * A function to check if device mode transformation should be applied for a destination.\n * @param dest Destination object\n * @returns Boolean indicating whether the transformation should be applied\n */const shouldApplyTransformation=dest=>{return dest.shouldApplyDeviceModeTransformation;};\n\nconst pluginName$5='NativeDestinationQueue';const NativeDestinationQueue=()=>({name:pluginName$5,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$5];},destinationsEventsQueue:{/**\n * Initialize the queue for delivery to destinations\n * @param state Application state\n * @param pluginsManager PluginsManager instance\n * @param storeManager StoreManager instance\n * @param errorHandler Error handler instance\n * @param logger Logger instance\n * @returns IQueue instance\n */init(state,pluginsManager,storeManager,dmtQueue,errorHandler,logger){const finalQOpts=getNormalizedQueueOptions$1(state.loadOptions.value.destinationsQueueOptions);const writeKey=state.lifecycle.writeKey.value;const eventsQueue=new RetryQueue(// adding write key to the queue name to avoid conflicts\n`${QUEUE_NAME$1}_${writeKey}`,finalQOpts,(rudderEvent,done)=>{const destinationsToSend=filterDestinations(rudderEvent.integrations,state.nativeDestinations.initializedDestinations.value);// list of destinations which are enable for DMT\nconst destWithTransformationEnabled=[];const clonedRudderEvent=clone(rudderEvent);destinationsToSend.forEach(dest=>{try{const sendEvent=!isEventDenyListed(clonedRudderEvent.type,clonedRudderEvent.event,dest);if(!sendEvent){logger?.warn(DESTINATION_EVENT_FILTERING_WARNING(NATIVE_DESTINATION_QUEUE_PLUGIN,clonedRudderEvent.event,dest.userFriendlyId));return;}if(shouldApplyTransformation(dest)){destWithTransformationEnabled.push(dest);}else {sendEventToDestination(clonedRudderEvent,dest,errorHandler,logger);}}catch(e){errorHandler?.onError({error:e,context:NATIVE_DESTINATION_QUEUE_PLUGIN,category:INTEGRATIONS_ERROR_CATEGORY});}});if(destWithTransformationEnabled.length>0){pluginsManager.invokeSingle('transformEvent.enqueue',state,dmtQueue,clonedRudderEvent,destWithTransformationEnabled,errorHandler,logger);}// Mark success always\ndone(null);},storeManager,MEMORY_STORAGE);// TODO: This seems to not work as expected. Need to investigate\n// effect(() => {\n// if (state.nativeDestinations.clientDestinationsReady.value === true) {\n// eventsQueue.start();\n// }\n// });\nreturn eventsQueue;},/**\n * Add event to the queue for delivery to destinations\n * @param state Application state\n * @param eventsQueue IQueue instance\n * @param event RudderEvent object\n * @param errorHandler Error handler instance\n * @param logger Logger instance\n * @returns none\n */enqueue(state,eventsQueue,event,errorHandler,logger){eventsQueue.addItem(event);},/**\n * This extension point is used to directly send the transformed event to the destination\n * @param state Application state\n * @param event RudderEvent Object\n * @param destination Destination Object\n * @param errorHandler Error handler instance\n * @param logger Logger instance\n */enqueueEventToDestination(state,event,destination,errorHandler,logger){sendEventToDestination(event,destination,errorHandler);}}});\n\nconst ONETRUST_ACCESS_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to access OneTrust SDK resources. Please ensure that the OneTrust SDK is loaded successfully before RudderStack SDK.`;const DESTINATION_CONSENT_STATUS_ERROR=`Failed to determine the consent status for the destination. Please check the destination configuration and try again.`;\n\nconst ONETRUST_CONSENT_MANAGER_PLUGIN='OneTrustConsentManagerPlugin';\n\nconst pluginName$4='OneTrustConsentManager';const OneTrustConsentManager=()=>({name:pluginName$4,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$4];},consentManager:{init(state,logger){// Nothing to initialize\n},updateConsentsInfo(state,storeManager,logger){if(!globalThis.OneTrust||!globalThis.OnetrustActiveGroups){logger?.error(ONETRUST_ACCESS_ERROR(ONETRUST_CONSENT_MANAGER_PLUGIN));state.consents.initialized.value=false;return;}// Get the groups (cookie categorization), user has created in OneTrust account.\nconst oneTrustAllGroupsInfo=globalThis.OneTrust.GetDomainData().Groups;// OneTrustConsentManager SDK populates a data layer object OnetrustActiveGroups with\n// the cookie categories Ids that the user has consented to.\n// Eg: ',C0001,C0003,'\n// We split it and save it as an array.\nconst allowedConsentIds=globalThis.OnetrustActiveGroups.split(',').filter(n=>n);const deniedConsentIds=[];oneTrustAllGroupsInfo.forEach(({CustomGroupId})=>{if(!allowedConsentIds.includes(CustomGroupId)){deniedConsentIds.push(CustomGroupId);}});state.consents.initialized.value=true;state.consents.data.value={allowedConsentIds,deniedConsentIds};},isDestinationConsented(state,destConfig,errorHandler,logger){if(!state.consents.initialized.value){return true;}const allowedConsentIds=state.consents.data.value.allowedConsentIds;try{// mapping of the destination with the consent group name\nconst{oneTrustCookieCategories,consentManagement}=destConfig;const matchPredicate=consent=>allowedConsentIds.includes(consent);// Generic consent management\nif(consentManagement){// Get the corresponding consents for the destination\nconst cmpConsents=consentManagement.find(c=>c.provider===state.consents.provider.value)?.consents;// If there are no consents configured for the destination for the current provider, events should be sent.\nif(!cmpConsents){return true;}const configuredConsents=cmpConsents.map(c=>c.consent.trim()).filter(n=>n);// match the configured consents with user provided consents as per\n// the configured resolution strategy\nswitch(state.consents.resolutionStrategy.value){case 'or':return configuredConsents.some(matchPredicate)||configuredConsents.length===0;case 'and':default:return configuredConsents.every(matchPredicate);}// Legacy cookie consent management\n// TODO: To be removed once the source config API is updated to support generic consent management\n}else if(oneTrustCookieCategories){// Change the structure of oneTrustConsentGroup as an array and filter values if empty string\n// Eg:\n// [\"Performance Cookies\", \"Fu
1nctional Cookies\"]\nconst configuredConsents=oneTrustCookieCategories.map(c=>c.oneTrustCookieCategory.trim()).filter(n=>n);// Check if all the destination's mapped cookie categories are consented by the user in the browser.\nreturn configuredConsents.every(matchPredicate);}// If there are no consents configured for the destination for the current provider, events should be sent.\nreturn true;}catch(err){errorHandler?.onError({error:err,context:ONETRUST_CONSENT_MANAGER_PLUGIN,customMessage:DESTINATION_CONSENT_STATUS_ERROR});return true;}}}});\n\nconst pluginName$3='StorageEncryption';const StorageEncryption=()=>({name:pluginName$3,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$3];},storage:{encrypt(value){return encryptBrowser(value);},decrypt(value){return decryptBrowser(value);}}});\n\n/* eslint-disable no-use-before-define */const crypto$1=(typeof globalThis!='undefined'?globalThis:void 0)?.crypto||(typeof __webpack_require__.g!='undefined'?__webpack_require__.g:void 0)?.crypto||(typeof window!='undefined'?window:void 0)?.crypto||(typeof self!='undefined'?self:void 0)?.crypto||(typeof frames!='undefined'?frames:void 0)?.[0]?.crypto;let randomWordArray;if(crypto$1){randomWordArray=nBytes=>{const words=[];for(let i=0,rcache;i<nBytes;i+=4){words.push(crypto$1.getRandomValues(new Uint32Array(1))[0]);}return new WordArray(words,nBytes);};}else {// Because there is no global crypto property in this context, cryptographically unsafe Math.random() is used.\nrandomWordArray=nBytes=>{const words=[];const r=m_w=>{let _m_w=m_w;let _m_z=0x3ade68b1;const mask=0xffffffff;return ()=>{_m_z=0x9069*(_m_z&0xFFFF)+(_m_z>>0x10)&mask;_m_w=0x4650*(_m_w&0xFFFF)+(_m_w>>0x10)&mask;let result=(_m_z<<0x10)+_m_w&mask;result/=0x100000000;result+=0.5;return result*(Math.random()>0.5?1:-1);};};for(let i=0,rcache;i<nBytes;i+=4){const _r=r((rcache||Math.random())*0x100000000);rcache=_r()*0x3ade67b7;words.push(_r()*0x100000000|0);}return new WordArray(words,nBytes);};}/**\n * Base class for inheritance.\n */class Base{/**\n * Extends this object and runs the init method.\n * Arguments to create() will be passed to init().\n *\n * @return {Object} The new object.\n *\n * @static\n *\n * @example\n *\n * var instance = MyType.create();\n */static create(...args){return new this(...args);}/**\n * Copies properties into this object.\n *\n * @param {Object} properties The properties to mix in.\n *\n * @example\n *\n * MyType.mixIn({\n * field: 'value'\n * });\n */mixIn(properties){return Object.assign(this,properties);}/**\n * Creates a copy of this object.\n *\n * @return {Object} The clone.\n *\n * @example\n *\n * var clone = instance.clone();\n */clone(){const clone=new this.constructor();Object.assign(clone,this);return clone;}}/**\n * An array of 32-bit words.\n *\n * @property {Array} words The array of 32-bit words.\n * @property {number} sigBytes The number of significant bytes in this word array.\n */class WordArray extends Base{/**\n * Initializes a newly created word array.\n *\n * @param {Array} words (Optional) An array of 32-bit words.\n * @param {number} sigBytes (Optional) The number of significant bytes in the words.\n *\n * @example\n *\n * var wordArray = CryptoJS.lib.WordArray.create();\n * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);\n * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);\n */constructor(words=[],sigBytes=words.length*4){super();let typedArray=words;// Convert buffers to uint8\nif(typedArray instanceof ArrayBuffer){typedArray=new Uint8Array(typedArray);}// Convert other array views to uint8\nif(typedArray instanceof Int8Array||typedArray instanceof Uint8ClampedArray||typedArray instanceof Int16Array||typedArray instanceof Uint16Array||typedArray instanceof Int32Array||typedArray instanceof Uint32Array||typedArray instanceof Float32Array||typedArray instanceof Float64Array){typedArray=new Uint8Array(typedArray.buffer,typedArray.byteOffset,typedArray.byteLength);}// Handle Uint8Array\nif(typedArray instanceof Uint8Array){// Shortcut\nconst typedArrayByteLength=typedArray.byteLength;// Extract bytes\nconst _words=[];for(let i=0;i<typedArrayByteLength;i+=1){_words[i>>>2]|=typedArray[i]<<24-i%4*8;}// Initialize this word array\nthis.words=_words;this.sigBytes=typedArrayByteLength;}else {// Else call normal init\nthis.words=words;this.sigBytes=sigBytes;}}/**\n * Creates a word array filled with random bytes.\n *\n * @param {number} nBytes The number of random bytes to generate.\n *\n * @return {WordArray} The random word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.lib.WordArray.random(16);\n */static random=randomWordArray;/**\n * Converts this word array to a string.\n *\n * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex\n *\n * @return {string} The stringified word array.\n *\n * @example\n *\n * var string = wordArray + '';\n * var string = wordArray.toString();\n * var string = wordArray.toString(CryptoJS.enc.Utf8);\n */toString(encoder=Hex){return encoder.stringify(this);}/**\n * Concatenates a word array to this word array.\n *\n * @param {WordArray} wordArray The word array to append.\n *\n * @return {WordArray} This word array.\n *\n * @example\n *\n * wordArray1.concat(wordArray2);\n */concat(wordArray){// Shortcuts\nconst thisWords=this.words;const thatWords=wordArray.words;const thisSigBytes=this.sigBytes;const thatSigBytes=wordArray.sigBytes;// Clamp excess bits\nthis.clamp();// Concat\nif(thisSigBytes%4){// Copy one byte at a time\nfor(let i=0;i<thatSigBytes;i+=1){const thatByte=thatWords[i>>>2]>>>24-i%4*8&0xff;thisWords[thisSigBytes+i>>>2]|=thatByte<<24-(thisSigBytes+i)%4*8;}}else {// Copy one word at a time\nfor(let i=0;i<thatSigBytes;i+=4){thisWords[thisSigBytes+i>>>2]=thatWords[i>>>2];}}this.sigBytes+=thatSigBytes;// Chainable\nreturn this;}
1/**\n * Removes insignificant bits.\n *\n * @example\n *\n * wordArray.clamp();\n */clamp(){// Shortcuts\nconst{words,sigBytes}=this;// Clamp\nwords[sigBytes>>>2]&=0xffffffff<<32-sigBytes%4*8;words.length=Math.ceil(sigBytes/4);}/**\n * Creates a copy of this word array.\n *\n * @return {WordArray} The clone.\n *\n * @example\n *\n * var clone = wordArray.clone();\n */clone(){const clone=super.clone.call(this);clone.words=this.words.slice(0);return clone;}}/**\n * Hex encoding strategy.\n */const Hex={/**\n * Converts a word array to a hex string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The hex string.\n *\n * @static\n *\n * @example\n *\n * var hexString = CryptoJS.enc.Hex.stringify(wordArray);\n */stringify(wordArray){// Shortcuts\nconst{words,sigBytes}=wordArray;// Convert\nconst hexChars=[];for(let i=0;i<sigBytes;i+=1){const bite=words[i>>>2]>>>24-i%4*8&0xff;hexChars.push((bite>>>4).toString(16));hexChars.push((bite&0x0f).toString(16));}return hexChars.join('');},/**\n * Converts a hex string to a word array.\n *\n * @param {string} hexStr The hex string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Hex.parse(hexString);\n */parse(hexStr){// Shortcut\nconst hexStrLength=hexStr.length;// Convert\nconst words=[];for(let i=0;i<hexStrLength;i+=2){words[i>>>3]|=parseInt(hexStr.substr(i,2),16)<<24-i%8*4;}return new WordArray(words,hexStrLength/2);}};/**\n * Latin1 encoding strategy.\n */const Latin1={/**\n * Converts a word array to a Latin1 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Latin1 string.\n *\n * @static\n *\n * @example\n *\n * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);\n */stringify(wordArray){// Shortcuts\nconst{words,sigBytes}=wordArray;// Convert\nconst latin1Chars=[];for(let i=0;i<sigBytes;i+=1){const bite=words[i>>>2]>>>24-i%4*8&0xff;latin1Chars.push(String.fromCharCode(bite));}return latin1Chars.join('');},/**\n * Converts a Latin1 string to a word array.\n *\n * @param {string} latin1Str The Latin1 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);\n */parse(latin1Str){// Shortcut\nconst latin1StrLength=latin1Str.length;// Convert\nconst words=[];for(let i=0;i<latin1StrLength;i+=1){words[i>>>2]|=(latin1Str.charCodeAt(i)&0xff)<<24-i%4*8;}return new WordArray(words,latin1StrLength);}};/**\n * UTF-8 encoding strategy.\n */const Utf8={/**\n * Converts a word array to a UTF-8 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The UTF-8 string.\n *\n * @static\n *\n * @example\n *\n * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);\n */stringify(wordArray){try{return decodeURIComponent(escape(Latin1.stringify(wordArray)));}catch(e){throw new Error('Malformed UTF-8 data');}},/**\n * Converts a UTF-8 string to a word array.\n *\n * @param {string} utf8Str The UTF-8 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * var wordArray = CryptoJS.enc.Utf8.parse(utf8Str
1ing);\n */parse(utf8Str){return Latin1.parse(unescape(encodeURIComponent(utf8Str)));}};/**\n * Abstract buffered block algorithm template.\n *\n * The property blockSize must be implemented in a concrete subtype.\n *\n * @property {number} _minBufferSize\n *\n * The number of blocks that should be kept unprocessed in the buffer. Default: 0\n */class BufferedBlockAlgorithm extends Base{constructor(){super();this._minBufferSize=0;}/**\n * Resets this block algorithm's data buffer to its initial state.\n *\n * @example\n *\n * bufferedBlockAlgorithm.reset();\n */reset(){// Initial values\nthis._data=new WordArray();this._nDataBytes=0;}/**\n * Adds new data to this block algorithm's buffer.\n *\n * @param {WordArray|string} data\n *\n * The data to append. Strings are converted to a WordArray using UTF-8.\n *\n * @example\n *\n * bufferedBlockAlgorithm._append('data');\n * bufferedBlockAlgorithm._append(wordArray);\n */_append(data){let m_data=data;// Convert string to WordArray, else assume WordArray already\nif(typeof m_data==='string'){m_data=Utf8.parse(m_data);}// Append\nthis._data.concat(m_data);this._nDataBytes+=m_data.sigBytes;}/**\n * Processes available data blocks.\n *\n * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.\n *\n * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.\n *\n * @return {WordArray} The processed data.\n *\n * @example\n *\n * var processedData = bufferedBlockAlgorithm._process();\n * var processedData = bufferedBlockAlgorithm._process(!!'flush');\n */_process(doFlush){let processedWords;// Shortcuts\nconst{_data:data,blockSize}=this;const dataWords=data.words;const dataSigBytes=data.sigBytes;const blockSizeBytes=blockSize*4;// Count blocks ready\nlet nBlocksReady=dataSigBytes/blockSizeBytes;if(doFlush){// Round up to include partial blocks\nnBlocksReady=Math.ceil(nBlocksReady);}else {// Round down to include only full blocks,\n// less the number of blocks that must remain in the buffer\nnBlocksReady=Math.max((nBlocksReady|0)-this._minBufferSize,0);}// Count words ready\nconst nWordsReady=nBlocksReady*blockSize;// Count bytes ready\nconst nBytesReady=Math.min(nWordsReady*4,dataSigBytes);// Process blocks\nif(nWordsReady){for(let offset=0;offset<nWordsReady;offset+=blockSize){// Perform concrete-algorithm logic\nthis._doProcessBlock(dataWords,offset);}// Remove processed words\nprocessedWords=dataWords.splice(0,nWordsReady);data.sigBytes-=nBytesReady;}// Return processed words\nreturn new WordArray(processedWords,nBytesReady);}/**\n * Creates a copy of this object.\n *\n * @return {Object} The clone.\n *\n * @example\n *\n * var clone = bufferedBlockAlgorithm.clone();\n */clone(){const clone=super.clone.call(this);clone._data=this._data.clone();return clone;}}/**\n * Abstract hasher template.\n *\n * @property {number} blockSize\n *\n * The number of 32-bit words this hasher operates on. Default: 16 (512 bits)\n */class Hasher extends BufferedBlockAlgorithm{constructor(cfg){super();this.blockSize=512/32;/**\n * Configuration options.\n */this.cfg=Object.assign(new Base(),cfg);// Set initial values\nthis.reset();}/**\n * Creates a shortcut function to a hasher's object interface.\n *\n * @param {Hasher} SubHasher The hasher to create a helper for.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);\n */static _createHelper(SubHasher){return (message,cfg)=>new SubHasher(cfg).finalize(message);}/**\n * Creates a shortcut function to the HMAC's object interface.\n *\n * @param {Hasher} SubHasher The hasher to use in this HMAC helper.\n *\n * @return {Function} The shortcut function.\n *\n * @static\n *\n * @example\n *\n * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);\n */static _createHmacHelper(SubHasher){return (message,key)=>new HMAC(SubHasher,key).finalize(message);}/**\n * Resets this hasher to its initial state.\n *\n * @example\n *\n * hasher.reset();\n */reset(){// Reset data buffer\nsuper.reset.call(this);// Perform concrete-hasher logic\nthis._doReset();}/**\n * Updates this hasher with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {Hasher} This hasher.\n *\n * @example\n *\n * hasher.update('message');\n * hasher.update(wordArray);\n */update(messageUpdate){// Append\nthis._append(messageUpdate);// Update the hash\nthis._process();// Chainable\nreturn this;}
1/**\n * Finalizes the hash computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The hash.\n *\n * @example\n *\n * var hash = hasher.finalize();\n * var hash = hasher.finalize('message');\n * var hash = hasher.finalize(wordArray);\n */finalize(messageUpdate){// Final message update\nif(messageUpdate){this._append(messageUpdate);}// Perform concrete-hasher logic\nconst hash=this._doFinalize();return hash;}}/**\n * HMAC algorithm.\n */class HMAC extends Base{/**\n * Initializes a newly created HMAC.\n *\n * @param {Hasher} SubHasher The hash algorithm to use.\n * @param {WordArray|string} key The secret key.\n *\n * @example\n *\n * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);\n */constructor(SubHasher,key){super();const hasher=new SubHasher();this._hasher=hasher;// Convert string to WordArray, else assume WordArray already\nlet _key=key;if(typeof _key==='string'){_key=Utf8.parse(_key);}// Shortcuts\nconst hasherBlockSize=hasher.blockSize;const hasherBlockSizeBytes=hasherBlockSize*4;// Allow arbitrary length keys\nif(_key.sigBytes>hasherBlockSizeBytes){_key=hasher.finalize(key);}// Clamp excess bits\n_key.clamp();// Clone key for inner and outer pads\nconst oKey=_key.clone();this._oKey=oKey;const iKey=_key.clone();this._iKey=iKey;// Shortcuts\nconst oKeyWords=oKey.words;const iKeyWords=iKey.words;// XOR keys with pad constants\nfor(let i=0;i<hasherBlockSize;i+=1){oKeyWords[i]^=0x5c5c5c5c;iKeyWords[i]^=0x36363636;}oKey.sigBytes=hasherBlockSizeBytes;iKey.sigBytes=hasherBlockSizeBytes;// Set initial values\nthis.reset();}/**\n * Resets this HMAC to its initial state.\n *\n * @example\n *\n * hmacHasher.reset();\n */reset(){// Shortcut\nconst hasher=this._hasher;// Reset\nhasher.reset();hasher.update(this._iKey);}/**\n * Updates this HMAC with a message.\n *\n * @param {WordArray|string} messageUpdate The message to append.\n *\n * @return {HMAC} This HMAC instance.\n *\n * @example\n *\n * hmacHasher.update('message');\n * hmacHasher.update(wordArray);\n */update(messageUpdate){this._hasher.update(messageUpdate);// Chainable\nreturn this;}/**\n * Finalizes the HMAC computation.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} messageUpdate (Optional) A final message update.\n *\n * @return {WordArray} The HMAC.\n *\n * @example\n *\n * var hmac = hmacHasher.finalize();\n * var hmac = hmacHasher.finalize('message');\n * var hmac = hmacHasher.finalize(wordArray);\n */finalize(messageUpdate){// Shortcut\nconst hasher=this._hasher;// Compute HMAC\nconst innerHash=hasher.finalize(messageUpdate);hasher.reset();const hmac=hasher.finalize(this._oKey.clone().concat(innerHash));return hmac;}}\n\nconst parseLoop=(base64Str,base64StrLength,reverseMap)=>{const words=[];let nBytes=0;for(let i=0;i<base64StrLength;i+=1){if(i%4){const bits1=reverseMap[base64Str.charCodeAt(i-1)]<<i%4*2;const bits2=reverseMap[base64Str.charCodeAt(i)]>>>6-i%4*2;const bitsCombined=bits1|bits2;words[nBytes>>>2]|=bitsCombined<<24-nBytes%4*8;nBytes+=1;}}return WordArray.create(words,nBytes);};/**\n * Base64 encoding strategy.\n */const Base64={/**\n * Converts a word array to a Base64 string.\n *\n * @param {WordArray} wordArray The word array.\n *\n * @return {string} The Base64 string.\n *\n * @static\n *\n * @example\n *\n * const base64String = CryptoJS.enc.Base64.stringify(wordArray);\n */stringify(wordArray){// Shortcuts\nconst{words,sigBytes}=wordArray;const map=this._map;// Clamp excess bits\nwordArray.clamp();// Convert\nconst base64Chars=[];for(let i=0;i<sigBytes;i+=3){const byte1=words[i>>>2]>>>24-i%4*8&0xff;const byte2=words[i+1>>>2]>>>24-(i+1)%4*8&0xff;const byte3=words[i+2>>>2]>>>24-(i+2)%4*8&0xff;const triplet=byte1<<16|byte2<<8|byte3;
1for(let j=0;j<4&&i+j*0.75<sigBytes;j+=1){base64Chars.push(map.charAt(triplet>>>6*(3-j)&0x3f));}}// Add padding\nconst paddingChar=map.charAt(64);if(paddingChar){while(base64Chars.length%4){base64Chars.push(paddingChar);}}return base64Chars.join('');},/**\n * Converts a Base64 string to a word array.\n *\n * @param {string} base64Str The Base64 string.\n *\n * @return {WordArray} The word array.\n *\n * @static\n *\n * @example\n *\n * const wordArray = CryptoJS.enc.Base64.parse(base64String);\n */parse(base64Str){// Shortcuts\nlet base64StrLength=base64Str.length;const map=this._map;let reverseMap=this._reverseMap;if(!reverseMap){this._reverseMap=[];reverseMap=this._reverseMap;for(let j=0;j<map.length;j+=1){reverseMap[map.charCodeAt(j)]=j;}}// Ignore padding\nconst paddingChar=map.charAt(64);if(paddingChar){const paddingIndex=base64Str.indexOf(paddingChar);if(paddingIndex!==-1){base64StrLength=paddingIndex;}}// Convert\nreturn parseLoop(base64Str,base64StrLength,reverseMap);},_map:'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='};\n\nconst T=[];// Compute constants\nfor(let i=0;i<64;i+=1){T[i]=Math.abs(Math.sin(i+1))*0x100000000|0;}const FF=(a,b,c,d,x,s,t)=>{const n=a+(b&c|~b&d)+x+t;return (n<<s|n>>>32-s)+b;};const GG=(a,b,c,d,x,s,t)=>{const n=a+(b&d|c&~d)+x+t;return (n<<s|n>>>32-s)+b;};const HH=(a,b,c,d,x,s,t)=>{const n=a+(b^c^d)+x+t;return (n<<s|n>>>32-s)+b;};const II=(a,b,c,d,x,s,t)=>{const n=a+(c^(b|~d))+x+t;return (n<<s|n>>>32-s)+b;};/**\n * MD5 hash algorithm.\n */class MD5Algo extends Hasher{_doReset(){this._hash=new WordArray([0x67452301,0xefcdab89,0x98badcfe,0x10325476]);}_doProcessBlock(M,offset){const _M=M;// Swap endian\nfor(let i=0;i<16;i+=1){// Shortcuts\nconst offset_i=offset+i;const M_offset_i=M[offset_i];_M[offset_i]=(M_offset_i<<8|M_offset_i>>>24)&0x00ff00ff|(M_offset_i<<24|M_offset_i>>>8)&0xff00ff00;}// Shortcuts\nconst H=this._hash.words;const M_offset_0=_M[offset+0];const M_offset_1=_M[offset+1];const M_offset_2=_M[offset+2];const M_offset_3=_M[offset+3];const M_offset_4=_M[offset+4];const M_offset_5=_M[offset+5];const M_offset_6=_M[offset+6];const M_offset_7=_M[offset+7];const M_offset_8=_M[offset+8];const M_offset_9=_M[offset+9];const M_offset_10=_M[offset+10];const M_offset_11=_M[offset+11];const M_offset_12=_M[offset+12];const M_offset_13=_M[offset+13];const M_offset_14=_M[offset+14];const M_offset_15=_M[offset+15];// Working varialbes\nlet a=H[0];let b=H[1];let c=H[2];let d=H[3];// Computation\na=FF(a,b,c,d,M_offset_0,7,T[0]);d=FF(d,a,b,c,M_offset_1,12,T[1]);c=FF(c,d,a,b,M_offset_2,17,T[2]);b=FF(b,c,d,a,M_offset_3,22,T[3]);a=FF(a,b,c,d,M_offset_4,7,T[4]);d=FF(d,a,b,c,M_offset_5,12,T[5]);c=FF(c,d,a,b,M_offset_6,17,T[6]);b=FF(b,c,d,a,M_offset_7,22,T[7]);a=FF(a,b,c,d,M_offset_8,7,T[8]);d=FF(d,a,b,c,M_offset_9,12,T[9]);c=FF(c,d,a,b,M_offset_10,17,T[10]);b=FF(b,c,d,a,M_offset_11,22,T[11]);a=FF(a,b,c,d,M_offset_12,7,T[12]);d=FF(d,a,b,c,M_offset_13,12,T[13]);c=FF(c,d,a,b,M_offset_14,17,T[14]);b=FF(b,c,d,a,M_offset_15,22,T[15]);a=GG(a,b,c,d,M_offset_1,5,T[16]);d=GG(d,a,b,c,M_offset_6,9,T[17]);c=GG(c,d,a,b,M_offset_11,14,T[18]);b=GG(b,c,d,a,M_offset_0,20,T[19]);a=GG(a,b,c,d,M_offset_5,5,T[20]);d=GG(d,a,b,c,M_offset_10,9,T[21]);c=GG(c,d,a,b,M_offset_15,14,T[22]);b=GG(b,c,d,a,M_offset_4,20,T[23]);a=GG(a,b,c,d,M_offset_9,5,T[24]);d=GG(d,a,b,c,M_offset_14,9,T[25]);c=GG(c,d,a,b,M_offset_3,14,T[26]);b=GG(b,c,d,a,M_offset_8,20,T[27]);a=GG(a,b,c,d,M_offset_13,5,T[28]);d=GG(d,a,b,c,M_offset_2,9,T[29]);c=GG(c,d,a,b,M_offset_7,14,T[30]);b=GG(b,c,d,a,M_offset_12,20,T[31]);a=HH(a,b,c,d,M_offset_5,4,T[32]);d=HH(d,a,b,c,M_offset_8,11,T[33]);c=HH(c,d,a,b,M_offset_11,16,T[34]);b=HH(b,c,d,a,M_offset_14,23,T[35]);a=HH(a,b,c,d,M_offset_1,4,T[36]);d=HH(d,a,b,c,M_offset_4,11,T[37]);c=HH(c,d,a,b,M_offset_7,16,T[38]);b=HH(b,c,d,a,M_offset_10,23,T[39]);a=HH(a,b,c,d,M_offset_13,4,T[40]);d=HH(d,a,b,c,M_offset_0,11,T[41]);c=HH(c,d,a,b,M_offset_3,16,T[42]);b=HH(b,c,d,a,M_offset_6,23,T[43]);a=HH(a,b,c,d,M_offset_9,4,T[44]);d=HH(d,a,b,c,M_offset_12,11,T[45]);c=HH(c,d,a,b,M_offset_15,16,T[46]);b=HH(b,c,d,a,M_offset_2,23,T[47]);a=II(a,b,c,d,M_offset_0,6,T[48]);d=II(d,a,b,c,M_offset_7,10,T[49]);c=II(c,d,a,b,M_offset_14,15,T[50]);b=II(b,c,d,a,M_offset_5,21,T[51]);a=II(a,b,c,d,M_offset_12,6,T[52]);d=II(d,a,b,c,M_offset_3,10,T[53]);c=II(c,d,a,b,M_offset_10,15,T[54]);b=II(b,c,d,a,M_offset_1,21,T[55]);a=II(a,b,c,d,M_offset_8,6,T[56]);d=II(d,a,b,c,M_offset_15,10,T[57]);c=II(c,d,a,b,M_offset_6,15,T[58]);b=II(b,c,d,a,M_offset_13,21,T[59]);a=II(a,b,c,d,M_offset_4,6,T[60]);d=II(d,a,b,c,M_offset_11,10,T[61]);c=II(c,d,a,b,M_offset_2,15,T[62]);b=II(b,c,d,a,M_offset_9,21,T[63]);// Intermediate hash value\nH[0]=H[0]+a|0;H[1]=H[1]+b|0;H[2]=H[2]+c|0;H[3]=H[3]+d|0;}/* eslint-ensable no-param-reassign */_doFinalize(){// Shortcuts\nconst data=this._data;const dataWords=data.words;const nBitsTotal=this._nDataBytes*8;const nBitsLeft=data.sigBytes*8;// Add padding\ndataWords[nBitsLeft>>>5]|=0x80<<24-nBitsLeft%32;const nBitsTotalH=Math.floor(nBitsTotal/0x100000000);const nBitsTotalL=nBitsTotal;dataWords[(nBitsLeft+64>>>9<<4)+15]=(nBitsTotalH<<8|nBitsTotalH>>>24)&0x00ff00ff|(nBitsTotalH<<24|nBitsTotalH>>>8)&0xff00ff00;dataWords[(nBitsLeft+64>>>9<<4)+14]=(nBitsTotalL<<8|nBitsTotalL>>>24)&0x00ff00ff|(nBitsTotalL<<24|nBitsTotalL>>>8)&0xff00ff00;data.sigBytes=(dataWords.length+1)*4;// Hash final blocks\nthis._process();// Shortcuts\nconst hash=this._hash;const H=hash.words;// Swap endian\nfor(let i=0;i<4;
1i+=1){// Shortcut\nconst H_i=H[i];H[i]=(H_i<<8|H_i>>>24)&0x00ff00ff|(H_i<<24|H_i>>>8)&0xff00ff00;}// Return final computed hash\nreturn hash;}clone(){const clone=super.clone.call(this);clone._hash=this._hash.clone();return clone;}}\n\n/**\n * This key derivation function is meant to conform with EVP_BytesToKey.\n * www.openssl.org/docs/crypto/EVP_BytesToKey.html\n */class EvpKDFAlgo extends Base{/**\n * Initializes a newly created key derivation function.\n *\n * @param {Object} cfg (Optional) The configuration options to use for the derivation.\n *\n * @example\n *\n * const kdf = CryptoJS.algo.EvpKDF.create();\n * const kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 });\n * const kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 });\n */constructor(cfg){super();/**\n * Configuration options.\n *\n * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)\n * @property {Hasher} hasher The hash algorithm to use. Default: MD5\n * @property {number} iterations The number of iterations to perform. Default: 1\n */this.cfg=Object.assign(new Base(),{keySize:128/32,hasher:MD5Algo,iterations:1},cfg);}/**\n * Derives a key from a password.\n *\n * @param {WordArray|string} password The password.\n * @param {WordArray|string} salt A salt.\n *\n * @return {WordArray} The derived key.\n *\n * @example\n *\n * const key = kdf.compute(password, salt);\n */compute(password,salt){let block;// Shortcut\nconst{cfg}=this;// Init hasher\nconst hasher=cfg.hasher.create();// Initial values\nconst derivedKey=WordArray.create();// Shortcuts\nconst derivedKeyWords=derivedKey.words;const{keySize,iterations}=cfg;// Generate key\nwhile(derivedKeyWords.length<keySize){if(block){hasher.update(block);}block=hasher.update(password).finalize(salt);hasher.reset();// Iterations\nfor(let i=1;i<iterations;i+=1){block=hasher.finalize(block);hasher.reset();}derivedKey.concat(block);}derivedKey.sigBytes=keySize*4;return derivedKey;}}\n\n// IE11 compatibility shim for Object.assign\n//\n// Why this patch exists:\n// crypto-es ships as native ESM and calls `Object.assign` directly inside its\n// module body. The SDK's legacy bundle must keep working in IE11, which does\n// not implement `Object.assign` natively.\n//\n// The SDK *does* load polyfill.io at runtime via CapabilitiesManager, but\n// that loader is asynchronous and runs AFTER crypto-es's module-level code\n// (class statics, default configs) has already been evaluated â see\n// `SerializableCipher.cfg = Object.assign(...)` and\n// `PasswordBasedCipher.cfg = Object.assign(...)` below. Without this shim,\n// those evaluations throw `Object.assign is not a function` before any\n// polyfill has had a chance to attach.\n//\n// This is the minimum-viable fix: a local `ObjectAssign` that falls back to\n// a spec-compliant implementation only when the runtime lacks the native\n// one. Every `Object.assign(...)` call in this file is rewritten to call it.\n//\n// Scope:\n// Only `cipher-core.js` is patched â it contains the call sites actually\n// exercised by the SDK in legacy builds. If new `Object.assign` usages\n// surface in other crypto-es files (e.g. core.js), extend the same pattern\n// there.\n// -----------------------------------------------------------------------------\nconst ObjectAssign=typeof Object.assign!==\"function\"?function(target){if(target==null)throw new TypeError('Cannot convert undefined or null to object');target=Object(target);for(let index=1;index<arguments.length;index++){const source=arguments[index];if(source!=null)for(const key in source)if(Object.prototype.hasOwnProperty.call(source,key))target[key]=source[key];}return target;}:Object.assign;/**\n * Abstract base cipher template.\n *\n * @property {number} keySize This cipher's key size. Default: 4 (128 bits)\n * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits)\n * @property {number} _ENC_XFORM_MODE A constant representing encryption mode.\n * @property {number} _DEC_XFORM_MODE A constant representing decryption mode.\n */class Cipher extends BufferedBlockAlgorithm{/**\n * Initializes a newly created cipher.\n *\n * @param {number} xformMode Either the encryption or decryption transormation mode constant.\n * @param {WordArray} key The key.\n * @param {Object} cfg (Optional) The configuration options to use for this operation.\n *\n * @example\n *\n * const cipher = CryptoJS.algo.AES.create(\n * CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }\n * );
1\n */constructor(xformMode,key,cfg){super();/**\n * Configuration options.\n *\n * @property {WordArray} iv The IV to use for this operation.\n */this.cfg=ObjectAssign(new Base(),cfg);// Store transform mode and key\nthis._xformMode=xformMode;this._key=key;// Set initial values\nthis.reset();}/**\n * Creates this cipher in encryption mode.\n *\n * @param {WordArray} key The key.\n * @param {Object} cfg (Optional) The configuration options to use for this operation.\n *\n * @return {Cipher} A cipher instance.\n *\n * @static\n *\n * @example\n *\n * const cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });\n */static createEncryptor(key,cfg){return this.create(this._ENC_XFORM_MODE,key,cfg);}/**\n * Creates this cipher in decryption mode.\n *\n * @param {WordArray} key The key.\n * @param {Object} cfg (Optional) The configuration options to use for this operation.\n *\n * @return {Cipher} A cipher instance.\n *\n * @static\n *\n * @example\n *\n * const cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });\n */static createDecryptor(key,cfg){return this.create(this._DEC_XFORM_MODE,key,cfg);}/**\n * Creates shortcut functions to a cipher's object interface.\n *\n * @param {Cipher} cipher The cipher to create a helper for.\n *\n * @return {Object} An object with encrypt and decrypt shortcut functions.\n *\n * @static\n *\n * @example\n *\n * const AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);\n */static _createHelper(SubCipher){const selectCipherStrategy=key=>{if(typeof key==='string'){return PasswordBasedCipher;}return SerializableCipher;};return {encrypt(message,key,cfg){return selectCipherStrategy(key).encrypt(SubCipher,message,key,cfg);},decrypt(ciphertext,key,cfg){return selectCipherStrategy(key).decrypt(SubCipher,ciphertext,key,cfg);}};}/**\n * Resets this cipher to its initial state.\n *\n * @example\n *\n * cipher.reset();\n */reset(){// Reset data buffer\nsuper.reset.call(this);// Perform concrete-cipher logic\nthis._doReset();}/**\n * Adds data to be encrypted or decrypted.\n *\n * @param {WordArray|string} dataUpdate The data to encrypt or decrypt.\n *\n * @return {WordArray} The data after processing.\n *\n * @example\n *\n * const encrypted = cipher.process('data');\n * const encrypted = cipher.process(wordArray);\n */process(dataUpdate){// Append\nthis._append(dataUpdate);// Process available blocks\nreturn this._process();}/**\n * Finalizes the encryption or decryption process.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n *\n * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt.\n *\n * @return {WordArray} The data after final processing.\n *\n * @example\n *\n * const encrypted = cipher.finalize();\n * const encrypted = cipher.finalize('data');\n * const encrypted = cipher.finalize(wordArray);\n */finalize(dataUpdate){// Final data update\nif(dataUpdate){this._append(dataUpdate);}// Perform concrete-cipher logic\nconst finalProcessedData=this._doFinalize();return finalProcessedData;}}Cipher._ENC_XFORM_MODE=1;Cipher._DEC_XFORM_MODE=2;Cipher.keySize=128/32;Cipher.ivSize=128/32;/**\n * Abstract base block cipher mode template.\n */class BlockCipherMode extends Base{/**\n * Initializes a newly created mode.\n *\n * @param {Cipher} cipher A block cipher instance.\n * @param {Array} iv The IV words.\n *\n * @example\n *\n * const mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);\n */constructor(cipher,iv){super();this._cipher=cipher;this._iv=iv;}/**\n * Creates this mode for encryption.\n *\n * @param {Cipher} cipher A block cipher instance.\n * @param {Array} iv The IV words.\n *\n * @static\n *\n * @example\n *\n * const mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);\n */static createEncryptor(cipher,iv){return this.Encryptor.create(cipher,iv);}/**\n * Creates this mode for decryption.\n *\n * @param {Cipher} cipher A block cipher instance.\n * @param {Array} iv The IV words.\n *\n * @static\n *\n * @example\n *\n * const mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);\n */static createDecryptor(cipher,iv){return this.Decryptor.create(cipher,iv);}}function xorBlock(words,offset,blockSize){const _words=words;let block;// Shortcut\nconst iv=this._iv;// Choose mixing block\nif(iv){block=iv;// Remove IV for subsequent blocks\nthis._iv=undefined;}else {block=this._prevBlock;}// XOR blocks\nfor(let i=0;i<blockSize;i+=1){_words[offset+i]^=block[i];}}/**\n * Cipher Block Chaining mode.\n *//**\n * Abstract base CBC mode.\n */class CBC extends BlockCipherMode{}/**\n * CBC encryptor.\n */CBC.Encryptor=class extends CBC{/**\n * Processes the data block at offset.\n *\n * @param {Array} words The data words to operate on.\n * @param {number} offset The offset where the block starts.\n *\n * @example\n *\n * mode.processBlock(data.words, offset);\n */processBlock(words,offset){// Shortcuts\nconst cipher=this._cipher;const{blockSize}=cipher;// XOR and encrypt\nxorBlock.call(this,words,offset,blockSize);cipher.encryptBlock(words,offset);// Remember this block to use with next block\nthis._prevBlock=words.slice(offset,offset+blockSize);}};/**\n * CBC decryptor.\n */CBC.Decryptor=class extends CBC{/**\n * Processes the data block at offset.\n *\n * @param {Array} words The data words to operate on.\n * @param {number} offset The offset where the block starts.\n *\n * @example\n *\n * mode.processBlock(data.words, offset);\n */processBlock(words,offset){// Shortcuts\nconst cipher=this._cipher;const{blockSize}=cipher;// Remember this block to use with next block\nconst thisBlock=words.slice(offset,offset+blockSize);// Decrypt and XOR\ncipher.decryptBlock(words,offset);xorBlock.call(this,words,offset,blockSize);// This block becomes the previous block\nthis._prevBlock=thisBlock;}};/**\n * PKCS #5/7 padding strategy.\n */const Pkcs7={/**\n * Pads data using the algorithm defined in PKCS #5/7.\n *\n * @param {WordArray} data The data to pad.\n * @param {number} blockSize The multiple that the data should be padded to.\n *\n * @static\n *\n * @example\n *\n * CryptoJS.pad.Pkcs7.pad(wordArray, 4);\n */pad(data,blockSize){// Shortcut\nconst blockSizeBytes=blockSize*4;// Count padding bytes\nconst nPaddingBytes=blockSizeBytes-data.sigBytes%blockSizeBytes;// Create padding word\nconst paddingWord=nPaddingBytes<<24|nPaddingBytes<<16|nPaddingBytes<<8|nPaddingBytes;// Create padding\nconst paddingWords=[];for(let i=0;i<nPaddingBytes;i+=4){paddingWords.push(paddingWord);}const padding=WordArray.create(paddingWords,nPaddingBytes);
1// Add padding\ndata.concat(padding);},/**\n * Unpads data that had been padded using the algorithm defined in PKCS #5/7.\n *\n * @param {WordArray} data The data to unpad.\n *\n * @static\n *\n * @example\n *\n * CryptoJS.pad.Pkcs7.unpad(wordArray);\n */unpad(data){const _data=data;// Get number of padding bytes from last byte\nconst nPaddingBytes=_data.words[_data.sigBytes-1>>>2]&0xff;// Remove padding\n_data.sigBytes-=nPaddingBytes;}};/**\n * Abstract base block cipher template.\n *\n * @property {number} blockSize\n *\n * The number of 32-bit words this cipher operates on. Default: 4 (128 bits)\n */class BlockCipher extends Cipher{constructor(xformMode,key,cfg){/**\n * Configuration options.\n *\n * @property {Mode} mode The block mode to use. Default: CBC\n * @property {Padding} padding The padding strategy to use. Default: Pkcs7\n */super(xformMode,key,ObjectAssign({mode:CBC,padding:Pkcs7},cfg));this.blockSize=128/32;}reset(){let modeCreator;// Reset cipher\nsuper.reset.call(this);// Shortcuts\nconst{cfg}=this;const{iv,mode}=cfg;// Reset block mode\nif(this._xformMode===this.constructor._ENC_XFORM_MODE){modeCreator=mode.createEncryptor;}else/* if (this._xformMode == this._DEC_XFORM_MODE) */{modeCreator=mode.createDecryptor;// Keep at least one block in the buffer for unpadding\nthis._minBufferSize=1;}this._mode=modeCreator.call(mode,this,iv&&iv.words);this._mode.__creator=modeCreator;}_doProcessBlock(words,offset){this._mode.processBlock(words,offset);}_doFinalize(){let finalProcessedBlocks;// Shortcut\nconst{padding}=this.cfg;// Finalize\nif(this._xformMode===this.constructor._ENC_XFORM_MODE){// Pad data\npadding.pad(this._data,this.blockSize);// Process final blocks\nfinalProcessedBlocks=this._process(true);}else/* if (this._xformMode == this._DEC_XFORM_MODE) */{// Process final blocks\nfinalProcessedBlocks=this._process(true);// Unpad data\npadding.unpad(finalProcessedBlocks);}return finalProcessedBlocks;}}/**\n * A collection of cipher parameters.\n *\n * @property {WordArray} ciphertext The raw ciphertext.\n * @property {WordArray} key The key to this ciphertext.\n * @property {WordArray} iv The IV used in the ciphering operation.\n * @property {WordArray} salt The salt used with a key derivation function.\n * @property {Cipher} algorithm The cipher algorithm.\n * @property {Mode} mode The block mode used in the ciphering operation.\n * @property {Padding} padding The padding scheme used in the ciphering operation.\n * @property {number} blockSize The block size of the cipher.\n * @property {Format} formatter\n * The default formatting strategy to convert this cipher params object to a string.\n */class CipherParams extends Base{/**\n * Initializes a newly created cipher params object.\n *\n * @param {Object} cipherParams An object with any of the possible cipher parameters.\n *\n * @example\n *\n * var cipherParams = CryptoJS.lib.CipherParams.create({\n * ciphertext: ciphertextWordArray,\n * key: keyWordArray,\n * iv: ivWordArray,\n * salt: saltWordArray,\n * algorithm: CryptoJS.algo.AES,\n * mode: CryptoJS.mode.CBC,\n * padding: CryptoJS.pad.PKCS7,\n * blockSize: 4,\n * formatter: CryptoJS.format.OpenSSL\n * });\n */constructor(cipherParams){super();this.mixIn(cipherParams);}/**\n * Converts this cipher params object to a string.\n *\n * @param {Format} formatter (Optional) The formatting strategy to use.\n *\n * @return {string} The stringified cipher params.\n *\n * @throws Error If neither the formatter nor the default formatter is set.\n *\n * @example\n *\n * var string = cipherParams + '';\n * var string = cipherParams.toString();\n * var string = cipherParams.toString(CryptoJS.format.OpenSSL);\n */toString(formatter){return (formatter||this.formatter).stringify(this);}}/**\n * OpenSSL formatting strategy.\n */const OpenSSLFormatter={/**\n * Converts a cipher params object to an OpenSSL-compatible string.\n *\n * @param {CipherParams} cipherParams The cipher params object.\n *\n * @return {string} The OpenSSL-compatible string.\n *\n * @static\n *\n * @example\n *\n * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);\n */stringify(cipherParams){let wordArray;// Shortcuts\nconst{ciphertext,salt}=cipherParams;// Format\nif(salt){wordArray=WordArray.create([0x53616c74,0x65645f5f]).concat(salt).concat(ciphertext);}else {wordArray=ciphertext;}return wordArray.toString(Base64);},/**\n * Converts an OpenSSL-compatible string to a cipher params object.\n *\n * @param {string} openSSLStr The OpenSSL-compatible string.\n *\n * @return {CipherParams} The cipher params object.\n *\n * @static\n *\n * @example\n *\n * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);\n */parse(openSSLStr){let salt;// Parse base64\nconst ciphertext=Base64.parse(openSSLStr);// Shortcut\nconst ciphertextWords=ciphertext.words;// Test for salt\nif(ciphertextWords[0]===0x53616c74&&ciphertextWords[1]===0x65645f5f){// Extract salt\nsalt=WordArray.create(ciphertextWords.slice(2,4));// Remove salt from ciphertext\nciphertextWords.splice(0,4);ciphertext.sigBytes-=16;}return CipherParams.create({ciphertext,salt});}};/**\n * A cipher wrapper that returns ciphertext as a serializable cipher params object.\n */class SerializableCipher extends Base{/**\n * Encrypts a message.\n *\n * @param {Cipher} cipher The cipher algorithm to use.\n * @param {WordArray|string} message The message to encrypt.\n * @param {WordArray} key The key.\n * @param {Object} cfg (Optional) The configuration options to use for this operation.\n *\n * @return {CipherParams} A cipher params object.\n *\n * @static\n *\n * @example\n *\n * var ciphertextParams = CryptoJS.lib.SerializableCipher\n * .encrypt(CryptoJS.algo.AES, message, key);\n * var ciphertextParams = CryptoJS.lib.SerializableCipher\n * .encrypt(CryptoJS.algo.AES, message, key, { iv: iv });\n * var ciphertextParams = CryptoJS.lib.SerializableCipher\n * .encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });\n */static encrypt(cipher,message,key,cfg){// Apply config defaults\nconst _cfg=ObjectAssign(new Base(),this.cfg,cfg);
1// Encrypt\nconst encryptor=cipher.createEncryptor(key,_cfg);const ciphertext=encryptor.finalize(message);// Shortcut\nconst cipherCfg=encryptor.cfg;// Create and return serializable cipher params\nreturn CipherParams.create({ciphertext,key,iv:cipherCfg.iv,algorithm:cipher,mode:cipherCfg.mode,padding:cipherCfg.padding,blockSize:encryptor.blockSize,formatter:_cfg.format});}/**\n * Decrypts serialized ciphertext.\n *\n * @param {Cipher} cipher The cipher algorithm to use.\n * @param {CipherParams|string} ciphertext The ciphertext to decrypt.\n * @param {WordArray} key The key.\n * @param {Object} cfg (Optional) The configuration options to use for this operation.\n *\n * @return {WordArray} The plaintext.\n *\n * @static\n *\n * @example\n *\n * var plaintext = CryptoJS.lib.SerializableCipher\n * .decrypt(CryptoJS.algo.AES, formattedCiphertext, key,\n * { iv: iv, format: CryptoJS.format.OpenSSL });\n * var plaintext = CryptoJS.lib.SerializableCipher\n * .decrypt(CryptoJS.algo.AES, ciphertextParams, key,\n * { iv: iv, format: CryptoJS.format.OpenSSL });\n */static decrypt(cipher,ciphertext,key,cfg){let _ciphertext=ciphertext;// Apply config defaults\nconst _cfg=ObjectAssign(new Base(),this.cfg,cfg);// Convert string to CipherParams\n_ciphertext=this._parse(_ciphertext,_cfg.format);// Decrypt\nconst plaintext=cipher.createDecryptor(key,_cfg).finalize(_ciphertext.ciphertext);return plaintext;}/**\n * Converts serialized ciphertext to CipherParams,\n * else assumed CipherParams already and returns ciphertext unchanged.\n *\n * @param {CipherParams|string} ciphertext The ciphertext.\n * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext.\n *\n * @return {CipherParams} The unserialized ciphertext.\n *\n * @static\n *\n * @example\n *\n * var ciphertextParams = CryptoJS.lib.SerializableCipher\n * ._parse(ciphertextStringOrParams, format);\n */static _parse(ciphertext,format){if(typeof ciphertext==='string'){return format.parse(ciphertext,this);}return ciphertext;}}/**\n * Configuration options.\n *\n * @property {Formatter} format\n *\n * The formatting strategy to convert cipher param objects to and from a string.\n * Default: OpenSSL\n */SerializableCipher.cfg=ObjectAssign(new Base(),{format:OpenSSLFormatter});/**\n * OpenSSL key derivation function.\n */const OpenSSLKdf={/**\n * Derives a key and IV from a password.\n *\n * @param {string} password The password to derive from.\n * @param {number} keySize The size in words of the key to generate.\n * @param {number} ivSize The size in words of the IV to generate.\n * @param {WordArray|string} salt\n * (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.\n *\n * @return {CipherParams} A cipher params object with the key, IV, and salt.\n *\n * @static\n *\n * @example\n *\n * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);\n * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');\n */execute(password,keySize,ivSize,salt,hasher){let _salt=salt;// Generate random salt\nif(!_salt){_salt=WordArray.random(64/8);}// Derive key and IV\nlet key;if(!hasher){key=EvpKDFAlgo.create({keySize:keySize+ivSize}).compute(password,_salt);}else {key=EvpKDFAlgo.create({keySize:keySize+ivSize,hasher}).compute(password,_salt);}// Separate key and IV\nconst iv=WordArray.create(key.words.slice(keySize),ivSize*4);key.sigBytes=keySize*4;// Return params\nreturn CipherParams.create({key,iv,salt:_salt});}};/**\n * A serializable cipher wrapper that derives the key from a password,\n * and returns ciphertext as a serializable cipher params object.\n */class PasswordBasedCipher extends SerializableCipher{/**\n * Encrypts a message using a password.\n *\n * @param {Cipher} cipher The cipher algorithm to use.\n * @param {WordArray|string} message The message to encrypt.\n * @param {string} password The password.\n * @param {Object} cfg (Optional) The configuration options to use for this operation.\n *\n * @return {CipherParams} A cipher params object.\n *\n * @static\n *\n * @example\n *\n * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher\n * .encrypt(CryptoJS.algo.AES, message, 'password');\n * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher\n * .encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });\n */static encrypt(cipher,message,password,cfg){// Apply config defaults\nconst _cfg=ObjectAssign(new Base(),this.cfg,cfg);// Derive key and other params\nconst derivedParams=_cfg.kdf.execute(password,cipher.keySize,cipher.ivSize,_cfg.salt,_cfg.hasher);// Add IV to config\n_cfg.iv=derivedParams.iv;// Encrypt\nconst ciphertext=SerializableCipher.encrypt.call(this,cipher,message,derivedParams.key,_cfg);// Mix in derived params\nciphertext.mixIn(derivedParams);return ciphertext;}/**\n * Decrypts serialized ciphertext using a password.\n *\n * @param {Cipher} cipher The cipher algorithm to use.\n * @param {CipherParams|string} ciphertext The ciphertext to decrypt.\n * @param {string} password The password.\n * @param {Object} cfg (Optional) The configuration options to use for this operation.\n *\n * @return {WordArray} The plaintext.\n *\n * @static\n *\n * @example\n *\n * var plaintext = CryptoJS.lib.PasswordBasedCipher\n * .decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password',\n * { format: CryptoJS.format.OpenSSL });\n * var plaintext = CryptoJS.lib.PasswordBasedCipher\n * .decrypt(CryptoJS.algo.AES, ciphertextParams, 'password',\n * { format: CryptoJS.format.OpenSSL });\n */static decrypt(cipher,ciphertext,password,cfg){let _ciphertext=ciphertext;// Apply config defaults\nconst _cfg=ObjectAssign(new Base(),this.cfg,cfg);// Convert string to CipherParams\n_ciphertext=this._parse(_ciphertext,_cfg.format);// Derive key and other params\nconst derivedParams=_cfg.kdf.execute(password,cipher.keySize,cipher.ivSize,_ciphertext.salt,_cfg.hasher);// Add IV to config\n_cfg.iv=derivedParams.iv;// Decrypt\nconst plaintext=SerializableCipher.decrypt.call(this,cipher,_ciphertext,derivedParams.key,_cfg);return plaintext;}}/**\n * Configuration options.\n *\n * @property {KDF} kdf\n * The key derivation function to use to generate a key and IV from a password.\n * Default: OpenSSL\n */PasswordBasedCipher.cfg=ObjectAssign(SerializableCipher.cfg,{kdf:OpenSSLKdf});\n\nconst _SBOX=[];const INV_SBOX=[];const _SUB_MIX_0=[];const _SUB_MIX_1=[];const _SUB_MIX_2=[];const _SUB_MIX_3=[];const INV_SUB_MIX_0=[];const INV_SUB_MIX_1=[];const INV_SUB_MIX_2=[];const INV_SUB_MIX_3=[];// Compute lookup tables\n// Compute double table\nconst d=[];for(let i=0;i<256;i+=1){if(i<128){d[i]=i<<1;}else {d[i]=i<<1^0x11b;}}// Walk GF(2^8)\nlet x=0;let xi=0;for(let i=0;i<256;i+=1){// Compute sbox\nlet sx=xi^xi<<1^xi<<2^xi<<3^xi<<4;sx=sx>>>8^sx&0xff^0x63;_SBOX[x]=sx;INV_SBOX[sx]=x;// Compute multiplication\nconst x2=d[x];const x4=d[x2];const x8=d[x4];// Compute sub bytes, mix columns tables\nlet t=d[sx]*0x101^sx*0x1010100;_SUB_MIX_0[x]=t<<24|t>>>8;_SUB_MIX_1[x]=t<<16|t>>>16;_SUB_MIX_2[x]=t<<8|t>>>24;_SUB_MIX_3[x]=t;// Compute inv sub bytes, inv mix columns tables\nt=x8*0x1010101^x4*0x10001^x2*0x101^x*0x1010100;INV_SUB_MIX_0[sx]=t<<24|t>>>8;INV_SUB_MIX_1[sx]=t<<16|t>>>16;INV_SUB_MIX_2[sx]=t<<8|t>>>24;INV_SUB_MIX_3[sx]=t;// Compute next counter\nif(!x){xi=1;x=xi;}else {x=x2^d[d[d[x8^x2]]];xi^=d[d[xi]];}}// Precomputed Rcon lookup\nconst RCON=[0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36];/**\n * AES block cipher algorithm.\n */class AESAlgo extends BlockCipher{_doReset(){let t;// Skip reset of nRounds has been set before and key did not change\nif(this._nRounds&&this._keyPriorReset===this._key){return;}// Shortcuts\nthis._keyPriorReset=this._key;const key=this._keyPriorReset;const keyWords=key.words;const keySize=key.sigBytes/4;
1// Compute number of rounds\nthis._nRounds=keySize+6;const nRounds=this._nRounds;// Compute number of key schedule rows\nconst ksRows=(nRounds+1)*4;// Compute key schedule\nthis._keySchedule=[];const keySchedule=this._keySchedule;for(let ksRow=0;ksRow<ksRows;ksRow+=1){if(ksRow<keySize){keySchedule[ksRow]=keyWords[ksRow];}else {t=keySchedule[ksRow-1];if(!(ksRow%keySize)){// Rot word\nt=t<<8|t>>>24;// Sub word\nt=_SBOX[t>>>24]<<24|_SBOX[t>>>16&0xff]<<16|_SBOX[t>>>8&0xff]<<8|_SBOX[t&0xff];// Mix Rcon\nt^=RCON[ksRow/keySize|0]<<24;}else if(keySize>6&&ksRow%keySize===4){// Sub word\nt=_SBOX[t>>>24]<<24|_SBOX[t>>>16&0xff]<<16|_SBOX[t>>>8&0xff]<<8|_SBOX[t&0xff];}keySchedule[ksRow]=keySchedule[ksRow-keySize]^t;}}// Compute inv key schedule\nthis._invKeySchedule=[];const invKeySchedule=this._invKeySchedule;for(let invKsRow=0;invKsRow<ksRows;invKsRow+=1){const ksRow=ksRows-invKsRow;if(invKsRow%4){t=keySchedule[ksRow];}else {t=keySchedule[ksRow-4];}if(invKsRow<4||ksRow<=4){invKeySchedule[invKsRow]=t;}else {invKeySchedule[invKsRow]=INV_SUB_MIX_0[_SBOX[t>>>24]]^INV_SUB_MIX_1[_SBOX[t>>>16&0xff]]^INV_SUB_MIX_2[_SBOX[t>>>8&0xff]]^INV_SUB_MIX_3[_SBOX[t&0xff]];}}}encryptBlock(M,offset){this._doCryptBlock(M,offset,this._keySchedule,_SUB_MIX_0,_SUB_MIX_1,_SUB_MIX_2,_SUB_MIX_3,_SBOX);}decryptBlock(M,offset){const _M=M;// Swap 2nd and 4th rows\nlet t=_M[offset+1];_M[offset+1]=_M[offset+3];_M[offset+3]=t;this._doCryptBlock(_M,offset,this._invKeySchedule,INV_SUB_MIX_0,INV_SUB_MIX_1,INV_SUB_MIX_2,INV_SUB_MIX_3,INV_SBOX);// Inv swap 2nd and 4th rows\nt=_M[offset+1];_M[offset+1]=_M[offset+3];_M[offset+3]=t;}_doCryptBlock(M,offset,keySchedule,SUB_MIX_0,SUB_MIX_1,SUB_MIX_2,SUB_MIX_3,SBOX){const _M=M;// Shortcut\nconst nRounds=this._nRounds;// Get input, add round key\nlet s0=_M[offset]^keySchedule[0];let s1=_M[offset+1]^keySchedule[1];let s2=_M[offset+2]^keySchedule[2];let s3=_M[offset+3]^keySchedule[3];// Key schedule row counter\nlet ksRow=4;// Rounds\nfor(let round=1;round<nRounds;round+=1){// Shift rows, sub bytes, mix columns, add round key\nconst t0=SUB_MIX_0[s0>>>24]^SUB_MIX_1[s1>>>16&0xff]^SUB_MIX_2[s2>>>8&0xff]^SUB_MIX_3[s3&0xff]^keySchedule[ksRow];ksRow+=1;const t1=SUB_MIX_0[s1>>>24]^SUB_MIX_1[s2>>>16&0xff]^SUB_MIX_2[s3>>>8&0xff]^SUB_MIX_3[s0&0xff]^keySchedule[ksRow];ksRow+=1;const t2=SUB_MIX_0[s2>>>24]^SUB_MIX_1[s3>>>16&0xff]^SUB_MIX_2[s0>>>8&0xff]^SUB_MIX_3[s1&0xff]^keySchedule[ksRow];ksRow+=1;const t3=SUB_MIX_0[s3>>>24]^SUB_MIX_1[s0>>>16&0xff]^SUB_MIX_2[s1>>>8&0xff]^SUB_MIX_3[s2&0xff]^keySchedule[ksRow];ksRow+=1;// Update state\ns0=t0;s1=t1;s2=t2;s3=t3;}// Shift rows, sub bytes, add round key\nconst t0=(SBOX[s0>>>24]<<24|SBOX[s1>>>16&0xff]<<16|SBOX[s2>>>8&0xff]<<8|SBOX[s3&0xff])^keySchedule[ksRow];ksRow+=1;const t1=(SBOX[s1>>>24]<<24|SBOX[s2>>>16&0xff]<<16|SBOX[s3>>>
18&0xff]<<8|SBOX[s0&0xff])^keySchedule[ksRow];ksRow+=1;const t2=(SBOX[s2>>>24]<<24|SBOX[s3>>>16&0xff]<<16|SBOX[s0>>>8&0xff]<<8|SBOX[s1&0xff])^keySchedule[ksRow];ksRow+=1;const t3=(SBOX[s3>>>24]<<24|SBOX[s0>>>16&0xff]<<16|SBOX[s1>>>8&0xff]<<8|SBOX[s2&0xff])^keySchedule[ksRow];ksRow+=1;// Set output\n_M[offset]=t0;_M[offset+1]=t1;_M[offset+2]=t2;_M[offset+3]=t3;}}AESAlgo.keySize=256/32;/**\n * Shortcut functions to the cipher's object interface.\n *\n * @example\n *\n * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg);\n * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg);\n */const AES=BlockCipher._createHelper(AESAlgo);\n\nconst ENCRYPTION_PREFIX_V1='RudderEncrypt:';const ENCRYPTION_KEY_V1='Rudder';\n\nconst encrypt=value=>`${ENCRYPTION_PREFIX_V1}${AES.encrypt(value,ENCRYPTION_KEY_V1).toString()}`;const decrypt=value=>{if(value.startsWith(ENCRYPTION_PREFIX_V1)){return AES.decrypt(value.substring(ENCRYPTION_PREFIX_V1.length),ENCRYPTION_KEY_V1).toString(Utf8);}return value;};\n\nconst pluginName$2='StorageEncryptionLegacy';const StorageEncryptionLegacy=()=>({name:pluginName$2,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$2];},storage:{encrypt(value){return encrypt(value);},decrypt(value){return decrypt(value);}}});\n\nconst STORAGE_MIGRATION_ERROR=key=>`Failed to retrieve or parse data for \"${key}\" from storage.`;\n\nconst STORAGE_MIGRATOR_PLUGIN='StorageMigratorPlugin';\n\nconst pluginName$1='StorageMigrator';const StorageMigrator=()=>({name:pluginName$1,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$1];},storage:{migrate(key,storageEngine,errorHandler,logger){try{const storedVal=storageEngine.getItem(key);if(isNullOrUndefined(storedVal)){return null;}let currentVal=storedVal;let decryptedVal=decrypt(currentVal);// Decrypt using the latest encryption method as well\ndecryptedVal=decryptBrowser(decryptedVal);// storejs that is used in localstorage engine already deserializes json strings but swallows errors\ncurrentVal=JSON.parse(decryptedVal);// Recursively decrypt the value until we reach a point where the value\n// is not encrypted anymore\nwhile(isString(currentVal)){decryptedVal=decrypt(currentVal);// Decrypt using the latest encryption method as well\ndecryptedVal=decryptBrowser(decryptedVal);// If the decrypted value is the same as the current value,\n// then it's not encrypted anymore\nif(decryptedVal===currentVal){break;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors\ncurrentVal=JSON.parse(decryptedVal);}return currentVal;}catch(err){const customMessage=STORAGE_MIGRATION_ERROR(key);errorHandler?.onError({error:err,context:STORAGE_MIGRATOR_PLUGIN,customMessage,groupingHash:customMessage});return null;}}}});\n\nconst DEFAULT_RETRY_QUEUE_OPTIONS={maxRetryDelay:360000,minRetryDelay:1000,backoffFactor:2,maxAttempts:10,maxItems:100};const REQUEST_TIMEOUT_MS=30*1000;// 30 seconds\nconst DATA_PLANE_API_VERSION='v1';const QUEUE_NAME='rudder';const XHR_QUEUE_PLUGIN='XhrQueuePlugin';\n\nconst EVENT_DELIVERY_FAILURE_ERROR_PREFIX=(context,originalErrorMsg)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to deliver event(s). Cause: ${originalErrorMsg}.`;\n\nconst getBatchDeliveryPayload=(events,currentTime,logger)=>{const batchPayload={batch:events,sentAt:currentTime};return stringifyWithoutCircular(batchPayload,true,undefined,logger);};const getNormalizedQueueOptions=queueOpts=>mergeDeepRight(DEFAULT_RETRY_QUEUE_OPTIONS,queueOpts);const getDeliveryUrl=(dataplaneUrl,endpoint)=>{const dpUrl=new URL(dataplaneUrl);return new URL(removeDuplicateSlashes([dpUrl.pathname,'/',DATA_PLANE_API_VERSION,'/',endpoint].join('')),dpUrl).href;};const getBatchDeliveryUrl=dataplaneUrl=>getDeliveryUrl(dataplaneUrl,'batch');const logMessageOnFailure=(details,isRetryable,qItemProcessInfo,logger)=>{if(!logger){return;}let logMsg=EVENT_DELIVERY_FAILURE_ERROR_PREFIX(XHR_QUEUE_PLUGIN,details?.error?.message??'Unknown');const dropMsg=`The event(s) will be dropped.`;if(isRetryable){if(qItemProcessInfo.willBeRetried){logMsg=`${logMsg} The event(s) will be retried.`;if(qItemProcessInfo.retryAttemptNumber>0){logMsg=`${logMsg} Retry attempt ${qItemProcessInfo.retryAttemptNumber} of ${qItemProcessInfo.maxRetryAttempts}.`;}// Use warning for retryable failures that will be retried\nlogger.warn(logMsg);}else {logger.error(`${logMsg} Retries exhausted (${qItemProcessInfo.maxRetryAttempts}). ${dropMsg}`);}}else {// Use error for non-retryable failures\nlogger.error(`${logMsg} ${dropMsg}`);}};const getRequestInfo=(itemData,state,qItemProcessInfo,logger)=>{let data;let headers;let url;const currentTime=getCurrentTimeFormatted();if(Array.isArray(itemData)){const finalEvents=itemData.map(queueItemData=>getFinalEventForDeliveryMutator(queueItemData.event,currentTime));data=getBatchDeliveryPayload(finalEvents,currentTime,logger);headers=itemData[0]?clone(itemData[0].headers):{};url=getBatchDeliveryUrl(state.lifecycle.activeDataplaneUrl.value);}else {const{url:eventUrl,event,headers:eventHeaders}=itemData;const finalEvent=getFinalEventForDeliveryMutator(event,currentTime);data=getDeliveryPayload(finalEvent,logger);headers=clone(eventHeaders);url=eventUrl;}// Add current timestamp as sentAt header\n// The same value is added in the event payload as well\nheaders.SentAt=currentTime;// Add a header to indicate if the item has been reclaimed from\n// local storage\nif(qItemProcessInfo.reclaimed){headers['Rsa-Recovered']='true';}// Add retry headers if the item is being retried for delivery\nif(qItemProcessInfo.retryAttemptNumber>0){// The number of times this item has been attempted to retry\nheaders['Rsa-Retry-Attempt']=qItemProcessInfo.retryAttemptNumber.toString();// The number of milliseconds since the last attempt\nheaders['Rsa-Since-Last-Attempt']=qItemProcessInfo.timeSinceLastAttempt.toString();// The number of milliseconds since the first attempt\nheaders['Rsa-Since-First-Attempt']=qItemProcessInfo.timeSinceFirstAttempt.toString();// The reason for the retry\nheaders['Rsa-Retry-Reason']=qItemProcessInfo.retryReason;}return {data,headers,url};};\n\nconst pluginName='XhrQueue';const XhrQueue=()=>({name:pluginName,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName];},dataplaneEventsQueue:{/**\n * Initialize the queue for delivery\n * @param state Application state\n * @param httpClient http client instance\n * @param storeManager Store Manager instance\n * @param errorHandler Error handler instance\n * @param logger Logger instance\n * @returns RetryQueue instance\n */init(state,httpClient,storeManager,errorHandler,logger){const writeKey=state.lifecycle.writeKey.value;httpClient.setAuthHeader(writeKey);const finalQOpts=getNormalizedQueueOptions(state.loadOptions.value.queueOptions);const eventsQueue=new RetryQueue(// adding write key to the queue name to avoid conflicts\n`${QUEUE_NAME}_${writeKey}`,finalQOpts,(itemData,done,qItemProcessInfo)=>{const{data,url,headers}=getRequestInfo(itemData,state,qItemProcessInfo,logger);httpClient.getAsyncData({url,options:{method:'POST',headers,data:data,sendRawData:true},isRawResponse:true,timeout:REQUEST_TIMEOUT_MS,callback:(result,details)=>{// If there is no error, we can consider the item as delivered\nif(isUndefined(details?.error)){// null means item will not be processed further and will be removed from the queue (even from the storage)\ndone(null);return;}const isRetryable=isErrRetryable(details?.xhr?.status??0);logMessageOnFailure(details,isRetryable,qItemProcessInfo,logger);if(isRetryable){let retryReason=DEFAULT_RETRY_REASON;if(details?.timedOut){retryReason=RETRY_REASON_CLIENT_TIMEOUT;}else if(isDefined(details?.xhr?.status)){retryReason=`server-${details.xhr.status}`;}done(details,{retryReason});}else {// null means item will not be processed further and will be removed from the queue (even from the storage)\ndone(null);}}});},storeManager,getStorageTypeForEventsPersistence(logger),logger,itemData=>{const currentTime=getCurrentTimeFormatted();const events=itemData.map(queueItemData=>queueItemData.event);// type casting to string as we know that the event has already been validated prior to enqueue\nreturn getBatchDeliveryPayload(events,currentTime,logger)?.length;});return eventsQueue;},/**\n * Add event to the queue for delivery\n * @param state Application state\n * @param eventsQueue RetryQueue instance\n * @param event RudderEvent object\n * @param errorHandler Error handler instance\n * @param logger Logger instance\n * @returns none\n */enqueue(state,eventsQueue,event,errorHandler,logger){// sentAt is only added here for the validation step\n// It'll be updated to the latest timestamp during actual delivery\nevent.sentAt=getCurrentTimeFormatted();validateEventPayloadSize(event,logger);const dataplaneUrl=state.lifecycle.activeDataplaneUrl.value;const url=getDeliveryUrl(dataplaneUrl,event.type);// Other default headers are added by the HttpClient\n// Auth header is added during initialization\nconst headers={// To maintain event ordering while using the HTTP API as per is documentation,\n// make sure to include anonymousId as a header\nAnonymousId:toBase64(event.anonymousId)};eventsQueue.addItem({url,headers,event});}}});\n\n/**\n * Map plugin names to direct code imports from plugins package\n */const getBundledBuildPluginImports=()=>({BeaconQueue,CustomConsentManager,DeviceModeDestinations,DeviceModeTransformation,ExternalAnonymousId,GoogleLinker,IubendaConsentManager,KetchConsentManager,NativeDestinationQueue,OneTrustConsentManager,StorageEncryption,StorageEncryptionLegacy,StorageMigrator,XhrQueue});\n\n/**\n * Map of mandatory plugin names and direct imports\n */const getMandatoryPluginsMap=()=>({});/**\n * Map of optional plugin names and direct imports for legacy builds\n */const getOptionalPluginsMap=()=>{return getBundledBuildPluginImports();};/**\n * Map of optional plugin names and dynamic imports for modern builds\n */const getRemotePluginsMap=activePluginNames=>{{return {};}};const pluginsInventory={...getMandatoryPluginsMap(),...getOptionalPluginsMap()};const remotePluginsInventory=activePluginNames=>({...getRemotePluginsMap()});\n\n// TODO: add retry mechanism for getting remote plugins\n// TODO: add timeout error mechanism for marking remote plugins that failed to load as failed in state\nclass PluginsManager{constructor(engine,errorHandler,logger){this.engine=engine;this.errorHandler=errorHandler;this.logger=logger;this.onError=this.onError.bind(this);}/**\n * Orchestrate the plugin loading and registering\n */init(){state.lifecycle.status.value='pluginsLoading';// Expose pluginsCDNPath to global object, so it can be used in the promise that determines\nthis.setActivePlugins();this.registerLocalPlugins();this.registerRemotePlugins();this.attachEffects();}/**\n * Update state based on plugin loaded status\n */// eslint-disable-next-line class-methods-use-this\nattachEffects(){j(()=>{const isAllPluginsReady=state.plugins.activePlugins.value.length===0||state.plugins.loadedPlugins.value.length+state.plugins.failedPlugins.value.length===state.plugins.totalPluginsToLoad.value;if(isAllPluginsReady){n(()=>{state.plugins.ready.value=true;// TODO: decide what to do if a plugin fails to load for any reason.\n// Should we stop here or should we progress?\nstate.lifecycle.status.value='pluginsReady';});}});}/**\n * Determine the list of plugins that should be loaded based on sourceConfig & load options\n */// eslint-disable-next-line class-methods-use-this\ngetPluginsToLoadBasedOnConfig(){// This contains the default plugins if load option has been omitted by user\nlet pluginsToLoadFromConfig=state.plugins.pluginsToLoadFromConfig.value;if(!pluginsToLoadFromConfig){return [];}// Filter deprecated plugins\npluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>{if(deprecatedPluginsList.includes(pluginName)){this.logger.warn(DEPRECATED_PLUGIN_WARNING(PLUGINS_MANAGER,pluginName));return false;}return true;});const pluginGroupsToProcess=[{configurationStatus:()=>isDefined(state.dataPlaneEvents.eventsQueuePluginName.value),configurationStatusStr:'Data plane events delivery is enabled',activePluginName:state.dataPlaneEvents.eventsQueuePluginName.value,supportedPlugins:Object.values(DataPlaneEventsTransportToPluginNameMap),shouldAddMissingPlugins:true},{configurationStatus:()=>getNonCloudDestinations(state.nativeDestinations.configuredDestinations.value).length>0,configurationStatusStr:'Device mode destinations are connected to the source',supportedPlugins:['DeviceModeDestinations','NativeDestinationQueue']},{configurationStatus:()=>getNonCloudDestinations(state.nativeDestinations.configuredDestinations.value).some(destination=>destination.shouldApplyDeviceModeTransformation),configurationStatusStr:'Device mode transformations are enabled for at least one destination',supp
1ortedPlugins:['DeviceModeTransformation']},{configurationStatus:()=>isDefined(state.consents.activeConsentManagerPluginName.value),configurationStatusStr:'Consent management is enabled',activePluginName:state.consents.activeConsentManagerPluginName.value,supportedPlugins:Object.values(ConsentManagersToPluginNameMap)},{configurationStatus:()=>isDefined(state.storage.encryptionPluginName.value),configurationStatusStr:'Storage encryption is enabled',activePluginName:state.storage.encryptionPluginName.value,supportedPlugins:Object.values(StorageEncryptionVersionsToPluginNameMap)},{configurationStatus:()=>state.storage.migrate.value,configurationStatusStr:'Storage migration is enabled',supportedPlugins:['StorageMigrator']}];const addMissingPlugins=false;pluginGroupsToProcess.forEach(group=>{if(group.configurationStatus()){pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(group.activePluginName?pluginName=>!(pluginName!==group.activePluginName&&group.supportedPlugins.includes(pluginName)):pluginName=>isDefined(pluginName)// pass through\n);this.addMissingPlugins(group,addMissingPlugins,pluginsToLoadFromConfig);}else {pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(group.basePlugins!==undefined?pluginName=>!(group.basePlugins.includes(pluginName)||group.supportedPlugins.includes(pluginName)):pluginName=>!group.supportedPlugins.includes(pluginName));}});return [...Object.keys(getMandatoryPluginsMap()),...pluginsToLoadFromConfig];}addMissingPlugins(group,addMissingPlugins,pluginsToLoadFromConfig){const shouldAddMissingPlugins=group.shouldAddMissingPlugins||addMissingPlugins;let pluginsToConfigure;if(group.activePluginName){pluginsToConfigure=[...(group.basePlugins||[]),group.activePluginName];}else {pluginsToConfigure=[...group.supportedPlugins];}const missingPlugins=pluginsToConfigure.filter(pluginName=>!pluginsToLoadFromConfig.includes(pluginName));if(missingPlugins.length>0){if(shouldAddMissingPlugins){pluginsToLoadFromConfig.push(...missingPlugins);}this.logger.warn(generateMisconfiguredPluginsWarning(PLUGINS_MANAGER,group.configurationStatusStr,missingPlugins,shouldAddMissingPlugins));}}/**\n * Determine the list of plugins that should be activated\n */setActivePlugins(){const pluginsToLoad=this.getPluginsToLoadBasedOnConfig();// Merging available mandatory and optional plugin name list\nconst availablePlugins=[...Object.keys(pluginsInventory),...pluginNamesList];const activePlugins=[];const failedPlugins=[];pluginsToLoad.forEach(pluginName=>{if(availablePlugins.includes(pluginName)){activePlugins.push(pluginName);}else {failedPlugins.push(pluginName);}});if(failedPlugins.length>0){this.logger.warn(UNKNOWN_PLUGINS_WARNING(PLUGINS_MANAGER,failedPlugins));}n(()=>{state.plugins.totalPluginsToLoad.value=pluginsToLoad.length;state.plugins.activePlugins.value=activePlugins;state.plugins.failedPlugins.value=failedPlugins;});}/**\n * Register plugins that are direct imports to PluginEngine\n */registerLocalPlugins(){const unavailablePlugins=[];Object.entries(pluginsInventory).forEach(([pluginName,localPlugin])=>{if(state.plugins.activePlugins.value.includes(pluginName)){if(isFunction(localPlugin)){this.register([localPlugin()]);}else {unavailablePlugins.push(pluginName);}}});if(unavailablePlugins.length>0){state.plugins.failedPlugins.value=[...state.plugins.failedPlugins.value,...unavailablePlugins];this.logger.error(UNAVAILABLE_PLUGINS_ERROR(PLUGINS_MANAGER,unavailablePlugins));}}/**\n * Register plugins that are dynamic imports to PluginEngine\n */registerRemotePlugins(){const remotePluginsList=remotePluginsInventory(state.plugins.activePlugins.value);Promise.all(Object.keys(remotePluginsList).map(async remotePluginKey=>{await remotePluginsList[remotePluginKey]().then(remotePluginModule=>this.register([remotePluginModule.default()])).catch(err=>{// TODO: add retry here if dynamic import fails\nstate.plugins.failedPlugins.value=[...state.plugins.failedPlugins.value,remotePluginKey];this.onError(err,`Failed to load plugin \"${remotePluginKey}\"`,err);});})).catch(err=>{this.onError(err);});}/**\n * Extension point invoke that allows multiple plugins to be registered to it with error handling\n */invokeMultiple(extPoint,...args){try{return this.engine.invokeMultiple(extPoint,...args);}catch(e){this.onError(e,extPoint);return [];}}
1/**\n * Extension point invoke that allows a single plugin to be registered to it with error handling\n */invokeSingle(extPoint,...args){try{return this.engine.invokeSingle(extPoint,...args);}catch(e){this.onError(e,extPoint);return null;}}/**\n * Plugin engine register with error handling\n */register(plugins){plugins.forEach(plugin=>{try{this.engine.register(plugin,state);}catch(e){state.plugins.failedPlugins.value=[...state.plugins.failedPlugins.value,plugin.name];this.onError(e,`Failed to register plugin \"${plugin.name}\"`);}});}// TODO: Implement reset API instead\nunregisterLocalPlugins(){Object.keys(pluginsInventory).forEach(pluginKey=>{try{this.engine.unregister(pluginKey);}catch(e){this.onError(e,`Failed to unregister plugin \"${pluginKey}\"`);}});}/**\n * Handle errors\n */onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:PLUGINS_MANAGER,customMessage,groupingHash});}}\n\nconst STORAGE_TEST_TOP_LEVEL_DOMAIN='__tld__';const CLIENT_DATA_STORE_COOKIE='clientDataInCookie';const CLIENT_DATA_STORE_LS='clientDataInLocalStorage';const CLIENT_DATA_STORE_MEMORY='clientDataInMemory';const CLIENT_DATA_STORE_SESSION='clientDataInSessionStorage';const USER_SESSION_KEYS=['userId','userTraits','anonymousId','groupId','groupTraits','initialReferrer','initialReferringDomain','sessionInfo','authToken'];\n\nconst storageClientDataStoreNameMap={[COOKIE_STORAGE]:CLIENT_DATA_STORE_COOKIE,[LOCAL_STORAGE]:CLIENT_DATA_STORE_LS,[MEMORY_STORAGE]:CLIENT_DATA_STORE_MEMORY,[SESSION_STORAGE]:CLIENT_DATA_STORE_SESSION};\n\nconst legacyGetHostname=href=>{const l=document.createElement('a');l.href=href;return l.hostname;};/**\n * Levels returns all levels of the given url\n *\n * The method returns an empty array when the hostname is an ip.\n */const levelsFunc=url=>{// This is called before the polyfills load thus new URL cannot be used\nconst host=typeof globalThis.URL!=='function'?legacyGetHostname(url):new URL(url).hostname;const parts=host?.split('.')??[];const last=parts[parts.length-1];const levels=[];// Ip address.\nif(parts.length===4&&last&&last===parseInt(last,10).toString()){return levels;}// Localhost.\nif(parts.length<=1){// Fix to support localhost\nif(parts[0]&&parts[0].indexOf('localhost')!==-1){return ['localhost'];}return levels;}// Create levels.\nfor(let i=parts.length-2;i>=0;i-=1){levels.push(parts.slice(i).join('.'));}return levels;};/**\n * Get the top domain.\n *\n * The function constructs the levels of domain and attempts to set a global\n * cookie on each one when it succeeds it returns the top level domain.\n *\n * The method returns an empty string when the hostname is an ip.\n */const domain=url=>{const levels=levelsFunc(url);// Lookup the real top level one.\n// eslint-disable-next-line unicorn/no-for-loop\nfor(let i=0;i<levels.length;i+=1){const domain=levels[i];const cname=STORAGE_TEST_TOP_LEVEL_DOMAIN;const opts={domain:`${domain.indexOf('localhost')!==-1?'':'.'}${domain}`};try{// Set cookie on domain\ncookie(cname,1,opts);
1// If successful\nif(cookie(cname)){// Remove cookie from domain\ncookie(cname,null,opts);return domain;}}catch{// Silently continue to next domain level if cookie access is restricted or setting fails\n// Best-effort cleanup to avoid leaking the test cookie\ntry{cookie(cname,null,opts);}catch{// Ignore if we are unable to delete the cookie\n}}}return '';};\n\nconst getDefaultCookieOptions=()=>{const topDomain=`.${domain(globalThis.location.href)}`;return {maxage:DEFAULT_COOKIE_MAX_AGE_MS,path:'/',domain:!topDomain||topDomain==='.'?undefined:topDomain,samesite:'Lax',enabled:true};};const getDefaultLocalStorageOptions=()=>({enabled:true});const getDefaultSessionStorageOptions=()=>({enabled:true});const getDefaultInMemoryStorageOptions=()=>({enabled:true});\n\n/**\n * A storage utility to retain values in memory via Storage interface\n */class InMemoryStorage{isEnabled=true;length=0;data={};constructor(logger){this.options=getDefaultInMemoryStorageOptions();this.logger=logger;}configure(options){this.options=mergeDeepRight(this.options,options??{});this.isEnabled=Boolean(this.options.enabled);return this.options;}setItem(key,value){this.data[key]=value;this.length=Object.keys(this.data).length;return value;}getItem(key){if(key in this.data){return this.data[key];}return null;}removeItem(key){if(key in this.data){delete this.data[key];}this.length=Object.keys(this.data).length;return null;}clear(){this.data={};this.length=0;}key(index){const curKeys=this.keys();return curKeys[index]??null;}keys(){return Object.keys(this.data);}}const defaultInMemoryStorage=new InMemoryStorage(defaultLogger);\n\nfunction getDefaultExportFromCjs (x) {\n\treturn x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;\n}\n\nvar store$2 = {exports: {}};\n\nvar store$1=store$2.exports;var hasRequiredStore;function requireStore(){if(hasRequiredStore)return store$2.exports;hasRequiredStore=1;(function(module,exports){(function(global,factory){module.exports=factory();})(store$1,function(){function isJSON(obj){obj=JSON.stringify(obj);if(!/^\\{[\\s\\S]*\\}$/.test(obj)){return false;}return true;}function stringify(val){return val===undefined||typeof val===\"function\"?val+'':JSON.stringify(val);}function deserialize(value){if(typeof value!=='string'){return undefined;}try{return JSON.parse(value);}catch(e){return value;}}function isFunction(value){return {}.toString.call(value)===\"[object Function]\";}function isArray(value){return Object.prototype.toString.call(value)===\"[object Array]\";}// https://github.com/jaywcjlove/store.js/pull/8\n// Error: QuotaExceededError\nfunction dealIncognito(storage){var _KEY='_Is_Incognit',_VALUE='yes';try{// NOTE: set default storage when not passed in\nif(!storage){storage=window.localStorage;}storage.setItem(_KEY,_VALUE);storage.removeItem(_KEY);}catch(e){var inMemoryStorage={};inMemoryStorage._data={};inMemoryStorage.setItem=function(id,val){return inMemoryStorage._data[id]=String(val);};inMemoryStorage.getItem=function(id){return inMemoryStorage._data.hasOwnProperty(id)?inMemoryStorage._data[id]:undefined;};inMemoryStorage.removeItem=function(id){return delete inMemoryStorage._data[id];};inMemoryStorage.clear=function(){return inMemoryStorage._data={};};storage=inMemoryStorage;}finally{if(storage.getItem(_KEY)===_VALUE)storage.removeItem(_KEY);}return storage;}// deal QuotaExceededError if user use incognito mode in browser\nvar storage=dealIncognito();function Store(){if(!(this instanceof Store)){return new Store();}}Store.prototype={set:function set(key,val){if(key&&!isJSON(key)){storage.setItem(key,stringify(val));}else if(isJSON(key)){for(var a in key)this.set(a,key[a]);}return this;},get:function get(key){// Return all entries if no key\nif(key===undefined){var ret={};this.forEach(function(key,val){return ret[key]=val;});return ret;}if(key.charAt(0)==='?'){return this.has(key.substr(1));}var args=arguments;if(args.length>1){var dt={};for(var i=0,len=args.length;i<len;i++){var value=deserialize(storage.getItem(args[i]));if(this.has(args[i])){dt[args[i]]=value;}}return dt;}return deserialize(storage.getItem(key));},clear:function clear(){storage.clear();return this;},remove:function remove(key){var val=this.get(key);storage.removeItem(key);return val;},has:function has(key){return {}.hasOwnProperty.call(this.get(),key);},keys:function keys(){var d=[];this.forEach(function(k){d.push(k);});return d;},forEach:function forEach(callback){for(var i=0,len=storage.length;i<len;i++){var key=storage.key(i);callback(key,this.get(key));}return this;},search:function search(str){var arr=this.keys(),dt={};for(var i=0,len=arr.length;i<len;i++){if(arr[i].indexOf(str)>-1)dt[arr[i]]=this.get(arr[i]);}return dt;},len:function len(){return storage.length;}};var _Store=null;function store(key,data){var argm=arguments;var dt=null;if(!_Store)_Store=Store();if(argm.length===0)return _Store.get();if(argm.length===1){if(typeof key===\"string\")return _Store.get(key);if(isJSON(key))return _Store.set(key);}if(argm.length===2&&typeof key===\"string\"){if(!data)return _Store.remove(key);if(data&&typeof data===\"string\")return _Store.set(key,data);if(data&&isFunction(data)){dt=null;dt=data(key,_Store.get(key));store.set(key,dt);}}if(argm.length===2&&isArray(key)&&isFunction(data)){for(var i=0,len=key.length;i<len;
1i++){dt=data(key[i],_Store.get(key[i]));store.set(key[i],dt);}}return store;}for(var a in Store.prototype)store[a]=Store.prototype[a];return store;});})(store$2);return store$2.exports;}\n\nvar storeExports = requireStore();\nconst store = /*@__PURE__*/getDefaultExportFromCjs(storeExports);\n\n// check if the get, set overloads and search methods are used at all\n// if we do, ensure we provide types to support overloads as per storejs docs\n// https://www.npmjs.com/package/storejs\n/**\n * A storage utility to persist values in localstorage via Storage interface\n */class LocalStorage{isSupportAvailable=true;isEnabled=true;length=0;constructor(logger){this.options=getDefaultLocalStorageOptions();this.logger=logger;}configure(options){this.options=mergeDeepRight(this.options,options??{});this.isSupportAvailable=isStorageAvailable(LOCAL_STORAGE);this.isEnabled=Boolean(this.options.enabled&&this.isSupportAvailable);return this.options;}setItem(key,value){store.set(key,value);this.length=store.len();}// eslint-disable-next-line class-methods-use-this\ngetItem(key){const value=store.get(key);return isUndefined(value)?null:value;}removeItem(key){store.remove(key);this.length=store.len();}clear(){store.clear();this.length=0;}key(index){const curKeys=this.keys();return curKeys[index]??null;}// eslint-disable-next-line class-methods-use-this\nkeys(){return store.keys();}}const defaultLocalStorage=new LocalStorage(defaultLogger);\n\n/**\n * A storage utility to persist values in SessionStorage via Storage interface\n */class SessionStorage{isSupportAvailable=true;isEnabled=true;length=0;constructor(logger){this.options=getDefaultSessionStorageOptions();this.logger=logger;}configure(options){this.options=mergeDeepRight(this.options,options??{});this.isSupportAvailable=isStorageAvailable(SESSION_STORAGE);// when storage is blocked by the user, even accessing the property throws an error\nif(this.isSupportAvailable){this.store=globalThis.sessionStorage;}this.isEnabled=Boolean(this.options.enabled&&this.isSupportAvailable);return this.options;}setItem(key,value){if(!this.store){return;}this.store.setItem(key,value);this.length=this.store.length;}getItem(key){if(!this.store){return null;}const value=this.store.getItem(key);return isUndefined(value)?null:value;}removeItem(key){if(!this.store){return;}this.store.removeItem(key);this.length=this.store.length;}clear(){this.store?.clear();this.length=0;}key(index){return this.store?.key(index)??null;}keys(){const keys=[];if(!this.store){return keys;}for(let i=0;i<this.store.length;i+=1){const key=this.store.key(i);if(key!==null){keys.push(key);}}return keys;}}const defaultSessionStorage=new SessionStorage(defaultLogger);\n\n/**\n * A storage utility to persist values in cookies via Storage interface\n */class CookieStorage{isSupportAvailable=true;isEnabled=true;length=0;constructor(logger){this.logger=logger;}configure(options){if(!this.options){this.options=getDefaultCookieOptions();}this.options=mergeDeepRight(this.options,options??{});if(this.options.sameDomainCookiesOnly){delete this.options.domain;}this.isSupportAvailable=isStorageAvailable(COOKIE_STORAGE,this);this.isEnabled=Boolean(this.options.enabled&&this.isSupportAvailable);return this.options;}setItem(key,value){cookie(key,value,this.options,this.logger);this.length=Object.keys(cookie()).length;return true;}// eslint-disable-next-line class-methods-use-this\ngetItem(key){const value=cookie(key);return isUndefined(value)?null:value;}removeItem(key){const result=this.setItem(key,null);this.length=Object.keys(cookie()).length;return result;}// eslint-disable-next-line class-methods-use-this\nclear(){// Not implemented\n// getting a list of all cookie storage keys and remove all values\n// sounds risky to do as it will take on all top domain cookies\n// better to explicitly clear specific ones if needed\n}key(index){const curKeys=this.keys();return curKeys[index]??null;}// eslint-disable-next-line class-methods-use-this\nkeys(){return Object.keys(cookie());}}const defaultCookieStorage=new CookieStorage(defaultLogger);\n\n/**\n * A utility to retrieve the storage singleton instance by type\n */const getStorageEngine=type=>{switch(type){case LOCAL_STORAGE:return defaultLocalStorage;case SESSION_STORAGE:return defaultSessionStorage;case MEMORY_STORAGE:return defaultInMemoryStorage;case COOKIE_STORAGE:return defaultCookieStorage;default:return defaultInMemoryStorage;}};/**\n * Configure cookie storage singleton\n */const configureCookieStorageEngine=options=>{const cookieStorageOptions=defaultCookieStorage.configure(options);
1// Update the state with the final cookie storage options\nstate.storage.cookie.value={maxage:cookieStorageOptions.maxage,path:cookieStorageOptions.path,domain:cookieStorageOptions.domain,samesite:cookieStorageOptions.samesite,expires:cookieStorageOptions.expires,secure:cookieStorageOptions.secure};};/**\n * Configure local storage singleton\n */const configureLocalStorageEngine=options=>{defaultLocalStorage.configure(options);};/**\n * Configure in memory storage singleton\n */const configureInMemoryStorageEngine=options=>{defaultInMemoryStorage.configure(options);};/**\n * Configure session storage singleton\n */const configureSessionStorageEngine=options=>{defaultSessionStorage.configure(options);};/**\n * Configure all storage singleton instances\n */const configureStorageEngines=(cookieStorageOptions={},localStorageOptions={},inMemoryStorageOptions={},sessionStorageOptions={})=>{configureCookieStorageEngine(cookieStorageOptions);configureLocalStorageEngine(localStorageOptions);configureInMemoryStorageEngine(inMemoryStorageOptions);configureSessionStorageEngine(sessionStorageOptions);};\n\n/**\n * Store Implementation with dedicated storage\n */class Store{constructor(config,engine,pluginsManager){this.id=config.id;this.name=config.name;this.isEncrypted=config.isEncrypted??false;this.validKeys=config.validKeys??{};this.engine=engine;this.noKeyValidation=Object.keys(this.validKeys).length===0;this.noCompoundKey=config.noCompoundKey;this.originalEngine=this.engine;this.errorHandler=config.errorHandler;this.logger=config.logger;this.pluginsManager=pluginsManager;}/**\n * Ensure the key is valid and with correct format\n */createValidKey(key){const{name,id,validKeys,noKeyValidation,noCompoundKey}=this;if(noKeyValidation){return noCompoundKey?key:[name,id,key].join('.');}// validate and return undefined if invalid key\nlet compoundKey;Object.values(validKeys).forEach(validKeyName=>{if(validKeyName===key){compoundKey=noCompoundKey?key:[name,id,key].join('.');}});return compoundKey;}/**\n * Switch to inMemoryEngine, bringing any existing data with.\n */swapQueueStoreToInMemoryEngine(){const{name,id,validKeys,noCompoundKey}=this;const inMemoryStorage=getStorageEngine(MEMORY_STORAGE);// grab existing data, but only for this page's queue instance, not all\n// better to keep other queues in localstorage to be flushed later\n// than to pull them into memory and remove them from durable storage\nObject.keys(validKeys).forEach(key=>{const value=this.get(validKeys[key]);const validKey=noCompoundKey?key:[name,id,key].join('.');inMemoryStorage.setItem(validKey,value);// TODO: are we sure we want to drop clientData\n// if cookies are not available and localstorage is full?\nthis.remove(key);});this.engine=inMemoryStorage;}/**\n * Set value by key.\n */set(key,value){const validKey=this.createValidKey(key);if(!validKey){return;}try{// storejs that is used in localstorage engine already stringifies json\nthis.engine.setItem(validKey,this.encrypt(stringifyWithoutCircular(value,fal
1se,[],this.logger)));}catch(err){if(isStorageQuotaExceeded(err)){this.logger.warn(STORAGE_QUOTA_EXCEEDED_WARNING(`Store ${this.id}`));// switch to inMemory engine\nthis.swapQueueStoreToInMemoryEngine();// and save it there\nthis.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**\n * Get by Key.\n */get(key){const validKey=this.createValidKey(key);let decryptedValue;try{if(!validKey){return null;}decryptedValue=this.decrypt(this.engine.getItem(validKey));if(isNullOrUndefined(decryptedValue)||decryptedValue===''){return null;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors\nreturn JSON.parse(decryptedValue);}catch(err){const encryptionPluginName=state.storage.encryptionPluginName.value;// Skip error reporting only when the encryption plugin is configured but failed to load\nconst shouldReportError=!encryptionPluginName||!state.plugins.failedPlugins.value.includes(encryptionPluginName);if(shouldReportError){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);}return null;}}/**\n * Remove by Key.\n */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**\n * Get original engine\n */getOriginalEngine(){return this.originalEngine;}/**\n * Decrypt values\n */decrypt(value){if(isNullOrUndefined(value)){return null;}return this.crypto(value,'decrypt');}/**\n * Encrypt value\n */encrypt(value){return this.crypto(value,'encrypt');}/**\n * Extension point to use with encryption plugins\n */crypto(value,mode){const noEncryption=!this.isEncrypted||!value||typeof value!=='string'||trim(value)==='';if(noEncryption){return value;}const extensionPointName=`storage.${mode}`;const formattedValue=this.pluginsManager?this.pluginsManager.invokeSingle(extensionPointName,value):value;return typeof formattedValue==='undefined'?value:formattedValue??'';}/**\n * Handle errors\n */onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:`Store ${this.id}`,customMessage,groupingHash});}}\n\nconst getStorageTypeFromPreConsentIfApplicable=(state,sessionKey)=>{let overriddenStorageType;if(state.consents.preConsent.value.enabled){switch(state.consents.preConsent.value.storage?.strategy){case 'none':overriddenStorageType=NO_STORAGE;break;case 'session':if(sessionKey!=='sessionInfo'){overriddenStorageType=NO_STORAGE;}break;case 'anonymousId':if(sessionKey!=='anonymousId'){overriddenStorageType=NO_STORAGE;}break;}}return overriddenStorageType;};\n\n/**\n * A service to manage stores & available storage client configurations\n */class StoreManager{stores={};isInitialized=false;constructor(pluginsManager,errorHandler,logger){this.errorHandler=errorHandler;this.logger=logger;this.pluginsManager=pluginsManager;}/**\n * Configure available storage client instances\n */init(){if(this.isInitialized){return;}const loadOptions=state.loadOptions.value;const config={cookieStorageOptions:{samesite:loadOptions.sameSiteCookie,secure:loadOptions.secureCookie,domain:loadOptions.setCookieDomain,sameDomainCookiesOnly:loadOptions.sameDomainCookiesOnly},localStorageOptions:{},inMemoryStorageOptions:{},sessionStorageOptions:{}};configureStorageEngines(removeUndefinedValues(mergeDeepRight(config.cookieStorageOptions??{},state.storage.cookie?.value??{})),removeUndefinedValues(config.localStorageOptions),removeUndefinedValues(config.inMemoryStorageOptions),removeUndefinedValues(config.sessionStorageOptions));this.initClientDataStores();this.isInitialized=true;}/**\n * Create store to persist data used by the SDK like session, used details etc\n */initClientDataStores(){this.initializeStorageState();// TODO: fill in extra config values and bring them in from StoreManagerOptions if needed\n// TODO: should we pass the keys for all in order to validate or leave free as v1.1?\n// Initializing all the enabled store because previous user data might be in different storage\n// that needs auto migration\nconst storageTypes=[MEMORY_STORAGE,LOCAL_STORAGE,COOKIE_STORAGE,SESSION_STORAGE];
1storageTypes.forEach(storageType=>{if(getStorageEngine(storageType)?.isEnabled){this.setStore({id:storageClientDataStoreNameMap[storageType],name:storageClientDataStoreNameMap[storageType],isEncrypted:true,noCompoundKey:true,type:storageType,errorHandler:this.errorHandler,logger:this.logger});}});}initializeStorageState(){let globalStorageType=state.storage.type.value;let entriesOptions=state.loadOptions.value.storage?.entries;// Use the storage options from post consent if anything is defined\nconst postConsentStorageOpts=state.consents.postConsent.value.storage;if(isDefined(postConsentStorageOpts?.type)||isDefined(postConsentStorageOpts?.entries)){globalStorageType=postConsentStorageOpts?.type;entriesOptions=postConsentStorageOpts?.entries;}let trulyAnonymousTracking=true;let storageEntries={};USER_SESSION_KEYS.forEach(sessionKey=>{const key=sessionKey;const storageKey=sessionKey;const configuredStorageType=entriesOptions?.[key]?.type;const preConsentStorageType=getStorageTypeFromPreConsentIfApplicable(state,sessionKey);// Storage type precedence order: pre-consent strategy > entry type > global type > default\nconst storageType=preConsentStorageType??configuredStorageType??globalStorageType??DEFAULT_STORAGE_TYPE;const finalStorageType=this.getResolvedStorageTypeForEntry(storageType,sessionKey);if(finalStorageType!==NO_STORAGE){trulyAnonymousTracking=false;}storageEntries={...storageEntries,[sessionKey]:{type:finalStorageType,key:COOKIE_KEYS[storageKey]}};});n(()=>{state.storage.type.value=globalStorageType;state.storage.entries.value=storageEntries;state.storage.trulyAnonymousTracking.value=trulyAnonymousTracking;});}getResolvedStorageTypeForEntry(storageType,sessionKey){let finalStorageType=storageType;switch(storageType){case LOCAL_STORAGE:if(!getStorageEngine(LOCAL_STORAGE)?.isEnabled){finalStorageType=MEMORY_STORAGE;}break;case SESSION_STORAGE:if(!getStorageEngine(SESSION_STORAGE)?.isEnabled){finalStorageType=MEMORY_STORAGE;}break;case MEMORY_STORAGE:case NO_STORAGE:break;case COOKIE_STORAGE:default:// First try setting the storage to cookie else to local storage\nif(getStorageEngine(COOKIE_STORAGE)?.isEnabled){finalStorageType=COOKIE_STORAGE;}else if(getStorageEngine(LOCAL_STORAGE)?.isEnabled){finalStorageType=LOCAL_STORAGE;}else if(getStorageEngine(SESSION_STORAGE)?.isEnabled){finalStorageType=SESSION_STORAGE;}else {finalStorageType=MEMORY_STORAGE;}break;}if(finalStorageType!==storageType){this.logger.warn(STORAGE_UNAVAILABLE_WARNING(STORE_MANAGER,sessionKey,storageType,finalStorageType));}return finalStorageType;}/**\n * Create a new store\n */setStore(storeConfig){const storageEngine=getStorageEngine(storeConfig.type);this.stores[storeConfig.id]=new Store(storeConfig,storageEngine,this.pluginsManager);return this.stores[storeConfig.id];}/**\n * Retrieve a store\n */getStore(id){return this.stores[id];}}\n\nconst isValidSourceConfig=res=>isObjectLiteralAndNotNull(res)&&isObjectLiteralAndNotNull(res.source)&&!isNullOrUndefined(res.source.id)&&isObjectLiteralAndNotNull(res.source.config)&&Array.isArray(res.source.destinations);const isValidStorageType=storageType=>typeof storageType==='string'&&SUPPORTED_STORAGE_TYPES.includes(storageType);const getTopDomain=url=>{// Create a URL object\nconst urlObj=new URL(url);// Extract the host and protocol\nconst{host,protocol}=urlObj;// Split the host into parts\nconst parts=host.split('.');let topDomain;// Handle different cases, especially for co.uk or similar TLDs\nif(parts.length>2){// Join the last two parts for the top-level domain\ntopDomain=`${parts[parts.length-2]}.${parts[parts.length-1]}`;}else {// If only two parts or less, return as it is\ntopDomain=host;}return {topDomain,protocol};};const getTopDomainUrl=url=>{const{topDomain,protocol}=getTopDomain(url);return `${protocol}//${topDomain}`;};const getDataServiceUrl=(endpoint,useExactDomain)=>{const url=useExactDomain?window.location.origin:getTopDomainUrl(window.location.href);const formattedEndpoint=endpoint.startsWith('/')?endpoint.substring(1):endpoint;return `${url}/${formattedEndpoint}`;};const isWebpageTopLevelDomain=providedDomain=>{const{topDomain}=getTopDomain(window.location.href);return topDomain===providedDomain;};\n\n/**\n * Removes trailing slash from url\n * @param url\n * @returns url\n */const removeTrailingSlashes=url=>url?.endsWith('/')?removeTrailingSlashes(url.substring(0,url.length-1)):url;const getDomain=url=>{try{const urlObj=new URL(url);return urlObj.host;}catch(error){return null;}};/**\n * Get the referring domain from the referrer URL\n * @param referrer Page referrer\n * @returns Page referring domain\n */const getReferringDomain=referrer=>getDomain(referrer)??'';/**\n * Extracts UTM parameters from the URL\n * @param url Page URL\n * @returns UTM parameters\n */const extractUTMParameters=url=>{const result={};try{const urlObj=new URL(url);const UTM_PREFIX='utm_';
1urlObj.searchParams.forEach((value,sParam)=>{if(sParam.startsWith(UTM_PREFIX)){let utmParam=sParam.substring(UTM_PREFIX.length);// Not sure why we're doing this\nif(utmParam==='campaign'){utmParam='name';}result[utmParam]=value;}});}catch(error){// Do nothing\n}return result;};/**\n * To get the URL until the hash\n * @param url The input URL\n * @returns URL until the hash\n */const getUrlWithoutHash=url=>{let urlWithoutHash=url;try{const urlObj=new URL(url);urlWithoutHash=urlObj.origin+urlObj.pathname+urlObj.search;}catch(error){// Do nothing\n}return urlWithoutHash;};\n\nconst DEFAULT_PRE_CONSENT_STORAGE_STRATEGY='none';const DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE='immediate';\n\nconst isErrorReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.errors?.enabled===true;const isMetricsReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.metrics?.enabled===true;\n\n/**\n * Validates and normalizes the consent options provided by the user\n * @param options Consent options provided by the user\n * @returns Validated and normalized consent options\n */const getValidPostConsentOptions=options=>{const validOptions={sendPageEvent:false,trackConsent:false,discardPreConsentEvents:false};if(isObjectLiteralAndNotNull(options)){const clonedOptions=clone(options);validOptions.storage=clonedOptions.storage;if(isNonEmptyObject(clonedOptions.integrations)){validOptions.integrations=clonedOptions.integrations;}validOptions.discardPreConsentEvents=clonedOptions.discardPreConsentEvents===true;validOptions.sendPageEvent=clonedOptions.sendPageEvent===true;validOptions.trackConsent=clonedOptions.trackConsent===true;if(isNonEmptyObject(clonedOptions.consentManagement)){// Override enabled value with the current state value\nvalidOptions.consentManagement=mergeDeepRight(clonedOptions.consentManagement,{enabled:state.consents.enabled.value});}}return validOptions;};/**\n * Validates if the input is a valid consents data\n * @param value Input consents data\n * @returns true if the input is a valid consents data else false\n */const isValidConsentsData=value=>isNonEmptyObject(value)||Array.isArray(value);/**\n * Retrieves the corresponding provider and plugin name of the selected consent manager from the supported consent managers\n * @param consentManagementOpts consent management options\n * @param logger logger instance\n * @returns Corresponding provider and plugin name of the selected consent manager from the supported consent managers\n */const getConsentManagerInfo=(consentManagementOpts,logger)=>{let{provider}=consentManagementOpts;const consentManagerPluginName=provider?ConsentManagersToPluginNameMap[provider]:undefined;if(provider&&!consentManagerPluginName){logger.error(UNSUPPORTED_CONSENT_MANAGER_ERROR(CONFIG_MANAGER,provider,ConsentManagersToPluginNameMap));// Reset the provider value\nprovider=undefined;}return {provider,consentManagerPluginName};};/**\n * Validates and converts the consent management options into a normalized format\n * @param consentManagementOpts Consent management options provided by the user\n * @param logger logger instance\n * @returns An object containing the consent manager plugin name, initialized, enabled and consents data\n */const getConsentManagementData=(consentManagementOpts,logger)=>{let consentManagerPluginName;let allowedConsentIds=[];let deniedConsentIds=[];let initialized=false;let provider;let enabled=consentManagementOpts?.enabled===true;if(isNonEmptyObject(consentManagementOpts)&&enabled){// Get the corresponding plugin name of the selected consent manager from the supported consent managers\n({provider,consentManagerPluginName}=getConsentManagerInfo(consentManagementOpts,logger));if(isValidConsentsData(consentManagementOpts.allowedConsentIds)){allowedConsentIds=consentManagementOpts.allowedConsentIds;initialized=true;}if(isValidConsentsData(consentManagementOpts.deniedConsentIds)){deniedConsentIds=consentManagementOpts.deniedConsentIds;initialized=true;}}const consentsData={allowedConsentIds,deniedConsentIds};// Enable consent management only if consent manager is supported\nenabled=enabled&&Boolean(consentManagerPluginName);return {provider,consentManagerPluginName,initialized,enabled,consentsData};};
1\n\n/**\n * Determines the SDK URL\n * @returns sdkURL\n */const getSDKUrl=()=>{// First try the new method of getting the SDK URL\n// from the script tag\nconst scriptTag=document.querySelector('script[data-rsa-write-key]');if(scriptTag&&scriptTag.dataset.rsaWriteKey===state.lifecycle.writeKey.value){return scriptTag.src;}// If the new method fails, try the old method\n// TODO: We need to remove this once all the customers upgrade to the\n// latest SDK loading snippet\nconst scripts=document.getElementsByTagName('script');const sdkFileNameRegex=/(?:^|\\/)rsa(\\.min)?\\.js$/;// eslint-disable-next-line no-restricted-syntax\nfor(const script of scripts){const src=script.getAttribute('src');if(src&&sdkFileNameRegex.test(src)){return src;}}return undefined;};/**\n * Updates the reporting state variables from the source config data\n * @param res Source config\n * @param logger Logger instance\n */const updateReportingState=res=>{state.reporting.isErrorReportingEnabled.value=isErrorReportingEnabled(res.source.config)&&!isSDKRunningInChromeExtension();state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);};const getServerSideCookiesStateData=logger=>{const{useServerSideCookies,dataServiceEndpoint,storage:storageOptsFromLoad,setCookieDomain,sameDomainCookiesOnly}=state.loadOptions.value;let cookieOptions=storageOptsFromLoad?.cookie;let sscEnabled=false;let finalDataServiceUrl;if(useServerSideCookies){sscEnabled=useServerSideCookies;const providedCookieDomain=cookieOptions.domain??setCookieDomain;/**\n * Based on the following conditions, we decide whether to use the exact domain or not to determine the data service URL:\n * 1. If the cookie domain is provided and it is not a top-level domain, then use the exact domain\n * 2. If the sameDomainCookiesOnly flag is set to true, then use the exact domain\n */const useExactDomain=isDefined(providedCookieDomain)&&!isWebpageTopLevelDomain(removeLeadingPerio
1d(providedCookieDomain))||sameDomainCookiesOnly;const dataServiceUrl=getDataServiceUrl(dataServiceEndpoint??DEFAULT_DATA_SERVICE_ENDPOINT,useExactDomain);if(isValidURL(dataServiceUrl)){finalDataServiceUrl=removeTrailingSlashes(dataServiceUrl);const curHost=getDomain(window.location.href);const dataServiceHost=getDomain(dataServiceUrl);// If the current host is different from the data service host, then it is a cross-site request\n// For server-side cookies to work, we need to set the SameSite=None and Secure attributes\n// One round of cookie options manipulation is taking place here\n// Based on these(setCookieDomain/storage.cookie or sameDomainCookiesOnly) two load-options, final cookie options are set in the storage module\n// TODO: Refactor the cookie options manipulation logic in one place\nif(curHost!==dataServiceHost){cookieOptions={...cookieOptions,samesite:'None',secure:true};}/**\n * If the sameDomainCookiesOnly flag is not set and the cookie domain is provided(not top level domain),\n * and the data service host is different from the provided cookie domain, then we disable server-side cookies\n * ex: provided cookie domain: 'random.com', data service host: 'sub.example.com'\n */if(!sameDomainCookiesOnly&&useExactDomain&&dataServiceHost!==removeLeadingPerio
1d(providedCookieDomain)){sscEnabled=false;logger.warn(SERVER_SIDE_COOKIE_FEATURE_OVERRIDE_WARNING(CONFIG_MANAGER,providedCookieDomain,dataServiceHost));}}else {sscEnabled=false;}}return {sscEnabled,cookieOptions,finalDataServiceUrl};};const updateStorageStateFromLoadOptions=logger=>{const{storage:storageOptsFromLoad}=state.loadOptions.value;let storageType=storageOptsFromLoad?.type;if(isDefined(storageType)&&!isValidStorageType(storageType)){logger.warn(STORAGE_TYPE_VALIDATION_WARNING(CONFIG_MANAGER,storageType,DEFAULT_STORAGE_TYPE));storageType=DEFAULT_STORAGE_TYPE;}let storageEncryptionVersion=storageOptsFromLoad?.encryption?.version;const encryptionPluginName=storageEncryptionVersion&&StorageEncryptionVersionsToPluginNameMap[storageEncryptionVersion];if(!isUndefined(storageEncryptionVersion)&&isUndefined(encryptionPluginName)){// set the default encryption plugin\nlogger.warn(UNSUPPORTED_STORAGE_ENCRYPTION_VERSION_WARNING(CONFIG_MANAGER,storageEncryptionVersion,StorageEncryptionVersionsToPluginNameMap,DEFAULT_STORAGE_ENCRYPTION_VERSION));storageEncryptionVersion=DEFAULT_STORAGE_ENCRYPTION_VERSION;}else if(isUndefined(storageEncryptionVersion)){storageEncryptionVersion=DEFAULT_STORAGE_ENCRYPTION_VERSION;}// Allow migration only if the configured encryption version is the default encryption version\nconst configuredMigrationValue=storageOptsFromLoad?.migrate;const finalMigrationVal=configuredMigrationValue&&storageEncryptionVersion===DEFAULT_STORAGE_ENCRYPTION_VERSION;if(configuredMigrationValue===true&&finalMigrationVal!==configuredMigrationValue){logger.warn(STORAGE_DATA_MIGRATION_OVERRIDE_WARNING(CONFIG_MANAGER,storageEncryptionVersion,DEFAULT_STORAGE_ENCRYPTION_VERSION));}const{sscEnabled,finalDataServiceUrl,cookieOptions}=getServerSideCookiesStateData(logger);n(()=>{state.storage.type.value=storageType;state.storage.cookie.value=cookieOptions;state.serverCookies.isEnabledServerSideCookies.value=sscEnabled;state.serverCookies.dataServiceUrl.value=finalDataServiceUrl;state.storage.encryptionPluginName.value=StorageEncryptionVersionsToPluginNameMap[storageEncryptionVersion];state.storage.migrate.value=finalMigrationVal;});};
1const updateConsentsStateFromLoadOptions=logger=>{const{provider,consentManagerPluginName,initialized,enabled,consentsData}=getConsentManagementData(state.loadOptions.value.consentManagement,logger);// Pre-consent\nconst preConsentOpts=state.loadOptions.value.preConsent;let storageStrategy=preConsentOpts?.storage?.strategy??DEFAULT_PRE_CONSENT_STORAGE_STRATEGY;const StorageStrategies=['none','session','anonymousId'];if(isDefined(storageStrategy)&&!StorageStrategies.includes(storageStrategy)){storageStrategy=DEFAULT_PRE_CONSENT_STORAGE_STRATEGY;logger.warn(UNSUPPORTED_PRE_CONSENT_STORAGE_STRATEGY(CONFIG_MANAGER,preConsentOpts?.storage?.strategy,DEFAULT_PRE_CONSENT_STORAGE_STRATEGY));}let eventsDeliveryType=preConsentOpts?.events?.delivery??DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE;const deliveryTypes=['immediate','buffer'];if(isDefined(eventsDeliveryType)&&!deliveryTypes.includes(eventsDeliveryType)){eventsDeliveryType=DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE;logger.warn(UNSUPPORTED_PRE_CONSENT_EVENTS_DELIVERY_TYPE(CONFIG_MANAGER,preConsentOpts?.events?.delivery,DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE));}n(()=>{state.consents.activeConsentManagerPluginName.value=consentManagerPluginName;state.consents.initialized.value=initialized;state.consents.enabled.value=enabled;state.consents.data.value=consentsData;state.consents.provider.value=provider;state.consents.preConsent.value={// Only enable pre-consent if it is explicitly enabled and\n// if it is not already initialized and\n// if consent management is enabled\nenabled:state.loadOptions.value.preConsent?.enabled===true&&initialized===false&&enabled===true,storage:{strategy:storageStrategy},events:{delivery:eventsDeliveryType}};});};/**\n * Determines the consent management state variables from the source config data\n * @param resp Source config response\n * @param logger Logger instance\n */const updateConsentsState=resp=>{let resolutionStrategy=state.consents.resolutionStrategy.value;let cmpMetadata;if(isObjectLiteralAndNotNull(resp.consentManagementMetadata)){if
1(state.consents.provider.value){resolutionStrategy=resp.consentManagementMetadata.providers.find(p=>p.provider===state.consents.provider.value)?.resolutionStrategy??state.consents.resolutionStrategy.value;}cmpMetadata=resp.consentManagementMetadata;}// If the provider is custom, then the resolution strategy is not applicable\nif(state.consents.provider.value==='custom'){resolutionStrategy=undefined;}n(()=>{state.consents.metadata.value=clone(cmpMetadata);state.consents.resolutionStrategy.value=resolutionStrategy;});};const updateDataPlaneEventsStateFromLoadOptions=logger=>{if(state.dataPlaneEvents.deliveryEnabled.value){const defaultEventsQueuePluginName='XhrQueue';let eventsQueuePluginName=defaultEventsQueuePluginName;if(state.loadOptions.value.useBeacon){if(state.capabilities.isBeaconAvailable.value){eventsQueuePluginName='BeaconQueue';}else {eventsQueuePluginName=defaultEventsQueuePluginName;logger.warn(UNSUPPORTED_BEACON_API_WARNING(CONFIG_MANAGER));}}n(()=>{state.dataPlaneEvents.eventsQueuePluginName.value=eventsQueuePluginName;});}};const getSourceConfigURL=(configUrl,writeKey,lockIntegrationsVersion,lockPluginsVersion,logger)=>{const defSearchParams=new URLSearchParams({p:MODULE_TYPE,v:APP_VERSION,build:BUILD_TYPE,writeKey,lockIntegrationsVersion:lockIntegrationsVersion.toString(),lockPluginsVersion:lockPluginsVersion.toString()});let origin=DEFAULT_CONFIG_BE_URL;let searchParams=defSearchParams;let pathname='/sourceConfig/';let hash='';if(isValidURL(configUrl)){const configUrlInstance=new URL(configUrl);if(!removeTrailingSlashes(configUrlInstance.pathname).endsWith('/sourceConfig')){configUrlInstance.pathname=`${removeTrailingSlashes(configUrlInstance.pathname)}/sourceConfig/`;}configUrlInstance.pathname=removeDuplicateSlashes(configUrlInstance.pathname);defSearchParams.forEach((value,key)=>{if(configUrlInstance.searchParams.get(key)===null){configUrlInstance.searchParams.set(key,value);}});origin=configUrlInstance.origin;pathname=configUrlInstance.pathname;searchParams=configUrlInstance.searchParams;hash=configUrlInstance.hash;}else {logger.warn(INVALID_CONFIG_URL_WARNING(CONFIG_MANAGER,configUrl));}return `${origin}${pathname}?${searchParams}${hash}`;};/**\n * Transforms destinations config from source config response to Destination format\n * @param destinations Array of destination items from config response\n * @returns Array of transformed Destination objects\n */const getDestinationsFromConfig=destinations=>destinations.map(destination=>({id:destination.id,displayName:destination.destinationDefinition.displayName,enabled:destination.enabled,config:destination.config,shouldApplyDeviceModeTransformation:destination.shouldApplyDeviceModeTransformation??false,propagateEventsUntransformedOnError:destination.propagateEventsUntransformedOnError??false,userFriendlyId:getDestinationUserFriendlyId(destination.destinationDefinition.displayName,destination.id),isCustomIntegration:destination.destinationDefinition.displayName===CUSTOM_DEVICE_MODE_DESTINATION_DISPLAY_NAME}));\n\n/**\n * A function that determines the base URL for the integrations or plugins SDK\n * @param componentType The type of the component (integrations or plugins)\n * @param pathSuffix The path suffix to be appended to the base URL (js-integrations or plugins)\n * @param defaultComponentUrl The default URL to be used if the user has not provided a custom URL\n * @param currentSdkVersion The current version of the SDK\n * @param lockVersion Flag to lock the version of the component\n * @param urlFromLoadOptions The URL provided by the user in the load options\n * @param logger Logger instance\n * @returns The base URL for the integrations or plugins SDK\n */const getSDKComponentBaseURL=(componentType,pathSuffix,defaultComponentUrl,currentSdkVersion,lockVersion,urlFromLoadOptions,logger)=>{let sdkComponentBaseURL;// If the user has provided a custom URL, then validate, clean up and use it\nif(urlFromLoadOptions){if(!isValidURL(urlFromLoadOptions)){logger.error(COMPONENT_BASE_URL_ERROR(CONFIG_MANAGER,componentType,urlFromLoadOptions));return null;}
1sdkComponentBaseURL=removeTrailingSlashes(urlFromLoadOptions);}else {sdkComponentBaseURL=defaultComponentUrl;// We can automatically determine the base URL only for CDN installations\nif(state.context.app.value.installType==='cdn'){const sdkURL=getSDKUrl();if(sdkURL){// Extract the base URL from the core SDK file URL\n// and append the path suffix to it\nsdkComponentBaseURL=sdkURL.split('/').slice(0,-1).concat(pathSuffix).join('/');}}}// If the version needs to be locked, then replace the major version in the URL\n// with the current version of the SDK\nif(lockVersion){sdkComponentBaseURL=sdkComponentBaseURL.replace(new RegExp(`/${CDN_ARCH_VERSION_DIR}/${BUILD_TYPE}/${pathSuffix}$`),`/${currentSdkVersion}/${BUILD_TYPE}/${pathSuffix}`);}return sdkComponentBaseURL;};/**\n * A function that determines integration SDK loading path\n * @param currentSdkVersion Current SDK version\n * @param lockIntegrationsVersion Flag to lock the integrations version\n * @param integrationsUrlFromLoadOptions URL to load the integrations from as provided by the user\n * @param logger Logger instance\n * @returns\n */const getIntegrationsCDNPath=(currentSdkVersion,lockIntegrationsVersion,integrationsUrlFromLoadOptions,logger)=>getSDKComponentBaseURL('integrations',CDN_INT_DIR,DEFAULT_INTEGRATION_SDKS_URL,currentSdkVersion,lockIntegrationsVersion,integrationsUrlFromLoadOptions,logger);\n\nclass ConfigManager{constructor(httpClient,errorHandler,logger){this.errorHandler=errorHandler;this.logger=logger;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.processConfig=this.processConfig.bind(this);}attachEffects(){j(()=>{this.logger.setMinLogLevel(state.lifecycle.logLevel.value);});}/**\n * A function to validate, construct and store loadOption, lifecycle, source and destination\n * config related information in global state\n */init(){const{logLevel,configUrl,lockIntegrationsVersion,lockPluginsVersion,destSDKBaseURL,pluginsSDKBaseURL,integrations}=state.loadOptions.value;// determine the path to fetch integration SDK from\nconst intgCdnUrl=getIntegrationsCDNPath(APP_VERSION,lockIntegrationsVersion,destSDKBaseURL,this.logger);if(isNull(intgCdnUrl)){return;}let pluginsCDNPath;this.attachEffects();state.lifecycle.activeDataplaneUrl.value=removeTrailingSlashes(state.lifecycle.dataPlaneUrl.value);updateStorageStateFromLoadOptions(this.logger);
1updateConsentsStateFromLoadOptions(this.logger);updateDataPlaneEventsStateFromLoadOptions(this.logger);// set application lifecycle state in global state\nn(()=>{state.lifecycle.integrationsCDNPath.value=intgCdnUrl;state.lifecycle.pluginsCDNPath.value=pluginsCDNPath;if(logLevel){state.lifecycle.logLevel.value=logLevel;}state.lifecycle.sourceConfigUrl.value=getSourceConfigURL(configUrl,state.lifecycle.writeKey.value,lockIntegrationsVersion,lockPluginsVersion,this.logger);state.metrics.metricsServiceUrl.value=`${state.lifecycle.activeDataplaneUrl.value}/${METRICS_SERVICE_ENDPOINT}`;// Data in the loadOptions state is already normalized\nstate.nativeDestinations.loadOnlyIntegrations.value=integrations;});this.getConfig();}/**\n * Handle errors\n */onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:CONFIG_MANAGER,customMessage,groupingHash});}/**\n * A callback function that is executed once we fetch the source config response.\n * Use to construct and store information that are dependent on the sourceConfig.\n */processConfig(response,details){// TODO: add retry logic with backoff based on rejectionDetails.xhr.status\n// We can use isErrRetryable utility method\nif(!isDefined(response)){if(isDefined(details)){this.onError(details.error,SOURCE_CONFIG_FETCH_ERROR);}else {this.onError(new Error(SOURCE_CONFIG_FETCH_ERROR));}return;}let res;try{if(isString(response)){res=JSON.parse(response);}else {res=response;}}catch(err){this.onError(err,SOURCE_CONFIG_RESOLUTION_ERROR);return;}if(!isValidSourceConfig(res)){this.onError(new Error(SOURCE_CONFIG_RESOLUTION_ERROR));return;}// Log error and abort if source is disabled\nif(res.source.enabled===false){this.logger.error(SOURCE_DISABLED_ERROR);return;}// set the values in state for reporting slice\nupdateReportingState(res);const nativeDestinations=res.source.destinations.length>0?getDestinationsFromConfig(res.source.destinations):[];// set in the state --\x3e source, destination, lifecycle, reporting\nn(()=>{// set source related information in state\nstate.source.value={config:res.source.config,name:res.source.name,id:res.source.id,workspaceId:res.source.workspaceId};// set device mode destination related information in state\nstate.nativeDestinations.configuredDestinations.value=nativeDestinations;// set the desired optional plugins\nstate.plugins.pluginsToLoadFromConfig.value=state.loadOptions.value.plugins??[];updateConsentsState(res);// set application lifecycle state\nstate.lifecycle.status.value='configured';});}/**\n * A function to fetch source config either from /sourceConfig endpoint\n * or from getSourceConfig load option\n * @returns\n */getConfig(){const sourceConfigFunc=state.loadOptions.value.getSourceConfig;if(sourceConfigFunc){if(!isFunction(sourceConfigFunc)){this.logger.error(SOURCE_CONFIG_OPTION_ERROR(CONFIG_MANAGER));return;}// Fetch source config from the function\nconst res=sourceConfigFunc();if(res instanceof Promise){res.then(pRes=>this.processConfig(pRes)).catch(err=>{this.onError(err,'SourceConfig');});}else {this.processConfig(res);}}else {// Fetch source configuration from the configured URL\nthis.httpClient.getAsyncData({url:state.lifecycle.sourceConfigUrl.value,options:{headers:{'Content-Type':undefined}},callback:this.processConfig});}}}\n\n/**\n * To get the timezone of the user\n *\n * @returns string\n */const getTimezone=()=>{// Not susceptible to super-linear backtracking\n// eslint-disable-next-line sonarjs/slow-regex\nconst timezone=/([A-Z]+[+-]\\d+)/.exec(new Date().toString());return timezone?.[1]?timezone[1]:'NA';};\n\n/**\n * Get the referrer URL\n * @returns The referrer URL\n */const getReferrer=(getDocument=()=>document)=>getDocument()?.referrer||'$direct';/**\n * To get the canonical URL of the page\n * @returns canonical URL\n */const getCanonicalUrl=(getDocument=()=>document)=>{const docInstance=getDocument();const tags=docInstance.getElementsByTagName('link');let canonicalUrl='';for(let i=0;tags[i];i+=1){const tag=tags[i];if(tag.getAttribute('rel')==='canonical'&&!canonicalUrl){canonicalUrl=tag.getAttribute('href')??'';break;}}return canonicalUrl;};const getUserAgent=(getNavigator=()=>globalThis.navigator)=>{const navigator=getNavigator();if(isUndefined(navigator)){return null;}let{userAgent}=navigator;const{brave}=navigator;// For supporting Brave browser detection,\n// add \"Brave/<version>\" to the user agent with the version value from the Chrome component\nif(brave&&Object.getPrototypeOf(brave).isBrave){// Example:\n// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36\nconst matchedArr=userAgent.match(/(chrome)\\/([\\w.]+)/i);if(matchedArr){userAgent=`${userAgent} Brave/${matchedArr[2]}`;}}return userAgent;};const getLanguage=(getNavigator=()=>globalThis.navigator)=>{const navigator=getNavigator();if(isUndefined(navigator)){return null;}return navigator.language??navigator.browserLanguage;};/**\n * Default page properties\n * @returns Default page properties\n */const getDefaultPageProperties=(getLocation=()=>globalThis.location,getDocument=()=>document)=>{const location=getLocation();const canonicalUrl=getCanonicalUrl(getDocument);let path=location.pathname;const{href:tabUrl}=location;let pageUrl=tabUrl;const{search}=location;// If valid canonical URL is provided use this as page URL.\nif(canonicalUrl){try{const urlObj=new URL(canonicalUrl);
1// If existing, query params of canonical URL will be used instead of the location.search ones\nif(urlObj.search===''){pageUrl=canonicalUrl+search;}else {pageUrl=canonicalUrl;}path=urlObj.pathname;}catch(err){// Do nothing\n}}const url=getUrlWithoutHash(pageUrl);const{title}=getDocument();const referrer=getReferrer(getDocument);return {path,referrer,referring_domain:getReferringDomain(referrer),search,title,url,tab_url:tabUrl};};\n\nconst getUserAgentClientHint=(callback,level='none')=>{if(level==='none'){callback(undefined);}if(level==='default'){callback(navigator.userAgentData);}if(level==='full'){navigator.userAgentData?.getHighEntropyValues(['architecture','bitness','brands','mobile','model','platform','platformVersion','uaFullVersion','fullVersionList','wow64']).then(ua=>{callback(ua);}).catch(()=>{callback();});}};\n\nconst isDatasetAvailable=()=>{const testElement=globalThis.document.createElement('div');testElement.setAttribute('data-a-b','c');return testElement.dataset?testElement.dataset.aB==='c':false;};const legacyJSEngineRequiredPolyfills={// Ideally, we should separate the checks for URL and URLSearchParams but\n// the polyfill service serves them under the same feature name, \"URL\".\nURL:()=>!isFunction(globalThis.URL)||!isFunction(globalThis.URLSearchParams),Promise:()=>!isFunction(globalThis.Promise),'Number.isNaN':()=>!isFunction(globalThis.Number.isNaN),'Number.isInteger':()=>!isFunction(globalThis.Number.isInteger),'Array.from':()=>!isFunction(globalThis.Array.from),'Array.prototype.find':()=>!isFunction(globalThis.Array.prototype.find),'Array.prototype.includes':()=>!isFunction(globalThis.Array.prototype.includes),'String.prototype.endsWith':()=>!isFunction(globalThis.String.prototype.endsWith),'String.prototype.startsWith':()=>!isFunction(globalThis.String.prototype.startsWith),'String.prototype.includes':()=>!isFunction(globalThis.String.prototype.includes),'String.prototype.replaceAll':()=>!isFunction(globalThis.String.prototype.replaceAll),'String.fromCodePoint':()=>!isFunction(globalThis.String.fromCodePoint),'Object.entries':()=>!isFunction(globalThis.Object.entries),'Object.values':()=>!isFunction(globalThis.Object.values),'Object.assign':()=>!isFunction(globalThis.Object.assign),'Object.fromEntries':()=>!isFunction(globalThis.Object.fromEntries),'Element.prototype.dataset':()=>!isDatasetAvailable(),// Ideally, we should separate the checks for TextEncoder and TextDecoder but\n// the polyfill service serves them under the same feature name, \"TextEncoder\".\nTextEncoder:()=>!isFunction(globalThis.TextEncoder)||!isFunction(globalThis.TextDecoder),requestAnimationFrame:()=>!isFunction(globalThis.requestAnimationFrame)||!isFunction(globalThis.cancelAnimationFrame),CustomEvent:()=>!isFunction(globalThis.CustomEvent),'navigator.sendBeacon':()=>!isFunction(globalThis.navigator.sendBeacon),// Note, the polyfill service serves both ArrayBuffer and Uint8Array under the same feature name, \"ArrayBuffer\".\nArrayBuffer:()=>!isFunction(globalThis.Uint8Array),Set:()=>!isFunction(globalThis.Set),atob:()=>!isFunction(globalThis.atob)};const isLegacyJSEngine=()=>{const requiredCapabilitiesList=Object.keys(legacyJSEngineRequiredPolyfills);let needsPolyfill=false;/* eslint-disable-next-line unicorn/no-for-loop */for(let i=0;i<requiredCapabilitiesList.length;i++){const isCapabilityMissing=legacyJSEngineRequiredPolyfills[requiredCapabilitiesList[i]];if(isFunction(isCapabilityMissing)&&isCapabilityMissing()){needsPolyfill=true;break;}}return needsPolyfill;};\n\nconst polyfillIoSdkUrl='https://polyfill-fastly.io/v3/polyfill.min.js';const POLYFILL_URL=`${polyfillIoSdkUrl}?version=3.111.0&features=${Object.keys(legacyJSEngineRequiredPolyfills).join('%2C')}`;const POLYFILL_LOAD_TIMEOUT=10*1000;// 10 seconds\nconst POLYFILL_SCRIPT_ID='rudderstackPolyfill';\n\nconst hasCrypto=()=>!isNullOrUndefined(globalThis.crypto)&&isFunction(globalThis.crypto.getRandomValues);// eslint-disable-next-line compat/compat -- We are checking for the existence of navigator.userAgentData\nconst hasUAClientHints=()=>!isNullOrUndefined(globalThis.navigator.userAgentData);const hasBeacon=()=>!isNullOrUndefined(globalThis.navigator.sendBeacon)&&isFunction(globalThis.navigator.sendBeacon);\n\nconst getScreenDetails=()=>{let screenDetails={density:0,width:0,height:0,innerWidth:0,innerHeight:0};screenDetails={width:globalThis.screen.width,height:globalThis.screen.height,density:globalThis.devicePixelRatio,innerWidth:globalThis.innerWidth,innerHeight:globalThis.innerHeight};return screenDetails;};\n\nclass CapabilitiesManager{constructor(httpClient,errorHandler,logger){this.httpClient=httpClient;this.errorHandler=errorHandler;this.logger=logger;this.externalSrcLoader=new ExternalSrcLoader(this.logger);this.onError=this.onError.bind(this);this.onReady=this.onReady.bind(this);}init(){this.prepareBrowserCapabilities();this.attachWindowListeners();}/**\n * Detect supported capabilities and set values in state\n */// eslint-disable-next-line class-methods-use-this\ndetectBrowserCapabilities(){n(()=>{// Storage related details\nstate.capabilities.storage.isCookieStorageAvailable.value=isStorageAvailable(COOKIE_STORAGE,getStorageEngine(COOKIE_STORAGE),this.logger);state.capabilities.storage.isLocalStorageAvailable.value=isStorageAvailable(LOCAL_STORAGE,undefined,this.logger);state.capabilities.storage.isSessionStorageAvailable.value=isStorageAvailable(SESSION_STORAGE,undefined,this.logger);// Browser feature detection details\nstate.capabilities.isBeaconAvailable.value=hasBeacon();state.capabilities.isUaCHAvailable.value=hasUAClientHints();state.capabilities.isCryptoAvailable.value=hasCrypto();state.capabilities.isOnline.value=globalThis.navigator.onLine;// Get page context details\nstate.context.userAgent.value=getUserAgent();state.context.locale.value=getLanguage();state.context.screen.value=getScreenDetails();state.context.timezone.value=getTimezone();if(hasUAClientHints()){getUserAgentClientHint(uach=>{state.context['ua-ch'].value=uach;},state.loadOptions.value.uaChTrackLevel);}});// Ad blocker detection\nj(()=>
1{if(state.loadOptions.value.sendAdblockPage===true&&state.lifecycle.sourceConfigUrl.value!==undefined){detectAdBlockers(this.httpClient);}});}/**\n * Detect if polyfills are required and then load script from polyfill URL\n */prepareBrowserCapabilities(){state.capabilities.isLegacyDOM.value=isLegacyJSEngine();const customPolyfillUrl=state.loadOptions.value.polyfillURL;let polyfillUrl=POLYFILL_URL;if(isDefinedAndNotNull(customPolyfillUrl)){if(isValidURL(customPolyfillUrl)){polyfillUrl=customPolyfillUrl;}else {this.logger.warn(INVALID_POLYFILL_URL_WARNING(CAPABILITIES_MANAGER,customPolyfillUrl));}}const shouldLoadPolyfill=state.loadOptions.value.polyfillIfRequired&&state.capabilities.isLegacyDOM.value&&isValidURL(polyfillUrl);if(shouldLoadPolyfill){const isDefaultPolyfillService=polyfillUrl!==state.loadOptions.value.polyfillURL;if(isDefaultPolyfillService){// write key specific callback\n// NOTE: we're not putting this into RudderStackGlobals as providing the property path to the callback function in the polyfill URL is not possible\nconst polyfillCallbackName=`RS_polyfillCallback_${state.lifecycle.writeKey.value}`;const polyfillCallback=()=>{this.onReady();// Remove the entry from window so we don't leave room for calling it again\ndelete globalThis[polyfillCallbackName];};globalThis[polyfillCallbackName]=polyfillCallback;polyfillUrl=`${polyfillUrl}&callback=${polyfillCallbackName}`;}this.externalSrcLoader.loadJSFile({url:polyfillUrl,id:POLYFILL_SCRIPT_ID,async:true,timeout:POLYFILL_LOAD_TIMEOUT,callback:scriptId=>{if(!scriptId){this.onError(new Error(POLYFILL_SCRIPT_LOAD_ERROR(POLYFILL_SCRIPT_ID,polyfillUrl)));}else if(!isDefaultPolyfillService){this.onReady();}}});}else {this.onReady();}}/**\n * Attach listeners to window to observe event that update capabilities state values\n */attachWindowListeners(){globalThis.addEventListener('offline',()=>{state.capabilities.isOnline.value=false;});globalThis.addEventListener('online',()=>{state.capabilities.isOnline.value=true;});globalThis.addEventListener('resize',debounce(()=>{state.context.screen.value=getScreenDetails();},this));}/**\n * Set the lifecycle status to next phase\n */// eslint-disable-next-line class-methods-use-this\nonReady(){this.detectBrowserCapabilities();state.lifecycle.status.value='browserCapabilitiesReady';}/**\n * Handles error\n * @param error The error object\n */onError(error,groupingHash){this.errorHandler.onError({error,context:CAPABILITIES_MANAGER,groupingHash});}}\n\nconst CHANNEL='web';// These are the top-level elements in the standard RudderStack event spec\nconst TOP_LEVEL_ELEMENTS=['integrations','anonymousId','originalTimestamp'];// Reserved elements in the context of standard RudderStack event spec\n// Typically, these elements are not allowed to be overridden by the user\nconst CONTEXT_RESERVED_ELEMENTS=['library','consentManagement','userAgent','ua-ch','screen'];// Reserved elements in the standard RudderStack event spec\nconst RESERVED_ELEMENTS=['id','anonymous_id','user_id','sent_at','timestamp','received_at','original_timestamp','event','event_text','channel','context_ip','context_request_ip','context_passed_ip','group_id','previous_id'];\n\n/**\n * A function to check given value is a number or not\n * @param num input value\n * @returns boolean\n */const isNumber=num=>typeof num==='number'&&!Number.isNaN(num);/**\n * A function to check given number has minimum length or not\n * @param minimumLength minimum length\n * @param num input number\n * @returns boolean\n */const hasMinLength=(minimumLength,num)=>num.toString().length>=minimumLength;/**\n * A function to check given value is a positive integer or not\n * @param num input value\n * @returns boolean\n */const isPositiveInteger=num=>isNumber(num)&&num>=0&&Number.isInteger(num);\n\nconst MIN_SESSION_ID_LENGTH=10;const isCutOffTimeExceeded=sessionInfo=>{const{cutOff}=sessionInfo;const timestamp=Date.now();return Boolean(cutOff?.enabled&&cutOff.expiresAt&×tamp>cutOff.expiresAt);};/**\n * A function to validate whether the current auto tracking session has expired or not.\n * It checks for the current session expiry and the cut off time expiry.\n * @param sessionInfo session info\n * @returns boolean\n */const hasSe
1ssionExpired=sessionInfo=>{const isCurrentSessionExpired=Boolean(!sessionInfo.expiresAt||Date.now()>sessionInfo.expiresAt);return isCurrentSessionExpired||isCutOffTimeExceeded(sessionInfo);};/**\n * A function to generate session id\n * @returns number\n */const generateSessionId=()=>Date.now();/**\n * Function to validate user provided sessionId\n * @param {number} sessionId\n * @param logger logger\n * @returns\n */const isManualSessionIdValid=(sessionId,logger)=>{if(!sessionId||!isPositiveInteger(sessionId)||!hasMinLength(MIN_SESSION_ID_LENGTH,sessionId)){logger.warn(INVALID_SESSION_ID_WARNING(USER_SESSION_MANAGER,sessionId,MIN_SESSION_ID_LENGTH));return false;}return true;};const getCutOffExpirationTimestamp=cutOff=>{if(!cutOff?.enabled){return undefined;}return cutOff.expiresAt??(isPositiveInteger(cutOff.duration)?Date.now()+cutOff.duration:undefined);};/**\n * A function to generate new auto tracking session\n * @param sessionInfo session info\n * @returns SessionInfo\n */const generateAutoTrackingSession=sessionInfo=>{const{timeout,cutOff}=sessionInfo;const timestamp=Date.now();return {id:timestamp,// set the current timestamp\nexpiresAt:timestamp+timeout,// set the expiry time of the session\ntimeout,autoTrack:true,...(cutOff&&{cutOff})};};/**\n * A function to generate new manual tracking session\n * @param id Provided sessionId\n * @param logger Logger module\n * @returns SessionInfo\n */const generateManualTrackingSession=(id,logger)=>{const sessionId=isManualSessionIdValid(id,logger)?id:generateSessionId();return {id:sessionId,sessionStart:undefined,manualTrack:true};};const isStorageTypeValidForStoringData=storageType=>Boolean(storageType===COOKIE_STORAGE||storageType===LOCAL_STORAGE||storageType===SESSION_STORAGE||storageType===MEMORY_STORAGE);/**\n * Generate a new anonymousId\n * @returns string anonymousID\n */const generateAnonymousId=()=>generateUUID();const getFinalResetOptions=options=>{// Legacy behavior: toggle only anonymousId without mutating defaults\nif(isBoolean(options)){const{entries,...rest}=DEFAULT_RESET_OPTIONS;return {...rest,entries:{...entries,anonymousId:options}};}// Override any defaults with the user provided options\nif(isObjectLiteralAndNotNull(options)&&isObjectLiteralAndNotNull(options.entries)){return mergeDeepRight(DEFAULT_RESET_OPTIONS,options);}return {...DEFAULT_RESET_OPTIONS};};\n\n/**\n * To get the page properties for context object\n * @param pageProps Page properties\n * @returns page properties object for context\n */const getContextPageProperties=pageProps=>{// Need to get updated page details on each event as an event to notify on SPA URL changes does not seem to exist\nconst curPageProps=getDefaultPageProperties();const ctxPageProps={};Object.keys(curPageProps).forEach(key=>{ctxPageProps[key]=pageProps?.[key]||curPageProps[key];});ctxPageProps.initial_referrer=pageProps?.initial_referrer||state.session.initialReferrer.value;ctxPageProps.initial_referring_domain=pageProps?.initial_referring_domain||state.session.initialReferringDomain.value;return ctxPageProps;};/**\n * Add any missing default page properties using values from options and defaults\n * @param properties Input page properties\n * @param options API options\n */const getUpdatedPageProperties=(properties,options)=>{const optionsPageProps=options?.page||{};const pageProps=properties;// Need to get updated page details on each event as an event to notify on SPA URL changes does not seem to exist\nconst curPageProps=getDefaultPageProperties();Object.keys(curPageProps).forEach(key=>{if(isUndefined(pageProps[key])){pageProps[key]=optionsPageProps[key]||curPageProps[key];}});if(isUndefined(pageProps.initial_referrer)){pageProps.initial_referrer=optionsPageProps.initial_referrer||state.session.initialReferrer.value;}if(isUndefined(pageProps.initial_referring_domain)){pageProps.initial_referring_domain=optionsPageProps.initial_referring_domain||state.session.initialReferringDomain.value;}return pageProps;};/**\n * Utility to check for reserved keys in the input object\n * @param obj Generic object\n * @param parentKeyPath Object's parent key path\n * @param logger Logger instance\n */const checkForReservedElementsInObject=(obj,parentKeyPath,logger)=>
1{if(isObjectLiteralAndNotNull(obj)){Object.keys(obj).forEach(property=>{if(RESERVED_ELEMENTS.includes(property)||RESERVED_ELEMENTS.includes(property.toLowerCase())){logger.warn(RESERVED_KEYWORD_WARNING(EVENT_MANAGER,property,parentKeyPath,RESERVED_ELEMENTS));}});}};/**\n * Checks for reserved keys in traits, properties, and contextual traits\n * @param rudderEvent Generated rudder event\n * @param logger Logger instance\n */const checkForReservedElements=(rudderEvent,logger)=>{// properties, traits, contextualTraits are either undefined or object\nconst{properties,traits,context}=rudderEvent;const{traits:contextualTraits}=context;checkForReservedElementsInObject(properties,'properties',logger);checkForReservedElementsInObject(traits,'traits',logger);checkForReservedElementsInObject(contextualTraits,'context.traits',logger);};/**\n * Overrides the top-level event properties with data from API options\n * @param rudderEvent Generated rudder event\n * @param options API options\n */const updateTopLevelEventElements=(rudderEvent,options)=>{if(options.anonymousId&&isString(options.anonymousId)){// eslint-disable-next-line no-param-reassign\nrudderEvent.anonymousId=options.anonymousId;}if(isNonEmptyObject(options.integrations)){// eslint-disable-next-line no-param-reassign\nrudderEvent.integrations=options.integrations;}if(options.originalTimestamp&&isString(options.originalTimestamp)){// eslint-disable-next-line no-param-reassign\nrudderEvent.originalTimestamp=options.originalTimestamp;}};/**\n * To merge the contextual information in API options with existing data\n * @param rudderContext Generated rudder event\n * @param options API options\n * @param logger Logger instance\n */const getMergedContext=(rudderContext,options,logger)=>{let context=rudderContext;Object.keys(options).forEach(key=>{if(!TOP_LEVEL_ELEMENTS.includes(key)&&!CONTEXT_RESERVED_ELEMENTS.includes(key)){if(key!=='context'){context=mergeDeepRight(context,{[key]:options[key]});}else if(!isUndefined(options[key])&&isObjectLiteralAndNotNull(options[key])){const tempContext={};Object.keys(options[key]).forEach(e=>{if(!CONTEXT_RESERVED_ELEMENTS.includes(e)){tempContext[e]=options[key][e];}});context=mergeDeepRight(context,{...tempContext});}else {logger.warn(INVALID_CONTEXT_OBJECT_WARNING(EVENT_MANAGER));}}});return context;};/**\n * Updates rudder event object with data from the API options\n * @param rudderEvent Generated rudder event\n * @param options API options\n */const processOptions=(rudderEvent,options,logger)=>{// Only allow object type for options\nif(isObjectLiteralAndNotNull(options)){updateTopLevelEventElements(rudderEvent,options);// eslint-disable-next-line no-param-reassign\nrudderEvent.context=getMergedContext(rudderEvent.context,options,logger);}};/**\n * Returns the final integrations config for the event based on the global config and event's config\n * @param integrationsConfig Event's integrations config\n * @returns Final integrations config\n */const getEventIntegrationsConfig=integrationsConfig=>{let finalIntgConfig;if(state.loadOptions.value.useGlobalIntegrationsConfigInEvents){// Prefer the integrations object from the consent API response over the load API integrations object\nfinalIntgConfig=state.consents.postConsent.value.integrations??state.nativeDestinations.loadOnlyIntegrations.value;}else if(integrationsConfig){finalIntgConfig=integrationsConfig;}else {finalIntgConfig=DEFAULT_INTEGRATIONS_CONFIG;}return clone(finalIntgConfig);};/**\n * Enrich the base event object with data from state and the API options\n * @param rudderEvent RudderEvent object\n * @param options API options\n * @param pageProps Page properties\n * @param logger logger\n * @returns Enriched RudderEvent object\n */const getEnrichedEvent=(rudderEvent,options,pageProps,logger)=>{const commonEventData={channel:CHANNEL,context:{traits:clone(state.session.userTraits.value),sessionId:state.session.sessionInfo.value.id||undefined,sessionStart:state.session.sessionInfo.value.sessionStart||undefined,// Add 'consentManagement' only if consent management is enabled\n...(state.consents.enabled.value&&{consentManagement:{deniedConsentIds:clone(state.consents.data.value.de
1niedConsentIds),allowedConsentIds:clone(state.consents.data.value.allowedConsentIds),provider:state.consents.provider.value,resolutionStrategy:state.consents.resolutionStrategy.value}}),'ua-ch':state.context['ua-ch'].value,app:state.context.app.value,library:state.context.library.value,userAgent:state.context.userAgent.value,os:state.context.os.value,locale:state.context.locale.value,screen:state.context.screen.value,campaign:extractUTMParameters(globalThis.location.href),page:getContextPageProperties(pageProps),timezone:state.context.timezone.value,// Add auto tracking information\n...(state.autoTrack.enabled.value&&{autoTrack:{...(state.autoTrack.pageLifecycle.enabled.value&&{page:{pageViewId:state.autoTrack.pageLifecycle.pageViewId.value}})}})},originalTimestamp:getCurrentTimeFormatted(),messageId:generateUUID(),userId:rudderEvent.userId||state.session.userId.value};if(!isStorageTypeValidForStoringData(state.storage.entries.value.anonymousId?.type)){// Generate new anonymous id for each request\ncommonEventData.anonymousId=generateAnonymousId();}else {// Type casting to string as the user session manager will take care of initializing the value\ncommonEventData.anonymousId=state.session.anonymousId.value;}// set truly anonymous tracking flag\nif(state.storage.trulyAnonymousTracking.value){commonEventData.context.trulyAnonymousTracking=true;}if(rudderEvent.type==='identify'){commonEventData.context.traits=state.storage.entries.value.userTraits?.type!==NO_STORAGE?clone(state.session.userTraits.value):rudderEvent.context.traits;}if(rudderEvent.type==='group'){if(rudderEvent.groupId||state.session.groupId.value){commonEventData.groupId=rudderEvent.groupId||state.session.groupId.value;}if(rudderEvent.traits||state.session.groupTraits.value){commonEventData.traits=state.storage.entries.value.groupTraits?.type!==NO_STORAGE?clone(state.session.groupTraits.value):rudderEvent.traits;}}const processedEvent=mergeDeepRight(rudderEvent,commonEventData);// Set the default values for the event properties\n// matching with v1.1 payload\nif(processedEvent.event===undefined){processedEvent.event=null;}if(processedEvent.properties===undefined){processedEvent.properties=null;}processOptions(processedEvent,options,logger);checkForReservedElements(processedEvent,logger);// Update the integrations config for the event\nprocessedEvent.integrations=getEventIntegrationsConfig(processedEvent.integrations);return processedEvent;};\n\nclass RudderEventFactory{constructor(logger){this.logger=logger;}/**\n * Generate a 'page' event based on the user-input fields\n * @param category Page's category\n * @param name Page name\n * @param properties Page properties\n * @param options API options\n */generatePageEvent(category,name,properties,options){let props=properties??{};props=getUpdatedPageProperties(props,options);const pageEvent={properties:props,name,category,type:'page'};return getEnrichedEvent(pageEvent,options,props,this.logger);}/**\n * Generate a 'track' event based on the user-input fields\n * @param event The event name\n * @param properties Event properties\n * @param options API options\n */generateTrackEvent(event,properties,options){const trackEvent={properties,event,type:'track'};return getEnrichedEvent(trackEvent,options,undefined,this.logger);}/**\n * Generate an 'identify' event based on the user-input fields\n * @param userId New user ID\n * @param traits new traits\n * @param options API options\n */generateIdentifyEvent(userId,traits,options){const identifyEvent={userId,type:'identify',context:{traits}};return getEnrichedEvent(identifyEvent,options,undefined,this.logger);}/**\n * Generate an 'alias' event based on the user-input fields\n * @param to New user ID\n * @param from Old user ID\n * @param options API options\n */generateAliasEvent(to,from,options){const aliasEvent={previousId:from,type:'alias'};const enrichedEvent=getEnrichedEvent(aliasEvent,options,undefined,this.logger);// override the User ID from the API inputs\nenrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**\n * Generate a 'group' event based on the user-input fields\n * @param groupId New group ID\n * @param traits new group traits\n * @param options API options\n */generateGroupEvent(groupId,traits,options){const groupEvent={type:'group'};
1if(groupId){groupEvent.groupId=groupId;}if(traits){groupEvent.traits=traits;}return getEnrichedEvent(groupEvent,options,undefined,this.logger);}/**\n * Generates a new RudderEvent object based on the user-input fields\n * @param event API event parameters object\n * @returns A RudderEvent object\n */create(event){let eventObj;switch(event.type){case 'page':eventObj=this.generatePageEvent(event.category,event.name,event.properties,event.options);break;case 'track':eventObj=this.generateTrackEvent(event.name,event.properties,event.options);break;case 'identify':eventObj=this.generateIdentifyEvent(event.userId,event.traits,event.options);break;case 'alias':eventObj=this.generateAliasEvent(event.to,event.from,event.options);break;case 'group':default:eventObj=this.generateGroupEvent(event.groupId,event.traits,event.options);break;}return eventObj;}}\n\n/**\n * A service to generate valid event payloads and queue them for processing\n */class EventManager{/**\n *\n * @param eventRepository Event repository instance\n * @param userSessionManager UserSession Manager instance\n * @param errorHandler Error handler object\n * @param logger Logger object\n */constructor(eventRepository,userSessionManager,errorHandler,logger){this.eventRepository=eventRepository;this.userSessionManager=userSessionManager;this.errorHandler=errorHandler;this.logger=logger;this.eventFactory=new RudderEventFactory(this.logger);}/**\n * Initializes the event manager\n */init(){this.eventRepository.init();}resume(){this.eventRepository.resume();}/**\n * Consumes a new incoming event\n * @param event Incoming event data\n */addEvent(event){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event);this.eventRepository.enqueue(rudderEvent,event.callback);}}\n\nclass UserSessionManager{/**\n * Tracks whether a server-side cookie setting request is in progress or not.\n */constructor(pluginsManager,storeManager,httpClient,errorHandler,logger){this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.serverSideCookieDebounceFuncs={};this.serverSideCookiesRequestInProgress={};}/**\n * Initialize User session with values from storage\n */init(){this.syncStorageDataToState();// Register the effect to sync with storage\nthis.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again\nthis.setUserId(this.getUserId());this.setUserTraits(this.getUserTraits());this.setGroupId(this.getGroupId());this.setGroupTraits(this.getGroupTraits());const{externalAnonymousIdCookieName,anonymousIdOptions}=state.loadOptions.value;let externalAnonymousId;if(isDefinedAndNotNull(externalAnonymousIdCookieName)&&typeof externalAnonymousIdCookieName==='string'){externalAnonymousId=this.getExternalAnonymousIdByCookieName(externalAnonymousIdCookieName);}this.setAnonymousId(externalAnonymousId??this.getAnonymousId(anonymousIdOptions));this.setAuthToken(this.getAuthToken());this.setInitialReferrerInfo();this.configureSessionTracking();}configureSessionTracking(){let sessionInfo;if(this.isPersistenceEnabledForStorageEntry('sessionInfo')){const configuredSessionTrackingInfo=this.getConfiguredSessionTrackingInfo();const initialSessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;// Merge the session info from the storage and the configuration\nsessionInfo={// If manualTrack is set to true in the storage, then do not enable auto tracking even if configured.\n// Once manual tracking ends (endSession is called), auto tracking will be enabled in the next SDK run.\nautoTrack:configuredSessionTrackingInfo.autoTrack&&initialSessionInfo.manualTrack!==true,timeout:configuredSessionTrackingInfo.timeout,manualTrack:initialSessionInfo.manualTrack,expiresAt:initialSessionInfo.expiresAt,id:initialSessionInfo.id,sessionStart:initialSessionInfo.sessionStart};// If both autoTrack and manualTrack are disabled, reset the session info to default values\nif(!sessionInfo.autoTrack&&sessionInfo.manualTrack!==true){sessionInfo=DEFAULT_USER_SESSION_VALUES.sessionInfo;}else if(configuredSessionTrackingInfo.cutOff?.enabled===true){sessionInfo.cutOff={enabled:true,duration:configuredSessionTrackingInfo.cutOff.duration,expiresAt:initialSessionInfo.cutOff?.expiresAt};}}else {sessionInfo=DEFAULT_USER_SESSION_VALUES.sessionInfo;}state.session.sessionInfo.value=sessionInfo;// If auto session tracking is enabled start the session tracking\nif(state.session.sessionInfo.value.autoTrack){this.startOrRenewAutoTracking(state.session.sessionInfo.value);}}setInitialReferrerInfo(){const persistedInitialReferrer=this.getInitialReferrer();const persistedInitialReferringDomain=this.getInitialReferringDomain();if(persistedInitialReferrer&&persistedInitialReferringDomain){this.setInitialReferrer(persistedInitialReferrer);this.setInitialReferringDomain(persistedInitialReferringDomain);}else {const initialReferrer=persistedInitialReferrer||getReferrer();this.setInitialReferrer(initialReferrer);this.setInitialReferringDomain(getReferringDomain(initialReferrer));}}isPersistenceEnabledForStorageEntry(entryName){return isStorageTypeValidForStoringData(state.storage.entries.value[entryName]?.type);}migrateDataFromPreviousStorage(){const entries=state.storage.entries.value;const storageTypesForMigration=[COOKIE_STORAGE,LOCAL_STORAGE,SESSION_STORAGE];
1Object.keys(entries).forEach(entry=>{const key=entry;const currentStorage=entries[key]?.type;const curStore=this.storeManager?.getStore(storageClientDataStoreNameMap[currentStorage]);if(curStore){storageTypesForMigration.forEach(storage=>{const store=this.storeManager?.getStore(storageClientDataStoreNameMap[storage]);if(store&&storage!==currentStorage){const value=store.get(COOKIE_KEYS[key]);if(isDefinedNotNullAndNotEmptyString(value)){curStore.set(COOKIE_KEYS[key],value);}store.remove(COOKIE_KEYS[key]);}});}});}migrateStorageIfNeeded(stores,keys){if(!state.storage.migrate.value){return;}let storesToMigrate=stores??[];if(storesToMigrate.length===0){const persistentStoreNames=[CLIENT_DATA_STORE_COOKIE,CLIENT_DATA_STORE_LS,CLIENT_DATA_STORE_SESSION];persistentStoreNames.forEach(storeName=>{const store=this.storeManager?.getStore(storeName);if(store){storesToMigrate.push(store);}});}let keysToMigrate=keys??Object.keys(COOKIE_KEYS);keysToMigrate.forEach(storageKey=>{const storageEntry=COOKIE_KEYS[storageKey];storesToMigrate.forEach(store=>{const migratedVal=this.pluginsManager?.invokeSingle('storage.migrate',storageEntry,store.engine,this.errorHandler,this.logger);// Skip setting the value if it is null or undefined\n// as those values indicate there is no need for migration or\n// migration failed\nif(!isNullOrUndefined(migratedVal)){store.set(storageEntry,migratedVal);}});});}getConfiguredSessionTrackingInfo(){let autoTrack=state.loadOptions.value.sessions.autoTrack!==false;// Do not validate any further if autoTrack is disabled\nif(!autoTrack){return {autoTrack};}let timeout;const configuredSessionTimeout=state.loadOptions.value.sessions?.timeout;if(!isPositiveInteger(configuredSessionTimeout)){this.logger.warn(TIMEOUT_NOT_NUMBER_WARNING(USER_SESSION_MANAGER,configuredSessionTimeout,DEFAULT_SESSION_TIMEOUT_MS));timeout=DEFAULT_SESSION_TIMEOUT_MS;}else {timeout=configuredSessionTimeout;}if(timeout===0){this.logger.warn(TIMEOUT_ZERO_WARNING(USER_SESSION_MANAGER));autoTrack=false;}// In case user provides a timeout value greater than 0 but less than 10 seconds SDK will show a warning\n// and will proceed with it\nif(timeout>0&&timeout<MIN_SESSION_TIMEOUT_MS){this.logger.warn(TIMEOUT_NOT_RECOMMENDED_WARNING(USER_SESSION_MANAGER,timeout,MIN_SESSION_TIMEOUT_MS));}const cutOff=this.getCutOffInfo(timeout);return {timeout,autoTrack,cutOff};}getCutOffInfo(sessionTimeout){const cutOff=state.loadOptions.value.sessions.cutOff;let cutOffDuration;let cutOffEnabled=false;if(cutOff.enabled===true){cutOffDuration=cutOff.duration;cutOffEnabled=true;if(!isPositiveInteger(cutOffDuration)){this.logger.warn(CUT_OFF_DURATION_NOT_NUMBER_WARNING(USER_SESSION_MANAGER,cutOffDuration,DEFAULT_SESSION_CUT_OFF_DURATION_MS));// Use the default value for cut off duration\ncutOffDuration=DEFAULT_SESSION_CUT_OFF_DURATION_MS;}else if(cutOffDuration<sessionTimeout){this.logger.warn(CUT_OFF_DURATION_LESS_THAN_TIMEOUT_WARNING(USER_SESSION_MANAGER,cutOffDuration,sessionTimeout));cutOffEnabled=false;}}return {enabled:cutOffEnabled,duration:cutOffDuration};}/**\n * Handles error\n * @param error The error object\n */onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:USER_SESSION_MANAGER,customMessage,groupingHash});}/**\n * A function to encrypt the cookie value and return the encrypted data\n * @param cookiesData\n * @param store\n * @returns\n */getEncryptedCookieData(cookiesData,store){const encryptedCookieData=[];cookiesData.forEach(cData=>{const encryptedValue=store?.encrypt(stringifyWithoutCircular(cData.value,false,[],this.logger));if(isDefinedAndNotNull(encryptedValue)){encryptedCookieData.push({name:cData.name,value:encryptedValue});}});return encryptedCookieData;}/**\n * A function that makes request to data service to set the cookie\n * @param encryptedCookieData\n * @param callback\n */makeRequestToSetCookie(encryptedCookieData,callback){this.httpClient?.getAsyncData({url:state.serverCookies.dataServiceUrl.value,options:{method:'POST',data:stringifyWithoutCircular({reqType:'setCookies',workspaceId:state.source.value?.workspaceId,data:{options:{maxAge:state.storage.cookie.value?.maxage,path:state.storage.cookie.value?.path,domain:state.storage.cookie.value?.domain,sameSite:state.storage.cookie.value?.samesite,secure:state.storage.cookie.value?.secure,expires:state.storage.cookie.value?.expires},cookies:encryptedCookieData}}),sendRawData:true,withCredentials:true},isRawResponse:true,callback});}/**\n * A function to make an external request to set the cookie from server side\n * @param sessionToCookiesMap map of session key to cookie name\n * @param cb callback function to be called when the cookie is set\n * @param store store to be used to get the cookie value\n */setServerSideCookies(se
1ssionToCookiesMap,cb,store){// Retrieve the cookie value from the state\nconst sessionKeys=Object.keys(sessionToCookiesMap);const getCurrentCookieValuesFromState=()=>{return sessionKeys.map(sessionKey=>{return {name:sessionToCookiesMap[sessionKey].name,value:state.session[sessionKey].value};});};// Preserve the current cookie values\nconst originalCookieValues={};sessionKeys.forEach(sessionKey=>{originalCookieValues[sessionToCookiesMap[sessionKey].name]=store?.get(sessionToCookiesMap[sessionKey].name);});const clearInProgressFlags=()=>{sessionKeys.forEach(sessionKey=>{this.serverSideCookiesRequestInProgress[sessionKey]=false;});};const setCookiesClientSide=()=>{getCurrentCookieValuesFromState().forEach(each=>{if(cb){cb(each.name,each.value);}});};try{const expectedCookieValues={};sessionKeys.forEach(sessionKey=>{expectedCookieValues[sessionToCookiesMap[sessionKey].name]=state.session[sessionKey].value;});// encrypt cookies values\nconst encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side\nthis.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{// Mark the cookie req status as done\nclearInProgressFlags();if(details?.xhr?.status===200){getCurrentCookieValuesFromState().forEach(cData=>{const originalCookieVal=originalCookieValues[cData.name];const currentCookieVal=store?.get(cData.name);// Check if the expected cookie values are set.\nif(stringifyWithoutCircular(expectedCookieValues[cData.name],false,[])!==stringifyWithoutCircular(currentCookieVal,false,[])){// It's fine if the values don't match as other active SDK sessions might have updated the cookie values\n// or other cookie requests might have updated the cookie value.\n// Log an error only when cookie didn't exist previously and currently also doesn't exist.\nif(isNull(originalCookieVal)&&isNull(currentCookieVal)){this.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));}if(cb){cb(cData.name,cData.value);}}});}else {this.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status));setCookiesClientSide();}});}else {setCookiesClientSide();// Mark the cookie req status as done\nclearInProgressFlags();}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);setCookiesClientSide();// Mark the cookie req status as done\nclearInProgressFlags();}}/**\n * A function to sync values in storage\n * @param sessionKey\n */syncValueToStorage(sessionKey){const entries=state.storage.entries.value;const storageType=entries[sessionKey]?.type;if(isStorageTypeValidForStoringData(storageType)){const curStore=this.storeManager.getStore(storageClientDataStoreNameMap[storageType]);const cookieName=entries[sessionKey]?.key;const cookieValue=state.session[sessionKey].value;if(cookieValue&&(isString(cookieValue)||isNonEmptyObject(cookieValue))){// if useServerSideCookies load option is set to true\n// set the cookie from server side\nif(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.\nthis.serverSideCookiesRequestInProgress[sessionKey]=true;if(this.serverSideCookieDebounceFuncs[sessionKey]){globalThis.clearTimeout(this.serverSideCookieDebounceFuncs[sessionKey]);}this.serverSideCookieDebounceFuncs[sessionKey]=globalThis.setTimeout(()=>{// Create a map of session key to cookie name\nconst sessionToCookiesMap={[sessionKey]:{name:cookieName}};this.setServerSideCookies(sessionToCookiesMap,(cookieName,cookieValue)=>{curStore?.set(cookieName,cookieValue);},curStore);},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {curStore?.set(cookieName,cookieValue);}}else {curStore?.remove(cookieName);}}}/**\n * Function to update storage whenever state value changes\n */registerEffects(){// This will work as long as the user session entry key names are same as the state keys\nUSER_SESSION_KEYS.forEach(sessionKey=>{j(()=>{this.syncValueToStorage(sessionKey);});});}/**\n * Sets anonymous id in the following precedence:\n *\n * 1. anonymousId: Id directly provided to the function.\n * 2. rudderAmpLinkerParam
1: value generated from linker query parm (rudderstack)\n * using parseLinker util.\n * 3. generateUUID: A new unique id is generated and assigned.\n */setAnonymousId(anonymousId,rudderAmpLinkerParam){let finalAnonymousId=anonymousId;if(!isString(anonymousId)||!finalAnonymousId){finalAnonymousId=undefined;}if(this.isPersistenceEnabledForStorageEntry('anonymousId')){if(!finalAnonymousId&&rudderAmpLinkerParam){const linkerPluginsResult=this.pluginsManager?.invokeSingle('userSession.anonymousIdGoogleLinker',rudderAmpLinkerParam);finalAnonymousId=linkerPluginsResult;}finalAnonymousId=finalAnonymousId||generateAnonymousId();}else {finalAnonymousId=DEFAULT_USER_SESSION_VALUES.anonymousId;}state.session.anonymousId.value=finalAnonymousId;}/**\n * Fetches anonymousId\n * @param options option to fetch it from external source\n * @returns anonymousId\n */getAnonymousId(options){const storage=state.storage.entries.value.anonymousId?.type;if(isStorageTypeValidForStoringData(storage)){let persistedAnonymousId=state.session.anonymousId.value;// If the anonymous ID is the default value, fetch it from storage\nif(!persistedAnonymousId||persistedAnonymousId===DEFAULT_USER_SESSION_VALUES.anonymousId){persistedAnonymousId=this.getEntryValue('anonymousId');}if(!persistedAnonymousId&&options){// fetch anonymousId from external source\nconst autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnonymousId',getStorageEngine,options);persistedAnonymousId=autoCapturedAnonymousId;}state.session.anonymousId.value=persistedAnonymousId||generateAnonymousId();}return state.session.anonymousId.value;}getEntryValue(sessionKey){const entries=state.storage.entries.value;const storageType=entries[sessionKey]?.type;if(isStorageTypeValidForStoringData(storageType)){const store=this.storeManager?.getStore(storageClientDataStoreNameMap[storageType]);// Migrate the storage data before fetching the value\n// This is needed for entries that are fetched from the storage\n// during the current session (for example, session info)\nthis.migrateStorageIfNeeded([store],[sessionKey]);const storageKey=entries[sessionKey]?.key;return store?.get(storageKey)??null;}return null;}getExternalAnonymousIdByCookieName(key){const storageEngine=getStorageEngine(COOKIE_STORAGE);if(storageEngine?.isEnabled){return storageEngine.getItem(key)??null;}return null;}/**\n * Fetches the value for a session key. Preferably from storage, if the server-side\n * cookies request is not in progress. Otherwise, from the state.\n * @param sessionKey - The session key to fetch the value for\n * @returns - The value for the session key\n */getUserSessionValue(sessionKey){// If the server-side cookies request is in progress, fetch the value from the state.\nif(this.serverSideCookiesRequestInProgress[sessionKey]){return state.session[sessionKey].value;}// Otherwise, fetch the value from storage.\nreturn this.getEntryValue(sessionKey);}/**\n * Fetches User Id\n * @returns\n */getUserId(){return this.getUserSessionValue('userId');}/**\n * Fetches User Traits\n * @returns\n */getUserTraits(){return this.getUserSessionValue('userTraits');}/**\n * Fetches Group Id\n * @returns\n */getGroupId(){return this.getUserSessionValue('groupId');}/**\n * Fetches Group Traits\n * @returns\n */getGroupTraits(){return this.getUserSessionValue('groupTraits');}/**\n * Fetches Initial Referrer\n * @returns\n */getInitialReferrer(){return this.getUserSessionValue('initialReferrer');}/**\n * Fetches Initial Referring domain\n * @returns\n */getInitialReferringDomain(){return this.getUserSessionValue('initialReferringDomain');}/**\n * Fetches session tracking information from storage\n * @returns\n */getSessionInfo(){return this.getUserSessionValue('sessionInfo');}/**\n * Fetches auth token from storage\n * @returns\n */getAuthToken(){return this.getUserSessionValue('authToken');}/**\n * If session is active it returns the sessionId\n * @returns\n */getSessionId(){const sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo)||sessionInfo.manualTrack){return sessionInfo.id??null;}return null;}/**\n * A function to keep the session information up to date in the state\n * before using it for building event payloads.\n */refreshSession(){let sessionInfo=this.getSessionInfo()??DEFAULT_USER_SESSION_VALUES.sessionInfo;if(sessionInfo.autoTrack||sessionInfo.manualTrack){if(sessionInfo.autoTrack){this.startOrRenewAutoTracking(sessionInfo);sessionInfo=state.session.sessionInfo.value;}// Note that if sessionStart is false, then it's an active session.\n// So, we needn't update the session info.\n//\n// For other scenarios,\n// 1. If sessionStart is undefined, then it's a new session.\n// Mark it as sessionStart.\n// 2. If sessionStart is true, then need to flip it for the future events.\nif(sessionInfo.sessionStart===undefined){sessionInfo={...sessionInfo,sessionStart:true};}else if(sessionInfo.sessionStart){sessionInfo={...sessionInfo,sessionStart:false};}}// Always write to state (in-turn to storage) to keep the session info up to date.\nstate.session.sessionInfo.value=sessionInfo;if(state.lifecycle.status.value!=='readyExecuted'){// Force update the storage as the 'effect' blocks are not getting triggered\n// when processing preload buffered requests\nthis.syncValueToStorage('sessionInfo');}}resetAndStartNewSession(){const session=state.session;const{manualTrack,autoTrack,timeout,cutOff}=session.sessionInfo.value;if(autoTrack){const sessionInfo={...DEFAULT_USER_SESSION_VALUES.sessionInfo,timeout};if(cutOff){sessionInfo.cutOff={enabled:cutOff.enabled,duration:cutOff.duration};}session.sessionInfo.value=sessionInfo;this.startOrRenewAutoTracking(session.sessionInfo.value);}else if(manualTrack){this.startManualTrackingInternal();}}/**\n * Reset state values\n * @param options options for reset\n * @returns\n */reset(options){const{session}=state;const opts=getFinalResetOptions(options);n(()=>
1{Object.keys(DEFAULT_USER_SESSION_VALUES).forEach(key=>{const userSessionKey=key;if(opts.entries[userSessionKey]!==true){return;}switch(key){case 'anonymousId':this.setAnonymousId();break;case 'sessionInfo':this.resetAndStartNewSession();break;default:session[userSessionKey].value=DEFAULT_USER_SESSION_VALUES[userSessionKey];break;}});});}/**\n * Set user Id\n * @param userId\n */setUserId(userId){state.session.userId.value=this.isPersistenceEnabledForStorageEntry('userId')&&userId?userId:DEFAULT_USER_SESSION_VALUES.userId;}/**\n * Set user traits\n * @param traits\n */setUserTraits(traits){state.session.userTraits.value=this.isPersistenceEnabledForStorageEntry('userTraits')&&isObjectLiteralAndNotNull(traits)?mergeDeepRight(state.session.userTraits.value??DEFAULT_USER_SESSION_VALUES.userTraits,traits):DEFAULT_USER_SESSION_VALUES.userTraits;}/**\n * Set group Id\n * @param groupId\n */setGroupId(groupId){state.session.groupId.value=this.isPersistenceEnabledForStorageEntry('groupId')&&groupId?groupId:DEFAULT_USER_SESSION_VALUES.groupId;}/**\n * Set group traits\n * @param traits\n */setGroupTraits(traits){state.session.groupTraits.value=this.isPersistenceEnabledForStorageEntry('groupTraits')&&isObjectLiteralAndNotNull(traits)?mergeDeepRight(state.session.groupTraits.value??DEFAULT_USER_SESSION_VALUES.groupTraits,traits):DEFAULT_USER_SESSION_VALUES.groupTraits;}/**\n * Set initial referrer\n * @param referrer\n */setInitialReferrer(referrer){state.session.initialReferrer.value=this.isPersistenceEnabledForStorageEntry('initialReferrer')&&referrer?referrer:DEFAULT_USER_SESSION_VALUES.initialReferrer;}/**\n * Set initial referring domain\n * @param {String} referringDomain\n */setInitialReferringDomain(referringDomain){state.session.initialReferringDomain.value=this.isPersistenceEnabledForStorageEntry('initialReferringDomain')&&referringDomain?referringDomain:DEFAULT_USER_SESSION_VALUES.initialReferringDomain;}/**\n * A function to check for existing session details and depending on that create a new session\n */startOrRenewAutoTracking(sessionInfo){let finalSessionInfo=sessionInfo;if(hasSessionExpired(sessionInfo)){finalSessionInfo=generateAutoTrackingSession(sessionInfo);}else {const timestamp=Date.now();const timeout=sessionInfo.timeout;// Set the expiry time of the session\nfinalSessionInfo.expiresAt=timestamp+timeout;}// Reset cut off expiry timestamp if it is exceeded\nif(isCutOffTimeExceeded(finalSessionInfo)){finalSessionInfo.cutOff.expiresAt=undefined;}// If cut off is active, set or retain the expiry time\nif(finalSessionInfo.cutOff){const cutOffExpiresAt=getCutOffExpirationTimestamp(finalSessionInfo.cutOff);finalSessionInfo.cutOff.expiresAt=cutOffExpiresAt;}// Update the session info in the state\nstate.session.sessionInfo.value=finalSessionInfo;}/**\n * A function method to start a manual session\n * @param {number} id session identifier\n * @returns\n */start(id){state.session.sessionInfo.value=generateManualTrackingSession(id,this.logger);}/**\n * An internal function to start manual session\n */startManualTrackingInternal(){this.start(Date.now());}/**\n * A public method to end an ongoing session.\n */end(){state.session.sessionInfo.value=DEFAULT_USER_SESSION_VALUES.sessionInfo;}/**\n * Set auth token\n * @param userId\n */setAuthToken(token){state.session.authToken.value=this.isPersistenceEnabledForStorageEntry('authToken')&&token?token:DEFAULT_USER_SESSION_VALUES.authToken;}}\n\n/**\n * Plugins to be loaded in the plugins loadOption is not defined\n */const allOptionalPlugins=['BeaconQueue','CustomConsentManager','DeviceModeDestinations','DeviceModeTransformation','ExternalAnonymousId','GoogleLinker','IubendaConsentManager','KetchConsentManager','NativeDestinationQueue','OneTrustConsentManager','StorageEncryption','StorageEncryptionLegacy','StorageMigrator','XhrQueue'];// Plugins excluded from lite builds which are also not connected to any SDK configuration options\nconst defaultOptionalPluginsList=allOptionalPlugins;\n\nconst normalizeLoadOptions=(loadOptionsFromState,loadOptions)=>{// TODO: Maybe add warnings for invalid values\nconst normalizedLoadOpts=clone(loadOptions);if(!isString(normalizedLoadOpts.setCookieDomain)){normalizedLoadOpts.setCookieDomain=undefined;}const cookieSameSiteValues=['Strict','Lax','None'];if(!cookieSameSiteValues.includes(normalizedLoadOpts.sameSiteCookie)){normalizedLoadOpts.sameSiteCookie=undefined;}normalizedLoadOpts.secureCookie=getNormalizedBooleanValue(normalizedLoadOpts.secureCookie,loadOptionsFromState.secureCookie);normalizedLoadOpts.sameDomainCookiesOnly=getNormalizedBooleanValue(normalizedLoadOpts.sameDomainCookiesOnly,loadOptionsFromState.sameDomainCookiesOnly);const uaChTrackLevels=['none','default','full'];if(!uaChTrackLevels.includes(normalizedLoadOpts.uaChTrackLevel)){normalizedLoadOpts.uaChTrackLevel=undefined;}normalizedLoadOpts.integrations=getNormalizedObjectValue(normalizedLoadOpts.integrations);if(!Array.isArray(normalizedLoadOpts.plugins)){normalizedLoadOpts.plugins=defaultOptionalPluginsList;}normalizedLoadOpts.useGlobalIntegrationsConfigInEvents=getNormalizedBooleanValue(normalizedLoadOpts.useGlobalIntegrationsConfigInEvents,loadOptionsFromState.useGlobalIntegrationsConfigInEvents);normalizedLoadOpts.bufferDataPlaneEventsUntilReady=getNormalizedBooleanValue(normalizedLoadOpts.bufferDataPlaneEventsUntilReady,loadOptionsFromState.bufferDataPlaneEventsUntilReady);normalizedLoadOpts.sendAdblockPage=getNormalizedBooleanValue(normalizedLoadOpts.sendAdblockPage,loadOptionsFromState.sendAdblockPage);normalizedLoadOpts.useServerSideCookies=getNormalizedBooleanValue(normalizedLoadOpts.useServerSideCookies,loadOptionsFromState.useServerSideCookies);if(!isString(normalizedLoadOpts.dataServiceEndpoint)){normalizedLoadOpts.dataServiceEndpoint=undefined;}normalizedLoadOpts.sendAdblockPageOptions=getNormalizedObjectValue(normalizedLoadOpts.sendAdblockPageOptions);normalizedLoadOpts.loadIntegration=getNormalizedBooleanValue(normalizedLoadOpts.loadIntegration,loadOptionsFromState.loadIntegration);if(!isNonEmptyObject(normalizedLoadOpts.storage)){normalizedLoadOpts.storage=undefined;}else {normalizedLoadOpts.storage.migrate=getNormalizedBooleanValue(normalizedLoadOpts.storage.migrate,loadOptionsFromState.storage?.migrate);normalizedLoadOpts.storage.cookie=getNormalizedObjectValue(normalizedLoadOpts.storage.cookie);normalizedLoadOpts.storage.encryption=getNormalizedObjectValue(normalizedLoadOpts.storage.encryption);normalizedLoadOpts.storage=removeUndefinedAndNullValues(normalizedLoadOpts.storage);}normalizedLoadOpts.destinationsQueueOptions=getNormalizedObjectValue(normalizedLoadOpts.destinationsQueueOptions);normalizedLoadOpts.queueOptions=getNormalizedObjectValue(normalizedLoadOpts.queueOptions);normalizedLoadOpts.lockIntegrationsVersion=getNormalizedBooleanValue(normalizedLoadOpts.lockIntegrationsVersion,loadOptionsFromState.lockIntegrationsVersion);normalizedLoadOpts.lockPluginsVersion=getNormalizedBooleanValue(normalizedLoadOpts.lockPluginsVersion,loadOptionsFromState.lockPluginsVersion);if(!isNumber(normalizedLoadOpts.dataPlaneEventsBufferTimeout)){normalizedLoadOpts.dataPlaneEventsBufferTimeout=undefined;}normalizedLoadOpts.beaconQueueOptions=getNormalizedObjectValue(normalizedLoadOpts.beaconQueueOptions);normalizedLoadOpts.preConsent=getNormalizedObjectValue(normalizedLoadOpts.preConsent);normalizedLoadOpts.sourceConfigurationOverride=getNormalizedObjectValue(normalizedLoadOpts.sourceConfigurationOverride);const mergedLoadOptions=mergeDeepRight(loadOptionsFromState,removeUndefinedAndNullValues(normalizedLoadOpts));return mergedLoadOptions;};\n\nconst DATA_PLANE_QUEUE_EXT_POINT_PREFIX='dataplaneEventsQueue';const DESTINATIONS_QUEUE_EXT_POINT_PREFIX='destinationsEventsQueue';const DMT_EXT_POINT_PREFIX='transformEvent';\n\n/**\n * Filters and returns the user supplied integrations config that should take preference over the destination specific integrations config\n * @param eventIntgConfig User supplied integrations config at event level\n * @param destinationsIntgConfig Cumulative integrations config from all destinations\n * @returns Filtered user supplied integrations config\n */const getOverriddenIntegrationOptions=(eventIntgConfig,destinationsIntgConfig)=>Object.keys(eventIntgConfig).filter(intgName=>eventIntgConfig[intgName]!==true||!destinationsIntgConfig[intgName]).reduce((obj,key)=>{const retVal=clone(obj);retVal[key]=eventIntgConfig[key];return retVal;},{});/**\n * Returns the event object with final integrations config\n * @param event RudderEvent object\n * @param state Application state\n * @returns Mutated event with final integrations config\n */const getFinalEvent=(event,state)=>{const finalEvent=clone(event);// Merge the destination specific integrations config with the event's integrations config\n// In general, the preference is given to the event's integrations config\nconst destinationsIntgConfig=state.nativeDestinations.integrationsConfig.value;const overriddenIntgOpts=getOverriddenIntegrationOptions(event.integrations,destinationsIntgConfig);finalEvent.integrations=mergeDeepRight(destinationsIntgConfig,overriddenIntgOpts);return finalEvent;};const shouldBufferEventsForPreConsent=state=>state.consents.preConsent.value.enabled&&state.consents.preConsent.value.events?.delivery==='buffer';\n\nconst safelyInvokeCallback=(callback,args,apiName,logger)=>{if(!isDefined(callback)){return;}if(isFunction(callback)){try{callback(...args);}catch(error){logger.error(CALLBACK_INVOKE_ERROR(apiName),error);}}else {logger.error(INVALID_CALLBACK_FN_ERROR(apiName));}};\n\n/**\n * Event repository class responsible for queuing events for further processing and delivery\n */class EventRepository{/**\n *\n * @param pluginsManager Plugins manager instance\n * @param storeManager Store Manager instance\n * @param errorHandler Error handler object\n * @param logger Logger object\n */constructor(pluginsManager,storeManager,httpClient,errorHandler,logger){this.pluginsManager=pluginsManager;this.errorHandler=errorHandler;this.httpClient=httpClient;this.logger=logger;this.storeManager=storeManager;}/**\n * Initializes the event repository\n */init(){this.dataplaneEventsQueue=this.pluginsManager.invokeSingle(`${DATA_PLANE_QUEUE_EXT_POINT_PREFIX}.init`,state,this.httpClient,this.storeManager,this.errorHandler,this.logger);this.dmtEventsQueue=this.pluginsManager.invokeSingle(`${DMT_EXT_POINT_PREFIX}.init`,state,this.pluginsManager,this.httpClient,this.storeManager,this.errorHandler,this.logger);this.destinationsEventsQueue=this.pluginsManager.invokeSingle(`${DESTINATIONS_QUEUE_EXT_POINT_PREFIX}.init`,state,this.pluginsManager,this.storeManager,this.dmtEventsQueue,this.errorHandler,this.logger);// Start the queue once the client destinations are ready\nj(()=>
1{if(state.nativeDestinations.clientDestinationsReady.value===true){this.destinationsEventsQueue?.start();this.dmtEventsQueue?.start();}});const bufferEventsBeforeConsent=shouldBufferEventsForPreConsent(state);// Start the queue processing only when the destinations are ready or hybrid mode destinations exist\n// However, events will be enqueued for now.\n// At the time of processing the events, the integrations config data from destinations\n// is merged into the event object\nlet timeoutId;j(()=>{const shouldBufferDpEvents=state.loadOptions.value.bufferDataPlaneEventsUntilReady===true&&state.nativeDestinations.clientDestinationsReady.value===false;const hybridDestExist=state.nativeDestinations.activeDestinations.value.some(dest=>isHybridModeDestination(dest));if((hybridDestExist===false||shouldBufferDpEvents===false)&&!bufferEventsBeforeConsent&&this.dataplaneEventsQueue?.scheduleTimeoutActive!==true){globalThis.clearTimeout(timeoutId);this.dataplaneEventsQueue?.start();}});// Force start the data plane events queue processing after a timeout\nif(state.loadOptions.value.bufferDataPlaneEventsUntilReady===true){timeoutId=globalThis.setTimeout(()=>{if(this.dataplaneEventsQueue?.scheduleTimeoutActive!==true){this.dataplaneEventsQueue?.start();}},state.loadOptions.value.dataPlaneEventsBufferTimeout);}}resume(){if(this.dataplaneEventsQueue?.scheduleTimeoutActive!==true){if(state.consents.postConsent.value.discardPreConsentEvents){this.dataplaneEventsQueue?.clear();this.destinationsEventsQueue?.clear();}this.dataplaneEventsQueue?.start();}}/**\n * Enqueues the event for processing\n * @param event RudderEvent object\n * @param callback API callback function\n */enqueue(event,callback){const dpQEvent=getFinalEvent(event,state);this.pluginsManager.invokeSingle(`${DATA_PLANE_QUEUE_EXT_POINT_PREFIX}.enqueue`,state,this.dataplaneEventsQueue,dpQEvent,this.errorHandler,this.logger);const dQEvent=clone(event);this.pluginsManager.invokeSingle(`${DESTINATIONS_QUEUE_EXT_POINT_PREFIX}.enqueue`,state,this.destinationsEventsQueue,dQEvent,this.errorHandler,this.logger);// Invoke the callback if it exists\nconst apiName=`${event.type.charAt(0).toUpperCase()}${event.type.slice(1)}${API_SUFFIX}`;safelyInvokeCallback(callback,[dpQEvent],apiName,this.logger);}}\n\nconst dispatchSDKEvent=event=>{const customEvent=new CustomEvent(event,{detail:{analyticsInstance:globalThis.rudderanalytics},bubbles:true,cancelable:true,composed:true});globalThis.document.dispatchEvent(customEvent);};const isWriteKeyValid=writeKey=>isString(writeKey)&&writeKey.trim().length>0;const isDataPlaneUrlValid=dataPlaneUrl=>isValidURL(dataPlaneUrl);\n\n/*\n * Analytics class with lifecycle based on state ad user triggered events\n */class Analytics{/**\n * Initialize services and components or use default ones if singletons\n */constructor(){this.preloadBuffer=new BufferQueue();this.initialized=false;this.errorHandler=defaultErrorHandler;this.logger=defaultLogger;this.externalSrcLoader=new ExternalSrcLoader(this.logger);this.httpClient=defaultHttpClient;this.httpClient.init(this.errorHandler);this.capabilitiesManager=new CapabilitiesManager(this.httpClient,this.errorHandler,this.logger);}/**\n * Start application lifecycle if not already started\n */load(writeKey,dataPlaneUrl,loadOptions={}){if(state.lifecycle.status.value){return;}if(!isWriteKeyValid(writeKey)){this.logger.error(WRITE_KEY_VALIDATION_ERROR(ANALYTICS_CORE,writeKey));return;}if(!isDataPlaneUrlValid(dataPlaneUrl)){this.logger.error(DATA_PLANE_URL_VALIDATION_ERROR(ANALYTICS_CORE,dataPlaneUrl));return;}// Set initial state values\nn(()=>{state.lifecycle.writeKey.value=clone(writeKey);state.lifecycle.dataPlaneUrl.value=clone(dataPlaneUrl);state.loadOptions.value=normalizeLoadOptions(state.loadOptions.value,loadOptions);state.lifecycle.status.value='mounted';});// set log level as early as possible\nthis.logger.setMinLogLevel(state.loadOptions.value.logLevel??POST_LOAD_LOG_LEVEL);// Expose state to global objects\nsetExposedGlobal('state',state,writeKey);// Configure initial config of any services or components here\n// State application lifecycle\nthis.startLifecycle();}// Start lifecycle methods\n/**\n * Orchestrate the lifecycle of the application phases/status\n */startLifecycle(){j(()=>{try{switch(state.lifecycle.status.value){case 'mounted':this.onMounted();break;case 'browserCapabilitiesReady':this.onBrowserCapabilitiesReady();break;case 'configured':this.onConfigured();break;case 'pluginsLoading':break;case 'pluginsReady':this.onPluginsReady();break;case 'initialized':this.onInitialized();break;case 'loaded':this.onLoaded();break;case 'destinationsLoading':break;case 'destinationsReady':this.onDestinationsReady();break;case 'ready':this.onReady();break;case 'readyExecuted':default:break;}}catch(err){const issue='Failed to load the SDK';this.errorHandler.onError({error:err,context:ANALYTICS_CORE,customMessage:issue,groupingHash:issue});}});}onBrowserCapabilitiesReady(){// initialize the preloaded events enqueuing\nretrievePreloadBufferEvents(this);this.prepareInternalServices();this.loadConfig();}onLoaded(){this.processBufferedEvents();// Short-circuit the life cycle and move to the ready state if pre-consent behavior is enabled\nif(state.consents.preConsent.value.enabled===true){state.lifecycle.status.value='ready';}else {this.loadDestinations();}}/**\n * Load browser polyfill if required\n */onMounted(){this.capabilitiesManager.init();}/**\n * Enqueue in SDK preload buffer events, used from preloadBuffer component\n */enqueuePreloadBufferEvents(bufferedEvents){if(Array.isArray(bufferedEvents)){bufferedEvents.forEac
1h(bufferedEvent=>this.preloadBuffer.enqueue(clone(bufferedEvent)));}}/**\n * Process the buffer preloaded events by passing their arguments to the respective facade methods\n */processDataInPreloadBuffer(){while(this.preloadBuffer.size()>0){const eventToProcess=this.preloadBuffer.dequeue();if(eventToProcess){consumePreloadBufferedEvent([...eventToProcess],this);}}}prepareInternalServices(){this.pluginsManager=new PluginsManager(defaultPluginEngine,this.errorHandler,this.logger);this.storeManager=new StoreManager(this.pluginsManager,this.errorHandler,this.logger);this.configManager=new ConfigManager(this.httpClient,this.errorHandler,this.logger);this.userSessionManager=new UserSessionManager(this.pluginsManager,this.storeManager,this.httpClient,this.errorHandler,this.logger);this.eventRepository=new EventRepository(this.pluginsManager,this.storeManager,this.httpClient,this.errorHandler,this.logger);this.eventManager=new EventManager(this.eventRepository,this.userSessionManager,this.errorHandler,this.logger);}/**\n * Load configuration\n */loadConfig(){if(state.lifecycle.writeKey.value){this.httpClient.setAuthHeader(state.lifecycle.writeKey.value);}this.configManager?.init();}/**\n * Initialize the storage and event queue\n */onPluginsReady(){// Initialize storage\nthis.storeManager?.init();this.userSessionManager?.init();// Initialize the appropriate consent manager plugin\nif(state.consents.enabled.value&&!state.consents.initialized.value){this.pluginsManager?.invokeSingle(`consentManager.init`,state,this.logger);if(state.consents.preConsent.value.enabled===false){this.pluginsManager?.invokeSingle(`consentManager.updateConsentsInfo`,state,this.storeManager,this.logger);}}// Initialize event manager\nthis.eventManager?.init();// Mark the SDK as initialized\nstate.lifecycle.status.value='initialized';}/**\n * Load plugins\n */onConfigured(){this.pluginsManager?.init();// TODO: are we going to enable custom plugins to be passed as load options?\n// registerCustomPlugins(state.loadOptions.value.customPlugins);\n}/**\n * Trigger onLoaded callback if any is provided in config & emit initialised event\n */onInitialized(){// Process any preloaded events\nthis.processDataInPreloadBuffer();// Set lifecycle state\nn(()=>{state.lifecycle.loaded.value=true;state.lifecycle.status.value='loaded';});this.initialized=true;// Execute onLoaded callback if provided in load options\nconst onLoadedCallbackFn=state.loadOptions.value.onLoaded;// TODO: we need to avoid passing the window object to the callback function\n// as this will prevent us from supporting multiple SDK instances in the same page\nsafelyInvokeCallback(onLoadedCallbackFn,[globalThis.rudderanalytics],LOAD_API,this.logger);// Emit an event to use as substitute to the onLoaded callback\ndispatchSDKEvent('RSA_Initialised');}/**\n * Emit ready event\n */// eslint-disable-next-line class-methods-use-this\nonReady(){state.lifecycle.status.value='readyExecuted';state.eventBuffer.readyCallbacksArray.value.forEach(callback=>{safelyInvokeCallback(callback,[],READY_API,this.logger);});// Emit an event to use as substitute to the ready callback\ndispatchSDKEvent('RSA_Ready');}/**\n * Consume preloaded events buffer\n */processBufferedEvents(){// This logic has been intentionally implemented without a simple\n// for-loop as the individual events that are processed may\n// add more events to the buffer (this is needed for the consent API)\nlet bufferedEvents=state.eventBuffer.toBeProcessedArray.value;while(bufferedEvents.length>0){const bufferedEvent=bufferedEvents.shift();state.eventBuffer.toBeProcessedArray.value=bufferedEvents;if(bufferedEvent){const methodName=bufferedEvent[0];if(isFunction(this[methodName])){// Send additional arg 'true' to indicate that this is a buffered invocation\nthis[methodName](...bufferedEvent.slice(1),true);}}bufferedEvents=state.eventBuffer.toBeProcessedArray.value;}}/**\n * Load device mode destinations\n */loadDestinations(){// If the integrations load is already triggered or completed, skip the rest of the logic\nif(state.lifecycle.status.value==='destinationsLoading'||state.nativeDestinations.clientDestinationsReady.value===true){return;}// Set in state the desired activeDestinations to inject in DOM\nthis.pluginsManager?.invokeSingle('nativeDestinations.setActiveDestinations',state,this.pluginsManager,this.errorHandler,this.logger);const totalDestinationsToLoad=state.nativeDestinations.activeDestinations.value.length;if(totalDestinationsToLoad===0){n(()=>{state.nativeDestinations.clientDestinationsReady.value=true;state.lifecycle.status.value='destinationsReady';});return;}// Start loading native integration scripts and create instances\nstate.lifecycle.status.value='destinationsLoading';this.pluginsManager?.invokeSingle('nativeDestinations.load',state,this.externalSrcLoader,this.errorHandler,this.logger);// Progress to next lifecycle phase if all native destinations are initialized or failed\nj(()=>{const areAllDestinationsReady=state.nativeDestinations.initializedDestinations.value.length+state.nativeDestinations.failedDestinations.value.length===totalDestinationsToLoad;if(areAllDestinationsReady){n(()=>{state.lifecycle.status.value='destinationsReady';state.nativeDestinations.clientDestinationsReady.value=true;});}});}/**\n * Move to the ready state\n */// eslint-disable-next-line class-methods-use-this\nonDestinationsReady(){// May be do any destination specific actions here\n// Mar
1k the ready status if not already done\nif(state.lifecycle.status.value!=='ready'){n(()=>{state.lifecycle.status.value='ready';});}}// End lifecycle methods\n// Start consumer exposed methods\nready(callback,isBufferedInvocation=false){const type='ready';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,callback]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);if(!isFunction(callback)){this.logger.error(INVALID_CALLBACK_FN_ERROR(READY_API));return;}/**\n * If destinations are loaded or no integration is available for loading\n * execute the callback immediately else push the callbacks to a queue that\n * will be executed after loading completes\n */if(state.lifecycle.status.value==='readyExecuted'){safelyInvokeCallback(callback,[],READY_API,this.logger);}else {state.eventBuffer.readyCallbacksArray.value=[...state.eventBuffer.readyCallbacksArray.value,callback];}}page(payload,isBufferedInvocation=false){const type='page';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;this.eventManager?.addEvent({type:'page',category:payload.category,name:payload.name,properties:payload.properties,options:payload.options,callback:payload.callback});// TODO: Maybe we should alter the behavior to send the ad-block page event even if the SDK is still loaded. It'll be pushed into the to be processed queue.\n// Send automatic ad blocked page event if ad-blockers are detected on the page\n// Check page category to avoid infinite loop\nif(state.capabilities.isAdBlocked.value===true&&payload.category!==ADBLOCK_PAGE_CATEGORY){this.page(pageArgumentsToCallOptions(ADBLOCK_PAGE_CATEGORY,ADBLOCK_PAGE_NAME,{// 'title' is intentionally omitted as it does not make sense\n// in v3 implementation\npath:ADBLOCK_PAGE_PATH},state.loadOptions.value.sendAdblockPageOptions));}}track(payload,isBufferedInvocation=false){const type='track';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event - ${payload.name}`);state.metrics.triggered.value+=1;this.eventManager?.addEvent({type,name:payload.name||undefined,properties:payload.properties,options:payload.options,callback:payload.callback});}identify(payload,isBufferedInvocation=false){const type='identify';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;const shouldResetSession=Boolean(payload.userId&&state.session.userId.value&&payload.userId!==state.session.userId.value);if(shouldResetSession){this.reset();}// `null` value indicates that previous user ID needs to be retained\nif(!isNull(payload.userId)){this.userSessionManager?.setUserId(payload.userId);}this.userSessionManager?.setUserTraits(payload.traits);this.eventManager?.addEvent({type,userId:payload.userId,traits:payload.traits,options:payload.options,callback:payload.callback});}alias(payload,isBufferedInvocation=false){const type='alias';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;const previousId=payload.from??(this.getUserId()||this.userSessionManager?.getAnonymousId());this.eventManager?.addEvent({type,to:payload.to,from:previousId,options:payload.options,callback:payload.callback});}group(payload,isBufferedInvocation=false){const type='group';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;// `null` value indicates that previous group ID needs to be retained\nif(!isNull(payload.groupId)){this.userSessionManager?.setGroupId(payload.groupId);}this.userSessionManager?.setGroupTraits(payload.traits);this.eventManager?.addEvent({type,groupId:payload.groupId,traits:payload.traits,options:payload.options,callback:payload.callback});}reset(options,isBufferedInvocation=false){const type='reset';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,options]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);this.userSessionManager?.reset(options);}getAnonymousId(options){return this.userSessionManager?.getAnonymousId(options);}setAnonymousId(anonymousId,rudderAmpLinkerParam,isBufferedInvocation=false){const type='setAnonymousId';
1// Buffering is needed as setting the anonymous ID may require invoking the GoogleLinker plugin\nif(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,anonymousId,rudderAmpLinkerParam]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);this.userSessionManager?.setAnonymousId(anonymousId,rudderAmpLinkerParam);}// eslint-disable-next-line class-methods-use-this\ngetUserId(){return state.session.userId.value;}// eslint-disable-next-line class-methods-use-this\ngetUserTraits(){return state.session.userTraits.value;}// eslint-disable-next-line class-methods-use-this\ngetGroupId(){return state.session.groupId.value;}// eslint-disable-next-line class-methods-use-this\ngetGroupTraits(){return state.session.groupTraits.value;}startSession(sessionId,isBufferedInvocation=false){const type='startSession';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,sessionId]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);this.userSessionManager?.start(sessionId);}endSession(isBufferedInvocation=false){const type='endSession';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);this.userSessionManager?.end();}// eslint-disable-next-line class-methods-use-this\ngetSessionId(){const sessionId=this.userSessionManager?.getSessionId();return sessionId??null;}consent(options,isBufferedInvocation=false){const type='consent';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,options]];return;}this.errorHandler.leaveBreadcrumb(`New consent invocation`);n(()=>{state.consents.preConsent.value={...state.consents.preConsent.value,enabled:false};state.consents.postConsent.value=getValidPostConsentOptions(options);const{initialized,consentsData}=getConsentManagementData(state.consents.postConsent.value.consentManagement,this.logger);state.consents.initialized.value=initialized;state.consents.data.value=consentsData;});// Update consents data in state\nif(state.consents.enabled.value&&!state.consents.initialized.value){this.pluginsManager?.invokeSingle(`consentManager.updateConsentsInfo`,state,this.storeManager,this.logger);}// Re-init store manager\nthis.storeManager?.initializeStorageState();// Re-init user session manager\nthis.userSessionManager?.syncStorageDataToState();// Resume event manager to process the events to destinations\nthis.eventManager?.resume();this.loadDestinations();this.sendTrackingEvents(isBufferedInvocation);}sendTrackingEvents(isBufferedInvocation){// If isBufferedInvocation is true, then the tracking events will be added to the end of the\n// events buffer array so that any other preload events (mainly from query string API) will be processed first.\nif(state.consents.postConsent.value.trackConsent){const trackOptions=trackArgumentsToCallOptions(CONSENT_TRACK_EVENT_NAME);if(isBufferedInvocation){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,['track',trackOptions]];}else {this.track(trackOptions);}}if(state.consents.postConsent.value.sendPageEvent){const pageOptions=pageArgumentsToCallOptions();if(isBufferedInvocation){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,['page',pageOptions]];}else {this.page(pageOptions);}}}setAuthToken(token){this.userSessionManager?.setAuthToken(token);}/**\n * Add a custom integration for a custom destination.\n * @param destinationId - The ID of the custom destination from the RudderStack dashboard.\n * @param integration - The custom integration object.\n * @param isBufferedInvocation - Whether the invocation is buffered.\n */addCustomIntegration(destinationId,integration,isBufferedInvocation=false){const type='addCustomIntegration';if(isBufferedInvocation){this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);this.pluginsManager?.invokeSingle('nativeDestinations.addCustomIntegration',destinationId,integration,state,this.logger);}else {if(state.lifecycle.loaded.value){this.logger.error(CUSTOM_INTEGRATION_CANNOT_BE_ADDED_ERROR(ANALYTICS_CORE,destinationId));return;}state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,destinationId,integration]];}}// End consumer exposed methods\n}\n\n/*\n * RudderAnalytics facade singleton that is exposed as global object and will:\n * expose overloaded methods\n * handle multiple Analytics instances\n * consume SDK preload event buffer\n */class RudderAnalytics{// START-NO-SONAR-SCAN\n// eslint-disable-next-line sonarjs/public-static-readonly\nstatic globalSingleton=null;// END-NO-SONAR-SCAN\nanalyticsInstances={};defaultAnalyticsKey='';
1logger=defaultLogger;// Singleton with constructor bind methods\nconstructor(){try{if(RudderAnalytics.globalSingleton){// START-NO-SONAR-SCAN\n// eslint-disable-next-line no-constructor-return\nreturn RudderAnalytics.globalSingleton;// END-NO-SONAR-SCAN\n}RudderAnalytics.initializeGlobalResources();this.setDefaultInstanceKey=this.setDefaultInstanceKey.bind(this);this.getAnalyticsInstance=this.getAnalyticsInstance.bind(this);this.load=this.load.bind(this);this.ready=this.ready.bind(this);this.triggerBufferedLoadEvent=this.triggerBufferedLoadEvent.bind(this);this.page=this.page.bind(this);this.track=this.track.bind(this);this.identify=this.identify.bind(this);this.alias=this.alias.bind(this);this.group=this.group.bind(this);this.reset=this.reset.bind(this);this.getAnonymousId=this.getAnonymousId.bind(this);this.setAnonymousId=this.setAnonymousId.bind(this);this.getUserId=this.getUserId.bind(this);this.getUserTraits=this.getUserTraits.bind(this);this.getGroupId=this.getGroupId.bind(this);this.getGroupTraits=this.getGroupTraits.bind(this);this.startSession=this.startSession.bind(this);this.endSession=this.endSession.bind(this);this.getSessionId=this.getSessionId.bind(this);this.setAuthToken=this.setAuthToken.bind(this);this.consent=this.consent.bind(this);this.addCustomIntegration=this.addCustomIntegration.bind(this);this.createSafeAnalyticsInstance();RudderAnalytics.globalSingleton=this;state.autoTrack.pageLifecycle.pageViewId.value=generateUUID();state.autoTrack.pageLifecycle.pageLoadedTimestamp.value=Date.now();// start loading if a load event was buffered or wait for explicit load call\nthis.triggerBufferedLoadEvent();// Assign to global \"rudderanalytics\" object after processing the preload buffer (if any exists)\n// for CDN bundling IIFE exports covers this but for npm ESM and CJS bundling has to be done explicitly\nglobalThis.rudderanalytics=this;}catch(error){dispatchErrorEvent(error);}}/**\n * Create an instance of the current instance that can be used\n * to call a subset of methods of the current instance.\n * It is typically used to expose the analytics instance to the integrations (standard and custom)\n */createSafeAnalyticsInstance(){state.lifecycle.safeAnalyticsInstance.value={page:this.page.bind(this),track:this.track.bind(this),identify:this.identify.bind(this),alias:this.alias.bind(this),group:this.group.bind(this),getAnonymousId:this.getAnonymousId.bind(this),getUserId:this.getUserId.bind(this),getUserTraits:this.getUserTraits.bind(this),getGroupId:this.getGroupId.bind(this),getGroupTraits:this.getGroupTraits.bind(this),getSessionId:this.getSessionId.bind(this)};}static initializeGlobalResources(){// We need to initialize the error handler first to catch any unhandled errors occurring in this module as well\ndefaultErrorHandler.init();// Initialize the storage engines with default options\ndefaultCookieStorage.configure();defaultLocalStorage.configure();defaultSessionStorage.configure();defaultInMemoryStorage.configure();}/**\n * Set instance to use if no specific writeKey is provided in methods\n * automatically for the first created instance\n * TODO: to support multiple analytics instances in the near future\n */setDefaultInstanceKey(writeKey){// IMP: Add try-catch block to handle any unhandled errors\n// similar to other public methods\n// if the implementation of this method goes beyond\n// this simple implementation\nif(isString(writeKey)&&writeKey){this.defaultAnalyticsKey=writeKey;}}/**\n * Retrieve an existing analytics instance\n */getAnalyticsInstance(writeKey){try{let instanceId=writeKey;if(!isString(instanceId)||!instanceId){instanceId=this.defaultAnalyticsKey;}const analyticsInstanceExists=Boolean(this.analyticsInstances[instanceId]);if(!analyticsInstanceExists){this.analyticsInstances[instanceId]=new Analytics();}return this.analyticsInstances[instanceId];}catch(error){dispatchErrorEvent(error);return undefined;}}/**\n * Loads the SDK\n * @param writeKey Source write key\n * @param dataPlaneUrl Data plane URL\n * @param loadOptions Additional options for loading the SDK\n * @returns none\n */load(writeKey,dataPlaneUrl,loadOptions){try{if(this.analyticsInstances[writeKey]){return;}this.setDefaultInstanceKey(writeKey);// Track page loaded lifecycle event if enabled\nthis.trackPageLifecycleEvents(loadOptions);// Get the preloaded events array from global buffer instead of window.rudderanalytics\n// as the constructor must have already pushed the events to the global buffer\nconst preloadedEventsArray=getExposedGlobal(GLOBAL_PRELOAD_BUFFER);// The array will be mutated in the below method\npromotePreloadedConsentEventsToTo
1p(preloadedEventsArray);setExposedGlobal(GLOBAL_PRELOAD_BUFFER,clone(preloadedEventsArray));this.getAnalyticsInstance(writeKey)?.load(writeKey,dataPlaneUrl,getSanitizedValue(loadOptions));}catch(error){dispatchErrorEvent(error);}}/**\n * A function to track page lifecycle events like page loaded and page unloaded\n * @param loadOptions\n * @returns\n */trackPageLifecycleEvents(loadOptions){const{autoTrack,useBeacon}=loadOptions??{};const{enabled:autoTrackEnabled=false,options:autoTrackOptions={},pageLifecycle}=autoTrack??{};const{events=[PageLifecycleEvents.UNLOADED],enabled:pageLifecycleEnabled=autoTrackEnabled,options=autoTrackOptions}=pageLifecycle??{};state.autoTrack.pageLifecycle.enabled.value=pageLifecycleEnabled;// Set the autoTrack enabled state\n// if at least one of the autoTrack options is enabled\n// IMPORTANT: make sure this is done at the end as it depends on the above states\nstate.autoTrack.enabled.value=autoTrackEnabled||pageLifecycleEnabled;if(!pageLifecycleEnabled){return;}this.setupPageUnloadTracking(events,useBeacon,options);}/**\n * Setup page unload tracking if enabled\n * @param events\n * @param useBeacon\n * @param options\n */setupPageUnloadTracking(events,useBeacon,options){if(events.length===0||events.includes(PageLifecycleEvents.UNLOADED)){if(useBeacon===true){onPageLeave(isAccessible=>{if(isAccessible===false&&state.lifecycle.loaded.value){const pageUnloadedTimestamp=Date.now();const timeOnPage=pageUnloadedTimestamp-state.autoTrack.pageLifecycle.pageLoadedTimestamp.value;this.track(PageLifecycleEvents.UNLOADED,{timeOnPage},{...options,originalTimestamp:getFormattedTimestamp(new Date(pageUnloadedTimestamp))});}},true);}else {// log warning if beacon is disabled\nthis.logger.warn(PAGE_UNLOAD_ON_BEACON_DISABLED_WARNING(RSA));}}}/**\n * Trigger load event in buffer queue if exists and stores the\n * remaining preloaded events array in global object\n */triggerBufferedLoadEvent(){const preloadedEventsArray=Array.isArray(globalThis.rudderanalytics)?globalThis.rudderanalytics:[];// Get any load method call that is buffered if any\n// BTW, load method is also removed from the array\n// So, the Analytics object can directly consume the remaining events\nconst loadEvent=getPreloadedLoadEvent(preloadedEventsArray);// Set the final preloaded events array in global object\nsetExposedGlobal(GLOBAL_PRELOAD_BUFFER,clone([...preloadedEventsArray]));// Process load method if present in the buffered requests\nif(loadEvent.length>0){// Remove the event name from the Buffered Event array and keep only arguments\nloadEvent.shift();// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nthis.load.apply(null,loadEvent);}}/**\n * Get ready callback arguments and forward to ready call\n */ready(callback){try{this.getAnalyticsInstance()?.ready(getSanitizedValue(callback));}catch(error){dispatchErrorEvent(error);}}/**\n * Process page arguments and forward to page call\n */// These overloads should be same as AnalyticsPageMethod in @rudderstack/analytics-js-common/types/IRudderAnalytics\npage(category,name,properties,options,callback){try{this.getAnalyticsInstance()?.page(pageArgumentsToCallOptions(getSanitizedValue(category),getSanitizedValue(name),getSanitizedValue(properties),getSanitizedValue(options),getSanitizedValue(callback)));}catch(error){dispatchErrorEvent(error);}}/**\n * Process track arguments and forward to page call\n */// These overloads should be same as AnalyticsTrackMethod in @rudderstack/analytics-js-common/types/IRudderAnalytics\ntrack(event,properties,options,callback){try{this.getAnalyticsInstance()?.track(trackArgumentsToCallOptions(getSanitizedValue(event),getSanitizedValue(properties),getSanitizedValue(options),getSanitizedValue(callback)));}catch(error){dispatchErrorEvent(error);}}/**\n * Process identify arguments and forward to page call\n */// These overloads should be same as AnalyticsIdentifyMethod in @rudderstack/analytics-js-common/types/IRudderAnalytics\nidentify(userId,traits,options,callback){try{this.getAnalyticsInstance()?.identify(identifyArgumentsToCallOptions(getSanitizedValue(userId),getSanitizedValue(traits),getSanitizedValue(options),getSanitizedValue(callback)));}
1catch(error){dispatchErrorEvent(error);}}/**\n * Process alias arguments and forward to page call\n */// These overloads should be same as AnalyticsAliasMethod in @rudderstack/analytics-js-common/types/IRudderAnalytics\nalias(to,from,options,callback){try{this.getAnalyticsInstance()?.alias(aliasArgumentsToCallOptions(getSanitizedValue(to),getSanitizedValue(from),getSanitizedValue(options),getSanitizedValue(callback)));}catch(error){dispatchErrorEvent(error);}}/**\n * Process group arguments and forward to page call\n */// These overloads should be same as AnalyticsGroupMethod in @rudderstack/analytics-js-common/types/IRudderAnalytics\ngroup(groupId,traits,options,callback){try{this.getAnalyticsInstance()?.group(groupArgumentsToCallOptions(getSanitizedValue(groupId),getSanitizedValue(traits),getSanitizedValue(options),getSanitizedValue(callback)));}catch(error){dispatchErrorEvent(error);}}/**\n * Reset the analytics instance\n * @param options Reset options. Except for anonymousId, initialReferrer, and initialReferringDomain\n * all other values will be reset by default.\n * @example\n * ```ts\n * reset({\n * entries: {\n * anonymousId: true,\n * }\n * });\n * ```\n * @example\n * ```ts\n * reset({\n * entries: {\n * userId: false,\n * sessionInfo: false,\n * }\n * });\n * ```\n * @returns none\n *//**\n * Reset the analytics instance\n * @param resetAnonymousId Reset anonymous ID\n * @returns none\n * @deprecated Use reset(options) instead\n */reset(options){try{this.getAnalyticsInstance()?.reset(getSanitizedValue(options));}catch(error){dispatchErrorEvent(error);}}getAnonymousId(options){try{return this.getAnalyticsInstance()?.getAnonymousId(getSanitizedValue(options));}catch(error){dispatchErrorEvent(error);return undefined;}}setAnonymousId(anonymousId,rudderAmpLinkerParam){try{this.getAnalyticsInstance()?.setAnonymousId(getSanitizedValue(anonymousId),getSanitizedValue(rudderAmpLinkerParam));}catch(error){dispatchErrorEvent(error);}}getUserId(){try{return this.getAnalyticsInstance()?.getUserId();}catch(error){dispatchErrorEvent(error);return undefined;}}getUserTraits(){try{return this.getAnalyticsInstance()?.getUserTraits();}catch(error){dispatchErrorEvent(error);return undefined;}}getGroupId(){try{return this.getAnalyticsInstance()?.getGroupId();}catch(error){dispatchErrorEvent(error);return undefined;}}getGroupTraits(){try{return this.getAnalyticsInstance()?.getGroupTraits();}catch(error){dispatchErrorEvent(error);return undefined;}}startSession(sessionId){try{this.getAnalyticsInstance()?.startSession(getSanitizedValue(sessionId));}catch(error){dispatchErrorEvent(error);}}endSession(){try{this.getAnalyticsInstance()?.endSession();}catch(error){dispatchErrorEvent(error);}}getSessionId(){try{return this.getAnalyticsInstance()?.getSessionId();}catch(error){dispatchErrorEvent(error);return undefined;}}setAuthToken(token){try{this.getAnalyticsInstance()?.setAuthToken(getSanitizedValue(token));}catch(error){dispatchErrorEvent(error);}}consent(options){try{this.getAnalyticsInstance()?.consent(getSanitizedValue(options));}catch(error){dispatchErrorEvent(error);}}addCustomIntegration(destinationId,integration){try{this.getAnalyticsInstance()?.addCustomIntegration(getSanitizedValue(destinationId),getSanitizedValue(integration));}catch(error){dispatchErrorEvent(error);}}}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQHJ1ZGRlcnN0YWNrL2FuYWx5dGljcy1qcy9kaXN0L25wbS9tb2Rlcm4vYnVuZGxlZC9lc20vaW5kZXgubWpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0
1FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BydWRkZXJzdGFjay9hbmFseXRpY3MtanMvZGlzdC9ucG0vbW9kZXJuL2J1bmRsZWQvZXNtL2luZGV4Lm1qcz80MmVjIl0sInNvdXJjZXNDb250ZW50IjpbImZ1bmN0aW9uIF9pc1BsYWNlaG9sZG
1VyKGEpe3JldHVybiBhIT1udWxsJiZ0eXBlb2YgYT09PSdvYmplY3QnJiZhWydAQGZ1bmN0aW9uYWwvcGxhY2Vob2xkZXInXT09PXRydWU7fVxuXG4vKipcbiAqIE9wdGltaXplZCBpbnRlcm5hbCBvbmUtYXJpdHkgY3VycnkgZnVuY3Rpb24uXG4gKlxuICogQHByaXZhdGVcbiAqIEBjYXRlZ29yeSBGdW5jdGlvblxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gVGhlIGZ1bmN0aW9uIHRvIGN1cnJ5LlxuICogQHJldHVybiB7RnVuY3Rpb259IFRoZSBjdXJyaWVkIGZ1bmN0aW9uLlxuICovZnVuY3Rpb24gX2N1cnJ5MShmbil7cmV0dXJuIGZ1bmN0aW9uIGYxKGEpe2lmKGFyZ3VtZW50cy5sZW5ndGg9PT0wfHxfaXNQbGFjZWhvbGRlcihhKSl7cmV0dXJuIGYxO31lbHNlIHtyZXR1cm4gZm4uYXBwbHkodGhpcyxhcmd1bWVudHMpO319O31cblxuLyoqXG4gKiBPcHRpbWl6ZWQgaW50ZXJuYWwgdHdvLWFyaXR5IGN1cnJ5IGZ1bmN0aW9uLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIFRoZSBmdW5jdGlvbiB0byBjdXJyeS5cbiAqIEByZXR1cm4ge0Z1bmN0aW9ufSBUaGUgY3VycmllZCBmdW5jdGlvbi5cbiAqL2Z1bmN0aW9uIF9jdXJyeTIoZm4pe3JldHVybiBmdW5jdGlvbiBmMihhLGIpe3N3aXRjaChhcmd1bWVudHMubGVuZ3RoKXtjYXNlIDA6cmV0dXJuIGYyO2Nhc2UgMTpyZXR1cm4gX2lzUGxhY2Vob2xkZXIoYSk/ZjI6X2N1cnJ5MShmdW5jdGlvbihfYil7cmV0dXJuIGZuKGEsX2IpO30pO2RlZmF1bHQ6cmV0dXJuIF9pc1BsYWNlaG9sZGVyKGEpJiZfaXNQbGFjZWhvbGRlcihiKT9mMjpfaXNQbGFjZWhvbGRlcihhKT9fY3VycnkxKGZ1bmN0aW9uKF9hKXtyZXR1cm4gZm4oX2EsYik7fSk6X2lzUGxhY2Vob2xkZXIoYik/X2N1cnJ5MShmdW5jdGlvbihfYil7cmV0dXJuIGZuKGEsX2IpO30pOmZuKGEsYik7fX07f
1VxuXG4vKipcbiAqIE9wdGltaXplZCBpbnRlcm5hbCB0aHJlZS1hcml0eSBjdXJyeSBmdW5jdGlvbi5cbiAqXG4gKiBAcHJpdmF0ZVxuICogQGNhdGVnb3J5IEZ1bmN0aW9uXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgZnVuY3Rpb24gdG8gY3VycnkuXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn0gVGhlIGN1cnJpZWQgZnVuY3Rpb24uXG4gKi9mdW5jdGlvbiBfY3VycnkzKGZuKXtyZXR1cm4gZnVuY3Rpb24gZjMoYSxiLGMpe3N3aXRjaChhcmd1bWVudHMubGVuZ3RoKXtjYXNlIDA6cmV0dXJuIGYzO2Nhc2UgMTpyZXR1cm4gX2lzUGxhY2Vob2xkZXIoYSk/ZjM6X2N1cnJ5MihmdW5jdGlvbihfYixfYyl7cmV0dXJuIGZuKGEsX2IsX2MpO30pO2Nhc2UgMjpyZXR1cm4gX2lzUGxhY2Vob2xkZXIoYSkmJl9pc1BsYWNlaG9sZGVyKGIpP2YzOl9pc1BsYWNlaG9sZGVyKGEpP19jdXJyeTIoZnVuY3Rpb24oX2EsX2Mpe3JldHVybiBmbihfYSxiLF9jKTt9KTpfaXNQbGFjZWhvbGRlcihiKT9fY3VycnkyKGZ1bmN0aW9uKF9iLF9jKXtyZXR1cm4gZm4oYSxfYixfYyk7fSk6X2N1cnJ5MShmdW5jdGlvbihfYyl7cmV0dXJuIGZuKGEsYixfYyk7fSk7ZGVmYXVsdDpyZXR1cm4gX2lzUGxhY2Vob2xkZXIoYSkmJl9pc1BsYWNlaG9sZGVyKGIpJiZfaXNQbGFjZWhvbGRlcihjKT9mMzpfaXNQbGFjZWhvbGRlcihhKSYmX2lzUGxhY2Vob2xkZXIoYik/X2N1cnJ5MihmdW5jdGlvbihfYSxfYil7cmV0dXJuIGZuKF9hLF9iLGMpO30pOl9pc1BsYWNlaG9sZGVyKGEpJiZfaXNQbGFjZWhvbGRlcihjKT9fY3VycnkyKGZ1bmN0aW9uKF9hLF9jKXtyZXR1cm4gZm4oX2EsYixfYyk7fSk6X2lzUGxhY2Vob2xkZXIoYikmJl9pc1BsYWNlaG9sZGVyKGMpP19jdXJyeTIoZnVuY3Rpb24oX2IsX2Mpe3JldHVybiBmbihhLF9iLF9jKTt9KTpfaXNQbGFjZWhvbGRlcihhKT9fY3VycnkxKGZ1bmN0aW9uKF9hKXtyZXR1cm4gZm4oX2EsYixjKTt9KTpfaXNQbGFjZWhvbGRlcihiKT9fY3VycnkxKGZ1bmN0aW9uKF9iKXtyZXR1cm4gZm4oYSxfYixjKTt9KTpfaXNQbGFjZWhvbGRlcihjKT9fY3VycnkxKGZ1bmN0aW9uKF9jKXtyZXR1cm4gZm4oYSxiLF9jKTt9KTpmbihhLGIsYyk7fX07fVxuXG5mdW5jdGlvbiBfaGFzKHByb3Asb2JqKXtyZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaixwcm9wKTt9XG5cbi8qKlxuICogR2l2ZXMgYSBzaW5nbGUtd29yZCBzdHJpbmcgZGVzY3JpcHRpb24gb2YgdGhlIChuYXRpdmUpIHR5cGUgb2YgYSB2YWx1ZSxcbiAqIHJldHVybmluZyBzdWNoIGFuc3dlcnMgYXMgJ09iamVjdCcsICdOdW1iZXInLCAnQXJyYXknLCBvciAnTnVsbCcuIERvZXMgbm90XG4gKiBhdHRlbXB0IHRvIGRpc3Rpbmd1aXNoIHVzZXIgT2JqZWN0IHR5cGVzIGFueSBmdXJ0aGVyLCByZXBvcnRpbmcgdGhlbSBhbGwgYXNcbiAqICdPYmplY3QnLlxuICpcbiAqIEBmdW5jXG4gKiBAbWVtYmVyT2YgUlxuICogQHNpbmNlIHY
1wLjguMFxuICogQGNhdGVnb3J5IFR5cGVcbiAqIEBzaWcgKiAtPiBTdHJpbmdcbiAqIEBwYXJhbSB7Kn0gdmFsIFRoZSB2YWx1ZSB0byB0ZXN0XG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKiBAZXhhbXBsZVxuICpcbiAqICAgICAgUi50eXBlKHt9KTsgLy89PiBcIk9iamVjdFwiXG4gKiAgICAgIFIudHlwZShuZXcgTWFwKTsgLy89PiBcIk1hcFwiXG4gKiAgICAgIFIudHlwZShuZXcgU2V0KTsgLy89PiBcIlNldFwiXG4gKiAgICAgIFIudHlwZSgxKTsgLy89PiBcIk51bWJlclwiXG4gKiAgICAgIFIudHlwZShmYWxzZSk7IC8vPT4gXCJCb29sZWFuXCJcbiAqICAgICAgUi50eXBlKCdzJyk7IC8vPT4gXCJTdHJpbmdcIlxuICogICAgICBSLnR5cGUobnVsbCk7IC8vPT4gXCJOdWxsXCJcbiAqICAgICAgUi50eXBlKFtdKTsgLy89PiBcIkFycmF5XCJcbiAqICAgICAgUi50eXBlKC9bQS16XS8pOyAvLz0+IFwiUmVnRXhwXCJcbiAqICAgICAgUi50eXBlKCgpID0+IHt9KTsgLy89PiBcIkZ1bmN0aW9uXCJcbiAqICAgICAgUi50eXBlKGFzeW5jICgpID0+IHt9KTsgLy89PiBcIkFzeW5jRnVuY3Rpb25cIlxuICogICAgICBSLnR5cGUodW5kZWZpbmVkKTsgLy89PiBcIlVuZGVmaW5lZFwiXG4gKiAgICAgIFIudHlwZShCaWdJbnQoMTIzKSk7IC8vPT4gXCJCaWdJbnRcIlxuICovdmFyIHR5cGU9LyojX19QVVJFX18qL19jdXJyeTEoZnVuY3Rpb24gdHlwZSh2YWwpe3JldHVybiB2YWw9PT1udWxsPydOdWxsJzp2YWw9PT11bmRlZmluZWQ/J1VuZGVmaW5lZCc6T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbCkuc2xpY2UoOCwtMSk7fSk7XG5cbmZ1bmN0aW9uIF9pc09iamVjdCh4KXtyZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHgpPT09J1tvYmplY3QgT2JqZWN0XSc7fVxuXG4vKipcbiAqIERldGVybWluZSBpZiB0aGUgcGFzc2VkIGFyZ3VtZW50IGlzIGFuIGludGVnZXIuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7Kn0gblxuICogQGNhdGVnb3J5IFR5cGVcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9jb25zdCBfaXNJbnRlZ2VyID0gTnVtYmVyLmlzSW50ZWdlcnx8ZnVuY3Rpb24gX2lzSW50ZWdlcihuKXtyZXR1cm4gbjw8MD09PW47fTtcblxuZnVuY3Rpb24gX250aChvZmZzZXQsbGlzdCl7dmFyIGlkeD1vZmZzZXQ8MD9saXN0Lmxlbmd0aCtvZmZzZXQ6b2Zmc2V0O3JldHVybiBsaXN0W2lkeF07fVxuXG5mdW5jdGlvbiBfY2xvbmVSZWdFeHAocGF0dGVybil7cmV0dXJuIG5ldyBSZWdFeHAocGF0dGVybi5zb3VyY2UscGF0dGVybi5mbGFncz9wYXR0ZXJuLmZsYWdzOihwYXR0ZXJuLmdsb2JhbD8nZyc6JycpKyhwYXR0ZXJuLmlnbm9yZUNhc2U/J2knOicnKSsocGF0dGVybi5tdWx0aWxpbmU/J20nOicnKSsocGF0dGVybi5zdGlja3k/J3knOicnKSsocGF0dGVybi51bmljb2RlPyd1JzonJykrKHBhdHRlcm4uZG90QWxsPydzJzonJykpO31cblxuLyoqXG4gKiBDb3BpZXMgYW4gb2JqZWN0LlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBiZSBjb3BpZWRcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gZGVlcCBXaGV0aGVyIG9yIG5vdCB0byBwZXJmb3JtIGRlZXAgY2xvbmluZy5cbiAqIEByZXR1cm4geyp9IFRoZSBjb3BpZWQgdmFsdWUuXG4gKi9mdW5jdGlvbiBfY2xvbmUodmFsdWUsZGVlcCxtYXApe21hcHx8KG1hcD1uZXcgX09iamVjdE1hcCgpKTsvLyB0aGlzIGF2b2lkcyB0aGUgc2xvd2VyIHN3aXRjaCB3aXRoIGEgcXVpY2sgaWYgZGVjaXNpb24gcmVtb3Zpbmcgc29tZSBtaWxsaXNlY29uZHMgaW4gZWFjaCBydW4uXG5pZihfaXNQcmltaXRpdmUodmFsdWUpKXtyZXR1cm4gdmFsdWU7fXZhciBjb3B5PWZ1bmN0aW9uIGNvcHkoY29waWVkVmFsdWUpey8vIENoZWNrIGZvciBjaXJjdWxhciBhbmQgc2FtZSByZWZlcmVuY2VzIG9uIHRoZSBvYmplY3QgZ3JhcGggYW5kIHJldHVybiBpdHMgY29ycmVzcG9uZGluZyBjbG9uZS5cbnZhciBjYWNoZWRDb3B5PW1hcC5nZXQodmFsdWUpO2lmKGNhY2hlZENvcHkpe3JldHVybiBjYWNoZWRDb3B5O31tYXAuc2V0KHZhbHVlLGNvcGllZFZhbHVlKTtmb3IodmFyIGtleSBpbiB2YWx1ZSl7aWYoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHZhbHVlLGtleSkpe2NvcGllZFZhbHVlW2tleV09X2Nsb25lKHZhbHVlW2tleV0sdHJ1ZSxtYXApO319cmV0dXJuIGNvcGllZFZhbHVlO307c3dpdGNoKHR5cGUodmFsdWUpKXtjYXNlICdPYmplY3QnOnJldHVybiBjb3B5KE9iamVjdC5jcmVhdGUoT2JqZWN0LmdldFByb3RvdHlwZU9mKHZhbHVlKSkpO2Nhc2UgJ0FycmF5JzpyZXR1cm4gY29weShBcnJheSh2YWx1ZS5sZW5ndGgpKTtjYXNlICdEYXRlJzpyZXR1cm4gbmV3IERhdGUodmFsdWUudmFsdWVPZigpKTtjYXNlICdSZWdFeHAnOnJldHVybiBfY2xvbmVSZWdFeHAodmFsdWUpO2Nhc2UgJ0ludDhBcnJheSc6Y2FzZSAnVWludDhBcnJheSc6Y2FzZSAnVWludDhDbGFtcGVkQXJyYXknOmNhc2UgJ0ludDE2QXJyYXknOmNhc2UgJ1VpbnQxNkFycmF
15JzpjYXNlICdJbnQzMkFycmF5JzpjYXNlICdVaW50MzJBcnJheSc6Y2FzZSAnRmxvYXQzMkFycmF5JzpjYXNlICdGbG9hdDY0QXJyYXknOmNhc2UgJ0JpZ0ludDY0QXJyYXknOmNhc2UgJ0JpZ1VpbnQ2NEFycmF5JzpyZXR1cm4gdmFsdWUuc2xpY2UoKTtkZWZhdWx0OnJldHVybiB2YWx1ZTt9fWZ1bmN0aW9uIF9pc1ByaW1pdGl2ZShwYXJhbSl7dmFyIHR5cGU9dHlwZW9mIHBhcmFtO3JldHVybiBwYXJhbT09bnVsbHx8dHlwZSE9J29iamVjdCcmJnR5cGUhPSdmdW5jdGlvbic7fXZhciBfT2JqZWN0TWFwPS8qI19fUFVSRV9fKi9mdW5jdGlvbigpe2Z1bmN0aW9uIF9PYmplY3RNYXAoKXt0aGlzLm1hcD17fTt0aGlzLmxlbmd0aD0wO31fT2JqZWN0TWFwLnByb3RvdHlwZS5zZXQ9ZnVuY3Rpb24oa2V5LHZhbHVlKXt2YXIgaGFzaGVkS2V5PXRoaXMuaGFzaChrZXkpO3ZhciBidWNrZXQ9dGhpcy5tYXBbaGFzaGVkS2V5XTtpZighYnVja2V0KXt0aGlzLm1hcFtoYXNoZWRLZXldPWJ1Y2tldD1bXTt9YnVja2V0LnB1c2goW2tleSx2YWx1ZV0pO3RoaXMubGVuZ3RoKz0xO307X09iamVjdE1hcC5wcm90b3R5cGUuaGFzaD1mdW5jdGlvbihrZXkpe3ZhciBoYXNoZWRLZXk9W107Zm9yKHZhciB2YWx1ZSBpbiBrZXkpe2hhc2hlZEtleS5wdXNoKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChrZXlbdmFsdWVdKSk7fXJldHVybiBoYXNoZWRLZXkuam9pbigpO307X09iamVjdE1hcC5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGtleSl7LyoqXG4gICAgICogZGVwZW5kaW5nIG9uIHRoZSBudW1iZXIgb2Ygb2JqZWN0cyB0byBiZSBjbG9uZWQgaXMgZmFzdGVyIHRvIGp1c3QgaXRlcmF0ZSBvdmVyIHRoZSBpdGVtcyBpbiB0aGUgbWFwIGp1c3QgYmVjYXVzZSB0aGUgaGFzaCBmdW5jdGlvbiBpcyBzbyBjb3N0bHksXG4gICAgICogb24gbXkgdGVzdHMgdGhpcyBudW1iZXIgaXMgMTgwLCBhbnl0aGluZyBhYm92ZSB0aGF0IHVzaW5nIHRoZSBoYXNoIGZ1bmN0aW9uIGlzIGZhc3Rlci5cbiAgICAgKi9pZih0aGlzLmxlbmd0aDw9MTgwKXtmb3IodmFyIHAgaW4gdGhpcy5tYXApe3ZhciBidWNrZXQ9dGhpcy5tYXBbcF07Zm9yKHZhciBpPTA7aTxidWNrZXQubGVuZ3RoO2krPTEpe3ZhciBlbGVtZW50PWJ1Y2tldFtpXTtpZihlbGVtZW50WzBdPT09a2V5KXtyZXR1cm4gZWxlbWVudFsxXTt9fX1yZXR1cm47fXZhciBoYXNoZWRLZXk9dGhpcy5oYXNoKGtleSk7dmFyIGJ1Y2tldD10aGlzLm1hcFtoYXNoZWRLZXldO2lmKCFidWNrZXQpe3JldHVybjt9Zm9yKHZhciBpPTA7aTxidWNrZXQubGVuZ3RoO2krPTEpe3ZhciBlbGVtZW50PWJ1Y2tldFtpXTtpZihlbGVtZW50WzBdPT09a2V5KXtyZXR1cm4gZWxlbWVudFsxXTt9fX07cmV0dXJuIF9PYmplY3RNYXA7fSgpO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBkZWVwIGNvcHkgb2YgdGhlIHNvdXJjZSB0aGF0IGNhbiBiZSB1c2VkIGluIHBsYWNlIG9mIHRoZSBzb3VyY2VcbiAqIG9iamVjdCB3aXRob3V0IHJldGFpbmluZyBhbnkgcmVmZXJlbmNlcyB0byBpdC5cbiAqIFRoZSBzb3VyY2Ugb2JqZWN0IG1heSBjb250YWluIChuZXN0ZWQpIGBBcnJheWBzIGFuZCBgT2JqZWN0YHMsXG4gKiBgTnVtYmVyYHMsIGBTdHJpbmdgcywgYEJvb2xlYW5gcyBhbmQgYERhdGVgcy5cbiAqIGBGdW5jdGlvbmBzIGFyZSBhc3NpZ25lZCBieSByZWZlcmVuY2UgcmF0aGVyIHRoYW4gY29waWVkLlxuICpcbiAqIERpc3BhdGNoZXMgdG8gYSBgY2xvbmVgIG1ldGhvZCBpZiBwcmVzZW50LlxuICpcbiAqIE5vdGUgdGhhdCBpZiB0aGUgc291cmNlIG9iamVjdCBoYXMgbXVsdGlwbGUgbm9kZXMgdGhhdCBzaGFyZSBhIHJlZmVyZW5jZSxcbiAqIHRoZSByZXR1cm5lZCBvYmplY3Qgd2lsbCBoYXZlIHRoZSBzYW1lIHN0cnVjdHVyZSwgYnV0IHRoZSByZWZlcmVuY2VzIHdpbGxcbiAqIGJlIHBvaW50ZWQgdG8gdGhlIGxvY2F0aW9uIHdpdGhpbiB0aGUgY2xvbmVkIHZhbHVlLlxuICpcbiAqIEBmdW5jXG4gKiBAbWVtYmVyT2YgUlxuICogQHNpbmNlIHY
1wLjEuMFxuICogQGNhdGVnb3J5IE9iamVjdFxuICogQHNpZyB7Kn0gLT4geyp9XG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSBvYmplY3Qgb3IgYXJyYXkgdG8gY2xvbmVcbiAqIEByZXR1cm4geyp9IEEgZGVlcGx5IGNsb25lZCBjb3B5IG9mIGB2YWxgXG4gKiBAZXhhbXBsZVxuICpcbiAqICAgICAgY29uc3Qgb2JqZWN0cyA9IFt7fSwge30sIHt9XTtcbiAqICAgICAgY29uc3Qgb2JqZWN0c0Nsb25lID0gUi5jbG9uZShvYmplY3RzKTtcbiAqICAgICAgb2JqZWN0cyA9PT0gb2JqZWN0c0Nsb25lOyAvLz0+IGZhbHNlXG4gKiAgICAgIG9iamVjdHNbMF0gPT09IG9iamVjdHNDbG9uZVswXTsgLy89PiBmYWxzZVxuICovdmFyIGNsb25lPS8qI19fUFVSRV9fKi9fY3VycnkxKGZ1bmN0aW9uIGNsb25lKHZhbHVlKXtyZXR1cm4gdmFsdWUhPW51bGwmJnR5cGVvZiB2YWx1ZS5jbG9uZT09PSdmdW5jdGlvbic/dmFsdWUuY2xvbmUoKTpfY2xvbmUodmFsdWUpO30pO1xuXG5mdW5jdGlvbiBfcGF0aChwYXRoQXIsb2JqKXt2YXIgdmFsPW9iajtmb3IodmFyIGk9MDtpPHBhdGhBci5sZW5ndGg7aSs9MSl7aWYodmFsPT1udWxsKXtyZXR1cm4gdW5kZWZpbmVkO312YXIgcD1wYXRoQXJbaV07aWYoX2lzSW50ZWdlcihwKSl7dmFsPV9udGgocCx2YWwpO31lbHNlIHt2YWw9dmFsW3BdO319cmV0dXJuIHZhbDt9XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBvYmplY3Qgd2l0aCB0aGUgb3duIHByb3BlcnRpZXMgb2YgdGhlIHR3byBwcm92aWRlZCBvYmplY3RzLiBJZlxuICogYSBrZXkgZXhpc3RzIGluIGJvdGggb2JqZWN0cywgdGhlI
1HByb3ZpZGVkIGZ1bmN0aW9uIGlzIGFwcGxpZWQgdG8gdGhlIGtleVxuICogYW5kIHRoZSB2YWx1ZXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBrZXkgaW4gZWFjaCBvYmplY3QsIHdpdGggdGhlIHJlc3VsdCBiZWluZ1xuICogdXNlZCBhcyB0aGUgdmFsdWUgYXNzb2NpYXRlZCB3aXRoIHRoZSBrZXkgaW4gdGhlIHJldHVybmVkIG9iamVjdC5cbiAqXG4gKiBAZnVuY1xuICogQG1lbWJlck9mIFJcbiAqIEBzaW5jZSB2MC4xOS4wXG4gKiBAY2F0ZWdvcnkgT2JqZWN0XG4gKiBAc2lnICgoU3RyaW5nLCBhLCBhKSAtPiBhKSAtPiB7YX0gLT4ge2F9IC0+IHthfVxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm5cbiAqIEBwYXJhbSB7T2JqZWN0fSBsXG4gKiBAcGFyYW0ge09iamVjdH0gclxuICogQHJldHVybiB7T2JqZWN0fVxuICogQHNlZSBSLm1lcmdlRGVlcFdpdGhLZXksIFIubWVyZ2VXaXRoXG4gKiBAZXhhbXBsZVxuICpcbiAqICAgICAgbGV0IGNvbmNhdFZhbHVlcyA9IChrLCBsLCByKSA9PiBrID09ICd2YWx1ZXMnID8gUi5jb25jYXQobCwgcikgOiByXG4gKiAgICAgIFIubWVyZ2VXaXRoS2V5KGNvbmNhdFZhbHVlcyxcbiAqICAgICAgICAgICAgICAgICAgICAgeyBhOiB0cnVlLCB0aGluZzogJ2ZvbycsIHZhbHVlczogWzEwLCAyMF0gfSxcbiAqICAgICAgICAgICAgICAgICAgICAgeyBiOiB0cnVlLCB0aGluZzogJ2JhcicsIHZhbHVlczogWzE1LCAzNV0gfSk7XG4gKiAgICAgIC8vPT4geyBhOiB0cnVlLCBiOiB0cnVlLCB0aGluZzogJ2JhcicsIHZhbHVlczogWzEwLCAyMCwgMTUsIDM1XSB9XG4gKiBAc3ltYiBSLm1lcmdlV2l0aEtleShmLCB7IHg6IDEsIHk6IDIgfSwgeyB5OiA1LCB6OiAzIH0pID0geyB4OiAxLCB5OiBmKCd5JywgMiwgNSksIHo6IDMgfVxuICovdmFyIG1lcmdlV2l0aEtleT0vKiNfX1BVUkVfXyovX2N1cnJ5MyhmdW5jdGlvbiBtZXJnZVdpdGhLZXkoZm4sbCxyKXt2YXIgcmVzdWx0PXt9O3ZhciBrO2w9bHx8e307cj1yfHx7fTtmb3IoayBpbiBsKXtpZihfaGFzKGssbCkpe3Jlc3VsdFtrXT1faGFzKGsscik/Zm4oayxsW2tdLHJba10pOmxba107fX1mb3IoayBpbiByKXtpZihfaGFzKGsscikmJiFfaGFzKGsscmVzdWx0KSl7cmVzdWx0W2tdPXJba107fX1yZXR1cm4gcmVzdWx0O30pO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgb2JqZWN0IHdpdGggdGhlIG93biBwcm9wZXJ0aWVzIG9mIHRoZSB0d28gcHJvdmlkZWQgb2JqZWN0cy5cbiAqIElmIGEga2V5IGV4aXN0cyBpbiBib3RoIG9iamVjdHM6XG4gKiAtIGFuZCBib3RoIGFzc29jaWF0ZWQgdmFsdWVzIGFyZSBhbHNvIG9iamVjdHMgdGhlbiB0aGUgdmFsdWVzIHdpbGwgYmVcbiAqICAgcmVjdXJzaXZlbHkgbWVyZ2VkLlxuICogLSBvdGhlcndpc2UgdGhlIHByb3ZpZGVkIGZ1bmN0aW9uIGlzIGFwcGxpZWQgdG8gdGhlIGtleSBhbmQgYXNzb2NpYXRlZCB2YWx1ZXNcbiAqICAgdXNpbmcgdGhlIHJlc3VsdGluZyB2YWx1ZSBhcyB0aGUgbmV3IHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGUga2V5LlxuICogSWYgYSBrZXkgb25seSBleGlzdHMgaW4gb25lIG9iamVjdCwgdGhlI
1HZhbHVlIHdpbGwgYmUgYXNzb2NpYXRlZCB3aXRoIHRoZSBrZXlcbiAqIG9mIHRoZSByZXN1bHRpbmcgb2JqZWN0LlxuICpcbiAqIEBmdW5jXG4gKiBAbWVtYmVyT2YgUlxuICogQHNpbmNlIHYwLjI0LjBcbiAqIEBjYXRlZ29yeSBPYmplY3RcbiAqIEBzaWcgKChTdHJpbmcsIGEsIGEpIC0+IGEpIC0+IHthfSAtPiB7YX0gLT4ge2F9XG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmblxuICogQHBhcmFtIHtPYmplY3R9IGxPYmpcbiAqIEBwYXJhbSB7T2JqZWN0fSByT2JqXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKiBAc2VlIFIubWVyZ2VXaXRoS2V5LCBSLm1lcmdlRGVlcFdpdGhcbiAqIEBleGFtcGxlXG4gKlxuICogICAgICBsZXQgY29uY2F0VmFsdWVzID0gKGssIGwsIHIpID0+IGsgPT0gJ3ZhbHVlcycgPyBSLmNvbmNhdChsLCByKSA6IHJcbiAqICAgICAgUi5tZXJnZURlZXBXaXRoS2V5KGNvbmNhdFZhbHVlcyxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgIHsgYTogdHJ1ZSwgYzogeyB0aGluZzogJ2ZvbycsIHZhbHVlczogWzEwLCAyMF0gfX0sXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICB7IGI6IHRydWUsIGM6IHsgdGhpbmc6ICdiYXInLCB2YWx1ZXM6IFsxNSwgMzVdIH19KTtcbiAqICAgICAgLy89PiB7IGE6IHRydWUsIGI6IHRydWUsIGM6IHsgdGhpbmc6ICdiYXInLCB2YWx1ZXM6IFsxMCwgMjAsIDE1LCAzNV0gfX1cbiAqL3ZhciBtZXJnZURlZXBXaXRoS2V5PS8qI19fUFVSRV9fKi9fY3VycnkzKGZ1bmN0aW9uIG1lcmdlRGVlcFdpdGhLZXkoZm4sbE9iaixyT2JqKXtyZXR1cm4gbWVyZ2VXaXRoS2V5KGZ1bmN0aW9uKGssbFZhbCxyVmFsKXtpZihfaXNPYmplY3QobFZhbCkmJl9pc09iamVjdChyVmFsKSl7cmV0dXJuIG1lcmdlRGVlcFdpdGhLZXkoZm4sbFZhbCxyVmFsKTt9ZWxzZSB7cmV0dXJuIGZuKGssbFZhbCxyVmFsKTt9fSxsT2JqLHJPYmopO30pO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgb2JqZWN0IHdpdGggdGhlIG93biBwcm9wZXJ0aWVzIG9mIHRoZSB0d28gcHJvdmlkZWQgb2JqZWN0cy5cbiAqIElmIGEga2V5IGV4aXN0cyBpbiBib3RoIG9iamVjdHM6XG4gKiAtIGFuZCBib3RoIGFzc29jaWF0ZWQgdmFsdWVzIGFyZSBhbHNvIG9iamVjdHMgdGhlbiB0aGUgdmFsdWVzIHdpbGwgYmVcbiAqICAgcmVjdXJzaXZlbHkgbWVyZ2VkLlxuICogLSBvdGhlcndpc2UgdGhlIHByb3ZpZGVkIGZ1bmN0aW9uIGlzIGFwcGxpZWQgdG8gYXNzb2NpYXRlZCB2YWx1ZXMgdXNpbmcgdGhlXG4gKiAgIHJlc3VsdGluZyB2YWx1ZSBhcyB0aGUgbmV3IHZhbHVlIGFzc29jaWF0ZWQgd2l0aCB0aGUga2V5LlxuICogSWYgYSBrZXkgb25seSBleGlzdHMgaW4gb25lIG9iamVjdCwgdGhlI
1HZhbHVlIHdpbGwgYmUgYXNzb2NpYXRlZCB3aXRoIHRoZSBrZXlcbiAqIG9mIHRoZSByZXN1bHRpbmcgb2JqZWN0LlxuICpcbiAqIEBmdW5jXG4gKiBAbWVtYmVyT2YgUlxuICogQHNpbmNlIHYwLjI0LjBcbiAqIEBjYXRlZ29yeSBPYmplY3RcbiAqIEBzaWcgKChhLCBhKSAtPiBhKSAtPiB7YX0gLT4ge2F9IC0+IHthfVxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm5cbiAqIEBwYXJhbSB7T2JqZWN0fSBsT2JqXG4gKiBAcGFyYW0ge09iamVjdH0gck9ialxuICogQHJldHVybiB7T2JqZWN0fVxuICogQHNlZSBSLm1lcmdlV2l0aCwgUi5tZXJnZURlZXBXaXRoS2V5XG4gKiBAZXhhbXBsZVxuICpcbiAqICAgICAgUi5tZXJnZURlZXBXaXRoKFIuY29uY2F0LFxuICogICAgICAgICAgICAgICAgICAgICAgeyBhOiB0cnVlLCBjOiB7IHZhbHVlczogWzEwLCAyMF0gfX0sXG4gKiAgICAgICAgICAgICAgICAgICAgICB7IGI6IHRydWUsIGM6IHsgdmFsdWVzOiBbMTUsIDM1XSB9fSk7XG4gKiAgICAgIC8vPT4geyBhOiB0cnVlLCBiOiB0cnVlLCBjOiB7IHZhbHVlczogWzEwLCAyMCwgMTUsIDM1XSB9fVxuICovdmFyIG1lcmdlRGVlcFdpdGg9LyojX19QVVJFX18qL19jdXJyeTMoZnVuY3Rpb24gbWVyZ2VEZWVwV2l0aChmbixsT2JqLHJPYmope3JldHVybiBtZXJnZURlZXBXaXRoS2V5KGZ1bmN0aW9uKGssbFZhbCxyVmFsKXtyZXR1cm4gZm4obFZhbCxyVmFsKTt9LGxPYmosck9iaik7fSk7XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSB2YWx1ZSBhdCBhIGdpdmVuIHBhdGguIFRoZSBub2RlcyBvZiB0aGUgcGF0aCBjYW4gYmUgYXJiaXRyYXJ5IHN0cmluZ3Mgb3Igbm9uLW5lZ2F0aXZlIGludGVnZXJzLlxuICogRm9yIGFueXRoaW5nIGVsc2UsIHRoZSB2YWx1ZSBpcyB1bnNwZWNpZmllZC4gSW50ZWdlciBwYXRocyBhcmUgbWVhbnQgdG8gaW5kZXggYXJyYXlzLCBzdHJpbmdzIGFyZSBtZWFudCBmb3Igb2JqZWN0cy5cbiAqXG4gKiBAZnVuY1xuICogQG1lbWJlck9mIFJcbiAqIEBzaW5jZSB2MC4yLjBcbiAqIEBjYXRlZ29yeSBPYmplY3RcbiAqIEB0eXBlZGVmbiBJZHggPSBTdHJpbmcgfCBJbnQgfCBTeW1ib2xcbiAqIEBzaWcgW0lkeF0gLT4ge2F9IC0+IGEgfCBVbmRlZmluZWRcbiAqIEBzaWcgSWR4ID0gU3RyaW5nIHwgTm9uTmVnYXRpdmVJbnRcbiAqIEBwYXJhbSB7QXJyYXl9IHBhdGggVGhlIHBhdGggdG8gdXNlLlxuICogQHBhcmFtIHtPYmplY3R9IG9iaiBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIHJldHJpZXZlIHRoZSBuZXN0ZWQgcHJvcGVydHkgZnJvbS5cbiAqIEByZXR1cm4geyp9IFRoZSBkYXRhIGF0IGBwYXRoYC5cbiAqIEBzZWUgUi5wcm9wLCBSLm50aCwgUi5hc3NvY1BhdGgsIFIuZGlzc29jUGF0aFxuICogQGV4YW1wbGVcbiAqXG4gKiAgICAgIFIucGF0aChbJ2EnLCAnYiddLCB7YToge2I6IDJ9fSk7IC8vPT4gMlxuICogICAgICBSLnBhdGgoWydhJywgJ2InXSwge2M6IHtiOiAyfX0pOyAvLz0+IHVuZGVmaW5lZFxuICogICAgICBSLnBhdGgoWydhJywgJ2InLCAwXSwge2E6IHtiOiBbMSwgMiwgM119fSk7IC8vPT4gMVxuICogICAgICBSLnBhdGgoWydhJywgJ2InLCAtMl0sIHthOiB7YjogWzEsIDIsIDNdfX0pOyAvLz0+IDJcbiAqICAgICAgUi5wYXRoKFsyXSwgeycyJzogMn0pOyAvLz0+IDJcbiAqICAgICAgUi5wYXRoKFstMl0sIHsnLTInOiAnYSd9KTsgLy89PiB1bmRlZmluZWRcbiAqL3ZhciBwYXRoPS8qI19fUFVSRV9fKi9fY3VycnkyKF9wYXRoKTtcblxuLyoqXG4gKiBSZXR1cm5zIGEgcGFydGlhbCBjb3B5IG9mIGFuIG9iamVjdCBjb250YWluaW5nIG9ubHkgdGhlIGtleXMgdGhhdCBzYXRpc2Z5XG4gKiB0aGUgc3VwcGxpZWQgcHJlZGljYXRlLlxuICpcbiAqIEBmdW5jXG4gKiBAbWVtYmVyT2YgUlxuICogQHNpbmNlIHY
1wLjguMFxuICogQGNhdGVnb3J5IE9iamVjdFxuICogQHNpZyAoKHYsIGspIC0+IEJvb2xlYW4pIC0+IHtrOiB2fSAtPiB7azogdn1cbiAqIEBwYXJhbSB7RnVuY3Rpb259IHByZWQgQSBwcmVkaWNhdGUgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IGEga2V5XG4gKiAgICAgICAgc2hvdWxkIGJlIGluY2x1ZGVkIG9uIHRoZSBvdXRwdXQgb2JqZWN0LlxuICogQHBhcmFtIHtPYmplY3R9IG9iaiBUaGUgb2JqZWN0IHRvIGNvcHkgZnJvbVxuICogQHJldHVybiB7T2JqZWN0fSBBIG5ldyBvYmplY3Qgd2l0aCBvbmx5IHByb3BlcnRpZXMgdGhhdCBzYXRpc2Z5IGBwcmVkYFxuICogICAgICAgICBvbiBpdC5cbiAqIEBzZWUgUi5waWNrLCBSLmZpbHRlclxuICogQGV4YW1wbGVcbiAqXG4gKiAgICAgIGNvbnN0IGlzVXBwZXJDYXNlID0gKHZhbCwga2V5KSA9PiBrZXkudG9VcHBlckNhc2UoKSA9PT0ga2V5O1xuICogICAgICBSLnBpY2tCeShpc1VwcGVyQ2FzZSwge2E6IDEsIGI6IDIsIEE6IDMsIEI6IDR9KTsgLy89PiB7QTogMywgQjogNH1cbiAqL3ZhciBwaWNrQnk9LyojX19QVVJFX18qL19jdXJyeTIoZnVuY3Rpb24gcGlja0J5KHRlc3Qsb2JqKXt2YXIgcmVzdWx0PXt9O2Zvcih2YXIgcHJvcCBpbiBvYmope2lmKHRlc3Qob2JqW3Byb3BdLHByb3Asb2JqKSl7cmVzdWx0W3Byb3BdPW9ialtwcm9wXTt9fXJldHVybiByZXN1bHQ7fSk7XG5cbi8qKlxuICogQSBmdW5jdGlvbiB0byBjaGVjayBnaXZlbiB2YWx1ZSBpcyBhIGZ1bmN0aW9uXG4gKiBAcGFyYW0gdmFsdWUgaW5wdXQgdmFsdWVcbiAqIEByZXR1cm5zIGJvb2xlYW5cbiAqL2NvbnN0IGlzRnVuY3Rpb249dmFsdWU9PnR5cGVvZiB2YWx1ZT09PSdmdW5jdGlvbicmJkJvb2xlYW4odmFsdWUuY29uc3RydWN0b3ImJnZhbHVlLmNhbGwmJnZhbHVlLmFwcGx5KTsvKipcbiAqIEEgZnVuY3Rpb24gdG8gY2hlY2sgZ2l2ZW4gdmFsdWUgaXMgYSBzdHJpbmdcbiAqIEBwYXJhbSB2YWx1ZSBpbnB1dCB2YWx1ZVxuICogQHJldHVybnMgYm9vbGVhblxuICovY29uc3QgaXNTdHJpbmc9dmFsdWU9PnR5cGVvZiB2YWx1ZT09PSdzdHJpbmcnOy8qKlxuICogQSBmdW5jdGlvbiB0byBjaGVjayBnaXZlbiB2YWx1ZSBpcyBudWxsIG9yIG5vdFxuICogQHBhcmFtIHZhbHVlIGlucHV0IHZhbHVlXG4gKiBAcmV0dXJucyBib29sZWFuXG4gKi9jb25zdCBpc051bGw9dmFsdWU9PnZhbHVlPT09bnVsbDsvKipcbiAqIEEgZnVuY3Rpb24gdG8gY2hlY2sgZ2l2ZW4gdmFsdWUgaXMgdW5kZWZpbmVkXG4gKiBAcGFyYW0gdmFsdWUgaW5wdXQgdmFsdWVcbiAqIEByZXR1cm5zIGJvb2xlYW5cbiAqL2NvbnN0IGlzVW5kZWZpbmVkPXZhbHVlPT50eXBlb2YgdmFsdWU9PT0ndW5kZWZpbmVkJzsvKipcbiAqIEEgZnVuY3Rpb24gdG8gY2hlY2sgZ2l2ZW4gdmFsdWUgaXMgbnVsbCBvciB1bmRlZmluZWRcbiAqIEBwYXJhbSB2YWx1ZSBpbnB1dCB2YWx1ZVxuICogQHJldHVybnMgYm9vbGVhblxuICovY29uc3QgaXNOdWxsT3JVbmRlZmluZWQ9dmFsdWU9PmlzTnVsbCh2YWx1ZSl8fGlzVW5kZWZpbmVkKHZhbHVlKTsvKipcbiAqIENoZWNrcyBpZiB0aGUgaW5wdXQgaXMgYSBCaWdJbnRcbiAqIEBwYXJhbSB2YWx1ZSBpbnB1dCB2YWx1ZVxuICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgaW5wdXQgaXMgYSBCaWdJbnRcbiAqL2NvbnN0IGlzQmlnSW50PXZhbHVlPT50eXBlb2YgdmFsdWU9PT0nYmlnaW50JzsvKipcbiAqIEEgZnVuY3Rpb24gdG8gY2hlY2sgZ2l2ZW4gdmFsdWUgaXMgZGVmaW5lZFxuICogQHBhcmFtIHZhbHVlIGlucHV0IHZhbHVlXG4gKiBAcmV0dXJucyBib29sZWFuXG4gKi9jb25zdCBpc0RlZmluZWQ9dmFsdWU9PiFpc1VuZGVmaW5lZCh2YWx1ZSk7LyoqXG4gKiBBIGZ1bmN0aW9uIHRvIGNoZWNrIGdpdmVuIHZhbHVlIGlzIGRlZmluZWQgYW5kIG5vdCBudWxsXG4gKiBAcGFyYW0gdmFsdWUgaW5wdXQgdmFsdWVcbiAqIEByZXR1cm5zIGJvb2xlYW5cbiAqL2NvbnN0IGlzRGVmaW5lZEFuZE5vdE51bGw9dmFsdWU9PiFpc051bGxPclVuZGVmaW5lZCh2YWx1ZSk7LyoqXG4gKiBBIGZ1bmN0aW9uIHRvIGNoZWNrIGdpdmVuIHZhbHVlIGlzIGRlZmluZWQgYW5kIG5vdCBudWxsXG4gKiBAcGFyYW0gdmFsdWUgaW5wdXQgdmFsdWVcbiAqIEByZXR1cm5zIGJvb2xlYW5cbiAqL2NvbnN0IGlzRGVmaW5lZE5vdE51bGxBbmROb3RFbXB0eVN0cmluZz12YWx1ZT0+aXNEZWZpbmVkQW5kTm90TnVsbCh2YWx1ZSkmJnZhbHVlIT09Jyc7LyoqXG4gKiBEZXRlcm1pbmVzIGlmIHRoZSBpbnB1dCBpcyBvZiB0eXBlIGVycm9yXG4gKiBAcGFyYW0gdmFsdWUgaW5wdXQgdmFsdWVcbiAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGlucHV0IGlzIG9mIHR5cGUgZXJyb3IgZWxzZSBmYWxzZVxuICovY29uc3QgaXNUeXBlT2ZFcnJvcj12YWx1ZT0+e3N3aXRjaChPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFsdWUpKXtjYXNlICdbb2JqZWN0IEVycm9yXSc6Y2FzZSAnW29iamVjdCBFeGNlcHRpb25dJzpjYXNlICdbb2JqZWN0IERPTUV4Y2VwdGlvbl0nOnJldHVybiB0cnVlO2RlZmF1bHQ6cmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgRXJyb3I7fX07LyoqXG4gKiBBIGZ1bmN0aW9uIHRvIGNoZWNrIGdpdmVuIHZhbHVlIGlzIGEgYm9vbGVhblxuICogQHBhcmFtIHZhbHVlIGlucHV0IHZhbHVlXG4gKiBAcmV0dXJucyBib29sZWFuXG4gKi9jb25zdCBpc0Jvb2xlYW49dmFsdWU9PnR5cGVvZiB2YWx1ZT09PSdib29sZWFuJztcblxuY29uc3QgZ2V0VmFsdWVCeVBhdGg9KG9iaixrZXlQYXRoKT0+e2NvbnN0IHBhdGhQYXJ0cz1rZXlQYXRoLnNwbGl0KCcuJyk7cmV0dXJuIHBhdGgocGF0aFBhcnRzLG9iaik7fTtjb25zdCBoYXNWYWx1ZUJ5UGF0aD0ob2JqLHBhdGgpPT5Cb29sZWFuKGdldFZhbHVlQnlQYXRoKG9iaixwYXRoKSk7Y29uc3QgaXNPYmplY3Q9dmFsdWU9PnR5cGVvZiB2YWx1ZT09PSdvYmplY3QnOy8qKlxuICogQ2hlY2tzIGlmIHRoZSBpbnB1dCBpcyBhbiBvYmplY3QgbGl0ZXJhbCBvciBidWlsdC1pbiBvYmplY3QgdHlwZSBhbmQgbm90IG51bGxcbiAqIEBwYXJhbSB2YWx1ZSBJbnB1dCB2YWx1ZVxuICogQHJldHVybnMgdHJ1ZSBpZiB0aGUgaW5wdXQgaXMgYW4gb2JqZWN0IGFuZCBub3QgbnVsbFxuICovY29uc3QgaXNPYmplY3RBbmROb3ROdWxsPXZhbHVlPT4haXNOdWxsK
1HZhbHVlKSYmaXNPYmplY3QodmFsdWUpJiYhQXJyYXkuaXNBcnJheSh2YWx1ZSk7LyoqXG4gKiBDaGVja3MgaWYgdGhlIGlucHV0IGlzIGFuIG9iamVjdCBsaXRlcmFsIGFuZCBub3QgbnVsbFxuICogQHBhcmFtIHZhbHVlIElucHV0IHZhbHVlXG4gKiBAcmV0dXJucyB0cnVlIGlmIHRoZSBpbnB1dCBpcyBhbiBvYmplY3QgYW5kIG5vdCBudWxsXG4gKi9jb25zdCBpc09iamVjdExpdGVyYWxBbmROb3ROdWxsPXZhbHVlPT4haXNOdWxsKHZhbHVlKSYmT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbHVlKT09PSdbb2JqZWN0IE9iamVjdF0nOy8qKlxuICogTWVyZ2VzIHR3byBhcnJheXMgZGVlcGx5LCByaWdodC10by1sZWZ0XG4gKiBJbiB0aGUgY2FzZSBvZiBjb25mbGljdHMsIHRoZSByaWdodCBhcnJheSdzIHZhbHVlcyByZXBsYWNlIHRoZSBsZWZ0IGFycmF5J3MgdmFsdWVzIGluIHRoZVxuICogc2FtZSBpbmRleCBwb3NpdGlvblxuICogQHBhcmFtIGxlZnRWYWx1ZSAtIFRoZSBsZWZ0IGFycmF5XG4gKiBAcGFyYW0gcmlnaHRWYWx1ZSAtIFRoZSByaWdodCBhcnJheVxuICogQHJldHVybnMgVGhlIG1lcmdlZCBhcnJheVxuICovY29uc3QgbWVyZ2VEZWVwUmlnaHRPYmplY3RBcnJheXM9KGxlZnRWYWx1ZSxyaWdodFZhbHVlKT0+e2lmKCFBcnJheS5pc0FycmF5KGxlZnRWYWx1ZSl8fCFBcnJheS5pc0FycmF5KHJpZ2h0VmFsdWUpKXtyZXR1cm4gY2xvbmUocmlnaHRWYWx1ZSk7fWNvbnN0IG1lcmdlZEFycmF5PWNsb25lKGxlZnRWYWx1ZSk7cmlnaHRWYWx1ZS5mb3JFYWNoKCh2YWx1ZSxpbmRleCk9PnttZXJnZWRBcnJheVtpbmRleF09QXJyYXkuaXNBcnJheSh2YWx1ZSl8fGlzT2JqZWN0QW5kTm90TnVsbCh2YWx1ZSk/Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11c2UtYmVmb3JlLWRlZmluZVxubWVyZ2VEZWVwUmlnaHQobWVyZ2VkQXJyYXlbaW5kZXhdLHZhbHVlKTp2YWx1ZTt9KTtyZXR1cm4gbWVyZ2VkQXJyYXk7fTsvKipcbiAqIE1lcmdlcyB0d28gb2JqZWN0cyBkZWVwbHksIHJpZ2h0LXRvLWxlZnQuXG4gKiBJbiB0aGUgY2FzZSBvZiBjb25mbGljdHMsIHRoZSByaWdodCBvYmplY3QncyB2YWx1ZXMgdGFrZSBwcmVjZWRlbmNlLlxuICogRm9yIGFycmF5cywgdGhlIHJpZ2h0IGFycmF5J3MgdmFsdWVzIHJlcGxhY2UgdGhlIGxlZnQgYXJyYXkncyB2YWx1ZXMgaW4gdGhlXG4gKiBzYW1lIGluZGV4IHBvc2l0aW9uIGtlZXBpbmcgdGhlIHJlbWFpbmluZyBsZWZ0IGFycmF5J3MgdmFsdWVzIGluIHRoZSByZXN1bHRhbnQgYXJyYXkuXG4gKiBAcGFyYW0gbGVmdE9iamVjdCAtIFRoZSBsZWZ0IG9iamVjdFxuICogQHBhcmFtIHJpZ2h0T2JqZWN0IC0gVGhlIHJpZ2h0IG9iamVjdFxuICogQHJldHVybnMgVGhlIG1lcmdlZCBvYmplY3RcbiAqL2NvbnN0IG1lcmdlRGVlcFJpZ2h0PShsZWZ0T2JqZWN0LHJpZ2h0T2JqZWN0KT0+bWVyZ2VEZWVwV2l0aChtZXJnZURlZXBSaWdodE9iamVjdEFycmF
15cyxsZWZ0T2JqZWN0LHJpZ2h0T2JqZWN0KTsvKipcbiBDaGVja3MgaWYgdGhlIGlucHV0IGlzIGEgbm9uLWVtcHR5IG9iamVjdCBsaXRlcmFsIHR5cGUgYW5kIG5vdCB1bmRlZmluZWQgb3IgbnVsbFxuICogQHBhcmFtIHZhbHVlIGlucHV0IGFueVxuICogQHJldHVybnMgYm9vbGVhblxuICovY29uc3QgaXNOb25FbXB0eU9iamVjdD12YWx1ZT0+aXNPYmplY3RMaXRlcmFsQW5kTm90TnVsbCh2YWx1ZSkmJk9iamVjdC5rZXlzKHZhbHVlKS5sZW5ndGg+MDsvKipcbiAqIEEgdXRpbGl0eSB0byByZWN1cnNpdmVseSByZW1vdmUgdW5kZWZpbmVkIHZhbHVlcyBmcm9tIGFuIG9iamVjdFxuICogQHBhcmFtIG9iaiBpbnB1dCBvYmplY3RcbiAqIEByZXR1cm5zIGEgbmV3IG9iamVjdFxuICovY29uc3QgcmVtb3ZlVW5kZWZpbmVkVmFsdWVzPW9iaj0+e2NvbnN0IHJlc3VsdD1waWNrQnkoaXNEZWZpbmVkLG9iaik7T2JqZWN0LmtleXMocmVzdWx0KS5mb3JFYWNoKGtleT0+e2NvbnN0IHZhbHVlPXJlc3VsdFtrZXldO2lmKGlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwodmFsdWUpKXtyZXN1bHRba2V5XT1yZW1vdmVVbmRlZmluZWRWYWx1ZXModmFsdWUpO319KTtyZXR1cm4gcmVzdWx0O307LyoqXG4gKiBBIHV0aWxpdHkgdG8gcmVjdXJzaXZlbHkgcmVtb3ZlIHVuZGVmaW5lZCBhbmQgbnVsbCB2YWx1ZXMgZnJvbSBhbiBvYmplY3RcbiAqIEBwYXJhbSBvYmogaW5wdXQgb2JqZWN0XG4gKiBAcmV0dXJucyBhIG5ldyBvYmplY3RcbiAqL2NvbnN0IHJlbW92ZVVuZGVmaW5lZEFuZE51bGxWYWx1ZXM9b2JqPT57Y29uc3QgcmVzdWx0PXBpY2tCeShpc0RlZmluZWRBbmROb3ROdWxsLG9iaik7T2JqZWN0LmtleXMocmVzdWx0KS5mb3JFYWNoKGtleT0+e2NvbnN0IHZhbHVlPXJlc3VsdFtrZXldO2lmKGlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwodmFsdWUpKXtyZXN1bHRba2V5XT1yZW1vdmVVbmRlZmluZWRBbmROdWxsVmFsdWVzKHZhbHVlKTt9fSk7cmV0dXJuIHJlc3VsdDt9Oy8qKlxuICogTm9ybWFsaXplcyBhbiBvYmplY3QgYnkgcmVtb3ZpbmcgdW5kZWZpbmVkIGFuZCBudWxsIHZhbHVlcy5cbiAqIEBwYXJhbSB2YWwgLSBUaGUgdmFsdWUgdG8gbm9ybWFsaXplXG4gKiBAcmV0dXJucyBUaGUgbm9ybWFsaXplZCBvYmplY3QsIG9yIHVuZGVmaW5lZCBpZiBpbnB1dCBpcyBub3QgYSBub24tZW1wdHkgb2JqZWN0XG4gKiBAZXhhbXBsZVxuICogZ2V0Tm9ybWFsaXplZE9iamVjdFZhbHVlKHsgYTogMSwgYjogbnVsbCwgYzogdW5kZWZpbmVkIH0pIC8vIHJldHVybnMgeyBhOiAxIH1cbiAqIGdldE5vcm1hbGl6ZWRPYmplY3RWYWx1ZSh7fSkgLy8gcmV0dXJucyB1bmRlZmluZWRcbiAqIGdldE5vcm1hbGl6ZWRPYmplY3RWYWx1ZShudWxsKSAvLyByZXR1cm5zIHVuZGVmaW5lZFxuICovY29uc3QgZ2V0Tm9ybWFsaXplZE9iamVjdFZhbHVlPXZhbD0+e2lmKCFpc05vbkVtcHR5T2JqZWN0KHZhbCkpe3JldHVybiB1bmRlZmluZWQ7fXJldHVybiByZW1vdmVVbmRlZmluZWRBbmROdWxsVmFsdWVzKHZhbCk7fTsvKipcbiAqIE5vcm1hbGl6ZXMgYSB2YWx1ZSB0byBhIGJvb2xlYW4sIHdpdGggc3VwcG9ydCBmb3IgYSBkZWZhdWx0IHZhbHVlXG4gKiBAcGFyYW0gdmFsIElucHV0IHZhbHVlXG4gKiBAcGFyYW0gZGVmVmFsIERlZmF1bHQgdmFsdWVcbiAqIEByZXR1cm5zIFJldHVybnMgdGhlIGlucHV0IHZhbHVlIGlmIGl0IGlzIGEgYm9vbGVhbiwgb3RoZXJ3aXNlIHJldHVybnMgdGhlIGRlZmF1bHQgdmFsdWVcbiAqIEBleGFtcGxlXG4gKiBnZXROb3JtYWxpemVkQm9vbGVhblZhbHVlKHRydWUsIGZhbHNlKSAvLyByZXR1cm5zIHRydWVcbiAqL2NvbnN0IGdldE5vcm1hbGl6ZWRCb29sZWFuVmFsdWU9KHZhbCxkZWZWYWwpPT50eXBlb2YgdmFsPT09J2Jvb2xlYW4nP3ZhbDpkZWZWYWw7Y29uc3QgZGVlcEZyZWV6ZT1vYmo9PntPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhvYmopLmZvckVhY2goZnVuY3Rpb24ocHJvcCl7aWYob2JqW3Byb3BdJiZ0eXBlb2Ygb2JqW3Byb3BdPT09J29iamVjdCcpe2RlZXBGcmVlemUob2JqW3Byb3BdKTt9fSk7cmV0dXJuIE9iamVjdC5mcmVlemUob2JqKTt9O1xuXG5jb25zdCB0cmltPXZhbHVlPT52YWx1ZS5yZXBsYWNlKC9eXFxzK3xcXHMrJC9nbSwnJyk7Y29uc3QgcmVtb3ZlTGVhZGluZ1BlcmlvZD12YWx1ZT0+dmFsdWUucmVwbGFjZSgvXlxcLisvLCcnKTsvKipcbiAqIEEgZnVuY3Rpb24gdG8gY29udmVydCB2YWx1ZXMgdG8gc3RyaW5nXG4gKiBAcGFyYW0gdmFsIGlucHV0IHZhbHVlXG4gKiBAcmV0dXJucyBzdHJpbmdpZmllZCB2YWx1ZVxuICovY29uc3QgdHJ5U3RyaW5naWZ5PXZhbD0+e2xldCByZXRWYWw9dmFsO2lmKCFpc1N0cmluZyh2YWwpJiYhaXNOdWxsT3JVbmRlZmluZWQodmFsKSl7dHJ5e3JldFZhbD1KU09OLnN0cmluZ2lmeSh2YWwpO31jYXRjaChlKXtyZXRWYWw9bnVsbDt9fXJldHVybiByZXRWYWw7fTsvLyBUaGUgZm9sbG93aW5nIHRleHQgZW5jb2RpbmcgYW5kIGRlY29kaW5nIGlzIGRvbmUgYmVmb3JlIGJhc2U2NCBlbmNvZGluZyB0byBwcmV2ZW50XG4vLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL0dsb3NzYXJ5L0Jhc2U2NCN0aGVfdW5pY29kZV9wcm9ibGVtXG4vKipcbiAqIENvbnZlcnRzIGEgYmFzZTY0IGVuY29kZWQgc3RyaW5nIHRvIGJ5dGVzIGFycmF5XG4gKiBAcGFyYW0gYmFzZTY0U3RyIGJhc2U2NCBlbmNvZGVkIHN0cmluZ1xuICogQHJldHVybnMgYnl0ZXMgYXJyYXlcbiAqL2NvbnN0IGJhc2U2NFRvQnl0ZXM9YmFzZTY0U3RyPT57Y29uc3QgYmluU3RyaW5nPWdsb2JhbFRoaXMuYXRvYihiYXNlNjRTdHIpO2NvbnN0IGJ5dGVzPWJpblN0cmluZy5zcGxpdCgnJykubWFwKGNoYXI9PmNoYXIuY2hhckNvZGVBdCgwKSk7cmV0dXJuIG5ldyBVaW50OEFycmF5KGJ5dGVzKTt9Oy8qKlxuICogQ29udmVydHMgYSBieXRlcyBhcnJheSB0byBiYXNlNjQgZW5jb2RlZCBzdHJpbmdcbiAqIEBwYXJhbSBieXRlcyBieXRlcyBhcnJheSB0byBiZSBjb252ZXJ0ZWQgdG8gYmFzZTY0XG4gKiBAcmV0dXJucyBiYXNlNjQgZW5jb2RlZCBzdHJpbmdcbiAqL2NvbnN0IGJ5dGVzVG9CYXNlNjQ9Ynl0ZXM9Pntjb25zdCBiaW5TdHJpbmc9QXJyYXkuZnJvbShieXRlcyx4PT5TdHJpbmcuZnJvbUNvZGVQb2ludCh4KSkuam9pbignJyk7cmV0dXJuIGdsb2JhbFRoaXMuYnRvYShiaW5TdHJpbmcpO307LyoqXG4gKiBFbmNvZGVzIGEgc3RyaW5nIHRvIGJhc2U2NCBldmVuIHdpdGggdW5pY29kZSBjaGFyYWN0ZXJzXG4gKiBAcGFyYW0gdmFsdWUgaW5wdXQgc3RyaW5nXG4gKiBAcmV0dXJucyBiYXNlNjQgZW5jb2RlZCBzdHJpbmdcbiAqL2NvbnN0IHRvQmFzZTY0PXZhbHVlPT5ieXRlc1RvQmFzZTY0KG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZSh2YWx1ZSkpOy8qKlxuICogRGVjb2RlcyBhIGJhc2U2NCBlbmNvZGVkIHN0cmluZ1xuICogQHBhcmFtIHZhbHVlIGJhc2U2NCBlbmNvZGVkIHN0cmluZ1xuICogQHJldHVybnMgZGVjb2RlZCBzdHJpbmdcbiAqL2NvbnN0IGZyb21CYXNlNjQ9dmFsdWU9Pm5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShiYXNlNjRUb0J5dGVzKHZhbHVlKSk7XG5cbi8vICAgaWYgeWVzIG1ha2UgdGhlbSBudWxsIGluc3RlYWQgb2Ygb21pdHRpbmcgaW4gb3ZlcmxvYWRlZCBjYXNlc1xuLypcbiAqIE5vcm1hbGlzZSB0aGUgb3ZlcmxvYWRlZCBhcmd1bWVudHMgb2YgdGhlIHBhZ2UgY2FsbCBmYWNhZG
1VcbiAqL2NvbnN0IHBhZ2VBcmd1bWVudHNUb0NhbGxPcHRpb25zPShjYXRlZ29yeSxuYW1lLHByb3BlcnRpZXMsb3B0aW9ucyxjYWxsYmFjayk9Pntjb25zdCBwYXlsb2FkPXtjYXRlZ29yeTpjYXRlZ29yeSxuYW1lOm5hbWUscHJvcGVydGllczpwcm9wZXJ0aWVzLG9wdGlvbnM6b3B0aW9ucyxjYWxsYmFjazp1bmRlZmluZWR9O2lmKGlzRnVuY3Rpb24oY2FsbGJhY2spKXtwYXlsb2FkLmNhbGxiYWNrPWNhbGxiYWNrO31pZihpc0Z1bmN0aW9uKG9wdGlvbnMpKXtwYXlsb2FkLmNhdGVnb3J5PWNhdGVnb3J5O3BheWxvYWQubmFtZT1uYW1lO3BheWxvYWQucHJvcGVydGllcz1wcm9wZXJ0aWVzO3BheWxvYWQub3B0aW9ucz11bmRlZmluZWQ7cGF5bG9hZC5jYWxsYmFjaz1vcHRpb25zO31pZihpc0Z1bmN0aW9uKHByb3BlcnRpZXMpKXtwYXlsb2FkLmNhdGVnb3J5PWNhdGVnb3J5O3BheWxvYWQubmFtZT1uYW1lO3BheWxvYWQucHJvcGVydGllcz11bmRlZmluZWQ7cGF5bG9hZC5vcHRpb25zPXVuZGVmaW5lZDtwYXlsb2FkLmNhbGxiYWNrPXByb3BlcnRpZXM7fWlmKGlzRnVuY3Rpb24obmFtZSkpe3BheWxvYWQuY2F0ZWdvcnk9Y2F0ZWdvcnk7cGF5bG9hZC5uYW1lPXVuZGVmaW5lZDtwYXlsb2FkLnByb3BlcnRpZXM9dW5kZWZpbmVkO3BheWxvYWQub3B0aW9ucz11bmRlZmluZWQ7cGF5bG9hZC5jYWxsYmFjaz1uYW1lO31pZihpc0Z1bmN0aW9uKGNhdGVnb3J5KSl7cGF5bG9hZC5jYXRlZ29yeT11bmRlZmluZWQ7cGF5bG9hZC5uYW1lPXVuZGVmaW5lZDtwYXlsb2FkLnByb3BlcnRpZXM9dW5kZWZpbmVkO3BheWxvYWQub3B0aW9ucz11bmRlZmluZWQ7cGF5bG9hZC5jYWxsYmFjaz1jYXRlZ29yeTt9aWYoaXNPYmplY3RMaXRlcmFsQW5kTm90TnVsbChjYXRlZ29yeSkpe3BheWxvYWQubmFtZT11bmRlZmluZWQ7cGF5bG9hZC5jYXRlZ29yeT11bmRlZmluZWQ7cGF5bG9hZC5wcm9wZXJ0aWVzPWNhdGVnb3J5O2lmKCFpc0Z1bmN0aW9uKG5hbWUpKXtwYXlsb2FkLm9wdGlvbnM9bmFtZTt9ZWxzZSB7cGF5bG9hZC5vcHRpb25zPXVuZGVmaW5lZDt9fWVsc2UgaWYoaXNPYmplY3RMaXRlcmFsQW5kTm90TnVsbChuYW1lKSl7cGF5bG9hZC5uYW1lPXVuZGVmaW5lZDtwYXlsb2FkLnByb3BlcnRpZXM9bmFtZTtpZighaXNGdW5jdGlvbihwcm9wZXJ0aWVzKSl7cGF5bG9hZC5vcHRpb25zPXByb3BlcnRpZXM7fWVsc2Uge3BheWxvYWQub3B0aW9ucz11bmRlZmluZWQ7fX0vLyBpZiB0aGUgY2F0ZWdvcnkgYXJndW1lbnQgYWxvbmUgaXMgcHJvdmlkZWQgYi93IGNhdGVnb3J5IGFuZCBuYW1lLFxuLy8gdXNlIGl0IGFzIG5hbWUgYW5kIHNldCBjYXRlZ29yeSB0byB1bmRlZmluZWRcbmlmKGlzU3RyaW5nKGNhdGVnb3J5KSYmIWlzU3RyaW5nKG5hbWUpKXtwYXlsb2FkLmNhdGVnb3J5PXVuZGVmaW5lZDtwYXlsb2FkLm5hbWU9Y2F0ZWdvcnk7fS8vIFJlc3Qgb2YgdGhlIGNvZGUgaXMganVzdCB0byBjbGVhbiB1cCB1bmRlZmluZWQgdmFsdWVzXG4vLyBhbmQgc2V0IHNvbWUgcHJvcGVyIGRlZmF1bHRzXG4vLyBBbHNvLCB0byBjbG9uZSB0aGUgaW5jb21pbmcgb2JqZWN0IHR5cGUgYXJndW1lbnRzXG5pZighaXNEZWZpbmVkKHBheWxvYWQuY2F0ZWdvcnkpKXtwYXlsb2FkLmNhdGVnb3J5PXVuZGVmaW5lZDt9aWYoIWlzRGVmaW5lZChwYXlsb2FkLm5hbWUpKXtwYXlsb2FkLm5hbWU9dW5kZWZpbmVkO31wYXlsb2FkLnByb3BlcnRpZXM9cGF5bG9hZC5wcm9wZXJ0aWVzP2Nsb25lKHBheWxvYWQucHJvcGVydGllcyk6e307aWYoaXNEZWZpbmVkKHBheWxvYWQub3B0aW9ucykpe3BheWxvYWQub3B0aW9ucz1jbG9uZShwYXlsb2FkLm9wdGlvbnMpO31lbHNlIHtwYXlsb2FkLm9wdGlvbnM9dW5kZWZpbmVkO31jb25zdCBuYW1lRm9yUHJvcGVydGllcz1pc1N0cmluZyhwYXlsb2FkLm5hbWUpP3BheWxvYWQubmFtZTpwYXlsb2FkLnByb3BlcnRpZXMubmFtZTtjb25zdCBjYXRlZ29yeUZvclByb3BlcnRpZXM9aXNTdHJpbmcocGF5bG9hZC5jYXRlZ29yeSk/cGF5bG9hZC5jYXRlZ29yeTpwYXlsb2FkLnByb3BlcnRpZXMuY2F0ZWdvcnk7Ly8gYWRkIG5hbWUgYW5kIGNhdGVnb3J5IHRvIHByb3BlcnRpZXNcbnBheWxvYWQucHJvcGVydGllcz1tZXJnZURlZXBSaWdodChpc09iamVjdExpdGVyYWxBbmROb3ROdWxsKHBheWxvYWQucHJvcGVydGllcyk/cGF5bG9hZC5wcm9wZXJ0aWVzOnt9LHsuLi4obmFtZUZvclByb3BlcnRpZXMmJntuYW1lOm5hbWVGb3JQcm9wZXJ0aWVzfSksLi4uKGNhdGVnb3J5Rm9yUHJvcGVydGllcyYme2NhdGVnb3J5OmNhdGVnb3J5Rm9yUHJvcGVydGllc30pfSk7cmV0dXJuIHBheWxvYWQ7fTsvKlxuICogTm9ybWFsaXNlIHRoZSBvdmVybG9hZGVkIGFyZ3VtZW50cyBvZiB0aGUgdHJhY2sgY2FsbCBmYWNhZGVcbiAqL2NvbnN0IHRyYWNrQXJndW1lbnRzVG9DYWxsT3B0aW9ucz0oZXZlbnQscHJvcGVydGllcyxvcHRpb25zLGNhbGxiYWNrKT0+e2NvbnN0IHBheWxvYWQ9e25hbWU6ZXZlbnQscHJvcGVydGllczpwcm9wZXJ0aWVzLG9wdGlvbnM6b3B0aW9ucyxjYWxsYmFjazp1bmRlZmluZWR9O2lmKGlzRnVuY3Rpb24oY2FsbGJhY2spKXtwYXlsb2FkLmNhbGxiYWNrPWNhbGxiYWNrO31pZihpc0Z1bmN0aW9uKG9wdGlvbnMpKXtwYXlsb2FkLnByb3BlcnRpZXM9cHJvcGVydGllcztwYXlsb2FkLm9wdGlvbnM9dW5kZWZpbmVkO3BheWxvYWQuY2FsbGJhY2s9b3B0aW9uczt9aWYoaXNGdW5jdGlvbihwcm9wZXJ0aWVzKSl7cGF5bG9hZC5wcm9wZXJ0aWVzPXVuZGVmaW5lZDtwYXlsb2FkLm9wdGlvbnM9dW5kZWZpbmVkO3BheWxvYWQuY2FsbGJhY2s9cHJvcGVydGllczt9Ly8gUmVzdCBvZiB0aGUgY29kZSBpcyBqdXN0IHRvIGNsZWFuIHVwIHVuZGVmaW5lZCB2YWx1ZXNcbi8vIGFuZCBzZXQgc29tZSBwcm9wZXIgZGVmYXVsdHNcbi8vIEFsc28sIHRvIGNsb25lIHRoZSBpbmNvbWluZyBvYmplY3QgdHlwZSBhcmd1bWVudHNcbnBheWxvYWQucHJvcGVydGllcz1pc0RlZmluZWRBbmROb3ROdWxsKHBheWxvYWQucHJvcGVydGllcyk/Y2xvbmUocGF5bG9hZC5wcm9wZXJ0aWVzKTp7fTtpZihpc0RlZmluZWQocGF5bG9hZC5vcHRpb25zKSl7cGF5bG9hZC5vcHRpb25zPWNsb25lKHBheWxvYWQub3B0aW9ucyk7fWVsc2Uge3BheWxvYWQub3B0aW9ucz11bmRlZmluZWQ7fXJldHVybi
1BwYXlsb2FkO307LypcbiAqIE5vcm1hbGlzZSB0aGUgb3ZlcmxvYWRlZCBhcmd1bWVudHMgb2YgdGhlIGlkZW50aWZ5IGNhbGwgZmFjYWRlXG4gKi9jb25zdCBpZGVudGlmeUFyZ3VtZW50c1RvQ2FsbE9wdGlvbnM9KHVzZXJJZCx0cmFpdHMsb3B0aW9ucyxjYWxsYmFjayk9Pntjb25zdCBwYXlsb2FkPXt1c2VySWQ6dXNlcklkLHRyYWl0czp0cmFpdHMsb3B0aW9uczpvcHRpb25zLGNhbGxiYWNrOnVuZGVmaW5lZH07aWYoaXNGdW5jdGlvbihjYWxsYmFjaykpe3BheWxvYWQuY2FsbGJhY2s9Y2FsbGJhY2s7fWlmKGlzRnVuY3Rpb24ob3B0aW9ucykpe3BheWxvYWQudXNlcklkPXVzZXJJZDtwYXlsb2FkLnRyYWl0cz10cmFpdHM7cGF5bG9hZC5vcHRpb25zPXVuZGVmaW5lZDtwYXlsb2FkLmNhbGxiYWNrPW9wdGlvbnM7fWlmKGlzRnVuY3Rpb24odHJhaXRzKSl7cGF5bG9hZC51c2VySWQ9dXNlcklkO3BheWxvYWQudHJhaXRzPXVuZGVmaW5lZDtwYXlsb2FkLm9wdGlvbnM9dW5kZWZpbmVkO3BheWxvYWQuY2FsbGJhY2s9dHJhaXRzO31pZihpc09iamVjdExpdGVyYWxBbmROb3ROdWxsKHVzZXJJZCl8fGlzTnVsbCh1c2VySWQpKXsvLyBFeHBsaWNpdGx5IHNldCBudWxsIHRvIHByZXZlbnQgcmVzZXR0aW5nIHRoZSBleGlzdGluZyB2YWx1ZVxuLy8gaW4gdGhlIEFuYWx5dGljcyBjbGFzc1xucGF5bG9hZC51c2VySWQ9bnVsbDtwYXlsb2FkLnRyYWl0cz11c2VySWQ7aWYoIWlzRnVuY3Rpb24odHJhaXRzKSl7cGF5bG9hZC5vcHRpb25zPXRyYWl0czt9ZWxzZSB7cGF5bG9hZC5vcHRpb25zPXVuZGVmaW5lZDt9fS8vIFJlc3Qgb2YgdGhlIGNvZGUgaXMganVzdCB0byBjbGVhbiB1cCB1bmRlZmluZWQgdmFsdWVzXG4vLyBhbmQgc2V0IHNvbWUgcHJvcGVyIGRlZmF1bHRzXG4vLyBBbHNvLCB0byBjbG9uZSB0aGUgaW5jb21pbmcgb2JqZWN0IHR5cGUgYXJndW1lbnRzXG5wYXlsb2FkLnVzZXJJZD10cnlTdHJpbmdpZnkocGF5bG9hZC51c2VySWQpO2lmKGlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwocGF5bG9hZC50cmFpdHMpKXtwYXlsb2FkLnRyYWl0cz1jbG9uZShwYXlsb2FkLnRyYWl0cyk7fWVsc2Uge3BheWxvYWQudHJhaXRzPXVuZGVmaW5lZDt9aWYoaXNEZWZpbmVkKHBheWxvYWQub3B0aW9ucykpe3BheWxvYWQub3B0aW9ucz1jbG9uZShwYXlsb2FkLm9wdGlvbnMpO31lbHNlIHtwYXlsb2FkLm9wdGlvbnM9dW5kZWZpbmVkO31yZXR1cm4gcGF5bG9hZDt9Oy8qXG4gKiBOb3JtYWxpc2UgdGhlIG92ZXJsb2FkZWQgYXJndW1lbnRzIG9mIHRoZSBhbGlhcyBjYWxsIGZhY2FkZVxuICovY29uc3QgYWxpYXNBcmd1bWVudHNUb0NhbGxPcHRpb25zPSh0byxmcm9tLG9wdGlvbnMsY2FsbGJhY2spPT57Y29uc3QgcGF5bG9hZD17dG8sZnJvbTpmcm9tLG9wdGlvbnM6b3B0aW9ucyxjYWxsYmFjazp1bmRlZmluZWR9O2lmKGlzRnVuY3Rpb24oY2FsbGJhY2spKXtwYXlsb2FkLmNhbGxiYWNrPWNhbGxiYWNrO31pZihpc0Z1bmN0aW9uKG9wdGlvbnMpKXtwYXlsb2FkLnRvPXRvO3BheWxvYWQuZnJvbT1mcm9tO3BheWxvYWQub3B0aW9ucz11bmRlZmluZWQ7cGF5bG9hZC5jYWxsYmFjaz1vcHRpb25zO31pZihpc0Z1bmN0aW9uKGZyb20pKXtwYXlsb2FkLnRvPXRvO3BheWxvYWQuZnJvbT11bmRlZmluZWQ7cGF5bG9hZC5vcHRpb25zPXVuZGVmaW5lZDtwYXlsb2FkLmNhbGxiYWNrPWZyb207fWVsc2UgaWYoaXNPYmplY3RMaXRlcmFsQW5kTm90TnVsbChmcm9tKXx8aXNOdWxsKGZyb20pKXtwYXlsb2FkLnRvPXRvO3BheWxvYWQuZnJvbT11bmRlZmluZWQ7cGF5bG9hZC5vcHRpb25zPWZyb207fS8vIFJlc3Qgb2YgdGhlIGNvZGUgaXMganVzdCB0byBjbGVhbiB1cCB1bmRlZmluZWQgdmFsdWVzXG4vLyBhbmQgc2V0IHNvbWUgcHJvcGVyIGRlZmF1bHRzXG4vLyBBbHNvLCB0byBjbG9uZSB0aGUgaW5jb21pbmcgb2JqZWN0IHR5cGUgYXJndW1lbnRzXG5pZihpc0RlZmluZWQocGF5bG9hZC50bykpe3BheWxvYWQudG89dHJ5U3RyaW5naWZ5KHBheWxvYWQudG8pO31pZihpc0RlZmluZWQocGF5bG9hZC5mcm9tKSl7cGF5bG9hZC5mcm9tPXRyeVN0cmluZ2lmeShwYXlsb2FkLmZyb20pO31lbHNlIHtwYXlsb2FkLmZyb209dW5kZWZpbmVkO31pZihpc0RlZmluZWQocGF5bG9hZC5vcHRpb25zKSl7cGF5bG9hZC5vcHRpb25zPWNsb25lKHBheWxvYWQub3B0aW9ucyk7fWVsc2Uge3BheWxvYWQub3B0aW9ucz11bmRlZmluZWQ7fXJldHVybiBwYXlsb2FkO307LypcbiAqIE5vcm1hbGlzZSB0aGUgb3ZlcmxvYWRlZCBhcmd1bWVudHMgb2YgdGhlIGdyb3VwIGNhbGwgZmFjYWRlXG4gKi9jb25zdCBncm91cEFyZ3VtZW50c1RvQ2FsbE9wdGlvbnM9KGdyb3VwSWQsdHJhaXRzLG9wdGlvbnMsY2FsbGJhY2spPT57Y29uc3QgcGF5bG9hZD17Z3JvdXBJZDpncm91cElkLHRyYWl0czp0cmFpdHMsb3B0aW9uczpvcHRpb25zLGNhbGxiYWNrOnVuZGVmaW5lZH07aWYoaXNGdW5jdGlvbihjYWxsYmFjaykpe3BheWxvYWQuY2FsbGJhY2s9Y2FsbGJhY2s7fWlmKGlzRnVuY3Rpb24ob3B0aW9ucykpe3BheWxvYWQuZ3JvdXBJZD1ncm91cElkO3BheWxvYWQudHJhaXRzPXRyYWl0cztwYXlsb2FkLm9wdGlvbnM9dW5kZWZpbmVkO3BheWxvYWQuY2FsbGJhY2s9b3B0aW9uczt9aWYoaXNGdW5jdGlvbih0cmFpdHMpKXtwYXlsb2FkLmdyb3VwSWQ9Z3JvdXBJZDtwYXlsb2FkLnRyYWl0cz11bmRlZmluZWQ7cGF5bG9hZC5vcHRpb25zPXVuZGVmaW5lZDtwYXlsb2FkLmNhbGxiYWNrPXRyYWl0czt9aWYoaXNPYmplY3RMaXRlcmFsQW5kTm90TnVsbChncm91cElkKXx8aXNOdWxsKGdyb3VwSWQpKXsvLyBFeHBsaWNpdGx5IHNldCBudWxsIHRvIHByZXZlbnQgcmVzZXR0aW5nIHRoZSBleGlzdGluZyB2YWx1ZVxuLy8gaW4gdGhlIEFuYWx5dGljcyBjbGFzc1xucGF5bG9hZC5ncm91cElkPW51bGw7cGF5bG9hZC50cmFpdHM9Z3JvdXBJZDtpZighaXNGdW5jdGlvbih0cmFpdHMpKXtwYXlsb2FkLm9wdGlvbnM9dHJhaXRzO31lbHNlIHtwYXlsb2FkLm9wdGlvbnM9dW5kZWZpbmVkO319Ly8gUmVzdCBvZiB0aGUgY29kZSBpcyBqdXN0IHRvIGNsZWFuIHVwIHVuZGVmaW5lZCB2YWx1ZXNcbi8vIGFuZCBzZXQgc29tZSBwcm9wZXIgZGVmYXVsdHNcbi8vIEFsc28sIHRvIGNsb25lIHRoZSBpbmNvbWluZyBvYmplY3QgdHlwZSBhcmd1bWVudHNcbnBheWxvYWQuZ3JvdXBJZD10cnlTdHJpbmdpZnkocGF5bG9hZC5ncm91cElkKTtpZihpc09iamVjdExpdGVyYWxBbmROb3ROdWxsKHBheWxvYWQudHJhaXRzKSl7cGF5bG9hZC50cmFpdHM9Y2xvbmUocGF5bG9hZC50cmFpdHMpO31lbHNlIHtwYXlsb2FkLnRyYWl0cz11bmRlZmluZWQ7fWlmKGlzRGVmaW5lZChwYXlsb2FkLm9wdGlvbnMpKXtwYXlsb2FkLm9wdGlvbnM9Y2xvbmUocGF5bG9hZC5vcHRpb25zKTt9ZWxzZSB7cGF5bG9hZC5vcHRpb25zPXVuZGVmaW5lZDt9cmV0dXJuIHBheWxvYWQ7fTtcblxuLyoqXG4gKiBSZXByZXNlbnRzIHRoZSBvcHRpb25zIHBhcmFtZXRlciBmb3IgYW5vbnltb3VzSWRcbiAqLy8qKlxuICogUmVwcmVzZW50cyB0aGUgYmVhY29uIHF1ZXVlIG9wdGlvbnMgcGFyYW1ldGVyIGluIGxvYWRPcHRpb25zIHR5cGVcbiAqLy8qKlxuICogUmVwcmVzZW50cyB0aGUgcXVldWUgb3B0aW9ucyBwYXJhbWV0ZXIgaW4gbG9hZE9wdGlvbnMgdHlwZVxuICovLyoqXG4gKiBSZXByZXNlbnRzIHRoZSBkZXN0aW5
1hdGlvbnMgcXVldWUgb3B0aW9ucyBwYXJhbWV0ZXIgaW4gbG9hZE9wdGlvbnMgdHlwZVxuICovbGV0IFBhZ2VMaWZlY3ljbGVFdmVudHM9LyojX19QVVJFX18qL2Z1bmN0aW9uKFBhZ2VMaWZlY3ljbGVFdmVudHMpe1BhZ2VMaWZlY3ljbGVFdmVudHNbXCJVTkxPQURFRFwiXT1cIlBhZ2UgVW5sb2FkZWRcIjtyZXR1cm4gUGFnZUxpZmVjeWNsZUV2ZW50czt9KHt9KTsvKipcbiAqIFJlcHJlc2VudHMgdGhlIHNvdXJjZSBjb25maWd1cmF0aW9uIG92ZXJyaWRlIG9wdGlvbnMgZm9yIGRlc3RpbmF0aW9uc1xuICovLyoqXG4gKiBSZXByZXNlbnRzIHRoZSBvcHRpb25zIHBhcmFtZXRlciBpbiB0aGUgbG9hZCBBUElcbiAqL1xuXG5jb25zdCBBUElfU1VGRklYPSdBUEknO2NvbnN0IENBUEFCSUxJVElFU19NQU5BR0VSPSdDYXBhYmlsaXRpZXNNYW5hZ2VyJztjb25zdCBDT05GSUdfTUFOQUdFUj0nQ29uZmlnTWFuYWdlcic7Y29uc3QgRVZFTlRfTUFOQUdFUj0nRXZlbnRNYW5hZ2VyJztjb25zdCBQTFVHSU5TX01BTkFHRVI9J1BsdWdpbnNNYW5hZ2VyJztjb25zdCBVU0VSX1NFU1NJT05fTUFOQUdFUj0nVXNlclNlc3Npb25NYW5hZ2VyJztjb25zdCBFUlJPUl9IQU5ETEVSPSdFcnJvckhhbmRsZXInO2NvbnN0IFBMVUdJTl9FTkdJTkU9J1BsdWdpbkVuZ2luZSc7Y29uc3QgU1RPUkVfTUFOQUdFUj0nU3RvcmVNYW5hZ2VyJztjb25zdCBSRUFEWV9BUEk9YFJlYWR5JHtBUElfU1VGRklYfWA7Y29uc3QgTE9BRF9BUEk9YExvYWQke0FQSV9TVUZGSVh9YDtjb25zdCBIVFRQX0NMSUVOVD0nSHR0cENsaWVudCc7Y29uc3QgUlNBPSdSdWRkZXJTdGFja0FuYWx5dGljcyc7Y29uc3QgQU5BTFlUSUNTX0NPUkU9J0FuYWx5dGljc0NvcmUnO1xuXG5mdW5jdGlvbiByYW5kb20obGVuKXtyZXR1cm4gY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhuZXcgVWludDhBcnJheShsZW4pKTt9XG5cbnZhciBTSVpFPTQwOTYsSEVYJDE9W10sSURYJDE9MCxCVUZGRVIkMTtmb3IoO0lEWCQxPDI1NjtJRFgkMSsrKXtIRVgkMVtJRFgkMV09KElEWCQxKzI1NikudG9TdHJpbmcoMTYpLnN1YnN0cmluZygxKTt9ZnVuY3Rpb24gdjQkMSgpe2lmKCFCVUZGRVIkMXx8SURYJDErMTY+U0laRSl7QlVGRkVSJDE9cmFuZG9tKFNJWkUpO0lEWCQxPTA7fXZhciBpPTAsdG1wLG91dD0nJztmb3IoO2k8MTY7aSsrKXt0bXA9QlVGRkVSJDFbSURYJDEraV07aWYoaT09NilvdXQrPUhFWCQxW3RtcCYxNXw2NF07ZWxzZSBpZihpPT04KW91dCs9SEVYJDFbdG1wJjYzfDEyOF07ZWxzZSBvdXQrPUhFWCQxW3RtcF07aWYoaSYxJiZpPjEmJmk8MTEpb3V0Kz0nLSc7fUlEWCQxKz0xNjtyZXR1cm4gb3V0O31cblxudmFyIElEWD0yNTYsSEVYPVtdLEJVRkZFUjt3aGlsZShJRFgtLSlIRVhbSURYXT0oSURYKzI1NikudG9TdHJpbmcoMTYpLnN1YnN0cmluZygxKTtmdW5jdGlvbiB2NCgpe3ZhciBpPTAsbnVtLG91dD0nJztpZighQlVGRkVSfHxJRFgrMTY+MjU2KXtCVUZGRVI9QXJyYXkoaT0yNTYpO3doaWxlKGktLSlCVUZGRVJbaV09MjU2Kk1hdGgucmFuZG9tKCl8MDtpPUlEWD0wO31mb3IoO2k8MTY7aSsrKXtudW09QlVGRkVSW0lEWCtpXTtpZihpPT02KW91dCs9SEVYW251bSYxNXw2NF07ZWxzZSBpZihpPT04KW91dCs9SEVYW251bSY2M3wxMjhdO2Vsc2Ugb3V0Kz1IRVhbbnVtXTtpZihpJjEmJmk+MSYmaTwxMSlvdXQrPSctJzt9SURYKys7cmV0dXJuIG91dDt9XG5cbmNvbnN0IGhhc0NyeXB0byQxPSgpPT4haXNOdWxsT3JVbmRlZmluZWQoZ2xvYmFsVGhpcy5jcnlwdG8pJiZpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyk7XG5cbmNvbnN0IGdlbmVyYXRlVVVJRD0oKT0+e2lmKGhhc0NyeXB0byQxKCkpe3JldHVybiB2NCQxKCk7fXJldHVybiB2NCgpO307XG5cbi8qKlxuICogRGV0ZXJtaW5lcyBpZiB0aGUgU0RLIGlzIHJ1bm5pbmcgaW5zaWRlIGEgY2hyb21lIGV4dGVuc2lvblxuICogQHJldHVybnMgYm9vbGVhblxuICovY29uc3QgaXNTREtSdW5uaW5nSW5DaHJvbWVFeHRlbnNpb249KCk9PiEhd2luZG93LmNocm9tZT8ucnVudGltZT8uaWQ7Y29uc3QgaXNJRTExPSgpPT5pc1N0cmluZyhnbG9iYWxUaGlzLm5hdmlnYXRvci51c2VyQWdlbnQpJiYvVHJpZGVudC4qcnY6MTFcXC4vLnRlc3QoZ2xvYmFsVGhpcy5uYXZpZ2F0b3IudXNlckFnZW50KTtcblxuLyoqXG4gKiBSZWdpc3RlcnMgZXZlbnRzIHRvIGRldGVjdCBwYWdlIGxlYXZlIHNjZW5hcmlvc1xuICogQHBhcmFtIGNhbGxiYWNrIENhbGxiYWNrIGZ1bmN0aW9uXG4gKiBAcGFyYW0gYXZvaWRCZkNhY2hlT3B0aW1pemF0aW9uIFdoZW4gYHRydWVgLCBmb3JjZWZ1bGx5IHN1YnNjcmliZXMgdG8gYmVmb3JldW5sb2FkIGV2ZW50LCBjb21wcm9taXNpbmcgb24gdGhlIGJmY2FjaGUgb3B0aW1pemF0aW9uXG4gKi9jb25zdCBvblBhZ2VMZWF2ZT0oY2FsbGJhY2ssYXZvaWRCZkNhY2hlT3B0aW1pemF0aW9uPWZhbHNlKT0+ey8vIFRvIGVuc3VyZSB0aGUgY2FsbGJhY2sgaXMgb25seSBjYWxsZWQgb25jZSBldmVuIGlmIG1vcmUgdGhhbiBvbmUgZXZlbnRzXG4vLyBhcmUgZmlyZWQgYXQgb25jZS5cbmxldCBwYWdlTGVmdD1mYWxzZTtsZXQgaXNBY2Nlc3NpYmxlPWZhbHNlO2Z1bmN0aW9uIGhhbmRsZU9uTGVhdmUoKXtpZihwYWdlTGVmdCl7cmV0dXJuO31wYWdlTGVmdD10cnVlO2NhbGxiYWNrKGlzQWNjZXNzaWJsZSk7Ly8gUmVzZXQgcGFnZUxlZnQgb24gdGhlIG5leHQgdGlja1xuLy8gdG8gZW5zdXJlIGNhbGxiYWNrIGV4ZWN1dGVzIGZvciBvdGhlciBsaXN0ZW5lcnNcbi8vIHdoZW4gY2xvc2luZyBhbiBpbmFjdGl2ZSBicm93c2VyIHRhYi5cbnNldFRpbWVvdXQoKCk9PntwYWdlTGVmdD1mYWxzZTt9LDApO30vLyBDYXRjaGVzIHRoZSB1bmxvYWRpbmcgb2YgdGhlIHBhZ2UgKGUuZy4sIGNsb3NpbmcgdGhlIHRhYiBvciBuYXZpZ2F0aW5nIGF3YXkpLlxuLy8gSW5jbHVkZXMgdXNlciBhY3Rpb25zIGxpa2UgY2xpY2tpbmcgYSBsaW5rLCBlbnRlcmluZyBhIG5ldyBVUkwsXG4vLyByZWZyZXNoaW5nIHRoZSBwYWdlLCBvciBjbG9zaW5nIHRoZSBicm93c2VyIHRhYlxuLy8gTm90ZSB0aGF0ICdwYWdlaGlkZScgaXMgbm90IHN1cHBvcnRlZCBpbiBJRS5cbi8vIFJlZ2lzdGVyaW5nIHRoaXMgZXZlbnQgY29uZGl0aW9uYWxseSBmb3IgSUUxMSBhbHNvIGJlY2F1c2Vcbi8vIGl0IGFmZmVjdHMgYmZjYWNoZSBvcHRpbWl6YXRpb24gb24gbW9kZXJuIGJyb3dzZXJzIG90aGVyd2lzZS5cbi8vIEhvd2V2ZXIsIGlmIG9wdGltaXphdGlvbiBpcyBkaXNhYmxlZCwgZm9yY2Ugc3Vic2NyaWJlIHRoZSBldmVudFxuaWYoYXZvaWRCZkNhY2hlT3B0aW1pemF0aW9ufHxpc0lFMTEoKSl7Z2xvYmFsVGh
1pcy5hZGRFdmVudExpc3RlbmVyKCdiZWZvcmV1bmxvYWQnLCgpPT57aXNBY2Nlc3NpYmxlPWZhbHNlO2hhbmRsZU9uTGVhdmUoKTt9KTt9Ly8gVGhpcyBpcyBpbXBvcnRhbnQgZm9yIGlPUyBTYWZhcmkgYnJvd3NlciBhcyBpdCBkb2VzIG5vdFxuLy8gZmlyZSB0aGUgcmVndWxhciBwYWdlaGlkZSBhbmQgdmlzaWJpbGl0eWNoYW5nZSBldmVudHNcbi8vIHdoZW4gdXNlciBnb2VzIHRvIHRhYmxpc3QgdmlldyBhbmQgY2xvc2VzIHRoZSB0YWIuXG5nbG9iYWxUaGlzLmFkZEV2ZW50TGlzdGVuZXIoJ2JsdXInLCgpPT57aXNBY2Nlc3NpYmxlPXRydWU7aGFuZGxlT25MZWF2ZSgpO30pO2dsb2JhbFRoaXMuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXMnLCgpPT57cGFnZUxlZnQ9ZmFsc2U7fSk7Ly8gQ2F0Y2hlcyB0aGUgcGFnZSBiZWluZyBoaWRkZW4sIGluY2x1ZGluZyBzY2VuYXJpb3MgbGlrZSBjbG9zaW5nIHRoZSB0YWIuXG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdwYWdlaGlkZScsKCk9Pntpc0FjY2Vzc2libGU9ZG9jdW1lbnQudmlzaWJpbGl0eVN0YXRlPT09J2hpZGRlbic7aGFuZGxlT25MZWF2ZSgpO30pOy8vIENhdGNoZXMgdmlzaWJpbGl0eSBjaGFuZ2VzLCBzdWNoIGFzIHN3aXRjaGluZyB0YWJzIG9yIG1pbmltaXppbmcgdGhlIGJyb3dzZXIuXG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCd2aXNpYmlsaXR5Y2hhbmdlJywoKT0+e2lzQWNjZXNzaWJsZT10cnVlO2lmKGRvY3VtZW50LnZpc2liaWxpdHlTdGF0ZT09PSdoaWRkZW4nKXtoYW5kbGVPbkxlYXZlKCk7fWVsc2Uge3BhZ2VMZWZ0PWZhbHNlO319KTt9O1xuXG5jb25zdCBnZXRGb3JtYXR0ZWRUaW1lc3RhbXA9ZGF0ZT0+ZGF0ZS50b0lTT1N0cmluZygpOy8qKlxuICogVG8gZ2V0IHRoZSBjdXJyZW50IHRpbWVzdGFtcCBpbiBJU08gc3RyaW5nIGZvcm1hdFxuICogQHJldHVybnMgSVNPIGZvcm1hdHRlZCB0aW1lc3RhbXAgc3RyaW5nXG4gKi9jb25zdCBnZXRDdXJyZW50VGltZUZvcm1hdHRlZD0oKT0+Z2V0Rm9ybWF0dGVkVGltZXN0YW1wKG5ldyBEYXRlKCkpO1xuXG5jb25zdCBMT0dfQ09OVEVYVF9TRVBBUkFUT1I9Jzo6ICc7Y29uc3QgU0NSSVBUX0FMUkVBRFlfRVhJU1RTX0VSUk9SPWlkPT5gQSBzY3JpcHQgd2l0aCB0aGUgaWQgXCIke2lkfVwiIGlzIGFscmVhZHkgbG9hZGVkLiBTa2lwcGluZyB0aGUgbG9hZGluZyBvZiB0aGlzIHNjcmlwdCB0byBwcmV2ZW50IGNvbmZsaWN0c2A7Y29uc3QgU0NSSVBUX0xPQURfRVJST1I9KGlkLHVybCxldik9PmBVbmFibGUgdG8gbG9hZCAoJHtpc1N0cmluZyhldik/ZXY6ZXYudHlwZX0pIHRoZSBzY3JpcHQgd2l0aCB0aGUgaWQgXCIke2lkfVwiIGZyb20gVVJMIFwiJHt1cmx9XCJgO2NvbnN0IFNDUklQVF9MT0FEX1RJTUVPVVRfRVJST1I9KGlkLHVybCx0aW1lb3V0KT0+YEEgdGltZW91dCBvZiAke3RpbWVvdXR9IG1zIG9jY3VycmVkIHdoaWxlIHRyeWluZyB0byBsb2FkIHRoZSBzY3JpcHQgd2l0aCBpZCBcIiR7aWR9XCIgZnJvbSBVUkwgXCIke3VybH1cImA7Y29uc3QgQ0lSQ1VMQVJfUkVGRVJFTkNFX1dBUk5JTkc9KGNvbnRleHQsa2V5KT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1BIGNpcmN1bGFyIHJlZmVyZW5jZSBoYXMgYmVlbiBkZXRlY3RlZCBpbiB0aGUgb2JqZWN0IGFuZCB0aGUgcHJvcGVydHkgXCIke2tleX1cIiBoYXMgYmVlbiBkcm9wcGVkIGZyb20gdGhlIG91dHB1dC5gO2NvbnN0IEpTT05fU1RSSU5HSUZZX1dBUk5JTkc9YEZhaWxlZCB0byBjb252ZXJ0IHRoZSB2YWx1ZSB0byBhIEpTT04gc3RyaW5nLmA7Y29uc3QgQ09PS0lFX0RBVEFfRU5DT0RJTkdfRVJST1I9YEZhaWxlZCB0byBlbmNvZGUgdGhlIGNvb2tpZSBkYXRhLmA7Y29uc3QgU1RPUkFHRV9VTkFWQUlMQUJJTElUWV9FUlJPUl9QUkVGSVg9KGNvbnRleHQsc3RvcmFnZVR5cGUpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBcIiR7c3RvcmFnZVR5cGV9XCIgc3RvcmFnZSB0eXBlIGlzIGA7XG5cbmNvbnN0IEpTT05fU1RSSU5HSUZZPSdKU09OU3RyaW5naWZ5Jztjb25zdCBCSUdfSU5UX1BMQUNFSE9MREVSPSdbQmlnSW50XSc7Y29uc3QgQ0lSQ1VMQVJfUkVGRVJFTkNFX1BMQUNFSE9MREVSPSdbQ2lyY3VsYXIgUmVmZXJlbmNlXSc7Y29uc3QgZ2V0Q2lyY3VsYXJSZXBsYWNlcj0oZXhjbHVkZU51bGwsZXhjbHVkZUtleXMsbG9nZ2VyKT0+e2NvbnN0IGFuY2VzdG9ycz1bXTsvLyBIZXJlIHdlIGRvIG5vdCB3YW50IHRvIHVzZSBhcnJvdyBmdW5jdGlvbiB0byB1c2UgXCJ0aGlzXCIgaW4gZnVuY3Rpb24gY29udGV4dFxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGZ1bmMtbmFtZXNcbnJldHVybiBmdW5jdGlvbihrZXksdmFsdWUpe2lmKGV4Y2x1ZGVLZXlzPy5pbmNsdWRlcyhrZXkpKXtyZXR1cm4gdW5kZWZpbmVkO31pZihleGNsdWRlTnVsbCYmaXNOdWxsT3JVbmRlZmluZWQodmFsdWUpKXtyZXR1cm4gdW5kZWZpbmVkO31pZih0eXBlb2YgdmFsdWUhPT0nb2JqZWN0J3x8aXNOdWxsKHZhbHVlKSl7cmV0dXJuIHZhbHVlO30vLyBgdGhpc2AgaXMgdGhlIG9iamVjdCB0aGF0IHZhbHVlIGlzIGNvbnRhaW5lZCBpbiwgaS5lLiwgaXRzIGRpcmVjdCBwYXJlbnQuXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50XG4vLyBAdHMtaWdub3JlLW5leHQtbGluZVxud2hpbGUoYW5jZXN0b3JzLmxlbmd0aD4wJiZhbmNlc3RvcnNbYW5jZXN0b3JzLmxlbmd0aC0xXSE9PXRoaXMpe2FuY2VzdG9ycy5wb3AoKTt9aWYoYW5jZXN0b3JzLmluY2x1ZGVzKHZhbHVlKSl7bG9nZ2VyPy53YXJuKENJUkNVTEFSX1JFRkVSRU5DRV9XQVJOSU5HKEpTT05fU1RSSU5HSUZZLGtleSkpO3JldHVybiBDSVJDVUxBUl9SRUZFUkVOQ0VfUExBQ0VIT0xERVI7fWFuY2VzdG9ycy5wdXNoKHZhbHVlKTtyZXR1cm4gdmFsdWU7fTt9Oy8qKlxuICogVXRpbGl0eSBtZXRob2QgZm9yIEpTT04gc3RyaW5naWZ5IG9iamVjdCBleGNsdWRpbmcgbnVsbCB2YWx1ZXMgJiBjaXJjdWxhciByZWZlcmVuY2VzXG4gKlxuICogQHBhcmFtIHsqfSB2YWx1ZSBpbnB1dFxuICogQHBhcmFtIHtib29sZWFufSBleGNsdWRlTnVsbCBpZiBpdCBzaG91bGQgZXhjbHVkZSBudWwgb3Igbm90XG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBsb2dnZXIgb3B0aW9uYWwgbG9nZ2VyIG1ldGhvZHMgZm9yIHdhcm5pbmdcbiAqIEByZXR1cm5zIHN0cmluZ1xuICovY29uc3Qgc3RyaW5naWZ5V2l0aG91dENpcmN1bGFyPSh2YWx1ZSxleGNsdWRlTnVsbCxleGNsdWRlS2V5cyxsb2dnZXIpPT57
1dHJ5e3JldHVybiBKU09OLnN0cmluZ2lmeSh2YWx1ZSxnZXRDaXJjdWxhclJlcGxhY2VyKGV4Y2x1ZGVOdWxsLGV4Y2x1ZGVLZXlzLGxvZ2dlcikpO31jYXRjaChlcnIpe2xvZ2dlcj8ud2FybihKU09OX1NUUklOR0lGWV9XQVJOSU5HLGVycik7cmV0dXJuIG51bGw7fX07Y29uc3QgZ2V0UmVwbGFjZXI9bG9nZ2VyPT57Y29uc3QgYW5jZXN0b3JzPVtdOy8vIEFycmF5IHRvIHRyYWNrIGFuY2VzdG9yIG9iamVjdHNcbi8vIFVzaW5nIGEgcmVndWxhciBmdW5jdGlvbiB0byB1c2UgYHRoaXNgIGZvciB0aGUgcGFyZW50IGNvbnRleHRcbnJldHVybiBmdW5jdGlvbiByZXBsYWNlcihrZXksdmFsdWUpe2lmKGlzQmlnSW50KHZhbHVlKSl7cmV0dXJuIEJJR19JTlRfUExBQ0VIT0xERVI7Ly8gUmVwbGFjZSBCaWdJbnQgdmFsdWVzXG59Ly8gYHRoaXNgIGlzIHRoZSBvYmplY3QgdGhhdCB2YWx1ZSBpcyBjb250YWluZWQgaW4sIGkuZS4sIGl0cyBkaXJlY3QgcGFyZW50LlxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9iYW4tdHMtY29tbWVudFxuLy8gQHRzLWlnbm9yZS1uZXh0LWxpbmVcbndoaWxlKGFuY2VzdG9ycy5sZW5ndGg+MCYmYW5jZXN0b3JzW2FuY2VzdG9ycy5sZW5ndGgtMV0hPT10aGlzKXthbmNlc3RvcnMucG9wKCk7Ly8gUmVtb3ZlIGFuY2VzdG9ycyB0aGF0IGFyZSBubyBsb25nZXIgcGFydCBvZiB0aGUgY2hhaW5cbn0vLyBDaGVjayBmb3IgY2lyY3VsYXIgcmVmZXJlbmNlcyAoaWYgdGhlIHZhbHVlIGlzIGFscmVhZHkgaW4gdGhlIGFuY2VzdG9ycylcbmlmKGFuY2VzdG9ycy5pbmNsdWRlcyh2YWx1ZSkpe3JldHVybiBDSVJDVUxBUl9SRUZFUkVOQ0VfUExBQ0VIT0xERVI7fS8vIEFkZCBjdXJyZW50IHZhbHVlIHRvIGFuY2VzdG9yc1xuYW5jZXN0b3JzLnB1c2godmFsdWUpO3JldHVybiB2YWx1ZTt9O307Y29uc3QgdHJhdmVyc2VXaXRoVGhpcz0ob2JqLHJlcGxhY2VyKT0+ey8vIENyZWF0ZSBhIG5ldyByZXN1bHQgb2JqZWN0IG9yIGFycmF5XG5jb25zdCByZXN1bHQ9QXJyYXkuaXNBcnJheShvYmopP1tdOnt9Oy8vIFRyYXZlcnNlIG9iamVjdCBwcm9wZXJ0aWVzIG9yIGFycmF5IGVsZW1lbnRzXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcmVzdHJpY3RlZC1zeW50YXhcbmZvcihjb25zdCBrZXkgaW4gb2JqKXtpZihPYmplY3QuaGFzT3duUHJvcGVydHkuY2FsbChvYmosa2V5KSl7Y29uc3QgdmFsdWU9b2JqW2tleV07Ly8gUmVjdXJzaXZlbHkgYXBwbHkgdGhlIHJlcGxhY2VyIGFuZCB0cmF2ZXJzYWxcbmNvbnN0IHNhbml0aXplZFZhbHVlPXJlcGxhY2VyLmNhbGwob2JqLGtleSx2YWx1ZSk7Ly8gSWYgdGhlIHZhbHVlIGlzIGFuIG9iamVjdCBvciBhcnJheSwgY29udGludWUgdHJhdmVyc2FsXG5pZihpc09iamVjdExpdGVyYWxBbmROb3ROdWxsKHNhbml0aXplZFZhbHVlKXx8QXJyYXkuaXNBcnJheShzYW5pdGl6ZWRWYWx1ZSkpe3Jlc3VsdFtrZXldPXRyYXZlcnNlV2l0aFRoaXMoc2FuaXRpemVkVmFsdWUscmVwbGFjZXIpO31lbHNlIHtyZXN1bHRba2V5XT1zYW5pdGl6ZWRWYWx1ZTt9fX1yZXR1cm4gcmVzdWx0O307LyoqXG4gKiBSZWN1cnNpdmVseSB0cmF2ZXJzZXMgYW4gb2JqZWN0IHNpbWlsYXIgdG8gSlNPTi5zdHJpbmdpZnksXG4gKiBzYW5pdGl6aW5nIEJpZ0ludHMgYW5kIGNpcmN1bGFyIHJlZmVyZW5jZXNcbiAqIEBwYXJhbSB2YWx1ZSBJbnB1dCBvYmplY3RcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gKiBAcmV0dXJucyBTYW5pdGl6ZWQgdmFsdWVcbiAqL2NvbnN0IGdldFNhbml0aXplZFZhbHVlPSh2YWx1ZSxsb2dnZXIpPT57Y29uc3QgcmVwbGFjZXI9Z2V0UmVwbGFjZXIoKTsvLyBUaGlzIGlzIG5lZWRlZCBmb3IgcmVnaXN0ZXJpbmcgdGhlIGZpcnN0IGFuY2VzdG9yXG5jb25zdCBuZXdWYWx1ZT1yZXBsYWNlci5jYWxsKHZhbHVlLCcnLHZhbHVlKTtpZihpc09iamVjdExpdGVyYWxBbmROb3ROdWxsKHZhbHVlKXx8QXJyYXkuaXNBcnJheSh2YWx1ZSkpe3JldHVybiB0cmF2ZXJzZVdpdGhUaGlzKHZhbHVlLHJlcGxhY2VyKTt9cmV0dXJuIG5ld1ZhbHVlO307XG5cbmNvbnN0IE1BTlVBTF9FUlJPUl9JREVOVElGSUVSPSdbU0RLIERJU1BBVENIRUQgRVJST1JdJztjb25zdCBnZXRTdGFja3RyYWNlPWVycj0+e2NvbnN0e3N0YWNrfT1lcnI7aWYodHlwZW9mIHN0YWNrPT09J3N0cmluZycmJnN0YWNrKXtyZXR1cm4gc3RhY2s7fXJldHVybiB1bmRlZmluZWQ7fTsvKipcbiAqIEdldCBtdXRhdGVkIGVycm9yIHdpdGggaXNzdWUgcHJlcGVuZGVkIHRvIGVycm9yIG1lc3NhZ2VcbiAqIEBwYXJhbSBlcnIgT3JpZ2luYWwgZXJyb3JcbiAqIEBwYXJhbSBpc3N1ZSBJc3N1ZSB0byBwcmVwZW5kIHRvIGVycm9yIG1lc3NhZ2VcbiAqIEByZXR1cm5zIEluc3RhbmNlIG9mIEVycm9yIHdpdGggbWVzc2FnZSBwcmVwZW5kZWQgd2l0aCBpc3N1ZVxuICovY29uc3QgZ2V0TXV0YXRlZEVycm9yPShlcnIsaXNzdWUpPT57aWYoIWlzVHlwZU9mRXJyb3IoZXJyKSl7cmV0dXJuIG5ldyBFcnJvcihgJHtpc3N1ZX06ICR7c3RyaW5naWZ5V2l0aG91dENpcmN1bGFyKGVycil9YCk7fXRyeXsvLyBQcmVzZXJ2ZSB0aGUgc3BlY2lmaWMgZXJyb3IgdHlwZSAoVHlwZUVycm9yLCBSZWZlcmVuY2VFcnJvciwgZXRjLilcbmNvbnN0IEVycm9yQ29uc3RydWN0b3I9ZXJyLmNvbnN0cnVjdG9yO2NvbnN0IG5ld0Vycm9yPW5ldyBFcnJvckNvbnN0cnVjdG9yKGAke2lzc3VlfTogJHtlcnIubWVzc2FnZX1gKTsvLyBQcmVzZXJ2ZSBzdGFjayB0cmFjZVxuY29uc3Qgc3RhY2s9Z2V0U3RhY2t0cmFjZShlcnIpO2lmKHN0YWNrKXtuZXdFcnJvci5zdGFjaz1zdGFjazt9Ly8gUHJlc2VydmUgYW55IG90aGVyIGVudW1lcmFibGUgcHJvcGVydGllc1xuT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoZXJyKS5mb3JFYWNoKGtleT0+e2lmKGtleSE9PSdtZXNzYWdlJyYma2V5IT09J3N0YWNrJyYma2V5IT09J25hbWUnKXt0cnl7bmV3RXJyb3Jba2V5XT1lcnJba2V5XTt9Y2F0Y2h7Ly8gSWdub3JlIGlmIHByb3BlcnR5IGlzIG5vdCB3cml0YWJsZVxufX19KTtyZXR1cm4gbmV3RXJyb3I7fWNhdGNoe3JldHVybiBuZXcgRXJyb3IoYCR7aXNzdWV9OiAke3N0cmluZ2lmeVdpdGhvdXRDaXJjdWxhcihlcnIpfWApO319O2NvbnN0IGRpc3BhdGNoRXJyb3JFdmVudD1lcnJvcj0+e2lmKGlzVHlwZU9mRXJyb3IoZXJyb3IpKXtjb25zdCBlcnJTdGFjaz1nZXRTdGFja3RyYWNlKGVycm9yKTtpZihlcnJTdGFjayl7Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXBhcmFtLXJlYXNzaWduXG5lcnJvci5zdGFjaz1gJHtlcnJTdGFja31cXG4ke01BTlVBTF9FUlJPUl9JREVOVElGSUVSfWA7fX1nbG9iYWxUaGlzLmRpc3BhdGNoRXZlbnQobmV3IEVycm9yRXZlbnQoJ2Vycm9yJyx7ZXJyb3IsYnViYmxlczp0cnVlLGNhbmNlbGFibG
1U6dHJ1ZSxjb21wb3NlZDp0cnVlfSkpO307XG5cbmNvbnN0IEFQUF9OQU1FPSdSdWRkZXJMYWJzIEphdmFTY3JpcHQgU0RLJztjb25zdCBBUFBfVkVSU0lPTj0nMy4zMS40Jztjb25zdCBBUFBfTkFNRVNQQUNFPSdjb20ucnVkZGVybGFicy5qYXZhc2NyaXB0Jztjb25zdCBNT0RVTEVfVFlQRT0nbnBtJztjb25zdCBCVUlMRF9WQVJJQU5UPSdidW5kbGVkJztjb25zdCBBREJMT0NLX1BBR0VfQ0FURUdPUlk9J1J1ZGRlckpTLUluaXRpYXRlZCc7Y29uc3QgQURCTE9DS19QQUdFX05BTUU9J2FkLWJsb2NrIHBhZ2UgcmVxdWVzdCc7Y29uc3QgQURCTE9DS19QQUdFX1BBVEg9Jy9hZC1ibG9ja2VkJztjb25zdCBHTE9CQUxfUFJFTE9BRF9CVUZGRVI9J3ByZWxvYWRlZEV2ZW50c0J1ZmZlcic7Y29uc3QgQ09OU0VOVF9UUkFDS19FVkVOVF9OQU1FPSdDb25zZW50IE1hbmFnZW1lbnQgSW50ZXJhY3Rpb24nO1xuXG5jb25zdCBRVUVSWV9QQVJBTV9UUkFJVF9QUkVGSVg9J2Fqc190cmFpdF8nO2NvbnN0IFFVRVJZX1BBUkFNX1BST1BFUlRZX1BSRUZJWD0nYWpzX3Byb3BfJztjb25zdCBRVUVSWV9QQVJBTV9BTk9OWU1PVVNfSURfS0VZPSdhanNfYWlkJztjb25zdCBRVUVSWV9QQVJBTV9VU0VSX0lEX0tFWT0nYWpzX3VpZCc7Y29uc3QgUVVFUllfUEFSQU1fVFJBQ0tfRVZFTlRfTkFNRV9LRVk9J2Fqc19ldmVudCc7XG5cbmNvbnN0IERFRkFVTFRfWEhSX1RJTUVPVVRfTVM9MTAqMTAwMDsvLyAxMCBzZWNvbmRzXG5jb25zdCBERUZBVUxUX0NPT0tJRV9NQVhfQUdFX01TPTMxNTM2MDAwKjEwMDA7Ly8gMSB5ZWFyXG5jb25zdCBERUZBVUxUX1NFU1NJT05fQ1VUX09GRl9EVVJBVElPTl9NUz0xMio2MCo2MCoxMDAwOy8vIDEyIGhvdXJzXG5jb25zdCBERUZBVUxUX1NFU1NJT05fVElNRU9VVF9NUz0zMCo2MCoxMDAwOy8vIDMwIG1pbnV0ZXNcbmNvbnN0IE1JTl9TRVNTSU9OX1RJTUVPVVRfTVM9MTAqMTAwMDsvLyAxMCBzZWNvbmRzXG5jb25zdCBERUZBVUxUX0RBVEFfUExBTkVfRVZFTlRTX0JVRkZFUl9USU1FT1VUX01TPTEwKjEwMDA7Ly8gMTAgc2Vjb25kc1xuY29uc3QgREVCT1VOQ0VEX1RJTUVPVVRfTVM9MjUwOy8vIDI1MCBtaWxsaXNlY29uZHNcblxuLyoqXG4gKiBDcmVhdGUgZ2xvYmFsbHkgYWNjZXNzaWJsZSBSdWRkZXJTdGFja0dsb2JhbHMgb2JqZWN0XG4gKi9jb25zdCBjcmVhdGVFeHBvc2VkR2xvYmFscz0oYW5hbHl0aWNzSW5zdGFuY2VJZD0nYXBwJyk9PntpZighZ2xvYmFsVGhpcy5SdWRkZXJTdGFja0dsb2JhbHMpe2dsb2JhbFRoaXMuUnVkZGVyU3RhY2tHbG9iYWxzPXt9O31pZighZ2xvYmFsVGhpcy5SdWRkZXJTdGFja0dsb2JhbHNbYW5hbHl0aWNzSW5zdGFuY2VJZF0pe2dsb2JhbFRoaXMuUnVkZGVyU3RhY2tHbG9iYWxzW2FuYWx5dGljc0luc3RhbmNlSWRdPXt9O319Oy8qKlxuICogQWRkIG1vdmUgdmFsdWVzIHRvIGdsb2JhbGx5IGFjY2Vzc2libGUgUnVkZGVyU3RhY2tHbG9iYWxzIG9iamVjdCBwZXIgYW5hbHl0aWNzIGluc3RhbmNlXG4gKi9jb25zdCBzZXRFeHBvc2VkR2xvYmFsPShrZXlOYW1lLHZhbHVlLGFuYWx5dGljc0luc3RhbmNlSWQ9J2FwcCcpPT57Y3JlYXRlRXhwb3NlZEdsb2JhbHMoYW5hbHl0aWNzSW5zdGFuY2VJZCk7Z2xvYmFsVGhpcy5SdWRkZXJTdGFja0dsb2JhbHNbYW5hbHl0aWNzSW5zdGFuY2VJZF1ba2V5TmFtZV09dmFsdWU7fTsvKipcbiAqIEdldCB2YWx1ZXMgZnJvbSBnbG9iYWxseSBhY2Nlc3NpYmxlIFJ1ZGRlclN0YWNrR2xvYmFscyBvYmplY3QgYnkgYW5hbHl0aWNzIGluc3RhbmNlXG4gKi9jb25zdCBnZXRFeHBvc2VkR2xvYmFsPShrZXlOYW1lLGFuYWx5dGljc0luc3RhbmNlSWQ9J2FwcCcpPT57Y3JlYXRlRXhwb3NlZEdsb2JhbHMoYW5hbHl0aWNzSW5zdGFuY2VJZCk7cmV0dXJuIGdsb2JhbFRoaXMuUnVkZGVyU3RhY2tHbG9iYWxzW2FuYWx5dGljc0luc3RhbmNlSWRdW2tleU5hbWVdO307ZnVuY3Rpb24gZGVib3VuY2UoZnVuYyx0aGlzQXJnLGRlbGF5PURFQk9VTkNFRF9USU1FT1VUX01TKXtsZXQgdGltZW91dElkO3JldHVybiAoLi4uYXJncyk9PntnbG9iYWxUaGlzLmNsZWFyVGltZW91dCh0aW1lb3V0SWQpO3RpbWVvdXRJZD1nbG9iYWxUaGlzLnNldFRpbWVvdXQoKCk9PntmdW5jLmFwcGx5KHRoaXNBcmcsYXJncyk7fSxkZWxheSk7fTt9XG5cbi8qKlxuICogUGFyc2UgcXVlcnkgc3RyaW5nIHBhcmFtcyBpbnRvIG9iamVjdCB2YWx1ZXMgZm9yIGtleXMgdGhhdCBzdGFydCB3aXRoIGEgZGVmaW5lZCBwcmVmaXhcbiAqL2NvbnN0IGdldEV2ZW50RGF0YUZyb21RdWVyeVN0cmluZz0ocGFyYW1zLGRhdGFUeXBlTmFtZVByZWZpeCk9Pntjb25zdCBkYXRhPXt9O3BhcmFtcy5mb3JFYWNoKCh2YWx1ZSxrZXkpPT57aWYoa2V5LnN0YXJ0c1dpdGgoZGF0YVR5cGVOYW1lUHJlZml4KSl7Ly8gcmVtb3ZlIHByZWZpeCBmcm9tIGtleSBuYW1lXG5jb25zdCBkYXRhS2V5PWtleS5zdWJzdHJpbmcoZGF0YVR5cGVOYW1lUHJlZml4Lmxlbmd0aCk7Ly8gYWRkIG5ldyBrZXkgdmFsdWUgcGFpciBpbiBnZW5lcmF0ZWQgb2JqZWN0XG5kYXRhW2RhdGFLZXldPXBhcmFtcy5nZXQoa2V5KTt9fSk7cmV0dXJuIGRhdGE7fTsvKipcbiAqIFBhcnNlIHF1ZXJ5IHN0cmluZyBpbnRvIHByZWxvYWQgYnVmZmVyIGV2ZW50cyAmIHB1c2ggaW50byBleGlzdGluZyBhcnJheSBiZWZvcmUgYW55IG90aGVyIGV2ZW50c1xuICovY29uc3QgcmV0cmlldmVFdmVudHNGcm9tUXVlcnlTdHJpbmc9KGFyZ3VtZW50c0FycmF5PVtdKT0+ey8vIE1hcHBpbmcgZm9yIHRyYWl0IGFuZCBwcm9wZXJ0aWVzIHZhbHVlcyBiYXNlZCBvbiBrZXkgcHJlZml4XG5jb25zdCBldmVudEFyZ3VtZW50VG9RdWVyeVBhcmFtTWFwPXt0cmFpdDpRVUVSWV9QQVJBTV9UUkFJVF9QUkVGSVgscHJvcGVydGllczpRVUVSWV9QQVJBTV9QUk9QRVJUWV9QUkVGSVh9O2NvbnN0IHF1ZXJ5T2JqZWN0PW5ldyBVUkxTZWFyY2hQYXJhbXMoZ2xvYmFsVGhpcy5sb2NhdGlvbi5zZWFyY2gpOy8vIEFkZCB0cmFjayBldmVudHMgd2l0aCBuYW1lIGFuZCBwcm9wZXJ0aWVzXG5pZihxdWVyeU9iamVjdC5nZXQoUVVFUllfUEFSQU1fVFJBQ0tfRVZFTlRfTkFNRV9LRVkpKXthcmd1bWVudHNBcnJheS51bnNoaWZ0KFsndHJhY2snLHF1ZXJ5T2JqZWN0LmdldChRVUVSWV9QQVJBTV9UUkFDS19FVkVOVF9OQU1FX0tFWSks
1Z2V0RXZlbnREYXRhRnJvbVF1ZXJ5U3RyaW5nKHF1ZXJ5T2JqZWN0LGV2ZW50QXJndW1lbnRUb1F1ZXJ5UGFyYW1NYXAucHJvcGVydGllcyldKTt9Ly8gU2VuZCBpZGVudGlmeSBldmVudFxuY29uc3QgdXNlcklkPXF1ZXJ5T2JqZWN0LmdldChRVUVSWV9QQVJBTV9VU0VSX0lEX0tFWSk7Y29uc3QgdXNlclRyYWl0cz1nZXRFdmVudERhdGFGcm9tUXVlcnlTdHJpbmcocXVlcnlPYmplY3QsZXZlbnRBcmd1bWVudFRvUXVlcnlQYXJhbU1hcC50cmFpdCk7aWYodXNlcklkfHxpc05vbkVtcHR5T2JqZWN0KHVzZXJUcmFpdHMpKXsvLyBJbiBpZGVudGlmeSBBUEksIHVzZXIgSUQgaXMgb3B0aW9uYWxcbmNvbnN0IGlkZW50aWZ5QXBpQXJncz1bLi4uKHVzZXJJZD9bdXNlcklkXTpbXSksdXNlclRyYWl0c107YXJndW1lbnRzQXJyYXkudW5zaGlmdChbJ2lkZW50aWZ5JywuLi5pZGVudGlmeUFwaUFyZ3NdKTt9Ly8gU2V0IGFub255bW91c0lEXG5pZihxdWVyeU9iamVjdC5nZXQoUVVFUllfUEFSQU1fQU5PTllNT1VTX0lEX0tFWSkpe2FyZ3VtZW50c0FycmF5LnVuc2hpZnQoWydzZXRBbm9ueW1vdXNJZCcscXVlcnlPYmplY3QuZ2V0KFFVRVJZX1BBUkFNX0FOT05ZTU9VU19JRF9LRVkpXSk7fX07LyoqXG4gKiBSZXRyaWV2ZSBhbiBleGlzdGluZyBidWZmZXJlZCBsb2FkIG1ldGhvZCBjYWxsIGFuZCByZW1vdmUgZnJvbSB0aGUgZXhpc3RpbmcgYXJyYXlcbiAqL2NvbnN0IGdldFByZWxvYWRlZExvYWRFdmVudD1wcmVsb2FkZWRFdmVudHNBcnJheT0+e2NvbnN0IGxvYWRNZXRob2ROYW1lPSdsb2FkJztsZXQgbG9hZEV2ZW50PVtdOy8qKlxuICAgKiBJdGVyYXRlIHRoZSBidWZmZXJlZCBBUEkgY2FsbHMgdW50aWwgd2UgZmluZCBsb2FkIGNhbGwgYW5kIHByb2Nlc3MgaXQgc2VwYXJhdGVseVxuICAgKi9sZXQgaT0wO3doaWxlKGk8cHJlbG9hZGVkRXZlbnRzQXJyYXkubGVuZ3RoKXtpZihwcmVsb2FkZWRFdmVudHNBcnJheVtpXSYmcHJlbG9hZGVkRXZlbnRzQXJyYXlbaV1bMF09PT1sb2FkTWV0aG9kTmFtZSl7bG9hZEV2ZW50PWNsb25lKHByZWxvYWRlZEV2ZW50c0FycmF5W2ldKTtwcmVsb2FkZWRFdmVudHNBcnJheS5zcGxpY2UoaSwxKTticmVhazt9aSs9MTt9cmV0dXJuIGxvYWRFdmVudDt9Oy8qKlxuICogUHJvbW90ZSBjb25zZW50IGV2ZW50cyB0byB0aGUgdG9wIG9mIHRoZSBwcmVsb2FkZWQgZXZlbnRzIGFycmF5XG4gKiBAcGFyYW0gcHJlbG9hZGVkRXZlbnRzQXJyYXkgUHJlbG9hZGVkIGV2ZW50cyBhcnJheVxuICogQHJldHVybnMgTm9uZVxuICovY29uc3QgcHJvbW90ZVByZWxvYWRlZENvbnNlbnRFdmVudHNUb1RvcD1wcmVsb2FkZWRFdmVudHNBcnJheT0+e2NvbnN0IGNvbnNlbnRNZXRob2ROYW1lPSdjb25zZW50Jztjb25zdCBjb25zZW50RXZlbnRzPXByZWxvYWRlZEV2ZW50c0FycmF5LmZpbHRlcihidWZmZXJlZEV2ZW50PT5idWZmZXJlZEV2ZW50WzBdPT09Y29uc2VudE1ldGhvZE5hbWUpO2NvbnN0IG5vbkNvbnNlbnRFdmVudHM9cHJlbG9hZGVkRXZlbnRzQXJyYXkuZmlsdGVyKGJ1ZmZlcmVkRXZlbnQ9PmJ1ZmZlcmVkRXZlbnRbMF0hPT1jb25zZW50TWV0aG9kTmFtZSk7Ly8gUmVtb3ZlIGFsbCBlbGVtZW50cyBhbmQgYWRkIGNvbnNlbnQgZXZlbnRzIGZpcnN0IGZvbGxvd2VkIGJ5IG5vbiBjb25zZW50IGV2ZW50c1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHVuaWNvcm4vbm8tdXNlbGVzcy1zcHJlYWRcbnByZWxvYWRlZEV2ZW50c0FycmF5LnNwbGljZSgwLHByZWxvYWRlZEV2ZW50c0FycmF5Lmxlbmd0aCwuLi5jb25zZW50RXZlbnRzLC4uLm5vbkNvbnNlbnRFdmVudHMpO307LyoqXG4gKiBSZXRyaWV2ZSBhbnkgZXhpc3RpbmcgZXZlbnRzIHRoYXQgd2VyZSB0cmlnZ2VyZWQgYmVmb3JlIFNESyBsb2FkIGFuZCBlbnF1ZXVlIGluIGJ1ZmZlclxuICovY29uc3QgcmV0cmlldmVQcmVsb2FkQnVmZmVyRXZlbnRzPWluc3RhbmNlPT57Y29uc3QgcHJlbG9hZGVkRXZlbnRzQXJyYXk9Z2V0RXhwb3NlZEdsb2JhbChHTE9CQUxfUFJFTE9BRF9CVUZGRVIpfHxbXTsvLyBHZXQgZXZlbnRzIHRoYXQgYXJlIHByZS1wb3B1bGF0ZWQgdmlhIHF1ZXJ5IHN0cmluZyBwYXJhbXNcbnJldHJpZXZlRXZlbnRzRnJvbVF1ZXJ5U3RyaW5nKHByZWxvYWRlZEV2ZW50c0FycmF5KTsvLyBFbnF1ZXVlIHRoZSBub24gbG9hZCBldmVudHMgaW4gdGhlIGJ1ZmZlciBvZiB0aGUgZ2xvYmFsIHJ1ZGRlciBhbmFseXRpY3Mgc2luZ2xldG9uXG5pZihwcmVsb2FkZWRFdmVudHNBcnJheS5sZW5ndGg+MCl7aW5zdGFuY2UuZW5xdWV1ZVByZWxvYWRCdWZmZXJFdmVudHMocHJlbG9hZGVkRXZlbnRzQXJyYXkpO3NldEV4cG9zZWRHbG9iYWwoR0xPQkFMX1BSRUxPQURfQlVGRkVSLFtdKTt9fTtjb25zdCBjb25zdW1lUHJlbG9hZEJ1ZmZlcmVkRXZlbnQ9KGV2ZW50LGFuYWx5dGljc0luc3RhbmNlKT0+e2NvbnN0IG1ldGhvZE5hbWU9ZXZlbnQuc2hpZnQoKTtsZXQgY2FsbE9wdGlvbnM7aWYoaXNGdW5jdGlvbihhbmFseXRpY3NJbnN0YW5jZVttZXRob2ROYW1lXSkpe3N3aXRjaChtZXRob2ROYW1lKXtjYXNlICdwYWdlJzpjYWxsT3B0aW9ucz1wYWdlQXJndW1lbnRzVG9DYWxsT3B0aW9ucyguLi5ldmVudCk7YnJlYWs7Y2FzZSAndHJhY2snOmNhbGxPcHRpb25zPXRyYWNrQXJndW1lbnRzVG9DYWxsT3B0aW9ucyguLi5ldmVudCk7YnJlYWs7Y2FzZSAnaWRlbnRpZnknOmNhbGxPcHRpb25zPWlkZW50aWZ5QXJndW1lbnRzVG9DYWxsT3B0aW9ucyguLi5ldmVudCk7YnJlYWs7Y2FzZSAnYWxpYXMnOmNhbGxPcHRpb25zPWFsaWFzQXJndW1lbnRzVG9DYWxsT3B0aW9ucyguLi5ldmVudCk7YnJlYWs7Y2FzZSAnZ3JvdXAnOmNhbGxPcHRpb25zPWdyb3VwQXJndW1lbnRzVG9DYWxsT3B0aW9ucyguLi5ldmVudCk7YnJlYWs7ZGVmYXVsdDphbmFseXRpY3NJbnN0YW5jZVttZXRob2ROYW1lXSguLi5ldmVudCk7YnJlYWs7fWlmKGNhbGxPcHRpb25zKXthbmFseXRpY3NJbnN0YW5jZVttZXRob2ROYW1lXShjYWxsT3B0aW9ucyk7fX19O1xuXG5jb25zdCBERUZBVUxUX0VYVF9TUkNfTE9BRF9USU1FT1VUX01TPTEwKjEwMDA7Ly8gMTAgc2Vjb25kc1xuXG5jb25zdCBFWFRFUk5BTF9TT1VSQ0VfTE9BRF9PUklHSU49J1JTX0pTX1NESyc7XG5cbi8qKlxuICogQ3JlYXRlIHRoZSBET00gZWxlbWVudCB0byBsb2FkIGEg
1c2NyaXB0IG1hcmtlZCBhcyBSUyBTREsgb3JpZ2luYXRlZFxuICpcbiAqIEBwYXJhbSB7Kn0gdXJsIFRoZSBVUkwgb2YgdGhlIHNjcmlwdCB0byBiZSBsb2FkZWRcbiAqIEBwYXJhbSB7Kn0gaWQgSUQgZm9yIHRoZSBzY3JpcHQgdGFnXG4gKiBAcGFyYW0geyp9IGFzeW5jIFdoZXRoZXIgdG8gbG9hZCB0aGUgc2NyaXB0IGluIGFzeW5jIG1vZGUuIERlZmF1bHRzIHRvIGB0cnVlYCBbb3B0aW9uYWxdXG4gKiBAcGFyYW0geyp9IG9ubG9hZCBjYWxsYmFjayB0byBpbnZva2Ugb25sb2FkIFtvcHRpb25hbF1cbiAqIEBwYXJhbSB7Kn0gb25lcnJvciBjYWxsYmFjayB0byBpbnZva2Ugb25lcnJvciBbb3B0aW9uYWxdXG4gKiBAcGFyYW0geyp9IGV4dHJhQXR0cmlidXRlcyBrZXkvdmFsdWUgcGFpciB3aXRoIGh0bWwgYXR0cmlidXRlcyB0byBhZGQgaW4gaHRtbCB0YWcgW29wdGlvbmFsXVxuICpcbiAqIEByZXR1cm5zIEhUTUxTY3JpcHRFbGVtZW50XG4gKi9jb25zdCBjcmVhdGVTY3JpcHRFbGVtZW50PSh1cmwsaWQsYXN5bmM9dHJ1ZSxvbmxvYWQ9bnVsbCxvbmVycm9yPW51bGwsZXh0cmFBdHRyaWJ1dGVzPXt9KT0+e2NvbnN0IHNjcmlwdEVsZW1lbnQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7c2NyaXB0RWxlbWVudC50eXBlPSd0ZXh0L2phdmFzY3JpcHQnO3NjcmlwdEVsZW1lbnQub25sb2FkPW9ubG9hZDtzY3JpcHRFbGVtZW50Lm9uZXJyb3I9b25lcnJvcjtzY3JpcHRFbGVtZW50LnNyYz11cmw7c2NyaXB0RWxlbWVudC5pZD1pZDtzY3JpcHRFbGVtZW50LmFzeW5jPWFzeW5jO09iamVjdC5rZXlzKGV4dHJhQXR0cmlidXRlcykuZm9yRWFjaChhdHRyaWJ1dGVOYW1lPT57c2NyaXB0RWxlbWVudC5zZXRBdHRyaWJ1dGUoYXR0cmlidXRlTmFtZSxleHRyYUF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZV0pO30pO3NjcmlwdEVsZW1lbnQuc2V0QXR0cmlidXRlKCdkYXRhLWxvYWRlcicsRVhURVJOQUxfU09VUkNFX0xPQURfT1JJR0lOKTtyZXR1cm4gc2NyaXB0RWxlbWVudDt9Oy8qKlxuICogQWRkIHNjcmlwdCBET00gZWxlbWVudCB0byBET01cbiAqXG4gKiBAcGFyYW0geyp9IG5ld1NjcmlwdEVsZW1lbnQgdGhlIHNjcmlwdCBlbGVtZW50IHRvIGFkZFxuICpcbiAqIEByZXR1cm5zXG4gKi9jb25zdCBpbnNlcnRTY3JpcHQ9bmV3U2NyaXB0RWxlbWVudD0+ey8vIEZpcnN0IHRyeSB0byBhZGQgaXQgdG8gdGhlIGhlYWRcbmNvbnN0IGhlYWRFbGVtZW50cz1kb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnaGVhZCcpO2lmKGhlYWRFbGVtZW50cy5sZW5ndGg+MCl7aGVhZEVsZW1lbnRzWzBdPy5pbnNlcnRCZWZvcmUobmV3U2NyaXB0RWxlbWVudCxoZWFkRWxlbWVudHNbMF0/LmZpcnN0Q2hpbGQpO3JldHVybjt9Ly8gRWxzZSB3aXNlIGFkZCBpdCBiZWZvcmUgdGhlIGZpcnN0IHNjcmlwdCB0YWdcbmNvbnN0IHNjcmlwdEVsZW1lbnRzPWRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtpZihzY3JpcHRFbGVtZW50cy5sZW5ndGg+MCYmc2NyaXB0RWxlbWVudHNbMF0/LnBhcmVudE5vZGUpe3NjcmlwdEVsZW1lbnRzWzBdPy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShuZXdTY3JpcHRFbGVtZW50LHNjcmlwdEVsZW1lbnRzWzBdKTtyZXR1cm47fS8vIENyZWF0ZSBhIG5ldyBoZWFkIGVsZW1lbnQgYW5kIGFkZCB0aGUgc2NyaXB0IGFzIGZ
1hbGxiYWNrXG5jb25zdCBoZWFkRWxlbWVudD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdoZWFkJyk7aGVhZEVsZW1lbnQuYXBwZW5kQ2hpbGQobmV3U2NyaXB0RWxlbWVudCk7Y29uc3QgaHRtbEVsZW1lbnQ9ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2h0bWwnKVswXTtodG1sRWxlbWVudD8uaW5zZXJ0QmVmb3JlKGhlYWRFbGVtZW50LGh0bWxFbGVtZW50LmZpcnN0Q2hpbGQpO307LyoqXG4gKiBMb2FkcyBleHRlcm5hbCBqcyBmaWxlIGFzIGEgc2NyaXB0IGh0bWwgdGFnXG4gKlxuICogQHBhcmFtIHsqfSB1cmwgVGhlIFVSTCBvZiB0aGUgc2NyaXB0IHRvIGJlIGxvYWRlZFxuICogQHBhcmFtIHsqfSBpZCBJRCBmb3IgdGhlIHNjcmlwdCB0YWdcbiAqIEBwYXJhbSB7Kn0gdGltZW91dCBsb2FkaW5nIHRpbWVvdXRcbiAqIEBwYXJhbSB7Kn0gYXN5bmMgV2hldGhlciB0byBsb2FkIHRoZSBzY3JpcHQgaW4gYXN5bmMgbW9kZS4gRGVmYXVsdHMgdG8gYHRydWVgIFtvcHRpb25hbF1cbiAqIEBwYXJhbSB7Kn0gZXh0cmFBdHRyaWJ1dGVzIGtleS92YWx1ZSBwYWlyIHdpdGggaHRtbCBhdHRyaWJ1dGVzIHRvIGFkZCBpbiBodG1sIHRhZyBbb3B0aW9uYWxdXG4gKlxuICogQHJldHVybnNcbiAqL2NvbnN0IGpzRmlsZUxvYWRlcj0odXJsLGlkLHRpbWVvdXQsYXN5bmM9dHJ1ZSxleHRyYUF0dHJpYnV0ZXMpPT5uZXcgUHJvbWlzZSgocmVzb2x2ZSxyZWplY3QpPT57Y29uc3Qgc2NyaXB0RXhpc3RzPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKTtpZihzY3JpcHRFeGlzdHMpe3JlamVjdChuZXcgRXJyb3IoU0NSSVBUX0FMUkVBRFlfRVhJU1RTX0VSUk9SKGlkKSkpO310cnl7bGV0IHRpbWVvdXRJRDtjb25zdCBvbmxvYWQ9KCk9PntnbG9iYWxUaGlzLmNsZWFyVGltZW91dCh0aW1lb3V0SUQpO3Jlc29sdmUoaWQpO307Y29uc3Qgb25lcnJvcj1ldj0+e2dsb2JhbFRoaXMuY2xlYXJUaW1lb3V0KHRpbWVvdXRJRCk7cmVqZWN0KG5ldyBFcnJvcihTQ1JJUFRfTE9BRF9FUlJPUihpZCx1cmwsZXYpKSk7fTsvLyBDcmVhdGUgdGhlIERPTSBlbGVtZW50IHRvIGxvYWQgdGhlIHNjcmlwdCBhbmQgYWRkIGl0IHRvIHRoZSBET01cbmluc2VydFNjcmlwdChjcmVhdGVTY3JpcHRFbGVtZW50KHVybCxpZCxhc3luYyxvbmxvYWQsb25lcnJvcixleHRyYUF0dHJpYnV0ZXMpKTsvLyBSZWplY3Qgb24gdGltZW91dFxudGltZW91dElEPWdsb2JhbFRoaXMuc2V0VGltZW91dCgoKT0+e3JlamVjdChuZXcgRXJyb3IoU0NSSVBUX0xPQURfVElNRU9VVF9FUlJPUihpZCx1cmwsdGltZW91dCkpKTt9LHRpbWVvdXQpO31jYXRjaChlcnIpe3JlamVjdChnZXRNdXRhdGVkRXJyb3IoZXJyLFNDUklQVF9MT0FEX0VSUk9SKGlkLHVybCwndW5rbm93bicpKSk7fX0pO1xuXG4vKipcbiAqIFNlcnZpY2UgdG8gbG9hZCBleHRlcm5hbCByZXNvdXJjZXMvZmlsZXNcbiAqL2NsYXNzIEV4dGVybmFsU3JjTG9hZGVye2NvbnN0cnVjdG9yKGxvZ2dlcix0aW1lb3V0PURFRkFVTFRfRVhUX1NSQ19MT0FEX1RJTUVPVVRfTVMpe3RoaXMubG9nZ2VyPWxvZ2dlcjt0aGlzLnRpbWVvdXQ9dGltZW91dDt9LyoqXG4gICAqIExvYWQgZXh0ZXJuYWwgcmVzb3VyY2Ugb2YgdHlwZSBqYXZhc2NyaXB0XG4gICAqL2xvYWRKU0ZpbGUoY29uZmlnKXtjb25zdHt1cmwsaWQsdGltZW91dCxhc3luYyxjYWxsYmFjayxleHRyYUF0dHJpYnV0ZXN9PWNvbmZpZztjb25zdCBpc0ZpcmVBbmRGb3JnZXQ9IWlzRnVuY3Rpb24oY2FsbGJhY2spO2pzRmlsZUxvYWRlcih1cmwsaWQsdGltZW91dHx8dGhpcy50aW1lb3V0LGFzeW5jLGV4dHJhQXR0cmlidXRlcykudGhlbihpZD0+e2lmKCFpc0ZpcmVBbmRGb3JnZXQpe2NhbGxiYWNrKGlkKTt9fSkuY2F0Y2goZXJyPT57aWYoIWlzRmlyZUFuZEZvcmdldCl7Y2FsbGJhY2soaWQsZXJyKTt9fSk7fX1cblxudmFyIGk9U3ltYm9sLmZvcihcInByZWFjdC1zaWduYWxzXCIpO2Z1bmN0aW9uIHQoKXtpZighKHM+MSkpe3ZhciBpLHQ9ZmFsc2U7IWZ1bmN0aW9uKCl7dmFyIGk9YztjPXZvaWQgMDt3aGlsZSh2b2lkIDAhPT1pKXtpZihpLlMudj09PWkudilpLlMuaT1pLmk7aT1pLm87fX0oKTt3aGlsZSh2b2lkIDAhPT1oKXt2YXIgbj1oO2g9dm9pZCAwO3YrKzt3aGlsZSh2b2lkIDAhPT1uKXt2YXIgcj1uLnU7bi51PXZvaWQgMDtuLmYmPS0zO2lmKCEoOCZuLmYpJiZ3KG4pKXRyeXtuLmMoKTt9Y2F0Y2gobil7aWYoIXQpe2k9bjt0PXRydWU7fX1uPXI7fX12PTA7cy0tO2lmKHQpdGhyb3cgaTt9ZWxzZSBzLS07fWZ1bmN0aW9uIG4oaSl7aWYocz4wKXJldHVybiBpKCk7ZT0rK3U7cysrO3RyeXtyZXR1cm4gaSgpO31maW5hbGx5e3QoKTt9fXZhciByPXZvaWQgMDtmdW5jdGlvbiBvKGkpe3ZhciB0PXI7cj12b2lkIDA7dHJ5e3JldHVybiBpKCk7fWZpbmFsbHl7cj10O319dmFyIGg9dm9pZCAwLHM9MCx2PTAsdT0wLGU9MCxjPXZvaWQgMCxkJDE9MDtmdW5jdGlvbiBhKGkpe2lmKHZvaWQgMCE9PXIpe3ZhciB0PWkubjtpZih2b2lkIDA9PT10fHx0LnQhPT1yKXt0PXtpOjAsUzppLHA6ci5zLG46dm9pZCAwLHQ6cixlOnZvaWQgMCx4OnZvaWQgMCxyOnR9O2lmKHZvaWQgMCE9PXIucylyLnMubj10O3Iucz10O2kubj10O2lmKDMyJnIuZilpLlModCk7cmV0dXJuIHQ7fWVsc2UgaWYoLTE9PT10Lmkpe3QuaT0wO2lmKHZvaWQgMCE9PXQubil7dC5uLnA9dC5wO2lmKHZvaWQgMCE9PXQucCl0LnAubj10Lm47dC5wPXIuczt0Lm49dm9pZCAwO3Iucy5uPXQ7ci5zPXQ7fXJldHVybiB0O319fWZ1bmN0aW9uIGwoaSx0KXt0aGlzLnY9aTt0aGlzLmk9MDt0aGlzLm49dm9pZCAwO3RoaXMudD12b2lkIDA7dGhpcy5sPTA7dGhpcy5XPW51bGw9PXQ/dm9pZCAwOnQud2F0Y2hlZDt0aGlzLlo9bnVsbD09dD92b2lkIDA6dC51bndhdGNoZWQ7dGhpcy5uYW1lPW51bGw9PXQ/dm9pZCAwOnQubmFtZTt9bC5wcm90b3R5cGUuYnJhbmQ9aTtsLnByb3RvdHlwZS5oPWZ1bmN0aW9uKCl7cmV0dXJuICB0cnVlO307bC5wcm90b3R5cGUuUz1mdW5jdGlvbihpKXt2YXIgdD10aGlzLG49dGhpcy50O2lmKG4hPT1pJiZ2b2lkIDA9PT1pLmUpe2kueD1uO3RoaXMudD1pO2lmKHZvaWQgMCE9PW4pbi5lPWk7ZWxzZSBvKGZ1bmN0aW9uKCl7dmFyIGk7bnVsbD09KGk9dC5XKXx8aS5jYWxsKHQpO30pO319O2wucHJvdG90eXBlLlU9ZnVuY3Rpb24oaSl7dmFyIHQ9dGhpcztpZih2b2lkIDAhPT10aGlzLnQpe3ZhciBuPWkuZSxyPWkueDtpZih2b2lkIDAhPT1uKXtuLng9cjtpLmU9dm9pZCAwO31pZih2b2lkIDAhPT1yKXtyLmU9bjtpLng9dm9pZCAwO31pZihpPT09dGhpcy50KXt0aGlzLnQ9cjtpZih2b2lkIDA9PT1yKW8oZnVuY3Rpb24oKXt2YXIgaTtudWxsPT0
1oaT10LlopfHxpLmNhbGwodCk7fSk7fX19O2wucHJvdG90eXBlLnN1YnNjcmliZT1mdW5jdGlvbihpKXt2YXIgdD10aGlzO3JldHVybiBqKGZ1bmN0aW9uKCl7dmFyIG49dC52YWx1ZSxvPXI7cj12b2lkIDA7dHJ5e2kobik7fWZpbmFsbHl7cj1vO319LHtuYW1lOlwic3ViXCJ9KTt9O2wucHJvdG90eXBlLnZhbHVlT2Y9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy52YWx1ZTt9O2wucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudmFsdWUrXCJcIjt9O2wucHJvdG90eXBlLnRvSlNPTj1mdW5jdGlvbigpe3JldHVybiB0aGlzLnZhbHVlO307bC5wcm90b3R5cGUucGVlaz1mdW5jdGlvbigpe3ZhciBpPXRoaXM7cmV0dXJuIG8oZnVuY3Rpb24oKXtyZXR1cm4gaS52YWx1ZTt9KTt9O09iamVjdC5kZWZpbmVQcm9wZXJ0eShsLnByb3RvdHlwZSxcInZhbHVlXCIse2dldDpmdW5jdGlvbigpe3ZhciBpPWEodGhpcyk7aWYodm9pZCAwIT09aSlpLmk9dGhpcy5pO3JldHVybiB0aGlzLnY7fSxzZXQ6ZnVuY3Rpb24oaSl7aWYoaSE9PXRoaXMudil7aWYodj4xMDApdGhyb3cgbmV3IEVycm9yKFwiQ3ljbGUgZGV0ZWN0ZWRcIik7IWZ1bmN0aW9uKGkpe2lmKDAhPT1zJiYwPT09dilpZihpLmwhPT1lKXtpLmw9ZTtjPXtTOmksdjppLnYsaTppLmksbzpjfTt9fSh0aGlzKTt0aGlzLnY9aTt0aGlzLmkrKztkJDErKztzKys7dHJ5e2Zvcih2YXIgbj10aGlzLnQ7dm9pZCAwIT09bjtuPW4ueCluLnQuTigpO31maW5hbGx5e3QoKTt9fX19KTtmdW5jdGlvbiB5KGksdCl7cmV0dXJuIG5ldyBsKGksdCk7fWZ1bmN0aW9uIHcoaSl7Zm9yKHZhciB0PWkuczt2b2lkIDAhPT10O3Q9dC5uKWlmKHQuUy5pIT09dC5pfHwhdC5TLmgoKXx8dC5TLmkhPT10LmkpcmV0dXJuICB0cnVlO3JldHVybiAgZmFsc2U7fWZ1bmN0aW9uIF8oaSl7Zm9yKHZhciB0PWkuczt2b2lkIDAhPT10O3Q9dC5uKXt2YXIgbj10LlMubjtpZih2b2lkIDAhPT1uKXQucj1uO3QuUy5uPXQ7dC5pPS0xO2lmKHZvaWQgMD09PXQubil7aS5zPXQ7YnJlYWs7fX19ZnVuY3Rpb24gYihpKXt2YXIgdD1pLnMsbj12b2lkIDA7d2hpbGUodm9pZCAwIT09dCl7dmFyIHI9dC5wO2lmKC0xPT09dC5pKXt0LlMuVSh0KTtpZih2b2lkIDAhPT1yKXIubj10Lm47aWYodm9pZCAwIT09dC5uKXQubi5wPXI7fWVsc2Ugbj10O3QuUy5uPXQucjtpZih2b2lkIDAhPT10LnIpdC5yPXZvaWQgMDt0PXI7fWkucz1uO31mdW5jdGlvbiBwKGksdCl7bC5jYWxsKHRoaXMsdm9pZCAwKTt0aGlzLng9aTt0aGlzLnM9dm9pZCAwO3RoaXMuZz1kJDEtMTt0aGlzLmY9NDt0aGlzLlc9bnVsbD09dD92b2lkIDA6dC53YXRjaGVkO3RoaXMuWj1udWxsPT10P3ZvaWQgMDp0LnVud2F0Y2hlZDt0aGlzLm5hbWU9bnVsbD09dD92b2lkIDA6dC5uYW1lO31wLnByb3RvdHlwZT1uZXcgbCgpO3AucHJvdG90eXBlLmg9ZnVuY3Rpb24oKXt0aGlzLmYmPS0zO2lmKDEmdGhpcy5mKXJldHVybiAgZmFsc2U7aWYoMzI9PSgzNiZ0aGlzLmYpKXJldHVybiAgdHJ1ZTt0aGlzLmYmPS01O2lmKHRoaXMuZz09PWQkMSlyZXR1cm4gIHRydWU7dGhpcy5nPWQkMTt0aGlzLmZ8PTE7aWYodGhpcy5pPjAmJiF3KHRoaXMpKXt0aGlzLmYmPS0yO3JldHVybiAgdHJ1ZTt9dmFyIGk9cjt0cnl7Xyh0aGlzKTtyPXRoaXM7dmFyIHQ9dGhpcy54KCk7aWYoMTYmdGhpcy5mfHx0aGlzLnYhPT10fHwwPT09dGhpcy5pKXt0aGlzLnY9dDt0aGlzLmYmPS0xNzt0aGlzLmkrKzt9fWNhdGNoKGkpe3RoaXMudj1pO3RoaXMuZnw9MTY7dGhpcy5pKys7fXI9aTtiKHRoaXMpO3RoaXMuZiY9LTI7cmV0dXJuICB0cnVlO307cC5wcm90b3R5cGUuUz1mdW5jdGlvbihpKXtpZih2b2lkIDA9PT10aGlzLnQpe3RoaXMuZnw9MzY7Zm9yKHZhciB0PXRoaXMuczt2b2lkIDAhPT10O3Q9dC5uKXQuUy5TKHQpO31sLnByb3RvdHlwZS5TLmNhbGwodGhpcyxpKTt9O3AucHJvdG90eXBlLlU9ZnVuY3Rpb24oaSl7aWYodm9pZCAwIT09dGhpcy50KXtsLnByb3RvdHlwZS5VLmNhbGwodGhpcyxpKTtpZih2b2lkIDA9PT10aGlzLnQpe3RoaXMuZiY9LTMzO2Zvcih2YXIgdD10aGlzLnM7dm9pZCAwIT09dDt0PXQubil0LlMuVSh0KTt9fX07cC5wcm90b3R5cGUuTj1mdW5jdGlvbigpe2lmKCEoMiZ0aGlzLmYpKXt0aGlzLmZ8PTY7Zm9yKHZhciBpPXRoaXMudDt2b2lkIDAhPT1pO2k9aS54KWkudC5OKCk7fX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHAucHJvdG90eXBlLFwidmFsdWVcIix7Z2V0OmZ1bmN0aW9uKCl7aWYoMSZ0aGlzLmYpdGhyb3cgbmV3IEVycm9yKFwiQ3ljbGUgZGV0ZWN0ZWRcIik7dmFyIGk9YSh0aGlzKTt0aGlzLmgoKTtpZih2b2lkIDAhPT1pKWkuaT10aGlzLmk7aWYoMTYmdGhpcy5mKXRocm93IHRoaXMudjtyZXR1cm4gdGhpcy52O319KTtmdW5jdGlvbiBTKGkpe3ZhciBuPWkubTtpLm09dm9pZCAwO2lmKFwiZnVuY3Rpb25cIj09dHlwZW9mIG4pe3MrKzt2YXIgbz1yO3I9dm9pZCAwO3RyeXtuKCk7fWNhdGNoKHQpe2kuZiY9LTI7aS5mfD04O20oaSk7dGhyb3cgdDt9ZmluYWxseXtyPW87dCgpO319fWZ1bmN0aW9uIG0oaSl7Zm9yKHZhciB0PWkuczt2b2lkIDAhPT10O3Q9dC5uKXQuUy5VKHQpO2kueD12b2lkIDA7aS5zPXZvaWQgMDtTKGkpO31mdW5jdGlvbiB4JDEoaSl7aWYociE9PXRoaXMpdGhyb3cgbmV3IEVycm9yKFwiT3V0LW9mLW9yZGVyIGVmZmVjdFwiKTtiKHRoaXMpO3I9aTt0aGlzLmYmPS0yO2lmKDgmdGhpcy5mKW0odGhpcyk7dCgpO31mdW5jdGlvbiBFKGksdCl7dGhpcy54PWk7dGhpcy5tPXZvaWQgMDt0aGlzLnM9dm9pZCAwO3RoaXMudT12b2lkIDA7dGhpcy5mPTMyO3RoaXMubmFtZT1udWxsPT10P3ZvaWQgMDp0Lm5hbWU7fUUucHJvdG90eXBlLmM9ZnVuY3Rpb24oKXt2YXIgaT10aGlzLlMoKTt0cnl7aWYoOCZ0aGlzLmYpcmV0dXJuO2lmKHZvaWQgMD09PXRoaXMueClyZXR1cm47dmFyIHQ9dGhpcy54KCk7aWYoXCJmdW5jdGlvblwiPT10eXBlb2YgdCl0aGlzLm09dDt9ZmluYWxseXtpKCk7fX07RS5wcm90b3R5cGUuUz1mdW5jdGlvbigpe2lmKDEmdGhpcy5mKXRocm93IG5ldyBFcnJvcihcIkN5Y2xlIGRldGVjdGVkXCIpO3RoaXMuZnw9MTt0aGlzLmYmPS05O1ModGhpcyk7Xyh0aGlzKTtzKys7dmFyIGk9cjtyPXRoaXM7cmV0dXJuIHgkMS5iaW5kKHRoaXMsaSk7fTtFLnByb3RvdHlwZS5OPWZ1bmN0aW9uKCl7aWYoISgyJnRoaXMuZikpe3RoaXMuZnw9Mjt0aGlzLnU9aDtoPXRoaXM7fX07RS5wcm90b3R5cGUuZD1mdW5jdGlvbigpe3RoaXMuZnw9ODtpZighKDEmdGhpcy5mKSltKHRoaXMpO307RS5wcm90b3R5cGUuZGlzcG9zZT1mdW5jdGlvbigpe3RoaXMuZCgpO307ZnVuY3Rpb24gaihpLHQpe3ZhciBuPW5ldyBFKGksdCk7dHJ5e24uYygpO31jYXRjaChpKXtuLmQoKTt0aHJvdyBpO312YXIgcj1uLmQuYmluZChuKTtyW1N5bWJvbC5kaXNwb3NlXT1yO3JldHVybiByO31cblxuLyoqXG4gKiBBIGJ1ZmZlciBxdWV1ZSB0byBzZXJ2ZSBhcyBh
1IHN0b3JlIGZvciBhbnkgdHlwZSBvZiBkYXRhXG4gKi9jbGFzcyBCdWZmZXJRdWV1ZXtjb25zdHJ1Y3Rvcigpe3RoaXMuaXRlbXM9W107fWVucXVldWUoaXRlbSl7dGhpcy5pdGVtcy5wdXNoKGl0ZW0pO31kZXF1ZXVlKCl7aWYodGhpcy5pdGVtcy5sZW5ndGg9PT0wKXtyZXR1cm4gbnVsbDt9cmV0dXJuIHRoaXMuaXRlbXMuc2hpZnQoKTt9aXNFbXB0eSgpe3JldHVybiB0aGlzLml0ZW1zLmxlbmd0aD09PTA7fXNpemUoKXtyZXR1cm4gdGhpcy5pdGVtcy5sZW5ndGg7fWNsZWFyKCl7dGhpcy5pdGVtcz1bXTt9fVxuXG5jb25zdCBMT0dfTEVWRUxfTUFQPXtMT0c6MCxJTkZPOjEsREVCVUc6MixXQVJOOjMsRVJST1I6NCxOT05FOjV9O2NvbnN0IERFRkFVTFRfTE9HX0xFVkVMPSdMT0cnO2NvbnN0IFBPU1RfTE9BRF9MT0dfTEVWRUw9J0VSUk9SJztjb25zdCBMT0dfTVNHX1BSRUZJWD0nUlMgU0RLJztjb25zdCBMT0dfTVNHX1BSRUZJWF9TVFlMRT0nZm9udC13ZWlnaHQ6IGJvbGQ7IGJhY2tncm91bmQ6IGJsYWNrOyBjb2xvcjogd2hpdGU7Jztjb25zdCBMT0dfTVNHX1NUWUxFPSdmb250LXdlaWdodDogbm9ybWFsOyc7LyoqXG4gKiBTZXJ2aWNlIHRvIGxvZyBtZXNzYWdlcy9kYXRhIHRvIG91dHB1dCBwcm92aWRlciwgZGVmYXVsdCBpcyBjb25zb2xlXG4gKi9jbGFzcyBMb2dnZXJ7Y29uc3RydWN0b3IobWluTG9nTGV2ZWw9REVGQVVMVF9MT0dfTEVWRUwsc2NvcGU9JycsbG9nUHJvdmlkZXI9Y29uc29sZSl7dGhpcy5taW5Mb2dMZXZlbD1MT0dfTEVWRUxfTUFQW21pbkxvZ0xldmVsXTt0aGlzLnNjb3BlPXNjb3BlO3RoaXMubG9nUHJvdmlkZXI9bG9nUHJvdmlkZXI7fWxvZyguLi5kYXRhKXt0aGlzLm91dHB1dExvZygnTE9HJyxkYXRhKTt9aW5mbyguLi5kYXRhKXt0aGlzLm91dHB1dExvZygnSU5GTycsZGF0YSk7fWRlYnVnKC4uLmRhdGEpe3RoaXMub3V0cHV0TG9nKCdERUJVRycsZGF0YSk7fXdhcm4oLi4uZGF0YSl7dGhpcy5vdXRwdXRMb2coJ1dBUk4nLGRhdGEpO31lcnJvciguLi5kYXRhKXt0aGlzLm91dHB1dExvZygnRVJST1InLGRhdGEpO31vdXRwdXRMb2cobG9nTWV0aG9kLGRhdGEpe2lmKHRoaXMubWluTG9nTGV2ZWw8PUxPR19MRVZFTF9NQVBbbG9nTWV0aG9kXSl7dGhpcy5sb2dQcm92aWRlcltsb2dNZXRob2QudG9Mb3dlckNhc2UoKV0/LiguLi50aGlzLmZvcm1hdExvZ0RhdGEoZGF0YSkpO319c2V0U2NvcGUoc2NvcGVWYWwpe3RoaXMuc2NvcGU9c2NvcGVWYWx8fHRoaXMuc2NvcGU7fS8vIFRPRE86IHNob3VsZCB3ZSBhbGxvdyB0byBjaGFuZ2UgdGhlIGxldmVsIHZpYSBnbG9iYWwgdmFyaWFibGUgb24gcnVuIHRpbWVcbi8vICB0byBhc3Npc3Qgb24gdGhlIGZseSBkZWJ1Z2dpbmc/XG5zZXRNaW5Mb2dMZXZlbChsb2dMZXZlbCl7dGhpcy5taW5Mb2dMZXZlbD1MT0dfTEVWRUxfTUFQW2xvZ0xldmVsXTtpZihpc1VuZGVmaW5lZCh0aGlzLm1pbkxvZ0xldmVsKSl7dGhpcy5taW5Mb2dMZXZlbD1MT0dfTEVWRUxfTUFQW0RFRkFVTFRfTE9HX0xFVkVMXTt9fS8qKlxuICAgKiBGb3JtYXRzIHRoZSBjb25zb2xlIG1lc3NhZ2UgdXNpbmcgYHNjb3BlYCBhbmQgc3R5bGVzXG4gICAqL2Zvcm1hdExvZ0RhdGEoZGF0YSl7aWYoQXJyYXkuaXNBcnJheShkYXRhKSYmZGF0YS5sZW5ndGg+MCl7Ly8gcHJlZml4IFNESyBpZGVudGlmaWVyXG5sZXQgbXNnPWAlYyAke0xPR19NU0dfUFJFRklYfWA7Ly8gZm9ybWF0IHRoZSBsb2cgbWVzc2FnZSB1c2luZyBgc2NvcGVgXG5pZih0aGlzLnNjb3BlKXttc2c9YCR7bXNnfSAtICR7dGhpcy5zY29wZX1gO30vLyB0cmltIHdoaXRlc3BhY2VzIGZvciBvcmlnaW5hbCBtZXNzYWdlXG5jb25zdCBvcmlnaW5hbE1zZz1pc1N0cmluZyhkYXRhWzBdKT9kYXRhWzBdLnRyaW0oKTonJzsvLyBwcmVwYXJlIHRoZSBmaW5hbCBtZXNzYWdlXG5tc2c9YCR7bXNnfSAlYyAke29yaWdpbmFsTXNnfWA7Y29uc3Qgc3R5bGVkTG9nQXJncz1bbXNnLExPR19NU0dfUFJFRklYX1NUWUxFLC8vIGFkZCBzdHlsZSBmb3IgdGhlIHByZWZpeFxuTE9HX01TR19TVFlMRS8vIHJlc2V0IHRoZSBzdHlsZSBmb3IgdGhlIGFjdHVhbCBtZXNzYWdlXG5dOy8vIGFkZCBmaXJzdCBpdCBpZiBpdCB3YXMgbm90IGEgc3RyaW5nIG1zZ1xuaWYoIWlzU3RyaW5nKGRhdGFbMF0pKXtzdHlsZWRMb2dBcmdzLnB1c2goZGF0YVswXSk7fS8vIGFwcGVuZCByZXN0IG9mIHRoZSBvcmlnaW5hbCBhcmd1bWVudHNcbnN0eWxlZExvZ0FyZ3MucHVzaCguLi5kYXRhLnNsaWNlKDEpKTtyZXR1cm4gc3R5bGVkTG9nQXJnczt9cmV0dXJuIGRhdGE7fX1jb25zdCBkZWZhdWx0TG9nZ2VyPW5ldyBMb2dnZXIoKTtcblxubGV0IEVycm9yVHlwZT0vKiNfX1BVUkVfXyovZnVuY3Rpb24oRXJyb3JUeXBlKXtFcnJvclR5cGVbXCJIQU5ETEVERVhDRVBUSU9OXCJdPVwiaGFuZGxlZEV4Y2VwdGlvblwiO0Vycm9yVHlwZVtcIlVOSEFORExFREVYQ0VQVElPTlwiXT1cInVuaGFuZGxlZEV4Y2VwdGlvblwiO0Vycm9yVHlwZVtcIlVOSEFORExFRFJFSkVDVElPTlwiXT1cInVuaGFuZGxlZFByb21pc2VSZWplY3Rpb25cIjtyZXR1cm4gRXJyb3JUeXBlO30oe30pO1xuXG4vLyBkZWZhdWx0IGlzIHYzXG5jb25zdCBTVVBQT1JURURfU1RPUkFHRV9UWVBFUz1bJ2xvY2FsU3RvcmFnZScsJ21lbW9yeVN0b3JhZ2UnLCdjb29raWVTdG9yYWdlJywnc2Vzc2lvblN0b3JhZ2UnLCdub25lJ107Y29uc3QgREVGQVVMVF9TVE9SQUdFX1RZUEU9J2Nvb2tpZVN0b3JhZ2UnO1xuXG5jb25zdCBTT1VSQ0VfQ09ORklHX1JFU09MVVRJT05fRVJST1I9YFVuYWJsZSB0byBwcm9jZXNzL3BhcnNlIHNvdXJjZSBjb25maWd1cmF0aW9uIHJlc3BvbnNlYDtjb25zdCBTT1VSQ0VfRElTQUJMRURfRVJST1I9YFRoZSBzb3VyY2UgaXMgZGlzYWJsZWQuIFBsZWFzZSBlbmFibGUgdGhlIHNvdXJjZSBpbiB0aGUgZGFzaGJvYXJkIHRvIHNlbmQgZXZlbnRzLmA7Y29uc3QgWEhSX1BBWUxPQURfUFJFUF9FUlJPUj1gRmFpbGVkIHRvIHByZXBhcmUgZGF0YSBmb3IgdGhlIHJlcXVlc3QuYDtjb25zdCBQTFVHSU5fRVhUX1BPSU5UX01JU1NJTkdfRVJST1I9YEZhaWxlZCB0byBpbnZva2UgcGx1Z2luIGJlY2F1c2UgdGhlIGV4dGVuc2lvbiBwb2ludCBuYW1lIGlzIG1pc3NpbmcuYDtjb25zdCBQTFVHSU5fRVhUX1BPSU5UX0lOVkFMSURfRVJST1I9YEZhaWxlZCB0byBpbnZva2UgcGx1Z2luIGJlY2F1c2UgdGhlIGV4dGVuc2lvbiBwb2ludCBuYW1lIGlzIGludmFsaWQuYDtjb25zdCBTT1VSQ0VfQ09ORklHX09QVElPTl9FUlJPUj1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBcImdldFNvdXJjZUNvbmZpZ1wiIGxvYWQgQVBJIG9wdGlvbiBtdXN0IGJlIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHZhbGlkIHNvdXJjZSBjb25maWd1cmF0aW9uIGRhdGEuYDtjb25zdCBDT01QT05FTlRfQkFTRV9VUkxfRVJST1I9KGNvbnRleHQsY29tcG9uZW50LHVybCk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVB
1BUkFUT1J9VGhlIGJhc2UgVVJMIFwiJHt1cmx9XCIgZm9yICR7Y29tcG9uZW50fSBpcyBub3QgdmFsaWQuYDsvLyBFUlJPUlxuY29uc3QgVU5TVVBQT1JURURfQ09OU0VOVF9NQU5BR0VSX0VSUk9SPShjb250ZXh0LHNlbGVjdGVkQ29uc2VudE1hbmFnZXIsY29uc2VudE1hbmFnZXJzVG9QbHVnaW5OYW1lTWFwKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1UaGUgY29uc2VudCBtYW5hZ2VyIFwiJHtzZWxlY3RlZENvbnNlbnRNYW5hZ2VyfVwiIGlzIG5vdCBzdXBwb3J0ZWQuIFBsZWFzZSBjaG9vc2Ugb25lIG9mIHRoZSBmb2xsb3dpbmcgc3VwcG9ydGVkIGNvbnNlbnQgbWFuYWdlcnM6IFwiJHtPYmplY3Qua2V5cyhjb25zZW50TWFuYWdlcnNUb1BsdWdpbk5hbWVNYXApfVwiLmA7Y29uc3QgTk9OX0VSUk9SX1dBUk5JTkc9KGNvbnRleHQsZXJyU3RyKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1JZ25vcmluZyBhIG5vbi1lcnJvcjogJHtlcnJTdHJ9LmA7Y29uc3QgQlJFQURDUlVNQl9FUlJPUj1gRmFpbGVkIHRvIGxvZyBicmVhZGNydW1iYDtjb25zdCBIQU5ETEVfRVJST1JfRkFJTFVSRT1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfUZhaWxlZCB0byBoYW5kbGUgdGhlIGVycm9yLmA7Y29uc3QgUExVR0lOX05BTUVfTUlTU0lOR19FUlJPUj1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVBsdWdpbiBuYW1lIGlzIG1pc3NpbmcuYDtjb25zdCBQTFVHSU5fQUxSRUFEWV9FWElTVFNfRVJST1I9KGNvbnRleHQscGx1Z2luTmFtZSk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9UGx1Z2luIFwiJHtwbHVnaW5OYW1lfVwiIGFscmVhZHkgZXhpc3RzLmA7Y29uc3QgUExVR0lOX05PVF9GT1VORF9FUlJPUj0oY29udGV4dCxwbHVnaW5OYW1lKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1QbHVnaW4gXCIke3BsdWdpbk5hbWV9XCIgbm90IGZvdW5kLmA7Y29uc3QgUExVR0lOX0VOR0lORV9CVUdfRVJST1I9KGNvbnRleHQscGx1Z2luTmFtZSk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9UGx1Z2luIFwiJHtwbHVnaW5OYW1lfVwiIG5vdCBmb3VuZCBpbiBwbHVnaW5zIGJ1dCBmb3VuZCBpbiBieU5hbWUuIFRoaXMgaW5kaWNhdGVzIGEgYnVnIGluIHRoZSBwbHVnaW4gZW5naW5lLiBQbGVhc2UgcmVwb3J0IHRoaXMgaXNzdWUgdG8gdGhlIGRldmVsb3BtZW50IHRlYW0uYDtjb25zdCBQTFVHSU5fREVQU19FUlJPUj0oY29udGV4dCxwbHVnaW5OYW1lLG5vdEV4aXN0RGVwcyk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9UGx1Z2luIFwiJHtwbHVnaW5OYW1lfVwiIGNvdWxkIG5vdCBiZSBsb2FkZWQgYmVjYXVzZSBzb21lIG9mIGl0cyBkZXBlbmRlbmNpZXMgXCIke25vdEV4aXN0RGVwc31cIiBkbyBub3QgZXhpc3QuYDtjb25zdCBQTFVHSU5fSU5WT0NBVElPTl9FUlJPUj0oY29udGV4dCxleHRQb2ludCxwbHVnaW5OYW1lKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1GYWlsZWQgdG8gaW52b2tlIHRoZSBcIiR7ZXh0UG9pbnR9XCIgZXh0ZW5zaW9uIHBvaW50IG9mIHBsdWdpbiBcIiR7cGx1Z2luTmFtZX1cIi5gO2NvbnN0IFNPVVJDRV9DT05GSUdfRkVUQ0hfRVJST1I9J0ZhaWxlZCB0byBmZXRjaCB0aGUgc291cmNlIGNvbmZpZyc7Y29uc3QgV1JJVEVfS0VZX1ZBTElEQVRJT05fRVJST1I9KGNvbnRleHQsd3JpdGVLZXkpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSB3cml0ZSBrZXkgXCIke3dyaXRlS2V5fVwiIGlzIGludmFsaWQuIEl0IG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nLiBQbGVhc2UgY2hlY2sgdGhhdCB0aGUgd3JpdGUga2V5IGlzIGNvcnJlY3QgYW5kIHRyeSBhZ2Fpbi5gO2NvbnN0IERBVEFfUExBTkVfVVJMX1ZBTElEQVRJT05fRVJST1I9KGNvbnRleHQsZGF0YVBsYW5lVXJsKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1UaGUgZGF0YSBwbGFuZSBVUkwgXCIke2RhdGFQbGFuZVVybH1cIiBpcyBpbnZhbGlkLiBJdCBtdXN0IGJlIGEgdmFsaWQgVVJMIHN0cmluZy4gUGxlYXNlIGNoZWNrIHRoYXQgdGhlIGRhdGEgcGxhbmUgVVJMIGlzIGNvcnJlY3QgYW5kIHRyeSBhZ2Fpbi5gO2NvbnN0IElOVkFMSURfQ0FMTEJBQ0tfRk5fRVJST1I9Y29udGV4dD0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1UaGUgcHJvdmlkZWQgY2FsbGJhY2sgcGFyYW1ldGVyIGlzIG5vdCBhIGZ1bmN0aW9uLmA7Y29uc3QgWEhSX0RFTElWRVJZX0VSUk9SPShwcmVmaXgsc3RhdHVzLHN0YXR1c1RleHQsdXJsLHJlc3BvbnNlKT0+YCR7cHJlZml4fSB3aXRoIHN0YXR1cyAke3N0YXR1c30gKCR7c3RhdHVzVGV4dH0pIGZvciBVUkw6ICR7dXJsfS4gUmVzcG9uc2U6ICR7cmVzcG9uc2UudHJpbSgpfWA7Y29uc3QgWEhSX1JFUVVFU1RfRVJST1I9KHByZWZpeCxlLHVybCk9PmAke3ByZWZpeH0gZHVlIHRvIHRpbWVvdXQgb3Igbm8gY29ubmVjdGlvbiAoJHtlP2UudHlwZTonJ30pIGF0IHRoZSBjbGllbnQgc2lkZSBmb3IgVVJMOiAke3VybH1gO2NvbnN0IFhIUl9TRU5EX0VSUk9SPShwcmVmaXgsdXJsKT0+YCR7cHJlZml4fSBmb3IgVVJMOiAke3VybH1gO2NvbnN0IFNUT1JFX0RBVEFfU0FWRV9FUlJPUj1rZXk9PmBGYWlsZWQgdG8gc2F2ZSB0aGUgdmFsdWUgZm9yIFwiJHtrZXl9XCIgdG8gc3RvcmFnZWA7Y29uc3QgU1RPUkVfREFUQV9GRVRDSF9FUlJPUj1rZXk9PmBGYWlsZWQgdG8gcmV0cmlldmUgb3IgcGFyc2UgZGF0YSBmb3IgXCIke2tleX1cIiBmcm9tIHN0b3JhZ2VgO2NvbnN0IERBVEFfU0VSVkVSX1JFUVVFU1RfRkFJTF9FUlJPUj1zdGF0dXM9PmBUaGUgc2VydmVyIHJlc3BvbmRlZCB3aXRoIHN0YXR1cyAke3N0YXR1c30gd2hpbGUgc2V0dGluZyB0aGUgY29va2llcy4gQXMgYSBmYWxsYmFjaywgdGhlIGNvb2tpZXMgd2lsbCBiZSBzZXQgY2xpZW50IHNpZGUuYDtjb25zdCBGQUlMRURfU0VUVElOR19DT09LSUVfRlJPTV9TRVJWRVJfRVJST1I9a2V5PT5gVGhlIHNlcnZlciBmYWlsZWQgdG8gc2V0IHRoZSAke2tleX0gY29va2llLiBBcyBhIGZhbGxiYWNrLCB0aGUgY29va2llcyB3aWxsIGJlIHNldCBjbGllbnQgc2lkZS5gO2NvbnN0IEZBSUxFRF9TRVRUSU5HX0NPT0tJRV9GUk9NX1NFUlZFUl9HTE9CQUxfRVJST1I9YEZhaWxlZCB0byBzZXQvcmVtb3ZlIGNvb2tpZXMgdmlhIHNlcnZlci4gQXMgYSBmYWxsYmFjaywgdGhlIGNvb2tpZXMgd2lsbCBiZSBtYW5hZ2VkIGNsaWVudCBzaWRlLmA7Ly8gV0FSTklOR1xuY29uc3QgU1RPUkFHRV9UW
1VBFX1ZBTElEQVRJT05fV0FSTklORz0oY29udGV4dCxzdG9yYWdlVHlwZSxkZWZhdWx0U3RvcmFnZVR5cGUpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBzdG9yYWdlIHR5cGUgXCIke3N0b3JhZ2VUeXBlfVwiIGlzIG5vdCBzdXBwb3J0ZWQuIFBsZWFzZSBjaG9vc2Ugb25lIG9mIHRoZSBmb2xsb3dpbmcgc3VwcG9ydGVkIHR5cGVzOiBcIiR7U1VQUE9SVEVEX1NUT1JBR0VfVFlQRVN9XCIuIFRoZSBkZWZhdWx0IHR5cGUgXCIke2RlZmF1bHRTdG9yYWdlVHlwZX1cIiB3aWxsIGJlIHVzZWQgaW5zdGVhZC5gO2NvbnN0IFVOU1VQUE9SVEVEX1NUT1JBR0VfRU5DUllQVElPTl9WRVJTSU9OX1dBUk5JTkc9KGNvbnRleHQsc2VsZWN0ZWRTdG9yYWdlRW5jcnlwdGlvblZlcnNpb24sc3RvcmFnZUVuY3J5cHRpb25WZXJzaW9uc1RvUGx1Z2luTmFtZU1hcCxkZWZhdWx0VmVyc2lvbik9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9VGhlIHN0b3JhZ2UgZW5jcnlwdGlvbiB2ZXJzaW9uIFwiJHtzZWxlY3RlZFN0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbn1cIiBpcyBub3Qgc3VwcG9ydGVkLiBQbGVhc2UgY2hvb3NlIG9uZSBvZiB0aGUgZm9sbG93aW5nIHN1cHBvcnRlZCB2ZXJzaW9uczogXCIke09iamVjdC5rZXlzKHN0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbnNUb1BsdWdpbk5hbWVNYXApfVwiLiBUaGUgZGVmYXVsdCB2ZXJzaW9uIFwiJHtkZWZhdWx0VmVyc2lvbn1cIiB3aWxsIGJlIHVzZWQgaW5zdGVhZC5gO2NvbnN0IFNUT1JBR0VfREFUQV9NSUdSQVRJT05fT1ZFUlJJREVfV0FSTklORz0oY29udGV4dCxzdG9yYWdlRW5jcnlwdGlvblZlcnNpb24sZGVmYXVsdFZlcnNpb24pPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBzdG9yYWdlIGRhdGEgbWlncmF0aW9uIGhhcyBiZWVuIGRpc2FibGVkIGJlY2F1c2UgdGhlIGNvbmZpZ3VyZWQgc3RvcmFnZSBlbmNyeXB0aW9uIHZlcnNpb24gKCR7c3RvcmFnZUVuY3J5cHRpb25WZXJzaW9ufSkgaXMgbm90IHRoZSBsYXRlc3QgKCR7ZGVmYXVsdFZlcnNpb259KS4gVG8gZW5hYmxlIHN0b3JhZ2UgZGF0YSBtaWdyYXRpb24sIHBsZWFzZSB1cGRhdGUgdGhlIHN0b3JhZ2UgZW5jcnlwdGlvbiB2ZXJzaW9uIHRvIHRoZSBsYXRlc3QgdmVyc2lvbi5gO2NvbnN0IFNFUlZFUl9TSURFX0NPT0tJRV9GRUFUVVJFX09WRVJSSURFX1dBUk5JTkc9KGNvbnRleHQscHJvdmlkZWRDb29raWVEb21haW4sY3VycmVudENvb2tpZURvbWFpbik9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9VGhlIHByb3ZpZGVkIGNvb2tpZSBkb21haW4gKCR7cHJvdmlkZWRDb29raWVEb21haW59KSBkb2VzIG5vdCBtYXRjaCB0aGUgY3VycmVudCB3ZWJwYWdlJ3MgZG9tYWluICgke2N1cnJlbnRDb29raWVEb21haW59KS4gSGVuY2UsIHRoZSBjb29raWVzIHdpbGwgYmUgc2V0IGNsaWVudC1zaWRlLmA7Y29uc3QgUkVTRVJWRURfS0VZV09SRF9XQVJOSU5HPShjb250ZXh0LHByb3BlcnR5LHBhcmVudEtleVBhdGgscmVzZXJ2ZWRFbGVtZW50cyk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9VGhlIFwiJHtwcm9wZXJ0eX1cIiBwcm9wZXJ0eSBkZWZpbmVkIHVuZGVyIFwiJHtwYXJlbnRLZXlQYXRofVwiIGlzIGEgcmVzZXJ2ZWQga2V5d29yZC4gUGxlYXNlIGNob29zZSBhIGRpZmZlcmVudCBwcm9wZXJ0eSBuYW1lIHRvIGF2b2lkIGNvbmZsaWN0cyB3aXRoIHJlc2VydmVkIGtleXdvcmRzICgke3Jlc2VydmVkRWxlbWVudHN9KS5gO2NvbnN0IElOVkFMSURfQ09OVEVYVF9PQkpFQ1RfV0FSTklORz1sb2dDb250ZXh0PT5gJHtsb2dDb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVBsZWFzZSBtYWtlIHN1cmUgdGhhdCB0aGUgXCJjb250ZXh0XCIgcHJvcGVydHkgaW4gdGhlIGV2ZW50IEFQSSdzIFwib3B0aW9uc1wiIGFyZ3VtZW50IGlzIGEgdmFsaWQgb2JqZWN0IGxpdGVyYWwgd2l0aCBrZXktdmFsdWUgcGFpcnMuYDtjb25zdCBVTlNVUFBPUlRFRF9CRUFDT05fQVBJX1dBUk5JTkc9Y29udGV4dD0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1UaGUgQmVhY29uIEFQSSBpcyBub3Qgc3VwcG9ydGVkIGJ5IHlvdXIgYnJvd3Nlci4gVGhlIGV2ZW50cyB3aWxsIGJlIHNlbnQgdXNpbmcgWEhSIGluc3RlYWQuYDtjb25zdCBUSU1FT1VUX05PVF9OVU1CRVJfV0FSTklORz0oY29udGV4dCx0aW1lb3V0LGRlZmF1bHRWYWx1ZSk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9VGhlIHNlc3Npb24gdGltZW91dCB2YWx1ZSBcIiR7dGltZW91dH1cIiBpcyBub3QgYSBudW1iZXIuIFRoZSBkZWZhdWx0IHRpbWVvdXQgb2YgJHtkZWZhdWx0VmFsdWV9IG1zIHdpbGwgYmUgdXNlZCBpbnN0ZWFkLmA7Y29uc3QgQ1VUX09GRl9EVVJBVElPTl9OT1RfTlVNQkVSX1dBUk5JTkc9KGNvbnRleHQsY3V0T2ZmRHVyYXRpb24sZGVmYXVsdFZhbHVlKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1UaGUgc2Vzc2lvbiBjdXQgb2ZmIGR1cmF0aW9uIHZhbHVlIFwiJHtjdXRPZmZEdXJhdGlvbn1cIiBpcyBub3QgYSBudW1iZXIuIFRoZSBkZWZhdWx0IGN1dCBvZmYgZHVyYXRpb24gb2YgJHtkZWZhdWx0VmFsdWV9IG1zIHdpbGwgYmUgdXNlZCBpbnN0ZWFkLmA7Y29uc3QgQ1VUX09GRl9EVVJBVElPTl9MRVNTX1RIQU5fVElNRU9VVF9XQVJOSU5HPShjb250ZXh0LGN1dE9mZkR1cmF0aW9uLHRpbWVvdXQpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBzZXNzaW9uIGN1dCBvZmYgZHVyYXRpb24gdmFsdWUgXCIke2N1dE9mZkR1cmF0aW9ufVwiIG1zIGlzIGxlc3MgdGhhbiB0aGUgc2Vzc2lvbiB0aW1lb3V0IHZhbHVlIFwiJHt0aW1lb3V0fVwiIG1zLiBUaGUgY3V0IG9mZiBmdW5jdGlvbmFsaXR5IHdpbGwgYmUgZGlzYWJsZWQuYDtjb25zdCBUSU1FT1VUX1pFUk9fV0FSTklORz1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBzZXNzaW9uIHRpbWVvdXQgdmFsdWUgaXMgMCwgd2hpY2ggZGlzYWJsZXMgdGhlIGF1dG9tYXRpYyBzZXNzaW9uIHRyYWNraW5nIGZlYXR1cmUuIElmIHlvdSB3YW50IHRvIGVuYWJsZSBzZXNzaW9uIHRyYWNraW5nLCBwbGVhc2UgcHJvdmlkZSBhIHBvc2l0aXZlIGludGVnZXIgdmFsdWUgZm9yIHRoZSB0aW1lb3V0LmA7Y29uc3QgVElNRU9VVF9OT1RfUkVDT01NRU5ERURfV0FSTklORz0oY29udGV4dCx0aW1lb3V0LG1pblRpbWVvdXQpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBzZXNzaW9uIHRpbWVvdXQgdmFsdWUgJHt0aW1lb3V0fSBtcyBpcyBsZXNzIHRoYW4gdGhlIHJlY29tbWVuZGVkIG1pbmltdW0gb2YgJHttaW5UaW1lb3V0fSBtcy4gUGxlYXNlIGNvbnNpZGVyIGluY3JlYXNpbmcgdGhlIHRpbWVvdXQgdmFsdWUgdG8gZW5zdXJlIG9wdGltYWwgcGVyZm9ybWFuY2UgYW5kIHJlbGlhYmlsaXR5LmA7Y29uc3QgSU5WQUxJRF9TRVNTSU9OX0lEX1dBUk5JTkc9KGNvbnRleHQsc2Vzc2lvbklkLG1pblNlc3Npb25JZExlbmd0aCk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVB
1BUkFUT1J9VGhlIHByb3ZpZGVkIHNlc3Npb24gSUQgKCR7c2Vzc2lvbklkfSkgaXMgZWl0aGVyIGludmFsaWQsIG5vdCBhIHBvc2l0aXZlIGludGVnZXIsIG9yIG5vdCBhdCBsZWFzdCBcIiR7bWluU2Vzc2lvbklkTGVuZ3RofVwiIGRpZ2l0cyBsb25nLiBBIG5ldyBzZXNzaW9uIElEIHdpbGwgYmUgYXV0by1nZW5lcmF0ZWQgaW5zdGVhZC5gO2NvbnN0IFNUT1JBR0VfUVVPVEFfRVhDRUVERURfV0FSTklORz1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBzdG9yYWdlIGlzIGVpdGhlciBmdWxsIG9yIHVuYXZhaWxhYmxlLCBzbyB0aGUgZGF0YSB3aWxsIG5vdCBiZSBwZXJzaXN0ZWQuIFN3aXRjaGluZyB0byBpbi1tZW1vcnkgc3RvcmFnZS5gO2NvbnN0IFNUT1JBR0VfVU5BVkFJTEFCTEVfV0FSTklORz0oY29udGV4dCxlbnRyeSxzZWxlY3RlZFN0b3JhZ2VUeXBlLGZpbmFsU3RvcmFnZVR5cGUpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBzdG9yYWdlIHR5cGUgXCIke3NlbGVjdGVkU3RvcmFnZVR5cGV9XCIgaXMgbm90IGF2YWlsYWJsZSBmb3IgZW50cnkgXCIke2VudHJ5fVwiLiBUaGUgU0RLIHdpbGwgaW5pdGlhbGl6ZSB0aGUgZW50cnkgd2l0aCBcIiR7ZmluYWxTdG9yYWdlVHlwZX1cIiBzdG9yYWdlIHR5cGUgaW5zdGVhZC5gO2NvbnN0IENBTExCQUNLX0lOVk9LRV9FUlJPUj1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBjYWxsYmFjayB0aHJldyBhbiBleGNlcHRpb25gO2NvbnN0IElOVkFMSURfQ09ORklHX1VSTF9XQVJOSU5HPShjb250ZXh0LGNvbmZpZ1VybCk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9VGhlIHByb3ZpZGVkIHNvdXJjZSBjb25maWcgVVJMIFwiJHtjb25maWdVcmx9XCIgaXMgaW52YWxpZC4gVXNpbmcgdGhlIGRlZmF1bHQgc291cmNlIGNvbmZpZyBVUkwgaW5zdGVhZC5gO2NvbnN0IFBPTFlGSUxMX1NDUklQVF9MT0FEX0VSUk9SPShzY3JpcHRJZCx1cmwpPT5gRmFpbGVkIHRvIGxvYWQgdGhlIHBvbHlmaWxsIHNjcmlwdCB3aXRoIElEIFwiJHtzY3JpcHRJZH1cIiBmcm9tIFVSTCAke3VybH0uYDtjb25zdCBVTlNVUFBPUlRFRF9QUkVfQ09OU0VOVF9TVE9SQUdFX1NUUkFURUdZPShjb250ZXh0LHNlbGVjdGVkU3RyYXRlZ3ksZGVmYXVsdFN0cmF0ZWd5KT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1UaGUgcHJlLWNvbnNlbnQgc3RvcmFnZSBzdHJhdGVneSBcIiR7c2VsZWN0ZWRTdHJhdGVneX1cIiBpcyBub3Qgc3VwcG9ydGVkLiBQbGVhc2UgY2hvb3NlIG9uZSBvZiB0aGUgZm9sbG93aW5nIHN1cHBvcnRlZCBzdHJhdGVnaWVzOiBcIm5vbmUsIHNlc3Npb24sIGFub255bW91c0lkXCIuIFRoZSBkZWZhdWx0IHN0cmF0ZWd5IFwiJHtkZWZhdWx0U3RyYXRlZ3l9XCIgd2lsbCBiZSB1c2VkIGluc3RlYWQuYDtjb25zdCBVTlNVUFBPUlRFRF9QUkVfQ09OU0VOVF9FVkVOVFNfREVMSVZFUllfVFlQRT0oY29udGV4dCxzZWxlY3RlZERlbGl2ZXJ5VHlwZSxkZWZhdWx0RGVsaXZlcnlUeXBlKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1UaGUgcHJlLWNvbnNlbnQgZXZlbnRzIGRlbGl2ZXJ5IHR5cGUgXCIke3NlbGVjdGVkRGVsaXZlcnlUeXBlfVwiIGlzIG5vdCBzdXBwb3J0ZWQuIFBsZWFzZSBjaG9vc2Ugb25lIG9mIHRoZSBmb2xsb3dpbmcgc3VwcG9ydGVkIHR5cGVzOiBcImltbWVkaWF0ZSwgYnVmZmVyXCIuIFRoZSBkZWZhdWx0IHR5cGUgXCIke2RlZmF1bHREZWxpdmVyeVR5cGV9XCIgd2lsbCBiZSB1c2VkIGluc3RlYWQuYDtjb25zdCBERVBSRUNBVEVEX1BMVUdJTl9XQVJOSU5HPShjb250ZXh0LHBsdWdpbk5hbWUpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfSR7cGx1Z2luTmFtZX0gcGx1Z2luIGlzIGRlcHJlY2F0ZWQuIFBsZWFzZSBleGNsdWRlIGl0IGZyb20gdGhlIGxvYWQgQVBJIG9wdGlvbnMuYDtjb25zdCBnZW5lcmF0ZU1pc2NvbmZpZ3VyZWRQbHVnaW5zV2FybmluZz0oY29udGV4dCxjb25maWd1cmF0aW9uU3RhdHVzLG1pc3NpbmdQbHVnaW5zLHNob3VsZEFkZE1pc3NpbmdQbHVnaW5zKT0+e2NvbnN0IGlzU2luZ2xlUGx1Z2luPW1pc3NpbmdQbHVnaW5zLmxlbmd0aD09PTE7Y29uc3QgcGx1Z2luc1N0cmluZz1pc1NpbmdsZVBsdWdpbj9gICcke21pc3NpbmdQbHVnaW5zWzBdfScgcGx1Z2luIHdhc2A6YCBbJyR7bWlzc2luZ1BsdWdpbnMuam9pbihcIicsICdcIil9J10gcGx1Z2lucyB3ZXJlYDtjb25zdCBiYXNlV2FybmluZz1gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfSR7Y29uZmlndXJhdGlvblN0YXR1c30sIGJ1dCR7cGx1Z2luc1N0cmluZ30gbm90IGNvbmZpZ3VyZWQgdG8gbG9hZC5gO2lmKHNob3VsZEFkZE1pc3NpbmdQbHVnaW5zKXtyZXR1cm4gYCR7YmFzZVdhcm5pbmd9IFNvLCAke2lzU2luZ2xlUGx1Z2luPyd0aGUgcGx1Z2luJzondGhvc2UgcGx1Z2lucyd9IHdpbGwgYmUgbG9hZGVkIGF1dG9tYXRpY2FsbHkuYDt9cmV0dXJuIGAke2Jhc2VXYXJuaW5nfSBJZ25vcmUgaWYgdGhpcyB3YXMgaW50ZW50aW9uYWwuIE90aGVyd2lzZSwgY29uc2lkZXIgYWRkaW5nICR7aXNTaW5nbGVQbHVnaW4/J2l0JzondGhlbSd9IHRvIHRoZSAncGx1Z2lucycgbG9hZCBBUEkgb3B0aW9uLmA7fTtjb25zdCBJTlZBTElEX1BPTFlGSUxMX1VSTF9XQVJOSU5HPShjb250ZXh0LGN1c3RvbVBvbHlmaWxsVXJsKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1UaGUgcHJvdmlkZWQgcG9seWZpbGwgVVJMIFwiJHtjdXN0b21Qb2x5ZmlsbFVybH1cIiBpcyBpbnZhbGlkLiBUaGUgZGVmYXVsdCBwb2x5ZmlsbCBVUkwgd2lsbCBiZSB1c2VkIGluc3RlYWQuYDtjb25zdCBQQUdFX1VOTE9BRF9PTl9CRUFDT05fRElTQUJMRURfV0FSTklORz1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVBhZ2UgVW5sb2FkZWQgZXZlbnQgY2FuIG9ubHkgYmUgdHJhY2tlZCB3aGVuIHRoZSBCZWFjb24gdHJhbnNwb3J0IGlzIGFjdGl2ZS4gUGxlYXNlIGVuYWJsZSBcInVzZUJlYWNvblwiIGxvYWQgQVBJIG9wdGlvbi5gO2NvbnN0IFVOS05PV05fUExVR0lOU19XQVJOSU5HPShjb250ZXh0LHVua25vd25QbHVnaW5zKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1JZ25vcmluZyB1bmtub3duIHBsdWdpbnM6ICR7dW5rbm93blBsdWdpbnMuam9pbignLCAnKX0uYDtjb25zdCBVTkFWQUlMQUJMRV9QTFVHSU5TX0VSUk9SPShjb250ZXh0LHVuYXZhaWxhYmxlUGx1Z2lucyk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVB
1BUkFUT1J9RmFpbGVkIHRvIGxvYWQgdGhlIGZvbGxvd2luZyB1bmF2YWlsYWJsZSBsb2NhbCBwbHVnaW5zOiAke3VuYXZhaWxhYmxlUGx1Z2lucy5qb2luKCcsICcpfS4gU29tZSBmZWF0dXJlcyBvZiB0aGUgU0RLIG1heSBub3Qgd29yayBhcyBleHBlY3RlZC4gTWFrZSBzdXJlIHlvdSBhcmUgdXNpbmcgdGhlIGNvcnJlY3QgU0RLIGJ1bmRsZSB2YXJpYW50LmA7Y29uc3QgQ1VTVE9NX0lOVEVHUkFUSU9OX0NBTk5PVF9CRV9BRERFRF9FUlJPUj0oY29udGV4dCxkZXN0aW5hdGlvbklkKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1DYW5ub3QgYWRkIGN1c3RvbSBpbnRlZ3JhdGlvbiBmb3IgZGVzdGluYXRpb24gSUQgXCIke2Rlc3RpbmF0aW9uSWR9XCIgYWZ0ZXIgdGhlIFNESyBpcyBsb2FkZWQuYDtcblxuY29uc3QgREVGQVVMVF9JTlRFR1JBVElPTlNfQ09ORklHPXtBbGw6dHJ1ZX07XG5cbmNvbnN0IENETl9JTlRfRElSPSdqcy1pbnRlZ3JhdGlvbnMnO2NvbnN0IENETl9QTFVHSU5TX0RJUj0ncGx1Z2lucyc7Y29uc3QgVVJMX1BBVFRFUk49bmV3IFJlZ0V4cCgnXihodHRwcz86XFxcXC9cXFxcLyknKy8vIHByb3RvY29sXG4nKCcrJygoKFthLXpBLVpcXFxcZF0oW2EtekEtWlxcXFxkLV0qW2EtekEtWlxcXFxkXSkqKVxcXFwuKStbYS16QS1aXXsyLH18JysvLyBkb21haW4gbmFtZVxuJ2xvY2FsaG9zdHwnKy8vIGxvY2FsaG9zdFxuJygoMjVbMC01XXwyWzAtNF1bMC05XXxbMC0xXT9bMC05XT9bMC05XT8pXFxcXC4pezN9JysvLyBPUiBJUCAodjQpIGFkZHJlc3MgZmlyc3QgMyBvY3RldHNcbicoMjVbMC01XXwyWzAtNF1bMC05XXxbMC0xXT9bMC05XT9bMC05XT8pKScrLy8gbGFzdCBvY3RldCBvZiBJUCBhZGRyZXNzXG4nKScrJyhcXFxcOlxcXFxkKyk/JysvLyBwb3J0XG4nKFxcXFwvWy1hLXpBLVpcXFxcZCVfLn4rXSopKicrLy8gcGF0aFxuJyhcXFxcP1s7JmEtekEtWlxcXFxkJV8ufis9LV0qKT8nKy8vIHF1ZXJ5IHN0cmluZ1xuJyhcXFxcI1stYS16QS1aXFxcXGRfXSopPyQnKS8vIGZyYWdtZW50IGxvY2F0b3JcbjtcblxuY29uc3QgQlVJTERfVFlQRT0nbW9kZXJuJztjb25zdCBTREtfQ0ROX0JBU0VfVVJMPSdodHRwczovL2Nkbi5ydWRkZXJsYWJzLmNvbSc7Y29uc3QgQ0ROX0FSQ0hfVkVSU0lPTl9ESVI9J3YzJztjb25zdCBERUZBVUxUX0lOVEVHUkFUSU9OX1NES1NfVVJMPWAke1NES19DRE5fQkFTRV9VUkx9LyR7Q0ROX0FSQ0hfVkVSU0lPTl9ESVJ9LyR7QlVJTERfVFlQRX0vJHtDRE5fSU5UX0RJUn1gO2NvbnN0IERFRkFVTFRfUExVR0lOU19VUkw9YCR7U0RLX0NETl9CQVNFX1VSTH0vJHtDRE5fQVJDSF9WRVJTSU9OX0RJUn0vJHtCVUlMRF9UWVBFfS8ke0NETl9QTFVHSU5TX0RJUn1gO2NvbnN0IERFRkFVTFRfQ09ORklHX0JFX1VSTD0naHR0cHM6Ly9hcGkucnVkZGVyc3RhY2suY29tJztcblxuY29uc3QgREVGQVVMVF9TVE9SQUdFX0VOQ1JZUFRJT05fVkVSU0lPTj0ndjMnO2NvbnN0IERFRkFVTFRfREFUQV9QTEFORV9FVkVOVFNfVFJBTlNQT1JUPSd4aHInO2NvbnN0IENvbnNlbnRNYW5hZ2Vyc1RvUGx1Z2luTmFtZU1hcD17aXViZW5kYTonSXViZW5kYUNvbnNlbnRNYW5hZ2VyJyxvbmVUcnVzdDonT25lVHJ1c3RDb25zZW50TWFuYWdlcicsa2V0Y2g6J0tldGNoQ29uc2VudE1hbmFnZXInLGN1c3RvbTonQ3VzdG9tQ29uc2VudE1hbmFnZXInfTtjb25zdCBTdG9yYWdlRW5jcnlwdGlvblZlcnNpb25zVG9QbHVnaW5OYW1lTWFwPXtbREVGQVVMVF9TVE9SQUdFX0VOQ1JZUFRJT05fVkVSU0lPTl06J1N0b3JhZ2VFbmNyeXB0aW9uJyxsZWdhY3k6J1N0b3JhZ2VFbmNyeXB0aW9uTGVnYWN5J307Y29uc3QgRGF0YVBsYW5lRXZlbnRzVHJhbnNwb3J0VG9QbHVnaW5OYW1lTWFwPXtbREVGQVVMVF9EQVRBX1BMQU5FX0VWRU5UU19UUkFOU1BPUlRdOidYaHJRdWV1ZScsYmVhY29uOidCZWFjb25RdWV1ZSd9O2NvbnN0IERFRkFVTFRfREFUQV9TRVJWSUNFX0VORFBPSU5UPSdyc2FSZXF1ZXN0Jztjb25zdCBNRVRSSUNTX1NFUlZJQ0VfRU5EUE9JTlQ9J3JzYU1ldHJpY3MnO2NvbnN0IENVU1RPTV9ERVZJQ0VfTU9ERV9ERVNUSU5BVElPTl9ESVNQTEFZX05BTUU9J0N1c3RvbSBEZXZpY2UgTW9kZSc7XG5cbmNvbnN0IGRlZmF1bHRMb2FkT3B0aW9ucz17Y29uZmlnVXJsOkRFRkFVTFRfQ09ORklHX0JFX1VSTCxsb2FkSW50ZWdyYXRpb246dHJ1ZSxzZXNzaW9uczp7YXV0b1RyYWNrOnRydWUsdGltZW91dDpERUZBVUxUX1NFU1NJT05fVElNRU9VVF9NUyxjdXRPZmY6e2VuYWJsZWQ6ZmFsc2V9fSxzYW1lU2l0ZUNvb2tpZTonTGF4Jyxwb2x5ZmlsbElmUmVxdWlyZWQ6dHJ1ZSxpbnRlZ3JhdGlvbnM6REVGQVVMVF9JTlRFR1JBVElPTlNfQ09ORklHLHVzZUJlYWNvbjpmYWxzZSxiZWFjb25RdWV1ZU9wdGlvbnM6e30sZGVzdGluYXRpb25zUXVldWVPcHRpb25zOnt9LHF1ZXVlT3B0aW9uczp7fSxsb2NrSW50ZWdyYXRpb25zVmVyc2lvbjp0cnVlLGxvY2tQbHVnaW5zVmVyc2lvbjp0cnVlLHVhQ2hUcmFja0xldmVsOidub25lJyxwbHVnaW5zOltdLHVzZUdsb2JhbEludGVncmF0aW9uc0NvbmZpZ0luRXZlbnRzOmZhbHNlLGJ1ZmZlckRhdGFQbGFuZUV2ZW50c1VudGlsUmVhZHk6ZmFsc2UsZGF0YVBsYW5lRXZlbnRzQnVmZmVyVGltZW91dDpERUZBVUxUX0RBVEFfUExBTkVfRVZFTlRTX0JVRkZFUl9USU1FT1VUX01TLHN0b3JhZ2U6e2VuY3J5cHRpb246e3ZlcnNpb246REVGQVVMVF9TVE9SQUdFX0VOQ1JZUFRJT05fVkVSU0lPTn0sbWlncmF0ZTp0cnVlLGNvb2tpZTp7fX0sc2VuZEFkYmxvY2tQYWdlOmZhbHNlLHNhbWVEb21haW5Db29raWVzT25seTpmYWxzZSxzZWN1cmVDb29raWU6ZmFsc2Usc2VuZEFkYmxvY2tQYWdlT3B0aW9uczp7fSx1c2VTZXJ2ZXJTaWRlQ29va2llczpmYWxzZX07Y29uc3QgbG9hZE9wdGlvbnNTdGF0ZT15KGNsb25lKGRlZmF1bHRMb2FkT3B0aW9ucykpO1xuXG5jb25zdCBERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVM9ZGVlcEZyZWV6ZSh7dXNlcklkOicnLHVzZXJUcmFpdHM6e30sYW5vbnltb3VzSWQ6JycsZ3JvdXBJZDonJyxncm91cFRyYWl0czp7fSxpbml0aWFsUmVmZXJyZXI6JycsaW5pdGlhbFJlZmVycmluZ0RvbWFpbjonJyxzZXNzaW9uSW5mbzp7fSxhdXRoVG9rZW46bnVsbH0pO2NvbnN0IERFRkFVTFRfUkVTRVRfT1BUSU9OUz1kZWVwRnJlZXplKHtlbnRyaWVzOnt1c2VySWQ6dHJ1ZSx1c2VyVHJhaXRzOnRydWUsZ3JvdXBJZDp0cnVlLGdyb3VwVHJhaXRzOnRydWUsc2Vzc2lvbkluZm86dHJ1ZSxhdXRoVG9rZW46dHJ1ZSwvLyBUaGVzZSBhcmUgbm90IHJlc2V0IGJ5IGRlZmF1bHRcbmFub25
15bW91c0lkOmZhbHNlLGluaXRpYWxSZWZlcnJlcjpmYWxzZSxpbml0aWFsUmVmZXJyaW5nRG9tYWluOmZhbHNlfX0pO2NvbnN0IFNFUlZFUl9TSURFX0NPT0tJRVNfREVCT1VOQ0VfVElNRT0xMDsvLyBtaWxsaXNlY29uZHNcblxuY29uc3Qgc2Vzc2lvblN0YXRlPXt1c2VySWQ6eShERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMudXNlcklkKSx1c2VyVHJhaXRzOnkoREVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLnVzZXJUcmFpdHMpLGFub255bW91c0lkOnkoREVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLmFub255bW91c0lkKSxncm91cElkOnkoREVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLmdyb3VwSWQpLGdyb3VwVHJhaXRzOnkoREVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLmdyb3VwVHJhaXRzKSxpbml0aWFsUmVmZXJyZXI6eShERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMuaW5pdGlhbFJlZmVycmVyKSxpbml0aWFsUmVmZXJyaW5nRG9tYWluOnkoREVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLmluaXRpYWxSZWZlcnJpbmdEb21haW4pLHNlc3Npb25JbmZvOnkoREVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLnNlc3Npb25JbmZvKSxhdXRoVG9rZW46eShERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMuYXV0aFRva2VuKX07XG5cbmNvbnN0IGNhcGFiaWxpdGllc1N0YXRlPXtpc09ubGluZTp5KHRydWUpLHN0b3JhZ2U6e2lzTG9jYWxTdG9yYWdlQXZhaWxhYmxlOnkoZmFsc2UpLGlzQ29va2llU3RvcmFnZUF2YWlsYWJsZTp5KGZhbHNlKSxpc1Nlc3Npb25TdG9yYWdlQXZhaWxhYmxlOnkoZmFsc2UpfSxpc0JlYWNvbkF2YWlsYWJsZTp5KGZhbHNlKSxpc0xlZ2FjeURPTTp5KGZhbHNlKSxpc1VhQ0hBdmFpbGFibGU6eShmYWxzZSksaXNDcnlwdG9BdmFpbGFibGU6eShmYWxzZSksaXNBZEJsb2NrZXJEZXRlY3Rpb25JblByb2dyZXNzOnkoZmFsc2UpLGlzQWRCbG9ja2VkOnkodW5kZWZpbmVkKSxjc3BCbG9ja2VkVVJMczp5KFtdKX07XG5cbmNvbnN0IHJlcG9ydGluZ1N0YXRlPXtpc0Vycm9yUmVwb3J0aW5nRW5hYmxlZDp5KGZhbHNlKSxpc01ldHJpY3NSZXBvcnRpbmdFbmFibGVkOnkoZmFsc2UpLGJyZWFkY3J1bWJzOnkoW10pfTtcblxuY29uc3Qgc291cmNlQ29uZmlnU3RhdGU9eSh1bmRlZmluZWQpO1xuXG5jb25zdCBsaWZlY3ljbGVTdGF0ZT17YWN0aXZlRGF0YXBsYW5lVXJsOnkodW5kZWZpbmVkKSxpbnRlZ3JhdGlvbnNDRE5QYXRoOnkoREVGQVVMVF9JTlRFR1JBVElPTl9TREtTX1VSTCkscGx1Z2luc0NETlBhdGg6eShERUZBVUxUX1BMVUdJTlNfVVJMKSxzb3VyY2VDb25maWdVcmw6eSh1bmRlZmluZWQpLHN0YXR1czp5KHVuZGVmaW5lZCksaW5pdGlhbGl6ZWQ6eShmYWxzZSksbG9nTGV2ZWw6eShQT1NUX0xPQURfTE9HX0xFVkVMKSxsb2FkZWQ6eShmYWxzZSkscmVhZHlDYWxsYmFja3M6eShbXSksd3JpdGVLZXk6eSh1bmRlZmluZWQpLGRhdGFQbGFuZVVybDp5KHVuZGVmaW5lZCksc2FmZUFuYWx5dGljc0luc3RhbmNlOnkodW5kZWZpbmVkKX07XG5cbmNvbnN0IGNvbnNlbnRzU3RhdGU9e2VuYWJsZWQ6eShmYWxzZSksaW5pdGlhbGl6ZWQ6eShmYWxzZSksZGF0YTp5KHt9KSxhY3RpdmVDb25zZW50TWFuYWdlclBsdWdpbk5hbWU6eSh1bmRlZmluZWQpLHByZUNvbnNlbnQ6eSh7ZW5hYmxlZDpmYWxzZX0pLHBvc3RDb25zZW50Onkoe30pLHJlc29sdXRpb25TdHJhdGVneTp5KCdhbmQnKSxwcm92aWRlcjp5KHVuZGVmaW5lZCksbWV0YWRhdGE6eSh1bmRlZmluZWQpfTtcblxuY29uc3QgbWV0cmljc1N0YXRlPXtyZXRyaWVzOnkoMCksZHJvcHBlZDp5KDApLHNlbnQ6eSgwKSxxdWV1ZWQ6eSgwKSx0cmlnZ2VyZWQ6eSgwKSxtZXRyaWNzU2VydmljZVVybDp5KHVuZGVmaW5lZCl9O1xuXG5jb25zdCBnZXRWYXJpYW50VmFsdWU9KCk9PnsvLyBGb3IgQ0ROIGJ1aWxkcywgdXNlIHJ1bnRpbWUgd2luZG93LnJ1ZGRlckFuYWx5dGljc0J1aWxkVHlwZVxucmV0dXJuIEJVSUxEX1ZBUklBTlQ7fTtjb25zdCBjb250ZXh0U3RhdGU9e2FwcDp5KHtuYW1lOkFQUF9OQU1FLG5hbWVzcGFjZTpBUFBfTkFNRVNQQUNFLHZlcnNpb246QVBQX1ZFUlNJT04saW5zdGFsbFR5cGU6TU9EVUxFX1RZUEV9KSx0cmFpdHM6eShudWxsKSxsaWJyYXJ5Onkoe25hbWU6QVBQX05BTUUsdmVyc2lvbjpBUFBfVkVSU0lPTixzbmlwcGV0VmVyc2lvbjpnbG9iYWxUaGlzLlJ1ZGRlclNuaXBwZXRWZXJzaW9uLHZhcmlhbnQ6Z2V0VmFyaWFudFZhbHVlKCl9KSx1c2VyQWdlbnQ6eShudWxsKSxkZXZpY2U6eShudWxsKSxuZXR3b3JrOnkobnVsbCksb3M6eSh7bmFtZTonJyx2ZXJzaW9uOicnfSksbG9jYWxlOnkobnVsbCksc2NyZWVuOnkoe2RlbnNpdHk6MCx3aWR0aDowLGhlaWdodDowLGlubmVyV2lkdGg6MCxpbm5lckhlaWdodDowfSksJ3VhLWNoJzp5KHVuZGVmaW5lZCksdGltZXpvbmU6eSh1bmRlZmluZWQpfTtcblxuY29uc3QgbmF0aXZlRGVzdGluYXRpb25zU3RhdGU9e2NvbmZpZ3VyZWREZXN0aW5hdGlvbnM6eShbXSksYWN0aXZlRGVzdGluYXRpb25zOnkoW10pLGxvYWRPbmx5SW50ZWdyYXRpb25zOnkoe30pLGZhaWxlZERlc3RpbmF0aW9uczp5KFtdKSxsb2FkSW50ZWdyYXRpb246eSh0cnVlKSxpbml0aWFsaXplZERlc3RpbmF0aW9uczp5KFtdKSxjbGllbnREZXN0aW5hdGlvbnNSZWFkeTp5KGZhbHNlKSxpbnRlZ3JhdGlvbnNDb25maWc6eSh7fSl9O1xuXG5jb25zdCBldmVudEJ1ZmZlclN0YXRlPXt0b0JlUHJvY2Vzc2VkQXJyYXk6eShbXSkscmVhZHlDYWxsYmFja3NBcnJheTp5KFtdKX07XG5cbmNvbnN0IHBsdWdpbnNTdGF0ZT17cmVhZHk6eShmYWxzZSksbG9h
1ZGVkUGx1Z2luczp5KFtdKSxmYWlsZWRQbHVnaW5zOnkoW10pLHBsdWdpbnNUb0xvYWRGcm9tQ29uZmlnOnkoW10pLGFjdGl2ZVBsdWdpbnM6eShbXSksdG90YWxQbHVnaW5zVG9Mb2FkOnkoMCl9O1xuXG5jb25zdCBzdG9yYWdlU3RhdGU9e2VuY3J5cHRpb25QbHVnaW5OYW1lOnkodW5kZWZpbmVkKSxtaWdyYXRlOnkoZmFsc2UpLHR5cGU6eSh1bmRlZmluZWQpLGNvb2tpZTp5KHVuZGVmaW5lZCksZW50cmllczp5KHt9KSx0cnVseUFub255bW91c1RyYWNraW5nOnkoZmFsc2UpfTtcblxuY29uc3Qgc2VydmVyU2lkZUNvb2tpZXNTdGF0ZT17aXNFbmFibGVkU2VydmVyU2lkZUNvb2tpZXM6eShmYWxzZSksZGF0YVNlcnZpY2VVcmw6eSh1bmRlZmluZWQpfTtcblxuY29uc3QgZGF0YVBsYW5lRXZlbnRzU3RhdGU9e2V2ZW50c1F1ZXVlUGx1Z2luTmFtZTp5KHVuZGVmaW5lZCksZGVsaXZlcnlFbmFibGVkOnkodHJ1ZSkvLyBEZWxpdmVyeSBzaG91bGQgYWx3YXlzIGhhcHBlblxufTtcblxuY29uc3QgYXV0b1RyYWNrU3RhdGU9e2VuYWJsZWQ6eShmYWxzZSkscGFnZUxpZmVjeWNsZTp7ZW5hYmxlZDp5KGZhbHNlKSxwYWdlVmlld0lkOnkodW5kZWZpbmVkKSxwYWdlTG9hZGVkVGltZXN0YW1wOnkodW5kZWZpbmVkKX19O1xuXG5jb25zdCBkZWZhdWx0U3RhdGVWYWx1ZXM9e2NhcGFiaWxpdGllczpjYXBhYmlsaXRpZXNTdGF0ZSxjb25zZW50czpjb25zZW50c1N0YXRlLGNvbnRleHQ6Y29udGV4dFN0YXRlLGV2ZW50QnVmZmVyOmV2ZW50QnVmZmVyU3RhdGUsbGlmZWN5Y2xlOmxpZmVjeWNsZVN0YXRlLGxvYWRPcHRpb25zOmxvYWRPcHRpb25zU3RhdGUsbWV0cmljczptZXRyaWNzU3RhdGUsbmF0aXZlRGVzdGluYXRpb25zOm5hdGl2ZURlc3RpbmF0aW9uc1N0YXRlLHBsdWdpbnM6cGx1Z2luc1N0YXRlLHJlcG9ydGluZzpyZXBvcnRpbmdTdGF0ZSxzZXNzaW9uOnNlc3Npb25TdGF0ZSxzb3VyY2U6c291cmNlQ29uZmlnU3RhdGUsc3RvcmFnZTpzdG9yYWdlU3RhdGUsc2VydmVyQ29va2llczpzZXJ2ZXJTaWRlQ29va2llc1N0YXRlLGRhdGFQbGFuZUV2ZW50czpkYXRhUGxhbmVFdmVudHNTdGF0ZSxhdXRvVHJhY2s6YXV0b1RyYWNrU3RhdGV9O2NvbnN0IHN0YXRlPXsuLi5jbG9uZShkZWZhdWx0U3RhdGVWYWx1ZXMpfTtcblxuY29uc3QgQ0hST01FX1NUQUNLX0xJTkVfUkU9L15cXHMqYXQgLztjb25zdCBTQUZBUklfTkFUSVZFX1JFPS9eKGV2YWxAKT8oXFxbbmF0aXZlIGNvZGVdKT8kLztjb25zdCBMT0NBVElPTl9SRT0vKC4rPykoPzo6KFxcZCspKT8oPzo6KFxcZCspKT8kLztmdW5jdGlvbiBleHRyYWN0TG9jYXRpb24odXJsTGlrZSl7aWYoIXVybExpa2U/LmluY2x1ZGVzKCc6Jykpe3JldHVybiBbdXJsTGlrZXx8dW5kZWZpbmVkLHVuZGVmaW5lZCx1bmRlZmluZWRdO31jb25zdCBub3JtYWxpemVkVXJsTGlrZT11cmxMaWtlLnN0YXJ0c1dpdGgoJygnKSYmdXJsTGlrZS5lbmRzV2l0aCgnKScpP3VybExpa2Uuc2xpY2UoMSwtMSk6dXJsTGlrZTtjb25zdCBwYXJ0cz1MT0NBVElPTl9SRS5leGVjKG5vcm1hbGl6ZWRVcmxMaWtlKTtpZighcGFydHMpe3JldHVybiBbdW5kZWZpbmVkLHVuZGVmaW5lZCx1bmRlZmluZWRdO31yZXR1cm4gW3BhcnRzWzFdfHx1bmRlZmluZWQscGFydHNbMl09PT11bmRlZmluZWQ/dW5kZWZpbmVkOk51bWJlcihwYXJ0c1syXSkscGFydHNbM109PT11bmRlZmluZWQ/dW5kZWZpbmVkOk51bWJlcihwYXJ0c1szXSldO31mdW5jdGlvbiBwYXJzZVY4TGluZShsaW5lKXtpZighQ0hST01FX1NUQUNLX0xJTkVfUkUudGVzdChsaW5lKSl7cmV0dXJuIG51bGw7fWlmKGxpbmUuaW5jbHVkZXMoJyhldmFsICcpKXtsaW5lPWxpbmUucmVwbGFjZUFsbCgnZXZhbCBjb2RlJywnZXZhbCcpLnJlcGxhY2VBbGwoLyhcXChldmFsIGF0IFteKCldKil8KCwuKiQpL2csJycpO31jb25zdCBzYW5pdGl6ZWQ9bGluZS5yZXBsYWNlKC9eXFxzKy8sJycpLnJlcGxhY2VBbGwoJyhldmFsIGNvZGUnLCcoJykucmVwbGFjZSgvXi4qP1xccysvLCcnKTtjb25zdCBwYXJlbkxvYz0vIChcXCguK1xcKSQpLy5leGVjKHNhbml0aXplZCk7Y29uc3Qgd2l0aG91dExvYz1wYXJlbkxvYz9zYW5pdGl6ZWQucmVwbGFjZShwYXJlbkxvY1swXSwnJyk6c2FuaXRpemVkO2NvbnN0W3Jhd0ZpbGUsbGluZU51bWJlcixjb2x1bW5OdW1iZXJdPWV4dHJhY3RMb2NhdGlvbihwYXJlbkxvYz9wYXJlbkxvY1sxXTpzYW5pdGl6ZWQpO2NvbnN0IGZ1bmN0aW9uTmFtZT1wYXJlbkxvYyYmd2l0aG91dExvY3x8dW5kZWZpbmVkO2NvbnN0IGZpbGVOYW1lPXJhd0ZpbGU9PT0nZXZhbCd8fHJhd0ZpbGU9PT0nPGFub255bW91cz4nP3VuZGVmaW5lZDpyYXdGaWxlO3JldHVybiB7ZnVuY3Rpb25OYW1lLGZpbGVOYW1lLGxpbmVOdW1iZXIsY29sdW1uTnVtYmVyfTt9ZnVuY3Rpb24gcGFyc2VGRlNhZmFyaUxpbmUobGluZSl7aWYoU0FGQVJJX05BVElWRV9SRS50ZXN0KGxpbmUpKXtyZXR1cm4gbnVsbDt9aWYobGluZS5pbmNsdWRlcygnID4gZXZhbCcpKXtsaW5lPWxpbmUucmVwbGFjZUFsbCgvIGxpbmUgKFxcZCspKD86ID4gZXZhbCBsaW5lIFxcZCspKiA+IGV2YWw6XFxkKzpcXGQrL2csJzokMScpO31pZighbGluZS5pbmNsdWRlcygnQCcpJiYhbGluZS5pbmNsdWRlcygnOicpKXtyZXR1cm4ge2Z1bmN0aW9uTmFtZTpsaW5lLGZpbGVOYW1lOnVuZGVmaW5lZCxsaW5lTnVtYmVyOnVuZGVmaW5lZCxjb2x1bW5OdW1iZXI6dW5kZWZpbmVkfTt9Y29uc3QgYXRJbmRleD1saW5lLmxhc3RJbmRleE9mKCdAJyk7Y29uc3QgZnVuY3Rpb25OYW1lPWF0SW5kZXg+MD9saW5lLnNsaWNlKDAsYXRJbmRleCk6dW5kZWZpbmVkO2NvbnN0W2ZpbGVOYW1lLGxpbmVOdW1iZXIsY29sdW1uTnVtYmVyXT1leHRyYWN0TG9jYXRpb24obGluZS5zbGljZShhdEluZGV4KzEpKTtyZXR1cm4ge2Z1bmN0aW9uTmFtZSxmaWxlTmFtZSxsaW5lTnVtYmVyLGNvbHVtbk51bWJlcn07fS8qKlxuICogUGFyc2VzIGFuIEVycm9yIG9iamVjdCdzIHN0YWNrIHRyYWNlIGludG8gc3RydWN0dXJlZCBmcmFtZXMuXG4gKiBTdXBwb3J0cyBWOC9DaHJvbWl1bSAoQ2hyb21lLCBFZGdlLCBOb2RlKSBhbmQgU3BpZGVyTW9ua2V5L1dlYktpdCAoRmlyZWZveCwgU2FmYXJpKSBmb3JtYXRzLlxuICogVGhyb3dzIGlmIHRoZSBlcnJvciBoYXMgbm8gc3RhY2sgcHJvcGVydHkuXG4gKi9mdW5jdGlvbiBwYXJzZVN0YWNrVHJhY2UoZXJyb3Ipe2lmKCFlcnJvci5zdGFjayl7dGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgcGFyc2UgZ2l2ZW4gRXJyb3Igb2JqZWN0Jyk7fWNvbnN0IGxpbmVzPWVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKTtpZihsaW5lcy5zb21lKGw9PkNIUk9NRV9TVEFDS19MSU5FX1JFLnRlc3QobCkpKXtyZXR1cm4gbGluZXMubWFwKHBhcnNlVjhMaW5lKS5maWx0ZXIoZj0+ZiE9PW51bGwpO31yZXR1cm4gbGluZXMubWFwKHBhcnNlRkZTYWZhcmlMaW5lKS
15maWx0ZXIoZj0+ZiE9PW51bGwpO31cblxuY29uc3QgR0xPQkFMX0NPREU9J2dsb2JhbCBjb2RlJztjb25zdCBub3JtYWxpemVGdW5jdGlvbk5hbWU9bmFtZT0+e2lmKGlzRGVmaW5lZChuYW1lKSl7cmV0dXJuIC9eZ2xvYmFsIGNvZGUkL2kudGVzdChuYW1lKT9HTE9CQUxfQ09ERTpuYW1lO31yZXR1cm4gbmFtZTt9O2NvbnN0IGZvcm1hdFN0YWNrZnJhbWU9ZnJhbWU9Pntjb25zdCBmPXtmaWxlOmZyYW1lLmZpbGVOYW1lLG1ldGhvZDpub3JtYWxpemVGdW5jdGlvbk5hbWUoZnJhbWUuZnVuY3Rpb25OYW1lKSxsaW5lTnVtYmVyOmZyYW1lLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOmZyYW1lLmNvbHVtbk51bWJlcn07Ly8gU29tZSBpbnN0YW5jZXMgcmVzdWx0IGluIG5vIGZpbGU6XG4vLyAtIG5vbi1lcnJvciBleGNlcHRpb24gdGhyb3duIGZyb20gZ2xvYmFsIGNvZGUgaW4gRkZcbi8vIFRoaXMgYWRkcyBvbmUuXG5pZihmLmxpbmVOdW1iZXImJmYubGluZU51bWJlcj4tMSYmIWYuZmlsZSYmIWYubWV0aG9kKXtmLmZpbGU9R0xPQkFMX0NPREU7fXJldHVybiBmO307Y29uc3QgZW5zdXJlU3RyaW5nPXN0cj0+aXNTdHJpbmcoc3RyKT9zdHI6Jyc7ZnVuY3Rpb24gY3JlYXRlRXhjZXB0aW9uKGVycm9yQ2xhc3MsZXJyb3JNZXNzYWdlLG1zZ1ByZWZpeCxzdGFja3RyYWNlKXtyZXR1cm4ge2Vycm9yQ2xhc3M6ZW5zdXJlU3RyaW5nKGVycm9yQ2xhc3MpLG1lc3NhZ2U6YCR7bXNnUHJlZml4fSR7ZW5zdXJlU3RyaW5nKGVycm9yTWVzc2FnZSl9YCx0eXBlOidicm93c2VyanMnLHN0YWNrdHJhY2U6c3RhY2t0cmFjZS5yZWR1Y2UoKGFjY3VtLGZyYW1lKT0+e2NvbnN0IGY9Zm9ybWF0U3RhY2tmcmFtZShmcmFtZSk7Ly8gZG9uJ3QgaW5jbHVkZSBhIHN0YWNrZnJhbWUgaWYgbm9uZSBvZiBpdHMgcHJvcGVydGllcyBhcmUgZGVmaW5lZFxudHJ5e2lmKEpTT04uc3RyaW5naWZ5KGYpPT09J3t9JylyZXR1cm4gYWNjdW07cmV0dXJuIGFjY3VtLmNvbmNhdChmKTt9Y2F0Y2h7cmV0dXJuIGFjY3VtO319LFtdKX07fWNvbnN0IG5vcm1hbGl6ZUVycm9yPShtYXliZUVycm9yLGxvZ2dlcik9PntsZXQgZXJyb3I7aWYoaXNUeXBlT2ZFcnJvcihtYXliZUVycm9yKSYmaXNTdHJpbmcoZ2V0U3RhY2t0cmFjZShtYXliZUVycm9yKSkpe2Vycm9yPW1heWJlRXJyb3I7fWVsc2Uge2xvZ2dlci53YXJuKE5PTl9FUlJPUl9XQVJOSU5HKEVSUk9SX0hBTkRMRVIsc3RyaW5naWZ5V2l0aG91dENpcmN1bGFyKG1heWJlRXJyb3IpKSk7ZXJyb3I9dW5kZWZpbmVkO31yZXR1cm4gZXJyb3I7fTtjb25zdCBjcmVhdGVCdWdzbmFnRXhjZXB0aW9uPShlcnJvcixtc2dQcmVmaXgpPT57dHJ5e2NvbnN0IHN0YWNrdHJhY2U9cGFyc2VTdGFja1RyYWNlKGVycm9yKTtyZXR1cm4gY3JlYXRlRXhjZXB0aW9uKGVycm9yLm5hbWUsZXJyb3IubWVzc2FnZSxtc2dQcmVmaXgsc3RhY2t0cmFjZSk7fWNhdGNoe3JldHVybiBjcmVhdGVFeGNlcHRpb24oZXJyb3IubmFtZSxlcnJvci5tZXNzYWdlLG1zZ1ByZWZpeCxbXSk7fX07XG5cbi8qKlxuICogVXRpbGl0eSB0byBwYXJzZSBYSFIgSlNPTiByZXNwb25zZVxuICovY29uc3QgcmVzcG9uc2VUZXh0VG9Kc29uPShyZXNwb25zZVRleHQsb25FcnJvcik9Pnt0cnl7cmV0dXJuIEpTT04ucGFyc2UocmVzcG9uc2VUZXh0fHwnJyk7fWNhdGNoKGVycil7Y29uc3QgZXJyb3I9Z2V0TXV0YXRlZEVycm9yKGVyciwnRmFpbGVkIHRvIHBhcnNlIHJlc3BvbnNlIGRhdGEnKTtvbkVycm9yKGVycm9yKTt9cmV0dXJuIHVuZGVmaW5lZDt9O1xuXG5jb25zdCBGQUlMRURfUkVRVUVTVF9FUlJfTVNHX1BSRUZJWD0nVGhlIHJlcXVlc3QgZmFpbGVkJztjb25zdCBQTFVHSU5TX0xPQURfRkFJTFVSRV9NRVNTQUdFUz1bL0ZhaWxlZCB0byBmZXRjaCBkeW5hbWljYWxseSBpbXBvcnRlZCBtb2R1bGU6IC4qL107Y29uc3QgSU5URUdSQVRJT05TX0xPQURfRkFJTFVSRV9NRVNTQUdFUz1bL1VuYWJsZSB0byBsb2FkIFxcKC4qXFwpIHRoZSBzY3JpcHQgd2l0aCB0aGUgaWQgLiovLC9BIHRpbWVvdXQgb2YgXFxkKyBtcyBvY2N1cnJlZCB3aGlsZSB0cnlpbmcgdG8gbG9hZCB0aGUgc2NyaXB0IHdpdGggaWQgLiovXTtjb25zdCBFUlJPUl9NRVNTQUdFU19UT19CRV9GSUxURVJFRD1bbmV3IFJlZ0V4cChgJHtGQUlMRURfUkVRVUVTVF9FUlJfTVNHX1BSRUZJWH0uKmApLC9BIHNjcmlwdCB3aXRoIHRoZSBpZCAuKiBpcyBhbHJlYWR5IGxvYWRlZFxcLi9dO2NvbnN0IFNDUklQVF9MT0FEX0ZBSUxVUkVfTUVTU0FHRVM9Wy4uLlBMVUdJTlNfTE9BRF9GQUlMVVJFX01FU1NBR0VTLC4uLklOVEVHUkFUSU9OU19MT0FEX0ZBSUxVUkVfTUVTU0FHRVNdO2NvbnN0IElOVEVHUkFUSU9OU19FUlJPUl9DQVRFR09SWT0naW50ZWdyYXRpb25zJztjb25zdCBTREtfRVJST1JfQ0FURUdPUlk9J3Nkayc7Y29uc3QgREVGQVVMVF9FUlJPUl9DQVRFR09SWT1TREtfRVJST1JfQ0FURUdPUlk7XG5cbmNvbnN0IERFRkFVTFRfWEhSX1JFUVVFU1RfT1BUSU9OUz17aGVhZGVyczp7QWNjZXB0OidhcHBsaWNhdGlvbi9qc29uJywnQ29udGVudC1UeXBlJzonYXBwbGljYXRpb24vanNvbjtjaGFyc2V0PVVURi04J30sbWV0aG9kOidHRVQnfTsvKipcbiAqIFV0aWxpdHkgdG8gY3JlYXRlIHJlcXVlc3QgY29uZmlndXJhdGlvbiBiYXNlZCBvbiBkZWZhdWx0IG9wdGlvbnNcbiAqL2NvbnN0IGNyZWF0ZVhoclJlcXVlc3RPcHRpb25zPSh1cmwsb3B0aW9ucyxiYXNpY0F1dGhIZWFkZXIpPT57Y29uc3QgcmVxdWVzdE9wdGlvbnM9bWVyZ2VEZWVwUmlnaHQoREVGQVVMVF9YSFJfUkVRVUVTVF9PUFRJT05TLG9wdGlvbnN8fHt9KTtpZihiYXNpY0F1dGhIZWFkZXIpe3JlcXVlc3RPcHRpb25zLmhlYWRlcnM9bWVyZ2VEZWVwUmlnaHQocmVxdWVzdE9wdGlvbnMuaGVhZGVycyx7QXV0aG9yaXphdGlvbjpiYXNpY0F1dGhIZWFkZXJ9KTt9cmVxdWVzdE9wdGlvbnMudXJsPXVybDtyZXR1cm4gcmVxdWVzdE9wdGlvbnM7fTsvKipcbiAqIFV0aWxpdHkgaW1wbGVtZW50YXRpb24gb2YgWEhSLCBmZXRjaCBjYW5ub3QgYmUgdXNlZCBhcyBpdCByZXF1aXJlcyBleHBsaWNpdFxuICogb3JpZ2luIGFsbG93ZWQgdmFsdWVzIGFuZCBub3Qgd2lsZGNhcmQgZm9yIENPUlMgcmVxdWVzdHMgd2l0aCBjcmVk
1ZW50aWFscyBhbmRcbiAqIHRoaXMgaXMgbm90IHN1cHBvcnRlZCBieSBvdXIgc291cmNlQ29uZmlnIEFQSVxuICovY29uc3QgeGhyUmVxdWVzdD0ob3B0aW9ucyx0aW1lb3V0PURFRkFVTFRfWEhSX1RJTUVPVVRfTVMsbG9nZ2VyKT0+bmV3IFByb21pc2UoKHJlc29sdmUscmVqZWN0KT0+e2xldCBwYXlsb2FkO2lmKG9wdGlvbnMuc2VuZFJhd0RhdGE9PT10cnVlKXtwYXlsb2FkPW9wdGlvbnMuZGF0YTt9ZWxzZSB7cGF5bG9hZD1zdHJpbmdpZnlXaXRob3V0Q2lyY3VsYXIob3B0aW9ucy5kYXRhLGZhbHNlLFtdLGxvZ2dlcik7aWYoaXNOdWxsKHBheWxvYWQpKXtyZWplY3Qoe2Vycm9yOm5ldyBFcnJvcihYSFJfUEFZTE9BRF9QUkVQX0VSUk9SKSx1bmRlZmluZWQsb3B0aW9uc30pOy8vIHJldHVybiBhbmQgZG9uJ3QgcHJvY2VzcyBmdXJ0aGVyIGlmIHRoZSBwYXlsb2FkIGNvdWxkIG5vdCBiZSBzdHJpbmdpZmllZFxucmV0dXJuO319Y29uc3QgeGhyPW5ldyBYTUxIdHRwUmVxdWVzdCgpOy8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbmNvbnN0IHhoclJlamVjdD1lPT57cmVqZWN0KHtlcnJvcjpuZXcgRXJyb3IoWEhSX0RFTElWRVJZX0VSUk9SKEZBSUxFRF9SRVFVRVNUX0VSUl9NU0dfUFJFRklYLHhoci5zdGF0dXMseGhyLnN0YXR1c1RleHQsb3B0aW9ucy51cmwseGhyLnJlc3BvbnNlVGV4dCkpLHhocixvcHRpb25zfSk7fTtjb25zdCB4aHJFcnJvcj1lPT57cmVqZWN0KHtlcnJvcjpuZXcgRXJyb3IoWEhSX1JFUVVFU1RfRVJST1IoRkFJTEVEX1JFUVVFU1RfRVJSX01TR19QUkVGSVgsZSxvcHRpb25zLnVybCkpLHhocixvcHRpb25zLC4uLihlPy50eXBlPT09J3RpbWVvdXQnP3t0aW1lZE91dDp0cnVlfTp7fSl9KTt9O3hoci5vbnRpbWVvdXQ9eGhyRXJyb3I7eGhyLm9uZXJyb3I9eGhyRXJyb3I7eGhyLm9ubG9hZD0oKT0+e2lmKHhoci5zdGF0dXM+PTIwMCYmeGhyLnN0YXR1czw0MDApe3Jlc29sdmUoe3Jlc3BvbnNlOnhoci5yZXNwb25zZVRleHQseGhyLG9wdGlvbnN9KTt9ZWxzZSB7eGhyUmVqZWN0KCk7fX07eGhyLm9wZW4ob3B0aW9ucy5tZXRob2Qsb3B0aW9ucy51cmwsdHJ1ZSk7aWYob3B0aW9ucy53aXRoQ3JlZGVudGlhbHM9PT10cnVlKXt4aHIud2l0aENyZWRlbnRpYWxzPXRydWU7fS8vIFRoZSB0aW1lb3V0IHByb3BlcnR5IG1heSBiZSBzZXQgb25seSBpbiB0aGUgdGltZSBpbnRlcnZhbCBiZXR3ZWVuIGEgY2FsbCB0byB0aGUgb3BlbiBtZXRob2Rcbi8vIGFuZCB0aGUgZmlyc3QgY2FsbCB0byB0aGUgc2VuZCBtZXRob2QgaW4gbGVnYWN5IGJyb3dzZXJzXG54aHIudGltZW91dD10aW1lb3V0O09iamVjdC5rZXlzKG9wdGlvbnMuaGVhZGVycykuZm9yRWFjaChoZWFkZXJOYW1lPT57aWYob3B0aW9ucy5oZWFkZXJzW2hlYWRlck5hbWVdKXt4aHIuc2V0UmVxdWVzdEhlYWRlcihoZWFkZXJOYW1lLG9wdGlvbnMuaGVhZGVyc1toZWFkZXJOYW1lXSk7fX0pO3RyeXt4aHIuc2VuZChwYXlsb2FkKTt9Y2F0Y2goZXJyKXtyZWplY3Qoe2Vycm9yOmdldE11dGF0ZWRFcnJvcihlcnIsWEhSX1NFTkRfRVJST1IoRkFJTEVEX1JFUVVFU1RfRVJSX01TR19QUkVGSVgsb3B0aW9ucy51cmwpKSx4aHIsb3B0aW9uc30pO319KTtcblxuLyoqXG4gKiBTZXJ2aWNlIHRvIGhhbmRsZSBkYXRhIGNvbW11bmljYXRpb24gd2l0aCBBUElzXG4gKi9jbGFzcyBIdHRwQ2xpZW50e2NvbnN0cnVjdG9yKGxvZ2dlcil7dGhpcy5sb2dnZXI9bG9nZ2VyO3RoaXMub25FcnJvcj10aGlzLm9uRXJyb3IuYmluZCh0aGlzKTt9aW5pdChlcnJvckhhbmRsZXIpe3RoaXMuZXJyb3JIYW5kbGVyPWVycm9ySGFuZGxlcjt9LyoqXG4gICAqIEltcGxlbWVudCByZXF1ZXN0cyBpbiBhIGJsb2NraW5nIHdheVxuICAgKi9hc3luYyBnZXREYXRhKGNvbmZpZyl7Y29uc3R7dXJsLG9wdGlvbnMsdGltZW91dCxpc1Jhd1Jlc3BvbnNlfT1jb25maWc7dHJ5e2NvbnN0IGRhdGE9YXdhaXQgeGhyUmVxdWVzdChjcmVhdGVYaHJSZXF1ZXN0T3B0aW9ucyh1cmwsb3B0aW9ucyx0aGlzLmJhc2ljQXV0aEhlYWRlciksdGltZW91dCx0aGlzLmxvZ2dlcik7cmV0dXJuIHtkYXRhOmlzUmF3UmVzcG9uc2U/ZGF0YS5yZXNwb25zZTpyZXNwb25zZVRleHRUb0pzb24oZGF0YS5yZXNwb25zZSx0aGlzLm9uRXJyb3IpLGRldGFpbHM6ZGF0YX07fWNhdGNoKHJlYXNvbil7cmV0dXJuIHtkYXRhOnVuZGVmaW5lZCxkZXRhaWxzOnJlYXNvbn07fX0vKipcbiAgICogSW1wbGVtZW50IHJlcXVlc3RzIGluIGEgbm9uLWJsb2NraW5nIHdheVxuICAgKi9nZXRBc3luY0RhdGEoY29uZmlnKXtjb25zdHtjYWxsYmFjayx1cmwsb3B0aW9ucyx0aW1lb3V0LGlzUmF3UmVzcG9uc2V9PWNvbmZpZztjb25zdCBpc0ZpcmVBbmRGb3JnZXQ9IWlzRnVuY3Rpb24oY2FsbGJhY2spO3hoclJlcXVlc3QoY3JlYXRlWGhyUmVxdWVzdE9wdGlvbnModXJsLG9wdGlvbnMsdGhpcy5iYXNpY0F1dGhIZWFkZXIpLHRpbWVvdXQsdGhpcy5sb2dnZXIpLnRoZW4oZGF0YT0+e2lmKCFpc0ZpcmVBbmRGb3JnZXQpe2NhbGxiYWNrKGlzUmF3UmVzcG9uc2U/ZGF0YS5yZXNwb25zZTpyZXNwb25zZVRleHRUb0pzb24oZGF0YS5yZXNwb25zZSx0aGlzLm9uRXJyb3IpLGRhdGEpO319KS5jYXRjaChkYXRhPT57aWYoIWlzRmlyZUFuZEZvcmdldCl7Y2FsbGJhY2sodW5kZWZpbmVkLGRhdGEpO319KTt9LyoqXG4gICAqIEhhbmRsZSBlcnJvcnNcbiAgICovb25FcnJvcihlcnJvcixncm91cGluZ0hhc2gpe3RoaXMuZXJyb3JIYW5kbGVyPy5vbkVycm9yKHtlcnJvcixjb250ZXh0OkhUVFBfQ0xJRU5ULGdyb3VwaW5nSGFzaH0pO30vKipcbiAgICogU2V0IGJhc2ljIGF1dGhlbnRpY2F0aW9uIGhlYWRlciAoZWcgd3JpdGVrZXkpXG4gICAqL3NldEF1dGhIZWFkZXIodmFsdWUsbm9CdG9hPWZhbHNlKXtjb25zdCBhdXRoVmFsPW5vQnRvYT92YWx1ZTp0b0Jhc2U2NChgJHt2YWx1ZX06YCk7dGhpcy5iYXNpY0F1dGhIZWFkZXI9YEJhc2ljICR7YXV0aFZhbH1gO30vKipcbiAgICogQ2xlYXIgYmFzaWMgYXV0aGVudGljYXRpb24gaGVhZGVyXG4gICAqL3Jlc2V0QXV0aEhlYWRlcigpe3RoaXMuYmFzaWNBdXRoSGVhZGVyPXVuZGVmaW5lZDt9fWNvbnN0IGRlZmF1bHRIdHRwQ2xpZW50PW5ldyBIdHRwQ2xpZW50KGRlZmF1bHRMb2dnZXIpO1xuXG5jb25zdCBNRVRSSUNTX1BBWUxPQURfVkVSU0lPTj0nMSc7XG5cbi8vIEVycm9ycyBmcm9tIHRoZSBiZWxvdyBzY3JpcHRzIGFyZSBOT1QgYWxsb3dlZCB0byByZWFjaCBCdWdzbmFnXG5jb25zdCBTREtfRklMRV9OQU1FX1BSRUZJWEVTPSgpPT5bJ3JzYScvLyBQcmVmaXggZm9yIGFsbCB0aGUgU0RLIHNjcmlwdHMgaW5jbHVkaW5nIHBsdWdpbnMgYW5kIG1vZHVsZSBmZWRlcmF0ZWQgY2h1bmtzXG5dO2NvbnN0IERFVl9IT1NUUz1bJ3d3dy50ZXN0LWhvc3QuY29tJywnbG9jYWxob3N0JywnMTI3LjAuMC4xJywnWzo6MV0nXTsvLyBMaXN0IG9mIGtleXMgdG8gZXhjbHVkZSBmcm9tIHRoZSBtZXRhZGF0YVxuLy8gUG90ZW50aWFsIFBJSSBvciBzZW5zaXRpdmUgZGF0YVxuY29uc3QgQVBQX1NUQVRFX0VYQ0xVREVfS0VZUz1bJ3VzZXJJZCcsJ3VzZXJUcmFpdHMnLCdncm91cElkJywnZ3JvdXBUcmFpdHMnLCdhbm9ueW1vdXNJZCcsJ2NvbmZpZycsJ2ludGVncmF0aW9uJywvLyBpbnRlZ3JhdGlvbiBpbnN0YW5jZSBvYmplY3RzXG4nZXZlbnRCdWZmZXInLC8vIHByZS1sb2FkIGV2ZW50IGJ1ZmZlciAobWF5IGNvbnRhaW4gUElJKVxuJ3RyYWl0cycsJ2F1dGhUb2tlbiddO2NvbnN0IE5PVElGSUVSX05BTUU9J1J1ZGRlclN0YWNrIEphdmFTY3JpcHQgU0RLJztjb25zdCBTREtfR0lUSFVCX1VSTD0nZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9ydWRkZXJsYWJzL3J1ZGRlci1zZGstanMuZ2l0Jztjb25zdCBTT1VSQ0VfTkFNRT0nanMnO1xuXG5jb25zdCBkZXRlY3RBZEJsb2NrZXJzPWh0dHBDbGllbnQ9PntzdGF0ZS5jYXBhYmlsaXRpZXMuaXNBZEJsb2NrZXJEZXRlY3Rpb25JblByb2dyZXNzLnZhbHVlPXRydWU7dHJ5ey8vIEFwcGFyZW50bHksICc/dmlldz1hZCcgaXMgYSBxdWVyeSBwYXJhbSB0aGF0IGlzIGJsb2NrZWQgYnkgbWFqb3JpdHkgb2YgYWRibG9ja2Vyc1xuLy8gVXNlIHNvdXJjZSBjb25maWcgVVJMIGhlcmUgYXMgaXQgaXMgdmVyeSB1bmxpa2VseSB0byBiZSBibG9ja2VkIGJ5IGFkYmxvY2tlcnNcbi8vIE9ubHkgdGhlIGV4dHJhIHF1ZXJ5IHBhcmFtIHNob3VsZCBtYWtlIGl0IHZ1bG5lcmFibGUgdG8gYWRibG9ja2Vyc1xuLy8gVGhpcyB3aWxsIHdvcmsgZXZlbiBpZiB0aGUgdXNlcnMgcHJveGllcyBpdC5cbi8vIFRoZSBlZGdlIGNhc2Ugd2hlcmUgdGhpcyBkb2Vzbid0IHdvcmsgaXMgd2hlbiBIRUFEIG1ldGhvZCBpcyBub3QgYWxsb3dlZCBieSB0aGUgc2VydmVyICh1c2VyJ3MpXG5jb25zdCBiYXNlVXJsPW5ldyBVUkwoc3RhdGUubGlmZWN5Y2xlLnNvdXJjZUNvbmZpZ1VybC52YWx1ZSk7Y29uc3QgdXJsPWAke2Jhc2VVcmwub3JpZ2lufSR7YmFzZVVybC5wYXRobmFtZX0/dmlldz1hZGA7aHR0cENsaWVudC5nZXRBc3luY0RhdGEoe3VybCxvcHRpb25zOnsvLyBXZSBhY3R1YWxseSBkb24ndCBuZWVkIHRoZSByZXNwb25zZSBmcm9tIHRoZSByZXF1ZXN0LCBzbyB3ZSBhcmUgdXNpbmcgSEVBRFxubWV0aG9kOidIRUFEJyxoZWFkZXJzOnsnQ29udGVudC1UeXBlJzp1bmRlZmluZWR9fSxpc1Jhd1Jlc3BvbnNlOnRydWUsY2FsbGJhY2s6KHJlc3VsdCxkZXRhaWxzKT0+e3N0YXRlLmNhcGFiaWxpdGllcy5pc0FkQmxvY2tlckRldGVjdGlvbkluUHJvZ3Jlc3MudmFsdWU9ZmFsc2U7Ly8gbm90IGFkIGJsb2NrZWQgaWYgdGhlIHJlcXVlc3QgaXMgc3VjY2Vzc2Z1bCBvciBpdCBpcyBub3QgaW50ZXJuYWxseSByZWRpcmVjdGVkIG9uIHRoZSBjbGllbnQgc2lkZVxuLy8gT2Z0ZW4gYWRibG9ja2VycyBpbnN0ZWFkIG9mIGJsb2NraW5nIHRoZSByZXF1ZXN0LCB0aGV5IHJlZGlyZWN0IGl0IHRvIGFuIGludGVybmFsIFVSTFxuc3RhdGUuY2FwYWJpbGl0aWVzLmlzQWRCbG9ja2VkLn
1ZhbHVlPWRldGFpbHM/LmVycm9yIT09dW5kZWZpbmVkfHxkZXRhaWxzPy54aHI/LnJlc3BvbnNlVVJMIT09dXJsO319KTt9Y2F0Y2goZXJyKXsvLyBSZXNldCB0aGUgZmxhZyB0byBwcmV2ZW50IGJsb2NraW5nIGZ1dHVyZSBkZXRlY3Rpb24gYXR0ZW1wdHNcbnN0YXRlLmNhcGFiaWxpdGllcy5pc0FkQmxvY2tlckRldGVjdGlvbkluUHJvZ3Jlc3MudmFsdWU9ZmFsc2U7Ly8gUmUtdGhyb3cgdGhlIGVycm9yIHRvIGJlIGhhbmRsZWQgYnkgdGhlIGNhbGxlclxudGhyb3cgZXJyO319O1xuXG5jb25zdCBnZXRFcnJJbnN0YW5jZT0oZXJyLGVycm9yVHlwZSk9Pntzd2l0Y2goZXJyb3JUeXBlKXtjYXNlIEVycm9yVHlwZS5VTkhBTkRMRURFWENFUFRJT046e2NvbnN0e2Vycm9yfT1lcnI7cmV0dXJuIGVycm9yfHxlcnI7fWNhc2UgRXJyb3JUeXBlLlVOSEFORExFRFJFSkVDVElPTjp7cmV0dXJuIGVyci5yZWFzb247fWNhc2UgRXJyb3JUeXBlLkhBTkRMRURFWENFUFRJT046ZGVmYXVsdDpyZXR1cm4gZXJyO319O2NvbnN0IGNyZWF0ZU5ld0JyZWFkY3J1bWI9bWVzc2FnZT0+KHt0eXBlOidtYW51YWwnLG5hbWU6bWVzc2FnZSx0aW1lc3RhbXA6bmV3IERhdGUoKSxtZXRhRGF0YTp7fX0pOy8qKlxuICogQSBmdW5jdGlvbiB0byBnZXQgdGhlIEJ1Z3NuYWcgcmVsZWFzZSBzdGFnZSBmb3IgdGhlIGN1cnJlbnQgZW52aXJvbm1lbnRcbiAqIEBwYXJhbSBnZXRIb3N0TmFtZSBPcHRpb25hbCBmdW5jdGlvbiB0byBnZXQgdGhlIGhvc3RuYW1lIChwcmltYXJpbHkgZm9yIHRlc3RpbmcpXG4gKiBAcmV0dXJucyAnZGV2ZWxvcG1lbnQnIGlmIHRoZSBob3N0IGlzIGVtcHR5IChmb3IgZmlsZTovLyBwcm90b2NvbCBldGMuKSBvciBhIGRldiBob3N0IChsb2NhbGhvc3QsIDEyNy4wLjAuMSwgZXRjLiksIG90aGVyd2lzZSAnJ3Byb2R1Y3Rpb24nJyAoaXQnbGwgYmUgcmVwbGFjZWQgd2l0aCB0aGUgYWN0dWFsIHJlbGVhc2Ugc3RhZ2UgZHVyaW5nIHRoZSBidWlsZClcbiAqL2NvbnN0IGdldFJlbGVhc2VTdGFnZT0oZ2V0SG9zdE5hbWU9KCk9PndpbmRvdy5sb2NhdGlvbi5ob3N0bmFtZSk9Pntjb25zdCBob3N0PWdldEhvc3ROYW1lKCk7cmV0dXJuICFob3N0fHxob3N0JiZERVZfSE9TVFMuaW5jbHVkZXMoaG9zdCk/J2RldmVsb3BtZW50JzoncHJvZHVjdGlvbic
17fTtjb25zdCBnZXRBcHBTdGF0ZUZvck1ldGFkYXRhPXN0YXRlPT57Y29uc3Qgc3RhdGVTdHI9c3RyaW5naWZ5V2l0aG91dENpcmN1bGFyKHN0YXRlLGZhbHNlLEFQUF9TVEFURV9FWENMVURFX0tFWVMpO3JldHVybiBzdGF0ZVN0ciE9PW51bGw/SlNPTi5wYXJzZShzdGF0ZVN0cik6e307fTtjb25zdCBnZXRVUkxXaXRob3V0UXVlcnlTdHJpbmc9KCk9Pntjb25zdCB1cmw9Z2xvYmFsVGhpcy5sb2NhdGlvbi5ocmVmLnNwbGl0KCc/Jyk7cmV0dXJuIHVybFswXTt9O2NvbnN0IGdldFVzZXJEZXRhaWxzPShzb3VyY2Usc2Vzc2lvbixsaWZlY3ljbGUsYXV0b1RyYWNrKT0+KHtpZDpgJHtzb3VyY2UudmFsdWU/LmlkPz9saWZlY3ljbGUud3JpdGVLZXkudmFsdWV9Li4ke3Nlc3Npb24uc2Vzc2lvbkluZm8udmFsdWUuaWQ/PydOQSd9Li4ke2F1dG9UcmFjay5wYWdlTGlmZWN5Y2xlLnBhZ2VWaWV3SWQudmFsdWU/PydOQSd9YCxuYW1lOnNvdXJjZS52YWx1ZT8ubmFtZT8/J05BJ30pO2NvbnN0IGdldERldmljZURldGFpbHM9KGxvY2FsZSx1c2VyQWdlbnQpPT4oe2xvY2FsZTpsb2NhbGUudmFsdWU/PydOQScsdXNlckFnZW50OnVzZXJBZ2VudC52YWx1ZT8/J05BJyx0aW1lOm5ldyBEYXRlKCl9KTtjb25zdCBnZXRCdWdzbmFnRXJyb3JFdmVudD0oZXhjZXB0aW9uLGVycm9yU3RhdGUsc3RhdGUsZ3JvdXBpbmdIYXNoKT0+e2NvbnN0e2NvbnRleHQsbGlmZWN5Y2xlLHNlc3Npb24sc291cmNlLHJlcG9ydGluZyxhdXRvVHJhY2t9PXN0YXRlO2NvbnN0e2FwcCxsb2NhbGUsdXNlckFnZW50LHRpbWV6b25lLHNjcmVlbixsaWJyYXJ5fT1jb250ZXh0O3JldHVybiB7cGF5bG9hZFZlcnNpb246JzUnLG5vdGlmaWVyOntuYW1lOk5PVElGSUVSX05BTUUsdmVyc2lvbjphcHAudmFsdWUudmVyc2lvbix1cmw6U0RLX0dJVEhVQl9VUkx9LGV2ZW50czpbe2V4Y2VwdGlvbnM6W2Nsb25lKGV4Y2VwdGlvbildLHNldmVyaXR5OmVycm9yU3RhdGUuc2V2ZXJpdHksdW5oYW5kbGVkOmVycm9yU3RhdGUudW5oYW5kbGVkLHNldmVyaXR5UmVhc29uOmVycm9yU3RhdGUuc2V2ZXJpdHlSZWFzb24sYXBwOnt2ZXJzaW9uOmFwcC52YWx1ZS52ZXJzaW9uLHJlbGVhc2VTdGFnZTpnZXRSZWxlYXNlU3RhZ2UoKSx0eXBlOmFwcC52YWx1ZS5pbnN0YWxsVHlwZX0sZGV2aWNlOmdldERldmljZURldGFpbHMobG9jYWxlLHVzZXJBZ2VudCkscmVxdWVzdDp7dXJsOmdldFVSTFdpdGhvdXRRdWVyeVN0cmluZygpLGNsaWVudElwOidbTk9UIENPTExFQ1RFRF0nfSxicmVhZGNydW1iczpjbG9uZShyZXBvcnRpbmcuYnJlYWRjcnVtYnMudmFsdWUpLGNvbnRleHQ6ZXhjZXB0aW9uLm1lc3NhZ2UsZ3JvdXBpbmdIYXNoLG1ldGFEYXRhOnthcHA6e3NuaXBwZXRWZXJzaW9uOmxpYnJhcnkudmFsdWUuc25pcHBldFZlcnNpb259LGRldmljZTp7Li4uc2NyZWVuLnZhbHVlLHRpbWV6b25lOnRpbWV6b25lLnZhbHVlfSwvLyBBZGQgcmVzdCBvZiB0aGUgc3RhdGUgZ3JvdXBzIGFzIG1ldGFkYXRhXG4vLyBzbyB0aGF0IHRoZXkgc2hvdyB1cCBhcyBzZXBhcmF0ZSB0YWJzIGluIHRoZSBkYXNoYm9hcmRcbi4uLmdldEFwcFN0YXRlRm9yTWV0YWRhdGEoc3RhdGUpfSx1c2VyOmdldFVzZXJEZXRhaWxzKHNvdXJjZSxzZXNzaW9uLGxpZmVjeWNsZSxhdXRvVHJhY2spfV19O307LyoqXG4gKiBBIGZ1bmN0aW9uIHRvIGNoZWNrIGlmIGFkYmxvY2tlcnMgYXJlIGFjdGl2ZS4gVGhlIHByb21pc2UncyByZXNvbHZlIGZ1bmN0aW9uXG4gKiBpcyBpbnZva2VkIHdpdGggdHJ1ZSBpZiBhZGJsb2NrZXJzIGFyZSBub3QgZGV0ZWN0ZWQgYW5kIGZhbHNlIG90aGVyd2lzZS5cbiAqIEBwYXJhbSB7QXBwbGljYXRpb25TdGF0ZX0gc3RhdGUgVGhlIGFwcGxpY2F0aW9uIHN0YXRlXG4gKiBAcGFyYW0ge0lIdHRwQ2xpZW50fSBodHRwQ2xpZW50IFRoZSBIVFRQIGNsaWVudCBpbnN0YW5jZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gcmVzb2x2ZSBUaGUgcHJvbWlzZSdzIHJlc29sdmUgZnVuY3Rpb25cbiAqL2NvbnN0IGNoZWNrSWZBZEJsb2NrZXJzQXJlQWN0aXZlPShzdGF0ZSxodHRwQ2xpZW50LHJlc29sdmUpPT57Ly8gSW5pdGlhdGUgYWQgYmxvY2tlciBkZXRlY3Rpb24gaWYgbm90IGRvbmUgcHJldmlvdXNseSBhbmQgbm90IGFscmVhZHkgaW4gcHJvZ3Jlc3MuXG5pZihpc1VuZGVmaW5lZChzdGF0ZS5jYXBhYmlsaXRpZXMuaXNBZEJsb2NrZWQudmFsdWUpKXtpZihzdGF0ZS5jYXBhYmlsaXRpZXMuaXNBZEJsb2NrZXJEZXRlY3Rpb25JblByb2dyZXNzLnZhbHVlPT09ZmFsc2Upe2RldGVjdEFkQmxvY2tlcnMoaHR0cENsaWVudCk7fS8vIFdhaXQgZm9yIHRoZSBkZXRlY3Rpb24gdG8gY29tcGxldGUuXG5jb25zdCBkZXRlY3Rpb25EaXNwb3Nlcj1qKCgpPT57aWYoaXNEZWZpbmVkKHN0YXRlLmNhcGFiaWxpdGllcy5pc0FkQmxvY2tlZC52YWx1ZSkpey8vIElmIGFkIGJsb2NrZXIgaXMgbm90IGRldGVjdGVkLCBub3RpZnkuXG5yZXNvbHZlKHN0YXRlLmNhcGFiaWxpdGllcy5pc0FkQmxvY2tlZC52YWx1ZT09PWZhbHNlKTsvLyBDbGVhbnVwIHRoZSBlZmZlY3QuXG5kZXRlY3Rpb25EaXNwb3NlcigpO319KTt9ZWxzZSB7Ly8gSWYgYWQgYmxvY2tlciBpcyBub3QgZGV0ZWN0ZWQsIG5vdGlmeS5cbnJlc29sdmUoc3RhdGUuY2FwYWJpbGl0aWVzLmlzQWRCbG9ja2VkLnZhbHVlPT09ZmFsc2UpO319Oy8qKlxuICogQSBmdW5jdGlvbiB0byBkZXRlcm1pbmUgd2hldGhlciB0aGUgZXJyb3Igc2hvdWxkIGJlIHByb21vdGVkIHRvIG5vdGlmeSBvciBub3QuXG4gKiBGb3IgcGx1Z2luIGFuZCBpbnRlZ3JhdGlvbiBlcnJvcnMgZnJvbSBSUyBDRE4sIGlmIGl0IGlzIGR1ZSB0byBDU1AgYmxvY2tlZCBVUkxzIG9yIEFkQmxvY2tlcnMsXG4gKiBpdCB3aWxsIG5vdCBiZSBwcm9tb3RlZCB0byBub3RpZnkuXG4gKiBJZiBpdCBpcyBkdWUgdG8gb3RoZXIgcmVhc29ucywgaXQgd2lsbCBiZSBwcm9tb3RlZCB0byBub3RpZnkuXG4gKiBAcGFyYW0ge0Vycm9yfSBleGNlcHRpb24gVGhlIGVycm9yIG9iamVjdFxuICogQHBhcmFtIHtBcHBsaWNhdGlvblN0YXRlfSBzdGF0ZSBUaGUgYXBwbGljYXRpb24gc3RhdGVcbiAqIEBwYXJhbSB7SUh0dHBDbGllbnR9IGh0dHBDbGllbnQgVGhlIEhUVFAgY2xpZW50IGluc3RhbmNlXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIHR
1oZSBlcnJvciBzaG91bGQgYmUgcHJvbW90ZWQgdG8gbm90aWZ5IG9yIG5vdFxuICovY29uc3QgY2hlY2tJZkFsbG93ZWRUb0JlTm90aWZpZWQ9KGV4Y2VwdGlvbixzdGF0ZSxodHRwQ2xpZW50KT0+e2NvbnN0IGVyck1zZz1leGNlcHRpb24ubWVzc2FnZTtyZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZT0+ey8vIEZpbHRlciBvdXQgc2NyaXB0IGxvYWQgZmFpbHVyZXMgdGhhdCBhcmUgbm90IGZyb20gdGhlIFJTIENETi5cbmlmKFNDUklQVF9MT0FEX0ZBSUxVUkVfTUVTU0FHRVMuc29tZShyZWdleD0+cmVnZXgudGVzdChlcnJNc2cpKSl7Y29uc3QgZXh0cmFjdGVkVVJMPS9odHRwcz86XFwvXFwvW15cXHNcIicoKSw7PD5bXFxde31dKy8uZXhlYyhlcnJNc2cpPy5bMF07aWYoaXNTdHJpbmcoZXh0cmFjdGVkVVJMKSl7aWYoZXh0cmFjdGVkVVJMLnN0YXJ0c1dpdGgoU0RLX0NETl9CQVNFX1VSTCkpey8vIEZpbHRlciBvdXQgZXJyb3JzIHRoYXQgYXJlIGZyb20gQ1NQIGJsb2NrZWQgVVJMcy5cbmlmKHN0YXRlLmNhcGFiaWxpdGllcy5jc3BCbG9ja2VkVVJMcy52YWx1ZS5pbmNsdWRlcyhleHRyYWN0ZWRVUkwpKXtyZXNvbHZlKGZhbHNlKTt9ZWxzZSB7Ly8gRmlsdGVyIG91dCBlcnJvcnMgaWYgYWRibG9ja2VycyBhcmUgZGV0ZWN0ZWQuXG5jaGVja0lmQWRCbG9ja2Vyc0FyZUFjdGl2ZShzdGF0ZSxodHRwQ2xpZW50LHJlc29sdmUpO319ZWxzZSB7Ly8gRmlsdGVyIG91dCBlcnJvcnMgdGhhdCBhcmUgbm90IGZyb20gdGhlIFJTIENETi5cbnJlc29sdmUoZmFsc2UpO319ZWxzZSB7Ly8gQWxsb3cgdGhlIGVycm9yIHRvIGJlIG5vdGlmaWVkIGlmIG5vIFVSTCBjb3VsZCBiZSBleHRyYWN0ZWQgZnJvbSB0aGUgZXJyb3IgbWVzc2FnZVxucmVzb2x2ZSh0cnVlKTt9fWVsc2Uge3Jlc29sdmUoIUVSUk9SX01FU1NBR0VTX1RPX0JFX0ZJTFRFUkVELnNvbWUoZT0+ZS50ZXN0KGVyck1zZykpKTt9fSk7fTsvKipcbiAqIEEgZnVuY3Rpb24gdG8gZ2V0IHRoZSBkaXJlY3RvcnkgbmFtZSBmcm9tIGEgZmlsZSBwYXRoLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVQYXRoIFRoZSBmaWxlIHBhdGhcbiAqIEByZXR1cm5zIFRoZSBkaXJlY3RvcnkgbmFtZSBvciB1bmRlZmluZWQgaWYgdGhlIGZpbGUgcGF0aCBpcyBpbnZhbGlkXG4gKi9jb25zdCBnZXREaXJlY3RvcnlOYW1lPWZpbGVQYXRoPT57aWYoIWZpbGVQYXRoKXtyZXR1cm4gdW5kZWZpbmVkO31jb25zdCBwYXRocz1maWxlUGF0aC5zcGxpdCgnLycpO3JldHVybiBwYXRocy5hdCgtMik7fTsvKipcbiAqIEEgZnVuY3Rpb24gdG8gZ2V0IHRoZSB0b3Agc3RhY2sgcGF0aCBmcm9tIHRoZSBleGNlcHRpb24uXG4gKiBAcGFyYW0ge0V4Y2VwdGlvbn0gZXhjZXB0aW9uIFRoZSBleGNlcHRpb24gb2JqZWN0XG4gKiBAcmV0dXJucyBUaGUgdG9wIHN0YWNrIHBhdGggb3IgdW5kZWZpbmVkIGlmIHRoZSBleGNlcHRpb24gaXMgaW52YWxpZFxuICovY29uc3QgZ2V0VG9wU3RhY2tQYXRoPWV4Y2VwdGlvbj0+e2NvbnN0IGVycm9yT3JpZ2luPWV4Y2VwdGlvbi5zdGFja3RyYWNlWzBdPy5maWxlO2lmKCFlcnJvck9yaWdpbnx8dHlwZW9mIGVycm9yT3JpZ2luIT09J3N0cmluZycpe3JldHVybiB1bmRlZmluZWQ7fXJldHVybiBlcnJvck9yaWdpbjt9Oy8qKlxuICogQSBmdW5jdGlvbiB0byBkZXRlcm1pbmUgaWYgdGhlIGVycm9yIGlzIGZyb20gUnVkZGVyIFNES1xuICogQHBhcmFtIHtFcnJvcn0gZXhjZXB0aW9uXG4gKiBAcmV0dXJuc1xuICovY29uc3QgaXNTREtFcnJvcj1leGNlcHRpb249Pntjb25zdCBlcnJvck9yaWdpbj1nZXRUb3BTdGFja1BhdGgoZXhjZXB0aW9uKTtpZighZXJyb3JPcmlnaW4pe3JldHVybiBmYWxzZTt9Y29uc3Qgc3JjRmlsZU5hbWU9ZXJyb3JPcmlnaW4uc3Vic3RyaW5nKGVycm9yT3JpZ2luLmxhc3RJbmRleE9mKCcvJykrMSk7Y29uc3QgcGFyZW50Rm9sZGVyTmFtZT1nZXREaXJlY3RvcnlOYW1lKGVycm9yT3JpZ2luKTtyZXR1cm4gcGFyZW50Rm9sZGVyTmFtZT09PUNETl9JTlRfRElSfHxTREtfRklMRV9OQU1FX1BSRUZJWEVTKCkuc29tZShwcmVmaXg9PnNyY0ZpbGVOYW1lLnN0YXJ0c1dpdGgocHJlZml4KSYmc3JjRmlsZU5hbWUuZW5kc1dpdGgoJy5qcycpKTt9O2NvbnN0IGdldEVycm9yQ2F0ZWdvcnk9KGV4Y2VwdGlvbixjYXRlZ29yeSk9PntpZihjYXRlZ29yeSl7cmV0dXJuIGNhdGVnb3J5O31jb25zdCBlcnJvck9yaWdpbj1nZXRUb3BTdGFja1BhdGgoZXhjZXB0aW9uKTtjb25zdCBkaXJlY3RvcnlOYW1lPWdldERpcmVjdG9yeU5hbWUoZXJyb3JPcmlnaW4pO2lmKGRpcmVjdG9yeU5hbWU9PT1DRE5fSU5UX0RJUil7cmV0dXJuIElOVEVHUkFUSU9OU19FUlJPUl9DQVRFR09SWTt9cmV0dXJuIERFRkFVTFRfRVJST1JfQ0FURUdPUlk7fTtjb25zdCBnZXRFcnJvckRlbGl2ZXJ5UGF5bG9hZD0ocGF5bG9hZCxzdGF0ZSxjYXRlZ29yeSk9Pntjb25zdCBkYXRhPXt2ZXJzaW9uOk1FVFJJQ1NfUEFZTE9BRF9WRVJTSU9OLG1lc3NhZ2VfaWQ6Z2VuZXJhdGVVVUlEKCksc291cmNlOntuYW1lOlNPVVJDRV9OQU1FLHNka192ZXJzaW9uOnN0YXRlLmNvbnRleHQuYXBwLnZhbHVlLnZlcnNpb24sd3JpdGVfa2V5OnN0YXRlLmxpZmVjeWNsZS53cml0ZUtleS52YWx1ZSxpbnN0YWxsX3R5cGU6c3RhdGUuY29udGV4dC5hcHAudmFsdWUuaW5zdGFsbFR5cGUsY2F0ZWdvcnl9LGVycm9yczpwYXlsb2FkfTtyZXR1cm4gc3RyaW5naWZ5V2l0aG91dENpcmN1bGFyKGRhdGEpO307LyoqXG4gKiBBIGZ1bmN0aW9uIHRvIGdldCB0aGUgZ3JvdXBpbmcgaGFzaCB2YWx1ZSB0byBiZSB1c2VkIGZvciB0aGUgZXJyb3IgZXZlbnQuXG4gKiBJZiB0aGUgZ3JvdXBpbmcgaGFzaCBpcyBhbiBlcnJvciBpbnN0YW5jZSwgdGhlIG5vcm1hbGl6ZWQgZXJyb3IgbWVzc2FnZSBpcyB1c2VkIGFzIHRoZSBncm91cGluZyBoYXNoLlxuICogSWYgdGhlIGdyb3VwaW5nIGhhc2ggaXMgYW4gZW1wdHkgc3RyaW5nIG9yIG5vdCBzcGVjaWZpZWQsIHRoZSBkZWZhdWx0IGdyb3VwaW5nIGhhc2ggaXMgdXNlZC5cbiAqIElmIHRoZSBncm91cGluZyBoYXNoIGlzIGEgc3RyaW5nLCBpdCBpcyB1c2VkIGFzIGlzLlxuICogQHBhcmFtIGN1ckVyckdyb3VwaW5nSGFzaCBUaGUgZ3JvdXBpbmcgaGFzaCB2YWx1ZSBwYXJ0IG9mIHRoZSBlcnJvciBldmVudFxuICogQHBhcmFtIGRlZmF1bHRHcm91cGluZ0hhc2ggVGhlIGRlZmF1bHQgZ3JvdXBpbmcgaGFzaCB2YWx1ZS4gSXQgaXMgdGhlIGVycm9yIG1lc3NhZ2UuXG4gKiBAcGFyYW0gbG9nZ2VyIFRoZSBsb2dnZXIgaW5zdGFuY2VcbiAqIEByZXR1cm5zIFRoZSBmaW5hbCBncm91cGluZyBoYXNoIHZhbHVlIHRvIGJlIHVzZWQgZm9yIHRoZSBlcnJvciBldmVudFxuICovY29uc3QgZ2V0RXJyb3JHcm91cGluZ0hhc2g9KGN1ckVyckdyb3VwaW5nSGFzaCxkZWZhdWx0R3JvdXBpbmdIYXNoLGxvZ2dlcik9PntsZXQgbm9ybWFsaXplZEdyb3VwaW5nSGFzaDtpZighaXNEZWZpbmVkKGN1ckVyckdyb3VwaW5nSGFzaCkpe25vcm1hbGl6ZWRHcm91cGluZ0hhc2g9ZGVmYXVsdEdyb3VwaW5nSGFzaDt9ZWxzZSBpZihpc1N0cmluZyhjdXJFcnJHcm91cGluZ0hhc2gpKXtub3JtYWxpem
1VkR3JvdXBpbmdIYXNoPWN1ckVyckdyb3VwaW5nSGFzaDt9ZWxzZSB7Y29uc3Qgbm9ybWFsaXplZEVycm9ySW5zdGFuY2U9bm9ybWFsaXplRXJyb3IoY3VyRXJyR3JvdXBpbmdIYXNoLGxvZ2dlcik7aWYoaXNEZWZpbmVkKG5vcm1hbGl6ZWRFcnJvckluc3RhbmNlKSl7bm9ybWFsaXplZEdyb3VwaW5nSGFzaD1ub3JtYWxpemVkRXJyb3JJbnN0YW5jZS5tZXNzYWdlO31lbHNlIHtub3JtYWxpemVkR3JvdXBpbmdIYXNoPWRlZmF1bHRHcm91cGluZ0hhc2g7fX1yZXR1cm4gbm9ybWFsaXplZEdyb3VwaW5nSGFzaDt9O1xuXG4vKipcbiAqIEEgc2VydmljZSB0byBoYW5kbGUgZXJyb3JzXG4gKi9jbGFzcyBFcnJvckhhbmRsZXJ7aW5pdGlhbGl6ZWQ9ZmFsc2U7Ly8gSWYgbm8gbG9nZ2VyIGlzIHBhc3NlZCBlcnJvcnMgd2lsbCBiZSB0aHJvd24gYXMgdW5oYW5kbGVkIGVycm9yXG5jb25zdHJ1Y3RvcihodHRwQ2xpZW50LGxvZ2dlcil7dGhpcy5odHRwQ2xpZW50PWh0dHBDbGllbnQ7dGhpcy5sb2dnZXI9bG9nZ2VyO30vKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIGVycm9yIGhhbmRsZXIgYnkgYXR0YWNoaW5nIGdsb2JhbCBlcnJvciBsaXN0ZW5lcnMuXG4gICAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgb25jZSBhZnRlciBjb25zdHJ1Y3Rpb24uXG4gICAqL2luaXQoKXtpZih0aGlzLmluaXRpYWxpemVkKXtyZXR1cm47fXRoaXMuYXR0YWNoRXJyb3JMaXN0ZW5lcnMoKTt0aGlzLmluaXRpYWxpemVkPXRydWU7fS8qKlxuICAgKiBBdHRhY2ggZXJyb3IgbGlzdGVuZXJzIHRvIHRoZSBnbG9iYWwgd2luZG93IG9iamVjdFxuICAgKi9hdHRhY2hFcnJvckxpc3RlbmVycygpe2dsb2JhbFRoaXMuYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLGV2ZW50PT57dGhpcy5vbkVycm9yKHtlcnJvcjpldmVudCxjb250ZXh0OkVSUk9SX0hBTkRMRVIsZXJyb3JUeXBlOkVycm9yVHlwZS5VTkhBTkRMRURFWENFUFRJT059KTt9KTtnbG9iYWxUaGlzLmFkZEV2ZW50TGlzdGVuZXIoJ3VuaGFuZGxlZHJlamVjdGlvbicsZXZlbnQ9Pnt0aGlzLm9uRXJyb3Ioe2Vycm9yOmV2ZW50LGNvbnRleHQ6RVJST1JfSEFORExFUixlcnJvclR5cGU6RXJyb3JUeXBlLlVOSEFORExFRFJFSkVDVElPTn0pO30pOy8vIExpc3RlbiB0byBDU1AgdmlvbGF0aW9ucyBhbmQgYWRkIHRoZSBibG9ja2VkIFVSTCB0byB0aGUgc3RhdGVcbi8vIGlmIHRob3NlIFVSTHMgYXJlIGZyb20gUlMgQ0ROLlxuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignc2VjdXJpdHlwb2xpY3l2aW9sYXRpb24nLGV2ZW50PT57Y29uc3QgYmxvY2tlZFVSTD1pc1N0cmluZyhldmVudC5ibG9ja2VkVVJJKT9ldmVudC5ibG9ja2VkVVJJOicnO2lmKGV2ZW50LmRpc3Bvc2l0aW9uPT09J2VuZm9yY2UnJiZibG9ja2VkVVJMLnN0YXJ0c1dpdGgoU0RLX0NETl9CQVNFX1VSTCkmJiFzdGF0ZS5jYXBhYmlsaXRpZXMuY3NwQmxvY2tlZFVSTHMudmFsdWUuaW5jbHVkZXMoYmxvY2tlZFVSTCkpe3N0YXRlLmNhcGFiaWxpdGllcy5jc3BCbG9ja2VkVVJMcy52YWx1ZT1bLi4uc3RhdGUuY2FwYWJpbGl0aWVzLmNzcEJsb2NrZWRVUkxzLnZhbHVlLGJsb2NrZWRVUkxdO319KTt9LyoqXG4gICAqIEhhbmRsZSBlcnJvcnNcbiAgICogQHBhcmFtIGVycm9ySW5mbyAtIFRoZSBlcnJvciBpbmZvcm1hdGlvblxuICAgKiBAcGFyYW0gZXJyb3JJbmZvLmVycm9yIC0gVGhlIGVycm9yIHRvIGhhbmRsZVxuICAgKiBAcGFyYW0gZXJyb3JJbmZvLmNvbnRleHQgLSBUaGUgY29udGV4dCBvZiB3aGVyZSB0aGUgZXJyb3Igb2NjdXJyZWRcbiAgICogQHBhcmFtIGVycm9ySW5mby5jdXN0b21NZXNzYWdlIC0gVGhlIGN1c3RvbSBtZXNzYWdlIG9mIHRoZSBlcnJvclxuICAgKiBAcGFyYW0gZXJyb3JJbmZvLmVycm9yVHlwZSAtIFRoZSB0eXBlIG9mIHRoZSBlcnJvciAoaGFuZGxlZCBvciB1bmhhbmRsZWQpXG4gICAqIEBwYXJhbSBlcnJvckluZm8uZ3JvdXBpbmdIYXNoIC0gVGhlIGdyb3VwaW5nIGhhc2ggb2YgdGhlIGVycm9yXG4gICAqIEBwYXJhbSBlcnJvckluZm8uY2F0ZWdvcnkgLSBUaGUgY2F0ZWdvcnkgb2YgdGhlIGVycm9yIChzZGsgb3IgaW50ZWdyYXRpb25zKVxuICAgKi9hc3luYyBvbkVycm9yKGVycm9ySW5mbyl7dHJ5e2NvbnN0e2Vycm9yLGNvbnRleHQsY3VzdG9tTWVzc2FnZSxncm91cGluZ0hhc2gsY2F0ZWdvcnl9PWVycm9ySW5mbztjb25zdCBlcnJvclR5cGU9ZXJyb3JJbmZvLmVycm9yVHlwZT8/RXJyb3JUeXBlLkhBTkRMRURFWENFUFRJT047Y29uc3QgZXJySW5zdGFuY2U9Z2V0RXJySW5zdGFuY2UoZXJyb3IsZXJyb3JUeXBlKTtjb25zdCBub3JtYWxpemVkRXJyb3I9bm9ybWFsaXplRXJyb3IoZXJySW5zdGFuY2UsdGhpcy5sb2dnZXIpO2lmKGlzVW5kZWZpbmVkKG5vcm1hbGl6ZWRFcnJvcikpe3JldHVybjt9Y29uc3QgY3VzdG9tTXNnVmFsPWN1c3RvbU1lc3NhZ2U/YCR7Y3VzdG9tTWVzc2FnZX0gLSBgOicnO2NvbnN0IGVycm9yTXNnUHJlZml4PWAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9JHtjdXN0b21Nc2dWYWx9YDtjb25zdCBic0V4Y2VwdGlvbj1jcmVhdGVCdWdzbmFnRXhjZXB0aW9uKG5vcm1hbGl6ZWRFcnJvcixlcnJvck1zZ1ByZWZpeCk7Y29uc3Qgc3RhY2t0cmFjZT1nZXRTdGFja3RyYWNlKG5vcm1hbGl6ZWRFcnJvcik7Y29uc3QgaXNTZGtEaXNwYXRjaGVkPXN0YWNrdHJhY2UuaW5jbHVkZXMoTUFOVUFMX0VSUk9SX0lERU5USUZJRVIpOy8vIEZpbHRlciBlcnJvcnMgdGhhdCBhcmUgbm90IG9yaWdpbmF0ZWQgaW4gdGhlIFNESy5cbi8vIEluIGNhc2Ugb2YgTlBNIGluc3RhbGxhdGlvbnMsIHRoZSB1bmhhbmRsZWQgZXJyb3JzIGZyb20gdGhlIFNESyBjYW5ub3QgYmUgaWRlbnRpZmllZFxuLy8gYW5kIHdpbGwgTk9UIGJlIHJlcG9ydGVkIHVubGVzcyB0aGV5IG9jY3VyIGluIHBsdWdpbnMgb3IgaW50ZWdyYXRpb25zLlxuaWYoIWlzU2RrRGlzcGF0Y2hlZCYmIWlzU0RLRXJyb3IoYnNFeGNlcHRpb24pJiZlcnJvclR5cGUhPT1FcnJvclR5cGUuSEFORExFREVYQ0VQVElPTil7cmV0dXJuO31pZihzdGF0ZS5yZXBvcnRpbmcuaXNFcnJvclJlcG9ydGluZ0VuYWJsZWQudmFsdWUpe2NvbnN0IGlzQWxsb3dlZD1hd2FpdCBjaGVja0lmQWxsb3dlZFRvQmVOb3RpZmllZChic0V4Y2VwdGlvbixzdGF0ZSx0aGlzLmh0dHBDbGllbnQpO2lmKGlzQWxsb3dlZCl7Y29uc3QgZXJyb3JTdGF0ZT17c2V2ZXJpdHk6J2Vycm9yJyx1bmhhbmRsZWQ6ZXJyb3JUeXBlIT09RXJyb3JUeXBlLkhBTkRMRURFWENFUFRJT04sc2V2ZXJpdHlSZWFzb246e3R5cGU6ZXJyb3JUeXBlfX07Ly8gVGhpcyB3aWxsIGFsbG93IGN1c3RvbSBncm91cGluZyBvZiBlcnJvcnMuXG4vLyBJbiBjYXNlIG9mIE5QTSBpbnN0YWxsYXRpb25zLCB0aGUgZGVmYXVsdCBncm91cGluZyBieSBzdXJyb3VuZGluZyBjb2RlXG4vLyBkb2VzIG5vdCBtYWtlIHNlbnNlIGFzIGVhY2ggdXNlciBhcHBsaWNhdGlvbiBpcyBkaWZmZXJlbnQgYW5kIHdpbGwgY3JlYXRlIGEgbG90IG9mIG5vaXNlIGluIHRoZSBhbGVydHMuXG4vLyBSZWZlcmVuY2VzOlxuLy8gaHR0cHM6Ly9kb2NzLmJ1Z3NuYWcuY29tL3BsYXRmb3Jtcy9qYXZhc2NyaXB0L2N1c3RvbWl6aW5nLWVycm9yLXJlcG9ydHMvI2dyb3VwaW5naGFzaFxuLy8gaH
1R0cHM6Ly9kb2NzLmJ1Z3NuYWcuY29tL3Byb2R1Y3QvZXJyb3ItZ3JvdXBpbmcvI3VzZXJfZGVmaW5lZFxuY29uc3Qgbm9ybWFsaXplZEdyb3VwaW5nSGFzaD1nZXRFcnJvckdyb3VwaW5nSGFzaChncm91cGluZ0hhc2gsYnNFeGNlcHRpb24ubWVzc2FnZSx0aGlzLmxvZ2dlcik7Ly8gR2V0IHRoZSBmaW5hbCBwYXlsb2FkIHRvIGJlIHNlbnQgdG8gdGhlIG1ldHJpY3Mgc2VydmljZVxuY29uc3QgYnVnc25hZ1BheWxvYWQ9Z2V0QnVnc25hZ0Vycm9yRXZlbnQoYnNFeGNlcHRpb24sZXJyb3JTdGF0ZSxzdGF0ZSxub3JtYWxpemVkR3JvdXBpbmdIYXNoKTtjb25zdCBlcnJvckNhdGVnb3J5PWdldEVycm9yQ2F0ZWdvcnkoYnNFeGNlcHRpb24sY2F0ZWdvcnkpOy8vIHNlbmQgaXQgdG8gbWV0cmljcyBzZXJ2aWNlXG50aGlzLmh0dHBDbGllbnQuZ2V0QXN5bmNEYXRhKHt1cmw6c3RhdGUubWV0cmljcy5tZXRyaWNzU2VydmljZVVybC52YWx1ZSxvcHRpb25zOnttZXRob2Q6J1BPU1QnLGRhdGE6Z2V0RXJyb3JEZWxpdmVyeVBheWxvYWQoYnVnc25hZ1BheWxvYWQsc3RhdGUsZXJyb3JDYXRlZ29yeSksc2VuZFJhd0RhdGE6dHJ1ZX0saXNSYXdSZXNwb25zZTp0cnVlfSk7fX0vLyBMb2cgaGFuZGxlZCBlcnJvcnMgYW5kIGVycm9ycyBkaXNwYXRjaGVkIGJ5IHRoZSBTREtcbmlmKGVycm9yVHlwZT09PUVycm9yVHlwZS5IQU5ETEVERVhDRVBUSU9OfHxpc1Nka0Rpc3BhdGNoZWQpe3RoaXMubG9nZ2VyLmVycm9yKGJzRXhjZXB0aW9uLm1lc3NhZ2UpO319Y2F0Y2goZXJyKXsvLyBJZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgaGFuZGxpbmcgYW4gZXJyb3IsIGxvZyBpdFxudGhpcy5sb2dnZXIuZXJyb3IoSEFORExFX0VSUk9SX0ZBSUxVUkUoRVJST1JfSEFORExFUiksZXJyKTt9fS8qKlxuICAgKiBBZGQgYnJlYWRjcnVtYnMgdG8gYWRkIGluc2lnaHQgb2YgYSB1c2VyJ3Mgam91cm5leSBiZWZvcmUgYW4gZXJyb3JcbiAgICogb2NjdXJyZWQgYW5kIHNlbmQgdG8gZXh0ZXJuYWwgZXJyb3IgbW9uaXRvcmluZyBzZXJ2aWNlIHZpYSBhIHBsdWdpblxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYnJlYWRjcnVtYiBicmVhZGNydW1icyBtZXNzYWdlXG4gICAqL2xlYXZlQnJlYWRjcnVtYihicmVhZGNydW1iKXt0cnl7c3RhdGUucmVwb3J0aW5nLmJyZWFkY3J1bWJzLnZhbHVlPVsuLi5zdGF0ZS5yZXBvcnRpbmcuYnJlYWRjcnVtYnMudmFsdWUsY3JlYXRlTmV3QnJlYWRjcnVtYihicmVhZGNydW1iKV07fWNhdGNoKGVycil7dGhpcy5vbkVycm9yKHtlcnJvcjplcnIsY29udGV4dDpFUlJPUl9IQU5ETEVSLGN1c3RvbU1lc3NhZ2U6QlJFQURDUlVNQl9FUlJPUixncm91cGluZ0hhc2g6QlJFQURDUlVNQl9FUlJPUn0pO319fS8vIE5vdGU6IFJlbWVtYmVyIHRvIGNhbGwgZGVmYXVsdEVycm9ySGFuZGxlci5pbml0KCkgYmVmb3JlIHVzaW5nIGl0XG5jb25zdCBkZWZhdWx0RXJyb3JIYW5kbGVyPW5ldyBFcnJvckhhbmRsZXIoZGVmYXVsdEh0dHBDbGllbnQsZGVmYXVsdExvZ2dlcik7XG5cbi8vICB0byBuZXh0IG9yIHJldHVybiB0aGUgdmFsdWUgaWYgaXQgaXMgdGhlIGxhc3Qgb25lIGluc3RlYWQgb2YgYW4gYXJyYXkgcGVyXG4vLyAgcGx1Z2luIHRoYXQgaXMgdGhlIG5vcm1hbCBpbnZva2Vcbi8vIFRPRE86IGFkZCBpbnZva2UgbWV0aG9kIGZvciBleHRlbnNpb24gcG9pbnQgdGhhdCB3ZSBrbm93IG9ubHkgb25lIHBsdWdpbiBjYW4gYmUgdXNlZC4gYWRkIGludm9rZU11bHRpcGxlIGFuZCBpbnZva2VTaW5nbGUgbWV0aG9kc1xuY2xhc3MgUGx1Z2luRW5naW5le3BsdWdpbnM9W107YnlOYW1lPXt9O2NhY2hlPXt9O2NvbmZpZz17dGhyb3dzOnRydWV9O2NvbnN0cnVjdG9yKGxvZ2dlcixvcHRpb25zPXt9KXt0aGlzLmNvbmZpZz17dGhyb3dzOnRydWUsLi4ub3B0aW9uc307dGhpcy5sb2dnZXI9bG9nZ2VyO31yZWdpc3RlcihwbHVnaW4sc3RhdGUpe2lmKCFwbHVnaW4ubmFtZSl7Y29uc3QgZXJyb3JNZXNzYWdlPVBMVUdJTl9OQU1FX01JU1NJTkdfRVJST1IoUExVR0lOX0VOR0lORSk7aWYodGhpcy5jb25maWcudGhyb3dzKXt0aHJvdyBuZXcgRXJyb3IoZXJyb3JNZXNzYWdlKTt9ZWxzZSB7dGhpcy5sb2dnZXIuZXJyb3IoZXJyb3JNZXNzYWdlLHBsdWdpbik7cmV0dXJuO319aWYodGhpcy5ieU5hbWVbcGx1Z2luLm5hbWVdKXtjb25zdCBlcnJvck1lc3NhZ2U9UExVR0lOX0FMUkVBRFlfRVhJU1RTX0VSUk9SKFBMVUdJTl9FTkdJTkUscGx1Z2luLm5hbWUpO2lmKHRoaXMuY29uZmlnLnRocm93cyl7dGhyb3cgbmV3IEVycm9yKGVycm9yTWVzc2FnZSk7fWVsc2Uge3RoaXMubG9nZ2VyLmVycm9yKGVycm9yTWVzc2FnZSk7cmV0dXJuO319dGhpcy5jYWNoZT17fTt0aGlzLnBsdWdpbnM9dGhpcy5wbHVnaW5zLnNsaWNlKCk7bGV0IHBvcz10aGlzLnBsdWdpbnMubGVuZ3RoO3RoaXMucGx1Z2lucy5mb3JFYWNoKChwbHVnaW5JdGVtLGluZGV4KT0+e2lmKHBsdWdpbkl0ZW0uZGVwcz8uaW5jbHVkZXMocGx1Z2luLm5hbWUpKXtwb3M9TWF0aC5taW4ocG9zLGluZGV4KTt9fSk7dGhpcy5wbHVnaW5zLnNwbGljZShwb3MsMCxwbHVnaW4pO3RoaXMuYnlOYW1lW3BsdWdpbi5uYW1lXT1wbHVnaW47aWYoaXNGdW5jdGlvbihwbHVnaW4uaW5pdGlhbGl6ZSkpe3BsdWdpbi5pbml0aWFsaXplKHN0YXRl
1KTt9fXVucmVnaXN0ZXIobmFtZSl7Y29uc3QgcGx1Z2luPXRoaXMuYnlOYW1lW25hbWVdO2lmKCFwbHVnaW4pe2NvbnN0IGVycm9yTWVzc2FnZT1QTFVHSU5fTk9UX0ZPVU5EX0VSUk9SKFBMVUdJTl9FTkdJTkUsbmFtZSk7aWYodGhpcy5jb25maWcudGhyb3dzKXt0aHJvdyBuZXcgRXJyb3IoZXJyb3JNZXNzYWdlKTt9ZWxzZSB7dGhpcy5sb2dnZXIuZXJyb3IoZXJyb3JNZXNzYWdlKTtyZXR1cm47fX1jb25zdCBpbmRleD10aGlzLnBsdWdpbnMuaW5kZXhPZihwbHVnaW4pO2lmKGluZGV4PT09LTEpe2NvbnN0IGVycm9yTWVzc2FnZT1QTFVHSU5fRU5HSU5FX0JVR19FUlJPUihQTFVHSU5fRU5HSU5FLG5hbWUpO2lmKHRoaXMuY29uZmlnLnRocm93cyl7dGhyb3cgbmV3IEVycm9yKGVycm9yTWVzc2FnZSk7fWVsc2Uge3RoaXMubG9nZ2VyLmVycm9yKGVycm9yTWVzc2FnZSk7cmV0dXJuO319dGhpcy5jYWNoZT17fTtkZWxldGUgdGhpcy5ieU5hbWVbbmFtZV07dGhpcy5wbHVnaW5zPXRoaXMucGx1Z2lucy5zbGljZSgpO3RoaXMucGx1Z2lucy5zcGxpY2UoaW5kZXgsMSk7fWdldFBsdWdpbihuYW1lKXtyZXR1cm4gdGhpcy5ieU5hbWVbbmFtZV07fWdldFBsdWdpbnMoZXh0UG9pbnQpe2NvbnN0IGxpZmVDeWNsZU5hbWU9ZXh0UG9pbnQ/PycuJztpZighdGhpcy5jYWNoZVtsaWZlQ3ljbGVOYW1lXSl7dGhpcy5jYWNoZVtsaWZlQ3ljbGVOYW1lXT10aGlzLnBsdWdpbnMuZmlsdGVyKHBsdWdpbj0+e2lmKHBsdWdpbi5kZXBzPy5zb21lKGRlcGVuZGVuY3k9PiF0aGlzLmJ5TmFtZVtkZXBlbmRlbmN5XSkpey8vIElmIGRlcHMgbm90IGV4aXN0LCB0aGVuIG5vdCBsb2FkIGl0LlxuY29uc3Qgbm90RXhpc3REZXBzPXBsdWdpbi5kZXBzLmZpbHRlcihkZXBlbmRlbmN5PT4hdGhpcy5ieU5hbWVbZGVwZW5kZW5jeV0pO3RoaXMubG9nZ2VyLmVycm9yKFBMVUdJTl9ERVBTX0VSUk9SKFBMVUdJTl9FTkdJTkUscGx1Z2luLm5hbWUsbm90RXhpc3REZXBzKSk7cmV0dXJuIGZhbHNlO31yZXR1cm4gbGlmZUN5Y2xlTmFtZT09PScuJz90cnVlOmhhc1ZhbHVlQnlQYXRoKHBsdWdpbixsaWZlQ3ljbGVOYW1lKTt9KTt9cmV0dXJuIHRoaXMuY2FjaGVbbGlmZUN5Y2xlTmFtZV07fS8vIFRoaXMgbWV0aG9kIGFsbG93cyB0byBwcm9jZXNzIHRoaXMucGx1Z2lucyBzbyB0aGF0IGl0IGNvdWxkXG4vLyBkbyBzb21lIHVuaWZpZWQgcHJlLXByb2Nlc3MgYmVmb3JlIGFwcGxpY2F0aW9uIHN0YXJ0cy5cbnByb2Nlc3NSYXdQbHVnaW5zKGNhbGxiYWNrKXtjYWxsYmFjayh0aGlzLnBsdWdpbnMpO3RoaXMuY2FjaGU9e307fWludm9rZShleHRQb2ludCxhbGxvd011bHRpcGxlPXRydWUsLi4uYXJncyl7bGV0IGV4dGVuc2lvblBvaW50TmFtZT1leHRQb2ludDtpZighZXh0ZW5zaW9uUG9pbnROYW1lKXt0aHJvdyBuZXcgRXJyb3IoUExVR0lOX0VYVF9QT0lOVF9NSVNTSU5HX0VSUk9SKTt9Y29uc3Qgbm9DYWxsPWV4dGVuc2lvblBvaW50TmFtZS5zdGFydHNXaXRoKCchJyk7Y29uc3QgdGhyb3dzPXRoaXMuY29uZmlnLnRocm93cz8/ZXh0ZW5zaW9uUG9pbnROYW1lLmVuZHNXaXRoKCchJyk7Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHVuaWNvcm4vYmV0dGVyLXJlZ2V4XG5leHRlbnNpb25Qb2ludE5hbWU9ZXh0ZW5zaW9uUG9pbnROYW1lLnJlcGxhY2UoLyheIXwhJCkvZywnJyk7aWYoIWV4dGVuc2lvblBvaW50TmFtZSl7dGhyb3cgbmV3IEVycm9yKFBMVUdJTl9FWFRfUE9JTlRfSU5WQUxJRF9FUlJPUik7fWNvbnN0IGV4dGVuc2lvblBvaW50TmFtZVBhcnRzPWV4dGVuc2lvblBvaW50TmFtZS5zcGxpdCgnLicpO2V4dGVuc2lvblBvaW50TmFtZVBhcnRzLnBvcCgpO2NvbnN0IHBsdWdpbk1ldGhvZFBhdGg9ZXh0ZW5zaW9uUG9pbnROYW1lUGFydHMuam9pbignLicpO2NvbnN0IHBsdWdpbnNUb0ludm9rZT1hbGxvd011bHRpcGxlP3RoaXMuZ2V0UGx1Z2lucyhleHRlbnNpb25Qb2ludE5hbWUpOlt0aGlzLmdldFBsdWdpbnMoZXh0ZW5zaW9uUG9pbnROYW1lKVswXV07cmV0dXJuIHBsdWdpbnNUb0ludm9rZS5tYXAocGx1Z2luPT57Y29uc3QgbWV0aG9kPWdldFZhbHVlQnlQYXRoKHBsdWdpbixleHRlbnNpb25Qb2ludE5hbWUpO2lmKCFpc0Z1bmN0aW9uKG1ldGhvZCl8fG5vQ2FsbCl7cmV0dXJuIG1ldGhvZDt9dHJ5e3JldHVybiBtZXRob2QuYXBwbHkoZ2V0VmFsdWVCeVBhdGgocGx1Z2luLHBsdWdpbk1ldGhvZFBhdGgpLGFyZ3MpO31jYXRjaChlcnIpey8vIFdoZW4gYSBwbHVnaW4gZmFpbGVkLCBkb2Vzbid0IGJyZWFrIHRoZSBhcHBcbmlmKHRocm93cyl7dGhyb3cgZXJyO31lbHNlIHt0aGlzLmxvZ2dlci5lcnJvcihQTFVHSU5fSU5WT0NBVElPTl9FUlJPUihQTFVHSU5fRU5HSU5FLGV4dGVuc2lvblBvaW50TmFtZSxwbHVnaW4ubmFtZSksZXJyKTt9fXJldHVybiBudWxsO30pO31pbnZva2VTaW5nbGUoZXh0UG9pbnQsLi4uYXJncyl7cmV0dXJuIHRoaXMuaW52b2tlKGV4dFBvaW50LGZhbHNlLC4uLmFyZ3MpWzBdO31pbnZva2VNdWx0aXBsZShleHRQb2ludCwuLi5hcmdzKXtyZXR1cm4gdGhpcy5pbnZva2UoZXh0UG9pbnQsdHJ1ZSwuLi5hcmdzKTt9fWNvbnN0IGRlZmF1bHRQbHVnaW5FbmdpbmU9bmV3IFBsdWdpbkVuZ2luZShkZWZhdWx0TG9nZ2VyLHt0aHJvd3M6dHJ1ZX0pO1xuXG4vKipcbiAqIEEgZnVuY3Rpb24gdG8gZmlsdGVyIGFuZCByZXR1cm4gbm9uIGNsb3VkIG1vZGUgZGVzdGluYXRpb25zXG4gKiBBIGRlc3RpbmF0aW9uIGlzIGNvbnNpZGVyZWQgbm9uIGNsb3VkIG1vZGUgaWYgaXQgaXMgbm90IGEgY2xvdWQgbW9kZSBkZXN0aW5hdGlvbiBvciBpZiBpdCBpcyBhIGh5YnJpZCBtb2RlIGRlc3RpbmF0aW9uXG4gKiBAcGFyYW0gZGVzdGluYXRpb25cbiAqXG4gKiBAcmV0dXJucyBib29sZWFuXG4gKi9jb25zdCBpc05vbkNsb3VkRGVzdGluYXRpb249ZGVzdGluYXRpb249PkJvb2xlYW4oZGVzdGluYXRpb24uY29uZmlnLmNvbm5lY3Rpb25Nb2RlIT09J2Nsb3VkJ3x8ZGVzdGluYXRpb24uY29uZmlnLnVzZU5hdGl2ZVNES1RvU2VuZD09PXRydWV8fC8vIHRoaXMgaXMgdGhlIG9sZGVyIGZsYWcgZm9yIGh5YnJpZCBtb2RlIGRlc3RpbmF0aW9uc1xuZGVzdGluYXRpb24uY29uZmlnLnVzZU5hdGl2ZVNESz09PXRydWUpO2NvbnN0IGlzSHlicmlkTW9kZURlc3RpbmF0aW9uPWRlc3RpbmF0aW9uPT5Cb29sZWFuKGRlc3RpbmF0aW9uLm
1NvbmZpZy5jb25uZWN0aW9uTW9kZT09PSdoeWJyaWQnfHxkZXN0aW5hdGlvbi5jb25maWcudXNlTmF0aXZlU0RLVG9TZW5kPT09dHJ1ZSk7LyoqXG4gKiBBIGZ1bmN0aW9uIHRvIGZpbHRlciBhbmQgcmV0dXJuIG5vbiBjbG91ZCBtb2RlIGRlc3RpbmF0aW9uc1xuICogQHBhcmFtIGRlc3RpbmF0aW9uc1xuICpcbiAqIEByZXR1cm5zIGRlc3RpbmF0aW9uc1xuICovY29uc3QgZ2V0Tm9uQ2xvdWREZXN0aW5hdGlvbnM9ZGVzdGluYXRpb25zPT5kZXN0aW5hdGlvbnMuZmlsdGVyKGlzTm9uQ2xvdWREZXN0aW5hdGlvbik7LyoqXG4gKiBBIGZ1bmN0aW9uIHRvIGdldCB0aGUgdXNlciBmcmllbmRseSBpZCBmb3IgYSBkZXN0aW5hdGlvblxuICogUmVwbGFjZXMgYWxsIHNwYWNlcyB3aXRoIGh5cGhlbnMgYW5kIGFwcGVuZHMgdGhlIGlkIHRvIHRoZSBkaXNwbGF5IG5hbWVcbiAqIEBwYXJhbSBkaXNwbGF5TmFtZSBUaGUgZGlzcGxheSBuYW1lIG9mIHRoZSBkZXN0aW5hdGlvblxuICogQHBhcmFtIGlkIFRoZSBpZCBvZiB0aGUgZGVzdGluYXRpb25cbiAqXG4gKiBAcmV0dXJucyB0aGUgdXNlciBmcmllbmRseSBpZFxuICovY29uc3QgZ2V0RGVzdGluYXRpb25Vc2VyRnJpZW5kbHlJZD0oZGlzcGxheU5hbWUsaWQpPT5gJHtkaXNwbGF5TmFtZS5yZXBsYWNlQWxsKCcgJywnLScpfV9fXyR7aWR9YDtcblxuLyoqXG4gKiBMaXN0IG9mIHBsdWdpbiBuYW1lcyB0aGF0IGFyZSBsb2FkZWQgYXMgZHluYW1pYyBpbXBvcnRzIGluIG1vZGVybiBidWlsZHNcbiAqL2NvbnN0IHBsdWdpbk5hbWVzTGlzdD1bJ0JlYWNvblF1ZXVlJywnQ3VzdG9tQ29uc2VudE1hbmFnZXInLCdEZXZpY2VNb2RlRGVzdGluYXRpb25zJywnRGV2aWNlTW9kZVRyYW5zZm9ybWF0aW9uJywnRXh0ZXJuYWxBbm9ueW1vdXNJZCcsJ0dvb2dsZUxpbmtlcicsJ0l1YmVuZGFDb25zZW50TWFuYWdlcicsJ0tldGNoQ29uc2VudE1hbmFnZXInLCdOYXRpdmVEZXN0aW5hdGlvblF1ZXVlJywnT25lVHJ1c3RDb25zZW50TWFuYWdlcicsJ1N0b3JhZ2VFbmNyeXB0aW9uJywnU3RvcmFnZUVuY3J5cHRpb25MZWdhY3knLCdTdG9yYWdlTWlncmF0b3InLCdYaHJRdWV1ZSddO2NvbnN0IGRlcHJlY2F0ZWRQbHVnaW5zTGlzdD1bJ0J1Z3NuYWcnLCdFcnJvclJlcG9ydGluZyddO1xuXG5jb25zdCBDT09LSUVfU1RPUkFHRT0nY29va2llU3RvcmFnZSc7Y29uc3QgTE9DQUxfU1RPUkFHRT0nbG9jYWxTdG9yYWdlJztjb25zdCBTRVNTSU9OX1NUT1JBR0U9J3Nlc3Npb25TdG9yYWdlJztjb25zdCBNRU1PUllfU1RPUkFHRT0nbWVtb3J5U3RvcmFnZSc7Y29uc3QgTk9fU1RPUkFHRT0nbm9uZSc7Y29uc3QgU1RPUkFHRV9URVNUX0NPT0tJRT0ndGVzdF9ydWRkZXJfY29va2llJztjb25zdCBTVE9SQUdFX1RFU1RfTE9DQUxfU1RPUkFHRT0ndGVzdF9ydWRkZXJfbHMnO2NvbnN0IFNUT1JBR0VfVEVTVF9TRVNTSU9OX1NUT1JBR0U9J3Rlc3RfcnVkZGVyX3NzJztcblxuY29uc3QgcmVtb3ZlRHVwbGljYXRlU2xhc2hlcz1zdHI9PnN0ci5yZXBsYWNlKC9cXC97Mix9L2csJy8nKTsvKipcbiAqIENoZWNrcyBpZiBwcm92aWRlZCB1cmwgaXMgdmFsaWQgb3Igbm90XG4gKiBAcGFyYW0gdXJsXG4gKiBAcmV0dXJucyB0cnVlIGlmIGB1cmxgIGlzIHZhbGlkIGFuZCBmYWxzZSBvdGhlcndpc2VcbiAqL2NvbnN0IGlzVmFsaWRVUkw9dXJsPT57aWYoIWlzU3RyaW5nKHVybCkpe3JldHVybiBmYWxzZTt9dHJ5ey8vIElmIFVSTCBpcyBzdXBwb3J0ZWQgYnkgdGhlIGJyb3dzZXIsIHdlIGNhbiB1c2UgaXQgdG8gdmFsaWRhdGUgdGhlIFVSTFxuLy8gT3RoZXJ3aXNlLCB3ZSBjYW4gYXQgbGVhc3QgY2hlY2sgaWYgdGhlIFVSTCBtYXRjaGVzIHRoZSBwYXR0ZXJuXG5pZihpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuVVJMKSl7Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLW5ld1xubmV3IFVSTCh1cmwpO31yZXR1cm4gVVJMX1BBVFRFUk4udGVzdCh1cmwpO31jYXRjaChlKXtyZXR1cm4gZmFsc2U7fX07XG5cbi8qKlxuICogVGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIGRldGVybWluZSBpZiB0aGUgaW5wdXQgc3RhdHVzIGNvZGUgaXMgcmV0cnlhYmxlLlxuICogQHBhcmFtIHN0YXR1cyAtIFRoZSBzdGF0dXMgY29kZS5cbiAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHN0YXR1cyBjb2RlIGlzIG5vdCA0eHggKGV4Y2VwdCA0MjkpLCBmYWxzZSBvdGhlcndpc2UuXG4gKi9jb25zdCBpc0VyclJldHJ5YWJsZT1zdGF0dXM9PntpZihzdGF0dXM9PT00Mjkpe3JldHVybiB0cnVlO31yZXR1cm4gIShzdGF0dXM+PTQwMCYmc3RhdHVzPDUwMCk7fTtcblxuLyoqXG4gKiBFbmNvZGUuXG4gKi9jb25zdCBlbmNvZGU9KHZhbHVlLGxvZ2dlcik9Pnt0cnl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSk7fWNhdGNoKGVycil7bG9nZ2VyPy5lcnJvcihDT09LSUVfREFUQV9FTkNPRElOR19FUlJPUixlcnIpO3JldHVybiB1bmRlZmluZWQ7fX07LyoqXG4gKiBEZWNvZGVcbiAqL2NvbnN0IGRlY29kZSQxPXZhbHVlPT57dHJ5e3JldHVybiBkZWNvZGVVUklDb21wb25lbnQodmFsdWUpO31jYXRjaChlcnIpey8vIERvIG5vdGhpbmcgYXMgbm9uLVJTIFNESyBjb29raWVzIG1heSBub3QgYmUgVVJJIGVuY29kZWRcbnJldHVybiB1bmRlZmluZWQ7fX07LyoqXG4gKiBQYXJzZSBjb29raWUgYHN0cmBcbiAqL2NvbnN0IHBhcnNlPXN0cj0+e2NvbnN0IG9iaj17fTtjb25zdCBwYWlycz1zdHIuc3BsaXQoL1xccyo7XFxzKi8pO2xldCBwYWlyO2lmKCFwYWlyc1swXSl7cmV0dXJuIG9iajt9Ly8gVE9ETzogRGVjb2RlIG9ubHkgdGhlIGNvb2tpZXMgdGhhdCBhcmUgbmVlZGVkIGJ5IHRoZSBTREtcbnBhaXJzLmZvckVhY2gocGFpckl0ZW09PntwYWlyPXBhaXJJdGVtLnNwbGl0KCc9Jyk7Y29uc3Qga2V5TmFtZT1wYWlyWzBdP2RlY29kZSQxKHBhaXJbMF0pOnVuZGVmaW5lZDtpZihrZXlOYW1lKXtvYmpba2V5TmFtZV09cGFpclsxXT9kZWNvZGUkMShwYWlyWzFdKTp1bmRlZmluZWQ7fX0pO3JldHVybiBvYmo7fTsvKipcbiAqIFNldCBjb29raWUgYG5hbWVgIHRvIGB2YWx1ZWBcbiAqL2NvbnN0IHNldD0obmFtZSx2YWx1ZSxvcHRpb25zQ29uZmlnLGxvZ2dlcik9Pntjb25zdCBvcHRpb25zPXsu
1Li4ob3B0aW9uc0NvbmZpZ3x8e30pfTtsZXQgY29va2llU3RyaW5nPWAke2VuY29kZShuYW1lLGxvZ2dlcil9PSR7ZW5jb2RlKHZhbHVlLGxvZ2dlcil9YDtpZihpc051bGwodmFsdWUpKXtvcHRpb25zLm1heGFnZT0tMTt9aWYob3B0aW9ucy5tYXhhZ2Upe29wdGlvbnMuZXhwaXJlcz1uZXcgRGF0ZSgrbmV3IERhdGUoKStvcHRpb25zLm1heGFnZSk7fWlmKG9wdGlvbnMucGF0aCl7Y29va2llU3RyaW5nKz1gOyBwYXRoPSR7b3B0aW9ucy5wYXRofWA7fWlmKG9wdGlvbnMuZG9tYWluKXtjb29raWVTdHJpbmcrPWA7IGRvbWFpbj0ke29wdGlvbnMuZG9tYWlufWA7fWlmKG9wdGlvbnMuZXhwaXJlcyl7Y29va2llU3RyaW5nKz1gOyBleHBpcmVzPSR7b3B0aW9ucy5leHBpcmVzLnRvVVRDU3RyaW5nKCl9YDt9aWYob3B0aW9ucy5zYW1lc2l0ZSl7Y29va2llU3RyaW5nKz1gOyBzYW1lc2l0ZT0ke29wdGlvbnMuc2FtZXNpdGV9YDt9aWYob3B0aW9ucy5zZWN1cmUpe2Nvb2tpZVN0cmluZys9YDsgc2VjdXJlYDt9Z2xvYmFsVGhpcy5kb2N1bWVudC5jb29raWU9Y29va2llU3RyaW5nO307LyoqXG4gKiBSZXR1cm4gYWxsIGNvb2tpZXNcbiAqL2NvbnN0IGFsbD0oKT0+e2NvbnN0IGNvb2tpZVN0cmluZ1ZhbHVlPWdsb2JhbFRoaXMuZG9jdW1lbnQuY29va2llO3JldHVybiBwYXJzZShjb29raWVTdHJpbmdWYWx1ZSk7fTsvKipcbiAqIEdldCBjb29raWUgYG5hbWVgXG4gKi9jb25zdCBnZXQ9bmFtZT0+YWxsKClbbmFtZV07LyoqXG4gKiBTZXQgb3IgZ2V0IGNvb2tpZSBgbmFtZWAgd2l0aCBgdmFsdWVgIGFuZCBgb3B0aW9uc2Agb2JqZWN0XG4gKi8vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZnVuYy1uYW1lc1xuY29uc3QgY29va2llPWZ1bmN0aW9uKG5hbWUsdmFsdWUsb3B0aW9ucyxsb2dnZXIpe3N3aXRjaChhcmd1bWVudHMubGVuZ3RoKXtjYXNlIDQ6Y2FzZSAzOmNhc2UgMjpyZXR1cm4gc2V0KG5hbWUsdmFsdWUsb3B0aW9ucyxsb2dnZXIpO2Nhc2UgMTppZihuYW1lKXtyZXR1cm4gZ2V0KG5hbWUpO31yZXR1cm4gYWxsKCk7ZGVmYXVsdDpyZXR1cm4gYWxsKCk7fX07XG5cbmNvbnN0IHVzZXJJZEtleT0ncmxfdXNlcl9pZCc7Y29uc3QgdXNlclRyYWl0c0tleT0ncmxfdHJhaXQnO2NvbnN0IGFub255bW91c1VzZXJJZEtleT0ncmxfYW5vbnltb3VzX2lkJztjb25zdCBncm91cElkS2V5PSdybF9ncm91cF9pZCc7Y29uc3QgZ3JvdXBUcmFpdHNLZXk9J3JsX2dyb3VwX3RyYWl0Jztjb25zdCBwYWdlSW5pdGlhbFJlZmVycmVyS2V5PSdybF9wYWdlX2luaXRfcmVmZXJyZXInO2NvbnN0IHBhZ2VJbml0aWFsUmVmZXJyaW5nRG9tYWluS2V5PSdybF9wYWdlX2luaXRfcmVmZXJyaW5nX2RvbWFpbic7Y29uc3Qgc2Vzc2lvbkluZm9LZXk9J3JsX3Nlc3Npb24nO2NvbnN0IGF1dGhUb2tlbktleT0ncmxfYXV0aF90b2tlbic7Y29uc3QgQ09PS0lFX0tFWVM9e3VzZXJJZDp1c2VySWRLZXksdXNlclRyYWl0czp1c2VyVHJhaXRzS2V5LGFub255bW91c0lkOmFub255bW91c1VzZXJJZEtleSxncm91cElkOmdyb3VwSWRLZXksZ3JvdXBUcmFpdHM6Z3JvdXBUcmFpdHNLZXksaW5pdGlhbFJlZmVycmVyOnBhZ2VJbml0aWFsUmVmZXJyZXJLZXksaW5pdGlhbFJlZmVycmluZ0RvbWFpbjpwYWdlSW5pdGlhbFJlZmVycmluZ0RvbWFpbktleSxzZXNzaW9uSW5mbzpzZXNzaW9uSW5mb0tleSxhdXRoVG9rZW46YXV0aFRva2VuS2V5fTtjb25zdCBFTkNSWVBUSU9OX1BSRUZJWF9WMz0nUlNfRU5DX3YzXyc7XG5cbmNvbnN0IGVuY3J5cHRCcm93c2VyPXZhbHVlPT5gJHtFTkNSWVBUSU9OX1BSRUZJWF9WM30ke3RvQmFzZTY0KHZhbHVlKX1gO2NvbnN0IGRlY3J5cHRCcm93c2VyPXZhbHVlPT57aWYodmFsdWU/LnN0YXJ0c1dpdGgoRU5DUllQVElPTl9QUkVGSVhfVjMpKXtyZXR1cm4gZnJvbUJhc2U2NCh2YWx1ZS5zdWJzdHJpbmcoRU5DUllQVElPTl9QUkVGSVhfVjMubGVuZ3RoKSk7fXJldHVybiB2YWx1ZTt9O1xuXG5jb25zdCBFVkVOVF9QQVlMT0FEX1NJWkVfQllURVNfTElNSVQ9MzIqMTAyNDsvLyAzMiBLQlxuY29uc3QgUkVUUllfUkVBU09OX0NMSUVOVF9ORVRXT1JLPSdjbGllbnQtbmV0d29yayc7Y29uc3QgUkVUUllfUkVBU09OX0NMSUVOVF9USU1FT1VUPSdjbGllbnQtdGltZW91dCc7Y29uc3QgREVGQVVMVF9SRVRSWV9SRUFTT049UkVUUllfUkVBU09OX0NMSUVOVF9ORVRXT1JLO1xuXG5jb25zdCBpc1N0b3JhZ2VRdW90YUV4Y2VlZGVkPWU9Pntjb25zdCBtYXRjaGluZ05hbWVzPVsnUXVvdGFFeGNlZWRlZEVycm9yJywnTlNfRVJST1JfRE9NX1FVT1RBX1JFQUNIRUQnXTsvLyBFdmVyeXRoaW5nIGV4Y2VwdCBGaXJlZm94LCBGaXJlZm94XG5jb25zdCBtYXRjaGluZ0NvZGVzPVsyMiwxMDE0XTtpZihlIGluc3RhbmNlb2YgRE9NRXhjZXB0aW9uKXtyZXR1cm4gbWF0Y2hpbmdOYW1lcy5pbmNsdWRlcyhlLm5hbWUpfHxtYXRjaGluZ0NvZGVzLmluY2x1ZGVzKGUuY29kZSk7fXJldHVybiBmYWxzZTt9Oy8vIFRPRE86IGFsc28gY2hlY2sgZm9yIFNlY3VyaXR5RXJyb3JzXG4vLyAgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL1dpbmRvdy9sb2NhbFN0b3JhZ2UjZXhjZXB0aW9uc1xuY29uc3QgaXNTdG9yYWdlQXZhaWxhYmxlPSh0eXBlPUxPQ0FMX1NUT1JBR0Usc3RvcmFnZUluc3RhbmNlLGxvZ2dlcik9PntsZXQgc3RvcmFnZTtsZXQgdGVzdERhdGE7Y29uc3QgbXNnUHJlZml4PVNUT1JBR0VfVU5BVkFJTEFCSUxJVFlfRVJST1JfUFJFRklYKENBUEFCSUxJVElFU19NQU5BR0VSLHR5cGUpO2xldCByZWFzb249J3VuYXZhaWxhYmxlJztsZXQgaXNBY2Nlc3NpYmxlPXRydWU7bGV0IGVyck9iajt0cnl7c3dpdGNoKHR5cGUpe2Nhc2UgTUVNT1JZX1NUT1JBR0U6cmV0dXJuIHRydWU7Y2FzZSBDT09LSUVfU1RPUkFHRTpzdG9yYWdlPXN0b3JhZ2VJbnN0YW5jZTt0ZXN0RGF0YT1TVE9SQUdFX1RFU1RfQ09PS0lFO2JyZWFrO2Nhc2UgTE9DQUxfU1RPUkFHRTpzdG9yYWdlPXN0b3JhZ2VJbnN0YW5jZT8/Z2xvYmFsVGhpcy5sb2NhbFN0b3JhZ2U7dGVzdERhdGE9U1RPUkFHRV9URVNUX0xPQ0FMX1NUT1JBR0U7Ly8gd2FzIFNUT1JBR0VfVEVTVF9MT0NBTF9TVE9SQUdFIGluIG91cnMgYW5kIGdlbmVyYXRlVVVJRCgpIGluIHNlZ21lbnQgcmV0cnkgb25lXG5icmVhaztjYXNlIFNFU1NJT05fU1RPUkFHRTpzdG9yYWdlPXN0b3JhZ2VJbnN0YW5jZT8/Z2xvYmFsVGh
1pcy5zZXNzaW9uU3RvcmFnZTt0ZXN0RGF0YT1TVE9SQUdFX1RFU1RfU0VTU0lPTl9TVE9SQUdFO2JyZWFrO2RlZmF1bHQ6cmV0dXJuIGZhbHNlO31pZihzdG9yYWdlKXtzdG9yYWdlLnNldEl0ZW0odGVzdERhdGEsJ3RydWUnKTtpZihzdG9yYWdlLmdldEl0ZW0odGVzdERhdGEpKXtzdG9yYWdlLnJlbW92ZUl0ZW0odGVzdERhdGEpO3JldHVybiB0cnVlO319aXNBY2Nlc3NpYmxlPWZhbHNlO31jYXRjaChlcnIpe2lzQWNjZXNzaWJsZT1mYWxzZTtlcnJPYmo9ZXJyO2lmKGlzU3RvcmFnZVF1b3RhRXhjZWVkZWQoZXJyKSl7cmVhc29uPSdmdWxsJzt9fWlmKCFpc0FjY2Vzc2libGUpe2xvZ2dlcj8ud2FybihgJHttc2dQcmVmaXh9JHtyZWFzb259LmAsZXJyT2JqKTt9Ly8gaWYgd2UndmUgaGF2ZSByZWFjaGVkIGhlcmUsIGl0IG1lYW5zIHRoZSBzdG9yYWdlIGlzIG5vdCBhdmFpbGFibGVcbnJldHVybiBmYWxzZTt9O1xuXG5jb25zdCBFVkVOVF9QQVlMT0FEX1NJWkVfQ0hFQ0tfRkFJTF9XQVJOSU5HPShjb250ZXh0LHBheWxvYWRTaXplLHNpemVMaW1pdCk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9VGhlIHNpemUgb2YgdGhlIGV2ZW50IHBheWxvYWQgKCR7cGF5bG9hZFNpemV9IGJ5dGVzKSBleGNlZWRzIHRoZSBtYXhpbXVtIGxpbWl0IG9mICR7c2l6ZUxpbWl0fSBieXRlcy4gRXZlbnRzIHdpdGggbGFyZ2UgcGF5bG9hZHMgbWF5IGJlIGRyb3BwZWQgaW4gdGhlIGZ1dHVyZS4gUGxlYXNlIHJldmlldyB5b3VyIGluc3RydW1lbnRhdGlvbiB0byBlbnN1cmUgdGhhdCBldmVudCBwYXlsb2FkcyBhcmUgd2l0aGluIHRoZSBzaXplIGxpbWl0LmA7Y29uc3QgRVZFTlRfUEFZTE9BRF9TSVpFX1ZBTElEQVRJT05fV0FSTklORz1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfUZhaWxlZCB0byB2YWxpZGF0ZSBldmVudCBwYXlsb2FkIHNpemUuIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB0aGUgZXZlbnQgcGF5bG9hZCBpcyB3aXRoaW4gdGhlIHNpemUgbGltaXQgYW5kIGlzIGEgdmFsaWQgSlNPTiBvYmplY3QuYDtjb25zdCBRVUVVRV9VVElMSVRJRVM9J1F1ZXVlVXRpbGl0aWVzJzsvKipcbiAqIFV0aWxpdHkgdG8gZ2V0IHRoZSBzdHJpbmdpZmllZCBldmVudCBwYXlsb2FkXG4gKiBAcGFyYW0gZXZlbnQgUnVkZGVyRXZlbnQgb2JqZWN0XG4gKiBAcGFyYW0gbG9nZ2VyIExvZ2dlciBpbnN0YW5jZVxuICogQHJldHVybnMgc3RyaW5naWZpZWQgZXZlbnQgcGF5bG9hZC4gRW1wdHkgc3RyaW5nIGlmIGVycm9yIG9jY3Vycy5cbiAqL2NvbnN0IGdldERlbGl2ZXJ5UGF5bG9hZD0oZXZlbnQsbG9nZ2VyKT0+c3RyaW5naWZ5V2l0aG91dENpcmN1bGFyKGV2ZW50LHRydWUsdW5kZWZpbmVkLGxvZ2dlcik7Y29uc3QgZ2V0RE1URGVsaXZlcnlQYXlsb2FkPShkbXRSZXF1ZXN0UGF5bG9hZCxsb2dnZXIpPT5zdHJpbmdpZnlXaXRob3V0Q2lyY3VsYXIoZG10UmVxdWVzdFBheWxvYWQsdHJ1ZSx1bmRlZmluZWQsbG9nZ2VyKTsvKipcbiAqIFV0aWxpdHkgdG8gdmFsaWRhdGUgZmluYWwgcGF5bG9hZCBzaXplIGJlZm9yZSBzZW5kaW5nIHRvIHNlcnZlclxuICogQHBhcmFtIGV2ZW50IFJ1ZGRlckV2ZW50IG9iamVjdFxuICogQHBhcmFtIGxvZ2dlciBMb2dnZXIgaW5zdGFuY2VcbiAqL2NvbnN0IHZhbGlkYXRlRXZlbnRQYXlsb2FkU2l6ZT0oZXZlbnQsbG9nZ2VyKT0+e2NvbnN0IHBheWxvYWRTdHI9Z2V0RGVsaXZlcnlQYXlsb2FkKGV2ZW50LGxvZ2dlcik7aWYocGF5bG9hZFN0cil7Y29uc3QgcGF5bG9hZFNpemU9cGF5bG9hZFN0ci5sZW5ndGg7aWYocGF5bG9hZFNpemU+RVZFTlRfUEFZTE9BRF9TSVpFX0JZVEVTX0xJTUlUKXtsb2dnZXI/Lndhcm4oRVZFTlRfUEFZTE9BRF9TSVpFX0NIRUNLX0ZBSUxfV0FSTklORyhRVUVVRV9VVElMSVRJRVMscGF5bG9hZFNpemUsRVZFTlRfUEFZTE9BRF9TSVpFX0JZVEVTX0xJTUlUKSk7fX1lbHNlIHtsb2dnZXI/Lndhcm4oRVZFTlRfUEFZTE9BRF9TSVpFX1ZBTElEQVRJT05fV0FSTklORyhRVUVVRV9VVElMSVRJRVMpKTt9fTsvKipcbiAqIE11dGF0ZXMgdGhlIGV2ZW50IGFuZCByZXR1cm4gZmluYWwgZXZlbnQgZm9yIGRlbGl2ZXJ5XG4gKiBVcGRhdGVzIGNlcnRhaW4gcGFyYW1ldGVycyBsaWtlIHNlbnRBdCB0aW1lc3RhbXAsIGludGVncmF0aW9ucyBjb25maWcgZXRjLlxuICogQHBhcmFtIGV2ZW50IFJ1ZGRlckV2ZW50IG9iamVjdFxuICogQHJldHVybnMgRmluYWwgZXZlbnQgcmVhZHkgdG8gYmUgZGVsaXZlcmVkXG4gKi9jb25zdCBnZXRGaW5hbEV2ZW50Rm9yRGVsaXZlcnlNdXRhdG9yPShldmVudCxjdXJyZW50VGltZSk9Pntjb25zdCBmaW5hbEV2ZW50PWNsb25lKGV2ZW50KTsvLyBVcGRhdGUgc2VudEF0IHRpbWVzdGFtcCB0byB0aGUgbGF0ZXN0IHRpbWVzdGFtcFxuZmluYWxFdmVudC5zZW50QXQ9Y3VycmVudFRpbWU7cmV0dXJuIGZpbmFsRXZlbnQ7fTsvKipcbiAqIFV0aWxpdHkgdG8gZ2V0IHRoZSBzdG9yYWdlIHR5cGUgZm9yIGV2ZW50cyBwZXJzaXN0ZW5jZVxuICogSWYgbG9jYWwgc3RvcmFnZSBpcyBhdmFpbGFibGUsIHVzZSBpdDsgZWxzZSwgZmFsbCBiYWNrIHRvIHNlc3Npb24gc3RvcmFnZTsgZWxzZSwgZmFsbCBiYWNrIHRvIG1lbW9yeSBzdG9yYWdlLlxuICogT24gc29tZSBicm93c2VycywgcGVyc2lzdGVuY2Ugc3RvcmFnZSBpcyBibG9ja2VkIGZvciB0aGUgSlMgU0RLIHRoYXQgaXMgbG9hZGVkIGZyb20gUlMgZG9tYWlucy5cbiAqIEluIHN1Y2ggY2FzZXMsIHdlIG5lZWQgdG8gdmVyaWZ5IGFsbCB0aGUgc3RvcmFnZSB0eXBlcyBhbmQgdXNlIHRoZSBmaXJzdCBvbmUgdGhhdCBpcyBhdmFpbGFibGUuXG4gKiBAcGFyYW0gbG9nZ2VyIExvZ2dlciBpbnN0YW5jZSBmb3IgbG9nZ2luZyBzdG9yYWdlIGF2YWlsYWJpbGl0eSB3YXJuaW5nc1xuICogQHJldHVybnMgU3RvcmFnZVR5cGVcbiAqL2NvbnN0IGdldFN0b3JhZ2VUeXBlRm9yRXZlbnRzUGVyc2lzdGVuY2U9bG9nZ2VyPT57aWYoaXNTdG9yYWdlQXZhaWxhYmxlKExPQ0FMX1NUT1JBR0UsdW5kZWZpbmVkLGxvZ2dlcikpe3JldHVybiBMT0NBTF9TVE9SQUdFO31pZihpc1N0b3JhZ2VBdmFpbGFibGUoU0VTU0lPTl9TVE9SQUdFLHVuZGVmaW5lZCxsb2dnZXIpKXtyZXR1cm4gU0VTU0lPTl9TVE9SQUdFO30vLyBEb24ndCB1c2UgY29va2llIHN0b3JhZ2UgYXMgaXQgY2FuIHBvdGVudGlhbGx5IGNhdXNlIG92ZXJoZWFkIHdpdGggdGhlIG5ldHdvcmsgcmVxdWVzdHMuXG4vLyBOb3RlIHRoYXQgZXZlbnRzIHdpbGwgbm90IGJlIHBlcnNpc3RlZCBhY3Jvc3MgcGFnZSByZWxvYWRzIGluIHRoaXMgY2FzZS5cbnJldHVybi
1BNRU1PUllfU1RPUkFHRTt9O1xuXG5jb25zdCBRdWV1ZVN0YXR1c2VzPXtJTl9QUk9HUkVTUzonaW5Qcm9ncmVzcycsUVVFVUU6J3F1ZXVlJyxSRUNMQUlNX1NUQVJUOidyZWNsYWltU3RhcnQnLFJFQ0xBSU1fRU5EOidyZWNsYWltRW5kJyxBQ0s6J2FjaycsQkFUQ0hfUVVFVUU6J2JhdGNoUXVldWUnfTtcblxuY29uc3QgQkVBQ09OX1BMVUdJTl9FVkVOVFNfUVVFVUVfREVCVUc9Y29udGV4dD0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1TZW5kaW5nIGV2ZW50cyB0byBkYXRhIHBsYW5lLmA7Y29uc3QgQkVBQ09OX1FVRVVFX1NUUklOR19DT05WRVJTSU9OX0ZBSUxVUkVfRVJST1I9Y29udGV4dD0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1GYWlsZWQgdG8gY29udmVydCBldmVudHMgYmF0Y2ggb2JqZWN0IHRvIHN0cmluZy5gO2NvbnN0IEJFQUNPTl9RVUVVRV9CTE9CX0NPTlZFUlNJT05fRkFJTFVSRV9FUlJPUj1jb250ZXh0PT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfUZhaWxlZCB0byBjb252ZXJ0IGV2ZW50cyBiYXRjaCBvYmplY3QgdG8gQmxvYi5gO2NvbnN0IEJFQUNPTl9RVUVVRV9TRU5EX0VSUk9SPShjb250ZXh0LHVybCk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9JHtCRUFDT05fUVVFVUVfREVMSVZFUllfRVJST1IodXJsKX1gO2NvbnN0IEJFQUNPTl9RVUVVRV9ERUxJVkVSWV9FUlJPUj11cmw9PmBGYWlsZWQgdG8gc2VuZCBldmVudHMgYmF0Y2ggZGF0YSB0byB0aGUgYnJvd3NlcidzIGJlYWNvbiBxdWV1ZSBmb3IgVVJMICR7dXJsfS5gO1xuXG5jb25zdCBERUZBVUxUX0JFQUNPTl9RVUVVRV9NQVhfU0laRT0xMDtjb25zdCBERUZBVUxUX0JFQUNPTl9RVUVVRV9GTFVTSF9JTlRFUlZBTF9NUz0xMCo2MCoxMDAwOy8vIDEwIG1pbnV0ZXNcbi8vIExpbWl0IG9mIHRoZSBCZWFjb24gdHJhbnNmZXIgbWVjaGFuaXNtIG9uIHRoZSBicm93c2Vyc1xuY29uc3QgTUFYX0JBVENIX1BBWUxPQURfU0laRV9CWVRFUz02NCoxMDI0Oy8vIDY0IEtCXG5jb25zdCBERUZBVUxUX0JFQUNPTl9RVUVVRV9PUFRJT05TPXttYXhJdGVtczpERUZBVUxUX0JFQUNPTl9RVUVVRV9NQVhfU0laRSxmbHVzaFF1ZXVlSW50ZXJ2YWw6REVGQVVMVF9CRUFDT05fUVVFVUVfRkxVU0hfSU5URVJWQUxfTVN9O2NvbnN0IERBVEFfUExBTkVfQVBJX1ZFUlNJT04kMT0ndjEnO2NvbnN0IFFVRVVFX05BTUUkMz0ncnVkZGVyX2JlYWNvbic7Y29uc3QgQkVBQ09OX1FVRVVFX1BMVUdJTj0nQmVhY29uUXVldWVQbHVnaW4nO1xuXG4vKipcbiAqIFV0aWxpdHkgdG8gZ2V0IHRoZSBzdHJpbmdpZmllZCBldmVudCBwYXlsb2FkIGFzIEJsb2JcbiAqIEBwYXJhbSBldmVudHMgUnVkZGVyRXZlbnQgb2JqZWN0IGFycmF5XG4gKiBAcGFyYW0gbG9nZ2VyIExvZ2dlciBpbnN0YW5jZVxuICogQHJldHVybnMgc3RyaW5naWZpZWQgZXZlbnRzIHBheWxvYWQgYXMgQmxvYiwgdW5kZWZpbmVkIGlmIGVycm9yIG9jY3Vycy5cbiAqL2NvbnN0IGdldEJhdGNoRGVsaXZlcnlQYXlsb2FkJDE9KGV2ZW50cyxjdXJyZW50VGltZSxsb2dnZXIpPT57Y29uc3QgZGF0YT17YmF0Y2g6ZXZlbnRzLHNlbnRBdDpjdXJyZW50VGltZX07dHJ5e2NvbnN0IGJsb2JQYXlsb2FkPXN0cmluZ2lmeVdpdGhvdXRDaXJjdWxhcihkYXRhLHRydWUpO2NvbnN0IGJsb2JPcHRpb25zPXt0eXBlOid0ZXh0L3BsYWluJ307aWYoYmxvYlBheWxvYWQpe3JldHVybiBuZXcgQmxvYihbYmxvYlBheWxvYWRdLGJsb2JPcHRpb25zKTt9bG9nZ2VyPy5lcnJvcihCRUFDT05fUVVFVUVfU1RSSU5HX0NPTlZFUlNJT05fRkFJTFVSRV9FUlJPUihCRUFDT05fUVVFVUVfUExVR0lOKSk7fWNhdGNoKGVycil7bG9nZ2VyPy5lcnJvcihCRUFDT05fUVVFVUVfQkxPQl9DT05WRVJTSU9OX0ZBSUxVUkVfRVJST1IoQkVBQ09OX1FVRVVFX1BMVUdJTiksZXJyKTt9cmV0dXJuIHVuZGVmaW5lZDt9O2NvbnN0IGdldE5vcm1hbGl6ZWRCZWFjb25RdWV1ZU9wdGlvbnM9cXVldWVPcHRzPT5tZXJnZURlZXBSaWdodChERUZBVUxUX0JFQUNPTl9RVUVVRV9PUFRJT05TLHF1ZXVlT3B0cyk7Y29uc3QgZ2V0RGVsaXZlcnlVcmwkMT0oZGF0YXBsYW5lVXJsLHdyaXRlS2V5KT0+e2NvbnN0IGRwVXJsPW5ldyBVUkwoZGF0YXBsYW5lVXJsKTtyZXR1cm4gbmV3IFVSTChyZW1vdmVEdXBsaWNhdGVTbGFzaGVzKFtkcFVybC5wYXRobmFtZSwnLycsJ2JlYWNvbicsJy8nLERBVEFfUExBTkVfQVBJX1ZFUlNJT04kMSwnLycsYGJhdGNoP3dyaXRlS2V5PSR7d3JpdGVLZXl9YF0uam9pbignJykpLGRwVXJsKS5ocmVmO307XG5cbmxldCBTY2hlZHVsZU1vZGVzPS8qI19fUFVSRV9fKi9mdW5jdGlvbihTY2hlZHVsZU1vZGVzKXtTY2hlZHVsZU1vZGVzW1NjaGVkdWxlTW9kZXNbXCJBU0FQXCJdPTFdPVwiQVNBUFwiO1NjaGVkdWxlTW9kZXNbU2NoZWR1bGVNb2Rlc1tcIlJFU0NIRURVTEVcIl09Ml09XCJSRVNDSEVEVUxFXCI7U2NoZWR1bGVNb2Rlc1tTY2hlZHVsZU1vZGVzW1wiQUJBTkRPTlwiXT0zXT1cIkFCQU5ET05cIjtyZXR1cm4gU2NoZWR1bGVNb2Rlczt9KHt9KTtjb25zdCBERUZBVUxUX0NMT0NLX0xBVEVfRkFDVE9SPTI7Y29uc3QgREVGQVVMVF9DTE9DSz17c2V0VGltZW91dChmbixtcyl7cmV0dXJuIGdsb2JhbFRoaXMuc2V0VGltZW91dChmbixtcyk7fSxjbGVhclRpbWVvdXQoaWQpe3JldHVybiBnbG9iYWxUaGlzLmNsZWFyVGltZW91dChpZCk7fSxEYXRlOmdsb2JhbFRoaXMuRGF0ZSxjbG9ja0xhdGVGYWN0b3I6REVGQVVMVF9DTE9DS19MQVRFX0ZBQ1RPUn07Y2xhc3MgU2NoZWR1bGV7Y29uc3RydWN0b3IoKXt0aGlzLnRhc2tzPXt9O3RoaXMubmV4dElkPTE7dGhpcy5jbG9jaz1ERUZBVUxUX0NMT0NLO31ub3coKXtyZXR1cm4gK25ldyB0aGlzLmNsb2NrLkRhdGUoKTt9cnVuKHRhc2ssdGltZW91dCxtb2RlKXtpZih0aGlzLm5leHRJZD09PU51bWJlci5NQVhfU0FGRV9JTlRFR0VSKXt0aGlzLm5leHRJZD0xO31jb25zdCBpZD0odGhpcy5uZXh0SWQrKykudG9TdHJpbmcoKTt0aGlzLnRhc2tzW2lkXT10aGlzLmNsb2NrLnNldFRpbWVvdXQodGhpcy5oYW5kbGUoaWQsdGFzayx0aW1lb3V0LG1vZGV8fFNjaGVkdWxlTW9kZXMuQVNBUCksdGltZW91dCk7cmV0dXJuIGlkO31oYW5kbGUoaWQsY2FsbGJhY2ssdGltZW91dCxtb2RlKXtjb25zdCBzdGFydD10aGlzLm5vdygpO3JldHVybiAoKT0+e2RlbGV0ZSB0aGlzLnRhc2tzW2lkXTtjb25zdCBlbGFwc2VkVGltZW91dFRpbWU9c3RhcnQrdGltZW91dCoodGhpcy5jbG9jay5jbG9ja0xhdGVGYWN0b3J8fERFRkFVTFRfQ0xPQ0tfTEFURV9GQUNUT1IpO2NvbnN0IGN1cnJlbnRUaW1lPXRoaXMubm93KCk7Y29uc3Qgbm90Q29tcGxldGVkT3JUaW1lZE91dD1tb2RlPj1TY2hlZHVsZU1vZGVzLlJFU0NIRURVTEUmJmVsYXBzZWRUaW1lb3V0VGltZTxjdXJyZW50VGltZTtpZihub3RDb21wbGV0ZWRPclRpbWVkT3V0KXtpZihtb2RlPT09U2NoZWR1bGVNb2Rlcy5SRVNDSEVEVUxFKXt0aGlzLnJ1bihjYWxsYmFjayx0aW1lb3V0LG1vZGUpO31yZXR1cm4gdW5kZWZpbmVkO31yZXR1cm4gY2FsbGJhY2soKTt9O31jYW5jZWwoaWQpe2lmKHRoaXMudGFza3NbaWRdKXt0aGlzLmNsb2NrLmNsZWFyVGltZW91dCh0aGlzLnRhc2tzW2lkXSk7ZGVsZXRlIHRoaXMudGFza3NbaWRdO319Y2FuY2VsQWxsKCl7T2JqZWN0LnZhbHVlcyh0aGlzLnRhc2tzKS5mb3JFYWNoKHRoaXMuY2xvY2suY2xlYXJUaW1lb3V0KTt0aGlzLnRhc2tzPXt9O319XG5cbmNvbnN0IFJFVFJZX1FVRVVFX1BST0NFU1NfRVJST1I9KGNvbnRleHQsZXJyTXNnKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1BbiB1bmtub3duIGVycm9yIG9jY3VycmVkIHdoaWxlIHByb2Nlc3NpbmcgdGhlIHF1ZXVlIGl0ZW0uICR7ZXJyTXNnfWA7Y29uc3QgUkVUUllfUVVFVUVfRU5UUllfUkVNT1ZFX0VSUk9SPShjb250ZXh0LGVudHJ5LGF0dGVtcHQpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfUZhaWxlZCB0byByZW1vdmUgbG9jYWwgc3RvcmFnZSBlbnRyeSBcIiR7ZW50cnl9XCIgKGF0dGVtcHQ6ICR7YXR0ZW1wdH0uYDtcblxuY29uc3QgREVGQVVMVF9NSU5fUkVUUllfREVMQVlfTVM9MTAwMDtjb25zdCBERUZBVUxUX01BWF9SRVRSWV9ERUxBWV9NUz0zMDAwMDtjb25zdCBERUZBVUxUX0JBQ0tPRkZfRkFDVE9SPTI7Y29uc3QgREVGQVVMVF9CQUNLT0ZGX0pJVFRFUj0wO2NvbnN0IERFRkFVTFRfTUFYX1JFVFJZX0FUVEVNUFRTPUluZmluaXR5O2NvbnN0IERFRkFVTFRfTUFYX0lURU1TPUluZmluaXR5O2NvbnN0IERFRkFVTFRfQUNLX1RJTUVSX01TPTEwMDA7Y29uc3QgREVGQVVMVF9SRUNMQUlNX1RJTUVSX01TPTMwMDA7Y29uc3QgREVGQVVMVF9SRUNMQUlNX1RJTUVPVVRfTVM9MTAwMDA7Y29uc3QgREVGQVVMVF9SRUNMQUlNX1dBSVRfTVM9NTAwO2NvbnN0IE1JTl9USU1FUl9TQ0FMRV9GQUNUT1I9MTtjb25zdCBNQVhfVElNRVJfU0NBTEVfRkFDVE9SPTEwO2NvbnN0IERFRkFVTFRfTUFYX0JBVENIX1NJWkVfQllURVM9NTEyKjEwMjQ7Ly8gNTEyIEtCOyB0aGlzIGlzIGFsc28gdGhlIG1heCBzaXplIG9mIGEgYmF0Y2hcbmNvbnN0IERFRkFVTFRfTUFYX0JBVENIX0lURU1TPTEwMDtjb25zdCBERUZBVUxUX0JBVENIX0ZMVVNIX0lOVEVSVkFMX01TPTYwKjEwMDA7Ly8gMSBtaW51dGVzXG5jb25zdCBCQVRDSF9RVUVVRV9JVEVNX1RZUEU9J0JhdGNoJztjb25zdCBTSU5HTEVfUVVFVUVfSVRFTV9UWVBFPSdTaW5nbGUnO1xuXG5jb25zdCBzb3J0QnlUaW1lPShhLGIpPT5hLnRpbWUtYi50aW1lO2NvbnN0IFJFVFJZX1FVRVVFPSdSZXRyeVF1ZXVlJztjbGFzcyBSZXRyeVF1ZXVley8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgUmV0cnlRdWV1ZSBiYWNrZWQgYnkgbG9jYWxTdG9yYWdlXG4gICAqXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIFRoZSBuYW1lIG9mIHRoZSBxdWV1ZS4gV2lsbCBiZSB1c2VkIHRvIGZpbmQgYWJhbmRvbmVkIHF1ZXVlcyBhbmQgcmV0cnkgdGhlaXIgaXRlbXNcbiAgICogQHBhcmFtIHtRdWV1ZU9wdHN9IFtvcHRpb25zXSBPcHRpb25hbCBhcmd1bWVudCB0byBvdmVycmlkZSBgbWF4SXRlbXNgLCBgbWF4QXR0ZW1wdHNgLCBgbWluUmV0cnlEZWxheSwgYG1heFJldHJ5RGVsYXlgLCBgYmFja29mZkZhY3RvcmAgYW5kIGBiYWNrb2ZmSml0dGVyYC5cbiAgICogQHBhcmFtIHtRdWV1ZVByb2Nlc3NDYWxsYmFja30gcXVldWVQcm9jZXNzQ2IgVGhlIGZ1bmN0aW9uIHRvIGNhbGwgaW4gb3JkZXIgdG8gcHJvY2VzcyBhbiBpdGVtIGFkZGVkIHRvIHRoZSBxdWV1ZVxuICAgKiBAcGFyYW0ge0lTdG9yZU1hbmFnZXJ9IHN0b3JlTWFuYWdlciBUaGUgc3RvcmUgbWFuYWdlciBpbnN0YW5jZSB0byB1c2VcbiAgICogQHBhcmFtIHtTdG9yYWdlVHlwZX0gW3N0b3JhZ2VUeXBlXSBUaGUgc3RvcmFnZSB0eXBlIHRvIHVzZS4gRGVmYXVsdHMgdG8gTE9DQUxfU1RPUkFHRVxuICAgKiBAcGFyYW0ge0lMb2dnZXJ9IFtsb2dnZXJdIFRoZSBsb2dnZXIgdG8gdXNlXG4gICAqIEBwYXJhbSB7UXVldWVCYXRjaEl0ZW1zU2l6ZUNhbGN1bGF0b3JDYWxsYmFja30gW3F1ZXVlQmF0Y2hJdGVtc1NpemVDYWxjdWxhdG9yQ2JdIFRoZSBjYWxsYmFjayB0byB1c2UgdG8gY2FsY3VsYXRlIHRoZSBzaXplIG9mIGl0ZW1zIGluIHRoZSBiYXRjaCBxdW
1V1ZVxuICAgKi9jb25zdHJ1Y3RvcihuYW1lLG9wdGlvbnMscXVldWVQcm9jZXNzQ2Isc3RvcmVNYW5hZ2VyLHN0b3JhZ2VUeXBlPUxPQ0FMX1NUT1JBR0UsbG9nZ2VyLHF1ZXVlQmF0Y2hJdGVtc1NpemVDYWxjdWxhdG9yQ2Ipe3RoaXMuc3RvcmVNYW5hZ2VyPXN0b3JlTWFuYWdlcjt0aGlzLmxvZ2dlcj1sb2dnZXI7dGhpcy5uYW1lPW5hbWU7dGhpcy5pZD1nZW5lcmF0ZVVVSUQoKTt0aGlzLnByb2Nlc3NRdWV1ZUNiPXF1ZXVlUHJvY2Vzc0NiO3RoaXMuYmF0Y2hTaXplQ2FsY0NiPXF1ZXVlQmF0Y2hJdGVtc1NpemVDYWxjdWxhdG9yQ2I7dGhpcy5tYXhJdGVtcz1vcHRpb25zLm1heEl0ZW1zfHxERUZBVUxUX01BWF9JVEVNUzt0aGlzLm1heEF0dGVtcHRzPW9wdGlvbnMubWF4QXR0ZW1wdHN8fERFRkFVTFRfTUFYX1JFVFJZX0FUVEVNUFRTO3RoaXMuYmF0Y2g9e2VuYWJsZWQ6ZmFsc2V9O3RoaXMuY29uZmlndXJlQmF0Y2hNb2RlKG9wdGlvbnMpO3RoaXMuYmFja29mZj17bWluUmV0cnlEZWxheTpvcHRpb25zLm1pblJldHJ5RGVsYXl8fERFRkFVTFRfTUlOX1JFVFJZX0RFTEFZX01TLG1heFJldHJ5RGVsYXk6b3B0aW9ucy5tYXhSZXRyeURlbGF5fHxERUZBVUxUX01BWF9SRVRSWV9ERUxBWV9NUyxmYWN0b3I6b3B0aW9ucy5iYWNrb2ZmRmFjdG9yfHxERUZBVUxUX0JBQ0tPRkZfRkFDVE9SLGppdHRlcjpvcHRpb25zLmJhY2tvZmZKaXR0ZXJ8fERFRkFVTFRfQkFDS09GRl9KSVRURVJ9Oy8vIExpbWl0IHRoZSB0aW1lciBzY2FsZSBmYWN0b3IgdG8gdGhlIG1pbmltdW0gdmFsdWVcbmxldCB0aW1lclNjYWxlRmFjdG9yPU1hdGgubWF4KG9wdGlvbnMudGltZXJTY2FsZUZhY3Rvcj8/TUlOX1RJTUVSX1NDQUxFX0ZBQ1RPUixNSU5fVElNRVJfU0NBTEVfRkFDVE9SKTsvLyBMaW1pdCB0aGUgdGltZXIgc2NhbGUgZmFjdG9yIHRvIHRoZSBtYXhpbXVtIHZhbHVlXG50aW1lclNjYWxlRmFjdG9yPU1hdGgubWluKHRpbWVyU2NhbGVGYWN0b3IsTUFYX1RJTUVSX1NDQUxFX0ZBQ1RPUik7Ly8gcGFpbnN0YWtpbmdseSB0dW5lZC4gdGhhdCdzIHdoeSB0aGV5J3JlIG5vdCBcImVhc2lseVwiIGNvbmZpZ3VyYWJsZVxudGhpcy50aW1lb3V0cz17YWNrVGltZXI6TWF0aC5yb3VuZCh0aW1lclNjYWxlRmFjdG9yKkRFRkFVTFRfQUNLX1RJTUVSX01TKSxyZWNsYWltVGltZXI6TWF0aC5yb3VuZCh0aW1lclNjYWxlRmFjdG9yKkRFRkFVTFRfUkVDTEFJTV9USU1FUl9NUykscmVjbGFpbVRpbWVvdXQ6TWF0aC5yb3VuZCh0aW1lclNjYWxlRmFjdG9yKkRFRkFVTFRfUkVDTEFJTV9USU1FT1VUX01TKSxyZWNsYWltV2FpdDpNYXRoLnJvdW5kKHRpbWVyU2NhbGVGYWN0b3IqREVGQVVMVF9SRUNMQUlNX1dBSVRfTVMpfTt0aGlzLnNjaGVkdWxlPW5ldyBTY2hlZHVsZSgpO3RoaXMucHJvY2Vzc0lkPScwJzsvLyBTZXQgdXAgb3VyIGVtcHR5IHF1ZXVlc1xudGhpcy5zdG9yZT10aGlzLnN0b3JlTWFuYWdlci5zZXRTdG9yZSh7aWQ6dGhpcy5pZCxuYW1lOnRoaXMubmFtZSx2YWxpZEtleXM6UXVldWVTdGF0dXNlcyx0eXBlOnN0b3JhZ2VUeXBlLGVycm9ySGFuZGxlcjp0aGlzLnN0b3JlTWFuYWdlci5lcnJvckhhbmRsZXIsbG9nZ2VyOnRoaXMuc3RvcmVNYW5hZ2VyLmxvZ2dlcn0pO3RoaXMuc2V0RGVmYXVsdFF1ZXVlRW50cmllcygpOy8vIGJpbmQgcmVjdXJyaW5nIHRhc2tzIGZvciBlYXNlIG9mIHVzZVxudGhpcy5hY2s9dGhpcy5hY2suYmluZCh0aGlzKTt0aGlzLmNoZWNrUmVjbGFpbT10aGlzLmNoZWNrUmVjbGFpbS5iaW5kKHRoaXMpO3RoaXMucHJvY2Vzc0hlYWQ9dGhpcy5wcm9jZXNzSGVhZC5iaW5kKHRoaXMpO3RoaXMuZmx1c2hCYXRjaD10aGlzLmZsdXNoQmF0Y2guYmluZCh0aGlzKTt0aGlzLmlzUGFnZUFjY2Vzc2libGU9dHJ1ZTsvLyBGbHVzaCB0aGUgcXVldWUgb24gcGFnZSBsZWF2ZVxudGhpcy5mbHVzaEJhdGNoT25QYWdlTGVhdmUoKTt0aGlzLnNjaGVkdWxlVGltZW91dEFjdGl2ZT1mYWxzZTt9c2V0RGVmYXVsdFF1ZXVlRW50cmllcygpe3RoaXMuc2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuSU5fUFJPR1JFU1Mse30pO3RoaXMuc2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuUVVFVUUsW10pO3RoaXMuc2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuQkFUQ0hfUVVFVUUsW10pO31jb25maWd1cmVCYXRjaE1vZGUob3B0aW9ucyl7dGhpcy5iYXRjaGluZ0luUHJvZ3Jlc3M9ZmFsc2U7aWYoIWlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwob3B0aW9ucy5iYXRjaCkpe3JldHVybjt9Y29uc3QgYmF0Y2hPcHRpb25zPW9wdGlvbnMuYmF0Y2g7dGhpcy5iYXRjaC5lbmFibGVkPWJhdGNoT3B0aW9ucy5lbmFibGVkPT09dHJ1ZTtpZih0aGlzLmJhdGNoLmVuYWJsZWQpey8vIFNldCB1cHBlciBjYXAgb24gdGhlIGJhdGNoIHBheWxvYWQgc2l6ZVxudGhpcy5iYXRjaC5tYXhTaXplPU1hdGgubWluKGJhdGNoT3B0aW9ucy5tYXhTaXplPz9ERUZBVUxUX01BWF9CQVRDSF9TSVpFX0JZVEVTLERFRkFVTFRfTUFYX0JBVENIX1NJWkVfQllURVMpO3RoaXMuYmF0Y2gubWF4SXRlbXM9YmF0Y2hPcHRpb25zLm1heEl0ZW1zPz9ERUZBVUxUX01BWF9CQVRDSF9JVEVNUzt0aGlzLmJhdGNoLmZsdXNoSW50ZXJ2YWw9YmF0Y2hPcHRpb25zLmZsdXNoSW50ZXJ2YWw/P0RFRkFVTFRfQkFUQ0hfRkxVU0hfSU5URVJWQUxfTVM7fX1mbHVzaEJhdGNoT25QYWdlTGVhdmUoKXtpZih0aGlzLmJhdGNoLmVuYWJsZWQpe29uUGFnZUxlYXZlKHRoaXMuZmx1c2hCYXRjaCk7fX1nZXRTdG9yYWdlRW50cnkobmFtZSl7cmV0dXJuIHRoaXMuc3RvcmUuZ2V0KG5hbWUpO30vLyBUT0RPOiBmaXggdGhlIHR5cGUgb2YgZGlmZmVyZW50IHF1ZXVlcyB0byBiZSB0aGUgc2FtZSBpZiBwb3NzaWJsZVxuc2V0U3RvcmFnZUVudHJ5KG5hbWUsdmFsdWUpe2lmKGlzTnVsbE9yVW5kZWZpbmVkKHZhbHVlKSl7dGhpcy5zdG9yZS5yZW1vdmUobmFtZSk7fWVsc2Uge3RoaXMuc3RvcmUuc2V0KG5hbWUsdmFsdWUpO319LyoqXG4gICAqIFN0b3BzIHByb2Nlc3NpbmcgdGhlIHF1ZXVlXG4gICAqL3N0b3AoKXt0aGlzLnNjaGVkdWxlLmNhbmNlbEFsbCgpO3RoaXMuc2NoZWR1bGVUaW1lb3V0QWN0aXZlPWZhbHNlO30vKipcbiAgICogU3RhcnRzIHByb2Nlc3NpbmcgdGhlIHF1ZXVlXG4gICAqL3N0YXJ0KCl7aWYodGhpcy5zY2hlZHVsZVRpbWVvdXRBY3RpdmUpe3RoaXMuc3RvcCgpO310aGlzLnNjaGVkdWxlVGltZW91dEFjdGl2ZT10cnVlO3RoaXMuc2NoZWR1bGVGbHVzaEJhdGNoKCk7dGhpcy5hY2soKTt0aGlzLmNoZWNrUmVjbGFpbSgpO3RoaXMucHJvY2Vzc0hlYWQoKTt9LyoqXG4gICAqIENvbmZpZ3VyZXMgdGhlIHRpbWVvdXQgaGFuZGxlciBmb3IgZmx1c2hpbmcgdGhlIGJhdGNoIHF1ZXVlXG4gICAqL3NjaGVkdWxlRmx1c2hCYXRjaCgpe2lmKHRoaXMuYmF0Y2guZW5hYmxlZCYmdGhpcy5iYXRja
1D8uZmx1c2hJbnRlcnZhbCl7aWYodGhpcy5mbHVzaEJhdGNoVGFza0lkKXt0aGlzLnNjaGVkdWxlLmNhbmNlbCh0aGlzLmZsdXNoQmF0Y2hUYXNrSWQpO310aGlzLmZsdXNoQmF0Y2hUYXNrSWQ9dGhpcy5zY2hlZHVsZS5ydW4odGhpcy5mbHVzaEJhdGNoLHRoaXMuYmF0Y2guZmx1c2hJbnRlcnZhbCxTY2hlZHVsZU1vZGVzLkFTQVApO319LyoqXG4gICAqIEZsdXNoZXMgdGhlIGJhdGNoIHF1ZXVlXG4gICAqL2ZsdXNoQmF0Y2goaXNBY2Nlc3NpYmxlPXRydWUpe2lmKCF0aGlzLmJhdGNoaW5nSW5Qcm9ncmVzcyl7dGhpcy5pc1BhZ2VBY2Nlc3NpYmxlPWlzQWNjZXNzaWJsZTt0aGlzLmJhdGNoaW5nSW5Qcm9ncmVzcz10cnVlO2xldCBiYXRjaFF1ZXVlPXRoaXMuZ2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuQkFUQ0hfUVVFVUUpPz9bXTtpZihiYXRjaFF1ZXVlLmxlbmd0aD4wKXtiYXRjaFF1ZXVlPWJhdGNoUXVldWUuc2xpY2UoLWJhdGNoUXVldWUubGVuZ3RoKTtjb25zdCBiYXRjaEVudHJ5PXRoaXMuZ2VuUXVldWVJdGVtKGJhdGNoUXVldWUubWFwKHF1ZXVlSXRlbT0+cXVldWVJdGVtLml0ZW0pLEJBVENIX1FVRVVFX0lURU1fVFlQRSk7dGhpcy5zZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5CQVRDSF9RVUVVRSxbXSk7dGhpcy5wdXNoVG9NYWluUXVldWUoYmF0Y2hFbnRyeSk7fXRoaXMuYmF0Y2hpbmdJblByb2dyZXNzPWZhbHNlOy8vIFJlLXNjaGVkdWxlIHRoZSBmbHVzaCB0YXNrXG50aGlzLnNjaGVkdWxlRmx1c2hCYXRjaCgpO319LyoqXG4gICAqIERlY2lkZXMgd2hldGhlciB0byByZXRyeS4gT3ZlcnJpZGFibGUuXG4gICAqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIFRoZSBpdGVtIGJlaW5nIHByb2Nlc3NlZFxuICAgKiBAcGFyYW0ge051bWJlcn0gYXR0ZW1wdE51bWJlciBUaGUgYXR0ZW1wdE51bWJlciAoMSBmb3IgZmlyc3QgcmV0cnkpXG4gICAqIEByZXR1cm4ge0Jvb2xlYW59IFdoZXRoZXIgdG8gcmVxdWV1ZSB0aGUgbWVzc2FnZVxuICAgKi9zaG91bGRSZXRyeShpdGVtLGF0dGVtcHROdW1iZXIpe3JldHVybiBhdHRlbXB0TnVtYmVyPD10aGlzLm1heEF0dGVtcHRzO30vKipcbiAgICogQ2FsY3VsYXRlcyB0aGUgZGVsYXkgKGluIG1zKSBmb3IgYSByZXRyeSBhdHRlbXB0XG4gICAqXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBhdHRlbXB0TnVtYmVyIFRoZSBhdHRlbXB0TnVtYmVyICgxIGZvciBmaXJzdCByZXRyeSlcbiAgICogQHJldHVybiB7TnVtYmVyfSBUaGUgZGVsYXkgaW4gbWlsbGlzZWNvbmRzIHRvIHdhaXQgYmVmb3JlIGF0dGVtcHRpbmcgYSByZXRyeVxuICAgKi9nZXREZWxheShhdHRlbXB0TnVtYmVyKXtsZXQgbXM9dGhpcy5iYWNrb2ZmLm1pblJldHJ5RGVsYXkqdGhpcy5iYWNrb2ZmLmZhY3RvcioqYXR0ZW1wdE51bWJlcjtpZih0aGlzLmJhY2tvZmYuaml0dGVyKXtjb25zdCByYW5kPU1hdGgucmFuZG9tKCk7Y29uc3QgZGV2aWF0aW9uPU1hdGguZmxvb3IocmFuZCp0aGlzLmJhY2tvZmYuaml0dGVyKm1zKTtpZihNYXRoLmZsb29yKHJhbmQqMTApPDUpe21zLT1kZXZpYXRpb247fWVsc2Uge21zKz1kZXZpYXRpb247fX1yZXR1cm4gTnVtYmVyKE1hdGgubWluKG1zLHRoaXMuYmFja29mZi5tYXhSZXRyeURlbGF5KS50b1ByZWNpc2lvbigxKSk7fWVucXVldWUoZW50cnkpe2xldCBjdXJFbnRyeTtpZih0aGlzLmJhdGNoLmVuYWJsZWQmJmVudHJ5LnR5cGU9PT1TSU5HTEVfUVVFVUVfSVRFTV9UWVBFKXtjdXJFbnRyeT10aGlzLmhhbmRsZU5ld0l0ZW1Gb3JCYXRjaChlbnRyeSk7fWVsc2Uge2N1ckVudHJ5PWVudHJ5O30vLyB3aGVuIGJhdGNoaW5nIGlzIGVuYWJsZWQsIGBjdXJFbnRyeWAgY291bGQgYmUgYHVuZGVmaW5lZGAgaWYgdGhlIGJhdGNoIGNyaXRlcmlhIGlzIG5vdCBtZXRcbmlmKGN1ckVudHJ5KXt0aGlzLnB1c2hUb01haW5RdWV1ZShjdXJFbnRyeSk7fX0vKipcbiAgICogSGFuZGxlcyBhIG5ldyBpdGVtIGFkZGVkIHRvIHRoZSByZXRyeSBxdWV1ZSB3aGVuIGJhdGNoaW5nIGlzIGVuYWJsZWRcbiAgICogQHBhcmFtIGVudHJ5IE5ldyBpdGVtIGFkZGVkIHRvIHRoZSByZXRyeSBxdWV1ZVxuICAgKiBAcmV0dXJucyBVbmRlZmluZWQgb3IgYmF0Y2ggZW50cnkgb2JqZWN0XG4gICAqL2hhbmRsZU5ld0l0ZW1Gb3JCYXRjaChlbnRyeSl7bGV0IGN1ckVudHJ5O2xldCBiYXRjaFF1ZXVlPXRoaXMuZ2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuQkFUQ0hfUVVFVUUpPz9bXTtpZighdGhpcy5iYXRjaGluZ0luUHJvZ3Jlc3Mpe3RoaXMuYmF0Y2hpbmdJblByb2dyZXNzPXRydWU7YmF0Y2hRdWV1ZT1iYXRjaFF1ZXVlLnNsaWNlKC1iYXRjaFF1ZXVlLmxlbmd0aCk7YmF0Y2hRdWV1ZS5wdXNoKGVudHJ5KTtjb25zdCBiYXRjaERpc3BhdGNoSW5mbz10aGlzLmdldEJhdGNoRGlzcGF0Y2hJbmZvKGJhdGNoUXVldWUpOy8vIGlmIGJhdGNoIGNyaXRlcmlhIGlzIG1ldCwgcXVldWUgdGhlIGJhdGNoIGV2ZW50cyB0byB0aGUgbWFpbiBxdWV1ZSBhbmQgY2xlYXIgYmF0Y2ggcXVldWVcbmlmKGJhdGNoRGlzcGF0Y2hJbmZvLmNyaXRlcmlhTWV0fHxiYXRjaERpc3BhdGNoSW5mby5jcml0ZXJpYUV4Y2VlZGVkKXtsZXQgYmF0Y2hFbnRyaWVzO2lmKGJhdGNoRGlzcGF0Y2hJbmZvLmNyaXRlcmlhRXhjZWVkZWQpe2JhdGNoRW50cmllcz1iYXRjaFF1ZXVlLnNsaWNlKDAsYmF0Y2hRdWV1ZS5sZW5ndGgtMSk7YmF0Y2hRdWV1ZT1bZW50cnldO31lbHNlIHtiYXRjaEVudHJpZXM9YmF0Y2hRdWV1ZTtiYXRjaFF1ZXVlPVtdO30vLyBEb24ndCBtYWtlIGFueSBiYXRjaCByZXF1ZXN0IGlmIHRoZXJlIGFyZSBubyBpdGVtc1xuaWYoYmF0Y2hFbnRyaWVzLmxlbmd0aD4wKXtjb25zdCBpc1JlY2xhaW1lZD1iYXRjaEVudHJpZXMuZXZlcnkocXVldWVJdGVtPT5xdWV1ZUl0ZW0ucmVjbGFpbWVkKTtjb25zdCBiYXRjaEl0ZW1zPWJhdGNoRW50cmllcy5tYXAocXVldWVJdGVtPT5xdWV1ZUl0ZW0uaXRlbSk7aWYoaXNSZWNsYWltZWQpe2N1ckVudHJ5PXRoaXMuZ2VuUXVldWVJdGVtKGJhdGNoSXRlbXMsQkFUQ0hfUVVFVUVfSVRFTV9UWVBFLHRydWUpO31lbHNlIHtjdXJFbnRyeT10aGlzLmdlblF1ZXVlSXRlbShiYXRjaEl0ZW1zLEJBVENIX1FVRVVFX0lURU1fVFlQRSk7fX0vLyByZS1hdHRhY2ggdGhlIHRpbWVvdXQgaGFuZGxlclxudGhpcy5zY2hlZHVsZUZsdXNoQmF0Y2goKTt9dGhpcy5iYXRjaGluZ0luUHJvZ3Jlc3M9ZmFsc2U7fWVsc2Uge2JhdGNoUXVldWUucHVzaChlbnRyeSk7fS8vIHVwZGF0ZSB0aGUgYmF0Y2ggcXVldWVcbnRoaXMuc2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuQkFUQ0hfUVVFVUUsYmF0Y2hRdWV1ZSk7cmV0dXJuIGN1ckVudHJ5O31wdXNoVG9NYWluUXVldWUoY3VyRW50cnkpe2xldCBxdWV1ZT10aGlzLmdldFN0b3JhZ2VFbnRyeShRdWV1ZVN0YXR1c2VzLlFVRVVFKT8/W107aWYodGhpcy5tYXhJdGVtcz4xKXtxdWV1ZT1xdWV1ZS5zbGljZSgtKHRoaXMubWF4SXRlbXMtMSkpO31lbHNlIHtxdWV1ZT1bXTt9cXVldWUucHVzaChjdXJFbnRyeSk7cXVldWU9cXVldWUuc29ydChzb3J0QnlUaW1lKTt0aGlzLnNldFN0b3JhZ2VFbnRyeShRdWV1ZVN0YXR1c2VzLlFVRVVFLHF1ZXVlKTtpZih0aGlzLnNjaGVkdWxlVGltZW91dEFjdGl2ZSl7dGhpcy5wcm9jZXNzSGVhZCgpO319LyoqXG4gICAqIEFkZHMgYW4gaXRlbSB0byB0aGUgcXVldWVcbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IGl0ZW1EYXRhIFRoZSBpdGVtIHRvIHByb2Nlc3NcbiAgICovYWRkSXRlbShpdGVtRGF0YSl7dGhpcy5lbnF1ZXVlKHRoaXMuZ2VuUXVldWVJdGVtKGl0ZW
11EYXRhKSk7fS8qKlxuICAgKiBHZW5lcmF0ZXMgYSBxdWV1ZSBpdGVtXG4gICAqIEBwYXJhbSBpdGVtRGF0YSBRdWV1ZSBpdGVtIGRhdGFcbiAgICogQHJldHVybnMgUXVldWUgaXRlbVxuICAgKi9nZW5RdWV1ZUl0ZW0oaXRlbURhdGEsdHlwZT1TSU5HTEVfUVVFVUVfSVRFTV9UWVBFLHJlY2xhaW1lZCl7cmV0dXJuIHtpdGVtOml0ZW1EYXRhLGF0dGVtcHROdW1iZXI6MCx0aW1lOnRoaXMuc2NoZWR1bGUubm93KCksaWQ6Z2VuZXJhdGVVVUlEKCksdHlwZSwuLi4oaXNEZWZpbmVkKHJlY2xhaW1lZCk/e3JlY2xhaW1lZH06e30pfTt9LyoqXG4gICAqIEFkZHMgYW4gaXRlbSB0byB0aGUgcmV0cnkgcXVldWVcbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IHFJdGVtIFRoZSBpdGVtIHRvIHByb2Nlc3NcbiAgICovcmVxdWV1ZShxSXRlbSl7Y29uc3R7YXR0ZW1wdE51bWJlcixpdGVtLHR5cGUsaWQsZmlyc3RBdHRlbXB0ZWRBdCxsYXN0QXR0ZW1wdGVkQXQscmVjbGFpbWVkLHJldHJ5UmVhc29ufT1xSXRlbTsvLyBJbmNyZW1lbnQgdGhlIGF0dGVtcHQgbnVtYmVyIGFzIHdlJ3JlIGFib3V0IHRvIHJldHJ5XG5jb25zdCBhdHRlbXB0TnVtYmVyVG9Vc2U9YXR0ZW1wdE51bWJlcisxO2lmKHRoaXMuc2hvdWxkUmV0cnkoaXRlbSxhdHRlbXB0TnVtYmVyVG9Vc2UpKXt0aGlzLmVucXVldWUoe2l0ZW0sYXR0ZW1wdE51bWJlcjphdHRlbXB0TnVtYmVyVG9Vc2UsdGltZTp0aGlzLnNjaGVkdWxlLm5vdygpK3RoaXMuZ2V0RGVsYXkoYXR0ZW1wdE51bWJlclRvVXNlKSxpZDppZD8/Z2VuZXJhdGVVVUlEKCksdHlwZSxmaXJzdEF0dGVtcHRlZEF0LGxhc3RBdHRlbXB0ZWRBdCxyZWNsYWltZWQscmV0cnlSZWFzb259KTt9fS8qKlxuICAgKiBSZXR1cm5zIHRoZSBpbmZvcm1hdGlvbiBhYm91dCB3aGV0aGVyIHR
1oZSBiYXRjaCBjcml0ZXJpYSBpcyBtZXQgb3IgZXhjZWVkZWRcbiAgICogQHBhcmFtIGJhdGNoSXRlbXMgUHJvc3BlY3RpdmUgYmF0Y2ggaXRlbXNcbiAgICogQHJldHVybnMgQmF0Y2ggZGlzcGF0Y2ggaW5mb1xuICAgKi9nZXRCYXRjaERpc3BhdGNoSW5mbyhiYXRjaEl0ZW1zKXtsZXQgbGVuZ3RoQ3JpdGVyaWFNZXQ9ZmFsc2U7bGV0IGxlbmd0aENyaXRlcmlhRXhjZWVkZWQ9ZmFsc2U7Y29uc3QgY29uZmlndXJlZEJhdGNoTWF4SXRlbXM9dGhpcy5iYXRjaD8ubWF4SXRlbXM7aWYoaXNEZWZpbmVkKGNvbmZpZ3VyZWRCYXRjaE1heEl0ZW1zKSl7bGVuZ3RoQ3JpdGVyaWFNZXQ9YmF0Y2hJdGVtcy5sZW5ndGg9PT1jb25maWd1cmVkQmF0Y2hNYXhJdGVtcztsZW5ndGhDcml0ZXJpYUV4Y2VlZGVkPWJhdGNoSXRlbXMubGVuZ3RoPmNvbmZpZ3VyZWRCYXRjaE1heEl0ZW1zO31pZihsZW5ndGhDcml0ZXJpYU1ldHx8bGVuZ3RoQ3JpdGVyaWFFeGNlZWRlZCl7cmV0dXJuIHtjcml0ZXJpYU1ldDpsZW5ndGhDcml0ZXJpYU1ldCxjcml0ZXJpYUV4Y2VlZGVkOmxlbmd0aENyaXRlcmlhRXhjZWVkZWR9O31sZXQgc2l6ZUNyaXRlcmlhTWV0PWZhbHNlO2xldCBzaXplQ3JpdGVyaWFFeGNlZWRlZD1mYWxzZTtjb25zdCBjb25maWd1cmVkQmF0Y2hNYXhTaXplPXRoaXMuYmF0Y2g/Lm1heFNpemU7aWYoaXNEZWZpbmVkKGNvbmZpZ3VyZWRCYXRjaE1heFNpemUpJiZpc0RlZmluZWQodGhpcy5iYXRjaFNpemVDYWxjQ2IpKXtjb25zdCBjdXJCYXRjaFNpemU9dGhpcy5iYXRjaFNpemVDYWxjQ2IoYmF0Y2hJdGVtcy5tYXAocXVldWVJdGVtPT5xdWV1ZUl0ZW0uaXRlbSkpO3NpemVDcml0ZXJpYU1ldD1jdXJCYXRjaFNpemU9PT1jb25maWd1cmVkQmF0Y2hNYXhTaXplO3NpemVDcml0ZXJpYUV4Y2VlZGVkPWN1ckJhdGNoU2l6ZT5jb25maWd1cmVkQmF0Y2hNYXhTaXplO31yZXR1cm4ge2NyaXRlcmlhTWV0OnNpemVDcml0ZXJpYU1ldCxjcml0ZXJpYUV4Y2VlZGVkOnNpemVDcml0ZXJpYUV4Y2VlZGVkfTt9cHJvY2Vzc0hlYWQoKXsvLyBjYW5jZWwgdGhlIHNjaGVkdWxlZCB0YXNrIGlmIGl0IGV4aXN0c1xudGhpcy5zY2hlZHVsZS5jYW5jZWwodGhpcy5wcm9jZXNzSWQpOy8vIFBvcCB0aGUgaGVhZCBvZmYgdGhlIHF1ZXVlXG5sZXQgcXVldWU9dGhpcy5nZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5RVUVVRSk/P1tdO2NvbnN0IG5vdz10aGlzLnNjaGVkdWxlLm5vdygpO2NvbnN0IHRvUnVuPVtdOy8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbmNvbnN0IHByb2Nlc3NJdGVtQ2FsbGJhY2s9KGVsLGlkKT0+KGVycixyZXMpPT57Y29uc3QgaW5Qcm9ncmVzcz10aGlzLmdldFN0b3JhZ2VFbnRyeShRdWV1ZVN0YXR1c2VzLklOX1BST0dSRVNTKT8/e307Y29uc3QgaW5Qcm9ncmVzc0l0ZW09aW5Qcm9ncmVzc1tpZF07Y29uc3QgZmlyc3RBdHRlbXB0ZWRBdD1pblByb2dyZXNzSXRlbT8uZmlyc3RBdHRlbXB0ZWRBdDtjb25zdCBsYXN0QXR0ZW1wdGVkQXQ9aW5Qcm9ncmVzc0l0ZW0/Lmxhc3RBdHRlbXB0ZWRBdDtkZWxldGUgaW5Qcm9ncmVzc1tpZF07dGhpcy5zZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5JTl9QUk9HUkVTUyxpblByb2dyZXNzKTtpZihlcnIpe3RoaXMucmVxdWV1ZSh7Li4uZWwsZmlyc3RBdHRlbXB0ZWRBdCxsYXN0QXR0ZW1wdGVkQXQscmV0cnlSZWFzb246cmVzPy5yZXRyeVJlYXNvbj8/REVGQVVMVF9SRVRSWV9SRUFTT059KTt9fTtjb25zdCBlbnF1ZXVlSXRlbT0oZWwsaWQpPT57dG9SdW4ucHVzaCh7aWQsaXRlbTplbC5pdGVtLGRvbmU6cHJvY2Vzc0l0ZW1DYWxsYmFjayhlbCxpZCksYXR0ZW1wdE51bWJlcjplbC5hdHRlbXB0TnVtYmVyfSk7fTtjb25zdCBpblByb2dyZXNzPXRoaXMuZ2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuSU5fUFJPR1JFU1MpPz97fTtsZXQgaW5Qcm9ncmVzc1NpemU9T2JqZWN0LmtleXMoaW5Qcm9ncmVzcykubGVuZ3RoOy8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1wbHVzcGx1c1xud2hpbGUocXVldWUubGVuZ3RoPjAmJnF1ZXVlWzBdLnRpbWU8PW5vdyYmaW5Qcm9ncmVzc1NpemUrKzx0aGlzLm1heEl0ZW1zKXtjb25zdCBlbD1xdWV1ZS5zaGlmdCgpO2lmKGVsKXtjb25zdCBpZD1nZW5lcmF0ZVVVSUQoKTsvLyBTYXZlIHRoaXMgdG8gdGhlIGluIHByb2dyZXNzIG1hcFxuaW5Qcm9ncmVzc1tpZF09e2l0ZW06ZWwuaXRlbSxhdHRlbXB0TnVtYmVyOmVsLmF0dGVtcHROdW1iZXIsdGltZTp0aGlzLnNjaGVkdWxlLm5vdygpLHR5cGU6ZWwudHlwZSxmaXJzdEF0dGVtcHRlZEF0OmVsLmZpcnN0QXR0ZW1wdGVkQXQsbGFzdEF0dGVtcHRlZEF0OmVsLmxhc3RBdHRlbXB0ZWRBdCxyZWNsYWltZWQ6ZWwucmVjbGFpbWVkfTtlbnF1ZXVlSXRlbShlbCxpZCk7fX10aGlzLnNldFN0b3JhZ2VFbnRyeShRdWV1ZVN0YXR1c2VzLlFVRVVFLHF1ZXVlKTt0aGlzLnNldFN0b3JhZ2VFbnRyeShRdWV1ZVN0YXR1c2VzLklOX1BST0dSRVNTLGluUHJvZ3Jlc3MpO3RvUnVuLmZvckVhY2goZWw9PnsvLyBUT0RPOiBoYW5kbGUgcHJvY2Vzc1F1ZXVlQ2IgdGltZW91dFxudHJ5e2NvbnN0IG5vdz10aGlzLnNjaGVkdWxlLm5vdygpO2NvbnN0IGluUHJvZ3Jlc3M9dGhpcy5nZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5JTl9QUk9HUkVTUyk/P3t9O2NvbnN0IGluUHJvZ3Jlc3NJdGVtPWluUHJvZ3Jlc3NbZWwuaWRdO2xldCBmaXJzdEF0dGVtcHRlZEF0PW5vdztsZXQgbGFzdEF0dGVtcHRlZEF0PW5vdztsZXQgcmVjbGFpbWVkPWZhbHNlO2xldCByZXRyeVJlYXNvbj1ERUZBVUxUX1JFVFJZX1JFQVNPTjtpZihpblByb2dyZXNzSXRlbSl7cmV0cnlSZWFzb249aW5Qcm9ncmVzc0l0ZW0ucmV0cnlSZWFzb24/P3JldHJ5UmVhc29uO2ZpcnN0QXR0ZW1wdGVkQXQ9aW5Qcm9ncmVzc0l0ZW0uZmlyc3RBdHRlbXB0ZWRBdD8/Zmlyc3RBdHRlbXB0ZWRBdDtsYXN0QXR0ZW1wdGVkQXQ9aW5Qcm9ncmVzc0l0ZW0ubGFzdEF0dGVtcHRlZEF0Pz9sYXN0QXR0ZW1wdGVkQXQ7Ly8gSW5kaWNhdGVzIGlmIHRoZSBpdGVtIGhhcyBiZWVuIHJlY2xhaW1lZCBmcm9tIGxvY2FsIHN0b3JhZ2VcbnJlY2x
1haW1lZD1pblByb2dyZXNzSXRlbS5yZWNsYWltZWQ/P3JlY2xhaW1lZDsvLyBVcGRhdGUgdGhlIGZpcnN0IGF0dGVtcHRlZCBhdCB0aW1lc3RhbXAgZm9yIHRoZSBpbiBwcm9ncmVzcyBpdGVtXG5pblByb2dyZXNzSXRlbS5maXJzdEF0dGVtcHRlZEF0PWZpcnN0QXR0ZW1wdGVkQXQ7Ly8gVXBkYXRlIHRoZSBsYXN0IGF0dGVtcHRlZCBhdCB0byBjdXJyZW50IHRpbWVzdGFtcCBmb3IgdGhlIGluIHByb2dyZXNzIGl0ZW1cbmluUHJvZ3Jlc3NJdGVtLmxhc3RBdHRlbXB0ZWRBdD1ub3c7aW5Qcm9ncmVzc1tlbC5pZF09aW5Qcm9ncmVzc0l0ZW07dGhpcy5zZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5JTl9QUk9HUkVTUyxpblByb2dyZXNzKTt9Ly8gQSBkZWNpbWFsIGludGVnZXIgcmVwcmVzZW50aW5nIHRoZSBtaWxsaXNlY29uZHMgc2luY2UgdGhlIGZpcnN0IGF0dGVtcHRcbmNvbnN0IHRpbWVTaW5jZUZpcnN0QXR0ZW1wdD1ub3ctZmlyc3RBdHRlbXB0ZWRBdDsvLyBBIGRlY2ltYWwgaW50ZWdlciByZXByZXNlbnRpbmcgdGhlIG1pbGxpc2Vjb25kcyBzaW5jZSB0aGUgbGFzdCBhdHRlbXB0XG5jb25zdCB0aW1lU2luY2VMYXN0QXR0ZW1wdD1ub3ctbGFzdEF0dGVtcHRlZEF0O2NvbnN0IHdpbGxCZVJldHJpZWQ9dGhpcy5zaG91bGRSZXRyeShlbC5pdGVtLGVsLmF0dGVtcHROdW1iZXIrMSk7dGhpcy5wcm9jZXNzUXVldWVDYihlbC5pdGVtLGVsLmRvbmUse3JldHJ5QXR0ZW1wdE51bWJlcjplbC5hdHRlbXB0TnVtYmVyLG1heFJldHJ5QXR0ZW1wdHM6dGhpcy5tYXhBdHRlbXB0cyx3aWxsQmVSZXRyaWVkLHRpbWVTaW5jZUZpcnN0QXR0ZW1wdCx0aW1lU2luY2VMYXN0QXR0ZW1wdCxyZWNsYWltZWQsaXNQYWdlQWNjZXNzaWJsZTp0aGlzLmlzUGFnZUFjY2Vzc2libGUscmV0cnlSZWFzb259KTt9Y2F0Y2goZXJyKXtsZXQgZXJyTXNnPScnO2lmKGVsLmF0dGVtcHROdW1iZXI8dGhpcy5tYXhBdHRlbXB0cyl7ZXJyTXNnPSdUaGUgaXRlbSB3aWxsIGJlIHJlcXVldWVkLic7aWYoZWwuYXR0ZW1wdE51bWJlcj4wKXtlcnJNc2c9YCR7ZXJyTXNnfSBSZXRyeSBhdHRlbXB0ICR7ZWwuYXR0ZW1wdE51bWJlcn0gb2YgJHt0aGlzLm1heEF0dGVtcHRzfS5gO30vLyByZXF1ZXVlIHRoZSBpdGVtIHRvIGJlIHJldHJpZWRcbmVsLmRvbmUoZXJyKTt9ZWxzZSB7ZXJyTXNnPWBSZXRyaWVzIGV4aGF1c3RlZCAoJHt0aGlzLm1heEF0dGVtcHRzfSkuIFRoZSBpdGVtIHdpbGwgYmUgZHJvcHBlZC5gOy8vIGRyb3AgdGhlIGV2ZW50IGFzIHdlJ3JlIHVuYWJsZSB0byBwcm9jZXNzIGl0XG4vLyBhZnRlciB0aGUgbWF4IGF0dGVtcHRzIGFyZSBleGhhdXN0ZWRcbmVsLmRvbmUoKTt9dGhpcy5sb2dnZXI/LmVycm9yKFJFVFJZX1FVRVVFX1BST0NFU1NfRVJST1IoUkVUUllfUVVFVUUsZXJyTXNnKSxlcnIpO319KTsvLyByZS1yZWFkIHRoZSBxdWV1ZSBpbiBjYXNlIHRoZSBwcm9jZXNzIGZ1bmN0aW9uIGZpbmlzaGVkIGltbWVkaWF0ZWx5IG9yIGFkZGVkIGFub3RoZXIgaXRlbVxucXVldWU9dGhpcy5nZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5RVUVVRSk/P1tdO3RoaXMuc2NoZWR1bGUuY2FuY2VsKHRoaXMucHJvY2Vzc0lkKTtpZihxdWV1ZS5sZW5ndGg+MCl7Y29uc3QgbmV4dFByb2Nlc3NFeGVjdXRpb25UaW1lPXF1ZXVlWzBdLnRpbWUtbm93O3RoaXMucHJvY2Vzc0lkPXRoaXMuc2NoZWR1bGUucnVuKHRoaXMucHJvY2Vzc0hlYWQsbmV4dFByb2Nlc3NFeGVjdXRpb25UaW1lLFNjaGVkdWxlTW9kZXMuQVNBUCk7fX0vLyBBY2sgY29udGludW91c2x5IHRvIHByZXZlbnQgb3RoZXIgdGFicyBmcm9tIGNsYWltaW5nIG91ciBxdWV1ZVxuYWNrKCl7dGhpcy5zZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5BQ0ssdGhpcy5zY2hlZHVsZS5ub3coKSk7aWYodGhpcy5yZWNsYWltU3RhcnRWYWwhPW51bGwpe3RoaXMucmVjbGFpbVN0YXJ0VmFsPW51bGw7dGhpcy5zZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5SRUNMQUlNX1NUQVJULG51bGwpO31pZih0aGlzLnJlY2xhaW1FbmRWYWwhPW51bGwpe3RoaXMucmVjbGFpbUVuZFZhbD1udWxsO3RoaXMuc2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuUkVDTEFJTV9FTkQsbnVsbCk7fXRoaXMuc2NoZWR1bGUucnVuKHRoaXMuYWNrLHRoaXMudGltZW91dHMuYWNrVGltZXIsU2NoZWR1bGVNb2Rlcy5BU0FQKTt9cmVjbGFpbShpZCl7Y29uc3Qgb3RoZXI9dGhpcy5zdG9yZU1hbmFnZXIuc2V0U3RvcmUoe2lkLG5hbWU6dGhpcy5uYW1lLHZhbGlkS2V5czpRdWV1ZVN0YXR1c2VzLHR5cGU6TE9DQUxfU1RPUkFHRSxlcnJvckhhbmRsZXI6dGhpcy5zdG9yZU1hbmFnZXIuZXJyb3JIYW5kbGVyLGxvZ2dlcjp0aGlzLnN0b3JlTWFuYWdlci5sb2dnZXJ9KTtjb25zdCBvdXI9e3F1ZXVlOnRoaXMuZ2V0U3RvcmFnZUVudHJ5KFF1ZXVlU3RhdHVzZXMuUVVFVUUpPz9bXX07Y29uc3QgdGhlaXI9e2luUHJvZ3Jlc3M6b3RoZXIuZ2V0KFF1ZXVlU3RhdHVzZXMuSU5fUFJPR1JFU1MpPz97fSxiYXRjaFF1ZXVlOm90aGVyLmdldChRdWV1ZVN0YXR1c2VzLkJBVENIX1FVRVVFKT8/W10scXVldWU6b3RoZXIuZ2V0KFF1ZXVlU3RhdHVzZXMuUVVFVUUpPz9bXX07Y29uc3QgdHJhY2tNZXNzYWdlSWRzPVtdO2NvbnN0IGFkZENvbmNhdFF1ZXVlPShxdWV1ZSxpbmNyZW1lbnRBdHRlbXB0TnVtYmVyQnkpPT57Y29uc3QgY29uY2F0SXRlcmF0b3I9ZWw9Pntjb25zdCBpZD1lbC5pZD8/Z2VuZXJhdGVVVUlEKCk7aWYodHJhY2tNZXNzYWdlSWRzLmluY2x1ZGVzKGlkKSk7ZWxzZSB7Ly8gSGFjayB0byBkZXRlcm1pbmUgdGhlIGl0ZW0gdHlwZSBieSB0aGUgY29udGVudHMgb2YgdGhlIGVudHJ5XG4vLyBBZnRlciBzb21lIHBvaW50LCB3ZSBjYW4gcmVtb3ZlIHRoaXMgaGFjayBhcyBtb3N0IG9mIHRoZSBzdGFsZSBkYXRhIHdpbGwgaGF2ZSBiZWVuIHByb2Nlc3NlZFxuLy8gYW5kIHRoZSBuZXcgZW50cmllcyB3aWxsIGhhdmUgdGhlIHR5cGUgZmllbGQgc2V0XG5jb25zdCB0eXBlPUFycmF5LmlzQXJyYXkoZWwuaXRlbSk/QkFUQ0hfUVVFVUVfSVRFTV9UWVBFOlNJTkdMRV9RVUVVRV9JVEVNX1RZUEU7b3VyLnF1ZXVlLnB1c2goe2l0ZW06ZWwuaXRlbSxhdHRlbXB0TnVtYmVyOmVsLmF0dGVtcHROdW1iZXIraW5jcmVtZW50QXR0ZW1wdE51bWJlckJ5LHRpbWU6dGhpcy5zY2hlZHVsZS5ub3coKSxpZCx0eXBlOmVsLnR5cGU/P3R5cGUsZmlyc3RBdHRlbXB0ZWRBdDplbC5maXJzdEF0dGVtcHRlZEF0LGxhc3RBdHRlbXB0ZWRBdDplbC5sYXN0QXR0ZW1wdGVkQXQscmV0cnlSZWFzb246ZWwucmV0cnlSZWFzb24sLy8gTWFyayB0aGUgaXRlbSBhcyByZWNsYWltZWQgZnJvbSBsb2NhbCBzdG9yYWdlXG5yZWNsYWltZWQ6dHJ1ZX0pO3RyYWNrTWVzc2FnZUlkcy5wdXNoKGlkKTt9fTtpZihBcnJheS5pc0FycmF
15KHF1ZXVlKSl7cXVldWUuZm9yRWFjaChjb25jYXRJdGVyYXRvcik7fWVsc2UgaWYocXVldWUpe09iamVjdC52YWx1ZXMocXVldWUpLmZvckVhY2goY29uY2F0SXRlcmF0b3IpO319Oy8vIGFkZCB0aGVpciBxdWV1ZSB0byBvdXJzLCByZXNldHRpbmcgcnVuLXRpbWUgdG8gaW1tZWRpYXRlIGFuZCBjb3B5aW5nIHRoZSBhdHRlbXB0I1xuYWRkQ29uY2F0UXVldWUodGhlaXIucXVldWUsMCk7Ly8gUHJvY2VzcyBiYXRjaCBxdWV1ZSBpdGVtc1xuaWYodGhpcy5iYXRjaC5lbmFibGVkKXt0aGVpci5iYXRjaFF1ZXVlLmZvckVhY2goZWw9Pntjb25zdCBpZD1lbC5pZD8/Z2VuZXJhdGVVVUlEKCk7aWYodHJhY2tNZXNzYWdlSWRzLmluY2x1ZGVzKGlkKSk7ZWxzZSB7dGhpcy5lbnF1ZXVlKHsuLi5lbCxpZCxyZXRyeVJlYXNvbjplbC5yZXRyeVJlYXNvbiwvLyBNYXJrIHRoZSBpdGVtIGFzIHJlY2xhaW1lZCBmcm9tIGxvY2FsIHN0b3JhZ2VcbnJlY2xhaW1lZDp0cnVlLHR5cGU6ZWwudHlwZT8/U0lOR0xFX1FVRVVFX0lURU1fVFlQRSx0aW1lOnRoaXMuc2NoZWR1bGUubm93KCl9KTt0cmFja01lc3NhZ2VJZHMucHVzaChpZCk7fX0pO31lbHNlIHsvLyBpZiBiYXRjaGluZyBpcyBub3QgZW5hYmxlZCBpbiB0aGUgY3VycmVudCBpbnN0YW5jZSwgYWRkIHRob3NlIGl0ZW1zIHRvIHRoZSBtYWluIHF1ZXVlIGRpcmVjdGx5XG5hZGRDb25jYXRRdWV1ZSh0aGVpci5iYXRjaFF1ZXVlLDApO30vLyBpZiB0aGUgcXVldWUgaXMgYWJhbmRvbmVkLCBhbGwgdGhlIGluLXByb2dyZXNzIGFyZSBmYWlsZWQuIHJldHJ5IHRoZW0gaW1tZWRpYXRlbHkgYW5kIGluY3JlbWVudCB0aGUgYXR0ZW1wdCNcbmFkZENvbmNhdFF1ZXVlKHRoZWlyLmluUHJvZ3Jlc3MsMSk7b3VyLnF1ZXVlLnNvcnQoc29ydEJ5VGltZSk7dGhpcy5zZXRTdG9yYWdlRW50cnkoUXVldWVTdGF0dXNlcy5RVUVVRSxvdXIucXVldWUpOy8vIHJlbW92ZSBhbGwga2V5cyBvbmUgYnkgb24gbmV4dCB0aWNrIHRvIGF2b2lkIE5TX0VSUk9SX1NUT1JBR0VfQlVTWSBlcnJvclxudGhpcy5jbGVhclF1ZXVlRW50cmllcyhvdGhlciwxKTsvLyBwcm9jZXNzIHRoZSBuZXcgaXRlbXMgd2UgY2xhaW1lZFxudGhpcy5wcm9jZXNzSGVhZCgpO31jbGVhclF1ZXVlRW50cmllcyhvdGhlcixsb2NhbFN0b3JhZ2VCYWNrb2ZmKXt0aGlzLnJlbW92ZVN0b3JhZ2VFbnRyeShvdGhlciwwLGxvY2FsU3RvcmFnZUJhY2tvZmYpO31yZW1vdmVTdG9yYWdlRW50cnkoc3RvcmUsZW50cnlJZHgsYmFja29mZixhdHRlbXB0PTEpe2NvbnN0IG1heEF0dGVtcHRzPTI7Y29uc3QgcXVldWVFbnRyeUtleXM9T2JqZWN0LmtleXMoUXVldWVTdGF0dXNlcyk7Y29uc3QgZW50cnk9UXVldWVTdGF0dXNlc1txdWV1ZUVudHJ5S2V5c1tlbnRyeUlkeF1dO2dsb2JhbFRoaXMuc2V0VGltZW91dCgoKT0+e3RyeXtzdG9yZS5yZW1vdmUoZW50cnkpOy8vIGNsZWFyIHRoZSBuZXh0IGVudHJ5XG5pZihlbnRyeUlkeCsxPHF1ZXVlRW50cnlLZXlzLmxlbmd0aCl7dGhpcy5yZW1vdmVTdG9yYWdlRW50cnkoc3RvcmUsZW50cnlJZHgrMSxiYWNrb2ZmKTt9fWNhdGNoKGVycil7Y29uc3Qgc3RvcmFnZUJ1c3lFcnI9J05TX0VSUk9SX1NUT1JBR0VfQlVTWSc7Y29uc3QgaXNMb2NhbFN0b3JhZ2VCdXN5PWVyci5uYW1lPT09c3RvcmFnZUJ1c3lFcnJ8fGVyci5jb2RlPT09c3RvcmFnZUJ1c3lFcnJ8fGVyci5jb2RlPT09MHg4MDYzMDAwMTtpZihpc0xvY2FsU3RvcmFnZUJ1c3kmJmF0dGVtcHQ8bWF4QXR0ZW1wdHMpey8vIFRyeSBjbGVhcmluZyB0aGUgc2FtZSBlbnRyeSBhZ2FpbiB3aXRoIHNvbWUgZXh0cmEgZGVsYXlcbnRoaXMucmVtb3ZlU3RvcmFnZUVudHJ5KHN0b3JlLGVudHJ5SWR4LGJhY2tvZmYrNDAsYXR0ZW1wdCsxKTt9ZWxzZSB7dGhpcy5sb2dnZXI/LmVycm9yKFJFVFJZX1FVRVVFX0VOVFJZX1JFTU9WRV9FUlJPUihSRVRSWV9RVUVVRSxlbnRyeSxhdHRlbXB0KSxlcnIpO30vLyBjbGVhciB0aGUgbmV4dCBlbnRyeSBhZnRlciB3ZSd2ZSBleGhhdXN0ZWQgb3VyIGF0dGVtcHRzXG5pZihhdHRlbXB0PT09bWF4QXR0ZW1wdHMmJmVudHJ5SWR4KzE8cXVldWVFbnRyeUtleXMubGVuZ3RoKXt0aGlzLnJlbW92ZVN0b3JhZ2VFbnRyeShzdG9yZSxlbnRyeUlkeCsxLGJhY2tvZmYpO319fSxiYWNrb2ZmKTt9Y2hlY2tSZWNsYWltKCl7Y29uc3QgY3JlYXRlUmVjbGFpbVN0YXJ0VGFzaz1zdG9yZT0+KCk9PntpZihzdG9yZS5nZXQoUXVldWVTdGF0dXNlcy5SRUNMQUlNX0VORCkhPT10aGlzLmlkKXtyZXR1cm47fWlmKHN0b3JlLmdldChRdWV1ZVN0YXR1c2VzLlJFQ0xBSU1fU1RBUlQpIT09dGhpcy5pZCl7cmV0dXJuO310aGlzLnJlY2xhaW0oc3RvcmUuaWQpO307Y29uc3QgY3JlYXRlUmVjbGFpbUVuZFRhc2s9c3RvcmU9PigpPT57aWYoc3RvcmUuZ2V0KFF1ZXVlU3RhdHVzZXMuUkVDTEFJTV9TVEFSVCkhPT10aGlzLmlkKXtyZXR1cm47fXN0b3JlLnNldChRdWV1ZVN0YXR1c2VzLlJFQ0xBSU1fRU5ELHRoaXMuaWQpO3RoaXMuc2NoZWR1bGUucnVuKGNyZWF0ZVJlY2xhaW1TdGFydFRhc2soc3RvcmUpLHRoaXMudGltZW91dHMucmVjbGFpbVdhaXQsU2NoZWR1bGVNb2Rlcy5BQkFORE9OKTt9O2NvbnN0IHRyeVJlY2xhaW09c3RvcmU9PntzdG9yZS5zZXQoUXVldWVTdGF0dXNlcy5SRUNMQUlNX1NUQVJULHRoaXMuaWQpO3N0b3JlLnNldChRdWV1ZVN0YXR1c2VzLkFDSyx0aGlzLnNjaGVkdWxlLm5vdygpKTt0aGlzLnNjaGVkdWxlLnJ1bihjcmVhdGVSZWNsYWltRW5kVGFzayhzdG9yZSksdGhpcy50aW1lb3V0cy5yZWNsYWltV2FpdCxTY2hlZHVsZU1vZGVzLkFCQU5ET04pO307Y29uc3QgZmluZE90aGVyUXVldWVzPW5hbWU9Pntjb25zdCByZXM9W107Y29uc3Qgc3RvcmFnZUVuZ2luZT10aGlzLnN0b3JlLmdldE9yaWdpbmFsRW5naW5lKCk7bGV0IHN0b3JhZ2VLZXlzPVtdOy8vICdrZXlzJyBBUEkgaXMgbm90IHN1cHBvcnRlZCBieSBhbGwgdGhlIGNvcmUgU0RLIHZlcnNpb25zXG4vLyBIZW5jZSwgd2UgbmVlZCB0aGlzIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkgY2hlY2tcbmlmKGlzRnVuY3Rpb24oc3RvcmFnZUVuZ2luZS5rZXlzKSl7c3RvcmFnZUtleXM9c3RvcmFnZUVuZ2luZS5rZXlzKCk7fWVsc2Uge2ZvcihsZXQgaT0wO2k8c3RvcmFnZUVuZ2luZS5sZW5ndGg7aSsrKXtjb25zdCBrZXk9c3RvcmFnZUVuZ2luZS5rZXkoaSk7aWYoa2V5KXtzdG9yYWdlS2V5cy5wdXNoKGtleSk7fX19c3RvcmFnZUtleXMuZm9yRWFjaChrPT57Y29uc3Qga2V5UGFydHM9az9rLnNwbGl0KCcuJyk6W107aWYoa2V5UGFydHMubGVuZ3RoPj0zJiZrZXlQYXJ0c1swXT09PW5hbWUmJmtleVBhcnRzWzFdIT09dGhpcy5pZCYma2V5UGFydHNbMl09PT1RdWV1ZVN0YXR1c2VzLkFDSyl7cmVzLnB1c2godGhpcy5zdG9yZU1hbmFnZXIuc2V0U3RvcmUoe2lkOmtleVBhcnRzWzFdLG5hbWUsdmFsaWRLZXlzOlF1ZXVlU3RhdHVzZXMsdHlwZTpMT0NBTF9TVE9SQUdFLGVycm9ySGFuZGxlcjp0aGlzLnN0b3JlTWFuYWdlci5lcnJvckhhbmRsZXIsbG9nZ2VyOnRoaXMuc3RvcmVNYW5hZ2VyLmxvZ2dlcn0pKTt9fSk7cmV0dXJuIHJlczt9O2ZpbmRPdGhlclF1ZXVlcyh0aGlzLm5hbWUpLmZvckVhY2goc3RvcmU9PntpZih0aGlzLnNjaGVkdWxlLm5vdygpLXN0b3JlLmdldChRdWV1ZVN0YXR1c2VzLkFDSyk8dGhpcy50aW1lb3V0cy5yZWNsYWltVGltZW91dCl7cmV0dXJuO310cnlSZWNsYWltKHN0b3JlKTt9KTt0aGlzLnNjaGVkdWxlLnJ1bih0aGlzLmNoZWNrUmVjbGFpbSx0aGlzLnRpbWVvdXRzLnJlY2xhaW1UaW1lcixTY2hlZHVsZU1vZGVzLlJFU0NIRURVTEUpO31jbGVhcigpe3RoaXMuc2NoZWR1bGUuY2FuY2VsQWxsKCk7dGhpcy5zZXREZWZhdWx0UXVldWVFbnRyaWVzKCk7fX1cblxuY29uc3QgcGx1Z2luTmFtZSRkPSdCZWFjb25RdWV1ZSc7Y29uc3QgQmVhY29uUXVldWU9KCk9Pih7bmFtZTpwbHVnaW5OYW1lJGQsZGVwczpbXSxpbml0aWFsaXplOnN0YXRlPT57c3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlPVsuLi5zdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWUscGx1Z2luTmFtZSRkXTt9LGRhdGFwbGFuZUV2ZW50c1F1ZXVlOnsvKipcbiAgICAgKiBJbml0aWFsaXplIHRoZSBxdWV1ZSBmb3IgZGVsaXZlcnlcbiAgICAgKiBAcGFyYW0gc3RhdGUgQXBwbGljYXRpb24gc3RhdGVcbiAgICAgKiBAcGFyYW0gaHR0cENsaWVudCBodHRwIGNsaWVudCBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBzdG9yZU1hbmFnZXIgU3RvcmUgTWFuYWdlciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBlcnJvckhhbmRsZXIgRXJyb3IgaGFuZGxlciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gICAgICogQHJldHVybnMgQmVhY29uSXRlbXNRdWV1ZSBpbnN0YW5jZVxuICAgICAqL2luaXQoc3RhdGUsaHR0cENsaWVudCxzdG9yZU1hbmFnZXIsZXJyb3JIYW5kbGVyLGxvZ2dlcil7Y29uc3Qgd3JpdGVLZXk9c3RhdGUubGlmZWN5Y2xlLndyaXRlS2V5LnZhbHVlO2NvbnN0IGRhdGFwbGFuZVVybD1zdGF0ZS5saWZlY3ljbGUuYWN0aXZlRGF0YXBsYW5lVXJsLnZhbHVlO2NvbnN0IHVybD1nZXREZWxpdmVyeVVybCQxKGRhdGFwbGFuZVVybCx3cml0ZUtleSk7Y29uc3QgZmluYWxRT3B0cz1nZXROb3JtYWxpem
1VkQmVhY29uUXVldWVPcHRpb25zKHN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLmJlYWNvblF1ZXVlT3B0aW9ucz8/e30pO2NvbnN0IHF1ZXVlUHJvY2Vzc0NhbGxiYWNrPShpdGVtRGF0YSxkb25lLGluZm8pPT57Y29uc3R7aXNQYWdlQWNjZXNzaWJsZX09aW5mbztsb2dnZXI/LmRlYnVnKEJFQUNPTl9QTFVHSU5fRVZFTlRTX1FVRVVFX0RFQlVHKEJFQUNPTl9RVUVVRV9QTFVHSU4pKTtjb25zdCBjdXJyZW50VGltZT1nZXRDdXJyZW50VGltZUZvcm1hdHRlZCgpO2NvbnN0IGZpbmFsRXZlbnRzPWl0ZW1EYXRhLm1hcChxdWV1ZUl0ZW1EYXRhPT5nZXRGaW5hbEV2ZW50Rm9yRGVsaXZlcnlNdXRhdG9yKHF1ZXVlSXRlbURhdGEuZXZlbnQsY3VycmVudFRpbWUpKTtjb25zdCBkYXRhPWdldEJhdGNoRGVsaXZlcnlQYXlsb2FkJDEoZmluYWxFdmVudHMsY3VycmVudFRpbWUsbG9nZ2VyKTtpZighZGF0YSl7Ly8gTWFyayB0aGUgaXRlbSBhcyBkb25lIHNvIHRoYXQgaXQgY2FuIGJlIHJlbW92ZWQgZnJvbSB0aGUgcXVldWVcbmRvbmUobnVsbCk7cmV0dXJuO310cnl7aWYoIW5hdmlnYXRvci5zZW5kQmVhY29uKHVybCxkYXRhKSl7aWYoaXNQYWdlQWNjZXNzaWJsZSl7bG9nZ2VyPy5lcnJvcihgJHtCRUFDT05fUVVFVUVfU0VORF9FUlJPUihCRUFDT05fUVVFVUVfUExVR0lOLHVybCl9IFRoZSBldmVudChzKSB3aWxsIGJlIGRyb3BwZWQuYCk7Ly8gUmVtb3ZlIHRoZSBpdGVtIGZyb20gcXVldWVcbmRvbmUobnVsbCk7fWVsc2Ugey8vIE5vdGU6IFdlJ3JlIG5vdCByZW1vdmluZyB0aGUgaXRlbSBmcm9tIHRoZSBxdWV1ZSBhcyB3ZSB3YW50IHRvIHJldHJ5IHRoZSByZXF1ZXN0XG5sb2dnZXI/Lndhcm4oYCR7QkVBQ09OX1FVRVVFX1NFTkRfRVJST1IoQkVBQ09OX1FVRVVFX1BMVUdJTix1cmwpfSBUaGUgZXZlbnQocykgd2lsbCBiZSByZXRyaWVkIGFzIHRoZSBjdXJyZW50IHBhZ2UgaXMgYmVpbmcgdW5sb2FkZWQuYCk7fX1lbHNlIHsvLyBSZW1vdmUgdGhlIGl0ZW0gZnJvbSBxdWV1ZSBhcyB0aGUgcmVxdWVzdCB3YXMgc3VjY2Vzc2Z1bFxuZG9uZShudWxsKTt9fWNhdGNoKGVycil7ZXJyb3JIYW5kbGVyPy5vbkVycm9yKHtlcnJvcjplcnIsY29udGV4dDpCRUFDT05fUVVFVUVfUExVR0lOLGN1c3RvbU1lc3NhZ2U6QkVBQ09OX1FVRVVFX0RFTElWRVJZX0VSUk9SKHVybCl9KTsvLyBSZW1vdmUgdGhlIGl0ZW0gZnJvbSBxdWV1ZVxuZG9uZShudWxsKTt9fTtjb25zdCBldmVudHNRdWV1ZT1uZXcgUmV0cnlRdWV1ZShgJHtRVUVVRV9OQU1FJDN9XyR7d3JpdGVLZXl9YCx7YmF0Y2g6e2VuYWJsZWQ6dHJ1ZSxmbHVzaEludGVydmFsOmZpbmFsUU9wdHMuZmx1c2hRdWV1ZUludGVydmFsLG1heFNpemU6TUFYX0JBVENIX1BBWUxPQURfU0laRV9CWVRFUywvLyBzZXQgdGhlIGhhcmQgbGltaXRcbm1heEl0ZW1zOmZpbmFsUU9wdHMubWF4SXRlbXN9fSxxdWV1ZVByb2Nlc3NDYWxsYmFjayxzdG9yZU1hbmFnZXIsZ2V0U3RvcmFnZVR5cGVGb3JFdmVudHNQZXJzaXN0ZW5jZShsb2dnZXIpLGxvZ2dlcixpdGVtRGF0YT0+e2NvbnN0IGN1cnJlbnRUaW1lPWdldEN1cnJlbnRUaW1lRm9ybWF0dGVkKCk7Y29uc3QgZXZlbnRzPWl0ZW1EYXRhLm1hcChxdWV1ZUl0ZW1EYXRhPT5xdWV1ZUl0ZW1EYXRhLmV2ZW50KTsvLyB0eXBlIGNhc3RpbmcgdG8gQmxvYiBhcyB3ZSBrbm93IHRoYXQgdGhlIGV2ZW50IGhhcyBhbHJlYWR5IGJlZW4gdmFsaWRhdGVkIHByaW9yIHRvIGVucXVldWVcbnJldHVybiBnZXRCYXRjaERlbGl2ZXJ5UGF5bG9hZCQxKGV2ZW50cyxjdXJyZW50VGltZSxsb2dnZXIpLnNpemU7fSk7cmV0dXJuIGV2ZW50c1F1ZXVlO30sLyoqXG4gICAgICogQWRkIGV2ZW50IHRvIHRoZSBxdWV1ZSBmb3IgZGVsaXZlcnlcbiAgICAgKiBAcGFyYW0gc3RhdGUgQXBwbGljYXRpb24gc3RhdGVcbiAgICAgKiBAcGFyYW0gZXZlbnRzUXVldWUgSVF1ZXVlIGluc3RhbmNlXG4gICAgICogQHBhcmFtIGV2ZW50IFJ1ZGRlckV2ZW50IG9iamVjdFxuICAgICAqIEBwYXJhbSBlcnJvckhhbmRsZXIgRXJyb3IgaGFuZGxlciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gICAgICogQHJldHVybnMgbm9uZVxuICAgICAqL2VucXVldWUoc3RhdGUsZXZlbnRzUXVldWUsZXZlbnQsZXJyb3JIYW5kbGVyLGxvZ2dlcil7Ly8gc2VudEF0IGlzIG9ubHkgYWRkZWQgaGVyZSBmb3IgdGhlIHZhbGlkYXRpb24gc3RlcFxuLy8gSXQnbGwgYmUgdXBkYXRlZCB0byB0aGUgbGF0ZXN0IHRpbWVzdGFtcCBkdXJpbmcgYWN0dWFsIGRlbGl2ZXJ5XG5ldmVudC5zZW50QXQ9Z2V0Q3VycmVudFRpbWVGb3JtYXR0ZWQoKTt2YWxpZGF0ZUV2ZW50UGF5bG9hZFNpemUoZXZlbnQsbG9nZ2VyKTtldmVudHNRdWV1ZS5hZGRJdGVtKHtldmVudH0pO319fSk7XG5cbmNvbnN0IENVU1RPTV9DT05TRU5UX01BTkFHRVJfUExVR0lOPSdDdXN0b21Db25zZW50TWFuYWdlclBsdWdpbic7XG5cbmNvbnN0IERFU1RJTkFUSU9OX0NPTlNFTlRfU1RBVFVTX0VSUk9SJDM9YEZhaWxlZCB0byBkZXRlcm1pbmUgdGhlIGNvbnNlbnQgc3RhdHVzIGZvciB0aGUgZGVzdGluYXRpb24uIFBsZWFzZSBjaGVjayB0aGUgZGVzdGluYXRpb24gY29uZmlndXJhdGlvbiBhbmQgdHJ5IGFnYWluLmA7XG5cbmNvbnN0IHBsdWdpbk5hbWUkYz0nQ3VzdG9tQ29uc2VudE1hbmFnZXInO2NvbnN0IEN1c3RvbUNvbnNlbnRNYW5hZ2VyPSgpPT4oe25hbWU6cGx1Z2luTmFtZSRjLGRlcHM6W10saW5pdGlhbGl6ZTpzdGF0ZT0+e3N0YXRlLnBsdWdpbnMubG9hZGVkUGx1Z2lucy52YWx1ZT1bLi4uc3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlLHBsdWdpbk5hbWUkY107fSxjb25zZW50TWFuYWdlcjp7aW5pdChzdGF0ZSxsb2dnZXIpey8vIE5vdGhpbmcgdG8gaW5pdGlhbGl6ZVxufSx1cGRhdGVDb25zZW50c0luZm8oc3RhdGUsc3RvcmVNYW5hZ2VyLGxvZ2dlcil7Ly8gTm90aGluZyB0byB1cGRhdGUuIEFscmVhZHkgcHJvdmlkZWQgYnkgdGhlIHVzZXJcbn0saXNEZXN0aW5hdGlvbkNvbnNlbnRlZChzdGF0ZSxkZXN0Q29uZmlnLGVycm9ySGFuZGxlcixsb2dnZXIpe2lmKCFzdGF0ZS5jb25zZW50cy5pbml0aWFsaXplZC52YWx1ZSl7cmV0dXJuIHRydWU7fWNvbnN0IGFsbG93ZWRDb25zZW50SWRzPXN0YXRlLmNvbnNlbnRzLmRhdGEudmFsdWUuYWxsb3dlZENvbnNlbnRJZHM7dHJ5e2NvbnN0e2NvbnNlbnRNYW5hZ2VtZW50fT1kZXN0Q29uZmlnOy8vIElmIHRoZSBkZXN0aW5
1hdGlvbiBkb2VzIG5vdCBoYXZlIGNvbnNlbnQgbWFuYWdlbWVudCBjb25maWcsIGV2ZW50cyBzaG91bGQgYmUgc2VudC5cbmlmKCFjb25zZW50TWFuYWdlbWVudCl7cmV0dXJuIHRydWU7fS8vIEdldCB0aGUgY29ycmVzcG9uZGluZyBjb25zZW50cyBmb3IgdGhlIGRlc3RpbmF0aW9uXG5jb25zdCBjbXBDb25maWc9Y29uc2VudE1hbmFnZW1lbnQuZmluZChjPT5jLnByb3ZpZGVyPT09c3RhdGUuY29uc2VudHMucHJvdmlkZXIudmFsdWUpOy8vIElmIHRoZXJlIGFyZSBubyBjb25zZW50cyBjb25maWd1cmVkIGZvciB0aGUgZGVzdGluYXRpb24gZm9yIHRoZSBjdXJyZW50IHByb3ZpZGVyLCBldmVudHMgc2hvdWxkIGJlIHNlbnQuXG5pZighY21wQ29uZmlnPy5jb25zZW50cyl7cmV0dXJuIHRydWU7fWNvbnN0IGNvbmZpZ3VyZWRDb25zZW50cz1jbXBDb25maWcuY29uc2VudHMubWFwKGM9PmMuY29uc2VudC50cmltKCkpLmZpbHRlcihuPT5uKTtjb25zdCByZXNvbHV0aW9uU3RyYXRlZ3k9Y21wQ29uZmlnLnJlc29sdXRpb25TdHJhdGVneT8/c3RhdGUuY29uc2VudHMucmVzb2x1dGlvblN0cmF0ZWd5LnZhbHVlOy8vIG1hdGNoIHRoZSBjb25maWd1cmVkIGNvbnNlbnRzIHdpdGggdXNlciBwcm92aWRlZCBjb25zZW50cyBhcyBwZXJcbi8vIHRoZSBjb25maWd1cmVkIHJlc29sdXRpb24gc3RyYXRlZ3lcbmNvbnN0IG1hdGNoUHJlZGljYXRlPWNvbnNlbnQ9PmFsbG93ZWRDb25zZW50SWRzLmluY2x1ZGVzKGNvbnNlbnQpO3N3aXRjaChyZXNvbHV0aW9uU3RyYXRlZ3kpe2Nhc2UgJ29yJzpyZXR1cm4gY29uZmlndXJlZENvbnNlbnRzLnNvbWUobWF0Y2hQcmVkaWNhdGUpfHxjb25maWd1cmVkQ29uc2VudHMubGVuZ3RoPT09MDtjYXNlICdhbmQnOmRlZmF1bHQ6cmV0dXJuIGNvbmZpZ3VyZWRDb25zZW50cy5ldmVyeShtYXRjaFByZWRpY2F0ZSk7fX1jYXRjaChlcnIpe2Vycm9ySGFuZGxlcj8ub25FcnJvcih7ZXJyb3I6ZXJyLGNvbnRleHQ6Q1VTVE9NX0NPTlNFTlRfTUFOQUdFUl9QTFVHSU4sY3VzdG9tTWVzc2FnZTpERVNUSU5BVElPTl9DT05TRU5UX1NUQVRVU19FUlJPUiQzfSk7cmV0dXJuIHRydWU7fX19fSk7XG5cbmNvbnN0IFJFQURZX0NIRUNLX1RJTUVPVVRfTVM9MTEqMTAwMDsvLyAxMSBzZWNvbmRzXG5jb25zdCBTQ1JJUFRfTE9BRF9USU1FT1VUX01TPTEwKjEwMDA7Ly8gMTAgc2Vjb25kc1xuY29uc3QgUkVBRFlfQ0hFQ0tfSU5URVJWQUxfTVM9MTAwOy8vIDEwMCBtaWxsaXNlY29uZHNcbmNvbnN0IERFVklDRV9NT0RFX0RFU1RJTkFUSU9OU19QTFVHSU49J0RldmljZU1vZGVEZXN0aW5hdGlvbnNQbHVnaW4nO1xuXG5jb25zdCBJTlRFR1JBVElPTl9OT1RfU1VQUE9SVEVEX0VSUk9SPWRlc3REaXNwbGF5TmFtZT0+YEludGVncmF0aW9uIGZvciBkZXN0aW5hdGlvbiBcIiR7ZGVzdERpc3BsYXlOYW1lfVwiIGlzIG5vdCBzdXBwb3J0ZWQuYDtjb25zdCBJTlRFR1JBVElPTl9TREtfTE9BRF9FUlJPUj1kZXN0RGlzcGxheU5hbWU9PmBGYWlsZWQgdG8gbG9hZCBpbnRlZ3JhdGlvbiBTREsgZm9yIGRlc3RpbmF0aW9uIFwiJHtkZXN0RGlzcGxheU5hbWV9XCJgO2NvbnN0IElOVEVHUkFUSU9OX0lOSVRfRVJST1I9ZGVzdFVzZXJGcmllbmRseUlkPT5gRmFpbGVkIHRvIGluaXRpYWxpemUgaW50ZWdyYXRpb24gZm9yIGRlc3RpbmF0aW9uIFwiJHtkZXN0VXNlckZyaWVuZGx5SWR9XCIuYDtjb25zdCBJTlRFR1JBVElPTlNfREFUQV9FUlJPUj1kZXN0VXNlckZyaWVuZGx5SWQ9PmBGYWlsZWQgdG8gZ2V0IGludGVncmF0aW9ucyBkYXRhIGZvciBkZXN0aW5hdGlvbiBcIiR7ZGVzdFVzZXJGcmllbmRseUlkfVwiLmA7Y29uc3QgSU5URUdSQVRJT05fUkVBRFlfVElNRU9VVF9FUlJPUj10aW1lb3V0PT5gQSB0aW1lb3V0IG9mICR7dGltZW91dH0gbXMgb2NjdXJyZWRgO2NvbnN0IElOVEVHUkFUSU9OX1JFQURZX0NIRUNLX0VSUk9SPWlkPT5gRmFpbGVkIHRvIGdldCB0aGUgcmVhZHkgc3RhdHVzIGZyb20gaW50ZWdyYXRpb24gZm9yIGRlc3RpbmF0aW9uIFwiJHtpZH1cImA7Y29uc3QgQ1VTVE9NX0lOVEVHUkFUSU9OX0lOVkFMSURfREVTVElOQVRJT05fSURfRVJST1I9KGNvbnRleHQsZGVzdGluYXRpb25JZCk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9VGhlIGRlc3RpbmF0aW9uIElEIFwiJHtkZXN0aW5hdGlvbklkfVwiIGRvZXMgbm90IGNvcnJlc3BvbmQgdG8gYSBjdXN0b20gZGV2aWNlIG1vZGUgZGVzdGluYXRpb24uYDtjb25zdCBDVVNUT01fSU5URUdSQVRJT05fQUxSRUFEWV9FWElTVFNfRVJST1I9KGNvbnRleHQsZGVzdGluYXRpb25JZCk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9QSBjdXN0b20gaW50ZWdyYXRpb24gd2l0aCBkZXN0aW5hdGlvbiBJRCBcIiR7ZGVzdGluYXRpb25JZH1cIiB3YXMgYWxyZWFkeSBhZGRlZC5gO2NvbnN0IElOVkFMSURfQ1VTVE9NX0lOVEVHUkFUSU9OX0VSUk9SPShjb250ZXh0LGRlc3RpbmF0aW9uSWQpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBjdXN0b20gaW50ZWdyYXRpb24gYWRkZWQgZm9yIGRlc3RpbmF0aW9uIElEIFwiJHtkZXN0aW5hdGlvbklkfVwiIGRvZXMgbm90IG1hdGNoIHRoZSBleHBlY3RlZCBpbXBsZW1lbnRhdGlvbiBmb3JtYXQuYDtjb25zdCBJTlRFR1JBVElPTl9OT1RfQURERURfVE9fQ1VTVE9NX0RFU1RJTkFUSU9OX1dBUk5JTkc9KGNvbnRleHQsZGVzdGluYXRpb25JZCk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9Tm8gdmFsaWQgY3VzdG9tIGludGVncmF0aW9uIHdhcyBhZGRlZCBmb3IgZGVzdGluYXRpb24gSUQgXCIke2Rlc3RpbmF0aW9uSWR9XCIuIElnbm9yaW5nIGl0LmA7XG5cbmNvbnN0IGlzRGVzdEludGdDb25maWdUcnV0aHk9ZGVzdEludGdDb25maWc9PiFpc1VuZGVmaW5lZChkZXN0SW50Z0NvbmZpZykmJkJvb2xlYW4oZGVzdEludGdDb25maWcpPT09dHJ1ZTtjb25zdCBpc0Rlc3RJbnRnQ29uZmlnRmFsc3k9ZGVzdEludGdDb25maWc9PiFpc1VuZGVmaW5lZChkZXN0SW50Z0NvbmZpZykmJkJvb2xlYW4oZGVzdEludGdDb25maWcpPT09ZmFsc2U7LyoqXG4gKiBGaWx0ZXJzIHRoZSBkZXN0aW5
1hdGlvbnMgdGhhdCBzaG91bGQgbm90IGJlIGxvYWRlZCBvciBmb3J3YXJkZWQgZXZlbnRzIHRvIGJhc2VkIG9uIHRoZSBpbnRlZ3JhdGlvbiBvcHRpb25zIChsb2FkIG9yIGV2ZW50cyBBUEkpXG4gKiBAcGFyYW0gaW50Z09wdHMgSW50ZWdyYXRpb24gb3B0aW9ucyBvYmplY3RcbiAqIEBwYXJhbSBkZXN0aW5hdGlvbnMgRGVzdGluYXRpb25zIGFycmF5XG4gKiBAcmV0dXJucyBEZXN0aW5hdGlvbnMgYXJyYXkgZmlsdGVyZWQgYmFzZWQgb24gdGhlIGludGVncmF0aW9uIG9wdGlvbnNcbiAqL2NvbnN0IGZpbHRlckRlc3RpbmF0aW9ucz0oaW50Z09wdHMsZGVzdGluYXRpb25zKT0+e2NvbnN0IGFsbE9wdFZhbD1pbnRnT3B0cy5BbGw/P3RydWU7cmV0dXJuIGRlc3RpbmF0aW9ucy5maWx0ZXIoZGVzdD0+e2NvbnN0IGRlc3REaXNwbGF5TmFtZT1kZXN0LmRpc3BsYXlOYW1lO2xldCBpc0Rlc3RFbmFibGVkO2lmKGFsbE9wdFZhbCl7aXNEZXN0RW5hYmxlZD10cnVlO2lmKGlzRGVzdEludGdDb25maWdGYWxzeShpbnRnT3B0c1tkZXN0RGlzcGxheU5hbWVdKSl7aXNEZXN0RW5hYmxlZD1mYWxzZTt9fWVsc2Uge2lzRGVzdEVuYWJsZWQ9ZmFsc2U7aWYoaXNEZXN0SW50Z0NvbmZpZ1RydXRoeShpbnRnT3B0c1tkZXN0RGlzcGxheU5hbWVdKSl7aXNEZXN0RW5hYmxlZD10cnVlO319cmV0dXJuIGlzRGVzdEVuYWJsZWQ7fSk7fTtcblxuY29uc3QgQUNUSVZFX0NBTVBBSUdOX0RJU1BMQVlfTkFNRT0nQWN0aXZlQ2FtcGFpZ24nO2NvbnN0IEFET0JFX0FOQUxZVElDU19ESVNQTEFZX05BTUU9J0Fkb2JlIEFuYWx5dGljcyc7Y29uc3QgQURST0xMX0RJU1BMQVlfTkFNRT0nQWRyb2xsJztjb25zdCBBTV9ESVNQTEFZX05BTUU9J0FtcGxpdHVkZSc7Y29uc3QgQVBQQ1VFU19ESVNQTEFZX05BTUU9J0FwcGN1ZXMnO2NvbnN0IEFYRVBUSU9fRElTUExBWV9OQU1FPSdBeGVwdGlvJztjb25zdCBCSU5HQURTX0RJU1BMQVlfTkFNRT0nQmluZyBBZHMnO2NvbnN0IEJSQVpFX0RJU1BMQVlfTkFNRT0nQnJhemUnO2NvbnN0IEJVR1NOQUdfRElTUExBWV9OQU1FPSdCdWdzbmFnJztjb25zdCBDSEFSVEJFQVRfRElTUExBWV9OQU1FPSdDaGFydGJlYXQnO2NvbnN0IENMRVZFUlRBUF9ESVNQTEFZX05BTUU9J0NsZXZlclRhcCc7Y29uc3QgQ09NTUFOREJBUl9ESVNQTEFZX05BTUU9J0NvbW1hbmRCYXInO2NvbnN0IENPTVNDT1JFX0RJU1BMQVlfTkFNRT0nQ29tc2NvcmUnO2NvbnN0IENPTlZFUlRGTE9XX0RJU1BMQVlfTkFNRT0nQ29udmVydGZsb3cnO2NvbnN0IENSSVRFT19ESVNQTEFZX05BTUU9J0NyaXRlbyc7Y29uc3QgQ1VTVE9NRVJJT19ESVNQTEFZX05BTUU9J0N1c3RvbWVyIElPJztjb25zdCBEQ01fRkxPT0RMSUdIVF9ESVNQTEFZX05BTUU9J0RDTSBGbG9vZGxpZ2h0Jztjb25zdCBEUklQX0RJU1BMQVlfTkFNRT0nRHJpcCc7Y29uc3QgRU5HQUdFX0RJU1BMQVlfTkFNRT0nRW5nYWdlJztjb25zdCBGQUNFQk9PS19QSVhFTF9ESVNQTEFZX05BTUU9J0ZhY2Vib29rIFBpeGVsJztjb25zdCBGVUxMU1RPUllfRElTUExBWV9OQU1FPSdGdWxsc3RvcnknO2NvbnN0IEdBX0RJU1BMQVlfTkFNRT0nR29vZ2xlIEFuYWx5dGljcyc7Y29uc3QgR0EzNjBfRElTUExBWV9OQU1FPSdHb29nbGUgQW5hbHl0aWNzIDM2MCc7Y29uc3QgR0E0X0RJU1BMQVlfTkFNRT0nR29vZ2xlIEFuYWx5dGljcyA0IChHQTQpJztjb25zdCBHQTRfVjJfRElTUExBWV9OQU1FPSdHb29nbGUgQW5hbHl0aWNzIDQgKEdBNCkgVjInO2NvbnN0IEdBSU5TSUdIVF9QWF9ESVNQTEFZX05BTUU9J0dhaW5zaWdodCBQWCc7Y29uc3QgR09PR0xFX09QVElNSVpFX0RJU1BMQVlfTkFNRT0nR29vZ2xlIE9wdGltaXplJztjb25zdCBHT09HTEVBRFNfRElTUExBWV9OQU1FPSdHb29nbGUgQWRzJzt
1jb25zdCBHVE1fRElTUExBWV9OQU1FPSdHb29nbGUgVGFnIE1hbmFnZXInO2NvbnN0IEhFQVBfRElTUExBWV9OQU1FPSdIZWFwLmlvJztjb25zdCBIT1RKQVJfRElTUExBWV9OQU1FPSdIb3RqYXInO2NvbnN0IEhTX0RJU1BMQVlfTkFNRT0nSHViU3BvdCc7Y29uc3QgSU5URVJDT01fRElTUExBWV9OQU1FPSdJbnRlcmNvbSc7Y29uc3QgSVRFUkFCTEVfRElTUExBWV9OQU1FPSdJdGVyYWJsZSc7Y29uc3QgSlVORV9ESVNQTEFZX05BTUU9J0pVTkUnO2NvbnN0IEtFRU5fRElTUExBWV9OQU1FPSdLZWVuJztjb25zdCBLSVNTTUVUUklDU19ESVNQTEFZX05BTUU9J0tpc3MgTWV0cmljcyc7Y29uc3QgS0xBVklZT19ESVNQTEFZX05BTUU9J0tsYXZpeW8nO2NvbnN0IExBVU5DSERBUktMWV9ESVNQTEFZX05BTUU9J0xhdW5jaERhcmtseSc7Y29uc3QgTEVNTklTS19ESVNQTEFZX05BTUU9J0xlbW5pc2sgTWFya2V0aW5nIEF1dG9tYXRpb24nO2NvbnN0IExJTktFRElOX0lOU0lHSFRfVEFHX0RJU1BMQVlfTkFNRT0nTGlua2VkaW4gSW5zaWdodCBUYWcnO2NvbnN0IExJVkVDSEFUX0RJU1BMQVlfTkFNRT0nbGl2ZWNoYXQnO2NvbnN0IExPVEFNRV9ESVNQTEFZX05BTUU9J0xvdGFtZSc7Y29uc3QgTFlUSUNTX0RJU1BMQVlfTkFNRT0nTHl0aWNzJztjb25zdCBNQVRPTU9fRElTUExBWV9OQU1FPSdNYXRvbW8nO2NvbnN0IE1JQ1JPU09GVF9DTEFSSVRZX0RJU1BMQVlfTkFNRT0nTWljcm9zb2Z0IENsYXJpdHknO2NvbnN0IE1PRU5HQUdFX0RJU1BMQVlfTkFNRT0nTW9FbmdhZ2UnO2NvbnN0IE1PVVNFRkxPV19ESVNQTEFZX05BTUU9J01vdXNlZmxvdyc7Y29uc3QgTVBfRElTUExBWV9OQU1FPSdNaXhwYW5lbCc7Y29uc3QgTklORVRBSUxFRF9ESVNQTEFZX05BTUU9J05pbmV0YWlsZWQnO2NvbnN0IE9MQVJLX0RJU1BMQVlfTkFNRT0nT2xhcmsnO2NvbnN0IE9QVElNSVpFTFlfRElTUExBWV9OQU1FPSdPcHRpbWl6ZWx5IFdlYic7Y29uc3QgUEVORE9fRElTUExBWV9OQU1FPSdQZW5kbyc7Y29uc3QgUElOVEVSRVNUX1RBR19ESVNQTEFZX05BTUU9J1BpbnRlcmVzdCBUYWcnO2NvbnN0IFBPRFNJR0hUU19ESVNQTEFZX05BTUU9J1BvZHNpZ2h0cyc7Y29uc3QgUE9TVF9BRkZJTElBVEVfUFJPX0RJU1BMQVlfTkFNRT0nUG9zdCBBZmZpbGlhdGUgUHJvJztjb25zdCBQT1NUSE9HX0RJU1BMQVlfTkFNRT0nUG9zdEhvZyc7Y29uc3QgUFJPRklUV0VMTF9ESVNQTEFZX05BTUU9J1Byb2ZpdFdlbGwnO2NvbnN0IFFVQUxBUk9PX0RJU1BMQVlfTkFNRT0nUXVhbGFyb28nO2NvbnN0IFFVQUxUUklDU19ESVNQTEFZX05BTUU9J1F1YWx0cmljcyc7Y29uc3QgUVVBTlRVTU1FVFJJQ19ESVNQTEFZX05BTUU9J1F1YW50dW0gTWV0cmljJztjb25zdCBRVU9SQV9QSVhFTF9ESVNQTEFZX05BTUU9J1F1b3JhIFBpeGVsJztjb25zdCBSRURESVRfUElYRUxfRElTUExBWV9OQU1FPSdSZWRkaXQgUGl4ZWwnO2NvbnN0IFJFRklORVJfRElTUExBWV9OQU1FPSdSZWZpbmVyJztjb25zdCBST0NLRVJCT1hfRElTUExBWV9OQU1FPSdSb2NrZXJib3gnO2NvbnN0IFJPTExCQVJfRElTUExBWV9OQU1FPSdyb2xsYmFyJztjb25zdCBTQVRJU01FVEVSX0RJU1BMQVlfTkFNRT0nU2F0aXNNZXRlcic7Y29uc3QgU0VORElOQkxVRV9ESVNQTEFZX05BTUU9J1NlbmRpbmJsdWUnO2NvbnN0IFNFTlRSWV9ESVNQTEFZX05BTUU9J1NlbnRyeSc7Y29uc3QgU0hZTkVUX0RJU1BMQVlfTkFNRT0nU2h5bmV0Jztjb25zdCBTTkFQX1BJWEVMX0RJU1BMQVlfTkFNRT0nU25hcCBQaXhlbCc7Y29uc3QgU05BUEVOR0FHRV9ESVNQTEFZX05BTUU9J1NuYXBFbmdhZ2UnO2NvbnN0IFNQT1RJRllQSVhFTF9ESVNQTEFZX05BTUU9J1Nwb3RpZnkgUGl4ZWwnO2NvbnN0IFNQUklHX0RJU1BMQVlfTkFNRT0nU3ByaWcnO2NvbnN0IFRJS1RPS19BRFNfRElTUExBWV9OQU1FPSdUaWtUb2sgQWRzJztjb25zdCBUVlNRVUFSRURfRElTUExBWV9OQU1FPSdUVlNxdWFyZWQnO2NvbnN0IFVTRVJQSUxPVF9ESVNQTEFZX05BTUU9J1VzZXJwaWxvdCc7Y29uc3QgVkVST19ESVNQTEFZX05BTUU9J1Zlcm8nO2NvbnN0IFZXT19ESVNQTEFZX05BTUU9J1ZXTyc7Y29uc3QgV09PUFJBX0RJU1BMQVlfTkFNRT0nV09PUFJBJztjb25zdCBYUElYRUxfRElTUExBWV9OQU1FPSdYUGl4ZWwnO2NvbnN0IFlBTkRFWF9NRVRSSUNBX0RJU1BMQVlfTkFNRT0nWWFuZGV4Lk1ldHJpY2EnO1xuXG5jb25zdCBESVJfTkFNRSQxaD0nSHViU3BvdCc7XG5cbmNvbnN0IERJUl9OQU1FJDFnPSdHQSc7XG5cbmNvbnN0IERJUl9OQU1FJDFmPSdIb3RqYXInO1xuXG5jb25zdCBESVJfTkFNRSQxZT0nR29vZ2xlQWRzJztcblxuY29uc3QgRElSX05BTUUkMWQ9J1ZXTyc7XG5cbmNvbnN0IERJUl9OQU1FJDFjPSdHb29nbGVUYWdNYW5hZ2VyJztcblxuY29uc3QgRElSX05BTUUkMWI9J0JyYXplJztcblxuY29uc3QgRElSX05BTUUkMWE9J0lOVEVSQ09NJztcblxuY29uc3QgRElSX05BTUUkMTk9J0tlZW4nO1xuXG5jb25zdCBESVJfTkFNRSQxOD0nS2lzc21ldHJpY3MnO1xuXG5jb25zdCBESVJfTkFNRSQxNz0nQ3VzdG9tZXJJTyc7XG5cbmNvbnN0IERJUl9OQU1FJDE2PSdDaGFydGJlYXQnO1xuXG5jb25zdCBESVJfTkFNRSQxNT0nRmFjZWJvb2tQaXhlbCc7XG5cbmNvbnN0IERJUl9OQU1FJDE0PSdMb3RhbWUnO1xuXG5jb25zdCBESVJfTkFNRSQxMz0nT3B0aW1pemVseSc7XG5cbmNvbnN0IERJUl9OQU1FJDEyPSdCdWdzbmFnJztcblxuY29uc3QgRElSX05BTUUkMTE9J0Z1bGxzdG9yeSc7XG5cbmNvbnN0IERJUl9OQU1FJDEwPSdUVlNxdWFyZWQnO1xuXG5jb25zdCBESVJfTkFNRSQkPSdHQTQnO1xuXG5jb25zdCBESVJfTkFNRSRfPSdHQTRfVjInO1xuXG5jb25zdCBESVJfTkFNRSRaPSdNb0VuZ2FnZSc7XG5cbmNvbnN0IERJUl9OQU1FJFk9J0FtcGxpdHVkZSc7XG5cbmNvbnN0IERJUl9OQU1FJFg9J1BlbmRvJztcblxuY29uc3QgRElSX05BTUUkVz0nTHl0aWNzJztcblxuY29uc3QgRElSX05BTUUkVj0nQXBwY3Vlcyc7XG5cbmNvbnN0IERJUl9OQU1FJFU9J1Bvc3Rob2cnO1xuXG5jb25zdCBESVJfTkFNRSRUPSdLbGF2aXlvJztcblxuY29uc3QgRElSX05BTUUkUz0nQ2xldmVydGFwJztcblxuY29uc3QgRElSX05BTUUkUj0nQmluZ0Fkcyc7XG5cbmNvbnN0IERJUl9OQU1FJFE9J1BpbnRlcmVzdFRhZyc7XG5cbmNvbnN0IERJUl9OQU1FJFA9J0Fkb2JlQW5hbHl0aWNzJztcblxuY29uc3QgRElSX05BTUUkTz0nTGlua2VkSW5JbnNpZ2h0VGFnJztcblxuY29uc3QgRElSX05BTUUkT
1j0nUmVkZGl0UGl4ZWwnO1xuXG5jb25zdCBESVJfTkFNRSRNPSdEcmlwJztcblxuY29uc3QgRElSX05BTUUkTD0nSGVhcCc7XG5cbmNvbnN0IERJUl9OQU1FJEs9J0NyaXRlbyc7XG5cbmNvbnN0IERJUl9OQU1FJEo9J01peHBhbmVsJztcblxuY29uc3QgRElSX05BTUUkST0nUXVhbHRyaWNzJztcblxuY29uc3QgRElSX05BTUUkSD0nUHJvZml0V2VsbCc7XG5cbmNvbnN0IERJUl9OQU1FJEc9J1NlbnRyeSc7XG5cbmNvbnN0IERJUl9OQU1FJEY9J1F1YW50dW1NZXRyaWMnO1xuXG5jb25zdCBESVJfTkFNRSRFPSdTbmFwUGl4ZWwnO1xuXG5jb25zdCBESVJfTkFNRSREPSdQb3N0QWZmaWxpYXRlUHJvJztcblxuY29uc3QgRElSX05BTUUkQz0nR29vZ2xlT3B0aW1pemUnO1xuXG5jb25zdCBESVJfTkFNRSRCPSdMYXVuY2hEYXJrbHknO1xuXG5jb25zdCBESVJfTkFNRSRBPSdHQTM2MCc7XG5cbmNvbnN0IERJUl9OQU1FJHo9J0Fkcm9sbCc7XG5cbmNvbnN0IERJUl9OQU1FJHk9J0RDTUZsb29kbGlnaHQnO1xuXG5jb25zdCBESVJfTkFNRSR4PSdNYXRvbW8nO1xuXG5jb25zdCBESVJfTkFNRSR3PSdWZXJvJztcblxuY29uc3QgRElSX05BTUUkdj0nTW91c2VmbG93JztcblxuY29uc3QgRElSX05BTUUkdT0nUm9ja2VyYm94JztcblxuY29uc3QgRElSX05BTUUkdD0nQ29udmVydEZsb3cnO1xuXG5jb25zdCBESVJfTkFNRSRzPSdTbmFwRW5nYWdlJztcblxuY29uc3QgRElSX05BTUUkcj0nTGl2ZUNoYXQnO1xuXG5jb25zdCBESVJfTkFNRSRxPSdTaHluZXQnO1xuXG5jb25zdCBESVJfTkFNRSRwPSdXb29wcmEnO1xuXG5jb25zdCBESVJfTkFNRSRvPSdSb2xsQmFyJztcblxuY29uc3QgRElSX05BTUUkbj0nUXVvcmFQaXhlbCc7XG5cbmNvbnN0IERJUl9OQU1FJG09J0p1bmUnO1xuXG5jb25zdCBESVJfTkFNRSRsPSdFbmdhZ2UnO1xuXG5jb25zdCBESVJfTkFNRSRrPSdJdGVyYWJsZSc7XG5cbmNvbnN0IERJUl9OQU1FJGo9J1lhbmRleE1ldHJpY2EnO1xuXG5jb25zdCBESVJfTkFNRSRpPSdSZWZpbmVyJztcblxuY29uc3QgRElSX05BTUUkaD0nUXVhbGFyb28nO1xuXG5jb25zdCBESVJfTkFNRSRnPSdQb2RzaWdodHMnO1xuXG5jb25zdCBESVJfTkFNRSRmPSdBeGVwdGlvJztcblxuY29uc3QgRElSX05BTUUkZT0nU2F0aXNtZXRlcic7XG5cbmNvbnN0IERJUl9OQU1FJGQ9J01pY3Jvc29mdENsYXJpdHknO1xuXG5jb25zdCBESVJfTkFNRSRjPSdTZW5kaW5ibHVlJztcblxuY29uc3QgRElSX05BTUUkYj0nT2xhcmsnO1xuXG5jb25zdCBESVJfTkFNRSRhPSdMZW1uaXNrJztcblxuY29uc3QgRElSX05BTUUkOT0nVGlrdG9rQWRzJztcblxuY29uc3QgRElSX05BTUUkOD0nQWN0aXZlQ2FtcGFpZ24nO1xuXG5jb25zdCBESVJfTkFNRSQ3PSdTcHJpZyc7XG5cbmNvbnN0IERJUl9OQU1FJDY9J1Nwb3RpZnlQaXhlbCc7XG5cbmNvbnN0IERJUl9OQU1FJDU9J0NvbW1hbmRCYXInO1xuXG5jb25zdCBESVJfTkFNRSQ0PSdOaW5ldGFpbGVkJztcblxuY29uc3QgRElSX05BTUUkMz0nR2FpbnNpZ2h0X1BYJztcblxuY29uc3QgRElSX05BTUUkMj0nWFBpeGVsJztcblxuY29uc3QgRElSX05BTUUkMT0nVXNlcnBpbG90JztcblxuY29uc3QgRElSX05BTUU9J0NvbXNjb3JlJztcblxuLy8gbWFwIG9mIHRoZSBkZXN0aW5hdGlvbiBkaXNwbGF5IG5hbWVzIHRvIHRoZSBkZXN0aW5hdGlvbiBkaXJlY3RvcnkgbmFtZXNcbi8vIEltcG9ydCBkaXNwbGF5IG5hbWVzIGFuZCBkaXJlY3RvcnkgbmFtZXMgZnJvbSBhbmFseXRpY3MtanMtaW50ZWdyYXRpb25zXG5jb25zdCBkZXN0RGlzcGxheU5hbWVzVG9GaWxlTmFtZXNNYXA9e1tIU19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDFoLFtHQV9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDFnLFtIT1RKQVJfRElTUExBWV9OQU1FXTpESVJfTkFNRSQxZixbR09PR0xFQURTX0RJU1BMQVlfTkFNRV06RElSX05BTUUkMWUsW1ZXT19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDFkLFtHVE1fRElTUExBWV9OQU1FXTpESVJfTkFNRSQxYyxbQlJBWkVfRElTUExBWV9OQU1FXTpESVJfTkFNRSQxYixbSU5URVJDT01fRElTUExBWV9OQU1FXTpESVJfTkFNRSQxYSxbS0VFTl9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDE5LFtLSVNTTUVUUklDU19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDE4LFtDVVNUT01FUklPX0RJU1BMQVlfTkFNRV06RElSX05BTUUkMTcsW0NIQVJUQkVBVF9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDE2LFtGQUNFQk9PS19QSVhFTF9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDE1LFtMT1RBTUVfRElTUExBWV9OQU1FXTpESVJfTkFNRSQxNCxbT1BUSU1JWkVMWV9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDEzLFtCVUdTTkFHX0RJU1BMQVlfTkFNRV06RElSX05BTUUkMTIsW0ZVTExTVE9SWV9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDExLFtUVlNRVUFSRURfRElTUExBWV9OQU1FXTpESVJfTkFNRSQxMCxbR0E0X0RJU1BMQVlfTkFNRV06RElSX05BTUUkJCxbR0E0X1YyX0RJU1BMQVlfTkFNRV06RElSX05BTUUkXyxbTU9FTkdBR0VfRElTUExBWV9OQU1FXTpESVJfTkFNRSRaLFtBTV9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJFksW1BFTkRPX0RJU1BMQVlfTkFNRV06RElSX05BTUUkWCxbTFlUSUNTX0RJU1BMQVlfTkFNRV06RElSX05BTUUkVyxbQVBQQ1VFU19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJFYsW1BPU1RIT0dfRElTUExBWV9OQU1FXTpESVJfTkFNRSRVLFtLTEFWSVlPX0RJU1BMQVlfTkFNRV06RElSX05BTUUkVCxbQ0xFVkVSVEFQX0RJU1BMQVlfTkFNRV06RElSX05BTUUkUyxbQklOR0FEU19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJFIsW1BJTlRFUkVTVF9UQUdfRElTUExBWV9OQU1FXTpESVJfTkFNRSRRLFtBRE9CRV9BTkFMWVRJQ1NfRElTUExBWV9OQU1FXTpESVJfTkFNRSRQLFtMSU5LRURJTl9JTlNJR0hUX1RBR19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJE8sW1JFRERJVF9QSVhFTF9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJE4sW0RSSVBfRElTUExBWV9OQU1FXTpESVJfTkFNRSRNLFtIRUFQX0RJU1BMQVlfTkFNRV06RElSX05BTUUkTCxbQ1JJVEVPX0RJU1BMQVlfTkFNRV06RElSX05BTUUkSyxbTVBfRElTUExBWV9OQU1FXTpESVJfTkFNRSRKLFtRVUFMVFJJQ1NfRElTUExBWV9OQU1FXTpESVJfTkFNRSRJLFtQUk9GSVRXRUxMX0RJU1BMQVlfTkFNRV06RElSX05BTUUkSCxbU0VOVFJZX0RJU1BMQVlfTkFNRV06RElSX05BTUUkRyxbUVVBTlRVTU1FVFJJQ19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJEYsW1NOQVBfUElYRUxfRElTUExBWV9OQU1FXTpESVJfTkFNRSRFLFtQT1NUX0FGRklMSUFURV9QUk9fRElTUExBWV9OQU1FXTpESVJfTkFNRSRELFtHT09HTEVfT1BUSU1JWkVfRElTUExBWV9OQU1FXTpESVJfTkFNRSRDLFtMQVVOQ0hEQVJLTFlfRElTUExBWV9OQU1FXTpESVJfTkFNRSRCLFtHQTM2MF9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJEEsW0FEUk9MTF9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJHosW0RDTV9GTE9PRExJR0hUX0RJU1BMQVlfTkFNRV06RElSX05BTUUkeSxbTUFUT01PX0RJU1BMQVlfTkFNRV06RElSX05BTUUkeCxbVkVST19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJHcsW01PVVNFRkxPV19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJHYsW1JPQ0tFUkJPWF9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJHUsW0NPTlZFUlRGTE9XX0RJU1BMQVlfTkFNRV06RElSX05BTUUkdCxbU05BUEVOR0FHRV9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJHMsW0xJVkVDSEFUX0RJU1BMQVlfTkFNRV06RElSX05BTUUkcixbU0hZTkVUX0RJU1BMQVlfTkFNRV06RElSX05BTUUkcSxbV09PUFJBX0RJ
1U1BMQVlfTkFNRV06RElSX05BTUUkcCxbUk9MTEJBUl9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJG8sW1FVT1JBX1BJWEVMX0RJU1BMQVlfTkFNRV06RElSX05BTUUkbixbSlVORV9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJG0sW0VOR0FHRV9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJGwsW0lURVJBQkxFX0RJU1BMQVlfTkFNRV06RElSX05BTUUkayxbWUFOREVYX01FVFJJQ0FfRElTUExBWV9OQU1FXTpESVJfTkFNRSRqLFtSRUZJTkVSX0RJU1BMQVlfTkFNRV06RElSX05BTUUkaSxbUVVBTEFST09fRElTUExBWV9OQU1FXTpESVJfTkFNRSRoLFtQT0RTSUdIVFNfRElTUExBWV9OQU1FXTpESVJfTkFNRSRnLFtBWEVQVElPX0RJU1BMQVlfTkFNRV06RElSX05BTUUkZixbU0FUSVNNRVRFUl9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJGUsW01JQ1JPU09GVF9DTEFSSVRZX0RJU1BMQVlfTkFNRV06RElSX05BTUUkZCxbU0VORElOQkxVRV9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJGMsW09MQVJLX0RJU1BMQVlfTkFNRV06RElSX05BTUUkYixbTEVNTklTS19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJGEsW1RJS1RPS19BRFNfRElTUExBWV9OQU1FXTpESVJfTkFNRSQ5LFtBQ1RJVkVfQ0FNUEFJR05fRElTUExBWV9OQU1FXTpESVJfTkFNRSQ4LFtTUFJJR19ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDcsW1NQT1RJRllQSVhFTF9ESVNQTEFZX05BTUVdOkRJUl9OQU1FJDYsW0NPTU1BTkRCQVJfRElTUExBWV9OQU1FXTpESVJfTkFNRSQ1LFtOSU5FVEFJTEVEX0RJU1BMQVlfTkFNRV06RElSX05BTUUkNCxbR0FJTlNJR0hUX1BYX0RJU1BMQVlfTkFNRV06RElSX05BTUUkMyxbWFBJWEVMX0RJU1BMQVlfTkFNRV06RElSX05BTUUkMixbVVNFUlBJTE9UX0RJU1BMQVlfTkFNRV06RElSX05BTUUkMSxbQ09NU0NPUkVfRElTUExBWV9OQU1FXTpESVJfTkFNRX07XG5cbi8qKlxuICogRGV0ZXJtaW5lcyBpZiB0aGUgZGVzdGluYXRpb24gU0RLIGNvZGUgaXMgZXZhbHVhdGVkXG4gKiBAcGFyYW0gZGVzdFNES0lkZW50aWZpZXIgVGhlIG5hbWUgb2YgdGhlIGdsb2JhbCBnbG9iYWxUaGlzIG9iamVjdCB0aGF0IGNvbnRhaW5zIHRoZSBkZXN0aW5hdGlvbiBTREtcbiAqIEBwYXJhbSBzZGtUeXBlTmFtZSBUaGUgbmFtZSBvZiB0aGUgZGVzdGluYXRpb24gU0RLIHR5cGVcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gKiBAcmV0dXJucyB0cnVlIGlmIHRoZSBkZXN0aW5hdGlvbiBTREsgY29kZSBpcyBldmFsdWF0ZWQsIGZhbHNlIG90aGVyd2lzZVxuICovY29uc3QgaXNEZXN0aW5hdGlvblNES01vdW50ZWQ9KGRlc3RTREtJZGVudGlmaWVyLHNka1R5cGVOYW1lLGxvZ2dlcik9PkJvb2xlYW4oZ2xvYmFsVGhpc1tkZXN0U0RLSWRlbnRpZmllcl0/LltzZGtUeXBlTmFtZV0/LnByb3RvdHlwZSYmdHlwZW9mIGdsb2JhbFRoaXNbZGVzdFNES0lkZW50aWZpZXJdW3Nka1R5cGVOYW1lXS5wcm90b3R5cGUuY29uc3RydWN0b3IhPT0ndW5kZWZpbmVkJyk7Y29uc3Qgd2FpdD10aW1lPT5uZXcgUHJvbWlzZS
1hyZXNvbHZlPT57Z2xvYmFsVGhpcy5zZXRUaW1lb3V0KHJlc29sdmUsdGltZSk7fSk7Y29uc3QgY3JlYXRlSW50ZWdyYXRpb25JbnN0YW5jZT0oZGVzdFNES0lkZW50aWZpZXIsc2RrVHlwZU5hbWUsZGVzdCxzdGF0ZSk9Pntjb25zdCBhbmFseXRpY3NJbnN0YW5jZT17bG9hZEludGVncmF0aW9uOnN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5sb2FkSW50ZWdyYXRpb24udmFsdWUsbG9nTGV2ZWw6c3RhdGUubGlmZWN5Y2xlLmxvZ0xldmVsLnZhbHVlLGxvYWRPbmx5SW50ZWdyYXRpb25zOnN0YXRlLmNvbnNlbnRzLnBvc3RDb25zZW50LnZhbHVlPy5pbnRlZ3JhdGlvbnM/P3N0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5sb2FkT25seUludGVncmF0aW9ucy52YWx1ZSwuLi5zdGF0ZS5saWZlY3ljbGUuc2FmZUFuYWx5dGljc0luc3RhbmNlLnZhbHVlfTtjb25zdCBpbnRlZ3JhdGlvbj1uZXcgZ2xvYmFsVGhpc1tkZXN0U0RLSWRlbnRpZmllcl1bc2RrVHlwZU5hbWVdKGNsb25lKGRlc3QuY29uZmlnKSxhbmFseXRpY3NJbnN0YW5jZSx7c2hvdWxkQXBwbHlEZXZpY2VNb2RlVHJhbnNmb3JtYXRpb246ZGVzdC5zaG91bGRBcHBseURldmljZU1vZGVUcmFuc2Zvcm1hdGlvbixwcm9wYWdhdGVFdmVudHNVbnRyYW5zZm9ybWVkT25FcnJvcjpkZXN0LnByb3BhZ2F0ZUV2ZW50c1VudHJhbnNmb3JtZWRPbkVycm9yLGRlc3RpbmF0aW9uSWQ6ZGVzdC5pZH0pO3JldHVybiBpbnRlZ3JhdGlvbjt9O2NvbnN0IGlzRGVzdGluYXRpb25SZWFkeT0oZGVzdCx0aW1lPTApPT5uZXcgUHJvbWlzZSgocmVzb2x2ZSxyZWplY3QpPT57aWYoZGVzdC5pbnRlZ3JhdGlvbj8uaXNSZWFkeSgpKXtyZXNvbHZlKHRydWUpO31lbHNlIGlmKHRpbWU+PVJFQURZX0NIRUNLX1RJTUVPVVRfTVMpe3JlamVjdChuZXcgRXJyb3IoSU5URUdSQVRJT05fUkVBRFlfVElNRU9VVF9FUlJPUihSRUFEWV9DSEVDS19USU1FT1VUX01TKSkpO31lbHNlIHtjb25zdCBjdXJUaW1lPURhdGUubm93KCk7d2FpdChSRUFEWV9DSEVDS19JTlRFUlZBTF9NUykudGhlbigoKT0+e2NvbnN0IGVsYXBzZWRUaW1lPURhdGUubm93KCktY3VyVGltZTtpc0Rlc3RpbmF0aW9uUmVhZHkoZGVzdCx0aW1lK2VsYXBzZWRUaW1lKS50aGVuKHJlc29sdmUpLmNhdGNoKGVycj0+cmVqZWN0KGVycikpO30pO319KTsvKipcbiAqIEV4dHJhY3RzIHRoZSBpbnRlZ3JhdGlvbiBjb25maWcsIGlmIGFueSwgZnJvbSB0aGUgZ2l2ZW4gZGVzdGluYXRpb25cbiAqIGFuZCBtZXJnZXMgaXQgd2l0aCB0aGUgY3VycmVudCBpbnRlZ3JhdGlvbnMgY29uZmlnXG4gKiBAcGFyYW0gZGVzdCBEZXN0aW5hdGlvbiBvYmplY3RcbiAqIEBwYXJhbSBjdXJEZXN0SW50Z0NvbmZpZyBDdXJyZW50IGRlc3RpbmF0aW9ucyBpbnRlZ3JhdGlvbiBjb25maWdcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIG9iamVjdFxuICogQHJldHVybnMgQ29tYmluZWQgZGVzdGluYXRpb25zIGludGVncmF0aW9ucyBjb25maWdcbiAqL2NvbnN0IGdldEN1bXVsYXRpdmVJbnRlZ3JhdGlvbnNDb25maWc9KGRlc3QsY3VyRGVzdEludGdDb25maWcsZXJyb3JIYW5kbGVyKT0+e2xldCBpbnRlZ3JhdGlvbnNDb25maWc9Y3VyRGVzdEludGdDb25maWc7aWYoaXNGdW5jdGlvbihkZXN0LmludGVncmF0aW9uPy5nZXREYXRhRm9ySW50ZWdyYXRpb25zT2JqZWN0KSl7dHJ5e2ludGVncmF0aW9uc0NvbmZpZz17Li4uY3VyRGVzdEludGdDb25maWcsLi4uZ2V0U2FuaXRpemVkVmFsdWUoZGVzdC5pbnRlZ3JhdGlvbi5nZXREYXRhRm9ySW50ZWdyYXRpb25zT2JqZWN0KCkpfTt9Y2F0Y2goZXJyKXtlcnJvckhhbmRsZXI/Lm9uRXJyb3Ioe2Vycm9yOmVycixjb250ZXh0OkRFVklDRV9NT0RFX0RFU1RJTkFUSU9OU19QTFVHSU4sY3VzdG9tTWVzc2FnZTpJTlRFR1JBVElPTlNfREFUQV9FUlJPUihkZXN0LnVzZXJGcmllbmRseUlkKSxncm91cGluZ0hhc2g6SU5URUdSQVRJT05TX0RBVEFfRVJST1IoZGVzdC5kaXNwbGF5TmFtZSksY2F0ZWdvcnk6SU5URUdSQVRJT05TX0VSUk9SX0NBVEVHT1JZfSk7fX1yZXR1cm4gaW50ZWdyYXRpb25zQ29uZmlnO307Y29uc3QgaW5pdGlhbGl6ZURlc3RpbmF0aW9uPShkZXN0LHN0YXRlLGRlc3RTREtJZGVudGlmaWVyLHNka1R5cGVOYW1lLGVycm9ySGFuZGxlcixsb2dnZXIpPT57dHJ5e2NvbnN0IGluaXRpYWxpemVkRGVzdGluYXRpb249Y2xvbmUoZGVzdCk7bGV0IGludGVncmF0aW9uPWluaXRpYWxpemVkRGVzdGluYXRpb24uaW50ZWdyYXRpb247aWYoaXNVbmRlZmluZWQoaW50ZWdyYXRpb24pKXtpbnRlZ3JhdGlvbj1jcmVhdGVJbnRlZ3JhdGlvbkluc3RhbmNlKGRlc3RTREtJZGVudGlmaWVyLHNka1R5cGVOYW1lLGRlc3Qsc3RhdGUpO2luaXRpYWxpemVkRGVzdGluYXRpb24uaW50ZWdyYXRpb249aW50ZWdyYXRpb247fWludGVncmF0aW9uLmluaXQ/LigpO2lzRGVzdGluYXRpb25SZWFkeShpbml0aWFsaXplZERlc3RpbmF0aW9uKS50aGVuKCgpPT57Ly8gQ29sbGVjdCB0aGUgaW50ZWdyYXRpb25zIGRhdGEgZm9yIHRoZSBoeWJyaWQgbW9kZSBkZXN0aW5hdGlvbnNcbmlmKGlzSHlicmlkTW9kZURlc3RpbmF0aW9uKGluaXRpYWxpemVkRGVzdGluYXRpb24pKXtzdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuaW50ZWdyYXRpb25zQ29uZmlnLnZhbHVlPWdldEN1bXVsYXRpdmVJbnRlZ3JhdGlvbnNDb25maWcoaW5pdGlhbGl6ZWREZXN0aW5hdGlvbixzdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuaW50ZWdyYXRpb25zQ29uZmlnLnZhbHVlLGVycm9ySGFuZGxlcik7fXN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5pbml0aWFsaXplZERlc3RpbmF0aW9ucy52YWx1ZT1bLi4uc3RhdGUubmF0aXZlRGVzdGluYXRpb25zLmluaXRpYWxpemVkRGVzdGluYXRpb25zLnZhbHVlLGluaXRpYWxpemVkRGVzdGluYXRpb25dO30pLmNhdGNoKGVycj0+e3N0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5mYWlsZWREZXN0aW5hdGlvbnMudmFsdWU9Wy4uLnN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5mYWlsZWREZXN0aW5hdGlvbnMudmFsdWUsZGVzdF07ZXJyb3JIYW5kbGVyPy5vbkVycm9yKHtlcnJvcjplcnIsY29udGV4dDpERVZJQ0VfTU9ERV9ERVNUSU5BVElPTlNfUExVR0lOLGN1c3RvbU1lc3NhZ2U6SU5URUdSQVRJT05fUkVBRFlfQ0hFQ0tfRVJST1IoZGVzdC51c2VyRnJpZW5kbHlJZCksZ3JvdXBpbmdIYXNoOklOVEVHUkFUSU9OX1JFQURZX0NIRUNLX0VSUk9SKGRlc3QuZGlzcGxheU5hbWUpLGNhdGVnb3J5OklOVEVHUkFUSU9OU19FUlJPUl9DQVRFR09SWX0pO30pO31jYXRjaChlcnIpe3N0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5mYWlsZWREZXN0aW5
1hdGlvbnMudmFsdWU9Wy4uLnN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5mYWlsZWREZXN0aW5hdGlvbnMudmFsdWUsZGVzdF07ZXJyb3JIYW5kbGVyPy5vbkVycm9yKHtlcnJvcjplcnIsY29udGV4dDpERVZJQ0VfTU9ERV9ERVNUSU5BVElPTlNfUExVR0lOLGN1c3RvbU1lc3NhZ2U6SU5URUdSQVRJT05fSU5JVF9FUlJPUihkZXN0LnVzZXJGcmllbmRseUlkKSxncm91cGluZ0hhc2g6SU5URUdSQVRJT05fSU5JVF9FUlJPUihkZXN0LmRpc3BsYXlOYW1lKSxjYXRlZ29yeTpJTlRFR1JBVElPTlNfRVJST1JfQ0FURUdPUll9KTt9fTsvKipcbiAqIEFwcGxpZXMgc291cmNlIGNvbmZpZ3VyYXRpb24gb3ZlcnJpZGVzIHRvIGRlc3RpbmF0aW9uc1xuICogQHBhcmFtIGRlc3RpbmF0aW9ucyBBcnJheSBvZiBkZXN0aW5hdGlvbnMgdG8gcHJvY2Vzc1xuICogQHBhcmFtIHNvdXJjZUNvbmZpZ092ZXJyaWRlIFNvdXJjZSBjb25maWd1cmF0aW9uIG92ZXJyaWRlIG9wdGlvbnNcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlIGZvciB3YXJuaW5nc1xuICogQHJldHVybnMgQXJyYXkgb2YgZGVzdGluYXRpb25zIHdpdGggb3ZlcnJpZGVzIGFwcGxpZWRcbiAqL2NvbnN0IGFwcGx5U291cmNlQ29uZmlndXJhdGlvbk92ZXJyaWRlcz0oZGVzdGluYXRpb25zLHNvdXJjZUNvbmZpZ092ZXJyaWRlLGxvZ2dlcik9PntpZighc291cmNlQ29uZmlnT3ZlcnJpZGU/LmRlc3RpbmF0aW9ucz8ubGVuZ3RoKXtyZXR1cm4gZmlsdGVyRGlzYWJsZWREZXN0aW5hdGlvbnMoZGVzdGluYXRpb25zKTt9Y29uc3QgZGVzdElkcz1kZXN0aW5hdGlvbnMubWFwKGRlc3Q9PmRlc3QuaWQpOy8vIEdyb3VwIG92ZXJyaWRlcyBieSBkZXN0aW5hdGlvbiBJRCB0byBzdXBwb3J0IGZ1dHVyZSBjbG9uaW5nXG4vLyBXaGVuIGNsb25pbmcgaXMgaW1wbGVtZW50ZWQsIG11bHRpcGxlIG92ZXJyaWRlcyB3aXRoIHNhbWUgSUQgd2lsbCBjcmVhdGUgbXVsdGlwbGUgZGVzdGluYXRpb24gaW5zdGFuY2VzXG5jb25zdCBvdmVycmlkZXNCeURlc3RJZD17fTtzb3VyY2VDb25maWdPdmVycmlkZS5kZXN0aW5hdGlvbnMuZm9yRWFjaChvdmVycmlkZT0+e2NvbnN0IGV4aXN0aW5nPW92ZXJyaWRlc0J5RGVzdElkW292ZXJyaWRlLmlkXXx8W107ZXhpc3RpbmcucHVzaChvdmVycmlkZSk7b3ZlcnJpZGVzQnlEZXN0SWRbb3ZlcnJpZGUuaWRdPWV4aXN0aW5nO30pOy8vIEZpbmQgdW5tYXRjaGVkIGRlc3RpbmF0aW9uIElEcyBhbmQgbG9nIHdhcm5pbmdcbmNvbnN0IHVubWF0Y2hlZElkcz1PYmplY3Qua2V5cyhvdmVycmlkZXNCeURlc3RJZCkuZmlsdGVyKGlkPT4hZGVzdElkcy5pbmNsdWRlcyhpZCkpO2lmKHVubWF0Y2hlZElkcy5sZW5ndGg+MCl7bG9nZ2VyPy53YXJuKGAke0RFVklDRV9NT0RFX0RFU1RJTkFUSU9OU19QTFVHSU59OjogU291cmNlIGNvbmZpZ3VyYXRpb24gb3ZlcnJpZGUgLSBVbmFibGUgdG8gaWRlbnRpZnkgdGhlIGRlc3RpbmF0aW9ucyB3aXRoIHRoZSBmb2xsb3dpbmcgSURzOiBcIiR7dW5tYXRjaGVkSWRzLmpvaW4oJywgJyl9XCJgKTt9Ly8gUHJvY2VzcyBvdmVycmlkZXMgYW5kIGFwcGx5IHRoZW0gdG8gZGVzdGluYXRpb25zXG5jb25zdCBwcm9jZXNzZWREZXN0aW5
1hdGlvbnM9W107ZGVzdGluYXRpb25zLmZvckVhY2goZGVzdD0+e2NvbnN0IG92ZXJyaWRlcz1vdmVycmlkZXNCeURlc3RJZFtkZXN0LmlkXTtpZighb3ZlcnJpZGVzfHxvdmVycmlkZXMubGVuZ3RoPT09MCl7Ly8gTm8gb3ZlcnJpZGUgZm9yIHRoaXMgZGVzdGluYXRpb24sIGtlZXAgb3JpZ2luYWxcbnByb2Nlc3NlZERlc3RpbmF0aW9ucy5wdXNoKGRlc3QpO3JldHVybjt9aWYob3ZlcnJpZGVzLmxlbmd0aD4xKXsvLyBNdWx0aXBsZSBvdmVycmlkZXMgZm9yIHRoZSBzYW1lIGRlc3RpbmF0aW9uLCBjcmVhdGUgY2xvbmVzXG5vdmVycmlkZXMuZm9yRWFjaCgob3ZlcnJpZGUsaW5kZXgpPT57Y29uc3Qgb3ZlcnJpZGRlbkRlc3RpbmF0aW9uPWFwcGx5T3ZlcnJpZGVUb0Rlc3RpbmF0aW9uKGRlc3Qsb3ZlcnJpZGUsYCR7aW5kZXgrMX1gKTtvdmVycmlkZGVuRGVzdGluYXRpb24uY2xvbmVkPXRydWU7b3ZlcnJpZGRlbkRlc3RpbmF0aW9uLm9yaWdpbmFsSWQ9ZGVzdC5pZDtwcm9jZXNzZWREZXN0aW5hdGlvbnMucHVzaChvdmVycmlkZGVuRGVzdGluYXRpb24pO30pO31lbHNlIHtjb25zdCBvdmVycmlkZGVuRGVzdGluYXRpb249YXBwbHlPdmVycmlkZVRvRGVzdGluYXRpb24oZGVzdCxvdmVycmlkZXNbMF0pO3Byb2Nlc3NlZERlc3RpbmF0aW9ucy5wdXNoKG92ZXJyaWRkZW5EZXN0aW5hdGlvbik7fX0pO3JldHVybiBmaWx0ZXJEaXNhYmxlZERlc3RpbmF0aW9ucyhwcm9jZXNzZWREZXN0aW5hdGlvbnMpO307LyoqXG4gKiBUaGlzIGZ1bmN0aW9uIGZpbHRlcnMgb3V0IGRpc2FibGVkIGRlc3RpbmF0aW9ucyBmcm9tIHRoZSBwcm92aWRlZCBhcnJheS5cbiAqIEBwYXJhbSBkZXN0aW5hdGlvbnMgQXJyYXkgb2YgZGVzdGluYXRpb25zIHRvIGZpbHRlclxuICogQHJldHVybnMgRmlsdGVyZWQgZGVzdGluYXRpb25zIHRvIG9ubHkgaW5jbHVkZSBlbmFibGVkIG9uZXNcbiAqL2NvbnN0IGZpbHRlckRpc2FibGVkRGVzdGluYXRpb25zPWRlc3RpbmF0aW9ucz0+ZGVzdGluYXRpb25zLmZpbHRlcihkZXN0PT5kZXN0LmVuYWJsZWQpOy8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBvdmVycmlkZSBjb25maWd1cmF0aW9uIHRvIGEgZGVzdGluYXRpb25cbiAqIEBwYXJhbSBkZXN0aW5hdGlvbiBPcmlnaW5hbCBkZXN0aW5hdGlvblxuICogQHBhcmFtIG92ZXJyaWRlIE92ZXJyaWRlIGNvbmZpZ3VyYXRpb25cbiAqIEBwYXJhbSBjbG9uZUlkIFVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgY2xvbmUsXG4gKiBpZiBwcm92aWRlZCwgdGhlIHZhbHVlIGlzIGFwcGVuZGVkIHRvIHRoZSBpZCBhbmQgdXNlckZyaWVuZGx5SWQgb2YgdGhlIGRlc3RpbmF0aW9uXG4gKiBAcmV0dXJucyBNb2RpZmllZCBkZXN0aW5hdGlvbiB3aXRoIG92ZXJyaWRlIGFwcGxpZWRcbiAqL2NvbnN0IGFwcGx5T3ZlcnJpZGVUb0Rlc3RpbmF0aW9uPShkZXN0aW5hdGlvbixvdmVycmlkZSxjbG9uZUlkKT0+ey8vIENoZWNrIGlmIGFueSBjaGFuZ2VzIGFyZSBuZWVkZWRcbmNvbnN0IGlzRW5hYmxlZFN0YXR1c0NoYW5nZWQ9aXNCb29sZWFuKG92ZXJyaWRlLmVuYWJsZWQpJiZvdmVycmlkZS5lbmFibGVkIT09ZGVzdGluYXRpb24uZW5hYmxlZDsvLyBDaGVjayBpZiBjb25maWcgaXMgcHJvdmlkZWRcbmNvbnN0IGlzQ29uZmlnQ2hhbmdlZD1pc05vbkVtcHR5T2JqZWN0KG92ZXJyaWRlLmNvbmZpZyk7Ly8gRGV0ZXJtaW5lIHRoZSBmaW5hbCBlbmFibGVkIHN0YXR1cyBhZnRlciBhcHBseWluZyBvdmVycmlkZXNcbmNvbnN0IGZpbmFsRW5hYmxlZFN0YXR1cz1pc0Jvb2xlYW4ob3ZlcnJpZGUuZW5hYmxlZCk/b3ZlcnJpZGUuZW5hYmxlZDpkZXN0aW5hdGlvbi5lbmFibGVkOy8vIENoZWNrIGlmIGNvbmZpZyB3aWxsIGFjdHVhbGx5IGJlIGFwcGxpZWQgKG9ubHkgZm9yIGVuYWJsZWQgZGVzdGluYXRpb25zKVxuY29uc3Qgd2lsbEFwcGx5Q29uZmlnPWlzQ29uZmlnQ2hhbmdlZCYmZmluYWxFbmFibGVkU3RhdHVzOy8vIElmIG5vIGNoYW5nZXMgbmVlZGVkIGFuZCBubyBjbG9uZUlkLCByZXR1cm4gb3JpZ2luYWwgZGVzdGluYXRpb25cbmlmKCFpc0VuYWJsZWRTdGF0dXNDaGFuZ2VkJiYhd2lsbEFwcGx5Q29uZmlnJiYhY2xvbmVJZCl7cmV0dXJuIGRlc3RpbmF0aW9uO30vLyBDbG9uZSBkZXN0aW5hdGlvbiBhbmQgYXBwbHkgb3ZlcnJpZGVzXG5jb25zdCBjbG9uZWREZXN0PWNsb25lKGRlc3RpbmF0aW9uKTtpZihjbG9uZUlkKXtjbG9uZWREZXN0LmlkPWAke2Rlc3RpbmF0aW9uLmlkfV8ke2Nsb25lSWR9YDtjbG9uZWREZXN0LnVzZXJGcmllbmRseUlkPWAke2Rlc3RpbmF0aW9uLnVzZXJGcmllbmRseUlkfV8ke2Nsb25lSWR9YDt9Ly8gQXBwbHkgZW5hYmxlZCBzdGF0dXMgb3ZlcnJpZGUgaWYgcHJvdmlkZWQgYW5kIGRpZmZlcmVudFxuaWYoaXNFbmFibGVkU3RhdHVzQ2hhbmdlZCl7Y2xvbmVkRGVzdC5lbmFibGVkPW92ZXJyaWRlLmVuYWJsZWQ7Ly8gTWFyayBhcyBvdmVycmlkZGVuXG5jbG9uZWREZXN0Lm92ZXJyaWRkZW49dHJ1ZTt9Ly8gQXBwbHkgY29uZmlnIG92ZXJyaWRlcyBpZiBwcm92aWRlZCBmb3IgZW5hYmxlZCBkZXN0aW5hdGlvblxuaWYod2lsbEFwcGx5Q29uZmlnKXsvLyBPdmVycmlkZSB0aGUgY29uZmlnIHdpdGggdGhlIG5ldyBjb25maWcgYW5kIHJlbW92ZSB1bmRlZmluZWQgYW5kIG51bGwgdmFsdWVzXG5jbG9uZWREZXN0LmNvbmZpZz1yZW1vdmVVbmRlZmluZWRBbmROdWxsVmFsdWVzKHsuLi5jbG9uZWREZXN0LmNvbmZpZywuLi5vdmVycmlkZS5jb25maWd9KTtjbG9uZWREZXN0Lm92ZXJyaWRkZW49dHJ1ZTt9cmV0dXJuIGNsb25lZERlc3Q7fTsvKipcbiAqIFZhbGlkYXRlcyBpZiB0aGUgZGVzdGluYXRpb24gSUQgYW5kIGN1c3RvbSBpbnRlZ3JhdGlvbiBhcmUgdmFsaWRcbiAqIEBwYXJhbSBkZXN0aW5hdGlvbklkIC0gVGhlIGRlc3RpbmF0aW9uIElEIHRvIHZhbGlkYXRlXG4gKiBAcGFyYW0gaW50ZWdyYXRpb24gLSBUaGUgY3VzdG9tIGludGVncmF0aW9uIGluc3RhbmNlXG4gKiBAcGFyYW0gc3RhdGUgLSBBcHBsaWNhdGlvbiBzdGF0ZVxuICogQHBhcmFtIGxvZ2dlciAtIExvZ2dlciBpbnN0YW5jZVxuICogQHJldHVybnMgRGVzdGluYXRpb24gb2JqZWN0IGlmIHRoZSBpbnRlZ3JhdGlvbiBpcyB2YWxpZCwgdW5kZWZpbmVkIG90aGVyd2lzZVxuICovY29uc3QgdmFsaWRhdGVDdXN0b21JbnRlZ3JhdGlvbj0oZGVzdGluYXRpb25JZCxpbnRlZ3JhdGlvbixzdGF0ZSxsb2dnZXIpPT57Y29uc3QgY29uZmlndXJlZERlc3RpbmF0aW9ucz1zdGF0ZS5uYXRpdmVEZXN0aW5
1hdGlvbnMuY29uZmlndXJlZERlc3RpbmF0aW9ucy52YWx1ZTtjb25zdCBkZXN0aW5hdGlvbj1jb25maWd1cmVkRGVzdGluYXRpb25zLmZpbmQoZGVzdD0+ZGVzdC5pZD09PWRlc3RpbmF0aW9uSWQmJmRlc3QuaXNDdXN0b21JbnRlZ3JhdGlvbj09PXRydWUpO2lmKCFkZXN0aW5hdGlvbil7bG9nZ2VyLmVycm9yKENVU1RPTV9JTlRFR1JBVElPTl9JTlZBTElEX0RFU1RJTkFUSU9OX0lEX0VSUk9SKERFVklDRV9NT0RFX0RFU1RJTkFUSU9OU19QTFVHSU4sZGVzdGluYXRpb25JZCkpO3JldHVybjt9Ly8gQ2hlY2sgaWYgYSBjdXN0b20gaW50ZWdyYXRpb24gaXMgYWxyZWFkeSBhZGRlZCBmb3IgdGhlIGRlc3RpbmF0aW9uIElEXG5pZihpc0RlZmluZWQoZGVzdGluYXRpb24uaW50ZWdyYXRpb24pKXtsb2dnZXIuZXJyb3IoQ1VTVE9NX0lOVEVHUkFUSU9OX0FMUkVBRFlfRVhJU1RTX0VSUk9SKERFVklDRV9NT0RFX0RFU1RJTkFUSU9OU19QTFVHSU4sZGVzdGluYXRpb25JZCkpO3JldHVybjt9Ly8gQ2hlY2sgaWYgdGhlIGludGVncmF0aW9uIGlzIGNvcnJlY3RseSBpbXBsZW1lbnRlZFxuaWYoaXNOdWxsT3JVbmRlZmluZWQoaW50ZWdyYXRpb24pfHwhaXNGdW5jdGlvbihpbnRlZ3JhdGlvbi5pc1JlYWR5KXx8aXNEZWZpbmVkKGludGVncmF0aW9uLmluaXQpJiYhaXNGdW5jdGlvbihpbnRlZ3JhdGlvbi5pbml0KXx8aXNEZWZpbmVkKGludGVncmF0aW9uLnRyYWNrKSYmIWlzRnVuY3Rpb24oaW50ZWdyYXRpb24udHJhY2spfHxpc0RlZmluZWQoaW50ZWdyYXRpb24ucGFnZSkmJiFpc0Z1bmN0aW9uKGludGVncmF0aW9uLnBhZ2UpfHxpc0RlZmluZWQoaW50ZWdyYXRpb24uaWRlbnRpZnkpJiYhaXNGdW5jdGlvbihpbnRlZ3JhdGlvbi5pZGVudGlmeSl8fGlzRGVmaW5lZChpbnRlZ3JhdGlvbi5ncm91cCkmJiFpc0Z1bmN0aW9uKGludGVncmF0aW9uLmdyb3VwKXx8aXNEZWZpbmVkKGludGVncmF0aW9uLmFsaWFzKSYmIWlzRnVuY3Rpb24oaW50ZWdyYXRpb24uYWxpYXMpKXtsb2dnZXIuZXJyb3IoSU5WQUxJRF9DVVNUT01fSU5URUdSQVRJT05fRVJST1IoREVWSUNFX01PREVfREVTVElOQVRJT05TX1BMVUdJTixkZXN0aW5hdGlvbklkKSk7cmV0dXJuO31yZXR1cm4gZGVzdGluYXRpb247fTsvKipcbiAqIFVwZGF0ZXMgZGVzdGluYXRpb24gb2JqZWN0IHdpdGggdGhlIGN1c3RvbSBpbnRlZ3JhdGlvblxuICogQHBhcmFtIGRlc3RpbmF0aW9uIC0gVGhlIGRlc3RpbmF0aW9uIG9iamVjdFxuICogQHBhcmFtIGludGVncmF0aW9uIC0gVGhlIGN1c3RvbSBpbnRlZ3JhdGlvbiBpbnN0YW5jZVxuICogQHBhcmFtIHN0YXRlIC0gQXBwbGljYXRpb24gc3RhdGVcbiAqIEBwYXJhbSBsb2dnZXIgLSBMb2dnZXIgaW5zdGFuY2VcbiAqIEByZXR1cm5zXG4gKi9jb25zdCBhZGRJbnRlZ3JhdGlvblRvRGVzdGluYXRpb249KGRlc3RpbmF0aW9uLGludGVncmF0aW9uLHN0YXRlLGxvZ2dlcik9Pntjb25zdCBhbmFseXRpY3NJbnN0YW5jZT1zdGF0ZS5saWZlY3ljbGUuc2FmZUFuYWx5dGljc0luc3RhbmNlLnZhbHVlOy8vIENyZWF0ZSBhIG5ldyBsb2dnZXIgb2JqZWN0IGZvciB0aGUgY3VzdG9tIGludGVncmF0aW9uXG4vLyB0byBhdm9pZCBjb25mbGljdHMgd2l0aCB0aGUgbWFpbiBsb2dnZXJcbmNvbnN0IGludGVncmF0aW9uTG9nZ2VyPWNsb25lKGxvZ2dlcik7Ly8gU2V0IHRoZSBzY29wZSB0byB0aGUgY3VzdG9tIGludGVncmF0aW9uIG5hbWVcbi8vIGZvciBlYXN5IGlkZW50aWZpY2F0aW9uIGluIHRoZSBsb2dzXG5pbnRlZ3JhdGlvbkxvZ2dlci5zZXRTY29wZShkZXN0aW5hdGlvbi5kaXNwbGF5TmFtZSk7Ly8gQmluZCBvbmx5IHRoZSBuZWNlc3NhcnkgbWV0aG9kcyB0byB0aGUgbmV3IGxvZ2dlciBvYmplY3RcbmNvbnN0IHNhZmVMb2dnZXI9e2xvZzppbnRlZ3JhdGlvbkxvZ2dlci5sb2cuYmluZChpbnRlZ3JhdGlvbkxvZ2dlciksaW5mbzppbnRlZ3JhdGlvbkxvZ2dlci5pbmZvLmJpbmQoaW50ZWdyYXRpb25Mb2dnZXIpLGRlYnVnOmludGVncmF0aW9uTG9nZ2VyLmRlYnVnLmJpbmQoaW50ZWdyYXRpb25Mb2dnZXIpLHdhcm46aW50ZWdyYXRpb25Mb2dnZXIud2Fybi5iaW5kKGludGVncmF0aW9uTG9nZ2VyKSxlcnJvcjppbnRlZ3JhdGlvbkxvZ2dlci5lcnJvci5iaW5kKGludGVncmF0aW9uTG9nZ2VyKSxzZXRNaW5Mb2dMZXZlbDppbnRlZ3JhdGlvbkxvZ2dlci5zZXRNaW5Mb2dMZXZlbC5iaW5kKGludGVncmF0aW9uTG9nZ2VyKX07Ly8gQ3JlYXRlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciB0aGUgY3VzdG9tIGludGVncmF0aW9uXG4vLyB0byBwYXNzIHRvIHRoZSBpbml0IG1ldGhvZFxuY29uc3QgY3VzdG9tRGVzdGluYXRpb25Db25maWc9Y2xvbmUoZGVzdGluYXRpb24uY29uZmlnKTsvLyBDcmVhdGUgYSB3cmFwcGVyIGFyb3VuZCB0aGUgY3VzdG9tIGludGVncmF0aW9uIEFQSXNcbi8vIHRvIG1ha2UgdGhlbSBjb25zaXN0ZW50IHdpdGggdGhlIHN0YW5kYXJkIGRldmljZSBtb2RlIGludGVncmF0aW9uc1xuZGVzdGluYXRpb24uaW50ZWdyYXRpb249ey4uLihpbnRlZ3JhdGlvbi5pbml0JiZ7aW5pdDooKT0+aW50ZWdyYXRpb24uaW5pdChjdXN0b21EZXN0aW5hdGlvbkNvbmZpZyxhbmFseXRpY3NJbnN0YW5jZSxzYWZlTG9nZ2VyKX0pLC4uLihpbnRlZ3JhdGlvbi50cmFjayYme3RyYWNrOmV2ZW50PT5pbnRlZ3JhdGlvbi50cmFjayhhbmFseXRpY3NJbnN0YW5jZSxzYWZlTG9nZ2VyLGV2ZW50KX0pLC4uLihpbnRlZ3JhdGlvbi5wYWdlJiZ7cGFnZTpldmVudD0+aW50ZWdyYXRpb24ucGFnZShhbmFseXRpY3NJbnN0YW5jZSxzYWZlTG9nZ2VyLGV2ZW50KX0pLC4uLihpbnRlZ3JhdGlvbi5pZGVudGlmeSYme2lkZW50aWZ5OmV2ZW50PT5pbnRlZ3JhdGlvbi5pZGVudGlmeShhbmFseXRpY3NJbnN0YW5jZSxzYWZlTG9nZ2VyLGV2ZW50KX0pLC4uLihpbnRlZ3JhdGlvbi5ncm91cCYme2dyb3VwOmV2ZW50PT5pbnRlZ3JhdGlvbi5ncm91cChhbmFseXRpY3NJbnN0YW5jZSxzYWZlTG9nZ2VyLGV2ZW50KX0pLC4uLihpbnRlZ3JhdGlvbi5hbGlhcyYme2FsaWFzOmV2ZW50PT5pbnRlZ3JhdGlvbi5hbGlhcyhhbmFseXRpY3NJbnN0YW5jZSxzYWZlTG9nZ2VyLGV2ZW50KX0pLGlzUmVhZHk6KCk9PmludGVncmF0aW9uLmlzUmVhZHkoYW5hbHl0aWNzSW5zdGFuY2Usc2FmZUxvZ2dlcil9O307XG5cbmNvbnN0IHBsdWdpbk5hbWUkYj0nRGV2aWNlTW9kZURlc3RpbmF0aW9ucyc7Y29uc3QgRGV2aWNlTW9kZURlc3RpbmF0aW9ucz0oKT0+KHtuYW1lOnBsdWdpbk5hbWUkYixpbml0aWFsaXplOnN0YXRlPT57c3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlPVsuLi5zdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWUscGx1Z2luTmFtZSRiXTt9LG5hdGl2ZURlc3RpbmF0aW9uczp7YWRkQ3VzdG9tSW50ZWdyYXRpb24oZGVzdGluYXRpb25JZCxpbnRlZ3JhdGlvbixzdGF0ZSxsb2dnZXIpe2NvbnN0IGRlc3RpbmF0aW9uPXZhbGlkYXRlQ3VzdG9tSW50ZWdyYXRpb24oZGVzdGluYXRpb25JZCxpbnRlZ3JhdGlvbixzdGF0ZSxsb2dnZXIpO2lmKCFkZXN0aW5
1hdGlvbil7cmV0dXJuO31hZGRJbnRlZ3JhdGlvblRvRGVzdGluYXRpb24oZGVzdGluYXRpb24saW50ZWdyYXRpb24sc3RhdGUsbG9nZ2VyKTsvLyBSZWZyZXNoIHRoZSBzdGF0ZSB2YWx1ZSB0byB0cmlnZ2VyIGFueSBlZmZlY3RzIHRoYXQgZGVwZW5kIG9uIGl0XG5zdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuY29uZmlndXJlZERlc3RpbmF0aW9ucy52YWx1ZT1bLi4uc3RhdGUubmF0aXZlRGVzdGluYXRpb25zLmNvbmZpZ3VyZWREZXN0aW5hdGlvbnMudmFsdWVdO30sc2V0QWN0aXZlRGVzdGluYXRpb25zKHN0YXRlLHBsdWdpbnNNYW5hZ2VyLGVycm9ySGFuZGxlcixsb2dnZXIpe3N0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5sb2FkSW50ZWdyYXRpb24udmFsdWU9c3RhdGUubG9hZE9wdGlvbnMudmFsdWUubG9hZEludGVncmF0aW9uOy8vIEZpbHRlciBkZXN0aW5hdGlvbiB0aGF0IGRvZXNuJ3QgaGF2ZSBtYXBwaW5nIGNvbmZpZy0tPkludGVncmF0aW9uIG5hbWVzXG5jb25zdCBjb25maWdTdXBwb3J0ZWREZXN0aW5hdGlvbnM9c3RhdGUubmF0aXZlRGVzdGluYXRpb25zLmNvbmZpZ3VyZWREZXN0aW5hdGlvbnMudmFsdWUuZmlsdGVyKGNvbmZpZ0Rlc3Q9PnsvLyBGaWx0ZXIgZW5hYmxlZCBvciBkaXNhYmxlZCBjdXN0b20gZGVzdGluYXRpb25zIHRoYXQgZG9uJ3QgaGF2ZSBhbiBpbnRlZ3JhdGlvbiBhZGRlZCB0byB0aGVtXG5pZihjb25maWdEZXN0LmlzQ3VzdG9tSW50ZWdyYXRpb24mJmlzVW5kZWZpbmVkKGNvbmZpZ0Rlc3QuaW50ZWdyYXRpb24pKXtpZihjb25maWdEZXN0LmVuYWJsZWQpe2xvZ2dlcj8ud2FybihJTlRFR1JBVElPTl9OT1RfQURERURfVE9fQ1VTVE9NX0RFU1RJTkFUSU9OX1dBUk5JTkcoREVWSUNFX01PREVfREVTVElOQVRJT05TX1BMVUdJTixjb25maWdEZXN0LmlkKSk7fXJldHVybiBmYWxzZTt9Ly8gRW5zdXJlIHRoZSBkZXN0aW5hdGlvbiBpcyBzdXBwb3J0ZWQgYnkgdGhlIFNES1xuLy8gb3IgaXQgaXMgYSBjdXN0b20gaW50ZWdyYXRpb25cbmlmKGNvbmZpZ0Rlc3QuaXNDdXN0b21JbnRlZ3JhdGlvbnx8ZGVzdERpc3BsYXlOYW1lc1RvRmlsZU5hbWVzTWFwW2NvbmZpZ0Rlc3QuZGlzcGxheU5hbWVdKXtyZXR1cm4gdHJ1ZTt9Y29uc3QgZXJyTWVzc2FnZT1JTlRFR1JBVElPTl9OT1RfU1VQUE9SVEVEX0VSUk9SKGNvbmZpZ0Rlc3QuZGlzcGxheU5hbWUpO2Vycm9ySGFuZGxlcj8ub25FcnJvcih7ZXJyb3I6bmV3IEVycm9yKGVyck1lc3NhZ2UpLGNvbnRleHQ6REVWSUNFX01PREVfREVTVElOQVRJT05TX1BMVUdJTixjYXRlZ29yeTpJTlRFR1JBVElPTlNfRVJST1JfQ0FURUdPUll9KTtyZXR1cm4gZmFsc2U7fSk7Ly8gQXBwbHkgc291cmNlIGNvbmZpZ3VyYXRpb24gb3ZlcnJpZGVzIGlmIHByb3ZpZGVkXG5jb25zdCBjb25maWd1cmVkRGVzdGluYXRpb25zPXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnNvdXJjZUNvbmZpZ3VyYXRpb25PdmVycmlkZT9hcHBseVNvdXJjZUNvbmZpZ3VyYXRpb25PdmVycmlkZXMoY29uZmlnU3VwcG9ydGVkRGVzdGluYXRpb25zLHN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnNvdXJjZUNvbmZpZ3VyYXRpb25PdmVycmlkZSxsb2dnZXIpOmZpbHRlckRpc2FibGVkRGVzdGluYXRpb25zKGNvbmZpZ1N1cHBvcnRlZERlc3RpbmF0aW9ucyk7Ly8gRmlsdGVyIGRlc3RpbmF0aW9ucyB0aGF0IGFyZSBkaXNhYmxlZCB0aHJvdWdoIGxvYWQgb3IgY29uc2VudCBBUEkgb3B0aW9uc1xuY29uc3QgZGVzdGluYXRpb25zVG9Mb2FkPWZpbHRlckRlc3RpbmF0aW9ucyhzdGF0ZS5jb25zZW50cy5wb3N0Q29uc2VudC52YWx1ZT8uaW50ZWdyYXRpb25zPz9zdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMubG9hZE9ubHlJbnRlZ3JhdGlvbnMudmFsdWUsY29uZmlndXJlZERlc3RpbmF0aW9ucyk7Y29uc3QgY29uc2VudGVkRGVzdGluYXRpb25zPWRlc3RpbmF0aW9uc1RvTG9hZC5maWx0ZXIoZGVzdD0+Ly8gaWYgY29uc2VudCBtYW5hZ2VyIGlzIG5vdCBjb25maWd1cmVkLCB0aGVuIGRlZmF1bHQgdG8gbG9hZCB0aGUgZGVzdGluYXRpb25cbnBsdWdpbnNNYW5hZ2VyLmludm9rZVNpbmdsZShgY29uc2VudE1hbmFnZXIuaXNEZXN0aW5hdGlvbkNvbnNlbnRlZGAsc3RhdGUsZGVzdC5jb25maWcsZXJyb3JIYW5kbGVyLGxvZ2dlcik/P3RydWUpOy8vIEFkZCB0aGUgZGlzdGlsbGVkIGRlc3RpbmF0aW9ucyB0byB0aGUgYWN0aXZlIGRlc3RpbmF0aW9ucyBsaXN0XG5zdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuYWN0aXZlRGVzdGluYXRpb25zLnZhbHVlPVsuLi5zdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuYWN0aXZlRGVzdGluYXRpb25zLnZhbHVlLC4uLmNvbnNlbnRlZERlc3RpbmF0aW9uc107fSxsb2FkKHN0YXRlLGV4dGVybmFsU3JjTG9hZGVyLGVycm9ySGFuZGxlcixsb2dnZXIsZXh0ZXJuYWxTY3JpcHRPbkxvYWQpe2NvbnN0IGludGVncmF0aW9uc0NETlBhdGg9c3RhdGUubGlmZWN5Y2xlLmludGVncmF0aW9uc0NETlBhdGgudmFsdWU7Y29uc3QgYWN0aXZlRGVzdGluYXRpb25zPXN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5hY3RpdmVEZXN0aW5hdGlvbnMudmFsdWU7YWN0aXZlRGVzdGluYXRpb25zLmZvckVhY2goZGVzdD0+e2NvbnN0IHNka05hbWU9ZGVzdERpc3BsYXlOYW1lc1RvRmlsZU5hbWVzTWFwW2Rlc3QuZGlzcGxheU5hbWVdO2NvbnN0IGRlc3RTREtJZGVudGlmaWVyPWAke3Nka05hbWV9X1JTYDsvLyB0aGlzIGlzIHRoZSBuYW1lIG9mIHRoZSBvYmplY3QgbG9hZGVkIG9uIHRoZSB3aW5kb3dcbmNvbnN0IHNka1R5cGVOYW1lPXNka05hbWU7aWYoc2RrVHlwZU5hbWUmJiFpc0Rlc3RpbmF0aW9uU0RLTW91bnRlZChkZXN0U0RLSWRlbnRpZmllcixzZGtUeXBlTmFtZSkpe2NvbnN0IGRlc3RTZGtVUkw9YCR7aW50ZWdyYXRpb25zQ0ROUGF0aH0vJHtzZGtOYW1lfS5taW4uanNgO2V4dGVybmFsU3JjTG9hZGVyLmxvYWRKU0ZpbGUoe3VybDpkZXN0U2RrVVJMLGlkOmRlc3QudXNlckZyaWVuZGx5SWQsY2FsbGJhY2s6ZXh0ZXJuYWxTY3JpcHRPbkxvYWQ/PygoaWQsZXJyKT0+e2lmKGVycil7Y29uc3QgY3VzdG9tTWVzc2FnZT1JTlRFR1JBVElPTl9TREtfTE9BRF9FUlJPUihkZXN0LmRpc3BsYXlOYW1lKTtlcnJvckhhbmRsZXI/Lm9uRXJyb3Ioe2Vycm9yOmVycixjb250ZXh0OkRFVklDRV9NT0RFX0RFU1RJTkFUSU9OU19QTFVHSU4sY3VzdG9tTWVzc2FnZSxncm91cGluZ0hhc2g6Y3VzdG9tTWVzc2FnZSxjYXRlZ29yeTpJTlRFR1JBVElPTlNfRVJST1JfQ0
1FURUdPUll9KTtzdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuZmFpbGVkRGVzdGluYXRpb25zLnZhbHVlPVsuLi5zdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuZmFpbGVkRGVzdGluYXRpb25zLnZhbHVlLGRlc3RdO31lbHNlIHtpbml0aWFsaXplRGVzdGluYXRpb24oZGVzdCxzdGF0ZSxkZXN0U0RLSWRlbnRpZmllcixzZGtUeXBlTmFtZSxlcnJvckhhbmRsZXIpO319KSx0aW1lb3V0OlNDUklQVF9MT0FEX1RJTUVPVVRfTVN9KTt9ZWxzZSB7aW5pdGlhbGl6ZURlc3RpbmF0aW9uKGRlc3Qsc3RhdGUsZGVzdFNES0lkZW50aWZpZXIsc2RrVHlwZU5hbWUsZXJyb3JIYW5kbGVyKTt9fSk7fX19KTtcblxuY29uc3QgREVGQVVMVF9UUkFOU0ZPUk1BVElPTl9RVUVVRV9PUFRJT05TPXttaW5SZXRyeURlbGF5OjUwMCxiYWNrb2ZmRmFjdG9yOjIsbWF4QXR0ZW1wdHM6M307Y29uc3QgUkVRVUVTVF9USU1FT1VUX01TJDE9MTAqMTAwMDsvLyAxMCBzZWNvbmRzXG5jb25zdCBRVUVVRV9OQU1FJDI9J3J1ZGRlcic7Y29uc3QgRE1UX1BMVUdJTj0nRGV2aWNlTW9kZVRyYW5zZm9ybWF0aW9uUGx1Z2luJztcblxuY29uc3QgRE1UX1RSQU5TRk9STUFUSU9OX1VOU1VDQ0VTU0ZVTF9FUlJPUj0oY29udGV4dCxkaXNwbGF5TmFtZSxpZCxyZWFzb24sYWN0aW9uKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1FdmVudCB0cmFuc2Zvcm1hdGlvbiB1bnN1Y2Nlc3NmdWwgZm9yIGRlc3RpbmF0aW9uIFwiJHtkaXNwbGF5TmFtZX1cIiB3aXRoIGlkIFwiJHtpZH1cIi4gUmVhc29uOiAke3JlYXNvbn0uICR7YWN0aW9ufS5gO2NvbnN0IERNVF9SRVFVRVNUX0ZBSUxFRF9FUlJPUj0oY29udGV4dCxkaXNwbGF5TmFtZSxpZCxzdGF0dXMsYWN0aW9uKT0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1bRGVzdGluYXRpb246ICR7ZGlzcGxheU5hbWV9IHdpdGggaWQgXCIke2lkfVwiXS5UcmFuc2Zvcm1hdGlvbiByZXF1ZXN0IGZhaWxlZCB3aXRoIHN0YXR1czogJHtzdGF0dXN9LiBSZXRyaWVzIGV4aGF1c3RlZC4gJHthY3Rpb259LmA7Y29uc3QgRE1UX0VYQ0VQVElPTj0oZGlzcGxheU5hbWUsaWQpPT5gVHJhbnNmb3JtYXRpb24gZmFpbGVkIGZvciBkZXN0aW5hdGlvbiBcIiR7ZGlzcGxheU5hbWV9XCIgd2l0aCBpZCBcIiR7aWR9XCJgO2NvbnN0IERNVF9TRVJWRVJfQUNDRVNTX0RFTklFRF9XQVJOSU5HPWNvbnRleHQ9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9VHJhbnNmb3JtYXRpb24gc2VydmVyIGFjY2VzcyBpcyBkZW5pZWQuIFRoZSBjb25maWd1cmF0aW9uIGRhdGEgc2VlbXMgdG8gYmUgb3V0IG9mIHN5bmMuIFNlbmRpbmcgdW50cmFuc2Zvcm1lZCBldmVudCB0byB0aGUgZGVzdGluYXRpb24uYDtcblxuLyoqXG4gKiBBIGhlbHBlciBmdW5jdGlvbiB0aGF0IHdpbGwgdGFrZSBydWRkZXJFdmVudCBhbmQgZ2VuZXJhdGVcbiAqIGEgYmF0Y2ggcGF5bG9hZCB0aGF0IHdpbGwgYmUgc2VudCB0byB0cmFuc2Zvcm1hdGlvbiBzZXJ2ZXJcbiAqXG4gKi9jb25zdCBjcmVhdGVQYXlsb2FkPShldmVudCxkZXN0aW5hdGlvbklkcyx0b2tlbik9Pntjb25zdCBvcmRlck5vPURhdGUubm93KCk7Y29uc3QgcGF5bG9hZD17bWV0YWRhdGE6eydDdXN0b20tQXV0aG9yaXphdGlvbic6dG9rZW59LGJhdGNoOlt7b3JkZXJObyxkZXN0aW5hdGlvbklkcyxldmVudH1dfTtyZXR1cm4gcGF5bG9hZDt9Oy8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRvIGdldCBkZXN0aW5hdGlvbiBpZGVudGlmaWVyIGNvbnNpc3RlbnRseVxuICovY29uc3QgZ2V0RGVzdGluYXRpb25JZD1kZXN0PT5kZXN0Lm9yaWdpbmFsSWQ/P2Rlc3QuaWQ7LyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gbG9nIG9uY2UgcGVyIGRlc3RpbmF0aW9uIHRvIGF2b2lkIGR1cGxpY2F0ZSBtZXNzYWdlc1xuICovY29uc3QgbG9nT25jZVBlckRlc3RpbmF0aW9uPShkZXN0aW5hdGlvbklkLGxvZ2dlZERlc3RpbmF0aW9ucyxsb2dGbik9PntpZighbG9nZ2VkRGVzdGluYXRpb25zLmluY2x1ZGVzKGRlc3RpbmF0aW9uSWQpKXtsb2dnZWREZXN0aW5hdGlvbnMucHVzaChkZXN0aW5hdGlvbklkKTtsb2dGbigpO319O2NvbnN0IHNlbmRUcmFuc2Zvcm1lZEV2ZW50VG9EZXN0aW5hdGlvbnM9KHN0YXRlLHBsdWdpbnNNYW5hZ2VyLGRlc3RpbmF0aW9uSWRzLHJlc3VsdCxzdGF0dXMsZXZlbnQsZXJyb3JIYW5kbGVyLGxvZ2dlcik9Pntjb25zdCBOQVRJVkVfREVTVF9FWFRfUE9JTlQ9J2Rlc3RpbmF0aW9uc0V2ZW50c1F1ZXVlLmVucXVldWVFdmVudFRvRGVzdGluYXRpb24nO2NvbnN0IEFDVElPTl9UT19TRU5EX1VOVFJBTlNGT1JNRURfRVZFTlQ9J1NlbmRpbmcgdW50cmFuc2Zvcm1lZCBldmVudCc7Y29uc3QgQUNUSU9OX1RPX0RST1BfRVZFTlQ9J0Ryb3BwaW5nIHRoZSBldmVudCc7Y29uc3QgZGVzdGluYXRpb25zPXN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5pbml0aWFsaXplZERlc3RpbmF0aW9ucy52YWx1ZS5maWx0ZXIoZD0+ZCYmZGVzdGluYXRpb25JZHMuaW5jbHVkZXMoZ2V0RGVzdGluYXRpb25JZChkKSkpO2NvbnN0IGxvZ2dlZERlc3RpbmF0aW9ucz1bXTtkZXN0aW5hdGlvbnMuZm9yRWFjaChkZXN0PT57dHJ5e2NvbnN0IGV2ZW50c1RvU2VuZD1bXTtjb25zdCBkZXN0aW5hdGlvbklkPWdldERlc3RpbmF0aW9uSWQoZGVzdCk7c3dpdGNoKHN0YXR1cyl7Y2FzZSAyMDA6e2NvbnN0IHJlc3BvbnNlPUpTT04ucGFyc2UocmVzdWx0KTtjb25zdCBkZXN0VHJhbnNmb3JtZWRSZXN1bHQ9cmVzcG9uc2UudHJhbnNmb3JtZWRCYXRjaC5maW5kKGU9PmUuaWQ9PT1kZXN0aW5
1hdGlvbklkKTtkZXN0VHJhbnNmb3JtZWRSZXN1bHQ/LnBheWxvYWQuZm9yRWFjaCh0RXZlbnQ9PntpZih0RXZlbnQuc3RhdHVzPT09JzIwMCcpe2V2ZW50c1RvU2VuZC5wdXNoKHRFdmVudC5ldmVudCk7fWVsc2Uge2xldCByZWFzb249J1Vua25vd24nO2lmKHRFdmVudC5zdGF0dXM9PT0nNDEwJyl7cmVhc29uPSdUcmFuc2Zvcm1hdGlvbiBpcyBub3QgYXZhaWxhYmxlJzt9bGV0IGFjdGlvbj1BQ1RJT05fVE9fRFJPUF9FVkVOVDtpZihkZXN0LnByb3BhZ2F0ZUV2ZW50c1VudHJhbnNmb3JtZWRPbkVycm9yPT09dHJ1ZSl7YWN0aW9uPUFDVElPTl9UT19TRU5EX1VOVFJBTlNGT1JNRURfRVZFTlQ7ZXZlbnRzVG9TZW5kLnB1c2goZXZlbnQpO2xvZ09uY2VQZXJEZXN0aW5hdGlvbihkZXN0aW5hdGlvbklkLGxvZ2dlZERlc3RpbmF0aW9ucywoKT0+e2xvZ2dlcj8ud2FybihETVRfVFJBTlNGT1JNQVRJT05fVU5TVUNDRVNTRlVMX0VSUk9SKERNVF9QTFVHSU4sZGVzdC5kaXNwbGF5TmFtZSxkZXN0aW5hdGlvbklkLHJlYXNvbixhY3Rpb24pKTt9KTt9ZWxzZSB7bG9nT25jZVBlckRlc3RpbmF0aW9uKGRlc3RpbmF0aW9uSWQsbG9nZ2VkRGVzdGluYXRpb25zLCgpPT57bG9nZ2VyPy5lcnJvcihETVRfVFJBTlNGT1JNQVRJT05fVU5TVUNDRVNTRlVMX0VSUk9SKERNVF9QTFVHSU4sZGVzdC5kaXNwbGF5TmFtZSxkZXN0aW5hdGlvbklkLHJlYXNvbixhY3Rpb24pKTt9KTt9fX0pO2JyZWFrO30vLyBUcmFuc2Zvcm1hdGlvbiBzZXJ2ZXIgYWNjZXNzIGRlbmllZFxuY2FzZSA0MDQ6e2xvZ09uY2VQZXJEZXN0aW5hdGlvbihkZXN0aW5hdGlvbklkLGxvZ2dlZERlc3RpbmF0aW9ucywoKT0+e2xvZ2dlcj8ud2FybihETVRfU0VSVkVSX0FDQ0VTU19ERU5JRURfV0FSTklORyhETVRfUExVR0lOKSk7fSk7ZXZlbnRzVG9TZW5kLnB1c2goZXZlbnQpO2JyZWFrO31kZWZhdWx0OntpZihkZXN0LnByb3BhZ2F0ZUV2ZW50c1VudHJhbnNmb3JtZWRPbkVycm9yPT09dHJ1ZSl7bG9nT25jZVBlckRlc3RpbmF0aW9uKGRlc3RpbmF0aW9uSWQsbG9nZ2VkRGVzdGluYXRpb25zLCgpPT57bG9nZ2VyPy53YXJuKERNVF9SRVFVRVNUX0ZBSUxFRF9FUlJPUihETVRfUExVR0lOLGRlc3QuZGlzcGxheU5hbWUsZGVzdGluYXRpb25JZCxzdGF0dXMsQUNUSU9OX1RPX1NFTkRfVU5UUkFOU0ZPUk1FRF9FVkVOVCkpO30pO2V2ZW50c1RvU2VuZC5wdXNoKGV2ZW50KTt9ZWxzZSB7bG9nT25jZVBlckRlc3RpbmF0aW9uKGRlc3RpbmF0aW9uSWQsbG9nZ2VkRGVzdGluYXRpb25zLCgpPT57bG9nZ2VyPy5lcnJvcihETVRfUkVRVUVTVF9GQUlMRURfRVJST1IoRE1UX1BMVUdJTixkZXN0LmRpc3BsYXlOYW1lLGRlc3RpbmF0aW9uSWQsc3RhdHVzLEFDVElPTl9UT19EUk9QX0VWRU5UKSk7fSk7fWJyZWFrO319ZXZlbnRzVG9TZW5kPy5mb3JFYWNoKHRFdmVudD0+e2lmKGlzTm9uRW1wdHlPYmplY3QodEV2ZW50KSl7cGx1Z2luc01hbmFnZXIuaW52b2tlU2luZ2xlKE5BVElWRV9ERVNUX0VYVF9QT0lOVCxzdGF0ZSx0RXZlbnQsZGVzdCxlcnJvckhhbmRsZXIsbG9nZ2VyKTt9fSk7fWNhdGNoKGVycil7ZXJyb3JIYW5kbGVyPy5vbkVycm9yKHtlcnJvcjplcnIsY29udGV4dDpETVRfUExVR0lOLGN1c3RvbU1lc3NhZ2U6RE1UX0VYQ0VQVElPTihkZXN0LmRpc3BsYXlOYW1lLGRlc3QuaWQpfSk7fX0pO307XG5cbmNvbnN0IHBsdWdpbk5hbWUkYT0nRGV2aWNlTW9kZVRyYW5zZm9ybWF0aW9uJztjb25zdCBEZXZpY2VNb2RlVHJhbnNmb3JtYXRpb249KCk9Pih7bmFtZTpwbHVnaW5OYW1lJGEsZGVwczpbXSxpbml0aWFsaXplOnN0YXRlPT57c3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlPVsuLi5zdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWUscGx1Z2luTmFtZSRhXTt9LHRyYW5zZm9ybUV2ZW50Ontpbml0KHN0YXRlLHBsdWdpbnNNYW5hZ2VyLGh0dHBDbGllbnQsc3RvcmVNYW5hZ2VyLGVycm9ySGFuZGxlcixsb2dnZXIpe2NvbnN0IHdyaXRlS2V5PXN0YXRlLmxpZmVjeWNsZS53cml0ZUtleS52YWx1ZTtodHRwQ2xpZW50LnNldEF1dGhIZWFkZXIod3JpdGVLZXkpO2NvbnN0IGV2ZW50c1F1ZXVlPW5ldyBSZXRyeVF1ZXVlKC8vIGFkZGluZyB3cml0ZSBrZXkgdG8gdGhlIHF1ZXVlIG5hbWUgdG8gYXZvaWQgY29uZmxpY3RzXG5gJHtRVUVVRV9OQU1FJDJ9XyR7d3JpdGVLZXl9YCxERUZBVUxUX1RSQU5TRk9STUFUSU9OX1FVRVVFX09QVElPTlMsKGl0ZW0sZG9uZSxxSXRlbVByb2Nlc3NJbmZvKT0+e2NvbnN0IHBheWxvYWQ9Y3JlYXRlUGF5bG9hZChpdGVtLmV2ZW50LGl0ZW0uZGVzdGluYXRpb25JZHMsaXRlbS50b2tlbik7aHR0cENsaWVudC5nZXRBc3luY0RhdGEoe3VybDpgJHtzdGF0ZS5saWZlY3ljbGUuYWN0aXZlRGF0YXBsYW5lVXJsLnZhbHVlfS90cmFuc2Zvcm1gLG9wdGlvbnM6e21ldGhvZDonUE9TVCcsZGF0YTpnZXRETVREZWxpdmVyeVBheWxvYWQocGF5bG9hZCksc2VuZFJhd0RhdGE6dHJ1ZX0saXNSYXdSZXNwb25zZTp0cnVlLHRpbWVvdXQ6UkVRVUVTVF9USU1FT1VUX01TJDEsY2FsbGJhY2s6KHJlc3VsdCxkZXRhaWxzKT0+e2NvbnN0IGlzUmV0cnlhYmxlPWlzRXJyUmV0cnlhYmxlKGRldGFpbHM/Lnhocj8uc3RhdHVzPz8wKTsvLyBJZiB0aGVyZSBpcyBubyBlcnJvciwgb3IgdGhlIGVycm9yIGlzIG5vdCByZXRyeWFibGUsIG9yIHRoZSBhdHRlbXB0IG51bWJlciBpcyB0aGUgbWF4IHJldHJ5IGF0dGVtcHRzLCB0aGVuIGF0dGVtcHQgc2VuZCB0aGUgZXZlbnQgdG8gdGhlIGRlc3RpbmF0aW9uc1xuaWYoaXNVbmRlZmluZWQoZGV0YWlscz8uZXJyb3IpfHwhaXNSZXRyeWFibGV8fHFJdGVtUHJvY2Vzc0luZm8ucmV0cnlBdHRlbXB0TnVtYmVyPT09cUl0ZW1Qcm9jZXNzSW5mby5tYXhSZXRyeUF0dGVtcHRzKXtzZW5kVHJhbnNmb3JtZWRFdmVudFRvRGVzdGluYXRpb25zKHN0YXRlLHBsdWdpbnNNYW5hZ2VyLGl0ZW0uZGVzdGluYXRpb25JZHMscmVzdWx0LGRldGFpbHM/Lnhocj8uc3RhdHVzLGl0ZW0uZXZlbnQsZXJyb3JIYW5kbGVyLGxvZ2dlcik7ZG9uZShudWxsKTt9ZWxzZSB7Ly8gUmVxdWV1ZSB0aGUgaXRlbSBhcyB0aGUgZXJyb3IgaXMgcmV0cnlhYmxlLlxuZG9uZShkZXRhaWxzKTt9fX0pO30sc3RvcmVNYW5hZ2VyLE1FTU9SWV9TVE9SQUdFKTtyZXR1cm4gZXZlbnRzUXVldWU7fSxlbnF1ZXVlKHN0YXRlLGV2ZW50c1F1ZXVlLGV2ZW50LGRlc3RpbmF0aW9ucyl7Ly8gQ29sbGVjdCB1bmlxdWUgZGVzdGluYXRpb24gSURzIGZvciB0cmFuc2Zvcm1hdGlvblxuLy8gRm9yIGNsb25lZCBkZXN0aW5
1hdGlvbnMsIGdldERlc3RpbmF0aW9uSWQgcmV0dXJucyBvcmlnaW5hbElkIHRvIGVuc3VyZSB1bmlxdWVuZXNzXG5jb25zdCBkZXN0aW5hdGlvbklkcz1bXTtkZXN0aW5hdGlvbnMuZm9yRWFjaChkPT57Y29uc3QgaWQ9Z2V0RGVzdGluYXRpb25JZChkKTtpZighZGVzdGluYXRpb25JZHMuaW5jbHVkZXMoaWQpKXtkZXN0aW5hdGlvbklkcy5wdXNoKGlkKTt9fSk7ZXZlbnRzUXVldWUuYWRkSXRlbSh7ZXZlbnQsZGVzdGluYXRpb25JZHMsdG9rZW46c3RhdGUuc2Vzc2lvbi5hdXRoVG9rZW4udmFsdWV9KTt9fX0pO1xuXG5jb25zdCBleHRlcm5hbGx5TG9hZGVkU2Vzc2lvblN0b3JhZ2VLZXlzPXtzZWdtZW50OidhanNfYW5vbnltb3VzX2lkJ307XG5cbmNvbnN0IGdldFNlZ21lbnRBbm9ueW1vdXNJZD1nZXRTdG9yYWdlRW5naW5lPT57bGV0IGFub255bW91c0lkOy8qKlxuICAgKiBGaXJzdCBjaGVjayB0aGUgbG9jYWwgc3RvcmFnZSBmb3IgYW5vbnltb3VzSWRcbiAgICogUmVmOiBodHRwczovL3NlZ21lbnQuY29tL2RvY3MvY29ubmVjdGlvbnMvc291cmNlcy9jYXRhbG9nL2xpYnJhcmllcy93ZWJzaXRlL2phdmFzY3JpcHQvI2lkZW50aWZ5XG4gICAqL2NvbnN0IGxzRW5naW5lPWdldFN0b3JhZ2VFbmdpbmUoTE9DQUxfU1RPUkFHRSk7aWYobHNFbmdpbmU/LmlzRW5hYmxlZCl7YW5vbnltb3VzSWQ9bHNFbmdpbmUuZ2V0SXRlbShleHRlcm5hbGx5TG9hZGVkU2Vzc2lvblN0b3JhZ2VLZXlzLnNlZ21lbnQpO30vLyBJZiBhbm9ueW1vdXNJZCBpcyBub3QgcHJlc2VudCBpbiBsb2NhbCBzdG9yYWdlIGFuZCBmaW5kIGl0IGluIGNvb2tpZXNcbmNvbnN0IGNzRW5naW5lPWdldFN0b3JhZ2VFbmdpbmUoQ09PS0lFX1NUT1JBR0UpO2lmKCFhbm9ueW1vdXNJZCYmY3NFbmdpbmU/LmlzRW5hYmxlZCl7YW5vbnltb3VzSWQ9Y3NFbmdpbmUuZ2V0SXRlbShleHRlcm5hbGx5TG9hZGVkU2Vzc2lvblN0b3JhZ2VLZXlzLnNlZ21lbnQpO31yZXR1cm4gYW5vbnltb3VzSWQ7fTtcblxuY29uc3QgcGx1Z2luTmFtZSQ5PSdFeHRlcm5hbEFub255bW91c0lkJztjb25zdCBFeHRlcm5hbEFub255bW91c0lkPSgpPT4oe25hbWU6cGx1Z2luTmFtZSQ5LGluaXRpYWxpemU6c3RhdGU9PntzdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWU9Wy4uLnN0YXRlLnBsdWdpbnMubG9hZGVkUGx1Z2lucy52YWx1ZSxwbHVnaW5OYW1lJDldO30sc3RvcmFnZTp7Z2V0QW5vbnltb3VzSWQoZ2V0U3RvcmFnZUVuZ2luZSxvcHRpb25zKXtsZXQgYW5vbnltb3VzSWQ7aWYob3B0aW9ucz8uYXV0b0NhcHR1cmU/LmVuYWJsZWQmJm9wdGlvbnMuYXV0b0NhcHR1cmUuc291cmNlKXtjb25zdCBzb3VyY2U9b3B0aW9ucy5hdXRvQ2FwdHVyZS5zb3VyY2UudG9Mb3dlckNhc2UoKTtpZighT2JqZWN0LmtleXMoZXh0ZXJuYWxseUxvYWRlZFNlc3Npb25TdG9yYWdlS2V5cykuaW5jbHVkZXMoc291cmNlKSl7cmV0dXJuIGFub255bW91c0lkO30vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgc29uYXJqcy9uby1zbWFsbC1zd2l0Y2hcbnN3aXRjaChzb3VyY2Upe2Nhc2UgJ3NlZ21lbnQnOmFub255bW91c0lkPWdldFNlZ21lbnRBbm9ueW1vdXNJZChnZXRTdG9yYWdlRW5naW5lKTticmVhazt9fXJldHVybiBhbm9ueW1vdXNJZDt9fX0pO1xuXG5jb25zdCBBTVBfTElOS0VSX0FOT05ZTU9VU19JRF9LRVk9J3JzX2FtcF9pZCc7XG5cbi8qIGVzbGludC1kaXNhYmxlIG5vLWJpdHdpc2UgKi8vKipcbiAqIGdlbmVyYXRlIGNyYyB0YWJsZVxuICpcbiAqIEBwYXJhbXMgbm9uZVxuICogQHJldHVybnMgYXJyYXkgb2YgQ1JDIHRhYmxlXG4gKi9jb25zdCBtYWtlQ1JDVGFibGU9KCk9Pntjb25zdCBjcmNUYWJsZT1bXTtsZXQgYztmb3IobGV0IG49MDtuPDI1NjtuKyspe2M9bjtmb3IobGV0IGs9MDtrPDg7aysrKXtjPWMmMT8weGVkYjg4MzIwXmM+Pj4xOmM+Pj4xO31jcmNUYWJsZVtuXT1jO31yZXR1cm4gY3JjVGFibGU7fTsvKipcbiAqIFRoaXMgaXMgdXRpbGl0eSBmdW5jdGlvbiBmb3IgY3JjMzIgYWxnb3JpdGhtXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHN0clxuICogQHJldHVybnMge251bWJlcn0gY3JjMzJcbiAqL2NvbnN0IGNyYzMyPXN0cj0+e2NvbnN0IGNyY1RhYmxlPW1ha2VDUkNUYWJsZSgpO2xldCBjcmM9MF4tMTtmb3IobGV0IGk9MDtpPHN0ci5sZW5ndGg7aSsrKXsvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50XG4vLyBAdHMtaWdub3JlXG5jcmM9Y3JjPj4+OF5jcmNUYWJsZVsoY3JjXnN0ci5jaGFyQ29kZUF0KGkpKSYweGZmXTt9cmV0dXJuIChjcmNeLTEpPj4+MDt9O1xuXG4vKipcbiAqIEFuIGludGVyZmFjZSB0byBmZXRjaCB1c2VyIGRldmljZSBkZXRhaWxzLlxuICovY29uc3QgVVNFUl9JTlRFUkZBQ0U9ey8qKlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSB1c2VyIGxhbmd1YWdlXG4gICAqL2dldFVzZXJMYW5ndWFnZTooKT0+bmF2aWdhdG9yPy5sYW5ndWFnZSwvKipcbiAgICogQHJldHVybnMge3N0cmluZ30gdXNlckFnZW50XG4gICAqL2dldFVzZXJBZ2VudDooKT0+bmF2aWdhdG9yPy51c2VyQWdlbnR9O1xuXG4vKipcbiAqIFRoaXMgaXMgdXRpbGl0eSBmdW5jdGlvbiBmb3IgZGVjb2RpbmcgZnJvbSBiYXNlIDY0IHRvIHV0ZjhcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyIGJhc2U2NFxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd9IHV0ZjhcbiAqL2NvbnN0IGI2NERlY29kZVVuaWNvZGU9c3RyPT4vLyBHb2luZyBiYWNrd2FyZHM6IGZyb20gYnl0ZXN0cmVhbSwgdG8gcGVyY2VudC1lbmNvZGluZywgdG8gb3JpZ2luYWwgc3RyaW5nLlxuZGVjb2RlVVJJQ29tcG9uZW50KGdsb2JhbFRoaXMuYXRvYihzdHIpLnNwbGl0KCcnKS5tYXAoYz0+e2NvbnN0IHBlcmNlbnRFbmNvZGluZ0NoYXI9YDAwJHtjLmNoYXJDb2RlQXQoMCkudG9TdHJpbmcoMTYpfWA7cmV0dXJuIGAlJHtwZXJjZW50RW5jb2RpbmdDaGFyLnNsaWNlKC0yKX1gO30pLmpvaW4oJycpKTsvKipcbiAqIFRoaXMgaXMgdXRpbGl0eSBmdW5jdGlvbiBmb3IgZGVjb2RpbmcgZnJvbSBiYXNlIDY0IHRvIHV0ZjhcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gZGF0YVxuICpcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL2NvbnN0IGRlY29kZT0oZGF0YT0nJyk9Pntjb25zdCBkZWNvZGVkRGF0YT1kYXRhLmVuZHNXaXRoKCcuLicpP2RhdGEuc3Vic3RyaW5nKDAsZGF0YS5sZW5ndGgtMik6ZGF0YTtyZXR1cm4gYjY0RGVjb2RlVW5pY29kZShkZWNvZGVkRGF0YSk7fTtcblxuY29uc3QgS0VZX1ZBTElEQVRPUj0vXltcXHcuLV0rJC87Y29uc3QgQ0hFQ0tTVU1fT0ZGU0VUX01BWF9NSU49MTtjb25zdCBWQUxJRF9WRVJTSU9OPTE7Y29uc3QgREVMSU1JVEVSPScqJzsvKipcbiAqIFBhcnNlIHRoZSBsaW5rZXIgcGFyYW0gdmFsdWUgdG8gdmVyc2lvbiBjaGVja3N1bSBhbmQgc2VyaWFsaXplZFBhcmFtc1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZVxuICpcbiAqIEByZXR1cm4gez9PYmplY3R9XG4gKi9jb25zdCBwYXJzZUxpbmtlclBhcmFtVmFsdWU9dmFsdWU9Pntjb25zdCBwYXJ0cz12YWx1ZS
15zcGxpdChERUxJTUlURVIpO2NvbnN0IGlzRXZlbj1wYXJ0cy5sZW5ndGglMj09PTA7aWYocGFydHMubGVuZ3RoPDR8fCFpc0V2ZW4pey8vIEZvcm1hdCA8dmVyc2lvbj4qPGNoZWNrc3VtPio8a2V5MT4qPHZhbHVlMT5cbi8vIE5vdGU6IGxpbmtlciBtYWtlcyBzdXJlIHRoZXJlJ3MgYXQgbGVhc3Qgb25lIHBhaXIgb2Ygbm9uIGVtcHR5IGtleSB2YWx1ZVxuLy8gTWFrZSBzdXJlIHRoZXJlIGlzIGF0IGxlYXN0IHRocmVlIGRlbGltaXRlcnMuXG5yZXR1cm4gbnVsbDt9Y29uc3QgdmVyc2lvbj1OdW1iZXIocGFydHMuc2hpZnQoKSk7aWYodmVyc2lvbiE9PVZBTElEX1ZFUlNJT04pe3JldHVybiBudWxsO31jb25zdCBjaGVja3N1bT1wYXJ0cy5zaGlmdCgpO2NvbnN0IHNlcmlhbGl6ZWRJZHM9cGFydHMuam9pbihERUxJTUlURVIpO3JldHVybiB7Y2hlY2tzdW06Y2hlY2tzdW0/PycnLHNlcmlhbGl6ZWRJZHN9O307LyoqXG4gKiBEZXNlcmlhbGl6ZSB0aGUgc2VyaWFsaXplZElkcyBhbmQgcmV0dXJuIGtleVZhbHVlIHBhaXJzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzZXJpYWxpemVkSWRzXG4gKlxuICogQHJldHVybiB7IU9iamVjdDxzdHJpbmcsIHN0cmluZz59XG4gKi9jb25zdCBkZXNlcmlhbGl6ZT1zZXJpYWxpemVkSWRzPT57aWYoIXNlcmlhbGl6ZWRJZHMpe3JldHVybiB7fTt9Y29uc3Qga2V5VmFsdWVQYWlycz17fTtjb25zdCBwYXJhbXM9c2VyaWFsaXplZElkcy5zcGxpdChERUxJTUlURVIpO2ZvcihsZXQgaT0wO2k8cGFyYW1zLmxlbmd0aDtpKz0yKXtjb25zdCBrZXk9cGFyYW1zW2ldO2NvbnN0IHZhbGlkPUtFWV9WQUxJREFUT1IudGVzdChrZXkpO2lmKHZhbGlkKXtrZXlWYWx1ZVBhaXJzW2tleV09ZGVjb2RlKHBhcmFtc1tpKzFdKTt9fXJldHVybiBrZXlWYWx1ZVBhaXJzO307LyoqXG4gKiBHZW5lcmF0ZXMgYSBzZW1pLXVuaXF1ZSB2YWx1ZSBmb3IgcGFnZSB2aXNpdG9yLlxuICpcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL2NvbnN0IGdldEZpbmdlcnByaW50PSh1c2VyQWdlbnQsbGFuZ3VhZ2UpPT57Y29uc3QgZGF0ZT1uZXcgRGF0ZSgpO2NvbnN0IHRpbWV6b25lPWRhdGUuZ2V0VGltZXpvbmVPZmZzZXQoKTtyZXR1cm4gW3VzZXJBZ2VudCx0aW1lem9uZSxsYW5ndWFnZV0uam9pbihERUxJTUlURVIpO307LyoqXG4gKiBSb3VuZGVkIHRpbWUgdXNlZCB0byBjaGVjayBpZiB0MiAtIHQxIGlzIHdpdGhpbiBvdXIgdGltZSB0b2xlcmFuY2UuXG4gKiBUaW1lc3RhbXAgaW4gbWludXRlcywgZmxvb3JlZC5cbiAqXG4gKiBAcmV0dXJuIHtudW1iZXJ9XG4gKi9jb25zdCBnZXRNaW5TaW5jZUVwb2NoPSgpPT5NYXRoLmZsb29yKERhdGUubm93KCkvNjAwMDApOy8qKlxuICogQ3JlYXRlIGEgdW5pcXVlIGNoZWNrc3VtIGhhc2hpbmcgdGhlIGZpbmdlcnByaW50IGFuZCBhIGZldyBvdGhlciB2YWx1ZXMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHNlcmlhbGl6ZWRJZHNcbiAqIEBwYXJhbSB7bnVtYmVyPX0gb3B0T2Zmc2V0TWluXG4gKiBAcGFyYW0ge3N0cmluZ30gdXNlckFnZW50XG4gKiBAcGFyYW0ge3N0cmluZ30gbGFuZ3VhZ2VcbiAqXG4gKiBAcmV0dXJuIHtzdHJpbmd9XG4gKi9jb25zdCBnZXRDaGVja1N1bT0oc2VyaWFsaXplZElkcyxvcHRPZmZzZXRNaW4sdXNlckFnZW50LGxhbmd1YWdlKT0+e2NvbnN0IGZpbmdlcnByaW50PWdldEZpbmdlcnByaW50KHVzZXJBZ2VudCxsYW5ndWFnZSk7Y29uc3Qgb2Zmc2V0PW9wdE9mZnNldE1pbnx8MDtjb25zdCB0aW1lc3RhbXA9Z2V0TWluU2luY2VFcG9jaCgpLW9mZnNldDtjb25zdCBjcmM9Y3JjMzIoW2ZpbmdlcnByaW50LHRpbWVzdGFtcCxzZXJpYWxpemVkSWRzXS5qb2luKERFTElNSVRFUikpOy8vIEVuY29kZWQgdG8gYmFzZTM2IGZvciBmZXdlciBieXRlcy5cbnJldHVybiBjcmMudG9TdHJpbmcoMzYpO307LyoqXG4gKiBDaGVjayBpZiB0aGUgY2hlY2tzdW0gaXMgdmFsaWQgd2l0aCB0aW1lIG9mZnNldCB0b2xlcmFuY2UuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHNlcmlhbGl6ZWRJZHNcbiAqIEBwYXJhbSB7c3RyaW5nfSBjaGVja3N1bVxuICpcbiAqIEByZXR1cm4ge2Jvb2xlYW59XG4gKi9jb25zdCBpc0NoZWNrU3VtVmFsaWQ9KHNlcmlhbGl6ZWRJZHMsY2hlY2tzdW0pPT57Y29uc3QgdXNlckFnZW50PVVTRVJfSU5URVJGQUNFLmdldFVzZXJBZ2VudCgpO2NvbnN0IGxhbmd1YWdlPVVTRVJfSU5URVJGQUNFLmdldFVzZXJMYW5ndWFnZSgpO2ZvcihsZXQgaT0wO2k8PUNIRUNLU1VNX09GRlNFVF9NQVhfTUlOO2krPTEpe2NvbnN0IGNhbGN1bGF0ZUNoZWNrU3VtPWdldENoZWNrU3VtKHNlcmlhbGl6ZWRJZHMsaSx1c2VyQWdlbnQsbGFuZ3VhZ2UpO2lmKGNhbGN1bGF0ZUNoZWNrU3VtPT09Y2hlY2tzdW0pe3JldHVybiB0cnVlO319cmV0dXJuIGZhbHNlO307LyoqXG4gKiBBTVAgTGlua2VyIFBhcnNlciAod29ya3MgZm9yIFJ1ZGRlciwgR0Egb3IgYW55IG90aGVyIGxpbmtlciBjcmVhdGVkIGJ5IGZvbGxvd2luZyBHb29nbGUncyBsaW5rZXIgc3RhbmRhcmQuKVxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZVxuICpcbiAqIEByZXR1cm4gez9PYmplY3Q8c3RyaW5nLCBzdHJpbmc+fVxuICovY29uc3QgcGFyc2VMaW5rZXI9dmFsdWU9Pntjb25zdCBsaW5rZXJPYmo9cGFyc2VMaW5rZXJQYXJhbVZhbHVlKHZhbHVlKTtpZighbGlua2VyT2JqKXtyZXR1cm4gbnVsbDt9Y29uc3R7Y2hlY2tzdW0sc2VyaWFsaXplZElkc309bGlua2VyT2JqO2lmKCFzZXJpYWxpemVkSWRzfHwhY2hlY2tzdW18fCFpc0NoZWNrU3VtVmFsaWQoc2VyaWFsaXplZElkcyxjaGVja3N1bSkpe3JldHVybiBudWxsO31yZXR1cm4gZGVzZXJpYWxpemUoc2VyaWFsaXplZElkcyk7fTtcblxuY29uc3QgcGx1Z2luTmFtZSQ4PSdHb29nbGVMaW5rZXInO2NvbnN0IEdvb2dsZUxpbmtlcj0oKT0+KHtuYW1lOnBsdWdpbk5hbWUkOCxpbml0aWFsaXplOnN0YXRlPT57c3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlPVsuLi5zdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWUscGx1Z2luTmFtZSQ4XTt9LHVzZXJTZXNzaW9uOnthbm9ueW1vdXNJZEdvb2dsZUxpbmtlcihydWRkZXJBbXBMaW5rZXJQYXJhbSl7aWYoIXJ1ZGRlckFtcExpbmtlclBhcmFtKXtyZXR1cm4gbnVsbDt9Y29uc3QgcGFyc2VkQW5vbnltb3VzSWRPYmo9cnVkZGVyQW1wTGlua2VyUGFyYW0/cGFyc2VMaW5rZXIocnVkZGVyQW1wTGlua2VyUGFyYW0pOm51bGw7cmV0dXJuIHBhcnNlZEFub255bW91c0lkT2JqP3BhcnNlZEFub255bW91c0lkT2JqW0FNUF9MSU5LRVJfQU5PTllNT1VTX0lEX0tFWV06bnVsbDt9fX0pO1xuXG5jb25zdCBJVUJFTkRBX0NPTlNFTlRfQ09PS0lFX1JFQURfRVJST1I9Y29udGV4dD0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1GYWlsZWQgdG8gcmVhZCB0aGUgY29uc2VudCBjb29raWUuYDtjb25zdCBJVUJFTkRBX0NPTlNFTlRfQ09PS0lFX1BBUlNFX0VSUk9SPWNvbn
1RleHQ9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9RmFpbGVkIHRvIHBhcnNlIHRoZSBjb25zZW50IGNvb2tpZS5gO2NvbnN0IERFU1RJTkFUSU9OX0NPTlNFTlRfU1RBVFVTX0VSUk9SJDI9YEZhaWxlZCB0byBkZXRlcm1pbmUgdGhlIGNvbnNlbnQgc3RhdHVzIGZvciB0aGUgZGVzdGluYXRpb24uIFBsZWFzZSBjaGVjayB0aGUgZGVzdGluYXRpb24gY29uZmlndXJhdGlvbiBhbmQgdHJ5IGFnYWluLmA7XG5cbmNvbnN0IElVQkVOREFfQ09OU0VOVF9NQU5BR0VSX1BMVUdJTj0nSXViZW5kYUNvbnNlbnRNYW5hZ2VyUGx1Z2luJztjb25zdCBJVUJFTkRBX0NPTlNFTlRfQ09PS0lFX05BTUVfUEFUVEVSTj0vXl9pdWJfY3MtXFxkKyQvO1xuXG5jb25zdCBnZXRJdWJlbmRhQ29va2llTmFtZT1sb2dnZXI9Pnt0cnl7Ly8gUmV0cmlldmUgY29va2llcyBhcyBhIHN0cmluZyBhbmQgc3BsaXQgdGhlbSBpbnRvIGFuIGFycmF5XG5jb25zdCBjb29raWVzPWRvY3VtZW50LmNvb2tpZS5zcGxpdCgnOyAnKTsvLyBGaW5kIHRoZSBjb29raWUgdGhhdCBtYXRjaGVzIHRoZSBpdWJlbmRhIGNvb2tpZSBwYXR0ZXJuXG5jb25zdCBtYXRjaGVkQ29va2llPWNvb2tpZXMuZmluZChjb29raWU9Pntjb25zdFtuYW1lXT1jb29raWUuc3BsaXQoJz0nKTtyZXR1cm4gSVVCRU5EQV9DT05TRU5UX0NPT0tJRV9OQU1FX1BBVFRFUk4udGVzdCgobmFtZXx8JycpLnRyaW0oKSk7fSk7aWYoIW1hdGNoZWRDb29raWUpe3Rocm93IG5ldyBFcnJvcignSXViZW5kYSBDb29raWUgbm90IGZvdW5kIHdpdGggdGhlIHNwZWNpZmllZCBwYXR0ZXJuLicpO30vLyBFeHRyYWN0IGFuZCByZXR1cm4gdGhlIGNvb2tpZSBuYW1lXG5jb25zdFtuYW1lXT1tYXRjaGVkQ29va2llLnNwbGl0KCc9Jyk7cmV0dXJuIG5hbWV8fCcnO31jYXRjaChlcnIpe2xvZ2dlcj8uZXJyb3IoSVVCRU5EQV9DT05TRU5UX0NPT0tJRV9SRUFEX0VSUk9SKElVQkVOREFfQ09OU0VOVF9NQU5BR0VSX1BMVUdJTiksZXJyKTtyZXR1cm4gJyc7fX07LyoqXG4gKiBHZXRzIHRoZSBjb25zZW50IGRhdGEgZnJvbSB0aGUgSXViZW5kYSdzIGNvbnNlbnQgY29va2llXG4gKiBAcGFyYW0gc3RvcmVNYW5hZ2VyIFN0b3JlIG1hbmFnZXIgaW5zdGFuY2VcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gKiBAcmV0dXJucyBDb25zZW50IGRhdGEgZnJvbSB0aGUgY29uc2VudCBjb29raWVcbiAqL2NvbnN0IGdldEl1YmVuZGFDb25zZW50RGF0YT0oc3RvcmVNYW5hZ2VyLGxvZ2dlcik9PntsZXQgcmF3Q29uc2VudENvb2tpZURhdGE9bnVsbDt0cnl7Y29uc3QgZGF0YVN0b3JlPXN0b3JlTWFuYWdlcj8uc2V0U3RvcmUoe2lkOklVQkVOREFfQ09OU0VOVF9NQU5BR0VSX1BMVUdJTixuYW1lOklVQkVOREFfQ09OU0VOVF9NQU5BR0VSX1BMVUdJTix0eXBlOkNPT0tJRV9TVE9SQUdFLGVycm9ySGFuZGxlcjpzdG9yZU1hbmFnZXI/LmVycm9ySGFuZGxlcixsb2dnZXI6c3RvcmVNYW5hZ2VyPy5sb2dnZXJ9KTtyYXdDb25zZW50Q29va2llRGF0YT1kYXRhU3RvcmU/LmVuZ2luZS5nZXRJdGVtKGdldEl1YmVuZGFDb29raWVOYW1lKGxvZ2dlcikpO31jYXRjaChlcnIpe2xvZ2dlcj8uZXJyb3IoSVVCRU5EQV9DT05TRU5UX0NPT0tJRV9SRUFEX0VSUk9SKElVQkVOREFfQ09OU0VOVF9NQU5BR0VSX1BMVUdJTiksZXJyKTtyZXR1cm4gdW5kZWZpbmVkO31pZihpc051bGxPclVuZGVmaW5lZChyYXdDb25zZW50Q29va2llRGF0YSkpe3JldHVybiB1bmRlZmluZWQ7fS8vIERlY29kZSBhbmQgcGFyc2UgdGhlIGNvb2tpZSBkYXRhIHRvIEpTT05cbmxldCBjb25zZW50Q29va2llRGF0YTt0cnl7Y29uc2VudENvb2tpZURhdGE9SlNPTi5wYXJzZShkZWNvZGVVUklDb21wb25lbnQocmF3Q29uc2VudENvb2tpZURhdGEpKTt9Y2F0Y2goZXJyKXtsb2dnZXI/LmVycm9yKElVQkVOREFfQ09OU0VOVF9DT09LSUVfUEFSU0VfRVJST1IoSVVCRU5EQV9DT05TRU5UX01BTkFHRVJfUExVR0lOKSxlcnIpO3JldHVybiB1bmRlZmluZWQ7fWlmKCFjb25zZW50Q29va2llRGF0YSl7cmV0dXJuIHVuZGVmaW5lZDt9Ly8gQ29udmVydCB0aGUgY29va2llIGRhdGEgdG8gY29uc2VudCBkYXRhXG5jb25zdCBjb25zZW50UHVycG9zZXM9Y29uc2VudENvb2tpZURhdGEucHVycG9zZXM7cmV0dXJuIGNvbnNlbnRQdXJwb3Nlczt9Oy8qKlxuICogR2V0cyB0aGUgY29uc2VudCBkYXRhIGluIHRoZSBmb3JtYXQgZXhwZWN0ZWQgYnkgdGhlIGFwcGxpY2F0aW9uIHN0YXRlXG4gKiBAcGFyYW0gaXViZW5kYUNvbnNlbnREYXRhIENvbnNlbnQgZGF0YSBkZXJpdmVkIGZyb20gdGhlIGNvbnNlbnQgY29va2llXG4gKiBAcmV0dXJucyBDb25zZW50IGRhdGFcbiAqL2NvbnN0IGdldENvbnNlbnREYXRhJDE9aXViZW5kYUNvbnNlbnREYXRhPT57Y29uc3QgYWxsb3dlZENvbnNlbnRJZHM9W107Y29uc3QgZGVuaWVkQ29uc2VudElkcz1bXTtpZihpdWJlbmRhQ29uc2VudERhdGEpe09iamVjdC5lbnRyaWVzKGl1YmVuZGFDb25zZW50RGF0YSkuZm9yRWFjaChlPT57Y29uc3QgcHVycG9zZUlkPWVbMF07Y29uc3QgaXNDb25zZW50ZWQ9ZVsxXTtpZihpc0NvbnNlbnRlZCl7YWxsb3dlZENvbnNlbnRJZHMucHVzaChwdXJwb3NlSWQpO31lbHNlIHtkZW5pZWRDb25zZW50SWRzLnB1c2gocHVycG9zZUlkKTt9fSk7fXJldHVybiB7YWxsb3dlZENvbnNlbnRJZHMsZGVuaWVkQ29uc2VudElkc307fTtjb25zdCB1cGRhdGVDb25zZW50U3RhdGVGcm9tRGF0YSQxPShzdGF0ZSxpdWJlbmRhQ29uc2VudERhdGEpPT57Y29uc3QgY29uc2VudERhdGE9Z2V0Q29uc2VudERhdGEkMShpdWJlbmRhQ29uc2VudERhdGEpO3N0YXRlLmNvbnNlbnRzLmluaXRpYWxpemVkLnZhbHVlPWlzRGVmaW5lZChpdWJlbmRhQ29uc2VudERhdGEpO3N0YXRlLmNvbnNlbnRzLmRhdGEudmFsdWU9Y29uc2VudERhdGE7fTtcblxuY29uc3QgcGx1Z2luTmFtZSQ3PSdJdWJlbmRhQ29uc2VudE1hbmFnZXInO2NvbnN0IEl1YmVuZGFDb25zZW50TWFuYWdlcj0oKT0+KHtuYW1lOnBsdWdpbk5hbWUkNyxkZXBzOltdLGluaXRpYWxpemU6c3RhdGU9PntzdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWU9Wy4uLnN0YXRlLnBsdWdpbnMubG9hZGVkUGx1Z2lucy52YWx1ZSxwbHVnaW5OYW1lJDddO30sY29uc2VudE1hbmFnZXI6e2luaXQoc3RhdGUsbG9nZ2VyKXsvLyBnZXRJdWJlbmRhVXNlckNvbnNlbnRlZFB1cnBvc2VzIHJldHVybnMgY3VycmVudCBpdWJlbmRhIG9wdGVkLWluIHB1cnBvc2VzXG4vLyBUaGlzIHdpbGwgYmUgaGVscGZ1bCBmb3IgZGVidWdnaW5nXG5nbG9iYWxUaGlzLmdldEl1YmVuZGFVc2VyQ29uc2VudGVkUHVycG9zZXM9KCk9PnN0YXRlLmNvbnNlbnRzLmRhdGEudmFsdWUuYWxsb3dlZENvbnNlbnRJZHM/LnNsaWNlKCk7Ly8gZ2V0SXViZW5kYVVzZXJEZW5pZWRQdXJwb3NlcyByZXR1cm5zIGN1cnJlbnQgSXViZW5kYSBvcHRlZC1vdXQgcHVycG9zZXNcbi8vIFRoaXMgd2lsbCBiZSBoZWxwZnVsIGZvciBkZWJ1Z2dpbmdcbmdsb2JhbFRoaXMuZ2V0SXViZW5kYVVzZXJEZW5pZWRQdXJwb3Nlcz0oKT0+c3RhdGUuY29uc2VudHMuZGF0YS52YWx1ZS
15kZW5pZWRDb25zZW50SWRzPy5zbGljZSgpOy8vIHVwZGF0ZUl1YmVuZGFDb25zZW50IGNhbGxiYWNrIGZ1bmN0aW9uIHRvIHVwZGF0ZSBjdXJyZW50IGNvbnNlbnQgcHVycG9zZSBzdGF0ZVxuZ2xvYmFsVGhpcy51cGRhdGVJdWJlbmRhQ29uc2VudD1pdWJlbmRhQ29uc2VudERhdGE9Pnt1cGRhdGVDb25zZW50U3RhdGVGcm9tRGF0YSQxKHN0YXRlLGl1YmVuZGFDb25zZW50RGF0YSk7fTt9LHVwZGF0ZUNvbnNlbnRzSW5mbyhzdGF0ZSxzdG9yZU1hbmFnZXIsbG9nZ2VyKXsvLyByZXRyaWV2ZSBjb25zZW50IGRhdGEgYW5kIHVwZGF0ZSB0aGUgc3RhdGVcbmxldCBpdWJlbmRhQ29uc2VudERhdGE7Ly8gRnJvbSB3aW5kb3dcbmlmKCFpc1VuZGVmaW5lZChnbG9iYWxUaGlzLl9pdWIuY3MuY29uc2VudC5wdXJwb3Nlcykpe2l1YmVuZGFDb25zZW50RGF0YT1nbG9iYWxUaGlzLl9pdWIuY3MuY29uc2VudC5wdXJwb3NlczsvLyBGcm9tIGNvb2tpZVxufWVsc2Uge2l1YmVuZGFDb25zZW50RGF0YT1nZXRJdWJlbmRhQ29uc2VudERhdGEoc3RvcmVNYW5hZ2VyLGxvZ2dlcik7fXVwZGF0ZUNvbnNlbnRTdGF0ZUZyb21EYXRhJDEoc3RhdGUsaXViZW5kYUNvbnNlbnREYXRhKTt9LGlzRGVzdGluYXRpb25Db25zZW50ZWQoc3RhdGUsZGVzdENvbmZpZyxlcnJvckhhbmRsZXIsbG9nZ2VyKXtpZighc3RhdGUuY29uc2VudHMuaW5pdGlhbGl6ZWQudmFsdWUpe3JldHVybiB0cnVlO31jb25zdCBhbGxvd2VkQ29uc2VudElkcz1zdGF0ZS5jb25zZW50cy5kYXRhLnZhbHVlLmFsbG93ZWRDb25zZW50SWRzO2NvbnN0IG1hdGNoUHJlZGljYXRlPWNvbnNlbnQ9PmFsbG93ZWRDb25zZW50SWRzLmluY2x1ZGVzKGNvbnNlbnQpO3RyeXtjb25zdHtjb25zZW50TWFuYWdlbWVudH09ZGVzdENvbmZpZzsvLyBJZiB0aGUgZGVzdGluYXRpb24gZG9lcyBub3QgaGF2ZSBjb25zZW50IG1hbmFnZW1lbnQgY29uZmlnLCBldmVudHMgc2hvdWxkIGJlIHNlbnQuXG5pZihjb25zZW50TWFuYWdlbWVudCl7Ly8gR2V0IHRoZSBjb3JyZXNwb25kaW5nIGNvbnNlbnRzIGZvciB0aGUgZGVzdGluYXRpb25cbmNvbnN0IGNtcENvbmZpZz1jb25zZW50TWFuYWdlbWVudC5maW5kKGM9PmMucHJvdmlkZXI9PT1zdGF0ZS5jb25zZW50cy5wcm92aWRlci52YWx1ZSk7Ly8gSWYgdGhlcmUgYXJlIG5vIGNvbnNlbnRzIGNvbmZpZ3VyZWQgZm9yIHRoZSBkZXN0aW5hdGlvbiBmb3IgdGhlIGN1cnJlbnQgcHJvdmlkZXIsIGV2ZW50cyBzaG91bGQgYmUgc2VudC5cbmlmKCFjbXBDb25maWc/LmNvbnNlbnRzKXtyZXR1cm4gdHJ1ZTt9Y29uc3QgY29uZmlndXJlZENvbnNlbnRzPWNtcENvbmZpZy5jb25zZW50cy5tYXAoYz0+Yy5jb25zZW50LnRyaW0oKSkuZmlsdGVyKG49Pm4pO2NvbnN0IHJlc29sdXRpb25TdHJhdGVneT1jbXBDb25maWcucmVzb2x1dGlvblN0cmF0ZWd5Pz9zdGF0ZS5jb25zZW50cy5yZXNvbHV0aW9uU3RyYXRlZ3kudmFsdWU7Ly8gbWF0Y2ggdGhlIGNvbmZpZ3VyZWQgY29uc2VudHMgd2l0aCB1c2VyIHByb3ZpZGVkIGNvbnNlbnRzIGFzIHBlclxuLy8gdGhlIGNvbmZpZ3VyZWQgcmVzb2x1dGlvbiBzdHJhdGVneVxuc3dpdGNoKHJlc29sdXRpb25TdHJhdGVneSl7Y2FzZSAnb3InOnJldHVybiBjb25maWd1cmVkQ29uc2VudHMuc29tZShtYXRjaFByZWRpY2F0ZSl8fGNvbmZpZ3VyZWRDb25zZW50cy5sZW5ndGg9PT0wO2Nhc2UgJ2FuZCc6ZGVmYXVsdDpyZXR1cm4gY29uZmlndXJlZENvbnNlbnRzLmV2ZXJ5KG1hdGNoUHJlZGljYXRlKTt9fXJldHVybiB0cnVlO31jYXRjaChlcnIpe2Vycm9ySGFuZGxlcj8ub25FcnJvcih7ZXJyb3I6ZXJyLGNvbnRleHQ6SVVCRU5EQV9DT05TRU5UX01BTkFHRVJfUExVR0lOLGN1c3RvbU1lc3NhZ2U6REVTVElOQVRJT05fQ09OU0VOVF9TVEFUVVNfRVJST1IkMn0pO3JldHVybiB0cnVlO319fX0pO1xuXG5jb25zdCBLRVRDSF9DT05TRU5UX0NPT0tJRV9SRUFEX0VSUk9SPWNvbnRleHQ9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9RmFpbGVkIHRvIHJlYWQgdGhlIGNvbnNlbnQgY29va2llLmA7Y29uc3QgS0VUQ0hfQ09OU0VOVF9DT09LSUVfUEFSU0VfRVJST1I9Y29udGV4dD0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1GYWlsZWQgdG8gcGFyc2UgdGhlIGNvbnNlbnQgY29va2llLmA7Y29uc3QgREVTVElOQVRJT05fQ09OU0VOVF9TVEFUVVNfRVJST1IkMT1gRmFpbGVkIHRvIGRldGVybWluZSB0aGUgY29uc2VudCBzdGF0dXMgZm9yIHRoZSBkZXN0aW5hdGlvbi4gUGxlYXNlIGNoZWNrIHRoZSBkZXN0aW5hdGlvbiBjb25maWd1cmF0aW9uIGFuZCB0cnkgYWdhaW4uYDtcblxuY29uc3QgS0VUQ0hfQ09OU0VOVF9NQU5BR0VSX1BMVUdJTj0nS2V0Y2hDb25zZW50TWFuYWdlclBsdWdpbic7Y29uc3QgS0VUQ0hfQ09OU0VOVF9DT09LSUVfTkFNRV9WMT0nX2tldGNoX2NvbnNlbnRfdjFfJztcblxuLyoqXG4gKiBHZXRzIHRoZSBjb25zZW50IGRhdGEgZnJvbSB0aGUgS2V0Y2gncyBjb25zZW50IGNvb2tpZVxuICogQHBhcmFtIHN0b3JlTWFuYWdlciBTdG9yZSBtYW5hZ2VyIGluc3RhbmNlXG4gKiBAcGFyYW0gbG9nZ2VyIExvZ2dlciBpbnN0YW5jZVxuICogQHJldHVybnMgQ29uc2VudCBkYXRhIGZyb20gdGhlIGNvbnNlbnQgY29va2llXG4gKi9jb25zdCBnZXRLZXRjaENvbnNlbnREYXRhPShzdG9yZU1hbmFnZXIsbG9nZ2VyKT0+e2xldCByYXdDb25zZW50Q29va2llRGF0YT1udWxsO3RyeXsvLyBDcmVhdGUgYSBkYXRhIHN0b3JlIGluc3RhbmNlIHRvIHJlYWQgdGhlIGNvbnNlbnQgY29va2llXG5jb25zdCBkYXRhU3RvcmU9c3RvcmVNYW5hZ2VyPy5zZXRTdG9yZSh7aWQ6S0VUQ0hfQ09OU0VOVF9NQU5BR0VSX1BMVUdJTixuYW1lOktFVENIX0NPTlNFTlRfTUFOQUdFUl9QTFVHSU4sdHlwZTpDT09LSUVfU1RPUkFHRSxlcnJvckhhbmRsZXI6c3RvcmVNYW5hZ2VyPy5lcnJvckhhbmRsZXIsbG9nZ2VyOnN0b3JlTWFuYWdlcj8ubG9nZ2VyfSk7cmF3Q29uc2VudENvb2tpZURhdGE9ZGF0YVN0b3JlPy5lbmdpbmUuZ2V0SXRlbShLRVRDSF9DT05TRU5UX0NPT0tJRV9OQU1FX1YxKTt9Y2F0Y2goZXJyKXtsb2dnZXI/LmVycm9yKEtFVENIX0NPTlNFTlRfQ09PS0lFX1JFQURfRVJST1IoS0VUQ0hfQ09OU0VOVF9NQU5BR0VSX1BMVUdJTiksZXJyKTtyZXR1cm4gdW5kZWZpbmVkO31pZihpc051bGxPclVuZGVmaW5lZChyYXdDb25zZW50Q29va2llRGF0YSkpe3JldHVybiB1bmRlZmluZWQ7fS8vIERlY29kZSBhbmQgcGFyc2UgdGhlIGNvb2tpZSBkYXRhIHRvIEpTT05cbmxldCBjb25zZW50Q29va2llRGF0YTt0cnl7Y29uc2VudENvb2tpZURhdGE9SlNPTi5wYXJzZShmcm9tQmFzZTY0KHJhd0NvbnNlbnRDb29raWVEYXRhKSk7fWNhdGNoKGVycil7bG9nZ2VyPy5lcnJvcihLRVRDSF9DT05TRU5UX0NPT0tJRV9QQVJTRV9FUlJPUihLRVRDSF9DT05TRU5UX01BTkFHRVJfUExVR0lOKSxlcnIpO3JldHVybiB1bmRlZmluZWQ7fWlmKCFjb25zZW50Q29va2llRGF0YSl7cmV0dXJuIHVuZGVmaW5lZDt9Ly8gQ29udmVydCB0aGUgY29va2llIGRhdGEgdG8gY29uc2VudCBkYXRhXG5jb25zdCBjb25zZW50UHVycG9zZXM9e307T2JqZWN0LmVud
1HJpZXMoY29uc2VudENvb2tpZURhdGEpLmZvckVhY2gocEVudHJ5PT57Y29uc3QgcHVycG9zZUNvZGU9cEVudHJ5WzBdO2NvbnN0IHB1cnBvc2VWYWx1ZT1wRW50cnlbMV07Y29uc2VudFB1cnBvc2VzW3B1cnBvc2VDb2RlXT1wdXJwb3NlVmFsdWU/LnN0YXR1cz09PSdncmFudGVkJzt9KTtyZXR1cm4gY29uc2VudFB1cnBvc2VzO307LyoqXG4gKiBHZXRzIHRoZSBjb25zZW50IGRhdGEgaW4gdGhlIGZvcm1hdCBleHBlY3RlZCBieSB0aGUgYXBwbGljYXRpb24gc3RhdGVcbiAqIEBwYXJhbSBrZXRjaENvbnNlbnREYXRhIENvbnNlbnQgZGF0YSBkZXJpdmVkIGZyb20gdGhlIGNvbnNlbnQgY29va2llXG4gKiBAcmV0dXJucyBDb25zZW50IGRhdGFcbiAqL2NvbnN0IGdldENvbnNlbnREYXRhPWtldGNoQ29uc2VudERhdGE9Pntjb25zdCBhbGxvd2VkQ29uc2VudElkcz1bXTtjb25zdCBkZW5pZWRDb25zZW50SWRzPVtdO2lmKGtldGNoQ29uc2VudERhdGEpe09iamVjdC5lbnRyaWVzKGtldGNoQ29uc2VudERhdGEpLmZvckVhY2goZT0+e2NvbnN0IHB1cnBvc2VDb2RlPWVbMF07Y29uc3QgaXNDb25zZW50ZWQ9ZVsxXTtpZihpc0NvbnNlbnRlZCl7YWxsb3dlZENvbnNlbnRJZHMucHVzaChwdXJwb3NlQ29kZSk7fWVsc2Uge2RlbmllZENvbnNlbnRJZHMucHVzaChwdXJwb3NlQ29kZSk7fX0pO31yZXR1cm4ge2FsbG93ZWRDb25zZW50SWRzLGRlbmllZENvbnNlbnRJZHN9O307Y29uc3QgdXBkYXRlQ29uc2VudFN0YXRlRnJvbURhdGE9KHN0YXRlLGtldGNoQ29uc2VudERhdGEpPT57Y29uc3QgY29uc2VudERhdGE9Z2V0Q29uc2VudERhdGEoa2V0Y2hDb25zZW50RGF0YSk7c3RhdGUuY29uc2VudHMuaW5pdGlhbGl6ZWQudmFsdWU9aXNEZWZpbmVkKGtldGNoQ29uc2VudERhdGEpO3N0YXRlLmNvbnNlbnRzLmRhdGEudmFsdWU9Y29uc2VudERhdGE7fTtcblxuY29uc3QgcGx1Z2luTmFtZSQ2PSdLZXRjaENvbnNlbnRNYW5hZ2VyJztjb25zdCBLZXRjaENvbnNlbnRNYW5hZ2VyPSgpPT4oe25hbWU6cGx1Z2luTmFtZSQ2LGRlcHM6W10saW5pdGlhbGl6ZTpzdGF0ZT0+e3N0YXRlLnBsdWdpbnMubG9hZGVkUGx1Z2lucy52YWx1ZT1bLi4uc3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlLHBsdWdpbk5hbWUkNl07fSxjb25zZW50TWFuYWdlcjp7aW5pdChzdGF0ZSxsb2dnZXIpey8vIGdldEtldGNoVXNlckNvbnNlbnRlZFB1cnBvc2VzIHJldHVybnMgY3VycmVudCBrZXRjaCBvcHRlZC1pbiBwdXJwb3Nlc1xuLy8gVGhpcyB3aWxsIGJlIGhlbHBmdWwgZm9yIGRlYnVnZ2luZ1xuZ2xvYmFsVGhpcy5nZXRLZXRjaFVzZXJDb25zZW50ZWRQdXJwb3Nlcz0oKT0+c3RhdGUuY29uc2VudHMuZGF0YS52YWx1ZS5hbGxvd2VkQ29uc2VudElkcz8uc2xpY2UoKTsvLyBnZXRLZXRjaFVzZXJEZW5pZWRQdXJwb3NlcyByZXR1cm5zIGN1cnJlbnQga2V0Y2ggb3B0ZWQtb3V0IHB1cnBvc2VzXG4vLyBUaGlzIHdpbGwgYmUgaGVscGZ1bCBmb3IgZGVidWdnaW5nXG5nbG9iYWxUaGlzLmdldEtldGNoVXNlckRlbmllZFB1cnBvc2VzPSgpPT5zdGF0ZS5jb25zZW50cy5kYXRhLnZhbHVlLmRlbmllZENvbnNlbnRJZHM/LnNsaWNlKCk7Ly8gdXBkYXRlS2V0Y2hDb25zZW50IGNhbGxiYWNrIGZ1bmN0aW9uIHRvIHVwZGF0ZSBjdXJyZW50IGNvbnNlbnQgcHVycG9zZSBzdGF0ZVxuLy8gdGhpcyB3aWxsIGJlIGNhbGxlZCBmcm9tIGtldGNoIHJ1ZGRlcnN0YWNrIHBsdWdpblxuZ2xvYmFsVGhpcy51cGRhdGVLZXRjaENvbnNlbnQ9a2V0Y2hDb25zZW50RGF0YT0+e3VwZGF0ZUNvbnNlbnRTdGF0ZUZyb21EYXRhKHN0YXRlLGtldGNoQ29uc2VudERhdGEpO307fSx1cGRhdGVDb25zZW50c0luZm8oc3RhdGUsc3RvcmVNYW5hZ2VyLGxvZ2dlcil7Ly8gcmV0cmlldmUgY29uc2VudCBkYXRhIGFuZCB1cGRhdGUgdGhlIHN0YXRlXG5sZXQga2V0Y2hDb25zZW50RGF0YTtpZighaXNVbmRlZmluZWQoZ2xvYmFsVGhpcy5rZXRjaENvbnNlbnQpKXtrZXRjaENvbnNlbnREYXRhPWdsb2JhbFRoaXMua2V0Y2hDb25zZW50O31lbHNlIHtrZXRjaENvbnNlbnREYXRhPWdldEtldGNoQ29uc2VudERhdGEoc3RvcmVNYW5hZ2VyLGxvZ2dlcik7fXVwZGF0ZUNvbnNlbnRTdGF0ZUZyb21EYXRhKHN0YXRlLGtldGNoQ29uc2VudERhdGEpO30saXNEZXN0aW5hdGlvbkNvbnNlbnRlZChzdGF0ZSxkZXN0Q29uZmlnLGVycm9ySGFuZGxlcixsb2dnZXIpe2lmKCFzdGF0ZS5jb25zZW50cy5pbml0aWFsaXplZC52YWx1ZSl7cmV0dXJuIHRydWU7fWNvbnN0IGFsbG93ZWRDb25zZW50SWRzPXN0YXRlLmNvbnNlbnRzLmRhdGEudmFsdWUuYWxsb3dlZENvbnNlbnRJZHM7dHJ5e2NvbnN0e2tldGNoQ29uc2VudFB1cnBvc2VzLGNvbnNlbnRNYW5hZ2VtZW50fT1kZXN0Q29uZmlnO2NvbnN0IG1hdGNoUHJlZGljYXRlPWNvbnNlbnQ9PmFsbG93ZWRDb25zZW50SWRzLmluY2x1ZGVzKGNvbnNlbnQpOy8vIEdlbmVyaWMgY29uc2VudCBtYW5hZ2VtZW50XG5pZihjb25zZW50TWFuYWdlbWVudCl7Ly8gR2V0IHRoZSBjb3JyZXNwb25kaW5nIGNvbnNlbnRzIGZvciB0aGUgZGVzdGluYXRpb25cbmNvbnN0IGNtcENvbnNlbnRzPWNvbnNlbnRNYW5hZ2VtZW50LmZpbmQoYz0+Yy5wcm92aWRlcj09PXN0YXRlLmNvbnNlbnRzLnByb3ZpZGVyLnZhbHVlKT8uY29uc2VudHM7Ly8gSWYgdGhlcmUgYXJlIG5vIGNvbnNlbnRzIGNvbmZpZ3VyZWQgZm9yIHRoZSBkZXN0aW5hdGlvbiBmb3IgdGhlIGN1cnJlbnQgcHJvdmlkZXIsIGV2ZW50cyBzaG91bGQgYmUgc2VudC5cbmlmKCFjbXBDb25zZW50cyl7cmV0dXJuIHRydWU7fWNvbnN0IGNvbmZpZ3VyZWRDb25zZW50cz1jbXBDb25zZW50cy5tYXAoYz0+Yy5jb25zZW50LnRyaW0oKSkuZmlsdGVyKG49Pm4pOy8vIG1hdGNoIHRoZSBjb25maWd1cmVkIGNvbnNlbnRzIHdpdGggdXNlciBwcm92aWRlZCBjb25zZW50cyBhcyBwZXJcbi8vIHRoZSBjb25maWd1cmVkIHJlc29sdXRpb24gc3RyYXRlZ3lcbnN3aXRjaChzdGF0ZS5jb25zZW50cy5yZXNvbHV0aW9uU3RyYXRlZ3kudmFsdWUpe2Nhc2UgJ29yJzpyZXR1cm4gY29uZmlndXJlZENvbnNlbnRzLnNvbWUobWF0Y2hQcmVkaWNhdGUpfHxjb25maWd1cmVkQ29uc2VudHMubGVuZ3RoPT09MDtjYXNlICdhbmQnOmRlZmF1bHQ6cmV0dXJuIGNvbmZpZ3VyZWRDb25zZW50cy5ldmVyeShtYXRjaFByZWRpY2F0ZSk7fS8vIExlZ2FjeSBjb29raWUgY29uc2VudCBtYW5hZ2VtZW50XG4vLyBUT0RPOiBUbyBiZSByZW1vdmVkIG9uY2UgdGhlIHNvdXJjZSBjb25maWcgQVBJIGlzIHVwZGF0ZWQgdG8gc3VwcG9ydCBnZW5lcmljIGNvbnNlbnQgbWFuYWdlbWVudFxufWVsc2UgaWYoa2V0Y2hDb25zZW50UHVycG9zZXMpe2NvbnN0IGNvbmZpZ3VyZWRDb25zZW50cz1rZXRjaENvbnNlbnRQdXJ
1wb3Nlcy5tYXAocD0+cC5wdXJwb3NlLnRyaW0oKSkuZmlsdGVyKG49Pm4pOy8vIENoZWNrIGlmIGFueSBvZiB0aGUgZGVzdGluYXRpb24ncyBtYXBwZWQga2V0Y2ggcHVycG9zZXMgYXJlIGNvbnNlbnRlZCBieSB0aGUgdXNlciBpbiB0aGUgYnJvd3Nlci5cbnJldHVybiBjb25maWd1cmVkQ29uc2VudHMuc29tZShtYXRjaFByZWRpY2F0ZSl8fGNvbmZpZ3VyZWRDb25zZW50cy5sZW5ndGg9PT0wO30vLyBJZiB0aGVyZSBhcmUgbm8gY29uc2VudHMgY29uZmlndXJlZCBmb3IgdGhlIGRlc3RpbmF0aW9uIGZvciB0aGUgY3VycmVudCBwcm92aWRlciwgZXZlbnRzIHNob3VsZCBiZSBzZW50LlxucmV0dXJuIHRydWU7fWNhdGNoKGVycil7ZXJyb3JIYW5kbGVyPy5vbkVycm9yKHtlcnJvcjplcnIsY29udGV4dDpLRVRDSF9DT05TRU5UX01BTkFHRVJfUExVR0lOLGN1c3RvbU1lc3NhZ2U6REVTVElOQVRJT05fQ09OU0VOVF9TVEFUVVNfRVJST1IkMX0pO3JldHVybiB0cnVlO319fX0pO1xuXG5jb25zdCBERUZBVUxUX1FVRVVFX09QVElPTlM9e21heEl0ZW1zOjEwMH07Y29uc3QgUVVFVUVfTkFNRSQxPSdydWRkZXJfZGVzdGluYXRpb25zX2V2ZW50cyc7Y29uc3QgTkFUSVZFX0RFU1RJTkFUSU9OX1FVRVVFX1BMVUdJTj0nTmF0aXZlRGVzdGluYXRpb25RdWV1ZVBsdWdpbic7XG5cbmNvbnN0IERFU1RJTkFUSU9OX0VWRU5UX0ZJTFRFUklOR19XQVJOSU5HPShjb250ZXh0LGV2ZW50TmFtZSxkZXN0VXNlckZyaWVuZGx5SWQpPT5gJHtjb250ZXh0fSR7TE9HX0NPTlRFWFRfU0VQQVJBVE9SfVRoZSBcIiR7ZXZlbnROYW1lfVwiIHRyYWNrIGV2ZW50IGhhcyBiZWVuIGZpbHRlcmVkIGZvciB0aGUgXCIke2Rlc3RVc2VyRnJpZW5kbHlJZH1cIiBkZXN0aW5hdGlvbi5gO2NvbnN0IElOVEVHUkFUSU9OX0VWRU5UX0ZPUldBUkRJTkdfRVJST1I9KHR5cGUsaWQsbmFtZSk9PmBGYWlsZWQgdG8gc2VuZCBcIiR7dHlwZX1cIiBldmVudCAke25hbWU/YFwiJHtuYW1lfVwiIGA6Jyd9dG8gaW50ZWdyYXRpb24gZm9yIGRlc3RpbmF0aW9uIFwiJHtpZH1cIi5gO1xuXG5jb25zdCBnZXROb3JtYWxpemVkUXVldWVPcHRpb25zJDE9cXVldWVPcHRzPT5tZXJnZURlZXBSaWdodChERUZBVUxUX1FVRVVFX09QVElPTlMscXVldWVPcHRzKTtjb25zdCBpc1ZhbGlkRXZlbnROYW1lPWV2ZW50TmFtZT0+ZXZlbnROYW1lJiZ0eXBlb2YgZXZlbnROYW1lPT09J3N0cmluZyc7Y29uc3QgaXNFdmVudERlbnlMaXN0ZWQ9KGV2ZW50VHlwZSxldmVudE5hbWUsZGVzdCk9PntpZihldmVudFR5cGUhPT0ndHJhY2snKXtyZXR1cm4gZmFsc2U7fWNvbnN0e2JsYWNrbGlzdGVkRXZlbnRzLHdoaXRlbGlzdGVkRXZlbnRzLGV2ZW50RmlsdGVyaW5nT3B0aW9ufT1kZXN0LmNvbmZpZztzd2l0Y2goZXZlbnRGaWx0ZXJpbmdPcHRpb24pey8vIEJsYWNrbGlzdCBpcyBjaG9zZW4gZm9yIGZpbHRlcmluZyBldmVudHNcbmNhc2UgJ2JsYWNrbGlzdGVkRXZlbnRzJzp7aWYoIWlzVmFsaWRFdmVudE5hbWUoZXZlbnROYW1lKSl7cmV0dXJuIGZhbHNlO31jb25zdCB0cmltbWVkRXZlbnROYW1lPWV2ZW50TmFtZS50cmltKCk7aWYoQXJyYXkuaXNBcnJheShibGFja2xpc3RlZEV2ZW50cykpe3JldHVybiBibGFja2xpc3RlZEV2ZW50cy5zb21lKGV2ZW50T2JqPT5ldmVudE9iai5ldmVudE5hbWUudHJpbSgpPT09dHJpbW1lZEV2ZW50TmFtZSk7fXJldHVybiBmYWxzZTt9Ly8gV2hpdGVsaXN0IGlzIGNob3NlbiBmb3IgZmlsdGVyaW5nIGV2ZW50c1xuY2FzZSAnd2hpdGVsaXN0ZWRFdmVudHMnOntpZighaXNWYWxpZEV2ZW50TmFtZShldmVudE5hbWUpKXtyZXR1cm4gdHJ1ZTt9Y29uc3QgdHJpbW1lZEV2ZW50TmFtZT1ldmVudE5hbWUudHJpbSgpO2lmKEFycmF
15LmlzQXJyYXkod2hpdGVsaXN0ZWRFdmVudHMpKXtyZXR1cm4gIXdoaXRlbGlzdGVkRXZlbnRzLnNvbWUoZXZlbnRPYmo9PmV2ZW50T2JqLmV2ZW50TmFtZS50cmltKCk9PT10cmltbWVkRXZlbnROYW1lKTt9cmV0dXJuIHRydWU7fWNhc2UgJ2Rpc2FibGUnOmRlZmF1bHQ6cmV0dXJuIGZhbHNlO319O2NvbnN0IHNlbmRFdmVudFRvRGVzdGluYXRpb249KGl0ZW0sZGVzdCxlcnJvckhhbmRsZXIsbG9nZ2VyKT0+e2NvbnN0IG1ldGhvZE5hbWU9aXRlbS50eXBlLnRvU3RyaW5nKCk7dHJ5ey8vIERlc3RpbmF0aW9ucyBleHBlY3QgdGhlIGV2ZW50IHRvIGJlIHdyYXBwZWQgdW5kZXIgdGhlIGBtZXNzYWdlYCBrZXlcbmNvbnN0IGludGVncmF0aW9uRXZlbnQ9e21lc3NhZ2U6aXRlbX07ZGVzdC5pbnRlZ3JhdGlvblttZXRob2ROYW1lXT8uKGludGVncmF0aW9uRXZlbnQpO31jYXRjaChlcnIpe2Vycm9ySGFuZGxlcj8ub25FcnJvcih7ZXJyb3I6ZXJyLGNvbnRleHQ6TkFUSVZFX0RFU1RJTkFUSU9OX1FVRVVFX1BMVUdJTixjdXN0b21NZXNzYWdlOklOVEVHUkFUSU9OX0VWRU5UX0ZPUldBUkRJTkdfRVJST1IobWV0aG9kTmFtZSxkZXN0LnVzZXJGcmllbmRseUlkLGl0ZW0uZXZlbnQpLGdyb3VwaW5nSGFzaDpJTlRFR1JBVElPTl9FVkVOVF9GT1JXQVJESU5HX0VSUk9SKG1ldGhvZE5hbWUsZGVzdC5kaXNwbGF5TmFtZSxpdGVtLmV2ZW50KSxjYXRlZ29yeTpJTlRFR1JBVElPTlNfRVJST1JfQ0FURUdPUll9KTt9fTsvKipcbiAqIEEgZnVuY3Rpb24gdG8gY2hlY2sgaWYgZGV2aWNlIG1vZGUgdHJhbnNmb3JtYXRpb24gc2hvdWxkIGJlIGFwcGxpZWQgZm9yIGEgZGVzdGluYXRpb24uXG4gKiBAcGFyYW0gZGVzdCBEZXN0aW5hdGlvbiBvYmplY3RcbiAqIEByZXR1cm5zIEJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIHR
1oZSB0cmFuc2Zvcm1hdGlvbiBzaG91bGQgYmUgYXBwbGllZFxuICovY29uc3Qgc2hvdWxkQXBwbHlUcmFuc2Zvcm1hdGlvbj1kZXN0PT57cmV0dXJuIGRlc3Quc2hvdWxkQXBwbHlEZXZpY2VNb2RlVHJhbnNmb3JtYXRpb247fTtcblxuY29uc3QgcGx1Z2luTmFtZSQ1PSdOYXRpdmVEZXN0aW5hdGlvblF1ZXVlJztjb25zdCBOYXRpdmVEZXN0aW5hdGlvblF1ZXVlPSgpPT4oe25hbWU6cGx1Z2luTmFtZSQ1LGRlcHM6W10saW5pdGlhbGl6ZTpzdGF0ZT0+e3N0YXRlLnBsdWdpbnMubG9hZGVkUGx1Z2lucy52YWx1ZT1bLi4uc3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlLHBsdWdpbk5hbWUkNV07fSxkZXN0aW5hdGlvbnNFdmVudHNRdWV1ZTp7LyoqXG4gICAgICogSW5pdGlhbGl6ZSB0aGUgcXVldWUgZm9yIGRlbGl2ZXJ5IHRvIGRlc3RpbmF0aW9uc1xuICAgICAqIEBwYXJhbSBzdGF0ZSBBcHBsaWNhdGlvbiBzdGF0ZVxuICAgICAqIEBwYXJhbSBwbHVnaW5zTWFuYWdlciBQbHVnaW5zTWFuYWdlciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBzdG9yZU1hbmFnZXIgU3RvcmVNYW5hZ2VyIGluc3RhbmNlXG4gICAgICogQHBhcmFtIGVycm9ySGFuZGxlciBFcnJvciBoYW5kbGVyIGluc3RhbmNlXG4gICAgICogQHBhcmFtIGxvZ2dlciBMb2dnZXIgaW5zdGFuY2VcbiAgICAgKiBAcmV0dXJucyBJUXVldWUgaW5zdGFuY2VcbiAgICAgKi9pbml0KHN0YXRlLHBsdWdpbnNNYW5hZ2VyLHN0b3JlTWFuYWdlcixkbXRRdWV1ZSxlcnJvckhhbmRsZXIsbG9nZ2VyKXtjb25zdCBmaW5hbFFPcHRzPWdldE5vcm1hbGl6ZWRRdWV1ZU9wdGlvbnMkMShzdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZS5kZXN0aW5
1hdGlvbnNRdWV1ZU9wdGlvbnMpO2NvbnN0IHdyaXRlS2V5PXN0YXRlLmxpZmVjeWNsZS53cml0ZUtleS52YWx1ZTtjb25zdCBldmVudHNRdWV1ZT1uZXcgUmV0cnlRdWV1ZSgvLyBhZGRpbmcgd3JpdGUga2V5IHRvIHRoZSBxdWV1ZSBuYW1lIHRvIGF2b2lkIGNvbmZsaWN0c1xuYCR7UVVFVUVfTkFNRSQxfV8ke3dyaXRlS2V5fWAsZmluYWxRT3B0cywocnVkZGVyRXZlbnQsZG9uZSk9Pntjb25zdCBkZXN0aW5hdGlvbnNUb1NlbmQ9ZmlsdGVyRGVzdGluYXRpb25zKHJ1ZGRlckV2ZW50LmludGVncmF0aW9ucyxzdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuaW5pdGlhbGl6ZWREZXN0aW5hdGlvbnMudmFsdWUpOy8vIGxpc3Qgb2YgZGVzdGluYXRpb25zIHdoaWNoIGFyZSBlbmFibGUgZm9yIERNVFxuY29uc3QgZGVzdFdpdGhUcmFuc2Zvcm1hdGlvbkVuYWJsZWQ9W107Y29uc3QgY2xvbmVkUnVkZGVyRXZlbnQ9Y2xvbmUocnVkZGVyRXZlbnQpO2Rlc3RpbmF0aW9uc1RvU2VuZC5mb3JFYWNoKGRlc3Q9Pnt0cnl7Y29uc3Qgc2VuZEV2ZW50PSFpc0V2ZW50RGVueUxpc3RlZChjbG9uZWRSdWRkZXJFdmVudC50eXBlLGNsb25lZFJ1ZGRlckV2ZW50LmV2ZW50LGRlc3QpO2lmKCFzZW5kRXZlbnQpe2xvZ2dlcj8ud2FybihERVNUSU5BVElPTl9FVkVOVF9GSUxURVJJTkdfV0FSTklORyhOQVRJVkVfREVTVElOQVRJT05fUVVFVUVfUExVR0lOLGNsb25lZFJ1ZGRlckV2ZW50LmV2ZW50LGRlc3QudXNlckZyaWVuZGx5SWQpKTtyZXR1cm47fWlmKHNob3VsZEFwcGx5VHJhbnNmb3JtYXRpb24oZGVzdCkpe2Rlc3RXaXRoVHJhbnNmb3JtYXRpb25FbmFibGVkLnB1c2goZGVzdCk7fWVsc2Uge3NlbmRFdmVudFRvRGVzdGluYXRpb24oY2xvbmVkUnVkZGVyRXZlbnQsZGVzdCxlcnJvckhhbmRsZXIsbG9nZ2VyKTt9fWNhdGNoKGUpe2Vycm9ySGFuZGxlcj8ub25FcnJvcih7ZXJyb3I6ZSxjb250ZXh0Ok5BVElWRV9ERVNUSU5BVElPTl9RVUVVRV9QTFVHSU4sY2F0ZWdvcnk6SU5URUdSQVRJT05TX0VSUk9SX0NBVEVHT1JZfSk7fX0pO2lmKGRlc3RXaXRoVHJhbnNmb3JtYXRpb25FbmFibGVkLmxlbmd0aD4wKXtwbHVnaW5zTWFuYWdlci5pbnZva2VTaW5nbGUoJ3RyYW5zZm9ybUV2ZW50LmVucXVldWUnLHN0YXRlLGRtdFF1ZXVlLGNsb25lZFJ1ZGRlckV2ZW50LGRlc3RXaXRoVHJhbnNmb3JtYXRpb25FbmFibGVkLGVycm9ySGFuZGxlcixsb2dnZXIpO30vLyBNYXJrIHN1Y2Nlc3MgYWx3YXlzXG5kb25lKG51bGwpO30sc3RvcmVNYW5hZ2VyLE1FTU9SWV9TVE9SQUdFKTsvLyBUT0RPOiBUaGlzIHNlZW1zIHRvIG5vdCB3b3JrIGFzIGV4cGVjdGVkLiBOZWVkIHRvIGludmVzdGlnYXRlXG4vLyBlZmZlY3QoKCkgPT4ge1xuLy8gICBpZiAoc3RhdGUubmF0aXZlRGVzdGluYXRpb25zLmNsaWVudERlc3RpbmF0aW9uc1JlYWR5LnZhbHVlID09PSB0cnVlKSB7XG4vLyAgICAgZXZlbnRzUXVldWUuc3RhcnQoKTtcbi8vICAgfVxuLy8gfSk7XG5yZXR1cm4gZXZlbnRzUXVldWU7fSwvKipcbiAgICAgKiBBZGQgZXZlbnQgdG8gdGhlIHF1ZXVlIGZvciBkZWxpdmVyeSB0byBkZXN0aW5hdGlvbnNcbiAgICAgKiBAcGFyYW0gc3RhdGUgQXBwbGljYXRpb24gc3RhdGVcbiAgICAgKiBAcGFyYW0gZXZlbnRzUXVldWUgSVF1ZXVlIGluc3RhbmNlXG4gICAgICogQHBhcmFtIGV2ZW50IFJ1ZGRlckV2ZW50IG9iamVjdFxuICAgICAqIEBwYXJhbSBlcnJvckhhbmRsZXIgRXJyb3IgaGFuZGxlciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gICAgICogQHJldHVybnMgbm9uZVxuICAgICAqL2VucXVldWUoc3RhdGUsZXZlbnRzUXVldWUsZXZlbnQsZXJyb3JIYW5kbGVyLGxvZ2dlcil7ZXZlbnRzUXVldWUuYWRkSXRlbShldmVudCk7fSwvKipcbiAgICAgKiBUaGlzIGV4dGVuc2lvbiBwb2ludCBpcyB1c2VkIHRvIGRpcmVjdGx5IHNlbmQgdGhlI
1HRyYW5zZm9ybWVkIGV2ZW50IHRvIHRoZSBkZXN0aW5hdGlvblxuICAgICAqIEBwYXJhbSBzdGF0ZSBBcHBsaWNhdGlvbiBzdGF0ZVxuICAgICAqIEBwYXJhbSBldmVudCBSdWRkZXJFdmVudCBPYmplY3RcbiAgICAgKiBAcGFyYW0gZGVzdGluYXRpb24gRGVzdGluYXRpb24gT2JqZWN0XG4gICAgICogQHBhcmFtIGVycm9ySGFuZGxlciBFcnJvciBoYW5kbGVyIGluc3RhbmNlXG4gICAgICogQHBhcmFtIGxvZ2dlciBMb2dnZXIgaW5zdGFuY2VcbiAgICAgKi9lbnF1ZXVlRXZlbnRUb0Rlc3RpbmF0aW9uKHN0YXRlLGV2ZW50LGRlc3RpbmF0aW9uLGVycm9ySGFuZGxlcixsb2dnZXIpe3NlbmRFdmVudFRvRGVzdGluYXRpb24oZXZlbnQsZGVzdGluYXRpb24sZXJyb3JIYW5kbGVyKTt9fX0pO1xuXG5jb25zdCBPTkVUUlVTVF9BQ0NFU1NfRVJST1I9Y29udGV4dD0+YCR7Y29udGV4dH0ke0xPR19DT05URVhUX1NFUEFSQVRPUn1GYWlsZWQgdG8gYWNjZXNzIE9uZVRydXN0IFNESyByZXNvdXJjZXMuIFBsZWFzZSBlbnN1cmUgdGhhdCB0aGUgT25lVHJ1c3QgU0RLIGlzIGxvYWRlZCBzdWNjZXNzZnVsbHkgYmVmb3JlIFJ1ZGRlclN0YWNrIFNESy5gO2NvbnN0IERFU1RJTkFUSU9OX0NPTlNFTlRfU1RBVFVTX0VSUk9SPWBGYWlsZWQgdG8gZGV0ZXJtaW5lIHRoZSBjb25zZW50IHN0YXR1cyBmb3IgdGhlIGRlc3RpbmF0aW9uLiBQbGVhc2UgY2hlY2sgdGhlIGRlc3RpbmF0aW9uIGNvbmZpZ3VyYXRpb24gYW5kIHRyeSBhZ2Fpbi5gO1xuXG5jb25zdCBPTkVUUlVTVF9DT05TRU5UX01BTkFHRVJfUExVR0lOPSdPbmVUcnVzdENvbnNlbnRNYW5hZ2VyUGx1Z2luJztcblxuY29uc3QgcGx1Z2luTmFtZSQ0PSdPbmVUcnVzdENvbnNlbnRNYW5hZ2VyJztjb25zdCBPbmVUcnVzdENvbnNlbnRNYW5hZ2VyPSgpPT4oe25hbWU6cGx1Z2luTmFtZSQ0LGRlcHM6W10saW5pdGlhbGl6ZTpzdGF0ZT0+e3N0YXRlLnBsdWdpbnMubG9hZGVkUGx1Z2lucy52YWx1ZT1bLi4uc3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlLHBsdWdpbk5hbWUkNF07fSxjb25zZW50TWFuYWdlcjp7aW5pdChzdGF0ZSxsb2dnZXIpey8vIE5vdGhpbmcgdG8gaW5pdGlhbGl6ZVxufSx1cGRhdGVDb25zZW50c0luZm8oc3RhdGUsc3RvcmVNYW5hZ2VyLGxvZ2dlcil7aWYoIWdsb2JhbFRoaXMuT25lVHJ1c3R8fCFnbG9iYWxUaGlzLk9uZXRydXN0QWN0aXZlR3JvdXBzKXtsb2dnZXI/LmVycm9yKE9ORVRSVVNUX0FDQ0VTU19FUlJPUihPTkVUUlVTVF9DT05TRU5UX01BTkFHRVJfUExVR0lOKSk7c3RhdGUuY29uc2VudHMuaW5pdGlhbGl6ZWQudmFsdWU9ZmFsc2U7cmV0dXJuO30vLyBHZXQgdGhlIGdyb3VwcyAoY29va2llIGNhdGVnb3JpemF0aW9uKSwgdXNlciBoYXMgY3JlYXRlZCBpbiBPbmVUcnVzdCBhY2NvdW50LlxuY29uc3Qgb25lVHJ1c3RBbGxHcm91cHNJbmZvPWdsb2JhbFRoaXMuT25lVHJ1c3QuR2V0RG9tYWluRGF0YSgpLkdyb3VwczsvLyBPbmVUcnVzdENvbnNlbnRNYW5hZ2VyIFNESyBwb3B1bGF0ZXMgYSBkYXRhIGxheWVyIG9iamVjdCBPbmV0cnVzdEFjdGl2ZUdyb3VwcyB3aXRoXG4vLyB0aGUgY29va2llIGNhdGVnb3JpZXMgSWRzIHRoYXQgdGhlIHVzZXIgaGFzIGNvbnNlbnRlZCB0by5cbi8vIEVnOiAnLEMwMDAxLEMwMDAzLCdcbi8vIFdlIHNwbGl0IGl0IGFuZCBzYXZlIGl0IGFzIGFuIGFycmF5LlxuY29uc3QgYWxsb3dlZENvbnNlbnRJZHM9Z2xvYmFsVGhpcy5PbmV0cnVzdEFjdGl2ZUdyb3Vwcy5zcGxpdCgnLCcpLmZpbHRlcihuPT5uKTtjb25zdCBkZW5pZWRDb25zZW50SWRzPVtdO29uZVRydXN0QWxsR3JvdXBzSW5mby5mb3JFYWNoKCh7Q3VzdG9tR3JvdXBJZH0pPT57aWYoIWFsbG93ZWRDb25zZW50SWRzLmluY2x1ZGVzKEN1c3RvbUdyb3VwSWQpKXtkZW5pZWRDb25zZW50SWRzLnB1c2goQ3VzdG9tR3JvdXBJZCk7fX0pO3N0YXRlLmNvbnNlbnRzLmluaXRpYWxpemVkLnZhbHVlPXRydWU7c3RhdGUuY29uc2VudHMuZGF0YS52YWx1ZT17YWxsb3dlZENvbnNlbnRJZHMsZGVuaWVkQ29uc2VudElkc307fSxpc0Rlc3RpbmF0aW9uQ29uc2VudGVkKHN0YXRlLGRlc3RDb25maWcsZXJyb3JIYW5kbGVyLGxvZ2dlcil7aWYoIXN0YXRlLmNvbnNlbnRzLmluaXRpYWxpemVkLnZhbHVlKXtyZXR1cm4gdHJ1ZTt9Y29uc3QgYWxsb3dlZENvbnNlbnRJZHM9c3RhdGUuY29uc2VudHMuZGF0YS52YWx1ZS5hbGxvd2VkQ29uc2VudElkczt0cnl7Ly8gbWFwcGluZyBvZiB0aGUgZGVzdGluYXRpb24gd2l0aCB0aGUgY29uc2VudCBncm91cCBuYW1lXG5jb25zdHtvbmVUcnVzdENvb2tpZUNhdGVnb3JpZXMsY29uc2VudE1hbmFnZW1lbnR9PWRlc3RDb25maWc7Y29uc3QgbWF0Y2hQcmVkaWNhdGU9Y29uc2VudD0+YWxsb3dlZENvbnNlbnRJZHMuaW5jbHVkZXMoY29uc2VudCk7Ly8gR2VuZXJpYyBjb25zZW50IG1hbmFnZW1lbnRcbmlmKGNvbnNlbnRNYW5hZ2VtZW50KXsvLyBHZXQgdGhlIGNvcnJlc3BvbmRpbmcgY29uc2VudHMgZm9yIHRoZSBkZXN0aW5hdGlvblxuY29uc3QgY21wQ29uc2VudHM9Y29uc2VudE1hbmFnZW1lbnQuZmluZChjPT5jLnByb3ZpZGVyPT09c3RhdGUuY29uc2VudHMucHJvdmlkZXIudmFsdWUpPy5jb25zZW50czsvLyBJZiB0aGVyZSBhcmUgbm8gY29uc2VudHMgY29uZmlndXJlZCBmb3IgdGhlIGRlc3RpbmF0aW9uIGZvciB0aGUgY3VycmVudCBwcm92aWRlciwgZXZlbnRzIHNob3VsZCBiZSBzZW50LlxuaWYoIWNtcENvbnNlbnRzKXtyZXR1cm4gdHJ1ZTt9Y29uc3QgY29uZmlndXJlZENvbnNlbnRzPWNtcENvbnNlbnRzLm1hcChjPT5jLmNvbnNlbnQudHJpbSgpKS5maWx0ZXIobj0+bik7Ly8gbWF0Y2ggdGhlIGNvbmZpZ3VyZWQgY29uc2VudHMgd2l0aCB1c2VyIHByb3ZpZGVkIGNvbnNlbnRzIGFzIHBlclxuLy8gdGhlIGNvbmZpZ3VyZWQgcmVzb2x1dGlvbiBzdHJhdGVneVxuc3dpdGNoKHN0YXRlLmNvbnNlbnRzLnJlc29sdXRpb25TdHJhdGVneS52YWx1ZSl7Y2FzZSAnb3InOnJldHVybiBjb25maWd1cmVkQ29uc2VudHMuc29tZShtYXRjaFByZWRpY2F0ZSl8fGNvbmZpZ3VyZWRDb25zZW50cy5sZW5ndGg9PT0wO2Nhc2UgJ2FuZCc6ZGVmYXVsdDpyZXR1cm4gY29uZmlndXJlZENvbnNlbnRzLmV2ZXJ5KG1hdGNoUHJlZGljYXRlKTt9Ly8gTGVnYWN5IGNvb2tpZSBjb25zZW50IG1hbmFnZW1lbnRcbi8vIFRPRE86IFRvIGJlIHJlbW92ZWQgb25jZSB0aGUgc291cmNlIGNvbmZpZyBBUEkgaXMgdXBkYXRlZCB0byBzdXBwb3J0IGdlbmVyaWMgY29uc2VudCBtYW5hZ2VtZW50XG59ZWxzZSBpZihvbmVUcnVzdENvb2tpZUNhdGVnb3JpZXMpey8vIENoYW5nZSB0aGUgc3RydWN0dXJlIG9mIG9uZVRydXN0Q29uc2VudEdyb3VwIGFzIGFuIGFycmF5IGFuZCBmaWx0ZXIgdmFsdWVzIGlmIGVtcHR5IHN0cmluZ1xuLy8gRWc6XG4vLyBbXCJQZXJmb3JtYW5jZSBDb29raWVzXCIsIFwiRnVuY3Rpb25hbCBDb29raWVzXCJdXG5jb25zdCBjb25maWd1cmVkQ29uc2VudHM9b25lVHJ1c3RDb29raWVDYXRlZ29yaWVzLm1hcChjPT5jLm9uZVRydXN0Q29va2llQ2F0ZWdvcnkudHJpbSgpKS5maWx0ZXIobj0+bik7Ly8gQ2hlY2sgaWYgYWxsIHRoZSBkZXN0aW5
1hdGlvbidzIG1hcHBlZCBjb29raWUgY2F0ZWdvcmllcyBhcmUgY29uc2VudGVkIGJ5IHRoZSB1c2VyIGluIHRoZSBicm93c2VyLlxucmV0dXJuIGNvbmZpZ3VyZWRDb25zZW50cy5ldmVyeShtYXRjaFByZWRpY2F0ZSk7fS8vIElmIHRoZXJlIGFyZSBubyBjb25zZW50cyBjb25maWd1cmVkIGZvciB0aGUgZGVzdGluYXRpb24gZm9yIHRoZSBjdXJyZW50IHByb3ZpZGVyLCBldmVudHMgc2hvdWxkIGJlIHNlbnQuXG5yZXR1cm4gdHJ1ZTt9Y2F0Y2goZXJyKXtlcnJvckhhbmRsZXI/Lm9uRXJyb3Ioe2Vycm9yOmVycixjb250ZXh0Ok9ORVRSVVNUX0NPTlNFTlRfTUFOQUdFUl9QTFVHSU4sY3VzdG9tTWVzc2FnZTpERVNUSU5BVElPTl9DT05TRU5UX1NUQVRVU19FUlJPUn0pO3JldHVybiB0cnVlO319fX0pO1xuXG5jb25zdCBwbHVnaW5OYW1lJDM9J1N0b3JhZ2VFbmNyeXB0aW9uJztjb25zdCBTdG9yYWdlRW5jcnlwdGlvbj0oKT0+KHtuYW1lOnBsdWdpbk5hbWUkMyxpbml0aWFsaXplOnN0YXRlPT57c3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlPVsuLi5zdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWUscGx1Z2luTmFtZSQzXTt9LHN0b3JhZ2U6e2VuY3J5cHQodmFsdWUpe3JldHVybiBlbmNyeXB0QnJvd3Nlcih2YWx1ZSk7fSxkZWNyeXB0KHZhbHVlKXtyZXR1cm4gZGVjcnlwdEJyb3dzZXIodmFsdWUpO319fSk7XG5cbi8qIGVzbGludC1kaXNhYmxlIG5vLXVzZS1iZWZvcmUtZGVmaW5lICovY29uc3QgY3J5cHRvJDE9KHR5cGVvZiBnbG9iYWxUaGlzIT0ndW5kZWZpbmVkJz9nbG9iYWxUaGlzOnZvaWQgMCk/LmNyeXB0b3x8KHR5cGVvZiBnbG9iYWwhPSd1bmRlZmluZWQnP2dsb2JhbDp2b2lkIDApPy5jcnlwdG98fCh0eXBlb2Ygd2luZG93IT0ndW5kZWZpbmVkJz93aW5kb3c6dm9pZCAwKT8uY3J5cHRvfHwodHlwZW9mIHNlbGYhPSd1bmRlZmluZWQnP3NlbGY6dm9pZCAwKT8uY3J5cHRvfHwodHlwZW9mIGZyYW1lcyE9J3VuZGVmaW5lZCc/ZnJhbWVzOnZvaWQgMCk/LlswXT8uY3J5cHRvO2xldCByYW5kb21Xb3JkQXJyYXk7aWYoY3J5cHRvJDEpe3JhbmRvbVdvcmRBcnJheT1uQnl0ZXM9Pntjb25zdCB3b3Jkcz1bXTtmb3IobGV0IGk9MCxyY2FjaGU7aTxuQnl0ZXM7aSs9NCl7d29yZHMucHVzaChjcnlwdG8kMS5nZXRSYW5kb21WYWx1ZXMobmV3IFVpbnQzMkFycmF5KDEpKVswXSk7fXJldHVybiBuZXcgV29yZEFycmF5KHdvcmRzLG5CeXRlcyk7fTt9ZWxzZSB7Ly8gQmVjYXVzZSB0aGVyZSBpcyBubyBnbG9iYWwgY3J5cHRvIHByb3BlcnR5IGluIHRoaXMgY29udGV4dCwgY3J5cHRvZ3JhcGh
1pY2FsbHkgdW5zYWZlIE1hdGgucmFuZG9tKCkgaXMgdXNlZC5cbnJhbmRvbVdvcmRBcnJheT1uQnl0ZXM9Pntjb25zdCB3b3Jkcz1bXTtjb25zdCByPW1fdz0+e2xldCBfbV93PW1fdztsZXQgX21fej0weDNhZGU2OGIxO2NvbnN0IG1hc2s9MHhmZmZmZmZmZjtyZXR1cm4gKCk9PntfbV96PTB4OTA2OSooX21feiYweEZGRkYpKyhfbV96Pj4weDEwKSZtYXNrO19tX3c9MHg0NjUwKihfbV93JjB4RkZGRikrKF9tX3c+PjB4MTApJm1hc2s7bGV0IHJlc3VsdD0oX21fejw8MHgxMCkrX21fdyZtYXNrO3Jlc3VsdC89MHgxMDAwMDAwMDA7cmVzdWx0Kz0wLjU7cmV0dXJuIHJlc3VsdCooTWF0aC5yYW5kb20oKT4wLjU/MTotMSk7fTt9O2ZvcihsZXQgaT0wLHJjYWNoZTtpPG5CeXRlcztpKz00KXtjb25zdCBfcj1yKChyY2FjaGV8fE1hdGgucmFuZG9tKCkpKjB4MTAwMDAwMDAwKTtyY2FjaGU9X3IoKSoweDNhZGU2N2I3O3dvcmRzLnB1c2goX3IoKSoweDEwMDAwMDAwMHwwKTt9cmV0dXJuIG5ldyBXb3JkQXJyYXkod29yZHMsbkJ5dGVzKTt9O30vKipcbiAqIEJhc2UgY2xhc3MgZm9yIGluaGVyaXRhbmNlLlxuICovY2xhc3MgQmFzZXsvKipcbiAgICogRXh0ZW5kcyB0aGlzIG9iamVjdCBhbmQgcnVucyB0aGUgaW5pdCBtZXRob2QuXG4gICAqIEFyZ3VtZW50cyB0byBjcmVhdGUoKSB3aWxsIGJlIHBhc3NlZCB0byBpbml0KCkuXG4gICAqXG4gICAqIEByZXR1cm4ge09iamVjdH0gVGhlIG5ldyBvYmplY3QuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBpbnN0YW5jZSA9IE15VHlwZS5jcmVhdGUoKTtcbiAgICovc3RhdGljIGNyZWF0ZSguLi5hcmdzKXtyZXR1cm4gbmV3IHRoaXMoLi4uYXJncyk7fS8qKlxuICAgKiBDb3BpZXMgcHJvcGVydGllcyBpbnRvIHRoaXMgb2JqZWN0LlxuICAgKlxuICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcGVydGllcyBUaGUgcHJvcGVydGllcyB0byBtaXggaW4uXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICBNeVR5cGUubWl4SW4oe1xuICAgKiAgICAgICAgIGZpZWxkOiAndmFsdWUnXG4gICAqICAgICB9KTtcbiAgICovbWl4SW4ocHJvcGVydGllcyl7cmV0dXJuIE9iamVjdC5hc3NpZ24odGhpcyxwcm9wZXJ0aWVzKTt9LyoqXG4gICAqIENyZWF0ZXMgYSBjb3B5IG9mIHRoaXMgb2JqZWN0LlxuICAgKlxuICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBjbG9uZS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBjbG9uZSA9IGluc3RhbmNlLmNsb25lKCk7XG4gICAqL2Nsb25lKCl7Y29uc3QgY2xvbmU9bmV3IHRoaXMuY29uc3RydWN0b3IoKTtPYmplY3QuYXNzaWduKGNsb25lLHRoaXMpO3JldHVybiBjbG9uZTt9fS8qKlxuICogQW4gYXJyYXkgb2YgMzItYml0IHdvcmRzLlxuICpcbiAqIEBwcm9wZXJ0eSB7QXJyYXl9IHdvcmRzIFRoZSBhcnJheSBvZiAzMi1iaXQgd29yZHMuXG4gKiBAcHJvcGVydHkge251bWJlcn0gc2lnQnl0ZXMgVGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBieXRlcyBpbiB0aGlzIHdvcmQgYXJyYXkuXG4gKi9jbGFzcyBXb3JkQXJyYXkgZXh0ZW5kcyBCYXNley8qKlxuICAgKiBJbml0aWFsaXplcyBhIG5ld2x5IGNyZWF0ZWQgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHBhcmFtIHtBcnJheX0gd29yZHMgKE9wdGlvbmFsKSBBbiBhcnJheSBvZiAzMi1iaXQgd29yZHMuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzaWdCeXRlcyAoT3B0aW9uYWwpIFRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgYnl0ZXMgaW4gdGhlIHdvcmRzLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmxpYi5Xb3JkQXJyYXkuY3JlYXRlKCk7XG4gICAqICAgICB2YXIgd29yZEFycmF5ID0gQ3J5cHRvSlMubGliLldvcmRBcnJheS5jcmVhdGUoWzB4MDAwMTAyMDMsIDB4MDQwNTA2MDddKTtcbiAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5saWIuV29yZEFycmF5LmNyZWF0ZShbMHgwMDAxMDIwMywgMHgwNDA1MDYwN10sIDYpO1xuICAgKi9jb25zdHJ1Y3Rvcih3b3Jkcz1bXSxzaWdCeXRlcz13b3Jkcy5sZW5ndGgqNCl7c3VwZXIoKTtsZXQgdHlwZWRBcnJheT13b3JkczsvLyBDb252ZXJ0IGJ1ZmZlcnMgdG8gdWludDhcbmlmKHR5cGVkQXJyYXkgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcil7dHlwZWRBcnJheT1uZXcgVWludDhBcnJheSh0eXBlZEFycmF5KTt9Ly8gQ29udmVydCBvdGhlciBhcnJheSB2aWV3cyB0byB1aW50OFxuaWYodHlwZWRBcnJheSBpbnN0YW5jZW9mIEludDhBcnJheXx8dHlwZWRBcnJheSBpbnN0YW5jZW9mIFVpbnQ4Q2xhbXBlZEFycmF5fHx0eXBlZEFycmF5IGluc3RhbmNlb2YgSW50MTZBcnJheXx8dHlwZWRBcnJheSBpbnN0YW5jZW9mIFVpbnQxNkFycmF
15fHx0eXBlZEFycmF5IGluc3RhbmNlb2YgSW50MzJBcnJheXx8dHlwZWRBcnJheSBpbnN0YW5jZW9mIFVpbnQzMkFycmF5fHx0eXBlZEFycmF5IGluc3RhbmNlb2YgRmxvYXQzMkFycmF5fHx0eXBlZEFycmF5IGluc3RhbmNlb2YgRmxvYXQ2NEFycmF5KXt0eXBlZEFycmF5PW5ldyBVaW50OEFycmF5KHR5cGVkQXJyYXkuYnVmZmVyLHR5cGVkQXJyYXkuYnl0ZU9mZnNldCx0eXBlZEFycmF5LmJ5dGVMZW5ndGgpO30vLyBIYW5kbGUgVWludDhBcnJheVxuaWYodHlwZWRBcnJheSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpey8vIFNob3J0Y3V0XG5jb25zdCB0eXBlZEFycmF5Qnl0ZUxlbmd0aD10eXBlZEFycmF5LmJ5dGVMZW5ndGg7Ly8gRXh0cmFjdCBieXRlc1xuY29uc3QgX3dvcmRzPVtdO2ZvcihsZXQgaT0wO2k8dHlwZWRBcnJheUJ5dGVMZW5ndGg7aSs9MSl7X3dvcmRzW2k+Pj4yXXw9dHlwZWRBcnJheVtpXTw8MjQtaSU0Kjg7fS8vIEluaXRpYWxpemUgdGhpcyB3b3JkIGFycmF5XG50aGlzLndvcmRzPV93b3Jkczt0aGlzLnNpZ0J5dGVzPXR5cGVkQXJyYXlCeXRlTGVuZ3RoO31lbHNlIHsvLyBFbHNlIGNhbGwgbm9ybWFsIGluaXRcbnRoaXMud29yZHM9d29yZHM7dGhpcy5zaWdCeXRlcz1zaWdCeXRlczt9fS8qKlxuICAgKiBDcmVhdGVzIGEgd29yZCBhcnJheSBmaWxsZWQgd2l0aCByYW5kb20gYnl0ZXMuXG4gICAqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBuQnl0ZXMgVGhlIG51bWJlciBvZiByYW5kb20gYnl0ZXMgdG8gZ2VuZXJhdGUuXG4gICAqXG4gICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIHJhbmRvbSB3b3JkIGFycmF5LlxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICB2YXIgd29yZEFycmF5ID0gQ3J5cHRvSlMubGliLldvcmRBcnJheS5yYW5kb20oMTYpO1xuICAgKi9zdGF0aWMgcmFuZG9tPXJhbmRvbVdvcmRBcnJheTsvKipcbiAgICogQ29udmVydHMgdGhpcyB3b3JkIGFycmF5IHRvIGEgc3RyaW5nLlxuICAgKlxuICAgKiBAcGFyYW0ge0VuY29kZXJ9IGVuY29kZXIgKE9wdGlvbmFsKSBUaGUgZW5jb2Rpbmcgc3RyYXRlZ3kgdG8gdXNlLiBEZWZhdWx0OiBDcnlwdG9KUy5lbmMuSGV4XG4gICAqXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIHN0cmluZ2lmaWVkIHdvcmQgYXJyYXkuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICB2YXIgc3RyaW5nID0gd29yZEFycmF5ICsgJyc7XG4gICAqICAgICB2YXIgc3RyaW5nID0gd29yZEFycmF5LnRvU3RyaW5nKCk7XG4gICAqICAgICB2YXIgc3RyaW5nID0gd29yZEFycmF5LnRvU3RyaW5nKENyeXB0b0pTLmVuYy5VdGY4KTtcbiAgICovdG9TdHJpbmcoZW5jb2Rlcj1IZXgpe3JldHVybiBlbmNvZGVyLnN0cmluZ2lmeSh0aGlzKTt9LyoqXG4gICAqIENvbmNhdGVuYXRlcyBhIHdvcmQgYXJyYXkgdG8gdGhpcyB3b3JkIGFycmF5LlxuICAgKlxuICAgKiBAcGFyYW0ge1dvcmRBcnJheX0gd29yZEFycmF5IFRoZSB3b3JkIGFycmF5IHRvIGFwcGVuZC5cbiAgICpcbiAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGlzIHdvcmQgYXJyYXkuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICB3b3JkQXJyYXkxLmNvbmNhdCh3b3JkQXJyYXkyKTtcbiAgICovY29uY2F0KHdvcmRBcnJheSl7Ly8gU2hvcnRjdXRzXG5jb25zdCB0aGlzV29yZHM9dGhpcy53b3Jkcztjb25zdCB0aGF0V29yZHM9d29yZEFycmF5LndvcmRzO2NvbnN0IHRoaXNTaWdCeXRlcz10aGlzLnNpZ0J5dGVzO2NvbnN0IHRoYXRTaWdCeXRlcz13b3JkQXJyYXkuc2lnQnl0ZXM7Ly8gQ2xhbXAgZXhjZXNzIGJpdHNcbnRoaXMuY2xhbXAoKTsvLyBDb25jYXRcbmlmKHRoaXNTaWdCeXRlcyU0KXsvLyBDb3B5IG9uZSBieXRlIGF0IGEgdGltZVxuZm9yKGxldCBpPTA7aTx0aGF0U2lnQnl0ZXM7aSs9MSl7Y29uc3QgdGhhdEJ5dGU9dGhhdFdvcmRzW2k+Pj4yXT4+PjI0LWklNCo4JjB4ZmY7dGhpc1dvcmRzW3RoaXNTaWdCeXRlcytpPj4+Ml18PXRoYXRCeXRlPDwyNC0odGhpc1NpZ0J5dGVzK2kpJTQqODt9fWVsc2Ugey8vIENvcHkgb25lIHdvcmQgYXQgYSB0aW1lXG5mb3IobGV0IGk9MDtpPHRoYXRTaWdCeXRlcztpKz00KXt0aGlzV29yZHNbdGhpc1NpZ0J5dGVzK2k+Pj4yXT10aGF0V29yZHNbaT4+PjJdO319dGhpcy5zaWdCeXRlcys9dGhhdFNpZ0J5dGVzOy8vIENoYWluYWJsZVxucmV0dXJuIHRoaXM7fS8qKlxuICAgKiBSZW1vdmVzIGluc2lnbmlmaWNhbnQgYml0cy5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHdvcmRBcnJheS5jbGFtcCgpO1xuICAgKi9jbGFtcCgpey8vIFNob3J0Y3V0c1xuY29uc3R7d29yZHMsc2lnQnl0ZXN9PXRoaXM7Ly8gQ2xhbXBcbndvcmRzW3NpZ0J5dGVzPj4+Ml0mPTB4ZmZmZmZmZmY8PDMyLXNpZ0J5dGVzJTQqODt3b3Jkcy5sZW5ndGg9TWF0aC5jZWlsKHNpZ0J5dGVzLzQpO30vKipcbiAgICogQ3JlYXRlcyBhIGNvcHkgb2YgdGhpcyB3b3JkIGFycmF5LlxuICAgKlxuICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBjbG9uZS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBjbG9uZSA9IHdvcmRBcnJheS5jbG9uZSgpO1xuICAgKi9jbG9uZSgpe2NvbnN0IGNsb25lPXN1cGVyLmNsb25lLmNhbGwodGhpcyk7Y2xvbmUud29yZHM9dGhpcy53b3Jkcy5zbGljZSgwKTtyZXR1cm4gY2xvbmU7fX0vKipcbiAqIEhleCBlbmNvZGluZyBzdHJhdGVneS5cbiAqL2NvbnN0IEhleD17LyoqXG4gICAqIENvbnZlcnRzIGEgd29yZCBhcnJheSB0byBhIGhleCBzdHJpbmcuXG4gICAqXG4gICAqIEBwYXJhbSB7V29yZEFycmF5fSB3b3JkQXJyYXkgVGhlIHdvcmQgYXJyYXkuXG4gICAqXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGhleCBzdHJpbmcuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBoZXhTdHJpbmcgPSBDcnlwdG9KUy5lbmMuSGV4LnN0cmluZ2lmeSh3b3JkQXJyYXkpO1xuICAgKi9zdHJpbmdpZnkod29yZEFycmF5KXsvLyBTaG9ydGN1dHNcbmNvbnN0e3dvcmRzLHNpZ0J5dGVzfT13b3JkQXJyYXk7Ly8gQ29udmVydFxuY29uc3QgaGV4Q2hhcnM9W107Zm9yKGxldCBpPTA7aTxzaWdCeXRlcztpKz0xKXtjb25zdCBiaXRlPXdvcmRzW2k+Pj4yXT4+PjI0LWklNCo4JjB4ZmY7aGV4Q2hhcnMucHVzaCgoYml0ZT4+PjQpLnRvU3RyaW5nKDE2KSk7aGV4Q2hhcnMucHVzaCgoYml0ZSYweDBmKS50b1N0cmluZygxNikpO31yZXR1cm4gaGV4Q2hhcnMuam9pbignJyk7fSwvKipcbiAgICogQ29udmVydHMgYSBoZXggc3RyaW5nIHRvIGEgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGhleFN0ciBUaGUgaGV4IHN0cmluZy5cbiAgICpcbiAgICogQHJldHVybi
1B7V29yZEFycmF5fSBUaGUgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmVuYy5IZXgucGFyc2UoaGV4U3RyaW5nKTtcbiAgICovcGFyc2UoaGV4U3RyKXsvLyBTaG9ydGN1dFxuY29uc3QgaGV4U3RyTGVuZ3RoPWhleFN0ci5sZW5ndGg7Ly8gQ29udmVydFxuY29uc3Qgd29yZHM9W107Zm9yKGxldCBpPTA7aTxoZXhTdHJMZW5ndGg7aSs9Mil7d29yZHNbaT4+PjNdfD1wYXJzZUludChoZXhTdHIuc3Vic3RyKGksMiksMTYpPDwyNC1pJTgqNDt9cmV0dXJuIG5ldyBXb3JkQXJyYXkod29yZHMsaGV4U3RyTGVuZ3RoLzIpO319Oy8qKlxuICogTGF0aW4xIGVuY29kaW5nIHN0cmF0ZWd5LlxuICovY29uc3QgTGF0aW4xPXsvKipcbiAgICogQ29udmVydHMgYSB3b3JkIGFycmF5IHRvIGEgTGF0aW4xIHN0cmluZy5cbiAgICpcbiAgICogQHBhcmFtIHtXb3JkQXJyYXl9IHdvcmRBcnJheSBUaGUgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgTGF0aW4xIHN0cmluZy5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIGxhdGluMVN0cmluZyA9IENyeXB0b0pTLmVuYy5MYXRpbjEuc3RyaW5naWZ5KHdvcmRBcnJheSk7XG4gICAqL3N0cmluZ2lmeSh3b3JkQXJyYXkpey8vIFNob3J0Y3V0c1xuY29uc3R7d29yZHMsc2lnQnl0ZXN9PXdvcmRBcnJheTsvLyBDb252ZXJ0XG5jb25zdCBsYXRpbjFDaGFycz1bXTtmb3IobGV0IGk9MDtpPHNpZ0J5dGVzO2krPTEpe2NvbnN0IGJpdGU9d29yZHNbaT4+PjJdPj4+MjQtaSU0KjgmMHhmZjtsYXRpbjFDaGFycy5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYml0ZSkpO31yZXR1cm4gbGF0aW4xQ2hhcnMuam9pbignJyk7fSwvKipcbiAgICogQ29udmVydHMgYSBMYXRpbjEgc3RyaW5nIHRvIGEgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGxhdGluMVN0ciBUaGUgTGF0aW4xIHN0cmluZy5cbiAgICpcbiAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmVuYy5MYXRpbjEucGFyc2UobGF0aW4xU3RyaW5nKTtcbiAgICovcGFyc2UobGF0aW4xU3RyKXsvLyBTaG9ydGN1dFxuY29uc3QgbGF0aW4xU3RyTGVuZ3RoPWxhdGluMVN0ci5sZW5ndGg7Ly8gQ29udmVydFxuY29uc3Qgd29yZHM9W107Zm9yKGxldCBpPTA7aTxsYXRpbjFTdHJMZW5ndGg7aSs9MSl7d29yZHNbaT4+PjJdfD0obGF0aW4xU3RyLmNoYXJDb2RlQXQoaSkmMHhmZik8PDI0LWklNCo4O31yZXR1cm4gbmV3IFdvcmRBcnJheSh3b3JkcyxsYXRpbjFTdHJMZW5ndGgpO319Oy8qKlxuICogVVRGLTggZW5jb2Rpbmcgc3RyYXRlZ3kuXG4gKi9jb25zdCBVdGY4PXsvKipcbiAgICogQ29udmVydHMgYSB3b3JkIGFycmF5IHRvIGEgVVRGLTggc3RyaW5nLlxuICAgKlxuICAgKiBAcGFyYW0ge1dvcmRBcnJheX0gd29yZEFycmF5IFRoZSB3b3JkIGFycmF5LlxuICAgKlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBVVEYtOCBzdHJpbmcuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciB1dGY4U3RyaW5nID0gQ3J5cHRvSlMuZW5jLlV0Zjguc3RyaW5naWZ5KHdvcmRBcnJheSk7XG4gICAqL3N0cmluZ2lmeSh3b3JkQXJyYXkpe3RyeXtyZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KGVzY2FwZShMYXRpbjEuc3RyaW5naWZ5KHdvcmRBcnJheSkpKTt9Y2F0Y2goZSl7dGhyb3cgbmV3IEVycm9yKCdNYWxmb3JtZWQgVVRGLTggZGF0YScpO319LC8qKlxuICAgKiBDb252ZXJ0cyBhIFVURi04IHN0cmluZyB0byBhIHdvcmQgYXJyYXkuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1dGY4U3RyIFRoZSBVVEYtOCBzdHJpbmcuXG4gICAqXG4gICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIHdvcmQgYXJyYXkuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5lbmMuVXRmOC5wYXJzZSh1dGY4U3RyaW5nKTtcbiAgICovcGFyc2UodXRmOFN0cil7cmV0dXJuIExhdGluMS5wYXJzZSh1bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQodXRmOFN0cikpKTt9fTsvKipcbiAqIEFic3RyYWN0IGJ1ZmZlcmVkIGJsb2NrIGFsZ29yaXRobSB0ZW1wbGF0ZS5cbiAqXG4gKiBUaGUgcHJvcGVydHkgYmxvY2tTaXplIG11c3QgYmUgaW1wbGVtZW50ZWQgaW4gYSBjb25jcmV0ZSBzdWJ0eXBlLlxuICpcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBfbWluQnVmZmVyU2l6ZVxuICpcbiAqICAgICBUaGUgbnVtYmVyIG9mIGJsb2NrcyB0aGF0IHNob3VsZCBiZSBrZXB0IHVucHJvY2Vzc2VkIGluIHRoZSBidWZmZXIuIERlZmF1bHQ6IDBcbiAqL2NsYXNzIEJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0gZXh0ZW5kcyBCYXNle2NvbnN0cnVjdG9yKCl7c3VwZXIoKTt0aGlzLl9taW5CdWZmZXJTaXplPTA7fS8qKlxuICAgKiBSZXNldHMgdGhpcyBibG9jayBhbGdvcml0aG0ncyBkYXRhIGJ1ZmZlciB0byBpdHMgaW5pdGlhbCBzdGF0ZS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0ucmVzZXQoKTtcbiAgICovcmVzZXQoKXsvLyBJbml0aWFsIHZhbHVlc1xudGhpcy5fZGF0YT1uZXcgV29yZEFycmF5KCk7dGhpcy5fbkRhdGFCeXRlcz0wO30vKipcbiAgICogQWRkcyBuZXcgZGF0YSB0byB0aGlzIGJsb2NrIGFsZ29yaXRobSdzIGJ1ZmZlci5cbiAgICpcbiAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBkYXRhXG4gICAqXG4gICAqICAgICBUaGUgZGF0YSB0byBhcHBlbmQuIFN0cmluZ3MgYXJlIGNvbnZlcnRlZCB0byBhIFdvcmRBcnJheSB1c2luZyBVVEYtOC5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0uX2FwcGVuZCgnZGF0YScpO1xuICAgKiAgICAgYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5fYXBwZW5kKHdvcmRBcnJheSk7XG4gICAqL19hcHBlbmQoZGF0YSl7bGV0IG1fZGF0YT1kYXRhOy8vIENvbnZlcnQgc3RyaW5nIHRvIFdvcmRBcnJheSwgZWxzZSBhc3N1bWUg
1V29yZEFycmF5IGFscmVhZHlcbmlmKHR5cGVvZiBtX2RhdGE9PT0nc3RyaW5nJyl7bV9kYXRhPVV0ZjgucGFyc2UobV9kYXRhKTt9Ly8gQXBwZW5kXG50aGlzLl9kYXRhLmNvbmNhdChtX2RhdGEpO3RoaXMuX25EYXRhQnl0ZXMrPW1fZGF0YS5zaWdCeXRlczt9LyoqXG4gICAqIFByb2Nlc3NlcyBhdmFpbGFibGUgZGF0YSBibG9ja3MuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIGludm9rZXMgX2RvUHJvY2Vzc0Jsb2NrKG9mZnNldCksIHdoaWNoIG11c3QgYmUgaW1wbGVtZW50ZWQgYnkgYSBjb25jcmV0ZSBzdWJ0eXBlLlxuICAgKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGRvRmx1c2ggV2hldGhlciBhbGwgYmxvY2tzIGFuZCBwYXJ0aWFsIGJsb2NrcyBzaG91bGQgYmUgcHJvY2Vzc2VkLlxuICAgKlxuICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBwcm9jZXNzZWQgZGF0YS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBwcm9jZXNzZWREYXRhID0gYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5fcHJvY2VzcygpO1xuICAgKiAgICAgdmFyIHByb2Nlc3NlZERhdGEgPSBidWZmZXJlZEJsb2NrQWxnb3JpdGhtLl9wcm9jZXNzKCEhJ2ZsdXNoJyk7XG4gICAqL19wcm9jZXNzKGRvRmx1c2gpe2xldCBwcm9jZXNzZWRXb3JkczsvLyBTaG9ydGN1dHNcbmNvbnN0e19kYXRhOmRhdGEsYmxvY2tTaXplfT10aGlzO2NvbnN0IGRhdGFXb3Jkcz1kYXRhLndvcmRzO2NvbnN0IGRhdGFTaWdCeXRlcz1kYXRhLnNpZ0J5dGVzO2NvbnN0IGJsb2NrU2l6ZUJ5dGVzPWJsb2NrU2l6ZSo0Oy8vIENvdW50IGJsb2NrcyByZWFkeVxubGV0IG5CbG9ja3NSZWFkeT1kYXRhU2lnQnl0ZXMvYmxvY2tTaXplQnl0ZXM7aWYoZG9GbHVzaCl7Ly8gUm91bmQgdXAgdG8gaW5jbHVkZSBwYXJ0aWFsIGJsb2Nrc1xubkJsb2Nrc1JlYWR5PU1hdGguY2VpbChuQmxvY2tzUmVhZHkpO31lbHNlIHsvLyBSb3VuZCBkb3duIHRvIGluY2x1ZGUgb25seSBmdWxsIGJsb2Nrcyxcbi8vIGxlc3MgdGhlIG51bWJlciBvZiBibG9ja3MgdGhhdCBtdXN0IHJlbWFpbiBpbiB0aGUgYnVmZmVyXG5uQmxvY2tzUmVhZHk9TWF0aC5tYXgoKG5CbG9ja3NSZWFkeXwwKS10aGlzLl9taW5CdWZmZXJTaXplLDApO30vLyBDb3VudCB3b3JkcyByZWFkeVxuY29uc3QgbldvcmRzUmVhZHk9bkJsb2Nrc1JlYWR5KmJsb2NrU2l6ZTsvLyBDb3VudCBieXRlcyByZWFkeVxuY29uc3QgbkJ5dGVzUmVhZHk9TWF0aC5taW4obldvcmRzUmVhZHkqNCxkYXRhU2lnQnl0ZXMpOy8vIFByb2Nlc3MgYmxvY2tzXG5pZihuV29yZHNSZWFkeSl7Zm9yKGxldCBvZmZzZXQ9MDtvZmZzZXQ8bldvcmRzUmVhZHk7b2Zmc2V0Kz1ibG9ja1NpemUpey8vIFBlcmZvcm0gY29uY3JldGUtYWxnb3JpdGhtIGxvZ2ljXG50aGlzLl9kb1Byb2Nlc3NCbG9jayhkYXRhV29yZHMsb2Zmc2V0KTt9Ly8gUmVtb3ZlIHByb2Nlc3NlZCB3b3Jkc1xucHJvY2Vzc2VkV29yZHM9ZGF0YVdvcmRzLnNwbGljZSgwLG5Xb3Jkc1JlYWR5KTtkYXRhLnNpZ0J5dGVzLT1uQnl0ZXNSZWFkeTt9Ly8gUmV0dXJuIHByb2Nlc3NlZCB3b3Jkc1xucmV0dXJuIG5ldyBXb3JkQXJyYXkocHJvY2Vzc2VkV29yZHMsbkJ5dGVzUmVhZHkpO30vKipcbiAgICogQ3JlYXRlcyBhIGNvcHkgb2YgdGhpcyBvYmplY3QuXG4gICAqXG4gICAqIEByZXR1cm4ge09iamVjdH0gVGhlIGNsb25lLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIGNsb25lID0gYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5jbG9uZSgpO1xuICAgKi9jbG9uZSgpe2NvbnN0IGNsb25lPXN1cGVyLmNsb25lLmNhbGwodGhpcyk7Y2xvbmUuX2RhdGE9dGhpcy5fZGF0YS5jbG9uZSgpO3JldHVybiBjbG9uZTt9fS8qKlxuICogQWJzdHJhY3QgaGFzaGVyIHRlbXBsYXRlLlxuICpcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibG9ja1NpemVcbiAqXG4gKiAgICAgVGhlIG51bWJlciBvZiAzMi1iaXQgd29yZHMgdGhpcyBoYXNoZXIgb3BlcmF0ZXMgb24uIERlZmF1bHQ6IDE2ICg1MTIgYml0cylcbiAqL2NsYXNzIEhhc2hlciBleHRlbmRzIEJ1ZmZlcmVkQmxvY2tBbGdvcml0aG17Y29uc3RydWN0b3IoY2ZnKXtzdXBlcigpO3RoaXMuYmxvY2tTaXplPTUxMi8zMjsvKipcbiAgICAgKiBDb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICovdGhpcy5jZmc9T2JqZWN0LmFzc2lnbihuZXcgQmFzZSgpLGNmZyk7Ly8gU2V0IGluaXRpYWwgdmFsdWVzXG50aGlzLnJlc2V0KCk7fS8qKlxuICAgKiBDcmVhdGVzIGEgc2hvcnRjdXQgZnVuY3Rpb24gdG8gYSBoYXNoZXIncyBvYmplY3QgaW50ZXJmYWNlLlxuICAgKlxuICAgKiBAcGFyYW0ge0hhc2hlcn0gU3ViSGFzaGVyIFRoZSBoYXNoZXIgdG8gY3JlYXRlIGEgaGVscGVyIGZvci5cbiAgICpcbiAgICogQHJldHVybiB7RnVuY3Rpb259IFRoZSBzaG9ydGN1dCBmdW5jdGlvbi5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIFNIQTI1NiA9IENyeXB0b0pTLmxpYi5IYXNoZXIuX2NyZWF0ZUhlbHBlcihDcnlwdG9KUy5hbGdvLlNIQTI1Nik7XG4gICAqL3N0YXRpYyBfY3JlYXRlSGVscGVyKFN1Ykhhc2hlcil7cmV0dXJuIChtZXNzYWdlLGNmZyk9Pm5ldyBTdWJIYXNoZXIoY2ZnKS5maW5hbGl6ZShtZXNzYWdlKTt9LyoqXG4gICAqIENyZWF0ZXMgYSBzaG9ydGN1dCBmdW5jdGlvbiB0byB0aGUgSE1BQydzIG9iamVjdCBpbnRlcmZhY2UuXG4gICAqXG4gICAqIEBwYXJhbSB7SGFzaGVyfSBTdWJIYXNoZXIgVGhlIGhhc2hlciB0byB1c2UgaW4gdGhpcyBITUFDIGhlbHBlci5cbiAgICpcbiAgICogQHJldHVybiB7RnVuY3Rpb259IFRoZSBzaG9ydGN1dCBmdW5jdGlvbi5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIEhtYWNTSEEyNTYgPSBDcnlwdG9KUy5saWIuSGFzaGVyLl9jcmVhdGVIbWFjSGVscGVyKENyeXB0b0pTLmFsZ28uU0hBMjU2KTtcbiAgICovc3RhdGljIF9jcmVhdGVIbWFjSGVscGVyKFN1Ykhhc2hlcil7cmV0dXJuIChtZXNzYWdlLGtleSk9Pm5ldyBITUFDKFN1Ykhhc2hlcixrZXkpLmZpbmFsaXplKG1lc3NhZ2UpO30vKipcbiAgICogUmVzZXRzIHRoaXMgaGFzaGVyIHRvIGl0cyBpbml0aWFsIHN0YXRlLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgaGFzaGVyLnJlc2V0KCk7XG4gICAqL3Jlc2V0KCl7Ly8gUmVzZXQgZGF0YSBidWZmZXJcbnN1cGVyLnJlc2V0LmNhbGwodGhpcyk7Ly8gUGVyZm9ybSBjb25jcmV0ZS1oYXNoZXIgbG9naWNcbnRoaXMuX2RvUmVzZXQoKTt9LyoqXG4gICAqIFVwZGF0ZXMgdGhpcyBoYXNoZXIgd2l0aCBhIG1lc3NhZ2UuXG4gICAqXG4gICAqIEBwYXJhbSB7V29yZEFycmF
15fHN0cmluZ30gbWVzc2FnZVVwZGF0ZSBUaGUgbWVzc2FnZSB0byBhcHBlbmQuXG4gICAqXG4gICAqIEByZXR1cm4ge0hhc2hlcn0gVGhpcyBoYXNoZXIuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICBoYXNoZXIudXBkYXRlKCdtZXNzYWdlJyk7XG4gICAqICAgICBoYXNoZXIudXBkYXRlKHdvcmRBcnJheSk7XG4gICAqL3VwZGF0ZShtZXNzYWdlVXBkYXRlKXsvLyBBcHBlbmRcbnRoaXMuX2FwcGVuZChtZXNzYWdlVXBkYXRlKTsvLyBVcGRhdGUgdGhlIGhhc2hcbnRoaXMuX3Byb2Nlc3MoKTsvLyBDaGFpbmFibGVcbnJldHVybiB0aGlzO30vKipcbiAgICogRmluYWxpemVzIHRoZSBoYXNoIGNvbXB1dGF0aW9uLlxuICAgKiBOb3RlIHRoYXQgdGhlIGZpbmFsaXplIG9wZXJhdGlvbiBpcyBlZmZlY3RpdmVseSBhIGRlc3RydWN0aXZlLCByZWFkLW9uY2Ugb3BlcmF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0ge1dvcmRBcnJheXxzdHJpbmd9IG1lc3NhZ2VVcGRhdGUgKE9wdGlvbmFsKSBBIGZpbmFsIG1lc3NhZ2UgdXBkYXRlLlxuICAgKlxuICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBoYXNoLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIGhhc2ggPSBoYXNoZXIuZmluYWxpemUoKTtcbiAgICogICAgIHZhciBoYXNoID0gaGFzaGVyLmZpbmFsaXplKCdtZXNzYWdlJyk7XG4gICAqICAgICB2YXIgaGFzaCA9IGhhc2hlci5maW5hbGl6ZSh3b3JkQXJyYXkpO1xuICAgKi9maW5hbGl6ZShtZXNzYWdlVXBkYXRlKXsvLyBGaW5hbCBtZXNzYWdlIHVwZGF0ZVxuaWYobWVzc2FnZVVwZGF0ZSl7dGhpcy5fYXBwZW5kKG1lc3NhZ2VVcGRhdGUpO30vLyBQZXJmb3JtIGNvbmNyZXRlLWhhc2hlciBsb2dpY1xuY29uc3QgaGFzaD10aGlzLl9kb0ZpbmFsaXplKCk7cmV0dXJuIGhhc2g7fX0vKipcbiAqIEhNQUMgYWxnb3JpdGhtLlxuICovY2xhc3MgSE1BQyBleHRlbmRzIEJhc2V7LyoqXG4gICAqIEluaXRpYWxpemVzIGEgbmV3bHkgY3JlYXRlZCBITUFDLlxuICAgKlxuICAgKiBAcGFyYW0ge0hhc2hlcn0gU3ViSGFzaGVyIFRoZSBoYXNoIGFsZ29yaXRobSB0byB1c2UuXG4gICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30ga2V5IFRoZSBzZWNyZXQga2V5LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIGhtYWNIYXNoZXIgPSBDcnlwdG9KUy5hbGdvLkhNQUMuY3JlYXRlKENyeXB0b0pTLmFsZ28uU0hBMjU2LCBrZXkpO1xuICAgKi9jb25zdHJ1Y3RvcihTdWJIYXNoZXIsa2V5KXtzdXBlcigpO2NvbnN0IGhhc2hlcj1uZXcgU3ViSGFzaGVyKCk7dGhpcy5faGFzaGVyPWhhc2hlcjsvLyBDb252ZXJ0IHN0cmluZyB0byBXb3JkQXJyYXksIGVsc2UgYXNzdW1lIFdvcmRBcnJheSBhbHJlYWR5XG5sZXQgX2tleT1rZXk7aWYodHlwZW9mIF9rZXk9PT0nc3RyaW5nJyl7X2tleT1VdGY4LnBhcnNlKF9rZXkpO30vLyBTaG9ydGN1dHNcbmNvbnN0IGhhc2hlckJsb2NrU2l6ZT1oYXNoZXIuYmxvY2tTaXplO2NvbnN0IGhhc2hlckJsb2NrU2l6ZUJ5dGVzPWhhc2hlckJsb2NrU2l6ZSo0Oy8vIEFsbG93IGFyYml0cmFyeSBsZW5ndGgga2V5c1xuaWYoX2tleS5zaWdCeXRlcz5oYXNoZXJCbG9ja1NpemVCeXRlcyl7X2tleT1oYXNoZXIuZmluYWxpemUoa2V5KTt9Ly8gQ2xhbXAgZXhjZXNzIGJpdHNcbl9rZXkuY2xhbXAoKTsvLyBDbG9uZSBrZXkgZm9yIGlubmVyIGFuZCBvdXRlciBwYWRzXG5jb25zdCBvS2V5PV9rZXkuY2xvbmUoKTt0aGlzLl9vS2V5PW9LZXk7Y29uc3QgaUtleT1fa2V5LmNsb25lKCk7dGhpcy5faUtleT1pS2V5Oy8vIFNob3J0Y3V0c1xuY29uc3Qgb0tleVdvcmRzPW9LZXkud29yZHM7Y29uc3QgaUtleVdvcmRzPWlLZXkud29yZHM7Ly8gWE9SIGtleXMgd2l0aCBwYWQgY29uc3RhbnRzXG5mb3IobGV0IGk9MDtpPGhhc2hlckJsb2NrU2l6ZTtpKz0xKXtvS2V5V29yZHNbaV1ePTB4NWM1YzVjNWM7aUtleVdvcmRzW2ldXj0weDM2MzYzNjM2O31vS2V5LnNpZ0J5dGVzPWhhc2hlckJsb2NrU2l6ZUJ5dGVzO2lLZXkuc2lnQnl0ZXM9aGFzaGVyQmxvY2tTaXplQnl0ZXM7Ly8gU2V0IGluaXRpYWwgdmFsdWVzXG50aGlzLnJlc2V0KCk7fS8qKlxuICAgKiBSZXNldHMgdGhpcyBITUFDIHRvIGl0cyBpbml0aWFsIHN0YXRlLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgaG1hY0hhc2hlci5yZXNldCgpO1xuICAgKi9yZXNldCgpey8vIFNob3J0Y3V0XG5jb25zdCBoYXNoZXI9dGhpcy5faGFzaGVyOy8vIFJlc2V0XG5oYXNoZXIucmVzZXQoKTtoYXNoZXIudXBkYXRlKHRoaXMuX2lLZXkpO30vKipcbiAgICogVXBkYXRlcyB0aGlzIEhNQUMgd2l0aCBhIG1lc3NhZ2UuXG4gICAqXG4gICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gbWVzc2FnZVVwZGF0ZSBUaGUgbWVzc2FnZSB0byBhcHBlbmQuXG4gICAqXG4gICAqIEByZXR1cm4ge0hNQUN9IFRoaXMgSE1BQyBpbnN0YW5jZS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGhtYWNIYXNoZXIudXBkYXRlKCdtZXNzYWdlJyk7XG4gICAqICAgICBobWFjSGFzaGVyLnVwZGF0ZSh3b3JkQXJyYXkpO1xuICAgKi91cGRhdGUobWVzc2FnZVVwZGF0ZSl7dGhpcy5faGFzaGVyLnVwZGF0ZShtZXNzYWdlVXBkYXRlKTsvLyBDaGFpbmFibGVcbnJldHVybiB0aGlzO30vKipcbiAgICogRmluYWxpemVzIHRoZSBITUFDIGNvbXB1dGF0aW9uLlxuICAgKiBOb3RlIHRoYXQgdGhlIGZpbmFsaXplIG9wZXJhdGlvbiBpcyBlZmZlY3RpdmVseSBhIGRlc3RydWN0aXZlLCByZWFkLW9uY2Ugb3BlcmF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0ge1dvcmRBcnJheXxzdHJpbmd9IG1lc3NhZ2VVcGRhdGUgKE9wdGlvbmFsKSBBIGZpbmFsIG1lc3NhZ2UgdXBkYXRlLlxuICAgKlxuICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBITUFDLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIGhtYWMgPSBobWFjSGFzaGVyLmZpbmFsaXplKCk7XG4gICAqICAgICB2YXIgaG1hYyA9IGhtYWNIYXNoZXIuZmluYWxpemUoJ21lc3NhZ2UnKTtcbiAgICogICAgIHZhciBobWFjID0gaG1hY0hhc2hlci5maW5hbGl6ZSh3b3JkQXJyYXkpO1xuICAgKi9maW5hbGl6ZShtZXNzYWdlVXBkYXRlKXsvLyBTaG9ydGN1dFxuY29uc3QgaGFzaGVyPXRoaXMuX2hhc2hlcjsvLyBDb21wdXRlIEhNQUNcbmNvbnN0IGlubmVySGFzaD1oYXNoZXIuZmluYWxpemUobWVzc2FnZVVwZGF0ZSk7aGFzaGVyLnJlc2V0KCk7Y29uc3QgaG1hYz1oYXNoZXIuZmluYWxpemUodGhpcy5fb0tleS5jbG9uZSgpLmNvbmNhdChpbm5lckhhc2gpKTtyZXR1cm4gaG1hYzt9fVxuXG5jb25zdCBwYXJzZUxvb3A9KGJhc2U2NFN0cixiYXNlNjRTdHJMZW5ndGgscmV2ZXJzZU1hcCk9Pntjb25zdCB3b3Jkcz1bXTtsZXQgbkJ5dGVzPTA7Zm9yKGxldCBpPTA7aTxiYXNlNjRTdHJMZW5ndGg7aSs9MSl7aWYoaSU0KXtjb25zdCBiaXRzMT1yZXZlcnNlTWFwW2Jhc2U2NFN0ci5jaGFyQ29kZUF0KGktMSldPDxpJTQqMjtjb25zdCBiaXRzMj1yZXZlcnNlTWFwW2Jhc2U2NFN0ci5jaGFyQ29kZUF0KGkpXT4+PjYtaSU0KjI7Y29uc3QgYml0c0NvbWJpbmVkPWJpdHMxfGJpdHMyO3dvcmRzW25CeXRlcz4+PjJdfD1iaXRzQ29tYmluZWQ8PDI0LW5CeXRlcyU0Kjg7bkJ5dGVzKz0xO319cmV0dXJuIFdvcmRBcnJheS5jcmVhdGUod29yZHMsbkJ5dGVzKTt9Oy8qKlxuICogQmFzZTY0IGVuY29kaW5nIHN0cmF0ZWd5LlxuICovY29uc3QgQmFzZTY0PXsvKipcbiAgICogQ29udmVydHMgYSB3b3JkIGFycmF5IHRvIGEgQmFzZTY0IHN0cmluZy5cbiAgICpcbiAgICogQHBhcmFtIHtXb3JkQXJyYXl9IHdvcmRBcnJheSBUaGUgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHJldHVybi
1B7c3RyaW5nfSBUaGUgQmFzZTY0IHN0cmluZy5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgY29uc3QgYmFzZTY0U3RyaW5nID0gQ3J5cHRvSlMuZW5jLkJhc2U2NC5zdHJpbmdpZnkod29yZEFycmF5KTtcbiAgICovc3RyaW5naWZ5KHdvcmRBcnJheSl7Ly8gU2hvcnRjdXRzXG5jb25zdHt3b3JkcyxzaWdCeXRlc309d29yZEFycmF5O2NvbnN0IG1hcD10aGlzLl9tYXA7Ly8gQ2xhbXAgZXhjZXNzIGJpdHNcbndvcmRBcnJheS5jbGFtcCgpOy8vIENvbnZlcnRcbmNvbnN0IGJhc2U2NENoYXJzPVtdO2ZvcihsZXQgaT0wO2k8c2lnQnl0ZXM7aSs9Myl7Y29uc3QgYnl0ZTE9d29yZHNbaT4+PjJdPj4+MjQtaSU0KjgmMHhmZjtjb25zdCBieXRlMj13b3Jkc1tpKzE+Pj4yXT4+PjI0LShpKzEpJTQqOCYweGZmO2NvbnN0IGJ5dGUzPXdvcmRzW2krMj4+PjJdPj4+MjQtKGkrMiklNCo4JjB4ZmY7Y29uc3QgdHJpcGxldD1ieXRlMTw8MTZ8Ynl0ZTI8PDh8Ynl0ZTM7Zm9yKGxldCBqPTA7ajw0JiZpK2oqMC43NTxzaWdCeXRlcztqKz0xKXtiYXNlNjRDaGFycy5wdXNoKG1hcC5jaGFyQXQodHJpcGxldD4+PjYqKDMtaikmMHgzZikpO319Ly8gQWRkIHBhZGRpbmdcbmNvbnN0IHBhZGRpbmdDaGFyPW1hcC5jaGFyQXQoNjQpO2lmKHBhZGRpbmdDaGFyKXt3aGlsZShiYXNlNjRDaGFycy5sZW5ndGglNCl7YmFzZTY0Q2hhcnMucHVzaChwYWRkaW5nQ2hhcik7fX1yZXR1cm4gYmFzZTY0Q2hhcnMuam9pbignJyk7fSwvKipcbiAgICogQ29udmVydHMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGJhc2U2NFN0ciBUaGUgQmFzZTY0IHN0cmluZy5cbiAgICpcbiAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgd29yZCBhcnJheS5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgY29uc3Qgd29yZEFycmF5ID0gQ3J5cHRvSlMuZW5jLkJhc2U2NC5wYXJzZShiYXNlNjRTdHJpbmcpO1xuICAgKi9wYXJzZShiYXNlNjRTdHIpey8vIFNob3J0Y3V0c1xubGV0IGJhc2U2NFN0ckxlbmd0aD1iYXNlNjRTdHIubGVuZ3RoO2NvbnN0IG1hcD10aGlzLl9tYXA7bGV0IHJldmVyc2VNYXA9dGhpcy5fcmV2ZXJzZU1hcDtpZighcmV2ZXJzZU1hcCl7dGhpcy5fcmV2ZXJzZU1hcD1bXTtyZXZlcnNlTWFwPXRoaXMuX3JldmVyc2VNYXA7Zm9yKGxldCBqPTA7ajxtYXAubGVuZ3RoO2orPTEpe3JldmVyc2VNYXBbbWFwLmNoYXJDb2RlQXQoaildPWo7fX0vLyBJZ25vcmUgcGFkZGluZ1xuY29uc3QgcGFkZGluZ0NoYXI9bWFwLmNoYXJBdCg2NCk7aWYocGFkZGluZ0NoYXIpe2NvbnN0IHBhZGRpbmdJbmRleD1iYXNlNjRTdHIuaW5kZXhPZihwYWRkaW5nQ2hhcik7aWYocGFkZGluZ0luZGV4IT09LTEpe2Jhc2U2NFN0ckxlbmd0aD1wYWRkaW5nSW5kZXg7fX0vLyBDb252ZXJ0XG5yZXR1cm4gcGFyc2VMb29wKGJhc2U2NFN0cixiYXNlNjRTdHJMZW5ndGgscmV2ZXJzZU1hcCk7fSxfbWFwOidBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvPSd9O1xuXG5jb25zdCBUPVtdOy8vIENvbXB1dGUgY29uc3RhbnRzXG5mb3IobGV0IGk9MDtpPDY0O2krPTEpe1RbaV09TWF0aC5hYnMoTWF0aC5zaW4oaSsxKSkqMHgxMDAwMDAwMDB8MDt9Y29uc3QgRkY9KGEsYixjLGQseCxzLHQpPT57Y29uc3Qgbj1hKyhiJmN8fmImZCkreCt0O3JldHVybiAobjw8c3xuPj4+MzItcykrYjt9O2NvbnN0IEdHPShhLGIsYyxkLHgscyx0KT0+e2NvbnN0IG49YSsoYiZkfGMmfmQpK3grdDtyZXR1cm4gKG48PHN8bj4+PjMyLXMpK2I7fTtjb25zdCBISD0oYSxiLGMsZCx4LHMsdCk9Pntjb25zdCBuPWErKGJeY15kKSt4K3Q7cmV0dXJuIChuPDxzfG4+Pj4zMi1zKStiO307Y29uc3QgSUk9KGEsYixjLGQseCxzLHQpPT57Y29uc3Qgbj1hKyhjXihifH5kKSkreCt0O3JldHVybiAobjw8c3xuPj4+MzItcykrYjt9Oy8qKlxuICogTUQ1IGhhc2ggYWxnb3JpdGhtLlxuICovY2xhc3MgTUQ1QWxnbyBleHRlbmRzIEhhc2hlcntfZG9SZXNldCgpe3RoaXMuX2hhc2g9bmV3IFdvcmRBcnJheShbMHg2NzQ1MjMwMSwweGVmY2RhYjg5LDB4OThiYWRjZmUsMHgxMDMyNTQ3Nl0pO31fZG9Qcm9jZXNzQmxvY2soTSxvZmZzZXQpe2NvbnN0IF9NPU07Ly8gU3dhcCBlbmRpYW5cbmZvcihsZXQgaT0wO2k8MTY7aSs9MSl7Ly8gU2hvcnRjdXRzXG5jb25zdCBvZmZzZXRfaT1vZmZzZXQraTtjb25zdCBNX29mZnNldF9pPU1bb2Zmc2V0X2ldO19NW29mZnNldF9pXT0oTV9vZmZzZXRfaTw8OHxNX29mZnNldF9pPj4+MjQpJjB4MDBmZjAwZmZ8KE1fb2Zmc2V0X2k8PDI0fE1fb2Zmc2V0X2k+Pj44KSYweGZmMDBmZjAwO30vLyBTaG9ydGN1dHNcbmNvbnN0IEg9dGhpcy5faGFzaC53b3Jkcztjb25zdCBNX29mZnNldF8wPV9NW29mZnNldCswXTtjb25zdCBNX29mZnNldF8xPV9NW29mZnNldCsxXTtjb25zdCBNX29mZnNldF8yPV9NW29mZnNldCsyXTtjb25zdCBNX29mZnNldF8zPV9NW29mZnNldCszXTtjb25zdCBNX29mZnNldF80PV9NW29mZnNldCs0XTtjb25zdCBNX29mZnNldF81PV9NW29mZnNldCs1XTtjb25zdCBNX29mZnNldF82PV9NW29mZnNldCs2XTtjb25zdCBNX29mZnNldF83PV9NW29mZnNldCs3XTtjb25zdCBNX29mZnNldF84PV9NW29mZnNldCs4XTtjb25zdCBNX29mZnNldF85PV9NW29mZnNldCs5XTtjb25zdCBNX29mZnNldF8xMD1fTVtvZmZzZXQrMTBdO2NvbnN0IE1fb2Zmc2V0XzExPV9NW29mZnNldCsxMV07Y29uc3QgTV9vZmZzZXRfMTI9X01bb2Zmc2V0KzEyXTtjb25zdCBNX29mZnNldF8xMz1fTVtvZmZzZXQrMTNdO2NvbnN0IE1fb2Zmc2V0XzE0PV9NW29mZnNldCsxNF07Y29uc3QgTV9vZmZzZXRfMTU9X01bb2Zmc2V0KzE1XTsvLyBXb3JraW5nIHZhcmlhbGJlc1xubGV0IGE9SFswXTtsZXQgYj1IWzFdO2xldCBjPUhbMl07bGV0IGQ9SFszXTsvLyBDb21wdXRhdGlvblxuYT1GRihhLGIsYyxkLE1fb2Zmc2V0XzAsNyxUWzBdKTtkPUZGKGQsYSxiLGMsTV9vZmZzZXRfMSwxMixUWzFdKTtjPUZGKGMsZCxhLGIsTV9vZmZzZXRfMiwxNyxUWzJdKTtiPUZGKGIsYyxkLGEsTV9vZmZzZXRfMywyMixUWzNdKTthPUZGKGEsYixjLGQsTV9vZmZzZXRfNCw3LFRbNF0pO2Q9RkYoZCxhLGIsYyxNX29mZnNldF81LDEyLFRbNV0pO2M9RkYoYyxkLGEsYixNX29mZnNldF82LDE3LFRbNl0pO2I9RkYoYixjLGQsYSxNX29mZnNldF83LDIyLFRbN10pO2E9RkYoYSxiLGMsZCxNX29mZnNldF84LDcsVFs4XSk7ZD1GRihkLGEsYixjLE1fb2Zmc2V0XzksMTIsVFs5XSk7Yz1GRihjLGQsYSxiLE1fb2Zmc2V0XzEwLDE3LFRbMTBdKTtiPUZGKGIsYyxkLGEsTV9vZmZzZXRfMTEsMjIsVFsxMV0pO2E9RkYoYSxiLGMsZCxNX29mZnNldF8xMiw3LFRbMTJdKTtkPUZGKGQsYSxiLGMsTV9vZmZzZXRfMTMsMTIsVFsxM10pO2M9RkYoYyxkLGEsYixNX29mZnNldF8xNCwxNyxUWzE0XSk7Yj1GRihiLGMsZCxhLE1fb2Zmc2V0XzE1LDIyLFRbMTVdKTthPUdHKGEsYixjLGQsTV9vZmZzZXRfMSw1LFRbMTZdKTtkPUdHKGQsYSxiLGMsTV9vZmZzZXRfNiw5LFRbMTddKTtjPUdHKGMsZCxhLGIsTV9vZmZzZXRfMTEsMTQsVFsxOF0pO2I9R0coYixjLGQsYSxNX29mZnNldF8wLDIwLFRbMTldKTthPUdHKGEsYixjLGQsTV9vZmZzZXRfNSw1LFRbMjBdKTtkPUdHKGQsYSxiLGMsTV9vZmZzZXRfMTAsOSxUWzIxXSk7Yz1HRyhjLGQsYSxiLE1fb2Zmc2V0XzE1LDE0LFRbMjJdKTtiPUdHKGIsYyxkLGEsTV9vZmZzZXRfNCwyMCxUWzIzXSk7YT1HRyhhLGIsYyxkLE1fb2Zmc2V0XzksNSxUWzI0XSk7ZD1H
1RyhkLGEsYixjLE1fb2Zmc2V0XzE0LDksVFsyNV0pO2M9R0coYyxkLGEsYixNX29mZnNldF8zLDE0LFRbMjZdKTtiPUdHKGIsYyxkLGEsTV9vZmZzZXRfOCwyMCxUWzI3XSk7YT1HRyhhLGIsYyxkLE1fb2Zmc2V0XzEzLDUsVFsyOF0pO2Q9R0coZCxhLGIsYyxNX29mZnNldF8yLDksVFsyOV0pO2M9R0coYyxkLGEsYixNX29mZnNldF83LDE0LFRbMzBdKTtiPUdHKGIsYyxkLGEsTV9vZmZzZXRfMTIsMjAsVFszMV0pO2E9SEgoYSxiLGMsZCxNX29mZnNldF81LDQsVFszMl0pO2Q9SEgoZCxhLGIsYyxNX29mZnNldF84LDExLFRbMzNdKTtjPUhIKGMsZCxhLGIsTV9vZmZzZXRfMTEsMTYsVFszNF0pO2I9SEgoYixjLGQsYSxNX29mZnNldF8xNCwyMyxUWzM1XSk7YT1ISChhLGIsYyxkLE1fb2Zmc2V0XzEsNCxUWzM2XSk7ZD1ISChkLGEsYixjLE1fb2Zmc2V0XzQsMTEsVFszN10pO2M9SEgoYyxkLGEsYixNX29mZnNldF83LDE2LFRbMzhdKTtiPUhIKGIsYyxkLGEsTV9vZmZzZXRfMTAsMjMsVFszOV0pO2E9SEgoYSxiLGMsZCxNX29mZnNldF8xMyw0LFRbNDBdKTtkPUhIKGQsYSxiLGMsTV9vZmZzZXRfMCwxMSxUWzQxXSk7Yz1ISChjLGQsYSxiLE1fb2Zmc2V0XzMsMTYsVFs0Ml0pO2I9SEgoYixjLGQsYSxNX29mZnNldF82LDIzLFRbNDNdKTthPUhIKGEsYixjLGQsTV9vZmZzZXRfOSw0LFRbNDRdKTtkPUhIKGQsYSxiLGMsTV9vZmZzZXRfMTIsMTEsVFs0NV0pO2M9SEgoYyxkLGEsYixNX29mZnNldF8xNSwxNixUWzQ2XSk7Yj1ISChiLGMsZCxhLE1fb2Zmc2V0XzIsMjMsVFs0N10pO2E9SUkoYSxiLGMsZCxNX29mZnNldF8wLDYsVFs0OF0pO2Q9SUkoZCxhLGIsYyxNX29mZnNldF83LDEwLFRbNDldKTtjPUlJKGMsZCxhLGIsTV9vZmZzZXRfMTQsMTUsVFs1MF0pO2I9SUkoYixjLGQsYSxNX29mZnNldF81LDIxLFRbNTFdKTthPUlJKGEsYixjLGQsTV9vZmZzZXRfMTIsNixUWzUyXSk7ZD1JSShkLGEsYixjLE1fb2Zmc2V0XzMsMTAsVFs1M10pO2M9SUkoYyxkLGEsYixNX29mZnNldF8xMCwxNSxUWzU0XSk7Yj1JSShiLGMsZCxhLE1fb2Zmc2V0XzEsMjEsVFs1NV0pO2E9SUkoYSxiLGMsZCxNX29mZnNldF84LDYsVFs1Nl0pO2Q9SUkoZCxhLGIsYyxNX29mZnNldF8xNSwxMCxUWzU3XSk7Yz1JSShjLGQsYSxiLE1fb2Zmc2V0XzYsMTUsVFs1OF0pO2I9SUkoYixjLGQsYSxNX29mZnNldF8xMywyMSxUWzU5XSk7YT1JSShhLGIsYyxkLE1fb2Zmc2V0XzQsNixUWzYwXSk7ZD1JSShkLGEsYixjLE1fb2Zmc2V0XzExLDEwLFRbNjFdKTtjPUlJKGMsZCxhLGIsTV9vZmZzZXRfMiwxNSxUWzYyXSk7Yj1JSShiLGMsZCxhLE1fb2Zmc2V0XzksMjEsVFs2M10pOy8vIEludGVybWVkaWF0ZSBoYXNoIHZhbHVlXG5IWzBdPUhbMF0rYXwwO0hbMV09SFsxXStifDA7SFsyXT1IWzJdK2N8MDtIWzNdPUhbM10rZHwwO30vKiBlc2xpbnQtZW5zYWJsZSBuby1wYXJhbS1yZWFzc2lnbiAqL19kb0ZpbmFsaXplKCl7Ly8gU2hvcnRjdXRzXG5jb25zdCBkYXRhPXRoaXMuX2RhdGE7Y29uc3QgZGF0YVdvcmRzPWRhdGEud29yZHM7Y29uc3QgbkJpdHNUb3RhbD10aGlzLl9uRGF0YUJ5dGVzKjg7Y29uc3QgbkJpdHNMZWZ0PWRhdGEuc2lnQnl0ZXMqODsvLyBBZGQgcGFkZGluZ1xuZGF0YVdvcmRzW25CaXRzTGVmdD4+PjVdfD0weDgwPDwyNC1uQml0c0xlZnQlMzI7Y29uc3QgbkJpdHNUb3RhbEg9TWF0aC5mbG9vcihuQml0c1RvdGFsLzB4MTAwMDAwMDAwKTtjb25zdCBuQml0c1RvdGFsTD1uQml0c1RvdGFsO2RhdGFXb3Jkc1sobkJpdHNMZWZ0KzY0Pj4+OTw8NCkrMTVdPShuQml0c1RvdGFsSDw8OHxuQml0c1RvdGFsSD4+PjI0KSYweDAwZmYwMGZmfChuQml0c1RvdGFsSDw8MjR8bkJpdHNUb3RhbEg+Pj44KSYweGZmMDBmZjAwO2RhdGFXb3Jkc1sobkJpdHNMZWZ0KzY0Pj4+OTw8NCkrMTRdPShuQml0c1RvdGFsTDw8OHxuQml0c1RvdGFsTD4+PjI0KSYweDAwZmYwMGZmfChuQml0c1RvdGFsTDw8MjR8bkJpdHNUb3RhbEw+Pj44KSYweGZmMDBmZjAwO2RhdGEuc2lnQnl0ZXM9KGRhdGFXb3Jkcy5sZW5ndGgrMSkqNDsvLyBIYXNoIGZpbmFsIGJsb2Nrc1xudGhpcy5fcHJvY2VzcygpOy8vIFNob3J0Y3V0c1xuY29uc3QgaGFzaD10aGlzLl9oYXNoO2NvbnN0IEg9aGFzaC53b3JkczsvLyBTd2FwIGVuZGlhblxuZm9yKGxldCBpPTA7aTw0O2krPTEpey8vIFNob3J0Y3V0XG5jb25zdCBIX2k9SFtpXTtIW2ldPShIX2k8PDh8SF9pPj4+MjQpJjB4MDBmZjAwZmZ8KEhfaTw8MjR8SF9pPj4+OCkmMHhmZjAwZmYwMDt9Ly8gUmV0dXJuIGZpbmFsIGNvbXB1dGVkIGhhc2hcbnJldHVybiBoYXNoO31jbG9uZSgpe2NvbnN0IGNsb25lPXN1cGVyLmNsb25lLmNhbGwodGhpcyk7Y2xvbmUuX2hhc2g9dGhpcy5faGFzaC5jbG9uZSgpO3JldHVybiBjbG9uZTt9fVxuXG4vKipcbiAqIFRoaXMga2V5IGRlcml2YXRpb24gZnVuY3Rpb24gaXMgbWVhbnQgdG8gY29uZm9ybSB3aXRoIEVWUF9CeXRlc1RvS2V5LlxuICogd3d3Lm9wZW5zc2wub3JnL2RvY3MvY3J5cHRvL0VWUF9CeXRlc1RvS2V5Lmh0bWxcbiAqL2NsYXNzIEV2cEtERkFsZ28gZXh0ZW5kcyBCYXNley8qKlxuICAgKiBJbml0aWFsaXplcyBhIG5ld2x5IGNyZWF0ZWQga2V5IGRlcml2YXRpb24gZnVuY3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgKE9wdGlvbmFsKSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHVzZSBmb3IgdGhlIGRlcml2YXRpb24uXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICBjb25zdCBrZGYgPSBDcnlwdG9KUy5hbGdvLkV2cEtERi5jcmVhdGUoKTtcbiAgICogICAgIGNvbnN0IGtkZiA9IENyeXB0b0pTLmFsZ28uRXZwS0RGLmNyZWF0ZSh7IGtleVNpemU6IDggfSk7XG4gICAqICAgICBjb25zdCBrZGYgPSBDcnlwdG9KUy5hbGdvLkV2cEtERi5jcmVhdGUoeyBrZXlTaXplOiA4LCBpdGVyYXRpb25zOiAxMDAwIH0pO1xuICAgKi9jb25zdHJ1Y3RvcihjZmcpe3N1cGVyKCk7LyoqXG4gICAgICogQ29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGtleVNpemUgVGhlIGtleSBzaXplIGluIHdvcmRzIHRvIGdlbmVyYXRlLiBEZWZhdWx0OiA0ICgxMjggYml0cylcbiAgICAgKiBAcHJvcGVydHkge0hhc2hlcn0gaGFzaGVyIFRoZSBoYXNoIGFsZ29yaXRobSB0byB1c2UuIERlZmF1bHQ6IE1ENVxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBpdGVyYXRpb25zIFRoZSBudW1iZXIgb2YgaXRlcmF0aW9ucyB0byBwZXJmb3JtLiBEZWZhdWx0OiAxXG4gICAgICovdGhpcy5jZmc9T2JqZWN0LmFzc2lnbihuZXcgQmFzZSgpLHtrZXlTaXplOjEyOC8zMixoYXNoZXI6TUQ1QWxnbyxpdGVyYXRpb25zOjF9LGNmZyk7fS8qKlxuICAgKiBEZXJpdmVzIGEga2V5IGZyb20gYSBwYXNzd29yZC5cbiAgICpcbiAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBwYXNzd29yZCBUaGUgcGFzc3dvcmQuXG4gICAqIEBwYXJhbSB7V29yZEFycmF
15fHN0cmluZ30gc2FsdCBBIHNhbHQuXG4gICAqXG4gICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIGRlcml2ZWQga2V5LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgY29uc3Qga2V5ID0ga2RmLmNvbXB1dGUocGFzc3dvcmQsIHNhbHQpO1xuICAgKi9jb21wdXRlKHBhc3N3b3JkLHNhbHQpe2xldCBibG9jazsvLyBTaG9ydGN1dFxuY29uc3R7Y2ZnfT10aGlzOy8vIEluaXQgaGFzaGVyXG5jb25zdCBoYXNoZXI9Y2ZnLmhhc2hlci5jcmVhdGUoKTsvLyBJbml0aWFsIHZhbHVlc1xuY29uc3QgZGVyaXZlZEtleT1Xb3JkQXJyYXkuY3JlYXRlKCk7Ly8gU2hvcnRjdXRzXG5jb25zdCBkZXJpdmVkS2V5V29yZHM9ZGVyaXZlZEtleS53b3Jkcztjb25zdHtrZXlTaXplLGl0ZXJhdGlvbnN9PWNmZzsvLyBHZW5lcmF0ZSBrZXlcbndoaWxlKGRlcml2ZWRLZXlXb3Jkcy5sZW5ndGg8a2V5U2l6ZSl7aWYoYmxvY2spe2hhc2hlci51cGRhdGUoYmxvY2spO31ibG9jaz1oYXNoZXIudXBkYXRlKHBhc3N3b3JkKS5maW5hbGl6ZShzYWx0KTtoYXNoZXIucmVzZXQoKTsvLyBJdGVyYXRpb25zXG5mb3IobGV0IGk9MTtpPGl0ZXJhdGlvbnM7aSs9MSl7YmxvY2s9aGFzaGVyLmZpbmFsaXplKGJsb2NrKTtoYXNoZXIucmVzZXQoKTt9ZGVyaXZlZEtleS5jb25jYXQoYmxvY2spO31kZXJpdmVkS2V5LnNpZ0J5dGVzPWtleVNpemUqNDtyZXR1cm4gZGVyaXZlZEtleTt9fVxuXG4vLyBJRTExIGNvbXBhdGliaWxpdHkgc2hpbSBmb3IgT2JqZWN0LmFzc2lnblxuLy9cbi8vIFdoeSB0aGlzIHBhdGNoIGV4aXN0czpcbi8vICAgY3J5cHRvLWVzIHNoaXBzIGFzIG5hdGl2ZSBFU00gYW5kIGNhbGxzIGBPYmplY3QuYXNzaWduYCBkaXJlY3RseSBpbnNpZGUgaXRzXG4vLyAgIG1vZHVsZSBib2R5LiBUaGUgU0RLJ3MgbGVnYWN5IGJ1bmRsZSBtdXN0IGtlZXAgd29ya2luZyBpbiBJRTExLCB3aGljaCBkb2VzXG4vLyAgIG5vdCBpbXBsZW1lbnQgYE9iamVjdC5hc3NpZ25gIG5hdGl2ZWx5LlxuLy9cbi8vICAgVGhlIFNESyAqZG9lcyogbG9hZCBwb2x5ZmlsbC5pbyBhdCBydW50aW1lIHZpYSBDYXBhYmlsaXRpZXNNYW5hZ2VyLCBidXRcbi8vICAgdGhhdCBsb2FkZXIgaXMgYXN5bmNocm9ub3VzIGFuZCBydW5zIEFGVEVSIGNyeXB0by1lcydzIG1vZHVsZS1sZXZlbCBjb2RlXG4vLyAgIChjbGFzcyBzdGF0aWNzLCBkZWZhdWx0IGNvbmZpZ3MpIGhhcyBhbHJlYWR5IGJlZW4gZXZhbHVhdGVkIOKAlCBzZWVcbi8vICAgYFNlcmlhbGl6YWJsZUNpcGhlci5jZmcgPSBPYmplY3QuYXNzaWduKC4uLilgIGFuZFxuLy8gICBgUGFzc3dvcmRCYXNlZENpcGhlci5jZmcgPSBPYmplY3QuYXNzaWduKC4uLilgIGJlbG93LiBXaXRob3V0IHRoaXMgc2hpbSxcbi8vICAgdGhvc2UgZXZhbHVhdGlvbnMgdGhyb3cgYE9iamVjdC5hc3NpZ24gaXMgbm90IGEgZnVuY3Rpb25gIGJlZm9yZSBhbnlcbi8vICAgcG9seWZpbGwgaGFzIGhhZCBhIGNoYW5jZSB0byBhdHRhY2guXG4vL1xuLy8gICBUaGlzIGlzIHRoZSBtaW5pbXVtLXZpYWJsZSBmaXg6IGEgbG9jYWwgYE9iamVjdEFzc2lnbmAgdGhhdCBmYWxscyBiYWNrIHRvXG4vLyAgIGEgc3BlYy1jb21wbGlhbnQgaW1wbGVtZW50YXRpb24gb25seSB3aGVuIHRoZSBydW50aW1lIGxhY2tzIHRoZSBuYXRpdmVcbi8vICAgb25lLiBFdmVyeSBgT2JqZWN0LmFzc2lnbiguLi4pYCBjYWxsIGluIHRoaXMgZmlsZSBpcyByZXdyaXR0ZW4gdG8gY2FsbCBpdC5cbi8vXG4vLyBTY29wZTpcbi8vICAgT25seSBgY2lwaGVyLWNvcmUuanNgIGlzIHBhdGNoZWQg4oCUIGl0IGNvbnRhaW5zIHRoZSBjYWxsIHNpdGVzIGFjdHVhbGx5XG4vLyAgIGV4ZXJjaXNlZCBieSB0aGUgU0RLIGluIGxlZ2FjeSBidWlsZHMuIElmIG5ldyBgT2JqZWN0LmFzc2lnbmAgdXNhZ2VzXG4vLyAgIHN1cmZhY2UgaW4gb3RoZXIgY3J5cHRvLWVzIGZpbGVzIChlLmcuIGNvcmUuanMpLCBleHRlbmQgdGhlIHNhbWUgcGF0dGVyblxuLy8gICB0aGVyZS5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5jb25zdCBPYmplY3RBc3NpZ249dHlwZW9mIE9iamVjdC5hc3NpZ24hPT1cImZ1bmN0aW9uXCI/ZnVuY3Rpb24odGFyZ2V0KXtpZih0YXJnZXQ9PW51bGwpdGhyb3cgbmV3IFR5cGVFcnJvcignQ2Fubm90IGNvbnZlcnQgdW5kZWZpbmVkIG9yIG51bGwgdG8gb2JqZWN0Jyk7dGFyZ2V0PU9iamVjdCh0YXJnZXQpO2ZvcihsZXQgaW5kZXg9MTtpbmRleDxhcmd1bWVudHMubGVuZ3RoO2luZGV4Kyspe2NvbnN0IHNvdXJjZT1hcmd1bWVudHNbaW5kZXhdO2lmKHNvdXJjZSE9bnVsbClmb3IoY29uc3Qga2V5IGluIHNvdXJjZSlpZihPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoc291cmNlLGtleSkpdGFyZ2V0W2tleV09c291cmNlW2tleV07fXJldHVybiB0YXJnZXQ7fTpPYmplY3QuYXNzaWduOy8qKlxuICogQWJzdHJhY3QgYmFzZSBjaXBoZXIgdGVtcGxhdGUuXG4gKlxuICogQHByb3BlcnR5IHtudW1iZXJ9IGtleVNpemUgVGhpcyBjaXBoZXIncyBrZXkgc2l6ZS4gRGVmYXVsdDogNCAoMTI4IGJpdHMpXG4gKiBAcHJvcGVydHkge251bWJlcn0gaXZTaXplIFRoaXMgY2lwaGVyJ3MgSVYgc2l6ZS4gRGVmYXVsdDogNCAoMTI4IGJpdHMpXG4gKiBAcHJvcGVydHkge251bWJlcn0gX0VOQ19YRk9STV9NT0RFIEEgY29uc3RhbnQgcmVwcmVzZW50aW5nIGVuY3J5cHRpb24gbW9kZS5cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBfREVDX1hGT1JNX01PREUgQSBjb25zdGFudCByZXByZXNlbnRpbmcgZGVjcnlwdGlvbiBtb2RlLlxuICovY2xhc3MgQ2lwaGVyIGV4dGVuZHMgQnVmZmVyZWRCbG9ja0FsZ29yaXRobXsvKipcbiAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIGNpcGhlci5cbiAgICpcbiAgICogQHBhcmFtIHtudW1iZXJ9IHhmb3JtTW9kZSBFaXRoZXIgdGhlIGVuY3J5cHRpb24gb3IgZGVjcnlwdGlvbiB0cmFuc29ybWF0aW9uIG1vZGUgY29uc3RhbnQuXG4gICAqIEBwYXJhbSB7V29yZEFycmF5fSBrZXkgVGhlIGtleS5cbiAgICogQHBhcmFtIHtPYmplY3R9IGNmZyAoT3B0aW9uYWwpIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdXNlIGZvciB0aGlzIG9wZXJhdGlvbi5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGNvbnN0IGNpcGhlciA9IENyeXB0b0pTLmFsZ28uQUVTLmNyZWF0ZShcbiAgICogICAgICAgQ3J5cHRvSlMuYWxnby5BRVMuX0VOQ19YRk9STV9NT0RFLCBrZXlXb3JkQXJyYXksIHsgaXY6IGl2V29yZEFycmF
15IH1cbiAgICogICAgICk7XG4gICAqL2NvbnN0cnVjdG9yKHhmb3JtTW9kZSxrZXksY2ZnKXtzdXBlcigpOy8qKlxuICAgICAqIENvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKlxuICAgICAqIEBwcm9wZXJ0eSB7V29yZEFycmF5fSBpdiBUaGUgSVYgdG8gdXNlIGZvciB0aGlzIG9wZXJhdGlvbi5cbiAgICAgKi90aGlzLmNmZz1PYmplY3RBc3NpZ24obmV3IEJhc2UoKSxjZmcpOy8vIFN0b3JlIHRyYW5zZm9ybSBtb2RlIGFuZCBrZXlcbnRoaXMuX3hmb3JtTW9kZT14Zm9ybU1vZGU7dGhpcy5fa2V5PWtleTsvLyBTZXQgaW5pdGlhbCB2YWx1ZXNcbnRoaXMucmVzZXQoKTt9LyoqXG4gICAqIENyZWF0ZXMgdGhpcyBjaXBoZXIgaW4gZW5jcnlwdGlvbiBtb2RlLlxuICAgKlxuICAgKiBAcGFyYW0ge1dvcmRBcnJheX0ga2V5IFRoZSBrZXkuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgKE9wdGlvbmFsKSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHVzZSBmb3IgdGhpcyBvcGVyYXRpb24uXG4gICAqXG4gICAqIEByZXR1cm4ge0NpcGhlcn0gQSBjaXBoZXIgaW5zdGFuY2UuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGNvbnN0IGNpcGhlciA9IENyeXB0b0pTLmFsZ28uQUVTLmNyZWF0ZUVuY3J5cHRvcihrZXlXb3JkQXJyYXksIHsgaXY6IGl2V29yZEFycmF5IH0pO1xuICAgKi9zdGF0aWMgY3JlYXRlRW5jcnlwdG9yKGtleSxjZmcpe3JldHVybiB0aGlzLmNyZWF0ZSh0aGlzLl9FTkNfWEZPUk1fTU9ERSxrZXksY2ZnKTt9LyoqXG4gICAqIENyZWF0ZXMgdGhpcyBjaXBoZXIgaW4gZGVjcnlwdGlvbiBtb2RlLlxuICAgKlxuICAgKiBAcGFyYW0ge1dvcmRBcnJheX0ga2V5IFRoZSBrZXkuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgKE9wdGlvbmFsKSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHVzZSBmb3IgdGhpcyBvcGVyYXRpb24uXG4gICAqXG4gICAqIEByZXR1cm4ge0NpcGhlcn0gQSBjaXBoZXIgaW5zdGFuY2UuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGNvbnN0IGNpcGhlciA9IENyeXB0b0pTLmFsZ28uQUVTLmNyZWF0ZURlY3J5cHRvcihrZXlXb3JkQXJyYXksIHsgaXY6IGl2V29yZEFycmF5IH0pO1xuICAgKi9zdGF0aWMgY3JlYXRlRGVjcnlwdG9yKGtleSxjZmcpe3JldHVybiB0aGlzLmNyZWF0ZSh0aGlzLl9ERUNfWEZPUk1fTU9ERSxrZXksY2ZnKTt9LyoqXG4gICAqIENyZWF0ZXMgc2hvcnRjdXQgZnVuY3Rpb25zIHRvIGEgY2lwaGVyJ3Mgb2JqZWN0IGludGVyZmFjZS5cbiAgICpcbiAgICogQHBhcmFtIHtDaXBoZXJ9IGNpcGhlciBUaGUgY2lwaGVyIHRvIGNyZWF0ZSBhIGhlbHBlciBmb3IuXG4gICAqXG4gICAqIEByZXR1cm4ge09iamVjdH0gQW4gb2JqZWN0IHdpdGggZW5jcnlwdCBhbmQgZGVjcnlwdCBzaG9ydGN1dCBmdW5jdGlvbnMuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGNvbnN0IEFFUyA9IENyeXB0b0pTLmxpYi5DaXBoZXIuX2NyZWF0ZUhlbHBlcihDcnlwdG9KUy5hbGdvLkFFUyk7XG4gICAqL3N0YXRpYyBfY3JlYXRlSGVscGVyKFN1YkNpcGhlcil7Y29uc3Qgc2VsZWN0Q2lwaGVyU3RyYXRlZ3k9a2V5PT57aWYodHlwZW9mIGtleT09PSdzdHJpbmcnKXtyZXR1cm4gUGFzc3dvcmRCYXNlZENpcGhlcjt9cmV0dXJuIFNlcmlhbGl6YWJsZUNpcGhlcjt9O3JldHVybiB7ZW5jcnlwdChtZXNzYWdlLGtleSxjZmcpe3JldHVybiBzZWxlY3RDaXBoZXJTdHJhdGVneShrZXkpLmVuY3J5cHQoU3ViQ2lwaGVyLG1lc3NhZ2Usa2V5LGNmZyk7fSxkZWNyeXB0KGNpcGhlcnRleHQsa2V5LGNmZyl7cmV0dXJuIHNlbGVjdENpcGhlclN0cmF0ZWd5KGtleSkuZGVjcnlwdChTdWJDaXBoZXIsY2lwaGVydGV4dCxrZXksY2ZnKTt9fTt9LyoqXG4gICAqIFJlc2V0cyB0aGlzIGNpcGhlciB0byBpdHMgaW5pdGlhbCBzdGF0ZS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGNpcGhlci5yZXNldCgpO1xuICAgKi9yZXNldCgpey8vIFJlc2V0IGRhdGEgYnVmZmVyXG5zdXBlci5yZXNldC5jYWxsKHRoaXMpOy8vIFBlcmZvcm0gY29uY3JldGUtY2lwaGVyIGxvZ2ljXG50aGlzLl9kb1Jlc2V0KCk7fS8qKlxuICAgKiBBZGRzIGRhdGEgdG8gYmUgZW5jcnlwdGVkIG9yIGRlY3J5cHRlZC5cbiAgICpcbiAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBkYXRhVXBkYXRlIFRoZSBkYXRhIHRvIGVuY3J5cHQgb3IgZGVjcnlwdC5cbiAgICpcbiAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgZGF0YSBhZnRlciBwcm9jZXNzaW5nLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgY29uc3QgZW5jcnlwdGVkID0gY2lwaGVyLnByb2Nlc3MoJ2RhdGEnKTtcbiAgICogICAgIGNvbnN0IGVuY3J5cHRlZCA9IGNpcGhlci5wcm9jZXNzKHdvcmRBcnJheSk7XG4gICAqL3Byb2Nlc3MoZGF0YVVwZGF0ZSl7Ly8gQXBwZW5kXG50aGlzLl9hcHBlbmQoZGF0YVVwZGF0ZSk7Ly8gUHJvY2VzcyBhdmFpbGFibGUgYmxvY2tzXG5yZXR1cm4gdGhpcy5fcHJvY2VzcygpO30vKipcbiAgICogRmluYWxpemVzIHRoZSBlbmNyeXB0aW9uIG9yIGRlY3J5cHRpb24gcHJvY2Vzcy5cbiAgICogTm90ZSB0aGF0IHRoZSBmaW5hbGl6ZSBvcGVyYXRpb24gaXMgZWZmZWN0aXZlbHkgYSBkZXN0cnVjdGl2ZSwgcmVhZC1vbmNlIG9wZXJhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBkYXRhVXBkYXRlIFRoZSBmaW5hbCBkYXRhIHRvIGVuY3J5cHQgb3IgZGVjcnlwdC5cbiAgICpcbiAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgZGF0YSBhZnRlciBmaW5hbCBwcm9jZXNzaW5nLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgY29uc3QgZW5jcnlwdGVkID0gY2lwaGVyLmZpbmFsaXplKCk7XG4gICAqICAgICBjb25zdCBlbmNyeXB0ZWQgPSBjaXBoZXIuZmluYWxpemUoJ2RhdGEnKTtcbiAgICogICAgIGNvbnN0IGVuY3J5cHRlZCA9IGNpcGhlci5maW5hbGl6ZSh3b3JkQXJyYXkpO1xuICAgKi9maW5hbGl6ZShkYXRhVXBkYXRlKXsvLyBGaW5hbCBkYXRhIHVwZGF0ZVxuaWYoZGF0YVVwZGF0ZSl7dGhpcy5fYXBwZW5kKGRhdGFVcGRhdGUpO30vLyBQZXJmb3JtIGNvbmNyZXRlLWNpcGhlciBsb2dpY1xuY29uc3QgZmluYWxQcm9jZXNzZWREYXRhPXRoaXMuX2RvRmluYWxpemUoKTtyZXR1cm4gZmluYWxQcm9jZXNzZWREYXRhO319Q2lwaGVyLl9FTkNfWEZPUk1fTU9ERT0xO0NpcGhlci5fREVDX1hGT1JNX01PREU9MjtDaXBoZXIua2V5U2l6ZT0xMjgvMzI7Q2lwaGVyLml2U2l6ZT0xMjgvMzI7LyoqXG4gKiBBYnN0cmFjdCBiYXNlIGJsb2NrIGNpcGhlciBtb2RlIHRlbXBsYXRlLlxuICovY2xhc3MgQmxvY2tDaXBoZXJNb2RlIGV4dGVuZHMgQmFzZXsvKipcbiAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIG1vZGUuXG4gICAqXG4gICAqIEBwYXJhbSB7Q2lwaGVyfSBjaXBoZXIgQSBibG9jayBjaXBoZXIgaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7QXJyYXl9IGl2IFRoZSBJViB3b3Jkcy5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGNvbnN0IG1vZGUgPSBDcnlwdG9KUy5tb2RlLkNCQy5FbmNyeXB0b3IuY3JlYXRlKGNpcGhlciwgaXYud29yZHMpO1xuICAgKi9jb25zdHJ1Y3RvcihjaXBoZXIsaXYpe3N1cGVyKCk7dGhpcy5fY2lwaGVyPWNpcGhlcjt0aGlzLl9pdj1pdjt9LyoqXG4gICAqIENyZWF0ZXMgdGhpcyBtb2RlIGZvciBlbmNyeXB0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0ge0NpcGhlcn0gY2lwaGVyIEEgYmxvY2sgY2lwaGVyIGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge0FycmF5fSBpdiBUaGUgSVYgd29yZHMuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIGNvbnN0IG1vZGUgPSBDcnlwdG9KUy5tb2RlLkNCQy5jcmVhdGVFbmNyeXB0b3IoY2lwaGVyLCBpdi53b3Jkcyk7XG4gICAqL3N0YXRpYyBjcmVhdGVFbmNyeXB0b3IoY2lwaGVyLGl2
1KXtyZXR1cm4gdGhpcy5FbmNyeXB0b3IuY3JlYXRlKGNpcGhlcixpdik7fS8qKlxuICAgKiBDcmVhdGVzIHRoaXMgbW9kZSBmb3IgZGVjcnlwdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtDaXBoZXJ9IGNpcGhlciBBIGJsb2NrIGNpcGhlciBpbnN0YW5jZS5cbiAgICogQHBhcmFtIHtBcnJheX0gaXYgVGhlIElWIHdvcmRzLlxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICBjb25zdCBtb2RlID0gQ3J5cHRvSlMubW9kZS5DQkMuY3JlYXRlRGVjcnlwdG9yKGNpcGhlciwgaXYud29yZHMpO1xuICAgKi9zdGF0aWMgY3JlYXRlRGVjcnlwdG9yKGNpcGhlcixpdil7cmV0dXJuIHRoaXMuRGVjcnlwdG9yLmNyZWF0ZShjaXBoZXIsaXYpO319ZnVuY3Rpb24geG9yQmxvY2sod29yZHMsb2Zmc2V0LGJsb2NrU2l6ZSl7Y29uc3QgX3dvcmRzPXdvcmRzO2xldCBibG9jazsvLyBTaG9ydGN1dFxuY29uc3QgaXY9dGhpcy5faXY7Ly8gQ2hvb3NlIG1peGluZyBibG9ja1xuaWYoaXYpe2Jsb2NrPWl2Oy8vIFJlbW92ZSBJViBmb3Igc3Vic2VxdWVudCBibG9ja3NcbnRoaXMuX2l2PXVuZGVmaW5lZDt9ZWxzZSB7YmxvY2s9dGhpcy5fcHJldkJsb2NrO30vLyBYT1IgYmxvY2tzXG5mb3IobGV0IGk9MDtpPGJsb2NrU2l6ZTtpKz0xKXtfd29yZHNbb2Zmc2V0K2ldXj1ibG9ja1tpXTt9fS8qKlxuICogQ2lwaGVyIEJsb2NrIENoYWluaW5nIG1vZGUuXG4gKi8vKipcbiAqIEFic3RyYWN0IGJhc2UgQ0JDIG1vZGUuXG4gKi9jbGFzcyBDQkMgZXh0ZW5kcyBCbG9ja0NpcGhlck1vZGV7fS8qKlxuICogQ0JDIGVuY3J5cHRvci5cbiAqL0NCQy5FbmNyeXB0b3I9Y2xhc3MgZXh0ZW5kcyBDQkN7LyoqXG4gICAqIFByb2Nlc3NlcyB0aGUgZGF0YSBibG9jayBhdCBvZmZzZXQuXG4gICAqXG4gICAqIEBwYXJhbSB7QXJyYXl9IHdvcmRzIFRoZSBkYXRhIHdvcmRzIHRvIG9wZXJhdGUgb24uXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBvZmZzZXQgVGhlIG9mZnNldCB3aGVyZSB0aGUgYmxvY2sgc3RhcnRzLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgbW9kZS5wcm9jZXNzQmxvY2soZGF0YS53b3Jkcywgb2Zmc2V0KTtcbiAgICovcHJvY2Vzc0Jsb2NrKHdvcmRzLG9mZnNldCl7Ly8gU2hvcnRjdXRzXG5jb25zdCBjaXBoZXI9dGhpcy5fY2lwaGVyO2NvbnN0e2Jsb2NrU2l6ZX09Y2lwaGVyOy8vIFhPUiBhbmQgZW5jcnlwdFxueG9yQmxvY2suY2FsbCh0aGlzLHdvcmRzLG9mZnNldCxibG9ja1NpemUpO2NpcGhlci5lbmNyeXB0QmxvY2sod29yZHMsb2Zmc2V0KTsvLyBSZW1lbWJlciB0aGlzIGJsb2NrIHRvIHVzZSB3aXRoIG5leHQgYmxvY2tcbnRoaXMuX3ByZXZCbG9jaz13b3Jkcy5zbGljZShvZmZzZXQsb2Zmc2V0K2Jsb2NrU2l6ZSk7fX07LyoqXG4gKiBDQkMgZGVjcnlwdG9yLlxuICovQ0JDLkRlY3J5cHRvcj1jbGFzcyBleHRlbmRzIENCQ3svKipcbiAgICogUHJvY2Vzc2VzIHRoZSBkYXRhIGJsb2NrIGF0IG9mZnNldC5cbiAgICpcbiAgICogQHBhcmFtIHtBcnJheX0gd29yZHMgVGhlIGRhdGEgd29yZHMgdG8gb3BlcmF0ZSBvbi5cbiAgICogQHBhcmFtIHtudW1iZXJ9IG9mZnNldCBUaGUgb2Zmc2V0IHdoZXJlIHRoZSBibG9jayBzdGFydHMuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICBtb2RlLnByb2Nlc3NCbG9jayhkYXRhLndvcmRzLCBvZmZzZXQpO1xuICAgKi9wcm9jZXNzQmxvY2sod29yZHMsb2Zmc2V0KXsvLyBTaG9ydGN1dHNcbmNvbnN0IGNpcGhlcj10aGlzLl9jaXBoZXI7Y29uc3R7YmxvY2tTaXplfT1jaXBoZXI7Ly8gUmVtZW1iZXIgdGhpcyBibG9jayB0byB1c2Ugd2l0aCBuZXh0IGJsb2NrXG5jb25zdCB0aGlzQmxvY2s9d29yZHMuc2xpY2Uob2Zmc2V0LG9mZnNldCtibG9ja1NpemUpOy8vIERlY3J5cHQgYW5kIFhPUlxuY2lwaGVyLmRlY3J5cHRCbG9jayh3b3JkcyxvZmZzZXQpO3hvckJsb2NrLmNhbGwodGhpcyx3b3JkcyxvZmZzZXQsYmxvY2tTaXplKTsvLyBUaGlzIGJsb2NrIGJlY29tZXMgdGhlIHByZXZpb3VzIGJsb2NrXG50aGlzLl9wcmV2QmxvY2s9dGhpc0Jsb2NrO319Oy8qKlxuICogUEtDUyAjNS83IHBhZGRpbmcgc3RyYXRlZ3kuXG4gKi9jb25zdCBQa2NzNz17LyoqXG4gICAqIFBhZHMgZGF0YSB1c2luZyB0aGUgYWxnb3JpdGhtIGRlZmluZWQgaW4gUEtDUyAjNS83LlxuICAgKlxuICAgKiBAcGFyYW0ge1dvcmRBcnJheX0gZGF0YSBUaGUgZGF0YSB0byBwYWQuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBibG9ja1NpemUgVGhlIG11bHRpcGxlIHRoYXQgdGhlIGRhdGEgc2hvdWxkIGJlIHBhZGRlZCB0by5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgQ3J5cHRvSlMucGFkLlBrY3M3LnBhZCh3b3JkQXJyYXksIDQpO1xuICAgKi9wYWQoZGF0YSxibG9ja1NpemUpey8vIFNob3J0Y3V0XG5jb25zdCBibG9ja1NpemVCeXRlcz1ibG9ja1NpemUqNDsvLyBDb3VudCBwYWRkaW5nIGJ5dGVzXG5jb25zdCBuUGFkZGluZ0J5dGVzPWJsb2NrU2l6ZUJ5dGVzLWRhdGEuc2lnQnl0ZXMlYmxvY2tTaXplQnl0ZXM7Ly8gQ3JlYXRlIHBhZGRpbmcgd29yZFxuY29uc3QgcGFkZGluZ1dvcmQ9blBhZGRpbmdCeXRlczw8MjR8blBhZGRpbmdCeXRlczw8MTZ8blBhZGRpbmdCeXRlczw8OHxuUGFkZGluZ0J5dGVzOy8vIENyZWF0ZSBwYWRkaW5nXG5jb25zdCBwYWRkaW5nV29yZHM9W107Zm9yKGxldCBpPTA7aTxuUGFkZGluZ0J5dGVzO2krPTQpe3BhZGRpbmdXb3Jkcy5wdXNoKHBhZGRpbmdXb3JkKTt9Y29uc3QgcGFkZGluZz1Xb3JkQXJyYXkuY3JlYXRlKHBhZGRpbmdXb3JkcyxuUGFkZGluZ0J5dGVzKTsvLyBBZGQgcGFkZGluZ1xuZGF0YS5jb25jYXQocGFkZGluZyk7fSwvKipcbiAgICogVW5wYWRzIGRhdGEgdGhhdCBoYWQgYmVlbiBwYWRkZWQgdXNpbmcgdGhlIGFsZ29yaXRobSBkZWZpbmVkIGluIFBLQ1MgIzUvNy5cbiAgICpcbiAgICogQHBhcmFtIHtXb3JkQXJyYXl9IGRhdGEgVGhlIGRhdGEgdG8gdW5wYWQuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIENyeXB0b0pTLnBhZC5Qa2NzNy51bnBhZCh3b3JkQXJyYXkpO1xuICAgKi91bnBhZChkYXRhKXtjb25zdCBfZGF0YT1kYXRhOy8vIEdldCBudW1iZXIgb2YgcGFkZGluZyBieXRlcyBmcm9tIGxhc3QgYnl0ZVxuY29uc3QgblBhZGRpbmdCeXRlcz1fZGF0YS53b3Jkc1tfZGF0YS5zaWdCeXRlcy0xPj4+Ml0mMHhmZjsvLyBSZW1vdmUgcGFkZGluZ1xuX2RhdGEuc2lnQnl0ZXMtPW5QYWRkaW5nQnl0ZXM7fX07LyoqXG4gKiBBYnN0cmFjdCBiYXNlIGJsb2NrIGNpcGhlciB0ZW1wbGF0ZS5cbiAqXG4gKiBAcHJvcGVydHkge251bWJlcn0gYmxvY2tTaXplXG4gKlxuICogICAgVGhlIG51bWJlciBvZiAzMi1iaXQgd29yZHMgdGhpcyBjaXBoZXIgb3BlcmF0ZXMgb24uIERlZmF1bHQ6IDQgKDEyOCBiaXRzKVxuICovY2xhc3MgQmxvY2tDaXBoZXIgZXh0ZW5kcyBDaXBoZXJ7Y29uc3RydWN0b3IoeGZvcm1Nb2RlLGtleSxjZmcpey8qKlxuICAgICAqIENvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKlxuICAgICAqIEBwcm9wZXJ0eSB7TW9kZX0gbW9kZSBUaGUgYmxvY2sgbW9kZSB0byB1c2UuIERlZmF1bHQ6IENCQ1xuICAgICAqIEBwcm9wZXJ0eSB7UGFkZGluZ30gcGFkZGluZyBUaGUgcGFkZGluZyBzdHJhdGVneSB0byB1c2UuIERlZmF1bHQ6IFBrY3M3XG4gICAgICovc3VwZXIoeGZvcm1Nb2RlLGtleSxPYmplY3RBc3NpZ24oe21vZGU6Q0JDLHBhZGRpbmc6UGtjczd9LGNmZykpO3RoaXMuYmxvY2tTaXplPTEyOC8zMjt9cmVzZXQoKXtsZXQgbW9kZUNyZWF0b3I7Ly8gUmVzZXQgY2lwaGVyXG5zdXBlci5yZXNldC5jYWxsKHRoaXMpOy8vIFNob3J0Y3V0c1xuY29uc3R7Y2ZnfT10aGlzO2NvbnN0e2l2LG1vZGV9PWNmZzsvLyBSZXNldCBibG9jayBtb2RlXG5pZih0aGlzLl94Zm9ybU1vZGU9PT10aGlzLmNvbnN0cnVjdG9yLl9FTkNfWEZPUk1fTU9ERSl7bW9kZUNyZWF0b3I9bW9kZS5jcmVhdGVFbmNyeXB0b3I7fWVsc2UvKiBpZiAodGhpcy5feGZvcm1Nb2RlID09IHRoaXMuX0RFQ19YRk9STV9NT0RFKSAqL3ttb2RlQ3JlYXRvcj1tb2RlLmNyZWF0ZURlY3J5cHRvcjsvLyBLZWVwIGF0IGxlYXN0IG9uZSBibG9jayBpbiB0aGUgYnVmZmVyIGZvciB1bnBhZGRpbmdcbnRoaXMuX21pbkJ1ZmZlclNpemU9MTt9dGhpcy5fbW9kZT1tb2RlQ3JlYXRvci5jYWxsKG1vZGUsdGhpcyxpdiYmaXYud29yZHMpO3RoaXMuX21vZGUuX19jcmVhdG9yPW1vZGVDcmVhdG9yO31fZG9Qcm9jZXNzQmxvY2sod29yZHMsb2Zmc2V0KXt0aGlzLl9tb2Rl
1LnByb2Nlc3NCbG9jayh3b3JkcyxvZmZzZXQpO31fZG9GaW5hbGl6ZSgpe2xldCBmaW5hbFByb2Nlc3NlZEJsb2NrczsvLyBTaG9ydGN1dFxuY29uc3R7cGFkZGluZ309dGhpcy5jZmc7Ly8gRmluYWxpemVcbmlmKHRoaXMuX3hmb3JtTW9kZT09PXRoaXMuY29uc3RydWN0b3IuX0VOQ19YRk9STV9NT0RFKXsvLyBQYWQgZGF0YVxucGFkZGluZy5wYWQodGhpcy5fZGF0YSx0aGlzLmJsb2NrU2l6ZSk7Ly8gUHJvY2VzcyBmaW5hbCBibG9ja3NcbmZpbmFsUHJvY2Vzc2VkQmxvY2tzPXRoaXMuX3Byb2Nlc3ModHJ1ZSk7fWVsc2UvKiBpZiAodGhpcy5feGZvcm1Nb2RlID09IHRoaXMuX0RFQ19YRk9STV9NT0RFKSAqL3svLyBQcm9jZXNzIGZpbmFsIGJsb2Nrc1xuZmluYWxQcm9jZXNzZWRCbG9ja3M9dGhpcy5fcHJvY2Vzcyh0cnVlKTsvLyBVbnBhZCBkYXRhXG5wYWRkaW5nLnVucGFkKGZpbmFsUHJvY2Vzc2VkQmxvY2tzKTt9cmV0dXJuIGZpbmFsUHJvY2Vzc2VkQmxvY2tzO319LyoqXG4gKiBBIGNvbGxlY3Rpb24gb2YgY2lwaGVyIHBhcmFtZXRlcnMuXG4gKlxuICogQHByb3BlcnR5IHtXb3JkQXJyYXl9IGNpcGhlcnRleHQgVGhlIHJhdyBjaXBoZXJ0ZXh0LlxuICogQHByb3BlcnR5IHtXb3JkQXJyYXl9IGtleSBUaGUga2V5IHRvIHRoaXMgY2lwaGVydGV4dC5cbiAqIEBwcm9wZXJ0eSB7V29yZEFycmF5fSBpdiBUaGUgSVYgdXNlZCBpbiB0aGUgY2lwaGVyaW5nIG9wZXJhdGlvbi5cbiAqIEBwcm9wZXJ0eSB7V29yZEFycmF5fSBzYWx0IFRoZSBzYWx0IHVzZWQgd2l0aCBhIGtleSBkZXJpdmF0aW9uIGZ1bmN0aW9uLlxuICogQHByb3BlcnR5IHtDaXBoZXJ9IGFsZ29yaXRobSBUaGUgY2lwaGVyIGFsZ29yaXRobS5cbiAqIEBwcm9wZXJ0eSB7TW9kZX0gbW9kZSBUaGUgYmxvY2sgbW9kZSB1c2VkIGluIHRoZSBjaXBoZXJpbmcgb3BlcmF0aW9uLlxuICogQHByb3BlcnR5IHtQYWRkaW5nfSBwYWRkaW5nIFRoZSBwYWRkaW5nIHNjaGVtZSB1c2VkIGluIHRoZSBjaXBoZXJpbmcgb3BlcmF0aW9uLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IGJsb2NrU2l6ZSBUaGUgYmxvY2sgc2l6ZSBvZiB0aGUgY2lwaGVyLlxuICogQHByb3BlcnR5IHtGb3JtYXR9IGZvcm1hdHRlclxuICogICAgVGhlIGRlZmF1bHQgZm9ybWF0dGluZyBzdHJhdGVneSB0byBjb252ZXJ0IHRoaXMgY2lwaGVyIHBhcmFtcyBvYmplY3QgdG8gYSBzdHJpbmcuXG4gKi9jbGFzcyBDaXBoZXJQYXJhbXMgZXh0ZW5kcyBCYXNley8qKlxuICAgKiBJbml0aWFsaXplcyBhIG5ld2x5IGNyZWF0ZWQgY2lwaGVyIHBhcmFtcyBvYmplY3QuXG4gICAqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBjaXBoZXJQYXJhbXMgQW4gb2JqZWN0IHdpdGggYW55IG9mIHRoZSBwb3NzaWJsZSBjaXBoZXIgcGFyYW1ldGVycy5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBjaXBoZXJQYXJhbXMgPSBDcnlwdG9KUy5saWIuQ2lwaGVyUGFyYW1zLmNyZWF0ZSh7XG4gICAqICAgICAgICAgY2lwaGVydGV4dDogY2lwaGVydGV4dFdvcmRBcnJheSxcbiAgICogICAgICAgICBrZXk6IGtleVdvcmRBcnJheSxcbiAgICogICAgICAgICBpdjogaXZXb3JkQXJyYXksXG4gICAqICAgICAgICAgc2FsdDogc2FsdFdvcmRBcnJheSxcbiAgICogICAgICAgICBhbGdvcml0aG06IENyeXB0b0pTLmFsZ28uQUVTLFxuICAgKiAgICAgICAgIG1vZGU6IENyeXB0b0pTLm1vZGUuQ0JDLFxuICAgKiAgICAgICAgIHBhZGRpbmc6IENyeX
1B0b0pTLnBhZC5QS0NTNyxcbiAgICogICAgICAgICBibG9ja1NpemU6IDQsXG4gICAqICAgICAgICAgZm9ybWF0dGVyOiBDcnlwdG9KUy5mb3JtYXQuT3BlblNTTFxuICAgKiAgICAgfSk7XG4gICAqL2NvbnN0cnVjdG9yKGNpcGhlclBhcmFtcyl7c3VwZXIoKTt0aGlzLm1peEluKGNpcGhlclBhcmFtcyk7fS8qKlxuICAgKiBDb252ZXJ0cyB0aGlzIGNpcGhlciBwYXJhbXMgb2JqZWN0IHRvIGEgc3RyaW5nLlxuICAgKlxuICAgKiBAcGFyYW0ge0Zvcm1hdH0gZm9ybWF0dGVyIChPcHRpb25hbCkgVGhlIGZvcm1hdHRpbmcgc3RyYXRlZ3kgdG8gdXNlLlxuICAgKlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBzdHJpbmdpZmllZCBjaXBoZXIgcGFyYW1zLlxuICAgKlxuICAgKiBAdGhyb3dzIEVycm9yIElmIG5laXRoZXIgdGhlIGZvcm1hdHRlciBub3IgdGhlIGRlZmF1bHQgZm9ybWF0dGVyIGlzIHNldC5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBzdHJpbmcgPSBjaXBoZXJQYXJhbXMgKyAnJztcbiAgICogICAgIHZhciBzdHJpbmcgPSBjaXBoZXJQYXJhbXMudG9TdHJpbmcoKTtcbiAgICogICAgIHZhciBzdHJpbmcgPSBjaXBoZXJQYXJhbXMudG9TdHJpbmcoQ3J5cHRvSlMuZm9ybWF0Lk9wZW5TU0wpO1xuICAgKi90b1N0cmluZyhmb3JtYXR0ZXIpe3JldHVybiAoZm9ybWF0dGVyfHx0aGlzLmZvcm1hdHRlcikuc3RyaW5naWZ5KHRoaXMpO319LyoqXG4gKiBPcGVuU1NMIGZvcm1hdHRpbmcgc3RyYXRlZ3kuXG4gKi9jb25zdCBPcGVuU1NMRm9ybWF0dGVyPXsvKipcbiAgICogQ29udmVydHMgYSBjaXBoZXIgcGFyYW1zIG9iamVjdCB0byBhbiBPcGVuU1NMLWNvbXBhdGlibGUgc3RyaW5nLlxuICAgKlxuICAgKiBAcGFyYW0ge0NpcGhlclBhcmFtc30gY2lwaGVyUGFyYW1zIFRoZSBjaXBoZXIgcGFyYW1zIG9iamVjdC5cbiAgICpcbiAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgT3BlblNTTC1jb21wYXRpYmxlIHN0cmluZy5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAgdmFyIG9wZW5TU0xTdHJpbmcgPSBDcnlwdG9KUy5mb3JtYXQuT3BlblNTTC5zdHJpbmdpZnkoY2lwaGVyUGFyYW1zKTtcbiAgICovc3RyaW5naWZ5KGNpcGhlclBhcmFtcyl7bGV0IHdvcmRBcnJheTsvLyBTaG9ydGN1dHNcbmNvbnN0e2NpcGhlcnRleHQsc2FsdH09Y2lwaGVyUGFyYW1zOy8vIEZvcm1hdFxuaWYoc2FsdCl7d29yZEFycmF5PVdvcmRBcnJheS5jcmVhdGUoWzB4NTM2MTZjNzQsMHg2NTY0NWY1Zl0pLmNvbmNhdChzYWx0KS5jb25jYXQoY2lwaGVydGV4dCk7fWVsc2Uge3dvcmRBcnJheT1jaXBoZXJ0ZXh0O31yZXR1cm4gd29yZEFycmF5LnRvU3RyaW5nKEJhc2U2NCk7fSwvKipcbiAgICogQ29udmVydHMgYW4gT3BlblNTTC1jb21wYXRpYmxlIHN0cmluZyB0byBhIGNpcGhlciBwYXJhbXMgb2JqZWN0LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gb3BlblNTTFN0ciBUaGUgT3BlblNTTC1jb21wYXRpYmxlIHN0cmluZy5cbiAgICpcbiAgICogQHJldHVybiB7Q2lwaGVyUGFyYW1zfSBUaGUgY2lwaGVyIHBhcmFtcyBvYmplY3QuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBjaXBoZXJQYXJhbXMgPSBDcnlwdG9KUy5mb3JtYXQuT3BlblNTTC5wYXJzZShvcGVuU1NMU3RyaW5nKTtcbiAgICovcGFyc2Uob3BlblNTTFN0cil7bGV0IHNhbHQ7Ly8gUGFyc2UgYmFzZTY0XG5jb25zdCBjaXBoZXJ0ZXh0PUJhc2U2NC5wYXJzZShvcGVuU1NMU3RyKTsvLyBTaG9ydGN1dFxuY29uc3QgY2lwaGVydGV4dFdvcmRzPWNpcGhlcnRleHQud29yZHM7Ly8gVGVzdCBmb3Igc2FsdFxuaWYoY2lwaGVydGV4dFdvcmRzWzBdPT09MHg1MzYxNmM3NCYmY2lwaGVydGV4dFdvcmRzWzFdPT09MHg2NTY0NWY1Zil7Ly8gRXh0cmFjdCBzYWx0XG5zYWx0PVdvcmRBcnJheS5jcmVhdGUoY2lwaGVydGV4dFdvcmRzLnNsaWNlKDIsNCkpOy8vIFJlbW92ZSBzYWx0IGZyb20gY2lwaGVydGV4dFxuY2lwaGVydGV4dFdvcmRzLnNwbGljZSgwLDQpO2NpcGhlcnRleHQuc2lnQnl0ZXMtPTE2O31yZXR1cm4gQ2lwaGVyUGFyYW1zLmNyZWF0ZSh7Y2lwaGVydGV4dCxzYWx0fSk7fX07LyoqXG4gKiBBIGNpcGhlciB3cmFwcGVyIHRoYXQgcmV0dXJucyBjaXBoZXJ0ZXh0IGFzIGEgc2VyaWFsaXphYmxlIGNpcGhlciBwYXJhbXMgb2JqZWN0LlxuICovY2xhc3MgU2VyaWFsaXphYmxlQ2lwaGVyIGV4dGVuZHMgQmFzZXsvKipcbiAgICogRW5jcnlwdHMgYSBtZXNzYWdlLlxuICAgKlxuICAgKiBAcGFyYW0ge0NpcGhlcn0gY2lwaGVyIFRoZSBjaXBoZXIgYWxnb3JpdGhtIHRvIHVzZS5cbiAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBtZXNzYWdlIFRoZSBtZXNzYWdlIHRvIGVuY3J5cHQuXG4gICAqIEBwYXJhbSB7V29yZEFycmF5fSBrZXkgVGhlIGtleS5cbiAgICogQHBhcmFtIHtPYmplY3R9IGNmZyAoT3B0aW9uYWwpIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdXNlIGZvciB0aGlzIG9wZXJhdGlvbi5cbiAgICpcbiAgICogQHJldHVybiB7Q2lwaGVyUGFyYW1zfSBBIGNpcGhlciBwYXJhbXMgb2JqZWN0LlxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICB2YXIgY2lwaGVydGV4dFBhcmFtcyA9IENyeXB0b0pTLmxpYi5TZXJpYWxpemFibGVDaXBoZXJcbiAgICogICAgICAgLmVuY3J5cHQoQ3J5cHRvSlMuYWxnby5BRVMsIG1lc3NhZ2UsIGtleSk7XG4gICAqICAgICB2YXIgY2lwaGVydGV4dFBhcmFtcyA9IENyeXB0b0pTLmxpYi5TZXJpYWxpemFibGVDaXBoZXJcbiAgICogICAgICAgLmVuY3J5cHQoQ3J5cHRvSlMuYWxnby5BRVMsIG1lc3NhZ2UsIGtleSwgeyBpdjogaXYgfSk7XG4gICAqICAgICB2YXIgY2lwaGVydGV4dFBhcmFtcyA9IENyeXB0b0pTLmxpYi5TZXJpYWxpemFibGVDaXBoZXJcbiAgICogICAgICAgLmVuY3J5cHQoQ3J5cHRvSlMuYWxnby5BRVMsIG1lc3NhZ2UsIGtleSwgeyBpdjogaXYsIGZvcm1hdDogQ3J5cHRvSlMuZm9ybWF0Lk9wZW5TU0wgfSk7XG4gICAqL3N0YXRpYyBlbmNyeXB0KGNpcGhlcixtZXNzYWdlLGtleSxjZmcpey8vIEFwcGx5IGNvbmZpZyBkZWZhdWx0c1xuY29uc3QgX2NmZz1PYmplY3RBc3NpZ24obmV3IEJhc2UoKSx0aGlzLmNmZyxjZmcpOy8vIEVuY3J5cHRcbmNvbnN0IGVuY3J5cHRvcj1jaXBoZXIuY3JlYXRlRW5jcnlwdG9yKGtleSxfY2ZnKTtjb25zdCBjaXBoZXJ0ZXh0PWVuY3J5cHRvci
15maW5hbGl6ZShtZXNzYWdlKTsvLyBTaG9ydGN1dFxuY29uc3QgY2lwaGVyQ2ZnPWVuY3J5cHRvci5jZmc7Ly8gQ3JlYXRlIGFuZCByZXR1cm4gc2VyaWFsaXphYmxlIGNpcGhlciBwYXJhbXNcbnJldHVybiBDaXBoZXJQYXJhbXMuY3JlYXRlKHtjaXBoZXJ0ZXh0LGtleSxpdjpjaXBoZXJDZmcuaXYsYWxnb3JpdGhtOmNpcGhlcixtb2RlOmNpcGhlckNmZy5tb2RlLHBhZGRpbmc6Y2lwaGVyQ2ZnLnBhZGRpbmcsYmxvY2tTaXplOmVuY3J5cHRvci5ibG9ja1NpemUsZm9ybWF0dGVyOl9jZmcuZm9ybWF0fSk7fS8qKlxuICAgKiBEZWNyeXB0cyBzZXJpYWxpemVkIGNpcGhlcnRleHQuXG4gICAqXG4gICAqIEBwYXJhbSB7Q2lwaGVyfSBjaXBoZXIgVGhlIGNpcGhlciBhbGdvcml0aG0gdG8gdXNlLlxuICAgKiBAcGFyYW0ge0NpcGhlclBhcmFtc3xzdHJpbmd9IGNpcGhlcnRleHQgVGhlIGNpcGhlcnRleHQgdG8gZGVjcnlwdC5cbiAgICogQHBhcmFtIHtXb3JkQXJyYXl9IGtleSBUaGUga2V5LlxuICAgKiBAcGFyYW0ge09iamVjdH0gY2ZnIChPcHRpb25hbCkgVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byB1c2UgZm9yIHRoaXMgb3BlcmF0aW9uLlxuICAgKlxuICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBwbGFpbnRleHQuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBwbGFpbnRleHQgPSBDcnlwdG9KUy5saWIuU2VyaWFsaXphYmxlQ2lwaGVyXG4gICAqICAgICAgIC5kZWNyeXB0KENyeXB0b0pTLmFsZ28uQUVTLCBmb3JtYXR0ZWRDaXBoZXJ0ZXh0LCBrZXksXG4gICAqICAgICAgICAgeyBpdjogaXYsIGZvcm1hdDogQ3J5cHRvSlMuZm9ybWF0Lk9wZW5TU0wgfSk7XG4gICAqICAgICB2YXIgcGxhaW50ZXh0ID0gQ3J5cHRvSlMubGliLlNlcmlhbGl6YWJsZUNpcGhlclxuICAgKiAgICAgICAuZGVjcnlwdChDcnlwdG9KUy5hbGdvLkFFUywgY2lwaGVydGV4dFBhcmFtcywga2V5LFxuICAgKiAgICAgICAgIHsgaXY6IGl2LCBmb3JtYXQ6IENyeXB0b0pTLmZvcm1hdC5PcGVuU1NMIH0pO1xuICAgKi9zdGF0aWMgZGVjcnlwdChjaXBoZXIsY2lwaGVydGV4dCxrZXksY2ZnKXtsZXQgX2NpcGhlcnRleHQ9Y2lwaGVydGV4dDsvLyBBcHBseSBjb25maWcgZGVmYXVsdHNcbmNvbnN0IF9jZmc9T2JqZWN0QXNzaWduKG5ldyBCYXNlKCksdGhpcy5jZmcsY2ZnKTsvLyBDb252ZXJ0IHN0cmluZyB0byBDaXBoZXJQYXJhbXNcbl9jaXBoZXJ0ZXh0PXRoaXMuX3BhcnNlKF9jaXBoZXJ0ZXh0LF9jZmcuZm9ybWF0KTsvLyBEZWNyeXB0XG5jb25zdCBwbGFpbnRleHQ9Y2lwaGVyLmNyZWF0ZURlY3J5cHRvcihrZXksX2NmZykuZmluYWxpemUoX2NpcGhlcnRleHQuY2lwaGVydGV4dCk7cmV0dXJuIHBsYWludGV4dDt9LyoqXG4gICAqIENvbnZlcnRzIHNlcmlhbGl6ZWQgY2lwaGVydGV4dCB0byBDaXBoZXJQYXJhbXMsXG4gICAqIGVsc2UgYXNzdW1lZCBDaXBoZXJQYXJhbXMgYWxyZWFkeSBhbmQgcmV0dXJucyBjaXBoZXJ0ZXh0IHVuY2hhbmdlZC5cbiAgICpcbiAgICogQHBhcmFtIHtDaXBoZXJQYXJhbXN8c3RyaW5nfSBjaXBoZXJ0ZXh0IFRoZSBjaXBoZXJ0ZXh0LlxuICAgKiBAcGFyYW0ge0Zvcm1hdHRlcn0gZm9ybWF0IFRoZSBmb3JtYXR0aW5nIHN0cmF0ZWd5IHRvIHVzZSB0byBwYXJzZSBzZXJpYWxpemVkIGNpcGhlcnRleHQuXG4gICAqXG4gICAqIEByZXR1cm4ge0NpcGhlclBhcmFtc30gVGhlIHVuc2VyaWFsaXplZCBjaXBoZXJ0ZXh0LlxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICB2YXIgY2lwaGVydGV4dFBhcmFtcyA9IENyeXB0b0pTLmxpYi5TZXJpYWxpemFibGVDaXBoZXJcbiAgICogICAgICAgLl9wYXJzZShjaXBoZXJ0ZXh0U3RyaW5nT3JQYXJhbXMsIGZvcm1hdCk7XG4gICAqL3N0YXRpYyBfcGFyc2UoY2lwaGVydGV4dCxmb3JtYXQpe2lmKHR5cGVvZiBjaXBoZXJ0ZXh0PT09J3N0cmluZycpe3JldHVybiBmb3JtYXQucGFyc2UoY2lwaGVydGV4dCx0aGlzKTt9cmV0dXJuIGNpcGhlcnRleHQ7fX0vKipcbiAqIENvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAqXG4gKiBAcHJvcGVydHkge0Zvcm1hdHRlcn0gZm9ybWF0XG4gKlxuICogICAgVGhlIGZvcm1hdHRpbmcgc3RyYXRlZ3kgdG8gY29udmVydCBjaXBoZXIgcGFyYW0gb2JqZWN0cyB0byBhbmQgZnJvbSBhIHN0cmluZy5cbiAqICAgIERlZmF1bHQ6IE9wZW5TU0xcbiAqL1NlcmlhbGl6YWJsZUNpcGhlci5jZmc9T2JqZWN0QXNzaWduKG5ldyBCYXNlKCkse2Zvcm1hdDpPcGVuU1NMRm9ybWF0dGVyfSk7LyoqXG4gKiBPcGVuU1NMIGtleSBkZXJpdmF0aW9uIGZ1bmN0aW9uLlxuICovY29uc3QgT3BlblNTTEtkZj17LyoqXG4gICAqIERlcml2ZXMgYSBrZXkgYW5kIElWIGZyb20gYSBwYXNzd29yZC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhc3N3b3JkIFRoZSBwYXNzd29yZCB0byBkZXJpdmUgZnJvbS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IGtleVNpemUgVGhlIHNpemUgaW4gd29yZHMgb2YgdGhlIGtleSB0byBnZW5lcmF0ZS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IGl2U2l6ZSBUaGUgc2l6ZSBpbiB3b3JkcyBvZiB0aGUgSVYgdG8gZ2VuZXJhdGUuXG4gICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gc2FsdFxuICAgKiAgICAgKE9wdGlvbmFsKSBBIDY0LWJpdCBzYWx0IHRvIHVzZS4gSWYgb21pdHRlZCwgYSBzYWx0IHdpbGwgYmUgZ2VuZXJhdGVkIHJhbmRvbWx5LlxuICAgKlxuICAgKiBAcmV0dXJuIHtDaXBoZXJQYXJhbXN9IEEgY2lwaGVyIHBhcmFtcyBvYmplY3Qgd2l0aCB0aGUga2V5LCBJViwgYW5kIHNhbHQuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBkZXJpdmVkUGFyYW1zID0gQ3J5cHRvSlMua2RmLk9wZW5TU0wuZXhlY3V0ZSgnUGFzc3dvcmQnLCAyNTYvMzIsIDEyOC8zMik7XG4gICAqICAgICB2YXIgZGVyaXZlZFBhcmFtcyA9IENyeXB0b0pTLmtkZi5PcGVuU1NMLmV4ZWN1dGUoJ1Bhc3N3b3JkJywgMjU2LzMyLCAxMjgvMzIsICdzYWx0c2FsdCcpO1xuICAgKi9leGVjdXRlKHBhc3N3b3JkLGtleVNpemUsaXZTaXplLHNhbHQsaGFzaGVyKXtsZXQgX3NhbHQ9c2FsdDsvLyBHZW5lcmF0ZSByYW5kb20gc2FsdFxuaWYoIV9zYWx0KXtfc2FsdD1Xb3JkQXJyYXkucmFuZG9tKDY0LzgpO30vLyBEZXJpdmUga2V5IGFuZCBJVlxubGV0IGtleTtpZighaGFzaGVyKXtrZXk9RXZwS0RGQWxnby5jcmVhdGUoe2tleVNpemU6a2V5U2l6ZStpdlNpemV9KS5jb21wdXRlKHBhc3N3b3JkLF9zYWx0KTt9ZWxzZSB7a2V5PUV2cEtERkFsZ28uY3JlYXRlKHtrZXlTaXplOmtleVNpemUraXZTaXplLGhhc2hlcn0pLmNvbXB1dGUocGFzc3dvcmQsX3NhbHQpO30vLyBTZXBhcmF0ZSBrZXkgYW5kIElWXG5jb25zdCBpdj1Xb3JkQXJyYXkuY3JlYXRlKGtleS53b3Jkcy5zbGljZShrZXlTaXplKSxpdlNpemUqNCk7a2V5LnNpZ0J5dGVzPWtleVNpemUqNDsvLyBSZXR1cm4gcGFyYW1zXG5yZXR1cm4gQ2lwaGVyUGFyYW1zLmNyZWF0ZSh7a2V5LGl2LHNhbHQ6X3NhbHR9KTt9fTsvKipcbiAqIEEgc2VyaWFsaXphYmxlIGNpcGhlciB3cmFwcGVyIHRoYXQgZGVyaXZlcyB0aGUga2V5IGZyb20gYSBwYXNzd29yZCxcbiAqIGFuZCByZXR1cm5zIGNpcGhlcnRleHQgYXMgYSBzZXJpYWxpemFibGUgY2lwaGVyIHBhcmFtcyBvYmplY3QuXG4gKi9jbGFzcyBQYXNzd29yZEJhc2VkQ2lwaGVyIGV4dGVuZHMgU2VyaWFsaXphYmxlQ2lwaGVyey8qKlxuICAgKiBFbmNyeXB0cyBhIG1lc3NhZ2UgdXN
1pbmcgYSBwYXNzd29yZC5cbiAgICpcbiAgICogQHBhcmFtIHtDaXBoZXJ9IGNpcGhlciBUaGUgY2lwaGVyIGFsZ29yaXRobSB0byB1c2UuXG4gICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gbWVzc2FnZSBUaGUgbWVzc2FnZSB0byBlbmNyeXB0LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFzc3dvcmQgVGhlIHBhc3N3b3JkLlxuICAgKiBAcGFyYW0ge09iamVjdH0gY2ZnIChPcHRpb25hbCkgVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byB1c2UgZm9yIHRoaXMgb3BlcmF0aW9uLlxuICAgKlxuICAgKiBAcmV0dXJuIHtDaXBoZXJQYXJhbXN9IEEgY2lwaGVyIHBhcmFtcyBvYmplY3QuXG4gICAqXG4gICAqIEBzdGF0aWNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgIHZhciBjaXBoZXJ0ZXh0UGFyYW1zID0gQ3J5cHRvSlMubGliLlBhc3N3b3JkQmFzZWRDaXBoZXJcbiAgICogICAgICAgLmVuY3J5cHQoQ3J5cHRvSlMuYWxnby5BRVMsIG1lc3NhZ2UsICdwYXNzd29yZCcpO1xuICAgKiAgICAgdmFyIGNpcGhlcnRleHRQYXJhbXMgPSBDcnlwdG9KUy5saWIuUGFzc3dvcmRCYXNlZENpcGhlclxuICAgKiAgICAgICAuZW5jcnlwdChDcnlwdG9KUy5hbGdvLkFFUywgbWVzc2FnZSwgJ3Bhc3N3b3JkJywgeyBmb3JtYXQ6IENyeXB0b0pTLmZvcm1hdC5PcGVuU1NMIH0pO1xuICAgKi9zdGF0aWMgZW5jcnlwdChjaXBoZXIsbWVzc2FnZSxwYXNzd29yZCxjZmcpey8vIEFwcGx5IGNvbmZpZyBkZWZhdWx0c1xuY29uc3QgX2NmZz1PYmplY3RBc3NpZ24obmV3IEJhc2UoKSx0aGlzLmNmZyxjZmcpOy8vIERlcml2ZSBrZXkgYW5kIG90aGVyIHBhcmFtc1xuY29uc3QgZGVyaXZlZFBhcmFtcz1fY2ZnLmtkZi5leGVjdXRlKHBhc3N3b3JkLGNpcGhlci5rZXlTaXplLGNpcGhlci5pdlNpemUsX2NmZy5zYWx0LF9jZmcuaGFzaGVyKTsvLyBBZGQgSVYgdG8gY29uZmlnXG5fY2ZnLml2PWRlcml2ZWRQYXJhbXMuaXY7Ly8gRW5jcnlwdFxuY29uc3QgY2lwaGVydGV4dD1TZXJpYWxpemFibGVDaXBoZXIuZW5jcnlwdC5jYWxsKHRoaXMsY2lwaGVyLG1lc3NhZ2UsZGVyaXZlZFBhcmFtcy5rZXksX2NmZyk7Ly8gTWl4IGluIGRlcml2ZWQgcGFyYW1zXG5jaXBoZXJ0ZXh0Lm1peEluKGRlcml2ZWRQYXJhbXMpO3JldHVybiBjaXBoZXJ0ZXh0O30vKipcbiAgICogRGVjcnlwdHMgc2VyaWFsaXplZCBjaXBoZXJ0ZXh0IHVzaW5nIGEgcGFzc3dvcmQuXG4gICAqXG4gICAqIEBwYXJhbSB7Q2lwaGVyfSBjaXBoZXIgVGhlIGNpcGhlciBhbGdvcml0aG0gdG8gdXNlLlxuICAgKiBAcGFyYW0ge0NpcGhlclBhcmFtc3xzdHJpbmd9IGNpcGhlcnRleHQgVGhlIGNpcGhlcnRleHQgdG8gZGVjcnlwdC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhc3N3b3JkIFRoZSBwYXNzd29yZC5cbiAgICogQHBhcmFtIHtPYmplY3R9IGNmZyAoT3B0aW9uYWwpIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdXNlIGZvciB0aGlzIG9wZXJhdGlvbi5cbiAgICpcbiAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgcGxhaW50ZXh0LlxuICAgKlxuICAgKiBAc3RhdGljXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICB2YXIgcGxhaW50ZXh0ID0gQ3J5cHRvSlMubGliLlBhc3N3b3JkQmFzZWRDaXBoZXJcbiAgICogICAgICAgLmRlY3J5cHQoQ3J5cHRvSlMuYWxnby5BRVMsIGZvcm1hdHRlZENpcGhlcnRleHQsICdwYXNzd29yZCcsXG4gICAqICAgICAgICAgeyBmb3JtYXQ6IENyeXB0b0pTLmZvcm1hdC5PcGVuU1NMIH0pO1xuICAgKiAgICAgdmFyIHBsYWludGV4dCA9IENyeXB0b0pTLmxpYi5QYXNzd29yZEJhc2VkQ2lwaGVyXG4gICAqICAgICAgIC5kZWNyeXB0KENyeXB0b0pTLmFsZ28uQUVTLCBjaXBoZXJ0ZXh0UGFyYW1zLCAncGFzc3dvcmQnLFxuICAgKiAgICAgICAgIHsgZm9ybWF0OiBDcnlwdG9KUy5mb3JtYXQuT3BlblNTTCB9KTtcbiAgICovc3RhdGljIGRlY3J5cHQoY2lwaGVyLGNpcGhlcnRleHQscGFzc3dvcmQsY2ZnKXtsZXQgX2NpcGhlcnRleHQ9Y2lwaGVydGV4dDsvLyBBcHBseSBjb25maWcgZGVmYXVsdHNcbmNvbnN0IF9jZmc9T2JqZWN0QXNzaWduKG5ldyBCYXNlKCksdGhpcy5jZmcsY2ZnKTsvLyBDb252ZXJ0IHN0cmluZyB0byBDaXBoZXJQYXJhbXNcbl9jaXBoZXJ0ZXh0PXRoaXMuX3BhcnNlKF9jaXBoZXJ0ZXh0LF9jZmcuZm9ybWF0KTsvLyBEZXJpdmUga2V5IGFuZCBvdGhlciBwYXJhbXNcbmNvbnN0IGRlcml2ZWRQYXJhbXM9X2NmZy5rZGYuZXhlY3V0ZShwYXNzd29yZCxjaXBoZXIua2V5U2l6ZSxjaXBoZXIuaXZTaXplLF9jaXBoZXJ0ZXh0LnNhbHQsX2NmZy5oYXNoZXIpOy8vIEFkZCBJViB0byBjb25maWdcbl9jZmcuaXY9ZGVyaXZlZFBhcmFtcy5pdjsvLyBEZWNyeXB0XG5jb25zdCBwbGFpbnRleHQ9U2VyaWFsaXphYmxlQ2lwaGVyLmRlY3J5cHQuY2FsbCh0aGlzLGNpcGhlcixfY2lwaGVydGV4dCxkZXJpdmVkUGFyYW1zLmtleSxfY2ZnKTtyZXR1cm4gcGxhaW50ZXh0O319LyoqXG4gKiBDb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gKlxuICogQHByb3BlcnR5IHtLREZ9IGtkZlxuICogICAgIFRoZSBrZXkgZGVyaXZhdGlvbiBmdW5jdGlvbiB0byB1c2UgdG8gZ2VuZXJhdGUgYSBrZXkgYW5kIElWIGZyb20gYSBwYXNzd29yZC5cbiAqICAgICBEZWZhdWx0OiBPcGVuU1NMXG4gKi9QYXNzd29yZEJhc2VkQ2lwaGVyLmNmZz1PYmplY3RBc3NpZ24oU2VyaWFsaXphYmxlQ2lwaGVyLmNmZyx7a2RmOk9wZW5TU0xLZGZ9KTtcblxuY29uc3QgX1NCT1g9W107Y29uc3QgSU5WX1NCT1g9W107Y29uc3QgX1NVQl9NSVhfMD1bXTtjb25zdCBfU1VCX01JWF8xPVtdO2NvbnN0IF9TVUJfTUlYXzI9W107Y29uc3QgX1NVQl9NSVhfMz1bXTtjb25zdCBJTlZfU1VCX01JWF8wPVtdO2NvbnN0IElOVl9TVUJfTUlYXzE9W107Y29uc3QgSU5WX1NVQl9NSVhfMj1bXTtjb25zdCBJTlZfU1VCX01JWF8zPVtdOy8vIENvbXB1dGUgbG9va3VwIHRhYmxlc1xuLy8gQ29tcHV0ZSBkb3VibGUgdGFibGVcbmNvbnN0IGQ9W107Zm9yKGxldCBpPTA7aTwyNTY7aSs9MSl7aWYoaTwxMjgpe2RbaV09aTw8MTt9ZWxzZSB7ZFtpXT1pPDwxXjB4MTFiO319Ly8gV2FsayBHRigyXjgpXG5sZXQgeD0wO2xldCB4aT0wO2ZvcihsZXQgaT0wO2k8MjU2O2krPTEpey8vIENvbXB1dGUgc2JveFxubGV0IHN4PXhpXnhpPDwxXnhpPDwyXnhpPDwzXnhpPDw0O3N4PXN4Pj4+OF5zeCYweGZmXjB4NjM7X1NCT1hbeF09c3g7SU5WX1NCT1hbc3hdPXg7Ly8gQ29tcHV0ZSBtdWx0aXBsaWNhdGlvblxuY29uc3QgeDI9ZFt4XTtjb25zdCB4ND1kW3gyXTtjb25zdCB4OD1kW3g0XTsvLyBDb21wdXRlIHN1YiBieXRlcywgbWl4IGNvbHVtbnMgdGFibGVzXG5sZXQgdD1kW3N4XSoweDEwMV5zeCoweDEwMTAxMDA7X1NVQl9NSVhfMFt4XT10PDwyNHx0Pj4+ODtfU1VCX01JWF8xW3hdPXQ8PDE2fHQ+Pj4xNjtfU1VCX01JWF8yW3hdPXQ8PDh8dD4+PjI0O19TVUJfTUlYXzNbeF09dDsvLyBDb21wdXRlIGludiBzdWIgYnl0ZXMsIGludiBtaXggY29sdW1ucyB0YWJsZXNcbnQ9eDgqMHgxMDEwMTAxXng0KjB4MTAwMDFeeDIqMHgxMDFeeCoweDEwMTAxMDA7SU5WX1NVQl9NSVhfMFtzeF09dDw8MjR8dD4+Pjg7SU5WX1NVQl9NSVhfMVtzeF09dDw8MTZ8dD4+PjE2O0lOVl9TVUJfTUlYXzJbc3hdPXQ8PDh8dD4+PjI0O0lOVl9TVUJfTUlYXzNbc3hdPXQ7Ly8gQ29tcHV0ZSBuZXh0IGNvdW50ZXJcbmlmKCF4KXt4aT0xO3g9eGk7fWVsc2Uge3g9eDJeZFtkW2RbeDheeDJdXV07eGlePWRbZFt4aV1dO319Ly8gUHJlY29tcHV0ZWQgUmNvbiBsb29rdXBcbmNvbnN0IFJDT049WzB4MDAsMHgwMSwweDAyLDB4MDQsMHgwOCwweDEwLDB4MjAsMHg0MCwweDgwLDB4MWIsMHgzNl07LyoqXG4gKiBBRVMgYmxvY2sgY2lwaGVyIGFsZ29yaXRobS5cbiAqL2NsYXNzIEFFU0FsZ28gZXh0ZW5kcyBCbG9ja0NpcGhlcntfZG9SZXNldCgpe2xldCB0Oy8vIFNraXAgcmVzZXQgb2YgblJvdW5kcyBoYXMgYmVlbiBzZXQgYmVmb3JlIGFuZCBrZXkgZGlkIG5vdCBjaGFuZ2VcbmlmKHRoaXMuX25Sb3VuZHMmJnRoaXMuX2tleVByaW9yUmVzZXQ9PT10aGlzLl9rZXkpe3JldHVybjt9Ly8gU2hvcnRjdXRzXG50aGlzLl9rZXlQcmlvclJlc2V0PXRoaXMuX2tleTtjb25zdCBrZXk9dGhpcy5fa2V5UHJpb3JSZXNldDtjb25zdCBrZXlXb3Jkcz1rZXkud29yZHM7Y29uc3Qga2V5U2l6ZT1rZXkuc2lnQnl0ZXMvNDsvLyBDb21wdXRlIG51bWJlciBvZiByb3VuZHNcbnRoaXMuX25Sb3VuZHM9a2V5U2l6ZSs2O2NvbnN0IG5Sb3VuZHM9dGhpcy5fblJvdW5kczsvLyBDb21wdXRlIG51bWJlciBvZiBrZXkgc2NoZWR1bGUgcm93c1xuY29uc3Qga3NSb3dzPShuUm91bmRzKzEpKjQ7Ly8gQ29tcHV0ZSBrZXkgc2NoZWR1bGVcbnRoaXMuX2tleVNjaGVkdWxlPVtdO2NvbnN0IGtleVNjaGVkdWxlPXRoaXMuX2tleVNjaGVkdWxlO2ZvcihsZXQga3NSb3c9MDtrc1Jvdzxrc1Jvd3M7a3NSb3crPTEpe2lmKGtzUm93PGtleVNpemUpe2tleVNjaGVkdWxlW2tzUm93XT1rZXlXb3Jkc1trc1Jvd107fWVsc2Uge3Q9a2V5U2NoZWR1bGVba3NSb3ctMV07aWYoIShrc1JvdyVrZXlTaXplKSl7Ly8gUm90IHdvcmRcbnQ9dDw8OHx0Pj4+MjQ7Ly8gU3ViIHdvcmRcbnQ9X1NCT1hbdD4+PjI0XTw8MjR8X1NCT1hbdD4+PjE2JjB4ZmZdPDwxNnxfU0JPWFt0Pj4+OCYweGZmXTw8OHxfU0JPWFt0JjB4ZmZdOy8vIE1peCBSY29uXG50Xj1SQ09OW2tzUm93L2tleVNpemV8MF08PDI0O31lbHNlIGlmKGtleVNpemU+NiYma3NSb3cla2V5U2l6ZT09PTQpey8vIFN1YiB3b3JkXG50PV9TQk9YW3Q+Pj4yNF08PDI0fF9TQk9YW3Q+Pj4xNiYweGZmXTw8MTZ8X1NCT1hbdD4+PjgmMHhmZl08PDh8X1NCT1hbdCYweGZmXTt9a2V5U2NoZWR1bGVba3NSb3ddPWtleVNjaGVkdWxlW2tzUm93LWtleVNpemVdXnQ7fX0vLyBDb21wdXRlIGludiBrZXkgc2NoZWR1bGVcbnRoaXMuX2ludktleVNjaGVkdWxlPVtdO2NvbnN0IGludktleVNjaGVkdWxlPXRoaXMuX2ludktleVNjaGVkdWxlO2ZvcihsZXQgaW52S3NSb3c9MDtpbnZLc1Jvdzxrc1Jvd3M7aW52S3NSb3crPTEpe2NvbnN0IGtzUm93PWtzUm93cy1pbnZLc1JvdztpZihpbnZLc1JvdyU0KXt0PWtleVNjaGVkdWxlW2tzUm93XTt9ZWxzZSB7dD1rZXlTY2hlZHVsZVtrc1Jvdy00XTt9aWYoaW52S3NSb3c8NHx8a3NSb3c8PTQpe2ludktleVNjaGVkdWxlW2ludktzUm93XT10O31lbHNlIHtpbnZLZXlTY2hlZHVsZVtpbnZLc1Jvd109SU5WX1NVQl9NSVhfMFtfU0JPWFt0Pj4+MjRdXV
15JTlZfU1VCX01JWF8xW19TQk9YW3Q+Pj4xNiYweGZmXV1eSU5WX1NVQl9NSVhfMltfU0JPWFt0Pj4+OCYweGZmXV1eSU5WX1NVQl9NSVhfM1tfU0JPWFt0JjB4ZmZdXTt9fX1lbmNyeXB0QmxvY2soTSxvZmZzZXQpe3RoaXMuX2RvQ3J5cHRCbG9jayhNLG9mZnNldCx0aGlzLl9rZXlTY2hlZHVsZSxfU1VCX01JWF8wLF9TVUJfTUlYXzEsX1NVQl9NSVhfMixfU1VCX01JWF8zLF9TQk9YKTt9ZGVjcnlwdEJsb2NrKE0sb2Zmc2V0KXtjb25zdCBfTT1NOy8vIFN3YXAgMm5kIGFuZCA0dGggcm93c1xubGV0IHQ9X01bb2Zmc2V0KzFdO19NW29mZnNldCsxXT1fTVtvZmZzZXQrM107X01bb2Zmc2V0KzNdPXQ7dGhpcy5fZG9DcnlwdEJsb2NrKF9NLG9mZnNldCx0aGlzLl9pbnZLZXlTY2hlZHVsZSxJTlZfU1VCX01JWF8wLElOVl9TVUJfTUlYXzEsSU5WX1NVQl9NSVhfMixJTlZfU1VCX01JWF8zLElOVl9TQk9YKTsvLyBJbnYgc3dhcCAybmQgYW5kIDR0aCByb3dzXG50PV9NW29mZnNldCsxXTtfTVtvZmZzZXQrMV09X01bb2Zmc2V0KzNdO19NW29mZnNldCszXT10O31fZG9DcnlwdEJsb2NrKE0sb2Zmc2V0LGtleVNjaGVkdWxlLFNVQl9NSVhfMCxTVUJfTUlYXzEsU1VCX01JWF8yLFNVQl9NSVhfMyxTQk9YKXtjb25zdCBfTT1NOy8vIFNob3J0Y3V0XG5jb25zdCBuUm91bmRzPXRoaXMuX25Sb3VuZHM7Ly8gR2V0IGlucHV0LCBhZGQgcm91bmQga2V5XG5sZXQgczA9X01bb2Zmc2V0XV5rZXlTY2hlZHVsZVswXTtsZXQgczE9X01bb2Zmc2V0KzFdXmtleVNjaGVkdWxlWzFdO2xldCBzMj1fTVtvZmZzZXQrMl1ea2V5U2NoZWR1bGVbMl07bGV0IHMzPV9NW29mZnNldCszXV5rZXlTY2hlZHVsZVszXTsvLyBLZXkgc2NoZWR1bGUgcm93IGNvdW50ZXJcbmxldCBrc1Jvdz00Oy8vIFJvdW5kc1xuZm9yKGxldCByb3VuZD0xO3JvdW5kPG5Sb3VuZHM7cm91bmQrPTEpey8vIFNoaWZ0IHJvd3MsIHN1YiBieXRlcywgbWl4IGNvbHVtbnMsIGFkZCByb3VuZCBrZXlcbmNvbnN0IHQwPVNVQl9NSVhfMFtzMD4+PjI0XV5TVUJfTUlYXzFbczE+Pj4xNiYweGZmXV5TVUJfTUlYXzJbczI+Pj44JjB4ZmZdXlNVQl9NSVhfM1tzMyYweGZmXV5rZXlTY2hlZHVsZVtrc1Jvd107a3NSb3crPTE7Y29uc3QgdDE9U1VCX01JWF8wW3MxPj4+MjRdXlNVQl9NSVhfMVtzMj4+PjE2JjB4ZmZdXlNVQl9NSVhfMltzMz4+PjgmMHhmZl1eU1VCX01JWF8zW3MwJjB4ZmZdXmtleVNjaGVkdWxlW2tzUm93XTtrc1Jvdys9MTtjb25zdCB0Mj1TVUJfTUlYXzBbczI+Pj4yNF1eU1VCX01JWF8xW3MzPj4+MTYmMHhmZl1eU1VCX01JWF8yW3MwPj4+OCYweGZmXV5TVUJfTUlYXzNbczEmMHhmZl1ea2V5U2NoZWR1bGVba3NSb3ddO2tzUm93Kz0xO2NvbnN0IHQzPVNVQl9NSVhfMFtzMz4+PjI0XV5TVUJfTUlYXzFbczA+Pj4xNiYweGZmXV5TVUJfTUlYXzJbczE+Pj44JjB4ZmZdXlNVQl9NSVhfM1tzMiYweGZmXV5rZXlTY2hlZHVsZVtrc1Jvd107a3NSb3crPTE7Ly8gVXBkYXRlIHN0YXRlXG5zMD10MDtzMT10MTtzMj10MjtzMz10Mzt9Ly8gU2hpZnQgcm93cywgc3ViIGJ5dGVzLCBhZGQgcm91bmQga2V5XG5jb25zdCB0MD0oU0JPWFtzMD4+PjI0XTw8MjR8U0JPWFtzMT4+PjE2JjB4ZmZdPDwxNnxTQk9YW3MyPj4+OCYweGZmXTw8OHxTQk9YW3MzJjB4ZmZdKV5rZXlTY2hlZHVsZVtrc1Jvd107a3NSb3crPTE7Y29uc3QgdDE9KFNCT1hbczE+Pj4yNF08PDI0fFNCT1hbczI+Pj4xNiYweGZmXTw8MTZ8U0JPWFtzMz4+PjgmMHhmZl08PDh8U0JPWFtzMCYweGZmXSlea2V5U2NoZWR1bGVba3NSb3ddO2tzUm93Kz0xO2NvbnN0IHQyPShTQk9YW3MyPj4+MjRdPDwyNHxTQk9YW3MzPj4+MTYmMHhmZl08PDE2fFNCT1hbczA+Pj44JjB4ZmZdPDw4fFNCT1hbczEmMHhmZl0pXmtleVNjaGVkdWxlW2tzUm93XTtrc1Jvdys9MTtjb25zdCB0Mz0oU0JPWFtzMz4+PjI0XTw8MjR8U0JPWFtzMD4+PjE2JjB4ZmZdPDwxNnxTQk9YW3MxPj4+OCYweGZmXTw8OHxTQk9YW3MyJjB4ZmZdKV5rZXlTY2hlZHVsZVtrc1Jvd107a3NSb3crPTE7Ly8gU2V0IG91dHB1dFxuX01bb2Zmc2V0XT10MDtfTVtvZmZzZXQrMV09dDE7X01bb2Zmc2V0KzJdPXQyO19NW29mZnNldCszXT10Mzt9fUFFU0FsZ28ua2V5U2l6ZT0yNTYvMzI7LyoqXG4gKiBTaG9ydGN1dCBmdW5jdGlvbnMgdG8gdGhlIGNpcGhlcidzIG9iamVjdCBpbnRlcmZhY2UuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiAgICAgdmFyIGNpcGhlcnRleHQgPSBDcnlwdG9KUy5BRVMuZW5jcnlwdChtZXNzYWdlLCBrZXksIGNmZyk7XG4gKiAgICAgdmFyIHBsYWludGV4dCAgPSBDcnlwdG9KUy5BRVMuZGVjcnlwdChjaXBoZXJ0ZXh0LCBrZXksIGNmZyk7XG4gKi9jb25zdCBBRVM9QmxvY2tDaXBoZXIuX2NyZWF0ZUhlbHBlcihBRVNBbGdvKTtcblxuY29uc3QgRU5DUllQVElPTl9QUkVGSVhfVjE9J1J1ZGRlckVuY3J5cHQ6Jztjb25zdCBFTkNSWVBUSU9OX0tFWV9WMT0nUnVkZGVyJztcblxuY29uc3QgZW5jcnlwdD12YWx1ZT0+YCR7RU5DUllQVElPTl9QUkVGSVhfVjF9JHtBRVMuZW5jcnlwdCh2YWx1ZSxFTkNSWVBUSU9OX0tFWV9WMSkudG9TdHJpbmcoKX1gO2NvbnN0IGRlY3J5cHQ9dmFsdWU9PntpZih2YWx1ZS5zdGFydHNXaXRoKEVOQ1JZUFRJT05fUFJFRklYX1YxKSl7cmV0dXJuIEFFUy5kZWNyeXB0KHZhbHVlLnN1YnN0cmluZyhFTkNSWVBUSU9OX1BSRUZJWF9WMS5sZW5ndGgpLEVOQ1JZUFRJT05fS0VZX1YxKS50b1N0cmluZyhVdGY4KTt9cmV0dXJuIHZhbHVlO307XG5cbmNvbnN0IHBsdWdpbk5hbWUkMj0nU3RvcmFnZUVuY3J5cHRpb25MZWdhY3knO2NvbnN0IFN0b3JhZ2VFbmNyeXB0aW9uTGVnYWN5PSgpPT4oe25hbWU6cGx1Z2luTmFtZSQyLGluaXRpYWxpemU6c3RhdGU9PntzdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWU9Wy4uLnN0YXRlLnBsdWdpbnMubG9hZGVkUGx1Z2lucy52YWx1ZSxwbHVnaW5OYW1lJDJdO30sc3RvcmFnZTp7ZW5jcnlwdCh2YWx1ZSl7cmV0dXJuIGVuY3J5cHQodmFsdWUpO30sZGVjcnlwdCh2YWx1ZSl7cmV0dXJuIGRlY3J5cHQodmFsdWUpO319fSk7XG5cbmNvbnN0IFNUT1JBR0VfTUlHUkFUSU9OX0VSUk9SPWtleT0+YEZhaWxlZCB0byByZXRyaWV2ZSBvciBwYXJzZSBkYXRhIGZvciBcIiR7a2V5fVwiIGZyb20gc3RvcmFnZS5gO1
1xuXG5jb25zdCBTVE9SQUdFX01JR1JBVE9SX1BMVUdJTj0nU3RvcmFnZU1pZ3JhdG9yUGx1Z2luJztcblxuY29uc3QgcGx1Z2luTmFtZSQxPSdTdG9yYWdlTWlncmF0b3InO2NvbnN0IFN0b3JhZ2VNaWdyYXRvcj0oKT0+KHtuYW1lOnBsdWdpbk5hbWUkMSxpbml0aWFsaXplOnN0YXRlPT57c3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlPVsuLi5zdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWUscGx1Z2luTmFtZSQxXTt9LHN0b3JhZ2U6e21pZ3JhdGUoa2V5LHN0b3JhZ2VFbmdpbmUsZXJyb3JIYW5kbGVyLGxvZ2dlcil7dHJ5e2NvbnN0IHN0b3JlZFZhbD1zdG9yYWdlRW5naW5lLmdldEl0ZW0oa2V5KTtpZihpc051bGxPclVuZGVmaW5lZChzdG9yZWRWYWwpKXtyZXR1cm4gbnVsbDt9bGV0IGN1cnJlbnRWYWw9c3RvcmVkVmFsO2xldCBkZWNyeXB0ZWRWYWw9ZGVjcnlwdChjdXJyZW50VmFsKTsvLyBEZWNyeXB0IHVzaW5nIHRoZSBsYXRlc3QgZW5jcnlwdGlvbiBtZXRob2QgYXMgd2VsbFxuZGVjcnlwdGVkVmFsPWRlY3J5cHRCcm93c2VyKGRlY3J5cHRlZFZhbCk7Ly8gc3RvcmVqcyB0aGF0IGlzIHVzZWQgaW4gbG9jYWxzdG9yYWdlIGVuZ2luZSBhbHJlYWR5IGRlc2VyaWFsaXplcyBqc29uIHN0cmluZ3MgYnV0IHN3YWxsb3dzIGVycm9yc1xuY3VycmVudFZhbD1KU09OLnBhcnNlKGRlY3J5cHRlZFZhbCk7Ly8gUmVjdXJzaXZlbHkgZGVjcnlwdCB0aGUgdmFsdWUgdW50aWwgd2UgcmVhY2ggYSBwb2ludCB3aGVyZSB0aGUgdmFsdWVcbi8vIGlzIG5vdCBlbmNyeXB0ZWQgYW55bW9yZVxud2hpbGUoaXNTdHJpbmcoY3VycmVudFZhbCkpe2RlY3J5cHRlZFZhbD1kZWNyeXB0KGN1cnJlbnRWYWwpOy8vIERlY3J5cHQgdXNpbmcgdGhlIGxhdGVzdCBlbmNyeXB0aW9uIG1ldGhvZCBhcyB3ZWxsXG5kZWNyeXB0ZWRWYWw9ZGVjcnlwdEJyb3dzZXIoZGVjcnlwdGVkVmFsKTsvLyBJZiB0aGUgZGVjcnlwdGVkIHZhbHVlIGlzIHRoZSBzYW1lIGFzIHRoZSBjdXJyZW50IHZhbHVlLFxuLy8gdGhlbiBpdCdzIG5vdCBlbmNyeXB0ZWQgYW55bW9yZVxuaWYoZGVjcnlwdGVkVmFsPT09Y3VycmVudFZhbCl7YnJlYWs7fS8vIHN0b3JlanMgdGhhdCBpcyB1c2VkIGluIGxvY2Fsc3RvcmFnZSBlbmdpbmUgYWxyZWFkeSBkZXNlcmlhbGl6ZXMganNvbiBzdHJpbmdzIGJ1dCBzd2FsbG93cyBlcnJvcnNcbmN1cnJlbnRWYWw9SlNPTi5wYXJzZShkZWNyeXB0ZWRWYWwpO31yZXR1cm4gY3VycmVudFZhbDt9Y2F0Y2goZXJyKXtjb25zdCBjdXN0b21NZXNzYWdlPVNUT1JBR0VfTUlHUkFUSU9OX0VSUk9SKGtleSk7ZXJyb3JIYW5kbGVyPy5vbkVycm9yKHtlcnJvcjplcnIsY29udGV4dDpTVE9SQUdFX01JR1JBVE9SX1BMVUdJTixjdXN0b21NZXNzYWdlLGdyb3VwaW5nSGFzaDpjdXN0b21NZXNzYWdlfSk7cmV0dXJuIG51bGw7fX19fSk7XG5cbmNvbnN0IERFRkFVTFRfUkVUUllfUVVFVUVfT1BUSU9OUz17bWF4UmV0cnlEZWxheTozNjAwMDAsbWluUmV0cnlEZWxheToxMDAwLGJhY2tvZmZGYWN0b3I6MixtYXhBdHRlbXB0czoxMCxtYXhJdGVtczoxMDB9O2NvbnN0IFJFUVVFU1RfVElNRU9VVF9NUz0zMCoxMDAwOy8vIDMwIHNlY29uZHNcbmNvbnN0IERBVEFfUExBTkVfQVBJX1ZFUlNJT049J3YxJztjb25zdCBRVUVVRV9OQU1FPSdydWRkZXInO2NvbnN0IFhIUl9RVUVVRV9QTFVHSU49J1hoclF1ZXVlUGx1Z2luJztcblxuY29uc3QgRVZFTlRfREVMSVZFUllfRkFJTFVSRV9FUlJPUl9QUkVGSVg9KGNvbnRleHQsb3JpZ2luYWxFcnJvck1zZyk9PmAke2NvbnRleHR9JHtMT0dfQ09OVEVYVF9TRVBBUkFUT1J9RmFpbGVkIHRvIGRlbGl2ZXIgZXZlbnQocykuIENhdXNlOiAke29yaWdpbmFsRXJyb3JNc2d9LmA7XG5cbmNvbnN0IGdldEJhdGNoRGVsaXZlcnlQYXlsb2FkPShldmVudHMsY3VycmVudFRpbWUsbG9nZ2VyKT0+e2NvbnN0IGJhdGNoUGF5bG9hZD17YmF0Y2g6ZXZlbnRzLHNlbnRBdDpjdXJyZW50VGltZX07cmV0dXJuIHN0cmluZ2lmeVdpdGhvdXRDaXJjdWxhcihiYXRjaFBheWxvYWQsdHJ1ZSx1bmRlZmluZWQsbG9nZ2VyKTt9O2NvbnN0IGdldE5vcm1hbGl6ZWRRdWV1ZU9wdGlvbnM9cXVldWVPcHRzPT5tZXJnZURlZXBSaWdodChERUZBVUxUX1JFVFJZX1FVRVVFX09QVElPTlMscXVldWVPcHRzKTtjb25zdCBnZXREZWxpdmVyeVVybD0oZGF0YXBsYW5lVXJsLGVuZHBvaW50KT0+e2NvbnN0IGRwVXJsPW5ldyBVUkwoZGF0YXBsYW5lVXJsKTtyZXR1cm4gbmV3IFVSTChyZW1vdmVEdXBsaWNhdGVTbGFzaGVzKFtkcFVybC5wYXRobmFtZSwnLycsREFUQV9QTEFORV9BUElfVkVSU0lPTiwnLycsZW5kcG9pbnRdLmpvaW4oJycpKSxkcFVybCkuaHJlZjt9O2NvbnN0IGdldEJhdGNoRGVsaXZlcnlVcmw9ZGF0YXBsYW5lVXJsPT5nZXREZWxpdmVyeVVybChkYXRhcGxhbmVVcmwsJ2JhdGNoJyk7Y29uc3QgbG9nTWVzc2FnZU9uRmFpbHVyZT0oZGV0YWlscyxpc1JldHJ5YWJsZSxxSXRlbVByb2Nlc3NJbmZvLGxvZ2dlcik9PntpZighbG9nZ2VyKXtyZXR1cm47fWxldCBsb2dNc2c9RVZFTlRfREVMSVZFUllfRkFJTFVSRV9FUlJPUl9QUkVGSVgoWEhSX1FVRVVFX1BMVUdJTixkZXRhaWxzPy5lcnJvcj8ubWVzc2FnZT8/J1Vua25vd24nKTtjb25zdCBkcm9wTXNnPWBUaGUgZXZlbnQocykgd2lsbCBiZSBkcm9wcGVkLmA7aWYoaXNSZXRyeWFibGUpe2lmKHFJdGVtUHJvY2Vzc0luZm8ud2lsbEJlUmV0cmllZCl7bG9nTXNnPWAke2xvZ01zZ30gVGhlIGV2ZW50KHMpIHdpbGwgYmUgcmV0cmllZC5gO2lmKHFJdGVtUHJvY2Vzc0luZm8ucmV0cnlBdHRlbXB0TnVtYmVyPjApe2xvZ01zZz1gJHtsb2dNc2d9IFJldHJ5IGF0dGVtcHQgJHtxSXRlbVByb2Nlc3NJbmZvLnJldHJ5QXR0ZW1wdE51bWJlcn0gb2YgJHtxSXRlbVByb2Nlc3NJbmZvLm1heFJldHJ5QXR0ZW1wdHN9LmA7fS8vIFVzZSB3YXJuaW5nIGZvciByZXRyeWFibGUgZmFpbHVyZXMgdGhhdCB3aWxsIGJlIHJldHJpZWRcbmxvZ2dlci53YXJuKGxvZ01zZyk7fWVsc2Uge2xvZ2dlci5lcnJvcihgJHtsb2dNc2d9IFJldHJpZXMgZXhoYXVzdGVkICgke3FJdGVtUHJvY2Vzc0luZm8ubWF4UmV0cnlBdHRlbXB0c30pLiAke2Ryb3BNc2d9YCk7fX1lbHNlI
1HsvLyBVc2UgZXJyb3IgZm9yIG5vbi1yZXRyeWFibGUgZmFpbHVyZXNcbmxvZ2dlci5lcnJvcihgJHtsb2dNc2d9ICR7ZHJvcE1zZ31gKTt9fTtjb25zdCBnZXRSZXF1ZXN0SW5mbz0oaXRlbURhdGEsc3RhdGUscUl0ZW1Qcm9jZXNzSW5mbyxsb2dnZXIpPT57bGV0IGRhdGE7bGV0IGhlYWRlcnM7bGV0IHVybDtjb25zdCBjdXJyZW50VGltZT1nZXRDdXJyZW50VGltZUZvcm1hdHRlZCgpO2lmKEFycmF5LmlzQXJyYXkoaXRlbURhdGEpKXtjb25zdCBmaW5hbEV2ZW50cz1pdGVtRGF0YS5tYXAocXVldWVJdGVtRGF0YT0+Z2V0RmluYWxFdmVudEZvckRlbGl2ZXJ5TXV0YXRvcihxdWV1ZUl0ZW1EYXRhLmV2ZW50LGN1cnJlbnRUaW1lKSk7ZGF0YT1nZXRCYXRjaERlbGl2ZXJ5UGF5bG9hZChmaW5hbEV2ZW50cyxjdXJyZW50VGltZSxsb2dnZXIpO2hlYWRlcnM9aXRlbURhdGFbMF0/Y2xvbmUoaXRlbURhdGFbMF0uaGVhZGVycyk6e307dXJsPWdldEJhdGNoRGVsaXZlcnlVcmwoc3RhdGUubGlmZWN5Y2xlLmFjdGl2ZURhdGFwbGFuZVVybC52YWx1ZSk7fWVsc2Uge2NvbnN0e3VybDpldmVudFVybCxldmVudCxoZWFkZXJzOmV2ZW50SGVhZGVyc309aXRlbURhdGE7Y29uc3QgZmluYWxFdmVudD1nZXRGaW5hbEV2ZW50Rm9yRGVsaXZlcnlNdXRhdG9yKGV2ZW50LGN1cnJlbnRUaW1lKTtkYXRhPWdldERlbGl2ZXJ5UGF5bG9hZChmaW5hbEV2ZW50LGxvZ2dlcik7aGVhZGVycz1jbG9uZShldmVudEhlYWRlcnMpO3VybD1ldmVudFVybDt9Ly8gQWRkIGN1cnJlbnQgdGltZXN0YW1wIGFzIHNlbnRBdCBoZWFkZXJcbi8vIFRoZSBzYW1lIHZhbHVlIGlzIGFkZGVkIGluIHRoZSBldmVudCBwYXlsb2FkIGFzIHdlbGxcbmhlYWRlcnMuU2VudEF0PWN1cnJlbnRUaW1lOy8vIEFkZCBhIGhlYWRlciB0byBpbmRpY2F0ZSBpZiB0aGUgaXRlbSBoYXMgYmVlbiByZWNsYWltZWQgZnJvbVxuLy8gbG9jYWwgc3RvcmFnZVxuaWYocUl0ZW1Qcm9jZXNzSW5mby5yZWNsYWltZWQpe2hlYWRlcnNbJ1JzYS1SZWNvdmVyZWQnXT0ndHJ1ZSc7fS8vIEFkZCByZXRyeSBoZWFkZXJzIGlmIHRoZSBpdGVtIGlzIGJlaW5nIHJldHJpZWQgZm9yIGRlbGl2ZXJ5XG5pZihxSXRlbVByb2Nlc3NJbmZvLnJldHJ5QXR0ZW1wdE51bWJlcj4wKXsvLyBUaGUgbnVtYmVyIG9mIHRpbWVzIHRoaXMgaXRlbSBoYXMgYmVlbiBhdHRlbXB0ZWQgdG8gcmV0cnlcbmhlYWRlcnNbJ1JzYS1SZXRyeS1BdHRlbXB0J109cUl0ZW1Qcm9jZXNzSW5mby5yZXRyeUF0dGVtcHROdW1iZXIudG9TdHJpbmcoKTsvLyBUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBzaW5jZSB0aGUgbGFzdCBhdHRlbXB0XG5oZWFkZXJzWydSc2EtU2luY2UtTGFzdC1BdHRlbXB0J109cUl0ZW1Qcm9jZXNzSW5mby50aW1lU2luY2VMYXN0QXR0ZW1wdC50b1N0cmluZygpOy8vIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHNpbmNlIHRoZSBmaXJzdCBhdHRlbXB0XG5oZWFkZXJzWydSc2EtU2luY2UtRmlyc3QtQXR0ZW1wdCddPXFJdGVtUHJvY2Vzc0luZm8udGltZVNpbmNlRmlyc3RBdHRlbXB0LnRvU3RyaW5nKCk7Ly8gVGhlIHJlYXNvbiBmb3IgdGhlIHJldHJ5XG5oZWFkZXJzWydSc2EtUmV0cnktUmVhc29uJ109cUl0ZW1Qcm9jZXNzSW5mby5yZXRyeVJlYXNvbjt9cmV0dXJuIHtkYXRhLGhlYWRlcnMsdXJsfTt9O1xuXG5jb25zdCBwbHVnaW5OYW1lPSdYaHJRdWV1ZSc7Y29uc3QgWGhyUXVldWU9KCk9Pih7bmFtZTpwbHVnaW5OYW1lLGRlcHM6W10saW5pdGlhbGl6ZTpzdGF0ZT0+e3N0YXRlLnBsdWdpbnMubG9hZGVkUGx1Z2lucy52YWx1ZT1bLi4uc3RhdGUucGx1Z2lucy5sb2FkZWRQbHVnaW5zLnZhbHVlLHBsdWdpbk5hbWVdO30sZGF0YXBsYW5lRXZlbnRzUXVldWU6ey8qKlxuICAgICAqIEluaXRpYWxpemUgdGhlIHF1ZXVlIGZvciBkZWxpdmVyeVxuICAgICAqIEBwYXJhbSBzdGF0ZSBBcHBsaWNhdGlvbiBzdGF0ZVxuICAgICAqIEBwYXJhbSBodHRwQ2xpZW50IGh0dHAgY2xpZW50IGluc3RhbmNlXG4gICAgICogQHBhcmFtIHN0b3JlTWFuYWdlciBTdG9yZSBNYW5hZ2VyIGluc3RhbmNlXG4gICAgICogQHBhcmFtIGVycm9ySGFuZGxlciBFcnJvciBoYW5kbGVyIGluc3RhbmNlXG4gICAgICogQHBhcmFtIGxvZ2dlciBMb2dnZXIgaW5zdGFuY2VcbiAgICAgKiBAcmV0dXJucyBSZXRyeVF1ZXVlIGluc3RhbmNlXG4gICAgICovaW5pdChzdGF0ZSxodHRwQ2xpZW50LHN0b3JlTWFuYWdlcixlcnJvckhhbmRsZXIsbG9nZ2VyKXtjb25zdCB3cml0ZUtleT1zdGF0ZS5saWZlY3ljbGUud3JpdGVLZXkudmFsdWU7aHR0cENsaWVudC5zZXRBdXRoSGVhZGVyKHdyaXRlS2V5KTtjb25zdCBmaW5hbFFPcHRzPWdldE5vcm1hbGl6ZWRRdWV1ZU9wdGlvbnMoc3RhdGUubG9hZE9wdGlvbnMudmFsdWUucXVldWVPcHRpb25zKTtjb25zdCBldmVudHNRdWV1ZT1uZXcgUmV0cnlRdWV1ZSgvLyBhZGRpbmcgd3JpdGUga2V5IHRvIHRoZSBxdWV1ZSBuYW1lIHRvIGF2b2lkIGNvbmZsaWN0c1xuYCR7UVVFVUVfTkFNRX1fJHt3cml0ZUtleX1gLGZpbmFsUU9wdHMsKGl0ZW1EYXRhLGRvbmUscUl0ZW1Qcm9jZXNzSW5mbyk9Pntjb25zdHtkYXRhLHVybCxoZWFkZXJzfT1nZXRSZXF1ZXN0SW5mbyhpdGVtRGF0YSxzdGF0ZSxxSXRlbVByb2Nlc3NJbmZvLGxvZ2dlcik7aHR0cENsaWVudC5nZXRBc3luY0RhdGEoe3VybCxvcHRpb25zOnttZXRob2Q6J1BPU1QnLGhlYWRlcnMsZGF0YTpkYXRhLHNlbmRSYXdEYXRhOnRydWV9LGlzUmF3UmVzcG9uc2U6dHJ1ZSx0aW1lb3V0OlJFUVVFU1RfVElNRU9VVF9NUyxjYWxsYmFjazoocmVzdWx0LGRldGFpbHMpPT57Ly8gSWYgdGhlcmUgaXMgbm8gZXJyb3IsIHdlIGNhbiBjb25zaWRlciB0aGUgaXRlbSBhcyBkZWxpdmVyZWRcbmlmKGlzVW5kZWZpbmVkKGRldGFpbHM/LmVycm9yKSl7Ly8gbnVsbCBtZWFucyBpdGVtIHdpbGwgbm90IGJlIHByb2Nlc3NlZCBmdXJ0aGVyIGFuZCB3aWxsIGJlIHJlbW92ZWQgZnJvbSB0aGUgcXVldWUgKGV2ZW4gZnJvbSB0aGUgc3RvcmFnZSlcbmRvbmUobnVsbCk7cmV0dXJuO31jb25zdCBpc1JldHJ5YWJsZT1pc0VyclJldHJ5YWJsZShkZXRhaWxzPy54aHI/LnN0YXR1cz8/MCk7bG9nTWVzc2FnZU9uRmFpbHVy
1ZShkZXRhaWxzLGlzUmV0cnlhYmxlLHFJdGVtUHJvY2Vzc0luZm8sbG9nZ2VyKTtpZihpc1JldHJ5YWJsZSl7bGV0IHJldHJ5UmVhc29uPURFRkFVTFRfUkVUUllfUkVBU09OO2lmKGRldGFpbHM/LnRpbWVkT3V0KXtyZXRyeVJlYXNvbj1SRVRSWV9SRUFTT05fQ0xJRU5UX1RJTUVPVVQ7fWVsc2UgaWYoaXNEZWZpbmVkKGRldGFpbHM/Lnhocj8uc3RhdHVzKSl7cmV0cnlSZWFzb249YHNlcnZlci0ke2RldGFpbHMueGhyLnN0YXR1c31gO31kb25lKGRldGFpbHMse3JldHJ5UmVhc29ufSk7fWVsc2Ugey8vIG51bGwgbWVhbnMgaXRlbSB3aWxsIG5vdCBiZSBwcm9jZXNzZWQgZnVydGhlciBhbmQgd2lsbCBiZSByZW1vdmVkIGZyb20gdGhlIHF1ZXVlIChldmVuIGZyb20gdGhlIHN0b3JhZ2UpXG5kb25lKG51bGwpO319fSk7fSxzdG9yZU1hbmFnZXIsZ2V0U3RvcmFnZVR5cGVGb3JFdmVudHNQZXJzaXN0ZW5jZShsb2dnZXIpLGxvZ2dlcixpdGVtRGF0YT0+e2NvbnN0IGN1cnJlbnRUaW1lPWdldEN1cnJlbnRUaW1lRm9ybWF0dGVkKCk7Y29uc3QgZXZlbnRzPWl0ZW1EYXRhLm1hcChxdWV1ZUl0ZW1EYXRhPT5xdWV1ZUl0ZW1EYXRhLmV2ZW50KTsvLyB0eXBlIGNhc3RpbmcgdG8gc3RyaW5nIGFzIHdlIGtub3cgdGhhdCB0aGUgZXZlbnQgaGFzIGFscmVhZHkgYmVlbiB2YWxpZGF0ZWQgcHJpb3IgdG8gZW5xdWV1ZVxucmV0dXJuIGdldEJhdGNoRGVsaXZlcnlQYXlsb2FkKGV2ZW50cyxjdXJyZW50VGltZSxsb2dnZXIpPy5sZW5ndGg7fSk7cmV0dXJuIGV2ZW50c1F1ZXVlO30sLyoqXG4gICAgICogQWRkIGV2ZW50IHRvIHRoZSBxdWV1ZSBmb3IgZGVsaXZlcnlcbiAgICAgKiBAcGFyYW0gc3RhdGUgQXBwbGljYXRpb24gc3RhdGVcbiAgICAgKiBAcGFyYW0gZXZlbnRzUXVldWUgUmV0cnlRdWV1ZSBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBldmVudCBSdWRkZXJFdmVudCBvYmplY3RcbiAgICAgKiBAcGFyYW0gZXJyb3JIYW5kbGVyIEVycm9yIGhhbmRsZXIgaW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gbG9nZ2VyIExvZ2dlciBpbnN0YW5jZVxuICAgICAqIEByZXR1cm5zIG5vbmVcbiAgICAgKi9lbnF1ZXVlKHN0YXRlLGV2ZW50c1F1ZXVlLGV2ZW50LGVycm9ySGFuZGxlcixsb2dnZXIpey8vIHNlbnRBdCBpcyBvbmx5IGFkZGVkIGhlcmUgZm9yIHRoZSB2YWxpZGF0aW9uIHN0ZXBcbi8vIEl0J2xsIGJlIHVwZGF0ZWQgdG8gdGhlIGxhdGVzdCB0aW1lc3RhbXAgZHVyaW5nIGFjdHVhbCBkZWxpdmVyeVxuZXZlbnQuc2VudEF0PWdldEN1cnJlbnRUaW1lRm9ybWF0dGVkKCk7dmFsaWRhdGVFdmVudFBheWxvYWRTaXplKGV2ZW50LGxvZ2dlcik7Y29uc3QgZGF0YXBsYW5lVXJsPXN0YXRlLmxpZmVjeWNsZS5hY3RpdmVEYXRhcGxhbmVVcmwudmFsdWU7Y29uc3QgdXJsPWdldERlbGl2ZXJ5VXJsKGRhdGFwbGFuZVVybCxldmVudC50eXBlKTsvLyBPdGhlciBkZWZhdWx0IGhlYWRlcnMgYXJlIGFkZGVkIGJ5IHRoZSBIdHRwQ2xpZW50XG4vLyBBdXRoIGhlYWRlciBpcyBhZGRlZCBkdXJpbmcgaW5pdGlhbGl6YXRpb25cbmNvbnN0IGhlYWRlcnM9ey8vIFRvIG1haW50YWluIGV2ZW50IG9yZGVyaW5nIHdoaWxlIHVzaW5nIHRoZSBIVFRQIEFQSSBhcyBwZXIgaXMgZG9jdW1lbnRhdGlvbixcbi8vIG1ha2Ugc3VyZSB0byBpbmNsdWRlIGFub255bW91c0lkIGFzIGEgaGVhZGVyXG5Bbm9ueW1vdXNJZDp0b0Jhc2U2NChldmVudC5hbm9ueW1vdXNJZCl9O2V2ZW50c1F1ZXVlLmFkZEl0ZW0oe3VybCxoZWFkZXJzLGV2ZW50fSk7fX19KTtcblxuLyoqXG4gKiBNYXAgcGx1Z2luIG5hbWVzIHRvIGRpcmVjdCBjb2RlIGltcG9ydHMgZnJvbSBwbHVnaW5zIHBhY2thZ2VcbiAqL2NvbnN0IGdldEJ1bmRsZWRCdWlsZFBsdWdpbkltcG9ydHM9KCk9Pih7QmVhY29uUXVldWUsQ3VzdG9tQ29uc2VudE1hbmFnZXIsRGV2aWNlTW9kZURlc3RpbmF0aW9ucyxEZXZpY2VNb2RlVHJhbnNmb3JtYXRpb24sRXh0ZXJuYWxBbm9ueW1vdXNJZCxHb29nbGVMaW5rZXIsSXViZW5kYUNvbnNlbnRNYW5hZ2VyLEtldGNoQ29uc2VudE1hbmFnZXIsTmF0aXZlRGVzdGluYXRpb25RdWV1ZSxPbmVUcnVzdENvbnNlbnRNYW5hZ2VyLFN0b3JhZ2VFbmNyeXB0aW9uLFN0b3JhZ2VFbmNyeXB0aW9uTGVnYWN5LFN0b3JhZ2VNaWdyYXRvcixYaHJRdWV1ZX0pO1xuXG4vKipcbiAqIE1hcCBvZiBtYW5kYXRvcnkgcGx1Z2luIG5hbWVzIGFuZCBkaXJlY3QgaW1wb3J0c1xuICovY29uc3QgZ2V0TWFuZGF0b3J5UGx1Z2luc01hcD0oKT0+KHt9KTsvKipcbiAqIE1hcCBvZiBvcHRpb25hbCBwbHVnaW4gbmFtZXMgYW5kIGRpcmVjdCBpbXBvcnRzIGZvciBsZWdhY3kgYnVpbGRzXG4gKi9jb25zdCBnZXRPcHRpb25hbFBsdWdpbnNNYXA9KCk9PntyZXR1cm4gZ2V0QnVuZGxlZEJ1aWxkUGx1Z2luSW1wb3J0cygpO307LyoqXG4gKiBNYXAgb2Ygb3B0aW9uYWwgcGx1Z2luIG5hbWVzIGFuZCBkeW5hbWljIGltcG9ydHMgZm9yIG1vZGVybiBidWlsZHNcbiAqL2NvbnN0IGdldFJlbW90ZVBsdWdpbnNNYXA9YWN0aXZlUGx1Z2luTmFtZXM9Pnt7cmV0dXJuIHt9O319O2NvbnN0IHBsdWdpbnNJbnZlbnRvcnk9ey4uLmdldE1hbmRhdG9yeVBsdWdpbnNNYXAoKSwuLi5nZXRPcHRpb25hbFBsdWdpbnNNYXAoKX07Y29uc3QgcmVtb3RlUGx1Z2luc0ludmVudG9yeT1hY3RpdmVQbHVnaW5OYW1lcz0+KHsuLi5nZXRSZW1vdGVQbHVnaW5zTWFwKCl9KTtcblxuLy8gVE9ETzogYWRkIHJldHJ5IG1lY2hhbmlzbSBmb3IgZ2V0dGluZyByZW1vdGUgcGx1Z2luc1xuLy8gVE9ETzogYWRkIHRpbWVvdXQgZXJyb3IgbWVjaGFuaXNtIGZvciBtYXJraW5nIHJlbW90ZSBwbHVnaW5zIHRoYXQgZmFpbGVkIHRvIGxvYWQgYXMgZmFpbGVkIGluIHN0YXRlXG5jbGFzcyBQbHVnaW5zTWFuYWdlcntjb25zdHJ1Y3RvcihlbmdpbmUsZXJyb3JIYW5kbGVyLGxvZ2dlcil7dGhpcy5lbmdpbmU9ZW5naW5lO3RoaXMuZXJyb3JIYW5kbGVyPWVycm9ySGFuZGxlcjt0aGlzLmxvZ2dlcj1sb2dnZXI7dGhpcy5vbkVycm9yPXRoaXMub25FcnJvci5iaW5kKHRoaXMpO30vKipcbiAgICogT3JjaGVzdHJhdGUgdGhlIHBsdWdpbiBsb2FkaW5nIGFuZCByZWdpc3RlcmluZ1xuICAgKi9pbml0KCl7c3RhdGUubGlmZWN5Y2xlLnN0YXR1cy52YWx1ZT0ncGx1Z2luc0xvYWRpbmcnOy8vIEV4cG9zZSBwbHVnaW5zQ0ROUGF0aCB0byBnbG9iYWwgb2JqZWN0LCBzbyBpdCBjYW4gYmUgdXNlZCBpbiB0aGUgcHJvbWlzZSB0aGF0IGRldGVybWluZXNcbnR
1oaXMuc2V0QWN0aXZlUGx1Z2lucygpO3RoaXMucmVnaXN0ZXJMb2NhbFBsdWdpbnMoKTt0aGlzLnJlZ2lzdGVyUmVtb3RlUGx1Z2lucygpO3RoaXMuYXR0YWNoRWZmZWN0cygpO30vKipcbiAgICogVXBkYXRlIHN0YXRlIGJhc2VkIG9uIHBsdWdpbiBsb2FkZWQgc3RhdHVzXG4gICAqLy8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjbGFzcy1tZXRob2RzLXVzZS10aGlzXG5hdHRhY2hFZmZlY3RzKCl7aigoKT0+e2NvbnN0IGlzQWxsUGx1Z2luc1JlYWR5PXN0YXRlLnBsdWdpbnMuYWN0aXZlUGx1Z2lucy52YWx1ZS5sZW5ndGg9PT0wfHxzdGF0ZS5wbHVnaW5zLmxvYWRlZFBsdWdpbnMudmFsdWUubGVuZ3RoK3N0YXRlLnBsdWdpbnMuZmFpbGVkUGx1Z2lucy52YWx1ZS5sZW5ndGg9PT1zdGF0ZS5wbHVnaW5zLnRvdGFsUGx1Z2luc1RvTG9hZC52YWx1ZTtpZihpc0FsbFBsdWdpbnNSZWFkeSl7bigoKT0+e3N0YXRlLnBsdWdpbnMucmVhZHkudmFsdWU9dHJ1ZTsvLyBUT0RPOiBkZWNpZGUgd2hhdCB0byBkbyBpZiBhIHBsdWdpbiBmYWlscyB0byBsb2FkIGZvciBhbnkgcmVhc29uLlxuLy8gIFNob3VsZCB3ZSBzdG9wIGhlcmUgb3Igc2hvdWxkIHdlIHByb2dyZXNzP1xuc3RhdGUubGlmZWN5Y2xlLnN0YXR1cy52YWx1ZT0ncGx1Z2luc1JlYWR5Jzt9KTt9fSk7fS8qKlxuICAgKiBEZXRlcm1pbmUgdGhlIGxpc3Qgb2YgcGx1Z2lucyB0aGF0IHNob3VsZCBiZSBsb2FkZWQgYmFzZWQgb24gc291cmNlQ29uZmlnICYgbG9hZCBvcHRpb25zXG4gICAqLy8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjbGFzcy1tZXRob2RzLXVzZS10aGlzXG5nZXRQbHVnaW5zVG9Mb2FkQmFzZWRPbkNvbmZpZygpey8vIFRoaXMgY29udGFpbnMgdGhlIGRlZmF1bHQgcGx1Z2lucyBpZiBsb2FkIG9wdGlvbiBoYXMgYmVlbiBvbWl0dGVkIGJ5IHVzZXJcbmxldCBwbHVnaW5zVG9Mb2FkRnJvbUNvbmZpZz1zdGF0ZS5wbHVnaW5zLnBsdWdpbnNUb0xvYWRGcm9tQ29uZmlnLnZhbHVlO2lmKCFwbHVnaW5zVG9Mb2FkRnJvbUNvbmZpZyl7cmV0dXJuIFtdO30vLyBGaWx0ZXIgZGVwcmVjYXRlZCBwbHVnaW5zXG5wbHVnaW5zVG9Mb2FkRnJvbUNvbmZpZz1wbHVnaW5zVG9Mb2FkRnJvbUNvbmZpZy5maWx0ZXIocGx1Z2luTmFtZT0+e2lmKGRlcHJlY2F0ZWRQbHVnaW5zTGlzdC5pbmNsdWRlcyhwbHVnaW5OYW1lKSl7dGhpcy5sb2dnZXIud2FybihERVBSRUNBVEVEX1BMVUdJTl9XQVJOSU5HKFBMVUdJTlNfTUFOQUdFUixwbHVnaW5OYW1lKSk7cmV0dXJuIGZhbHNlO31yZXR1cm4gdHJ1ZTt9KTtjb25zdCBwbHVnaW5Hcm91cHNUb1Byb2Nlc3M9W3tjb25maWd1cmF0aW9uU3RhdHVzOigpPT5pc0RlZmluZWQoc3RhdGUuZGF0YVBsYW5lRXZlbnRzLmV2ZW50c1F1ZXVlUGx1Z2luTmFtZS52YWx1ZSksY29uZmlndXJhdGlvblN0YXR1c1N0cjonRGF0YSBwbGFuZSBldmVudHMgZGVsaXZlcnkgaXMgZW5hYmxlZCcsYWN0aXZlUGx1Z2luTmFtZTpzdGF0ZS5kYXRhUGxhbmVFdmVudHMuZXZlbnRzUXVldWVQbHVnaW5OYW1lLnZhbHVlLHN1cHBvcnRlZFBsdWdpbnM6T2JqZWN0LnZhbHVlcyhEYXRhUGxhbmVFdmVudHNUcmFuc3BvcnRUb1BsdWdpbk5hbWVNYXApLHNob3VsZEFkZE1pc3NpbmdQbHVnaW5zOnRydWV9LHtjb25maWd1cmF0aW9uU3RhdHVzOigpPT5nZXROb25DbG91ZERlc3RpbmF0aW9ucyhzdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuY29uZmlndXJlZERlc3RpbmF0aW9ucy52YWx1ZSkubGVuZ3RoPjAsY29uZmlndXJhdGlvblN0YXR1c1N0cjonRGV2aWNlIG1vZGUgZGVzdGluYXRpb25zIGFyZSBjb25uZWN0ZWQgdG8gdGhlIHNvdXJjZScsc3VwcG9ydGVkUGx1Z2luczpbJ0RldmljZU1vZGVEZXN0aW5hdGlvbnMnLCdOYXRpdmVEZXN0aW5hdGlvblF1ZXVlJ119LHtjb25maWd1cmF0aW9uU3RhdHVzOigpPT5nZXROb25DbG91ZERlc3RpbmF0aW9ucyhzdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuY29uZmlndXJlZERlc3RpbmF0aW9ucy52YWx1ZSkuc29tZShkZXN0aW5
1hdGlvbj0+ZGVzdGluYXRpb24uc2hvdWxkQXBwbHlEZXZpY2VNb2RlVHJhbnNmb3JtYXRpb24pLGNvbmZpZ3VyYXRpb25TdGF0dXNTdHI6J0RldmljZSBtb2RlIHRyYW5zZm9ybWF0aW9ucyBhcmUgZW5hYmxlZCBmb3IgYXQgbGVhc3Qgb25lIGRlc3RpbmF0aW9uJyxzdXBwb3J0ZWRQbHVnaW5zOlsnRGV2aWNlTW9kZVRyYW5zZm9ybWF0aW9uJ119LHtjb25maWd1cmF0aW9uU3RhdHVzOigpPT5pc0RlZmluZWQoc3RhdGUuY29uc2VudHMuYWN0aXZlQ29uc2VudE1hbmFnZXJQbHVnaW5OYW1lLnZhbHVlKSxjb25maWd1cmF0aW9uU3RhdHVzU3RyOidDb25zZW50IG1hbmFnZW1lbnQgaXMgZW5hYmxlZCcsYWN0aXZlUGx1Z2luTmFtZTpzdGF0ZS5jb25zZW50cy5hY3RpdmVDb25zZW50TWFuYWdlclBsdWdpbk5hbWUudmFsdWUsc3VwcG9ydGVkUGx1Z2luczpPYmplY3QudmFsdWVzKENvbnNlbnRNYW5hZ2Vyc1RvUGx1Z2luTmFtZU1hcCl9LHtjb25maWd1cmF0aW9uU3RhdHVzOigpPT5pc0RlZmluZWQoc3RhdGUuc3RvcmFnZS5lbmNyeXB0aW9uUGx1Z2luTmFtZS52YWx1ZSksY29uZmlndXJhdGlvblN0YXR1c1N0cjonU3RvcmFnZSBlbmNyeXB0aW9uIGlzIGVuYWJsZWQnLGFjdGl2ZVBsdWdpbk5hbWU6c3RhdGUuc3RvcmFnZS5lbmNyeXB0aW9uUGx1Z2luTmFtZS52YWx1ZSxzdXBwb3J0ZWRQbHVnaW5zOk9iamVjdC52YWx1ZXMoU3RvcmFnZUVuY3J5cHRpb25WZXJzaW9uc1RvUGx1Z2luTmFtZU1hcCl9LHtjb25maWd1cmF0aW9uU3RhdHVzOigpPT5zdGF0ZS5zdG9yYWdlLm1pZ3JhdGUudmFsdWUsY29uZmlndXJhdGlvblN0YXR1c1N0cjonU3RvcmFnZSBtaWdyYXRpb24gaXMgZW5hYmxlZCcsc3VwcG9ydGVkUGx1Z2luczpbJ1N0b3JhZ2VNaWdyYXRvciddfV07Y29uc3QgYWRkTWlzc2luZ1BsdWdpbnM9ZmFsc2U7cGx1Z2luR3JvdXBzVG9Qcm9jZXNzLmZvckVhY2goZ3JvdXA9PntpZihncm91cC5jb25maWd1cmF0aW9uU3RhdHVzKCkpe3BsdWdpbnNUb0xvYWRGcm9tQ29uZmlnPXBsdWdpbnNUb0xvYWRGcm9tQ29uZmlnLmZpbHRlcihncm91cC5hY3RpdmVQbHVnaW5OYW1lP3BsdWdpbk5hbWU9PiEocGx1Z2luTmFtZSE9PWdyb3VwLmFjdGl2ZVBsdWdpbk5hbWUmJmdyb3VwLnN1cHBvcnRlZFBsdWdpbnMuaW5jbHVkZXMocGx1Z2luTmFtZSkpOnBsdWdpbk5hbWU9PmlzRGVmaW5lZChwbHVnaW5OYW1lKS8vIHBhc3MgdGhyb3VnaFxuKTt0aGlzLmFkZE1pc3NpbmdQbHVnaW5zKGdyb3VwLGFkZE1pc3NpbmdQbHVnaW5zLHBsdWdpbnNUb0xvYWRGcm9tQ29uZmlnKTt9ZWxzZSB7cGx1Z2luc1RvTG9hZEZyb21Db25maWc9cGx1Z2luc1RvTG9hZEZyb21Db25maWcuZmlsdGVyKGdyb3VwLmJhc2VQbHVnaW5zIT09dW5kZWZpbmVkP3BsdWdpbk5hbWU9PiEoZ3JvdXAuYmFzZVBsdWdpbnMuaW5jbHVkZXMocGx1Z2luTmFtZSl8fGdyb3VwLnN1cHBvcnRlZFBsdWdpbnMuaW5jbHVkZXMocGx1Z2luTmFtZSkpOnBsdWdpbk5hbWU9PiFncm91cC5zdXBwb3J0ZWRQbHVnaW5zLmluY2x1ZGVzKHBsdWdpbk5hbWUpKTt9fSk7cmV0dXJuIFsuLi5PYmplY3Qua2V5cyhnZXRNYW5kYXRvcnlQbHVnaW5zTWFwKCkpLC4uLnBsdWdpbnNUb0xvYWRGcm9tQ29uZmlnXTt9YWRkTWlzc2luZ1BsdWdpbnMoZ3JvdXAsYWRkTWlzc2luZ1BsdWdpbnMscGx1Z2luc1RvTG9hZEZyb21Db25maWcpe2NvbnN0IHNob3VsZEFkZE1pc3NpbmdQbHVnaW5zPWdyb3VwLnNob3VsZEFkZE1pc3NpbmdQbHVnaW5zfHxhZGRNaXNzaW5nUGx1Z2lucztsZXQgcGx1Z2luc1RvQ29uZmlndXJlO2lmKGdyb3VwLmFjdGl2ZVBsdWdpbk5hbWUpe3BsdWdpbnNUb0NvbmZpZ3VyZT1bLi4uKGdyb3VwLmJhc2VQbHVnaW5zfHxbXSksZ3JvdXAuYWN0aXZlUGx1Z2luTmFtZV07fWVsc2Uge3BsdWdpbnNUb0NvbmZpZ3VyZT1bLi4uZ3JvdXAuc3VwcG9ydGVkUGx1Z2luc107fWNvbnN0IG1pc3NpbmdQbHVnaW5zPXBsdWdpbnNUb0NvbmZpZ3VyZS5maWx0ZXIocGx1Z2luTmFtZT0+IXBsdWdpbnNUb0xvYWRGcm9tQ29uZmlnLmluY2x1ZGVzKHBsdWdpbk5hbWUpKTtpZihtaXNzaW5nUGx1Z2lucy5sZW5ndGg+MCl7aWYoc2hvdWxkQWRkTWlzc2luZ1BsdWdpbnMpe3BsdWdpbnNUb0xvYWRGcm9tQ29uZmlnLnB1c2goLi4ubWlzc2luZ1BsdWdpbnMpO310aGlzLmxvZ2dlci53YXJuKGdlbmVyYXRlTWlzY29uZmlndXJlZFBsdWdpbnNXYXJuaW5nKFBMVUdJTlNfTUFOQUdFUixncm91cC5jb25maWd1cmF0aW9uU3RhdHVzU3RyLG1pc3NpbmdQbHVnaW5zLHNob3VsZEFkZE1pc3NpbmdQbHVnaW5zKSk7fX0vKipcbiAgICogRGV0ZXJtaW5lIHRoZSBsaXN0IG9mIHBsdWdpbnMgdGhhdCBzaG91bGQgYmUgYWN0aXZhdGVkXG4gICAqL3NldEFjdGl2ZVBsdWdpbnMoKXtjb25zdCBwbHVnaW5zVG9Mb2FkPXRoaXMuZ2V0UGx1Z2luc1RvTG9hZEJhc2VkT25Db25maWcoKTsvLyBNZXJnaW5nIGF2YWlsYWJsZSBtYW5kYXRvcnkgYW5kIG9wdGlvbmFsIHBsdWdpbiBuYW1lIGxpc3RcbmNvbnN0IGF2YWlsYWJsZVBsdWdpbnM9Wy4uLk9iamVjdC5rZXlzKHBsdWdpbnNJbnZlbnRvcnkpLC4uLnBsdWdpbk5hbWVzTGlzdF07Y29uc3QgYWN0aXZlUGx1Z2lucz1bXTtjb25zdCBmYWlsZWRQbHVnaW5zPVtdO3BsdWdpbnNUb0xvYWQuZm9yRWFjaChwbHVnaW5OYW1lPT57aWYoYXZhaWxhYmxlUGx1Z2lucy5pbmNsdWRlcyhwbHVnaW5OYW1lKSl7YWN0aXZlUGx1Z2lucy5wdXNoKHBsdWdpbk5hbWUpO31lbHNlIHtmYWlsZWRQbHVnaW5zLnB1c2gocGx1Z2luTmFtZSk7fX0pO2lmKGZhaWxlZFBsdWdpbnMubGVuZ3RoPjApe3RoaXMubG9nZ2VyLndhcm4oVU5LTk9XTl9QTFVHSU5TX1dBUk5JTkcoUExVR0lOU19NQU5BR0VSLGZhaWxlZFBsdWdpbnMpKTt9bigoKT0+e3N0YXRlLnBsdWdpbnMudG90YWxQbHVnaW5zVG9Mb2FkLnZhbHVlPXBsdWdpbnNUb0xvYWQubGVuZ3RoO3N0YXRlLnBsdWdpbnMuYWN0aXZlUGx1Z2lucy52YWx1ZT1hY3RpdmVQbHVnaW5zO3N0YXRlLnBsdWdpbnMuZmFpbGVkUGx1Z2lucy52YWx1ZT1mYWlsZWRQbHVnaW5zO30pO30vKipcbiAgICogUmVnaXN0ZXIgcGx1Z2lucyB0aGF0IGFyZSBkaXJlY3QgaW1wb3J0cyB0byBQbHVnaW5FbmdpbmVcbiAgICovcmVnaXN0ZXJMb2NhbFBsdWdpbnMoKXtjb25zdCB1bmF2YWlsYWJsZVBsdWdpbnM9W107T2JqZWN0LmVud
1HJpZXMocGx1Z2luc0ludmVudG9yeSkuZm9yRWFjaCgoW3BsdWdpbk5hbWUsbG9jYWxQbHVnaW5dKT0+e2lmKHN0YXRlLnBsdWdpbnMuYWN0aXZlUGx1Z2lucy52YWx1ZS5pbmNsdWRlcyhwbHVnaW5OYW1lKSl7aWYoaXNGdW5jdGlvbihsb2NhbFBsdWdpbikpe3RoaXMucmVnaXN0ZXIoW2xvY2FsUGx1Z2luKCldKTt9ZWxzZSB7dW5hdmFpbGFibGVQbHVnaW5zLnB1c2gocGx1Z2luTmFtZSk7fX19KTtpZih1bmF2YWlsYWJsZVBsdWdpbnMubGVuZ3RoPjApe3N0YXRlLnBsdWdpbnMuZmFpbGVkUGx1Z2lucy52YWx1ZT1bLi4uc3RhdGUucGx1Z2lucy5mYWlsZWRQbHVnaW5zLnZhbHVlLC4uLnVuYXZhaWxhYmxlUGx1Z2luc107dGhpcy5sb2dnZXIuZXJyb3IoVU5BVkFJTEFCTEVfUExVR0lOU19FUlJPUihQTFVHSU5TX01BTkFHRVIsdW5hdmFpbGFibGVQbHVnaW5zKSk7fX0vKipcbiAgICogUmVnaXN0ZXIgcGx1Z2lucyB0aGF0IGFyZSBkeW5hbWljIGltcG9ydHMgdG8gUGx1Z2luRW5naW5lXG4gICAqL3JlZ2lzdGVyUmVtb3RlUGx1Z2lucygpe2NvbnN0IHJlbW90ZVBsdWdpbnNMaXN0PXJlbW90ZVBsdWdpbnNJbnZlbnRvcnkoc3RhdGUucGx1Z2lucy5hY3RpdmVQbHVnaW5zLnZhbHVlKTtQcm9taXNlLmFsbChPYmplY3Qua2V5cyhyZW1vdGVQbHVnaW5zTGlzdCkubWFwKGFzeW5jIHJlbW90ZVBsdWdpbktleT0+e2F3YWl0IHJlbW90ZVBsdWdpbnNMaXN0W3JlbW90ZVBsdWdpbktleV0oKS50aGVuKHJlbW90ZVBsdWdpbk1vZHVsZT0+dGhpcy5yZWdpc3RlcihbcmVtb3RlUGx1Z2luTW9kdWxlLmRlZmF1bHQoKV0pKS5jYXRjaChlcnI9PnsvLyBUT0RPOiBhZGQgcmV0cnkgaGVyZSBpZiBkeW5hbWljIGltcG9ydCBmYWlsc1xuc3RhdGUucGx1Z2lucy5mYWlsZWRQbHVnaW5zLnZhbHVlPVsuLi5zdGF0ZS5wbHVnaW5zLmZhaWxlZFBsdWdpbnMudmFsdWUscmVtb3RlUGx1Z2luS2V5XTt0aGlzLm9uRXJyb3IoZXJyLGBGYWlsZWQgdG8gbG9hZCBwbHVnaW4gXCIke3JlbW90ZVBsdWdpbktleX1cImAsZXJyKTt9KTt9KSkuY2F0Y2goZXJyPT57dGhpcy5vbkVycm9yKGVycik7fSk
17fS8qKlxuICAgKiBFeHRlbnNpb24gcG9pbnQgaW52b2tlIHRoYXQgYWxsb3dzIG11bHRpcGxlIHBsdWdpbnMgdG8gYmUgcmVnaXN0ZXJlZCB0byBpdCB3aXRoIGVycm9yIGhhbmRsaW5nXG4gICAqL2ludm9rZU11bHRpcGxlKGV4dFBvaW50LC4uLmFyZ3Mpe3RyeXtyZXR1cm4gdGhpcy5lbmdpbmUuaW52b2tlTXVsdGlwbGUoZXh0UG9pbnQsLi4uYXJncyk7fWNhdGNoKGUpe3RoaXMub25FcnJvcihlLGV4dFBvaW50KTtyZXR1cm4gW107fX0vKipcbiAgICogRXh0ZW5zaW9uIHBvaW50IGludm9rZSB0aGF0IGFsbG93cyBhIHNpbmdsZSBwbHVnaW4gdG8gYmUgcmVnaXN0ZXJlZCB0byBpdCB3aXRoIGVycm9yIGhhbmRsaW5nXG4gICAqL2ludm9rZVNpbmdsZShleHRQb2ludCwuLi5hcmdzKXt0cnl7cmV0dXJuIHRoaXMuZW5naW5lLmludm9rZVNpbmdsZShleHRQb2ludCwuLi5hcmdzKTt9Y2F0Y2goZSl7dGhpcy5vbkVycm9yKGUsZXh0UG9pbnQpO3JldHVybiBudWxsO319LyoqXG4gICAqIFBsdWdpbiBlbmdpbmUgcmVnaXN0ZXIgd2l0aCBlcnJvciBoYW5kbGluZ1xuICAgKi9yZWdpc3RlcihwbHVnaW5zKXtwbHVnaW5zLmZvckVhY2gocGx1Z2luPT57dHJ5e3RoaXMuZW5naW5lLnJlZ2lzdGVyKHBsdWdpbixzdGF0ZSk7fWNhdGNoKGUpe3N0YXRlLnBsdWdpbnMuZmFpbGVkUGx1Z2lucy52YWx1ZT1bLi4uc3RhdGUucGx1Z2lucy5mYWlsZWRQbHVnaW5zLnZhbHVlLHBsdWdpbi5uYW1lXTt0aGlzLm9uRXJyb3IoZSxgRmFpbGVkIHRvIHJlZ2lzdGVyIHBsdWdpbiBcIiR7cGx1Z2luLm5hbWV9XCJgKTt9fSk7fS8vIFRPRE86IEltcGxlbWVudCByZXNldCBBUEkgaW5zdGVhZFxudW5yZWdpc3RlckxvY2FsUGx1Z2lucygpe09iamVjdC5rZXlzKHBsdWdpbnNJbnZlbnRvcnkpLmZvckVhY2gocGx1Z2luS2V5PT57
1dHJ5e3RoaXMuZW5naW5lLnVucmVnaXN0ZXIocGx1Z2luS2V5KTt9Y2F0Y2goZSl7dGhpcy5vbkVycm9yKGUsYEZhaWxlZCB0byB1bnJlZ2lzdGVyIHBsdWdpbiBcIiR7cGx1Z2luS2V5fVwiYCk7fX0pO30vKipcbiAgICogSGFuZGxlIGVycm9yc1xuICAgKi9vbkVycm9yKGVycm9yLGN1c3RvbU1lc3NhZ2UsZ3JvdXBpbmdIYXNoKXt0aGlzLmVycm9ySGFuZGxlci5vbkVycm9yKHtlcnJvcixjb250ZXh0OlBMVUdJTlNfTUFOQUdFUixjdXN0b21NZXNzYWdlLGdyb3VwaW5nSGFzaH0pO319XG5cbmNvbnN0IFNUT1JBR0VfVEVTVF9UT1BfTEVWRUxfRE9NQUlOPSdfX3RsZF9fJztjb25zdCBDTElFTlRfREFUQV9TVE9SRV9DT09LSUU9J2NsaWVudERhdGFJbkNvb2tpZSc7Y29uc3QgQ0xJRU5UX0RBVEFfU1RPUkVfTFM9J2NsaWVudERhdGFJbkxvY2FsU3RvcmFnZSc7Y29uc3QgQ0xJRU5UX0RBVEFfU1RPUkVfTUVNT1JZPSdjbGllbnREYXRhSW5NZW1vcnknO2NvbnN0IENMSUVOVF9EQVRBX1NUT1JFX1NFU1NJT049J2NsaWVudERhdGFJblNlc3Npb25TdG9yYWdlJztjb25zdCBVU0VSX1NFU1NJT05fS0VZUz1bJ3VzZXJJZCcsJ3VzZXJUcmFpdHMnLCdhbm9ueW1vdXNJZCcsJ2dyb3VwSWQnLCdncm91cFRyYWl0cycsJ2luaXRpYWxSZWZlcnJlcicsJ2luaXRpYWxSZWZlcnJpbmdEb21haW4nLCdzZXNzaW9uSW5mbycsJ2F1dGhUb2tlbiddO1xuXG5jb25zdCBzdG9yYWdlQ2xpZW50RGF0YVN0b3JlTmFtZU1hcD17W0NPT0tJRV9TVE9SQUdFXTpDTElFTlRfREFUQV9TVE9SRV9DT09LSUUsW0xPQ0FMX1NUT1JBR0VdOkNMSUVOVF9EQVRBX1NUT1JFX0xTLFtNRU1PUllfU1RPUkFHRV06Q0xJRU5UX0RBVEFfU1RPUkVfTUVNT1JZLFtTRVNTSU9OX1NUT1JBR0VdOkNMSUVOVF9EQVRBX1NUT1JFX1NFU1NJT059O1xuXG5jb25zdCBsZWdhY3lHZXRIb3N0bmFtZT1ocmVmPT57Y29uc3QgbD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7bC5ocmVmPWhyZWY7cmV0dXJuIGwuaG9zdG5hbWU7fTsvKipcbiAqIExldmVscyByZXR1cm5zIGFsbCBsZXZlbHMgb2YgdGhlIGdpdmVuIHVybFxuICpcbiAqIFRoZSBtZXRob2QgcmV0dXJucyBhbiBlbXB0eSBhcnJheSB3aGVuIHRoZSBob3N0bmFtZSBpcyBhbiBpcC5cbiAqL2NvbnN0IGxldmVsc0Z1bmM9dXJsPT57Ly8gVGhpcyBpcyBjYWxsZWQgYmVmb3JlIHRoZSBwb2x5ZmlsbHMgbG9hZCB0aHVzIG5ldyBVUkwgY2Fubm90IGJlIHVzZWRcbmNvbnN0IGhvc3Q9dHlwZW9mIGdsb2JhbFRoaXMuVVJMIT09J2Z1bmN0aW9uJz9sZWdhY3lHZXRIb3N0bmFtZSh1cmwpOm5ldyBVUkwodXJsKS5ob3N0bmFtZTtjb25zdCBwYXJ0cz1ob3N0Py5zcGxpdCgnLicpPz9bXTtjb25zdCBsYXN0PXBhcnRzW3BhcnRzLmxlbmd0aC0xXTtjb25zdCBsZXZlbHM9W107Ly8gSXAgYWRkcmVzcy5cbmlmKHBhcnRzLmxlbmd0aD09PTQmJmxhc3QmJmxhc3Q9PT1wYXJzZUludChsYXN0LDEwKS50b1N0cmluZygpKXtyZXR1cm4gbGV2ZWxzO30vLyBMb2NhbGhvc3QuXG5pZihwYXJ0cy5sZW5ndGg8PTEpey8vIEZpeCB0byBzdXBwb3J0IGxvY2FsaG9zdFxuaWYocGFydHNbMF0mJnBhcnRzWzBdLmluZGV4T2YoJ2xvY2FsaG9zdCcpIT09LTEpe3JldHVybiBbJ2xvY2FsaG9zdCddO31yZXR1cm4gbGV2ZWxzO30vLyBDcmVhdGUgbGV2ZWxzLlxuZm9yKGxldCBpPXBhcnRzLmxlbmd0aC0yO2k+PTA7aS09MSl7bGV2ZWxzLnB1c2gocGFydHMuc2xpY2UoaSkuam9pbignLicpKTt9cmV0dXJuIGxldmVsczt9Oy8qKlxuICogR2V0IHRoZSB0b3AgZG9tYWluLlxuICpcbiAqIFRoZSBmdW5jdGlvbiBjb25zdHJ1Y3RzIHRoZSBsZXZlbHMgb2YgZG9tYWluIGFuZCBhdHRlbXB0cyB0byBzZXQgYSBnbG9iYWxcbiAqIGNvb2tpZSBvbiBlYWNoIG9uZSB3aGVuIGl0IHN1Y2NlZWRzIGl0IHJldHVybnMgdGhlIHRvcCBsZXZlbCBkb21haW4uXG4gKlxuICogVGhlIG1ldGhvZCByZXR1cm5zIGFuIGVtcHR5IHN0cmluZyB3aGVuIHRoZSBob3N0bmFtZSBpcyBhbiBpcC5cbiAqL2NvbnN0IGRvbWFpbj11cmw9Pntjb25zdCBsZXZlbHM9bGV2ZWxzRnVuYyh1cmwpOy8vIExvb2t1cCB0aGUgcmVhbCB0b3AgbGV2ZWwgb25lLlxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHVuaWNvcm4vbm8tZm9yLWxvb3BcbmZvcihsZXQgaT0wO2k8bGV2ZWxzLmxlbmd0aDtpKz0xKXtjb25zdCBkb21haW49bGV2ZWxzW2ldO2NvbnN0IGNuYW1lPVNUT1JBR0VfVEVTVF9UT1BfTEVWRUxfRE9NQUlOO2NvbnN0IG9wdHM9e2RvbWFpbjpgJHtkb21haW4uaW5kZXhPZignbG9jYWxob3N0JykhPT0tMT8nJzonLid9JHtkb21haW59YH07dHJ5ey8vIFNldCBjb29raWUgb24gZG9tYWluXG5jb29raWUoY25hbWUsMSxvcHRzKTsvLyBJZiBzdWNjZXNzZnVsXG5pZihjb29raWUoY25hbWUpKXsvLyBSZW1vdmUgY29va2llIGZyb20gZG9tYWluXG5jb29raWUoY25hbWUsbnVsbCxvcHRzKTtyZXR1cm4gZG9tYWluO319Y2F0Y2h7Ly8gU2lsZW50bHkgY29udGludWUgdG8gbmV4dCBkb21haW4gbGV2ZWwgaWYgY29va2llIGFjY2VzcyBpcyByZXN0cmljdGVkIG9yIHNldHRpbmcgZmFpbHNcbi8vIEJlc3QtZWZmb3J0IGNsZWFudXAgdG8gYXZvaWQgbGVha2luZyB0aGUgdGVzdCBjb29raWVcbnRyeXtjb29raWUoY25hbWUsbnVsbCxvcHRzKTt9Y2F0Y2h7Ly8gSWdub3JlIGlmIHdlIGFyZSB1bmFibGUgdG8gZGVsZXRlIHRoZSBjb29raWVcbn19fXJldHVybiAnJzt9O1xuXG5jb25zdCBnZXREZWZhdWx0Q29va2llT3B0aW9ucz0oKT0+e2NvbnN0IHRvcERvbWFpbj1gLiR7ZG9tYWluKGdsb2JhbFRoaXMubG9jYXRpb24uaHJlZil9YDtyZXR1cm4ge21heGFnZTpERUZBVUxUX0NPT0tJRV9NQVhfQUdFX01TLHBhdGg6Jy8nLGRvbWFpbjohdG9wRG9tYWlufHx0b3BEb21haW49PT0nLic/dW5kZWZpbmVkOnRvcERvbWFpbixzYW1lc2l0ZTonTGF4JyxlbmFibGVkOnRydWV9O307Y29uc3QgZ2V0RGVmYXVsdExvY2FsU3RvcmFnZU9wdGlvbnM9KCk9Pih7ZW5hYmxlZDp0cnVlfSk7Y29uc3QgZ2V0RGVmYXVsdFNlc3Npb25TdG9yYWdlT3B0aW9ucz0oKT0+KHtlbmFibGVkOnRydWV9KTtjb25zdCBnZXREZWZhdWx0SW5NZW1vcnlTdG9yYWdlT3B0aW9ucz0oKT0+KHtlbmFibGVkOnRydWV9KTtcblxuLyoqXG4gKiBBIHN0b3JhZ2UgdXRpbGl0eSB0byByZXRhaW4gdmFsdWVzIGluIG1lbW9yeSB2aWEgU3RvcmFnZSBpbnRlcmZhY2VcbiAqL2NsYXNzIEluTWVtb3J5U3RvcmFnZXtpc0VuYWJsZWQ9dHJ1ZTtsZW5ndGg9MDtkYXRhPXt9O2NvbnN0cnVjdG9yKGxvZ2dlcil7dGhpcy5vcHRpb25zPWdldERlZmF1bHRJbk1lbW9yeVN0b3JhZ2VPcHRpb25zKCk7dGhpcy5sb2dnZXI9bG9nZ2VyO31jb25maWd1cmUob3B0aW9ucyl7dGhpcy5vcHRpb25zPW1lcmdlRGVlcFJpZ2h0KHRoaXMub3B0aW9ucyxvcHRpb25zPz97fSk7dGhpcy5pc0VuYWJsZWQ9Qm9vbGVhbih0aGlzLm9wdGlvbnMuZW5hYmxlZCk7cmV0dXJuIHRoaXMub3B0aW9uczt9c2V0SXRlbShrZXksdmFsdWUpe3RoaXMuZGF0YVtrZXldPXZhbHVlO3RoaXMubGVuZ3RoPU9iamVjdC5rZXlzKHRoaXMuZGF0YSkubGVuZ3RoO3JldHVybiB2YWx1ZTt9Z2V0SXRlbShrZXkpe2lmKGtleSBpbiB0aGlzLmRhdGEpe3JldHVybiB0aGlzLmRhdGFba2V5XTt9cmV0dXJuIG51bGw7fXJlbW92ZUl0ZW0oa2V5KXtpZihrZXkgaW4gdGhpcy5kYXRhKXtkZWxldGUgdGhpcy5kYXRhW2tleV07fXRoaXMubGVuZ3RoPU9iamVjdC5rZXlzKHRoaXMuZGF0YSkubGVuZ3RoO3JldHVybiBudWxsO31jbGVhcigpe3RoaXMuZGF0YT17fTt0aGlzLmxlbmd0aD0wO31rZXkoaW5kZXgpe2NvbnN0IGN1cktleXM9dGhpcy5rZXlzKCk7cmV0dXJuIGN1cktleXNbaW5kZXhdPz9udWxsO31rZXlzKCl7cmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuZGF0YSk7fX1jb25zdCBkZWZhdWx0SW5NZW1vcnlTdG9yYWdlPW5ldyBJbk1lbW9yeVN0b3JhZ2UoZGVmYXVsdExvZ2dlcik7XG5cbmZ1bmN0aW9uIGdldERlZmF1bHRFeHBvcnRGcm9tQ2pzICh4KSB7XG5cdHJldHVybi
1B4ICYmIHguX19lc01vZHVsZSAmJiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoeCwgJ2RlZmF1bHQnKSA/IHhbJ2RlZmF1bHQnXSA6IHg7XG59XG5cbnZhciBzdG9yZSQyID0ge2V4cG9ydHM6IHt9fTtcblxudmFyIHN0b3JlJDE9c3RvcmUkMi5leHBvcnRzO3ZhciBoYXNSZXF1aXJlZFN0b3JlO2Z1bmN0aW9uIHJlcXVpcmVTdG9yZSgpe2lmKGhhc1JlcXVpcmVkU3RvcmUpcmV0dXJuIHN0b3JlJDIuZXhwb3J0cztoYXNSZXF1aXJlZFN0b3JlPTE7KGZ1bmN0aW9uKG1vZHVsZSxleHBvcnRzKXsoZnVuY3Rpb24oZ2xvYmFsLGZhY3Rvcnkpe21vZHVsZS5leHBvcnRzPWZhY3RvcnkoKTt9KShzdG9yZSQxLGZ1bmN0aW9uKCl7ZnVuY3Rpb24gaXNKU09OKG9iail7b2JqPUpTT04uc3RyaW5naWZ5KG9iaik7aWYoIS9eXFx7W1xcc1xcU10qXFx9JC8udGVzdChvYmopKXtyZXR1cm4gZmFsc2U7fXJldHVybiB0cnVlO31mdW5jdGlvbiBzdHJpbmdpZnkodmFsKXtyZXR1cm4gdmFsPT09dW5kZWZpbmVkfHx0eXBlb2YgdmFsPT09XCJmdW5jdGlvblwiP3ZhbCsnJzpKU09OLnN0cmluZ2lmeSh2YWwpO31mdW5jdGlvbiBkZXNlcmlhbGl6ZSh2YWx1ZSl7aWYodHlwZW9mIHZhbHVlIT09J3N0cmluZycpe3JldHVybiB1bmRlZmluZWQ7fXRyeXtyZXR1cm4gSlNPTi5wYXJzZSh2YWx1ZSk7fWNhdGNoKGUpe3JldHVybiB2YWx1ZTt9fWZ1bmN0aW9uIGlzRnVuY3Rpb24odmFsdWUpe3JldHVybiB7fS50b1N0cmluZy5jYWxsKHZhbHVlKT09PVwiW29iamVjdCBGdW5jdGlvbl1cIjt9ZnVuY3Rpb24gaXNBcnJheSh2YWx1ZSl7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSk9PT1cIltvYmplY3QgQXJyYXldXCI7fS8vIGh0dHBzOi8vZ2l0aHViLmNvbS9qYXl3Y2psb3ZlL3N0b3JlLmpzL3B1bGwvOFxuLy8gRXJyb3I6IFF1b3RhRXhjZWVkZWRFcnJvclxuZnVuY3Rpb24gZGVhbEluY29nbml0byhzdG9yYWdlKXt2YXIgX0tFWT0nX0lzX0luY29nbml0JyxfVkFMVUU9J3llcyc7dHJ5ey8vIE5PVEU6IHNldCBkZWZhdWx0IHN0b3JhZ2Ugd2hlbiBub3QgcGFzc2VkIGluXG5pZighc3RvcmFnZSl7c3RvcmFnZT13aW5kb3cubG9jYWxTdG9yYWdlO31zdG9yYWdlLnNldEl0ZW0oX0tFWSxfVkFMVUUpO3N0b3JhZ2UucmVtb3ZlSXRlbShfS0VZKTt9Y2F0Y2goZSl7dmFyIGluTWVtb3J5U3RvcmFnZT17fTtpbk1lbW9yeVN0b3JhZ2UuX2RhdGE9e307aW5NZW1vcnlTdG9yYWdlLnNldEl0ZW09ZnVuY3Rpb24oaWQsdmFsKXtyZXR1cm4gaW5NZW1vcnlTdG9yYWdlLl9kYXRhW2lkXT1TdHJpbmcodmFsKTt9O2luTWVtb3J5U3RvcmFnZS5nZXRJdGVtPWZ1bmN0aW9uKGlkKXtyZXR1cm4gaW5NZW1vcnlTdG9yYWdlLl9kYXRhLmhhc093blByb3BlcnR5KGlkKT9pbk1lbW9yeVN0b3JhZ2UuX2RhdGFbaWRdOnVuZGVmaW5lZDt9O2luTWVtb3J5U3RvcmFnZS5yZW1vdmVJdGVtPWZ1bmN0aW9uKGlkKXtyZXR1cm4gZGVsZXRlIGluTWVtb3J5U3RvcmFnZS5fZGF0YVtpZF07fTtpbk1lbW9yeVN0b3JhZ2UuY2xlYXI9ZnVuY3Rpb24oKXtyZXR1cm4gaW5NZW1vcnlTdG9yYWdlLl9kYXRhPXt9O307c3RvcmFnZT1pbk1lbW9yeVN0b3JhZ2U7fWZpbmFsbHl7aWYoc3RvcmFnZS5nZXRJdGVtKF9LRVkpPT09X1ZBTFVFKXN0b3JhZ2UucmVtb3ZlSXRlbShfS0VZKTt9cmV0dXJuIHN0b3JhZ2U7fS8vIGRlYWwgUXVvdGFFeGNlZWRlZEVycm9yIGlmIHVzZXIgdXNlIGluY29nbml0byBtb2RlIGluIGJyb3dzZXJcbnZhciBzdG9yYWdlPWRlYWxJbmNvZ25pdG8oKTtmdW5jdGlvbiBTdG9yZSgpe2lmKCEodGhpcyBpbnN0YW5jZW9mIFN0b3JlKSl7cmV0dXJuIG5ldyBTdG9yZSgpO319U3RvcmUucHJvdG90eXBlPXtzZXQ6ZnVuY3Rpb24gc2V0KGtleSx2YWwpe2lmKGtleSYmIWlzSlNPTihrZXkpKXtzdG9yYWdlLnNldEl0ZW0oa2V5LHN0cmluZ2lmeSh2YWwpKTt9ZWxzZSBpZihpc0pTT04oa2V5KSl7Zm9yKHZhciBhIGluIGtleSl0aGlzLnNldChhLGtleVthXSk7fXJldHVybiB0aGlzO30sZ2V0OmZ1bmN0aW9uIGdldChrZXkpey8vIFJldHVybiBhbGwgZW50cmllcyBpZiBubyBrZXlcbmlmKGtleT09PXVuZGVmaW5lZCl7dmFyIHJldD17fTt0aGlzLmZvckVhY2goZnVuY3Rpb24oa2V5LHZhbCl7cmV0dXJuIHJldFtrZXldPXZhbDt9KTtyZXR1cm4gcmV0O31pZihrZXkuY2hhckF0KDApPT09Jz8nKXtyZXR1cm4gdGhpcy5oYXMoa2V5LnN1YnN0cigxKSk7fXZhciBhcmdzPWFyZ3VtZW50cztpZihhcmdzLmxlbmd0aD4xKXt2YXIgZHQ9e307Zm9yKHZhciBpPTAsbGVuPWFyZ3MubGVuZ3RoO2k8bGVuO2krKyl7dmFyIHZhbHVlPWRlc2VyaWFsaXplKHN0b3JhZ2UuZ2V0SXRlbShhcmdzW2ldKSk7aWYodGhpcy5oYXMoYXJnc1tpXSkpe2R0W2FyZ3NbaV1dPXZhbHVlO319cmV0dXJuIGR0O31yZXR1cm4gZGVzZXJpYWxpemUoc3RvcmFnZS5nZXRJdGVtKGtleSkpO30sY2xlYXI6ZnVuY3Rpb24gY2xlYXIoKXtzdG9yYWdlLmNsZWFyKCk7cmV0dXJuIHRoaXM7fSxyZW1vdmU6ZnVuY3Rpb24gcmVtb3ZlKGtleSl7dmFyIHZhbD10aGlzLmdldChrZXkpO3N0b3JhZ2UucmVtb3ZlSXRlbShrZXkpO3JldHVybiB2YWw7fSxoYXM6ZnVuY3Rpb24gaGFzKGtleSl7cmV0dXJuIHt9Lmhhc093blByb3BlcnR5LmNhbGwodGhpcy5nZXQoKSxrZXkpO30sa2V5czpmdW5jdGlvbiBrZXlzKCl7dmFyIGQ9W107dGhpcy5mb3JFYWNoKGZ1bmN0aW9uKGspe2QucHVzaChrKTt9KTtyZXR1cm4gZDt9LGZvckVhY2g6ZnVuY3Rpb24gZm9yRWFjaChjYWxsYmFjayl7Zm9yKHZhciBpPTAsbGVuPXN0b3JhZ2UubGVuZ3RoO2k8bGVuO2krKyl7dmFyIGtleT1zdG9yYWdlLmtleShpKTtjYWxsYmFjayhrZXksdGhpcy5nZXQoa2V5KSk7fXJldHVybiB0aGlzO30sc2VhcmNoOmZ1bmN0aW9uIHNlYXJjaChzdHIpe3ZhciBhcnI9dGhpcy5rZXlzKCksZHQ9e307Zm9yKHZhciBpPTAsbGVuPWFyci5sZW5ndGg7aTxsZW47aSsrKXtpZihhcnJbaV0uaW5kZXhPZihzdHIpPi0xKWR0W2FycltpXV09dGhpcy5nZXQoYXJyW2ldKTt9cmV0dXJuIGR0O30sbGVuOmZ1bmN0aW9uIGxlbigpe3JldHVybiBzdG9yYWdlLmxlbmd0aDt9fTt2YXIgX1N0b3JlPW51bGw7ZnVuY3Rpb24gc3RvcmUoa2V5LGRhdGEpe3ZhciBhcmdtPWFyZ3VtZW50czt2YXIgZHQ9bnVsbDtpZighX1N0b3JlKV9TdG9yZT1TdG9yZSgpO2lmKGFyZ20ubGVuZ3RoPT09MClyZXR1cm4gX1N0b3JlLmdldCgpO2lmKGFyZ20ubGVuZ3RoPT09MSl7aWYodHlwZW9mIGtleT09PVwic3RyaW5nXCIpcmV0dXJuIF9TdG9yZS5nZXQoa2V5KTtpZihpc0pTT04oa2V5KSlyZXR1cm4gX1N0b3JlLnNldChrZXkpO31pZihhcmdtLmxlbmd0aD09PTImJnR5cGVvZiBrZXk9PT1cInN0cmluZ1wiKXtpZighZGF0YSlyZXR1cm4gX1N0b3JlLnJlbW92ZShrZXkpO2lmKGRhdGEmJnR5cGVvZiBkYXRhPT09XCJzdHJpbmdcIilyZXR1cm4gX1N0b3JlLnNldChrZXksZGF0YSk7aWYoZGF0YSYmaXNGdW5jdGlvbihkYXRhKSl7ZHQ9bnVsbDtkdD1kYXRhKGtleSxfU3RvcmUuZ2V0KGtleSkpO3N0b3JlLnNldChrZXksZHQpO319aWYoYXJnbS5sZW5ndGg9PT0yJiZpc0FycmF
15KGtleSkmJmlzRnVuY3Rpb24oZGF0YSkpe2Zvcih2YXIgaT0wLGxlbj1rZXkubGVuZ3RoO2k8bGVuO2krKyl7ZHQ9ZGF0YShrZXlbaV0sX1N0b3JlLmdldChrZXlbaV0pKTtzdG9yZS5zZXQoa2V5W2ldLGR0KTt9fXJldHVybiBzdG9yZTt9Zm9yKHZhciBhIGluIFN0b3JlLnByb3RvdHlwZSlzdG9yZVthXT1TdG9yZS5wcm90b3R5cGVbYV07cmV0dXJuIHN0b3JlO30pO30pKHN0b3JlJDIpO3JldHVybiBzdG9yZSQyLmV4cG9ydHM7fVxuXG52YXIgc3RvcmVFeHBvcnRzID0gcmVxdWlyZVN0b3JlKCk7XG5jb25zdCBzdG9yZSA9IC8qQF9fUFVSRV9fKi9nZXREZWZhdWx0RXhwb3J0RnJvbUNqcyhzdG9yZUV4cG9ydHMpO1xuXG4vLyAgY2hlY2sgaWYgdGhlIGdldCwgc2V0IG92ZXJsb2FkcyBhbmQgc2VhcmNoIG1ldGhvZHMgYXJlIHVzZWQgYXQgYWxsXG4vLyAgaWYgd2UgZG8sIGVuc3VyZSB3ZSBwcm92aWRlIHR5cGVzIHRvIHN1cHBvcnQgb3ZlcmxvYWRzIGFzIHBlciBzdG9yZWpzIGRvY3Ncbi8vICBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9zdG9yZWpzXG4vKipcbiAqIEEgc3RvcmFnZSB1dGlsaXR5IHRvIHBlcnNpc3QgdmFsdWVzIGluIGxvY2Fsc3RvcmFnZSB2aWEgU3RvcmFnZSBpbnRlcmZhY2VcbiAqL2NsYXNzIExvY2FsU3RvcmFnZXtpc1N1cHBvcnRBdmFpbGFibGU9dHJ1ZTtpc0VuYWJsZWQ9dHJ1ZTtsZW5ndGg9MDtjb25zdHJ1Y3Rvcihsb2dnZXIpe3RoaXMub3B0aW9ucz1nZXREZWZhdWx0TG9jYWxTdG9yYWdlT3B0aW9ucygpO3RoaXMubG9nZ2VyPWxvZ2dlcjt9Y29uZmlndXJlKG9wdGlvbnMpe3RoaXMub3B0aW9ucz1tZXJnZURlZXBSaWdodCh0aGlzLm9wdGlvbnMsb3B0aW9ucz8/e30pO3RoaXMuaXNTdXBwb3J0QXZhaWxhYmxlPWlzU3RvcmFnZUF2YWlsYWJsZShMT0NBTF9TVE9SQUdFKTt0aGlzLmlzRW5hYmxlZD1Cb29sZWFuKHRoaXMub3B0aW9ucy5lbmFibGVkJiZ0aGlzLmlzU3VwcG9ydEF2YWlsYWJsZSk7cmV0dXJuIHRoaXMub3B0aW9uczt9c2V0SXRlbShrZXksdmFsdWUpe3N0b3JlLnNldChrZXksdmFsdWUpO3RoaXMubGVuZ3RoPXN0b3JlLmxlbigpO30vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY2xhc3MtbWV0aG9kcy11c2UtdGhpc1xuZ2V0SXRlbShrZXkpe2NvbnN0IHZhbHVlPXN0b3JlLmdldChrZXkpO3JldHVybiBpc1VuZGVmaW5lZCh2YWx1ZSk/bnVsbDp2YWx1ZTt9cmVtb3ZlSXRlbShrZXkpe3N0b3JlLnJlbW92ZShrZXkpO3RoaXMubGVuZ3RoPXN0b3JlLmxlbigpO31jbGVhcigpe3N0b3JlLmNsZWFyKCk7dGhpcy5sZW5ndGg9MDt9a2V5KGluZGV4KXtjb25zdCBjdXJLZXlzPXRoaXMua2V5cygpO3JldHVybiBjdXJLZXlzW2luZGV4XT8/bnVsbDt9Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbmtleXMoKXtyZXR1cm4gc3RvcmUua2V5cygpO319Y29uc3QgZGVmYXVsdExvY2FsU3RvcmFnZT1uZXcgTG9jYWxTdG9yYWdlKGRlZmF1bHRMb2dnZXIpO1xuXG4vKipcbiAqIEEgc3RvcmFnZSB1dGlsaXR5IHRvIHBlcnNpc3QgdmFsdWVzIGluIFNlc3Npb25TdG9yYWdlIHZpYSBTdG9yYWdlIGludGVyZmFjZVxuICovY2xhc3MgU2Vzc2lvblN0b3JhZ2V7aXNTdXBwb3J0QXZhaWxhYmxlPXRydWU7aXNFbmFibGVkPXRydWU7bGVuZ3RoPTA7Y29uc3RydWN0b3IobG9nZ2VyKXt0aGlzLm9wdGlvbnM9Z2V0RGVmYXVsdFNlc3Npb25TdG9yYWdlT3B0aW9ucygpO3RoaXMubG9nZ2VyPWxvZ2dlcjt9Y29uZmlndXJlKG9wdGlvbnMpe3RoaXMub3B0aW9ucz1tZXJnZURlZXBSaWdodCh0aGlzLm9wdGlvbnMsb3B0aW9ucz8/e30pO3RoaXMuaXNTdXBwb3J0QXZhaWxhYmxlPWlzU3RvcmFnZUF2YWlsYWJsZShTRVNTSU9OX1NUT1JBR0UpOy8vIHdoZW4gc3RvcmFnZSBpcyBibG9ja2VkIGJ5IHRoZSB1c2VyLCBldmVuIGFjY2Vzc2luZyB0aGUgcHJvcGVydHkgdGhyb3dzIGFuIGVycm9yXG5pZih0aGlzLmlzU3VwcG9ydEF2YWlsYWJsZSl7dGhpcy5zdG9yZT1nbG9iYWxUaGlzLnNlc3Npb25TdG9yYWdlO310aGlzLmlzRW5hYmxlZD1Cb29sZWFuKHRoaXMub3B0aW9ucy5lbmFibGVkJiZ0aGlzLmlzU3VwcG9ydEF2YWlsYWJsZSk7cmV0dXJuIHRoaXMub3B0aW9uczt9c2V0SXRlbShrZXksdmFsdWUpe2lmKCF0aGlzLnN0b3JlKXtyZXR1cm47fXRoaXMuc3RvcmUuc2V0SXRlbShrZXksdmFsdWUpO3RoaXMubGVuZ3RoPXRoaXMuc3RvcmUubGVuZ3RoO31nZXRJdGVtKGtleSl7aWYoIXRoaXMuc3RvcmUpe3JldHVybiBudWxsO31jb25zdCB2YWx1ZT10aGlzLnN0b3JlLmdldEl0ZW0oa2V5KTtyZXR1cm4gaXNVbmRlZmluZWQodmFsdWUpP251bGw6dmFsdWU7fXJlbW92ZUl0ZW0oa2V5KXtpZighdGhpcy5zdG9yZSl7cmV0dXJuO310aGlzLnN0b3JlLnJlbW92ZUl0ZW0oa2V5KTt0aGlzLmxlbmd0aD10aGlzLnN0b3JlLmxlbmd0aDt9Y2xlYXIoKXt0aGlzLnN0b3JlPy5jbGVhcigpO3RoaXMubGVuZ3RoPTA7fWtleShpbmRleCl7cmV0dXJuIHRoaXMuc3RvcmU/LmtleShpbmRleCk/P251bGw7fWtleXMoKXtjb25zdCBrZXlzPVtdO2lmKCF0aGlzLnN0b3JlKXtyZXR1cm4ga2V5czt9Zm9yKGxldCBpPTA7aTx0aGlzLnN0b3JlLmxlbmd0aDtpKz0xKXtjb25zdCBrZXk9dGhpcy5zdG9yZS5rZXkoaSk7aWYoa2V5IT09bnVsbCl7a2V5cy5wdXNoKGtleSk7fX1yZXR1cm4ga2V5czt9fWNvbnN0IGRlZmF1bHRTZXNzaW9uU3RvcmFnZT1uZXcgU2Vzc2lvblN0b3JhZ2UoZGVmYXVsdExvZ2dlcik7XG5cbi8qKlxuICogQSBzdG9yYWdlIHV0aWxpdHkgdG8gcGVyc2lzdCB2YWx1ZXMgaW4gY29va2llcyB2aWEgU3RvcmFnZSBpbnRlcmZhY2VcbiAqL2NsYXNzIENvb2tpZVN0b3JhZ2V7aXNTdXBwb3J0QXZhaWxhYmxlPXRydWU7aXNFbmFibGVkPXRydWU7bGVuZ3RoPTA7Y29uc3RydWN0b3IobG9nZ2VyKXt0aGlzLmxvZ2dlcj1sb2dnZXI7fWNvbmZpZ3VyZShvcHRpb25zKXtpZighdGhpcy5vcHRpb25zKXt0aGlzLm9wdGlvbnM9Z2V0RGVmYXVsdENvb2tpZU9wdGlvbnMoKTt9dGhpcy5vcHRpb25zPW1lcmdlRGVlcFJpZ2h0KHRoaXMub3B0aW9ucyxvcHRpb25zPz97fSk7aWYodGhpcy5vcHRpb25zLnNhbWVEb21haW5Db29raWVzT25seSl7ZGVsZXRlIHRoaXMub3B0aW9ucy5kb21haW47fXRoaXMuaXNTdXBwb3J0QXZhaWxhYmxlPWlzU3RvcmFnZUF2YWlsYWJsZShDT09LSUVfU1RPUkFHRSx0aGlzKTt0aGlzLmlzRW5hYmxlZD1Cb29sZWFuKHRoaXMub3B0aW9ucy5lbmFibGVkJiZ0aGlzLmlzU3VwcG9ydEF2YWlsYWJsZSk7cmV0dXJuIHRoaXMub3B0aW9uczt9c2V0SXRlbShrZXksdmFsdWUpe2Nvb2tpZShrZXksdmFsdWUsdGhpcy5vcHRpb25zLHRoaXMubG9nZ2VyKTt0aGlzLmxlbmd0aD1PYmplY3Qua2V5cyhjb29raWUoKSkubGVuZ3RoO3JldHVybiB0cnVlO30vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY2xhc3MtbWV0aG9kcy11c2UtdGhpc1xuZ2V0SXRlbShrZXkpe2NvbnN0IHZhbHVlPWNvb2tpZShrZXkpO3JldHVybiBpc1VuZGVmaW5lZCh2YWx1ZSk/bnVsbDp2YWx1ZTt9cmVtb3ZlSXRlbShrZXkpe2NvbnN0IHJlc3VsdD10aGlzLnNldEl0ZW0oa2V5LG51bGwpO3RoaXMubGVuZ3RoPU9iamVjdC5rZXlzKGNvb2tpZSgpKS5sZW5ndGg7cmV0dXJuIHJlc3VsdDt9Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbmNsZWFyKCl7Ly8gTm90IGltcGxlbWVudGVkXG4vLyBnZXR0aW5nIGEgbGlzdCBvZiBhbGwgY29va2llIHN0b3JhZ2Uga2V5cyBhbmQgcmVtb3ZlIGFsbCB2YWx1ZXNcbi8vIHNvdW5kcyByaXNreSB0byBkbyBhcyBpdCB3aWxsIHRha2Ugb24gYWxsIHRvcCBkb21haW4gY29va2llc1xuLy8gYmV0dGVyIHRvIGV4cGxpY2l0bHkgY2xlYXIgc3BlY2lmaWMgb25lcyBpZiBuZWVkZWRcbn1rZXkoaW5kZXgpe2NvbnN0IGN1cktleXM9dGhpcy5rZXlzKCk7cmV0dXJuIGN1cktleXNbaW5kZXhdPz9udWxsO30vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY2xhc3MtbWV0aG9kcy11c2UtdGhpc1xua2V5cygpe3JldHVybiBPYmplY3Qua2V5cyhjb29raWUoKSk7fX1jb25zdCBkZWZhdWx0Q29va2llU3RvcmFnZT1uZXcgQ29va2llU3RvcmFnZShkZWZh
1dWx0TG9nZ2VyKTtcblxuLyoqXG4gKiBBIHV0aWxpdHkgdG8gcmV0cmlldmUgdGhlIHN0b3JhZ2Ugc2luZ2xldG9uIGluc3RhbmNlIGJ5IHR5cGVcbiAqL2NvbnN0IGdldFN0b3JhZ2VFbmdpbmU9dHlwZT0+e3N3aXRjaCh0eXBlKXtjYXNlIExPQ0FMX1NUT1JBR0U6cmV0dXJuIGRlZmF1bHRMb2NhbFN0b3JhZ2U7Y2FzZSBTRVNTSU9OX1NUT1JBR0U6cmV0dXJuIGRlZmF1bHRTZXNzaW9uU3RvcmFnZTtjYXNlIE1FTU9SWV9TVE9SQUdFOnJldHVybiBkZWZhdWx0SW5NZW1vcnlTdG9yYWdlO2Nhc2UgQ09PS0lFX1NUT1JBR0U6cmV0dXJuIGRlZmF1bHRDb29raWVTdG9yYWdlO2RlZmF1bHQ6cmV0dXJuIGRlZmF1bHRJbk1lbW9yeVN0b3JhZ2U7fX07LyoqXG4gKiBDb25maWd1cmUgY29va2llIHN0b3JhZ2Ugc2luZ2xldG9uXG4gKi9jb25zdCBjb25maWd1cmVDb29raWVTdG9yYWdlRW5naW5lPW9wdGlvbnM9Pntjb25zdCBjb29raWVTdG9yYWdlT3B0aW9ucz1kZWZhdWx0Q29va2llU3RvcmFnZS5jb25maWd1cmUob3B0aW9ucyk7Ly8gVXBkYXRlIHRoZSBzdGF0ZSB3aXRoIHRoZSBmaW5hbCBjb29raWUgc3RvcmFnZSBvcHRpb25zXG5zdGF0ZS5zdG9yYWdlLmNvb2tpZS52YWx1ZT17bWF4YWdlOmNvb2tpZVN0b3JhZ2VPcHRpb25zLm1heGFnZSxwYXRoOmNvb2tpZVN0b3JhZ2VPcHRpb25zLnBhdGgsZG9tYWluOmNvb2tpZVN0b3JhZ2VPcHRpb25zLmRvbWFpbixzYW1lc2l0ZTpjb29raWVTdG9yYWdlT3B0aW9ucy5zYW1lc2l0ZSxleHBpcmVzOmNvb2tpZVN0b3JhZ2VPcHRpb25zLmV4cGlyZXMsc2VjdXJlOmNvb2tpZVN0b3JhZ2VPcHRpb25zLnNlY3VyZX07fTsvKipcbiAqIENvbmZpZ3VyZSBsb2NhbCBzdG9yYWdlIHNpbmdsZXRvblxuICovY29uc3QgY29uZmlndXJlTG9jYWxTdG9yYWdlRW5naW5lPW9wdGlvbnM9PntkZWZhdWx0TG9jYWxTdG9yYWdlLmNvbmZpZ3VyZShvcHRpb25zKTt9Oy8qKlxuICogQ29uZmlndXJlIGluIG1lbW9yeSBzdG9yYWdlIHNpbmdsZXRvblxuICovY29uc3QgY29uZmlndXJlSW5NZW1vcnlTdG9yYWdlRW5naW5lPW9wdGlvbnM9PntkZWZhdWx0SW5NZW1vcnlTdG9yYWdlLmNvbmZpZ3VyZShvcHRpb25zKTt9Oy8qKlxuICogQ29uZmlndXJlIHNlc3Npb24gc3RvcmFnZSBzaW5nbGV0b25cbiAqL2NvbnN0IGNvbmZpZ3VyZVNlc3Npb25TdG9yYWdlRW5naW5lPW9wdGlvbnM9PntkZWZhdWx0U2Vzc2lvblN0b3JhZ2UuY29uZmlndXJlKG9wdGlvbnMpO307LyoqXG4gKiBDb25maWd1cmUgYWxsIHN0b3JhZ2Ugc2luZ2xldG9uIGluc3RhbmNlc1xuICovY29uc3QgY29uZmlndXJlU3RvcmFnZUVuZ2luZXM9KGNvb2tpZVN0b3JhZ2VPcHRpb25zPXt9LGxvY2FsU3RvcmFnZU9wdGlvbnM9e30saW5NZW1vcnlTdG9yYWdlT3B0aW9ucz17fSxzZXNzaW9uU3RvcmFnZU9wdGlvbnM9e30pPT57Y29uZmlndXJlQ29va2llU3RvcmFnZUVuZ2luZShjb29raWVTdG9yYWdlT3B0aW9ucyk7Y29uZmlndXJlTG9jYWxTdG9yYWdlRW5naW5lKGxvY2FsU3RvcmFnZU9wdGlvbnMpO2NvbmZpZ3VyZUluTWVtb3J5U3RvcmFnZUVuZ2luZShpbk1lbW9yeVN0b3JhZ2VPcHRpb25zKTtjb25maWd1cmVTZXNzaW9uU3RvcmFnZUVuZ2luZShzZXNzaW9uU3RvcmFnZU9wdGlvbnMpO307XG5cbi8qKlxuICogU3RvcmUgSW1wbGVtZW50YXRpb24gd2l0aCBkZWRpY2F0ZWQgc3RvcmFnZVxuICovY2xhc3MgU3RvcmV7Y29uc3RydWN0b3IoY29uZmlnLGVuZ2luZSxwbHVnaW5zTWFuYWdlcil7dGhpcy5pZD1jb25maWcuaWQ7dGhpcy5uYW1lPWNvbmZpZy5uYW1lO3RoaXMuaXNFbmNyeXB0ZWQ9Y29uZmlnLmlzRW5jcnlwdGVkPz9mYWxzZTt0aGlzLnZhbGlkS2V5cz1jb25maWcudmFsaWRLZXlzPz97fTt0aGlzLmVuZ2luZT1lbmdpbmU7dGhpcy5ub0tleVZhbGlkYXRpb249T2JqZWN0LmtleXModGhpcy52YWxpZEtleXMpLmxlbmd0aD09PTA7dGhpcy5ub0NvbXBvdW5kS2V5PWNvbmZpZy5ub0NvbXBvdW5kS2V5O3RoaXMub3JpZ2luYWxFbmdpbmU9dGhpcy5lbmdpbmU7dGhpcy5lcnJvckhhbmRsZXI9Y29uZmlnLmVycm9ySGFuZGxlcjt0aGlzLmxvZ2dlcj1jb25maWcubG9nZ2VyO3RoaXMucGx1Z2luc01hbmFnZXI9cGx1Z2luc01hbmFnZXI7fS8qKlxuICAgKiBFbnN1cmUgdGhlIGtleSBpcyB2YWxpZCBhbmQgd2l0aCBjb3JyZWN0IGZvcm1hdFxuICAgKi9jcmVhdGVWYWxpZEtleShrZXkpe2NvbnN0e25hbWUsaWQsdmFsaWRLZXlzLG5vS2V5VmFsaWRhdGlvbixub0NvbXBvdW5kS2V5fT10aGlzO2lmKG5vS2V5VmFsaWRhdGlvbil7cmV0dXJuIG5vQ29tcG91bmRLZXk/a2V5OltuYW1lLGlkLGtleV0uam9pbignLicpO30vLyB2YWxpZGF0ZSBhbmQgcmV0dXJuIHVuZGVmaW5lZCBpZiBpbnZhbGlkIGtleVxubGV0IGNvbXBvdW5kS2V5O09iamVjdC52YWx1ZXModmFsaWRLZXlzKS5mb3JFYWNoKHZhbGlkS2V5TmFtZT0+e2lmKHZhbGlkS2V5TmFtZT09PWtleSl7Y29tcG91bmRLZXk9bm9Db21wb3VuZEtleT9rZXk6W25hbWUsaWQsa2V5XS5qb2luKCcuJyk7fX0pO3JldHVybiBjb21wb3VuZEtleTt9LyoqXG4gICAqIFN3aXRjaCB0byBpbk1lbW9yeUVuZ2luZSwgYnJpbmdpbmcgYW55IGV4aXN0aW5nIGRhdGEgd2l0aC5cbiAgICovc3dhcFF1ZXVlU3RvcmVUb0luTWVtb3J5RW5naW5lKCl7Y29uc3R7bmFtZSxpZCx2YWxpZEtleXMsbm9Db21wb3VuZEtleX09dGhpcztjb25zdCBpbk1lbW9yeVN0b3JhZ2U9Z2V0U3RvcmFnZUVuZ2luZShNRU1PUllfU1RPUkFHRSk7Ly8gZ3JhYiBleGlzdGluZyBkYXRhLCBidXQgb25seSBmb3IgdGhpcyBwYWdlJ3MgcXVldWUgaW5zdGFuY2UsIG5vdCBhbGxcbi8vIGJldHRlciB0byBrZWVwIG90aGVyIHF1ZXVlcyBpbiBsb2NhbHN0b3JhZ2UgdG8gYmUgZmx1c2hlZCBsYXRlclxuLy8gdGhhbiB0byBwdWxsIHRoZW0gaW50byBtZW1vcnkgYW5kIHJlbW92ZSB0aGVtIGZyb20gZHVyYWJsZSBzdG9yYWdlXG5PYmplY3Qua2V5cyh2YWxpZEtleXMpLmZvckVhY2goa2V5PT57Y29uc3QgdmFsdWU9dGhpcy5nZXQodmFsaWRLZXlzW2tleV0pO2NvbnN0IHZhbGlkS2V5PW5vQ29tcG91bmRLZXk/a2V5OltuYW1lLGlkLGtleV0uam9pbignLicpO2luTWVtb3J5U3RvcmFnZS5zZXRJdGVtKHZhbGlkS2V5LHZhbHVlKTsvLyBUT0RPOiBhcmUgd2Ug
1c3VyZSB3ZSB3YW50IHRvIGRyb3AgY2xpZW50RGF0YVxuLy8gIGlmIGNvb2tpZXMgYXJlIG5vdCBhdmFpbGFibGUgYW5kIGxvY2Fsc3RvcmFnZSBpcyBmdWxsP1xudGhpcy5yZW1vdmUoa2V5KTt9KTt0aGlzLmVuZ2luZT1pbk1lbW9yeVN0b3JhZ2U7fS8qKlxuICAgKiBTZXQgdmFsdWUgYnkga2V5LlxuICAgKi9zZXQoa2V5LHZhbHVlKXtjb25zdCB2YWxpZEtleT10aGlzLmNyZWF0ZVZhbGlkS2V5KGtleSk7aWYoIXZhbGlkS2V5KXtyZXR1cm47fXRyeXsvLyBzdG9yZWpzIHRoYXQgaXMgdXNlZCBpbiBsb2NhbHN0b3JhZ2UgZW5naW5lIGFscmVhZHkgc3RyaW5naWZpZXMganNvblxudGhpcy5lbmdpbmUuc2V0SXRlbSh2YWxpZEtleSx0aGlzLmVuY3J5cHQoc3RyaW5naWZ5V2l0aG91dENpcmN1bGFyKHZhbHVlLGZhbHNlLFtdLHRoaXMubG9nZ2VyKSkpO31jYXRjaChlcnIpe2lmKGlzU3RvcmFnZVF1b3RhRXhjZWVkZWQoZXJyKSl7dGhpcy5sb2dnZXIud2FybihTVE9SQUdFX1FVT1RBX0VYQ0VFREVEX1dBUk5JTkcoYFN0b3JlICR7dGhpcy5pZH1gKSk7Ly8gc3dpdGNoIHRvIGluTWVtb3J5IGVuZ2luZVxudGhpcy5zd2FwUXVldWVTdG9yZVRvSW5NZW1vcnlFbmdpbmUoKTsvLyBhbmQgc2F2ZSBpdCB0aGVyZVxudGhpcy5zZXQoa2V5LHZhbHVlKTt9ZWxzZSB7Y29uc3QgY3VzdG9tTWVzc2FnZT1TVE9SRV9EQVRBX1NBVkVfRVJST1Ioa2V5KTt0aGlzLm9uRXJyb3IoZXJyLGN1c3RvbU1lc3NhZ2UsY3VzdG9tTWVzc2FnZSk7fX19LyoqXG4gICAqIEdldCBieSBLZXkuXG4gICAqL2dldChrZXkpe2NvbnN0IHZhbGlkS2V5PXRoaXMuY3JlYXRlVmFsaWRLZXkoa2V5KTtsZXQgZGVjcnlwdGVkVmFsdWU7dHJ5e2lmKCF2YWxpZEtleSl7cmV0dXJuIG51bGw7fWRlY3J5cHRlZFZhbHVlPXRoaXMuZGVjcnlwdCh0aGlzLmVuZ2luZS5nZXRJdGVtKHZhbGlkS2V5KSk7aWYoaXNOdWxsT3JVbmRlZmluZWQoZGVjcnlwdGVkVmFsdWUpfHxkZWNyeXB0ZWRWYWx1ZT09PScnKXtyZXR1cm4gbnVsbDt9Ly8gc3RvcmVqcyB0aGF0IGlzIHVzZWQgaW4gbG9jYWxzdG9yYWdlIGVuZ2luZSBhbHJlYWR5IGRlc2VyaWFsaXplcyBqc29uIHN0cmluZ3MgYnV0IHN3YWxsb3dzIGVycm9yc1xucmV0dXJuIEpTT04ucGFyc2UoZGVjcnlwdGVkVmFsdWUpO31jYXRjaChlcnIpe2NvbnN0IGVuY3J5cHRpb25QbHVnaW5OYW1lPXN0YXRlLnN0b3JhZ2UuZW5jcnlwdGlvblBsdWdpbk5hbWUudmFsdWU7Ly8gU2tpcCBlcnJvciByZXBvcnRpbmcgb25seSB3aGVuIHRoZSBlbmNyeXB0aW9uIHBsdWdpbiBpcyBjb25maWd1cmVkIGJ1dCBmYWlsZWQgdG8gbG9hZFxuY29uc3Qgc2hvdWxkUmVwb3J0RXJyb3I9IWVuY3J5cHRpb25QbHVnaW5OYW1lfHwhc3RhdGUucGx1Z2lucy5mYWlsZWRQbHVnaW5zLnZhbHVlLmluY2x1ZGVzKGVuY3J5cHRpb25QbHVnaW5OYW1lKTtpZihzaG91bGRSZXBvcnRFcnJvcil7Y29uc3QgY3VzdG9tTWVzc2FnZT1TVE9SRV9EQVRBX0ZFVENIX0VSUk9SKGtleSk7dGhpcy5vbkVycm9yKGVycixjdXN0b21NZXNzYWdlLGN1c3RvbU1lc3NhZ2UpO31yZXR1cm4gbnVsbDt9fS8qKlxuICAgKiBSZW1vdmUgYnkgS2V5LlxuICAgKi9yZW1vdmUoa2V5KXtjb25zdCB2YWxpZEtleT10aGlzLmNyZWF0ZVZhbGlkS2V5KGtleSk7aWYodmFsaWRLZXkpe3RoaXMuZW5naW5lLnJlbW92ZUl0ZW0odmFsaWRLZXkpO319LyoqXG4gICAqIEdldCBvcmlnaW5hbCBlbmdpbmVcbiAgICovZ2V0T3JpZ2luYWxFbmdpbmUoKXtyZXR1cm4gdGhpcy5vcmlnaW5hbEVuZ2luZTt9LyoqXG4gICAqIERlY3J5cHQgdmFsdWVzXG4gICAqL2RlY3J5cHQodmFsdWUpe2lmKGlzTnVsbE9yVW5kZWZpbmVkKHZhbHVlKSl7cmV0dXJuIG51bGw7fXJldHVybiB0aGlzLmNyeXB0byh2YWx1ZSwnZGVjcnlwdCcpO30vKipcbiAgICogRW5jcnlwdCB2YWx1ZVxuICAgKi9lbmNyeXB0KHZhbHVlKXtyZXR1cm4gdGhpcy5jcnlwdG8odmFsdWUsJ2VuY3J5cHQnKTt9LyoqXG4gICAqIEV4dGVuc2lvbiBwb2ludCB0byB1c2Ugd2l0aCBlbmNyeXB0aW9uIHBsdWdpbnNcbiAgICovY3J5cHRvKHZhbHVlLG1vZGUpe2NvbnN0IG5vRW5jcnlwdGlvbj0hdGhpcy5pc0VuY3J5cHRlZHx8IXZhbHVlfHx0eXBlb2YgdmFsdWUhPT0nc3RyaW5nJ3x8dHJpbSh2YWx1ZSk9PT0nJztpZihub0VuY3J5cHRpb24pe3JldHVybiB2YWx1ZTt9Y29uc3QgZXh0ZW5zaW9uUG9pbnROYW1lPWBzdG9yYWdlLiR7bW9kZX1gO2NvbnN0IGZvcm1hdHRlZFZhbHVlPXRoaXMucGx1Z2luc01hbmFnZXI/dGhpcy5wbHVnaW5zTWFuYWdlci5pbnZva2VTaW5nbGUoZXh0ZW5zaW9uUG9pbnROYW1lLHZhbHVlKTp2YWx1ZTtyZXR1cm4gdHlwZW9mIGZvcm1hdHRlZFZhbHVlPT09J3VuZGVmaW5lZCc/dmFsdWU6Zm9ybWF0dGVkVmFsdWU/PycnO30vKipcbiAgICogSGFuZGxlIGVycm9yc1xuICAgKi9vbkVycm9yKGVycm9yLGN1c3RvbU1lc3NhZ2UsZ3JvdXBpbmdIYXNoKXt0aGlzLmVycm9ySGFuZGxlci5vbkVycm9yKHtlcnJvcixjb250ZXh0OmBTdG9yZSAke3RoaXMuaWR9YCxjdXN0b21NZXNzYWdlLGdyb3VwaW5nSGFzaH0pO319XG5cbmNvbnN0IGdldFN0b3JhZ2VUeXBlRnJvbVByZUNvbnNlbnRJZkFwcGxpY2FibGU9KHN0YXRlLHNlc3Npb25LZXkpPT57bGV0IG92ZXJyaWRkZW5TdG9yYWdlVHlwZTtpZihzdGF0ZS5jb25zZW50cy5wcmVDb25zZW50LnZhbHVlLmVuYWJsZWQpe3N3aXRjaChzdGF0ZS5jb25zZW50cy5wcmVDb25zZW50LnZhbHVlLnN0b3JhZ2U/LnN0cmF0ZWd5KXtjYXNlICdub25lJzpvdmVycmlkZGVuU3RvcmFnZVR5cGU9Tk9fU1RPUkFHRTticmVhaztjYXNlICdzZXNzaW9uJzppZihzZXNzaW9uS2V5IT09J3Nlc3Npb25JbmZvJyl7b3ZlcnJpZGRlblN0b3JhZ2VUeXBlPU5PX1NUT1JBR0U7fWJyZWFrO2Nhc2UgJ2Fub255bW91c0lkJzppZihzZXNzaW9uS2V5IT09J2Fub255bW91c0lkJyl7b3ZlcnJpZGRlblN0b3JhZ2VUeXBlPU5PX1NUT1JBR0U7fWJyZWFrO319cmV0dXJuIG92ZXJyaWRkZW5TdG9yYWdlVHlwZTt9O1xuXG4vKipcbiAqIEEgc2VydmljZSB0byBtYW5hZ2Ugc3RvcmVzICYgYXZhaWxhYmxlIHN0b3JhZ2UgY2xpZW50IGNvbmZpZ3VyYXRpb25zXG4gKi9jbGFzcyBTdG9yZU1hbmFnZXJ7c3RvcmVzPXt9O2lzSW5pdGlhbGl6ZWQ9ZmFsc2U7Y29uc3RydWN0b3IocGx1Z2luc01hbmFnZXIsZXJyb3JIYW5kbGVyLGxvZ2dlcil7dGhpcy5lcnJvckhhbmRsZXI9ZXJyb3JIYW5kbGVyO3RoaXMubG9nZ2VyPWxvZ2dlcjt0aGlzLnBsdWdpbnNNYW5hZ2VyPXBsdWdpbnNNYW5hZ2VyO30vKipcbiAgICogQ29uZmlndXJlIGF2YWlsYWJsZSBzdG9yYWdlIGNsaWVudCBpbnN0YW5jZXNcbiAgICovaW5pdCgpe2lmKHRoaXMuaXNJbml0aWFsaXplZCl7cmV0dXJuO31jb25zdCBsb2FkT3B0aW9ucz1zdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZTtjb25zdCBjb25maWc9e2Nvb2tpZVN0b3JhZ2VPcHRpb25zOntzYW1lc2l0ZTpsb2FkT3B0aW9ucy5zYW1lU2l0ZUNvb2tpZSxzZWN1cmU6bG9hZE9wdGlvbnMuc2VjdXJlQ29va2llLGRvbWFpbjpsb2FkT3B0aW9ucy5zZXRDb29raWVEb21haW4sc2FtZURvbWFpbkNvb2tpZXNPbmx5OmxvYWRPcHRpb25zLnNhbWVEb21haW5Db29raWVzT25seX0sbG9jYWxTdG9yYWdlT3B0aW9uczp7fSxpbk1lbW9yeVN0b3JhZ2VPcHRpb25zOnt9LHNlc3Npb25TdG9yYWdlT3B0aW9uczp7fX07Y29uZmlndXJlU3RvcmFnZUVuZ2luZXMocmVtb3ZlVW5kZWZpbmVkVmFsdWVzKG1lcmdlRGVlcFJpZ2h0KGNvbmZpZy5jb29raWVTdG9yYWdlT3B0aW9ucz8/e30sc3RhdGUuc3RvcmFnZS5jb29raWU/LnZhbHVlPz97fSkpLHJlbW92ZVVuZGVmaW5lZFZhbHVlcyhjb25maWcubG9jYWxTdG9yYWdlT3B0aW9ucykscmVtb3ZlVW5kZWZpbmVkVmFsdWVzKGNvbmZpZy5pbk1lbW9yeVN0b3JhZ2VPcHRpb25zKSxyZW1vdmVVbmRlZmluZWRWYWx1ZXMoY29uZmlnLnNlc3Npb25TdG9yYWdlT3B0aW9ucykpO3RoaXMuaW5pdENsaWVudERhdGFTdG9yZXMoKTt0aGlzLmlzSW5pdGlhbGl6ZWQ9dHJ1ZTt9LyoqXG4gICAqIENyZWF0ZSBzdG9yZSB0byBwZXJzaXN0IGRhdGEgdXNlZCBieSB0aGUgU0RLIGxpa2Ugc2Vzc2lvbiwgdXNlZCBkZXRhaWxzIGV0Y1xuICAgKi9pbml0Q2xpZW50RGF0YVN0b3Jlcygpe3RoaXMuaW5pdGlhbGl6ZVN0b3JhZ2VTdGF0ZSgpOy8vIFRPRE86IGZpbGwgaW4gZXh0cmEgY29uZmlnIHZhbHVlcyBhbmQgYnJpbmcgdGhlbSBpbiBmcm9tIFN0b3JlTWFuYWdlck9wdGlvbnMgaWYgbmVlZGVkXG4vLyBUT0RPOiBzaG91bGQgd2UgcGFzcyB0aGUga2V5cyBmb3IgYWxsIGluIG9yZGVyIHRvIHZhbGlkYXRlIG9yIGxlYXZlIGZyZWUgYXMgdjEuMT9cbi8vIEluaXRpYWxpemluZyBhbGwgdGhlIGVuYWJsZWQgc3RvcmUgYmVjYXVzZSBwcmV2aW91cyB1c2VyIGRhdGEgbWlnaHQgYmUgaW4gZGlmZmVyZW50IHN0b3JhZ2Vcbi8vIHRoYXQgbmVlZHMgY
1XV0byBtaWdyYXRpb25cbmNvbnN0IHN0b3JhZ2VUeXBlcz1bTUVNT1JZX1NUT1JBR0UsTE9DQUxfU1RPUkFHRSxDT09LSUVfU1RPUkFHRSxTRVNTSU9OX1NUT1JBR0VdO3N0b3JhZ2VUeXBlcy5mb3JFYWNoKHN0b3JhZ2VUeXBlPT57aWYoZ2V0U3RvcmFnZUVuZ2luZShzdG9yYWdlVHlwZSk/LmlzRW5hYmxlZCl7dGhpcy5zZXRTdG9yZSh7aWQ6c3RvcmFnZUNsaWVudERhdGFTdG9yZU5hbWVNYXBbc3RvcmFnZVR5cGVdLG5hbWU6c3RvcmFnZUNsaWVudERhdGFTdG9yZU5hbWVNYXBbc3RvcmFnZVR5cGVdLGlzRW5jcnlwdGVkOnRydWUsbm9Db21wb3VuZEtleTp0cnVlLHR5cGU6c3RvcmFnZVR5cGUsZXJyb3JIYW5kbGVyOnRoaXMuZXJyb3JIYW5kbGVyLGxvZ2dlcjp0aGlzLmxvZ2dlcn0pO319KTt9aW5pdGlhbGl6ZVN0b3JhZ2VTdGF0ZSgpe2xldCBnbG9iYWxTdG9yYWdlVHlwZT1zdGF0ZS5zdG9yYWdlLnR5cGUudmFsdWU7bGV0IGVudHJpZXNPcHRpb25zPXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnN0b3JhZ2U/LmVudHJpZXM7Ly8gVXNlIHRoZSBzdG9yYWdlIG9wdGlvbnMgZnJvbSBwb3N0IGNvbnNlbnQgaWYgYW55dGhpbmcgaXMgZGVmaW5lZFxuY29uc3QgcG9zdENvbnNlbnRTdG9yYWdlT3B0cz1zdGF0ZS5jb25zZW50cy5wb3N0Q29uc2VudC52YWx1ZS5zdG9yYWdlO2lmKGlzRGVmaW5lZChwb3N0Q29uc2VudFN0b3JhZ2VPcHRzPy50eXBlKXx8aXNEZWZpbmVkKHBvc3RDb25zZW50U3RvcmFnZU9wdHM/LmVudHJpZXMpKXtnbG9iYWxTdG9yYWdlVHlwZT1wb3N0Q29uc2VudFN0b3JhZ2VPcHRzPy50eXBlO2VudHJpZXNPcHRpb25zPXBvc3RDb25zZW50U3RvcmFnZU9wdHM/LmVudHJpZXM7fWxldCB0cnVseUFub255bW91c1RyYWNraW5nPXRydWU7bGV0IHN0b3JhZ2VFbnRyaWVzPXt9O1VTRVJfU0VTU0lPTl9LRVlTLmZvckVhY2goc2Vzc2lvbktleT0+e2NvbnN0IGtleT1zZXNzaW9uS2V5O2NvbnN0IHN0b3JhZ2VLZXk9c2Vzc2lvbktleTtjb25zdCBjb25maWd1cmVkU3RvcmFnZVR5cGU9ZW50cmllc09wdGlvbnM/LltrZXldPy50eXBlO2NvbnN0IHByZUNvbnNlbnRTdG9yYWdlVHlwZT1nZXRTdG9yYWdlVHlwZUZyb21QcmVDb25zZW50SWZBcHBsaWNhYmxlKHN0YXRlLHNlc3Npb25LZXkpOy8vIFN0b3JhZ2UgdHlwZSBwcmVjZWRlbmNlIG9yZGVyOiBwcmUtY29uc2VudCBzdHJhdGVneSA+IGVudHJ5IHR5cGUgPiBnbG9iYWwgdHlwZSA+IGRlZmF1bHRcbmNvbnN0IHN0b3JhZ2VUeXBlPXByZUNvbnNlbnRTdG9yYWdlVHlwZT8/Y29uZmlndXJlZFN0b3JhZ2VUeXBlPz9nbG9iYWxTdG9yYWdlVHlwZT8/REVGQVVMVF9TVE9SQUdFX1RZUEU7Y29uc3QgZmluYWxTdG9yYWdlVHlwZT10aGlzLmdldFJlc29sdmVkU3RvcmFnZVR5cGVGb3JFbnRyeShzdG9yYWdlVHlwZSxzZXNzaW9uS2V5KTtpZihmaW5hbFN0b3JhZ2VUeXBlIT09Tk9fU1RPUkFHRSl7dHJ1bHlBbm9ueW1vdXNUcmFja2luZz1mYWxzZTt9c3RvcmFnZUVudHJpZXM9ey4uLnN0b3JhZ2VFbnRyaWVzLFtzZXNzaW9uS2V5XTp7dHlwZTpmaW5hbFN0b3JhZ2VUeXBlLGtleTpDT09LSUVfS0VZU1tzdG9yYWdlS2V5XX19O30pO24oKCk9PntzdGF0ZS5zdG9yYWdlLnR5cGUudmFsdWU9Z2xvYmFsU3RvcmFnZVR5cGU7c3RhdGUuc3RvcmFnZS5lbnRyaWVzLnZhbHVlPXN0b3JhZ2VFbnRyaWVzO3N0YXRlLnN0b3JhZ2UudHJ1bHlBbm9ueW1vdXNUcmFja2luZy52YWx1ZT10cnVseUFub255bW91c1RyYWNraW5nO30pO31nZXRSZXNvbHZlZFN0b3JhZ2VUeXBlRm9yRW50cnkoc3RvcmFnZVR5cGUsc2Vzc2lvbktleSl7bGV0IGZpbmFsU3RvcmFnZVR5cGU9c3RvcmFnZVR5cGU7c3dpdGNoKHN0b3JhZ2VUeXBlKXtjYXNlIExPQ0FMX1NUT1JBR0U6aWYoIWdldFN0b3JhZ2VFbmdpbmUoTE9DQUxfU1RPUkFHRSk/LmlzRW5hYmxlZCl7ZmluYWxTdG9yYWdlVHlwZT1NRU1PUllfU1RPUkFHRTt9YnJlYWs7Y2FzZSBTRVNTSU9OX1NUT1JBR0U6aWYoIWdldFN0b3JhZ2VFbmdpbmUoU0VTU0lPTl9TVE9SQUdFKT8uaXNFbmFibGVkKXtmaW5hbFN0b3JhZ2VUeXBlPU1FTU9SWV9TVE9SQUdFO31icmVhaztjYXNlIE1FTU9SWV9TVE9SQUdFOmNhc2UgTk9fU1RPUkFHRTpicmVhaztjYXNlIENPT0tJRV9TVE9SQUdFOmRlZmF1bHQ6Ly8gRmlyc3QgdHJ5IHNldHRpbmcgdGhlIHN0b3JhZ2UgdG8gY29va2llIGVsc2UgdG8gbG9jYWwgc3RvcmFnZVxuaWYoZ2V0U3RvcmFnZUVuZ2luZShDT09LSUVfU1RPUkFHRSk/LmlzRW5hYmxlZCl7ZmluYWxTdG9yYWdlVHlwZT1DT09LSUVfU1RPUkFHRTt9ZWxzZSBpZihnZXRTdG9yYWdlRW5naW5lKExPQ0FMX1NUT1JBR0UpPy5pc0VuYWJsZWQpe2ZpbmFsU3RvcmFnZVR5cGU9TE9DQUxfU1RPUkFHRTt9ZWxzZSBpZihnZXRTdG9yYWdlRW5naW5lKFNFU1NJT05fU1RPUkFHRSk/LmlzRW5hYmxlZCl7ZmluYWxTdG9yYWdlVHlwZT1TRVNTSU9OX1NUT1JBR0U7fWVsc2Uge2ZpbmFsU3RvcmFnZVR5cGU9TUVNT1JZX1NUT1JBR0U7fWJyZWFrO31pZihmaW5hbFN0b3JhZ2VUeXBlIT09c3RvcmFnZVR5cGUpe3RoaXMubG9nZ2VyLndhcm4oU1RPUkFHRV9VTkFWQUlMQUJMRV9XQVJOSU5HKFNUT1JFX01BTkFHRVIsc2Vzc2lvbktleSxzdG9yYWdlVHlwZSxmaW5hbFN0b3JhZ2VUeXBlKSk7fXJldHVybiBmaW5hbFN0b3JhZ2VUeXBlO30vKipcbiAgICogQ3JlYXRlIGEgbmV3IHN0b3JlXG4gICAqL3NldFN0b3JlKHN0b3JlQ29uZmlnKXtjb25zdCBzdG9yYWdlRW5naW5lPWdldFN0b3JhZ2VFbmdpbmUoc3RvcmVDb25maWcudHlwZSk7dGhpcy5zdG9yZXNbc3RvcmVDb25maWcuaWRdPW5ldyBTdG9yZShzdG9yZUNvbmZpZyxzdG9yYWdlRW5naW5lLHRoaXMucGx1Z2luc01hbmFnZXIpO3JldHVybiB0aGlzLnN0b3Jlc1tzdG9yZUNvbmZpZy5pZF07fS8qKlxuICAgKiBSZXRyaWV2ZSBhIHN0b3JlXG4gICAqL2dldFN0b3JlKGlkKXtyZXR1cm4gdGhpcy5zdG9yZXNbaWRdO319XG5cbmNvbnN0IGlzVmFsaWRTb3VyY2VDb25maWc9cmVzPT5pc09iamVjdExpdGVyYWxBbmROb3ROdWxsKHJlcykmJmlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwocmVzLnNvdXJjZSkmJiFpc051bGxPclVuZGVmaW5lZChyZXMuc291cmNlLmlkKSYmaXNPYmplY3RMaXRlcmFsQW5kTm90TnVsbChyZXMuc291cmNlLmNvbmZpZykmJkFycmF5LmlzQXJyYXkocmVzLnNvdXJjZS5kZXN0aW5
1hdGlvbnMpO2NvbnN0IGlzVmFsaWRTdG9yYWdlVHlwZT1zdG9yYWdlVHlwZT0+dHlwZW9mIHN0b3JhZ2VUeXBlPT09J3N0cmluZycmJlNVUFBPUlRFRF9TVE9SQUdFX1RZUEVTLmluY2x1ZGVzKHN0b3JhZ2VUeXBlKTtjb25zdCBnZXRUb3BEb21haW49dXJsPT57Ly8gQ3JlYXRlIGEgVVJMIG9iamVjdFxuY29uc3QgdXJsT2JqPW5ldyBVUkwodXJsKTsvLyBFeHRyYWN0IHRoZSBob3N0IGFuZCBwcm90b2NvbFxuY29uc3R7aG9zdCxwcm90b2NvbH09dXJsT2JqOy8vIFNwbGl0IHRoZSBob3N0IGludG8gcGFydHNcbmNvbnN0IHBhcnRzPWhvc3Quc3BsaXQoJy4nKTtsZXQgdG9wRG9tYWluOy8vIEhhbmRsZSBkaWZmZXJlbnQgY2FzZXMsIGVzcGVjaWFsbHkgZm9yIGNvLnVrIG9yIHNpbWlsYXIgVExEc1xuaWYocGFydHMubGVuZ3RoPjIpey8vIEpvaW4gdGhlIGxhc3QgdHdvIHBhcnRzIGZvciB0aGUgdG9wLWxldmVsIGRvbWFpblxudG9wRG9tYWluPWAke3BhcnRzW3BhcnRzLmxlbmd0aC0yXX0uJHtwYXJ0c1twYXJ0cy5sZW5ndGgtMV19YDt9ZWxzZSB7Ly8gSWYgb25seSB0d28gcGFydHMgb3IgbGVzcywgcmV0dXJuIGFzIGl0IGlzXG50b3BEb21haW49aG9zdDt9cmV0dXJuIHt0b3BEb21haW4scHJvdG9jb2x9O307Y29uc3QgZ2V0VG9wRG9tYWluVXJsPXVybD0+e2NvbnN0e3RvcERvbWFpbixwcm90b2NvbH09Z2V0VG9wRG9tYWluKHVybCk7cmV0dXJuIGAke3Byb3RvY29sfS8vJHt0b3BEb21haW59YDt9O2NvbnN0IGdldERhdGFTZXJ2aWNlVXJsPShlbmRwb2ludCx1c2VFeGFjdERvbWFpbik9Pntjb25zdCB1cmw9dXNlRXhhY3REb21haW4/d2luZG93LmxvY2F0aW9uLm9yaWdpbjpnZXRUb3BEb21haW5Vcmwod2luZG93LmxvY2F0aW9uLmhyZWYpO2NvbnN0IGZvcm1hdHRlZEVuZHBvaW50PWVuZHBvaW50LnN0YXJ0c1dpdGgoJy8nKT9lbmRwb2ludC5zdWJzdHJpbmcoMSk6ZW5kcG9pbnQ7cmV0dXJuIGAke3VybH0vJHtmb3JtYXR0ZWRFbmRwb2ludH1gO307Y29uc3QgaXNXZWJwYWdlVG9wTGV2ZWxEb21haW49cHJvdmlkZWREb21haW49Pntjb25zdHt0b3BEb21haW59PWdldFRvcERvbWFpbih3aW5kb3cubG9jYXRpb24uaHJlZik7cmV0dXJuIHRvcERvbWFpbj09PXByb3ZpZGVkRG9tYWluO307XG5cbi8qKlxuICogUmVtb3ZlcyB0cmFpbGluZyBzbGFzaCBmcm9tIHVybFxuICogQHBhcmFtIHVybFxuICogQHJldHVybnMgdXJsXG4gKi9jb25zdCByZW1vdmVUcmFpbGluZ1NsYXNoZXM9dXJsPT51cmw/LmVuZHNXaXRoKCcvJyk/cmVtb3ZlVHJhaWxpbmdTbGFzaGVzKHVybC5zdWJzdHJpbmcoMCx1cmwubGVuZ3RoLTEpKTp1cmw7Y29uc3QgZ2V0RG9tYWluPXVybD0+e3RyeXtjb25zdCB1cmxPYmo9bmV3IFVSTCh1cmwpO3JldHVybiB1cmxPYmouaG9zdDt9Y2F0Y2goZXJyb3Ipe3JldHVybiBudWxsO319Oy8qKlxuICogR2V0IHRoZSByZWZlcnJpbmcgZG9tYWluIGZyb20gdGhlIHJlZmVycmVyIFVSTFxuICogQHBhcmFtIHJlZmVycmVyIFBhZ2UgcmVmZXJyZXJcbiAqIEByZXR1cm5zIFBhZ2UgcmVmZXJyaW5nIGRvbWFpblxuICovY29uc3QgZ2V0UmVmZXJyaW5nRG9tYWluPXJlZmVycmVyPT5nZXREb21haW4ocmVmZXJyZXIpPz8nJzsvKipcbiAqIEV4dHJhY3RzIFVUTSBwYXJhbWV0ZXJzIGZyb20gdGhlIFVSTFxuICogQHBhcmFtIHVybCBQYWdlIFVSTFxuICogQHJldHVybnMgVVRNIHBhcmFtZXRlcnNcbiAqL2NvbnN0IGV4dHJhY3RVVE1QYXJhbWV0ZXJzPXVybD0+e2NvbnN0IHJlc3VsdD17fTt0cnl7Y29uc3QgdXJsT2JqPW5ldyBVUkwodXJsKTtjb25zdCBVVE1fUFJFRklYPSd1dG1fJzt1cmxPYmouc2VhcmNoUGFyYW1zLmZvckVhY2goKHZhbHVlLHNQYXJhbSk9PntpZihzUGFyYW0uc3RhcnRzV2l0aChVVE1fUFJFRklYKSl7bGV0IHV0bVBhcmFtPXNQYXJhbS5zdWJzdHJpbmcoVVRNX1BSRUZJWC5sZW5ndGgpOy8vIE5vdCBzdXJlIHdoeSB3ZSdyZSBkb2luZyB0aGlzXG5pZih1dG1QYXJhbT09PSdjYW1wYWlnbicpe3V0bVBhcmFtPSduYW1lJzt9cmVzdWx0W3V0bVBhcmFtXT12YWx1ZTt9fSk7fWNhdGNoKGVycm9yKXsvLyBEbyBub3RoaW5nXG59cmV0dXJuIHJlc3VsdDt9Oy8qKlxuICogVG8gZ2V0IHRoZSBVUkwgdW50aWwgdGhlIGhhc2hcbiAqIEBwYXJhbSB1cmwgVGhlIGlucHV0IFVSTFxuICogQHJldHVybnMgVVJMIHVudGlsIHRoZSBoYXNoXG4gKi9jb25zdCBnZXRVcmxXaXRob3V0SGFzaD11cmw9PntsZXQgdXJsV2l0aG91dEhhc2g9dXJsO3RyeXtjb25zdCB1cmxPYmo9bmV3IFVSTCh1cmwpO3VybFdpdGhvdXRIYXNoPXVybE9iai5vcmlnaW4rdXJsT2JqLnBhdGhuYW1lK3VybE9iai5zZWFyY2g7fWNhdGNoKGVycm9yKXsvLyBEbyBub3RoaW5nXG59cmV0dXJuIHVybFdpdGhvdXRIYXNoO307XG5cbmNvbnN0IERFRkFVTFRfUFJFX0NPTlNFTlRfU1RPUkFHRV9TVFJBVEVHWT0nbm9uZSc7Y29uc3QgREVGQVVMVF9QUkVfQ09OU0VOVF9FVkVOVFNfREVMSVZFUllfVFlQRT0naW1tZWRpYXRlJztcblxuY29uc3QgaXNFcnJvclJlcG9ydGluZ0VuYWJsZWQ9c291cmNlQ29uZmlnPT5zb3VyY2VDb25maWc/LnN0YXRzQ29sbGVjdGlvbj8uZXJyb3JzPy5lbmFibGVkPT09dHJ1ZTtjb25zdCBpc01ldHJpY3NSZXBvcnRpbmdFbmFibGVkPXNvdXJjZUNvbmZpZz0+c291cmNlQ29uZmlnPy5zdGF0c0NvbGxlY3Rpb24/Lm1ldHJpY3M/LmVuYWJsZWQ9PT10cnVlO1xuXG4vKipcbiAqIFZhbGlkYXRlcyBhbmQgbm9ybWFsaXplcyB0aGUgY29uc2VudCBvcHRpb25zIHByb3ZpZGVkIGJ5IHRoZSB1c2VyXG4gKiBAcGFyYW0gb3B0aW9ucyBDb25zZW50IG9wdGlvbnMgcHJvdmlkZWQgYnkgdGhlIHVzZXJcbiAqIEByZXR1cm5zIFZhbGlkYXRlZCBhbmQgbm9ybWFsaXplZCBjb25zZW50IG9wdGlvbnNcbiAqL2NvbnN0IGdldFZhbGlkUG9zdENvbnNlbnRPcHRpb25zPW9wdGlvbnM9Pntjb25zdCB2YWxpZE9wdGlvbnM9e3NlbmRQYWdlRXZlbnQ6ZmFsc2UsdHJhY2tDb25zZW50OmZhbHNlLGRpc2NhcmRQcmVDb25zZW50RXZlbnRzOmZhbHNlfTtpZihpc09iamVjdExpdGVyYWxBbmROb3ROdWxsKG9wdGlvbnMpKXtjb25zdCBjbG9uZWRPcHRpb25zPWNsb25lKG9wdGlvbnMpO3ZhbGlkT3B0aW9ucy5zdG9yYWdlPWNsb25lZE9wdGlvbnMuc3RvcmFnZTtpZihpc0
15vbkVtcHR5T2JqZWN0KGNsb25lZE9wdGlvbnMuaW50ZWdyYXRpb25zKSl7dmFsaWRPcHRpb25zLmludGVncmF0aW9ucz1jbG9uZWRPcHRpb25zLmludGVncmF0aW9uczt9dmFsaWRPcHRpb25zLmRpc2NhcmRQcmVDb25zZW50RXZlbnRzPWNsb25lZE9wdGlvbnMuZGlzY2FyZFByZUNvbnNlbnRFdmVudHM9PT10cnVlO3ZhbGlkT3B0aW9ucy5zZW5kUGFnZUV2ZW50PWNsb25lZE9wdGlvbnMuc2VuZFBhZ2VFdmVudD09PXRydWU7dmFsaWRPcHRpb25zLnRyYWNrQ29uc2VudD1jbG9uZWRPcHRpb25zLnRyYWNrQ29uc2VudD09PXRydWU7aWYoaXNOb25FbXB0eU9iamVjdChjbG9uZWRPcHRpb25zLmNvbnNlbnRNYW5hZ2VtZW50KSl7Ly8gT3ZlcnJpZGUgZW5hYmxlZCB2YWx1ZSB3aXRoIHRoZSBjdXJyZW50IHN0YXRlIHZhbHVlXG52YWxpZE9wdGlvbnMuY29uc2VudE1hbmFnZW1lbnQ9bWVyZ2VEZWVwUmlnaHQoY2xvbmVkT3B0aW9ucy5jb25zZW50TWFuYWdlbWVudCx7ZW5hYmxlZDpzdGF0ZS5jb25zZW50cy5lbmFibGVkLnZhbHVlfSk7fX1yZXR1cm4gdmFsaWRPcHRpb25zO307LyoqXG4gKiBWYWxpZGF0ZXMgaWYgdGhlIGlucHV0IGlzIGEgdmFsaWQgY29uc2VudHMgZGF0YVxuICogQHBhcmFtIHZhbHVlIElucHV0IGNvbnNlbnRzIGRhdGFcbiAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGlucHV0IGlzIGEgdmFsaWQgY29uc2VudHMgZGF0YSBlbHNlIGZhbHNlXG4gKi9jb25zdCBpc1ZhbGlkQ29uc2VudHNEYXRhPXZhbHVlPT5pc05vbkVtcHR5T2JqZWN0KHZhbHVlKXx8QXJyYXkuaXNBcnJheSh2YWx1ZSk7LyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGNvcnJlc3BvbmRpbmcgcHJvdmlkZXIgYW5kIHBsdWdpbiBuYW1lIG9mIHRoZSBzZWxlY3RlZCBjb25zZW50IG1hbmFnZXIgZnJvbSB0aGUgc3VwcG9ydGVkIGNvbnNlbnQgbWFuYWdlcnNcbiAqIEBwYXJhbSBjb25zZW50TWFuYWdlbWVudE9wdHMgY29uc2VudCBtYW5hZ2VtZW50IG9wdGlvbnNcbiAqIEBwYXJhbSBsb2dnZXIgbG9nZ2VyIGluc3RhbmNlXG4gKiBAcmV0dXJucyBDb3JyZXNwb25kaW5nIHByb3ZpZGVyIGFuZCBwbHVnaW4gbmFtZSBvZiB0aGUgc2VsZWN0ZWQgY29uc2VudCBtYW5hZ2VyIGZyb20gdGhlIHN1cHBvcnRlZCBjb25zZW50IG1hbmFnZXJzXG4gKi9jb25zdCBnZXRDb25zZW50TWFuYWdlckluZm89KGNvbnNlbnRNYW5hZ2VtZW50T3B0cyxsb2dnZXIpPT57bGV0e3Byb3ZpZGVyfT1jb25zZW50TWFuYWdlbWVudE9wdHM7Y29uc3QgY29uc2VudE1hbmFnZXJQbHVnaW5OYW1lPXByb3ZpZGVyP0NvbnNlbnRNYW5hZ2Vyc1RvUGx1Z2luTmFtZU1hcFtwcm92aWRlcl06dW5kZWZpbmVkO2lmKHByb3ZpZGVyJiYhY29uc2VudE1hbmFnZXJQbHVnaW5OYW1lKXtsb2dnZXIuZXJyb3IoVU5TVVBQT1JURURfQ09OU0VOVF9NQU5BR0VSX0VSUk9SKENPTkZJR19NQU5BR0VSLHByb3ZpZGVyLENvbnNlbnRNYW5hZ2Vyc1RvUGx1Z2luTmFtZU1hcCkpOy8vIFJlc2V0IHRoZSBwcm92aWRlciB2YWx1ZVxucHJvdmlkZXI9dW5kZWZpbmVkO31yZXR1cm4ge3Byb3ZpZGVyLGNvbnNlbnRNYW5hZ2VyUGx1Z2luTmFtZX07fTsvKipcbiAqIFZhbGlkYXRlcyBhbmQgY29udmVydHMgdGhlIGNvbnNlbnQgbWFuYWdlbWVudCBvcHRpb25zIGludG8gYSBub3JtYWxpemVkIGZvcm1hdFxuICogQHBhcmFtIGNvbnNlbnRNYW5hZ2VtZW50T3B0cyBDb25zZW50IG1hbmFnZW1lbnQgb3B0aW9ucyBwcm92aWRlZCBieSB0aGUgdXNlclxuICogQHBhcmFtIGxvZ2dlciBsb2dnZXIgaW5zdGFuY2VcbiAqIEByZXR1cm5zIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjb25zZW50IG1hbmFnZXIgcGx1Z2luIG5hbWUsIGluaXRpYWxpemVkLCBlbmFibGVkIGFuZCBjb25zZW50cyBkYXRhXG4gKi9jb25zdCBnZXRDb25zZW50TWFuYWdlbWVudERhdGE9KGNvbnNlbnRNYW5hZ2VtZW50T3B0cyxsb2dnZXIpPT57bGV0IGNvbnNlbnRNYW5hZ2VyUGx1Z2luTmFtZTtsZXQgYWxsb3dlZENvbnNlbnRJZHM9W107bGV0IGRlbmllZENvbnNlbnRJZHM9W107bGV0IGluaXRpYWxpemVkPWZhbHNlO2xldCBwcm92aWRlcjtsZXQgZW5hYmxlZD1jb25zZW50TWFuYWdlbWVudE9wdHM/LmVuYWJsZWQ9PT10cnVlO2lmKGlzTm9uRW1wdHlPYmplY3QoY29uc2VudE1hbmFnZW1lbnRPcHRzKSYmZW5hYmxlZCl7Ly8gR2V0IHRoZSBjb3JyZXNwb25kaW5nIHBsdWdpbiBuYW1lIG9mIHRoZSBzZWxlY3RlZCBjb25zZW50IG1hbmFnZXIgZnJvbSB0aGUgc3VwcG9ydGVkIGNvbnNlbnQgbWFuYWdlcnNcbih7cHJvdmlkZXIsY29uc2VudE1hbmFnZXJQbHVnaW5OYW1lfT1nZXRDb25zZW50TWFuYWdlckluZm8oY29uc2VudE1hbmFnZW1lbnRPcHRzLGxvZ2dlcikpO2lmKGlzVmFsaWRDb25zZW50c0RhdGEoY29uc2VudE1hbmFnZW1lbnRPcHRzLmFsbG93ZWRDb25zZW50SWRzKSl7YWxsb3dlZENvbnNlbnRJZHM9Y29uc2VudE1hbmFnZW1lbnRPcHRzLmFsbG93ZWRDb25zZW50SWRzO2luaXRpYWxpemVkPXRydWU7fWlmKGlzVmFsaWRDb25zZW50c0RhdGEoY29uc2VudE1hbmFnZW1lbnRPcHRzLmRlbmllZENvbnNlbnRJZHMpKXtkZW5pZWRDb25zZW50SWRzPWNvbnNlbnRNYW5hZ2VtZW50T3B0cy5kZW5pZWRDb25zZW50SWRzO2luaXRpYWxpemVkPXRydWU7fX1jb25zdCBjb25zZW50c0RhdGE9e2FsbG93ZWRDb25zZW50SWRzLGRlbmllZENvbnNlbnRJZHN9Oy8vIEVuYWJsZSBjb25zZW50IG1hbmFnZW1lbnQgb25seSBpZiBjb25zZW50IG1hbmFnZXIgaXMgc3VwcG9ydGVkXG5lbmFibGVkPWVuYWJsZWQmJkJvb2xlYW4oY29uc2VudE1hbmFnZXJQbHVnaW5OYW1lKTtyZXR1cm4ge3Byb3ZpZGVyLGNvbnNlbnRNYW5hZ2VyUGx1Z2luTmFtZSxpbml0aWFsaXplZCxlbmFibGVkLGNvbnNlbnRzRGF0YX07fTtcblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSBTREsgVVJMXG4gKiBAcmV0dXJucyBzZGtVUkxcbiAqL2NvbnN0IGdldFNES1VybD0oKT0+ey8vIEZpcnN0IHRyeSB0aGUgbmV3IG1ldGhvZCBvZiBnZXR0aW5nIHRoZSBTREsgVVJMXG4vLyBmcm9tIHRoZSBzY3JpcHQgdGFnXG5jb25zdCBzY3JpcHRUYWc9ZG9jdW1lbnQucXVlcnlTZWxlY3Rvcignc2NyaXB0W2RhdGEtcnNhLXdyaXRlLWtleV0nKTtpZihzY3JpcHRUYWcmJnNjcmlwdFRhZy5kYXRhc2V0LnJzYVdyaXRlS2V5PT09c3RhdGUubGlmZWN5Y2xlLndyaXRlS2V5LnZhbHVlKXtyZXR1cm4gc2NyaXB0VGFnLnNyYzt9Ly8gSWYgdGhlIG5ldyBtZXRob2QgZmFpbHMsIHRyeSB0aGUgb2xkIG1ldGhvZFxuLy8gVE9ETzogV2UgbmVlZCB0byByZW1vdmUgdGhpcyBvbmNlIGFsbCB0aGUgY3VzdG9tZXJzIHVwZ3JhZGUgdG8gdGhlXG4vLyBsYXRlc3QgU0RLIGxvYWRpbmcgc25pcHBldFxuY29uc3Qgc2NyaXB0cz1kb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7Y29uc3Qgc2RrRmlsZU5hbWVSZWdleD0vKD86XnxcXC8pcnNhKFxcLm1pbik/XFwuanMkLzsvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcmVzdHJpY3RlZC1zeW50YXhcbmZvcihjb25zdCBzY3JpcHQgb2Ygc2NyaXB0cyl7Y29uc3Qgc3JjPXNjcmlwdC5nZXRBdHRyaWJ1dGUoJ3NyYycpO2lmKHNyYyYmc2RrRmlsZU5hbWVSZWdleC50ZXN0KHNyYykpe3JldHVybiBzcmM7fX1yZXR1cm4gdW5kZWZpbmVkO307LyoqXG4gKiBVcGRhdGVzIHRoZSByZXBvcnRpbmcgc3RhdGUgdmFyaWFibGVzIGZyb20gdGhlIHNvdXJjZSBjb25maWcgZGF0YVxuICogQHBhcmFtIHJlcyBTb3VyY2UgY29uZmlnXG4gKiBAcGFyYW0gbG9nZ2VyIExvZ2dlciBpbnN0YW5jZVxuICovY29uc3QgdXBkYXRlUmVwb3J0aW5nU3RhdGU9cmVzPT57c3RhdGUucmVwb3J0aW5nLmlzRXJyb3JSZXBvcnRpbmdFbmFibGVkLnZhbHVlPWlzRXJyb3JSZXBvcnRpbmdFbmFibGVkKHJlcy5zb3VyY2UuY29uZmlnKSYmIWlzU0RLUnVubmluZ0luQ2hyb21lRXh0ZW5zaW9uKCk7c3R
1hdGUucmVwb3J0aW5nLmlzTWV0cmljc1JlcG9ydGluZ0VuYWJsZWQudmFsdWU9aXNNZXRyaWNzUmVwb3J0aW5nRW5hYmxlZChyZXMuc291cmNlLmNvbmZpZyk7fTtjb25zdCBnZXRTZXJ2ZXJTaWRlQ29va2llc1N0YXRlRGF0YT1sb2dnZXI9Pntjb25zdHt1c2VTZXJ2ZXJTaWRlQ29va2llcyxkYXRhU2VydmljZUVuZHBvaW50LHN0b3JhZ2U6c3RvcmFnZU9wdHNGcm9tTG9hZCxzZXRDb29raWVEb21haW4sc2FtZURvbWFpbkNvb2tpZXNPbmx5fT1zdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZTtsZXQgY29va2llT3B0aW9ucz1zdG9yYWdlT3B0c0Zyb21Mb2FkPy5jb29raWU7bGV0IHNzY0VuYWJsZWQ9ZmFsc2U7bGV0IGZpbmFsRGF0YVNlcnZpY2VVcmw7aWYodXNlU2VydmVyU2lkZUNvb2tpZXMpe3NzY0VuYWJsZWQ9dXNlU2VydmVyU2lkZUNvb2tpZXM7Y29uc3QgcHJvdmlkZWRDb29raWVEb21haW49Y29va2llT3B0aW9ucy5kb21haW4/P3NldENvb2tpZURvbWFpbjsvKipcbiAgICAgKiBCYXNlZCBvbiB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnMsIHdlIGRlY2lkZSB3aGV0aGVyIHRvIHVzZSB0aGUgZXhhY3QgZG9tYWluIG9yIG5vdCB0byBkZXRlcm1pbmUgdGhlIGRhdGEgc2VydmljZSBVUkw6XG4gICAgICogMS4gSWYgdGhlIGNvb2tpZSBkb21haW4gaXMgcHJvdmlkZWQgYW5kIGl0IGlzIG5vdCBhIHRvcC1sZXZlbCBkb21haW4sIHRoZW4gdXNlIHRoZSBleGFjdCBkb21haW5cbiAgICAgKiAyLiBJZiB0aGUgc2FtZURvbWFpbkNvb2tpZXNPbmx5IGZsYWcgaXMgc2V0IHRvIHRydWUsIHRoZW4gdXNlIHRoZSBleGFjdCBkb21haW5cbiAgICAgKi9jb25zdCB1c2VFeGFjdERvbWFpbj1pc0RlZmluZWQocHJvdmlkZWRDb29raWVEb21haW4pJiYhaXNXZWJwYWdlVG9wTGV2ZWxEb21haW4ocmVtb3ZlTGVhZGluZ1BlcmlvZChwcm92aWRlZENvb2tpZURvbWFpbikpfHxzYW1lRG9tYWluQ29va2llc09ubHk7Y29uc3QgZGF0YVNlcnZpY2VVcmw9Z2V0RGF0YVNlcnZpY2VVcmwoZGF0YVNlcnZpY2VFbmRwb2ludD8/REVGQVVMVF9EQVRBX1NFUlZJQ0VfRU5EUE9JTlQsdXNlRXhhY3REb21haW4pO2lmKGlzVmFsaWRVUkwoZGF0YVNlcnZpY2VVcmwpKXtmaW5hbERhdGFTZXJ2aWNlVXJsPXJlbW92ZVRyYWlsaW5nU2xhc2hlcyhkYXRhU2VydmljZVVybCk7Y29uc3QgY3VySG9zdD1nZXREb21haW4od2luZG93LmxvY2F0aW9uLmhyZWYpO2NvbnN0IGRhdGFTZXJ2aWNlSG9zdD1nZXREb21haW4oZGF0YVNlcnZpY2VVcmwpOy8vIElmIHRoZSBjdXJyZW50IGhvc3QgaXMgZGlmZmVyZW50IGZyb20gdGhlIGRhdGEgc2VydmljZSBob3N0LCB0aGVuIGl0IGlzIGEgY3Jvc3Mtc2l0ZSByZXF1ZXN0XG4vLyBGb3Igc2VydmVyLXNpZGUgY29va2llcyB0byB3b3JrLCB3ZSBuZWVkIHRvIHNldCB0aGUgU2FtZVNpdGU9Tm9uZSBhbmQgU2VjdXJlIGF0dHJpYnV0ZXNcbi8vIE9uZSByb3VuZCBvZiBjb29raWUgb3B0aW9ucyBtYW5pcHVsYXRpb24gaXMgdGFraW5nIHBsYWNlIGhlcmVcbi8vIEJhc2VkIG9uIHRoZXNlKHNldENvb2tpZURvbWFpbi9zdG9yYWdlLmNvb2tpZSBvciBzYW1lRG9tYWluQ29va2llc09ubHkpIHR3byBsb2FkLW9wdGlvbnMsIGZpbmFsIGNvb2tpZSBvcHRpb25zIGFyZSBzZXQgaW4gdGhlIHN0b3JhZ2UgbW9kdWxlXG4vLyBUT0RPOiBSZWZhY3RvciB0aGUgY29va2llIG9wdGlvbnMgbWFuaXB1bGF0aW9uIGxvZ2ljIGluIG9uZSBwbGFjZVxuaWYoY3VySG9zdCE9PWRhdGFTZXJ2aWNlSG9zdCl7Y29va2llT3B0aW9ucz17Li4uY29va2llT3B0aW9ucyxzYW1lc2l0ZTonTm9uZScsc2VjdXJlOnRydWV9O30vKipcbiAgICAgICAqIElmIHRoZSBzYW1lRG9tYWluQ29va2llc09ubHkgZmxhZyBpcyBub3Qgc2V0IGFuZCB0aGUgY29va2llIGRvbWFpbiBpcyBwcm92aWRlZChub3QgdG9wIGxldmVsIGRvbWFpbiksXG4gICAgICAgKiBhbmQgdGhlIGRhdGEgc2VydmljZSBob3N0IGlzIGRpZmZlcmVudCBmcm9tIHRoZSBwcm92aWRlZCBjb29raWUgZG9tYWluLCB0aGVuIHdlIGRpc2FibGUgc2VydmVyLXNpZGUgY29va2llc1xuICAgICAgICogZXg6IHByb3ZpZGVkIGNvb2tpZSBkb21haW46ICdyYW5kb20uY29tJywgZGF0YSBzZXJ2aWNlIGhvc3Q6ICdzdWIuZXhhbXBsZS5jb20nXG4gICAgICAgKi9pZighc2FtZURvbWFpbkNvb2tpZXNPbmx5JiZ1c2VFeGFjdERvbWFpbiYmZGF0YVNlcnZpY2VIb3N0IT09cmVtb3ZlTGVhZGluZ1BlcmlvZChwcm92aWRlZENvb2tpZURvbWFpbikpe3NzY0VuYWJsZWQ9ZmFsc2U7bG9nZ2VyLndhcm4oU0VSVkVSX1NJREVfQ09PS0lFX0ZFQVRVUkVfT1ZFUlJJREVfV0FSTklORyhDT05GSUdfTUFOQUdFUixwcm92aWRlZENvb2tpZURvbWFpbixkYXRhU2VydmljZUhvc3QpKTt9fWVsc2Uge3NzY0VuYWJsZWQ9ZmFsc2U7fX1yZXR1cm4ge3NzY0VuYWJsZWQsY29va2llT3B0aW9ucyxmaW5hbERhdGFTZXJ2aWNlVXJsfTt9O2NvbnN0IHVwZGF0ZVN0b3JhZ2VTdGF0ZUZyb21Mb2FkT3B0aW9ucz1sb2dnZXI9Pntjb25zdHtzdG9yYWdlOnN0b3JhZ2VPcHRzRnJvbUxvYWR9PXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlO2xldCBzdG9yYWdlVHlwZT1zdG9yYWdlT3B0c0Zyb21Mb2FkPy50eXBlO2lmKGlzRGVmaW5lZChzdG9yYWdlVHlwZSkmJiFpc1ZhbGlkU3RvcmFnZVR5cGUoc3RvcmFnZVR5cGUpKXtsb2dnZXIud2FybihTVE9SQUdFX1RZUEVfVkFMSURBVElPTl9XQVJOSU5HKENPTkZJR19NQU5BR0VSLHN0b3JhZ2VUeXBlLERFRkFVTFRfU1RPUkFHRV9UWVBFKSk7c3RvcmFnZVR5cGU9REVGQVVMVF9TVE9SQUdFX1RZUEU7fWxldCBzdG9yYWdlRW5jcnlwdGlvblZlcnNpb249c3RvcmFnZU9wdHNGcm9tTG9hZD8uZW5jcnlwdGlvbj8udmVyc2lvbjtjb25zdCBlbmNyeXB0aW9uUGx1Z2luTmFtZT1zdG9yYWdlRW5jcnlwdGlvblZlcnNpb24mJlN0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbnNUb1BsdWdpbk5hbWVNYXBbc3RvcmFnZUVuY3J5cHRpb25WZXJzaW9uXTtpZighaXNVbmRlZmluZWQoc3RvcmFnZUVuY3J5cHRpb25WZXJzaW9uKSYmaXNVbmRlZmluZWQoZW5jcnlwdGlvblBsdWdpbk5hbWUpKXsvLyBzZXQgdGhlIGRlZmF1bHQgZW5jcnlwdGlvbiBwbHVnaW5cbmxvZ2dlci53YXJuKFVOU1VQUE9SVEVEX1NUT1JBR0VfRU5DUllQVElPTl9WRVJTSU9OX1dBUk5JTkcoQ09ORklHX01BTkFHRVIsc3RvcmFnZUVuY3J5cHRpb25WZXJzaW9uLFN0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbnNUb1BsdWdpbk5hbWVNYXAsREVGQVVMVF9TVE9SQUdFX0VOQ1JZUFRJT05fVkVSU0lPTikpO3N0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbj1ERUZBVUxUX1NUT1JBR0VfRU5DUllQVElPTl9WRVJTSU9OO31lbHNlIGlmKGlzVW5kZWZpbmVkKHN0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbikpe3N0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbj1ERUZBVUxUX1NUT1JBR0VfRU5DUllQVElPTl9WRVJTSU9OO30vLyBBbGxvdyBtaWdyYXRpb24gb25seSBpZiB0aGUgY29uZmlndXJlZCBlbmNyeXB0aW9uIHZlcnNpb24gaXMgdGhlIGRlZmF1bHQgZW5jcnlwdGlvbiB2ZXJzaW9uXG5jb25zdCBjb25maWd1cmVkTWlncmF0aW9uVmFsdWU9c3RvcmFnZU9wdHNGcm9tTG9hZD8ubWlncmF0ZTtjb25zdCBmaW5hbE1pZ3JhdGlvblZhbD1jb25maWd1cmVkTWlncmF0aW9uVmFsdWUmJnN0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbj09PURFRkFVTFRfU1RPUkFHRV9FTkNSWVBUSU9OX1ZFUlNJT047aWYoY29uZmlndXJlZE1pZ3JhdGlvblZhbHVlPT09dHJ1ZSYmZmluYWxNaWdyYXRpb25WYWwhPT1jb25maWd1cmVkTWlncmF0aW9uVmFsdWUpe2xvZ2dlci53YXJuKFNUT1JBR0VfREFUQV9NSUdSQVRJT05fT1ZFUlJJREVfV0FSTklORyhDT05GSUdfTUFOQUdFUixzdG9yYWdlRW5jcnlwdGlvblZlcnNpb24sREVGQVVMVF9TVE9SQUdFX0VOQ1JZUFRJT05fVkVSU0lPTikpO31jb25zdHtzc2NFbmFibGVkLGZpbmFsRGF0YVNlcnZpY2VVcmwsY29va2llT3B0aW9uc309Z2V0U2VydmVyU2lkZUNvb2tpZXNTdGF0ZURhdGEobG9nZ2VyKTtuKCgpPT57c3RhdGUuc3RvcmFnZS50eXBlLnZhbHVlPXN0b3JhZ2VUeXBlO3N0YXRlLnN0b3JhZ2UuY29va2llLnZhbHVlPWNvb2tpZU9wdGlvbnM7c3RhdGUuc2VydmVyQ29va2llcy5pc0VuYWJsZWRTZXJ2ZXJTaWRlQ29va2llcy52YWx1ZT1zc2NFbmFibGVkO3N0YXRlLnNlcnZlckNvb2tpZXMuZGF0YVNlcnZpY2VVcmwudmFsdWU9ZmluYWxEYXRhU2VydmljZVVybDtzdGF0ZS5zdG9yYWdlLmVuY3J5cHRpb25QbHVnaW5OYW1lLnZhbHVlPVN0b3JhZ2VFbmNyeXB0aW9uVmVyc2lvbnNUb1BsdWdpbk5hbWVNYXBbc3RvcmFnZUVuY3J5cHRpb25WZXJzaW9uXTtzdGF0ZS5zdG9yYWdlLm1pZ3JhdGUudmFsdWU9ZmluYWxNaWdyYXRpb25WYWw7fSk7fTtjb25zdCB1cGRhdGVDb25zZW50c1N0YXRlRnJvbUxvYWRPcHRpb25zPWxvZ2dlcj0+e2NvbnN0e3Byb3ZpZGVyLGNvbnNlbnRNYW5hZ2VyUGx1Z2luTmFtZSxpbml0aWFsaXplZCxlbmFibGVkLGNvbnNlbnRzRGF0YX09Z2V0Q29uc2VudE1hbmFnZW1lbnREYXRhKHN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLmNvbnNlbnRNYW5hZ2VtZW50LGxvZ2dlcik7Ly8gUHJlLWNvbnNlbnRcbmNvbnN0IHByZUNvbnNlbnRPcHRzPXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnByZUNvbnNlbnQ7bGV0IHN0b3JhZ2VTdHJhdGVneT1wcmVDb25zZW50T3B0cz8uc3RvcmFnZT8uc3RyYXRlZ3k/P0RFRkFVTFRfUFJFX0NPTlNFTlRfU1RPUkFHRV9TVFJBVEVHWTtjb25zdCBTdG9yYWdlU3RyYXRlZ2llcz1bJ25vbmUnLCdzZXNzaW9uJywnYW5vbnltb3VzSWQnXTtpZihpc0RlZmluZWQoc3RvcmFnZVN0cmF0ZWd5KSYmIVN0b3JhZ2VTdHJhdGVnaWVzLmluY2x1ZGVzKHN0b3JhZ2VTdHJhdGVneSkpe3N0b3JhZ2VTdHJhdGVneT1ERUZBVUxUX1BSRV9DT05TRU5UX1NUT1JBR0VfU1RSQVRFR1k7bG9nZ2VyLndhcm4oVU5TVVBQT1JURURfUFJFX0NPTlNFTlRfU1RPUkFHRV9TVFJBVEVHWShDT05GSUdfTUFOQUdFUixwcmVDb25zZW50T3B0cz8uc3RvcmFnZT8uc3RyYXRlZ3ksREVGQVVMVF9QUkVfQ09OU0VOVF9TVE9SQUdFX1NUUkFURUdZKSk7fWxldCBldmVudHNEZWxpdmVyeVR5cGU9cHJlQ29uc2VudE9wdHM/LmV2ZW50cz8uZGVsaXZlcnk/P0RFRkFVTFRfUFJFX0NPTlNFTlRfRVZFTlRTX0RFTElWRVJZX1RZUEU7Y29uc3QgZGVsaXZlcnlUeXBlcz1bJ2ltbWVkaWF0ZScsJ2J1ZmZlciddO2lmKGlzRGVmaW5lZChldmVudHNEZWxpdmVyeVR5cGUpJiYhZGVsaXZlcnlUeXBlcy5pbmNsdWRlcyhldmVudHNEZWxpdmVyeVR5cGUpKXtldmVudHNEZWxpdmVyeVR5cGU9REVGQVVMVF9QUkVfQ09OU0VOVF9FVkVOVFNfREVMSVZFUllfVFlQRTtsb2dnZXIud2FybihVTlNVUFBPUlRFRF9QUkVfQ09OU0VOVF9FVkVOVFNfREVMSVZFUllfVFlQRShDT05GSUdfTUFOQUdFUixwcmVDb25zZW50T3B0cz8uZXZlbnRzPy5kZWxpdmVyeSxERUZBVUxUX1BSRV9DT05TRU5UX0VWRU5UU19ERUxJVkVSWV9UWVBFKSk7fW4oKCk9PntzdGF0ZS5jb25zZW50cy5hY3RpdmVDb25zZW50TWFuYWdlclBsdWdpbk5hbWUudmFsdWU9Y29uc2VudE1hbmFnZXJQbHVnaW5OYW1lO3N0YXRlLmNvbnNlbnRzLmluaXRpYWxpemVkLnZhbHVlPWluaXRpYWxpemVkO3N0YXRlLmNvbnNlbnRzLmVuYWJsZWQudmFsdWU9ZW5hYmxlZDtzdGF0ZS5jb25zZW50cy5kYXRhLnZhbHVlPWNvbnNlbnRzRGF0YTtzdGF0ZS5jb25zZW50cy5wcm92aWRlci52YWx1ZT1wcm92aWRlcjtzdGF0ZS5jb25zZW50cy5wcmVDb25zZW50LnZhbHVlPXsvLyBPbmx5IGVuYWJsZSBwcmUtY29uc2VudCBpZiBpdCBpcyBleHBsaWNpdGx5IGVuYWJsZWQgYW5kXG4vLyBpZiBpdCBpcyBub3QgYWxyZWFkeSBpbml0aWFsaXplZCBhbmRcbi8vIGlmIGNvbnNlbnQgbWFuYWdlbWVudCBpcyBlbmFibGVkXG5lbmFibGVkOnN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnByZUNvbnNlbnQ/LmVuYWJsZWQ9PT10cnVlJiZpbml0aWFsaXplZD09PWZhbHNlJiZlbmFibGVkPT09dHJ1ZSxzdG9yYWdlOntzdHJhdGVneTpzdG9yYWdlU3RyYXRlZ3l9LGV2ZW50czp7ZGVsaXZlcnk6ZXZlbn
1RzRGVsaXZlcnlUeXBlfX07fSk7fTsvKipcbiAqIERldGVybWluZXMgdGhlIGNvbnNlbnQgbWFuYWdlbWVudCBzdGF0ZSB2YXJpYWJsZXMgZnJvbSB0aGUgc291cmNlIGNvbmZpZyBkYXRhXG4gKiBAcGFyYW0gcmVzcCBTb3VyY2UgY29uZmlnIHJlc3BvbnNlXG4gKiBAcGFyYW0gbG9nZ2VyIExvZ2dlciBpbnN0YW5jZVxuICovY29uc3QgdXBkYXRlQ29uc2VudHNTdGF0ZT1yZXNwPT57bGV0IHJlc29sdXRpb25TdHJhdGVneT1zdGF0ZS5jb25zZW50cy5yZXNvbHV0aW9uU3RyYXRlZ3kudmFsdWU7bGV0IGNtcE1ldGFkYXRhO2lmKGlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwocmVzcC5jb25zZW50TWFuYWdlbWVudE1ldGFkYXRhKSl7aWYoc3RhdGUuY29uc2VudHMucHJvdmlkZXIudmFsdWUpe3Jlc29sdXRpb25TdHJhdGVneT1yZXNwLmNvbnNlbnRNYW5hZ2VtZW50TWV0YWRhdGEucHJvdmlkZXJzLmZpbmQocD0+cC5wcm92aWRlcj09PXN0YXRlLmNvbnNlbnRzLnByb3ZpZGVyLnZhbHVlKT8ucmVzb2x1dGlvblN0cmF0ZWd5Pz9zdGF0ZS5jb25zZW50cy5yZXNvbHV0aW9uU3RyYXRlZ3kudmFsdWU7fWNtcE1ldGFkYXRhPXJlc3AuY29uc2VudE1hbmFnZW1lbnRNZXRhZGF0YTt9Ly8gSWYgdGhlIHByb3ZpZGVyIGlzIGN1c3RvbSwgdGhlbiB0aGUgcmVzb2x1dGlvbiBzdHJhdGVneSBpcyBub3QgYXBwbGljYWJsZVxuaWYoc3RhdGUuY29uc2VudHMucHJvdmlkZXIudmFsdWU9PT0nY3VzdG9tJyl7cmVzb2x1dGlvblN0cmF0ZWd5PXVuZGVmaW5lZDt9bigoKT0+e3N0YXRlLmNvbnNlbnRzLm1ldGFkYXRhLnZhbHVlPWNsb25lKGNtcE1ldGFkYXRhKTtzdGF0ZS5jb25zZW50cy5yZXNvbHV0aW9uU3RyYXRlZ3kudmFsdWU9cmVzb2x1dGlvblN0cmF0ZWd5O30pO307Y29uc3QgdXBkYXRlRGF0YVBsYW5lRXZlbnRzU3RhdGVGcm9tTG9hZE9wdGlvbnM9bG9nZ2VyPT57aWYoc3RhdGUuZGF0YVBsYW5lRXZlbnRzLmRlbGl2ZXJ5RW5hYmxlZC52YWx1ZSl7Y29uc3QgZGVmYXVsdEV2ZW50c1F1ZXVlUGx1Z2luTmFtZT0nWGhyUXVldWUnO2xldCBldmVudHNRdWV1ZVBsdWdpbk5hbWU9ZGVmYXVsdEV2ZW50c1F1ZXVlUGx1Z2luTmFtZTtpZihzdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZS51c2VCZWFjb24pe2lmKHN0YXRlLmNhcGFiaWxpdGllcy5pc0JlYWNvbkF2YWlsYWJsZS52YWx1ZSl7ZXZlbnRzUXVldWVQbHVnaW5OYW1lPSdCZWFjb25RdWV1ZSc7fWVsc2Uge2V2ZW50c1F1ZXVlUGx1Z2luTmFtZT1kZWZhdWx0RXZlbnRzUXVldWVQbHVnaW5OYW1lO2xvZ2dlci53YXJuKFVOU1VQUE9SVEVEX0JFQUNPTl9BUElfV0FSTklORyhDT05GSUdfTUFOQUdFUikpO319bigoKT0+e3N0YXRlLmRhdGFQbGFuZUV2ZW50cy5ldmVudHNRdWV1ZVBsdWdpbk5hbWUudmFsdWU9ZXZlbnRzUXVldWVQbHVnaW5OYW1lO30pO319O2NvbnN0IGdldFNvdXJjZUNvbmZpZ1VSTD0oY29uZmlnVXJsLHdyaXRlS2V5LGxvY2tJbnRlZ3JhdGlvbnNWZXJzaW9uLGxvY2tQbHVnaW5zVmVyc2lvbixsb2dnZXIpPT57Y29uc3QgZGVmU2VhcmNoUGFyYW1zPW5ldyBVUkxTZWFyY2hQYXJhbXMoe3A6TU9EVUxFX1RZUEUsdjpBUFBfVkVSU0lPTixidWlsZDpCVUlMRF9UWVBFLHdyaXRlS2V5LGxvY2tJbnRlZ3JhdGlvbnNWZXJzaW9uOmxvY2tJbnRlZ3JhdGlvbnNWZXJzaW9uLnRvU3RyaW5nKCksbG9ja1BsdWdpbnNWZXJzaW9uOmxvY2tQbHVnaW5zVmVyc2lvbi50b1N0cmluZygpfSk7bGV0IG9yaWdpbj1ERUZBVUxUX0NPTkZJR19CRV9VUkw7bGV0IHNlYXJjaFBhcmFtcz1kZWZTZWFyY2hQYXJhbXM7bGV0IHBhdGhuYW1lPScvc291cmNlQ29uZmlnLyc7bGV0IGhhc2g9Jyc7aWYoaXNWYWxpZFVSTChjb25maWdVcmwpKXtjb25zdCBjb25maWdVcmxJbnN0YW5jZT1uZXcgVVJMKGNvbmZpZ1VybCk7aWYoIXJlbW92ZVRyYWlsaW5nU2xhc2hlcyhjb25maWdVcmxJbnN0YW5jZS5wYXRobmFtZSkuZW5kc1dpdGgoJy9zb3VyY2VDb25maWcnKSl7Y29uZmlnVXJsSW5zdGFuY2UucGF0aG5hbWU9YCR7cmVtb3ZlVHJhaWxpbmdTbGFzaGVzKGNvbmZpZ1VybEluc3RhbmNlLnBhdGhuYW1lKX0vc291cmNlQ29uZmlnL2A7fWNvbmZpZ1VybEluc3RhbmNlLnBhdGhuYW1lPXJlbW92ZUR1cGxpY2F0ZVNsYXNoZXMoY29uZmlnVXJsSW5zdGFuY2UucGF0aG5hbWUpO2RlZlNlYXJjaFBhcmFtcy5mb3JFYWNoKCh2YWx1ZSxrZXkpPT57aWYoY29uZmlnVXJsSW5zdGFuY2Uuc2VhcmNoUGFyYW1zLmdldChrZXkpPT09bnVsbCl7Y29uZmlnVXJsSW5zdGFuY2Uuc2VhcmNoUGFyYW1zLnNldChrZXksdmFsdWUpO319KTtvcmlnaW49Y29uZmlnVXJsSW5zdGFuY2Uub3JpZ2luO3BhdGhuYW1lPWNvbmZpZ1VybEluc3RhbmNlLnBhdGhuYW1lO3NlYXJjaFBhcmFtcz1jb25maWdVcmxJbnN0YW5jZS5zZWFyY2hQYXJhbXM7aGFzaD1jb25maWdVcmxJbnN0YW5jZS5oYXNoO31lbHNlIHtsb2dnZXIud2FybihJTlZBTElEX0NPTkZJR19VUkxfV0FSTklORyhDT05GSUdfTUFOQUdFUixjb25maWdVcmwpKTt9cmV0dXJuIGAke29yaWdpbn0ke3BhdGhuYW1lfT8ke3NlYXJjaFBhcmFtc30ke2hhc2h9YDt9Oy8qKlxuICogVHJhbnNmb3JtcyBkZXN0aW5hdGlvbnMgY29uZmlnIGZyb20gc291cmNlIGNvbmZpZyByZXNwb25zZSB0byBEZXN0aW5hdGlvbiBmb3JtYXRcbiAqIEBwYXJhbSBkZXN0aW5hdGlvbnMgQXJyYXkgb2YgZGVzdGluYXRpb24gaXRlbXMgZnJvbSBjb25maWcgcmVzcG9uc2VcbiAqIEByZXR1cm5zIEFycmF5IG9mIHRyYW5zZm9ybWVkIERlc3RpbmF0aW9uIG9iamVjdHNcbiAqL2NvbnN0IGdldERlc3RpbmF0aW9uc0Zyb21Db25maWc9ZGVzdGluYXRpb25zPT5kZXN0aW5hdGlvbnMubWFwKGRlc3RpbmF0aW9uPT4oe2lkOmRlc3RpbmF0aW9uLmlkLGRpc3BsYXlOYW1lOmRlc3RpbmF0aW9uLmRlc3RpbmF0aW9uRGVmaW5pdGlvbi5kaXNwbGF5TmFtZSxlbmFibGVkOmRlc3RpbmF0aW9uLmVuYWJsZWQsY29uZmlnOmRlc3RpbmF0aW9uLmNvbmZpZyxzaG91bGRBcHBseURldmljZU1vZGVUcmFuc2Zvcm1hdGlvbjpkZXN0aW5hdGlvbi5zaG91bGRBcHBseURldmljZU1vZGVUcmFuc2Zvcm1hdGlvbj8/ZmFsc2UscHJvcGFnYXRlRXZlbnRzVW50cmFuc2Zvcm1lZE9uRXJyb3I6ZGVzdGluYXRpb24ucHJvcGFnYXRlRXZlbnRzVW50cmFuc2Zvcm1lZE9uRXJyb3I/P2ZhbHNlLHVzZXJGcmllbmRseUlkOmdldERlc3RpbmF0aW9uVXNlckZyaWVuZGx5SWQoZGVzdGluYXRpb24uZGVzdGluYXRpb25EZWZpbml0aW9uLmRpc3BsYXlOYW1lLGRlc3RpbmF0aW9uLmlkKSxpc0N1c3RvbUludGVncmF0aW9uOmRlc3RpbmF0aW9uLmRlc3RpbmF0aW9uRGVmaW5pdGlvbi5kaXNwbGF5TmFtZT09PUNVU1RPTV9ERVZJQ0VfTU9E
1RV9ERVNUSU5BVElPTl9ESVNQTEFZX05BTUV9KSk7XG5cbi8qKlxuICogQSBmdW5jdGlvbiB0aGF0IGRldGVybWluZXMgdGhlIGJhc2UgVVJMIGZvciB0aGUgaW50ZWdyYXRpb25zIG9yIHBsdWdpbnMgU0RLXG4gKiBAcGFyYW0gY29tcG9uZW50VHlwZSBUaGUgdHlwZSBvZiB0aGUgY29tcG9uZW50IChpbnRlZ3JhdGlvbnMgb3IgcGx1Z2lucylcbiAqIEBwYXJhbSBwYXRoU3VmZml4IFRoZSBwYXRoIHN1ZmZpeCB0byBiZSBhcHBlbmRlZCB0byB0aGUgYmFzZSBVUkwgKGpzLWludGVncmF0aW9ucyBvciBwbHVnaW5zKVxuICogQHBhcmFtIGRlZmF1bHRDb21wb25lbnRVcmwgVGhlIGRlZmF1bHQgVVJMIHRvIGJlIHVzZWQgaWYgdGhlIHVzZXIgaGFzIG5vdCBwcm92aWRlZCBhIGN1c3RvbSBVUkxcbiAqIEBwYXJhbSBjdXJyZW50U2RrVmVyc2lvbiBUaGUgY3VycmVudCB2ZXJzaW9uIG9mIHRoZSBTREtcbiAqIEBwYXJhbSBsb2NrVmVyc2lvbiBGbGFnIHRvIGxvY2sgdGhlIHZlcnNpb24gb2YgdGhlIGNvbXBvbmVudFxuICogQHBhcmFtIHVybEZyb21Mb2FkT3B0aW9ucyBUaGUgVVJMIHByb3ZpZGVkIGJ5IHRoZSB1c2VyIGluIHRoZSBsb2FkIG9wdGlvbnNcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gKiBAcmV0dXJucyBUaGUgYmFzZSBVUkwgZm9yIHRoZSBpbnRlZ3JhdGlvbnMgb3IgcGx1Z2lucyBTREtcbiAqL2NvbnN0IGdldFNES0NvbXBvbmVudEJhc2VVUkw9KGNvbXBvbmVudFR5cGUscGF0aFN1ZmZpeCxkZWZhdWx0Q29tcG9uZW50VXJsLGN1cnJlbnRTZGtWZXJzaW9uLGxvY2tWZXJzaW9uLHVybEZyb21Mb2FkT3B0aW9ucyxsb2dnZXIpPT57bGV0IHNka0NvbXBvbmVudEJhc2VVUkw7Ly8gSWYgdGhlIHVzZXIgaGFzIHByb3ZpZGVkIGEgY3VzdG9tIFVSTCwgdGhlbiB2YWxpZGF0ZSwgY2xlYW4gdXAgYW5kIHVzZSBpdFxuaWYodXJsRnJvbUxvYWRPcHRpb25zKXtpZighaXNWYWxpZFVSTCh1cmxGcm9tTG9hZE9wdGlvbnMpKXtsb2dnZXIuZXJyb3IoQ09NUE9ORU5UX0JBU0VfVVJMX0VSUk9SKENPTkZJR19NQU5BR0VSLGNvbXBvbmVudFR5cGUsdXJs
1RnJvbUxvYWRPcHRpb25zKSk7cmV0dXJuIG51bGw7fXNka0NvbXBvbmVudEJhc2VVUkw9cmVtb3ZlVHJhaWxpbmdTbGFzaGVzKHVybEZyb21Mb2FkT3B0aW9ucyk7fWVsc2Uge3Nka0NvbXBvbmVudEJhc2VVUkw9ZGVmYXVsdENvbXBvbmVudFVybDsvLyBXZSBjYW4gYXV0b21hdGljYWxseSBkZXRlcm1pbmUgdGhlIGJhc2UgVVJMIG9ubHkgZm9yIENETiBpbnN0YWxsYXRpb25zXG5pZihzdGF0ZS5jb250ZXh0LmFwcC52YWx1ZS5pbnN0YWxsVHlwZT09PSdjZG4nKXtjb25zdCBzZGtVUkw9Z2V0U0RLVXJsKCk7aWYoc2RrVVJMKXsvLyBFeHRyYWN0IHRoZSBiYXNlIFVSTCBmcm9tIHRoZSBjb3JlIFNESyBmaWxlIFVSTFxuLy8gYW5kIGFwcGVuZCB0aGUgcGF0aCBzdWZmaXggdG8gaXRcbnNka0NvbXBvbmVudEJhc2VVUkw9c2RrVVJMLnNwbGl0KCcvJykuc2xpY2UoMCwtMSkuY29uY2F0KHBhdGhTdWZmaXgpLmpvaW4oJy8nKTt9fX0vLyBJZiB0aGUgdmVyc2lvbiBuZWVkcyB0byBiZSBsb2NrZWQsIHRoZW4gcmVwbGFjZSB0aGUgbWFqb3IgdmVyc2lvbiBpbiB0aGUgVVJMXG4vLyB3aXRoIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIFNES1xuaWYobG9ja1ZlcnNpb24pe3Nka0NvbXBvbmVudEJhc2VVUkw9c2RrQ29tcG9uZW50QmFzZVVSTC5yZXBsYWNlKG5ldyBSZWdFeHAoYC8ke0NETl9BUkNIX1ZFUlNJT05fRElSfS8ke0JVSUxEX1RZUEV9LyR7cGF0aFN1ZmZpeH0kYCksYC8ke2N1cnJlbnRTZGtWZXJzaW9ufS8ke0JVSUxEX1RZUEV9LyR7cGF0aFN1ZmZpeH1gKTt9cmV0dXJuIHNka0NvbXBvbmVudEJhc2VVUkw7fTsvKipcbiAqIEEgZnVuY3Rpb24gdGhhdCBkZXRlcm1pbmVzIGludGVncmF0aW9uIFNESyBsb2FkaW5nIHBhdGhcbiAqIEBwYXJhbSBjdXJyZW50U2RrVmVyc2lvbiBDdXJyZW50IFNESyB2ZXJzaW9uXG4gKiBAcGFyYW0gbG9ja0ludGVncmF0aW9uc1ZlcnNpb24gRmxhZyB0byBsb2NrIHRoZSBpbnRlZ3JhdGlvbnMgdmVyc2lvblxuICogQHBhcmFtIGludGVncmF0aW9uc1VybEZyb21Mb2FkT3B0aW9ucyBVUkwgdG8gbG9hZCB0aGUgaW50ZWdyYXRpb25zIGZyb20gYXMgcHJvdmlkZWQgYnkgdGhlIHVzZXJcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gKiBAcmV0dXJuc1xuICovY29uc3QgZ2V0SW50ZWdyYXRpb25zQ0ROUGF0aD0oY3VycmVudFNka1ZlcnNpb24sbG9ja0ludGVncmF0aW9uc1ZlcnNpb24saW50ZWdyYXRpb25zVXJsRnJvbUxvYWRPcHRpb25zLGxvZ2dlcik9PmdldFNES0NvbXBvbmVudEJhc2VVUkwoJ2ludGVncmF0aW9ucycsQ0ROX0lOVF9ESVIsREVGQVVMVF9JTlRFR1JBVElPTl9TREtTX1VSTCxjdXJyZW50U2RrVmVyc2lvbixsb2NrSW50ZWdyYXRpb25zVmVyc2lvbixpbnRlZ3JhdGlvbnNVcmxGcm9tTG9hZE9wdGlvbnMsbG9nZ2VyKTtcblxuY2xhc3MgQ29uZmlnTWFuYWdlcntjb25zdHJ1Y3RvcihodHRwQ2xpZW50LGVycm9ySGFuZGxlcixsb2dnZXIpe3RoaXMuZXJyb3JIYW5kbGVyPWVycm9ySGFuZGxlcjt0aGlzLmxvZ2dlcj1sb2dnZXI7dGhpcy5odHRwQ2xpZW50PWh0dHBDbGllbnQ7dGhpcy5vbkVycm9yPXRoaXMub25FcnJvci5iaW5kKHRoaXMpO3RoaXMucHJvY2Vzc0NvbmZpZz10aGlzLnByb2Nlc3NDb25maWcuYmluZCh0aGlzKTt9YXR0YWNoRWZmZWN0cygpe2ooKCk9Pnt0aGlzLmxvZ2dlci5zZXRNaW5Mb2dMZXZlbChzdGF0ZS5saWZlY3ljbGUubG9nTGV2ZWwudmFsdWUpO30pO30vKipcbiAgICogQSBmdW5jdGlvbiB0byB2YWxpZGF0ZSwgY29uc3RydWN0IGFuZCBzdG9yZSBsb2FkT3B0aW9uLCBsaWZlY3ljbGUsIHNvdXJjZSBhbmQgZGVzdGluYXRpb25cbiAgICogY29uZmlnIHJlbGF0ZWQgaW5mb3JtYXRpb24gaW4gZ2xvYmFsIHN0YXRlXG4gICAqL2luaXQoKXtjb25zdHtsb2dMZXZlbCxjb25maWdVcmwsbG9ja0ludGVncmF0aW9uc1ZlcnNpb24sbG9ja1BsdWdpbnNWZXJzaW9uLGRlc3RTREtCYXNlVVJMLHBsdWdpbnNTREtCYXNlVVJMLGludGVncmF0aW9uc309c3RhdGUubG9hZE9wdGlvbnMudmFsdWU7Ly8gZGV0ZXJtaW5lIHRoZSBwYXRoIHRvIGZldGNoIGludGVncmF0aW9uIFNESyBmcm9tXG5jb25zdCBpbnRnQ2RuVXJsPWdldEludGVncmF0aW9uc0NETlBhdGgoQVBQX1ZFUlNJT04sbG9ja0ludGVncmF0aW9uc1ZlcnNpb24sZGVzdFNES0Jhc2VVUkwsdGhpcy5sb2dnZXIpO2lmKGlzTnVsbChpbnRnQ2RuVXJsKSl7cmV0dXJuO31sZXQgcGx1Z2luc0NETlBhdGg7dGhpcy5hdHRhY2hFZmZlY3RzKCk7c3RhdGUubGlmZWN5Y2xlLmFjdGl2ZURhdGFwbGFuZVVybC52YWx1ZT1yZW1vdmVUcmFpbGluZ1NsYXNoZXMoc3RhdGUubGlmZWN5Y2xlLmRhdGFQbGFuZVVybC52YWx1ZSk7dXBkYXRlU3RvcmFnZVN0YXRlRnJvbUxvYWRPcHRpb25zKHRoaXMubG9nZ2VyKTt1cGRhdGVDb25zZW50c1N0YXRlRnJvbUxvYWRPcHRpb25zKHRoaXMubG9nZ2VyKTt1cGRhdGVEYXRhUGxhbmVFdmVudHNTdGF0ZUZyb21Mb2FkT3B0aW9ucyh0aGlzLmxvZ2dlcik7Ly8gc2V0IGFwcGxpY2F0aW9uIGxpZmVjeWNsZSBzdGF0ZSBpbiBnbG9iYWwgc3RhdGVcbm4oKCk9PntzdGF0ZS5saWZlY3ljbGUuaW50ZWdyYXRpb25zQ0ROUGF0aC52YWx1ZT1pbnRnQ2RuVXJsO3N0YXRlLmxpZmVjeWNsZS5wbHVnaW5zQ0ROUGF0aC52YWx1ZT1wbHVnaW5zQ0ROUGF0aDtpZihsb2dMZXZlbCl7c3RhdGUubGlmZWN5Y2xlLmxvZ0xldmVsLnZhbHVlPWxvZ0xldmVsO31zdGF0ZS5saWZlY3ljbGUuc291cmNlQ29uZmlnVXJsLnZhbHVlPWdldFNvdXJjZUNvbmZpZ1VSTChjb25maWdVcmwsc3RhdGUubGlmZWN5Y2xlLndyaXRlS2V5LnZhbHVlLGxvY2tJbnRlZ3JhdGlvbnNWZXJzaW9uLGxvY2tQbHVnaW5zVmVyc2lvbix0aGlzLmxvZ2dlcik7c3RhdGUubWV0cmljcy5tZXRyaWNzU2VydmljZVVybC52YWx1ZT1gJHtzdGF0ZS5saWZlY3ljbGUuYWN0aXZlRGF0YXBsYW5lVXJsLnZhbHVlfS8ke01FVFJJQ1NfU0VSVklDRV9FTkRQT0lOVH1gOy8vIERhdGEgaW4gdGhlIGxvYWRPcHRpb25zIHN0YXRlIGlzIGFscmVhZHkgbm9ybWFsaXplZFxuc3RhdGUubmF0aXZlRGVzdGluYXRpb25zLmxvYWRPbmx5SW50ZWdyYXRpb25zLnZhbHVlPWludGVncmF0aW9uczt9KTt0aGlzLmdldENvbmZpZygpO30vKipcbiAgICogSGFuZGxlIGVycm9yc1xuICAgKi9vbkVycm9yKGVycm9yLGN1c3RvbU1lc3NhZ2UsZ3JvdXBpbmdIYXNoKXt0aGlzLmVycm9ySGFuZGxlci5vbkVycm9yKHtlcnJvcixjb250ZXh0OkNPTkZJR19NQU5BR0VSLGN1c3RvbU1lc3NhZ2UsZ3JvdXBpbmdIYXNofSk7fS8qKlxuICAgKiBBIGNhbGxiYWNrIGZ1bmN0aW9uIHRoYXQgaXMgZXhlY3V0ZWQgb25jZSB3ZSBmZXRjaCB0aGUgc291cmNlIGNvbmZpZyByZXNwb25zZS5cbiAgICogVXNlIHRvIGNvbnN0cnVjdCBhbmQgc3RvcmUgaW5mb3JtYXRpb24gdGhhdCBhcmUgZGVwZW5kZW50IG9uIHRoZSBzb3VyY2VDb25maWcuXG4gICAqL3Byb2Nlc3NDb25maWcocmVzcG9uc2UsZGV0YWlscyl7Ly8gVE9ETzogYWRkIHJldHJ5IGxvZ2ljIHdpdGggYmFja29mZiBiYXNlZCBvbiByZWplY3Rpb25EZXRhaWxzLnhoci5zdGF0dXNcbi8vIFdlIGNhbiB1c2UgaXNFcnJSZXRyeWFibGUgdXRpbGl0eSBtZXRob2RcbmlmKCFpc0RlZmluZWQocmVzcG9uc2UpKXtp
1Zihpc0RlZmluZWQoZGV0YWlscykpe3RoaXMub25FcnJvcihkZXRhaWxzLmVycm9yLFNPVVJDRV9DT05GSUdfRkVUQ0hfRVJST1IpO31lbHNlIHt0aGlzLm9uRXJyb3IobmV3IEVycm9yKFNPVVJDRV9DT05GSUdfRkVUQ0hfRVJST1IpKTt9cmV0dXJuO31sZXQgcmVzO3RyeXtpZihpc1N0cmluZyhyZXNwb25zZSkpe3Jlcz1KU09OLnBhcnNlKHJlc3BvbnNlKTt9ZWxzZSB7cmVzPXJlc3BvbnNlO319Y2F0Y2goZXJyKXt0aGlzLm9uRXJyb3IoZXJyLFNPVVJDRV9DT05GSUdfUkVTT0xVVElPTl9FUlJPUik7cmV0dXJuO31pZighaXNWYWxpZFNvdXJjZUNvbmZpZyhyZXMpKXt0aGlzLm9uRXJyb3IobmV3IEVycm9yKFNPVVJDRV9DT05GSUdfUkVTT0xVVElPTl9FUlJPUikpO3JldHVybjt9Ly8gTG9nIGVycm9yIGFuZCBhYm9ydCBpZiBzb3VyY2UgaXMgZGlzYWJsZWRcbmlmKHJlcy5zb3VyY2UuZW5hYmxlZD09PWZhbHNlKXt0aGlzLmxvZ2dlci5lcnJvcihTT1VSQ0VfRElTQUJMRURfRVJST1IpO3JldHVybjt9Ly8gc2V0IHRoZSB2YWx1ZXMgaW4gc3RhdGUgZm9yIHJlcG9ydGluZyBzbGljZVxudXBkYXRlUmVwb3J0aW5nU3RhdGUocmVzKTtjb25zdCBuYXRpdmVEZXN0aW5hdGlvbnM9cmVzLnNvdXJjZS5kZXN0aW5hdGlvbnMubGVuZ3RoPjA/Z2V0RGVzdGluYXRpb25zRnJvbUNvbmZpZyhyZXMuc291cmNlLmRlc3RpbmF0aW9ucyk6W107Ly8gc2V0IGluIHRoZSBzdGF0ZSAtLT4gc291cmNlLCBkZXN0aW5hdGlvbiwgbGlmZWN5Y2xlLCByZXBvcnRpbmdcbm4oKCk9PnsvLyBzZXQgc291cmNlIHJlbGF0ZWQgaW5mb3JtYXRpb24gaW4gc3RhdGVcbnN0YXRlLnNvdXJjZS52YWx1ZT17Y29uZmlnOnJlcy5zb3VyY2UuY29uZmlnLG5hbWU6cmVzLnNvdXJjZS5uYW1lLGlkOnJlcy5zb3VyY2UuaWQsd29ya3NwYWNlSWQ6cmVzLnNvdXJjZS53b3Jrc3BhY2VJZH07Ly8gc2V0IGRldmljZSBtb2RlIGRlc3RpbmF0aW9uIHJlbGF0ZWQgaW5mb3JtYXRpb24gaW4gc3RhdGVcbnN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5jb25maWd1cmVkRGVzdGluYXRpb25zLnZhbHVlPW5hdGl2ZURlc3RpbmF0aW9uczsvLyBzZXQgdGhlIGRlc2lyZWQgb3B0aW9uYWwgcGx1Z2luc1xuc3RhdGUucGx1Z2lucy5wbHVnaW5zVG9Mb2FkRnJvbUNvbmZpZy52YWx1ZT1zdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZS5wbHVnaW5zPz9bXTt1cGRhdGVDb25zZW50c1N0YXRlKHJlcyk7Ly8gc2V0IGFwcGxpY2F0aW9uIGxpZmVjeWNsZSBzdGF0ZVxuc3RhdGUubGlmZWN5Y2xlLnN0YXR1cy52YWx1ZT0nY29uZmlndXJlZCc7fSk7fS8qKlxuICAgKiBBIGZ1bmN0aW9uIHRvIGZldGNoIHNvdXJjZSBjb25maWcgZWl0aGVyIGZyb20gL3NvdXJjZUNvbmZpZyBlbmRwb2ludFxuICAgKiBvciBmcm9tIGdldFNvdXJjZUNvbmZpZyBsb2FkIG9wdGlvblxuICAgKiBAcmV0dXJuc1xuICAgKi9nZXRDb25maWcoKXtjb25zdCBzb3VyY2VDb25maWdGdW5jPXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLmdldFNvdXJjZUNvbmZpZztpZihzb3VyY2VDb25maWdGdW5jKXtpZighaXNGdW5jdGlvbihzb3VyY2VDb25maWdGdW5jKSl7dGhpcy5sb2dnZXIuZXJyb3IoU09VUkNFX0NPTkZJR19PUFRJT05fRVJST1IoQ09ORklHX01BTkFHRVIpKTtyZXR1cm47fS8vIEZldGNoIHNvdXJjZSBjb25maWcgZnJvbSB0aGUgZnVuY3Rpb25cbmNvbnN0IHJlcz1zb3VyY2VDb25maWdGdW5jKCk7aWYocmVzIGluc3RhbmNlb2YgUHJvbWlzZSl7cmVzLnRoZW4ocFJlcz0+dGhpcy5wcm9jZXNzQ29uZmlnKHBSZXMpKS5jYXRjaChlcnI9Pnt0aGlzLm9uRXJyb3IoZXJyLCdTb3VyY2VDb25maWcnKTt9KTt9ZWxzZSB7dGhpcy5wcm9jZXNzQ29uZmlnKHJlcyk7fX1lbHNlIHsvLyBGZXRjaCBzb3VyY2UgY29uZmlndXJhdGlvbiBmcm9tIHRoZSBjb25maWd1cmVkIFVSTFxudGhpcy5odHRwQ2xpZW50LmdldEFzeW5jRGF0YSh7dXJsOnN0YXRlLmxpZmVjeWNsZS5zb3VyY2VDb25maWdVcmwudmFsdWUsb3B0aW9uczp7aGVhZGVyczp7J0NvbnRlbnQtVHlwZSc6dW5kZWZpbmVkfX0sY2FsbGJhY2s6dGhpcy5wcm9jZXNzQ29uZmlnfSk7fX19XG5cbi8qKlxuICogVG8gZ2V0IHRoZSB0aW1lem9uZSBvZiB0aGUgdXNlclxuICpcbiAqIEByZXR1cm5zIHN0cmluZ1xuICovY29uc3QgZ2V0VGltZXpvbmU9KCk9PnsvLyBOb3Qgc3VzY2VwdGlibGUgdG8gc3VwZXItbGluZWFyIGJhY2t0cmFja2luZ1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHNvbmFyanMvc2xvdy1yZWdleFxuY29uc3QgdGltZXpvbmU9LyhbQS1aXStbKy1dXFxkKykvLmV4ZWMobmV3IERhdGUoKS50b1N0cmluZygpKTtyZXR1cm4gdGltZXpvbmU/LlsxXT90aW1lem9uZVsxXTonTkEnO307XG5cbi8qKlxuICogR2V0IHRoZSByZWZlcnJlciBVUkxcbiAqIEByZXR1cm5zIFRoZSByZWZlcnJlciBVUkxcbiAqL2NvbnN0IGdldFJlZmVycmVyPShnZXREb2N1bWVudD0oKT0+ZG9jdW1lbnQpPT5nZXREb2N1bWVudCgpPy5yZWZlcnJlcnx8JyRkaXJlY3QnOy8qKlxuICogVG8gZ2V0IHRoZSBjYW5vbmljYWwgVVJMIG9mIHRoZSBwYWdlXG4gKiBAcmV0dXJucyBjYW5vbmljYWwgVVJMXG4gKi9jb25zdCBnZXRDYW5vbmljYWxVcmw9KGdldERvY3VtZW50PSgpPT5kb2N1bWVudCk9Pntjb25zdCBkb2NJbnN0YW5jZT1nZXREb2N1bWVudCgpO2NvbnN0IHRhZ3M9ZG9jSW5zdGFuY2UuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtsZXQgY2Fub25pY2FsVXJsPScnO2ZvcihsZXQgaT0wO3RhZ3NbaV07aSs9MSl7Y29uc3QgdGFnPXRhZ3NbaV07aWYodGFnLmdldEF0dHJpYnV0ZSgncmVsJyk9PT0nY2Fub25pY2FsJyYmIWNhbm9uaWNhbFVybCl7Y2Fub25pY2FsVXJsPXRhZy5nZXRBdHRyaWJ1dGUoJ2hyZWYnKT8/Jyc7YnJlYWs7fX1yZXR1cm4gY2Fub25pY2FsVXJsO307Y29uc3QgZ2V0VXNlckFnZW50PShnZXROYXZpZ2F0b3I9KCk9Pmdsb2JhbFRoaXMubmF2aWdhdG9yKT0+e2NvbnN0IG5hdmlnYXRvcj1nZXROYXZpZ2F0b3IoKTtpZihpc1VuZGVmaW5lZChuYXZpZ2F0b3IpKXtyZXR1cm4gbnVsbDt9bGV0e3VzZXJBZ2VudH09bmF2aWdhdG9yO2NvbnN0e2JyYXZlfT1uYXZpZ2F0b3I7Ly8gRm9yIHN1cHBvcnRpbmcgQnJhdmUgYnJvd3NlciBkZXRlY3Rpb24sXG4vLyBhZGQgXCJCcmF2ZS88dmVyc2lvbj5cIiB0byB0aGUgdXNlciBhZ2VudCB3aXRoIHRoZSB2ZXJzaW9uIHZhbHVlIGZyb20gdGhlIENocm9tZSBjb21wb25lbnRcbmlmKGJyYXZlJiZPYmplY3QuZ2V0UHJvdG90eXBlT2YoYnJhdmUpLmlzQnJhdmUpey8vIEV4YW1wbGU6XG4vLyBNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xNV83KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvMTAzLjAuNTA2MC4xMTQgU2FmYXJpLzUzNy4zNlxuY29uc3QgbWF0Y2hlZEFycj11c2VyQWdlbnQubWF0Y2goLyhjaHJvbWUpXFwvKFtcXHcuXSspL2kpO2lmKG1hdGNoZWRBcnIpe3VzZXJBZ2VudD1gJHt1c2VyQWdlbnR9IEJyYXZlLyR7bWF0Y2hlZEFyclsyXX1gO319cmV0dXJuIHVzZXJBZ2VudDt9O2NvbnN0IGdldExhbmd1YWdlPShnZXROYXZpZ2F0b3I9KCk9Pmdsb2JhbFRoaXMubmF2aWdhdG9yKT0+e2NvbnN0IG5hdmlnYXRvcj1nZXROYXZpZ2F0b3IoKTtpZihpc1VuZGVmaW5lZChuYXZpZ2F0b3IpKXtyZXR1cm4gbnVsbDt9cmV0dXJuIG5hdmlnYXRvci5sYW5ndWFnZT8/bmF2aWdhdG9yLmJyb3dzZXJMYW5ndWFnZTt9Oy8qKlxuICogRGVmYXVsdCBwYWdlIHByb3BlcnRpZXNcbiAqIEByZXR1cm5zIERlZmF1bHQgcGFn
1ZSBwcm9wZXJ0aWVzXG4gKi9jb25zdCBnZXREZWZhdWx0UGFnZVByb3BlcnRpZXM9KGdldExvY2F0aW9uPSgpPT5nbG9iYWxUaGlzLmxvY2F0aW9uLGdldERvY3VtZW50PSgpPT5kb2N1bWVudCk9Pntjb25zdCBsb2NhdGlvbj1nZXRMb2NhdGlvbigpO2NvbnN0IGNhbm9uaWNhbFVybD1nZXRDYW5vbmljYWxVcmwoZ2V0RG9jdW1lbnQpO2xldCBwYXRoPWxvY2F0aW9uLnBhdGhuYW1lO2NvbnN0e2hyZWY6dGFiVXJsfT1sb2NhdGlvbjtsZXQgcGFnZVVybD10YWJVcmw7Y29uc3R7c2VhcmNofT1sb2NhdGlvbjsvLyBJZiB2YWxpZCBjYW5vbmljYWwgVVJMIGlzIHByb3ZpZGVkIHVzZSB0aGlzIGFzIHBhZ2UgVVJMLlxuaWYoY2Fub25pY2FsVXJsKXt0cnl7Y29uc3QgdXJsT2JqPW5ldyBVUkwoY2Fub25pY2FsVXJsKTsvLyBJZiBleGlzdGluZywgcXVlcnkgcGFyYW1zIG9mIGNhbm9uaWNhbCBVUkwgd2lsbCBiZSB1c2VkIGluc3RlYWQgb2YgdGhlIGxvY2F0aW9uLnNlYXJjaCBvbmVzXG5pZih1cmxPYmouc2VhcmNoPT09Jycpe3BhZ2VVcmw9Y2Fub25pY2FsVXJsK3NlYXJjaDt9ZWxzZSB7cGFnZVVybD1jYW5vbmljYWxVcmw7fXBhdGg9dXJsT2JqLnBhdGhuYW1lO31jYXRjaChlcnIpey8vIERvIG5vdGhpbmdcbn19Y29uc3QgdXJsPWdldFVybFdpdGhvdXRIYXNoKHBhZ2VVcmwpO2NvbnN0e3RpdGxlfT1nZXREb2N1bWVudCgpO2NvbnN0IHJlZmVycmVyPWdldFJlZmVycmVyKGdldERvY3VtZW50KTtyZXR1cm4ge3BhdGgscmVmZXJyZXIscmVmZXJyaW5nX2RvbWFpbjpnZXRSZWZlcnJpbmdEb21haW4ocmVmZXJyZXIpLHNlYXJjaCx0aXRsZSx1cmwsdGFiX3VybDp0YWJVcmx9O307XG5cbmNvbnN0IGdldFVzZXJBZ2VudENsaWVudEhpbnQ9KGNhbGxiYWNrLGxldmVsPSdub25lJyk9PntpZihsZXZlbD09PSdub25lJyl7Y2FsbGJhY2sodW5kZWZpbmVkKTt9aWYobGV2ZWw9PT0nZGVmYXVsdCcpe2NhbGxiYWNrKG5hdmlnYXRvci51c2VyQWdlbnREYXRhKTt9aWYobGV2ZWw9PT0nZnVsbCcpe25hdmlnYXRvci51c2VyQWdlbnREYXRhPy5nZXRIaWdoRW50cm9weVZhbHVlcyhbJ2FyY2hpdGVjdHVyZScsJ2JpdG5lc3MnLCdicmFuZHMnLCdtb2JpbGUnLCdtb2RlbCcsJ3BsYXRmb3JtJywncGxhdGZvcm1WZXJzaW9uJywndWFGdWxsVmVyc2lvbicsJ2Z1bGxWZXJzaW9uTGlzdCcsJ3dvdzY0J10pLnRoZW4odWE9PntjYWxsYmFjayh1YSk7fSkuY2F0Y2goKCk9PntjYWxsYmFjaygpO30pO319O1xuXG5jb25zdCBpc0RhdGFzZXRBdmFpbGFibGU9KCk9Pntjb25zdCB0ZXN0RWxlbWVudD1nbG9iYWxUaGlzLmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO3Rlc3RFbGVtZW50LnNldEF0dHJpYnV0ZSgnZGF0YS1hLWInLCdjJyk7cmV0dXJuIHRlc3RFbGVtZW50LmRhdGFzZXQ/dGVzdEVsZW1lbnQuZGF0YXNldC5hQj09PSdjJzpmYWxzZTt9O2NvbnN0IGxlZ2FjeUpTRW5naW5lUmVxdWlyZWRQb2x5ZmlsbHM9ey8vIElkZWFsbHksIHdlIHNob3VsZCBzZXBhcmF0ZSB0aGUgY2hlY2tzIGZvciBVUkwgYW5kIFVSTFNlYXJjaFBhcmFtcyBidXRcbi8vIHRoZSBwb2x5ZmlsbCBzZXJ2aWNlIHNlcnZlcyB0aGVtIHVuZGVyIHRoZSBzYW1lIGZlYXR1cmUgbmFtZSwgXCJVUkxcIi5cblVSTDooKT0+IWlzRnVuY3Rpb24oZ2xvYmFsVGhpcy5VUkwpfHwhaXNGdW5jdGlvbihnbG9iYWxUaGlzLlVSTFNlYXJjaFBhcmFtcyksUHJvbWlzZTooKT0+IWlzRnVuY3Rpb24oZ2xvYmFsVGhpcy5Qcm9taXNlKSwnTnVtYmVyLmlzTmFOJzooKT0+IWlzRnVuY3Rpb24oZ2xvYmFsVGhpcy5OdW1iZXIuaXNOYU4pLCdOdW1iZXIuaXNJbnRlZ2VyJzooKT0+IWlzRnVuY3Rpb24oZ2xvYmFsVGhpcy5OdW1iZXIuaXNJbnRlZ2VyKSwnQXJyYXkuZnJvbSc6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuQXJyYXkuZnJvbSksJ0FycmF5LnByb3RvdHlwZS5maW5kJzooKT0+IWlzRnVuY3Rpb24oZ2xvYmFsVGhpcy5BcnJheS5wcm90b3R5cGUuZmluZCksJ0FycmF5LnByb3RvdHlwZS5pbmNsdWRlcyc6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuQXJyYXkucHJvdG90eXBlLmluY2x1ZGVzKSwnU3RyaW5nLnByb3RvdHlwZS5lbmRzV2l0aCc6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuU3RyaW5nLnByb3RvdHlwZS5lbmRzV2l0aCksJ1N0cmluZy5wcm90b3R5cGUuc3RhcnRzV2l0aCc6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuU3RyaW5nLnByb3RvdHlwZS5zdGFydHNXaXRoKSwnU3RyaW5nLnByb3RvdHlwZS5pbmNsdWRlcyc6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuU3RyaW5nLnByb3RvdHlwZS5pbmNsdWRlcyksJ1N0cmluZy5wcm90b3R5cGUucmVwbGFjZUFsbCc6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuU3RyaW5nLnByb3RvdHlwZS5yZXBsYWNlQWxsKSwnU3RyaW5nLmZyb21Db2RlUG9pbnQnOigpPT4haXNGdW5jdGlvbihnbG9iYWxUaGlzLlN0cmluZy5mcm9tQ29kZVBvaW50KSwnT2JqZWN0LmVud
1HJpZXMnOigpPT4haXNGdW5jdGlvbihnbG9iYWxUaGlzLk9iamVjdC5lbnRyaWVzKSwnT2JqZWN0LnZhbHVlcyc6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuT2JqZWN0LnZhbHVlcyksJ09iamVjdC5hc3NpZ24nOigpPT4haXNGdW5jdGlvbihnbG9iYWxUaGlzLk9iamVjdC5hc3NpZ24pLCdPYmplY3QuZnJvbUVudHJpZXMnOigpPT4haXNGdW5jdGlvbihnbG9iYWxUaGlzLk9iamVjdC5mcm9tRW50cmllcyksJ0VsZW1lbnQucHJvdG90eXBlLmRhdGFzZXQnOigpPT4haXNEYXRhc2V0QXZhaWxhYmxlKCksLy8gSWRlYWxseSwgd2Ugc2hvdWxkIHNlcGFyYXRlIHRoZSBjaGVja3MgZm9yIFRleHRFbmNvZGVyIGFuZCBUZXh0RGVjb2RlciBidXRcbi8vIHRoZSBwb2x5ZmlsbCBzZXJ2aWNlIHNlcnZlcyB0aGVtIHVuZGVyIHRoZSBzYW1lIGZlYXR1cmUgbmFtZSwgXCJUZXh0RW5jb2RlclwiLlxuVGV4dEVuY29kZXI6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuVGV4dEVuY29kZXIpfHwhaXNGdW5jdGlvbihnbG9iYWxUaGlzLlRleHREZWNvZGVyKSxyZXF1ZXN0QW5pbWF0aW9uRnJhbWU6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMucmVxdWVzdEFuaW1hdGlvbkZyYW1lKXx8IWlzRnVuY3Rpb24oZ2xvYmFsVGhpcy5jYW5jZWxBbmltYXRpb25GcmFtZSksQ3VzdG9tRXZlbnQ6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuQ3VzdG9tRXZlbnQpLCduYXZpZ2F0b3Iuc2VuZEJlYWNvbic6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMubmF2aWdhdG9yLnNlbmRCZWFjb24pLC8vIE5vdGUsIHRoZSBwb2x5ZmlsbCBzZXJ2aWNlIHNlcnZlcyBib3RoIEFycmF5QnVmZmVyIGFuZCBVaW50OEFycmF5IHVuZGVyIHRoZSBzYW1lIGZlYXR1cmUgbmFtZSwgXCJBcnJheUJ1ZmZlclwiLlxuQXJyYXlCdWZmZXI6KCk9PiFpc0Z1bmN0aW9uKGdsb2JhbFRoaXMuVWludDhBcnJheSksU2V0OigpPT4haXNGdW5jdGlvbihnbG9iYWxUaGlzLlNldCksYXRvYjooKT0+IWlzRnVuY3Rpb24oZ2xvYmFsVGhpcy5hdG9iKX07Y29uc3QgaXNMZWdhY3lKU0VuZ2luZT0oKT0+e2NvbnN0IHJlcXVpcmVkQ2FwYWJpbGl0aWVzTGlzdD1PYmplY3Qua2V5cyhsZWdhY3lKU0VuZ2luZVJlcXVpcmVkUG9seWZpbGxzKTtsZXQgbmVlZHNQb2x5ZmlsbD1mYWxzZTsvKiBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgdW5pY29ybi9uby1mb3ItbG9vcCAqL2ZvcihsZXQgaT0wO2k8cmVxdWlyZWRDYXBhYmlsaXRpZXNMaXN0Lmxlbmd0aDtpKyspe2NvbnN0IGlzQ2FwYWJpbGl0eU1pc3Npbmc9bGVnYWN5SlNFbmdpbmVSZXF1aXJlZFBvbHlmaWxsc1tyZXF1aXJlZENhcGFiaWxpdGllc0xpc3RbaV1dO2lmKGlzRnVuY3Rpb24oaXNDYXBhYmlsaXR5TWlzc2luZykmJmlzQ2FwYWJpbGl0eU1pc3NpbmcoKSl7bmVlZHNQb2x5ZmlsbD10cnVlO2JyZWFrO319cmV0dXJuIG5lZWRzUG9seWZpbGw7fTtcblxuY29uc3QgcG9seWZpbGxJb1Nka1VybD0naHR0cHM6Ly9wb2x5ZmlsbC1mYXN0bHkuaW8vdjMvcG9seWZpbGwubWluLmpzJztjb25zdCBQT0xZRklMTF9VUkw9YCR7cG9seWZpbGxJb1Nka1VybH0/dmVyc2lvbj0zLjExMS4wJmZlYXR1cmVzPSR7T2JqZWN0LmtleXMobGVnYWN5SlNFbmdpbmVSZXF1aXJlZFBvbHlmaWxscykuam9pbignJTJDJyl9YDtjb25zdCBQT0xZRklMTF9MT0FEX1RJTUVPVVQ9MTAqMTAwMDsvLyAxMCBzZWNvbmRzXG5jb25zdCBQT0xZRklMTF9TQ1JJUFRfSUQ9J3J1ZGRlcnN0YWNrUG9seWZpbGwnO1xuXG5jb25zdCBoYXNDcnlwdG89KCk9PiFpc051bGxPclVuZGVmaW5lZChnbG9iYWxUaGlzLmNyeXB0bykmJmlzRnVuY3Rpb24oZ2xvYmFsVGhpcy5jcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKTsvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGF0L2NvbXBhdCAtLSBXZSBhcmUgY2hlY2tpbmcgZm9yIHRoZSBleGlzdGVuY2Ugb2YgbmF2aWdhdG9yLnVzZXJBZ2VudERhdGFcbmNvbnN0IGhhc1VBQ2xpZW50SGludHM9KCk9PiFpc051bGxPclVuZGVmaW5lZChnbG9iYWxUaGlzLm5hdmlnYXRvci51c2VyQWdlbnREYXRhKTtjb25zdCBoYXNCZWFjb249KCk9PiFpc051bGxPclVuZGVmaW5lZChnbG9iYWxUaGlzLm5hdmlnYXRvci5zZW5kQmVhY29uKSYmaXNGdW5jdGlvbihnbG9iYWxUaGlzLm5hdmlnYXRvci5zZW5kQmVhY29uKTtcblxuY29uc3QgZ2V0U2NyZWVuRGV0YWlscz0oKT0+e2xldCBzY3JlZW5EZXRhaWxzPXtkZW5zaXR5OjAsd2lkdGg6MCxoZWlnaHQ6MCxpbm5lcldpZHRoOjAsaW5uZXJIZWlnaHQ6MH07c2NyZWVuRGV0YWlscz17d2lkdGg6Z2xvYmFsVGhpcy5zY3JlZW4ud2lkdGgsaGVpZ2h0Omdsb2JhbFRoaXMuc2NyZWVuLmhlaWdodCxkZW5zaXR5Omdsb2JhbFRoaXMuZGV2aWNlUGl4ZWxSYXRpbyxpbm5lcldpZHRoOmdsb2JhbFRoaXMuaW5uZXJXaWR0aCxpbm5lckhlaWdodDpnbG9iYWxUaGlzLmlubmVySGVpZ2h0fTtyZXR1cm4gc2NyZWVuRGV0YWlsczt9O1xuXG5jbGFzcyBDYXBhYmlsaXRpZXNNYW5hZ2Vye2NvbnN0cnVjdG9yKGh0dHBDbGllbnQsZXJyb3JIYW5kbGVyLGxvZ2dlcil7dGhpcy5odHRwQ2xpZW50PWh0dHBDbGllbnQ7dGhpcy5lcnJvckhhbmRsZXI9ZXJyb3JIYW5kbGVyO3RoaXMubG9nZ2VyPWxvZ2dlcjt0aGlzLmV4dGVybmFsU3JjTG9hZGVyPW5ldyBFeHRlcm5hbFNyY0xvYWRlcih0aGlzLmxvZ2dlcik7dGhpcy5vbkVycm9yPXRoaXMub25FcnJvci5iaW5kKHRoaXMpO3RoaXMub25SZWFkeT10aGlzLm9uUmVhZHkuYmluZCh0aGlzKTt9aW5pdCgpe3RoaXMucHJlcGFyZUJyb3dzZXJDYXBhYmlsaXRpZXMoKTt0aGlzLmF0dGFjaFdpbmRvd0xpc3RlbmVycygpO30vKipcbiAgICogRGV0ZWN0IHN1cHBvcnRlZCBjYXBhYmlsaXRpZXMgYW5kIHNldCB2YWx1ZXMgaW4gc3RhdGVcbiAgICovLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbmRldGVjdEJyb3dzZXJDYXBhYmlsaXRpZXMoKXtuKCgpPT57Ly8gU3RvcmFnZSByZWxhdGVkIGRldGFpbHNcbnN0YXRlLmNhcGFiaWxpdGllcy5zdG9yYWdlLmlzQ29va2llU3RvcmFnZUF2YWlsYWJsZS52YWx1ZT1pc1N0b3JhZ2VBdmFpbGFibGUoQ09PS0lFX1NUT1JBR0UsZ2V0U3RvcmFnZUVuZ2luZShDT09LSUVfU1RPUkFHRSksdGhpcy5sb2dnZXIpO3N0YXRlLmNhcGFiaWxpdGllcy5zdG9yYWdlLmlzTG9jYWxTdG9yYWdlQXZhaWxhYmxlLnZhbHVlPWlzU3RvcmFnZUF2YWlsYWJsZShMT0NBTF9TVE9SQUdFLHVuZGVmaW5lZCx0aGlzLmxvZ2dlcik7c3RhdGUuY2FwYWJpbGl0aWVzLnN0b3JhZ2UuaXNTZXNzaW9uU3RvcmFnZUF2YWlsYWJsZS52YWx1ZT1pc1N0b3JhZ2VBdmFpbGFibGUoU0VTU0lPTl9TVE9SQUdFLHVuZGVmaW5lZCx0aGlzLmxvZ2dlcik7Ly8gQnJvd3NlciBmZWF0dXJlIGRldGVjdGlvbiBkZXRhaWxzXG5zdGF0ZS5jYXBhYmlsaXRpZXMuaXNCZWFjb25BdmFpbGFibGUudmFsdWU9aGFzQmVhY29uKCk7c3R
1hdGUuY2FwYWJpbGl0aWVzLmlzVWFDSEF2YWlsYWJsZS52YWx1ZT1oYXNVQUNsaWVudEhpbnRzKCk7c3RhdGUuY2FwYWJpbGl0aWVzLmlzQ3J5cHRvQXZhaWxhYmxlLnZhbHVlPWhhc0NyeXB0bygpO3N0YXRlLmNhcGFiaWxpdGllcy5pc09ubGluZS52YWx1ZT1nbG9iYWxUaGlzLm5hdmlnYXRvci5vbkxpbmU7Ly8gR2V0IHBhZ2UgY29udGV4dCBkZXRhaWxzXG5zdGF0ZS5jb250ZXh0LnVzZXJBZ2VudC52YWx1ZT1nZXRVc2VyQWdlbnQoKTtzdGF0ZS5jb250ZXh0LmxvY2FsZS52YWx1ZT1nZXRMYW5ndWFnZSgpO3N0YXRlLmNvbnRleHQuc2NyZWVuLnZhbHVlPWdldFNjcmVlbkRldGFpbHMoKTtzdGF0ZS5jb250ZXh0LnRpbWV6b25lLnZhbHVlPWdldFRpbWV6b25lKCk7aWYoaGFzVUFDbGllbnRIaW50cygpKXtnZXRVc2VyQWdlbnRDbGllbnRIaW50KHVhY2g9PntzdGF0ZS5jb250ZXh0Wyd1YS1jaCddLnZhbHVlPXVhY2g7fSxzdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZS51YUNoVHJhY2tMZXZlbCk7fX0pOy8vIEFkIGJsb2NrZXIgZGV0ZWN0aW9uXG5qKCgpPT57aWYoc3RhdGUubG9hZE9wdGlvbnMudmFsdWUuc2VuZEFkYmxvY2tQYWdlPT09dHJ1ZSYmc3RhdGUubGlmZWN5Y2xlLnNvdXJjZUNvbmZpZ1VybC52YWx1ZSE9PXVuZGVmaW5lZCl7ZGV0ZWN0QWRCbG9ja2Vycyh0aGlzLmh0dHBDbGllbnQpO319KTt9LyoqXG4gICAqIERldGVjdCBpZiBwb2x5ZmlsbHMgYXJlIHJlcXVpcmVkIGFuZCB0aGVuIGxvYWQgc2NyaXB0IGZyb20gcG9seWZpbGwgVVJMXG4gICAqL3ByZXBhcmVCcm93c2VyQ2FwYWJpbGl0aWVzKCl7c3RhdGUuY2FwYWJpbGl0aWVzLmlzTGVnYWN5RE9NLnZhbHVlPWlzTGVnYWN5SlNFbmdpbmUoKTtjb25zdCBjdXN0b21Qb2x5ZmlsbFVybD1zdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZS5wb2x5ZmlsbFVSTDtsZXQgcG9seWZpbGxVcmw9UE9MWUZJTExfVVJMO2lmKGlzRGVmaW5lZEFuZE5vdE51bGwoY3VzdG9tUG9seWZpbGxVcmwpKXtpZihpc1ZhbGlkVVJMKGN1c3RvbVBvbHlmaWxsVXJsKSl7cG9seWZpbGxVcmw9Y3VzdG9tUG9seWZpbGxVcmw7fWVsc2Uge3RoaXMubG9nZ2VyLndhcm4oSU5WQUxJRF9QT0xZRklMTF9VUkxfV0FSTklORyhDQVBBQklMSVRJRVNfTUFOQUdFUixjdXN0b21Qb2x5ZmlsbFVybCkpO319Y29uc3Qgc2hvdWxkTG9hZFBvbHlmaWxsPXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnBvbHlmaWxsSWZSZXF1aXJlZCYmc3RhdGUuY2FwYWJpbGl0aWVzLmlzTGVnYWN5RE9NLnZhbHVlJiZpc1ZhbGlkVVJMKHBvbHlmaWxsVXJsKTtpZihzaG91bGRMb2FkUG9seWZpbGwpe2NvbnN0IGlzRGVmYXVsdFBvbHlmaWxsU2VydmljZT1wb2x5ZmlsbFVybCE9PXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnBvbHlmaWxsVVJMO2lmKGlzRGVmYXVsdFBvbHlmaWxsU2VydmljZSl7Ly8gd3JpdGUga2V5IHNwZWNpZmljIGNhbGxiYWNrXG4vLyBOT1RFOiB3ZSdyZSBub3QgcHV0dGluZyB0aGlzIGludG8gUnVkZGVyU3RhY2tHbG9iYWxzIGFzIHByb3ZpZGluZyB0aGUgcHJvcGVydHkgcGF0aCB0byB0aGUgY2FsbGJhY2sgZnVuY3Rpb24gaW4gdGhlIHBvbHlmaWxsIFVSTCBpcyBub3QgcG9zc2libGVcbmNvbnN0IHBvbHlmaWxsQ2FsbGJhY2tOYW1lPWBSU19wb2x5ZmlsbENhbGxiYWNrXyR7c3RhdGUubGlmZWN5Y2xlLndyaXRlS2V5LnZhbHVlfWA7Y29uc3QgcG9seWZpbGxDYWxsYmFjaz0oKT0+e3RoaXMub25SZWFkeSgpOy8vIFJlbW92ZSB0aGUgZW50cnkgZnJvbSB3aW5kb3cgc28gd2UgZG9uJ3QgbGVhdmUgcm9vbSBmb3IgY2FsbGluZyBpdCBhZ2FpblxuZGVsZXRlIGdsb2JhbFRoaXNbcG9seWZpbGxDYWxsYmFja05hbWVdO307Z2xvYmFsVGhpc1twb2x5ZmlsbENhbGxiYWNrTmFtZV09cG9seWZpbGxDYWxsYmFjaztwb2x5ZmlsbFVybD1gJHtwb2x5ZmlsbFVybH0mY2FsbGJhY2s9JHtwb2x5ZmlsbENhbGxiYWNrTmFtZX1gO310aGlzLmV4dGVybmFsU3JjTG9hZGVyLmxvYWRKU0ZpbGUoe3VybDpwb2x5ZmlsbFVybCxpZDpQT0xZRklMTF9TQ1JJUFRfSUQsYXN5bmM6dHJ1ZSx0aW1lb3V0OlBPTFlGSUxMX0xPQURfVElNRU9VVCxjYWxsYmFjazpzY3JpcHRJZD0+e2lmKCFzY3JpcHRJZCl7dGhpcy5vbkVycm9yKG5ldyBFcnJvcihQT0xZRklMTF9TQ1JJUFRfTE9BRF9FUlJPUihQT0xZRklMTF9TQ1JJUFRfSUQscG9seWZpbGxVcmwpKSk7fWVsc2UgaWYoIWlzRGVmYXVsdFBvbHlmaWxsU2VydmljZSl7dGhpcy5vblJlYWR5KCk7fX19KTt9ZWxzZSB7dGhpcy5vblJlYWR5KCk7fX0vKipcbiAgICogQXR0YWNoIGxpc3RlbmVycyB0byB3aW5kb3cgdG8gb2JzZXJ2ZSBldmVudCB0aGF0IHVwZGF0ZSBjYXBhYmlsaXRpZXMgc3RhdGUgdmFsdWVzXG4gICAqL2F0dGFjaFdpbmRvd0xpc3RlbmVycygpe2dsb2JhbFRoaXMuYWRkRXZlbnRMaXN0ZW5lcignb2ZmbGluZScsKCk9PntzdGF0ZS5jYXBhYmlsaXRpZXMuaXNPbmxpbmUudmFsdWU9ZmFsc2U7fSk7Z2xvYmFsVGhpcy5hZGRFdmVudExpc3RlbmVyKCdvbmxpbmUnLCgpPT57c3RhdGUuY2FwYWJpbGl0aWVzLmlzT25saW5lLnZhbHVlPXRydWU7fSk7Z2xvYmFsVGhpcy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLGRlYm91bmNlKCgpPT57c3RhdGUuY29udGV4dC5zY3JlZW4udmFsdWU9Z2V0U2NyZWVuRGV0YWlscygpO30sdGhpcykpO30vKipcbiAgICogU2V0IHRoZSBsaWZlY3ljbGUgc3RhdHVzIHRvIG5leHQgcGhhc2VcbiAgICovLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbm9uUmVhZHkoKXt0aGlzLmRldGVjdEJyb3dzZXJDYXBhYmlsaXRpZXMoKTtzdGF0ZS5saWZlY3ljbGUuc3RhdHVzLnZhbHVlPSdicm93c2VyQ2FwYWJpbGl0aWVzUmVhZHknO30vKipcbiAgICogSGFuZGxlcyBlcnJvclxuICAgKiBAcGFyYW0gZXJyb3IgVGhlIGVycm9yIG9iamVjdFxuICAgKi9vbkVycm9yKGVycm9yLGdyb3VwaW5nSGFzaCl7dGhpcy5lcnJvckhhbmRsZXIub25FcnJvcih7ZXJyb3IsY29udGV4dDpDQVBBQklMSVRJRVNfTUFOQUdFUixncm91cGluZ0hhc2h9KTt9fVxuXG5jb25zdCBDSEFOTkVMPSd3ZWInOy8vIFRoZXNlIGFyZSB0aGUgdG9wLWxldmVsIGVsZW1lbnRzIGluIHRoZSBzdGFuZGFyZCBSdWRkZXJTdGFjayBldmVudCBzcGVjXG5jb25zdCBUT1BfTEVWRUxfRUxFTUVOVFM9WydpbnRlZ3JhdGlvbnMnLCdhbm9ueW1vdXNJZCcsJ29yaWdpbmFsVGltZXN0YW1wJ107Ly8gUmVzZXJ2ZWQgZWxlbWVudHMgaW4gdGhlIGNvbnRleHQgb2Ygc3RhbmRhcmQgUnVkZGVyU3RhY2sgZXZlbnQgc3BlY1xuLy8gVHlwaWNhbGx5LCB0aGVzZSBlbGVtZW50cyBhcmUgbm90IGFsbG93ZWQgdG8gYmUgb3ZlcnJpZGRlbiBieSB0aGUgdXNlclxuY29uc3QgQ09OVEVYVF9SRVNFUlZFRF9FTEVNRU5UUz1bJ2xpYnJhcnknLCdjb25zZW50TWFuYWdlbWVudCcsJ3VzZXJBZ2VudCcsJ3VhLWNoJywnc2NyZWVuJ107Ly8gUmVzZXJ2ZWQgZWxlbWVudHMgaW4gdGhlIHN0YW5kYXJkIFJ1ZGRlclN0YWNrIGV2ZW50IHNwZWNcbmNvbnN0IFJFU0VSVkVEX0VMRU1FTlRTPVsnaWQnLCdhbm9ueW1vdXNfaWQnLCd1c2VyX2lkJywnc2VudF9hdCcsJ3RpbWVzdGFtcCcsJ3JlY2VpdmVkX2F0Jywnb3JpZ2luYWxfdGltZXN0YW1wJywnZXZlbnQnLCdldmVudF90ZXh0JywnY2hhbm5lbCcsJ2NvbnRleHRfaXAnLCdjb250ZXh0X3JlcXVlc3RfaXAnLCdjb250ZXh0X3Bhc3NlZF9pcCcsJ2dyb3VwX2lkJywncHJldmlvdXNfaWQnXTtcblxuLyoqXG4gKiBBIGZ1bmN0aW9uIHRvIGNoZWNrIGdpdmVuIHZhbHVlIGlzIGEgbnVtYmVyIG9yIG5vdFxuICogQHBhcmFtIG51bSBpbnB1dCB2YWx1ZVxuICogQHJldHVybnMgYm9vbGVhblxuICovY29uc3QgaXNOdW1iZXI9bnVtPT50eXBlb2YgbnVtPT09J251bWJlcicmJiFOdW1iZXIuaXNOYU4obnVtKTsvKipcbiAqIEEgZnVuY3Rpb24gdG8gY2hlY2sgZ2l2ZW4gbnVtYmVyIGhhcyBtaW5pbXVtIGxlbmd0aCBvciBub3RcbiAqIEBwYXJhbSBtaW5pbXVtTGVuZ3RoICAgICBtaW5pbXVtIGxlbmd0aFxuICogQHBhcmFtIG51bSAgICAgICAgICAgICAgIGlucHV0IG51bWJlclxuICogQHJldHVybnMgYm9vbGVhblxuICovY29uc3QgaGFzTWluTGVuZ3RoPShtaW5pbXVtTGVuZ3RoLG51bSk9Pm51bS50b1N0cmluZygpLmxlbmd0aD49bWluaW11bUxlbmd0aDsvKipcbiAqIEEgZnVuY3Rpb24gdG8gY2hlY2sgZ2l2ZW4gdmFsdWUgaXMgYSBwb3NpdGl2ZSBpbnRlZ2VyIG9yIG5vdFxuICogQHBhcmFtIG51bSBpbnB1dCB2YWx1ZVxuICogQHJldHVybnMgYm9vbGVhblxuICovY29uc3QgaXNQb3NpdGl2ZUludGVnZXI9bnVtPT5pc051bWJlcihudW0pJiZudW0+PTAmJk51bWJlci5pc0ludGVnZXIobnVtKTtcblxuY29uc3QgTUlOX1NFU1NJT05fSURfTEVOR1RIPTEwO2NvbnN0IGlzQ3V0T2ZmVGltZUV4Y2VlZGVkPXNlc3Npb25JbmZvPT57Y29uc3R7Y3V0T2ZmfT1zZXNzaW9uSW5mbztjb25zdCB0aW1lc3RhbXA9RGF0ZS5ub3coKTtyZXR1cm4gQm9vbGVhbihjdXRPZmY/LmVuYWJsZWQmJmN1dE9mZi5leHBpcmVzQXQmJnRpbWVzdGFtcD5jdXRPZmYuZXhwaXJlc0F0KTt9Oy8qKlxuICogQSBmdW5jdGlvbiB0byB2YWxpZGF0ZSB3aGV0aGVyIHR
1oZSBjdXJyZW50IGF1dG8gdHJhY2tpbmcgc2Vzc2lvbiBoYXMgZXhwaXJlZCBvciBub3QuXG4gKiBJdCBjaGVja3MgZm9yIHRoZSBjdXJyZW50IHNlc3Npb24gZXhwaXJ5IGFuZCB0aGUgY3V0IG9mZiB0aW1lIGV4cGlyeS5cbiAqIEBwYXJhbSBzZXNzaW9uSW5mbyBzZXNzaW9uIGluZm9cbiAqIEByZXR1cm5zIGJvb2xlYW5cbiAqL2NvbnN0IGhhc1Nlc3Npb25FeHBpcmVkPXNlc3Npb25JbmZvPT57Y29uc3QgaXNDdXJyZW50U2Vzc2lvbkV4cGlyZWQ9Qm9vbGVhbighc2Vzc2lvbkluZm8uZXhwaXJlc0F0fHxEYXRlLm5vdygpPnNlc3Npb25JbmZvLmV4cGlyZXNBdCk7cmV0dXJuIGlzQ3VycmVudFNlc3Npb25FeHBpcmVkfHxpc0N1dE9mZlRpbWVFeGNlZWRlZChzZXNzaW9uSW5mbyk7fTsvKipcbiAqIEEgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgc2Vzc2lvbiBpZFxuICogQHJldHVybnMgbnVtYmVyXG4gKi9jb25zdCBnZW5lcmF0ZVNlc3Npb25JZD0oKT0+RGF0ZS5ub3coKTsvKipcbiAqIEZ1bmN0aW9uIHRvIHZhbGlkYXRlIHVzZXIgcHJvdmlkZWQgc2Vzc2lvbklkXG4gKiBAcGFyYW0ge251bWJlcn0gc2Vzc2lvbklkXG4gKiBAcGFyYW0gbG9nZ2VyIGxvZ2dlclxuICogQHJldHVybnNcbiAqL2NvbnN0IGlzTWFudWFsU2Vzc2lvbklkVmFsaWQ9KHNlc3Npb25JZCxsb2dnZXIpPT57aWYoIXNlc3Npb25JZHx8IWlzUG9zaXRpdmVJbnRlZ2VyKHNlc3Npb25JZCl8fCFoYXNNaW5MZW5ndGgoTUlOX1NFU1NJT05fSURfTEVOR1RILHNlc3Npb25JZCkpe2xvZ2dlci53YXJuKElOVkFMSURfU0VTU0lPTl9JRF9XQVJOSU5HKFVTRVJfU0VTU0lPTl9NQU5BR0VSLHNlc3Npb25JZCxNSU5fU0VTU0lPTl9JRF9MRU5HVEgpKTtyZXR1cm4gZmFsc2U7fXJldHVybiB0cnVlO307Y29uc3QgZ2V0Q3V0T2ZmRXhwaXJhdGlvblRpbWVzdGFtcD1jdXRPZmY9PntpZighY3V0T2ZmPy5lbmFibGVkKXtyZXR1cm4gdW5kZWZpbmVkO31yZXR1cm4gY3V0T2ZmLmV4cGlyZXNBdD8/KGlzUG9zaXRpdmVJbnRlZ2VyKGN1dE9mZi5kdXJhdGlvbik/RGF0ZS5ub3coKStjdXRPZmYuZHVyYXRpb246dW5kZWZpbmVkKTt9Oy8qKlxuICogQSBmdW5jdGlvbiB0byBnZW5lcmF0ZSBuZXcgYXV0byB0cmFja2luZyBzZXNzaW9uXG4gKiBAcGFyYW0gc2Vzc2lvbkluZm8gc2Vzc2lvbiBpbmZvXG4gKiBAcmV0dXJucyBTZXNzaW9uSW5mb1xuICovY29uc3QgZ2VuZXJhdGVBdXRvVHJhY2tpbmdTZXNzaW9uPXNlc3Npb25JbmZvPT57Y29uc3R7dGltZW91dCxjdXRPZmZ9PXNlc3Npb25JbmZvO2NvbnN0IHRpbWVzdGFtcD1EYXRlLm5vdygpO3JldHVybiB7aWQ6dGltZXN0YW1wLC8vIHNldCB0aGUgY3VycmVudCB0aW1lc3RhbXBcbmV4cGlyZXNBdDp0aW1lc3RhbXArdGltZW91dCwvLyBzZXQgdGhlIGV4cGlyeSB0aW1lIG9mIHRoZSBzZXNzaW9uXG50aW1lb3V0LGF1dG9UcmFjazp0cnVlLC4uLihjdXRPZmYmJntjdXRPZmZ9KX07fTsvKipcbiAqIEEgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgbmV3IG1hbnVhbCB0cmFja2luZyBzZXNzaW9uXG4gKiBAcGFyYW0gaWQgUHJvdmlkZWQgc2Vzc2lvbklkXG4gKiBAcGFyYW0gbG9nZ2VyIExvZ2dlciBtb2R1bGVcbiAqIEByZXR1cm5zIFNlc3Npb25JbmZvXG4gKi9jb25zdCBnZW5lcmF0ZU1hbnVhbFRyYWNraW5nU2Vzc2lvbj0oaWQsbG9nZ2VyKT0+e2NvbnN0IHNlc3Npb25JZD1pc01hbnVhbFNlc3Npb25JZFZhbGlkKGlkLGxvZ2dlcik/aWQ6Z2VuZXJhdGVTZXNzaW9uSWQoKTtyZXR1cm4ge2lkOnNlc3Npb25JZCxzZXNzaW9uU3RhcnQ6dW5kZWZpbmVkLG1hbnVhbFRyYWNrOnRydWV9O307Y29uc3QgaXNTdG9yYWdlVHlwZVZhbGlkRm9yU3RvcmluZ0RhdGE9c3RvcmFnZVR5cGU9PkJvb2xlYW4oc3RvcmFnZVR5cGU9PT1DT09LSUVfU1RPUkFHRXx8c3RvcmFnZVR5cGU9PT1MT0NBTF9TVE9SQUdFfHxzdG9yYWdlVHlwZT09PVNFU1NJT05fU1RPUkFHRXx8c3RvcmFnZVR5cGU9PT1NRU1PUllfU1RPUkFHRSk7LyoqXG4gKiBHZW5lcmF0ZSBhIG5ldyBhbm9ueW1vdXNJZFxuICogQHJldHVybnMgc3RyaW5nIGFub255bW91c0lEXG4gKi9jb25zdCBnZW5lcmF0ZUFub255bW91c0lkPSgpPT5nZW5lcmF0ZVVVSUQoKTtjb25zdCBnZXRGaW5hbFJlc2V0T3B0aW9ucz1vcHRpb25zPT57Ly8gTGVnYWN5IGJlaGF2aW9yOiB0b2dnbGUgb25seSBhbm9ueW1vdXNJZCB3aXRob3V0IG11dGF0aW5nIGRlZmF1bHRzXG5pZihpc0Jvb2xlYW4ob3B0aW9ucykpe2NvbnN0e2VudHJpZXMsLi4ucmVzdH09REVGQVVMVF9SRVNFVF9PUFRJT05TO3JldHVybiB7Li4ucmVzdCxlbnRyaWVzOnsuLi5lbnRyaWVzLGFub255bW91c0lkOm9wdGlvbnN9fTt9Ly8gT3ZlcnJpZGUgYW55IGRlZmF1bHRzIHdpdGggdGhlIHVzZXIgcHJvdmlkZWQgb3B0aW9uc1xuaWYoaXNPYmplY3RMaXRlcmFsQW5kTm90TnVsbChvcHRpb25zKSYmaXNPYmplY3RMaXRlcmFsQW5kTm90TnVsbChvcHRpb25zLmVudHJpZXMpKXtyZXR1cm4gbWVyZ2VEZWVwUmlnaHQoREVGQVVMVF9SRVNFVF9PUFRJT05TLG9wdGlvbnMpO31yZXR1cm4gey4uLkRFRkFVTFRfUkVTRVRfT1BUSU9OU307fTtcblxuLyoqXG4gKiBUbyBnZXQgdGhlIHBhZ2UgcHJvcGVydGllcyBmb3IgY29udGV4dCBvYmplY3RcbiAqIEBwYXJhbSBwYWdlUHJvcHMgUGFnZSBwcm9wZXJ0aWVzXG4gKiBAcmV0dXJucyBwYWdlIHByb3BlcnRpZXMgb2JqZWN0IGZvciBjb250ZXh0XG4gKi9jb25zdCBnZXRDb250ZXh0UGFnZVByb3BlcnRpZXM9cGFnZVByb3BzPT57Ly8gTmVlZCB0byBnZXQgdXBkYXRlZCBwYWdlIGRldGFpbHMgb24gZWFjaCBldmVudCBhcyBhbiBldmVudCB0byBub3RpZnkgb24gU1BBIFVSTCBjaGFuZ2VzIGRvZXMgbm90IHNlZW0gdG8gZXhpc3RcbmNvbnN0IGN1clBhZ2VQcm9wcz1nZXREZWZhdWx0UGFnZVByb3BlcnRpZXMoKTtjb25zdCBjdHhQYWdlUHJvcHM9e307T2JqZWN0LmtleXMoY3VyUGFnZVByb3BzKS5mb3JFYWNoKGtleT0+e2N0eFBhZ2VQcm9wc1trZXldPXBhZ2VQcm9wcz8uW2tleV18fGN1clBhZ2VQcm9wc1trZXldO30pO2N0eFBhZ2VQcm9wcy5pbml0aWFsX3JlZmVycmVyPXBhZ2VQcm9wcz8uaW5pdGlhbF9yZWZlcnJlcnx8c3RhdGUuc2Vzc2lvbi5pbml0aWFsUmVmZXJyZXIudmFsdWU7Y3R4UGFnZVByb3BzLmluaXRpYWxfcmVmZXJyaW5nX2RvbWFpbj1wYWdlUHJvcHM/LmluaXRpYWxfcmVmZXJyaW5nX2RvbWFpbnx8c3RhdGUuc2Vzc2lvbi5pbml0aWFsUmVmZXJyaW5nRG9tYWluLnZhbHVlO3JldHVybiBjdHhQYWdlUHJvcHM7fTsvKipcbiAqIEFkZCBhbnkgbWlzc2luZyBkZWZhdWx0IHBhZ2UgcHJv
1cGVydGllcyB1c2luZyB2YWx1ZXMgZnJvbSBvcHRpb25zIGFuZCBkZWZhdWx0c1xuICogQHBhcmFtIHByb3BlcnRpZXMgSW5wdXQgcGFnZSBwcm9wZXJ0aWVzXG4gKiBAcGFyYW0gb3B0aW9ucyBBUEkgb3B0aW9uc1xuICovY29uc3QgZ2V0VXBkYXRlZFBhZ2VQcm9wZXJ0aWVzPShwcm9wZXJ0aWVzLG9wdGlvbnMpPT57Y29uc3Qgb3B0aW9uc1BhZ2VQcm9wcz1vcHRpb25zPy5wYWdlfHx7fTtjb25zdCBwYWdlUHJvcHM9cHJvcGVydGllczsvLyBOZWVkIHRvIGdldCB1cGRhdGVkIHBhZ2UgZGV0YWlscyBvbiBlYWNoIGV2ZW50IGFzIGFuIGV2ZW50IHRvIG5vdGlmeSBvbiBTUEEgVVJMIGNoYW5nZXMgZG9lcyBub3Qgc2VlbSB0byBleGlzdFxuY29uc3QgY3VyUGFnZVByb3BzPWdldERlZmF1bHRQYWdlUHJvcGVydGllcygpO09iamVjdC5rZXlzKGN1clBhZ2VQcm9wcykuZm9yRWFjaChrZXk9PntpZihpc1VuZGVmaW5lZChwYWdlUHJvcHNba2V5XSkpe3BhZ2VQcm9wc1trZXldPW9wdGlvbnNQYWdlUHJvcHNba2V5XXx8Y3VyUGFnZVByb3BzW2tleV07fX0pO2lmKGlzVW5kZWZpbmVkKHBhZ2VQcm9wcy5pbml0aWFsX3JlZmVycmVyKSl7cGFnZVByb3BzLmluaXRpYWxfcmVmZXJyZXI9b3B0aW9uc1BhZ2VQcm9wcy5pbml0aWFsX3JlZmVycmVyfHxzdGF0ZS5zZXNzaW9uLmluaXRpYWxSZWZlcnJlci52YWx1ZTt9aWYoaXNVbmRlZmluZWQocGFnZVByb3BzLmluaXRpYWxfcmVmZXJyaW5nX2RvbWFpbikpe3BhZ2VQcm9wcy5pbml0aWFsX3JlZmVycmluZ19kb21haW49b3B0aW9uc1BhZ2VQcm9wcy5pbml0aWFsX3JlZmVycmluZ19kb21haW58fHN0YXRlLnNlc3Npb24uaW5pdGlhbFJlZmVycmluZ0RvbWFpbi52YWx1ZTt9cmV0dXJuIHBhZ2VQcm9wczt9Oy8qKlxuICogVXRpbGl0eSB0byBjaGVjayBmb3IgcmVzZXJ2ZWQga2V5cyBpbiB0aGUgaW5wdXQgb2JqZWN0XG4gKiBAcGFyYW0gb2JqIEdlbmVyaWMgb2JqZWN0XG4gKiBAcGFyYW0gcGFyZW50S2V5UGF0aCBPYmplY3QncyBwYXJlbnQga2V5IHBhdGhcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gKi9jb25zdCBjaGVja0ZvclJlc2VydmVkRWxlbWVudHNJbk9iamVjdD0ob2JqLHBhcmVudEtleVBhdGgsbG9nZ2VyKT0+e2lmKGlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwob2JqKSl7T2JqZWN0LmtleXMob2JqKS5mb3JFYWNoKHByb3BlcnR5PT57aWYoUkVTRVJWRURfRUxFTUVOVFMuaW5jbHVkZXMocHJvcGVydHkpfHxSRVNFUlZFRF9FTEVNRU5UUy5pbmNsdWRlcyhwcm9wZXJ0eS50b0xvd2VyQ2FzZSgpKSl7bG9nZ2VyLndhcm4oUkVTRVJWRURfS0VZV09SRF9XQVJOSU5HKEVWRU5UX01BTkFHRVIscHJvcGVydHkscGFyZW50S2V5UGF0aCxSRVNFUlZFRF9FTEVNRU5UUykpO319KTt9fTsvKipcbiAqIENoZWNrcyBmb3IgcmVzZXJ2ZWQga2V5cyBpbiB0cmFpdHMsIHByb3BlcnRpZXMsIGFuZCBjb250ZXh0dWFsIHRyYWl0c1xuICogQHBhcmFtIHJ1ZGRlckV2ZW50IEdlbmVyYXRlZCBydWRkZXIgZXZlbnRcbiAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIGluc3RhbmNlXG4gKi9jb25zdCBjaGVja0ZvclJlc2VydmVkRWxlbWVudHM9KHJ1ZGRlckV2ZW50LGxvZ2dlcik9PnsvLyAgcHJvcGVydGllcywgdHJhaXRzLCBjb250ZXh0dWFsVHJhaXRzIGFyZSBlaXRoZXIgdW5kZWZpbmVkIG9yIG9iamVjdFxuY29uc3R7cHJvcGVydGllcyx0cmFpdHMsY29udGV4dH09cnVkZGVyRXZlbnQ7Y29uc3R7dHJhaXRzOmNvbnRleHR1YWxUcmFpdHN9PWNvbnRleHQ7Y2hlY2tGb3JSZXNlcnZlZEVsZW1lbnRzSW5PYmplY3QocHJvcGVydGllcywncHJvcGVydGllcycsbG9nZ2VyKTtjaGVja0ZvclJlc2VydmVkRWxlbWVudHNJbk9iamVjdCh0cmFpdHMsJ3RyYWl0cycsbG9nZ2VyKTtjaGVja0ZvclJlc2VydmVkRWxlbWVudHNJbk9iamVjdChjb250ZXh0dWFsVHJhaXRzLCdjb250ZXh0LnRyYWl0cycsbG9nZ2VyKTt9Oy8qKlxuICogT3ZlcnJpZGVzIHRoZSB0b3AtbGV2ZWwgZXZlbnQgcHJvcGVydGllcyB3aXRoIGRhdGEgZnJvbSBBUEkgb3B0aW9uc1xuICogQHBhcmFtIHJ1ZGRlckV2ZW50IEdlbmVyYXRlZCBydWRkZXIgZXZlbnRcbiAqIEBwYXJhbSBvcHRpb25zIEFQSSBvcHRpb25zXG4gKi9jb25zdCB1cGRhdGVUb3BMZXZlbEV2ZW50RWxlbWVudHM9KHJ1ZGRlckV2ZW50LG9wdGlvbnMpPT57aWYob3B0aW9ucy5hbm9ueW1vdXNJZCYmaXNTdHJpbmcob3B0aW9ucy5hbm9ueW1vdXNJZCkpey8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1wYXJhbS1yZWFzc2lnblxucnVkZGVyRXZlbnQuYW5vbnltb3VzSWQ9b3B0aW9ucy5hbm9ueW1vdXNJZDt9aWYoaXNOb25FbXB0eU9iamVjdChvcHRpb25zLmludGVncmF0aW9ucykpey8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1wYXJhbS1yZWFzc2lnblxucnVkZGVyRXZlbnQuaW50ZWdyYXRpb25zPW9wdGlvbnMuaW50ZWdyYXRpb25zO31pZihvcHRpb25zLm9yaWdpbmFsVGltZXN0YW1wJiZpc1N0cmluZyhvcHRpb25zLm9yaWdpbmFsVGltZXN0YW1wKSl7Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXBhcmFtLXJlYXNzaWduXG5ydWRkZXJFdmVudC5vcmlnaW5hbFRpbWVzdGFtcD1vcHRpb25zLm9yaWdpbmFsVGltZXN0YW1wO319Oy8qKlxuICogVG8gbWVyZ2UgdGhlIGNvbnRleHR1YWwgaW5mb3JtYXRpb24gaW4gQVBJIG9wdGlvbnMgd2l0aCBleGlzdGluZyBkYXRhXG4gKiBAcGFyYW0gcnVkZGVyQ29udGV4dCBHZW5lcmF0ZWQgcnVkZGVyIGV2ZW50XG4gKiBAcGFyYW0gb3B0aW9ucyBBUEkgb3B0aW9uc1xuICogQHBhcmFtIGxvZ2dlciBMb2dnZXIgaW5zdGFuY2VcbiAqL2NvbnN0IGdldE1lcmdlZENvbnRleHQ9KHJ1ZGRlckNvbnRleHQsb3B0aW9ucyxsb2dnZXIpPT57bGV0IGNvbnRleHQ9cnVkZGVyQ29udGV4dDtPYmplY3Qua2V5cyhvcHRpb25zKS5mb3JFYWNoKGtleT0+e2lmKCFUT1BfTEVWRUxfRUxFTUVOVFMuaW5jbHVkZXMoa2V5KSYmIUNPTlRFWFRfUkVTRVJWRURfRUxFTUVOVFMuaW5jbHVkZXMoa2V5KSl7aWYoa2V5IT09J2NvbnRleHQnKXtjb250ZXh0PW1lcmdlRGVlcFJpZ2h0KGNvbnRleHQse1trZXldOm9wdGlvbnNba2V5XX0pO31lbHNlIGlmKCFpc1VuZGVmaW5lZChvcHRpb25zW2tleV0pJiZpc09iamVjdExpdGVyYWxBbmROb3ROdWxsKG9wdGlvbnNba2V5XSkpe2NvbnN0IHRlbXBDb250ZXh0PXt9O09iamVjdC5rZXlzKG9wdGlvbnNba2V5XSkuZm9yRWFjaChlPT57aWYoIUNPTlRFWFRfUkVTRVJWRURfRUxFTUVOVFMuaW5jbHVkZXMoZSkpe3RlbXBDb250ZXh0W2VdPW9wdGlvbnNba2V5XVtlXTt9fSk7Y29udGV4dD1tZXJnZURlZXBSaWdodChjb250ZXh0LHsuLi50ZW1wQ29udGV4dH0pO31lbHNlIHtsb2dnZXIud2FybihJTlZBTElEX0NPTlRFWFRfT0JKRUNUX1dBUk5JTkcoRVZFTlRfTUFOQUdFUikpO319fSk7cmV0dXJuIGNvbnRleHQ7fTsvKipcbiAqIFVwZGF0ZXMgcnVkZGVyIGV2ZW50IG9iamVjdCB3aXRoIGRhdGEgZnJvbSB0aGUgQVBJIG9wdGlvbnNcbiAqIEBwYXJhbSBydWRkZXJFdmVudCBHZW5lcmF0ZWQgcnVkZGVyIGV2ZW50XG4gKiBAcGFyYW0gb3B0aW9ucyBBUEkgb3B0aW9uc1xuICovY29uc3QgcHJvY2Vzc09wdGlvbnM9KHJ1ZGRlckV2ZW50LG9wdGlvbnMsbG9nZ2VyKT0+ey8vIE9ubHkgYWxsb3cgb2JqZWN0IHR5cGUgZm9yIG9wdGlvbnNcbmlmKGlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwob3B0aW9ucykpe3VwZGF0ZVRvcExldmVsRXZlbnRFbGVtZW50cyhydWRkZXJFdmVudCxvcHRpb25zKTsvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcGFyYW0tcmVhc3NpZ25cbnJ1ZGRlckV2ZW50LmNvbnRleHQ9Z2V0TWVyZ2VkQ29udGV4dChydWRkZXJFdmVudC5jb250ZXh0LG9wdGlvbnMsbG9nZ2VyKTt9fTsvKipcbiAqIFJldHVybnMgdGhlIGZpbmFsIGludGVncmF0aW9ucyBjb25maWcgZm9yIHRoZSBldmVudCBiYXNlZCBvbiB0aGUgZ2xvYmFsIGNvbmZpZyBhbmQgZXZlbnQncyBjb25maWdcbiAqIEBwYXJhbSBpbnRlZ3JhdGlvbnNDb25maWcgRXZlbnQncyBpbnRlZ3JhdGlvbnMgY29uZmlnXG4gKiBAcmV0dXJucyBGaW5hbCBpbnRlZ3JhdGlvbnMgY29uZmlnXG4gKi9jb25zdCBnZXRFdmVudEludGVncmF0aW9uc0NvbmZpZz1pbnRlZ3JhdGlvbnNDb25maWc9PntsZXQgZmluYWxJbnRnQ29uZmlnO2lmKHN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnVzZUdsb2JhbEludGVncmF0aW9uc0NvbmZpZ0luRXZlbnRzKXsvLyBQcmVmZXIgdGhlIGludGVncmF0aW9ucyBvYmplY3QgZnJvbSB0aGUgY29uc2VudCBBUEkgcmVzcG9uc2Ugb3ZlciB0aGUgbG9hZCBBUEkgaW50ZWdyYXRpb25zIG9iamVjdFxuZmluYWxJbnRnQ29uZmlnPXN0YXRlLmNvbnNlbnRzLnBvc3RDb25zZW50LnZhbHVlLmludGVncmF0aW9ucz8/c3RhdGUubmF0aXZlRGVzdGluYXRpb25zLmxvYWRPbmx5SW50ZWdyYXRpb25zLnZhbHVlO31lbHNlIGlmKGludGVncmF0aW9uc0NvbmZpZyl7ZmluYWxJbnRnQ29uZmlnPWludGVncmF0aW9uc0NvbmZpZzt9ZWxzZSB7ZmluYWxJbnRnQ29uZmlnPURFRkFVTFRfSU5URUdSQVRJT05TX0NPTkZJRzt9cmV0dXJuIGNsb25lKGZpbmFsSW50Z0NvbmZpZyk7fTsvKipcbiAqIEVucmljaCB0aGUgYmFzZSBldmVudCBvYmplY3Qgd2l0aCBkYXRhIGZyb20gc3RhdGUgYW5kIHR
1oZSBBUEkgb3B0aW9uc1xuICogQHBhcmFtIHJ1ZGRlckV2ZW50IFJ1ZGRlckV2ZW50IG9iamVjdFxuICogQHBhcmFtIG9wdGlvbnMgQVBJIG9wdGlvbnNcbiAqIEBwYXJhbSBwYWdlUHJvcHMgUGFnZSBwcm9wZXJ0aWVzXG4gKiBAcGFyYW0gbG9nZ2VyIGxvZ2dlclxuICogQHJldHVybnMgRW5yaWNoZWQgUnVkZGVyRXZlbnQgb2JqZWN0XG4gKi9jb25zdCBnZXRFbnJpY2hlZEV2ZW50PShydWRkZXJFdmVudCxvcHRpb25zLHBhZ2VQcm9wcyxsb2dnZXIpPT57Y29uc3QgY29tbW9uRXZlbnREYXRhPXtjaGFubmVsOkNIQU5ORUwsY29udGV4dDp7dHJhaXRzOmNsb25lKHN0YXRlLnNlc3Npb24udXNlclRyYWl0cy52YWx1ZSksc2Vzc2lvbklkOnN0YXRlLnNlc3Npb24uc2Vzc2lvbkluZm8udmFsdWUuaWR8fHVuZGVmaW5lZCxzZXNzaW9uU3RhcnQ6c3RhdGUuc2Vzc2lvbi5zZXNzaW9uSW5mby52YWx1ZS5zZXNzaW9uU3RhcnR8fHVuZGVmaW5lZCwvLyBBZGQgJ2NvbnNlbnRNYW5hZ2VtZW50JyBvbmx5IGlmIGNvbnNlbnQgbWFuYWdlbWVudCBpcyBlbmFibGVkXG4uLi4oc3RhdGUuY29uc2VudHMuZW5hYmxlZC52YWx1ZSYme2NvbnNlbnRNYW5hZ2VtZW50OntkZW5pZWRDb25zZW50SWRzOmNsb25lKHN0YXRlLmNvbnNlbnRzLmRhdGEudmFsdWUuZGVuaWVkQ29uc2VudElkcyksYWxsb3dlZENvbnNlbnRJZHM6Y2xvbmUoc3RhdGUuY29uc2VudHMuZGF0YS52YWx1ZS5hbGxvd2VkQ29uc2VudElkcykscHJvdmlkZXI6c3RhdGUuY29uc2VudHMucHJvdmlkZXIudmFsdWUscmVzb2x1dGlvblN0cmF0ZWd5OnN0YXRlLmNvbnNlbnRzLnJlc29sdXRpb25TdHJhdGVneS52YWx1ZX19KSwndWEtY2gnOnN0YXRlLmNvbnRleHRbJ3VhLWNoJ10udmFsdWUsYXBwOnN0YXRlLmNvbnRleHQuYXBwLnZhbHVlLGxpYnJhcnk6c3RhdGUuY29udGV4dC5saWJyYXJ5LnZhbHVlLHVzZXJBZ2VudDpzdGF0ZS5jb250ZXh0LnVzZXJBZ2VudC52YWx1ZSxvczpzdGF0ZS5jb250ZXh0Lm9zLnZhbHVlLGxvY2FsZTpzdGF0ZS5jb250ZXh0LmxvY2FsZS52YWx1ZSxzY3JlZW46c3RhdGUuY29udGV4dC5zY3JlZW4udmFsdWUsY2FtcGFpZ246ZXh0cmFjdFVUTVBhcmFtZXRlcnMoZ2xvYmFsVGhpcy5sb2NhdGlvbi5ocmVmKSxwYWdlOmdldENvbnRleHRQYWdlUHJvcGVydGllcyhwYWdlUHJvcHMpLHRpbWV6b25lOnN0YXRlLmNvbnRleHQudGltZXpvbmUudmFsdWUsLy8gQWRkIGF1dG8gdHJhY2tpbmcgaW5mb3JtYXRpb25cbi4uLihzdGF0ZS5hdXRvVHJhY2suZW5hYmxlZC52YWx1ZSYme2F1dG9UcmFjazp7Li4uKHN0YXRlLmF1dG9UcmFjay5wYWdlTGlmZWN5Y2xlLmVuYWJsZWQudmFsdWUmJntwYWdlOntwYWdlVmlld0lkOnN0YXRlLmF1dG9UcmFjay5wYWdlTGlmZWN5Y2xlLnBhZ2VWaWV3SWQudmFsdWV9fSl9fSl9LG9yaWdpbmFsVGltZXN0YW1wOmdldEN1cnJlbnRUaW1lRm9ybWF0dGVkKCksbWVzc2FnZUlkOmdlbmVyYXRlVVVJRCgpLHVzZXJJZDpydWRkZXJFdmVudC51c2VySWR8fHN0YXRlLnNlc3Npb24udXNlcklkLnZhbHVlfTtpZighaXNTdG9yYWdlVHlwZVZhbGlkRm9yU3RvcmluZ0RhdGEoc3RhdGUuc3RvcmFnZS5lbnRyaWVzLnZhbHVlLmFub255bW91c0lkPy50eXBlKSl7Ly8gR2VuZXJhdGUgbmV3IGFub255bW91cyBpZCBmb3IgZWFjaCByZXF1ZXN0XG5jb21tb25FdmVudERhdGEuYW5vbnltb3VzSWQ9Z2VuZXJhdGVBbm9ueW1vdXNJZCgpO31lbHNlIHsvLyBUeXBlIGNhc3RpbmcgdG8gc3RyaW5nIGFzIHRoZSB1c2VyIHNlc3Npb24gbWFuYWdlciB3aWxsIHRha2UgY2FyZSBvZiBpbml0aWFsaXppbmcgdGhlIHZhbHVlXG5jb21tb25FdmVudERhdGEuYW5vbnltb3VzSWQ9c3RhdGUuc2Vzc2lvbi5hbm9ueW1vdXNJZC52YWx1ZTt9Ly8gc2V0IHRydWx5IGFub255bW91cyB0cmFja2luZyBmbGFnXG5pZihzdGF0ZS5zdG9yYWdlLnRydWx5QW5vbnltb3VzVHJhY2tpbmcudmFsdWUpe2NvbW1vbkV2ZW50RGF0YS5jb250ZXh0LnRydWx5QW5vbnltb3VzVHJhY2tpbmc9dHJ1ZTt9aWYocnVkZGVyRXZlbnQudHlwZT09PSdpZGVudGlmeScpe2NvbW1vbkV2ZW50RGF0YS5jb250ZXh0LnRyYWl0cz1zdGF0ZS5zdG9yYWdlLmVudHJpZXMudmFsdWUudXNlclRyYWl0cz8udHlwZSE9PU5PX1NUT1JBR0U/Y2xvbmUoc3RhdGUuc2Vzc2lvbi51c2VyVHJhaXRzLnZhbHVlKTpydWRkZXJFdmVudC5jb250ZXh0LnRyYWl0czt9aWYocnVkZGVyRXZlbnQudHlwZT09PSdncm91cCcpe2lmKHJ1ZGRlckV2ZW50Lmdyb3VwSWR8fHN0YXRlLnNlc3Npb24uZ3JvdXBJZC52YWx1ZSl7Y29tbW9uRXZlbnREYXRhLmdyb3VwSWQ9cnVkZGVyRXZlbnQuZ3JvdXBJZHx8c3RhdGUuc2Vzc2lvbi5ncm91cElkLnZhbHVlO31pZihydWRkZXJFdmVudC50cmFpdHN8fHN0YXRlLnNlc3Npb24uZ3JvdXBUcmFpdHMudmFsdWUpe2NvbW1vbkV2ZW50RGF0YS50cmFpdHM9c3RhdGUuc3RvcmFnZS5lbnRyaWVzLnZhbHVlLmdyb3VwVHJhaXRzPy50eXBlIT09Tk9fU1RPUkFHRT9jbG9uZShzdGF0ZS5zZXNzaW9uLmdyb3VwVHJhaXRzLnZhbHVlKTpydWRkZXJFdmVudC50cmFpdHM7fX1jb25zdCBwcm9jZXNzZWRFdmVudD1tZXJnZURlZXBSaWdodChydWRkZXJFdmVudCxjb21tb25FdmVudERhdGEpOy8vIFNldCB0aGUgZGVmYXVsdCB2YWx1ZXMgZm9yIHRoZSBldmVudCBwcm9wZXJ0aWVzXG4vLyBtYXRjaGluZyB3aXRoIHYxLjEgcGF5bG9hZFxuaWYocHJvY2Vzc2VkRXZlbnQuZXZlbnQ9PT11bmRlZmluZWQpe3Byb2Nlc3NlZEV2ZW50LmV2ZW50PW51bGw7fWlmKHByb2Nlc3NlZEV2ZW50LnByb3BlcnRpZXM9PT11bmRlZmluZWQpe3Byb2Nlc3NlZEV2ZW50LnByb3BlcnRpZXM9bnVsbDt9cHJvY2Vzc09wdGlvbnMocHJvY2Vzc2VkRXZlbnQsb3B0aW9ucyxsb2dnZXIpO2NoZWNrRm9yUmVzZXJ2ZWRFbGVtZW50cyhwcm9jZXNzZWRFdmVudCxsb2dnZXIpOy8vIFVwZGF0ZSB0aGUgaW50ZWdyYXRpb25zIGNvbmZpZyBmb3IgdGhlIGV2ZW50XG5wcm9jZXNzZWRFdmVudC5pbnRlZ3JhdGlvbnM9Z2V0RXZlbnRJbnRlZ3JhdGlvbnNDb25maWcocHJvY2Vzc2VkRXZlbnQuaW50ZWdyYXRpb25zKTtyZXR1cm4gcHJvY2Vzc2VkRXZlbnQ7fTtcblxuY2xhc3MgUnVkZGVyRXZlbnRGYWN0b3J5e2NvbnN0cnVjdG9yKGxvZ2dlcil7dGhpcy5sb2dnZXI9bG9nZ2VyO30vKipcbiAgICogR2VuZXJhdGUgYSAncGFnZScgZXZlbnQgYmFzZWQgb24gdGhlIHVzZXItaW5wdXQgZmllbGRzXG4gICAqIEBwYXJhbSBjYXRlZ29yeSBQYWdlJ3MgY2F0ZWdvcnlcbiAgICogQHBhcmFtIG5hbWUgUGFnZSBuYW1lXG4gICAqIEBwYXJhbSBwcm9wZXJ0aWVzIFBhZ2UgcHJv
1cGVydGllc1xuICAgKiBAcGFyYW0gb3B0aW9ucyBBUEkgb3B0aW9uc1xuICAgKi9nZW5lcmF0ZVBhZ2VFdmVudChjYXRlZ29yeSxuYW1lLHByb3BlcnRpZXMsb3B0aW9ucyl7bGV0IHByb3BzPXByb3BlcnRpZXM/P3t9O3Byb3BzPWdldFVwZGF0ZWRQYWdlUHJvcGVydGllcyhwcm9wcyxvcHRpb25zKTtjb25zdCBwYWdlRXZlbnQ9e3Byb3BlcnRpZXM6cHJvcHMsbmFtZSxjYXRlZ29yeSx0eXBlOidwYWdlJ307cmV0dXJuIGdldEVucmljaGVkRXZlbnQocGFnZUV2ZW50LG9wdGlvbnMscHJvcHMsdGhpcy5sb2dnZXIpO30vKipcbiAgICogR2VuZXJhdGUgYSAndHJhY2snIGV2ZW50IGJhc2VkIG9uIHRoZSB1c2VyLWlucHV0IGZpZWxkc1xuICAgKiBAcGFyYW0gZXZlbnQgVGhlIGV2ZW50IG5hbWVcbiAgICogQHBhcmFtIHByb3BlcnRpZXMgRXZlbnQgcHJvcGVydGllc1xuICAgKiBAcGFyYW0gb3B0aW9ucyBBUEkgb3B0aW9uc1xuICAgKi9nZW5lcmF0ZVRyYWNrRXZlbnQoZXZlbnQscHJvcGVydGllcyxvcHRpb25zKXtjb25zdCB0cmFja0V2ZW50PXtwcm9wZXJ0aWVzLGV2ZW50LHR5cGU6J3RyYWNrJ307cmV0dXJuIGdldEVucmljaGVkRXZlbnQodHJhY2tFdmVudCxvcHRpb25zLHVuZGVmaW5lZCx0aGlzLmxvZ2dlcik7fS8qKlxuICAgKiBHZW5lcmF0ZSBhbiAnaWRlbnRpZnknIGV2ZW50IGJhc2VkIG9uIHRoZSB1c2VyLWlucHV0IGZpZWxkc1xuICAgKiBAcGFyYW0gdXNlcklkIE5ldyB1c2VyIElEXG4gICAqIEBwYXJhbSB0cmFpdHMgbmV3IHRyYWl0c1xuICAgKiBAcGFyYW0gb3B0aW9ucyBBUEkgb3B0aW9uc1xuICAgKi9nZW5lcmF0ZUlkZW50aWZ5RXZlbnQodXNlcklkLHRyYWl0cyxvcHRpb25zKXtjb25zdCBpZGVudGlmeUV2ZW50PXt1c2VySWQsdHlwZTonaWRlbnRpZnknLGNvbnRleHQ6e3RyYWl0c319O3JldHVybiBnZXRFbnJpY2hlZEV2ZW50KGlkZW50aWZ5RXZlbnQsb3B0aW9ucyx1bmRlZmluZWQsdGhpcy5sb2dnZXIpO30vKipcbiAgICogR2VuZXJhdGUgYW4gJ2FsaWFzJyBldmVudCBiYXNlZCBvbiB0aGUgdXNlci1pbnB1dCBmaWVsZHNcbiAgICogQHBhcmFtIHRvIE5ldyB1c2VyIElEXG4gICAqIEBwYXJhbSBmcm9tIE9sZCB1c2VyIElEXG4gICAqIEBwYXJhbSBvcHRpb25zIEFQSSBvcHRpb25zXG4gICAqL2dlbmVyYXRlQWxpYXNFdmVudCh0byxmcm9tLG9wdGlvbnMpe2NvbnN0IGFsaWFzRXZlbnQ9e3ByZXZpb3VzSWQ6ZnJvbSx0eXBlOidhbGlhcyd9O2NvbnN0IGVucmljaGVkRXZlbnQ9Z2V0RW5yaWNoZWRFdmVudChhbGlhc0V2ZW50LG9wdGlvbnMsdW5kZWZpbmVkLHRoaXMubG9nZ2VyKTsvLyBvdmVycmlkZSB0aGUgVXNlciBJRCBmcm9tIHRoZSBBUEkgaW5wdXRzXG5lbnJpY2hlZEV2ZW50LnVzZXJJZD10bz8/ZW5yaWNoZWRFdmVudC51c2VySWQ7cmV0dXJuIGVucmljaGVkRXZlbnQ7fS8qKlxuICAgKiBHZW5lcmF0ZSBhICdncm91cCcgZXZlbnQgYmFzZWQgb24gdGhlIHVzZXItaW5wdXQgZmllbGRzXG4gICAqIEBwYXJhbSBncm91cElkIE5ldyBncm91cCBJRFxuICAgKiBAcGFyYW0gdHJhaXRzIG5ldyBncm91cCB0cmFpdHNcbiAgICogQHBhcmFtIG9wdGlvbnMgQVBJIG9wdGlvbnNcbiAgICovZ2VuZXJhdGVHcm91cEV2ZW50KGdyb3VwSWQsdHJhaXRzLG9wdGlvbnMpe2NvbnN0IGdyb3VwRXZlbnQ9e3R5cGU6J2dyb3VwJ307aWYoZ3JvdXBJZCl7Z3JvdXBFdmVudC5ncm91cElkPWdyb3VwSWQ7fWlmKHRyYWl0cyl7Z3JvdXBFdmVudC50cmFpdHM9dHJhaXRzO31yZXR1cm4gZ2V0RW5yaWNoZWRFdmVudChncm91cEV2ZW50LG9wdGlvbnMsdW5kZWZpbmVkLHRoaXMubG9nZ2VyKTt9LyoqXG4gICAqIEdlbmVyYXRlcyBhIG5ldyBSdWRkZXJFdmVudCBvYmplY3QgYmFzZWQgb24gdGhlIHVzZXItaW5wdXQgZmllbGRzXG4gICAqIEBwYXJhbSBldmVudCBBUEkgZXZlbnQgcGFyYW1ldGVycyBvYmplY3RcbiAgICogQHJldHVybnMgQSBSdWRkZXJFdmVudCBvYmplY3RcbiAgICovY3JlYXRlKGV2ZW50KXtsZXQgZXZlbnRPYmo7c3dpdGNoKGV2ZW50LnR5cGUpe2Nhc2UgJ3BhZ2UnOmV2ZW50T2JqPXRoaXMuZ2VuZXJhdGVQYWdlRXZlbnQoZXZlbnQuY2F0ZWdvcnksZXZlbnQubmFtZSxldmVudC5wcm9wZXJ0aWVzLGV2ZW50Lm9wdGlvbnMpO2JyZWFrO2Nhc2UgJ3RyYWNrJzpldmVudE9iaj10aGlzLmdlbmVyYXRlVHJhY2tFdmVudChldmVudC5uYW1lLGV2ZW50LnByb3BlcnRpZXMsZXZlbnQub3B0aW9ucyk7YnJlYWs7Y2FzZSAnaWRlbnRpZnknOmV2ZW50T2JqPXRoaXMuZ2VuZXJhdGVJZGVudGlmeUV2ZW50KGV2ZW50LnVzZXJJZCxldmVudC50cmFpdHMsZXZlbnQub3B0aW9ucyk7YnJlYWs7Y2FzZSAnYWxpYXMnOmV2ZW50T2JqPXRoaXMuZ2VuZXJhdGVBbGlhc0V2ZW50KGV2ZW50LnRvLGV2ZW50LmZyb20sZXZlbnQub3B0aW9ucyk7YnJlYWs7Y2FzZSAnZ3JvdXAnOmRlZmF1bHQ6ZXZlbnRPYmo9dGhpcy5nZW5lcmF0ZUdyb3VwRXZlbnQoZXZlbnQuZ3JvdXBJZCxldmVudC50cmFpdHMsZXZlbnQub3B0aW9ucyk7YnJlYWs7fXJldHVybiBldmVudE9iajt9fVxuXG4vKipcbiAqIEEgc2VydmljZSB0byBnZW5lcmF0ZSB2YWxpZCBldmVudCBwYXlsb2FkcyBhbmQgcXVldWUgdGhlbSBmb3IgcHJvY2Vzc2luZ1xuICovY2xhc3MgRXZlbnRNYW5hZ2Vyey8qKlxuICAgKlxuICAgKiBAcGFyYW0gZXZlbnRSZXBvc2l0b3J5IEV2ZW50IHJlcG9zaXRvcnkgaW5zdGFuY2VcbiAgICogQHBhcmFtIHVzZXJTZXNzaW9uTWFuYWdlciBVc2VyU2Vzc2lvbiBNYW5hZ2VyIGluc3RhbmNlXG4gICAqIEBwYXJhbSBlcnJvckhhbmRsZXIgRXJyb3IgaGFuZGxlciBvYmplY3RcbiAgICogQHBhcmFtIGxvZ2dlciBMb2dnZXIgb2JqZWN0XG4gICAqL2NvbnN0cnVjdG9yKGV2ZW50UmVwb3NpdG9yeSx1c2VyU2Vzc2lvbk1hbmFnZXIsZXJyb3JIYW5kbGVyLGxvZ2dlcil7dGhpcy5ldmVudFJlcG9zaXRvcnk9ZXZlbnRSZXBvc2l0b3J5O3RoaXMudXNlclNlc3Npb25NYW5hZ2VyPXVzZXJTZXNzaW9uTWFuYWdlcjt0aGlzLmVycm9ySGFuZGxlcj1lcnJvckhhbmRsZXI7dGhpcy5sb2dnZXI9bG9nZ2VyO3RoaXMuZXZlbnRGYWN0b3J5PW5ldyBSdWRkZXJFdmVudEZhY3RvcnkodGhpcy5sb2dnZXIpO30vKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIGV2ZW50IG1hbmFnZXJcbiAgICovaW5pdCgpe3RoaXMuZXZlbnRSZXBvc2l0b3J5LmluaXQoKTt9cmVzdW1lKCl7dGhpcy5ldmVudFJlcG9zaXRvcnkucmVzdW1lKCk7fS8qKlxuICAgKiBDb25zdW1lcyBhIG5ldyBpbmNvbWluZyBldmVudFxuICAgKiBAcGFyYW0gZXZlbnQgSW5jb21pbmcgZXZlbnQgZGF0YVxuICAgKi9hZGRFdmVudChldmVudCl7dGhpcy51c2VyU2Vzc2lvbk1hbmFnZXIucmVmcmVzaFNlc3Npb24oKTtjb25zdCBydWRkZXJFdmVudD10aGlzLmV2ZW50RmFjdG9yeS5jcmVhdGUoZXZlbnQpO3RoaXMuZXZlbnRSZXBvc2l0b3J5LmVucXVldWUocnVkZGVyRXZlbnQsZXZlbnQuY2FsbGJhY2spO319XG5cbmNsYXNzIFVzZXJTZXNzaW9uTWFuYWdlcnsvKipcbiAgICogVHJhY2tzIHdoZXRoZXIgYSBzZXJ2ZXItc2lkZSBjb29raWUgc2V0dGluZyByZXF1ZXN0IGlzIGluIHByb2dyZXNzIG9yIG5vdC5cbiAgICovY29uc3RydWN0b3IocGx1Z2luc01hbmFnZXIsc3RvcmVNYW5hZ2VyLGh0dHBDbGllbnQsZXJyb3JIYW5kbGVyLGxvZ2dlcil7dGhpcy5zdG9yZU1hbmFnZXI9c3RvcmVNYW5hZ2VyO3RoaXMucGx1Z2luc01hbmFnZXI9cGx1Z2luc01hbmFnZXI7dGhpcy5sb2dnZXI9bG9nZ2VyO3RoaXMuZXJyb3JIYW5kbGVyPWVycm9ySGFuZGxlcjt0aGlzLmh0dHBDbGllbnQ9aHR0cENsaWVudDt0aGlzLm9uRXJyb3I9dGhpcy5vbkVycm9yLmJpbmQodGhpcyk7dGhpcy5zZXJ2ZXJTaWRlQ29va2llRGVib3VuY2VGdW5jcz17fTt0aGlzLnNlcnZlclNpZG
1VDb29raWVzUmVxdWVzdEluUHJvZ3Jlc3M9e307fS8qKlxuICAgKiBJbml0aWFsaXplIFVzZXIgc2Vzc2lvbiB3aXRoIHZhbHVlcyBmcm9tIHN0b3JhZ2VcbiAgICovaW5pdCgpe3RoaXMuc3luY1N0b3JhZ2VEYXRhVG9TdGF0ZSgpOy8vIFJlZ2lzdGVyIHRoZSBlZmZlY3QgdG8gc3luYyB3aXRoIHN0b3JhZ2VcbnRoaXMucmVnaXN0ZXJFZmZlY3RzKCk7fXN5bmNTdG9yYWdlRGF0YVRvU3RhdGUoKXt0aGlzLm1pZ3JhdGVTdG9yYWdlSWZOZWVkZWQoKTt0aGlzLm1pZ3JhdGVEYXRhRnJvbVByZXZpb3VzU3RvcmFnZSgpOy8vIGdldCB0aGUgdmFsdWVzIGZyb20gc3RvcmFnZSBhbmQgc2V0IGl0IGFnYWluXG50aGlzLnNldFVzZXJJZCh0aGlzLmdldFVzZXJJZCgpKTt0aGlzLnNldFVzZXJUcmFpdHModGhpcy5nZXRVc2VyVHJhaXRzKCkpO3RoaXMuc2V0R3JvdXBJZCh0aGlzLmdldEdyb3VwSWQoKSk7dGhpcy5zZXRHcm91cFRyYWl0cyh0aGlzLmdldEdyb3VwVHJhaXRzKCkpO2NvbnN0e2V4dGVybmFsQW5vbnltb3VzSWRDb29raWVOYW1lLGFub255bW91c0lkT3B0aW9uc309c3RhdGUubG9hZE9wdGlvbnMudmFsdWU7bGV0IGV4dGVybmFsQW5vbnltb3VzSWQ7aWYoaXNEZWZpbmVkQW5kTm90TnVsbChleHRlcm5hbEFub255bW91c0lkQ29va2llTmFtZSkmJnR5cGVvZiBleHRlcm5hbEFub255bW91c0lkQ29va2llTmFtZT09PSdzdHJpbmcnKXtleHRlcm5hbEFub255bW91c0lkPXRoaXMuZ2V0RXh0ZXJuYWxBbm9ueW1vdXNJZEJ5Q29va2llTmFtZShleHRlcm5hbEFub255bW91c0lkQ29va2llTmFtZSk7fXRoaXMuc2V0QW5vbnltb3VzSWQoZXh0ZXJuYWxBbm9ueW1vdXNJZD8/dGhpcy5nZXRBbm9ueW1vdXNJZChhbm9ueW1vdXNJZE9wdGlvbnMpKTt0aGlzLnNldEF1dGhUb2tlbih0aGlzLmdldEF1dGhUb2tlbigpKTt0aGlzLnNldEluaXRpYWxSZWZlcnJlckluZm8oKTt0aGlzLmNvbmZpZ3VyZVNlc3Npb25UcmFja2luZygpO31jb25maWd1cmVTZXNzaW9uVHJhY2tpbmcoKXtsZXQgc2Vzc2lvbkluZm87aWYodGhpcy5pc1BlcnNpc3RlbmNlRW5hYmxlZEZvclN0b3JhZ2VFbnRyeSgnc2Vzc2lvbkluZm8nKSl7Y29uc3QgY29uZmlndXJlZFNlc3Npb25UcmFja2luZ0luZm89dGhpcy5nZXRDb25maWd1cmVkU2Vzc2lvblRyYWNraW5nSW5mbygpO2NvbnN0IGluaXRpYWxTZXNzaW9uSW5mbz10aGlzLmdldFNlc3Npb25JbmZvKCk/P0RFRkFVTFRfVVNFUl9TRVNTSU9OX1ZBTFVFUy5zZXNzaW9uSW5mbzsvLyBNZXJnZSB0aGUgc2Vzc2lvbiBpbmZvIGZyb20gdGhlIHN0b3JhZ2UgYW5kIHRoZSBjb25maWd1cmF0aW9uXG5zZXNzaW9uSW5mbz17Ly8gSWYgbWFudWFsVHJhY2sgaXMgc2V0IHRvIHRydWUgaW4gdGhlIHN0b3JhZ2UsIHRoZW4gZG8gbm90IGVuYWJsZSBhdXRvIHRyYWNraW5nIGV2ZW4gaWYgY29uZmlndXJlZC5cbi8vIE9uY2UgbWFudWFsIHRyYWNraW5nIGVuZHMgKGVuZFNlc3Npb24gaXMgY2FsbGVkKSwgYXV0byB0cmFja2luZyB3aWxsIGJlIGVuYWJsZWQgaW4gdGhlIG5leHQgU0RLIHJ1bi5cbmF1dG9UcmFjazpjb25maWd1cmVkU2Vzc2lvblRyYWNraW5nSW5mby5hdXRvVHJhY2smJmluaXRpYWxTZXNzaW9uSW5mby5tYW51YWxUcmFjayE9PXRydWUsdGltZW91dDpjb25maWd1cmVkU2Vzc2lvblRyYWNraW5nSW5mby50aW1lb3V0LG1hbnVhbFRyYWNrOmluaXRpYWxTZXNzaW9uSW5mby5tYW51YWxUcmFjayxleHBpcmVzQXQ6aW5pdGlhbFNlc3Npb25JbmZvLmV4cGlyZXNBdCxpZDppbml0aWFsU2Vzc2lvbkluZm8uaWQsc2Vzc2lvblN0YXJ0OmluaXRpYWxTZXNzaW9uSW5mby5zZXNzaW9uU3RhcnR9Oy8vIElmIGJvdGggYXV0b1RyYWNrIGFuZCBtYW51YWxUcmFjayBhcmUgZGlzYWJsZWQsIHJlc2V0IHRoZSBzZXNzaW9uIGluZm8gdG8gZGVmYXVsdCB2YWx1ZXNcbmlmKCFzZXNzaW9uSW5mby5hdXRvVHJhY2smJnNlc3Npb25JbmZvLm1hbnVhbFRyYWNrIT09dHJ1ZSl7c2Vzc2lvbkluZm89REVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLnNlc3Npb25JbmZvO31lbHNlIGlmKGNvbmZpZ3VyZWRTZXNzaW9uVHJhY2tpbmdJbmZvLmN1dE9mZj8uZW5hYmxlZD09PXRydWUpe3Nlc3Npb25JbmZvLmN1dE9mZj17ZW5hYmxlZDp0cnVlLGR1cmF0aW9uOmNvbmZpZ3VyZWRTZXNzaW9uVHJhY2tpbmdJbmZvLmN1dE9mZi5kdXJhdGlvbixleHBpcmVzQXQ6aW5pdGlhbFNlc3Npb25JbmZvLmN1dE9mZj8uZXhwaXJlc0F0fTt9fWVsc2Uge3Nlc3Npb25JbmZvPURFRkFVTFRfVVNFUl9TRVNTSU9OX1ZBTFVFUy5zZXNzaW9uSW5mbzt9c3RhdGUuc2Vzc2lvbi5zZXNzaW9uSW5mby52YWx1ZT1zZXNzaW9uSW5mbzsvLyBJZiBhdXRvIHNlc3Npb24gdHJhY2tpbmcgaXMgZW5hYmxlZCBzdGFydCB0aGUgc2Vzc2lvbiB0cmFja2luZ1xuaWYoc3RhdGUuc2Vzc2lvbi5zZXNzaW9uSW5mby52YWx1ZS5hdXRvVHJhY2spe3RoaXMuc3RhcnRPclJlbmV3QXV0b1RyYWNraW5nKHN0YXRlLnNlc3Npb24uc2Vzc2lvbkluZm8udmFsdWUpO319c2V0SW5pdGlhbFJlZmVycmVySW5mbygpe2NvbnN0IHBlcnNpc3RlZEluaXRpYWxSZWZlcnJlcj10aGlzLmdldEluaXRpYWxSZWZlcnJlcigpO2NvbnN0IHBlcnNpc3RlZEluaXRpYWxSZWZlcnJpbmdEb21haW49dGhpcy5nZXRJbml0aWFsUmVmZXJyaW5nRG9tYWluKCk7aWYocGVyc2lzdGVkSW5pdGlhbFJlZmVycmVyJiZwZXJzaXN0ZWRJbml0aWFsUmVmZXJyaW5nRG9tYWluKXt0aGlzLnNldEluaXRpYWxSZWZlcnJlcihwZXJzaXN0ZWRJbml0aWFsUmVmZXJyZXIpO3RoaXMuc2V0SW5pdGlhbFJlZmVycmluZ0RvbWFpbihwZXJzaXN0ZWRJbml0aWFsUmVmZXJyaW5nRG9tYWluKTt9ZWxzZSB7Y29uc3QgaW5pdGlhbFJlZmVycmVyPXBlcnNpc3RlZEluaXRpYWxSZWZlcnJlcnx8Z2V0UmVmZXJyZXIoKTt0aGlzLnNldEluaXRpYWxSZWZlcnJlcihpbml0aWFsUmVmZXJyZXIpO3RoaXMuc2V0SW5pdGlhbFJlZmVycmluZ0RvbWFpbihnZXRSZWZlcnJpbmdEb21haW4oaW5pdGlhbFJlZmVycmVyKSk7fX1pc1BlcnNpc3RlbmNlRW5hYmxlZEZvclN0b3JhZ2VFbnRyeShlbnRyeU5hbWUpe3JldHVybiBpc1N0b3JhZ2VUeXBlVmFsaWRGb3JTdG9yaW5nRGF0YShzdGF0ZS5zdG9yYWdlLmVudHJpZXMudmFsdWVbZW50cnlOYW1lXT8udHlwZSk7fW1pZ3JhdGVEYXRhRnJvbVByZXZpb3VzU3RvcmFnZSgpe2NvbnN0IGVudHJpZXM9c3RhdGUuc3RvcmFnZS5lbnRyaWVzLnZhbHVlO2NvbnN0IHN0b3JhZ2VUeXBlc0Zvck1pZ3JhdGlvbj1bQ09PS0lFX1NUT1JBR0UsTE9DQUxfU1RPUkFHRSxTRVNTSU9OX1NUT1JBR0VdO09iamVjdC5rZXlzKGVudHJpZXMpLmZvckVhY2goZW50cnk9Pntjb25zdCBrZXk9ZW50cnk7Y29uc3QgY3VycmVudFN0b3JhZ2U9ZW50cmllc1trZXldPy50eXBlO2NvbnN0IGN1clN0b3JlPXRoaXMuc3RvcmVNYW5hZ2VyPy5nZXRTdG9yZShzdG9yYWdlQ2xpZW50RGF0YVN0b3JlTmFtZU1hcFtjdXJyZW50U3RvcmFnZV0pO2lmKGN1clN0b3JlKXtzdG9yYWdlVHlwZXNGb3JNaWdyYXRpb24uZm9yRWFjaChzdG9yYWdlPT57Y29uc3Qgc3RvcmU9dGhpcy5zdG9yZU1hbmFnZXI/LmdldFN0b3JlKHN0b3JhZ2VDbGllbnREYXRhU3RvcmVOYW1lTWFwW3N0b3JhZ2VdKTtpZihzdG9yZSYmc3RvcmFnZSE9PWN1cnJlbnRTdG9yYWdlKXtjb25zdCB2YWx1ZT1zdG9yZS5nZXQoQ09PS0lFX0tFWVNba2V5XSk7aWYoaXNEZWZpbmVkTm90TnVsbEFuZE5vdEVtcHR5U3RyaW5nKHZhbHVlKSl7Y3VyU3RvcmUuc2V0KENPT0tJRV9LRVlTW2tleV0sdmFsdWUpO31zdG9yZS5yZW1vdmUoQ09PS0lFX0tFWVNba2V5XSk7fX0pO319KTt9bWlncmF0ZVN0b3JhZ2VJZk5lZWRlZChzdG9yZXMsa2V5cyl7aWYoIXN0YXRlLnN0b3JhZ2UubWlncmF0ZS52YWx1ZSl7cmV0dXJuO31sZXQgc3RvcmVzVG9NaWdyYXRlPXN0b3Jlcz8/W107aWYoc3RvcmVzVG9NaWdyYXRlLmxlbmd0aD09PTApe2NvbnN0IHBlcnNpc3Rlb
1nRTdG9yZU5hbWVzPVtDTElFTlRfREFUQV9TVE9SRV9DT09LSUUsQ0xJRU5UX0RBVEFfU1RPUkVfTFMsQ0xJRU5UX0RBVEFfU1RPUkVfU0VTU0lPTl07cGVyc2lzdGVudFN0b3JlTmFtZXMuZm9yRWFjaChzdG9yZU5hbWU9Pntjb25zdCBzdG9yZT10aGlzLnN0b3JlTWFuYWdlcj8uZ2V0U3RvcmUoc3RvcmVOYW1lKTtpZihzdG9yZSl7c3RvcmVzVG9NaWdyYXRlLnB1c2goc3RvcmUpO319KTt9bGV0IGtleXNUb01pZ3JhdGU9a2V5cz8/T2JqZWN0LmtleXMoQ09PS0lFX0tFWVMpO2tleXNUb01pZ3JhdGUuZm9yRWFjaChzdG9yYWdlS2V5PT57Y29uc3Qgc3RvcmFnZUVudHJ5PUNPT0tJRV9LRVlTW3N0b3JhZ2VLZXldO3N0b3Jlc1RvTWlncmF0ZS5mb3JFYWNoKHN0b3JlPT57Y29uc3QgbWlncmF0ZWRWYWw9dGhpcy5wbHVnaW5zTWFuYWdlcj8uaW52b2tlU2luZ2xlKCdzdG9yYWdlLm1pZ3JhdGUnLHN0b3JhZ2VFbnRyeSxzdG9yZS5lbmdpbmUsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpOy8vIFNraXAgc2V0dGluZyB0aGUgdmFsdWUgaWYgaXQgaXMgbnVsbCBvciB1bmRlZmluZWRcbi8vIGFzIHRob3NlIHZhbHVlcyBpbmRpY2F0ZSB0aGVyZSBpcyBubyBuZWVkIGZvciBtaWdyYXRpb24gb3Jcbi8vIG1pZ3JhdGlvbiBmYWlsZWRcbmlmKCFpc051bGxPclVuZGVmaW5lZChtaWdyYXRlZFZhbCkpe3N0b3JlLnNldChzdG9yYWdlRW50cnksbWlncmF0ZWRWYWwpO319KTt9KTt9Z2V0Q29uZmlndXJlZFNlc3Npb25UcmFja2luZ0luZm8oKXtsZXQgYXV0b1RyYWNrPXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnNlc3Npb25zLmF1dG9UcmFjayE9PWZhbHNlOy8vIERvIG5vdCB2YWxpZGF0ZSBhbnkgZnVydGhlciBpZiBhdXRvVHJhY2sgaXMgZGlzYWJsZWRcbmlmKCFhdXRvVHJhY2spe3JldHVybiB7YXV0b1RyYWNrfTt9bGV0IHRpbWVvdXQ7Y29uc3QgY29uZmlndXJlZFNlc3Npb25UaW1lb3V0PXN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnNlc3Npb25zPy50aW1lb3V0O2lmKCFpc1Bvc2l0aXZlSW50ZWdlcihjb25maWd1cmVkU2Vzc2lvblRpbWVvdXQpKXt0aGlzLmxvZ2dlci53YXJuKFRJTUVPVVRfTk9UX05VTUJFUl9XQVJOSU5HKFVTRVJfU0VTU0lPTl9NQU5BR0VSLGNvbmZpZ3VyZWRTZXNzaW9uVGltZW91dCxERUZBVUxUX1NFU1NJT05fVElNRU9VVF9NUykpO3RpbWVvdXQ9REVGQVVMVF9TRVNTSU9OX1RJTUVPVVRfTVM7fWVsc2Uge3RpbWVvdXQ9Y29uZmlndXJlZFNlc3Npb25UaW1lb3V0O31pZih0aW1lb3V0PT09MCl7dGhpcy5sb2dnZXIud2FybihUSU1FT1VUX1pFUk9fV0FSTklORyhVU0VSX1NFU1NJT05fTUFOQUdFUikpO2F1dG9UcmFjaz1mYWxzZTt9Ly8gSW4gY2FzZSB1c2VyIHByb3ZpZGVzIGEgdGltZW91dCB2YWx1ZSBncmVhdGVyIHRoYW4gMCBidXQgbGVzcyB0aGFuIDEwIHNlY29uZHMgU0RLIHdpbGwgc2hvdyBhIHdhcm5pbmdcbi8vIGFuZCB3aWxsIHByb2NlZWQgd2l0aCBpdFxuaWYodGltZW91dD4wJiZ0aW1lb3V0PE1JTl9TRVNTSU9OX1RJTUVPVVRfTVMpe3RoaXMubG9nZ2VyLndhcm4oVElNRU9VVF9OT1RfUkVDT01NRU5ERURfV0FSTklORyhVU0VSX1NFU1NJT05fTUFOQUdFUix0aW1lb3V0LE1JTl9TRVNTSU9OX1RJTUVPVVRfTVMpKTt9Y29uc3QgY3V0T2ZmPXRoaXMuZ2V0Q3V0T2ZmSW5mbyh0aW1lb3V0KTtyZXR1cm4ge3RpbWVvdXQsYXV0b1RyYWNrLGN1dE9mZn07fWdldEN1dE9mZkluZm8oc2Vzc2lvblRpbWVvdXQpe2NvbnN0IGN1dE9mZj1zdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZS5zZXNzaW9ucy5jdXRPZmY7bGV0IGN1dE9mZkR1cmF0aW9uO2xldCBjdXRPZmZFbmFibGVkPWZhbHNlO2lmKGN1dE9mZi5lbmFibGVkPT09dHJ1ZSl7Y3V0T2ZmRHVyYXRpb249Y3V0T2ZmLmR1cmF0aW9uO2N1dE9mZkVuYWJsZWQ9dHJ1ZTtpZighaXNQb3NpdGl2ZUludGVnZXIoY3V0T2ZmRHVyYXRpb24pKXt0aGlzLmxvZ2dlci53YXJuKENVVF9PRkZfRFVSQVRJT05fTk9UX05VTUJFUl9XQVJOSU5HKFVTRVJfU0VTU0lPTl9NQU5BR0VSLGN1dE9mZkR1cmF0aW9uLERFRkFVTFRfU0VTU0lPTl9DVVRfT0ZGX0RVUkFUSU9OX01TKSk7Ly8gVXNlIHRoZSBkZWZhdWx0IHZhbHVlIGZvciBjdXQgb2ZmIGR1cmF0aW9uXG5jdXRPZmZEdXJhdGlvbj1ERUZBVUxUX1NFU1NJT05fQ1VUX09GRl9EVVJBVElPTl9NUzt9ZWxzZSBpZihjdXRPZmZEdXJhdGlvbjxzZXNzaW9uVGltZW91dCl7dGhpcy5sb2dnZXIud2FybihDVVRfT0ZGX0RVUkFUSU9OX0xFU1NfVEhBTl9USU1FT1VUX1dBUk5JTkcoVVNFUl9TRVNTSU9OX01BTkFHRVIsY3V0T2ZmRHVyYXRpb24sc2Vzc2lvblRpbWVvdXQpKTtjdXRPZmZFbmFibGVkPWZhbHNlO319cmV0dXJuIHtlbmFibGVkOmN1dE9mZkVuYWJsZWQsZHVyYXRpb246Y3V0T2ZmRHVyYXRpb259O30vKipcbiAgICogSGFuZGxlcyBlcnJvclxuICAgKiBAcGFyYW0gZXJyb3IgVGhlIGVycm9yIG9iamVjdFxuICAgKi9vbkVycm9yKGVycm9yLGN1c3RvbU1lc3NhZ2UsZ3JvdXBpbmdIYXNoKXt0aGlzLmVycm9ySGFuZGxlci5vbkVycm9yKHtlcnJvcixjb250ZXh0OlVTRVJfU0VTU0lPTl9NQU5BR0VSLGN1c3RvbU1lc3NhZ2UsZ3JvdXBpbmdIYXNofSk7fS8qKlxuICAgKiBBIGZ1bmN0aW9uIHRvIGVuY3J5cHQgdGhlIGNvb2tpZSB2YWx1ZSBhbmQgcmV0dXJuIHRoZSBlbmNyeXB0ZWQgZGF0YVxuICAgKiBAcGFyYW0gY29va2llc0RhdGFcbiAgICogQHBhcmFtIHN0b3JlXG4gICAqIEByZXR1cm5zXG4gICAqL2dldEVuY3J5cHRlZENvb2tpZURhdGEoY29va2llc0RhdGEsc3RvcmUpe2NvbnN0IGVuY3J5cHRlZENvb2tpZURhdGE9W107Y29va2llc0RhdGEuZm9yRWFjaChjRGF0YT0+e2NvbnN0IGVuY3J5cHRlZFZhbHVlPXN0b3JlPy5lbmNyeXB0KHN0cmluZ2lmeVdpdGhvdXRDaXJjdWxhcihjRGF0YS52YWx1ZSxmYWxzZSxbXSx0aGlzLmxvZ2dlcikpO2lmKGlzRGVmaW5lZEFuZE5vdE51bGwoZW5jcnlwdGVkVmFsdWUpKXtlbmNyeXB0ZWRDb29raWVEYXRhLnB1c2goe25hbWU6Y0RhdGEubmFtZSx2YWx1ZTplbmNyeXB0ZWRWYWx1ZX0pO319KTtyZXR1cm4gZW5jcnlwdGVkQ29va2llRGF0YTt9LyoqXG4gICAqIEEgZnVuY3Rpb24gdGhhdCBtYWtlcyByZXF1ZXN0IHRvIGRhdGEgc2VydmljZSB0byBzZXQgdGhlIGNvb2tpZVxuICAgKiBAcGFyYW0gZW5jcnlwdGVkQ29va2llRGF0YVxuICAgKiBAcGFyYW0gY2FsbGJhY2tcbiAgICovbWFrZVJlcXVlc3RUb1NldENvb2tpZShlbmNyeXB0ZWRDb29raWVEYXRhLGNhbGxiYWNrKXt0aGlzLmh0dHBDbGllbnQ/LmdldEFzeW5jRGF0YSh7dXJsOnN0YXRlLnNlcnZlckNvb2tpZXMuZGF0YVNlcnZpY2VVcmwudmFsdWUsb3B0aW9uczp7bWV0aG9kOidQT1NUJyxkYXRhOnN0cmluZ2lmeVdpdGhvdXRDaXJjdWxhcih7cmVxVHlwZTonc2V0Q29va2llcycsd29ya3NwYWNlSWQ6c3RhdGUuc291cmNlLnZhbHVlPy53b3Jrc3BhY2VJZCxkYXRhOntvcHRpb25zOnttYXhBZ2U6c3RhdGUuc3RvcmFnZS5jb29raWUudmFsdWU/Lm1heGFnZSxwYXRoOnN0YXRlLnN0b3JhZ2UuY29va2llLnZhbHVlPy5wYXRoLGRvbWFpbjpzdGF0ZS5zdG9yYWdlLmNvb2tpZS52YWx1ZT8uZG9tYWluLHNhbWVTaXRlOnN0YXRlLnN0b3JhZ2UuY29va2llLnZhbHVlPy5zYW1lc2l0ZSxzZWN1cmU6c3RhdGUuc3RvcmFnZS5jb29raWUudmFsdWU/LnNlY3VyZSxleHBpcmVzOnN0YXRlLnN0b3JhZ2UuY29va2llLnZhbHVlPy5leHBpcmVzfSxjb29raWVzOmVuY3J5cHRlZENvb2tpZURhdGF9fSksc2VuZFJhd0RhdGE6dHJ1ZSx3aXRoQ3JlZGVudGlhbHM6dHJ1ZX0saXNSYXdSZXNwb25zZTp0cnVlLGNhbGxiYWNrfSk7fS8qKlxuICAgKiBBIGZ1bmN0aW9uIHRvIG1ha2UgYW4gZXh0ZXJuYWwgcmVxdWVzdCB0byBzZXQgdGhlIGNvb2tpZSBmcm9tIHNlcnZlciBzaWRlXG4gICAqIEBwYXJhbSBzZXNzaW9uVG9Db29raWVzTWFwIG1hcCBvZiBzZXNzaW9uIGtleSB0byBjb29raWUgbmFtZVxuICAgKiBAcGFyYW0gY2IgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGNvb2tpZSBpcyBzZXRcbiAgICogQHBhcmFtIHN0b3JlIHN0b3JlIHRvIGJlIHVzZWQgdG8gZ2V0IHRoZSBjb29raWUgdmFsdWVcbiAgICovc2V0U2VydmVyU2lkZUNvb2tpZXMoc2Vzc2lvblRvQ29va2llc01hcCxjYixzdG9yZSl7Ly8gUmV0cmlldmUgdGhlIGNvb2tpZSB2YWx1ZSBmcm9tIHRoZSBzdGF0ZVxuY29uc3Qgc2Vzc2lvbktleXM9T2JqZWN0LmtleXMoc2Vzc2lvblRvQ29va2llc01hcCk7Y29uc3QgZ2V0Q3VycmVudENvb2tpZVZhbHVlc0Zyb21TdGF0ZT0oKT0+e3JldHVybiBzZXNzaW9uS2V5cy5tYXAoc2Vzc2lvbktleT0+e3JldHVybiB7bmFtZTpzZXNzaW9uVG9Db29raWVzTWFwW3Nlc3Npb25LZXldLm5hbWUsdmFsdWU6c3RhdGUuc2Vzc2lvbltzZXNzaW9uS2V5XS52YWx1ZX07fSk7fTsvLyBQcmVzZXJ2ZSB0aGUgY3VycmVudCBjb29raWUgdmFsdWVzXG5jb25zdCBvcmlnaW5hbENvb2tpZVZhbHVlcz17fTtzZXNzaW9uS2V5cy5mb3JFYWNoKHNlc3Npb25LZXk9PntvcmlnaW5hbENvb2tpZVZhbHVlc1tzZXNzaW9uVG9Db29raWVzTWFwW3Nlc3Npb25LZXldLm5hbWVdPXN0b3JlPy5nZXQoc2Vzc2lvblRvQ29va2llc01hcFtzZXNzaW9uS2V5XS5uYW1lKTt9KTtjb25zdCBjbGVhckluUHJvZ3Jlc3NGbGFncz0oKT0+e3Nlc3Npb25LZXlzLmZvckVhY2goc2Vzc2lvbktleT0+e3RoaXMuc2VydmVyU2lkZUNvb2tpZXNSZXF1ZXN0SW5Qcm9ncmVzc1tzZXNzaW9uS2V5XT1mYWxzZTt9KTt9O2NvbnN0IHNldENvb2tpZXNDbGllbnRTaWRlPSgpPT57Z2V0Q3VycmVudENvb2tpZVZhbHVlc0Zyb21TdGF0ZSgpLmZvckVhY2goZWFjaD0+e2lmKGNiKXtjYihlYWNoLm5hbWUsZWFjaC52YWx1ZSk7fX0pO307dHJ5e2NvbnN0IGV4cGVjdGVkQ29va2llVmFsdWVzPXt9O3Nlc3Npb25LZXlzLmZvckVhY2goc2Vzc2lvbktleT0+e2V4cGVjdGVkQ29va2llVmFsdWVzW3Nlc3Npb25Ub0Nvb2tpZXNNYXBbc2Vzc2lvbktleV0ubmFtZV09c3RhdGUuc2Vzc2lvbltzZXNzaW9uS2V5XS52YWx1ZTt9KTsvLyBlbmNyeXB0IGNvb2tpZXMgdmFsdWVzXG5jb25zdCBlbmNyeXB0ZWRDb29raWVEYXRhPXRoaXMuZ2V0RW5jcnlwdGVkQ29va2llRGF0YShnZXRDdXJyZW50Q29va2llVmFsdWVzRnJvbVN0YXRl
1KCksc3RvcmUpO2lmKGVuY3J5cHRlZENvb2tpZURhdGEubGVuZ3RoPjApey8vIG1ha2UgcmVxdWVzdCB0byBkYXRhIHNlcnZpY2UgdG8gc2V0IHRoZSBjb29raWUgZnJvbSBzZXJ2ZXIgc2lkZVxudGhpcy5tYWtlUmVxdWVzdFRvU2V0Q29va2llKGVuY3J5cHRlZENvb2tpZURhdGEsKHJlcyxkZXRhaWxzKT0+ey8vIE1hcmsgdGhlIGNvb2tpZSByZXEgc3RhdHVzIGFzIGRvbmVcbmNsZWFySW5Qcm9ncmVzc0ZsYWdzKCk7aWYoZGV0YWlscz8ueGhyPy5zdGF0dXM9PT0yMDApe2dldEN1cnJlbnRDb29raWVWYWx1ZXNGcm9tU3RhdGUoKS5mb3JFYWNoKGNEYXRhPT57Y29uc3Qgb3JpZ2luYWxDb29raWVWYWw9b3JpZ2luYWxDb29raWVWYWx1ZXNbY0RhdGEubmFtZV07Y29uc3QgY3VycmVudENvb2tpZVZhbD1zdG9yZT8uZ2V0KGNEYXRhLm5hbWUpOy8vIENoZWNrIGlmIHRoZSBleHBlY3RlZCBjb29raWUgdmFsdWVzIGFyZSBzZXQuXG5pZihzdHJpbmdpZnlXaXRob3V0Q2lyY3VsYXIoZXhwZWN0ZWRDb29raWVWYWx1ZXNbY0RhdGEubmFtZV0sZmFsc2UsW10pIT09c3RyaW5naWZ5V2l0aG91dENpcmN1bGFyKGN1cnJlbnRDb29raWVWYWwsZmFsc2UsW10pKXsvLyBJdCdzIGZpbmUgaWYgdGhlIHZhbHVlcyBkb24ndCBtYXRjaCBhcyBvdGhlciBhY3RpdmUgU0RLIHNlc3Npb25zIG1pZ2h0IGhhdmUgdXBkYXRlZCB0aGUgY29va2llIHZhbHVlc1xuLy8gb3Igb3RoZXIgY29va2llIHJlcXVlc3RzIG1pZ2h0IGhhdmUgdXBkYXRlZCB0aGUgY29va2llIHZhbHVlLlxuLy8gTG9nIGFuIGVycm9yIG9ubHkgd2hlbiBjb29raWUgZGlkbid0IGV4aXN0IHByZXZpb3VzbHkgYW5kIGN1cnJlbnRseSBhbHNvIGRvZXNuJ3QgZXhpc3QuXG5pZihpc051bGwob3JpZ2luYWxDb29raWVWYWwpJiZpc051bGwoY3VycmVudENvb2tpZVZhbCkpe3RoaXMubG9nZ2VyLmVycm9yKEZBSUxFRF9TRVRUSU5HX0NPT0tJRV9GUk9NX1NFUlZFUl9FUlJPUihjRGF0YS5uYW1lKSk7fWlmKGNiKXtjYihjRGF0YS5uYW1lLGNEYXRhLnZhbHVlKTt9fX0pO31lbHNlIHt0aGlzLmxvZ2dlci5lcnJvcihEQVRBX1NFUlZFUl9SRVFVRVNUX0ZBSUxfRVJST1IoZGV0YWlscz8ueGhyPy5zdGF0dXMpKTtzZXRDb29raWVzQ2xpZW50U2lkZSgpO319KTt9ZWxzZSB7c2V0Q29va2llc0NsaWVudFNpZGUoKTsvLyBNYXJrIHRoZSBjb29raWUgcmVxIHN0YXR1cyBhcyBkb25lXG5jbGVhckluUHJvZ3Jlc3NGbGFncygpO319Y2F0Y2goZSl7dGhpcy5vbkVycm9yKGUsRkFJTEVEX1NFVFRJTkdfQ09PS0lFX0ZST01fU0VSVkVSX0dMT0JBTF9FUlJPUixGQUlMRURfU0VUVElOR19DT09LSUVfRlJPTV9TRVJWRVJfR0xPQkFMX0VSUk9SKTtzZXRDb29raWVzQ2xpZW50U2lkZSgpOy8vIE1hcmsgdGhlIGNvb2tpZSByZXEgc3RhdHVzIGFzIGRvbmVcbmNsZWFySW5Qcm9ncmVzc0ZsYWdzKCk7fX0vKipcbiAgICogQSBmdW5jdGlvbiB0byBzeW5jIHZhbHVlcyBpbiBzdG9yYWdlXG4gICAqIEBwYXJhbSBzZXNzaW9uS2V5XG4gICAqL3N5bmNWYWx1ZVRvU3RvcmFnZShzZXNzaW9uS2V5KXtjb25zdCBlbnRyaWVzPXN0YXRlLnN0b3JhZ2UuZW50cmllcy52YWx1ZTtjb25zdCBzdG9yYWdlVHlwZT1lbnRyaWVzW3Nlc3Npb25LZXldPy50eXBlO2lmKGlzU3RvcmFnZVR5cGVWYWxpZEZvclN0b3JpbmdEYXRhKHN0b3JhZ2VUeXBlKSl7Y29uc3QgY3VyU3RvcmU9dGhpcy5zdG9yZU1hbmFnZXIuZ2V0U3RvcmUoc3RvcmFnZUNsaWVudERhdGFTdG9yZU5hbWVNYXBbc3RvcmFnZVR5cGVdKTtjb25zdCBjb29raWVOYW1lPWVudHJpZXNbc2Vzc2lvbktleV0/LmtleTtjb25zdCBjb29raWVWYWx1ZT1zdGF0ZS5zZXNzaW9uW3Nlc3Npb25LZXldLnZhbHVlO2lmKGNvb2tpZVZhbHVlJiYoaXNTdHJpbmcoY29va2llVmFsdWUpfHxpc05vbkVtcHR5T2JqZWN0KGNvb2tpZVZhbHVlKSkpey8vIGlmIHVzZVNlcnZlclNpZG
1VDb29raWVzIGxvYWQgb3B0aW9uIGlzIHNldCB0byB0cnVlXG4vLyBzZXQgdGhlIGNvb2tpZSBmcm9tIHNlcnZlciBzaWRlXG5pZihzdGF0ZS5zZXJ2ZXJDb29raWVzLmlzRW5hYmxlZFNlcnZlclNpZGVDb29raWVzLnZhbHVlJiZzdG9yYWdlVHlwZT09PUNPT0tJRV9TVE9SQUdFKXsvLyBNYXJrIHRoZSByZXF1ZXN0cyBhcyBpbiBwcm9ncmVzcy5cbnRoaXMuc2VydmVyU2lkZUNvb2tpZXNSZXF1ZXN0SW5Qcm9ncmVzc1tzZXNzaW9uS2V5XT10cnVlO2lmKHRoaXMuc2VydmVyU2lkZUNvb2tpZURlYm91bmNlRnVuY3Nbc2Vzc2lvbktleV0pe2dsb2JhbFRoaXMuY2xlYXJUaW1lb3V0KHRoaXMuc2VydmVyU2lkZUNvb2tpZURlYm91bmNlRnVuY3Nbc2Vzc2lvbktleV0pO310aGlzLnNlcnZlclNpZGVDb29raWVEZWJvdW5jZUZ1bmNzW3Nlc3Npb25LZXldPWdsb2JhbFRoaXMuc2V0VGltZW91dCgoKT0+ey8vIENyZWF0ZSBhIG1hcCBvZiBzZXNzaW9uIGtleSB0byBjb29raWUgbmFtZVxuY29uc3Qgc2Vzc2lvblRvQ29va2llc01hcD17W3Nlc3Npb25LZXldOntuYW1lOmNvb2tpZU5hbWV9fTt0aGlzLnNldFNlcnZlclNpZGVDb29raWVzKHNlc3Npb25Ub0Nvb2tpZXNNYXAsKGNvb2tpZU5hbWUsY29va2llVmFsdWUpPT57Y3VyU3RvcmU/LnNldChjb29raWVOYW1lLGNvb2tpZVZhbHVlKTt9LGN1clN0b3JlKTt9LFNFUlZFUl9TSURFX0NPT0tJRVNfREVCT1VOQ0VfVElNRSk7fWVsc2Uge2N1clN0b3JlPy5zZXQoY29va2llTmFtZSxjb29raWVWYWx1ZSk7fX1lbHNlIHtjdXJTdG9yZT8ucmVtb3ZlKGNvb2tpZU5hbWUpO319fS8qKlxuICAgKiBGdW5jdGlvbiB0byB1cGRhdGUgc3RvcmFnZSB3aGVuZXZlciBzdGF0ZSB2YWx1ZSBjaGFuZ2VzXG4gICAqL3JlZ2lzdGVyRWZmZWN0cygpey8vIFRoaXMgd2lsbCB3b3JrIGFzIGxvbmcgYXMgdGhlIHVzZXIgc2Vzc2lvbiBlbnRyeSBrZXkgbmFtZXMgYXJlIHNhbWUgYXMgdGhlIHN0YXRlIGtleXNcblVTRVJfU0VTU0lPTl9LRVlTLmZvckVhY2goc2Vzc2lvbktleT0+e2ooKCk9Pnt0aGlzLnN5bmNWYWx1ZVRvU3RvcmFnZShzZXNzaW9uS2V5KTt9KTt9KTt9LyoqXG4gICAqIFNldHMgYW5vbnltb3VzIGlkIGluIHRoZSBmb2xsb3dpbmcgcHJlY2VkZW5jZTpcbiAgICpcbiAgICogMS4gYW5vbnltb3VzSWQ6IElkIGRpcmVjdGx5IHByb3ZpZGVkIHRvIHRoZSBmdW5jdGlvbi5cbiAgICogMi4gcnVkZGVyQW1wTGlua2VyUGFyYW06IHZhbHVlIGdlbmVyYXRlZCBmcm9tIGxpbmtlciBxdWVyeSBwYXJtIChydWRkZXJzdGFjaylcbiAgICogICAgdXNpbmcgcGFyc2VMaW5rZXIgdXRpbC5cbiAgICogMy4gZ2VuZXJhdGVVVUlEOiBBIG5ldyB1bmlxdWUgaWQgaXMgZ2VuZXJhdGVkIGFuZCBhc3NpZ25lZC5cbiAgICovc2V0QW5vbnltb3VzSWQoYW5vbnltb3VzSWQscnVkZGVyQW1wTGlua2VyUGFyYW0pe2xldCBmaW5hbEFub255bW91c0lkPWFub255bW91c0lkO2lmKCFpc1N0cmluZyhhbm9ueW1vdXNJZCl8fCFmaW5hbEFub255bW91c0lkKXtmaW5hbEFub255bW91c0lkPXVuZGVmaW5lZDt9aWYodGhpcy5pc1BlcnNpc3RlbmNlRW5hYmxlZEZvclN0b3JhZ2VFbnRyeSgnYW5vbnltb3VzSWQnKSl7aWYoIWZpbmFsQW5vbnltb3VzSWQmJnJ1ZGRlckFtcExpbmtlclBhcmFtKXtjb25zdCBsaW5rZXJQbHVnaW5zUmVzdWx0PXRoaXMucGx1Z2luc01hbmFnZXI/Lmludm9rZVNpbmdsZSgndXNlclNlc3Npb24uYW5vbnltb3VzSWRHb29nbGVMaW5rZXInLHJ1ZGRlckFtcExpbmtlclBhcmFtKTtmaW5hbEFub255bW91c0lkPWxpbmtlclBsdWdpbnNSZXN1bHQ7fWZpbmFsQW5vbnltb3VzSWQ9ZmluYWxBbm9ueW1vdXNJZHx8Z2VuZXJhdGVBbm9ueW1vdXNJZCgpO31lbHNlIHtmaW5hbEFub255bW91c0lkPURFRkFVTFRfVVNFUl9TRVNTSU9OX1ZBTFVFUy5hbm9ueW1vdXNJZDt9c3RhdGUuc2Vzc2lvbi5hbm9ueW1vdXNJZC52YWx1ZT1maW5hbEFub255bW91c0lkO30vKipcbiAgICogRmV0Y2hlcyBhbm9ueW1vdXNJZFxuICAgKiBAcGFyYW0gb3B0aW9ucyBvcHRpb24gdG8gZmV0Y2ggaXQgZnJvbSBleHRlcm5hbCBzb3VyY2VcbiAgICogQHJldHVybnMgYW5vbnltb3VzSWRcbiAgICovZ2V0QW5vbnltb3VzSWQob3B0aW9ucyl7Y29uc3Qgc3RvcmFnZT1zdGF0ZS5zdG9yYWdlLmVudHJpZXMudmFsdWUuYW5vbnltb3VzSWQ/LnR5cGU7aWYoaXNTdG9yYWdlVHlwZVZhbGlkRm9yU3RvcmluZ0RhdGEoc3RvcmFnZSkpe2xldCBwZXJzaXN0ZWRBbm9ueW1vdXNJZD1zdGF0ZS5zZXNzaW9uLmFub255bW91c0lkLnZhbHVlOy8vIElmIHRoZSBhbm9ueW1vdXMgSUQgaXMgdGhlIGRlZmF1bHQgdmFsdWUsIGZldGNoIGl0IGZyb20gc3RvcmFnZVxuaWYoIXBlcnNpc3RlZEFub255bW91c0lkfHxwZXJzaXN0ZWRBbm9ueW1vdXNJZD09PURFRkFVTFRfVVNFUl9TRVNTSU9OX1ZBTFVFUy5hbm9ueW1vdXNJZCl7cGVyc2lzdGVkQW5vbnltb3VzSWQ9dGhpcy5nZXRFbnRyeVZhbHVlKCdhbm9ueW1vdXNJZCcpO31pZighcGVyc2lzdGVkQW5vbnltb3VzSWQmJm9wdGlvbnMpey8vIGZldGNoIGFub255bW91c0lkIGZyb20gZXh0ZXJuYWwgc291cmNlXG5jb25zdCBhdXRvQ2FwdHVyZWRBbm9ueW1vdXNJZD10aGlzLnBsdWdpbnNNYW5hZ2VyPy5pbnZva2VTaW5nbGUoJ3N0b3JhZ2UuZ2V0QW5vbnltb3VzSWQnLGdldFN0b3JhZ2VFbmdpbmUsb3B0aW9ucyk7cGVyc2lzdGVkQW5vbnltb3VzSWQ9YXV0b0NhcHR1cmVkQW5vbnltb3VzSWQ7fXN0YXRlLnNlc3Npb24uYW5vbnltb3VzSWQudmFsdWU9cGVyc2lzdGVkQW5vbnltb3VzSWR8fGdlbmVyYXRlQW5vbnltb3VzSWQoKTt9cmV0dXJuIHN0YXRlLnNlc3Npb24uYW5vbnltb3VzSWQudmFsdWU7fWdldEVudHJ5VmFsdWUoc2Vzc2lvbktleSl7Y29uc3QgZW50cmllcz1zdGF0ZS5zdG9yYWdlLmVudHJpZXMudmFsdWU7Y29uc3Qgc3RvcmFnZVR5cGU9ZW50cmllc1tzZXNzaW9uS2V5XT8udHlwZTtpZihpc1N0b3JhZ2VUeXBlVmFsaWRGb3JTdG9yaW5nRGF0YShzdG9yYWdlVHlwZSkpe2NvbnN0IHN0b3JlPXRoaXMuc3RvcmVNYW5hZ2VyPy5nZXRTdG9yZShzdG9yYWdlQ2xpZW50RGF0YVN0b3JlTmFtZU1hcFtzdG9yYWdlVHlwZV0pOy8vIE1pZ3JhdGUgdGhlIHN0b3JhZ2UgZGF0YSBiZWZvcmUgZmV0Y2hpbmcgdGhlIHZhbHVlXG4vLyBUaGlzIGlzIG5lZWRlZCBmb3IgZW50cmllcyB0aGF0IGFyZSBmZXRjaGVkIGZyb20gdGhlIHN0b3JhZ2Vcbi8vIGR1cmluZyB0aGUgY3VycmVudCBzZXNzaW9uIChmb3IgZXhhbXBsZSwgc2Vzc2lvbiBpbmZvKVxudGhpcy5taWdyYXRlU3RvcmFnZUlmTmVlZGVkKFtzdG9yZV0sW3Nlc3Npb25LZXldKTtjb25zdCBzdG9yYWdlS2V5PWVudHJpZXNbc2Vzc2lvbktleV0/LmtleTtyZXR1cm4gc3RvcmU/LmdldChzdG9yYWdlS2V5KT8/bnVsbDt9cmV0dXJuIG51bGw7fWdldEV4dGVybmFsQW5vbnltb3VzSWRCeUNvb2tpZU5hbWUoa2V5KXtjb25zdCBzdG9yYWdlRW5naW5lPWdldFN0b3JhZ2VFbmdpbmUoQ09PS0lFX1NUT1JBR0UpO2lmKHN0b3JhZ2VFbmdpbmU/LmlzRW5hYmxlZCl7cmV0dXJuIHN0b3JhZ2VFbmdpbmUuZ2V0SXRlbShrZXkpPz9udWxsO31yZXR1cm4gbnVsbDt9LyoqXG4gICAqIEZldGNoZXMgdGhlIHZhbHVlIGZvciBhIHNlc3Npb24ga2V5LiBQcmVmZXJhYmx5IGZyb20gc3RvcmFnZSwgaWYgdGhlIHNlcnZlci1zaWRlXG4gICAqIGNvb2tpZXMgcmVxdWVzdCBpcyBub3QgaW4gcHJvZ3Jlc3MuIE90aGVyd2lzZSwgZnJvbSB0aGUgc3RhdGUuXG4gICAqIEBwYXJhbSBzZXNzaW9uS2V5IC0gVGhlIHNlc3Npb24ga2V5IHRvIGZldGNoIHRoZSB2YWx1ZSBmb3JcbiAgICogQHJldHVybnMgLSBUaGUgdmFsdWUgZm9yIHRoZSBzZXNzaW9uIGtleVxuICAgKi9nZXRVc2VyU2Vzc2lvblZhbHVlKHNlc3Npb25LZXkpey8vIElmIHRoZSBzZXJ2ZXItc2lkZSBjb29raWVzIHJlcXVlc3QgaXMgaW4gcHJvZ3Jlc3MsIGZldGNoIHRoZSB2YWx1ZSBmcm9tIHRoZSBzdGF0ZS5cbmlmKHRoaXMuc2VydmVyU2lkZUNvb2tpZXNSZXF1ZXN0SW5Qcm9ncmVzc1tzZXNzaW9uS2V5XSl7cmV0dXJuIHN0YXRlLnNlc3Npb25bc2Vzc2lvbktleV0udmFsdWU7fS8vIE90aGVyd2lzZSwgZmV0Y2ggdGhlIHZhbHVlIGZyb20gc3RvcmFnZS5cbnJldHVybi
1B0aGlzLmdldEVudHJ5VmFsdWUoc2Vzc2lvbktleSk7fS8qKlxuICAgKiBGZXRjaGVzIFVzZXIgSWRcbiAgICogQHJldHVybnNcbiAgICovZ2V0VXNlcklkKCl7cmV0dXJuIHRoaXMuZ2V0VXNlclNlc3Npb25WYWx1ZSgndXNlcklkJyk7fS8qKlxuICAgKiBGZXRjaGVzIFVzZXIgVHJhaXRzXG4gICAqIEByZXR1cm5zXG4gICAqL2dldFVzZXJUcmFpdHMoKXtyZXR1cm4gdGhpcy5nZXRVc2VyU2Vzc2lvblZhbHVlKCd1c2VyVHJhaXRzJyk7fS8qKlxuICAgKiBGZXRjaGVzIEdyb3VwIElkXG4gICAqIEByZXR1cm5zXG4gICAqL2dldEdyb3VwSWQoKXtyZXR1cm4gdGhpcy5nZXRVc2VyU2Vzc2lvblZhbHVlKCdncm91cElkJyk7fS8qKlxuICAgKiBGZXRjaGVzIEdyb3VwIFRyYWl0c1xuICAgKiBAcmV0dXJuc1xuICAgKi9nZXRHcm91cFRyYWl0cygpe3JldHVybiB0aGlzLmdldFVzZXJTZXNzaW9uVmFsdWUoJ2dyb3VwVHJhaXRzJyk7fS8qKlxuICAgKiBGZXRjaGVzIEluaXRpYWwgUmVmZXJyZXJcbiAgICogQHJldHVybnNcbiAgICovZ2V0SW5pdGlhbFJlZmVycmVyKCl7cmV0dXJuIHRoaXMuZ2V0VXNlclNlc3Npb25WYWx1ZSgnaW5pdGlhbFJlZmVycmVyJyk7fS8qKlxuICAgKiBGZXRjaGVzIEluaXRpYWwgUmVmZXJyaW5nIGRvbWFpblxuICAgKiBAcmV0dXJuc1xuICAgKi9nZXRJbml0aWFsUmVmZXJyaW5nRG9tYWluKCl7cmV0dXJuIHRoaXMuZ2V0VXNlclNlc3Npb25WYWx1ZSgnaW5pdGlhbFJlZmVycmluZ0RvbWFpbicpO30vKipcbiAgICogRmV0Y2hlcyBzZXNzaW9uIHRyYWNraW5nIGluZm9ybWF0aW9uIGZyb20gc3RvcmFnZVxuICAgKiBAcmV0dXJuc1xuICAgKi9nZXRTZXNzaW9uSW5mbygpe3JldHVybiB0aGlzLmdldFVzZXJTZXNzaW9uVmFsdWUoJ3Nlc3Npb25JbmZvJyk7fS8qKlxuICAgKiBGZXRjaGVzIGF1dGggdG9rZW4gZnJvbSBzdG9yYWdlXG4gICAqIEByZXR1cm5zXG4gICAqL2dldEF1dGhUb2tlbigpe3JldHVybiB0aGlzLmdldFVzZXJTZXNzaW9uVmFsdWUoJ2F1dGhUb2tlbicpO30vKipcbiAgICogSWYgc2Vzc2lvbiBpcyBhY3RpdmUgaXQgcmV0dXJucyB0aGUgc2Vzc2lvbklkXG4gICAqIEByZXR1cm5zXG4gICAqL2dldFNlc3Npb25JZCgpe2NvbnN0IHNlc3Npb25JbmZvPXRoaXMuZ2V0U2Vzc2lvbkluZm8oKT8/REVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLnNlc3Npb25JbmZvO2lmKHNlc3Npb25JbmZvLmF1dG9UcmFjayYmIWhhc1Nlc3Npb25FeHBpcmVkKHNlc3Npb25JbmZvKXx8c2Vzc2lvbkluZm8ubWFudWFsVHJhY2spe3JldHVybiBzZXNzaW9uSW5mby5pZD8/bnVsbDt9cmV0dXJuIG51bGw7fS8qKlxuICAgKiBBIGZ1bmN0aW9uIHRvIGtlZXAgdGhlIHNlc3Npb24gaW5mb3JtYXRpb24gdXAgdG8gZGF0ZSBpbiB0aGUgc3RhdGVcbiAgICogYmVmb3JlIHVzaW5nIGl0IGZvciBidWlsZGluZyBldmVudCBwYXlsb2Fkcy5cbiAgICovcmVmcmVzaFNlc3Npb24oKXtsZXQgc2Vzc2lvbkluZm89dGhpcy5nZXRTZXNzaW9uSW5mbygpPz9ERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMuc2Vzc2lvbkluZm87aWYoc2Vzc2lvbkluZm8uYXV0b1RyYWNrfHxzZXNzaW9uSW5mby5tYW51YWxUcmFjayl7aWYoc2Vzc2lvbkluZm8uYXV0b1RyYWNrKXt0aGlzLnN0YXJ0T3JSZW5ld0F1dG9UcmFja2luZyhzZXNzaW9uSW5mbyk7c2Vzc2lvbkluZm89c3RhdGUuc2Vzc2lvbi5zZXNzaW9uSW5mby52YWx1ZTt9Ly8gTm90ZSB0aGF0IGlmIHNlc3Npb25TdGFydCBpcyBmYWxzZSwgdGhlbiBpdCdzIGFuIGFjdGl2ZSBzZXNzaW9uLlxuLy8gU28sIHdlIG5lZWRuJ3QgdXBkYXRlIHRoZSBzZXNzaW9uIGluZm8uXG4vL1xuLy8gRm9yIG90aGVyIHNjZW5hcmlvcyxcbi8vIDEuIElmIHNlc3Npb25TdGFydCBpcyB1bmRlZmluZWQsIHRoZW4gaXQncyBhIG5ldyBzZXNzaW9uLlxuLy8gICBNYXJrIGl0IGFzIHNlc3Npb25TdGFydC5cbi8vIDIuIElmIHNlc3Npb25TdGFydCBpcyB0cnVlLCB0aGVuIG5lZWQgdG8gZmxpcCBpdCBmb3IgdGhlIGZ1dHVyZSBldmVudHMuXG5pZihzZXNzaW9uSW5mby5zZXNzaW9uU3RhcnQ9PT11bmRlZmluZWQpe3Nlc3Npb25JbmZvPXsuLi5zZXNzaW9uSW5mbyxzZXNzaW9uU3RhcnQ6dHJ1ZX07fWVsc2UgaWYoc2Vzc2lvbkluZm8uc2Vzc2lvblN0YXJ0KXtzZXNzaW9uSW5mbz17Li4uc2Vzc2lvbkluZm8sc2Vzc2lvblN0YXJ0OmZhbHNlfTt9fS8vIEFsd2F5cyB3cml0ZSB0byBzdGF0ZSAoaW4tdHVybiB0byBzdG9yYWdlKSB0byBrZWVwIHRoZSBzZXNzaW9uIGluZm8gdXAgdG8gZGF0ZS5cbnN0YXRlLnNlc3Npb24uc2Vzc2lvbkluZm8udmFsdWU9c2Vzc2lvbkluZm87aWYoc3RhdGUubGlmZWN5Y2xlLnN0YXR1cy52YWx1ZSE9PSdyZWFkeUV4ZWN1dG
1VkJyl7Ly8gRm9yY2UgdXBkYXRlIHRoZSBzdG9yYWdlIGFzIHRoZSAnZWZmZWN0JyBibG9ja3MgYXJlIG5vdCBnZXR0aW5nIHRyaWdnZXJlZFxuLy8gd2hlbiBwcm9jZXNzaW5nIHByZWxvYWQgYnVmZmVyZWQgcmVxdWVzdHNcbnRoaXMuc3luY1ZhbHVlVG9TdG9yYWdlKCdzZXNzaW9uSW5mbycpO319cmVzZXRBbmRTdGFydE5ld1Nlc3Npb24oKXtjb25zdCBzZXNzaW9uPXN0YXRlLnNlc3Npb247Y29uc3R7bWFudWFsVHJhY2ssYXV0b1RyYWNrLHRpbWVvdXQsY3V0T2ZmfT1zZXNzaW9uLnNlc3Npb25JbmZvLnZhbHVlO2lmKGF1dG9UcmFjayl7Y29uc3Qgc2Vzc2lvbkluZm89ey4uLkRFRkFVTFRfVVNFUl9TRVNTSU9OX1ZBTFVFUy5zZXNzaW9uSW5mbyx0aW1lb3V0fTtpZihjdXRPZmYpe3Nlc3Npb25JbmZvLmN1dE9mZj17ZW5hYmxlZDpjdXRPZmYuZW5hYmxlZCxkdXJhdGlvbjpjdXRPZmYuZHVyYXRpb259O31zZXNzaW9uLnNlc3Npb25JbmZvLnZhbHVlPXNlc3Npb25JbmZvO3RoaXMuc3RhcnRPclJlbmV3QXV0b1RyYWNraW5nKHNlc3Npb24uc2Vzc2lvbkluZm8udmFsdWUpO31lbHNlIGlmKG1hbnVhbFRyYWNrKXt0aGlzLnN0YXJ0TWFudWFsVHJhY2tpbmdJbnRlcm5hbCgpO319LyoqXG4gICAqIFJlc2V0IHN0YXRlIHZhbHVlc1xuICAgKiBAcGFyYW0gb3B0aW9ucyBvcHRpb25zIGZvciByZXNldFxuICAgKiBAcmV0dXJuc1xuICAgKi9yZXNldChvcHRpb25zKXtjb25zdHtzZXNzaW9ufT1zdGF0ZTtjb25zdCBvcHRzPWdldEZpbmFsUmVzZXRPcHRpb25zKG9wdGlvbnMpO24oKCk9PntPYmplY3Qua2V5cyhERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMpLmZvckVhY2goa2V5PT57Y29uc3QgdXNlclNlc3Npb25LZXk9a2V5O2lmKG9wdHMuZW50cmllc1t1c2VyU2Vzc2lvbktleV0hPT10cnVlKXtyZXR1cm47fXN3aXRjaChrZXkpe2Nhc2UgJ2Fub255bW91c0lkJzp0aGlzLnNldEFub255bW91c0lkKCk7YnJlYWs7Y2FzZSAnc2Vzc2lvbkluZm8nOnRoaXMucmVzZXRBbmRTdGFydE5ld1Nlc3Npb24oKTticmVhaztkZWZhdWx0OnNlc3Npb25bdXNlclNlc3Npb25LZXldLnZhbHVlPURFRkFVTFRfVVNFUl9TRVNTSU9OX1ZBTFVFU1t1c2VyU2Vzc2lvbktleV07YnJlYWs7fX0pO30pO30vKipcbiAgICogU2V0IHVzZXIgSWRcbiAgICogQHBhcmFtIHVzZXJJZFxuICAgKi9zZXRVc2VySWQodXNlcklkKXtzdGF0ZS5zZXNzaW9uLnVzZXJJZC52YWx1ZT10aGlzLmlzUGVyc2lzdGVuY2VFbmFibGVkRm9yU3RvcmFnZUVudHJ5KCd1c2VySWQnKSYmdXNlcklkP3VzZXJJZDpERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMudXNlcklkO30vKipcbiAgICogU2V0IHVzZXIgdHJhaXRzXG4gICAqIEBwYXJhbSB0cmFpdHNcbiAgICovc2V0VXNlclRyYWl0cyh0cmFpdHMpe3N0YXRlLnNlc3Npb24udXNlclRyYWl0cy52YWx1ZT10aGlzLmlzUGVyc2lzdGVuY2VFbmFibGVkRm9yU3RvcmFnZUVudHJ5KCd1c2VyVHJhaXRzJykmJmlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwodHJhaXRzKT9tZXJnZURlZXBSaWdodChzdGF0ZS5zZXNzaW9uLnVzZXJUcmFpdHMudmFsdWU/P0RFRkFVTFRfVVNFUl9TRVNTSU9OX1ZBTFVFUy51c2VyVHJhaXRzLHRyYWl0cyk6REVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLnVzZXJUcmFpdHM7fS8qKlxuICAgKiBTZXQgZ3JvdXAgSWRcbiAgICogQHBhcmFtIGdyb3VwSWRcbiAgICovc2V0R3JvdXBJZChncm91cElkKXtzdGF0ZS5zZXNzaW9uLmdyb3VwSWQudmFsdWU9dGhpcy5pc1BlcnNpc3RlbmNlRW5hYmxlZEZvclN0b3JhZ2VFbnRyeSgnZ3JvdXBJZCcpJiZncm91cElkP2dyb3VwSWQ6REVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLmdyb3VwSWQ7fS8qKlxuICAgKiBTZXQgZ3JvdXAgdHJhaXRzXG4gICAqIEBwYXJhbSB0cmFpdHNcbiAgICovc2V0R3JvdXBUcmFpdHModHJhaXRzKXtzdGF0ZS5zZXNzaW9uLmdyb3VwVHJhaXRzLnZhbHVlPXRoaXMuaXNQZXJzaXN0ZW5jZUVuYWJsZWRGb3JTdG9yYWdlRW50cnkoJ2dyb3VwVHJhaXRzJykmJmlzT2JqZWN0TGl0ZXJhbEFuZE5vdE51bGwodHJhaXRzKT9tZXJnZURlZXBSaWdodChzdGF0ZS5zZXNzaW9uLmdyb3VwVHJhaXRzLnZhbHVlPz9ERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMuZ3JvdXBUcmFpdHMsdHJhaXRzKTpERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMuZ3JvdXBUcmFpdHM7fS8qKlxuICAgKiBTZXQgaW5pdGlhbCByZWZlcnJlclxuICAgKiBAcGFyYW0gcmVmZXJyZXJcbiAgICovc2V0SW5pdGlhbFJlZmVycmVyKHJlZmVycmVyKXtzdGF0ZS5zZXNzaW9uLmluaXRpYWxSZWZlcnJlci52YWx1ZT10aGlzLmlzUGVyc2lzdGVuY2VFbmFibGVkRm9yU3RvcmFnZUVudHJ5KCdpbml0aWFsUmVmZXJyZXInKSYmcmVmZXJyZXI/cmVmZXJyZXI6REVGQVVMVF9VU0VSX1NFU1NJT05fVkFMVUVTLmluaXRpYWxSZWZlcnJlcjt9LyoqXG4gICAqIFNldCBpbml0aWFsIHJlZmVycmluZyBkb21haW5cbiAgICogQHBhcmFtIHtTdHJpbmd9IHJlZmVycmluZ0RvbWFpblxuICAgKi9zZXRJbml0aWFsUmVmZXJyaW5nRG9tYWluKHJlZmVycmluZ0RvbWFpbil7c3RhdGUuc2Vzc2lvbi5pbml0aWFsUmVmZXJyaW5nRG9tYWluLnZhbHVlPXRoaXMuaXNQZXJzaXN0ZW5jZUVuYWJsZWRGb3JTdG9yYWdlRW50cnkoJ2luaXRpYWxSZWZlcnJpbmdEb21haW4nKSYmcmVmZXJyaW5nRG9tYWluP3JlZmVycmluZ0RvbWFpbjpERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMuaW5pdGlhbFJlZmVycmluZ0RvbWFpbjt9LyoqXG4gICAqIEEgZnVuY3Rpb24gdG8gY2hlY2sgZm9yIGV4aXN0aW5nIHNlc3Npb24gZGV0YWlscyBhbmQgZGVwZW5kaW5nIG9uIHRoYXQgY3JlYXRlIGEgbmV3IHNlc3Npb25cbiAgICovc3RhcnRPclJlbmV3QXV0b1RyYWNraW5nKHNlc3Npb25JbmZvKXtsZXQgZmluYWxTZXNzaW9uSW5mbz1zZXNzaW9uSW5mbztpZihoYXNTZXNzaW9uRXhwaXJlZChzZXNzaW9uSW5mbykpe2ZpbmFsU2Vzc2lvbkluZm89Z2VuZXJhdGVBdXRvVHJhY2tpbmdTZXNzaW9uKHNlc3Npb25JbmZvKTt9ZWxzZSB7Y29uc3QgdGltZXN0YW1wPURhdGUubm93KCk7Y29uc3QgdGltZW91dD1zZXNzaW9uSW5mby50aW1lb3V0Oy8vIFNldCB0aGUgZXhwaXJ5IHRpbWUgb2YgdGhlIHNlc3Npb25cbmZpbmFsU2Vzc2lvbkluZm8uZXhwaXJlc0F0PXRpbWVzdGFtcCt0aW1lb3V0O30vLyBSZXNldCBjdXQgb2ZmIGV4cGlyeSB0aW1lc3RhbXAgaWYgaXQgaXMgZXhjZWVkZWRcbmlmKGlzQ3V0T2ZmVGltZUV4Y2VlZGVkKGZpbmFsU2Vzc2lvbkluZm8pKXtmaW5hbFNlc3Npb25JbmZvLmN1dE9mZi5leHBpcmVzQXQ9dW5kZWZpbmVkO30vLyBJZiBjdXQgb2ZmIGlzIGFjdGl2ZSwgc2V0IG9yIHJldGFpbiB0aGUgZXhwaXJ5IHRpbWVcbmlmKGZpbmFsU2Vzc2lvbkluZm8uY3V0T2ZmKXtjb25zdCBjdXRPZmZFeHBpcmVzQXQ9Z2V0Q3V0T2ZmRXhwaXJhdGlvblRpbWVzdGFtcChmaW5hbFNlc3Npb25JbmZvLmN1dE9mZik7ZmluYWxTZXNzaW9uSW5mby5jdXRPZmYuZXhwaXJlc0F0PWN1dE9mZkV4cGlyZXNBdDt9Ly8gVXBkYXRlIHRoZSBzZXNzaW9uIGluZm8gaW4gdGhlIHN0YXRlXG5zdGF0ZS5zZXNzaW9uLnNlc3Npb25JbmZvLnZhbHVlPWZpbmFsU2Vzc2lvbkluZm87fS8qKlxuICAgKiBBIGZ1bmN0aW9uIG1ldGhvZCB0byBzdGFydCBhIG1hbnVhbCBzZXNzaW9uXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpZCAgICAgc2Vzc2lvbiBpZGVudGlmaWVyXG4gICAqIEByZXR1cm5zXG4gICAqL3N0YXJ0KGlkKXtzdGF0ZS5zZXNzaW9uLnNlc3Npb25JbmZvLnZhbHVlPWdlbmVyYXRlTWFudWFsVHJhY2tpbmdTZXNzaW9uKGlkLHRoaXMubG9nZ2VyKTt9LyoqXG4gICAqIEFuIGludGVybmFsIGZ1bmN0aW9uIHRvIHN0YXJ0IG1hbnVhbCBzZXNzaW9uXG4gICAqL3N0YXJ0TWFudWFsVHJhY2tpbmdJbnRlcm5hbCgpe3RoaXMuc3RhcnQoRGF0ZS5ub3coKSk7fS8qKlxuICAgKiBBIHB1YmxpYyBtZXRob2QgdG8gZW5kIGFuIG9uZ29pbmcgc2Vzc2lvbi5cbiAgICovZW5kKCl7c3RhdGUuc2Vzc2lvbi5zZXNzaW9uSW5mby52YWx1ZT1ERUZBVUxUX1VTRVJfU0VTU0lPTl9WQUxVRVMuc2Vzc2lvbkluZm87fS8qKlxuICAgKiBTZXQgYXV0aCB0b2tlblxuICAgKiBAcGFyYW0gdXNlcklkXG4gICAqL3NldEF1dGhUb2tlbih0b2tlbil7c3RhdGUuc2Vzc2lvbi5hdXRoVG9rZW4udmFsdWU9dGhpcy5pc1BlcnNpc3RlbmNlRW5hYmxlZEZvclN0b3JhZ2VFbnRyeSgnYXV0aFRva2VuJykmJnRva2VuP3Rva2VuOkRFRkFVTFRfVVNFUl9TRVNTSU9OX1ZBTFVFUy5hdXRoVG9rZW47fX1cblxuLyoqXG4gKiBQbHVnaW5zIHRvIGJlIGxvYWRlZCBpbiB0aGUgcGx1Z2lucyBsb2FkT3B0aW9uIGlzIG5vdCBkZWZpbmVkXG4gKi9jb25zdCBhbGxPcHRpb25hbFBsdWdpbnM9WydCZWFjb25RdWV1ZScsJ0N1c3RvbUNvbnNlbnRNYW5hZ2VyJywnRGV2aWNlTW9kZURlc3RpbmF0aW9ucycsJ0RldmljZU1vZGVUcmFuc2Zvcm1hdGlvbicsJ0V4dGVybmFsQW5vbnltb3VzSWQnLCdHb29nbGVMaW5rZXInLCdJdWJlbmRhQ29uc2VudE1hbmFnZXInLCdLZXRjaENvbnNlbnRNYW5hZ2VyJywnTmF0aXZlRGVzdGluYXRpb25RdWV1ZScsJ09uZVRydXN0Q29uc2VudE1hbmFnZXInLCdTdG9yYWdlRW5jcnlwdGlvbicsJ1N0b3JhZ2VFbmNyeXB0aW9uTGVnYWN5JywnU3RvcmFnZU1pZ3JhdG9yJywnWGhyUXVldWUnXTsvLyBQbHVnaW5zIGV4Y2x1ZGVkIGZyb20gbGl0ZSBidWlsZHMgd2hpY2ggYXJlIGFsc28gbm90IGNvbm5lY3RlZCB0byBhbnkgU0RLIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuY29uc3QgZGVmYXVsdE9wdGlvbmFsUGx1Z2luc0xpc3Q9YWxsT3B0aW9uYWxQbHVnaW5zO1xuXG5jb25zdCBub3JtYWxpem
1VMb2FkT3B0aW9ucz0obG9hZE9wdGlvbnNGcm9tU3RhdGUsbG9hZE9wdGlvbnMpPT57Ly8gVE9ETzogTWF5YmUgYWRkIHdhcm5pbmdzIGZvciBpbnZhbGlkIHZhbHVlc1xuY29uc3Qgbm9ybWFsaXplZExvYWRPcHRzPWNsb25lKGxvYWRPcHRpb25zKTtpZighaXNTdHJpbmcobm9ybWFsaXplZExvYWRPcHRzLnNldENvb2tpZURvbWFpbikpe25vcm1hbGl6ZWRMb2FkT3B0cy5zZXRDb29raWVEb21haW49dW5kZWZpbmVkO31jb25zdCBjb29raWVTYW1lU2l0ZVZhbHVlcz1bJ1N0cmljdCcsJ0xheCcsJ05vbmUnXTtpZighY29va2llU2FtZVNpdGVWYWx1ZXMuaW5jbHVkZXMobm9ybWFsaXplZExvYWRPcHRzLnNhbWVTaXRlQ29va2llKSl7bm9ybWFsaXplZExvYWRPcHRzLnNhbWVTaXRlQ29va2llPXVuZGVmaW5lZDt9bm9ybWFsaXplZExvYWRPcHRzLnNlY3VyZUNvb2tpZT1nZXROb3JtYWxpemVkQm9vbGVhblZhbHVlKG5vcm1hbGl6ZWRMb2FkT3B0cy5zZWN1cmVDb29raWUsbG9hZE9wdGlvbnNGcm9tU3RhdGUuc2VjdXJlQ29va2llKTtub3JtYWxpemVkTG9hZE9wdHMuc2FtZURvbWFpbkNvb2tpZXNPbmx5PWdldE5vcm1hbGl6ZWRCb29sZWFuVmFsdWUobm9ybWFsaXplZExvYWRPcHRzLnNhbWVEb21haW5Db29raWVzT25seSxsb2FkT3B0aW9uc0Zyb21TdGF0ZS5zYW1lRG9tYWluQ29va2llc09ubHkpO2NvbnN0IHVhQ2hUcmFja0xldmVscz1bJ25vbmUnLCdkZWZhdWx0JywnZnVsbCddO2lmKCF1YUNoVHJhY2tMZXZlbHMuaW5jbHVkZXMobm9ybWFsaXplZExvYWRPcHRzLnVhQ2hUcmFja0xldmVsKSl7bm9ybWFsaXplZExvYWRPcHRzLnVhQ2hUcmFja0xldmVsPXVuZGVmaW5lZDt9bm9ybWFsaXplZExvYWRPcHRzLmludGVncmF0aW9ucz1nZXROb3JtYWxpemVkT2JqZWN0VmFsdWUobm9ybWFsaXplZExvYWRPcHRzLmludGVncmF0aW9ucyk7aWYoIUFycmF5LmlzQXJyYXkobm9ybWFsaXplZExvYWRPcHRzLnBsdWdpbnMpKXtub3JtYWxpemVkTG9hZE9wdHMucGx1Z2lucz1kZWZhdWx0T3B0aW9uYWxQbHVnaW5zTGlzdDt9bm9ybWFsaXplZExvYWRPcHRzLnVzZUdsb2JhbEludGVncmF0aW9uc0NvbmZpZ0luRXZlbnRzPWdldE5vcm1hbGl6ZWRCb29sZWFuVmFsdWUobm9ybWFsaXplZExvYWRPcHRzLnVzZUdsb2JhbEludGVncmF0aW9uc0NvbmZpZ0luRXZlbnRzLGxvYWRPcHRpb25zRnJvbVN0YXRlLnVzZUdsb2JhbEludGVncmF0aW9uc0NvbmZpZ0luRXZlbnRzKTtub3JtYWxpemVkTG9hZE9wdHMuYnVmZmVyRGF0YVBsYW5lRXZlbnRzVW50aWxSZWFkeT1nZXROb3JtYWxpemVkQm9vbGVhblZhbHVlKG5vcm1hbGl6ZWRMb2FkT3B0cy5idWZmZXJEYXRhUGxhbmVFdmVudHNVbnRpbFJlYWR5LGxvYWRPcHRpb25zRnJvbVN0YXRlLmJ1ZmZlckRhdGFQbGFuZUV2ZW50c1VudGlsUmVhZHkpO25vcm1hbGl6ZWRMb2FkT3B0cy5zZW5kQWRibG9ja1BhZ2U9Z2V0Tm9ybWFsaXplZEJvb2xlYW5WYWx1ZShub3JtYWxpemVkTG9hZE9wdHMuc2VuZEFkYmxvY2tQYWdlLGxvYWRPcHRpb25zRnJvbVN0YXRlLnNlbmRBZGJsb2NrUGFnZSk7bm9ybWFsaXplZExvYWRPcHRzLnVzZVNlcnZlclNpZG
1VDb29raWVzPWdldE5vcm1hbGl6ZWRCb29sZWFuVmFsdWUobm9ybWFsaXplZExvYWRPcHRzLnVzZVNlcnZlclNpZGVDb29raWVzLGxvYWRPcHRpb25zRnJvbVN0YXRlLnVzZVNlcnZlclNpZGVDb29raWVzKTtpZighaXNTdHJpbmcobm9ybWFsaXplZExvYWRPcHRzLmRhdGFTZXJ2aWNlRW5kcG9pbnQpKXtub3JtYWxpemVkTG9hZE9wdHMuZGF0YVNlcnZpY2VFbmRwb2ludD11bmRlZmluZWQ7fW5vcm1hbGl6ZWRMb2FkT3B0cy5zZW5kQWRibG9ja1BhZ2VPcHRpb25zPWdldE5vcm1hbGl6ZWRPYmplY3RWYWx1ZShub3JtYWxpemVkTG9hZE9wdHMuc2VuZEFkYmxvY2tQYWdlT3B0aW9ucyk7bm9ybWFsaXplZExvYWRPcHRzLmxvYWRJbnRlZ3JhdGlvbj1nZXROb3JtYWxpemVkQm9vbGVhblZhbHVlKG5vcm1hbGl6ZWRMb2FkT3B0cy5sb2FkSW50ZWdyYXRpb24sbG9hZE9wdGlvbnNGcm9tU3RhdGUubG9hZEludGVncmF0aW9uKTtpZighaXNOb25FbXB0eU9iamVjdChub3JtYWxpemVkTG9hZE9wdHMuc3RvcmFnZSkpe25vcm1hbGl6ZWRMb2FkT3B0cy5zdG9yYWdlPXVuZGVmaW5lZDt9ZWxzZSB7bm9ybWFsaXplZExvYWRPcHRzLnN0b3JhZ2UubWlncmF0ZT1nZXROb3JtYWxpemVkQm9vbGVhblZhbHVlKG5vcm1hbGl6ZWRMb2FkT3B0cy5zdG9yYWdlLm1pZ3JhdGUsbG9hZE9wdGlvbnNGcm9tU3RhdGUuc3RvcmFnZT8ubWlncmF0ZSk7bm9ybWFsaXplZExvYWRPcHRzLnN0b3JhZ2UuY29va2llPWdldE5vcm1hbGl6ZWRPYmplY3RWYWx1ZShub3JtYWxpemVkTG9hZE9wdHMuc3RvcmFnZS5jb29raWUpO25vcm1hbGl6ZWRMb2FkT3B0cy5zdG9yYWdlLmVuY3J5cHRpb249Z2V0Tm9ybWFsaXplZE9iamVjdFZhbHVlKG5vcm1hbGl6ZWRMb2FkT3B0cy5zdG9yYWdlLmVuY3J5cHRpb24pO25vcm1hbGl6ZWRMb2FkT3B0cy5zdG9yYWdlPXJlbW92ZVVuZGVmaW5lZEFuZE51bGxWYWx1ZXMobm9ybWFsaXplZExvYWRPcHRzLnN0b3JhZ2UpO31ub3JtYWxpemVkTG9hZE9wdHMuZGVzdGluYXRpb25zUXVldWVPcHRpb25zPWdldE5vcm1hbGl6ZWRPYmplY3RWYWx1ZShub3JtYWxpemVkTG9hZE9wdHMuZGVzdGluYXRpb25zUXVldWVPcHRpb25zKTtub3JtYWxpemVkTG9hZE9wdHMucXVldWVPcHRpb25zPWdldE5vcm1hbGl6ZWRPYmplY3RWYWx1ZShub3JtYWxpemVkTG9hZE9wdHMucXVldWVPcHRpb25zKTtub3JtYWxpemVkTG9hZE9wdHMubG9ja0ludGVncmF0aW9uc1ZlcnNpb249Z2V0Tm9ybWFsaXplZEJvb2xlYW5WYWx1ZShub3JtYWxpemVkTG9hZE9wdHMubG9ja0ludGVncmF0aW9uc1ZlcnNpb24sbG9hZE9wdGlvbnNGcm9tU3RhdGUubG9ja0ludGVncmF0aW9uc1ZlcnNpb24pO25vcm1hbGl6ZWRMb2FkT3B0cy5sb2NrUGx1Z2luc1ZlcnNpb249Z2V0Tm9ybWFsaXplZEJvb2xlYW5WYWx1ZShub3JtYWxpemVkTG9hZE9wdHMubG9ja1BsdWdpbnNWZXJzaW9uLGxvYWRPcHRpb25zRnJvbVN0YXRlLmxvY2tQbHVnaW5zVmVyc2lvbik7aWYoIWlzTnVtYmVyKG5vcm1hbGl6ZWRMb2FkT3B0cy5kYXRhUGxhbmVFdmVudHNCdWZmZXJUaW1lb3V0KSl7bm9ybWFsaXplZExvYWRPcHRzLmRhdGFQbGFuZUV2ZW50c0J1ZmZlclRpbWVvdXQ9dW5kZWZpbmVkO31ub3JtYWxpemVkTG9hZE9wdHMuYmVhY29uUXVldWVPcHRpb25zPWdldE5vcm1hbGl6ZWRPYmplY3RWYWx1ZShub3JtYWxpemVkTG9hZE9wdHMuYmVhY29uUXVldWVPcHRpb25zKTtub3JtYWxpemVkTG9hZE9wdHMucHJlQ29uc2VudD1nZXROb3JtYWxpemVkT2JqZWN0VmFsdWUobm9ybWFsaXplZExvYWRPcHRzLnByZUNvbnNlbnQpO25vcm1hbGl6ZWRMb2FkT3B0cy5zb3VyY2VDb25maWd1cmF0aW9uT3ZlcnJpZGU9Z2V0Tm9ybWFsaXplZE9iamVjdFZhbHVlKG5vcm1hbGl6ZWRMb2FkT3B0cy5zb3VyY2VDb25maWd1cmF0aW9uT3ZlcnJpZGUpO2NvbnN0IG1lcmdlZExvYWRPcHRpb25zPW1lcmdlRGVlcFJpZ2h0KGxvYWRPcHRpb25zRnJvbVN0YXRlLHJlbW92ZVVuZGVmaW5lZEFuZE51bGxWYWx1ZXMobm9ybWFsaXplZExvYWRPcHRzKSk7cmV0dXJuIG1lcmdlZExvYWRPcHRpb25zO307XG5cbmNvbnN0IERBVEFfUExBTkVfUVVFVUVfRVhUX1BPSU5UX1BSRUZJWD0nZGF0YXBsYW5lRXZlbnRzUXVldWUnO2NvbnN0IERFU1RJTkFUSU9OU19RVUVVRV9FWFRfUE9JTlRfUFJFRklYPSdkZXN0aW5
1hdGlvbnNFdmVudHNRdWV1ZSc7Y29uc3QgRE1UX0VYVF9QT0lOVF9QUkVGSVg9J3RyYW5zZm9ybUV2ZW50JztcblxuLyoqXG4gKiBGaWx0ZXJzIGFuZCByZXR1cm5zIHRoZSB1c2VyIHN1cHBsaWVkIGludGVncmF0aW9ucyBjb25maWcgdGhhdCBzaG91bGQgdGFrZSBwcmVmZXJlbmNlIG92ZXIgdGhlIGRlc3RpbmF0aW9uIHNwZWNpZmljIGludGVncmF0aW9ucyBjb25maWdcbiAqIEBwYXJhbSBldmVudEludGdDb25maWcgVXNlciBzdXBwbGllZCBpbnRlZ3JhdGlvbnMgY29uZmlnIGF0IGV2ZW50IGxldmVsXG4gKiBAcGFyYW0gZGVzdGluYXRpb25zSW50Z0NvbmZpZyBDdW11bGF0aXZlIGludGVncmF0aW9ucyBjb25maWcgZnJvbSBhbGwgZGVzdGluYXRpb25zXG4gKiBAcmV0dXJucyBGaWx0ZXJlZCB1c2VyIHN1cHBsaWVkIGludGVncmF0aW9ucyBjb25maWdcbiAqL2NvbnN0IGdldE92ZXJyaWRkZW5JbnRlZ3JhdGlvbk9wdGlvbnM9KGV2ZW50SW50Z0NvbmZpZyxkZXN0aW5hdGlvbnNJbnRnQ29uZmlnKT0+T2JqZWN0LmtleXMoZXZlbnRJbnRnQ29uZmlnKS5maWx0ZXIoaW50Z05hbWU9PmV2ZW50SW50Z0NvbmZpZ1tpbnRnTmFtZV0hPT10cnVlfHwhZGVzdGluYXRpb25zSW50Z0NvbmZpZ1tpbnRnTmFtZV0pLnJlZHVjZSgob2JqLGtleSk9Pntjb25zdCByZXRWYWw9Y2xvbmUob2JqKTtyZXRWYWxba2V5XT1ldmVudEludGdDb25maWdba2V5XTtyZXR1cm4gcmV0VmFsO30se30pOy8qKlxuICogUmV0dXJucyB0aGUgZXZlbnQgb2JqZWN0IHdpdGggZmluYWwgaW50ZWdyYXRpb25zIGNvbmZpZ1xuICogQHBhcmFtIGV2ZW50IFJ1ZGRlckV2ZW50IG9iamVjdFxuICogQHBhcmFtIHN0YXRlIEFwcGxpY2F0aW9uIHN0YXRlXG4gKiBAcmV0dXJucyBNdXRhdGVkIGV2ZW50IHdpdGggZmluYWwgaW50ZWdyYXRpb25zIGNvbmZpZ1xuICovY29uc3QgZ2V0RmluYWxFdmVudD0oZXZlbnQsc3RhdGUpPT57Y29uc3QgZmluYWxFdmVudD1jbG9uZShldmVudCk7Ly8gTWVyZ2UgdGhlIGRlc3RpbmF0aW9uIHNwZWNpZmljIGludGVncmF0aW9ucyBjb25maWcgd2l0aCB0aGUgZXZlbnQncyBpbnRlZ3JhdGlvbnMgY29uZmlnXG4vLyBJbiBnZW5lcmFsLCB0aGUgcHJlZmVyZW5jZSBpcyBnaXZlbiB0byB0aGUgZXZlbnQncyBpbnRlZ3JhdGlvbnMgY29uZmlnXG5jb25zdCBkZXN0aW5hdGlvbnNJbnRnQ29uZmlnPXN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5pbnRlZ3JhdGlvbnNDb25maWcudmFsdWU7Y29uc3Qgb3ZlcnJpZGRlbkludGdPcHRzPWdldE92ZXJyaWRkZW5JbnRlZ3JhdGlvbk9wdGlvbnMoZXZlbnQuaW50ZWdyYXRpb25zLGRlc3RpbmF0aW9uc0ludGdDb25maWcpO2ZpbmFsRXZlbnQuaW50ZWdyYXRpb25zPW1lcmdlRGVlcFJpZ2h0KGRlc3RpbmF0aW9uc0ludGdDb25maWcsb3ZlcnJpZGRlbkludGdPcHRzKTtyZXR1cm4gZmluYWxFdmVudDt9O2NvbnN0IHNob3VsZEJ1ZmZlckV2ZW50c0ZvclByZUNvbnNlbnQ9c3RhdGU9PnN0YXRlLmNvbnNlbnRzLnByZUNvbnNlbnQudmFsdWUuZW5hYmxlZCYmc3RhdGUuY29uc2VudHMucHJlQ29uc2VudC52YWx1ZS
15ldmVudHM/LmRlbGl2ZXJ5PT09J2J1ZmZlcic7XG5cbmNvbnN0IHNhZmVseUludm9rZUNhbGxiYWNrPShjYWxsYmFjayxhcmdzLGFwaU5hbWUsbG9nZ2VyKT0+e2lmKCFpc0RlZmluZWQoY2FsbGJhY2spKXtyZXR1cm47fWlmKGlzRnVuY3Rpb24oY2FsbGJhY2spKXt0cnl7Y2FsbGJhY2soLi4uYXJncyk7fWNhdGNoKGVycm9yKXtsb2dnZXIuZXJyb3IoQ0FMTEJBQ0tfSU5WT0tFX0VSUk9SKGFwaU5hbWUpLGVycm9yKTt9fWVsc2Uge2xvZ2dlci5lcnJvcihJTlZBTElEX0NBTExCQUNLX0ZOX0VSUk9SKGFwaU5hbWUpKTt9fTtcblxuLyoqXG4gKiBFdmVudCByZXBvc2l0b3J5IGNsYXNzIHJlc3BvbnNpYmxlIGZvciBxdWV1aW5nIGV2ZW50cyBmb3IgZnVydGhlciBwcm9jZXNzaW5nIGFuZCBkZWxpdmVyeVxuICovY2xhc3MgRXZlbnRSZXBvc2l0b3J5ey8qKlxuICAgKlxuICAgKiBAcGFyYW0gcGx1Z2luc01hbmFnZXIgUGx1Z2lucyBtYW5hZ2VyIGluc3RhbmNlXG4gICAqIEBwYXJhbSBzdG9yZU1hbmFnZXIgU3RvcmUgTWFuYWdlciBpbnN0YW5jZVxuICAgKiBAcGFyYW0gZXJyb3JIYW5kbGVyIEVycm9yIGhhbmRsZXIgb2JqZWN0XG4gICAqIEBwYXJhbSBsb2dnZXIgTG9nZ2VyIG9iamVjdFxuICAgKi9jb25zdHJ1Y3RvcihwbHVnaW5zTWFuYWdlcixzdG9yZU1hbmFnZXIsaHR0cENsaWVudCxlcnJvckhhbmRsZXIsbG9nZ2VyKXt0aGlzLnBsdWdpbnNNYW5hZ2VyPXBsdWdpbnNNYW5hZ2VyO3RoaXMuZXJyb3JIYW5kbGVyPWVycm9ySGFuZGxlcjt0aGlzLmh0dHBDbGllbnQ9aHR0cENsaWVudDt0aGlzLmxvZ2dlcj1sb2dnZXI7dGhpcy5zdG9yZU1hbmFnZXI9c3RvcmVNYW5hZ2VyO30vKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIGV2ZW50IHJlcG9zaXRvcnlcbiAgICovaW5pdCgpe3RoaXMuZGF0YXBsYW5lRXZlbnRzUXVldWU9dGhpcy5wbHVnaW5zTWFuYWdlci5pbnZva2VTaW5nbGUoYCR7REFUQV9QTEFORV9RVUVVRV9FWFRfUE9JTlRfUFJFRklYfS5pbml0YCxzdGF0ZSx0aGlzLmh0dHBDbGllbnQsdGhpcy5zdG9yZU1hbmFnZXIsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpO3RoaXMuZG10RXZlbnRzUXVldWU9dGhpcy5wbHVnaW5zTWFuYWdlci5pbnZva2VTaW5nbGUoYCR7RE1UX0VYVF9QT0lOVF9QUkVGSVh9LmluaXRgLHN0YXRlLHRoaXMucGx1Z2luc01hbmFnZXIsdGhpcy5odHRwQ2xpZW50LHRoaXMuc3RvcmVNYW5hZ2VyLHRoaXMuZXJyb3JIYW5kbGVyLHRoaXMubG9nZ2VyKTt0aGlzLmRlc3RpbmF0aW9uc0V2ZW50c1F1ZXVlPXRoaXMucGx1Z2luc01hbmFnZXIuaW52b2tlU2luZ2xlKGAke0RFU1RJTkFUSU9OU19RVUVVRV9FWFRfUE9JTlRfUFJFRklYfS5pbml0YCxzdGF0ZSx0aGlzLnBsdWdpbnNNYW5hZ2VyLHRoaXMuc3RvcmVNYW5hZ2VyLHRoaXMuZG10RXZlbnRzUXVldWUsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpOy8vIFN0YXJ0IHRoZSBxdWV1ZSBvbmNlIHRoZSBjbGllbnQgZGVzdGluYXRpb25zIGFyZSByZWFkeVxuaigoKT0+e2lmKHN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5jbGllbnREZXN0aW5hdGlvbnNSZWFkeS52YWx1ZT09PXRydWUpe3RoaXMuZGVzdGluYXRpb25zRXZlbnRzUXVldWU/LnN0YXJ0KCk7dGhpcy5kbXRFdmVudHNRdWV1ZT8uc3RhcnQoKTt9fSk7Y29uc3QgYnVmZmVyRXZlbnRzQmVmb3JlQ29uc2VudD1zaG91bGRCdWZmZXJFdmVudHNGb3JQcmVDb25zZW50KHN0YXRlKTsvLyBTdGFydCB0aGUgcXVldWUgcHJvY2Vzc2luZyBvbmx5IHdoZW4gdGhlIGRlc3RpbmF0aW9ucyBhcmUgcmVhZHkgb3IgaHlicmlkIG1vZGUgZGVzdGluYXRpb25zIGV4aXN0XG4vLyBIb3dldmVyLCBldmVudHMgd2lsbCBiZSBlbnF1ZXVlZCBmb3Igbm93LlxuLy8gQXQgdGhlIHRpbWUgb2YgcHJvY2Vzc2luZyB0aGUgZXZlbnRzLCB0aGUgaW50ZWdyYXRpb25zIGNvbmZpZyBkYXRhIGZyb20gZGVzdGluYXRpb25zXG4vLyBpcyBtZXJnZWQgaW50byB0aGUgZXZlbnQgb2JqZWN0XG5sZXQgdGltZW91dElkO2ooKCk9Pntjb25zdCBzaG91bGRCdWZmZXJEcEV2ZW50cz1zdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZS5idWZmZXJEYXRhUGxhbmVFdmVudHNVbnRpbFJlYWR5PT09dHJ1ZSYmc3RhdGUubmF0aXZlRGVzdGluYXRpb25zLmNsaWVudERlc3RpbmF0aW9uc1JlYWR5LnZhbHVlPT09ZmFsc2U7Y29uc3QgaHlicmlkRGVzdEV4aXN0PXN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5hY3RpdmVEZXN0aW5hdGlvbnMudmFsdWUuc29tZShkZXN0PT5pc0h5YnJpZE1vZGVEZXN0aW5hdGlvbihkZXN0KSk7aWYoKGh5YnJpZERlc3RFeGlzdD09PWZhbHNlfHxzaG91bGRCdWZmZXJEcEV2ZW50cz09PWZhbHNlKSYmIWJ1ZmZlckV2ZW50c0JlZm9yZUNvbnNlbnQmJnRoaXMuZGF0YXBsYW5lRXZlbnRzUXVldWU/LnNjaGVkdWxlVGltZW91dEFjdGl2ZSE9PXRydWUpe2dsb2JhbFRoaXMuY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7dGhpcy5kYXRhcGxhbmVFdmVudHNRdWV1ZT8uc3RhcnQoKTt9fSk7Ly8gRm9yY2Ugc3RhcnQgdGhlIGRhdGEgcGxhbmUgZXZlbnRzIHF1ZXVlIHByb2Nlc3NpbmcgYWZ0ZXIgYSB0aW1lb3V0XG5pZihzdGF0ZS5sb2FkT3B0aW9ucy52YWx1ZS5idWZmZXJEYXRhUGxhbmVFdmVudHNVbnRpbFJlYWR5PT09dHJ1ZSl7dGltZW91dElkPWdsb2JhbFRoaXMuc2V0VGltZW91dCgoKT0+e2lmKHRoaXMuZGF0YXBsYW5lRXZlbnRzUXVldWU/LnNjaGVkdWxlVGltZW91dEFjdGl2ZSE9PXRydWUpe3RoaXMuZGF0YXBsYW5lRXZlbnRzUXVldWU/LnN0YXJ0KCk7fX0sc3RhdGUubG9hZE9wdGlvbnMudmFsdWUuZGF0YVBsYW5lRXZlbnRzQnVmZmVyVGltZW91dCk7fX1yZXN1bWUoKXtpZih0aGlzLmRhdGFwbGFuZUV2ZW50c1F1ZXVlPy5zY2hlZHVsZVRpbWVvdXRBY3RpdmUhPT10cnVlKXtpZihzdGF0ZS5jb25zZW50cy5wb3N0Q29uc2VudC52YWx1ZS
15kaXNjYXJkUHJlQ29uc2VudEV2ZW50cyl7dGhpcy5kYXRhcGxhbmVFdmVudHNRdWV1ZT8uY2xlYXIoKTt0aGlzLmRlc3RpbmF0aW9uc0V2ZW50c1F1ZXVlPy5jbGVhcigpO310aGlzLmRhdGFwbGFuZUV2ZW50c1F1ZXVlPy5zdGFydCgpO319LyoqXG4gICAqIEVucXVldWVzIHRoZSBldmVudCBmb3IgcHJvY2Vzc2luZ1xuICAgKiBAcGFyYW0gZXZlbnQgUnVkZGVyRXZlbnQgb2JqZWN0XG4gICAqIEBwYXJhbSBjYWxsYmFjayBBUEkgY2FsbGJhY2sgZnVuY3Rpb25cbiAgICovZW5xdWV1ZShldmVudCxjYWxsYmFjayl7Y29uc3QgZHBRRXZlbnQ9Z2V0RmluYWxFdmVudChldmVudCxzdGF0ZSk7dGhpcy5wbHVnaW5zTWFuYWdlci5pbnZva2VTaW5nbGUoYCR7REFUQV9QTEFORV9RVUVVRV9FWFRfUE9JTlRfUFJFRklYfS5lbnF1ZXVlYCxzdGF0ZSx0aGlzLmRhdGFwbGFuZUV2ZW50c1F1ZXVlLGRwUUV2ZW50LHRoaXMuZXJyb3JIYW5kbGVyLHRoaXMubG9nZ2VyKTtjb25zdCBkUUV2ZW50PWNsb25lKGV2ZW50KTt0aGlzLnBsdWdpbnNNYW5hZ2VyLmludm9rZVNpbmdsZShgJHtERVNUSU5BVElPTlNfUVVFVUVfRVhUX1BPSU5UX1BSRUZJWH0uZW5xdWV1ZWAsc3RhdGUsdGhpcy5kZXN0aW5hdGlvbnNFdmVudHNRdWV1ZSxkUUV2ZW50LHRoaXMuZXJyb3JIYW5kbGVyLHRoaXMubG9nZ2VyKTsvLyBJbnZva2UgdGhlIGNhbGxiYWNrIGlmIGl0IGV4aXN0c1xuY29uc3QgYXBpTmFtZT1gJHtldmVudC50eXBlLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpfSR7ZXZlbnQudHlwZS5zbGljZSgxKX0ke0FQSV9TVUZGSVh9YDtzYWZlbHlJbnZva2VDYWxsYmFjayhjYWxsYmFjayxbZHBRRXZlbnRdLGFwaU5hbWUsdGhpcy5sb2dnZXIpO319XG5cbmNvbnN0IGRpc3BhdGNoU0RLRXZlbnQ9ZXZlbnQ9Pntjb25zdCBjdXN0b21FdmVudD1uZXcgQ3VzdG9tRXZlbnQoZXZlbnQse2RldGFpbDp7YW5hbHl0aWNzSW5zdGFuY2U6Z2xvYmFsVGhpcy5ydWRkZXJhbmFseXRpY3N9LGJ1YmJsZXM6dHJ1ZSxjYW5jZWxhYmxlOnRydWUsY29tcG9zZWQ6dHJ1ZX0pO2dsb2JhbFRoaXMuZG9jdW1lbnQuZGlzcGF0Y2hFdmVudChjdXN0b21FdmVudCk7fTtjb25zdCBpc1dyaXRlS2V5VmFsaWQ9d3JpdGVLZXk9PmlzU3RyaW5nKHdyaXRlS2V5KSYmd3JpdGVLZXkudHJpbSgpLmxlbmd0aD4wO2NvbnN0IGlzRGF0YVBsYW5lVXJsVmFsaWQ9ZGF0YVBsYW5lVXJsPT5pc1ZhbGlkVVJMKGRhdGFQbGFuZVVybCk7XG5cbi8qXG4gKiBBbmFseXRpY3MgY2xhc3Mgd2l0aCBsaWZlY3ljbGUgYmFzZWQgb24gc3RhdGUgYWQgdXNlciB0cmlnZ2VyZWQgZXZlbnRzXG4gKi9jbGFzcyBBbmFseXRpY3N7LyoqXG4gICAqIEluaXRpYWxpemUgc2VydmljZXMgYW5kIGNvbXBvbmVudHMgb3IgdXNlIGRlZmF1bHQgb25lcyBpZiBzaW5nbGV0b25zXG4gICAqL2NvbnN0cnVjdG9yKCl7dGhpcy5wcmVsb2FkQnVmZmVyPW5ldyBCdWZmZXJRdWV1ZSgpO3RoaXMuaW5pdGlhbGl6ZWQ9ZmFsc2U7dGhpcy5lcnJvckhhbmRsZXI9ZGVmYXVsdEVycm9ySGFuZGxlcjt0aGlzLmxvZ2dlcj1kZWZhdWx0TG9nZ2VyO3RoaXMuZXh0ZXJuYWxTcmNMb2FkZXI9bmV3IEV4dGVybmFsU3JjTG9hZGVyKHRoaXMubG9nZ2VyKTt0aGlzLmh0dHBDbGllbnQ9ZGVmYXVsdEh0dHBDbGllbnQ7dGhpcy5odHRwQ2xpZW50LmluaXQodGhpcy5lcnJvckhhbmRsZXIpO3RoaXMuY2FwYWJpbGl0aWVzTWFuYWdlcj1uZXcgQ2FwYWJpbGl0aWVzTWFuYWdlcih0aGlzLmh0dHBDbGllbnQsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpO30vKipcbiAgICogU3RhcnQgYXBwbGljYXRpb24gbGlmZWN5Y2xlIGlmIG5vdCBhbHJlYWR5IHN0YXJ0ZWRcbiAgICovbG9hZCh3cml0ZUtleSxkYXRhUGxhbmVVcmwsbG9hZE9wdGlvbnM9e30pe2lmKHN0YXRlLmxpZmVjeWNsZS5zdGF0dXMudmFsdWUpe3JldHVybjt9aWYoIWlzV3JpdGVLZXlWYWxpZCh3cml0ZUtleSkpe3RoaXMubG9nZ2VyLmVycm9yKFdSSVRFX0tFWV9WQUxJREFUSU9OX0VSUk9SKEFOQUxZVElDU19DT1JFLHdyaXRlS2V5KSk7cmV0dXJuO31pZighaXNEYXRhUGxhbmVVcmxWYWxpZChkYXRhUGxhbmVVcmwpKXt0aGlzLmxvZ2dlci5lcnJvcihEQVRBX1BMQU5FX1VSTF9WQUxJREFUSU9OX0VSUk9SKEFOQUxZVElDU19DT1JFLGRhdGFQbGFuZVVybCkpO3JldHVybjt9Ly8gU2V0IGluaXRpYWwgc3RhdGUgdmFsdWVzXG5uKCgpPT57c3RhdGUubGlmZWN5Y2xlLndyaXRlS2V5LnZhbHVlPWNsb25lKHdyaXRlS2V5KTtzdGF0ZS5saWZlY3ljbGUuZGF0YVBsYW5lVXJsLnZhbHVlPWNsb25lKGRhdGFQbGFuZVVybCk7c3RhdGUubG9hZE9wdGlvbnMudmFsdWU9bm9ybWFsaXplTG9hZE9wdGlvbnMoc3RhdGUubG9hZE9wdGlvbnMudmFsdWUsbG9hZE9wdGlvbnMpO3N0YXRlLmxpZmVjeWNsZS5zdGF0dXMudmFsdWU9J21vdW50ZWQnO30pOy8vIHNldCBsb2cgbGV2ZWwgYXMgZWFybHkgYXMgcG9zc2libGVcbnRoaXMubG9nZ2VyLnNldE1pbkxvZ0xldmVsKHN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLmxvZ0xldmVsPz9QT1NUX0xPQURfTE9HX0xFVkVMKTsvLyBFeHBvc2Ugc3RhdGUgdG8gZ2xvYmFsIG9iamVjdHNcbnNldEV4cG9zZWRHbG9iYWwoJ3N0YXRlJyxzdGF0ZSx3cml0ZUtleSk7Ly8gQ29uZmlndXJlIGluaXRpYWwgY29uZmlnIG9mIGFueSBzZXJ2aWNlcyBvciBjb21wb25lbnRzIGhlcmVcbi8vIFN0YXRlIGFwcGxpY2F0aW9uIGxpZmVjeWNsZVxudGhpcy5zdGFydExpZmVjeWNsZSgpO30vLyBTdGFydCBsaWZlY3ljbGUgbWV0aG9kc1xuLyoqXG4gICAqIE9yY2hlc3RyYXRlIHRoZSBsaWZlY3ljbGUgb2YgdGhlIGFwcGxpY2F0aW9uIHBoYXNlcy9zdGF0dXNcbiAgICovc3RhcnRMaWZlY3ljbGUoKXtqKCgpPT57dHJ5e3N3aXRjaChzdGF0ZS5saWZlY3ljbGUuc3RhdHVzLnZhbHVlKXtjYXNlICdtb3VudGVkJzp0aGlzLm9uTW91bnRlZCgpO2JyZWFrO2Nhc2UgJ2Jyb3dzZXJDYXBhYmlsaXRpZXNSZWFkeSc6dGhpcy5vbkJyb3dzZXJDYXBhYmlsaXRpZXNSZWFkeSgpO2JyZWFrO2Nhc2UgJ2NvbmZpZ3VyZWQnOnRoaXMub25Db25maWd1cmVkKCk7YnJlYWs7Y2FzZSAncGx1Z2luc0xvYWRpbmcnOmJyZWFrO2Nhc2UgJ3BsdWdpbnNSZWFkeSc6dGhpcy5vblBsdWdpbnNSZWFkeSgpO2JyZWFrO2Nhc2UgJ2luaXRpYWxpemVkJzp0aGlzLm9uSW5pdGlhbGl6ZWQoKTticmVhaztjYXNlICdsb2FkZWQnOnRoaXMub25Mb2FkZWQoKTticmVhaztjYXNlICdkZXN0aW5
1hdGlvbnNMb2FkaW5nJzpicmVhaztjYXNlICdkZXN0aW5hdGlvbnNSZWFkeSc6dGhpcy5vbkRlc3RpbmF0aW9uc1JlYWR5KCk7YnJlYWs7Y2FzZSAncmVhZHknOnRoaXMub25SZWFkeSgpO2JyZWFrO2Nhc2UgJ3JlYWR5RXhlY3V0ZWQnOmRlZmF1bHQ6YnJlYWs7fX1jYXRjaChlcnIpe2NvbnN0IGlzc3VlPSdGYWlsZWQgdG8gbG9hZCB0aGUgU0RLJzt0aGlzLmVycm9ySGFuZGxlci5vbkVycm9yKHtlcnJvcjplcnIsY29udGV4dDpBTkFMWVRJQ1NfQ09SRSxjdXN0b21NZXNzYWdlOmlzc3VlLGdyb3VwaW5nSGFzaDppc3N1ZX0pO319KTt9b25Ccm93c2VyQ2FwYWJpbGl0aWVzUmVhZHkoKXsvLyBpbml0aWFsaXplIHRoZSBwcmVsb2FkZWQgZXZlbnRzIGVucXVldWluZ1xucmV0cmlldmVQcmVsb2FkQnVmZmVyRXZlbnRzKHRoaXMpO3RoaXMucHJlcGFyZUludGVybmFsU2VydmljZXMoKTt0aGlzLmxvYWRDb25maWcoKTt9b25Mb2FkZWQoKXt0aGlzLnByb2Nlc3NCdWZmZXJlZEV2ZW50cygpOy8vIFNob3J0LWNpcmN1aXQgdGhlIGxpZmUgY3ljbGUgYW5kIG1vdmUgdG8gdGhlIHJlYWR5IHN0YXRlIGlmIHByZS1jb25zZW50IGJlaGF2aW9yIGlzIGVuYWJsZWRcbmlmKHN0YXRlLmNvbnNlbnRzLnByZUNvbnNlbnQudmFsdWUuZW5hYmxlZD09PXRydWUpe3N0YXRlLmxpZmVjeWNsZS5zdGF0dXMudmFsdWU9J3JlYWR5Jzt9ZWxzZSB7dGhpcy5sb2FkRGVzdGluYXRpb25zKCk7fX0vKipcbiAgICogTG9hZCBicm93c2VyIHBvbHlmaWxsIGlmIHJlcXVpcmVkXG4gICAqL29uTW91bnRlZCgpe3RoaXMuY2FwYWJpbGl0aWVzTWFuYWdlci5pbml0KCk7fS8qKlxuICAgKiBFbnF1ZXVlIGluIFNESyBwcmVsb2FkIGJ1ZmZlciBldmVudHMsIHVzZWQgZnJvbSBwcmVsb2FkQnVmZmVyIGNvbXBvbmVudFxuICAgKi9lbnF1ZXVlUHJlbG9hZEJ1ZmZlckV2ZW50cyhidWZmZXJlZEV2ZW50cyl7aWYoQXJyYXkuaXNBcnJheShidWZmZXJlZEV2ZW50cykpe2J1ZmZlcmVkRXZlbnRzLmZvckVhY2goYnVmZmVyZWRFdmVudD0+dGhpcy5wcmVsb2FkQnVmZmVyLmVucXVldWUoY2xvbmUoYnVmZmVyZWRFdmVudCkpKTt9fS8qKlxuICAgKiBQcm9jZXNzIHRoZSBidWZmZXIgcHJlbG9hZGVkIGV2ZW50cyBieSBwYXNzaW5nIHRoZWlyIGFyZ3VtZW50cyB0byB0aGUgcmVzcGVjdGl2ZSBmYWNhZGUgbWV0aG9kc1xuICAgKi9wcm9jZXNzRGF0YUluUHJlbG9hZEJ1ZmZlcigpe3doaWxlKHRoaXMucHJlbG9hZEJ1ZmZlci5zaXplKCk+MCl7Y29uc3QgZXZlbnRUb1Byb2Nlc3M9dGhpcy5wcmVsb2FkQnVmZmVyLmRlcXVldWUoKTtpZihldmVudFRvUHJvY2Vzcyl7Y29uc3VtZVByZWxvYWRCdWZmZXJlZEV2ZW50KFsuLi5ldmVudFRvUHJvY2Vzc10sdGhpcyk7fX19cHJlcGFyZUludGVybmFsU2VydmljZXMoKXt0aGlzLnBsdWdpbnNNYW5hZ2VyPW5ldyBQbHVnaW5zTWFuYWdlcihkZWZh
1dWx0UGx1Z2luRW5naW5lLHRoaXMuZXJyb3JIYW5kbGVyLHRoaXMubG9nZ2VyKTt0aGlzLnN0b3JlTWFuYWdlcj1uZXcgU3RvcmVNYW5hZ2VyKHRoaXMucGx1Z2luc01hbmFnZXIsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpO3RoaXMuY29uZmlnTWFuYWdlcj1uZXcgQ29uZmlnTWFuYWdlcih0aGlzLmh0dHBDbGllbnQsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpO3RoaXMudXNlclNlc3Npb25NYW5hZ2VyPW5ldyBVc2VyU2Vzc2lvbk1hbmFnZXIodGhpcy5wbHVnaW5zTWFuYWdlcix0aGlzLnN0b3JlTWFuYWdlcix0aGlzLmh0dHBDbGllbnQsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpO3RoaXMuZXZlbnRSZXBvc2l0b3J5PW5ldyBFdmVudFJlcG9zaXRvcnkodGhpcy5wbHVnaW5zTWFuYWdlcix0aGlzLnN0b3JlTWFuYWdlcix0aGlzLmh0dHBDbGllbnQsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpO3RoaXMuZXZlbnRNYW5hZ2VyPW5ldyBFdmVudE1hbmFnZXIodGhpcy5ldmVudFJlcG9zaXRvcnksdGhpcy51c2VyU2Vzc2lvbk1hbmFnZXIsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpO30vKipcbiAgICogTG9hZCBjb25maWd1cmF0aW9uXG4gICAqL2xvYWRDb25maWcoKXtpZihzdGF0ZS5saWZlY3ljbGUud3JpdGVLZXkudmFsdWUpe3RoaXMuaHR0cENsaWVudC5zZXRBdXRoSGVhZGVyKHN0YXRlLmxpZmVjeWNsZS53cml0ZUtleS52YWx1ZSk7fXRoaXMuY29uZmlnTWFuYWdlcj8uaW5pdCgpO30vKipcbiAgICogSW5pdGlhbGl6ZSB0aGUgc3RvcmFnZSBhbmQgZXZlbnQgcXVldWVcbiAgICovb25QbHVnaW5zUmVhZHkoKXsvLyBJbml0aWFsaXplIHN0b3JhZ2VcbnRoaXMuc3RvcmVNYW5hZ2VyPy5pbml0KCk7dGhpcy51c2VyU2Vzc2lvbk1hbmFnZXI/LmluaXQoKTsvLyBJbml0aWFsaXplIHRoZSBhcHByb3ByaWF0ZSBjb25zZW50IG1hbmFnZXIgcGx1Z2luXG5pZihzdGF0ZS5jb25zZW50cy5lbmFibGVkLnZhbHVlJiYhc3RhdGUuY29uc2VudHMuaW5pdGlhbGl6ZWQudmFsdWUpe3RoaXMucGx1Z2luc01hbmFnZXI/Lmludm9rZVNpbmdsZShgY29uc2VudE1hbmFnZXIuaW5pdGAsc3RhdGUsdGhpcy5sb2dnZXIpO2lmKHN0YXRlLmNvbnNlbnRzLnByZUNvbnNlbnQudmFsdWUuZW5hYmxlZD09PWZhbHNlKXt0aGlzLnBsdWdpbnNNYW5hZ2VyPy5pbnZva2VTaW5nbGUoYGNvbnNlbnRNYW5hZ2VyLnVwZGF0ZUNvbnNlbnRzSW5mb2Asc3RhdGUsdGhpcy5zdG9yZU1hbmFnZXIsdGhpcy5sb2dnZXIpO319Ly8gSW5pdGlhbGl6ZSBldmVudCBtYW5hZ2VyXG50aGlzLmV2ZW50TWFuYWdlcj8uaW5pdCgpOy8vIE1hcmsgdGhlIFNESyBhcyBpbml0aWFsaXplZFxuc3RhdGUubGlmZWN5Y2xlLnN0YXR1cy52YWx1ZT0naW5pdGlhbGl6ZWQnO30vKipcbiAgICogTG9hZCBwbHVnaW5zXG4gICAqL29uQ29uZmlndXJlZCgpe3RoaXMucGx1Z2luc01hbmFnZXI/LmluaXQoKTsvLyBUT0RPOiBhcmUgd2UgZ29pbmcgdG8gZW5hYmxlIGN1c3RvbSBwbHVnaW5zIHRvIGJlIHBhc3NlZCBhcyBsb2FkIG9wdGlvbnM/XG4vLyByZWdpc3RlckN1c3RvbVBsdWdpbnMoc3RhdGUubG9hZE9wdGlvbnMudmFsdWUuY3VzdG9tUGx1Z2lucyk7XG59LyoqXG4gICAqIFRyaWdnZXIgb25Mb2FkZWQgY2FsbGJhY2sgaWYgYW55IGlzIHByb3ZpZGVkIGluIGNvbmZpZyAmIGVtaXQgaW5pdGlhbGlzZWQgZXZlbnRcbiAgICovb25Jbml0aWFsaXplZCgpey8vIFByb2Nlc3MgYW55IHByZWxvYWRlZCBldmVudHNcbnRoaXMucHJvY2Vzc0RhdGFJblByZWxvYWRCdWZmZXIoKTsvLyBTZXQgbGlmZWN5Y2xlIHN0YXRlXG5uKCgpPT57c3RhdGUubGlmZWN5Y2xlLmxvYWRlZC52YWx1ZT10cnVlO3N0YXRlLmxpZmVjeWNsZS5zdGF0dXMudmFsdWU9J2xvYWRlZCc7fSk7dGhpcy5pbml0aWFsaXplZD10cnVlOy8vIEV4ZWN1dGUgb25Mb2FkZWQgY2FsbGJhY2sgaWYgcHJvdmlkZWQgaW4gbG9hZCBvcHRpb25zXG5jb25zdCBvbkxvYWRlZENhbGxiYWNrRm49c3RhdGUubG9hZE9wdGlvbnMudmFsdWUub25Mb2FkZWQ7Ly8gVE9ETzogd2UgbmVlZCB0byBhdm9pZCBwYXNzaW5nIHRoZSB3aW5kb3cgb2JqZWN0IHRvIHRoZSBjYWxsYmFjayBmdW5jdGlvblxuLy8gYXMgdGhpcyB3aWxsIHByZXZlbnQgdXMgZnJvbSBzdXBwb3J0aW5nIG11bHRpcGxlIFNESyBpbnN0YW5jZXMgaW4gdGhlIHNhbWUgcGFnZVxuc2FmZWx5SW52b2tlQ2FsbGJhY2sob25Mb2FkZWRDYWxsYmFja0ZuLFtnbG9iYWxUaGlzLnJ1ZGRlcmFuYWx5dGljc10sTE9BRF9BUEksdGhpcy5sb2dnZXIpOy8vIEVtaXQgYW4gZXZlbnQgdG8gdXNlIGFzIHN1YnN0aXR1dGUgdG8gdGhlIG9uTG9hZGVkIGNhbGxiYWNrXG5kaXNwYXRjaFNES0V2ZW50KCdSU0FfSW5pdGlhbGlzZWQnKTt9LyoqXG4gICAqIEVtaXQgcmVhZHkgZXZlbnRcbiAgICovLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbm9uUmVhZHkoKXtzdGF0ZS5saWZlY3ljbGUuc3RhdHVzLnZhbHVlPSdyZWFkeUV4ZWN1dG
1VkJztzdGF0ZS5ldmVudEJ1ZmZlci5yZWFkeUNhbGxiYWNrc0FycmF5LnZhbHVlLmZvckVhY2goY2FsbGJhY2s9PntzYWZlbHlJbnZva2VDYWxsYmFjayhjYWxsYmFjayxbXSxSRUFEWV9BUEksdGhpcy5sb2dnZXIpO30pOy8vIEVtaXQgYW4gZXZlbnQgdG8gdXNlIGFzIHN1YnN0aXR1dGUgdG8gdGhlIHJlYWR5IGNhbGxiYWNrXG5kaXNwYXRjaFNES0V2ZW50KCdSU0FfUmVhZHknKTt9LyoqXG4gICAqIENvbnN1bWUgcHJlbG9hZGVkIGV2ZW50cyBidWZmZXJcbiAgICovcHJvY2Vzc0J1ZmZlcmVkRXZlbnRzKCl7Ly8gVGhpcyBsb2dpYyBoYXMgYmVlbiBpbnRlbnRpb25hbGx5IGltcGxlbWVudGVkIHdpdGhvdXQgYSBzaW1wbGVcbi8vIGZvci1sb29wIGFzIHRoZSBpbmRpdmlkdWFsIGV2ZW50cyB0aGF0IGFyZSBwcm9jZXNzZWQgbWF5XG4vLyBhZGQgbW9yZSBldmVudHMgdG8gdGhlIGJ1ZmZlciAodGhpcyBpcyBuZWVkZWQgZm9yIHRoZSBjb25zZW50IEFQSSlcbmxldCBidWZmZXJlZEV2ZW50cz1zdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWU7d2hpbGUoYnVmZmVyZWRFdmVudHMubGVuZ3RoPjApe2NvbnN0IGJ1ZmZlcmVkRXZlbnQ9YnVmZmVyZWRFdmVudHMuc2hpZnQoKTtzdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWU9YnVmZmVyZWRFdmVudHM7aWYoYnVmZmVyZWRFdmVudCl7Y29uc3QgbWV0aG9kTmFtZT1idWZmZXJlZEV2ZW50WzBdO2lmKGlzRnVuY3Rpb24odGhpc1ttZXRob2ROYW1lXSkpey8vIFNlbmQgYWRkaXRpb25hbCBhcmcgJ3RydWUnIHRvIGluZGljYXRlIHRoYXQgdGhpcyBpcyBhIGJ1ZmZlcmVkIGludm9jYXRpb25cbnRoaXNbbWV0aG9kTmFtZV0oLi4uYnVmZmVyZWRFdmVudC5zbGljZSgxKSx0cnVlKTt9fWJ1ZmZlcmVkRXZlbnRzPXN0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZTt9fS8qKlxuICAgKiBMb2FkIGRldmljZSBtb2RlIGRlc3RpbmF0aW9uc1xuICAgKi9sb2FkRGVzdGluYXRpb25zKCl7Ly8gSWYgdGhlIGludGVncmF0aW9ucyBsb2FkIGlzIGFscmVhZHkgdHJpZ2dlcmVkIG9yIGNvbXBsZXRlZCwgc2tpcCB0aGUgcmVzdCBvZiB0aGUgbG9naWNcbmlmKHN0YXRlLmxpZmVjeWNsZS5zdGF0dXMudmFsdWU9PT0nZGVzdGluYXRpb25zTG9hZGluZyd8fHN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5jbGllbnREZXN0aW5hdGlvbnNSZWFkeS52YWx1ZT09PXRydWUpe3JldHVybjt9Ly8gU2V0IGluIHN0YXRlIHRoZSBkZXNpcmVkIGFjdGl2ZURlc3RpbmF0aW9ucyB0byBpbmplY3QgaW4gRE9NXG50aGlzLnBsdWdpbnNNYW5hZ2VyPy5pbnZva2VTaW5nbGUoJ25hdGl2ZURlc3RpbmF0aW9ucy5zZXRBY3RpdmVEZXN0aW5hdGlvbnMnLHN0YXRlLHRoaXMucGx1Z2luc01hbmFnZXIsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpO2NvbnN0IHRvdGFsRGVzdGluYXRpb25zVG9Mb2FkPXN0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5hY3RpdmVEZXN0aW5hdGlvbnMudmFsdWUubGVuZ3RoO2lmKHRvdGFsRGVzdGluYXRpb25zVG9Mb2FkPT09MCl7bigoKT0+e3N0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5jbGllbnREZXN0aW5hdGlvbnNSZWFkeS52YWx1ZT10cnVlO3N0YXRlLmxpZmVjeWNsZS5zdGF0dXMudmFsdWU9J2Rlc3RpbmF0aW9uc1JlYWR5Jzt9KTtyZXR1cm47fS8vIFN0YXJ0IGxvYWRpbmcgbmF0aXZlIGludGVncmF0aW9uIHNjcmlwdHMgYW5kIGNyZWF0ZSBpbnN0YW5jZXNcbnN0YXRlLmxpZmVjeWNsZS5zdGF0dXMudmFsdWU9J2Rlc3RpbmF0aW9uc0xvYWRpbmcnO3RoaXMucGx1Z2luc01hbmFnZXI/Lmludm9rZVNpbmdsZSgnbmF0aXZlRGVzdGluYXRpb25zLmxvYWQnLHN0YXRlLHRoaXMuZXh0ZXJuYWxTcmNMb2FkZXIsdGhpcy5lcnJvckhhbmRsZXIsdGhpcy5sb2dnZXIpOy8vIFByb2dyZXNzIHRvIG5leHQgbGlmZWN5Y2xlIHBoYXNlIGlmIGFsbCBuYXRpdmUgZGVzdGluYXRpb25zIGFyZSBpbml0aWFsaXplZCBvciBmYWlsZWRcbmooKCk9Pntjb25zdCBhcmVBbGxEZXN0aW5hdGlvbnNSZWFkeT1zdGF0ZS5uYXRpdmVEZXN0aW5hdGlvbnMuaW5pdGlhbGl6ZWREZXN0aW5hdGlvbnMudmFsdWUubGVuZ3RoK3N0YXRlLm5hdGl2ZURlc3RpbmF0aW9ucy5mYWlsZWREZXN0aW5hdGlvbnMudmFsdWUubGVuZ3RoPT09dG90YWxEZXN0aW5hdGlvbnNUb0xvYWQ7aWYoYXJlQWxsRGVzdGluYXRpb25zUmVhZHkpe24oKCk9PntzdGF0ZS5saWZlY3ljbGUuc3RhdHVzLnZhbHVlPSdkZXN0aW5hdGlvbnNSZWFkeSc7c3RhdGUubmF0aXZlRGVzdGluYXRpb25zLmNsaWVudERlc3RpbmF0aW9uc1JlYWR5LnZhbHVlPXRydWU7fSk7fX0pO30vKipcbiAgICogTW92ZSB0byB0aGUgcmVhZHkgc3RhdGVcbiAgICovLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbm9uRGVzdGluYXRpb25zUmVhZHkoKXsvLyBNYXkgYmUgZG8gYW55IGRlc3RpbmF0aW9uIHNwZWNpZmljIGFjdGlvbnMgaGVyZVxuLy8gTWFyayB0aGUgcmVhZHkgc3RhdHVzIGlmIG5vdCBhbHJlYWR5IGRvbmVcbmlmKHN0YXRlLmxpZmVjeWNsZS5zdGF0dXMudmFsdWUhPT0ncmVhZHknKXtuKCgpPT57c3RhdGUubGlmZWN5Y2xlLnN0YXR1cy52YWx1ZT0ncmVhZHknO30pO319Ly8gRW5kIGxpZmVjeWNsZSBtZXRob2RzXG4vLyBTdGFydCBjb25zdW1lciBleHBvc2VkIG1ldGhvZHNcbnJlYWR5KGNhbGxiYWNrLGlzQnVmZmVyZWRJbnZvY2F0aW9uPWZhbHNlKXtjb25zdCB0eXBlPSdyZWFkeSc7aWYoIXN0YXRlLmxpZmVjeWNsZS5sb2FkZWQudmFsdWUpe3N0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZT1bLi4uc3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlLFt0eXBlLGNhbGxiYWNrXV07cmV0dXJuO310aGlzLmVycm9ySGFuZGxlci5sZWF2ZUJyZWFkY3J1bWIoYE5ldyAke3R5cGV9IGludm9jYXRpb25gKTtpZighaXNGdW5jdGlvbihjYWxsYmFjaykpe3RoaXMubG9nZ2VyLmVycm9yKElOVkFMSURfQ0FMTEJBQ0tfRk5fRVJST1IoUkVBRFlfQVBJKSk7cmV0dXJuO30vKipcbiAgICAgKiBJZiBkZXN0aW5
1hdGlvbnMgYXJlIGxvYWRlZCBvciBubyBpbnRlZ3JhdGlvbiBpcyBhdmFpbGFibGUgZm9yIGxvYWRpbmdcbiAgICAgKiBleGVjdXRlIHRoZSBjYWxsYmFjayBpbW1lZGlhdGVseSBlbHNlIHB1c2ggdGhlIGNhbGxiYWNrcyB0byBhIHF1ZXVlIHRoYXRcbiAgICAgKiB3aWxsIGJlIGV4ZWN1dGVkIGFmdGVyIGxvYWRpbmcgY29tcGxldGVzXG4gICAgICovaWYoc3RhdGUubGlmZWN5Y2xlLnN0YXR1cy52YWx1ZT09PSdyZWFkeUV4ZWN1dGVkJyl7c2FmZWx5SW52b2tlQ2FsbGJhY2soY2FsbGJhY2ssW10sUkVBRFlfQVBJLHRoaXMubG9nZ2VyKTt9ZWxzZSB7c3RhdGUuZXZlbnRCdWZmZXIucmVhZHlDYWxsYmFja3NBcnJheS52YWx1ZT1bLi4uc3RhdGUuZXZlbnRCdWZmZXIucmVhZHlDYWxsYmFja3NBcnJheS52YWx1ZSxjYWxsYmFja107fX1wYWdlKHBheWxvYWQsaXNCdWZmZXJlZEludm9jYXRpb249ZmFsc2Upe2NvbnN0IHR5cGU9J3BhZ2UnO2lmKCFzdGF0ZS5saWZlY3ljbGUubG9hZGVkLnZhbHVlKXtzdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWU9Wy4uLnN0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZSxbdHlwZSxwYXlsb2FkXV07cmV0dXJuO310aGlzLmVycm9ySGFuZGxlci5sZWF2ZUJyZWFkY3J1bWIoYE5ldyAke3R5cGV9IGV2ZW50YCk7c3RhdGUubWV0cmljcy50cmlnZ2VyZWQudmFsdWUrPTE7dGhpcy5ldmVudE1hbmFnZXI/LmFkZEV2ZW50KHt0eXBlOidwYWdlJyxjYXRlZ29yeTpwYXlsb2FkLmNhdGVnb3J5LG5hbWU6cGF5bG9hZC5uYW1lLHByb3BlcnRpZXM6cGF5bG9hZC5wcm9wZXJ0aWVzLG9wdGlvbnM6cGF5bG9hZC5vcHRpb25zLGNhbGxiYWNrOnBheWxvYWQuY2FsbGJhY2t9KTsvLyBUT0RPOiBNYXliZSB3ZSBzaG91bGQgYWx0ZXIgdGhlIGJlaGF2aW9yIHRvIHNlbmQgdGhlIGFkLWJsb2NrIHBhZ2UgZXZlbnQgZXZlbiBpZiB0aGUgU0RLIGlzIHN0aWxsIGxvYWRlZC4gSXQnbGwgYmUgcHVzaGVkIGludG8gdGhlIHRvIGJlIHByb2Nlc3NlZCBxdWV1ZS5cbi8vIFNlbmQgYXV0b21hdGljIGFkIGJsb2NrZWQgcGFnZSBldmVudCBpZiBhZC1ibG9ja2VycyBhcmUgZGV0ZWN0ZWQgb24gdGhlIHBhZ2Vcbi8vIENoZWNrIHBhZ2UgY2F0ZWdvcnkgdG8gYXZvaWQgaW5maW5pdGUgbG9vcFxuaWYoc3RhdGUuY2FwYWJpbGl0aWVzLmlzQWRCbG9ja2VkLnZhbHVlPT09dHJ1ZSYmcGF5bG9hZC5jYXRlZ29yeSE9PUFEQkxPQ0tfUEFHRV9DQVRFR09SWSl7dGhpcy5wYWdlKHBhZ2VBcmd1bWVudHNUb0NhbGxPcHRpb25zKEFEQkxPQ0tfUEFHRV9DQVRFR09SWSxBREJMT0NLX1BBR0VfTkFNRSx7Ly8gJ3RpdGxlJyBpcyBpbnRlbnRpb25hbGx5IG9taXR0ZWQgYXMgaXQgZG9lcyBub3QgbWFrZSBzZW5zZVxuLy8gaW4gdjMgaW1wbGVtZW50YXRpb25cbnBhdGg6QURCTE9DS19QQUdFX1BBVEh9LHN0YXRlLmxvYWRPcHRpb25zLnZhbHVlLnNlbmRBZGJsb2NrUGFnZU9wdGlvbnMpKTt9fXRyYWNrKHBheWxvYWQsaXNCdWZmZXJlZEludm9jYXRpb249ZmFsc2Upe2NvbnN0IHR5cGU9J3RyYWNrJztpZighc3RhdGUubGlmZWN5Y2xlLmxvYWRlZC52YWx1ZSl7c3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlPVsuLi5zdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWUsW3R5cGUscGF5bG9hZF1dO3JldHVybjt9dGhpcy5lcnJvckhhbmRsZXIubGVhdmVCcmVhZGNydW1iKGBOZXcgJHt0eXBlfSBldmVudCAtICR7cGF5bG9hZC5uYW1lfWApO3N0YXRlLm1ldHJpY3MudHJpZ2dlcmVkLnZhbHVlKz0xO3RoaXMuZXZlbnRNYW5hZ2VyPy5hZGRFdmVudCh7dHlwZSxuYW1lOnBheWxvYWQubmFtZXx8dW5kZWZpbmVkLHByb3BlcnRpZXM6cGF5bG9hZC5wcm9wZXJ0aWVzLG9wdGlvbnM6cGF5bG9hZC5vcHRpb25zLGNhbGxiYWNrOnBheWxvYWQuY2FsbGJhY2t9KTt9aWRlbnRpZnkocGF5bG9hZCxpc0J1ZmZlcmVkSW52b2NhdGlvbj1mYWxzZSl7Y29uc3QgdHlwZT0naWRlbnRpZnknO2lmKCFzdGF0ZS5saWZlY3ljbGUubG9hZGVkLnZhbHVlKXtzdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWU9Wy4uLnN0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZSxbdHlwZSxwYXlsb2FkXV07cmV0dXJuO310aGlzLmVycm9ySGFuZGxlci5sZWF2ZUJyZWFkY3J1bWIoYE5ldyAke3R5cGV9IGV2ZW50YCk7c3RhdGUubWV0cmljcy50cmlnZ2VyZWQudmFsdWUrPTE7Y29uc3Qgc2hvdWxkUmVzZXRTZXNzaW9uPUJvb2xlYW4ocGF5bG9hZC51c2VySWQmJnN0YXRlLnNlc3Npb24udXNlcklkLnZhbHVlJiZwYXlsb2FkLnVzZXJJZCE9PXN0YXRlLnNlc3Npb24udXNlcklkLnZhbHVlKTtpZihzaG91bGRSZXNldFNlc3Npb24pe3RoaXMucmVzZXQoKTt9Ly8gYG51bGxgIHZhbHVlIGluZGljYXRlcyB0aGF0IHByZXZpb3VzIHVzZXIgSUQgbmVlZHMgdG8gYmUgcmV0YWluZWRcbmlmKCFpc051bGwocGF5bG9hZC51c2VySWQpKXt0aGlzLnVzZXJTZXNzaW9uTWFuYWdlcj8uc2V0VXNlcklkKHBheWxvYWQudXNlcklkKTt9dGhpcy51c2VyU2Vzc2lvbk1hbmFnZXI/LnNldFVzZXJUcmFpdHMocGF5bG9hZC50cmFpdHMpO3RoaXMuZXZlbnRNYW5hZ2VyPy5hZGRFdmVudCh7dHlwZSx1c2VySWQ6cGF5bG9hZC51c2VySWQsdHJhaXRzOnBheWxvYWQudHJhaXRzLG9wdGlvbnM6cGF5bG9hZC5vcHRpb25zLGNhbGxiYWNrOnBheWxvYWQuY2FsbGJhY2t9KTt9YWxpYXMocGF5bG9hZCxpc0J1ZmZlcmVkSW52b2NhdGlvbj1mYWxzZSl7Y29uc3QgdHlwZT0nYWxpYXMnO2lmKCFzdGF0ZS5saWZlY3ljbGUubG9hZGVkLnZhbHVlKXtzdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWU9Wy4uLnN0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZSxbdHlwZSxwYXlsb2FkXV07cmV0dXJuO310aGlzLmVycm9ySGFuZGxlci5sZWF2ZUJyZWFkY3J1bWIoYE5ldyAke3R5cGV9IGV2ZW50YCk7c3RhdGUubWV0cmljcy50cmlnZ2VyZWQudmFsdWUrPTE7Y29uc3QgcHJldmlvdXNJZD1wYXlsb2FkLmZyb20/Pyh0aGlzLmdldFVzZXJJZCgpfHx0aGlzLnVzZXJTZXNzaW9uTWFuYWdlcj8uZ2V0QW5vbnltb3VzSWQoKSk7dGhpcy5ldmVudE1hbmFnZXI/LmFkZEV2ZW50KHt0eXBlLHRvOnBheWxvYWQudG8sZnJvbTpwcmV2aW91c0lkLG9wdGlvbnM6cGF5bG9hZC5vcHRpb25zLGNhbGxiYWNrOnBheWxvYWQuY2FsbGJhY2t9KTt9Z3JvdXAocGF5bG9hZCxpc0J1ZmZlcmVkSW52b2NhdGlvbj1mYWxzZSl7Y29uc3QgdHlwZT0nZ3JvdXAnO2lmKCFzdGF0ZS5saWZlY3ljbGUubG9hZGVkLn
1ZhbHVlKXtzdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWU9Wy4uLnN0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZSxbdHlwZSxwYXlsb2FkXV07cmV0dXJuO310aGlzLmVycm9ySGFuZGxlci5sZWF2ZUJyZWFkY3J1bWIoYE5ldyAke3R5cGV9IGV2ZW50YCk7c3RhdGUubWV0cmljcy50cmlnZ2VyZWQudmFsdWUrPTE7Ly8gYG51bGxgIHZhbHVlIGluZGljYXRlcyB0aGF0IHByZXZpb3VzIGdyb3VwIElEIG5lZWRzIHRvIGJlIHJldGFpbmVkXG5pZighaXNOdWxsKHBheWxvYWQuZ3JvdXBJZCkpe3RoaXMudXNlclNlc3Npb25NYW5hZ2VyPy5zZXRHcm91cElkKHBheWxvYWQuZ3JvdXBJZCk7fXRoaXMudXNlclNlc3Npb25NYW5hZ2VyPy5zZXRHcm91cFRyYWl0cyhwYXlsb2FkLnRyYWl0cyk7dGhpcy5ldmVudE1hbmFnZXI/LmFkZEV2ZW50KHt0eXBlLGdyb3VwSWQ6cGF5bG9hZC5ncm91cElkLHRyYWl0czpwYXlsb2FkLnRyYWl0cyxvcHRpb25zOnBheWxvYWQub3B0aW9ucyxjYWxsYmFjazpwYXlsb2FkLmNhbGxiYWNrfSk7fXJlc2V0KG9wdGlvbnMsaXNCdWZmZXJlZEludm9jYXRpb249ZmFsc2Upe2NvbnN0IHR5cGU9J3Jlc2V0JztpZighc3RhdGUubGlmZWN5Y2xlLmxvYWRlZC52YWx1ZSl7c3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlPVsuLi5zdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWUsW3R5cGUsb3B0aW9uc11dO3JldHVybjt9dGhpcy5lcnJvckhhbmRsZXIubGVhdmVCcmVhZGNydW1iKGBOZXcgJHt0eXBlfSBpbnZvY2F0aW9uYCk7dGhpcy51c2VyU2Vzc2lvbk1hbmFnZXI/LnJlc2V0KG9wdGlvbnMpO31nZXRBbm9ueW1vdXNJZChvcHRpb25zKXtyZXR1cm4gdGhpcy51c2VyU2Vzc2lvbk1hbmFnZXI/LmdldEFub255bW91c0lkKG9wdGlvbnMpO31zZXRBbm9ueW1vdXNJZChhbm9ueW1vdXNJZCxydWRkZXJBbXBMaW5rZXJQYXJhbSxpc0J1ZmZlcmVkSW52b2NhdGlvbj1mYWxzZSl7Y29uc3QgdHlwZT0nc2V0QW5vbnltb3VzSWQnOy8vIEJ1ZmZlcmluZyBpcyBuZWVkZWQgYXMgc2V0dGluZyB0aGUgYW5vbnltb3VzIElEIG1heSByZXF1aXJlIGludm9raW5nIHRoZSBHb29nbGVMaW5rZXIgcGx1Z2luXG5pZighc3RhdGUubGlmZWN5Y2xlLmxvYWRlZC52YWx1ZSl7c3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlPVsuLi5zdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWUsW3R5cGUsYW5vbnltb3VzSWQscnVkZGVyQW1wTGlua2VyUGFyYW1dXTtyZXR1cm47fXRoaXMuZXJyb3JIYW5kbGVyLmxlYXZlQnJlYWRjcnVtYihgTmV3ICR7dHlwZX0gaW52b2NhdGlvbmApO3RoaXMudXNlclNlc3Npb25NYW5hZ2VyPy5zZXRBbm9ueW1vdXNJZChhbm9ueW1vdXNJZCxydWRkZXJBbXBMaW5rZXJQYXJhbSk7fS8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjbGFzcy1tZXRob2RzLXVzZS10aGlzXG5nZXRVc2VySWQoKXtyZXR1cm4gc3RhdGUuc2Vzc2lvbi51c2VySWQudmFsdWU7fS8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjbGFzcy1tZXRob2RzLXVzZS10aGlzXG5nZXRVc2VyVHJhaXRzKCl7cmV0dXJuIHN0YXRlLnNlc3Npb24udXNlclRyYWl0cy52YWx1ZTt9Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbmdldEdyb3VwSWQoKXtyZXR1cm4gc3RhdGUuc2Vzc2lvbi5ncm91cElkLnZhbHVlO30vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY2xhc3MtbWV0aG9kcy11c2UtdGhpc1xuZ2V0R3JvdXBUcmFpdHMoKXtyZXR1cm4gc3RhdGUuc2Vzc2lvbi5ncm91cFRyYWl0cy52YWx1ZTt9c3RhcnRTZXNzaW9uKHNlc3Npb25JZCxpc0J1ZmZlcmVkSW52b2NhdGlvbj1mYWxzZSl7Y29uc3QgdHlwZT0nc3RhcnRTZXNzaW9uJztpZighc3RhdGUubGlmZWN5Y2xlLmxvYWRlZC52YWx1ZSl7c3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlPVsuLi5zdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWUsW3R5cGUsc2Vzc2lvbklkXV07cmV0dXJuO310aGlzLmVycm9ySGFuZGxlci5sZWF2ZUJyZWFkY3J1bWIoYE5ldyAke3R5cGV9IGludm9jYXRpb25gKTt0aGlzLnVzZXJTZXNzaW9uTWFuYWdlcj8uc3RhcnQoc2Vzc2lvbklkKTt9ZW5kU2Vzc2lvbihpc0J1ZmZlcmVkSW52b2NhdGlvbj1mYWxzZSl7Y29uc3QgdHlwZT0nZW5kU2Vzc2lvbic7aWYoIXN0YXRlLmxpZmVjeWNsZS5sb2FkZWQudmFsdWUpe3N0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZT1bLi4uc3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlLFt0eXBlXV07cmV0dXJuO310aGlzLmVycm9ySGFuZGxlci5sZWF2ZUJyZWFkY3J1bWIoYE5ldyAke3R5cGV9IGludm9jYXRpb25gKTt0aGlzLnVzZXJTZXNzaW9uTWFuYWdlcj8uZW5kKCk7fS8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjbGFzcy1tZXRob2RzLXVzZS10aGlzXG5nZXRTZXNzaW9uSWQoKXtjb25zdCBzZXNzaW9uSWQ9dGhpcy51c2VyU2Vzc2lvbk1hbmFnZXI/LmdldFNlc3Npb25JZCgpO3JldHVybiBzZXNzaW9uSWQ/P251bGw7fWNvbnNlbnQob3B0aW9ucyxpc0J1ZmZlcmVkSW52b2NhdGlvbj1mYWxzZSl7Y29uc3QgdHlwZT0nY29uc2VudCc7aWYoIXN0YXRlLmxpZmVjeWNsZS5sb2FkZWQudmFsdWUpe3N0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZT1bLi4uc3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlLFt0eXBlLG9wdGlvbnNdXTtyZXR1cm47fXRoaXMuZXJyb3JIYW5kbGVyLmxlYXZlQnJlYWRjcnVtYihgTmV3IGNvbnNlbnQgaW52b2NhdGlvbmApO24oKCk9PntzdGF0ZS5jb25zZW50cy5wcmVDb25zZW50LnZhbHVlPXsuLi5zdGF0ZS5jb25zZW50cy5wcmVDb25zZW50LnZhbHVlLGVuYWJsZWQ6ZmFsc2V9O3N0YXRlLmNvbnNlbnRzLnBvc3RDb25zZW50LnZhbHVlPWdldFZhbGlkUG9zdENvbnNlbnRPcHRpb25zKG9wdGlvbnMpO2NvbnN0e2luaXRpYWxpemVkLGNvbnNlbnRzRGF0YX09Z2V0Q29uc2VudE1hbmFnZW1lbnREYXRhKHN0YXRlLmNvbnNlbnRzLnBvc3RDb25zZW50LnZhbHVlLmNvbnNlbnRNYW5hZ2VtZW50LHRoaXMubG9nZ2VyKTtzdGF0ZS5jb25zZW50cy5pbml0aWFsaXplZC52YWx1ZT1pbml0aWFsaXplZDtzdGF0ZS5jb25zZW50cy5kYXRhLnZhbHVlPWNvbnNlbnRzRGF0YTt9KTsvLyBVcGRhdGUgY29uc2VudHMgZGF0YSBpbiBzdGF0ZVxuaWYoc3RhdGUuY29uc2VudHMuZW5hYmxlZC52YWx1ZSYmIXN0YXRlLmNvbnNlbnRzLmluaXRpYWxpemVkLnZhbHVlKXt0aGlzLnBsdWdpbnNNYW5hZ2VyPy5pbnZva2VTaW5nbGUoYGNvbnNlbnRNYW5hZ2VyLnVwZGF0ZUNvbnNlbnRzSW5mb2Asc3RhdGUsdGhpcy5zdG9yZU1hbmFnZXIsdGhpcy5sb2dnZXIpO30vLyBSZS1pbml0IHN0b3JlIG1hbmFnZXJcbnRoaXMuc3RvcmVNYW5hZ2VyPy5pbml0aWFsaXplU3RvcmFnZVN0YXRlKCk7Ly8gUmUtaW5pdCB1c2VyIHNlc3Npb24gbWFuYWdlclxudGhpcy51c2VyU2Vzc2lvbk1hbmFnZXI/LnN5bmNTdG9yYWdlRGF0YVRvU3RhdGUoKTsvLyBSZXN1bWUgZXZlbnQgbWFuYWdlciB0byBwcm9jZXNzIHRoZSBldmVudHMgdG8gZGVzdGluYXRpb25zXG50aGlzLmV2ZW50TWFuYWdlcj8ucmVzdW1lKCk7dGhpcy5sb2FkRGVzdGluYXRpb25zKCk7dGhpcy5zZW5kVHJhY2tpbmdFdmVudHMoaXNCdWZmZXJlZEludm9jYXRpb24pO31zZW5kVHJhY2tpbmdFdmVudHMoaXNCdWZmZXJlZEludm9jYXRpb24pey8vIElmIGlzQnVmZmVyZWRJbnZvY2F0aW9uIGlzIHRydWUsIHRoZW4gdGhlIHRyYWNraW5nIGV2ZW50cyB3aWxsIGJlIGFkZGVkIHRvIHRoZSBlbmQgb2YgdGhlXG4vLyBldmVudHMgYnVmZmVyIGFycmF5IHNvIHRoYXQgYW55IG90aGVyIHByZWxvYWQgZXZlbnRzIChtYWlubHkgZnJvbSBxdWVyeSBzdHJpbmcgQVBJKSB3aWxsIGJlIHByb2Nlc3NlZCBmaXJzdC5cbmlmKHN0YXRlLmNvbnNlbnRzLnBvc3RDb25zZW50LnZhbHVlLnRyYWNrQ29uc2VudCl7Y29uc3QgdHJhY2tPcHRpb25zPXRyYWNrQXJndW1lbnRzVG9DYWxsT3B0aW9ucyhDT05TRU5UX1RSQUNLX0VWRU5UX05BTUUpO2lmKGlzQnVmZmVyZWRJbnZvY2F0aW9uKXtzdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWU9Wy4uLnN0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZSxbJ3RyYWNrJyx0cmFja09wdGlvbnNdXTt9ZWxzZSB7dGhpcy50cmFjayh0cmFja09wdGlvbnMpO319aWYoc3RhdGUuY29uc2VudHMucG9zdENvbnNlbnQudmFsdWUuc2VuZFBhZ2VFdmVudCl7Y29uc3QgcGFnZU9wdGlvbnM9cGFnZUFyZ3VtZW50c1RvQ2FsbE9wdGlvbnMoKTtpZihpc0J1ZmZlcmVkSW52b2NhdGlvbil7c3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlPVsuLi5zdGF0ZS5ldmVudEJ1ZmZlci50b0JlUHJvY2Vzc2VkQXJyYXkudmFsdWUsWydwYWdlJyxwYWdlT3B0aW9uc11dO31lbHNlIHt0aGlzLnBhZ2UocGFnZU9wdGlvbnMpO319fXNldEF1dGhUb2tlbih0b2tlbil7dGhpcy51c2VyU2Vzc2lvbk1hbmFnZXI/LnNldEF1dGhUb2tlbih0b2tlbik7fS8qKlxuICAgKiBBZGQgYSBjdXN0b20gaW50ZWdyYXRpb24gZm9yIGEgY3VzdG9tIGRlc3RpbmF0aW9uLlxuICAgKiBAcGFyYW0gZGVzdGluYXRpb25JZCAtIFRoZSBJRCBvZiB0aGUgY3VzdG9tIGRlc3RpbmF0aW9uIGZyb20gdGhlIFJ1ZGRlclN0YWNrIGRhc2hib2FyZC5cbiAgICogQHBhcmFtIGludGVncmF0aW9uIC0gVGhlIGN1c3RvbSBpbnRlZ3JhdGlvbiBvYmplY3QuXG4gICAqIEBwYXJhbSBpc0J1ZmZlcmVkSW52b2NhdGlvbiAtIFdoZXRoZXIgdGhlIGludm9jYXRpb24gaXMgYnVmZmVyZWQuXG4gICAqL2FkZEN1c3RvbUludGVncmF0aW9uKGRlc3RpbmF0aW9uSWQsaW50ZWdyYXRpb24saXNCdWZmZXJlZEludm9jYXRpb249ZmFsc2Upe2NvbnN0IHR5cGU9J2FkZEN1c3RvbUludGVncmF0aW9uJztpZihpc0J1ZmZlcmVkSW52b2NhdGlvbil7dGhpcy5lcnJvckhhbmRsZXIubGVhdmVCcmVhZGNydW1iKGBOZXcgJHt0eXBlfSBpbnZvY2F0aW9uYCk7dGhpcy5wbHVnaW5zTWFuYWdlcj8uaW52b2tlU2luZ2xlKCduYXRpdmVEZXN0aW5
1hdGlvbnMuYWRkQ3VzdG9tSW50ZWdyYXRpb24nLGRlc3RpbmF0aW9uSWQsaW50ZWdyYXRpb24sc3RhdGUsdGhpcy5sb2dnZXIpO31lbHNlIHtpZihzdGF0ZS5saWZlY3ljbGUubG9hZGVkLnZhbHVlKXt0aGlzLmxvZ2dlci5lcnJvcihDVVNUT01fSU5URUdSQVRJT05fQ0FOTk9UX0JFX0FEREVEX0VSUk9SKEFOQUxZVElDU19DT1JFLGRlc3RpbmF0aW9uSWQpKTtyZXR1cm47fXN0YXRlLmV2ZW50QnVmZmVyLnRvQmVQcm9jZXNzZWRBcnJheS52YWx1ZT1bLi4uc3RhdGUuZXZlbnRCdWZmZXIudG9CZVByb2Nlc3NlZEFycmF5LnZhbHVlLFt0eXBlLGRlc3RpbmF0aW9uSWQsaW50ZWdyYXRpb25dXTt9fS8vIEVuZCBjb25zdW1lciBleHBvc2VkIG1ldGhvZHNcbn1cblxuLypcbiAqIFJ1ZGRlckFuYWx5dGljcyBmYWNhZGUgc2luZ2xldG9uIHRoYXQgaXMgZXhwb3NlZCBhcyBnbG9iYWwgb2JqZWN0IGFuZCB3aWxsOlxuICogZXhwb3NlIG92ZXJsb2FkZWQgbWV0aG9kc1xuICogaGFuZGxlIG11bHRpcGxlIEFuYWx5dGljcyBpbnN0YW5jZXNcbiAqIGNvbnN1bWUgU0RLIHByZWxvYWQgZXZlbnQgYnVmZmVyXG4gKi9jbGFzcyBSdWRkZXJBbmFseXRpY3N7Ly8gU1RBUlQtTk8tU09OQVItU0NBTlxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHNvbmFyanMvcHVibGljLXN0YXRpYy1yZWFkb25seVxuc3RhdGljIGdsb2JhbFNpbmdsZXRvbj1udWxsOy8vIEVORC1OTy1TT05BUi1TQ0FOXG5hbmFseXRpY3NJbnN0YW5jZXM9e307ZGVmYXVsdEFuYWx5dGljc0tleT0nJztsb2dnZXI9ZGVmYXVsdExvZ2dlcjsvLyBTaW5nbGV0b24gd2l0aCBjb25zdHJ1Y3RvciBiaW5kIG1ldGhvZHNcbmNvbnN0cnVjdG9yKCl7dHJ5e2lmKFJ1ZGRlckFuYWx5dGljcy5nbG9iYWxTaW5nbGV0b24pey8vIFNUQVJULU5PLVNPTkFSLVNDQU5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zdHJ1Y3Rvci1yZXR1cm5cbnJldHVybiBSdWRkZXJBbmFseXRpY3MuZ2xvYmFsU2luZ2xldG9uOy8vIEVORC1OTy1TT05BUi1TQ0FOXG59UnVkZGVyQW5hbHl0aWNzLmluaXRpYWxpemVHbG9iYWxSZXNvdXJjZXMoKTt0aGlzLnNldERlZmF1bHRJbnN0YW5jZUtleT10aGlzLnNldERlZmF1bHRJbnN0YW5jZUtleS5iaW5kKHRoaXMpO3RoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2U9dGhpcy5nZXRBbmFseXRpY3NJbnN0YW5jZS5iaW5kKHRoaXMpO3RoaXMubG9hZD10aGlzLmxvYWQuYmluZCh0aGlzKTt0aGlzLnJlYWR5PXRoaXMucmVhZHkuYmluZCh0aGlzKTt0aGlzLnRyaWdnZXJCdWZmZXJlZExvYWRFdmVudD10aGlzLnRyaWdnZXJCdWZmZXJlZExvYWRFdmVudC5iaW5kKHRoaXMpO3RoaXMucGFnZT10aGlzLnBhZ2UuYmluZCh0aGlzKTt0aGlzLnRyYWNrPXRoaXMudHJhY2suYmluZCh0aGlzKTt0aGlzLmlkZW50aWZ5PXRoaXMuaWRlbnRpZnkuYmluZCh0aGlzKTt0aGlzLmFsaWFzPXRoaXMuYWxpYXMuYmluZCh0aGlzKTt0aGlzLmdyb3VwPXRoaXMuZ3JvdXAuYmluZCh0aGlzKTt0aGlzLnJlc2V0PXRoaXMucmVzZXQuYmluZCh0aGlzKTt0aGlzLmdldEFub255bW91c0lkPXRoaXMuZ2V0QW5vbnltb3VzSWQuYmluZCh0aGlzKTt0aGlzLnNldEFub255bW91c0lkPXRoaXMuc2V0QW5vbnltb3VzSWQuYmluZCh0aGlzKTt0aGlzLmdldFVzZXJJZD10aGlzLmdldFVzZXJJZC5iaW5kKHRoaXMpO3RoaXMuZ2V0VXNlclRyYWl0cz10aGlzLmdldFVzZXJUcmFpdHMuYmluZCh0aGlzKTt0aGlzLmdldEdyb3VwSWQ9dGhpcy5nZXRHcm91cElkLmJpbmQodGhpcyk7dGhpcy5nZXRHcm91cFRyYWl0cz10aGlzLmdldEdyb3VwVHJhaXRzLmJpbmQodGhpcyk7dGhpcy5zdGFydFNlc3Npb249dGhpcy5zdGFydFNlc3Npb24uYmluZCh0aGlzKTt0aGlzLmVuZFNlc3Npb249dGhpcy5lbmRTZXNzaW9uLmJpbmQodGhpcyk7dGhpcy5nZXRTZXNzaW9uSWQ9dGhpcy5nZXRTZXNzaW9uSWQuYmluZCh0aGlzKTt0aGlzLnNldEF1dGhUb2tlbj10aGlzLnNldEF1dGhUb2tlbi5iaW5kKHRoaXMpO3RoaXMuY29uc2VudD10aGlzLmNvbnNlbnQuYmluZCh0aGlzKTt0aGlzLmFkZEN1c3RvbUludGVncmF0aW9uPXRoaXMuYWRkQ3VzdG9tSW50ZWdyYXRpb24uYmluZCh0aGlzKTt0aGlzLmNyZWF0ZVNhZmVBbmFseXRpY3NJbnN0YW5jZSgpO1J1ZGRlckFuYWx5dGljcy5nbG9iYWxTaW5nbGV0b249dGhpcztzdGF0ZS5hdXRvVHJhY2sucGFnZUxpZmVjeWNsZS5wYWdlVmlld0lkLnZhbHVlPWdlbmVyYXRlVVVJRCgpO3N0YXRlLmF1dG9UcmFjay5wYWdlTGlmZWN5Y2xlLnBhZ2VMb2FkZWRUaW1lc3RhbXAudmFsdWU9RGF0ZS5ub3coKTsvLyBzdGFydCBsb2FkaW5nIGlmIGEgbG9hZCBldmVudCB3YXMgYnVmZmVyZWQgb3Igd2FpdCBmb3IgZXhwbGljaXQgbG9hZCBjYWxsXG50aGlzLnRyaWdnZXJCdWZmZXJlZExvYWRFdmVudCgpOy8vIEFzc2lnbiB0byBnbG9iYWwgXCJydWRkZXJhbmFseXRpY3NcIiBvYmplY3QgYWZ0ZXIgcHJvY2Vzc2luZyB0aGUgcHJlbG9hZCBidWZmZXIgKGlmIGFueSBleGlzdHMpXG4vLyBmb3IgQ0ROIGJ1bmRsaW5nIElJRkUgZXhwb3J0cyBjb3ZlcnMgdGhpcyBidXQgZm9yIG5wbSBFU00gYW5kIENKUyBidW5kbGluZyBoYXMgdG8gYmUgZG9uZSBleHBsaWNpdGx5XG5nbG9iYWxUaGlzLnJ1ZGRlcmFuYWx5dGljcz10aGlzO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTt9fS8qKlxuICAgKiBDcmVhdGUgYW4gaW5zdGFuY2Ugb2YgdGhlIGN1cnJlbnQgaW5zdGFuY2UgdGhhdCBjYW4gYmUgdXNlZFxuICAgKiB0byBjYWxsIGEgc3Vic2V0IG9mIG1ldGhvZHMgb2YgdGhlIGN1cnJlbnQgaW5zdGFuY2UuXG4gICAqIEl0IGlzIHR5cGljYWxseSB1c2VkIHRvIGV4cG9zZSB0aGUgYW5hbHl0aWNzIGluc3RhbmNlIHRvIHRoZSBpbnRlZ3JhdGlvbnMgKHN0YW5kYXJkIGFuZCBjdXN0b20pXG4gICAqL2NyZWF0ZVNhZmVBbmFseXRpY3NJbnN0YW5jZSgpe3N0YXRlLmxpZmVjeWNsZS5zYWZlQW5hbHl0aWNzSW5zdGFuY2UudmFsdWU9e3BhZ2U6dGhpcy5wYWdlLmJpbmQodGhpcyksdHJhY2s6dGhpcy50cmFjay5iaW5kKHRoaXMpLGlkZW50aWZ5OnR
1oaXMuaWRlbnRpZnkuYmluZCh0aGlzKSxhbGlhczp0aGlzLmFsaWFzLmJpbmQodGhpcyksZ3JvdXA6dGhpcy5ncm91cC5iaW5kKHRoaXMpLGdldEFub255bW91c0lkOnRoaXMuZ2V0QW5vbnltb3VzSWQuYmluZCh0aGlzKSxnZXRVc2VySWQ6dGhpcy5nZXRVc2VySWQuYmluZCh0aGlzKSxnZXRVc2VyVHJhaXRzOnRoaXMuZ2V0VXNlclRyYWl0cy5iaW5kKHRoaXMpLGdldEdyb3VwSWQ6dGhpcy5nZXRHcm91cElkLmJpbmQodGhpcyksZ2V0R3JvdXBUcmFpdHM6dGhpcy5nZXRHcm91cFRyYWl0cy5iaW5kKHRoaXMpLGdldFNlc3Npb25JZDp0aGlzLmdldFNlc3Npb25JZC5iaW5kKHRoaXMpfTt9c3RhdGljIGluaXRpYWxpemVHbG9iYWxSZXNvdXJjZXMoKXsvLyBXZSBuZWVkIHRvIGluaXRpYWxpemUgdGhlIGVycm9yIGhhbmRsZXIgZmlyc3QgdG8gY2F0Y2ggYW55IHVuaGFuZGxlZCBlcnJvcnMgb2NjdXJyaW5nIGluIHRoaXMgbW9kdWxlIGFzIHdlbGxcbmRlZmF1bHRFcnJvckhhbmRsZXIuaW5pdCgpOy8vIEluaXRpYWxpemUgdGhlIHN0b3JhZ2UgZW5naW5lcyB3aXRoIGRlZmF1bHQgb3B0aW9uc1xuZGVmYXVsdENvb2tpZVN0b3JhZ2UuY29uZmlndXJlKCk7ZGVmYXVsdExvY2FsU3RvcmFnZS5jb25maWd1cmUoKTtkZWZhdWx0U2Vzc2lvblN0b3JhZ2UuY29uZmlndXJlKCk7ZGVmYXVsdEluTWVtb3J5U3RvcmFnZS5jb25maWd1cmUoKTt9LyoqXG4gICAqIFNldCBpbnN0YW5jZSB0byB1c2UgaWYgbm8gc3BlY2lmaWMgd3JpdGVLZXkgaXMgcHJvdmlkZWQgaW4gbWV0aG9kc1xuICAgKiBhdXRvbWF0aWNhbGx5IGZvciB0aGUgZmlyc3QgY3JlYXRlZCBpbnN0YW5jZVxuICAgKiBUT0RPOiB0byBzdXBwb3J0IG11bHRpcGxlIGFuYWx5dGljcyBpbnN0YW5jZXMgaW4gdGhlIG5lYXIgZnV0dXJlXG4gICAqL3NldERlZmF1bHRJbnN0YW5jZUtleSh3cml0ZUtleSl7Ly8gSU1QOiBBZGQgdHJ5LWNhdGNoIGJsb2NrIHRvIGhhbmRsZSBhbnkgdW5oYW5kbGVkIGVycm9yc1xuLy8gc2ltaWxhciB0byBvdGhlciBwdWJsaWMgbWV0aG9kc1xuLy8gaWYgdGhlIGltcGxlbWVudGF0aW9uIG9mIHRoaXMgbWV0aG9kIGdvZXMgYmV5b25kXG4vLyB0aGlzIHNpbXBsZSBpbXBsZW1lbnRhdGlvblxuaWYoaXNTdHJpbmcod3JpdGVLZXkpJiZ3cml0ZUtleSl7dGhpcy5kZWZhdWx0QW5hbHl0aWNzS2V5PXdyaXRlS2V5O319LyoqXG4gICAqIFJldHJpZXZlIGFuIGV4aXN0aW5nIGFuYWx5dGljcyBpbnN0YW5jZVxuICAgKi9nZXRBbmFseXRpY3NJbnN0YW5jZSh3cml0ZUtleSl7dHJ5e2xldCBpbnN0YW5jZUlkPXdyaXRlS2V5O2lmKCFpc1N0cmluZyhpbnN0YW5jZUlkKXx8IWluc3RhbmNlSWQpe2luc3RhbmNlSWQ9dGhpcy5kZWZhdWx0QW5hbHl0aWNzS2V5O31jb25zdCBhbmFseXRpY3NJbnN0YW5jZUV4aXN0cz1Cb29sZWFuKHRoaXMuYW5hbHl0aWNzSW5zdGFuY2VzW2luc3RhbmNlSWRdKTtpZighYW5hbHl0aWNzSW5zdGFuY2VFeGlzdHMpe3RoaXMuYW5hbHl0aWNzSW5zdGFuY2VzW2luc3RhbmNlSWRdPW5ldyBBbmFseXRpY3MoKTt9cmV0dXJuIHRoaXMuYW5hbHl0aWNzSW5zdGFuY2VzW2luc3RhbmNlSWRdO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTtyZXR1cm4gdW5kZWZpbmVkO319LyoqXG4gICAqIExvYWRzIHRoZSBTREtcbiAgICogQHBhcmFtIHdyaXRlS2V5IFNvdXJjZSB3cml0ZSBrZXlcbiAgICogQHBhcmFtIGRhdGFQbGFuZVVybCBEYXRhIHBsYW5lIFVSTFxuICAgKiBAcGFyYW0gbG9hZE9wdGlvbnMgQWRkaXRpb25hbCBvcHRpb25zIGZvciBsb2FkaW5nIHRoZSBTREtcbiAgICogQHJldHVybnMgbm9uZVxuICAgKi9sb2FkKHdyaXRlS2V5LGRhdGFQbGFuZVVybCxsb2FkT3B0aW9ucyl7dHJ5e2lmKHRoaXMuYW5hbHl0aWNzSW5zdGFuY2VzW3dyaXRlS2V5XSl7cmV0dXJuO310aGlzLnNldERlZmF1bHRJbnN0YW5jZUtleSh3cml0ZUtleSk7Ly8gVHJhY2sgcGFnZSBsb2FkZWQgbGlmZWN5Y2xlIGV2ZW50IGlmIGVuYWJsZWRcbnRoaXMudHJhY2tQYWdlTGlmZWN5Y2xlRXZlbnRzKGxvYWRPcHRpb25zKTsvLyBHZXQgdGhlIHByZWxvYWRlZCBldmVudHMgYXJyYXkgZnJvbSBnbG9iYWwgYnVmZmVyIGluc3RlYWQgb2Ygd2luZG93LnJ1ZGRlcmFuYWx5dGljc1xuLy8gYXMgdGhlIGNvbnN0cnVjdG9yIG11c3QgaGF2ZSBhbHJlYWR5IHB1c2hlZCB0aGUgZXZlbnRzIHRvIHRoZSBnbG9iYWwgYnVmZmVyXG5jb25zdCBwcmVsb2FkZWRFdmVudHNBcnJheT1nZXRFeHBvc2VkR2xvYmFsKEdMT0JBTF9QUkVMT0FEX0JVRkZFUik7Ly8gVGhlIGFycmF5IHdpbGwgYmUgbXV0YXRlZCBpbiB0aGUgYmVsb3cgbWV0aG9kXG5wcm9tb3RlUHJlbG9hZGVkQ29uc2VudEV2ZW50c1RvVG9wKHByZWxvYWRlZEV2ZW50c0FycmF5KTtzZXRFeHBvc2VkR2xvYmFsKEdMT0JBTF9QUkVMT0FEX0JVRkZFUixjbG9uZShwcmVsb2FkZWRFdmVudHNBcnJheSkpO3RoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2Uod3JpdGVLZXkpPy5sb2FkKHdyaXRlS2V5LGRhdGFQbGFuZVVybCxnZXRTYW5pdGl6ZWRWYWx1ZShsb2FkT3B0aW9ucykpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTt9fS8qKlxuICAgKiBBIGZ1bmN0aW9uIHRvIHRyYWNrIHBhZ2UgbGlmZWN5Y2xlIGV2ZW50cyBsaWtlIHBhZ2UgbG9hZGVkIGFuZCBwYWdlIHVubG9hZGVkXG4gICAqIEBwYXJhbSBsb2FkT3B0aW9uc1xuICAgKiBAcmV0dXJuc1xuICAgKi90cmFja1BhZ2VMaWZlY3ljbGVFdmVudHMobG9hZE9wdGlvbnMpe2NvbnN0e2F1dG9UcmFjayx1c2VCZWFjb259PWxvYWRPcHRpb25zPz97fTtjb25zdHtlbmFibGVkOmF1dG9UcmFja0VuYWJsZWQ9ZmFsc2Usb3B0aW9uczphdXRvVHJhY2tPcHRpb25zPXt9LHBhZ2VMaWZlY3ljbGV9PWF1dG9UcmFjaz8/e307Y29uc3R7ZXZlbnRzPVtQYWdlTGlmZWN5Y2xlRXZlbnRzLlVOTE9BREVEXSxlbmFibGVkOnBhZ2VMaWZlY3ljbGVFbmFibGVkPWF1dG9UcmFja0VuYWJsZWQsb3B0aW9ucz1hdXRvVHJhY2tPcHRpb25zfT1wYWdlTGlmZWN5Y2xlPz97fTtzdGF0ZS5hdXRvVHJhY2sucGFnZUxpZmVjeWNsZS5lbmFibGVkLnZhbHVlPXBhZ2VMaWZlY3ljbGVFbmFibGVkOy8vIFNldCB0aGUgYXV0b1RyYWNrIGVuYWJsZWQgc3RhdGVcbi8vIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgYXV0b1RyYWNrIG9wdGlvbnMgaXMgZW5hYmxlZFxuLy8gSU1QT1JUQU5UOiBtYWtlIHN1cmUgdGhpcyBpcyBkb25lIGF0IHRoZSBlbmQgYXMgaXQgZGVwZW5kcyBvbiB0aGUgYWJvdmUgc3RhdGVzXG5zdGF0ZS5hdXRvVHJhY2suZW5hYmxlZC52YWx1ZT1hdXRvVHJhY2tFbmFibGVkfHxwYWdlTGlmZWN5Y2xlRW5hYmxlZDtpZighcGFnZUxpZmVjeWNsZUVuYWJsZWQpe3JldHVybjt9dGhpcy5zZXR1cFBhZ2VVbmxvYWRUcmFja2luZyhldmVudHMsdXNlQmVhY29uLG9wdGlvbnMpO30vKipcbiAgICogU2V0dXAgcGFnZSB1bmxvYWQgdHJhY2tpbmcgaWYgZW5hYmxlZFxuICAgKiBAcGFyYW0gZXZlbnRzXG4gICAqIEBwYXJhbSB1c2VCZWFjb25cbiAgICogQHBhcmFtIG9wdGlvbnNcbiAgICovc2V0dXBQYWdlVW5sb2FkVHJhY2tpbmcoZXZlbnRzLHVzZUJlYWNvbixvcHRpb25zKXtpZihldmVudHMubGVuZ3RoPT09MHx8ZXZlbnRzLmluY2x1ZGVzKFBhZ2VMaWZlY3ljbGVFdmVudHMuVU5MT0FERUQpKXtpZih1c2VCZWFjb249PT10cnVlKXtvblBhZ2VMZWF2ZShpc0FjY2Vzc2libGU9PntpZihpc0FjY2Vzc2libGU9PT1mYWxzZSYmc3RhdGUubGlmZWN5Y2xlLmxvYWRlZC52YWx1ZSl7Y29uc3QgcGFnZVVubG9hZGVkVGltZXN0YW1wPURhdGUubm93KCk7Y29uc3QgdGltZU9uUGFnZT1wYWdlVW5sb2FkZWRUaW1lc3RhbXAtc3RhdGUuYXV0b1RyYWNrLnBhZ2VM
1aWZlY3ljbGUucGFnZUxvYWRlZFRpbWVzdGFtcC52YWx1ZTt0aGlzLnRyYWNrKFBhZ2VMaWZlY3ljbGVFdmVudHMuVU5MT0FERUQse3RpbWVPblBhZ2V9LHsuLi5vcHRpb25zLG9yaWdpbmFsVGltZXN0YW1wOmdldEZvcm1hdHRlZFRpbWVzdGFtcChuZXcgRGF0ZShwYWdlVW5sb2FkZWRUaW1lc3RhbXApKX0pO319LHRydWUpO31lbHNlIHsvLyBsb2cgd2FybmluZyBpZiBiZWFjb24gaXMgZGlzYWJsZWRcbnRoaXMubG9nZ2VyLndhcm4oUEFHRV9VTkxPQURfT05fQkVBQ09OX0RJU0FCTEVEX1dBUk5JTkcoUlNBKSk7fX19LyoqXG4gICAqIFRyaWdnZXIgbG9hZCBldmVudCBpbiBidWZmZXIgcXVldWUgaWYgZXhpc3RzIGFuZCBzdG9yZXMgdGhlXG4gICAqIHJlbWFpbmluZyBwcmVsb2FkZWQgZXZlbnRzIGFycmF5IGluIGdsb2JhbCBvYmplY3RcbiAgICovdHJpZ2dlckJ1ZmZlcmVkTG9hZEV2ZW50KCl7Y29uc3QgcHJlbG9hZGVkRXZlbnRzQXJyYXk9QXJyYXkuaXNBcnJheShnbG9iYWxUaGlzLnJ1ZGRlcmFuYWx5dGljcyk/Z2xvYmFsVGhpcy5ydWRkZXJhbmFseXRpY3M6W107Ly8gR2V0IGFueSBsb2FkIG1ldGhvZCBjYWxsIHRoYXQgaXMgYnVmZmVyZWQgaWYgYW55XG4vLyBCVFcsIGxvYWQgbWV0aG9kIGlzIGFsc28gcmVtb3ZlZCBmcm9tIHRoZSBhcnJheVxuLy8gU28sIHRoZSBBbmFseXRpY3Mgb2JqZWN0IGNhbiBkaXJlY3RseSBjb25zdW1lIHRoZSByZW1haW5pbmcgZXZlbnRzXG5jb25zdCBsb2FkRXZlbnQ9Z2V0UHJlbG9hZGVkTG9hZEV2ZW50KHByZWxvYWRlZEV2ZW50c0FycmF5KTsvLyBTZXQgdGhlIGZpbmFsIHByZWxvYWRlZCBldmVudHMgYXJyYXkgaW4gZ2xvYmFsIG9iamVjdFxuc2V0RXhwb3NlZEdsb2JhbChHTE9CQUxfUFJFTE9BRF9CVUZGRVIsY2xvbmUoWy4uLnByZWxvYWRlZEV2ZW50c0FycmF5XSkpOy8vIFByb2Nlc3MgbG9hZCBtZXRob2QgaWYgcHJlc2VudCBpbiB0aGUgYnVmZmVyZWQgcmVxdWVzdHNcbmlmKGxvYWRFdmVudC5sZW5ndGg+MCl7Ly8gUmVtb3ZlIHRoZSBldmVudCBuYW1lIGZyb20gdGhlIEJ1ZmZlcmVkIEV2ZW50IGFycmF5IGFuZCBrZWVwIG9ubHkgYXJndW1lbnRzXG5sb2FkRXZlbnQuc2hpZnQoKTsvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50XG4vLyBAdHMtaWdub3JlXG50aGlzLmxvYWQuYXBwbHkobnVsbCxsb2FkRXZlbnQpO319LyoqXG4gICAqIEdldCByZWFkeSBjYWxsYmFjayBhcmd1bWVudHMgYW5kIGZvcndhcmQgdG8gcmVhZHkgY2FsbFxuICAgKi9yZWFkeShjYWxsYmFjayl7dHJ5e3RoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2UoKT8ucmVhZHkoZ2V0U2FuaXRpemVkVmFsdWUoY2FsbGJhY2spKTt9Y2F0Y2goZXJyb3Ipe2Rpc3BhdGNoRXJyb3JFdmVudChlcnJvcik7fX0vKipcbiAgICogUHJvY2VzcyBwYWdlIGFyZ3VtZW50cyBhbmQgZm9yd2FyZCB0byBwYWdlIGNhbGxcbiAgICovLy8gVGhlc2Ugb3ZlcmxvYWRzIHNob3VsZCBiZSBzYW1lIGFzIEFuYWx5dGljc1BhZ2VNZXRob2QgaW4gQHJ1ZGRlcnN0YWNrL2FuYWx5dGljcy1qcy1jb21tb24vdHlwZXMvSVJ1ZGRlckFuYWx5dGljc1xucGFnZShjYXRlZ29yeSxuYW1lLHByb3BlcnRpZXMsb3B0aW9ucyxjYWxsYmFjayl7dHJ5e3RoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2UoKT8ucGFnZShwYWdlQXJndW1lbnRzVG9DYWxsT3B0aW9ucyhnZXRTYW5pdGl6ZWRWYWx1ZShjYXRlZ29yeSksZ2V0U2FuaXRpemVkVmFsdWUobmFtZSksZ2V0U2FuaXRpemVkVmFsdWUocHJvcGVydGllcyksZ2V0U2FuaXRpemVkVmFsdWUob3B0aW9ucyksZ2V0U2FuaXRpemVkVmFsdWUoY2FsbGJhY2spKSk7fWNhdGNoKGVycm9yKXtkaXNwYXRjaEVycm9yRXZlbnQoZXJyb3IpO319LyoqXG4gICAqIFByb2Nlc3MgdHJhY2sgYXJndW1lbnRzIGFuZCBmb3J3YXJkIHRvIHBhZ2UgY2FsbFxuICAgKi8vLyBUaGVzZSBvdmVybG9hZHMgc2hvdWxkIGJlIHNhbWUgYXMgQW5hbHl0aWNzVHJhY2tNZXRob2QgaW4gQHJ1ZGRlcnN0YWNrL2FuYWx5dGljcy1qcy1jb21tb24vdHlwZXMvSVJ1ZGRlckFuYWx5dGljc1xudHJhY2soZXZlbnQscHJvcGVydGllcyxvcHRpb25zLGNhbGxiYWNrKXt0cnl7dGhpcy5nZXRBbmFseXRpY3NJbnN0YW5jZSgpPy50cmFjayh0cmFja0FyZ3VtZW50c1RvQ2FsbE9wdGlvbnMoZ2V0U2FuaXRpemVkVmFsdWUoZXZlbnQpLGdldFNhbml0aXplZFZhbHVlKHByb3BlcnRpZXMpLGdldFNhbml0aXplZFZhbHVlKG9wdGlvbnMpLGdldFNhbml0aXplZFZhbHVlKGNhbGxiYWNrKSkpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTt9fS8qKlxuICAgKiBQcm9jZXNzIGlkZW50aWZ5IGFyZ3VtZW50cyBhbmQgZm9yd2FyZCB0byBwYWdlIGNhbGxcbiAgICovLy8gVGhlc2Ugb3ZlcmxvYWRzIHNob3VsZCBiZSBzYW1lIGFzIEFuYWx5dGljc0lkZW50aWZ5TWV0aG9kIGluIEBydWRkZXJzdGFjay9hbmFseXRpY3MtanMtY29tbW9uL3R5cGVzL0lSdWRkZXJBbmFseXRpY3NcbmlkZW50aWZ5KHVzZXJJZCx0cmFpdHMsb3B0aW9ucyxjYWxsYmFjayl7dHJ5e3RoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2UoKT8uaWRlbnRpZnkoaWRlbnRpZnlBcmd1bWVudHNUb0NhbGxPcHRpb25zKGdldFNhbml0aXplZFZhbHVlKHVzZXJJZCksZ2V0U2FuaXRpemVkVmFsdWUodHJhaXRzKSxnZXRTYW5pdGl6ZWRWYWx1ZShvcHRpb25zKSxnZXRTYW5pdGl6ZWRWYWx1ZShjYWxsYmFjaykpKTt9Y2F0Y2goZXJyb3Ipe2Rpc3BhdGNoRXJyb3JFdmVudChlcnJvcik7fX0vKipcbiAgICogUHJvY2VzcyBhbGlhcyBhcmd1bWVudHMgYW5kIGZvcndhcmQgdG8gcGFnZSBjYWxsXG4gICAqLy8vIFRoZXNlIG92ZXJsb2FkcyBzaG91bGQgYmUgc2FtZSBhcyBBbmFseXRpY3NBbGlhc01ldGhvZCBpbiBAcnVkZGVyc3RhY2svYW5hbHl0aWNzLWpzLWNvbW1vbi90eXBlcy9JUnVkZGVyQW5hbHl0aWNzXG5hbGlhcyh0byxmcm9tLG9wdGlvbnMsY2FsbGJhY2spe3RyeXt0aGlzLmdldEFuYWx5dGljc0luc3RhbmNlKCk/LmFsaWFzKGFsaWFzQXJndW1lbnRzVG9DYWxsT3B0aW9ucyhnZXRTYW5pdGl6ZWRWYWx1ZSh0byksZ2V0U2FuaXRpemVkVmFsdWUoZnJvbSksZ2V0U2FuaXRpemVkVmFsdWUob3B0aW9ucyksZ2V0U2FuaXRpemVkVmFsdWUoY2FsbGJhY2spKSk7fWNhdGNoKGVycm9yKXtkaXNwYXRjaEVycm9yRXZlbnQoZXJyb3IpO319LyoqXG4gICAqIFByb2Nlc3MgZ3JvdXAgYXJndW1lbnRzIGFuZCBmb3J3YXJkIHRvIHBhZ2UgY2FsbFxuICAgKi8vLyBUaGVzZSBvdmVybG9hZHMgc2hvdWxkIGJlIHNhbWUgYXMgQW5hbHl0aWNzR3JvdXBNZXRob2QgaW4gQHJ1ZGRlcnN0YWNrL2FuYWx5dGljcy1qcy1jb21tb24vdHlwZXMvSVJ1ZGRlckFuYWx5dGljc1xuZ3JvdXAoZ3JvdXBJZCx0cmFpdHMsb3B0aW9ucyxjYWxsYmFjayl7dHJ5e3RoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2UoKT8uZ3JvdXAoZ3JvdXBBcmd1bWVudHNUb0NhbGxPcHRpb25zKGdldFNhbml0aXplZFZhbHVlKGdyb3VwSWQpLGdldFNhbml0aXplZFZhbHVlKHRyYWl0cyksZ2V0U2FuaXRpemVkVmFsdWUob3B0aW9ucyksZ2V0U2FuaXRpemVkVmFsdWUoY2FsbGJhY2spKSk7fWNhdGNoKGVycm9yKXtkaXNwYXRjaEVycm9yRXZlbnQoZXJyb3IpO319LyoqXG4gICAqIFJlc2V0IHRoZSBhbmFseXRpY3MgaW5zdGFuY2VcbiAgICogQHBhcmFtIG9wdGlvbnMgUmVzZXQgb3B0aW9ucy4gRXhjZXB0IGZvciBhbm9ueW1vdXNJZCwgaW5pdGlhbFJlZmVycmVyLCBhbmQgaW5pdGlhbFJlZmVycmluZ0RvbWFpblxuICAgKiBhbGwgb3RoZXIgdmFsdWVzIHdpbGwgYmUgcmVzZXQgYnkgZGVmYXVsdC5cbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHNcbiAgICogcmVzZXQoe1xuICAgKiAgZW50cmllczoge1xuICAgKiAgICBhbm9ueW1vdXNJZDogdHJ1ZSxcbiAgICogIH1cbiAgICogfSk7XG4gICAqIGBgYFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0c1xuICAgKiByZXNldCh7XG4gICAqICBlbnRyaWVzOiB7XG4gICAqICAgIHVzZXJJZDogZmFsc2UsXG4gICAqICAgIHNlc3Npb25JbmZvOiBmYWxzZSxcbiAgICogIH1cbiAgICogfSk7XG4gICAqIGBgYFxuICAgKiBAcmV0dXJucyBub25lXG4gICAqLy8qKlxuICAgKiBSZXNldCB0aGUgYW5hbHl0aWNzIGluc3RhbmNlXG4gICAqIEBwYXJhbSByZXNldEFub255bW91c0lkIFJlc2V0IGFub255bW91cyBJRFxuICAgKiBAcmV0dXJucyBub25lXG4gICAqIEBkZXByZWNhdGVkIFVzZSByZXNldChvcHRpb25zKSBpbnN0ZWFkXG4gICAqL3Jlc2V0KG9wdGlvbnMpe3RyeXt0aGlzLmdldEFuYWx5dGljc0luc3RhbmNlKCk/LnJlc2V0KGdldFNhbml0aXplZFZhbHVlKG9wdGlvbnMpKTt9Y2F0Y2goZXJyb3Ipe2Rpc3BhdGNoRXJyb3JFdmVudChlcnJvcik7fX1nZXRBbm9ueW1vdXNJZChvcHRpb25zKXt0cnl7cmV0dXJuIHRoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2UoKT8uZ2V0QW5vbnltb3VzSWQoZ2V0U2FuaXRpemVkVmFsdWUob3B0aW9ucykpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTtyZXR1cm4gdW5kZWZpbmVkO319c2V0QW5vbnltb3VzSWQoYW5vbnltb3VzSWQscnVkZGVyQW1wTGlua2VyUGFyYW0pe3RyeXt0aGlzLmdldEFuYWx5dGljc0luc3RhbmNlKCk/LnNldEFub255bW91c0lkKGdldFNhbml0aXplZFZhbHVlKGFub255bW91c0lkKSxnZXRTYW5pdGl6ZWRWYWx1ZShydWRkZXJBbXBMaW5rZXJQYXJhbSkpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTt9fWdldFVzZXJJZCgpe3RyeXtyZXR1cm4gdGhpcy5nZXRBbmFseXRpY3NJbnN0YW5jZSgpPy5nZXRVc2VySWQoKTt9Y2F0Y2goZXJyb3Ipe2Rpc3BhdGNoRXJyb3JFdmVudChlcnJvcik7cmV0dXJuIHVuZGVmaW5lZDt9fWdldFVzZXJUcmFpdHMoKXt0cnl7cmV0dXJuIHRoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2UoKT8uZ2V0VXNlclRyYWl0cygpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTtyZXR1cm4gdW5kZWZpbmVkO319Z2V0R3JvdXBJZCgpe3RyeXtyZXR1cm4gdGhpcy5nZXRBbmFseXRpY3NJbnN0YW5jZSgpPy5nZXRHcm91cElkKCk7fWNhdGNoKGVycm9yKXtkaXNwYXRjaEVycm9yRXZlbnQoZXJyb3IpO3JldHVybiB1bmRlZmluZWQ7fX1nZXRHcm91cFRyYWl0cygpe3RyeXtyZXR1cm4gdGhpcy5nZXRBbmFseXRpY3NJbnN0YW5jZSgpPy5nZXRHcm91cFRyYWl0cygpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTtyZXR1cm4gdW5kZWZpbmVkO319c3RhcnRTZXNzaW9uKHNlc3Npb25JZCl7dHJ5e3RoaXMuZ2V0QW5hbHl0aWNzSW5zdGFuY2UoKT8uc3RhcnRTZXNzaW9uKGdldFNhbml0aXplZFZhbHVlKHNlc3Npb25JZCkpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTt9fWVuZFNlc3Npb24oKXt0cnl7dGhpcy5nZXRBbmFseXRpY3NJbnN0YW5jZSgpPy5lbmRTZXNzaW9uKCk7fWNhdGNoKGVycm9yKXtkaXNwYXRjaEVycm9yRXZlbnQoZXJyb3IpO319Z2V0U2Vzc2lvbklkKCl7dHJ5e3JldHVybiB0aGlzLmdldEFuYWx5dGljc0luc3RhbmNlKCk/LmdldFNlc3Npb25JZCgpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTtyZXR1cm4gdW5kZWZpbmVkO319c2V0QXV0aFRva2VuKHRva2VuKXt0cnl7dGhpcy5nZXRBbmFseXRpY3NJbnN0YW5jZSgpPy5zZXRB
1dXRoVG9rZW4oZ2V0U2FuaXRpemVkVmFsdWUodG9rZW4pKTt9Y2F0Y2goZXJyb3Ipe2Rpc3BhdGNoRXJyb3JFdmVudChlcnJvcik7fX1jb25zZW50KG9wdGlvbnMpe3RyeXt0aGlzLmdldEFuYWx5dGljc0luc3RhbmNlKCk/LmNvbnNlbnQoZ2V0U2FuaXRpemVkVmFsdWUob3B0aW9ucykpO31jYXRjaChlcnJvcil7ZGlzcGF0Y2hFcnJvckV2ZW50KGVycm9yKTt9fWFkZEN1c3RvbUludGVncmF0aW9uKGRlc3RpbmF0aW9uSWQsaW50ZWdyYXRpb24pe3RyeXt0aGlzLmdldEFuYWx5dGljc0luc3RhbmNlKCk/LmFkZEN1c3RvbUludGVncmF0aW9uKGdldFNhbml0aXplZFZhbHVlKGRlc3RpbmF0aW9uSWQpLGdldFNhbml0aXplZFZhbHVlKGludGVncmF0aW9uKSk7fWNhdGNoKGVycm9yKXtkaXNwYXRjaEVycm9yRXZlbnQoZXJyb3IpO319fVxuXG5leHBvcnQgeyBSdWRkZXJBbmFseXRpY3MgfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./node_modules/@rudderstack/analytics-js/dist/npm/modern/bundled/esm/index.mjs\n\n}")}};const __webpack_module_cache__={};function __webpack_require__(e){const t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;const l=__webpack_module_cache__[e]={exports:{}};if(!(e in __webpack_modules__)){delete __webpack_module_cache__[e];const t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return __webpack_modules__[e](l,l.exports,__webpack_require__),l.exports}__webpack_require__.n=e=>{const t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},__webpack_require__.d=(e,t)=>{if(Array.isArray(t))for(var l=0;l<t.length;){var n=t[l++],c=t[l++];__webpack_require__.o(e,n)?0===c&&l++:0===c?Object.defineProperty(e,n,{enumerable:!0,value:t[l++]}):Object.defineProperty(e,n,{enumerable:!0,get:c})}else for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};let __webpack_exports__=__webpack_require__("../assets/src/scripts/rudder/main.js")})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.