[{"data":1,"prerenderedAt":62},["Reactive",2],{"blog-post-markdown-link-validation-testing-complete-guide":3},{"slug":4,"title":5,"description":6,"excerpt":7,"date":8,"category":9,"author":10,"keywords":11,"readingMinutes":12,"html":13,"headings":14,"tools":37,"related":38},"markdown-link-validation-testing-complete-guide","Markdown Link Validation and Testing: Complete Guide for Reliable Documentation Links","Master comprehensive link validation techniques for Markdown documentation. Learn automated testing, broken link detection, and maintenance strategies for reliable documentation systems.","Advanced Markdown link validation and testing ensures comprehensive documentation reliability through systematic verification of internal references, external URLs, and cross-document…","2025-11-25","Tutorial","Matthew Rathbone","markdown link validation, broken link detection, markdown testing, link checker markdown, documentation maintenance, automated link testing, markdown CI testing",22,"\u003Cp>Advanced Markdown link validation and testing ensures comprehensive documentation reliability through systematic verification of internal references, external URLs, and cross-document relationships. By implementing automated validation pipelines, intelligent link monitoring systems, and proactive maintenance strategies, technical teams can maintain robust documentation ecosystems that provide consistent user experiences while minimizing broken links and outdated references across large content repositories.\u003C/p>\n\u003Ch2 id=\"why-master-link-validation-and-testing\">Why Master Link Validation and Testing?\u003C/h2>\n\u003Cp>Professional link validation provides essential benefits for documentation maintenance:\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>User Experience\u003C/strong>: Prevent frustrating broken links that interrupt reader workflows\u003C/li>\n\u003Cli>\u003Cstrong>SEO Performance\u003C/strong>: Maintain search engine rankings through healthy link structures\u003C/li>\n\u003Cli>\u003Cstrong>Content Integrity\u003C/strong>: Ensure documentation remains current and accessible over time\u003C/li>\n\u003Cli>\u003Cstrong>Automated Quality\u003C/strong>: Reduce manual testing overhead through systematic validation\u003C/li>\n\u003Cli>\u003Cstrong>Cross-Platform Reliability\u003C/strong>: Verify links work across different environments and platforms\u003C/li>\n\u003C/ul>\n\u003Ch2 id=\"foundation-link-validation-techniques\">Foundation Link Validation Techniques\u003C/h2>\n\u003Ch3 id=\"basic-link-analysis-and-detection\">Basic Link Analysis and Detection\u003C/h3>\n\u003Cp>Understanding different link types and their validation requirements:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-python\">\u003Cspan class=\"hljs-comment\"># link_analyzer.py - Comprehensive link analysis and validation\u003C/span>\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> re\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> urllib.parse\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> typing \u003Cspan class=\"hljs-keyword\">import\u003C/span> \u003Cspan class=\"hljs-type\">List\u003C/span>, \u003Cspan class=\"hljs-type\">Dict\u003C/span>, \u003Cspan class=\"hljs-type\">Set\u003C/span>, \u003Cspan class=\"hljs-type\">Optional\u003C/span>, \u003Cspan class=\"hljs-type\">Tuple\u003C/span>\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> pathlib \u003Cspan class=\"hljs-keyword\">import\u003C/span> Path\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> enum \u003Cspan class=\"hljs-keyword\">import\u003C/span> Enum\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> requests\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> concurrent.futures \u003Cspan class=\"hljs-keyword\">import\u003C/span> ThreadPoolExecutor, as_completed\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> time\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">LinkType\u003C/span>(\u003Cspan class=\"hljs-title class_ inherited__\">Enum\u003C/span>):\n    INTERNAL_RELATIVE = \u003Cspan class=\"hljs-string\">&quot;internal_relative&quot;\u003C/span>\n    INTERNAL_ABSOLUTE = \u003Cspan class=\"hljs-string\">&quot;internal_absolute&quot;\u003C/span> \n    EXTERNAL_HTTP = \u003Cspan class=\"hljs-string\">&quot;external_http&quot;\u003C/span>\n    EXTERNAL_HTTPS = \u003Cspan class=\"hljs-string\">&quot;external_https&quot;\u003C/span>\n    ANCHOR_LINK = \u003Cspan class=\"hljs-string\">&quot;anchor_link&quot;\u003C/span>\n    EMAIL_MAILTO = \u003Cspan class=\"hljs-string\">&quot;email_mailto&quot;\u003C/span>\n    FILE_REFERENCE = \u003Cspan class=\"hljs-string\">&quot;file_reference&quot;\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">LinkStatus\u003C/span>(\u003Cspan class=\"hljs-title class_ inherited__\">Enum\u003C/span>):\n    VALID = \u003Cspan class=\"hljs-string\">&quot;valid&quot;\u003C/span>\n    BROKEN = \u003Cspan class=\"hljs-string\">&quot;broken&quot;\u003C/span>\n    REDIRECT = \u003Cspan class=\"hljs-string\">&quot;redirect&quot;\u003C/span>\n    TIMEOUT = \u003Cspan class=\"hljs-string\">&quot;timeout&quot;\u003C/span>\n    UNKNOWN = \u003Cspan class=\"hljs-string\">&quot;unknown&quot;\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">MarkdownLinkAnalyzer\u003C/span>:\n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__init__\u003C/span>(\u003Cspan class=\"hljs-params\">self, base_path: Path = \u003Cspan class=\"hljs-literal\">None\u003C/span>, timeout: \u003Cspan class=\"hljs-built_in\">int\u003C/span> = \u003Cspan class=\"hljs-number\">10\u003C/span>\u003C/span>):\n        self.base_path = base_path \u003Cspan class=\"hljs-keyword\">or\u003C/span> Path.cwd()\n        self.timeout = timeout\n        \n        \u003Cspan class=\"hljs-comment\"># Comprehensive link pattern matching\u003C/span>\n        self.link_patterns = {\n            \u003Cspan class=\"hljs-string\">&#x27;markdown_links&#x27;\u003C/span>: re.\u003Cspan class=\"hljs-built_in\">compile\u003C/span>(\u003Cspan class=\"hljs-string\">r&#x27;\\[([^\\]]*)\\]\\(([^)]+)\\)&#x27;\u003C/span>),\n            \u003Cspan class=\"hljs-string\">&#x27;reference_links&#x27;\u003C/span>: re.\u003Cspan class=\"hljs-built_in\">compile\u003C/span>(\u003Cspan class=\"hljs-string\">r&#x27;\\[([^\\]]*)\\]\\[([^\\]]*)\\]&#x27;\u003C/span>),\n            \u003Cspan class=\"hljs-string\">&#x27;reference_definitions&#x27;\u003C/span>: re.\u003Cspan class=\"hljs-built_in\">compile\u003C/span>(\u003Cspan class=\"hljs-string\">r&#x27;^\\[([^\\]]+)\\]:\\s*(.+)$&#x27;\u003C/span>, re.MULTILINE),\n            \u003Cspan class=\"hljs-string\">&#x27;html_links&#x27;\u003C/span>: re.\u003Cspan class=\"hljs-built_in\">compile\u003C/span>(\u003Cspan class=\"hljs-string\">r&#x27;&lt;a[^&gt;]+href=[&quot;\\&#x27;]([^&quot;\\&#x27;]+)[&quot;\\&#x27;][^&gt;]*&gt;&#x27;\u003C/span>),\n            \u003Cspan class=\"hljs-string\">&#x27;auto_links&#x27;\u003C/span>: re.\u003Cspan class=\"hljs-built_in\">compile\u003C/span>(\u003Cspan class=\"hljs-string\">r&#x27;&lt;(https?://[^&gt;]+)&gt;&#x27;\u003C/span>),\n            \u003Cspan class=\"hljs-string\">&#x27;bare_urls&#x27;\u003C/span>: re.\u003Cspan class=\"hljs-built_in\">compile\u003C/span>(\u003Cspan class=\"hljs-string\">r&#x27;(?&lt;![\\(\\[])(https?://[^\\s\\)]+)&#x27;\u003C/span>)\n        }\n        \n        self.session = requests.Session()\n        self.session.headers.update({\n            \u003Cspan class=\"hljs-string\">&#x27;User-Agent&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;MarkdownLinkValidator/1.0 (+https://blog.markdowntools.com)&#x27;\u003C/span>\n        })\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">extract_all_links\u003C/span>(\u003Cspan class=\"hljs-params\">self, markdown_content: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, file_path: Path = \u003Cspan class=\"hljs-literal\">None\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>, \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-type\">Dict\u003C/span>]]:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Extract all types of links from markdown content&quot;&quot;&quot;\u003C/span>\n        extracted_links = {\n            \u003Cspan class=\"hljs-string\">&#x27;direct_links&#x27;\u003C/span>: [],\n            \u003Cspan class=\"hljs-string\">&#x27;reference_links&#x27;\u003C/span>: [],\n            \u003Cspan class=\"hljs-string\">&#x27;reference_definitions&#x27;\u003C/span>: [],\n            \u003Cspan class=\"hljs-string\">&#x27;html_links&#x27;\u003C/span>: [],\n            \u003Cspan class=\"hljs-string\">&#x27;auto_links&#x27;\u003C/span>: [],\n            \u003Cspan class=\"hljs-string\">&#x27;bare_urls&#x27;\u003C/span>: []\n        }\n        \n        \u003Cspan class=\"hljs-comment\"># Extract direct markdown links [text](url)\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> \u003Cspan class=\"hljs-keyword\">match\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.link_patterns[\u003Cspan class=\"hljs-string\">&#x27;markdown_links&#x27;\u003C/span>].finditer(markdown_content):\n            link_text, url = \u003Cspan class=\"hljs-keyword\">match\u003C/span>.groups()\n            link_info = self._analyze_link(url, link_text, \u003Cspan class=\"hljs-keyword\">match\u003C/span>.start(), file_path)\n            extracted_links[\u003Cspan class=\"hljs-string\">&#x27;direct_links&#x27;\u003C/span>].append(link_info)\n        \n        \u003Cspan class=\"hljs-comment\"># Extract reference-style links [text][ref]\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> \u003Cspan class=\"hljs-keyword\">match\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.link_patterns[\u003Cspan class=\"hljs-string\">&#x27;reference_links&#x27;\u003C/span>].finditer(markdown_content):\n            link_text, ref_id = \u003Cspan class=\"hljs-keyword\">match\u003C/span>.groups()\n            extracted_links[\u003Cspan class=\"hljs-string\">&#x27;reference_links&#x27;\u003C/span>].append({\n                \u003Cspan class=\"hljs-string\">&#x27;text&#x27;\u003C/span>: link_text,\n                \u003Cspan class=\"hljs-string\">&#x27;reference_id&#x27;\u003C/span>: ref_id \u003Cspan class=\"hljs-keyword\">or\u003C/span> link_text,\n                \u003Cspan class=\"hljs-string\">&#x27;position&#x27;\u003C/span>: \u003Cspan class=\"hljs-keyword\">match\u003C/span>.start(),\n                \u003Cspan class=\"hljs-string\">&#x27;line_number&#x27;\u003C/span>: self._get_line_number(markdown_content, \u003Cspan class=\"hljs-keyword\">match\u003C/span>.start())\n            })\n        \n        \u003Cspan class=\"hljs-comment\"># Extract reference definitions [ref]: url\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> \u003Cspan class=\"hljs-keyword\">match\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.link_patterns[\u003Cspan class=\"hljs-string\">&#x27;reference_definitions&#x27;\u003C/span>].finditer(markdown_content):\n            ref_id, url = \u003Cspan class=\"hljs-keyword\">match\u003C/span>.groups()\n            link_info = self._analyze_link(url.strip(), \u003Cspan class=\"hljs-string\">f&quot;[\u003Cspan class=\"hljs-subst\">{ref_id}\u003C/span>]&quot;\u003C/span>, \u003Cspan class=\"hljs-keyword\">match\u003C/span>.start(), file_path)\n            link_info[\u003Cspan class=\"hljs-string\">&#x27;reference_id&#x27;\u003C/span>] = ref_id\n            extracted_links[\u003Cspan class=\"hljs-string\">&#x27;reference_definitions&#x27;\u003C/span>].append(link_info)\n        \n        \u003Cspan class=\"hljs-comment\"># Extract HTML links\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> \u003Cspan class=\"hljs-keyword\">match\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.link_patterns[\u003Cspan class=\"hljs-string\">&#x27;html_links&#x27;\u003C/span>].finditer(markdown_content):\n            url = \u003Cspan class=\"hljs-keyword\">match\u003C/span>.group(\u003Cspan class=\"hljs-number\">1\u003C/span>)\n            link_info = self._analyze_link(url, \u003Cspan class=\"hljs-string\">&quot;HTML link&quot;\u003C/span>, \u003Cspan class=\"hljs-keyword\">match\u003C/span>.start(), file_path)\n            extracted_links[\u003Cspan class=\"hljs-string\">&#x27;html_links&#x27;\u003C/span>].append(link_info)\n        \n        \u003Cspan class=\"hljs-comment\"># Extract auto-links &lt;url&gt;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> \u003Cspan class=\"hljs-keyword\">match\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.link_patterns[\u003Cspan class=\"hljs-string\">&#x27;auto_links&#x27;\u003C/span>].finditer(markdown_content):\n            url = \u003Cspan class=\"hljs-keyword\">match\u003C/span>.group(\u003Cspan class=\"hljs-number\">1\u003C/span>)\n            link_info = self._analyze_link(url, url, \u003Cspan class=\"hljs-keyword\">match\u003C/span>.start(), file_path)\n            extracted_links[\u003Cspan class=\"hljs-string\">&#x27;auto_links&#x27;\u003C/span>].append(link_info)\n        \n        \u003Cspan class=\"hljs-comment\"># Extract bare URLs\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> \u003Cspan class=\"hljs-keyword\">match\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.link_patterns[\u003Cspan class=\"hljs-string\">&#x27;bare_urls&#x27;\u003C/span>].finditer(markdown_content):\n            url = \u003Cspan class=\"hljs-keyword\">match\u003C/span>.group(\u003Cspan class=\"hljs-number\">0\u003C/span>)\n            link_info = self._analyze_link(url, url, \u003Cspan class=\"hljs-keyword\">match\u003C/span>.start(), file_path)\n            extracted_links[\u003Cspan class=\"hljs-string\">&#x27;bare_urls&#x27;\u003C/span>].append(link_info)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> extracted_links\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_analyze_link\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, text: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, position: \u003Cspan class=\"hljs-built_in\">int\u003C/span>, file_path: Path = \u003Cspan class=\"hljs-literal\">None\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Analyze a single link and determine its type and properties&quot;&quot;&quot;\u003C/span>\n        link_info = {\n            \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n            \u003Cspan class=\"hljs-string\">&#x27;text&#x27;\u003C/span>: text,\n            \u003Cspan class=\"hljs-string\">&#x27;position&#x27;\u003C/span>: position,\n            \u003Cspan class=\"hljs-string\">&#x27;line_number&#x27;\u003C/span>: \u003Cspan class=\"hljs-literal\">None\u003C/span>,  \u003Cspan class=\"hljs-comment\"># Will be set by caller if needed\u003C/span>\n            \u003Cspan class=\"hljs-string\">&#x27;type&#x27;\u003C/span>: self._determine_link_type(url),\n            \u003Cspan class=\"hljs-string\">&#x27;absolute_url&#x27;\u003C/span>: \u003Cspan class=\"hljs-literal\">None\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;file_path&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">str\u003C/span>(file_path) \u003Cspan class=\"hljs-keyword\">if\u003C/span> file_path \u003Cspan class=\"hljs-keyword\">else\u003C/span> \u003Cspan class=\"hljs-literal\">None\u003C/span>\n        }\n        \n        \u003Cspan class=\"hljs-comment\"># Resolve relative URLs to absolute paths\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> link_info[\u003Cspan class=\"hljs-string\">&#x27;type&#x27;\u003C/span>] \u003Cspan class=\"hljs-keyword\">in\u003C/span> [LinkType.INTERNAL_RELATIVE, LinkType.FILE_REFERENCE]:\n            link_info[\u003Cspan class=\"hljs-string\">&#x27;absolute_url&#x27;\u003C/span>] = self._resolve_relative_url(url, file_path)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> link_info\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_determine_link_type\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; LinkType:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Determine the type of a given URL&quot;&quot;&quot;\u003C/span>\n        url = url.strip()\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> url.startswith(\u003Cspan class=\"hljs-string\">&#x27;mailto:&#x27;\u003C/span>):\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkType.EMAIL_MAILTO\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> url.startswith(\u003Cspan class=\"hljs-string\">&#x27;https://&#x27;\u003C/span>):\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkType.EXTERNAL_HTTPS\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> url.startswith(\u003Cspan class=\"hljs-string\">&#x27;http://&#x27;\u003C/span>):\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkType.EXTERNAL_HTTP\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> url.startswith(\u003Cspan class=\"hljs-string\">&#x27;#&#x27;\u003C/span>):\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkType.ANCHOR_LINK\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> url.startswith(\u003Cspan class=\"hljs-string\">&#x27;/&#x27;\u003C/span>):\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkType.INTERNAL_ABSOLUTE\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;://&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> url:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkType.EXTERNAL_HTTPS  \u003Cspan class=\"hljs-comment\"># Assume HTTPS for other protocols\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n            \u003Cspan class=\"hljs-comment\"># Check if it&#x27;s a file reference\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">any\u003C/span>(url.endswith(ext) \u003Cspan class=\"hljs-keyword\">for\u003C/span> ext \u003Cspan class=\"hljs-keyword\">in\u003C/span> [\u003Cspan class=\"hljs-string\">&#x27;.pdf&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;.doc&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;.zip&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;.png&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;.jpg&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;.svg&#x27;\u003C/span>]):\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkType.FILE_REFERENCE\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkType.INTERNAL_RELATIVE\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_resolve_relative_url\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, file_path: Path = \u003Cspan class=\"hljs-literal\">None\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Optional\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>]:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Resolve relative URLs to absolute file paths&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> file_path \u003Cspan class=\"hljs-keyword\">or\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> self.base_path:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-literal\">None\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n            \u003Cspan class=\"hljs-comment\"># Remove fragment identifiers for file resolution\u003C/span>\n            clean_url = url.split(\u003Cspan class=\"hljs-string\">&#x27;#&#x27;\u003C/span>)[\u003Cspan class=\"hljs-number\">0\u003C/span>]\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> clean_url:\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-built_in\">str\u003C/span>(file_path)  \u003Cspan class=\"hljs-comment\"># Same file anchor link\u003C/span>\n                \n            \u003Cspan class=\"hljs-comment\"># Resolve relative to the current file&#x27;s directory\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> file_path.is_absolute():\n                base_dir = file_path.parent\n            \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n                base_dir = self.base_path / file_path.parent\n            \n            resolved_path = (base_dir / clean_url).resolve()\n            \n            \u003Cspan class=\"hljs-comment\"># Ensure the resolved path is within the base path\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.base_path.resolve() \u003Cspan class=\"hljs-keyword\">in\u003C/span> resolved_path.parents \u003Cspan class=\"hljs-keyword\">or\u003C/span> resolved_path == self.base_path.resolve():\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-built_in\">str\u003C/span>(resolved_path)\n            \n        \u003Cspan class=\"hljs-keyword\">except\u003C/span> Exception:\n            \u003Cspan class=\"hljs-keyword\">pass\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-literal\">None\u003C/span>\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_get_line_number\u003C/span>(\u003Cspan class=\"hljs-params\">self, content: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, position: \u003Cspan class=\"hljs-built_in\">int\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-built_in\">int\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Get line number for a given character position&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> content[:position].count(\u003Cspan class=\"hljs-string\">&#x27;\\n&#x27;\u003C/span>) + \u003Cspan class=\"hljs-number\">1\u003C/span>\n\n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">validate_links\u003C/span>(\u003Cspan class=\"hljs-params\">self, links: \u003Cspan class=\"hljs-type\">Dict\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>, \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-type\">Dict\u003C/span>]], max_workers: \u003Cspan class=\"hljs-built_in\">int\u003C/span> = \u003Cspan class=\"hljs-number\">10\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Validate all extracted links&quot;&quot;&quot;\u003C/span>\n        validation_results = {\n            \u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>: {\n                \u003Cspan class=\"hljs-string\">&#x27;total_links&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">0\u003C/span>,\n                \u003Cspan class=\"hljs-string\">&#x27;valid_links&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">0\u003C/span>,\n                \u003Cspan class=\"hljs-string\">&#x27;broken_links&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">0\u003C/span>,\n                \u003Cspan class=\"hljs-string\">&#x27;redirect_links&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">0\u003C/span>,\n                \u003Cspan class=\"hljs-string\">&#x27;timeout_links&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">0\u003C/span>\n            },\n            \u003Cspan class=\"hljs-string\">&#x27;details&#x27;\u003C/span>: {\n                \u003Cspan class=\"hljs-string\">&#x27;internal_results&#x27;\u003C/span>: [],\n                \u003Cspan class=\"hljs-string\">&#x27;external_results&#x27;\u003C/span>: [],\n                \u003Cspan class=\"hljs-string\">&#x27;reference_results&#x27;\u003C/span>: []\n            },\n            \u003Cspan class=\"hljs-string\">&#x27;errors&#x27;\u003C/span>: []\n        }\n        \n        \u003Cspan class=\"hljs-comment\"># Collect all links for validation\u003C/span>\n        all_links = []\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> category, link_list \u003Cspan class=\"hljs-keyword\">in\u003C/span> links.items():\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> category != \u003Cspan class=\"hljs-string\">&#x27;reference_links&#x27;\u003C/span>:  \u003Cspan class=\"hljs-comment\"># Handle reference links separately\u003C/span>\n                all_links.extend(link_list)\n        \n        validation_results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;total_links&#x27;\u003C/span>] = \u003Cspan class=\"hljs-built_in\">len\u003C/span>(all_links)\n        \n        \u003Cspan class=\"hljs-comment\"># Validate internal links\u003C/span>\n        internal_links = [link \u003Cspan class=\"hljs-keyword\">for\u003C/span> link \u003Cspan class=\"hljs-keyword\">in\u003C/span> all_links \n                         \u003Cspan class=\"hljs-keyword\">if\u003C/span> link[\u003Cspan class=\"hljs-string\">&#x27;type&#x27;\u003C/span>] \u003Cspan class=\"hljs-keyword\">in\u003C/span> [LinkType.INTERNAL_RELATIVE, LinkType.INTERNAL_ABSOLUTE, \n                                           LinkType.FILE_REFERENCE]]\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> link \u003Cspan class=\"hljs-keyword\">in\u003C/span> internal_links:\n            result = self._validate_internal_link(link)\n            validation_results[\u003Cspan class=\"hljs-string\">&#x27;details&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;internal_results&#x27;\u003C/span>].append(result)\n            self._update_summary(validation_results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>], result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>])\n        \n        \u003Cspan class=\"hljs-comment\"># Validate external links with threading\u003C/span>\n        external_links = [link \u003Cspan class=\"hljs-keyword\">for\u003C/span> link \u003Cspan class=\"hljs-keyword\">in\u003C/span> all_links \n                         \u003Cspan class=\"hljs-keyword\">if\u003C/span> link[\u003Cspan class=\"hljs-string\">&#x27;type&#x27;\u003C/span>] \u003Cspan class=\"hljs-keyword\">in\u003C/span> [LinkType.EXTERNAL_HTTP, LinkType.EXTERNAL_HTTPS]]\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> external_links:\n            \u003Cspan class=\"hljs-keyword\">with\u003C/span> ThreadPoolExecutor(max_workers=max_workers) \u003Cspan class=\"hljs-keyword\">as\u003C/span> executor:\n                future_to_link = {\n                    executor.submit(self._validate_external_link, link): link \n                    \u003Cspan class=\"hljs-keyword\">for\u003C/span> link \u003Cspan class=\"hljs-keyword\">in\u003C/span> external_links\n                }\n                \n                \u003Cspan class=\"hljs-keyword\">for\u003C/span> future \u003Cspan class=\"hljs-keyword\">in\u003C/span> as_completed(future_to_link):\n                    \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n                        result = future.result()\n                        validation_results[\u003Cspan class=\"hljs-string\">&#x27;details&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;external_results&#x27;\u003C/span>].append(result)\n                        self._update_summary(validation_results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>], result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>])\n                    \u003Cspan class=\"hljs-keyword\">except\u003C/span> Exception \u003Cspan class=\"hljs-keyword\">as\u003C/span> e:\n                        link = future_to_link[future]\n                        validation_results[\u003Cspan class=\"hljs-string\">&#x27;errors&#x27;\u003C/span>].append({\n                            \u003Cspan class=\"hljs-string\">&#x27;link&#x27;\u003C/span>: link,\n                            \u003Cspan class=\"hljs-string\">&#x27;error&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">str\u003C/span>(e)\n                        })\n        \n        \u003Cspan class=\"hljs-comment\"># Validate reference links\u003C/span>\n        reference_links = links.get(\u003Cspan class=\"hljs-string\">&#x27;reference_links&#x27;\u003C/span>, [])\n        reference_definitions = {rd.get(\u003Cspan class=\"hljs-string\">&#x27;reference_id&#x27;\u003C/span>): rd \u003Cspan class=\"hljs-keyword\">for\u003C/span> rd \u003Cspan class=\"hljs-keyword\">in\u003C/span> links.get(\u003Cspan class=\"hljs-string\">&#x27;reference_definitions&#x27;\u003C/span>, [])}\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> ref_link \u003Cspan class=\"hljs-keyword\">in\u003C/span> reference_links:\n            result = self._validate_reference_link(ref_link, reference_definitions)\n            validation_results[\u003Cspan class=\"hljs-string\">&#x27;details&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;reference_results&#x27;\u003C/span>].append(result)\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] != LinkStatus.VALID:\n                validation_results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;broken_links&#x27;\u003C/span>] += \u003Cspan class=\"hljs-number\">1\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n                validation_results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;valid_links&#x27;\u003C/span>] += \u003Cspan class=\"hljs-number\">1\u003C/span>\n            validation_results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;total_links&#x27;\u003C/span>] += \u003Cspan class=\"hljs-number\">1\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> validation_results\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_validate_internal_link\u003C/span>(\u003Cspan class=\"hljs-params\">self, link: \u003Cspan class=\"hljs-type\">Dict\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Validate an internal link&quot;&quot;&quot;\u003C/span>\n        result = {\n            \u003Cspan class=\"hljs-string\">&#x27;link&#x27;\u003C/span>: link,\n            \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: LinkStatus.UNKNOWN,\n            \u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;resolved_path&#x27;\u003C/span>: link.get(\u003Cspan class=\"hljs-string\">&#x27;absolute_url&#x27;\u003C/span>)\n        }\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> link[\u003Cspan class=\"hljs-string\">&#x27;type&#x27;\u003C/span>] == LinkType.ANCHOR_LINK:\n            \u003Cspan class=\"hljs-comment\"># For anchor links, we&#x27;d need to check if the anchor exists in the document\u003C/span>\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.VALID\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">&#x27;Anchor link (not validated for target existence)&#x27;\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> result\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> link.get(\u003Cspan class=\"hljs-string\">&#x27;absolute_url&#x27;\u003C/span>):\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.BROKEN\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">&#x27;Could not resolve relative path&#x27;\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> result\n        \n        resolved_path = Path(link[\u003Cspan class=\"hljs-string\">&#x27;absolute_url&#x27;\u003C/span>])\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> resolved_path.exists():\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.VALID\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">&#x27;File exists&#x27;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.BROKEN\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">f&#x27;File not found: \u003Cspan class=\"hljs-subst\">{resolved_path}\u003C/span>&#x27;\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> result\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_validate_external_link\u003C/span>(\u003Cspan class=\"hljs-params\">self, link: \u003Cspan class=\"hljs-type\">Dict\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Validate an external link&quot;&quot;&quot;\u003C/span>\n        result = {\n            \u003Cspan class=\"hljs-string\">&#x27;link&#x27;\u003C/span>: link,\n            \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: LinkStatus.UNKNOWN,\n            \u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;response_code&#x27;\u003C/span>: \u003Cspan class=\"hljs-literal\">None\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;final_url&#x27;\u003C/span>: \u003Cspan class=\"hljs-literal\">None\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;response_time&#x27;\u003C/span>: \u003Cspan class=\"hljs-literal\">None\u003C/span>\n        }\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> link[\u003Cspan class=\"hljs-string\">&#x27;type&#x27;\u003C/span>] == LinkType.EMAIL_MAILTO:\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.VALID\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">&#x27;Email link (not validated)&#x27;\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> result\n        \n        start_time = time.time()\n        \n        \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n            response = self.session.head(link[\u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>], timeout=self.timeout, allow_redirects=\u003Cspan class=\"hljs-literal\">True\u003C/span>)\n            response_time = time.time() - start_time\n            \n            result[\u003Cspan class=\"hljs-string\">&#x27;response_code&#x27;\u003C/span>] = response.status_code\n            result[\u003Cspan class=\"hljs-string\">&#x27;final_url&#x27;\u003C/span>] = response.url\n            result[\u003Cspan class=\"hljs-string\">&#x27;response_time&#x27;\u003C/span>] = \u003Cspan class=\"hljs-built_in\">round\u003C/span>(response_time, \u003Cspan class=\"hljs-number\">2\u003C/span>)\n            \n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> response.status_code == \u003Cspan class=\"hljs-number\">200\u003C/span>:\n                result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.VALID\n                result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">&#x27;OK&#x27;\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">elif\u003C/span> \u003Cspan class=\"hljs-number\">300\u003C/span> &lt;= response.status_code &lt; \u003Cspan class=\"hljs-number\">400\u003C/span>:\n                result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.REDIRECT\n                result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">f&#x27;Redirects to \u003Cspan class=\"hljs-subst\">{response.url}\u003C/span>&#x27;\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n                result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.BROKEN\n                result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">f&#x27;HTTP \u003Cspan class=\"hljs-subst\">{response.status_code}\u003C/span>&#x27;\u003C/span>\n                \n        \u003Cspan class=\"hljs-keyword\">except\u003C/span> requests.exceptions.Timeout:\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.TIMEOUT\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">f&#x27;Timeout after \u003Cspan class=\"hljs-subst\">{self.timeout}\u003C/span>s&#x27;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">except\u003C/span> requests.exceptions.RequestException \u003Cspan class=\"hljs-keyword\">as\u003C/span> e:\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.BROKEN\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">f&#x27;Request failed: \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">str\u003C/span>(e)}\u003C/span>&#x27;\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> result\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_validate_reference_link\u003C/span>(\u003Cspan class=\"hljs-params\">self, ref_link: \u003Cspan class=\"hljs-type\">Dict\u003C/span>, reference_definitions: \u003Cspan class=\"hljs-type\">Dict\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Validate a reference-style link&quot;&quot;&quot;\u003C/span>\n        result = {\n            \u003Cspan class=\"hljs-string\">&#x27;link&#x27;\u003C/span>: ref_link,\n            \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: LinkStatus.UNKNOWN,\n            \u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C/span>\n        }\n        \n        ref_id = ref_link[\u003Cspan class=\"hljs-string\">&#x27;reference_id&#x27;\u003C/span>]\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> ref_id \u003Cspan class=\"hljs-keyword\">in\u003C/span> reference_definitions:\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.VALID\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">f&#x27;Reference found: \u003Cspan class=\"hljs-subst\">{reference_definitions[ref_id][\u003Cspan class=\"hljs-string\">&quot;url&quot;\u003C/span>]}\u003C/span>&#x27;\u003C/span>\n            result[\u003Cspan class=\"hljs-string\">&#x27;referenced_url&#x27;\u003C/span>] = reference_definitions[ref_id][\u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>]\n        \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n            result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] = LinkStatus.BROKEN\n            result[\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>] = \u003Cspan class=\"hljs-string\">f&#x27;Reference definition not found: [\u003Cspan class=\"hljs-subst\">{ref_id}\u003C/span>]&#x27;\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> result\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_update_summary\u003C/span>(\u003Cspan class=\"hljs-params\">self, summary: \u003Cspan class=\"hljs-type\">Dict\u003C/span>, status: LinkStatus\u003C/span>):\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Update validation summary counts&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> status == LinkStatus.VALID:\n            summary[\u003Cspan class=\"hljs-string\">&#x27;valid_links&#x27;\u003C/span>] += \u003Cspan class=\"hljs-number\">1\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> status == LinkStatus.BROKEN:\n            summary[\u003Cspan class=\"hljs-string\">&#x27;broken_links&#x27;\u003C/span>] += \u003Cspan class=\"hljs-number\">1\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> status == LinkStatus.REDIRECT:\n            summary[\u003Cspan class=\"hljs-string\">&#x27;redirect_links&#x27;\u003C/span>] += \u003Cspan class=\"hljs-number\">1\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> status == LinkStatus.TIMEOUT:\n            summary[\u003Cspan class=\"hljs-string\">&#x27;timeout_links&#x27;\u003C/span>] += \u003Cspan class=\"hljs-number\">1\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">validate_markdown_file\u003C/span>(\u003Cspan class=\"hljs-params\">file_path: Path\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n    \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Validate all links in a single markdown file&quot;&quot;&quot;\u003C/span>\n    analyzer = MarkdownLinkAnalyzer(base_path=file_path.parent)\n    \n    \u003Cspan class=\"hljs-keyword\">with\u003C/span> \u003Cspan class=\"hljs-built_in\">open\u003C/span>(file_path, \u003Cspan class=\"hljs-string\">&#x27;r&#x27;\u003C/span>, encoding=\u003Cspan class=\"hljs-string\">&#x27;utf-8&#x27;\u003C/span>) \u003Cspan class=\"hljs-keyword\">as\u003C/span> f:\n        content = f.read()\n    \n    \u003Cspan class=\"hljs-comment\"># Extract all links\u003C/span>\n    links = analyzer.extract_all_links(content, file_path)\n    \n    \u003Cspan class=\"hljs-comment\"># Validate all links\u003C/span>\n    validation_results = analyzer.validate_links(links)\n    \n    \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n        \u003Cspan class=\"hljs-string\">&#x27;file_path&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">str\u003C/span>(file_path),\n        \u003Cspan class=\"hljs-string\">&#x27;links&#x27;\u003C/span>: links,\n        \u003Cspan class=\"hljs-string\">&#x27;validation&#x27;\u003C/span>: validation_results\n    }\n\n\u003Cspan class=\"hljs-comment\"># Usage example\u003C/span>\n\u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">demonstrate_link_validation\u003C/span>():\n    \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Demonstrate link validation capabilities&quot;&quot;&quot;\u003C/span>\n    sample_markdown = \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;\n# Link Validation Examples\n\nHere are various types of links for testing:\n\n## Internal Links\n- [Relative link](../docs/README.md)\n- [Absolute link](/home/user/docs/guide.md)\n- [Same page anchor](#validation-results)\n\n## External Links\n- [Valid HTTPS link](https://blog.markdowntools.com)\n- [HTTP link](http://example.com)\n- [Broken link](https://thisdomaindoesnotexist123456.com)\n\n## Reference Links\n- [Reference style link][ref1]\n- [Another reference][ref2]\n\n## Other Link Types\n- &lt;https://autolink.example.com&gt;\n- Email: &lt;mailto:contact@example.com&gt;\n\n[ref1]: https://blog.markdowntools.com/posts/markdown-guide\n[ref2]: ./local-file.md\n\n## Validation Results\n\nResults will appear here.\n&quot;&quot;&quot;\u003C/span>\n    \n    \u003Cspan class=\"hljs-comment\"># Analyze the sample\u003C/span>\n    analyzer = MarkdownLinkAnalyzer()\n    links = analyzer.extract_all_links(sample_markdown)\n    \n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">&quot;=== Link Analysis Results ===&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-keyword\">for\u003C/span> category, link_list \u003Cspan class=\"hljs-keyword\">in\u003C/span> links.items():\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> link_list:\n            \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;\\n\u003Cspan class=\"hljs-subst\">{category.replace(\u003Cspan class=\"hljs-string\">&#x27;_&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27; &#x27;\u003C/span>).title()}\u003C/span>:&quot;\u003C/span>)\n            \u003Cspan class=\"hljs-keyword\">for\u003C/span> link \u003Cspan class=\"hljs-keyword\">in\u003C/span> link_list:\n                \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;  - \u003Cspan class=\"hljs-subst\">{link[\u003Cspan class=\"hljs-string\">&#x27;text&#x27;\u003C/span>][:\u003Cspan class=\"hljs-number\">30\u003C/span>]}\u003C/span>... → \u003Cspan class=\"hljs-subst\">{link[\u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>]}\u003C/span> (\u003Cspan class=\"hljs-subst\">{link[\u003Cspan class=\"hljs-string\">&#x27;type&#x27;\u003C/span>].value}\u003C/span>)&quot;\u003C/span>)\n    \n    \u003Cspan class=\"hljs-comment\"># Validate links\u003C/span>\n    validation = analyzer.validate_links(links)\n    \n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;\\n=== Validation Summary ===&quot;\u003C/span>)\n    summary = validation[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>]\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Total links: \u003Cspan class=\"hljs-subst\">{summary[\u003Cspan class=\"hljs-string\">&#x27;total_links&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Valid: \u003Cspan class=\"hljs-subst\">{summary[\u003Cspan class=\"hljs-string\">&#x27;valid_links&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Broken: \u003Cspan class=\"hljs-subst\">{summary[\u003Cspan class=\"hljs-string\">&#x27;broken_links&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Redirects: \u003Cspan class=\"hljs-subst\">{summary[\u003Cspan class=\"hljs-string\">&#x27;redirect_links&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Timeouts: \u003Cspan class=\"hljs-subst\">{summary[\u003Cspan class=\"hljs-string\">&#x27;timeout_links&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n\n\u003Cspan class=\"hljs-keyword\">if\u003C/span> __name__ == \u003Cspan class=\"hljs-string\">&quot;__main__&quot;\u003C/span>:\n    demonstrate_link_validation()\n\u003C/code>\u003C/pre>\u003Ch2 id=\"automated-testing-integration\">Automated Testing Integration\u003C/h2>\n\u003Ch3 id=\"cicd-pipeline-integration\">CI/CD Pipeline Integration\u003C/h3>\n\u003Cp>Implementing link validation in continuous integration workflows:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-yaml\">\u003Cspan class=\"hljs-comment\"># .github/workflows/link-validation.yml - Comprehensive link testing\u003C/span>\n\u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Link\u003C/span> \u003Cspan class=\"hljs-string\">Validation\u003C/span> \u003Cspan class=\"hljs-string\">and\u003C/span> \u003Cspan class=\"hljs-string\">Testing\u003C/span>\n\n\u003Cspan class=\"hljs-attr\">on:\u003C/span>\n  \u003Cspan class=\"hljs-attr\">push:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">branches:\u003C/span> [ \u003Cspan class=\"hljs-string\">main\u003C/span>, \u003Cspan class=\"hljs-string\">develop\u003C/span> ]\n    \u003Cspan class=\"hljs-attr\">paths:\u003C/span>\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;**/*.md&#x27;\u003C/span>\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;**/*.markdown&#x27;\u003C/span>\n  \u003Cspan class=\"hljs-attr\">pull_request:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">branches:\u003C/span> [ \u003Cspan class=\"hljs-string\">main\u003C/span>, \u003Cspan class=\"hljs-string\">develop\u003C/span> ]\n    \u003Cspan class=\"hljs-attr\">paths:\u003C/span>\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;**/*.md&#x27;\u003C/span>\n      \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;**/*.markdown&#x27;\u003C/span>\n  \u003Cspan class=\"hljs-attr\">schedule:\u003C/span>\n    \u003Cspan class=\"hljs-comment\"># Run weekly comprehensive link check\u003C/span>\n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">cron:\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;0 2 * * 1&#x27;\u003C/span>\n\n\u003Cspan class=\"hljs-attr\">jobs:\u003C/span>\n  \u003Cspan class=\"hljs-attr\">validate-internal-links:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">runs-on:\u003C/span> \u003Cspan class=\"hljs-string\">ubuntu-latest\u003C/span>\n    \n    \u003Cspan class=\"hljs-attr\">steps:\u003C/span>\n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Checkout\u003C/span> \u003Cspan class=\"hljs-string\">repository\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/checkout@v4\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">fetch-depth:\u003C/span> \u003Cspan class=\"hljs-number\">0\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Setup\u003C/span> \u003Cspan class=\"hljs-string\">Python\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/setup-python@v4\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">python-version:\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;3.9&#x27;\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Install\u003C/span> \u003Cspan class=\"hljs-string\">dependencies\u003C/span>\n      \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">|\n        pip install requests pathlib markdown\n\u003C/span>        \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Run\u003C/span> \u003Cspan class=\"hljs-string\">internal\u003C/span> \u003Cspan class=\"hljs-string\">link\u003C/span> \u003Cspan class=\"hljs-string\">validation\u003C/span>\n      \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">|\n        python scripts/validate-internal-links.py \\\n          --path . \\\n          --output reports/internal-links.json \\\n          --format json\n\u003C/span>    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Upload\u003C/span> \u003Cspan class=\"hljs-string\">internal\u003C/span> \u003Cspan class=\"hljs-string\">link\u003C/span> \u003Cspan class=\"hljs-string\">report\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/upload-artifact@v3\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">internal-link-report\u003C/span>\n        \u003Cspan class=\"hljs-attr\">path:\u003C/span> \u003Cspan class=\"hljs-string\">reports/internal-links.json\u003C/span>\n\n  \u003Cspan class=\"hljs-attr\">validate-external-links:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">runs-on:\u003C/span> \u003Cspan class=\"hljs-string\">ubuntu-latest\u003C/span>\n    \u003Cspan class=\"hljs-attr\">if:\u003C/span> \u003Cspan class=\"hljs-string\">github.event_name\u003C/span> \u003Cspan class=\"hljs-string\">==\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;schedule&#x27;\u003C/span> \u003Cspan class=\"hljs-string\">||\u003C/span> \u003Cspan class=\"hljs-string\">contains(github.event.head_commit.message,\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;[check-external]&#x27;\u003C/span>\u003Cspan class=\"hljs-string\">)\u003C/span>\n    \n    \u003Cspan class=\"hljs-attr\">steps:\u003C/span>\n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Checkout\u003C/span> \u003Cspan class=\"hljs-string\">repository\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/checkout@v4\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Setup\u003C/span> \u003Cspan class=\"hljs-string\">Node.js\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/setup-node@v4\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">node-version:\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;18&#x27;\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Install\u003C/span> \u003Cspan class=\"hljs-string\">markdown-link-check\u003C/span>\n      \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">npm\u003C/span> \u003Cspan class=\"hljs-string\">install\u003C/span> \u003Cspan class=\"hljs-string\">-g\u003C/span> \u003Cspan class=\"hljs-string\">markdown-link-check\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Create\u003C/span> \u003Cspan class=\"hljs-string\">link\u003C/span> \u003Cspan class=\"hljs-string\">check\u003C/span> \u003Cspan class=\"hljs-string\">configuration\u003C/span>\n      \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">|\n        cat &gt; .markdown-link-check.json &lt;&lt; EOF\n        {\n          &quot;ignorePatterns&quot;: [\n            {&quot;pattern&quot;: &quot;^http://localhost&quot;},\n            {&quot;pattern&quot;: &quot;^https://localhost&quot;},\n            {&quot;pattern&quot;: &quot;\\\\\\.example\\\\\\.com&quot;}\n          ],\n          &quot;replacementPatterns&quot;: [],\n          &quot;httpHeaders&quot;: [\n            {\n              &quot;urls&quot;: [&quot;https://github.com&quot;],\n              &quot;headers&quot;: {\n                &quot;Accept&quot;: &quot;text/html&quot;,\n                &quot;User-Agent&quot;: &quot;Mozilla/5.0&quot;\n              }\n            }\n          ],\n          &quot;timeout&quot;: &quot;10s&quot;,\n          &quot;retryOn429&quot;: true,\n          &quot;retryCount&quot;: 2,\n          &quot;fallbackRetryDelay&quot;: &quot;30s&quot;,\n          &quot;aliveStatusCodes&quot;: [200, 206, 999]\n        }\n        EOF\n\u003C/span>    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Check\u003C/span> \u003Cspan class=\"hljs-string\">external\u003C/span> \u003Cspan class=\"hljs-string\">links\u003C/span>\n      \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">|\n        find . -name &quot;*.md&quot; -not -path &quot;./node_modules/*&quot; \\\n          -exec markdown-link-check --config .markdown-link-check.json {} \\; \\\n          &gt; external-link-results.txt\n\u003C/span>    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Process\u003C/span> \u003Cspan class=\"hljs-string\">external\u003C/span> \u003Cspan class=\"hljs-string\">link\u003C/span> \u003Cspan class=\"hljs-string\">results\u003C/span>\n      \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">|\n        python scripts/process-external-link-results.py \\\n          external-link-results.txt \\\n          reports/external-links.json\n\u003C/span>    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Upload\u003C/span> \u003Cspan class=\"hljs-string\">external\u003C/span> \u003Cspan class=\"hljs-string\">link\u003C/span> \u003Cspan class=\"hljs-string\">report\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/upload-artifact@v3\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">external-link-report\u003C/span>\n        \u003Cspan class=\"hljs-attr\">path:\u003C/span> \u003Cspan class=\"hljs-string\">reports/external-links.json\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Create\u003C/span> \u003Cspan class=\"hljs-string\">issue\u003C/span> \u003Cspan class=\"hljs-string\">for\u003C/span> \u003Cspan class=\"hljs-string\">broken\u003C/span> \u003Cspan class=\"hljs-string\">external\u003C/span> \u003Cspan class=\"hljs-string\">links\u003C/span>\n      \u003Cspan class=\"hljs-attr\">if:\u003C/span> \u003Cspan class=\"hljs-string\">failure()\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/github-script@v6\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">script:\u003C/span> \u003Cspan class=\"hljs-string\">|\n          const fs = require(&#x27;fs&#x27;);\n\u003C/span>          \n          \u003Cspan class=\"hljs-string\">try\u003C/span> {\n            \u003Cspan class=\"hljs-string\">const\u003C/span> \u003Cspan class=\"hljs-string\">report\u003C/span> \u003Cspan class=\"hljs-string\">=\u003C/span> \u003Cspan class=\"hljs-string\">fs.readFileSync(&#x27;external-link-results.txt&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;utf8&#x27;\u003C/span>\u003Cspan class=\"hljs-string\">);\u003C/span>\n            \u003Cspan class=\"hljs-string\">const\u003C/span> \u003Cspan class=\"hljs-string\">brokenLinks\u003C/span> \u003Cspan class=\"hljs-string\">=\u003C/span> \u003Cspan class=\"hljs-string\">report.split(&#x27;\\n&#x27;)\u003C/span>\n              \u003Cspan class=\"hljs-string\">.filter(line\u003C/span> \u003Cspan class=\"hljs-string\">=&gt;\u003C/span> \u003Cspan class=\"hljs-string\">line.includes(&#x27;✖&#x27;))\u003C/span>\n              \u003Cspan class=\"hljs-string\">.slice(0\u003C/span>, \u003Cspan class=\"hljs-number\">20\u003C/span>\u003Cspan class=\"hljs-string\">);\u003C/span> \u003Cspan class=\"hljs-string\">//\u003C/span> \u003Cspan class=\"hljs-string\">Limit\u003C/span> \u003Cspan class=\"hljs-string\">to\u003C/span> \u003Cspan class=\"hljs-string\">first\u003C/span> \u003Cspan class=\"hljs-number\">20\u003C/span> \u003Cspan class=\"hljs-string\">broken\u003C/span> \u003Cspan class=\"hljs-string\">links\u003C/span>\n            \n            \u003Cspan class=\"hljs-string\">if\u003C/span> \u003Cspan class=\"hljs-string\">(brokenLinks.length\u003C/span> \u003Cspan class=\"hljs-string\">&gt;\u003C/span> \u003Cspan class=\"hljs-number\">0\u003C/span>\u003Cspan class=\"hljs-string\">)\u003C/span> {\n              \u003Cspan class=\"hljs-string\">github.rest.issues.create(\u003C/span>{\n                \u003Cspan class=\"hljs-attr\">owner:\u003C/span> \u003Cspan class=\"hljs-string\">context.repo.owner\u003C/span>,\n                \u003Cspan class=\"hljs-attr\">repo:\u003C/span> \u003Cspan class=\"hljs-string\">context.repo.repo\u003C/span>,\n                \u003Cspan class=\"hljs-attr\">title:\u003C/span> \u003Cspan class=\"hljs-string\">`🔗\u003C/span> \u003Cspan class=\"hljs-string\">Broken\u003C/span> \u003Cspan class=\"hljs-string\">External\u003C/span> \u003Cspan class=\"hljs-string\">Links\u003C/span> \u003Cspan class=\"hljs-string\">Detected\u003C/span> \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">$\u003C/span>{\u003Cspan class=\"hljs-string\">new\u003C/span> \u003Cspan class=\"hljs-string\">Date().toISOString().split(&#x27;T&#x27;)\u003C/span>[\u003Cspan class=\"hljs-number\">0\u003C/span>]}\u003Cspan class=\"hljs-string\">`\u003C/span>,\n                \u003Cspan class=\"hljs-attr\">body:\u003C/span> \u003Cspan class=\"hljs-string\">`\u003C/span>\n                \u003Cspan class=\"hljs-attr\">Automated link checking has detected broken external links:\u003C/span>\n                \n                \u003Cspan class=\"hljs-comment\">## Broken Links\u003C/span>\n                \u003Cspan class=\"hljs-string\">$\u003C/span>{\u003Cspan class=\"hljs-string\">brokenLinks.map(link\u003C/span> \u003Cspan class=\"hljs-string\">=&gt;\u003C/span> \u003Cspan class=\"hljs-string\">`-\u003C/span> \u003Cspan class=\"hljs-string\">$\u003C/span>{\u003Cspan class=\"hljs-string\">link\u003C/span>}\u003Cspan class=\"hljs-string\">`).join(&#x27;\\n&#x27;)\u003C/span>}\n                \n                \u003Cspan class=\"hljs-string\">$\u003C/span>{\u003Cspan class=\"hljs-string\">brokenLinks.length\u003C/span> \u003Cspan class=\"hljs-string\">&gt;=\u003C/span> \u003Cspan class=\"hljs-number\">20\u003C/span> \u003Cspan class=\"hljs-string\">?\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;\\n_Note: Only showing first 20 broken links. Check the full report for complete results._&#x27;\u003C/span> \u003Cspan class=\"hljs-string\">:\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C/span>}\n                \n                \u003Cspan class=\"hljs-comment\">## Next Steps\u003C/span>\n                \u003Cspan class=\"hljs-attr\">1. Review each broken link and determine if it should be:\u003C/span>\n                   \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">Fixed\u003C/span> \u003Cspan class=\"hljs-string\">with\u003C/span> \u003Cspan class=\"hljs-string\">the\u003C/span> \u003Cspan class=\"hljs-string\">correct\u003C/span> \u003Cspan class=\"hljs-string\">URL\u003C/span>\n                   \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">Removed\u003C/span> \u003Cspan class=\"hljs-string\">if\u003C/span> \u003Cspan class=\"hljs-literal\">no\u003C/span> \u003Cspan class=\"hljs-string\">longer\u003C/span> \u003Cspan class=\"hljs-string\">relevant\u003C/span>\n                   \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">Replaced\u003C/span> \u003Cspan class=\"hljs-string\">with\u003C/span> \u003Cspan class=\"hljs-string\">an\u003C/span> \u003Cspan class=\"hljs-string\">archive.org\u003C/span> \u003Cspan class=\"hljs-string\">link\u003C/span>\n                   \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-string\">Added\u003C/span> \u003Cspan class=\"hljs-string\">to\u003C/span> \u003Cspan class=\"hljs-string\">the\u003C/span> \u003Cspan class=\"hljs-string\">ignore\u003C/span> \u003Cspan class=\"hljs-string\">list\u003C/span> \u003Cspan class=\"hljs-string\">if\u003C/span> \u003Cspan class=\"hljs-string\">temporary\u003C/span>\n                \n                \u003Cspan class=\"hljs-string\">_This\u003C/span> \u003Cspan class=\"hljs-string\">issue\u003C/span> \u003Cspan class=\"hljs-string\">was\u003C/span> \u003Cspan class=\"hljs-string\">created\u003C/span> \u003Cspan class=\"hljs-string\">automatically\u003C/span> \u003Cspan class=\"hljs-string\">by\u003C/span> \u003Cspan class=\"hljs-string\">the\u003C/span> \u003Cspan class=\"hljs-string\">link\u003C/span> \u003Cspan class=\"hljs-string\">validation\u003C/span> \u003Cspan class=\"hljs-string\">workflow._\u003C/span>\n                \u003Cspan class=\"hljs-string\">`\u003C/span>,\n                \u003Cspan class=\"hljs-attr\">labels:\u003C/span> [\u003Cspan class=\"hljs-string\">&#x27;maintenance&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;broken-links&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;automated&#x27;\u003C/span>]\n              }\u003Cspan class=\"hljs-string\">);\u003C/span>\n            }\n          } \u003Cspan class=\"hljs-string\">catch\u003C/span> \u003Cspan class=\"hljs-string\">(error)\u003C/span> {\n            \u003Cspan class=\"hljs-string\">console.error(&#x27;Failed\u003C/span> \u003Cspan class=\"hljs-string\">to\u003C/span> \u003Cspan class=\"hljs-string\">create\u003C/span> \u003Cspan class=\"hljs-string\">issue:&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">error);\u003C/span>\n          }\n\n  \u003Cspan class=\"hljs-attr\">link-health-report:\u003C/span>\n    \u003Cspan class=\"hljs-attr\">runs-on:\u003C/span> \u003Cspan class=\"hljs-string\">ubuntu-latest\u003C/span>\n    \u003Cspan class=\"hljs-attr\">needs:\u003C/span> [\u003Cspan class=\"hljs-string\">validate-internal-links\u003C/span>, \u003Cspan class=\"hljs-string\">validate-external-links\u003C/span>]\n    \u003Cspan class=\"hljs-attr\">if:\u003C/span> \u003Cspan class=\"hljs-string\">always()\u003C/span>\n    \n    \u003Cspan class=\"hljs-attr\">steps:\u003C/span>\n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Checkout\u003C/span> \u003Cspan class=\"hljs-string\">repository\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/checkout@v4\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Download\u003C/span> \u003Cspan class=\"hljs-string\">link\u003C/span> \u003Cspan class=\"hljs-string\">reports\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/download-artifact@v3\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">path:\u003C/span> \u003Cspan class=\"hljs-string\">reports/\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Setup\u003C/span> \u003Cspan class=\"hljs-string\">Python\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/setup-python@v4\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">python-version:\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;3.9&#x27;\u003C/span>\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Generate\u003C/span> \u003Cspan class=\"hljs-string\">comprehensive\u003C/span> \u003Cspan class=\"hljs-string\">report\u003C/span>\n      \u003Cspan class=\"hljs-attr\">run:\u003C/span> \u003Cspan class=\"hljs-string\">|\n        python scripts/generate-link-health-report.py \\\n          --internal-report reports/internal-link-report/internal-links.json \\\n          --external-report reports/external-link-report/external-links.json \\\n          --output reports/link-health-summary.md\n\u003C/span>    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Post\u003C/span> \u003Cspan class=\"hljs-string\">report\u003C/span> \u003Cspan class=\"hljs-string\">to\u003C/span> \u003Cspan class=\"hljs-string\">PR\u003C/span>\n      \u003Cspan class=\"hljs-attr\">if:\u003C/span> \u003Cspan class=\"hljs-string\">github.event_name\u003C/span> \u003Cspan class=\"hljs-string\">==\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;pull_request&#x27;\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/github-script@v6\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">script:\u003C/span> \u003Cspan class=\"hljs-string\">|\n          const fs = require(&#x27;fs&#x27;);\n\u003C/span>          \n          \u003Cspan class=\"hljs-string\">try\u003C/span> {\n            \u003Cspan class=\"hljs-string\">const\u003C/span> \u003Cspan class=\"hljs-string\">report\u003C/span> \u003Cspan class=\"hljs-string\">=\u003C/span> \u003Cspan class=\"hljs-string\">fs.readFileSync(&#x27;reports/link-health-summary.md&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;utf8&#x27;\u003C/span>\u003Cspan class=\"hljs-string\">);\u003C/span>\n            \n            \u003Cspan class=\"hljs-string\">github.rest.issues.createComment(\u003C/span>{\n              \u003Cspan class=\"hljs-attr\">issue_number:\u003C/span> \u003Cspan class=\"hljs-string\">context.issue.number\u003C/span>,\n              \u003Cspan class=\"hljs-attr\">owner:\u003C/span> \u003Cspan class=\"hljs-string\">context.repo.owner\u003C/span>,\n              \u003Cspan class=\"hljs-attr\">repo:\u003C/span> \u003Cspan class=\"hljs-string\">context.repo.repo\u003C/span>,\n              \u003Cspan class=\"hljs-attr\">body:\u003C/span> \u003Cspan class=\"hljs-string\">report\u003C/span>\n            }\u003Cspan class=\"hljs-string\">);\u003C/span>\n          } \u003Cspan class=\"hljs-string\">catch\u003C/span> \u003Cspan class=\"hljs-string\">(error)\u003C/span> {\n            \u003Cspan class=\"hljs-string\">console.error(&#x27;Failed\u003C/span> \u003Cspan class=\"hljs-string\">to\u003C/span> \u003Cspan class=\"hljs-string\">post\u003C/span> \u003Cspan class=\"hljs-string\">report:&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">error);\u003C/span>\n          }\n    \n    \u003Cspan class=\"hljs-bullet\">-\u003C/span> \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">Upload\u003C/span> \u003Cspan class=\"hljs-string\">comprehensive\u003C/span> \u003Cspan class=\"hljs-string\">report\u003C/span>\n      \u003Cspan class=\"hljs-attr\">uses:\u003C/span> \u003Cspan class=\"hljs-string\">actions/upload-artifact@v3\u003C/span>\n      \u003Cspan class=\"hljs-attr\">with:\u003C/span>\n        \u003Cspan class=\"hljs-attr\">name:\u003C/span> \u003Cspan class=\"hljs-string\">link-health-report\u003C/span>\n        \u003Cspan class=\"hljs-attr\">path:\u003C/span> \u003Cspan class=\"hljs-string\">reports/link-health-summary.md\u003C/span>\n\u003C/code>\u003C/pre>\u003Ch3 id=\"custom-testing-scripts\">Custom Testing Scripts\u003C/h3>\n\u003Cp>Implementing specialized testing functionality:\u003C/p>\n\u003Cpre>\u003Ccode class=\"hljs language-python\">\u003Cspan class=\"hljs-comment\"># link_testing_suite.py - Comprehensive link testing suite\u003C/span>\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> json\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> time\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> asyncio\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> aiohttp\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> pathlib \u003Cspan class=\"hljs-keyword\">import\u003C/span> Path\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> typing \u003Cspan class=\"hljs-keyword\">import\u003C/span> \u003Cspan class=\"hljs-type\">Dict\u003C/span>, \u003Cspan class=\"hljs-type\">List\u003C/span>, \u003Cspan class=\"hljs-type\">Set\u003C/span>\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> dataclasses \u003Cspan class=\"hljs-keyword\">import\u003C/span> dataclass\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> datetime \u003Cspan class=\"hljs-keyword\">import\u003C/span> datetime, timedelta\n\n\u003Cspan class=\"hljs-meta\">@dataclass\u003C/span>\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">LinkTestConfig\u003C/span>:\n    max_concurrent: \u003Cspan class=\"hljs-built_in\">int\u003C/span> = \u003Cspan class=\"hljs-number\">20\u003C/span>\n    timeout: \u003Cspan class=\"hljs-built_in\">int\u003C/span> = \u003Cspan class=\"hljs-number\">10\u003C/span>\n    retry_count: \u003Cspan class=\"hljs-built_in\">int\u003C/span> = \u003Cspan class=\"hljs-number\">3\u003C/span>\n    retry_delay: \u003Cspan class=\"hljs-built_in\">float\u003C/span> = \u003Cspan class=\"hljs-number\">1.0\u003C/span>\n    ignore_patterns: \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>] = \u003Cspan class=\"hljs-literal\">None\u003C/span>\n    check_anchors: \u003Cspan class=\"hljs-built_in\">bool\u003C/span> = \u003Cspan class=\"hljs-literal\">True\u003C/span>\n    follow_redirects: \u003Cspan class=\"hljs-built_in\">bool\u003C/span> = \u003Cspan class=\"hljs-literal\">True\u003C/span>\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__post_init__\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.ignore_patterns \u003Cspan class=\"hljs-keyword\">is\u003C/span> \u003Cspan class=\"hljs-literal\">None\u003C/span>:\n            self.ignore_patterns = []\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">AdvancedLinkTester\u003C/span>:\n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__init__\u003C/span>(\u003Cspan class=\"hljs-params\">self, config: LinkTestConfig = \u003Cspan class=\"hljs-literal\">None\u003C/span>\u003C/span>):\n        self.config = config \u003Cspan class=\"hljs-keyword\">or\u003C/span> LinkTestConfig()\n        self.session = \u003Cspan class=\"hljs-literal\">None\u003C/span>\n        self.link_cache = {}\n        self.anchor_cache = {}\n        \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__aenter__\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        connector = aiohttp.TCPConnector(limit=self.config.max_concurrent)\n        timeout = aiohttp.ClientTimeout(total=self.config.timeout)\n        \n        self.session = aiohttp.ClientSession(\n            connector=connector,\n            timeout=timeout,\n            headers={\n                \u003Cspan class=\"hljs-string\">&#x27;User-Agent&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;AdvancedLinkTester/1.0 (+https://blog.markdowntools.com)&#x27;\u003C/span>\n            }\n        )\n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> self\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__aexit__\u003C/span>(\u003Cspan class=\"hljs-params\">self, exc_type, exc_val, exc_tb\u003C/span>):\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.session:\n            \u003Cspan class=\"hljs-keyword\">await\u003C/span> self.session.close()\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">test_link_with_retries\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Test a link with retry logic&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> attempt \u003Cspan class=\"hljs-keyword\">in\u003C/span> \u003Cspan class=\"hljs-built_in\">range\u003C/span>(self.config.retry_count):\n            \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n                result = \u003Cspan class=\"hljs-keyword\">await\u003C/span> self._test_single_link(url)\n                \n                \u003Cspan class=\"hljs-comment\"># If successful or non-retryable error, return\u003C/span>\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] \u003Cspan class=\"hljs-keyword\">in\u003C/span> [\u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>]:\n                    \u003Cspan class=\"hljs-keyword\">return\u003C/span> result\n                \n                \u003Cspan class=\"hljs-comment\"># Wait before retry\u003C/span>\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> attempt &lt; self.config.retry_count - \u003Cspan class=\"hljs-number\">1\u003C/span>:\n                    \u003Cspan class=\"hljs-keyword\">await\u003C/span> asyncio.sleep(self.config.retry_delay * (\u003Cspan class=\"hljs-number\">2\u003C/span> ** attempt))\n                    \n            \u003Cspan class=\"hljs-keyword\">except\u003C/span> Exception \u003Cspan class=\"hljs-keyword\">as\u003C/span> e:\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> attempt == self.config.retry_count - \u003Cspan class=\"hljs-number\">1\u003C/span>:\n                    \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n                        \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n                        \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;error&#x27;\u003C/span>,\n                        \u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">f&#x27;Failed after \u003Cspan class=\"hljs-subst\">{self.config.retry_count}\u003C/span> attempts: \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">str\u003C/span>(e)}\u003C/span>&#x27;\u003C/span>,\n                        \u003Cspan class=\"hljs-string\">&#x27;attempts&#x27;\u003C/span>: attempt + \u003Cspan class=\"hljs-number\">1\u003C/span>\n                    }\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n            \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n            \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;timeout&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">f&#x27;Failed after \u003Cspan class=\"hljs-subst\">{self.config.retry_count}\u003C/span> attempts&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;attempts&#x27;\u003C/span>: self.config.retry_count\n        }\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_test_single_link\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Test a single link&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-comment\"># Check cache first\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.link_cache:\n            cache_entry = self.link_cache[url]\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> datetime.now() - cache_entry[\u003Cspan class=\"hljs-string\">&#x27;timestamp&#x27;\u003C/span>] &lt; timedelta(hours=\u003Cspan class=\"hljs-number\">1\u003C/span>):\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> cache_entry[\u003Cspan class=\"hljs-string\">&#x27;result&#x27;\u003C/span>]\n        \n        start_time = time.time()\n        \n        \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n            \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">with\u003C/span> self.session.head(url, allow_redirects=self.config.follow_redirects) \u003Cspan class=\"hljs-keyword\">as\u003C/span> response:\n                response_time = time.time() - start_time\n                \n                result = {\n                    \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n                    \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">if\u003C/span> response.status == \u003Cspan class=\"hljs-number\">200\u003C/span> \u003Cspan class=\"hljs-keyword\">else\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>,\n                    \u003Cspan class=\"hljs-string\">&#x27;status_code&#x27;\u003C/span>: response.status,\n                    \u003Cspan class=\"hljs-string\">&#x27;final_url&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">str\u003C/span>(response.url),\n                    \u003Cspan class=\"hljs-string\">&#x27;response_time&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">round\u003C/span>(response_time, \u003Cspan class=\"hljs-number\">2\u003C/span>),\n                    \u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">f&#x27;HTTP \u003Cspan class=\"hljs-subst\">{response.status}\u003C/span>&#x27;\u003C/span>,\n                    \u003Cspan class=\"hljs-string\">&#x27;redirected&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">str\u003C/span>(response.url) != url\n                }\n                \n                \u003Cspan class=\"hljs-comment\"># Check for specific content if it&#x27;s an anchor link\u003C/span>\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;#&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> url \u003Cspan class=\"hljs-keyword\">and\u003C/span> self.config.check_anchors:\n                    anchor_result = \u003Cspan class=\"hljs-keyword\">await\u003C/span> self._check_anchor_exists(url, response)\n                    result.update(anchor_result)\n                \n                \u003Cspan class=\"hljs-comment\"># Cache the result\u003C/span>\n                self.link_cache[url] = {\n                    \u003Cspan class=\"hljs-string\">&#x27;result&#x27;\u003C/span>: result,\n                    \u003Cspan class=\"hljs-string\">&#x27;timestamp&#x27;\u003C/span>: datetime.now()\n                }\n                \n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> result\n                \n        \u003Cspan class=\"hljs-keyword\">except\u003C/span> asyncio.TimeoutError:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n                \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n                \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;timeout&#x27;\u003C/span>,\n                \u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">f&#x27;Timeout after \u003Cspan class=\"hljs-subst\">{self.config.timeout}\u003C/span>s&#x27;\u003C/span>,\n                \u003Cspan class=\"hljs-string\">&#x27;response_time&#x27;\u003C/span>: self.config.timeout\n            }\n        \u003Cspan class=\"hljs-keyword\">except\u003C/span> aiohttp.ClientError \u003Cspan class=\"hljs-keyword\">as\u003C/span> e:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n                \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n                \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>,\n                \u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">f&#x27;Client error: \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">str\u003C/span>(e)}\u003C/span>&#x27;\u003C/span>\n            }\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_check_anchor_exists\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, response\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Check if an anchor exists in the target page&quot;&quot;&quot;\u003C/span>\n        anchor_info = {\u003Cspan class=\"hljs-string\">&#x27;anchor_exists&#x27;\u003C/span>: \u003Cspan class=\"hljs-literal\">None\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;anchor_checked&#x27;\u003C/span>: \u003Cspan class=\"hljs-literal\">False\u003C/span>}\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;#&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> url:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> anchor_info\n        \n        anchor = url.split(\u003Cspan class=\"hljs-string\">&#x27;#&#x27;\u003C/span>, \u003Cspan class=\"hljs-number\">1\u003C/span>)[\u003Cspan class=\"hljs-number\">1\u003C/span>]\n        base_url = url.split(\u003Cspan class=\"hljs-string\">&#x27;#&#x27;\u003C/span>, \u003Cspan class=\"hljs-number\">1\u003C/span>)[\u003Cspan class=\"hljs-number\">0\u003C/span>]\n        \n        \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n            \u003Cspan class=\"hljs-comment\"># Get the full page content to check for anchor\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">with\u003C/span> self.session.get(base_url) \u003Cspan class=\"hljs-keyword\">as\u003C/span> full_response:\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> full_response.status == \u003Cspan class=\"hljs-number\">200\u003C/span>:\n                    content = \u003Cspan class=\"hljs-keyword\">await\u003C/span> full_response.text()\n                    anchor_info[\u003Cspan class=\"hljs-string\">&#x27;anchor_checked&#x27;\u003C/span>] = \u003Cspan class=\"hljs-literal\">True\u003C/span>\n                    anchor_info[\u003Cspan class=\"hljs-string\">&#x27;anchor_exists&#x27;\u003C/span>] = self._find_anchor_in_content(content, anchor)\n                    \n        \u003Cspan class=\"hljs-keyword\">except\u003C/span> Exception:\n            \u003Cspan class=\"hljs-comment\"># If we can&#x27;t check the anchor, just note that we couldn&#x27;t verify\u003C/span>\n            anchor_info[\u003Cspan class=\"hljs-string\">&#x27;anchor_checked&#x27;\u003C/span>] = \u003Cspan class=\"hljs-literal\">False\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> anchor_info\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_find_anchor_in_content\u003C/span>(\u003Cspan class=\"hljs-params\">self, content: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, anchor: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-built_in\">bool\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Find if an anchor exists in HTML content&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">import\u003C/span> re\n        \n        \u003Cspan class=\"hljs-comment\"># Common anchor patterns\u003C/span>\n        patterns = [\n            \u003Cspan class=\"hljs-string\">f&#x27;id=&quot;\u003Cspan class=\"hljs-subst\">{re.escape(anchor)}\u003C/span>&quot;&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">f&quot;id=&#x27;\u003Cspan class=\"hljs-subst\">{re.escape(anchor)}\u003C/span>&#x27;&quot;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">f&#x27;name=&quot;\u003Cspan class=\"hljs-subst\">{re.escape(anchor)}\u003C/span>&quot;&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">f&quot;name=&#x27;\u003Cspan class=\"hljs-subst\">{re.escape(anchor)}\u003C/span>&#x27;&quot;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">f&#x27;&lt;h[1-6][^&gt;]*id=&quot;\u003Cspan class=\"hljs-subst\">{re.escape(anchor)}\u003C/span>&quot;&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">f&quot;&lt;h[1-6][^&gt;]*id=&#x27;\u003Cspan class=\"hljs-subst\">{re.escape(anchor)}\u003C/span>&#x27;&quot;\u003C/span>\n        ]\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> pattern \u003Cspan class=\"hljs-keyword\">in\u003C/span> patterns:\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> re.search(pattern, content, re.IGNORECASE):\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-literal\">True\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-literal\">False\u003C/span>\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">test_links_batch\u003C/span>(\u003Cspan class=\"hljs-params\">self, urls: \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>]\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Test multiple links concurrently&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-comment\"># Filter out ignored patterns\u003C/span>\n        filtered_urls = [\n            url \u003Cspan class=\"hljs-keyword\">for\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> urls \n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> \u003Cspan class=\"hljs-built_in\">any\u003C/span>(pattern \u003Cspan class=\"hljs-keyword\">in\u003C/span> url \u003Cspan class=\"hljs-keyword\">for\u003C/span> pattern \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.config.ignore_patterns)\n        ]\n        \n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Testing \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">len\u003C/span>(filtered_urls)}\u003C/span> links (filtered \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">len\u003C/span>(urls) - \u003Cspan class=\"hljs-built_in\">len\u003C/span>(filtered_urls)}\u003C/span>)...&quot;\u003C/span>)\n        \n        \u003Cspan class=\"hljs-comment\"># Create semaphore to limit concurrent requests\u003C/span>\n        semaphore = asyncio.Semaphore(self.config.max_concurrent)\n        \n        \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">test_with_semaphore\u003C/span>(\u003Cspan class=\"hljs-params\">url\u003C/span>):\n            \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">with\u003C/span> semaphore:\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-keyword\">await\u003C/span> self.test_link_with_retries(url)\n        \n        \u003Cspan class=\"hljs-comment\"># Run tests concurrently\u003C/span>\n        tasks = [test_with_semaphore(url) \u003Cspan class=\"hljs-keyword\">for\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> filtered_urls]\n        results = \u003Cspan class=\"hljs-keyword\">await\u003C/span> asyncio.gather(*tasks, return_exceptions=\u003Cspan class=\"hljs-literal\">True\u003C/span>)\n        \n        \u003Cspan class=\"hljs-comment\"># Process results\u003C/span>\n        successful_results = []\n        errors = []\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> i, result \u003Cspan class=\"hljs-keyword\">in\u003C/span> \u003Cspan class=\"hljs-built_in\">enumerate\u003C/span>(results):\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">isinstance\u003C/span>(result, Exception):\n                errors.append({\n                    \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: filtered_urls[i],\n                    \u003Cspan class=\"hljs-string\">&#x27;error&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">str\u003C/span>(result)\n                })\n            \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n                successful_results.append(result)\n        \n        \u003Cspan class=\"hljs-comment\"># Generate summary\u003C/span>\n        valid_count = \u003Cspan class=\"hljs-built_in\">sum\u003C/span>(\u003Cspan class=\"hljs-number\">1\u003C/span> \u003Cspan class=\"hljs-keyword\">for\u003C/span> r \u003Cspan class=\"hljs-keyword\">in\u003C/span> successful_results \u003Cspan class=\"hljs-keyword\">if\u003C/span> r[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] == \u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span>)\n        broken_count = \u003Cspan class=\"hljs-built_in\">sum\u003C/span>(\u003Cspan class=\"hljs-number\">1\u003C/span> \u003Cspan class=\"hljs-keyword\">for\u003C/span> r \u003Cspan class=\"hljs-keyword\">in\u003C/span> successful_results \u003Cspan class=\"hljs-keyword\">if\u003C/span> r[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] == \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>)\n        timeout_count = \u003Cspan class=\"hljs-built_in\">sum\u003C/span>(\u003Cspan class=\"hljs-number\">1\u003C/span> \u003Cspan class=\"hljs-keyword\">for\u003C/span> r \u003Cspan class=\"hljs-keyword\">in\u003C/span> successful_results \u003Cspan class=\"hljs-keyword\">if\u003C/span> r[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] == \u003Cspan class=\"hljs-string\">&#x27;timeout&#x27;\u003C/span>)\n        error_count = \u003Cspan class=\"hljs-built_in\">len\u003C/span>(errors)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n            \u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>: {\n                \u003Cspan class=\"hljs-string\">&#x27;total_tested&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">len\u003C/span>(filtered_urls),\n                \u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span>: valid_count,\n                \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>: broken_count,\n                \u003Cspan class=\"hljs-string\">&#x27;timeout&#x27;\u003C/span>: timeout_count,\n                \u003Cspan class=\"hljs-string\">&#x27;errors&#x27;\u003C/span>: error_count,\n                \u003Cspan class=\"hljs-string\">&#x27;success_rate&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">round\u003C/span>(valid_count / \u003Cspan class=\"hljs-built_in\">len\u003C/span>(filtered_urls) * \u003Cspan class=\"hljs-number\">100\u003C/span>, \u003Cspan class=\"hljs-number\">2\u003C/span>) \u003Cspan class=\"hljs-keyword\">if\u003C/span> filtered_urls \u003Cspan class=\"hljs-keyword\">else\u003C/span> \u003Cspan class=\"hljs-number\">0\u003C/span>\n            },\n            \u003Cspan class=\"hljs-string\">&#x27;results&#x27;\u003C/span>: successful_results,\n            \u003Cspan class=\"hljs-string\">&#x27;errors&#x27;\u003C/span>: errors,\n            \u003Cspan class=\"hljs-string\">&#x27;cache_hits&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">len\u003C/span>([url \u003Cspan class=\"hljs-keyword\">for\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> filtered_urls \u003Cspan class=\"hljs-keyword\">if\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.link_cache])\n        }\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">LinkHealthMonitor\u003C/span>:\n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__init__\u003C/span>(\u003Cspan class=\"hljs-params\">self, base_path: Path\u003C/span>):\n        self.base_path = base_path\n        self.history_file = base_path / \u003Cspan class=\"hljs-string\">&#x27;.link-health-history.json&#x27;\u003C/span>\n        self.load_history()\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">load_history\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Load link health history&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.history_file.exists():\n            \u003Cspan class=\"hljs-keyword\">with\u003C/span> \u003Cspan class=\"hljs-built_in\">open\u003C/span>(self.history_file, \u003Cspan class=\"hljs-string\">&#x27;r&#x27;\u003C/span>) \u003Cspan class=\"hljs-keyword\">as\u003C/span> f:\n                self.history = json.load(f)\n        \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n            self.history = {\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>: [], \u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>: {}}\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">save_history\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Save link health history&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">with\u003C/span> \u003Cspan class=\"hljs-built_in\">open\u003C/span>(self.history_file, \u003Cspan class=\"hljs-string\">&#x27;w&#x27;\u003C/span>) \u003Cspan class=\"hljs-keyword\">as\u003C/span> f:\n            json.dump(self.history, f, indent=\u003Cspan class=\"hljs-number\">2\u003C/span>, default=\u003Cspan class=\"hljs-built_in\">str\u003C/span>)\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">record_check\u003C/span>(\u003Cspan class=\"hljs-params\">self, results: \u003Cspan class=\"hljs-type\">Dict\u003C/span>\u003C/span>):\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Record the results of a link check&quot;&quot;&quot;\u003C/span>\n        check_record = {\n            \u003Cspan class=\"hljs-string\">&#x27;timestamp&#x27;\u003C/span>: datetime.now().isoformat(),\n            \u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>: results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>],\n            \u003Cspan class=\"hljs-string\">&#x27;broken_links&#x27;\u003C/span>: [r[\u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>] \u003Cspan class=\"hljs-keyword\">for\u003C/span> r \u003Cspan class=\"hljs-keyword\">in\u003C/span> results[\u003Cspan class=\"hljs-string\">&#x27;results&#x27;\u003C/span>] \u003Cspan class=\"hljs-keyword\">if\u003C/span> r[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] == \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>]\n        }\n        \n        self.history[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>].append(check_record)\n        \n        \u003Cspan class=\"hljs-comment\"># Update individual link status\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> result \u003Cspan class=\"hljs-keyword\">in\u003C/span> results[\u003Cspan class=\"hljs-string\">&#x27;results&#x27;\u003C/span>]:\n            url = result[\u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>]\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> url \u003Cspan class=\"hljs-keyword\">not\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.history[\u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>]:\n                self.history[\u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>][url] = {\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>: []}\n            \n            self.history[\u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>][url][\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>].append({\n                \u003Cspan class=\"hljs-string\">&#x27;timestamp&#x27;\u003C/span>: datetime.now().isoformat(),\n                \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: result[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>],\n                \u003Cspan class=\"hljs-string\">&#x27;status_code&#x27;\u003C/span>: result.get(\u003Cspan class=\"hljs-string\">&#x27;status_code&#x27;\u003C/span>),\n                \u003Cspan class=\"hljs-string\">&#x27;response_time&#x27;\u003C/span>: result.get(\u003Cspan class=\"hljs-string\">&#x27;response_time&#x27;\u003C/span>)\n            })\n            \n            \u003Cspan class=\"hljs-comment\"># Keep only last 10 checks per link\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">len\u003C/span>(self.history[\u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>][url][\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>]) &gt; \u003Cspan class=\"hljs-number\">10\u003C/span>:\n                self.history[\u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>][url][\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>] = \\\n                    self.history[\u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>][url][\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>][-\u003Cspan class=\"hljs-number\">10\u003C/span>:]\n        \n        \u003Cspan class=\"hljs-comment\"># Keep only last 50 overall checks\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">len\u003C/span>(self.history[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>]) &gt; \u003Cspan class=\"hljs-number\">50\u003C/span>:\n            self.history[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>] = self.history[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>][-\u003Cspan class=\"hljs-number\">50\u003C/span>:]\n        \n        self.save_history()\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">generate_health_report\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Generate a health report based on historical data&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> self.history[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>]:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\u003Cspan class=\"hljs-string\">&#x27;message&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;No historical data available&#x27;\u003C/span>}\n        \n        latest_check = self.history[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>][-\u003Cspan class=\"hljs-number\">1\u003C/span>]\n        \n        \u003Cspan class=\"hljs-comment\"># Find consistently broken links\u003C/span>\n        consistently_broken = []\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> url, status \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.history[\u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>].items():\n            recent_checks = status[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>][-\u003Cspan class=\"hljs-number\">5\u003C/span>:]  \u003Cspan class=\"hljs-comment\"># Last 5 checks\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">len\u003C/span>(recent_checks) &gt;= \u003Cspan class=\"hljs-number\">3\u003C/span> \u003Cspan class=\"hljs-keyword\">and\u003C/span> \u003Cspan class=\"hljs-built_in\">all\u003C/span>(c[\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] == \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">for\u003C/span> c \u003Cspan class=\"hljs-keyword\">in\u003C/span> recent_checks):\n                consistently_broken.append(url)\n        \n        \u003Cspan class=\"hljs-comment\"># Find recently fixed links\u003C/span>\n        recently_fixed = []\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> url, status \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.history[\u003Cspan class=\"hljs-string\">&#x27;link_status&#x27;\u003C/span>].items():\n            checks = status[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>]\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">len\u003C/span>(checks) &gt;= \u003Cspan class=\"hljs-number\">2\u003C/span>:\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> checks[-\u003Cspan class=\"hljs-number\">1\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] == \u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">and\u003C/span> checks[-\u003Cspan class=\"hljs-number\">2\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>] == \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>:\n                    recently_fixed.append(url)\n        \n        \u003Cspan class=\"hljs-comment\"># Calculate trend\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">len\u003C/span>(self.history[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>]) &gt;= \u003Cspan class=\"hljs-number\">2\u003C/span>:\n            current_success = latest_check[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;success_rate&#x27;\u003C/span>]\n            previous_success = self.history[\u003Cspan class=\"hljs-string\">&#x27;checks&#x27;\u003C/span>][-\u003Cspan class=\"hljs-number\">2\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;success_rate&#x27;\u003C/span>]\n            trend = current_success - previous_success\n        \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n            trend = \u003Cspan class=\"hljs-number\">0\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n            \u003Cspan class=\"hljs-string\">&#x27;latest_check&#x27;\u003C/span>: latest_check,\n            \u003Cspan class=\"hljs-string\">&#x27;trend&#x27;\u003C/span>: {\n                \u003Cspan class=\"hljs-string\">&#x27;success_rate_change&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">round\u003C/span>(trend, \u003Cspan class=\"hljs-number\">2\u003C/span>),\n                \u003Cspan class=\"hljs-string\">&#x27;direction&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;improving&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">if\u003C/span> trend &gt; \u003Cspan class=\"hljs-number\">0\u003C/span> \u003Cspan class=\"hljs-keyword\">else\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;declining&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">if\u003C/span> trend &lt; \u003Cspan class=\"hljs-number\">0\u003C/span> \u003Cspan class=\"hljs-keyword\">else\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;stable&#x27;\u003C/span>\n            },\n            \u003Cspan class=\"hljs-string\">&#x27;problem_links&#x27;\u003C/span>: {\n                \u003Cspan class=\"hljs-string\">&#x27;consistently_broken&#x27;\u003C/span>: consistently_broken,\n                \u003Cspan class=\"hljs-string\">&#x27;recently_fixed&#x27;\u003C/span>: recently_fixed\n            },\n            \u003Cspan class=\"hljs-string\">&#x27;recommendations&#x27;\u003C/span>: self._generate_recommendations(consistently_broken, trend)\n        }\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_generate_recommendations\u003C/span>(\u003Cspan class=\"hljs-params\">self, consistently_broken: \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>], trend: \u003Cspan class=\"hljs-built_in\">float\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>]:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Generate actionable recommendations&quot;&quot;&quot;\u003C/span>\n        recommendations = []\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> consistently_broken:\n            recommendations.append(\n                \u003Cspan class=\"hljs-string\">f&quot;Address \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">len\u003C/span>(consistently_broken)}\u003C/span> consistently broken links that have failed multiple checks&quot;\u003C/span>\n            )\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> trend &lt; -\u003Cspan class=\"hljs-number\">5\u003C/span>:\n            recommendations.append(\n                \u003Cspan class=\"hljs-string\">&quot;Link health is declining. Consider investigating external dependencies&quot;\u003C/span>\n            )\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> consistently_broken \u003Cspan class=\"hljs-keyword\">and\u003C/span> trend &gt;= \u003Cspan class=\"hljs-number\">0\u003C/span>:\n            recommendations.append(\n                \u003Cspan class=\"hljs-string\">&quot;Link health is good. Continue regular monitoring&quot;\u003C/span>\n            )\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> recommendations\n\n\u003Cspan class=\"hljs-comment\"># Usage example\u003C/span>\n\u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">run_comprehensive_link_test\u003C/span>():\n    \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Run a comprehensive link test on markdown files&quot;&quot;&quot;\u003C/span>\n    config = LinkTestConfig(\n        max_concurrent=\u003Cspan class=\"hljs-number\">10\u003C/span>,\n        timeout=\u003Cspan class=\"hljs-number\">15\u003C/span>,\n        retry_count=\u003Cspan class=\"hljs-number\">2\u003C/span>,\n        ignore_patterns=[\u003Cspan class=\"hljs-string\">&#x27;localhost&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;.example.com&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;tempurl&#x27;\u003C/span>]\n    )\n    \n    \u003Cspan class=\"hljs-comment\"># Find all markdown files\u003C/span>\n    markdown_files = \u003Cspan class=\"hljs-built_in\">list\u003C/span>(Path(\u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C/span>).glob(\u003Cspan class=\"hljs-string\">&#x27;**/*.md&#x27;\u003C/span>))\n    \n    \u003Cspan class=\"hljs-comment\"># Extract all external links\u003C/span>\n    analyzer = MarkdownLinkAnalyzer()\n    all_external_links = \u003Cspan class=\"hljs-built_in\">set\u003C/span>()\n    \n    \u003Cspan class=\"hljs-keyword\">for\u003C/span> md_file \u003Cspan class=\"hljs-keyword\">in\u003C/span> markdown_files:\n        \u003Cspan class=\"hljs-keyword\">with\u003C/span> \u003Cspan class=\"hljs-built_in\">open\u003C/span>(md_file, \u003Cspan class=\"hljs-string\">&#x27;r&#x27;\u003C/span>, encoding=\u003Cspan class=\"hljs-string\">&#x27;utf-8&#x27;\u003C/span>) \u003Cspan class=\"hljs-keyword\">as\u003C/span> f:\n            content = f.read()\n        \n        links = analyzer.extract_all_links(content, md_file)\n        \n        \u003Cspan class=\"hljs-comment\"># Collect external links\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> category, link_list \u003Cspan class=\"hljs-keyword\">in\u003C/span> links.items():\n            \u003Cspan class=\"hljs-keyword\">for\u003C/span> link \u003Cspan class=\"hljs-keyword\">in\u003C/span> link_list:\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> link[\u003Cspan class=\"hljs-string\">&#x27;type&#x27;\u003C/span>] \u003Cspan class=\"hljs-keyword\">in\u003C/span> [LinkType.EXTERNAL_HTTP, LinkType.EXTERNAL_HTTPS]:\n                    all_external_links.add(link[\u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>])\n    \n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Found \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">len\u003C/span>(all_external_links)}\u003C/span> unique external links&quot;\u003C/span>)\n    \n    \u003Cspan class=\"hljs-comment\"># Test all external links\u003C/span>\n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">with\u003C/span> AdvancedLinkTester(config) \u003Cspan class=\"hljs-keyword\">as\u003C/span> tester:\n        results = \u003Cspan class=\"hljs-keyword\">await\u003C/span> tester.test_links_batch(\u003Cspan class=\"hljs-built_in\">list\u003C/span>(all_external_links))\n    \n    \u003Cspan class=\"hljs-comment\"># Record results in health monitor\u003C/span>\n    monitor = LinkHealthMonitor(Path(\u003Cspan class=\"hljs-string\">&#x27;.&#x27;\u003C/span>))\n    monitor.record_check(results)\n    \n    \u003Cspan class=\"hljs-comment\"># Generate health report\u003C/span>\n    health_report = monitor.generate_health_report()\n    \n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">&quot;=== Link Health Summary ===&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Total links tested: \u003Cspan class=\"hljs-subst\">{results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;total_tested&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Valid: \u003Cspan class=\"hljs-subst\">{results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Broken: \u003Cspan class=\"hljs-subst\">{results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Success rate: \u003Cspan class=\"hljs-subst\">{results[\u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;success_rate&#x27;\u003C/span>]}\u003C/span>%&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Trend: \u003Cspan class=\"hljs-subst\">{health_report[\u003Cspan class=\"hljs-string\">&#x27;trend&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;direction&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \n    \u003Cspan class=\"hljs-keyword\">if\u003C/span> health_report[\u003Cspan class=\"hljs-string\">&#x27;problem_links&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;consistently_broken&#x27;\u003C/span>]:\n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;\\nConsistently broken links:&quot;\u003C/span>)\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> health_report[\u003Cspan class=\"hljs-string\">&#x27;problem_links&#x27;\u003C/span>][\u003Cspan class=\"hljs-string\">&#x27;consistently_broken&#x27;\u003C/span>]:\n            \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;  - \u003Cspan class=\"hljs-subst\">{url}\u003C/span>&quot;\u003C/span>)\n    \n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;\\nRecommendations:&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-keyword\">for\u003C/span> rec \u003Cspan class=\"hljs-keyword\">in\u003C/span> health_report[\u003Cspan class=\"hljs-string\">&#x27;recommendations&#x27;\u003C/span>]:\n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;  - \u003Cspan class=\"hljs-subst\">{rec}\u003C/span>&quot;\u003C/span>)\n\n\u003Cspan class=\"hljs-keyword\">if\u003C/span> __name__ == \u003Cspan class=\"hljs-string\">&quot;__main__&quot;\u003C/span>:\n    asyncio.run(run_comprehensive_link_test())\n\u003C/code>\u003C/pre>\u003Ch2 id=\"link-monitoring-and-maintenance\">Link Monitoring and Maintenance\u003C/h2>\n\u003Cp>Link validation integrates seamlessly with comprehensive documentation workflows. When combined with \u003Ca href=\"/blog/markdown-automation-workflows-complete-guide\">automation systems and CI/CD pipelines\u003C/a>, systematic link monitoring ensures that documentation remains current and accessible while reducing maintenance overhead through intelligent validation scheduling and automated issue detection.\u003C/p>\n\u003Cp>For sophisticated content management, link validation works effectively with \u003Ca href=\"/blog/markdown-progressive-web-app-documentation-complete-guide\">Progressive Web App documentation systems\u003C/a> to ensure that offline caching preserves valid link relationships while providing enhanced user experiences for navigating complex documentation hierarchies even without internet connectivity.\u003C/p>\n\u003Cp>When building comprehensive content architectures, proper link validation complements \u003Ca href=\"/blog/markdown-version-control-git-integration-complete-guide\">version control and Git integration systems\u003C/a> by maintaining link integrity across branches, ensuring that content merges preserve cross-references, and coordinating link updates with content restructuring operations.\u003C/p>\n\u003Ch2 id=\"advanced-validation-strategies\">Advanced Validation Strategies\u003C/h2>\n\u003Ch3 id=\"performance-optimized-testing\">Performance-Optimized Testing\u003C/h3>\n\u003Cpre>\u003Ccode class=\"hljs language-python\">\u003Cspan class=\"hljs-comment\"># performance_link_tester.py - Optimized link testing for large repositories\u003C/span>\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> asyncio\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> hashlib\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> pickle\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> dataclasses \u003Cspan class=\"hljs-keyword\">import\u003C/span> dataclass\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> pathlib \u003Cspan class=\"hljs-keyword\">import\u003C/span> Path\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> typing \u003Cspan class=\"hljs-keyword\">import\u003C/span> \u003Cspan class=\"hljs-type\">Dict\u003C/span>, \u003Cspan class=\"hljs-type\">List\u003C/span>, \u003Cspan class=\"hljs-type\">Optional\u003C/span>\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> aioredis\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> sqlite3\n\n\u003Cspan class=\"hljs-meta\">@dataclass\u003C/span>\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">CacheConfig\u003C/span>:\n    cache_ttl: \u003Cspan class=\"hljs-built_in\">int\u003C/span> = \u003Cspan class=\"hljs-number\">3600\u003C/span>  \u003Cspan class=\"hljs-comment\"># 1 hour\u003C/span>\n    use_redis: \u003Cspan class=\"hljs-built_in\">bool\u003C/span> = \u003Cspan class=\"hljs-literal\">False\u003C/span>\n    redis_url: \u003Cspan class=\"hljs-built_in\">str\u003C/span> = \u003Cspan class=\"hljs-string\">&quot;redis://localhost:6379&quot;\u003C/span>\n    sqlite_path: \u003Cspan class=\"hljs-built_in\">str\u003C/span> = \u003Cspan class=\"hljs-string\">&quot;.link_cache.db&quot;\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">PerformanceLinkValidator\u003C/span>:\n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__init__\u003C/span>(\u003Cspan class=\"hljs-params\">self, cache_config: CacheConfig = \u003Cspan class=\"hljs-literal\">None\u003C/span>\u003C/span>):\n        self.cache_config = cache_config \u003Cspan class=\"hljs-keyword\">or\u003C/span> CacheConfig()\n        self.redis = \u003Cspan class=\"hljs-literal\">None\u003C/span>\n        self.sqlite_conn = \u003Cspan class=\"hljs-literal\">None\u003C/span>\n        \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">setup_cache\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Initialize caching backend&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.cache_config.use_redis:\n            \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n                self.redis = \u003Cspan class=\"hljs-keyword\">await\u003C/span> aioredis.from_url(self.cache_config.redis_url)\n            \u003Cspan class=\"hljs-keyword\">except\u003C/span> Exception:\n                \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">&quot;Redis not available, falling back to SQLite&quot;\u003C/span>)\n                self._setup_sqlite()\n        \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n            self._setup_sqlite()\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_setup_sqlite\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Initialize SQLite cache&quot;&quot;&quot;\u003C/span>\n        self.sqlite_conn = sqlite3.connect(self.cache_config.sqlite_path)\n        self.sqlite_conn.execute(\u003Cspan class=\"hljs-string\">&#x27;&#x27;&#x27;\n            CREATE TABLE IF NOT EXISTS link_cache (\n                url_hash TEXT PRIMARY KEY,\n                url TEXT,\n                result BLOB,\n                timestamp INTEGER\n            )\n        &#x27;&#x27;&#x27;\u003C/span>)\n        self.sqlite_conn.commit()\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">get_cached_result\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Optional\u003C/span>[\u003Cspan class=\"hljs-type\">Dict\u003C/span>]:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Get cached validation result&quot;&quot;&quot;\u003C/span>\n        url_hash = hashlib.md5(url.encode()).hexdigest()\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.redis:\n            cached = \u003Cspan class=\"hljs-keyword\">await\u003C/span> self.redis.get(\u003Cspan class=\"hljs-string\">f&quot;link:\u003Cspan class=\"hljs-subst\">{url_hash}\u003C/span>&quot;\u003C/span>)\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> cached:\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> pickle.loads(cached)\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> self.sqlite_conn:\n            cursor = self.sqlite_conn.cursor()\n            cursor.execute(\n                \u003Cspan class=\"hljs-string\">&quot;SELECT result FROM link_cache WHERE url_hash = ? AND timestamp &gt; ?&quot;\u003C/span>,\n                (url_hash, time.time() - self.cache_config.cache_ttl)\n            )\n            row = cursor.fetchone()\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> row:\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> pickle.loads(row[\u003Cspan class=\"hljs-number\">0\u003C/span>])\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-literal\">None\u003C/span>\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">cache_result\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, result: \u003Cspan class=\"hljs-type\">Dict\u003C/span>\u003C/span>):\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Cache validation result&quot;&quot;&quot;\u003C/span>\n        url_hash = hashlib.md5(url.encode()).hexdigest()\n        \n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.redis:\n            \u003Cspan class=\"hljs-keyword\">await\u003C/span> self.redis.setex(\n                \u003Cspan class=\"hljs-string\">f&quot;link:\u003Cspan class=\"hljs-subst\">{url_hash}\u003C/span>&quot;\u003C/span>,\n                self.cache_config.cache_ttl,\n                pickle.dumps(result)\n            )\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> self.sqlite_conn:\n            self.sqlite_conn.execute(\n                \u003Cspan class=\"hljs-string\">&quot;INSERT OR REPLACE INTO link_cache (url_hash, url, result, timestamp) VALUES (?, ?, ?, ?)&quot;\u003C/span>,\n                (url_hash, url, pickle.dumps(result), time.time())\n            )\n            self.sqlite_conn.commit()\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">validate_with_smart_batching\u003C/span>(\u003Cspan class=\"hljs-params\">self, urls: \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>]\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Validate URLs with intelligent batching and caching&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-comment\"># Separate cached and uncached URLs\u003C/span>\n        cached_results = []\n        uncached_urls = []\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> urls:\n            cached = \u003Cspan class=\"hljs-keyword\">await\u003C/span> self.get_cached_result(url)\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> cached:\n                cached_results.append(cached)\n            \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n                uncached_urls.append(url)\n        \n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Using \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">len\u003C/span>(cached_results)}\u003C/span> cached results, testing \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">len\u003C/span>(uncached_urls)}\u003C/span> new URLs&quot;\u003C/span>)\n        \n        \u003Cspan class=\"hljs-comment\"># Batch uncached URLs by domain for respectful testing\u003C/span>\n        domain_batches = self._group_urls_by_domain(uncached_urls)\n        \n        all_results = cached_results[:]\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> domain, domain_urls \u003Cspan class=\"hljs-keyword\">in\u003C/span> domain_batches.items():\n            \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Testing \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">len\u003C/span>(domain_urls)}\u003C/span> URLs from \u003Cspan class=\"hljs-subst\">{domain}\u003C/span>&quot;\u003C/span>)\n            \n            \u003Cspan class=\"hljs-comment\"># Add delay between domain batches\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> domain != \u003Cspan class=\"hljs-built_in\">list\u003C/span>(domain_batches.keys())[\u003Cspan class=\"hljs-number\">0\u003C/span>]:\n                \u003Cspan class=\"hljs-keyword\">await\u003C/span> asyncio.sleep(\u003Cspan class=\"hljs-number\">1\u003C/span>)\n            \n            batch_results = \u003Cspan class=\"hljs-keyword\">await\u003C/span> self._test_domain_batch(domain_urls)\n            all_results.extend(batch_results)\n            \n            \u003Cspan class=\"hljs-comment\"># Cache results\u003C/span>\n            \u003Cspan class=\"hljs-keyword\">for\u003C/span> result \u003Cspan class=\"hljs-keyword\">in\u003C/span> batch_results:\n                \u003Cspan class=\"hljs-keyword\">await\u003C/span> self.cache_result(result[\u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>], result)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> self._summarize_results(all_results)\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_group_urls_by_domain\u003C/span>(\u003Cspan class=\"hljs-params\">self, urls: \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>]\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>, \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>]]:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Group URLs by domain for respectful testing&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">from\u003C/span> urllib.parse \u003Cspan class=\"hljs-keyword\">import\u003C/span> urlparse\n        \n        domain_groups = {}\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> urls:\n            \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n                domain = urlparse(url).netloc\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> domain \u003Cspan class=\"hljs-keyword\">not\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> domain_groups:\n                    domain_groups[domain] = []\n                domain_groups[domain].append(url)\n            \u003Cspan class=\"hljs-keyword\">except\u003C/span> Exception:\n                \u003Cspan class=\"hljs-comment\"># Handle malformed URLs\u003C/span>\n                \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;malformed&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> \u003Cspan class=\"hljs-keyword\">in\u003C/span> domain_groups:\n                    domain_groups[\u003Cspan class=\"hljs-string\">&#x27;malformed&#x27;\u003C/span>] = []\n                domain_groups[\u003Cspan class=\"hljs-string\">&#x27;malformed&#x27;\u003C/span>].append(url)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> domain_groups\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_test_domain_batch\u003C/span>(\u003Cspan class=\"hljs-params\">self, urls: \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-built_in\">str\u003C/span>]\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-type\">Dict\u003C/span>]:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Test a batch of URLs from the same domain with rate limiting&quot;&quot;&quot;\u003C/span>\n        results = []\n        \n        \u003Cspan class=\"hljs-comment\"># Limit concurrent requests per domain\u003C/span>\n        semaphore = asyncio.Semaphore(\u003Cspan class=\"hljs-number\">3\u003C/span>)\n        \n        \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">test_with_limit\u003C/span>(\u003Cspan class=\"hljs-params\">url\u003C/span>):\n            \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">with\u003C/span> semaphore:\n                \u003Cspan class=\"hljs-comment\"># Add small delay between requests to same domain\u003C/span>\n                \u003Cspan class=\"hljs-keyword\">await\u003C/span> asyncio.sleep(\u003Cspan class=\"hljs-number\">0.1\u003C/span>)\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-keyword\">await\u003C/span> self._test_single_url(url)\n        \n        tasks = [test_with_limit(url) \u003Cspan class=\"hljs-keyword\">for\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> urls]\n        batch_results = \u003Cspan class=\"hljs-keyword\">await\u003C/span> asyncio.gather(*tasks, return_exceptions=\u003Cspan class=\"hljs-literal\">True\u003C/span>)\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> result \u003Cspan class=\"hljs-keyword\">in\u003C/span> batch_results:\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-keyword\">not\u003C/span> \u003Cspan class=\"hljs-built_in\">isinstance\u003C/span>(result, Exception):\n                results.append(result)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> results\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_test_single_url\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Test a single URL with comprehensive error handling&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">try\u003C/span>:\n            \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">with\u003C/span> aiohttp.ClientSession() \u003Cspan class=\"hljs-keyword\">as\u003C/span> session:\n                \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">with\u003C/span> session.head(url, timeout=aiohttp.ClientTimeout(total=\u003Cspan class=\"hljs-number\">10\u003C/span>)) \u003Cspan class=\"hljs-keyword\">as\u003C/span> response:\n                    \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n                        \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n                        \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span> \u003Cspan class=\"hljs-keyword\">if\u003C/span> response.status == \u003Cspan class=\"hljs-number\">200\u003C/span> \u003Cspan class=\"hljs-keyword\">else\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>,\n                        \u003Cspan class=\"hljs-string\">&#x27;status_code&#x27;\u003C/span>: response.status,\n                        \u003Cspan class=\"hljs-string\">&#x27;response_time&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">0\u003C/span>,  \u003Cspan class=\"hljs-comment\"># Would need timing logic\u003C/span>\n                        \u003Cspan class=\"hljs-string\">&#x27;final_url&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">str\u003C/span>(response.url)\n                    }\n        \u003Cspan class=\"hljs-keyword\">except\u003C/span> Exception \u003Cspan class=\"hljs-keyword\">as\u003C/span> e:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n                \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n                \u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>,\n                \u003Cspan class=\"hljs-string\">&#x27;error&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">str\u003C/span>(e)\n            }\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_summarize_results\u003C/span>(\u003Cspan class=\"hljs-params\">self, results: \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-type\">Dict\u003C/span>]\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Generate summary statistics&quot;&quot;&quot;\u003C/span>\n        total = \u003Cspan class=\"hljs-built_in\">len\u003C/span>(results)\n        valid = \u003Cspan class=\"hljs-built_in\">sum\u003C/span>(\u003Cspan class=\"hljs-number\">1\u003C/span> \u003Cspan class=\"hljs-keyword\">for\u003C/span> r \u003Cspan class=\"hljs-keyword\">in\u003C/span> results \u003Cspan class=\"hljs-keyword\">if\u003C/span> r.get(\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>) == \u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span>)\n        broken = \u003Cspan class=\"hljs-built_in\">sum\u003C/span>(\u003Cspan class=\"hljs-number\">1\u003C/span> \u003Cspan class=\"hljs-keyword\">for\u003C/span> r \u003Cspan class=\"hljs-keyword\">in\u003C/span> results \u003Cspan class=\"hljs-keyword\">if\u003C/span> r.get(\u003Cspan class=\"hljs-string\">&#x27;status&#x27;\u003C/span>) == \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n            \u003Cspan class=\"hljs-string\">&#x27;summary&#x27;\u003C/span>: {\n                \u003Cspan class=\"hljs-string\">&#x27;total&#x27;\u003C/span>: total,\n                \u003Cspan class=\"hljs-string\">&#x27;valid&#x27;\u003C/span>: valid,\n                \u003Cspan class=\"hljs-string\">&#x27;broken&#x27;\u003C/span>: broken,\n                \u003Cspan class=\"hljs-string\">&#x27;success_rate&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">round\u003C/span>(valid / total * \u003Cspan class=\"hljs-number\">100\u003C/span>, \u003Cspan class=\"hljs-number\">2\u003C/span>) \u003Cspan class=\"hljs-keyword\">if\u003C/span> total &gt; \u003Cspan class=\"hljs-number\">0\u003C/span> \u003Cspan class=\"hljs-keyword\">else\u003C/span> \u003Cspan class=\"hljs-number\">0\u003C/span>\n            },\n            \u003Cspan class=\"hljs-string\">&#x27;results&#x27;\u003C/span>: results\n        }\n    \n    \u003Cspan class=\"hljs-keyword\">async\u003C/span> \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">cleanup\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Clean up resources&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.redis:\n            \u003Cspan class=\"hljs-keyword\">await\u003C/span> self.redis.close()\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> self.sqlite_conn:\n            self.sqlite_conn.close()\n\u003C/code>\u003C/pre>\u003Ch3 id=\"intelligent-link-categorization\">Intelligent Link Categorization\u003C/h3>\n\u003Cpre>\u003Ccode class=\"hljs language-python\">\u003Cspan class=\"hljs-comment\"># link_categorizer.py - Advanced link categorization and prioritization\u003C/span>\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> typing \u003Cspan class=\"hljs-keyword\">import\u003C/span> \u003Cspan class=\"hljs-type\">Dict\u003C/span>, \u003Cspan class=\"hljs-type\">List\u003C/span>, \u003Cspan class=\"hljs-type\">Set\u003C/span>\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> re\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> urllib.parse \u003Cspan class=\"hljs-keyword\">import\u003C/span> urlparse\n\u003Cspan class=\"hljs-keyword\">from\u003C/span> enum \u003Cspan class=\"hljs-keyword\">import\u003C/span> Enum\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">LinkPriority\u003C/span>(\u003Cspan class=\"hljs-title class_ inherited__\">Enum\u003C/span>):\n    CRITICAL = \u003Cspan class=\"hljs-string\">&quot;critical&quot;\u003C/span>      \u003Cspan class=\"hljs-comment\"># Homepage, main navigation\u003C/span>\n    HIGH = \u003Cspan class=\"hljs-string\">&quot;high&quot;\u003C/span>             \u003Cspan class=\"hljs-comment\"># Documentation, tutorials\u003C/span>\n    MEDIUM = \u003Cspan class=\"hljs-string\">&quot;medium&quot;\u003C/span>         \u003Cspan class=\"hljs-comment\"># Examples, references\u003C/span>\n    LOW = \u003Cspan class=\"hljs-string\">&quot;low&quot;\u003C/span>              \u003Cspan class=\"hljs-comment\"># External tools, optional resources\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">LinkCategory\u003C/span>(\u003Cspan class=\"hljs-title class_ inherited__\">Enum\u003C/span>):\n    NAVIGATION = \u003Cspan class=\"hljs-string\">&quot;navigation&quot;\u003C/span>\n    DOCUMENTATION = \u003Cspan class=\"hljs-string\">&quot;documentation&quot;\u003C/span>\n    EXAMPLE = \u003Cspan class=\"hljs-string\">&quot;example&quot;\u003C/span>\n    REFERENCE = \u003Cspan class=\"hljs-string\">&quot;reference&quot;\u003C/span>\n    SOCIAL = \u003Cspan class=\"hljs-string\">&quot;social&quot;\u003C/span>\n    TOOL = \u003Cspan class=\"hljs-string\">&quot;tool&quot;\u003C/span>\n    MEDIA = \u003Cspan class=\"hljs-string\">&quot;media&quot;\u003C/span>\n    UNKNOWN = \u003Cspan class=\"hljs-string\">&quot;unknown&quot;\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">IntelligentLinkCategorizer\u003C/span>:\n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__init__\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        self.domain_patterns = {\n            LinkCategory.SOCIAL: [\n                \u003Cspan class=\"hljs-string\">r&#x27;twitter\\.com&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;github\\.com&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;linkedin\\.com&#x27;\u003C/span>, \n                \u003Cspan class=\"hljs-string\">r&#x27;facebook\\.com&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;instagram\\.com&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;youtube\\.com&#x27;\u003C/span>\n            ],\n            LinkCategory.DOCUMENTATION: [\n                \u003Cspan class=\"hljs-string\">r&#x27;docs\\.&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;documentation\\.&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;wiki\\.&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;guide\\.&#x27;\u003C/span>, \n                \u003Cspan class=\"hljs-string\">r&#x27;tutorial\\.&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;\\.readthedocs\\.io&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;gitbook\\.io&#x27;\u003C/span>\n            ],\n            LinkCategory.TOOL: [\n                \u003Cspan class=\"hljs-string\">r&#x27;npmjs\\.com&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;pypi\\.org&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;crates\\.io&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;packagist\\.org&#x27;\u003C/span>,\n                \u003Cspan class=\"hljs-string\">r&#x27;maven\\.org&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;rubygems\\.org&#x27;\u003C/span>\n            ],\n            LinkCategory.MEDIA: [\n                \u003Cspan class=\"hljs-string\">r&#x27;imgur\\.com&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;cloudinary\\.com&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;amazonaws\\.com&#x27;\u003C/span>\n            ]\n        }\n        \n        self.url_patterns = {\n            LinkCategory.EXAMPLE: [\n                \u003Cspan class=\"hljs-string\">r&#x27;/example&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/demo&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/sample&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/playground&#x27;\u003C/span>\n            ],\n            LinkCategory.REFERENCE: [\n                \u003Cspan class=\"hljs-string\">r&#x27;/api&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/reference&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/spec&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/rfc&#x27;\u003C/span>\n            ]\n        }\n        \n        self.priority_rules = {\n            \u003Cspan class=\"hljs-comment\"># Critical links (site functionality)\u003C/span>\n            LinkPriority.CRITICAL: [\n                \u003Cspan class=\"hljs-string\">r&#x27;^/$&#x27;\u003C/span>,  \u003Cspan class=\"hljs-comment\"># Homepage\u003C/span>\n                \u003Cspan class=\"hljs-string\">r&#x27;/index\\.&#x27;\u003C/span>,  \u003Cspan class=\"hljs-comment\"># Index pages\u003C/span>\n                \u003Cspan class=\"hljs-string\">r&#x27;/home&#x27;\u003C/span>,  \u003Cspan class=\"hljs-comment\"># Home pages\u003C/span>\n                \u003Cspan class=\"hljs-string\">r&#x27;/main&#x27;\u003C/span>,  \u003Cspan class=\"hljs-comment\"># Main pages\u003C/span>\n            ],\n            \u003Cspan class=\"hljs-comment\"># High priority (core content)\u003C/span>\n            LinkPriority.HIGH: [\n                \u003Cspan class=\"hljs-string\">r&#x27;/docs?/&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/documentation/&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/guide/&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/tutorial/&#x27;\u003C/span>,\n                \u003Cspan class=\"hljs-string\">r&#x27;/getting-?started&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/quickstart&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/installation&#x27;\u003C/span>\n            ],\n            \u003Cspan class=\"hljs-comment\"># Medium priority (supporting content)\u003C/span>\n            LinkPriority.MEDIUM: [\n                \u003Cspan class=\"hljs-string\">r&#x27;/example&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/demo&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/sample&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/blog&#x27;\u003C/span>,\n                \u003Cspan class=\"hljs-string\">r&#x27;/news&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/changelog&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">r&#x27;/releases&#x27;\u003C/span>\n            ]\n            \u003Cspan class=\"hljs-comment\"># Low priority is default for everything else\u003C/span>\n        }\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">categorize_link\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, context: \u003Cspan class=\"hljs-type\">Dict\u003C/span> = \u003Cspan class=\"hljs-literal\">None\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Categorize a link and assign priority&quot;&quot;&quot;\u003C/span>\n        parsed = urlparse(url)\n        domain = parsed.netloc.lower()\n        path = parsed.path.lower()\n        \n        \u003Cspan class=\"hljs-comment\"># Determine category\u003C/span>\n        category = self._determine_category(domain, path, url)\n        \n        \u003Cspan class=\"hljs-comment\"># Determine priority\u003C/span>\n        priority = self._determine_priority(domain, path, category, context)\n        \n        \u003Cspan class=\"hljs-comment\"># Additional metadata\u003C/span>\n        metadata = self._extract_metadata(parsed, category)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n            \u003Cspan class=\"hljs-string\">&#x27;url&#x27;\u003C/span>: url,\n            \u003Cspan class=\"hljs-string\">&#x27;category&#x27;\u003C/span>: category,\n            \u003Cspan class=\"hljs-string\">&#x27;priority&#x27;\u003C/span>: priority,\n            \u003Cspan class=\"hljs-string\">&#x27;domain&#x27;\u003C/span>: domain,\n            \u003Cspan class=\"hljs-string\">&#x27;metadata&#x27;\u003C/span>: metadata,\n            \u003Cspan class=\"hljs-string\">&#x27;should_check_frequently&#x27;\u003C/span>: priority \u003Cspan class=\"hljs-keyword\">in\u003C/span> [LinkPriority.CRITICAL, LinkPriority.HIGH],\n            \u003Cspan class=\"hljs-string\">&#x27;cache_duration&#x27;\u003C/span>: self._get_cache_duration(priority, category)\n        }\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_determine_category\u003C/span>(\u003Cspan class=\"hljs-params\">self, domain: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, path: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; LinkCategory:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Determine link category based on patterns&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-comment\"># Check domain patterns\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> category, patterns \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.domain_patterns.items():\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">any\u003C/span>(re.search(pattern, domain) \u003Cspan class=\"hljs-keyword\">for\u003C/span> pattern \u003Cspan class=\"hljs-keyword\">in\u003C/span> patterns):\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> category\n        \n        \u003Cspan class=\"hljs-comment\"># Check URL path patterns\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> category, patterns \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.url_patterns.items():\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">any\u003C/span>(re.search(pattern, path) \u003Cspan class=\"hljs-keyword\">for\u003C/span> pattern \u003Cspan class=\"hljs-keyword\">in\u003C/span> patterns):\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> category\n        \n        \u003Cspan class=\"hljs-comment\"># Special cases\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">any\u003C/span>(ext \u003Cspan class=\"hljs-keyword\">in\u003C/span> path \u003Cspan class=\"hljs-keyword\">for\u003C/span> ext \u003Cspan class=\"hljs-keyword\">in\u003C/span> [\u003Cspan class=\"hljs-string\">&#x27;.pdf&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;.doc&#x27;\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;.zip&#x27;\u003C/span>]):\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkCategory.MEDIA\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkCategory.UNKNOWN\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_determine_priority\u003C/span>(\u003Cspan class=\"hljs-params\">self, domain: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, path: \u003Cspan class=\"hljs-built_in\">str\u003C/span>, category: LinkCategory, \n                          context: \u003Cspan class=\"hljs-type\">Dict\u003C/span> = \u003Cspan class=\"hljs-literal\">None\u003C/span>\u003C/span>) -&gt; LinkPriority:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Determine link priority&quot;&quot;&quot;\u003C/span>\n        \u003Cspan class=\"hljs-comment\"># Context-based priority (if link is in navigation, header, etc.)\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> context:\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> context.get(\u003Cspan class=\"hljs-string\">&#x27;in_navigation&#x27;\u003C/span>):\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkPriority.CRITICAL\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> context.get(\u003Cspan class=\"hljs-string\">&#x27;in_main_content&#x27;\u003C/span>):\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkPriority.HIGH\n        \n        \u003Cspan class=\"hljs-comment\"># Category-based priority\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> category == LinkCategory.NAVIGATION:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkPriority.CRITICAL\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> category \u003Cspan class=\"hljs-keyword\">in\u003C/span> [LinkCategory.DOCUMENTATION, LinkCategory.REFERENCE]:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkPriority.HIGH\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> category \u003Cspan class=\"hljs-keyword\">in\u003C/span> [LinkCategory.EXAMPLE, LinkCategory.TOOL]:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkPriority.MEDIUM\n        \n        \u003Cspan class=\"hljs-comment\"># URL pattern-based priority\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> priority, patterns \u003Cspan class=\"hljs-keyword\">in\u003C/span> self.priority_rules.items():\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> \u003Cspan class=\"hljs-built_in\">any\u003C/span>(re.search(pattern, path) \u003Cspan class=\"hljs-keyword\">for\u003C/span> pattern \u003Cspan class=\"hljs-keyword\">in\u003C/span> patterns):\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> priority\n        \n        \u003Cspan class=\"hljs-comment\"># Default to low priority\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> LinkPriority.LOW\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_extract_metadata\u003C/span>(\u003Cspan class=\"hljs-params\">self, parsed, category: LinkCategory\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Extract additional metadata about the link&quot;&quot;&quot;\u003C/span>\n        metadata = {\n            \u003Cspan class=\"hljs-string\">&#x27;is_secure&#x27;\u003C/span>: parsed.scheme == \u003Cspan class=\"hljs-string\">&#x27;https&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;has_fragment&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">bool\u003C/span>(parsed.fragment),\n            \u003Cspan class=\"hljs-string\">&#x27;has_query&#x27;\u003C/span>: \u003Cspan class=\"hljs-built_in\">bool\u003C/span>(parsed.query),\n            \u003Cspan class=\"hljs-string\">&#x27;file_extension&#x27;\u003C/span>: Path(parsed.path).suffix \u003Cspan class=\"hljs-keyword\">if\u003C/span> parsed.path \u003Cspan class=\"hljs-keyword\">else\u003C/span> \u003Cspan class=\"hljs-literal\">None\u003C/span>,\n        }\n        \n        \u003Cspan class=\"hljs-comment\"># Category-specific metadata\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> category == LinkCategory.SOCIAL:\n            metadata[\u003Cspan class=\"hljs-string\">&#x27;platform&#x27;\u003C/span>] = self._identify_social_platform(parsed.netloc)\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> category == LinkCategory.TOOL:\n            metadata[\u003Cspan class=\"hljs-string\">&#x27;tool_type&#x27;\u003C/span>] = self._identify_tool_type(parsed.netloc)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> metadata\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_identify_social_platform\u003C/span>(\u003Cspan class=\"hljs-params\">self, domain: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-built_in\">str\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Identify specific social media platform&quot;&quot;&quot;\u003C/span>\n        social_platforms = {\n            \u003Cspan class=\"hljs-string\">&#x27;twitter.com&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;Twitter&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;github.com&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;GitHub&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;linkedin.com&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;LinkedIn&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;facebook.com&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;Facebook&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;youtube.com&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;YouTube&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;instagram.com&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;Instagram&#x27;\u003C/span>\n        }\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> platform_domain, platform_name \u003Cspan class=\"hljs-keyword\">in\u003C/span> social_platforms.items():\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> platform_domain \u003Cspan class=\"hljs-keyword\">in\u003C/span> domain:\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> platform_name\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;Unknown&#x27;\u003C/span>\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_identify_tool_type\u003C/span>(\u003Cspan class=\"hljs-params\">self, domain: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-built_in\">str\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Identify type of development tool&quot;&quot;&quot;\u003C/span>\n        tool_types = {\n            \u003Cspan class=\"hljs-string\">&#x27;npmjs.com&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;JavaScript Package&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;pypi.org&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;Python Package&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;crates.io&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;Rust Package&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;packagist.org&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;PHP Package&#x27;\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;rubygems.org&#x27;\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;Ruby Gem&#x27;\u003C/span>\n        }\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> tool_domain, tool_type \u003Cspan class=\"hljs-keyword\">in\u003C/span> tool_types.items():\n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> tool_domain \u003Cspan class=\"hljs-keyword\">in\u003C/span> domain:\n                \u003Cspan class=\"hljs-keyword\">return\u003C/span> tool_type\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;Development Tool&#x27;\u003C/span>\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">_get_cache_duration\u003C/span>(\u003Cspan class=\"hljs-params\">self, priority: LinkPriority, category: LinkCategory\u003C/span>) -&gt; \u003Cspan class=\"hljs-built_in\">int\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Get appropriate cache duration in seconds&quot;&quot;&quot;\u003C/span>\n        cache_durations = {\n            LinkPriority.CRITICAL: \u003Cspan class=\"hljs-number\">1800\u003C/span>,   \u003Cspan class=\"hljs-comment\"># 30 minutes\u003C/span>\n            LinkPriority.HIGH: \u003Cspan class=\"hljs-number\">3600\u003C/span>,       \u003Cspan class=\"hljs-comment\"># 1 hour\u003C/span>\n            LinkPriority.MEDIUM: \u003Cspan class=\"hljs-number\">7200\u003C/span>,     \u003Cspan class=\"hljs-comment\"># 2 hours\u003C/span>\n            LinkPriority.LOW: \u003Cspan class=\"hljs-number\">14400\u003C/span>        \u003Cspan class=\"hljs-comment\"># 4 hours\u003C/span>\n        }\n        \n        base_duration = cache_durations.get(priority, \u003Cspan class=\"hljs-number\">7200\u003C/span>)\n        \n        \u003Cspan class=\"hljs-comment\"># Adjust based on category\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> category == LinkCategory.SOCIAL:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> base_duration * \u003Cspan class=\"hljs-number\">2\u003C/span>  \u003Cspan class=\"hljs-comment\"># Social links change less frequently\u003C/span>\n        \u003Cspan class=\"hljs-keyword\">elif\u003C/span> category == LinkCategory.DOCUMENTATION:\n            \u003Cspan class=\"hljs-keyword\">return\u003C/span> base_duration // \u003Cspan class=\"hljs-number\">2\u003C/span>  \u003Cspan class=\"hljs-comment\"># Documentation might update more often\u003C/span>\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> base_duration\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">create_testing_schedule\u003C/span>(\u003Cspan class=\"hljs-params\">self, categorized_links: \u003Cspan class=\"hljs-type\">List\u003C/span>[\u003Cspan class=\"hljs-type\">Dict\u003C/span>]\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Create an intelligent testing schedule based on link categories and priorities&quot;&quot;&quot;\u003C/span>\n        schedule = {\n            \u003Cspan class=\"hljs-string\">&#x27;immediate&#x27;\u003C/span>: [],      \u003Cspan class=\"hljs-comment\"># Test now\u003C/span>\n            \u003Cspan class=\"hljs-string\">&#x27;hourly&#x27;\u003C/span>: [],        \u003Cspan class=\"hljs-comment\"># Test every hour\u003C/span>\n            \u003Cspan class=\"hljs-string\">&#x27;daily&#x27;\u003C/span>: [],         \u003Cspan class=\"hljs-comment\"># Test daily\u003C/span>\n            \u003Cspan class=\"hljs-string\">&#x27;weekly&#x27;\u003C/span>: []         \u003Cspan class=\"hljs-comment\"># Test weekly\u003C/span>\n        }\n        \n        \u003Cspan class=\"hljs-keyword\">for\u003C/span> link_info \u003Cspan class=\"hljs-keyword\">in\u003C/span> categorized_links:\n            priority = link_info[\u003Cspan class=\"hljs-string\">&#x27;priority&#x27;\u003C/span>]\n            category = link_info[\u003Cspan class=\"hljs-string\">&#x27;category&#x27;\u003C/span>]\n            \n            \u003Cspan class=\"hljs-keyword\">if\u003C/span> priority == LinkPriority.CRITICAL:\n                schedule[\u003Cspan class=\"hljs-string\">&#x27;immediate&#x27;\u003C/span>].append(link_info)\n            \u003Cspan class=\"hljs-keyword\">elif\u003C/span> priority == LinkPriority.HIGH:\n                schedule[\u003Cspan class=\"hljs-string\">&#x27;hourly&#x27;\u003C/span>].append(link_info)\n            \u003Cspan class=\"hljs-keyword\">elif\u003C/span> priority == LinkPriority.MEDIUM:\n                schedule[\u003Cspan class=\"hljs-string\">&#x27;daily&#x27;\u003C/span>].append(link_info)\n            \u003Cspan class=\"hljs-keyword\">else\u003C/span>:\n                schedule[\u003Cspan class=\"hljs-string\">&#x27;weekly&#x27;\u003C/span>].append(link_info)\n        \n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> schedule\n\n\u003Cspan class=\"hljs-comment\"># Usage example\u003C/span>\n\u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">demonstrate_intelligent_categorization\u003C/span>():\n    \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Demonstrate intelligent link categorization&quot;&quot;&quot;\u003C/span>\n    categorizer = IntelligentLinkCategorizer()\n    \n    sample_links = [\n        \u003Cspan class=\"hljs-string\">&quot;https://blog.markdowntools.com/&quot;\u003C/span>,\n        \u003Cspan class=\"hljs-string\">&quot;https://github.com/user/repo&quot;\u003C/span>,\n        \u003Cspan class=\"hljs-string\">&quot;https://docs.example.com/api/reference&quot;\u003C/span>,\n        \u003Cspan class=\"hljs-string\">&quot;https://example.com/tutorial/getting-started&quot;\u003C/span>,\n        \u003Cspan class=\"hljs-string\">&quot;https://npmjs.com/package/markdown-it&quot;\u003C/span>,\n        \u003Cspan class=\"hljs-string\">&quot;https://twitter.com/example&quot;\u003C/span>,\n        \u003Cspan class=\"hljs-string\">&quot;https://example.com/demo/playground&quot;\u003C/span>,\n        \u003Cspan class=\"hljs-string\">&quot;http://unsecure-site.com/resource&quot;\u003C/span>\n    ]\n    \n    categorized = []\n    \n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">&quot;=== Link Categorization Results ===&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-keyword\">for\u003C/span> url \u003Cspan class=\"hljs-keyword\">in\u003C/span> sample_links:\n        result = categorizer.categorize_link(url)\n        categorized.append(result)\n        \n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;\\nURL: \u003Cspan class=\"hljs-subst\">{url}\u003C/span>&quot;\u003C/span>)\n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Category: \u003Cspan class=\"hljs-subst\">{result[\u003Cspan class=\"hljs-string\">&#x27;category&#x27;\u003C/span>].value}\u003C/span>&quot;\u003C/span>)\n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Priority: \u003Cspan class=\"hljs-subst\">{result[\u003Cspan class=\"hljs-string\">&#x27;priority&#x27;\u003C/span>].value}\u003C/span>&quot;\u003C/span>)\n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Check Frequently: \u003Cspan class=\"hljs-subst\">{result[\u003Cspan class=\"hljs-string\">&#x27;should_check_frequently&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Cache Duration: \u003Cspan class=\"hljs-subst\">{result[\u003Cspan class=\"hljs-string\">&#x27;cache_duration&#x27;\u003C/span>]}\u003C/span>s&quot;\u003C/span>)\n        \u003Cspan class=\"hljs-keyword\">if\u003C/span> result[\u003Cspan class=\"hljs-string\">&#x27;metadata&#x27;\u003C/span>]:\n            \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;Metadata: \u003Cspan class=\"hljs-subst\">{result[\u003Cspan class=\"hljs-string\">&#x27;metadata&#x27;\u003C/span>]}\u003C/span>&quot;\u003C/span>)\n    \n    \u003Cspan class=\"hljs-comment\"># Create testing schedule\u003C/span>\n    schedule = categorizer.create_testing_schedule(categorized)\n    \n    \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;\\n=== Testing Schedule ===&quot;\u003C/span>)\n    \u003Cspan class=\"hljs-keyword\">for\u003C/span> frequency, links \u003Cspan class=\"hljs-keyword\">in\u003C/span> schedule.items():\n        \u003Cspan class=\"hljs-built_in\">print\u003C/span>(\u003Cspan class=\"hljs-string\">f&quot;\u003Cspan class=\"hljs-subst\">{frequency.title()}\u003C/span>: \u003Cspan class=\"hljs-subst\">{\u003Cspan class=\"hljs-built_in\">len\u003C/span>(links)}\u003C/span> links&quot;\u003C/span>)\n\n\u003Cspan class=\"hljs-keyword\">if\u003C/span> __name__ == \u003Cspan class=\"hljs-string\">&quot;__main__&quot;\u003C/span>:\n    demonstrate_intelligent_categorization()\n\u003C/code>\u003C/pre>\u003Ch2 id=\"troubleshooting-and-best-practices\">Troubleshooting and Best Practices\u003C/h2>\n\u003Ch3 id=\"common-validation-issues\">Common Validation Issues\u003C/h3>\n\u003Cp>\u003Cstrong>Problem\u003C/strong>: False positives from temporary network issues\u003C/p>\n\u003Cp>\u003Cstrong>Solutions\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>Implement retry logic with exponential backoff\u003C/li>\n\u003Cli>Use circuit breakers for frequently failing domains\u003C/li>\n\u003Cli>Distinguish between different error types (timeout vs 404)\u003C/li>\n\u003C/ul>\n\u003Cp>\u003Cstrong>Problem\u003C/strong>: Rate limiting from target servers\u003C/p>\n\u003Cp>\u003Cstrong>Solutions\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>Implement respectful request timing\u003C/li>\n\u003Cli>Use different user agents for different checks\u003C/li>\n\u003Cli>Group requests by domain with appropriate delays\u003C/li>\n\u003C/ul>\n\u003Cp>\u003Cstrong>Problem\u003C/strong>: Links that work in browser but fail in automated tests\u003C/p>\n\u003Cp>\u003Cstrong>Solutions\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>Check for JavaScript-dependent redirects\u003C/li>\n\u003Cli>Verify required headers or authentication\u003C/li>\n\u003Cli>Test with different user agent strings\u003C/li>\n\u003C/ul>\n\u003Ch3 id=\"performance-optimization\">Performance Optimization\u003C/h3>\n\u003Cpre>\u003Ccode class=\"hljs language-python\">\u003Cspan class=\"hljs-comment\"># Best practices for production link validation\u003C/span>\n\u003Cspan class=\"hljs-keyword\">class\u003C/span> \u003Cspan class=\"hljs-title class_\">ProductionLinkValidator\u003C/span>:\n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">__init__\u003C/span>(\u003Cspan class=\"hljs-params\">self\u003C/span>):\n        self.rate_limits = {\n            \u003Cspan class=\"hljs-string\">&#x27;github.com&#x27;\u003C/span>: {\u003Cspan class=\"hljs-string\">&#x27;requests_per_minute&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">60\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;delay&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">1\u003C/span>},\n            \u003Cspan class=\"hljs-string\">&#x27;docs.python.org&#x27;\u003C/span>: {\u003Cspan class=\"hljs-string\">&#x27;requests_per_minute&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">30\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;delay&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">2\u003C/span>},\n            \u003Cspan class=\"hljs-string\">&#x27;default&#x27;\u003C/span>: {\u003Cspan class=\"hljs-string\">&#x27;requests_per_minute&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">120\u003C/span>, \u003Cspan class=\"hljs-string\">&#x27;delay&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">0.5\u003C/span>}\n        }\n        \n        self.retry_config = {\n            \u003Cspan class=\"hljs-string\">&#x27;max_retries&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">3\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;backoff_factor&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">2\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;retry_status_codes&#x27;\u003C/span>: [\u003Cspan class=\"hljs-number\">429\u003C/span>, \u003Cspan class=\"hljs-number\">502\u003C/span>, \u003Cspan class=\"hljs-number\">503\u003C/span>, \u003Cspan class=\"hljs-number\">504\u003C/span>]\n        }\n        \n        self.timeout_config = {\n            \u003Cspan class=\"hljs-string\">&#x27;connect_timeout&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">5\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;read_timeout&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">10\u003C/span>,\n            \u003Cspan class=\"hljs-string\">&#x27;total_timeout&#x27;\u003C/span>: \u003Cspan class=\"hljs-number\">15\u003C/span>\n        }\n    \n    \u003Cspan class=\"hljs-keyword\">def\u003C/span> \u003Cspan class=\"hljs-title function_\">get_domain_config\u003C/span>(\u003Cspan class=\"hljs-params\">self, url: \u003Cspan class=\"hljs-built_in\">str\u003C/span>\u003C/span>) -&gt; \u003Cspan class=\"hljs-type\">Dict\u003C/span>:\n        \u003Cspan class=\"hljs-string\">&quot;&quot;&quot;Get configuration for specific domain&quot;&quot;&quot;\u003C/span>\n        domain = urlparse(url).netloc\n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> self.rate_limits.get(domain, self.rate_limits[\u003Cspan class=\"hljs-string\">&#x27;default&#x27;\u003C/span>])\n\u003C/code>\u003C/pre>\u003Ch2 id=\"conclusion\">Conclusion\u003C/h2>\n\u003Cp>Advanced Markdown link validation and testing represents a sophisticated approach to documentation maintenance that transforms manual link checking into automated, intelligent monitoring systems capable of maintaining content quality across large-scale documentation projects. Through systematic validation strategies, performance optimization, and intelligent categorization, technical teams can ensure their documentation remains reliable and accessible while minimizing maintenance overhead.\u003C/p>\n\u003Cp>The key to successful link validation lies in balancing thoroughness with performance, implementing intelligent caching and scheduling systems, and providing actionable insights that enable proactive maintenance rather than reactive fixes. Whether you&#39;re maintaining internal documentation, open-source project guides, or comprehensive knowledge bases, the validation techniques covered in this guide provide the foundation for creating robust, reliable documentation systems.\u003C/p>\n\u003Cp>Remember to implement validation early in your content development process, establish clear monitoring schedules that match your content update frequency, and continuously optimize your validation strategies based on real-world usage patterns and failure modes. With proper implementation of advanced link validation systems, your Markdown documentation can maintain the same level of reliability and user experience that modern web applications demand from their critical infrastructure.\u003C/p>\n",[15,19,22,25,28,31,34],{"id":16,"text":17,"level":18},"why-master-link-validation-and-testing","Why Master Link Validation and Testing?",2,{"id":20,"text":21,"level":18},"foundation-link-validation-techniques","Foundation Link Validation Techniques",{"id":23,"text":24,"level":18},"automated-testing-integration","Automated Testing Integration",{"id":26,"text":27,"level":18},"link-monitoring-and-maintenance","Link Monitoring and Maintenance",{"id":29,"text":30,"level":18},"advanced-validation-strategies","Advanced Validation Strategies",{"id":32,"text":33,"level":18},"troubleshooting-and-best-practices","Troubleshooting and Best Practices",{"id":35,"text":36,"level":18},"conclusion","Conclusion",[],[39,46,54],{"slug":40,"title":41,"description":42,"excerpt":43,"date":44,"category":9,"author":10,"keywords":45,"readingMinutes":12},"markdown-automated-testing-validation-complete-guide","Markdown Automated Testing and Validation: Complete Guide for Quality Assurance and Continuous Integration","Master comprehensive Markdown testing strategies, automated validation systems, and CI/CD integration for maintaining high-quality documentation and content integrity across large-scale projects.","Automated testing and validation for Markdown content ensures consistency, quality, and reliability across documentation projects through comprehensive testing frameworks that verify syntax…","2025-10-17","markdown testing, markdown validation, automated testing markdown, CI/CD markdown, markdown quality assurance, content testing, documentation testing, markdown linting",{"slug":47,"title":48,"description":49,"excerpt":50,"date":51,"category":9,"author":10,"keywords":52,"readingMinutes":53},"markdown-form-validation-input-handling-complete-guide","Markdown Form Validation and Input Handling: Complete Guide for Interactive Documentation with Dynamic Validation Systems","Master advanced Markdown form validation and input handling techniques for creating interactive documentation with comprehensive validation systems, real-time feedback, and user-friendly error handling that ensures data quality and user experience.","Advanced Markdown form validation and input handling systems enable interactive documentation with robust data validation, real-time user feedback, and comprehensive error handling mechanisms. By…","2025-10-23","markdown form validation, input validation markdown, form handling markdown, interactive forms markdown, markdown input validation, form validation systems, dynamic form validation, markdown user input",34,{"slug":55,"title":56,"description":57,"excerpt":58,"date":59,"category":9,"author":10,"keywords":60,"readingMinutes":61},"markdown-form-creation-input-validation-complete-guide","Markdown Form Creation and Input Validation: Complete Guide for Interactive Documentation and User Input Systems","Master advanced Markdown form creation techniques for interactive documentation, user input validation, and dynamic content generation. Learn to build accessible forms, implement client-side validation, and create sophisticated input systems within Markdown-based platforms.","Advanced Markdown form creation and input validation capabilities enable sophisticated interactive documentation systems that combine the simplicity of Markdown with powerful user input…","2025-10-10","markdown forms, markdown input validation, interactive markdown, markdown user input, form creation markdown, markdown form validation, dynamic markdown forms, markdown form processing",23,1792184945154]