[{"data":1,"prerenderedAt":8},["ShallowReactive",2],{"code:txt:18pqelm":3,"code:json:5xqmky":4,"code:ts:cc1mqi":5,"code:txt:d4z68u":6,"code:go:5ylkby":7},"\u003Cpre class=\"shiki ipscope\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan>[ Smartphone in Augsburg ]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   |  Internal Carrier IP (100.64.18.42 \u002F RFC 6598 Shared CGNAT Space)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   v\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>[ Local 5G Cell Tower (gNodeB in Augsburg) ]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   |  Encapsulates packet in GTP-U (UDP Port 2152) over Carrier Core MPLS\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   v\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>[ Regional 5G User Plane Function (UPF) in Munich (80 km away) ]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   |  1. Decapsulates GTP-U header\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   |  2. CGNAT translates 100.64.18.42:54112 -> Public IP 203.0.113.88:41029\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   |     (Port-Block Allocation: 64 ports per subscriber, ~1,000-4,000 users\u002FIP)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   v\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>[ Public Internet \u002F DE-CIX Munich Peering ]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   |  Source IP seen by your server: 203.0.113.88\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>   v\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>[ Your API Gateway \u002F Load Balancer ]\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki ipscope\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  \"ip\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"203.0.113.88\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  \"ip_version\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 4\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  \"matched_network\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"203.0.113.0\u002F24\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  \"geo\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"country_code\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"DE\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"declared_country_code\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"DE\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"physical_country_code\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"DE\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_virtual_location\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"location_type\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"physical\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"confidence\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0.91\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"subdivision\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"Bavaria\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"city\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"Munich\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"latitude\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 48.1351\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"longitude\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 11.582\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"accuracy_radius_km\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 120\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"timezone\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"Europe\u002FBerlin\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  }\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  \"network\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"cidr\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"203.0.113.0\u002F24\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"asn\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 3320\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"organization\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"Deutsche Telekom AG\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"rir\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"RIPE\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  }\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  \"connection\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"connection_type\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"mobile\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_residential\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_mobile\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> true\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_business\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_hosting\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  }\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  \"security\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_vpn\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_hosting\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_tor_exit\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"is_proxy\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"anonymizer_type\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"none\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"confidence\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0.99\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    \"reason_codes\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> []\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki ipscope\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">import\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> { IpScopeClient } \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">from\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> '@ipscope\u002Fsdk-node'\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">const\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> ipscope\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> new\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> IpScopeClient\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">({\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  apiKey\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> process\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">env\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">IPSCOPE_KEY\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">!\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  maxCacheEntries\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 16_384\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  cacheTtlMs\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 300_000\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">});\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">export\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> interface\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> RateLimitConfig\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  bucketKey\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> string\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  maxRequestsPerMinute\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> number\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  windowSeconds\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> number\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">export\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> async\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> function\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> resolveRateLimitPolicy\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  clientIp\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> string\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  deviceCookieId\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> string\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> |\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> undefined\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  tlsJa4Fingerprint\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> string\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> |\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> undefined\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">)\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> Promise\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">RateLimitConfig\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  const\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> res\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> await\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> ipscope\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">.lookupIp\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(clientIp);\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  const\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> { \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">connection\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> security\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> security_extensions\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> } \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> res;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  const\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> velocity\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> security_extensions\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">?.abuse_velocity_score \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">??\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">  \u002F\u002F 1. High-velocity scanner or active proxy: strict per-IP quarantine bucket\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  if\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> (velocity \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">>=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 75\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> ||\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> security\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">.is_tor_exit \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">||\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> security\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">.is_proxy) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    return\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">      bucketKey\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> `rl:strict:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">${\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">clientIp\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">}\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">`\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">      maxRequestsPerMinute\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 10\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">      windowSeconds\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 60\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">    };\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">  \u002F\u002F 2. Cellular 4G\u002F5G CGNAT pool: partition bucket by (IP + device\u002FTLS sub-key)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">  \u002F\u002F    and raise the aggregate IP ceiling so shared carrier NAT never starves legitimate users\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  if\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> (\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">connection\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">?.is_mobile \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">&#x26;&#x26;\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> !\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">security\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">.is_vpn) {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    const\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> subKey\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> deviceCookieId \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">||\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> tlsJa4Fingerprint \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">||\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> 'anon'\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">    return\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">      bucketKey\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> `rl:mobile:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">${\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">clientIp\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">}\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">${\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">subKey\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">}\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">`\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">      maxRequestsPerMinute\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 180\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">      windowSeconds\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 60\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">    };\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">  \u002F\u002F 3. Standard residential or business broadband: per-IP bucket\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  return\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">    bucketKey\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> `rl:std:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">${\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">clientIp\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">}\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">`\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">    maxRequestsPerMinute\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 120\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">    windowSeconds\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 60\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  };\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki ipscope\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan>D_effective = max(0, D_haversine(p1, p2) - R1 - R2)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki ipscope\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">package\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> sessionsec\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">import\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> (\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\t\"math\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\t\"time\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">type\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> GeoObservation\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> struct\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tObservedAt       \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">time\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Time\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tCountryCode      \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">string\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tLatitude         \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">float64\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tLongitude        \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">float64\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tAccuracyRadiusKm \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">float64\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tIsMobile         \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">bool\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tIsVPN            \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">bool\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">\u002F\u002F EffectiveTravelDistanceKm computes the minimum distance between two IP geolocation\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">\u002F\u002F uncertainty circles on the WGS84 sphere.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">func\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> EffectiveTravelDistanceKm\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(prev, curr \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">GeoObservation\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">) \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">float64\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\tconst\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> earthRadiusKm\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 6371.0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tdLat \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> (curr.Latitude \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> prev.Latitude) \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> math.Pi \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 180.0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tdLon \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> (curr.Longitude \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> prev.Longitude) \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> math.Pi \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 180.0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tlat1 \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> prev.Latitude \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> math.Pi \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 180.0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tlat2 \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> curr.Latitude \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> math.Pi \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 180.0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\ta \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> math.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Sin\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(dLat\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">2\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">)\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">math.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Sin\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(dLat\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">2\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">) \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">+\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\t\tmath.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Cos\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(lat1)\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">math.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Cos\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(lat2)\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">math.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Sin\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(dLon\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">2\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">)\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">math.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Sin\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(dLon\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">2\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tcentroidDistanceKm \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 2\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> *\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> earthRadiusKm \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">*\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> math.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Atan2\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(math.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Sqrt\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(a), math.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Sqrt\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\">1\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">a))\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">\t\u002F\u002F Subtract both uncertainty radii (plus a 50km carrier UPF handoff buffer if either leg is mobile)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\tmobileBufferKm \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0.0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\tif\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> prev.IsMobile \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">||\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> curr.IsMobile {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\t\tmobileBufferKm \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 50.0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\teffective \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> centroidDistanceKm \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> prev.AccuracyRadiusKm \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> curr.AccuracyRadiusKm \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> mobileBufferKm\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\tif\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> effective \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\treturn\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> effective\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">\u002F\u002F IsImpossibleTravel returns true only when the effective minimum distance between\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">\u002F\u002F uncertainty circles exceeds 900 km\u002Fh (commercial aircraft speed).\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">func\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> IsImpossibleTravel\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(prev, curr \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">GeoObservation\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">) \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">bool\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\tif\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> EffectiveTravelDistanceKm\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(prev, curr) \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">==\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\t\treturn\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> false\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\thours \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> curr.ObservedAt.\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Sub\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(prev.ObservedAt).\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\">Hours\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\tif\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> hours \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">&#x3C;=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0.05\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\">\t\t\u002F\u002F Enforce a minimum 3-minute floor to avoid division spikes\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\t\thours \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 0.05\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\t}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">\trequiredSpeedKmh \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-function)\"> EffectiveTravelDistanceKm\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">(prev, curr) \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">\u002F\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> hours\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">\treturn\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> requiredSpeedKmh \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">>\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-constant)\"> 900.0\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",1793226491917]