[
  {
    "path": ".editorconfig",
    "content": "# 如果要从更高级别的目录继承 .editorconfig 设置，请删除以下行\nroot = true\n\n[*]\n# 字符集\ncharset = utf-8\n\n# 缩进和间距\nindent_style = space\nindent_size = 4\n\n# 新行首选项\nend_of_line = crlf\ninsert_final_newline = true\n\n[*.bat]\nindent_style = tab\n\n[*.csproj]\nindent_size = 2\n\n# c# 文件\n[*.cs]\n\n# 缩进和间距\nindent_style = space\n\n#### .NET 编码约定 ####\n\n# 组织 Using\ndotnet_separate_import_directive_groups = false\ndotnet_sort_system_directives_first = false\nfile_header_template = unset\n\n# this. 和 Me. 首选项\ndotnet_style_qualification_for_event = false:warning\ndotnet_style_qualification_for_field = false:warning\ndotnet_style_qualification_for_method = false:warning\ndotnet_style_qualification_for_property = false:warning\n\n# 语言关键字与 bcl 类型首选项\ndotnet_style_predefined_type_for_locals_parameters_members = true:warning\ndotnet_style_predefined_type_for_member_access = true:warning\n\n# 括号首选项\ndotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent\ndotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:silent\ndotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning\ndotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent\n\n# 修饰符首选项\ndotnet_style_require_accessibility_modifiers = for_non_interface_members:warning\n\n# 表达式级首选项\ndotnet_style_coalesce_expression = true:warning\ndotnet_style_collection_initializer = true:warning\ndotnet_style_explicit_tuple_names = true:warning\ndotnet_style_null_propagation = true:warning\ndotnet_style_object_initializer = true:warning\ndotnet_style_operator_placement_when_wrapping = beginning_of_line\ndotnet_style_prefer_auto_properties = true:warning\ndotnet_style_prefer_compound_assignment = true:warning\ndotnet_style_prefer_conditional_expression_over_assignment = true:silent\ndotnet_style_prefer_conditional_expression_over_return = true:silent\ndotnet_style_prefer_inferred_anonymous_type_member_names = true:silent\ndotnet_style_prefer_inferred_tuple_names = true:silent\ndotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning\ndotnet_style_prefer_simplified_boolean_expressions = true:warning\ndotnet_style_prefer_simplified_interpolation = true:suggestion\n\n# 字段首选项\ndotnet_style_readonly_field = true:suggestion\n\n# 参数首选项\ndotnet_code_quality_unused_parameters = all:warning\n\n# 禁止显示首选项\ndotnet_remove_unnecessary_suppression_exclusions = none\n\n#### c# 编码约定 ####\n\n# var 首选项\ncsharp_style_var_elsewhere = true:silent\ncsharp_style_var_for_built_in_types = true:warning\ncsharp_style_var_when_type_is_apparent = true:warning\n\n# Expression-bodied 成员\ncsharp_style_expression_bodied_accessors = when_on_single_line:warning\ncsharp_style_expression_bodied_constructors = false:suggestion\ncsharp_style_expression_bodied_indexers = when_on_single_line:warning\ncsharp_style_expression_bodied_lambdas = when_on_single_line:suggestion\ncsharp_style_expression_bodied_local_functions = false:suggestion\ncsharp_style_expression_bodied_methods = false:suggestion\ncsharp_style_expression_bodied_operators = false:suggestion\ncsharp_style_expression_bodied_properties = when_on_single_line:warning\n\n# 模式匹配首选项\ncsharp_style_pattern_matching_over_as_with_null_check = true:warning\ncsharp_style_pattern_matching_over_is_with_cast_check = true:warning\ncsharp_style_prefer_not_pattern = true:warning\ncsharp_style_prefer_pattern_matching = true:warning\ncsharp_style_prefer_switch_expression = true:warning\n\n# Null 检查首选项\ncsharp_style_conditional_delegate_call = true:warning\n\n# 修饰符首选项\ncsharp_prefer_static_local_function = true:suggestion\ncsharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion\n\n# 代码块首选项\ncsharp_prefer_braces = true:warning\ncsharp_prefer_simple_using_statement = true:suggestion\n\n# 表达式级首选项\ncsharp_prefer_simple_default_expression = true:warning\ncsharp_style_deconstructed_variable_declaration = true:suggestion\ncsharp_style_inlined_variable_declaration = true:warning\ncsharp_style_pattern_local_over_anonymous_function = true:suggestion\ncsharp_style_prefer_index_operator = true:warning\ncsharp_style_prefer_range_operator = true:suggestion\ncsharp_style_throw_expression = true:suggestion\ncsharp_style_unused_value_assignment_preference = discard_variable:silent\ncsharp_style_unused_value_expression_statement_preference = discard_variable:silent\n\n# \"using\" 指令首选项\ncsharp_using_directive_placement = outside_namespace:warning\n\n#### C# 格式规则 ####\n\n# 新行首选项\ncsharp_new_line_before_catch = true\ncsharp_new_line_before_else = true\ncsharp_new_line_before_finally = true\ncsharp_new_line_before_members_in_anonymous_types = true\ncsharp_new_line_before_members_in_object_initializers = true\ncsharp_new_line_before_open_brace = all\ncsharp_new_line_between_query_expression_clauses = true\n\n# 缩进首选项\ncsharp_indent_block_contents = true\ncsharp_indent_braces = false\ncsharp_indent_case_contents = true\ncsharp_indent_case_contents_when_block = false\ncsharp_indent_labels = flush_left\ncsharp_indent_switch_labels = true\n\n# 空格键首选项\ncsharp_space_after_cast = false\ncsharp_space_after_colon_in_inheritance_clause = true\ncsharp_space_after_comma = true\ncsharp_space_after_dot = false\ncsharp_space_after_keywords_in_control_flow_statements = true\ncsharp_space_after_semicolon_in_for_statement = true\ncsharp_space_around_binary_operators = before_and_after\ncsharp_space_around_declaration_statements = false\ncsharp_space_before_colon_in_inheritance_clause = true\ncsharp_space_before_comma = false\ncsharp_space_before_dot = false\ncsharp_space_before_open_square_brackets = false\ncsharp_space_before_semicolon_in_for_statement = false\ncsharp_space_between_empty_square_brackets = false\ncsharp_space_between_method_call_empty_parameter_list_parentheses = false\ncsharp_space_between_method_call_name_and_opening_parenthesis = false\ncsharp_space_between_method_call_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_name_and_open_parenthesis = false\ncsharp_space_between_method_declaration_parameter_list_parentheses = false\ncsharp_space_between_parentheses = false\ncsharp_space_between_square_brackets = false\n\n# 包装首选项\ncsharp_preserve_single_line_blocks = true\ncsharp_preserve_single_line_statements = false\n\n#### 命名样式 ####\n\n# 命名规则\n\ndotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion\ndotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface\ndotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i\n\ndotnet_naming_rule.types_should_be_pascal_case.severity = suggestion\ndotnet_naming_rule.types_should_be_pascal_case.symbols = types\ndotnet_naming_rule.types_should_be_pascal_case.style = pascal_case\n\ndotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion\ndotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members\ndotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case\n\n# 符号规范\n\ndotnet_naming_symbols.interface.applicable_kinds = interface\ndotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal\ndotnet_naming_symbols.interface.required_modifiers = \n\ndotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum\ndotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal\ndotnet_naming_symbols.types.required_modifiers = \n\ndotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method\ndotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal\ndotnet_naming_symbols.non_field_members.required_modifiers = \n\n# 命名样式\n\ndotnet_naming_style.pascal_case.required_prefix =\ndotnet_naming_style.pascal_case.required_suffix =\ndotnet_naming_style.pascal_case.word_separator =\ndotnet_naming_style.pascal_case.capitalization = pascal_case\n\ndotnet_naming_style.begins_with_i.required_prefix = I\ndotnet_naming_style.begins_with_i.required_suffix =\ndotnet_naming_style.begins_with_i.word_separator =\ndotnet_naming_style.begins_with_i.capitalization = pascal_case\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG]\"\nlabels: Bug\nassignees: ''\n\n---\n\n**描述 bug**\n\n简要描述所遇到的bug\n\n**如何复现**\n\n说明您在进行了怎样的操作后出现了bug：\n\n1. \n2. \n3. \n\n**预期行为**\n\n简要描述进行以上操作后预期的脚本行为\n\n**截图**\n\n如果可以，请添加屏幕截图以帮助解释您的问题\n\n**环境**\n\n - 系统：[如 Windows 10 1809]\n - 浏览器：[如 Chrome 74.0.3729.157，无关则删除]\n - 程序版本：[如 5.0.0.0 .Net Core SelfContained x64]\n \n**其它内容**\n\n在此添加有关此问题的任何其它内容。\n最好能贴上相关的日志\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Telegram Channel\n    url: https://t.me/ShadowsocksR_Windows\n    about: Telegram Channel"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: Enhancement\nassignees: ''\n\n---\n\n**您的功能请求是否与 BUG 有关？ 请描述一下。**\n\n简明扼要地描述了问题所在\n\n**描述您想要的解决方案**\n\n简明扼要地描述您想要发生的事情\n\n**描述您考虑过的替代方案**\n\n对您考虑的任何替代解决方案或功能的简明扼要描述\n\n**其它内容**\n\n在此处添加有关功能请求的任何其它内容或屏幕截图\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/other-issue.md",
    "content": "---\nname: Other issue\nabout: Other issue\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n之所以写中文，本issue是写给打算写给乱发中文问题的人看的\n\n1. 不欢迎小白，不回答诸如软件如何使用，如何搭建，如何配置，使用速度不快，如何提速等等和软件问题无关的问题，或把开发者当成客服的问题\n2. 这里用于反馈软件可能的Bug，软件潜在的问题，和软件功能需求及讨论\n3. 同一个issue不得在不同repo重复发，除非你发现发错地方（这种情况下你自行删除错误的issue），否则直接关闭且不回答问题，严重者拉黑名单\n4. 建议你把问题事先在其它社区或和其它使用者讨论过，以确认不是密码错误，协议或插件错误，或服务器防火墙没关诸如此类本来应该自己解决的问题\n5. 在你确认你需要发问题时，请尽可能提供详细的信息，包括服务端客户端具体版本，及相应log，及相应服务端客户端协议混淆等等的配置。如信息明显过少，则直接close不理踩\n\n确认你读完以上内容后，请删除以上所有内容，然后写下你的问题\n\nPlease remove all above then write down your issue\n"
  },
  {
    "path": ".github/renovate.json",
    "content": "{\n\t\"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n\t\"assignees\": [\n\t\t\"HMBSbige\"\n\t],\n\t\"commitMessagePrefix\": \"dep:\",\n\t\"dependencyDashboard\": false,\n\t\"extends\": [\n\t\t\"config:base\",\n\t\t\":automergeBranch\",\n\t\t\":automergeDigest\",\n\t\t\":automergeMinor\",\n\t\t\":disableRateLimiting\"\n\t],\n\t\"packageRules\": [\n\t\t{\n\t\t\t\"matchPackagePrefixes\": [\n\t\t\t\t\"Syncfusion\"\n\t\t\t],\n\t\t\t\"groupName\": \"Syncfusion\"\n\t\t}\n\t],\n\t\"labels\": [\n\t\t\"Automatic\"\n\t]\n}"
  },
  {
    "path": ".github/workflows/CI.yml",
    "content": "name: CI\non: [push, pull_request, workflow_dispatch]\nenv:\n  ProjectName: ShadowsocksR\n\njobs:\n\n  build:\n    name: Build\n    runs-on: windows-latest\n    env:\n      SyncfusionLicenseKey: ${{ secrets.SyncfusionLicenseKey }}\n      NET_TFM: net7.0-windows\n      Configuration: Release\n\n    steps:\n    - name: Checkout code\n      uses: actions/checkout@v4\n      with:\n        submodules: true\n\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        dotnet-version: 7.0.x\n\n    - name: Setup NuGet Private Sources\n      shell: pwsh\n      run: dotnet nuget add source https://nuget.pkg.github.com/HMBSbige/index.json -n GitHub-HMBSbige -u HMBSbige -p ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text\n\n    - name: Build .NET App\n      shell: pwsh\n      run: .\\build.ps1 app\n\n    - name: Build x64\n      shell: pwsh\n      run: .\\build.ps1 x64\n\n    - name: Build x86\n      shell: pwsh\n      run: .\\build.ps1 x86\n\n    - name: Upload .NET App\n      continue-on-error: true\n      if: ${{ !startsWith(github.ref, 'refs/tags/') }}\n      uses: actions/upload-artifact@v4\n      with:\n        name: ${{ env.ProjectName }}\n        path: shadowsocks-csharp\\bin\\${{ env.Configuration }}\\${{ env.NET_TFM }}\\publish\\\n\n    - name: Upload x64\n      continue-on-error: true\n      if: ${{ !startsWith(github.ref, 'refs/tags/') }}\n      uses: actions/upload-artifact@v4\n      with:\n        name: ${{ env.ProjectName }}-Win64\n        path: shadowsocks-csharp\\bin\\${{ env.Configuration }}\\${{ env.NET_TFM }}\\win-x64\\publish\\\n\n    - name: Upload x86\n      continue-on-error: true\n      if: ${{ !startsWith(github.ref, 'refs/tags/') }}\n      uses: actions/upload-artifact@v4\n      with:\n        name: ${{ env.ProjectName }}-Win32\n        path: shadowsocks-csharp\\bin\\${{ env.Configuration }}\\${{ env.NET_TFM }}\\win-x86\\publish\\\n\n    - name: Get tag\n      if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}\n      id: tag\n      uses: dawidd6/action-get-tag@v1\n\n    - name: Package .NET App\n      if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}\n      shell: pwsh\n      run: |\n        New-Item -ItemType Directory -Path C:\\builtfiles -Force > $null\n        $zip_path = \"C:\\builtfiles\\$env:ProjectName-${{ steps.tag.outputs.tag }}.7z\"\n        7z a -mx9 \"$zip_path\" \".\\shadowsocks-csharp\\bin\\$env:Configuration\\$env:NET_TFM\\publish\\\"\n        7z rn \"$zip_path\" publish $env:ProjectName\n        echo \"NET_SHA256=$((Get-FileHash $zip_path -Algorithm SHA256).Hash)\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n\n    - name: Package x64\n      if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}\n      shell: pwsh\n      run: |\n        New-Item -ItemType Directory -Path C:\\builtfiles -Force > $null\n        $zip_path = \"C:\\builtfiles\\$env:ProjectName-Win64-${{ steps.tag.outputs.tag }}.7z\"\n        7z a -mx9 \"$zip_path\" \".\\shadowsocks-csharp\\bin\\$env:Configuration\\$env:NET_TFM\\win-x64\\publish\\\"\n        7z rn \"$zip_path\" publish $env:ProjectName\n        echo \"NET64_SHA256=$((Get-FileHash $zip_path -Algorithm SHA256).Hash)\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n\n    - name: Package x86\n      if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}\n      shell: pwsh\n      run: |\n        New-Item -ItemType Directory -Path C:\\builtfiles -Force > $null\n        $zip_path = \"C:\\builtfiles\\$env:ProjectName-Win32-${{ steps.tag.outputs.tag }}.7z\"\n        7z a -mx9 \"$zip_path\" \".\\shadowsocks-csharp\\bin\\$env:Configuration\\$env:NET_TFM\\win-x86\\publish\\\"\n        7z rn \"$zip_path\" publish $env:ProjectName\n        echo \"NET86_SHA256=$((Get-FileHash $zip_path -Algorithm SHA256).Hash)\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n\n    - name: Create a new GitHub release if a new tag is pushed\n      uses: ncipollo/release-action@v1\n      if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}\n      with:\n        token: ${{ secrets.GITHUB_TOKEN }}\n        name: v${{ steps.tag.outputs.tag }}\n        prerelease: true\n        draft: false\n        artifacts: C:\\builtfiles\\*\n        body: |\n          [![](https://img.shields.io/badge/Channel-blue?label=Telegram&logo=telegram)](https://t.me/ShadowsocksR_Windows) [![](https://img.shields.io/badge/Group-green?label=Telegram&logo=telegram)](https://t.me/joinchat/Gn-Aa0-j4HcpdBaW-Iv8Sw)\n\n          ## 更新日志：\n          * 这是 GitHub Action 自动化部署，更新日志应该很快会手动更新\n\n          ## 文件校验\n          | 文件名 | SHA256 |\n          | :- | :- |\n          | <sub>${{ env.ProjectName }}-${{ steps.tag.outputs.tag }}.7z</sub> | <sub>${{ env.NET_SHA256 }}</sub> |\n          | <sub>${{ env.ProjectName }}-Win64-${{ steps.tag.outputs.tag }}.7z</sub> | <sub>${{ env.NET64_SHA256 }}</sub> |\n          | <sub>${{ env.ProjectName }}-Win32-${{ steps.tag.outputs.tag }}.7z</sub> | <sub>${{ env.NET86_SHA256 }}</sub> |\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/"
  },
  {
    "path": "Build/DotNetDllPathPatcher.ps1",
    "content": "using namespace System.IO\nusing namespace System.Text\n\nparam([string]$exe_path, [string]$target_path = 'bin')\n$ErrorActionPreference = 'Stop'\n#$DebugPreference = 'Continue'\n\n$exe_path = (Resolve-Path -Path $exe_path).Path\n\nWrite-Host \"Origin path: `\"$exe_path`\"\"\nWrite-Host \"Target dll path: $target_path\"\n\n$separator = '\\'\n$max_path_length = 1024\n\n$exe_name = [Path]::GetFileName($exe_path)\n$dll_name = [Path]::ChangeExtension($exe_name, '.dll')\nWrite-Debug \"exe: $exe_name\"\nWrite-Debug \"dll: $dll_name\"\n\nfunction Update-Exe {\n    $old_bytes = [Encoding]::UTF8.GetBytes(\"$dll_name`0\")\n    if ($old_bytes.Count -gt $max_path_length) {\n        throw [PathTooLongException] 'old dll path is too long'\n    }\n\n    $new_dll_path = \"$target_path$separator$dll_name\"\n    $new_bytes = [Encoding]::UTF8.GetBytes(\"$new_dll_path`0\")\n    Write-Host \"Dll path Change to `\"$new_dll_path`\"\"\n    if ($new_bytes.Count -gt $max_path_length) {\n        throw [PathTooLongException] 'new dll path is too long'\n    }\n\n    $bytes = [File]::ReadAllBytes($exe_path)\n    $index = (Get-Content $exe_path -Raw -Encoding 28591).IndexOf(\"$dll_name`0\")\n    if ($index -lt 0) {\n        throw [InvalidDataException] 'Could not find old dll path'\n    }\n    Write-Debug \"Position: $index\"\n    $end_postion = $index + $($new_bytes.Count)\n    $end_length = $bytes.Count - $end_postion\n    if ($end_postion -gt $bytes.Count) {\n        throw [PathTooLongException] 'new dll path is too long'\n    }\n    Write-Debug \"End Position: $end_postion\"\n    Write-Debug \"End Length: $end_length\"\n\n    $fs = [File]::OpenWrite($exe_path)\n    try {\n        $fs.Write($bytes, 0, $index)\n        $fs.Write($new_bytes)\n        $fs.Write($bytes, $end_postion, $end_length)\n    }\n    finally {\n        $fs.Dispose();\n    }\n}\n\nfunction Move-Dll {\n    $tmpbin = 'tmpbin'\n    $dir = [Path]::GetDirectoryName($exe_path);\n    $root = [Path]::GetDirectoryName($dir);\n    Write-Debug \"root path: $root\"\n    Write-Debug \"dir path: $dir\"\n\n    Rename-Item $dir $tmpbin\n    New-Item -ItemType Directory $dir > $null\n    Move-Item $root\\$tmpbin $dir\n    Rename-Item $dir\\$tmpbin $target_path\n    Move-Item $dir\\$target_path\\$exe_name $dir\n}\n\nUpdate-Exe\nMove-Dll"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "How to Contribute\n=================\n\nPull Requests\n-------------\n\n1. Pull requests are welcome.\n2. Make sure to pass the unit tests. Write unit tests for new modules if\nneeded.\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\r\n                       Version 3, 29 June 2007\r\n\r\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\r\n Everyone is permitted to copy and distribute verbatim copies\r\n of this license document, but changing it is not allowed.\r\n\r\n                            Preamble\r\n\r\n  The GNU General Public License is a free, copyleft license for\r\nsoftware and other kinds of works.\r\n\r\n  The licenses for most software and other practical works are designed\r\nto take away your freedom to share and change the works.  By contrast,\r\nthe GNU General Public License is intended to guarantee your freedom to\r\nshare and change all versions of a program--to make sure it remains free\r\nsoftware for all its users.  We, the Free Software Foundation, use the\r\nGNU General Public License for most of our software; it applies also to\r\nany other work released this way by its authors.  You can apply it to\r\nyour programs, too.\r\n\r\n  When we speak of free software, we are referring to freedom, not\r\nprice.  Our General Public Licenses are designed to make sure that you\r\nhave the freedom to distribute copies of free software (and charge for\r\nthem if you wish), that you receive source code or can get it if you\r\nwant it, that you can change the software or use pieces of it in new\r\nfree programs, and that you know you can do these things.\r\n\r\n  To protect your rights, we need to prevent others from denying you\r\nthese rights or asking you to surrender the rights.  Therefore, you have\r\ncertain responsibilities if you distribute copies of the software, or if\r\nyou modify it: responsibilities to respect the freedom of others.\r\n\r\n  For example, if you distribute copies of such a program, whether\r\ngratis or for a fee, you must pass on to the recipients the same\r\nfreedoms that you received.  You must make sure that they, too, receive\r\nor can get the source code.  And you must show them these terms so they\r\nknow their rights.\r\n\r\n  Developers that use the GNU GPL protect your rights with two steps:\r\n(1) assert copyright on the software, and (2) offer you this License\r\ngiving you legal permission to copy, distribute and/or modify it.\r\n\r\n  For the developers' and authors' protection, the GPL clearly explains\r\nthat there is no warranty for this free software.  For both users' and\r\nauthors' sake, the GPL requires that modified versions be marked as\r\nchanged, so that their problems will not be attributed erroneously to\r\nauthors of previous versions.\r\n\r\n  Some devices are designed to deny users access to install or run\r\nmodified versions of the software inside them, although the manufacturer\r\ncan do so.  This is fundamentally incompatible with the aim of\r\nprotecting users' freedom to change the software.  The systematic\r\npattern of such abuse occurs in the area of products for individuals to\r\nuse, which is precisely where it is most unacceptable.  Therefore, we\r\nhave designed this version of the GPL to prohibit the practice for those\r\nproducts.  If such problems arise substantially in other domains, we\r\nstand ready to extend this provision to those domains in future versions\r\nof the GPL, as needed to protect the freedom of users.\r\n\r\n  Finally, every program is threatened constantly by software patents.\r\nStates should not allow patents to restrict development and use of\r\nsoftware on general-purpose computers, but in those that do, we wish to\r\navoid the special danger that patents applied to a free program could\r\nmake it effectively proprietary.  To prevent this, the GPL assures that\r\npatents cannot be used to render the program non-free.\r\n\r\n  The precise terms and conditions for copying, distribution and\r\nmodification follow.\r\n\r\n                       TERMS AND CONDITIONS\r\n\r\n  0. Definitions.\r\n\r\n  \"This License\" refers to version 3 of the GNU General Public License.\r\n\r\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\r\nworks, such as semiconductor masks.\r\n\r\n  \"The Program\" refers to any copyrightable work licensed under this\r\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\r\n\"recipients\" may be individuals or organizations.\r\n\r\n  To \"modify\" a work means to copy from or adapt all or part of the work\r\nin a fashion requiring copyright permission, other than the making of an\r\nexact copy.  The resulting work is called a \"modified version\" of the\r\nearlier work or a work \"based on\" the earlier work.\r\n\r\n  A \"covered work\" means either the unmodified Program or a work based\r\non the Program.\r\n\r\n  To \"propagate\" a work means to do anything with it that, without\r\npermission, would make you directly or secondarily liable for\r\ninfringement under applicable copyright law, except executing it on a\r\ncomputer or modifying a private copy.  Propagation includes copying,\r\ndistribution (with or without modification), making available to the\r\npublic, and in some countries other activities as well.\r\n\r\n  To \"convey\" a work means any kind of propagation that enables other\r\nparties to make or receive copies.  Mere interaction with a user through\r\na computer network, with no transfer of a copy, is not conveying.\r\n\r\n  An interactive user interface displays \"Appropriate Legal Notices\"\r\nto the extent that it includes a convenient and prominently visible\r\nfeature that (1) displays an appropriate copyright notice, and (2)\r\ntells the user that there is no warranty for the work (except to the\r\nextent that warranties are provided), that licensees may convey the\r\nwork under this License, and how to view a copy of this License.  If\r\nthe interface presents a list of user commands or options, such as a\r\nmenu, a prominent item in the list meets this criterion.\r\n\r\n  1. Source Code.\r\n\r\n  The \"source code\" for a work means the preferred form of the work\r\nfor making modifications to it.  \"Object code\" means any non-source\r\nform of a work.\r\n\r\n  A \"Standard Interface\" means an interface that either is an official\r\nstandard defined by a recognized standards body, or, in the case of\r\ninterfaces specified for a particular programming language, one that\r\nis widely used among developers working in that language.\r\n\r\n  The \"System Libraries\" of an executable work include anything, other\r\nthan the work as a whole, that (a) is included in the normal form of\r\npackaging a Major Component, but which is not part of that Major\r\nComponent, and (b) serves only to enable use of the work with that\r\nMajor Component, or to implement a Standard Interface for which an\r\nimplementation is available to the public in source code form.  A\r\n\"Major Component\", in this context, means a major essential component\r\n(kernel, window system, and so on) of the specific operating system\r\n(if any) on which the executable work runs, or a compiler used to\r\nproduce the work, or an object code interpreter used to run it.\r\n\r\n  The \"Corresponding Source\" for a work in object code form means all\r\nthe source code needed to generate, install, and (for an executable\r\nwork) run the object code and to modify the work, including scripts to\r\ncontrol those activities.  However, it does not include the work's\r\nSystem Libraries, or general-purpose tools or generally available free\r\nprograms which are used unmodified in performing those activities but\r\nwhich are not part of the work.  For example, Corresponding Source\r\nincludes interface definition files associated with source files for\r\nthe work, and the source code for shared libraries and dynamically\r\nlinked subprograms that the work is specifically designed to require,\r\nsuch as by intimate data communication or control flow between those\r\nsubprograms and other parts of the work.\r\n\r\n  The Corresponding Source need not include anything that users\r\ncan regenerate automatically from other parts of the Corresponding\r\nSource.\r\n\r\n  The Corresponding Source for a work in source code form is that\r\nsame work.\r\n\r\n  2. Basic Permissions.\r\n\r\n  All rights granted under this License are granted for the term of\r\ncopyright on the Program, and are irrevocable provided the stated\r\nconditions are met.  This License explicitly affirms your unlimited\r\npermission to run the unmodified Program.  The output from running a\r\ncovered work is covered by this License only if the output, given its\r\ncontent, constitutes a covered work.  This License acknowledges your\r\nrights of fair use or other equivalent, as provided by copyright law.\r\n\r\n  You may make, run and propagate covered works that you do not\r\nconvey, without conditions so long as your license otherwise remains\r\nin force.  You may convey covered works to others for the sole purpose\r\nof having them make modifications exclusively for you, or provide you\r\nwith facilities for running those works, provided that you comply with\r\nthe terms of this License in conveying all material for which you do\r\nnot control copyright.  Those thus making or running the covered works\r\nfor you must do so exclusively on your behalf, under your direction\r\nand control, on terms that prohibit them from making any copies of\r\nyour copyrighted material outside their relationship with you.\r\n\r\n  Conveying under any other circumstances is permitted solely under\r\nthe conditions stated below.  Sublicensing is not allowed; section 10\r\nmakes it unnecessary.\r\n\r\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\r\n\r\n  No covered work shall be deemed part of an effective technological\r\nmeasure under any applicable law fulfilling obligations under article\r\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\r\nsimilar laws prohibiting or restricting circumvention of such\r\nmeasures.\r\n\r\n  When you convey a covered work, you waive any legal power to forbid\r\ncircumvention of technological measures to the extent such circumvention\r\nis effected by exercising rights under this License with respect to\r\nthe covered work, and you disclaim any intention to limit operation or\r\nmodification of the work as a means of enforcing, against the work's\r\nusers, your or third parties' legal rights to forbid circumvention of\r\ntechnological measures.\r\n\r\n  4. Conveying Verbatim Copies.\r\n\r\n  You may convey verbatim copies of the Program's source code as you\r\nreceive it, in any medium, provided that you conspicuously and\r\nappropriately publish on each copy an appropriate copyright notice;\r\nkeep intact all notices stating that this License and any\r\nnon-permissive terms added in accord with section 7 apply to the code;\r\nkeep intact all notices of the absence of any warranty; and give all\r\nrecipients a copy of this License along with the Program.\r\n\r\n  You may charge any price or no price for each copy that you convey,\r\nand you may offer support or warranty protection for a fee.\r\n\r\n  5. Conveying Modified Source Versions.\r\n\r\n  You may convey a work based on the Program, or the modifications to\r\nproduce it from the Program, in the form of source code under the\r\nterms of section 4, provided that you also meet all of these conditions:\r\n\r\n    a) The work must carry prominent notices stating that you modified\r\n    it, and giving a relevant date.\r\n\r\n    b) The work must carry prominent notices stating that it is\r\n    released under this License and any conditions added under section\r\n    7.  This requirement modifies the requirement in section 4 to\r\n    \"keep intact all notices\".\r\n\r\n    c) You must license the entire work, as a whole, under this\r\n    License to anyone who comes into possession of a copy.  This\r\n    License will therefore apply, along with any applicable section 7\r\n    additional terms, to the whole of the work, and all its parts,\r\n    regardless of how they are packaged.  This License gives no\r\n    permission to license the work in any other way, but it does not\r\n    invalidate such permission if you have separately received it.\r\n\r\n    d) If the work has interactive user interfaces, each must display\r\n    Appropriate Legal Notices; however, if the Program has interactive\r\n    interfaces that do not display Appropriate Legal Notices, your\r\n    work need not make them do so.\r\n\r\n  A compilation of a covered work with other separate and independent\r\nworks, which are not by their nature extensions of the covered work,\r\nand which are not combined with it such as to form a larger program,\r\nin or on a volume of a storage or distribution medium, is called an\r\n\"aggregate\" if the compilation and its resulting copyright are not\r\nused to limit the access or legal rights of the compilation's users\r\nbeyond what the individual works permit.  Inclusion of a covered work\r\nin an aggregate does not cause this License to apply to the other\r\nparts of the aggregate.\r\n\r\n  6. Conveying Non-Source Forms.\r\n\r\n  You may convey a covered work in object code form under the terms\r\nof sections 4 and 5, provided that you also convey the\r\nmachine-readable Corresponding Source under the terms of this License,\r\nin one of these ways:\r\n\r\n    a) Convey the object code in, or embodied in, a physical product\r\n    (including a physical distribution medium), accompanied by the\r\n    Corresponding Source fixed on a durable physical medium\r\n    customarily used for software interchange.\r\n\r\n    b) Convey the object code in, or embodied in, a physical product\r\n    (including a physical distribution medium), accompanied by a\r\n    written offer, valid for at least three years and valid for as\r\n    long as you offer spare parts or customer support for that product\r\n    model, to give anyone who possesses the object code either (1) a\r\n    copy of the Corresponding Source for all the software in the\r\n    product that is covered by this License, on a durable physical\r\n    medium customarily used for software interchange, for a price no\r\n    more than your reasonable cost of physically performing this\r\n    conveying of source, or (2) access to copy the\r\n    Corresponding Source from a network server at no charge.\r\n\r\n    c) Convey individual copies of the object code with a copy of the\r\n    written offer to provide the Corresponding Source.  This\r\n    alternative is allowed only occasionally and noncommercially, and\r\n    only if you received the object code with such an offer, in accord\r\n    with subsection 6b.\r\n\r\n    d) Convey the object code by offering access from a designated\r\n    place (gratis or for a charge), and offer equivalent access to the\r\n    Corresponding Source in the same way through the same place at no\r\n    further charge.  You need not require recipients to copy the\r\n    Corresponding Source along with the object code.  If the place to\r\n    copy the object code is a network server, the Corresponding Source\r\n    may be on a different server (operated by you or a third party)\r\n    that supports equivalent copying facilities, provided you maintain\r\n    clear directions next to the object code saying where to find the\r\n    Corresponding Source.  Regardless of what server hosts the\r\n    Corresponding Source, you remain obligated to ensure that it is\r\n    available for as long as needed to satisfy these requirements.\r\n\r\n    e) Convey the object code using peer-to-peer transmission, provided\r\n    you inform other peers where the object code and Corresponding\r\n    Source of the work are being offered to the general public at no\r\n    charge under subsection 6d.\r\n\r\n  A separable portion of the object code, whose source code is excluded\r\nfrom the Corresponding Source as a System Library, need not be\r\nincluded in conveying the object code work.\r\n\r\n  A \"User Product\" is either (1) a \"consumer product\", which means any\r\ntangible personal property which is normally used for personal, family,\r\nor household purposes, or (2) anything designed or sold for incorporation\r\ninto a dwelling.  In determining whether a product is a consumer product,\r\ndoubtful cases shall be resolved in favor of coverage.  For a particular\r\nproduct received by a particular user, \"normally used\" refers to a\r\ntypical or common use of that class of product, regardless of the status\r\nof the particular user or of the way in which the particular user\r\nactually uses, or expects or is expected to use, the product.  A product\r\nis a consumer product regardless of whether the product has substantial\r\ncommercial, industrial or non-consumer uses, unless such uses represent\r\nthe only significant mode of use of the product.\r\n\r\n  \"Installation Information\" for a User Product means any methods,\r\nprocedures, authorization keys, or other information required to install\r\nand execute modified versions of a covered work in that User Product from\r\na modified version of its Corresponding Source.  The information must\r\nsuffice to ensure that the continued functioning of the modified object\r\ncode is in no case prevented or interfered with solely because\r\nmodification has been made.\r\n\r\n  If you convey an object code work under this section in, or with, or\r\nspecifically for use in, a User Product, and the conveying occurs as\r\npart of a transaction in which the right of possession and use of the\r\nUser Product is transferred to the recipient in perpetuity or for a\r\nfixed term (regardless of how the transaction is characterized), the\r\nCorresponding Source conveyed under this section must be accompanied\r\nby the Installation Information.  But this requirement does not apply\r\nif neither you nor any third party retains the ability to install\r\nmodified object code on the User Product (for example, the work has\r\nbeen installed in ROM).\r\n\r\n  The requirement to provide Installation Information does not include a\r\nrequirement to continue to provide support service, warranty, or updates\r\nfor a work that has been modified or installed by the recipient, or for\r\nthe User Product in which it has been modified or installed.  Access to a\r\nnetwork may be denied when the modification itself materially and\r\nadversely affects the operation of the network or violates the rules and\r\nprotocols for communication across the network.\r\n\r\n  Corresponding Source conveyed, and Installation Information provided,\r\nin accord with this section must be in a format that is publicly\r\ndocumented (and with an implementation available to the public in\r\nsource code form), and must require no special password or key for\r\nunpacking, reading or copying.\r\n\r\n  7. Additional Terms.\r\n\r\n  \"Additional permissions\" are terms that supplement the terms of this\r\nLicense by making exceptions from one or more of its conditions.\r\nAdditional permissions that are applicable to the entire Program shall\r\nbe treated as though they were included in this License, to the extent\r\nthat they are valid under applicable law.  If additional permissions\r\napply only to part of the Program, that part may be used separately\r\nunder those permissions, but the entire Program remains governed by\r\nthis License without regard to the additional permissions.\r\n\r\n  When you convey a copy of a covered work, you may at your option\r\nremove any additional permissions from that copy, or from any part of\r\nit.  (Additional permissions may be written to require their own\r\nremoval in certain cases when you modify the work.)  You may place\r\nadditional permissions on material, added by you to a covered work,\r\nfor which you have or can give appropriate copyright permission.\r\n\r\n  Notwithstanding any other provision of this License, for material you\r\nadd to a covered work, you may (if authorized by the copyright holders of\r\nthat material) supplement the terms of this License with terms:\r\n\r\n    a) Disclaiming warranty or limiting liability differently from the\r\n    terms of sections 15 and 16 of this License; or\r\n\r\n    b) Requiring preservation of specified reasonable legal notices or\r\n    author attributions in that material or in the Appropriate Legal\r\n    Notices displayed by works containing it; or\r\n\r\n    c) Prohibiting misrepresentation of the origin of that material, or\r\n    requiring that modified versions of such material be marked in\r\n    reasonable ways as different from the original version; or\r\n\r\n    d) Limiting the use for publicity purposes of names of licensors or\r\n    authors of the material; or\r\n\r\n    e) Declining to grant rights under trademark law for use of some\r\n    trade names, trademarks, or service marks; or\r\n\r\n    f) Requiring indemnification of licensors and authors of that\r\n    material by anyone who conveys the material (or modified versions of\r\n    it) with contractual assumptions of liability to the recipient, for\r\n    any liability that these contractual assumptions directly impose on\r\n    those licensors and authors.\r\n\r\n  All other non-permissive additional terms are considered \"further\r\nrestrictions\" within the meaning of section 10.  If the Program as you\r\nreceived it, or any part of it, contains a notice stating that it is\r\ngoverned by this License along with a term that is a further\r\nrestriction, you may remove that term.  If a license document contains\r\na further restriction but permits relicensing or conveying under this\r\nLicense, you may add to a covered work material governed by the terms\r\nof that license document, provided that the further restriction does\r\nnot survive such relicensing or conveying.\r\n\r\n  If you add terms to a covered work in accord with this section, you\r\nmust place, in the relevant source files, a statement of the\r\nadditional terms that apply to those files, or a notice indicating\r\nwhere to find the applicable terms.\r\n\r\n  Additional terms, permissive or non-permissive, may be stated in the\r\nform of a separately written license, or stated as exceptions;\r\nthe above requirements apply either way.\r\n\r\n  8. Termination.\r\n\r\n  You may not propagate or modify a covered work except as expressly\r\nprovided under this License.  Any attempt otherwise to propagate or\r\nmodify it is void, and will automatically terminate your rights under\r\nthis License (including any patent licenses granted under the third\r\nparagraph of section 11).\r\n\r\n  However, if you cease all violation of this License, then your\r\nlicense from a particular copyright holder is reinstated (a)\r\nprovisionally, unless and until the copyright holder explicitly and\r\nfinally terminates your license, and (b) permanently, if the copyright\r\nholder fails to notify you of the violation by some reasonable means\r\nprior to 60 days after the cessation.\r\n\r\n  Moreover, your license from a particular copyright holder is\r\nreinstated permanently if the copyright holder notifies you of the\r\nviolation by some reasonable means, this is the first time you have\r\nreceived notice of violation of this License (for any work) from that\r\ncopyright holder, and you cure the violation prior to 30 days after\r\nyour receipt of the notice.\r\n\r\n  Termination of your rights under this section does not terminate the\r\nlicenses of parties who have received copies or rights from you under\r\nthis License.  If your rights have been terminated and not permanently\r\nreinstated, you do not qualify to receive new licenses for the same\r\nmaterial under section 10.\r\n\r\n  9. Acceptance Not Required for Having Copies.\r\n\r\n  You are not required to accept this License in order to receive or\r\nrun a copy of the Program.  Ancillary propagation of a covered work\r\noccurring solely as a consequence of using peer-to-peer transmission\r\nto receive a copy likewise does not require acceptance.  However,\r\nnothing other than this License grants you permission to propagate or\r\nmodify any covered work.  These actions infringe copyright if you do\r\nnot accept this License.  Therefore, by modifying or propagating a\r\ncovered work, you indicate your acceptance of this License to do so.\r\n\r\n  10. Automatic Licensing of Downstream Recipients.\r\n\r\n  Each time you convey a covered work, the recipient automatically\r\nreceives a license from the original licensors, to run, modify and\r\npropagate that work, subject to this License.  You are not responsible\r\nfor enforcing compliance by third parties with this License.\r\n\r\n  An \"entity transaction\" is a transaction transferring control of an\r\norganization, or substantially all assets of one, or subdividing an\r\norganization, or merging organizations.  If propagation of a covered\r\nwork results from an entity transaction, each party to that\r\ntransaction who receives a copy of the work also receives whatever\r\nlicenses to the work the party's predecessor in interest had or could\r\ngive under the previous paragraph, plus a right to possession of the\r\nCorresponding Source of the work from the predecessor in interest, if\r\nthe predecessor has it or can get it with reasonable efforts.\r\n\r\n  You may not impose any further restrictions on the exercise of the\r\nrights granted or affirmed under this License.  For example, you may\r\nnot impose a license fee, royalty, or other charge for exercise of\r\nrights granted under this License, and you may not initiate litigation\r\n(including a cross-claim or counterclaim in a lawsuit) alleging that\r\nany patent claim is infringed by making, using, selling, offering for\r\nsale, or importing the Program or any portion of it.\r\n\r\n  11. Patents.\r\n\r\n  A \"contributor\" is a copyright holder who authorizes use under this\r\nLicense of the Program or a work on which the Program is based.  The\r\nwork thus licensed is called the contributor's \"contributor version\".\r\n\r\n  A contributor's \"essential patent claims\" are all patent claims\r\nowned or controlled by the contributor, whether already acquired or\r\nhereafter acquired, that would be infringed by some manner, permitted\r\nby this License, of making, using, or selling its contributor version,\r\nbut do not include claims that would be infringed only as a\r\nconsequence of further modification of the contributor version.  For\r\npurposes of this definition, \"control\" includes the right to grant\r\npatent sublicenses in a manner consistent with the requirements of\r\nthis License.\r\n\r\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\r\npatent license under the contributor's essential patent claims, to\r\nmake, use, sell, offer for sale, import and otherwise run, modify and\r\npropagate the contents of its contributor version.\r\n\r\n  In the following three paragraphs, a \"patent license\" is any express\r\nagreement or commitment, however denominated, not to enforce a patent\r\n(such as an express permission to practice a patent or covenant not to\r\nsue for patent infringement).  To \"grant\" such a patent license to a\r\nparty means to make such an agreement or commitment not to enforce a\r\npatent against the party.\r\n\r\n  If you convey a covered work, knowingly relying on a patent license,\r\nand the Corresponding Source of the work is not available for anyone\r\nto copy, free of charge and under the terms of this License, through a\r\npublicly available network server or other readily accessible means,\r\nthen you must either (1) cause the Corresponding Source to be so\r\navailable, or (2) arrange to deprive yourself of the benefit of the\r\npatent license for this particular work, or (3) arrange, in a manner\r\nconsistent with the requirements of this License, to extend the patent\r\nlicense to downstream recipients.  \"Knowingly relying\" means you have\r\nactual knowledge that, but for the patent license, your conveying the\r\ncovered work in a country, or your recipient's use of the covered work\r\nin a country, would infringe one or more identifiable patents in that\r\ncountry that you have reason to believe are valid.\r\n\r\n  If, pursuant to or in connection with a single transaction or\r\narrangement, you convey, or propagate by procuring conveyance of, a\r\ncovered work, and grant a patent license to some of the parties\r\nreceiving the covered work authorizing them to use, propagate, modify\r\nor convey a specific copy of the covered work, then the patent license\r\nyou grant is automatically extended to all recipients of the covered\r\nwork and works based on it.\r\n\r\n  A patent license is \"discriminatory\" if it does not include within\r\nthe scope of its coverage, prohibits the exercise of, or is\r\nconditioned on the non-exercise of one or more of the rights that are\r\nspecifically granted under this License.  You may not convey a covered\r\nwork if you are a party to an arrangement with a third party that is\r\nin the business of distributing software, under which you make payment\r\nto the third party based on the extent of your activity of conveying\r\nthe work, and under which the third party grants, to any of the\r\nparties who would receive the covered work from you, a discriminatory\r\npatent license (a) in connection with copies of the covered work\r\nconveyed by you (or copies made from those copies), or (b) primarily\r\nfor and in connection with specific products or compilations that\r\ncontain the covered work, unless you entered into that arrangement,\r\nor that patent license was granted, prior to 28 March 2007.\r\n\r\n  Nothing in this License shall be construed as excluding or limiting\r\nany implied license or other defenses to infringement that may\r\notherwise be available to you under applicable patent law.\r\n\r\n  12. No Surrender of Others' Freedom.\r\n\r\n  If conditions are imposed on you (whether by court order, agreement or\r\notherwise) that contradict the conditions of this License, they do not\r\nexcuse you from the conditions of this License.  If you cannot convey a\r\ncovered work so as to satisfy simultaneously your obligations under this\r\nLicense and any other pertinent obligations, then as a consequence you may\r\nnot convey it at all.  For example, if you agree to terms that obligate you\r\nto collect a royalty for further conveying from those to whom you convey\r\nthe Program, the only way you could satisfy both those terms and this\r\nLicense would be to refrain entirely from conveying the Program.\r\n\r\n  13. Use with the GNU Affero General Public License.\r\n\r\n  Notwithstanding any other provision of this License, you have\r\npermission to link or combine any covered work with a work licensed\r\nunder version 3 of the GNU Affero General Public License into a single\r\ncombined work, and to convey the resulting work.  The terms of this\r\nLicense will continue to apply to the part which is the covered work,\r\nbut the special requirements of the GNU Affero General Public License,\r\nsection 13, concerning interaction through a network will apply to the\r\ncombination as such.\r\n\r\n  14. Revised Versions of this License.\r\n\r\n  The Free Software Foundation may publish revised and/or new versions of\r\nthe GNU General Public License from time to time.  Such new versions will\r\nbe similar in spirit to the present version, but may differ in detail to\r\naddress new problems or concerns.\r\n\r\n  Each version is given a distinguishing version number.  If the\r\nProgram specifies that a certain numbered version of the GNU General\r\nPublic License \"or any later version\" applies to it, you have the\r\noption of following the terms and conditions either of that numbered\r\nversion or of any later version published by the Free Software\r\nFoundation.  If the Program does not specify a version number of the\r\nGNU General Public License, you may choose any version ever published\r\nby the Free Software Foundation.\r\n\r\n  If the Program specifies that a proxy can decide which future\r\nversions of the GNU General Public License can be used, that proxy's\r\npublic statement of acceptance of a version permanently authorizes you\r\nto choose that version for the Program.\r\n\r\n  Later license versions may give you additional or different\r\npermissions.  However, no additional obligations are imposed on any\r\nauthor or copyright holder as a result of your choosing to follow a\r\nlater version.\r\n\r\n  15. Disclaimer of Warranty.\r\n\r\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\r\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\r\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\r\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\r\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\r\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\r\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r\n\r\n  16. Limitation of Liability.\r\n\r\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\r\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\r\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\r\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\r\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\r\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\r\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\r\nSUCH DAMAGES.\r\n\r\n  17. Interpretation of Sections 15 and 16.\r\n\r\n  If the disclaimer of warranty and limitation of liability provided\r\nabove cannot be given local legal effect according to their terms,\r\nreviewing courts shall apply local law that most closely approximates\r\nan absolute waiver of all civil liability in connection with the\r\nProgram, unless a warranty or assumption of liability accompanies a\r\ncopy of the Program in return for a fee.\r\n\r\n                     END OF TERMS AND CONDITIONS\r\n\r\n            How to Apply These Terms to Your New Programs\r\n\r\n  If you develop a new program, and you want it to be of the greatest\r\npossible use to the public, the best way to achieve this is to make it\r\nfree software which everyone can redistribute and change under these terms.\r\n\r\n  To do so, attach the following notices to the program.  It is safest\r\nto attach them to the start of each source file to most effectively\r\nstate the exclusion of warranty; and each file should have at least\r\nthe \"copyright\" line and a pointer to where the full notice is found.\r\n\r\n    {one line to give the program's name and a brief idea of what it does.}\r\n    Copyright (C) {year}  {name of author}\r\n\r\n    This program is free software: you can redistribute it and/or modify\r\n    it under the terms of the GNU General Public License as published by\r\n    the Free Software Foundation, either version 3 of the License, or\r\n    (at your option) any later version.\r\n\r\n    This program is distributed in the hope that it will be useful,\r\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n    GNU General Public License for more details.\r\n\r\n    You should have received a copy of the GNU General Public License\r\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n\r\nAlso add information on how to contact you by electronic and paper mail.\r\n\r\n  If the program does terminal interaction, make it output a short\r\nnotice like this when it starts in an interactive mode:\r\n\r\n    {project}  Copyright (C) {year}  {fullname}\r\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r\n    This is free software, and you are welcome to redistribute it\r\n    under certain conditions; type `show c' for details.\r\n\r\nThe hypothetical commands `show w' and `show c' should show the appropriate\r\nparts of the General Public License.  Of course, your program's commands\r\nmight be different; for a GUI interface, you would use an \"about box\".\r\n\r\n  You should also get your employer (if you work as a programmer) or school,\r\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\r\nFor more information on this, and how to apply and follow the GNU GPL, see\r\n<http://www.gnu.org/licenses/>.\r\n\r\n  The GNU General Public License does not permit incorporating your program\r\ninto proprietary programs.  If your program is a subroutine library, you\r\nmay consider it more useful to permit linking proprietary applications with\r\nthe library.  If this is what you want to do, use the GNU Lesser General\r\nPublic License instead of this License.  But first, please read\r\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\r\n\r\n"
  },
  {
    "path": "README.md",
    "content": "<img src=\"shadowsocks-csharp/Resources/ssw128.png\" width=\"48\"/>ShadowsocksR for Windows\n=======================\n\n[![](https://img.shields.io/badge/Channel-blue?label=Telegram&logo=telegram)](https://t.me/ShadowsocksR_Windows)\n[![](https://img.shields.io/badge/Group-green?label=Telegram&logo=telegram)](https://t.me/joinchat/Gn-Aa0-j4HcpdBaW-Iv8Sw)\n\n## Build\n\n[![](https://github.com/HMBSbige/ShadowsocksR-Windows/workflows/CI/badge.svg)](https://github.com/HMBSbige/ShadowsocksR-Windows/actions)\n\n## [Wiki](https://github.com/HMBSbige/ShadowsocksR-Windows/wiki)\n\n## Download\n\n* [latest release]\n\n## Develop\n\nVisual Studio Community 2022 is recommended.\n\n## License\n\nGPLv3\n\nCopyright © 2019 - 2022 HMBSbige. Forked from ShadowsocksR by BreakWa11\n\n[latest release]: https://github.com/HMBSbige/ShadowsocksR-Windows/releases\n"
  },
  {
    "path": "UnitTest/DnsTest.cs",
    "content": "using Microsoft.VisualStudio.TestTools.UnitTesting;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Util.NetUtils;\nusing System;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading.Tasks;\n\nnamespace UnitTest;\n\n[TestClass]\npublic class DnsTest\n{\n    [TestMethod]\n    public async Task DefaultTest()\n    {\n        var ip1 = await DnsUtil.QueryDefaultAsync(@\"dns.google\");\n        Assert.IsTrue(Equals(ip1, IPAddress.Parse(@\"8.8.8.8\")) || Equals(ip1, IPAddress.Parse(@\"8.8.4.4\")));\n        var ip2 = await DnsUtil.QueryDefaultAsync(@\"dns.google\", true);\n        Assert.IsTrue(Equals(ip2, IPAddress.Parse(@\"2001:4860:4860::8888\")) || Equals(ip2, IPAddress.Parse(@\"2001:4860:4860::8844\")));\n    }\n\n    [TestMethod]\n    public async Task Test()\n    {\n        var client = new Shadowsocks.Model.DnsClient(DnsType.Default)\n        {\n            DnsServer = @\"101.6.6.6\",\n            Port = 5353,\n            IsTcpEnabled = true,\n            IsUdpEnabled = false\n        };\n        var ip = await client.QueryIpAddressAsync(@\"www.google.com\", default);\n        Assert.IsNotNull(ip);\n        Console.WriteLine(ip);\n    }\n\n    [TestMethod]\n    public async Task DnsOverTlsTest()\n    {\n        var client = new Shadowsocks.Model.DnsClient(DnsType.DnsOverTls);\n        var ip = await client.QueryIpAddressAsync(@\"www.google.com\", default);\n        Assert.IsNotNull(ip);\n        Console.WriteLine(ip);\n    }\n\n    [TestMethod]\n    public async Task TestTwoDnsAsync()\n    {\n        const string host = @\"www.google.com\";\n        var clients = new List<Shadowsocks.Model.DnsClient>\n        {\n            new(DnsType.Default)\n            {\n                DnsServer = @\"101.6.6.6\",\n                Port = 5353,\n                IsTcpEnabled = true,\n                IsUdpEnabled = false\n            },\n            new(DnsType.DnsOverTls)\n        };\n        var res = await DnsUtil.QueryAsync(host, clients);\n        Assert.IsNotNull(res);\n        Console.WriteLine(res);\n    }\n\n    [TestMethod]\n    public async Task TestIpv6FallbackAsync()\n    {\n        const string host = @\"speed.neu6.edu.cn\";\n\n        var resDefault = await DnsUtil.QueryDefaultAsync(host);\n        Assert.IsNotNull(resDefault);\n        Console.WriteLine(resDefault);\n\n        var clients = new List<Shadowsocks.Model.DnsClient>\n        {\n            new(DnsType.DnsOverTls)\n            {\n                DnsServer = @\"dns.alidns.com\"\n            },\n            new(DnsType.Default)\n            {\n                DnsServer = @\"114.114.114.114\",\n                Port = 53,\n                IsTcpEnabled = true,\n                IsUdpEnabled = false\n            }\n        };\n        var res = await DnsUtil.QueryAsync(host, clients);\n        Assert.IsNotNull(res);\n        Console.WriteLine(res);\n    }\n\n    [TestMethod]\n    public async Task TestIpv6FirstAsync()\n    {\n        const string host = @\"speed.neu.edu.cn\";\n        var clients = new List<Shadowsocks.Model.DnsClient>\n        {\n            new(DnsType.Default)\n            {\n                DnsServer = @\"114.114.114.114\",\n                Port = 53,\n                IsTcpEnabled = true,\n                IsUdpEnabled = false,\n                Ipv6First = true\n            }\n        };\n        var res = await DnsUtil.QueryAsync(host, clients);\n\n        Assert.IsNotNull(res);\n        Assert.AreEqual(AddressFamily.InterNetworkV6, res.AddressFamily);\n        Console.WriteLine(res);\n    }\n}\n"
  },
  {
    "path": "UnitTest/EncryptionTest.cs",
    "content": "using Microsoft.VisualStudio.TestTools.UnitTesting;\nusing Shadowsocks.Encryption;\nusing Shadowsocks.Encryption.Stream;\nusing Shadowsocks.Util;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace UnitTest\n{\n    [TestClass]\n    public class EncryptionTest\n    {\n        private void RunEncryptionRound(IEncryptor encryptor, IEncryptor decryptor)\n        {\n            var plain = new byte[16384];\n            var cipher = new byte[plain.Length + 16];\n            var plain2 = new byte[plain.Length + 16];\n            Rng.RandBytes(plain);\n            encryptor.Encrypt(plain, plain.Length, cipher, out var outLen);\n            decryptor.Decrypt(cipher, outLen, plain2, out var outLen2);\n            Assert.AreEqual(plain.Length, outLen2);\n            for (var j = 0; j < plain.Length; j++)\n            {\n                Assert.AreEqual(plain[j], plain2[j]);\n            }\n            encryptor.Encrypt(plain, 1000, cipher, out outLen);\n            decryptor.Decrypt(cipher, outLen, plain2, out outLen2);\n            Assert.AreEqual(1000, outLen2);\n            for (var j = 0; j < outLen2; j++)\n            {\n                Assert.AreEqual(plain[j], plain2[j]);\n            }\n            encryptor.Encrypt(plain, 12333, cipher, out outLen);\n            decryptor.Decrypt(cipher, outLen, plain2, out outLen2);\n            Assert.AreEqual(12333, outLen2);\n            for (var j = 0; j < outLen2; j++)\n            {\n                Assert.AreEqual(plain[j], plain2[j]);\n            }\n        }\n\n        [TestMethod]\n        public void TestStreamOpenSSLEncryption()\n        {\n            var failed = false;\n            // run it once before the multi-threading test to initialize global tables\n            RunSingleStreamOpenSSLEncryptionThread();\n\n            var tasks = new List<Task>();\n            foreach (var cipher in StreamOpenSSLEncryptor.SupportedCiphers())\n            {\n                if (cipher.EndsWith(@\"-cbc\"))\n                {\n                    continue;\n                }\n                var t = new Task(() =>\n                {\n                    try\n                    {\n                        RunSingleStreamOpenSSLEncryptionThread(cipher);\n                    }\n                    catch (Exception e)\n                    {\n                        Console.WriteLine($@\"{cipher}:{e.Message}\");\n                        failed = true;\n                        throw;\n                    }\n                });\n                tasks.Add(t);\n                t.Start();\n            }\n\n            Task.WaitAll(tasks.ToArray());\n            Assert.IsFalse(failed);\n        }\n\n        private void RunSingleStreamOpenSSLEncryptionThread(string methodName = @\"aes-256-cfb8\", string password = @\"barfoo!\")\n        {\n            for (var i = 0; i < 100; i++)\n            {\n                IEncryptor encryptor = new StreamOpenSSLEncryptor(methodName, password);\n                IEncryptor decryptor = new StreamOpenSSLEncryptor(methodName, password);\n                RunEncryptionRound(encryptor, decryptor);\n            }\n        }\n\n        [TestMethod]\n        public void TestStreamSodiumEncryption()\n        {\n            var failed = false;\n            // run it once before the multi-threading test to initialize global tables\n            RunSingleStreamSodiumEncryptionThread();\n            var tasks = new List<Task>();\n            foreach (var cipher in StreamSodiumEncryptor.SupportedCiphers())\n            {\n                if (cipher.StartsWith(@\"x\"))\n                {\n                    continue;\n                }\n                var t = new Task(() =>\n                {\n                    try\n                    {\n                        RunSingleStreamSodiumEncryptionThread(cipher);\n                    }\n                    catch (Exception e)\n                    {\n                        Console.WriteLine($@\"{cipher}:{e.Message}\");\n                        failed = true;\n                        throw;\n                    }\n                });\n                tasks.Add(t);\n                t.Start();\n            }\n\n            Task.WaitAll(tasks.ToArray());\n            Assert.IsFalse(failed);\n        }\n\n        private void RunSingleStreamSodiumEncryptionThread(string methodName = @\"salsa20\", string password = @\"barfoo!\")\n        {\n            for (var i = 0; i < 100; i++)\n            {\n                IEncryptor encryptor = new StreamSodiumEncryptor(methodName, password);\n                IEncryptor decryptor = new StreamSodiumEncryptor(methodName, password);\n                RunEncryptionRound(encryptor, decryptor);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "UnitTest/IPSubnet.cs",
    "content": "using Microsoft.VisualStudio.TestTools.UnitTesting;\nusing Shadowsocks.Util.NetUtils;\nusing System.Net;\n\nnamespace UnitTest\n{\n    [TestClass]\n    public class IPSubnetTest\n    {\n        [TestMethod]\n        public void IsLoopBackTest()\n        {\n            Assert.IsTrue(IPSubnet.IsLoopBack(IPAddress.Loopback));\n            Assert.IsTrue(IPSubnet.IsLoopBack(IPAddress.IPv6Loopback));\n            Assert.IsTrue(IPSubnet.IsLoopBack(IPAddress.Parse(@\"127.0.0.255\")));\n            Assert.IsTrue(IPSubnet.IsLoopBack(IPAddress.Parse(@\"127.255.255.255\")));\n            Assert.IsFalse(IPSubnet.IsLoopBack(IPAddress.Parse(@\"192.168.1.1\")));\n            Assert.IsFalse(IPSubnet.IsLoopBack(IPAddress.Parse(@\"2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFFF\")));\n        }\n\n        [TestMethod]\n        public void IsInSubnetTest()\n        {\n            Assert.IsTrue(IPAddress.Parse(@\"192.168.5.1\").IsInSubnet(@\"192.168.5.85/24\"));\n            Assert.IsTrue(IPAddress.Parse(@\"192.168.5.254\").IsInSubnet(@\"192.168.5.85/24\"));\n            Assert.IsTrue(IPAddress.Parse(@\"10.128.240.48\").IsInSubnet(@\"10.128.240.50/30\"));\n            Assert.IsTrue(IPAddress.Parse(@\"10.128.240.49\").IsInSubnet(@\"10.128.240.50/30\"));\n            Assert.IsTrue(IPAddress.Parse(@\"10.128.240.50\").IsInSubnet(@\"10.128.240.50/30\"));\n            Assert.IsTrue(IPAddress.Parse(@\"10.128.240.51\").IsInSubnet(@\"10.128.240.50/30\"));\n\n            Assert.IsFalse(IPAddress.Parse(@\"192.168.4.254\").IsInSubnet(@\"192.168.5.85/24\"));\n            Assert.IsFalse(IPAddress.Parse(@\"191.168.5.254\").IsInSubnet(@\"192.168.5.85/24\"));\n            Assert.IsFalse(IPAddress.Parse(@\"10.128.240.47\").IsInSubnet(@\"10.128.240.50/30\"));\n            Assert.IsFalse(IPAddress.Parse(@\"10.128.240.52\").IsInSubnet(@\"10.128.240.50/30\"));\n            Assert.IsFalse(IPAddress.Parse(@\"10.128.239.50\").IsInSubnet(@\"10.128.240.50/30\"));\n            Assert.IsFalse(IPAddress.Parse(@\"10.127.240.51\").IsInSubnet(@\"10.128.240.50/30\"));\n\n            Assert.IsTrue(IPAddress.Parse(@\"2001:0DB8:ABCD:0012:0000:0000:0000:0000\").IsInSubnet(@\"2001:db8:abcd:0012::0/64\"));\n            Assert.IsTrue(IPAddress.Parse(@\"2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFFF\").IsInSubnet(@\"2001:db8:abcd:0012::0/64\"));\n            Assert.IsTrue(IPAddress.Parse(@\"2001:0DB8:ABCD:0012:0001:0000:0000:0000\").IsInSubnet(@\"2001:db8:abcd:0012::0/64\"));\n            Assert.IsTrue(IPAddress.Parse(@\"2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFF0\").IsInSubnet(@\"2001:db8:abcd:0012::0/64\"));\n            Assert.IsTrue(IPAddress.Parse(@\"2001:0DB8:ABCD:0012:0000:0000:0000:0000\").IsInSubnet(@\"2001:db8:abcd:0012::0/128\"));\n\n            Assert.IsFalse(IPAddress.Parse(@\"2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFFF\").IsInSubnet(@\"2001:db8:abcd:0012::0/64\"));\n            Assert.IsFalse(IPAddress.Parse(@\"2001:0DB8:ABCD:0013:0000:0000:0000:0000\").IsInSubnet(@\"2001:db8:abcd:0012::0/64\"));\n            Assert.IsFalse(IPAddress.Parse(@\"2001:0DB8:ABCD:0013:0001:0000:0000:0000\").IsInSubnet(@\"2001:db8:abcd:0012::0/64\"));\n            Assert.IsFalse(IPAddress.Parse(@\"2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFF0\").IsInSubnet(@\"2001:db8:abcd:0012::0/64\"));\n            Assert.IsFalse(IPAddress.Parse(@\"2001:0DB8:ABCD:0012:0000:0000:0000:0001\").IsInSubnet(@\"2001:db8:abcd:0012::0/128\"));\n        }\n    }\n}\n"
  },
  {
    "path": "UnitTest/ServerTest.cs",
    "content": "using Microsoft.VisualStudio.TestTools.UnitTesting;\nusing Shadowsocks.Model;\nusing System;\n\nnamespace UnitTest\n{\n    [TestClass]\n    public class ServerTest\n    {\n        [TestMethod]\n        public void TestServerFromSSR()\n        {\n            var server = new Server();\n            var nornameCase = \"ssr://MTI3LjAuMC4xOjEyMzQ6YXV0aF9hZXMxMjhfbWQ1OmFlcy0xMjgtY2ZiOnRsczEuMl90aWNrZXRfYXV0aDpZV0ZoWW1KaS8_b2Jmc3BhcmFtPVluSmxZV3QzWVRFeExtMXZaUQ\";\n\n            server.ServerFromSsr(nornameCase, \"\");\n\n            Assert.AreEqual(server.server, \"127.0.0.1\");\n            Assert.AreEqual(server.Server_Port, (ushort)1234);\n            Assert.AreEqual(server.Protocol, \"auth_aes128_md5\");\n            Assert.AreEqual(server.Method, \"aes-128-cfb\");\n            Assert.AreEqual(server.obfs, \"tls1.2_ticket_auth\");\n            Assert.AreEqual(server.ObfsParam, \"breakwa11.moe\");\n            Assert.AreEqual(server.Password, \"aaabbb\");\n\n            server = new Server();\n            const string normalCaseWithRemark = \"ssr://MTI3LjAuMC4xOjEyMzQ6YXV0aF9hZXMxMjhfbWQ1OmFlcy0xMjgtY2ZiOnRsczEuMl90aWNrZXRfYXV0aDpZV0ZoWW1KaS8_b2Jmc3BhcmFtPVluSmxZV3QzWVRFeExtMXZaUSZyZW1hcmtzPTVyV0w2Sy1WNUxpdDVwYUg\";\n\n            server.ServerFromSsr(normalCaseWithRemark, \"firewallAirport\");\n\n            Assert.AreEqual(server.server, \"127.0.0.1\");\n            Assert.AreEqual<ushort>(server.Server_Port, 1234);\n            Assert.AreEqual(server.Protocol, \"auth_aes128_md5\");\n            Assert.AreEqual(server.Method, \"aes-128-cfb\");\n            Assert.AreEqual(server.obfs, \"tls1.2_ticket_auth\");\n            Assert.AreEqual(server.ObfsParam, \"breakwa11.moe\");\n            Assert.AreEqual(server.Password, \"aaabbb\");\n\n            Assert.AreEqual(server.Remarks, \"测试中文\");\n            Assert.AreEqual(server.Group, string.Empty);\n            Assert.AreEqual(server.SubTag, \"firewallAirport\");\n        }\n\n        [TestMethod]\n        public void TestBadPortNumber()\n        {\n            var server = new Server();\n\n            const string link = \"ssr://MTI3LjAuMC4xOjgwOmF1dGhfc2hhMV92NDpjaGFjaGEyMDpodHRwX3NpbXBsZTplaWZnYmVpd3ViZ3IvP29iZnNwYXJhbT0mcHJvdG9wYXJhbT0mcmVtYXJrcz0mZ3JvdXA9JnVkcHBvcnQ9NDY0MzgxMzYmdW90PTQ2MDA3MTI4\";\n            try\n            {\n                server.ServerFromSsr(link, \"\");\n            }\n            catch (OverflowException e)\n            {\n                Console.Write(e.ToString());\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "UnitTest/SubscribeTest.cs",
    "content": "using Microsoft.VisualStudio.TestTools.UnitTesting;\nusing Shadowsocks.Controller.HttpRequest;\nusing Shadowsocks.Util;\nusing System;\nusing System.Text.RegularExpressions;\n\nnamespace UnitTest\n{\n    [TestClass]\n    public class SubscribeTest\n    {\n        [TestMethod]\n        public void ParseTest()\n        {\n            var url = @\"sub://aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0hNQlNiaWdlL1RleHRfVHJhbnNsYXRpb24vbWFzdGVyL1NoYWRvd3NvY2tzUi9mcmVlbm9kZXBsYWluLnR4dA\";\n            var sub = Regex.Match(url, \"sub://([A-Za-z0-9_-]+)\", RegexOptions.IgnoreCase);\n            if (!sub.Success)\n            {\n                throw new FormatException();\n            }\n\n            var res = Base64.DecodeUrlSafeBase64(sub.Groups[1].Value);\n            Assert.AreEqual(res, UpdateNode.DefaultUpdateUrl);\n        }\n    }\n}\n"
  },
  {
    "path": "UnitTest/UnitTest.cs",
    "content": "using Microsoft.VisualStudio.TestTools.UnitTesting;\nusing Shadowsocks.Encryption;\nusing Shadowsocks.Util;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text;\n\nnamespace UnitTest\n{\n    [TestClass]\n    public class UnitTest\n    {\n        [TestMethod]\n        public void TestMd5()\n        {\n            var buff = Encoding.UTF8.GetBytes(@\"密码\");\n            var md5Sum = CryptoUtils.MD5(buff);\n            var md5Hash = MD5.Create().ComputeHash(buff);\n            Assert.IsTrue(md5Hash.SequenceEqual(md5Sum));\n        }\n\n        [TestMethod]\n        public void EncryptStringTest()\n        {\n            var largeBytes = new byte[ushort.MaxValue * 100];\n            Rng.RandBytes(largeBytes);\n            var largeStr = Encoding.UTF8.GetString(largeBytes);\n            using var encryptor = EncryptorFactory.GetEncryptor(@\"aes-256-cfb\", @\"密码\");\n\n            var encodeStr = Utils.EncryptLargeBytesToBase64String(encryptor, largeBytes);\n\n            var decodeStr = Encoding.UTF8.GetString(Utils.DecryptLargeBase64StringToBytes(encryptor, encodeStr));\n\n            Assert.AreEqual(largeStr, decodeStr);\n        }\n\n    }\n}\n"
  },
  {
    "path": "UnitTest/UnitTest.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net7.0-windows</TargetFramework>\n    <LangVersion>latest</LangVersion>\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.1\" />\n    <PackageReference Include=\"MSTest.TestAdapter\" Version=\"3.9.3\" />\n    <PackageReference Include=\"MSTest.TestFramework\" Version=\"3.9.3\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\shadowsocks-csharp\\shadowsocksr.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "build.ps1",
    "content": "param([string]$buildtfm = 'all')\n$ErrorActionPreference = 'Stop'\n\nWrite-Host 'dotnet SDK info'\ndotnet --info\n\n$exe = 'ShadowsocksR.exe'\n$net_tfm = 'net7.0-windows'\n$configuration = 'Release'\n$output_dir = \"$PSScriptRoot\\shadowsocks-csharp\\bin\\$configuration\"\n$proj_path = \"$PSScriptRoot\\shadowsocks-csharp\\shadowsocksr.csproj\"\n\n$build    = $buildtfm -eq 'all' -or $buildtfm -eq 'app'\n$buildX86 = $buildtfm -eq 'all' -or $buildtfm -eq 'x86'\n$buildX64 = $buildtfm -eq 'all' -or $buildtfm -eq 'x64'\nfunction Build-App\n{\n\tWrite-Host 'Building .NET App'\n\t\n\t$outdir = \"$output_dir\\$net_tfm\"\n\t$publishDir = \"$outdir\\publish\"\n\n\tRemove-Item $publishDir -Recurse -Force -Confirm:$false -ErrorAction Ignore\n\t\n\tdotnet publish -c $configuration -f $net_tfm $proj_path\n\tif ($LASTEXITCODE) { exit $LASTEXITCODE }\n\n\t& \"$PSScriptRoot\\Build\\DotNetDllPathPatcher.ps1\" $publishDir\\$exe bin\n\tif ($LASTEXITCODE) { exit $LASTEXITCODE }\n}\n\nfunction Build-SelfContained\n{\n\tparam([string]$rid)\n\n\tWrite-Host \"Building .NET App SelfContained $rid\"\n\n\t$outdir = \"$output_dir\\$net_tfm\\$rid\"\n\t$publishDir = \"$outdir\\publish\"\n\n\tRemove-Item $publishDir -Recurse -Force -Confirm:$false -ErrorAction Ignore\n\n\tdotnet publish -c $configuration -f $net_tfm -r $rid --self-contained true $proj_path\n\tif ($LASTEXITCODE) { exit $LASTEXITCODE }\n\n\t& \"$PSScriptRoot\\Build\\DotNetDllPathPatcher.ps1\" $publishDir\\$exe bin\n\tif ($LASTEXITCODE) { exit $LASTEXITCODE }\n}\n\nif ($build)\n{\n\tBuild-App\n}\n\nif ($buildX64)\n{\n\tBuild-SelfContained win-x64\n}\n\nif ($buildX86)\n{\n\tBuild-SelfContained win-x86\n}"
  },
  {
    "path": "shadowsocks-csharp/Controller/AutoStartup.cs",
    "content": "using CryptoBase;\r\nusing RunAtStartup;\r\nusing System;\r\nusing System.IO;\r\nusing Utils = Shadowsocks.Util.Utils;\r\n\r\nnamespace Shadowsocks.Controller\r\n{\r\n    internal static class AutoStartup\r\n    {\r\n        private static readonly string Key = $@\"ShadowsocksR_{Directory.GetCurrentDirectory().GetClassicHashCode()}\";\r\n\r\n        public static bool Set(bool enabled)\r\n        {\r\n            try\r\n            {\r\n                var path = $@\"\"\"{Utils.GetExecutablePath()}\"\"\";\r\n                var service = new StartupService(Key);\r\n                if (enabled)\r\n                {\r\n                    service.Set(path);\r\n                }\r\n                else\r\n                {\r\n                    service.Delete();\r\n                }\r\n                return true;\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                Logging.LogUsefulException(e);\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static bool Check()\r\n        {\r\n            try\r\n            {\r\n                var path = $@\"\"\"{Utils.GetExecutablePath()}\"\"\";\r\n                var service = new StartupService(Key);\r\n                return service.Check(path);\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                Logging.LogUsefulException(e);\r\n                return false;\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/FileManager.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Shadowsocks.Controller\n{\n    public static class FileManager\n    {\n        public static bool ByteArrayToFile(string fileName, byte[] content)\n        {\n            try\n            {\n                var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write);\n                fileStream.Write(content, 0, content.Length);\n                fileStream.Close();\n                return true;\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($@\"Exception caught in process: {ex}\");\n            }\n            return false;\n        }\n\n        public static void DecompressFile(string fileName, byte[] content)\n        {\n            var destinationFile = File.Create(fileName);\n\n            // Because the uncompressed size of the file is unknown, \n            // we are using an arbitrary buffer size.\n            var buffer = new byte[4096];\n\n            using (var input = new GZipStream(new MemoryStream(content), CompressionMode.Decompress, false))\n            {\n                while (true)\n                {\n                    var n = input.Read(buffer, 0, buffer.Length);\n                    if (n == 0)\n                    {\n                        break;\n                    }\n                    destinationFile.Write(buffer, 0, n);\n                }\n            }\n            destinationFile.Close();\n        }\n\n        public static byte[] DeflateCompress(byte[] content, int index, int count, out int size)\n        {\n            size = 0;\n            try\n            {\n                var memStream = new MemoryStream();\n                using (var ds = new DeflateStream(memStream, CompressionMode.Compress))\n                {\n                    ds.Write(content, index, count);\n                }\n                var buffer = memStream.ToArray();\n                size = buffer.Length;\n                return buffer;\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($@\"Exception caught in process: {ex}\");\n            }\n            return null;\n        }\n\n        public static byte[] DeflateDecompress(byte[] content, int index, int count, out int size)\n        {\n            size = 0;\n            try\n            {\n                var buffer = new byte[16384];\n                var ds = new DeflateStream(new MemoryStream(content, index, count), CompressionMode.Decompress);\n                while (true)\n                {\n                    var readSize = ds.Read(buffer, size, buffer.Length - size);\n                    if (readSize == 0)\n                    {\n                        break;\n                    }\n                    size += readSize;\n                    var newBuffer = new byte[buffer.Length * 2];\n                    buffer.CopyTo(newBuffer, 0);\n                    buffer = newBuffer;\n                }\n                return buffer;\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($@\"Exception caught in process: {ex}\");\n            }\n            return null;\n        }\n\n        [SuppressMessage(\"ReSharper\", \"AssignNullToNotNullAttribute\")]\n        public static async Task<bool> ZipCompressToFile(string path)\n        {\n            try\n            {\n                var filename = Path.GetFileName(path);\n                var zipFilePath = $@\"{Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path))}.zip\";\n                using (var zipFileToOpen = new FileStream(zipFilePath, FileMode.Create))\n                {\n                    using var archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Create);\n                    var readMeEntry = archive.CreateEntry(filename);\n                    using var zipStream = readMeEntry.Open();\n                    using var stream = File.Open(path, FileMode.Open);\n                    var bytes = new byte[(int)stream.Length];\n                    var totalBytesRead = 0;\n                    while (totalBytesRead < bytes.Length)\n                    {\n                        totalBytesRead += await stream.ReadAsync(bytes, totalBytesRead, bytes.Length - totalBytesRead);\n                    }\n\n                    await zipStream.WriteAsync(bytes, 0, bytes.Length);\n                }\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        public static string NonExclusiveReadAllText(string path)\n        {\n            return NonExclusiveReadAllText(path, Encoding.UTF8);\n        }\n\n        public static string NonExclusiveReadAllText(string path, Encoding encoding)\n        {\n            try\n            {\n                using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);\n                using var sr = new StreamReader(fs, encoding);\n                return sr.ReadToEnd();\n            }\n            catch (Exception ex)\n            {\n                Logging.Error(ex);\n                throw;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/HttpRequest/GfwListUpdater.cs",
    "content": "using Shadowsocks.Controller.Service;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Properties;\nusing Shadowsocks.Util;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\n\nnamespace Shadowsocks.Controller.HttpRequest\n{\n    public class GfwListUpdater : HttpRequest\n    {\n        private const string GfwlistUrl = @\"https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt\";\n\n        #region event\n\n        public event EventHandler<ResultEventArgs> UpdateCompleted;\n\n        public event ErrorEventHandler Error;\n\n        public class ResultEventArgs : EventArgs\n        {\n            public readonly bool Success;\n            public readonly PacType PacType;\n\n            public ResultEventArgs(bool success, PacType pacType)\n            {\n                Success = success;\n                PacType = pacType;\n            }\n        }\n\n        #endregion\n\n        #region GfwList\n\n        public async void UpdatePacFromGfwList(Configuration config)\n        {\n            Logging.Info($@\"Checking GFWList from {GfwlistUrl}\");\n            try\n            {\n                var userAgent = config.ProxyUserAgent;\n                var proxy = CreateProxy(config);\n\n                var content = await AutoGetAsync(GfwlistUrl, proxy, userAgent, config.ConnectTimeout * 1000, TimeSpan.FromMinutes(1).TotalMilliseconds);\n                File.WriteAllText(Utils.GetTempPath(PACServer.gfwlist_FILE), content, Encoding.UTF8);\n                var pacFileChanged = MergeAndWritePacFile(content);\n                UpdateCompleted?.Invoke(this, new ResultEventArgs(pacFileChanged, PacType.GfwList));\n            }\n            catch (Exception ex)\n            {\n                Error?.Invoke(this, new ErrorEventArgs(ex));\n            }\n        }\n\n        public static bool MergeAndWritePacFile(string gfwListResult)\n        {\n            var abpContent = MergePacFile(gfwListResult);\n            if (File.Exists(PACDaemon.PAC_FILE))\n            {\n                var original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE, Encoding.UTF8);\n                if (original == abpContent)\n                {\n                    return false;\n                }\n            }\n\n            File.WriteAllText(PACDaemon.PAC_FILE, abpContent, Encoding.UTF8);\n            return true;\n        }\n\n        private static string MergePacFile(string gfwListResult)\n        {\n            var abpContent = File.Exists(PACDaemon.USER_ABP_FILE) ? FileManager.NonExclusiveReadAllText(PACDaemon.USER_ABP_FILE) : Resources.abp;\n\n            var userRuleLines = new List<string>();\n            if (File.Exists(PACDaemon.USER_RULE_FILE))\n            {\n                var userRulesString = FileManager.NonExclusiveReadAllText(PACDaemon.USER_RULE_FILE);\n                userRuleLines = ParseToValidList(userRulesString);\n            }\n\n            var gfwLines = ParseBase64ToValidList(gfwListResult);\n\n            abpContent = abpContent.Replace(@\"__USERRULES__\", JsonUtils.Serialize(userRuleLines, false))\n                    .Replace(@\"__RULES__\", JsonUtils.Serialize(gfwLines, false));\n            return abpContent;\n        }\n\n        private static List<string> ParseBase64ToValidList(string response)\n        {\n            var bytes = Convert.FromBase64String(response);\n            var content = Encoding.ASCII.GetString(bytes);\n            return ParseToValidList(content);\n        }\n\n        private static List<string> ParseToValidList(string content)\n        {\n            var lines = content.GetLines().ToArray();\n            var validLines = new List<string>(lines.Length);\n            validLines.AddRange(lines.Where(line => !line.StartsWith(@\"!\") && !line.StartsWith(@\"[\")));\n            return validLines;\n        }\n\n        #endregion\n\n        #region OnlinePAC\n\n        public async void UpdateOnlinePac(Configuration config, string url)\n        {\n            try\n            {\n                var userAgent = config.ProxyUserAgent;\n                var proxy = CreateProxy(config);\n\n                var content = await AutoGetAsync(url, proxy, userAgent, config.ConnectTimeout * 1000, TimeSpan.FromMinutes(1).TotalMilliseconds);\n                if (File.Exists(PACDaemon.PAC_FILE))\n                {\n                    var original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE);\n                    if (original == content)\n                    {\n                        UpdateCompleted?.Invoke(this, new ResultEventArgs(false, PacType.Online));\n                        return;\n                    }\n                }\n\n                File.WriteAllText(PACDaemon.PAC_FILE, content);\n                UpdateCompleted?.Invoke(this, new ResultEventArgs(true, PacType.Online));\n            }\n            catch (Exception ex)\n            {\n                Error?.Invoke(this, new ErrorEventArgs(ex));\n            }\n        }\n\n        #endregion\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/HttpRequest/HttpRequest.cs",
    "content": "using Shadowsocks.Model;\nusing System;\nusing System.Net;\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nnamespace Shadowsocks.Controller.HttpRequest\n{\n    public abstract class HttpRequest\n    {\n        private const string DefaultUserAgent = @\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36\";\n        private const int DefaultGetTimeout = 30000;\n        private const int DefaultHeadTimeout = 4000;\n\n        public static HttpClient CreateClient(bool useProxy, IWebProxy proxy, string userAgent, double timeout)\n        {\n            var httpClientHandler = new SocketsHttpHandler\n            {\n                Proxy = proxy,\n                UseProxy = useProxy\n            };\n\n            var client = new HttpClient(httpClientHandler)\n            {\n                Timeout = TimeSpan.FromMilliseconds(timeout),\n                DefaultRequestVersion = HttpVersion.Version20\n            };\n\n            client.DefaultRequestHeaders.Add(@\"User-Agent\", string.IsNullOrWhiteSpace(userAgent) ? DefaultUserAgent : userAgent);\n            return client;\n        }\n\n        private static async Task<string> GetAsync(string url, IWebProxy proxy, string userAgent = DefaultUserAgent, double timeout = DefaultGetTimeout, bool useProxy = true)\n        {\n            using var client = CreateClient(useProxy, proxy, userAgent, timeout);\n            using var response = await client.GetAsync(url);\n            response.EnsureSuccessStatusCode();\n            return await response.Content.ReadAsStringAsync();\n        }\n\n        private static async Task<bool> HeadAsync(string url, IWebProxy proxy, double timeout = DefaultHeadTimeout)\n        {\n            using var client = CreateClient(proxy != null, proxy, DefaultUserAgent, timeout);\n            try\n            {\n                using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        protected static async Task<string> AutoGetAsync(string url, IWebProxy proxy, string userAgent = @\"\", double headTimeout = DefaultHeadTimeout, double getTimeout = DefaultGetTimeout)\n        {\n            string res = null;\n            if (await HeadAsync(url, proxy, headTimeout))\n            {\n                try\n                {\n                    res = await ProxyGetAsync(url, proxy, userAgent, getTimeout);\n                }\n                catch\n                {\n                    res = null;\n                }\n            }\n            if (res != null)\n            {\n                return res;\n            }\n\n            res = await DirectGetAsync(url, userAgent, getTimeout);\n            return res;\n        }\n\n        protected static async Task<string> DirectGetAsync(string url, string userAgent = DefaultUserAgent, double getTimeout = DefaultGetTimeout)\n        {\n            Logging.Info($@\"GET request directly: {url}\");\n            return await GetAsync(url, null, userAgent, getTimeout, false);\n        }\n\n        protected static async Task<string> ProxyGetAsync(string url, IWebProxy proxy, string userAgent = DefaultUserAgent, double timeout = DefaultGetTimeout)\n        {\n            Logging.Info($@\"GET request by proxy: {url}\");\n            return await GetAsync(url, proxy, userAgent, timeout);\n        }\n\n        protected static async Task<string> DefaultGetAsync(string url, string userAgent = DefaultUserAgent, double getTimeout = DefaultGetTimeout)\n        {\n            Logging.Info($@\"GET request by default: {url}\");\n            return await GetAsync(url, null, userAgent, getTimeout);\n        }\n\n        protected static IWebProxy CreateProxy(Configuration config)\n        {\n            var proxy = new WebProxy(Global.LocalHost, config.LocalPort);\n            if (!string.IsNullOrEmpty(config.AuthPass))\n            {\n                proxy.Credentials = new NetworkCredential(config.AuthUser, config.AuthPass);\n            }\n\n            return proxy;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/HttpRequest/UpdateChecker.cs",
    "content": "using Shadowsocks.Model;\nusing System;\nusing UpdateChecker;\n\nnamespace Shadowsocks.Controller.HttpRequest\n{\n    public class UpdateChecker : HttpRequest\n    {\n        private const string Owner = @\"HMBSbige\";\n        private const string Repo = @\"ShadowsocksR-Windows\";\n\n        public string LatestVersionNumber;\n        public string LatestVersionUrl;\n\n        public bool Found;\n\n        public event EventHandler NewVersionFound;\n        public event EventHandler NewVersionFoundFailed;\n        public event EventHandler NewVersionNotFound;\n\n        public const string Name = @\"ShadowsocksR\";\n        public const string Copyright = @\"Copyright © 2019 - 2022 HMBSbige. Forked from ShadowsocksR by BreakWa11\";\n        public const string Version = @\"6.1.0\";\n\n        public const string FullVersion = Version +\n#if SelfContained\n#if Is64Bit\n            @\" x64\" +\n#else\n            @\" x86\" +\n#endif\n#endif\n#if DEBUG\n        @\" Debug\";\n#else\n        @\"\";\n#endif\n\n        public async void Check(Configuration config, bool notifyNoFound)\n        {\n            try\n            {\n                var updater = new GitHubReleasesUpdateChecker(\n                    Owner,\n                    Repo,\n                    config.IsPreRelease,\n                    Version);\n\n                var userAgent = config.ProxyUserAgent;\n                var proxy = CreateProxy(config);\n                using var client = CreateClient(true, proxy, userAgent, config.ConnectTimeout * 1000);\n\n                var res = await updater.CheckAsync(client, default);\n                LatestVersionNumber = updater.LatestVersion;\n                Found = res;\n                if (Found)\n                {\n                    LatestVersionUrl = updater.LatestVersionUrl;\n                    NewVersionFound?.Invoke(this, EventArgs.Empty);\n                }\n                else\n                {\n                    if (notifyNoFound)\n                    {\n                        NewVersionNotFound?.Invoke(this, EventArgs.Empty);\n                    }\n                }\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                if (notifyNoFound)\n                {\n                    NewVersionFoundFailed?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/HttpRequest/UpdateNode.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing System;\nusing System.Net;\n\nnamespace Shadowsocks.Controller.HttpRequest\n{\n    public class UpdateNode : HttpRequest\n    {\n        public const string DefaultUpdateUrl = @\"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/freenodeplain.txt\";\n\n        public event EventHandler NewFreeNodeFound;\n        public string FreeNodeResult;\n        public ServerSubscribe SubscribeTask;\n        public bool Notify;\n\n        public void CheckUpdate(Configuration config, ServerSubscribe subscribeTask, bool notify)\n        {\n            FreeNodeResult = null;\n            Notify = notify;\n            try\n            {\n                var proxy = CreateProxy(config);\n                SubscribeTask = subscribeTask;\n                var url = subscribeTask.Url ?? DefaultUpdateUrl;\n                Update(subscribeTask.ProxyType, proxy, config.ConnectTimeout * 1000, url, config.ProxyUserAgent);\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n            }\n        }\n\n        private async void Update(HttpRequestProxyType proxyType, IWebProxy proxy, int timeout, string url, string userAgent)\n        {\n            try\n            {\n                FreeNodeResult = proxyType switch\n                {\n                    HttpRequestProxyType.Auto => await AutoGetAsync(url, proxy, userAgent, timeout),\n                    HttpRequestProxyType.Direct => await DirectGetAsync(url, userAgent, timeout),\n                    HttpRequestProxyType.Proxy => await ProxyGetAsync(url, proxy, userAgent, timeout),\n                    HttpRequestProxyType.SystemSetting => await DefaultGetAsync(url, userAgent, timeout),\n                    _ => await AutoGetAsync(url, proxy, userAgent, timeout)\n                };\n            }\n            catch (Exception ex)\n            {\n                Logging.Debug(ex.ToString());\n            }\n\n            NewFreeNodeFound?.Invoke(this, EventArgs.Empty);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Logging.cs",
    "content": "using Shadowsocks.Enums;\r\nusing Shadowsocks.Obfs;\r\nusing Shadowsocks.Util;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Net.Sockets;\r\nusing System.Text;\r\n\r\nnamespace Shadowsocks.Controller\r\n{\r\n    public static class Logging\r\n    {\r\n        public static string LogFile;\r\n        public static string LogFileName;\r\n        private static string _date;\r\n\r\n        private static FileStream _logFileStream;\r\n        private static StreamWriterWithTimestamp _logStreamWriter;\r\n        private static readonly object Lock = new();\r\n        public static bool SaveToFile = true;\r\n        public static TextWriter DefaultOut;\r\n        public static TextWriter DefaultError;\r\n\r\n        public static bool OpenLogFile()\r\n        {\r\n            try\r\n            {\r\n                CloseLogFile();\r\n\r\n                if (SaveToFile)\r\n                {\r\n                    var newDate = DateTime.Now.ToString(\"yyyy-MM\");\r\n                    LogFileName = $@\"shadowsocks_{newDate}.log\";\r\n                    LogFile = Utils.GetTempPath(LogFileName);\r\n                    _logFileStream = new FileStream(LogFile, FileMode.Append);\r\n                    _logStreamWriter = new StreamWriterWithTimestamp(_logFileStream)\r\n                    {\r\n                        AutoFlush = true\r\n                    };\r\n                    Console.SetOut(_logStreamWriter);\r\n                    Console.SetError(_logStreamWriter);\r\n                    _date = newDate;\r\n                    CompressOldLogFile();\r\n                }\r\n                else\r\n                {\r\n                    Console.SetOut(DefaultOut);\r\n                    Console.SetError(DefaultError);\r\n                }\r\n\r\n                return true;\r\n            }\r\n            catch (IOException e)\r\n            {\r\n                Console.WriteLine(e.ToString());\r\n                return false;\r\n            }\r\n        }\r\n\r\n        private static void CloseLogFile()\r\n        {\r\n            _logStreamWriter?.Close();\r\n            _logStreamWriter?.Dispose();\r\n            _logFileStream?.Close();\r\n            _logFileStream?.Dispose();\r\n\r\n            _logStreamWriter = null;\r\n            _logFileStream = null;\r\n        }\r\n\r\n        public static void Clear()\r\n        {\r\n            CloseLogFile();\r\n            if (LogFile != null)\r\n            {\r\n                File.Delete(LogFile);\r\n            }\r\n            OpenLogFile();\r\n        }\r\n\r\n        public static void Error(object o)\r\n        {\r\n            Log(LogLevel.Error, o);\r\n            System.Diagnostics.Debug.WriteLine($@\"[{DateTime.Now}] ERROR {o}\");\r\n        }\r\n\r\n        public static void Info(object o)\r\n        {\r\n            Log(LogLevel.Info, o);\r\n            System.Diagnostics.Debug.WriteLine($@\"[{DateTime.Now}] INFO {o}\");\r\n        }\r\n\r\n        [Conditional(\"DEBUG\")]\r\n        public static void Debug(object o)\r\n        {\r\n            Log(LogLevel.Debug, o);\r\n            System.Diagnostics.Debug.WriteLine($@\"[{DateTime.Now}] DEBUG {o}\");\r\n        }\r\n\r\n        private static string ToString(IEnumerable<StackFrame> stacks)\r\n        {\r\n            return stacks.Aggregate(string.Empty, (current, stack) => current + $@\"{stack.GetMethod()}{Environment.NewLine}\");\r\n        }\r\n\r\n        private static void CompressOldLogFile()\r\n        {\r\n            var list = Directory.GetFiles(Utils.TempPath, @\"shadowsocks_*.log\", SearchOption.TopDirectoryOnly);\r\n            foreach (var file in list)\r\n            {\r\n                if (file != LogFile)\r\n                {\r\n                    FileManager.ZipCompressToFile(file).ContinueWith(task =>\r\n                    {\r\n                        if (task.Result)\r\n                        {\r\n                            File.Delete(file);\r\n                        }\r\n                    });\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void UpdateLogFile()\r\n        {\r\n            if (DateTime.Now.ToString(\"yyyy-MM\") != _date)\r\n            {\r\n                lock (Lock)\r\n                {\r\n                    if (DateTime.Now.ToString(\"yyyy-MM\") != _date)\r\n                    {\r\n                        OpenLogFile();\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void LogUsefulException(Exception e)\r\n        {\r\n            UpdateLogFile();\r\n            // just log useful exceptions, not all of them\r\n            if (e is SocketException se)\r\n            {\r\n                switch (se.SocketErrorCode)\r\n                {\r\n                    case SocketError.ConnectionAborted:\r\n                        // closed by browser when sending\r\n                        // normally happens when download is canceled or a tab is closed before page is loaded\r\n                        break;\r\n                    case SocketError.ConnectionReset:\r\n                        // received rst\r\n                        break;\r\n                    case SocketError.NotConnected:\r\n                        // close when not connected\r\n                        break;\r\n                    case SocketError.Shutdown:\r\n                        // ignore\r\n                        break;\r\n                    case SocketError.Interrupted:\r\n                        // ignore\r\n                        break;\r\n                    default:\r\n                    {\r\n                        if ((uint)se.SocketErrorCode == 0x80004005)\r\n                        {\r\n                            // already closed\r\n                        }\r\n                        else\r\n                        {\r\n                            Error(e);\r\n\r\n                            Debug(ToString(new StackTrace().GetFrames()));\r\n                        }\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            else\r\n            {\r\n                Error(e);\r\n\r\n                Debug(ToString(new StackTrace().GetFrames()));\r\n            }\r\n        }\r\n\r\n        public static bool LogSocketException(string remarks, string server, Exception e)\r\n        {\r\n            UpdateLogFile();\r\n            switch (e)\r\n            {\r\n                // just log useful exceptions, not all of them\r\n                case ObfsException oe:\r\n                    Error($@\"Proxy server [{remarks}({server})] {oe.Message}\");\r\n                    return true;\r\n                case NullReferenceException _:\r\n                case ObjectDisposedException _:\r\n                    return true;\r\n                case SocketException se when se.ErrorCode == 11004:\r\n                    Log(LogLevel.Warn, $@\"Proxy server [{remarks}({server})] DNS lookup failed\");\r\n                    return true;\r\n                case SocketException se when (uint)se.SocketErrorCode == 0x80004005:\r\n                    // already closed\r\n                    return true;\r\n                case SocketException se:\r\n                    switch (se.SocketErrorCode)\r\n                    {\r\n                        case SocketError.HostNotFound:\r\n                            Log(LogLevel.Warn, $@\"Proxy server [{remarks}({server})] Host not found\");\r\n                            return true;\r\n                        case SocketError.ConnectionRefused:\r\n                            Log(LogLevel.Warn, $@\"Proxy server [{remarks}({server})] connection refused\");\r\n                            return true;\r\n                        case SocketError.NetworkUnreachable:\r\n                            Log(LogLevel.Warn, $@\"Proxy server [{remarks}({server})] network unreachable\");\r\n                            return true;\r\n                        case SocketError.TimedOut:\r\n                        case SocketError.Shutdown:\r\n                            return true;\r\n                    }\r\n\r\n                    Log(LogLevel.Info, $@\"Proxy server [{remarks}({server})] {Convert.ToString(se.SocketErrorCode)}:{se.Message}\");\r\n\r\n                    Debug(ToString(new StackTrace().GetFrames()));\r\n                    return true;\r\n                default:\r\n                    return false;\r\n            }\r\n        }\r\n\r\n        public static void Log(LogLevel level, object s)\r\n        {\r\n            UpdateLogFile();\r\n            Console.WriteLine($@\"[{level}] {s}\");\r\n        }\r\n\r\n        [Conditional(\"DEBUG\")]\r\n        public static void LogBin(LogLevel level, string info, byte[] data, int length)\r\n        {\r\n            var s = new StringBuilder();\r\n            for (var i = 0; i < length; ++i)\r\n            {\r\n                var fs = $@\"0{Convert.ToString(data[i], 16)}\";\r\n                s.Append($@\" {fs.Substring(fs.Length - 2, 2)}\");\r\n            }\r\n            Log(level, $@\"{info}{s}\");\r\n        }\r\n\r\n    }\r\n\r\n    // Simply extended System.IO.StreamWriter for adding timestamp workaround\r\n    public class StreamWriterWithTimestamp : StreamWriter\r\n    {\r\n        public StreamWriterWithTimestamp(Stream stream) : base(stream)\r\n        {\r\n        }\r\n\r\n        private static string GetTimestamp()\r\n        {\r\n            return $@\"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] \";\r\n        }\r\n\r\n        public override void WriteLine(string value)\r\n        {\r\n            try\r\n            {\r\n                base.WriteLine(GetTimestamp() + value);\r\n            }\r\n            catch (ObjectDisposedException)\r\n            {\r\n\r\n            }\r\n        }\r\n\r\n        public override void Write(string value)\r\n        {\r\n            try\r\n            {\r\n                base.Write(GetTimestamp() + value);\r\n            }\r\n            catch (ObjectDisposedException)\r\n            {\r\n\r\n            }\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/MainController.cs",
    "content": "using Shadowsocks.Controller.HttpRequest;\nusing Shadowsocks.Controller.Service;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Model.Transfer;\nusing Shadowsocks.Util;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net.Sockets;\nusing System.Text.RegularExpressions;\nusing System.Windows;\n\nnamespace Shadowsocks.Controller\n{\n    public class MainController\n    {\n        // controller:\n        // handle user actions\n        // manipulates UI\n        // interacts with low level logic\n\n        private Listener _listener;\n        private List<Listener> _portMapListener;\n        private PACDaemon _pacDaemon;\n        private PACServer _pacServer;\n\n        private readonly ServerTransferTotal _transfer;\n        private HostDaemon _hostDaemon;\n        private IPRangeSet _chnRangeSet;\n        private HttpProxyRunner _httpProxyRunner;\n        private GfwListUpdater _gfwListUpdater;\n        private bool _stopped;\n\n        public class PathEventArgs : EventArgs\n        {\n            public string Path;\n        }\n\n        #region Event\n\n        public event EventHandler ConfigChanged;\n        public event EventHandler ShowConfigFormEvent;\n        public event EventHandler ShowSubscribeWindowEvent;\n\n        // when user clicked Edit PAC, and PAC file has already created\n        public event EventHandler<PathEventArgs> PACFileReadyToOpen;\n        public event EventHandler<PathEventArgs> UserRuleFileReadyToOpen;\n\n        public event EventHandler<GfwListUpdater.ResultEventArgs> UpdatePACFromGFWListCompleted;\n\n        public event ErrorEventHandler UpdatePACFromGFWListError;\n\n        public event ErrorEventHandler Errored;\n\n        #endregion\n\n        public MainController()\n        {\n            _transfer = ServerTransferTotal.Load();\n\n            foreach (var server in Global.GuiConfig.Configs)\n            {\n                if (_transfer.Servers.TryGetValue(server.Id, out var st))\n                {\n                    var log = new ServerSpeedLog(st.TotalUploadBytes, st.TotalDownloadBytes);\n                    server.SpeedLog = log;\n                }\n            }\n        }\n\n        private void ReportError(Exception e)\n        {\n            Errored?.Invoke(this, new ErrorEventArgs(e));\n        }\n\n        private static int FindFirstMatchServer(Server server, IReadOnlyList<Server> servers)\n        {\n            for (var i = 0; i < servers.Count; ++i)\n            {\n                if (server.IsMatchServer(servers[i]))\n                {\n                    return i;\n                }\n            }\n            return -1;\n        }\n\n        private static void AppendConfiguration(Configuration mergeConfig, IReadOnlyList<Server> servers)\n        {\n            if (servers != null)\n            {\n                Application.Current.Dispatcher?.InvokeAsync(() =>\n                {\n                    foreach (var server in servers)\n                    {\n                        if (FindFirstMatchServer(server, mergeConfig.Configs) == -1)\n                        {\n                            mergeConfig.Configs.Add(server);\n                        }\n                    }\n                });\n            }\n        }\n\n        private static IEnumerable<Server> MergeConfiguration(Configuration mergeConfig, IReadOnlyList<Server> servers)\n        {\n            if (servers != null)\n            {\n                foreach (var server in servers)\n                {\n                    var i = FindFirstMatchServer(server, mergeConfig.Configs);\n                    if (i != -1)\n                    {\n                        var enable = server.Enable;\n                        server.CopyServer(mergeConfig.Configs[i]);\n                        server.Enable = enable;\n                    }\n                }\n            }\n\n            return from t in mergeConfig.Configs let j = FindFirstMatchServer(t, servers) where j == -1 select t;\n        }\n\n        private static Configuration MergeGetConfiguration(Configuration mergeConfig)\n        {\n            var ret = Global.Load();\n            if (mergeConfig != null)\n            {\n                MergeConfiguration(mergeConfig, ret.Configs);\n            }\n            return ret;\n        }\n\n        /// <summary>\n        /// 从配置文件导入服务器\n        /// </summary>\n        /// <param name=\"mergeConfig\"></param>\n        public void MergeConfiguration(Configuration mergeConfig)\n        {\n            AppendConfiguration(Global.GuiConfig, mergeConfig.Configs);\n            SaveAndReload();\n        }\n\n        public void SaveServersConfig(Configuration config, bool reload)\n        {\n            var missingServers = MergeConfiguration(Global.GuiConfig, config.Configs);\n            Global.GuiConfig.CopyFrom(config);\n            foreach (var s in missingServers)\n            {\n                s.Connections.CloseAll();\n            }\n\n            if (reload)\n            {\n                SaveAndReload();\n            }\n            else\n            {\n                SaveAndNotifyChanged();\n            }\n        }\n\n        public void SaveServersPortMap(Configuration config)\n        {\n            StopPortMap();\n            Global.GuiConfig.PortMap = config.PortMap;\n            Global.GuiConfig.FlushPortMapCache();\n            LoadPortMap();\n            SaveAndNotifyChanged();\n        }\n\n        /// <summary>\n        /// 选择指定服务器\n        /// </summary>\n        public void SelectServerIndex(int index)\n        {\n            Global.GuiConfig.Index = index;\n            SaveAndNotifyChanged();\n        }\n\n        /// <summary>\n        /// 导入服务器链接\n        /// </summary>\n        public bool AddServerBySsUrl(string ssUrLs, string force_group = null, bool toLast = false)\n        {\n            try\n            {\n                var urls = ssUrLs.GetLines().Reverse();\n                var i = 0;\n                foreach (var url in urls.Select(url => url.Trim('/')).Where(url => url.StartsWith(@\"ss://\", StringComparison.OrdinalIgnoreCase) || url.StartsWith(@\"ssr://\", StringComparison.OrdinalIgnoreCase)))\n                {\n                    ++i;\n                    var server = new Server(url, force_group);\n                    if (toLast)\n                    {\n                        Global.GuiConfig.Configs.Add(server);\n                    }\n                    else\n                    {\n                        var index = Global.GuiConfig.Index + 1;\n                        if (index < 0 || index > Global.GuiConfig.Configs.Count)\n                        {\n                            index = Global.GuiConfig.Configs.Count;\n                        }\n\n                        Global.GuiConfig.Configs.Insert(index, server);\n                    }\n                }\n                if (i > 0)\n                {\n                    SaveAndReload();\n                    return true;\n                }\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                return false;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// 导入订阅链接\n        /// </summary>\n        public bool AddSubscribeUrl(string str)\n        {\n            try\n            {\n                var urls = str.GetLines();\n                var newSubscribes = new List<ServerSubscribe>();\n                var existSubscribes = new List<ServerSubscribe>();\n                foreach (var url in urls.Where(url => url.StartsWith(@\"sub://\", StringComparison.OrdinalIgnoreCase)))\n                {\n                    var sub = Regex.Match(url, \"sub://([A-Za-z0-9_-]+)\", RegexOptions.IgnoreCase);\n                    if (sub.Success)\n                    {\n                        var res = Base64.DecodeUrlSafeBase64(sub.Groups[1].Value);\n                        if (Global.GuiConfig.ServerSubscribes.All(serverSubscribe => serverSubscribe.Url != res))\n                        {\n                            var newSub = new ServerSubscribe { Url = res };\n                            newSubscribes.Add(newSub);\n                            Global.GuiConfig.ServerSubscribes.Add(newSub);\n                        }\n                        else\n                        {\n                            existSubscribes.Add(Global.GuiConfig.ServerSubscribes.Find(serverSubscribe => serverSubscribe.Url == res));\n                        }\n                    }\n                }\n                if (newSubscribes.Count > 0)\n                {\n                    SaveAndNotifyChanged();\n                    Global.UpdateSubscribeManager.CreateTask(Global.GuiConfig, Global.UpdateNodeChecker, true, newSubscribes);\n                    return true;\n                }\n                if (existSubscribes.Count > 0)\n                {\n                    Global.UpdateSubscribeManager.CreateTask(Global.GuiConfig, Global.UpdateNodeChecker, true, existSubscribes);\n                    return false;\n                }\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                return false;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// 切换系统代理模式\n        /// </summary>\n        public void ToggleMode(ProxyMode mode)\n        {\n            ProxyMode oldMode = Global.GuiConfig.SysProxyMode;\n            Global.GuiConfig.SysProxyMode = mode;\n            ReloadPacServer();\n            if (oldMode is not ProxyMode.NoModify && mode is ProxyMode.NoModify)\n            {\n                SystemProxy.Restore();\n            }\n            else\n            {\n                UpdateSystemProxy();\n            }\n            SaveAndNotifyChanged();\n        }\n\n        /// <summary>\n        /// 切换代理规则\n        /// </summary>\n        /// <param name=\"mode\"></param>\n        public void ToggleRuleMode(ProxyRuleMode mode)\n        {\n            Global.GuiConfig.ProxyRuleMode = mode;\n            SaveAndNotifyChanged();\n        }\n\n        public void ToggleSelectRandom(bool enabled)\n        {\n            Global.GuiConfig.Random = enabled;\n            if (!enabled)\n            {\n                DisconnectAllConnections(true);\n            }\n            SaveAndNotifyChanged();\n        }\n\n        public void ToggleSameHostForSameTargetRandom(bool enabled)\n        {\n            Global.GuiConfig.SameHostForSameTarget = enabled;\n            SaveAndNotifyChanged();\n        }\n\n        public void ToggleSelectAutoCheckUpdate(bool enabled)\n        {\n            Global.GuiConfig.AutoCheckUpdate = enabled;\n            Global.SaveConfig();\n        }\n\n        public void ToggleSelectAllowPreRelease(bool enabled)\n        {\n            Global.GuiConfig.IsPreRelease = enabled;\n            Global.SaveConfig();\n        }\n\n        /// <summary>\n        /// 保存配置文件并通知配置改变\n        /// </summary>\n        public void SaveAndNotifyChanged()\n        {\n            Global.SaveConfig();\n            Application.Current.Dispatcher?.InvokeAsync(() => { ConfigChanged?.Invoke(this, EventArgs.Empty); });\n        }\n\n        /// <summary>\n        /// 保存配置文件并重载\n        /// </summary>\n        private void SaveAndReload()\n        {\n            Global.SaveConfig();\n            Reload();\n        }\n\n        private void StopPortMap()\n        {\n            if (_portMapListener != null)\n            {\n                foreach (var l in _portMapListener)\n                {\n                    l.Stop();\n                }\n\n                _portMapListener = null;\n            }\n        }\n\n        private void LoadPortMap()\n        {\n            _portMapListener = new List<Listener>();\n            foreach (var pair in Global.GuiConfig.PortMapCache)\n            {\n                try\n                {\n                    var local = new Local(Global.GuiConfig, _transfer, _chnRangeSet);\n                    var services = new List<Listener.IService> { local };\n                    var listener = new Listener(services);\n                    listener.Start(Global.GuiConfig, pair.Key);\n                    _portMapListener.Add(listener);\n                }\n                catch (Exception e)\n                {\n                    ThrowSocketException(ref e);\n                    Logging.LogUsefulException(e);\n                    ReportError(e);\n                }\n            }\n        }\n\n        public void Stop()\n        {\n            if (_stopped)\n            {\n                return;\n            }\n            _stopped = true;\n\n            StopPortMap();\n\n            _listener?.Stop();\n            _httpProxyRunner?.Stop();\n            if (Global.GuiConfig.SysProxyMode is not ProxyMode.NoModify)\n            {\n                SystemProxy.Restore();\n            }\n            ServerTransferTotal.Save(_transfer, Global.GuiConfig.Configs);\n        }\n\n        public void ClearTransferTotal(string serverId)\n        {\n            _transfer.Clear(serverId);\n            var server = Global.GuiConfig.Configs.Find(s => s.Id == serverId);\n            server?.SpeedLog.ClearTrans();\n        }\n\n        public void TouchPACFile()\n        {\n            PACFileReadyToOpen?.Invoke(this, new PathEventArgs { Path = _pacDaemon.TouchPACFile() });\n        }\n\n        public void TouchUserRuleFile()\n        {\n            UserRuleFileReadyToOpen?.Invoke(this, new PathEventArgs { Path = _pacDaemon.TouchUserRuleFile() });\n        }\n\n        public void UpdatePACFromGFWList()\n        {\n            _gfwListUpdater?.UpdatePacFromGfwList(Global.GuiConfig);\n        }\n\n        public void UpdatePACFromOnlinePac(string url)\n        {\n            _gfwListUpdater?.UpdateOnlinePac(Global.GuiConfig, url);\n        }\n\n        private void ReloadPacServer()\n        {\n            if (_pacDaemon == null)\n            {\n                _pacDaemon = new PACDaemon();\n                _pacDaemon.PACFileChanged += (o, args) =>\n                {\n                    _pacServer?.UpdatePacUrl(Global.GuiConfig);\n                    UpdateSystemProxy();\n                };\n                _pacDaemon.UserRuleFileChanged += PacDaemon_UserRuleFileChanged;\n            }\n\n            if (_pacServer == null)\n            {\n                _pacServer = new PACServer(_pacDaemon);\n            }\n\n            _pacServer.UpdatePacUrl(Global.GuiConfig);\n        }\n\n        private void ReloadIPRange()\n        {\n            _chnRangeSet = new IPRangeSet();\n            _chnRangeSet.LoadChn();\n        }\n\n        private void ReloadProxyRule()\n        {\n            if (_hostDaemon == null)\n            {\n                _hostDaemon = new HostDaemon();\n                _hostDaemon.ChnIpChanged += (o, args) => ReloadIPRange();\n                _hostDaemon.UserRuleChanged += (o, args) => HostMap.Reload();\n            }\n\n            ReloadIPRange();\n            HostMap.Reload();\n        }\n\n        public void Reload()\n        {\n            StopPortMap();\n            // some logic in configuration updated the config when saving, we need to read it again\n            Global.GuiConfig = MergeGetConfiguration(Global.GuiConfig);\n            Global.GuiConfig.FlushPortMapCache();\n            Logging.SaveToFile = Global.GuiConfig.LogEnable;\n            Logging.OpenLogFile();\n\n            ReloadProxyRule();\n\n            _httpProxyRunner ??= new HttpProxyRunner();\n            ReloadPacServer();\n            if (_gfwListUpdater == null)\n            {\n                _gfwListUpdater = new GfwListUpdater();\n                _gfwListUpdater.UpdateCompleted += (o, args) => UpdatePACFromGFWListCompleted?.Invoke(o, args);\n                _gfwListUpdater.Error += (o, args) => UpdatePACFromGFWListError?.Invoke(o, args);\n            }\n\n            _listener?.Stop();\n            _httpProxyRunner.Stop();\n            try\n            {\n                _httpProxyRunner.Start(Global.GuiConfig);\n\n                var local = new Local(Global.GuiConfig, _transfer, _chnRangeSet);\n                var services = new List<Listener.IService>\n                {\n                    local,\n                    _pacServer,\n                    new HttpPortForwarder(_httpProxyRunner.RunningPort, Global.GuiConfig)\n                };\n                _listener = new Listener(services);\n                _listener.Start(Global.GuiConfig, 0);\n            }\n            catch (Exception e)\n            {\n                ThrowSocketException(ref e);\n                Logging.LogUsefulException(e);\n                ReportError(e);\n            }\n\n            LoadPortMap();\n\n            Application.Current.Dispatcher?.InvokeAsync(() => { ConfigChanged?.Invoke(this, EventArgs.Empty); });\n\n            UpdateSystemProxy();\n        }\n\n        private static void ThrowSocketException(ref Exception e)\n        {\n            // TODO:translate Microsoft language into human language\n            // i.e. An attempt was made to access a socket in a way forbidden by its access permissions => Port already in use\n            // https://docs.microsoft.com/zh-cn/dotnet/api/system.net.sockets.socketerror\n            if (e is not SocketException se)\n            {\n                return;\n            }\n\n            switch (se.SocketErrorCode)\n            {\n                case SocketError.AddressAlreadyInUse:\n                {\n                    e = new Exception(string.Format(I18NUtil.GetAppStringValue(@\"PortInUse\"), Global.GuiConfig.LocalPort), se);\n                    break;\n                }\n                case SocketError.AccessDenied:\n                {\n                    e = new Exception(string.Format(I18NUtil.GetAppStringValue(@\"PortReserved\"), Global.GuiConfig.LocalPort), se);\n                    break;\n                }\n            }\n        }\n\n        private void UpdateSystemProxy()\n        {\n            SystemProxy.Update(Global.GuiConfig, _pacServer);\n        }\n\n        private void PacDaemon_UserRuleFileChanged(object sender, EventArgs e)\n        {\n            if (!Utils.IsGFWListPAC(PACDaemon.PAC_FILE))\n            {\n                return;\n            }\n            if (!File.Exists(Utils.GetTempPath(PACServer.gfwlist_FILE)))\n            {\n                UpdatePACFromGFWList();\n            }\n            else\n            {\n                GfwListUpdater.MergeAndWritePacFile(FileManager.NonExclusiveReadAllText(Utils.GetTempPath(PACServer.gfwlist_FILE)));\n            }\n\n            UpdateSystemProxy();\n        }\n\n        public void ShowConfigForm(int? index = null)\n        {\n            ShowConfigFormEvent?.Invoke(index, EventArgs.Empty);\n        }\n\n        public void ShowSubscribeWindow()\n        {\n            ShowSubscribeWindowEvent?.Invoke(default, EventArgs.Empty);\n        }\n\n        /// <summary>\n        /// Disconnect all connections from the remote host.\n        /// </summary>\n        public void DisconnectAllConnections(bool checkSwitchAutoCloseAll = false)\n        {\n            var config = Global.GuiConfig;\n            if (checkSwitchAutoCloseAll && !config.CheckSwitchAutoCloseAll)\n            {\n                Console.WriteLine(@\"config.checkSwitchAutoCloseAll:False\");\n                return;\n            }\n            foreach (var server in config.Configs)\n            {\n                server.Connections.CloseAll();\n            }\n        }\n\n        public void CopyPacUrl()\n        {\n            Clipboard.SetDataObject(_pacServer.PacUrl);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/MenuViewController.cs",
    "content": "using Hardcodet.Wpf.TaskbarNotification;\nusing Microsoft.Win32;\nusing Shadowsocks.Controller.HttpRequest;\nusing Shadowsocks.Controller.Service;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Properties;\nusing Shadowsocks.Util;\nusing Shadowsocks.View;\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Windows.Shapes;\nusing Brushes = System.Windows.Media.Brushes;\nusing Rectangle = System.Drawing.Rectangle;\n\nnamespace Shadowsocks.Controller\n{\n    public class MenuViewController\n    {\n        private class EventParams\n        {\n            public readonly object sender;\n            public readonly EventArgs e;\n\n            public EventParams(object sender, EventArgs e)\n            {\n                this.sender = sender;\n                this.e = e;\n            }\n        }\n\n        // yes this is just a menu view controller\n        // when config form is closed, it moves away from RAM\n        // and it should just do anything related to the config form\n\n        private readonly MainController controller;\n        private readonly HttpRequest.UpdateChecker updateChecker;\n\n        private readonly TaskbarIcon _notifyIcon;\n        private ContextMenu _contextMenu;\n\n        private MenuItem noModifyItem;\n        private MenuItem enableItem;\n        private MenuItem PACModeItem;\n        private MenuItem globalModeItem;\n\n        private MenuItem ruleBypassLan;\n        private MenuItem ruleBypassChina;\n        private MenuItem ruleBypassNotChina;\n        private MenuItem ruleUser;\n        private MenuItem ruleDisableBypass;\n\n        private Separator SeparatorItem;\n        private MenuItem ServersItem;\n        private MenuItem SelectRandomItem;\n        private MenuItem sameHostForSameTargetItem;\n        private MenuItem _moreMenu;\n        private MenuItem _updateMenu;\n        private MenuItem UpdateItem;\n        private MenuItem AutoCheckUpdateItem;\n        private MenuItem AllowPreReleaseItem;\n        private ServerConfigWindow _serverConfigWindow;\n        private SettingsWindow _settingsWindow;\n        private DnsSettingWindow _dnsSettingsWindow;\n\n        #region ServerLogWindow\n\n        private ServerLogWindow _serverLogWindow;\n        private WindowStatus _serverLogWindowStatus;\n\n        #endregion\n\n        private PortSettingsWindow _portMapWindow;\n        private SubscribeWindow _subScribeWindow;\n        private LogWindow _logWindow;\n        private string _urlToOpen;\n        private System.Timers.Timer timerDelayCheckUpdate;\n\n        private bool configFrom_open;\n        private readonly List<EventParams> eventList = new();\n\n        public MenuViewController(MainController controller)\n        {\n            this.controller = controller;\n\n            LoadMenu();\n\n            controller.ConfigChanged += controller_ConfigChanged;\n            controller.PACFileReadyToOpen += controller_FileReadyToOpen;\n            controller.UserRuleFileReadyToOpen += controller_FileReadyToOpen;\n            controller.Errored += ControllerError;\n            controller.UpdatePACFromGFWListCompleted += controller_UpdatePACFromGFWListCompleted;\n            controller.UpdatePACFromGFWListError += controller_UpdatePACFromGFWListError;\n            controller.ShowConfigFormEvent += Config_Click;\n            controller.ShowSubscribeWindowEvent += Controller_ShowSubscribeWindowEvent;\n\n            _notifyIcon = new TaskbarIcon();\n            UpdateTrayIcon();\n            _notifyIcon.Visibility = Visibility.Visible;\n            _notifyIcon.ContextMenu = _contextMenu;\n\n            _notifyIcon.TrayLeftMouseUp += notifyIcon_TrayLeftMouseUp;\n            _notifyIcon.TrayMiddleMouseUp += notifyIcon_TrayMiddleMouseUp;\n            _notifyIcon.TrayBalloonTipClicked += notifyIcon_TrayBalloonTipClicked;\n\n            updateChecker = new HttpRequest.UpdateChecker();\n            updateChecker.NewVersionFound += updateChecker_NewVersionFound;\n            updateChecker.NewVersionNotFound += updateChecker_NewVersionNotFound;\n            updateChecker.NewVersionFoundFailed += UpdateChecker_NewVersionFoundFailed;\n\n            Global.UpdateNodeChecker = new UpdateNode();\n            Global.UpdateNodeChecker.NewFreeNodeFound += UpdateNodeCheckerNewNodeFound;\n\n            Global.UpdateSubscribeManager = new UpdateSubscribeManager();\n\n            LoadCurrentConfiguration();\n\n            timerDelayCheckUpdate = new System.Timers.Timer(1000.0 * 10);\n            timerDelayCheckUpdate.Elapsed += timer_Elapsed;\n            timerDelayCheckUpdate.Start();\n        }\n\n        private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)\n        {\n            timerDelayCheckUpdate.Interval = 1000.0 * 60 * 60 * 1;// 1 hour\n\n            var cfg = Global.GuiConfig;\n            if (cfg.AutoCheckUpdate)\n            {\n                updateChecker.Check(cfg, false);\n            }\n\n            Global.UpdateSubscribeManager.CreateTask(cfg, Global.UpdateNodeChecker, false);\n        }\n\n        private static void ControllerError(object sender, ErrorEventArgs e)\n        {\n            MessageBox.Show(e.GetException().ToString(), string.Format(I18NUtil.GetAppStringValue(@\"ControllerError\"), e.GetException().Message));\n        }\n\n        private void UpdateTrayIcon()\n        {\n            var config = Global.GuiConfig;\n            var enabled = config.SysProxyMode is not ProxyMode.NoModify and not ProxyMode.Direct;\n            var global = config.SysProxyMode == ProxyMode.Global;\n            var random = config.Random;\n\n            var colorMask = ViewUtils.SelectColorMask(enabled, global);\n            var icon = ViewUtils.ChangeBitmapColor(Resources.ss128, colorMask, random);\n            var size = ViewUtils.GetIconSize();\n            var newIcon = Icon.FromHandle(ViewUtils.ResizeBitmap(icon, size.Width, size.Height).GetHicon());\n\n            if (_notifyIcon.Icon != null)\n            {\n                ViewUtils.DestroyIcon(_notifyIcon.Icon.Handle);\n            }\n\n            _notifyIcon.Icon = newIcon;\n\n            string strServer = null;\n            var line3 = string.Empty;\n            var line4 = string.Empty;\n            if (random)\n            {\n                strServer = $@\"{I18NUtil.GetAppStringValue(@\"LoadBalance\")}{I18NUtil.GetAppStringValue(@\"Colon\")}{I18NUtil.GetAppStringValue(config.BalanceType.ToString())}\";\n                if (config.RandomInGroup)\n                {\n                    line3 = $@\"{I18NUtil.GetAppStringValue(@\"BalanceInGroup\")}{Environment.NewLine}\";\n                }\n\n                if (config.AutoBan)\n                {\n                    line4 = $@\"{I18NUtil.GetAppStringValue(@\"AutoBan\")}{Environment.NewLine}\";\n                }\n            }\n            else\n            {\n                if (config.Index >= 0 && config.Index < config.Configs.Count)\n                {\n                    var groupName = config.Configs[config.Index].Group;\n                    var serverName = config.Configs[config.Index].Remarks;\n                    if (string.IsNullOrWhiteSpace(groupName))\n                    {\n                        strServer = string.IsNullOrWhiteSpace(serverName) ? null : serverName;\n                    }\n                    else if (string.IsNullOrWhiteSpace(serverName))\n                    {\n                        strServer = $@\"{groupName}\";\n                    }\n                    else\n                    {\n                        strServer = $@\"{groupName}{I18NUtil.GetAppStringValue(@\"Colon\")}{serverName}\";\n                    }\n                }\n            }\n\n            string line1;\n            switch (config.SysProxyMode)\n            {\n                case ProxyMode.NoModify:\n                {\n                    line1 = $@\"{I18NUtil.GetAppStringValue(@\"NoProxy\")}{Environment.NewLine}\";\n                    break;\n                }\n                case ProxyMode.Direct:\n                {\n                    line1 = $@\"{I18NUtil.GetAppStringValue(@\"DisableProxy\")}{Environment.NewLine}\";\n                    break;\n                }\n                case ProxyMode.Pac:\n                {\n                    line1 = $@\"{I18NUtil.GetAppStringValue(@\"PacProxy\")}{Environment.NewLine}\";\n                    break;\n                }\n                case ProxyMode.Global:\n                {\n                    line1 = $@\"{I18NUtil.GetAppStringValue(@\"GlobalProxy\")}{Environment.NewLine}\";\n                    break;\n                }\n                default:\n                {\n                    line1 = null;\n                    break;\n                }\n            }\n            var line2 = string.IsNullOrWhiteSpace(strServer) ? null : $@\"{strServer}{Environment.NewLine}\";\n            var line5 = string.Format(I18NUtil.GetAppStringValue(@\"RunningPort\"), config.LocalPort); // this feedback is very important because they need to know Shadowsocks is running\n\n            var text = $@\"{line1}{line2}{line3}{line4}{line5}\";\n            _notifyIcon.ToolTipText = text;\n        }\n\n        private void LoadMenu()\n        {\n            if (Application.Current.FindResource(@\"SysTrayMenu\") is ContextMenu menu)\n            {\n                _contextMenu = menu;\n            }\n\n            I18NUtil.SetLanguage(_contextMenu);\n            foreach (var obj in _contextMenu.Items)\n            {\n                if (obj is MenuItem menuItem)\n                {\n                    switch (menuItem.Name)\n                    {\n                        case @\"Mode\":\n                        {\n                            enableItem = (MenuItem)menuItem.Items[0];\n                            PACModeItem = (MenuItem)menuItem.Items[1];\n                            globalModeItem = (MenuItem)menuItem.Items[2];\n                            noModifyItem = (MenuItem)menuItem.Items[4];\n                            enableItem.Click += EnableItem_Click;\n                            PACModeItem.Click += PACModeItem_Click;\n                            globalModeItem.Click += GlobalModeItem_Click;\n                            noModifyItem.Click += NoModifyItem_Click;\n                            break;\n                        }\n                        case @\"ProxySetting\":\n                        {\n                            var pacMenuItem = (MenuItem)menuItem.Items[0];\n                            var proxyMenuItem = (MenuItem)menuItem.Items[1];\n                            ((MenuItem)menuItem.Items[3]).Click += CopyPacUrlItem_Click;\n                            ((MenuItem)menuItem.Items[4]).Click += EditPACFileItem_Click;\n                            ((MenuItem)menuItem.Items[5]).Click += EditUserRuleFileForGFWListItem_Click;\n\n                            ((MenuItem)pacMenuItem.Items[0]).Click += UpdatePACFromLanIPListItem_Click;\n\n                            ((MenuItem)pacMenuItem.Items[2]).Click += UpdatePACFromCNWhiteListItem_Click;\n                            ((MenuItem)pacMenuItem.Items[3]).Click += UpdatePACFromCnWhiteListIpItem_Click;\n                            ((MenuItem)pacMenuItem.Items[4]).Click += UpdatePACFromChnIpItem_Click;\n                            ((MenuItem)pacMenuItem.Items[5]).Click += UpdatePACFromGFWListItem_Click;\n\n                            ((MenuItem)pacMenuItem.Items[7]).Click += UpdatePACFromCNOnlyListItem_Click;\n\n                            ruleBypassLan = (MenuItem)proxyMenuItem.Items[0];\n                            ruleBypassChina = (MenuItem)proxyMenuItem.Items[1];\n                            ruleBypassNotChina = (MenuItem)proxyMenuItem.Items[2];\n                            ruleUser = (MenuItem)proxyMenuItem.Items[3];\n                            ruleDisableBypass = (MenuItem)proxyMenuItem.Items[5];\n\n                            ruleBypassLan.Click += RuleBypassLanItem_Click;\n                            ruleBypassChina.Click += RuleBypassChinaItem_Click;\n                            ruleBypassNotChina.Click += RuleBypassNotChinaItem_Click;\n                            ruleUser.Click += RuleUserItem_Click;\n                            ruleDisableBypass.Click += RuleBypassDisableItem_Click;\n                            break;\n                        }\n                        case @\"Servers\":\n                        {\n                            ServersItem = menuItem;\n                            SeparatorItem = (Separator)menuItem.Items[0];\n                            SelectRandomItem = (MenuItem)menuItem.Items[7];\n                            sameHostForSameTargetItem = (MenuItem)menuItem.Items[8];\n\n                            ((MenuItem)menuItem.Items[1]).Click += Config_Click;\n                            ((MenuItem)menuItem.Items[3]).Click += ScanQRCodeItem_Click;\n                            ((MenuItem)menuItem.Items[4]).Click += ImportAddressFromClipboard_Click;\n                            ((MenuItem)menuItem.Items[5]).Click += Import_Click;\n                            SelectRandomItem.Click += SelectRandomItem_Click;\n                            sameHostForSameTargetItem.Click += SelectSameHostForSameTargetItem_Click;\n                            ((MenuItem)menuItem.Items[10]).Click += ShowServerLogItem_Click;\n                            ((MenuItem)menuItem.Items[11]).Click += DisconnectCurrent_Click;\n                            break;\n                        }\n                        case @\"ServersSubscribe\":\n                        {\n                            ((MenuItem)menuItem.Items[0]).Click += SubscribeSetting_Click;\n                            ((MenuItem)menuItem.Items[1]).Click += CheckNodeUpdate_Click;\n                            break;\n                        }\n                        case @\"ShowLogs\":\n                        {\n                            menuItem.Click += ShowLogItem_Click;\n                            break;\n                        }\n                        case @\"More\":\n                        {\n                            _moreMenu = menuItem;\n                            ((MenuItem)_moreMenu.Items[0]).Click += Setting_Click;\n                            ((MenuItem)_moreMenu.Items[1]).Click += DnsSetting_Click;\n                            ((MenuItem)_moreMenu.Items[2]).Click += ShowPortMapItem_Click;\n                            ((MenuItem)_moreMenu.Items[3]).Click += ShowUrlFromQrCode;\n                            ((MenuItem)_moreMenu.Items[5]).Click += OpenWiki_Click;\n                            ((MenuItem)_moreMenu.Items[6]).Click += FeedbackItem_Click;\n\n                            _updateMenu = (MenuItem)_moreMenu.Items[8];\n\n                            ((MenuItem)_updateMenu.Items[0]).Click += CheckUpdate_Click;\n                            UpdateItem = (MenuItem)_updateMenu.Items[1];\n                            AutoCheckUpdateItem = (MenuItem)_updateMenu.Items[3];\n                            AllowPreReleaseItem = (MenuItem)_updateMenu.Items[4];\n                            UpdateItem.Click += UpdateItem_Clicked;\n                            AutoCheckUpdateItem.Click += AutoCheckUpdateItem_Click;\n                            AllowPreReleaseItem.Click += AllowPreRelease_Click;\n                            break;\n                        }\n                        case @\"Quit\":\n                        {\n                            menuItem.Click += Quit_Click;\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        private void controller_ConfigChanged(object sender, EventArgs e)\n        {\n            LoadCurrentConfiguration();\n            UpdateTrayIcon();\n        }\n\n        private void controller_FileReadyToOpen(object sender, MainController.PathEventArgs e)\n        {\n            Utils.OpenURL(e.Path);\n        }\n\n        private void controller_UpdatePACFromGFWListError(object sender, ErrorEventArgs e)\n        {\n            _notifyIcon.ShowBalloonTip(I18NUtil.GetAppStringValue(@\"UpdatePacFailed\"), e.GetException().Message, BalloonIcon.Error);\n            Logging.LogUsefulException(e.GetException());\n        }\n\n        private void controller_UpdatePACFromGFWListCompleted(object sender, GfwListUpdater.ResultEventArgs e)\n        {\n            var result = e.Success ?\n                    e.PacType == PacType.GfwList ?\n                    I18NUtil.GetAppStringValue(@\"GfwListPacUpdated\") : I18NUtil.GetAppStringValue(@\"PacUpdated\")\n                : I18NUtil.GetAppStringValue(@\"GfwListPacNotFound\");\n            _notifyIcon.ShowBalloonTip(HttpRequest.UpdateChecker.Name, result, BalloonIcon.Info);\n        }\n\n        private void UpdateNodeCheckerNewNodeFound(object sender, EventArgs e)\n        {\n            if (configFrom_open)\n            {\n                eventList.Add(new EventParams(sender, e));\n                return;\n            }\n            string lastGroup = null;\n            var count = 0;\n            if (!string.IsNullOrWhiteSpace(Global.UpdateNodeChecker.FreeNodeResult))\n            {\n                Global.UpdateNodeChecker.FreeNodeResult = Global.UpdateNodeChecker.FreeNodeResult.TrimEnd('\\r', '\\n', ' ');\n                var config = Global.GuiConfig;\n                var selectedServer = config.Configs.ElementAtOrDefault(config.Index);\n                try\n                {\n                    Global.UpdateNodeChecker.FreeNodeResult = Base64.DecodeBase64(Global.UpdateNodeChecker.FreeNodeResult);\n                }\n                catch\n                {\n                    Global.UpdateNodeChecker.FreeNodeResult = string.Empty;\n                }\n                var urls = Global.UpdateNodeChecker.FreeNodeResult.GetLines().ToList();\n                urls.RemoveAll(url => !url.StartsWith(@\"ssr://\"));\n                if (urls.Count > 0)\n                {\n                    lastGroup = Global.UpdateSubscribeManager.CurrentServerSubscribe.OriginTag;\n                    if (string.IsNullOrEmpty(lastGroup))\n                    {\n                        foreach (var url in urls)\n                        {\n                            try // try get group name\n                            {\n                                var server = new Server(url, null);\n                                if (!string.IsNullOrEmpty(server.Group))\n                                {\n                                    if (config.ServerSubscribes.Any(subscribe => subscribe.Tag == server.Group))\n                                    {\n                                        continue;\n                                    }\n\n                                    var serverSubscribe = config.ServerSubscribes.Find(sub =>\n                                    sub.Url == Global.UpdateSubscribeManager.CurrentServerSubscribe.Url\n                                    && string.IsNullOrEmpty(sub.OriginTag));\n\n                                    if (serverSubscribe != null)\n                                    {\n                                        lastGroup = serverSubscribe.Tag = server.Group;\n                                    }\n\n                                    break;\n                                }\n                            }\n                            catch\n                            {\n                                // ignored\n                            }\n                        }\n                    }\n                    if (string.IsNullOrEmpty(lastGroup))\n                    {\n                        lastGroup = Global.UpdateSubscribeManager.CurrentServerSubscribe.UrlMd5;\n                    }\n\n                    //Find old servers\n                    var firstInsertIndex = config.Configs.Count;\n                    var oldServers = config.Configs.FindAll(server => server.SubTag == lastGroup);\n                    var index = config.Configs.FindIndex(server => server.SubTag == lastGroup);\n                    if (index >= 0)\n                    {\n                        firstInsertIndex = index;\n                    }\n\n                    //Find new servers\n                    var newServers = new List<Server>();\n                    foreach (var url in urls)\n                    {\n                        try\n                        {\n                            var server = new Server(url, lastGroup) { Index = firstInsertIndex++ };\n                            newServers.Add(server);\n                        }\n                        catch\n                        {\n                            // ignored\n                        }\n                    }\n\n                    //Group name is not empty\n                    foreach (var newServer in newServers.Where(newServer => string.IsNullOrEmpty(newServer.Group)))\n                    {\n                        newServer.Group = lastGroup;\n                    }\n\n                    count = newServers.Count;\n\n                    var removeServers = oldServers.Except(newServers);\n                    var addServers = newServers.Except(oldServers);\n\n                    //Remove servers\n                    foreach (var server in removeServers)\n                    {\n                        server.Connections.CloseAll();\n                        config.Configs.Remove(server);\n                    }\n\n                    //Add servers\n                    foreach (var server in addServers)\n                    {\n                        if (server.Index > config.Configs.Count)\n                        {\n                            server.Index = config.Configs.Count;\n                        }\n                        config.Configs.Insert(server.Index, server);\n                    }\n\n                    //Set SelectedServer\n                    var selectedIndex = -1;\n                    if (selectedServer is not null)\n                    {\n                        selectedIndex = config.Configs.FindIndex(server => server.Id == selectedServer.Id);\n\n                        if (selectedIndex < 0)\n                        {\n                            selectedIndex = config.Configs.FindIndex(server =>\n                                server.SubTag == selectedServer.SubTag && server.IsMatchServer(selectedServer)\n                            );\n                        }\n\n                        if (selectedIndex < 0)\n                        {\n                            selectedIndex = config.Configs.FindIndex(server =>\n                                server.SubTag == selectedServer.SubTag\n                                && server.Group == selectedServer.Group\n                                && server.Remarks == selectedServer.Remarks\n                            );\n                        }\n\n                        if (selectedIndex < 0)\n                        {\n                            selectedIndex = config.Configs.FindIndex(server =>\n                                server.SubTag == selectedServer.SubTag\n                                && server.Group == selectedServer.Group\n                            );\n                        }\n\n                        if (selectedIndex < 0)\n                        {\n                            selectedIndex = config.Configs.FindIndex(server => server.SubTag == selectedServer.SubTag);\n                        }\n                    }\n\n                    config.Index = selectedIndex < 0 ? default : selectedIndex;\n\n                    //If Update Success\n                    if (count > 0)\n                    {\n                        foreach (var serverSubscribe in config.ServerSubscribes.Where(serverSubscribe => serverSubscribe.Url == Global.UpdateNodeChecker.SubscribeTask.Url))\n                        {\n                            serverSubscribe.LastUpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();\n                        }\n\n                        var defaultServer = new Server();\n                        config.Configs.RemoveAll(server => server.IsMatchServer(defaultServer));\n                    }\n                    controller.SaveServersConfig(config, true);\n                }\n            }\n\n            if (count > 0)\n            {\n                if (Global.UpdateNodeChecker.Notify)\n                {\n                    _notifyIcon.ShowBalloonTip(I18NUtil.GetAppStringValue(@\"Success\"), string.Format(I18NUtil.GetAppStringValue(@\"UpdateSubscribeSuccess\"), lastGroup), BalloonIcon.Info);\n                }\n            }\n            else\n            {\n                if (string.IsNullOrEmpty(lastGroup))\n                {\n                    lastGroup = Global.UpdateNodeChecker.SubscribeTask.Tag;\n                }\n\n                if (Global.UpdateNodeChecker.Notify)\n                {\n                    _notifyIcon.ShowBalloonTip(I18NUtil.GetAppStringValue(@\"Error\"), string.Format(I18NUtil.GetAppStringValue(@\"UpdateSubscribeFailure\"), lastGroup), BalloonIcon.Info);\n                }\n            }\n\n            Global.UpdateSubscribeManager.Next();\n        }\n\n        private void updateChecker_NewVersionFound(object sender, EventArgs e)\n        {\n            Application.Current.Dispatcher?.InvokeAsync(() =>\n            {\n                if (updateChecker.Found)\n                {\n                    if (UpdateItem.Visibility != Visibility.Visible)\n                    {\n                        _notifyIcon.ShowBalloonTip(\n                                string.Format(I18NUtil.GetAppStringValue(@\"NewVersionFound\"),\n                                        HttpRequest.UpdateChecker.Name, updateChecker.LatestVersionNumber),\n                                I18NUtil.GetAppStringValue(@\"ClickMenuToDownload\"), BalloonIcon.Info);\n                    }\n                    _moreMenu.Icon = CreateSelectedIcon();\n                    _updateMenu.Icon = CreateSelectedIcon();\n                    UpdateItem.Visibility = Visibility.Visible;\n                    UpdateItem.Header = string.Format(I18NUtil.GetAppStringValue(@\"NewVersionAvailable\"),\n                            HttpRequest.UpdateChecker.Name, updateChecker.LatestVersionNumber);\n                }\n            });\n        }\n\n        private void updateChecker_NewVersionNotFound(object sender, EventArgs e)\n        {\n            _notifyIcon.ShowBalloonTip($@\"{HttpRequest.UpdateChecker.Name} {HttpRequest.UpdateChecker.FullVersion}\",\n            $@\"{I18NUtil.GetAppStringValue(@\"NewVersionNotFound\")}{Environment.NewLine}{HttpRequest.UpdateChecker.Version}≥{updateChecker.LatestVersionNumber}\",\n            BalloonIcon.Info);\n        }\n\n        private void UpdateChecker_NewVersionFoundFailed(object sender, EventArgs e)\n        {\n            _notifyIcon.ShowBalloonTip($@\"{HttpRequest.UpdateChecker.Name} {HttpRequest.UpdateChecker.FullVersion}\", I18NUtil.GetAppStringValue(@\"NewVersionFoundFailed\"), BalloonIcon.Info);\n        }\n\n        private void UpdateItem_Clicked(object sender, RoutedEventArgs e)\n        {\n            Utils.OpenURL(updateChecker.LatestVersionUrl);\n            _moreMenu.Icon = null;\n            _updateMenu.Icon = null;\n            UpdateItem.Visibility = Visibility.Collapsed;\n            updateChecker.Found = false;\n        }\n\n        private void notifyIcon_TrayBalloonTipClicked(object sender, RoutedEventArgs e)\n        {\n            var url = updateChecker.LatestVersionUrl;\n            if (!string.IsNullOrWhiteSpace(url))\n            {\n                Utils.OpenURL(url);\n            }\n        }\n\n        private void UpdateSysProxyMode(Configuration config)\n        {\n            noModifyItem.IsChecked = config.SysProxyMode == ProxyMode.NoModify;\n            enableItem.IsChecked = config.SysProxyMode == ProxyMode.Direct;\n            PACModeItem.IsChecked = config.SysProxyMode == ProxyMode.Pac;\n            globalModeItem.IsChecked = config.SysProxyMode == ProxyMode.Global;\n        }\n\n        private void UpdateProxyRule(Configuration config)\n        {\n            ruleDisableBypass.IsChecked = config.ProxyRuleMode == ProxyRuleMode.Disable;\n            ruleBypassLan.IsChecked = config.ProxyRuleMode == ProxyRuleMode.BypassLan;\n            ruleBypassChina.IsChecked = config.ProxyRuleMode == ProxyRuleMode.BypassLanAndChina;\n            ruleBypassNotChina.IsChecked = config.ProxyRuleMode == ProxyRuleMode.BypassLanAndNotChina;\n            ruleUser.IsChecked = config.ProxyRuleMode == ProxyRuleMode.UserCustom;\n        }\n\n        private void LoadCurrentConfiguration()\n        {\n            var config = Global.GuiConfig;\n            UpdateServersMenu();\n            UpdateSysProxyMode(config);\n\n            UpdateProxyRule(config);\n\n            SelectRandomItem.IsChecked = config.Random;\n            sameHostForSameTargetItem.IsChecked = config.SameHostForSameTarget;\n            AutoCheckUpdateItem.IsChecked = config.AutoCheckUpdate;\n            AllowPreReleaseItem.IsChecked = config.IsPreRelease;\n        }\n\n        private static Grid CreateSelectedIcon()\n        {\n            var icon = new Grid();\n            icon.Children.Add(new Ellipse\n            {\n                Width = 8,\n                Height = 8,\n                Fill = Brushes.Black\n            });\n            return icon;\n        }\n\n        private void UpdateServersMenu()\n        {\n            var items = ServersItem.Items;\n            while (!Equals(items[0], SeparatorItem))\n            {\n                items.RemoveAt(0);\n            }\n\n            var configuration = Global.GuiConfig;\n            for (var i = 0; i < configuration.Configs.Count;)\n            {\n                configuration.Configs[i].Index = ++i;\n            }\n            var sub = new List<MenuItem>();\n            var subTags = new HashSet<string>(configuration.Configs.Select(server => server.SubTag));\n            foreach (var subTag in subTags)\n            {\n                var isSelected = false;\n                var subItem = new MenuItem\n                {\n                    Header = string.IsNullOrEmpty(subTag) ? I18NUtil.GetAppStringValue(@\"EmptySubtag\") : subTag\n                };\n                var servers = configuration.Configs.Where(server => server.SubTag == subTag).ToArray();\n                var groups = new HashSet<string>(servers.Select(server => server.Group));\n                foreach (var group in groups)\n                {\n                    var groupItem = new MenuItem\n                    {\n                        Header = string.IsNullOrEmpty(group) ? I18NUtil.GetAppStringValue(@\"EmptyGroup\") : group\n                    };\n                    var subServers = servers.Where(server => server.Group == group);\n                    foreach (var server in subServers)\n                    {\n                        var item = new MenuItem\n                        {\n                            Header = server.FriendlyName,\n                            Tag = server.Index - 1\n                        };\n                        item.Click += AServerItem_Click;\n                        if (configuration.Index == Convert.ToInt32(item.Tag))\n                        {\n                            item.IsChecked = true;\n                            isSelected = true;\n                        }\n                        groupItem.Items.Add(item);\n                    }\n                    if (groups.Count > 1)\n                    {\n                        subItem.Items.Add(groupItem);\n                        if (isSelected)\n                        {\n                            groupItem.Icon = CreateSelectedIcon();\n                            subItem.Icon = CreateSelectedIcon();\n                            isSelected = false;\n                        }\n                    }\n                    else\n                    {\n                        groupItem.Header = subItem.Header;\n                        sub.Add(groupItem);\n                        if (isSelected)\n                        {\n                            groupItem.Icon = CreateSelectedIcon();\n                        }\n                    }\n                }\n                if (groups.Count > 1)\n                {\n                    sub.Add(subItem);\n                }\n            }\n            var index = 0;\n            foreach (var menuItem in sub)\n            {\n                items.Insert(index++, menuItem);\n            }\n        }\n\n        private void ShowConfigForm(bool addNode)\n        {\n            if (_serverConfigWindow != null)\n            {\n                _serverConfigWindow.Activate();\n                _serverConfigWindow.UpdateLayout();\n                if (_serverConfigWindow.WindowState == WindowState.Minimized)\n                {\n                    _serverConfigWindow.WindowState = WindowState.Normal;\n                }\n                if (addNode)\n                {\n                    var cfg = Global.GuiConfig;\n                    _serverConfigWindow.MoveToSelectedItem(cfg.Index + 1);\n                }\n            }\n            else\n            {\n                configFrom_open = true;\n                _serverConfigWindow = new ServerConfigWindow(controller, addNode ? -1 : -2);\n                _serverConfigWindow.Show();\n                _serverConfigWindow.Activate();\n                _serverConfigWindow.BringToFront();\n                _serverConfigWindow.Closed += ServerConfigWindowClosed;\n            }\n        }\n\n        private void ServerConfigWindowClosed(object sender, EventArgs e)\n        {\n            _serverConfigWindow = null;\n            configFrom_open = false;\n            if (eventList.Count > 0)\n            {\n                foreach (var p in eventList)\n                {\n                    UpdateNodeCheckerNewNodeFound(p.sender, p.e);\n                }\n\n                eventList.Clear();\n            }\n        }\n\n        private void ShowConfigForm(int index)\n        {\n            if (_serverConfigWindow != null)\n            {\n                _serverConfigWindow.Activate();\n                _serverConfigWindow.UpdateLayout();\n                if (_serverConfigWindow.WindowState == WindowState.Minimized)\n                {\n                    _serverConfigWindow.WindowState = WindowState.Normal;\n                }\n                _serverConfigWindow.Topmost = true;\n                _serverConfigWindow.MoveToSelectedItem(index);\n            }\n            else\n            {\n                configFrom_open = true;\n                _serverConfigWindow = new ServerConfigWindow(controller, index);\n                _serverConfigWindow.Show();\n                _serverConfigWindow.Activate();\n                _serverConfigWindow.Topmost = true;\n                _serverConfigWindow.Closed += ServerConfigWindowClosed;\n            }\n        }\n\n        private void ShowSettingForm()\n        {\n            if (_settingsWindow != null)\n            {\n                _settingsWindow.Activate();\n            }\n            else\n            {\n                _settingsWindow = new SettingsWindow(controller);\n                _settingsWindow.Show();\n                _settingsWindow.Activate();\n                _settingsWindow.BringToFront();\n                _settingsWindow.Closed += (_, _) =>\n                {\n                    _settingsWindow = null;\n                };\n            }\n        }\n\n        private void ShowDnsSettingWindow()\n        {\n            if (_dnsSettingsWindow != null)\n            {\n                _dnsSettingsWindow.Activate();\n            }\n            else\n            {\n                _dnsSettingsWindow = new DnsSettingWindow();\n                _dnsSettingsWindow.Show();\n                _dnsSettingsWindow.Activate();\n                _dnsSettingsWindow.BringToFront();\n                _dnsSettingsWindow.Closed += (o, args) =>\n                {\n                    _dnsSettingsWindow = null;\n                };\n            }\n        }\n\n        private void ShowPortMapForm()\n        {\n            if (_portMapWindow != null)\n            {\n                _portMapWindow.Activate();\n                _portMapWindow.UpdateLayout();\n                if (_portMapWindow.WindowState == WindowState.Minimized)\n                {\n                    _portMapWindow.WindowState = WindowState.Normal;\n                }\n            }\n            else\n            {\n                _portMapWindow = new PortSettingsWindow(controller);\n                _portMapWindow.Show();\n                _portMapWindow.Activate();\n                _portMapWindow.BringToFront();\n                _portMapWindow.Closed += (o, e) =>\n                {\n                    _portMapWindow = null;\n                };\n            }\n        }\n\n        private void ShowServerLogForm()\n        {\n            if (_serverLogWindow != null)\n            {\n                _serverLogWindow.Activate();\n                _serverLogWindow.UpdateLayout();\n                if (_serverLogWindow.WindowState == WindowState.Minimized)\n                {\n                    _serverLogWindow.WindowState = WindowState.Normal;\n                }\n            }\n            else\n            {\n                _serverLogWindow = new ServerLogWindow(controller, _serverLogWindowStatus);\n                _serverLogWindow.Show();\n                _serverLogWindow.Activate();\n                _serverLogWindow.BringToFront();\n                _serverLogWindow.Closed += (o, e) =>\n                {\n                    _serverLogWindowStatus = new WindowStatus(_serverLogWindow);\n                    _serverLogWindow = null;\n                };\n            }\n        }\n\n        private void ShowGlobalLogWindow()\n        {\n            if (_logWindow != null)\n            {\n                _logWindow.Activate();\n                _logWindow.UpdateLayout();\n                if (_logWindow.WindowState == WindowState.Minimized)\n                {\n                    _logWindow.WindowState = WindowState.Normal;\n                }\n            }\n            else\n            {\n                _logWindow = new LogWindow();\n                _logWindow.Show();\n                _logWindow.Activate();\n                _logWindow.BringToFront();\n                _logWindow.Closed += (sender, args) =>\n                {\n                    _logWindow = null;\n                };\n            }\n        }\n\n        private void ShowSubscribeSettingForm()\n        {\n            if (_subScribeWindow != null)\n            {\n                _subScribeWindow.Activate();\n                _subScribeWindow.UpdateLayout();\n                if (_subScribeWindow.WindowState == WindowState.Minimized)\n                {\n                    _subScribeWindow.WindowState = WindowState.Normal;\n                }\n            }\n            else\n            {\n                _subScribeWindow = new SubscribeWindow(controller);\n                _subScribeWindow.Show();\n                _subScribeWindow.Activate();\n                _subScribeWindow.BringToFront();\n                _subScribeWindow.Closed += (sender, args) =>\n                {\n                    _subScribeWindow = null;\n                };\n            }\n        }\n\n        private void Config_Click(object sender, EventArgs e)\n        {\n            if (sender is int i)\n            {\n                ShowConfigForm(i);\n            }\n            else\n            {\n                ShowConfigForm(false);\n            }\n        }\n\n        private void Controller_ShowSubscribeWindowEvent(object sender, EventArgs e)\n        {\n            ShowSubscribeSettingForm();\n        }\n\n        private void Import_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() =>\n            {\n                var dlg = new OpenFileDialog\n                {\n                    InitialDirectory = Directory.GetCurrentDirectory()\n                };\n                if (dlg.ShowDialog() == true)\n                {\n                    var name = dlg.FileName;\n                    var cfg = Global.LoadFile(name);\n                    if (cfg.IsDefaultConfig())\n                    {\n                        MessageBox.Show(I18NUtil.GetAppStringValue(@\"ImportConfigFailed\"), HttpRequest.UpdateChecker.Name);\n                    }\n                    else\n                    {\n                        controller.MergeConfiguration(cfg);\n                    }\n                }\n            });\n        }\n\n        private void Setting_Click(object sender, RoutedEventArgs e)\n        {\n            ShowSettingForm();\n        }\n\n        private void DnsSetting_Click(object sender, RoutedEventArgs e)\n        {\n            ShowDnsSettingWindow();\n        }\n\n        public void Quit_Click(object sender, EventArgs e)\n        {\n            controller.Stop();\n            if (_serverConfigWindow != null)\n            {\n                _serverConfigWindow.Close();\n                _serverConfigWindow = null;\n            }\n            if (_serverLogWindow != null)\n            {\n                _serverLogWindow.Close();\n                _serverLogWindow = null;\n            }\n            if (timerDelayCheckUpdate != null)\n            {\n                timerDelayCheckUpdate.Elapsed -= timer_Elapsed;\n                timerDelayCheckUpdate.Stop();\n                timerDelayCheckUpdate = null;\n            }\n            if (_notifyIcon.Icon != null)\n            {\n                ViewUtils.DestroyIcon(_notifyIcon.Icon.Handle);\n            }\n            _notifyIcon.Dispose();\n            Application.Current.Shutdown();\n        }\n\n        private static void OpenWiki_Click(object sender, RoutedEventArgs e)\n        {\n            Utils.OpenURL(@\"https://github.com/HMBSbige/ShadowsocksR-Windows/wiki\");\n        }\n\n        private static void FeedbackItem_Click(object sender, RoutedEventArgs e)\n        {\n            Utils.OpenURL(@\"https://github.com/HMBSbige/ShadowsocksR-Windows/issues/new/choose\");\n        }\n\n        private void notifyIcon_TrayLeftMouseUp(object sender, RoutedEventArgs e)\n        {\n            var key = Keyboard.IsKeyDown(Key.LeftShift) ? 1 : 0;\n            key |= Keyboard.IsKeyDown(Key.RightShift) ? 1 : 0;\n            key |= Keyboard.IsKeyDown(Key.LeftCtrl) ? 2 : 0;\n            key |= Keyboard.IsKeyDown(Key.RightCtrl) ? 2 : 0;\n            key |= Keyboard.IsKeyDown(Key.LeftAlt) ? 4 : 0;\n            switch (key)\n            {\n                case 1:\n                    ShowSettingForm();\n                    break;\n                case 2:\n                    ShowServerLogForm();\n                    break;\n                case 3:\n                    ShowSubscribeSettingForm();\n                    break;\n                case 4:\n                    ShowPortMapForm();\n                    break;\n                case 6:\n                    ShowDnsSettingWindow();\n                    break;\n                default:\n                    ShowConfigForm(false);\n                    break;\n            }\n        }\n\n        private void notifyIcon_TrayMiddleMouseUp(object sender, RoutedEventArgs e)\n        {\n            ShowServerLogForm();\n        }\n\n        private void NoModifyItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleMode(ProxyMode.NoModify); });\n        }\n\n        private void EnableItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleMode(ProxyMode.Direct); });\n        }\n\n        private void GlobalModeItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleMode(ProxyMode.Global); });\n        }\n\n        private void PACModeItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleMode(ProxyMode.Pac); });\n        }\n\n        private void RuleBypassLanItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.BypassLan); });\n        }\n\n        private void RuleBypassChinaItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.BypassLanAndChina); });\n        }\n\n        private void RuleBypassNotChinaItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.BypassLanAndNotChina); });\n        }\n\n        private void RuleUserItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.UserCustom); });\n        }\n\n        private void RuleBypassDisableItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.Disable); });\n        }\n\n        private void SelectRandomItem_Click(object sender, RoutedEventArgs e)\n        {\n            SelectRandomItem.IsChecked = !SelectRandomItem.IsChecked;\n            if (SelectRandomItem.IsChecked)\n            {\n                Task.Run(() => { controller.ToggleSelectRandom(true); });\n            }\n            else\n            {\n                Task.Run(() => { controller.ToggleSelectRandom(false); });\n            }\n        }\n\n        private void AutoCheckUpdateItem_Click(object sender, RoutedEventArgs e)\n        {\n            AutoCheckUpdateItem.IsChecked = !AutoCheckUpdateItem.IsChecked;\n            controller.ToggleSelectAutoCheckUpdate(AutoCheckUpdateItem.IsChecked);\n        }\n\n        private void AllowPreRelease_Click(object sender, RoutedEventArgs e)\n        {\n            AllowPreReleaseItem.IsChecked = !AllowPreReleaseItem.IsChecked;\n            controller.ToggleSelectAllowPreRelease(AllowPreReleaseItem.IsChecked);\n        }\n\n        private void SelectSameHostForSameTargetItem_Click(object sender, RoutedEventArgs e)\n        {\n            sameHostForSameTargetItem.IsChecked = !sameHostForSameTargetItem.IsChecked;\n            if (sameHostForSameTargetItem.IsChecked)\n            {\n                Task.Run(() => { controller.ToggleSameHostForSameTargetRandom(true); });\n            }\n            else\n            {\n                Task.Run(() => { controller.ToggleSameHostForSameTargetRandom(false); });\n            }\n        }\n\n        private void CopyPacUrlItem_Click(object sender, RoutedEventArgs e)\n        {\n            controller.CopyPacUrl();\n        }\n\n        private void EditPACFileItem_Click(object sender, RoutedEventArgs e)\n        {\n            controller.TouchPACFile();\n        }\n\n        private void UpdatePACFromGFWListItem_Click(object sender, RoutedEventArgs e)\n        {\n            controller.UpdatePACFromGFWList();\n        }\n\n        private void UpdatePACFromLanIPListItem_Click(object sender, RoutedEventArgs e)\n        {\n            controller.UpdatePACFromOnlinePac(@\"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_lanip.pac\");\n        }\n\n        private void UpdatePACFromCNWhiteListItem_Click(object sender, RoutedEventArgs e)\n        {\n            //域名白名单\n            controller.UpdatePACFromOnlinePac(@\"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white.pac\");\n        }\n\n        private void UpdatePACFromCNOnlyListItem_Click(object sender, RoutedEventArgs e)\n        {\n            //回国\n            controller.UpdatePACFromOnlinePac(@\"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white_r.pac\");\n        }\n\n        private void UpdatePACFromCnWhiteListIpItem_Click(object sender, RoutedEventArgs e)\n        {\n            //域名白名单+国内IP\n            controller.UpdatePACFromOnlinePac(@\"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_cnall.pac\");\n        }\n\n        private void UpdatePACFromChnIpItem_Click(object sender, RoutedEventArgs e)\n        {\n            //国内IP\n            controller.UpdatePACFromOnlinePac(@\"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_cnip.pac\");\n        }\n\n        private void EditUserRuleFileForGFWListItem_Click(object sender, RoutedEventArgs e)\n        {\n            controller.TouchUserRuleFile();\n        }\n\n        private void AServerItem_Click(object sender, EventArgs e)\n        {\n            var item = (MenuItem)sender;\n            var index = (int)item.Tag;\n            Task.Run(() =>\n            {\n                controller.DisconnectAllConnections(true);\n                controller.SelectServerIndex(index);\n            });\n        }\n\n        private void CheckUpdate_Click(object sender, RoutedEventArgs e)\n        {\n            updateChecker.Check(Global.GuiConfig, true);\n        }\n\n        private void CheckNodeUpdate_Click(object sender, RoutedEventArgs e)\n        {\n            Global.UpdateSubscribeManager.CreateTask(Global.GuiConfig, Global.UpdateNodeChecker, true);\n        }\n\n        private void ShowLogItem_Click(object sender, RoutedEventArgs e)\n        {\n            ShowGlobalLogWindow();\n        }\n\n        private void ShowPortMapItem_Click(object sender, RoutedEventArgs e)\n        {\n            ShowPortMapForm();\n        }\n\n        private void ShowServerLogItem_Click(object sender, RoutedEventArgs e)\n        {\n            ShowServerLogForm();\n        }\n\n        private void SubscribeSetting_Click(object sender, RoutedEventArgs e)\n        {\n            ShowSubscribeSettingForm();\n        }\n\n        private void DisconnectCurrent_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() => { controller.DisconnectAllConnections(); });\n        }\n\n        public void ImportAddress(string text)\n        {\n            ImportSsrUrl(text);\n\n            ImportSubUrl(text);\n        }\n\n        private void ImportSsrUrl(string text)\n        {\n            if (controller.AddServerBySsUrl(text))\n            {\n                ShowConfigForm(true);\n            }\n        }\n\n        private void ImportSubUrl(string text)\n        {\n            if (controller.AddSubscribeUrl(text))\n            {\n                ShowSubscribeSettingForm();\n            }\n        }\n\n        private void ImportAddressFromClipboard_Click(object sender, RoutedEventArgs e)\n        {\n            try\n            {\n                var iData = Clipboard.GetDataObject();\n                if (iData != null && iData.GetDataPresent(DataFormats.Text))\n                {\n                    ImportAddress((string)iData.GetData(DataFormats.Text));\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        #region QRCode\n\n        private void ScanQRCodeItem_Click(object sender, RoutedEventArgs e)\n        {\n            Task.Run(() =>\n            {\n                var w = (int)SystemParameters.VirtualScreenWidth;\n                var h = (int)SystemParameters.VirtualScreenHeight;\n                var x = (int)SystemParameters.VirtualScreenLeft;\n                var y = (int)SystemParameters.VirtualScreenTop;\n                var fullImage = new Bitmap(w, h);\n                using (var g = Graphics.FromImage(fullImage))\n                {\n                    g.CopyFromScreen(x, y,\n                            0, 0,\n                            fullImage.Size,\n                            CopyPixelOperation.SourceCopy);\n                }\n\n                const int maxTry = 10;\n                for (var i = 0; i < maxTry; i++)\n                {\n                    var marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);\n                    var marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);\n                    var cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2,\n                            fullImage.Height - marginTop * 2);\n                    var target = new Bitmap(w, h);\n\n                    var imageScale = w / (double)cropRect.Width;\n                    using (var g = Graphics.FromImage(target))\n                    {\n                        g.DrawImage(fullImage,\n                        new Rectangle(0, 0, target.Width, target.Height),\n                                cropRect,\n                                GraphicsUnit.Pixel);\n                    }\n\n                    var result = QrCodeUtils.ScanBitmap(target);\n                    if (result != null)\n                    {\n                        var success = controller.AddServerBySsUrl(result.Text);\n                        var successSub = controller.AddSubscribeUrl(result.Text);\n                        Application.Current.Dispatcher?.InvokeAsync(() =>\n                        {\n                            var splash = new QRCodeSplashWindow();\n                            if (successSub)\n                            {\n                                splash.Closed += Splash_Closed0;\n                            }\n                            if (success)\n                            {\n                                splash.Closed += Splash_Closed;\n                            }\n                            if (!(successSub || success))\n                            {\n                                _urlToOpen = result.Text;\n                                splash.Closed += Splash_Closed2;\n                            }\n\n                            double minX = int.MaxValue, minY = int.MaxValue, maxX = 0, maxY = 0;\n                            foreach (var point in result.ResultPoints)\n                            {\n                                minX = Math.Min(minX, point.X);\n                                minY = Math.Min(minY, point.Y);\n                                maxX = Math.Max(maxX, point.X);\n                                maxY = Math.Max(maxY, point.Y);\n                            }\n\n                            minX /= imageScale;\n                            minY /= imageScale;\n                            maxX /= imageScale;\n                            maxY /= imageScale;\n                            // make it 20% larger\n                            var margin = (maxX - minX) * 0.20f;\n                            minX += -margin + marginLeft;\n                            maxX += margin + marginLeft;\n                            minY += -margin + marginTop;\n                            maxY += margin + marginTop;\n                            splash.Left = x;\n                            splash.Top = y;\n                            splash.TargetRect = new Rectangle((int)minX, (int)minY, (int)maxX - (int)minX,\n                                    (int)maxY - (int)minY);\n                            splash.Width = fullImage.Width;\n                            splash.Height = fullImage.Height;\n                            fullImage.Dispose();\n                            splash.Show();\n                        });\n                        return;\n                    }\n                }\n\n                MessageBox.Show(I18NUtil.GetAppStringValue(@\"QrCodeNotFound\"));\n            });\n        }\n\n        private void Splash_Closed(object sender, EventArgs e)\n        {\n            ShowConfigForm(true);\n        }\n\n        private void Splash_Closed0(object sender, EventArgs e)\n        {\n            ShowSubscribeSettingForm();\n        }\n\n        private void ShowUrlFromQrCode()\n        {\n            var dlg = new ShowTextWindow(_urlToOpen);\n            dlg.Show();\n            dlg.Activate();\n            dlg.BringToFront();\n        }\n\n        private void Splash_Closed2(object sender, EventArgs e)\n        {\n            ShowUrlFromQrCode();\n        }\n\n        private void ShowUrlFromQrCode(object sender, RoutedEventArgs e)\n        {\n            ShowUrlFromQrCode();\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/HostDaemon.cs",
    "content": "using Shadowsocks.Model;\nusing System;\nusing System.IO;\nusing System.Threading.Tasks;\n\nnamespace Shadowsocks.Controller.Service\n{\n    public class HostDaemon\n    {\n        private FileSystemWatcher _userRuleWatcher;\n        private FileSystemWatcher _chnIpWatcher;\n\n        public event EventHandler UserRuleChanged;\n        public event EventHandler ChnIpChanged;\n\n        public HostDaemon()\n        {\n            WatchChnIp();\n            WatchUserRule();\n        }\n\n        private void WatchChnIp()\n        {\n            _chnIpWatcher?.Dispose();\n            _chnIpWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory())\n            {\n                NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,\n                Filter = IPRangeSet.ChnFilename\n            };\n            _chnIpWatcher.Changed += ChnIpWatcher_Changed;\n            _chnIpWatcher.Created += ChnIpWatcher_Changed;\n            _chnIpWatcher.Deleted += ChnIpWatcher_Changed;\n            _chnIpWatcher.Renamed += ChnIpWatcher_Changed;\n            _chnIpWatcher.EnableRaisingEvents = true;\n        }\n\n        private void WatchUserRule()\n        {\n            _userRuleWatcher?.Dispose();\n            _userRuleWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory())\n            {\n                NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,\n                Filter = HostMap.UserRule\n            };\n            _userRuleWatcher.Changed += UserRuleWatcher_Changed;\n            _userRuleWatcher.Created += UserRuleWatcher_Changed;\n            _userRuleWatcher.Deleted += UserRuleWatcher_Changed;\n            _userRuleWatcher.Renamed += UserRuleWatcher_Changed;\n            _userRuleWatcher.EnableRaisingEvents = true;\n        }\n\n        private void UserRuleWatcher_Changed(object sender, FileSystemEventArgs e)\n        {\n            if (UserRuleChanged == null)\n            {\n                return;\n            }\n\n            try\n            {\n                ((FileSystemWatcher)sender).EnableRaisingEvents = false;\n                Logging.Info($@\"Detected: user rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}.\");\n                Task.Delay(10).ContinueWith(task => UserRuleChanged(this, EventArgs.Empty));\n            }\n            finally\n            {\n                ((FileSystemWatcher)sender).EnableRaisingEvents = true;\n            }\n        }\n\n        private void ChnIpWatcher_Changed(object sender, FileSystemEventArgs e)\n        {\n            if (ChnIpChanged == null)\n            {\n                return;\n            }\n\n            try\n            {\n                ((FileSystemWatcher)sender).EnableRaisingEvents = false;\n                Logging.Info($@\"Detected: '{e.Name}' was {e.ChangeType.ToString().ToLower()}.\");\n                Task.Delay(10).ContinueWith(task => ChnIpChanged(this, EventArgs.Empty));\n            }\n            finally\n            {\n                ((FileSystemWatcher)sender).EnableRaisingEvents = true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/HostMap.cs",
    "content": "using Shadowsocks.Model;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Net;\n\nnamespace Shadowsocks.Controller.Service\n{\n    public static class HostMap\n    {\n        private static readonly Dictionary<string, HostNode> Root = new();\n        private static IPSegment _ips;\n\n        public const string UserRule = @\"user.rule\";\n\n        static HostMap()\n        {\n            Clear();\n        }\n\n        private static void Clear()\n        {\n            Root.Clear();\n            _ips = new IPSegment(@\"remoteproxy\");\n        }\n\n        public static void Reload()\n        {\n            Clear();\n            LoadHostFile();\n        }\n\n        private static void AddHost(string host, string addr)\n        {\n            if (IPAddress.TryParse(host, out _))\n            {\n                var addr_parts = addr.Split(new[] { ' ', '\\t' }, 2, StringSplitOptions.RemoveEmptyEntries);\n                if (addr_parts.Length >= 2)\n                {\n                    _ips.insert(new IPAddressCmp(host), new IPAddressCmp(addr_parts[0]), addr_parts[1]);\n                    return;\n                }\n            }\n\n            var parts = host.Split('.');\n            var node = Root;\n            var include_sub = false;\n            var end = 0;\n            if (parts[0].Length == 0)\n            {\n                end = 1;\n                include_sub = true;\n            }\n            for (var i = parts.Length - 1; i > end; --i)\n            {\n                if (!node.ContainsKey(parts[i]))\n                {\n                    node[parts[i]] = new HostNode();\n                }\n                if (node[parts[i]].SubNode == null)\n                {\n                    node[parts[i]].SubNode = new Dictionary<string, HostNode>();\n                }\n                node = node[parts[i]].SubNode;\n            }\n            node[parts[end]] = new HostNode(include_sub, addr);\n        }\n\n        public static bool GetHost(string host, out string addr)\n        {\n            var parts = host.Split('.');\n            var node = Root;\n            addr = null;\n            for (var i = parts.Length - 1; i >= 0; --i)\n            {\n                if (!node.ContainsKey(parts[i]))\n                {\n                    return false;\n                }\n                if (node[parts[i]].Addr.Length > 0 || node[parts[i]].IncludeSub)\n                {\n                    addr = node[parts[i]].Addr;\n                    return true;\n                }\n                if (node.ContainsKey(\"*\"))\n                {\n                    addr = node[\"*\"].Addr;\n                    return true;\n                }\n                if (node[parts[i]].SubNode == null)\n                {\n                    return false;\n                }\n                node = node[parts[i]].SubNode;\n            }\n            return false;\n        }\n\n        public static bool GetIP(IPAddress ip, out string addr)\n        {\n            var host = ip.ToString();\n            addr = _ips.Get(new IPAddressCmp(host)) as string;\n            return addr != null;\n        }\n\n        private static void LoadHostFile()\n        {\n            if (File.Exists(UserRule))\n            {\n                try\n                {\n                    foreach (var line in File.ReadLines(UserRule))\n                    {\n                        if (line.Length > 0 && line.StartsWith(@\"#\"))\n                        {\n                            continue;\n                        }\n\n                        var parts = line.Split(new[] { ' ', '\\t' }, 2, StringSplitOptions.RemoveEmptyEntries);\n                        if (parts.Length < 2)\n                        {\n                            continue;\n                        }\n\n                        AddHost(parts[0], parts[1]);\n                    }\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/HttpPortForwarder.cs",
    "content": "using Shadowsocks.Model;\nusing Shadowsocks.Proxy;\nusing Shadowsocks.Util.NetUtils;\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\n\nnamespace Shadowsocks.Controller.Service\n{\n    internal class HttpPortForwarder : Listener.Service\n    {\n        private readonly int _targetPort;\n        private readonly Configuration _config;\n\n        public HttpPortForwarder(int targetPort, Configuration config)\n        {\n            _targetPort = targetPort;\n            _config = config;\n        }\n\n        public override bool Handle(byte[] firstPacket, int length, Socket socket)\n        {\n            if (socket.ProtocolType != ProtocolType.Tcp)\n            {\n                return false;\n            }\n            new Handler().Start(_config, firstPacket, length, socket, _targetPort);\n            return true;\n        }\n\n        private class Handler\n        {\n            private byte[] _firstPacket;\n            private int _firstPacketLength;\n            private int _targetPort;\n            private Socket _local;\n            private WrappedSocket _remote;\n            private bool _closed;\n            private bool _localShutdown;\n            private bool _remoteShutdown;\n            private Configuration _config;\n\n            private HttpParser _httpProxyState;\n\n            private const int RecvSize = 4096;\n            // remote receive buffer\n            private readonly byte[] _remoteRecvBuffer = new byte[RecvSize];\n            // connection receive buffer\n            private readonly byte[] _connetionRecvBuffer = new byte[RecvSize];\n\n            public void Start(Configuration config, byte[] firstPacket, int length, Socket socket, int targetPort)\n            {\n                _config = config;\n                _firstPacket = firstPacket;\n                _firstPacketLength = length;\n                _local = socket;\n                _targetPort = targetPort;\n                if ((_config.AuthUser ?? string.Empty).Length == 0\n                || IPSubnet.IsLoopBack(((IPEndPoint)_local.RemoteEndPoint).Address))\n                {\n                    Connect();\n                }\n                else\n                {\n                    RspHttpHandshakeReceive();\n                }\n            }\n\n            private void RspHttpHandshakeReceive()\n            {\n                if (_httpProxyState == null)\n                {\n                    _httpProxyState = new HttpParser(true);\n                }\n                _httpProxyState.httpAuthUser = _config.AuthUser;\n                _httpProxyState.httpAuthPass = _config.AuthPass;\n                var err = _httpProxyState.HandshakeReceive(_firstPacket, _firstPacketLength, out _);\n                if (err == 1)\n                {\n                    _local.BeginReceive(_connetionRecvBuffer, 0, _firstPacket.Length, 0,\n                        HttpHandshakeRecv, null);\n                }\n                else if (err == 2)\n                {\n                    var dataSend = HttpParser.Http407();\n                    var httpData = System.Text.Encoding.UTF8.GetBytes(dataSend);\n                    _local.BeginSend(httpData, 0, httpData.Length, 0, HttpHandshakeAuthEndSend, null);\n                }\n                else if (err == 3)\n                {\n                    Connect();\n                }\n                else if (err == 4)\n                {\n                    Connect();\n                }\n                else if (err == 0)\n                {\n                    var dataSend = HttpParser.Http200();\n                    var httpData = System.Text.Encoding.UTF8.GetBytes(dataSend);\n                    _local.BeginSend(httpData, 0, httpData.Length, 0, StartConnect, null);\n                }\n                else if (err == 500)\n                {\n                    var dataSend = HttpParser.Http500();\n                    var httpData = System.Text.Encoding.UTF8.GetBytes(dataSend);\n                    _local.BeginSend(httpData, 0, httpData.Length, 0, HttpHandshakeAuthEndSend, null);\n                }\n            }\n\n            private void HttpHandshakeRecv(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    var bytesRead = _local.EndReceive(ar);\n                    if (bytesRead > 0)\n                    {\n                        Array.Copy(_connetionRecvBuffer, _firstPacket, bytesRead);\n                        _firstPacketLength = bytesRead;\n                        RspHttpHandshakeReceive();\n                    }\n                    else\n                    {\n                        Console.WriteLine(@\"failed to recv data in HttpHandshakeRecv\");\n                        Close();\n                    }\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void HttpHandshakeAuthEndSend(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    _local.EndSend(ar);\n                    _local.BeginReceive(_connetionRecvBuffer, 0, _firstPacket.Length, 0,\n                        HttpHandshakeRecv, null);\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void StartConnect(IAsyncResult ar)\n            {\n                try\n                {\n                    _local.EndSend(ar);\n                    Connect();\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n\n            }\n\n            private void Connect()\n            {\n                try\n                {\n                    var ipAddress = Global.OSSupportsLocalIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback;\n                    var remoteEp = new IPEndPoint(ipAddress, _targetPort);\n\n                    _remote = new WrappedSocket();\n\n                    // Connect to the remote endpoint.\n                    _remote.BeginConnect(remoteEp, ConnectCallback, null);\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void ConnectCallback(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    _remote.EndConnect(ar);\n                    _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);\n                    HandshakeReceive();\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void HandshakeReceive()\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    _remote.BeginSend(_firstPacket, 0, _firstPacketLength, SocketFlags.None, StartPipe, null);\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void StartPipe(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    _remote.EndSend(ar);\n                    _remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null);\n                    _local.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, PipeConnectionReceiveCallback, null);\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void PipeRemoteReceiveCallback(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    var bytesRead = _remote.EndReceive(ar);\n\n                    if (bytesRead > 0)\n                    {\n                        _local.BeginSend(_remoteRecvBuffer, 0, bytesRead, 0, PipeConnectionSendCallback, null);\n                    }\n                    else\n                    {\n                        _local.Shutdown(SocketShutdown.Send);\n                        _localShutdown = true;\n                        CheckClose();\n                    }\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void PipeConnectionReceiveCallback(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    var bytesRead = _local.EndReceive(ar);\n\n                    if (bytesRead > 0)\n                    {\n                        _remote.BeginSend(_connetionRecvBuffer, 0, bytesRead, SocketFlags.None, PipeRemoteSendCallback, null);\n                    }\n                    else\n                    {\n                        _remote.Shutdown(SocketShutdown.Send);\n                        _remoteShutdown = true;\n                        CheckClose();\n                    }\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void PipeRemoteSendCallback(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    _remote.EndSend(ar);\n                    _local.BeginReceive(_connetionRecvBuffer, 0, RecvSize, 0,\n                        PipeConnectionReceiveCallback, null);\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void PipeConnectionSendCallback(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    _local.EndSend(ar);\n                    _remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, 0,\n                        PipeRemoteReceiveCallback, null);\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void CheckClose()\n            {\n                if (_localShutdown && _remoteShutdown)\n                {\n                    Close();\n                }\n            }\n\n            private void Close()\n            {\n                lock (this)\n                {\n                    if (_closed)\n                    {\n                        return;\n                    }\n                    _closed = true;\n                }\n                if (_local != null)\n                {\n                    try\n                    {\n                        _local.Shutdown(SocketShutdown.Both);\n                        _local.Close();\n                    }\n                    catch (Exception e)\n                    {\n                        Logging.LogUsefulException(e);\n                    }\n                }\n                if (_remote != null)\n                {\n                    try\n                    {\n                        _remote.Shutdown(SocketShutdown.Both);\n                        _remote.Dispose();\n                    }\n                    catch (SocketException e)\n                    {\n                        Logging.LogUsefulException(e);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/HttpProxyRunner.cs",
    "content": "using HttpProxy;\nusing Microsoft.VisualStudio.Threading;\nusing Shadowsocks.Model;\nusing Socks5.Models;\nusing System.Net;\n\n#nullable enable\n\nnamespace Shadowsocks.Controller.Service\n{\n    public class HttpProxyRunner\n    {\n        private HttpSocks5Service? _service;\n\n        public int RunningPort { get; private set; }\n\n        public void Start(Configuration configuration)\n        {\n            if (_service is not null)\n            {\n                return;\n            }\n\n            var ip = configuration.ShareOverLan ? Global.IpAny : Global.IpLocal;\n            var ipe = new IPEndPoint(ip, 0);\n            var option = new Socks5CreateOption\n            {\n                Address = Global.IpLocal,\n                Port = (ushort)configuration.LocalPort,\n                UsernamePassword = new UsernamePassword\n                {\n                    UserName = configuration.AuthUser,\n                    Password = configuration.AuthPass\n                }\n            };\n            _service = new HttpSocks5Service(ipe, new HttpToSocks5(), option);\n            _service.StartAsync().Forget();\n            RunningPort = ((IPEndPoint)_service.TcpListener.LocalEndpoint).Port;\n        }\n\n        public void Stop()\n        {\n            if (_service is null)\n            {\n                return;\n            }\n\n            _service.Stop();\n            _service = null;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/Listener.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Util;\nusing Shadowsocks.Util.NetUtils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Net.NetworkInformation;\nusing System.Net.Sockets;\n\nnamespace Shadowsocks.Controller.Service\n{\n    public class Listener\n    {\n        public interface IService\n        {\n            bool Handle(byte[] firstPacket, int length, Socket socket);\n\n            void Stop();\n        }\n\n        public abstract class Service : IService\n        {\n            public abstract bool Handle(byte[] firstPacket, int length, Socket socket);\n\n            public virtual void Stop() { }\n        }\n\n        private Configuration _config;\n        private bool _shareOverLan;\n        private string _authUser;\n        private Socket _socket;\n        private Socket _socketV6;\n        private bool _stop;\n        private readonly List<IService> _services;\n\n        public Listener(List<IService> services)\n        {\n            _services = services;\n            _stop = false;\n        }\n\n        private static bool CheckIfPortInUse(int port)\n        {\n            var ipProperties = IPGlobalProperties.GetIPGlobalProperties();\n            return ipProperties.GetActiveTcpListeners().Any(endPoint => endPoint.Port == port);\n        }\n\n        public void Start(Configuration config, int port)\n        {\n            _config = config;\n            _shareOverLan = config.ShareOverLan;\n            _authUser = config.AuthUser;\n\n            var localPort = port == 0 ? _config.LocalPort : port;\n            if (CheckIfPortInUse(localPort))\n            {\n                throw new Exception(string.Format(I18NUtil.GetAppStringValue(@\"PortInUse\"), localPort));\n            }\n\n            try\n            {\n                //TODO:UDP socket\n                // Create a TCP/IP socket.\n                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);\n                _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);\n                var localEndPoint = new IPEndPoint(_shareOverLan ? IPAddress.Any : IPAddress.Loopback, localPort);\n                // Bind the socket to the local endpoint and listen for incoming connections.\n                _socket.Bind(localEndPoint);\n                _socket.Listen(1024);\n\n                // IPv6\n                if (Global.OSSupportsLocalIPv6)\n                {\n                    try\n                    {\n                        _socketV6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);\n                        _socketV6.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);\n                    }\n                    catch\n                    {\n                        _socketV6 = null;\n                    }\n                    var localEndPointV6 = new IPEndPoint(_shareOverLan ? IPAddress.IPv6Any : IPAddress.IPv6Loopback, localPort);\n                    if (_socketV6 != null)\n                    {\n                        _socketV6.Bind(localEndPointV6);\n                        _socketV6.Listen(1024);\n                    }\n                }\n                else\n                {\n                    _socketV6 = null;\n                }\n\n                // Start an asynchronous socket to listen for connections.\n                Console.WriteLine($@\"ShadowsocksR started on port {localPort}\");\n                _socket.BeginAccept(AcceptCallback, _socket);\n                _socketV6?.BeginAccept(AcceptCallback, _socketV6);\n            }\n            catch (SocketException e)\n            {\n                Logging.LogUsefulException(e);\n                if (_socket != null)\n                {\n                    _socket.Close();\n                    _socket = null;\n                }\n                if (_socketV6 != null)\n                {\n                    _socketV6.Close();\n                    _socketV6 = null;\n                }\n                throw;\n            }\n        }\n\n        public void Stop()\n        {\n            _stop = true;\n\n            if (_socket != null)\n            {\n                _socket.Close();\n                _socket = null;\n            }\n            if (_socketV6 != null)\n            {\n                _socketV6.Close();\n                _socketV6 = null;\n            }\n\n            _services.ForEach(s => s.Stop());\n        }\n\n        private void AcceptCallback(IAsyncResult ar)\n        {\n            if (_stop)\n            {\n                return;\n            }\n            var listener = (Socket)ar.AsyncState;\n            try\n            {\n                var conn = listener.EndAccept(ar);\n\n                var localPort = ((IPEndPoint)conn.LocalEndPoint).Port;\n\n                if ((_authUser ?? string.Empty).Length == 0 && !IPSubnet.IsLan(conn)\n                    && !(_config.PortMapCache.ContainsKey(localPort)\n                    || _config.PortMapCache[localPort].type == PortMapType.Forward))\n                {\n                    conn.Shutdown(SocketShutdown.Both);\n                    conn.Close();\n                }\n                else\n                {\n                    var buf = new byte[4096];\n                    object[] state = {\n                        conn,\n                        buf\n                    };\n\n                    if (_config.PortMapCache.TryGetValue(localPort, out var portMap)\n                    && portMap.type == PortMapType.Forward)\n                    {\n                        if (_services.Any(service => service.Handle(buf, 0, conn)))\n                        {\n                            return;\n                        }\n\n                        // no service found for this\n                        // shouldn't happen\n                        conn.Shutdown(SocketShutdown.Both);\n                        conn.Close();\n                    }\n                    else\n                    {\n                        conn.BeginReceive(buf, 0, buf.Length, 0, ReceiveCallback, state);\n                    }\n                }\n            }\n            catch (ObjectDisposedException)\n            {\n            }\n            catch (Exception e)\n            {\n                Console.WriteLine(e);\n            }\n            finally\n            {\n                try\n                {\n                    listener.BeginAccept(AcceptCallback, listener);\n                }\n                catch (ObjectDisposedException)\n                {\n                    // do nothing\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                }\n            }\n        }\n\n        private void ReceiveCallback(IAsyncResult ar)\n        {\n            var state = (object[])ar.AsyncState;\n\n            var conn = (Socket)state[0];\n            var buf = (byte[])state[1];\n            try\n            {\n                var bytesRead = conn.EndReceive(ar);\n                if (bytesRead > 0 && _services.Any(service => service.Handle(buf, bytesRead, conn)))\n                {\n                    return;\n                }\n\n                // no service found for this\n                // shouldn't happen\n                conn.Shutdown(SocketShutdown.Both);\n                conn.Close();\n            }\n            catch (Exception e)\n            {\n                Console.WriteLine(e);\n                conn.Shutdown(SocketShutdown.Both);\n                conn.Close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/Local.cs",
    "content": "using Shadowsocks.Model;\nusing Shadowsocks.Model.Transfer;\nusing Shadowsocks.Proxy;\nusing System.Diagnostics;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading.Tasks;\n\nnamespace Shadowsocks.Controller.Service\n{\n    public class Local : Listener.Service\n    {\n        private readonly Configuration _config;\n        private readonly ServerTransferTotal _transfer;\n        private readonly IPRangeSet _ipRange;\n\n        public Local(Configuration config, ServerTransferTotal transfer, IPRangeSet IPRange)\n        {\n            _config = config;\n            _transfer = transfer;\n            _ipRange = IPRange;\n        }\n\n        private static bool Accept(byte[] firstPacket, int length)\n        {\n            if (length < 2)\n            {\n                return false;\n            }\n            if (firstPacket[0] is 5 or 4)\n            {\n                return true;\n            }\n            Debug.WriteLine(System.Text.Encoding.UTF8.GetString(firstPacket));\n            if (length > 8\n                && firstPacket[0] == 'C'\n                && firstPacket[1] == 'O'\n                && firstPacket[2] == 'N'\n                && firstPacket[3] == 'N'\n                && firstPacket[4] == 'E'\n                && firstPacket[5] == 'C'\n                && firstPacket[6] == 'T'\n                && firstPacket[7] == ' ')\n            {\n                return true;\n            }\n            return false;\n        }\n\n        public override bool Handle(byte[] firstPacket, int length, Socket socket)\n        {\n            if (!_config.PortMapCache.ContainsKey(((IPEndPoint)socket.LocalEndPoint).Port) && !Accept(firstPacket, length))\n            {\n                return false;\n            }\n            Task.Run(() =>\n            {\n                var unused = new ProxyAuthHandler(_config, _transfer, _ipRange, firstPacket, length, socket);\n            });\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/PACDaemon.cs",
    "content": "using Shadowsocks.Properties;\nusing System;\nusing System.IO;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Shadowsocks.Controller.Service\n{\n    /// <summary>\n    /// Processing the PAC file content\n    /// </summary>\n    public class PACDaemon\n    {\n        public const string PAC_FILE = @\"pac.txt\";\n        public const string USER_RULE_FILE = @\"user-rule.txt\";\n        public const string USER_ABP_FILE = @\"abp.txt\";\n\n        FileSystemWatcher PACFileWatcher;\n        FileSystemWatcher UserRuleFileWatcher;\n\n        public event EventHandler PACFileChanged;\n        public event EventHandler UserRuleFileChanged;\n\n        public PACDaemon()\n        {\n            TouchPACFile();\n            TouchUserRuleFile();\n\n            WatchPacFile();\n            WatchUserRuleFile();\n        }\n\n        public string TouchPACFile()\n        {\n            if (!File.Exists(PAC_FILE))\n            {\n                File.WriteAllText(PAC_FILE, Resources.proxy_pac);\n            }\n            return PAC_FILE;\n        }\n\n        internal string TouchUserRuleFile()\n        {\n            if (!File.Exists(USER_RULE_FILE))\n            {\n                File.WriteAllText(USER_RULE_FILE, Resources.user_rule);\n            }\n            return USER_RULE_FILE;\n        }\n\n        internal string GetPACContent()\n        {\n            if (File.Exists(PAC_FILE))\n            {\n                return File.ReadAllText(PAC_FILE, Encoding.UTF8);\n            }\n            return Resources.proxy_pac;\n        }\n\n        private void WatchPacFile()\n        {\n            PACFileWatcher?.Dispose();\n            PACFileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory())\n            {\n                NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,\n                Filter = PAC_FILE\n            };\n            PACFileWatcher.Changed += PACFileWatcher_Changed;\n            PACFileWatcher.Created += PACFileWatcher_Changed;\n            PACFileWatcher.Deleted += PACFileWatcher_Changed;\n            PACFileWatcher.Renamed += PACFileWatcher_Changed;\n            PACFileWatcher.EnableRaisingEvents = true;\n        }\n\n        private void WatchUserRuleFile()\n        {\n            UserRuleFileWatcher?.Dispose();\n            UserRuleFileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory())\n            {\n                NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,\n                Filter = USER_RULE_FILE\n            };\n            UserRuleFileWatcher.Changed += UserRuleFileWatcher_Changed;\n            UserRuleFileWatcher.Created += UserRuleFileWatcher_Changed;\n            UserRuleFileWatcher.Deleted += UserRuleFileWatcher_Changed;\n            UserRuleFileWatcher.Renamed += UserRuleFileWatcher_Changed;\n            UserRuleFileWatcher.EnableRaisingEvents = true;\n        }\n\n        #region FileSystemWatcher.OnChanged()\n        // FileSystemWatcher Changed event is raised twice\n        // http://stackoverflow.com/questions/1764809/filesystemwatcher-changed-event-is-raised-twice\n        // Add a short delay to avoid raise event twice in a short period\n        private void PACFileWatcher_Changed(object sender, FileSystemEventArgs e)\n        {\n            if (PACFileChanged == null)\n            {\n                return;\n            }\n\n            try\n            {\n                ((FileSystemWatcher)sender).EnableRaisingEvents = false;\n                Logging.Info($@\"Detected: PAC file '{e.Name}' was {e.ChangeType.ToString().ToLower()}.\");\n                Task.Delay(10).ContinueWith(task => { PACFileChanged(this, EventArgs.Empty); });\n            }\n            finally\n            {\n                ((FileSystemWatcher)sender).EnableRaisingEvents = true;\n            }\n        }\n\n        private void UserRuleFileWatcher_Changed(object sender, FileSystemEventArgs e)\n        {\n            if (UserRuleFileChanged == null)\n            {\n                return;\n            }\n\n            try\n            {\n                ((FileSystemWatcher)sender).EnableRaisingEvents = false;\n                Logging.Info($@\"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}.\");\n                Task.Delay(10).ContinueWith(task => { UserRuleFileChanged(this, EventArgs.Empty); });\n            }\n            finally\n            {\n                ((FileSystemWatcher)sender).EnableRaisingEvents = true;\n            }\n        }\n        #endregion\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/PACServer.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Util;\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\n\nnamespace Shadowsocks.Controller.Service\n{\n    public class PACServer : Listener.Service\n    {\n        private const string ResourceName = @\"pac\";\n\n        public static string gfwlist_FILE = @\"gfwlist.txt\";\n\n        public static string WHITELIST_FILE = @\"whitelist.txt\";\n\n        public static string USER_WHITELIST_TEMPLATE_FILE = @\"user_whitelist_temp.txt\";\n\n        public string PacUrl { get; private set; } = string.Empty;\n\n        private Configuration _config;\n        private readonly PACDaemon _pacDaemon;\n\n        public PACServer(PACDaemon pacDaemon)\n        {\n            _pacDaemon = pacDaemon;\n        }\n\n        public void UpdatePacUrl(Configuration config)\n        {\n            _config = config;\n            //Lots of software do not support ipv6 pac url yet\n            PacUrl = $@\"http://{IPAddress.Loopback}:{config.LocalPort}/{ResourceName}?t={DateTime.Now:yyyyMMddHHmmssffff}\";\n        }\n\n        public override bool Handle(byte[] firstPacket, int length, Socket socket)\n        {\n            if (socket.ProtocolType != ProtocolType.Tcp)\n            {\n                return false;\n            }\n            try\n            {\n                var request = Encoding.UTF8.GetString(firstPacket, 0, length);\n                var lines = request.GetLines();\n                bool hostMatch = false, pathMatch = false;\n                var socksType = 0;\n                string proxy = null;\n\n                foreach (var line in lines)\n                {\n                    var kv = line.Split(new[] { ':' }, 2);\n                    switch (kv.Length)\n                    {\n                        case 2:\n                        {\n                            if (kv[0] == @\"Host\")\n                            {\n                                if (kv[1].Trim() == ((IPEndPoint)socket.LocalEndPoint).ToString())\n                                {\n                                    hostMatch = true;\n                                }\n                            }\n                            break;\n                        }\n                        case 1:\n                        {\n                            if (line.IndexOf($\" /{ResourceName}?\", StringComparison.Ordinal) > 0 && line.IndexOf(@\"GET\", StringComparison.Ordinal) == 0)\n                            {\n                                var url = line.Substring(line.IndexOf(\" \", StringComparison.Ordinal) + 1);\n                                url = url.Substring(0, url.IndexOf(\" \", StringComparison.Ordinal));\n                                pathMatch = true;\n                                var portPos = url.IndexOf(\"port=\", StringComparison.Ordinal);\n                                if (portPos > 0)\n                                {\n                                    var port = url.Substring(portPos + 5);\n                                    if (port.IndexOf(\"&\", StringComparison.Ordinal) >= 0)\n                                    {\n                                        port = port.Substring(0, port.IndexOf(\"&\", StringComparison.Ordinal));\n                                    }\n\n                                    var ipPos = url.IndexOf(\"ip=\", StringComparison.Ordinal);\n                                    if (ipPos > 0)\n                                    {\n                                        proxy = url.Substring(ipPos + 3);\n                                        if (proxy.IndexOf(\"&\", StringComparison.Ordinal) >= 0)\n                                        {\n                                            proxy = proxy.Substring(0, proxy.IndexOf(\"&\", StringComparison.Ordinal));\n                                        }\n\n                                        proxy += $@\":{port};\";\n                                    }\n                                    else\n                                    {\n                                        proxy = $@\"127.0.0.1:{port};\";\n                                    }\n                                }\n\n                                if (url.IndexOf(\"type=socks4\", StringComparison.Ordinal) > 0 ||\n                                    url.IndexOf(\"type=s4\", StringComparison.Ordinal) > 0)\n                                {\n                                    socksType = 4;\n                                }\n\n                                if (url.IndexOf(\"type=socks5\", StringComparison.Ordinal) > 0 ||\n                                    url.IndexOf(\"type=s5\", StringComparison.Ordinal) > 0)\n                                {\n                                    socksType = 5;\n                                }\n                            }\n                            break;\n                        }\n                    }\n                }\n                if (hostMatch && pathMatch)\n                {\n                    SendResponse(socket, socksType, proxy);\n                    return true;\n                }\n                return false;\n            }\n            catch (ArgumentException)\n            {\n                return false;\n            }\n        }\n\n        private void SendResponse(Socket socket, int socksType, string setProxy)\n        {\n            try\n            {\n                var pac = _pacDaemon.GetPACContent();\n\n                var localEndPoint = (IPEndPoint)socket.LocalEndPoint;\n\n                var proxy =\n                    setProxy == null ? GetPACAddress(localEndPoint, socksType) :\n                    socksType == 5 ? $@\"SOCKS5 {setProxy}\" :\n                    socksType == 4 ? $@\"SOCKS {setProxy}\" :\n                    $@\"PROXY {setProxy}\";\n\n                if (_config.PacDirectGoProxy && _config.ProxyEnable)\n                {\n                    if (_config.ProxyType == ProxyType.Socks5)\n                    {\n                        pac = pac.Replace(@\"__DIRECT__\", $@\"SOCKS5 {_config.ProxyHost}:{_config.ProxyPort};DIRECT;\");\n                    }\n                    else if (_config.ProxyType == ProxyType.Http)\n                    {\n                        pac = pac.Replace(@\"__DIRECT__\", $@\"PROXY {_config.ProxyHost}:{_config.ProxyPort};DIRECT;\");\n                    }\n                }\n                else\n                {\n                    pac = pac.Replace(@\"__DIRECT__\", @\"DIRECT;\");\n                }\n\n                pac = pac.Replace(@\"__PROXY__\", $@\"{proxy}DIRECT;\");\n\n                var text =\n$@\"HTTP/1.1 200 OK\nServer: {HttpRequest.UpdateChecker.Name}/{HttpRequest.UpdateChecker.Version}\nContent-Type: application/x-ns-proxy-autoconfig\nContent-Length: {Encoding.UTF8.GetBytes(pac).Length}\nConnection: Close\n\n{pac}\";\n                var response = Encoding.UTF8.GetBytes(text);\n                socket.BeginSend(response, 0, response.Length, 0, SendCallback, socket);\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                socket.Shutdown(SocketShutdown.Both);\n                socket.Close();\n            }\n        }\n\n        private static void SendCallback(IAsyncResult ar)\n        {\n            var conn = (Socket)ar.AsyncState;\n            try\n            {\n                conn.Shutdown(SocketShutdown.Both);\n                conn.Close();\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        private string GetPACAddress(IPEndPoint localEndPoint, int socksType)\n        {\n            var localhost = localEndPoint.AddressFamily == AddressFamily.InterNetworkV6\n                    ? $@\"[{localEndPoint.Address}]\"\n                    : $@\"{localEndPoint.Address}\";\n            return socksType switch\n            {\n                5 => $@\"SOCKS5 {localhost}:{_config.LocalPort};\",\n                4 => $@\"SOCKS {localhost}:{_config.LocalPort};\",\n                _ => $@\"PROXY {localhost}:{_config.LocalPort};\"\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/ProtocolResponseDetector.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Controller.Service\n{\n    internal class ProtocolResponseDetector\n    {\n        protected enum Protocol\n        {\n            Unknown = -1,\n            NotBegin = 0,\n            HTTP = 1,\n            TLS = 2,\n            SOCKS4 = 4,\n            SOCKS5 = 5\n        }\n\n        protected Protocol protocol = Protocol.NotBegin;\n        private byte[] _sendBuffer = new byte[0];\n        private byte[] _recvBuffer = new byte[0];\n\n        public bool Pass { get; set; }\n\n        public ProtocolResponseDetector()\n        {\n            Pass = false;\n        }\n\n        public void OnSend(byte[] sendData, int length)\n        {\n            if (protocol != Protocol.NotBegin)\n            {\n                return;\n            }\n\n            Array.Resize(ref _sendBuffer, _sendBuffer.Length + length);\n            Array.Copy(sendData, 0, _sendBuffer, _sendBuffer.Length - length, length);\n\n            if (_sendBuffer.Length < 2)\n            {\n                return;\n            }\n\n            var head_size = Obfs.ObfsBase.GetHeadSize(_sendBuffer, _sendBuffer.Length);\n            if (_sendBuffer.Length - head_size < 0)\n            {\n                return;\n            }\n\n            var data = new byte[_sendBuffer.Length - head_size];\n            Array.Copy(_sendBuffer, head_size, data, 0, data.Length);\n\n            if (data.Length < 2)\n            {\n                return;\n            }\n\n            if (data.Length > 8)\n            {\n                if (data[0] == 22 && data[1] == 3 && data[2] <= 3)\n                {\n                    protocol = Protocol.TLS;\n                    return;\n                }\n                if (data[0] == 'G' && data[1] == 'E' && data[2] == 'T' && data[3] == ' '\n                    || data[0] == 'P' && data[1] == 'U' && data[2] == 'T' && data[3] == ' '\n                    || data[0] == 'H' && data[1] == 'E' && data[2] == 'A' && data[3] == 'D' && data[4] == ' '\n                    || data[0] == 'P' && data[1] == 'O' && data[2] == 'S' && data[3] == 'T' && data[4] == ' '\n                    || data[0] == 'C' && data[1] == 'O' && data[2] == 'N' && data[3] == 'N' && data[4] == 'E' && data[5] == 'C' && data[6] == 'T' && data[7] == ' '\n                )\n                {\n                    protocol = Protocol.HTTP;\n                }\n            }\n            else\n            {\n                protocol = Protocol.Unknown;\n            }\n        }\n\n        public int OnRecv(byte[] recv_data, int length)\n        {\n            if (protocol is Protocol.Unknown or Protocol.NotBegin)\n            {\n                return 0;\n            }\n\n            Array.Resize(ref _recvBuffer, _recvBuffer.Length + length);\n            Array.Copy(recv_data, 0, _recvBuffer, _recvBuffer.Length - length, length);\n\n            if (_recvBuffer.Length < 2)\n            {\n                return 0;\n            }\n\n            if (protocol == Protocol.HTTP && _recvBuffer.Length > 4)\n            {\n                if (_recvBuffer[0] == 'H' && _recvBuffer[1] == 'T' && _recvBuffer[2] == 'T' && _recvBuffer[3] == 'P')\n                {\n                    Finish();\n                    return 0;\n                }\n\n                protocol = Protocol.Unknown;\n                return 1;\n                //throw new ProtocolException(\"Wrong http response\");\n            }\n\n            if (protocol == Protocol.TLS && _recvBuffer.Length > 4)\n            {\n                if (_recvBuffer[0] == 22 && _recvBuffer[1] == 3)\n                {\n                    Finish();\n                    return 0;\n                }\n\n                protocol = Protocol.Unknown;\n                return 2;\n                //throw new ProtocolException(\"Wrong tls response\");\n            }\n            return 0;\n        }\n\n        private void Finish()\n        {\n            _sendBuffer = null;\n            _recvBuffer = null;\n            protocol = Protocol.Unknown;\n            Pass = true;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/Socks5Forwarder.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Proxy;\nusing Shadowsocks.Util.NetUtils;\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Timers;\n\nnamespace Shadowsocks.Controller.Service\n{\n    class Socks5Forwarder : Listener.Service\n    {\n        private Configuration _config;\n        private IPRangeSet _IPRange;\n        const int CONNECT_DIRECT = 1;\n        const int CONNECT_LOCALPROXY = 2;\n        const int CONNECT_REMOTEPROXY = 0;\n\n        public Socks5Forwarder(Configuration config, IPRangeSet IPRange)\n        {\n            _config = config;\n            _IPRange = IPRange;\n        }\n\n        public override bool Handle(byte[] firstPacket, int length, Socket socket)\n        {\n            return Handle(firstPacket, length, socket, null);\n        }\n\n        public bool Handle(byte[] firstPacket, int length, Socket socket, string local_sendback_protocol)\n        {\n            var handle = IsHandle(firstPacket, length);\n            if (handle > 0)\n            {\n                if (_config.ProxyEnable)\n                {\n                    new Handler().Start(_config, firstPacket, socket, local_sendback_protocol, handle == 2);\n                }\n                else\n                {\n                    new Handler().Start(_config, firstPacket, socket, local_sendback_protocol, false);\n                }\n                return true;\n            }\n            return false;\n        }\n\n        private int IsHandle(byte[] firstPacket, int length)\n        {\n            if (length >= 7 && _config.ProxyRuleMode != ProxyRuleMode.Disable)\n            {\n                IPAddress ipAddress = null;\n                if (firstPacket[0] == 1)\n                {\n                    var addr = new byte[4];\n                    Array.Copy(firstPacket, 1, addr, 0, addr.Length);\n                    ipAddress = new IPAddress(addr);\n                }\n                else if (firstPacket[0] == 3)\n                {\n                    int len = firstPacket[1];\n                    var addr = new byte[len];\n                    if (length >= len + 2)\n                    {\n                        Array.Copy(firstPacket, 2, addr, 0, addr.Length);\n                        var host = Encoding.UTF8.GetString(firstPacket, 2, len);\n                        if (IPAddress.TryParse(host, out ipAddress))\n                        {\n                            //pass\n                        }\n                        else\n                        {\n                            if ((_config.ProxyRuleMode == ProxyRuleMode.BypassLanAndChina || _config.ProxyRuleMode == ProxyRuleMode.BypassLanAndNotChina) && _IPRange != null || _config.ProxyRuleMode == ProxyRuleMode.UserCustom)\n                            {\n                                if (!IPAddress.TryParse(host, out ipAddress))\n                                {\n                                    if (_config.ProxyRuleMode == ProxyRuleMode.UserCustom)\n                                    {\n                                        if (HostMap.GetHost(host, out var host_addr))\n                                        {\n                                            if (!string.IsNullOrEmpty(host_addr))\n                                            {\n                                                var lower_host_addr = host_addr.ToLower();\n                                                if (lower_host_addr.StartsWith(\"reject\")\n                                                    || lower_host_addr.StartsWith(\"direct\")\n                                                    )\n                                                {\n                                                    return CONNECT_DIRECT;\n                                                }\n\n                                                if (lower_host_addr.StartsWith(\"localproxy\"))\n                                                {\n                                                    return CONNECT_LOCALPROXY;\n                                                }\n\n                                                if (lower_host_addr.StartsWith(\"remoteproxy\"))\n                                                {\n                                                    return CONNECT_REMOTEPROXY;\n                                                }\n\n                                                if (lower_host_addr.IndexOf('.') >= 0 || lower_host_addr.IndexOf(':') >= 0)\n                                                {\n                                                    if (!IPAddress.TryParse(lower_host_addr, out ipAddress))\n                                                    {\n                                                        //\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    }\n                                    if (ipAddress == null)\n                                    {\n                                        ipAddress = DnsUtil.DnsBuffer.Get(host);\n                                    }\n                                }\n                                if (ipAddress == null)\n                                {\n                                    ipAddress = DnsUtil.QueryDns(host);\n                                    if (ipAddress != null)\n                                    {\n                                        DnsUtil.DnsBuffer.Set(host, new IPAddress(ipAddress.GetAddressBytes()));\n                                        if (host.IndexOf('.') >= 0 && IPSubnet.IsLan(ipAddress))\n                                        {\n                                            // assume that it is pollution if return LAN address\n                                            return CONNECT_REMOTEPROXY;\n                                        }\n                                    }\n                                    else\n                                    {\n                                        Logging.Log(LogLevel.Debug, \"DNS query fail: \" + host);\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n                else if (firstPacket[0] == 4)\n                {\n                    var addr = new byte[16];\n                    Array.Copy(firstPacket, 1, addr, 0, addr.Length);\n                    ipAddress = new IPAddress(addr);\n                }\n                if (ipAddress != null)\n                {\n                    if (_config.ProxyRuleMode == ProxyRuleMode.UserCustom)\n                    {\n                        if (HostMap.GetIP(ipAddress, out var host_addr))\n                        {\n                            var lower_host_addr = host_addr.ToLower();\n                            if (lower_host_addr.StartsWith(\"reject\")\n                                || lower_host_addr.StartsWith(\"direct\")\n                                )\n                            {\n                                return CONNECT_DIRECT;\n                            }\n\n                            if (lower_host_addr.StartsWith(\"localproxy\"))\n                            {\n                                return CONNECT_LOCALPROXY;\n                            }\n\n                            if (lower_host_addr.StartsWith(\"remoteproxy\"))\n                            {\n                                return CONNECT_REMOTEPROXY;\n                            }\n                        }\n                    }\n                    else\n                    {\n                        if (IPSubnet.IsLan(ipAddress))\n                        {\n                            return CONNECT_DIRECT;\n                        }\n                        if (_config.ProxyRuleMode is ProxyRuleMode.BypassLanAndChina or ProxyRuleMode.BypassLanAndNotChina && _IPRange is not null)\n                        {\n                            if (_IPRange.IsInIPRange(ipAddress))\n                            {\n                                return CONNECT_LOCALPROXY;\n                            }\n\n                            DnsUtil.DnsBuffer.Sweep();\n                        }\n                    }\n                }\n            }\n            return CONNECT_REMOTEPROXY;\n        }\n\n        private class Handler : IHandler\n        {\n            private Configuration _config;\n\n            private byte[] _firstPacket;\n            private ProxySocketTunLocal _local;\n            private ProxySocketTun _remote;\n\n            private bool _closed;\n            private bool _local_proxy;\n            private string _remote_host;\n            private int _remote_port;\n\n            public const int RecvSize = 1460 * 8;\n            // remote receive buffer\n            private byte[] remoteRecvBuffer = new byte[RecvSize];\n            // connection receive buffer\n            private byte[] connetionRecvBuffer = new byte[RecvSize];\n            private int _totalRecvSize;\n\n            protected int TTL = 600;\n            protected System.Timers.Timer timer;\n            protected object timerLock = new();\n            protected DateTime lastTimerSetTime;\n\n            public void Start(Configuration config, byte[] firstPacket, Socket socket, string local_sendback_protocol, bool proxy)\n            {\n                _firstPacket = firstPacket;\n                _local = new ProxySocketTunLocal(socket)\n                {\n                    local_sendback_protocol = local_sendback_protocol\n                };\n                _config = config;\n                _local_proxy = proxy;\n                Connect();\n            }\n\n            private void Connect()\n            {\n                try\n                {\n                    IPAddress ipAddress = null;\n                    var _targetPort = 0;\n                    {\n                        if (_firstPacket[0] == 1)\n                        {\n                            var addr = new byte[4];\n                            Array.Copy(_firstPacket, 1, addr, 0, addr.Length);\n                            ipAddress = new IPAddress(addr);\n                            _targetPort = (_firstPacket[5] << 8) | _firstPacket[6];\n                            _remote_host = ipAddress.ToString();\n                            Logging.Info((_local_proxy ? \"Local proxy\" : \"Direct\") + \" connect \" + _remote_host + \":\" + _targetPort);\n                        }\n                        else if (_firstPacket[0] == 4)\n                        {\n                            var addr = new byte[16];\n                            Array.Copy(_firstPacket, 1, addr, 0, addr.Length);\n                            ipAddress = new IPAddress(addr);\n                            _targetPort = (_firstPacket[17] << 8) | _firstPacket[18];\n                            _remote_host = ipAddress.ToString();\n                            Logging.Info((_local_proxy ? \"Local proxy\" : \"Direct\") + \" connect \" + _remote_host + \":\" + _targetPort);\n                        }\n                        else if (_firstPacket[0] == 3)\n                        {\n                            int len = _firstPacket[1];\n                            var addr = new byte[len];\n                            Array.Copy(_firstPacket, 2, addr, 0, addr.Length);\n                            _remote_host = Encoding.UTF8.GetString(_firstPacket, 2, len);\n                            _targetPort = (_firstPacket[len + 2] << 8) | _firstPacket[len + 3];\n                            Logging.Info((_local_proxy ? \"Local proxy\" : \"Direct\") + \" connect \" + _remote_host + \":\" + _targetPort);\n\n                            //if (!_local_proxy)\n                            {\n                                if (!IPAddress.TryParse(_remote_host, out ipAddress))\n                                {\n                                    if (_config.ProxyRuleMode == ProxyRuleMode.UserCustom)\n                                    {\n                                        if (HostMap.GetHost(_remote_host, out var host_addr))\n                                        {\n                                            if (!string.IsNullOrEmpty(host_addr))\n                                            {\n                                                var lower_host_addr = host_addr.ToLower();\n                                                if (lower_host_addr.StartsWith(\"reject\"))\n                                                {\n                                                    Close();\n                                                    return;\n                                                }\n\n                                                if (lower_host_addr.IndexOf('.') >= 0 || lower_host_addr.IndexOf(':') >= 0)\n                                                {\n                                                    if (!IPAddress.TryParse(lower_host_addr, out ipAddress))\n                                                    {\n                                                        //\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    }\n                                    if (ipAddress == null)\n                                    {\n                                        ipAddress = DnsUtil.DnsBuffer.Get(_remote_host);\n                                    }\n                                }\n                                if (ipAddress == null)\n                                {\n                                    ipAddress = DnsUtil.QueryDns(_remote_host);\n                                }\n                                if (ipAddress != null)\n                                {\n                                    DnsUtil.DnsBuffer.Set(_remote_host, new IPAddress(ipAddress.GetAddressBytes()));\n                                    DnsUtil.DnsBuffer.Sweep();\n                                }\n                                else\n                                {\n                                    if (!_local_proxy)\n                                    {\n                                        throw new SocketException((int)SocketError.HostNotFound);\n                                    }\n                                }\n                            }\n                        }\n                        _remote_port = _targetPort;\n                    }\n                    if (ipAddress != null && _config.ProxyRuleMode == ProxyRuleMode.UserCustom)\n                    {\n                        if (HostMap.GetIP(ipAddress, out var host_addr))\n                        {\n                            var lower_host_addr = host_addr.ToLower();\n                            if (lower_host_addr.StartsWith(\"reject\")\n                                )\n                            {\n                                Close();\n                                return;\n                            }\n                        }\n                    }\n                    if (_local_proxy)\n                    {\n                        IPAddress.TryParse(_config.ProxyHost, out ipAddress);\n                        _targetPort = _config.ProxyPort;\n                    }\n                    // ProxyAuth recv only socks5 head, so don't need to save anything else\n                    var remoteEP = new IPEndPoint(ipAddress ?? throw new InvalidOperationException(), _targetPort);\n\n                    _remote = new ProxySocketTun(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);\n                    _remote.GetSocket().NoDelay = true;\n\n                    // Connect to the remote endpoint.\n                    _remote.BeginConnect(remoteEP, ConnectCallback, null);\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private bool ConnectProxyServer(string strRemoteHost, int iRemotePort)\n            {\n                if (_config.ProxyType == ProxyType.Socks5)\n                {\n                    var ret = _remote.ConnectSocks5ProxyServer(strRemoteHost, iRemotePort, false, _config.ProxyAuthUser, _config.ProxyAuthPass);\n                    return ret;\n                }\n\n                if (_config.ProxyType == ProxyType.Http)\n                {\n                    var ret = _remote.ConnectHttpProxyServer(strRemoteHost, iRemotePort, _config.ProxyAuthUser, _config.ProxyAuthPass, _config.ProxyUserAgent);\n                    return ret;\n                }\n\n                return true;\n            }\n\n            private void ConnectCallback(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    _remote.EndConnect(ar);\n                    if (_local_proxy)\n                    {\n                        if (!ConnectProxyServer(_remote_host, _remote_port))\n                        {\n                            throw new SocketException((int)SocketError.ConnectionReset);\n                        }\n                    }\n                    StartPipe();\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void ResetTimeout(double time)\n            {\n                if (time <= 0 && timer == null)\n                {\n                    return;\n                }\n\n                if (time <= 0)\n                {\n                    if (timer != null)\n                    {\n                        lock (timerLock)\n                        {\n                            if (timer != null)\n                            {\n                                timer.Enabled = false;\n                                timer.Elapsed -= timer_Elapsed;\n                                timer.Dispose();\n                                timer = null;\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    if ((DateTime.Now - lastTimerSetTime).TotalMilliseconds > 500)\n                    {\n                        lock (timerLock)\n                        {\n                            if (timer == null)\n                            {\n                                timer = new System.Timers.Timer(time * 1000.0);\n                                timer.Elapsed += timer_Elapsed;\n                            }\n                            else\n                            {\n                                timer.Interval = time * 1000.0;\n                                timer.Stop();\n                            }\n                            timer.Start();\n                            lastTimerSetTime = DateTime.Now;\n                        }\n                    }\n                }\n            }\n\n            private void timer_Elapsed(object sender, ElapsedEventArgs e)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                Close();\n            }\n\n            private void StartPipe()\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    Server.ForwardServer.Connections.AddRef(this);\n                    _remote.BeginReceive(remoteRecvBuffer, RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null);\n                    _local.BeginReceive(connetionRecvBuffer, RecvSize, SocketFlags.None, PipeConnectionReceiveCallback, null);\n\n                    _local.Send(connetionRecvBuffer, 0, SocketFlags.None);\n                    ResetTimeout(TTL);\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void PipeRemoteReceiveCallback(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    var bytesRead = _remote.EndReceive(ar);\n\n                    if (bytesRead > 0)\n                    {\n                        ResetTimeout(TTL);\n                        //_local.BeginSend(remoteRecvBuffer, bytesRead, 0, new AsyncCallback(PipeConnectionSendCallback), null);\n                        _local.Send(remoteRecvBuffer, bytesRead, SocketFlags.None);\n                        _totalRecvSize += bytesRead;\n                        if (_totalRecvSize <= 1024 * 1024 * 2)\n                        {\n                            _remote.BeginReceive(remoteRecvBuffer, RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null);\n                        }\n                        else\n                        {\n                            PipeRemoteReceiveLoop();\n                        }\n                    }\n                    else\n                    {\n                        Close();\n                    }\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void PipeRemoteReceiveLoop()\n            {\n                var final_close = false;\n                var recv_buffer = new byte[RecvSize];\n                var beforeReceive = DateTime.Now;\n                while (!_closed)\n                {\n                    try\n                    {\n                        var bytesRead = _remote.Receive(recv_buffer, RecvSize, SocketFlags.None);\n                        var now = DateTime.Now;\n                        if (_remote != null && _remote.IsClose)\n                        {\n                            final_close = true;\n                            break;\n                        }\n                        if (_closed)\n                        {\n                            break;\n                        }\n                        ResetTimeout(TTL);\n\n                        if (bytesRead > 0)\n                        {\n                            _local.Send(recv_buffer, bytesRead, SocketFlags.None);\n\n                            if ((now - beforeReceive).TotalSeconds > 5)\n                            {\n                                _totalRecvSize = 0;\n                                _remote.BeginReceive(remoteRecvBuffer, RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null);\n                                return;\n                            }\n\n                            beforeReceive = now;\n                        }\n                        else\n                        {\n                            Close();\n                        }\n                    }\n                    catch (Exception e)\n                    {\n                        Logging.LogUsefulException(e);\n                        final_close = true;\n                        break;\n                    }\n                }\n                if (final_close)\n                {\n                    Close();\n                }\n            }\n\n            private void PipeConnectionReceiveCallback(IAsyncResult ar)\n            {\n                if (_closed)\n                {\n                    return;\n                }\n                try\n                {\n                    var bytesRead = _local.EndReceive(ar);\n\n                    if (bytesRead > 0)\n                    {\n                        ResetTimeout(TTL);\n                        //_remote.BeginSend(connetionRecvBuffer, bytesRead, 0, new AsyncCallback(PipeRemoteSendCallback), null);\n                        _remote.Send(connetionRecvBuffer, bytesRead, SocketFlags.None);\n                        _local.BeginReceive(connetionRecvBuffer, RecvSize, SocketFlags.None, PipeConnectionReceiveCallback, null);\n                    }\n                    else\n                    {\n                        Close();\n                    }\n                }\n                catch (Exception e)\n                {\n                    Logging.LogUsefulException(e);\n                    Close();\n                }\n            }\n\n            private void CloseSocket(ProxySocketTun sock)\n            {\n                lock (this)\n                {\n                    if (sock != null)\n                    {\n                        var s = sock;\n                        try\n                        {\n                            s.Shutdown(SocketShutdown.Both);\n                        }\n                        catch\n                        {\n                            // ignored\n                        }\n                        try\n                        {\n                            s.Close();\n                        }\n                        catch\n                        {\n                            // ignored\n                        }\n                    }\n                }\n            }\n\n            public void Close()\n            {\n                lock (this)\n                {\n                    if (_closed)\n                    {\n                        return;\n                    }\n                    _closed = true;\n                }\n                ResetTimeout(0);\n                Thread.Sleep(100);\n                CloseSocket(_remote);\n                CloseSocket(_local);\n                Server.ForwardServer.Connections.DecRef(this);\n            }\n\n            public override void Shutdown()\n            {\n                Task.Run(Close);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/SpeedTest.cs",
    "content": "using System;\nusing Shadowsocks.Model.Transfer;\n#if DEBUG\nusing System.Collections.Generic;\n#endif\n\nnamespace Shadowsocks.Controller.Service\n{\n    internal class SpeedTester\n    {\n#if DEBUG\n        private struct TransLog\n        {\n            public int Dir;\n            public int Size;\n        }\n#endif\n        public DateTime TimeConnectBegin;\n        public DateTime TimeConnectEnd;\n        public DateTime TimeBeginUpload;\n        public DateTime TimeBeginDownload;\n        public long SizeUpload;\n        public long SizeDownload;\n        public long SizeProtocolRecv;\n        public long SizeRecv;\n#if DEBUG\n        private readonly List<TransLog> _sizeTransfer = new();\n#endif\n        public string ServerId;\n        public ServerTransferTotal Transfer;\n        private int _uploadCnt;\n        private int _downloadCnt;\n\n        public void BeginConnect()\n        {\n            TimeConnectBegin = DateTime.Now;\n        }\n\n        public void EndConnect()\n        {\n            TimeConnectEnd = DateTime.Now;\n        }\n\n        public void BeginUpload()\n        {\n            TimeBeginUpload = DateTime.Now;\n        }\n\n        public bool BeginDownload()\n        {\n            if (TimeBeginDownload == new DateTime())\n            {\n                TimeBeginDownload = DateTime.Now;\n                return true;\n            }\n            return false;\n        }\n\n        public bool AddDownloadSize(int size)\n        {\n            SizeDownload += size;\n            if (Transfer != null && ServerId != null)\n            {\n                Transfer.AddDownload(ServerId, size);\n            }\n            _uploadCnt = 0;\n            _downloadCnt += 1;\n#if DEBUG\n            if (_sizeTransfer.Count < 1024 * 128)\n            {\n                lock (_sizeTransfer)\n                {\n                    _sizeTransfer.Add(new TransLog { Dir = 1, Size = size });\n                }\n            }\n#endif\n            return _downloadCnt > 30;\n        }\n\n        public void AddProtocolRecvSize(int size)\n        {\n            SizeProtocolRecv += size;\n        }\n\n        public void AddRecvSize(int size)\n        {\n            SizeRecv += size;\n        }\n\n        public bool AddUploadSize(int size)\n        {\n            SizeUpload += size;\n            if (Transfer != null && ServerId != null)\n            {\n                Transfer.AddUpload(ServerId, size);\n            }\n            _uploadCnt += 1;\n            _downloadCnt = 0;\n#if DEBUG\n            if (_sizeTransfer.Count < 1024 * 128)\n            {\n                lock (_sizeTransfer)\n                {\n                    _sizeTransfer.Add(new TransLog { Dir = 0, Size = size });\n                }\n            }\n#endif\n            return _uploadCnt > 30;\n        }\n\n        public string TransferLog()\n        {\n            var ret = string.Empty;\n#if DEBUG\n            var lastDir = -1;\n            foreach (var t in _sizeTransfer)\n            {\n                if (t.Dir != lastDir)\n                {\n                    lastDir = t.Dir;\n                    ret += t.Dir == 0 ? \" u\" : \" d\";\n                }\n                ret += $\" {t.Size}\";\n            }\n#endif\n            return ret;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/Service/UpdateSubscribeManager.cs",
    "content": "using Shadowsocks.Controller.HttpRequest;\nusing Shadowsocks.Model;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Shadowsocks.Controller.Service\n{\n    public class UpdateSubscribeManager\n    {\n        private Configuration _config;\n        private Queue<ServerSubscribe> _serverSubscribes;\n        private UpdateNode _updater;\n        private bool _notify;\n\n        public void CreateTask(Configuration config, UpdateNode updater, bool updateManually, List<ServerSubscribe> serverSubscribe = null)\n        {\n            if (_config != null)\n            {\n                return;\n            }\n\n            _config = config;\n            _updater = updater;\n            _notify = updateManually;\n            if (serverSubscribe?.Count > 0)\n            {\n                _serverSubscribes = new Queue<ServerSubscribe>(serverSubscribe);\n            }\n            else\n            {\n                _serverSubscribes = new Queue<ServerSubscribe>();\n                if (updateManually)\n                {\n                    config.ServerSubscribes.ForEach(sub => _serverSubscribes.Enqueue(sub));\n                }\n                else\n                {\n                    foreach (var server in config.ServerSubscribes.Where(server => server.AutoCheckUpdate))\n                    {\n                        _serverSubscribes.Enqueue(server);\n                    }\n                }\n            }\n            Next();\n        }\n\n        public void Next()\n        {\n            if (_serverSubscribes.Count == 0)\n            {\n                _config = null;\n                return;\n            }\n\n            CurrentServerSubscribe = _serverSubscribes.Dequeue();\n            _updater.CheckUpdate(_config, CurrentServerSubscribe, _notify);\n        }\n\n        public ServerSubscribe CurrentServerSubscribe { get; private set; }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Controller/SystemProxy.cs",
    "content": "using Shadowsocks.Controller.Service;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing System;\nusing WindowsProxy;\n\nnamespace Shadowsocks.Controller;\n\npublic static class SystemProxy\n{\n    private static readonly ProxyStatus Old;\n    static SystemProxy()\n    {\n        try\n        {\n            using var proxy = new ProxyService();\n            Old = proxy.Query();\n        }\n        catch (Exception e)\n        {\n            Logging.LogUsefulException(e);\n        }\n    }\n\n    public static void Restore()\n    {\n        try\n        {\n            using var proxy = new ProxyService();\n            proxy.Set(Old);\n        }\n        catch (Exception e)\n        {\n            Logging.LogUsefulException(e);\n        }\n    }\n\n    public static void Update(Configuration config, PACServer pacSrv)\n    {\n        var sysProxyMode = config.SysProxyMode;\n        try\n        {\n            using var proxy = new ProxyService();\n\n            switch (sysProxyMode)\n            {\n                case ProxyMode.Direct:\n                {\n                    proxy.Direct();\n                    break;\n                }\n                case ProxyMode.Pac:\n                {\n                    proxy.AutoConfigUrl = pacSrv.PacUrl;\n                    proxy.Pac();\n                    break;\n                }\n                case ProxyMode.Global:\n                {\n                    proxy.Server = $@\"localhost:{config.LocalPort}\";\n                    proxy.Bypass = string.Join(';', ProxyService.LanIp);\n                    proxy.Global();\n                    break;\n                }\n            }\n        }\n        catch (Exception e)\n        {\n            Logging.LogUsefulException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Data/abp.js",
    "content": "var direct = \"__DIRECT__\";\nif (direct == \"__DIR\" + \"ECT__\") direct = \"DIRECT;\";\n\nvar wall_proxy = function(){ return \"__PROXY__\"; };\nvar wall_v6_proxy = function(){ return \"__PROXY__\"; };\n\nvar nowall_proxy = function(){ return direct; };\nvar ip_proxy = function(){ return nowall_proxy(); };\nvar ipv6_proxy = function(){ return nowall_proxy(); };\n\nvar userrules = __USERRULES__;\nvar rules = __RULES__;\n\n/*\n* This file is part of Adblock Plus <http://adblockplus.org/>,\n* Copyright (C) 2006-2014 Eyeo GmbH\n*\n* Adblock Plus is free software: you can redistribute it and/or modify\n* it under the terms of the GNU General Public License version 3 as\n* published by the Free Software Foundation.\n*\n* Adblock Plus is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\tSee the\n* GNU General Public License for more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with Adblock Plus.\tIf not, see <http://www.gnu.org/licenses/>.\n*/\n\nfunction createDict()\n{\n\tvar result = {};\n\tresult.__proto__ = null;\n\treturn result;\n}\n\nfunction getOwnPropertyDescriptor(obj, key)\n{\n\tif (obj.hasOwnProperty(key))\n\t{\n\t\treturn obj[key];\n\t}\n\treturn null;\n}\n\nfunction extend(subclass, superclass, definition)\n{\n\tif (Object.__proto__)\n\t{\n\t\tdefinition.__proto__ = superclass.prototype;\n\t\tsubclass.prototype = definition;\n\t}\n\telse\n\t{\n\t\tvar tmpclass = function(){}, ret;\n\t\ttmpclass.prototype = superclass.prototype;\n\t\tsubclass.prototype = new tmpclass();\n\t\tsubclass.prototype.constructor = superclass;\n\t\tfor (var i in definition)\n\t\t{\n\t\t\tif (definition.hasOwnProperty(i))\n\t\t\t{\n\t\t\t\tsubclass.prototype[i] = definition[i];\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction Filter(text)\n{\n\tthis.text = text;\n\tthis.subscriptions = [];\n}\nFilter.prototype = {\n\ttext: null,\n\tsubscriptions: null,\n\ttoString: function()\n\t{\n\t\treturn this.text;\n\t}\n};\nFilter.knownFilters = createDict();\nFilter.elemhideRegExp = /^([^\\/\\*\\|\\@\"!]*?)#(\\@)?(?:([\\w\\-]+|\\*)((?:\\([\\w\\-]+(?:[$^*]?=[^\\(\\)\"]*)?\\))*)|#([^{}]+))$/;\nFilter.regexpRegExp = /^(@@)?\\/.*\\/(?:\\$~?[\\w\\-]+(?:=[^,\\s]+)?(?:,~?[\\w\\-]+(?:=[^,\\s]+)?)*)?$/;\nFilter.optionsRegExp = /\\$(~?[\\w\\-]+(?:=[^,\\s]+)?(?:,~?[\\w\\-]+(?:=[^,\\s]+)?)*)$/;\nFilter.fromText = function(text)\n{\n\tif (text in Filter.knownFilters)\n\t{\n\t\treturn Filter.knownFilters[text];\n\t}\n\tvar ret;\n\tif (text.charAt(0) == \"!\")\n\t{\n\t\tret = new CommentFilter(text);\n\t}\n\telse\n\t{\n\t\tret = RegExpFilter.fromText(text);\n\t}\n\tFilter.knownFilters[ret.text] = ret;\n\treturn ret;\n};\n\nfunction InvalidFilter(text, reason)\n{\n\tFilter.call(this, text);\n\tthis.reason = reason;\n}\nextend(InvalidFilter, Filter, {\n\treason: null\n});\n\nfunction CommentFilter(text)\n{\n\tFilter.call(this, text);\n}\nextend(CommentFilter, Filter, {\n});\n\nfunction ActiveFilter(text, domains)\n{\n\tFilter.call(this, text);\n\tthis.domainSource = domains;\n}\nextend(ActiveFilter, Filter, {\n\tdomainSource: null,\n\tdomainSeparator: null,\n\tignoreTrailingDot: true,\n\tdomainSourceIsUpperCase: false,\n\tgetDomains: function()\n\t{\n\t\tvar prop = getOwnPropertyDescriptor(this, \"domains\");\n\t\tif (prop)\n\t\t{\n\t\t\treturn prop;\n\t\t}\n\t\tvar domains = null;\n\t\tif (this.domainSource)\n\t\t{\n\t\t\tvar source = this.domainSource;\n\t\t\tif (!this.domainSourceIsUpperCase)\n\t\t\t{\n\t\t\t\tsource = source.toUpperCase();\n\t\t\t}\n\t\t\tvar list = source.split(this.domainSeparator);\n\t\t\tif (list.length == 1 && (list[0]).charAt(0) != \"~\")\n\t\t\t{\n\t\t\t\tdomains = createDict();\n\t\t\t\tdomains[\"\"] = false;\n\t\t\t\tif (this.ignoreTrailingDot)\n\t\t\t\t{\n\t\t\t\t\tlist[0] = list[0].replace(/\\.+$/, \"\");\n\t\t\t\t}\n\t\t\t\tdomains[list[0]] = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvar hasIncludes = false;\n\t\t\t\tfor (var i = 0; i < list.length; i++)\n\t\t\t\t{\n\t\t\t\t\tvar domain = list[i];\n\t\t\t\t\tif (this.ignoreTrailingDot)\n\t\t\t\t\t{\n\t\t\t\t\t\tdomain = domain.replace(/\\.+$/, \"\");\n\t\t\t\t\t}\n\t\t\t\t\tif (domain == \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tvar include;\n\t\t\t\t\tif (domain.charAt(0) == \"~\")\n\t\t\t\t\t{\n\t\t\t\t\t\tinclude = false;\n\t\t\t\t\t\tdomain = domain.substr(1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tinclude = true;\n\t\t\t\t\t\thasIncludes = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (!domains)\n\t\t\t\t\t{\n\t\t\t\t\t\tdomains = createDict();\n\t\t\t\t\t}\n\t\t\t\t\tdomains[domain] = include;\n\t\t\t\t}\n\t\t\t\tdomains[\"\"] = !hasIncludes;\n\t\t\t}\n\t\t\tthis.domainSource = null;\n\t\t}\n\t\treturn this.domains;\n\t},\n\tsitekeys: null,\n\tisActiveOnDomain: function(docDomain, sitekey)\n\t{\n\t\tif (this.getSitekeys() && (!sitekey || this.getSitekeys().indexOf(sitekey.toUpperCase()) < 0))\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tif (!this.getDomains())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\tif (!docDomain)\n\t\t{\n\t\t\treturn this.getDomains()[\"\"];\n\t\t}\n\t\tif (this.ignoreTrailingDot)\n\t\t{\n\t\t\tdocDomain = docDomain.replace(/\\.+$/, \"\");\n\t\t}\n\t\tdocDomain = docDomain.toUpperCase();\n\t\twhile (true)\n\t\t{\n\t\t\tif (docDomain in this.getDomains())\n\t\t\t{\n\t\t\t\treturn this.domains[docDomain];\n\t\t\t}\n\t\t\tvar nextDot = docDomain.indexOf(\".\");\n\t\t\tif (nextDot < 0)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdocDomain = docDomain.substr(nextDot + 1);\n\t\t}\n\t\treturn this.domains[\"\"];\n\t},\n\tisActiveOnlyOnDomain: function(docDomain)\n\t{\n\t\tif (!docDomain || !this.getDomains() || this.getDomains()[\"\"])\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tif (this.ignoreTrailingDot)\n\t\t{\n\t\t\tdocDomain = docDomain.replace(/\\.+$/, \"\");\n\t\t}\n\t\tdocDomain = docDomain.toUpperCase();\n\t\tfor (var domain in this.getDomains())\n\t\t{\n\t\t\tif (this.domains[domain] && domain != docDomain && (domain.length <= docDomain.length || domain.indexOf(\".\" + docDomain) != domain.length - docDomain.length - 1))\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n});\n\nfunction RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys)\n{\n\tActiveFilter.call(this, text, domains, sitekeys);\n\tif (contentType != null)\n\t{\n\t\tthis.contentType = contentType;\n\t}\n\tif (matchCase)\n\t{\n\t\tthis.matchCase = matchCase;\n\t}\n\tif (thirdParty != null)\n\t{\n\t\tthis.thirdParty = thirdParty;\n\t}\n\tif (sitekeys != null)\n\t{\n\t\tthis.sitekeySource = sitekeys;\n\t}\n\tif (regexpSource.length >= 2 && regexpSource.charAt(0) == \"/\" && regexpSource.charAt(regexpSource.length - 1) == \"/\")\n\t{\n\t\tvar regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), this.matchCase ? \"\" : \"i\");\n\t\tthis.regexp = regexp;\n\t}\n\telse\n\t{\n\t\tthis.regexpSource = regexpSource;\n\t}\n}\nextend(RegExpFilter, ActiveFilter, {\n\tdomainSourceIsUpperCase: true,\n\tlength: 1,\n\tdomainSeparator: \"|\",\n\tregexpSource: null,\n\tgetRegexp: function()\n\t{\n\t\tvar prop = getOwnPropertyDescriptor(this, \"regexp\");\n\t\tif (prop)\n\t\t{\n\t\t\treturn prop;\n\t\t}\n\t\tvar source = this.regexpSource.replace(/\\*+/g, \"*\").replace(/\\^\\|$/, \"^\").replace(/\\W/g, \"\\\\$&\").replace(/\\\\\\*/g, \".*\").replace(/\\\\\\^/g, \"(?:[\\\\x00-\\\\x24\\\\x26-\\\\x2C\\\\x2F\\\\x3A-\\\\x40\\\\x5B-\\\\x5E\\\\x60\\\\x7B-\\\\x7F]|$)\").replace(/^\\\\\\|\\\\\\|/, \"^[\\\\w\\\\-]+:\\\\/+(?!\\\\/)(?:[^\\\\/]+\\\\.)?\").replace(/^\\\\\\|/, \"^\").replace(/\\\\\\|$/, \"$\").replace(/^(\\.\\*)/, \"\").replace(/(\\.\\*)$/, \"\");\n\t\tvar regexp = new RegExp(source, this.matchCase ? \"\" : \"i\");\n\t\tthis.regexp = regexp;\n\t\treturn regexp;\n\t},\n\tcontentType: 2147483647,\n\tmatchCase: false,\n\tthirdParty: null,\n\tsitekeySource: null,\n\tgetSitekeys: function()\n\t{\n\t\tvar prop = getOwnPropertyDescriptor(this, \"sitekeys\");\n\t\tif (prop)\n\t\t{\n\t\t\treturn prop;\n\t\t}\n\t\tvar sitekeys = null;\n\t\tif (this.sitekeySource)\n\t\t{\n\t\t\tsitekeys = this.sitekeySource.split(\"|\");\n\t\t\tthis.sitekeySource = null;\n\t\t}\n\t\tthis.sitekeys = sitekeys;\n\t\treturn this.sitekeys;\n\t},\n\tmatches: function(location, contentType, docDomain, thirdParty, sitekey)\n\t{\n\t\tif (this.getRegexp().test(location) && this.isActiveOnDomain(docDomain, sitekey))\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n});\nRegExpFilter.prototype[\"0\"] = \"#this\";\nRegExpFilter.fromText = function(text)\n{\n\tvar blocking = true;\n\tvar origText = text;\n\tif (text.indexOf(\"@@\") == 0)\n\t{\n\t\tblocking = false;\n\t\ttext = text.substr(2);\n\t}\n\tvar contentType = null;\n\tvar matchCase = null;\n\tvar domains = null;\n\tvar sitekeys = null;\n\tvar thirdParty = null;\n\tvar collapse = null;\n\tvar options;\n\tvar match = text.indexOf(\"$\") >= 0 ? Filter.optionsRegExp.exec(text) : null;\n\tif (match)\n\t{\n\t\toptions = match[1].toUpperCase().split(\",\");\n\t\ttext = match.input.substr(0, match.index);\n\t\tfor (var _loopIndex6 = 0; _loopIndex6 < options.length; ++_loopIndex6)\n\t\t{\n\t\t\tvar option = options[_loopIndex6];\n\t\t\tvar value = null;\n\t\t\tvar separatorIndex = option.indexOf(\"=\");\n\t\t\tif (separatorIndex >= 0)\n\t\t\t{\n\t\t\t\tvalue = option.substr(separatorIndex + 1);\n\t\t\t\toption = option.substr(0, separatorIndex);\n\t\t\t}\n\t\t\toption = option.replace(/-/, \"_\");\n\t\t\tif (option in RegExpFilter.typeMap)\n\t\t\t{\n\t\t\t\tif (contentType == null)\n\t\t\t\t{\n\t\t\t\t\tcontentType = 0;\n\t\t\t\t}\n\t\t\t\tcontentType |= RegExpFilter.typeMap[option];\n\t\t\t}\n\t\t\telse if (option.charAt(0) == \"~\" && option.substr(1) in RegExpFilter.typeMap)\n\t\t\t{\n\t\t\t\tif (contentType == null)\n\t\t\t\t{\n\t\t\t\t\tcontentType = RegExpFilter.prototype.contentType;\n\t\t\t\t}\n\t\t\t\tcontentType &= ~RegExpFilter.typeMap[option.substr(1)];\n\t\t\t}\n\t\t\telse if (option == \"MATCH_CASE\")\n\t\t\t{\n\t\t\t\tmatchCase = true;\n\t\t\t}\n\t\t\telse if (option == \"~MATCH_CASE\")\n\t\t\t{\n\t\t\t\tmatchCase = false;\n\t\t\t}\n\t\t\telse if (option == \"DOMAIN\" && typeof value != \"undefined\")\n\t\t\t{\n\t\t\t\tdomains = value;\n\t\t\t}\n\t\t\telse if (option == \"THIRD_PARTY\")\n\t\t\t{\n\t\t\t\tthirdParty = true;\n\t\t\t}\n\t\t\telse if (option == \"~THIRD_PARTY\")\n\t\t\t{\n\t\t\t\tthirdParty = false;\n\t\t\t}\n\t\t\telse if (option == \"COLLAPSE\")\n\t\t\t{\n\t\t\t\tcollapse = true;\n\t\t\t}\n\t\t\telse if (option == \"~COLLAPSE\")\n\t\t\t{\n\t\t\t\tcollapse = false;\n\t\t\t}\n\t\t\telse if (option == \"SITEKEY\" && typeof value != \"undefined\")\n\t\t\t{\n\t\t\t\tsitekeys = value;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn new InvalidFilter(origText, \"Unknown option \" + option.toLowerCase());\n\t\t\t}\n\t\t}\n\t}\n\tif (!blocking && (contentType == null || contentType & RegExpFilter.typeMap.DOCUMENT) && (!options || options.indexOf(\"DOCUMENT\") < 0) && !/^\\|?[\\w\\-]+:/.test(text))\n\t{\n\t\tif (contentType == null)\n\t\t{\n\t\t\tcontentType = RegExpFilter.prototype.contentType;\n\t\t}\n\t\tcontentType &= ~RegExpFilter.typeMap.DOCUMENT;\n\t}\n\ttry\n\t{\n\t\tif (blocking)\n\t\t{\n\t\t\treturn new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn new WhitelistFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys);\n\t\t}\n\t}\n\tcatch (e)\n\t{\n\t\treturn new InvalidFilter(origText, e);\n\t}\n};\nRegExpFilter.typeMap = {\n\tOTHER: 1,\n\tSCRIPT: 2,\n\tIMAGE: 4,\n\tSTYLESHEET: 8,\n\tOBJECT: 16,\n\tSUBDOCUMENT: 32,\n\tDOCUMENT: 64,\n\tXBL: 1,\n\tPING: 1,\n\tXMLHTTPREQUEST: 2048,\n\tOBJECT_SUBREQUEST: 4096,\n\tDTD: 1,\n\tMEDIA: 16384,\n\tFONT: 32768,\n\tBACKGROUND: 4,\n\tPOPUP: 268435456,\n\tELEMHIDE: 1073741824\n};\nRegExpFilter.prototype.contentType &= ~ (RegExpFilter.typeMap.ELEMHIDE | RegExpFilter.typeMap.POPUP);\n\nfunction BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys, collapse)\n{\n\tRegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys);\n\tthis.collapse = collapse;\n}\nextend(BlockingFilter, RegExpFilter, {\n\tcollapse: null\n});\n\nfunction WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys)\n{\n\tRegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys);\n}\nextend(WhitelistFilter, RegExpFilter, {\n});\n\nfunction Matcher()\n{\n\tthis.clear();\n}\nMatcher.prototype = {\n\tfilterByKeyword: null,\n\tkeywordByFilter: null,\n\tclear: function()\n\t{\n\t\tthis.filterByKeyword = createDict();\n\t\tthis.keywordByFilter = createDict();\n\t},\n\tadd: function(filter)\n\t{\n\t\tif (filter.text in this.keywordByFilter)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tvar keyword = this.findKeyword(filter);\n\t\tvar oldEntry = this.filterByKeyword[keyword];\n\t\tif (typeof oldEntry == \"undefined\")\n\t\t{\n\t\t\tthis.filterByKeyword[keyword] = filter;\n\t\t}\n\t\telse if (oldEntry.length == 1)\n\t\t{\n\t\t\tthis.filterByKeyword[keyword] = [oldEntry, filter];\n\t\t}\n\t\telse\n\t\t{\n\t\t\toldEntry.push(filter);\n\t\t}\n\t\tthis.keywordByFilter[filter.text] = keyword;\n\t},\n\tremove: function(filter)\n\t{\n\t\tif (!(filter.text in this.keywordByFilter))\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tvar keyword = this.keywordByFilter[filter.text];\n\t\tvar list = this.filterByKeyword[keyword];\n\t\tif (list.length <= 1)\n\t\t{\n\t\t\tdelete this.filterByKeyword[keyword];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvar index = list.indexOf(filter);\n\t\t\tif (index >= 0)\n\t\t\t{\n\t\t\t\tlist.splice(index, 1);\n\t\t\t\tif (list.length == 1)\n\t\t\t\t{\n\t\t\t\t\tthis.filterByKeyword[keyword] = list[0];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdelete this.keywordByFilter[filter.text];\n\t},\n\tfindKeyword: function(filter)\n\t{\n\t\tvar result = \"\";\n\t\tvar text = filter.text;\n\t\tif (Filter.regexpRegExp.test(text))\n\t\t{\n\t\t\treturn result;\n\t\t}\n\t\tvar match = Filter.optionsRegExp.exec(text);\n\t\tif (match)\n\t\t{\n\t\t\ttext = match.input.substr(0, match.index);\n\t\t}\n\t\tif (text.substr(0, 2) == \"@@\")\n\t\t{\n\t\t\ttext = text.substr(2);\n\t\t}\n\t\tvar candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g);\n\t\tif (!candidates)\n\t\t{\n\t\t\treturn result;\n\t\t}\n\t\tvar hash = this.filterByKeyword;\n\t\tvar resultCount = 16777215;\n\t\tvar resultLength = 0;\n\t\tfor (var i = 0, l = candidates.length; i < l; i++)\n\t\t{\n\t\t\tvar candidate = candidates[i].substr(1);\n\t\t\tvar count = candidate in hash ? hash[candidate].length : 0;\n\t\t\tif (count < resultCount || count == resultCount && candidate.length > resultLength)\n\t\t\t{\n\t\t\t\tresult = candidate;\n\t\t\t\tresultCount = count;\n\t\t\t\tresultLength = candidate.length;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t},\n\thasFilter: function(filter)\n\t{\n\t\treturn filter.text in this.keywordByFilter;\n\t},\n\tgetKeywordForFilter: function(filter)\n\t{\n\t\tif (filter.text in this.keywordByFilter)\n\t\t{\n\t\t\treturn this.keywordByFilter[filter.text];\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn null;\n\t\t}\n\t},\n\t_checkEntryMatch: function(keyword, location, contentType, docDomain, thirdParty, sitekey)\n\t{\n\t\tvar list = this.filterByKeyword[keyword];\n\t\tfor (var i = 0; i < list.length; i++)\n\t\t{\n\t\t\tvar filter = list[i];\n\t\t\tif (filter == \"#this\")\n\t\t\t{\n\t\t\t\tfilter = list;\n\t\t\t}\n\t\t\tif (filter.matches(location, contentType, docDomain, thirdParty, sitekey))\n\t\t\t{\n\t\t\t\treturn filter;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t},\n\tmatchesAny: function(location, contentType, docDomain, thirdParty, sitekey)\n\t{\n\t\tvar candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);\n\t\tif (candidates === null)\n\t\t{\n\t\t\tcandidates = [];\n\t\t}\n\t\tcandidates.push(\"\");\n\t\tfor (var i = 0, l = candidates.length; i < l; i++)\n\t\t{\n\t\t\tvar substr = candidates[i];\n\t\t\tif (substr in this.filterByKeyword)\n\t\t\t{\n\t\t\t\tvar result = this._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);\n\t\t\t\tif (result)\n\t\t\t\t{\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n};\n\nfunction CombinedMatcher()\n{\n\tthis.blacklist = new Matcher();\n\tthis.whitelist = new Matcher();\n\tthis.resultCache = createDict();\n}\nCombinedMatcher.maxCacheEntries = 1000;\nCombinedMatcher.prototype = {\n\tblacklist: null,\n\twhitelist: null,\n\tresultCache: null,\n\tcacheEntries: 0,\n\tclear: function()\n\t{\n\t\tthis.blacklist.clear();\n\t\tthis.whitelist.clear();\n\t\tthis.resultCache = createDict();\n\t\tthis.cacheEntries = 0;\n\t},\n\tadd: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\tthis.whitelist.add(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.blacklist.add(filter);\n\t\t}\n\t\tif (this.cacheEntries > 0)\n\t\t{\n\t\t\tthis.resultCache = createDict();\n\t\t\tthis.cacheEntries = 0;\n\t\t}\n\t},\n\tremove: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\tthis.whitelist.remove(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.blacklist.remove(filter);\n\t\t}\n\t\tif (this.cacheEntries > 0)\n\t\t{\n\t\t\tthis.resultCache = createDict();\n\t\t\tthis.cacheEntries = 0;\n\t\t}\n\t},\n\tfindKeyword: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\treturn this.whitelist.findKeyword(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn this.blacklist.findKeyword(filter);\n\t\t}\n\t},\n\thasFilter: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\treturn this.whitelist.hasFilter(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn this.blacklist.hasFilter(filter);\n\t\t}\n\t},\n\tgetKeywordForFilter: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\treturn this.whitelist.getKeywordForFilter(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn this.blacklist.getKeywordForFilter(filter);\n\t\t}\n\t},\n\tisSlowFilter: function(filter)\n\t{\n\t\tvar matcher = filter instanceof WhitelistFilter ? this.whitelist : this.blacklist;\n\t\tif (matcher.hasFilter(filter))\n\t\t{\n\t\t\treturn !matcher.getKeywordForFilter(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn !matcher.findKeyword(filter);\n\t\t}\n\t},\n\tmatchesAnyInternal: function(location, contentType, docDomain, thirdParty, sitekey)\n\t{\n\t\tvar candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);\n\t\tif (candidates === null)\n\t\t{\n\t\t\tcandidates = [];\n\t\t}\n\t\tcandidates.push(\"\");\n\t\tvar blacklistHit = null;\n\t\tfor (var i = 0, l = candidates.length; i < l; i++)\n\t\t{\n\t\t\tvar substr = candidates[i];\n\t\t\tif (substr in this.whitelist.filterByKeyword)\n\t\t\t{\n\t\t\t\tvar result = this.whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);\n\t\t\t\tif (result)\n\t\t\t\t{\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (substr in this.blacklist.filterByKeyword && blacklistHit === null)\n\t\t\t{\n\t\t\t\tblacklistHit = this.blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);\n\t\t\t}\n\t\t}\n\t\treturn blacklistHit;\n\t},\n\tmatchesAny: function(location, docDomain)\n\t{\n\t\tvar key = location + \" \" + docDomain + \" \";\n\t\tif (key in this.resultCache)\n\t\t{\n\t\t\treturn this.resultCache[key];\n\t\t}\n\t\tvar result = this.matchesAnyInternal(location, 0, docDomain, null, null);\n\t\tif (this.cacheEntries >= CombinedMatcher.maxCacheEntries)\n\t\t{\n\t\t\tthis.resultCache = createDict();\n\t\t\tthis.cacheEntries = 0;\n\t\t}\n\t\tthis.resultCache[key] = result;\n\t\tthis.cacheEntries++;\n\t\treturn result;\n\t}\n};\n\nvar userrulesMatcher = new CombinedMatcher();\nvar defaultMatcher = new CombinedMatcher();\n\nfor (var i = 0; i < userrules.length; i++) {\n    userrulesMatcher.add(Filter.fromText(userrules[i]));\n}\n\nfor (var i = 0; i < rules.length; i++) {\n\tdefaultMatcher.add(Filter.fromText(rules[i]));\n}\n\nvar subnetIpRangeList = [\n0,16777216,\t\t\t\t//0.0.0.0/8\n167772160,184549376,\t//10.0.0.0/8\n1681915904,1686110208,\t//100.64.0.0/10\n2130706432,2147483648,\t//127.0.0.0/8\n2851995648,2852061184,\t//169.254.0.0/16\n2886729728,2887778304,\t//172.16.0.0/12\n3221225472,3221225728,\t//192.0.0.0/24\n3221225984,3221226240,\t//192.0.2.0/24\n3227017984,3227018240,\t//192.88.99.0/24\n3232235520,3232301056,\t//192.168.0.0/16\n3323068416,3323199488,\t//198.18.0.0/15\n3325256704,3325256960,\t//198.51.100.0/24\n3405803776,3405804032,\t//203.0.113.0/24\n3758096384,4026531840\t//224.0.0.0/4\n];\n\nfunction convertAddress(ipchars) {\n\tvar bytes = ipchars.split('.');\n\tvar result = (bytes[0] << 24) |\n\t(bytes[1] << 16) |\n\t(bytes[2] << 8) |\n\t(bytes[3]);\n\treturn result >>> 0;\n}\n\nfunction check_ipv4(host) {\n\tvar re_ipv4 = /^\\d+\\.\\d+\\.\\d+\\.\\d+$/g;\n\tif (re_ipv4.test(host)) {\n\t\treturn true;\n\t}\n}\nfunction check_ipv6(host) {\n\tvar re_ipv6 = /^\\[?([a-fA-F0-9]{0,4}\\:){1,7}[a-fA-F0-9]{0,4}\\]?$/g;\n\tif (re_ipv6.test(host)) {\n\t\treturn true;\n\t}\n}\nfunction check_ipv6_dns(dnsstr) {\n\tvar re_ipv6 = /([a-fA-F0-9]{0,4}\\:){1,7}[a-fA-F0-9]{0,4}(%[0-9]+)?/g;\n\tif (re_ipv6.test(dnsstr)) {\n\t\treturn true;\n\t}\n}\nfunction isInSubnetRange(ipRange, intIp) {\n\tfor ( var i = 0; i < 28; i += 2 ) {\n\t\tif ( ipRange[i] <= intIp && intIp < ipRange[i+1] )\n\t\t\treturn true;\n\t}\n}\nfunction getProxyFromIP(strIp) {\n\tvar intIp = convertAddress(strIp);\n\tif ( isInSubnetRange(subnetIpRangeList, intIp) ) {\n\t\treturn direct;\n\t}\n\treturn ip_proxy();\n}\n\nfunction FindProxyForURL(url, host) {\n\tif ( isPlainHostName(host) === true ) {\n\t\treturn direct;\n\t}\n\tif (userrulesMatcher.matchesAny(url, host) instanceof BlockingFilter) {\n        return wall_proxy();\n    }\n    if (userrulesMatcher.matchesAny(url, host) instanceof WhitelistFilter) {\n        return direct;\n    }\n\tif (defaultMatcher.matchesAny(url, host) instanceof BlockingFilter) {\n\t\treturn wall_proxy();\n\t}\n\tif ( check_ipv4(host) === true ) {\n\t\treturn getProxyFromIP(host);\n\t}\n\treturn direct;\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Data/chn_ip.txt",
    "content": "1.0.1.0/24\n1.0.2.0/23\n1.0.8.0/21\n1.0.32.0/19\n1.1.0.0/24\n1.1.2.0/23\n1.1.4.0/22\n1.1.8.0/21\n1.1.16.0/20\n1.1.32.0/19\n1.2.0.0/23\n1.2.2.0/24\n1.2.4.0/22\n1.2.8.0/21\n1.2.16.0/20\n1.2.32.0/19\n1.2.64.0/18\n1.3.0.0/16\n1.4.1.0/24\n1.4.2.0/23\n1.4.4.0/22\n1.4.8.0/21\n1.4.16.0/20\n1.4.32.0/19\n1.4.64.0/18\n1.8.0.0/16\n1.10.0.0/21\n1.10.8.0/23\n1.10.11.0/24\n1.10.12.0/22\n1.10.16.0/20\n1.10.32.0/19\n1.10.64.0/18\n1.12.16.0/20\n1.12.32.0/23\n1.12.36.0/22\n1.12.40.0/21\n1.12.48.0/20\n1.12.64.0/18\n1.12.128.0/17\n1.13.0.0/16\n1.14.0.0/15\n1.18.128.0/24\n1.24.0.0/13\n1.45.0.0/16\n1.48.0.0/14\n1.56.0.0/13\n1.68.0.0/14\n1.80.0.0/12\n1.116.0.0/15\n1.118.1.0/24\n1.118.2.0/23\n1.118.4.0/22\n1.118.8.0/21\n1.118.16.0/20\n1.118.33.0/24\n1.118.34.0/23\n1.118.36.0/22\n1.118.40.0/21\n1.118.48.0/20\n1.118.64.0/18\n1.118.128.0/17\n1.119.0.0/16\n1.180.0.0/14\n1.184.0.0/15\n1.188.0.0/14\n1.192.0.0/13\n1.202.0.0/15\n1.204.0.0/14\n3.5.214.0/23\n8.128.0.0/10\n14.0.0.0/21\n14.0.12.0/22\n14.1.0.0/22\n14.1.24.0/22\n14.1.108.0/22\n14.16.0.0/12\n14.102.128.0/22\n14.102.180.0/22\n14.103.0.0/16\n14.104.0.0/13\n14.112.0.0/12\n14.130.0.0/15\n14.134.0.0/15\n14.144.0.0/12\n14.192.60.0/22\n14.192.76.0/22\n14.196.0.0/15\n14.204.0.0/15\n14.208.0.0/12\n15.230.41.0/24\n15.230.49.0/24\n15.230.141.0/24\n20.139.160.0/20\n20.249.255.0/24\n20.251.0.0/22\n27.0.128.0/22\n27.0.132.0/24\n27.0.134.0/23\n27.0.160.0/21\n27.0.188.0/22\n27.0.204.0/22\n27.0.208.0/21\n27.8.0.0/13\n27.16.0.0/12\n27.34.232.0/21\n27.36.0.0/14\n27.40.0.0/13\n27.50.40.0/21\n27.50.128.0/17\n27.54.72.0/21\n27.54.152.0/21\n27.54.192.0/18\n27.98.208.0/20\n27.98.224.0/19\n27.99.128.0/17\n27.103.0.0/16\n27.106.128.0/18\n27.106.204.0/22\n27.109.32.0/19\n27.109.124.0/22\n27.112.0.0/18\n27.112.80.0/20\n27.112.112.0/21\n27.113.128.0/18\n27.115.0.0/17\n27.116.44.0/22\n27.121.72.0/21\n27.121.120.0/21\n27.128.0.0/15\n27.131.220.0/22\n27.144.0.0/16\n27.148.0.0/14\n27.152.0.0/13\n27.184.0.0/13\n27.192.0.0/11\n27.224.0.0/14\n36.0.0.0/22\n36.0.16.0/20\n36.0.32.0/19\n36.0.64.0/18\n36.0.128.0/17\n36.1.0.0/16\n36.4.0.0/14\n36.16.0.0/12\n36.32.0.0/14\n36.36.0.0/16\n36.37.0.0/19\n36.37.36.0/23\n36.37.39.0/24\n36.37.40.0/21\n36.37.48.0/20\n36.40.0.0/13\n36.48.0.0/15\n36.51.0.0/17\n36.51.128.0/18\n36.51.192.0/19\n36.51.224.0/20\n36.51.240.0/21\n36.51.250.0/23\n36.51.252.0/23\n36.56.0.0/13\n36.96.0.0/11\n36.128.0.0/10\n36.192.0.0/11\n36.248.0.0/14\n36.254.0.0/16\n36.255.116.0/22\n36.255.128.0/22\n36.255.164.0/22\n36.255.172.0/22\n36.255.176.0/22\n39.0.0.0/24\n39.0.2.0/23\n39.0.4.0/22\n39.0.8.0/21\n39.0.16.0/20\n39.0.32.0/19\n39.0.64.0/18\n39.0.128.0/17\n39.64.0.0/11\n39.96.0.0/16\n39.97.0.0/17\n39.97.128.0/18\n39.97.192.0/21\n39.97.200.0/22\n39.97.208.0/20\n39.97.224.0/19\n39.98.0.0/15\n39.100.0.0/14\n39.104.0.0/14\n39.108.0.0/16\n39.109.120.0/23\n39.128.0.0/10\n40.0.176.0/20\n40.0.248.0/21\n40.72.0.0/15\n40.77.136.112/28\n40.77.236.224/27\n40.77.254.64/27\n40.125.128.0/17\n40.126.64.0/18\n40.198.10.0/24\n40.198.16.0/21\n40.198.24.0/23\n40.251.225.0/24\n40.251.227.0/24\n42.0.0.0/22\n42.0.8.0/21\n42.0.16.0/21\n42.0.24.0/22\n42.0.32.0/19\n42.0.128.0/17\n42.1.0.0/19\n42.1.32.0/20\n42.1.48.0/21\n42.1.56.0/22\n42.4.0.0/14\n42.48.0.0/13\n42.56.0.0/14\n42.62.0.0/17\n42.62.128.0/19\n42.62.160.0/20\n42.62.180.0/22\n42.62.184.0/21\n42.63.0.0/16\n42.80.0.0/15\n42.83.64.0/20\n42.83.80.0/22\n42.83.88.0/21\n42.83.96.0/19\n42.83.128.0/23\n42.83.134.0/24\n42.83.138.0/23\n42.83.140.0/22\n42.83.144.0/20\n42.83.160.0/19\n42.83.192.0/18\n42.84.0.0/14\n42.88.0.0/13\n42.96.64.0/19\n42.96.96.0/21\n42.96.108.0/22\n42.96.112.0/20\n42.96.128.0/17\n42.97.0.0/16\n42.99.0.0/18\n42.99.64.0/19\n42.99.96.0/20\n42.99.112.0/22\n42.99.120.0/21\n42.100.0.0/14\n42.120.0.0/15\n42.122.0.0/16\n42.123.0.0/19\n42.123.36.0/22\n42.123.40.0/21\n42.123.48.0/20\n42.123.64.0/18\n42.123.128.0/17\n42.128.0.0/12\n42.156.0.0/19\n42.156.36.0/22\n42.156.40.0/21\n42.156.48.0/20\n42.156.64.0/18\n42.156.128.0/17\n42.157.0.0/21\n42.157.8.0/22\n42.157.14.0/23\n42.157.16.0/20\n42.157.32.0/19\n42.157.64.0/18\n42.157.128.0/17\n42.158.0.0/15\n42.160.0.0/12\n42.176.0.0/13\n42.184.0.0/15\n42.186.0.0/16\n42.187.0.0/18\n42.187.64.0/19\n42.187.96.0/20\n42.187.112.0/21\n42.187.120.0/22\n42.187.128.0/17\n42.192.0.0/13\n42.201.0.0/17\n42.202.0.0/15\n42.204.0.0/14\n42.208.0.0/12\n42.224.0.0/12\n42.240.0.0/16\n42.242.0.0/15\n42.244.0.0/15\n42.246.0.0/16\n42.247.0.0/22\n42.247.4.0/24\n42.247.5.0/25\n42.247.5.128/26\n42.247.5.204/30\n42.247.5.208/28\n42.247.5.224/27\n42.247.6.0/23\n42.247.8.0/21\n42.247.16.0/20\n42.247.32.0/19\n42.247.64.0/18\n42.247.128.0/17\n42.248.0.0/13\n43.0.0.0/10\n43.64.0.0/12\n43.80.0.0/13\n43.88.128.0/17\n43.89.0.0/16\n43.90.0.0/15\n43.95.64.0/19\n43.95.96.0/20\n43.95.112.0/21\n43.96.0.0/11\n43.130.128.0/17\n43.131.128.0/17\n43.132.8.0/21\n43.132.16.0/20\n43.132.32.0/19\n43.132.69.0/24\n43.132.70.0/23\n43.132.72.0/23\n43.132.75.0/24\n43.132.78.0/23\n43.132.80.0/23\n43.132.82.0/24\n43.132.84.0/22\n43.132.88.0/21\n43.133.192.0/18\n43.134.0.0/15\n43.136.0.0/13\n43.144.0.0/12\n43.160.0.0/11\n43.224.12.0/22\n43.224.24.0/22\n43.224.44.0/22\n43.224.52.0/22\n43.224.56.0/22\n43.224.68.0/22\n43.224.72.0/22\n43.224.80.0/22\n43.224.100.0/22\n43.224.144.0/22\n43.224.161.0/24\n43.224.176.0/22\n43.224.184.0/22\n43.224.200.0/21\n43.224.208.0/21\n43.224.216.0/22\n43.224.240.0/22\n43.225.76.0/22\n43.225.86.0/24\n43.225.120.0/22\n43.225.180.0/22\n43.225.208.0/22\n43.225.216.0/21\n43.225.224.0/20\n43.225.240.0/21\n43.225.252.0/22\n43.226.32.0/19\n43.226.64.0/19\n43.226.96.0/20\n43.226.112.0/21\n43.226.120.0/22\n43.226.128.0/19\n43.226.160.0/21\n43.226.236.0/22\n43.226.240.0/20\n43.227.0.0/21\n43.227.8.0/22\n43.227.32.0/19\n43.227.64.0/19\n43.227.104.0/22\n43.227.136.0/21\n43.227.144.0/22\n43.227.152.0/21\n43.227.160.0/20\n43.227.176.0/21\n43.227.188.0/22\n43.227.192.0/19\n43.227.232.0/22\n43.227.248.0/21\n43.228.0.0/18\n43.228.64.0/21\n43.228.76.0/22\n43.228.100.0/22\n43.228.116.0/22\n43.228.132.0/22\n43.228.136.0/22\n43.228.148.0/22\n43.228.152.0/22\n43.228.188.0/22\n43.229.40.0/22\n43.229.48.0/22\n43.229.56.0/22\n43.229.96.0/22\n43.229.136.0/21\n43.229.168.0/21\n43.229.176.0/20\n43.229.192.0/21\n43.229.216.0/21\n43.229.232.0/21\n43.230.20.0/22\n43.230.32.0/22\n43.230.68.0/22\n43.230.72.0/22\n43.230.124.0/22\n43.230.220.0/22\n43.230.224.0/19\n43.231.32.0/20\n43.231.80.0/20\n43.231.96.0/20\n43.231.136.0/21\n43.231.144.0/20\n43.231.160.0/20\n43.231.176.0/21\n43.236.0.0/15\n43.238.0.0/16\n43.239.0.0/19\n43.239.32.0/20\n43.239.48.0/22\n43.239.116.0/22\n43.239.120.0/22\n43.239.172.0/22\n43.240.0.0/22\n43.240.56.0/21\n43.240.68.0/22\n43.240.72.0/21\n43.240.84.0/22\n43.240.124.0/22\n43.240.128.0/21\n43.240.136.0/22\n43.240.156.0/22\n43.240.160.0/19\n43.240.192.0/19\n43.240.240.0/20\n43.241.0.0/20\n43.241.16.0/21\n43.241.48.0/22\n43.241.76.0/22\n43.241.80.0/20\n43.241.112.0/22\n43.241.168.0/21\n43.241.176.0/21\n43.241.184.0/22\n43.241.208.0/20\n43.241.224.0/20\n43.241.240.0/22\n43.241.248.0/22\n43.242.8.0/21\n43.242.16.0/20\n43.242.48.0/22\n43.242.53.0/24\n43.242.54.0/24\n43.242.56.0/21\n43.242.64.0/22\n43.242.72.0/21\n43.242.80.0/20\n43.242.96.0/22\n43.242.144.0/20\n43.242.160.0/21\n43.242.180.0/22\n43.242.188.0/22\n43.242.192.0/21\n43.242.204.0/22\n43.242.216.0/21\n43.242.252.0/22\n43.243.4.0/22\n43.243.8.0/21\n43.243.16.0/22\n43.243.88.0/22\n43.243.128.0/22\n43.243.136.0/22\n43.243.144.0/21\n43.243.156.0/22\n43.243.180.0/22\n43.243.228.0/22\n43.243.232.0/22\n43.243.244.0/22\n43.246.0.0/18\n43.246.64.0/19\n43.246.96.0/22\n43.246.148.0/24\n43.246.150.0/24\n43.246.228.0/22\n43.247.4.0/22\n43.247.8.0/22\n43.247.44.0/22\n43.247.48.0/22\n43.247.68.0/22\n43.247.76.0/22\n43.247.84.0/22\n43.247.88.0/21\n43.247.96.0/21\n43.247.108.0/22\n43.247.112.0/22\n43.247.148.0/22\n43.247.152.0/22\n43.247.176.0/20\n43.247.196.0/22\n43.247.200.0/21\n43.247.208.0/20\n43.247.224.0/19\n43.248.0.0/21\n43.248.20.0/22\n43.248.28.0/22\n43.248.48.0/22\n43.248.76.0/22\n43.248.80.0/20\n43.248.96.0/19\n43.248.128.0/20\n43.248.144.0/21\n43.248.176.0/20\n43.248.192.0/20\n43.248.208.0/22\n43.248.228.0/22\n43.248.232.0/22\n43.248.244.0/22\n43.249.4.0/22\n43.249.120.0/22\n43.249.132.0/22\n43.249.136.0/22\n43.249.144.0/20\n43.249.160.0/21\n43.249.168.0/22\n43.249.192.0/22\n43.249.236.0/22\n43.250.4.0/22\n43.250.12.0/22\n43.250.16.0/21\n43.250.28.0/22\n43.250.32.0/22\n43.250.96.0/21\n43.250.108.0/22\n43.250.112.0/22\n43.250.118.0/23\n43.250.128.0/22\n43.250.144.0/21\n43.250.160.0/22\n43.250.168.0/22\n43.250.176.0/22\n43.250.200.0/22\n43.250.212.0/22\n43.250.216.0/21\n43.250.236.0/22\n43.250.244.0/22\n43.251.4.0/22\n43.251.36.0/22\n43.251.69.0/24\n43.251.70.0/24\n43.251.149.0/24\n43.251.192.0/22\n43.251.232.0/22\n43.251.244.0/22\n43.252.48.0/22\n43.252.56.0/22\n43.252.224.0/22\n43.254.0.0/21\n43.254.8.0/22\n43.254.24.0/22\n43.254.36.0/22\n43.254.44.0/22\n43.254.52.0/22\n43.254.64.0/22\n43.254.72.0/22\n43.254.84.0/22\n43.254.88.0/21\n43.254.100.0/22\n43.254.104.0/22\n43.254.112.0/21\n43.254.128.0/22\n43.254.136.0/21\n43.254.144.0/20\n43.254.168.0/21\n43.254.180.0/22\n43.254.184.0/21\n43.254.192.0/22\n43.254.200.0/22\n43.254.208.0/22\n43.254.220.0/22\n43.254.224.0/20\n43.254.240.0/22\n43.254.248.0/21\n43.255.0.0/21\n43.255.8.0/22\n43.255.16.0/22\n43.255.48.0/22\n43.255.64.0/20\n43.255.84.0/22\n43.255.96.0/22\n43.255.144.0/22\n43.255.176.0/22\n43.255.184.0/22\n43.255.192.0/22\n43.255.200.0/21\n43.255.208.0/21\n43.255.224.0/21\n43.255.232.0/22\n43.255.244.0/22\n45.40.192.0/20\n45.40.208.0/21\n45.40.224.0/19\n45.65.16.0/20\n45.87.53.0/24\n45.87.54.0/23\n45.112.132.0/22\n45.112.188.0/22\n45.112.208.0/20\n45.112.228.0/22\n45.112.232.0/21\n45.113.12.0/22\n45.113.16.0/20\n45.113.40.0/22\n45.113.52.0/22\n45.113.72.0/22\n45.113.144.0/21\n45.113.168.0/22\n45.113.184.0/22\n45.113.200.0/21\n45.113.208.0/20\n45.113.240.0/22\n45.113.252.0/22\n45.114.0.0/22\n45.114.32.0/22\n45.114.52.0/22\n45.114.96.0/22\n45.114.136.0/22\n45.114.196.0/22\n45.114.200.0/22\n45.114.228.0/22\n45.114.252.0/22\n45.115.44.0/22\n45.115.100.0/22\n45.115.120.0/22\n45.115.132.0/22\n45.115.144.0/22\n45.115.156.0/22\n45.115.164.0/22\n45.115.200.0/22\n45.115.212.0/22\n45.115.244.0/22\n45.115.248.0/22\n45.116.16.0/22\n45.116.24.0/22\n45.116.32.0/21\n45.116.52.0/22\n45.116.96.0/21\n45.116.140.0/22\n45.116.152.0/22\n45.116.208.0/22\n45.117.8.0/22\n45.117.20.0/22\n45.117.68.0/22\n45.117.124.0/22\n45.117.252.0/22\n45.119.60.0/22\n45.119.64.0/21\n45.119.72.0/22\n45.119.104.0/22\n45.119.232.0/22\n45.120.100.0/22\n45.120.140.0/22\n45.120.164.0/22\n45.120.180.128/27\n45.120.240.0/24\n45.120.242.0/23\n45.121.52.0/22\n45.121.64.0/21\n45.121.72.0/22\n45.121.92.0/22\n45.121.96.0/22\n45.121.172.0/22\n45.121.176.0/22\n45.121.240.0/20\n45.122.0.0/19\n45.122.32.0/21\n45.122.40.0/22\n45.122.60.0/22\n45.122.64.0/19\n45.122.96.0/20\n45.122.112.0/21\n45.122.160.0/19\n45.122.192.0/20\n45.122.208.0/21\n45.122.216.0/22\n45.123.28.0/22\n45.123.32.0/21\n45.123.44.0/22\n45.123.48.0/20\n45.123.64.0/20\n45.123.80.0/21\n45.123.120.0/22\n45.123.128.0/21\n45.123.136.0/22\n45.123.148.0/22\n45.123.152.0/21\n45.123.164.0/22\n45.123.168.0/21\n45.123.176.0/21\n45.123.184.0/22\n45.123.204.0/22\n45.123.212.0/22\n45.123.224.0/19\n45.124.0.0/22\n45.124.20.0/22\n45.124.28.0/22\n45.124.32.0/21\n45.124.44.0/22\n45.124.68.0/22\n45.124.76.0/22\n45.124.80.0/22\n45.124.100.0/22\n45.124.124.0/22\n45.124.172.0/22\n45.124.176.0/22\n45.124.208.0/22\n45.124.248.0/22\n45.125.24.0/22\n45.125.44.0/22\n45.125.52.0/22\n45.125.56.0/22\n45.125.76.0/22\n45.125.80.0/20\n45.125.96.0/21\n45.125.136.0/22\n45.126.48.0/21\n45.126.108.0/22\n45.126.112.0/21\n45.126.120.0/22\n45.126.220.0/22\n45.127.8.0/21\n45.127.128.0/22\n45.127.144.0/21\n45.127.156.0/22\n45.248.8.0/22\n45.248.80.0/22\n45.248.88.0/22\n45.248.96.0/20\n45.248.128.0/21\n45.248.204.0/22\n45.248.208.0/20\n45.248.224.0/19\n45.249.0.0/21\n45.249.12.0/22\n45.249.16.0/20\n45.249.32.0/21\n45.249.112.0/22\n45.249.188.0/22\n45.249.192.0/20\n45.249.208.0/21\n45.250.12.0/22\n45.250.16.0/22\n45.250.28.0/22\n45.250.32.0/21\n45.250.40.0/22\n45.250.76.0/22\n45.250.80.0/20\n45.250.96.0/22\n45.250.104.0/21\n45.250.112.0/20\n45.250.128.0/20\n45.250.144.0/21\n45.250.152.0/22\n45.250.164.0/22\n45.250.180.0/22\n45.250.184.0/21\n45.250.192.0/22\n45.251.0.0/22\n45.251.8.0/22\n45.251.16.0/21\n45.251.52.0/22\n45.251.84.0/22\n45.251.88.0/21\n45.251.96.0/21\n45.251.120.0/21\n45.251.138.0/23\n45.251.140.0/22\n45.251.144.0/20\n45.251.160.0/19\n45.251.192.0/19\n45.251.224.0/22\n45.252.0.0/19\n45.252.32.0/20\n45.252.48.0/22\n45.252.84.0/22\n45.252.88.0/21\n45.252.96.0/19\n45.252.128.0/19\n45.252.160.0/20\n45.252.176.0/22\n45.252.192.0/19\n45.252.224.0/21\n45.252.232.0/22\n45.253.0.0/18\n45.253.64.0/20\n45.253.80.0/21\n45.253.92.0/22\n45.253.96.0/20\n45.253.112.0/21\n45.253.120.0/22\n45.253.132.0/22\n45.253.136.0/21\n45.253.144.0/20\n45.253.160.0/19\n45.253.192.0/19\n45.253.224.0/20\n45.253.240.0/22\n45.254.0.0/20\n45.254.16.0/21\n45.254.28.0/22\n45.254.40.0/22\n45.254.48.0/20\n45.254.64.0/18\n45.254.128.0/18\n45.254.192.0/19\n45.254.224.0/21\n45.254.236.0/22\n45.254.248.0/22\n45.255.0.0/18\n45.255.64.0/19\n45.255.96.0/20\n45.255.112.0/21\n45.255.120.0/22\n45.255.136.0/21\n45.255.144.0/20\n45.255.160.0/19\n45.255.192.0/19\n45.255.224.0/20\n45.255.240.0/21\n45.255.248.0/22\n46.248.24.0/23\n47.92.0.0/14\n47.96.0.0/11\n49.4.0.0/14\n49.51.57.0/24\n49.51.58.0/23\n49.51.60.0/23\n49.51.110.0/23\n49.51.112.0/20\n49.52.0.0/14\n49.64.0.0/11\n49.112.0.0/13\n49.120.0.0/14\n49.128.0.0/24\n49.128.2.0/23\n49.140.0.0/15\n49.152.0.0/14\n49.208.0.0/14\n49.220.0.0/14\n49.232.0.0/14\n49.239.0.0/18\n49.239.192.0/18\n52.80.0.0/14\n52.93.242.120/29\n52.93.242.128/25\n52.94.249.0/27\n52.130.0.0/15\n54.222.0.0/15\n54.240.224.0/24\n58.14.0.0/15\n58.16.0.0/13\n58.24.0.0/15\n58.30.0.0/15\n58.32.0.0/11\n58.65.232.0/21\n58.66.0.0/15\n58.68.128.0/19\n58.68.160.0/21\n58.68.200.0/21\n58.68.208.0/20\n58.68.224.0/19\n58.82.0.0/17\n58.83.0.0/16\n58.87.64.0/18\n58.99.128.0/17\n58.100.0.0/15\n58.116.0.0/14\n58.128.0.0/13\n58.144.0.0/16\n58.154.0.0/15\n58.192.0.0/11\n58.240.0.0/12\n59.32.0.0/11\n59.64.0.0/12\n59.80.0.0/15\n59.82.0.0/16\n59.83.0.0/18\n59.83.136.0/21\n59.83.144.0/20\n59.83.160.0/20\n59.83.180.0/22\n59.83.184.0/21\n59.83.192.0/19\n59.83.224.0/20\n59.83.240.0/21\n59.83.248.0/22\n59.83.252.0/23\n59.83.254.0/24\n59.107.0.0/16\n59.108.0.0/14\n59.151.0.0/17\n59.152.16.0/20\n59.152.36.0/22\n59.152.64.0/20\n59.152.112.0/21\n59.153.4.0/22\n59.153.32.0/22\n59.153.64.0/21\n59.153.72.0/22\n59.153.92.0/22\n59.153.136.0/22\n59.153.152.0/22\n59.153.159.0/24\n59.153.164.0/22\n59.153.168.0/21\n59.153.176.0/20\n59.153.192.0/22\n59.155.0.0/16\n59.172.0.0/14\n59.191.0.0/17\n59.192.0.0/10\n60.0.0.0/11\n60.55.0.0/16\n60.63.0.0/16\n60.160.0.0/11\n60.194.0.0/15\n60.200.0.0/13\n60.208.0.0/12\n60.232.0.0/15\n60.235.0.0/16\n60.245.128.0/17\n60.247.0.0/16\n60.252.0.0/16\n60.253.128.0/17\n60.255.0.0/16\n61.4.81.0/24\n61.4.82.0/23\n61.4.84.0/22\n61.4.88.0/21\n61.4.176.0/20\n61.8.160.0/20\n61.14.212.0/22\n61.14.216.0/21\n61.14.240.0/21\n61.28.0.0/17\n61.29.128.0/18\n61.29.194.0/23\n61.29.196.0/22\n61.29.200.0/21\n61.29.208.0/20\n61.29.224.0/20\n61.45.128.0/18\n61.45.224.0/20\n61.47.128.0/18\n61.48.0.0/13\n61.87.192.0/18\n61.128.0.0/10\n61.232.0.0/14\n61.236.0.0/15\n61.240.0.0/14\n62.234.0.0/16\n64.188.38.0/23\n64.188.40.0/22\n64.188.44.0/23\n68.79.0.0/18\n69.230.192.0/18\n69.231.128.0/18\n69.234.192.0/18\n69.235.128.0/18\n71.131.192.0/18\n71.132.0.0/18\n71.136.64.0/18\n71.137.0.0/18\n72.163.240.0/23\n72.163.248.0/22\n81.68.0.0/14\n82.156.0.0/15\n87.254.207.0/24\n93.183.14.0/24\n93.183.18.0/24\n94.191.0.0/17\n101.0.0.0/22\n101.1.0.0/22\n101.2.172.0/22\n101.4.0.0/14\n101.16.0.0/12\n101.33.20.0/23\n101.33.128.0/17\n101.34.0.0/15\n101.36.0.0/18\n101.36.64.0/20\n101.36.88.0/21\n101.36.128.0/17\n101.37.0.0/16\n101.38.0.0/15\n101.40.0.0/13\n101.48.0.0/15\n101.50.8.0/21\n101.50.56.0/22\n101.52.0.0/16\n101.53.100.0/22\n101.54.0.0/16\n101.55.224.0/21\n101.64.0.0/13\n101.72.0.0/14\n101.76.0.0/15\n101.78.0.0/22\n101.78.32.0/19\n101.80.0.0/12\n101.96.0.0/21\n101.96.8.0/22\n101.96.16.0/20\n101.96.128.0/17\n101.99.96.0/19\n101.101.64.0/19\n101.101.100.0/24\n101.101.102.0/23\n101.101.104.0/21\n101.101.112.0/20\n101.102.64.0/19\n101.102.100.0/23\n101.102.102.0/24\n101.102.104.0/21\n101.102.112.0/20\n101.104.0.0/14\n101.110.64.0/19\n101.110.96.0/20\n101.110.116.0/22\n101.110.120.0/21\n101.120.0.0/14\n101.124.0.0/15\n101.126.0.0/16\n101.128.0.0/22\n101.128.8.0/21\n101.128.16.0/20\n101.128.32.0/19\n101.129.0.0/16\n101.130.0.0/15\n101.132.0.0/15\n101.134.0.0/17\n101.134.128.0/19\n101.134.160.0/20\n101.134.176.0/21\n101.134.184.0/22\n101.134.189.0/24\n101.134.190.0/23\n101.134.192.0/18\n101.135.0.0/16\n101.144.0.0/12\n101.192.0.0/14\n101.196.0.0/16\n101.198.0.0/22\n101.198.128.0/24\n101.198.170.0/23\n101.198.172.0/22\n101.198.176.0/21\n101.198.184.0/22\n101.198.189.0/24\n101.198.190.0/23\n101.198.194.0/24\n101.198.196.0/23\n101.198.200.0/22\n101.198.224.0/19\n101.199.0.0/19\n101.199.48.0/20\n101.199.64.0/18\n101.199.128.0/17\n101.200.0.0/15\n101.203.128.0/19\n101.203.160.0/21\n101.203.172.0/22\n101.203.176.0/20\n101.204.0.0/14\n101.224.0.0/13\n101.232.0.0/15\n101.234.64.0/21\n101.234.76.0/22\n101.234.80.0/20\n101.234.96.0/19\n101.236.0.0/14\n101.240.0.0/13\n101.248.0.0/15\n101.251.0.0/22\n101.251.8.0/21\n101.251.16.0/20\n101.251.32.0/19\n101.251.64.0/18\n101.251.128.0/17\n101.252.0.0/15\n101.254.0.0/16\n103.1.8.0/22\n103.1.20.0/22\n103.1.24.0/22\n103.1.88.0/22\n103.1.168.0/22\n103.2.108.0/22\n103.2.156.0/22\n103.2.164.0/22\n103.2.200.0/21\n103.2.208.0/21\n103.3.84.0/22\n103.3.88.0/21\n103.3.96.0/19\n103.3.128.0/20\n103.3.148.0/22\n103.3.152.0/21\n103.4.56.0/22\n103.4.168.0/22\n103.4.184.0/22\n103.5.36.0/22\n103.5.52.0/24\n103.5.56.0/22\n103.5.152.0/22\n103.5.168.0/22\n103.5.192.0/22\n103.5.252.0/22\n103.6.76.0/22\n103.6.120.0/22\n103.6.220.0/22\n103.7.140.0/22\n103.7.212.0/22\n103.7.216.0/21\n103.8.0.0/21\n103.8.8.0/22\n103.8.32.0/22\n103.8.52.0/22\n103.8.68.0/22\n103.8.108.0/22\n103.8.156.0/22\n103.8.200.0/21\n103.8.220.0/22\n103.9.8.0/22\n103.9.24.0/22\n103.9.108.0/22\n103.9.152.0/22\n103.9.248.0/21\n103.10.0.0/22\n103.10.16.0/22\n103.10.84.0/22\n103.10.111.0/24\n103.10.140.0/22\n103.11.16.0/22\n103.11.168.0/22\n103.11.180.0/22\n103.12.32.0/22\n103.12.136.0/22\n103.12.184.0/22\n103.12.232.0/22\n103.13.12.0/22\n103.13.124.0/22\n103.13.145.0/24\n103.13.147.0/24\n103.13.196.0/22\n103.13.244.0/22\n103.14.84.0/22\n103.14.132.0/22\n103.14.136.0/22\n103.14.156.0/22\n103.14.240.0/22\n103.15.4.0/22\n103.15.8.0/22\n103.15.16.0/22\n103.15.96.0/22\n103.15.200.0/22\n103.16.52.0/22\n103.16.80.0/21\n103.16.88.0/22\n103.16.108.0/22\n103.16.124.0/22\n103.17.40.0/22\n103.17.64.0/22\n103.17.120.0/23\n103.17.136.0/22\n103.17.160.0/22\n103.17.204.0/22\n103.17.228.0/22\n103.18.192.0/22\n103.18.208.0/21\n103.18.224.0/22\n103.19.12.0/22\n103.19.40.0/21\n103.19.64.0/21\n103.19.72.0/22\n103.19.232.0/22\n103.20.12.0/22\n103.20.32.0/23\n103.20.34.0/24\n103.20.68.0/22\n103.20.112.0/22\n103.20.128.0/22\n103.20.160.0/22\n103.20.248.0/22\n103.21.112.0/21\n103.21.140.0/22\n103.21.176.0/22\n103.21.240.0/24\n103.21.242.0/23\n103.22.0.0/18\n103.22.64.0/19\n103.22.100.0/22\n103.22.104.0/21\n103.22.112.0/20\n103.22.188.0/22\n103.22.228.0/22\n103.22.252.0/22\n103.23.8.0/22\n103.23.56.0/22\n103.23.160.0/22\n103.23.164.0/23\n103.23.166.0/24\n103.23.176.0/22\n103.23.228.0/22\n103.24.24.0/22\n103.24.116.0/22\n103.24.128.0/22\n103.24.144.0/22\n103.24.176.0/22\n103.24.184.0/22\n103.24.228.0/22\n103.24.252.0/22\n103.25.20.0/22\n103.25.24.0/21\n103.25.32.0/21\n103.25.40.0/22\n103.25.48.0/22\n103.25.64.0/21\n103.25.148.0/22\n103.25.156.0/22\n103.25.216.0/22\n103.26.0.0/22\n103.26.64.0/22\n103.26.76.0/22\n103.26.116.0/22\n103.26.156.0/22\n103.26.160.0/22\n103.26.228.0/22\n103.26.240.0/22\n103.27.4.0/22\n103.27.12.0/22\n103.27.24.0/22\n103.27.56.0/22\n103.27.96.0/22\n103.27.240.0/22\n103.28.4.0/22\n103.28.8.0/22\n103.28.184.0/22\n103.28.204.0/22\n103.28.212.0/22\n103.29.16.0/22\n103.29.128.0/21\n103.29.136.0/22\n103.30.20.0/22\n103.30.96.0/22\n103.30.148.0/22\n103.30.202.0/23\n103.30.228.0/22\n103.30.236.0/22\n103.31.0.0/22\n103.31.48.0/21\n103.31.60.0/22\n103.31.64.0/21\n103.31.72.0/24\n103.31.148.0/22\n103.31.160.0/22\n103.31.168.0/22\n103.31.200.0/22\n103.32.0.0/15\n103.34.0.0/16\n103.35.0.0/19\n103.35.32.0/20\n103.35.48.0/22\n103.35.104.0/22\n103.35.220.0/22\n103.36.28.0/22\n103.36.36.0/22\n103.36.56.0/21\n103.36.64.0/22\n103.36.72.0/22\n103.36.96.0/22\n103.36.132.0/22\n103.36.136.0/22\n103.36.160.0/19\n103.36.192.0/19\n103.36.224.0/20\n103.36.240.0/21\n103.37.12.0/22\n103.37.16.0/22\n103.37.24.0/22\n103.37.44.0/22\n103.37.52.0/22\n103.37.56.0/22\n103.37.72.0/22\n103.37.100.0/22\n103.37.104.0/22\n103.37.136.0/21\n103.37.144.0/20\n103.37.160.0/21\n103.37.172.0/22\n103.37.176.0/22\n103.37.188.0/22\n103.37.208.0/20\n103.37.252.0/22\n103.38.0.0/22\n103.38.32.0/22\n103.38.40.0/21\n103.38.76.0/22\n103.38.84.0/22\n103.38.92.0/22\n103.38.96.0/22\n103.38.116.0/22\n103.38.132.0/22\n103.38.140.0/22\n103.38.220.0/22\n103.38.224.0/21\n103.38.232.0/22\n103.38.252.0/23\n103.39.64.0/22\n103.39.88.0/22\n103.39.100.0/22\n103.39.104.0/22\n103.39.160.0/19\n103.39.200.0/21\n103.39.208.0/20\n103.39.224.0/21\n103.39.232.0/22\n103.40.12.0/22\n103.40.16.0/20\n103.40.32.0/20\n103.40.88.0/22\n103.40.192.0/22\n103.40.212.0/22\n103.40.220.0/22\n103.40.228.0/22\n103.40.232.0/21\n103.40.240.0/20\n103.41.0.0/22\n103.41.52.0/22\n103.41.140.0/22\n103.41.148.0/22\n103.41.152.0/22\n103.41.160.0/21\n103.41.220.0/22\n103.41.224.0/21\n103.42.8.0/22\n103.42.24.0/22\n103.42.32.0/22\n103.42.64.0/21\n103.42.76.0/22\n103.42.232.0/22\n103.43.26.0/23\n103.43.96.0/21\n103.43.104.0/22\n103.43.124.0/22\n103.43.184.0/22\n103.43.192.0/21\n103.43.208.0/22\n103.43.220.0/22\n103.43.224.0/22\n103.43.240.0/22\n103.44.80.0/22\n103.44.120.0/21\n103.44.144.0/22\n103.44.152.0/22\n103.44.168.0/22\n103.44.176.0/20\n103.44.192.0/20\n103.44.224.0/22\n103.44.236.0/22\n103.44.240.0/20\n103.45.0.0/18\n103.45.72.0/21\n103.45.80.0/20\n103.45.96.0/19\n103.45.128.0/18\n103.45.192.0/19\n103.45.224.0/22\n103.45.248.0/22\n103.46.0.0/22\n103.46.12.0/22\n103.46.16.0/20\n103.46.32.0/19\n103.46.64.0/18\n103.46.128.0/21\n103.46.136.0/22\n103.46.152.0/21\n103.46.160.0/20\n103.46.176.0/21\n103.46.244.0/22\n103.46.248.0/22\n103.47.4.0/22\n103.47.20.0/22\n103.47.36.0/22\n103.47.40.0/22\n103.47.48.0/22\n103.47.80.0/22\n103.47.96.0/22\n103.47.116.0/22\n103.47.120.0/22\n103.47.136.0/21\n103.47.212.0/22\n103.48.52.0/22\n103.48.92.0/22\n103.48.148.0/22\n103.48.152.0/22\n103.48.202.0/23\n103.48.216.0/21\n103.48.224.0/20\n103.48.240.0/21\n103.49.12.0/22\n103.49.20.0/22\n103.49.72.0/21\n103.49.96.0/22\n103.49.108.0/22\n103.49.176.0/21\n103.50.36.0/22\n103.50.44.0/22\n103.50.48.0/20\n103.50.64.0/21\n103.50.72.0/22\n103.50.108.0/22\n103.50.112.0/20\n103.50.132.0/22\n103.50.136.0/21\n103.50.172.0/22\n103.50.176.0/20\n103.50.192.0/21\n103.50.200.0/22\n103.50.220.0/22\n103.50.224.0/20\n103.50.240.0/21\n103.50.248.0/22\n103.52.40.0/22\n103.52.72.0/21\n103.52.80.0/21\n103.52.96.0/21\n103.52.104.0/22\n103.52.160.0/21\n103.52.172.0/22\n103.52.176.0/22\n103.52.184.0/22\n103.52.196.0/22\n103.53.64.0/21\n103.53.92.0/22\n103.53.124.0/22\n103.53.128.0/20\n103.53.144.0/22\n103.53.160.0/22\n103.53.180.0/22\n103.53.204.0/22\n103.53.208.0/21\n103.53.236.0/22\n103.53.248.0/22\n103.54.8.0/22\n103.54.48.0/22\n103.54.160.0/21\n103.54.212.0/22\n103.54.228.0/22\n103.54.240.0/22\n103.55.80.0/22\n103.55.120.0/22\n103.55.152.0/22\n103.55.172.0/22\n103.55.204.0/22\n103.55.208.0/22\n103.55.228.0/22\n103.55.236.0/22\n103.55.240.0/22\n103.56.20.0/22\n103.56.32.0/22\n103.56.56.0/21\n103.56.72.0/21\n103.56.140.0/22\n103.56.152.0/22\n103.56.184.0/22\n103.56.200.0/22\n103.57.12.0/22\n103.57.52.0/22\n103.57.56.0/22\n103.57.76.0/22\n103.57.136.0/22\n103.57.196.0/22\n103.58.24.0/22\n103.59.76.0/22\n103.59.112.0/21\n103.59.120.0/24\n103.59.123.0/24\n103.59.124.0/22\n103.59.128.0/22\n103.59.148.0/22\n103.60.32.0/22\n103.60.44.0/22\n103.60.164.0/22\n103.60.228.0/22\n103.60.236.0/22\n103.61.60.0/24\n103.61.104.0/22\n103.61.140.0/22\n103.61.152.0/21\n103.61.160.0/22\n103.61.172.0/22\n103.61.176.0/22\n103.62.24.0/22\n103.62.72.0/21\n103.62.80.0/21\n103.62.88.0/22\n103.62.96.0/19\n103.62.128.0/21\n103.62.156.0/22\n103.62.160.0/19\n103.62.192.0/22\n103.62.204.0/22\n103.62.208.0/20\n103.62.224.0/22\n103.63.32.0/19\n103.63.64.0/20\n103.63.80.0/21\n103.63.88.0/22\n103.63.140.0/22\n103.63.144.0/22\n103.63.152.0/22\n103.63.160.0/20\n103.63.176.0/21\n103.63.184.0/22\n103.63.192.0/20\n103.63.208.0/22\n103.63.240.0/20\n103.64.0.0/21\n103.64.24.0/21\n103.64.32.0/19\n103.64.64.0/18\n103.64.140.0/22\n103.64.144.0/22\n103.64.152.0/21\n103.64.160.0/19\n103.64.192.0/18\n103.65.0.0/20\n103.65.16.0/22\n103.65.48.0/20\n103.65.64.0/19\n103.65.100.0/22\n103.65.104.0/21\n103.65.112.0/20\n103.65.128.0/21\n103.65.136.0/22\n103.65.144.0/20\n103.65.160.0/20\n103.66.32.0/22\n103.66.40.0/22\n103.66.108.0/22\n103.66.200.0/22\n103.66.240.0/20\n103.67.0.0/21\n103.67.8.0/22\n103.67.40.0/21\n103.67.48.0/20\n103.67.64.0/18\n103.67.128.0/20\n103.67.144.0/21\n103.67.172.0/24\n103.67.175.0/24\n103.67.192.0/22\n103.67.212.0/22\n103.68.88.0/22\n103.68.100.0/22\n103.68.128.0/22\n103.69.16.0/22\n103.70.8.0/22\n103.70.148.0/22\n103.70.236.0/22\n103.70.252.0/22\n103.71.0.0/22\n103.71.68.0/22\n103.71.72.0/22\n103.71.80.0/21\n103.71.88.0/22\n103.71.120.0/21\n103.71.128.0/22\n103.71.196.0/22\n103.71.200.0/22\n103.71.232.0/22\n103.72.12.0/22\n103.72.16.0/20\n103.72.32.0/20\n103.72.48.0/21\n103.72.112.0/21\n103.72.124.0/22\n103.72.128.0/21\n103.72.149.0/24\n103.72.150.0/23\n103.72.172.0/22\n103.72.180.0/22\n103.72.224.0/19\n103.73.0.0/19\n103.73.48.0/22\n103.73.116.0/22\n103.73.120.0/22\n103.73.128.0/20\n103.73.168.0/22\n103.73.176.0/22\n103.73.204.0/22\n103.73.208.0/22\n103.73.240.0/23\n103.73.244.0/22\n103.73.248.0/22\n103.74.24.0/21\n103.74.32.0/20\n103.74.48.0/22\n103.74.56.0/21\n103.74.80.0/22\n103.74.124.0/22\n103.74.148.0/22\n103.74.152.0/21\n103.74.204.0/22\n103.74.232.0/22\n103.75.87.0/24\n103.75.88.0/21\n103.75.104.0/21\n103.75.112.0/22\n103.75.120.0/22\n103.75.128.0/22\n103.75.144.0/23\n103.75.146.0/24\n103.75.152.0/22\n103.76.60.0/22\n103.76.64.0/21\n103.76.72.0/22\n103.76.92.0/22\n103.76.216.0/21\n103.76.224.0/22\n103.77.28.0/22\n103.77.52.0/22\n103.77.56.0/22\n103.77.88.0/22\n103.77.132.0/22\n103.77.148.0/22\n103.77.220.0/22\n103.78.56.0/21\n103.78.64.0/22\n103.78.124.0/22\n103.78.172.0/22\n103.78.176.0/22\n103.78.196.0/22\n103.78.228.0/22\n103.79.24.0/21\n103.79.36.0/22\n103.79.40.0/21\n103.79.56.0/21\n103.79.64.0/21\n103.79.80.0/21\n103.79.136.0/22\n103.79.188.0/22\n103.79.192.0/20\n103.79.208.0/21\n103.80.44.0/22\n103.80.72.0/22\n103.80.176.0/21\n103.80.184.0/22\n103.80.192.0/22\n103.80.200.0/22\n103.80.232.0/22\n103.81.4.0/22\n103.81.44.0/22\n103.81.48.0/22\n103.81.96.0/22\n103.81.120.0/22\n103.81.148.0/22\n103.81.164.0/22\n103.81.200.0/22\n103.81.232.0/22\n103.82.60.0/22\n103.82.68.0/22\n103.82.84.0/22\n103.82.104.0/22\n103.82.224.0/22\n103.82.236.0/22\n103.83.44.0/22\n103.83.52.0/22\n103.83.60.0/22\n103.83.72.0/22\n103.83.112.0/22\n103.83.132.0/22\n103.83.180.0/22\n103.84.0.0/22\n103.84.12.0/22\n103.84.20.0/22\n103.84.24.0/21\n103.84.48.0/22\n103.84.56.0/22\n103.84.64.0/22\n103.84.72.0/22\n103.85.44.0/22\n103.85.48.0/21\n103.85.56.0/22\n103.85.84.0/22\n103.85.136.0/22\n103.85.144.0/22\n103.85.164.0/22\n103.85.168.0/21\n103.85.176.0/22\n103.86.28.0/22\n103.86.32.0/22\n103.86.60.0/22\n103.86.129.0/24\n103.86.204.0/22\n103.86.208.0/20\n103.86.224.0/19\n103.87.0.0/21\n103.87.20.0/22\n103.87.32.0/22\n103.87.96.0/22\n103.87.132.0/22\n103.87.180.0/22\n103.87.224.0/22\n103.88.4.0/22\n103.88.8.0/21\n103.88.16.0/21\n103.88.32.0/21\n103.88.60.0/22\n103.88.64.0/22\n103.88.72.0/22\n103.88.96.0/21\n103.88.152.0/23\n103.88.164.0/22\n103.88.212.0/22\n103.89.28.0/22\n103.89.96.0/20\n103.89.112.0/22\n103.89.148.0/22\n103.89.172.0/22\n103.89.184.0/21\n103.89.192.0/19\n103.89.224.0/21\n103.90.52.0/22\n103.90.92.0/22\n103.90.100.0/22\n103.90.104.0/21\n103.90.112.0/20\n103.90.128.0/21\n103.90.152.0/22\n103.90.168.0/22\n103.90.173.0/24\n103.90.176.0/22\n103.90.188.0/22\n103.90.192.0/22\n103.91.36.0/22\n103.91.40.0/22\n103.91.108.0/22\n103.91.152.0/22\n103.91.176.0/22\n103.91.200.0/22\n103.91.208.0/21\n103.91.236.0/22\n103.92.48.0/20\n103.92.64.0/20\n103.92.80.0/22\n103.92.88.0/22\n103.92.108.0/22\n103.92.124.0/22\n103.92.132.0/22\n103.92.156.0/22\n103.92.164.0/22\n103.92.168.0/21\n103.92.176.0/20\n103.92.192.0/22\n103.92.236.0/22\n103.92.240.0/20\n103.93.0.0/21\n103.93.28.0/22\n103.93.84.0/22\n103.93.152.0/22\n103.93.180.0/22\n103.93.204.0/22\n103.94.12.0/22\n103.94.20.0/22\n103.94.30.0/23\n103.94.32.0/20\n103.94.72.0/22\n103.94.88.0/22\n103.94.116.0/22\n103.94.160.0/22\n103.94.200.0/22\n103.95.52.0/22\n103.95.68.0/22\n103.95.88.0/21\n103.95.136.0/21\n103.95.144.0/22\n103.95.152.0/22\n103.95.216.0/21\n103.95.224.0/22\n103.95.236.0/22\n103.95.240.0/20\n103.96.8.0/22\n103.96.124.0/22\n103.96.136.0/22\n103.96.152.0/21\n103.96.160.0/19\n103.96.192.0/20\n103.96.208.0/21\n103.96.216.0/22\n103.97.40.0/22\n103.97.60.0/23\n103.97.112.0/21\n103.97.148.0/22\n103.97.188.0/22\n103.97.192.0/22\n103.98.40.0/21\n103.98.48.0/22\n103.98.56.0/22\n103.98.80.0/22\n103.98.88.0/22\n103.98.100.0/22\n103.98.124.0/24\n103.98.126.0/24\n103.98.136.0/21\n103.98.144.0/22\n103.98.164.0/22\n103.98.168.0/22\n103.98.180.0/22\n103.98.196.0/22\n103.98.216.0/21\n103.98.224.0/21\n103.98.232.0/22\n103.98.240.0/21\n103.98.250.0/24\n103.99.56.0/22\n103.99.104.0/22\n103.99.116.0/22\n103.99.120.0/22\n103.99.132.0/22\n103.99.136.0/21\n103.99.144.0/22\n103.99.152.0/22\n103.99.220.0/22\n103.99.232.0/21\n103.100.0.0/22\n103.100.32.0/22\n103.100.40.0/22\n103.100.48.0/22\n103.100.56.0/22\n103.100.64.0/22\n103.100.88.0/22\n103.100.116.0/22\n103.100.144.0/22\n103.100.240.0/22\n103.100.248.0/21\n103.101.4.0/22\n103.101.8.0/21\n103.101.60.0/22\n103.101.121.0/24\n103.101.122.0/23\n103.101.124.0/24\n103.101.126.0/23\n103.101.144.0/21\n103.101.180.0/22\n103.101.184.0/22\n103.102.76.0/22\n103.102.80.0/22\n103.102.168.0/21\n103.102.180.0/22\n103.102.184.0/21\n103.102.192.0/22\n103.102.196.0/24\n103.102.200.0/22\n103.102.208.0/21\n103.103.12.0/22\n103.103.16.0/22\n103.103.36.0/22\n103.103.72.0/22\n103.103.188.0/22\n103.103.204.0/22\n103.104.36.0/22\n103.104.40.0/22\n103.104.64.0/22\n103.104.152.0/22\n103.104.252.0/22\n103.105.0.0/21\n103.105.12.0/22\n103.105.16.0/22\n103.105.60.0/22\n103.105.116.0/22\n103.105.180.0/22\n103.105.184.0/22\n103.105.200.0/21\n103.105.220.0/22\n103.106.36.0/22\n103.106.40.0/21\n103.106.60.0/22\n103.106.68.0/22\n103.106.96.0/22\n103.106.120.0/22\n103.106.128.0/21\n103.106.190.0/23\n103.106.196.0/22\n103.106.212.0/22\n103.106.252.0/22\n103.107.0.0/22\n103.107.28.0/22\n103.107.32.0/22\n103.107.44.0/22\n103.107.72.0/22\n103.107.164.0/22\n103.107.168.0/22\n103.107.188.0/22\n103.107.192.0/22\n103.107.208.0/20\n103.108.52.0/22\n103.108.160.0/22\n103.108.196.0/22\n103.108.208.0/21\n103.108.224.0/22\n103.108.244.0/22\n103.108.251.0/24\n103.109.20.0/22\n103.109.48.0/22\n103.109.88.0/22\n103.109.248.0/22\n103.110.32.0/22\n103.110.92.0/22\n103.110.119.0/24\n103.110.127.0/24\n103.110.128.0/23\n103.110.131.0/24\n103.110.132.0/22\n103.110.136.0/22\n103.110.156.0/22\n103.110.188.0/22\n103.110.204.0/22\n103.111.64.0/22\n103.111.172.0/22\n103.111.252.0/22\n103.112.72.0/22\n103.112.88.0/21\n103.112.108.0/22\n103.112.112.0/22\n103.112.140.0/22\n103.113.4.0/22\n103.113.144.0/22\n103.113.220.0/22\n103.113.232.0/21\n103.114.4.0/22\n103.114.68.0/22\n103.114.100.0/22\n103.114.148.0/22\n103.114.156.0/23\n103.114.176.0/22\n103.114.212.0/22\n103.114.236.0/22\n103.114.240.0/22\n103.115.52.0/22\n103.115.68.0/22\n103.115.92.0/22\n103.115.120.0/22\n103.115.148.0/22\n103.115.248.0/22\n103.116.76.0/22\n103.116.92.0/22\n103.116.120.0/22\n103.116.128.0/22\n103.116.184.0/22\n103.116.220.0/22\n103.116.224.0/21\n103.117.16.0/22\n103.117.88.0/22\n103.117.188.0/22\n103.117.220.0/22\n103.118.19.0/24\n103.118.52.0/22\n103.118.56.0/21\n103.118.64.0/21\n103.118.72.0/22\n103.118.88.0/22\n103.118.173.0/24\n103.119.115.0/24\n103.119.156.0/22\n103.119.180.0/22\n103.119.200.0/22\n103.120.52.0/22\n103.120.72.0/22\n103.120.76.0/24\n103.120.88.0/22\n103.120.96.0/22\n103.120.140.0/22\n103.120.196.0/22\n103.120.224.0/22\n103.121.52.0/22\n103.121.160.0/21\n103.121.250.0/24\n103.121.252.0/22\n103.122.48.0/22\n103.122.179.0/24\n103.122.192.0/22\n103.122.240.0/23\n103.122.242.0/24\n103.123.4.0/22\n103.123.56.0/22\n103.123.88.0/21\n103.123.116.0/22\n103.123.176.0/22\n103.123.200.0/21\n103.123.208.0/21\n103.124.24.0/22\n103.124.48.0/22\n103.124.64.0/22\n103.124.212.0/22\n103.124.216.0/22\n103.125.20.0/22\n103.125.44.0/22\n103.125.132.0/22\n103.125.164.0/22\n103.125.196.0/22\n103.125.236.0/22\n103.126.0.0/22\n103.126.16.0/23\n103.126.44.0/22\n103.126.124.0/22\n103.126.128.0/22\n103.129.53.0/24\n103.129.54.0/23\n103.129.148.0/22\n103.130.132.0/22\n103.130.160.0/22\n103.130.228.0/22\n103.131.20.0/22\n103.131.36.0/22\n103.131.152.0/22\n103.131.168.0/22\n103.131.224.0/21\n103.131.240.0/22\n103.132.60.0/22\n103.132.64.0/20\n103.132.80.0/22\n103.132.104.0/21\n103.132.112.0/21\n103.132.120.0/22\n103.132.188.0/22\n103.132.208.0/21\n103.133.12.0/22\n103.133.40.0/22\n103.133.128.0/22\n103.133.232.0/22\n103.134.196.0/22\n103.135.80.0/22\n103.135.124.0/22\n103.135.148.0/22\n103.135.156.0/22\n103.135.160.0/21\n103.135.176.0/22\n103.135.184.0/22\n103.135.192.0/21\n103.135.236.0/22\n103.136.128.0/22\n103.136.232.0/22\n103.137.58.0/23\n103.137.60.0/24\n103.137.136.0/23\n103.137.149.0/24\n103.137.180.0/22\n103.137.236.0/22\n103.138.2.0/23\n103.138.135.0/24\n103.138.208.0/23\n103.138.220.0/23\n103.138.248.0/23\n103.139.22.0/23\n103.139.134.0/23\n103.139.172.0/23\n103.139.204.0/23\n103.139.212.0/23\n103.140.14.0/23\n103.140.46.0/23\n103.140.140.0/23\n103.140.144.0/23\n103.140.192.0/23\n103.141.10.0/23\n103.141.58.0/23\n103.141.128.0/23\n103.141.186.0/23\n103.141.242.0/23\n103.142.0.0/23\n103.142.28.0/23\n103.142.58.0/23\n103.142.82.0/23\n103.142.96.0/23\n103.142.122.0/23\n103.142.128.0/23\n103.142.154.0/23\n103.142.156.0/23\n103.142.180.0/23\n103.142.186.0/23\n103.142.234.0/23\n103.142.238.0/23\n103.143.16.0/22\n103.143.31.0/24\n103.143.74.0/23\n103.143.124.0/23\n103.143.132.0/22\n103.143.174.0/23\n103.143.228.0/23\n103.144.66.0/23\n103.144.70.0/23\n103.144.72.0/23\n103.144.88.0/24\n103.144.136.0/23\n103.144.158.0/23\n103.145.42.0/23\n103.145.94.0/23\n103.145.98.0/23\n103.145.188.0/23\n103.146.6.0/23\n103.146.72.0/23\n103.146.126.0/23\n103.146.138.0/23\n103.146.236.0/23\n103.146.252.0/23\n103.147.124.0/23\n103.147.206.0/23\n103.148.174.0/23\n103.149.6.0/23\n103.149.17.0/24\n103.149.44.0/23\n103.149.210.0/23\n103.149.214.0/23\n103.149.220.0/23\n103.149.242.0/23\n103.149.244.0/22\n103.150.24.0/23\n103.150.66.0/23\n103.150.72.0/23\n103.150.122.0/23\n103.150.126.0/23\n103.150.128.0/23\n103.150.146.0/23\n103.150.164.0/23\n103.150.200.0/23\n103.150.216.0/23\n103.150.244.0/23\n103.151.142.0/23\n103.151.148.0/23\n103.151.158.0/23\n103.152.28.0/22\n103.152.56.0/23\n103.152.76.0/23\n103.152.80.0/23\n103.152.120.0/22\n103.152.152.0/23\n103.152.168.0/23\n103.152.186.0/23\n103.152.190.0/23\n103.152.192.0/23\n103.152.200.0/23\n103.152.208.0/23\n103.152.224.0/23\n103.152.250.0/23\n103.153.99.0/24\n103.153.114.0/23\n103.153.122.0/23\n103.153.128.0/24\n103.153.132.0/23\n103.153.146.0/23\n103.153.160.0/23\n103.154.18.0/23\n103.154.30.0/23\n103.154.32.0/23\n103.154.40.0/23\n103.154.66.0/23\n103.154.162.0/23\n103.154.164.0/23\n103.154.168.0/23\n103.155.14.0/23\n103.155.17.0/24\n103.155.34.0/23\n103.155.48.0/23\n103.155.76.0/23\n103.155.100.0/23\n103.155.248.0/23\n103.156.28.0/23\n103.156.68.0/23\n103.156.78.0/23\n103.156.104.0/23\n103.156.158.0/23\n103.156.166.0/23\n103.156.174.0/23\n103.156.186.0/23\n103.156.228.0/23\n103.157.30.0/23\n103.157.174.0/23\n103.157.212.0/23\n103.157.234.0/23\n103.157.254.0/23\n103.158.0.0/23\n103.158.8.0/23\n103.158.16.0/23\n103.158.200.0/23\n103.158.224.0/23\n103.159.122.0/23\n103.159.124.0/23\n103.159.134.0/23\n103.159.142.0/23\n103.160.32.0/22\n103.160.112.0/22\n103.160.244.0/23\n103.160.254.0/23\n103.161.14.0/23\n103.161.102.0/23\n103.161.138.0/23\n103.161.208.0/23\n103.161.220.0/23\n103.161.254.0/23\n103.162.10.0/23\n103.162.32.0/23\n103.162.38.0/23\n103.162.116.0/23\n103.163.28.0/23\n103.163.32.0/23\n103.163.46.0/23\n103.163.74.0/23\n103.163.180.0/23\n103.164.4.0/23\n103.164.32.0/23\n103.164.40.0/22\n103.164.64.0/23\n103.164.76.0/23\n103.164.178.0/23\n103.164.226.0/23\n103.165.44.0/23\n103.165.52.0/23\n103.165.82.0/23\n103.165.110.0/23\n103.166.50.0/23\n103.166.52.0/22\n103.166.84.0/23\n103.166.138.0/23\n103.166.242.0/23\n103.167.0.0/23\n103.167.36.0/23\n103.168.98.0/23\n103.168.170.0/23\n103.169.50.0/23\n103.169.62.0/23\n103.169.108.0/23\n103.169.162.0/23\n103.169.202.0/23\n103.169.216.0/23\n103.170.4.0/23\n103.170.134.0/23\n103.170.210.0/23\n103.170.212.0/23\n103.192.0.0/19\n103.192.48.0/21\n103.192.56.0/22\n103.192.84.0/22\n103.192.88.0/21\n103.192.96.0/20\n103.192.112.0/22\n103.192.128.0/20\n103.192.144.0/22\n103.192.164.0/22\n103.192.188.0/22\n103.192.208.0/21\n103.192.216.0/22\n103.192.252.0/22\n103.193.40.0/21\n103.193.120.0/22\n103.193.140.0/22\n103.193.160.0/22\n103.193.188.0/22\n103.193.192.0/22\n103.193.212.0/22\n103.193.216.0/21\n103.193.224.0/20\n103.194.16.0/22\n103.195.112.0/22\n103.195.152.0/22\n103.195.160.0/22\n103.196.64.0/22\n103.196.72.0/22\n103.196.88.0/21\n103.196.96.0/22\n103.196.168.0/22\n103.196.185.0/24\n103.196.186.0/23\n103.197.181.0/24\n103.197.183.0/24\n103.197.228.0/22\n103.197.253.0/24\n103.197.254.0/23\n103.198.20.0/22\n103.198.60.0/22\n103.198.64.0/22\n103.198.72.0/22\n103.198.124.0/22\n103.198.156.0/22\n103.198.180.0/22\n103.198.196.0/22\n103.198.201.0/24\n103.198.202.0/23\n103.199.164.0/22\n103.199.196.0/22\n103.199.228.0/22\n103.199.252.0/22\n103.200.52.0/22\n103.200.64.0/21\n103.200.136.0/21\n103.200.144.0/20\n103.200.160.0/19\n103.200.192.0/22\n103.200.220.0/22\n103.200.224.0/19\n103.201.0.0/20\n103.201.16.0/21\n103.201.28.0/22\n103.201.32.0/19\n103.201.64.0/22\n103.201.76.0/22\n103.201.80.0/20\n103.201.96.0/20\n103.201.112.0/21\n103.201.120.0/22\n103.201.152.0/21\n103.201.160.0/19\n103.201.192.0/18\n103.202.0.0/19\n103.202.32.0/20\n103.202.56.0/21\n103.202.64.0/18\n103.202.128.0/20\n103.202.144.0/22\n103.202.152.0/21\n103.202.160.0/19\n103.202.192.0/20\n103.202.212.0/22\n103.202.228.0/22\n103.202.236.0/22\n103.202.240.0/20\n103.203.0.0/19\n103.203.32.0/22\n103.203.96.0/19\n103.203.128.0/22\n103.203.140.0/22\n103.203.164.0/22\n103.203.168.0/22\n103.203.192.0/22\n103.203.200.0/22\n103.203.212.0/22\n103.203.216.0/22\n103.204.24.0/22\n103.204.72.0/22\n103.204.88.0/22\n103.204.112.0/22\n103.204.136.0/21\n103.204.144.0/21\n103.204.152.0/22\n103.204.196.0/22\n103.204.232.0/21\n103.205.4.0/22\n103.205.40.0/21\n103.205.52.0/22\n103.205.108.0/22\n103.205.116.0/22\n103.205.136.0/22\n103.205.162.0/24\n103.205.188.0/22\n103.205.192.0/21\n103.205.200.0/22\n103.205.236.0/22\n103.205.248.0/21\n103.206.0.0/22\n103.206.44.0/22\n103.206.148.0/22\n103.207.104.0/22\n103.207.184.0/21\n103.207.192.0/20\n103.207.208.0/21\n103.207.220.0/22\n103.207.228.0/22\n103.207.232.0/22\n103.208.12.0/22\n103.208.16.0/22\n103.208.28.0/22\n103.208.48.0/22\n103.208.148.0/22\n103.209.112.0/22\n103.209.136.0/22\n103.209.200.0/22\n103.209.208.0/22\n103.209.216.0/22\n103.210.0.0/22\n103.210.96.0/22\n103.210.156.0/22\n103.210.164.0/22\n103.210.168.0/21\n103.210.176.0/20\n103.210.217.0/24\n103.210.218.0/23\n103.211.44.0/22\n103.211.96.0/23\n103.211.98.0/24\n103.211.102.0/23\n103.211.156.0/22\n103.211.165.0/24\n103.211.168.0/22\n103.211.220.0/22\n103.211.248.0/22\n103.212.0.0/20\n103.212.44.0/22\n103.212.48.0/22\n103.212.84.0/22\n103.212.100.0/22\n103.212.148.0/22\n103.212.164.0/22\n103.212.196.0/22\n103.212.200.0/22\n103.212.252.0/22\n103.213.40.0/21\n103.213.48.0/20\n103.213.64.0/19\n103.213.96.0/22\n103.213.132.0/22\n103.213.136.0/21\n103.213.144.0/20\n103.213.160.0/19\n103.213.252.0/22\n103.214.48.0/22\n103.214.84.0/22\n103.214.212.0/22\n103.214.240.0/21\n103.215.28.0/22\n103.215.32.0/21\n103.215.44.0/22\n103.215.100.0/23\n103.215.108.0/22\n103.215.116.0/22\n103.215.120.0/22\n103.215.140.0/22\n103.216.4.0/22\n103.216.8.0/21\n103.216.16.0/20\n103.216.32.0/20\n103.216.64.0/22\n103.216.108.0/22\n103.216.136.0/22\n103.216.152.0/22\n103.216.224.0/21\n103.216.240.0/20\n103.217.0.0/18\n103.217.168.0/22\n103.217.180.0/22\n103.217.184.0/21\n103.217.192.0/20\n103.218.8.0/21\n103.218.16.0/21\n103.218.28.0/22\n103.218.32.0/19\n103.218.64.0/19\n103.218.192.0/20\n103.218.208.0/21\n103.218.216.0/22\n103.219.24.0/21\n103.219.32.0/21\n103.219.64.0/22\n103.219.84.0/22\n103.219.88.0/21\n103.219.96.0/21\n103.219.176.0/22\n103.219.184.0/22\n103.220.48.0/20\n103.220.64.0/22\n103.220.92.0/22\n103.220.96.0/22\n103.220.104.0/21\n103.220.116.0/22\n103.220.120.0/21\n103.220.128.0/20\n103.220.144.0/21\n103.220.152.0/22\n103.220.160.0/19\n103.220.192.0/21\n103.220.200.0/22\n103.220.240.0/21\n103.221.32.0/22\n103.221.88.0/22\n103.221.96.0/19\n103.221.128.0/18\n103.221.192.0/20\n103.222.0.0/20\n103.222.16.0/22\n103.222.24.0/21\n103.222.33.0/24\n103.222.34.0/23\n103.222.36.0/22\n103.222.40.0/21\n103.222.48.0/20\n103.222.64.0/18\n103.222.128.0/18\n103.222.192.0/19\n103.222.224.0/21\n103.222.232.0/22\n103.222.240.0/21\n103.223.16.0/20\n103.223.32.0/19\n103.223.64.0/19\n103.223.96.0/20\n103.223.112.0/21\n103.223.124.0/22\n103.223.128.0/21\n103.223.140.0/22\n103.223.144.0/20\n103.223.160.0/20\n103.223.176.0/21\n103.223.188.0/22\n103.223.192.0/18\n103.224.0.0/22\n103.224.40.0/21\n103.224.60.0/22\n103.224.220.0/22\n103.224.224.0/21\n103.224.232.0/22\n103.225.32.0/22\n103.226.40.0/22\n103.226.57.0/24\n103.226.58.0/23\n103.226.60.0/22\n103.226.80.0/22\n103.226.116.0/22\n103.226.132.0/22\n103.226.156.0/22\n103.226.180.0/22\n103.226.196.0/22\n103.227.48.0/22\n103.227.72.0/21\n103.227.80.0/22\n103.227.100.0/22\n103.227.120.0/22\n103.227.132.0/22\n103.227.136.0/22\n103.227.196.0/22\n103.227.204.0/23\n103.227.206.0/24\n103.227.212.0/22\n103.227.228.0/22\n103.228.12.0/22\n103.228.88.0/22\n103.228.136.0/22\n103.228.160.0/22\n103.228.176.0/22\n103.228.204.0/22\n103.228.208.0/22\n103.228.228.0/22\n103.228.232.0/22\n103.229.20.0/22\n103.229.136.0/22\n103.229.148.0/22\n103.229.172.0/22\n103.229.212.0/22\n103.229.216.0/21\n103.229.228.0/22\n103.229.236.0/22\n103.229.240.0/22\n103.230.0.0/22\n103.230.28.0/22\n103.230.40.0/21\n103.230.96.0/22\n103.230.196.0/22\n103.230.200.0/21\n103.230.212.0/22\n103.230.236.0/22\n103.231.16.0/21\n103.231.64.0/21\n103.231.144.0/22\n103.231.180.0/22\n103.231.244.0/22\n103.232.4.0/22\n103.232.17.168/29\n103.232.144.0/22\n103.233.4.0/22\n103.233.44.0/22\n103.233.52.0/22\n103.233.104.0/22\n103.233.128.0/22\n103.233.136.0/22\n103.233.228.0/22\n103.234.0.0/22\n103.234.20.0/22\n103.234.56.0/22\n103.234.124.0/22\n103.234.128.0/22\n103.234.172.0/22\n103.234.180.0/22\n103.235.56.0/21\n103.235.80.0/22\n103.235.85.0/24\n103.235.87.0/24\n103.235.128.0/20\n103.235.144.0/21\n103.235.184.0/22\n103.235.192.0/22\n103.235.200.0/22\n103.235.220.0/22\n103.235.224.0/19\n103.236.0.0/18\n103.236.64.0/19\n103.236.96.0/22\n103.236.120.0/22\n103.236.184.0/22\n103.236.240.0/20\n103.237.0.0/20\n103.237.24.0/21\n103.237.68.0/22\n103.237.88.0/22\n103.237.152.0/22\n103.237.176.0/20\n103.237.192.0/18\n103.238.0.0/21\n103.238.18.0/23\n103.238.20.0/22\n103.238.24.0/21\n103.238.32.0/20\n103.238.48.0/21\n103.238.56.0/22\n103.238.88.0/21\n103.238.96.0/22\n103.238.132.0/22\n103.238.140.0/22\n103.238.144.0/22\n103.238.160.0/22\n103.238.165.0/24\n103.238.166.0/23\n103.238.168.0/21\n103.238.176.0/20\n103.238.196.0/22\n103.238.204.0/22\n103.238.252.0/22\n103.239.0.0/22\n103.239.44.0/22\n103.239.68.0/22\n103.239.152.0/21\n103.239.180.0/22\n103.239.184.0/22\n103.239.192.0/21\n103.239.204.0/22\n103.239.208.0/22\n103.239.224.0/22\n103.239.244.0/22\n103.240.16.0/22\n103.240.36.0/22\n103.240.72.0/22\n103.240.84.0/22\n103.240.124.0/22\n103.240.172.0/22\n103.240.188.0/22\n103.240.244.0/22\n103.241.12.0/22\n103.241.92.0/22\n103.241.96.0/22\n103.241.160.0/22\n103.241.184.0/21\n103.241.220.0/22\n103.242.64.0/23\n103.242.128.0/24\n103.242.160.0/22\n103.242.168.0/21\n103.242.176.0/22\n103.242.200.0/22\n103.242.212.0/22\n103.242.220.0/22\n103.242.240.0/22\n103.243.136.0/22\n103.243.252.0/22\n103.244.16.0/22\n103.244.58.0/23\n103.244.60.0/22\n103.244.64.0/20\n103.244.80.0/21\n103.244.164.0/22\n103.244.232.0/22\n103.244.252.0/22\n103.245.23.0/24\n103.245.52.0/22\n103.245.60.0/22\n103.245.80.0/22\n103.245.124.0/22\n103.245.128.0/22\n103.246.8.0/21\n103.246.120.0/21\n103.246.132.0/22\n103.246.152.0/22\n103.247.168.0/21\n103.247.176.0/22\n103.247.200.0/22\n103.247.212.0/22\n103.248.64.0/23\n103.248.100.0/22\n103.248.124.0/22\n103.248.152.0/22\n103.248.168.0/22\n103.248.192.0/22\n103.248.212.0/22\n103.248.224.0/21\n103.249.8.0/21\n103.249.52.0/22\n103.249.128.0/22\n103.249.136.0/22\n103.249.144.0/22\n103.249.164.0/22\n103.249.168.0/21\n103.249.176.0/22\n103.249.188.0/22\n103.249.192.0/22\n103.249.244.0/22\n103.249.252.0/22\n103.250.32.0/22\n103.250.104.0/22\n103.250.124.0/22\n103.250.180.0/22\n103.250.192.0/22\n103.250.216.0/22\n103.250.224.0/22\n103.250.236.0/22\n103.250.248.0/21\n103.251.32.0/22\n103.251.84.0/22\n103.251.96.0/22\n103.251.124.0/22\n103.251.160.0/22\n103.251.192.0/22\n103.251.204.0/22\n103.251.240.0/22\n103.252.28.0/22\n103.252.36.0/22\n103.252.64.0/22\n103.252.96.0/22\n103.252.104.0/22\n103.252.172.0/22\n103.252.204.0/22\n103.252.208.0/22\n103.252.232.0/22\n103.252.248.0/22\n103.253.4.0/22\n103.253.60.0/22\n103.253.204.0/22\n103.253.220.0/22\n103.253.224.0/22\n103.253.232.0/22\n103.254.8.0/22\n103.254.20.0/22\n103.254.64.0/21\n103.254.76.0/22\n103.254.112.0/22\n103.254.176.0/22\n103.254.188.0/22\n103.255.68.0/22\n103.255.88.0/21\n103.255.136.0/21\n103.255.184.0/22\n103.255.200.0/22\n103.255.208.0/22\n103.255.228.0/22\n106.0.0.0/24\n106.0.2.0/23\n106.0.4.0/22\n106.0.8.0/21\n106.0.16.0/20\n106.0.44.0/22\n106.0.64.0/18\n106.2.0.0/17\n106.2.128.0/20\n106.2.144.0/21\n106.2.152.0/22\n106.2.156.0/23\n106.2.160.0/19\n106.2.192.0/18\n106.3.16.0/20\n106.3.32.0/19\n106.3.64.0/20\n106.3.80.0/22\n106.3.88.0/21\n106.3.96.0/19\n106.3.128.0/19\n106.3.164.0/22\n106.3.168.0/21\n106.3.176.0/20\n106.3.192.0/18\n106.4.0.0/14\n106.8.0.0/15\n106.11.0.0/16\n106.12.0.0/14\n106.16.0.0/12\n106.32.0.0/12\n106.48.0.0/21\n106.48.8.0/22\n106.48.16.0/20\n106.48.32.0/20\n106.48.57.0/24\n106.48.60.0/24\n106.48.63.0/24\n106.48.64.0/18\n106.48.128.0/17\n106.49.1.0/24\n106.49.2.0/23\n106.49.4.0/22\n106.49.8.0/21\n106.49.16.0/20\n106.49.32.0/19\n106.49.64.0/19\n106.49.96.0/24\n106.49.98.0/23\n106.49.100.0/22\n106.49.104.0/21\n106.49.112.0/20\n106.49.128.0/17\n106.50.0.0/16\n106.52.0.0/14\n106.56.0.0/13\n106.74.0.0/16\n106.75.0.0/17\n106.75.128.0/18\n106.75.201.0/24\n106.75.204.0/22\n106.75.208.0/20\n106.75.224.0/19\n106.80.0.0/12\n106.108.0.0/14\n106.112.0.0/12\n106.224.0.0/12\n107.176.0.0/15\n109.71.4.0/24\n109.244.0.0/16\n110.6.0.0/15\n110.16.0.0/14\n110.34.40.0/21\n110.40.0.0/14\n110.44.12.0/22\n110.44.144.0/20\n110.48.0.0/16\n110.51.0.0/16\n110.52.0.0/15\n110.56.0.0/13\n110.64.0.0/15\n110.72.0.0/15\n110.75.0.0/16\n110.76.0.0/20\n110.76.16.0/22\n110.76.20.0/24\n110.76.22.0/24\n110.76.24.0/21\n110.76.32.0/19\n110.76.132.0/22\n110.76.156.0/22\n110.76.184.0/22\n110.76.192.0/18\n110.77.0.0/17\n110.80.0.0/13\n110.88.0.0/14\n110.92.68.0/22\n110.93.32.0/19\n110.94.0.0/15\n110.96.0.0/11\n110.152.0.0/14\n110.156.0.0/15\n110.166.0.0/15\n110.172.192.0/18\n110.173.0.0/19\n110.173.32.0/20\n110.173.64.0/19\n110.173.192.0/19\n110.176.0.0/12\n110.192.0.0/11\n110.228.0.0/14\n110.232.32.0/19\n110.236.0.0/15\n110.240.0.0/12\n111.0.0.0/10\n111.66.0.0/17\n111.66.128.0/19\n111.66.160.0/20\n111.66.176.0/23\n111.66.178.0/24\n111.66.180.0/22\n111.66.184.0/21\n111.66.192.0/18\n111.67.192.0/20\n111.68.64.0/19\n111.72.0.0/13\n111.85.0.0/16\n111.91.192.0/19\n111.92.248.0/21\n111.112.0.0/14\n111.116.0.0/15\n111.118.200.0/21\n111.119.64.0/18\n111.119.128.0/19\n111.120.0.0/14\n111.124.0.0/16\n111.126.0.0/15\n111.128.0.0/11\n111.160.0.0/13\n111.170.0.0/16\n111.172.0.0/14\n111.176.0.0/13\n111.186.0.0/15\n111.192.0.0/12\n111.208.0.0/13\n111.221.28.0/24\n111.221.128.0/17\n111.222.0.0/16\n111.223.4.0/22\n111.223.8.0/21\n111.223.16.0/22\n111.223.240.0/22\n111.223.249.0/24\n111.223.250.0/23\n111.224.0.0/13\n111.235.96.0/19\n111.235.156.0/22\n111.235.160.0/21\n111.235.170.0/23\n111.235.172.0/22\n111.235.176.0/20\n112.0.0.0/10\n112.64.0.0/14\n112.73.64.0/18\n112.74.0.0/15\n112.80.0.0/12\n112.96.0.0/13\n112.109.128.0/17\n112.111.0.0/16\n112.112.0.0/14\n112.116.0.0/15\n112.122.0.0/15\n112.124.0.0/14\n112.128.0.0/14\n112.132.0.0/16\n112.137.48.0/21\n112.192.0.0/14\n112.224.0.0/11\n113.0.0.0/13\n113.8.0.0/15\n113.11.192.0/19\n113.12.0.0/14\n113.16.0.0/15\n113.18.0.0/16\n113.21.232.0/24\n113.21.236.0/22\n113.24.0.0/14\n113.31.0.0/16\n113.44.0.0/14\n113.48.0.0/14\n113.52.160.0/19\n113.52.228.0/22\n113.54.0.0/15\n113.56.0.0/15\n113.58.0.0/16\n113.59.0.0/17\n113.59.224.0/22\n113.62.0.0/15\n113.64.0.0/10\n113.128.0.0/15\n113.130.96.0/20\n113.130.112.0/21\n113.132.0.0/14\n113.136.0.0/13\n113.194.0.0/15\n113.197.100.0/23\n113.197.102.0/24\n113.197.104.0/22\n113.200.0.0/15\n113.202.0.0/16\n113.204.0.0/14\n113.208.96.0/19\n113.208.128.0/17\n113.209.0.0/16\n113.212.0.0/18\n113.212.100.0/22\n113.212.184.0/21\n113.213.0.0/17\n113.214.0.0/15\n113.218.0.0/15\n113.220.0.0/14\n113.224.0.0/12\n113.240.0.0/13\n113.248.0.0/14\n114.28.0.0/17\n114.28.128.0/18\n114.28.194.0/23\n114.28.196.0/22\n114.28.200.0/21\n114.28.208.0/20\n114.28.232.0/22\n114.28.240.0/20\n114.31.64.0/21\n114.54.0.0/15\n114.60.0.0/14\n114.64.0.0/14\n114.68.0.0/18\n114.68.64.0/19\n114.68.96.0/22\n114.68.101.0/24\n114.68.102.0/23\n114.68.104.0/21\n114.68.112.0/20\n114.68.128.0/17\n114.79.64.0/18\n114.80.0.0/12\n114.96.0.0/13\n114.104.0.0/14\n114.110.0.0/20\n114.110.64.0/18\n114.111.0.0/19\n114.111.160.0/19\n114.112.4.0/22\n114.112.8.0/22\n114.112.24.0/21\n114.112.32.0/19\n114.112.64.0/19\n114.112.96.0/20\n114.112.116.0/22\n114.112.120.0/21\n114.112.136.0/21\n114.112.144.0/20\n114.112.160.0/19\n114.112.192.0/19\n114.113.0.0/17\n114.113.128.0/21\n114.113.140.0/22\n114.113.144.0/20\n114.113.160.0/19\n114.113.196.0/22\n114.113.200.0/21\n114.113.208.0/20\n114.113.224.0/20\n114.114.0.0/15\n114.116.0.0/15\n114.118.0.0/16\n114.119.0.0/17\n114.119.192.0/18\n114.132.0.0/16\n114.135.0.0/16\n114.138.0.0/15\n114.141.64.0/21\n114.141.80.0/21\n114.141.128.0/18\n114.196.0.0/15\n114.198.248.0/21\n114.208.0.0/12\n114.224.0.0/11\n115.24.0.0/14\n115.28.0.0/15\n115.31.64.0/20\n115.32.0.0/14\n115.42.56.0/22\n115.44.0.0/14\n115.48.0.0/12\n115.69.64.0/20\n115.84.0.0/18\n115.84.192.0/19\n115.85.192.0/18\n115.100.0.0/14\n115.104.0.0/14\n115.120.0.0/14\n115.124.16.0/20\n115.148.0.0/14\n115.152.0.0/13\n115.166.64.0/19\n115.168.0.0/16\n115.169.0.0/23\n115.169.3.0/24\n115.169.6.0/24\n115.169.9.0/24\n115.169.14.0/23\n115.169.16.0/20\n115.169.39.0/24\n115.169.42.0/23\n115.169.44.0/22\n115.169.48.0/20\n115.169.64.0/18\n115.169.128.0/17\n115.170.0.0/15\n115.172.0.0/14\n115.180.0.0/14\n115.187.0.0/20\n115.190.0.0/15\n115.192.0.0/11\n115.224.0.0/12\n116.0.8.0/21\n116.0.24.0/21\n116.1.0.0/16\n116.2.0.0/15\n116.4.0.0/14\n116.8.0.0/14\n116.13.0.0/16\n116.16.0.0/12\n116.50.0.0/20\n116.52.0.0/14\n116.56.0.0/15\n116.58.128.0/20\n116.58.208.0/20\n116.60.0.0/14\n116.66.0.0/18\n116.66.64.0/19\n116.66.96.0/20\n116.66.120.0/22\n116.68.136.0/21\n116.68.176.0/21\n116.69.0.0/16\n116.70.0.0/17\n116.76.0.0/14\n116.85.0.0/17\n116.85.128.0/18\n116.85.192.0/19\n116.85.224.0/20\n116.85.240.0/21\n116.85.248.0/23\n116.85.250.0/24\n116.85.252.0/22\n116.89.144.0/20\n116.90.80.0/20\n116.90.184.0/21\n116.95.0.0/16\n116.112.0.0/14\n116.116.0.0/15\n116.128.0.0/10\n116.192.0.0/16\n116.193.16.0/20\n116.193.32.0/19\n116.193.176.0/21\n116.194.0.0/15\n116.196.0.0/21\n116.196.8.0/22\n116.196.12.0/23\n116.196.16.0/20\n116.196.32.0/19\n116.196.64.0/18\n116.196.128.0/18\n116.196.192.0/21\n116.196.201.0/24\n116.196.203.0/24\n116.196.204.0/22\n116.196.208.0/20\n116.196.224.0/19\n116.197.160.0/21\n116.197.180.0/23\n116.198.0.0/16\n116.199.0.0/17\n116.199.128.0/19\n116.204.0.0/17\n116.204.232.0/22\n116.205.0.0/16\n116.207.0.0/16\n116.208.0.0/14\n116.212.160.0/20\n116.213.64.0/18\n116.213.128.0/17\n116.214.32.0/19\n116.214.64.0/20\n116.214.128.0/17\n116.215.0.0/16\n116.216.0.0/14\n116.224.0.0/12\n116.242.0.0/15\n116.244.0.0/14\n116.248.0.0/15\n116.252.0.0/15\n116.254.104.0/21\n116.254.129.0/24\n116.254.130.0/23\n116.254.132.0/22\n116.254.136.0/21\n116.254.144.0/20\n116.254.160.0/19\n116.254.192.0/18\n116.255.128.0/17\n117.8.0.0/13\n117.21.0.0/16\n117.22.0.0/15\n117.24.0.0/13\n117.32.0.0/13\n117.40.0.0/14\n117.44.0.0/15\n117.48.0.0/15\n117.50.0.0/16\n117.51.128.0/23\n117.51.131.0/24\n117.51.132.0/22\n117.51.136.0/21\n117.51.144.0/20\n117.51.160.0/19\n117.51.192.0/18\n117.53.48.0/20\n117.53.176.0/20\n117.57.0.0/16\n117.58.0.0/17\n117.59.0.0/16\n117.60.0.0/14\n117.64.0.0/13\n117.72.0.0/15\n117.74.64.0/19\n117.74.128.0/17\n117.75.0.0/16\n117.76.0.0/14\n117.80.0.0/12\n117.100.0.0/15\n117.103.16.0/20\n117.103.40.0/21\n117.103.72.0/21\n117.103.128.0/20\n117.104.168.0/21\n117.106.0.0/15\n117.112.0.0/13\n117.120.64.0/18\n117.120.128.0/17\n117.121.0.0/17\n117.121.128.0/20\n117.121.148.0/22\n117.121.152.0/21\n117.121.160.0/19\n117.121.192.0/21\n117.122.128.0/17\n117.124.0.0/14\n117.128.0.0/10\n118.24.0.0/15\n118.26.0.0/19\n118.26.40.0/21\n118.26.48.0/20\n118.26.64.0/19\n118.26.98.0/23\n118.26.112.0/21\n118.26.121.0/24\n118.26.122.0/23\n118.26.124.0/23\n118.26.128.0/20\n118.26.144.0/22\n118.26.149.0/24\n118.26.150.0/23\n118.26.152.0/21\n118.26.160.0/19\n118.26.192.0/18\n118.28.0.0/15\n118.30.0.0/20\n118.30.16.0/21\n118.30.24.0/22\n118.30.32.0/19\n118.30.64.0/18\n118.30.128.0/17\n118.31.0.0/16\n118.64.0.0/15\n118.66.0.0/16\n118.67.112.0/20\n118.72.0.0/13\n118.80.0.0/15\n118.84.0.0/15\n118.88.32.0/19\n118.88.64.0/18\n118.88.128.0/17\n118.89.0.0/16\n118.102.16.0/20\n118.102.32.0/21\n118.103.164.0/22\n118.103.168.0/21\n118.103.176.0/22\n118.103.245.0/24\n118.103.246.0/23\n118.112.0.0/13\n118.120.0.0/14\n118.124.0.0/15\n118.126.1.0/24\n118.126.2.0/23\n118.126.4.0/22\n118.126.8.0/21\n118.126.16.0/23\n118.126.18.0/24\n118.126.32.0/19\n118.126.64.0/18\n118.126.128.0/17\n118.127.128.0/19\n118.132.0.0/14\n118.144.0.0/14\n118.178.0.0/16\n118.180.0.0/14\n118.184.5.0/24\n118.184.128.0/18\n118.184.192.0/19\n118.184.240.0/20\n118.186.0.0/15\n118.188.0.0/16\n118.190.0.0/16\n118.191.0.0/20\n118.191.32.0/19\n118.191.64.0/18\n118.191.144.0/21\n118.191.153.0/24\n118.191.154.0/23\n118.191.156.0/22\n118.191.160.0/19\n118.191.192.0/20\n118.191.209.0/24\n118.191.210.0/23\n118.191.212.0/22\n118.191.248.0/21\n118.192.0.0/16\n118.193.0.0/22\n118.193.96.0/19\n118.194.0.0/17\n118.194.128.0/18\n118.194.192.0/19\n118.194.240.0/21\n118.195.0.0/16\n118.196.0.0/14\n118.202.0.0/15\n118.204.0.0/14\n118.212.0.0/15\n118.215.192.0/18\n118.224.0.0/14\n118.228.0.0/17\n118.228.128.0/20\n118.228.144.0/21\n118.228.156.0/22\n118.228.160.0/19\n118.228.192.0/18\n118.229.0.0/16\n118.230.0.0/16\n118.239.0.0/16\n118.242.0.0/16\n118.244.0.0/14\n118.248.0.0/13\n119.0.0.0/15\n119.2.0.0/19\n119.2.128.0/17\n119.3.0.0/16\n119.4.0.0/14\n119.10.0.0/17\n119.15.136.0/21\n119.16.0.0/16\n119.18.192.0/20\n119.18.208.0/21\n119.18.224.0/19\n119.19.0.0/16\n119.20.0.0/14\n119.27.64.0/18\n119.27.128.0/17\n119.28.28.0/24\n119.29.0.0/16\n119.30.48.0/20\n119.31.192.0/19\n119.32.0.0/14\n119.36.0.0/15\n119.38.0.0/17\n119.38.128.0/18\n119.38.192.0/20\n119.38.208.0/22\n119.38.212.0/23\n119.38.214.0/27\n119.38.214.56/29\n119.38.214.64/26\n119.38.214.128/25\n119.38.215.0/24\n119.38.216.0/21\n119.39.0.0/16\n119.40.0.0/18\n119.40.64.0/20\n119.40.128.0/17\n119.41.0.0/16\n119.42.0.0/19\n119.42.128.0/20\n119.42.224.0/19\n119.44.0.0/15\n119.48.0.0/13\n119.57.0.0/16\n119.58.0.0/16\n119.59.128.0/17\n119.60.0.0/15\n119.62.0.0/16\n119.63.32.0/19\n119.75.208.0/20\n119.78.0.0/15\n119.80.0.0/16\n119.82.208.0/20\n119.84.0.0/14\n119.88.0.0/16\n119.89.0.0/17\n119.89.128.0/21\n119.89.136.0/23\n119.89.139.0/24\n119.89.140.0/22\n119.89.144.0/20\n119.89.160.0/20\n119.89.176.0/22\n119.89.180.0/23\n119.89.183.0/24\n119.89.184.0/21\n119.89.192.0/23\n119.89.194.0/24\n119.89.196.0/22\n119.89.200.0/21\n119.89.208.0/21\n119.89.217.0/24\n119.89.218.0/23\n119.89.220.0/22\n119.89.224.0/19\n119.90.0.0/15\n119.96.0.0/13\n119.108.0.0/15\n119.112.0.0/12\n119.128.0.0/12\n119.144.0.0/14\n119.148.160.0/19\n119.151.192.0/18\n119.160.200.0/21\n119.161.120.0/21\n119.161.128.0/21\n119.161.160.0/19\n119.161.192.0/18\n119.162.0.0/15\n119.164.0.0/14\n119.176.0.0/12\n119.232.0.0/15\n119.235.128.0/19\n119.235.160.0/20\n119.235.184.0/22\n119.248.0.0/14\n119.252.96.0/21\n119.252.240.0/21\n119.252.249.0/24\n119.252.252.0/23\n119.253.0.0/16\n119.254.0.0/15\n120.0.0.0/12\n120.24.0.0/14\n120.30.0.0/15\n120.32.0.0/12\n120.48.0.0/15\n120.52.0.0/16\n120.53.0.0/19\n120.53.32.0/20\n120.53.48.0/22\n120.53.54.0/23\n120.53.56.0/21\n120.53.64.0/18\n120.53.128.0/17\n120.54.0.0/15\n120.64.0.0/13\n120.72.32.0/19\n120.72.128.0/17\n120.76.0.0/14\n120.80.0.0/13\n120.88.8.0/21\n120.90.0.0/15\n120.92.0.0/17\n120.92.128.0/18\n120.92.192.0/22\n120.92.198.0/23\n120.92.200.0/21\n120.92.208.0/20\n120.92.224.0/19\n120.94.0.0/15\n120.128.0.0/13\n120.136.16.0/21\n120.136.128.0/18\n120.137.0.0/17\n120.143.128.0/19\n120.192.0.0/10\n121.0.8.0/21\n121.0.16.0/20\n121.4.0.0/22\n121.4.8.0/21\n121.4.16.0/20\n121.4.32.0/19\n121.4.64.0/18\n121.4.128.0/17\n121.5.0.0/16\n121.8.0.0/13\n121.16.0.0/12\n121.32.0.0/13\n121.40.0.0/14\n121.46.0.0/18\n121.46.76.0/22\n121.46.128.0/17\n121.47.0.0/16\n121.48.0.0/15\n121.50.8.0/21\n121.51.0.0/16\n121.52.160.0/19\n121.52.208.0/20\n121.52.224.0/19\n121.54.176.0/21\n121.55.0.0/18\n121.56.0.0/15\n121.58.0.0/17\n121.58.136.0/21\n121.58.144.0/20\n121.58.160.0/21\n121.59.0.0/20\n121.59.16.0/21\n121.59.24.0/22\n121.59.28.0/24\n121.59.31.0/24\n121.59.33.0/24\n121.59.36.0/22\n121.59.40.0/21\n121.59.48.0/20\n121.59.64.0/19\n121.59.96.0/22\n121.59.101.0/24\n121.59.102.0/23\n121.59.104.0/21\n121.59.112.0/21\n121.59.121.0/24\n121.59.122.0/23\n121.59.124.0/22\n121.59.128.0/21\n121.59.136.0/22\n121.59.141.0/24\n121.59.142.0/23\n121.59.144.0/21\n121.59.152.0/24\n121.59.154.0/23\n121.59.156.0/22\n121.59.160.0/19\n121.59.192.0/18\n121.60.0.0/14\n121.68.0.0/14\n121.76.0.0/15\n121.79.128.0/18\n121.89.0.0/16\n121.100.128.0/17\n121.101.0.0/18\n121.101.208.0/20\n121.192.0.0/13\n121.200.192.0/23\n121.200.194.0/24\n121.200.196.0/22\n121.201.0.0/16\n121.204.0.0/14\n121.224.0.0/12\n121.248.0.0/14\n121.255.0.0/16\n122.0.64.0/18\n122.0.128.0/17\n122.4.0.0/14\n122.9.0.0/16\n122.10.132.0/23\n122.10.136.0/23\n122.10.216.0/22\n122.10.228.0/22\n122.10.232.0/21\n122.10.240.0/22\n122.11.0.0/17\n122.12.0.0/15\n122.14.0.0/17\n122.14.192.0/18\n122.48.0.0/16\n122.49.0.0/18\n122.51.0.0/16\n122.64.0.0/14\n122.68.0.0/15\n122.70.0.0/18\n122.70.64.0/19\n122.70.96.0/20\n122.70.112.0/21\n122.70.120.0/22\n122.70.124.0/23\n122.70.126.0/24\n122.70.128.0/17\n122.71.0.0/16\n122.72.0.0/13\n122.80.0.0/12\n122.96.0.0/15\n122.98.144.0/20\n122.98.160.0/21\n122.98.172.0/22\n122.98.176.0/20\n122.98.192.0/21\n122.98.232.0/21\n122.98.240.0/20\n122.102.0.0/20\n122.102.64.0/19\n122.112.0.0/18\n122.112.64.0/19\n122.112.96.0/22\n122.112.118.0/24\n122.112.122.0/24\n122.112.125.0/24\n122.112.128.0/17\n122.113.0.0/16\n122.114.0.0/16\n122.115.0.0/18\n122.115.80.0/20\n122.115.96.0/19\n122.115.128.0/17\n122.119.0.0/16\n122.128.100.0/22\n122.128.120.0/21\n122.136.0.0/13\n122.144.128.0/17\n122.152.192.0/18\n122.156.0.0/14\n122.188.0.0/14\n122.192.0.0/14\n122.198.0.0/16\n122.200.40.0/21\n122.200.64.0/18\n122.201.48.0/20\n122.204.0.0/14\n122.224.0.0/12\n122.240.0.0/13\n122.248.24.0/21\n122.248.48.0/20\n122.255.64.0/21\n123.0.128.0/21\n123.0.136.0/23\n123.0.139.0/24\n123.0.140.0/22\n123.0.144.0/20\n123.0.160.0/19\n123.4.0.0/14\n123.8.0.0/13\n123.49.130.0/23\n123.49.132.0/22\n123.49.136.0/22\n123.49.152.0/21\n123.49.160.0/19\n123.49.192.0/18\n123.50.160.0/19\n123.52.0.0/14\n123.56.0.0/15\n123.58.0.0/18\n123.58.64.0/20\n123.58.80.0/21\n123.58.88.0/22\n123.58.96.0/19\n123.58.128.0/18\n123.58.224.0/19\n123.59.0.0/16\n123.60.0.0/15\n123.62.0.0/16\n123.64.0.0/11\n123.96.0.0/15\n123.98.0.0/17\n123.99.128.0/19\n123.99.160.0/20\n123.99.176.0/21\n123.99.184.0/22\n123.99.188.0/24\n123.99.190.0/23\n123.99.192.0/18\n123.100.0.0/19\n123.100.232.0/24\n123.101.0.0/16\n123.103.0.0/20\n123.103.16.0/21\n123.103.24.0/22\n123.103.28.0/23\n123.103.30.0/24\n123.103.32.0/19\n123.103.64.0/18\n123.108.134.0/24\n123.108.138.0/23\n123.108.140.0/24\n123.108.142.0/24\n123.108.208.0/20\n123.112.0.0/12\n123.128.0.0/13\n123.137.0.0/16\n123.138.0.0/15\n123.144.0.0/12\n123.160.0.0/12\n123.176.60.0/22\n123.176.80.0/20\n123.177.0.0/16\n123.178.0.0/15\n123.180.0.0/14\n123.184.0.0/13\n123.196.0.0/15\n123.199.128.0/17\n123.206.0.0/15\n123.232.0.0/14\n123.242.0.0/17\n123.242.192.0/21\n123.244.0.0/14\n123.249.0.0/16\n123.253.240.0/22\n123.254.96.0/21\n124.6.64.0/18\n124.14.0.0/15\n124.16.0.0/15\n124.20.0.0/14\n124.28.192.0/18\n124.29.0.0/17\n124.31.0.0/16\n124.40.112.0/20\n124.40.128.0/18\n124.40.192.0/19\n124.40.240.0/22\n124.42.0.0/16\n124.47.0.0/18\n124.64.0.0/15\n124.66.0.0/17\n124.67.0.0/16\n124.68.0.0/19\n124.68.32.0/20\n124.68.48.0/21\n124.68.56.0/22\n124.68.60.0/23\n124.68.63.0/24\n124.68.64.0/18\n124.68.128.0/18\n124.68.192.0/19\n124.68.224.0/23\n124.68.226.0/24\n124.68.228.0/22\n124.68.232.0/21\n124.68.240.0/23\n124.68.242.0/24\n124.68.244.0/23\n124.68.254.0/24\n124.69.0.0/16\n124.70.0.0/16\n124.71.0.0/17\n124.71.128.0/18\n124.71.192.0/19\n124.71.224.0/20\n124.71.240.0/21\n124.71.250.0/23\n124.71.252.0/22\n124.72.0.0/13\n124.88.0.0/13\n124.108.8.0/21\n124.108.40.0/21\n124.109.96.0/21\n124.112.0.0/13\n124.126.0.0/15\n124.128.0.0/13\n124.147.128.0/17\n124.150.137.0/24\n124.151.0.0/16\n124.152.0.0/16\n124.160.0.0/13\n124.172.0.0/16\n124.173.32.0/19\n124.173.64.0/18\n124.173.128.0/17\n124.174.0.0/15\n124.192.0.0/15\n124.196.0.0/16\n124.200.0.0/13\n124.220.0.0/14\n124.224.0.0/12\n124.240.0.0/17\n124.240.128.0/18\n124.242.0.0/16\n124.243.192.0/18\n124.248.0.0/17\n124.249.0.0/16\n124.250.0.0/15\n124.254.0.0/18\n125.31.192.0/18\n125.32.0.0/12\n125.58.128.0/17\n125.61.128.0/17\n125.62.0.0/18\n125.64.0.0/11\n125.96.0.0/15\n125.98.0.0/16\n125.104.0.0/13\n125.112.0.0/12\n125.169.0.0/16\n125.171.0.0/16\n125.208.0.0/19\n125.208.37.0/24\n125.208.40.0/24\n125.208.45.0/24\n125.208.46.0/23\n125.208.48.0/20\n125.210.0.0/15\n125.213.0.0/17\n125.214.96.0/19\n125.215.0.0/18\n125.216.0.0/13\n125.254.128.0/17\n128.108.0.0/16\n129.28.0.0/16\n129.204.0.0/16\n129.211.0.0/16\n129.223.254.0/24\n130.36.146.0/23\n130.214.218.0/23\n131.228.96.0/24\n131.253.12.0/29\n131.253.12.80/28\n131.253.12.240/29\n132.232.0.0/16\n132.237.134.0/24\n134.175.0.0/16\n135.84.254.0/23\n135.159.208.0/20\n135.244.80.0/20\n137.59.59.0/24\n137.59.88.0/22\n138.32.244.0/24\n139.5.56.0/22\n139.5.61.0/24\n139.5.62.0/23\n139.5.80.0/22\n139.5.92.0/22\n139.5.128.0/22\n139.5.160.0/22\n139.5.192.0/22\n139.5.204.0/22\n139.5.244.0/22\n139.9.0.0/16\n139.129.0.0/16\n139.138.238.0/28\n139.148.0.0/16\n139.155.0.0/16\n139.159.0.0/19\n139.159.32.0/21\n139.159.40.0/22\n139.159.52.0/22\n139.159.56.0/21\n139.159.64.0/19\n139.159.96.0/20\n139.159.112.0/24\n139.159.113.24/29\n139.159.113.32/27\n139.159.113.64/26\n139.159.113.128/25\n139.159.114.0/23\n139.159.116.0/23\n139.159.120.0/21\n139.159.128.0/17\n139.170.0.0/16\n139.176.0.0/16\n139.183.0.0/16\n139.186.0.0/16\n139.189.0.0/16\n139.196.0.0/15\n139.198.0.0/18\n139.198.66.0/23\n139.198.68.0/22\n139.198.72.0/21\n139.198.80.0/20\n139.198.96.0/20\n139.198.116.0/22\n139.198.122.0/23\n139.198.124.0/22\n139.198.128.0/17\n139.199.0.0/16\n139.200.0.0/13\n139.208.0.0/13\n139.217.0.0/16\n139.219.0.0/16\n139.220.0.0/17\n139.220.128.0/18\n139.220.192.0/22\n139.220.196.0/23\n139.220.200.0/21\n139.220.208.0/23\n139.220.212.0/22\n139.220.216.0/21\n139.220.224.0/19\n139.221.0.0/16\n139.224.0.0/16\n139.226.0.0/15\n140.75.0.0/16\n140.101.208.0/24\n140.143.0.0/16\n140.179.0.0/16\n140.205.0.0/16\n140.206.0.0/15\n140.210.0.0/16\n140.224.0.0/16\n140.237.0.0/16\n140.240.0.0/16\n140.242.223.0/24\n140.242.224.0/24\n140.243.0.0/16\n140.246.0.0/16\n140.249.0.0/16\n140.250.0.0/16\n140.255.0.0/16\n142.70.0.0/16\n142.86.0.0/16\n144.0.0.0/16\n144.7.0.0/16\n144.12.0.0/16\n144.36.146.0/23\n144.48.64.0/22\n144.48.88.0/22\n144.48.156.0/22\n144.48.180.0/22\n144.48.184.0/22\n144.48.204.0/22\n144.48.208.0/21\n144.52.0.0/16\n144.123.0.0/16\n144.211.80.0/24\n144.211.138.0/24\n144.255.0.0/16\n146.56.192.0/18\n146.88.175.0/24\n146.196.56.0/22\n146.196.68.0/22\n146.196.92.0/22\n146.196.112.0/21\n146.196.124.0/22\n146.217.137.0/24\n146.222.79.0/24\n146.222.81.0/24\n146.222.94.0/24\n147.243.13.32/27\n147.243.13.64/27\n147.243.14.32/27\n148.70.0.0/16\n150.0.0.0/16\n150.115.0.0/16\n150.121.0.0/16\n150.122.0.0/16\n150.129.136.0/22\n150.129.192.0/22\n150.129.252.0/22\n150.138.0.0/15\n150.158.0.0/16\n150.222.88.0/23\n150.223.0.0/16\n150.242.0.0/21\n150.242.8.0/22\n150.242.28.0/22\n150.242.44.0/22\n150.242.48.0/21\n150.242.56.0/22\n150.242.76.0/22\n150.242.80.0/22\n150.242.92.0/22\n150.242.96.0/22\n150.242.112.0/21\n150.242.120.0/22\n150.242.152.0/22\n150.242.158.0/24\n150.242.160.0/21\n150.242.168.0/22\n150.242.184.0/21\n150.242.192.0/22\n150.242.226.0/23\n150.242.232.0/21\n150.242.240.0/21\n150.242.248.0/22\n150.248.0.0/16\n150.255.0.0/16\n152.32.178.0/23\n152.104.128.0/17\n152.136.0.0/16\n153.0.0.0/16\n153.3.0.0/16\n153.34.0.0/15\n153.36.0.0/15\n153.99.0.0/16\n153.101.0.0/16\n153.118.0.0/15\n154.8.128.0/17\n154.209.251.0/24\n155.126.176.0/23\n156.107.160.0/24\n156.107.170.0/24\n156.107.179.0/24\n156.107.181.0/24\n156.154.62.0/23\n157.0.0.0/16\n157.18.0.0/16\n157.61.0.0/16\n157.119.8.0/21\n157.119.16.0/22\n157.119.28.0/22\n157.119.132.0/22\n157.119.136.0/21\n157.119.144.0/20\n157.119.160.0/21\n157.119.172.0/22\n157.119.192.0/21\n157.119.240.0/22\n157.119.252.0/22\n157.122.0.0/16\n157.133.186.0/23\n157.133.192.0/21\n157.133.212.0/24\n157.133.236.0/24\n157.148.0.0/16\n157.156.0.0/16\n157.255.0.0/16\n158.60.128.0/17\n158.79.0.0/24\n158.79.2.0/23\n158.79.4.0/22\n158.79.8.0/21\n158.79.16.0/20\n158.79.32.0/19\n158.79.64.0/18\n158.79.128.0/17\n159.27.0.0/16\n159.75.0.0/16\n159.221.232.0/22\n159.226.0.0/16\n160.19.208.0/21\n160.19.216.0/22\n160.20.48.0/22\n160.62.10.0/24\n160.83.109.0/24\n160.83.110.0/23\n160.202.60.0/23\n160.202.62.0/24\n160.202.148.0/22\n160.202.152.0/22\n160.202.212.0/22\n160.202.216.0/21\n160.202.224.0/19\n160.238.64.0/22\n161.120.0.0/16\n161.163.0.0/21\n161.163.28.0/23\n161.189.0.0/16\n161.207.0.0/16\n162.14.0.0/21\n162.14.12.0/22\n162.14.16.0/21\n162.14.26.0/23\n162.14.28.0/22\n162.14.32.0/19\n162.14.64.0/18\n162.14.128.0/17\n162.105.0.0/16\n163.0.0.0/16\n163.47.4.0/22\n163.53.0.0/20\n163.53.36.0/22\n163.53.40.0/22\n163.53.48.0/20\n163.53.64.0/22\n163.53.88.0/21\n163.53.96.0/19\n163.53.128.0/21\n163.53.136.0/22\n163.53.160.0/20\n163.53.188.0/22\n163.53.220.0/22\n163.53.240.0/22\n163.125.0.0/16\n163.142.0.0/16\n163.177.0.0/16\n163.179.0.0/16\n163.204.0.0/16\n163.228.0.0/16\n163.244.246.0/24\n164.52.80.0/24\n165.84.197.0/24\n165.154.56.0/21\n165.154.64.0/18\n165.154.128.0/18\n165.154.192.0/19\n165.154.254.0/23\n165.156.30.0/24\n166.111.0.0/16\n167.139.0.0/16\n167.189.0.0/16\n167.220.244.0/22\n168.159.144.0/21\n168.159.152.0/22\n168.159.156.0/23\n168.159.158.0/24\n168.160.0.0/16\n168.230.0.0/24\n170.179.0.0/16\n170.225.224.0/23\n170.252.152.0/21\n171.8.0.0/13\n171.34.0.0/15\n171.36.0.0/14\n171.40.0.0/13\n171.80.0.0/12\n171.104.0.0/13\n171.112.0.0/12\n171.208.0.0/12\n172.81.192.0/18\n173.39.200.0/23\n175.0.0.0/12\n175.16.0.0/13\n175.24.0.0/14\n175.30.0.0/15\n175.42.0.0/15\n175.44.0.0/16\n175.46.0.0/15\n175.48.0.0/12\n175.64.0.0/11\n175.102.0.0/16\n175.106.128.0/17\n175.111.144.0/20\n175.111.160.0/20\n175.111.184.0/22\n175.146.0.0/15\n175.148.0.0/14\n175.152.0.0/14\n175.158.96.0/22\n175.160.0.0/12\n175.176.156.0/22\n175.176.188.0/22\n175.178.0.0/16\n175.184.128.0/18\n175.185.0.0/16\n175.186.0.0/15\n175.188.0.0/14\n180.76.16.0/20\n180.76.32.0/19\n180.76.64.0/18\n180.76.128.0/17\n180.77.0.0/16\n180.78.0.0/15\n180.84.0.0/15\n180.86.0.0/16\n180.88.0.0/14\n180.92.176.0/23\n180.94.56.0/21\n180.94.96.0/23\n180.94.98.0/24\n180.94.100.0/22\n180.94.104.0/21\n180.94.120.0/21\n180.95.128.0/17\n180.96.0.0/11\n180.129.128.0/17\n180.130.0.0/16\n180.136.0.0/13\n180.148.16.0/21\n180.148.152.0/21\n180.148.216.0/21\n180.148.224.0/19\n180.149.128.0/19\n180.150.160.0/21\n180.150.176.0/20\n180.152.0.0/13\n180.160.0.0/12\n180.178.112.0/21\n180.178.192.0/18\n180.184.0.0/14\n180.188.0.0/17\n180.189.148.0/22\n180.200.252.0/22\n180.201.0.0/16\n180.202.0.0/15\n180.208.0.0/15\n180.210.212.0/22\n180.210.233.0/24\n180.210.236.0/22\n180.212.0.0/15\n180.222.224.0/19\n180.223.0.0/18\n180.223.83.0/24\n180.223.84.0/22\n180.223.88.0/21\n180.223.96.0/19\n180.233.0.0/18\n180.233.64.0/19\n180.233.144.0/22\n180.235.64.0/19\n180.235.112.0/22\n182.16.144.0/21\n182.16.192.0/19\n182.18.0.0/17\n182.23.184.0/21\n182.23.200.0/21\n182.32.0.0/12\n182.48.96.0/19\n182.49.0.0/16\n182.50.0.0/22\n182.50.8.0/21\n182.50.112.0/20\n182.51.0.0/16\n182.54.0.0/17\n182.61.0.0/18\n182.61.128.0/19\n182.61.192.0/18\n182.80.0.0/13\n182.88.0.0/14\n182.92.0.0/16\n182.96.0.0/11\n182.128.0.0/12\n182.144.0.0/13\n182.157.0.0/16\n182.160.52.0/22\n182.160.56.0/22\n182.160.60.0/23\n182.160.62.0/24\n182.160.64.0/19\n182.174.0.0/15\n182.200.0.0/13\n182.236.128.0/17\n182.237.24.0/21\n182.238.0.0/16\n182.239.0.0/19\n182.240.0.0/13\n182.254.0.0/18\n182.254.64.0/19\n182.254.96.0/20\n182.254.112.0/22\n182.254.117.0/24\n182.254.119.0/24\n182.254.120.0/21\n182.254.128.0/17\n183.0.0.0/10\n183.64.0.0/13\n183.78.160.0/21\n183.78.180.0/22\n183.81.180.0/22\n183.84.0.0/15\n183.91.128.0/22\n183.91.136.0/21\n183.91.144.0/20\n183.92.0.0/14\n183.128.0.0/11\n183.160.0.0/13\n183.168.0.0/15\n183.170.0.0/16\n183.172.0.0/14\n183.184.0.0/13\n183.192.0.0/10\n185.109.236.0/24\n188.131.128.0/17\n192.11.23.0/24\n192.11.26.0/24\n192.11.39.0/24\n192.11.236.0/24\n192.23.191.0/24\n192.55.10.0/23\n192.55.40.0/24\n192.55.46.0/24\n192.55.68.0/22\n192.102.204.0/22\n192.124.154.0/24\n192.137.31.0/24\n192.140.128.0/21\n192.140.136.0/22\n192.140.156.0/22\n192.140.160.0/19\n192.140.192.0/20\n192.140.208.0/21\n192.144.128.0/17\n192.163.11.0/24\n192.232.97.0/24\n193.17.120.0/22\n193.20.64.0/22\n193.112.0.0/16\n193.200.222.160/28\n194.138.136.0/24\n194.138.202.0/23\n194.138.245.0/24\n195.142.215.0/24\n198.175.100.0/22\n198.208.17.0/24\n198.208.19.0/24\n199.7.72.0/24\n199.65.192.0/21\n199.244.144.0/24\n202.0.100.0/23\n202.0.122.0/23\n202.1.64.0/23\n202.1.68.0/23\n202.1.72.0/21\n202.1.80.0/20\n202.1.96.0/23\n202.1.100.0/22\n202.1.104.0/22\n202.1.110.0/23\n202.1.112.0/23\n202.3.128.0/23\n202.4.128.0/19\n202.4.252.0/22\n202.5.208.0/21\n202.5.216.0/22\n202.6.6.0/23\n202.6.66.0/23\n202.6.72.0/23\n202.6.87.0/24\n202.6.88.0/23\n202.6.92.0/23\n202.6.103.0/24\n202.6.108.0/24\n202.6.110.0/23\n202.6.114.0/24\n202.6.176.0/20\n202.8.0.0/24\n202.8.2.0/23\n202.8.4.0/23\n202.8.12.0/24\n202.8.24.0/24\n202.8.77.0/24\n202.8.128.0/19\n202.8.192.0/20\n202.9.32.0/24\n202.9.34.0/23\n202.9.48.0/23\n202.9.51.0/24\n202.9.52.0/23\n202.9.54.0/24\n202.9.57.0/24\n202.9.58.0/23\n202.10.64.0/21\n202.10.74.0/23\n202.10.76.0/22\n202.10.112.0/20\n202.12.1.0/24\n202.12.2.0/24\n202.12.17.0/24\n202.12.18.0/23\n202.12.72.0/24\n202.12.84.0/23\n202.12.96.0/24\n202.12.98.0/23\n202.12.106.0/24\n202.12.111.0/24\n202.12.116.0/24\n202.14.64.0/23\n202.14.69.0/24\n202.14.73.0/24\n202.14.74.0/23\n202.14.76.0/24\n202.14.78.0/23\n202.14.88.0/24\n202.14.97.0/24\n202.14.104.0/23\n202.14.108.0/23\n202.14.111.0/24\n202.14.114.0/23\n202.14.118.0/23\n202.14.124.0/23\n202.14.127.0/24\n202.14.129.0/24\n202.14.135.0/24\n202.14.136.0/24\n202.14.149.0/24\n202.14.151.0/24\n202.14.157.0/24\n202.14.158.0/23\n202.14.169.0/24\n202.14.170.0/23\n202.14.172.0/22\n202.14.176.0/24\n202.14.184.0/23\n202.14.208.0/23\n202.14.213.0/24\n202.14.219.0/24\n202.14.220.0/24\n202.14.222.0/23\n202.14.225.0/24\n202.14.226.0/23\n202.14.231.0/24\n202.14.235.0/24\n202.14.236.0/22\n202.14.246.0/24\n202.14.251.0/24\n202.20.66.0/24\n202.20.79.0/24\n202.20.87.0/24\n202.20.88.0/23\n202.20.90.0/24\n202.20.94.0/23\n202.20.114.0/24\n202.20.117.0/24\n202.20.120.0/24\n202.20.125.0/24\n202.20.126.0/23\n202.21.48.0/20\n202.21.131.0/24\n202.21.132.0/24\n202.21.141.0/24\n202.21.142.0/24\n202.21.147.0/24\n202.21.148.0/24\n202.21.150.0/23\n202.21.152.0/23\n202.21.154.0/24\n202.21.156.0/24\n202.21.208.0/24\n202.22.248.0/21\n202.27.12.0/24\n202.27.14.0/24\n202.27.136.0/23\n202.36.226.0/24\n202.38.0.0/22\n202.38.8.0/21\n202.38.48.0/20\n202.38.64.0/18\n202.38.128.0/21\n202.38.136.0/23\n202.38.138.0/24\n202.38.140.0/22\n202.38.146.0/23\n202.38.149.0/24\n202.38.150.0/23\n202.38.152.0/22\n202.38.156.0/24\n202.38.158.0/23\n202.38.160.0/23\n202.38.164.0/22\n202.38.168.0/22\n202.38.176.0/23\n202.38.184.0/21\n202.38.192.0/18\n202.40.4.0/23\n202.40.7.0/24\n202.40.15.0/24\n202.40.135.0/24\n202.40.136.0/24\n202.40.140.0/24\n202.40.143.0/24\n202.40.144.0/23\n202.40.150.0/24\n202.40.155.0/24\n202.40.156.0/24\n202.40.158.0/23\n202.40.162.0/24\n202.41.8.0/23\n202.41.11.0/24\n202.41.12.0/23\n202.41.128.0/24\n202.41.130.0/23\n202.41.142.0/24\n202.41.152.0/21\n202.41.192.0/24\n202.41.196.0/22\n202.41.200.0/22\n202.41.240.0/20\n202.43.76.0/22\n202.43.144.0/20\n202.44.16.0/20\n202.44.48.0/22\n202.44.67.0/24\n202.44.74.0/24\n202.44.97.0/24\n202.44.129.0/24\n202.44.132.0/23\n202.44.146.0/23\n202.45.0.0/23\n202.45.2.0/24\n202.45.15.0/24\n202.45.16.0/20\n202.46.16.0/23\n202.46.18.0/24\n202.46.20.0/23\n202.46.128.0/24\n202.46.224.0/20\n202.47.82.0/23\n202.47.96.0/20\n202.47.126.0/24\n202.47.128.0/24\n202.47.130.0/23\n202.52.34.0/24\n202.52.143.0/24\n202.53.140.0/24\n202.53.143.0/24\n202.57.212.0/22\n202.57.216.0/22\n202.57.240.0/20\n202.58.0.0/24\n202.58.112.0/22\n202.59.0.0/23\n202.59.212.0/22\n202.59.236.0/24\n202.59.240.0/24\n202.60.48.0/21\n202.60.96.0/21\n202.60.112.0/20\n202.60.132.0/22\n202.60.136.0/21\n202.60.144.0/20\n202.61.68.0/22\n202.61.76.0/22\n202.61.88.0/22\n202.61.123.0/24\n202.61.127.0/24\n202.62.112.0/22\n202.62.248.0/22\n202.62.252.0/24\n202.62.255.0/24\n202.63.80.0/20\n202.63.160.0/19\n202.63.248.0/22\n202.63.253.0/24\n202.65.0.0/21\n202.65.8.0/23\n202.67.0.0/22\n202.69.4.0/23\n202.69.16.0/20\n202.70.0.0/19\n202.70.96.0/20\n202.70.192.0/20\n202.71.32.0/20\n202.72.40.0/21\n202.72.80.0/20\n202.72.112.0/20\n202.73.128.0/22\n202.73.240.0/20\n202.74.8.0/21\n202.74.36.0/24\n202.74.42.0/24\n202.74.52.0/24\n202.74.80.0/20\n202.74.254.0/23\n202.75.208.0/20\n202.75.252.0/22\n202.76.247.0/24\n202.76.252.0/22\n202.77.80.0/21\n202.77.92.0/22\n202.78.8.0/21\n202.79.224.0/21\n202.79.248.0/22\n202.80.192.0/20\n202.81.0.0/22\n202.81.176.0/20\n202.83.252.0/22\n202.84.4.0/22\n202.84.8.0/21\n202.84.16.0/23\n202.84.22.0/24\n202.84.24.0/21\n202.85.208.0/20\n202.86.249.0/24\n202.87.80.0/20\n202.88.32.0/22\n202.89.8.0/21\n202.89.96.0/22\n202.89.108.0/22\n202.89.119.0/24\n202.89.232.0/21\n202.90.0.0/22\n202.90.16.0/20\n202.90.37.0/24\n202.90.96.0/19\n202.90.193.0/24\n202.90.196.0/24\n202.90.205.0/24\n202.90.224.0/20\n202.91.0.0/22\n202.91.96.0/20\n202.91.128.0/22\n202.91.176.0/20\n202.91.224.0/19\n202.92.0.0/22\n202.92.8.0/21\n202.92.48.0/20\n202.92.252.0/22\n202.93.0.0/22\n202.93.252.0/22\n202.94.0.0/19\n202.94.74.0/24\n202.94.81.0/24\n202.94.92.0/22\n202.95.240.0/21\n202.95.252.0/22\n202.96.0.0/12\n202.112.0.0/13\n202.120.0.0/15\n202.122.0.0/21\n202.122.32.0/21\n202.122.64.0/19\n202.122.112.0/20\n202.122.128.0/24\n202.122.132.0/24\n202.123.96.0/20\n202.123.116.0/22\n202.123.120.0/22\n202.124.16.0/21\n202.124.24.0/22\n202.125.107.0/24\n202.125.109.0/24\n202.125.112.0/20\n202.125.176.0/20\n202.127.0.0/21\n202.127.12.0/22\n202.127.16.0/20\n202.127.40.0/21\n202.127.48.0/20\n202.127.112.0/20\n202.127.128.0/19\n202.127.160.0/21\n202.127.192.0/20\n202.127.208.0/23\n202.127.212.0/22\n202.127.216.0/21\n202.127.224.0/19\n202.129.208.0/24\n202.130.0.0/19\n202.130.39.0/24\n202.130.224.0/19\n202.131.16.0/21\n202.131.59.0/24\n202.131.208.0/20\n202.133.32.0/20\n202.134.58.0/24\n202.134.128.0/20\n202.134.208.0/20\n202.136.48.0/20\n202.136.208.0/20\n202.136.224.0/20\n202.136.248.0/22\n202.136.254.0/23\n202.137.231.0/24\n202.140.140.0/22\n202.140.144.0/20\n202.141.160.0/19\n202.142.16.0/20\n202.143.4.0/22\n202.143.16.0/20\n202.143.32.0/20\n202.143.56.0/21\n202.143.100.0/22\n202.143.104.0/22\n202.146.160.0/20\n202.146.186.0/24\n202.146.188.0/22\n202.146.196.0/22\n202.146.200.0/21\n202.147.144.0/20\n202.148.32.0/20\n202.148.64.0/18\n202.149.32.0/19\n202.149.160.0/19\n202.149.224.0/19\n202.150.16.0/20\n202.150.32.0/20\n202.150.56.0/22\n202.150.192.0/20\n202.150.224.0/19\n202.151.0.0/22\n202.151.128.0/19\n202.152.176.0/20\n202.153.0.0/22\n202.153.7.0/24\n202.153.48.0/20\n202.157.192.0/19\n202.158.160.0/19\n202.158.242.0/24\n202.160.140.0/22\n202.160.156.0/22\n202.160.176.64/26\n202.160.176.128/25\n202.160.177.0/24\n202.160.178.0/23\n202.160.180.0/22\n202.160.184.0/21\n202.162.67.0/24\n202.162.75.0/24\n202.164.0.0/20\n202.164.96.0/19\n202.165.176.0/20\n202.165.208.0/20\n202.165.239.0/24\n202.165.240.0/23\n202.165.243.0/24\n202.165.245.0/24\n202.165.251.0/24\n202.165.252.0/22\n202.166.224.0/19\n202.168.80.0/22\n202.168.128.0/20\n202.168.160.0/19\n202.170.128.0/19\n202.170.216.0/21\n202.170.224.0/19\n202.171.216.0/21\n202.171.232.0/24\n202.171.235.0/24\n202.172.0.0/22\n202.172.7.0/24\n202.173.0.0/22\n202.173.6.0/24\n202.173.8.0/21\n202.173.112.0/22\n202.173.224.0/19\n202.174.64.0/20\n202.174.124.0/22\n202.176.224.0/19\n202.179.160.0/20\n202.179.240.0/20\n202.180.128.0/19\n202.180.208.0/21\n202.181.8.0/22\n202.181.28.0/22\n202.181.112.0/20\n202.182.32.0/20\n202.182.192.0/19\n202.189.0.0/18\n202.189.80.0/20\n202.189.184.0/21\n202.191.0.0/24\n202.191.68.0/22\n202.191.72.0/21\n202.191.80.0/20\n202.192.0.0/12\n203.0.4.0/22\n203.0.10.0/23\n203.0.18.0/24\n203.0.24.0/24\n203.0.42.0/23\n203.0.45.0/24\n203.0.46.0/23\n203.0.81.0/24\n203.0.82.0/23\n203.0.90.0/23\n203.0.96.0/23\n203.0.104.0/21\n203.0.114.0/23\n203.0.122.0/24\n203.0.128.0/24\n203.0.130.0/23\n203.0.132.0/22\n203.0.137.0/24\n203.0.142.0/24\n203.0.144.0/24\n203.0.146.0/24\n203.0.148.0/24\n203.0.150.0/23\n203.0.152.0/24\n203.0.177.0/24\n203.0.224.0/24\n203.1.4.0/22\n203.1.18.0/24\n203.1.26.0/23\n203.1.65.0/24\n203.1.66.0/23\n203.1.70.0/23\n203.1.76.0/23\n203.1.90.0/24\n203.1.97.0/24\n203.1.98.0/23\n203.1.100.0/22\n203.1.108.0/24\n203.1.253.0/24\n203.1.254.0/24\n203.2.64.0/21\n203.2.73.0/24\n203.2.112.0/21\n203.2.126.0/23\n203.2.140.0/24\n203.2.150.0/24\n203.2.152.0/22\n203.2.156.0/23\n203.2.160.0/21\n203.2.180.0/23\n203.2.196.0/23\n203.2.209.0/24\n203.2.214.0/23\n203.2.226.0/23\n203.2.229.0/24\n203.2.236.0/23\n203.3.68.0/24\n203.3.72.0/23\n203.3.75.0/24\n203.3.80.0/21\n203.3.96.0/22\n203.3.105.0/24\n203.3.112.0/21\n203.3.120.0/24\n203.3.123.0/24\n203.3.135.0/24\n203.3.139.0/24\n203.3.143.0/24\n203.4.132.0/23\n203.4.134.0/24\n203.4.151.0/24\n203.4.152.0/22\n203.4.174.0/23\n203.4.180.0/24\n203.4.186.0/24\n203.4.205.0/24\n203.4.208.0/22\n203.4.227.0/24\n203.4.230.0/23\n203.5.4.0/23\n203.5.7.0/24\n203.5.8.0/23\n203.5.11.0/24\n203.5.21.0/24\n203.5.22.0/24\n203.5.44.0/24\n203.5.46.0/23\n203.5.52.0/22\n203.5.56.0/23\n203.5.60.0/23\n203.5.114.0/23\n203.5.118.0/24\n203.5.120.0/24\n203.5.172.0/24\n203.5.180.0/23\n203.5.182.0/24\n203.5.185.0/24\n203.5.186.0/24\n203.5.188.0/23\n203.5.190.0/24\n203.5.195.0/24\n203.5.214.0/23\n203.5.218.0/23\n203.6.131.0/24\n203.6.136.0/24\n203.6.138.0/23\n203.6.142.0/24\n203.6.150.0/23\n203.6.157.0/24\n203.6.159.0/24\n203.6.224.0/20\n203.6.248.0/23\n203.7.129.0/24\n203.7.138.0/23\n203.7.147.0/24\n203.7.150.0/23\n203.7.158.0/24\n203.7.192.0/23\n203.7.200.0/24\n203.8.0.0/24\n203.8.8.0/24\n203.8.23.0/24\n203.8.70.0/24\n203.8.82.0/24\n203.8.86.0/23\n203.8.91.0/24\n203.8.110.0/23\n203.8.115.0/24\n203.8.166.0/23\n203.8.169.0/24\n203.8.173.0/24\n203.8.184.0/24\n203.8.186.0/23\n203.8.190.0/23\n203.8.192.0/24\n203.8.197.0/24\n203.8.198.0/23\n203.8.203.0/24\n203.8.209.0/24\n203.8.210.0/23\n203.8.212.0/22\n203.8.217.0/24\n203.8.220.0/24\n203.9.32.0/24\n203.9.36.0/23\n203.9.57.0/24\n203.9.63.0/24\n203.9.65.0/24\n203.9.70.0/23\n203.9.72.0/24\n203.9.75.0/24\n203.9.76.0/23\n203.9.96.0/22\n203.9.100.0/23\n203.9.108.0/24\n203.9.158.0/24\n203.10.34.0/24\n203.10.56.0/24\n203.10.74.0/23\n203.10.84.0/22\n203.10.88.0/24\n203.10.95.0/24\n203.10.125.0/24\n203.11.70.0/24\n203.11.76.0/22\n203.11.82.0/24\n203.11.84.0/22\n203.11.100.0/22\n203.11.109.0/24\n203.11.117.0/24\n203.11.122.0/24\n203.11.126.0/24\n203.11.136.0/22\n203.11.141.0/24\n203.11.142.0/23\n203.11.180.0/22\n203.11.208.0/22\n203.12.16.0/24\n203.12.19.0/24\n203.12.24.0/24\n203.12.57.0/24\n203.12.65.0/24\n203.12.66.0/24\n203.12.70.0/23\n203.12.87.0/24\n203.12.100.0/23\n203.12.103.0/24\n203.12.114.0/24\n203.12.118.0/24\n203.12.130.0/24\n203.12.137.0/24\n203.12.196.0/22\n203.12.211.0/24\n203.12.219.0/24\n203.12.226.0/24\n203.12.240.0/22\n203.13.18.0/24\n203.13.24.0/24\n203.13.44.0/23\n203.13.88.0/23\n203.13.92.0/22\n203.13.173.0/24\n203.13.224.0/23\n203.13.227.0/24\n203.13.233.0/24\n203.14.24.0/22\n203.14.33.0/24\n203.14.56.0/24\n203.14.61.0/24\n203.14.62.0/24\n203.14.104.0/24\n203.14.114.0/23\n203.14.118.0/24\n203.14.162.0/24\n203.14.184.0/21\n203.14.192.0/24\n203.14.194.0/23\n203.14.214.0/24\n203.14.231.0/24\n203.14.246.0/24\n203.15.0.0/20\n203.15.20.0/23\n203.15.22.0/24\n203.15.87.0/24\n203.15.88.0/23\n203.15.105.0/24\n203.15.112.0/21\n203.15.130.0/23\n203.15.149.0/24\n203.15.151.0/24\n203.15.156.0/22\n203.15.174.0/24\n203.15.227.0/24\n203.15.232.0/22\n203.15.238.0/23\n203.15.240.0/23\n203.15.246.0/24\n203.16.10.0/24\n203.16.12.0/23\n203.16.16.0/21\n203.16.27.0/24\n203.16.38.0/24\n203.16.49.0/24\n203.16.50.0/23\n203.16.58.0/24\n203.16.63.0/24\n203.16.133.0/24\n203.16.161.0/24\n203.16.162.0/24\n203.16.186.0/23\n203.16.228.0/24\n203.16.238.0/24\n203.16.240.0/24\n203.16.245.0/24\n203.17.2.0/24\n203.17.18.0/24\n203.17.28.0/24\n203.17.39.0/24\n203.17.56.0/24\n203.17.74.0/23\n203.17.88.0/23\n203.17.136.0/24\n203.17.164.0/24\n203.17.187.0/24\n203.17.190.0/23\n203.17.231.0/24\n203.17.233.0/24\n203.17.248.0/23\n203.17.255.0/24\n203.18.2.0/23\n203.18.4.0/24\n203.18.7.0/24\n203.18.31.0/24\n203.18.37.0/24\n203.18.48.0/23\n203.18.52.0/24\n203.18.72.0/22\n203.18.80.0/23\n203.18.87.0/24\n203.18.100.0/23\n203.18.105.0/24\n203.18.107.0/24\n203.18.110.0/24\n203.18.129.0/24\n203.18.131.0/24\n203.18.132.0/23\n203.18.144.0/24\n203.18.153.0/24\n203.18.199.0/24\n203.18.208.0/24\n203.18.211.0/24\n203.18.215.0/24\n203.19.1.0/24\n203.19.18.0/24\n203.19.24.0/24\n203.19.30.0/24\n203.19.41.0/24\n203.19.44.0/23\n203.19.46.0/24\n203.19.58.0/24\n203.19.60.0/23\n203.19.64.0/24\n203.19.68.0/24\n203.19.72.0/24\n203.19.101.0/24\n203.19.111.0/24\n203.19.131.0/24\n203.19.133.0/24\n203.19.144.0/24\n203.19.147.0/24\n203.19.149.0/24\n203.19.156.0/24\n203.19.176.0/24\n203.19.178.0/23\n203.19.208.0/24\n203.19.228.0/22\n203.19.233.0/24\n203.19.242.0/24\n203.19.248.0/23\n203.19.255.0/24\n203.20.17.0/24\n203.20.40.0/23\n203.20.44.0/24\n203.20.48.0/24\n203.20.61.0/24\n203.20.65.0/24\n203.20.84.0/23\n203.20.89.0/24\n203.20.106.0/23\n203.20.115.0/24\n203.20.117.0/24\n203.20.118.0/23\n203.20.122.0/24\n203.20.126.0/23\n203.20.135.0/24\n203.20.140.0/22\n203.20.150.0/24\n203.20.230.0/24\n203.20.232.0/24\n203.20.236.0/24\n203.21.0.0/23\n203.21.2.0/24\n203.21.8.0/24\n203.21.10.0/24\n203.21.18.0/24\n203.21.33.0/24\n203.21.34.0/24\n203.21.41.0/24\n203.21.44.0/24\n203.21.68.0/24\n203.21.82.0/24\n203.21.96.0/22\n203.21.124.0/24\n203.21.136.0/23\n203.21.145.0/24\n203.21.206.0/24\n203.22.24.0/24\n203.22.28.0/23\n203.22.31.0/24\n203.22.68.0/24\n203.22.76.0/24\n203.22.78.0/24\n203.22.84.0/24\n203.22.87.0/24\n203.22.92.0/22\n203.22.99.0/24\n203.22.106.0/24\n203.22.122.0/23\n203.22.131.0/24\n203.22.163.0/24\n203.22.166.0/24\n203.22.170.0/24\n203.22.194.0/24\n203.22.242.0/23\n203.22.245.0/24\n203.22.246.0/24\n203.22.252.0/23\n203.23.0.0/24\n203.23.47.0/24\n203.23.61.0/24\n203.23.62.0/23\n203.23.73.0/24\n203.23.85.0/24\n203.23.92.0/22\n203.23.98.0/24\n203.23.107.0/24\n203.23.112.0/24\n203.23.130.0/24\n203.23.140.0/23\n203.23.172.0/24\n203.23.182.0/24\n203.23.186.0/23\n203.23.192.0/24\n203.23.197.0/24\n203.23.198.0/24\n203.23.204.0/22\n203.23.224.0/24\n203.23.226.0/23\n203.23.228.0/22\n203.23.249.0/24\n203.23.251.0/24\n203.24.13.0/24\n203.24.18.0/24\n203.24.27.0/24\n203.24.43.0/24\n203.24.56.0/24\n203.24.58.0/24\n203.24.67.0/24\n203.24.74.0/24\n203.24.79.0/24\n203.24.80.0/23\n203.24.84.0/23\n203.24.86.0/24\n203.24.90.0/24\n203.24.111.0/24\n203.24.112.0/24\n203.24.116.0/24\n203.24.122.0/23\n203.24.145.0/24\n203.24.152.0/23\n203.24.157.0/24\n203.24.161.0/24\n203.24.167.0/24\n203.24.186.0/23\n203.24.199.0/24\n203.24.202.0/24\n203.24.212.0/23\n203.24.217.0/24\n203.24.219.0/24\n203.24.244.0/24\n203.25.19.0/24\n203.25.20.0/23\n203.25.46.0/24\n203.25.64.0/23\n203.25.91.0/24\n203.25.99.0/24\n203.25.100.0/24\n203.25.106.0/24\n203.25.131.0/24\n203.25.135.0/24\n203.25.138.0/24\n203.25.147.0/24\n203.25.153.0/24\n203.25.154.0/23\n203.25.164.0/24\n203.25.166.0/24\n203.25.174.0/23\n203.25.180.0/24\n203.25.182.0/24\n203.25.191.0/24\n203.25.199.0/24\n203.25.200.0/24\n203.25.202.0/23\n203.25.208.0/20\n203.25.229.0/24\n203.25.235.0/24\n203.25.236.0/24\n203.25.242.0/24\n203.26.12.0/24\n203.26.34.0/24\n203.26.49.0/24\n203.26.50.0/24\n203.26.55.0/24\n203.26.56.0/23\n203.26.60.0/24\n203.26.65.0/24\n203.26.68.0/24\n203.26.76.0/24\n203.26.80.0/24\n203.26.84.0/24\n203.26.97.0/24\n203.26.102.0/23\n203.26.115.0/24\n203.26.116.0/24\n203.26.129.0/24\n203.26.143.0/24\n203.26.144.0/24\n203.26.148.0/23\n203.26.154.0/24\n203.26.158.0/23\n203.26.170.0/24\n203.26.173.0/24\n203.26.176.0/24\n203.26.185.0/24\n203.26.202.0/23\n203.26.210.0/24\n203.26.214.0/24\n203.26.222.0/24\n203.26.224.0/24\n203.26.228.0/24\n203.26.232.0/24\n203.27.0.0/24\n203.27.10.0/24\n203.27.15.0/24\n203.27.16.0/24\n203.27.20.0/24\n203.27.22.0/23\n203.27.40.0/24\n203.27.45.0/24\n203.27.53.0/24\n203.27.65.0/24\n203.27.66.0/24\n203.27.81.0/24\n203.27.88.0/24\n203.27.102.0/24\n203.27.109.0/24\n203.27.117.0/24\n203.27.121.0/24\n203.27.122.0/23\n203.27.125.0/24\n203.27.200.0/24\n203.27.202.0/24\n203.27.233.0/24\n203.27.241.0/24\n203.27.250.0/24\n203.28.10.0/24\n203.28.12.0/24\n203.28.33.0/24\n203.28.34.0/23\n203.28.43.0/24\n203.28.44.0/24\n203.28.54.0/24\n203.28.56.0/24\n203.28.73.0/24\n203.28.74.0/24\n203.28.76.0/24\n203.28.86.0/24\n203.28.88.0/24\n203.28.112.0/24\n203.28.131.0/24\n203.28.136.0/24\n203.28.140.0/24\n203.28.145.0/24\n203.28.165.0/24\n203.28.169.0/24\n203.28.170.0/24\n203.28.178.0/23\n203.28.185.0/24\n203.28.187.0/24\n203.28.196.0/24\n203.28.226.0/23\n203.28.239.0/24\n203.29.2.0/24\n203.29.8.0/23\n203.29.13.0/24\n203.29.14.0/24\n203.29.28.0/24\n203.29.46.0/24\n203.29.57.0/24\n203.29.61.0/24\n203.29.63.0/24\n203.29.69.0/24\n203.29.73.0/24\n203.29.81.0/24\n203.29.90.0/24\n203.29.95.0/24\n203.29.100.0/24\n203.29.103.0/24\n203.29.112.0/24\n203.29.120.0/22\n203.29.182.0/23\n203.29.187.0/24\n203.29.189.0/24\n203.29.190.0/24\n203.29.205.0/24\n203.29.210.0/24\n203.29.217.0/24\n203.29.227.0/24\n203.29.231.0/24\n203.29.233.0/24\n203.29.234.0/24\n203.29.248.0/24\n203.29.254.0/23\n203.30.16.0/23\n203.30.25.0/24\n203.30.27.0/24\n203.30.29.0/24\n203.30.66.0/24\n203.30.81.0/24\n203.30.87.0/24\n203.30.111.0/24\n203.30.121.0/24\n203.30.123.0/24\n203.30.152.0/24\n203.30.156.0/24\n203.30.162.0/24\n203.30.173.0/24\n203.30.175.0/24\n203.30.187.0/24\n203.30.194.0/24\n203.30.217.0/24\n203.30.220.0/24\n203.30.222.0/24\n203.30.232.0/23\n203.30.235.0/24\n203.30.240.0/23\n203.30.246.0/24\n203.30.250.0/23\n203.31.45.0/24\n203.31.46.0/24\n203.31.49.0/24\n203.31.51.0/24\n203.31.54.0/23\n203.31.69.0/24\n203.31.72.0/24\n203.31.80.0/24\n203.31.85.0/24\n203.31.97.0/24\n203.31.105.0/24\n203.31.106.0/24\n203.31.108.0/23\n203.31.124.0/24\n203.31.162.0/24\n203.31.174.0/24\n203.31.177.0/24\n203.31.181.0/24\n203.31.187.0/24\n203.31.189.0/24\n203.31.204.0/24\n203.31.220.0/24\n203.31.222.0/23\n203.31.225.0/24\n203.31.229.0/24\n203.31.248.0/23\n203.31.253.0/24\n203.32.20.0/24\n203.32.48.0/23\n203.32.56.0/24\n203.32.60.0/24\n203.32.62.0/24\n203.32.68.0/23\n203.32.76.0/24\n203.32.81.0/24\n203.32.84.0/23\n203.32.95.0/24\n203.32.102.0/24\n203.32.105.0/24\n203.32.130.0/24\n203.32.133.0/24\n203.32.140.0/24\n203.32.152.0/24\n203.32.186.0/23\n203.32.192.0/24\n203.32.196.0/24\n203.32.203.0/24\n203.32.204.0/23\n203.32.212.0/24\n203.33.4.0/24\n203.33.7.0/24\n203.33.12.0/23\n203.33.21.0/24\n203.33.26.0/24\n203.33.32.0/24\n203.33.63.0/24\n203.33.64.0/24\n203.33.67.0/24\n203.33.68.0/24\n203.33.73.0/24\n203.33.79.0/24\n203.33.100.0/24\n203.33.122.0/24\n203.33.129.0/24\n203.33.131.0/24\n203.33.145.0/24\n203.33.156.0/24\n203.33.158.0/23\n203.33.174.0/24\n203.33.185.0/24\n203.33.200.0/24\n203.33.202.0/23\n203.33.204.0/24\n203.33.206.0/23\n203.33.214.0/23\n203.33.224.0/23\n203.33.226.0/24\n203.33.233.0/24\n203.33.243.0/24\n203.33.250.0/24\n203.34.4.0/24\n203.34.21.0/24\n203.34.27.0/24\n203.34.39.0/24\n203.34.48.0/23\n203.34.54.0/24\n203.34.56.0/23\n203.34.67.0/24\n203.34.69.0/24\n203.34.76.0/24\n203.34.92.0/24\n203.34.106.0/24\n203.34.113.0/24\n203.34.147.0/24\n203.34.150.0/24\n203.34.152.0/23\n203.34.161.0/24\n203.34.162.0/24\n203.34.187.0/24\n203.34.198.0/24\n203.34.204.0/22\n203.34.232.0/24\n203.34.240.0/24\n203.34.242.0/24\n203.34.245.0/24\n203.34.251.0/24\n203.55.2.0/23\n203.55.4.0/24\n203.55.10.0/24\n203.55.13.0/24\n203.55.22.0/24\n203.55.30.0/24\n203.55.93.0/24\n203.55.101.0/24\n203.55.109.0/24\n203.55.110.0/24\n203.55.116.0/23\n203.55.119.0/24\n203.55.128.0/23\n203.55.146.0/23\n203.55.192.0/24\n203.55.196.0/24\n203.55.218.0/23\n203.55.221.0/24\n203.55.224.0/24\n203.56.1.0/24\n203.56.4.0/24\n203.56.12.0/24\n203.56.24.0/24\n203.56.38.0/24\n203.56.40.0/24\n203.56.46.0/24\n203.56.68.0/23\n203.56.82.0/23\n203.56.84.0/23\n203.56.95.0/24\n203.56.110.0/24\n203.56.121.0/24\n203.56.161.0/24\n203.56.169.0/24\n203.56.172.0/23\n203.56.175.0/24\n203.56.183.0/24\n203.56.185.0/24\n203.56.187.0/24\n203.56.192.0/24\n203.56.198.0/24\n203.56.201.0/24\n203.56.208.0/23\n203.56.210.0/24\n203.56.214.0/24\n203.56.216.0/24\n203.56.227.0/24\n203.56.228.0/24\n203.56.232.0/24\n203.56.240.0/24\n203.56.252.0/24\n203.56.254.0/24\n203.57.5.0/24\n203.57.6.0/24\n203.57.12.0/23\n203.57.28.0/24\n203.57.39.0/24\n203.57.46.0/24\n203.57.58.0/24\n203.57.61.0/24\n203.57.66.0/24\n203.57.69.0/24\n203.57.70.0/23\n203.57.73.0/24\n203.57.90.0/24\n203.57.101.0/24\n203.57.109.0/24\n203.57.123.0/24\n203.57.157.0/24\n203.57.200.0/24\n203.57.202.0/24\n203.57.206.0/24\n203.57.222.0/24\n203.57.224.0/20\n203.57.246.0/23\n203.57.249.0/24\n203.57.253.0/24\n203.57.254.0/23\n203.62.2.0/24\n203.62.131.0/24\n203.62.139.0/24\n203.62.161.0/24\n203.62.197.0/24\n203.62.228.0/22\n203.62.234.0/24\n203.62.246.0/24\n203.65.240.0/22\n203.76.160.0/22\n203.76.168.0/22\n203.76.208.0/21\n203.76.216.0/22\n203.76.240.0/22\n203.77.180.0/22\n203.78.48.0/20\n203.78.156.0/22\n203.79.0.0/20\n203.80.4.0/23\n203.80.32.0/20\n203.80.57.0/24\n203.80.129.0/24\n203.80.132.0/22\n203.80.144.0/20\n203.81.16.0/20\n203.81.244.0/22\n203.82.0.0/23\n203.82.112.0/20\n203.82.224.0/20\n203.83.0.0/22\n203.83.12.0/22\n203.83.56.0/21\n203.83.224.0/20\n203.86.0.0/17\n203.86.250.0/24\n203.86.254.0/23\n203.88.32.0/19\n203.88.100.0/22\n203.88.192.0/19\n203.89.0.0/22\n203.89.136.0/22\n203.89.144.0/24\n203.90.0.0/22\n203.90.8.0/21\n203.90.128.0/18\n203.90.192.0/19\n203.91.32.0/19\n203.91.96.0/20\n203.91.120.0/21\n203.92.0.0/22\n203.92.6.0/24\n203.92.160.0/19\n203.93.0.0/16\n203.94.0.0/19\n203.95.0.0/21\n203.95.96.0/19\n203.95.129.0/24\n203.95.130.0/23\n203.95.132.0/22\n203.95.136.0/21\n203.95.144.0/20\n203.95.160.0/19\n203.95.200.0/21\n203.95.208.0/22\n203.95.224.0/19\n203.99.16.0/22\n203.99.30.0/23\n203.99.80.0/20\n203.100.32.0/20\n203.100.58.0/24\n203.100.60.0/24\n203.100.63.0/24\n203.100.80.0/20\n203.100.96.0/19\n203.100.192.0/20\n203.104.32.0/20\n203.105.96.0/19\n203.105.128.0/19\n203.107.0.0/19\n203.107.32.0/20\n203.107.52.0/22\n203.107.56.0/21\n203.107.69.0/24\n203.107.70.0/23\n203.107.72.0/21\n203.107.80.0/20\n203.107.96.0/19\n203.110.160.0/19\n203.110.208.0/20\n203.110.232.0/23\n203.110.234.0/24\n203.114.80.0/20\n203.114.244.0/22\n203.118.192.0/19\n203.118.241.0/24\n203.118.248.0/22\n203.119.24.0/22\n203.119.28.0/23\n203.119.30.0/24\n203.119.32.0/24\n203.119.34.0/23\n203.119.80.0/22\n203.119.85.0/24\n203.119.113.0/24\n203.119.114.0/23\n203.119.116.0/22\n203.119.128.0/17\n203.123.58.0/24\n203.128.32.0/19\n203.128.96.0/19\n203.128.128.0/24\n203.130.32.0/20\n203.130.49.0/24\n203.130.51.0/24\n203.130.53.0/24\n203.130.54.0/23\n203.130.56.0/22\n203.130.60.0/23\n203.132.32.0/19\n203.134.240.0/22\n203.134.246.0/23\n203.135.96.0/19\n203.135.160.0/20\n203.142.12.0/23\n203.142.219.0/24\n203.142.224.0/19\n203.144.96.0/19\n203.145.0.0/19\n203.148.0.0/18\n203.148.64.0/20\n203.148.80.0/22\n203.148.86.0/23\n203.149.92.0/22\n203.152.64.0/19\n203.152.128.0/19\n203.153.0.0/22\n203.156.192.0/18\n203.158.16.0/21\n203.160.129.0/24\n203.160.192.0/19\n203.161.0.0/22\n203.161.180.0/24\n203.161.183.0/24\n203.161.192.0/19\n203.166.160.0/19\n203.167.28.0/22\n203.168.0.0/19\n203.170.58.0/23\n203.171.0.0/22\n203.171.208.0/24\n203.171.224.0/20\n203.174.4.0/24\n203.174.6.0/24\n203.174.96.0/20\n203.175.128.0/19\n203.175.192.0/18\n203.176.0.0/18\n203.176.64.0/19\n203.176.168.0/21\n203.184.80.0/20\n203.187.160.0/19\n203.189.0.0/23\n203.189.6.0/23\n203.189.112.0/22\n203.189.192.0/19\n203.189.240.0/22\n203.190.96.0/20\n203.190.249.0/24\n203.191.0.0/23\n203.191.2.0/24\n203.191.5.0/24\n203.191.7.0/24\n203.191.29.0/24\n203.191.31.0/24\n203.191.64.0/18\n203.191.133.0/24\n203.191.144.0/20\n203.192.0.0/19\n203.193.224.0/19\n203.195.64.0/19\n203.195.128.0/17\n203.196.0.0/21\n203.196.28.0/22\n203.201.181.0/24\n203.201.182.0/24\n203.202.236.0/22\n203.205.64.0/19\n203.207.64.0/18\n203.207.128.0/17\n203.208.0.0/20\n203.208.16.0/22\n203.208.32.0/19\n203.209.224.0/19\n203.212.0.0/20\n203.212.80.0/20\n203.217.164.0/22\n203.223.0.0/20\n204.55.160.0/24\n204.74.96.0/24\n204.114.176.0/23\n210.2.0.0/23\n210.2.2.0/24\n210.2.5.0/24\n210.2.6.0/23\n210.2.8.0/21\n210.2.24.0/21\n210.5.0.0/19\n210.5.60.0/24\n210.5.128.0/19\n210.7.56.0/21\n210.12.0.0/15\n210.14.64.0/19\n210.14.112.0/20\n210.14.128.0/17\n210.15.0.0/17\n210.15.128.0/18\n210.16.128.0/21\n210.16.136.0/22\n210.16.156.0/22\n210.16.160.0/24\n210.16.162.0/23\n210.16.164.0/22\n210.16.168.0/21\n210.16.176.0/20\n210.21.0.0/16\n210.22.0.0/16\n210.23.32.0/19\n210.25.0.0/17\n210.25.128.0/19\n210.25.160.0/20\n210.25.176.0/21\n210.25.184.0/23\n210.25.186.0/26\n210.25.186.128/25\n210.25.187.0/24\n210.25.188.0/22\n210.25.192.0/18\n210.26.0.0/15\n210.28.0.0/14\n210.32.0.0/12\n210.51.0.0/16\n210.52.0.0/18\n210.52.64.0/23\n210.52.66.0/24\n210.52.69.0/24\n210.52.70.0/23\n210.52.72.0/21\n210.52.80.0/20\n210.52.96.0/21\n210.52.104.0/22\n210.52.108.0/24\n210.52.110.0/23\n210.52.112.0/20\n210.52.128.0/17\n210.53.0.0/16\n210.56.192.0/19\n210.72.0.0/14\n210.76.0.0/15\n210.78.0.0/16\n210.79.64.0/18\n210.79.224.0/19\n210.82.0.0/15\n210.87.128.0/18\n210.185.192.0/18\n210.192.96.0/19\n211.64.0.0/13\n211.80.0.0/12\n211.96.0.0/14\n211.100.0.0/17\n211.100.128.0/19\n211.100.160.0/20\n211.100.184.0/21\n211.100.192.0/18\n211.101.0.0/16\n211.102.0.0/15\n211.136.0.0/13\n211.144.0.0/13\n211.152.0.0/17\n211.152.134.0/23\n211.152.140.0/22\n211.152.150.0/23\n211.152.157.0/24\n211.152.160.0/19\n211.152.192.0/18\n211.153.0.0/16\n211.154.0.0/19\n211.154.32.0/20\n211.154.48.0/21\n211.154.64.0/18\n211.154.128.0/17\n211.155.0.0/18\n211.155.67.0/24\n211.155.68.0/24\n211.155.72.0/21\n211.155.80.0/20\n211.155.97.0/24\n211.155.98.0/23\n211.155.100.0/22\n211.155.104.0/21\n211.155.113.0/24\n211.155.116.0/22\n211.155.120.0/21\n211.155.128.0/17\n211.156.0.0/18\n211.156.64.0/19\n211.156.96.0/21\n211.156.104.0/22\n211.156.108.0/23\n211.156.112.0/20\n211.156.128.0/17\n211.157.0.0/16\n211.158.0.0/15\n211.160.0.0/13\n212.64.0.0/17\n212.129.128.0/17\n213.199.169.0/24\n213.255.230.0/23\n218.0.0.0/12\n218.16.0.0/13\n218.24.0.0/14\n218.28.0.0/15\n218.30.0.0/19\n218.30.64.0/18\n218.30.128.0/17\n218.31.0.0/16\n218.56.0.0/13\n218.64.0.0/11\n218.96.0.0/15\n218.98.0.0/18\n218.98.77.0/24\n218.98.78.0/23\n218.98.80.0/20\n218.98.96.0/22\n218.98.100.0/24\n218.98.102.0/23\n218.98.104.0/21\n218.98.112.0/20\n218.98.128.0/19\n218.98.192.0/18\n218.99.0.0/16\n218.100.96.0/19\n218.100.128.0/17\n218.104.0.0/14\n218.108.0.0/15\n218.185.192.0/19\n218.192.0.0/12\n218.240.0.0/14\n218.244.0.0/15\n218.246.0.0/19\n218.246.32.0/20\n218.246.48.0/21\n218.246.56.0/23\n218.246.58.0/24\n218.246.60.0/22\n218.246.64.0/18\n218.246.129.0/24\n218.246.131.0/24\n218.246.132.0/23\n218.246.134.0/24\n218.246.139.0/24\n218.246.144.0/20\n218.246.160.0/19\n218.246.192.0/18\n218.247.0.0/18\n218.247.96.0/19\n218.247.128.0/17\n218.249.0.0/16\n219.72.0.0/16\n219.82.0.0/16\n219.83.128.0/17\n219.90.68.0/22\n219.90.72.0/21\n219.128.0.0/11\n219.216.0.0/13\n219.224.0.0/13\n219.232.0.0/15\n219.234.0.0/21\n219.234.10.0/23\n219.234.12.0/22\n219.234.32.0/19\n219.234.64.0/18\n219.234.128.0/17\n219.235.0.0/16\n219.236.0.0/14\n219.242.0.0/15\n219.244.0.0/14\n220.101.192.0/18\n220.112.0.0/14\n220.152.128.0/17\n220.154.0.0/16\n220.155.0.0/21\n220.155.9.0/24\n220.155.10.0/23\n220.155.12.0/22\n220.155.16.0/21\n220.155.24.0/22\n220.155.28.0/23\n220.155.31.0/24\n220.155.32.0/19\n220.155.64.0/18\n220.155.128.0/17\n220.158.241.0/24\n220.158.243.0/24\n220.160.0.0/11\n220.192.0.0/12\n220.231.0.0/18\n220.231.128.0/17\n220.232.64.0/18\n220.234.0.0/16\n220.242.0.0/23\n220.242.6.0/24\n220.242.8.0/24\n220.242.12.0/23\n220.242.14.0/24\n220.242.17.0/24\n220.242.18.0/23\n220.242.20.0/24\n220.242.32.0/20\n220.242.48.0/23\n220.242.53.0/24\n220.242.55.0/24\n220.242.56.0/22\n220.242.60.0/23\n220.242.62.0/24\n220.242.64.0/19\n220.242.96.0/20\n220.242.112.0/21\n220.242.120.0/22\n220.242.124.0/23\n220.242.126.0/24\n220.242.134.0/23\n220.242.173.0/24\n220.242.183.0/24\n220.242.197.0/24\n220.242.205.0/24\n220.242.207.0/24\n220.242.217.0/24\n220.242.218.0/23\n220.242.220.0/22\n220.242.224.0/19\n220.243.0.0/17\n220.243.128.0/18\n220.243.192.0/23\n220.243.196.0/24\n220.243.198.0/23\n220.243.201.0/24\n220.243.204.0/24\n220.243.214.0/24\n220.243.216.0/23\n220.243.218.0/24\n220.243.220.0/23\n220.243.223.0/24\n220.243.225.0/24\n220.243.226.0/23\n220.243.229.0/24\n220.243.230.0/24\n220.243.234.0/23\n220.243.237.0/24\n220.243.238.0/23\n220.243.243.0/24\n220.243.244.0/24\n220.243.246.0/23\n220.243.249.0/24\n220.243.250.0/24\n220.243.252.0/24\n220.243.254.0/23\n220.247.136.0/21\n220.248.0.0/14\n220.252.0.0/16\n221.0.0.0/13\n221.8.0.0/14\n221.12.0.0/17\n221.12.128.0/18\n221.13.0.0/16\n221.14.0.0/15\n221.122.0.0/15\n221.128.128.0/17\n221.129.0.0/16\n221.130.0.0/15\n221.133.224.0/19\n221.136.0.0/15\n221.172.0.0/14\n221.176.0.0/19\n221.176.32.0/20\n221.176.48.0/21\n221.176.56.0/24\n221.176.58.0/23\n221.176.60.0/22\n221.176.64.0/18\n221.176.128.0/17\n221.177.0.0/16\n221.178.0.0/15\n221.180.0.0/14\n221.192.0.0/14\n221.196.0.0/15\n221.198.0.0/16\n221.199.0.0/17\n221.199.128.0/18\n221.199.192.0/20\n221.199.224.0/19\n221.200.0.0/13\n221.208.0.0/12\n221.224.0.0/12\n222.16.0.0/12\n222.32.0.0/11\n222.64.0.0/11\n222.125.0.0/16\n222.126.128.0/19\n222.126.160.0/21\n222.126.168.0/22\n222.126.172.0/23\n222.126.174.40/29\n222.126.174.76/30\n222.126.174.88/29\n222.126.174.144/28\n222.126.178.0/23\n222.126.180.0/22\n222.126.184.0/21\n222.126.192.0/21\n222.126.200.104/29\n222.126.206.0/23\n222.126.208.0/22\n222.126.212.0/26\n222.126.212.64/27\n222.126.212.96/28\n222.126.212.112/29\n222.126.212.128/25\n222.126.213.0/24\n222.126.214.0/23\n222.126.216.0/21\n222.126.224.0/19\n222.128.0.0/12\n222.160.0.0/14\n222.168.0.0/13\n222.176.0.0/12\n222.192.0.0/11\n222.240.0.0/13\n222.248.0.0/15\n223.0.0.0/12\n223.20.0.0/15\n223.27.184.0/22\n223.29.208.0/22\n223.64.0.0/11\n223.96.0.0/12\n223.112.0.0/14\n223.116.0.0/15\n223.120.0.0/13\n223.128.0.0/15\n223.144.0.0/12\n223.160.0.0/14\n223.166.0.0/15\n223.192.0.0/15\n223.198.0.0/15\n223.201.0.0/22\n223.201.8.0/21\n223.201.16.0/20\n223.201.32.0/19\n223.201.64.0/18\n223.201.128.0/17\n223.202.0.0/15\n223.208.0.0/13\n223.220.0.0/15\n223.223.176.0/20\n223.223.192.0/20\n223.240.0.0/13\n223.248.0.0/14\n223.252.128.0/19\n223.252.192.0/18\n223.254.0.0/16\n223.255.0.0/17\n223.255.236.0/22\n223.255.252.0/23\n2001:250::/35\n2001:250:2000::/35\n2001:250:4000::/34\n2001:250:8000::/33\n2001:251::/32\n2001:252::/32\n2001:253::/32\n2001:254::/32\n2001:255::/32\n2001:256::/32\n2001:7fa:5::/48\n2001:7fa:10::/48\n2001:c68::/32\n2001:cc0::/32\n2001:da8::/32\n2001:da9::/32\n2001:daa::/32\n2001:dc7::/32\n2001:dd8:1::/48\n2001:dd8:5::/48\n2001:dd8:1a::/48\n2001:dd9::/48\n2001:df0:27e::/48\n2001:df0:423::/48\n2001:df0:2180::/48\n2001:df0:2d80::/48\n2001:df0:2e00::/48\n2001:df0:2e80::/48\n2001:df0:4500::/48\n2001:df0:9a00::/48\n2001:df0:b180::/48\n2001:df0:bf80::/48\n2001:df0:d180::/48\n2001:df0:d880::/48\n2001:df1:c80::/48\n2001:df1:4580::/48\n2001:df1:5280::/48\n2001:df1:5b80::/48\n2001:df1:6180::/48\n2001:df1:6b80::/48\n2001:df1:8b00::/48\n2001:df1:a100::/48\n2001:df1:bd80::/48\n2001:df1:c900::/48\n2001:df1:d100::/48\n2001:df1:d180::/48\n2001:df1:da00::/48\n2001:df1:f480::/48\n2001:df1:f580::/48\n2001:df1:fd80::/48\n2001:df2:80::/48\n2001:df2:180::/48\n2001:df2:5200::/48\n2001:df2:5780::/48\n2001:df2:5a80::/48\n2001:df2:a580::/48\n2001:df3:1480::/48\n2001:df3:2a80::/48\n2001:df3:3a80::/48\n2001:df3:a680::/48\n2001:df3:b100::/48\n2001:df3:b380::/48\n2001:df3:c380::/48\n2001:df3:c680::/48\n2001:df3:d880::/48\n2001:df3:ed80::/48\n2001:df3:ef80::/48\n2001:df4:80::/48\n2001:df4:880::/48\n2001:df4:d80::/48\n2001:df4:1280::/48\n2001:df4:1500::/48\n2001:df4:1880::/48\n2001:df4:2780::/48\n2001:df4:2e80::/48\n2001:df4:2f00::/48\n2001:df4:3c80::/48\n2001:df4:3d80::/48\n2001:df4:4b80::/48\n2001:df4:4d80::/48\n2001:df4:a680::/48\n2001:df4:a980::/48\n2001:df4:c180::/48\n2001:df4:c580::/48\n2001:df4:c780::/48\n2001:df4:cf00::/48\n2001:df4:de80::/48\n2001:df5:2080::/48\n2001:df5:5f80::/48\n2001:df5:7800::/48\n2001:df6:100::/48\n2001:df6:1c00::/48\n2001:df6:3d00::/48\n2001:df6:5d00::/48\n2001:df6:6800::/48\n2001:df6:9e80::/48\n2001:df6:9f80::/48\n2001:df6:df00::/48\n2001:df6:f400::/48\n2001:df7:1480::/48\n2001:df7:2b80::/48\n2001:df7:5900::/48\n2001:df7:6600::/48\n2001:df7:ab00::/48\n2001:e08::/32\n2001:e18::/32\n2001:e80::/32\n2001:e88::/32\n2001:f38::/32\n2001:f88::/32\n2001:4438::/32\n2001:4510::/29\n2400:1040::/32\n2400:12c0::/32\n2400:1340::/32\n2400:1380::/32\n2400:15c0::/32\n2400:1640::/32\n2400:16c0::/32\n2400:1740::/32\n2400:17c0::/32\n2400:1840::/32\n2400:18c0::/32\n2400:1940::/32\n2400:19c0::/32\n2400:1a40::/32\n2400:1ac0::/32\n2400:1b40::/32\n2400:1cc0::/32\n2400:1d40::/32\n2400:1dc0::/32\n2400:1e40::/32\n2400:1ec0::/32\n2400:1f40::/32\n2400:1fc0::/32\n2400:3040::/32\n2400:3140::/32\n2400:31c0::/32\n2400:3200::/32\n2400:3280::/32\n2400:32c0::/32\n2400:3340::/32\n2400:33c0::/32\n2400:3440::/32\n2400:34c0::/32\n2400:3540::/32\n2400:35c0::/32\n2400:3600::/32\n2400:3640::/32\n2400:36c0::/32\n2400:38c0::/32\n2400:39c0::/32\n2400:3a00::/32\n2400:3a40::/32\n2400:3b40::/32\n2400:3bc0::/32\n2400:3c40::/32\n2400:3cc0::/32\n2400:3e00::/32\n2400:3f40::/32\n2400:3fc0::/32\n2400:4440::/32\n2400:44c0::/32\n2400:4540::/32\n2400:4600::/32\n2400:4640::/32\n2400:46c0::/32\n2400:4740::/32\n2400:4bc0::/32\n2400:4e00::/32\n2400:4e40::/32\n2400:5080::/32\n2400:5280::/32\n2400:5400::/32\n2400:5580::/32\n2400:55c0::/32\n2400:5600::/32\n2400:5640::/32\n2400:56c0::/32\n2400:57c0::/32\n2400:5840::/32\n2400:5a00::/32\n2400:5a40::/32\n2400:5ac0::/32\n2400:5b40::/32\n2400:5bc0::/32\n2400:5c40::/32\n2400:5c80::/32\n2400:5cc0::/32\n2400:5e80::/32\n2400:5fc0::/32\n2400:6000::/32\n2400:6040::/32\n2400:60c0::/32\n2400:61c0::/32\n2400:6200::/32\n2400:6600::/32\n2400:6640::/32\n2400:66c0::/32\n2400:6740::/32\n2400:67c0::/32\n2400:6840::/32\n2400:68c0::/32\n2400:6940::/32\n2400:69c0::/32\n2400:6a00::/32\n2400:6a40::/32\n2400:6ac0::/32\n2400:6b40::/32\n2400:6bc0::/32\n2400:6c40::/32\n2400:6cc0::/32\n2400:6d40::/32\n2400:6dc0::/32\n2400:6e00::/32\n2400:6e40::/32\n2400:6ec0::/32\n2400:6f40::/32\n2400:6f80::/32\n2400:6fc0::/32\n2400:7040::/32\n2400:7100::/32\n2400:7140::/32\n2400:71c0::/32\n2400:7200::/32\n2400:7240::/32\n2400:72c0::/32\n2400:7340::/32\n2400:73c0::/32\n2400:7440::/32\n2400:74c0::/32\n2400:7540::/32\n2400:75c0::/32\n2400:7640::/32\n2400:7680::/32\n2400:76c0::/32\n2400:7740::/32\n2400:77c0::/32\n2400:79c0::/32\n2400:7ac0::/32\n2400:7bc0::/32\n2400:7f80::/32\n2400:7fc0::/32\n2400:8080::/32\n2400:8200::/32\n2400:82c0::/32\n2400:8580::/32\n2400:8600::/32\n2400:8780::/32\n2400:87c0::/32\n2400:8840::/32\n2400:8980::/32\n2400:89c0::/32\n2400:8e00::/32\n2400:8f00::/32\n2400:8fc0::/32\n2400:9040::/32\n2400:9340::/32\n2400:9580::/32\n2400:95c0::/32\n2400:9600::/32\n2400:98c0::/32\n2400:9a00::/32\n2400:9dc0::/32\n2400:9e00::/32\n2400:a040::/32\n2400:a380::/32\n2400:a480::/32\n2400:a780::/32\n2400:a8c0::/32\n2400:a900::/32\n2400:a980::/32\n2400:a981::/32\n2400:a982::/31\n2400:a984::/30\n2400:abc0::/32\n2400:ae00::/32\n2400:b200::/32\n2400:b2c0::/32\n2400:b500::/32\n2400:b600::/32\n2400:b6c0::/32\n2400:b700::/32\n2400:b8c0::/32\n2400:b9c0::/32\n2400:ba00::/32\n2400:ba40::/32\n2400:ba41::/32\n2400:bac0::/32\n2400:bc40::/32\n2400:be00::/32\n2400:bf00::/32\n2400:c200::/32\n2400:c380::/32\n2400:c840::/32\n2400:c8c0::/32\n2400:c940::/32\n2400:c9c0::/32\n2400:ca40::/32\n2400:cac0::/32\n2400:cb40::/32\n2400:cb80::/32\n2400:cbc0::/32\n2400:cc40::/32\n2400:cc80::/32\n2400:ccc0::/32\n2400:cd40::/32\n2400:cdc0::/32\n2400:ce00::/32\n2400:ce40::/32\n2400:cf40::/32\n2400:cf80::/32\n2400:cfc0::/32\n2400:d0c0::/32\n2400:d100::/32\n2400:d1c0::/32\n2400:d200::/32\n2400:d300::/32\n2400:d440::/32\n2400:d600::/32\n2400:d6c0::/32\n2400:d780::/32\n2400:da00::/32\n2400:dd00::/28\n2400:dd40::/32\n2400:de00::/32\n2400:de80::/32\n2400:e0c0::/32\n2400:e5c0::/32\n2400:e680::/32\n2400:e880::/32\n2400:ebc0::/32\n2400:edc0::/32\n2400:ee00::/32\n2400:eec0::/32\n2400:ef40::/32\n2400:f480::/32\n2400:f5c0::/32\n2400:f7c0::/32\n2400:f840::/32\n2400:f980::/32\n2400:fac0::/32\n2400:fb40::/32\n2400:fbc0::/32\n2400:fc40::/32\n2400:fcc0::/32\n2400:fe00::/32\n2401:80::/32\n2401:140::/32\n2401:1c0::/32\n2401:540::/32\n2401:7c0::/32\n2401:800::/32\n2401:9c0::/32\n2401:a00::/32\n2401:a40::/32\n2401:ac0::/32\n2401:b40::/32\n2401:bc0::/32\n2401:c40::/32\n2401:cc0::/32\n2401:d40::/32\n2401:e00::/32\n2401:1000::/32\n2401:11c0::/32\n2401:1200::/32\n2401:12c0::/32\n2401:15c0::/32\n2401:1740::/32\n2401:18c0::/32\n2401:1940::/32\n2401:19c0::/32\n2401:1a40::/32\n2401:1ac0::/32\n2401:1d40::/32\n2401:1dc0::/32\n2401:1e00::/32\n2401:1ec0::/32\n2401:1f40::/32\n2401:2040::/32\n2401:2080::/32\n2401:23c0::/32\n2401:2600::/32\n2401:2780::/32\n2401:2980::/32\n2401:2a00::/32\n2401:2b40::/32\n2401:2e00::/32\n2401:3100::/32\n2401:3380::/32\n2401:33c0::/32\n2401:3440::/32\n2401:3480::/32\n2401:34c0::/32\n2401:3640::/32\n2401:3780::/32\n2401:3800::/32\n2401:3880::/32\n2401:3980::/32\n2401:3a00::/32\n2401:3a80::/32\n2401:3b80::/32\n2401:3c80::/32\n2401:3d80::/32\n2401:3e80::/32\n2401:3f80::/32\n2401:4080::/32\n2401:4180::/32\n2401:4280::/32\n2401:4380::/32\n2401:4480::/32\n2401:4580::/32\n2401:4680::/32\n2401:4780::/32\n2401:4880::/32\n2401:4a80::/32\n2401:4b00::/32\n2401:4f80::/32\n2401:5180::/32\n2401:5680::/32\n2401:56c0::/32\n2401:59c0::/32\n2401:5b40::/32\n2401:5c80::/32\n2401:7180::/32\n2401:71c0::/32\n2401:7240::/32\n2401:7340::/32\n2401:7580::/32\n2401:7680::/32\n2401:7700::/32\n2401:7780::/32\n2401:7880::/32\n2401:7980::/32\n2401:7a00::/32\n2401:7a80::/32\n2401:7b80::/32\n2401:7bc0::/32\n2401:7c80::/32\n2401:7cc0::/32\n2401:7d40::/32\n2401:7d80::/32\n2401:7e00::/32\n2401:7f80::/32\n2401:8200::/32\n2401:82c0::/32\n2401:8380::/32\n2401:8540::/32\n2401:8600::/32\n2401:8680::/32\n2401:8840::/32\n2401:8d00::/32\n2401:8e40::/32\n2401:8f40::/32\n2401:8fc0::/32\n2401:9340::/32\n2401:9600::/32\n2401:96c0::/32\n2401:9740::/32\n2401:98c0::/32\n2401:9a00::/32\n2401:9ac0::/32\n2401:9b40::/32\n2401:9bc0::/32\n2401:9dc0::/32\n2401:9e40::/32\n2401:9f80::/32\n2401:a140::/32\n2401:a180::/32\n2401:a340::/32\n2401:a3c0::/32\n2401:a4c0::/32\n2401:a540::/32\n2401:a5c0::/32\n2401:a640::/32\n2401:a940::/32\n2401:a980::/32\n2401:aa00::/32\n2401:aa40::/32\n2401:acc0::/32\n2401:ad40::/32\n2401:adc0::/32\n2401:b040::/32\n2401:b180::/32\n2401:b340::/32\n2401:b400::/32\n2401:b480::/32\n2401:b4c0::/32\n2401:b540::/32\n2401:b580::/32\n2401:b600::/32\n2401:b680::/32\n2401:b6c0::/32\n2401:b7c0::/32\n2401:b940::/32\n2401:ba00::/32\n2401:ba40::/32\n2401:bb80::/32\n2401:be00::/32\n2401:c200::/32\n2401:c540::/32\n2401:c600::/32\n2401:c640::/32\n2401:c6c0::/32\n2401:c840::/32\n2401:c8c0::/32\n2401:ca00::/32\n2401:cb80::/32\n2401:cc00::/32\n2401:ce00::/32\n2401:cf40::/32\n2401:cfc0::/32\n2401:d0c0::/32\n2401:d140::/32\n2401:d180::/32\n2401:d2c0::/32\n2401:d340::/32\n2401:d780::/32\n2401:da00::/32\n2401:de00::/32\n2401:e080::/32\n2401:e0c0::/32\n2401:e140::/32\n2401:e240::/32\n2401:e2c0::/32\n2401:e340::/32\n2401:e6c0::/32\n2401:e840::/32\n2401:e8c0::/32\n2401:e940::/32\n2401:e9c0::/32\n2401:ec00::/32\n2401:ec40::/32\n2401:f300::/32\n2401:f7c0::/32\n2401:fa80::/32\n2401:fac0::/32\n2401:fb80::/32\n2401:fc80::/32\n2401:fe80::/32\n2401:ffc0::/32\n2402:440::/32\n2402:5c0::/32\n2402:840::/32\n2402:ac0::/32\n2402:e00::/32\n2402:fc0::/32\n2402:1000::/32\n2402:1440::/32\n2402:14c0::/32\n2402:1540::/32\n2402:1600::/32\n2402:1740::/32\n2402:19c0::/32\n2402:1ec0::/32\n2402:1f40::/32\n2402:1f80::/32\n2402:2000::/32\n2402:2280::/32\n2402:22c0::/32\n2402:2440::/32\n2402:24c0::/32\n2402:2540::/32\n2402:2640::/32\n2402:27c0::/32\n2402:2a00::/32\n2402:2b80::/32\n2402:2bc0::/32\n2402:2d00::/32\n2402:2d80::/32\n2402:2e80::/32\n2402:2f40::/32\n2402:3040::/32\n2402:3080::/32\n2402:3140::/32\n2402:3180::/32\n2402:31c0::/32\n2402:3240::/32\n2402:33c0::/32\n2402:39c0::/32\n2402:3a40::/32\n2402:3ac0::/32\n2402:3c00::/32\n2402:3e00::/32\n2402:3ec0::/32\n2402:3f40::/32\n2402:3f80::/32\n2402:4140::/32\n2402:42c0::/32\n2402:4340::/32\n2402:43c0::/32\n2402:4440::/32\n2402:4500::/32\n2402:4540::/32\n2402:4a00::/32\n2402:4a40::/32\n2402:4a80::/32\n2402:4ac0::/32\n2402:4b80::/32\n2402:4bc0::/32\n2402:4c40::/32\n2402:4d80::/32\n2402:4e00::/32\n2402:4ec0::/32\n2402:4f80::/32\n2402:50c0::/32\n2402:5140::/32\n2402:5180::/32\n2402:51c0::/32\n2402:5240::/32\n2402:52c0::/32\n2402:5340::/32\n2402:5880::/32\n2402:5940::/32\n2402:59c0::/32\n2402:5a40::/32\n2402:5b40::/32\n2402:5bc0::/32\n2402:5d00::/32\n2402:5e00::/32\n2402:5e40::/32\n2402:5ec0::/32\n2402:5f40::/32\n2402:6280::/32\n2402:62c0::/32\n2402:64c0::/32\n2402:66c0::/32\n2402:6740::/32\n2402:67c0::/32\n2402:6a00::/32\n2402:6b40::/32\n2402:6bc0::/32\n2402:6e00::/32\n2402:6e80::/32\n2402:6ec0::/32\n2402:6f40::/32\n2402:6fc0::/32\n2402:7040::/32\n2402:7080::/32\n2402:70c0::/32\n2402:7140::/32\n2402:71c0::/32\n2402:7240::/32\n2402:72c0::/32\n2402:7540::/32\n2402:75c0::/32\n2402:7740::/32\n2402:7d00::/32\n2402:7d80::/32\n2402:8180::/32\n2402:8300::/32\n2402:8380::/32\n2402:85c0::/32\n2402:8800::/32\n2402:8840::/32\n2402:8900::/32\n2402:8940::/32\n2402:89c0::/32\n2402:8b40::/32\n2402:8bc0::/32\n2402:8cc0::/32\n2402:8d40::/32\n2402:8f40::/32\n2402:8f80::/32\n2402:9240::/32\n2402:92c0::/32\n2402:93c0::/32\n2402:9440::/32\n2402:9480::/32\n2402:94c0::/32\n2402:9580::/32\n2402:95c0::/32\n2402:9680::/32\n2402:96c0::/32\n2402:9840::/32\n2402:98c0::/32\n2402:9940::/32\n2402:9a80::/32\n2402:9b80::/32\n2402:9f80::/32\n2402:9fc0::/32\n2402:a080::/32\n2402:a180::/32\n2402:a200::/32\n2402:a240::/32\n2402:a280::/32\n2402:a380::/32\n2402:a3c0::/32\n2402:a640::/32\n2402:a680::/32\n2402:a6c0::/32\n2402:a840::/32\n2402:a880::/32\n2402:a9c0::/32\n2402:aa80::/32\n2402:ab80::/32\n2402:ae00::/32\n2402:ae40::/32\n2402:aec0::/32\n2402:af80::/32\n2402:afc0::/32\n2402:b080::/32\n2402:b200::/32\n2402:b380::/32\n2402:b3c0::/32\n2402:b440::/32\n2402:b6c0::/32\n2402:b880::/32\n2402:b8c0::/32\n2402:b940::/32\n2402:b980::/32\n2402:ba80::/32\n2402:bac0::/32\n2402:bbc0::/32\n2402:bf80::/32\n2402:c280::/32\n2402:c3c0::/32\n2402:c5c0::/32\n2402:c9c0::/32\n2402:cbc0::/32\n2402:cc40::/32\n2402:cc80::/32\n2402:cf00::/32\n2402:cf40::/32\n2402:d040::/32\n2402:d140::/32\n2402:d2c0::/32\n2402:d300::/32\n2402:d340::/32\n2402:d380::/32\n2402:d5c0::/32\n2402:d6c0::/32\n2402:d740::/32\n2402:d780::/32\n2402:d880::/32\n2402:d980::/32\n2402:da40::/32\n2402:db40::/32\n2402:dcc0::/32\n2402:de40::/32\n2402:dec0::/32\n2402:df40::/32\n2402:dfc0::/32\n2402:e040::/32\n2402:e0c0::/32\n2402:e140::/32\n2402:e2c0::/32\n2402:e3c0::/32\n2402:e480::/32\n2402:e540::/32\n2402:e680::/32\n2402:e740::/32\n2402:e780::/32\n2402:e7c0::/32\n2402:e880::/32\n2402:e980::/32\n2402:eb80::/32\n2402:ec80::/32\n2402:ed80::/32\n2402:ef40::/32\n2402:ef80::/32\n2402:f000::/32\n2402:f140::/32\n2402:f340::/32\n2402:f3c0::/32\n2402:f480::/32\n2402:f540::/32\n2402:f580::/32\n2402:f740::/32\n2402:f780::/32\n2402:f8c0::/32\n2402:f980::/32\n2402:f9c0::/32\n2402:fac0::/32\n2402:fcc0::/32\n2402:ff40::/32\n2402:ffc0::/32\n2403:600::/32\n2403:700::/32\n2403:7c0::/32\n2403:800::/31\n2403:980::/32\n2403:a80::/32\n2403:b80::/32\n2403:c80::/32\n2403:d40::/32\n2403:d80::/32\n2403:e80::/32\n2403:f00::/32\n2403:f40::/32\n2403:f80::/32\n2403:fc0::/32\n2403:1180::/32\n2403:1340::/32\n2403:1440::/32\n2403:1580::/32\n2403:16c0::/32\n2403:17c0::/32\n2403:1980::/32\n2403:1a40::/32\n2403:1b80::/32\n2403:1c80::/32\n2403:1d80::/32\n2403:1dc0::/32\n2403:1e80::/32\n2403:1ec0::/32\n2403:1f80::/32\n2403:2040::/32\n2403:2080::/32\n2403:2180::/32\n2403:2240::/32\n2403:2280::/32\n2403:2380::/32\n2403:2440::/32\n2403:24c0::/32\n2403:2580::/32\n2403:25c0::/32\n2403:2680::/32\n2403:26c0::/32\n2403:2740::/32\n2403:2780::/32\n2403:28c0::/32\n2403:2940::/32\n2403:2a00::/32\n2403:2a40::/32\n2403:2ac0::/32\n2403:2b40::/32\n2403:2bc0::/32\n2403:2cc0::/32\n2403:2f40::/32\n2403:2fc0::/32\n2403:3040::/32\n2403:30c0::/32\n2403:3140::/32\n2403:3280::/32\n2403:32c0::/32\n2403:3380::/32\n2403:3480::/32\n2403:3580::/32\n2403:3640::/32\n2403:3680::/32\n2403:36c0::/32\n2403:3740::/32\n2403:3780::/32\n2403:37c0::/32\n2403:3840::/32\n2403:3880::/32\n2403:38c0::/32\n2403:3940::/32\n2403:3980::/32\n2403:39c0::/32\n2403:3a40::/32\n2403:3b40::/32\n2403:3b80::/32\n2403:3bc0::/32\n2403:3c40::/32\n2403:3c80::/32\n2403:3cc0::/32\n2403:3d40::/32\n2403:3d80::/32\n2403:3dc0::/32\n2403:3e80::/32\n2403:3ec0::/32\n2403:3f40::/32\n2403:3f80::/32\n2403:4080::/32\n2403:4180::/32\n2403:4240::/32\n2403:4280::/32\n2403:4300::/32\n2403:4380::/32\n2403:4580::/32\n2403:4680::/32\n2403:4780::/32\n2403:4840::/32\n2403:4880::/32\n2403:4980::/32\n2403:4a40::/32\n2403:4a80::/32\n2403:4b40::/32\n2403:4b80::/32\n2403:4c80::/32\n2403:4cc0::/32\n2403:4d40::/32\n2403:4d80::/32\n2403:4ec0::/32\n2403:5040::/32\n2403:5080::/32\n2403:50c0::/32\n2403:5280::/32\n2403:5380::/32\n2403:54c0::/32\n2403:5540::/32\n2403:5580::/32\n2403:5640::/32\n2403:5780::/32\n2403:58c0::/32\n2403:5980::/32\n2403:5a80::/32\n2403:5b40::/32\n2403:5b80::/32\n2403:5c80::/32\n2403:5d80::/32\n2403:5e40::/32\n2403:5e80::/32\n2403:5ec0::/32\n2403:5f80::/32\n2403:5fc0::/32\n2403:6080::/32\n2403:6180::/32\n2403:6280::/32\n2403:62c0::/32\n2403:6380::/32\n2403:6580::/32\n2403:6680::/32\n2403:6740::/32\n2403:6780::/32\n2403:6880::/32\n2403:6980::/32\n2403:6a00::/32\n2403:6c80::/32\n2403:6d40::/32\n2403:6d80::/32\n2403:6e80::/32\n2403:6f40::/32\n2403:6fc0::/32\n2403:7040::/32\n2403:7080::/32\n2403:7180::/32\n2403:7280::/32\n2403:7380::/32\n2403:7480::/32\n2403:7540::/32\n2403:7580::/32\n2403:76c0::/32\n2403:7700::/32\n2403:7840::/32\n2403:78c0::/32\n2403:7a80::/32\n2403:7b00::/32\n2403:7d80::/32\n2403:7e80::/32\n2403:7f80::/32\n2403:8080::/32\n2403:8180::/32\n2403:8280::/32\n2403:8380::/32\n2403:83c0::/32\n2403:8480::/32\n2403:8580::/32\n2403:8880::/32\n2403:8900::/32\n2403:8980::/32\n2403:8a40::/32\n2403:8a80::/32\n2403:8b00::/32\n2403:8b80::/32\n2403:8c00::/32\n2403:8c80::/32\n2403:8d00::/32\n2403:8d80::/32\n2403:8f80::/32\n2403:9080::/32\n2403:9180::/32\n2403:9280::/32\n2403:9380::/32\n2403:9480::/32\n2403:9580::/32\n2403:9680::/32\n2403:9780::/32\n2403:9880::/32\n2403:9a80::/32\n2403:9ac0::/32\n2403:9b00::/32\n2403:9b40::/32\n2403:9b80::/32\n2403:9c80::/32\n2403:9d00::/32\n2403:9d80::/32\n2403:9e40::/32\n2403:9e80::/32\n2403:9ec0::/32\n2403:9f80::/32\n2403:a100::/32\n2403:a140::/32\n2403:a200::/32\n2403:a300::/32\n2403:a480::/32\n2403:a580::/32\n2403:a680::/32\n2403:a6c0::/32\n2403:a780::/32\n2403:a880::/32\n2403:a940::/32\n2403:a980::/32\n2403:a9c0::/32\n2403:aa40::/32\n2403:aa80::/32\n2403:ab80::/32\n2403:ac00::/32\n2403:af80::/32\n2403:b080::/32\n2403:b180::/32\n2403:b280::/32\n2403:b380::/32\n2403:b400::/32\n2403:b480::/32\n2403:b580::/32\n2403:b680::/32\n2403:b780::/32\n2403:b880::/32\n2403:b980::/32\n2403:ba40::/32\n2403:c040::/32\n2403:c080::/32\n2403:c100::/32\n2403:c140::/32\n2403:c180::/32\n2403:c3c0::/32\n2403:c440::/32\n2403:c480::/32\n2403:c4c0::/32\n2403:c980::/32\n2403:cdc0::/32\n2403:cec0::/32\n2403:cf80::/32\n2403:d080::/32\n2403:d180::/32\n2403:d280::/32\n2403:d2c0::/32\n2403:d380::/32\n2403:d400::/32\n2403:d440::/32\n2403:d480::/32\n2403:d580::/32\n2403:d680::/32\n2403:d780::/32\n2403:d7c0::/32\n2403:d880::/32\n2403:d980::/32\n2403:d9c0::/32\n2403:da80::/32\n2403:dac0::/32\n2403:db00::/32\n2403:db80::/32\n2403:dc80::/32\n2403:dd80::/32\n2403:de80::/32\n2403:df80::/32\n2403:e080::/32\n2403:e180::/32\n2403:e280::/32\n2403:e300::/32\n2403:e480::/32\n2403:e500::/32\n2403:e580::/32\n2403:e640::/32\n2403:e680::/32\n2403:e700::/32\n2403:e780::/32\n2403:e7c0::/32\n2403:e880::/32\n2403:e980::/32\n2403:ea80::/32\n2403:eac0::/32\n2403:eb80::/32\n2403:ec80::/32\n2403:ed00::/32\n2403:ed40::/32\n2403:ed80::/32\n2403:ee80::/32\n2403:ef80::/32\n2403:f080::/32\n2403:f100::/32\n2403:f180::/32\n2403:f240::/32\n2403:f280::/32\n2403:f300::/32\n2403:f380::/32\n2403:f4c0::/32\n2403:f580::/32\n2403:f740::/32\n2403:f8c0::/32\n2403:f980::/32\n2403:fb00::/32\n2403:fb80::/32\n2403:fc40::/32\n2403:fe40::/32\n2403:fe80::/32\n2403:fec0::/32\n2403:ff80::/32\n2403:ffc0::/32\n2404:100::/32\n2404:158::/32\n2404:240::/32\n2404:280::/32\n2404:440::/32\n2404:480::/32\n2404:680::/32\n2404:a80::/32\n2404:b80::/32\n2404:bc0::/32\n2404:c40::/32\n2404:d80::/32\n2404:f00::/32\n2404:f80::/32\n2404:1080::/32\n2404:10c0::/32\n2404:1180::/32\n2404:14c0::/32\n2404:1880::/32\n2404:1c80::/32\n2404:1cc0::/32\n2404:1d80::/32\n2404:1e80::/32\n2404:1f40::/32\n2404:21c0::/32\n2404:30c0::/32\n2404:3140::/32\n2404:31c0::/32\n2404:3240::/32\n2404:32c0::/32\n2404:3300::/32\n2404:3340::/32\n2404:3480::/32\n2404:35c0::/32\n2404:3640::/32\n2404:36c0::/32\n2404:3700::/32\n2404:3740::/32\n2404:37c0::/32\n2404:3840::/32\n2404:3940::/32\n2404:3b00::/32\n2404:3bc0::/32\n2404:3c40::/32\n2404:3f40::/32\n2404:4080::/32\n2404:41c0::/32\n2404:4540::/32\n2404:4740::/32\n2404:4bc0::/32\n2404:4d00::/32\n2404:4dc0::/32\n2404:51c0::/32\n2404:5640::/32\n2404:5a80::/32\n2404:5b00::/32\n2404:5d00::/32\n2404:5e80::/32\n2404:6000::/32\n2404:6100::/32\n2404:6380::/32\n2404:6500::/32\n2404:65c0::/32\n2404:6a40::/32\n2404:6f80::/32\n2404:7100::/32\n2404:7180::/32\n2404:71c0::/32\n2404:7240::/32\n2404:74c0::/32\n2404:7600::/32\n2404:7740::/32\n2404:7940::/32\n2404:7d00::/32\n2404:8040::/32\n2404:80c0::/32\n2404:8140::/32\n2404:81c0::/32\n2404:8480::/32\n2404:8580::/32\n2404:8700::/32\n2404:8880::/32\n2404:8a80::/32\n2404:8b00::/32\n2404:8dc0::/32\n2404:9340::/32\n2404:9880::/32\n2404:9b80::/32\n2404:9c80::/32\n2404:a000::/32\n2404:a080::/32\n2404:a0c0::/32\n2404:a180::/32\n2404:a240::/32\n2404:a740::/32\n2404:b100::/32\n2404:b340::/32\n2404:b3c0::/32\n2404:b440::/32\n2404:b4c0::/32\n2404:b900::/32\n2404:bbc0::/32\n2404:bc40::/32\n2404:c1c0::/32\n2404:c240::/32\n2404:c2c0::/32\n2404:c300::/32\n2404:c3c0::/32\n2404:c440::/32\n2404:c4c0::/32\n2404:c540::/32\n2404:c5c0::/32\n2404:c640::/32\n2404:c940::/32\n2404:c9c0::/32\n2404:cd00::/32\n2404:d040::/32\n2404:d080::/32\n2404:d140::/32\n2404:d280::/32\n2404:d3c0::/32\n2404:d480::/32\n2404:d640::/32\n2404:d6c0::/32\n2404:d7c0::/32\n2404:d840::/32\n2404:dd80::/32\n2404:df00::/32\n2404:e280::/32\n2404:e540::/32\n2404:e5c0::/32\n2404:e780::/32\n2404:e880::/32\n2404:e8c0::/32\n2404:eb40::/32\n2404:eb80::/32\n2404:ec40::/32\n2404:ecc0::/32\n2404:edc0::/32\n2404:f040::/32\n2404:f4c0::/32\n2404:f7c0::/32\n2405:80::/32\n2405:480::/32\n2405:580::/32\n2405:680::/32\n2405:6c0::/32\n2405:780::/32\n2405:880::/32\n2405:940::/32\n2405:980::/32\n2405:9c0::/32\n2405:a80::/32\n2405:b80::/32\n2405:c80::/32\n2405:d80::/32\n2405:e80::/32\n2405:f80::/32\n2405:1080::/32\n2405:1180::/32\n2405:1280::/32\n2405:1380::/32\n2405:1480::/32\n2405:1580::/32\n2405:1680::/32\n2405:18c0::/32\n2405:1c80::/32\n2405:1d80::/32\n2405:1e80::/32\n2405:1f80::/32\n2405:1fc0::/32\n2405:2080::/32\n2405:2180::/32\n2405:2280::/32\n2405:2340::/32\n2405:2380::/32\n2405:2480::/32\n2405:24c0::/32\n2405:2580::/32\n2405:2680::/32\n2405:2780::/32\n2405:2880::/32\n2405:2980::/32\n2405:2a80::/32\n2405:2b80::/32\n2405:2bc0::/32\n2405:2c80::/32\n2405:2d80::/32\n2405:2e80::/32\n2405:2ec0::/32\n2405:2f40::/32\n2405:2f80::/32\n2405:3140::/32\n2405:31c0::/32\n2405:37c0::/32\n2405:3880::/32\n2405:3980::/32\n2405:39c0::/32\n2405:3a80::/32\n2405:3ac0::/32\n2405:3b00::/32\n2405:3b80::/32\n2405:3bc0::/32\n2405:3c40::/32\n2405:3c80::/32\n2405:3d80::/32\n2405:3e80::/32\n2405:3f40::/32\n2405:3f80::/32\n2405:4080::/32\n2405:4140::/32\n2405:4180::/32\n2405:41c0::/32\n2405:4280::/32\n2405:4380::/32\n2405:4480::/32\n2405:44c0::/32\n2405:4540::/32\n2405:4580::/32\n2405:4680::/32\n2405:4780::/32\n2405:4880::/32\n2405:4980::/32\n2405:4a80::/32\n2405:4b80::/32\n2405:4d40::/32\n2405:4e80::/32\n2405:4f80::/32\n2405:5080::/32\n2405:5180::/32\n2405:5240::/32\n2405:5280::/32\n2405:52c0::/32\n2405:5380::/32\n2405:5480::/32\n2405:5580::/32\n2405:5680::/32\n2405:5780::/32\n2405:57c0::/32\n2405:5880::/32\n2405:5980::/32\n2405:5a80::/32\n2405:5b00::/32\n2405:5b80::/32\n2405:5c80::/32\n2405:5cc0::/32\n2405:5d40::/32\n2405:5d80::/32\n2405:5dc0::/32\n2405:5e80::/32\n2405:5f80::/32\n2405:6080::/32\n2405:6180::/32\n2405:6200::/32\n2405:66c0::/32\n2405:6880::/32\n2405:68c0::/32\n2405:6940::/32\n2405:69c0::/32\n2405:6a80::/32\n2405:6b80::/32\n2405:6c80::/32\n2405:6d80::/32\n2405:6e80::/32\n2405:6f00::/32\n2405:6f80::/32\n2405:7040::/32\n2405:7080::/32\n2405:7180::/32\n2405:7240::/32\n2405:7280::/32\n2405:7380::/32\n2405:7480::/32\n2405:7580::/32\n2405:7680::/32\n2405:7780::/32\n2405:7880::/32\n2405:78c0::/32\n2405:7980::/32\n2405:79c0::/32\n2405:7a80::/32\n2405:7b80::/32\n2405:7c80::/32\n2405:7d40::/32\n2405:7f40::/32\n2405:7fc0::/32\n2405:8280::/32\n2405:83c0::/32\n2405:8480::/32\n2405:84c0::/32\n2405:8580::/32\n2405:8680::/32\n2405:8780::/32\n2405:8880::/32\n2405:8980::/32\n2405:8a40::/32\n2405:8a80::/32\n2405:8ac0::/32\n2405:8b80::/32\n2405:8c80::/32\n2405:8d80::/32\n2405:8e80::/32\n2405:8f40::/32\n2405:8f80::/32\n2405:9080::/32\n2405:9180::/32\n2405:9280::/32\n2405:9300::/32\n2405:9340::/32\n2405:9380::/32\n2405:93c0::/32\n2405:9480::/32\n2405:94c0::/32\n2405:9580::/32\n2405:9680::/32\n2405:9700::/32\n2405:9780::/32\n2405:97c0::/32\n2405:9880::/32\n2405:9900::/32\n2405:9980::/32\n2405:99c0::/32\n2405:9a80::/32\n2405:9b00::/32\n2405:9b80::/32\n2405:9bc0::/32\n2405:9e00::/32\n2405:a240::/32\n2405:a3c0::/32\n2405:a500::/32\n2405:a680::/32\n2405:a900::/32\n2405:a980::/32\n2405:aa80::/32\n2405:ab00::/32\n2405:ad00::/32\n2405:af00::/32\n2405:b100::/32\n2405:b300::/32\n2405:b7c0::/32\n2405:b880::/32\n2405:b980::/32\n2405:bb00::/32\n2405:bd00::/32\n2405:bd80::/32\n2405:bdc0::/32\n2405:be80::/32\n2405:bf00::/32\n2405:c040::/32\n2405:c280::/32\n2405:c380::/32\n2405:c480::/32\n2405:c500::/32\n2405:c580::/32\n2405:c680::/32\n2405:c780::/32\n2405:c880::/32\n2405:c980::/32\n2405:ca80::/32\n2405:cb80::/32\n2405:cc80::/32\n2405:cd80::/32\n2405:ce80::/32\n2405:d280::/32\n2405:d4c0::/32\n2405:d700::/32\n2405:d740::/32\n2405:d900::/32\n2405:df40::/32\n2405:e000::/32\n2405:e040::/32\n2405:e1c0::/32\n2405:e600::/32\n2405:ed40::/32\n2405:ee80::/32\n2405:ef40::/30\n2405:f340::/32\n2405:f380::/32\n2405:f3c0::/32\n2405:f580::/32\n2405:f6c0::/32\n2405:f940::/32\n2405:fdc0::/32\n2405:fe80::/32\n2405:fec0::/32\n2405:ff80::/32\n2406:40::/32\n2406:80::/32\n2406:c0::/32\n2406:140::/32\n2406:280::/32\n2406:440::/32\n2406:4c0::/32\n2406:7c0::/32\n2406:840::/32\n2406:880::/32\n2406:8c0::/32\n2406:9c0::/32\n2406:d80::/32\n2406:e80::/32\n2406:f80::/32\n2406:1080::/32\n2406:1100::/32\n2406:1180::/32\n2406:1280::/32\n2406:1380::/32\n2406:1480::/32\n2406:1580::/32\n2406:15c0::/32\n2406:1680::/32\n2406:1780::/32\n2406:1880::/32\n2406:1980::/32\n2406:1a80::/32\n2406:1b80::/32\n2406:1c80::/32\n2406:1d80::/32\n2406:1e40::/32\n2406:1e80::/32\n2406:1f80::/32\n2406:2080::/32\n2406:2580::/32\n2406:2640::/32\n2406:2700::/32\n2406:2780::/32\n2406:2880::/32\n2406:2980::/32\n2406:2a80::/32\n2406:2b80::/32\n2406:2c40::/32\n2406:2c80::/32\n2406:2d80::/32\n2406:2e80::/32\n2406:2f80::/32\n2406:3080::/32\n2406:3180::/32\n2406:31c0::/32\n2406:3280::/32\n2406:3300::/32\n2406:3340::/32\n2406:3380::/32\n2406:3440::/32\n2406:3480::/32\n2406:34c0::/32\n2406:3580::/32\n2406:3640::/32\n2406:3680::/32\n2406:3700::/32\n2406:3780::/32\n2406:3880::/32\n2406:3980::/32\n2406:39c0::/32\n2406:3ac0::/32\n2406:3d80::/32\n2406:3e80::/32\n2406:3f80::/32\n2406:4080::/32\n2406:40c0::/32\n2406:4180::/32\n2406:4280::/32\n2406:42c0::/32\n2406:4340::/32\n2406:4380::/32\n2406:43c0::/32\n2406:4480::/32\n2406:4500::/32\n2406:4680::/32\n2406:4980::/32\n2406:4b80::/32\n2406:4c80::/32\n2406:4d00::/32\n2406:4d80::/32\n2406:4e80::/32\n2406:4f00::/32\n2406:4f80::/32\n2406:5080::/32\n2406:50c0::/32\n2406:5180::/32\n2406:5280::/32\n2406:52c0::/32\n2406:5340::/32\n2406:5380::/32\n2406:5480::/32\n2406:5580::/32\n2406:5680::/32\n2406:5780::/32\n2406:5840::/32\n2406:5880::/32\n2406:5940::/32\n2406:5980::/32\n2406:5a40::/32\n2406:5ac0::/32\n2406:5b40::/32\n2406:5d80::/32\n2406:5e80::/32\n2406:5f80::/32\n2406:6080::/32\n2406:6100::/32\n2406:6180::/32\n2406:61c0::/30\n2406:6280::/32\n2406:6300::/32\n2406:6340::/32\n2406:6380::/32\n2406:6480::/32\n2406:6500::/32\n2406:6580::/32\n2406:65c0::/32\n2406:6640::/32\n2406:6680::/32\n2406:6780::/32\n2406:6880::/32\n2406:6980::/32\n2406:6a80::/32\n2406:6b80::/32\n2406:6bc0::/32\n2406:6c80::/32\n2406:6d80::/32\n2406:6e80::/32\n2406:6f80::/32\n2406:7080::/32\n2406:7280::/32\n2406:7380::/32\n2406:7480::/32\n2406:7580::/32\n2406:7680::/32\n2406:7780::/32\n2406:7880::/32\n2406:7980::/32\n2406:7a80::/32\n2406:7b80::/32\n2406:7c80::/32\n2406:7cc0::/32\n2406:7d00::/32\n2406:7d80::/32\n2406:7e80::/32\n2406:7f80::/32\n2406:7fc0::/32\n2406:8080::/32\n2406:8180::/32\n2406:8280::/32\n2406:8380::/32\n2406:8480::/32\n2406:8500::/32\n2406:8580::/32\n2406:8780::/32\n2406:8880::/32\n2406:8980::/32\n2406:8a80::/32\n2406:8b80::/32\n2406:8bc0::/32\n2406:8c80::/32\n2406:8d80::/32\n2406:8e80::/32\n2406:8f40::/32\n2406:8f80::/32\n2406:9180::/32\n2406:9200::/32\n2406:9280::/32\n2406:9380::/32\n2406:9480::/32\n2406:94c0::/32\n2406:9780::/32\n2406:9d80::/32\n2406:9e40::/32\n2406:9e80::/32\n2406:9f80::/32\n2406:a080::/32\n2406:a180::/32\n2406:a280::/32\n2406:a380::/32\n2406:a480::/32\n2406:a580::/32\n2406:a680::/32\n2406:a780::/32\n2406:a7c0::/32\n2406:a880::/32\n2406:a8c0::/32\n2406:a980::/32\n2406:aa80::/32\n2406:aac0::/32\n2406:ab80::/32\n2406:abc0::/32\n2406:ac80::/32\n2406:acc0::/32\n2406:ad40::/32\n2406:ad80::/32\n2406:ae80::/32\n2406:af80::/32\n2406:b080::/32\n2406:b640::/32\n2406:b880::/32\n2406:b980::/32\n2406:ba80::/32\n2406:bb80::/32\n2406:bc80::/32\n2406:bd40::/32\n2406:bd80::/32\n2406:bdc0::/32\n2406:be80::/32\n2406:bf80::/32\n2406:c080::/32\n2406:c180::/32\n2406:c280::/32\n2406:c340::/32\n2406:c480::/32\n2406:c580::/32\n2406:c680::/32\n2406:c780::/32\n2406:c880::/32\n2406:c900::/32\n2406:c980::/32\n2406:ca80::/32\n2406:cac0::/32\n2406:cb80::/32\n2406:cc80::/32\n2406:cd80::/32\n2406:ce80::/32\n2406:cf00::/32\n2406:cf01::/32\n2406:cf02::/31\n2406:cf80::/32\n2406:d080::/32\n2406:d140::/32\n2406:d180::/32\n2406:d280::/32\n2406:d2c0::/32\n2406:d380::/32\n2406:d440::/32\n2406:d480::/32\n2406:d580::/32\n2406:d680::/32\n2406:d780::/32\n2406:d880::/32\n2406:d980::/32\n2406:db80::/32\n2406:dc80::/32\n2406:dd00::/32\n2406:dd80::/32\n2406:de80::/32\n2406:df80::/32\n2406:e080::/32\n2406:e180::/32\n2406:e280::/32\n2406:e2c0::/32\n2406:e380::/32\n2406:e3c0::/32\n2406:e500::/32\n2406:e580::/32\n2406:e680::/32\n2406:e780::/32\n2406:e8c0::/32\n2406:ea40::/28\n2406:f280::/32\n2406:f300::/32\n2406:f4c0::/32\n2406:f7c0::/32\n2406:f980::/32\n2406:fc80::/32\n2406:fd80::/32\n2406:fe80::/32\n2406:ff00::/32\n2407:480::/32\n2407:580::/32\n2407:cc0::/32\n2407:f40::/32\n2407:1180::/32\n2407:17c0::/32\n2407:1900::/32\n2407:1d00::/32\n2407:1e80::/32\n2407:2280::/32\n2407:2380::/32\n2407:23c0::/32\n2407:2440::/32\n2407:2780::/32\n2407:2840::/32\n2407:2ac0::/32\n2407:31c0::/32\n2407:3340::/32\n2407:3540::/32\n2407:3700::/32\n2407:3740::/32\n2407:37c0::/32\n2407:3900::/32\n2407:3f40::/32\n2407:43c0::/32\n2407:4440::/32\n2407:4580::/32\n2407:4680::/32\n2407:4740::/32\n2407:4880::/32\n2407:4980::/32\n2407:4a80::/32\n2407:4c80::/32\n2407:4d80::/32\n2407:4e80::/32\n2407:4f00::/32\n2407:5380::/32\n2407:53c0::/32\n2407:5500::/32\n2407:5780::/32\n2407:5840::/32\n2407:6040::/32\n2407:6580::/32\n2407:6c40::/32\n2407:7680::/32\n2407:7780::/32\n2407:7880::/32\n2407:7980::/32\n2407:7c80::/32\n2407:7d00::/32\n2407:7d80::/32\n2407:7e80::/32\n2407:8880::/32\n2407:8b80::/32\n2407:8f40::/32\n2407:9080::/32\n2407:9180::/32\n2407:94c0::/32\n2407:9680::/32\n2407:9980::/32\n2407:9b40::/32\n2407:9bc0::/32\n2407:9f00::/32\n2407:9f80::/32\n2407:a040::/32\n2407:a480::/32\n2407:a640::/32\n2407:a7c0::/32\n2407:a880::/32\n2407:a940::/32\n2407:ad80::/32\n2407:ae80::/32\n2407:af80::/32\n2407:b080::/32\n2407:b180::/32\n2407:b280::/32\n2407:b380::/32\n2407:b580::/32\n2407:b680::/32\n2407:b780::/32\n2407:b880::/32\n2407:b980::/32\n2407:ba00::/32\n2407:ba80::/32\n2407:bb80::/32\n2407:bc00::/32\n2407:bc80::/32\n2407:bd80::/32\n2407:bdc0::/32\n2407:be80::/32\n2407:bf80::/32\n2407:c080::/32\n2407:c380::/32\n2407:c400::/32\n2407:c480::/32\n2407:c580::/32\n2407:c680::/32\n2407:c780::/32\n2407:c880::/32\n2407:c900::/32\n2407:c980::/32\n2407:cb80::/32\n2407:cc80::/32\n2407:cd80::/32\n2407:ce80::/32\n2407:cf00::/32\n2407:cf80::/32\n2407:d480::/32\n2407:d580::/32\n2407:d680::/32\n2407:d780::/32\n2407:d880::/32\n2407:d980::/32\n2407:da80::/32\n2407:db80::/32\n2407:dc80::/32\n2407:dd80::/32\n2407:de80::/32\n2407:df80::/32\n2407:e080::/32\n2407:e180::/32\n2407:e280::/32\n2407:e380::/32\n2407:e480::/32\n2407:e580::/32\n2407:e680::/32\n2407:e780::/32\n2407:e800::/32\n2407:ea80::/32\n2407:eb80::/32\n2407:ec80::/32\n2407:ed80::/32\n2407:ee80::/32\n2407:ef80::/32\n2407:f080::/32\n2407:f180::/32\n2407:f280::/32\n2407:f380::/32\n2407:f480::/32\n2407:f580::/32\n2407:f680::/32\n2407:f780::/32\n2407:f880::/32\n2407:f980::/32\n2407:fa80::/32\n2407:fb80::/32\n2407:fc80::/32\n2407:fd80::/32\n2408:4000::/22\n2408:6000::/24\n2408:8000::/22\n2408:8400::/22\n2408:8800::/21\n2409:2000::/21\n2409:6000::/20\n2409:8000::/20\n240a:2000::/24\n240a:4000::/21\n240a:6000::/24\n240a:8000::/21\n240a:a000::/20\n240a:c000::/20\n240b:8000::/21\n240c::/28\n240c:4000::/22\n240c:8000::/21\n240c:c000::/20\n240d:4000::/21\n240d:8000::/24\n240e::/24\n240e:100::/24\n240e:200::/23\n240e:400::/22\n240e:800::/21\n240e:1000::/20\n240e:2000::/19\n240f:4000::/24\n240f:8000::/24\n240f:c000::/24\n"
  },
  {
    "path": "shadowsocks-csharp/Data/proxy.pac.txt",
    "content": "var direct = \"__DIRECT__\";\nif (direct == \"__DIR\" + \"ECT__\") direct = \"DIRECT;\";\n\nvar wall_proxy = function(){ return \"__PROXY__\"; };\nvar wall_v6_proxy = function(){ return \"__PROXY__\"; };\n\nvar nowall_proxy = function(){ return direct; };\nvar ip_proxy = function(){ return nowall_proxy(); };\nvar ipv6_proxy = function(){ return nowall_proxy(); };\n\nvar userrules = [];\nvar rules = [\n  \"|http://85.17.73.31/\",\n  \"||afreecatv.com\",\n  \"||agnesb.fr\",\n  \"||akiba-web.com\",\n  \"||altrec.com\",\n  \"||angela-merkel.de\",\n  \"||angola.org\",\n  \"||apartmentratings.com\",\n  \"||apartments.com\",\n  \"||arena.taipei\",\n  \"||asianspiss.com\",\n  \"||assimp.org\",\n  \"||athenaeizou.com\",\n  \"||azubu.tv\",\n  \"||bankmobilevibe.com\",\n  \"||banorte.com\",\n  \"||beeg.com\",\n  \"||global.bing.com\",\n  \"||booktopia.com.au\",\n  \"||boysmaster.com\",\n  \"||bynet.co.il\",\n  \"||carfax.com\",\n  \".casinobellini.com\",\n  \"||casinobellini.com\",\n  \"||centauro.com.br\",\n  \"||chobit.cc\",\n  \"||clearsurance.com\",\n  \"||images.comico.tw\",\n  \"||static.comico.tw\",\n  \"||counter.social\",\n  \"||costco.com\",\n  \"||crossfire.co.kr\",\n  \"||crunchyroll.com\",\n  \"||d2pass.com\",\n  \"||darpa.mil\",\n  \"||dawangidc.com\",\n  \"||deezer.com\",\n  \"||desipro.de\",\n  \"||dingchin.com.tw\",\n  \"||discord.com\",\n  \"||discord.gg\",\n  \"||discordapp.com\",\n  \"||discordapp.net\",\n  \"||dish.com\",\n  \"|http://img.dlsite.jp/\",\n  \"||dm530.net\",\n  \"share.dmhy.org\",\n  \"||dmhy.org\",\n  \"||dmm.co.jp\",\n  \"|http://www.dmm.com/netgame\",\n  \"||dnvod.tv\",\n  \"||dubox.com\",\n  \"||dvdpac.com\",\n  \"||eesti.ee\",\n  \"||esurance.com\",\n  \".expekt.com\",\n  \"||expekt.com\",\n  \".extmatrix.com\",\n  \"||extmatrix.com\",\n  \"||fakku.net\",\n  \"||fastpic.ru\",\n  \"||filesor.com\",\n  \"||financetwitter.com\",\n  \"||flipboard.com\",\n  \"||flitto.com\",\n  \"||fnac.be\",\n  \"||fnac.com\",\n  \"||funkyimg.com\",\n  \"||fxnetworks.com\",\n  \"||g-area.org\",\n  \"||gettyimages.com\",\n  \"||getuploader.com\",\n  \"||ghidra-sre.org\",\n  \"|https://raw.githubusercontent.com/programthink/zhao\",\n  \"||glass8.eu\",\n  \"||glype.com\",\n  \"||go141.com\",\n  \"||guo.media\",\n  \"||hautelook.com\",\n  \"||hautelookcdn.com\",\n  \"||wego.here.com\",\n  \"||gamer-cds.cdn.hinet.net\",\n  \"||gamer2-cds.cdn.hinet.net\",\n  \"||hmvdigital.ca\",\n  \"||hmvdigital.com\",\n  \"||homedepot.com\",\n  \"||hoovers.com\",\n  \"||hulu.com\",\n  \"||huluim.com\",\n  \"|http://secure.hustler.com\",\n  \"|http://hustlercash.com\",\n  \"|http://www.hustlercash.com\",\n  \"||hybrid-analysis.com\",\n  \"||cdn*.i-scmp.com\",\n  \"||ilbe.com\",\n  \"||ilovelongtoes.com\",\n  \"|http://imgmega.com/*.gif.html\",\n  \"|http://imgmega.com/*.jpg.html\",\n  \"|http://imgmega.com/*.jpeg.html\",\n  \"|http://imgmega.com/*.png.html\",\n  \"||imlive.com\",\n  \"||tw.iqiyi.com\",\n  \"||javhub.net\",\n  \"||javhuge.com\",\n  \".javlibrary.com\",\n  \"||javlibrary.com\",\n  \"||jcpenney.com\",\n  \"||jims.net\",\n  \"||tv.jtbc.joins.com\",\n  \"||jukujo-club.com\",\n  \"||juliepost.com\",\n  \"||kawaiikawaii.jp\",\n  \"||kendatire.com\",\n  \"||khatrimaza.org\",\n  \"||kkbox.com\",\n  \"||leisurepro.com\",\n  \"||lifemiles.com\",\n  \"||longtoes.com\",\n  \"||lovetvshow.com\",\n  \"|http://www.m-sport.co.uk\",\n  \"||macgamestore.com\",\n  \"||madonna-av.com\",\n  \"||mangafox.com\",\n  \"||mangafox.me\",\n  \"||manta.com\",\n  \"||matome-plus.com\",\n  \"||matome-plus.net\",\n  \"||mattwilcox.net\",\n  \"||metarthunter.com\",\n  \"||mfxmedia.com\",\n  \"||mojim.com\",\n  \"||kb.monitorware.com\",\n  \"||monster.com\",\n  \"||moodyz.com\",\n  \"||moonbingo.com\",\n  \"||mos.ru\",\n  \"||msha.gov\",\n  \"||muzu.tv\",\n  \"||mvg.jp\",\n  \".mybet.com\",\n  \"||mybet.com\",\n  \"||nationwide.com\",\n  \"|http://www.nbc.com/live\",\n  \"||neo-miracle.com\",\n  \"||netflix.com\",\n  \"||netflix.net\",\n  \"||nflximg.com\",\n  \"||nflximg.net\",\n  \"||nflxext.com\",\n  \"||nflxso.net\",\n  \"||nflxvideo.net\",\n  \"||nic.gov\",\n  \"|http://mo.nightlife141.com\",\n  \"||purpose.nike.com\",\n  \"||noxinfluencer.com\",\n  \"@@||cn.noxinfluencer.com\",\n  \"||nordstrom.com\",\n  \"||nordstromimage.com\",\n  \"||nordstromrack.com\",\n  \"||nottinghampost.com\",\n  \"||npsboost.com\",\n  \"||ntdtv.cz\",\n  \"||s1.nudezz.com\",\n  \"||nusatrip.com\",\n  \"||nuuvem.com\",\n  \"||omni7.jp\",\n  \"||onapp.com\",\n  \"||ontrac.com\",\n  \"@@|http://blog.ontrac.com\",\n  \"||pandora.com\",\n  \".pandora.tv\",\n  \"||parkansky.com\",\n  \"||phmsociety.org\",\n  \"|http://*.pimg.tw/\",\n  \"||pure18.com\",\n  \"||pytorch.org\",\n  \"||qq.co.za\",\n  \"||r18.com\",\n  \"|http://radiko.jp\",\n  \"||ramcity.com.au\",\n  \"||rateyourmusic.com\",\n  \"||rd.com\",\n  \"||rdio.com\",\n  \"|https://riseup.net\",\n  \"||sadistic-v.com\",\n  \"||isc.sans.edu\",\n  \"|http://cdn*.search.xxx/\",\n  \"||shiksha.com\",\n  \"||slacker.com\",\n  \"||sm-miracle.com\",\n  \"||softnology.biz\",\n  \"||soylentnews.org\",\n  \"||spotify.com\",\n  \"||spreadshirt.es\",\n  \"||springboardplatform.com\",\n  \"||sprite.org\",\n  \"@@|http://store.sprite.org\",\n  \"||superokayama.com\",\n  \"||superpages.com\",\n  \"||swagbucks.com\",\n  \"||switch1.jp\",\n  \"||tapanwap.com\",\n  \"||gsp.target.com\",\n  \"||login.target.com\",\n  \"||rcam.target.com\",\n  \"||technews.tw\",\n  \"||thinkgeek.com\",\n  \"||thebodyshop-usa.com\",\n  \"||tma.co.jp\",\n  \"||tracfone.com\",\n  \"||tryheart.jp\",\n  \"||turntable.fm\",\n  \"||twerkingbutt.com\",\n  \"||ulop.net\",\n  \"||uukanshu.com\",\n  \"||vegasred.com\",\n  \"||vevo.com\",\n  \"||vip-enterprise.com\",\n  \"|http://viu.tv/ch/\",\n  \"|http://viu.tv/encore/\",\n  \"||vmpsoft.com\",\n  \"|http://ecsm.vs.com/\",\n  \"||wanz-factory.com\",\n  \"||ssl.webpack.de\",\n  \"||wheretowatch.com\",\n  \"||wingamestore.com\",\n  \"||wizcrafts.net\",\n  \"||vod.wwe.com\",\n  \"||xfinity.com\",\n  \"||youwin.com\",\n  \"||ytn.co.kr\",\n  \"||zattoo.com\",\n  \"||zim.vn\",\n  \"||zozotown.com\",\n  \"14.102.250.18\",\n  \"14.102.250.19\",\n  \"50.7.31.230:8898\",\n  \"174.142.105.153\",\n  \"69.65.19.160\",\n  \"||xn--4gq171p.com\",\n  \"||xn--czq75pvv1aj5c.org\",\n  \"||xn--i2ru8q2qg.com\",\n  \"||xn--oiq.cc\",\n  \"||xn--p8j9a0d9c9a.xn--q9jyb4c\",\n  \"||abebooks.com\",\n  \"|https://*.s3.amazonaws.com\",\n  \"||s3-ap-southeast-2.amazonaws.com\",\n  \"||43110.cf\",\n  \"||9cache.com\",\n  \"||9gag.com\",\n  \"||agro.hk\",\n  \"||share.america.gov\",\n  \"||apkmirror.com\",\n  \"||arte.tv\",\n  \"||artstation.com\",\n  \"||bangdream.space\",\n  \"||behance.net\",\n  \"||bird.so\",\n  \"||bitterwinter.org\",\n  \"||bnn.co\",\n  \"||businessinsider.com\",\n  \"||boomssr.com\",\n  \"||bwgyhw.com\",\n  \"||castbox.fm\",\n  \"||chinatimes.com\",\n  \"||clyp.it\",\n  \"||cmcn.org\",\n  \"||cmx.im\",\n  \"||dailyview.tw\",\n  \"||daum.net\",\n  \"||depositphotos.com\",\n  \"||disconnect.me\",\n  \"||documentingreality.com\",\n  \"||doubibackup.com\",\n  \"||doubmirror.cf\",\n  \"||encyclopedia.com\",\n  \"||fangeqiang.com\",\n  \"||fanqiangdang.com\",\n  \"||feedly.com\",\n  \"||feedx.net\",\n  \"||flyzy2005.com\",\n  \"||foreignpolicy.com\",\n  \"||free-ss.site\",\n  \"||freehongkong.org\",\n  \"||blog.fuckgfw233.org\",\n  \"||g0v.social\",\n  \"||globalvoices.org\",\n  \"||glorystar.me\",\n  \"||goregrish.com\",\n  \"||guangnianvpn.com\",\n  \"||hanime.tv\",\n  \"||hbo.com\",\n  \"||spaces.hightail.com\",\n  \"||hkgalden.com\",\n  \"||hkgolden.com\",\n  \"||hudson.org\",\n  \"||ipfs.io\",\n  \"||japantimes.co.jp\",\n  \"||jiji.com\",\n  \"||jintian.net\",\n  \"||jinx.com\",\n  \"||joinmastodon.org\",\n  \"||liangzhichuanmei.com\",\n  \"||lighti.me\",\n  \"||lightyearvpn.com\",\n  \"||lihkg.com\",\n  \"||line-scdn.net\",\n  \"||i.lithium.com\",\n  \"||cloud.mail.ru\",\n  \"||cdn-images.mailchimp.com\",\n  \"||mastodon.cloud\",\n  \"||mastodon.host\",\n  \"||mastodon.social\",\n  \"||mastodon.xyz\",\n  \"||matters.news\",\n  \"||me.me\",\n  \"||metart.com\",\n  \"||mohu.club\",\n  \"||mohu.ml\",\n  \"||motiyun.com\",\n  \"||msa-it.org\",\n  \"||dictionary.goo.ne.jp\",\n  \"||go.nesnode.com\",\n  \"||international-news.newsmagazine.asia\",\n  \"||nikkei.com\",\n  \"||nitter.cc\",\n  \"||nitter.net\",\n  \"||niu.moe\",\n  \"||nofile.io\",\n  \"||now.com\",\n  \"||openvpn.org\",\n  \"||onejav.com\",\n  \"||paste.ee\",\n  \"||my.pcloud.com\",\n  \"||picacomic.com\",\n  \"||pincong.rocks\",\n  \"||pixiv.net\",\n  \"||potato.im\",\n  \"||premproxy.com\",\n  \"||prism-break.org\",\n  \"||protonvpn.com\",\n  \"||api.pureapk.com\",\n  \"||quora.com\",\n  \"||quoracdn.net\",\n  \"||qz.com\",\n  \"||cdn.seatguru.com\",\n  \"||secure.raxcdn.com\",\n  \"||redd.it\",\n  \"||reddit.com\",\n  \".redditlist.com\",\n  \"|http://redditlist.com\",\n  \"||redditmedia.com\",\n  \"||redditstatic.com\",\n  \"||rixcloud.com\",\n  \"||rixcloud.us\",\n  \"||rsdlmonitor.com\",\n  \"||shadowsocks.be\",\n  \"||shadowsocks9.com\",\n  \"||tn1.shemalez.com\",\n  \"||tn2.shemalez.com\",\n  \"||tn3.shemalez.com\",\n  \"||static.shemalez.com\",\n  \"||six-degrees.io\",\n  \"||softfamous.com\",\n  \"||softsmirror.cf\",\n  \"||sosreader.com\",\n  \"||sspanel.net\",\n  \"||sulian.me\",\n  \"||supchina.com\",\n  \"||teddysun.com\",\n  \"||textnow.me\",\n  \"||tineye.com\",\n  \"||top10vpn.com\",\n  \"||tubepornclassic.com\",\n  \"||uku.im\",\n  \"||unseen.is\",\n  \"||cn.uptodown.com\",\n  \"||uraban.me\",\n  \"||vrsmash.com\",\n  \"||vultryhw.com\",\n  \"||scache.vzw.com\",\n  \"||scache1.vzw.com\",\n  \"||scache2.vzw.com\",\n  \"||ss7.vzw.com\",\n  \"||ssr.tools\",\n  \"||steemit.com\",\n  \"||taiwanjustice.net\",\n  \"||tinc-vpn.org\",\n  \"||u15.info\",\n  \"||washingtonpost.com\",\n  \"||wenzhao.ca\",\n  \"||whatsonweibo.com\",\n  \"||wire.com\",\n  \"||blog.workflow.is\",\n  \"||xm.com\",\n  \"||xuehua.us\",\n  \"||yes-news.com\",\n  \"||yigeni.com\",\n  \"||you-get.org\",\n  \"||zzcloud.me\",\n  \"||aex.com\",\n  \"||allcoin.com\",\n  \"||adcex.com\",\n  \"||bcex.ca\",\n  \"||bibox.com\",\n  \"||big.one\",\n  \"||bigone.com\",\n  \"||binance.com\",\n  \"||bit-z.com\",\n  \"||bitz.ai\",\n  \"||bitbay.net\",\n  \"||bitcoinworld.com\",\n  \"||bitfinex.com\",\n  \"||bithumb.com\",\n  \"||bitinka.com.ar\",\n  \"||bitmex.com\",\n  \"||btc98.com\",\n  \"||btcbank.bank\",\n  \"||btctrade.im\",\n  \"||c2cx.com\",\n  \"||chaoex.com\",\n  \"||cobinhood.com\",\n  \"||coin2co.in\",\n  \"||coinbene.com\",\n  \".coinegg.com\",\n  \"||coinegg.com\",\n  \"||coinex.com\",\n  \"||coingi.com\",\n  \"||coinrail.co.kr\",\n  \"||cointiger.com\",\n  \"||cointobe.com\",\n  \"||coinut.com\",\n  \"||discoins.com\",\n  \"||dragonex.io\",\n  \"||ebtcbank.com\",\n  \"||etherdelta.com\",\n  \"||etherscan.io\",\n  \"||exmo.com\",\n  \"||exrates.me\",\n  \"||exx.com\",\n  \"||fatbtc.com\",\n  \"||gate.io\",\n  \"||gatecoin.com\",\n  \"||hbg.com\",\n  \"||hitbtc.com\",\n  \"||huobi.co\",\n  \"||huobi.com\",\n  \"||huobi.me\",\n  \"||huobi.pro\",\n  \"||huobi.sc\",\n  \"||huobipro.com\",\n  \"||bx.in.th\",\n  \"||jex.com\",\n  \"||kex.com\",\n  \"||kspcoin.com\",\n  \"||kucoin.com\",\n  \"||lbank.info\",\n  \"||livecoin.net\",\n  \"||localbitcoins.com\",\n  \"||mercatox.com\",\n  \"||oex.com\",\n  \"||okex.com\",\n  \"||otcbtc.com\",\n  \"||paxful.com\",\n  \"||rightbtc.com\",\n  \"||topbtc.com\",\n  \"||xbtce.com\",\n  \"||yobit.net\",\n  \"||zb.com\",\n  \"||read01.com\",\n  \"||kknews.cc\",\n  \"china-mmm.jp.net\",\n  \".lsxszzg.com\",\n  \".china-mmm.net\",\n  \"||china-mmm.net\",\n  \"china-mmm.sa.com\",\n  \".allowed.org\",\n  \".now.im\",\n  \"||amazon.co.jp\",\n  \".amazon.com/Dalai-Lama\",\n  \"amazon.com/Prisoner-State-Secret-Journal-Premier\",\n  \"s3-ap-northeast-1.amazonaws.com\",\n  \"||aolchannels.aol.com\",\n  \"video.aol.ca/video-detail\",\n  \"video.aol.co.uk/video-detail\",\n  \"video.aol.com\",\n  \"||video.aol.com\",\n  \"||search.aol.com\",\n  \"www.aolnews.com\",\n  \".avmo.pw\",\n  \".avmoo.com\",\n  \"|http://avmoo.com\",\n  \".avmoo.net\",\n  \"|http://avmoo.net\",\n  \"||avmoo.pw\",\n  \".javmoo.xyz\",\n  \"|http://javmoo.xyz\",\n  \".javtag.com\",\n  \"|http://javtag.com\",\n  \".javzoo.com\",\n  \"|http://javzoo.com\",\n  \".tellme.pw\",\n  \".bbc.com\",\n  \"||bbc.com\",\n  \".bbc.co.uk\",\n  \"||bbc.co.uk\",\n  \"||bbci.co.uk\",\n  \".bbcchinese.com\",\n  \"||bbcchinese.com\",\n  \"|http://bbc.in\",\n  \".bloomberg.cn\",\n  \"||bloomberg.cn\",\n  \".bloomberg.com\",\n  \"||bloomberg.com\",\n  \"bloomberg.de\",\n  \"||bloomberg.de\",\n  \"||bloombergview.com\",\n  \".businessweek.com\",\n  \".1dumb.com\",\n  \".25u.com\",\n  \".2waky.com\",\n  \".3-a.net\",\n  \".4dq.com\",\n  \".4mydomain.com\",\n  \".4pu.com\",\n  \".acmetoy.com\",\n  \".almostmy.com\",\n  \".americanunfinished.com\",\n  \".authorizeddns.net\",\n  \".authorizeddns.org\",\n  \".authorizeddns.us\",\n  \".bigmoney.biz\",\n  \".changeip.name\",\n  \".changeip.net\",\n  \".changeip.org\",\n  \".cleansite.biz\",\n  \".cleansite.info\",\n  \".cleansite.us\",\n  \".compress.to\",\n  \".ddns.info\",\n  \".ddns.me.uk\",\n  \".ddns.mobi\",\n  \".ddns.ms\",\n  \".ddns.name\",\n  \".ddns.us\",\n  \".dhcp.biz\",\n  \".dns-dns.com\",\n  \".dns-stuff.com\",\n  \".dns04.com\",\n  \".dns05.com\",\n  \".dns1.us\",\n  \".dns2.us\",\n  \".dnset.com\",\n  \".dnsrd.com\",\n  \".dsmtp.com\",\n  \".dumb1.com\",\n  \".dynamic-dns.net\",\n  \".dynamicdns.biz\",\n  \".dynamicdns.co.uk\",\n  \".dynamicdns.me.uk\",\n  \".dynamicdns.org.uk\",\n  \".dyndns.pro\",\n  \".dynssl.com\",\n  \".edns.biz\",\n  \".epac.to\",\n  \".esmtp.biz\",\n  \".ezua.com\",\n  \".faqserv.com\",\n  \".fartit.com\",\n  \".freeddns.com\",\n  \".freetcp.com\",\n  \".freewww.biz\",\n  \".freewww.info\",\n  \".ftp1.biz\",\n  \".ftpserver.biz\",\n  \".gettrials.com\",\n  \".got-game.org\",\n  \".gr8domain.biz\",\n  \".gr8name.biz\",\n  \".https443.net\",\n  \".https443.org\",\n  \".ikwb.com\",\n  \".instanthq.com\",\n  \".iownyour.biz\",\n  \".iownyour.org\",\n  \".isasecret.com\",\n  \".itemdb.com\",\n  \".itsaol.com\",\n  \".jetos.com\",\n  \".jkub.com\",\n  \".jungleheart.com\",\n  \".justdied.com\",\n  \".lflink.com\",\n  \".lflinkup.com\",\n  \".lflinkup.net\",\n  \".lflinkup.org\",\n  \".longmusic.com\",\n  \".mefound.com\",\n  \".moneyhome.biz\",\n  \".mrbasic.com\",\n  \".mrbonus.com\",\n  \".mrface.com\",\n  \".mrslove.com\",\n  \".my03.com\",\n  \".mydad.info\",\n  \".myddns.com\",\n  \".myftp.info\",\n  \".myftp.name\",\n  \".mylftv.com\",\n  \".mymom.info\",\n  \".mynetav.net\",\n  \".mynetav.org\",\n  \".mynumber.org\",\n  \".mypicture.info\",\n  \".mypop3.net\",\n  \".mypop3.org\",\n  \".mysecondarydns.com\",\n  \".mywww.biz\",\n  \".myz.info\",\n  \".ninth.biz\",\n  \".ns01.biz\",\n  \".ns01.info\",\n  \".ns01.us\",\n  \".ns02.biz\",\n  \".ns02.info\",\n  \".ns02.us\",\n  \".ns1.name\",\n  \".ns2.name\",\n  \".ns3.name\",\n  \".ocry.com\",\n  \".onedumb.com\",\n  \".onmypc.biz\",\n  \".onmypc.info\",\n  \".onmypc.net\",\n  \".onmypc.org\",\n  \".onmypc.us\",\n  \".organiccrap.com\",\n  \".otzo.com\",\n  \".ourhobby.com\",\n  \".pcanywhere.net\",\n  \".port25.biz\",\n  \".proxydns.com\",\n  \".qhigh.com\",\n  \".qpoe.com\",\n  \".rebatesrule.net\",\n  \".sellclassics.com\",\n  \".sendsmtp.com\",\n  \".serveuser.com\",\n  \".serveusers.com\",\n  \".sexidude.com\",\n  \".sexxxy.biz\",\n  \".sixth.biz\",\n  \".squirly.info\",\n  \".ssl443.org\",\n  \".toh.info\",\n  \".toythieves.com\",\n  \".trickip.net\",\n  \".trickip.org\",\n  \".vizvaz.com\",\n  \".wha.la\",\n  \".wikaba.com\",\n  \".www1.biz\",\n  \".wwwhost.biz\",\n  \"@@|http://xx.wwwhost.biz\",\n  \".x24hr.com\",\n  \".xxuz.com\",\n  \".xxxy.biz\",\n  \".xxxy.info\",\n  \".ygto.com\",\n  \".youdontcare.com\",\n  \".yourtrap.com\",\n  \".zyns.com\",\n  \".zzux.com\",\n  \"d1b183sg0nvnuh.cloudfront.net\",\n  \"|https://d1b183sg0nvnuh.cloudfront.net\",\n  \"d1c37gjwa26taa.cloudfront.net\",\n  \"|https://d1c37gjwa26taa.cloudfront.net\",\n  \"d3c33hcgiwev3.cloudfront.net\",\n  \"|https://d3c33hcgiwev3.cloudfront.net\",\n  \"||d3rhr7kgmtrq1v.cloudfront.net\",\n  \".3d-game.com\",\n  \".4irc.com\",\n  \".b0ne.com\",\n  \".chatnook.com\",\n  \".darktech.org\",\n  \".deaftone.com\",\n  \".dtdns.net\",\n  \".effers.com\",\n  \".etowns.net\",\n  \".etowns.org\",\n  \".flnet.org\",\n  \".gotgeeks.com\",\n  \".scieron.com\",\n  \".slyip.com\",\n  \".slyip.net\",\n  \".suroot.com\",\n  \".blogdns.org\",\n  \".dyndns.org\",\n  \".dyndns-ip.com\",\n  \".dyndns-pics.com\",\n  \".from-sd.com\",\n  \".from-pr.com\",\n  \".is-a-hunter.com\",\n  \".dynu.com\",\n  \"||dynu.com\",\n  \".dynu.net\",\n  \".freeddns.org\",\n  \"||accountkit.com\",\n  \"cdninstagram.com\",\n  \"||cdninstagram.com\",\n  \"||f8.com\",\n  \"||facebook.br\",\n  \".facebook.com\",\n  \"||facebook.com\",\n  \"@@||v6.facebook.com\",\n  \"||facebook.design\",\n  \"||connect.facebook.net\",\n  \"||facebook.hu\",\n  \"||facebook.in\",\n  \"||facebook.nl\",\n  \"||facebook.se\",\n  \"||facebookmail.com\",\n  \"||fb.com\",\n  \"||fb.me\",\n  \"||fb.watch\",\n  \"||fbcdn.net\",\n  \"||fbsbx.com\",\n  \"||fbaddins.com\",\n  \"||fbworkmail.com\",\n  \".instagram.com\",\n  \"||instagram.com\",\n  \"||m.me\",\n  \"||messenger.com\",\n  \"||oculus.com\",\n  \"||oculuscdn.com\",\n  \"||rocksdb.org\",\n  \"@@||ip6.static.sl-reverse.com\",\n  \"||parse.com\",\n  \"||thefacebook.com\",\n  \"||whatsapp.com\",\n  \"||whatsapp.net\",\n  \"||auntology.fandom.com\",\n  \"||hongkong.fandom.com\",\n  \".ftchinese.com\",\n  \"||ftchinese.com\",\n  \"||1e100.net\",\n  \"||466453.com\",\n  \"||abc.xyz\",\n  \"||about.google\",\n  \"||admob.com\",\n  \"||adsense.com\",\n  \"||advertisercommunity.com\",\n  \"||agoogleaday.com\",\n  \"||ai.google\",\n  \"||ampproject.org\",\n  \"@@|https://www.ampproject.org\",\n  \"@@|https://cdn.ampproject.org\",\n  \"||android.com\",\n  \"||androidify.com\",\n  \"||androidtv.com\",\n  \"||api.ai\",\n  \".appspot.com\",\n  \"||appspot.com\",\n  \"||autodraw.com\",\n  \"||blog.google\",\n  \"||blogblog.com\",\n  \"blogspot.com\",\n  \"/^https?:\\\\/\\\\/[^\\\\/]+blogspot\\\\.(.*)/\",\n  \".blogspot.hk\",\n  \".blogspot.jp\",\n  \".blogspot.tw\",\n  \"||certificate-transparency.org\",\n  \"||chrome.com\",\n  \"||chromecast.com\",\n  \"||chromeenterprise.google\",\n  \"||chromeexperiments.com\",\n  \"||chromercise.com\",\n  \"||chromestatus.com\",\n  \"||chromium.org\",\n  \"||com.google\",\n  \"||crbug.com\",\n  \"||creativelab5.com\",\n  \"||crisisresponse.google\",\n  \"||crrev.com\",\n  \"||data-vocabulary.org\",\n  \"||debug.com\",\n  \"||deepmind.com\",\n  \"||deja.com\",\n  \"||design.google\",\n  \"||digisfera.com\",\n  \"||dns.google\",\n  \"||domains.google\",\n  \"||duck.com\",\n  \"||environment.google\",\n  \"||feedburner.com\",\n  \"||firebaseio.com\",\n  \"||g.co\",\n  \"||gcr.io\",\n  \"||get.app\",\n  \"||get.dev\",\n  \"||get.how\",\n  \"||get.page\",\n  \"||getmdl.io\",\n  \"||getoutline.org\",\n  \"||ggpht.com\",\n  \"||gmail.com\",\n  \"||gmodules.com\",\n  \"||godoc.org\",\n  \"||golang.org\",\n  \"||goo.gl\",\n  \".google.ae\",\n  \".google.as\",\n  \".google.am\",\n  \".google.at\",\n  \".google.az\",\n  \".google.ba\",\n  \".google.be\",\n  \".google.bg\",\n  \".google.ca\",\n  \".google.cd\",\n  \".google.ci\",\n  \".google.co.id\",\n  \".google.co.jp\",\n  \".google.co.kr\",\n  \".google.co.ma\",\n  \".google.co.uk\",\n  \".google.com\",\n  \".google.de\",\n  \"||google.dev\",\n  \".google.dj\",\n  \".google.dk\",\n  \".google.es\",\n  \".google.fi\",\n  \".google.fm\",\n  \".google.fr\",\n  \".google.gg\",\n  \".google.gl\",\n  \".google.gr\",\n  \".google.ie\",\n  \".google.is\",\n  \".google.it\",\n  \".google.jo\",\n  \".google.kz\",\n  \".google.lv\",\n  \".google.mn\",\n  \".google.ms\",\n  \".google.nl\",\n  \".google.nu\",\n  \".google.no\",\n  \".google.ro\",\n  \".google.ru\",\n  \".google.rw\",\n  \".google.sc\",\n  \".google.sh\",\n  \".google.sk\",\n  \".google.sm\",\n  \".google.sn\",\n  \".google.tk\",\n  \".google.tm\",\n  \".google.to\",\n  \".google.tt\",\n  \".google.vu\",\n  \".google.ws\",\n  \"/^https?:\\\\/\\\\/([^\\\\/]+\\\\.)*google\\\\.(ac|ad|ae|af|ai|al|am|as|at|az|ba|be|bf|bg|bi|bj|bs|bt|by|ca|cat|cd|cf|cg|ch|ci|cl|cm|co.ao|co.bw|co.ck|co.cr|co.id|co.il|co.in|co.jp|co.ke|co.kr|co.ls|co.ma|com|com.af|com.ag|com.ai|com.ar|com.au|com.bd|com.bh|com.bn|com.bo|com.br|com.bz|com.co|com.cu|com.cy|com.do|com.ec|com.eg|com.et|com.fj|com.gh|com.gi|com.gt|com.hk|com.jm|com.kh|com.kw|com.lb|com.ly|com.mm|com.mt|com.mx|com.my|com.na|com.nf|com.ng|com.ni|com.np|com.om|com.pa|com.pe|com.pg|com.ph|com.pk|com.pr|com.py|com.qa|com.sa|com.sb|com.sg|com.sl|com.sv|com.tj|com.tr|com.tw|com.ua|com.uy|com.vc|com.vn|co.mz|co.nz|co.th|co.tz|co.ug|co.uk|co.uz|co.ve|co.vi|co.za|co.zm|co.zw|cv|cz|de|dj|dk|dm|dz|ee|es|eu|fi|fm|fr|ga|ge|gg|gl|gm|gp|gr|gy|hk|hn|hr|ht|hu|ie|im|iq|is|it|it.ao|je|jo|kg|ki|kz|la|li|lk|lt|lu|lv|md|me|mg|mk|ml|mn|ms|mu|mv|mw|mx|ne|nl|no|nr|nu|org|pl|pn|ps|pt|ro|rs|ru|rw|sc|se|sh|si|sk|sm|sn|so|sr|st|td|tg|tk|tl|tm|tn|to|tt|us|vg|vn|vu|ws)\\\\/.*/\",\n  \"||googleapis.cn\",\n  \"||googleapis.com\",\n  \"||googleapps.com\",\n  \"||googleartproject.com\",\n  \"||googleblog.com\",\n  \"||googlebot.com\",\n  \"||googlechinawebmaster.com\",\n  \"||googlecode.com\",\n  \"||googlecommerce.com\",\n  \"||googledomains.com\",\n  \"||googlearth.com\",\n  \"||googleearth.com\",\n  \"||googledrive.com\",\n  \"||googlefiber.net\",\n  \"||googlegroups.com\",\n  \"||googlehosted.com\",\n  \"||googleideas.com\",\n  \"||googleinsidesearch.com\",\n  \"||googlelabs.com\",\n  \"||googlemail.com\",\n  \"||googlemashups.com\",\n  \"||googlepagecreator.com\",\n  \"||googleplay.com\",\n  \"||googleplus.com\",\n  \"||googlescholar.comUSA\",\n  \"||googlesource.com\",\n  \"||googleusercontent.com\",\n  \".googlevideo.com\",\n  \"||googlevideo.com\",\n  \"||googleweblight.com\",\n  \"||googlezip.net\",\n  \"||groups.google.cn\",\n  \"||grow.google\",\n  \"||gstatic.com\",\n  \"||gvt0.com\",\n  \"||gvt1.com\",\n  \"@@||redirector.gvt1.com\",\n  \"||gvt3.com\",\n  \"||gwtproject.org\",\n  \"||html5rocks.com\",\n  \"||iam.soy\",\n  \"||igoogle.com\",\n  \"||itasoftware.com\",\n  \"||lers.google\",\n  \"||like.com\",\n  \"||madewithcode.com\",\n  \"||material.io\",\n  \"||nic.google\",\n  \"||on2.com\",\n  \"||opensource.google\",\n  \"||panoramio.com\",\n  \"||picasaweb.com\",\n  \"||pki.goog\",\n  \"||plus.codes\",\n  \"||polymer-project.org\",\n  \"||pride.google\",\n  \"||questvisual.com\",\n  \"||admin.recaptcha.net\",\n  \"||api.recaptcha.net\",\n  \"||api-secure.recaptcha.net\",\n  \"||api-verify.recaptcha.net\",\n  \"||redhotlabs.com\",\n  \"||registry.google\",\n  \"||research.google\",\n  \"||safety.google\",\n  \"||savethedate.foo\",\n  \"||schema.org\",\n  \"||shattered.io\",\n  \"|http://sipml5.org/\",\n  \"||stories.google\",\n  \"||sustainability.google\",\n  \"||synergyse.com\",\n  \"||teachparentstech.org\",\n  \"||tensorflow.org\",\n  \"||tfhub.dev\",\n  \"||thinkwithgoogle.com\",\n  \"||tiltbrush.com\",\n  \"||translate.google\",\n  \"||tv.google\",\n  \"||urchin.com\",\n  \"||waveprotocol.org\",\n  \"||waymo.com\",\n  \"||web.dev\",\n  \"||webmproject.org\",\n  \"||webrtc.org\",\n  \"||whatbrowser.org\",\n  \"||widevine.com\",\n  \"||withgoogle.com\",\n  \"||withyoutube.com\",\n  \"||x.company\",\n  \"||xn--ngstr-lra8j.com\",\n  \"||youtu.be\",\n  \".youtube.com\",\n  \"||youtube.com\",\n  \"||youtube-nocookie.com\",\n  \"||youtubeeducation.com\",\n  \"||youtubegaming.com\",\n  \"||youtubekids.com\",\n  \"||yt.be\",\n  \"||ytimg.com\",\n  \"||zynamics.com\",\n  \"||naughtyamerica.com\",\n  \"static01.nyt.com\",\n  \"||nyt.com\",\n  \"nytchina.com\",\n  \"nytcn.me\",\n  \"||nytcn.me\",\n  \"||nytco.com\",\n  \"|http://nyti.ms/\",\n  \".nytimes.com\",\n  \"||nytimes.com\",\n  \"||nytimg.com\",\n  \"userapi.nytlog.com\",\n  \"cn.nytstyle.com\",\n  \"||nytstyle.com\",\n  \".steamcommunity.com\",\n  \"||steamcommunity.com\",\n  \"|http://store.steampowered.com\",\n  \"||t.me\",\n  \"||updates.tdesktop.com\",\n  \"||telegram.dog\",\n  \"||telegram.me\",\n  \"||telegram.org\",\n  \".telegramdownload.com\",\n  \"||telesco.pe\",\n  \"||jtvnw.net\",\n  \"||ttvnw.net\",\n  \"||twitch.tv\",\n  \"||twitchcdn.net\",\n  \"||periscope.tv\",\n  \".pscp.tv\",\n  \"||pscp.tv\",\n  \".t.co\",\n  \"||t.co\",\n  \".tweetdeck.com\",\n  \"||tweetdeck.com\",\n  \"||twimg.com\",\n  \".twitpic.com\",\n  \"||twitpic.com\",\n  \".twitter.com\",\n  \"||twitter.com\",\n  \"||twitter.jp\",\n  \"||vine.co\",\n  \"||gov.taipei\",\n  \".gov.tw\",\n  \"|https://aiss.anws.gov.tw\",\n  \"||archives.gov.tw\",\n  \"||tacc.cwb.gov.tw\",\n  \"||data.gov.tw\",\n  \"||epa.gov.tw\",\n  \"||fa.gov.tw\",\n  \"||fda.gov.tw\",\n  \"||hpa.gov.tw\",\n  \"||immigration.gov.tw\",\n  \"||itaiwan.gov.tw\",\n  \"||mjib.gov.tw\",\n  \"||moeaic.gov.tw\",\n  \"||mofa.gov.tw\",\n  \"||mol.gov.tw\",\n  \"||mvdis.gov.tw\",\n  \"||nat.gov.tw\",\n  \"||nhi.gov.tw\",\n  \"||npa.gov.tw\",\n  \"||nsc.gov.tw\",\n  \"||ntbk.gov.tw\",\n  \"||ntbna.gov.tw\",\n  \"||ntbt.gov.tw\",\n  \"||ntsna.gov.tw\",\n  \"||pcc.gov.tw\",\n  \"||stat.gov.tw\",\n  \"||taipei.gov.tw\",\n  \"||taiwanjobs.gov.tw\",\n  \"||thb.gov.tw\",\n  \"||tipo.gov.tw\",\n  \"||wda.gov.tw\",\n  \"||teco-hk.org\",\n  \"||teco-mo.org\",\n  \"@@||aftygh.gov.tw\",\n  \"@@||aide.gov.tw\",\n  \"@@||tpde.aide.gov.tw\",\n  \"@@||arte.gov.tw\",\n  \"@@||chukuang.gov.tw\",\n  \"@@||cwb.gov.tw\",\n  \"@@||cycab.gov.tw\",\n  \"@@||dbnsa.gov.tw\",\n  \"@@||df.gov.tw\",\n  \"@@||eastcoast-nsa.gov.tw\",\n  \"@@||erv-nsa.gov.tw\",\n  \"@@||grb.gov.tw\",\n  \"@@||gysd.nyc.gov.tw\",\n  \"@@||hchcc.gov.tw\",\n  \"@@||hsinchu-cc.gov.tw\",\n  \"@@||iner.gov.tw\",\n  \"@@||klsio.gov.tw\",\n  \"@@||kmseh.gov.tw\",\n  \"@@||lungtanhr.gov.tw\",\n  \"@@||maolin-nsa.gov.tw\",\n  \"@@||matsu-news.gov.tw\",\n  \"@@||matsu-nsa.gov.tw\",\n  \"@@||matsucc.gov.tw\",\n  \"@@||moe.gov.tw\",\n  \"@@||mvdis.gov.tw\",\n  \"@@||nankan.gov.tw\",\n  \"@@||ncree.gov.tw\",\n  \"@@||necoast-nsa.gov.tw\",\n  \"@@||siraya-nsa.gov.tw\",\n  \"@@||cromotc.nat.gov.tw\",\n  \"@@||tax.nat.gov.tw\",\n  \"@@||necoast-nsa.gov.tw\",\n  \"@@||ner.gov.tw\",\n  \"@@||nmmba.gov.tw\",\n  \"@@||nmp.gov.tw\",\n  \"@@||nmvttc.gov.tw\",\n  \"@@||northguan-nsa.gov.tw\",\n  \"@@||npm.gov.tw\",\n  \"@@||nstm.gov.tw\",\n  \"@@||ntdmh.gov.tw\",\n  \"@@||ntl.gov.tw\",\n  \"@@||ntsec.gov.tw\",\n  \"@@||ntuh.gov.tw\",\n  \"@@||nvri.gov.tw\",\n  \"@@||penghu-nsa.gov.tw\",\n  \"@@||post.gov.tw\",\n  \"@@||siraya-nsa.gov.tw\",\n  \"@@||stdtime.gov.tw\",\n  \"@@||sunmoonlake.gov.tw\",\n  \"@@||taitung-house.gov.tw\",\n  \"@@||taoyuan.gov.tw\",\n  \"@@||tphcc.gov.tw\",\n  \"@@||trimt-nsa.gov.tw\",\n  \"@@||vghtpe.gov.tw\",\n  \"@@||vghks.gov.tw\",\n  \"@@||vghtc.gov.tw\",\n  \"@@||wanfang.gov.tw\",\n  \"@@||yatsen.gov.tw\",\n  \"@@||yda.gov.tw\",\n  \"||kinmen.org.tw\",\n  \"|http://www.americorps.gov\",\n  \"||jpl.nasa.gov\",\n  \"||pds.nasa.gov\",\n  \"||solarsystem.nasa.gov\",\n  \"iipdigital.usembassy.gov\",\n  \"||usfk.mil\",\n  \"||usmc.mil\",\n  \"|http://tarr.uspto.gov/\",\n  \"||tsdr.uspto.gov\",\n  \"||v2ex.com\",\n  \"cn.voa.mobi\",\n  \"tw.voa.mobi\",\n  \"||voacambodia.com\",\n  \".voachineseblog.com\",\n  \"||voachineseblog.com\",\n  \".voacantonese.com\",\n  \"||voacantonese.com\",\n  \"voachinese.com\",\n  \"||voachinese.com\",\n  \"voagd.com\",\n  \"||voaindonesia.com\",\n  \".voanews.com\",\n  \"||voanews.com\",\n  \"voatibetan.com\",\n  \"||voatibetan.com\",\n  \".voatibetanenglish.com\",\n  \"||voatibetanenglish.com\",\n  \"||zh.ecdm.wikia.com\",\n  \"||evchk.wikia.com\",\n  \"fq.wikia.com\",\n  \"zh.pttpedia.wikia.com/wiki/%E7%BF%92%E5%8C%85%E5%AD%90%E4%B9%8B%E4%BA%82\",\n  \"cn.uncyclopedia.wikia.com\",\n  \"zh.uncyclopedia.wikia.com\",\n  \"||wikimedia.org\",\n  \"|http://zh.wikisource.org\",\n  \"||zh.wikiquote.org\",\n  \"||zh.wikinews.org\",\n  \"||ja.wikipedia.org\",\n  \"||wikipedia.org\",\n  \"||data.flurry.com\",\n  \"page.bid.yahoo.com\",\n  \"tw.bid.yahoo.com\",\n  \"|https://tw.bid.yahoo.com\",\n  \"blogs.yahoo.co.jp\",\n  \"||search.yahoo.co.jp\",\n  \"buy.yahoo.com.tw/gdsale\",\n  \"hk.yahoo.com\",\n  \"hk.knowledge.yahoo.com\",\n  \"tw.money.yahoo.com\",\n  \"hk.myblog.yahoo.com\",\n  \"news.yahoo.com/china-blocks-bbc\",\n  \"||hk.news.yahoo.com\",\n  \"hk.rd.yahoo.com\",\n  \"hk.search.yahoo.com/search\",\n  \"hk.video.news.yahoo.com/video\",\n  \"meme.yahoo.com\",\n  \"tw.answers.yahoo.com\",\n  \"|https://tw.answers.yahoo.com\",\n  \"||tw.knowledge.yahoo.com\",\n  \"||tw.mall.yahoo.com\",\n  \"tw.yahoo.com\",\n  \"||tw.mobi.yahoo.com\",\n  \"tw.myblog.yahoo.com\",\n  \"||tw.news.yahoo.com\",\n  \"pulse.yahoo.com\",\n  \"||search.yahoo.com\",\n  \"upcoming.yahoo.com\",\n  \"video.yahoo.com\",\n  \"||yahoo.com.hk\",\n  \"||duckduckgo-owned-server.yahoo.net\",\n  \"||000webhost.com\",\n  \".030buy.com\",\n  \".0rz.tw\",\n  \"|http://0rz.tw\",\n  \"1-apple.com.tw\",\n  \"||1-apple.com.tw\",\n  \".10.tt\",\n  \".100ke.org\",\n  \".1000giri.net\",\n  \"||1000giri.net\",\n  \"||10beasts.net\",\n  \".10conditionsoflove.com\",\n  \"||10musume.com\",\n  \"123rf.com\",\n  \".12bet.com\",\n  \"||12bet.com\",\n  \".12vpn.com\",\n  \".12vpn.net\",\n  \"||12vpn.com\",\n  \"||12vpn.net\",\n  \"||1337x.to\",\n  \".138.com\",\n  \"141hongkong.com/forum\",\n  \"||141jj.com\",\n  \".141tube.com\",\n  \".1688.com.au\",\n  \".173ng.com\",\n  \"||173ng.com\",\n  \".177pic.info\",\n  \".17t17p.com\",\n  \"||18board.com\",\n  \"||18board.info\",\n  \"18onlygirls.com\",\n  \".18p2p.com\",\n  \".18virginsex.com\",\n  \".1949er.org\",\n  \"zhao.1984.city\",\n  \"||zhao.1984.city\",\n  \"1984bbs.com\",\n  \"||1984bbs.com\",\n  \".1984bbs.org\",\n  \"||1984bbs.org\",\n  \".1991way.com\",\n  \"||1991way.com\",\n  \".1998cdp.org\",\n  \".1bao.org\",\n  \"|http://1bao.org\",\n  \".1eew.com\",\n  \".1mobile.com\",\n  \"|http://*.1mobile.tw\",\n  \"||1pondo.tv\",\n  \".2-hand.info\",\n  \".2000fun.com/bbs\",\n  \".2008xianzhang.info\",\n  \"||2008xianzhang.info\",\n  \"||2017.hk\",\n  \"||2047.name\",\n  \"21andy.com/blog\",\n  \".21join.com\",\n  \".21pron.com\",\n  \"21sextury.com\",\n  \".228.net.tw\",\n  \"||233abc.com\",\n  \"||24hrs.ca\",\n  \"24smile.org\",\n  \"2lipstube.com\",\n  \".2shared.com\",\n  \"30boxes.com\",\n  \".315lz.com\",\n  \"||32red.com\",\n  \"||36rain.com\",\n  \".3a5a.com\",\n  \"3arabtv.com\",\n  \".3boys2girls.com\",\n  \".3proxy.ru\",\n  \".3ren.ca\",\n  \".3tui.net\",\n  \"||404museum.com\",\n  \"||4bluestones.biz\",\n  \".4chan.com\",\n  \".4everproxy.com\",\n  \"||4everproxy.com\",\n  \"||4rbtv.com\",\n  \"||4shared.com\",\n  \"taiwannation.50webs.com\",\n  \"||51.ca\",\n  \"||51jav.org\",\n  \".51luoben.com\",\n  \"||51luoben.com\",\n  \".5278.cc\",\n  \".5299.tv\",\n  \"5aimiku.com\",\n  \"5i01.com\",\n  \".5isotoi5.org\",\n  \".5maodang.com\",\n  \"||63i.com\",\n  \".64museum.org\",\n  \"64tianwang.com\",\n  \"64wiki.com\",\n  \".66.ca\",\n  \"666kb.com\",\n  \"||6do.news\",\n  \".6park.com\",\n  \"||6park.com\",\n  \"||6parkbbs.com\",\n  \"||6parker.com\",\n  \"||6parknews.com\",\n  \"||7capture.com\",\n  \".7cow.com\",\n  \".8-d.com\",\n  \"|http://8-d.com\",\n  \"85cc.net\",\n  \".85cc.us\",\n  \"|http://85cc.us\",\n  \"|http://85st.com\",\n  \".881903.com/page/zh-tw/\",\n  \"||881903.com\",\n  \".888.com\",\n  \".888poker.com\",\n  \"89.64.charter.constitutionalism.solutions\",\n  \"89-64.org\",\n  \"||89-64.org\",\n  \"||8964museum.com\",\n  \".8news.com.tw\",\n  \".8z1.net\",\n  \"||8z1.net\",\n  \".9001700.com\",\n  \"|http://908taiwan.org/\",\n  \"||91porn.com\",\n  \"||91vps.club\",\n  \".92ccav.com\",\n  \".991.com\",\n  \"|http://991.com\",\n  \".99btgc01.com\",\n  \"||99btgc01.com\",\n  \".99cn.info\",\n  \"|http://99cn.info\",\n  \"||9bis.com\",\n  \"||9bis.net\",\n  \"||9news.com.au\",\n  \".tibet.a.se\",\n  \"|http://tibet.a.se\",\n  \"||a-normal-day.com\",\n  \"a5.com.ru\",\n  \"|http://aamacau.com\",\n  \".abc.com\",\n  \".abc.net.au\",\n  \"||abc.net.au\",\n  \".abchinese.com\",\n  \"abclite.net\",\n  \"|https://www.abclite.net\",\n  \".ablwang.com\",\n  \".aboluowang.com\",\n  \"||aboluowang.com\",\n  \".aboutgfw.com\",\n  \".abs.edu\",\n  \".accim.org\",\n  \".aceros-de-hispania.com\",\n  \".acevpn.com\",\n  \"||acevpn.com\",\n  \".acg18.me\",\n  \"|http://acg18.me\",\n  \"||acgbox.org\",\n  \"||acgkj.com\",\n  \"||acgnx.se\",\n  \".acmedia365.com\",\n  \".acnw.com.au\",\n  \"actfortibet.org\",\n  \"actimes.com.au\",\n  \"activpn.com\",\n  \"||activpn.com\",\n  \"||aculo.us\",\n  \"||addictedtocoffee.de\",\n  \"||addyoutube.com\",\n  \".adelaidebbs.com/bbs\",\n  \".adpl.org.hk\",\n  \"|http://adpl.org.hk\",\n  \".adult-sex-games.com\",\n  \"||adult-sex-games.com\",\n  \"adultfriendfinder.com\",\n  \"adultkeep.net/peepshow/members/main.htm\",\n  \"||advanscene.com\",\n  \"||advertfan.com\",\n  \".ae.org\",\n  \"||aenhancers.com\",\n  \"||af.mil\",\n  \".afantibbs.com\",\n  \"|http://afantibbs.com\",\n  \"||afr.com\",\n  \".ai-kan.net\",\n  \"||ai-kan.net\",\n  \"ai-wen.net\",\n  \".aiph.net\",\n  \"||aiph.net\",\n  \".airasia.com\",\n  \"||airconsole.com\",\n  \"|http://download.aircrack-ng.org\",\n  \".airvpn.org\",\n  \"||airvpn.org\",\n  \".aisex.com\",\n  \"||ait.org.tw\",\n  \"aiweiwei.com\",\n  \".aiweiweiblog.com\",\n  \"||aiweiweiblog.com\",\n  \"||www.ajsands.com\",\n  \"a248.e.akamai.net\",\n  \"||a248.e.akamai.net\",\n  \"rfalive1.akacast.akamaistream.net\",\n  \"voa-11.akacast.akamaistream.net\",\n  \"||abematv.akamaized.net\",\n  \"||linear-abematv.akamaized.net\",\n  \"||vod-abematv.akamaized.net\",\n  \"|https://fbcdn*.akamaihd.net/\",\n  \"rthklive2-lh.akamaihd.net\",\n  \".akademiye.org/ug\",\n  \"|http://akademiye.org/ug\",\n  \"||akiba-online.com\",\n  \"||akow.org\",\n  \".al-islam.com\",\n  \"||al-qimmah.net\",\n  \"||alabout.com\",\n  \".alanhou.com\",\n  \"|http://alanhou.com\",\n  \".alarab.qa\",\n  \"||alasbarricadas.org\",\n  \"alexlur.org\",\n  \"||alforattv.net\",\n  \".alhayat.com\",\n  \".alicejapan.co.jp\",\n  \"aliengu.com\",\n  \"||alive.bar\",\n  \"||alkasir.com\",\n  \"||all4mom.org\",\n  \"||allconnected.co\",\n  \".alldrawnsex.com\",\n  \"||alldrawnsex.com\",\n  \".allervpn.com\",\n  \"||allfinegirls.com\",\n  \".allgirlmassage.com\",\n  \"allgirlsallowed.org\",\n  \".allgravure.com\",\n  \"alliance.org.hk\",\n  \".allinfa.com\",\n  \"||allinfa.com\",\n  \".alljackpotscasino.com\",\n  \"||allmovie.com\",\n  \"||almasdarnews.com\",\n  \".alphaporno.com\",\n  \"||alternate-tools.com\",\n  \"alternativeto.net/software\",\n  \"alvinalexander.com\",\n  \"alwaysdata.com\",\n  \"||alwaysdata.com\",\n  \"||alwaysdata.net\",\n  \".alwaysvpn.com\",\n  \"||alwaysvpn.com\",\n  \"||am730.com.hk\",\n  \"ameblo.jp\",\n  \"||ameblo.jp\",\n  \"www1.american.edu/ted/ice/tibet\",\n  \"||americangreencard.com\",\n  \"||amiblockedornot.com\",\n  \".amigobbs.net\",\n  \".amitabhafoundation.us\",\n  \"|http://amitabhafoundation.us\",\n  \".amnesty.org\",\n  \"||amnesty.org\",\n  \"||amnesty.org.hk\",\n  \".amnesty.tw\",\n  \".amnestyusa.org\",\n  \"||amnestyusa.org\",\n  \".amnyemachen.org\",\n  \".amoiist.com\",\n  \".amtb-taipei.org\",\n  \"androidplus.co/apk\",\n  \".andygod.com\",\n  \"|http://andygod.com\",\n  \"annatam.com/chinese\",\n  \"||anchor.fm\",\n  \"||anchorfree.com\",\n  \"||ancsconf.org\",\n  \"||andfaraway.net\",\n  \"||android-x86.org\",\n  \"angelfire.com/hi/hayashi\",\n  \"||angularjs.org\",\n  \"animecrazy.net\",\n  \"aniscartujo.com\",\n  \"||aniscartujo.com\",\n  \"||anobii.com\",\n  \"anonymise.us\",\n  \".anonymitynetwork.com\",\n  \".anonymizer.com\",\n  \".anonymouse.org\",\n  \"||anonymouse.org\",\n  \"anontext.com\",\n  \".anpopo.com\",\n  \".answering-islam.org\",\n  \"|http://www.antd.org\",\n  \"||anthonycalzadilla.com\",\n  \".anti1984.com\",\n  \"antichristendom.com\",\n  \".antiwave.net\",\n  \"|http://antiwave.net\",\n  \".anyporn.com\",\n  \".anysex.com\",\n  \"|http://anysex.com\",\n  \".ao3.org\",\n  \"||ao3.org\",\n  \"||aobo.com.au\",\n  \".aofriend.com\",\n  \"|http://aofriend.com\",\n  \".aofriend.com.au\",\n  \".aojiao.org\",\n  \"||aomiwang.com\",\n  \"video.ap.org\",\n  \"||apat1989.org\",\n  \".apetube.com\",\n  \"||apiary.io\",\n  \".apigee.com\",\n  \"||apigee.com\",\n  \"||apk.support\",\n  \"||apk-dl.com\",\n  \"||apkcombo.com\",\n  \".apkmonk.com/app\",\n  \"||apkmonk.com\",\n  \"||apkplz.com\",\n  \"apkpure.com\",\n  \"||apkpure.com\",\n  \".aplusvpn.com\",\n  \"||appbrain.com\",\n  \".appdownloader.net/Android\",\n  \".appledaily.com\",\n  \"||appledaily.com\",\n  \"appledaily.com.hk\",\n  \"||appledaily.com.hk\",\n  \"appledaily.com.tw\",\n  \"||appledaily.com.tw\",\n  \".appshopper.com\",\n  \"|http://appshopper.com\",\n  \"||appsocks.net\",\n  \"||appsto.re\",\n  \".aptoide.com\",\n  \"||aptoide.com\",\n  \"||archives.gov\",\n  \".archive.fo\",\n  \"||archive.fo\",\n  \".archive.is\",\n  \"||archive.is\",\n  \".archive.li\",\n  \"||archive.li\",\n  \"||archive.org\",\n  \"||archive.ph\",\n  \"archive.today\",\n  \"|https://archive.today\",\n  \"||archiveofourown.com\",\n  \"||archiveofourown.org\",\n  \".arctosia.com\",\n  \"|http://arctosia.com\",\n  \"||areca-backup.org\",\n  \".arethusa.su\",\n  \"||arethusa.su\",\n  \"||arlingtoncemetery.mil\",\n  \"||army.mil\",\n  \".art4tibet1998.org\",\n  \"artofpeacefoundation.org\",\n  \"artsy.net\",\n  \"||asacp.org\",\n  \"asdfg.jp/dabr\",\n  \"asg.to\",\n  \".asia-gaming.com\",\n  \".asiaharvest.org\",\n  \"||asiaharvest.org\",\n  \"||asianage.com\",\n  \"||asianews.it\",\n  \"|http://japanfirst.asianfreeforum.com/\",\n  \"||asiansexdiary.com\",\n  \"||asianwomensfilm.de\",\n  \".asiatgp.com\",\n  \".asiatoday.us\",\n  \"||askstudent.com\",\n  \".askynz.net\",\n  \"||askynz.net\",\n  \"||aspi.org.au\",\n  \"||aspistrategist.org.au\",\n  \"||assembla.com\",\n  \"||astrill.com\",\n  \"||atc.org.au\",\n  \".atchinese.com\",\n  \"|http://atchinese.com\",\n  \"atgfw.org\",\n  \".atlaspost.com\",\n  \"||atlaspost.com\",\n  \"||atdmt.com\",\n  \".atlanta168.com\",\n  \"||atlanta168.com\",\n  \".atnext.com\",\n  \"||atnext.com\",\n  \"ice.audionow.com\",\n  \".av.com\",\n  \"||av.movie\",\n  \".av-e-body.com\",\n  \"avaaz.org\",\n  \"||avaaz.org\",\n  \".avbody.tv\",\n  \".avcity.tv\",\n  \".avcool.com\",\n  \".avdb.in\",\n  \"||avdb.in\",\n  \".avdb.tv\",\n  \"||avdb.tv\",\n  \".avfantasy.com\",\n  \"||avg.com\",\n  \".avgle.com\",\n  \"||avgle.com\",\n  \"||avidemux.org\",\n  \"||avoision.com\",\n  \".avyahoo.com\",\n  \"||axios.com\",\n  \"||axureformac.com\",\n  \".azerbaycan.tv\",\n  \"azerimix.com\",\n  \"boxun*.azurewebsites.net\",\n  \"||boxun*.azurewebsites.net\",\n  \"||b-ok.cc\",\n  \"forum.baby-kingdom.com\",\n  \"||babylonbee.com\",\n  \"babynet.com.hk\",\n  \"backchina.com\",\n  \"||backchina.com\",\n  \".backpackers.com.tw/forum\",\n  \"backtotiananmen.com\",\n  \".badiucao.com\",\n  \"||badiucao.com\",\n  \".badjojo.com\",\n  \"badoo.com\",\n  \"|http://*2.bahamut.com.tw\",\n  \"||baidu.jp\",\n  \".baijie.org\",\n  \"|http://baijie.org\",\n  \"||bailandaily.com\",\n  \"||baixing.me\",\n  \"||bakgeekhome.tk\",\n  \".banana-vpn.com\",\n  \"||banana-vpn.com\",\n  \".band.us\",\n  \"||bandcamp.com\",\n  \".bandwagonhost.com\",\n  \"||bandwagonhost.com\",\n  \".bangbrosnetwork.com\",\n  \".bangchen.net\",\n  \"|http://bangchen.net\",\n  \"||bangkokpost.com\",\n  \"||bangyoulater.com\",\n  \"bannedbook.org\",\n  \"||bannedbook.org\",\n  \".bannednews.org\",\n  \".baramangaonline.com\",\n  \"|http://baramangaonline.com\",\n  \".barenakedislam.com\",\n  \"||barnabu.co.uk\",\n  \"||barton.de\",\n  \".bastillepost.com\",\n  \"||bastillepost.com\",\n  \"bayvoice.net\",\n  \"||bayvoice.net\",\n  \"dajusha.baywords.com\",\n  \"||bbchat.tv\",\n  \"||bb-chat.tv\",\n  \".bbg.gov\",\n  \".bbkz.com/forum\",\n  \".bbnradio.org\",\n  \"bbs-tw.com\",\n  \".bbsdigest.com/thread\",\n  \"||bbsfeed.com\",\n  \"bbsland.com\",\n  \".bbsmo.com\",\n  \".bbsone.com\",\n  \"bbtoystore.com\",\n  \".bcast.co.nz\",\n  \".bcc.com.tw/board\",\n  \".bcchinese.net\",\n  \".bcmorning.com\",\n  \"bdsmvideos.net\",\n  \".beaconevents.com\",\n  \".bebo.com\",\n  \"||bebo.com\",\n  \".beevpn.com\",\n  \"||beevpn.com\",\n  \".behindkink.com\",\n  \"||beijing1989.com\",\n  \"beijingspring.com\",\n  \"||beijingspring.com\",\n  \".beijingzx.org\",\n  \"|http://beijingzx.org\",\n  \".belamionline.com\",\n  \".bell.wiki\",\n  \"|http://bell.wiki\",\n  \"bemywife.cc\",\n  \"beric.me\",\n  \"||berlinerbericht.de\",\n  \".berlintwitterwall.com\",\n  \"||berlintwitterwall.com\",\n  \".berm.co.nz\",\n  \".bestforchina.org\",\n  \"||bestforchina.org\",\n  \".bestgore.com\",\n  \".bestpornstardb.com\",\n  \"||bestvpn.com\",\n  \".bestvpnanalysis.com\",\n  \".bestvpnserver.com\",\n  \".bestvpnservice.com\",\n  \".bestvpnusa.com\",\n  \"||bet365.com\",\n  \".betfair.com\",\n  \"||betternet.co\",\n  \".bettervpn.com\",\n  \"||bettervpn.com\",\n  \".bettween.com\",\n  \"||bettween.com\",\n  \"||betvictor.com\",\n  \".bewww.net\",\n  \".beyondfirewall.com\",\n  \"||bfnn.org\",\n  \"||bfsh.hk\",\n  \".bgvpn.com\",\n  \"||bgvpn.com\",\n  \".bianlei.com\",\n  \"@@||bianlei.com\",\n  \"biantailajiao.com\",\n  \"biantailajiao.in\",\n  \".biblesforamerica.org\",\n  \"|http://biblesforamerica.org\",\n  \".bic2011.org\",\n  \"||biedian.me\",\n  \"bigfools.com\",\n  \"||bigjapanesesex.com\",\n  \".bignews.org\",\n  \"||bignews.org\",\n  \".bigsound.org\",\n  \"||bild.de\",\n  \".biliworld.com\",\n  \"|http://biliworld.com\",\n  \"|http://billypan.com/wiki\",\n  \".binux.me\",\n  \"ai.binwang.me/couplet\",\n  \".bit.do\",\n  \"|http://bit.do\",\n  \".bit.ly\",\n  \"|http://bit.ly\",\n  \"||bitchute.com\",\n  \"||bitcointalk.org\",\n  \".bitshare.com\",\n  \"||bitshare.com\",\n  \"bitsnoop.com\",\n  \".bitvise.com\",\n  \"||bitvise.com\",\n  \"bizhat.com\",\n  \"||bl-doujinsouko.com\",\n  \".bjnewlife.org\",\n  \".bjs.org\",\n  \"bjzc.org\",\n  \"||bjzc.org\",\n  \".blacklogic.com\",\n  \".blackvpn.com\",\n  \"||blackvpn.com\",\n  \"blewpass.com\",\n  \"tor.blingblingsquad.net\",\n  \".blinkx.com\",\n  \"||blinkx.com\",\n  \"blinw.com\",\n  \".blip.tv\",\n  \"||blip.tv/\",\n  \".blockcn.com\",\n  \"||blockcn.com\",\n  \"||blockless.com\",\n  \"||blog.de\",\n  \".blog.jp\",\n  \"|http://blog.jp\",\n  \"@@||jpush.cn\",\n  \".blogcatalog.com\",\n  \"||blogcatalog.com\",\n  \"||blogcity.me\",\n  \".blogger.com\",\n  \"||blogger.com\",\n  \"blogimg.jp\",\n  \"||blog.kangye.org\",\n  \".bloglines.com\",\n  \"||bloglines.com\",\n  \"||bloglovin.com\",\n  \"rconversation.blogs.com\",\n  \"blogtd.net\",\n  \".blogtd.org\",\n  \"|http://blogtd.org\",\n  \"||bloodshed.net\",\n  \"||assets.bwbx.io\",\n  \"||bloomfortune.com\",\n  \"blueangellive.com\",\n  \".bmfinn.com\",\n  \".bnews.co\",\n  \"||bnews.co\",\n  \"||bnrmetal.com\",\n  \"boardreader.com/thread\",\n  \"||boardreader.com\",\n  \".bod.asia\",\n  \"|http://bod.asia\",\n  \".bodog88.com\",\n  \".bolehvpn.net\",\n  \"||bolehvpn.net\",\n  \"bonbonme.com\",\n  \".bonbonsex.com\",\n  \".bonfoundation.org\",\n  \".bongacams.com\",\n  \"||boobstagram.com\",\n  \"||book.com.tw\",\n  \"bookepub.com\",\n  \"||books.com.tw\",\n  \"||botanwang.com\",\n  \".bot.nu\",\n  \".bowenpress.com\",\n  \"||bowenpress.com\",\n  \"||app.box.com\",\n  \"dl.box.net\",\n  \"||dl.box.net\",\n  \".boxpn.com\",\n  \"||boxpn.com\",\n  \"boxun.com\",\n  \"||boxun.com\",\n  \".boxun.tv\",\n  \"||boxun.tv\",\n  \"boxunblog.com\",\n  \"||boxunblog.com\",\n  \".boxunclub.com\",\n  \"boyangu.com\",\n  \".boyfriendtv.com\",\n  \".boysfood.com\",\n  \"||br.st\",\n  \".brainyquote.com/quotes/authors/d/dalai_lama\",\n  \"||brandonhutchinson.com\",\n  \"||braumeister.org\",\n  \"||brave.com\",\n  \".bravotube.net\",\n  \"||bravotube.net\",\n  \".brazzers.com\",\n  \"||brazzers.com\",\n  \".break.com\",\n  \"||break.com\",\n  \"breakgfw.com\",\n  \"||breakgfw.com\",\n  \"breaking911.com\",\n  \".breakingtweets.com\",\n  \"||breakingtweets.com\",\n  \"||breakwall.net\",\n  \"briian.com/6511/freegate\",\n  \".briefdream.com/%E7%B4%A0%E6%A3%BA\",\n  \"brizzly.com\",\n  \"||brizzly.com\",\n  \"||brkmd.com\",\n  \"broadbook.com\",\n  \".broadpressinc.com\",\n  \"||broadpressinc.com\",\n  \"bbs.brockbbs.com\",\n  \"||brookings.edu\",\n  \"brucewang.net\",\n  \".brutaltgp.com\",\n  \"||brutaltgp.com\",\n  \".bt2mag.com\",\n  \"||bt95.com\",\n  \".btaia.com\",\n  \".btbtav.com\",\n  \"|http://btdigg.org\",\n  \".btku.me\",\n  \"||btku.me\",\n  \"||btku.org\",\n  \".btspread.com\",\n  \".btsynckeys.com\",\n  \".budaedu.org\",\n  \"||budaedu.org\",\n  \".buddhanet.com.tw/zfrop/tibet\",\n  \".buddhistchannel.tv\",\n  \".buffered.com\",\n  \"|http://buffered.com\",\n  \"||bullguard.com\",\n  \".bullog.org\",\n  \"||bullog.org\",\n  \".bullogger.com\",\n  \"||bullogger.com\",\n  \"||bunbunhk.com\",\n  \".busayari.com\",\n  \"|http://busayari.com\",\n  \"||business-humanrights.org\",\n  \".businessinsider.com/bing-could-be-censoring-search-results-2014\",\n  \".businessinsider.com/china-banks-preparing-for-debt-implosion-2014\",\n  \".businessinsider.com/hong-kong-activists-defy-police-tear-gas-as-protests-continue-overnight-2014\",\n  \".businessinsider.com/internet-outages-reported-in-north-korea-2014\",\n  \".businessinsider.com/iphone-6-is-approved-for-sale-in-china-2014\",\n  \".businessinsider.com/nfl-announcers-surface-tablets-2014\",\n  \".businessinsider.com/panama-papers\",\n  \".businessinsider.com/umbrella-man-hong-kong-2014\",\n  \"|http://www.businessinsider.com.au/*\",\n  \".businesstoday.com.tw\",\n  \"||businesstoday.com.tw\",\n  \".busu.org/news\",\n  \"|http://busu.org/news\",\n  \"busytrade.com\",\n  \".buugaa.com\",\n  \".buzzhand.com\",\n  \".buzzhand.net\",\n  \".buzzorange.com\",\n  \"||buzzorange.com\",\n  \"||bvpn.com\",\n  \"||bwh1.net\",\n  \"bwsj.hk\",\n  \"||bx.tl\",\n  \"||bypasscensorship.org\",\n  \"||c-span.org\",\n  \".c-spanvideo.org\",\n  \"||c-spanvideo.org\",\n  \"||c-est-simple.com\",\n  \".c100tibet.org\",\n  \"||cablegatesearch.net\",\n  \".cachinese.com\",\n  \".cacnw.com\",\n  \"|http://cacnw.com\",\n  \".cactusvpn.com\",\n  \"||cactusvpn.com\",\n  \".cafepress.com\",\n  \".cahr.org.tw\",\n  \".caijinglengyan.com\",\n  \"||caijinglengyan.com\",\n  \".calameo.com/books\",\n  \".calgarychinese.ca\",\n  \".calgarychinese.com\",\n  \".calgarychinese.net\",\n  \"|http://blog.calibre-ebook.com\",\n  \"falun.caltech.edu\",\n  \".its.caltech.edu/~falun/\",\n  \".cam4.com\",\n  \".cam4.jp\",\n  \".cam4.sg\",\n  \".camfrog.com\",\n  \"||camfrog.com\",\n  \"||campaignforuyghurs.org\",\n  \"||cams.com\",\n  \".cams.org.sg\",\n  \"canadameet.com\",\n  \".canalporno.com\",\n  \"|http://bbs.cantonese.asia/\",\n  \".canyu.org\",\n  \"||canyu.org\",\n  \".cao.im\",\n  \".caobian.info\",\n  \"||caobian.info\",\n  \"caochangqing.com\",\n  \"||caochangqing.com\",\n  \".cap.org.hk\",\n  \"||cap.org.hk\",\n  \".carabinasypistolas.com\",\n  \"cardinalkungfoundation.org\",\n  \"||posts.careerengine.us\",\n  \"carmotorshow.com\",\n  \"||carrd.co\",\n  \"ss.carryzhou.com\",\n  \".cartoonmovement.com\",\n  \"||cartoonmovement.com\",\n  \".casadeltibetbcn.org\",\n  \".casatibet.org.mx\",\n  \"|http://casatibet.org.mx\",\n  \".cari.com.my\",\n  \"||cari.com.my\",\n  \"||caribbeancom.com\",\n  \".casinoking.com\",\n  \".casinoriva.com\",\n  \"||catch22.net\",\n  \".catchgod.com\",\n  \"|http://catchgod.com\",\n  \"||catfightpayperview.xxx\",\n  \".catholic.org.hk\",\n  \"||catholic.org.hk\",\n  \"catholic.org.tw\",\n  \"||catholic.org.tw\",\n  \".cathvoice.org.tw\",\n  \"||cato.org\",\n  \"||cattt.com\",\n  \".cbc.ca\",\n  \"||cbc.ca\",\n  \".cbsnews.com/video\",\n  \".cbtc.org.hk\",\n  \"||southpark.cc.com\",\n  \"||cccat.cc\",\n  \"||cccat.co\",\n  \".ccdtr.org\",\n  \"||ccdtr.org\",\n  \".cchere.com\",\n  \"||cchere.com\",\n  \".ccim.org\",\n  \".cclife.ca\",\n  \"cclife.org\",\n  \"||cclife.org\",\n  \"cclifefl.org\",\n  \"||cclifefl.org\",\n  \".ccthere.com\",\n  \"||ccthere.com\",\n  \"||ccthere.net\",\n  \".cctmweb.net\",\n  \".cctongbao.com/article/2078732\",\n  \"ccue.ca\",\n  \"ccue.com\",\n  \".ccvoice.ca\",\n  \".ccw.org.tw\",\n  \".cgdepot.org\",\n  \"|http://cgdepot.org\",\n  \"||cdbook.org\",\n  \".cdcparty.com\",\n  \".cdef.org\",\n  \"||cdef.org\",\n  \"||cdig.info\",\n  \"cdjp.org\",\n  \"||cdjp.org\",\n  \".cdn-apple.com\",\n  \"||cdn-apple.com\",\n  \".cdnews.com.tw\",\n  \"cdp1989.org\",\n  \"cdp1998.org\",\n  \"||cdp1998.org\",\n  \"cdp2006.org\",\n  \"||cdp2006.org\",\n  \".cdpa.url.tw\",\n  \"cdpeu.org\",\n  \"cdpusa.org\",\n  \"cdpweb.org\",\n  \"||cdpweb.org\",\n  \"cdpwu.org\",\n  \"||cdpwu.org\",\n  \"||cdw.com\",\n  \".cecc.gov\",\n  \"||cecc.gov\",\n  \"||cellulo.info\",\n  \"||cenews.eu\",\n  \"||centerforhumanreprod.com\",\n  \"||centralnation.com\",\n  \".centurys.net\",\n  \"|http://centurys.net\",\n  \".cfhks.org.hk\",\n  \".cfos.de\",\n  \"||cfr.org\",\n  \".cftfc.com\",\n  \".cgst.edu\",\n  \".change.org\",\n  \"||change.org\",\n  \".changp.com\",\n  \"||changp.com\",\n  \".changsa.net\",\n  \"|http://changsa.net\",\n  \"||channelnewsasia.com\",\n  \".chapm25.com\",\n  \".chaturbate.com\",\n  \"||chaturbate.com\",\n  \".chuang-yen.org\",\n  \"||checkgfw.com\",\n  \"chengmingmag.com\",\n  \".chenguangcheng.com\",\n  \"||chenguangcheng.com\",\n  \".chenpokong.com\",\n  \"||chenpokong.com\",\n  \".chenpokong.net\",\n  \"|http://chenpokong.net\",\n  \"||chenpokongvip.com\",\n  \"||cherrysave.com\",\n  \".chhongbi.org\",\n  \"chicagoncmtv.com\",\n  \"|http://chicagoncmtv.com\",\n  \".china-week.com\",\n  \"china101.com\",\n  \"||china101.com\",\n  \"||china18.org\",\n  \"||china21.com\",\n  \"china21.org\",\n  \"||china21.org\",\n  \".china5000.us\",\n  \"chinaaffairs.org\",\n  \"||chinaaffairs.org\",\n  \"||chinaaid.me\",\n  \"chinaaid.us\",\n  \"chinaaid.org\",\n  \"chinaaid.net\",\n  \"||chinaaid.net\",\n  \"chinacomments.org\",\n  \"||chinacomments.org\",\n  \".chinachange.org\",\n  \"||chinachange.org\",\n  \"chinachannel.hk\",\n  \"||chinachannel.hk\",\n  \".chinacitynews.be\",\n  \".chinadialogue.net\",\n  \".chinadigitaltimes.net\",\n  \"||chinadigitaltimes.net\",\n  \".chinaelections.org\",\n  \"||chinaelections.org\",\n  \".chinaeweekly.com\",\n  \"||chinaeweekly.com\",\n  \"||chinafreepress.org\",\n  \".chinagate.com\",\n  \"chinageeks.org\",\n  \"chinagfw.org\",\n  \"||chinagfw.org\",\n  \".chinagonet.com\",\n  \".chinagreenparty.org\",\n  \"||chinagreenparty.org\",\n  \".chinahorizon.org\",\n  \"||chinahorizon.org\",\n  \".chinahush.com\",\n  \".chinainperspective.com\",\n  \"||chinainterimgov.org\",\n  \"chinalaborwatch.org\",\n  \"chinalawtranslate.com\",\n  \".chinapost.com.tw/taiwan/national/national-news\",\n  \"chinaxchina.com/howto\",\n  \"chinalawandpolicy.com\",\n  \".chinamule.com\",\n  \"||chinamule.com\",\n  \"chinamz.org\",\n  \".chinanewscenter.com\",\n  \"|https://chinanewscenter.com\",\n  \".chinapress.com.my\",\n  \"||chinapress.com.my\",\n  \".china-review.com.ua\",\n  \"|http://china-review.com.ua\",\n  \".chinarightsia.org\",\n  \"chinasmile.net/forums\",\n  \"chinasocialdemocraticparty.com\",\n  \"||chinasocialdemocraticparty.com\",\n  \"chinasoul.org\",\n  \"||chinasoul.org\",\n  \".chinasucks.net\",\n  \"||chinatopsex.com\",\n  \".chinatown.com.au\",\n  \"chinatweeps.com\",\n  \"chinaway.org\",\n  \".chinaworker.info\",\n  \"||chinaworker.info\",\n  \"chinayouth.org.hk\",\n  \"chinayuanmin.org\",\n  \"||chinayuanmin.org\",\n  \".chinese-hermit.net\",\n  \"chinese-leaders.org\",\n  \"chinese-memorial.org\",\n  \".chinesedaily.com\",\n  \"||chinesedailynews.com\",\n  \".chinesedemocracy.com\",\n  \"||chinesedemocracy.com\",\n  \"||chinesegay.org\",\n  \".chinesen.de\",\n  \"||chinesen.de\",\n  \".chinesenews.net.au/\",\n  \".chinesepen.org\",\n  \"||chineseradioseattle.com\",\n  \".chinesetalks.net/ch\",\n  \"||chineseupress.com\",\n  \".chingcheong.com\",\n  \"||chingcheong.com\",\n  \".chinman.net\",\n  \"|http://chinman.net\",\n  \"chithu.org\",\n  \"||cnnews.chosun.com\",\n  \".chrdnet.com\",\n  \"|http://chrdnet.com\",\n  \".christianfreedom.org\",\n  \"||christianfreedom.org\",\n  \"christianstudy.com\",\n  \"||christianstudy.com\",\n  \"christusrex.org/www1/sdc\",\n  \".chubold.com\",\n  \"chubun.com\",\n  \"||christiantimes.org.hk\",\n  \".chrlawyers.hk\",\n  \"||chrlawyers.hk\",\n  \".churchinhongkong.org/b5/index.php\",\n  \"|http://churchinhongkong.org/b5/index.php\",\n  \".chushigangdrug.ch\",\n  \".cienen.com\",\n  \".cineastentreff.de\",\n  \".cipfg.org\",\n  \"||circlethebayfortibet.org\",\n  \"||cirosantilli.com\",\n  \".citizencn.com\",\n  \"||citizencn.com\",\n  \"||citizenlab.ca\",\n  \"||citizenlab.org\",\n  \"||citizenscommission.hk\",\n  \".citizenlab.org\",\n  \"citizensradio.org\",\n  \".city365.ca\",\n  \"|http://city365.ca\",\n  \"city9x.com\",\n  \"||citypopulation.de\",\n  \".citytalk.tw/event\",\n  \".civicparty.hk\",\n  \"||civicparty.hk\",\n  \".civildisobediencemovement.org\",\n  \"civilhrfront.org\",\n  \"||civilhrfront.org\",\n  \".civiliangunner.com\",\n  \".civilmedia.tw\",\n  \"||civilmedia.tw\",\n  \"psiphon.civisec.org\",\n  \"||vpn.cjb.net\",\n  \".ck101.com\",\n  \"||ck101.com\",\n  \".clarionproject.org/news/islamic-state-isis-isil-propaganda\",\n  \"||classicalguitarblog.net\",\n  \".clb.org.hk\",\n  \"clearharmony.net\",\n  \"clearwisdom.net\",\n  \"||clinica-tibet.ru\",\n  \".clipfish.de\",\n  \"cloakpoint.com\",\n  \"||app.cloudcone.com\",\n  \"||club1069.com\",\n  \"||clubhouseapi.com\",\n  \"cmi.org.tw\",\n  \"|http://www.cmoinc.org\",\n  \"cmp.hku.hk\",\n  \"hkupop.hku.hk\",\n  \"||cmule.com\",\n  \"||cmule.org\",\n  \"||cms.gov\",\n  \"|http://vpn.cmu.edu\",\n  \"|http://vpn.sv.cmu.edu\",\n  \".cn6.eu\",\n  \".cna.com.tw\",\n  \"||cna.com.tw\",\n  \".cnabc.com\",\n  \".cnd.org\",\n  \"||cnd.org\",\n  \"download.cnet.com\",\n  \".cnex.org.cn\",\n  \".cnineu.com\",\n  \"wiki.cnitter.com\",\n  \".cnn.com/video\",\n  \".cnpolitics.org\",\n  \"||cnpolitics.org\",\n  \".cn-proxy.com\",\n  \"|http://cn-proxy.com\",\n  \".cnproxy.com\",\n  \"blog.cnyes.com\",\n  \"news.cnyes.com\",\n  \"||coat.co.jp\",\n  \".cochina.co\",\n  \"||cochina.co\",\n  \"||cochina.org\",\n  \".code1984.com/64\",\n  \"|http://goagent.codeplex.com\",\n  \"||codeshare.io\",\n  \"||codeskulptor.org\",\n  \"||conoha.jp\",\n  \"|http://tosh.comedycentral.com\",\n  \"comefromchina.com\",\n  \"||comefromchina.com\",\n  \".comic-mega.me\",\n  \"commandarms.com\",\n  \"||commentshk.com\",\n  \".communistcrimes.org\",\n  \"||communistcrimes.org\",\n  \"||communitychoicecu.com\",\n  \"||comparitech.com\",\n  \"||compileheart.com\",\n  \"||conoha.jp\",\n  \".contactmagazine.net\",\n  \".convio.net\",\n  \".coobay.com\",\n  \"|http://www.cool18.com/bbs*/\",\n  \".coolaler.com\",\n  \"||coolaler.com\",\n  \"coolder.com\",\n  \"||coolder.com\",\n  \"||coolloud.org.tw\",\n  \".coolncute.com\",\n  \"||coolstuffinc.com\",\n  \"corumcollege.com\",\n  \".cos-moe.com\",\n  \"|http://cos-moe.com\",\n  \".cosplayjav.pl\",\n  \"|http://cosplayjav.pl\",\n  \".cotweet.com\",\n  \"||cotweet.com\",\n  \".coursehero.com\",\n  \"||coursehero.com\",\n  \"cpj.org\",\n  \"||cpj.org\",\n  \".cq99.us\",\n  \"|http://cq99.us\",\n  \"crackle.com\",\n  \"||crackle.com\",\n  \".crazys.cc\",\n  \".crazyshit.com\",\n  \"||crazyshit.com\",\n  \"||crchina.org\",\n  \"crd-net.org\",\n  \"creaders.net\",\n  \"||creaders.net\",\n  \".creadersnet.com\",\n  \"||cristyli.com\",\n  \".crocotube.com\",\n  \"|http://crocotube.com\",\n  \".crossthewall.net\",\n  \"||crossthewall.net\",\n  \".crossvpn.net\",\n  \"||crossvpn.net\",\n  \"||crucial.com\",\n  \"||blog.cryptographyengineering.com\",\n  \"csdparty.com\",\n  \"||csdparty.com\",\n  \"||csis.org\",\n  \"||csmonitor.com\",\n  \"||csuchen.de\",\n  \".csw.org.uk\",\n  \".ct.org.tw\",\n  \"||ct.org.tw\",\n  \".ctao.org\",\n  \".ctfriend.net\",\n  \".ctitv.com.tw\",\n  \"||ctowc.org\",\n  \".cts.com.tw\",\n  \"||cts.com.tw\",\n  \"||ctwant.com\",\n  \"|http://library.usc.cuhk.edu.hk/\",\n  \"|http://mjlsh.usc.cuhk.edu.hk/\",\n  \".cuhkacs.org/~benng\",\n  \".cuihua.org\",\n  \"||cuihua.org\",\n  \".cuiweiping.net\",\n  \"||cuiweiping.net\",\n  \"||culture.tw\",\n  \".cumlouder.com\",\n  \"||cumlouder.com\",\n  \"||curvefish.com\",\n  \"||cusp.hk\",\n  \".cusu.hk\",\n  \"||cusu.hk\",\n  \".cutscenes.net\",\n  \"||cutscenes.net\",\n  \".cw.com.tw\",\n  \"||cw.com.tw\",\n  \"|http://forum.cyberctm.com\",\n  \"cyberghostvpn.com\",\n  \"||cyberghostvpn.com\",\n  \"||cynscribe.com\",\n  \"cytode.us\",\n  \"||ifan.cz.cc\",\n  \"||mike.cz.cc\",\n  \"||nic.cz.cc\",\n  \".d-fukyu.com\",\n  \"|http://d-fukyu.com\",\n  \"cl.d0z.net\",\n  \".d100.net\",\n  \"||d100.net\",\n  \".d2bay.com\",\n  \"|http://d2bay.com\",\n  \".dabr.co.uk\",\n  \"||dabr.co.uk\",\n  \"dabr.eu\",\n  \"dabr.mobi\",\n  \"||dabr.mobi\",\n  \"||dabr.me\",\n  \"dadazim.com\",\n  \"||dadazim.com\",\n  \".dadi360.com\",\n  \".dafabet.com\",\n  \"dafagood.com\",\n  \"dafahao.com\",\n  \".dafoh.org\",\n  \".daftporn.com\",\n  \".dagelijksestandaard.nl\",\n  \".daidostup.ru\",\n  \"|http://daidostup.ru\",\n  \".dailidaili.com\",\n  \"||dailidaili.com\",\n  \"||dailymail.co.uk\",\n  \".dailymotion.com\",\n  \"||dailymotion.com\",\n  \"||dailysabah.com\",\n  \"daiphapinfo.net\",\n  \".dajiyuan.com\",\n  \"||dajiyuan.de\",\n  \"dajiyuan.eu\",\n  \"dalailama.com\",\n  \".dalailama.mn\",\n  \"|http://dalailama.mn\",\n  \".dalailama.ru\",\n  \"||dalailama.ru\",\n  \"dalailama80.org\",\n  \".dalailama-archives.org\",\n  \".dalailamacenter.org\",\n  \"|http://dalailamacenter.org\",\n  \"dalailamafellows.org\",\n  \".dalailamafilm.com\",\n  \".dalailamafoundation.org\",\n  \".dalailamahindi.com\",\n  \".dalailamainaustralia.org\",\n  \".dalailamajapanese.com\",\n  \".dalailamaprotesters.info\",\n  \".dalailamaquotes.org\",\n  \".dalailamatrust.org\",\n  \".dalailamavisit.org.nz\",\n  \".dalailamaworld.com\",\n  \"||dalailamaworld.com\",\n  \"dalianmeng.org\",\n  \"||dalianmeng.org\",\n  \".daliulian.org\",\n  \"||daliulian.org\",\n  \".danke4china.net\",\n  \"||danke4china.net\",\n  \".danwei.org\",\n  \"daolan.net\",\n  \".daozhongxing.org\",\n  \"darktoy.net\",\n  \"||dastrassi.org\",\n  \"||daum.net\",\n  \".david-kilgour.com\",\n  \"|http://david-kilgour.com\",\n  \"daxa.cn\",\n  \"||daxa.cn\",\n  \"cn.dayabook.com\",\n  \".daylife.com/topic/dalai_lama\",\n  \"||db.tt\",\n  \".dbc.hk/main\",\n  \"||dbgjd.com\",\n  \"||dcard.tw\",\n  \"dcmilitary.com\",\n  \".ddc.com.tw\",\n  \".ddhw.info\",\n  \"||de-sci.org\",\n  \".de-sci.org\",\n  \"||deadline.com\",\n  \"||decodet.co\",\n  \".definebabe.com\",\n  \"||delcamp.net\",\n  \"delicious.com/GFWbookmark\",\n  \".democrats.org\",\n  \"||democrats.org\",\n  \".demosisto.hk\",\n  \"||demosisto.hk\",\n  \"||desc.se\",\n  \"||dessci.com\",\n  \".destroy-china.jp\",\n  \"||deutsche-welle.de\",\n  \"||deviantart.com\",\n  \"||deviantart.net\",\n  \"||devio.us\",\n  \"||devpn.com\",\n  \"||dfas.mil\",\n  \"dfn.org\",\n  \"dharmakara.net\",\n  \".dharamsalanet.com\",\n  \".diaoyuislands.org\",\n  \"||diaoyuislands.org\",\n  \".difangwenge.org\",\n  \"|http://digiland.tw/\",\n  \"||digitalnomadsproject.org\",\n  \".diigo.com\",\n  \"||diigo.com\",\n  \"||dilber.se\",\n  \"||furl.net\",\n  \".dipity.com\",\n  \"||directcreative.com\",\n  \".discuss.com.hk\",\n  \"||discuss.com.hk\",\n  \".discuss4u.com\",\n  \"disp.cc\",\n  \".disqus.com\",\n  \"||disqus.com\",\n  \".dit-inc.us\",\n  \"||dit-inc.us\",\n  \".dizhidizhi.com\",\n  \"||dizhuzhishang.com\",\n  \"djangosnippets.org\",\n  \".djorz.com\",\n  \"||djorz.com\",\n  \"||dl-laby.jp\",\n  \"||dlive.tv\",\n  \"||dlsite.com\",\n  \"||dlyoutube.com\",\n  \"||dmcdn.net\",\n  \".dnscrypt.org\",\n  \"||dnscrypt.org\",\n  \"||dns2go.com\",\n  \"||dnssec.net\",\n  \"doctorvoice.org\",\n  \".dogfartnetwork.com/tour\",\n  \"gloryhole.com\",\n  \".dojin.com\",\n  \".dok-forum.net\",\n  \"||dolc.de\",\n  \"||dolf.org.hk\",\n  \"||dollf.com\",\n  \".domain.club.tw\",\n  \".domaintoday.com.au\",\n  \"chinese.donga.com\",\n  \"dongtaiwang.com\",\n  \"||dongtaiwang.com\",\n  \".dongtaiwang.net\",\n  \"||dongtaiwang.net\",\n  \".dongyangjing.com\",\n  \"|http://danbooru.donmai.us\",\n  \".dontfilter.us\",\n  \"||dontmovetochina.com\",\n  \".dorjeshugden.com\",\n  \".dotplane.com\",\n  \"||dotplane.com\",\n  \"||dotsub.com\",\n  \".dotvpn.com\",\n  \"||dotvpn.com\",\n  \".doub.io\",\n  \"||doub.io\",\n  \"||dougscripts.com\",\n  \"||douhokanko.net\",\n  \"||doujincafe.com\",\n  \"dowei.org\",\n  \"|https://bartender.dowjones.com\",\n  \"dphk.org\",\n  \"dpp.org.tw\",\n  \"||dpp.org.tw\",\n  \"||dpr.info\",\n  \"||dragonsprings.org\",\n  \".dreamamateurs.com\",\n  \".drepung.org\",\n  \"||drgan.net\",\n  \".drmingxia.org\",\n  \"|http://drmingxia.org\",\n  \"||dropbooks.tv\",\n  \"||dropbox.com\",\n  \"||api.dropboxapi.com\",\n  \"||notify.dropboxapi.com\",\n  \"||dropboxusercontent.com\",\n  \"drsunacademy.com\",\n  \".drtuber.com\",\n  \".dscn.info\",\n  \"|http://dscn.info\",\n  \".dstk.dk\",\n  \"|http://dstk.dk\",\n  \"||dtiblog.com\",\n  \"||dtic.mil\",\n  \".dtwang.org\",\n  \".duanzhihu.com\",\n  \".duckdns.org\",\n  \"|http://duckdns.org\",\n  \".duckduckgo.com\",\n  \"||duckduckgo.com\",\n  \".duckload.com/download\",\n  \"||duckmylife.com\",\n  \".duga.jp\",\n  \"|http://duga.jp\",\n  \".duihua.org\",\n  \"||duihua.org\",\n  \"||duihuahrjournal.org\",\n  \".dunyabulteni.net\",\n  \".duoweitimes.com\",\n  \"||duoweitimes.com\",\n  \"duping.net\",\n  \"||duplicati.com\",\n  \"dupola.com\",\n  \"dupola.net\",\n  \".dushi.ca\",\n  \"||duyaoss.com\",\n  \"||dvorak.org\",\n  \".dw.com\",\n  \"||dw.com\",\n  \"||dw.de\",\n  \".dw-world.com\",\n  \"||dw-world.com\",\n  \".dw-world.de\",\n  \"|http://dw-world.de\",\n  \"www.dwheeler.com\",\n  \"dwnews.com\",\n  \"||dwnews.com\",\n  \"dwnews.net\",\n  \"||dwnews.net\",\n  \"xys.dxiong.com\",\n  \"||dynawebinc.com\",\n  \"||dysfz.cc\",\n  \".dzze.com\",\n  \"||e-classical.com.tw\",\n  \"||e-gold.com\",\n  \".e-gold.com\",\n  \".e-hentai.org\",\n  \"||e-hentai.org\",\n  \".e-hentaidb.com\",\n  \"|http://e-hentaidb.com\",\n  \"e-info.org.tw\",\n  \".e-traderland.net/board\",\n  \".e-zone.com.hk/discuz\",\n  \"|http://e-zone.com.hk/discuz\",\n  \".e123.hk\",\n  \"||e123.hk\",\n  \".earlytibet.com\",\n  \"|http://earlytibet.com\",\n  \".earthcam.com\",\n  \".earthvpn.com\",\n  \"||earthvpn.com\",\n  \"eastern-ark.com\",\n  \".easternlightning.org\",\n  \".eastturkestan.com\",\n  \"|http://www.eastturkistan.net/\",\n  \".eastturkistan-gov.org\",\n  \".eastturkistancc.org\",\n  \".eastturkistangovernmentinexile.us\",\n  \"||eastturkistangovernmentinexile.us\",\n  \".easyca.ca\",\n  \".easypic.com\",\n  \"||fnc.ebc.net.tw\",\n  \".ebony-beauty.com\",\n  \"ebookbrowse.com\",\n  \"ebookee.com\",\n  \"||ecfa.org.tw\",\n  \"ushuarencity.echainhost.com\",\n  \"||ecimg.tw\",\n  \"ecministry.net\",\n  \".economist.com\",\n  \"bbs.ecstart.com\",\n  \"edgecastcdn.net\",\n  \"||edgecastcdn.net\",\n  \"/twimg\\\\.edgesuite\\\\.net\\\\/\\\\/?appledaily/\",\n  \"edicypages.com\",\n  \".edmontonchina.cn\",\n  \".edmontonservice.com\",\n  \"edoors.com\",\n  \".edubridge.com\",\n  \"||edubridge.com\",\n  \".edupro.org\",\n  \"||eevpn.com\",\n  \"efcc.org.hk\",\n  \".efukt.com\",\n  \"|http://efukt.com\",\n  \"||eic-av.com\",\n  \"||eireinikotaerukai.com\",\n  \".eisbb.com\",\n  \".eksisozluk.com\",\n  \"||eksisozluk.com\",\n  \"electionsmeter.com\",\n  \"||elgoog.im\",\n  \".ellawine.org\",\n  \".elpais.com\",\n  \"||elpais.com\",\n  \".eltondisney.com\",\n  \".emaga.com/info/3407\",\n  \"emilylau.org.hk\",\n  \".emanna.com/chineseTraditional\",\n  \"bitc.bme.emory.edu/~lzhou/blogs\",\n  \".empfil.com\",\n  \".emule-ed2k.com\",\n  \"|http://emule-ed2k.com\",\n  \".emulefans.com\",\n  \"|http://emulefans.com\",\n  \".emuparadise.me\",\n  \".enanyang.my\",\n  \"||encrypt.me\",\n  \"||enewstree.com\",\n  \".enfal.de\",\n  \"chinese.engadget.com\",\n  \"||engagedaily.org\",\n  \"englishforeveryone.org\",\n  \"||englishfromengland.co.uk\",\n  \"englishpen.org\",\n  \".enlighten.org.tw\",\n  \"||entermap.com\",\n  \"||app.evozi.com\",\n  \".episcopalchurch.org\",\n  \".epochhk.com\",\n  \"|http://epochhk.com\",\n  \"epochtimes-bg.com\",\n  \"||epochtimes-bg.com\",\n  \"epochtimes-romania.com\",\n  \"||epochtimes-romania.com\",\n  \"epochtimes.co.il\",\n  \"||epochtimes.co.il\",\n  \"epochtimes.co.kr\",\n  \"||epochtimes.co.kr\",\n  \"epochtimes.com\",\n  \"||epochtimes.com\",\n  \".epochtimes.cz\",\n  \"epochtimes.de\",\n  \"epochtimes.fr\",\n  \".epochtimes.ie\",\n  \".epochtimes.it\",\n  \"epochtimes.jp\",\n  \"epochtimes.ru\",\n  \"epochtimes.se\",\n  \"epochtimestr.com\",\n  \".epochweek.com\",\n  \"||epochweek.com\",\n  \"||epochweekly.com\",\n  \".eporner.com\",\n  \".equinenow.com\",\n  \"erabaru.net\",\n  \".eracom.com.tw\",\n  \".eraysoft.com.tr\",\n  \".erepublik.com\",\n  \".erights.net\",\n  \"||erights.net\",\n  \".erktv.com\",\n  \"|http://erktv.com\",\n  \"||ernestmandel.org\",\n  \"||erodaizensyu.com\",\n  \"||erodoujinlog.com\",\n  \"||erodoujinworld.com\",\n  \"||eromanga-kingdom.com\",\n  \"||eromangadouzin.com\",\n  \".eromon.net\",\n  \"|http://eromon.net\",\n  \".eroprofile.com\",\n  \".eroticsaloon.net\",\n  \".eslite.com\",\n  \"||eslite.com\",\n  \"wiki.esu.im/%E8%9B%A4%E8%9B%A4%E8%AF%AD%E5%BD%95\",\n  \"||esu.dog\",\n  \".etaa.org.au\",\n  \".etadult.com\",\n  \"etaiwannews.com\",\n  \"||etizer.org\",\n  \"||etokki.com\",\n  \"||etsy.com\",\n  \".ettoday.net/news/20151216/614081\",\n  \"etvonline.hk\",\n  \".eu.org\",\n  \"||eu.org\",\n  \".eucasino.com\",\n  \".eulam.com\",\n  \".eurekavpt.com\",\n  \"||eurekavpt.com\",\n  \".euronews.com\",\n  \"||euronews.com\",\n  \"eeas.europa.eu/delegations/china/press_corner/all_news/news/2015/20150716_zh\",\n  \"eeas.europa.eu/statements-eeas/2015/151022\",\n  \".evschool.net\",\n  \"|http://evschool.net\",\n  \"||exblog.jp\",\n  \"||blog.exblog.co.jp\",\n  \"@@||www.exblog.jp\",\n  \".exchristian.hk\",\n  \"||exchristian.hk\",\n  \"|http://blog.excite.co.jp\",\n  \"||exhentai.org\",\n  \"||exmormon.org\",\n  \"||expatshield.com\",\n  \".expecthim.com\",\n  \"||expecthim.com\",\n  \"experts-univers.com\",\n  \"||exploader.net\",\n  \".expressvpn.com\",\n  \"||expressvpn.com\",\n  \".extremetube.com\",\n  \"eyevio.jp\",\n  \"||eyevio.jp\",\n  \".eyny.com\",\n  \"||eyny.com\",\n  \".ezpc.tk/category/soft\",\n  \".ezpeer.com\",\n  \"||facebookquotes4u.com\",\n  \".faceless.me\",\n  \"||faceless.me\",\n  \"|http://facesoftibetanselfimmolators.info\",\n  \"||facesofnyfw.com\",\n  \"||factpedia.org\",\n  \".faith100.org\",\n  \"|http://faith100.org\",\n  \".faithfuleye.com\",\n  \"||faiththedog.info\",\n  \".fakku.net\",\n  \"||fallenark.com\",\n  \".falsefire.com\",\n  \"||falsefire.com\",\n  \"falun-co.org\",\n  \"falunart.org\",\n  \"||falunasia.info\",\n  \"|http://falunau.org\",\n  \".falunaz.net\",\n  \"falundafa.org\",\n  \"falundafa-dc.org\",\n  \"||falundafa-florida.org\",\n  \"||falundafa-nc.org\",\n  \"||falundafa-pa.net\",\n  \"||falundafa-sacramento.org\",\n  \"falun-ny.net\",\n  \"||falundafaindia.org\",\n  \"falundafamuseum.org\",\n  \".falungong.club\",\n  \".falungong.de\",\n  \"falungong.org.uk\",\n  \"||falunhr.org\",\n  \"faluninfo.de\",\n  \"faluninfo.net\",\n  \".falunpilipinas.net\",\n  \"||falunworld.net\",\n  \"familyfed.org\",\n  \".fangeming.com\",\n  \"||fanglizhi.info\",\n  \"||fangong.org\",\n  \"fangongheike.com\",\n  \".fanqiang.tk\",\n  \"fanqianghou.com\",\n  \"||fanqianghou.com\",\n  \".fanqiangzhe.com\",\n  \"||fanqiangzhe.com\",\n  \"||fantv.hk\",\n  \"fapdu.com\",\n  \"faproxy.com\",\n  \".fawanghuihui.org\",\n  \"fanqiangyakexi.net\",\n  \"fail.hk\",\n  \"||famunion.com\",\n  \".fan-qiang.com\",\n  \".fangbinxing.com\",\n  \"||fangbinxing.com\",\n  \"fangeming.com\",\n  \".fangmincn.org\",\n  \"||fangmincn.org\",\n  \".fanhaodang.com\",\n  \"||fanqiang.network\",\n  \"||fanswong.com\",\n  \".fanyue.info\",\n  \".farwestchina.com\",\n  \"en.favotter.net\",\n  \"nytimes.map.fastly.net\",\n  \"||nytimes.map.fastly.net\",\n  \"||fast.wistia.com\",\n  \"||fastestvpn.com\",\n  \"||fastssh.com\",\n  \"||faststone.org\",\n  \"favstar.fm\",\n  \"||favstar.fm\",\n  \"faydao.com/weblog\",\n  \"||faz.net\",\n  \".fc2.com\",\n  \".fc2china.com\",\n  \".fc2cn.com\",\n  \"||fc2cn.com\",\n  \"fc2blog.net\",\n  \"|http://uygur.fc2web.com/\",\n  \"video.fdbox.com\",\n  \".fdc64.de\",\n  \".fdc64.org\",\n  \".fdc89.jp\",\n  \"||fourface.nodesnoop.com\",\n  \"||feeder.co\",\n  \"||feelssh.com\",\n  \"feer.com\",\n  \".feifeiss.com\",\n  \"|http://feitianacademy.org\",\n  \".feitian-california.org\",\n  \"||feixiaohao.com\",\n  \"||feministteacher.com\",\n  \".fengzhenghu.com\",\n  \"||fengzhenghu.com\",\n  \".fengzhenghu.net\",\n  \"||fengzhenghu.net\",\n  \".fevernet.com\",\n  \"|http://ff.im\",\n  \"fffff.at\",\n  \"fflick.com\",\n  \".ffvpn.com\",\n  \"fgmtv.net\",\n  \".fgmtv.org\",\n  \".fhreports.net\",\n  \"|http://fhreports.net\",\n  \".figprayer.com\",\n  \"||figprayer.com\",\n  \".fileflyer.com\",\n  \"||fileflyer.com\",\n  \"|http://feeds.fileforum.com\",\n  \".files2me.com\",\n  \".fileserve.com/file\",\n  \"fillthesquare.org\",\n  \"filmingfortibet.org\",\n  \".filthdump.com\",\n  \".finchvpn.com\",\n  \"||finchvpn.com\",\n  \"findmespot.com\",\n  \"||findyoutube.com\",\n  \"||findyoutube.net\",\n  \".fingerdaily.com\",\n  \"finler.net\",\n  \".firearmsworld.net\",\n  \"|http://firearmsworld.net\",\n  \".fireofliberty.org\",\n  \"||fireofliberty.org\",\n  \".firetweet.io\",\n  \"||firetweet.io\",\n  \"||firstpost.com\",\n  \".flagsonline.it\",\n  \"fleshbot.com\",\n  \".fleursdeslettres.com\",\n  \"|http://fleursdeslettres.com\",\n  \"||flgg.us\",\n  \"||flgjustice.org\",\n  \"||flickr.com\",\n  \"||staticflickr.com\",\n  \"flickrhivemind.net\",\n  \".flickriver.com\",\n  \".fling.com\",\n  \"||flipkart.com\",\n  \"||flog.tw\",\n  \".flyvpn.com\",\n  \"||flyvpn.com\",\n  \"|http://cn.fmnnow.com\",\n  \"fofldfradio.org\",\n  \"blog.foolsmountain.com\",\n  \".forum4hk.com\",\n  \"fangong.forums-free.com\",\n  \"pioneer-worker.forums-free.com\",\n  \"|https://ss*.4sqi.net\",\n  \"video.foxbusiness.com\",\n  \"|http://foxgay.com\",\n  \"||fringenetwork.com\",\n  \"||flecheinthepeche.fr\",\n  \".fochk.org\",\n  \"||fochk.org\",\n  \"||focustaiwan.tw\",\n  \".focusvpn.com\",\n  \"||fofg.org\",\n  \".fofg-europe.net\",\n  \".fooooo.com\",\n  \"||fooooo.com\",\n  \"||foreignaffairs.com\",\n  \".fotile.me\",\n  \"||fourthinternational.org\",\n  \"||foxdie.us\",\n  \"||foxsub.com\",\n  \"foxtang.com\",\n  \".fpmt.org\",\n  \"|http://fpmt.org\",\n  \".fpmt.tw\",\n  \".fpmt-osel.org\",\n  \"||fpmtmexico.org\",\n  \"fqok.org\",\n  \"||fqrouter.com\",\n  \"||franklc.com\",\n  \".freakshare.com\",\n  \"|http://freakshare.com\",\n  \"||free4u.com.ar\",\n  \"free-gate.org\",\n  \".free-hada-now.org\",\n  \"free-proxy.cz\",\n  \".free.fr/adsl\",\n  \"kineox.free.fr\",\n  \"tibetlibre.free.fr\",\n  \"||freealim.com\",\n  \"whitebear.freebearblog.org\",\n  \"||freebrowser.org\",\n  \".freechal.com\",\n  \".freedomchina.info\",\n  \"||freedomchina.info\",\n  \".freedomhouse.org\",\n  \"||freedomhouse.org\",\n  \".freedomsherald.org\",\n  \"||freedomsherald.org\",\n  \".freefq.com\",\n  \".freefuckvids.com\",\n  \".freegao.com\",\n  \"||freegao.com\",\n  \"freeilhamtohti.org\",\n  \"||freekazakhs.org\",\n  \".freekwonpyong.org\",\n  \"||saveliuxiaobo.com\",\n  \".freelotto.com\",\n  \"||freelotto.com\",\n  \"freeman2.com\",\n  \".freeopenvpn.com\",\n  \"freemoren.com\",\n  \"freemorenews.com\",\n  \"freemuse.org/archives/789\",\n  \"freenet-china.org\",\n  \"freenewscn.com\",\n  \"cn.freeones.com\",\n  \".freeoz.org/bbs\",\n  \"||freeoz.org\",\n  \"||freessh.us\",\n  \"free4u.com.ar\",\n  \".free-ssh.com\",\n  \"||free-ssh.com\",\n  \"||freebeacon.com\",\n  \".freechina.news\",\n  \"||freechinaforum.org\",\n  \"||freechinaweibo.com\",\n  \".freedomcollection.org/interviews/rebiya_kadeer\",\n  \".freeforums.org\",\n  \"||freenetproject.org\",\n  \".freeoz.org\",\n  \".freetibet.net\",\n  \"||freetibet.org\",\n  \".freetibetanheroes.org\",\n  \"|http://freetibetanheroes.org\",\n  \"||freetribe.me\",\n  \".freeviewmovies.com\",\n  \".freevpn.me\",\n  \"|http://freevpn.me\",\n  \"||freewallpaper4.me\",\n  \".freewebs.com\",\n  \".freewechat.com\",\n  \"||freewechat.com\",\n  \"freeweibo.com\",\n  \"||freeweibo.com\",\n  \".freexinwen.com\",\n  \".freeyoutubeproxy.net\",\n  \"||freeyoutubeproxy.net\",\n  \"friendfeed.com\",\n  \"friendfeed-media.com/e99a4ebe2fb4c1985c2a58775eb4422961aa5a2e\",\n  \"friends-of-tibet.org\",\n  \".friendsoftibet.org\",\n  \"freechina.net\",\n  \"|http://www.zensur.freerk.com/\",\n  \"freevpn.nl\",\n  \"freeyellow.com\",\n  \"hk.frienddy.com/hk\",\n  \"|http://adult.friendfinder.com/\",\n  \".fring.com\",\n  \"||fring.com\",\n  \".fromchinatousa.net\",\n  \"||frommel.net\",\n  \".frontlinedefenders.org\",\n  \"||frontlinedefenders.org\",\n  \".frootvpn.com\",\n  \"||frootvpn.com\",\n  \"||fscked.org\",\n  \".fsurf.com\",\n  \".ftv.com.tw\",\n  \"||ftv.com.tw\",\n  \"||ftvnews.com.tw\",\n  \"fucd.com\",\n  \".fuckcnnic.net\",\n  \"||fuckcnnic.net\",\n  \"fuckgfw.org\",\n  \".fulione.com\",\n  \"|https://fulione.com\",\n  \"||fullerconsideration.com\",\n  \"fulue.com\",\n  \".funf.tw\",\n  \"funp.com\",\n  \".fuq.com\",\n  \".furhhdl.org\",\n  \"||furinkan.com\",\n  \".futurechinaforum.org\",\n  \"||futuremessage.org\",\n  \".fux.com\",\n  \".fuyin.net\",\n  \".fuyindiantai.org\",\n  \".fuyu.org.tw\",\n  \"||fw.cm\",\n  \".fxcm-chinese.com\",\n  \"||fxcm-chinese.com\",\n  \"fzh999.com\",\n  \"fzh999.net\",\n  \"fzlm.com\",\n  \".g6hentai.com\",\n  \"|http://g6hentai.com\",\n  \"||g-queen.com\",\n  \"||gab.com\",\n  \"||gabocorp.com\",\n  \".gaeproxy.com\",\n  \".gaforum.org\",\n  \".gagaoolala.com\",\n  \"||gagaoolala.com\",\n  \".galaxymacau.com\",\n  \"||galenwu.com\",\n  \".galstars.net\",\n  \"||game735.com\",\n  \"gamebase.com.tw\",\n  \"gamejolt.com\",\n  \"|http://wiki.gamerp.jp\",\n  \"||gamer.com.tw\",\n  \".gamer.com.tw\",\n  \".gamez.com.tw\",\n  \"||gamez.com.tw\",\n  \".gamousa.com\",\n  \".gaoming.net\",\n  \"||gaoming.net\",\n  \"ganges.com\",\n  \".gaopi.net\",\n  \"|http://gaopi.net\",\n  \".gaozhisheng.org\",\n  \".gaozhisheng.net\",\n  \"gardennetworks.com\",\n  \"||gardennetworks.org\",\n  \"72.52.81.22\",\n  \"||gartlive.com\",\n  \"||gate-project.com\",\n  \"||gather.com\",\n  \".gatherproxy.com\",\n  \"gati.org.tw\",\n  \".gaybubble.com\",\n  \".gaycn.net\",\n  \".gayhub.com\",\n  \"||gaymap.cc\",\n  \".gaymenring.com\",\n  \".gaytube.com\",\n  \"||images-gaytube.com\",\n  \".gaywatch.com\",\n  \"|http://gaywatch.com\",\n  \".gazotube.com\",\n  \"||gazotube.com\",\n  \"||gcc.org.hk\",\n  \"||gclooney.com\",\n  \"||gclubs.com\",\n  \"||gcmasia.com\",\n  \".gcpnews.com\",\n  \"|http://gcpnews.com\",\n  \".gdbt.net/forum\",\n  \"gdzf.org\",\n  \"||geek-art.net\",\n  \"geekerhome.com/2010/03/xixiang-project-cross-gfw\",\n  \"||geekheart.info\",\n  \".gekikame.com\",\n  \"|http://gekikame.com\",\n  \".gelbooru.com\",\n  \"|http://gelbooru.com\",\n  \"||genius.com\",\n  \".geocities.co.jp\",\n  \".geocities.com/SiliconValley/Circuit/5683/download.html\",\n  \"hk.geocities.com\",\n  \"geocities.jp\",\n  \"||geph.io\",\n  \".gerefoundation.org\",\n  \"||getastrill.com\",\n  \".getchu.com\",\n  \".getcloak.com\",\n  \"||getcloak.com\",\n  \"||getfoxyproxy.org\",\n  \".getfreedur.com\",\n  \"||getgom.com\",\n  \".geti2p.net\",\n  \"||geti2p.net\",\n  \"getiton.com\",\n  \".getjetso.com/forum\",\n  \".getlantern.org\",\n  \"||getlantern.org\",\n  \"||getmalus.com\",\n  \".getsocialscope.com\",\n  \"||getsync.com\",\n  \"||gettr.com\",\n  \"gfbv.de\",\n  \".gfgold.com.hk\",\n  \".gfsale.com\",\n  \"||gfsale.com\",\n  \"gfw.org.ua\",\n  \".gfw.press\",\n  \"||gfw.press\",\n  \".ggssl.com\",\n  \"||ggssl.com\",\n  \".ghostpath.com\",\n  \"||ghostpath.com\",\n  \"||ghut.org\",\n  \".giantessnight.com\",\n  \"|http://giantessnight.com\",\n  \".gifree.com\",\n  \"||giga-web.jp\",\n  \"tw.gigacircle.com\",\n  \"|http://cn.giganews.com/\",\n  \"gigporno.ru\",\n  \"||girlbanker.com\",\n  \".git.io\",\n  \"||git.io\",\n  \"|http://softwaredownload.gitbooks.io\",\n  \"||github.blog\",\n  \"||github.com\",\n  \".github.io\",\n  \"||github.io\",\n  \"||githubusercontent.com\",\n  \"||githubassets.com\",\n  \".gizlen.net\",\n  \"||gizlen.net\",\n  \".gjczz.com\",\n  \"||gjczz.com\",\n  \"globaljihad.net\",\n  \"globalmediaoutreach.com\",\n  \"globalmuseumoncommunism.org\",\n  \"||globalrescue.net\",\n  \".globaltm.org\",\n  \".globalvoicesonline.org\",\n  \"||globalvoicesonline.org\",\n  \"||globalvpn.net\",\n  \".glock.com\",\n  \"gluckman.com/DalaiLama\",\n  \"gmbd.cn\",\n  \"||gmhz.org\",\n  \"|http://www.gmiddle.com\",\n  \"|http://www.gmiddle.net\",\n  \".gmll.org\",\n  \"||suche.gmx.net\",\n  \"||gnci.org.hk\",\n  \"||gnews.org\",\n  \"go-pki.com\",\n  \"||goagent.biz\",\n  \"||goagentplus.com\",\n  \"gobet.cc\",\n  \"godfootsteps.org\",\n  \"||godfootsteps.org\",\n  \"godns.work\",\n  \"godsdirectcontact.co.uk\",\n  \".godsdirectcontact.org\",\n  \"godsdirectcontact.org.tw\",\n  \".godsimmediatecontact.com\",\n  \"||gofundme.com\",\n  \".gogotunnel.com\",\n  \"||gohappy.com.tw\",\n  \".gokbayrak.com\",\n  \".goldbet.com\",\n  \"||goldbetsports.com\",\n  \"||golden-ages.org\",\n  \"||goldeneyevault.com\",\n  \".goldenfrog.com\",\n  \"||goldenfrog.com\",\n  \".goldjizz.com\",\n  \"|http://goldjizz.com\",\n  \".goldstep.net\",\n  \"||goldwave.com\",\n  \"gongmeng.info\",\n  \"gongm.in\",\n  \"gongminliliang.com\",\n  \".gongwt.com\",\n  \"|http://gongwt.com\",\n  \"blog.goo.ne.jp/duck-tail_2009\",\n  \".gooday.xyz\",\n  \"|http://gooday.xyz\",\n  \".goodreads.com\",\n  \"||goodreads.com\",\n  \".goodreaders.com\",\n  \"||goodreaders.com\",\n  \".goodtv.com.tw\",\n  \".goodtv.tv\",\n  \"||goofind.com\",\n  \".googlesile.com\",\n  \".gopetition.com\",\n  \"||gopetition.com\",\n  \".goproxing.net\",\n  \"||goreforum.com\",\n  \".gotrusted.com\",\n  \"||gotrusted.com\",\n  \"||gotw.ca\",\n  \"||grammaly.com\",\n  \"grandtrial.org\",\n  \".graphis.ne.jp\",\n  \"||graphis.ne.jp\",\n  \"||graphql.org\",\n  \"greatfirewall.biz\",\n  \"||greatfirewallofchina.net\",\n  \".greatfirewallofchina.org\",\n  \"||greatfirewallofchina.org\",\n  \"||greenfieldbookstore.com.hk\",\n  \".greenparty.org.tw\",\n  \"||greenpeace.org\",\n  \".greenreadings.com/forum\",\n  \"great-firewall.com\",\n  \"great-roc.org\",\n  \"greatroc.org\",\n  \"greatzhonghua.org\",\n  \".greenpeace.com.tw\",\n  \".greenvpn.net\",\n  \"||greenvpn.net\",\n  \".greenvpn.org\",\n  \"||grotty-monday.com\",\n  \"gs-discuss.com\",\n  \"||gsearch.media\",\n  \"||gtricks.com\",\n  \"guancha.org\",\n  \"guaneryu.com\",\n  \".guardster.com\",\n  \".gun-world.net\",\n  \"gunsandammo.com\",\n  \"||gutteruncensored.com\",\n  \"||gvm.com.tw\",\n  \"||gwins.org\",\n  \".gzm.tv\",\n  \"||gzone-anime.info\",\n  \"||clementine-player.org\",\n  \"echofon.com\",\n  \"||greasespot.net\",\n  \"||www.klip.me\",\n  \"@@||site.locql.com\",\n  \"||stephaniered.com\",\n  \"@@||download.syniumsoftware.com\",\n  \"|http://ub0.cc\",\n  \"wozy.in\",\n  \"gospelherald.com\",\n  \"||gospelherald.com\",\n  \"|http://hk.gradconnection.com/\",\n  \"||grangorz.org\",\n  \"greatfire.org\",\n  \"||greatfire.org\",\n  \"greatfirewallofchina.org\",\n  \"||greatroc.tw\",\n  \".gts-vpn.com\",\n  \"|http://gts-vpn.com\",\n  \"||gtv.org\",\n  \"||gtv1.org\",\n  \".gu-chu-sum.org\",\n  \"|http://gu-chu-sum.org\",\n  \".guaguass.com\",\n  \"|http://guaguass.com\",\n  \".guaguass.org\",\n  \"|http://guaguass.org\",\n  \".guangming.com.my\",\n  \"guishan.org\",\n  \"||guishan.org\",\n  \".gumroad.com\",\n  \"||gumroad.com\",\n  \"||gunsamerica.com\",\n  \"guruonline.hk\",\n  \"|http://gvlib.com\",\n  \".gyalwarinpoche.com\",\n  \".gyatsostudio.com\",\n  \".h528.com\",\n  \".h5dm.com\",\n  \".h5galgame.me\",\n  \"||h-china.org\",\n  \".h-moe.com\",\n  \"|http://h-moe.com\",\n  \"h1n1china.org\",\n  \".hacg.club\",\n  \"||hacg.club\",\n  \".hacg.in\",\n  \"|http://hacg.in\",\n  \".hacg.li\",\n  \"|http://hacg.li\",\n  \".hacg.me\",\n  \"|http://hacg.me\",\n  \".hacg.red\",\n  \"|http://hacg.red\",\n  \".hacken.cc/bbs\",\n  \".hacker.org\",\n  \"||hackmd.io\",\n  \"||hackthatphone.net\",\n  \"hahlo.com\",\n  \"||hakkatv.org.tw\",\n  \".handcraftedsoftware.org\",\n  \"|http://bbs.hanminzu.org/\",\n  \".hanunyi.com\",\n  \".hao.news/news\",\n  \"|http://ae.hao123.com\",\n  \"|http://ar.hao123.com\",\n  \"|http://br.hao123.com\",\n  \"|http://en.hao123.com\",\n  \"|http://id.hao123.com\",\n  \"|http://jp.hao123.com\",\n  \"|http://ma.hao123.com\",\n  \"|http://mx.hao123.com\",\n  \"|http://sa.hao123.com\",\n  \"|http://th.hao123.com\",\n  \"|http://tw.hao123.com\",\n  \"|http://vn.hao123.com\",\n  \"|http://hk.hao123img.com\",\n  \"|http://ld.hao123img.com\",\n  \"||happy-vpn.com\",\n  \".haproxy.org\",\n  \"||hardsextube.com\",\n  \".harunyahya.com\",\n  \"|http://harunyahya.com\",\n  \"bbs.hasi.wang\",\n  \"have8.com\",\n  \"@@||haygo.com\",\n  \".hclips.com\",\n  \"||hdlt.me\",\n  \"||hdtvb.net\",\n  \".hdzog.com\",\n  \"|http://hdzog.com\",\n  \"||ordns.he.net\",\n  \"||heartyit.com\",\n  \".heavy-r.com\",\n  \".hec.su\",\n  \"|http://hec.su\",\n  \".hecaitou.net\",\n  \"||hecaitou.net\",\n  \".hechaji.com\",\n  \"||hechaji.com\",\n  \"||heeact.edu.tw\",\n  \".hegre-art.com\",\n  \"|http://hegre-art.com\",\n  \"||cdn.helixstudios.net\",\n  \"||helplinfen.com\",\n  \"||helpuyghursnow.org\",\n  \"||helloandroid.com\",\n  \"||helloqueer.com\",\n  \".helloss.pw\",\n  \"hellotxt.com\",\n  \"||hellotxt.com\",\n  \".hentai.to\",\n  \".hellouk.org/forum/lofiversion\",\n  \".helpeachpeople.com\",\n  \"||helpeachpeople.com\",\n  \"||helpster.de\",\n  \".helpzhuling.org\",\n  \"hentaitube.tv\",\n  \".hentaivideoworld.com\",\n  \"||id.heroku.com\",\n  \"heqinglian.net\",\n  \"||heqinglian.net\",\n  \"||heritage.org\",\n  \"||heungkongdiscuss.com\",\n  \".hexieshe.com\",\n  \"||hexieshe.com\",\n  \"||hexieshe.xyz\",\n  \"||hexxeh.net\",\n  \"app.heywire.com\",\n  \".heyzo.com\",\n  \".hgseav.com\",\n  \".hhdcb3office.org\",\n  \".hhthesakyatrizin.org\",\n  \"hi-on.org.tw\",\n  \"hidden-advent.org\",\n  \"||hidden-advent.org\",\n  \"hidecloud.com/blog/2008/07/29/fuck-beijing-olympics.html\",\n  \"||hide.me\",\n  \".hidein.net\",\n  \".hideipvpn.com\",\n  \"||hideipvpn.com\",\n  \".hideman.net\",\n  \"||hideman.net\",\n  \"hideme.nl\",\n  \"||hidemy.name\",\n  \".hidemyass.com\",\n  \"||hidemyass.com\",\n  \"hidemycomp.com\",\n  \"||hidemycomp.com\",\n  \".hihiforum.com\",\n  \".hihistory.net\",\n  \"||hihistory.net\",\n  \".higfw.com\",\n  \"highpeakspureearth.com\",\n  \"||highrockmedia.com\",\n  \"||hiitch.com\",\n  \"||hikinggfw.org\",\n  \".hilive.tv\",\n  \".himalayan-foundation.org\",\n  \"||himalayan-foundation.org\",\n  \"himalayanglacier.com\",\n  \".himemix.com\",\n  \"||himemix.com\",\n  \".himemix.net\",\n  \"times.hinet.net\",\n  \".hitomi.la\",\n  \"|http://hitomi.la\",\n  \".hiwifi.com\",\n  \"@@||hiwifi.com\",\n  \"hizbuttahrir.org\",\n  \"hizb-ut-tahrir.info\",\n  \"hizb-ut-tahrir.org\",\n  \".hjclub.info\",\n  \".hk-pub.com/forum\",\n  \"|http://hk-pub.com\",\n  \".hk01.com\",\n  \"||hk01.com\",\n  \".hk32168.com\",\n  \"||hk32168.com\",\n  \"||hkacg.com\",\n  \"||hkacg.net\",\n  \".hkatvnews.com\",\n  \"hkbc.net\",\n  \".hkbf.org\",\n  \".hkbookcity.com\",\n  \"||hkbookcity.com\",\n  \"||hkchronicles.com\",\n  \".hkchurch.org\",\n  \"hkci.org.hk\",\n  \".hkcmi.edu\",\n  \"||hkcnews.com\",\n  \"||hkcoc.com\",\n  \"||hkctu.org.hk\",\n  \"hkday.net\",\n  \".hkdailynews.com.hk/china.php\",\n  \"||hkdc.us\",\n  \"hkdf.org\",\n  \".hkej.com\",\n  \".hkepc.com/forum/viewthread.php?tid=1153322\",\n  \"||hket.com\",\n  \"||hkfaa.com\",\n  \"hkfreezone.com\",\n  \"hkfront.org\",\n  \"m.hkgalden.com\",\n  \"|https://m.hkgalden.com\",\n  \".hkgreenradio.org/home\",\n  \"||hkgpao.com\",\n  \".hkheadline.com*blog\",\n  \".hkheadline.com/instantnews\",\n  \"hkhkhk.com\",\n  \"hkhrc.org.hk\",\n  \"hkhrm.org.hk\",\n  \"||hkip.org.uk\",\n  \"1989report.hkja.org.hk\",\n  \"hkjc.com\",\n  \".hkjp.org\",\n  \".hklft.com\",\n  \".hklts.org.hk\",\n  \"||hklts.org.hk\",\n  \"||hkmap.live\",\n  \"||hkopentv.com\",\n  \"||hkpeanut.com\",\n  \"hkptu.org\",\n  \".hkreporter.com\",\n  \"||hkreporter.com\",\n  \"|http://hkupop.hku.hk/\",\n  \".hkusu.net\",\n  \"||hkusu.net\",\n  \".hkvwet.com\",\n  \".hkwcc.org.hk\",\n  \"||hkzone.org\",\n  \".hmonghot.com\",\n  \"|http://hmonghot.com\",\n  \".hmv.co.jp/\",\n  \"hnjhj.com\",\n  \"||hnjhj.com\",\n  \".hnntube.com\",\n  \"||hola.com\",\n  \"||hola.org\",\n  \"holymountaincn.com\",\n  \"holyspiritspeaks.org\",\n  \"||holyspiritspeaks.org\",\n  \"||derekhsu.homeip.net\",\n  \".homeperversion.com\",\n  \"|http://homeservershow.com\",\n  \"|http://old.honeynet.org/scans/scan31/sub/doug_eric/spam_translation.html\",\n  \".hongkongfp.com\",\n  \"||hongkongfp.com\",\n  \"hongmeimei.com\",\n  \"||hongzhi.li\",\n  \"||honven.xyz\",\n  \".hootsuite.com\",\n  \"||hootsuite.com\",\n  \"||hoover.org\",\n  \".hopedialogue.org\",\n  \"|http://hopedialogue.org\",\n  \".hopto.org\",\n  \".hornygamer.com\",\n  \".hornytrip.com\",\n  \"|http://hornytrip.com\",\n  \"||hotair.com\",\n  \".hotav.tv\",\n  \".hotels.cn\",\n  \"hotfrog.com.tw\",\n  \"hotgoo.com\",\n  \".hotpornshow.com\",\n  \"hotpot.hk\",\n  \".hotshame.com\",\n  \"||hotspotshield.com\",\n  \"||hottg.com\",\n  \".hotvpn.com\",\n  \"||hotvpn.com\",\n  \"||hougaige.com\",\n  \"||howtoforge.com\",\n  \"||hoxx.com\",\n  \".hqcdp.org\",\n  \"||hqcdp.org\",\n  \"||hqjapanesesex.com\",\n  \"hqmovies.com\",\n  \".hrcir.com\",\n  \".hrcchina.org\",\n  \".hrea.org\",\n  \".hrichina.org\",\n  \"||hrichina.org\",\n  \".hrtsea.com\",\n  \".hrw.org\",\n  \"||hrw.org\",\n  \"hrweb.org\",\n  \"||hsjp.net\",\n  \"||hsselite.com\",\n  \"|http://hst.net.tw\",\n  \".hstern.net\",\n  \".hstt.net\",\n  \".htkou.net\",\n  \"||htkou.net\",\n  \".hua-yue.net\",\n  \".huaglad.com\",\n  \"||huaglad.com\",\n  \".huanghuagang.org\",\n  \"||huanghuagang.org\",\n  \".huangyiyu.com\",\n  \".huaren.us\",\n  \"||huaren.us\",\n  \".huaren4us.com\",\n  \".huashangnews.com\",\n  \"|http://huashangnews.com\",\n  \"bbs.huasing.org\",\n  \"huaxia-news.com\",\n  \"huaxiabao.org\",\n  \"huaxin.ph\",\n  \"||huayuworld.org\",\n  \".huffingtonpost.com/rebiya-kadeer\",\n  \"||hugoroy.eu\",\n  \"||huhaitai.com\",\n  \"||huhamhire.com\",\n  \".huhangfei.com\",\n  \"||huhangfei.com\",\n  \"huiyi.in\",\n  \".hulkshare.com\",\n  \"||hung-ya.com\",\n  \"||hungerstrikeforaids.org\",\n  \"||huping.net\",\n  \"hurgokbayrak.com\",\n  \".hurriyet.com.tr\",\n  \".hut2.ru\",\n  \"||hutianyi.net\",\n  \"hutong9.net\",\n  \"huyandex.com\",\n  \".hwadzan.tw\",\n  \"||hwayue.org.tw\",\n  \"||hwinfo.com\",\n  \"||hxwk.org\",\n  \"hxwq.org\",\n  \"||hyperrate.com\",\n  \"ebook.hyread.com.tw\",\n  \"||ebook.hyread.com.tw\",\n  \"||i1.hk\",\n  \"||i2p2.de\",\n  \"||i2runner.com\",\n  \"||i818hk.com\",\n  \".i-cable.com\",\n  \".i-part.com.tw\",\n  \".iamtopone.com\",\n  \"iask.ca\",\n  \"||iask.ca\",\n  \"iask.bz\",\n  \"||iask.bz\",\n  \".iav19.com\",\n  \"ibiblio.org/pub/packages/ccic\",\n  \"||ibit.am\",\n  \".iblist.com\",\n  \"||iblogserv-f.net\",\n  \"ibros.org\",\n  \"|http://cn.ibtimes.com\",\n  \".ibvpn.com\",\n  \"||ibvpn.com\",\n  \"icams.com\",\n  \"blogs.icerocket.com/tag\",\n  \".icij.org\",\n  \"||icij.org\",\n  \"||icl-fi.org\",\n  \".icoco.com\",\n  \"||icoco.com\",\n  \"||furbo.org\",\n  \"||warbler.iconfactory.net\",\n  \"||iconpaper.org\",\n  \"||icu-project.org\",\n  \"w.idaiwan.com/forum\",\n  \"idemocracy.asia\",\n  \".identi.ca\",\n  \"||identi.ca\",\n  \"||idiomconnection.com\",\n  \"|http://www.idlcoyote.com\",\n  \".idouga.com\",\n  \".idreamx.com\",\n  \"forum.idsam.com\",\n  \".idv.tw\",\n  \".ieasy5.com\",\n  \"|http://ieasy5.com\",\n  \".ied2k.net\",\n  \".ienergy1.com\",\n  \"||iepl.us\",\n  \"||ift.tt\",\n  \"ifanqiang.com\",\n  \".ifcss.org\",\n  \"||ifcss.org\",\n  \"ifjc.org\",\n  \".ift.tt\",\n  \"|http://ift.tt\",\n  \"||ifreewares.com\",\n  \"||igcd.net\",\n  \".igfw.net\",\n  \"||igfw.net\",\n  \".igfw.tech\",\n  \"||igfw.tech\",\n  \".igmg.de\",\n  \"||ignitedetroit.net\",\n  \".igotmail.com.tw\",\n  \"||igvita.com\",\n  \"||ihakka.net\",\n  \".ihao.org/dz5\",\n  \"||iicns.com\",\n  \".ikstar.com\",\n  \"||ilhamtohtiinstitute.org\",\n  \"||illusionfactory.com\",\n  \"||ilove80.be\",\n  \"||im.tv\",\n  \"@@||myvlog.im.tv\",\n  \"||im88.tw\",\n  \".imgchili.net\",\n  \"|http://imgchili.net\",\n  \".imageab.com\",\n  \".imagefap.com\",\n  \"||imagefap.com\",\n  \"||imageflea.com\",\n  \"imageshack.us\",\n  \"||imagevenue.com\",\n  \"||imagezilla.net\",\n  \".imb.org\",\n  \"|http://imb.org\",\n  \"|http://www.imdb.com/name/nm0482730\",\n  \".imdb.com/title/tt0819354\",\n  \".imdb.com/title/tt1540068\",\n  \".imdb.com/title/tt4908644\",\n  \".img.ly\",\n  \"||img.ly\",\n  \".imgur.com\",\n  \"||imgur.com\",\n  \".imkev.com\",\n  \"||imkev.com\",\n  \".imlive.com\",\n  \".immoral.jp\",\n  \"impact.org.au\",\n  \"impp.mn\",\n  \"|http://tech2.in.com/video/\",\n  \"in99.org\",\n  \"in-disguise.com\",\n  \".incapdns.net\",\n  \".incloak.com\",\n  \"||incloak.com\",\n  \"||incredibox.fr\",\n  \"||independent.co.uk\",\n  \"||indiablooms.com\",\n  \"||indiandefensenews.in\",\n  \"||indianarrative.com\",\n  \"||timesofindia.indiatimes.com\",\n  \".indiemerch.com\",\n  \"||indiemerch.com\",\n  \"info-graf.fr\",\n  \"website.informer.com\",\n  \"||initiativesforchina.org\",\n  \".inkui.com\",\n  \".inmediahk.net\",\n  \"||inmediahk.net\",\n  \"||innermongolia.org\",\n  \"||inoreader.com\",\n  \".inote.tw\",\n  \".insecam.org\",\n  \"|http://insecam.org\",\n  \"||insidevoa.com\",\n  \".institut-tibetain.org\",\n  \"|http://internet.org/\",\n  \"internetdefenseleague.org\",\n  \"internetfreedom.org\",\n  \"||internetpopculture.com\",\n  \".inthenameofconfuciusmovie.com\",\n  \"||inthenameofconfuciusmovie.com\",\n  \"inxian.com\",\n  \"||inxian.com\",\n  \"ipalter.com\",\n  \".ipfire.org\",\n  \"||iphone4hongkong.com\",\n  \"||iphonehacks.com\",\n  \"||iphonetaiwan.org\",\n  \"||iphonix.fr\",\n  \"||ipicture.ru\",\n  \".ipjetable.net\",\n  \"||ipjetable.net\",\n  \".ipobar.com/read.php?\",\n  \"ipoock.com/img\",\n  \".iportal.me\",\n  \"|http://iportal.me\",\n  \"||ippotv.com\",\n  \".ipredator.se\",\n  \"||ipredator.se\",\n  \".iptv.com.tw\",\n  \"||iptvbin.com\",\n  \"||ipvanish.com\",\n  \"iredmail.org\",\n  \"chinese.irib.ir\",\n  \"||ironbigfools.compython.net\",\n  \"||ironpython.net\",\n  \".ironsocket.com\",\n  \"||ironsocket.com\",\n  \".is.gd\",\n  \".islahhaber.net\",\n  \".islam.org.hk\",\n  \"|http://islam.org.hk\",\n  \".islamawareness.net/Asia/China\",\n  \".islamhouse.com\",\n  \"||islamhouse.com\",\n  \".islamicity.com\",\n  \".islamicpluralism.org\",\n  \".islamtoday.net\",\n  \".isaacmao.com\",\n  \"||isaacmao.com\",\n  \"||isgreat.org\",\n  \"||ismaelan.com\",\n  \".ismalltits.com\",\n  \"||ismprofessional.net\",\n  \"isohunt.com\",\n  \"||israbox.com\",\n  \".issuu.com\",\n  \"||issuu.com\",\n  \".istars.co.nz\",\n  \"oversea.istarshine.com\",\n  \"||oversea.istarshine.com\",\n  \"blog.istef.info/2007/10/21/myentunnel\",\n  \".istiqlalhewer.com\",\n  \".istockphoto.com\",\n  \"isunaffairs.com\",\n  \"isuntv.com\",\n  \"itaboo.info\",\n  \"||itaboo.info\",\n  \".italiatibet.org\",\n  \"download.ithome.com.tw\",\n  \"ithelp.ithome.com.tw\",\n  \"||itshidden.com\",\n  \".itsky.it\",\n  \".itweet.net\",\n  \"|http://itweet.net\",\n  \".iu45.com\",\n  \".iuhrdf.org\",\n  \"||iuhrdf.org\",\n  \".iuksky.com\",\n  \".ivacy.com\",\n  \"||ivacy.com\",\n  \".iverycd.com\",\n  \".ivpn.net\",\n  \"||ixquick.com\",\n  \".ixxx.com\",\n  \"iyouport.com\",\n  \"||iyouport.com\",\n  \".izaobao.us\",\n  \"||gmozomg.izihost.org\",\n  \".izles.net\",\n  \".izlesem.org\",\n  \"||j.mp\",\n  \"blog.jackjia.com\",\n  \"jamaat.org\",\n  \"||jamestown.org\",\n  \".jamyangnorbu.com\",\n  \"|http://jamyangnorbu.com\",\n  \".jandyx.com\",\n  \"||janwongphoto.com\",\n  \"||japan-whores.com\",\n  \".jav.com\",\n  \".jav101.com\",\n  \".jav2be.com\",\n  \"||jav2be.com\",\n  \".jav68.tv\",\n  \".javakiba.org\",\n  \"|http://javakiba.org\",\n  \".javbus.com\",\n  \"||javbus.com\",\n  \"||javfor.me\",\n  \".javhd.com\",\n  \".javhip.com\",\n  \".javmobile.net\",\n  \"|http://javmobile.net\",\n  \".javmoo.com\",\n  \".javseen.com\",\n  \"|http://javseen.com\",\n  \"jbtalks.cc\",\n  \"jbtalks.com\",\n  \"jbtalks.my\",\n  \".jdwsy.com\",\n  \"jeanyim.com\",\n  \"||jfqu36.club\",\n  \"||jfqu37.xyz\",\n  \"||jgoodies.com\",\n  \".jiangweiping.com\",\n  \"||jiangweiping.com\",\n  \"||jiaoyou8.com\",\n  \".jiehua.cz\",\n  \"||hk.jiepang.com\",\n  \"||tw.jiepang.com\",\n  \"jieshibaobao.com\",\n  \".jigglegifs.com\",\n  \"56cun04.jigsy.com\",\n  \"jigong1024.com\",\n  \"daodu14.jigsy.com\",\n  \"specxinzl.jigsy.com\",\n  \"wlcnew.jigsy.com\",\n  \".jihadology.net\",\n  \"|http://jihadology.net\",\n  \"jinbushe.org\",\n  \"||jinbushe.org\",\n  \".jingsim.org\",\n  \"zhao.jinhai.de\",\n  \"jingpin.org\",\n  \"||jingpin.org\",\n  \"jinpianwang.com\",\n  \".jinroukong.com\",\n  \"ac.jiruan.net\",\n  \"||jitouch.com\",\n  \".jizzthis.com\",\n  \"jjgirls.com\",\n  \".jkb.cc\",\n  \"|http://jkb.cc\",\n  \"jkforum.net\",\n  \"||jma.go.jp\",\n  \"research.jmsc.hku.hk/social\",\n  \"weiboscope.jmsc.hku.hk\",\n  \".jmscult.com\",\n  \"|http://jmscult.com\",\n  \"||joachims.org\",\n  \"||jobso.tv\",\n  \".sunwinism.joinbbs.net\",\n  \"||joinclubhouse.com\",\n  \".journalchretien.net\",\n  \"||journalofdemocracy.org\",\n  \".joymiihub.com\",\n  \".joyourself.com\",\n  \"jpopforum.net\",\n  \"||fiddle.jshell.net\",\n  \".jubushoushen.com\",\n  \"||jubushoushen.com\",\n  \".juhuaren.com\",\n  \"||juliereyc.com\",\n  \"||junauza.com\",\n  \".june4commemoration.org\",\n  \".junefourth-20.net\",\n  \"||junefourth-20.net\",\n  \"||bbs.junglobal.net\",\n  \".juoaa.com\",\n  \"|http://juoaa.com\",\n  \"justfreevpn.com\",\n  \".justicefortenzin.org\",\n  \"justpaste.it\",\n  \"||justmysocks1.net\",\n  \"justtristan.com\",\n  \"juyuange.org\",\n  \"juziyue.com\",\n  \"||juziyue.com\",\n  \"||jwmusic.org\",\n  \"@@||music.jwmusic.org\",\n  \".jyxf.net\",\n  \"||k-doujin.net\",\n  \"||ka-wai.com\",\n  \"||kadokawa.co.jp\",\n  \".kagyu.org\",\n  \"||kagyu.org.za\",\n  \".kagyumonlam.org\",\n  \".kagyunews.com.hk\",\n  \".kagyuoffice.org\",\n  \"||kagyuoffice.org\",\n  \"||kagyuoffice.org.tw\",\n  \".kaiyuan.de\",\n  \".kakao.com\",\n  \"||kakao.com\",\n  \".kalachakralugano.org\",\n  \".kankan.today\",\n  \".kannewyork.com\",\n  \"||kannewyork.com\",\n  \".kanshifang.com\",\n  \"||kanshifang.com\",\n  \"||kantie.org\",\n  \"kanzhongguo.com\",\n  \"kanzhongguo.eu\",\n  \".kaotic.com\",\n  \"||kaotic.com\",\n  \"||karayou.com\",\n  \"karkhung.com\",\n  \".karmapa.org\",\n  \".karmapa-teachings.org\",\n  \"||kawase.com\",\n  \".kba-tx.org\",\n  \".kcoolonline.com\",\n  \".kebrum.com\",\n  \"||kebrum.com\",\n  \".kechara.com\",\n  \".keepandshare.com/visit/visit_page.php?i=688154\",\n  \".keezmovies.com\",\n  \".kendincos.net\",\n  \".kenengba.com\",\n  \"||kenengba.com\",\n  \"||keontech.net\",\n  \".kepard.com\",\n  \"||kepard.com\",\n  \"wiki.keso.cn/Home\",\n  \"||keycdn.com\",\n  \".khabdha.org\",\n  \".khmusic.com.tw\",\n  \"||kichiku-doujinko.com\",\n  \".kik.com\",\n  \"||kik.com\",\n  \"bbs.kimy.com.tw\",\n  \".kindleren.com\",\n  \"|http://kindleren.com\",\n  \"|http://www.kindleren.com\",\n  \".kingdomsalvation.org\",\n  \"||kingdomsalvation.org\",\n  \"kinghost.com\",\n  \"||kingstone.com.tw\",\n  \".kink.com\",\n  \".kinokuniya.com\",\n  \"||kinokuniya.com\",\n  \"killwall.com\",\n  \"||killwall.com\",\n  \"||kinmen.travel\",\n  \".kir.jp\",\n  \".kissbbao.cn\",\n  \"|http://kiwi.kz\",\n  \"||kk-whys.co.jp\",\n  \".kmuh.org.tw\",\n  \".knowledgerush.com/kr/encyclopedia\",\n  \"||knowyourmeme.com\",\n  \".kobo.com\",\n  \"||kobo.com\",\n  \".kobobooks.com\",\n  \"||kobobooks.com\",\n  \"||kodingen.com\",\n  \"@@||www.kodingen.com\",\n  \"||kompozer.net\",\n  \".konachan.com\",\n  \"|http://konachan.com\",\n  \".kone.com\",\n  \"||koolsolutions.com\",\n  \".koornk.com\",\n  \"||koornk.com\",\n  \"||koranmandarin.com\",\n  \".korenan2.com\",\n  \"||kqes.net\",\n  \"|http://gojet.krtco.com.tw\",\n  \".ksdl.org\",\n  \".ksnews.com.tw\",\n  \"||ktzhk.com\",\n  \".kui.name/event\",\n  \"kun.im\",\n  \".kurashsultan.com\",\n  \"||kurtmunger.com\",\n  \"kusocity.com\",\n  \"||kwcg.ca\",\n  \"||kwok7.com\",\n  \".kwongwah.com.my\",\n  \"||kwongwah.com.my\",\n  \".kxsw.life\",\n  \"||kxsw.life\",\n  \".kyofun.com\",\n  \"kyohk.net\",\n  \"||kyoyue.com\",\n  \".kyzyhello.com\",\n  \"||kyzyhello.com\",\n  \".kzeng.info\",\n  \"||kzeng.info\",\n  \"la-forum.org\",\n  \"ladbrokes.com\",\n  \"||labiennale.org\",\n  \".lagranepoca.com\",\n  \"||lagranepoca.com\",\n  \"||lala.im\",\n  \".lalulalu.com\",\n  \".lama.com.tw\",\n  \"||lama.com.tw\",\n  \".lamayeshe.com\",\n  \"|http://lamayeshe.com\",\n  \"|http://www.lamenhu.com\",\n  \".lamnia.co.uk\",\n  \"||lamnia.co.uk\",\n  \"lamrim.com\",\n  \"||landofhope.tv\",\n  \".lanterncn.cn\",\n  \"|http://lanterncn.cn\",\n  \".lantosfoundation.org\",\n  \".laod.cn\",\n  \"|http://laod.cn\",\n  \"laogai.org\",\n  \"||laogai.org\",\n  \"||laogairesearch.org\",\n  \"laomiu.com\",\n  \".laoyang.info\",\n  \"|http://laoyang.info\",\n  \"||laptoplockdown.com\",\n  \".laqingdan.net\",\n  \"||laqingdan.net\",\n  \"||larsgeorge.com\",\n  \".lastcombat.com\",\n  \"|http://lastcombat.com\",\n  \"||lastfm.es\",\n  \"latelinenews.com\",\n  \"||lausan.hk\",\n  \"||le-vpn.com\",\n  \".leafyvpn.net\",\n  \"||leafyvpn.net\",\n  \"leeao.com.cn/bbs/forum.php\",\n  \"lefora.com\",\n  \"||left21.hk\",\n  \".legalporno.com\",\n  \".legsjapan.com\",\n  \"|http://leirentv.ca\",\n  \"leisurecafe.ca\",\n  \"||lematin.ch\",\n  \".lemonde.fr\",\n  \"||lenwhite.com\",\n  \"||leorockwell.com\",\n  \"lerosua.org\",\n  \"||lerosua.org\",\n  \"blog.lester850.info\",\n  \"||lesoir.be\",\n  \".letou.com\",\n  \"letscorp.net\",\n  \"||letscorp.net\",\n  \"||ocsp.int-x3.letsencrypt.org\",\n  \"||ss.levyhsu.com\",\n  \"||cdn.assets.lfpcontent.com\",\n  \".lhakar.org\",\n  \"|http://lhakar.org\",\n  \".lhasocialwork.org\",\n  \".liangyou.net\",\n  \"||liangyou.net\",\n  \".lianyue.net\",\n  \"||liaowangxizang.net\",\n  \".liaowangxizang.net\",\n  \"||liberal.org.hk\",\n  \".libertytimes.com.tw\",\n  \"blogs.libraryinformationtechnology.com/jxyz\",\n  \".lidecheng.com/blog/fucking-gfw\",\n  \".lighten.org.tw\",\n  \".lightnovel.cn\",\n  \"@@|https://www.lightnovel.cn\",\n  \"limiao.net\",\n  \"linkuswell.com\",\n  \"abitno.linpie.com/use-ipv6-to-fuck-gfw\",\n  \"||line.me\",\n  \"||line-apps.com\",\n  \".linglingfa.com\",\n  \"||lingvodics.com\",\n  \".link-o-rama.com\",\n  \"|http://link-o-rama.com\",\n  \".linkideo.com\",\n  \"||api.linksalpha.com\",\n  \"||apidocs.linksalpha.com\",\n  \"||www.linksalpha.com\",\n  \"||help.linksalpha.com\",\n  \"||linux.org.hk\",\n  \"linuxtoy.org/archives/installing-west-chamber-on-ubuntu\",\n  \".lionsroar.com\",\n  \".lipuman.com\",\n  \"||liquidvpn.com\",\n  \"||greatfire.us7.list-manage.com\",\n  \"||listennotes.com\",\n  \"||listentoyoutube.com\",\n  \"listorious.com\",\n  \".liu-xiaobo.org\",\n  \"||liudejun.com\",\n  \".liuhanyu.com\",\n  \".liujianshu.com\",\n  \"||liujianshu.com\",\n  \".liuxiaobo.net\",\n  \"|http://liuxiaobo.net\",\n  \"liuxiaotong.com\",\n  \"||liuxiaotong.com\",\n  \".livedoor.jp\",\n  \".liveleak.com\",\n  \"||liveleak.com\",\n  \"||livemint.com\",\n  \".livestation.com\",\n  \"livestream.com\",\n  \"||livestream.com\",\n  \"||livingonline.us\",\n  \"||livingstream.com\",\n  \"||livevideo.com\",\n  \".livevideo.com\",\n  \".liwangyang.com\",\n  \"lizhizhuangbi.com\",\n  \"lkcn.net\",\n  \".llss.me/\",\n  \"||lncn.org\",\n  \".load.to\",\n  \".lobsangwangyal.com\",\n  \".localdomain.ws\",\n  \"||localdomain.ws\",\n  \"localpresshk.com\",\n  \"||lockestek.com\",\n  \"logbot.net\",\n  \"||logiqx.com\",\n  \"secure.logmein.com\",\n  \"||secure.logmein.com\",\n  \"||logos.com.hk\",\n  \".londonchinese.ca\",\n  \".longhair.hk\",\n  \"longmusic.com\",\n  \"||longtermly.net\",\n  \"||lookpic.com\",\n  \".looktoronto.com\",\n  \"|http://looktoronto.com\",\n  \".lotsawahouse.org/tibetan-masters/fourteenth-dalai-lama\",\n  \".lotuslight.org.hk\",\n  \".lotuslight.org.tw\",\n  \"hkreporter.loved.hk\",\n  \"||lpsg.com\",\n  \"||lrfz.com\",\n  \".lrip.org\",\n  \"||lrip.org\",\n  \".lsd.org.hk\",\n  \"||lsd.org.hk\",\n  \"lsforum.net\",\n  \".lsm.org\",\n  \"||lsm.org\",\n  \".lsmchinese.org\",\n  \"||lsmchinese.org\",\n  \".lsmkorean.org\",\n  \"||lsmkorean.org\",\n  \".lsmradio.com/rad_archives\",\n  \".lsmwebcast.com\",\n  \".ltn.com.tw\",\n  \"||ltn.com.tw\",\n  \"||luckydesigner.space\",\n  \".luke54.com\",\n  \".luke54.org\",\n  \".lupm.org\",\n  \"||lupm.org\",\n  \"||lushstories.com\",\n  \"luxebc.com\",\n  \"lvhai.org\",\n  \"||lvhai.org\",\n  \"||lvv2.com\",\n  \".lyfhk.net\",\n  \"|http://lyfhk.net\",\n  \"||lzjscript.com\",\n  \".lzmtnews.org\",\n  \"||lzmtnews.org\",\n  \"http://*.m-team.cc\",\n  \".macrovpn.com\",\n  \"macts.com.tw\",\n  \"||mad-ar.ch\",\n  \"||madrau.com\",\n  \"||madthumbs.com\",\n  \"||magic-net.info\",\n  \"mahabodhi.org\",\n  \"my.mail.ru\",\n  \".maiplus.com\",\n  \"|http://maiplus.com\",\n  \".maizhong.org\",\n  \"makkahnewspaper.com\",\n  \".mamingzhe.com\",\n  \"manicur4ik.ru\",\n  \"||manyvoices.news\",\n  \".maplew.com\",\n  \"|http://maplew.com\",\n  \"||marc.info\",\n  \"marguerite.su\",\n  \"||martincartoons.com\",\n  \"maskedip.com\",\n  \".maiio.net\",\n  \".mail-archive.com\",\n  \".malaysiakini.com\",\n  \"||makemymood.com\",\n  \".manchukuo.net\",\n  \".maniash.com\",\n  \"|http://maniash.com\",\n  \".mansion.com\",\n  \".mansionpoker.com\",\n  \"||martau.com\",\n  \"|http://blog.martinoei.com\",\n  \".martsangkagyuofficial.org\",\n  \"|http://martsangkagyuofficial.org\",\n  \"maruta.be/forget\",\n  \".marxist.com\",\n  \"||marxist.net\",\n  \".marxists.org/chinese\",\n  \"||matainja.com\",\n  \"||mathable.io\",\n  \"||mathiew-badimon.com\",\n  \"||matrix.org\",\n  \"||matsushimakaede.com\",\n  \"|http://maturejp.com\",\n  \"mayimayi.com\",\n  \".maxing.jp\",\n  \".mcaf.ee\",\n  \"|http://mcaf.ee\",\n  \"||mcadforums.com\",\n  \"mcfog.com\",\n  \"mcreasite.com\",\n  \".md-t.org\",\n  \"||md-t.org\",\n  \"||meansys.com\",\n  \".media.org.hk\",\n  \".mediachinese.com\",\n  \"||mediachinese.com\",\n  \".mediafire.com/?\",\n  \".mediafire.com/download\",\n  \".mediafreakcity.com\",\n  \"||mediafreakcity.com\",\n  \".medium.com\",\n  \"||medium.com\",\n  \".meetav.com\",\n  \"||meetup.com\",\n  \"mefeedia.com\",\n  \"jihadintel.meforum.org\",\n  \"||mega.co.nz\",\n  \"||mega.io\",\n  \"||mega.nz\",\n  \"||megaproxy.com\",\n  \"||megarotic.com\",\n  \"megavideo.com\",\n  \"||megurineluka.com\",\n  \"meirixiaochao.com\",\n  \".meltoday.com\",\n  \".memehk.com\",\n  \"||memehk.com\",\n  \"memorybbs.com\",\n  \".memri.org\",\n  \".memrijttm.org\",\n  \"||mercdn.net\",\n  \".mercyprophet.org\",\n  \"|http://mercyprophet.org\",\n  \"||mergersandinquisitions.org\",\n  \".meridian-trust.org\",\n  \"|http://meridian-trust.org\",\n  \".meripet.biz\",\n  \"|http://meripet.biz\",\n  \".meripet.com\",\n  \"|http://meripet.com\",\n  \"merit-times.com.tw\",\n  \"meshrep.com\",\n  \".mesotw.com/bbs\",\n  \"metacafe.com/watch\",\n  \"||metafilter.com\",\n  \"||meteorshowersonline.com\",\n  \"|http://www.metro.taipei/\",\n  \".metrohk.com.hk/?cmd=detail&categoryID=2\",\n  \"||metrolife.ca\",\n  \".metroradio.com.hk\",\n  \"|http://metroradio.com.hk\",\n  \"||mewe.com\",\n  \"meyou.jp\",\n  \".meyul.com\",\n  \"||mgoon.com\",\n  \"||mgstage.com\",\n  \"||mh4u.org\",\n  \"mhradio.org\",\n  \"|http://michaelanti.com\",\n  \"||michaelmarketl.com\",\n  \"|http://bbs.mikocon.com\",\n  \".microvpn.com\",\n  \"|http://microvpn.com\",\n  \"middle-way.net\",\n  \".mihk.hk/forum\",\n  \".mihr.com\",\n  \"mihua.org\",\n  \"||mikesoltys.com\",\n  \".milph.net\",\n  \"|http://milph.net\",\n  \".milsurps.com\",\n  \"mimiai.net\",\n  \".mimivip.com\",\n  \".mimivv.com\",\n  \".mindrolling.org\",\n  \"|http://mindrolling.org\",\n  \"||mingdemedia.org\",\n  \".minghui.or.kr\",\n  \"|http://minghui.or.kr\",\n  \"minghui.org\",\n  \"||minghui.org\",\n  \"minghui-a.org\",\n  \"minghui-b.org\",\n  \"minghui-school.org\",\n  \".mingjinglishi.com\",\n  \"||mingjinglishi.com\",\n  \"mingjingnews.com\",\n  \"||mingjingtimes.com\",\n  \".mingpao.com\",\n  \"||mingpao.com\",\n  \".mingpaocanada.com\",\n  \".mingpaomonthly.com\",\n  \"|http://mingpaomonthly.com\",\n  \"mingpaonews.com\",\n  \".mingpaony.com\",\n  \".mingpaosf.com\",\n  \".mingpaotor.com\",\n  \".mingpaovan.com\",\n  \".mingshengbao.com\",\n  \".minhhue.net\",\n  \".miniforum.org\",\n  \".ministrybooks.org\",\n  \".minzhuhua.net\",\n  \"||minzhuhua.net\",\n  \"minzhuzhanxian.com\",\n  \"minzhuzhongguo.org\",\n  \"||miroguide.com\",\n  \"mirrorbooks.com\",\n  \"||mirrormedia.mg\",\n  \".mist.vip\",\n  \"||thecenter.mit.edu\",\n  \"||scratch.mit.edu\",\n  \".mitao.com.tw\",\n  \".mitbbs.com\",\n  \"||mitbbs.com\",\n  \"mitbbsau.com\",\n  \".mixero.com\",\n  \"||mixero.com\",\n  \"||mixi.jp\",\n  \"mixpod.com\",\n  \".mixx.com\",\n  \"||mixx.com\",\n  \"||mizzmona.com\",\n  \".mk5000.com\",\n  \".mlcool.com\",\n  \"||mlzs.work\",\n  \".mm-cg.com\",\n  \"||mmaaxx.com\",\n  \".mmmca.com\",\n  \"mnewstv.com\",\n  \"||mobatek.net\",\n  \".mobile01.com\",\n  \"||mobile01.com\",\n  \"||mobileways.de\",\n  \".mobypicture.com\",\n  \"|http://moby.to\",\n  \"||modernchinastudies.org\",\n  \"||moeerolibrary.com\",\n  \"wiki.moegirl.org\",\n  \".mofaxiehui.com\",\n  \".mofos.com\",\n  \"||mog.com\",\n  \"||mohu.rocks\",\n  \"molihua.org\",\n  \"||mondex.org\",\n  \".money-link.com.tw\",\n  \"|http://money-link.com.tw\",\n  \"|http://www.monlamit.org\",\n  \".moonbbs.com\",\n  \"||moonbbs.com\",\n  \"||moptt.tw\",\n  \"||monitorchina.org\",\n  \"bbs.morbell.com\",\n  \"||morningsun.org\",\n  \"||moroneta.com\",\n  \".motherless.com\",\n  \"|http://motherless.com\",\n  \"motor4ik.ru\",\n  \".mousebreaker.com\",\n  \".movements.org\",\n  \"||movements.org\",\n  \"||moviefap.com\",\n  \"||www.moztw.org\",\n  \".mp3buscador.com\",\n  \"||mpettis.com\",\n  \".mpfinance.com\",\n  \"||mpfinance.com\",\n  \".mpinews.com\",\n  \"||mpinews.com\",\n  \"mponline.hk\",\n  \".mqxd.org\",\n  \"|http://mqxd.org\",\n  \"mrtweet.com\",\n  \"||mrtweet.com\",\n  \"news.hk.msn.com\",\n  \"news.msn.com.tw\",\n  \"msguancha.com\",\n  \".mswe1.org\",\n  \"|http://mswe1.org\",\n  \"||mthruf.com\",\n  \"||mubi.com\",\n  \"muchosucko.com\",\n  \"||multiply.com\",\n  \"multiproxy.org\",\n  \"multiupload.com\",\n  \".mullvad.net\",\n  \"||mullvad.net\",\n  \".mummysgold.com\",\n  \".murmur.tw\",\n  \"|http://murmur.tw\",\n  \".musicade.net\",\n  \".muslimvideo.com\",\n  \"||muzi.com\",\n  \"||muzi.net\",\n  \"||mx981.com\",\n  \".my-formosa.com\",\n  \".my-proxy.com\",\n  \".my-private-network.co.uk\",\n  \"||my-private-network.co.uk\",\n  \"forum.my903.com\",\n  \".myactimes.com/actimes\",\n  \"||myanniu.com\",\n  \".myaudiocast.com\",\n  \"||myaudiocast.com\",\n  \".myav.com.tw/bbs\",\n  \".mybbs.us\",\n  \".myca168.com\",\n  \".mycanadanow.com\",\n  \"||bbs.mychat.to\",\n  \"||mychinamyhome.com\",\n  \".mychinamyhome.com\",\n  \".mychinanet.com\",\n  \".mychinanews.com\",\n  \"||mychinanews.com\",\n  \".mychinese.news\",\n  \"||mycnnews.com\",\n  \"||mykomica.org\",\n  \"mycould.com/discuz\",\n  \".myeasytv.com\",\n  \"||myeclipseide.com\",\n  \".myforum.com.hk\",\n  \"||myforum.com.hk\",\n  \"||myforum.com.uk\",\n  \".myfreecams.com\",\n  \".myfreepaysite.com\",\n  \".myfreshnet.com\",\n  \".myiphide.com\",\n  \"||myiphide.com\",\n  \"forum.mymaji.com\",\n  \"mymediarom.com/files/box\",\n  \"||mymoe.moe\",\n  \"||mymusic.net.tw\",\n  \"||myparagliding.com\",\n  \"||mypopescu.com\",\n  \"myradio.hk/podcast\",\n  \".myreadingmanga.info\",\n  \"mysinablog.com\",\n  \".myspace.com\",\n  \"||myspacecdn.com\",\n  \".mytalkbox.com\",\n  \".mytizi.com\",\n  \"||naacoalition.org\",\n  \"old.nabble.com\",\n  \"||naitik.net\",\n  \".nakido.com\",\n  \"||nakido.com\",\n  \".nakuz.com/bbs\",\n  \"||nalandabodhi.org\",\n  \"||nalandawest.org\",\n  \".namgyal.org\",\n  \"namgyalmonastery.org\",\n  \"||namsisi.com\",\n  \".nanyang.com\",\n  \"||nanyang.com\",\n  \".nanyangpost.com\",\n  \"||nanyangpost.com\",\n  \".nanzao.com\",\n  \".naol.ca\",\n  \".naol.cc\",\n  \"uighur.narod.ru\",\n  \".nat.moe\",\n  \"||nat.moe\",\n  \"cyberghost.natado.com\",\n  \"||national-lottery.co.uk\",\n  \"||nationalawakening.org\",\n  \"||nationalinterest.org\",\n  \"news.nationalgeographic.com/news/2014/06/140603-tiananmen-square\",\n  \"||nationalreview.com\",\n  \".nationsonline.org/oneworld/tibet\",\n  \"||line.naver.jp\",\n  \"||navyfamily.navy.mil\",\n  \"||navyreserve.navy.mil\",\n  \"||nko.navy.mil\",\n  \"||usno.navy.mil\",\n  \"naweeklytimes.com\",\n  \"||nbcnews.com\",\n  \".nbtvpn.com\",\n  \"|http://nbtvpn.com\",\n  \"nccwatch.org.tw\",\n  \".nch.com.tw\",\n  \".ncn.org\",\n  \"||nchrd.org\",\n  \"||ncn.org\",\n  \"||etools.ncol.com\",\n  \".nde.de\",\n  \"||ndi.org\",\n  \".ndr.de\",\n  \".ned.org\",\n  \"||nekoslovakia.net\",\n  \"||neowin.net\",\n  \"||nepusoku.com\",\n  \"||net-fits.pro\",\n  \"||netalert.me\",\n  \"bbs.netbig.com\",\n  \".netbirds.com\",\n  \"netcolony.com\",\n  \"bolin.netfirms.com\",\n  \"||netflav.com\",\n  \"||netme.cc\",\n  \"netsneak.com\",\n  \".network54.com\",\n  \"networkedblogs.com\",\n  \".networktunnel.net\",\n  \"neverforget8964.org\",\n  \"new-3lunch.net\",\n  \".new-akiba.com\",\n  \".new96.ca\",\n  \".newcenturymc.com\",\n  \"|http://newcenturymc.com\",\n  \"newcenturynews.com\",\n  \"||newchen.com\",\n  \".newchen.com\",\n  \".newgrounds.com\",\n  \"||newhighlandvision.com\",\n  \"newipnow.com\",\n  \".newlandmagazine.com.au\",\n  \".newnews.ca\",\n  \"news100.com.tw\",\n  \"newschinacomment.org\",\n  \".newscn.org\",\n  \"||newscn.org\",\n  \"newspeak.cc/story\",\n  \".newsancai.com\",\n  \"||newsancai.com\",\n  \".newsdetox.ca\",\n  \".newsdh.com\",\n  \"||newstamago.com\",\n  \"||newstapa.org\",\n  \"newstarnet.com\",\n  \"||newsweek.com\",\n  \".newtaiwan.com.tw\",\n  \"newtalk.tw\",\n  \"||newtalk.tw\",\n  \"||newyorker.com\",\n  \"newyorktimes.com\",\n  \"||nexon.com\",\n  \".next11.co.jp\",\n  \"||nextdigital.com.hk\",\n  \".nextmag.com.tw\",\n  \".nextmedia.com\",\n  \"||nexton-net.jp\",\n  \"nexttv.com.tw\",\n  \".nfjtyd.com\",\n  \"||co.ng.mil\",\n  \"||nga.mil\",\n  \"ngensis.com\",\n  \"||ngodupdongchung.com\",\n  \".nhentai.net\",\n  \"|http://nhentai.net\",\n  \".nhk-ondemand.jp\",\n  \".nicovideo.jp/watch\",\n  \"||nicovideo.jp\",\n  \"||nighost.org\",\n  \"av.nightlife141.com\",\n  \"ninecommentaries.com\",\n  \".ninjacloak.com\",\n  \"||ninjaproxy.ninja\",\n  \"nintendium.com\",\n  \"taiwanyes.ning.com\",\n  \"usmgtcg.ning.com/forum\",\n  \"||niusnews.com\",\n  \"||njactb.org\",\n  \"njuice.com\",\n  \"||njuice.com\",\n  \"||nlfreevpn.com\",\n  \"||nmsl.website\",\n  \"||nnews.eu\",\n  \".ddns.net/\",\n  \".gooddns.info\",\n  \"||gotdns.ch\",\n  \".maildns.xyz\",\n  \".no-ip.org\",\n  \".opendn.xyz\",\n  \".servehttp.com\",\n  \"sytes.net\",\n  \".whodns.xyz\",\n  \".zapto.org\",\n  \"|http://dynupdate.no-ip.com/\",\n  \"||nobel.se\",\n  \"nobelprize.org/nobel_prizes/peace/laureates/1989\",\n  \"nobelprize.org/nobel_prizes/peace/laureates/2010\",\n  \"nobodycanstop.us\",\n  \"||nobodycanstop.us\",\n  \"||nokogiri.org\",\n  \"||nokola.com\",\n  \"noodlevpn.com\",\n  \".norbulingka.org\",\n  \"nordvpn.com\",\n  \"||nordvpn.com\",\n  \"||novelasia.com\",\n  \".news.now.com\",\n  \"|http://news.now.com\",\n  \"news.now.com%2Fhome\",\n  \"||nownews.com\",\n  \".nowtorrents.com\",\n  \".noypf.com\",\n  \"||noypf.com\",\n  \"||npa.go.jp\",\n  \".npnt.me\",\n  \"|http://npnt.me\",\n  \".nps.gov\",\n  \".nradio.me\",\n  \"|http://nradio.me\",\n  \".nrk.no\",\n  \"||nrk.no\",\n  \".ntd.tv\",\n  \"||ntd.tv\",\n  \".ntdtv.com\",\n  \"||ntdtv.com\",\n  \"||ntdtv.com.tw\",\n  \".ntdtv.co.kr\",\n  \"ntdtv.ca\",\n  \"ntdtv.org\",\n  \"ntdtv.ru\",\n  \"ntdtvla.com\",\n  \".ntrfun.com\",\n  \"||cbs.ntu.edu.tw\",\n  \"||media.nu.nl\",\n  \".nubiles.net\",\n  \"||nuexpo.com\",\n  \".nukistream.com\",\n  \"||nurgo-software.com\",\n  \"||nutaku.net\",\n  \"||nutsvpn.work\",\n  \".nuvid.com\",\n  \"||nvdst.com\",\n  \"nuzcom.com\",\n  \".nvquan.org\",\n  \".nvtongzhisheng.org\",\n  \"|http://nvtongzhisheng.org\",\n  \".nwtca.org\",\n  \"|http://nyaa.eu\",\n  \"||nyaa.si\",\n  \"||nybooks.com\",\n  \".nydus.ca\",\n  \"nylon-angel.com\",\n  \"nylonstockingsonline.com\",\n  \"||nypost.com\",\n  \".nzchinese.com\",\n  \"||nzchinese.net.nz\",\n  \"observechina.net\",\n  \".obutu.com\",\n  \"ocaspro.com\",\n  \"occupytiananmen.com\",\n  \"oclp.hk\",\n  \".ocreampies.com\",\n  \"||october-review.org\",\n  \"||odysee.com\",\n  \"offbeatchina.com\",\n  \"||officeoftibet.com\",\n  \"|http://ofile.org\",\n  \"||ogaoga.org\",\n  \"twtr2src.ogaoga.org\",\n  \".ogate.org\",\n  \"||ogate.org\",\n  \"www2.ohchr.org/english/bodies/cat/docs/ngos/II_China_41.pdf\",\n  \"||ohmyrss.com\",\n  \".oikos.com.tw/v4\",\n  \".oiktv.com\",\n  \"oizoblog.com\",\n  \".ok.ru\",\n  \"||ok.ru\",\n  \".okayfreedom.com\",\n  \"||okayfreedom.com\",\n  \"okk.tw\",\n  \"|http://filmy.olabloga.pl/player\",\n  \"old-cat.net\",\n  \"||olumpo.com\",\n  \".olympicwatch.org\",\n  \"omgili.com\",\n  \"||omnitalk.com\",\n  \"||omnitalk.org\",\n  \"||omny.fm\",\n  \"cling.omy.sg\",\n  \"forum.omy.sg\",\n  \"news.omy.sg\",\n  \"showbiz.omy.sg\",\n  \"||on.cc\",\n  \"||onedrive.live.com\",\n  \"||onion.city\",\n  \".onlinecha.com\",\n  \"||onlineyoutube.com\",\n  \"||onlygayvideo.com\",\n  \".onlytweets.com\",\n  \"|http://onlytweets.com\",\n  \"onmoon.net\",\n  \"onmoon.com\",\n  \".onthehunt.com\",\n  \"|http://onthehunt.com\",\n  \".oopsforum.com\",\n  \"open.com.hk\",\n  \"openallweb.com\",\n  \"opendemocracy.net\",\n  \"||opendemocracy.net\",\n  \".openervpn.in\",\n  \"openid.net\",\n  \"||openid.net\",\n  \".openleaks.org\",\n  \"||openleaks.org\",\n  \"||opentech.fund\",\n  \"openvpn.net\",\n  \"||openvpn.net\",\n  \"||openwebster.com\",\n  \".openwrt.org.cn\",\n  \"@@||openwrt.org.cn\",\n  \"my.opera.com/dahema\",\n  \"||demo.opera-mini.net\",\n  \".opus-gaming.com\",\n  \"|http://opus-gaming.com\",\n  \"www.orchidbbs.com\",\n  \".organcare.org.tw\",\n  \"organharvestinvestigation.net\",\n  \".orgasm.com\",\n  \".orgfree.com\",\n  \"||orient-doll.com\",\n  \"orientaldaily.com.my\",\n  \"||orientaldaily.com.my\",\n  \"||orn.jp\",\n  \"t.orzdream.com\",\n  \"||t.orzdream.com\",\n  \"tui.orzdream.com\",\n  \"||orzistic.org\",\n  \"||osfoora.com\",\n  \".otnd.org\",\n  \"||otnd.org\",\n  \"||otto.de\",\n  \"||ourdearamy.com\",\n  \"oursogo.com\",\n  \".oursteps.com.au\",\n  \"||oursteps.com.au\",\n  \".oursweb.net\",\n  \"||ourtv.hk\",\n  \"xinqimeng.over-blog.com\",\n  \"||overdaily.org\",\n  \"||overplay.net\",\n  \"share.ovi.com/media\",\n  \"||ovpn.com\",\n  \"|http://owl.li\",\n  \"|http://ht.ly\",\n  \"|http://htl.li\",\n  \"|http://mash.to\",\n  \"www.owind.com\",\n  \"||owltail.com\",\n  \"||oxfordscholarship.com\",\n  \"|http://www.oxid.it\",\n  \"oyax.com\",\n  \"oyghan.com/wps\",\n  \".ozchinese.com/bbs\",\n  \"||ow.ly\",\n  \"bbs.ozchinese.com\",\n  \".ozvoice.org\",\n  \"||ozvoice.org\",\n  \".ozxw.com\",\n  \".ozyoyo.com\",\n  \"||pachosting.com\",\n  \".pacificpoker.com\",\n  \".packetix.net\",\n  \"||pacopacomama.com\",\n  \".padmanet.com\",\n  \"page2rss.com\",\n  \"||pagodabox.com\",\n  \".palacemoon.com\",\n  \"forum.palmislife.com\",\n  \"||eriversoft.com\",\n  \".paldengyal.com\",\n  \"paljorpublications.com\",\n  \".paltalk.com\",\n  \"||pandapow.co\",\n  \".pandapow.net\",\n  \".pandavpn-jp.com\",\n  \"||pandavpn-jp.com\",\n  \"||pandavpnpro.com\",\n  \".panluan.net\",\n  \"||panluan.net\",\n  \"||pao-pao.net\",\n  \"paper.li\",\n  \"paperb.us\",\n  \".paradisehill.cc\",\n  \".paradisepoker.com\",\n  \"||parler.com\",\n  \"||parsevideo.com\",\n  \".partycasino.com\",\n  \".partypoker.com\",\n  \".passion.com\",\n  \"||passion.com\",\n  \".passiontimes.hk\",\n  \"pastebin.com\",\n  \".pastie.org\",\n  \"||pastie.org\",\n  \"||blog.pathtosharepoint.com\",\n  \"pbs.org/wgbh/pages/frontline/tankman\",\n  \"pbs.org/wgbh/pages/frontline/tibet\",\n  \"video.pbs.org\",\n  \"pbwiki.com\",\n  \"||pbworks.com\",\n  \"||developers.box.net\",\n  \"||wiki.oauth.net\",\n  \"||wiki.phonegap.com\",\n  \"||wiki.jqueryui.com\",\n  \"||pbxes.com\",\n  \"||pbxes.org\",\n  \"pcdvd.com.tw\",\n  \".pchome.com.tw\",\n  \"|http://pcij.org\",\n  \".pcstore.com.tw\",\n  \"||pct.org.tw\",\n  \"pdetails.com\",\n  \"||pdproxy.com\",\n  \"||peace.ca\",\n  \"peacefire.org\",\n  \"peacehall.com\",\n  \"||peacehall.com\",\n  \"|http://pearlher.org\",\n  \".peeasian.com\",\n  \"||peing.net\",\n  \".pekingduck.org\",\n  \"||pekingduck.org\",\n  \".pemulihan.or.id\",\n  \"|http://pemulihan.or.id\",\n  \"||pen.io\",\n  \"penchinese.com\",\n  \"||penchinese.net\",\n  \".penchinese.net\",\n  \"pengyulong.com\",\n  \"penisbot.com\",\n  \"||blog.pentalogic.net\",\n  \".penthouse.com\",\n  \".pentoy.hk/%E4%B8%AD%E5%9C%8B\",\n  \".pentoy.hk/%E6%99%82%E4%BA%8B\",\n  \".peoplebookcafe.com\",\n  \".peoplenews.tw\",\n  \"||peoplenews.tw\",\n  \".peopo.org\",\n  \"||peopo.org\",\n  \".percy.in\",\n  \".perfectgirls.net\",\n  \"perfectvpn.net\",\n  \".persecutionblog.com\",\n  \".persiankitty.com\",\n  \"pfd.org.hk\",\n  \"phapluan.org\",\n  \".phayul.com\",\n  \"||phayul.com\",\n  \"philborges.com\",\n  \"philly.com\",\n  \"||phncdn.com\",\n  \"||photodharma.net\",\n  \"||photofocus.com\",\n  \"||phuquocservices.com\",\n  \"||picacomiccn.com\",\n  \".picidae.net\",\n  \"||img*.picturedip.com\",\n  \"picturesocial.com\",\n  \"||pin-cong.com\",\n  \".pin6.com\",\n  \"||pin6.com\",\n  \".ping.fm\",\n  \"||ping.fm\",\n  \"||pinimg.com\",\n  \".pinkrod.com\",\n  \"||pinoy-n.com\",\n  \"||pinterest.at\",\n  \"||pinterest.ca\",\n  \"||pinterest.co.kr\",\n  \"||pinterest.co.uk\",\n  \".pinterest.com\",\n  \"||pinterest.com\",\n  \"||pinterest.com.mx\",\n  \"||pinterest.de\",\n  \"||pinterest.dk\",\n  \"||pinterest.fr\",\n  \"||pinterest.jp\",\n  \"||pinterest.nl\",\n  \"||pinterest.se\",\n  \".pipii.tv\",\n  \".piposay.com\",\n  \"piraattilahti.org\",\n  \".piring.com\",\n  \"||pixelqi.com\",\n  \"||css.pixnet.in\",\n  \"||pixnet.net\",\n  \".pixnet.net\",\n  \".pk.com\",\n  \"||placemix.com\",\n  \"|http://pictures.playboy.com\",\n  \"||playboy.com\",\n  \".playboyplus.com\",\n  \"||playboyplus.com\",\n  \"||player.fm\",\n  \".playno1.com\",\n  \"||playno1.com\",\n  \"||playpcesor.com\",\n  \"plays.com.tw\",\n  \"||plexvpn.pro\",\n  \"||m.plixi.com\",\n  \"plm.org.hk\",\n  \"plunder.com\",\n  \".plurk.com\",\n  \"||plurk.com\",\n  \".plus28.com\",\n  \".plusbb.com\",\n  \".pmatehunter.com\",\n  \"||pmatehunter.com\",\n  \".pmates.com\",\n  \"||po2b.com\",\n  \"pobieramy.top\",\n  \"||podbean.com\",\n  \"||podictionary.com\",\n  \".pokerstars.com\",\n  \"||pokerstars.com\",\n  \".pokerstars.net\",\n  \"zh.pokerstrategy.com\",\n  \"politicalchina.org\",\n  \"politicalconsultation.org\",\n  \".politiscales.net\",\n  \"||poloniex.com\",\n  \".polymerhk.com\",\n  \"|http://polymerhk.com\",\n  \".popo.tw\",\n  \"||popvote.hk\",\n  \".popyard.com\",\n  \"||popyard.org\",\n  \".porn.com\",\n  \".porn2.com\",\n  \".porn5.com\",\n  \".pornbase.org\",\n  \".pornerbros.com\",\n  \"||pornhd.com\",\n  \".pornhost.com\",\n  \".pornhub.com\",\n  \"||pornhub.com\",\n  \".pornhubdeutsch.net\",\n  \"|http://pornhubdeutsch.net\",\n  \"||pornmm.net\",\n  \".pornoxo.com\",\n  \".pornrapidshare.com\",\n  \"||pornrapidshare.com\",\n  \".pornsharing.com\",\n  \"|http://pornsharing.com\",\n  \".pornsocket.com\",\n  \".pornstarclub.com\",\n  \"||pornstarclub.com\",\n  \".porntube.com\",\n  \".porntubenews.com\",\n  \".porntvblog.com\",\n  \"||porntvblog.com\",\n  \".pornvisit.com\",\n  \".portablevpn.nl\",\n  \"||poskotanews.com\",\n  \".post01.com\",\n  \".post76.com\",\n  \"||post76.com\",\n  \".post852.com\",\n  \"||post852.com\",\n  \"postadult.com\",\n  \".postimg.org\",\n  \"||potvpn.com\",\n  \"||powercx.com\",\n  \".powerphoto.org\",\n  \"||www.powerpointninja.com\",\n  \"||presidentlee.tw\",\n  \"||cdn.printfriendly.com\",\n  \".pritunl.com\",\n  \"provpnaccounts.com\",\n  \"||provpnaccounts.com\",\n  \".proxfree.com\",\n  \"||proxfree.com\",\n  \"proxyanonimo.es\",\n  \".proxynetwork.org.uk\",\n  \"||proxynetwork.org.uk\",\n  \"||pts.org.tw\",\n  \".pttvan.org\",\n  \"pubu.com.tw\",\n  \"puffinbrowser.com\",\n  \"pureinsight.org\",\n  \".pushchinawall.com\",\n  \".putty.org\",\n  \"||putty.org\",\n  \"||calebelston.com\",\n  \"||blog.fizzik.com\",\n  \"||nf.id.au\",\n  \"||sogrady.me\",\n  \"||vatn.org\",\n  \"||ventureswell.com\",\n  \"||whereiswerner.com\",\n  \".power.com\",\n  \"||power.com\",\n  \"powerapple.com\",\n  \"||powerapple.com\",\n  \"||abc.pp.ru\",\n  \"heix.pp.ru\",\n  \"||prayforchina.net\",\n  \"||premeforwindows7.com\",\n  \"||presentationzen.com\",\n  \"||prestige-av.com\",\n  \"prisoner-state-secret-journal-premier\",\n  \".prisoneralert.com\",\n  \"||pritunl.com\",\n  \"||privacybox.de\",\n  \".private.com/home\",\n  \"||privateinternetaccess.com\",\n  \"privatepaste.com\",\n  \"||privatepaste.com\",\n  \"privatetunnel.com\",\n  \"||privatetunnel.com\",\n  \"||privatevpn.com\",\n  \"||procopytips.com\",\n  \"||project-syndicate.org\",\n  \"provideocoalition.com\",\n  \"||prosiben.de\",\n  \"proxifier.com\",\n  \"api.proxlet.com\",\n  \"||proxomitron.info\",\n  \".proxpn.com\",\n  \"||proxpn.com\",\n  \".proxylist.org.uk\",\n  \"||proxylist.org.uk\",\n  \".proxypy.net\",\n  \"||proxypy.net\",\n  \"proxyroad.com\",\n  \".proxytunnel.net\",\n  \"||proyectoclubes.com\",\n  \"prozz.net\",\n  \"psblog.name\",\n  \"||psblog.name\",\n  \"||pshvpn.com\",\n  \"||psiphon.ca\",\n  \".psiphon3.com\",\n  \"||psiphon3.com\",\n  \".psiphontoday.com\",\n  \"||pt.im\",\n  \".ptt.cc\",\n  \"||ptt.cc\",\n  \".puffstore.com\",\n  \".puuko.com\",\n  \"||pullfolio.com\",\n  \".punyu.com/puny\",\n  \"||pureconcepts.net\",\n  \"||pureinsight.org\",\n  \"||purepdf.com\",\n  \"||purevpn.com\",\n  \".purplelotus.org\",\n  \".pursuestar.com\",\n  \"||pursuestar.com\",\n  \"||nitter.pussthecat.org\",\n  \".pussyspace.com\",\n  \".putihome.org\",\n  \".putlocker.com/file\",\n  \"pwned.com\",\n  \"python.com\",\n  \".python.com.tw\",\n  \"|http://python.com.tw\",\n  \"pythonhackers.com/p\",\n  \"ss.pythonic.life/\",\n  \".qanote.com\",\n  \"||qanote.com\",\n  \".qgirl.com.tw\",\n  \"||qianbai.tw\",\n  \"||qiandao.today\",\n  \"||qiangwaikan.com\",\n  \".qi-gong.me\",\n  \"||qi-gong.me\",\n  \"||qiangyou.org\",\n  \".qidian.ca\",\n  \".qienkuen.org\",\n  \"||qienkuen.org\",\n  \"||qiwen.lu\",\n  \"qixianglu.cn\",\n  \"bbs.qmzdd.com\",\n  \".qkshare.com\",\n  \"qoos.com\",\n  \"||qoos.com\",\n  \"blog.qooza.hk/dafengqixi\",\n  \"||efksoft.com\",\n  \"||qstatus.com\",\n  \"||qtweeter.com\",\n  \"||qtrac.eu\",\n  \".quannengshen.org\",\n  \"|http://quannengshen.org\",\n  \"quantumbooter.net\",\n  \"||quitccp.net\",\n  \".quitccp.net\",\n  \"||quitccp.org\",\n  \".quitccp.org\",\n  \".quora.com/Chinas-Future\",\n  \".quran.com\",\n  \"|http://quran.com\",\n  \".quranexplorer.com\",\n  \"qusi8.net\",\n  \".qvodzy.org\",\n  \"nemesis2.qx.net/pages/MyEnTunnel\",\n  \"qxbbs.org\",\n  \"||r0.ru\",\n  \".ra.gg\",\n  \"|http://ra.gg/\",\n  \".radicalparty.org\",\n  \"||rael.org\",\n  \"radicalparty.org\",\n  \"||radio.garden\",\n  \"radioaustralia.net.au\",\n  \".radiohilight.net\",\n  \"||radiohilight.net\",\n  \"||radioline.co\",\n  \"opml.radiotime.com\",\n  \"||radiovaticana.org\",\n  \"||radiovncr.com\",\n  \"||raggedbanner.com\",\n  \"||raidcall.com.tw\",\n  \".raidtalk.com.tw\",\n  \".rainbowplan.org/bbs\",\n  \"|https://raindrop.io/\",\n  \".raizoji.or.jp\",\n  \"|http://raizoji.or.jp\",\n  \"rangwang.biz\",\n  \"rangzen.com\",\n  \"rangzen.net\",\n  \"rangzen.org\",\n  \"|http://blog.ranxiang.com/\",\n  \"ranyunfei.com\",\n  \"||ranyunfei.com\",\n  \".rapbull.net\",\n  \"|http://rapidgator.net/\",\n  \"||rapidmoviez.com\",\n  \"rapidvpn.com\",\n  \"||rapidvpn.com\",\n  \"||rarbgprx.org\",\n  \".raremovie.cc\",\n  \"|http://raremovie.cc\",\n  \".raremovie.net\",\n  \"|http://raremovie.net\",\n  \"||rationalwiki.org\",\n  \"||rawgit.com\",\n  \"||rawgithub.com\",\n  \"||razyboard.com\",\n  \"rcinet.ca\",\n  \".read100.com\",\n  \".readingtimes.com.tw\",\n  \"||readingtimes.com.tw\",\n  \"||readmoo.com\",\n  \".readydown.com\",\n  \"|http://readydown.com\",\n  \".realcourage.org\",\n  \".realitykings.com\",\n  \"||realitykings.com\",\n  \".realraptalk.com\",\n  \".realsexpass.com\",\n  \"||reason.com\",\n  \".recordhistory.org\",\n  \".recovery.org.tw\",\n  \"|http://online.recoveryversion.org\",\n  \"||recoveryversion.com.tw\",\n  \"||red-lang.org\",\n  \"redballoonsolidarity.org\",\n  \"||redbubble.com\",\n  \".redchinacn.net\",\n  \"|http://redchinacn.net\",\n  \"redchinacn.org\",\n  \"redtube.com\",\n  \"referer.us\",\n  \"||referer.us\",\n  \"||reflectivecode.com\",\n  \"relaxbbs.com\",\n  \".relay.com.tw\",\n  \".releaseinternational.org\",\n  \"religioustolerance.org\",\n  \"renminbao.com\",\n  \"||renminbao.com\",\n  \".renyurenquan.org\",\n  \"||renyurenquan.org\",\n  \"|http://certificate.revocationcheck.com\",\n  \"subacme.rerouted.org\",\n  \"||resilio.com\",\n  \".reuters.com\",\n  \"||reuters.com\",\n  \"||reutersmedia.net\",\n  \".revleft.com\",\n  \"||resistchina.org\",\n  \"retweetist.com\",\n  \"||retweetrank.com\",\n  \"revver.com\",\n  \".rfa.org\",\n  \"||rfa.org\",\n  \".rfachina.com\",\n  \".rfamobile.org\",\n  \"rfaweb.org\",\n  \"||rferl.org\",\n  \".rfi.fr\",\n  \"||rfi.fr\",\n  \"|http://rfi.my/\",\n  \"|http://vds.rightster.com/\",\n  \".rigpa.org\",\n  \".rileyguide.com\",\n  \"riku.me/\",\n  \".ritouki.jp\",\n  \"||ritter.vg\",\n  \".rlwlw.com\",\n  \"||rlwlw.com\",\n  \".rmjdw.com\",\n  \".rmjdw132.info\",\n  \".roadshow.hk\",\n  \".roboforex.com\",\n  \"||robustnessiskey.com\",\n  \"||rocket-inc.net\",\n  \"|http://www2.rocketbbs.com/11/bbs.cgi?id=5mus\",\n  \"|http://www2.rocketbbs.com/11/bbs.cgi?id=freemgl\",\n  \"||rojo.com\",\n  \"||ronjoneswriter.com\",\n  \"||rolfoundation.org\",\n  \"||rolia.net\",\n  \"||rolsociety.org\",\n  \".roodo.com\",\n  \".rosechina.net\",\n  \".rotten.com\",\n  \".rsf.org\",\n  \"||rsf.org\",\n  \".rsf-chinese.org\",\n  \"||rsf-chinese.org\",\n  \".rsgamen.org\",\n  \"||rsshub.app\",\n  \"||phosphation13.rssing.com\",\n  \".rssmeme.com\",\n  \"||rssmeme.com\",\n  \"||rtalabel.org\",\n  \".rthk.hk\",\n  \"||rthk.hk\",\n  \".rthk.org.hk\",\n  \"||rthk.org.hk\",\n  \".rti.org.tw\",\n  \"||rti.org.tw\",\n  \"||rti.tw\",\n  \".rtycminnesota.org\",\n  \".ruanyifeng.com/blog*some_ways_to_break_the_great_firewall\",\n  \"rukor.org\",\n  \"||rule34.xxx\",\n  \".runbtx.com\",\n  \".rushbee.com\",\n  \".ruten.com.tw\",\n  \"||ruten.com.tw\",\n  \"rutube.ru\",\n  \".ruyiseek.com\",\n  \".rxhj.net\",\n  \"|http://rxhj.net\",\n  \".s1s1s1.com\",\n  \"||s-cute.com\",\n  \".s-dragon.org\",\n  \"||s1heng.com\",\n  \"|http://www.s4miniarchive.com\",\n  \"||s8forum.com\",\n  \"cdn1.lp.saboom.com\",\n  \"||sacks.com\",\n  \"sacom.hk\",\n  \"||sacom.hk\",\n  \"||sadpanda.us\",\n  \".safervpn.com\",\n  \"||safervpn.com\",\n  \".saintyculture.com\",\n  \"|http://saintyculture.com\",\n  \".saiq.me\",\n  \"||saiq.me\",\n  \"||sakuralive.com\",\n  \".sakya.org\",\n  \".salvation.org.hk\",\n  \"||salvation.org.hk\",\n  \".samair.ru/proxy/type-01\",\n  \".sambhota.org\",\n  \".cn.sandscotaicentral.com\",\n  \"|http://cn.sandscotaicentral.com\",\n  \"||sankei.com\",\n  \".sanmin.com.tw\",\n  \"sapikachu.net\",\n  \"savemedia.com\",\n  \"||savethesounds.info\",\n  \".savetibet.de\",\n  \"||savetibet.de\",\n  \"savetibet.fr\",\n  \"savetibet.nl\",\n  \".savetibet.org\",\n  \"||savetibet.org\",\n  \"savetibet.ru\",\n  \".savetibetstore.org\",\n  \"||savetibetstore.org\",\n  \"||saveuighur.org\",\n  \"savevid.com\",\n  \"||say2.info\",\n  \".sbme.me\",\n  \"|http://sbme.me\",\n  \".sbs.com.au/yourlanguage\",\n  \".scasino.com\",\n  \"|http://www.sciencemag.org/content/344/6187/953\",\n  \".sciencenets.com\",\n  \".scmp.com\",\n  \"||scmp.com\",\n  \".scmpchinese.com\",\n  \"||scramble.io\",\n  \".scribd.com\",\n  \"||scribd.com\",\n  \"||scriptspot.com\",\n  \"||search.com\",\n  \".searchtruth.com\",\n  \"||searx.me\",\n  \"||seattlefdc.com\",\n  \".secretchina.com\",\n  \"||secretchina.com\",\n  \"||secretgarden.no\",\n  \".secretsline.biz\",\n  \"||secretsline.biz\",\n  \"||secureservercdn.net\",\n  \"||securetunnel.com\",\n  \"securityinabox.org\",\n  \"|https://securityinabox.org\",\n  \".securitykiss.com\",\n  \"||securitykiss.com\",\n  \"||seed4.me\",\n  \"news.seehua.com\",\n  \"seesmic.com\",\n  \"||seevpn.com\",\n  \"||seezone.net\",\n  \"sejie.com\",\n  \".sendspace.com\",\n  \"|http://tweets.seraph.me/\",\n  \"sesawe.net\",\n  \"||sesawe.net\",\n  \".sesawe.org\",\n  \"||sethwklein.net\",\n  \".setn.com\",\n  \".settv.com.tw\",\n  \"forum.setty.com.tw\",\n  \".sevenload.com\",\n  \"||sevenload.com\",\n  \".sex.com\",\n  \".sex-11.com\",\n  \"||sex3.com\",\n  \"||sex8.cc\",\n  \".sexandsubmission.com\",\n  \".sexbot.com\",\n  \".sexhu.com\",\n  \".sexhuang.com\",\n  \"sexinsex.net\",\n  \"||sexinsex.net\",\n  \".sextvx.com\",\n  \"67.220.91.15\",\n  \"67.220.91.18\",\n  \"67.220.91.23\",\n  \"|http://*.sf.net\",\n  \".sfileydy.com\",\n  \"||sfshibao.com\",\n  \".sftindia.org\",\n  \".sftuk.org\",\n  \"||sftuk.org\",\n  \"||shadeyouvpn.com\",\n  \"shadow.ma\",\n  \".shadowsky.xyz\",\n  \".shadowsocks.asia\",\n  \"||www.shadowsocks.com\",\n  \".shadowsocks.com\",\n  \"||shadowsocks.com.hk\",\n  \".shadowsocks.org\",\n  \"||shadowsocks.org\",\n  \"||shadowsocks-r.com\",\n  \"|http://cn.shafaqna.com\",\n  \".shambalapost.com\",\n  \".shambhalasun.com\",\n  \".shangfang.org\",\n  \"||shangfang.org\",\n  \"shapeservices.com\",\n  \".sharebee.com\",\n  \"||sharecool.org\",\n  \"sharpdaily.com.hk\",\n  \"||sharpdaily.com.hk\",\n  \".sharpdaily.hk\",\n  \".sharpdaily.tw\",\n  \".shat-tibet.com\",\n  \"sheikyermami.com\",\n  \".shellfire.de\",\n  \"||shellfire.de\",\n  \".shenshou.org\",\n  \"shenyun.com\",\n  \"shenyunperformingarts.org\",\n  \"||shenyunperformingarts.org\",\n  \"||shenyunshop.com\",\n  \"shenzhoufilm.com\",\n  \"||shenzhoufilm.com\",\n  \"||shenzhouzhengdao.org\",\n  \"||sherabgyaltsen.com\",\n  \".shiatv.net\",\n  \".shicheng.org\",\n  \"shinychan.com\",\n  \"shipcamouflage.com\",\n  \".shireyishunjian.com\",\n  \".shitaotv.org\",\n  \"||shixiao.org\",\n  \"||shizhao.org\",\n  \"shizhao.org\",\n  \"shkspr.mobi/dabr\",\n  \"||shodanhq.com\",\n  \"||shooshtime.com\",\n  \".shop2000.com.tw\",\n  \"||shopee.tw\",\n  \".shopping.com\",\n  \".showhaotu.com\",\n  \".showtime.jp\",\n  \"||showwe.tw\",\n  \".shutterstock.com\",\n  \"||shutterstock.com\",\n  \"ch.shvoong.com\",\n  \".shwchurch.org\",\n  \"||shwchurch.org\",\n  \".shwchurch3.com\",\n  \"|http://shwchurch3.com\",\n  \".siddharthasintent.org\",\n  \"||sidelinesnews.com\",\n  \".sidelinessportseatery.com\",\n  \"||signal.org\",\n  \".sijihuisuo.club\",\n  \".sijihuisuo.com\",\n  \".silkbook.com\",\n  \"||simbolostwitter.com\",\n  \"simplecd.org\",\n  \"||simplecd.org\",\n  \"@@||simplecd.me\",\n  \"simpleproductivityblog.com\",\n  \"bbs.sina.com/\",\n  \"bbs.sina.com%2F\",\n  \"blog.sina.com.tw\",\n  \"dailynews.sina.com/\",\n  \"dailynews.sina.com%2F\",\n  \"forum.sina.com.hk\",\n  \"home.sina.com\",\n  \"||magazines.sina.com.tw\",\n  \"news.sina.com.hk\",\n  \"news.sina.com.tw\",\n  \"news.sinchew.com.my\",\n  \".sinchew.com.my/node/\",\n  \".sinchew.com.my/taxonomy/term\",\n  \".singaporepools.com.sg\",\n  \"||singaporepools.com.sg\",\n  \".singfortibet.com\",\n  \".singpao.com.hk\",\n  \"singtao.com\",\n  \"||singtao.com\",\n  \"news.singtao.ca\",\n  \".singtaousa.com\",\n  \"||singtaousa.com\",\n  \"sino-monthly.com\",\n  \"||sinoca.com\",\n  \"||sinocast.com\",\n  \"sinocism.com\",\n  \"sinomontreal.ca\",\n  \".sinonet.ca\",\n  \".sinopitt.info\",\n  \".sinoants.com\",\n  \"||sinoants.com\",\n  \"||sinoinsider.com\",\n  \".sinoquebec.com\",\n  \".sierrafriendsoftibet.org\",\n  \"sis.xxx\",\n  \"||sis001.com\",\n  \"sis001.us\",\n  \".site2unblock.com\",\n  \"||site90.net\",\n  \".sitebro.tw\",\n  \"||sitekreator.com\",\n  \"||siteks.uk.to\",\n  \"||sitemaps.org\",\n  \".sjrt.org\",\n  \"|http://sjrt.org\",\n  \"||sjum.cn\",\n  \"||sketchappsources.com\",\n  \"||skimtube.com\",\n  \"||lab.skk.moe\",\n  \"||skybet.com\",\n  \"|http://users.skynet.be/reves/tibethome.html\",\n  \".skyking.com.tw\",\n  \"bbs.skykiwi.com\",\n  \"|http://www.skype.com/intl/\",\n  \"|http://www.skype.com/zh-Hant\",\n  \"||skyvegas.com\",\n  \".xskywalker.com\",\n  \"||xskywalker.com\",\n  \"||skyxvpn.com\",\n  \"m.slandr.net\",\n  \".slaytizle.com\",\n  \".sleazydream.com\",\n  \"||slheng.com\",\n  \"||slideshare.net\",\n  \"forum.slime.com.tw\",\n  \".slinkset.com\",\n  \"||slickvpn.com\",\n  \".slutload.com\",\n  \"||smartdnsproxy.com\",\n  \".smarthide.com\",\n  \"||app.smartmailcloud.com\",\n  \"smchbooks.com\",\n  \".smh.com.au/world/death-of-chinese-playboy-leaves-fresh-scratches-in-party-paintwork-20120903-25a8v\",\n  \"smhric.org\",\n  \".smith.edu/dalailama\",\n  \".smyxy.org\",\n  \"||snapchat.com\",\n  \".snaptu.com\",\n  \"||snaptu.com\",\n  \"||sndcdn.com\",\n  \"sneakme.net\",\n  \"snowlionpub.com\",\n  \"home.so-net.net.tw/yisa_tsai\",\n  \"||soc.mil\",\n  \"||socialblade.com\",\n  \".socks-proxy.net\",\n  \"||socks-proxy.net\",\n  \".sockscap64.com\",\n  \"||sockslist.net\",\n  \".socrec.org\",\n  \"|http://socrec.org\",\n  \".sod.co.jp\",\n  \".softether.org\",\n  \"||softether.org\",\n  \".softether-download.com\",\n  \"||softether-download.com\",\n  \"||cdn.softlayer.net\",\n  \"||sogclub.com\",\n  \"sohcradio.com\",\n  \"||sohcradio.com\",\n  \".sokmil.com\",\n  \"||sorting-algorithms.com\",\n  \".sostibet.org\",\n  \".soumo.info\",\n  \"||soup.io\",\n  \"@@||static.soup.io\",\n  \".sobees.com\",\n  \"||sobees.com\",\n  \"socialwhale.com\",\n  \".softether.co.jp\",\n  \"||softwarebychuck.com\",\n  \"blog.sogoo.org\",\n  \"soh.tw\",\n  \"||soh.tw\",\n  \"sohfrance.org\",\n  \"||sohfrance.org\",\n  \"chinese.soifind.com\",\n  \"sokamonline.com\",\n  \".solidaritetibet.org\",\n  \".solidfiles.com\",\n  \"||somee.com\",\n  \".songjianjun.com\",\n  \"||songjianjun.com\",\n  \".sonicbbs.cc\",\n  \".sonidodelaesperanza.org\",\n  \".sopcast.com\",\n  \".sopcast.org\",\n  \".sorazone.net\",\n  \"||sos.org\",\n  \"bbs.sou-tong.org\",\n  \".soubory.com\",\n  \"|http://soubory.com\",\n  \".soul-plus.net\",\n  \".soulcaliburhentai.net\",\n  \"||soulcaliburhentai.net\",\n  \"||soundcloud.com\",\n  \".soundofhope.kr\",\n  \"soundofhope.org\",\n  \"||soundofhope.org\",\n  \"||soupofmedia.com\",\n  \"|http://sourceforge.net/p*/shadowsocksgui/\",\n  \".sourcewadio.com\",\n  \"||south-plus.org\",\n  \"southnews.com.tw\",\n  \"sowers.org.hk\",\n  \"||wlx.sowiki.net\",\n  \"||spankbang.com\",\n  \".spankingtube.com\",\n  \".spankwire.com\",\n  \"||spb.com\",\n  \"||speakerdeck.com\",\n  \"||speedify.com\",\n  \"spem.at\",\n  \"||spencertipping.com\",\n  \"||spendee.com\",\n  \"||spicevpn.com\",\n  \".spideroak.com\",\n  \"||spideroak.com\",\n  \".spike.com\",\n  \".spotflux.com\",\n  \"||spotflux.com\",\n  \".spring4u.info\",\n  \"|http://spring4u.info\",\n  \"||sproutcore.com\",\n  \"||sproxy.info\",\n  \"||squirrelvpn.com\",\n  \"||srocket.us\",\n  \".ss-link.com\",\n  \"||ss-link.com\",\n  \".ssglobal.co/wp\",\n  \"|http://ssglobal.co\",\n  \".ssglobal.me\",\n  \"||ssh91.com\",\n  \".sspro.ml\",\n  \"|http://sspro.ml\",\n  \".ssrshare.com\",\n  \"||ssrshare.com\",\n  \"||sss.camp\",\n  \"||sstm.moe\",\n  \"||sstmlt.moe\",\n  \"sstmlt.net\",\n  \"||sstmlt.net\",\n  \"|http://stackoverflow.com/users/895245\",\n  \".stage64.hk\",\n  \"||stage64.hk\",\n  \"||standupfortibet.org\",\n  \"||standwithhk.org\",\n  \"stanford.edu/group/falun\",\n  \"usinfo.state.gov\",\n  \"||statueofdemocracy.org\",\n  \".starfishfx.com\",\n  \".starp2p.com\",\n  \"||starp2p.com\",\n  \".startpage.com\",\n  \"||startpage.com\",\n  \".startuplivingchina.com\",\n  \"|http://startuplivingchina.com\",\n  \"||static-economist.com\",\n  \"||stboy.net\",\n  \"||stc.com.sa\",\n  \"||steel-storm.com\",\n  \".steganos.com\",\n  \"||steganos.com\",\n  \".steganos.net\",\n  \".stepchina.com\",\n  \"ny.stgloballink.com\",\n  \"hd.stheadline.com/news/realtime\",\n  \"sthoo.com\",\n  \"||sthoo.com\",\n  \".stickam.com\",\n  \"stickeraction.com/sesawe\",\n  \".stileproject.com\",\n  \".sto.cc\",\n  \".stoporganharvesting.org\",\n  \"||storagenewsletter.com\",\n  \".storm.mg\",\n  \"||storm.mg\",\n  \".stoptibetcrisis.net\",\n  \"||stoptibetcrisis.net\",\n  \"||storify.com\",\n  \".stormmediagroup.com\",\n  \"||stoweboyd.com\",\n  \"||straitstimes.com\",\n  \"stranabg.com\",\n  \"||straplessdildo.com\",\n  \"||streamable.com\",\n  \"||streamate.com\",\n  \"||streamingthe.net\",\n  \"streema.com/tv/NTDTV_Chinese\",\n  \"cn.streetvoice.com/article\",\n  \"cn.streetvoice.com/diary\",\n  \"cn2.streetvoice.com\",\n  \"tw.streetvoice.com\",\n  \".strikingly.com\",\n  \"||strongvpn.com\",\n  \".strongwindpress.com\",\n  \".student.tw/db\",\n  \"||studentsforafreetibet.org\",\n  \"||stumbleupon.com\",\n  \"stupidvideos.com\",\n  \".successfn.com\",\n  \"panamapapers.sueddeutsche.de\",\n  \".sugarsync.com\",\n  \"||sugarsync.com\",\n  \".sugobbs.com\",\n  \"||sugumiru18.com\",\n  \"||suissl.com\",\n  \"summify.com\",\n  \".sumrando.com\",\n  \"||sumrando.com\",\n  \"sun1911.com\",\n  \"||sundayguardianlive.com\",\n  \".sunporno.com\",\n  \"||sunmedia.ca\",\n  \"||sunporno.com\",\n  \".sunskyforum.com\",\n  \".sunta.com.tw\",\n  \".sunvpn.net\",\n  \".suoluo.org\",\n  \".superfreevpn.com\",\n  \".supervpn.net\",\n  \"||supervpn.net\",\n  \".superzooi.com\",\n  \"|http://superzooi.com\",\n  \".suppig.net\",\n  \".suprememastertv.com\",\n  \"|http://suprememastertv.com\",\n  \".surfeasy.com\",\n  \"||surfeasy.com\",\n  \".surfeasy.com.au\",\n  \"|http://surfeasy.com.au\",\n  \"||surfshark.com\",\n  \"||surrenderat20.net\",\n  \".svsfx.com\",\n  \".swissinfo.ch\",\n  \"||swissinfo.ch\",\n  \".swissvpn.net\",\n  \"||swissvpn.net\",\n  \"switchvpn.net\",\n  \"||switchvpn.net\",\n  \".sydneytoday.com\",\n  \"||sydneytoday.com\",\n  \".sylfoundation.org\",\n  \"||sylfoundation.org\",\n  \"||syncback.com\",\n  \"sysresccd.org\",\n  \".sytes.net\",\n  \"blog.syx86.com/2009/09/puff\",\n  \"blog.syx86.cn/2009/09/puff\",\n  \".szbbs.net\",\n  \".szetowah.org.hk\",\n  \"||t-g.com\",\n  \".t35.com\",\n  \".t66y.com\",\n  \"||t66y.com\",\n  \"||esg.t91y.com\",\n  \".taa-usa.org\",\n  \"|http://taa-usa.org\",\n  \".taaze.tw\",\n  \"||taaze.tw\",\n  \"|http://www.tablesgenerator.com/\",\n  \"tabtter.jp\",\n  \".tacem.org\",\n  \".taconet.com.tw\",\n  \"||taedp.org.tw\",\n  \".tafm.org\",\n  \".tagwa.org.au\",\n  \"tagwalk.com\",\n  \"||tagwalk.com\",\n  \"tahr.org.tw\",\n  \".taipeisociety.org\",\n  \"||taipeisociety.org\",\n  \".taiwanbible.com\",\n  \".taiwancon.com\",\n  \".taiwandaily.net\",\n  \"||taiwandaily.net\",\n  \".taiwandc.org\",\n  \"||taiwanhot.net\",\n  \".taiwanjustice.com\",\n  \"taiwankiss.com\",\n  \"taiwannation.com\",\n  \"taiwannation.com.tw\",\n  \"||taiwanncf.org.tw\",\n  \"||taiwannews.com.tw\",\n  \"|http://www.taiwanonline.cc/\",\n  \"taiwantp.net\",\n  \"||taiwantt.org.tw\",\n  \"taiwanus.net\",\n  \"taiwanyes.com\",\n  \"taiwan-sex.com\",\n  \".talk853.com\",\n  \".talkboxapp.com\",\n  \"||talkboxapp.com\",\n  \".talkcc.com\",\n  \"||talkcc.com\",\n  \".talkonly.net\",\n  \"||talkonly.net\",\n  \"||tamiaode.tk\",\n  \"||tanc.org\",\n  \"tangben.com\",\n  \".tangren.us\",\n  \".taoism.net\",\n  \"|http://taoism.net\",\n  \".taolun.info\",\n  \"||taolun.info\",\n  \".tapatalk.com\",\n  \"||tapatalk.com\",\n  \"blog.taragana.com\",\n  \".tascn.com.au\",\n  \"||taup.net\",\n  \"|http://www.taup.org.tw\",\n  \".taweet.com\",\n  \"||taweet.com\",\n  \".tbcollege.org\",\n  \"||tbcollege.org\",\n  \".tbi.org.hk\",\n  \".tbicn.org\",\n  \".tbjyt.org\",\n  \"||tbpic.info\",\n  \".tbrc.org\",\n  \"tbs-rainbow.org\",\n  \".tbsec.org\",\n  \"||tbsec.org\",\n  \"tbskkinabalu.page.tl\",\n  \".tbsmalaysia.org\",\n  \".tbsn.org\",\n  \"||tbsn.org\",\n  \".tbsseattle.org\",\n  \".tbssqh.org\",\n  \"|http://tbssqh.org\",\n  \"tbswd.org\",\n  \".tbtemple.org.uk\",\n  \".tbthouston.org\",\n  \".tccwonline.org\",\n  \".tcewf.org\",\n  \"tchrd.org\",\n  \"tcnynj.org\",\n  \"||tcpspeed.co\",\n  \".tcpspeed.com\",\n  \"||tcpspeed.com\",\n  \".tcsofbc.org\",\n  \".tcsovi.org\",\n  \".tdm.com.mo\",\n  \"teamamericany.com\",\n  \"||static.techspot.com\",\n  \"||techviz.net\",\n  \"||teck.in\",\n  \".teeniefuck.net\",\n  \"teensinasia.com\",\n  \"||tehrantimes.com\",\n  \".telecomspace.com\",\n  \"||telegraph.co.uk\",\n  \"||telegra.ph\",\n  \".tenacy.com\",\n  \"||tenzinpalmo.com\",\n  \".tew.org\",\n  \"||tew.org\",\n  \"||tfiflve.com\",\n  \".thaicn.com\",\n  \"||theatlantic.com\",\n  \"||theatrum-belli.com\",\n  \"||cn.theaustralian.com.au\",\n  \"theblemish.com\",\n  \"||thebcomplex.com\",\n  \"||theblaze.com\",\n  \".thebobs.com\",\n  \"||thebobs.com\",\n  \".thechinabeat.org\",\n  \"||thechinacollection.org\",\n  \"|http://www.thechinastory.org/yearbooks/yearbook-2012/\",\n  \"||theconversation.com\",\n  \".thedalailamamovie.com\",\n  \"|http://thedalailamamovie.com\",\n  \"||thediplomat.com\",\n  \"||thedw.us\",\n  \"thefrontier.hk/tf\",\n  \"||theguardian.com\",\n  \"||thegay.com\",\n  \"|http://thegioitinhoc.vn/\",\n  \".thegly.com\",\n  \".thehots.info\",\n  \"thehousenews.com\",\n  \"||thehun.net\",\n  \".theinitium.com\",\n  \"||theinitium.com\",\n  \".thenewslens.com\",\n  \"||thenewslens.com\",\n  \".thepiratebay.org\",\n  \"||thepiratebay.org\",\n  \".theporndude.com\",\n  \"||theporndude.com\",\n  \"||theportalwiki.com\",\n  \"||theprint.in\",\n  \"thereallove.kr\",\n  \"therock.net.nz\",\n  \"||thesaturdaypaper.com.au\",\n  \"||thestandnews.com\",\n  \"thetibetcenter.org\",\n  \"thetibetconnection.org\",\n  \".thetibetmuseum.org\",\n  \".thetibetpost.com\",\n  \"||thetibetpost.com\",\n  \"||thetinhat.com\",\n  \"thetrotskymovie.com\",\n  \"thevivekspot.com\",\n  \"||thewgo.org\",\n  \".theync.com\",\n  \"|http://theync.com\",\n  \".thinkingtaiwan.com\",\n  \"||thinkingtaiwan.com\",\n  \".thisav.com\",\n  \"|http://thisav.com\",\n  \".thlib.org\",\n  \"||thomasbernhard.org\",\n  \".thongdreams.com\",\n  \"threatchaos.com\",\n  \"||throughnightsfire.com\",\n  \".thumbzilla.com\",\n  \"||thywords.com\",\n  \".thywords.com.tw\",\n  \"tiananmenmother.org\",\n  \".tiananmenduizhi.com\",\n  \"||tiananmenduizhi.com\",\n  \"||tiananmenuniv.com\",\n  \"||tiananmenuniv.net\",\n  \"||tiandixing.org\",\n  \".tianhuayuan.com\",\n  \".tianlawoffice.com\",\n  \"||tianti.io\",\n  \"tiantibooks.org\",\n  \"||tiantibooks.org\",\n  \"tianyantong.org.cn\",\n  \".tianzhu.org\",\n  \".tibet.at\",\n  \"tibet.ca\",\n  \".tibet.com\",\n  \"||tibet.com\",\n  \"tibet.fr\",\n  \".tibet.net\",\n  \"||tibet.net\",\n  \"tibet.nu\",\n  \".tibet.org\",\n  \"||tibet.org\",\n  \".tibet.sk\",\n  \"tibet.org.tw\",\n  \".tibet.to\",\n  \".tibet-envoy.eu\",\n  \"||tibet-envoy.eu\",\n  \".tibet-foundation.org\",\n  \".tibet-house-trust.co.uk\",\n  \"||tibet-initiative.de\",\n  \".tibet-munich.de\",\n  \".tibet3rdpole.org\",\n  \"|http://tibet3rdpole.org\",\n  \"tibetaction.net\",\n  \"||tibetaction.net\",\n  \".tibetaid.org\",\n  \"tibetalk.com\",\n  \".tibetan.fr\",\n  \"tibetan-alliance.org\",\n  \".tibetanarts.org\",\n  \".tibetanbuddhistinstitute.org\",\n  \"|http://tibetanbuddhistinstitute.org\",\n  \"tibetancommunity.org\",\n  \".tibetanjournal.com\",\n  \".tibetanlanguage.org\",\n  \".tibetanliberation.org\",\n  \"||tibetanliberation.org\",\n  \".tibetcollection.com\",\n  \".tibetanaidproject.org\",\n  \".tibetancommunityuk.net\",\n  \"|http://tibetancommunityuk.net\",\n  \"tibetanculture.org\",\n  \"tibetanfeministcollective.org\",\n  \".tibetanpaintings.com\",\n  \".tibetanphotoproject.com\",\n  \".tibetanpoliticalreview.org\",\n  \".tibetanreview.net\",\n  \"|http://tibetansports.org\",\n  \".tibetanwomen.org\",\n  \"|http://tibetanwomen.org\",\n  \".tibetanyouth.org\",\n  \".tibetanyouthcongress.org\",\n  \"||tibetanyouthcongress.org\",\n  \".tibetcharity.dk\",\n  \"tibetcharity.in\",\n  \".tibetchild.org\",\n  \".tibetcity.com\",\n  \".tibetcorps.org\",\n  \".tibetexpress.net\",\n  \"|http://tibetexpress.net\",\n  \"tibetfocus.com\",\n  \"tibetfund.org\",\n  \".tibetgermany.com\",\n  \"||tibetgermany.de\",\n  \".tibethaus.com\",\n  \".tibetheritagefund.org\",\n  \"||tibethouse.jp\",\n  \"||tibethouse.org\",\n  \"||tibethouse.us\",\n  \".tibetinfonet.net\",\n  \".tibetjustice.org\",\n  \".tibetkomite.dk\",\n  \"||tibetmuseum.org\",\n  \"||tibetnetwork.org\",\n  \".tibetoffice.ch\",\n  \"|http://tibetoffice.ch\",\n  \"tibetoffice.eu\",\n  \"||tibetoffice.org\",\n  \"tibetonline.com\",\n  \"||tibetonline.com\",\n  \".tibetoffice.com.au\",\n  \"|http://tibetoffice.com.au\",\n  \"||tibetonline.tv\",\n  \".tibetonline.tv\",\n  \".tibetoralhistory.org\",\n  \"|http://tibetoralhistory.org\",\n  \".tibetpolicy.eu\",\n  \".tibetrelieffund.co.uk\",\n  \"tibetsites.com\",\n  \".tibetsociety.com\",\n  \"||tibetsociety.com\",\n  \".tibetsun.com\",\n  \".tibetsupportgroup.org\",\n  \"|http://tibetsupportgroup.org\",\n  \".tibetswiss.ch\",\n  \".tibettelegraph.com\",\n  \"tibettimes.net\",\n  \"||tibetwrites.org\",\n  \".ticket.com.tw\",\n  \".tigervpn.com\",\n  \"||tigervpn.com\",\n  \".timdir.com\",\n  \"|http://timdir.com\",\n  \".time.com\",\n  \"|http://time.com\",\n  \"||timesnownews.com\",\n  \".timsah.com\",\n  \"||timtales.com\",\n  \"||blog.tiney.com\",\n  \"tintuc101.com\",\n  \".tiny.cc\",\n  \"|http://tiny.cc\",\n  \"tinychat.com\",\n  \"||tinypaste.com\",\n  \".tistory.com\",\n  \"||tkcs-collins.com\",\n  \".tmagazine.com\",\n  \"||tmagazine.com\",\n  \".tmdfish.com\",\n  \"|http://tmi.me\",\n  \".tmpp.org\",\n  \"|http://tmpp.org\",\n  \".tnaflix.com\",\n  \"||tnaflix.com\",\n  \".tngrnow.com\",\n  \".tngrnow.net\",\n  \".tnp.org\",\n  \"|http://tnp.org\",\n  \".to-porno.com\",\n  \"||to-porno.com\",\n  \"togetter.com\",\n  \".tokyo-247.com\",\n  \".tokyo-hot.com\",\n  \"||tokyo-porn-tube.com\",\n  \"||tokyocn.com\",\n  \"tw.tomonews.net\",\n  \".tongil.or.kr\",\n  \".tono-oka.jp\",\n  \"tonyyan.net\",\n  \".toodoc.com\",\n  \"toonel.net\",\n  \"top81.ws\",\n  \".topnews.in\",\n  \".toppornsites.com\",\n  \"|http://toppornsites.com\",\n  \".torguard.net\",\n  \"||torguard.net\",\n  \"||top.tv\",\n  \".topshareware.com\",\n  \".topsy.com\",\n  \"||topsy.com\",\n  \"||toptip.ca\",\n  \"tora.to\",\n  \".torcn.com\",\n  \"||torlock.com\",\n  \".torproject.org\",\n  \"||torproject.org\",\n  \"||torrentkitty.tv\",\n  \"torrentprivacy.com\",\n  \"||torrentprivacy.com\",\n  \"|http://torrentproject.se\",\n  \"||torrenty.org\",\n  \"||torrentz.eu\",\n  \"||torvpn.com\",\n  \"||totalvpn.com\",\n  \".toutiaoabc.com\",\n  \"towngain.com\",\n  \"toypark.in\",\n  \"toytractorshow.com\",\n  \".tparents.org\",\n  \".tpi.org.tw\",\n  \"||tpi.org.tw\",\n  \"traffichaus.com\",\n  \"||transparency.org\",\n  \"||treemall.com.tw\",\n  \"trendsmap.com\",\n  \"||trendsmap.com\",\n  \".trialofccp.org\",\n  \"||trialofccp.org\",\n  \".trimondi.de/SDLE\",\n  \".trouw.nl\",\n  \"|http://trouw.nl\",\n  \".trt.net.tr\",\n  \"trtc.com.tw\",\n  \".truebuddha-md.org\",\n  \"|http://truebuddha-md.org\",\n  \"trulyergonomic.com\",\n  \".truth101.co.tv\",\n  \"|http://truth101.co.tv\",\n  \".truthontour.org\",\n  \"|http://truthontour.org\",\n  \".truveo.com\",\n  \".tsctv.net\",\n  \".tsemtulku.com\",\n  \"tsquare.tv\",\n  \".tsu.org.tw\",\n  \"tsunagarumon.com\",\n  \".tsctv.net\",\n  \"||tt1069.com\",\n  \".tttan.com\",\n  \"||tttan.com\",\n  \"bb.ttv.com.tw/bb\",\n  \"tu8964.com\",\n  \".tubaholic.com\",\n  \".tube.com\",\n  \"tube8.com\",\n  \"||tube8.com\",\n  \".tube911.com\",\n  \"||tube911.com\",\n  \".tubecup.com\",\n  \".tubegals.com\",\n  \".tubeislam.com\",\n  \"|http://tubeislam.com\",\n  \".tubestack.com\",\n  \"||tubewolf.com\",\n  \".tuibeitu.net\",\n  \"tuidang.net\",\n  \".tuidang.org\",\n  \"||tuidang.org\",\n  \".tuidang.se\",\n  \"bbs.tuitui.info\",\n  \".tumutanzi.com\",\n  \"|http://tumutanzi.com\",\n  \"||tumview.com\",\n  \".tunein.com\",\n  \"|http://tunein.com\",\n  \"||tunnelbear.com\",\n  \".tunnelr.com\",\n  \"||tunnelr.com\",\n  \"||tunsafe.com\",\n  \"tuitwit.com\",\n  \".turansam.org\",\n  \".turbobit.net\",\n  \"||turbobit.net\",\n  \".turbohide.com\",\n  \"||turbohide.com\",\n  \"||turkistantimes.com\",\n  \".tushycash.com\",\n  \"|http://tushycash.com\",\n  \"||app.tutanota.com\",\n  \".tuvpn.com\",\n  \"||tuvpn.com\",\n  \"|http://tuzaijidi.com\",\n  \"|http://*.tuzaijidi.com\",\n  \".tw01.org\",\n  \"|http://tw01.org\",\n  \".tumblr.com\",\n  \"||tumblr.com\",\n  \"||lecloud.net\",\n  \"|http://cosmic.monar.ch\",\n  \"||slutmoonbeam.com\",\n  \"|http://blog.soylent.com\",\n  \".tv.com\",\n  \"|http://tv.com\",\n  \"tvants.com\",\n  \"forum.tvb.com\",\n  \"news.tvb.com/list/world\",\n  \"news.tvb.com/local\",\n  \"news.tvbs.com.tw\",\n  \".tvboxnow.com\",\n  \"|http://tvboxnow.com/\",\n  \"tvider.com\",\n  \".tvmost.com.hk\",\n  \".tvplayvideos.com\",\n  \"||tvunetworks.com\",\n  \".tw-blog.com\",\n  \"|https://tw-blog.com\",\n  \".tw-npo.org\",\n  \".twaitter.com\",\n  \"twapperkeeper.com\",\n  \"||twapperkeeper.com\",\n  \"||twaud.io\",\n  \".twaud.io\",\n  \".twavi.com\",\n  \".twbbs.net.tw\",\n  \"twbbs.org\",\n  \"twbbs.tw\",\n  \"||twblogger.com\",\n  \"tweepmag.com\",\n  \".tweepml.org\",\n  \"||tweepml.org\",\n  \".tweetbackup.com\",\n  \"||tweetbackup.com\",\n  \"tweetboard.com\",\n  \"||tweetboard.com\",\n  \".tweetboner.biz\",\n  \"||tweetboner.biz\",\n  \".tweetcs.com\",\n  \"|http://tweetcs.com\",\n  \"|http://deck.ly\",\n  \"||mtw.tl\",\n  \"||tweetedtimes.com\",\n  \"||tweetmylast.fm\",\n  \"tweetphoto.com\",\n  \"||tweetphoto.com\",\n  \"||tweetrans.com\",\n  \"tweetree.com\",\n  \"||tweetree.com\",\n  \".tweettunnel.com\",\n  \"||tweettunnel.com\",\n  \"||tweetwally.com\",\n  \"tweetymail.com\",\n  \"||twelve.today\",\n  \".tweez.net\",\n  \"|http://tweez.net\",\n  \"||twftp.org\",\n  \"||twgreatdaily.com\",\n  \"twibase.com\",\n  \".twibble.de\",\n  \"||twibble.de\",\n  \"twibbon.com\",\n  \"||twibs.com\",\n  \".twicountry.org\",\n  \"|http://twicountry.org\",\n  \"twicsy.com\",\n  \".twiends.com\",\n  \"|http://twiends.com\",\n  \".twifan.com\",\n  \"|http://twifan.com\",\n  \"twiffo.com\",\n  \"||twiffo.com\",\n  \".twilightsex.com\",\n  \"twilog.org\",\n  \"twimbow.com\",\n  \"||twindexx.com\",\n  \"twipple.jp\",\n  \"||twipple.jp\",\n  \"||twip.me\",\n  \"twishort.com\",\n  \"||twishort.com\",\n  \"twistar.cc\",\n  \"||twister.net.co\",\n  \"||twisterio.com\",\n  \"twisternow.com\",\n  \"twistory.net\",\n  \"twitbrowser.net\",\n  \"||twitcause.com\",\n  \"||twitgether.com\",\n  \"||twiggit.org\",\n  \"twitgoo.com\",\n  \"twitiq.com\",\n  \"||twitiq.com\",\n  \".twitlonger.com\",\n  \"||twitlonger.com\",\n  \"|http://tl.gd/\",\n  \"twitmania.com\",\n  \"twitoaster.com\",\n  \"||twitoaster.com\",\n  \"||twitonmsn.com\",\n  \".twit2d.com\",\n  \"||twit2d.com\",\n  \".twitstat.com\",\n  \"||twitstat.com\",\n  \"||firstfivefollowers.com\",\n  \"||retweeteffect.com\",\n  \"||tweeplike.me\",\n  \"||tweepguide.com\",\n  \"||turbotwitter.com\",\n  \".twitvid.com\",\n  \"||twitvid.com\",\n  \"|http://twt.tl\",\n  \"twittbot.net\",\n  \"||ads-twitter.com\",\n  \"||twttr.com\",\n  \"||twitter4j.org\",\n  \".twittercounter.com\",\n  \"||twittercounter.com\",\n  \"twitterfeed.com\",\n  \".twittergadget.com\",\n  \"||twittergadget.com\",\n  \".twitterkr.com\",\n  \"||twitterkr.com\",\n  \"||twittermail.com\",\n  \"||twitterrific.com\",\n  \"twittertim.es\",\n  \"||twittertim.es\",\n  \"twitthat.com\",\n  \"||twitturk.com\",\n  \".twitturly.com\",\n  \"||twitturly.com\",\n  \".twitzap.com\",\n  \"twiyia.com\",\n  \"||twstar.net\",\n  \".twtkr.com\",\n  \"|http://twtkr.com\",\n  \".twnorth.org.tw\",\n  \"||twreporter.org\",\n  \"twskype.com\",\n  \"twtrland.com\",\n  \"twurl.nl\",\n  \".twyac.org\",\n  \"||twyac.org\",\n  \".txxx.com\",\n  \".tycool.com\",\n  \"||tycool.com\",\n  \"||typepad.com\",\n  \"@@||www.typepad.com\",\n  \"@@||static.typepad.com\",\n  \"||blog.expofutures.com\",\n  \"||legaltech.law.com\",\n  \"||blogs.tampabay.com\",\n  \"||contests.twilio.com\",\n  \".embr.in\",\n  \"||embr.in\",\n  \".u9un.com\",\n  \"||u9un.com\",\n  \".ubddns.org\",\n  \"|http://ubddns.org\",\n  \"||uberproxy.net\",\n  \".uc-japan.org\",\n  \"||uc-japan.org\",\n  \".srcf.ucam.org/salon/\",\n  \"|http://china.ucanews.com/\",\n  \"||ucdc1998.org\",\n  \"|http://hum*.uchicago.edu/faculty/ywang/history\",\n  \"||uderzo.it\",\n  \".udn.com\",\n  \"||udn.com\",\n  \"||udn.com.tw\",\n  \"udnbkk.com/bbs\",\n  \"||uforadio.com.tw\",\n  \"ufreevpn.com\",\n  \".ugo.com\",\n  \"||uhdwallpapers.org\",\n  \"||uhrp.org\",\n  \".uighur.nl\",\n  \"||uighur.nl\",\n  \"uighurbiz.net\",\n  \".ulike.net\",\n  \"ukcdp.co.uk\",\n  \"ukliferadio.co.uk\",\n  \"||ukliferadio.co.uk\",\n  \"ultravpn.fr\",\n  \"||ultravpn.fr\",\n  \"ultraxs.com\",\n  \"umich.edu/~falun\",\n  \"||unblock.cn.com\",\n  \".unblocker.yt\",\n  \"unblock-us.com\",\n  \"||unblock-us.com\",\n  \".unblockdmm.com\",\n  \"|http://unblockdmm.com\",\n  \"||unblocksit.es\",\n  \"uncyclomedia.org\",\n  \".uncyclopedia.hk/wiki\",\n  \"|http://uncyclopedia.hk\",\n  \"|http://uncyclopedia.tw\",\n  \"underwoodammo.com\",\n  \"||underwoodammo.com\",\n  \"||unholyknight.com\",\n  \".uni.cc\",\n  \"||cldr.unicode.org\",\n  \".unification.net\",\n  \".unification.org.tw\",\n  \"||unirule.cloud\",\n  \".unitedsocialpress.com\",\n  \".unix100.com\",\n  \"||unknownspace.org\",\n  \".unodedos.com\",\n  \"unpo.org\",\n  \"||unstable.icu\",\n  \".untraceable.us\",\n  \"|http://untraceable.us\",\n  \"||uocn.org\",\n  \"tor.updatestar.com\",\n  \"||upghsbc.com\",\n  \".upholdjustice.org\",\n  \".upload4u.info\",\n  \"uploaded.net/file\",\n  \"|http://uploaded.net/file\",\n  \"|http://uploaded.to/file\",\n  \".uploadstation.com/file\",\n  \".upmedia.mg\",\n  \"||upmedia.mg\",\n  \".upornia.com\",\n  \"|http://upornia.com\",\n  \"||uproxy.org\",\n  \"||uptodown.com\",\n  \".upwill.org\",\n  \"ur7s.com\",\n  \"||urbandictionary.com\",\n  \"||urbansurvival.com\",\n  \"myshare.url.com.tw/\",\n  \"||urlborg.com\",\n  \"||urlparser.com\",\n  \"us.to\",\n  \"||usacn.com\",\n  \".usaip.eu\",\n  \"||usaip.eu\",\n  \"dalailama.usc.edu\",\n  \"||usma.edu\",\n  \".usocctn.com\",\n  \"||ustibetcommittee.org\",\n  \".ustream.tv\",\n  \"||ustream.tv\",\n  \".usunitednews.com\",\n  \"|http://usunitednews.com\",\n  \"usus.cc\",\n  \".utopianpal.com\",\n  \"||utopianpal.com\",\n  \".uu-gg.com\",\n  \".uvwxyz.xyz\",\n  \"||uvwxyz.xyz\",\n  \".uwants.com\",\n  \".uwants.net\",\n  \"uyghur.co.uk\",\n  \"|http://uyghur-j.org\",\n  \"||uyghuramerican.org\",\n  \"||uyghurbiz.org\",\n  \".uyghurcanadiansociety.org\",\n  \".uyghurensemble.co.uk\",\n  \"||uyghurcongress.org\",\n  \".uyghurpen.org\",\n  \".uyghurpress.com\",\n  \"|https://uyghurpress.com\",\n  \".uyghurstudies.org\",\n  \"|http://uyghurstudies.org\",\n  \"uygur.org\",\n  \"|http://uymaarip.com/\",\n  \"||v2fly.org\",\n  \".v2ray.com\",\n  \"||v2ray.com\",\n  \"||v2raycn.com\",\n  \"||v2raytech.com\",\n  \"||valeursactuelles.com\",\n  \".van001.com\",\n  \".van698.com\",\n  \".vanemu.cn\",\n  \".vanilla-jp.com\",\n  \".vanpeople.com\",\n  \"vansky.com\",\n  \"||vaticannews.va\",\n  \"||vcf-online.org\",\n  \"||vcfbuilder.org\",\n  \".vegasred.com\",\n  \".velkaepocha.sk\",\n  \".venbbs.com\",\n  \".venchina.com\",\n  \".venetianmacao.com\",\n  \"||venetianmacao.com\",\n  \"veoh.com\",\n  \"mysite.verizon.net\",\n  \"vermonttibet.org\",\n  \".versavpn.com\",\n  \"||versavpn.com\",\n  \"||verybs.com\",\n  \".vft.com.tw\",\n  \".viber.com\",\n  \"||viber.com\",\n  \".vica.info\",\n  \".victimsofcommunism.org\",\n  \"|http://victimsofcommunism.org\",\n  \"||vid.me\",\n  \"||vidble.com\",\n  \"videobam.com\",\n  \"||videobam.com\",\n  \".videodetective.com\",\n  \".videomega.tv\",\n  \"||videomega.tv\",\n  \".videomo.com\",\n  \"videopediaworld.com\",\n  \".videopress.com\",\n  \".vidinfo.org/video\",\n  \"vietdaikynguyen.com\",\n  \".vijayatemple.org\",\n  \"||vilavpn.com\",\n  \"vimeo.com\",\n  \"||vimeo.com\",\n  \"||vimperator.org\",\n  \"||vincnd.com\",\n  \"||vinniev.com\",\n  \"|http://www.lib.virginia.edu/area-studies/Tibet/tibet.html\",\n  \".virtualrealporn.com\",\n  \"||virtualrealporn.com\",\n  \"visibletweets.com\",\n  \"|http://ny.visiontimes.com\",\n  \".vital247.org\",\n  \"||viu.com\",\n  \".vivahentai4u.net\",\n  \".vivatube.com\",\n  \".vivthomas.com\",\n  \"||vivthomas.com\",\n  \".vjav.com\",\n  \"||vjav.com\",\n  \".vjmedia.com.hk\",\n  \".vllcs.org\",\n  \"|http://vllcs.org\",\n  \"||vmixcore.com\",\n  \"||vnet.link\",\n  \".vocativ.com\",\n  \"vocn.tv\",\n  \"||vocus.cc\",\n  \"||voicettank.org\",\n  \".vot.org\",\n  \"||vot.org\",\n  \".vovo2000.com\",\n  \"|http://vovo2000.com\",\n  \".voxer.com\",\n  \"||voxer.com\",\n  \".voy.com\",\n  \"||vpn.ac\",\n  \".vpn4all.com\",\n  \"||vpn4all.com\",\n  \".vpnaccount.org\",\n  \"|http://vpnaccount.org\",\n  \".vpnaccounts.com\",\n  \"||vpnaccounts.com\",\n  \".vpncomparison.org\",\n  \".vpncup.com\",\n  \"||vpncup.com\",\n  \"vpnbook.com\",\n  \".vpncoupons.com\",\n  \"|http://vpncoupons.com\",\n  \".vpndada.com\",\n  \"||vpndada.com\",\n  \".vpnfan.com\",\n  \"vpnfire.com\",\n  \".vpnfires.biz\",\n  \".vpnforgame.net\",\n  \"||vpnforgame.net\",\n  \"||vpngate.jp\",\n  \".vpngate.net\",\n  \"||vpngate.net\",\n  \".vpngratis.net\",\n  \"vpnhq.com\",\n  \"||vpnhub.com\",\n  \".vpnmaster.com\",\n  \"||vpnmaster.com\",\n  \".vpnmentor.com\",\n  \"||vpnmentor.com\",\n  \".vpninja.net\",\n  \"||vpninja.net\",\n  \".vpnintouch.com\",\n  \"||vpnintouch.net\",\n  \"vpnjack.com\",\n  \"||vpnjack.com\",\n  \".vpnpick.com\",\n  \"||vpnpick.com\",\n  \"||vpnpop.com\",\n  \"||vpnpronet.com\",\n  \".vpnreactor.com\",\n  \"||vpnreactor.com\",\n  \"||vpnreviewz.com\",\n  \".vpnsecure.me\",\n  \"||vpnsecure.me\",\n  \".vpnshazam.com\",\n  \"||vpnshazam.com\",\n  \".vpnshieldapp.com\",\n  \"||vpnshieldapp.com\",\n  \".vpnsp.com\",\n  \".vpntraffic.com\",\n  \".vpntunnel.com\",\n  \"||vpntunnel.com\",\n  \".vpnuk.info\",\n  \"||vpnuk.info\",\n  \"||vpnunlimitedapp.com\",\n  \".vpnvip.com\",\n  \"||vpnvip.com\",\n  \".vpnworldwide.com\",\n  \".vporn.com\",\n  \"||vporn.com\",\n  \".vpser.net\",\n  \"@@||vpser.net\",\n  \"vraiesagesse.net\",\n  \".vrmtr.com\",\n  \"||vtunnel.com\",\n  \"||vuku.cc\",\n  \"lists.w3.org/archives/public\",\n  \"||w3schools.com\",\n  \"||waffle1999.com\",\n  \".wahas.com\",\n  \".waigaobu.com\",\n  \"waikeung.org/php_wind\",\n  \".wailaike.net\",\n  \".waiwaier.com\",\n  \"|http://waiwaier.com\",\n  \"||wallmama.com\",\n  \"wallornot.org\",\n  \"||wallpapercasa.com\",\n  \".wallproxy.com\",\n  \"@@||wallproxy.com.cn\",\n  \"||wallsttv.com\",\n  \"||waltermartin.com\",\n  \"||waltermartin.org\",\n  \"||www.wan-press.org\",\n  \"||wanderinghorse.net\",\n  \"||wangafu.net\",\n  \"||wangjinbo.org\",\n  \".wangjinbo.org\",\n  \"wanglixiong.com\",\n  \".wango.org\",\n  \"||wango.org\",\n  \"wangruoshui.net\",\n  \"www.wangruowang.org\",\n  \"||want-daily.com\",\n  \"wapedia.mobi/zhsimp\",\n  \"||warroom.org\",\n  \"||waselpro.com\",\n  \".watchinese.com\",\n  \"||watchout.tw\",\n  \".wattpad.com\",\n  \"||wattpad.com\",\n  \".makzhou.warehouse333.com\",\n  \"washeng.net\",\n  \".watch8x.com\",\n  \"||watchmygf.net\",\n  \"||wav.tv\",\n  \".wdf5.com\",\n  \".wearehairy.com\",\n  \".wearn.com\",\n  \"||wearn.com\",\n  \"|http://hkcoc.weather.com.hk\",\n  \"||hudatoriq.web.id\",\n  \"||web2project.net\",\n  \"webbang.net\",\n  \".webevader.org\",\n  \".webfreer.com\",\n  \"weblagu.com\",\n  \".webjb.org\",\n  \".webrush.net\",\n  \"webs-tv.net\",\n  \".websitepulse.com/help/testtools.china-test\",\n  \"|http://www.websnapr.com\",\n  \".webwarper.net\",\n  \"|http://webwarper.net\",\n  \"webworkerdaily.com\",\n  \"||wechatlawsuit.com\",\n  \".weekmag.info\",\n  \"||wefightcensorship.org\",\n  \".wefong.com\",\n  \"weiboleak.com\",\n  \".weihuo.org\",\n  \"weijingsheng.org\",\n  \".weiming.info\",\n  \"||weiming.info\",\n  \"weiquanwang.org\",\n  \"|http://weisuo.ws\",\n  \".welovecock.com\",\n  \"||welt.de\",\n  \".wemigrate.org\",\n  \"|http://wemigrate.org\",\n  \"wengewang.com\",\n  \"||wengewang.org\",\n  \".wenhui.ch\",\n  \"|http://trans.wenweipo.com/gb/\",\n  \".wenxuecity.com\",\n  \"||wenxuecity.com\",\n  \".wenyunchao.com\",\n  \"||wenyunchao.com\",\n  \".westca.com\",\n  \"||westca.com\",\n  \"||westernwolves.com\",\n  \".westkit.net\",\n  \"||westpoint.edu\",\n  \".westernshugdensociety.org\",\n  \"wetpussygames.com\",\n  \".wetplace.com\",\n  \"wexiaobo.org\",\n  \"||wexiaobo.org\",\n  \"wezhiyong.org\",\n  \"||wezone.net\",\n  \".wforum.com\",\n  \"||wforum.com/\",\n  \".whatblocked.com\",\n  \"||whatblocked.com\",\n  \".wheatseeds.org\",\n  \"||wheelockslatin.com\",\n  \".whippedass.com\",\n  \".whoer.net\",\n  \"||whoer.net\",\n  \"whotalking.com\",\n  \"whylover.com\",\n  \"||whyx.org\",\n  \"||wikileaks.ch\",\n  \"||wikileaks.com\",\n  \"||wikileaks.de\",\n  \"||wikileaks.eu\",\n  \"||wikileaks.lu\",\n  \".wikileaks.org\",\n  \"||wikileaks.org\",\n  \"||wikileaks.pl\",\n  \".wikileaks-forum.com\",\n  \"wildammo.com\",\n  \".williamhill.com\",\n  \"||collateralmurder.com\",\n  \"||collateralmurder.org\",\n  \"wikilivres.info/wiki/%E9%9B%B6%E5%85%AB%E5%AE%AA%E7%AB%A0\",\n  \"||wikimapia.org\",\n  \".wikiwand.com\",\n  \"||wikiwand.com\",\n  \"||wikiwiki.jp\",\n  \"||casino.williamhill.com\",\n  \"||sports.williamhill.com\",\n  \"||vegas.williamhill.com\",\n  \"||willw.net\",\n  \"||windowsphoneme.com\",\n  \".windscribe.com\",\n  \"||windscribe.com\",\n  \"||community.windy.com\",\n  \"||wingy.site\",\n  \".winning11.com\",\n  \"winwhispers.info\",\n  \"||wionews.com\",\n  \"||wiredbytes.com\",\n  \"||wiredpen.com\",\n  \"||wireguard.com\",\n  \".wisdompubs.org\",\n  \".wisevid.com\",\n  \"||wisevid.com\",\n  \"||whispersystems.org\",\n  \".witnessleeteaching.com\",\n  \".witopia.net\",\n  \".wjbk.org\",\n  \"||wjbk.org\",\n  \"|http://wn.com\",\n  \".wnacg.com\",\n  \".wnacg.org\",\n  \".wo.tc\",\n  \"||woeser.com\",\n  \"|http://woesermiddle-way.net/\",\n  \".wokar.org\",\n  \"|http://wokar.org\",\n  \"wolfax.com\",\n  \"||wolfax.com\",\n  \"||wombo.ai\",\n  \"||woolyss.com\",\n  \"woopie.jp\",\n  \"||woopie.jp\",\n  \"woopie.tv\",\n  \"||woopie.tv\",\n  \"||workatruna.com\",\n  \".workerdemo.org.hk\",\n  \".workerempowerment.org\",\n  \"||workersthebig.net\",\n  \".worldcat.org\",\n  \"worldjournal.com\",\n  \".worldvpn.net\",\n  \"||worldvpn.net\",\n  \"||videopress.com\",\n  \".wordpress.com\",\n  \"|http://*.wordpress.com\",\n  \"||chenshan20042005.wordpress.com\",\n  \"||chinaview.wordpress.com\",\n  \"||cnbbnews.wordpress.com\",\n  \"||freedominfonetweb.wordpress.com\",\n  \"||hka8964.wordpress.com\",\n  \"||hkanews.wordpress.com\",\n  \"||hqsbnet.wordpress.com\",\n  \"||hqsbonline.wordpress.com\",\n  \"||investigating.wordpress.com\",\n  \"||jobnewera.wordpress.com\",\n  \"||matthewdgreen.wordpress.com\",\n  \"||minghuiyw.wordpress.com\",\n  \"||wo3ttt.wordpress.com\",\n  \"||sujiatun.wordpress.com\",\n  \"||xijie.wordpress.com\",\n  \"||wp.com\",\n  \".wow.com\",\n  \".wow-life.net\",\n  \"||wowlegacy.ml\",\n  \"||wowporn.com\",\n  \"||wowgirls.com\",\n  \".wowrk.com\",\n  \"woxinghuiguo.com\",\n  \".woyaolian.org\",\n  \"|http://woyaolian.org\",\n  \".wpoforum.com\",\n  \"||wpoforum.com\",\n  \".wqyd.org\",\n  \"||wqyd.org\",\n  \"wrchina.org\",\n  \"wretch.cc\",\n  \".wsj.com\",\n  \"||wsj.com\",\n  \".wsj.net\",\n  \"||wsj.net\",\n  \".wsjhk.com\",\n  \".wtbn.org\",\n  \".wtfpeople.com\",\n  \"wuerkaixi.com\",\n  \"||wufafangwen.com\",\n  \"wufi.org.tw\",\n  \"||wuguoguang.com\",\n  \"wujie.net\",\n  \"wujieliulan.com\",\n  \"||wujieliulan.com\",\n  \"wukangrui.net\",\n  \"||wuw.red\",\n  \"||wuyanblog.com\",\n  \".wwitv.com\",\n  \"||wwitv.com\",\n  \"wzyboy.im/post/160\",\n  \".x-berry.com\",\n  \"||x-berry.com\",\n  \"||x-art.com\",\n  \"||x-wall.org\",\n  \"x1949x.com\",\n  \"x365x.com\",\n  \"xanga.com\",\n  \"||xbabe.com\",\n  \".xbookcn.com\",\n  \"||xbookcn.com\",\n  \"||xcafe.in\",\n  \"||xcity.jp\",\n  \".xcritic.com\",\n  \"|http://cdn*.xda-developers.com\",\n  \".xerotica.com\",\n  \"destiny.xfiles.to/ubbthreads\",\n  \".xfm.pp.ru\",\n  \".xgmyd.com\",\n  \"||xgmyd.com\",\n  \"xhamster.com\",\n  \"||xhamster.com\",\n  \".xianba.net\",\n  \".xianchawang.net\",\n  \".xianjian.tw\",\n  \"|http://xianjian.tw\",\n  \".xianqiao.net\",\n  \".xiaobaiwu.com\",\n  \".xiaochuncnjp.com\",\n  \".xiaod.in\",\n  \".xiaohexie.com\",\n  \"||xiaolan.me\",\n  \"||xiaoma.org\",\n  \"||xiaohexie.com\",\n  \"||xiaxiaoqiang.net\",\n  \"xiezhua.com\",\n  \".xihua.es\",\n  \"forum.xinbao.de/forum\",\n  \".xing.com\",\n  \"|http://xing.com\",\n  \".xinmiao.com.hk\",\n  \"||xinmiao.com.hk\",\n  \"xinsheng.net\",\n  \"xinshijue.com\",\n  \"xinhuanet.org\",\n  \"|http://xinyubbs.net\",\n  \".xiongpian.com\",\n  \".xiuren.org\",\n  \"||xixicui.icu\",\n  \"xizang-zhiye.org\",\n  \"xjp.cc\",\n  \"||xjp.cc\",\n  \"||xjtravelguide.com\",\n  \"xlfmtalk.com\",\n  \"||xlfmwz.info\",\n  \"||xml-training-guide.com\",\n  \"xmovies.com\",\n  \"||xnxx.com\",\n  \"xpdo.net\",\n  \"||xpud.org\",\n  \".xrentdvd.com\",\n  \".xskywalker.net\",\n  \"||xtube.com\",\n  \"blog.xuite.net\",\n  \"vlog.xuite.net\",\n  \"xuzhiyong.net\",\n  \"||xuchao.org\",\n  \"xuchao.net\",\n  \"||xuchao.net\",\n  \"xvideo.cc\",\n  \".xvideos.com\",\n  \"||xvideos.com\",\n  \"||xvideos-cdn.com\",\n  \"||xvideos.es\",\n  \"||xvbelink.com\",\n  \"||xvinlink.com\",\n  \".xkiwi.tk/\",\n  \"||xsden.info\",\n  \".xxbbx.com\",\n  \".xxlmovies.com\",\n  \"||xxx.com\",\n  \".xxx.xxx\",\n  \"|http://xxx.xxx\",\n  \".xxxfuckmom.com\",\n  \"||xxxx.com.au\",\n  \".xxxymovies.com\",\n  \"|http://xxxymovies.com\",\n  \"xys.org\",\n  \"xysblogs.org\",\n  \"xyy69.com\",\n  \"xyy69.info\",\n  \"||y2mate.com\",\n  \"||yakbutterblues.com\",\n  \"||yam.com\",\n  \"||yam.org.tw\",\n  \"||yande.re\",\n  \"||disk.yandex.com\",\n  \".yanghengjun.com\",\n  \"yangjianli.com\",\n  \".yasni.co.uk\",\n  \"||yasni.co.uk\",\n  \".yayabay.com/forum\",\n  \"||news.ycombinator.com\",\n  \".ydy.com\",\n  \".yeahteentube.com\",\n  \"||yeahteentube.com\",\n  \"||yecl.net\",\n  \"||yeelou.com\",\n  \"||yeeyi.com\",\n  \"yegle.net\",\n  \"||yegle.net\",\n  \".yes.xxx\",\n  \"||yes123.com.tw\",\n  \"||yesasia.com\",\n  \"||yesasia.com.hk\",\n  \".yes-news.com\",\n  \"|http://yes-news.com\",\n  \".yespornplease.com\",\n  \"||yespornplease.com\",\n  \"|http://yeyeclub.com\",\n  \"||yhcw.net\",\n  \".yibada.com\",\n  \".yibaochina.com\",\n  \".yidio.com\",\n  \"||yidio.com\",\n  \"yilubbs.com\",\n  \"xa.yimg.com\",\n  \".yingsuoss.com\",\n  \".yipub.com\",\n  \"||yipub.com\",\n  \"yinlei.org/mt\",\n  \"||yiyechat.com\",\n  \".yizhihongxing.com\",\n  \".yobt.com\",\n  \".yobt.tv\",\n  \"||yobt.tv\",\n  \".yogichen.org\",\n  \"||yogichen.org\",\n  \".yolasite.com\",\n  \".yomiuri.co.jp\",\n  \"yong.hu\",\n  \".yorkbbs.ca\",\n  \"||youxu.info\",\n  \".youjizz.com\",\n  \"||youjizz.com\",\n  \".youmaker.com\",\n  \"||youmaker.com\",\n  \".youngpornvideos.com\",\n  \"youngspiration.hk\",\n  \".youpai.org\",\n  \"||youpai.org\",\n  \".your-freedom.net\",\n  \"||yourepeat.com\",\n  \".yourprivatevpn.com\",\n  \"||yourprivatevpn.com\",\n  \".yousendit.com\",\n  \"||yousendit.com\",\n  \"||youthforfreechina.org\",\n  \".youthnetradio.org/tmit/forum\",\n  \"blog.youthwant.com.tw\",\n  \"me.youthwant.com.tw\",\n  \"share.youthwant.com.tw\",\n  \"topic.youthwant.com.tw\",\n  \".youporn.com\",\n  \"||youporn.com\",\n  \".youporngay.com\",\n  \"||youporngay.com\",\n  \".yourlisten.com\",\n  \"|http://yourlisten.com\",\n  \".yourlust.com\",\n  \"|http://yourlust.com\",\n  \"youshun12.com\",\n  \".youtubecn.com\",\n  \"youversion.com\",\n  \"||youversion.com\",\n  \"blog.youxu.info/2010/03/14/west-chamber\",\n  \"ytht.net\",\n  \"yuanming.net\",\n  \".yuanzhengtang.org\",\n  \".yulghun.com\",\n  \"||yunchao.net\",\n  \"||yuntipub.com\",\n  \".yuvutu.com\",\n  \"||yvesgeleyn.com\",\n  \".ywpw.com/forums/history/post/A0/p0/html/227\",\n  \"yx51.net\",\n  \".yyii.org\",\n  \"||yyii.org\",\n  \"||yyjlymb.xyz\",\n  \".yzzk.com\",\n  \"||yzzk.com\",\n  \"zacebook.com\",\n  \".zalmos.com\",\n  \"||zalmos.com\",\n  \"||zannel.com\",\n  \".zaobao.com\",\n  \"||zaobao.com\",\n  \"|http://zaobao.com.sg\",\n  \"||zaobao.com.sg\",\n  \".zaozon.com\",\n  \"||zdnet.com.tw\",\n  \".zello.com\",\n  \"||zello.com\",\n  \".zengjinyan.org\",\n  \".zenmate.com\",\n  \"||zenmate.com\",\n  \"||zenmate.com.ru\",\n  \"||zerohedge.com\",\n  \"||zeronet.io\",\n  \"||zeutch.com\",\n  \".zfreet.com\",\n  \".zgsddh.com\",\n  \"zgzcjj.net\",\n  \".zhanbin.net\",\n  \"||zhanbin.net\",\n  \".zhangboli.net\",\n  \"||zhangtianliang.com\",\n  \"||zhanlve.org\",\n  \"zhenghui.org\",\n  \".zhengjian.org\",\n  \"||zhengjian.org\",\n  \"zhengwunet.org\",\n  \"zhenlibu.info\",\n  \"||zhenlibu.info\",\n  \".zhenlibu1984.com\",\n  \"||zhenlibu1984.com\",\n  \"|http://zhenxiang.biz\",\n  \".zhinengluyou.com\",\n  \"zhongguo.ca\",\n  \"|http://zhongguorenquan.org\",\n  \"zhongguotese.net\",\n  \"||zhongguotese.net\",\n  \"||zhongmeng.org\",\n  \".zhoushuguang.com\",\n  \"||zhreader.com\",\n  \".zhuangbi.me\",\n  \"||zhuangbi.me\",\n  \".zhuanxing.cn\",\n  \"||zhuatieba.com\",\n  \"zhuichaguoji.org\",\n  \"||zhuichaguoji.org\",\n  \"||zi.media\",\n  \"|http://book.zi5.me\",\n  \".ziddu.com/download\",\n  \"||zillionk.com\",\n  \".zinio.com\",\n  \"||zinio.com\",\n  \".ziporn.com\",\n  \".zippyshare.com\",\n  \".zkaip.com\",\n  \"||zkaip.com\",\n  \"realforum.zkiz.com\",\n  \"||zmw.cn\",\n  \".zodgame.us\",\n  \"zomobo.net\",\n  \".zonaeuropa.com\",\n  \"||zonaeuropa.com\",\n  \"||zonghexinwen.com\",\n  \".zonghexinwen.net\",\n  \"||zoogvpn.com\",\n  \"||zootool.com\",\n  \".zoozle.net\",\n  \"||zophar.net\",\n  \"writer.zoho.com\",\n  \"||zorrovpn.com\",\n  \"||zpn.im\",\n  \"||zspeeder.me\",\n  \".zsrhao.com\",\n  \".zuo.la\",\n  \"||zuo.la\",\n  \"||zuobiao.me\",\n  \".zuola.com\",\n  \"||zuola.com\",\n  \"||zvereff.com\",\n  \"||zyxel.com\",\n  \".zynaima.com\",\n  \"zyzc9.com\",\n  \".zzcartoon.com\",\n  \"64memo\",\n  \"aHR0cHM6Ly95ZWNsLm5ldA\",\n  \"freenet\",\n  \".google.*/falun\",\n  \"phobos.apple.com*/video\",\n  \"q=freedom\",\n  \"q%3Dfreedom\",\n  \"remembering_tiananmen_20_years\",\n  \"search*safeweb\",\n  \"q=triangle\",\n  \"q%3DTriangle\",\n  \"ultrareach\",\n  \"ultrasurf\",\n  \"@@||aliyun.com\",\n  \"@@||baidu.com\",\n  \"@@||chinaso.com\",\n  \"@@||chinaz.com\",\n  \"@@|http://nrch.culture.tw/\",\n  \"@@||adservice.google.com\",\n  \"@@||dl.google.com\",\n  \"@@||kh.google.com\",\n  \"@@||khm.google.com\",\n  \"@@||khm0.google.com\",\n  \"@@||khm1.google.com\",\n  \"@@||khm2.google.com\",\n  \"@@||khm3.google.com\",\n  \"@@||khmdb.google.com\",\n  \"@@||tools.google.com\",\n  \"@@||clientservices.googleapis.com\",\n  \"@@||fonts.googleapis.com\",\n  \"@@||khm.googleapis.com\",\n  \"@@||khm0.googleapis.com\",\n  \"@@||khm1.googleapis.com\",\n  \"@@||khm2.googleapis.com\",\n  \"@@||khm3.googleapis.com\",\n  \"@@||khmdb.googleapis.com\",\n  \"@@||storage.googleapis.com\",\n  \"@@||translate.googleapis.com\",\n  \"@@||update.googleapis.com\",\n  \"@@||safebrowsing.googleapis.com\",\n  \"@@||cn.gravatar.com\",\n  \"@@||connectivitycheck.gstatic.com\",\n  \"@@||csi.gstatic.com\",\n  \"@@||fonts.gstatic.com\",\n  \"@@||ssl.gstatic.com\",\n  \"@@||haosou.com\",\n  \"@@||ip.cn\",\n  \"@@||jike.com\",\n  \"@@|http://translate.google.cn\",\n  \"@@|http://www.google.cn/maps\",\n  \"@@||http2.golang.org\",\n  \"@@||gov.cn\",\n  \"@@||qq.com\",\n  \"@@||sina.cn\",\n  \"@@||sina.com.cn\",\n  \"@@||sogou.com\",\n  \"@@||so.com\",\n  \"@@||soso.com\",\n  \"@@||uluai.com.cn\",\n  \"@@||weibo.com\",\n  \"@@||yahoo.cn\",\n  \"@@||youdao.com\",\n  \"@@||zhongsou.com\",\n  \"@@|http://ime.baidu.jp\"\n];\n\n/*\n* This file is part of Adblock Plus <http://adblockplus.org/>,\n* Copyright (C) 2006-2014 Eyeo GmbH\n*\n* Adblock Plus is free software: you can redistribute it and/or modify\n* it under the terms of the GNU General Public License version 3 as\n* published by the Free Software Foundation.\n*\n* Adblock Plus is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\tSee the\n* GNU General Public License for more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with Adblock Plus.\tIf not, see <http://www.gnu.org/licenses/>.\n*/\n\nfunction createDict()\n{\n\tvar result = {};\n\tresult.__proto__ = null;\n\treturn result;\n}\n\nfunction getOwnPropertyDescriptor(obj, key)\n{\n\tif (obj.hasOwnProperty(key))\n\t{\n\t\treturn obj[key];\n\t}\n\treturn null;\n}\n\nfunction extend(subclass, superclass, definition)\n{\n\tif (Object.__proto__)\n\t{\n\t\tdefinition.__proto__ = superclass.prototype;\n\t\tsubclass.prototype = definition;\n\t}\n\telse\n\t{\n\t\tvar tmpclass = function(){}, ret;\n\t\ttmpclass.prototype = superclass.prototype;\n\t\tsubclass.prototype = new tmpclass();\n\t\tsubclass.prototype.constructor = superclass;\n\t\tfor (var i in definition)\n\t\t{\n\t\t\tif (definition.hasOwnProperty(i))\n\t\t\t{\n\t\t\t\tsubclass.prototype[i] = definition[i];\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction Filter(text)\n{\n\tthis.text = text;\n\tthis.subscriptions = [];\n}\nFilter.prototype = {\n\ttext: null,\n\tsubscriptions: null,\n\ttoString: function()\n\t{\n\t\treturn this.text;\n\t}\n};\nFilter.knownFilters = createDict();\nFilter.elemhideRegExp = /^([^\\/\\*\\|\\@\"!]*?)#(\\@)?(?:([\\w\\-]+|\\*)((?:\\([\\w\\-]+(?:[$^*]?=[^\\(\\)\"]*)?\\))*)|#([^{}]+))$/;\nFilter.regexpRegExp = /^(@@)?\\/.*\\/(?:\\$~?[\\w\\-]+(?:=[^,\\s]+)?(?:,~?[\\w\\-]+(?:=[^,\\s]+)?)*)?$/;\nFilter.optionsRegExp = /\\$(~?[\\w\\-]+(?:=[^,\\s]+)?(?:,~?[\\w\\-]+(?:=[^,\\s]+)?)*)$/;\nFilter.fromText = function(text)\n{\n\tif (text in Filter.knownFilters)\n\t{\n\t\treturn Filter.knownFilters[text];\n\t}\n\tvar ret;\n\tif (text.charAt(0) == \"!\")\n\t{\n\t\tret = new CommentFilter(text);\n\t}\n\telse\n\t{\n\t\tret = RegExpFilter.fromText(text);\n\t}\n\tFilter.knownFilters[ret.text] = ret;\n\treturn ret;\n};\n\nfunction InvalidFilter(text, reason)\n{\n\tFilter.call(this, text);\n\tthis.reason = reason;\n}\nextend(InvalidFilter, Filter, {\n\treason: null\n});\n\nfunction CommentFilter(text)\n{\n\tFilter.call(this, text);\n}\nextend(CommentFilter, Filter, {\n});\n\nfunction ActiveFilter(text, domains)\n{\n\tFilter.call(this, text);\n\tthis.domainSource = domains;\n}\nextend(ActiveFilter, Filter, {\n\tdomainSource: null,\n\tdomainSeparator: null,\n\tignoreTrailingDot: true,\n\tdomainSourceIsUpperCase: false,\n\tgetDomains: function()\n\t{\n\t\tvar prop = getOwnPropertyDescriptor(this, \"domains\");\n\t\tif (prop)\n\t\t{\n\t\t\treturn prop;\n\t\t}\n\t\tvar domains = null;\n\t\tif (this.domainSource)\n\t\t{\n\t\t\tvar source = this.domainSource;\n\t\t\tif (!this.domainSourceIsUpperCase)\n\t\t\t{\n\t\t\t\tsource = source.toUpperCase();\n\t\t\t}\n\t\t\tvar list = source.split(this.domainSeparator);\n\t\t\tif (list.length == 1 && (list[0]).charAt(0) != \"~\")\n\t\t\t{\n\t\t\t\tdomains = createDict();\n\t\t\t\tdomains[\"\"] = false;\n\t\t\t\tif (this.ignoreTrailingDot)\n\t\t\t\t{\n\t\t\t\t\tlist[0] = list[0].replace(/\\.+$/, \"\");\n\t\t\t\t}\n\t\t\t\tdomains[list[0]] = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvar hasIncludes = false;\n\t\t\t\tfor (var i = 0; i < list.length; i++)\n\t\t\t\t{\n\t\t\t\t\tvar domain = list[i];\n\t\t\t\t\tif (this.ignoreTrailingDot)\n\t\t\t\t\t{\n\t\t\t\t\t\tdomain = domain.replace(/\\.+$/, \"\");\n\t\t\t\t\t}\n\t\t\t\t\tif (domain == \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tvar include;\n\t\t\t\t\tif (domain.charAt(0) == \"~\")\n\t\t\t\t\t{\n\t\t\t\t\t\tinclude = false;\n\t\t\t\t\t\tdomain = domain.substr(1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tinclude = true;\n\t\t\t\t\t\thasIncludes = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (!domains)\n\t\t\t\t\t{\n\t\t\t\t\t\tdomains = createDict();\n\t\t\t\t\t}\n\t\t\t\t\tdomains[domain] = include;\n\t\t\t\t}\n\t\t\t\tdomains[\"\"] = !hasIncludes;\n\t\t\t}\n\t\t\tthis.domainSource = null;\n\t\t}\n\t\treturn this.domains;\n\t},\n\tsitekeys: null,\n\tisActiveOnDomain: function(docDomain, sitekey)\n\t{\n\t\tif (this.getSitekeys() && (!sitekey || this.getSitekeys().indexOf(sitekey.toUpperCase()) < 0))\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tif (!this.getDomains())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\tif (!docDomain)\n\t\t{\n\t\t\treturn this.getDomains()[\"\"];\n\t\t}\n\t\tif (this.ignoreTrailingDot)\n\t\t{\n\t\t\tdocDomain = docDomain.replace(/\\.+$/, \"\");\n\t\t}\n\t\tdocDomain = docDomain.toUpperCase();\n\t\twhile (true)\n\t\t{\n\t\t\tif (docDomain in this.getDomains())\n\t\t\t{\n\t\t\t\treturn this.domains[docDomain];\n\t\t\t}\n\t\t\tvar nextDot = docDomain.indexOf(\".\");\n\t\t\tif (nextDot < 0)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdocDomain = docDomain.substr(nextDot + 1);\n\t\t}\n\t\treturn this.domains[\"\"];\n\t},\n\tisActiveOnlyOnDomain: function(docDomain)\n\t{\n\t\tif (!docDomain || !this.getDomains() || this.getDomains()[\"\"])\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tif (this.ignoreTrailingDot)\n\t\t{\n\t\t\tdocDomain = docDomain.replace(/\\.+$/, \"\");\n\t\t}\n\t\tdocDomain = docDomain.toUpperCase();\n\t\tfor (var domain in this.getDomains())\n\t\t{\n\t\t\tif (this.domains[domain] && domain != docDomain && (domain.length <= docDomain.length || domain.indexOf(\".\" + docDomain) != domain.length - docDomain.length - 1))\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n});\n\nfunction RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys)\n{\n\tActiveFilter.call(this, text, domains, sitekeys);\n\tif (contentType != null)\n\t{\n\t\tthis.contentType = contentType;\n\t}\n\tif (matchCase)\n\t{\n\t\tthis.matchCase = matchCase;\n\t}\n\tif (thirdParty != null)\n\t{\n\t\tthis.thirdParty = thirdParty;\n\t}\n\tif (sitekeys != null)\n\t{\n\t\tthis.sitekeySource = sitekeys;\n\t}\n\tif (regexpSource.length >= 2 && regexpSource.charAt(0) == \"/\" && regexpSource.charAt(regexpSource.length - 1) == \"/\")\n\t{\n\t\tvar regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), this.matchCase ? \"\" : \"i\");\n\t\tthis.regexp = regexp;\n\t}\n\telse\n\t{\n\t\tthis.regexpSource = regexpSource;\n\t}\n}\nextend(RegExpFilter, ActiveFilter, {\n\tdomainSourceIsUpperCase: true,\n\tlength: 1,\n\tdomainSeparator: \"|\",\n\tregexpSource: null,\n\tgetRegexp: function()\n\t{\n\t\tvar prop = getOwnPropertyDescriptor(this, \"regexp\");\n\t\tif (prop)\n\t\t{\n\t\t\treturn prop;\n\t\t}\n\t\tvar source = this.regexpSource.replace(/\\*+/g, \"*\").replace(/\\^\\|$/, \"^\").replace(/\\W/g, \"\\\\$&\").replace(/\\\\\\*/g, \".*\").replace(/\\\\\\^/g, \"(?:[\\\\x00-\\\\x24\\\\x26-\\\\x2C\\\\x2F\\\\x3A-\\\\x40\\\\x5B-\\\\x5E\\\\x60\\\\x7B-\\\\x7F]|$)\").replace(/^\\\\\\|\\\\\\|/, \"^[\\\\w\\\\-]+:\\\\/+(?!\\\\/)(?:[^\\\\/]+\\\\.)?\").replace(/^\\\\\\|/, \"^\").replace(/\\\\\\|$/, \"$\").replace(/^(\\.\\*)/, \"\").replace(/(\\.\\*)$/, \"\");\n\t\tvar regexp = new RegExp(source, this.matchCase ? \"\" : \"i\");\n\t\tthis.regexp = regexp;\n\t\treturn regexp;\n\t},\n\tcontentType: 2147483647,\n\tmatchCase: false,\n\tthirdParty: null,\n\tsitekeySource: null,\n\tgetSitekeys: function()\n\t{\n\t\tvar prop = getOwnPropertyDescriptor(this, \"sitekeys\");\n\t\tif (prop)\n\t\t{\n\t\t\treturn prop;\n\t\t}\n\t\tvar sitekeys = null;\n\t\tif (this.sitekeySource)\n\t\t{\n\t\t\tsitekeys = this.sitekeySource.split(\"|\");\n\t\t\tthis.sitekeySource = null;\n\t\t}\n\t\tthis.sitekeys = sitekeys;\n\t\treturn this.sitekeys;\n\t},\n\tmatches: function(location, contentType, docDomain, thirdParty, sitekey)\n\t{\n\t\tif (this.getRegexp().test(location) && this.isActiveOnDomain(docDomain, sitekey))\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n});\nRegExpFilter.prototype[\"0\"] = \"#this\";\nRegExpFilter.fromText = function(text)\n{\n\tvar blocking = true;\n\tvar origText = text;\n\tif (text.indexOf(\"@@\") == 0)\n\t{\n\t\tblocking = false;\n\t\ttext = text.substr(2);\n\t}\n\tvar contentType = null;\n\tvar matchCase = null;\n\tvar domains = null;\n\tvar sitekeys = null;\n\tvar thirdParty = null;\n\tvar collapse = null;\n\tvar options;\n\tvar match = text.indexOf(\"$\") >= 0 ? Filter.optionsRegExp.exec(text) : null;\n\tif (match)\n\t{\n\t\toptions = match[1].toUpperCase().split(\",\");\n\t\ttext = match.input.substr(0, match.index);\n\t\tfor (var _loopIndex6 = 0; _loopIndex6 < options.length; ++_loopIndex6)\n\t\t{\n\t\t\tvar option = options[_loopIndex6];\n\t\t\tvar value = null;\n\t\t\tvar separatorIndex = option.indexOf(\"=\");\n\t\t\tif (separatorIndex >= 0)\n\t\t\t{\n\t\t\t\tvalue = option.substr(separatorIndex + 1);\n\t\t\t\toption = option.substr(0, separatorIndex);\n\t\t\t}\n\t\t\toption = option.replace(/-/, \"_\");\n\t\t\tif (option in RegExpFilter.typeMap)\n\t\t\t{\n\t\t\t\tif (contentType == null)\n\t\t\t\t{\n\t\t\t\t\tcontentType = 0;\n\t\t\t\t}\n\t\t\t\tcontentType |= RegExpFilter.typeMap[option];\n\t\t\t}\n\t\t\telse if (option.charAt(0) == \"~\" && option.substr(1) in RegExpFilter.typeMap)\n\t\t\t{\n\t\t\t\tif (contentType == null)\n\t\t\t\t{\n\t\t\t\t\tcontentType = RegExpFilter.prototype.contentType;\n\t\t\t\t}\n\t\t\t\tcontentType &= ~RegExpFilter.typeMap[option.substr(1)];\n\t\t\t}\n\t\t\telse if (option == \"MATCH_CASE\")\n\t\t\t{\n\t\t\t\tmatchCase = true;\n\t\t\t}\n\t\t\telse if (option == \"~MATCH_CASE\")\n\t\t\t{\n\t\t\t\tmatchCase = false;\n\t\t\t}\n\t\t\telse if (option == \"DOMAIN\" && typeof value != \"undefined\")\n\t\t\t{\n\t\t\t\tdomains = value;\n\t\t\t}\n\t\t\telse if (option == \"THIRD_PARTY\")\n\t\t\t{\n\t\t\t\tthirdParty = true;\n\t\t\t}\n\t\t\telse if (option == \"~THIRD_PARTY\")\n\t\t\t{\n\t\t\t\tthirdParty = false;\n\t\t\t}\n\t\t\telse if (option == \"COLLAPSE\")\n\t\t\t{\n\t\t\t\tcollapse = true;\n\t\t\t}\n\t\t\telse if (option == \"~COLLAPSE\")\n\t\t\t{\n\t\t\t\tcollapse = false;\n\t\t\t}\n\t\t\telse if (option == \"SITEKEY\" && typeof value != \"undefined\")\n\t\t\t{\n\t\t\t\tsitekeys = value;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn new InvalidFilter(origText, \"Unknown option \" + option.toLowerCase());\n\t\t\t}\n\t\t}\n\t}\n\tif (!blocking && (contentType == null || contentType & RegExpFilter.typeMap.DOCUMENT) && (!options || options.indexOf(\"DOCUMENT\") < 0) && !/^\\|?[\\w\\-]+:/.test(text))\n\t{\n\t\tif (contentType == null)\n\t\t{\n\t\t\tcontentType = RegExpFilter.prototype.contentType;\n\t\t}\n\t\tcontentType &= ~RegExpFilter.typeMap.DOCUMENT;\n\t}\n\ttry\n\t{\n\t\tif (blocking)\n\t\t{\n\t\t\treturn new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn new WhitelistFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys);\n\t\t}\n\t}\n\tcatch (e)\n\t{\n\t\treturn new InvalidFilter(origText, e);\n\t}\n};\nRegExpFilter.typeMap = {\n\tOTHER: 1,\n\tSCRIPT: 2,\n\tIMAGE: 4,\n\tSTYLESHEET: 8,\n\tOBJECT: 16,\n\tSUBDOCUMENT: 32,\n\tDOCUMENT: 64,\n\tXBL: 1,\n\tPING: 1,\n\tXMLHTTPREQUEST: 2048,\n\tOBJECT_SUBREQUEST: 4096,\n\tDTD: 1,\n\tMEDIA: 16384,\n\tFONT: 32768,\n\tBACKGROUND: 4,\n\tPOPUP: 268435456,\n\tELEMHIDE: 1073741824\n};\nRegExpFilter.prototype.contentType &= ~ (RegExpFilter.typeMap.ELEMHIDE | RegExpFilter.typeMap.POPUP);\n\nfunction BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys, collapse)\n{\n\tRegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys);\n\tthis.collapse = collapse;\n}\nextend(BlockingFilter, RegExpFilter, {\n\tcollapse: null\n});\n\nfunction WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys)\n{\n\tRegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys);\n}\nextend(WhitelistFilter, RegExpFilter, {\n});\n\nfunction Matcher()\n{\n\tthis.clear();\n}\nMatcher.prototype = {\n\tfilterByKeyword: null,\n\tkeywordByFilter: null,\n\tclear: function()\n\t{\n\t\tthis.filterByKeyword = createDict();\n\t\tthis.keywordByFilter = createDict();\n\t},\n\tadd: function(filter)\n\t{\n\t\tif (filter.text in this.keywordByFilter)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tvar keyword = this.findKeyword(filter);\n\t\tvar oldEntry = this.filterByKeyword[keyword];\n\t\tif (typeof oldEntry == \"undefined\")\n\t\t{\n\t\t\tthis.filterByKeyword[keyword] = filter;\n\t\t}\n\t\telse if (oldEntry.length == 1)\n\t\t{\n\t\t\tthis.filterByKeyword[keyword] = [oldEntry, filter];\n\t\t}\n\t\telse\n\t\t{\n\t\t\toldEntry.push(filter);\n\t\t}\n\t\tthis.keywordByFilter[filter.text] = keyword;\n\t},\n\tremove: function(filter)\n\t{\n\t\tif (!(filter.text in this.keywordByFilter))\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tvar keyword = this.keywordByFilter[filter.text];\n\t\tvar list = this.filterByKeyword[keyword];\n\t\tif (list.length <= 1)\n\t\t{\n\t\t\tdelete this.filterByKeyword[keyword];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvar index = list.indexOf(filter);\n\t\t\tif (index >= 0)\n\t\t\t{\n\t\t\t\tlist.splice(index, 1);\n\t\t\t\tif (list.length == 1)\n\t\t\t\t{\n\t\t\t\t\tthis.filterByKeyword[keyword] = list[0];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdelete this.keywordByFilter[filter.text];\n\t},\n\tfindKeyword: function(filter)\n\t{\n\t\tvar result = \"\";\n\t\tvar text = filter.text;\n\t\tif (Filter.regexpRegExp.test(text))\n\t\t{\n\t\t\treturn result;\n\t\t}\n\t\tvar match = Filter.optionsRegExp.exec(text);\n\t\tif (match)\n\t\t{\n\t\t\ttext = match.input.substr(0, match.index);\n\t\t}\n\t\tif (text.substr(0, 2) == \"@@\")\n\t\t{\n\t\t\ttext = text.substr(2);\n\t\t}\n\t\tvar candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g);\n\t\tif (!candidates)\n\t\t{\n\t\t\treturn result;\n\t\t}\n\t\tvar hash = this.filterByKeyword;\n\t\tvar resultCount = 16777215;\n\t\tvar resultLength = 0;\n\t\tfor (var i = 0, l = candidates.length; i < l; i++)\n\t\t{\n\t\t\tvar candidate = candidates[i].substr(1);\n\t\t\tvar count = candidate in hash ? hash[candidate].length : 0;\n\t\t\tif (count < resultCount || count == resultCount && candidate.length > resultLength)\n\t\t\t{\n\t\t\t\tresult = candidate;\n\t\t\t\tresultCount = count;\n\t\t\t\tresultLength = candidate.length;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t},\n\thasFilter: function(filter)\n\t{\n\t\treturn filter.text in this.keywordByFilter;\n\t},\n\tgetKeywordForFilter: function(filter)\n\t{\n\t\tif (filter.text in this.keywordByFilter)\n\t\t{\n\t\t\treturn this.keywordByFilter[filter.text];\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn null;\n\t\t}\n\t},\n\t_checkEntryMatch: function(keyword, location, contentType, docDomain, thirdParty, sitekey)\n\t{\n\t\tvar list = this.filterByKeyword[keyword];\n\t\tfor (var i = 0; i < list.length; i++)\n\t\t{\n\t\t\tvar filter = list[i];\n\t\t\tif (filter == \"#this\")\n\t\t\t{\n\t\t\t\tfilter = list;\n\t\t\t}\n\t\t\tif (filter.matches(location, contentType, docDomain, thirdParty, sitekey))\n\t\t\t{\n\t\t\t\treturn filter;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t},\n\tmatchesAny: function(location, contentType, docDomain, thirdParty, sitekey)\n\t{\n\t\tvar candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);\n\t\tif (candidates === null)\n\t\t{\n\t\t\tcandidates = [];\n\t\t}\n\t\tcandidates.push(\"\");\n\t\tfor (var i = 0, l = candidates.length; i < l; i++)\n\t\t{\n\t\t\tvar substr = candidates[i];\n\t\t\tif (substr in this.filterByKeyword)\n\t\t\t{\n\t\t\t\tvar result = this._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);\n\t\t\t\tif (result)\n\t\t\t\t{\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n};\n\nfunction CombinedMatcher()\n{\n\tthis.blacklist = new Matcher();\n\tthis.whitelist = new Matcher();\n\tthis.resultCache = createDict();\n}\nCombinedMatcher.maxCacheEntries = 1000;\nCombinedMatcher.prototype = {\n\tblacklist: null,\n\twhitelist: null,\n\tresultCache: null,\n\tcacheEntries: 0,\n\tclear: function()\n\t{\n\t\tthis.blacklist.clear();\n\t\tthis.whitelist.clear();\n\t\tthis.resultCache = createDict();\n\t\tthis.cacheEntries = 0;\n\t},\n\tadd: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\tthis.whitelist.add(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.blacklist.add(filter);\n\t\t}\n\t\tif (this.cacheEntries > 0)\n\t\t{\n\t\t\tthis.resultCache = createDict();\n\t\t\tthis.cacheEntries = 0;\n\t\t}\n\t},\n\tremove: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\tthis.whitelist.remove(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis.blacklist.remove(filter);\n\t\t}\n\t\tif (this.cacheEntries > 0)\n\t\t{\n\t\t\tthis.resultCache = createDict();\n\t\t\tthis.cacheEntries = 0;\n\t\t}\n\t},\n\tfindKeyword: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\treturn this.whitelist.findKeyword(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn this.blacklist.findKeyword(filter);\n\t\t}\n\t},\n\thasFilter: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\treturn this.whitelist.hasFilter(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn this.blacklist.hasFilter(filter);\n\t\t}\n\t},\n\tgetKeywordForFilter: function(filter)\n\t{\n\t\tif (filter instanceof WhitelistFilter)\n\t\t{\n\t\t\treturn this.whitelist.getKeywordForFilter(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn this.blacklist.getKeywordForFilter(filter);\n\t\t}\n\t},\n\tisSlowFilter: function(filter)\n\t{\n\t\tvar matcher = filter instanceof WhitelistFilter ? this.whitelist : this.blacklist;\n\t\tif (matcher.hasFilter(filter))\n\t\t{\n\t\t\treturn !matcher.getKeywordForFilter(filter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn !matcher.findKeyword(filter);\n\t\t}\n\t},\n\tmatchesAnyInternal: function(location, contentType, docDomain, thirdParty, sitekey)\n\t{\n\t\tvar candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);\n\t\tif (candidates === null)\n\t\t{\n\t\t\tcandidates = [];\n\t\t}\n\t\tcandidates.push(\"\");\n\t\tvar blacklistHit = null;\n\t\tfor (var i = 0, l = candidates.length; i < l; i++)\n\t\t{\n\t\t\tvar substr = candidates[i];\n\t\t\tif (substr in this.whitelist.filterByKeyword)\n\t\t\t{\n\t\t\t\tvar result = this.whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);\n\t\t\t\tif (result)\n\t\t\t\t{\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (substr in this.blacklist.filterByKeyword && blacklistHit === null)\n\t\t\t{\n\t\t\t\tblacklistHit = this.blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey);\n\t\t\t}\n\t\t}\n\t\treturn blacklistHit;\n\t},\n\tmatchesAny: function(location, docDomain)\n\t{\n\t\tvar key = location + \" \" + docDomain + \" \";\n\t\tif (key in this.resultCache)\n\t\t{\n\t\t\treturn this.resultCache[key];\n\t\t}\n\t\tvar result = this.matchesAnyInternal(location, 0, docDomain, null, null);\n\t\tif (this.cacheEntries >= CombinedMatcher.maxCacheEntries)\n\t\t{\n\t\t\tthis.resultCache = createDict();\n\t\t\tthis.cacheEntries = 0;\n\t\t}\n\t\tthis.resultCache[key] = result;\n\t\tthis.cacheEntries++;\n\t\treturn result;\n\t}\n};\n\nvar userrulesMatcher = new CombinedMatcher();\nvar defaultMatcher = new CombinedMatcher();\n\nfor (var i = 0; i < userrules.length; i++) {\n    userrulesMatcher.add(Filter.fromText(userrules[i]));\n}\n\nfor (var i = 0; i < rules.length; i++) {\n\tdefaultMatcher.add(Filter.fromText(rules[i]));\n}\n\nvar subnetIpRangeList = [\n0,16777216,\t\t\t\t//0.0.0.0/8\n167772160,184549376,\t//10.0.0.0/8\n1681915904,1686110208,\t//100.64.0.0/10\n2130706432,2147483648,\t//127.0.0.0/8\n2851995648,2852061184,\t//169.254.0.0/16\n2886729728,2887778304,\t//172.16.0.0/12\n3221225472,3221225728,\t//192.0.0.0/24\n3221225984,3221226240,\t//192.0.2.0/24\n3227017984,3227018240,\t//192.88.99.0/24\n3232235520,3232301056,\t//192.168.0.0/16\n3323068416,3323199488,\t//198.18.0.0/15\n3325256704,3325256960,\t//198.51.100.0/24\n3405803776,3405804032,\t//203.0.113.0/24\n3758096384,4026531840\t//224.0.0.0/4\n];\n\nfunction convertAddress(ipchars) {\n\tvar bytes = ipchars.split('.');\n\tvar result = (bytes[0] << 24) |\n\t(bytes[1] << 16) |\n\t(bytes[2] << 8) |\n\t(bytes[3]);\n\treturn result >>> 0;\n}\n\nfunction check_ipv4(host) {\n\tvar re_ipv4 = /^\\d+\\.\\d+\\.\\d+\\.\\d+$/g;\n\tif (re_ipv4.test(host)) {\n\t\treturn true;\n\t}\n}\nfunction check_ipv6(host) {\n\tvar re_ipv6 = /^\\[?([a-fA-F0-9]{0,4}\\:){1,7}[a-fA-F0-9]{0,4}\\]?$/g;\n\tif (re_ipv6.test(host)) {\n\t\treturn true;\n\t}\n}\nfunction check_ipv6_dns(dnsstr) {\n\tvar re_ipv6 = /([a-fA-F0-9]{0,4}\\:){1,7}[a-fA-F0-9]{0,4}(%[0-9]+)?/g;\n\tif (re_ipv6.test(dnsstr)) {\n\t\treturn true;\n\t}\n}\nfunction isInSubnetRange(ipRange, intIp) {\n\tfor ( var i = 0; i < 28; i += 2 ) {\n\t\tif ( ipRange[i] <= intIp && intIp < ipRange[i+1] )\n\t\t\treturn true;\n\t}\n}\nfunction getProxyFromIP(strIp) {\n\tvar intIp = convertAddress(strIp);\n\tif ( isInSubnetRange(subnetIpRangeList, intIp) ) {\n\t\treturn direct;\n\t}\n\treturn ip_proxy();\n}\n\nfunction FindProxyForURL(url, host) {\n\tif ( isPlainHostName(host) === true ) {\n\t\treturn direct;\n\t}\n\tif (userrulesMatcher.matchesAny(url, host) instanceof BlockingFilter) {\n        return wall_proxy();\n    }\n    if (userrulesMatcher.matchesAny(url, host) instanceof WhitelistFilter) {\n        return direct;\n    }\n\tif (defaultMatcher.matchesAny(url, host) instanceof BlockingFilter) {\n\t\treturn wall_proxy();\n\t}\n\tif ( check_ipv4(host) === true ) {\n\t\treturn getProxyFromIP(host);\n\t}\n\treturn direct;\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Data/user-rule.txt",
    "content": "﻿! Put user rules line by line in this file.\r\n! See https://adblockplus.org/en/filter-cheatsheet\r\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/CircularBuffer/ByteCircularBuffer.cs",
    "content": "#region Original License\n\n//New BSD License(BSD)\n//\n//Copyright(c) 2014-2015 Cyotek Ltd\n//Copyright(c) 2012, Alex Regueiro\n//All rights reserved.\n//\n//Redistribution and use in source and binary forms, with or without\n//modification, are permitted provided that the following conditions are met:\n//    * Redistributions of source code must retain the above copyright\n//      notice, this list of conditions and the following disclaimer.\n//    * Redistributions in binary form must reproduce the above copyright\n//      notice, this list of conditions and the following disclaimer in the\n//      documentation and/or other materials provided with the distribution.\n//    * Neither the name of Cyotek nor the\n//      names of its contributors may be used to endorse or promote products\n//      derived from this software without specific prior written permission.\n//\n//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n//DISCLAIMED.IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\n//DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#endregion\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Encryption.CircularBuffer\n{\n    /// <summary>\n    /// Represents a first-in, first-out collection of objects using a fixed buffer.\n    /// </summary>\n    /// <remarks>\n    /// <para>The capacity of a <see cref=\"ByteCircularBuffer\" /> is the number of elements the <see cref=\"ByteCircularBuffer\"/> can hold. </para>\n    /// <para>ByteCircularBuffer accepts <c>null</c> as a valid value for reference types and allows duplicate elements.</para>\n    /// <para>The <see cref=\"Get()\"/> methods will remove the items that are returned from the ByteCircularBuffer. To view the contents of the ByteCircularBuffer without removing items, use the <see cref=\"Peek()\"/> or <see cref=\"PeekLast\"/> methods.</para>\n    /// </remarks>\n    public class ByteCircularBuffer\n    {\n        // based on http://circularbuffer.codeplex.com/\n        // http://en.wikipedia.org/wiki/Circular_buffer\n        // modified from https://github.com/cyotek/Cyotek.Collections.Generic.CircularBuffer\n        // some code taken from https://github.com/xorxornop/RingBuffer\n        // and https://github.com/xorxornop/PerfCopy\n\n        #region Instance Fields\n\n        private byte[] _buffer;\n\n        private int _capacity;\n\n        #endregion\n\n        #region Public Constructors\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ByteCircularBuffer\"/> class that is empty and has the specified initial capacity.\n        /// </summary>\n        /// <param name=\"capacity\">The maximum capcity of the buffer.</param>\n        /// <exception cref=\"System.ArgumentException\">Thown if the <paramref name=\"capacity\"/> is less than zero.</exception>\n        public ByteCircularBuffer(int capacity)\n        {\n            if (capacity < 0)\n            {\n                throw new ArgumentException(@\"The buffer capacity must be greater than or equal to zero.\",\n                    nameof(capacity));\n            }\n\n            _buffer = new byte[capacity];\n            this.Capacity = capacity;\n            this.Size = 0;\n            this.Head = 0;\n            this.Tail = 0;\n        }\n\n        #endregion\n\n        #region Public Properties\n\n        /// <summary>\n        /// Gets or sets the total number of elements the internal data structure can hold.\n        /// </summary>\n        /// <value>The total number of elements that the <see cref=\"ByteCircularBuffer\"/> can contain.</value>\n        /// <exception cref=\"System.ArgumentOutOfRangeException\">Thrown if the specified new capacity is smaller than the current contents of the buffer.</exception>\n        public int Capacity\n        {\n            get { return _capacity; }\n            set\n            {\n                if (value != _capacity)\n                {\n                    if (value < this.Size)\n                    {\n                        throw new ArgumentOutOfRangeException(nameof(value), value,\n                            @\"The new capacity must be greater than or equal to the buffer size.\");\n                    }\n\n                    var newBuffer = new byte[value];\n                    if (this.Size > 0)\n                    {\n                        this.CopyTo(newBuffer);\n                    }\n\n                    _buffer = newBuffer;\n\n                    _capacity = value;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets the index of the beginning of the buffer data.\n        /// </summary>\n        /// <value>The index of the first element in the buffer.</value>\n        public int Head { get; protected set; }\n\n        /// <summary>\n        /// Gets a value indicating whether the buffer is empty.\n        /// </summary>\n        /// <value><c>true</c> if buffer is empty; otherwise, <c>false</c>.</value>\n        public virtual bool IsEmpty => this.Size == 0;\n\n        /// <summary>\n        /// Gets a value indicating whether the buffer is full.\n        /// </summary>\n        /// <value><c>true</c> if the buffer is full; otherwise, <c>false</c>.</value>\n        /// <remarks>The <see cref=\"IsFull\"/> property always returns <c>false</c> if the property is set to <c>true</c>.</remarks>\n        public virtual bool IsFull => this.Size == this.Capacity;\n\n        /// <summary>\n        /// Gets the number of elements contained in the <see cref=\"ByteCircularBuffer\"/>.\n        /// </summary>\n        /// <value>The number of elements contained in the <see cref=\"ByteCircularBuffer\"/>.</value>\n        public int Size { get; protected set; }\n\n        /// <summary>\n        /// Gets the index of the end of the buffer data.\n        /// </summary>\n        /// <value>The index of the last element in the buffer.</value>\n        public int Tail { get; protected set; }\n\n        #endregion\n\n        #region Public Members\n\n        /// <summary>\n        /// Removes all items from the <see cref=\"ByteCircularBuffer\" />.\n        /// </summary>\n        public void Clear()\n        {\n            this.Size = 0;\n            this.Head = 0;\n            this.Tail = 0;\n            _buffer = new byte[this.Capacity];\n        }\n\n        /// <summary>\n        /// Determines whether the <see cref=\"ByteCircularBuffer\" /> contains a specific value.\n        /// </summary>\n        /// <param name=\"item\">The object to locate in the <see cref=\"ByteCircularBuffer\" />.</param>\n        /// <returns><c>true</c> if <paramref name=\"item\" /> is found in the <see cref=\"ByteCircularBuffer\" />; otherwise, <c>false</c>.</returns>\n        public bool Contains(byte item)\n        {\n            var bufferIndex = this.Head;\n            var comparer = EqualityComparer<byte>.Default;\n            var result = false;\n\n            for (int i = 0; i < this.Size; i++, bufferIndex++)\n            {\n                if (bufferIndex == this.Capacity)\n                {\n                    bufferIndex = 0;\n                }\n\n                if (comparer.Equals(_buffer[bufferIndex], item))\n                {\n                    result = true;\n                    break;\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Copies the entire <see cref=\"ByteCircularBuffer\"/> to a compatible one-dimensional array, starting at the beginning of the target array.\n        /// </summary>\n        /// <param name=\"array\">The one-dimensional <see cref=\"Array\"/> that is the destination of the elements copied from <see cref=\"ByteCircularBuffer\"/>. The <see cref=\"Array\"/> must have zero-based indexing.</param>\n        public void CopyTo(byte[] array)\n        {\n            this.CopyTo(array, 0);\n        }\n\n        /// <summary>\n        /// Copies the entire <see cref=\"ByteCircularBuffer\"/> to a compatible one-dimensional array, starting at the specified index of the target array.\n        /// </summary>\n        /// <param name=\"array\">The one-dimensional <see cref=\"Array\"/> that is the destination of the elements copied from <see cref=\"ByteCircularBuffer\"/>. The <see cref=\"Array\"/> must have zero-based indexing.</param>\n        /// <param name=\"arrayIndex\">The zero-based index in <paramref name=\"array\"/> at which copying begins.</param>\n        public void CopyTo(byte[] array, int arrayIndex)\n        {\n            this.CopyTo(this.Head, array, arrayIndex, Math.Min(this.Size, array.Length - arrayIndex));\n        }\n\n        /// <summary>\n        /// Copies a range of elements from the <see cref=\"ByteCircularBuffer\"/> to a compatible one-dimensional array, starting at the specified index of the target array.\n        /// </summary>\n        /// <param name=\"index\">The zero-based index in the source <see cref=\"ByteCircularBuffer\"/> at which copying begins.</param>\n        /// <param name=\"array\">The one-dimensional <see cref=\"Array\"/> that is the destination of the elements copied from <see cref=\"ByteCircularBuffer\"/>. The <see cref=\"Array\"/> must have zero-based indexing.</param>\n        /// <param name=\"arrayIndex\">The zero-based index in <paramref name=\"array\"/> at which copying begins.</param>\n        /// <param name=\"count\">The number of elements to copy.</param>\n        public virtual void CopyTo(int index, byte[] array, int arrayIndex, int count)\n        {\n            if (count > this.Size)\n            {\n                throw new ArgumentOutOfRangeException(nameof(count), count,\n                    @\"The read count cannot be greater than the buffer size.\");\n            }\n\n            var startAnchor = index;\n            var dstIndex = arrayIndex;\n\n            while (count > 0)\n            {\n                int chunk = Math.Min(Capacity - startAnchor, count);\n                Buffer.BlockCopy(_buffer, startAnchor, array, dstIndex, chunk);\n                startAnchor = (startAnchor + chunk == Capacity) ? 0 : startAnchor + chunk;\n                dstIndex += chunk;\n                count -= chunk;\n            }\n        }\n\n        /// <summary>\n        /// Removes and returns the specified number of objects from the beginning of the <see cref=\"ByteCircularBuffer\"/>.\n        /// </summary>\n        /// <param name=\"count\">The number of elements to remove and return from the <see cref=\"ByteCircularBuffer\"/>.</param>\n        /// <returns>The objects that are removed from the beginning of the <see cref=\"ByteCircularBuffer\"/>.</returns>\n        public byte[] Get(int count)\n        {\n            if (count <= 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(count));\n            }\n\n            var result = new byte[count];\n\n            this.Get(result);\n\n            return result;\n        }\n\n        /// <summary>\n        /// Copies and removes the specified number elements from the <see cref=\"ByteCircularBuffer\"/> to a compatible one-dimensional array, starting at the beginning of the target array. \n        /// </summary>\n        /// <param name=\"array\">The one-dimensional <see cref=\"Array\"/> that is the destination of the elements copied from <see cref=\"ByteCircularBuffer\"/>. The <see cref=\"Array\"/> must have zero-based indexing.</param>\n        /// <returns>The actual number of elements copied into <paramref name=\"array\"/>.</returns>\n        public int Get(byte[] array)\n        {\n            if (array.Length <= 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(array));\n            }\n\n            return this.Get(array, 0, array.Length);\n        }\n\n        /// <summary>\n        /// Copies and removes the specified number elements from the <see cref=\"ByteCircularBuffer\"/> to a compatible one-dimensional array, starting at the specified index of the target array. \n        /// </summary>\n        /// <param name=\"array\">The one-dimensional <see cref=\"Array\"/> that is the destination of the elements copied from <see cref=\"ByteCircularBuffer\"/>. The <see cref=\"Array\"/> must have zero-based indexing.</param>\n        /// <param name=\"arrayIndex\">The zero-based index in <paramref name=\"array\"/> at which copying begins.</param>\n        /// <param name=\"count\">The number of elements to copy.</param>\n        /// <returns>The actual number of elements copied into <paramref name=\"array\"/>.</returns>\n        public virtual int Get(byte[] array, int arrayIndex, int count)\n        {\n            if (arrayIndex < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(arrayIndex), @\"Negative offset specified. Offsets must be positive.\");\n            }\n            if (count < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(count), @\"Negative count specified. Count must be positive.\");\n            }\n            if (count > this.Size)\n            {\n                throw new ArgumentException(@\"Ringbuffer contents insufficient for take/read operation.\", nameof(count));\n            }\n            if (array.Length < arrayIndex + count)\n            {\n                throw new ArgumentException(\"Destination array too small for requested output.\");\n            }\n            var bytesCopied = 0;\n            var dstIndex = arrayIndex;\n            while (count > 0)\n            {\n                int chunk = Math.Min(Capacity - this.Head, count);\n                Buffer.BlockCopy(_buffer, this.Head, array, dstIndex, chunk);\n                this.Head = (this.Head + chunk == Capacity) ? 0 : this.Head + chunk;\n                this.Size -= chunk;\n                dstIndex += chunk;\n                bytesCopied += chunk;\n                count -= chunk;\n            }\n            return bytesCopied;\n        }\n\n        /// <summary>\n        /// Removes and returns the object at the beginning of the <see cref=\"ByteCircularBuffer\"/>.\n        /// </summary>\n        /// <returns>The object that is removed from the beginning of the <see cref=\"ByteCircularBuffer\"/>.</returns>\n        /// <exception cref=\"System.InvalidOperationException\">Thrown if the buffer is empty.</exception>\n        /// <remarks>This method is similar to the <see cref=\"Peek()\"/> method, but <c>Peek</c> does not modify the <see cref=\"ByteCircularBuffer\"/>.</remarks>\n        public virtual byte Get()\n        {\n            if (this.IsEmpty)\n            {\n                throw new InvalidOperationException(\"The buffer is empty.\");\n            }\n\n            var item = _buffer[this.Head];\n            if (++this.Head == this.Capacity)\n            {\n                this.Head = 0;\n            }\n            this.Size--;\n\n            return item;\n        }\n\n        /// <summary>\n        /// Returns the object at the beginning of the <see cref=\"ByteCircularBuffer\"/> without removing it.\n        /// </summary>\n        /// <returns>The object at the beginning of the <see cref=\"ByteCircularBuffer\"/>.</returns>\n        /// <exception cref=\"System.InvalidOperationException\">Thrown if the buffer is empty.</exception>\n        public virtual byte Peek()\n        {\n            if (this.IsEmpty)\n            {\n                throw new InvalidOperationException(\"The buffer is empty.\");\n            }\n\n            var item = _buffer[this.Head];\n\n            return item;\n        }\n\n        /// <summary>\n        /// Returns the specified number of objects from the beginning of the <see cref=\"ByteCircularBuffer\"/>.\n        /// </summary>\n        /// <param name=\"count\">The number of elements to return from the <see cref=\"ByteCircularBuffer\"/>.</param>\n        /// <returns>The objects that from the beginning of the <see cref=\"ByteCircularBuffer\"/>.</returns>\n        /// <exception cref=\"System.InvalidOperationException\">Thrown if the buffer is empty.</exception>\n        public virtual byte[] Peek(int count)\n        {\n            if (this.IsEmpty)\n            {\n                throw new InvalidOperationException(\"The buffer is empty.\");\n            }\n\n            var items = new byte[count];\n            this.CopyTo(items);\n\n            return items;\n        }\n\n        /// <summary>\n        /// Returns the object at the end of the <see cref=\"ByteCircularBuffer\"/> without removing it.\n        /// </summary>\n        /// <returns>The object at the end of the <see cref=\"ByteCircularBuffer\"/>.</returns>\n        /// <exception cref=\"System.InvalidOperationException\">Thrown if the buffer is empty.</exception>\n        public virtual byte PeekLast()\n        {\n            int bufferIndex;\n\n            if (this.IsEmpty)\n            {\n                throw new InvalidOperationException(\"The buffer is empty.\");\n            }\n\n            if (this.Tail == 0)\n            {\n                bufferIndex = this.Size - 1;\n            }\n            else\n            {\n                bufferIndex = this.Tail - 1;\n            }\n\n            var item = _buffer[bufferIndex];\n\n            return item;\n        }\n\n        /// <summary>\n        /// Copies an entire compatible one-dimensional array to the <see cref=\"ByteCircularBuffer\"/>.\n        /// </summary>\n        /// <param name=\"array\">The one-dimensional <see cref=\"Array\"/> that is the source of the elements copied to <see cref=\"ByteCircularBuffer\"/>. The <see cref=\"Array\"/> must have zero-based indexing.</param>\n        /// <exception cref=\"System.InvalidOperationException\">Thrown if buffer does not have sufficient capacity to put in new items.</exception>\n        /// <remarks>If <see cref=\"Size\"/> plus the size of <paramref name=\"array\"/> exceeds the capacity of the <see cref=\"ByteCircularBuffer\"/> and the property is <c>true</c>, the oldest items in the <see cref=\"ByteCircularBuffer\"/> are overwritten with <paramref name=\"array\"/>.</remarks>\n        public int Put(byte[] array)\n        {\n            return this.Put(array, 0, array.Length);\n        }\n\n        /// <summary>\n        /// Copies a range of elements from a compatible one-dimensional array to the <see cref=\"ByteCircularBuffer\"/>.\n        /// </summary>\n        /// <param name=\"array\">The one-dimensional <see cref=\"Array\"/> that is the source of the elements copied to <see cref=\"ByteCircularBuffer\"/>. The <see cref=\"Array\"/> must have zero-based indexing.</param>\n        /// <param name=\"arrayIndex\">The zero-based index in <paramref name=\"array\"/> at which copying begins.</param>\n        /// <param name=\"count\">The number of elements to copy.</param>\n        /// <exception cref=\"System.InvalidOperationException\">Thrown if buffer does not have sufficient capacity to put in new items.</exception>\n        /// <remarks>If <see cref=\"Size\"/> plus <paramref name=\"count\"/> exceeds the capacity of the <see cref=\"ByteCircularBuffer\"/> and the property is <c>true</c>, the oldest items in the <see cref=\"ByteCircularBuffer\"/> are overwritten with <paramref name=\"array\"/>.</remarks>\n        public virtual int Put(byte[] array, int arrayIndex, int count)\n        {\n            if (count <= 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(count), @\"Count must be positive.\");\n            }\n\n            if (this.Size + count > this.Capacity)\n            {\n                throw new InvalidOperationException(\"The buffer does not have sufficient capacity to put new items.\");\n            }\n\n            if (array.Length < arrayIndex + count)\n            {\n                throw new ArgumentException(\"Source array too small for requested input.\");\n            }\n            var srcIndex = arrayIndex;\n            var bytesToProcess = count;\n            while (bytesToProcess > 0)\n            {\n                int chunk = Math.Min(Capacity - Tail, bytesToProcess);\n                Buffer.BlockCopy(array, srcIndex, _buffer, Tail, chunk);\n                Tail = (Tail + chunk == Capacity) ? 0 : Tail + chunk;\n                this.Size += chunk;\n                srcIndex += chunk;\n                bytesToProcess -= chunk;\n            }\n\n            return count;\n        }\n\n        /// <summary>\n        /// Adds a byte to the end of the <see cref=\"ByteCircularBuffer\"/>.\n        /// </summary>\n        /// <param name=\"item\">The byte to add to the <see cref=\"ByteCircularBuffer\"/>. </param>\n        /// <exception cref=\"System.InvalidOperationException\">Thrown if buffer does not have sufficient capacity to put in new items.</exception>\n        public virtual void Put(byte item)\n        {\n            if (IsFull)\n            {\n                throw new InvalidOperationException(\"The buffer does not have sufficient capacity to put new items.\");\n            }\n\n            _buffer[this.Tail] = item;\n\n            this.Tail++;\n            if (this.Size == this.Capacity)\n            {\n                this.Head++;\n                if (this.Head >= this.Capacity)\n                {\n                    this.Head -= this.Capacity;\n                }\n            }\n\n            if (this.Tail == this.Capacity)\n            {\n                this.Tail = 0;\n            }\n\n            if (this.Size != this.Capacity)\n            {\n                this.Size++;\n            }\n        }\n\n        /// <summary>\n        /// Increments the starting index of the data buffer in the <see cref=\"ByteCircularBuffer\"/>.\n        /// </summary>\n        /// <param name=\"count\">The number of elements to increment the data buffer start index by.</param>\n        public void Skip(int count)\n        {\n            if (count < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(count), @\"Negative count specified. Count must be positive.\");\n            }\n            if (count > this.Size)\n            {\n                throw new ArgumentException(@\"Ringbuffer contents insufficient for operation.\", nameof(count));\n            }\n\n            // Modular division gives new offset position\n            this.Head = (this.Head + count) % Capacity;\n            this.Size -= count;\n        }\n\n        /// <summary>\n        /// Copies the <see cref=\"ByteCircularBuffer\"/> elements to a new array.\n        /// </summary>\n        /// <returns>A new array containing elements copied from the <see cref=\"ByteCircularBuffer\"/>.</returns>\n        /// <remarks>The <see cref=\"ByteCircularBuffer\"/> is not modified. The order of the elements in the new array is the same as the order of the elements from the beginning of the <see cref=\"ByteCircularBuffer\"/> to its end.</remarks>\n        public byte[] ToArray()\n        {\n            var result = new byte[this.Size];\n\n            this.CopyTo(result);\n\n            return result;\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/CryptoUtils.cs",
    "content": "using CryptoBase.Abstractions.Digests;\nusing CryptoBase.Digests;\nusing CryptoBase.SymmetricCryptos.BlockCryptos.AES;\nusing Shadowsocks.Crypto;\nusing System;\nusing System.Buffers;\n\nnamespace Shadowsocks.Encryption\n{\n    public static class CryptoUtils\n    {\n        public static void SsAes128(string password, ReadOnlySpan<byte> source, Span<byte> destination)\n        {\n            var buffer = ArrayPool<byte>.Shared.Rent(16);\n            try\n            {\n                buffer.AsSpan(0, 16).SsDeriveKey(password);\n                using var aes = AESUtils.CreateECB(buffer);\n                aes.Encrypt(source, destination);\n            }\n            finally\n            {\n                ArrayPool<byte>.Shared.Return(buffer);\n            }\n        }\n\n        public static byte[] MD5(ReadOnlySpan<byte> input)\n        {\n            var output = new byte[HashConstants.Md5Length];\n            using var hash = DigestUtils.Create(DigestType.Md5);\n            hash.UpdateFinal(input, output);\n            return output;\n        }\n\n        public static byte[] SHA1(ReadOnlySpan<byte> input)\n        {\n            var output = new byte[HashConstants.Sha1Length];\n            using var hash = DigestUtils.Create(DigestType.Sha1);\n            hash.UpdateFinal(input, output);\n            return output;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/EncryptorBase.cs",
    "content": "namespace Shadowsocks.Encryption\r\n{\r\n    public abstract class EncryptorBase : IEncryptor\r\n    {\r\n        public const int MAX_INPUT_SIZE = 32768;\r\n\r\n        public const int MD5_LEN = 16;\r\n\r\n        public const int ADDR_PORT_LEN = 2;\r\n        public const int ADDR_ATYP_LEN = 1;\r\n\r\n        public const int ATYP_IPv4 = 0x01;\r\n        public const int ATYP_DOMAIN = 0x03;\r\n        public const int ATYP_IPv6 = 0x04;\r\n\r\n        protected EncryptorBase(string method, string password)\r\n        {\r\n            Method = method;\r\n            Password = password;\r\n        }\r\n\r\n        protected string Method;\r\n        protected string Password;\r\n\r\n        public abstract void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength);\r\n\r\n        public abstract void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength);\r\n\r\n        public abstract void ResetEncrypt();\r\n        public abstract void ResetDecrypt();\r\n\r\n        public abstract void Dispose();\r\n        public abstract byte[] getIV();\r\n        public abstract byte[] getKey();\r\n        public abstract EncryptorInfo getInfo();\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/EncryptorFactory.cs",
    "content": "using Shadowsocks.Encryption.Stream;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\n\r\nnamespace Shadowsocks.Encryption\r\n{\r\n    public static class EncryptorFactory\r\n    {\r\n        public static readonly Dictionary<string, Type> RegisteredEncryptors = new();\r\n\r\n        private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) };\r\n\r\n        static EncryptorFactory()\r\n        {\r\n            foreach (var method in NoneEncryptor.SupportedCiphers().Where(method => !RegisteredEncryptors.ContainsKey(method)))\r\n            {\r\n                RegisteredEncryptors.Add(method, typeof(NoneEncryptor));\r\n            }\r\n\r\n            foreach (var method in StreamOpenSSLEncryptor.SupportedCiphers().Where(method => !RegisteredEncryptors.ContainsKey(method)))\r\n            {\r\n                RegisteredEncryptors.Add(method, typeof(StreamOpenSSLEncryptor));\r\n            }\r\n\r\n            foreach (var method in StreamSodiumEncryptor.SupportedCiphers().Where(method => !RegisteredEncryptors.ContainsKey(method)))\r\n            {\r\n                RegisteredEncryptors.Add(method, typeof(StreamSodiumEncryptor));\r\n            }\r\n\r\n            var allEncryptor = new StringBuilder(Environment.NewLine);\r\n            allEncryptor.AppendLine(@\"============================\");\r\n            allEncryptor.AppendLine(@\"Registered Encryptor Info\");\r\n            foreach (var encryptor in RegisteredEncryptors)\r\n            {\r\n                allEncryptor.AppendLine($@\"{encryptor.Key}=>{encryptor.Value.Name}\");\r\n            }\r\n            allEncryptor.AppendLine(@\"============================\");\r\n            Console.WriteLine(allEncryptor);\r\n        }\r\n\r\n        public static IEncryptor GetEncryptor(string method, string password)\r\n        {\r\n            if (string.IsNullOrEmpty(method))\r\n            {\r\n                method = @\"aes-256-cfb\";\r\n            }\r\n            method = method.ToLowerInvariant();\r\n            var t = RegisteredEncryptors[method];\r\n            var c = t.GetConstructor(ConstructorTypes);\r\n            if (c == null)\r\n            {\r\n                throw new System.Exception(\"Invalid ctor\");\r\n            }\r\n            var result = (IEncryptor)c.Invoke(new object[] { method, password });\r\n            return result;\r\n        }\r\n\r\n        public static EncryptorInfo GetEncryptorInfo(string method)\r\n        {\r\n            if (string.IsNullOrEmpty(method))\r\n            {\r\n                method = @\"aes-256-cfb\";\r\n            }\r\n            method = method.ToLowerInvariant();\r\n            var t = RegisteredEncryptors[method];\r\n            var c = t.GetConstructor(ConstructorTypes);\r\n            if (c == null)\r\n            {\r\n                throw new System.Exception(\"Invalid ctor\");\r\n            }\r\n            var result = (IEncryptor)c.Invoke(new object[] { method, \"0\" });\r\n            var info = result.getInfo();\r\n            result.Dispose();\r\n            return info;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/EncryptorInfo.cs",
    "content": "namespace Shadowsocks.Encryption\n{\n    public class EncryptorInfo\n    {\n        public int KeySize;\n        public int IvSize;\n        public bool Display;\n        public int Type;\n        public string InnerLibName;\n\n        public EncryptorInfo(int key, int iv, int type, string innerLibName = @\"\", bool display = true)\n        {\n            KeySize = key;\n            IvSize = iv;\n            Display = display;\n            Type = type;\n            InnerLibName = innerLibName;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/Exception/CryptoException.cs",
    "content": "namespace Shadowsocks.Encryption.Exception\n{\n    public class CryptoErrorException : System.Exception\n    {\n        public CryptoErrorException()\n        {\n        }\n\n        public CryptoErrorException(string msg) : base(msg)\n        {\n        }\n\n        public CryptoErrorException(string message, System.Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/IEncryptor.cs",
    "content": "using System;\r\n\r\nnamespace Shadowsocks.Encryption\r\n{\r\n    public interface IEncryptor : IDisposable\r\n    {\r\n        void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength);\r\n        void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength);\r\n        void ResetEncrypt();\r\n        void ResetDecrypt();\r\n        byte[] getIV();\r\n        byte[] getKey();\r\n        EncryptorInfo getInfo();\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/OpenSSL.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Properties;\nusing Shadowsocks.Util;\nusing System;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Security;\nusing System.Text;\n\nnamespace Shadowsocks.Encryption\n{\n    public static class OpenSSL\n    {\n        private const string DLLNAME = @\"libsscrypto.dll\";\n\n        public const int OPENSSL_ENCRYPT = 1;\n        public const int OPENSSL_DECRYPT = 0;\n\n        static OpenSSL()\n        {\n            var dllPath = Utils.GetTempPath(DLLNAME);\n            try\n            {\n                FileManager.DecompressFile(dllPath, Environment.Is64BitProcess ? Resources.libsscrypto64_dll : Resources.libsscrypto_dll);\n                LoadLibrary(dllPath);\n            }\n            catch (IOException)\n            {\n            }\n            catch (System.Exception e)\n            {\n                Logging.LogUsefulException(e);\n            }\n        }\n\n        public static IntPtr GetCipherInfo(string cipherName)\n        {\n            var name = Encoding.ASCII.GetBytes(cipherName);\n            Array.Resize(ref name, name.Length + 1);\n            return EVP_get_cipherbyname(name);\n        }\n\n        [DllImport(@\"Kernel32.dll\")]\n        private static extern IntPtr LoadLibrary(string path);\n\n        [SuppressUnmanagedCodeSecurity]\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr EVP_get_cipherbyname(byte[] name);\n\n        [SuppressUnmanagedCodeSecurity]\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr EVP_CIPHER_CTX_new();\n\n        [SuppressUnmanagedCodeSecurity]\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void EVP_CIPHER_CTX_free(IntPtr ctx);\n\n        [SuppressUnmanagedCodeSecurity]\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\n        public static extern int EVP_CipherInit_ex(IntPtr ctx, IntPtr type, IntPtr impl, byte[] key, byte[] iv, int enc);\n\n        [SuppressUnmanagedCodeSecurity]\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\n        public static extern int EVP_CipherUpdate(IntPtr ctx, byte[] outb, out int outl, byte[] inb, int inl);\n\n        [SuppressUnmanagedCodeSecurity]\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\n        public static extern int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding);\n\n        [SuppressUnmanagedCodeSecurity]\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\n        public static extern int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen);\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/Sodium.cs",
    "content": "using Shadowsocks.Controller;\r\nusing Shadowsocks.Properties;\r\nusing Shadowsocks.Util;\r\nusing System;\r\nusing System.IO;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace Shadowsocks.Encryption\r\n{\r\n    public static class Sodium\r\n    {\r\n        private const string DLLNAME = @\"libsscrypto.dll\";\r\n\r\n        private static readonly bool _initialized;\r\n        private static readonly object _initLock = new();\r\n\r\n        static Sodium()\r\n        {\r\n            var dllPath = Utils.GetTempPath(DLLNAME);\r\n            try\r\n            {\r\n                FileManager.DecompressFile(dllPath, Environment.Is64BitProcess ? Resources.libsscrypto64_dll : Resources.libsscrypto_dll);\r\n                LoadLibrary(dllPath);\r\n            }\r\n            catch (IOException)\r\n            {\r\n            }\r\n            catch (System.Exception e)\r\n            {\r\n                Logging.LogUsefulException(e);\r\n            }\r\n\r\n            lock (_initLock)\r\n            {\r\n                if (!_initialized)\r\n                {\r\n                    if (sodium_init() == -1)\r\n                    {\r\n                        throw new System.Exception(@\"Failed to initialize sodium\");\r\n                    }\r\n\r\n                    _initialized = true;\r\n                }\r\n            }\r\n        }\r\n\r\n        [DllImport(@\"Kernel32.dll\")]\r\n        private static extern IntPtr LoadLibrary(string path);\r\n\r\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\r\n        private static extern int sodium_init();\r\n\r\n        #region Stream\r\n\r\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\r\n        public static extern int crypto_stream_salsa20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k);\r\n\r\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\r\n        public static extern int crypto_stream_xsalsa20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k);\r\n\r\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\r\n        public static extern int crypto_stream_chacha20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k);\r\n\r\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\r\n        public static extern int crypto_stream_xchacha20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k);\r\n\r\n        [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]\r\n        public static extern int crypto_stream_chacha20_ietf_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, uint ic, byte[] k);\r\n\r\n        #endregion\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/Stream/NoneEncryptor.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Encryption.Stream\n{\n    public sealed class NoneEncryptor : StreamEncryptor\n    {\n        public NoneEncryptor(string method, string password) : base(method, password)\n        { }\n\n        private static Dictionary<string, EncryptorInfo> _ciphers = new()\n        {\n            { @\"none\", new EncryptorInfo(16, 0, 1) }\n        };\n\n        public static List<string> SupportedCiphers()\n        {\n            return new(_ciphers.Keys);\n        }\n\n        protected override Dictionary<string, EncryptorInfo> getCiphers()\n        {\n            return _ciphers;\n        }\n\n        protected override void CipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(ToString());\n            }\n\n            Array.Copy(buf, outbuf, length);\n        }\n\n        #region IDisposable\n\n        private bool _disposed;\n\n        public override void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        ~NoneEncryptor()\n        {\n            Dispose(false);\n        }\n\n        private void Dispose(bool disposing)\n        {\n            lock (this)\n            {\n                if (_disposed)\n                {\n                    return;\n                }\n\n                _disposed = true;\n\n                if (disposing)\n                {\n                    // free managed objects\n                }\n\n                // free unmanaged objects\n            }\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs",
    "content": "using Shadowsocks.Crypto;\nusing Shadowsocks.Encryption.CircularBuffer;\nusing Shadowsocks.Proxy;\nusing Shadowsocks.Util;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Encryption.Stream\n{\n    public abstract class StreamEncryptor : EncryptorBase\n    {\n        // every connection should create its own buffer\n        private readonly ByteCircularBuffer _encCircularBuffer = new(ProxyAuthHandler.BufferSize * 2);\n        private readonly ByteCircularBuffer _decCircularBuffer = new(ProxyAuthHandler.BufferSize * 2);\n\n        protected Dictionary<string, EncryptorInfo> ciphers;\n\n        protected byte[] _encryptIV;\n        protected byte[] _decryptIV;\n\n        // Is first packet\n        protected bool _decryptIVReceived;\n        protected bool _encryptIVSent;\n\n        protected string _method;\n        protected int _cipher;\n        // internal name in the crypto library\n        protected string _innerLibName;\n        protected EncryptorInfo CipherInfo;\n        // long-time master key\n        protected byte[] _key;\n        protected int keyLen;\n        protected byte[] _iv;\n        protected int ivLen;\n\n        protected StreamEncryptor(string method, string password) : base(method, password)\n        {\n            InitEncryptorInfo(method);\n            InitKey(password);\n        }\n\n        protected abstract Dictionary<string, EncryptorInfo> getCiphers();\n\n        public bool SetIV(byte[] iv)\n        {\n            if (iv != null && iv.Length == ivLen)\n            {\n                iv.CopyTo(_iv, 0);\n                _encryptIVSent = true;\n                InitCipher(iv, true);\n                return true;\n            }\n            return false;\n        }\n        public override byte[] getIV()\n        {\n            return _iv;\n        }\n        public override byte[] getKey()\n        {\n            var key = (byte[])_key.Clone();\n            Array.Resize(ref key, keyLen);\n            return key;\n        }\n        public override EncryptorInfo getInfo()\n        {\n            return CipherInfo;\n        }\n\n        private void InitEncryptorInfo(string method)\n        {\n            method = method.ToLower();\n            _method = method;\n            ciphers = getCiphers();\n            CipherInfo = ciphers[_method];\n            _innerLibName = string.IsNullOrWhiteSpace(CipherInfo.InnerLibName) ? method : CipherInfo.InnerLibName;\n            _cipher = CipherInfo.Type;\n            if (_cipher == 0)\n            {\n                throw new System.Exception(\"method not found\");\n            }\n\n            keyLen = CipherInfo.KeySize;\n            ivLen = CipherInfo.IvSize;\n        }\n\n        private void InitKey(string password)\n        {\n            _key = new byte[keyLen];\n\n            _key.AsSpan(0, keyLen).SsDeriveKey(password);\n\n            Array.Resize(ref _iv, ivLen);\n            Rng.RandBytes(_iv, ivLen);\n        }\n\n        protected virtual void InitCipher(byte[] iv, bool isCipher)\n        {\n            if (isCipher)\n            {\n                _encryptIV = new byte[ivLen];\n                Array.Copy(iv, _encryptIV, ivLen);\n            }\n            else\n            {\n                _decryptIV = new byte[ivLen];\n                Array.Copy(iv, _decryptIV, ivLen);\n            }\n        }\n\n        protected abstract void CipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf);\n\n        public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)\n        {\n            //none rc4\n            if (length == 0)\n            {\n                outlength = 0;\n                return;\n            }\n\n            var cipherOffset = 0;\n            _encCircularBuffer.Put(buf, 0, length);\n            if (!_encryptIVSent)\n            {\n                InitCipher(_iv, true);\n                Array.Copy(_iv, 0, outbuf, 0, ivLen);\n                cipherOffset = ivLen;\n                _encryptIVSent = true;\n            }\n            var size = _encCircularBuffer.Size;\n            var plain = _encCircularBuffer.Get(size);\n            var cipher = new byte[size];\n            CipherUpdate(true, size, plain, cipher);\n            Buffer.BlockCopy(cipher, 0, outbuf, cipherOffset, size);\n            outlength = size + cipherOffset;\n        }\n\n        public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength)\n        {\n            _decCircularBuffer.Put(buf, 0, length);\n            if (!_decryptIVReceived)\n            {\n                if (_decCircularBuffer.Size <= ivLen)\n                {\n                    // we need more data\n                    outlength = 0;\n                    return;\n                }\n                // start decryption\n                _decryptIVReceived = true;\n                var iv = ivLen == 0 ? new byte[0] : _decCircularBuffer.Get(ivLen); //none rc4\n                InitCipher(iv, false);\n            }\n            var cipher = _decCircularBuffer.ToArray();\n            CipherUpdate(false, cipher.Length, cipher, outbuf);\n            // move pointer only\n            _decCircularBuffer.Skip(_decCircularBuffer.Size);\n            outlength = cipher.Length;\n            // done the decryption\n        }\n\n        public override void ResetEncrypt()\n        {\n            _encryptIVSent = false;\n            Rng.RandBytes(_iv, ivLen);\n        }\n\n        public override void ResetDecrypt()\n        {\n            _decryptIVReceived = false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/Stream/StreamOpenSSLEncryptor.cs",
    "content": "using Shadowsocks.Encryption.Exception;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\n\nnamespace Shadowsocks.Encryption.Stream\n{\n    public sealed class StreamOpenSSLEncryptor : StreamEncryptor\n    {\n        const int CIPHER_AES = 1;\n        const int CIPHER_RC4 = 2;\n        const int CIPHER_CAMELLIA = 3;\n        const int CIPHER_OTHER_CFB = 4;\n\n        private IntPtr _encryptCtx = IntPtr.Zero;\n        private IntPtr _decryptCtx = IntPtr.Zero;\n\n        public StreamOpenSSLEncryptor(string method, string password) : base(method, password)\n        {\n\n        }\n\n        private static readonly Dictionary<string, EncryptorInfo> _ciphers = new()\n        {\n            { @\"aes-128-ctr\", new EncryptorInfo(16, 16, CIPHER_AES) },\n            { @\"aes-192-ctr\", new EncryptorInfo(24, 16, CIPHER_AES) },\n            { @\"aes-256-ctr\", new EncryptorInfo(32, 16, CIPHER_AES) },\n            { @\"aes-128-cfb\", new EncryptorInfo(16, 16, CIPHER_AES) },\n            { @\"aes-192-cfb\", new EncryptorInfo(24, 16, CIPHER_AES) },\n            { @\"aes-256-cfb\", new EncryptorInfo(32, 16, CIPHER_AES) },\n\n            { @\"aes-128-cfb8\", new EncryptorInfo(16, 16, CIPHER_AES) },\n            { @\"aes-192-cfb8\", new EncryptorInfo(24, 16, CIPHER_AES) },\n            { @\"aes-256-cfb8\", new EncryptorInfo(32, 16, CIPHER_AES) },\n            { @\"aes-128-cfb1\", new EncryptorInfo(16, 16, CIPHER_AES, @\"\", false) },\n            { @\"aes-192-cfb1\", new EncryptorInfo(24, 16, CIPHER_AES, @\"\", false) },\n            { @\"aes-256-cfb1\", new EncryptorInfo(32, 16, CIPHER_AES, @\"\", false) },\n            { @\"camellia-128-cfb\", new EncryptorInfo(16, 16, CIPHER_CAMELLIA, @\"\", false) },\n            { @\"camellia-192-cfb\", new EncryptorInfo(24, 16, CIPHER_CAMELLIA, @\"\", false) },\n            { @\"camellia-256-cfb\", new EncryptorInfo(32, 16, CIPHER_CAMELLIA, @\"\", false) },\n            { @\"bf-cfb\", new EncryptorInfo(16, 8, CIPHER_OTHER_CFB, @\"\", false) },\n            { @\"cast5-cfb\", new EncryptorInfo(16, 8, CIPHER_OTHER_CFB, @\"\", false) },\n            { @\"idea-cfb\", new EncryptorInfo(16, 8, CIPHER_OTHER_CFB, @\"\", false) },\n            { @\"rc2-cfb\", new EncryptorInfo(16, 8, CIPHER_OTHER_CFB, @\"\", false) },\n            { @\"rc4\", new EncryptorInfo(16, 0, CIPHER_RC4) }, // weak\n            { @\"rc4-md5\", new EncryptorInfo(16, 16, CIPHER_RC4, @\"RC4\") }, // weak\n            { @\"rc4-md5-6\", new EncryptorInfo(16, 6, CIPHER_RC4, @\"RC4\") }, // weak\n            { @\"seed-cfb\", new EncryptorInfo(16, 16, CIPHER_OTHER_CFB, @\"\", false) }\n        };\n\n        public static List<string> SupportedCiphers()\n        {\n            return new(_ciphers.Keys);\n        }\n\n        protected override Dictionary<string, EncryptorInfo> getCiphers()\n        {\n            return _ciphers;\n        }\n\n        protected override void InitCipher(byte[] iv, bool isEncrypt)\n        {\n            base.InitCipher(iv, isEncrypt);\n\n            var cipherInfo = OpenSSL.GetCipherInfo(_innerLibName);\n            if (cipherInfo == IntPtr.Zero)\n            {\n                throw new System.Exception(\"openssl: cipher not found\");\n            }\n\n            var ctx = OpenSSL.EVP_CIPHER_CTX_new();\n            if (ctx == IntPtr.Zero)\n            {\n                throw new System.Exception(\"fail to create ctx\");\n            }\n\n            if (isEncrypt)\n            {\n                _encryptCtx = ctx;\n            }\n            else\n            {\n                _decryptCtx = ctx;\n            }\n\n            byte[] realKey;\n            if (_method.StartsWith(@\"rc4-\"))\n            {\n                var temp = new byte[keyLen + ivLen];\n                Array.Copy(_key, 0, temp, 0, keyLen);\n                Array.Copy(iv, 0, temp, keyLen, ivLen);\n                realKey = CryptoUtils.MD5(temp);\n            }\n            else\n            {\n                realKey = _key;\n            }\n\n            var ret = OpenSSL.EVP_CipherInit_ex(ctx, cipherInfo, IntPtr.Zero, null, null, isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);\n            if (ret != 1)\n            {\n                throw new System.Exception(\"openssl: fail to set key length\");\n            }\n\n            ret = OpenSSL.EVP_CIPHER_CTX_set_key_length(ctx, keyLen);\n            if (ret != 1)\n            {\n                throw new System.Exception(\"openssl: fail to set key length\");\n            }\n\n            ret = OpenSSL.EVP_CipherInit_ex(ctx, IntPtr.Zero, IntPtr.Zero, realKey, _method.StartsWith(@\"rc4-\") ? null : iv, isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);\n            if (ret != 1)\n            {\n                throw new System.Exception(\"openssl: cannot set key and iv\");\n            }\n\n            OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0);\n        }\n\n        protected override void CipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(ToString());\n            }\n\n            var ret = OpenSSL.EVP_CipherUpdate(isCipher ? _encryptCtx : _decryptCtx, outbuf, out var outlen, buf, length);\n            if (ret != 1)\n            {\n                throw new CryptoErrorException($@\"ret is {ret}\");\n            }\n\n            Debug.Assert(outlen == length);\n        }\n\n        #region IDisposable\n        private bool _disposed;\n\n        // instance based lock\n        private readonly object _lock = new();\n\n        public override void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        ~StreamOpenSSLEncryptor()\n        {\n            Dispose(false);\n        }\n\n        private void Dispose(bool disposing)\n        {\n            lock (_lock)\n            {\n                if (_disposed)\n                {\n                    return;\n                }\n                _disposed = true;\n            }\n\n            if (disposing)\n            {\n                // free managed objects\n            }\n\n            // free unmanaged objects\n            if (_encryptCtx != IntPtr.Zero)\n            {\n                OpenSSL.EVP_CIPHER_CTX_free(_encryptCtx);\n                _encryptCtx = IntPtr.Zero;\n            }\n\n            if (_decryptCtx != IntPtr.Zero)\n            {\n                OpenSSL.EVP_CIPHER_CTX_free(_decryptCtx);\n                _decryptCtx = IntPtr.Zero;\n            }\n        }\n        #endregion\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Encryption/Stream/StreamSodiumEncryptor.cs",
    "content": "using Shadowsocks.Encryption.Exception;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Encryption.Stream\n{\n    public class StreamSodiumEncryptor : StreamEncryptor\n    {\n        private const int CIPHER_SALSA20 = 1;\n        private const int CIPHER_CHACHA20 = 2;\n        private const int CIPHER_CHACHA20_IETF = 3;\n        private const int CIPHER_XSALSA20 = 4 + 1;\n        private const int CIPHER_XCHACHA20 = 4 + 2;\n\n        private const int SODIUM_BLOCK_SIZE = 64;\n\n        protected int _encryptBytesRemaining;\n        protected int _decryptBytesRemaining;\n        protected ulong _encryptIC;\n        protected ulong _decryptIC;\n        protected byte[] _encryptBuf;\n        protected byte[] _decryptBuf;\n\n        private delegate int CryptoStream(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k);\n        private readonly CryptoStream _encryptorDelegate;\n\n        public StreamSodiumEncryptor(string method, string password) : base(method, password)\n        {\n            _encryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE];\n            _decryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE];\n            _encryptorDelegate = _cipher switch\n            {\n                CIPHER_SALSA20 => Sodium.crypto_stream_salsa20_xor_ic,\n                CIPHER_CHACHA20 => Sodium.crypto_stream_chacha20_xor_ic,\n                CIPHER_XSALSA20 => Sodium.crypto_stream_xsalsa20_xor_ic,\n                CIPHER_XCHACHA20 => Sodium.crypto_stream_xchacha20_xor_ic,\n                CIPHER_CHACHA20_IETF => crypto_stream_chacha20_ietf_xor_ic,\n                _ => _encryptorDelegate\n            };\n        }\n\n        private static Dictionary<string, EncryptorInfo> _ciphers = new()\n        {\n            { @\"salsa20\", new EncryptorInfo(32, 8, CIPHER_SALSA20) },\n            { @\"chacha20\", new EncryptorInfo(32, 8, CIPHER_CHACHA20) },\n            { @\"xsalsa20\", new EncryptorInfo(32, 24, CIPHER_XSALSA20) },\n            { @\"xchacha20\", new EncryptorInfo(32, 24, CIPHER_XCHACHA20) },\n            { @\"chacha20-ietf\", new EncryptorInfo(32, 12, CIPHER_CHACHA20_IETF) }\n        };\n\n        protected override Dictionary<string, EncryptorInfo> getCiphers()\n        {\n            return _ciphers;\n        }\n\n        public static List<string> SupportedCiphers()\n        {\n            return new(_ciphers.Keys);\n        }\n\n        protected override void CipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf)\n        {\n            int bytesRemaining;\n            ulong ic;\n            byte[] sodiumBuf;\n            byte[] iv;\n            if (isCipher)\n            {\n                bytesRemaining = _encryptBytesRemaining;\n                ic = _encryptIC;\n                sodiumBuf = _encryptBuf;\n                iv = _encryptIV;\n            }\n            else\n            {\n                bytesRemaining = _decryptBytesRemaining;\n                ic = _decryptIC;\n                sodiumBuf = _decryptBuf;\n                iv = _decryptIV;\n            }\n            var padding = bytesRemaining;\n            Buffer.BlockCopy(buf, 0, sodiumBuf, padding, length);\n            var ret = _encryptorDelegate(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, ic, _key);\n            if (ret != 0)\n            {\n                throw new CryptoErrorException();\n            }\n\n            Buffer.BlockCopy(sodiumBuf, padding, outbuf, 0, length);\n            padding += length;\n            ic += (ulong)padding / SODIUM_BLOCK_SIZE;\n            bytesRemaining = padding % SODIUM_BLOCK_SIZE;\n\n            if (isCipher)\n            {\n                _encryptBytesRemaining = bytesRemaining;\n                _encryptIC = ic;\n            }\n            else\n            {\n                _decryptBytesRemaining = bytesRemaining;\n                _decryptIC = ic;\n            }\n        }\n\n        public override void ResetEncrypt()\n        {\n            _encryptIVSent = false;\n            _encryptIC = 0;\n            _encryptBytesRemaining = 0;\n        }\n\n        public override void ResetDecrypt()\n        {\n            _decryptIVReceived = false;\n            _decryptIC = 0;\n            _decryptBytesRemaining = 0;\n        }\n\n        private int crypto_stream_chacha20_ietf_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k)\n        {\n            return Sodium.crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, n, (uint)ic, k);\n        }\n\n        public override void Dispose()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/BalanceType.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum BalanceType\n    {\n        OneByOne,\n        Random,\n        FastDownloadSpeed,\n        LowLatency,\n        LowException,\n        SelectedFirst,\n        Timer,\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/DnsType.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum DnsType\n    {\n        Default,\n        DnsOverTls\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/HttpRequestProxyType.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum HttpRequestProxyType\n    {\n        Auto,\n        Direct,\n        Proxy,\n        SystemSetting\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/LogLevel.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum LogLevel\n    {\n        Debug = 0,\n        Info,\n        Warn,\n        Error,\n        Assert\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/PacType.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum PacType\n    {\n        GfwList,\n        Online,\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/PortMapType.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum PortMapType\n    {\n        Forward = 0,\n        ForceProxy,\n        RuleProxy\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/ProxyMode.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum ProxyMode\n    {\n        NoModify,\n        Direct,\n        Pac,\n        Global\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/ProxyRuleMode.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum ProxyRuleMode\n    {\n        Disable = 0,\n        BypassLan,\n        BypassLanAndChina,\n        BypassLanAndNotChina,\n        UserCustom = 16\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/ProxyType.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum ProxyType\n    {\n        Socks5,\n        Http,\n        TcpPortTunnel\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Enums/ServerTreeViewType.cs",
    "content": "namespace Shadowsocks.Enums\n{\n    public enum ServerTreeViewType\n    {\n        Subtag,\n        Group,\n        Server\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/I18N/App.en-US.xaml",
    "content": "<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">en-US</sys:String>\n\n    <sys:String x:Key=\"Mode\">Mode</sys:String>\n    <sys:String x:Key=\"DisableProxy\">Disable</sys:String>\n    <sys:String x:Key=\"PacProxy\">PAC</sys:String>\n    <sys:String x:Key=\"GlobalProxy\">Global</sys:String>\n    <sys:String x:Key=\"NoProxy\">No modify</sys:String>\n\n    <sys:String x:Key=\"UpdatePac\">Update PAC</sys:String>\n    <sys:String x:Key=\"UpdateLanPac\">Lan IP list</sys:String>\n    <sys:String x:Key=\"UpdateChnDomainPac\">Chn Domain list</sys:String>\n    <sys:String x:Key=\"UpdateChnDomainIpPac\">Chn Domain and IP list</sys:String>\n    <sys:String x:Key=\"UpdateChnIpPac\">Chn IP list</sys:String>\n    <sys:String x:Key=\"UpdateGfwList\">GFWList</sys:String>\n    <sys:String x:Key=\"UpdateChnOnlyPac\">Chn Only list</sys:String>\n    <sys:String x:Key=\"CopyPacUrl\">Copy PAC URL</sys:String>\n    <sys:String x:Key=\"EditPacFile\">Edit local PAC file...</sys:String>\n    <sys:String x:Key=\"EditGfwListUserRule\">Edit user rule for GFWList...</sys:String>\n\n    <sys:String x:Key=\"ProxySetting\">Proxy setting</sys:String>\n    <sys:String x:Key=\"ProxyRule\">Proxy rule</sys:String>\n    <sys:String x:Key=\"BypassLan\">Bypass LAN</sys:String>\n    <sys:String x:Key=\"BypassLanChina\">Bypass LAN &amp;&amp; China</sys:String>\n    <sys:String x:Key=\"BypassLanNotChina\">Bypass LAN &amp;&amp; not China</sys:String>\n    <sys:String x:Key=\"UserCustom\">User custom</sys:String>\n    <sys:String x:Key=\"DisableBypass\">Disable bypass</sys:String>\n\n    <sys:String x:Key=\"Servers\">Servers</sys:String>\n    <sys:String x:Key=\"EditServers\">Edit servers...</sys:String>\n    <sys:String x:Key=\"ScanQrCode\">Scan QRCode from screen...</sys:String>\n    <sys:String x:Key=\"ImportSsrLinksFromClipboard\">Import links from clipboard...</sys:String>\n    <sys:String x:Key=\"ImportServers\">Import servers from file...</sys:String>\n    <sys:String x:Key=\"LoadBalance\">Load balance</sys:String>\n    <sys:String x:Key=\"SameHostForSameAddress\">Same host for same address</sys:String>\n    <sys:String x:Key=\"ServerStatistic\">Server statistic...</sys:String>\n    <sys:String x:Key=\"DisconnectCurrent\">Disconnect current</sys:String>\n\n    <sys:String x:Key=\"ServersSubscribe\">Subscription</sys:String>\n    <sys:String x:Key=\"SubscribeSetting\">Setting</sys:String>\n    <sys:String x:Key=\"UpdateSubscribeSsrNode\">Update</sys:String>\n\n    <sys:String x:Key=\"ShowLogs\">Show logs...</sys:String>\n    <sys:String x:Key=\"UpdateAvailable\">Update available</sys:String>\n\n    <sys:String x:Key=\"More\">More</sys:String>\n    <sys:String x:Key=\"GlobalSettings\">Global settings...</sys:String>\n    <sys:String x:Key=\"DnsSettings\">DNS settings...</sys:String>\n    <sys:String x:Key=\"PortSettings\">Port settings...</sys:String>\n    <sys:String x:Key=\"OpenWiki\">Open wiki...</sys:String>\n    <sys:String x:Key=\"Feedback\">Feedback...</sys:String>\n    <sys:String x:Key=\"GenQrCode\">Gen custom QRCode...</sys:String>\n    <sys:String x:Key=\"Update\">Update...</sys:String>\n    <sys:String x:Key=\"CheckUpdate\">Check update</sys:String>\n    <sys:String x:Key=\"AutoCheckUpdate\">Auto check update</sys:String>\n    <sys:String x:Key=\"AllowPreRelease\">Include prerelease version</sys:String>\n\n    <sys:String x:Key=\"Quit\">Quit</sys:String>\n\n    <sys:String x:Key=\"NewVersionNotFound\">No newer version was found</sys:String>\n    <sys:String x:Key=\"NewVersionFound\">{0} {1} Update Found</sys:String>\n    <sys:String x:Key=\"ClickMenuToDownload\">Click menu to download</sys:String>\n    <sys:String x:Key=\"NewVersionAvailable\">New version {0} {1} available</sys:String>\n    <sys:String x:Key=\"NewVersionFoundFailed\">Check for update failure</sys:String>\n\n    <sys:String x:Key=\"UnexpectedError\">Unexpected error, ShadowsocksR will exit.</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesMessage1\">Find Shadowsocks icon in your notify tray.</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesMessage2\">If you want to start multiple Shadowsocks, make a copy in another directory.</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesCaption\">ShadowsocksR is already running</sys:String>\n\n    <sys:String x:Key=\"NewServer\">New server</sys:String>\n\n    <sys:String x:Key=\"PortInUse\">Port {0} already in use</sys:String>\n    <sys:String x:Key=\"PortReserved\">Port {0} is reserved by system</sys:String>\n    <sys:String x:Key=\"PortOutOfRange\">Port out of range</sys:String>\n\n    <sys:String x:Key=\"ControllerError\">ShadowsocksR Error: {0}</sys:String>\n\n    <sys:String x:Key=\"Colon\" xml:space=\"preserve\">: </sys:String>\n\n    <sys:String x:Key=\"OneByOne\">OneByOne</sys:String>\n    <sys:String x:Key=\"Random\">Random</sys:String>\n    <sys:String x:Key=\"FastDownloadSpeed\">FastDownloadSpeed</sys:String>\n    <sys:String x:Key=\"LowLatency\">LowLatency</sys:String>\n    <sys:String x:Key=\"LowException\">LowException</sys:String>\n    <sys:String x:Key=\"SelectedFirst\">SelectedFirst</sys:String>\n    <sys:String x:Key=\"Timer\">Timer</sys:String>\n\n    <sys:String x:Key=\"BalanceInGroup\">Balance in group</sys:String>\n    <sys:String x:Key=\"AutoBan\">AutoBan</sys:String>\n\n    <sys:String x:Key=\"RunningPort\">Running: Port {0}</sys:String>\n\n    <sys:String x:Key=\"UpdatePacFailed\">Failed to update PAC file</sys:String>\n    <sys:String x:Key=\"GfwListPacUpdated\">GFWList PAC updated</sys:String>\n    <sys:String x:Key=\"PacUpdated\">PAC updated</sys:String>\n    <sys:String x:Key=\"GfwListPacNotFound\">No updates found. Please report to GFWList if you have problems with it.</sys:String>\n    <sys:String x:Key=\"PacNotFound\">No updates found.</sys:String>\n\n    <sys:String x:Key=\"Success\">Success</sys:String>\n    <sys:String x:Key=\"Error\">Error</sys:String>\n\n    <sys:String x:Key=\"UpdateSubscribeSuccess\">Update subscribe {0} success</sys:String>\n    <sys:String x:Key=\"UpdateSubscribeFailure\">Update subscribe {0} failure</sys:String>\n\n    <sys:String x:Key=\"QrCodeNotFound\">No QRCode found. Try to zoom in or move it to the center of the screen.</sys:String>\n\n    <sys:String x:Key=\"EmptySubtag\">[Empty subscription remarks]</sys:String>\n    <sys:String x:Key=\"EmptyGroup\">[Empty group name]</sys:String>\n\n    <sys:String x:Key=\"ImportConfigFailed\">Import servers failed</sys:String>\n    <sys:String x:Key=\"DefaultConfigMessage\">Default configuration detected</sys:String>\n    <sys:String x:Key=\"DefaultConfigQuestion\">Tap ‘Yes’ to open config window or ‘No’ to open subscription window</sys:String>\n\n    <sys:String x:Key=\"Socks5\">Socks5(support UDP)</sys:String>\n    <sys:String x:Key=\"Http\">Http tunnel</sys:String>\n    <sys:String x:Key=\"TcpPortTunnel\">TCP Port tunnel</sys:String>\n</ResourceDictionary>\n"
  },
  {
    "path": "shadowsocks-csharp/I18N/App.zh-CN.xaml",
    "content": "<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-CN</sys:String>\n\n    <sys:String x:Key=\"Mode\">系统代理</sys:String>\n    <sys:String x:Key=\"DisableProxy\">直连</sys:String>\n    <sys:String x:Key=\"PacProxy\">PAC</sys:String>\n    <sys:String x:Key=\"GlobalProxy\">全局</sys:String>\n    <sys:String x:Key=\"NoProxy\">不修改</sys:String>\n\n    <sys:String x:Key=\"UpdatePac\">更新 PAC</sys:String>\n    <sys:String x:Key=\"UpdateLanPac\">绕过局域网 IP</sys:String>\n    <sys:String x:Key=\"UpdateChnDomainPac\">绕过大陆域名</sys:String>\n    <sys:String x:Key=\"UpdateChnDomainIpPac\">绕过大陆域名和 IP</sys:String>\n    <sys:String x:Key=\"UpdateChnIpPac\">绕过大陆 IP</sys:String>\n    <sys:String x:Key=\"UpdateGfwList\">GFWList</sys:String>\n    <sys:String x:Key=\"UpdateChnOnlyPac\">仅大陆常见域名（回国）</sys:String>\n    <sys:String x:Key=\"CopyPacUrl\">复制 PAC URL</sys:String>\n    <sys:String x:Key=\"EditPacFile\">编辑本地 PAC 文件</sys:String>\n    <sys:String x:Key=\"EditGfwListUserRule\">编辑 GFWList 的用户规则</sys:String>\n\n    <sys:String x:Key=\"ProxySetting\">规则设置</sys:String>\n    <sys:String x:Key=\"ProxyRule\">代理规则</sys:String>\n    <sys:String x:Key=\"BypassLan\">绕过局域网</sys:String>\n    <sys:String x:Key=\"BypassLanChina\">绕过局域网和大陆</sys:String>\n    <sys:String x:Key=\"BypassLanNotChina\">绕过局域网和非大陆</sys:String>\n    <sys:String x:Key=\"UserCustom\">用户自定义</sys:String>\n    <sys:String x:Key=\"DisableBypass\">全局</sys:String>\n\n    <sys:String x:Key=\"Servers\">服务器</sys:String>\n    <sys:String x:Key=\"EditServers\">编辑服务器</sys:String>\n    <sys:String x:Key=\"ScanQrCode\">扫描二维码</sys:String>\n    <sys:String x:Key=\"ImportSsrLinksFromClipboard\">从链接导入</sys:String>\n    <sys:String x:Key=\"ImportServers\">从文件导入</sys:String>\n    <sys:String x:Key=\"LoadBalance\">负载均衡</sys:String>\n    <sys:String x:Key=\"SameHostForSameAddress\">同址优先</sys:String>\n    <sys:String x:Key=\"ServerStatistic\">连接统计</sys:String>\n    <sys:String x:Key=\"DisconnectCurrent\">强制断开连接</sys:String>\n\n    <sys:String x:Key=\"ServersSubscribe\">订阅</sys:String>\n    <sys:String x:Key=\"SubscribeSetting\">设置</sys:String>\n    <sys:String x:Key=\"UpdateSubscribeSsrNode\">更新</sys:String>\n\n    <sys:String x:Key=\"ShowLogs\">日志</sys:String>\n    <sys:String x:Key=\"UpdateAvailable\">更新可用</sys:String>\n\n    <sys:String x:Key=\"More\">更多</sys:String>\n    <sys:String x:Key=\"GlobalSettings\">选项设置</sys:String>\n    <sys:String x:Key=\"DnsSettings\">DNS 设置</sys:String>\n    <sys:String x:Key=\"PortSettings\">端口设置</sys:String>\n    <sys:String x:Key=\"OpenWiki\">帮助文档</sys:String>\n    <sys:String x:Key=\"Feedback\">问题反馈</sys:String>\n    <sys:String x:Key=\"GenQrCode\">二维码生成器</sys:String>\n    <sys:String x:Key=\"Update\">更新</sys:String>\n    <sys:String x:Key=\"CheckUpdate\">检查更新</sys:String>\n    <sys:String x:Key=\"AutoCheckUpdate\">自动检查更新</sys:String>\n    <sys:String x:Key=\"AllowPreRelease\">包括测试版更新</sys:String>\n\n    <sys:String x:Key=\"Quit\">退出</sys:String>\n\n    <sys:String x:Key=\"NewVersionNotFound\">没有找到新版本</sys:String>\n    <sys:String x:Key=\"NewVersionFound\">{0} {1} 更新</sys:String>\n    <sys:String x:Key=\"ClickMenuToDownload\">点击菜单项下载</sys:String>\n    <sys:String x:Key=\"NewVersionAvailable\">【点击下载新版本 {0} {1}】</sys:String>\n    <sys:String x:Key=\"NewVersionFoundFailed\">检查更新失败</sys:String>\n\n    <sys:String x:Key=\"UnexpectedError\">Unexpected error, ShadowsocksR will exit.</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesMessage1\">请在任务栏里寻找 ShadowsocksR 图标</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesMessage2\">如果想启动多份，可以另外复制一份到别的目录</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesCaption\">ShadowsocksR 已经在运行</sys:String>\n\n    <sys:String x:Key=\"NewServer\">未配置的服务器</sys:String>\n\n    <sys:String x:Key=\"PortInUse\">端口 {0} 已被占用</sys:String>\n    <sys:String x:Key=\"PortReserved\">端口 {0} 是系统保留端口</sys:String>\n    <sys:String x:Key=\"PortOutOfRange\">端口超出范围</sys:String>\n\n    <sys:String x:Key=\"ControllerError\">ShadowsocksR Error: {0}</sys:String>\n\n    <sys:String x:Key=\"Colon\" xml:space=\"preserve\">：</sys:String>\n\n    <sys:String x:Key=\"OneByOne\">按次序</sys:String>\n    <sys:String x:Key=\"Random\">随机</sys:String>\n    <sys:String x:Key=\"FastDownloadSpeed\">下载速度优先</sys:String>\n    <sys:String x:Key=\"LowLatency\">低延迟优先</sys:String>\n    <sys:String x:Key=\"LowException\">低错误优先</sys:String>\n    <sys:String x:Key=\"SelectedFirst\">选中优先</sys:String>\n    <sys:String x:Key=\"Timer\">定时切换</sys:String>\n\n    <sys:String x:Key=\"BalanceInGroup\">所选组切换</sys:String>\n    <sys:String x:Key=\"AutoBan\">自动禁用出错服务器</sys:String>\n\n    <sys:String x:Key=\"RunningPort\">正在运行：端口 {0}</sys:String>\n\n    <sys:String x:Key=\"UpdatePacFailed\">更新 PAC 文件失败</sys:String>\n    <sys:String x:Key=\"GfwListPacUpdated\">更新 GFWList PAC 成功</sys:String>\n    <sys:String x:Key=\"PacUpdated\">更新 PAC 成功</sys:String>\n    <sys:String x:Key=\"GfwListPacNotFound\">未发现更新。如有问题请提交给 GFWList</sys:String>\n    <sys:String x:Key=\"PacNotFound\">未发现更新</sys:String>\n\n    <sys:String x:Key=\"Success\">成功</sys:String>\n    <sys:String x:Key=\"Error\">错误</sys:String>\n\n    <sys:String x:Key=\"UpdateSubscribeSuccess\">服务器订阅 {0} 更新成功</sys:String>\n    <sys:String x:Key=\"UpdateSubscribeFailure\">服务器订阅 {0} 更新失败</sys:String>\n\n    <sys:String x:Key=\"QrCodeNotFound\">未发现二维码，尝试把它放大或移动到靠近屏幕中间的位置</sys:String>\n\n    <sys:String x:Key=\"EmptySubtag\">【不属于任何订阅】</sys:String>\n    <sys:String x:Key=\"EmptyGroup\">【空群组名】</sys:String>\n\n    <sys:String x:Key=\"ImportConfigFailed\">导入服务器失败</sys:String>\n    <sys:String x:Key=\"DefaultConfigMessage\">检测到是默认服务器</sys:String>\n    <sys:String x:Key=\"DefaultConfigQuestion\">“是”打开服务器设置，“否”打开订阅设置</sys:String>\n\n    <sys:String x:Key=\"Socks5\">Socks5(支持UDP)</sys:String>\n    <sys:String x:Key=\"Http\">HTTP 隧道</sys:String>\n    <sys:String x:Key=\"TcpPortTunnel\">TCP 端口转发</sys:String>\n</ResourceDictionary>\n"
  },
  {
    "path": "shadowsocks-csharp/I18N/App.zh-TW.xaml",
    "content": "<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-TW</sys:String>\n\n    <sys:String x:Key=\"Mode\">代理模式</sys:String>\n    <sys:String x:Key=\"DisableProxy\">直連</sys:String>\n    <sys:String x:Key=\"PacProxy\">PAC</sys:String>\n    <sys:String x:Key=\"GlobalProxy\">全域</sys:String>\n    <sys:String x:Key=\"NoProxy\">不修改</sys:String>\n\n    <sys:String x:Key=\"UpdatePac\">更新 PAC</sys:String>\n    <sys:String x:Key=\"UpdateLanPac\">繞過區域網路IP</sys:String>\n    <sys:String x:Key=\"UpdateChnDomainPac\">繞過大陸域名</sys:String>\n    <sys:String x:Key=\"UpdateChnDomainIpPac\">繞過大陸域名和IP</sys:String>\n    <sys:String x:Key=\"UpdateChnIpPac\">繞過大陸IP</sys:String>\n    <sys:String x:Key=\"UpdateGfwList\">GFWList</sys:String>\n    <sys:String x:Key=\"UpdateChnOnlyPac\">僅大陸常見域名（國外訪問大陸）</sys:String>\n    <sys:String x:Key=\"CopyPacUrl\">複製 PAC URL</sys:String>\n    <sys:String x:Key=\"EditPacFile\">編輯本地 PAC 檔...</sys:String>\n    <sys:String x:Key=\"EditGfwListUserRule\">編輯 GFWList 的使用者規則...</sys:String>\n\n    <sys:String x:Key=\"ProxySetting\">代理設定</sys:String>\n    <sys:String x:Key=\"ProxyRule\">代理規則</sys:String>\n    <sys:String x:Key=\"BypassLan\">繞過區域網路</sys:String>\n    <sys:String x:Key=\"BypassLanChina\">繞過區域網路和大陸</sys:String>\n    <sys:String x:Key=\"BypassLanNotChina\">繞過區域網路和非大陸</sys:String>\n    <sys:String x:Key=\"UserCustom\">使用者自訂</sys:String>\n    <sys:String x:Key=\"DisableBypass\">全域</sys:String>\n\n    <sys:String x:Key=\"Servers\">伺服器</sys:String>\n    <sys:String x:Key=\"EditServers\">編輯伺服器...</sys:String>\n    <sys:String x:Key=\"ScanQrCode\">QR 碼掃描...</sys:String>\n    <sys:String x:Key=\"ImportSsrLinksFromClipboard\">剪貼板批量匯入連結...</sys:String>\n    <sys:String x:Key=\"ImportServers\">自檔案匯入伺服器...</sys:String>\n    <sys:String x:Key=\"LoadBalance\">伺服器負載均衡</sys:String>\n    <sys:String x:Key=\"SameHostForSameAddress\">優先相同節點連接同一位址</sys:String>\n    <sys:String x:Key=\"ServerStatistic\">伺服器連接統計...</sys:String>\n    <sys:String x:Key=\"DisconnectCurrent\">斷開當前所有連接</sys:String>\n\n    <sys:String x:Key=\"ServersSubscribe\">訂閱</sys:String>\n    <sys:String x:Key=\"SubscribeSetting\">設定</sys:String>\n    <sys:String x:Key=\"UpdateSubscribeSsrNode\">更新</sys:String>\n\n    <sys:String x:Key=\"ShowLogs\">顯示日誌...</sys:String>\n    <sys:String x:Key=\"UpdateAvailable\">可用更新</sys:String>\n\n    <sys:String x:Key=\"More\">更多</sys:String>\n    <sys:String x:Key=\"GlobalSettings\">選項設定...</sys:String>\n    <sys:String x:Key=\"DnsSettings\">DNS 設定...</sys:String>\n    <sys:String x:Key=\"PortSettings\">通訊埠設定...</sys:String>\n    <sys:String x:Key=\"OpenWiki\">打開Wiki文件...</sys:String>\n    <sys:String x:Key=\"Feedback\">問題回饋...</sys:String>\n    <sys:String x:Key=\"GenQrCode\">自訂產生 QR 碼</sys:String>\n    <sys:String x:Key=\"Update\">更新...</sys:String>\n    <sys:String x:Key=\"CheckUpdate\">檢查更新</sys:String>\n    <sys:String x:Key=\"AutoCheckUpdate\">自動檢查更新</sys:String>\n    <sys:String x:Key=\"AllowPreRelease\">包括測試版更新</sys:String>\n\n    <sys:String x:Key=\"Quit\">退出</sys:String>\n\n    <sys:String x:Key=\"NewVersionNotFound\">沒有找到新版本</sys:String>\n    <sys:String x:Key=\"NewVersionFound\">{0} {1} 更新</sys:String>\n    <sys:String x:Key=\"ClickMenuToDownload\">點選選單項下載</sys:String>\n    <sys:String x:Key=\"NewVersionAvailable\">【點選下載新版本 {0} {1}】</sys:String>\n    <sys:String x:Key=\"NewVersionFoundFailed\">檢查更新失敗</sys:String>\n\n    <sys:String x:Key=\"UnexpectedError\">Unexpected error, ShadowsocksR will exit.</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesMessage1\">請在工作列裡尋找 ShadowsocksR 圖示。</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesMessage2\">如果想啟動多份，可以另外複製一份到別的目錄。</sys:String>\n    <sys:String x:Key=\"SuccessiveInstancesCaption\">ShadowsocksR 已經在執行</sys:String>\n\n    <sys:String x:Key=\"NewServer\">未配置的伺服器</sys:String>\n\n    <sys:String x:Key=\"PortInUse\">通訊埠 {0} 已被使用</sys:String>\n    <sys:String x:Key=\"PortReserved\">通訊埠 {0} 由系統保留</sys:String>\n    <sys:String x:Key=\"PortOutOfRange\">通訊埠超出範圍</sys:String>\n\n    <sys:String x:Key=\"ControllerError\">ShadowsocksR Error: {0}</sys:String>\n\n    <sys:String x:Key=\"Colon\" xml:space=\"preserve\">：</sys:String>\n\n    <sys:String x:Key=\"OneByOne\">按次序</sys:String>\n    <sys:String x:Key=\"Random\">隨機</sys:String>\n    <sys:String x:Key=\"FastDownloadSpeed\">下載速度優先</sys:String>\n    <sys:String x:Key=\"LowLatency\">低延遲優先</sys:String>\n    <sys:String x:Key=\"LowException\">低錯誤優先</sys:String>\n    <sys:String x:Key=\"SelectedFirst\">選中優先</sys:String>\n    <sys:String x:Key=\"Timer\">定時切換</sys:String>\n\n    <sys:String x:Key=\"BalanceInGroup\">所選組切換</sys:String>\n    <sys:String x:Key=\"AutoBan\">自動禁用出錯伺服器</sys:String>\n\n    <sys:String x:Key=\"RunningPort\">正在執行：通訊埠 {0}</sys:String>\n\n    <sys:String x:Key=\"UpdatePacFailed\">更新 PAC 檔失敗</sys:String>\n    <sys:String x:Key=\"GfwListPacUpdated\">更新 GFWList PAC 成功</sys:String>\n    <sys:String x:Key=\"PacUpdated\">更新 PAC 成功</sys:String>\n    <sys:String x:Key=\"GfwListPacNotFound\">未發現更新。如有問題請提交給 GFWList</sys:String>\n    <sys:String x:Key=\"PacNotFound\">未發現更新</sys:String>\n\n    <sys:String x:Key=\"Success\">成功</sys:String>\n    <sys:String x:Key=\"Error\">錯誤</sys:String>\n\n    <sys:String x:Key=\"UpdateSubscribeSuccess\">伺服器訂閱 {0} 更新成功</sys:String>\n    <sys:String x:Key=\"UpdateSubscribeFailure\">伺服器訂閱 {0} 更新失敗</sys:String>\n\n    <sys:String x:Key=\"QrCodeNotFound\">未發現 QR 碼，嘗試把它放大或移動到靠近螢幕中間的位置</sys:String>\n\n    <sys:String x:Key=\"EmptySubtag\">【不屬於任何訂閱】</sys:String>\n    <sys:String x:Key=\"EmptyGroup\">【空群組名】</sys:String>\n\n    <sys:String x:Key=\"ImportConfigFailed\">匯入伺服器失敗</sys:String>\n    <sys:String x:Key=\"DefaultConfigMessage\">檢測到是默認伺服器</sys:String>\n    <sys:String x:Key=\"DefaultConfigQuestion\">「是」開啟伺服器設定，「否」開啟訂閱設定</sys:String>\n\n    <sys:String x:Key=\"Socks5\">Socks5(支援UDP)</sys:String>\n    <sys:String x:Key=\"Http\">Http隧道</sys:String>\n    <sys:String x:Key=\"TcpPortTunnel\">TCP通訊埠轉發</sys:String>\n</ResourceDictionary>\n"
  },
  {
    "path": "shadowsocks-csharp/I18N/ConfigWindow.en-US.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">en-US</sys:String>\n\n    <sys:String x:Key=\"Add\">Add</sys:String>\n    <sys:String x:Key=\"Delete\">Delete</sys:String>\n    <sys:String x:Key=\"Expand\">Expand</sys:String>\n    <sys:String x:Key=\"Collapse\">Collapse</sys:String>\n\n    <sys:String x:Key=\"Title\">Edit Servers</sys:String>\n    <sys:String x:Key=\"Any\">Any</sys:String>\n    <sys:String x:Key=\"Local\">Local</sys:String>\n    <sys:String x:Key=\"Version\">Version</sys:String>\n\n    <sys:String x:Key=\"Server\">Server</sys:String>\n    <sys:String x:Key=\"ServerIp\">Server IP</sys:String>\n    <sys:String x:Key=\"ServerPort\">Server Port</sys:String>\n    <sys:String x:Key=\"Password\">Password</sys:String>\n    <sys:String x:Key=\"Encryption\">Encryption</sys:String>\n    <sys:String x:Key=\"Protocol\">Protocol</sys:String>\n    <sys:String x:Key=\"ProtocolParam\">Protocol param</sys:String>\n    <sys:String x:Key=\"Obfs\">Obfs</sys:String>\n    <sys:String x:Key=\"ObfsParam\">Obfs param</sys:String>\n    <sys:String x:Key=\"Remarks\">Remarks</sys:String>\n    <sys:String x:Key=\"Group\">Group</sys:String>\n    <sys:String x:Key=\"SsrLink\">SSR Link</sys:String>\n    <sys:String x:Key=\"AdvSetting\">Adv. Setting</sys:String>\n    <sys:String x:Key=\"AdvSettingDescription\">NOT all server support belows</sys:String>\n    <sys:String x:Key=\"UdpPort\">UDP Port</sys:String>\n    <sys:String x:Key=\"UdpOverTcp\">UDP over TCP</sys:String>\n    <sys:String x:Key=\"UdpOverTcpCheckBox\">UDP over TCP if not checked</sys:String>\n\n    <sys:String x:Key=\"Ok\">OK</sys:String>\n    <sys:String x:Key=\"Cancel\">Cancel</sys:String>\n    <sys:String x:Key=\"Apply\">Apply</sys:String>\n\n    <sys:String x:Key=\"NoServer\">Please add at least one server</sys:String>\n    <sys:String x:Key=\"AddServerError\">Please select a group or server</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/ConfigWindow.zh-CN.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-CN</sys:String>\n\n    <sys:String x:Key=\"Add\">添加</sys:String>\n    <sys:String x:Key=\"Delete\">删除</sys:String>\n    <sys:String x:Key=\"Expand\">展开</sys:String>\n    <sys:String x:Key=\"Collapse\">折叠</sys:String>\n\n    <sys:String x:Key=\"Title\">编辑服务器</sys:String>\n    <sys:String x:Key=\"Any\">任意地址</sys:String>\n    <sys:String x:Key=\"Local\">本机地址</sys:String>\n    <sys:String x:Key=\"Version\">版本</sys:String>\n\n    <sys:String x:Key=\"Server\">服务器</sys:String>\n    <sys:String x:Key=\"ServerIp\">服务器 IP</sys:String>\n    <sys:String x:Key=\"ServerPort\">服务器端口</sys:String>\n    <sys:String x:Key=\"Password\">密码</sys:String>\n    <sys:String x:Key=\"Encryption\">加密</sys:String>\n    <sys:String x:Key=\"Protocol\">协议</sys:String>\n    <sys:String x:Key=\"ProtocolParam\">协议参数</sys:String>\n    <sys:String x:Key=\"Obfs\">混淆</sys:String>\n    <sys:String x:Key=\"ObfsParam\">混淆参数</sys:String>\n    <sys:String x:Key=\"Remarks\">备注</sys:String>\n    <sys:String x:Key=\"Group\">群组名</sys:String>\n    <sys:String x:Key=\"SsrLink\">SSR 链接</sys:String>\n    <sys:String x:Key=\"AdvSetting\">高级选项</sys:String>\n    <sys:String x:Key=\"AdvSettingDescription\">以下选项不是所有服务端都支持</sys:String>\n    <sys:String x:Key=\"UdpPort\">UDP 端口</sys:String>\n    <sys:String x:Key=\"UdpOverTcp\">UDP over TCP</sys:String>\n    <sys:String x:Key=\"UdpOverTcpCheckBox\">不打钩使用原生 UDP</sys:String>\n\n    <sys:String x:Key=\"Ok\">确定</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">应用</sys:String>\n\n    <sys:String x:Key=\"NoServer\">请添加至少一个服务器</sys:String>\n    <sys:String x:Key=\"AddServerError\">请先选择一个群组或服务器</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/ConfigWindow.zh-TW.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-TW</sys:String>\n\n    <sys:String x:Key=\"Add\">新增</sys:String>\n    <sys:String x:Key=\"Delete\">刪除</sys:String>\n    <sys:String x:Key=\"Expand\">展開</sys:String>\n    <sys:String x:Key=\"Collapse\">折疊</sys:String>\n\n    <sys:String x:Key=\"Title\">編輯伺服器</sys:String>\n    <sys:String x:Key=\"Any\">任意位址</sys:String>\n    <sys:String x:Key=\"Local\">本機位址</sys:String>\n    <sys:String x:Key=\"Version\">版本</sys:String>\n\n    <sys:String x:Key=\"Server\">伺服器</sys:String>\n    <sys:String x:Key=\"ServerIp\">伺服器 IP</sys:String>\n    <sys:String x:Key=\"ServerPort\">伺服器通訊埠</sys:String>\n    <sys:String x:Key=\"Password\">密碼</sys:String>\n    <sys:String x:Key=\"Encryption\">加密</sys:String>\n    <sys:String x:Key=\"Protocol\">協議</sys:String>\n    <sys:String x:Key=\"ProtocolParam\">協議參數</sys:String>\n    <sys:String x:Key=\"Obfs\">混淆</sys:String>\n    <sys:String x:Key=\"ObfsParam\">混淆參數</sys:String>\n    <sys:String x:Key=\"Remarks\">備註</sys:String>\n    <sys:String x:Key=\"Group\">群組名</sys:String>\n    <sys:String x:Key=\"SsrLink\">SSR連結</sys:String>\n    <sys:String x:Key=\"AdvSetting\">高級選項</sys:String>\n    <sys:String x:Key=\"AdvSettingDescription\">以下選項不是所有伺服器都支援</sys:String>\n    <sys:String x:Key=\"UdpPort\">UDP通訊埠</sys:String>\n    <sys:String x:Key=\"UdpOverTcp\">UDP over TCP</sys:String>\n    <sys:String x:Key=\"UdpOverTcpCheckBox\">不打勾使用原生 UDP</sys:String>\n\n    <sys:String x:Key=\"Ok\">確定</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">套用</sys:String>\n\n    <sys:String x:Key=\"NoServer\">請添加至少一個伺服器</sys:String>\n    <sys:String x:Key=\"AddServerError\">請選擇一個群組或伺服器</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/DnsSettingWindow.en-US.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">en-US</sys:String>\n\n    <sys:String x:Key=\"Title\">DNS Setting</sys:String>\n\n    <sys:String x:Key=\"Ok\">&#160;&#160;OK&#160;&#160;</sys:String>\n    <sys:String x:Key=\"Cancel\">Cancel</sys:String>\n    <sys:String x:Key=\"Apply\">Apply</sys:String>\n\n    <sys:String x:Key=\"Add\">Add</sys:String>\n    <sys:String x:Key=\"Delete\">Delete</sys:String>\n\n    <sys:String x:Key=\"Enable\">Enable</sys:String>\n    <sys:String x:Key=\"DnsDefault\">Default</sys:String>\n    <sys:String x:Key=\"DnsOverTls\">DNS over TLS</sys:String>\n    <sys:String x:Key=\"Ipv6\">IPv6 first</sys:String>\n    <sys:String x:Key=\"Tcp\">TCP</sys:String>\n    <sys:String x:Key=\"Udp\">UDP</sys:String>\n    <sys:String x:Key=\"Address\">Address</sys:String>\n    <sys:String x:Key=\"Port\">Port</sys:String>\n    <sys:String x:Key=\"Timeout\">Timeout</sys:String>\n    <sys:String x:Key=\"EDns\">EDNS</sys:String>\n    <sys:String x:Key=\"Ip\">IP</sys:String>\n    <sys:String x:Key=\"SourceNetmask\">Source netmask</sys:String>\n    <sys:String x:Key=\"ScopeNetmask\">Scope netmask</sys:String>\n    <sys:String x:Key=\"Test\">Test</sys:String>\n    <sys:String x:Key=\"Domain\">Domain</sys:String>\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/DnsSettingWindow.zh-CN.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-CN</sys:String>\n\n    <sys:String x:Key=\"Title\">DNS 设置</sys:String>\n\n    <sys:String x:Key=\"Ok\">确定</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">应用</sys:String>\n\n    <sys:String x:Key=\"Add\">添加</sys:String>\n    <sys:String x:Key=\"Delete\">删除</sys:String>\n\n    <sys:String x:Key=\"Enable\">启用</sys:String>\n    <sys:String x:Key=\"DnsDefault\">默认</sys:String>\n    <sys:String x:Key=\"DnsOverTls\">DNS over TLS</sys:String>\n    <sys:String x:Key=\"Ipv6\">IPv6 优先</sys:String>\n    <sys:String x:Key=\"Tcp\">TCP</sys:String>\n    <sys:String x:Key=\"Udp\">UDP</sys:String>\n    <sys:String x:Key=\"Address\">服务器</sys:String>\n    <sys:String x:Key=\"Port\">端口</sys:String>\n    <sys:String x:Key=\"Timeout\">超时</sys:String>\n    <sys:String x:Key=\"EDns\">EDNS</sys:String>\n    <sys:String x:Key=\"Ip\">IP</sys:String>\n    <sys:String x:Key=\"SourceNetmask\">Source netmask</sys:String>\n    <sys:String x:Key=\"ScopeNetmask\">Scope netmask</sys:String>\n    <sys:String x:Key=\"Test\">测试</sys:String>\n    <sys:String x:Key=\"Domain\">域名</sys:String>\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/DnsSettingWindow.zh-TW.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-TW</sys:String>\n\n    <sys:String x:Key=\"Title\">DNS 設定</sys:String>\n\n    <sys:String x:Key=\"Ok\">確定</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">套用</sys:String>\n\n    <sys:String x:Key=\"Add\">新增</sys:String>\n    <sys:String x:Key=\"Delete\">刪除</sys:String>\n\n    <sys:String x:Key=\"Enable\">啟用</sys:String>\n    <sys:String x:Key=\"DnsDefault\">預設</sys:String>\n    <sys:String x:Key=\"DnsOverTls\">DNS over TLS</sys:String>\n    <sys:String x:Key=\"Ipv6\">IPv6 優先</sys:String>\n    <sys:String x:Key=\"Tcp\">TCP</sys:String>\n    <sys:String x:Key=\"Udp\">UDP</sys:String>\n    <sys:String x:Key=\"Address\">伺服器</sys:String>\n    <sys:String x:Key=\"Port\">連接埠</sys:String>\n    <sys:String x:Key=\"Timeout\">連接逾時</sys:String>\n    <sys:String x:Key=\"EDns\">EDNS</sys:String>\n    <sys:String x:Key=\"Ip\">IP</sys:String>\n    <sys:String x:Key=\"SourceNetmask\">Source netmask</sys:String>\n    <sys:String x:Key=\"ScopeNetmask\">Scope netmask</sys:String>\n    <sys:String x:Key=\"Test\">測試</sys:String>\n    <sys:String x:Key=\"Domain\">網域</sys:String>\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/LogWindow.en-US.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">en-US</sys:String>\n\n    <sys:String x:Key=\"Title\">Log Viewer</sys:String>\n\n    <sys:String x:Key=\"File\">_File</sys:String>\n    <sys:String x:Key=\"ClearLog\">Clear _log</sys:String>\n    <sys:String x:Key=\"ShowInExplorer\">Show in _Explorer</sys:String>\n    <sys:String x:Key=\"Close\">_Close</sys:String>\n    <sys:String x:Key=\"View\">_View</sys:String>\n    <sys:String x:Key=\"Font\">_Font</sys:String>\n    <sys:String x:Key=\"WrapText\">_Wrap Text</sys:String>\n    <sys:String x:Key=\"AlwaysOnTop\">_Always on top</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/LogWindow.zh-CN.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-CN</sys:String>\n\n    <sys:String x:Key=\"Title\">日志查看器</sys:String>\n\n    <sys:String x:Key=\"File\">文件(_F)</sys:String>\n    <sys:String x:Key=\"ClearLog\">清空日志(_L)</sys:String>\n    <sys:String x:Key=\"ShowInExplorer\">在资源管理器中显示(_E)</sys:String>\n    <sys:String x:Key=\"Close\">关闭(_C)</sys:String>\n    <sys:String x:Key=\"View\">视图(_V)</sys:String>\n    <sys:String x:Key=\"Font\">字体设置(_F)</sys:String>\n    <sys:String x:Key=\"WrapText\">自动换行(_W)</sys:String>\n    <sys:String x:Key=\"AlwaysOnTop\">置于顶层(_A)</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/LogWindow.zh-TW.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-TW</sys:String>\n\n    <sys:String x:Key=\"Title\">Log Viewer</sys:String>\n\n    <sys:String x:Key=\"File\">檔案(_F)</sys:String>\n    <sys:String x:Key=\"ClearLog\">清空日誌(_L)</sys:String>\n    <sys:String x:Key=\"ShowInExplorer\">在檔案總管中顯示(_E)</sys:String>\n    <sys:String x:Key=\"Close\">關閉(_C)</sys:String>\n    <sys:String x:Key=\"View\">視圖(_V)</sys:String>\n    <sys:String x:Key=\"Font\">字型設定(_F)</sys:String>\n    <sys:String x:Key=\"WrapText\">自動換行(_W)</sys:String>\n    <sys:String x:Key=\"AlwaysOnTop\">置於頂層(_A)</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/PortSettingsWindow.en-US.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">en-US</sys:String>\n\n    <sys:String x:Key=\"Title\">Port Settings</sys:String>\n\n    <sys:String x:Key=\"PortForward\">Port Forward</sys:String>\n    <sys:String x:Key=\"ForceProxy\">Force Proxy</sys:String>\n    <sys:String x:Key=\"ProxyWithRule\">Proxy With Rule</sys:String>\n\n    <sys:String x:Key=\"MapSetting\">Map Setting</sys:String>\n    <sys:String x:Key=\"Enable\">Enable</sys:String>\n    <sys:String x:Key=\"Type\">Type</sys:String>\n    <sys:String x:Key=\"ServerId\">Server ID</sys:String>\n    <sys:String x:Key=\"LocalPort\">Local Port</sys:String>\n    <sys:String x:Key=\"TargetAddress\">Target Addr</sys:String>\n    <sys:String x:Key=\"TargetPort\">Target Port</sys:String>\n    <sys:String x:Key=\"Remarks\">Remarks</sys:String>\n\n    <sys:String x:Key=\"Add\">Add</sys:String>\n    <sys:String x:Key=\"Delete\">Delete</sys:String>\n    <sys:String x:Key=\"Ok\">OK</sys:String>\n    <sys:String x:Key=\"Cancel\">Cancel</sys:String>\n    <sys:String x:Key=\"Apply\">Apply</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/PortSettingsWindow.zh-CN.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-CN</sys:String>\n\n    <sys:String x:Key=\"Title\">端口设置</sys:String>\n\n    <sys:String x:Key=\"PortForward\">端口转发</sys:String>\n    <sys:String x:Key=\"ForceProxy\">强制代理</sys:String>\n    <sys:String x:Key=\"ProxyWithRule\">规则代理</sys:String>\n\n    <sys:String x:Key=\"MapSetting\">映射设置</sys:String>\n    <sys:String x:Key=\"Enable\">开关</sys:String>\n    <sys:String x:Key=\"Type\">类型</sys:String>\n    <sys:String x:Key=\"ServerId\">服务器 ID</sys:String>\n    <sys:String x:Key=\"LocalPort\">本地端口</sys:String>\n    <sys:String x:Key=\"TargetAddress\">目标地址</sys:String>\n    <sys:String x:Key=\"TargetPort\">目标端口</sys:String>\n    <sys:String x:Key=\"Remarks\">备注</sys:String>\n\n    <sys:String x:Key=\"Add\">添加</sys:String>\n    <sys:String x:Key=\"Delete\">删除</sys:String>\n    <sys:String x:Key=\"Ok\">确定</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">应用</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/PortSettingsWindow.zh-TW.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-TW</sys:String>\n\n    <sys:String x:Key=\"Title\">通訊埠設定</sys:String>\n\n    <sys:String x:Key=\"PortForward\">通訊埠轉發</sys:String>\n    <sys:String x:Key=\"ForceProxy\">強制代理</sys:String>\n    <sys:String x:Key=\"ProxyWithRule\">規則代理</sys:String>\n\n    <sys:String x:Key=\"MapSetting\">映射設定</sys:String>\n    <sys:String x:Key=\"Enable\">開關</sys:String>\n    <sys:String x:Key=\"Type\">類型</sys:String>\n    <sys:String x:Key=\"ServerId\">伺服器 ID</sys:String>\n    <sys:String x:Key=\"LocalPort\">本地通訊埠</sys:String>\n    <sys:String x:Key=\"TargetAddress\">目標位址</sys:String>\n    <sys:String x:Key=\"TargetPort\">目標通訊埠</sys:String>\n    <sys:String x:Key=\"Remarks\">備註</sys:String>\n\n    <sys:String x:Key=\"Add\">新增</sys:String>\n    <sys:String x:Key=\"Delete\">刪除</sys:String>\n    <sys:String x:Key=\"Ok\">確定</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">套用</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/ServerLogWindow.en-US.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">en-US</sys:String>\n\n    <sys:String x:Key=\"Title\">ServerLog</sys:String>\n    <sys:String x:Key=\"Any\">Any</sys:String>\n    <sys:String x:Key=\"Local\">Local</sys:String>\n    <sys:String x:Key=\"Version\">Version</sys:String>\n\n    <sys:String x:Key=\"Control\">_Control</sys:String>\n    <sys:String x:Key=\"DisconnectDirect\">_Disconnect direct connections</sys:String>\n    <sys:String x:Key=\"DisconnectAll\">Disconnect _All</sys:String>\n    <sys:String x:Key=\"ClearMaxSpeed\">Clear _MaxSpeed</sys:String>\n    <sys:String x:Key=\"Clear\">_Clear</sys:String>\n    <sys:String x:Key=\"ClearSelectedTotal\">Clear _Selected Total</sys:String>\n    <sys:String x:Key=\"ClearTotal\">Clear _Total</sys:String>\n\n    <sys:String x:Key=\"PortOut\">Port _out</sys:String>\n    <sys:String x:Key=\"CopyCurrentLink\">Copy current link</sys:String>\n    <sys:String x:Key=\"CopyCurrentGroupLinks\">Copy current group links</sys:String>\n    <sys:String x:Key=\"CopyAllEnableLinks\">Copy all enable links</sys:String>\n    <sys:String x:Key=\"CopyAllLinks\">Copy all links</sys:String>\n\n    <sys:String x:Key=\"Window\">_Window</sys:String>\n    <sys:String x:Key=\"AutoSize\">Auto _size</sys:String>\n    <sys:String x:Key=\"AlwaysOnTop\">Always On _Top</sys:String>\n\n    <sys:String x:Key=\"Index\">Id</sys:String>\n    <sys:String x:Key=\"Group\">Group</sys:String>\n    <sys:String x:Key=\"Server\">Server</sys:String>\n    <sys:String x:Key=\"Connecting\">Connecting</sys:String>\n    <sys:String x:Key=\"Latency\">Latency</sys:String>\n    <sys:String x:Key=\"AvgDSpeed\">Avg DSpeed</sys:String>\n    <sys:String x:Key=\"MaxDSpeed\">Max DSpeed</sys:String>\n    <sys:String x:Key=\"AvgUpSpeed\">Avg UpSpeed</sys:String>\n    <sys:String x:Key=\"MaxUpSpeed\">Max UpSpeed</sys:String>\n    <sys:String x:Key=\"Dload\">Dload</sys:String>\n    <sys:String x:Key=\"Upload\">Upload</sys:String>\n    <sys:String x:Key=\"DloadRaw\">DloadRaw</sys:String>\n    <sys:String x:Key=\"Error\">Error</sys:String>\n    <sys:String x:Key=\"Timeout\">Timeout</sys:String>\n    <sys:String x:Key=\"EmptyResponse\">Empty Response</sys:String>\n    <sys:String x:Key=\"Continuous\">Continuous</sys:String>\n    <sys:String x:Key=\"ErrorPercent\">Error Percent</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/ServerLogWindow.zh-CN.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-CN</sys:String>\n\n    <sys:String x:Key=\"Title\">服务器记录</sys:String>\n    <sys:String x:Key=\"Any\">任意地址</sys:String>\n    <sys:String x:Key=\"Local\">本机地址</sys:String>\n    <sys:String x:Key=\"Version\">版本</sys:String>\n\n    <sys:String x:Key=\"Control\">操作(_C)</sys:String>\n    <sys:String x:Key=\"DisconnectDirect\">断开直连连接(_D)</sys:String>\n    <sys:String x:Key=\"DisconnectAll\">断开当前所有连接(_A)</sys:String>\n    <sys:String x:Key=\"ClearMaxSpeed\">重置历史最高(_M)</sys:String>\n    <sys:String x:Key=\"Clear\">清空(_C)</sys:String>\n    <sys:String x:Key=\"ClearSelectedTotal\">清空选中节点历史流量(_S)</sys:String>\n    <sys:String x:Key=\"ClearTotal\">清空所有历史流量(_T)</sys:String>\n\n    <sys:String x:Key=\"PortOut\">导出(_O)</sys:String>\n    <sys:String x:Key=\"CopyCurrentLink\">复制选中链接</sys:String>\n    <sys:String x:Key=\"CopyCurrentGroupLinks\">复制选中组链接</sys:String>\n    <sys:String x:Key=\"CopyAllEnableLinks\">复制所有开启节点链接</sys:String>\n    <sys:String x:Key=\"CopyAllLinks\">复制所有节点链接</sys:String>\n\n    <sys:String x:Key=\"Window\">窗口(_W)</sys:String>\n    <sys:String x:Key=\"AutoSize\">自动调整大小(_S)</sys:String>\n    <sys:String x:Key=\"AlwaysOnTop\">窗口置顶(_T)</sys:String>\n\n    <sys:String x:Key=\"Index\">序号</sys:String>\n    <sys:String x:Key=\"Group\">群组名</sys:String>\n    <sys:String x:Key=\"Server\">服务器</sys:String>\n    <sys:String x:Key=\"Connecting\">连接</sys:String>\n    <sys:String x:Key=\"Latency\">延迟</sys:String>\n    <sys:String x:Key=\"AvgDSpeed\">平均下载速度</sys:String>\n    <sys:String x:Key=\"MaxDSpeed\">最高下载速度</sys:String>\n    <sys:String x:Key=\"AvgUpSpeed\">平均上传速度</sys:String>\n    <sys:String x:Key=\"MaxUpSpeed\">最高上传速度</sys:String>\n    <sys:String x:Key=\"Dload\">总下载</sys:String>\n    <sys:String x:Key=\"Upload\">总上传</sys:String>\n    <sys:String x:Key=\"DloadRaw\">实下载</sys:String>\n    <sys:String x:Key=\"Error\">错误</sys:String>\n    <sys:String x:Key=\"Timeout\">超时</sys:String>\n    <sys:String x:Key=\"EmptyResponse\">空连</sys:String>\n    <sys:String x:Key=\"Continuous\">连错</sys:String>\n    <sys:String x:Key=\"ErrorPercent\">出错比例</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/ServerLogWindow.zh-TW.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-TW</sys:String>\n\n    <sys:String x:Key=\"Title\">伺服器記錄</sys:String>\n    <sys:String x:Key=\"Any\">任意位址</sys:String>\n    <sys:String x:Key=\"Local\">本機位址</sys:String>\n    <sys:String x:Key=\"Version\">版本</sys:String>\n\n    <sys:String x:Key=\"Control\">操作(_C)</sys:String>\n    <sys:String x:Key=\"DisconnectDirect\">斷開直連連接(_D)</sys:String>\n    <sys:String x:Key=\"DisconnectAll\">斷開當前所有連接(_A)</sys:String>\n    <sys:String x:Key=\"ClearMaxSpeed\">重置歷史最高(_M)</sys:String>\n    <sys:String x:Key=\"Clear\">清空(_C)</sys:String>\n    <sys:String x:Key=\"ClearSelectedTotal\">清空選中節點歷史流量(_S)</sys:String>\n    <sys:String x:Key=\"ClearTotal\">清空所有歷史流量(_T)</sys:String>\n\n    <sys:String x:Key=\"PortOut\">匯出(_O)</sys:String>\n    <sys:String x:Key=\"CopyCurrentLink\">複製選中連結</sys:String>\n    <sys:String x:Key=\"CopyCurrentGroupLinks\">複製選中組連結</sys:String>\n    <sys:String x:Key=\"CopyAllEnableLinks\">複製所有開啟節點連結</sys:String>\n    <sys:String x:Key=\"CopyAllLinks\">複製所有節點連結</sys:String>\n\n    <sys:String x:Key=\"Window\">視窗(_W)</sys:String>\n    <sys:String x:Key=\"AutoSize\">自動調整大小(_S)</sys:String>\n    <sys:String x:Key=\"AlwaysOnTop\">視窗置頂(_T)</sys:String>\n\n    <sys:String x:Key=\"Index\">Id</sys:String>\n    <sys:String x:Key=\"Group\">群組名</sys:String>\n    <sys:String x:Key=\"Server\">伺服器</sys:String>\n    <sys:String x:Key=\"Connecting\">連接</sys:String>\n    <sys:String x:Key=\"Latency\">延遲</sys:String>\n    <sys:String x:Key=\"AvgDSpeed\">平均下載速度</sys:String>\n    <sys:String x:Key=\"MaxDSpeed\">最高下載速度</sys:String>\n    <sys:String x:Key=\"AvgUpSpeed\">平均上傳速度</sys:String>\n    <sys:String x:Key=\"MaxUpSpeed\">最高上傳速度</sys:String>\n    <sys:String x:Key=\"Dload\">總下載</sys:String>\n    <sys:String x:Key=\"Upload\">總上傳</sys:String>\n    <sys:String x:Key=\"DloadRaw\">實下載</sys:String>\n    <sys:String x:Key=\"Error\">錯誤</sys:String>\n    <sys:String x:Key=\"Timeout\">超時</sys:String>\n    <sys:String x:Key=\"EmptyResponse\">空連</sys:String>\n    <sys:String x:Key=\"Continuous\">連錯</sys:String>\n    <sys:String x:Key=\"ErrorPercent\">出錯比例</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/SettingsWindow.en-US.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">en-US</sys:String>\n\n    <sys:String x:Key=\"Title\">Global Settings</sys:String>\n    <sys:String x:Key=\"Any\">Any</sys:String>\n    <sys:String x:Key=\"Local\">Local</sys:String>\n    <sys:String x:Key=\"Version\">Version</sys:String>\n\n    <sys:String x:Key=\"Ok\">&#160;&#160;OK&#160;&#160;</sys:String>\n    <sys:String x:Key=\"Cancel\">Cancel</sys:String>\n    <sys:String x:Key=\"Apply\">Apply</sys:String>\n\n    <sys:String x:Key=\"FailAutoStartUp\">Failed to update registry</sys:String>\n    <sys:String x:Key=\"RestartRequired\">Restart required</sys:String>\n\n    <sys:String x:Key=\"RemoteProxy\">Remote proxy</sys:String>\n    <sys:String x:Key=\"ProxyOn\">Proxy On</sys:String>\n    <sys:String x:Key=\"Pac\">PAC \"direct\" return this proxy</sys:String>\n\n    <sys:String x:Key=\"ServerIp\">Server IP</sys:String>\n    <sys:String x:Key=\"ServerPort\">Server Port</sys:String>\n    <sys:String x:Key=\"Username\">Username</sys:String>\n    <sys:String x:Key=\"Password\">Password</sys:String>\n    <sys:String x:Key=\"UserAgent\">User Agent</sys:String>\n\n    <sys:String x:Key=\"LocalProxy\">Local proxy</sys:String>\n    <sys:String x:Key=\"AllowLan\">Allow Clients from LAN</sys:String>\n    <sys:String x:Key=\"LocalPort\">Local Port</sys:String>\n\n    <sys:String x:Key=\"Misc\">Misc</sys:String>\n    <sys:String x:Key=\"Balance\">Balance</sys:String>\n    <sys:String x:Key=\"Logging\">Logging</sys:String>\n    <sys:String x:Key=\"Language\">Language</sys:String>\n    <sys:String x:Key=\"StartOnBoot\">Start on Boot</sys:String>\n    <sys:String x:Key=\"SwitchAutoCloseTcpLinks\">Switch auto close TCP links</sys:String>\n    <sys:String x:Key=\"LoadBalance\">Load balance</sys:String>\n    <sys:String x:Key=\"BalanceInGroup\">Balance in group</sys:String>\n    <sys:String x:Key=\"AutoBan\">AutoBan</sys:String>\n    <sys:String x:Key=\"EnableLog\">Enable Log</sys:String>\n\n    <sys:String x:Key=\"SetDefault\">Set Default</sys:String>\n    <sys:String x:Key=\"ReconnectTimes\">Reconnect Times</sys:String>\n    <sys:String x:Key=\"ConnectTimeout\">Connect Timeout</sys:String>\n    <sys:String x:Key=\"Ttl\">TTL</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/SettingsWindow.zh-CN.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-CN</sys:String>\n\n    <sys:String x:Key=\"Title\">选项设置</sys:String>\n    <sys:String x:Key=\"Any\">任意地址</sys:String>\n    <sys:String x:Key=\"Local\">本机地址</sys:String>\n    <sys:String x:Key=\"Version\">版本</sys:String>\n\n    <sys:String x:Key=\"Ok\">确定</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">应用</sys:String>\n\n    <sys:String x:Key=\"FailAutoStartUp\">无法修改注册表</sys:String>\n    <sys:String x:Key=\"RestartRequired\">需要重启</sys:String>\n\n    <sys:String x:Key=\"RemoteProxy\">二级（前置）代理</sys:String>\n    <sys:String x:Key=\"ProxyOn\">开启代理</sys:String>\n    <sys:String x:Key=\"Pac\">PAC “直连” 使用二级代理</sys:String>\n\n    <sys:String x:Key=\"ServerIp\">服务器 IP</sys:String>\n    <sys:String x:Key=\"ServerPort\">服务器端口</sys:String>\n    <sys:String x:Key=\"Username\">用户名</sys:String>\n    <sys:String x:Key=\"Password\">密码</sys:String>\n    <sys:String x:Key=\"UserAgent\">用户代理</sys:String>\n\n    <sys:String x:Key=\"LocalProxy\">本地代理</sys:String>\n    <sys:String x:Key=\"AllowLan\">允许来自局域网的连接</sys:String>\n    <sys:String x:Key=\"LocalPort\">本地端口</sys:String>\n\n    <sys:String x:Key=\"Misc\">杂项</sys:String>\n    <sys:String x:Key=\"Balance\">负载均衡</sys:String>\n    <sys:String x:Key=\"Logging\">日志记录</sys:String>\n    <sys:String x:Key=\"Language\">选择语言</sys:String>\n    <sys:String x:Key=\"StartOnBoot\">开机启动</sys:String>\n    <sys:String x:Key=\"SwitchAutoCloseTcpLinks\">切换服务器前断开所有连接</sys:String>\n    <sys:String x:Key=\"LoadBalance\">服务器负载均衡</sys:String>\n    <sys:String x:Key=\"BalanceInGroup\">所选组切换</sys:String>\n    <sys:String x:Key=\"AutoBan\">自动禁用出错服务器</sys:String>\n    <sys:String x:Key=\"EnableLog\">开启日志</sys:String>\n\n    <sys:String x:Key=\"SetDefault\">重置默认值</sys:String>\n    <sys:String x:Key=\"ReconnectTimes\">重连次数</sys:String>\n    <sys:String x:Key=\"ConnectTimeout\">连接超时</sys:String>\n    <sys:String x:Key=\"Ttl\">空闲断开秒数</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/SettingsWindow.zh-TW.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-TW</sys:String>\n\n    <sys:String x:Key=\"Title\">選項設定</sys:String>\n    <sys:String x:Key=\"Any\">任意位址</sys:String>\n    <sys:String x:Key=\"Local\">本機位址</sys:String>\n    <sys:String x:Key=\"Version\">版本</sys:String>\n\n    <sys:String x:Key=\"Ok\">確定</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">套用</sys:String>\n\n    <sys:String x:Key=\"FailAutoStartUp\">無法修改登錄檔</sys:String>\n    <sys:String x:Key=\"RestartRequired\">請重新啟動應用程式</sys:String>\n\n    <sys:String x:Key=\"RemoteProxy\">二級（前置）代理</sys:String>\n    <sys:String x:Key=\"ProxyOn\">開啟代理</sys:String>\n    <sys:String x:Key=\"Pac\">PAC「直接連接」使用二級代理</sys:String>\n\n    <sys:String x:Key=\"ServerIp\">伺服器 IP</sys:String>\n    <sys:String x:Key=\"ServerPort\">伺服器通訊埠</sys:String>\n    <sys:String x:Key=\"Username\">使用者名稱</sys:String>\n    <sys:String x:Key=\"Password\">密碼</sys:String>\n    <sys:String x:Key=\"UserAgent\">使用者代理</sys:String>\n\n    <sys:String x:Key=\"LocalProxy\">本地代理</sys:String>\n    <sys:String x:Key=\"AllowLan\">允許來自區域網路的連接</sys:String>\n    <sys:String x:Key=\"LocalPort\">本地通訊埠</sys:String>\n\n    <sys:String x:Key=\"Misc\">雜項</sys:String>\n    <sys:String x:Key=\"Balance\">負載均衡</sys:String>\n    <sys:String x:Key=\"Logging\">日誌記錄</sys:String>\n    <sys:String x:Key=\"Language\">語言</sys:String>\n    <sys:String x:Key=\"StartOnBoot\">開機啟動</sys:String>\n    <sys:String x:Key=\"SwitchAutoCloseTcpLinks\">切換伺服器前斷開所有連結</sys:String>\n    <sys:String x:Key=\"LoadBalance\">伺服器負載均衡</sys:String>\n    <sys:String x:Key=\"BalanceInGroup\">所選組切換</sys:String>\n    <sys:String x:Key=\"AutoBan\">自動禁用出錯伺服器</sys:String>\n    <sys:String x:Key=\"EnableLog\">開啟日誌</sys:String>\n\n    <sys:String x:Key=\"SetDefault\">重置預設值</sys:String>\n    <sys:String x:Key=\"ReconnectTimes\">重連次數</sys:String>\n    <sys:String x:Key=\"ConnectTimeout\">連接逾時</sys:String>\n    <sys:String x:Key=\"Ttl\">空閒斷開秒數</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/SubscribeWindow.en-US.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">en-US</sys:String>\n\n    <sys:String x:Key=\"Title\">Subscribe Settings</sys:String>\n\n    <sys:String x:Key=\"Ok\">Confirm &amp; update</sys:String>\n    <sys:String x:Key=\"Cancel\">Cancel</sys:String>\n    <sys:String x:Key=\"Apply\">Apply</sys:String>\n\n    <sys:String x:Key=\"Add\">Add</sys:String>\n    <sys:String x:Key=\"Delete\">Delete</sys:String>\n\n    <sys:String x:Key=\"Url\">URL</sys:String>\n    <sys:String x:Key=\"GroupName\">Subscription remark</sys:String>\n    <sys:String x:Key=\"LastUpdate\">Last Update</sys:String>\n    <sys:String x:Key=\"AutoUpdate\">Auto update</sys:String>\n    <sys:String x:Key=\"Update\">Update current subscription</sys:String>\n    <sys:String x:Key=\"SaveError\">Subscription remarks cannot have the same</sys:String>\n\n    <sys:String x:Key=\"ProxyType\">Proxy type</sys:String>\n    <sys:String x:Key=\"Auto\">Auto</sys:String>\n    <sys:String x:Key=\"Direct\">Direct</sys:String>\n    <sys:String x:Key=\"Proxy\">Proxy</sys:String>\n    <sys:String x:Key=\"SystemSetting\">System Setting</sys:String>\n\n    <sys:String x:Key=\"SaveQuestion\" xml:space=\"preserve\">Some subscription servers that are not on the subscription list were found.&#13;Do you want to delete these servers？</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/SubscribeWindow.zh-CN.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-CN</sys:String>\n\n    <sys:String x:Key=\"Title\">订阅设置</sys:String>\n\n    <sys:String x:Key=\"Ok\">确定并更新</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">应用</sys:String>\n\n    <sys:String x:Key=\"Add\">添加</sys:String>\n    <sys:String x:Key=\"Delete\">删除</sys:String>\n\n    <sys:String x:Key=\"Url\">订阅地址</sys:String>\n    <sys:String x:Key=\"GroupName\">订阅备注</sys:String>\n    <sys:String x:Key=\"LastUpdate\">最近更新</sys:String>\n    <sys:String x:Key=\"AutoUpdate\">自动更新</sys:String>\n    <sys:String x:Key=\"Update\">更新当前订阅</sys:String>\n    <sys:String x:Key=\"SaveError\">订阅备注不能一样</sys:String>\n\n    <sys:String x:Key=\"ProxyType\">更新订阅使用的代理类型</sys:String>\n    <sys:String x:Key=\"Auto\">自动</sys:String>\n    <sys:String x:Key=\"Direct\">直连</sys:String>\n    <sys:String x:Key=\"Proxy\">代理</sys:String>\n    <sys:String x:Key=\"SystemSetting\">系统设置</sys:String>\n\n    <sys:String x:Key=\"SaveQuestion\" xml:space=\"preserve\">发现不在订阅列表的订阅服务器&#13;是否删除？</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/I18N/SubscribeWindow.zh-TW.xaml",
    "content": "﻿<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n                    xmlns:sys=\"clr-namespace:System;assembly=mscorlib\">\n    <sys:String x:Key=\"ResourceDictionaryName\">zh-TW</sys:String>\n\n    <sys:String x:Key=\"Title\">訂閱設定</sys:String>\n\n    <sys:String x:Key=\"Ok\">確定並更新</sys:String>\n    <sys:String x:Key=\"Cancel\">取消</sys:String>\n    <sys:String x:Key=\"Apply\">套用</sys:String>\n\n    <sys:String x:Key=\"Add\">新增</sys:String>\n    <sys:String x:Key=\"Delete\">刪除</sys:String>\n\n    <sys:String x:Key=\"Url\">網址</sys:String>\n    <sys:String x:Key=\"GroupName\">訂閱備註</sys:String>\n    <sys:String x:Key=\"LastUpdate\">最近更新</sys:String>\n    <sys:String x:Key=\"AutoUpdate\">自動更新</sys:String>\n    <sys:String x:Key=\"Update\">更新當前訂閱</sys:String>\n    <sys:String x:Key=\"SaveError\">訂閱備註不能一樣</sys:String>\n\n    <sys:String x:Key=\"ProxyType\">更新訂閱使用的代理類型</sys:String>\n    <sys:String x:Key=\"Auto\">自動</sys:String>\n    <sys:String x:Key=\"Direct\">直接連線</sys:String>\n    <sys:String x:Key=\"Proxy\">代理</sys:String>\n    <sys:String x:Key=\"SystemSetting\">系統設定</sys:String>\n\n    <sys:String x:Key=\"SaveQuestion\" xml:space=\"preserve\">發現不在訂閱列表的訂閱服務器&#13;是否刪除？</sys:String>\n\n</ResourceDictionary>"
  },
  {
    "path": "shadowsocks-csharp/Model/Configuration.cs",
    "content": "using Shadowsocks.Enums;\r\nusing Shadowsocks.ViewModel;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Net;\r\nusing System.Text.Json.Serialization;\r\n\r\nnamespace Shadowsocks.Model\r\n{\r\n    [Serializable]\r\n    public class Configuration : ViewModelBase\r\n    {\r\n        #region private\r\n\r\n        private List<Server> _configs;\r\n        private int _index;\r\n        private bool _random;\r\n        private ProxyMode _sysProxyMode;\r\n        private bool _shareOverLan;\r\n        private int _localPort;\r\n        private int _reconnectTimes;\r\n        private BalanceType _balanceType;\r\n        private bool _randomInGroup;\r\n        private int _ttl;\r\n        private int _connectTimeout;\r\n        private ProxyRuleMode _proxyRuleMode;\r\n        private bool _proxyEnable;\r\n        private bool _pacDirectGoProxy;\r\n        private ProxyType _proxyType;\r\n        private string _proxyHost;\r\n        private int _proxyPort;\r\n        private string _proxyAuthUser;\r\n        private string _proxyAuthPass;\r\n        private string _proxyUserAgent;\r\n        private string _authUser;\r\n        private string _authPass;\r\n        private bool _autoBan;\r\n        private bool _checkSwitchAutoCloseAll;\r\n        private bool _logEnable;\r\n        private bool _sameHostForSameTarget;\r\n        private bool _isPreRelease;\r\n        private bool _autoCheckUpdate;\r\n        private string _langName;\r\n        private List<DnsClient> _dnsClients;\r\n        private List<ServerSubscribe> _serverSubscribes;\r\n        private Dictionary<string, PortMapConfig> _portMap;\r\n\r\n        #endregion\r\n\r\n        #region Public\r\n\r\n        /// <summary>\r\n        /// 服务器列表\r\n        /// </summary>\r\n        public List<Server> Configs { get => _configs; set => SetField(ref _configs, value); }\r\n\r\n        /// <summary>\r\n        /// 选中的服务器在列表的位置\r\n        /// </summary>\r\n        public int Index { get => _index; set => SetField(ref _index, value); }\r\n\r\n        /// <summary>\r\n        /// 是否启用负载均衡\r\n        /// </summary>\r\n        public bool Random { get => _random; set => SetField(ref _random, value); }\r\n\r\n        /// <summary>\r\n        /// 系统代理模式\r\n        /// </summary>\r\n        public ProxyMode SysProxyMode { get => _sysProxyMode; set => SetField(ref _sysProxyMode, value); }\r\n\r\n        /// <summary>\r\n        /// 是否监听所有网卡\r\n        /// </summary>\r\n        public bool ShareOverLan { get => _shareOverLan; set => SetField(ref _shareOverLan, value); }\r\n\r\n        /// <summary>\r\n        /// 监听端口\r\n        /// </summary>\r\n        public int LocalPort { get => _localPort; set => SetField(ref _localPort, value); }\r\n\r\n        /// <summary>\r\n        /// 重连次数\r\n        /// </summary>\r\n        public int ReconnectTimes { get => _reconnectTimes; set => SetField(ref _reconnectTimes, value); }\r\n\r\n        /// <summary>\r\n        /// 负载均衡使用的算法\r\n        /// </summary>\r\n        public BalanceType BalanceType { get => _balanceType; set => SetField(ref _balanceType, value); }\r\n\r\n        /// <summary>\r\n        /// 负载均衡是否只在所选组切换\r\n        /// </summary>\r\n        public bool RandomInGroup { get => _randomInGroup; set => SetField(ref _randomInGroup, value); }\r\n\r\n        /// <summary>\r\n        /// 空闲断开间隔（单位：秒）\r\n        /// </summary>\r\n        public int Ttl { get => _ttl; set => SetField(ref _ttl, value); }\r\n\r\n        /// <summary>\r\n        /// 连接超时（单位：秒）\r\n        /// </summary>\r\n        public int ConnectTimeout { get => _connectTimeout; set => SetField(ref _connectTimeout, value); }\r\n\r\n        /// <summary>\r\n        /// 代理规则模式\r\n        /// </summary>\r\n        public ProxyRuleMode ProxyRuleMode { get => _proxyRuleMode; set => SetField(ref _proxyRuleMode, value); }\r\n\r\n        /// <summary>\r\n        /// 是否开启二级代理\r\n        /// </summary>\r\n        public bool ProxyEnable { get => _proxyEnable; set => SetField(ref _proxyEnable, value); }\r\n\r\n        /// <summary>\r\n        /// PAC 的直连使用二级代理\r\n        /// </summary>\r\n        public bool PacDirectGoProxy { get => _pacDirectGoProxy; set => SetField(ref _pacDirectGoProxy, value); }\r\n\r\n        /// <summary>\r\n        /// 二级代理类型\r\n        /// </summary>\r\n        public ProxyType ProxyType { get => _proxyType; set => SetField(ref _proxyType, value); }\r\n\r\n        /// <summary>\r\n        /// 二级代理服务器地址\r\n        /// </summary>\r\n        public string ProxyHost { get => _proxyHost; set => SetField(ref _proxyHost, value); }\r\n\r\n        /// <summary>\r\n        /// 二级代理服务器端口\r\n        /// </summary>\r\n        public int ProxyPort { get => _proxyPort; set => SetField(ref _proxyPort, value); }\r\n\r\n        /// <summary>\r\n        /// 二级代理用户名\r\n        /// </summary>\r\n        public string ProxyAuthUser { get => _proxyAuthUser; set => SetField(ref _proxyAuthUser, value); }\r\n\r\n        /// <summary>\r\n        /// 二级代理密码\r\n        /// </summary>\r\n        public string ProxyAuthPass { get => _proxyAuthPass; set => SetField(ref _proxyAuthPass, value); }\r\n\r\n        /// <summary>\r\n        /// Http 请求所用的 UserAgent\r\n        /// </summary>\r\n        public string ProxyUserAgent { get => _proxyUserAgent; set => SetField(ref _proxyUserAgent, value); }\r\n\r\n        /// <summary>\r\n        /// 本地代理的用户名\r\n        /// </summary>\r\n        public string AuthUser { get => _authUser; set => SetField(ref _authUser, value); }\r\n\r\n        /// <summary>\r\n        /// 本地代理的密码\r\n        /// </summary>\r\n        public string AuthPass { get => _authPass; set => SetField(ref _authPass, value); }\r\n\r\n        /// <summary>\r\n        /// 自动禁用出错服务器\r\n        /// </summary>\r\n        public bool AutoBan { get => _autoBan; set => SetField(ref _autoBan, value); }\r\n\r\n        /// <summary>\r\n        /// 切换服务器前断开所有连接\r\n        /// </summary>\r\n        public bool CheckSwitchAutoCloseAll { get => _checkSwitchAutoCloseAll; set => SetField(ref _checkSwitchAutoCloseAll, value); }\r\n\r\n        /// <summary>\r\n        /// 是否开启日志\r\n        /// </summary>\r\n        public bool LogEnable { get => _logEnable; set => SetField(ref _logEnable, value); }\r\n\r\n        /// <summary>\r\n        /// 负载均衡优先使用同一个服务器访问同一地址\r\n        /// </summary>\r\n        public bool SameHostForSameTarget { get => _sameHostForSameTarget; set => SetField(ref _sameHostForSameTarget, value); }\r\n\r\n        /// <summary>\r\n        /// 检查更新是否包括测试版更新\r\n        /// </summary>\r\n        public bool IsPreRelease { get => _isPreRelease; set => SetField(ref _isPreRelease, value); }\r\n\r\n        /// <summary>\r\n        /// 自动检查更新\r\n        /// </summary>\r\n        public bool AutoCheckUpdate { get => _autoCheckUpdate; set => SetField(ref _autoCheckUpdate, value); }\r\n\r\n        /// <summary>\r\n        /// 所选的语言\r\n        /// </summary>\r\n        public string LangName { get => _langName; set => SetField(ref _langName, value); }\r\n\r\n        /// <summary>\r\n        /// 自定义的 DNS\r\n        /// </summary>\r\n        public List<DnsClient> DnsClients { get => _dnsClients; set => SetField(ref _dnsClients, value); }\r\n\r\n        /// <summary>\r\n        /// 订阅列表\r\n        /// </summary>\r\n        public List<ServerSubscribe> ServerSubscribes { get => _serverSubscribes; set => SetField(ref _serverSubscribes, value); }\r\n\r\n        /// <summary>\r\n        /// 端口设置列表\r\n        /// </summary>\r\n        public Dictionary<string, PortMapConfig> PortMap { get => _portMap; set => SetField(ref _portMap, value); }\r\n\r\n        #endregion\r\n\r\n        #region NotConfig\r\n\r\n        private const int KeepVisitTime = 1800;\r\n\r\n        private readonly Dictionary<int, ServerSelectStrategy> _serverStrategyMap = new();\r\n\r\n        [JsonIgnore]\r\n        public Dictionary<int, PortMapConfigCache> PortMapCache { get; private set; } = new();\r\n\r\n        private readonly LRUCache<string, UriVisitTime> _uriCache = new(180);\r\n\r\n        #endregion\r\n\r\n        public bool KeepCurrentServer(int port, string targetAddr, string id)\r\n        {\r\n            if (SameHostForSameTarget && targetAddr != null)\r\n            {\r\n                lock (_serverStrategyMap)\r\n                {\r\n                    if (!_serverStrategyMap.ContainsKey(port))\r\n                    {\r\n                        _serverStrategyMap[port] = new ServerSelectStrategy();\r\n                    }\r\n\r\n                    if (_uriCache.ContainsKey(targetAddr))\r\n                    {\r\n                        var visit = _uriCache.Get(targetAddr);\r\n                        var j = -1;\r\n                        for (var i = 0; i < Configs.Count; ++i)\r\n                        {\r\n                            if (Configs[i].Id == id)\r\n                            {\r\n                                j = i;\r\n                                break;\r\n                            }\r\n                        }\r\n                        if (j >= 0 && visit.index == j && Configs[j].Enable)\r\n                        {\r\n                            _uriCache.Del(targetAddr);\r\n                            return true;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return false;\r\n        }\r\n\r\n        public Server GetCurrentServer(int port, ServerSelectStrategy.FilterFunc filter, string targetAddr = null, bool cfgRandom = false, bool usingRandom = false, bool forceRandom = false)\r\n        {\r\n            lock (_serverStrategyMap)\r\n            {\r\n                if (!_serverStrategyMap.ContainsKey(port))\r\n                {\r\n                    _serverStrategyMap[port] = new ServerSelectStrategy();\r\n                }\r\n\r\n                var serverStrategy = _serverStrategyMap[port];\r\n\r\n                _uriCache.SetTimeout(KeepVisitTime);\r\n                _uriCache.Sweep();\r\n                if (SameHostForSameTarget && !forceRandom && targetAddr != null && _uriCache.ContainsKey(targetAddr))\r\n                {\r\n                    var visit = _uriCache.Get(targetAddr);\r\n                    if (visit.index < Configs.Count && Configs[visit.index].Enable && Configs[visit.index].SpeedLog.ErrorContinuousTimes == 0)\r\n                    {\r\n                        _uriCache.Del(targetAddr);\r\n                        return Configs[visit.index];\r\n                    }\r\n                }\r\n                if (forceRandom)\r\n                {\r\n                    int i;\r\n                    if (filter == null && RandomInGroup)\r\n                    {\r\n                        i = serverStrategy.Select(Configs, Index, BalanceType, delegate (Server server, Server selServer)\r\n                        {\r\n                            if (selServer != null)\r\n                            {\r\n                                return selServer.Group == server.Group;\r\n                            }\r\n\r\n                            return false;\r\n                        }, true);\r\n                    }\r\n                    else\r\n                    {\r\n                        i = serverStrategy.Select(Configs, Index, BalanceType, filter, true);\r\n                    }\r\n                    return i == -1 ? GetErrorServer() : Configs[i];\r\n                }\r\n\r\n                if (usingRandom && cfgRandom)\r\n                {\r\n                    int i;\r\n                    if (filter == null && RandomInGroup)\r\n                    {\r\n                        i = serverStrategy.Select(Configs, Index, BalanceType, delegate (Server server, Server selServer)\r\n                        {\r\n                            if (selServer != null)\r\n                            {\r\n                                return selServer.Group == server.Group;\r\n                            }\r\n\r\n                            return false;\r\n                        });\r\n                    }\r\n                    else\r\n                    {\r\n                        i = serverStrategy.Select(Configs, Index, BalanceType, filter);\r\n                    }\r\n                    if (i == -1)\r\n                    {\r\n                        return GetErrorServer();\r\n                    }\r\n\r\n                    if (targetAddr != null)\r\n                    {\r\n                        var visit = new UriVisitTime\r\n                        {\r\n                            uri = targetAddr,\r\n                            index = i,\r\n                            visitTime = DateTime.Now\r\n                        };\r\n                        _uriCache.Set(targetAddr, visit);\r\n                    }\r\n                    return Configs[i];\r\n                }\r\n\r\n                if (Index >= 0 && Index < Configs.Count)\r\n                {\r\n                    var selIndex = Index;\r\n                    if (usingRandom)\r\n                    {\r\n                        foreach (var unused in Configs)\r\n                        {\r\n                            if (Configs[selIndex].Enable)\r\n                            {\r\n                                break;\r\n                            }\r\n\r\n                            selIndex = (selIndex + 1) % Configs.Count;\r\n                        }\r\n                    }\r\n\r\n                    if (targetAddr != null)\r\n                    {\r\n                        var visit = new UriVisitTime\r\n                        {\r\n                            uri = targetAddr,\r\n                            index = selIndex,\r\n                            visitTime = DateTime.Now\r\n                        };\r\n                        _uriCache.Set(targetAddr, visit);\r\n                    }\r\n                    return Configs[selIndex];\r\n                }\r\n\r\n                return GetErrorServer();\r\n            }\r\n        }\r\n\r\n        public void FlushPortMapCache()\r\n        {\r\n            PortMapCache = new Dictionary<int, PortMapConfigCache>();\r\n            var id2server = new Dictionary<string, Server>();\r\n            var server_group = new Dictionary<string, int>();\r\n            foreach (var s in Configs)\r\n            {\r\n                id2server[s.Id] = s;\r\n                if (!string.IsNullOrEmpty(s.Group))\r\n                {\r\n                    server_group[s.Group] = 1;\r\n                }\r\n            }\r\n            foreach (var pair in PortMap)\r\n            {\r\n                int key;\r\n                var pm = pair.Value;\r\n                if (!pm.Enable)\r\n                {\r\n                    continue;\r\n                }\r\n\r\n                if (id2server.ContainsKey(pm.Id) || server_group.ContainsKey(pm.Id) || pm.Id == null || pm.Id.Length == 0)\r\n                { }\r\n                else\r\n                {\r\n                    continue;\r\n                }\r\n\r\n                try\r\n                {\r\n                    key = int.Parse(pair.Key);\r\n                }\r\n                catch (FormatException)\r\n                {\r\n                    continue;\r\n                }\r\n                PortMapCache[key] = new PortMapConfigCache\r\n                {\r\n                    type = pm.Type,\r\n                    id = pm.Id,\r\n                    server = id2server.ContainsKey(pm.Id) ? id2server[pm.Id] : null,\r\n                    server_addr = pm.Server_addr,\r\n                    server_port = pm.Server_port\r\n                };\r\n            }\r\n            lock (_serverStrategyMap)\r\n            {\r\n                var remove_ports = new List<int>();\r\n                foreach (var pair in _serverStrategyMap)\r\n                {\r\n                    if (PortMapCache.ContainsKey(pair.Key))\r\n                    {\r\n                        continue;\r\n                    }\r\n\r\n                    remove_ports.Add(pair.Key);\r\n                }\r\n                foreach (var port in remove_ports)\r\n                {\r\n                    _serverStrategyMap.Remove(port);\r\n                }\r\n                if (!PortMapCache.ContainsKey(LocalPort))\r\n                {\r\n                    _serverStrategyMap.Remove(LocalPort);\r\n                }\r\n            }\r\n\r\n            _uriCache.Clear();\r\n        }\r\n\r\n        public Configuration()\r\n        {\r\n            Configs = new List<Server>();\r\n            Index = 0;\r\n            Random = false;\r\n            SysProxyMode = ProxyMode.NoModify;\r\n            ShareOverLan = false;\r\n            LocalPort = 1080;\r\n            ReconnectTimes = 2;\r\n            BalanceType = BalanceType.LowException;\r\n            RandomInGroup = true;\r\n            Ttl = 60;\r\n            ConnectTimeout = 5;\r\n            ProxyRuleMode = ProxyRuleMode.Disable;\r\n            ProxyEnable = false;\r\n            PacDirectGoProxy = false;\r\n            ProxyType = ProxyType.Socks5;\r\n            ProxyHost = string.Empty;\r\n            ProxyPort = 1;\r\n            ProxyAuthUser = string.Empty;\r\n            ProxyAuthPass = string.Empty;\r\n            ProxyUserAgent = string.Empty;\r\n            AuthUser = string.Empty;\r\n            AuthPass = string.Empty;\r\n            AutoBan = false;\r\n            CheckSwitchAutoCloseAll = true;\r\n            LogEnable = true;\r\n            SameHostForSameTarget = true;\r\n            IsPreRelease = false;\r\n            AutoCheckUpdate = true;\r\n            LangName = string.Empty;\r\n            DnsClients = new List<DnsClient>\r\n            {\r\n                new(DnsType.DnsOverTls) { DnsServer = @\"208.67.222.222\" },\r\n                new(DnsType.DnsOverTls) { DnsServer = @\"208.67.220.220\" },\r\n                new(DnsType.DnsOverTls) { DnsServer = @\"1.1.1.1\" },\r\n                new(DnsType.DnsOverTls) { DnsServer = @\"1.0.0.1\" },\r\n                new(DnsType.DnsOverTls) { DnsServer = @\"1.12.12.12\" },\r\n            };\r\n            ServerSubscribes = new List<ServerSubscribe>();\r\n            PortMap = new Dictionary<string, PortMapConfig>();\r\n        }\r\n\r\n        public void CopyFrom(Configuration config)\r\n        {\r\n            Configs = config.Configs;\r\n            Index = config.Index;\r\n            Random = config.Random;\r\n            SysProxyMode = config.SysProxyMode;\r\n            ShareOverLan = config.ShareOverLan;\r\n            LocalPort = config.LocalPort;\r\n            ReconnectTimes = config.ReconnectTimes;\r\n            BalanceType = config.BalanceType;\r\n            RandomInGroup = config.RandomInGroup;\r\n            Ttl = config.Ttl;\r\n            ConnectTimeout = config.ConnectTimeout;\r\n            ProxyRuleMode = config.ProxyRuleMode;\r\n            ProxyEnable = config.ProxyEnable;\r\n            PacDirectGoProxy = config.PacDirectGoProxy;\r\n            ProxyType = config.ProxyType;\r\n            ProxyHost = config.ProxyHost;\r\n            ProxyPort = config.ProxyPort;\r\n            ProxyAuthUser = config.ProxyAuthUser;\r\n            ProxyAuthPass = config.ProxyAuthPass;\r\n            ProxyUserAgent = config.ProxyUserAgent;\r\n            AuthUser = config.AuthUser;\r\n            AuthPass = config.AuthPass;\r\n            AutoBan = config.AutoBan;\r\n            CheckSwitchAutoCloseAll = config.CheckSwitchAutoCloseAll;\r\n            LogEnable = config.LogEnable;\r\n            SameHostForSameTarget = config.SameHostForSameTarget;\r\n            IsPreRelease = config.IsPreRelease;\r\n            AutoCheckUpdate = config.AutoCheckUpdate;\r\n            LangName = config.LangName;\r\n            DnsClients = config.DnsClients;\r\n            ServerSubscribes = config.ServerSubscribes;\r\n            //PortMap = config.PortMap;\r\n        }\r\n\r\n        public void FixConfiguration()\r\n        {\r\n            if (!IsPort(LocalPort))\r\n            {\r\n                LocalPort = 1080;\r\n            }\r\n            if (PortMap == null)\r\n            {\r\n                PortMap = new Dictionary<string, PortMapConfig>();\r\n            }\r\n            if (ConnectTimeout == 0)\r\n            {\r\n                ConnectTimeout = 5;\r\n                ReconnectTimes = 2;\r\n                Ttl = 60;\r\n            }\r\n            if (Index < 0 || Index >= Configs.Count)\r\n            {\r\n                Index = 0;\r\n            }\r\n            if (Configs.Count == 0)\r\n            {\r\n                Configs.Add(new Server());\r\n            }\r\n\r\n            var id = new HashSet<string>();\r\n            foreach (var server in Configs)\r\n            {\r\n                while (id.Contains(server.Id))\r\n                {\r\n                    server.Id = Guid.NewGuid().ToString(@\"N\");\r\n                }\r\n                id.Add(server.Id);\r\n            }\r\n        }\r\n\r\n        public bool IsDefaultConfig()\r\n        {\r\n            return Configs.All(server => server.server == new Server().server);\r\n        }\r\n\r\n        private static Server GetErrorServer()\r\n        {\r\n            var server = new Server { server = @\"invalid\" };\r\n            return server;\r\n        }\r\n\r\n        private static bool IsPort(int port)\r\n        {\r\n            return port is > IPEndPoint.MinPort and <= IPEndPoint.MaxPort;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Model/ConfigurationException.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Model\n{\n    [Serializable]\n    internal class ConfigurationException : Exception\n    {\n        public ConfigurationException()\n        { }\n        public ConfigurationException(string message) : base(message) { }\n        public ConfigurationException(string message, Exception inner) : base(message, inner) { }\n        protected ConfigurationException(System.Runtime.Serialization.SerializationInfo info,\n                System.Runtime.Serialization.StreamingContext context)\n        { }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/Connections.cs",
    "content": "using Shadowsocks.Proxy;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Model\n{\n    public class Connections\n    {\n        private readonly Dictionary<IHandler, int> sockets = new();\n        public bool AddRef(IHandler socket)\n        {\n            lock (this)\n            {\n                if (sockets.ContainsKey(socket))\n                {\n                    sockets[socket] += 1;\n                }\n                else\n                {\n                    sockets[socket] = 1;\n                }\n                return true;\n            }\n        }\n        public bool DecRef(IHandler socket)\n        {\n            lock (this)\n            {\n                if (sockets.ContainsKey(socket))\n                {\n                    sockets[socket] -= 1;\n                    if (sockets[socket] == 0)\n                    {\n                        sockets.Remove(socket);\n                    }\n                }\n                else\n                {\n                    return false;\n                }\n                return true;\n            }\n        }\n        public void CloseAll()\n        {\n            IHandler[] s;\n            lock (this)\n            {\n                s = new IHandler[sockets.Count];\n                sockets.Keys.CopyTo(s, 0);\n            }\n            foreach (var handler in s)\n            {\n                try\n                {\n                    handler.Shutdown();\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/DnsBuffer.cs",
    "content": "using System;\nusing System.Net;\n\nnamespace Shadowsocks.Model\n{\n    public class DnsBuffer\n    {\n        public IPAddress Ip;\n        public DateTime updateTime;\n        public string Host;\n        public bool force_expired;\n\n        public bool IsExpired(string host)\n        {\n            if (Host != host)\n            {\n                return true;\n            }\n\n            if (force_expired && (DateTime.Now - updateTime).TotalMinutes > 1)\n            {\n                return true;\n            }\n\n            return (DateTime.Now - updateTime).TotalMinutes > 30;\n        }\n\n        public void UpdateDns(string host, IPAddress ip)\n        {\n            updateTime = DateTime.Now;\n            Ip = new IPAddress(ip.GetAddressBytes());\n            Host = host;\n            force_expired = false;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/DnsClient.cs",
    "content": "using ARSoft.Tools.Net;\nusing ARSoft.Tools.Net.Dns;\nusing Shadowsocks.Enums;\nusing Shadowsocks.ViewModel;\nusing System;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Security.Authentication;\nusing System.Text.Json.Serialization;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n#nullable enable\n\nnamespace Shadowsocks.Model;\n\n[Serializable]\npublic class DnsClient : ViewModelBase\n{\n    #region private\n\n    private bool _enable;\n    private DnsType _dnsType;\n    private bool _ipv6First;\n    private string _dnsServer;\n    private ushort _port;\n    private int _timeout;\n    private bool _isEDnsEnabled;\n    private string _ecsIp;\n    private byte _ecsSourceNetmask;\n    private byte _ecsScopeNetmask;\n    private bool _isTcpEnabled;\n    private bool _isUdpEnabled;\n\n    #endregion\n\n    #region public\n\n    public bool Enable\n    {\n        get => _enable;\n        set => SetField(ref _enable, value);\n    }\n\n    public DnsType DnsType\n    {\n        get => _dnsType;\n        set => SetField(ref _dnsType, value);\n    }\n\n    public bool Ipv6First\n    {\n        get => _ipv6First;\n        set => SetField(ref _ipv6First, value);\n    }\n\n    public string DnsServer\n    {\n        get => IsValidDns(_dnsServer) ? _dnsServer : DefaultDnsServer;\n        set\n        {\n            if (IsValidDns(value))\n            {\n                SetField(ref _dnsServer, value);\n                _ip = null;\n            }\n        }\n    }\n\n    public ushort Port\n    {\n        get => _port;\n        set => SetField(ref _port, value);\n    }\n\n    public int Timeout\n    {\n        get => _timeout;\n        set => SetField(ref _timeout, value);\n    }\n\n    public bool IsEDnsEnabled\n    {\n        get => _isEDnsEnabled;\n        set => SetField(ref _isEDnsEnabled, value);\n    }\n\n    public string EcsIp\n    {\n        get => IsIp(_ecsIp) ? _ecsIp : DefaultDnsServer;\n        set\n        {\n            if (IsIp(value))\n            {\n                SetField(ref _ecsIp, value);\n            }\n        }\n    }\n\n    public byte EcsSourceNetmask\n    {\n        get => _ecsSourceNetmask;\n        set => SetField(ref _ecsSourceNetmask, value);\n    }\n\n    public byte EcsScopeNetmask\n    {\n        get => _ecsScopeNetmask;\n        set => SetField(ref _ecsScopeNetmask, value);\n    }\n\n    public bool IsTcpEnabled\n    {\n        get => _isTcpEnabled;\n        set => SetField(ref _isTcpEnabled, value);\n    }\n\n    public bool IsUdpEnabled\n    {\n        get => _isUdpEnabled;\n        set => SetField(ref _isUdpEnabled, value);\n    }\n\n    #endregion\n\n    #region Ignore\n\n    private IPAddress? _ip;\n    public const string DefaultDnsServer = @\"208.67.222.222\";\n    public const ushort DefaultPort = 53;\n    public const string DefaultTlsDnsServer = @\"208.67.222.222\";\n    public const ushort DefaultTlsPort = 853;\n\n    #endregion\n\n    #region 构造函数\n\n    [JsonConstructor]\n    public DnsClient()\n    {\n        _ip = null;\n\n        _enable = true;\n        _dnsType = DnsType.Default;\n        _ipv6First = false;\n        _dnsServer = DefaultDnsServer;\n        _port = DefaultPort;\n        _timeout = 10000;\n        _isEDnsEnabled = false;\n        _ecsIp = DefaultDnsServer;\n        _ecsSourceNetmask = 32;\n        _ecsScopeNetmask = 0;\n        _isTcpEnabled = true;\n        _isUdpEnabled = true;\n    }\n\n    public DnsClient(DnsType type) : this()\n    {\n        _dnsType = type;\n        switch (type)\n        {\n            case DnsType.Default:\n            {\n                _dnsServer = DefaultDnsServer;\n                _port = DefaultPort;\n                break;\n            }\n            case DnsType.DnsOverTls:\n            {\n                _dnsServer = DefaultTlsDnsServer;\n                _port = DefaultTlsPort;\n                break;\n            }\n        }\n    }\n\n    #endregion\n\n    #region Private Method\n\n    private static bool IsIp(string? str)\n    {\n        return IPAddress.TryParse(str, out var ip) && ip.ToString() == str;\n    }\n\n    private bool IsValidDns(string? dns)\n    {\n        return DnsType == DnsType.DnsOverTls || IsIp(dns);\n    }\n\n    private static async Task<IPAddress?> QueryBaseAAsync(ARSoft.Tools.Net.Dns.DnsClient client, DomainName domain, DnsQueryOptions options, CancellationToken ct)\n    {\n        DnsMessage? message = null;\n        try\n        {\n            message = await client.ResolveAsync(domain, RecordType.A, RecordClass.INet, options, ct);\n        }\n        catch\n        {\n            // ignored\n        }\n        return message?.AnswerRecords?.OfType<ARecord>().Select(answerRecord => answerRecord.Address).FirstOrDefault();\n    }\n\n    private static async Task<IPAddress?> QueryBaseAaaaAsync(ARSoft.Tools.Net.Dns.DnsClient client, DomainName domain, DnsQueryOptions options, CancellationToken ct)\n    {\n        DnsMessage? message = null;\n        try\n        {\n            message = await client.ResolveAsync(domain, RecordType.Aaaa, RecordClass.INet, options, ct);\n        }\n        catch\n        {\n            // ignored\n        }\n        return message?.AnswerRecords?.OfType<AaaaRecord>().Select(answerRecord => answerRecord.Address).FirstOrDefault();\n    }\n\n    private static async Task<IPAddress?> QueryBaseAsync(ARSoft.Tools.Net.Dns.DnsClient client, DomainName domain, DnsQueryOptions options, bool ipv6First, CancellationToken ct)\n    {\n        var res = await Task.WhenAll(\n            QueryBaseAaaaAsync(client, domain, options, ct),\n            QueryBaseAAsync(client, domain, options, ct));\n\n        if (ipv6First)\n        {\n            return res[0] ?? res[1];\n        }\n\n        return res[1] ?? res[0];\n    }\n\n    private static async Task<IPAddress?> QueryBaseTlsAAsync(DnsOverTlsClient client, DomainName domain, DnsQueryOptions options, CancellationToken ct)\n    {\n        DnsMessage? message = null;\n        try\n        {\n            message = await client.ResolveAsync(domain, RecordType.A, RecordClass.INet, options, ct);\n        }\n        catch\n        {\n            // ignored\n        }\n        return message?.AnswerRecords?.OfType<ARecord>().Select(answerRecord => answerRecord.Address).FirstOrDefault();\n    }\n\n    private static async Task<IPAddress?> QueryBaseTlsAaaaAsync(DnsOverTlsClient client, DomainName domain, DnsQueryOptions options, CancellationToken ct)\n    {\n        DnsMessage? message = null;\n        try\n        {\n            message = await client.ResolveAsync(domain, RecordType.Aaaa, RecordClass.INet, options, ct);\n        }\n        catch\n        {\n            // ignored\n        }\n        return message?.AnswerRecords?.OfType<AaaaRecord>().Select(answerRecord => answerRecord.Address).FirstOrDefault();\n    }\n\n    private static async Task<IPAddress?> QueryBaseTlsAsync(DnsOverTlsClient client, DomainName domain, DnsQueryOptions options, bool ipv6First, CancellationToken ct)\n    {\n        if (ipv6First)\n        {\n            var res = await Task.WhenAll(QueryBaseTlsAaaaAsync(client, domain, options, ct), QueryBaseTlsAAsync(client, domain, options, ct));\n            return res[0] ?? res[1];\n        }\n        else\n        {\n            var res = await Task.WhenAll(QueryBaseTlsAAsync(client, domain, options, ct));\n            return res[0];\n        }\n    }\n\n    #endregion\n\n    public static async Task<IPAddress?> QueryIpAddressDefaultAsync(string host, bool ipv6First, CancellationToken ct)\n    {\n        IPAddress[] ips = await Dns.GetHostAddressesAsync(host, ct);\n\n        if (ipv6First)\n        {\n            foreach (var ip in ips)\n            {\n                if (ip.AddressFamily is AddressFamily.InterNetworkV6)\n                {\n                    return ip;\n                }\n            }\n        }\n\n        return ips.FirstOrDefault();\n    }\n\n    public async Task<IPAddress?> QueryIpAddressAsync(string host, CancellationToken ct)\n    {\n        var domain = DomainName.Parse(host);\n        var options = new DnsQueryOptions\n        {\n            IsEDnsEnabled = IsEDnsEnabled,\n            IsRecursionDesired = true,\n        };\n        if (options.IsEDnsEnabled)\n        {\n            options.EDnsOptions = new OptRecord { Options = { new ClientSubnetOption(EcsSourceNetmask, EcsScopeNetmask, IPAddress.Parse(EcsIp)) } };\n        }\n        switch (DnsType)\n        {\n            case DnsType.Default:\n            {\n                var dnsClient = new ARSoft.Tools.Net.Dns.DnsClient(IPAddress.Parse(DnsServer), Timeout, Port)\n                {\n                    IsTcpEnabled = IsTcpEnabled,\n                    IsUdpEnabled = IsUdpEnabled\n                };\n                return await QueryBaseAsync(dnsClient, domain, options, Ipv6First, ct);\n            }\n            case DnsType.DnsOverTls:\n            {\n                _ip ??= await QueryIpAddressDefaultAsync(DnsServer, Ipv6First, ct);\n                if (_ip is null)\n                {\n                    return null;\n                }\n                var tlsServer = new TlsUpstreamServer\n                {\n                    IPAddress = _ip,\n                    AuthName = DnsServer,\n                    SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12\n                };\n                var dnsClient = new DnsOverTlsClient(tlsServer, Timeout, Port);\n                var res = await QueryBaseTlsAsync(dnsClient, domain, options, Ipv6First, ct);\n                if (res is null)\n                {\n                    _ip = null;\n                }\n                return res;\n            }\n            default:\n                return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/ErrorLog.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Model\n{\n    public class ErrorLog\n    {\n        public int errno;\n        public DateTime time;\n        public ErrorLog(int no)\n        {\n            errno = no;\n            time = DateTime.Now;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/Global.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Controller.HttpRequest;\nusing Shadowsocks.Controller.Service;\nusing Shadowsocks.Util;\nusing System;\nusing System.IO;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text.Json;\n\nnamespace Shadowsocks.Model\n{\n    public static class Global\n    {\n        private const string ConfigFile = @\"gui-config.json\";\n\n        public static bool OSSupportsLocalIPv6 => Socket.OSSupportsIPv6;\n\n        public static string LocalHost => OSSupportsLocalIPv6 ? $@\"[{IPAddress.IPv6Loopback}]\" : $@\"{IPAddress.Loopback}\";\n\n        public static string AnyHost => OSSupportsLocalIPv6 ? $@\"[{IPAddress.IPv6Any}]\" : $@\"{IPAddress.Any}\";\n\n        public static IPAddress IpLocal => OSSupportsLocalIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback;\n\n        public static IPAddress IpAny => OSSupportsLocalIPv6 ? IPAddress.IPv6Any : IPAddress.Any;\n\n        public static Configuration GuiConfig;\n\n        public static MainController Controller;\n\n        public static MenuViewController ViewController;\n\n        public static UpdateNode UpdateNodeChecker;\n\n        public static UpdateSubscribeManager UpdateSubscribeManager;\n\n        public static Configuration LoadFile(string filename)\n        {\n            Configuration config;\n            try\n            {\n                if (File.Exists(filename))\n                {\n                    var configContent = File.ReadAllText(filename);\n                    config = Load(configContent);\n                    if (config != null)\n                    {\n                        return config;\n                    }\n                }\n            }\n            catch (Exception e)\n            {\n                Console.WriteLine(e);\n            }\n\n            config = new Configuration();\n            config.FixConfiguration();\n            return config;\n        }\n\n        public static Configuration Load()\n        {\n            return LoadFile(ConfigFile);\n        }\n\n        private static Configuration Load(string configStr)\n        {\n            try\n            {\n                var config = JsonSerializer.Deserialize<Configuration>(configStr);\n                if (config is not null)\n                {\n                    config.FixConfiguration();\n                    return config;\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n            return null;\n        }\n\n        public static void LoadConfig()\n        {\n            GuiConfig = Load();\n        }\n\n        public static void SaveConfig()\n        {\n            if (GuiConfig.Index >= GuiConfig.Configs.Count)\n            {\n                GuiConfig.Index = GuiConfig.Configs.Count - 1;\n            }\n            else if (GuiConfig.Index < 0)\n            {\n                GuiConfig.Index = 0;\n            }\n\n            try\n            {\n                var jsonString = JsonUtils.Serialize(GuiConfig, true);\n                File.WriteAllText(ConfigFile, jsonString);\n            }\n            catch (IOException e)\n            {\n                Console.Error.WriteLine(e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/HostNode.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Shadowsocks.Model\n{\n    internal class HostNode\n    {\n        public readonly bool IncludeSub;\n        public readonly string Addr;\n        public Dictionary<string, HostNode> SubNode;\n\n        public HostNode()\n        {\n            IncludeSub = false;\n            Addr = string.Empty;\n            SubNode = new Dictionary<string, HostNode>();\n        }\n\n        public HostNode(bool sub, string addr)\n        {\n            IncludeSub = sub;\n            Addr = addr;\n            SubNode = null;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/IPRangeSet.cs",
    "content": "using RouteMatcher.Abstractions;\nusing RouteMatcher.IPMatchers;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Properties;\nusing Shadowsocks.Util;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing System.Net;\nusing System.Text;\n\n#nullable enable\n\nnamespace Shadowsocks.Model\n{\n    public class IPRangeSet\n    {\n        public const string ChnFilename = @\"chn_ip.txt\";\n        private static bool IsReverse => Global.GuiConfig.ProxyRuleMode == ProxyRuleMode.BypassLanAndNotChina;\n\n        private IIPAddressMatcher<Rule> _ipMatcher;\n\n        public IPRangeSet()\n        {\n            Reset();\n        }\n\n        [MemberNotNull(nameof(_ipMatcher))]\n        private void Reset()\n        {\n            _ipMatcher = new IPMatcherTrie<Rule>();\n        }\n\n        public bool IsInIPRange(IPAddress ip)\n        {\n            if (!IsReverse)\n            {\n                return _ipMatcher.Match(ip) == Rule.Direct;\n            }\n\n            return _ipMatcher.Match(ip) == default;\n        }\n\n        private bool LoadChn(IEnumerable<string?> lines)\n        {\n            try\n            {\n                var hasRule = false;\n                foreach (var line in lines)\n                {\n                    if (line is null)\n                    {\n                        continue;\n                    }\n\n                    var strings = line.Split('/', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);\n                    if (strings.Length != 2\n                        || !IPAddress.TryParse(strings[0], out var ip)\n                        || !byte.TryParse(strings[1], out var mask))\n                    {\n                        continue;\n                    }\n\n                    _ipMatcher.Update(ip, mask, Rule.Direct);\n                    hasRule = true;\n                }\n                return hasRule;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        public void LoadChn()\n        {\n            var absFilePath = Path.Combine(Directory.GetCurrentDirectory(), ChnFilename);\n            if (File.Exists(absFilePath))\n            {\n                if (!LoadChn(File.ReadLines(absFilePath, Encoding.UTF8)))\n                {\n                    Reset();\n                }\n            }\n            else\n            {\n                LoadChn(Resources.chn_ip.GetLines());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/IPSegment.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Net;\n\nnamespace Shadowsocks.Model\n{\n    public class IPAddressCmp : IPAddress, IComparable\n    {\n        public IPAddressCmp(IPAddress ip) : base(ip.GetAddressBytes())\n        {\n        }\n\n        public IPAddressCmp(byte[] ip) : base(ip)\n        {\n        }\n\n        public IPAddressCmp(string ip) : base(FromString(ip).GetAddressBytes())\n        {\n        }\n\n        public static IPAddress FromString(string ip)\n        {\n            TryParse(ip, out var addr);\n            return addr;\n        }\n\n        public int CompareTo(object obj)\n        {\n            var b1 = GetAddressBytes();\n            var b2 = ((IPAddressCmp)obj).GetAddressBytes();\n            for (var i = 0; i < b1.Length; ++i)\n            {\n                if (b1[i] < b2[i])\n                {\n                    return -1;\n                }\n\n                if (b1[i] > b2[i])\n                {\n                    return 1;\n                }\n            }\n            if (b1.Length < b2.Length)\n            {\n                return -1;\n            }\n\n            if (b1.Length > b2.Length)\n            {\n                return 1;\n            }\n\n            return 0;\n        }\n\n        public IPAddressCmp ToIPv6()\n        {\n            if (AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)\n            {\n                return this;\n            }\n\n            var b1 = GetAddressBytes();\n            var br = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0 };\n            b1.CopyTo(br, 12);\n            return new IPAddressCmp(br);\n        }\n\n        public IPAddressCmp Inc()\n        {\n            var b = GetAddressBytes();\n            var i = b.Length - 1;\n            for (; i >= 0; --i)\n            {\n                if (b[i] == 0xff)\n                {\n                    b[i] = 0;\n                }\n                else\n                {\n                    b[i]++;\n                    break;\n                }\n            }\n            if (i < 0)\n            {\n                return new IPAddressCmp(GetAddressBytes());\n            }\n            return new IPAddressCmp(b);\n        }\n    }\n\n    public class IPSegment\n    {\n        protected SortedList list = new();\n\n        public IPSegment(object val = null)\n        {\n            list.Add(new IPAddressCmp(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }), val);\n        }\n\n        public bool insert(IPAddressCmp ipStart, IPAddressCmp ipEnd, object val)\n        {\n            var s = ipStart.ToIPv6();\n            var e = ipEnd.ToIPv6().Inc();\n            object ed_val = null;\n            if (list.Contains(s))\n            {\n                ed_val = list[s];\n                list[s] = val;\n            }\n            else\n            {\n                list[s] = val;\n                var index = list.IndexOfKey(s) - 1;\n                if (index >= 0)\n                {\n                    ed_val = list.GetByIndex(index);\n                }\n            }\n            {\n                var index = list.IndexOfKey(s);\n                while (index > 0)\n                {\n                    if (val.Equals(list.GetByIndex(index - 1)))\n                    {\n                        list.RemoveAt(index);\n                        --index;\n                    }\n                    else\n                    {\n                        break;\n                    }\n                }\n                ++index;\n                var keep = false;\n                while (index < list.Count)\n                {\n                    var cmp = ((IPAddressCmp)list.GetKey(index)).CompareTo(e);\n                    if (cmp >= 0)\n                    {\n                        if (cmp == 0)\n                        {\n                            keep = true;\n                        }\n\n                        break;\n                    }\n                    ed_val = list.GetByIndex(index);\n                    list.RemoveAt(index);\n                }\n                if (!keep)\n                {\n                    list[e] = ed_val;\n                    index = list.IndexOfKey(e);\n                    while (index > 0)\n                    {\n                        if (ed_val != null && ed_val.Equals(list.GetByIndex(index - 1)))\n                        {\n                            list.RemoveAt(index);\n                            --index;\n                        }\n                        else\n                        {\n                            break;\n                        }\n                    }\n                    while (index + 1 < list.Count)\n                    {\n                        if (ed_val != null && ed_val.Equals(list.GetByIndex(index + 1)))\n                        {\n                            list.RemoveAt(index);\n                        }\n                        else\n                        {\n                            break;\n                        }\n                    }\n                }\n            }\n            return true;\n        }\n\n        public object Get(IPAddressCmp ip)\n        {\n            var ip_addr = ip.ToIPv6();\n            int l = 0, r = list.Count - 1;\n            while (l < r)\n            {\n                var m = (l + r + 1) / 2;\n                if (list.GetKey(m) is IPAddressCmp v)\n                {\n                    var cmp = v.CompareTo(ip_addr);\n\n                    if (cmp > 0)\n                    {\n                        r = m - 1;\n                    }\n                    else if (cmp < 0)\n                    {\n                        l = m;\n                    }\n                    else if (cmp == 0)\n                    {\n                        return list.GetByIndex(m);\n                    }\n                }\n            }\n            return list.GetByIndex(l);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/LRUCache.cs",
    "content": "using Shadowsocks.Controller;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Model\n{\n    public class LRUCache<K, V>\n    {\n        protected Dictionary<K, V> _store = new();\n        protected Dictionary<K, DateTime> _key_2_time = new();\n        protected Dictionary<DateTime, K> _time_2_key = new();\n        protected object _lock = new();\n        protected int _sweep_time;\n\n        public LRUCache(int sweep_time = 60 * 60)\n        {\n            _sweep_time = sweep_time;\n        }\n\n        public void SetTimeout(int time)\n        {\n            _sweep_time = time;\n        }\n\n        public void Clear()\n        {\n            lock (_lock)\n            {\n                _store.Clear();\n                _key_2_time.Clear();\n                _time_2_key.Clear();\n            }\n        }\n\n        public bool isTimeout(K key)\n        {\n            lock (_lock)\n            {\n                if ((DateTime.Now - _key_2_time[key]).TotalSeconds > _sweep_time)\n                {\n                    return true;\n                }\n                return false;\n            }\n        }\n\n        public bool ContainsKey(K key)\n        {\n            lock (_lock)\n            {\n                return _store.ContainsKey(key);\n            }\n        }\n\n        public V Get(K key)\n        {\n            lock (_lock)\n            {\n                if (_store.ContainsKey(key))\n                {\n                    var t = _key_2_time[key];\n                    _key_2_time.Remove(key);\n                    _time_2_key.Remove(t);\n                    t = DateTime.Now;\n                    while (_time_2_key.ContainsKey(t))\n                    {\n                        t = t.AddTicks(1);\n                    }\n                    _time_2_key[t] = key;\n                    _key_2_time[key] = t;\n                    return _store[key];\n                }\n                return default;\n            }\n        }\n\n        public V Set(K key, V val)\n        {\n            lock (_lock)\n            {\n                DateTime t;\n                if (_store.ContainsKey(key))\n                {\n                    t = _key_2_time[key];\n                    _key_2_time.Remove(key);\n                    _time_2_key.Remove(t);\n                }\n                t = DateTime.Now;\n                while (_time_2_key.ContainsKey(t))\n                {\n                    t = t.AddTicks(1);\n                }\n                _time_2_key[t] = key;\n                _key_2_time[key] = t;\n                _store[key] = val;\n                return val;\n            }\n        }\n\n        public void Del(K key)\n        {\n            lock (_lock)\n            {\n                DateTime t;\n                if (_store.ContainsKey(key))\n                {\n                    t = _key_2_time[key];\n                    _key_2_time.Remove(key);\n                    _time_2_key.Remove(t);\n                    _store.Remove(key);\n                }\n            }\n        }\n\n        public void Sweep()\n        {\n            lock (_lock)\n            {\n                var now = DateTime.Now;\n                var sweep = 0;\n                for (var i = 0; i < 100; ++i)\n                {\n                    var finish = false;\n                    foreach (var p in _time_2_key)\n                    {\n                        if ((now - p.Key).TotalSeconds < _sweep_time)\n                        {\n                            finish = true;\n                            break;\n                        }\n                        _key_2_time.Remove(p.Value);\n                        _time_2_key.Remove(p.Key);\n                        _store.Remove(p.Value);\n                        Logging.Debug(\"sweep [\" + p.Key + \"]: \" + p.Value);\n                        sweep += 1;\n                        break;\n                    }\n                    if (finish)\n                    {\n                        break;\n                    }\n                }\n                if (sweep > 0)\n                {\n                    Logging.Debug(\"sweep \" + sweep + \" items\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/MinSearchTree.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Model\n{\n    public struct MinSearchTreeNode\n    {\n        public int range_min;\n        public int range_max;\n        public int count;\n        public long min;\n    }\n\n    public class MinSearchTree\n    {\n        protected int _count;\n        protected int _size;\n        protected int _level;\n        protected MinSearchTreeNode[] _tree;\n\n        public MinSearchTree(int size)\n        {\n            _level = GetLevel(size);\n            _size = size;\n            _count = size + (1 << _level);\n            _tree = new MinSearchTreeNode[2 << _level];\n        }\n\n        public int Size => _size;\n\n        protected int GetLevel(int size)\n        {\n            var ret = 0;\n            for (var s = size; s > 1; s >>= 1)\n            {\n                ret++;\n            }\n            if (size != 1 << ret)\n            {\n                ++ret;\n            }\n\n            return ret;\n        }\n\n        protected void _Init(int index, int level, int range_min, int range_max)\n        {\n            _tree[index].range_min = range_min;\n            _tree[index].range_max = range_max;\n            _tree[index].min = 0;\n            _tree[index].count = range_max - range_min;\n            if (level >= 0)\n            {\n                var l = index * 2;\n                var r = l + 1;\n                _Init(l, level - 1, range_min, range_min + (1 << level));\n                _Init(r, level - 1, range_min + (1 << level), range_max);\n            }\n        }\n\n        public void Init()\n        {\n            _Init(1, _level - 1, 0, _size);\n            for (var i = _count; i < 2 << _level; ++i)\n            {\n                _tree[i].min = long.MaxValue;\n            }\n            var offset = 1 << _level;\n            for (var i = _count >> 1; i < offset; ++i)\n            {\n                Maintain(i);\n            }\n        }\n\n        public MinSearchTree Clone()\n        {\n            var tree = new MinSearchTree(_size);\n            for (var i = 0; i < 2 << _level; ++i)\n            {\n                tree._tree[i] = _tree[i];\n            }\n            return tree;\n        }\n\n        public void Update(int[] add_list)\n        {\n            var offset = 1 << _level;\n            for (var i = 0; i < add_list.Length; ++i)\n            {\n                if (add_list[i] > 0)\n                {\n                    _tree[offset + i].min += add_list[i];\n                    add_list[i] = 0;\n                    Maintain((offset + i) >> 1);\n                }\n            }\n        }\n\n        public void Update(Dictionary<int, long> add_map)\n        {\n            var offset = 1 << _level;\n            foreach (var pair in add_map)\n            {\n                _tree[offset + pair.Key].min += pair.Value;\n                Maintain((offset + pair.Key) >> 1);\n            }\n            add_map.Clear();\n            if (_tree[1].min > int.MaxValue)\n            {\n                for (var i = 1; i < _tree.Length; ++i)\n                {\n                    _tree[i].min -= int.MaxValue;\n                }\n            }\n        }\n\n        protected void Maintain(int index)\n        {\n            for (; index > 0; index >>= 1)\n            {\n                var l = index * 2;\n                var r = l + 1;\n                var min = Math.Min(_tree[l].min, _tree[r].min);\n                var count = 0;\n                if (min == _tree[l].min)\n                {\n                    count += _tree[l].count;\n                }\n\n                if (min == _tree[r].min)\n                {\n                    count += _tree[r].count;\n                }\n\n                if (_tree[index].min == min && _tree[index].count == count)\n                {\n                    return;\n                }\n\n                _tree[index].min = min;\n                _tree[index].count = count;\n            }\n        }\n\n        public void Update(int index, int add = 1)\n        {\n            index = (1 << _level) + index;\n            _tree[index].min += add;\n            Maintain(index >> 1);\n        }\n\n        public int FindMinCount(int index, int range_min, int range_max, out long min_val)\n        {\n            if (range_min == _tree[index].range_min && range_max == _tree[index].range_max)\n            {\n                min_val = _tree[index].min;\n                return _tree[index].count;\n            }\n            var l = index * 2;\n            var r = l + 1;\n            var count = 0;\n            var sub_min_val = long.MaxValue;\n            if (_tree[l].range_max > range_min)\n            {\n                var cnt = FindMinCount(l, range_min, Math.Min(range_max, _tree[l].range_max), out var out_val);\n                if (out_val < sub_min_val)\n                {\n                    sub_min_val = out_val;\n                    count = cnt;\n                }\n                else if (out_val == sub_min_val)\n                {\n                    count += cnt;\n                }\n            }\n            if (_tree[r].range_min < range_max)\n            {\n                var cnt = FindMinCount(r, Math.Max(range_min, _tree[r].range_min), range_max, out var out_val);\n                if (out_val < sub_min_val)\n                {\n                    sub_min_val = out_val;\n                    count = cnt;\n                }\n                else if (out_val == sub_min_val)\n                {\n                    count += cnt;\n                }\n            }\n            min_val = sub_min_val;\n            return count;\n        }\n\n        public int FindNthMin(int index, int range_min, int range_max, int nth, long val)\n        {\n            if (_tree[index].range_min + 1 == _tree[index].range_max)\n            {\n                return index - (1 << _level);\n            }\n            var l = index * 2;\n            var r = l + 1;\n            if (_tree[l].range_max > range_min)\n            {\n                if (_tree[r].range_min < range_max)\n                {\n                    var cnt = FindMinCount(l, range_min, _tree[l].range_max, out var out_val);\n                    if (out_val != val)\n                    {\n                        cnt = 0;\n                    }\n\n                    if (cnt > nth)\n                    {\n                        return FindNthMin(l, range_min, _tree[l].range_max, nth, val);\n                    }\n\n                    return FindNthMin(r, _tree[r].range_min, range_max, nth - cnt, val);\n                }\n\n                return FindNthMin(l, Math.Max(range_min, _tree[l].range_min), range_max, nth, val);\n            }\n\n            return FindNthMin(r, range_min, Math.Min(range_max, _tree[r].range_max), nth, val);\n        }\n\n        public int FindMinCount2(int index, int range_min, int range_max, out long min_val)\n        {\n            var offset = 1 << _level;\n            var min = long.MaxValue;\n            var cnt = 0;\n            for (var i = range_min; i < range_max; ++i)\n            {\n                if (_tree[offset + i].min < min)\n                {\n                    min = _tree[offset + i].min;\n                }\n            }\n            for (var i = range_min; i < range_max; ++i)\n            {\n                if (_tree[offset + i].min == min)\n                {\n                    ++cnt;\n                }\n            }\n            min_val = min;\n            return cnt;\n        }\n\n        public int FindNthMin2(int range_min, int range_max, int nth)\n        {\n            var offset = 1 << _level;\n            var min = long.MaxValue;\n            var cnt = 0;\n            for (var i = range_min; i < range_max; ++i)\n            {\n                if (_tree[offset + i].min < min)\n                {\n                    min = _tree[offset + i].min;\n                }\n            }\n            for (var i = range_min; i < range_max; ++i)\n            {\n                if (_tree[offset + i].min == min)\n                {\n                    if (cnt == nth)\n                    {\n                        return i;\n                    }\n\n                    ++cnt;\n                }\n            }\n            return -1;\n        }\n\n        public int RandomFindIndex(int range_min, int range_max, Random random)\n        {\n            var count = FindMinCount(1, range_min, range_max, out var out_val);\n            var nth = random.Next(count);\n            var index = FindNthMin(1, range_min, range_max, nth, out_val);\n            return index;\n        }\n\n        public long GetMin(int range_min, int range_max)\n        {\n            FindMinCount(1, range_min, range_max, out var ret);\n            return ret;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/PortMapConfig.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.ViewModel;\nusing System;\n\nnamespace Shadowsocks.Model\n{\n    [Serializable]\n    public class PortMapConfig : ViewModelBase\n    {\n        #region private\n\n        private bool _enable;\n        private PortMapType _type;\n        private string _id;\n        private string _serverAddr;\n        private int _serverPort;\n        private string _remarks;\n\n        #endregion\n\n        #region public\n\n        public bool Enable\n        {\n            get => _enable;\n            set => SetField(ref _enable, value);\n        }\n\n        public PortMapType Type\n        {\n            get => _type;\n            set => SetField(ref _type, value);\n        }\n\n        public string Id\n        {\n            get => _id;\n            set => SetField(ref _id, value);\n        }\n\n        public string Server_addr\n        {\n            get => _serverAddr;\n            set => SetField(ref _serverAddr, value);\n        }\n\n        public int Server_port\n        {\n            get => _serverPort;\n            set => SetField(ref _serverPort, value);\n        }\n\n        public string Remarks\n        {\n            get => _remarks;\n            set => SetField(ref _remarks, value);\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/PortMapConfigCache.cs",
    "content": "using Shadowsocks.Enums;\n\nnamespace Shadowsocks.Model\n{\n    public class PortMapConfigCache\n    {\n        public PortMapType type;\n        public string id;\n        public Server server;\n        public string server_addr;\n        public int server_port;\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/Rule.cs",
    "content": "namespace Shadowsocks.Model\n{\n    public enum Rule : byte\n    {\n        Unknown,\n        Block,\n        Direct,\n        Proxy\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/Server.cs",
    "content": "using Shadowsocks.Model.Transfer;\r\nusing Shadowsocks.Util;\r\nusing Shadowsocks.ViewModel;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.Text.Json.Serialization;\r\nusing System.Text.RegularExpressions;\r\n\r\nnamespace Shadowsocks.Model\r\n{\r\n    [Serializable]\r\n    public class Server : ViewModelBase, ICloneable\r\n    {\r\n        #region private\r\n\r\n        private string _id;\r\n        private string _server;\r\n        private ushort _serverPort;\r\n        private ushort _serverUdpPort;\r\n        private string _password;\r\n        private string _method;\r\n        private string _protocol;\r\n        private string _protocolParam;\r\n        private string _obfs;\r\n        private string _obfsParam;\r\n        private string _remarksBase64;\r\n        private string _group;\r\n        private string _subTag;\r\n        private bool _enable;\r\n        private bool _udpOverTcp;\r\n\r\n        #endregion\r\n\r\n        #region Public\r\n\r\n        public string Id\r\n        {\r\n            get => _id;\r\n            set => SetField(ref _id, value);\r\n        }\r\n\r\n        public string server\r\n        {\r\n            get => _server;\r\n            set\r\n            {\r\n                if (SetField(ref _server, value))\r\n                {\r\n                    OnPropertyChanged(nameof(FriendlyName));\r\n                }\r\n            }\r\n        }\r\n\r\n        public ushort Server_Port\r\n        {\r\n            get => _serverPort;\r\n            set\r\n            {\r\n                if (SetField(ref _serverPort, value))\r\n                {\r\n                    OnPropertyChanged(nameof(FriendlyName));\r\n                }\r\n            }\r\n        }\r\n\r\n        public ushort Server_Udp_Port\r\n        {\r\n            get => _serverUdpPort;\r\n            set\r\n            {\r\n                if (SetField(ref _serverUdpPort, value))\r\n                {\r\n                    OnPropertyChanged(nameof(FriendlyName));\r\n                }\r\n            }\r\n        }\r\n\r\n        public string Password\r\n        {\r\n            get => _password;\r\n            set => SetField(ref _password, value);\r\n        }\r\n\r\n        public string Method\r\n        {\r\n            get => string.IsNullOrWhiteSpace(_method) ? @\"aes-256-cfb\" : _method;\r\n            set => SetField(ref _method, value);\r\n        }\r\n\r\n        public string Protocol\r\n        {\r\n            get => string.IsNullOrWhiteSpace(_protocol) ? @\"origin\" : _protocol;\r\n            set => SetField(ref _protocol, value);\r\n        }\r\n\r\n        public string ProtocolParam\r\n        {\r\n            get => _protocolParam ?? string.Empty;\r\n            set => SetField(ref _protocolParam, value);\r\n        }\r\n\r\n        public string obfs\r\n        {\r\n            get => string.IsNullOrWhiteSpace(_obfs) ? @\"plain\" : _obfs;\r\n            set => SetField(ref _obfs, value);\r\n        }\r\n\r\n        public string ObfsParam\r\n        {\r\n            get => _obfsParam ?? string.Empty;\r\n            set => SetField(ref _obfsParam, value);\r\n        }\r\n\r\n        public string Remarks_Base64\r\n        {\r\n            get => _remarksBase64;\r\n            set\r\n            {\r\n                if (SetField(ref _remarksBase64, value))\r\n                {\r\n                    OnPropertyChanged(nameof(Remarks));\r\n                    OnPropertyChanged(nameof(FriendlyName));\r\n                }\r\n            }\r\n        }\r\n\r\n        public string Group\r\n        {\r\n            get => _group;\r\n            set\r\n            {\r\n                if (SetField(ref _group, value))\r\n                {\r\n                    OnPropertyChanged(nameof(GroupName));\r\n                }\r\n            }\r\n        }\r\n\r\n        public string SubTag\r\n        {\r\n            get => _subTag;\r\n            set => SetField(ref _subTag, value);\r\n        }\r\n\r\n        public bool Enable\r\n        {\r\n            get => _enable;\r\n            set => SetField(ref _enable, value);\r\n        }\r\n\r\n        public bool UdpOverTcp\r\n        {\r\n            get => _udpOverTcp;\r\n            set\r\n            {\r\n                if (SetField(ref _udpOverTcp, value))\r\n                {\r\n                    OnPropertyChanged(nameof(ShowAdvSetting));\r\n                }\r\n            }\r\n        }\r\n\r\n        #endregion\r\n\r\n        #region NotConfig\r\n\r\n        private int _index;\r\n        private bool _isSelected;\r\n        private ServerSpeedLog _serverSpeedLog;\r\n\r\n        [JsonIgnore]\r\n        public int Index\r\n        {\r\n            get => _index;\r\n            set => SetField(ref _index, value);\r\n        }\r\n\r\n        [JsonIgnore]\r\n        public bool IsSelected\r\n        {\r\n            get => _isSelected;\r\n            set => SetField(ref _isSelected, value);\r\n        }\r\n\r\n        [JsonIgnore]\r\n        public string GroupName => string.IsNullOrEmpty(Group) ? I18NUtil.GetAppStringValue(@\"EmptyGroup\") : Group;\r\n\r\n        [JsonIgnore]\r\n        public string Remarks\r\n        {\r\n            get\r\n            {\r\n                if (Remarks_Base64.Length == 0)\r\n                {\r\n                    return string.Empty;\r\n                }\r\n\r\n                try\r\n                {\r\n                    return Base64.DecodeUrlSafeBase64(Remarks_Base64);\r\n                }\r\n                catch (FormatException)\r\n                {\r\n                    var old = Remarks_Base64;\r\n                    Remarks = Remarks_Base64;\r\n                    return old;\r\n                }\r\n            }\r\n            set\r\n            {\r\n                var newValue = Base64.EncodeUrlSafeBase64(value);\r\n                if (newValue != Remarks_Base64)\r\n                {\r\n                    Remarks_Base64 = newValue;\r\n                }\r\n            }\r\n        }\r\n\r\n        [JsonIgnore]\r\n        public string FriendlyName\r\n        {\r\n            get\r\n            {\r\n                if (string.IsNullOrEmpty(server))\r\n                {\r\n                    return I18NUtil.GetAppStringValue(@\"NewServer\");\r\n                }\r\n\r\n                if (string.IsNullOrEmpty(Remarks))\r\n                {\r\n                    if (server.IndexOf(':') >= 0)\r\n                    {\r\n                        return $@\"[{server}]:{Server_Port}\";\r\n                    }\r\n\r\n                    return $@\"{server}:{Server_Port}\";\r\n                }\r\n\r\n                return $@\"{Remarks}\";\r\n            }\r\n        }\r\n\r\n        [JsonIgnore]\r\n        public string SsLink\r\n        {\r\n            get\r\n            {\r\n                var parts = $@\"{Method}:{Password}@{server}:{Server_Port}\";\r\n                var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts)).Replace(@\"=\", string.Empty);\r\n                return $@\"ss://{base64}\";\r\n            }\r\n        }\r\n\r\n        [JsonIgnore]\r\n        public string SsrLink\r\n        {\r\n            get\r\n            {\r\n                var mainPart = $@\"{server}:{Server_Port}:{Protocol}:{Method}:{obfs}:{Base64.EncodeUrlSafeBase64(Password)}\";\r\n                var paramStr = $@\"obfsparam={Base64.EncodeUrlSafeBase64(ObfsParam)}\";\r\n                if (!string.IsNullOrEmpty(ProtocolParam))\r\n                {\r\n                    paramStr += $@\"&protoparam={Base64.EncodeUrlSafeBase64(ProtocolParam)}\";\r\n                }\r\n\r\n                if (!string.IsNullOrEmpty(Remarks))\r\n                {\r\n                    paramStr += $@\"&remarks={Base64.EncodeUrlSafeBase64(Remarks)}\";\r\n                }\r\n\r\n                if (!string.IsNullOrEmpty(Group))\r\n                {\r\n                    paramStr += $@\"&group={Base64.EncodeUrlSafeBase64(Group)}\";\r\n                }\r\n\r\n                if (UdpOverTcp)\r\n                {\r\n                    paramStr += @\"&uot=1\";\r\n                }\r\n\r\n                if (Server_Udp_Port > 0)\r\n                {\r\n                    paramStr += $@\"&udpport={Server_Udp_Port}\";\r\n                }\r\n\r\n                var base64 = Base64.EncodeUrlSafeBase64($@\"{mainPart}/?{paramStr}\");\r\n                return $@\"ssr://{base64}\";\r\n            }\r\n        }\r\n\r\n        [JsonIgnore]\r\n        public bool ShowAdvSetting => UdpOverTcp || Server_Udp_Port != 0;\r\n\r\n        [JsonIgnore]\r\n        public object ProtocolData { get; set; }\r\n\r\n        [JsonIgnore]\r\n        public object ObfsData { get; set; }\r\n\r\n        [JsonIgnore]\r\n        public ServerSpeedLog SpeedLog\r\n        {\r\n            get => _serverSpeedLog;\r\n            set => SetField(ref _serverSpeedLog, value);\r\n        }\r\n\r\n        [JsonIgnore]\r\n        public Connections Connections { get; private set; } = new();\r\n\r\n        [JsonIgnore]\r\n        public DnsBuffer DnsBuffer { get; private set; } = new();\r\n\r\n        [JsonIgnore]\r\n        public static Server ForwardServer { get; } = new();\r\n\r\n        #endregion\r\n\r\n        public void CopyServer(Server oldServer)\r\n        {\r\n            ProtocolData = oldServer.ProtocolData;\r\n            ObfsData = oldServer.ObfsData;\r\n            SpeedLog = oldServer.SpeedLog;\r\n            DnsBuffer = oldServer.DnsBuffer;\r\n            Connections = oldServer.Connections;\r\n            Enable = oldServer.Enable;\r\n        }\r\n\r\n        public object Clone()\r\n        {\r\n            return new Server\r\n            {\r\n                server = server,\r\n                Server_Port = Server_Port,\r\n                Password = Password,\r\n                Method = Method,\r\n                Protocol = Protocol,\r\n                obfs = obfs,\r\n                ObfsParam = ObfsParam,\r\n                Remarks_Base64 = Remarks_Base64,\r\n                Group = Group,\r\n                Enable = Enable,\r\n                UdpOverTcp = UdpOverTcp,\r\n\r\n                Id = Id,\r\n                ProtocolData = ProtocolData,\r\n                ObfsData = ObfsData\r\n            };\r\n        }\r\n\r\n        public static Server Clone(Server serverObject)\r\n        {\r\n            return new()\r\n            {\r\n                server = serverObject.server,\r\n                Server_Port = serverObject.Server_Port,\r\n                Server_Udp_Port = serverObject.Server_Udp_Port,\r\n                Password = serverObject.Password,\r\n                Method = serverObject.Method,\r\n                Protocol = serverObject.Protocol,\r\n                ProtocolParam = serverObject.ProtocolParam,\r\n                obfs = serverObject.obfs,\r\n                ObfsParam = serverObject.ObfsParam,\r\n                Remarks = serverObject.Remarks,\r\n                Group = serverObject.Group,\r\n                UdpOverTcp = serverObject.UdpOverTcp\r\n            };\r\n        }\r\n\r\n        public Server()\r\n        {\r\n            server = @\"server host\";\r\n            Server_Port = 8388;\r\n            Method = @\"aes-256-cfb\";\r\n            Protocol = @\"origin\";\r\n            ProtocolParam = @\"\";\r\n            obfs = @\"plain\";\r\n            ObfsParam = @\"\";\r\n            Password = @\"0\";\r\n            Remarks_Base64 = @\"\";\r\n            Group = @\"Default Group\";\r\n            SubTag = @\"\";\r\n            UdpOverTcp = false;\r\n            Enable = true;\r\n            Id = Guid.NewGuid().ToString(@\"N\");\r\n            SpeedLog = new ServerSpeedLog();\r\n            Index = 0;\r\n            IsSelected = false;\r\n        }\r\n\r\n        public Server(string ssUrl, string forceGroup) : this()\r\n        {\r\n            if (ssUrl.StartsWith(@\"ss://\", StringComparison.OrdinalIgnoreCase))\r\n            {\r\n                ServerFromSs(ssUrl, forceGroup);\r\n            }\r\n            else if (ssUrl.StartsWith(@\"ssr://\", StringComparison.OrdinalIgnoreCase))\r\n            {\r\n                ServerFromSsr(ssUrl, forceGroup);\r\n            }\r\n            else\r\n            {\r\n                throw new FormatException();\r\n            }\r\n        }\r\n\r\n        private static Dictionary<string, string> ParseParam(string paramStr)\r\n        {\r\n            var paramsDict = new Dictionary<string, string>();\r\n            var obfsParams = paramStr.Split('&');\r\n            foreach (var p in obfsParams)\r\n            {\r\n                if (p.IndexOf('=') > 0)\r\n                {\r\n                    var index = p.IndexOf('=');\r\n                    var key = p.Substring(0, index);\r\n                    var val = p.Substring(index + 1);\r\n                    paramsDict[key] = val;\r\n                }\r\n            }\r\n            return paramsDict;\r\n        }\r\n\r\n        public void ServerFromSsr(string ssrUrl, string forceGroup)\r\n        {\r\n            // ssr://host:port:protocol:method:obfs:base64pass/?obfsparam=base64&remarks=base64&group=base64&udpport=0&uot=1\r\n            var ssr = Regex.Match(ssrUrl, \"ssr://([A-Za-z0-9+/=_-]+)\", RegexOptions.IgnoreCase);\r\n            if (!ssr.Success)\r\n            {\r\n                throw new FormatException();\r\n            }\r\n\r\n            var data = Base64.DecodeUrlSafeBase64(ssr.Groups[1].Value);\r\n            var params_dict = new Dictionary<string, string>();\r\n\r\n            var param_start_pos = data.IndexOf(\"?\", StringComparison.Ordinal);\r\n            if (param_start_pos > 0)\r\n            {\r\n                params_dict = ParseParam(data.Substring(param_start_pos + 1));\r\n                data = data.Substring(0, param_start_pos);\r\n            }\r\n            if (data.IndexOf(\"/\", StringComparison.Ordinal) >= 0)\r\n            {\r\n                data = data.Substring(0, data.LastIndexOf(\"/\", StringComparison.Ordinal));\r\n            }\r\n\r\n            var UrlFinder = new Regex(\"^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)\");\r\n            var match = UrlFinder.Match(data);\r\n\r\n            if (match == null || !match.Success)\r\n            {\r\n                throw new FormatException();\r\n            }\r\n\r\n            server = match.Groups[1].Value;\r\n            Server_Port = ushort.Parse(match.Groups[2].Value);\r\n            Protocol = match.Groups[3].Value.Length == 0 ? \"origin\" : match.Groups[3].Value;\r\n            Protocol = Protocol.Replace(\"_compatible\", \"\");\r\n            Method = match.Groups[4].Value;\r\n            obfs = match.Groups[5].Value.Length == 0 ? \"plain\" : match.Groups[5].Value;\r\n            obfs = obfs.Replace(\"_compatible\", \"\");\r\n            Password = Base64.DecodeUrlSafeBase64(match.Groups[6].Value);\r\n\r\n            if (params_dict.ContainsKey(\"protoparam\"))\r\n            {\r\n                ProtocolParam = Base64.DecodeUrlSafeBase64(params_dict[\"protoparam\"]);\r\n            }\r\n            if (params_dict.ContainsKey(\"obfsparam\"))\r\n            {\r\n                ObfsParam = Base64.DecodeUrlSafeBase64(params_dict[\"obfsparam\"]);\r\n            }\r\n            if (params_dict.ContainsKey(\"remarks\"))\r\n            {\r\n                Remarks = Base64.DecodeUrlSafeBase64(params_dict[\"remarks\"]);\r\n            }\r\n            Group = params_dict.ContainsKey(\"group\") ? Base64.DecodeUrlSafeBase64(params_dict[\"group\"]) : string.Empty;\r\n\r\n            if (params_dict.ContainsKey(\"uot\"))\r\n            {\r\n                UdpOverTcp = int.Parse(params_dict[\"uot\"]) != 0;\r\n            }\r\n            if (params_dict.ContainsKey(\"udpport\"))\r\n            {\r\n                Server_Udp_Port = ushort.Parse(params_dict[\"udpport\"]);\r\n            }\r\n            if (!string.IsNullOrEmpty(forceGroup))\r\n            {\r\n                SubTag = forceGroup;\r\n            }\r\n        }\r\n\r\n        private void ServerFromSs(string ssUrl, string forceGroup)\r\n        {\r\n            Regex UrlFinder = new(\"^(?i)ss://([A-Za-z0-9+-/=_]+)(#(.+))?\", RegexOptions.IgnoreCase),\r\n                DetailsParser = new(\"^((?<method>.+):(?<password>.*)@(?<hostname>.+?)\" +\r\n                                    \":(?<port>\\\\d+?))$\", RegexOptions.IgnoreCase);\r\n\r\n            var match = UrlFinder.Match(ssUrl);\r\n            if (!match.Success)\r\n            {\r\n                throw new FormatException();\r\n            }\r\n\r\n            var base64 = match.Groups[1].Value;\r\n            match = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String(\r\n                base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '='))));\r\n            Protocol = \"origin\";\r\n            Method = match.Groups[\"method\"].Value;\r\n            Password = match.Groups[\"password\"].Value;\r\n            server = match.Groups[\"hostname\"].Value;\r\n            Server_Port = ushort.Parse(match.Groups[\"port\"].Value);\r\n            SubTag = !string.IsNullOrEmpty(forceGroup) ? forceGroup : string.Empty;\r\n        }\r\n\r\n        public bool IsMatchServer(Server serverObject)\r\n        {\r\n            return server == serverObject.server\r\n                   && Server_Port == serverObject.Server_Port\r\n                   && Server_Udp_Port == serverObject.Server_Udp_Port\r\n                   && Method == serverObject.Method\r\n                   && Protocol == serverObject.Protocol\r\n                   && ProtocolParam == serverObject.ProtocolParam\r\n                   && obfs == serverObject.obfs\r\n                   && ObfsParam == serverObject.ObfsParam\r\n                   && Password == serverObject.Password\r\n                   && UdpOverTcp == serverObject.UdpOverTcp\r\n                   && Remarks == serverObject.Remarks\r\n                   && Group == serverObject.Group;\r\n        }\r\n\r\n        public event EventHandler ServerChanged;\r\n\r\n        protected override bool SetField<T>(ref T field, T value, string propertyName = @\"\")\r\n        {\r\n            if (base.SetField(ref field, value, propertyName))\r\n            {\r\n                OnPropertyChanged(nameof(SsLink));\r\n                OnPropertyChanged(nameof(SsrLink));\r\n                ServerChanged?.Invoke(this, EventArgs.Empty);\r\n                return true;\r\n            }\r\n            return false;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Model/ServerSelectStrategy.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Model.Transfer;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Model\n{\n    public class ServerSelectStrategy\n    {\n        public delegate bool FilterFunc(Server server, Server selServer); // return true if select the server\n        private Random randomGennarator;\n        private int lastSelectIndex;\n        private string lastSelectID;\n        private DateTime lastSelectTime;\n        private int lastUserSelectIndex;\n        private const int MAX_CHANCE = 10000;\n        private const int ERROR_PENALTY = MAX_CHANCE / 20;\n        private const int CONNECTION_PENALTY = MAX_CHANCE / 100;\n        private const int MIN_CHANCE = 10;\n\n        private struct ServerIndex\n        {\n            public int index;\n            public Server server;\n            public ServerIndex(int i, Server s)\n            {\n                index = i;\n                server = s;\n            }\n        }\n        private int lowerBound(List<double> data, double target)\n        {\n            var left = 0;\n            var right = data.Count - 1;\n            while (left < right)\n            {\n                var mid = (left + right) / 2;\n                if (data[mid] >= target)\n                {\n                    right = mid;\n                }\n                else if (data[mid] < target)\n                {\n                    left = mid + 1;\n                }\n            }\n            return left;\n        }\n\n        private double Algorithm2(ServerSpeedLog serverSpeedLog) // perfer less delay\n        {\n            if (serverSpeedLog.ErrorContinuousTimes >= 20)\n            {\n                return 1;\n            }\n\n            if (serverSpeedLog.ErrorContinuousTimes >= 10)\n            {\n                return MIN_CHANCE;\n            }\n\n            if (serverSpeedLog.AvgConnectTime < 0 && serverSpeedLog.TotalConnectTimes >= 3)\n            {\n                return MIN_CHANCE;\n            }\n\n            if (serverSpeedLog.TotalConnectTimes < 1)\n            {\n                return MAX_CHANCE;\n            }\n\n            long avgConnectTime = serverSpeedLog.AvgConnectTime <= 0 ? 1 : serverSpeedLog.AvgConnectTime;\n            if (serverSpeedLog.TotalConnectTimes >= 1 && serverSpeedLog.AvgConnectTime < 0)\n            {\n                avgConnectTime = 5000;\n            }\n\n            var connections = serverSpeedLog.TotalConnectTimes - serverSpeedLog.TotalDisconnectTimes;\n            var chance = MAX_CHANCE * 10.0 / avgConnectTime - connections * CONNECTION_PENALTY;\n            if (chance > MAX_CHANCE)\n            {\n                chance = MAX_CHANCE;\n            }\n\n            chance -= serverSpeedLog.ErrorContinuousTimes * ERROR_PENALTY;\n            if (chance < MIN_CHANCE)\n            {\n                chance = MIN_CHANCE;\n            }\n\n            return chance;\n        }\n\n        private double Algorithm3(ServerSpeedLog serverSpeedLog) // perfer less error\n        {\n            if (serverSpeedLog.ErrorContinuousTimes >= 20)\n            {\n                return 1;\n            }\n\n            if (serverSpeedLog.ErrorContinuousTimes >= 10)\n            {\n                return MIN_CHANCE;\n            }\n\n            if (serverSpeedLog.AvgConnectTime < 0 && serverSpeedLog.TotalConnectTimes >= 3)\n            {\n                return MIN_CHANCE;\n            }\n\n            if (serverSpeedLog.TotalConnectTimes < 1)\n            {\n                return MAX_CHANCE;\n            }\n\n            long avgConnectTime = serverSpeedLog.AvgConnectTime <= 0 ? 1 : serverSpeedLog.AvgConnectTime / 1000 * 1000;\n            if (serverSpeedLog.TotalConnectTimes >= 1 && serverSpeedLog.AvgConnectTime < 0)\n            {\n                avgConnectTime = 5000;\n            }\n\n            var connections = serverSpeedLog.TotalConnectTimes - serverSpeedLog.TotalDisconnectTimes;\n            var chance = MAX_CHANCE * 1.0 / (avgConnectTime / 500 + 1) - connections * CONNECTION_PENALTY;\n            if (chance > MAX_CHANCE)\n            {\n                chance = MAX_CHANCE;\n            }\n\n            chance -= serverSpeedLog.ErrorContinuousTimes * ERROR_PENALTY;\n            if (chance < MIN_CHANCE)\n            {\n                chance = MIN_CHANCE;\n            }\n\n            return chance;\n        }\n\n        private double Algorithm4(ServerSpeedLog serverSpeedLog, long avg_speed, double zero_chance) // perfer fast speed\n        {\n            if (serverSpeedLog.ErrorContinuousTimes >= 20)\n            {\n                return 1;\n            }\n\n            if (serverSpeedLog.ErrorContinuousTimes >= 10)\n            {\n                return MIN_CHANCE;\n            }\n\n            if (serverSpeedLog.AvgConnectTime < 0 && serverSpeedLog.TotalConnectTimes >= 3)\n            {\n                return MIN_CHANCE;\n            }\n\n            if (serverSpeedLog.TotalConnectTimes < 1)\n            {\n                return MAX_CHANCE;\n            }\n\n            long avgConnectTime = serverSpeedLog.AvgConnectTime <= 0 ? 1 : serverSpeedLog.AvgConnectTime / 2000 * 2000;\n            serverSpeedLog.GetTransSpeed(out _, out var speed_d);\n            if (serverSpeedLog.TotalConnectTimes >= 1 && serverSpeedLog.AvgConnectTime < 0)\n            {\n                avgConnectTime = 5000;\n            }\n\n            var speed_mul = speed_d > avg_speed ? 1.0 :\n                    speed_d == 0 ? zero_chance :\n                    speed_d < avg_speed / 2 ? 0.001 : 0.005;\n            var connections = serverSpeedLog.TotalConnectTimes - serverSpeedLog.TotalDisconnectTimes;\n            var chance = MAX_CHANCE * speed_mul / (avgConnectTime / 500 + 1) - connections * CONNECTION_PENALTY;\n            if (chance > MAX_CHANCE)\n            {\n                chance = MAX_CHANCE;\n            }\n\n            chance -= serverSpeedLog.ErrorContinuousTimes * ERROR_PENALTY;\n            if (chance < MIN_CHANCE)\n            {\n                chance = MIN_CHANCE;\n            }\n\n            return chance;\n        }\n\n        protected int SubSelect(IList<Server> configs, int curIndex, BalanceType algorithm, FilterFunc filter, bool forceChange)\n        {\n            if (randomGennarator == null)\n            {\n                randomGennarator = new Random();\n                lastSelectIndex = -1;\n            }\n            if (configs.Count <= lastSelectIndex || lastSelectIndex < 0)\n            {\n                lastSelectIndex = -1;\n                lastSelectTime = DateTime.Now;\n                lastUserSelectIndex = -1;\n            }\n            else\n            {\n                if (configs[lastSelectIndex].Id != lastSelectID)\n                {\n                    if (lastSelectID != null)\n                    {\n                        for (var i = 0; i < configs.Count; ++i)\n                        {\n                            if (configs[i].Id == lastSelectID)\n                            {\n                                lastSelectIndex = i;\n                                break;\n                            }\n                        }\n                    }\n                    if (configs[lastSelectIndex].Id != lastSelectID)\n                    {\n                        lastSelectIndex = -1;\n                        lastSelectTime = DateTime.Now;\n                        lastUserSelectIndex = -1;\n                    }\n                }\n            }\n            if (lastUserSelectIndex != curIndex)\n            {\n                if (configs.Count > curIndex && curIndex >= 0 && algorithm != BalanceType.Timer)\n                {\n                    lastSelectIndex = curIndex;\n                }\n                lastUserSelectIndex = curIndex;\n            }\n            if (lastSelectIndex == -1)\n            {\n                if (configs.Count > curIndex && curIndex >= 0)\n                {\n                    lastSelectIndex = curIndex;\n                }\n            }\n            if (configs.Count > 0)\n            {\n                var serverList = new List<ServerIndex>();\n                for (var i = 0; i < configs.Count; ++i)\n                {\n                    if (configs[i].Enable)\n                    {\n                        if (filter != null)\n                        {\n                            if (!filter(configs[i], lastSelectIndex < 0 ? null : configs[lastSelectIndex]))\n                            {\n                                continue;\n                            }\n                        }\n                        serverList.Add(new ServerIndex(i, configs[i]));\n                    }\n                }\n                if (serverList.Count == 0 && filter != null)\n                {\n                    for (var i = 0; i < configs.Count; ++i)\n                    {\n                        if (!filter(configs[i], lastSelectIndex < 0 ? null : configs[lastSelectIndex]))\n                        {\n                            continue;\n                        }\n\n                        serverList.Add(new ServerIndex(i, configs[i]));\n                    }\n                }\n                if (forceChange && serverList.Count > 1 && algorithm != BalanceType.OneByOne)\n                {\n                    for (var i = 0; i < serverList.Count; ++i)\n                    {\n                        if (serverList[i].index == lastSelectIndex)\n                        {\n                            serverList.RemoveAt(i);\n                            break;\n                        }\n                    }\n                }\n                if (serverList.Count == 0)\n                {\n                    var i = lastSelectIndex;\n                    if (i >= 0 && i < configs.Count && configs[i].Enable)\n                    {\n                        serverList.Add(new ServerIndex(i, configs[i]));\n                    }\n                }\n                var serverListIndex = -1;\n                if (serverList.Count > 0)\n                {\n                    if (algorithm == BalanceType.OneByOne)\n                    {\n                        var selIndex = -1;\n                        for (var i = 0; i < serverList.Count; ++i)\n                        {\n                            if (serverList[i].index == lastSelectIndex)\n                            {\n                                selIndex = i;\n                                break;\n                            }\n                        }\n                        serverListIndex = serverList[(selIndex + 1) % serverList.Count].index;\n                    }\n                    else if (algorithm == BalanceType.Random)\n                    {\n                        serverListIndex = randomGennarator.Next(serverList.Count);\n                        serverListIndex = serverList[serverListIndex].index;\n                    }\n                    else if (algorithm is BalanceType.LowException\n                        or BalanceType.Timer\n                        or BalanceType.FastDownloadSpeed)\n                    {\n                        if (algorithm == BalanceType.Timer)\n                        {\n                            if ((DateTime.Now - lastSelectTime).TotalSeconds > 60 * 5)\n                            {\n                                lastSelectTime = DateTime.Now;\n                            }\n                            else\n                            {\n                                if (configs.Count > lastSelectIndex && lastSelectIndex >= 0 && configs[lastSelectIndex].Enable && !forceChange)\n                                {\n                                    return lastSelectIndex;\n                                }\n                            }\n                        }\n                        var chances = new List<double>();\n                        double lastBeginVal = 0;\n                        if (algorithm == BalanceType.FastDownloadSpeed)\n                        {\n                            long avg_speed = 1024 * 64;\n                            long sum_speed = 0;\n                            var sum_cnt = 0;\n                            var zero_cnt = 0;\n                            foreach (var s in serverList)\n                            {\n                                s.server.SpeedLog.GetTransSpeed(out _, out var speed_d);\n                                if (speed_d == 0)\n                                {\n                                    ++zero_cnt;\n                                }\n                                else\n                                {\n                                    sum_speed += speed_d;\n                                    ++sum_cnt;\n                                }\n                            }\n                            var zero_chance = 0.5;\n                            if (sum_cnt > 0)\n                            {\n                                avg_speed = sum_speed / sum_cnt;\n                                if (zero_cnt + sum_cnt > 0)\n                                {\n                                    zero_chance = 0.1 * sum_cnt / (zero_cnt + sum_cnt);\n                                }\n                            }\n                            foreach (var s in serverList)\n                            {\n                                var chance = Algorithm4(s.server.SpeedLog, avg_speed, zero_chance);\n                                if (chance > 0)\n                                {\n                                    chances.Add(lastBeginVal + chance);\n                                    lastBeginVal += chance;\n                                }\n                            }\n                        }\n                        else\n                        {\n                            foreach (var s in serverList)\n                            {\n                                var chance = Algorithm3(s.server.SpeedLog);\n                                if (chance > 0)\n                                {\n                                    chances.Add(lastBeginVal + chance);\n                                    lastBeginVal += chance;\n                                }\n                            }\n                        }\n                        {\n                            var target = randomGennarator.NextDouble() * lastBeginVal;\n                            serverListIndex = lowerBound(chances, target);\n                            serverListIndex = serverList[serverListIndex].index;\n                            return serverListIndex;\n                        }\n                    }\n                    else //if (algorithm == (int)SelectAlgorithm.LowLatency || algorithm == (int)SelectAlgorithm.SelectedFirst)\n                    {\n                        var chances = new List<double>();\n                        double lastBeginVal = 0;\n                        foreach (var s in serverList)\n                        {\n                            var chance = Algorithm2(s.server.SpeedLog);\n                            if (chance > 0)\n                            {\n                                chances.Add(lastBeginVal + chance);\n                                lastBeginVal += chance;\n                            }\n                        }\n                        if (algorithm == BalanceType.SelectedFirst\n                            && randomGennarator.Next(3) == 0\n                            && configs[curIndex].Enable)\n                        {\n                            for (var i = 0; i < serverList.Count; ++i)\n                            {\n                                if (curIndex == serverList[i].index)\n                                {\n                                    return curIndex;\n                                }\n                            }\n                        }\n                        {\n                            var target = randomGennarator.NextDouble() * lastBeginVal;\n                            serverListIndex = lowerBound(chances, target);\n                            serverListIndex = serverList[serverListIndex].index;\n                            return serverListIndex;\n                        }\n                    }\n                }\n                return serverListIndex;\n            }\n\n            return -1;\n        }\n\n        public int Select(IList<Server> configs, int curIndex, BalanceType algorithm, FilterFunc filter, bool forceChange = false)\n        {\n            lastSelectIndex = SubSelect(configs, curIndex, algorithm, filter, forceChange);\n            if (lastSelectIndex >= 0 && lastSelectIndex < configs.Count)\n            {\n                lastSelectID = configs[lastSelectIndex].Id;\n            }\n            else\n            {\n                lastSelectID = null;\n            }\n            return lastSelectIndex;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/ServerSubscribe.cs",
    "content": "using Shadowsocks.Controller.HttpRequest;\nusing Shadowsocks.Encryption;\nusing Shadowsocks.Enums;\nusing Shadowsocks.ViewModel;\nusing System;\nusing System.Text;\nusing System.Text.Json.Serialization;\n\nnamespace Shadowsocks.Model\n{\n    [Serializable]\n    public class ServerSubscribe : ViewModelBase\n    {\n        private string _url;\n        private string _tag;\n        private long _lastUpdateTime;\n        private bool _autoCheckUpdate;\n        private HttpRequestProxyType _proxyType;\n\n        public ServerSubscribe()\n        {\n            _url = UpdateNode.DefaultUpdateUrl;\n            _autoCheckUpdate = true;\n            _proxyType = HttpRequestProxyType.Auto;\n        }\n\n        public string Url\n        {\n            get => _url;\n            set\n            {\n                if (SetField(ref _url, value))\n                {\n                    SubscribeChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        [JsonIgnore]\n        public string OriginTag => _tag;\n\n        [JsonIgnore]\n        public string UrlMd5 => BitConverter.ToString(CryptoUtils.MD5(Encoding.UTF8.GetBytes(Url))).Replace(@\"-\", string.Empty);\n\n        public string Tag\n        {\n            get => string.IsNullOrWhiteSpace(_tag) ? UrlMd5 : _tag;\n            set\n            {\n                if (UrlMd5 == value)\n                {\n                    value = string.Empty;\n                }\n                if (SetField(ref _tag, value))\n                {\n                    SubscribeChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public long LastUpdateTime\n        {\n            get => _lastUpdateTime;\n            set\n            {\n                if (SetField(ref _lastUpdateTime, value))\n                {\n                    SubscribeChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public bool AutoCheckUpdate\n        {\n            get => _autoCheckUpdate;\n            set\n            {\n                if (SetField(ref _autoCheckUpdate, value))\n                {\n                    SubscribeChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public HttpRequestProxyType ProxyType\n        {\n            get => _proxyType;\n            set\n            {\n                if (SetField(ref _proxyType, value))\n                {\n                    SubscribeChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public event EventHandler SubscribeChanged;\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/ServerTreeViewModel.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Util;\nusing Shadowsocks.ViewModel;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\n\nnamespace Shadowsocks.Model\n{\n    public class ServerTreeViewModel : ViewModelBase\n    {\n        public ServerTreeViewModel()\n        {\n            _nodes = new ObservableCollection<ServerTreeViewModel>();\n            _name = string.Empty;\n            _server = null;\n            _type = ServerTreeViewType.Subtag;\n        }\n\n        private string _name;\n        public string Name\n        {\n            get\n            {\n                switch (Type)\n                {\n                    case ServerTreeViewType.Subtag:\n                        if (string.IsNullOrEmpty(_name))\n                        {\n                            return I18NUtil.GetAppStringValue(@\"EmptySubtag\");\n                        }\n                        break;\n                    case ServerTreeViewType.Group:\n                        if (string.IsNullOrEmpty(_name))\n                        {\n                            return I18NUtil.GetAppStringValue(@\"EmptyGroup\");\n                        }\n                        break;\n                    case ServerTreeViewType.Server:\n                        if (Server != null)\n                        {\n                            return Server.FriendlyName;\n                        }\n                        break;\n                    default:\n                        throw new ArgumentOutOfRangeException(nameof(Type));\n                }\n                return _name;\n            }\n            set => SetField(ref _name, value);\n        }\n\n        private ObservableCollection<ServerTreeViewModel> _nodes;\n        public ObservableCollection<ServerTreeViewModel> Nodes\n        {\n            get => _nodes;\n            set => SetField(ref _nodes, value);\n        }\n\n        private ServerTreeViewType _type;\n        public ServerTreeViewType Type\n        {\n            get => _type;\n            set => SetField(ref _type, value);\n        }\n\n        private Server _server;\n        public Server Server\n        {\n            get => _server;\n            set\n            {\n                if (SetField(ref _server, value))\n                {\n                    _server.ServerChanged += Server_ServerChanged;\n                    OnPropertyChanged(nameof(Name));\n                }\n            }\n        }\n\n        private void Server_ServerChanged(object sender, EventArgs e)\n        {\n            OnPropertyChanged(nameof(Name));\n        }\n\n        #region Static Method\n\n        public static void Remove(ObservableCollection<ServerTreeViewModel> root, ServerTreeViewModel st)\n        {\n            if (root.Remove(st))\n            {\n                return;\n            }\n\n            foreach (var serverTreeViewModel in root)\n            {\n                Remove(serverTreeViewModel.Nodes, st);\n            }\n        }\n\n        public static ServerTreeViewModel FindParentNode(Collection<ServerTreeViewModel> root, ServerTreeViewModel st)\n        {\n            var res = root.Where(serverTreeViewModel => serverTreeViewModel.Nodes != null)\n                    .FirstOrDefault(serverTreeViewModel => serverTreeViewModel.Nodes.Contains(st));\n            if (res != null)\n            {\n                return res;\n            }\n\n            foreach (var serverTreeViewModel in root)\n            {\n                res = FindParentNode(serverTreeViewModel.Nodes, st);\n                if (res != null)\n                {\n                    return res;\n                }\n            }\n\n            return null;\n        }\n\n        public static ServerTreeViewModel FindNode(Collection<ServerTreeViewModel> root, string serverId)\n        {\n            var res = root.FirstOrDefault(serverTreeViewModel => serverTreeViewModel.Server?.Id == serverId);\n            if (res != null)\n            {\n                return res;\n            }\n\n            foreach (var serverTreeViewModel in root)\n            {\n                res = FindNode(serverTreeViewModel.Nodes, serverId);\n                if (res != null)\n                {\n                    return res;\n                }\n            }\n            return null;\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/Transfer/ServerSpeedLog.cs",
    "content": "using Shadowsocks.Util;\nusing Shadowsocks.ViewModel;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\n// ReSharper disable MemberCanBePrivate.Global\n\nnamespace Shadowsocks.Model.Transfer\n{\n    public class ServerSpeedLog : ViewModelBase\n    {\n        private long _totalConnectTimes;\n        private long _totalDisconnectTimes;\n        private long _errorConnectTimes;\n        private long _errorTimeoutTimes;\n        private long _errorDecodeTimes;\n        private long _errorEmptyTimes;\n        private long _errorContinuousTimes;\n        private long _transUpload;\n        private long _transDownload;\n        private long _transDownloadRaw;\n        private readonly List<TransLog> _downTransLog = new();\n        private readonly List<TransLog> _upTransLog = new();\n        private long _maxTransDownload;\n        private long _maxTransUpload;\n        private long _avgConnectTime = -1;\n        private readonly ConcurrentQueue<ErrorLog> _errList = new();\n\n        private const int AvgTime = 5;\n\n        public ServerSpeedLog() { }\n\n        public ServerSpeedLog(long upload, long download)\n        {\n            Interlocked.Exchange(ref _transUpload, upload);\n            Interlocked.Exchange(ref _transDownload, download);\n        }\n\n        public void GetTransSpeed(out long upload, out long download)\n        {\n            upload = MaxUpSpeed;\n            download = MaxDownSpeed;\n        }\n\n        /// <summary>\n        /// 总连接数\n        /// </summary>\n        public long TotalConnectTimes => Interlocked.Read(ref _totalConnectTimes);\n\n        public long TotalDisconnectTimes => Interlocked.Read(ref _totalDisconnectTimes);\n\n        /// <summary>\n        /// 连接数\n        /// </summary>\n        public long Connecting => TotalConnectTimes - TotalDisconnectTimes;\n\n        #region 下载速度\n\n        public long AvgDownloadBytes\n        {\n            get\n            {\n                List<TransLog> transLog;\n                lock (this)\n                {\n                    transLog = _downTransLog.ToList();\n                }\n                double totalTime = 0;\n                if (transLog.Count == 0 || transLog.Count > 0 &&\n                    DateTime.Now > transLog.Last().recvTime.AddSeconds(AvgTime))\n                {\n                    return 0;\n                }\n\n                var totalBytes = transLog.Aggregate<TransLog, long>(0, (current, t) => current + t.size);\n                totalBytes -= transLog[0].firstsize;\n\n                if (transLog.Count > 1)\n                {\n                    totalTime = (transLog.Last().endTime - transLog[0].recvTime).TotalSeconds;\n                }\n\n                if (totalTime > 0.2)\n                {\n                    var ret = (long)(totalBytes / totalTime);\n                    return ret;\n                }\n\n                return 0;\n            }\n        }\n\n        public string AvgDownloadBytesText => $@\"{Utils.FormatBytes(AvgDownloadBytes)}/s\";\n\n        #endregion\n\n        #region 上传速度\n\n        public long AvgUploadBytes\n        {\n            get\n            {\n                List<TransLog> transLog;\n                lock (this)\n                {\n                    transLog = _upTransLog.ToList();\n                }\n                double totalTime = 0;\n                if (transLog.Count == 0 || transLog.Count > 0 &&\n                    DateTime.Now > transLog.Last().recvTime.AddSeconds(AvgTime))\n                {\n                    return 0;\n                }\n\n                var totalBytes = transLog.Aggregate<TransLog, long>(0, (current, t) => current + t.size);\n                totalBytes -= transLog[0].firstsize;\n\n                if (transLog.Count > 1)\n                {\n                    totalTime = (transLog.Last().endTime - transLog[0].recvTime).TotalSeconds;\n                }\n\n                if (totalTime > 0.2)\n                {\n                    var ret = (long)(totalBytes / totalTime);\n                    return ret;\n                }\n\n                return 0;\n            }\n        }\n\n        public string AvgUploadBytesText => $@\"{Utils.FormatBytes(AvgUploadBytes)}/s\";\n\n        #endregion\n\n        #region 最大下载速度\n\n        public long MaxDownSpeed => Interlocked.Read(ref _maxTransDownload);\n\n        public string MaxDownSpeedText => $@\"{Utils.FormatBytes(MaxDownSpeed)}/s\";\n\n        #endregion\n\n        #region 最大上传速度\n\n        public long MaxUpSpeed => Interlocked.Read(ref _maxTransUpload);\n\n        public string MaxUpSpeedText => $@\"{Utils.FormatBytes(MaxUpSpeed)}/s\";\n\n        #endregion\n\n        #region 延迟\n\n        public long AvgConnectTime => Interlocked.Read(ref _avgConnectTime);\n\n        public long AvgConnectTimeText\n        {\n            get\n            {\n                if (AvgConnectTime > 0)\n                {\n                    return AvgConnectTime / 1000;\n                }\n\n                return 0;\n            }\n        }\n\n        #endregion\n\n        #region 总上传\n\n        public long TotalUploadBytes => Interlocked.Read(ref _transUpload);\n\n        public string TotalUploadBytesText => Utils.FormatBytes(TotalUploadBytes);\n\n        #endregion\n\n        #region 总下载\n\n        public long TotalDownloadBytes => Interlocked.Read(ref _transDownload);\n\n        public string TotalDownloadBytesText => Utils.FormatBytes(TotalDownloadBytes);\n\n        #endregion\n\n        #region 实下载\n\n        public long TotalDownloadRawBytes => Interlocked.Read(ref _transDownloadRaw);\n\n        public string TotalDownloadRawBytesText => Utils.FormatBytes(TotalDownloadRawBytes);\n\n        #endregion\n\n        /// <summary>\n        /// 错误\n        /// </summary>\n        public long ConnectError => ErrorConnectTimes + ErrorDecodeTimes;\n\n        public long ErrorConnectTimes => Interlocked.Read(ref _errorConnectTimes);\n\n        public long ErrorDecodeTimes => Interlocked.Read(ref _errorDecodeTimes);\n\n        /// <summary>\n        /// 连错\n        /// </summary>\n        public long ErrorContinuousTimes => Interlocked.Read(ref _errorContinuousTimes);\n\n        /// <summary>\n        /// 超时\n        /// </summary>\n        public long ErrorTimeoutTimes => Interlocked.Read(ref _errorTimeoutTimes);\n\n        /// <summary>\n        /// 空连\n        /// </summary>\n        public long ErrorEmptyTimes => Interlocked.Read(ref _errorEmptyTimes);\n\n        #region 出错比例\n\n        public double? ErrorPercent\n        {\n            get\n            {\n                var errorLogTimes = _errList.Count;\n                var m = errorLogTimes + Connecting;\n                if (m > 0)\n                {\n                    return (ConnectError + ErrorTimeoutTimes) * 100.0 / m;\n                }\n\n                return null;\n            }\n        }\n\n        #endregion\n\n        public void ClearTrans()\n        {\n            Interlocked.Exchange(ref _transUpload, 0);\n            Interlocked.Exchange(ref _transDownload, 0);\n\n            OnPropertyChanged(nameof(TotalUploadBytes));\n            OnPropertyChanged(nameof(TotalUploadBytesText));\n            OnPropertyChanged(nameof(TotalDownloadBytes));\n            OnPropertyChanged(nameof(TotalDownloadBytesText));\n        }\n\n        public void ClearError()\n        {\n            var value = Connecting;\n            if (value > 0)\n            {\n                Interlocked.Exchange(ref _totalConnectTimes, value);\n            }\n            else\n            {\n                Interlocked.Exchange(ref _totalConnectTimes, 0);\n            }\n            Interlocked.Exchange(ref _totalDisconnectTimes, 0);\n            Interlocked.Exchange(ref _errorConnectTimes, 0);\n            Interlocked.Exchange(ref _errorTimeoutTimes, 0);\n            Interlocked.Exchange(ref _errorDecodeTimes, 0);\n            Interlocked.Exchange(ref _errorEmptyTimes, 0);\n            Interlocked.Exchange(ref _errorContinuousTimes, 0);\n            _errList.Clear();\n\n            OnPropertyChanged(nameof(Connecting));\n            OnPropertyChanged(nameof(TotalConnectTimes));\n            OnPropertyChanged(nameof(TotalDisconnectTimes));\n            OnPropertyChanged(nameof(ConnectError));\n            OnPropertyChanged(nameof(ErrorConnectTimes));\n            OnPropertyChanged(nameof(ErrorTimeoutTimes));\n            OnPropertyChanged(nameof(ErrorDecodeTimes));\n            OnPropertyChanged(nameof(ErrorEmptyTimes));\n            OnPropertyChanged(nameof(ErrorContinuousTimes));\n            OnPropertyChanged(nameof(ErrorPercent));\n        }\n\n        public void ClearMaxSpeed()\n        {\n            Interlocked.Exchange(ref _maxTransDownload, 0);\n            Interlocked.Exchange(ref _maxTransUpload, 0);\n\n            OnPropertyChanged(nameof(MaxDownSpeed));\n            OnPropertyChanged(nameof(MaxDownSpeedText));\n            OnPropertyChanged(nameof(MaxUpSpeed));\n            OnPropertyChanged(nameof(MaxUpSpeedText));\n        }\n\n        public void Clear()\n        {\n            ResetConnectTime();\n            ClearError();\n            ClearMaxSpeed();\n            ClearTrans();\n            Interlocked.Exchange(ref _transDownloadRaw, 0);\n            OnPropertyChanged(nameof(TotalDownloadRawBytes));\n            OnPropertyChanged(nameof(TotalDownloadRawBytesText));\n        }\n\n        public void AddConnectTimes()\n        {\n            Interlocked.Increment(ref _totalConnectTimes);\n            OnPropertyChanged(nameof(TotalConnectTimes));\n            OnPropertyChanged(nameof(Connecting));\n            OnPropertyChanged(nameof(ErrorPercent));\n        }\n\n        public void AddDisconnectTimes()\n        {\n            Interlocked.Increment(ref _totalDisconnectTimes);\n            OnPropertyChanged(nameof(TotalDisconnectTimes));\n            OnPropertyChanged(nameof(Connecting));\n            OnPropertyChanged(nameof(ErrorPercent));\n        }\n\n        private void Sweep()\n        {\n            while (_errList.TryPeek(out var first))\n            {\n                if ((DateTime.Now - first.time).TotalMinutes < 30 && _errList.Count < 100)\n                {\n                    break;\n                }\n                _errList.TryDequeue(out first);\n                switch (first.errno)\n                {\n                    case 1:\n                    {\n                        if (ErrorConnectTimes > 0)\n                        {\n                            Interlocked.Decrement(ref _errorConnectTimes);\n                            OnPropertyChanged(nameof(ErrorConnectTimes));\n                            OnPropertyChanged(nameof(ConnectError));\n                        }\n\n                        break;\n                    }\n                    case 2:\n                    {\n                        if (ErrorTimeoutTimes > 0)\n                        {\n                            Interlocked.Decrement(ref _errorTimeoutTimes);\n                            OnPropertyChanged(nameof(ErrorTimeoutTimes));\n                        }\n\n                        break;\n                    }\n                    case 3:\n                    {\n                        if (ErrorDecodeTimes > 0)\n                        {\n                            Interlocked.Decrement(ref _errorDecodeTimes);\n                            OnPropertyChanged(nameof(ErrorDecodeTimes));\n                            OnPropertyChanged(nameof(ConnectError));\n                        }\n\n                        break;\n                    }\n                    case 4:\n                    {\n                        if (ErrorEmptyTimes > 0)\n                        {\n                            Interlocked.Decrement(ref _errorEmptyTimes);\n                            OnPropertyChanged(nameof(ErrorEmptyTimes));\n                        }\n\n                        break;\n                    }\n                }\n                OnPropertyChanged(nameof(ErrorPercent));\n            }\n        }\n\n        public void AddNoErrorTimes()\n        {\n            _errList.Enqueue(new ErrorLog(0));\n            Sweep();\n\n            Interlocked.Exchange(ref _errorEmptyTimes, 0);\n            OnPropertyChanged(nameof(ErrorEmptyTimes));\n        }\n\n        public void AddErrorTimes()\n        {\n            Interlocked.Increment(ref _errorConnectTimes);\n            Interlocked.Add(ref _errorContinuousTimes, 2);\n            _errList.Enqueue(new ErrorLog(1));\n            Sweep();\n\n            OnPropertyChanged(nameof(ErrorConnectTimes));\n            OnPropertyChanged(nameof(ErrorContinuousTimes));\n            OnPropertyChanged(nameof(ConnectError));\n        }\n\n        public void AddTimeoutTimes()\n        {\n            Interlocked.Increment(ref _errorTimeoutTimes);\n            Interlocked.Increment(ref _errorContinuousTimes);\n            _errList.Enqueue(new ErrorLog(2));\n            Sweep();\n\n            OnPropertyChanged(nameof(ErrorTimeoutTimes));\n            OnPropertyChanged(nameof(ErrorContinuousTimes));\n            OnPropertyChanged(nameof(ConnectError));\n        }\n\n        public void AddErrorDecodeTimes()\n        {\n            Interlocked.Increment(ref _errorDecodeTimes);\n            Interlocked.Add(ref _errorContinuousTimes, 10);\n            _errList.Enqueue(new ErrorLog(3));\n            Sweep();\n\n            OnPropertyChanged(nameof(ErrorDecodeTimes));\n            OnPropertyChanged(nameof(ErrorContinuousTimes));\n            OnPropertyChanged(nameof(ConnectError));\n        }\n\n        public void AddErrorEmptyTimes()\n        {\n            Interlocked.Increment(ref _errorEmptyTimes);\n            Interlocked.Increment(ref _errorContinuousTimes);\n            _errList.Enqueue(new ErrorLog(0));\n            Sweep();\n\n            OnPropertyChanged(nameof(ErrorEmptyTimes));\n            OnPropertyChanged(nameof(ErrorContinuousTimes));\n            OnPropertyChanged(nameof(ConnectError));\n        }\n\n        private static void UpdateTransLog(IList<TransLog> transLog, int bytes, DateTime now, ref long maxTrans, bool updateMaxTrans)\n        {\n            if (transLog.Count > 0)\n            {\n                const int baseTimeDiff = 100;\n                const int maxTimeDiff = 3 * baseTimeDiff;\n                var timeDiff = (int)(now - transLog.Last().recvTime).TotalMilliseconds;\n                if (timeDiff < 0)\n                {\n                    transLog.Clear();\n                    transLog.Add(new TransLog(bytes, now));\n                    return;\n                }\n                if (timeDiff < baseTimeDiff)\n                {\n                    transLog.Last().times++;\n                    transLog.Last().size += bytes;\n                    if (transLog.Last().endTime < now)\n                    {\n                        transLog.Last().endTime = now;\n                    }\n                }\n                else\n                {\n                    transLog.Add(new TransLog(bytes, now));\n\n                    var baseTimes = 1 + (maxTrans > 1024 * 512 ? 1 : 0);\n                    var lastIndex = transLog.Count - 1 - 2;\n                    if (updateMaxTrans && transLog.Count >= 6 && transLog[lastIndex].times > baseTimes)\n                    {\n                        var beginIndex = lastIndex - 1;\n                        for (; beginIndex > 0; --beginIndex)\n                        {\n                            if ((transLog[beginIndex + 1].recvTime - transLog[beginIndex].endTime).TotalMilliseconds > maxTimeDiff\n                            || transLog[beginIndex].times <= baseTimes\n                            )\n                            {\n                                break;\n                            }\n                        }\n\n                        if (beginIndex <= lastIndex - 4)\n                        {\n                            beginIndex++;\n                            var t = new TransLog(transLog[beginIndex].firstsize, transLog[beginIndex].recvTime)\n                            {\n                                endTime = transLog[lastIndex].endTime,\n                                size = 0\n                            };\n                            for (var i = beginIndex; i <= lastIndex; ++i)\n                            {\n                                t.size += transLog[i].size;\n                            }\n\n                            if (maxTrans == 0)\n                            {\n                                maxTrans = (long)((t.size - t.firstsize) / (t.endTime - t.recvTime).TotalSeconds * 0.7);\n                            }\n                            else\n                            {\n                                const double a = 2.0 / (1 + 32);\n                                maxTrans = (long)(0.5 + maxTrans * (1 - a) + a * ((t.size - t.firstsize) / (t.endTime - t.recvTime).TotalSeconds));\n                            }\n                        }\n                    }\n\n                }\n                while (transLog.Count > 0 && now > transLog[0].recvTime.AddSeconds(AvgTime))\n                {\n                    transLog.RemoveAt(0);\n                }\n            }\n            else\n            {\n                transLog.Add(new TransLog(bytes, now));\n            }\n        }\n\n        public void AddUploadBytes(int bytes, DateTime now, bool updateMaxTrans)\n        {\n            Interlocked.Add(ref _transUpload, bytes);\n            OnPropertyChanged(nameof(TotalUploadBytes));\n            OnPropertyChanged(nameof(TotalUploadBytesText));\n            lock (this)\n            {\n                UpdateTransLog(_upTransLog, bytes, now, ref _maxTransUpload, updateMaxTrans);\n            }\n\n            OnPropertyChanged(nameof(AvgUploadBytes));\n            OnPropertyChanged(nameof(AvgUploadBytesText));\n            OnPropertyChanged(nameof(MaxUpSpeed));\n            OnPropertyChanged(nameof(MaxUpSpeedText));\n        }\n\n        public void AddDownloadBytes(int bytes, DateTime now, bool updateMaxTrans)\n        {\n            Interlocked.Add(ref _transDownload, bytes);\n            OnPropertyChanged(nameof(TotalDownloadBytes));\n            OnPropertyChanged(nameof(TotalDownloadBytesText));\n            lock (this)\n            {\n                UpdateTransLog(_downTransLog, bytes, now, ref _maxTransDownload, updateMaxTrans);\n            }\n\n            OnPropertyChanged(nameof(AvgDownloadBytes));\n            OnPropertyChanged(nameof(AvgDownloadBytesText));\n            OnPropertyChanged(nameof(MaxDownSpeed));\n            OnPropertyChanged(nameof(MaxDownSpeedText));\n        }\n\n        public void AddDownloadRawBytes(long bytes)\n        {\n            Interlocked.Add(ref _transDownloadRaw, bytes);\n            OnPropertyChanged(nameof(TotalDownloadRawBytes));\n            OnPropertyChanged(nameof(TotalDownloadRawBytesText));\n        }\n\n        public void ResetErrorDecodeTimes()\n        {\n            Interlocked.Exchange(ref _errorDecodeTimes, 0);\n            Interlocked.Exchange(ref _errorEmptyTimes, 0);\n            Interlocked.Exchange(ref _errorContinuousTimes, 0);\n\n            OnPropertyChanged(nameof(ErrorDecodeTimes));\n            OnPropertyChanged(nameof(ErrorEmptyTimes));\n            OnPropertyChanged(nameof(ErrorContinuousTimes));\n            OnPropertyChanged(nameof(ConnectError));\n            OnPropertyChanged(nameof(ErrorPercent));\n        }\n\n        public void ResetContinuousTimes()\n        {\n            Interlocked.Exchange(ref _errorEmptyTimes, 0);\n            Interlocked.Exchange(ref _errorContinuousTimes, 0);\n\n            OnPropertyChanged(nameof(ErrorEmptyTimes));\n            OnPropertyChanged(nameof(ErrorContinuousTimes));\n        }\n\n        public void ResetEmptyTimes()\n        {\n            Interlocked.Exchange(ref _errorEmptyTimes, 0);\n            OnPropertyChanged(nameof(ErrorEmptyTimes));\n        }\n\n        public void ResetConnectTime()\n        {\n            Interlocked.Exchange(ref _avgConnectTime, -1);\n            OnPropertyChanged(nameof(AvgConnectTimeText));\n        }\n\n        public void AddConnectTime(long millisecond)\n        {\n            if (millisecond == 0)\n            {\n                millisecond = 10;\n            }\n            else\n            {\n                millisecond *= 1000;\n            }\n\n            var oldValue = AvgConnectTime;\n            if (oldValue == -1)\n            {\n                Interlocked.Exchange(ref _avgConnectTime, millisecond);\n            }\n            else\n            {\n                const double a = 2.0 / (1 + 16);\n                Interlocked.Exchange(ref _avgConnectTime, Convert.ToInt64(0.5 + oldValue * (1 - a) + a * millisecond));\n            }\n            OnPropertyChanged(nameof(AvgConnectTimeText));\n        }\n    }\n\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/Transfer/ServerTrans.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Model.Transfer\n{\n    [Serializable]\n    public class ServerTrans\n    {\n        public long TotalUploadBytes { get; set; }\n        public long TotalDownloadBytes { get; set; }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/Transfer/ServerTransferTotal.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text.Json;\n\nnamespace Shadowsocks.Model.Transfer\n{\n    [Serializable]\n    public class ServerTransferTotal\n    {\n        private const string LogFile = @\"transfer_log.json\";\n\n        public Dictionary<string, ServerTrans> Servers = new();\n        private int _saveCounter;\n        private DateTime _saveTime;\n\n        private static readonly TimeSpan MinInterval = TimeSpan.FromMinutes(10);\n        private const int MaxSaveCounter = 256;\n\n        public static ServerTransferTotal Load()\n        {\n            try\n            {\n                ServerTransferTotal config;\n                if (File.Exists(LogFile))\n                {\n                    config = new ServerTransferTotal\n                    {\n                        Servers = JsonSerializer.Deserialize<Dictionary<string, ServerTrans>>(File.ReadAllText(LogFile))\n                    };\n                }\n                else\n                {\n                    config = new ServerTransferTotal();\n                }\n                config.Init();\n                return config;\n            }\n            catch (FileNotFoundException)\n            {\n                // ignored\n            }\n            catch (Exception e)\n            {\n                Console.WriteLine(e);\n            }\n            return new ServerTransferTotal();\n        }\n\n        private void Init()\n        {\n            _saveCounter = MaxSaveCounter;\n            _saveTime = DateTime.Now;\n            if (Servers == null)\n            {\n                Servers = new Dictionary<string, ServerTrans>();\n            }\n        }\n\n        public static void Save(ServerTransferTotal config, List<Server> servers = null)\n        {\n            try\n            {\n                if (servers != null)\n                {\n                    config.Servers = config.Servers\n                    .Where(pair => servers.Exists(server => server.Id == pair.Key))\n                    .ToDictionary(pair => pair.Key, pair => pair.Value);\n                }\n                var jsonString = JsonUtils.Serialize(config.Servers, true);\n                File.WriteAllTextAsync(LogFile, jsonString);\n            }\n            catch (IOException e)\n            {\n                Console.Error.WriteLine(e);\n            }\n        }\n\n        public void Clear(string serverId)\n        {\n            lock (Servers)\n            {\n                if (Servers.TryGetValue(serverId, out var trans))\n                {\n                    trans.TotalUploadBytes = 0;\n                    trans.TotalDownloadBytes = 0;\n                }\n            }\n        }\n\n        public void AddUpload(string serverId, long size)\n        {\n            lock (Servers)\n            {\n                if (Servers.TryGetValue(serverId, out var trans))\n                {\n                    trans.TotalUploadBytes += size;\n                }\n                else\n                {\n                    Servers.Add(serverId, new ServerTrans());\n                }\n            }\n            if (--_saveCounter <= 0)\n            {\n                _saveCounter = MaxSaveCounter;\n                if (DateTime.Now - _saveTime > MinInterval)\n                {\n                    lock (Servers)\n                    {\n                        Save(this);\n                        _saveTime = DateTime.Now;\n                    }\n                }\n            }\n        }\n\n        public void AddDownload(string server, long size)\n        {\n            lock (Servers)\n            {\n                if (Servers.TryGetValue(server, out var trans))\n                {\n                    trans.TotalDownloadBytes += size;\n                }\n                else\n                {\n                    Servers.Add(server, new ServerTrans());\n                }\n            }\n            if (--_saveCounter <= 0)\n            {\n                _saveCounter = MaxSaveCounter;\n                if (DateTime.Now - _saveTime > MinInterval)\n                {\n                    lock (Servers)\n                    {\n                        Save(this);\n                        _saveTime = DateTime.Now;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/Transfer/TransLog.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Model.Transfer\n{\n    public class TransLog\n    {\n        public int size;\n        public int firstsize;\n        public int times;\n        public DateTime recvTime;\n        public DateTime endTime;\n        public TransLog(int s, DateTime t)\n        {\n            firstsize = s;\n            size = s;\n            recvTime = t;\n            endTime = t;\n            times = 1;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/UriVisitTime.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Model\n{\n    public class UriVisitTime : IComparable\n    {\n        public DateTime visitTime;\n        public string uri;\n        public int index;\n\n        public int CompareTo(object other)\n        {\n            if (other is not UriVisitTime)\n            {\n                throw new InvalidOperationException(\"CompareTo: Not a UriVisitTime\");\n            }\n\n            return Equals(other) ? 0 : visitTime.CompareTo(((UriVisitTime)other).visitTime);\n        }\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Model/WindowStatus.cs",
    "content": "using Shadowsocks.Util;\nusing System.Windows;\n\nnamespace Shadowsocks.Model\n{\n    public class WindowStatus\n    {\n        public double Width;\n        public double Height;\n        public double Left;\n        public double Top;\n        public WindowState State;\n\n        public WindowStatus()\n        {\n            Width = 0.0;\n            Height = 0.0;\n            Left = 0.0;\n            Top = 0.0;\n            State = WindowState.Normal;\n        }\n\n        public WindowStatus(Window window)\n        {\n            Width = window.Width;\n            Height = window.Height;\n            Left = window.Left;\n            Top = window.Top;\n            State = window.WindowState;\n        }\n\n        public void SetStatus(Window window)\n        {\n            window.Width = Width;\n            window.Height = Height;\n            window.Left = Left;\n            window.Top = Top;\n            window.WindowState = State;\n            window.WindowStartupLocation = ViewUtils.IsOnScreen(window) ? WindowStartupLocation.Manual : WindowStartupLocation.CenterScreen;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthAES128SHA1.cs",
    "content": "using CryptoBase.Abstractions;\nusing CryptoBase.Abstractions.Digests;\nusing CryptoBase.Digests;\nusing CryptoBase.Macs.Hmac;\nusing Shadowsocks.Controller;\nusing Shadowsocks.Encryption;\nusing Shadowsocks.Enums;\nusing System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\n\nnamespace Shadowsocks.Obfs\n{\n    public class AuthAES128SHA1 : VerifySimpleBase\n    {\n        protected delegate byte[] hash_func(ReadOnlySpan<byte> input);\n\n        protected class AuthDataAes128 : AuthData\n        {\n            public Model.MinSearchTree tree;\n        }\n\n        public AuthAES128SHA1(string method)\n                : base(method)\n        {\n            has_sent_header = false;\n            has_recv_header = false;\n            pack_id = 1;\n            recv_id = 1;\n            SALT = method;\n            if (method == \"auth_aes128_md5\")\n            {\n                hash = CryptoUtils.MD5;\n            }\n            else\n            {\n                hash = CryptoUtils.SHA1;\n            }\n\n            random = new Random(RandomNumberGenerator.GetInt32(int.MaxValue));\n        }\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_aes128_md5\", new[] { 1, 0, 1 } },\n            { \"auth_aes128_sha1\", new[] { 1, 0, 1 } }\n        };\n\n        protected bool has_sent_header;\n        protected bool has_recv_header;\n        protected string SALT;\n\n        protected uint pack_id;\n        protected uint recv_id;\n        protected byte[] user_key;\n        protected byte[] user_id;\n        protected hash_func hash;\n        protected byte[] send_buffer;\n        protected int last_datalength;\n\n        protected const int overhead = 9; // 2(length) + 2(len-MAC) + 4(data-MAC) + 1(padding)\n        //protected int[] packet_cnt;\n        protected Dictionary<int, long> packet_cnt = new();\n        //protected int[] packet_mul;\n        protected Model.MinSearchTree tree;\n        protected const int tree_offset = 9;\n        protected DateTime lastSendTime;\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        public override object InitData()\n        {\n            return new AuthDataAes128();\n        }\n\n        public override bool isKeepAlive()\n        {\n            return true;\n        }\n\n        public override bool isAlwaysSendback()\n        {\n            return true;\n        }\n\n        public override int GetOverhead()\n        {\n            return overhead;\n        }\n\n        protected IMac CreateHMAC(byte[] key)\n        {\n            return Method switch\n            {\n                @\"auth_aes128_md5\" => HmacUtils.Create(DigestType.Md5, key),\n                @\"auth_aes128_sha1\" => HmacUtils.Create(DigestType.Sha1, key),\n                _ => null\n            };\n        }\n\n        protected void Sync()\n        {\n#if PROTOCOL_STATISTICS\n            if (Server.data is not null and AuthDataAes128 authData)\n            {\n                lock (authData)\n                {\n                    if (authData.tree != null && packet_cnt != null)\n                    {\n                        authData.tree.Update(packet_cnt);\n                        tree = authData.tree.Clone();\n                    }\n                }\n            }\n#endif\n        }\n\n        // return final size, include dataLengthMax\n        protected int RandomInMin(int dataLengthMin, int dataLengthMax)\n        {\n            dataLengthMin -= tree_offset;\n            dataLengthMax -= tree_offset;\n            var len = tree.RandomFindIndex(dataLengthMin - 1, dataLengthMax, random);\n            tree.Update(len);\n            return len + tree_offset + 1;\n        }\n\n        // real packet size. mapping: 1 => 0\n        protected void AddPacket(int length)\n        {\n#if PROTOCOL_STATISTICS\n            if (length > tree_offset)\n            {\n                length -= 1 + tree_offset;\n                if (length >= tree.Size)\n                {\n                    length = tree.Size - 1;\n                }\n\n                lock (Server.data)\n                {\n                    if (packet_cnt.ContainsKey(length))\n                    {\n                        packet_cnt[length] += 1;\n                    }\n                    else\n                    {\n                        packet_cnt[length] = 1;\n                    }\n                }\n            }\n            else\n            {\n                throw new ObfsException(\"AddPacket size uncorrect\");\n            }\n#endif\n        }\n\n        protected void StatisticsInit(AuthDataAes128 authData)\n        {\n#if PROTOCOL_STATISTICS\n            if (authData.tree == null)\n            {\n                authData.tree = new Model.MinSearchTree(Server.tcp_mss - tree_offset);\n                authData.tree.Init();\n            }\n\n            tree = authData.tree.Clone();\n#endif\n        }\n\n        protected int GetRandLen(int datalength, int fulldatalength, bool nopadding)\n        {\n            if (nopadding || fulldatalength >= Server.buffer_size)\n            {\n                return 0;\n            }\n\n            var rev_len = Server.tcp_mss - datalength - overhead;\n            if (rev_len <= 0)\n            {\n                return 0;\n            }\n\n            if (datalength > 1100)\n            {\n                return LinearRandomInt(rev_len);\n            }\n\n            return TrapezoidRandomInt(rev_len, -0.3);\n        }\n\n#if PROTOCOL_STATISTICS\n        // packetlength + padding = real_packetlength\n        // return size of padding, at least 1\n        protected int GenRandLenFull(int packetlength, int fulldatalength, bool nopadding)\n        {\n            if (nopadding || fulldatalength >= Server.buffer_size)\n            {\n                return packetlength;\n            }\n\n            if (packetlength >= Server.tcp_mss)\n            {\n                if (packetlength > Server.tcp_mss && packetlength < Server.tcp_mss * 2)\n                {\n                    return packetlength + TrapezoidRandomInt(Server.tcp_mss * 2 - packetlength, -0.3);\n                }\n                return packetlength + TrapezoidRandomInt(32, -0.3);\n            }\n            return RandomInMin(packetlength, Server.tcp_mss - 1);\n        }\n\n        protected int GenRandLen(int packetlength, int maxpacketlength)\n        {\n            return RandomInMin(packetlength, maxpacketlength);\n        }\n#endif\n\n        public void PackData(byte[] data, int datalength, int fulldatalength, byte[] outdata, out int outlength, bool nopadding = false)\n        {\n#if !PROTOCOL_STATISTICS\n            int rand_len = GetRandLen(datalength, fulldatalength, nopadding) + 1;\n#else\n            const int overHead = 8;\n            var rand_len = GenRandLenFull((datalength == 0 ? 1 : datalength) + overHead + 1, fulldatalength, nopadding)\n                           - datalength - overHead;\n#endif\n            outlength = rand_len + datalength + 8;\n            if (datalength > 0)\n            {\n                Array.Copy(data, 0, outdata, rand_len + 4, datalength);\n            }\n\n            outdata[0] = (byte)outlength;\n            outdata[1] = (byte)(outlength >> 8);\n            var key = new byte[user_key.Length + 4];\n            user_key.CopyTo(key, 0);\n            BitConverter.GetBytes(pack_id).CopyTo(key, key.Length - 4);\n            {\n                var rnd_data = new byte[rand_len];\n                random.NextBytes(rnd_data);\n                rnd_data.CopyTo(outdata, 4);\n            }\n\n            using var sha1 = CreateHMAC(key);\n            {\n                sha1.Update(outdata.AsSpan(0, 2));\n                Span<byte> span = stackalloc byte[sha1.Length];\n                sha1.GetMac(span);\n                span[..2].CopyTo(outdata.AsSpan(2, 2));\n            }\n            if (rand_len < 128)\n            {\n                outdata[4] = (byte)rand_len;\n            }\n            else\n            {\n                outdata[4] = 0xFF;\n                outdata[5] = (byte)rand_len;\n                outdata[6] = (byte)(rand_len >> 8);\n            }\n            ++pack_id;\n            {\n                sha1.Update(outdata.AsSpan(0, outlength - 4));\n                Span<byte> span = stackalloc byte[sha1.Length];\n                sha1.GetMac(span);\n                span[..4].CopyTo(outdata.AsSpan(outlength - 4, 4));\n            }\n        }\n\n        public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            const int authHeadLen = 7 + 4 + 16 + 4;\n            const int overHead = authHeadLen + 4;\n            var encrypt = new byte[24];\n\n            if (Server.data is AuthDataAes128 authData)\n            {\n                lock (authData)\n                {\n                    if (authData.connectionID > 0xFF000000)\n                    {\n                        authData.clientID = null;\n                    }\n\n                    if (authData.clientID == null)\n                    {\n                        authData.clientID = RandomNumberGenerator.GetBytes(4);\n                        authData.connectionID = (uint)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD;\n                    }\n\n                    authData.connectionID += 1;\n                    Array.Copy(authData.clientID, 0, encrypt, 4, 4);\n                    Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, encrypt, 8, 4);\n\n                    StatisticsInit(authData);\n                }\n            }\n\n#if !PROTOCOL_STATISTICS\n            int rand_len = TrapezoidRandomInt(Server.tcp_mss - datalength - overhead + 1, -0.3); //(datalength > 400 ? LinearRandomInt(512) : LinearRandomInt(1024));\n#else\n            var rand_len = GenRandLenFull(datalength + overHead, datalength, false) - datalength - overHead;\n#endif\n            var data_offset = rand_len + authHeadLen;\n            outlength = data_offset + datalength + 4;\n            var encrypt_data = new byte[32];\n            var key = new byte[Server.Iv.Length + Server.key.Length];\n            Server.Iv.CopyTo(key, 0);\n            Server.key.CopyTo(key, Server.Iv.Length);\n\n            {\n                var rnd_data = new byte[rand_len];\n                random.NextBytes(rnd_data);\n                rnd_data.CopyTo(outdata, data_offset - rand_len);\n            }\n\n            var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);\n            var utc_time = (uint)utc_time_second;\n            Array.Copy(BitConverter.GetBytes(utc_time), 0, encrypt, 0, 4);\n            encrypt[12] = (byte)outlength;\n            encrypt[13] = (byte)(outlength >> 8);\n            encrypt[14] = (byte)rand_len;\n            encrypt[15] = (byte)(rand_len >> 8);\n\n            {\n                var uid = new byte[4];\n                var index_of_split = Server.param.IndexOf(':');\n                if (index_of_split > 0)\n                {\n                    try\n                    {\n                        var user = uint.Parse(Server.param.Substring(0, index_of_split));\n                        user_key = hash(System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1)));\n                        BitConverter.GetBytes(user).CopyTo(uid, 0);\n                    }\n                    catch (Exception ex)\n                    {\n                        Logging.Log(LogLevel.Warn, $\"Faild to parse auth param, fallback to basic mode. {ex}\");\n                    }\n                }\n                if (user_key == null)\n                {\n                    random.NextBytes(uid);\n                    user_key = Server.key;\n                }\n\n                var encrypt_key = user_key;\n\n                CryptoUtils.SsAes128(Convert.ToBase64String(encrypt_key) + SALT, encrypt.AsSpan(0, 16), encrypt_data.AsSpan(0, 16));\n                Array.Copy(encrypt_data, 0, encrypt, 4, 16);\n                uid.CopyTo(encrypt, 0);\n            }\n            {\n                using var sha1 = CreateHMAC(key);\n                sha1.Update(encrypt.AsSpan(0, 20));\n                Span<byte> span = stackalloc byte[sha1.Length];\n                sha1.GetMac(span);\n                span[..4].CopyTo(encrypt.AsSpan(20, 4));\n\n                var rnd = new byte[1];\n                random.NextBytes(rnd);\n                rnd.CopyTo(outdata, 0);\n\n                sha1.Update(rnd);\n                sha1.GetMac(span);\n                span[..(7 - rnd.Length)].CopyTo(outdata.AsSpan(rnd.Length, 7 - rnd.Length));\n            }\n            encrypt.CopyTo(outdata, 7);\n            Array.Copy(data, 0, outdata, data_offset, datalength);\n\n            {\n                using var sha1 = CreateHMAC(user_key);\n                sha1.Update(outdata.AsSpan(0, outlength - 4));\n                Span<byte> span = stackalloc byte[sha1.Length];\n                sha1.GetMac(span);\n                span[..4].CopyTo(outdata.AsSpan(outlength - 4, 4));\n            }\n        }\n\n        // plaindata == null    try send buffer data, return null if empty buffer\n        // datalength == 0      sendback, return 0\n        // datalength == -1     keepalive\n        public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var last = lastSendTime;\n            var now = DateTime.Now;\n            lastSendTime = now;\n            var outdata = new byte[datalength + datalength / 10 + 32];\n            var packdata = new byte[9000];\n            var data = plaindata == null ? send_buffer : plaindata;\n            outlength = 0;\n            if (data == null)\n            {\n                return null;\n            }\n\n            if (data == send_buffer)\n            {\n                datalength = send_buffer.Length;\n                send_buffer = null;\n                Sync();\n                last = now;\n            }\n            else if (send_buffer != null)\n            {\n                if (datalength <= 0)\n                {\n                    return outdata;\n                }\n\n                Array.Resize(ref send_buffer, send_buffer.Length + datalength);\n                Array.Copy(data, 0, send_buffer, send_buffer.Length - datalength, datalength);\n                data = send_buffer;\n                datalength = send_buffer.Length;\n                send_buffer = null;\n            }\n            const int unit_len = 8100;\n            var ogn_datalength = datalength;\n            if (datalength < 0 || (now - last).TotalSeconds > 3)\n            {\n                Sync();\n            }\n            if (!has_sent_header)\n            {\n                var _datalength = Math.Min(1200, datalength);\n                PackAuthData(data, _datalength, packdata, out var outlen);\n                has_sent_header = true;\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= _datalength;\n                var newdata = new byte[datalength];\n                Array.Copy(data, _datalength, newdata, 0, newdata.Length);\n                data = newdata;\n\n                send_buffer = data.Length > 0 ? data : null;\n\n                AddPacket(outlength);\n                return outdata;\n            }\n            var nopadding = false;\n\n#if !PROTOCOL_STATISTICS\n            if (datalength > 120 * 4 && pack_id < 32)\n            {\n                {\n                    int send_len = LinearRandomInt(120 * 16);\n                    if (send_len < datalength)\n                    {\n                        send_len = TrapezoidRandomInt(Math.Min(datalength - 1, Server.tcp_mss - overhead) - 1, -0.3) + 1;  // must less than datalength\n#else\n            if (datalength > 120 * 4 && pack_id < 64)\n            {\n                var send_len = LinearRandomInt(datalength + 120 * 4);\n                if (send_len < datalength)\n                {\n                    //long min_0 = tree.GetMin(0, 512);\n                    //long min_512 = tree.GetMin(512, tree.Size);\n                    //if (min_0 < min_512)\n                    {\n                        var max_packet_size = Math.Min(datalength - 1 + overhead, Server.tcp_mss); // must less than datalength + overhead\n                        var len = GenRandLen(overhead + 1, max_packet_size) - overhead; // at least 1 byte data\n                        send_len = len;\n#endif\n\n                        send_len = datalength - send_len;\n\n                        if (send_len > 0)\n                        {\n                            send_buffer = new byte[send_len];\n                            Array.Copy(data, datalength - send_len, send_buffer, 0, send_len);\n                            datalength -= send_len;\n                        }\n                        nopadding = true;\n                    }\n                }\n            }\n            while (datalength > unit_len)\n            {\n                PackData(data, unit_len, ogn_datalength, packdata, out var outlen, nopadding);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= unit_len;\n                var newdata = new byte[datalength];\n                Array.Copy(data, unit_len, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            if (datalength > 0 || ogn_datalength == -1)\n            {\n                if (ogn_datalength == -1)\n                {\n                    datalength = 0;\n                }\n\n                PackData(data, datalength, ogn_datalength, packdata, out var outlen, nopadding);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n            }\n            last_datalength = ogn_datalength;\n            if (outlength > 0)\n            {\n                AddPacket(outlength);\n            }\n\n            return outdata;\n        }\n\n        public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[recv_buf_len + datalength];\n            Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength);\n            recv_buf_len += datalength;\n            outlength = 0;\n            var key = new byte[user_key.Length + 4];\n            user_key.CopyTo(key, 0);\n\n            Span<byte> span = stackalloc byte[HashConstants.Sha1Length];\n            while (recv_buf_len > 4)\n            {\n                BitConverter.GetBytes(recv_id).CopyTo(key, key.Length - 4);\n                using var sha1 = CreateHMAC(key);\n                {\n                    sha1.Update(recv_buf.AsSpan(0, 2));\n                    sha1.GetMac(span);\n                    if (span[0] != recv_buf[2] || span[1] != recv_buf[3])\n                    {\n                        throw new ObfsException(\"ClientPostDecrypt data error\");\n                    }\n                }\n\n                var len = (recv_buf[1] << 8) + recv_buf[0];\n                if (len is >= 8192 or < 8)\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data error\");\n                }\n                if (len > recv_buf_len)\n                {\n                    break;\n                }\n\n                sha1.Update(recv_buf.AsSpan(0, len - 4));\n                sha1.GetMac(span);\n\n                if (!span[..4].SequenceEqual(recv_buf.AsSpan(len - 4, 4)))\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data uncorrect checksum\");\n                }\n\n                {\n                    ++recv_id;\n                    int pos = recv_buf[4];\n                    if (pos < 255)\n                    {\n                        pos += 4;\n                    }\n                    else\n                    {\n                        pos = ((recv_buf[6] << 8) | recv_buf[5]) + 4;\n                    }\n                    var outlen = len - pos - 4;\n                    Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                    Array.Copy(recv_buf, pos, outdata, outlength, outlen);\n                    outlength += outlen;\n                    recv_buf_len -= len;\n                    Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len);\n                }\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[datalength + 8];\n            if (user_key == null)\n            {\n                user_id = new byte[4];\n                var index_of_split = Server.param.IndexOf(':');\n                if (index_of_split > 0)\n                {\n                    try\n                    {\n                        var user = uint.Parse(Server.param.Substring(0, index_of_split));\n                        user_key = hash(System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1)));\n                        BitConverter.GetBytes(user).CopyTo(user_id, 0);\n                    }\n                    catch (Exception ex)\n                    {\n                        Logging.Log(LogLevel.Warn, $\"Faild to parse auth param, fallback to basic mode. {ex}\");\n                    }\n                }\n                if (user_key == null)\n                {\n                    random.NextBytes(user_id);\n                    user_key = Server.key;\n                }\n            }\n            outlength = datalength + 8;\n            Array.Copy(plaindata, 0, outdata, 0, datalength);\n            user_id.CopyTo(outdata, datalength);\n            {\n                using var sha1 = CreateHMAC(user_key);\n                sha1.Update(outdata.AsSpan(0, outlength - 4));\n                Span<byte> span = stackalloc byte[sha1.Length];\n                sha1.GetMac(span);\n                span[..4].CopyTo(outdata.AsSpan(outlength - 4, 4));\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            if (datalength <= 4)\n            {\n                outlength = 0;\n                return plaindata;\n            }\n            using var sha1 = CreateHMAC(Server.key);\n            sha1.Update(plaindata.AsSpan(0, datalength - 4));\n            Span<byte> span = stackalloc byte[sha1.Length];\n            sha1.GetMac(span);\n\n            if (span[..4].SequenceEqual(plaindata.AsSpan(datalength - 4, 4)))\n            {\n                outlength = datalength - 4;\n                return plaindata;\n            }\n\n            outlength = 0;\n            return plaindata;\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n#if PROTOCOL_STATISTICS\n            if (disposing)\n            {\n                if (Server != null && Server.data != null && packet_cnt != null)\n                {\n                    var authData = Server.data as AuthDataAes128;\n                    if (authData != null && authData.tree != null)\n                    {\n                        lock (authData)\n                        {\n                            authData.tree.Update(packet_cnt);\n                        }\n                    }\n                }\n            }\n#endif\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthAkarin.cs",
    "content": "using CryptoBase.Abstractions;\nusing CryptoBase.Digests;\nusing CryptoBase.Macs.Hmac;\nusing Shadowsocks.Controller;\nusing Shadowsocks.Encryption;\nusing Shadowsocks.Encryption.Stream;\nusing Shadowsocks.Enums;\nusing System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\n\nnamespace Shadowsocks.Obfs\n{\n    internal class AuthAkarin : VerifySimpleBase\n    {\n        protected class AuthDataAesChain : AuthData\n        {\n        }\n\n        public AuthAkarin(string method)\n            : base(method)\n        {\n            has_sent_header = false;\n            has_recv_header = false;\n            pack_id = 1;\n            recv_id = 1;\n            SALT = method;\n            random = new Random(RandomNumberGenerator.GetInt32(int.MaxValue));\n        }\n\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_akarin_rand\", new[] { 1, 0, 1 } }\n        };\n\n        protected bool has_sent_header;\n        protected bool has_recv_header;\n        protected string SALT;\n\n        protected uint pack_id;\n        protected uint recv_id;\n        protected byte[] user_key;\n        protected byte[] user_id;\n        protected byte[] send_buffer;\n        protected int last_datalength;\n        protected byte[] last_client_hash;\n        protected byte[] last_server_hash;\n        protected xorshift128plus random_client = new(0);\n        protected xorshift128plus random_server = new(0);\n        protected StreamEncryptor encryptor;\n        protected int send_tcp_mss = 2000;\n        protected int recv_tcp_mss = 2000;\n        protected List<int> send_back_cmd = new();\n\n        protected const int overhead = 4;\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        protected override void Disposing()\n        {\n            if (encryptor != null)\n            {\n                encryptor.Dispose();\n                encryptor = null;\n            }\n        }\n\n        public override object InitData()\n        {\n            return new AuthDataAesChain();\n        }\n\n        public override bool isKeepAlive()\n        {\n            return true;\n        }\n\n        public override bool isAlwaysSendback()\n        {\n            return true;\n        }\n\n        public override int GetOverhead()\n        {\n            return overhead;\n        }\n\n        protected IMac CreateHMAC(byte[] key)\n        {\n            return HmacUtils.Create(DigestType.Md5, key);\n        }\n\n        protected virtual int GetSendRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            if (datalength + Server.overhead > send_tcp_mss)\n            {\n                rd.init_from_bin(last_hash, datalength);\n                return (int)(rd.next() % 521);\n            }\n            if (datalength >= 1440 || datalength + Server.overhead == recv_tcp_mss)\n            {\n                return 0;\n            }\n\n            rd.init_from_bin(last_hash, datalength);\n            if (datalength > 1300)\n            {\n                return (int)(rd.next() % 31);\n            }\n\n            if (datalength > 900)\n            {\n                return (int)(rd.next() % 127);\n            }\n\n            if (datalength > 400)\n            {\n                return (int)(rd.next() % 521);\n            }\n\n            return (int)(rd.next() % (ulong)(send_tcp_mss - datalength - Server.overhead));\n            //return (int)(random.next() % 1021);\n        }\n\n        protected virtual int GetRecvRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            if (datalength + Server.overhead > recv_tcp_mss)\n            {\n                rd.init_from_bin(last_hash, datalength);\n                return (int)(rd.next() % 521);\n            }\n            if (datalength >= 1440 || datalength + Server.overhead == recv_tcp_mss)\n            {\n                return 0;\n            }\n\n            rd.init_from_bin(last_hash, datalength);\n            if (datalength > 1300)\n            {\n                return (int)(rd.next() % 31);\n            }\n\n            if (datalength > 900)\n            {\n                return (int)(rd.next() % 127);\n            }\n\n            if (datalength > 400)\n            {\n                return (int)(rd.next() % 521);\n            }\n\n            return (int)(rd.next() % (ulong)(recv_tcp_mss - datalength - Server.overhead));\n            //return (int)(random.next() % 1021);\n        }\n\n        protected int UdpGetRandLen(xorshift128plus rd, byte[] last_hash)\n        {\n            rd.init_from_bin(last_hash);\n            return (int)(rd.next() % 127);\n        }\n\n        protected int GetSendRandLen(int datalength)\n        {\n            return GetSendRandLen(datalength, random_client, last_client_hash);\n        }\n\n        public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var cmdlen = 0;\n            int rand_len;\n            var start_pos = 2;\n            if (send_back_cmd.Count > 0)\n            {\n                cmdlen += 2;\n                send_tcp_mss = recv_tcp_mss;\n                rand_len = GetSendRandLen(datalength + cmdlen);\n                outlength = rand_len + datalength + cmdlen + 2;\n                start_pos += cmdlen;\n                outdata[0] = (byte)(send_back_cmd[0] ^ last_client_hash[14]);\n                outdata[1] = (byte)((send_back_cmd[0] >> 8) ^ last_client_hash[15]);\n                outdata[2] = (byte)(datalength ^ last_client_hash[12]);\n                outdata[3] = (byte)((datalength >> 8) ^ last_client_hash[13]);\n                send_back_cmd.Clear();\n            }\n            else\n            {\n                rand_len = GetSendRandLen(datalength);\n                outlength = rand_len + datalength + 2;\n                outdata[0] = (byte)(datalength ^ last_client_hash[14]);\n                outdata[1] = (byte)((datalength >> 8) ^ last_client_hash[15]);\n            }\n            {\n                var rnd_data = new byte[rand_len];\n                random.NextBytes(rnd_data);\n                if (datalength > 0)\n                {\n                    encryptor.Encrypt(data, datalength, data, out datalength);\n                    Array.Copy(data, 0, outdata, start_pos, datalength);\n                    if (rand_len > 0)\n                    {\n                        rnd_data.CopyTo(outdata, start_pos + datalength);\n                    }\n                }\n                else\n                {\n                    rnd_data.CopyTo(outdata, start_pos);\n                }\n            }\n\n            var key = new byte[user_key.Length + 4];\n            user_key.CopyTo(key, 0);\n            BitConverter.GetBytes(pack_id).CopyTo(key, key.Length - 4);\n\n            using var md5 = CreateHMAC(key);\n            ++pack_id;\n            {\n                md5.Update(outdata.AsSpan(0, outlength));\n                var md5data = new byte[md5.Length];\n                md5.GetMac(md5data);\n                last_client_hash = md5data;\n                md5data[..2].CopyTo(outdata.AsSpan(outlength, 2));\n                outlength += 2;\n            }\n        }\n\n        public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            const int authhead_len = 4 + 8 + 4 + 16 + 4;\n            var encrypt = new byte[24];\n\n            if (Server.data is AuthDataAesChain authData)\n            {\n                lock (authData)\n                {\n                    if (authData.connectionID > 0xFF000000)\n                    {\n                        authData.clientID = null;\n                    }\n\n                    if (authData.clientID == null)\n                    {\n                        authData.clientID = RandomNumberGenerator.GetBytes(4);\n                        authData.connectionID = (uint)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD;\n                    }\n\n                    authData.connectionID += 1;\n                    Array.Copy(authData.clientID, 0, encrypt, 4, 4);\n                    Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, encrypt, 8, 4);\n                }\n            }\n\n            outlength = authhead_len;\n            var encrypt_data = new byte[32];\n            var key = new byte[Server.Iv.Length + Server.key.Length];\n            Server.Iv.CopyTo(key, 0);\n            Server.key.CopyTo(key, Server.Iv.Length);\n\n            var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);\n            var utc_time = (uint)utc_time_second;\n            Array.Copy(BitConverter.GetBytes(utc_time), 0, encrypt, 0, 4);\n\n            encrypt[12] = (byte)Server.overhead;\n            encrypt[13] = (byte)(Server.overhead >> 8);\n            send_tcp_mss = 1024; //random.Next(1024) + 400;\n            recv_tcp_mss = send_tcp_mss;\n            encrypt[14] = (byte)send_tcp_mss;\n            encrypt[15] = (byte)(send_tcp_mss >> 8);\n\n            // first 12 bytes\n            {\n                Span<byte> rnd = stackalloc byte[4];\n                RandomNumberGenerator.Fill(rnd);\n                rnd.CopyTo(outdata);\n                using var md5 = CreateHMAC(key);\n                md5.Update(rnd);\n                var md5data = new byte[md5.Length];\n                md5.GetMac(md5data);\n                last_client_hash = md5data;\n                md5data[..8].CopyTo(outdata.AsSpan(rnd.Length, 8));\n            }\n            // uid & 16 bytes auth data\n            {\n                var uid = new byte[4];\n                var index_of_split = Server.param.IndexOf(':');\n                if (index_of_split > 0)\n                {\n                    try\n                    {\n                        var user = uint.Parse(Server.param.Substring(0, index_of_split));\n                        user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1));\n                        BitConverter.GetBytes(user).CopyTo(uid, 0);\n                    }\n                    catch (Exception ex)\n                    {\n                        Logging.Log(LogLevel.Warn, $\"Faild to parse auth param, fallback to basic mode. {ex}\");\n                    }\n                }\n                if (user_key == null)\n                {\n                    random.NextBytes(uid);\n                    user_key = Server.key;\n                }\n                for (var i = 0; i < 4; ++i)\n                {\n                    uid[i] ^= last_client_hash[8 + i];\n                }\n\n                var encrypt_key = user_key;\n\n                CryptoUtils.SsAes128(Convert.ToBase64String(encrypt_key) + SALT, encrypt.AsSpan(0, 16), encrypt_data.AsSpan(0, 16));\n                Array.Copy(encrypt_data, 0, encrypt, 4, 16);\n                uid.CopyTo(encrypt, 0);\n            }\n            // final HMAC\n            {\n                using var md5 = CreateHMAC(user_key);\n                md5.Update(encrypt.AsSpan(0, 20));\n                var md5data = new byte[md5.Length];\n                md5.GetMac(md5data);\n                last_server_hash = md5data;\n                md5data[..4].CopyTo(encrypt.AsSpan(20, 4));\n            }\n            encrypt.CopyTo(outdata, 12);\n            encryptor = (StreamEncryptor)EncryptorFactory.GetEncryptor(\"chacha20\", Convert.ToBase64String(user_key) + Convert.ToBase64String(last_client_hash, 0, 16));\n            {\n                var iv = new byte[8];\n                Array.Copy(last_client_hash, iv, 8);\n                encryptor.SetIV(iv);\n            }\n            {\n                encryptor.Decrypt(last_server_hash, 8, outdata, out _);\n            }\n\n            // combine first chunk\n            {\n                var pack_outdata = new byte[outdata.Length];\n                PackData(data, datalength, pack_outdata, out var pack_outlength);\n                Array.Copy(pack_outdata, 0, outdata, outlength, pack_outlength);\n                outlength += pack_outlength;\n            }\n        }\n\n        // plaindata == null    try send buffer data, return null if empty buffer\n        // datalength == 0      sendback, return 0\n        // datalength == -1     keepalive\n        public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[datalength + datalength / 10 + 32];\n            var packdata = new byte[9000];\n            var data = plaindata == null ? send_buffer : plaindata;\n            outlength = 0;\n            if (data == null)\n            {\n                return null;\n            }\n\n            if (data == send_buffer)\n            {\n                datalength = send_buffer.Length;\n                send_buffer = null;\n            }\n            else if (send_buffer != null)\n            {\n                if (datalength <= 0)\n                {\n                    return outdata;\n                }\n\n                Array.Resize(ref send_buffer, send_buffer.Length + datalength);\n                Array.Copy(data, 0, send_buffer, send_buffer.Length - datalength, datalength);\n                data = send_buffer;\n                datalength = send_buffer.Length;\n                send_buffer = null;\n            }\n            var unit_len = Server.tcp_mss - Server.overhead;\n            var ogn_datalength = datalength;\n            if (!has_sent_header)\n            {\n                var _datalength = Math.Min(1200, datalength);\n                PackAuthData(data, _datalength, packdata, out var outlen);\n                has_sent_header = true;\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= _datalength;\n                var newdata = new byte[datalength];\n                Array.Copy(data, _datalength, newdata, 0, newdata.Length);\n                data = newdata;\n\n                send_buffer = data.Length > 0 ? data : null;\n\n                return outdata;\n            }\n\n            if (datalength > 120 * 4 && pack_id < 32)\n            {\n                var send_len = LinearRandomInt(120 * 16);\n                if (send_len < datalength)\n                {\n                    send_len = TrapezoidRandomInt(Math.Min(datalength - 1, Server.tcp_mss - overhead) - 1, -0.3) + 1;  // must less than datalength\n\n                    send_len = datalength - send_len;\n\n                    if (send_len > 0)\n                    {\n                        send_buffer = new byte[send_len];\n                        Array.Copy(data, datalength - send_len, send_buffer, 0, send_len);\n                        datalength -= send_len;\n                    }\n                }\n            }\n            while (datalength > unit_len)\n            {\n                PackData(data, unit_len, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= unit_len;\n                var newdata = new byte[datalength];\n                Array.Copy(data, unit_len, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            if (datalength > 0 || ogn_datalength == -1)\n            {\n                if (ogn_datalength == -1)\n                {\n                    datalength = 0;\n                }\n\n                PackData(data, datalength, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n            }\n            last_datalength = ogn_datalength;\n            return outdata;\n        }\n\n        public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[recv_buf_len + datalength];\n            Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength);\n            recv_buf_len += datalength;\n            outlength = 0;\n            var key = new byte[user_key.Length + 4];\n            user_key.CopyTo(key, 0);\n            while (recv_buf_len > 4)\n            {\n                BitConverter.GetBytes(recv_id).CopyTo(key, key.Length - 4);\n                using var md5 = CreateHMAC(key);\n\n                var data_len = ((recv_buf[1] ^ last_server_hash[15]) << 8) + (recv_buf[0] ^ last_server_hash[14]);\n                var rand_len = GetRecvRandLen(data_len, random_server, last_server_hash);\n                var len = rand_len + data_len;\n                if (len >= 4096)\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data error\");\n                }\n                if (len + 4 > recv_buf_len)\n                {\n                    break;\n                }\n\n                md5.Update(recv_buf.AsSpan(0, len + 2));\n                var md5data = new byte[md5.Length];\n                md5.GetMac(md5data);\n                if (md5data[0] != recv_buf[len + 2]\n                    || md5data[1] != recv_buf[len + 3]\n                    )\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data uncorrect checksum\");\n                }\n\n                {\n                    var pos = 2;\n                    var outlen = data_len;\n                    Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                    var data = new byte[outlen];\n                    Array.Copy(recv_buf, pos, data, 0, outlen);\n                    encryptor.Decrypt(data, outlen, data, out outlen);\n                    last_server_hash = md5data;\n                    if (recv_id == 1)\n                    {\n                        Server.tcp_mss = recv_tcp_mss = data[0] | (data[1] << 8);\n                        pos = 2;\n                        outlen -= 2;\n                        send_back_cmd.Add(0xff00);\n                    }\n                    else\n                    {\n                        pos = 0;\n                    }\n                    Array.Copy(data, pos, outdata, outlength, outlen);\n                    outlength += outlen;\n                    recv_buf_len -= len + 4;\n                    Array.Copy(recv_buf, len + 4, recv_buf, 0, recv_buf_len);\n                    ++recv_id;\n                }\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[datalength + 1024];\n            if (user_key == null)\n            {\n                user_id = new byte[4];\n                var index_of_split = Server.param.IndexOf(':');\n                if (index_of_split > 0)\n                {\n                    try\n                    {\n                        var user = uint.Parse(Server.param.Substring(0, index_of_split));\n                        user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1));\n                        BitConverter.GetBytes(user).CopyTo(user_id, 0);\n                    }\n                    catch (Exception ex)\n                    {\n                        Logging.Log(LogLevel.Warn, $\"Faild to parse auth param, fallback to basic mode. {ex}\");\n                    }\n                }\n                if (user_key == null)\n                {\n                    random.NextBytes(user_id);\n                    user_key = Server.key;\n                }\n            }\n            var auth_data = new byte[3];\n            random.NextBytes(auth_data);\n\n            using var md5 = CreateHMAC(Server.key);\n            md5.Update(auth_data);\n            var md5data = new byte[md5.Length];\n            md5.GetMac(md5data);\n            var rand_len = UdpGetRandLen(random_client, md5data);\n            var rand_data = new byte[rand_len];\n            random.NextBytes(rand_data);\n            outlength = datalength + rand_len + 8;\n            encryptor = (StreamEncryptor)EncryptorFactory.GetEncryptor(\"chacha20\", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16));\n            {\n                var iv = new byte[8];\n                Array.Copy(Server.key, iv, 8);\n                encryptor.SetIV(iv);\n            }\n            encryptor.Encrypt(plaindata, datalength, outdata, out datalength);\n            rand_data.CopyTo(outdata, datalength);\n            auth_data.CopyTo(outdata, outlength - 8);\n            var uid = new byte[4];\n            for (var i = 0; i < 4; ++i)\n            {\n                uid[i] = (byte)(user_id[i] ^ md5data[i]);\n            }\n            uid.CopyTo(outdata, outlength - 5);\n            {\n                using var userMd5 = CreateHMAC(user_key);\n                userMd5.Update(outdata.AsSpan(0, outlength - 1));\n                Span<byte> span = stackalloc byte[userMd5.Length];\n                userMd5.GetMac(span);\n                outdata[outlength - 1] = span[0];\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            if (datalength <= 8)\n            {\n                outlength = 0;\n                return plaindata;\n            }\n\n            using var md5 = CreateHMAC(user_key);\n            md5.Update(plaindata.AsSpan(0, datalength - 1));\n            var md5data = new byte[md5.Length];\n            md5.GetMac(md5data);\n            if (md5data[0] != plaindata[datalength - 1])\n            {\n                outlength = 0;\n                return plaindata;\n            }\n\n            using var serverMd5 = CreateHMAC(Server.key);\n            serverMd5.Update(plaindata.AsSpan(datalength - 8, 7));\n            serverMd5.GetMac(md5data);\n            var rand_len = UdpGetRandLen(random_server, md5data);\n            outlength = datalength - rand_len - 8;\n            encryptor = (StreamEncryptor)EncryptorFactory.GetEncryptor(\"chacha20\", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16));\n            {\n                var iv = new byte[8];\n                Array.Copy(Server.key, iv, 8);\n                encryptor.Decrypt(iv, 8, plaindata, out _);\n            }\n            encryptor.Decrypt(plaindata, outlength, plaindata, out outlength);\n            return plaindata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthAkarin_spec_a.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    class AuthAkarin_spec_a : AuthAkarin\n    {\n        public AuthAkarin_spec_a(string method)\n                : base(method)\n        {\n\n        }\n\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_akarin_spec_a\", new[] { 1, 0, 1 } }\n        };\n\n        protected int[] data_size_list;\n        protected int[] data_size_list2;\n\n        public static new List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        protected void InitDataSizeList()\n        {\n            var rd = new xorshift128plus(0);\n            rd.init_from_bin(Server.key);\n            var len = (int)(rd.next() % 8 + 4);\n            var data_list = new List<int>();\n            for (var i = 0; i < len; ++i)\n            {\n                data_list.Add((int)(rd.next() % 2340 % 2040 % 1440));\n            }\n            data_list.Sort();\n            data_size_list = data_list.ToArray();\n\n            len = (int)(rd.next() % 16 + 8);\n            data_list.Clear();\n            for (var i = 0; i < len; ++i)\n            {\n                data_list.Add((int)(rd.next() % 2340 % 2040 % 1440));\n            }\n            data_list.Sort();\n            data_size_list2 = data_list.ToArray();\n        }\n\n        public override void SetServerInfo(ServerInfo serverInfo)\n        {\n            Server = serverInfo;\n            InitDataSizeList();\n        }\n\n        protected int FindPos(int[] arr, int key)\n        {\n            var low = 0;\n            var high = arr.Length - 1;\n\n            if (key > arr[high])\n            {\n                return arr.Length;\n            }\n\n            while (low < high)\n            {\n                var middle = (low + high) / 2;\n                if (key > arr[middle])\n                {\n                    low = middle + 1;\n                }\n                else if (key <= arr[middle])\n                {\n                    high = middle;\n                }\n            }\n            return low;\n        }\n\n        protected override int GetSendRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            if (datalength + Server.overhead > send_tcp_mss)\n            {\n                rd.init_from_bin(last_hash, datalength);\n                return (int)(rd.next() % 521);\n            }\n            if (datalength >= 1440 || datalength + Server.overhead == recv_tcp_mss)\n            {\n                return 0;\n            }\n\n            rd.init_from_bin(last_hash, datalength);\n\n            var pos = FindPos(data_size_list, datalength + Server.overhead);\n            var final_pos = pos + (int)(rd.next() % (ulong)data_size_list.Length);\n            if (final_pos < data_size_list.Length)\n            {\n                return data_size_list[final_pos] - datalength - Server.overhead;\n            }\n\n            pos = FindPos(data_size_list2, datalength + Server.overhead);\n            final_pos = pos + (int)(rd.next() % (ulong)data_size_list2.Length);\n            if (final_pos < data_size_list2.Length)\n            {\n                return data_size_list2[final_pos] - datalength - Server.overhead;\n            }\n            if (final_pos < pos + data_size_list2.Length - 1)\n            {\n                return 0;\n            }\n            if (datalength > 1300)\n            {\n                return (int)(rd.next() % 31);\n            }\n\n            if (datalength > 900)\n            {\n                return (int)(rd.next() % 127);\n            }\n\n            if (datalength > 400)\n            {\n                return (int)(rd.next() % 521);\n            }\n\n            return (int)(rd.next() % 1021);\n        }\n\n        protected override int GetRecvRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            if (datalength + Server.overhead > recv_tcp_mss)\n            {\n                rd.init_from_bin(last_hash, datalength);\n                return (int)(rd.next() % 521);\n            }\n            if (datalength >= 1440 || datalength + Server.overhead == recv_tcp_mss)\n            {\n                return 0;\n            }\n\n            rd.init_from_bin(last_hash, datalength);\n\n            var pos = FindPos(data_size_list, datalength + Server.overhead);\n            var final_pos = pos + (int)(rd.next() % (ulong)data_size_list.Length);\n            if (final_pos < data_size_list.Length)\n            {\n                return data_size_list[final_pos] - datalength - Server.overhead;\n            }\n\n            pos = FindPos(data_size_list2, datalength + Server.overhead);\n            final_pos = pos + (int)(rd.next() % (ulong)data_size_list2.Length);\n            if (final_pos < data_size_list2.Length)\n            {\n                return data_size_list2[final_pos] - datalength - Server.overhead;\n            }\n            if (final_pos < pos + data_size_list2.Length - 1)\n            {\n                return 0;\n            }\n            if (datalength > 1300)\n            {\n                return (int)(rd.next() % 31);\n            }\n\n            if (datalength > 900)\n            {\n                return (int)(rd.next() % 127);\n            }\n\n            if (datalength > 400)\n            {\n                return (int)(rd.next() % 521);\n            }\n\n            return (int)(rd.next() % 1021);\n        }\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthChain_a.cs",
    "content": "using CryptoBase.Abstractions;\nusing CryptoBase.Digests;\nusing CryptoBase.Macs.Hmac;\nusing Shadowsocks.Controller;\nusing Shadowsocks.Encryption;\nusing Shadowsocks.Enums;\nusing System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\n\nnamespace Shadowsocks.Obfs\n{\n    class AuthChain_a : VerifySimpleBase\n    {\n        protected class AuthDataAesChain : AuthData\n        {\n        }\n\n        public AuthChain_a(string method)\n                : base(method)\n        {\n            has_sent_header = false;\n            has_recv_header = false;\n            pack_id = 1;\n            recv_id = 1;\n            SALT = method;\n            random = new Random(RandomNumberGenerator.GetInt32(int.MaxValue));\n        }\n\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_chain_a\", new[] { 1, 0, 1 } }\n        };\n\n        protected bool has_sent_header;\n        protected bool has_recv_header;\n        protected string SALT;\n\n        protected uint pack_id;\n        protected uint recv_id;\n        protected byte[] user_key;\n        protected byte[] user_id;\n        protected byte[] send_buffer;\n        protected int last_datalength;\n        protected byte[] last_client_hash;\n        protected byte[] last_server_hash;\n        protected xorshift128plus random_client = new();\n        protected xorshift128plus random_server = new();\n        protected IEncryptor encryptor;\n\n        protected const int overhead = 4;\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        protected override void Disposing()\n        {\n            if (encryptor != null)\n            {\n                encryptor.Dispose();\n                encryptor = null;\n            }\n        }\n\n        public override object InitData()\n        {\n            return new AuthDataAesChain();\n        }\n\n        public override bool isKeepAlive()\n        {\n            return true;\n        }\n\n        public override bool isAlwaysSendback()\n        {\n            return true;\n        }\n\n        public override int GetOverhead()\n        {\n            return overhead;\n        }\n\n        protected IMac CreateHMAC(byte[] key)\n        {\n            return HmacUtils.Create(DigestType.Md5, key);\n        }\n\n        protected virtual int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            if (datalength > 1440)\n            {\n                return 0;\n            }\n\n            rd.init_from_bin(last_hash, datalength);\n            if (datalength > 1300)\n            {\n                return (int)(rd.next() % 31);\n            }\n\n            if (datalength > 900)\n            {\n                return (int)(rd.next() % 127);\n            }\n\n            if (datalength > 400)\n            {\n                return (int)(rd.next() % 521);\n            }\n\n            return (int)(rd.next() % 1021);\n        }\n\n        protected int UdpGetRandLen(xorshift128plus rd, byte[] last_hash)\n        {\n            rd.init_from_bin(last_hash);\n            return (int)(rd.next() % 127);\n        }\n\n        protected int GetRandStartPos(int rand_len, xorshift128plus rd)\n        {\n            if (rand_len > 0)\n            {\n                return (int)(rd.next() % 8589934609 % (ulong)rand_len);\n            }\n\n            return 0;\n        }\n\n        protected int GetRandLen(int datalength)\n        {\n            return GetRandLen(datalength, random_client, last_client_hash);\n        }\n\n        public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var rand_len = GetRandLen(datalength);\n            outlength = rand_len + datalength + 2;\n            outdata[0] = (byte)(datalength ^ last_client_hash[14]);\n            outdata[1] = (byte)((datalength >> 8) ^ last_client_hash[15]);\n            {\n                var rnd_data = new byte[rand_len];\n                random.NextBytes(rnd_data);\n                encryptor.Encrypt(data, datalength, data, out datalength);\n                if (datalength > 0)\n                {\n                    if (rand_len > 0)\n                    {\n                        var start_pos = GetRandStartPos(rand_len, random_client);\n                        Array.Copy(data, 0, outdata, 2 + start_pos, datalength);\n                        Array.Copy(rnd_data, 0, outdata, 2, start_pos);\n                        Array.Copy(rnd_data, start_pos, outdata, 2 + start_pos + datalength, rand_len - start_pos);\n                    }\n                    else\n                    {\n                        Array.Copy(data, 0, outdata, 2, datalength);\n                    }\n                }\n                else\n                {\n                    rnd_data.CopyTo(outdata, 2);\n                }\n            }\n\n            var key = new byte[user_key.Length + 4];\n            user_key.CopyTo(key, 0);\n            BitConverter.GetBytes(pack_id).CopyTo(key, key.Length - 4);\n\n            using var md5 = CreateHMAC(key);\n            ++pack_id;\n            {\n                md5.Update(outdata.AsSpan(0, outlength));\n                var md5data = new byte[md5.Length];\n                md5.GetMac(md5data);\n                last_client_hash = md5data;\n                md5data[..2].CopyTo(outdata.AsSpan(outlength, 2));\n                outlength += 2;\n            }\n        }\n\n        public virtual void OnInitAuthData(ulong unixTimestamp)\n        {\n\n        }\n\n        public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            const int authhead_len = 4 + 8 + 4 + 16 + 4;\n            var encrypt = new byte[24];\n\n            if (Server.data is AuthDataAesChain authData)\n            {\n                lock (authData)\n                {\n                    if (authData.connectionID > 0xFF000000)\n                    {\n                        authData.clientID = null;\n                    }\n\n                    if (authData.clientID == null)\n                    {\n                        authData.clientID = RandomNumberGenerator.GetBytes(4);\n                        authData.connectionID = (uint)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD;\n                    }\n\n                    authData.connectionID += 1;\n                    Array.Copy(authData.clientID, 0, encrypt, 4, 4);\n                    Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, encrypt, 8, 4);\n                }\n            }\n\n            outlength = authhead_len;\n            var encrypt_data = new byte[32];\n            var key = new byte[Server.Iv.Length + Server.key.Length];\n            Server.Iv.CopyTo(key, 0);\n            Server.key.CopyTo(key, Server.Iv.Length);\n\n            var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);\n            var utc_time = (uint)utc_time_second;\n            Array.Copy(BitConverter.GetBytes(utc_time), 0, encrypt, 0, 4);\n            OnInitAuthData(utc_time_second);\n\n            encrypt[12] = (byte)Server.overhead;\n            encrypt[13] = (byte)(Server.overhead >> 8);\n\n            // first 12 bytes\n            {\n                Span<byte> rnd = stackalloc byte[4];\n                RandomNumberGenerator.Fill(rnd);\n                rnd.CopyTo(outdata);\n                using var md5 = CreateHMAC(key);\n                md5.Update(rnd);\n                var md5data = new byte[md5.Length];\n                md5.GetMac(md5data);\n                last_client_hash = md5data;\n                md5data[..8].CopyTo(outdata.AsSpan(rnd.Length, 8));\n            }\n            // uid & 16 bytes auth data\n            {\n                var uid = new byte[4];\n                var index_of_split = Server.param.IndexOf(':');\n                if (index_of_split > 0)\n                {\n                    try\n                    {\n                        var user = uint.Parse(Server.param.Substring(0, index_of_split));\n                        user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1));\n                        BitConverter.GetBytes(user).CopyTo(uid, 0);\n                    }\n                    catch (Exception ex)\n                    {\n                        Logging.Log(LogLevel.Warn, $\"Faild to parse auth param, fallback to basic mode. {ex}\");\n                    }\n                }\n                if (user_key == null)\n                {\n                    random.NextBytes(uid);\n                    user_key = Server.key;\n                }\n                for (var i = 0; i < 4; ++i)\n                {\n                    uid[i] ^= last_client_hash[8 + i];\n                }\n\n                var encrypt_key = user_key;\n\n                CryptoUtils.SsAes128(Convert.ToBase64String(encrypt_key) + SALT, encrypt.AsSpan(0, 16), encrypt_data.AsSpan(0, 16));\n                Array.Copy(encrypt_data, 0, encrypt, 4, 16);\n                uid.CopyTo(encrypt, 0);\n            }\n            // final HMAC\n            {\n                using var md5 = CreateHMAC(user_key);\n                md5.Update(encrypt.AsSpan(0, 20));\n                var md5data = new byte[md5.Length];\n                md5.GetMac(md5data);\n                last_server_hash = md5data;\n                md5data[..4].CopyTo(encrypt.AsSpan(20, 4));\n            }\n            encrypt.CopyTo(outdata, 12);\n            encryptor = EncryptorFactory.GetEncryptor(\"rc4\", Convert.ToBase64String(user_key) + Convert.ToBase64String(last_client_hash, 0, 16));\n\n            // combine first chunk\n            {\n                var pack_outdata = new byte[outdata.Length];\n                PackData(data, datalength, pack_outdata, out var pack_outlength);\n                Array.Copy(pack_outdata, 0, outdata, outlength, pack_outlength);\n                outlength += pack_outlength;\n            }\n        }\n\n        // plaindata == null    try send buffer data, return null if empty buffer\n        // datalength == 0      sendback, return 0\n        // datalength == -1     keepalive\n        public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[datalength + datalength / 10 + 32];\n            var packdata = new byte[9000];\n            var data = plaindata == null ? send_buffer : plaindata;\n            outlength = 0;\n            if (data == null)\n            {\n                return null;\n            }\n\n            if (data == send_buffer)\n            {\n                datalength = send_buffer.Length;\n                send_buffer = null;\n            }\n            else if (send_buffer != null)\n            {\n                if (datalength <= 0)\n                {\n                    return outdata;\n                }\n\n                Array.Resize(ref send_buffer, send_buffer.Length + datalength);\n                Array.Copy(data, 0, send_buffer, send_buffer.Length - datalength, datalength);\n                data = send_buffer;\n                datalength = send_buffer.Length;\n                send_buffer = null;\n            }\n            var unit_len = Server.tcp_mss - Server.overhead;\n            var ogn_datalength = datalength;\n            if (!has_sent_header)\n            {\n                var _datalength = Math.Min(1200, datalength);\n                PackAuthData(data, _datalength, packdata, out var outlen);\n                has_sent_header = true;\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= _datalength;\n                var newdata = new byte[datalength];\n                Array.Copy(data, _datalength, newdata, 0, newdata.Length);\n                data = newdata;\n\n                send_buffer = data.Length > 0 ? data : null;\n\n                return outdata;\n            }\n\n            if (datalength > 120 * 4 && pack_id < 32)\n            {\n                var send_len = LinearRandomInt(120 * 16);\n                if (send_len < datalength)\n                {\n                    send_len = TrapezoidRandomInt(Math.Min(datalength - 1, Server.tcp_mss - overhead) - 1, -0.3) + 1;  // must less than datalength\n\n                    send_len = datalength - send_len;\n\n                    if (send_len > 0)\n                    {\n                        send_buffer = new byte[send_len];\n                        Array.Copy(data, datalength - send_len, send_buffer, 0, send_len);\n                        datalength -= send_len;\n                    }\n                }\n            }\n            while (datalength > unit_len)\n            {\n                PackData(data, unit_len, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= unit_len;\n                var newdata = new byte[datalength];\n                Array.Copy(data, unit_len, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            if (datalength > 0 || ogn_datalength == -1)\n            {\n                if (ogn_datalength == -1)\n                {\n                    datalength = 0;\n                }\n\n                PackData(data, datalength, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n            }\n            last_datalength = ogn_datalength;\n            return outdata;\n        }\n\n        public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[recv_buf_len + datalength];\n            Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength);\n            recv_buf_len += datalength;\n            outlength = 0;\n            var key = new byte[user_key.Length + 4];\n            user_key.CopyTo(key, 0);\n            while (recv_buf_len > 4)\n            {\n                BitConverter.GetBytes(recv_id).CopyTo(key, key.Length - 4);\n                using var md5 = CreateHMAC(key);\n\n                var data_len = ((recv_buf[1] ^ last_server_hash[15]) << 8) + (recv_buf[0] ^ last_server_hash[14]);\n                var rand_len = GetRandLen(data_len, random_server, last_server_hash);\n                var len = rand_len + data_len;\n                if (len >= 4096)\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data error\");\n                }\n                if (len + 4 > recv_buf_len)\n                {\n                    break;\n                }\n\n                md5.Update(recv_buf.AsSpan(0, len + 2));\n                var md5data = new byte[md5.Length];\n                md5.GetMac(md5data);\n                if (md5data[0] != recv_buf[len + 2]\n                    || md5data[1] != recv_buf[len + 3]\n                )\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data uncorrect checksum\");\n                }\n\n                {\n                    int pos;\n                    if (data_len > 0 && rand_len > 0)\n                    {\n                        pos = 2 + GetRandStartPos(rand_len, random_server);\n                    }\n                    else\n                    {\n                        pos = 2;\n                    }\n                    var outlen = data_len;\n                    Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                    var data = new byte[outlen];\n                    Array.Copy(recv_buf, pos, data, 0, outlen);\n                    encryptor.Decrypt(data, outlen, data, out outlen);\n                    last_server_hash = md5data;\n                    if (recv_id == 1)\n                    {\n                        Server.tcp_mss = data[0] | (data[1] << 8);\n                        pos = 2;\n                        outlen -= 2;\n                    }\n                    else\n                    {\n                        pos = 0;\n                    }\n                    Array.Copy(data, pos, outdata, outlength, outlen);\n                    outlength += outlen;\n                    recv_buf_len -= len + 4;\n                    Array.Copy(recv_buf, len + 4, recv_buf, 0, recv_buf_len);\n                    ++recv_id;\n                }\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[datalength + 1024];\n            if (user_key == null)\n            {\n                user_id = new byte[4];\n                var index_of_split = Server.param.IndexOf(':');\n                if (index_of_split > 0)\n                {\n                    try\n                    {\n                        var user = uint.Parse(Server.param.Substring(0, index_of_split));\n                        user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1));\n                        BitConverter.GetBytes(user).CopyTo(user_id, 0);\n                    }\n                    catch (Exception ex)\n                    {\n                        Logging.Log(LogLevel.Warn, $\"Faild to parse auth param, fallback to basic mode. {ex}\");\n                    }\n                }\n                if (user_key == null)\n                {\n                    random.NextBytes(user_id);\n                    user_key = Server.key;\n                }\n            }\n            var auth_data = new byte[3];\n            random.NextBytes(auth_data);\n\n            using var md5 = CreateHMAC(Server.key);\n            md5.Update(auth_data);\n            var md5data = new byte[md5.Length];\n            md5.GetMac(md5data);\n            var rand_len = UdpGetRandLen(random_client, md5data);\n            var rand_data = new byte[rand_len];\n            random.NextBytes(rand_data);\n            outlength = datalength + rand_len + 8;\n            encryptor = EncryptorFactory.GetEncryptor(\"rc4\", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16));\n            encryptor.Encrypt(plaindata, datalength, outdata, out datalength);\n            rand_data.CopyTo(outdata, datalength);\n            auth_data.CopyTo(outdata, outlength - 8);\n            var uid = new byte[4];\n            for (var i = 0; i < 4; ++i)\n            {\n                uid[i] = (byte)(user_id[i] ^ md5data[i]);\n            }\n            uid.CopyTo(outdata, outlength - 5);\n            {\n                using var userMd5 = CreateHMAC(user_key);\n                userMd5.Update(outdata.AsSpan(0, outlength - 1));\n                Span<byte> span = stackalloc byte[userMd5.Length];\n                userMd5.GetMac(span);\n                outdata[outlength - 1] = span[0];\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            if (datalength <= 8)\n            {\n                outlength = 0;\n                return plaindata;\n            }\n\n            using var md5 = CreateHMAC(user_key);\n            md5.Update(plaindata.AsSpan(0, datalength - 1));\n            var md5data = new byte[md5.Length];\n            md5.GetMac(md5data);\n            if (md5data[0] != plaindata[datalength - 1])\n            {\n                outlength = 0;\n                return plaindata;\n            }\n\n            using var serverMd5 = CreateHMAC(Server.key);\n            serverMd5.Update(plaindata.AsSpan(datalength - 8, 7));\n            serverMd5.GetMac(md5data);\n            var rand_len = UdpGetRandLen(random_server, md5data);\n            outlength = datalength - rand_len - 8;\n            encryptor = EncryptorFactory.GetEncryptor(\"rc4\", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16));\n            encryptor.Decrypt(plaindata, outlength, plaindata, out outlength);\n            return plaindata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthChain_b.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    class AuthChain_b : AuthChain_a\n    {\n        public AuthChain_b(string method)\n                : base(method)\n        {\n\n        }\n\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_chain_b\", new[] { 1, 0, 1 } }\n        };\n\n        protected int[] data_size_list;\n        protected int[] data_size_list2;\n\n        public static new List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        protected virtual void InitDataSizeList()\n        {\n            var rd = new xorshift128plus();\n            rd.init_from_bin(Server.key);\n            var len = (int)(rd.next() % 8 + 4);\n            var data_list = new List<int>();\n            for (var i = 0; i < len; ++i)\n            {\n                data_list.Add((int)(rd.next() % 2340 % 2040 % 1440));\n            }\n            data_list.Sort();\n            data_size_list = data_list.ToArray();\n\n            len = (int)(rd.next() % 16 + 8);\n            data_list.Clear();\n            for (var i = 0; i < len; ++i)\n            {\n                data_list.Add((int)(rd.next() % 2340 % 2040 % 1440));\n            }\n            data_list.Sort();\n            data_size_list2 = data_list.ToArray();\n        }\n\n        public override void SetServerInfo(ServerInfo serverInfo)\n        {\n            Server = serverInfo;\n            InitDataSizeList();\n        }\n\n        protected int FindPos(int[] arr, int key)\n        {\n            var low = 0;\n            var high = arr.Length - 1;\n\n            if (key > arr[high])\n            {\n                return arr.Length;\n            }\n\n            while (low < high)\n            {\n                var middle = (low + high) / 2;\n                if (key > arr[middle])\n                {\n                    low = middle + 1;\n                }\n                else if (key <= arr[middle])\n                {\n                    high = middle;\n                }\n            }\n            return low;\n        }\n\n        protected override int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            if (datalength >= 1440)\n            {\n                return 0;\n            }\n\n            rd.init_from_bin(last_hash, datalength);\n\n            var pos = FindPos(data_size_list, datalength + Server.overhead);\n            var final_pos = pos + (int)(rd.next() % (ulong)data_size_list.Length);\n            if (final_pos < data_size_list.Length)\n            {\n                return data_size_list[final_pos] - datalength - Server.overhead;\n            }\n\n            pos = FindPos(data_size_list2, datalength + Server.overhead);\n            final_pos = pos + (int)(rd.next() % (ulong)data_size_list2.Length);\n            if (final_pos < data_size_list2.Length)\n            {\n                return data_size_list2[final_pos] - datalength - Server.overhead;\n            }\n            if (final_pos < pos + data_size_list2.Length - 1)\n            {\n                return 0;\n            }\n            if (datalength > 1300)\n            {\n                return (int)(rd.next() % 31);\n            }\n\n            if (datalength > 900)\n            {\n                return (int)(rd.next() % 127);\n            }\n\n            if (datalength > 400)\n            {\n                return (int)(rd.next() % 521);\n            }\n\n            return (int)(rd.next() % 1021);\n        }\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthChain_c.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    class AuthChain_c : AuthChain_b\n    {\n        public AuthChain_c(string method)\n                : base(method)\n        {\n\n        }\n\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_chain_c\", new[] { 1, 0, 1 } }\n        };\n\n        protected int[] data_size_list0;\n\n        public static new List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        protected override void InitDataSizeList()\n        {\n            var rd = new xorshift128plus();\n            rd.init_from_bin(Server.key);\n            var len = (int)(rd.next() % (8 + 16) + (4 + 8));\n            var data_list = new List<int>();\n            for (var i = 0; i < len; ++i)\n            {\n                data_list.Add((int)(rd.next() % 2340 % 2040 % 1440));\n            }\n            data_list.Sort();\n            data_size_list0 = data_list.ToArray();\n        }\n\n        public override void SetServerInfo(ServerInfo serverInfo)\n        {\n            Server = serverInfo;\n            InitDataSizeList();\n        }\n\n        protected override int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            var other_data_size = datalength + Server.overhead;\n\n            // 一定要在random使用前初始化，以保证服务器与客户端同步，保证包大小验证结果正确\n            rd.init_from_bin(last_hash, datalength);\n            if (other_data_size >= data_size_list0[data_size_list0.Length - 1])\n            {\n                if (datalength >= 1440)\n                {\n                    return 0;\n                }\n\n                if (datalength > 1300)\n                {\n                    return (int)(rd.next() % 31);\n                }\n\n                if (datalength > 900)\n                {\n                    return (int)(rd.next() % 127);\n                }\n\n                if (datalength > 400)\n                {\n                    return (int)(rd.next() % 521);\n                }\n\n                return (int)(rd.next() % 1021);\n            }\n\n            var pos = FindPos(data_size_list0, other_data_size);\n            var final_pos = pos + (int)(rd.next() % (ulong)(data_size_list0.Length - pos));\n            return data_size_list0[final_pos] - other_data_size;\n        }\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthChain_d.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    class AuthChain_d : AuthChain_c\n    {\n        public AuthChain_d(string method)\n                : base(method)\n        {\n\n        }\n\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_chain_d\", new[] { 1, 0, 1 } }\n        };\n\n        public static new List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        protected void CheckAndPatchDataSize(List<int> data_list, xorshift128plus rd)\n        {\n            if (data_list[data_list.Count - 1] < 1300 && data_list.Count < 64)\n            {\n                data_list.Add((int)(rd.next() % 2340 % 2040 % 1440));\n                CheckAndPatchDataSize(data_list, rd);\n            }\n        }\n\n        protected override void InitDataSizeList()\n        {\n            var rd = new xorshift128plus();\n            rd.init_from_bin(Server.key);\n            var len = (int)(rd.next() % (8 + 16) + (4 + 8));\n            var data_list = new List<int>();\n            for (var i = 0; i < len; ++i)\n            {\n                data_list.Add((int)(rd.next() % 2340 % 2040 % 1440));\n            }\n            data_list.Sort();\n            var old_len = data_list.Count;\n            CheckAndPatchDataSize(data_list, rd);\n            if (old_len != data_list.Count)\n            {\n                data_list.Sort();\n            }\n            data_size_list0 = data_list.ToArray();\n        }\n\n        public override void SetServerInfo(ServerInfo serverInfo)\n        {\n            Server = serverInfo;\n            InitDataSizeList();\n        }\n\n        protected override int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            var other_data_size = datalength + Server.overhead;\n\n            if (other_data_size >= data_size_list0[data_size_list0.Length - 1])\n            {\n                return 0;\n            }\n\n            rd.init_from_bin(last_hash, datalength);\n            var pos = FindPos(data_size_list0, other_data_size);\n            var final_pos = pos + (int)(rd.next() % (ulong)(data_size_list0.Length - pos));\n            return data_size_list0[final_pos] - other_data_size;\n        }\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthChain_e.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    class AuthChain_e : AuthChain_d\n    {\n        public AuthChain_e(string method)\n                : base(method)\n        {\n\n        }\n\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_chain_e\", new[] { 1, 0, 1 } }\n        };\n\n        public static new List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        protected override int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash)\n        {\n            rd.init_from_bin(last_hash, datalength);\n            var other_data_size = datalength + Server.overhead;\n\n            if (other_data_size >= data_size_list0[data_size_list0.Length - 1])\n            {\n                return 0;\n            }\n\n            var pos = FindPos(data_size_list0, other_data_size);\n            return data_size_list0[pos] - other_data_size;\n        }\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthChain_f.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    class AuthChain_f : AuthChain_e\n    {\n        public AuthChain_f(string method)\n                : base(method)\n        {\n\n        }\n\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_chain_f\", new[] { 1, 0, 1 } }\n        };\n\n        public static new List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        protected ulong key_change_interval = 60 * 60 * 24;    // a day by second\n        protected ulong key_change_datetime_key;\n        protected List<byte> key_change_datetime_key_bytes = new();\n\n        protected override void InitDataSizeList()\n        {\n            var rd = new xorshift128plus();\n            var newKey = new byte[Server.key.Length];\n            Server.key.CopyTo(newKey, 0);\n            for (var i = 0; i < 8; i++)\n            {\n                newKey[i] ^= key_change_datetime_key_bytes[i];\n            }\n            rd.init_from_bin(newKey);\n            var len = (int)(rd.next() % (8 + 16) + (4 + 8));\n            var data_list = new List<int>();\n            for (var i = 0; i < len; ++i)\n            {\n                data_list.Add((int)(rd.next() % 2340 % 2040 % 1440));\n            }\n            data_list.Sort();\n            var old_len = data_list.Count;\n            CheckAndPatchDataSize(data_list, rd);\n            if (old_len != data_list.Count)\n            {\n                data_list.Sort();\n            }\n            data_size_list0 = data_list.ToArray();\n        }\n\n        public override void SetServerInfo(ServerInfo serverInfo)\n        {\n            Server = serverInfo;\n            var protocalParams = serverInfo.param;\n            if (protocalParams != \"\")\n            {\n                if (-1 != protocalParams.IndexOf(\"#\", StringComparison.Ordinal))\n                {\n                    protocalParams = protocalParams.Split('#')[1];\n                }\n\n                if (ulong.TryParse(protocalParams, out var interval))\n                {\n                    key_change_interval = interval;\n                }\n            }\n        }\n\n        public override void OnInitAuthData(ulong unixTimestamp)\n        {\n            key_change_datetime_key = unixTimestamp / key_change_interval;\n            for (var i = 7; i > -1; --i)\n            {\n                var b = (byte)(key_change_datetime_key >> (8 * i) & 0xFF);\n                key_change_datetime_key_bytes.Add(b);\n            }\n            InitDataSizeList();\n        }\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthData.cs",
    "content": "namespace Shadowsocks.Obfs\n{\n    public class AuthData : VerifyData\n    {\n        public byte[] clientID;\n        public uint connectionID;\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthSHA1.cs",
    "content": "using CryptoBase.Digests;\nusing CryptoBase.Macs.Hmac;\nusing System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\n\nnamespace Shadowsocks.Obfs\n{\n    public class AuthSHA1 : VerifySimpleBase\n    {\n        public AuthSHA1(string method)\n                : base(method)\n        {\n            has_sent_header = false;\n            has_recv_header = false;\n        }\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_sha1\", new[] { 1, 0, 1 } }\n        };\n\n        protected bool has_sent_header;\n        protected bool has_recv_header;\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        public override object InitData()\n        {\n            return new AuthData();\n        }\n\n        public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var rand_len = datalength > 1300 ? 1 : LinearRandomInt(64) + 1;\n            outlength = rand_len + datalength + 6;\n            if (datalength > 0)\n            {\n                Array.Copy(data, 0, outdata, rand_len + 2, datalength);\n            }\n\n            outdata[0] = (byte)(outlength >> 8);\n            outdata[1] = (byte)outlength;\n            outdata[2] = (byte)rand_len;\n            var adler = Util.Adler32.CalcAdler32(outdata, outlength - 4);\n            BitConverter.GetBytes((uint)adler).CopyTo(outdata, outlength - 4);\n        }\n\n        public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var rand_len = LinearRandomInt(250) + 1;\n            var data_offset = rand_len + 4 + 2;\n            outlength = data_offset + datalength + 12 + 10;\n            var authData = (AuthData)Server.data;\n            lock (authData)\n            {\n                if (authData.connectionID > 0xFF000000)\n                {\n                    authData.clientID = null;\n                }\n                if (authData.clientID == null)\n                {\n                    authData.clientID = RandomNumberGenerator.GetBytes(4);\n                    authData.connectionID = (uint)LinearRandomInt(0x1000000);\n                }\n                authData.connectionID += 1;\n                Array.Copy(authData.clientID, 0, outdata, data_offset + 4, 4);\n                Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, outdata, data_offset + 8, 4);\n            }\n            var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);\n            var utc_time = (uint)utc_time_second;\n            Array.Copy(BitConverter.GetBytes(utc_time), 0, outdata, data_offset, 4);\n\n            Array.Copy(data, 0, outdata, data_offset + 12, datalength);\n            outdata[4] = (byte)(outlength >> 8);\n            outdata[5] = (byte)outlength;\n            outdata[6] = (byte)rand_len;\n\n            var crc32 = Util.CRC32.CalcCRC32(Server.key, Server.key.Length);\n            BitConverter.GetBytes((uint)crc32).CopyTo(outdata, 0);\n\n            Span<byte> key = new byte[Server.Iv.Length + Server.key.Length];\n            Server.Iv.AsSpan().CopyTo(key);\n            Server.key.AsSpan().CopyTo(key[Server.Iv.Length..]);\n\n            using var hmac = HmacUtils.Create(DigestType.Sha1, key);\n            hmac.Update(outdata.AsSpan(0, outlength - 10));\n            Span<byte> hash = stackalloc byte[hmac.Length];\n            hmac.GetMac(hash);\n\n            hash[..10].CopyTo(outdata.AsSpan(outlength - 10, 10));\n        }\n\n        public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            if (plaindata == null)\n            {\n                outlength = 0;\n                return null;\n            }\n            var outdata = new byte[datalength + datalength / 10 + 32];\n            var packdata = new byte[9000];\n            var data = plaindata;\n            outlength = 0;\n            const int unit_len = 8100;\n            if (!has_sent_header)\n            {\n                var headsize = GetHeadSize(plaindata, 30);\n                var _datalength = Math.Min(LinearRandomInt(32) + headsize, datalength);\n                PackAuthData(data, _datalength, packdata, out var outlen);\n                has_sent_header = true;\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= _datalength;\n                var newdata = new byte[datalength];\n                Array.Copy(data, _datalength, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            while (datalength > unit_len)\n            {\n                PackData(data, unit_len, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= unit_len;\n                var newdata = new byte[datalength];\n                Array.Copy(data, unit_len, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            if (datalength > 0)\n            {\n                PackData(data, datalength, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[recv_buf_len + datalength];\n            Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength);\n            recv_buf_len += datalength;\n            outlength = 0;\n            while (recv_buf_len > 2)\n            {\n                var len = (recv_buf[0] << 8) + recv_buf[1];\n                if (len is >= 8192 or < 7)\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data error\");\n                }\n                if (len > recv_buf_len)\n                {\n                    break;\n                }\n\n                if (Util.Adler32.CheckAdler32(recv_buf, len))\n                {\n                    var pos = recv_buf[2] + 2;\n                    var outlen = len - pos - 4;\n                    Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                    Array.Copy(recv_buf, pos, outdata, outlength, outlen);\n                    outlength += outlen;\n                    recv_buf_len -= len;\n                    Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len);\n                }\n                else\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data uncorrect checksum\");\n                }\n            }\n            return outdata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthSHA1V2.cs",
    "content": "using CryptoBase.Digests;\nusing CryptoBase.Macs.Hmac;\nusing System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\n\nnamespace Shadowsocks.Obfs\n{\n    public class AuthSHA1V2 : VerifySimpleBase\n    {\n        public AuthSHA1V2(string method)\n                : base(method)\n        {\n            has_sent_header = false;\n            has_recv_header = false;\n        }\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_sha1_v2\", new[] { 1, 0, 1 } }\n        };\n\n        protected bool has_sent_header;\n        protected bool has_recv_header;\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        public override object InitData()\n        {\n            return new AuthData();\n        }\n\n        public override bool isKeepAlive()\n        {\n            return true;\n        }\n\n        public override bool isAlwaysSendback()\n        {\n            return true;\n        }\n\n        public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var rand_len = (datalength >= 1300 ? 0 : datalength > 400 ? LinearRandomInt(128) : LinearRandomInt(1024)) + 1;\n            outlength = rand_len + datalength + 6;\n            if (datalength > 0)\n            {\n                Array.Copy(data, 0, outdata, rand_len + 2, datalength);\n            }\n\n            outdata[0] = (byte)(outlength >> 8);\n            outdata[1] = (byte)outlength;\n            {\n                var rnd_data = new byte[rand_len];\n                random.NextBytes(rnd_data);\n                rnd_data.CopyTo(outdata, 2);\n            }\n            if (rand_len < 128)\n            {\n                outdata[2] = (byte)rand_len;\n            }\n            else\n            {\n                outdata[2] = 0xFF;\n                outdata[3] = (byte)(rand_len >> 8);\n                outdata[4] = (byte)rand_len;\n            }\n            var adler = Util.Adler32.CalcAdler32(outdata, outlength - 4);\n            BitConverter.GetBytes((uint)adler).CopyTo(outdata, outlength - 4);\n        }\n\n        public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var rand_len = (datalength > 400 ? LinearRandomInt(128) : LinearRandomInt(1024)) + 1;\n            var data_offset = rand_len + 4 + 2;\n            outlength = data_offset + datalength + 12 + 10;\n            var authData = (AuthData)Server.data;\n            {\n                var rnd_data = new byte[rand_len];\n                random.NextBytes(rnd_data);\n                rnd_data.CopyTo(outdata, data_offset - rand_len);\n            }\n            lock (authData)\n            {\n                if (authData.connectionID > 0xFF000000)\n                {\n                    authData.clientID = null;\n                }\n                if (authData.clientID == null)\n                {\n                    authData.clientID = RandomNumberGenerator.GetBytes(8);\n                    authData.connectionID = (uint)BitConverter.ToInt64(authData.clientID, 0) % 0xFFFFFD;\n                }\n                authData.connectionID += 1;\n                Array.Copy(authData.clientID, 0, outdata, data_offset, 8);\n                Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, outdata, data_offset + 8, 4);\n            }\n\n            Array.Copy(data, 0, outdata, data_offset + 12, datalength);\n            outdata[4] = (byte)(outlength >> 8);\n            outdata[5] = (byte)outlength;\n            if (rand_len < 128)\n            {\n                outdata[6] = (byte)rand_len;\n            }\n            else\n            {\n                outdata[6] = 0xFF;\n                outdata[7] = (byte)(rand_len >> 8);\n                outdata[8] = (byte)rand_len;\n            }\n\n            var salt = System.Text.Encoding.UTF8.GetBytes(\"auth_sha1_v2\");\n            var crcdata = new byte[salt.Length + Server.key.Length];\n            salt.CopyTo(crcdata, 0);\n            Server.key.CopyTo(crcdata, salt.Length);\n            var crc32 = Util.CRC32.CalcCRC32(crcdata, crcdata.Length);\n            BitConverter.GetBytes((uint)crc32).CopyTo(outdata, 0);\n\n            Span<byte> key = new byte[Server.Iv.Length + Server.key.Length];\n            Server.Iv.AsSpan().CopyTo(key);\n            Server.key.AsSpan().CopyTo(key[Server.Iv.Length..]);\n\n            using var hmac = HmacUtils.Create(DigestType.Sha1, key);\n            hmac.Update(outdata.AsSpan(0, outlength - 10));\n            Span<byte> hash = stackalloc byte[hmac.Length];\n            hmac.GetMac(hash);\n\n            hash[..10].CopyTo(outdata.AsSpan(outlength - 10, 10));\n        }\n\n        public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            if (plaindata == null)\n            {\n                outlength = 0;\n                return null;\n            }\n            var outdata = new byte[datalength + datalength / 10 + 32];\n            var packdata = new byte[9000];\n            var data = plaindata;\n            outlength = 0;\n            const int unit_len = 8100;\n            var ogn_datalength = datalength;\n            if (!has_sent_header)\n            {\n                var headsize = GetHeadSize(plaindata, 30);\n                var _datalength = Math.Min(LinearRandomInt(32) + headsize, datalength);\n                PackAuthData(data, _datalength, packdata, out var outlen);\n                has_sent_header = true;\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= _datalength;\n                var newdata = new byte[datalength];\n                Array.Copy(data, _datalength, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            while (datalength > unit_len)\n            {\n                PackData(data, unit_len, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= unit_len;\n                var newdata = new byte[datalength];\n                Array.Copy(data, unit_len, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            if (datalength > 0 || ogn_datalength == -1)\n            {\n                if (ogn_datalength == -1)\n                {\n                    datalength = 0;\n                }\n\n                PackData(data, datalength, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[recv_buf_len + datalength];\n            Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength);\n            recv_buf_len += datalength;\n            outlength = 0;\n            while (recv_buf_len > 2)\n            {\n                var len = (recv_buf[0] << 8) + recv_buf[1];\n                if (len is >= 8192 or < 8)\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data error\");\n                }\n                if (len > recv_buf_len)\n                {\n                    break;\n                }\n\n                if (Util.Adler32.CheckAdler32(recv_buf, len))\n                {\n                    int pos = recv_buf[2];\n                    if (pos < 255)\n                    {\n                        pos += 2;\n                    }\n                    else\n                    {\n                        pos = ((recv_buf[3] << 8) | recv_buf[4]) + 2;\n                    }\n                    var outlen = len - pos - 4;\n                    Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                    Array.Copy(recv_buf, pos, outdata, outlength, outlen);\n                    outlength += outlen;\n                    recv_buf_len -= len;\n                    Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len);\n                }\n                else\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data uncorrect checksum\");\n                }\n            }\n            return outdata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/AuthSHA1V4.cs",
    "content": "using CryptoBase.Digests;\nusing CryptoBase.Macs.Hmac;\nusing System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\n\nnamespace Shadowsocks.Obfs\n{\n    public class AuthSHA1V4 : VerifySimpleBase\n    {\n        public AuthSHA1V4(string method)\n                : base(method)\n        {\n            has_sent_header = false;\n            has_recv_header = false;\n        }\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"auth_sha1_v4\", new[] { 1, 0, 1 } }\n        };\n\n        protected bool has_sent_header;\n        protected bool has_recv_header;\n        protected const string SALT = \"auth_sha1_v4\";\n        protected const int overhead = 9;\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        public override object InitData()\n        {\n            return new AuthData();\n        }\n\n        public override bool isKeepAlive()\n        {\n            return true;\n        }\n\n        public override bool isAlwaysSendback()\n        {\n            return true;\n        }\n\n        public override int GetOverhead()\n        {\n            return overhead;\n        }\n\n        public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var rand_len = (datalength > 1200 ? 0 : datalength > 400 ? LinearRandomInt(256) : LinearRandomInt(512)) + 1;\n            outlength = rand_len + datalength + 8;\n            if (datalength > 0)\n            {\n                Array.Copy(data, 0, outdata, rand_len + 4, datalength);\n            }\n\n            outdata[0] = (byte)(outlength >> 8);\n            outdata[1] = (byte)outlength;\n            var crc32 = Util.CRC32.CalcCRC32(outdata, 2);\n            BitConverter.GetBytes((ushort)crc32).CopyTo(outdata, 2);\n            {\n                var rnd_data = new byte[rand_len];\n                random.NextBytes(rnd_data);\n                rnd_data.CopyTo(outdata, 4);\n            }\n            if (rand_len < 128)\n            {\n                outdata[4] = (byte)rand_len;\n            }\n            else\n            {\n                outdata[4] = 0xFF;\n                outdata[5] = (byte)(rand_len >> 8);\n                outdata[6] = (byte)rand_len;\n            }\n            var adler = Util.Adler32.CalcAdler32(outdata, outlength - 4);\n            BitConverter.GetBytes((uint)adler).CopyTo(outdata, outlength - 4);\n        }\n\n        public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var rand_len = (datalength > 400 ? LinearRandomInt(128) : LinearRandomInt(1024)) + 1;\n            var data_offset = rand_len + 4 + 2;\n            outlength = data_offset + datalength + 12 + 10;\n            var authData = (AuthData)Server.data;\n            {\n                var rnd_data = new byte[rand_len];\n                random.NextBytes(rnd_data);\n                rnd_data.CopyTo(outdata, data_offset - rand_len);\n            }\n            lock (authData)\n            {\n                if (authData.connectionID > 0xFF000000)\n                {\n                    authData.clientID = null;\n                }\n                if (authData.clientID == null)\n                {\n                    authData.clientID = RandomNumberGenerator.GetBytes(4);\n                    authData.connectionID = (uint)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD;\n                }\n                authData.connectionID += 1;\n                Array.Copy(authData.clientID, 0, outdata, data_offset + 4, 4);\n                Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, outdata, data_offset + 8, 4);\n            }\n            var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);\n            var utc_time = (uint)utc_time_second;\n            Array.Copy(BitConverter.GetBytes(utc_time), 0, outdata, data_offset, 4);\n\n            Array.Copy(data, 0, outdata, data_offset + 12, datalength);\n            outdata[0] = (byte)(outlength >> 8);\n            outdata[1] = (byte)outlength;\n            if (rand_len < 128)\n            {\n                outdata[6] = (byte)rand_len;\n            }\n            else\n            {\n                outdata[6] = 0xFF;\n                outdata[7] = (byte)(rand_len >> 8);\n                outdata[8] = (byte)rand_len;\n            }\n\n            var salt = System.Text.Encoding.UTF8.GetBytes(SALT);\n            var crcdata = new byte[salt.Length + Server.key.Length + 2];\n            salt.CopyTo(crcdata, 2);\n            Server.key.CopyTo(crcdata, salt.Length + 2);\n            crcdata[0] = outdata[0];\n            crcdata[1] = outdata[1];\n            var crc32 = Util.CRC32.CalcCRC32(crcdata, crcdata.Length);\n            BitConverter.GetBytes((uint)crc32).CopyTo(outdata, 2);\n\n            Span<byte> key = new byte[Server.Iv.Length + Server.key.Length];\n            Server.Iv.AsSpan().CopyTo(key);\n            Server.key.AsSpan().CopyTo(key[Server.Iv.Length..]);\n\n            using var hmac = HmacUtils.Create(DigestType.Sha1, key);\n            hmac.Update(outdata.AsSpan(0, outlength - 10));\n            Span<byte> hash = stackalloc byte[hmac.Length];\n            hmac.GetMac(hash);\n\n            hash[..10].CopyTo(outdata.AsSpan(outlength - 10, 10));\n        }\n\n        public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            if (plaindata == null)\n            {\n                outlength = 0;\n                return null;\n            }\n            var outdata = new byte[datalength + datalength / 10 + 32];\n            var packdata = new byte[9000];\n            var data = plaindata;\n            outlength = 0;\n            const int unit_len = 8100;\n            var ogn_datalength = datalength;\n            if (!has_sent_header)\n            {\n                var headsize = GetHeadSize(plaindata, 30);\n                var _datalength = Math.Min(LinearRandomInt(32) + headsize, datalength);\n                PackAuthData(data, _datalength, packdata, out var outlen);\n                has_sent_header = true;\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= _datalength;\n                var newdata = new byte[datalength];\n                Array.Copy(data, _datalength, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            while (datalength > unit_len)\n            {\n                PackData(data, unit_len, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= unit_len;\n                var newdata = new byte[datalength];\n                Array.Copy(data, unit_len, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            if (datalength > 0 || ogn_datalength == -1)\n            {\n                if (ogn_datalength == -1)\n                {\n                    datalength = 0;\n                }\n\n                PackData(data, datalength, packdata, out var outlen);\n                Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[recv_buf_len + datalength];\n            Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength);\n            recv_buf_len += datalength;\n            outlength = 0;\n            while (recv_buf_len > 4)\n            {\n                var crc32 = Util.CRC32.CalcCRC32(recv_buf, 2);\n                if ((uint)((recv_buf[3] << 8) | recv_buf[2]) != ((uint)crc32 & 0xffff))\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data error\");\n                }\n                var len = (recv_buf[0] << 8) + recv_buf[1];\n                if (len is >= 8192 or < 8)\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data error\");\n                }\n                if (len > recv_buf_len)\n                {\n                    break;\n                }\n\n                if (Util.Adler32.CheckAdler32(recv_buf, len))\n                {\n                    int pos = recv_buf[4];\n                    if (pos < 255)\n                    {\n                        pos += 4;\n                    }\n                    else\n                    {\n                        pos = ((recv_buf[5] << 8) | recv_buf[6]) + 4;\n                    }\n                    var outlen = len - pos - 4;\n                    Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                    Array.Copy(recv_buf, pos, outdata, outlength, outlen);\n                    outlength += outlen;\n                    recv_buf_len -= len;\n                    Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len);\n                }\n                else\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data uncorrect checksum\");\n                }\n            }\n            return outdata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/HttpSimpleObfs.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    class HttpSimpleObfs : ObfsBase\n    {\n        public HttpSimpleObfs(string method)\n            : base(method)\n        {\n            has_sent_header = false;\n            //has_recv_header = false;\n            raw_trans_sent = false;\n            raw_trans_recv = false;\n        }\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            //modify original protocol, wrap protocol, obfs param\n            { \"http_simple\", new[] { 0, 1, 1 } },\n            { \"http_post\", new[] { 0, 1, 1 } },\n            { \"random_head\", new[] { 0, 1, 0 } }\n        };\n        private static string[] _request_path = {\n            \"\", \"\",\n            \"login.php?redir=\", \"\",\n            \"register.php?code=\", \"\",\n            \"?keyword=\", \"\",\n            \"search?src=typd&q=\", \"&lang=en\",\n            \"s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&ch=&bar=&wd=\", \"&rn=\",\n            \"post.php?id=\", \"&goto=view.php\"\n        };\n\n        private static string[] _request_useragent = {\n            \"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0\",\n            \"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/44.0\",\n            \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36\",\n            \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36\",\n            \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0\",\n            \"Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)\",\n            \"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27\",\n            \"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C)\",\n            \"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko\",\n            \"Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/BuildID) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36\",\n            \"Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3\",\n            \"Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3\"\n        };\n        private static int _useragent_index = new Random().Next(_request_useragent.Length);\n\n        private bool has_sent_header;\n        //private bool has_recv_header;\n        private bool raw_trans_sent;\n        private bool raw_trans_recv;\n        private List<byte[]> data_buffer = new();\n        private Random random = new();\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        private string data2urlencode(byte[] encryptdata, int datalength)\n        {\n            var ret = \"\";\n            for (var i = 0; i < datalength; ++i)\n            {\n                ret += \"%\" + encryptdata[i].ToString(\"x2\");\n            }\n            return ret;\n        }\n\n        private string boundary()\n        {\n            var set = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n            var ret = \"\";\n            for (var i = 0; i < 32; ++i)\n            {\n                ret += set[random.Next(set.Length)];\n            }\n            return ret;\n        }\n\n        public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength)\n        {\n            if (raw_trans_sent)\n            {\n                SentLength += datalength;\n                outlength = datalength;\n                return encryptdata;\n            }\n\n            var outdata = new byte[datalength + 4096];\n            byte[] headdata;\n            if (Method == \"random_head\")\n            {\n                if (has_sent_header)\n                {\n                    outlength = 0;\n                    if (datalength > 0)\n                    {\n                        var data = new byte[datalength];\n                        Array.Copy(encryptdata, 0, data, 0, datalength);\n                        data_buffer.Add(data);\n                    }\n                    else\n                    {\n                        foreach (var data in data_buffer)\n                        {\n                            Array.Copy(data, 0, outdata, outlength, data.Length);\n                            SentLength += data.Length;\n                            outlength += data.Length;\n                        }\n                        data_buffer.Clear();\n                        raw_trans_sent = true;\n                    }\n                }\n                else\n                {\n                    var size = random.Next(96) + 8;\n                    var rnd = new byte[size];\n                    random.NextBytes(rnd);\n                    Util.CRC32.SetCRC32(rnd);\n                    rnd.CopyTo(outdata, 0);\n                    outlength = rnd.Length;\n\n                    var data = new byte[datalength];\n                    Array.Copy(encryptdata, 0, data, 0, datalength);\n                    data_buffer.Add(data);\n                }\n            }\n            else if (Method is \"http_simple\" or \"http_post\")\n            {\n                var headsize = Server.Iv.Length + Server.head_len;\n                if (datalength - headsize > 64)\n                {\n                    headdata = new byte[headsize + random.Next(0, 64)];\n                }\n                else\n                {\n                    headdata = new byte[datalength];\n                }\n                Array.Copy(encryptdata, 0, headdata, 0, headdata.Length);\n                var request_path_index = new Random().Next(_request_path.Length / 2) * 2;\n                var host = Server.host;\n                var custom_head = \"\";\n                if (Server.param.Length > 0)\n                {\n                    var custom_heads = Server.param.Split(new[] { '#' }, 2);\n                    var param = Server.param;\n                    if (custom_heads.Length > 1)\n                    {\n                        custom_head = custom_heads[1];\n                        param = custom_heads[0];\n                    }\n                    var hosts = param.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);\n                    if (hosts.Length > 0)\n                    {\n                        host = hosts[random.Next(hosts.Length)];\n                        host = host.Trim(' ');\n                    }\n                }\n                var http_buf =\n                        (Method == \"http_post\" ? \"POST /\" : \"GET /\") + _request_path[request_path_index] + data2urlencode(headdata, headdata.Length) + _request_path[request_path_index + 1] + \" HTTP/1.1\\r\\n\"\n                        + \"Host: \" + host + (Server.port == 80 ? \"\" : \":\" + Server.port) + \"\\r\\n\";\n                if (custom_head.Length > 0)\n                {\n                    http_buf += custom_head.Replace(\"\\\\n\", \"\\r\\n\") + \"\\r\\n\\r\\n\";\n                }\n                else\n                {\n                    http_buf +=\n                            \"User-Agent: \" + _request_useragent[_useragent_index] + \"\\r\\n\"\n                            + \"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\\r\\n\"\n                            + \"Accept-Language: en-US,en;q=0.8\\r\\n\"\n                            + \"Accept-Encoding: gzip, deflate\\r\\n\"\n                            + (Method == \"http_post\" ? \"Content-Type: multipart/form-data; boundary=\" + boundary() + \"\\r\\n\" : \"\")\n                            + \"DNT: 1\\r\\n\"\n                            + \"Connection: keep-alive\\r\\n\"\n                            + \"\\r\\n\";\n                }\n                for (var i = 0; i < http_buf.Length; ++i)\n                {\n                    outdata[i] = (byte)http_buf[i];\n                }\n                if (headdata.Length < datalength)\n                {\n                    Array.Copy(encryptdata, headdata.Length, outdata, http_buf.Length, datalength - headdata.Length);\n                }\n                SentLength += headdata.Length;\n                outlength = http_buf.Length + datalength - headdata.Length;\n                raw_trans_sent = true;\n            }\n            else\n            {\n                outlength = 0;\n            }\n            has_sent_header = true;\n            return outdata;\n        }\n\n        private int FindSubArray(byte[] array, int length, byte[] subArray)\n        {\n            for (var pos = 0; pos < length; ++pos)\n            {\n                var offset = 0;\n                for (; offset < subArray.Length; ++offset)\n                {\n                    if (array[pos + offset] != subArray[offset])\n                    {\n                        break;\n                    }\n                }\n                if (offset == subArray.Length)\n                {\n                    return pos;\n                }\n            }\n            return -1;\n        }\n\n        public override byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback)\n        {\n            if (raw_trans_recv)\n            {\n                outlength = datalength;\n                needsendback = false;\n                return encryptdata;\n            }\n\n            var outdata = new byte[datalength];\n            if (Method == \"random_head\")\n            {\n                outlength = 0;\n                raw_trans_recv = true;\n                needsendback = true;\n                return encryptdata;\n            }\n\n            var pos = FindSubArray(encryptdata, datalength, new[] { (byte)'\\r', (byte)'\\n', (byte)'\\r', (byte)'\\n' });\n            if (pos > 0)\n            {\n                outlength = datalength - (pos + 4);\n                Array.Copy(encryptdata, pos + 4, outdata, 0, outlength);\n                raw_trans_recv = true;\n            }\n            else\n            {\n                outlength = 0;\n            }\n            needsendback = false;\n            return outdata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/IObfs.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Obfs\n{\n    public interface IObfs : IDisposable\n    {\n        string Name();\n        bool isKeepAlive();\n        bool isAlwaysSendback();\n        byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength);\n        byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength);\n        byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback);\n        byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength);\n        byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength);\n        byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength);\n        object InitData();\n        void SetServerInfo(ServerInfo serverInfo);\n        void SetServerInfoIV(byte[] iv);\n        long GetSentLength();\n        int GetOverhead();\n        int GetTcpMSS();\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/ObfsBase.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    public abstract class ObfsBase : IObfs\n    {\n        protected ObfsBase(string method)\n        {\n            Method = method;\n        }\n\n        protected string Method;\n        protected ServerInfo Server;\n        protected long SentLength;\n\n        public abstract Dictionary<string, int[]> GetObfs();\n\n        public string Name()\n        {\n            return Method;\n        }\n\n        public virtual bool isKeepAlive()\n        {\n            return false;\n        }\n\n        public virtual bool isAlwaysSendback()\n        {\n            return false;\n        }\n\n\n        public virtual byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            outlength = datalength;\n            return plaindata;\n        }\n        public abstract byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength);\n        public abstract byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback);\n        public virtual byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            outlength = datalength;\n            return plaindata;\n        }\n        public virtual byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            outlength = datalength;\n            return plaindata;\n        }\n        public virtual byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            outlength = datalength;\n            return plaindata;\n        }\n\n        public virtual object InitData()\n        {\n            return null;\n        }\n        public virtual void SetServerInfo(ServerInfo serverInfo)\n        {\n            Server = serverInfo;\n        }\n        public virtual void SetServerInfoIV(byte[] iv)\n        {\n            Server.SetIV(iv);\n        }\n        public static int GetHeadSize(byte[] plaindata, int defaultValue)\n        {\n            if (plaindata == null || plaindata.Length < 2)\n            {\n                return defaultValue;\n            }\n\n            var head_type = plaindata[0] & 0x7;\n            if (head_type == 1)\n            {\n                return 7;\n            }\n\n            if (head_type == 4)\n            {\n                return 19;\n            }\n\n            if (head_type == 3)\n            {\n                return 4 + plaindata[1];\n            }\n\n            if (head_type == 2)\n            {\n                return 4 + plaindata[1];\n            }\n\n            return defaultValue;\n        }\n        public long GetSentLength()\n        {\n            return SentLength;\n        }\n        public virtual int GetOverhead()\n        {\n            return 0;\n        }\n\n        public int GetTcpMSS()\n        {\n            return Server.tcp_mss;\n        }\n\n\n        #region IDisposable\n        protected bool _disposed;\n\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        protected virtual void Dispose(bool disposing)\n        {\n            lock (this)\n            {\n                if (_disposed)\n                {\n                    return;\n                }\n                _disposed = true;\n                Disposing();\n            }\n        }\n\n        protected virtual void Disposing()\n        {\n\n        }\n        #endregion\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/ObfsException.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Obfs\n{\n    public class ObfsException : Exception\n    {\n        public ObfsException(string info)\n                : base(info)\n        {\n\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/ObfsFactory.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    public static class ObfsFactory\n    {\n        private static Dictionary<string, Type> _registeredObfs;\n\n        private static Type[] _constructorTypes = { typeof(string) };\n\n        static ObfsFactory()\n        {\n            _registeredObfs = new Dictionary<string, Type>();\n            foreach (var method in Plain.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(Plain));\n            }\n            foreach (var method in HttpSimpleObfs.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(HttpSimpleObfs));\n            }\n            foreach (var method in TlsTicketAuthObfs.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(TlsTicketAuthObfs));\n            }\n            foreach (var method in VerifyDeflateObfs.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(VerifyDeflateObfs));\n            }\n#if DEBUG\n            foreach (var method in AuthSHA1.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthSHA1));\n            }\n            foreach (var method in AuthSHA1V2.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthSHA1V2));\n            }\n#endif\n            foreach (var method in AuthSHA1V4.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthSHA1V4));\n            }\n            foreach (var method in AuthAES128SHA1.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthAES128SHA1));\n            }\n            foreach (var method in AuthChain_a.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthChain_a));\n            }\n            foreach (var method in AuthChain_b.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthChain_b));\n            }\n            foreach (var method in AuthChain_c.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthChain_c));\n            }\n            foreach (var method in AuthChain_d.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthChain_d));\n            }\n            foreach (var method in AuthChain_e.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthChain_e));\n            }\n            foreach (var method in AuthChain_f.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthChain_f));\n            }\n            foreach (var method in AuthAkarin.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthAkarin));\n            }\n            foreach (var method in AuthAkarin_spec_a.SupportedObfs())\n            {\n                _registeredObfs.Add(method, typeof(AuthAkarin_spec_a));\n            }\n        }\n\n        public static IObfs GetObfs(string method)\n        {\n            if (string.IsNullOrEmpty(method))\n            {\n                method = \"plain\";\n            }\n            method = method.ToLowerInvariant();\n            var t = _registeredObfs[method];\n            var c = t.GetConstructor(_constructorTypes);\n            var result = (IObfs)c?.Invoke(new object[] { method });\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/Plain.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    public class Plain : ObfsBase\n    {\n        public Plain(string method)\n            : base(method)\n        {\n        }\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"plain\", new[] { 0, 0, 0 } },\n            { \"origin\", new[] { 0, 0, 0 } }\n        };\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength)\n        {\n            outlength = datalength;\n            SentLength += outlength;\n            return encryptdata;\n        }\n        public override byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback)\n        {\n            outlength = datalength;\n            needsendback = false;\n            return encryptdata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/ProtocolException.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Obfs\n{\n    public class ProtocolException : Exception\n    {\n        public ProtocolException(string info) : base(info)\n        {\n\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/ServerInfo.cs",
    "content": "namespace Shadowsocks.Obfs\n{\n    public class ServerInfo\n    {\n        public string host;\n        public int port;\n        public string param;\n        public object data;\n        public int tcp_mss;\n        public int overhead;\n        public int buffer_size;\n        public byte[] Iv;\n        public byte[] key;\n        public string key_str;\n        public int head_len;\n\n        public ServerInfo(string host, int port, string param, object data, byte[] iv, string key_str, byte[] key, int head_len, int tcp_mss, int overhead, int buffer_size)\n        {\n            this.host = host;\n            this.port = port;\n            this.param = param;\n            this.data = data;\n            this.Iv = iv;\n            this.key = key;\n            this.key_str = key_str;\n            this.head_len = head_len;\n            this.tcp_mss = tcp_mss;\n            this.overhead = overhead;\n            this.buffer_size = buffer_size;\n        }\n\n        public void SetIV(byte[] iv)\n        {\n            this.Iv = iv;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/TlsAuthData.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    public class TlsAuthData\n    {\n        public byte[] clientID;\n        public Dictionary<string, byte[]> ticket_buf;\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/TlsTicketAuthObfs.cs",
    "content": "using CryptoBase.Digests;\nusing CryptoBase.Macs.Hmac;\nusing System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\n\nnamespace Shadowsocks.Obfs\n{\n    class TlsTicketAuthObfs : ObfsBase\n    {\n        public TlsTicketAuthObfs(string method)\n                : base(method)\n        {\n            handshake_status = 0;\n            if (method == \"tls1.2_ticket_fastauth\")\n            {\n                fastauth = true;\n            }\n        }\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"tls1.2_ticket_auth\", new[] { 0, 1, 1 } },\n            { \"tls1.2_ticket_fastauth\", new[] { 0, 1, 1 } }\n        };\n\n        private int handshake_status;\n        private List<byte[]> data_sent_buffer = new();\n        private byte[] data_recv_buffer = new byte[0];\n        private uint send_id;\n        private bool fastauth;\n\n        protected Random random = new();\n        protected const int overhead = 5;\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        public override object InitData()\n        {\n            return new TlsAuthData();\n        }\n\n        public override bool isAlwaysSendback()\n        {\n            return true;\n        }\n\n        public override int GetOverhead()\n        {\n            return overhead;\n        }\n\n        protected byte[] sni(string url)\n        {\n            if (url == null)\n            {\n                url = \"\";\n            }\n            var b_url = System.Text.Encoding.UTF8.GetBytes(url);\n            var len = b_url.Length;\n            var ret = new byte[len + 9];\n            Array.Copy(b_url, 0, ret, 9, len);\n            ret[7] = (byte)(len >> 8);\n            ret[8] = (byte)len;\n            len += 3;\n            ret[4] = (byte)(len >> 8);\n            ret[5] = (byte)len;\n            len += 2;\n            ret[2] = (byte)(len >> 8);\n            ret[3] = (byte)len;\n            return ret;\n        }\n\n        protected byte to_val(char c)\n        {\n            if (c > '9')\n            {\n                return (byte)(c - 'a' + 10);\n            }\n\n            return (byte)(c - '0');\n        }\n\n        protected byte[] to_bin(string str)\n        {\n            var ret = new byte[str.Length / 2];\n            for (var i = 0; i < str.Length; i += 2)\n            {\n                ret[i / 2] = (byte)((to_val(str[i]) << 4) | to_val(str[i + 1]));\n            }\n            return ret;\n        }\n\n        protected void hmac_sha1(byte[] data, int length)\n        {\n            Span<byte> key = new byte[Server.key.Length + 32];\n            Server.key.AsSpan().CopyTo(key);\n            ((TlsAuthData)Server.data).clientID.AsSpan().CopyTo(key[Server.key.Length..]);\n\n            using var hmac = HmacUtils.Create(DigestType.Sha1, key);\n            hmac.Update(data.AsSpan(0, length - 10));\n            Span<byte> hash = stackalloc byte[hmac.Length];\n            hmac.GetMac(hash);\n            hash[..10].CopyTo(data.AsSpan(length - 10, 10));\n        }\n\n        public void PackAuthData(byte[] outdata)\n        {\n            var authData = (TlsAuthData)Server.data;\n            var outlength = 32;\n            {\n                var randomdata = new byte[18];\n                lock (authData)\n                {\n                    RandomNumberGenerator.Fill(randomdata);\n                }\n                randomdata.CopyTo(outdata, 4);\n            }\n\n            lock (authData)\n            {\n                authData.clientID ??= RandomNumberGenerator.GetBytes(32);\n            }\n            var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);\n            var utc_time = (uint)utc_time_second;\n            var time_bytes = BitConverter.GetBytes(utc_time);\n            Array.Reverse(time_bytes);\n            Array.Copy(time_bytes, 0, outdata, 0, 4);\n\n            hmac_sha1(outdata, outlength);\n        }\n\n        protected void PackData(byte[] data, ref int start, int len, byte[] outdata, ref int outlength)\n        {\n            outdata[outlength] = 0x17;\n            outdata[outlength + 1] = 0x3;\n            outdata[outlength + 2] = 0x3;\n            outdata[outlength + 3] = (byte)(len >> 8);\n            outdata[outlength + 4] = (byte)len;\n            Array.Copy(data, start, outdata, outlength + 5, len);\n            start += len;\n            outlength += len + 5;\n            ++send_id;\n        }\n\n        public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength)\n        {\n            if (handshake_status == -1)\n            {\n                SentLength += datalength;\n                outlength = datalength;\n                return encryptdata;\n            }\n            var outdata = new byte[datalength + 4096];\n            if ((handshake_status & 4) == 4)\n            {\n                var start = 0;\n                outlength = 0;\n                while (send_id <= 4 && datalength - start > 256)\n                {\n                    var len = random.Next(512) + 64;\n                    if (len > datalength - start)\n                    {\n                        len = datalength - start;\n                    }\n\n                    PackData(encryptdata, ref start, len, outdata, ref outlength);\n                }\n                while (datalength - start > 2048)\n                {\n                    var len = random.Next(4096) + 100;\n                    if (len > datalength - start)\n                    {\n                        len = datalength - start;\n                    }\n\n                    PackData(encryptdata, ref start, len, outdata, ref outlength);\n                }\n                if (datalength - start > 0)\n                {\n                    PackData(encryptdata, ref start, datalength - start, outdata, ref outlength);\n                }\n                return outdata;\n            }\n            if (datalength > 0)\n            {\n                var data = new byte[datalength + 5];\n                data[0] = 0x17;\n                data[1] = 0x3;\n                data[2] = 0x3;\n                data[3] = (byte)(datalength >> 8);\n                data[4] = (byte)datalength;\n                Array.Copy(encryptdata, 0, data, 5, datalength);\n                data_sent_buffer.Add(data);\n            }\n            if ((handshake_status & 3) != 0)\n            {\n                outlength = 0;\n                if ((handshake_status & 2) == 0)\n                {\n                    int[] finish_len_set = { 32 }; //, 40, 64\n                    var finish_len = finish_len_set[random.Next(finish_len_set.Length)];\n                    var hmac_data = new byte[11 + finish_len];\n                    var rnd = new byte[finish_len - 10];\n                    random.NextBytes(rnd);\n\n                    var handshake_finish = System.Text.Encoding.ASCII.GetBytes(\"\\x14\\x03\\x03\\x00\\x01\\x01\" + \"\\x16\\x03\\x03\\x00\\x20\");\n                    handshake_finish[handshake_finish.Length - 1] = (byte)finish_len;\n                    handshake_finish.CopyTo(hmac_data, 0);\n                    rnd.CopyTo(hmac_data, handshake_finish.Length);\n\n                    hmac_sha1(hmac_data, hmac_data.Length);\n\n                    data_sent_buffer.Insert(0, hmac_data);\n                    SentLength -= hmac_data.Length;\n                    handshake_status |= 2;\n                }\n                if (datalength == 0 || fastauth)\n                {\n                    foreach (var data in data_sent_buffer)\n                    {\n                        Util.Utils.SetArrayMinSize2(ref outdata, outlength + data.Length);\n                        Array.Copy(data, 0, outdata, outlength, data.Length);\n                        SentLength += data.Length;\n                        outlength += data.Length;\n                    }\n                    data_sent_buffer.Clear();\n                }\n                if (datalength == 0)\n                {\n                    handshake_status |= 4;\n                }\n            }\n            else\n            {\n                var rnd = new byte[32];\n                PackAuthData(rnd);\n                var ssl_buf = new List<byte>();\n                var ext_buf = new List<byte>();\n                var str_buf = \"001cc02bc02fcca9cca8cc14cc13c00ac014c009c013009c0035002f000a0100\";\n                ssl_buf.AddRange(rnd);\n                ssl_buf.Add(32);\n                ssl_buf.AddRange(((TlsAuthData)Server.data).clientID);\n                ssl_buf.AddRange(to_bin(str_buf));\n\n                str_buf = \"ff01000100\";\n                ext_buf.AddRange(to_bin(str_buf));\n                var host = Server.host;\n                if (Server.param.Length > 0)\n                {\n                    var hosts = Server.param.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);\n                    if (hosts.Length > 0)\n                    {\n                        host = hosts[random.Next(hosts.Length)];\n                        host = host.Trim(' ');\n                    }\n                }\n                if (!string.IsNullOrEmpty(host) && host[host.Length - 1] >= '0' && host[host.Length - 1] <= '9' && Server.param.Length == 0)\n                {\n                    host = \"\";\n                }\n                ext_buf.AddRange(sni(host));\n                var str_buf2 = \"001700000023\";\n                ext_buf.AddRange(to_bin(str_buf2));\n                {\n                    var authData = (TlsAuthData)Server.data;\n                    byte[] ticket;\n                    lock (authData)\n                    {\n                        if (authData.ticket_buf == null)\n                        {\n                            authData.ticket_buf = new Dictionary<string, byte[]>();\n                        }\n                        if (!authData.ticket_buf.ContainsKey(host ?? throw new InvalidOperationException()) || random.Next(16) == 0)\n                        {\n                            var ticketSize = random.Next(32, 196) * 2;\n                            ticket = RandomNumberGenerator.GetBytes(ticketSize);\n                            authData.ticket_buf[host] = ticket;\n                        }\n                        else\n                        {\n                            ticket = authData.ticket_buf[host];\n                        }\n                    }\n                    ext_buf.Add((byte)(ticket.Length >> 8));\n                    ext_buf.Add((byte)(ticket.Length & 0xff));\n                    ext_buf.AddRange(ticket);\n                }\n                var str_buf3 = \"000d0016001406010603050105030401040303010303020102030005000501000000000012000075500000000b00020100000a0006000400170018\";\n                str_buf3 += \"00150066000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\";\n                ext_buf.AddRange(to_bin(str_buf3));\n                ext_buf.Insert(0, (byte)(ext_buf.Count % 256));\n                ext_buf.Insert(0, (byte)((ext_buf.Count - 1) / 256));\n\n                ssl_buf.AddRange(ext_buf);\n                // client version\n                ssl_buf.Insert(0, 3); // version\n                ssl_buf.Insert(0, 3);\n                // length\n                ssl_buf.Insert(0, (byte)(ssl_buf.Count % 256));\n                ssl_buf.Insert(0, (byte)((ssl_buf.Count - 1) / 256));\n                ssl_buf.Insert(0, 0);\n                ssl_buf.Insert(0, 1); // client hello\n                // length\n                ssl_buf.Insert(0, (byte)(ssl_buf.Count % 256));\n                ssl_buf.Insert(0, (byte)((ssl_buf.Count - 1) / 256));\n                //\n                ssl_buf.Insert(0, 0x1); // version\n                ssl_buf.Insert(0, 0x3);\n                ssl_buf.Insert(0, 0x16);\n                for (var i = 0; i < ssl_buf.Count; ++i)\n                {\n                    outdata[i] = ssl_buf[i];\n                }\n                outlength = ssl_buf.Count;\n\n                handshake_status = 1;\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback)\n        {\n            if (handshake_status == -1)\n            {\n                outlength = datalength;\n                needsendback = false;\n                return encryptdata;\n            }\n\n            if ((handshake_status & 8) == 8)\n            {\n                Array.Resize(ref data_recv_buffer, data_recv_buffer.Length + datalength);\n                Array.Copy(encryptdata, 0, data_recv_buffer, data_recv_buffer.Length - datalength, datalength);\n                needsendback = false;\n                var outdata = new byte[65536];\n                outlength = 0;\n                while (data_recv_buffer.Length > 5)\n                {\n                    if (data_recv_buffer[0] != 0x17)\n                    {\n                        throw new ObfsException(\"ClientDecode appdata error\");\n                    }\n\n                    var len = (data_recv_buffer[3] << 8) + data_recv_buffer[4];\n                    var pack_len = len + 5;\n                    if (pack_len > data_recv_buffer.Length)\n                    {\n                        break;\n                    }\n\n                    Array.Copy(data_recv_buffer, 5, outdata, outlength, len);\n                    outlength += len;\n                    var buffer = new byte[data_recv_buffer.Length - pack_len];\n                    Array.Copy(data_recv_buffer, pack_len, buffer, 0, buffer.Length);\n                    data_recv_buffer = buffer;\n                }\n                return outdata;\n            }\n            else\n            {\n                Array.Resize(ref data_recv_buffer, data_recv_buffer.Length + datalength);\n                Array.Copy(encryptdata, 0, data_recv_buffer, data_recv_buffer.Length - datalength, datalength);\n                outlength = 0;\n                needsendback = false;\n                if (data_recv_buffer.Length >= 11 + 32 + 1 + 32)\n                {\n                    var data = new byte[32];\n                    Array.Copy(data_recv_buffer, 11, data, 0, 22);\n                    hmac_sha1(data, data.Length);\n\n                    if (!data_recv_buffer.AsSpan(11 + 22, 10).SequenceEqual(data.AsSpan(22, 10)))\n                    {\n                        throw new ObfsException(\"ClientDecode data error: wrong sha1\");\n                    }\n\n                    var headerlength = data_recv_buffer.Length;\n                    data = new byte[headerlength];\n                    Array.Copy(data_recv_buffer, 0, data, 0, headerlength - 10);\n                    hmac_sha1(data, headerlength);\n                    if (!data_recv_buffer.AsSpan(headerlength - 10, 10).SequenceEqual(data.AsSpan(headerlength - 10, 10)))\n                    {\n                        headerlength = 0;\n                        while (headerlength < data_recv_buffer.Length &&\n                               (data_recv_buffer[headerlength] == 0x14 || data_recv_buffer[headerlength] == 0x16))\n                        {\n                            headerlength += 5;\n                            if (headerlength >= data_recv_buffer.Length)\n                            {\n                                return encryptdata;\n                            }\n                            headerlength += (data_recv_buffer[headerlength - 2] << 8) | data_recv_buffer[headerlength - 1];\n                            if (headerlength > data_recv_buffer.Length)\n                            {\n                                return encryptdata;\n                            }\n                        }\n                        data = new byte[headerlength];\n                        Array.Copy(data_recv_buffer, 0, data, 0, headerlength - 10);\n                        hmac_sha1(data, headerlength);\n\n                        if (!data_recv_buffer.AsSpan(headerlength - 10, 10).SequenceEqual(data.AsSpan(headerlength - 10, 10)))\n                        {\n                            throw new ObfsException(\"ClientDecode data error: wrong sha1\");\n                        }\n                    }\n                    var buffer = new byte[data_recv_buffer.Length - headerlength];\n                    Array.Copy(data_recv_buffer, headerlength, buffer, 0, buffer.Length);\n                    data_recv_buffer = buffer;\n                    handshake_status |= 8;\n                    var ret = ClientDecode(encryptdata, 0, out outlength, out needsendback);\n                    needsendback = true;\n                    return ret;\n                }\n                return encryptdata;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/VerifyData.cs",
    "content": "namespace Shadowsocks.Obfs\n{\n    public class VerifyData\n    {\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/VerifyDeflateObfs.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Util;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Shadowsocks.Obfs\n{\n    public class VerifyDeflateObfs : VerifySimpleBase\n    {\n        public VerifyDeflateObfs(string method)\n                : base(method)\n        {\n        }\n        private static Dictionary<string, int[]> _obfs = new()\n        {\n            { \"verify_deflate\", new[] { 1, 0, 1 } }\n        };\n\n        public static List<string> SupportedObfs()\n        {\n            return new(_obfs.Keys);\n        }\n\n        public override Dictionary<string, int[]> GetObfs()\n        {\n            return _obfs;\n        }\n\n        public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength)\n        {\n            var comdata = FileManager.DeflateCompress(data, 0, datalength, out var outlen);\n            outlength = outlen + 2 + 4;\n            outdata[0] = (byte)(outlength >> 8);\n            outdata[1] = (byte)outlength;\n            Array.Copy(comdata, 0, outdata, 2, outlen);\n            var adler = Adler32.CalcAdler32(data, datalength);\n            outdata[outlength - 4] = (byte)(adler >> 24);\n            outdata[outlength - 3] = (byte)(adler >> 16);\n            outdata[outlength - 2] = (byte)(adler >> 8);\n            outdata[outlength - 1] = (byte)adler;\n        }\n\n        public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            if (plaindata == null)\n            {\n                outlength = 0;\n                return null;\n            }\n            var outdata = new byte[datalength + datalength / 10 + 32];\n            var packdata = new byte[32768];\n            var data = plaindata;\n            outlength = 0;\n            const int unit_len = 32700;\n            while (datalength > unit_len)\n            {\n                PackData(data, unit_len, packdata, out var outlen);\n                Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n                datalength -= unit_len;\n                var newdata = new byte[datalength];\n                Array.Copy(data, unit_len, newdata, 0, newdata.Length);\n                data = newdata;\n            }\n            if (datalength > 0)\n            {\n                PackData(data, datalength, packdata, out var outlen);\n                Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                Array.Copy(packdata, 0, outdata, outlength, outlen);\n                outlength += outlen;\n            }\n            return outdata;\n        }\n\n        public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength)\n        {\n            var outdata = new byte[recv_buf_len + datalength * 2 + 16];\n            Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength);\n            recv_buf_len += datalength;\n            outlength = 0;\n            while (recv_buf_len > 2)\n            {\n                var len = (recv_buf[0] << 8) + recv_buf[1];\n                if (len is >= 32768 or < 6)\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data error\");\n                }\n                if (len > recv_buf_len)\n                {\n                    break;\n                }\n\n                var buf = FileManager.DeflateDecompress(recv_buf, 2, len - 6, out var outlen);\n                if (buf != null)\n                {\n                    var alder = Adler32.CalcAdler32(buf, outlen);\n                    if (recv_buf[len - 4] == (byte)(alder >> 24)\n                        && recv_buf[len - 3] == (byte)(alder >> 16)\n                        && recv_buf[len - 2] == (byte)(alder >> 8)\n                        && recv_buf[len - 1] == (byte)alder)\n                    {\n                        //pass\n                    }\n                    else\n                    {\n                        throw new ObfsException(\"ClientPostDecrypt data decompress ERROR\");\n                    }\n                    Utils.SetArrayMinSize2(ref outdata, outlength + outlen);\n                    Array.Copy(buf, 0, outdata, outlength, outlen);\n                    outlength += outlen;\n                    recv_buf_len -= len;\n                    Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len);\n                }\n                else\n                {\n                    throw new ObfsException(\"ClientPostDecrypt data decompress ERROR\");\n                }\n            }\n            return outdata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/VerifySimpleBase.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Obfs\n{\n    public abstract class VerifySimpleBase : ObfsBase\n    {\n        public VerifySimpleBase(string method)\n                : base(method)\n        {\n        }\n\n        protected const int RecvBufferSize = 65536 * 2;\n\n        protected byte[] recv_buf = new byte[RecvBufferSize];\n        protected int recv_buf_len;\n        protected Random random = new();\n\n        public override object InitData()\n        {\n            return new VerifyData();\n        }\n\n        public int LinearRandomInt(int max)\n        {\n            return random.Next(max);\n        }\n\n        public int NonLinearRandomInt(int max)\n        {\n            int r1, r2;\n            if ((max & 1) == 1)\n            {\n                var mid = (max + 1) >> 1;\n                r1 = random.Next(mid);\n                r2 = random.Next(mid + 1);\n                var r = r1 + r2;\n                if (r == max)\n                {\n                    return mid - 1;\n                }\n\n                if (r < mid)\n                {\n                    return mid - r - 1;\n                }\n\n                return max - r + mid - 1;\n            }\n            else\n            {\n                var mid = max >> 1;\n                r1 = random.Next(mid);\n                r2 = random.Next(mid + 1);\n                var r = r1 + r2;\n                if (r < mid)\n                {\n                    return mid - r - 1;\n                }\n\n                return max - r + mid - 1;\n            }\n        }\n\n        public double TrapezoidRandomFloat(double d) // －1 <= d <= 1\n        {\n            if (Math.Abs(d) < 0.000001)\n            {\n                return random.NextDouble();\n            }\n\n            var s = random.NextDouble();\n            //(2dx + 2(1 - d))x/2 = s\n            //dx^2 + (1-d)x - s = 0\n            var a = 1 - d;\n            //dx^2 + ax - s = 0\n            //[-a + sqrt(a^2 + 4ds)] / 2d\n            return (Math.Sqrt(a * a + 4 * d * s) - a) / (2 * d);\n        }\n\n        public int TrapezoidRandomInt(int max, double d)\n        {\n            var v = TrapezoidRandomFloat(d);\n            return (int)(v * max);\n        }\n\n        public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength)\n        {\n            outlength = datalength;\n            return encryptdata;\n        }\n\n        public override byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback)\n        {\n            outlength = datalength;\n            needsendback = false;\n            return encryptdata;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Obfs/xorshift128plus.cs",
    "content": "using System;\n\nnamespace Shadowsocks.Obfs\n{\n    class xorshift128plus\n    {\n        protected ulong v0, v1;\n        protected int init_loop;\n\n        public xorshift128plus(int init_loop_ = 4)\n        {\n            v0 = v1 = 0;\n            init_loop = init_loop_;\n        }\n\n        public ulong next()\n        {\n            var x = v0;\n            var y = v1;\n            v0 = y;\n            x ^= x << 23;\n            x ^= y ^ (x >> 17) ^ (y >> 26);\n            v1 = x;\n            return x + y;\n        }\n\n        public void init_from_bin(byte[] bytes)\n        {\n            var fill_bytes = new byte[16];\n            Array.Copy(bytes, fill_bytes, 16);\n            v0 = BitConverter.ToUInt64(fill_bytes, 0);\n            v1 = BitConverter.ToUInt64(fill_bytes, 8);\n        }\n\n        public void init_from_bin(byte[] bytes, int datalength)\n        {\n            var fill_bytes = new byte[16];\n            Array.Copy(bytes, fill_bytes, 16);\n            BitConverter.GetBytes((ushort)datalength).CopyTo(fill_bytes, 0);\n            v0 = BitConverter.ToUInt64(fill_bytes, 0);\n            v1 = BitConverter.ToUInt64(fill_bytes, 8);\n            for (var i = 0; i < init_loop; ++i)\n            {\n                next();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Program.cs",
    "content": "using CryptoBase;\r\nusing Microsoft.Win32;\r\nusing Shadowsocks.Controller;\r\nusing Shadowsocks.Enums;\r\nusing Shadowsocks.Model;\r\nusing Shadowsocks.Util;\r\nusing SingleInstance;\r\nusing System;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Threading;\r\nusing System.Threading.Tasks;\r\nusing System.Windows;\r\nusing Utils = Shadowsocks.Util.Utils;\r\n\r\nnamespace Shadowsocks\r\n{\r\n    internal static class Program\r\n    {\r\n        [STAThread]\r\n        private static void Main(string[] args)\r\n        {\r\n            Directory.SetCurrentDirectory(Path.GetDirectoryName(Utils.GetExecutablePath()) ?? throw new InvalidOperationException());\r\n            var identifier = $@\"Global\\{Controller.HttpRequest.UpdateChecker.Name}_{Directory.GetCurrentDirectory().GetClassicHashCode()}\";\r\n            using var singleInstance = new SingleInstanceService(identifier);\r\n            if (!singleInstance.TryStartSingleInstance())\r\n            {\r\n                SendCommand(singleInstance, args.Length <= 0 ? Constants.ParameterMultiplyInstance : string.Join(' ', args));\r\n                return;\r\n            }\r\n            using var d = singleInstance.Received.Subscribe(ArgumentsReceived);\r\n\r\n            var app = new Application\r\n            {\r\n                ShutdownMode = ShutdownMode.OnExplicitShutdown\r\n            };\r\n\r\n            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;\r\n\r\n            SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;\r\n            app.Exit += App_Exit;\r\n\r\n            Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(@\"##SyncfusionLicense##\");\r\n\r\n            Global.LoadConfig();\r\n\r\n            I18NUtil.SetLanguage(Global.GuiConfig.LangName);\r\n            ViewUtils.SetResource(app.Resources, @\"../View/NotifyIconResources.xaml\", 1);\r\n\r\n            Global.Controller = new MainController();\r\n\r\n            // Logging\r\n            Logging.DefaultOut = Console.Out;\r\n            Logging.DefaultError = Console.Error;\r\n\r\n            Utils.SetTls();\r\n\r\n            Global.ViewController = new MenuViewController(Global.Controller);\r\n            SystemEvents.SessionEnding += Global.ViewController.Quit_Click;\r\n\r\n            Global.Controller.Reload();\r\n            if (Global.GuiConfig.IsDefaultConfig())\r\n            {\r\n                var res = MessageBox.Show(\r\n                $@\"{I18NUtil.GetAppStringValue(@\"DefaultConfigMessage\")}{Environment.NewLine}{I18NUtil.GetAppStringValue(@\"DefaultConfigQuestion\")}\",\r\n                Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.OK);\r\n                switch (res)\r\n                {\r\n                    case MessageBoxResult.Yes:\r\n                    {\r\n                        Global.Controller.ShowConfigForm();\r\n                        break;\r\n                    }\r\n                    case MessageBoxResult.No:\r\n                    {\r\n                        Global.Controller.ShowSubscribeWindow();\r\n                        break;\r\n                    }\r\n                    default:\r\n                    {\r\n                        StopController();\r\n                        return;\r\n                    }\r\n                }\r\n            }\r\n\r\n            Reg.SetUrlProtocol(@\"ssr\");\r\n            Reg.SetUrlProtocol(@\"sub\");\r\n\r\n            singleInstance.StartListenServer();\r\n            app.Run();\r\n        }\r\n\r\n        private static void StopController()\r\n        {\r\n            Global.ViewController?.Quit_Click(default, default);\r\n            Global.Controller?.Stop();\r\n            Global.Controller = null;\r\n        }\r\n\r\n        private static void App_Exit(object sender, ExitEventArgs e)\r\n        {\r\n            Reg.RemoveUrlProtocol(@\"ssr\");\r\n            Reg.RemoveUrlProtocol(@\"sub\");\r\n            StopController();\r\n        }\r\n\r\n        private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)\r\n        {\r\n            switch (e.Mode)\r\n            {\r\n                case PowerModes.Resume:\r\n                {\r\n                    Logging.Info(\"os wake up\");\r\n                    if (Global.Controller != null)\r\n                    {\r\n                        Task.Run(() =>\r\n                        {\r\n                            Thread.Sleep(10 * 1000);\r\n                            try\r\n                            {\r\n                                Global.Controller.Reload();\r\n                                Logging.Info(\"controller started\");\r\n                            }\r\n                            catch (Exception ex)\r\n                            {\r\n                                Logging.LogUsefulException(ex);\r\n                            }\r\n                        });\r\n                    }\r\n                    break;\r\n                }\r\n                case PowerModes.Suspend:\r\n                {\r\n                    if (Global.Controller != null)\r\n                    {\r\n                        Global.Controller.Stop();\r\n                        Logging.Info(\"controller stopped\");\r\n                    }\r\n                    Logging.Info(\"os suspend\");\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private static int _exited;\r\n        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)\r\n        {\r\n            if (Interlocked.Increment(ref _exited) == 1)\r\n            {\r\n                Logging.Log(LogLevel.Error, $@\"{e.ExceptionObject}\");\r\n                MessageBox.Show(\r\n                $@\"{I18NUtil.GetAppStringValue(@\"UnexpectedError\")}{Environment.NewLine}{e.ExceptionObject}\",\r\n                Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.OK, MessageBoxImage.Error);\r\n                Environment.Exit(1);\r\n            }\r\n        }\r\n\r\n        private static void SendCommand(ISingleInstanceService service, string command)\r\n        {\r\n            try\r\n            {\r\n                service.SendMessageToFirstInstanceAsync(command).GetAwaiter().GetResult();\r\n            }\r\n            catch\r\n            {\r\n                // ignored\r\n            }\r\n        }\r\n\r\n        private static void ArgumentsReceived((string, Action<string>) receive)\r\n        {\r\n            var (message, endFunc) = receive;\r\n            var args = message\r\n                .Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)\r\n                .ToHashSet();\r\n\r\n            if (args.Contains(Constants.ParameterMultiplyInstance))\r\n            {\r\n                MessageBox.Show(I18NUtil.GetAppStringValue(@\"SuccessiveInstancesMessage1\") + Environment.NewLine +\r\n                                I18NUtil.GetAppStringValue(@\"SuccessiveInstancesMessage2\"),\r\n                    I18NUtil.GetAppStringValue(@\"SuccessiveInstancesCaption\"), MessageBoxButton.OK, MessageBoxImage.Information);\r\n            }\r\n            Application.Current.Dispatcher?.InvokeAsync(() =>\r\n            {\r\n                Global.ViewController.ImportAddress(string.Join(Environment.NewLine, args));\r\n            });\r\n\r\n            endFunc(string.Empty);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Properties/AssemblyInfo.cs",
    "content": "using System.Reflection;\r\n\r\n[assembly: AssemblyTitle(Shadowsocks.Controller.HttpRequest.UpdateChecker.Name)]\r\n[assembly: AssemblyProduct(Shadowsocks.Controller.HttpRequest.UpdateChecker.Name)]\r\n[assembly: AssemblyCopyright(Shadowsocks.Controller.HttpRequest.UpdateChecker.Copyright)]\r\n[assembly: AssemblyVersion(Shadowsocks.Controller.HttpRequest.UpdateChecker.Version)]\r\n[assembly: AssemblyFileVersion(Shadowsocks.Controller.HttpRequest.UpdateChecker.Version)]\r\n[assembly: AssemblyInformationalVersion(Shadowsocks.Controller.HttpRequest.UpdateChecker.FullVersion)]\r\n"
  },
  {
    "path": "shadowsocks-csharp/Properties/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\r\n// <auto-generated>\r\n//     此代码由工具生成。\r\n//     运行时版本:4.0.30319.42000\r\n//\r\n//     对此文件的更改可能会导致不正确的行为，并且如果\r\n//     重新生成代码，这些更改将会丢失。\r\n// </auto-generated>\r\n//------------------------------------------------------------------------------\r\n\r\nnamespace Shadowsocks.Properties {\r\n    using System;\r\n    \r\n    \r\n    /// <summary>\r\n    ///   一个强类型的资源类，用于查找本地化的字符串等。\r\n    /// </summary>\r\n    // 此类是由 StronglyTypedResourceBuilder\r\n    // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。\r\n    // 若要添加或移除成员，请编辑 .ResX 文件，然后重新运行 ResGen\r\n    // (以 /str 作为命令选项)，或重新生成 VS 项目。\r\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"16.0.0.0\")]\r\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\r\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\r\n    internal class Resources {\r\n        \r\n        private static global::System.Resources.ResourceManager resourceMan;\r\n        \r\n        private static global::System.Globalization.CultureInfo resourceCulture;\r\n        \r\n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\r\n        internal Resources() {\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   返回此类使用的缓存的 ResourceManager 实例。\r\n        /// </summary>\r\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\r\n        internal static global::System.Resources.ResourceManager ResourceManager {\r\n            get {\r\n                if (object.ReferenceEquals(resourceMan, null)) {\r\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Shadowsocks.Properties.Resources\", typeof(Resources).Assembly);\r\n                    resourceMan = temp;\r\n                }\r\n                return resourceMan;\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   重写当前线程的 CurrentUICulture 属性，对\r\n        ///   使用此强类型资源类的所有资源查找执行重写。\r\n        /// </summary>\r\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\r\n        internal static global::System.Globalization.CultureInfo Culture {\r\n            get {\r\n                return resourceCulture;\r\n            }\r\n            set {\r\n                resourceCulture = value;\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   查找类似 var direct = &quot;__DIRECT__&quot;;\r\n        ///if (direct == &quot;__DIR&quot; + &quot;ECT__&quot;) direct = &quot;DIRECT;&quot;;\r\n        ///\r\n        ///var wall_proxy = function(){ return &quot;__PROXY__&quot;; };\r\n        ///var wall_v6_proxy = function(){ return &quot;__PROXY__&quot;; };\r\n        ///\r\n        ///var nowall_proxy = function(){ return direct; };\r\n        ///var ip_proxy = function(){ return nowall_proxy(); };\r\n        ///var ipv6_proxy = function(){ return nowall_proxy(); };\r\n        ///\r\n        ///var userrules = __USERRULES__;\r\n        ///var rules = __RULES__;\r\n        ///\r\n        ////*\r\n        ///* This file is part of Adblock Plus &lt;http://adblockplus.org/&gt;,\r\n        ///* Copyright (C) 2006-2014 Eye [字符串的其余部分被截断]&quot;; 的本地化字符串。\r\n        /// </summary>\r\n        internal static string abp {\r\n            get {\r\n                return ResourceManager.GetString(\"abp\", resourceCulture);\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   查找类似 1.0.1.0/24\n        ///1.0.2.0/23\n        ///1.0.8.0/21\n        ///1.0.32.0/19\n        ///1.1.0.0/24\n        ///1.1.2.0/23\n        ///1.1.4.0/22\n        ///1.1.8.0/21\n        ///1.1.16.0/20\n        ///1.1.32.0/19\n        ///1.2.0.0/23\n        ///1.2.2.0/24\n        ///1.2.4.0/22\n        ///1.2.8.0/21\n        ///1.2.16.0/20\n        ///1.2.32.0/19\n        ///1.2.64.0/18\n        ///1.3.0.0/16\n        ///1.4.1.0/24\n        ///1.4.2.0/23\n        ///1.4.4.0/22\n        ///1.4.8.0/21\n        ///1.4.16.0/20\n        ///1.4.32.0/19\n        ///1.4.64.0/18\n        ///1.8.0.0/16\n        ///1.10.0.0/21\n        ///1.10.8.0/23\n        ///1.10.11.0/24\n        ///1.10.12.0/22\n        ///1.10.16.0/20\n        ///1.10.32.0/19\n        ///1.10.64.0/18\n        ///1.12.16.0/20\n        ///1.12.32.0/23\n        ///1.12.36.0/22\n        ///1.12.40.0/21\n        ///1.12.48.0/20\n        ///1.12.64.0/18\n        ///1.12.128.0/17\n        ///1.13.0.0/16\n        ///1.14.0.0/15\n        ///1.18.128.0/2 [字符串的其余部分被截断]&quot;; 的本地化字符串。\r\n        /// </summary>\r\n        internal static string chn_ip {\r\n            get {\r\n                return ResourceManager.GetString(\"chn_ip\", resourceCulture);\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   查找 System.Byte[] 类型的本地化资源。\r\n        /// </summary>\r\n        internal static byte[] libsscrypto_dll {\r\n            get {\r\n                object obj = ResourceManager.GetObject(\"libsscrypto_dll\", resourceCulture);\r\n                return ((byte[])(obj));\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   查找 System.Byte[] 类型的本地化资源。\r\n        /// </summary>\r\n        internal static byte[] libsscrypto64_dll {\r\n            get {\r\n                object obj = ResourceManager.GetObject(\"libsscrypto64_dll\", resourceCulture);\r\n                return ((byte[])(obj));\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   查找类似 var direct = &quot;__DIRECT__&quot;;\n        ///if (direct == &quot;__DIR&quot; + &quot;ECT__&quot;) direct = &quot;DIRECT;&quot;;\n        ///\n        ///var wall_proxy = function(){ return &quot;__PROXY__&quot;; };\n        ///var wall_v6_proxy = function(){ return &quot;__PROXY__&quot;; };\n        ///\n        ///var nowall_proxy = function(){ return direct; };\n        ///var ip_proxy = function(){ return nowall_proxy(); };\n        ///var ipv6_proxy = function(){ return nowall_proxy(); };\n        ///\n        ///var userrules = [];\n        ///var rules = [\n        ///  &quot;|http://85.17.73.31/&quot;,\n        ///  &quot;||afreecatv.com&quot;,\n        ///  &quot;||agnesb.fr&quot;,\n        ///  &quot;||akiba-web.com&quot;,\n        ///  &quot;||altrec.com&quot;,\n        ///  &quot;||angela-merkel.de&quot;,\n        ///  &quot;| [字符串的其余部分被截断]&quot;; 的本地化字符串。\r\n        /// </summary>\r\n        internal static string proxy_pac {\r\n            get {\r\n                return ResourceManager.GetString(\"proxy_pac\", resourceCulture);\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   查找 System.Drawing.Bitmap 类型的本地化资源。\r\n        /// </summary>\r\n        internal static System.Drawing.Bitmap ss128 {\r\n            get {\r\n                object obj = ResourceManager.GetObject(\"ss128\", resourceCulture);\r\n                return ((System.Drawing.Bitmap)(obj));\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   查找类似 ! Put user rules line by line in this file.\r\n        ///! See https://adblockplus.org/en/filter-cheatsheet\r\n        /// 的本地化字符串。\r\n        /// </summary>\r\n        internal static string user_rule {\r\n            get {\r\n                return ResourceManager.GetString(\"user_rule\", resourceCulture);\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "shadowsocks-csharp/Properties/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <assembly alias=\"System.Windows.Forms\" name=\"System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\" />\r\n  <data name=\"abp\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\r\n    <value>..\\Data\\abp.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value>\r\n  </data>\r\n  <data name=\"chn_ip\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\r\n    <value>..\\Data\\chn_ip.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value>\r\n  </data>\r\n  <data name=\"libsscrypto64_dll\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\r\n    <value>..\\Data\\libsscrypto64.dll.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </data>\r\n  <data name=\"libsscrypto_dll\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\r\n    <value>..\\data\\libsscrypto.dll.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </data>\r\n  <data name=\"proxy_pac\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\r\n    <value>..\\Data\\proxy.pac.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value>\r\n  </data>\r\n  <data name=\"ss128\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\r\n    <value>..\\Resources\\ss128.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>\r\n  </data>\r\n  <data name=\"user_rule\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\r\n    <value>..\\data\\user-rule.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>\r\n  </data>\r\n</root>"
  },
  {
    "path": "shadowsocks-csharp/Proxy/CallbackState.cs",
    "content": "namespace Shadowsocks.Proxy\n{\n    public class CallbackState\n    {\n        public byte[] buffer;\n        public int size;\n        public int protocol_size;\n        public object state;\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/CallbackStatus.cs",
    "content": "namespace Shadowsocks.Proxy\n{\n    class CallbackStatus\n    {\n        protected int status;\n\n        public CallbackStatus()\n        {\n            status = 0;\n        }\n\n        public void SetIfEqu(int newStatus, int oldStatus)\n        {\n            lock (this)\n            {\n                if (status == oldStatus)\n                {\n                    status = newStatus;\n                }\n            }\n        }\n\n        public int Status\n        {\n            get\n            {\n                lock (this)\n                {\n                    return status;\n                }\n            }\n            set\n            {\n                lock (this)\n                {\n                    status = value;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/Handler.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Controller.Service;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Model.Transfer;\nusing Shadowsocks.Obfs;\nusing Shadowsocks.Util;\nusing Shadowsocks.Util.NetUtils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Timers;\nusing static Shadowsocks.Encryption.EncryptorBase;\nusing Timer = System.Timers.Timer;\n\nnamespace Shadowsocks.Proxy\n{\n    internal class Handler : IHandler\n    {\n        public delegate Server GetCurrentServer(int localPort, ServerSelectStrategy.FilterFunc filter, string targetURI = null, bool cfgRandom = false, bool usingRandom = false, bool forceRandom = false);\n        public delegate void KeepCurrentServer(int localPort, string targetURI, string id);\n        public GetCurrentServer getCurrentServer;\n        public KeepCurrentServer keepCurrentServer;\n        public Server server;\n        public ServerSelectStrategy.FilterFunc select_server;\n        public HandlerConfig cfg = new();\n        // Connection socket\n        public ProxySocketTunLocal connection;\n        public Socket connectionUDP;\n        protected IPEndPoint connectionUDPEndPoint;\n        protected int localPort;\n\n        protected ProtocolResponseDetector detector = new();\n        // remote socket.\n        //protected Socket remote;\n        protected ProxyEncryptSocket remote;\n        protected ProxyEncryptSocket remoteUDP;\n        // Size of receive buffer.\n        protected const int RecvSize = ProxyEncryptSocket.MSS * 4;\n        protected const int BufferSize = ProxyEncryptSocket.MSS * 16;\n        // remote header send buffer\n        protected byte[] remoteHeaderSendBuffer;\n        // connection send buffer\n        protected List<byte[]> connectionSendBufferList = new();\n\n        protected DateTime lastKeepTime;\n        private int _totalRecvSize;\n\n        protected byte[] remoteUDPRecvBuffer = new byte[BufferSize];\n        protected int remoteUDPRecvBufferLength;\n        protected object recvUDPoverTCPLock = new();\n\n        protected bool closed;\n        protected bool local_error;\n        protected bool is_protocol_sendback;\n        protected bool is_obfs_sendback;\n\n        protected bool connectionTCPIdle, connectionUDPIdle, remoteTCPIdle, remoteUDPIdle;\n\n        protected SpeedTester speedTester = new();\n        protected int lastErrCode;\n        protected Timer timer;\n        protected object timerLock = new();\n        protected DateTime lastTimerSetTime;\n\n        enum ConnectState\n        {\n            END = -1,\n            READY = 0,\n            HANDSHAKE = 1,\n            CONNECTING = 2,\n            CONNECTED = 3\n        }\n        private ConnectState state = ConnectState.READY;\n\n        private ConnectState State\n        {\n            get => state;\n            set\n            {\n                lock (this)\n                {\n                    state = value;\n                }\n            }\n        }\n\n        private void ResetTimeout(double time, bool reset_keep_alive = true)\n        {\n            if (time <= 0 && timer == null)\n            {\n                return;\n            }\n\n            if (reset_keep_alive)\n            {\n                cfg.TryKeepAlive = 0;\n            }\n\n            if (time <= 0)\n            {\n                if (timer != null)\n                {\n                    lock (timerLock)\n                    {\n                        if (timer != null)\n                        {\n                            timer.Enabled = false;\n                            timer.Elapsed -= timer_Elapsed;\n                            timer.Dispose();\n                            timer = null;\n                        }\n                    }\n                }\n            }\n            else if (!closed)\n            {\n                if ((DateTime.Now - lastTimerSetTime).TotalMilliseconds > 500)\n                {\n                    lock (timerLock)\n                    {\n                        if (timer == null)\n                        {\n                            timer = new Timer(time * 1000.0);\n                            timer.Elapsed += timer_Elapsed;\n                        }\n                        else\n                        {\n                            timer.Interval = time * 1000.0;\n                            timer.Stop();\n                        }\n                        timer.Start();\n                        lastTimerSetTime = DateTime.Now;\n                    }\n                }\n            }\n        }\n\n        private void timer_Elapsed(object sender, ElapsedEventArgs e)\n        {\n            if (closed)\n            {\n                return;\n            }\n            var stop = false;\n\n            try\n            {\n                if (cfg.TryKeepAlive <= 0 && State == ConnectState.CONNECTED && remote != null && remoteUDP == null && remote.CanSendKeepAlive)\n                {\n                    cfg.TryKeepAlive++;\n                    RemoteSend(remoteUDPRecvBuffer, -1);\n                }\n                else\n                {\n                    if (connection != null)\n                    {\n                        var s = server;\n                        if (remote != null && cfg.ReconnectTimesRemain > 0\n                                           //&& obfs != null && obfs.getSentLength() == 0\n                                           && connectionSendBufferList != null\n                                           && (State == ConnectState.CONNECTED || State == ConnectState.CONNECTING))\n                        {\n                            if (lastErrCode == 0)\n                            {\n                                if (State == ConnectState.CONNECTING && cfg.Socks5RemotePort > 0)\n                                {\n                                }\n                                else\n                                {\n                                    lastErrCode = 8;\n                                    s.SpeedLog.AddTimeoutTimes();\n                                }\n                            }\n                            //remote.Shutdown(SocketShutdown.Both);\n                            stop = true;\n                        }\n                        else\n                        {\n                            if (s != null\n                                && connectionSendBufferList != null\n                            )\n                            {\n                                if (lastErrCode == 0)\n                                {\n                                    lastErrCode = 8;\n                                    s.SpeedLog.AddTimeoutTimes();\n                                }\n                            }\n                            //connection.Shutdown(SocketShutdown.Both);\n                            stop = true;\n                            local_error = true;\n                        }\n                    }\n                }\n            }\n            catch (Exception)\n            {\n                //\n            }\n            if (stop)\n            {\n                //Thread.Sleep(200);\n                Close();\n            }\n        }\n\n        public void setServerTransferTotal(ServerTransferTotal transfer)\n        {\n            speedTester.Transfer = transfer;\n        }\n\n        public int LogSocketException(Exception e)\n        {\n            // just log useful exceptions, not all of them\n            var s = server;\n            if (e is ObfsException)\n            {\n                if (lastErrCode == 0)\n                {\n                    if (s != null)\n                    {\n                        lastErrCode = 16;\n                        s.SpeedLog.AddErrorDecodeTimes();\n                    }\n                }\n\n                return 16; // ObfsException(decrypt error)\n            }\n\n            if (e is ProtocolException)\n            {\n                if (lastErrCode == 0)\n                {\n                    if (s != null)\n                    {\n                        lastErrCode = 16;\n                        s.SpeedLog.AddErrorDecodeTimes();\n                    }\n                }\n\n                return 16; // ObfsException(decrypt error)\n            }\n\n            if (e is SocketException se)\n            {\n                switch (se.SocketErrorCode)\n                {\n                    case SocketError.ConnectionAborted:\n                    case SocketError.ConnectionReset:\n                    case SocketError.NotConnected:\n                    case SocketError.Interrupted:\n                    case SocketError.Shutdown:\n                        // closed by browser when sending\n                        // normally happens when download is canceled or a tab is closed before page is loaded\n                        break;\n                    case SocketError.NoData:\n                    {\n                        if (lastErrCode == 0)\n                        {\n                            if (s != null)\n                            {\n                                lastErrCode = 1;\n                                s.SpeedLog.AddErrorTimes();\n                            }\n                        }\n\n                        return 1; // proxy DNS error\n                    }\n                    case SocketError.HostNotFound:\n                    {\n                        if (lastErrCode == 0)\n                        {\n                            if (s != null)\n                            {\n                                lastErrCode = 2;\n                                s.SpeedLog.AddErrorTimes();\n                            }\n                        }\n\n                        return 2; // ip not exist\n                    }\n                    case SocketError.ConnectionRefused:\n                    {\n                        if (lastErrCode == 0)\n                        {\n                            if (s != null)\n                            {\n                                lastErrCode = 1;\n                                if (cfg != null && cfg.Socks5RemotePort == 0)\n                                {\n                                    s.SpeedLog.AddErrorTimes();\n                                }\n                            }\n                        }\n\n                        return 2; // proxy ip/port error\n                    }\n                    case SocketError.NetworkUnreachable:\n                    {\n                        if (lastErrCode == 0 && s != null)\n                        {\n                            lastErrCode = 3;\n                            s.SpeedLog.AddErrorTimes();\n                        }\n\n                        return 3; // proxy ip/port error\n                    }\n                    case SocketError.TimedOut:\n                    {\n                        if (lastErrCode == 0 && s != null)\n                        {\n                            lastErrCode = 8;\n                            s.SpeedLog.AddTimeoutTimes();\n                        }\n\n                        return 8; // proxy server no response too slow\n                    }\n                    default:\n                    {\n                        if (lastErrCode == 0)\n                        {\n                            lastErrCode = -1;\n                            s?.SpeedLog.AddNoErrorTimes(); //?\n                        }\n\n                        return -1;\n                    }\n                }\n            }\n\n            return 0;\n        }\n\n        public bool ReConnect()\n        {\n            Logging.Debug(\"Reconnect \" + cfg.TargetHost + \":\" + cfg.TargetPort + \" \" + connection.GetSocket().Handle);\n            {\n                var handler = new Handler();\n                handler.getCurrentServer = getCurrentServer;\n                handler.keepCurrentServer = keepCurrentServer;\n                handler.select_server = select_server;\n                handler.connection = connection;\n                handler.connectionUDP = connectionUDP;\n                if (cfg.Clone() is HandlerConfig config)\n                {\n                    handler.cfg = config;\n                    handler.cfg.ReconnectTimesRemain = cfg.ReconnectTimesRemain - 1;\n                    handler.cfg.ReconnectTimes = cfg.ReconnectTimes + 1;\n                }\n\n                handler.speedTester.Transfer = speedTester.Transfer;\n\n                var total_len = 0;\n                var newFirstPacket = remoteHeaderSendBuffer;\n                if (connectionSendBufferList != null && connectionSendBufferList.Count > 0)\n                {\n                    foreach (var data in connectionSendBufferList)\n                    {\n                        total_len += data.Length;\n                    }\n                    newFirstPacket = new byte[total_len];\n                    total_len = 0;\n                    foreach (var data in connectionSendBufferList)\n                    {\n                        Buffer.BlockCopy(data, 0, newFirstPacket, total_len, data.Length);\n                        total_len += data.Length;\n                    }\n                }\n                handler.Start(newFirstPacket, newFirstPacket.Length, connection.local_sendback_protocol);\n            }\n            return true;\n        }\n\n        public void Start(byte[] firstPacket, int length, string rsp_protocol)\n        {\n            connection.local_sendback_protocol = rsp_protocol;\n            if (cfg.Socks5RemotePort > 0)\n            {\n                cfg.AutoSwitchOff = false;\n            }\n            ResetTimeout(cfg.Ttl);\n            if (State == ConnectState.READY)\n            {\n                State = ConnectState.HANDSHAKE;\n                remoteHeaderSendBuffer = firstPacket;\n\n                detector.OnSend(remoteHeaderSendBuffer, length);\n                var data = new byte[length];\n                Array.Copy(remoteHeaderSendBuffer, data, data.Length);\n                connectionSendBufferList.Add(data);\n                remoteHeaderSendBuffer = data;\n\n                if (cfg.ReconnectTimes > 0)\n                {\n                    Task.Run(Connect);\n                }\n                else\n                {\n                    Connect();\n                }\n            }\n            else\n            {\n                Close();\n            }\n        }\n\n        private void BeginConnect(IPAddress ipAddress, int serverPort)\n        {\n            var remoteEP = new IPEndPoint(ipAddress, serverPort);\n\n            if (cfg.Socks5RemotePort != 0\n                || connectionUDP == null\n                || connectionUDP != null && server.UdpOverTcp)\n            {\n                remote = new ProxyEncryptSocket(ipAddress.AddressFamily,\n                        SocketType.Stream, ProtocolType.Tcp);\n                remote.GetSocket().NoDelay = true;\n                try\n                {\n                    remote.CreateEncryptor(server.Method, server.Password);\n                }\n                catch\n                {\n                    // ignored\n                }\n\n                remote.SetProtocol(ObfsFactory.GetObfs(server.Protocol));\n                remote.SetObfs(ObfsFactory.GetObfs(server.obfs));\n            }\n\n            if (connectionUDP != null && !server.UdpOverTcp)\n            {\n                try\n                {\n                    remoteUDP = new ProxyEncryptSocket(ipAddress.AddressFamily,\n                            SocketType.Dgram, ProtocolType.Udp);\n                    remoteUDP.GetSocket().Bind(new IPEndPoint(ipAddress.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0));\n\n                    remoteUDP.CreateEncryptor(server.Method, server.Password);\n                    remoteUDP.SetProtocol(ObfsFactory.GetObfs(server.Protocol));\n                    remoteUDP.SetObfs(ObfsFactory.GetObfs(server.obfs));\n                    if (server.Server_Udp_Port == 0 || cfg.Socks5RemotePort != 0)\n                    {\n                        var _remoteEP = new IPEndPoint(ipAddress, serverPort);\n                        remoteUDP.SetUdpEndPoint(_remoteEP);\n                    }\n                    else\n                    {\n                        var _remoteEP = new IPEndPoint(ipAddress, server.Server_Udp_Port);\n                        remoteUDP.SetUdpEndPoint(_remoteEP);\n                    }\n                }\n                catch (SocketException)\n                {\n                    remoteUDP = null;\n                }\n            }\n            ResetTimeout(cfg.Ttl);\n\n            // Connect to the remote endpoint.\n            if (cfg.Socks5RemotePort == 0 && connectionUDP != null && !server.UdpOverTcp)\n            {\n                var _state = State;\n                if (_state == ConnectState.CONNECTING)\n                {\n                    StartPipe();\n                }\n            }\n            else\n            {\n                speedTester.BeginConnect();\n                var result = remote.BeginConnect(remoteEP,\n                        ConnectCallback, new CallbackStatus());\n                var t = cfg.ConnectTimeout <= 0 ? 30 : cfg.ConnectTimeout;\n                var success = result.AsyncWaitHandle.WaitOne((int)(t * 1000), true);\n                if (!success)\n                {\n                    ((CallbackStatus)result.AsyncState).SetIfEqu(-1, 0);\n                    if (((CallbackStatus)result.AsyncState).Status == -1)\n                    {\n                        if (lastErrCode == 0)\n                        {\n                            lastErrCode = 8;\n                            server.SpeedLog.AddTimeoutTimes();\n                        }\n                        CloseSocket(ref remote);\n                        Close();\n                    }\n                }\n            }\n        }\n\n        public bool TryReconnect()\n        {\n            if (local_error)\n            {\n                return false;\n            }\n\n            if (cfg.ReconnectTimesRemain > 0)\n            {\n                if (State == ConnectState.CONNECTING)\n                {\n                    return ReConnect();\n                }\n\n                if (State == ConnectState.CONNECTED && lastErrCode == 8)\n                {\n                    if (connectionSendBufferList != null)\n                    {\n                        return ReConnect();\n                    }\n                }\n            }\n            return false;\n        }\n\n        private void CloseSocket(ref Socket sock)\n        {\n            lock (this)\n            {\n                if (sock != null)\n                {\n                    var s = sock;\n                    sock = null;\n                    try\n                    {\n                        s.Shutdown(SocketShutdown.Both);\n                    }\n                    catch\n                    {\n                        // ignored\n                    }\n\n                    try\n                    {\n                        s.Close();\n                    }\n                    catch\n                    {\n                        // ignored\n                    }\n                }\n            }\n        }\n\n        private void CloseSocket(ref ProxySocketTunLocal sock)\n        {\n            lock (this)\n            {\n                if (sock != null)\n                {\n                    var s = sock;\n                    sock = null;\n                    try\n                    {\n                        s.Shutdown(SocketShutdown.Both);\n                    }\n                    catch\n                    {\n                        // ignored\n                    }\n\n                    try\n                    {\n                        s.Close();\n                    }\n                    catch\n                    {\n                        // ignored\n                    }\n                }\n            }\n        }\n\n        private void CloseSocket(ref ProxyEncryptSocket sock)\n        {\n            lock (this)\n            {\n                if (sock != null)\n                {\n                    var s = sock;\n                    sock = null;\n                    try\n                    {\n                        s.Shutdown(SocketShutdown.Both);\n                    }\n                    catch\n                    {\n                        // ignored\n                    }\n\n                    try\n                    {\n                        s.Close();\n                    }\n                    catch\n                    {\n                        // ignored\n                    }\n                }\n            }\n        }\n\n        public override void Shutdown()\n        {\n            Task.Run(Close);\n        }\n\n        public void Close()\n        {\n            lock (this)\n            {\n                if (closed)\n                {\n                    return;\n                }\n                closed = true;\n            }\n            Thread.Sleep(200);\n            CloseSocket(ref remote);\n            CloseSocket(ref remoteUDP);\n            if (connection != null && cfg != null && connection.GetSocket() != null)\n            {\n                if (cfg.TargetHost is not null)\n                {\n                    Logging.Debug($@\"Close {cfg.TargetHost}:{cfg.TargetPort} {connection.GetSocket().Handle}\");\n                }\n            }\n            if (lastErrCode == 0 && server != null && speedTester != null)\n            {\n                if (!local_error && speedTester.SizeProtocolRecv == 0 && speedTester.SizeUpload > 0)\n                {\n                    if (is_protocol_sendback\n                        || is_obfs_sendback && speedTester.SizeDownload == 0)\n                    {\n                        lastErrCode = 16;\n                        server.SpeedLog.AddErrorDecodeTimes();\n                    }\n                    else\n                    {\n                        server.SpeedLog.AddErrorEmptyTimes();\n                    }\n                }\n                else\n                {\n                    server.SpeedLog.AddNoErrorTimes();\n                }\n            }\n\n            if (lastErrCode == 0 && server != null && cfg != null)\n            {\n                keepCurrentServer?.Invoke(localPort, cfg.TargetHost, server.Id);\n            }\n\n            ResetTimeout(0);\n            try\n            {\n                var reconnect = TryReconnect();\n                //lock (this)\n                {\n                    if (State != ConnectState.END)\n                    {\n                        if (State != ConnectState.READY && State != ConnectState.HANDSHAKE && server != null)\n                        {\n                            if (server.Connections.DecRef(this))\n                            {\n                                server.SpeedLog.AddDisconnectTimes();\n                            }\n                        }\n                        State = ConnectState.END;\n                    }\n                }\n\n                if (!reconnect)\n                {\n                    if (cfg.TargetHost is not null)\n                    {\n                        Logging.Info($@\"Disconnect {cfg.TargetHost}:{cfg.TargetPort}\");\n                    }\n\n                    CloseSocket(ref connection);\n                    CloseSocket(ref connectionUDP);\n\n                    if (cfg.TargetHost is not null)\n                    {\n                        Logging.Debug($@\"Transfer {cfg.TargetHost}:{cfg.TargetPort + speedTester.TransferLog()}\");\n                    }\n                }\n                else\n                {\n                    connection = null;\n                    connectionUDP = null;\n                }\n\n\n                if (cfg != null && cfg.AutoSwitchOff && server != null)\n                {\n                    if (server.SpeedLog.ErrorPercent.HasValue && server.SpeedLog.ErrorPercent >= 100\n                    && (server.SpeedLog.ConnectError >= 3 || server.SpeedLog.ErrorContinuousTimes >= 3 ||\n                       server.SpeedLog.ErrorTimeoutTimes >= 3 || server.SpeedLog.ErrorEmptyTimes >= 3))\n                    {\n                        server.Enable = false;\n                    }\n                }\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n            }\n\n            getCurrentServer = null;\n            keepCurrentServer = null;\n\n            detector = null;\n            speedTester = null;\n            remoteUDPRecvBuffer = null;\n\n            server = null;\n            select_server = null;\n\n            cfg = null;\n        }\n\n        private bool ConnectProxyServer(string strRemoteHost, int iRemotePort)\n        {\n            if (cfg.ProxyType == ProxyType.Socks5)\n            {\n                var ret = remote.ConnectSocks5ProxyServer(strRemoteHost, iRemotePort, connectionUDP != null && !server.UdpOverTcp, cfg.Socks5RemoteUsername, cfg.Socks5RemotePassword);\n                remote.SetTcpServer(server.server, server.Server_Port);\n                remote.SetUdpServer(server.server, server.Server_Udp_Port == 0 ? server.Server_Port : server.Server_Udp_Port);\n                if (remoteUDP != null)\n                {\n                    remoteUDP.GoS5Proxy = true;\n                    remoteUDP.SetUdpServer(server.server, server.Server_Udp_Port == 0 ? server.Server_Port : server.Server_Udp_Port);\n                    remoteUDP.SetUdpEndPoint(remote.GetProxyUdpEndPoint());\n                }\n                return ret;\n            }\n\n            if (cfg.ProxyType == ProxyType.Http)\n            {\n                var ret = remote.ConnectHttpProxyServer(strRemoteHost, iRemotePort, cfg.Socks5RemoteUsername, cfg.Socks5RemotePassword, cfg.ProxyUserAgent);\n                remote.SetTcpServer(server.server, server.Server_Port);\n                return ret;\n            }\n\n            return true;\n        }\n\n        private void Connect()\n        {\n            remote = null;\n            remoteUDP = null;\n            localPort = ((IPEndPoint)connection.GetSocket().LocalEndPoint).Port;\n            if (select_server == null)\n            {\n                if (cfg.TargetHost == null)\n                {\n                    cfg.TargetHost = GetQueryString();\n                    cfg.TargetPort = GetQueryPort();\n                    server = getCurrentServer(localPort, null, cfg.TargetHost, cfg.Random, true);\n                }\n                else\n                {\n                    server = getCurrentServer(localPort, null, cfg.TargetHost, cfg.Random, true, cfg.ForceRandom);\n                }\n            }\n            else\n            {\n                if (cfg.TargetHost == null)\n                {\n                    cfg.TargetHost = GetQueryString();\n                    cfg.TargetPort = GetQueryPort();\n                    server = getCurrentServer(localPort, select_server, cfg.TargetHost, true, true);\n                }\n                else\n                {\n                    server = getCurrentServer(localPort, select_server, cfg.TargetHost, true, true, cfg.ForceRandom);\n                }\n            }\n            speedTester.ServerId = server.Id;\n            Logging.Info(cfg.TargetHost is null\n                    ? $@\"Send udp via {server.server}:{server.Server_Port}\"\n                    : $@\"Connect {cfg.TargetHost}:{cfg.TargetPort} via {server.server}:{server.Server_Port}\");\n\n            ResetTimeout(cfg.Ttl);\n            if (Global.GuiConfig.ProxyRuleMode != ProxyRuleMode.Disable && cfg.TargetHost != null)\n            {\n                var host = cfg.TargetHost;\n                if (!IPAddress.TryParse(host, out var ipAddress))\n                {\n                    ipAddress = DnsUtil.DnsBuffer.Get(host) ?? DnsUtil.QueryDns(host);\n                    if (ipAddress != null)\n                    {\n                        Logging.Info($@\"DNS nolock query {host} answer {ipAddress}\");\n                        DnsUtil.DnsBuffer.Set(host, new IPAddress(ipAddress.GetAddressBytes()));\n                        DnsUtil.DnsBuffer.Sweep();\n                    }\n                    else\n                    {\n                        Logging.Info($@\"DNS nolock query {host} failed.\");\n                    }\n                }\n\n                if (ipAddress != null)\n                {\n                    cfg.TargetHost = ipAddress.ToString();\n                    ResetTimeout(cfg.Ttl);\n                }\n            }\n\n            lock (this)\n            {\n                server.SpeedLog.AddConnectTimes();\n                if (State == ConnectState.HANDSHAKE)\n                {\n                    State = ConnectState.CONNECTING;\n                }\n                server.Connections.AddRef(this);\n            }\n            try\n            {\n                var serverHost = server.server;\n                int serverPort = server.Server_Port;\n                if (cfg.Socks5RemotePort > 0)\n                {\n                    serverHost = cfg.Socks5RemoteHost;\n                    serverPort = cfg.Socks5RemotePort;\n                }\n                if (!IPAddress.TryParse(serverHost, out var ipAddress))\n                {\n                    if (server.SpeedLog.ErrorContinuousTimes > 10)\n                    {\n                        server.DnsBuffer.force_expired = true;\n                    }\n\n                    if (server.DnsBuffer.IsExpired(serverHost))\n                    {\n                        var dnsOk = false;\n                        var buf = server.DnsBuffer;\n                        if (Monitor.TryEnter(buf, buf.Ip != null ? 100 : 1000000))\n                        {\n                            if (buf.IsExpired(serverHost))\n                            {\n                                ipAddress = DnsUtil.QueryDns(serverHost);\n\n                                if (ipAddress != null)\n                                {\n                                    buf.UpdateDns(serverHost, ipAddress);\n                                    dnsOk = true;\n                                }\n                            }\n                            else\n                            {\n                                ipAddress = buf.Ip;\n                                dnsOk = true;\n                            }\n\n                            Monitor.Exit(buf);\n                        }\n                        else\n                        {\n                            if (buf.Ip != null)\n                            {\n                                ipAddress = buf.Ip;\n                                dnsOk = true;\n                            }\n                        }\n\n                        if (!dnsOk)\n                        {\n                            if (server.DnsBuffer.Ip != null)\n                            {\n                                ipAddress = server.DnsBuffer.Ip;\n                            }\n                            else\n                            {\n                                lastErrCode = 8;\n                                server.SpeedLog.AddTimeoutTimes();\n                                Close();\n                                return;\n                            }\n                        }\n                    }\n                    else\n                    {\n                        ipAddress = server.DnsBuffer.Ip;\n                    }\n                }\n                BeginConnect(ipAddress, serverPort);\n            }\n            catch (Exception e)\n            {\n                LogException(e);\n                Close();\n            }\n        }\n\n        private void ConnectCallback(IAsyncResult ar)\n        {\n            if (ar?.AsyncState != null)\n            {\n                ((CallbackStatus)ar.AsyncState).SetIfEqu(1, 0);\n                if (((CallbackStatus)ar.AsyncState).Status != 1)\n                {\n                    return;\n                }\n            }\n            try\n            {\n                remote.EndConnect(ar);\n                if (cfg.Socks5RemotePort > 0)\n                {\n                    if (!ConnectProxyServer(server.server, server.Server_Port))\n                    {\n                        throw new SocketException((int)SocketError.ConnectionReset);\n                    }\n                }\n                speedTester.EndConnect();\n\n                var _state = State;\n                if (_state == ConnectState.CONNECTING)\n                {\n                    StartPipe();\n                }\n            }\n            catch (Exception e)\n            {\n                LogExceptionAndClose(e);\n            }\n        }\n\n        // do/end xxx tcp/udp Recv\n        private void doConnectionTCPRecv()\n        {\n            if (connection != null && connectionTCPIdle)\n            {\n                connectionTCPIdle = false;\n                var recv_size = remote == null ? RecvSize : remote.TcpMSS - remote.OverHead;\n                var buffer = new byte[recv_size];\n                connection.BeginReceive(buffer, recv_size, SocketFlags.None, PipeConnectionReceiveCallback, null);\n            }\n        }\n\n        private int endConnectionTCPRecv(IAsyncResult ar)\n        {\n            if (connection != null)\n            {\n                var bytesRead = connection.EndReceive(ar);\n                connectionTCPIdle = true;\n                return bytesRead;\n            }\n            return 0;\n        }\n\n        private void doConnectionUDPRecv()\n        {\n            if (connectionUDP != null && connectionUDPIdle)\n            {\n                connectionUDPIdle = false;\n                const int bufferSize = 65536;\n                var sender = new IPEndPoint(connectionUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0);\n                EndPoint tempEP = sender;\n                var buffer = new byte[bufferSize];\n                connectionUDP.BeginReceiveFrom(buffer, 0, bufferSize, SocketFlags.None, ref tempEP,\n                        PipeConnectionUDPReceiveCallback, buffer);\n            }\n        }\n\n        private int endConnectionUDPRecv(IAsyncResult ar, ref EndPoint endPoint)\n        {\n            if (connectionUDP != null)\n            {\n                var bytesRead = connectionUDP.EndReceiveFrom(ar, ref endPoint);\n                if (connectionUDPEndPoint == null)\n                {\n                    connectionUDPEndPoint = (IPEndPoint)endPoint;\n                }\n\n                connectionUDPIdle = true;\n                return bytesRead;\n            }\n            return 0;\n        }\n\n        private void doRemoteTCPRecv()\n        {\n            if (remote != null && remoteTCPIdle)\n            {\n                remoteTCPIdle = false;\n                remote.BeginReceive(new byte[BufferSize], RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null);\n            }\n        }\n\n        private int endRemoteTCPRecv(IAsyncResult ar)\n        {\n            if (remote != null)\n            {\n                var bytesRead = remote.EndReceive(ar, out var sendback);\n\n                var bytesRecv = remote.GetAsyncResultSize(ar);\n                server.SpeedLog.AddDownloadBytes(bytesRecv, DateTime.Now, speedTester.AddDownloadSize(bytesRecv));\n\n                if (sendback)\n                {\n                    RemoteSend(remoteUDPRecvBuffer, 0);\n                    doConnectionRecv();\n                }\n                remoteTCPIdle = true;\n                return bytesRead;\n            }\n            return 0;\n        }\n\n        private void doRemoteUDPRecv()\n        {\n            if (remoteUDP != null && remoteUDPIdle)\n            {\n                remoteUDPIdle = false;\n                const int bufferSize = 65536;\n                var sender = new IPEndPoint(remoteUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0);\n                EndPoint tempEp = sender;\n                remoteUDP.BeginReceiveFrom(new byte[bufferSize], bufferSize, SocketFlags.None, ref tempEp,\n                        PipeRemoteUDPReceiveCallback, null);\n            }\n        }\n\n        private int endRemoteUDPRecv(IAsyncResult ar, ref EndPoint endPoint)\n        {\n            if (remoteUDP != null)\n            {\n                var bytesRead = remoteUDP.EndReceiveFrom(ar, ref endPoint);\n                remoteUDPIdle = true;\n                return bytesRead;\n            }\n            return 0;\n        }\n\n        private void doConnectionRecv()\n        {\n            doConnectionTCPRecv();\n            doConnectionUDPRecv();\n        }\n\n        private void SetObfsPlugin()\n        {\n            int headLen;\n            if (connectionSendBufferList != null && connectionSendBufferList.Count > 0)\n            {\n                headLen = ObfsBase.GetHeadSize(connectionSendBufferList[0], 30);\n            }\n            else\n            {\n                headLen = ObfsBase.GetHeadSize(remoteHeaderSendBuffer, 30);\n            }\n\n            remote?.SetObfsPlugin(server, headLen);\n            remoteUDP?.SetObfsPlugin(server, headLen);\n        }\n\n        private string GetQueryString()\n        {\n            if (remoteHeaderSendBuffer == null)\n            {\n                return null;\n            }\n\n            switch (remoteHeaderSendBuffer[0])\n            {\n                case ATYP_IPv4:\n                {\n                    if (remoteHeaderSendBuffer.Length > 4)\n                    {\n                        return new IPAddress(remoteHeaderSendBuffer.Skip(1).Take(4).ToArray()).ToString();\n                    }\n                    return null;\n                }\n\n                case ATYP_IPv6:\n                {\n                    if (remoteHeaderSendBuffer.Length > 16)\n                    {\n                        return new IPAddress(remoteHeaderSendBuffer.Skip(1).Take(16).ToArray()).ToString();\n                    }\n                    return null;\n                }\n\n                case ATYP_DOMAIN when remoteHeaderSendBuffer.Length > 1:\n                {\n                    if (remoteHeaderSendBuffer.Length > remoteHeaderSendBuffer[1] + 1)\n                    {\n                        return System.Text.Encoding.UTF8.GetString(remoteHeaderSendBuffer, 2, remoteHeaderSendBuffer[1]);\n                    }\n                    break;\n                }\n            }\n            return null;\n        }\n\n        private int GetQueryPort()\n        {\n            if (remoteHeaderSendBuffer == null)\n            {\n                return 0;\n            }\n\n            switch (remoteHeaderSendBuffer[0])\n            {\n                case ATYP_IPv4:\n                {\n                    if (remoteHeaderSendBuffer.Length > 6)\n                    {\n                        return (remoteHeaderSendBuffer[5] << 8) | remoteHeaderSendBuffer[6];\n                    }\n                    return 0;\n                }\n\n                case ATYP_IPv6:\n                {\n                    if (remoteHeaderSendBuffer.Length > 18)\n                    {\n                        return (remoteHeaderSendBuffer[17] << 8) | remoteHeaderSendBuffer[18];\n                    }\n                    return 0;\n                }\n\n                case ATYP_DOMAIN when remoteHeaderSendBuffer.Length > 1:\n                {\n                    if (remoteHeaderSendBuffer.Length > remoteHeaderSendBuffer[1] + 2)\n                    {\n                        var len = remoteHeaderSendBuffer[1];\n                        return (remoteHeaderSendBuffer[len + 2] << 8) | remoteHeaderSendBuffer[len + 3];\n                    }\n\n                    break;\n                }\n            }\n            return 0;\n        }\n\n        // 2 sides connection start\n        private void StartPipe()\n        {\n            try\n            {\n                // set mark\n                connectionTCPIdle = true;\n                connectionUDPIdle = true;\n                remoteTCPIdle = true;\n                remoteUDPIdle = true;\n                closed = false;\n\n                remoteUDPRecvBufferLength = 0;\n                SetObfsPlugin();\n\n                ResetTimeout(cfg.ConnectTimeout);\n\n                speedTester.BeginUpload();\n\n                // remote ready\n                if (connectionUDP == null) // TCP\n                {\n                    if (cfg.ReconnectTimes > 0 || cfg.TargetPort != 0)\n                    {\n                        RemoteSend(remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length);\n                        remoteHeaderSendBuffer = null;\n                    }\n\n                    is_protocol_sendback = remote.isProtocolSendback;\n                    is_obfs_sendback = remote.isObfsSendback;\n                }\n                else // UDP\n                {\n                    if (!server.UdpOverTcp &&\n                        remoteUDP != null)\n                    {\n                        if (cfg.Socks5RemotePort == 0)\n                        {\n                            CloseSocket(ref remote);\n                        }\n\n                        remoteHeaderSendBuffer = null;\n                    }\n                    else if (remoteHeaderSendBuffer != null)\n                    {\n                        RemoteSend(remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length);\n                        remoteHeaderSendBuffer = null;\n                    }\n                }\n                State = ConnectState.CONNECTED;\n\n                if (connection.local_sendback_protocol != null)\n                {\n                    connection.Send(remoteUDPRecvBuffer, 0, SocketFlags.None);\n                }\n\n                // remote recv first\n                doRemoteTCPRecv();\n                doRemoteUDPRecv();\n\n                doConnectionTCPRecv();\n                doConnectionUDPRecv();\n            }\n            catch (Exception e)\n            {\n                LogExceptionAndClose(e);\n            }\n        }\n\n        private void ConnectionSend(byte[] buffer, int bytesToSend)\n        {\n            if (connectionUDP == null)\n            {\n                connection.Send(buffer, bytesToSend, SocketFlags.None);\n                doRemoteUDPRecv();\n            }\n            else\n            {\n                connectionUDP.BeginSendTo(buffer, 0, bytesToSend, SocketFlags.None, connectionUDPEndPoint, PipeConnectionUDPSendCallback, null);\n            }\n        }\n\n        private void UDPoverTCPConnectionSend(byte[] send_buffer, int bytesToSend)\n        {\n            var buffer_list = new List<byte[]>();\n            lock (recvUDPoverTCPLock)\n            {\n                Utils.SetArrayMinSize(ref remoteUDPRecvBuffer, bytesToSend + remoteUDPRecvBufferLength);\n                Array.Copy(send_buffer, 0, remoteUDPRecvBuffer, remoteUDPRecvBufferLength, bytesToSend);\n                remoteUDPRecvBufferLength += bytesToSend;\n                while (remoteUDPRecvBufferLength > 6)\n                {\n                    var len = (remoteUDPRecvBuffer[0] << 8) + remoteUDPRecvBuffer[1];\n                    if (len > remoteUDPRecvBufferLength)\n                    {\n                        break;\n                    }\n\n                    var buffer = new byte[len];\n                    Array.Copy(remoteUDPRecvBuffer, buffer, len);\n                    remoteUDPRecvBufferLength -= len;\n                    Array.Copy(remoteUDPRecvBuffer, len, remoteUDPRecvBuffer, 0, remoteUDPRecvBufferLength);\n\n                    buffer[0] = 0;\n                    buffer[1] = 0;\n                    buffer_list.Add(buffer);\n                }\n            }\n            if (buffer_list.Count == 0)\n            {\n                doRemoteTCPRecv();\n            }\n            else\n            {\n                foreach (var buffer in buffer_list)\n                {\n                    if (buffer == buffer_list[buffer_list.Count - 1])\n                    {\n                        connectionUDP.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, connectionUDPEndPoint, PipeConnectionUDPSendCallback, null);\n                    }\n                    else\n                    {\n                        connectionUDP.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, connectionUDPEndPoint, PipeConnectionUDPSendCallbackNoRecv, null);\n                    }\n                }\n            }\n        }\n\n        private void PipeRemoteReceiveCallback(IAsyncResult ar)\n        {\n            var final_close = false;\n            try\n            {\n                if (closed)\n                {\n                    return;\n                }\n                var bytesRead = endRemoteTCPRecv(ar);\n\n                if (remote.IsClose)\n                {\n                    final_close = true;\n                }\n                else\n                {\n                    remote.GetAsyncResultSize(ar);\n                    if (speedTester.BeginDownload())\n                    {\n                        var pingTime = Convert.ToInt64((speedTester.TimeBeginDownload - speedTester.TimeBeginUpload).TotalMilliseconds);\n                        if (pingTime >= 0)\n                        {\n                            server.SpeedLog.AddConnectTime(pingTime);\n                        }\n                    }\n                    ResetTimeout(cfg.Ttl);\n\n                    speedTester.AddProtocolRecvSize(remote.GetAsyncProtocolSize(ar));\n                    if (bytesRead > 0)\n                    {\n                        var remoteSendBuffer = new byte[BufferSize];\n\n                        Array.Copy(remote.GetAsyncResultBuffer(ar), remoteSendBuffer, bytesRead);\n                        if (connectionUDP == null)\n                        {\n                            if (detector.OnRecv(remoteSendBuffer, bytesRead) > 0)\n                            {\n                                server.SpeedLog.AddErrorTimes();\n                            }\n                            if (detector.Pass)\n                            {\n                                server.SpeedLog.ResetErrorDecodeTimes();\n                            }\n                            else\n                            {\n                                server.SpeedLog.ResetEmptyTimes();\n                            }\n                            connection.Send(remoteSendBuffer, bytesRead, SocketFlags.None);\n                        }\n                        else\n                        {\n                            UDPoverTCPConnectionSend(remoteSendBuffer, bytesRead);\n                        }\n                        server.SpeedLog.AddDownloadRawBytes(bytesRead);\n                        speedTester.AddRecvSize(bytesRead);\n                        _totalRecvSize += bytesRead;\n                    }\n                    if (connectionUDP == null && _totalRecvSize > 1024 * 1024 * 2)\n                    {\n                        PipeRemoteReceiveLoop();\n                    }\n                    else\n                    {\n                        doRemoteTCPRecv();\n                    }\n                }\n            }\n            catch (Exception e)\n            {\n                LogException(e);\n                final_close = true;\n            }\n            finally\n            {\n                if (final_close)\n                {\n                    Close();\n                }\n            }\n        }\n\n        private void PipeRemoteReceiveLoop()\n        {\n            var final_close = false;\n            var recv_buffer = new byte[BufferSize * 4];\n\n            var beforeReceive = DateTime.Now;\n            while (!closed)\n            {\n                try\n                {\n                    var bytesRead = remote.Receive(recv_buffer, RecvSize, SocketFlags.None, out var bytesRecv, out var protocolSize, out var sendback);\n                    var now = DateTime.Now;\n                    if (remote != null && remote.IsClose)\n                    {\n                        final_close = true;\n                        break;\n                    }\n                    if (closed)\n                    {\n                        break;\n                    }\n                    if (speedTester.BeginDownload())\n                    {\n                        var pingTime = Convert.ToInt64((speedTester.TimeBeginDownload - speedTester.TimeBeginUpload).TotalMilliseconds);\n                        if (pingTime >= 0)\n                        {\n                            server.SpeedLog.AddConnectTime(pingTime);\n                        }\n                    }\n                    server.SpeedLog.AddDownloadBytes(bytesRecv, now, speedTester.AddDownloadSize(bytesRecv));\n                    ResetTimeout(cfg.Ttl);\n                    if (sendback)\n                    {\n                        RemoteSend(remoteUDPRecvBuffer, 0);\n                        doConnectionRecv();\n                    }\n\n                    if (bytesRead > 0)\n                    {\n                        var remoteSendBuffer = new byte[BufferSize];\n\n                        Array.Copy(recv_buffer, remoteSendBuffer, bytesRead);\n                        if (connectionUDP == null)\n                        {\n                            if (detector.OnRecv(remoteSendBuffer, bytesRead) > 0)\n                            {\n                                server.SpeedLog.AddErrorTimes();\n                            }\n                            if (detector.Pass)\n                            {\n                                server.SpeedLog.ResetErrorDecodeTimes();\n                            }\n                            else\n                            {\n                                server.SpeedLog.ResetEmptyTimes();\n                            }\n                            connection.Send(remoteSendBuffer, bytesRead, SocketFlags.None);\n                        }\n                        else\n                        {\n                            UDPoverTCPConnectionSend(remoteSendBuffer, bytesRead);\n                        }\n                        speedTester.AddProtocolRecvSize(protocolSize);\n                        server.SpeedLog.AddDownloadRawBytes(bytesRead);\n                        speedTester.AddRecvSize(bytesRead);\n                    }\n\n                    if ((now - beforeReceive).TotalSeconds > 5)\n                    {\n                        _totalRecvSize = 0;\n                        doRemoteTCPRecv();\n                        return;\n                    }\n\n                    beforeReceive = now;\n                }\n                catch (Exception e)\n                {\n                    LogException(e);\n                    final_close = true;\n                    break;\n                }\n            }\n            if (final_close)\n            {\n                Close();\n            }\n        }\n\n        // end ReceiveCallback\n        private void PipeRemoteUDPReceiveCallback(IAsyncResult ar)\n        {\n            var final_close = false;\n            try\n            {\n                if (closed)\n                {\n                    return;\n                }\n                var sender = new IPEndPoint(remoteUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0);\n                EndPoint tempEP = sender;\n\n                var bytesRead = endRemoteUDPRecv(ar, ref tempEP);\n\n                if (remoteUDP.IsClose)\n                {\n                    final_close = true;\n                }\n                else\n                {\n                    var bytesRecv = remoteUDP.GetAsyncResultSize(ar);\n                    if (speedTester.BeginDownload())\n                    {\n                        var pingTime = Convert.ToInt64((speedTester.TimeBeginDownload - speedTester.TimeBeginUpload).TotalMilliseconds);\n                        if (pingTime >= 0)\n                        {\n                            server.SpeedLog.AddConnectTime(pingTime);\n                        }\n                    }\n                    server.SpeedLog.AddDownloadBytes(bytesRecv, DateTime.Now, speedTester.AddDownloadSize(bytesRecv));\n                    ResetTimeout(cfg.Ttl);\n\n                    if (bytesRead <= 0)\n                    {\n                        doRemoteUDPRecv();\n                    }\n                    else //if (bytesRead > 0)\n                    {\n                        ConnectionSend(remoteUDP.GetAsyncResultBuffer(ar), bytesRead);\n\n                        speedTester.AddRecvSize(bytesRead);\n                        server.SpeedLog.AddDownloadRawBytes(bytesRead);\n                    }\n                }\n            }\n            catch (Exception e)\n            {\n                LogException(e);\n                final_close = true;\n            }\n            finally\n            {\n                if (final_close)\n                {\n                    Close();\n                }\n            }\n        }\n\n        private int RemoteSend(byte[] bytes, int length)\n        {\n            var total_len = 0;\n            int send_len;\n            send_len = remote.Send(bytes, length, SocketFlags.None);\n            if (send_len > 0)\n            {\n                server.SpeedLog.AddUploadBytes(send_len, DateTime.Now, speedTester.AddUploadSize(send_len));\n                if (length >= 0)\n                {\n                    ResetTimeout(cfg.Ttl);\n                }\n                else\n                {\n                    ResetTimeout(cfg.ConnectTimeout <= 0 ? 30 : cfg.ConnectTimeout, false);\n                }\n\n                total_len += send_len;\n\n                if ((DateTime.Now - lastKeepTime).TotalSeconds > 5)\n                {\n                    keepCurrentServer?.Invoke(localPort, cfg.TargetHost, server.Id);\n                    lastKeepTime = DateTime.Now;\n                }\n\n                while (true)\n                {\n                    send_len = remote.Send(null, 0, SocketFlags.None);\n                    if (send_len > 0)\n                    {\n                        server.SpeedLog.AddUploadBytes(send_len, DateTime.Now, speedTester.AddUploadSize(send_len));\n                        total_len += send_len;\n                    }\n                    else\n                    {\n                        break;\n                    }\n                }\n            }\n            return total_len;\n        }\n\n        private void RemoteSendto(byte[] bytes, int length)\n        {\n            int send_len;\n            send_len = remoteUDP.BeginSendTo(bytes, length, SocketFlags.None, PipeRemoteUDPSendCallback, null);\n            server.SpeedLog.AddUploadBytes(send_len, DateTime.Now, speedTester.AddUploadSize(send_len));\n        }\n\n        private void PipeConnectionReceiveCallback(IAsyncResult ar)\n        {\n            var final_close = false;\n            try\n            {\n                if (closed)\n                {\n                    return;\n                }\n                var bytesRead = endConnectionTCPRecv(ar);\n\n                if (bytesRead > 0)\n                {\n                    if (connectionUDP != null)\n                    {\n                        doConnectionTCPRecv();\n                        ResetTimeout(cfg.Ttl);\n                        return;\n                    }\n                    var connetionRecvBuffer = new byte[BufferSize];\n                    Array.Copy(((CallbackState)ar.AsyncState).buffer, 0, connetionRecvBuffer, 0, bytesRead);\n                    if (connectionSendBufferList != null)\n                    {\n                        detector.OnSend(connetionRecvBuffer, bytesRead);\n                        var data = new byte[bytesRead];\n                        Array.Copy(connetionRecvBuffer, data, data.Length);\n                        connectionSendBufferList.Add(data);\n                    }\n                    if (State == ConnectState.CONNECTED)\n                    {\n                        if (remoteHeaderSendBuffer != null)\n                        {\n                            Array.Copy(connetionRecvBuffer, 0, connetionRecvBuffer, remoteHeaderSendBuffer.Length, bytesRead);\n                            Array.Copy(remoteHeaderSendBuffer, 0, connetionRecvBuffer, 0, remoteHeaderSendBuffer.Length);\n                            bytesRead += remoteHeaderSendBuffer.Length;\n                            remoteHeaderSendBuffer = null;\n                        }\n                        else\n                        {\n                            Logging.LogBin(LogLevel.Debug, \"remote send\", connetionRecvBuffer, bytesRead);\n                        }\n                    }\n                    if (speedTester.SizeRecv > 0)\n                    {\n                        connectionSendBufferList = null;\n                        server.SpeedLog.ResetContinuousTimes();\n                    }\n                    if (closed || State != ConnectState.CONNECTED)\n                    {\n                        return;\n                    }\n                    if (connectionSendBufferList != null)\n                    {\n                        ResetTimeout(cfg.ConnectTimeout);\n                    }\n                    else\n                    {\n                        ResetTimeout(cfg.Ttl);\n                    }\n                    var send_len = RemoteSend(connetionRecvBuffer, bytesRead);\n                    if (!(send_len == 0 && bytesRead > 0))\n                    {\n                        Task.Run(() =>\n                        {\n                            try\n                            {\n                                doConnectionRecv();\n                            }\n                            catch (Exception ex)\n                            {\n                                local_error = true;\n                                LogException(ex);\n                                Close();\n                            }\n                        });\n                    }\n                }\n                else\n                {\n                    local_error = true;\n                    final_close = true;\n                }\n            }\n            catch (Exception e)\n            {\n                local_error = true;\n                LogException(e);\n                final_close = true;\n            }\n            finally\n            {\n                if (final_close)\n                {\n                    Close();\n                }\n            }\n        }\n\n        private void PipeConnectionUDPReceiveCallback(IAsyncResult ar)\n        {\n            var final_close = false;\n            try\n            {\n                if (closed)\n                {\n                    return;\n                }\n                var sender = new IPEndPoint(connectionUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0);\n                EndPoint tempEP = sender;\n\n                var bytesRead = endConnectionUDPRecv(ar, ref tempEP);\n\n                if (bytesRead > 0)\n                {\n                    var connetionSendBuffer = new byte[bytesRead];\n                    Array.Copy((byte[])ar.AsyncState, connetionSendBuffer, bytesRead);\n                    if (!server.UdpOverTcp && remoteUDP != null)\n                    {\n                        RemoteSendto(connetionSendBuffer, bytesRead);\n                    }\n                    else\n                    {\n                        if (connetionSendBuffer[0] == 0 && connetionSendBuffer[1] == 0)\n                        {\n                            connetionSendBuffer[0] = (byte)(bytesRead >> 8);\n                            connetionSendBuffer[1] = (byte)bytesRead;\n                            RemoteSend(connetionSendBuffer, bytesRead);\n                            doConnectionRecv();\n                        }\n                    }\n                    ResetTimeout(cfg.Ttl);\n                }\n                else\n                {\n                    final_close = true;\n                }\n            }\n            catch (Exception e)\n            {\n                LogException(e);\n                final_close = true;\n            }\n            finally\n            {\n                if (final_close)\n                {\n                    Close();\n                }\n            }\n        }\n\n        private void PipeRemoteUDPSendCallback(IAsyncResult ar)\n        {\n            if (closed)\n            {\n                return;\n            }\n            try\n            {\n                remoteUDP.EndSendTo(ar);\n                doConnectionRecv();\n            }\n            catch (Exception e)\n            {\n                LogExceptionAndClose(e);\n            }\n        }\n\n        private void PipeConnectionUDPSendCallbackNoRecv(IAsyncResult ar)\n        {\n            if (closed)\n            {\n                return;\n            }\n            try\n            {\n                connectionUDP.EndSendTo(ar);\n            }\n            catch (Exception e)\n            {\n                LogExceptionAndClose(e);\n            }\n        }\n\n        private void PipeConnectionUDPSendCallback(IAsyncResult ar)\n        {\n            if (closed)\n            {\n                return;\n            }\n            try\n            {\n                connectionUDP.EndSendTo(ar);\n                doRemoteTCPRecv();\n                doRemoteUDPRecv();\n            }\n            catch (Exception e)\n            {\n                LogExceptionAndClose(e);\n            }\n        }\n\n        protected string getServerUrl(out string remarks)\n        {\n            var s = server;\n            if (s == null)\n            {\n                remarks = \"\";\n                return \"\";\n            }\n            remarks = s.Remarks;\n            return s.server;\n        }\n\n        private void LogException(Exception e)\n        {\n            var err = LogSocketException(e);\n            var server_url = getServerUrl(out var remarks);\n            if (err != 0 && !Logging.LogSocketException(remarks, server_url, e))\n            {\n                Logging.LogUsefulException(e);\n            }\n        }\n\n        private void LogExceptionAndClose(Exception e)\n        {\n            LogException(e);\n            Close();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/HandlerConfig.cs",
    "content": "using Shadowsocks.Enums;\nusing System;\n\nnamespace Shadowsocks.Proxy\n{\n    class HandlerConfig : ICloneable\n    {\n        public string TargetHost;\n        public int TargetPort;\n\n        public double Ttl; // Second\n        public double ConnectTimeout;\n        public int TryKeepAlive;\n        public bool ForceLocalDnsQuery;\n        // Server proxy\n        public ProxyType ProxyType;\n        public string Socks5RemoteHost;\n        public int Socks5RemotePort;\n        public string Socks5RemoteUsername;\n        public string Socks5RemotePassword;\n        public string ProxyUserAgent;\n        // auto ban\n        public bool AutoSwitchOff = true;\n        // Reconnect\n        public int ReconnectTimesRemain;\n        public int ReconnectTimes;\n        public bool Random;\n        public bool ForceRandom;\n\n        public object Clone()\n        {\n            var obj = new HandlerConfig\n            {\n                TargetHost = TargetHost,\n                TargetPort = TargetPort,\n                Ttl = Ttl,\n                ConnectTimeout = ConnectTimeout,\n                TryKeepAlive = TryKeepAlive,\n                ForceLocalDnsQuery = ForceLocalDnsQuery,\n                ProxyType = ProxyType,\n                Socks5RemoteHost = Socks5RemoteHost,\n                Socks5RemotePort = Socks5RemotePort,\n                Socks5RemoteUsername = Socks5RemoteUsername,\n                Socks5RemotePassword = Socks5RemotePassword,\n                ProxyUserAgent = ProxyUserAgent,\n                AutoSwitchOff = AutoSwitchOff,\n                ReconnectTimesRemain = ReconnectTimesRemain,\n                ReconnectTimes = ReconnectTimes,\n                Random = Random,\n                ForceRandom = ForceRandom\n            };\n            return obj;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/HttpParser.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\n\nnamespace Shadowsocks.Proxy\n{\n    internal class HttpParser\n    {\n        public bool httpProxy;\n        public byte[] httpRequestBuffer;\n        public int httpContentLength;\n        //public byte[] lastContentBuffer;\n        public string httpAuthUser;\n        public string httpAuthPass;\n        protected string httpHost;\n        protected int httpPort;\n        private readonly bool _redir;\n\n        public HttpParser(bool redir = false)\n        {\n            this._redir = redir;\n        }\n\n        private static string ParseHostAndPort(string str, ref int port)\n        {\n            string host;\n            if (str.StartsWith(\"[\"))\n            {\n                var pos = str.LastIndexOf(']');\n                if (pos > 0)\n                {\n                    host = str.Substring(1, pos - 1);\n                    if (str.Length > pos + 1 && str[pos + 2] == ':')\n                    {\n                        port = Convert.ToInt32(str.Substring(pos + 2));\n                    }\n                }\n                else\n                {\n                    host = str;\n                }\n            }\n            else\n            {\n                var pos = str.LastIndexOf(':');\n                if (pos > 0)\n                {\n                    host = str.Substring(0, pos);\n                    port = Convert.ToInt32(str.Substring(pos + 1));\n                }\n                else\n                {\n                    host = str;\n                }\n            }\n            return host;\n        }\n\n        protected string ParseURL(string url, string host, int port)\n        {\n            if (url.StartsWith(\"http://\"))\n            {\n                url = url.Substring(7);\n            }\n            if (url.StartsWith(\"[\"))\n            {\n                if (url.StartsWith(\"[\" + host + \"]\"))\n                {\n                    url = url.Substring(host.Length + 2);\n                }\n            }\n            else if (url.StartsWith(host))\n            {\n                url = url.Substring(host.Length);\n            }\n            if (url.StartsWith(\":\"))\n            {\n                if (url.StartsWith(\":\" + port))\n                {\n                    url = url.Substring((\":\" + port).Length);\n                }\n            }\n            if (!url.StartsWith(\"/\"))\n            {\n                var pos_slash = url.IndexOf('/');\n                var pos_space = url.IndexOf(' ');\n                if (pos_slash > 0 && pos_slash < pos_space)\n                {\n                    url = url.Substring(pos_slash);\n                }\n            }\n            if (url.StartsWith(\" \"))\n            {\n                url = \"/\" + url;\n            }\n            return url;\n        }\n\n        public void HostToHandshakeBuffer(string host, int port, ref byte[] remoteHeaderSendBuffer)\n        {\n            if (_redir)\n            {\n                remoteHeaderSendBuffer = new byte[0];\n            }\n            else if (host.Length > 0)\n            {\n                var parsed = IPAddress.TryParse(host, out var ipAddress);\n                if (!parsed)\n                {\n                    remoteHeaderSendBuffer = new byte[2 + host.Length + 2];\n                    remoteHeaderSendBuffer[0] = 3;\n                    remoteHeaderSendBuffer[1] = (byte)host.Length;\n                    Encoding.UTF8.GetBytes(host).CopyTo(remoteHeaderSendBuffer, 2);\n                }\n                else\n                {\n                    if (ipAddress.AddressFamily == AddressFamily.InterNetwork)\n                    {\n                        remoteHeaderSendBuffer = new byte[7];\n                        remoteHeaderSendBuffer[0] = 1;\n                        ipAddress.GetAddressBytes().CopyTo(remoteHeaderSendBuffer, 1);\n                    }\n                    else\n                    {\n                        remoteHeaderSendBuffer = new byte[19];\n                        remoteHeaderSendBuffer[0] = 4;\n                        ipAddress.GetAddressBytes().CopyTo(remoteHeaderSendBuffer, 1);\n                    }\n                }\n                remoteHeaderSendBuffer[remoteHeaderSendBuffer.Length - 2] = (byte)(port >> 8);\n                remoteHeaderSendBuffer[remoteHeaderSendBuffer.Length - 1] = (byte)(port & 0xff);\n            }\n        }\n\n        protected int AppendRequest(ref byte[] Packet, ref int PacketLength)\n        {\n            if (httpContentLength > 0)\n            {\n                if (httpContentLength >= PacketLength)\n                {\n                    httpContentLength -= PacketLength;\n                    PacketLength = 0;\n                    Packet = new byte[0];\n                    return -1;\n                }\n\n                var len = PacketLength - httpContentLength;\n                var nextbuffer = new byte[len];\n                Array.Copy(Packet, httpContentLength, nextbuffer, 0, len);\n                Packet = nextbuffer;\n                PacketLength -= httpContentLength;\n                httpContentLength = 0;\n            }\n            byte[] block = { (byte)'\\r', (byte)'\\n', (byte)'\\r', (byte)'\\n' };\n            int pos;\n            if (httpRequestBuffer == null)\n            {\n                httpRequestBuffer = new byte[PacketLength];\n            }\n            else\n            {\n                Array.Resize(ref httpRequestBuffer, httpRequestBuffer.Length + PacketLength);\n            }\n            Array.Copy(Packet, 0, httpRequestBuffer, httpRequestBuffer.Length - PacketLength, PacketLength);\n            pos = httpRequestBuffer.AsSpan().IndexOf(block);\n            return pos;\n        }\n\n        protected Dictionary<string, string> ParseHttpHeader(string header)\n        {\n            var header_dict = new Dictionary<string, string>();\n            var lines = header.Split(new[] { \"\\r\\n\" }, StringSplitOptions.RemoveEmptyEntries);\n            var cmdItems = lines[0].Split(new[] { ' ' }, 3);\n            for (var index = 1; index < lines.Length; ++index)\n            {\n                var parts = lines[index].Split(new[] { \": \" }, 2, StringSplitOptions.RemoveEmptyEntries);\n                if (parts.Length > 1)\n                {\n                    header_dict[parts[0]] = parts[1];\n                }\n            }\n            header_dict[\"@0\"] = cmdItems[0];\n            header_dict[\"@1\"] = cmdItems[1];\n            header_dict[\"@2\"] = cmdItems[2];\n            return header_dict;\n        }\n\n        protected string HeaderDictToString(Dictionary<string, string> dict)\n        {\n            var result = \"\";\n            var cmd = dict[\"@0\"] + \" \" + dict[\"@1\"] + \" \" + dict[\"@2\"] + \"\\r\\n\";\n            dict.Remove(\"@0\");\n            dict.Remove(\"@1\");\n            dict.Remove(\"@2\");\n            result += \"Host\" + \": \" + dict[\"Host\"] + \"\\r\\n\";\n            dict.Remove(\"Host\");\n            result = dict.Aggregate(result, (current, it) => $\"{current}{it.Key}: {it.Value}\\r\\n\");\n            return cmd + result + \"\\r\\n\";\n        }\n\n        public int HandshakeReceive(byte[] _firstPacket, int _firstPacketLength, out byte[] remoteHeaderSendBuffer)\n        {\n            remoteHeaderSendBuffer = null;\n            var pos = AppendRequest(ref _firstPacket, ref _firstPacketLength);\n            if (pos < 0)\n            {\n                return 1;\n            }\n            var data = Encoding.UTF8.GetString(httpRequestBuffer, 0, pos + 4);\n            {\n                var nextbuffer = new byte[httpRequestBuffer.Length - (pos + 4)];\n                Array.Copy(httpRequestBuffer, pos + 4, nextbuffer, 0, nextbuffer.Length);\n                httpRequestBuffer = nextbuffer;\n            }\n            var header_dict = ParseHttpHeader(data);\n            httpPort = 80;\n            if (header_dict[\"@0\"] == \"CONNECT\")\n            {\n                httpHost = ParseHostAndPort(header_dict[\"@1\"], ref httpPort);\n            }\n            else if (header_dict.ContainsKey(\"Host\"))\n            {\n                httpHost = ParseHostAndPort(header_dict[\"Host\"], ref httpPort);\n            }\n            else\n            {\n                return 500;\n            }\n            if (header_dict.ContainsKey(\"Content-Length\") && Convert.ToInt32(header_dict[\"Content-Length\"]) > 0)\n            {\n                httpContentLength = Convert.ToInt32(header_dict[\"Content-Length\"]) + 2;\n            }\n            HostToHandshakeBuffer(httpHost, httpPort, ref remoteHeaderSendBuffer);\n            if (_redir)\n            {\n                if (header_dict.ContainsKey(\"Proxy-Connection\"))\n                {\n                    header_dict[\"Connection\"] = header_dict[\"Proxy-Connection\"];\n                    header_dict.Remove(\"Proxy-Connection\");\n                }\n                var httpRequest = HeaderDictToString(header_dict);\n                var len = remoteHeaderSendBuffer.Length;\n                var httpData = Encoding.UTF8.GetBytes(httpRequest);\n                Array.Resize(ref remoteHeaderSendBuffer, len + httpData.Length);\n                httpData.CopyTo(remoteHeaderSendBuffer, len);\n                httpProxy = true;\n            }\n            var authOk = string.IsNullOrEmpty(httpAuthUser);\n            if (header_dict.ContainsKey(\"Proxy-Authorization\"))\n            {\n                var authString = header_dict[\"Proxy-Authorization\"].Substring(\"Basic \".Length);\n                var authStr = httpAuthUser + \":\" + (httpAuthPass ?? \"\");\n                var httpAuthString = Convert.ToBase64String(Encoding.UTF8.GetBytes(authStr));\n                if (httpAuthString == authString)\n                {\n                    authOk = true;\n                }\n                header_dict.Remove(\"Proxy-Authorization\");\n            }\n            if (authOk && httpRequestBuffer.Length > 0)\n            {\n                var len = httpRequestBuffer.Length;\n                var httpData = httpRequestBuffer;\n                Array.Resize(ref remoteHeaderSendBuffer, len + remoteHeaderSendBuffer.Length);\n                httpData.CopyTo(remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length - len);\n                httpRequestBuffer = new byte[0];\n            }\n            if (authOk && httpContentLength > 0)\n            {\n                var len = Math.Min(httpRequestBuffer.Length, httpContentLength);\n                Array.Resize(ref remoteHeaderSendBuffer, len + remoteHeaderSendBuffer.Length);\n                Array.Copy(httpRequestBuffer, 0, remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length - len, len);\n                var nextbuffer = new byte[httpRequestBuffer.Length - len];\n                Array.Copy(httpRequestBuffer, len, nextbuffer, 0, nextbuffer.Length);\n                httpRequestBuffer = nextbuffer;\n            }\n            else\n            {\n                httpContentLength = 0;\n                httpRequestBuffer = new byte[0];\n            }\n            if (remoteHeaderSendBuffer == null || !authOk)\n            {\n                return 2;\n            }\n            if (httpProxy)\n            {\n                return 3;\n            }\n            return 0;\n        }\n\n        public static string Http200()\n        {\n            return \"HTTP/1.1 200 Connection Established\\r\\n\\r\\n\";\n        }\n\n        public static string Http407()\n        {\n            var header = \"HTTP/1.1 407 Proxy Authentication Required\\r\\nProxy-Authenticate: Basic realm=\\\"RRR\\\"\\r\\n\";\n            var content = \"<!DOCTYPE HTML PUBLIC \\\"-//W3C//DTD HTML 4.01 Transitional//EN\" +\n                        \" \\\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\\\">\" +\n                        \"<HTML>\" +\n                        \"  <HEAD>\" +\n                        \"    <TITLE>Error</TITLE>\" +\n                        \"    <META HTTP-EQUIV=\\\"Content-Type\\\" CONTENT=\\\"text/html; charset=ISO-8859-1\\\">\" +\n                        \"  </HEAD>\" +\n                        \"  <BODY><H1>407 Proxy Authentication Required.</H1></BODY>\" +\n                        \"</HTML>\\r\\n\";\n            return header + \"\\r\\n\" + content + \"\\r\\n\";\n        }\n\n        public static string Http500()\n        {\n            var header = \"HTTP/1.1 500 Internal Server Error\\r\\n\";\n            var content = \"<!DOCTYPE HTML PUBLIC \\\"-//W3C//DTD HTML 4.01 Transitional//EN\" +\n                        \" \\\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\\\">\" +\n                        \"<HTML>\" +\n                        \"  <HEAD>\" +\n                        \"    <TITLE>Error</TITLE>\" +\n                        \"    <META HTTP-EQUIV=\\\"Content-Type\\\" CONTENT=\\\"text/html; charset=ISO-8859-1\\\">\" +\n                        \"  </HEAD>\" +\n                        \"  <BODY><H1>500 Internal Server Error.</H1></BODY>\" +\n                        \"</HTML>\";\n            return header + \"\\r\\n\" + content + \"\\r\\n\";\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/IHandler.cs",
    "content": "namespace Shadowsocks.Proxy\n{\n    public abstract class IHandler\n    {\n        public abstract void Shutdown();\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/ProxyAuthHandler.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Controller.Service;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Model.Transfer;\nusing Shadowsocks.Util.NetUtils;\nusing System;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\nusing static Shadowsocks.Encryption.EncryptorBase;\n\nnamespace Shadowsocks.Proxy\n{\n    class ProxyAuthHandler\n    {\n        private Configuration _config;\n        private ServerTransferTotal _transfer;\n        private IPRangeSet _IPRange;\n\n        private byte[] _firstPacket;\n        private int _firstPacketLength;\n\n        private Socket _connection;\n        private Socket _connectionUDP;\n        private string local_sendback_protocol;\n\n        protected const int RecvSize = 2048;\n        public const int BufferSize = 18497;\n        protected byte[] _connetionRecvBuffer = new byte[BufferSize];\n\n        private byte _command;\n        protected byte[] _remoteHeaderSendBuffer;\n\n        protected HttpParser httpProxyState;\n\n        private const int CMD_CONNECT = 0x01;\n        private const int CMD_UDP_ASSOC = 0x03;\n\n        public ProxyAuthHandler(Configuration config, ServerTransferTotal transfer, IPRangeSet ipRange, byte[] firstPacket, int length, Socket socket)\n        {\n            var localPort = ((IPEndPoint)socket.LocalEndPoint).Port;\n\n            _config = config;\n            _transfer = transfer;\n            _IPRange = ipRange;\n            _firstPacket = firstPacket;\n            _firstPacketLength = length;\n            _connection = socket;\n            socket.NoDelay = true;\n\n            if (_config.PortMapCache.TryGetValue(localPort, out var portMap) && portMap.type == PortMapType.Forward)\n            {\n                Connect();\n            }\n            else\n            {\n                HandshakeReceive();\n            }\n        }\n\n        private bool AuthConnection(string authUser, string authPass)\n        {\n            if (string.IsNullOrEmpty(_config.AuthUser))\n            {\n                return true;\n            }\n            if (_config.AuthUser == authUser && _config.AuthPass == authPass)\n            {\n                return true;\n            }\n            return IPSubnet.IsLoopBack(((IPEndPoint)_connection.RemoteEndPoint).Address);\n        }\n\n        private void HandshakeReceive()\n        {\n            try\n            {\n                var bytesRead = _firstPacketLength;\n\n                if (bytesRead > 1)\n                {\n                    if (_firstPacket[0] == 4 && _firstPacketLength >= 9\n                    && (!string.IsNullOrEmpty(_config.AuthUser)\n                    || IPSubnet.IsLoopBack(((IPEndPoint)_connection.RemoteEndPoint).Address)))\n                    {\n                        RspSocks4aHandshakeReceive();\n                    }\n                    else if (_firstPacket[0] == 5 && _firstPacketLength >= 3)\n                    {\n                        RspSocks5HandshakeReceive();\n                    }\n                    else\n                    {\n                        RspHttpHandshakeReceive();\n                    }\n                }\n                else\n                {\n                    Close();\n                }\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                Close();\n            }\n        }\n\n        private void RspSocks4aHandshakeReceive()\n        {\n            var firstPacket = new List<byte>();\n            for (var i = 0; i < _firstPacketLength; ++i)\n            {\n                firstPacket.Add(_firstPacket[i]);\n            }\n            var dataSockSend = firstPacket.GetRange(0, 4);\n            dataSockSend[0] = 0;\n            dataSockSend[1] = 90;\n\n            var remoteDNS = _firstPacket[4] == 0 && _firstPacket[5] == 0 && _firstPacket[6] == 0 && _firstPacket[7] == 1;\n            if (remoteDNS)\n            {\n                for (var i = 0; i < 4; ++i)\n                {\n                    dataSockSend.Add(0);\n                }\n                var addrStartPos = firstPacket.IndexOf(0x0, 8);\n                var addr = firstPacket.GetRange(addrStartPos + 1, firstPacket.Count - addrStartPos - 2);\n                _remoteHeaderSendBuffer = new byte[2 + addr.Count + 2];\n                _remoteHeaderSendBuffer[0] = 3;\n                _remoteHeaderSendBuffer[1] = (byte)addr.Count;\n                Array.Copy(addr.ToArray(), 0, _remoteHeaderSendBuffer, 2, addr.Count);\n                _remoteHeaderSendBuffer[2 + addr.Count] = dataSockSend[2];\n                _remoteHeaderSendBuffer[2 + addr.Count + 1] = dataSockSend[3];\n            }\n            else\n            {\n                for (var i = 0; i < 4; ++i)\n                {\n                    dataSockSend.Add(_firstPacket[4 + i]);\n                }\n                _remoteHeaderSendBuffer = new byte[1 + 4 + 2];\n                _remoteHeaderSendBuffer[0] = 1;\n                Array.Copy(dataSockSend.ToArray(), 4, _remoteHeaderSendBuffer, 1, 4);\n                _remoteHeaderSendBuffer[1 + 4] = dataSockSend[2];\n                _remoteHeaderSendBuffer[1 + 4 + 1] = dataSockSend[3];\n            }\n            _command = 1; // Set TCP connect command\n            _connection.Send(dataSockSend.ToArray());\n            Connect();\n        }\n\n        private void RspSocks5HandshakeReceive()\n        {\n            byte[] response = { 5, 0 };\n            if (_firstPacket[0] != 5)\n            {\n                response = new byte[] { 0, 91 };\n                Console.WriteLine(@\"socks 4/5 protocol error\");\n                _connection.Send(response);\n                Close();\n                return;\n            }\n\n            var auth = false;\n            var hasMethod = false;\n            for (var index = 0; index < _firstPacket[1]; ++index)\n            {\n                if (_firstPacket[2 + index] == 0)\n                {\n                    hasMethod = true;\n                }\n                else if (_firstPacket[2 + index] == 2)\n                {\n                    auth = true;\n                    hasMethod = true;\n                }\n            }\n            if (!hasMethod)\n            {\n                Console.WriteLine(@\"Socks5 no acceptable auth method\");\n                Close();\n                return;\n            }\n            if (auth)\n            {\n                response[1] = 2;\n                _connection.BeginSend(response, 0, response.Length, SocketFlags.None, HandshakeAuthSendCallback, null);\n            }\n            else if (string.IsNullOrEmpty(_config.AuthUser)\n            || IPSubnet.IsLoopBack(((IPEndPoint)_connection.RemoteEndPoint).Address))\n            {\n                _connection.BeginSend(response, 0, response.Length, SocketFlags.None, HandshakeSendCallback, null);\n            }\n            else\n            {\n                Console.WriteLine(@\"Socks5 Auth failed\");\n                Close();\n            }\n        }\n\n        private void HandshakeAuthSendCallback(IAsyncResult ar)\n        {\n            try\n            {\n                _connection.EndSend(ar);\n                var bytesRead = _connection.Receive(_connetionRecvBuffer, 1024, 0); //_connection.EndReceive(ar);\n\n                if (bytesRead >= 3)\n                {\n                    var user_len = _connetionRecvBuffer[1];\n                    var pass_len = _connetionRecvBuffer[user_len + 2];\n                    byte[] response = { 1, 0 };\n                    var user = Encoding.UTF8.GetString(_connetionRecvBuffer, 2, user_len);\n                    var pass = Encoding.UTF8.GetString(_connetionRecvBuffer, user_len + 3, pass_len);\n                    if (AuthConnection(user, pass))\n                    {\n                        _connection.BeginSend(response, 0, response.Length, SocketFlags.None, HandshakeSendCallback, null);\n                    }\n                }\n                else\n                {\n                    Console.WriteLine(@\"failed to recv data in HandshakeAuthSendCallback\");\n                    Close();\n                }\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                Close();\n            }\n        }\n\n        private void HandshakeSendCallback(IAsyncResult ar)\n        {\n            try\n            {\n                _connection.EndSend(ar);\n\n                // +-----+-----+-------+------+----------+----------+\n                // | VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |\n                // +-----+-----+-------+------+----------+----------+\n                // |  1  |  1  | X'00' |  1   | Variable |    2     |\n                // +-----+-----+-------+------+----------+----------+\n                // Skip first 3 bytes, and read 2 more bytes to analysis the address.\n                // 2 more bytes is designed if address is domain then we don't need to read once more to get the addr length.\n                // TODO validate\n                _connection.BeginReceive(_connetionRecvBuffer, 0, 3 + ADDR_ATYP_LEN + 1, SocketFlags.None, HandshakeReceive2Callback, null);\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                Close();\n            }\n        }\n\n        private void HandshakeReceive2Callback(IAsyncResult ar)\n        {\n            try\n            {\n                var bytesRead = _connection.EndReceive(ar);\n                if (bytesRead >= 5)\n                {\n                    _command = _connetionRecvBuffer[1];\n                    _remoteHeaderSendBuffer = new byte[bytesRead - 3];\n                    Array.Copy(_connetionRecvBuffer, 3, _remoteHeaderSendBuffer, 0, _remoteHeaderSendBuffer.Length);\n\n                    var size = _remoteHeaderSendBuffer[0] switch\n                    {\n                        ATYP_IPv4 => (4 - 1),\n                        ATYP_IPv6 => (16 - 1),\n                        ATYP_DOMAIN => _remoteHeaderSendBuffer[1],\n                        _ => 0\n                    };\n                    if (size == 0)\n                    {\n                        throw new Exception(\"Wrong socks5 addr type\");\n                    }\n\n                    HandshakeReceive3Callback(size + ADDR_PORT_LEN); // recv port\n                }\n                else\n                {\n                    Console.WriteLine(@\"failed to recv data in HandshakeReceive2Callback\");\n                    Close();\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        private void HandshakeReceive3Callback(int bytesRemain)\n        {\n            try\n            {\n                var bytesRead = _connection.Receive(_connetionRecvBuffer, bytesRemain, SocketFlags.None);\n                if (bytesRead > 0)\n                {\n                    Array.Resize(ref _remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length + bytesRead);\n                    Array.Copy(_connetionRecvBuffer, 0, _remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length - bytesRead, bytesRead);\n                    switch (_command)\n                    {\n                        case CMD_UDP_ASSOC:\n                            RspSocks5UDPHeader(bytesRead);\n                            break;\n                        case CMD_CONNECT:\n                            local_sendback_protocol = @\"socks5\";\n                            Connect();\n                            break;\n                        default:\n                            Logging.Debug($@\"Unsupported CMD={_command}\");\n                            Close();\n                            break;\n                    }\n                }\n                else\n                {\n                    Console.WriteLine(@\"failed to recv data in HandshakeReceive3Callback\");\n                    Close();\n                }\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                Close();\n            }\n        }\n\n        private void RspSocks5UDPHeader(int bytesRead)\n        {\n            var ipv6 = _connection.AddressFamily == AddressFamily.InterNetworkV6;\n            var udpPort = 0;\n            if (bytesRead >= 3 + 6)\n            {\n                ipv6 = _remoteHeaderSendBuffer[0] == 4;\n                if (!ipv6)\n                {\n                    udpPort = _remoteHeaderSendBuffer[5] * 0x100 + _remoteHeaderSendBuffer[6];\n                }\n                else\n                {\n                    udpPort = _remoteHeaderSendBuffer[17] * 0x100 + _remoteHeaderSendBuffer[18];\n                }\n            }\n            if (!ipv6)\n            {\n                _remoteHeaderSendBuffer = new byte[1 + 4 + 2];\n                _remoteHeaderSendBuffer[0] = 0x8 | 1;\n                _remoteHeaderSendBuffer[5] = (byte)(udpPort / 0x100);\n                _remoteHeaderSendBuffer[6] = (byte)(udpPort % 0x100);\n            }\n            else\n            {\n                _remoteHeaderSendBuffer = new byte[1 + 16 + 2];\n                _remoteHeaderSendBuffer[0] = 0x8 | 4;\n                _remoteHeaderSendBuffer[17] = (byte)(udpPort / 0x100);\n                _remoteHeaderSendBuffer[18] = (byte)(udpPort % 0x100);\n            }\n\n            var port = 0;\n            var ip = ipv6 ? IPAddress.IPv6Any : IPAddress.Any;\n            _connectionUDP = new Socket(ip.AddressFamily, SocketType.Dgram, ProtocolType.Udp);\n            for (; port < 65536; ++port)\n            {\n                try\n                {\n                    _connectionUDP.Bind(new IPEndPoint(ip, port));\n                    break;\n                }\n                catch (Exception)\n                {\n                    //\n                }\n            }\n            port = ((IPEndPoint)_connectionUDP.LocalEndPoint).Port;\n            if (!ipv6)\n            {\n                byte[] response = { 5, 0, 0, 1,\n                                0, 0, 0, 0,\n                                (byte)(port / 0x100), (byte)(port % 0x100) };\n                var ip_bytes = ((IPEndPoint)_connection.LocalEndPoint).Address.GetAddressBytes();\n                Array.Copy(ip_bytes, 0, response, 4, 4);\n                _connection.Send(response);\n                Connect();\n            }\n            else\n            {\n                byte[] response = { 5, 0, 0, 4,\n                                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n                                (byte)(port / 0x100), (byte)(port % 0x100) };\n                var ip_bytes = ((IPEndPoint)_connection.LocalEndPoint).Address.GetAddressBytes();\n                Array.Copy(ip_bytes, 0, response, 4, 16);\n                _connection.Send(response);\n                Connect();\n            }\n        }\n\n        private void RspHttpHandshakeReceive()\n        {\n            _command = 1; // Set TCP connect command\n            if (httpProxyState == null)\n            {\n                httpProxyState = new HttpParser();\n            }\n            if (IPSubnet.IsLoopBack(((IPEndPoint)_connection.RemoteEndPoint).Address))\n            {\n                httpProxyState.httpAuthUser = string.Empty;\n                httpProxyState.httpAuthPass = string.Empty;\n            }\n            else\n            {\n                httpProxyState.httpAuthUser = _config.AuthUser;\n                httpProxyState.httpAuthPass = _config.AuthPass;\n            }\n            for (var i = 1; ; ++i)\n            {\n                var err = httpProxyState.HandshakeReceive(_firstPacket, _firstPacketLength, out _remoteHeaderSendBuffer);\n                if (err == 1)\n                {\n                    if (HttpHandshakeRecv())\n                    {\n                        break;\n                    }\n                }\n                else if (err == 2)\n                {\n                    var dataSend = HttpParser.Http407();\n                    var httpData = Encoding.UTF8.GetBytes(dataSend);\n                    _connection.Send(httpData);\n                    if (HttpHandshakeRecv())\n                    {\n                        break;\n                    }\n                }\n                else if (err is 3 or 4)\n                {\n                    Connect();\n                    break;\n                }\n                else if (err == 0)\n                {\n                    local_sendback_protocol = \"http\";\n                    Connect();\n                    break;\n                }\n                else if (err == 500)\n                {\n                    var dataSend = HttpParser.Http500();\n                    var httpData = Encoding.UTF8.GetBytes(dataSend);\n                    _connection.Send(httpData);\n                    if (HttpHandshakeRecv())\n                    {\n                        break;\n                    }\n                }\n                if (i == 3)\n                {\n                    Close();\n                    break;\n                }\n            }\n        }\n\n        private bool HttpHandshakeRecv()\n        {\n            try\n            {\n                var bytesRead = _connection.Receive(_connetionRecvBuffer, _firstPacket.Length, 0);\n                if (bytesRead > 0)\n                {\n                    Array.Copy(_connetionRecvBuffer, _firstPacket, bytesRead);\n                    _firstPacketLength = bytesRead;\n                    return false;\n                }\n\n                Console.WriteLine(@\"failed to recv data in HttpHandshakeRecv\");\n                Close();\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n                Close();\n            }\n            return true;\n        }\n\n        private void Connect()\n        {\n            Server GetCurrentServer(int localPort, ServerSelectStrategy.FilterFunc filter, string targetURI, bool cfgRandom, bool usingRandom, bool forceRandom)\n            => _config.GetCurrentServer(localPort, filter, targetURI, cfgRandom, usingRandom, forceRandom);\n\n            void KeepCurrentServer(int localPort, string targetURI, string id)\n            {\n                _config.KeepCurrentServer(localPort, targetURI, id);\n            }\n\n            var local_port = ((IPEndPoint)_connection.LocalEndPoint).Port;\n            var handler = new Handler\n            {\n                getCurrentServer = GetCurrentServer,\n                keepCurrentServer = KeepCurrentServer,\n                connection = new ProxySocketTunLocal(_connection),\n                connectionUDP = _connectionUDP,\n                cfg =\n                    {\n                            ReconnectTimesRemain = _config.ReconnectTimes,\n                            Random = _config.Random,\n                            ForceRandom = _config.Random\n                    }\n            };\n\n            handler.setServerTransferTotal(_transfer);\n            if (_config.ProxyEnable)\n            {\n                handler.cfg.ProxyType = _config.ProxyType;\n                handler.cfg.Socks5RemoteHost = _config.ProxyHost;\n                handler.cfg.Socks5RemotePort = _config.ProxyPort;\n                handler.cfg.Socks5RemoteUsername = _config.ProxyAuthUser;\n                handler.cfg.Socks5RemotePassword = _config.ProxyAuthPass;\n                handler.cfg.ProxyUserAgent = _config.ProxyUserAgent;\n            }\n            handler.cfg.Ttl = _config.Ttl;\n            handler.cfg.ConnectTimeout = _config.ConnectTimeout;\n            handler.cfg.AutoSwitchOff = _config.AutoBan;\n            if (_config.PortMapCache.ContainsKey(local_port))\n            {\n                var cfg = _config.PortMapCache[local_port];\n                if (cfg.server == null || cfg.id == cfg.server.Id)\n                {\n                    if (cfg.server != null)\n                    {\n                        handler.select_server = (server, selServer) => server.Id == cfg.server.Id;\n                    }\n                    else if (!string.IsNullOrEmpty(cfg.id))\n                    {\n                        handler.select_server = (server, selServer) => server.Group == cfg.id;\n                    }\n                    if (cfg.type == PortMapType.Forward) // tunnel\n                    {\n                        var addr = Encoding.UTF8.GetBytes(cfg.server_addr);\n                        var newFirstPacket = new byte[_firstPacketLength + addr.Length + 4];\n                        newFirstPacket[0] = 3;\n                        newFirstPacket[1] = (byte)addr.Length;\n                        Array.Copy(addr, 0, newFirstPacket, 2, addr.Length);\n                        newFirstPacket[addr.Length + 2] = (byte)(cfg.server_port / 256);\n                        newFirstPacket[addr.Length + 3] = (byte)(cfg.server_port % 256);\n                        Array.Copy(_firstPacket, 0, newFirstPacket, addr.Length + 4, _firstPacketLength);\n                        _remoteHeaderSendBuffer = newFirstPacket;\n                        handler.Start(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, null);\n                    }\n                    else if (_connectionUDP == null && cfg.type == PortMapType.RuleProxy\n                        && new Socks5Forwarder(_config, _IPRange).Handle(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, _connection, local_sendback_protocol))\n                    {\n                    }\n                    else\n                    {\n                        handler.Start(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, @\"socks5\");\n                    }\n                    Dispose();\n                    return;\n                }\n            }\n            else\n            {\n                if (_connectionUDP != null\n                || !new Socks5Forwarder(_config, _IPRange)\n                    .Handle(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, _connection, local_sendback_protocol))\n                {\n                    handler.Start(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, local_sendback_protocol);\n                }\n\n                Dispose();\n                return;\n            }\n            Dispose();\n            Close();\n        }\n\n        private void CloseSocket(ref Socket sock)\n        {\n            lock (this)\n            {\n                if (sock == null)\n                {\n                    return;\n                }\n\n                try\n                {\n                    sock.Shutdown(SocketShutdown.Both);\n                }\n                catch\n                {\n                    // ignored\n                }\n\n                try\n                {\n                    sock.Close();\n                }\n                catch\n                {\n                    // ignored\n                }\n                finally\n                {\n                    sock = null;\n                }\n            }\n        }\n\n        private void Close()\n        {\n            CloseSocket(ref _connection);\n            CloseSocket(ref _connectionUDP);\n\n            _config = null;\n        }\n\n        private void Dispose()\n        {\n            _transfer = null;\n            _IPRange = null;\n\n            _firstPacket = null;\n            _connection = null;\n            _connectionUDP = null;\n\n            _connetionRecvBuffer = null;\n            _remoteHeaderSendBuffer = null;\n\n            httpProxyState = null;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/ProxyEncryptSocket.cs",
    "content": "using Shadowsocks.Encryption;\nusing Shadowsocks.Model;\nusing Shadowsocks.Obfs;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\n\nnamespace Shadowsocks.Proxy\n{\n    class ProxyEncryptSocket\n    {\n        protected Socket _socket;\n        protected EndPoint _socketEndPoint;\n        protected IPEndPoint _remoteUDPEndPoint;\n\n        protected IEncryptor _encryptor;\n        protected object _encryptionLock = new();\n        protected object _decryptionLock = new();\n        protected string _method;\n        protected string _password;\n        public IObfs _protocol;\n        public IObfs _obfs;\n        protected bool _proxy;\n        protected string _proxy_server;\n        protected int _proxy_udp_port;\n\n        public const int MTU = 1492;\n        public const int MSS = MTU - 40;\n        protected const int RecvSize = ProxyAuthHandler.BufferSize;\n        public int TcpMSS = MSS;\n        public int RecvBufferSize;\n        public int OverHead;\n\n        private byte[] SendEncryptBuffer = new byte[RecvSize];\n        private byte[] ReceiveDecryptBuffer = new byte[RecvSize];\n\n        protected bool _close;\n\n        public ProxyEncryptSocket(AddressFamily af, SocketType type, ProtocolType protocol)\n        {\n            _socket = new Socket(af, type, protocol);\n        }\n\n        public Socket GetSocket()\n        {\n            return _socket;\n        }\n\n        public bool IsClose => _close;\n\n        public bool GoS5Proxy\n        {\n            get => _proxy;\n            set => _proxy = value;\n        }\n\n        public bool CanSendKeepAlive => _protocol.isKeepAlive();\n\n        public bool isProtocolSendback => _protocol.isAlwaysSendback();\n\n        public bool isObfsSendback => _obfs.isAlwaysSendback();\n\n        public AddressFamily AddressFamily => _socket.AddressFamily;\n\n        public int Available => _socket.Available;\n\n        public void Shutdown(SocketShutdown how)\n        {\n            _socket.Shutdown(how);\n        }\n\n        public void Close()\n        {\n            _socket.Close();\n\n            if (_protocol != null)\n            {\n                _protocol.Dispose();\n                _protocol = null;\n            }\n            if (_obfs != null)\n            {\n                _obfs.Dispose();\n                _obfs = null;\n            }\n\n            lock (_encryptionLock)\n            {\n                lock (_decryptionLock)\n                {\n                    if (_encryptor != null)\n                    {\n                        _encryptor.Dispose();\n                        _encryptor = null;\n                    }\n                }\n            }\n\n            _socket = null;\n            SendEncryptBuffer = null;\n            ReceiveDecryptBuffer = null;\n        }\n\n        public IAsyncResult BeginConnect(EndPoint ep, AsyncCallback callback, object state)\n        {\n            _close = false;\n            _socketEndPoint = ep;\n            return _socket.BeginConnect(ep, callback, state);\n        }\n\n        public void EndConnect(IAsyncResult ar)\n        {\n            _socket.EndConnect(ar);\n        }\n\n        public void CreateEncryptor(string method, string password)\n        {\n            _encryptor = EncryptorFactory.GetEncryptor(method, password);\n            _method = method;\n            _password = password;\n        }\n\n        public void SetProtocol(IObfs protocol)\n        {\n            _protocol = protocol;\n        }\n\n        public void SetObfs(IObfs obfs)\n        {\n            _obfs = obfs;\n        }\n\n        public void SetObfsPlugin(Server server, int head_len)\n        {\n            lock (server) // need a server lock\n            {\n                if (server.ProtocolData == null)\n                {\n                    server.ProtocolData = _protocol.InitData();\n                }\n                if (server.ObfsData == null)\n                {\n                    server.ObfsData = _obfs.InitData();\n                }\n            }\n            var mss = MSS;\n            var server_addr = server.server;\n            OverHead = _protocol.GetOverhead() + _obfs.GetOverhead();\n            RecvBufferSize = RecvSize - OverHead;\n            if (_proxy_server != null)\n            {\n                server_addr = _proxy_server;\n            }\n\n            _protocol.SetServerInfo(new ServerInfo(server_addr, server.Server_Port, server.ProtocolParam, server.ProtocolData,\n                _encryptor.getIV(), _password, _encryptor.getKey(), head_len, mss, OverHead, RecvBufferSize));\n            _obfs.SetServerInfo(new ServerInfo(server_addr, server.Server_Port, server.ObfsParam, server.ObfsData,\n                _encryptor.getIV(), _password, _encryptor.getKey(), head_len, mss, OverHead, RecvBufferSize));\n        }\n\n        public int Receive(byte[] recv_buffer, int size, SocketFlags flags, out int bytesRead, out int protocolSize, out bool sendback)\n        {\n            bytesRead = _socket.Receive(recv_buffer, size, flags);\n            protocolSize = 0;\n            if (bytesRead > 0)\n            {\n                lock (_decryptionLock)\n                {\n                    var remoteRecvObfsBuffer = _obfs.ClientDecode(recv_buffer, bytesRead, out var obfsRecvSize, out sendback);\n                    if (obfsRecvSize > 0)\n                    {\n                        Util.Utils.SetArrayMinSize(ref ReceiveDecryptBuffer, obfsRecvSize);\n                        _encryptor.Decrypt(remoteRecvObfsBuffer, obfsRecvSize, ReceiveDecryptBuffer, out var bytesToSend);\n                        protocolSize = bytesToSend;\n                        var buffer = _protocol.ClientPostDecrypt(ReceiveDecryptBuffer, bytesToSend, out var outlength);\n                        TcpMSS = _protocol.GetTcpMSS();\n                        //if (recv_buffer.Length < outlength) //ASSERT\n                        Array.Copy(buffer, 0, recv_buffer, 0, outlength);\n                        return outlength;\n                    }\n                }\n                return 0;\n            }\n\n            sendback = false;\n            _close = true;\n            return bytesRead;\n        }\n\n        public IAsyncResult BeginReceive(byte[] buffer, int size, SocketFlags flags, AsyncCallback callback, object state)\n        {\n            var st = new CallbackState();\n            st.buffer = buffer;\n            st.size = size;\n            st.state = state;\n            return _socket.BeginReceive(buffer, 0, size, flags, callback, st);\n        }\n\n        public int EndReceive(IAsyncResult ar, out bool sendback)\n        {\n            var bytesRead = _socket.EndReceive(ar);\n            sendback = false;\n            if (bytesRead > 0)\n            {\n                var st = (CallbackState)ar.AsyncState;\n                st.size = bytesRead;\n\n                lock (_decryptionLock)\n                {\n                    var remoteRecvObfsBuffer = _obfs.ClientDecode(st.buffer, bytesRead, out var obfsRecvSize, out sendback);\n                    if (obfsRecvSize > 0)\n                    {\n                        Util.Utils.SetArrayMinSize(ref ReceiveDecryptBuffer, obfsRecvSize);\n                        _encryptor.Decrypt(remoteRecvObfsBuffer, obfsRecvSize, ReceiveDecryptBuffer, out var bytesToSend);\n                        st.protocol_size = bytesToSend;\n                        var buffer = _protocol.ClientPostDecrypt(ReceiveDecryptBuffer, bytesToSend, out var outlength);\n                        TcpMSS = _protocol.GetTcpMSS();\n                        if (st.buffer.Length < outlength)\n                        {\n                            Array.Resize(ref st.buffer, outlength);\n                        }\n                        Array.Copy(buffer, 0, st.buffer, 0, outlength);\n                        return outlength;\n                    }\n                }\n                return 0;\n            }\n\n            _close = true;\n            return bytesRead;\n        }\n\n        public int SendAll(byte[] buffer, int size, SocketFlags flags)\n        {\n            var sendSize = _socket.Send(buffer, size, flags);\n            while (sendSize < size)\n            {\n                var new_size = _socket.Send(buffer, sendSize, size - sendSize, flags);\n                sendSize += new_size;\n            }\n            return size;\n        }\n\n        public int Send(byte[] buffer, int size, SocketFlags flags)\n        {\n            int obfsSendSize;\n            byte[] obfsBuffer;\n\n            lock (_encryptionLock)\n            {\n                var bytesToEncrypt = _protocol.ClientPreEncrypt(buffer, size, out var outlength);\n                if (bytesToEncrypt == null)\n                {\n                    return 0;\n                }\n\n                Util.Utils.SetArrayMinSize(ref SendEncryptBuffer, outlength + 32);\n                _encryptor.Encrypt(bytesToEncrypt, outlength, SendEncryptBuffer, out var bytesToSend);\n                obfsBuffer = _obfs.ClientEncode(SendEncryptBuffer, bytesToSend, out obfsSendSize);\n            }\n            return SendAll(obfsBuffer, obfsSendSize, flags);\n        }\n\n        public IAsyncResult BeginReceiveFrom(byte[] buffer, int size, SocketFlags flags, ref EndPoint ep, AsyncCallback callback, object state)\n        {\n            var st = new CallbackState();\n            st.buffer = buffer;\n            st.size = size;\n            st.state = state;\n            return _socket.BeginReceiveFrom(buffer, 0, size, flags, ref ep, callback, st);\n        }\n\n        private bool RemoveRemoteUDPRecvBufferHeader(byte[] remoteRecvBuffer, ref int bytesRead)\n        {\n            if (_proxy)\n            {\n                if (bytesRead < 7)\n                {\n                    return false;\n                }\n\n                if (remoteRecvBuffer[3] == 1)\n                {\n                    var head = 3 + 1 + 4 + 2;\n                    bytesRead = bytesRead - head;\n                    Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead);\n                }\n                else if (remoteRecvBuffer[3] == 4)\n                {\n                    var head = 3 + 1 + 16 + 2;\n                    bytesRead = bytesRead - head;\n                    Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead);\n                }\n                else if (remoteRecvBuffer[3] == 3)\n                {\n                    var head = 3 + 1 + 1 + remoteRecvBuffer[4] + 2;\n                    bytesRead = bytesRead - head;\n                    Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead);\n                }\n                else\n                {\n                    return false;\n                }\n                //if (port != server.server_port && port != server.server_udp_port)\n                //{\n                //    return false;\n                //}\n            }\n            return true;\n        }\n\n        protected static byte[] ParseUDPHeader(byte[] buffer, ref int len)\n        {\n            if (buffer.Length == 0)\n            {\n                return buffer;\n            }\n\n            if (buffer[0] == 0x81)\n            {\n                len = len - 1;\n                var ret = new byte[len];\n                Array.Copy(buffer, 1, ret, 0, len);\n                return ret;\n            }\n            if (buffer[0] == 0x80 && len >= 2)\n            {\n                int ofbs_len = buffer[1];\n                if (ofbs_len + 2 < len)\n                {\n                    len = len - ofbs_len - 2;\n                    var ret = new byte[len];\n                    Array.Copy(buffer, ofbs_len + 2, ret, 0, len);\n                    return ret;\n                }\n            }\n            if (buffer[0] == 0x82 && len >= 3)\n            {\n                var ofbs_len = (buffer[1] << 8) + buffer[2];\n                if (ofbs_len + 3 < len)\n                {\n                    len = len - ofbs_len - 3;\n                    var ret = new byte[len];\n                    Array.Copy(buffer, ofbs_len + 3, ret, 0, len);\n                    return ret;\n                }\n            }\n            if (len < buffer.Length)\n            {\n                var ret = new byte[len];\n                Array.Copy(buffer, ret, len);\n                return ret;\n            }\n            return buffer;\n        }\n\n        protected void AddRemoteUDPRecvBufferHeader(byte[] decryptBuffer, byte[] remoteSendBuffer, ref int bytesToSend)\n        {\n            Array.Copy(decryptBuffer, 0, remoteSendBuffer, 3, bytesToSend);\n            remoteSendBuffer[0] = 0;\n            remoteSendBuffer[1] = 0;\n            remoteSendBuffer[2] = 0;\n            bytesToSend += 3;\n        }\n\n        public int EndReceiveFrom(IAsyncResult ar, ref EndPoint ep)\n        {\n            var bytesRead = _socket.EndReceiveFrom(ar, ref ep);\n            if (bytesRead > 0)\n            {\n                var st = (CallbackState)ar.AsyncState;\n                st.size = bytesRead;\n\n                int bytesToSend;\n                if (!RemoveRemoteUDPRecvBufferHeader(st.buffer, ref bytesRead))\n                {\n                    return 0; // drop\n                }\n                var remoteSendBuffer = new byte[RecvSize];\n                byte[] obfsBuffer;\n                lock (_decryptionLock)\n                {\n                    var decryptBuffer = new byte[RecvSize];\n                    _encryptor.ResetDecrypt();\n                    _encryptor.Decrypt(st.buffer, bytesRead, decryptBuffer, out bytesToSend);\n                    obfsBuffer = _protocol.ClientUdpPostDecrypt(decryptBuffer, bytesToSend, out bytesToSend);\n                    decryptBuffer = ParseUDPHeader(obfsBuffer, ref bytesToSend);\n                    AddRemoteUDPRecvBufferHeader(decryptBuffer, remoteSendBuffer, ref bytesToSend);\n                }\n                Array.Copy(remoteSendBuffer, 0, st.buffer, 0, bytesToSend);\n                return bytesToSend;\n            }\n\n            _close = true;\n            return bytesRead;\n        }\n\n        public int BeginSendTo(byte[] buffer, int size, SocketFlags flags, AsyncCallback callback, object state)\n        {\n            var st = new CallbackState();\n            st.buffer = buffer;\n            st.size = size;\n            st.state = state;\n\n            int bytesToSend;\n            var connetionSendBuffer = new byte[RecvSize];\n            var bytes_beg = 3;\n            var length = size - bytes_beg;\n\n            var bytesToEncrypt = new byte[length];\n            Array.Copy(buffer, bytes_beg, bytesToEncrypt, 0, length);\n            lock (_encryptionLock)\n            {\n                _encryptor.ResetEncrypt();\n                _protocol.SetServerInfoIV(_encryptor.getIV());\n                var obfsBuffer = _protocol.ClientUdpPreEncrypt(bytesToEncrypt, length, out var obfsSendSize);\n                _encryptor.Encrypt(obfsBuffer, obfsSendSize, connetionSendBuffer, out bytesToSend);\n            }\n\n            if (_proxy)\n            {\n                var serverURI = _proxy_server;\n                var serverPort = _proxy_udp_port;\n                var parsed = IPAddress.TryParse(serverURI, out var ipAddress);\n                if (!parsed)\n                {\n                    bytesToEncrypt = new byte[bytes_beg + 1 + 1 + serverURI.Length + 2 + bytesToSend];\n                    Array.Copy(connetionSendBuffer, 0, bytesToEncrypt, bytes_beg + 1 + 1 + serverURI.Length + 2, bytesToSend);\n                    bytesToEncrypt[0] = 0;\n                    bytesToEncrypt[1] = 0;\n                    bytesToEncrypt[2] = 0;\n                    bytesToEncrypt[3] = 3;\n                    bytesToEncrypt[4] = (byte)serverURI.Length;\n                    for (var i = 0; i < serverURI.Length; ++i)\n                    {\n                        bytesToEncrypt[5 + i] = (byte)serverURI[i];\n                    }\n                    bytesToEncrypt[5 + serverURI.Length] = (byte)(serverPort / 0x100);\n                    bytesToEncrypt[5 + serverURI.Length + 1] = (byte)(serverPort % 0x100);\n                }\n                else\n                {\n                    var addBytes = ipAddress.GetAddressBytes();\n                    bytesToEncrypt = new byte[bytes_beg + 1 + addBytes.Length + 2 + bytesToSend];\n                    Array.Copy(connetionSendBuffer, 0, bytesToEncrypt, bytes_beg + 1 + addBytes.Length + 2, bytesToSend);\n                    bytesToEncrypt[0] = 0;\n                    bytesToEncrypt[1] = 0;\n                    bytesToEncrypt[2] = 0;\n                    bytesToEncrypt[3] = ipAddress.AddressFamily == AddressFamily.InterNetworkV6 ? (byte)4 : (byte)1;\n                    for (var i = 0; i < addBytes.Length; ++i)\n                    {\n                        bytesToEncrypt[4 + i] = addBytes[i];\n                    }\n                    bytesToEncrypt[4 + addBytes.Length] = (byte)(serverPort / 0x100);\n                    bytesToEncrypt[4 + addBytes.Length + 1] = (byte)(serverPort % 0x100);\n                }\n\n                bytesToSend = bytesToEncrypt.Length;\n                Array.Copy(bytesToEncrypt, connetionSendBuffer, bytesToSend);\n            }\n            _socket.BeginSendTo(connetionSendBuffer, 0, bytesToSend, flags, _remoteUDPEndPoint, callback, st);\n            return bytesToSend;\n        }\n\n        public int EndSendTo(IAsyncResult ar)\n        {\n            return _socket.EndSendTo(ar);\n        }\n\n        public int GetAsyncResultSize(IAsyncResult ar)\n        {\n            var st = (CallbackState)ar.AsyncState;\n            return st.size;\n        }\n\n        public int GetAsyncProtocolSize(IAsyncResult ar)\n        {\n            var st = (CallbackState)ar.AsyncState;\n            return st.protocol_size;\n        }\n\n        public byte[] GetAsyncResultBuffer(IAsyncResult ar)\n        {\n            var st = (CallbackState)ar.AsyncState;\n            return st.buffer;\n        }\n\n        public IPEndPoint GetProxyUdpEndPoint()\n        {\n            return _remoteUDPEndPoint;\n        }\n\n        public bool ConnectSocks5ProxyServer(string strRemoteHost, int iRemotePort, bool udp, string socks5RemoteUsername, string socks5RemotePassword)\n        {\n            var socketErrorCode = (int)SocketError.ConnectionReset;\n            _proxy = true;\n\n            //构造Socks5代理服务器第一连接头(无用户名密码)\n            var bySock5Send = new byte[10];\n            bySock5Send[0] = 5;\n            bySock5Send[1] = socks5RemoteUsername.Length == 0 ? (byte)1 : (byte)2;\n            bySock5Send[2] = 0;\n            bySock5Send[3] = 2;\n\n            //发送Socks5代理第一次连接信息\n            SendAll(bySock5Send, 2 + bySock5Send[1], SocketFlags.None);\n\n            var bySock5Receive = new byte[32];\n            var iRecCount = _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None);\n\n            if (iRecCount < 2)\n            {\n                throw new SocketException(socketErrorCode);\n                //throw new Exception(\"不能获得代理服务器正确响应。\");\n            }\n\n            if (bySock5Receive[0] != 5 || bySock5Receive[1] != 0 && bySock5Receive[1] != 2)\n            {\n                throw new SocketException(socketErrorCode);\n                //throw new Exception(\"代理服务其返回的响应错误。\");\n            }\n\n            if (bySock5Receive[1] != 0) // auth\n            {\n                if (bySock5Receive[1] == 2)\n                {\n                    if (socks5RemoteUsername.Length == 0)\n                    {\n                        throw new SocketException(socketErrorCode);\n                        //throw new Exception(\"代理服务器需要进行身份确认。\");\n                    }\n\n                    bySock5Send = new byte[socks5RemoteUsername.Length + socks5RemotePassword.Length + 3];\n                    bySock5Send[0] = 1;\n                    bySock5Send[1] = (byte)socks5RemoteUsername.Length;\n                    for (var i = 0; i < socks5RemoteUsername.Length; ++i)\n                    {\n                        bySock5Send[2 + i] = (byte)socks5RemoteUsername[i];\n                    }\n                    bySock5Send[socks5RemoteUsername.Length + 2] = (byte)socks5RemotePassword.Length;\n                    for (var i = 0; i < socks5RemotePassword.Length; ++i)\n                    {\n                        bySock5Send[socks5RemoteUsername.Length + 3 + i] = (byte)socks5RemotePassword[i];\n                    }\n                    SendAll(bySock5Send, bySock5Send.Length, SocketFlags.None);\n                    _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None);\n\n                    if (bySock5Receive[0] != 1 || bySock5Receive[1] != 0)\n                    {\n                        throw new SocketException((int)SocketError.ConnectionRefused);\n                    }\n                }\n                else\n                {\n                    return false;\n                }\n            }\n            // connect\n            if (!udp) // TCP\n            {\n                var dataSock5Send = new List<byte> { 5, 1, 0 };\n\n                if (!IPAddress.TryParse(strRemoteHost, out var ipAdd))\n                {\n                    dataSock5Send.Add(3); // remote DNS resolve\n                    dataSock5Send.Add((byte)strRemoteHost.Length);\n                    dataSock5Send.AddRange(strRemoteHost.Select(t => (byte)t));\n                }\n                else\n                {\n                    var addBytes = ipAdd.GetAddressBytes();\n                    if (addBytes.GetLength(0) > 4)\n                    {\n                        dataSock5Send.Add(4); // IPv6\n                        for (var i = 0; i < 16; ++i)\n                        {\n                            dataSock5Send.Add(addBytes[i]);\n                        }\n                    }\n                    else\n                    {\n                        dataSock5Send.Add(1); // IPv4\n                        for (var i = 0; i < 4; ++i)\n                        {\n                            dataSock5Send.Add(addBytes[i]);\n                        }\n                    }\n                }\n\n                dataSock5Send.Add((byte)(iRemotePort / 256));\n                dataSock5Send.Add((byte)(iRemotePort % 256));\n\n                SendAll(dataSock5Send.ToArray(), dataSock5Send.Count, SocketFlags.None);\n                iRecCount = _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None);\n\n                if (iRecCount < 2 || bySock5Receive[0] != 5 || bySock5Receive[1] != 0)\n                {\n                    throw new SocketException(socketErrorCode);\n                    //throw new Exception(\"第二次连接Socks5代理返回数据出错。\");\n                }\n                return true;\n            }\n            else // UDP\n            {\n                var dataSock5Send = new List<byte>();\n                dataSock5Send.Add(5);\n                dataSock5Send.Add(3);\n                dataSock5Send.Add(0);\n\n                var ipAdd = ((IPEndPoint)_socketEndPoint).Address;\n                {\n                    var addBytes = ipAdd.GetAddressBytes();\n                    if (addBytes.GetLength(0) > 4)\n                    {\n                        dataSock5Send.Add(4); // IPv6\n                        for (var i = 0; i < 16; ++i)\n                        {\n                            dataSock5Send.Add(addBytes[i]);\n                        }\n                    }\n                    else\n                    {\n                        dataSock5Send.Add(1); // IPv4\n                        for (var i = 0; i < 4; ++i)\n                        {\n                            dataSock5Send.Add(addBytes[i]);\n                        }\n                    }\n                }\n\n                dataSock5Send.Add(0);\n                dataSock5Send.Add(0);\n\n                SendAll(dataSock5Send.ToArray(), dataSock5Send.Count, SocketFlags.None);\n                _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None);\n\n                if (bySock5Receive[0] != 5 || bySock5Receive[1] != 0)\n                {\n                    throw new SocketException(socketErrorCode);\n                    //throw new Exception(\"第二次连接Socks5代理返回数据出错。\");\n                }\n\n                var ipv6 = bySock5Receive[0] == 4;\n                byte[] addr;\n                int port;\n                if (!ipv6)\n                {\n                    addr = new byte[4];\n                    Array.Copy(bySock5Receive, 4, addr, 0, 4);\n                    port = bySock5Receive[8] * 0x100 + bySock5Receive[9];\n                }\n                else\n                {\n                    addr = new byte[16];\n                    Array.Copy(bySock5Receive, 4, addr, 0, 16);\n                    port = bySock5Receive[20] * 0x100 + bySock5Receive[21];\n                }\n                ipAdd = new IPAddress(addr);\n                _remoteUDPEndPoint = new IPEndPoint(ipAdd, port);\n                return true;\n            }\n        }\n\n        public void SetTcpServer(string server, int port)\n        {\n            _proxy_server = server;\n            _proxy_udp_port = port;\n        }\n\n        public void SetUdpServer(string server, int port)\n        {\n            _proxy_server = server;\n            _proxy_udp_port = port;\n        }\n\n        public void SetUdpEndPoint(IPEndPoint ep)\n        {\n            _remoteUDPEndPoint = ep;\n        }\n\n        public bool ConnectHttpProxyServer(string strRemoteHost, int iRemotePort, string socks5RemoteUsername, string socks5RemotePassword, string proxyUserAgent)\n        {\n            _proxy = true;\n\n            if (IPAddress.TryParse(strRemoteHost, out var ipAdd))\n            {\n                strRemoteHost = ipAdd.ToString();\n            }\n            var host = (strRemoteHost.IndexOf(':') >= 0 ? \"[\" + strRemoteHost + \"]\" : strRemoteHost) + \":\" + iRemotePort;\n            var authstr = Convert.ToBase64String(Encoding.UTF8.GetBytes(socks5RemoteUsername + \":\" + socks5RemotePassword));\n            var cmd = \"CONNECT \" + host + \" HTTP/1.0\\r\\n\"\n                + \"Host: \" + host + \"\\r\\n\";\n            if (!string.IsNullOrEmpty(proxyUserAgent))\n            {\n                cmd += \"User-Agent: \" + proxyUserAgent + \"\\r\\n\";\n            }\n\n            cmd += \"Proxy-Connection: Keep-Alive\\r\\n\";\n            if (socks5RemoteUsername.Length > 0)\n            {\n                cmd += \"Proxy-Authorization: Basic \" + authstr + \"\\r\\n\";\n            }\n\n            cmd += \"\\r\\n\";\n            var httpData = Encoding.UTF8.GetBytes(cmd);\n            SendAll(httpData, httpData.Length, SocketFlags.None);\n            var byReceive = new byte[1024];\n            var iRecCount = _socket.Receive(byReceive, byReceive.Length, SocketFlags.None);\n            if (iRecCount > 13)\n            {\n                var data = Encoding.UTF8.GetString(byReceive, 0, iRecCount);\n                var data_part = data.Split(' ');\n                if (data_part.Length > 1 && data_part[1] == \"200\")\n                {\n                    return true;\n                }\n            }\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/ProxySocketTun.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Text;\n\nnamespace Shadowsocks.Proxy\n{\n    public class ProxySocketTun\n    {\n        protected Socket _socket;\n        protected EndPoint _socketEndPoint;\n        protected IPEndPoint _remoteUDPEndPoint;\n\n        protected bool _proxy;\n        protected string _proxy_server;\n        protected int _proxy_udp_port;\n\n        protected const int RecvSize = 1460 * 2;\n\n        protected bool _close;\n\n        public ProxySocketTun(Socket socket)\n        {\n            _socket = socket;\n        }\n\n        public ProxySocketTun(AddressFamily af, SocketType type, ProtocolType protocol)\n        {\n            _socket = new Socket(af, type, protocol);\n        }\n\n        public Socket GetSocket()\n        {\n            return _socket;\n        }\n\n        public bool IsClose => _close;\n\n        public bool GoS5Proxy\n        {\n            get => _proxy;\n            set => _proxy = value;\n        }\n\n        public AddressFamily AddressFamily => _socket.AddressFamily;\n\n        public int Available => _socket.Available;\n\n        public void Shutdown(SocketShutdown how)\n        {\n            _socket.Shutdown(how);\n        }\n\n        public void Close()\n        {\n            _socket.Close();\n            _socket = null;\n        }\n\n        public IAsyncResult BeginConnect(EndPoint ep, AsyncCallback callback, object state)\n        {\n            _close = false;\n            _socketEndPoint = ep;\n            return _socket.BeginConnect(ep, callback, state);\n        }\n\n        public void EndConnect(IAsyncResult ar)\n        {\n            _socket.EndConnect(ar);\n        }\n\n        public int Receive(byte[] buffer, int size, SocketFlags flags)\n        {\n            return _socket.Receive(buffer, size, flags);\n        }\n\n        public IAsyncResult BeginReceive(byte[] buffer, int size, SocketFlags flags, AsyncCallback callback, object state)\n        {\n            var st = new CallbackState();\n            st.buffer = buffer;\n            st.size = size;\n            st.state = state;\n            return _socket.BeginReceive(buffer, 0, size, flags, callback, st);\n        }\n\n        public int EndReceive(IAsyncResult ar)\n        {\n            var bytesRead = _socket.EndReceive(ar);\n            if (bytesRead > 0)\n            {\n                var st = (CallbackState)ar.AsyncState;\n                st.size = bytesRead;\n                return bytesRead;\n            }\n\n            _close = true;\n            return bytesRead;\n        }\n\n        public int SendAll(byte[] buffer, int size, SocketFlags flags)\n        {\n            var sendSize = _socket.Send(buffer, size, flags);\n            while (sendSize < size)\n            {\n                var new_size = _socket.Send(buffer, sendSize, size - sendSize, flags);\n                sendSize += new_size;\n            }\n            return size;\n        }\n\n        public virtual int Send(byte[] buffer, int size, SocketFlags flags)\n        {\n            return SendAll(buffer, size, flags);\n        }\n\n        public int BeginSend(byte[] buffer, int size, SocketFlags flags, AsyncCallback callback, object state)\n        {\n            var st = new CallbackState();\n            st.size = size;\n            st.state = state;\n\n            _socket.BeginSend(buffer, 0, size, flags, callback, st);\n            return size;\n        }\n\n        public int EndSend(IAsyncResult ar)\n        {\n            return _socket.EndSend(ar);\n        }\n\n        public IAsyncResult BeginReceiveFrom(byte[] buffer, int size, SocketFlags flags, ref EndPoint ep, AsyncCallback callback, object state)\n        {\n            var st = new CallbackState();\n            st.buffer = buffer;\n            st.size = size;\n            st.state = state;\n            return _socket.BeginReceiveFrom(buffer, 0, size, flags, ref ep, callback, st);\n        }\n\n        public int GetAsyncResultSize(IAsyncResult ar)\n        {\n            var st = (CallbackState)ar.AsyncState;\n            return st.size;\n        }\n\n        public byte[] GetAsyncResultBuffer(IAsyncResult ar)\n        {\n            var st = (CallbackState)ar.AsyncState;\n            return st.buffer;\n        }\n\n        public bool ConnectSocks5ProxyServer(string strRemoteHost, int iRemotePort, bool udp, string socks5RemoteUsername, string socks5RemotePassword)\n        {\n            var socketErrorCode = (int)SocketError.ConnectionReset;\n            _proxy = true;\n\n            //构造Socks5代理服务器第一连接头(无用户名密码)\n            var bySock5Send = new byte[10];\n            bySock5Send[0] = 5;\n            bySock5Send[1] = socks5RemoteUsername.Length == 0 ? (byte)1 : (byte)2;\n            bySock5Send[2] = 0;\n            bySock5Send[3] = 2;\n\n            //发送Socks5代理第一次连接信息\n            _socket.Send(bySock5Send, bySock5Send[1] + 2, SocketFlags.None);\n\n            var bySock5Receive = new byte[32];\n            var iRecCount = _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None);\n\n            if (iRecCount < 2)\n            {\n                throw new SocketException(socketErrorCode);\n            }\n\n            if (bySock5Receive[0] != 5 || bySock5Receive[1] != 0 && bySock5Receive[1] != 2)\n            {\n                throw new SocketException(socketErrorCode);\n            }\n\n            if (bySock5Receive[1] != 0) // auth\n            {\n                if (bySock5Receive[1] == 2)\n                {\n                    if (socks5RemoteUsername.Length == 0)\n                    {\n                        throw new SocketException(socketErrorCode);\n                    }\n\n                    bySock5Send = new byte[socks5RemoteUsername.Length + socks5RemotePassword.Length + 3];\n                    bySock5Send[0] = 1;\n                    bySock5Send[1] = (byte)socks5RemoteUsername.Length;\n                    for (var i = 0; i < socks5RemoteUsername.Length; ++i)\n                    {\n                        bySock5Send[2 + i] = (byte)socks5RemoteUsername[i];\n                    }\n                    bySock5Send[socks5RemoteUsername.Length + 2] = (byte)socks5RemotePassword.Length;\n                    for (var i = 0; i < socks5RemotePassword.Length; ++i)\n                    {\n                        bySock5Send[socks5RemoteUsername.Length + 3 + i] = (byte)socks5RemotePassword[i];\n                    }\n                    _socket.Send(bySock5Send, bySock5Send.Length, SocketFlags.None);\n                    _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None);\n\n                    if (bySock5Receive[0] != 1 || bySock5Receive[1] != 0)\n                    {\n                        throw new SocketException((int)SocketError.ConnectionRefused);\n                    }\n                }\n                else\n                {\n                    return false;\n                }\n            }\n            // connect\n            if (!udp) // TCP\n            {\n                var dataSock5Send = new List<byte> { 5, 1, 0 };\n\n                if (!IPAddress.TryParse(strRemoteHost, out var ipAdd))\n                {\n                    dataSock5Send.Add(3); // remote DNS resolve\n                    dataSock5Send.Add((byte)strRemoteHost.Length);\n                    dataSock5Send.AddRange(strRemoteHost.Select(t => (byte)t));\n                }\n                else\n                {\n                    var addBytes = ipAdd.GetAddressBytes();\n                    if (addBytes.GetLength(0) > 4)\n                    {\n                        dataSock5Send.Add(4); // IPv6\n                        for (var i = 0; i < 16; ++i)\n                        {\n                            dataSock5Send.Add(addBytes[i]);\n                        }\n                    }\n                    else\n                    {\n                        dataSock5Send.Add(1); // IPv4\n                        for (var i = 0; i < 4; ++i)\n                        {\n                            dataSock5Send.Add(addBytes[i]);\n                        }\n                    }\n                }\n\n                dataSock5Send.Add((byte)(iRemotePort / 256));\n                dataSock5Send.Add((byte)(iRemotePort % 256));\n\n                _socket.Send(dataSock5Send.ToArray(), dataSock5Send.Count, SocketFlags.None);\n                iRecCount = _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None);\n\n                if (iRecCount < 2 || bySock5Receive[0] != 5 || bySock5Receive[1] != 0)\n                {\n                    throw new SocketException(socketErrorCode);\n                    //throw new Exception(\"第二次连接Socks5代理返回数据出错。\");\n                }\n                return true;\n            }\n            else // UDP\n            {\n                var dataSock5Send = new List<byte>();\n                dataSock5Send.Add(5);\n                dataSock5Send.Add(3);\n                dataSock5Send.Add(0);\n\n                var ipAdd = ((IPEndPoint)_socketEndPoint).Address;\n                {\n                    var addBytes = ipAdd.GetAddressBytes();\n                    if (addBytes.GetLength(0) > 4)\n                    {\n                        dataSock5Send.Add(4); // IPv6\n                        for (var i = 0; i < 16; ++i)\n                        {\n                            dataSock5Send.Add(addBytes[i]);\n                        }\n                    }\n                    else\n                    {\n                        dataSock5Send.Add(1); // IPv4\n                        for (var i = 0; i < 4; ++i)\n                        {\n                            dataSock5Send.Add(addBytes[i]);\n                        }\n                    }\n                }\n\n                dataSock5Send.Add(0);\n                dataSock5Send.Add(0);\n\n                _socket.Send(dataSock5Send.ToArray(), dataSock5Send.Count, SocketFlags.None);\n                _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None);\n\n                if (bySock5Receive[0] != 5 || bySock5Receive[1] != 0)\n                {\n                    throw new SocketException(socketErrorCode);\n                    //throw new Exception(\"第二次连接Socks5代理返回数据出错。\");\n                }\n\n                var ipv6 = bySock5Receive[0] == 4;\n                byte[] addr;\n                int port;\n                if (!ipv6)\n                {\n                    addr = new byte[4];\n                    Array.Copy(bySock5Receive, 4, addr, 0, 4);\n                    port = bySock5Receive[8] * 0x100 + bySock5Receive[9];\n                }\n                else\n                {\n                    addr = new byte[16];\n                    Array.Copy(bySock5Receive, 4, addr, 0, 16);\n                    port = bySock5Receive[20] * 0x100 + bySock5Receive[21];\n                }\n                ipAdd = new IPAddress(addr);\n                _remoteUDPEndPoint = new IPEndPoint(ipAdd, port);\n                return true;\n            }\n        }\n\n        public void SetTcpServer(string server, int port)\n        {\n            _proxy_server = server;\n            _proxy_udp_port = port;\n        }\n\n        public void SetUdpServer(string server, int port)\n        {\n            _proxy_server = server;\n            _proxy_udp_port = port;\n        }\n\n        public void SetUdpEndPoint(IPEndPoint ep)\n        {\n            _remoteUDPEndPoint = ep;\n        }\n\n        public bool ConnectHttpProxyServer(string strRemoteHost, int iRemotePort, string socks5RemoteUsername, string socks5RemotePassword, string proxyUserAgent)\n        {\n            _proxy = true;\n\n            if (IPAddress.TryParse(strRemoteHost, out var ipAdd))\n            {\n                strRemoteHost = ipAdd.ToString();\n            }\n            var host = (strRemoteHost.IndexOf(':') >= 0 ? \"[\" + strRemoteHost + \"]\" : strRemoteHost) + \":\" + iRemotePort;\n            var authstr = Convert.ToBase64String(Encoding.UTF8.GetBytes(socks5RemoteUsername + \":\" + socks5RemotePassword));\n            var cmd = \"CONNECT \" + host + \" HTTP/1.0\\r\\n\"\n                + \"Host: \" + host + \"\\r\\n\";\n            if (!string.IsNullOrEmpty(proxyUserAgent))\n            {\n                cmd += \"User-Agent: \" + proxyUserAgent + \"\\r\\n\";\n            }\n\n            cmd += \"Proxy-Connection: Keep-Alive\\r\\n\";\n            if (socks5RemoteUsername.Length > 0)\n            {\n                cmd += \"Proxy-Authorization: Basic \" + authstr + \"\\r\\n\";\n            }\n\n            cmd += \"\\r\\n\";\n            var httpData = Encoding.UTF8.GetBytes(cmd);\n            _socket.Send(httpData, httpData.Length, SocketFlags.None);\n            var byReceive = new byte[1024];\n            var iRecCount = _socket.Receive(byReceive, byReceive.Length, SocketFlags.None);\n            if (iRecCount > 13)\n            {\n                var data = Encoding.UTF8.GetString(byReceive, 0, iRecCount);\n                var data_part = data.Split(' ');\n                if (data_part.Length > 1 && data_part[1] == \"200\")\n                {\n                    return true;\n                }\n            }\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Proxy/ProxySocketTunLocal.cs",
    "content": "using System.Net.Sockets;\n\nnamespace Shadowsocks.Proxy\n{\n    public class ProxySocketTunLocal : ProxySocketTun\n    {\n        public string local_sendback_protocol;\n\n        public ProxySocketTunLocal(Socket socket) : base(socket)\n        {\n        }\n\n        public override int Send(byte[] buffer, int size, SocketFlags flags)\n        {\n            if (local_sendback_protocol != null)\n            {\n                if (local_sendback_protocol == \"http\")\n                {\n                    var data = System.Text.Encoding.UTF8.GetBytes(\"HTTP/1.1 200 Connection Established\\r\\n\\r\\n\");\n                    _socket.Send(data, data.Length, 0);\n                }\n                else if (local_sendback_protocol == \"socks5\")\n                {\n                    if (_socket.AddressFamily == AddressFamily.InterNetwork)\n                    {\n                        byte[] response =\n                        {\n                                5, 0, 0, 1,\n                                0, 0, 0, 0,\n                                0, 0\n                        };\n                        _socket.Send(response);\n                    }\n                    else\n                    {\n                        byte[] response =\n                        {\n                                5, 0, 0, 4,\n                                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n                                0, 0\n                        };\n                        _socket.Send(response);\n                    }\n                }\n\n                local_sendback_protocol = null;\n            }\n\n            return SendAll(buffer, size, flags);\n        }\n\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/SyncfusionLicenseRegister.bat",
    "content": "@echo on&setlocal\n    setlocal enableextensions disabledelayedexpansion\n\n\t::Arguments of either PreBuild or PostBuild\n\tset buildType=%1\n\t::License key replacement file\n\tset sourceFile=%2\n\t\n\t::Replacement string\n    set DummyKey=##SyncfusionLicense##\n\tset LicenseKey=%SyncfusionLicenseKey%\n\t\n\t::Replacement statement\n\tif NOT \"%LicenseKey%\" == \"\" (\n\t\tif \"%buildType%\" == \"PostBuild\" (\n\t\tpowershell -Command \"(gc %sourceFile%) -Replace '%LicenseKey%','%DummyKey%'|SC %sourceFile%\"\n\t\t)\n\t\tif \"%buildType%\" == \"PreBuild\" (\n\t\tpowershell -Command \"(gc %sourceFile%) -Replace '%DummyKey%','%LicenseKey%'|SC %sourceFile%\"\n\t\t)\n\t)"
  },
  {
    "path": "shadowsocks-csharp/Util/Base64.cs",
    "content": "using System;\nusing System.Text;\n\nnamespace Shadowsocks.Util\n{\n    public static class Base64\n    {\n        public static string DecodeBase64(string val)\n        {\n            return Encoding.UTF8.GetString(DecodeBase64ToBytes(val));\n        }\n\n        private static byte[] DecodeBase64ToBytes(string val)\n        {\n            var data = val.PadRight(val.Length + (4 - val.Length % 4) % 4, '=');\n            return Convert.FromBase64String(data);\n        }\n\n        private static string EncodeUrlSafeBase64(byte[] val, bool trim)\n        {\n            return trim ? Convert.ToBase64String(val).Replace('+', '-').Replace('/', '_').TrimEnd('=') : Convert.ToBase64String(val).Replace('+', '-').Replace('/', '_');\n        }\n\n        private static byte[] DecodeUrlSafeBase64ToBytes(string val)\n        {\n            var data = val.Replace('-', '+').Replace('_', '/').PadRight(val.Length + (4 - val.Length % 4) % 4, '=');\n            return Convert.FromBase64String(data);\n        }\n\n        public static string EncodeUrlSafeBase64(string val, bool trim = true)\n        {\n            return EncodeUrlSafeBase64(Encoding.UTF8.GetBytes(val), trim);\n        }\n\n        public static string DecodeUrlSafeBase64(string val)\n        {\n            return Encoding.UTF8.GetString(DecodeUrlSafeBase64ToBytes(val));\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/CRC.cs",
    "content": "using CryptoBase.Digests;\nusing System;\nusing System.Buffers.Binary;\n\nnamespace Shadowsocks.Util\n{\n    public static class CRC32\n    {\n        public static ulong CalcCRC32(byte[] input, int len)\n        {\n            using var hash = DigestUtils.Create(DigestType.Crc32);\n            var t = new byte[hash.Length];\n            hash.UpdateFinal(input.AsSpan(0, len), t);\n            return BinaryPrimitives.ReadUInt32BigEndian(t);\n        }\n\n        public static void SetCRC32(byte[] buffer)\n        {\n            using var hash = DigestUtils.Create(DigestType.Crc32);\n            var t = new byte[hash.Length];\n            hash.UpdateFinal(buffer.AsSpan(0, buffer.Length - 4), t);\n            var x = ~BinaryPrimitives.ReadUInt32BigEndian(t);\n            BinaryPrimitives.WriteUInt32LittleEndian(buffer.AsSpan(buffer.Length - 4), x);\n        }\n    }\n\n    public static class Adler32\n    {\n        public static ulong CalcAdler32(byte[] input, int len)\n        {\n            ulong a = 1;\n            ulong b = 0;\n            for (var i = 0; i < len; ++i)\n            {\n                a += input[i];\n                b += a;\n            }\n            a %= 65521;\n            b %= 65521;\n            return (b << 16) + a;\n        }\n\n        public static bool CheckAdler32(byte[] input, int len)\n        {\n            var adler32 = CalcAdler32(input, len - 4);\n            var checksum = BinaryPrimitives.ReadUInt32LittleEndian(input.AsSpan(len - 4));\n            return (uint)adler32 == checksum;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/ColorConvert.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Windows.Media;\nusing Color = System.Windows.Media.Color;\n\nnamespace Shadowsocks.Util\n{\n    public static class ColorConvert\n    {\n        public static Color EnableColor = Color.FromRgb(0, 255, 170);\n        public static readonly Brush EnableBrush = new SolidColorBrush(EnableColor);\n        public static Color DisableColor = Colors.Red;\n        public static readonly Brush DisableBrush = new SolidColorBrush(DisableColor);\n\n        public static Color TotalDownloadColor1 = Color.FromRgb(229, 255, 246);\n        public static readonly Brush TotalDownloadBrush1 = new SolidColorBrush(TotalDownloadColor1);\n        public static Color TotalDownloadColor2 = Color.FromRgb(218, 242, 234);\n        public static readonly Brush TotalDownloadBrush2 = new SolidColorBrush(TotalDownloadColor2);\n\n        public static Color TotalUploadColor1 = Color.FromRgb(255, 229, 229);\n        public static readonly Brush TotalUploadBrush1 = new SolidColorBrush(TotalUploadColor1);\n        public static Color TotalUploadColor2 = Color.FromRgb(242, 218, 218);\n        public static readonly Brush TotalUploadBrush2 = new SolidColorBrush(TotalUploadColor2);\n\n        public static Color TotalDownloadRawColor1 = Color.FromRgb(255, 255, 229);\n        public static readonly Brush TotalDownloadRawBrush1 = new SolidColorBrush(TotalDownloadRawColor1);\n        public static Color TotalDownloadRawColor2 = Color.FromRgb(242, 242, 218);\n        public static readonly Brush TotalDownloadRawBrush2 = new SolidColorBrush(TotalDownloadRawColor2);\n\n        private static readonly Color[] SpeedColorList = { Colors.White, Colors.LightGreen, Colors.Yellow, Colors.Pink, Colors.Red };\n        private static readonly long[] SpeedBytesList = { 0, 1024 * 64, 1024 * 512, 1024 * 1024 * 4, 1024 * 1024 * 16 };\n\n        private static readonly Color[] ConnectionColorList = { Colors.White, Colors.LightGreen, Colors.Yellow, Colors.Red };\n        private static readonly long[] ConnectionBytesList = { 0, 16, 32, 64 };\n\n        private static readonly Color[] LatencyColorList = { Colors.White, Colors.LightGreen, Colors.Yellow, Colors.Red };\n        private static readonly long[] LatencyList = { 0, 128, 256, 512 };\n\n        private static byte ColorMix(byte a, byte b, double alpha)\n        {\n            return (byte)(b * alpha + a * (1 - alpha));\n        }\n\n        private static Color ColorMix(Color a, Color b, double alpha)\n        {\n            return Color.FromRgb(ColorMix(a.R, b.R, alpha),\n                    ColorMix(a.G, b.G, alpha),\n                    ColorMix(a.B, b.B, alpha));\n        }\n\n        public static Color GetSpeedColor(long bytes)\n        {\n            for (var i = 1; i < SpeedColorList.Length; ++i)\n            {\n                if (bytes < SpeedBytesList[i])\n                {\n                    return ColorMix(SpeedColorList[i - 1],\n                                    SpeedColorList[i],\n                                    (double)(bytes - SpeedBytesList[i - 1]) / (SpeedBytesList[i] - SpeedBytesList[i - 1]));\n                }\n            }\n            return SpeedColorList.Last();\n        }\n\n        public static Color GetConnectionColor(long connections)\n        {\n            for (var i = 1; i < ConnectionColorList.Length; ++i)\n            {\n                if (connections < ConnectionBytesList[i])\n                {\n                    return ColorMix(ConnectionColorList[i - 1],\n                                    ConnectionColorList[i],\n                                    (double)(connections - ConnectionBytesList[i - 1]) / (ConnectionBytesList[i] - ConnectionBytesList[i - 1]));\n                }\n            }\n            return ConnectionColorList.Last();\n        }\n\n        public static Color GetLatencyColor(long latency)\n        {\n            for (var i = 1; i < ConnectionColorList.Length; ++i)\n            {\n                if (latency < LatencyList[i])\n                {\n                    return ColorMix(LatencyColorList[i - 1],\n                                    LatencyColorList[i],\n                                    (double)(latency - LatencyList[i - 1]) / (LatencyList[i] - LatencyList[i - 1]));\n                }\n            }\n            return ConnectionColorList.Last();\n        }\n\n        public static Color GetConnectErrorColor(long val)\n        {\n            return Color.FromRgb(255, (byte)Math.Max(0, 255 - val * 2.5), (byte)Math.Max(0, 255 - val * 2.5));\n        }\n\n        public static Color GetConnectEmptyColor(long val)\n        {\n            return Color.FromRgb(255, (byte)Math.Max(0, 255 - val * 8), (byte)Math.Max(0, 255 - val * 8));\n        }\n\n        public static Color GetErrorPercentColor(double? percent)\n        {\n            if (percent != null)\n            {\n                return Color.FromRgb(255, (byte)(255 - percent * 2), (byte)(255 - percent * 2));\n            }\n            return Colors.Transparent;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/Constants.cs",
    "content": "namespace Shadowsocks.Util\n{\n    internal static class Constants\n    {\n        public const string ParameterMultiplyInstance = @\"-show\";\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/I18NUtil.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Shadowsocks.Util\n{\n    public static class I18NUtil\n    {\n        private const string DefaultLanguage = @\"en-US\";\n\n        public static string CurrentLanguage;\n\n        public static readonly Dictionary<string, string> SupportLanguage = new()\n        {\n            { @\"zh-CN\", @\"zh-CN\" },\n            { @\"zh\", @\"zh-CN\" },\n            { @\"zh-Hans\", @\"zh-CN\" },\n            { @\"zh-SG\", @\"zh-CN\" },\n            { @\"zh-Hant\", @\"zh-TW\" },\n            { @\"zh-HK\", @\"zh-TW\" },\n            { @\"zh-TW\", @\"zh-TW\" },\n            { @\"zh-MO\", @\"zh-TW\" },\n            { @\"en-US\", @\"en-US\" }\n        };\n\n        public static string GetLanguage(string langName = @\"\")\n        {\n            if (string.IsNullOrEmpty(langName))\n            {\n                langName = System.Globalization.CultureInfo.CurrentCulture.Name;\n            }\n\n            if (SupportLanguage.TryGetValue(langName, out var res))\n            {\n                return res;\n            }\n            return DefaultLanguage;\n        }\n\n        public static void SetLanguage(string langName)\n        {\n            SetLanguage(Application.Current.Resources, @\"App\", langName);\n            CurrentLanguage = langName;\n        }\n\n        public static string GetAppStringValue(string key)\n        {\n            if (Application.Current.Resources.MergedDictionaries[0][key] is string str)\n            {\n                return str;\n            }\n            return key;\n        }\n\n        public static string GetWindowStringValue(this Window window, string key)\n        {\n            if (window.Resources.MergedDictionaries[0][key] is string str)\n            {\n                return str;\n            }\n            return key;\n        }\n\n        public static void SetLanguage(ResourceDictionary resources, string filename, string langName = @\"\")\n        {\n            langName = GetLanguage(string.IsNullOrEmpty(langName) ? CurrentLanguage : langName);\n\n            var url = new Uri($@\"../I18N/{filename}.{langName}.xaml\", UriKind.Relative);\n            if (resources.MergedDictionaries.Count > 0)\n            {\n                resources.MergedDictionaries[0].Source = url;\n            }\n            else if (Application.LoadComponent(url) is ResourceDictionary langRd)\n            {\n                resources.MergedDictionaries.Add(langRd);\n            }\n        }\n\n        public static void SetLanguage(object obj)\n        {\n            if (obj is ContextMenu contextMenu)\n            {\n                foreach (var o in contextMenu.Items)\n                {\n                    if (o is MenuItem)\n                    {\n                        SetLanguage(o);\n                    }\n                }\n            }\n            else if (obj is MenuItem menuItem)\n            {\n                menuItem.Header = GetAppStringValue(menuItem.Name);\n                foreach (var o in menuItem.Items)\n                {\n                    if (o is MenuItem)\n                    {\n                        SetLanguage(o);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/JsonUtils.cs",
    "content": "using System.Text.Encodings.Web;\nusing System.Text.Json;\n\nnamespace Shadowsocks.Util\n{\n    public static class JsonUtils\n    {\n        private static readonly JsonSerializerOptions Options = new()\n        {\n            WriteIndented = true,\n            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping\n        };\n\n        private static readonly JsonSerializerOptions StrictOptions = new()\n        {\n            WriteIndented = true,\n            Encoder = JavaScriptEncoder.Default\n        };\n\n        public static string Serialize(object obj, bool strict)\n        {\n            return JsonSerializer.Serialize(obj, strict ? StrictOptions : Options);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/NetUtils/DnsUtil.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Model;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Reactive.Linq;\nusing System.Threading.Tasks;\n\n#nullable enable\n\nnamespace Shadowsocks.Util.NetUtils\n{\n    public static class DnsUtil\n    {\n        public static LRUCache<string, IPAddress> DnsBuffer { get; } = new();\n\n        public static IPAddress? QueryDns(string host)\n        {\n            var res = host.Contains('.') && Global.GuiConfig.DnsClients.Any(s => s.Enable)\n                    ? QueryAsync(host, Global.GuiConfig.DnsClients).Result\n                    : QueryDefaultAsync(host).Result;\n            Logging.Info(res is null\n                    ? $@\"DNS query {host} failed.\"\n                    : $@\"DNS query {host} answer {res}\");\n            return res;\n        }\n\n        public static async Task<IPAddress?> QueryDefaultAsync(string host, bool ipv6First = default)\n        {\n            return await DnsClient.QueryIpAddressDefaultAsync(host, ipv6First, default);\n        }\n\n        public static async Task<IPAddress?> QueryAsync(string host, IEnumerable<DnsClient> clients)\n        {\n            return await clients\n                    .Where(client => client.Enable)\n                    .Select(s => Observable\n                            .FromAsync(ct => s.QueryIpAddressAsync(host, ct))\n                            .Where(ip => ip is not null)\n                    )\n                    .Merge()\n                    .FirstOrDefaultAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/NetUtils/IPSubnet.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\n\nnamespace Shadowsocks.Util.NetUtils\n{\n    public static class IPSubnet\n    {\n        public static bool IsInSubnet(this IPAddress address, string subnetMask)\n        {\n            var slashIdx = subnetMask.IndexOf(\"/\", StringComparison.Ordinal);\n            if (!subnetMask.Contains(\"/\"))\n            {\n                // We only handle netmasks in format \"IP/PrefixLength\".\n                throw new NotSupportedException(\"Only SubNetMasks with a given prefix length are supported.\");\n            }\n\n            // First parse the address of the netmask before the prefix length.\n            var maskAddress = IPAddress.Parse(subnetMask.Substring(0, slashIdx));\n\n            if (maskAddress.AddressFamily != address.AddressFamily)\n            { // We got something like an IPV4-Address for an IPv6-Mask. This is not valid.\n                return false;\n            }\n\n            // Now find out how long the prefix is.\n            var maskLength = int.Parse(subnetMask.Substring(slashIdx + 1));\n\n            if (maskAddress.AddressFamily == AddressFamily.InterNetwork)\n            {\n                // Convert the mask address to an unsigned integer.\n                var maskAddressBits = BitConverter.ToUInt32(maskAddress.GetAddressBytes().Reverse().ToArray());\n\n                // And convert the IpAddress to an unsigned integer.\n                var ipAddressBits = BitConverter.ToUInt32(address.GetAddressBytes().Reverse().ToArray());\n\n                // Get the mask/network address as unsigned integer.\n                var mask = uint.MaxValue << (32 - maskLength);\n\n                // https://stackoverflow.com/a/1499284/3085985\n                // Bitwise AND mask and MaskAddress, this should be the same as mask and IpAddress\n                // as the end of the mask is 0000 which leads to both addresses to end with 0000\n                // and to start with the prefix.\n                return (maskAddressBits & mask) == (ipAddressBits & mask);\n            }\n\n            if (maskAddress.AddressFamily == AddressFamily.InterNetworkV6)\n            {\n                // Convert the mask address to a BitArray.\n                var maskAddressBits = new BitArray(maskAddress.GetAddressBytes());\n\n                // And convert the IpAddress to a BitArray.\n                var ipAddressBits = new BitArray(address.GetAddressBytes());\n\n                if (maskAddressBits.Length != ipAddressBits.Length)\n                {\n                    throw new ArgumentException(\"Length of IP Address and Subnet Mask do not match.\");\n                }\n\n                // Compare the prefix bits.\n                for (var i = 0; i < maskLength; i++)\n                {\n                    if (ipAddressBits[i] != maskAddressBits[i])\n                    {\n                        return false;\n                    }\n                }\n\n                return true;\n            }\n\n            throw new NotSupportedException(\"Only InterNetworkV6 or InterNetwork address families are supported.\");\n        }\n\n        public static bool IsLoopBack(IPAddress ip)\n        {\n            return Equals(ip, IPAddress.IPv6Loopback) || ip.IsInSubnet(@\"127.0.0.0/8\");\n        }\n\n        public static bool IsLocal(IPAddress ip)\n        {\n            return ip.IsInSubnet(@\"127.0.0.0/8\") || ip.IsInSubnet(@\"169.254.0.0/16\") || ip.IsInSubnet(@\"::1/128\");\n        }\n\n        public static bool IsLocal(Socket socket)\n        {\n            return IsLocal(((IPEndPoint)socket.RemoteEndPoint).Address);\n        }\n\n        public static bool IsLan(IPAddress ip)\n        {\n            var netmasks = new[]\n            {\n                    @\"0.0.0.0/8\",\n                    @\"10.0.0.0/8\",\n                    //\"100.64.0.0/10\", //部分地区运营商貌似在使用这个，这个可能不安全\n                    @\"127.0.0.0/8\",\n                    @\"169.254.0.0/16\",\n                    @\"172.16.0.0/12\",\n                    //\"192.0.0.0/24\",\n                    //\"192.0.2.0/24\",\n                    //\"192.88.99.0/24\",\n                    @\"192.168.0.0/16\",\n                    //\"198.18.0.0/15\",\n                    //\"198.51.100.0/24\",\n                    //\"203.0.113.0/24\",\n                    @\"::1/128\",\n                    @\"fc00::/7\",\n                    @\"fe80::/10\"\n            };\n            return netmasks.Any(ip.IsInSubnet);\n        }\n\n        public static bool IsLan(Socket socket)\n        {\n            return IsLan(((IPEndPoint)socket.RemoteEndPoint).Address);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/NetUtils/SocketUtil.cs",
    "content": "using System;\nusing System.Net.Sockets;\n\nnamespace Shadowsocks.Util.NetUtils\n{\n    public static class SocketUtil\n    {\n        public static void FullClose(this Socket s)\n        {\n            try\n            {\n                s.Shutdown(SocketShutdown.Both);\n            }\n            catch (Exception)\n            {\n                // ignored\n            }\n\n            try\n            {\n                s.Disconnect(false);\n            }\n            catch (Exception)\n            {\n                // ignored\n            }\n\n            try\n            {\n                s.Close();\n            }\n            catch (Exception)\n            {\n                // ignored\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/NetUtils/WrappedSocket.cs",
    "content": "using System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\n\nnamespace Shadowsocks.Util.NetUtils\n{\n    /*\n     * A wrapped socket class which support both ipv4 and ipv6 based on the\n     * connected remote endpoint.\n     * \n     * If the server address is host name, then it may have both ipv4 and ipv6 address\n     * after resolving. The main idea is we don't want to resolve and choose the address\n     * by ourselves. Instead, Socket.ConnectAsync() do handle this thing internally by trying\n     * each address and returning an established socket connection.\n     */\n    public class WrappedSocket\n    {\n        public EndPoint LocalEndPoint => _activeSocket?.LocalEndPoint;\n\n        // Only used during connection and close, so it won't cost too much.\n        private SpinLock _socketSyncLock = new();\n\n        private bool _disposed;\n        private bool Connected => _activeSocket != null;\n        private Socket _activeSocket;\n\n\n        public void BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n            if (Connected)\n            {\n                throw new SocketException((int)SocketError.IsConnected);\n            }\n\n            var arg = new SocketAsyncEventArgs { RemoteEndPoint = remoteEP };\n            arg.Completed += OnTcpConnectCompleted;\n            arg.UserToken = new TcpUserToken(callback, state);\n\n            if (!Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg))\n            {\n                OnTcpConnectCompleted(this, arg);\n            }\n        }\n\n        private class FakeAsyncResult : IAsyncResult\n        {\n            public bool IsCompleted { get; } = true;\n            // ReSharper disable once AssignNullToNotNullAttribute\n            public WaitHandle AsyncWaitHandle { get; } = null;\n            public object AsyncState { get; set; }\n            public bool CompletedSynchronously { get; } = true;\n            public Exception InternalException { get; set; }\n        }\n\n        private class TcpUserToken\n        {\n            public AsyncCallback Callback { get; }\n            public object AsyncState { get; }\n\n            public TcpUserToken(AsyncCallback callback, object state)\n            {\n                Callback = callback;\n                AsyncState = state;\n            }\n        }\n\n        private void OnTcpConnectCompleted(object sender, SocketAsyncEventArgs args)\n        {\n            using (args)\n            {\n                args.Completed -= OnTcpConnectCompleted;\n                var token = (TcpUserToken)args.UserToken;\n\n                if (args.SocketError != SocketError.Success)\n                {\n                    var ex = args.ConnectByNameError ?? new SocketException((int)args.SocketError);\n\n                    var r = new FakeAsyncResult\n                    {\n                        AsyncState = token.AsyncState,\n                        InternalException = ex\n                    };\n\n                    token.Callback(r);\n                }\n                else\n                {\n                    var lockTaken = false;\n                    if (!_socketSyncLock.IsHeldByCurrentThread)\n                    {\n                        _socketSyncLock.TryEnter(ref lockTaken);\n                    }\n                    try\n                    {\n                        if (Connected)\n                        {\n                            args.ConnectSocket.FullClose();\n                        }\n                        else\n                        {\n                            _activeSocket = args.ConnectSocket;\n                            if (_disposed)\n                            {\n                                _activeSocket.FullClose();\n                            }\n\n                            var r = new FakeAsyncResult\n                            {\n                                AsyncState = token.AsyncState\n                            };\n                            token.Callback(r);\n                        }\n                    }\n                    finally\n                    {\n                        if (lockTaken)\n                        {\n                            _socketSyncLock.Exit();\n                        }\n                    }\n                }\n            }\n        }\n\n        public void EndConnect(IAsyncResult asyncResult)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n\n            var r = asyncResult as FakeAsyncResult;\n            if (r == null)\n            {\n                throw new ArgumentException(@\"Invalid asyncResult.\", nameof(asyncResult));\n            }\n\n            if (r.InternalException != null)\n            {\n                throw r.InternalException;\n            }\n        }\n\n        public void Dispose()\n        {\n            if (_disposed)\n            {\n                return;\n            }\n            var lockTaken = false;\n            if (!_socketSyncLock.IsHeldByCurrentThread)\n            {\n                _socketSyncLock.TryEnter(ref lockTaken);\n            }\n            try\n            {\n                _disposed = true;\n                _activeSocket?.FullClose();\n            }\n            finally\n            {\n                if (lockTaken)\n                {\n                    _socketSyncLock.Exit();\n                }\n            }\n\n        }\n\n        public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n            if (!Connected)\n            {\n                throw new SocketException((int)SocketError.NotConnected);\n            }\n\n            return _activeSocket.BeginSend(buffer, offset, size, socketFlags, callback, state);\n        }\n\n        public int EndSend(IAsyncResult asyncResult)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n            if (!Connected)\n            {\n                throw new SocketException((int)SocketError.NotConnected);\n            }\n\n            return _activeSocket.EndSend(asyncResult);\n        }\n\n        public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n            if (!Connected)\n            {\n                throw new SocketException((int)SocketError.NotConnected);\n            }\n\n            return _activeSocket.BeginReceive(buffer, offset, size, socketFlags, callback, state);\n        }\n\n        public int EndReceive(IAsyncResult asyncResult)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n            if (!Connected)\n            {\n                throw new SocketException((int)SocketError.NotConnected);\n            }\n\n            return _activeSocket.EndReceive(asyncResult);\n        }\n\n        public void Shutdown(SocketShutdown how)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n            if (!Connected)\n            {\n                return;\n            }\n\n            _activeSocket.Shutdown(how);\n        }\n\n        public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)\n        {\n            SetSocketOption(optionLevel, optionName, optionValue ? 1 : 0);\n        }\n\n        public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n            if (!Connected)\n            {\n                throw new SocketException((int)SocketError.NotConnected);\n            }\n\n            _activeSocket.SetSocketOption(optionLevel, optionName, optionValue);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/QrCodeUtils.cs",
    "content": "using System;\nusing System.Drawing;\nusing System.IO;\nusing System.Windows.Media;\nusing System.Windows.Media.Imaging;\nusing ZXing;\nusing ZXing.Common;\nusing ZXing.QrCode;\nusing ZXing.QrCode.Internal;\nusing ZXing.Windows.Compatibility;\nusing Brush = System.Drawing.Brush;\nusing Color = System.Drawing.Color;\n\nnamespace Shadowsocks.Util;\n\npublic static class QrCodeUtils\n{\n    private static BitmapImage ToBitmapImage(Image src)\n    {\n        var ms = new MemoryStream();\n        src.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);\n        var image = new BitmapImage();\n        image.BeginInit();\n        ms.Seek(0, SeekOrigin.Begin);\n        image.StreamSource = ms;\n        image.EndInit();\n        return image;\n    }\n\n    public static ImageSource GenQrCode(string content, int width, int height)\n    {\n        var options = new QrCodeEncodingOptions\n        {\n            DisableECI = true,\n            CharacterSet = @\"UTF-8\",\n            Width = width,\n            Height = height,\n            Margin = 0,\n            ErrorCorrection = ErrorCorrectionLevel.H\n        };\n        var write = new BarcodeWriter\n        {\n            Format = BarcodeFormat.QR_CODE,\n            Options = options\n        };\n        var bitmap = write.Write(content);\n        return ToBitmapImage(bitmap);\n    }\n\n    public static ImageSource GenQrCode2(string str, int height)\n    {\n        var options = new QrCodeEncodingOptions\n        {\n            DisableECI = true,\n            CharacterSet = @\"UTF-8\",\n            Margin = 0\n        };\n        var code = Encoder.encode(str, ErrorCorrectionLevel.H, options.Hints);\n        var m = code.Matrix;\n        var blockSize = Math.Max(height / (m.Height + 1), 1);\n\n        var drawArea = new Bitmap(m.Width * blockSize, m.Height * blockSize);\n        using (var g = Graphics.FromImage(drawArea))\n        {\n            g.Clear(Color.White);\n            using Brush b = new SolidBrush(Color.Black);\n            for (var row = 0; row < m.Width; ++row)\n            {\n                for (var col = 0; col < m.Height; ++col)\n                {\n                    if (m[row, col] != 0)\n                    {\n                        g.FillRectangle(b, blockSize * row, blockSize * col, blockSize, blockSize);\n                    }\n                }\n            }\n        }\n\n        return ToBitmapImage(drawArea);\n    }\n\n    public static Result ScanBitmap(Bitmap target)\n    {\n        var source = new BitmapLuminanceSource(target);\n        var bitmap = new BinaryBitmap(new HybridBinarizer(source));\n        var reader = new QRCodeReader();\n        return reader.decode(bitmap);\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/RNG.cs",
    "content": "using System;\nusing System.Security.Cryptography;\n\nnamespace Shadowsocks.Util;\n\npublic static class Rng\n{\n    public static void RandBytes(byte[] buf, int length = -1)\n    {\n        RandomNumberGenerator.Fill(length < 0 ? buf : buf.AsSpan(0, length));\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/Reg.cs",
    "content": "using System.Diagnostics;\nusing URIScheme;\n\nnamespace Shadowsocks.Util\n{\n    public static class Reg\n    {\n        [Conditional(\"RELEASE\")]\n        public static void SetUrlProtocol(string link)\n        {\n            try\n            {\n                var service = new URISchemeService(link, @\"URL:ShadowsocksR Link\", Utils.GetExecutablePath());\n                service.Set();\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        [Conditional(\"RELEASE\")]\n        public static void RemoveUrlProtocol(string link)\n        {\n            try\n            {\n                var service = new URISchemeService(link, string.Empty, string.Empty);\n                service.Delete();\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/Utils.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Encryption;\nusing Shadowsocks.Model;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Reflection;\nusing System.Text;\n\n#nullable enable\n\nnamespace Shadowsocks.Util\n{\n    public static class Utils\n    {\n        public static void SetArrayMinSize<T>(ref T[] array, int size)\n        {\n            if (size > array.Length)\n            {\n                Array.Resize(ref array, size);\n            }\n        }\n\n        public static void SetArrayMinSize2<T>(ref T[] array, int size)\n        {\n            if (size > array.Length)\n            {\n                Array.Resize(ref array, size * 2);\n            }\n        }\n\n        public static string GetExecutablePath()\n        {\n            var p = Process.GetCurrentProcess();\n            var res = p.MainModule?.FileName;\n            if (res is not null)\n            {\n                return res;\n            }\n\n            var dllPath = GetDllPath();\n            return Path.ChangeExtension(dllPath, @\"exe\");\n        }\n\n        public static string GetDllPath()\n        {\n            return Assembly.GetExecutingAssembly().Location;\n        }\n\n        /// <summary>\n        /// return path to store temporary files\n        /// </summary>\n        public static string TempPath => TempPathLazy.Value;\n        private static readonly Lazy<string> TempPathLazy = new(() =>\n        {\n            try\n            {\n                return Directory.CreateDirectory(Path.Combine(Directory.GetCurrentDirectory(), @\"temp\")).FullName;\n            }\n            catch (Exception e)\n            {\n                Logging.Error(e);\n                throw;\n            }\n        });\n\n        public static string GetTempPath(string filename)\n        {\n            return Path.Combine(TempPath, filename);\n        }\n\n        public static bool IsGFWListPAC(string filename)\n        {\n            if (File.Exists(filename))\n            {\n                var original = FileManager.NonExclusiveReadAllText(filename, Encoding.UTF8);\n                if (original.Contains(@\"adblockplus\") && !original.Contains(@\"cnIpRange\"))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static void OpenURL(string path)\n        {\n            new Process\n            {\n                StartInfo = new ProcessStartInfo(path)\n                {\n                    UseShellExecute = true\n                }\n            }.Start();\n        }\n\n        public static string EncryptLargeBytesToBase64String(IEncryptor encryptor, byte[] cfgData)\n        {\n            var cfgEncrypt = new byte[cfgData.Length + 128];\n            var dataLen = 0;\n            const int bufferSize = 32768;\n            var input = new byte[bufferSize];\n            var output = new byte[bufferSize + 128];\n            for (var startPos = 0; startPos < cfgData.Length; startPos += bufferSize)\n            {\n                var len = Math.Min(cfgData.Length - startPos, bufferSize);\n                Buffer.BlockCopy(cfgData, startPos, input, 0, len);\n                encryptor.Encrypt(input, len, output, out var outLen);\n                Buffer.BlockCopy(output, 0, cfgEncrypt, dataLen, outLen);\n                dataLen += outLen;\n            }\n\n            return Convert.ToBase64String(cfgEncrypt, 0, dataLen);\n        }\n\n        public static byte[] DecryptLargeBase64StringToBytes(IEncryptor encryptor, string encodeStr)\n        {\n            var cfgEncrypt = Convert.FromBase64String(encodeStr);\n            var cfgData = new byte[cfgEncrypt.Length];\n            var dataLen = 0;\n            const int bufferSize = 32768;\n            var input = new byte[bufferSize];\n            var output = new byte[bufferSize + 128];\n            for (var startPos = 0; startPos < cfgEncrypt.Length; startPos += bufferSize)\n            {\n                var len = Math.Min(cfgEncrypt.Length - startPos, bufferSize);\n                Buffer.BlockCopy(cfgEncrypt, startPos, input, 0, len);\n                encryptor.Decrypt(input, len, output, out var outLen);\n                Buffer.BlockCopy(output, 0, cfgData, dataLen, outLen);\n                dataLen += outLen;\n            }\n\n            Array.Resize(ref cfgData, dataLen);\n            return cfgData;\n        }\n\n        public static string FormatBytes(long bytes)\n        {\n            const long K = 1024L;\n            const long M = K * 1024L;\n            const long G = M * 1024L;\n            const long T = G * 1024L;\n            const long P = T * 1024L;\n            const long E = P * 1024L;\n\n            return bytes switch\n            {\n                >= M * 990 and >= G * 990 => bytes switch\n                {\n                    >= P * 990 => $@\"{bytes / (double)E:F3}EB\",\n                    >= T * 990 => $@\"{bytes / (double)P:F3}PB\",\n                    _ => $@\"{bytes / (double)T:F3}TB\"\n                },\n                >= M * 990 and >= G * 99 => $@\"{bytes / (double)G:F2}GB\",\n                >= M * 990 and >= G * 9 => $@\"{bytes / (double)G:F3}GB\",\n                >= M * 990 => $@\"{bytes / (double)G:F4}GB\",\n                >= K * 990 and >= M * 100 => $@\"{bytes / (double)M:F1}MB\",\n                >= K * 990 when bytes > M * 9.9 => $@\"{bytes / (double)M:F2}MB\",\n                >= K * 990 => $@\"{bytes / (double)M:F3}MB\",\n                > K * 99 => $@\"{bytes / (double)K:F0}KB\",\n                > 900 => $@\"{bytes / (double)K:F1}KB\",\n                _ => bytes == 0 ? $@\"{bytes}Byte\" : $@\"{bytes}Bytes\"\n            };\n        }\n\n        public static IEnumerable<Server> Except(this IEnumerable<Server> x, IList<Server> y)\n        {\n            return from xi in x let found = y.Any(xi.IsMatchServer) where !found select xi;\n        }\n\n        public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = true)\n        {\n            using var sr = new StringReader(str);\n            string? line;\n            while ((line = sr.ReadLine()) is not null)\n            {\n                if (removeEmptyLines && string.IsNullOrEmpty(line))\n                {\n                    continue;\n                }\n                yield return line;\n            }\n        }\n\n        public static void SetTls()\n        {\n            if (!OperatingSystem.IsWindows())\n            {\n                return;\n            }\n            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;\n            if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 20170))\n            {\n                ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls13;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/Util/ViewUtils.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Media;\nusing Color = System.Drawing.Color;\nusing Size = System.Drawing.Size;\n\nnamespace Shadowsocks.Util\n{\n    public static class ViewUtils\n    {\n        private static readonly Color ColorMaskDirect = Color.FromArgb(255, 102, 102, 255);\n        private static readonly Color ColorMaskPac = Color.FromArgb(102, 204, 102);\n        private static readonly Color ColorMaskGlobal = Color.FromArgb(255, 102, 255, 255);\n\n        [DllImport(@\"user32.dll\", CharSet = CharSet.Auto)]\n        public static extern bool DestroyIcon(IntPtr handle);\n\n        public static void BringToFront(this FrameworkElement element)\n        {\n            if (element?.Parent is Panel parent)\n            {\n                var maxZ = parent.Children.OfType<UIElement>()\n                        .Where(x => x != element)\n                        .Select(Panel.GetZIndex)\n                        .Max();\n                Panel.SetZIndex(element, maxZ + 1);\n            }\n        }\n\n        public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject\n        {\n            if (depObj != null)\n            {\n                for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)\n                {\n                    var child = VisualTreeHelper.GetChild(depObj, i);\n                    if (child is T dependencyObject)\n                    {\n                        yield return dependencyObject;\n                    }\n\n                    foreach (var childOfChild in FindVisualChildren<T>(child))\n                    {\n                        yield return childOfChild;\n                    }\n                }\n            }\n        }\n\n        public static Color SelectColorMask(bool isProxyEnabled, bool isGlobalProxy)\n        {\n            if (isProxyEnabled)\n            {\n                return isGlobalProxy ? ColorMaskGlobal : ColorMaskPac;\n            }\n\n            return ColorMaskDirect;\n        }\n\n        public static Bitmap ChangeBitmapColor(Bitmap original, Color colorMask, bool isRandom = false)\n        {\n            var newBitmap = new Bitmap(original);\n\n            for (var x = 0; x < newBitmap.Width; ++x)\n            {\n                for (var y = 0; y < newBitmap.Height; ++y)\n                {\n                    var color = original.GetPixel(x, y);\n                    if (color.A != 0)\n                    {\n                        var red = Convert.ToByte(color.R * colorMask.R * (isRandom ? 2.5 : 1) / 255);\n                        var green = Convert.ToByte(color.G * colorMask.G / 255);\n                        var blue = Convert.ToByte(color.B * colorMask.B / 255);\n                        var alpha = Convert.ToByte(color.A * colorMask.A / 255);\n                        newBitmap.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue));\n                    }\n                    else\n                    {\n                        newBitmap.SetPixel(x, y, color);\n                    }\n                }\n            }\n            return newBitmap;\n        }\n\n        public static Bitmap ResizeBitmap(Bitmap original, int width, int height)\n        {\n            var newBitmap = new Bitmap(width, height);\n            using (var g = Graphics.FromImage(newBitmap))\n            {\n                g.SmoothingMode = SmoothingMode.HighQuality;\n                g.InterpolationMode = InterpolationMode.HighQualityBicubic;\n                g.PixelOffsetMode = PixelOffsetMode.HighQuality;\n                g.CompositingQuality = CompositingQuality.HighQuality;\n                g.DrawImage(original, new Rectangle(0, 0, width, height));\n            }\n            return newBitmap;\n        }\n\n        public static int GetDpi()\n        {\n            var dpiXProperty = typeof(SystemParameters).GetProperty(@\"DpiX\", BindingFlags.NonPublic | BindingFlags.Static);\n            return dpiXProperty?.GetValue(null, null) is int dpiX ? dpiX : 96;\n        }\n\n        /// <summary>\n        /// Determine the icon size based on the screen DPI.\n        /// </summary>\n        /// <returns></returns>\n        /// https://stackoverflow.com/a/40851713/2075611\n        public static Size GetIconSize()\n        {\n            var dpi = GetDpi();\n            var size = dpi switch\n            {\n                < 97 => new Size(16, 16),\n                < 121 => new Size(20, 20),\n                < 145 => new Size(24, 24),\n                < 169 => new Size(28, 28),\n                _ => new Size(32, 32)\n            };\n            return size;\n        }\n\n        public static void SetResource(ResourceDictionary resources, string filename, int index)\n        {\n            var url = new Uri(filename, UriKind.Relative);\n            if (resources.MergedDictionaries.Count > index)\n            {\n                resources.MergedDictionaries[index].Source = url;\n            }\n            else if (Application.LoadComponent(url) is ResourceDictionary langRd)\n            {\n                resources.MergedDictionaries.Add(langRd);\n            }\n        }\n\n        public static bool IsOnScreen(Window window)\n        {\n            return IsOnScreen(window.Left, window.Top)\n                || IsOnScreen(window.Left + window.Width, window.Top + window.Height);\n        }\n\n        public static bool IsOnScreen(double x, double y)\n        {\n            return\n                    SystemParameters.VirtualScreenLeft <= x &&\n                    SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth >= x &&\n                    SystemParameters.VirtualScreenTop <= y &&\n                    SystemParameters.VirtualScreenTop + SystemParameters.VirtualScreenHeight >= y;\n        }\n\n        public static bool IsScrolledToEnd(this TextBox textBox)\n        {\n            return Math.Abs(textBox.VerticalOffset + textBox.ViewportHeight - textBox.ExtentHeight) < 0.001;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/Controls/BindablePasswordBox.cs",
    "content": "using System.Windows;\nusing System.Windows.Controls;\n\nnamespace Shadowsocks.View.Controls\n{\n    public sealed class BindablePasswordBox : Decorator\n    {\n        /// <summary>\n        /// The password dependency property.\n        /// </summary>\n        public static readonly DependencyProperty PasswordProperty;\n\n        private bool _isPreventCallback;\n        private readonly RoutedEventHandler _savedCallback;\n\n        /// <summary>\n        /// Static constructor to initialize the dependency properties.\n        /// </summary>\n        static BindablePasswordBox()\n        {\n            PasswordProperty = DependencyProperty.Register(\n                \"Password\",\n                typeof(string),\n                typeof(BindablePasswordBox),\n                new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnPasswordPropertyChanged)\n            );\n        }\n\n        /// <summary>\n        /// Saves the password changed callback and sets the child element to the password box.\n        /// </summary>\n        public BindablePasswordBox()\n        {\n            _savedCallback = HandlePasswordChanged;\n\n            var passwordBox = new PasswordBox();\n            passwordBox.PasswordChanged += _savedCallback;\n            Child = passwordBox;\n        }\n\n        /// <summary>\n        /// The password dependency property.\n        /// </summary>\n        public string Password\n        {\n            get => GetValue(PasswordProperty) as string;\n            set => SetValue(PasswordProperty, value);\n        }\n\n        /// <summary>\n        /// Handles changes to the password dependency property.\n        /// </summary>\n        /// <param name=\"d\">the dependency object</param>\n        /// <param name=\"eventArgs\">the event args</param>\n        private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs eventArgs)\n        {\n            var bindablePasswordBox = (BindablePasswordBox)d;\n            var passwordBox = (PasswordBox)bindablePasswordBox.Child;\n\n            if (bindablePasswordBox._isPreventCallback)\n            {\n                return;\n            }\n\n            passwordBox.PasswordChanged -= bindablePasswordBox._savedCallback;\n            passwordBox.Password = eventArgs.NewValue != null ? eventArgs.NewValue.ToString() : string.Empty;\n            passwordBox.PasswordChanged += bindablePasswordBox._savedCallback;\n        }\n\n        /// <summary>\n        /// Handles the password changed event.\n        /// </summary>\n        /// <param name=\"sender\">the sender</param>\n        /// <param name=\"eventArgs\">the event args</param>\n        private void HandlePasswordChanged(object sender, RoutedEventArgs eventArgs)\n        {\n            var passwordBox = (PasswordBox)sender;\n\n            _isPreventCallback = true;\n            Password = passwordBox.Password;\n            _isPreventCallback = false;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/Controls/GridColumnSizerExt.cs",
    "content": "using Syncfusion.UI.Xaml.Grid;\nusing System.Linq;\nusing System.Windows;\n\nnamespace Shadowsocks.View.Controls\n{\n    public class GridColumnSizerExt : GridColumnSizer\n    {\n        public GridColumnSizerExt(SfDataGrid dataGrid) : base(dataGrid) { }\n\n        protected override double CalculateCellWidth(GridColumn column, bool setWidth = true)\n        {\n            var length = base.CalculateCellWidth(column, setWidth);\n\n            if (column is GridTextColumn)\n            {\n                var clientSize = new Size(double.MaxValue, DataGrid.RowHeight);\n                length = DataGrid.View.Records.Where(recordEntry => recordEntry?.Data != null)\n                    .Select(recordEntry => GetDisplayText(column, recordEntry.Data)).Select(text =>\n                        MeasureText(clientSize, text, column, null, GridQueryBounds.Width).Width).Prepend(length).Max();\n            }\n\n            return length;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/Controls/MaskedTextBox.xaml",
    "content": "﻿<UserControl x:Class=\"Shadowsocks.View.Controls.MaskedTextBox\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" \n             mc:Ignorable=\"d\"\n             x:Name=\"Uc\">\n\n    <Grid >\n        <PasswordBox x:Name=\"MyPasswordBox\" />\n        <TextBox x:Name=\"MyTextBox\" Text=\"{Binding Text, Mode=TwoWay, ElementName=Uc,UpdateSourceTrigger=PropertyChanged}\" Visibility=\"Collapsed\" />\n    </Grid>\n</UserControl>\n"
  },
  {
    "path": "shadowsocks-csharp/View/Controls/MaskedTextBox.xaml.cs",
    "content": "using System;\nusing System.Windows;\n\nnamespace Shadowsocks.View.Controls\n{\n    public partial class MaskedTextBox\n    {\n        public MaskedTextBox()\n        {\n            InitializeComponent();\n            PlainModeChanged += MaskedTextBoxPlainModeChanged;\n            MyPasswordBox.PasswordChanged += (o, e) =>\n            {\n                if (MyPasswordBox.IsFocused)\n                {\n                    Text = MyPasswordBox.Password;\n                }\n            };\n            MyTextBox.TextChanged += (o, e) =>\n            {\n                if (!MyPasswordBox.IsFocused)\n                {\n                    MyPasswordBox.Password = MyTextBox.Text;\n                }\n            };\n        }\n\n        private bool _plainMode;\n        public bool PlainMode\n        {\n            get => _plainMode;\n            set\n            {\n                if (_plainMode != value)\n                {\n                    _plainMode = value;\n                    PlainModeChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public string Text\n        {\n            get => GetValue(TextProperty) as string;\n            set => SetValue(TextProperty, value);\n        }\n\n        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(@\"Text\", typeof(string), typeof(MaskedTextBox));\n\n        public event EventHandler PlainModeChanged;\n\n        private void MaskedTextBoxPlainModeChanged(object sender, EventArgs e)\n        {\n            if (_plainMode)\n            {\n                MyPasswordBox.Visibility = Visibility.Collapsed;\n                MyTextBox.Visibility = Visibility.Visible;\n            }\n            else\n            {\n                MyPasswordBox.Visibility = Visibility.Visible;\n                MyTextBox.Visibility = Visibility.Collapsed;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/Controls/NumberUpDown.xaml",
    "content": "﻿<UserControl x:Class=\"Shadowsocks.View.Controls.NumberUpDown\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \n             xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n             mc:Ignorable=\"d\"\n             x:Name=\"Uc\"\n             Loaded=\"UserControl_Loaded\">\n    <Grid LostFocus=\"Grid_LostFocus\">\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"1*\" />\n            <RowDefinition Height=\"1*\" />\n        </Grid.RowDefinitions>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition Width=\"*\" />\n            <ColumnDefinition Width=\"12\" />\n        </Grid.ColumnDefinitions>\n        <TextBox x:FieldModifier=\"private\" Grid.Row=\"0\" Grid.Column=\"0\" Grid.RowSpan=\"2\" x:Name=\"TxtNum\"\n        Text=\"{Binding Value , Mode=TwoWay, ElementName=Uc,UpdateSourceTrigger=PropertyChanged}\" TextChanged=\"TxtNum_TextChanged\" VerticalContentAlignment=\"Center\"/>\n        <RepeatButton Grid.Row=\"0\" Grid.Column=\"1\" Content=\"▲\" Click=\"Up_Click\" FontSize=\"6\" />\n        <RepeatButton Grid.Row=\"1\" Grid.Column=\"1\" Content=\"▼\" Click=\"Down_Click\" FontSize=\"6\" />\n    </Grid>\n</UserControl>\n"
  },
  {
    "path": "shadowsocks-csharp/View/Controls/NumberUpDown.xaml.cs",
    "content": "using System;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Shadowsocks.View.Controls\n{\n    public partial class NumberUpDown\n    {\n        private int _numValue;\n\n        private int _maxNum = 65535;\n\n        private int _minNum;\n\n        public int NumValue\n        {\n            get\n            {\n                if (_numValue > _maxNum)\n                {\n                    return _maxNum;\n                }\n                if (_numValue < _minNum)\n                {\n                    return _minNum;\n                }\n                return _numValue;\n            }\n            set\n            {\n                if (_numValue != value)\n                {\n                    _numValue = value;\n                    TxtNum.Text = value.ToString();\n                    ValueChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public string Value\n        {\n            get => GetValue(ValueProperty) as string;\n            set => SetValue(ValueProperty, value);\n        }\n\n        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(@\"Value\", typeof(string), typeof(NumberUpDown));\n\n        public int MinNum\n        {\n            get => _minNum;\n            set => _minNum = value > _maxNum ? _maxNum : value;\n        }\n\n        public int MaxNum\n        {\n            get => _maxNum;\n            set => _maxNum = value < _minNum ? _minNum : value;\n        }\n\n        public event EventHandler ValueChanged;\n\n        public NumberUpDown()\n        {\n            InitializeComponent();\n        }\n\n        private void Up_Click(object sender, RoutedEventArgs e)\n        {\n            if (NumValue < _maxNum)\n            {\n                ++NumValue;\n            }\n            else\n            {\n                NumValue = _maxNum;\n            }\n        }\n\n        private void Down_Click(object sender, RoutedEventArgs e)\n        {\n            if (NumValue > _minNum)\n            {\n                --NumValue;\n            }\n            else\n            {\n                NumValue = _minNum;\n            }\n        }\n\n        private void TxtNum_TextChanged(object sender, TextChangedEventArgs e)\n        {\n            if (TxtNum == null)\n            {\n                return;\n            }\n\n            if (int.TryParse(TxtNum.Text, out var num))\n            {\n                NumValue = num;\n            }\n        }\n\n        private void UserControl_Loaded(object sender, RoutedEventArgs e)\n        {\n            TxtNum.Text = NumValue.ToString();\n        }\n\n        private void Grid_LostFocus(object sender, RoutedEventArgs e)\n        {\n            TxtNum.Text = NumValue.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/DnsSettingWindow.xaml",
    "content": "﻿<Window x:Class=\"Shadowsocks.View.DnsSettingWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:model=\"clr-namespace:Shadowsocks.Model\"\n        xmlns:valueConverter=\"clr-namespace:Shadowsocks.View.ValueConverter\"\n        xmlns:enums=\"clr-namespace:Shadowsocks.Enums\"\n        xmlns:controls=\"clr-namespace:Shadowsocks.View.Controls\"\n        Title=\"{DynamicResource Title}\"\n        Height=\"420\" Width=\"524\"\n        WindowStartupLocation=\"CenterScreen\"\n        DataContext=\"{Binding DnsSettingViewModel,RelativeSource={RelativeSource Self}}\"\n        >\n    <Window.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"../I18N/DnsSettingWindow.en-US.xaml\" />\n            </ResourceDictionary.MergedDictionaries>\n            <SolidColorBrush x:Key=\"DisabledBackgroundBrush\" Color=\"LightGray\" />\n            <Style TargetType=\"{x:Type TextBox}\">\n                <Style.Triggers>\n                    <Trigger Property=\"IsEnabled\" Value=\"False\">\n                        <Setter Property=\"Background\" Value=\"{StaticResource DisabledBackgroundBrush}\" />\n                    </Trigger>\n                </Style.Triggers>\n            </Style>\n            <DataTemplate x:Key=\"ListBoxTemplate\" DataType=\"model:DnsClient\">\n                <StackPanel Margin=\"3\">\n                    <WrapPanel>\n                        <TextBlock Text=\"{Binding DnsServer}\" Foreground=\"Green\" FontWeight=\"Bold\" FontSize=\"16\"/>\n                        <TextBlock Text=\":\" FontWeight=\"Bold\" FontSize=\"16\" />\n                        <TextBlock Text=\"{Binding Port}\" Foreground=\"DarkOrange\" FontWeight=\"Bold\" FontSize=\"16\" />\n                    </WrapPanel>\n                </StackPanel>\n            </DataTemplate>\n            <valueConverter:ProxyTypeConverter x:Key=\"DnsTypeConverter\" />\n        </ResourceDictionary>\n    </Window.Resources>\n    <Grid>\n        <Grid.RowDefinitions>\n            <RowDefinition />\n            <RowDefinition Height=\"Auto\" />\n        </Grid.RowDefinitions>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition MinWidth=\"150\" />\n            <ColumnDefinition MinWidth=\"270\" />\n        </Grid.ColumnDefinitions>\n        <GridSplitter Grid.Column=\"0\" Grid.RowSpan=\"2\"\n                      HorizontalAlignment=\"Right\"\n                      VerticalAlignment=\"Stretch\"\n                      Width=\"3\" />\n        <ListBox Grid.Row=\"0\" Grid.Column=\"0\" Grid.RowSpan=\"2\" Margin=\"10,5,10,10\"\n                 ScrollViewer.HorizontalScrollBarVisibility=\"Auto\"\n                 ScrollViewer.VerticalScrollBarVisibility=\"Auto\"\n                 ScrollViewer.CanContentScroll=\"True\"\n                 ItemsSource=\"{Binding Clients}\"\n                 SelectedItem=\"{Binding CurrentClient,Mode=TwoWay}\"\n                 ItemTemplate=\"{StaticResource ListBoxTemplate}\">\n            <ListBox.ContextMenu>\n                <ContextMenu>\n                    <MenuItem Header=\"{DynamicResource Add}\" Click=\"AddButton_OnClick\" />\n                    <MenuItem Header=\"{DynamicResource Delete}\" Click=\"DeleteButton_OnClick\" />\n                </ContextMenu>\n            </ListBox.ContextMenu>\n        </ListBox>\n        <StackPanel Grid.Row=\"0\" Grid.Column=\"1\" Margin=\"10,5,10,0\" Visibility=\"{Binding IsCurrentClientNull,Mode=OneWay}\">\n            <CheckBox x:Name=\"EnableCheckBox\" Margin=\"0,3\" Content=\"{DynamicResource Enable}\" IsChecked=\"{Binding CurrentClient.Enable}\"/>\n            <StackPanel IsEnabled=\"{Binding IsChecked,ElementName=EnableCheckBox}\">\n                <WrapPanel Margin=\"0,3\">\n                    <RadioButton Content=\"{DynamicResource DnsDefault}\" x:Name=\"DnsDefaultRadioButton\"\n                    IsChecked=\"{Binding CurrentClient.DnsType,Converter={StaticResource DnsTypeConverter}, ConverterParameter={x:Static enums:DnsType.Default}}\" />\n                    <RadioButton Content=\"{DynamicResource DnsOverTls}\" Margin=\"10,0,0,0\"\n                    IsChecked=\"{Binding CurrentClient.DnsType,Converter={StaticResource DnsTypeConverter}, ConverterParameter={x:Static enums:DnsType.DnsOverTls}}\" />\n                    <CheckBox Margin=\"10,0,0,0\" Content=\"{DynamicResource Ipv6}\" IsChecked=\"{Binding CurrentClient.Ipv6First}\"/>\n                </WrapPanel>\n                <WrapPanel Margin=\"0,3\" IsEnabled=\"{Binding IsChecked,ElementName=DnsDefaultRadioButton}\">\n                    <CheckBox Content=\"{DynamicResource Tcp}\" IsChecked=\"{Binding CurrentClient.IsTcpEnabled}\"/>\n                    <CheckBox Margin=\"10,0,0,0\" Content=\"{DynamicResource Udp}\" IsChecked=\"{Binding CurrentClient.IsUdpEnabled}\"/>\n                </WrapPanel>\n                <Grid Margin=\"0,3\">\n                    <Grid.RowDefinitions>\n                        <RowDefinition Height=\"24\" />\n                        <RowDefinition Height=\"24\" />\n                        <RowDefinition Height=\"24\" />\n                    </Grid.RowDefinitions>\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\" />\n                        <ColumnDefinition Width=\"*\" />\n                    </Grid.ColumnDefinitions>\n                    <TextBlock Grid.Row=\"0\" Grid.Column=\"0\" Text=\"{DynamicResource Address}\" VerticalAlignment=\"Center\"/>\n                    <TextBox Grid.Row=\"0\" Grid.Column=\"1\" Margin=\"10,2,0,2\" Text=\"{Binding CurrentClient.DnsServer,Mode=TwoWay}\" VerticalContentAlignment=\"Center\"/>\n                    <TextBlock Grid.Row=\"1\" Grid.Column=\"0\" Text=\"{DynamicResource Port}\" VerticalAlignment=\"Center\" />\n                    <controls:NumberUpDown Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"10,2,0,2\" MinNum=\"1\" MaxNum=\"65535\" Value=\"{Binding CurrentClient.Port,Mode=TwoWay}\"/>\n                    <TextBlock Grid.Row=\"2\" Grid.Column=\"0\" Text=\"{DynamicResource Timeout}\" VerticalAlignment=\"Center\" />\n                    <controls:NumberUpDown Grid.Row=\"2\" Grid.Column=\"1\" Margin=\"10,2,0,2\" MinNum=\"1\" MaxNum=\"10000\" Value=\"{Binding CurrentClient.Timeout,Mode=TwoWay}\"/>\n                </Grid>\n                <GroupBox Margin=\"0,3\" Header=\"{DynamicResource EDns}\">\n                    <StackPanel>\n                        <CheckBox x:Name=\"EnableEDns\" Content=\"{DynamicResource Enable}\" IsChecked=\"{Binding CurrentClient.IsEDnsEnabled}\"/>\n                        <Grid IsEnabled=\"{Binding IsChecked,ElementName=EnableEDns}\">\n                            <Grid.RowDefinitions>\n                                <RowDefinition Height=\"24\" />\n                                <RowDefinition Height=\"24\" />\n                                <RowDefinition Height=\"24\" />\n                            </Grid.RowDefinitions>\n                            <Grid.ColumnDefinitions>\n                                <ColumnDefinition Width=\"Auto\" />\n                                <ColumnDefinition Width=\"*\" />\n                            </Grid.ColumnDefinitions>\n                            <TextBlock Grid.Row=\"0\" Grid.Column=\"0\" Text=\"{DynamicResource Ip}\" VerticalAlignment=\"Center\" />\n                            <TextBox Grid.Row=\"0\" Grid.Column=\"1\" Margin=\"10,2,0,2\" Text=\"{Binding CurrentClient.EcsIp,Mode=TwoWay}\" VerticalContentAlignment=\"Center\" />\n                            <TextBlock Grid.Row=\"1\" Grid.Column=\"0\" Text=\"{DynamicResource SourceNetmask}\" VerticalAlignment=\"Center\" />\n                            <controls:NumberUpDown Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"10,2,0,2\" MinNum=\"0\" MaxNum=\"255\" Value=\"{Binding CurrentClient.EcsSourceNetmask,Mode=TwoWay}\" />\n                            <TextBlock Grid.Row=\"2\" Grid.Column=\"0\" Text=\"{DynamicResource ScopeNetmask}\" VerticalAlignment=\"Center\" />\n                            <controls:NumberUpDown Grid.Row=\"2\" Grid.Column=\"1\" Margin=\"10,2,0,2\" MinNum=\"0\" MaxNum=\"255\" Value=\"{Binding CurrentClient.EcsScopeNetmask,Mode=TwoWay}\" />\n                        </Grid>\n                    </StackPanel>\n                </GroupBox>\n            </StackPanel>\n            <GroupBox Header=\"{DynamicResource Test}\">\n                <Grid>\n                    <Grid.RowDefinitions>\n                        <RowDefinition Height=\"24\" />\n                        <RowDefinition Height=\"24\" />\n                    </Grid.RowDefinitions>\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\" />\n                        <ColumnDefinition Width=\"*\" />\n                    </Grid.ColumnDefinitions>\n                    <TextBlock Grid.Row=\"0\" Grid.Column=\"0\" Text=\"{DynamicResource Domain}\" Margin=\"2,0,0,0\" VerticalAlignment=\"Center\" FontSize=\"14\"/>\n                    <TextBox x:Name=\"DomainTextBox\" Grid.Row=\"0\" Grid.Column=\"1\" Margin=\"10,2,0,2\" Text=\"www.google.com\" VerticalContentAlignment=\"Center\" />\n                    <Button Grid.Row=\"1\" Grid.Column=\"0\" Content=\"{DynamicResource Test}\" Padding=\"3,0\" Click=\"TestButton_OnClick\"/>\n                    <TextBox x:Name=\"AnswerTextBox\" Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"10,2,0,2\" IsReadOnly=\"True\" Background=\"{StaticResource DisabledBackgroundBrush}\" VerticalContentAlignment=\"Center\" />\n                </Grid>\n            </GroupBox>\n        </StackPanel>\n        <Grid Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"0,10,10,10\" HorizontalAlignment=\"Right\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"Auto\" />\n                <ColumnDefinition Width=\"Auto\" />\n                <ColumnDefinition Width=\"Auto\" />\n            </Grid.ColumnDefinitions>\n            <Button Grid.Column=\"0\" Content=\"{DynamicResource Ok}\" Padding=\"10,0\" Margin=\"10,0\" FontSize=\"14\" Click=\"OkButton_OnClick\"/>\n            <Button Grid.Column=\"1\" Content=\"{DynamicResource Cancel}\" Padding=\"10,0\" Margin=\"10,0\" FontSize=\"14\" Click=\"CancelButton_OnClick\"/>\n            <Button x:Name=\"ApplyButton\" Grid.Column=\"2\" Content=\"{DynamicResource Apply}\" Padding=\"10,0\" Margin=\"10,0,0,0\" FontSize=\"14\" Click=\"ApplyButton_OnClick\"/>\n        </Grid>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "shadowsocks-csharp/View/DnsSettingWindow.xaml.cs",
    "content": "using Shadowsocks.Util;\nusing Shadowsocks.ViewModel;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Shadowsocks.View\n{\n    public partial class DnsSettingWindow\n    {\n        public DnsSettingWindow()\n        {\n            InitializeComponent();\n            I18NUtil.SetLanguage(Resources, @\"DnsSettingWindow\");\n            Closed += (o, e) =>\n            {\n                DnsSettingViewModel.DnsClientsChanged -= DnsSettingViewModel_DnsClientsChanged;\n            };\n            DnsSettingViewModel.DnsClientsChanged += DnsSettingViewModel_DnsClientsChanged;\n            LoadConfig();\n        }\n\n        private void DnsSettingViewModel_DnsClientsChanged(object sender, System.EventArgs e)\n        {\n            ApplyButton.IsEnabled = true;\n        }\n\n        public DnsSettingViewModel DnsSettingViewModel { get; set; } = new();\n\n        private void LoadConfig()\n        {\n            DnsSettingViewModel.ReadConfig();\n            ApplyButton.IsEnabled = false;\n        }\n\n        private void SaveConfig()\n        {\n            if (ApplyButton.IsEnabled)\n            {\n                DnsSettingViewModel.SaveConfig();\n            }\n        }\n\n        private void AddButton_OnClick(object sender, RoutedEventArgs e)\n        {\n            DnsSettingViewModel.AddNewDns();\n        }\n\n        private void DeleteButton_OnClick(object sender, RoutedEventArgs e)\n        {\n            DnsSettingViewModel.Delete();\n        }\n\n        private void OkButton_OnClick(object sender, RoutedEventArgs e)\n        {\n            SaveConfig();\n            Close();\n        }\n\n        private void CancelButton_OnClick(object sender, RoutedEventArgs e)\n        {\n            Close();\n        }\n\n        private void ApplyButton_OnClick(object sender, RoutedEventArgs e)\n        {\n            SaveConfig();\n            LoadConfig();\n        }\n\n        private void TestButton_OnClick(object sender, RoutedEventArgs e)\n        {\n            if (sender is Button button && DnsSettingViewModel.CurrentClient != null)\n            {\n                var client = DnsSettingViewModel.CurrentClient;\n                var domain = DomainTextBox.Text;\n                button.IsEnabled = false;\n                AnswerTextBox.Text = string.Empty;\n                Task.Run(async () =>\n                {\n                    var res = await client.QueryIpAddressAsync(domain, default);\n                    Dispatcher?.InvokeAsync(() => { AnswerTextBox.Text = $@\"{res}\"; });\n                }).ContinueWith(task =>\n                {\n                    Dispatcher?.InvokeAsync(() => { button.IsEnabled = true; });\n                });\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/LogWindow.xaml",
    "content": "﻿<Window x:Class=\"Shadowsocks.View.LogWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\"\n        Height=\"475\" Width=\"1000\"\n        ResizeMode=\"CanResizeWithGrip\"\n        WindowStartupLocation=\"CenterScreen\" Loaded=\"Window_Loaded\" Closed=\"Window_Closed\">\n\n    <Window.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"../I18N/LogWindow.en-US.xaml\" />\n            </ResourceDictionary.MergedDictionaries>\n        </ResourceDictionary>\n    </Window.Resources>\n    <Grid>\n        <DockPanel>\n            <Menu DockPanel.Dock=\"Top\" Background=\"White\">\n                <MenuItem Header=\"{DynamicResource File}\">\n                    <MenuItem Header=\"{DynamicResource ClearLog}\" Click=\"ClearLogMenuItem_Click\" />\n                    <MenuItem Header=\"{DynamicResource ShowInExplorer}\" Click=\"ShowInExplorerMenuItem_Click\" />\n                    <Separator />\n                    <MenuItem Header=\"{DynamicResource Close}\" Click=\"CloseMenuItem_Click\" />\n                </MenuItem>\n                <MenuItem Header=\"{DynamicResource View}\">\n                    <MenuItem Header=\"{DynamicResource Font}\" Click=\"FontMenuItem_Click\" />\n                    <MenuItem x:Name=\"WrapTextMenuItem\" Header=\"{DynamicResource WrapText}\" Click=\"WrapTextMenuItem_Click\" Checked=\"WrapTextMenuItem_Checked\" Unchecked=\"WrapTextMenuItem_Checked\" />\n                    <MenuItem x:Name=\"AlwaysOnTopMenuItem\" Header=\"{DynamicResource AlwaysOnTop}\" Click=\"AlwaysOnTopMenuItem_Click\" Checked=\"AlwaysOnTopMenuItem_Checked\" Unchecked=\"AlwaysOnTopMenuItem_Checked\" />\n                </MenuItem>\n            </Menu>\n            <TextBox x:Name=\"LogTextBox\"\n            HorizontalScrollBarVisibility=\"Auto\" VerticalScrollBarVisibility=\"Auto\"\n            TextWrapping=\"NoWrap\" IsReadOnly=\"True\"\n            Background=\"Black\" Foreground=\"White\"\n            FontFamily=\"Courier New\" FontSize=\"14\" FontWeight=\"Bold\"\n            \n            />\n        </DockPanel>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "shadowsocks-csharp/View/LogWindow.xaml.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Util;\nusing System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing WpfColorFontDialog;\n\nnamespace Shadowsocks.View\n{\n    public partial class LogWindow\n    {\n        public LogWindow()\n        {\n            InitializeComponent();\n            I18NUtil.SetLanguage(Resources, @\"LogWindow\");\n        }\n\n        private const int MaxReadSize = 65536;\n\n        private string _currentLogFile;\n        private string _currentLogFileName;\n        private long _currentOffset;\n\n        private readonly CancellationTokenSource _cts = new();\n\n        private void ReadLog()\n        {\n            var newLogFile = Logging.LogFile;\n            if (newLogFile != _currentLogFile)\n            {\n                _currentOffset = 0;\n                _currentLogFile = newLogFile;\n                _currentLogFileName = Logging.LogFileName;\n            }\n\n            try\n            {\n                if (!File.Exists(newLogFile))\n                {\n                    Title = $@\"{this.GetWindowStringValue(@\"Title\")}\";\n                    return;\n                }\n                using var reader = new StreamReader(new FileStream(newLogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));\n                if (_currentOffset == 0)\n                {\n                    var maxSize = reader.BaseStream.Length;\n                    if (maxSize > MaxReadSize)\n                    {\n                        reader.BaseStream.Seek(-MaxReadSize, SeekOrigin.End);\n                        reader.ReadLine();\n                    }\n                }\n                else\n                {\n                    reader.BaseStream.Seek(_currentOffset, SeekOrigin.Begin);\n                }\n\n                var txt = reader.ReadToEnd();\n                if (!string.IsNullOrEmpty(txt))\n                {\n                    LogTextBox.AppendText(txt);\n\n                    if (LogTextBox.SelectionStart == 0 || LogTextBox.IsScrolledToEnd())\n                    {\n                        LogTextBox.ScrollToEnd();\n                    }\n                    else\n                    {\n                        LogTextBox.ScrollToLine(LogTextBox.GetLineIndexFromCharacterIndex(LogTextBox.SelectionStart));\n                    }\n                }\n\n                _currentOffset = reader.BaseStream.Position;\n            }\n            catch (FileNotFoundException)\n            {\n\n            }\n            catch (ArgumentNullException)\n            {\n\n            }\n\n            Title = $@\"{this.GetWindowStringValue(@\"Title\")} {_currentLogFileName}\";\n        }\n\n        private void ClearLogMenuItem_Click(object sender, RoutedEventArgs e)\n        {\n            Logging.Clear();\n            _currentOffset = 0;\n            LogTextBox.Clear();\n        }\n\n        private void ShowInExplorerMenuItem_Click(object sender, RoutedEventArgs _)\n        {\n            try\n            {\n                var argument = $@\"/n,/select,{Logging.LogFile}\";\n                Process.Start(@\"explorer.exe\", argument);\n            }\n            catch (Exception e)\n            {\n                Logging.LogUsefulException(e);\n            }\n        }\n\n        private void Window_Loaded(object sender, RoutedEventArgs e)\n        {\n            SyncLog(_cts);\n        }\n\n        private async void SyncLog(CancellationTokenSource cts)\n        {\n            while (true)\n            {\n                ReadLog();\n                try\n                {\n                    await Task.Delay(100, cts.Token);\n                }\n                catch (TaskCanceledException)\n                {\n                    break;\n                }\n                if (cts.IsCancellationRequested)\n                {\n                    break;\n                }\n            }\n        }\n\n        private void CloseMenuItem_Click(object sender, RoutedEventArgs e)\n        {\n            Close();\n        }\n\n        private void FontMenuItem_Click(object sender, RoutedEventArgs e)\n        {\n            var dialog = new ColorFontDialog\n            {\n                Font = FontInfo.GetControlFont(LogTextBox)\n            };\n\n            if (dialog.ShowDialog() == true)\n            {\n                var font = dialog.Font;\n                if (font != null)\n                {\n                    FontInfo.ApplyFont(LogTextBox, font);\n                }\n            }\n        }\n\n        private void WrapTextMenuItem_Click(object sender, RoutedEventArgs e)\n        {\n            WrapTextMenuItem.IsChecked = !WrapTextMenuItem.IsChecked;\n        }\n\n        private void AlwaysOnTopMenuItem_Click(object sender, RoutedEventArgs e)\n        {\n            AlwaysOnTopMenuItem.IsChecked = !AlwaysOnTopMenuItem.IsChecked;\n        }\n\n        private void WrapTextMenuItem_Checked(object sender, RoutedEventArgs e)\n        {\n            LogTextBox.TextWrapping = WrapTextMenuItem.IsChecked ? TextWrapping.Wrap : TextWrapping.NoWrap;\n            LogTextBox.ScrollToEnd();\n        }\n\n        private void AlwaysOnTopMenuItem_Checked(object sender, RoutedEventArgs e)\n        {\n            Topmost = AlwaysOnTopMenuItem.IsChecked;\n        }\n\n        private void Window_Closed(object sender, EventArgs e)\n        {\n            _cts.Cancel();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/NotifyIconResources.xaml",
    "content": "<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n                    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\n    <Style TargetType=\"MenuItem\">\n        <Setter Property=\"BorderThickness\" Value=\"3\"></Setter>\n    </Style>\n    <ContextMenu x:Shared=\"False\" x:Key=\"SysTrayMenu\">\n        <MenuItem x:Name=\"Mode\">\n            <MenuItem x:Name=\"DisableProxy\" />\n            <MenuItem x:Name=\"PacProxy\" />\n            <MenuItem x:Name=\"GlobalProxy\" />\n            <Separator />\n            <MenuItem x:Name=\"NoProxy\" />\n        </MenuItem>\n        <MenuItem x:Name=\"ProxySetting\">\n            <MenuItem x:Name=\"UpdatePac\">\n                <MenuItem x:Name=\"UpdateLanPac\" />\n                <Separator />\n                <MenuItem x:Name=\"UpdateChnDomainPac\" />\n                <MenuItem x:Name=\"UpdateChnDomainIpPac\" />\n                <MenuItem x:Name=\"UpdateChnIpPac\" />\n                <MenuItem x:Name=\"UpdateGfwList\" />\n                <Separator />\n                <MenuItem x:Name=\"UpdateChnOnlyPac\" />\n            </MenuItem>\n            <MenuItem x:Name=\"ProxyRule\">\n                <MenuItem x:Name=\"BypassLan\" />\n                <MenuItem x:Name=\"BypassLanChina\" />\n                <MenuItem x:Name=\"BypassLanNotChina\" />\n                <MenuItem x:Name=\"UserCustom\" />\n                <Separator />\n                <MenuItem x:Name=\"DisableBypass\" />\n            </MenuItem>\n            <Separator />\n            <MenuItem x:Name=\"CopyPacUrl\" />\n            <MenuItem x:Name=\"EditPacFile\" />\n            <MenuItem x:Name=\"EditGfwListUserRule\" />\n        </MenuItem>\n        <Separator />\n        <MenuItem x:Name=\"Servers\">\n            <Separator />\n            <MenuItem x:Name=\"EditServers\" />\n            <Separator />\n            <MenuItem x:Name=\"ScanQrCode\" />\n            <MenuItem x:Name=\"ImportSsrLinksFromClipboard\" />\n            <MenuItem x:Name=\"ImportServers\" />\n            <Separator />\n            <MenuItem x:Name=\"LoadBalance\" />\n            <MenuItem x:Name=\"SameHostForSameAddress\" />\n            <Separator />\n            <MenuItem x:Name=\"ServerStatistic\" />\n            <MenuItem x:Name=\"DisconnectCurrent\" />\n        </MenuItem>\n        <MenuItem x:Name=\"ServersSubscribe\">\n            <MenuItem x:Name=\"SubscribeSetting\" />\n            <MenuItem x:Name=\"UpdateSubscribeSsrNode\" />\n        </MenuItem>\n        <MenuItem x:Name=\"ShowLogs\" />\n        <Separator />\n        <MenuItem x:Name=\"More\">\n            <MenuItem x:Name=\"GlobalSettings\" />\n            <MenuItem x:Name=\"DnsSettings\" />\n            <MenuItem x:Name=\"PortSettings\" />\n            <MenuItem x:Name=\"GenQrCode\" />\n            <Separator />\n            <MenuItem x:Name=\"OpenWiki\" />\n            <MenuItem x:Name=\"Feedback\" />\n            <Separator />\n            <MenuItem x:Name=\"Update\">\n                <MenuItem x:Name=\"CheckUpdate\" />\n                <MenuItem x:Name=\"UpdateAvailable\" Visibility=\"Collapsed\" />\n                <Separator />\n                <MenuItem x:Name=\"AutoCheckUpdate\" />\n                <MenuItem x:Name=\"AllowPreRelease\" />\n            </MenuItem>\n        </MenuItem>\n        <MenuItem x:Name=\"Quit\" />\n    </ContextMenu>\n</ResourceDictionary>\n"
  },
  {
    "path": "shadowsocks-csharp/View/PortSettingsWindow.xaml",
    "content": "﻿<Window\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:controls=\"clr-namespace:Shadowsocks.View.Controls\"\n        x:Class=\"Shadowsocks.View.PortSettingsWindow\"\n        Title=\"{DynamicResource Title}\"\n        Height=\"500\" Width=\"730\" WindowStartupLocation=\"CenterScreen\"\n        Loaded=\"Window_Loaded\">\n\n    <Window.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"../I18N/PortSettingsWindow.en-US.xaml\" />\n            </ResourceDictionary.MergedDictionaries>\n            <SolidColorBrush x:Key=\"DisabledBackgroundBrush\" Color=\"LightGray\" />\n            <Style TargetType=\"{x:Type TextBox}\">\n                <Style.Triggers>\n                    <Trigger Property=\"IsEnabled\" Value=\"False\">\n                        <Setter Property=\"Background\" Value=\"{StaticResource DisabledBackgroundBrush}\" />\n                    </Trigger>\n                    <Trigger Property=\"IsReadOnly\" Value=\"True\">\n                        <Setter Property=\"Background\" Value=\"{StaticResource DisabledBackgroundBrush}\" />\n                    </Trigger>\n                </Style.Triggers>\n            </Style>\n        </ResourceDictionary>\n    </Window.Resources>\n\n    <Grid>\n        <Grid.RowDefinitions>\n            <RowDefinition />\n            <RowDefinition Height=\"Auto\" />\n        </Grid.RowDefinitions>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition />\n            <ColumnDefinition />\n        </Grid.ColumnDefinitions>\n        <ListBox x:Name=\"PortsListBox\" Grid.Row=\"0\" Grid.Column=\"0\" Margin=\"10,0,0,0\"\n                 ScrollViewer.HorizontalScrollBarVisibility=\"Auto\"\n                 ScrollViewer.VerticalScrollBarVisibility=\"Auto\" ScrollViewer.CanContentScroll=\"True\" SelectionChanged=\"PortsListBox_SelectionChanged\"/>\n        <GroupBox Grid.Row=\"0\" Grid.Column=\"1\" Header=\"{DynamicResource MapSetting}\">\n            <StackPanel>\n                <Grid Margin=\"0,10,0,0\">\n                    <Grid.RowDefinitions>\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                    </Grid.RowDefinitions>\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\" />\n                        <ColumnDefinition Width=\"*\" />\n                    </Grid.ColumnDefinitions>\n                    <Label Grid.Row=\"1\" Grid.Column=\"0\" Content=\"{DynamicResource Type}\"/>\n                    <Label Grid.Row=\"2\" Grid.Column=\"0\" Content=\"{DynamicResource ServerId}\"/>\n                    <Label Grid.Row=\"3\" Grid.Column=\"0\" Content=\"{DynamicResource LocalPort}\"/>\n                    <Label Grid.Row=\"4\" Grid.Column=\"0\" Content=\"{DynamicResource TargetAddress}\"/>\n                    <Label Grid.Row=\"5\" Grid.Column=\"0\" Content=\"{DynamicResource TargetPort}\"/>\n                    <Label Grid.Row=\"6\" Grid.Column=\"0\" Content=\"{DynamicResource Remarks}\"/>\n                    <CheckBox x:Name=\"EnableCheckBox\" Grid.Row=\"0\" Grid.Column=\"1\" Content=\"{DynamicResource Enable}\" VerticalAlignment=\"Center\" Margin=\"0,0,0,5\" />\n                    <ComboBox x:Name=\"TypeComboBox\" Grid.Row=\"1\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\"\n                    DisplayMemberPath=\"Text\"\n                    SelectedValuePath=\"Value\"\n                    SelectedIndex=\"0\"\n                    SelectionChanged=\"TypeComboBox_SelectionChanged\" />\n                    <ComboBox x:Name=\"ServersComboBox\" Grid.Row=\"2\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" />\n                    <controls:NumberUpDown x:Name=\"LocalPortNumber\" Grid.Row=\"3\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" MinNum=\"0\" MaxNum=\"65535\" />\n                    <TextBox x:Name=\"TargetAddressTextBox\" Grid.Row=\"4\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" VerticalContentAlignment=\"Center\" />\n                    <controls:NumberUpDown x:Name=\"TargetPortNumber\" Grid.Row=\"5\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" MinNum=\"0\" MaxNum=\"65535\" />\n                    <TextBox x:Name=\"RemarksTextBox\" Grid.Row=\"6\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" VerticalContentAlignment=\"Center\" />\n                </Grid>\n            </StackPanel>\n        </GroupBox>\n        <Grid Grid.Row=\"1\" Grid.Column=\"0\" Margin=\"10,10,0,10\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition />\n                <ColumnDefinition />\n            </Grid.ColumnDefinitions>\n            <Button Grid.Column=\"0\" Content=\"{DynamicResource Add}\" FontSize=\"14\" Click=\"AddButton_Click\"/>\n            <Button Grid.Column=\"1\" Content=\"{DynamicResource Delete}\" FontSize=\"14\" Click=\"DeleteButton_Click\"/>\n        </Grid>\n        <Grid Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"10,10,10,10\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition />\n                <ColumnDefinition />\n                <ColumnDefinition />\n            </Grid.ColumnDefinitions>\n            <Button Grid.Column=\"0\" Content=\"{DynamicResource Ok}\" FontSize=\"14\" Click=\"OkButton_Click\"/>\n            <Button Grid.Column=\"1\" Content=\"{DynamicResource Cancel}\" FontSize=\"14\" Click=\"CancelButton_Click\"/>\n            <Button x:Name=\"ApplyButton\" Grid.Column=\"2\" Content=\"{DynamicResource Apply}\" FontSize=\"14\" Click=\"ApplyButton_Click\"/>\n        </Grid>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "shadowsocks-csharp/View/PortSettingsWindow.xaml.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Util;\nusing Shadowsocks.View.Controls;\nusing System;\nusing System.Collections.Generic;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Shadowsocks.View\n{\n    //TODO:MVVM\n    public partial class PortSettingsWindow\n    {\n        private readonly MainController _controller;\n        private Configuration _modifiedConfiguration;\n        private int _oldSelectedIndex = -1;\n\n        private event EventHandler ValueChanged;\n\n        public PortSettingsWindow(MainController controller)\n        {\n            InitializeComponent();\n            I18NUtil.SetLanguage(Resources, @\"PortSettingsWindow\");\n            Closed += (o, e) => { _controller.ConfigChanged -= controller_ConfigChanged; };\n            _controller = controller;\n            LoadItems();\n        }\n\n        private void Window_Loaded(object sender, RoutedEventArgs _)\n        {\n            _controller.ConfigChanged += controller_ConfigChanged;\n            ValueChanged += PortSettingsWindow_ValueChanged;\n\n            foreach (var c in ViewUtils.FindVisualChildren<TextBox>(this))\n            {\n                //Not Child of NumberUpDown\n                if (c.Name.EndsWith(@\"TextBox\"))\n                {\n                    c.TextChanged += (o, e) =>\n                    {\n                        ValueChanged?.Invoke(this, EventArgs.Empty);\n                    };\n                }\n            }\n            foreach (var c in ViewUtils.FindVisualChildren<CheckBox>(this))\n            {\n                c.Checked += (o, e) =>\n                {\n                    ValueChanged?.Invoke(this, EventArgs.Empty);\n                };\n                c.Unchecked += (o, e) =>\n                {\n                    ValueChanged?.Invoke(this, EventArgs.Empty);\n                };\n            }\n            foreach (var c in ViewUtils.FindVisualChildren<ComboBox>(this))\n            {\n                c.SelectionChanged += (o, e) =>\n                {\n                    ValueChanged?.Invoke(this, EventArgs.Empty);\n                };\n            }\n            foreach (var c in ViewUtils.FindVisualChildren<NumberUpDown>(this))\n            {\n                c.ValueChanged += (o, e) =>\n                {\n                    ValueChanged?.Invoke(this, EventArgs.Empty);\n                };\n            }\n\n            LoadCurrentConfiguration();\n            ApplyButton.IsEnabled = false;\n        }\n\n        private void PortSettingsWindow_ValueChanged(object sender, EventArgs e)\n        {\n            ApplyButton.IsEnabled = true;\n        }\n\n        private void LoadItems()\n        {\n            var items = new[]\n            {\n                    new {Text = this.GetWindowStringValue(@\"PortForward\"), Value = PortMapType.Forward},\n                    new {Text = this.GetWindowStringValue(@\"ForceProxy\"), Value = PortMapType.ForceProxy},\n                    new {Text = this.GetWindowStringValue(@\"ProxyWithRule\"), Value = PortMapType.RuleProxy}\n            };\n            TypeComboBox.ItemsSource = items;\n        }\n\n        private void controller_ConfigChanged(object sender, EventArgs e)\n        {\n            LoadCurrentConfiguration();\n            ApplyButton.IsEnabled = false;\n        }\n\n        private void LoadCurrentConfiguration()\n        {\n            _modifiedConfiguration = Global.Load();\n            LoadConfiguration(_modifiedConfiguration);\n            LoadSelectedServer();\n        }\n\n        private void LoadConfiguration(Configuration configuration)\n        {\n            ServersComboBox.Items.Clear();\n            ServersComboBox.Items.Add(string.Empty);\n            var serverGroup = new Dictionary<string, int>();\n            foreach (var s in configuration.Configs)\n            {\n                if (!string.IsNullOrEmpty(s.Group) && !serverGroup.ContainsKey(s.Group))\n                {\n                    ServersComboBox.Items.Add(@\"#\" + s.Group);\n                    serverGroup[s.Group] = 1;\n                }\n            }\n\n            foreach (var s in configuration.Configs)\n            {\n                ServersComboBox.Items.Add(GetDisplayText(s));\n            }\n\n            PortsListBox.Items.Clear();\n            var list = new int[configuration.PortMap.Count];\n            var listIndex = 0;\n            foreach (var it in configuration.PortMap)\n            {\n                int.TryParse(it.Key, out list[listIndex]);\n\n                listIndex += 1;\n            }\n\n            Array.Sort(list);\n            foreach (var port in list)\n            {\n                var remarks = configuration.PortMap[port.ToString()].Remarks ?? string.Empty;\n                PortsListBox.Items.Add(port + \"    \" + remarks);\n            }\n\n            _oldSelectedIndex = -1;\n            if (PortsListBox.Items.Count > 0)\n            {\n                PortsListBox.SelectedIndex = 0;\n            }\n        }\n\n        private void SaveSelectedServer()\n        {\n            if (_oldSelectedIndex != -1)\n            {\n                var refreshList = false;\n                var key = _oldSelectedIndex.ToString();\n                if (key != LocalPortNumber.NumValue.ToString())\n                {\n                    if (_modifiedConfiguration.PortMap.ContainsKey(key))\n                    {\n                        _modifiedConfiguration.PortMap.Remove(key);\n                    }\n                    refreshList = true;\n                    key = LocalPortNumber.NumValue.ToString();\n                    if (!int.TryParse(key, out _oldSelectedIndex))\n                    {\n                        _oldSelectedIndex = 0;\n                    }\n                }\n                if (!_modifiedConfiguration.PortMap.ContainsKey(key))\n                {\n                    _modifiedConfiguration.PortMap[key] = new PortMapConfig();\n                }\n                var cfg = _modifiedConfiguration.PortMap[key];\n\n                cfg.Enable = EnableCheckBox.IsChecked.GetValueOrDefault();\n                cfg.Type = (PortMapType)TypeComboBox.SelectedValue;\n                cfg.Id = GetId(ServersComboBox.Text);\n                cfg.Server_addr = TargetAddressTextBox.Text;\n                if (cfg.Remarks != RemarksTextBox.Text)\n                {\n                    refreshList = true;\n                }\n                cfg.Remarks = RemarksTextBox.Text;\n                cfg.Server_port = TargetPortNumber.NumValue;\n                if (refreshList)\n                {\n                    LoadConfiguration(_modifiedConfiguration);\n                }\n            }\n        }\n\n        private string GetIdText(string id)\n        {\n            foreach (var s in _modifiedConfiguration.Configs)\n            {\n                if (id == s.Id)\n                {\n                    return GetDisplayText(s);\n                }\n            }\n\n            return string.Empty;\n        }\n\n        private void LoadSelectedServer()\n        {\n            var key = ServerListText2Key((string)PortsListBox.SelectedItem);\n            var serverGroup = new Dictionary<string, int>();\n            foreach (var s in _modifiedConfiguration.Configs)\n            {\n                if (!string.IsNullOrEmpty(s.Group) && !serverGroup.ContainsKey(s.Group))\n                {\n                    serverGroup[s.Group] = 1;\n                }\n            }\n            if (key != null && _modifiedConfiguration.PortMap.ContainsKey(key))\n            {\n                var cfg = _modifiedConfiguration.PortMap[key];\n\n                EnableCheckBox.IsChecked = cfg.Enable;\n                TypeComboBox.SelectedValue = cfg.Type;\n                var text = GetIdText(cfg.Id);\n                if (text.Length == 0 && serverGroup.ContainsKey(cfg.Id))\n                {\n                    text = $@\"#{cfg.Id}\";\n                }\n                ServersComboBox.Text = text;\n                LocalPortNumber.NumValue = int.Parse(key);\n                TargetAddressTextBox.Text = cfg.Server_addr;\n                TargetPortNumber.NumValue = cfg.Server_port;\n                RemarksTextBox.Text = cfg.Remarks ?? string.Empty;\n\n                if (!int.TryParse(key, out _oldSelectedIndex))\n                {\n                    _oldSelectedIndex = 0;\n                }\n            }\n        }\n\n        private void AddButton_Click(object sender, RoutedEventArgs e)\n        {\n            var hasBind = false;\n            if (ValueChanged != null)\n            {\n                ValueChanged -= PortSettingsWindow_ValueChanged;\n                hasBind = true;\n            }\n\n            SaveSelectedServer();\n            const string key = @\"0\";\n            if (!_modifiedConfiguration.PortMap.ContainsKey(key))\n            {\n                _modifiedConfiguration.PortMap[key] = new PortMapConfig();\n                PortSettingsWindow_ValueChanged(this, EventArgs.Empty);\n            }\n\n            var cfg = _modifiedConfiguration.PortMap[key];\n\n            cfg.Enable = EnableCheckBox.IsChecked.GetValueOrDefault();\n            cfg.Type = (PortMapType)TypeComboBox.SelectedValue;\n            cfg.Id = GetId(ServersComboBox.Text);\n            cfg.Server_addr = TargetAddressTextBox.Text;\n            cfg.Remarks = RemarksTextBox.Text;\n            cfg.Server_port = TargetPortNumber.NumValue;\n\n            _oldSelectedIndex = -1;\n            LoadConfiguration(_modifiedConfiguration);\n            LoadSelectedServer();\n\n            if (hasBind)\n            {\n                ValueChanged += PortSettingsWindow_ValueChanged;\n            }\n        }\n\n        private void DeleteButton_Click(object sender, RoutedEventArgs e)\n        {\n            var key = _oldSelectedIndex.ToString();\n            if (_modifiedConfiguration.PortMap.ContainsKey(key))\n            {\n                _modifiedConfiguration.PortMap.Remove(key);\n            }\n            _oldSelectedIndex = -1;\n            LoadConfiguration(_modifiedConfiguration);\n            LoadSelectedServer();\n            ValueChanged?.Invoke(this, EventArgs.Empty);\n        }\n\n        private void TypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)\n        {\n            if (TypeComboBox.SelectedIndex == 0)\n            {\n                TargetAddressTextBox.IsReadOnly = false;\n                TargetPortNumber.IsEnabled = true;\n            }\n            else\n            {\n                TargetAddressTextBox.IsReadOnly = true;\n                TargetPortNumber.IsEnabled = false;\n            }\n        }\n\n        private void PortsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)\n        {\n            var hasBind = false;\n            if (ValueChanged != null)\n            {\n                ValueChanged -= PortSettingsWindow_ValueChanged;\n                hasBind = true;\n            }\n\n            if (PortsListBox.SelectedIndex != -1)\n            {\n                SaveSelectedServer();\n                LoadSelectedServer();\n            }\n\n            if (hasBind)\n            {\n                ValueChanged += PortSettingsWindow_ValueChanged;\n            }\n        }\n\n        private void SaveConfig()\n        {\n            SaveSelectedServer();\n            _controller.SaveServersPortMap(_modifiedConfiguration);\n        }\n\n        private void OkButton_Click(object sender, RoutedEventArgs e)\n        {\n            if (ApplyButton.IsEnabled)\n            {\n                SaveConfig();\n            }\n            Close();\n        }\n\n        private void CancelButton_Click(object sender, RoutedEventArgs e)\n        {\n            Close();\n        }\n\n        private void ApplyButton_Click(object sender, RoutedEventArgs e)\n        {\n            SaveConfig();\n            ApplyButton.IsEnabled = false;\n        }\n\n        #region Static\n\n        private static string GetDisplayText(Server s)\n        {\n            return (!string.IsNullOrEmpty(s.Group) ? s.Group + \" - \" : \"    - \") + s.FriendlyName + \"        #\" + s.Id;\n        }\n\n        private static string GetId(string text)\n        {\n            if (text.IndexOf('#') >= 0)\n            {\n                return text.Substring(text.IndexOf('#') + 1);\n            }\n\n            return text;\n        }\n\n        private static string ServerListText2Key(string text)\n        {\n            if (text != null)\n            {\n                var pos = text.IndexOf(' ');\n                if (pos > 0)\n                {\n                    return text.Substring(0, pos);\n                }\n            }\n\n            return text;\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/QRCodeSplashWindow.xaml",
    "content": "﻿<Window x:Class=\"Shadowsocks.View.QRCodeSplashWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\"\n        Height=\"300\" Width=\"300\"\n        WindowStyle=\"None\" ResizeMode=\"NoResize\"\n        Background=\"Transparent\" AllowsTransparency=\"True\"\n        Topmost=\"True\" ShowInTaskbar=\"False\" WindowStartupLocation=\"Manual\">\n    <Grid>\n        <Border BorderBrush=\"Red\" BorderThickness=\"3,3,3,3\" Background=\"#4CFF0000\" />\n    </Grid>\n</Window>\n"
  },
  {
    "path": "shadowsocks-csharp/View/QRCodeSplashWindow.xaml.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.Threading.Tasks;\nusing System.Windows;\n\nnamespace Shadowsocks.View\n{\n    public partial class QRCodeSplashWindow\n    {\n        public QRCodeSplashWindow()\n        {\n            InitializeComponent();\n            Loaded += Window_Loaded;\n        }\n\n        public Rectangle TargetRect;\n\n        private int _flashStep;\n        private const double Fps = 1.0 / 15.6 * 1000; // Timer resolution is 15.625ms\n        private const double AnimationTime = 0.5;\n        private const int AnimationSteps = (int)(AnimationTime * Fps);\n        private double _x;\n        private double _y;\n        private double _w;\n        private double _h;\n\n        private void Window_Loaded(object sender, RoutedEventArgs e)\n        {\n            Visibility = Visibility.Hidden;\n            _flashStep = 0;\n            _x = Left;\n            _y = Top;\n            _w = Width;\n            _h = Height;\n            Splash();\n        }\n\n        private async void Splash()\n        {\n            var sw = Stopwatch.StartNew();\n            var interval = (int)(AnimationTime * 1000 / AnimationSteps);\n            while (true)\n            {\n                var percent = sw.ElapsedMilliseconds / 1000.0 / AnimationTime;\n                if (percent < 1)\n                {\n                    percent = 1 - Math.Pow(1 - percent, 4);\n                    Left = _x + TargetRect.X * percent;\n                    Top = _y + TargetRect.Y * percent;\n                    Width = TargetRect.Width * percent + _w * (1 - percent);\n                    Height = TargetRect.Height * percent + _h * (1 - percent);\n                    Visibility = Visibility.Visible;\n                }\n                else\n                {\n                    if (_flashStep == 0)\n                    {\n                        interval = 100;\n                        Visibility = Visibility.Hidden;\n                    }\n                    else if (_flashStep == 1)\n                    {\n                        interval = 50;\n                        Visibility = Visibility.Visible;\n                    }\n                    else if (_flashStep == 2)\n                    {\n                        Visibility = Visibility.Hidden;\n                    }\n                    else if (_flashStep == 3)\n                    {\n                        Visibility = Visibility.Visible;\n                    }\n                    else if (_flashStep == 4)\n                    {\n                        Visibility = Visibility.Hidden;\n                    }\n                    else if (_flashStep == 5)\n                    {\n                        Visibility = Visibility.Visible;\n                    }\n                    else\n                    {\n                        sw.Stop();\n                        Close();\n                        return;\n                    }\n                    ++_flashStep;\n                }\n                await Task.Delay(interval);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ServerConfigWindow.xaml",
    "content": "﻿<Window x:Class=\"Shadowsocks.View.ServerConfigWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:syncfusion=\"http://schemas.syncfusion.com/wpf\"\n        xmlns:valueConverter=\"clr-namespace:Shadowsocks.View.ValueConverter\"\n        xmlns:controls=\"clr-namespace:Shadowsocks.View.Controls\"\n        mc:Ignorable=\"d\"\n        x:Name=\"Cw\" \n        Title=\"ConfigWindow\" Height=\"560\" Width=\"800\" WindowStartupLocation=\"CenterScreen\"\n        Loaded=\"Window_Loaded\"\n        Activated=\"ConfigWindow_OnActivated\"\n        >\n\n    <Window.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"../I18N/ConfigWindow.en-US.xaml\" />\n            </ResourceDictionary.MergedDictionaries>\n            <SolidColorBrush x:Key=\"DisabledBackgroundBrush\" Color=\"LightGray\" />\n            <Style TargetType=\"{x:Type TextBox}\">\n                <Style.Triggers>\n                    <Trigger Property=\"IsEnabled\" Value=\"False\">\n                        <Setter Property=\"Background\" Value=\"{StaticResource DisabledBackgroundBrush}\" />\n                    </Trigger>\n                    <Trigger Property=\"IsReadOnly\" Value=\"True\">\n                        <Setter Property=\"Background\" Value=\"{StaticResource DisabledBackgroundBrush}\" />\n                    </Trigger>\n                </Style.Triggers>\n            </Style>\n            <BooleanToVisibilityConverter x:Key=\"Bool2Visibility\" />\n            <valueConverter:ServerTreeTypeToFontConverter x:Key=\"ServerTreeTypeToFontConverter\" />\n            <valueConverter:BooleanToEnabledConverter x:Key=\"BooleanToEnabledConverter\" />\n        </ResourceDictionary>\n    </Window.Resources>\n\n    <Grid x:Name=\"MainGrid\">\n        <Grid.RowDefinitions>\n            <RowDefinition />\n            <RowDefinition Height=\"Auto\"/>\n            <RowDefinition Height=\"Auto\"/>\n        </Grid.RowDefinitions>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition />\n            <ColumnDefinition Width=\"*\"/>\n            <ColumnDefinition Width=\"Auto\" />\n        </Grid.ColumnDefinitions>\n        <GridSplitter Grid.Column=\"0\" Grid.RowSpan=\"3\"\n                      HorizontalAlignment=\"Right\"\n                      VerticalAlignment=\"Stretch\"\n                      Width=\"3\"\n                       />\n        <GridSplitter x:Name=\"Splitter2\" Grid.Row=\"0\" Grid.Column=\"1\" Grid.RowSpan=\"3\"\n                      HorizontalAlignment=\"Right\"\n                      VerticalAlignment=\"Stretch\"\n                      Width=\"3\" Visibility=\"Collapsed\"/>\n\n        <syncfusion:SfTreeView x:Name=\"ServersTreeView\"\n                               Grid.Row=\"0\" Grid.Column=\"0\" Grid.RowSpan=\"3\" Margin=\"10,0,10,10\"\n                               ChildPropertyName=\"Nodes\"\n                               FullRowSelect=\"True\"\n                               IsAnimationEnabled=\"False\"\n                               SelectionMode=\"Extended\"\n                               ItemTemplateDataContextType=\"Item\"\n                               AutoExpandMode=\"AllNodes\"\n                               DataContext=\"{Binding Path=ServerConfigViewModel, ElementName=Cw}\"\n                               ItemsSource=\"{Binding ServersTreeViewCollection}\"\n                               ExpandActionTrigger=\"Expander\"\n                               AllowDragging=\"True\"\n                               SelectionChanged=\"ServersTreeView_OnSelectionChanged\"\n                               ItemDropping=\"ServersTreeView_OnItemDropping\"\n                               >\n            <syncfusion:SfTreeView.ContextMenu>\n                <ContextMenu>\n                    <MenuItem Header=\"{DynamicResource Add}\" Click=\"AddButton_Click\" />\n                    <MenuItem Header=\"{DynamicResource Delete}\" Click=\"DeleteButton_Click\" />\n                </ContextMenu>\n            </syncfusion:SfTreeView.ContextMenu>\n            <syncfusion:SfTreeView.ItemTemplate>\n                <DataTemplate>\n                    <Grid >\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width=\"Auto\" />\n                            <ColumnDefinition Width=\"*\" />\n                        </Grid.ColumnDefinitions>\n                        <CheckBox x:Name=\"CheckBox\" FocusVisualStyle=\"{x:Null}\" Margin=\"0,3,3,0\"\n                                  VerticalAlignment=\"Center\" Height=\"22\"\n                                  IsChecked=\"{Binding Server.Enable, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"\n                                  Visibility=\"{Binding Type,Converter={StaticResource BooleanToEnabledConverter}}\" />\n                        <TextBlock Grid.Column=\"1\" Text=\"{Binding Name}\" \n                                   VerticalAlignment=\"Stretch\" HorizontalAlignment=\"Stretch\" FontSize=\"14\" Height=\"22\"\n                                   Foreground=\"{Binding Type,Converter={StaticResource ServerTreeTypeToFontConverter}}\"\n                                   FontWeight=\"{Binding Type,Converter={StaticResource ServerTreeTypeToFontConverter}}\" />\n                    </Grid>\n                </DataTemplate>\n            </syncfusion:SfTreeView.ItemTemplate>\n\n        </syncfusion:SfTreeView>\n        <Button x:Name=\"ShowQrCodeButton\" Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"10,10,10,0\" Content=\">>\" HorizontalAlignment=\"Right\" Width=\"40\" Click=\"ShowQrCodeButton_OnClick\"/>\n        <Grid Grid.Row=\"2\" Grid.Column=\"1\" Margin=\"5,10,10,10\" >\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition />\n                <ColumnDefinition />\n                <ColumnDefinition />\n            </Grid.ColumnDefinitions>\n            <Button Grid.Column=\"0\" Content=\"{DynamicResource Ok}\" FontSize=\"14\" Click=\"OkButton_Click\"></Button>\n            <Button Grid.Column=\"1\" Content=\"{DynamicResource Cancel}\" FontSize=\"14\" Click=\"CancelButton_Click\"></Button>\n            <Button x:Name=\"ApplyButton\" Grid.Column=\"2\" Content=\"{DynamicResource Apply}\" FontSize=\"14\" Click=\"ApplyButton_Click\"></Button>\n        </Grid>\n        <GroupBox x:Name=\"ServerGroupBox\" Grid.Row=\"0\" Grid.Column=\"1\" Header=\"{DynamicResource Server}\" Margin=\"5,0,5,0\"\n                  DataContext=\"{Binding Path=ServerConfigViewModel, ElementName=Cw}\">\n            <StackPanel >\n                <Grid>\n                    <Grid.RowDefinitions>\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                        <RowDefinition />\n                    </Grid.RowDefinitions>\n                    <Grid.ColumnDefinitions>\n                        <ColumnDefinition Width=\"Auto\" />\n                        <ColumnDefinition Width=\"*\" />\n                    </Grid.ColumnDefinitions>\n\n                    <CheckBox Grid.Row=\"0\" Grid.Column=\"0\" Content=\"{DynamicResource ServerIp}\" VerticalAlignment=\"Center\" Margin=\"0,10,5,0\" IsChecked=\"{Binding PlainMode,Mode=TwoWay,ElementName=ServerIpTextBox}\" ContentStringFormat=\"*{0}\" HorizontalAlignment=\"Right\" />\n                    <controls:MaskedTextBox x:Name=\"ServerIpTextBox\" Grid.Row=\"0\" Grid.Column=\"1\"\n                                            Height=\"23.24\" Margin=\"0,10,0,0\"\n                                            PlainMode=\"False\"\n                                            Text=\"{Binding SelectedItem.Server.server,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <Label Grid.Row=\"1\" Grid.Column=\"0\" Content=\"{DynamicResource ServerPort}\" ContentStringFormat=\"*{0}\" Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\" />\n                    <controls:NumberUpDown Grid.Row=\"1\" Grid.Column=\"1\" Height=\"23.24\" Margin=\"0,5,0,0\"\n                                           VerticalAlignment=\"Center\" MinNum=\"0\" MaxNum=\"65535\"\n                                           Value=\"{Binding SelectedItem.Server.Server_Port,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <CheckBox Grid.Row=\"2\" Grid.Column=\"0\"\n                              Content=\"{DynamicResource Password}\" VerticalAlignment=\"Center\"\n                              Margin=\"0,5,5,0\" IsChecked=\"{Binding PlainMode,Mode=TwoWay,ElementName=PasswordTextBox}\"\n                              ContentStringFormat=\"*{0}\" HorizontalAlignment=\"Right\" />\n                    <controls:MaskedTextBox x:Name=\"PasswordTextBox\" Grid.Row=\"2\" Grid.Column=\"1\"\n                                            Height=\"23.24\" Margin=\"0,5,0,0\" \n                                            PlainMode=\"False\"\n                                            Text=\"{Binding SelectedItem.Server.Password,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <Label Grid.Row=\"3\" Grid.Column=\"0\" Content=\"{DynamicResource Encryption}\" ContentStringFormat=\"*{0}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\" />\n                    <ComboBox x:Name=\"EncryptionComboBox\" Grid.Row=\"3\" Grid.Column=\"1\"\n                              Height=\"23.24\" Margin=\"0,5,0,0\" IsEditable=\"True\"\n                              Text=\"{Binding SelectedItem.Server.Method,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <Label Grid.Row=\"4\" Grid.Column=\"0\" Content=\"{DynamicResource Protocol}\" ContentStringFormat=\"*{0}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\" Foreground=\"#FF8000C0\" />\n                    <ComboBox x:Name=\"ProtocolComboBox\" Grid.Row=\"4\" Grid.Column=\"1\"\n                              Height=\"23.24\" Margin=\"0,5,0,0\" IsEditable=\"True\"\n                              Text=\"{Binding SelectedItem.Server.Protocol,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <Label Grid.Row=\"5\" Grid.Column=\"0\" Content=\"{DynamicResource ProtocolParam}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\" Foreground=\"#FF8000C0\" />\n                    <TextBox Grid.Row=\"5\" Grid.Column=\"1\" Height=\"23.24\" Margin=\"0,5,0,0\" \n                             Text=\"{Binding SelectedItem.Server.ProtocolParam,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n\n                    <Label Grid.Row=\"6\" Grid.Column=\"0\" Content=\"{DynamicResource Obfs}\" ContentStringFormat=\"*{0}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\" Foreground=\"#FF8000C0\" />\n                    <ComboBox x:Name=\"ObfsComboBox\" Grid.Row=\"6\" Grid.Column=\"1\"\n                              Height=\"23.24\" Margin=\"0,5,0,0\" IsEditable=\"True\" SelectionChanged=\"ObfsComboBox_SelectionChanged\"\n                              Text=\"{Binding SelectedItem.Server.obfs,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <Label Grid.Row=\"7\" Grid.Column=\"0\" Content=\"{DynamicResource ObfsParam}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\" Foreground=\"#FF8000C0\" />\n                    <TextBox x:Name=\"ObfsParamTextBox\" Grid.Row=\"7\" Grid.Column=\"1\" Height=\"23.24\" Margin=\"0,5,0,0\"\n                             Text=\"{Binding SelectedItem.Server.ObfsParam,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <Label Grid.Row=\"8\" Grid.Column=\"0\" Content=\"{DynamicResource Remarks}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\" />\n                    <TextBox Grid.Row=\"8\" Grid.Column=\"1\" Height=\"23.24\" Margin=\"0,5,0,0\" \n                    Text=\"{Binding SelectedItem.Server.Remarks,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n\n                    <Label Grid.Row=\"9\" Grid.Column=\"0\" Content=\"{DynamicResource Group}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\" />\n                    <TextBox Grid.Row=\"9\" Grid.Column=\"1\" Height=\"23.24\" Margin=\"0,5,0,0\"\n                             Text=\"{Binding SelectedItem.Server.Group,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <CheckBox x:Name=\"SsrLinkCheckBox\" Grid.Row=\"10\" Grid.Column=\"0\"\n                              Content=\"{DynamicResource SsrLink}\" VerticalAlignment=\"Center\"\n                              Margin=\"0,5,5,0\"\n                              HorizontalAlignment=\"Right\"\n                              IsChecked=\"True\"/>\n                    <TextBox x:Name=\"LinkTextBox\" Grid.Row=\"10\" Grid.Column=\"1\" Height=\"23.24\" Margin=\"0,5,0,0\" IsReadOnly=\"True\"\n                    GotFocus=\"LinkTextBox_GotFocus\" PreviewMouseUp=\"LinkTextBox_PreviewMouseUp\"\n                    TextChanged=\"LinkTextBox_TextChanged\">\n                         <TextBox.Style>\n                            <Style TargetType=\"{x:Type TextBox}\" BasedOn=\"{StaticResource {x:Type TextBox}}\">\n                                <Setter Property=\"Text\" Value=\"{Binding SelectedItem.Server.SsrLink,ElementName=ServersTreeView,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}\" />\n                                <Style.Triggers>\n                                    <DataTrigger Binding=\"{Binding IsChecked,ElementName=SsrLinkCheckBox}\" Value=\"False\">\n                                        <Setter Property=\"Text\" Value=\"{Binding SelectedItem.Server.SsLink,ElementName=ServersTreeView,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}\" />\n                                </DataTrigger>\n                            </Style.Triggers>\n                            </Style>\n                        </TextBox.Style>\n                    </TextBox>\n\n                    <CheckBox x:Name=\"AdvSettingCheckBox\" Grid.Row=\"11\" Grid.Column=\"0\"\n                              Content=\"{DynamicResource AdvSetting}\" VerticalAlignment=\"Center\"\n                              Margin=\"0,5,5,0\"\n                              HorizontalAlignment=\"Right\"\n                              IsChecked=\"{Binding SelectedItem.Server.ShowAdvSetting,ElementName=ServersTreeView,Mode=OneWay}\" />\n                    <TextBlock Grid.Row=\"11\" Grid.Column=\"1\" Margin=\"0,5,0,0\" Text=\"{DynamicResource AdvSettingDescription}\"/>\n\n                    <Label Grid.Row=\"12\" Grid.Column=\"0\" Content=\"{DynamicResource UdpPort}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\"\n                           Visibility=\"{Binding IsChecked,ElementName=AdvSettingCheckBox,Converter={StaticResource Bool2Visibility}}\" />\n                    <controls:NumberUpDown Grid.Row=\"12\" Grid.Column=\"1\" Height=\"23.24\" Margin=\"0,5,0,0\"\n                                           VerticalAlignment=\"Center\" MinNum=\"0\" MaxNum=\"65535\"\n                                           Visibility=\"{Binding IsChecked,ElementName=AdvSettingCheckBox,Converter={StaticResource Bool2Visibility}}\"\n                                           Value=\"{Binding SelectedItem.Server.Server_Udp_Port,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n\n                    <Label Grid.Row=\"13\" Grid.Column=\"0\" Content=\"{DynamicResource UdpOverTcp}\"\n                           Margin=\"0,5,0,0\" HorizontalAlignment=\"Right\"\n                           Visibility=\"{Binding IsChecked,ElementName=AdvSettingCheckBox,Converter={StaticResource Bool2Visibility}}\" />\n                    <CheckBox Grid.Row=\"13\" Grid.Column=\"1\"\n                              Content=\"{DynamicResource UdpOverTcpCheckBox}\" VerticalAlignment=\"Center\"\n                              Margin=\"0,5,5,0\"\n                              Visibility=\"{Binding IsChecked,ElementName=AdvSettingCheckBox,Converter={StaticResource Bool2Visibility}}\" \n                              IsChecked=\"{Binding SelectedItem.Server.UdpOverTcp,ElementName=ServersTreeView,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n                </Grid>\n            </StackPanel>\n        </GroupBox>\n        <Image x:Name=\"PictureQrCode\" Grid.Row=\"0\" Grid.Column=\"2\" Grid.RowSpan=\"3\" Visibility=\"Collapsed\"\n        Stretch=\"Uniform\" HorizontalAlignment=\"Stretch\" VerticalAlignment=\"Stretch\" Margin=\"10,0,10,0\" StretchDirection=\"Both\" />\n\n    </Grid>\n</Window>\n"
  },
  {
    "path": "shadowsocks-csharp/View/ServerConfigWindow.xaml.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Encryption;\nusing Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Util;\nusing Shadowsocks.ViewModel;\nusing Syncfusion.Data.Extensions;\nusing Syncfusion.UI.Xaml.TreeView;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Input;\n\nnamespace Shadowsocks.View\n{\n    public partial class ServerConfigWindow\n    {\n        public ServerConfigWindow(MainController controller, int focusIndex)\n        {\n            InitializeComponent();\n            I18NUtil.SetLanguage(Resources, @\"ConfigWindow\");\n            SizeChanged += (o, args) => { GenQr(LinkTextBox.Text); };\n            Splitter2.DragDelta += (o, args) => { GenQr(LinkTextBox.Text); };\n            Closed += (o, e) =>\n            {\n                _controller.ConfigChanged -= controller_ConfigChanged;\n                ServerConfigViewModel.ServersChanged -= ServerViewModel_ServersChanged;\n            };\n\n            _controller = controller;\n            foreach (var name in from name in EncryptorFactory.RegisteredEncryptors.Keys let info = EncryptorFactory.GetEncryptorInfo(name) where info.Display select name)\n            {\n                EncryptionComboBox.Items.Add(name);\n            }\n            foreach (var protocol in Protocols)\n            {\n                ProtocolComboBox.Items.Add(protocol);\n            }\n            foreach (var obfs in ObfsStrings)\n            {\n                ObfsComboBox.Items.Add(obfs);\n            }\n\n            _controller.ConfigChanged += controller_ConfigChanged;\n            ServerConfigViewModel.ServersChanged += ServerViewModel_ServersChanged;\n            _focusIndex = focusIndex;\n            ServersTreeView_OnSelectionChanged(this, new ItemSelectionChangedEventArgs());\n        }\n\n        private void ServerViewModel_ServersChanged(object sender, EventArgs e)\n        {\n            ApplyButton.IsEnabled = true;\n        }\n\n        private static readonly string[] Protocols = {\n                \"origin\",\n                \"verify_deflate\",\n                \"auth_sha1_v4\",\n                \"auth_aes128_md5\",\n                \"auth_aes128_sha1\",\n                \"auth_chain_a\",\n                \"auth_chain_b\",\n                \"auth_chain_c\",\n                \"auth_chain_d\",\n                \"auth_chain_e\",\n                \"auth_chain_f\",\n                \"auth_akarin_rand\",\n                \"auth_akarin_spec_a\"\n        };\n\n        private static readonly string[] ObfsStrings = {\n                \"plain\",\n                \"http_simple\",\n                \"http_post\",\n                \"random_head\",\n                \"tls1.2_ticket_auth\",\n                \"tls1.2_ticket_fastauth\"\n        };\n\n        private readonly MainController _controller;\n\n        private Configuration _modifiedConfiguration;\n        private int _focusIndex;\n\n        public ServerConfigViewModel ServerConfigViewModel { get; set; } = new();\n\n        private void Window_Loaded(object sender, RoutedEventArgs e)\n        {\n            UpdateTitle();\n            LoadCurrentConfiguration(false);\n            switch (_focusIndex)\n            {\n                case -1:\n                {\n                    var index = _modifiedConfiguration.Index + 1;\n                    if (index < 0 || index > _modifiedConfiguration.Configs.Count)\n                    {\n                        index = _modifiedConfiguration.Configs.Count;\n                    }\n\n                    _focusIndex = index;\n                    break;\n                }\n                case -2:\n                {\n                    var index = _modifiedConfiguration.Index;\n                    if (index < 0 || index > _modifiedConfiguration.Configs.Count)\n                    {\n                        index = _modifiedConfiguration.Configs.Count;\n                    }\n\n                    _focusIndex = index;\n                    break;\n                }\n            }\n\n            if (_focusIndex >= 0 && _focusIndex < _modifiedConfiguration.Configs.Count)\n            {\n                MoveToSelectedItem(_focusIndex);\n            }\n        }\n\n        private void UpdateTitle()\n        {\n            Title = $@\"{this.GetWindowStringValue(@\"Title\")}({(Global.GuiConfig.ShareOverLan ? this.GetWindowStringValue(@\"Any\") : this.GetWindowStringValue(@\"Local\"))}:{Global.GuiConfig.LocalPort} {this.GetWindowStringValue(@\"Version\")}:{Controller.HttpRequest.UpdateChecker.FullVersion})\";\n        }\n\n        private void controller_ConfigChanged(object sender, EventArgs e)\n        {\n            LoadCurrentConfiguration(true);\n            UpdateTitle();\n        }\n\n        private void LoadCurrentConfiguration(bool scrollToSelectedItem)\n        {\n            _modifiedConfiguration = Global.Load();\n            ServerConfigViewModel.ReadServers(_modifiedConfiguration.Configs);\n\n            ServersTreeView.ExpandAll();\n            ServersTreeView.CollapseAll();\n\n            if (scrollToSelectedItem)\n            {\n                MoveToSelectedItem(_modifiedConfiguration.Index);\n            }\n\n            ApplyButton.IsEnabled = false;\n        }\n\n        #region TreeView\n\n        public void MoveToSelectedItem(int index)\n        {\n            if (index >= 0 && index < _modifiedConfiguration.Configs.Count)\n            {\n                var server = _modifiedConfiguration.Configs[index];\n                MoveToSelectedItem(server.Id);\n            }\n        }\n\n        private void MoveToSelectedItem(string id)\n        {\n            var serverTreeViewModel = ServerTreeViewModel.FindNode(ServerConfigViewModel.ServersTreeViewCollection, id);\n            if (serverTreeViewModel != null)\n            {\n                MoveToSelectedItem(serverTreeViewModel);\n            }\n        }\n\n        private void MoveToSelectedItem(ServerTreeViewModel serverTreeViewModel)\n        {\n            ServersTreeView.BringIntoView(serverTreeViewModel, false, true, ScrollToPosition.Center);\n            ServersTreeView.SelectedItems?.Clear();\n            ServersTreeView.SelectedItem = serverTreeViewModel;\n            ServersTreeView_OnSelectionChanged(this, new ItemSelectionChangedEventArgs());\n        }\n\n        private void AddButton_Click(object sender, RoutedEventArgs e)\n        {\n            if (ServersTreeView.SelectedItem is ServerTreeViewModel st)\n            {\n                switch (st.Type)\n                {\n                    case ServerTreeViewType.Subtag:\n                        MessageBox.Show(this.GetWindowStringValue(@\"AddServerError\"), Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.OK, MessageBoxImage.Error);\n                        return;\n                    case ServerTreeViewType.Group:\n                    {\n                        var item = new ServerTreeViewModel\n                        {\n                            Type = ServerTreeViewType.Server,\n                            Server = new Server { Group = st.Name }\n                        };\n                        st.Nodes.Add(item);\n                        MoveToSelectedItem(item);\n                        return;\n                    }\n                    case ServerTreeViewType.Server:\n                    {\n                        var parent = ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, st);\n                        if (parent != null)\n                        {\n                            var item = new ServerTreeViewModel\n                            {\n                                Type = ServerTreeViewType.Server,\n                                Server = Server.Clone(st.Server)\n                            };\n                            var index = parent.Nodes.IndexOf(st) + 1;\n                            parent.Nodes.Insert(index, item);\n                            MoveToSelectedItem(item);\n                        }\n                        return;\n                    }\n                    default:\n                        throw new ArgumentOutOfRangeException();\n                }\n            }\n            var newServer = new Server();\n            ServerConfigViewModel.ReadServers(new List<Server> { newServer });\n            MoveToSelectedItem(newServer.Id);\n        }\n\n        private void DeleteButton_Click(object sender, RoutedEventArgs e)\n        {\n            var deleteItems = ServersTreeView.SelectedItems.ToArray();\n            foreach (var selectedItem in deleteItems)\n            {\n                if (selectedItem is ServerTreeViewModel st)\n                {\n                    ServerTreeViewModel.Remove(ServerConfigViewModel.ServersTreeViewCollection, st);\n                    ServersTreeView.SelectedItems.Clear();\n                    ServersTreeView_OnSelectionChanged(this, new ItemSelectionChangedEventArgs());\n                }\n            }\n        }\n\n        private void ServersTreeView_OnSelectionChanged(object sender, ItemSelectionChangedEventArgs e)\n        {\n            if (ServersTreeView.SelectedItems is not null\n                && ServersTreeView.SelectedItems.Count == 1\n                && ServersTreeView.SelectedItem is ServerTreeViewModel { Type: ServerTreeViewType.Server })\n            {\n                ServerGroupBox.Visibility = Visibility.Visible;\n            }\n            else\n            {\n                ServerGroupBox.Visibility = Visibility.Hidden;\n            }\n        }\n\n        private void ServersTreeView_OnItemDropping(object sender, TreeViewItemDroppingEventArgs e)\n        {\n            if (e.TargetNode.Content is ServerTreeViewModel target)\n            {\n                var source = e.DraggingNodes.Where(n => n.Content is ServerTreeViewModel).Select(n => (ServerTreeViewModel)n.Content).ToArray();\n                if (!source.Any())\n                {\n                    goto Skip;\n                }\n\n                if (source.Any(st => st.Type == ServerTreeViewType.Subtag))\n                {\n                    if (ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, target) != null)\n                    {\n                        goto Skip;\n                    }\n\n                    var res = e.DraggingNodes.Where(n => n.Content is ServerTreeViewModel st && st.Type == ServerTreeViewType.Subtag).ToArray();\n                    e.DraggingNodes.Clear();\n                    res.ForEach(x => e.DraggingNodes.Add(x));\n\n                    if (e.DropPosition == DropPosition.DropAsChild)\n                    {\n                        e.DropPosition = DropPosition.DropBelow;\n                    }\n                    return;\n                }\n                if (source.Any(st => st.Type == ServerTreeViewType.Group))\n                {\n                    var res = e.DraggingNodes.Where(n => n.Content is ServerTreeViewModel st && st.Type == ServerTreeViewType.Group).ToArray();\n                    e.DraggingNodes.Clear();\n                    res.ForEach(x => e.DraggingNodes.Add(x));\n\n                    if (target.Type == ServerTreeViewType.Subtag)\n                    {\n                        goto Skip;\n                    }\n                    if (target.Type == ServerTreeViewType.Group)\n                    {\n                        var parent = ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, target);\n                        if (parent == null)\n                        {\n                            goto Skip;\n                        }\n\n                        var isSameParent = e.DraggingNodes.All(n => n.Content is ServerTreeViewModel st\n                           && ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, st) == parent);\n\n                        if (!isSameParent)\n                        {\n                            goto Skip;\n                        }\n\n                        if (e.DropPosition == DropPosition.DropAsChild)\n                        {\n                            e.DropPosition = DropPosition.DropBelow;\n                        }\n                        return;\n                    }\n                    goto Skip;\n                }\n                // all is servers\n                if (target.Type == ServerTreeViewType.Subtag)\n                {\n                    goto Skip;\n                }\n                if (target.Type == ServerTreeViewType.Group)\n                {\n                    var sub = ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, target);\n                    if (sub == null)\n                    {\n                        return;\n                    }\n\n                    var subName = sub.Name == I18NUtil.GetAppStringValue(@\"EmptySubtag\") ? string.Empty : sub.Name;\n                    var groupName = target.Name == I18NUtil.GetAppStringValue(@\"EmptyGroup\") ? string.Empty : target.Name;\n\n                    e.DraggingNodes.ForEach(n =>\n                    {\n                        var server = ((ServerTreeViewModel)n.Content).Server;\n                        server.Group = groupName;\n                        server.SubTag = subName;\n                    });\n\n                    e.DropPosition = DropPosition.DropAsChild;\n                    return;\n                }\n\n                e.DraggingNodes.ForEach(n =>\n                {\n                    var server = ((ServerTreeViewModel)n.Content).Server;\n                    server.Group = target.Server.Group;\n                    server.SubTag = target.Server.SubTag;\n                });\n\n                if (e.DropPosition == DropPosition.DropAsChild)\n                {\n                    e.DropPosition = DropPosition.DropBelow;\n                }\n                return;\n            }\nSkip:\n            e.Handled = true;\n        }\n\n        #endregion\n\n        #region LinkTextBox\n\n        private void LinkTextBox_TextChanged(object sender, TextChangedEventArgs e)\n        {\n            GenQr(LinkTextBox.Text);\n        }\n\n        private void LinkTextBox_PreviewMouseUp(object sender, MouseButtonEventArgs e)\n        {\n            if (e.ChangedButton == MouseButton.Left)\n            {\n                var textBox = (TextBox)sender;\n                textBox.Dispatcher?.InvokeAsync(() => { textBox.SelectAll(); });\n            }\n        }\n\n        private void LinkTextBox_GotFocus(object sender, RoutedEventArgs e)\n        {\n            ((TextBox)sender).SelectAll();\n        }\n\n        #endregion\n\n        private void ObfsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)\n        {\n            try\n            {\n                if (ObfsComboBox.SelectedItem == null)\n                {\n                    return;\n                }\n                var obfs = (Obfs.ObfsBase)Obfs.ObfsFactory.GetObfs(ObfsComboBox.SelectedItem.ToString());\n                var properties = obfs.GetObfs()[$@\"{ObfsComboBox.SelectedItem}\"];\n                ObfsParamTextBox.IsEnabled = properties[2] > 0;\n            }\n            catch\n            {\n                ObfsParamTextBox.IsEnabled = true;\n            }\n        }\n\n        private bool SaveConfig()\n        {\n            string oldServerId = null;\n            if (_modifiedConfiguration.Index >= 0 && _modifiedConfiguration.Index < _modifiedConfiguration.Configs.Count)\n            {\n                oldServerId = _modifiedConfiguration.Configs[_modifiedConfiguration.Index].Id;\n            }\n            _modifiedConfiguration.Configs.Clear();\n            _modifiedConfiguration.Configs.AddRange(ServerConfigViewModel.ServerTreeViewModelToList(ServerConfigViewModel.ServersTreeViewCollection));\n            if (oldServerId != null)\n            {\n                var currentIndex = _modifiedConfiguration.Configs.FindIndex(server => server.Id == oldServerId);\n                if (currentIndex != -1)\n                {\n                    _modifiedConfiguration.Index = currentIndex;\n                }\n            }\n\n            if (_modifiedConfiguration.Configs.Count == 0)\n            {\n                MessageBox.Show(this.GetWindowStringValue(@\"NoServer\"));\n                return false;\n            }\n\n            _controller.SaveServersConfig(_modifiedConfiguration, true);\n            return true;\n        }\n\n        private void OkButton_Click(object sender, RoutedEventArgs e)\n        {\n            if (ApplyButton.IsEnabled)\n            {\n                if (SaveConfig())\n                {\n                    Close();\n                }\n            }\n            else\n            {\n                Close();\n            }\n        }\n\n        private void CancelButton_Click(object sender, RoutedEventArgs e)\n        {\n            Close();\n        }\n\n        private void ApplyButton_Click(object sender, RoutedEventArgs e)\n        {\n            if (SaveConfig())\n            {\n                ApplyButton.IsEnabled = false;\n            }\n        }\n\n        #region QrCode\n\n        private void GenQr(string text)\n        {\n            if (PictureQrCode.Visibility != Visibility.Visible)\n            {\n                return;\n            }\n\n            try\n            {\n                var h = Convert.ToInt32(MainGrid.ActualHeight);\n                var w = Convert.ToInt32(MainGrid.ColumnDefinitions[2].ActualWidth - PictureQrCode.Margin.Left -\n                                        PictureQrCode.Margin.Right);\n                if (h <= 0 || w <= 0)\n                {\n                    PictureQrCode.Source = null;\n                }\n                else\n                {\n                    PictureQrCode.Source = text != string.Empty\n                            ? QrCodeUtils.GenQrCode(text, w, h)\n                            : QrCodeUtils.GenQrCode2(text, Math.Min(w, h));\n                }\n            }\n            catch\n            {\n                PictureQrCode.Source = null;\n            }\n        }\n        private double _oldWidth = 400.0;\n        private void ShowQrCodeButton_OnClick(object sender, RoutedEventArgs e)\n        {\n            if (PictureQrCode.Visibility != Visibility.Visible)\n            {\n                PictureQrCode.Visibility = Splitter2.Visibility = Visibility.Visible;\n                MainGrid.ColumnDefinitions[2].Width = new GridLength(_oldWidth, GridUnitType.Pixel);\n                Width += _oldWidth;\n                ShowQrCodeButton.Content = @\"<<\";\n            }\n            else\n            {\n                PictureQrCode.Visibility = Splitter2.Visibility = Visibility.Collapsed;\n                _oldWidth = MainGrid.ColumnDefinitions[2].ActualWidth;\n                Width -= _oldWidth;\n                MainGrid.ColumnDefinitions[2].Width = new GridLength(0);\n                ShowQrCodeButton.Content = @\">>\";\n            }\n        }\n\n        #endregion\n\n        private void ConfigWindow_OnActivated(object sender, EventArgs e)\n        {\n            Topmost = false;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ServerLogWindow.xaml",
    "content": "<Window x:Class=\"Shadowsocks.View.ServerLogWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:syncfusion=\"http://schemas.syncfusion.com/wpf\"\n        xmlns:model=\"clr-namespace:Shadowsocks.Model\"\n        xmlns:system=\"clr-namespace:System;assembly=mscorlib\"\n        xmlns:valueConverter=\"clr-namespace:Shadowsocks.View.ValueConverter\"\n        x:Name=\"Slw\" >\n\n    <Window.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"../I18N/ServerLogWindow.en-US.xaml\" />\n            </ResourceDictionary.MergedDictionaries>\n\n            <system:String x:Key=\"IndexMappingName\">Index</system:String>\n            <system:String x:Key=\"GroupMappingName\">GroupName</system:String>\n            <system:String x:Key=\"ServerMappingName\">FriendlyName</system:String>\n            <system:String x:Key=\"ConnectingMappingName\">SpeedLog.Connecting</system:String>\n            <system:String x:Key=\"AvgConnectTimeMappingName\">SpeedLog.AvgConnectTimeText</system:String>\n            <system:String x:Key=\"AvgDownloadBytesMappingName\">SpeedLog.AvgDownloadBytesText</system:String>\n            <system:String x:Key=\"MaxDownSpeedMappingName\">SpeedLog.MaxDownSpeedText</system:String>\n            <system:String x:Key=\"AvgUploadBytesMappingName\">SpeedLog.AvgUploadBytesText</system:String>\n            <system:String x:Key=\"MaxUpSpeedMappingName\">SpeedLog.MaxUpSpeedText</system:String>\n            <system:String x:Key=\"TotalDownloadBytesMappingName\">SpeedLog.TotalDownloadBytesText</system:String>\n            <system:String x:Key=\"TotalUploadBytesMappingName\">SpeedLog.TotalUploadBytesText</system:String>\n            <system:String x:Key=\"TotalDownloadRawBytesMappingName\">SpeedLog.TotalDownloadRawBytesText</system:String>\n            <system:String x:Key=\"ConnectErrorMappingName\">SpeedLog.ConnectError</system:String>\n            <system:String x:Key=\"ErrorTimeoutTimesMappingName\">SpeedLog.ErrorTimeoutTimes</system:String>\n            <system:String x:Key=\"ErrorEmptyTimesMappingName\">SpeedLog.ErrorEmptyTimes</system:String>\n            <system:String x:Key=\"ErrorContinuousTimesMappingName\">SpeedLog.ErrorContinuousTimes</system:String>\n            <system:String x:Key=\"ErrorPercentMappingName\">SpeedLog.ErrorPercent</system:String>\n\n            <valueConverter:SpeedToBrushConverter x:Key=\"SpeedToBrushConverter\" />\n            <valueConverter:ConnectNumberToBrushConverter x:Key=\"ConnectNumberToBrushConverter\" />\n            <valueConverter:LatencyToBrushConverter x:Key=\"LatencyToBrushConverter\" />\n            <valueConverter:ConnectErrorToBrushConverter x:Key=\"ConnectErrorToBrushConverter\" />\n            <valueConverter:ConnectEmptyToBrushConverter x:Key=\"ConnectEmptyToBrushConverter\" />\n            <valueConverter:ErrorPercentToBrushConverter x:Key=\"ErrorPercentToBrushConverter\" />\n            <valueConverter:BooleanToEnabledConverter x:Key=\"BooleanToEnabledConverter\" />\n            <valueConverter:TotalDownloadBackgroundBrushConvert x:Key=\"TotalDownloadBackgroundBrushConvert\" />\n            <valueConverter:TotalUploadBackgroundBrushConvert x:Key=\"TotalUploadBackgroundBrushConvert\" />\n            <valueConverter:TotalDownloadRawBackgroundBrushConvert x:Key=\"TotalDownloadRawBackgroundBrushConvert\" />\n            <SolidColorBrush x:Key=\"BorderBrush\">#E5E5E5</SolidColorBrush>\n            <Style TargetType=\"syncfusion:GridHeaderCellControl\">\n                <Setter Property=\"Foreground\" Value=\"Black\" />\n                <Setter Property=\"BorderBrush\" Value=\"#808080\" />\n                <Setter Property=\"Background\" Value=\"#CCCCCC\" />\n            </Style>\n            <Style TargetType=\"syncfusion:HeaderRowControl\">\n            </Style>\n            <Style TargetType=\"syncfusion:GridRowHeaderCell\">\n                <Setter Property=\"Background\" Value=\"{Binding Path=Enable,Converter={StaticResource BooleanToEnabledConverter},Mode=OneWay}\" />\n                <Setter Property=\"BorderBrush\" Value=\"{StaticResource BorderBrush}\" />\n                <Setter Property=\"BorderThickness\" Value=\"0,0,1,1\" />\n            </Style>\n            <Style TargetType=\"syncfusion:VirtualizingCellsControl\" x:Key=\"AlternatingRowStyle\">\n                <Setter Property=\"Background\" Value=\"#FAFAFA\" />\n            </Style>\n            <Style TargetType=\"syncfusion:GridCell\">\n                <Setter Property=\"BorderBrush\" Value=\"{StaticResource BorderBrush}\" />\n            </Style>\n            <Style TargetType=\"syncfusion:GridCell\" x:Key=\"BaseGridCell\">\n                <Setter Property=\"BorderBrush\" Value=\"{StaticResource BorderBrush}\" />\n            </Style>\n        </ResourceDictionary>\n    </Window.Resources>\n    <Grid>\n        <DockPanel>\n            <Menu DockPanel.Dock=\"Top\" Background=\"White\">\n                <MenuItem Header=\"{DynamicResource Control}\" >\n                    <MenuItem Header=\"{DynamicResource DisconnectDirect}\" Click=\"DisconnectDirectMenuItem_OnClick\"/>\n                    <MenuItem Header=\"{DynamicResource DisconnectAll}\" Click=\"DisconnectAllMenuItem_OnClick\"/>\n                    <Separator />\n                    <MenuItem Header=\"{DynamicResource ClearMaxSpeed}\" Click=\"ClearMaxMenuItem_OnClick\"/>\n                    <MenuItem Header=\"{DynamicResource Clear}\" Click=\"ClearAllMenuItem_OnClick\"/>\n                    <Separator />\n                    <MenuItem Header=\"{DynamicResource ClearSelectedTotal}\" Click=\"ClearSelectedTotalMenuItem_OnClick\"/>\n                    <MenuItem Header=\"{DynamicResource ClearTotal}\" Click=\"ClearTotalMenuItem_OnClick\"/>\n                </MenuItem>\n                <MenuItem Header=\"{DynamicResource PortOut}\">\n                    <MenuItem Header=\"{DynamicResource CopyCurrentLink}\" Click=\"CopyCurrentLinkMenuItem_OnClick\"/>\n                    <MenuItem Header=\"{DynamicResource CopyCurrentGroupLinks}\" Click=\"CopyCurrentGroupLinksMenuItem_OnClick\"/>\n                    <MenuItem Header=\"{DynamicResource CopyAllEnableLinks}\" Click=\"CopyAllEnableLinksMenuItem_OnClick\"/>\n                    <MenuItem Header=\"{DynamicResource CopyAllLinks}\" Click=\"CopyAllLinksMenuItem_OnClick\"/>\n                </MenuItem>\n                <MenuItem Header=\"{DynamicResource Window}\">\n                    <MenuItem Header=\"{DynamicResource AutoSize}\" Click=\"AutoSizeMenuItem_OnClick\"/>\n                    <MenuItem Header=\"{DynamicResource AlwaysOnTop}\" IsChecked=\"{Binding Topmost,ElementName=Slw}\" Click=\"AlwaysTopMenuItem_OnClick\"/>\n                </MenuItem>\n            </Menu>\n            <syncfusion:SfDataGrid x:Name=\"ServerDataGrid\"\n                                   AllowResizingHiddenColumns=\"False\"\n                                   DataContext=\"{Binding ServerLogViewModel, ElementName=Slw}\"\n                                   ItemsSource=\"{Binding ServersCollection}\"\n                                   SourceType=\"{x:Type model:Server}\"\n                                   AutoGenerateColumns=\"False\"\n                                   ColumnSizer=\"Auto\"\n                                   AlternatingRowStyle=\"{StaticResource AlternatingRowStyle}\"\n                                   RowSelectionBrush=\"Transparent\"\n                                   BorderThickness=\"0,1,0,0\"\n\n                                   SelectionUnit=\"Cell\" SelectionMode=\"Single\"\n                                   AllowEditing=\"False\" AddNewRowPosition=\"None\"\n                                   AllowResizingColumns=\"True\"\n                                   AllowDeleting=\"False\"\n                                   AllowDraggingRows=\"False\" AllowDraggingColumns=\"True\" AllowDrop=\"False\"\n                                   AllowGrouping=\"False\" ShowGroupDropArea=\"False\"\n                                   AllowSorting=\"True\" AllowFiltering=\"False\" ShowSortNumbers=\"True\"\n                                   ShowToolTip=\"True\"\n                                   ShowRowHeader=\"True\"\n \n                                   EnableDataVirtualization=\"True\"\n                                   ScrollMode=\"None\" CanMaintainScrollPosition=\"True\" ShowBusyIndicator=\"True\"\n                                   CellTapped=\"ServerDataGrid_OnCellTapped\"\n                                   CellDoubleTapped=\"ServerDataGrid_OnCellDoubleTapped\"\n                                   MouseLeftButtonUp=\"ServerDataGrid_OnMouseLeftButtonUp\"\n                                   >\n                <syncfusion:SfDataGrid.Columns>\n                    <syncfusion:GridNumericColumn MappingName=\"{StaticResource IndexMappingName}\" NumberDecimalDigits=\"0\" TextAlignment=\"Left\" />\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource GroupMappingName}\" AllowFiltering=\"True\" />\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource ServerMappingName}\" AllowFiltering=\"True\" >\n                        <syncfusion:GridTextColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Style.Triggers>\n                                    <DataTrigger Binding=\"{Binding IsSelected,Mode=OneWay}\" Value=\"True\">\n                                        <Setter Property=\"Background\" Value=\"#FF00FFAA\" />\n                                    </DataTrigger>\n                                </Style.Triggers>\n                            </Style>\n                        </syncfusion:GridTextColumn.CellStyle>\n                    </syncfusion:GridTextColumn>\n\n                    <syncfusion:GridNumericColumn MappingName=\"{StaticResource ConnectingMappingName}\" NumberDecimalDigits=\"0\" TextAlignment=\"Left\">\n                        <syncfusion:GridNumericColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                Value=\"{Binding Path=SpeedLog.Connecting,Converter={StaticResource ConnectNumberToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridNumericColumn.CellStyle>\n                    </syncfusion:GridNumericColumn>\n\n                    <syncfusion:GridNumericColumn MappingName=\"{StaticResource AvgConnectTimeMappingName}\" NumberDecimalDigits=\"0\" TextAlignment=\"Left\">\n                        <syncfusion:GridNumericColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                        Value=\"{Binding Path=SpeedLog.AvgConnectTimeText,Converter={StaticResource LatencyToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridNumericColumn.CellStyle>\n                    </syncfusion:GridNumericColumn>\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource AvgDownloadBytesMappingName}\" \n                                               DisplayBinding=\"{Binding SpeedLog.AvgDownloadBytesText,Mode=OneWay}\" \n                                               ValueBinding=\"{Binding SpeedLog.AvgDownloadBytes,Mode=OneWay}\" SortMode=\"Value\">\n                        <syncfusion:GridTextColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                Value=\"{Binding SpeedLog.AvgDownloadBytes,Converter={StaticResource SpeedToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridTextColumn.CellStyle>\n                    </syncfusion:GridTextColumn>\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource MaxDownSpeedMappingName}\"\n                                               DisplayBinding=\"{Binding SpeedLog.MaxDownSpeedText,Mode=OneWay}\"\n                                               ValueBinding=\"{Binding SpeedLog.MaxDownSpeed,Mode=OneWay}\" SortMode=\"Value\">\n                        <syncfusion:GridTextColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\" \n                                Value=\"{Binding SpeedLog.MaxDownSpeed,Converter={StaticResource SpeedToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridTextColumn.CellStyle>\n                    </syncfusion:GridTextColumn>\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource AvgUploadBytesMappingName}\"\n                                               DisplayBinding=\"{Binding SpeedLog.AvgUploadBytesText,Mode=OneWay}\"\n                                               ValueBinding=\"{Binding SpeedLog.AvgUploadBytes,Mode=OneWay}\" SortMode=\"Value\">\n                        <syncfusion:GridTextColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                        Value=\"{Binding SpeedLog.AvgUploadBytes,Converter={StaticResource SpeedToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridTextColumn.CellStyle>\n                    </syncfusion:GridTextColumn>\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource MaxUpSpeedMappingName}\"\n                                               DisplayBinding=\"{Binding SpeedLog.MaxUpSpeedText,Mode=OneWay}\"\n                                               ValueBinding=\"{Binding SpeedLog.MaxUpSpeed,Mode=OneWay}\" SortMode=\"Value\">\n                        <syncfusion:GridTextColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                        Value=\"{Binding SpeedLog.MaxUpSpeed,Converter={StaticResource SpeedToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridTextColumn.CellStyle>\n                    </syncfusion:GridTextColumn>\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource TotalDownloadBytesMappingName}\"\n                                               DisplayBinding=\"{Binding SpeedLog.TotalDownloadBytesText,Mode=OneWay}\"\n                                               ValueBinding=\"{Binding SpeedLog.TotalDownloadBytes,Mode=OneWay}\" SortMode=\"Value\">\n                        <syncfusion:GridTextColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\" Value=\"{Binding ColumnBase.RowIndex,RelativeSource={RelativeSource Self},Converter={StaticResource TotalDownloadBackgroundBrushConvert},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridTextColumn.CellStyle>\n                    </syncfusion:GridTextColumn>\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource TotalUploadBytesMappingName}\"\n                                               DisplayBinding=\"{Binding SpeedLog.TotalUploadBytesText,Mode=OneWay}\"\n                                               ValueBinding=\"{Binding SpeedLog.TotalUploadBytes,Mode=OneWay}\" SortMode=\"Value\">\n                        <syncfusion:GridTextColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\" Value=\"{Binding ColumnBase.RowIndex,RelativeSource={RelativeSource Self},Converter={StaticResource TotalUploadBackgroundBrushConvert},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridTextColumn.CellStyle>\n                    </syncfusion:GridTextColumn>\n\n                    <syncfusion:GridTextColumn MappingName=\"{StaticResource TotalDownloadRawBytesMappingName}\"\n                                               DisplayBinding=\"{Binding SpeedLog.TotalDownloadRawBytesText,Mode=OneWay}\"\n                                               ValueBinding=\"{Binding SpeedLog.TotalDownloadRawBytes,Mode=OneWay}\" SortMode=\"Value\">\n                        <syncfusion:GridTextColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\" Value=\"{Binding ColumnBase.RowIndex,RelativeSource={RelativeSource Self},Converter={StaticResource TotalDownloadRawBackgroundBrushConvert},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridTextColumn.CellStyle>\n                    </syncfusion:GridTextColumn>\n\n                    <syncfusion:GridNumericColumn MappingName=\"{StaticResource ConnectErrorMappingName}\" NumberDecimalDigits=\"0\" TextAlignment=\"Left\">\n                        <syncfusion:GridNumericColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                        Value=\"{Binding SpeedLog.ConnectError,Converter={StaticResource ConnectErrorToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridNumericColumn.CellStyle>\n                    </syncfusion:GridNumericColumn>\n\n                    <syncfusion:GridNumericColumn MappingName=\"{StaticResource ErrorTimeoutTimesMappingName}\" NumberDecimalDigits=\"0\" TextAlignment=\"Left\">\n                        <syncfusion:GridNumericColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                        Value=\"{Binding SpeedLog.ErrorTimeoutTimes,Converter={StaticResource ConnectEmptyToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridNumericColumn.CellStyle>\n                    </syncfusion:GridNumericColumn>\n\n                    <syncfusion:GridNumericColumn MappingName=\"{StaticResource ErrorEmptyTimesMappingName}\" NumberDecimalDigits=\"0\" TextAlignment=\"Left\">\n                        <syncfusion:GridNumericColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                        Value=\"{Binding SpeedLog.ErrorEmptyTimes,Converter={StaticResource ConnectEmptyToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridNumericColumn.CellStyle>\n                    </syncfusion:GridNumericColumn>\n\n                    <syncfusion:GridNumericColumn MappingName=\"{StaticResource ErrorContinuousTimesMappingName}\" NumberDecimalDigits=\"0\" TextAlignment=\"Left\">\n                        <syncfusion:GridNumericColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                        Value=\"{Binding SpeedLog.ErrorContinuousTimes,Converter={StaticResource ConnectEmptyToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridNumericColumn.CellStyle>\n                    </syncfusion:GridNumericColumn>\n\n                    <syncfusion:GridPercentColumn MappingName=\"{StaticResource ErrorPercentMappingName}\" NullValue=\"0\" AllowNullValue=\"True\" \n                                                  PercentDecimalDigits=\"0\" TextAlignment=\"Left\">\n                        <syncfusion:GridPercentColumn.CellStyle>\n                            <Style TargetType=\"syncfusion:GridCell\" BasedOn=\"{StaticResource BaseGridCell}\">\n                                <Setter Property=\"Background\"\n                                        Value=\"{Binding SpeedLog.ErrorPercent,Converter={StaticResource ErrorPercentToBrushConverter},Mode=OneWay}\" />\n                            </Style>\n                        </syncfusion:GridPercentColumn.CellStyle>\n                    </syncfusion:GridPercentColumn>\n\n                    <syncfusion:GridCheckBoxColumn MappingName=\"Enable\" IsHidden=\"True\" />\n\n                </syncfusion:SfDataGrid.Columns>\n            </syncfusion:SfDataGrid>\n\n        </DockPanel>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "shadowsocks-csharp/View/ServerLogWindow.xaml.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Controller.HttpRequest;\nusing Shadowsocks.Model;\nusing Shadowsocks.Util;\nusing Shadowsocks.View.Controls;\nusing Shadowsocks.ViewModel;\nusing Syncfusion.Data;\nusing Syncfusion.UI.Xaml.Grid;\nusing Syncfusion.UI.Xaml.Grid.Helpers;\nusing Syncfusion.UI.Xaml.ScrollAxis;\nusing System;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Input;\nusing System.Windows.Threading;\n\nnamespace Shadowsocks.View\n{\n    public partial class ServerLogWindow\n    {\n        public ServerLogWindow(MainController controller, WindowStatus status)\n        {\n            InitializeComponent();\n            I18NUtil.SetLanguage(Resources, @\"ServerLogWindow\");\n            LoadLanguage();\n\n            ServerDataGrid.GridColumnSizer = new GridColumnSizerExt(ServerDataGrid);\n\n            _controller = controller;\n            Closed += (o, e) => { _controller.ConfigChanged -= controller_ConfigChanged; };\n            _controller.ConfigChanged += controller_ConfigChanged;\n            LoadConfig(true);\n\n            ServerDataGrid.GridColumnSizer.SortIconWidth = 0;\n            if (status == null)\n            {\n                SizeToContent = SizeToContent.Width;\n                Height = 600;\n                WindowStartupLocation = WindowStartupLocation.CenterScreen;\n                ServerDataGrid.ShowBusyIndicator = false;\n            }\n            else\n            {\n                ServerDataGrid.ShowBusyIndicator = true;\n                SizeToContent = SizeToContent.Manual;\n                status.SetStatus(this);\n            }\n        }\n\n        private void LoadLanguage()\n        {\n            ServerDataGrid.Columns[Resources[@\"IndexMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Index\");\n            ServerDataGrid.Columns[Resources[@\"GroupMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Group\");\n            ServerDataGrid.Columns[Resources[@\"ServerMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Server\");\n            ServerDataGrid.Columns[Resources[@\"ConnectingMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Connecting\");\n            ServerDataGrid.Columns[Resources[@\"AvgConnectTimeMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Latency\");\n            ServerDataGrid.Columns[Resources[@\"AvgDownloadBytesMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"AvgDSpeed\");\n            ServerDataGrid.Columns[Resources[@\"MaxDownSpeedMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"MaxDSpeed\");\n            ServerDataGrid.Columns[Resources[@\"AvgUploadBytesMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"AvgUpSpeed\");\n            ServerDataGrid.Columns[Resources[@\"MaxUpSpeedMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"MaxUpSpeed\");\n            ServerDataGrid.Columns[Resources[@\"TotalDownloadBytesMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Dload\");\n            ServerDataGrid.Columns[Resources[@\"TotalUploadBytesMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Upload\");\n            ServerDataGrid.Columns[Resources[@\"TotalDownloadRawBytesMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"DloadRaw\");\n            ServerDataGrid.Columns[Resources[@\"ConnectErrorMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Error\");\n            ServerDataGrid.Columns[Resources[@\"ErrorTimeoutTimesMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Timeout\");\n            ServerDataGrid.Columns[Resources[@\"ErrorEmptyTimesMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"EmptyResponse\");\n            ServerDataGrid.Columns[Resources[@\"ErrorContinuousTimesMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"Continuous\");\n            ServerDataGrid.Columns[Resources[@\"ErrorPercentMappingName\"].ToString()].HeaderText = this.GetWindowStringValue(@\"ErrorPercent\");\n        }\n\n        private void LoadConfig(bool isFirstLoad)\n        {\n            UpdateTitle();\n            ServerDataGrid.View?.BeginInit();\n            ServerLogViewModel.ReadConfig();\n            ServerDataGrid.View?.EndInit();\n\n            Dispatcher.CurrentDispatcher.InvokeAsync(() =>\n            {\n                if (isFirstLoad && ServerLogViewModel.SelectedServer != null)\n                {\n                    ServerDataGrid.ScrollInView(new RowColumnIndex(ServerLogViewModel.SelectedServer.Index, 2));\n                }\n            }, DispatcherPriority.Input);\n        }\n\n        private void controller_ConfigChanged(object sender, EventArgs e)\n        {\n            LoadConfig(false);\n        }\n\n        private readonly MainController _controller;\n        public ServerLogViewModel ServerLogViewModel { get; set; } = new();\n\n        private void UpdateTitle()\n        {\n            Title = $@\"{this.GetWindowStringValue(@\"Title\")}({(Global.GuiConfig.ShareOverLan ? this.GetWindowStringValue(@\"Any\") : this.GetWindowStringValue(@\"Local\"))}:{Global.GuiConfig.LocalPort} {this.GetWindowStringValue(@\"Version\")}{Controller.HttpRequest.UpdateChecker.FullVersion})\";\n        }\n\n        private void AlwaysTopMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            Topmost = !Topmost;\n        }\n\n        private void AutoSizeMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            //Refreshing auto size calculation\n            ServerDataGrid.GridColumnSizer.ResetAutoCalculationforAllColumns();\n            ServerDataGrid.GridColumnSizer.Refresh();\n            foreach (var column in ServerDataGrid.Columns.Where(column => !double.IsNaN(column.Width)))\n            {\n                column.Width = double.NaN;\n            }\n            ServerDataGrid.GridColumnSizer.Refresh();\n            SizeToContent = SizeToContent.Width;\n        }\n\n        private void DisconnectDirectMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            Server.ForwardServer.Connections.CloseAll();\n        }\n\n        private void DisconnectAllMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            _controller.DisconnectAllConnections();\n            Server.ForwardServer.Connections.CloseAll();\n        }\n\n        private void ClearMaxMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            var config = Global.GuiConfig;\n            foreach (var server in config.Configs)\n            {\n                server.SpeedLog.ClearMaxSpeed();\n            }\n        }\n\n        private void ClearAllMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            var config = Global.GuiConfig;\n            foreach (var server in config.Configs)\n            {\n                server.SpeedLog.Clear();\n            }\n        }\n\n        private void ClearSelectedTotalMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            var config = Global.GuiConfig;\n            if (config.Index >= 0 && config.Index < config.Configs.Count)\n            {\n                try\n                {\n                    _controller.ClearTransferTotal(config.Configs[config.Index].Id);\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n\n        private void ClearTotalMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            var config = Global.GuiConfig;\n            foreach (var server in config.Configs)\n            {\n                _controller.ClearTransferTotal(server.Id);\n            }\n        }\n\n        private void CopyCurrentLinkMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            var config = Global.GuiConfig;\n            if (config.Index >= 0 && config.Index < config.Configs.Count)\n            {\n                var link = config.Configs[config.Index].SsrLink;\n                Clipboard.SetDataObject(link);\n            }\n        }\n\n        private void CopyCurrentGroupLinksMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            var config = Global.GuiConfig;\n            if (config.Index >= 0 && config.Index < config.Configs.Count)\n            {\n                var group = config.Configs[config.Index].Group;\n                var link = config.Configs.Where(t => t.Group == group).Aggregate(string.Empty, (current, t) => current + $@\"{t.SsrLink}{Environment.NewLine}\");\n                Clipboard.SetDataObject(link);\n            }\n        }\n\n        private void CopyAllEnableLinksMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            var config = Global.GuiConfig;\n            var link = config.Configs.Where(t => t.Enable).Aggregate(string.Empty, (current, t) => current + $@\"{t.SsrLink}{Environment.NewLine}\");\n            Clipboard.SetDataObject(link);\n        }\n\n        private void CopyAllLinksMenuItem_OnClick(object sender, RoutedEventArgs e)\n        {\n            var config = Global.GuiConfig;\n            var link = config.Configs.Aggregate(string.Empty, (current, t) => current + $@\"{t.SsrLink}{Environment.NewLine}\");\n            Clipboard.SetDataObject(link);\n        }\n\n        private void ServerDataGrid_OnCellTapped(object sender, GridCellTappedEventArgs e)\n        {\n            if (e.ChangedButton != MouseButton.Left)\n            {\n                return;\n            }\n\n            if (ServerDataGrid.CurrentColumn != null && ServerDataGrid.SelectedItem is Server server)\n            {\n                var index = server.Index - 1;\n                var mappingName = ServerDataGrid.CurrentColumn.MappingName;\n                if (mappingName == Resources[@\"ServerMappingName\"].ToString())\n                {\n                    _controller.DisconnectAllConnections(true);\n                    _controller.SelectServerIndex(index);\n                }\n                else if (mappingName == Resources[@\"GroupMappingName\"].ToString())\n                {\n                    var group = server.Group;\n                    if (!string.IsNullOrEmpty(group))\n                    {\n                        var enable = !server.Enable;\n                        foreach (var sameGroupServer in ServerLogViewModel.ServersCollection)\n                        {\n                            if (sameGroupServer.Group == group)\n                            {\n                                sameGroupServer.Enable = enable;\n                            }\n                        }\n                        Global.SaveConfig();\n                    }\n                }\n                else\n                {\n                    return;\n                }\n                ServerDataGrid.ClearSelections(false);\n                ServerDataGrid.SelectCell(server, ServerDataGrid.Columns[0]);\n            }\n        }\n\n        private void ServerDataGrid_OnCellDoubleTapped(object sender, GridCellDoubleTappedEventArgs e)\n        {\n            if (e.ChangedButton != MouseButton.Left)\n            {\n                return;\n            }\n\n            if (ServerDataGrid.CurrentColumn != null && ServerDataGrid.SelectedItem is Server server)\n            {\n                var index = server.Index - 1;\n                var mappingName = ServerDataGrid.CurrentColumn.MappingName;\n                if (mappingName == Resources[@\"IndexMappingName\"].ToString())\n                {\n                    _controller.ShowConfigForm(index);\n                }\n                else if (mappingName == Resources[@\"ConnectingMappingName\"].ToString())\n                {\n                    server.Connections.CloseAll();\n                }\n                else if (mappingName == Resources[@\"MaxDownSpeedMappingName\"].ToString()\n                        || mappingName == Resources[@\"MaxUpSpeedMappingName\"].ToString())\n                {\n                    server.SpeedLog.ClearMaxSpeed();\n                }\n                else if (mappingName == Resources[@\"TotalDownloadBytesMappingName\"].ToString()\n                         || mappingName == Resources[@\"TotalUploadBytesMappingName\"].ToString())\n                {\n                    server.SpeedLog.ClearTrans();\n                }\n                else if (mappingName == Resources[@\"TotalDownloadRawBytesMappingName\"].ToString())\n                {\n                    server.SpeedLog.Clear();\n                    server.Enable = true;\n                }\n                else if (mappingName == Resources[@\"ConnectErrorMappingName\"].ToString()\n                         || mappingName == Resources[@\"ErrorTimeoutTimesMappingName\"].ToString()\n                         || mappingName == Resources[@\"ErrorEmptyTimesMappingName\"].ToString()\n                         || mappingName == Resources[@\"ErrorContinuousTimesMappingName\"].ToString()\n                         || mappingName == Resources[@\"ErrorPercentMappingName\"].ToString())\n                {\n                    server.SpeedLog.ClearError();\n                    server.Enable = true;\n                }\n                else\n                {\n                    ServerDataGrid.ClearSelections(false);\n                    ServerDataGrid.SelectCell(server, ServerDataGrid.Columns[0]);\n                }\n            }\n        }\n\n        private void ServerDataGrid_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)\n        {\n            var visualContainer = ServerDataGrid.GetVisualContainer();\n            var rowColumnIndex = visualContainer.PointToCellRowColumnIndex(e.GetPosition(visualContainer));\n            if (rowColumnIndex.IsEmpty)\n            {\n                return;\n            }\n\n            var columnIndex = ServerDataGrid.ResolveToGridVisibleColumnIndex(rowColumnIndex.ColumnIndex);\n            if (columnIndex != -1)\n            {\n                return;\n            }\n\n            var recordIndex = ServerDataGrid.ResolveToRecordIndex(rowColumnIndex.RowIndex);\n            if (recordIndex == -1)\n            {\n                const string columnName = @\"Enable\";\n                var sortColumnDescription = ServerDataGrid.SortColumnDescriptions.FirstOrDefault(col => col.ColumnName == columnName);\n                if (sortColumnDescription != null)\n                {\n                    sortColumnDescription.SortDirection = sortColumnDescription.SortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;\n                    ServerDataGrid.SortColumnDescriptions.Remove(sortColumnDescription);\n                }\n                else\n                {\n                    sortColumnDescription = new SortColumnDescription\n                    {\n                        ColumnName = columnName,\n                        SortDirection = ListSortDirection.Ascending\n                    };\n                }\n                if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))\n                {\n                }\n                else\n                {\n                    ServerDataGrid.SortColumnDescriptions.Clear();\n                }\n                ServerDataGrid.SortColumnDescriptions.Add(sortColumnDescription);\n            }\n            else\n            {\n                var entry = ServerDataGrid.View.GroupDescriptions.Count == 0\n                        ? ServerDataGrid.View.Records[recordIndex]\n                        : ServerDataGrid.View.TopLevelGroup.DisplayElements[recordIndex];\n                if (entry.IsRecords && entry is RecordEntry recordEntry && recordEntry.Data is Server server)\n                {\n                    server.Enable = !server.Enable;\n                    Global.SaveConfig();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/SettingsWindow.xaml",
    "content": "﻿<Window x:Class=\"Shadowsocks.View.SettingsWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:controls=\"clr-namespace:Shadowsocks.View.Controls\"\n        xmlns:system=\"clr-namespace:System;assembly=System.Runtime\"\n        xmlns:enums=\"clr-namespace:Shadowsocks.Enums\"\n        xmlns:valueConverter=\"clr-namespace:Shadowsocks.View.ValueConverter\"\n        Title=\"SettingsWindow\"\n        Height=\"500\" Width=\"600\" WindowStartupLocation=\"CenterScreen\" ResizeMode=\"NoResize\"\n        DataContext=\"{Binding SettingViewModel,RelativeSource={RelativeSource Self}}\">\n\n    <Window.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"../I18N/SettingsWindow.en-US.xaml\" />\n            </ResourceDictionary.MergedDictionaries>\n            <ObjectDataProvider x:Key=\"ProxyTypeEnum\" MethodName=\"GetValues\"\n                                ObjectType=\"{x:Type system:Enum}\">\n                <ObjectDataProvider.MethodParameters>\n                    <x:Type TypeName=\"enums:ProxyType\" />\n                </ObjectDataProvider.MethodParameters>\n            </ObjectDataProvider>\n            <valueConverter:ProxyTypeEnumConverter x:Key=\"ProxyTypeEnumConverter\" />\n            <ObjectDataProvider x:Key=\"BalanceTypeEnum\" MethodName=\"GetValues\"\n                                ObjectType=\"{x:Type system:Enum}\">\n                <ObjectDataProvider.MethodParameters>\n                    <x:Type TypeName=\"enums:BalanceType\" />\n                </ObjectDataProvider.MethodParameters>\n            </ObjectDataProvider>\n            <valueConverter:BalanceTypeEnumConverter x:Key=\"BalanceTypeEnumConverter\" />\n        </ResourceDictionary>\n    </Window.Resources>\n\n    <Grid>\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"282*\" />\n            <RowDefinition Height=\"163*\" />\n            <RowDefinition Height=\"Auto\" />\n        </Grid.RowDefinitions>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition />\n            <ColumnDefinition />\n        </Grid.ColumnDefinitions>\n\n        <GroupBox Header=\"{DynamicResource RemoteProxy}\" Grid.Row=\"0\" Grid.Column=\"0\" Margin=\"10,0,0,0\">\n            <Grid>\n                <Grid.RowDefinitions>\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                </Grid.RowDefinitions>\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition />\n                </Grid.ColumnDefinitions>\n                <CheckBox Grid.Row=\"0\" Grid.Column=\"0\" Content=\"{DynamicResource ProxyOn}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,5\"\n                IsChecked=\"{Binding ModifiedConfiguration.ProxyEnable,Mode=TwoWay}\"/>\n                <CheckBox Grid.Row=\"0\" Grid.Column=\"1\" Content=\"{DynamicResource Pac}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,5\"\n                IsChecked=\"{Binding ModifiedConfiguration.PacDirectGoProxy,Mode=TwoWay}\"/>\n                <ComboBox Grid.Row=\"1\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\"\n                ItemsSource=\"{Binding Source={StaticResource ProxyTypeEnum}}\" SelectedItem=\"{Binding ModifiedConfiguration.ProxyType,Mode=TwoWay}\">\n                    <ComboBox.ItemTemplate>\n                        <DataTemplate>\n                            <TextBlock Text=\"{Binding Converter={StaticResource ProxyTypeEnumConverter}}\" />\n                        </DataTemplate>\n                    </ComboBox.ItemTemplate>\n                </ComboBox>\n                <Label Grid.Row=\"2\" Grid.Column=\"0\" Content=\"{DynamicResource ServerIp}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <Label Grid.Row=\"3\" Grid.Column=\"0\" Content=\"{DynamicResource ServerPort}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <Label Grid.Row=\"4\" Grid.Column=\"0\" Content=\"{DynamicResource Username}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <Label Grid.Row=\"5\" Grid.Column=\"0\" Content=\"{DynamicResource Password}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <Label Grid.Row=\"6\" Grid.Column=\"0\" Content=\"{DynamicResource UserAgent}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <TextBox Grid.Row=\"2\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" VerticalContentAlignment=\"Center\" \n                Text=\"{Binding ModifiedConfiguration.ProxyHost,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n                <controls:NumberUpDown Grid.Row=\"3\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" MinNum=\"1\" MaxNum=\"65535\" \n                Value=\"{Binding ModifiedConfiguration.ProxyPort,Mode=TwoWay}\"/>\n                <TextBox Grid.Row=\"4\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" VerticalContentAlignment=\"Center\" \n                Text=\"{Binding ModifiedConfiguration.ProxyAuthUser,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n                <controls:BindablePasswordBox Grid.Row=\"5\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" Password=\"{Binding ModifiedConfiguration.ProxyAuthPass}\"/>\n                <TextBox Grid.Row=\"6\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" VerticalContentAlignment=\"Center\" \n                Text=\"{Binding ModifiedConfiguration.ProxyUserAgent,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n            </Grid>\n        </GroupBox>\n        <GroupBox Header=\"{DynamicResource LocalProxy}\" Grid.Row=\"1\" Grid.Column=\"0\" Margin=\"10,0,0,40\" Grid.RowSpan=\"2\">\n            <Grid>\n                <Grid.RowDefinitions>\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                </Grid.RowDefinitions>\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition />\n                </Grid.ColumnDefinitions>\n                <CheckBox Grid.Row=\"0\" Grid.Column=\"1\" Content=\"{DynamicResource AllowLan}\" VerticalAlignment=\"Center\"\n                IsChecked=\"{Binding ModifiedConfiguration.ShareOverLan,Mode=TwoWay}\"/>\n\n                <Label Grid.Row=\"1\" Grid.Column=\"0\" Content=\"{DynamicResource LocalPort}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,10\" />\n                <Label Grid.Row=\"2\" Grid.Column=\"0\" Content=\"{DynamicResource Username}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,10\" />\n                <Label Grid.Row=\"3\" Grid.Column=\"0\" Content=\"{DynamicResource Password}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,10\" />\n\n                <controls:NumberUpDown Grid.Row=\"1\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" MinNum=\"1\" MaxNum=\"65535\" \n                Value=\"{Binding ModifiedConfiguration.LocalPort,Mode=TwoWay}\"/>\n                <TextBox Grid.Row=\"2\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" VerticalContentAlignment=\"Center\" \n                Text=\"{Binding ModifiedConfiguration.AuthUser,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n                <controls:BindablePasswordBox Grid.Row=\"3\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\"\n                Password=\"{Binding ModifiedConfiguration.AuthPass,Mode=TwoWay}\" />\n            </Grid>\n        </GroupBox>\n        <GroupBox Header=\"{DynamicResource Misc}\" Grid.Row=\"0\" Grid.Column=\"1\" Margin=\"10,0,10,0\">\n            <Grid>\n                <Grid.RowDefinitions>\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                </Grid.RowDefinitions>\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\" />\n                    <ColumnDefinition />\n                </Grid.ColumnDefinitions>\n                <Label Grid.Row=\"3\" Grid.Column=\"0\" Content=\"{DynamicResource Balance}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <Label Grid.Row=\"6\" Grid.Column=\"0\" Content=\"{DynamicResource Logging}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <Label Grid.Row=\"7\" Grid.Column=\"0\" Content=\"{DynamicResource Language}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <CheckBox x:Name=\"AutoStartupCheckBox\" Grid.Row=\"0\" Grid.Column=\"1\" Content=\"{DynamicResource StartOnBoot}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\"\n                Checked=\"AutoStartupCheckBox_CheckedChanged\" Unchecked=\"AutoStartupCheckBox_CheckedChanged\"/>\n                <CheckBox Grid.Row=\"1\" Grid.Column=\"1\" Content=\"{DynamicResource SwitchAutoCloseTcpLinks}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" \n                IsChecked=\"{Binding ModifiedConfiguration.CheckSwitchAutoCloseAll,Mode=TwoWay}\"/>\n                <CheckBox Grid.Row=\"2\" Grid.Column=\"1\" Content=\"{DynamicResource LoadBalance}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" \n                IsChecked=\"{Binding ModifiedConfiguration.Random,Mode=TwoWay}\"/>\n                <ComboBox Grid.Row=\"3\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\"\n                          ItemsSource=\"{Binding Source={StaticResource BalanceTypeEnum}}\"\n                          SelectedItem=\"{Binding ModifiedConfiguration.BalanceType,Mode=TwoWay}\">\n                    <ComboBox.ItemTemplate>\n                        <DataTemplate>\n                            <TextBlock Text=\"{Binding Converter={StaticResource BalanceTypeEnumConverter}}\" />\n                        </DataTemplate>\n                    </ComboBox.ItemTemplate>\n                </ComboBox>\n                <CheckBox Grid.Row=\"4\" Grid.Column=\"1\" Content=\"{DynamicResource BalanceInGroup}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" \n                IsChecked=\"{Binding ModifiedConfiguration.RandomInGroup,Mode=TwoWay}\"/>\n                <CheckBox Grid.Row=\"5\" Grid.Column=\"1\" Content=\"{DynamicResource AutoBan}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" \n                IsChecked=\"{Binding ModifiedConfiguration.AutoBan,Mode=TwoWay}\"/>\n                <CheckBox Grid.Row=\"6\" Grid.Column=\"1\" Content=\"{DynamicResource EnableLog}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" \n                IsChecked=\"{Binding ModifiedConfiguration.LogEnable,Mode=TwoWay}\"/>\n                <ComboBox Grid.Row=\"7\" Grid.Column=\"1\" Text=\"{Binding ModifiedConfiguration.LangName}\" Height=\"23.24\">\n                    <ComboBoxItem Content=\"en-US\" />\n                    <ComboBoxItem Content=\"zh-CN\" />\n                    <ComboBoxItem Content=\"zh-TW\" />\n                </ComboBox>\n            </Grid>\n        </GroupBox>\n        <GroupBox Header=\"{DynamicResource Misc}\" Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"10,0,10,40\" Grid.RowSpan=\"2\">\n            <Grid >\n                <Grid.RowDefinitions>\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                </Grid.RowDefinitions>\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\" />\n                    <ColumnDefinition />\n                </Grid.ColumnDefinitions>\n                <Button Grid.Row=\"0\" Grid.Column=\"1\" Content=\"{DynamicResource SetDefault}\" Click=\"DefaultButton_Click\" Height=\"23.24\"/>\n                <Label Grid.Row=\"1\" Grid.Column=\"0\" Content=\"{DynamicResource ReconnectTimes}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <Label Grid.Row=\"2\" Grid.Column=\"0\" Content=\"{DynamicResource ConnectTimeout}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n                <Label Grid.Row=\"3\" Grid.Column=\"0\" Content=\"{DynamicResource Ttl}\" VerticalAlignment=\"Center\" Margin=\"0,0,10,0\" />\n\n                <controls:NumberUpDown Grid.Row=\"1\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" MinNum=\"0\" MaxNum=\"20\" \n                Value=\"{Binding ModifiedConfiguration.ReconnectTimes,Mode=TwoWay}\"/>\n                <controls:NumberUpDown Grid.Row=\"2\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" MinNum=\"0\" MaxNum=\"60\" \n                Value=\"{Binding ModifiedConfiguration.ConnectTimeout,Mode=TwoWay}\"/>\n                <controls:NumberUpDown Grid.Row=\"3\" Grid.Column=\"1\" VerticalAlignment=\"Center\" Height=\"23.24\" MinNum=\"0\" MaxNum=\"600\" \n                Value=\"{Binding ModifiedConfiguration.Ttl,Mode=TwoWay}\"/>\n            </Grid>\n        </GroupBox>\n        <Grid Grid.Row=\"2\" Grid.Column=\"1\" Margin=\"54,10,0,10\" HorizontalAlignment=\"Right\" Width=\"246\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition />\n                <ColumnDefinition />\n                <ColumnDefinition />\n            </Grid.ColumnDefinitions>\n            <Button Grid.Column=\"0\" Content=\"{DynamicResource Ok}\" Padding=\"10,0\" Margin=\"10,0\" FontSize=\"14\" Click=\"OkButton_Click\" />\n            <Button Grid.Column=\"1\" Content=\"{DynamicResource Cancel}\" Padding=\"10,0\" Margin=\"10,0\" FontSize=\"14\" Click=\"CancelButton_Click\" />\n            <Button x:Name=\"ApplyButton\" Grid.Column=\"2\" Content=\"{DynamicResource Apply}\" Padding=\"10,0\" Margin=\"10,0\" FontSize=\"14\" Click=\"ApplyButton_Click\" />\n        </Grid>\n    </Grid>\n</Window>"
  },
  {
    "path": "shadowsocks-csharp/View/SettingsWindow.xaml.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Controller.HttpRequest;\nusing Shadowsocks.Model;\nusing Shadowsocks.Util;\nusing Shadowsocks.ViewModel;\nusing System;\nusing System.Windows;\n\nnamespace Shadowsocks.View\n{\n    public partial class SettingsWindow\n    {\n        public SettingsWindow(MainController controller)\n        {\n            InitializeComponent();\n            I18NUtil.SetLanguage(Resources, @\"SettingsWindow\");\n            _controller = controller;\n            Closed += (o, e) => { _controller.ConfigChanged -= controller_ConfigChanged; };\n            _controller.ConfigChanged += controller_ConfigChanged;\n            LoadCurrentConfiguration();\n        }\n\n        private readonly MainController _controller;\n\n        public SettingViewModel SettingViewModel { get; set; } = new();\n\n        private void LoadCurrentConfiguration()\n        {\n            SettingViewModel.ReadConfig();\n            SettingViewModel.ModifiedConfiguration.PropertyChanged += (o, args) =>\n            {\n                ApplyButton.IsEnabled = true;\n            };\n            AutoStartupCheckBox.IsChecked = AutoStartup.Check();\n            Title = $@\"{this.GetWindowStringValue(@\"Title\")}({(Global.GuiConfig.ShareOverLan ? this.GetWindowStringValue(@\"Any\") : this.GetWindowStringValue(@\"Local\"))}:{Global.GuiConfig.LocalPort} {this.GetWindowStringValue(@\"Version\")}:{Controller.HttpRequest.UpdateChecker.FullVersion})\";\n            ApplyButton.IsEnabled = false;\n        }\n\n        private void controller_ConfigChanged(object sender, EventArgs e)\n        {\n            LoadCurrentConfiguration();\n        }\n\n        private void SaveConfig()\n        {\n            if (SettingViewModel.ModifiedConfiguration.LangName != Global.GuiConfig.LangName)\n            {\n                MessageBox.Show(this.GetWindowStringValue(@\"RestartRequired\"), Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.OK);\n            }\n            _controller.SaveServersConfig(SettingViewModel.ModifiedConfiguration, true);\n            var isAutoStartup = AutoStartupCheckBox.IsChecked.GetValueOrDefault();\n            if (isAutoStartup != AutoStartup.Check()\n            && !AutoStartup.Set(isAutoStartup))\n            {\n                MessageBox.Show(this.GetWindowStringValue(@\"FailAutoStartUp\"), Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.OK);\n            }\n        }\n\n        private void OkButton_Click(object sender, RoutedEventArgs e)\n        {\n            if (ApplyButton.IsEnabled)\n            {\n                SaveConfig();\n            }\n            Close();\n        }\n\n        private void CancelButton_Click(object sender, RoutedEventArgs e)\n        {\n            Close();\n        }\n\n        private void ApplyButton_Click(object sender, RoutedEventArgs e)\n        {\n            SaveConfig();\n        }\n\n        private void DefaultButton_Click(object sender, RoutedEventArgs e)\n        {\n            SettingViewModel.ModifiedConfiguration.ReconnectTimes = 4;\n            SettingViewModel.ModifiedConfiguration.ConnectTimeout = SettingViewModel.ModifiedConfiguration.ProxyEnable ? 10 : 5;\n            SettingViewModel.ModifiedConfiguration.Ttl = 60;\n        }\n\n        private void AutoStartupCheckBox_CheckedChanged(object sender, RoutedEventArgs e)\n        {\n            ApplyButton.IsEnabled = true;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ShowTextWindow.xaml",
    "content": "﻿<Window x:Class=\"Shadowsocks.View.ShowTextWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\"\n        Title=\"QRCode\" Height=\"562\" Width=\"500\" ResizeMode=\"CanResizeWithGrip\" WindowStartupLocation=\"CenterScreen\">\n    <Grid x:Name=\"Grid1\">\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"62\"></RowDefinition>\n            <RowDefinition></RowDefinition>\n        </Grid.RowDefinitions>\n        <TextBox x:Name=\"TextBox\" Grid.Row=\"0\" HorizontalScrollBarVisibility=\"Disabled\" VerticalScrollBarVisibility=\"Auto\" TextWrapping=\"Wrap\" AcceptsReturn=\"True\" AcceptsTab=\"True\" />\n        <Image x:Name=\"PictureQrCode\" Grid.Row=\"1\" Stretch=\"Uniform\" StretchDirection=\"Both\" HorizontalAlignment=\"Stretch\" VerticalAlignment=\"Stretch\"/> \n       \n\t</Grid>\n</Window>\n"
  },
  {
    "path": "shadowsocks-csharp/View/ShowTextWindow.xaml.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Windows;\n\nnamespace Shadowsocks.View\n{\n    public partial class ShowTextWindow\n    {\n        public ShowTextWindow(string text)\n        {\n            InitializeComponent();\n            _initText = text ?? string.Empty;\n            Loaded += ShowTextWindow_Loaded;\n        }\n\n        private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)\n        {\n            GenQr(TextBox.Text);\n        }\n\n        private void ShowTextWindow_SizeChanged(object sender, SizeChangedEventArgs e)\n        {\n            GenQr(TextBox.Text);\n        }\n\n        private readonly string _initText;\n\n        private void ShowTextWindow_Loaded(object sender, RoutedEventArgs e)\n        {\n            GenQr(_initText);\n            TextBox.Text = _initText;\n            SizeChanged += ShowTextWindow_SizeChanged;\n            TextBox.TextChanged += TextBox_TextChanged;\n        }\n\n        private void GenQr(string text)\n        {\n            try\n            {\n                var h = Convert.ToInt32(Grid1.RowDefinitions[1].ActualHeight);\n                var w = Convert.ToInt32(Grid1.ActualWidth);\n                PictureQrCode.Source = text != string.Empty ? QrCodeUtils.GenQrCode(text, w, h) : QrCodeUtils.GenQrCode2(text, Math.Min(w, h));\n            }\n            catch\n            {\n                PictureQrCode.Source = null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/SubscribeWindow.xaml",
    "content": "<Window x:Class=\"Shadowsocks.View.SubscribeWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:model=\"clr-namespace:Shadowsocks.Model\"\n        xmlns:enums=\"clr-namespace:Shadowsocks.Enums\"\n        xmlns:valueConverter=\"clr-namespace:Shadowsocks.View.ValueConverter\"\n        x:Name=\"Sw\"\n        Title=\"{DynamicResource Title}\"\n        Height=\"360\" Width=\"680\"\n        MinHeight=\"360\" MinWidth=\"680\"\n        WindowStartupLocation=\"CenterScreen\"\n        DataContext=\"{Binding SubscribeWindowViewModel,ElementName=Sw}\"\n        Loaded=\"Window_Loaded\">\n\n    <Window.Resources>\n        <ResourceDictionary>\n            <ResourceDictionary.MergedDictionaries>\n                <ResourceDictionary Source=\"../I18N/SubscribeWindow.en-US.xaml\" />\n            </ResourceDictionary.MergedDictionaries>\n            <SolidColorBrush x:Key=\"DisabledBackgroundBrush\" Color=\"LightGray\" />\n            <Style TargetType=\"{x:Type TextBox}\">\n                <Style.Triggers>\n                    <Trigger Property=\"IsEnabled\" Value=\"False\">\n                        <Setter Property=\"Background\" Value=\"{StaticResource DisabledBackgroundBrush}\" />\n                    </Trigger>\n                </Style.Triggers>\n            </Style>\n            <DataTemplate x:Key=\"ListBoxTemplate\" DataType=\"model:ServerSubscribe\">\n                <StackPanel Margin=\"3\">\n                    <DockPanel>\n                        <TextBlock Text=\"{Binding Tag}\" Foreground=\"Green\" FontWeight=\"Bold\" />\n                    </DockPanel>\n                    <DockPanel>\n                        <TextBlock FontWeight=\"Bold\" Text=\"{Binding Url}\" Foreground=\"DarkOrange\"\n                                   DockPanel.Dock=\"Left\" />\n                    </DockPanel>\n                </StackPanel>\n            </DataTemplate>\n            <valueConverter:UnixSecondsToString x:Key=\"UlongToDateTimeString\" />\n            <valueConverter:ProxyTypeConverter x:Key=\"ProxyTypeConverter\" />\n        </ResourceDictionary>\n    </Window.Resources>\n\n    <Grid>\n        <Grid.RowDefinitions>\n            <RowDefinition />\n            <RowDefinition Height=\"Auto\"/>\n        </Grid.RowDefinitions>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition />\n            <ColumnDefinition MinWidth=\"330\"/>\n        </Grid.ColumnDefinitions>\n        <GridSplitter Grid.Column=\"0\" Grid.RowSpan=\"2\"\n                      HorizontalAlignment=\"Right\"\n                      VerticalAlignment=\"Stretch\"\n                      Width=\"3\" />\n\n        <ListBox x:Name=\"ServerSubscribeListBox\" Grid.Row=\"0\" Grid.Column=\"0\" Margin=\"10,0,10,0\" \n        SelectionChanged=\"ServerSubscribeListBox_SelectionChanged\" \n        ScrollViewer.HorizontalScrollBarVisibility=\"Auto\" \n        ScrollViewer.VerticalScrollBarVisibility=\"Auto\" ScrollViewer.CanContentScroll=\"True\" \n        ItemsSource=\"{Binding SubscribeCollection}\"\n        ItemTemplate=\"{StaticResource ListBoxTemplate}\"\n        SelectedItem=\"{Binding SelectedServer,Mode=TwoWay}\">\n        </ListBox>\n        <StackPanel Grid.Row=\"0\" Grid.Column=\"1\" Margin=\"10,0,10,0\" >\n            <Grid x:Name=\"InfoGrid\">\n                <Grid.RowDefinitions>\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                    <RowDefinition />\n                </Grid.RowDefinitions>\n                <Grid.ColumnDefinitions>\n                    <ColumnDefinition Width=\"Auto\"/>\n                    <ColumnDefinition Width=\"*\"/>\n                </Grid.ColumnDefinitions>\n                <Label Grid.Row=\"0\" Grid.Column=\"0\" Content=\"{DynamicResource Url}\" Margin=\"0,3\"/>\n                <Label Grid.Row=\"1\" Grid.Column=\"0\" Content=\"{DynamicResource GroupName}\" Margin=\"0,3\" />\n                <Label Grid.Row=\"2\" Grid.Column=\"0\" Content=\"{DynamicResource LastUpdate}\" Margin=\"0,3\" />\n                <TextBox Grid.Row=\"0\" Grid.Column=\"1\" Margin=\"0,3\" VerticalContentAlignment=\"Center\"\n                Text=\"{Binding SelectedServer.Url,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n                <TextBox Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"0,3\" VerticalContentAlignment=\"Center\"\n                Text=\"{Binding SelectedServer.Tag,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n                <TextBox Grid.Row=\"2\" Grid.Column=\"1\" Margin=\"0,3\" IsReadOnly=\"True\" Background=\"{StaticResource DisabledBackgroundBrush}\" VerticalContentAlignment=\"Center\"\n                Text=\"{Binding SelectedServer.LastUpdateTime,Converter={StaticResource UlongToDateTimeString},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\" />\n                <CheckBox Grid.Row=\"3\" Grid.Column=\"1\" Content=\"{DynamicResource AutoUpdate}\" VerticalAlignment=\"Center\" Margin=\"0,10,0,0\" \n                IsChecked=\"{Binding SelectedServer.AutoCheckUpdate,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}\"/>\n                <GroupBox Grid.Row=\"4\" Grid.Column=\"1\" Header=\"{DynamicResource ProxyType}\" Margin=\"0,10,0,0\">\n                    <StackPanel>\n                        <RadioButton Content=\"{DynamicResource Auto}\" IsChecked=\"{Binding Path=SelectedServer.ProxyType, Converter={StaticResource ProxyTypeConverter}, ConverterParameter={x:Static enums:HttpRequestProxyType.Auto}}\" />\n                        <RadioButton Content=\"{DynamicResource Direct}\" IsChecked=\"{Binding Path=SelectedServer.ProxyType, Converter={StaticResource ProxyTypeConverter}, ConverterParameter={x:Static enums:HttpRequestProxyType.Direct}}\" />\n                        <RadioButton Content=\"{DynamicResource Proxy}\" IsChecked=\"{Binding Path=SelectedServer.ProxyType, Converter={StaticResource ProxyTypeConverter}, ConverterParameter={x:Static enums:HttpRequestProxyType.Proxy}}\" />\n                        <RadioButton Content=\"{DynamicResource SystemSetting}\" IsChecked=\"{Binding Path=SelectedServer.ProxyType, Converter={StaticResource ProxyTypeConverter}, ConverterParameter={x:Static enums:HttpRequestProxyType.SystemSetting}}\" />\n                    </StackPanel>\n                </GroupBox>\n                <Button Grid.Row=\"5\" Grid.Column=\"1\" Content=\"{DynamicResource Update}\" Margin=\"0,10,0,0\" Click=\"UpdateButton_OnClick\" />\n            </Grid>\n        </StackPanel>\n        <Grid Grid.Row=\"1\" Grid.Column=\"0\" Margin=\"0,10,0,10\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"1*\" />\n                <ColumnDefinition Width=\"1*\" />\n            </Grid.ColumnDefinitions>\n            <Button Grid.Column=\"0\" Content=\"{DynamicResource Add}\" Margin=\"10,0\" FontSize=\"14\" Click=\"AddButton_Click\" />\n            <Button Grid.Column=\"1\" Content=\"{DynamicResource Delete}\" Margin=\"10,0\" FontSize=\"14\" Click=\"DeleteButton_Click\" />\n        </Grid>\n        <Grid Grid.Row=\"1\" Grid.Column=\"1\" Margin=\"0,10,0,10\" HorizontalAlignment=\"Right\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition Width=\"Auto\" />\n                <ColumnDefinition Width=\"Auto\" />\n                <ColumnDefinition Width=\"Auto\" />\n            </Grid.ColumnDefinitions>\n            <Button Grid.Column=\"0\" Content=\"{DynamicResource Ok}\" Padding=\"10,0\" Margin=\"10,0\" FontSize=\"14\" Click=\"OkButton_Click\" />\n            <Button Grid.Column=\"1\" Content=\"{DynamicResource Cancel}\" Padding=\"10,0\" Margin=\"10,0\" FontSize=\"14\" Click=\"CancelButton_Click\" />\n            <Button x:Name=\"ApplyButton\" Grid.Column=\"2\" Content=\"{DynamicResource Apply}\" Padding=\"10,0\" Margin=\"10,0\" FontSize=\"14\" Click=\"ApplyButton_Click\" />\n        </Grid>\n    </Grid>\n</Window>\n"
  },
  {
    "path": "shadowsocks-csharp/View/SubscribeWindow.xaml.cs",
    "content": "using Shadowsocks.Controller;\nusing Shadowsocks.Model;\nusing Shadowsocks.Util;\nusing Shadowsocks.ViewModel;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows;\nusing System.Windows.Controls;\n\nnamespace Shadowsocks.View\n{\n    public partial class SubscribeWindow\n    {\n        public SubscribeWindow(MainController controller)\n        {\n            InitializeComponent();\n            I18NUtil.SetLanguage(Resources, @\"SubscribeWindow\");\n            Closed += (o, e) =>\n            {\n                controller.ConfigChanged -= controller_ConfigChanged;\n                SubscribeWindowViewModel.SubscribesChanged -= SubscribeWindowViewModel_SubscribesChanged;\n            };\n            _controller = controller;\n            _controller.ConfigChanged += controller_ConfigChanged;\n            LoadCurrentConfiguration();\n            SubscribeWindowViewModel.SubscribesChanged += SubscribeWindowViewModel_SubscribesChanged;\n        }\n\n        private void SubscribeWindowViewModel_SubscribesChanged(object sender, EventArgs e)\n        {\n            ApplyButton.IsEnabled = true;\n        }\n\n        private readonly MainController _controller;\n        private Configuration _modifiedConfiguration;\n\n        public SubscribeWindowViewModel SubscribeWindowViewModel { get; set; } = new();\n\n        private bool _isDeleteServer;\n\n        private void Window_Loaded(object sender, RoutedEventArgs _)\n        {\n            InfoGrid.Visibility = ServerSubscribeListBox.SelectedIndex == -1 ? Visibility.Hidden : Visibility.Visible;\n        }\n\n        private void controller_ConfigChanged(object sender, EventArgs e)\n        {\n            LoadCurrentConfiguration();\n        }\n\n        private void LoadCurrentConfiguration()\n        {\n            _modifiedConfiguration = Global.Load();\n            SubscribeWindowViewModel.ReadConfig(_modifiedConfiguration);\n\n            ApplyButton.IsEnabled = false;\n        }\n\n        private void ServerSubscribeListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)\n        {\n            InfoGrid.Visibility = ServerSubscribeListBox.SelectedIndex == -1 ? Visibility.Hidden : Visibility.Visible;\n        }\n\n        private void DeleteUnusedServer()\n        {\n            _modifiedConfiguration.Configs.RemoveAll(server =>\n                    !string.IsNullOrEmpty(server.SubTag)\n                    && _modifiedConfiguration.ServerSubscribes.All(subscribe => subscribe.Tag != server.SubTag));\n            _isDeleteServer = true;\n        }\n\n        private bool SaveConfig()\n        {\n            var remarks = new HashSet<string>();\n            foreach (var serverSubscribe in SubscribeWindowViewModel.SubscribeCollection)\n            {\n                if (remarks.Contains(serverSubscribe.Tag))\n                {\n                    return false;\n                }\n                remarks.Add(serverSubscribe.Tag);\n            }\n            _modifiedConfiguration.ServerSubscribes.Clear();\n            _modifiedConfiguration.ServerSubscribes.AddRange(SubscribeWindowViewModel.SubscribeCollection);\n\n            if (_modifiedConfiguration.Configs.Any(server =>\n            !string.IsNullOrEmpty(server.SubTag)\n            && _modifiedConfiguration.ServerSubscribes.All(subscribe => subscribe.Tag != server.SubTag)))\n            {\n                if (MessageBox.Show(this.GetWindowStringValue(@\"SaveQuestion\"),\n                            Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes)\n                        == MessageBoxResult.Yes)\n                {\n                    DeleteUnusedServer();\n                }\n            }\n            _controller.SaveServersConfig(_modifiedConfiguration, _isDeleteServer);\n            return true;\n        }\n\n        private void OkButton_Click(object sender, RoutedEventArgs e)\n        {\n            if (Save())\n            {\n                Global.UpdateSubscribeManager.CreateTask(Global.GuiConfig, Global.UpdateNodeChecker, true);\n                Close();\n            }\n            else\n            {\n                SaveError();\n            }\n        }\n\n        private void CancelButton_Click(object sender, RoutedEventArgs e)\n        {\n            Close();\n        }\n\n        private void ApplyButton_Click(object sender, RoutedEventArgs e)\n        {\n            if (SaveConfig())\n            {\n                return;\n            }\n            SaveError();\n        }\n\n        private void AddButton_Click(object sender, RoutedEventArgs e)\n        {\n            SubscribeWindowViewModel.SubscribeCollection.Add(new ServerSubscribe());\n            SetServerListSelectedIndex(SubscribeWindowViewModel.SubscribeCollection.Count - 1);\n        }\n\n        private void DeleteButton_Click(object sender, RoutedEventArgs e)\n        {\n            var index = ServerSubscribeListBox.SelectedIndex;\n            if (ServerSubscribeListBox.SelectedItem is ServerSubscribe serverSubscribe)\n            {\n                var tag = serverSubscribe.Tag;\n                _modifiedConfiguration.Configs.RemoveAll(server => server.SubTag == tag);\n                _isDeleteServer = true;\n                SubscribeWindowViewModel.SubscribeCollection.Remove(serverSubscribe);\n            }\n\n            SetServerListSelectedIndex(index);\n        }\n\n        private void SetServerListSelectedIndex(int index)\n        {\n            if (index < 0)\n            {\n                return;\n            }\n\n            if (index < ServerSubscribeListBox.Items.Count)\n            {\n                ServerSubscribeListBox.SelectedIndex = index;\n                ServerSubscribeListBox.ScrollIntoView(ServerSubscribeListBox.Items[index]);\n            }\n            else\n            {\n                ServerSubscribeListBox.SelectedIndex = ServerSubscribeListBox.Items.Count - 1;\n                if (ServerSubscribeListBox.SelectedIndex > 0)\n                {\n                    ServerSubscribeListBox.ScrollIntoView(ServerSubscribeListBox.Items[ServerSubscribeListBox.Items.Count - 1]);\n                }\n            }\n        }\n\n        private bool Save()\n        {\n            return !ApplyButton.IsEnabled || SaveConfig();\n        }\n\n        private void SaveError()\n        {\n            MessageBox.Show(this.GetWindowStringValue(@\"SaveError\"), Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.OK, MessageBoxImage.Error);\n        }\n\n        private void UpdateButton_OnClick(object sender, RoutedEventArgs e)\n        {\n            if (ServerSubscribeListBox.SelectedItem is ServerSubscribe serverSubscribe)\n            {\n                if (Save())\n                {\n                    Global.UpdateSubscribeManager.CreateTask(Global.GuiConfig, Global.UpdateNodeChecker, true, new List<ServerSubscribe> { serverSubscribe });\n                }\n                else\n                {\n                    SaveError();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/BalanceTypeEnumConverter.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Util;\nusing System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class BalanceTypeEnumConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            if (value is BalanceType type)\n            {\n                return I18NUtil.GetAppStringValue(type.ToString());\n            }\n\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/BooleanToEnabledConverter.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Util;\nusing System;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class BooleanToEnabledConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            if (value is bool enable)\n            {\n                if (targetType == typeof(Brush))\n                {\n                    return enable ? ColorConvert.EnableBrush : ColorConvert.DisableBrush;\n                }\n            }\n            else if (value is ServerTreeViewType type)\n            {\n                if (targetType == typeof(Visibility))\n                {\n                    return type == ServerTreeViewType.Server ? Visibility.Visible : Visibility.Collapsed;\n                }\n            }\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/ConnectEmptyToBrushConverter.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class ConnectEmptyToBrushConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            if (value is long bytes && bytes > 0)\n            {\n                return new SolidColorBrush(ColorConvert.GetConnectEmptyColor(bytes));\n            }\n\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter,\n                System.Globalization.CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/ConnectErrorToBrushConverter.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class ConnectErrorToBrushConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            if (value is long bytes && bytes > 0)\n            {\n                return new SolidColorBrush(ColorConvert.GetConnectErrorColor(bytes));\n            }\n\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter,\n                System.Globalization.CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/ConnectNumberToBrushConverter.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class ConnectNumberToBrushConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            if (value is long bytes && bytes > 0)\n            {\n                return new SolidColorBrush(ColorConvert.GetConnectionColor(bytes));\n            }\n\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/ErrorPercentToBrushConverter.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class ErrorPercentToBrushConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            if (value is double percent && percent > 0)\n            {\n                return new SolidColorBrush(ColorConvert.GetErrorPercentColor(percent));\n            }\n\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter,\n                System.Globalization.CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/LatencyToBrushConverter.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class LatencyToBrushConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            if (value is long bytes && bytes > 0)\n            {\n                return new SolidColorBrush(ColorConvert.GetLatencyColor(bytes));\n            }\n\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter,\n                System.Globalization.CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/ProxyTypeConverter.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Windows.Data;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class ProxyTypeConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            return value?.Equals(parameter);\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            return value?.Equals(true) == true ? parameter : Binding.DoNothing;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/ProxyTypeEnumConverter.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Util;\nusing System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class ProxyTypeEnumConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            if (value is ProxyType type)\n            {\n                return I18NUtil.GetAppStringValue(type.ToString());\n            }\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/ServerTreeTypeToFontConverter.cs",
    "content": "using Shadowsocks.Enums;\nusing System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class ServerTreeTypeToFontConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            if (value is ServerTreeViewType type)\n            {\n                if (targetType == typeof(Brush))\n                {\n                    switch (type)\n                    {\n                        case ServerTreeViewType.Subtag:\n                            return Brushes.Green;\n                        case ServerTreeViewType.Group:\n                            return Brushes.DarkOrange;\n                        case ServerTreeViewType.Server:\n                            break;\n                        default:\n                            return DependencyProperty.UnsetValue;\n                    }\n                }\n                else if (targetType == typeof(FontWeight))\n                {\n                    switch (type)\n                    {\n                        case ServerTreeViewType.Subtag:\n                        case ServerTreeViewType.Group:\n                            return FontWeights.Bold;\n                        default:\n                            return DependencyProperty.UnsetValue;\n                    }\n                }\n            }\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/SpeedToBrushConverter.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class SpeedToBrushConverter : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            if (value is long bytes && bytes > 0)\n            {\n                return new SolidColorBrush(ColorConvert.GetSpeedColor(bytes));\n            }\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter,\n        System.Globalization.CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/TotalDownloadBackgroundBrushConvert.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class TotalDownloadBackgroundBrushConvert : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            if (value is int index)\n            {\n                if (targetType == typeof(Brush))\n                {\n                    return System.Convert.ToBoolean(index & 1) ? ColorConvert.TotalDownloadBrush1 : ColorConvert.TotalDownloadBrush2;\n                }\n            }\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/TotalDownloadRawBackgroundBrushConvert.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class TotalDownloadRawBackgroundBrushConvert : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            if (value is int index)\n            {\n                if (targetType == typeof(Brush))\n                {\n                    return System.Convert.ToBoolean(index & 1) ? ColorConvert.TotalDownloadRawBrush1 : ColorConvert.TotalDownloadRawBrush2;\n                }\n            }\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/TotalUploadBackgroundBrushConvert.cs",
    "content": "using Shadowsocks.Util;\nusing System;\nusing System.Globalization;\nusing System.Windows;\nusing System.Windows.Data;\nusing System.Windows.Media;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class TotalUploadBackgroundBrushConvert : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            if (value is int index)\n            {\n                if (targetType == typeof(Brush))\n                {\n                    return System.Convert.ToBoolean(index & 1) ? ColorConvert.TotalUploadBrush1 : ColorConvert.TotalUploadBrush2;\n                }\n            }\n            return DependencyProperty.UnsetValue;\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/View/ValueConverter/UnixSecondsToString.cs",
    "content": "using System;\nusing System.Windows.Data;\n\nnamespace Shadowsocks.View.ValueConverter\n{\n    public class UnixSecondsToString : IValueConverter\n    {\n        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            if (value is long lastUpdateTime && targetType == typeof(string))\n            {\n                if (lastUpdateTime is not 0)\n                {\n                    return DateTimeOffset.FromUnixTimeSeconds(lastUpdateTime).ToLocalTime().ToString();\n                }\n            }\n            return @\"(｀・ω・´)\";\n        }\n\n        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)\n        {\n            throw new NotSupportedException();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/ViewModel/DnsSettingViewModel.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing Shadowsocks.Util.NetUtils;\nusing System;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System.Windows;\n\nnamespace Shadowsocks.ViewModel\n{\n    public class DnsSettingViewModel : ViewModelBase\n    {\n        public DnsSettingViewModel()\n        {\n            _currentClient = null;\n            _clients = new ObservableCollection<DnsClient>();\n        }\n\n        #region Event\n\n        public event EventHandler DnsClientsChanged;\n\n        private void CurrentClient_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)\n        {\n            if (e.PropertyName == nameof(DnsClient.DnsType))\n            {\n                if (sender is DnsClient client)\n                {\n                    client.Port = client.DnsType switch\n                    {\n                        DnsType.Default when client.Port == DnsClient.DefaultTlsPort => DnsClient.DefaultPort,\n                        DnsType.DnsOverTls when client.Port == DnsClient.DefaultPort => DnsClient.DefaultTlsPort,\n                        _ => client.Port\n                    };\n                    client.DnsServer = client.DnsType switch\n                    {\n                        DnsType.Default when client.DnsServer == DnsClient.DefaultTlsDnsServer => DnsClient.DefaultDnsServer,\n                        DnsType.DnsOverTls when client.DnsServer == DnsClient.DefaultDnsServer => DnsClient.DefaultTlsDnsServer,\n                        _ => client.DnsServer\n                    };\n                }\n            }\n            DnsClientsChanged?.Invoke(sender, EventArgs.Empty);\n        }\n\n        private void Clients_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)\n        {\n            DnsClientsChanged?.Invoke(sender, EventArgs.Empty);\n        }\n\n        #endregion\n\n        private ObservableCollection<DnsClient> _clients;\n        private DnsClient _currentClient;\n\n        public ObservableCollection<DnsClient> Clients\n        {\n            get => _clients;\n            set\n            {\n                if (SetField(ref _clients, value))\n                {\n                    DnsClientsChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public DnsClient CurrentClient\n        {\n            get => _currentClient;\n            set\n            {\n                if (SetField(ref _currentClient, value))\n                {\n                    if (_currentClient != null)\n                    {\n                        _currentClient.PropertyChanged -= CurrentClient_PropertyChanged;\n                        _currentClient.PropertyChanged += CurrentClient_PropertyChanged;\n                    }\n                    OnPropertyChanged(nameof(IsCurrentClientNull));\n                }\n            }\n        }\n\n        public Visibility IsCurrentClientNull => CurrentClient == null ? Visibility.Hidden : Visibility.Visible;\n\n        public void ReadConfig()\n        {\n            var config = Global.Load();\n            Clients.Clear();\n            foreach (var client in config.DnsClients)\n            {\n                Clients.Add(client);\n            }\n            CurrentClient = Clients.Count > 0 ? Clients[0] : null;\n            Clients.CollectionChanged -= Clients_CollectionChanged;\n            Clients.CollectionChanged += Clients_CollectionChanged;\n        }\n\n        public void SaveConfig()\n        {\n            Global.GuiConfig.DnsClients.Clear();\n            foreach (var client in Clients)\n            {\n                Global.GuiConfig.DnsClients.Add(client);\n            }\n            DnsUtil.DnsBuffer.Clear();\n            Global.Controller.SaveAndNotifyChanged();\n        }\n\n        public void AddNewDns()\n        {\n            var newDns = new DnsClient(DnsType.Default);\n            Clients.Add(newDns);\n            CurrentClient = newDns;\n        }\n\n        public void Delete()\n        {\n            if (CurrentClient != null)\n            {\n                Clients.Remove(CurrentClient);\n                CurrentClient = Clients.LastOrDefault();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/ViewModel/ServerConfigViewModel.cs",
    "content": "using Shadowsocks.Enums;\nusing Shadowsocks.Model;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\n\nnamespace Shadowsocks.ViewModel\n{\n    public class ServerConfigViewModel : ViewModelBase\n    {\n        public ServerConfigViewModel()\n        {\n            ServersTreeViewCollection = new ObservableCollection<ServerTreeViewModel>();\n        }\n\n        private ObservableCollection<ServerTreeViewModel> _serverTreeViewCollection;\n        public ObservableCollection<ServerTreeViewModel> ServersTreeViewCollection\n        {\n            get => _serverTreeViewCollection;\n            set\n            {\n                if (SetField(ref _serverTreeViewCollection, value))\n                {\n                    ServersChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public void ReadServers(List<Server> configs)\n        {\n            ServersTreeViewCollection.Clear();\n            var subTags = new HashSet<string>(configs.Select(server => server.SubTag));\n            foreach (var subTag in subTags)\n            {\n                var sub1 = new ServerTreeViewModel\n                {\n                    Name = subTag,\n                    Type = ServerTreeViewType.Subtag\n                };\n                var servers = configs.Where(server => server.SubTag == subTag).ToArray();\n                var groups = new HashSet<string>(servers.Select(server => server.Group));\n\n                foreach (var group in groups)\n                {\n                    var sub2 = new ServerTreeViewModel\n                    {\n                        Name = group,\n                        Type = ServerTreeViewType.Group\n                    };\n                    var subServers = servers.Where(server => server.Group == group);\n                    foreach (var server in subServers)\n                    {\n                        server.ServerChanged += ServerChanged;\n                        sub2.Nodes.CollectionChanged -= ServerCollection_CollectionChanged;\n                        sub2.Nodes.CollectionChanged += ServerCollection_CollectionChanged;\n                        sub2.Nodes.Add(new ServerTreeViewModel\n                        {\n                            Server = server,\n                            Type = ServerTreeViewType.Server\n                        });\n                    }\n                    sub1.Nodes.CollectionChanged -= ServerCollection_CollectionChanged;\n                    sub1.Nodes.CollectionChanged += ServerCollection_CollectionChanged;\n                    sub1.Nodes.Add(sub2);\n                }\n\n                if (groups.Count == 1)\n                {\n                    sub1.Nodes[0].Name = subTag;\n                    sub1.Nodes[0].Type = ServerTreeViewType.Subtag;\n                    ServersTreeViewCollection.Add(sub1.Nodes[0]);\n                }\n                else\n                {\n                    ServersTreeViewCollection.Add(sub1);\n                }\n            }\n\n            ServersTreeViewCollection.CollectionChanged -= ServerCollection_CollectionChanged;\n            ServersTreeViewCollection.CollectionChanged += ServerCollection_CollectionChanged;\n        }\n\n        public static IEnumerable<Server> ServerTreeViewModelToList(IEnumerable<ServerTreeViewModel> nodes)\n        {\n            var res = new List<Server>();\n            foreach (var serverTreeViewModel in nodes)\n            {\n                if (serverTreeViewModel.Type == ServerTreeViewType.Server)\n                {\n                    res.Add(serverTreeViewModel.Server);\n                }\n                else\n                {\n                    res.AddRange(ServerTreeViewModelToList(serverTreeViewModel.Nodes));\n                }\n            }\n            return res;\n        }\n\n        private void ServerCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)\n        {\n            ServersChanged?.Invoke(this, EventArgs.Empty);\n        }\n\n        public event EventHandler ServersChanged;\n\n        private void ServerChanged(object sender, EventArgs e)\n        {\n            ServersChanged?.Invoke(this, EventArgs.Empty);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/ViewModel/ServerLogViewModel.cs",
    "content": "using Shadowsocks.Model;\nusing System.Collections.ObjectModel;\n\nnamespace Shadowsocks.ViewModel\n{\n    public class ServerLogViewModel : ViewModelBase\n    {\n        public ServerLogViewModel()\n        {\n            _serversCollection = new ObservableCollection<Server>();\n        }\n\n        private ObservableCollection<Server> _serversCollection;\n        public ObservableCollection<Server> ServersCollection\n        {\n            get => _serversCollection;\n            set => SetField(ref _serversCollection, value);\n        }\n\n        private Server _selectedServer;\n        public Server SelectedServer\n        {\n            get => _selectedServer;\n            private set => SetField(ref _selectedServer, value);\n        }\n\n        public void ReadConfig()\n        {\n            var config = Global.GuiConfig;\n            ServersCollection.Clear();\n            var index = 1;\n            foreach (var server in config.Configs)\n            {\n                server.Index = index++;\n                if (config.Index == server.Index - 1)\n                {\n                    server.IsSelected = true;\n                    SelectedServer = server;\n                }\n                else\n                {\n                    server.IsSelected = false;\n                }\n                ServersCollection.Add(server);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/ViewModel/SettingViewModel.cs",
    "content": "using Shadowsocks.Model;\n\nnamespace Shadowsocks.ViewModel\n{\n    public class SettingViewModel : ViewModelBase\n    {\n        public SettingViewModel()\n        {\n            _modifiedConfiguration = new Configuration();\n        }\n\n        private Configuration _modifiedConfiguration;\n\n        public Configuration ModifiedConfiguration\n        {\n            get => _modifiedConfiguration;\n            set => SetField(ref _modifiedConfiguration, value);\n        }\n\n        public void ReadConfig()\n        {\n            ModifiedConfiguration = Global.Load();\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/ViewModel/SubscribeWindowViewModel.cs",
    "content": "using Shadowsocks.Model;\nusing System;\nusing System.Collections.ObjectModel;\n\nnamespace Shadowsocks.ViewModel\n{\n    public class SubscribeWindowViewModel : ViewModelBase\n    {\n        public SubscribeWindowViewModel()\n        {\n            SubscribeCollection = new ObservableCollection<ServerSubscribe>();\n        }\n\n        public void ReadConfig(Configuration config)\n        {\n            SubscribeCollection.Clear();\n            foreach (var serverSubscribe in config.ServerSubscribes)\n            {\n                SubscribeCollection.Add(serverSubscribe);\n            }\n            SelectedServer = SubscribeCollection.Count > 0 ? SubscribeCollection[0] : null;\n            SubscribeCollection.CollectionChanged -= SubscribeCollection_CollectionChanged;\n            SubscribeCollection.CollectionChanged += SubscribeCollection_CollectionChanged;\n        }\n\n        private void SubscribeCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)\n        {\n            SubscribesChanged?.Invoke(this, EventArgs.Empty);\n        }\n\n        public event EventHandler SubscribesChanged;\n\n        private ObservableCollection<ServerSubscribe> _subscribeCollection;\n        public ObservableCollection<ServerSubscribe> SubscribeCollection\n        {\n            get => _subscribeCollection;\n            set\n            {\n                if (SetField(ref _subscribeCollection, value))\n                {\n                    SubscribesChanged?.Invoke(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        private ServerSubscribe _selectedServer;\n        public ServerSubscribe SelectedServer\n        {\n            get => _selectedServer;\n            set\n            {\n                if (SetField(ref _selectedServer, value))\n                {\n                    if (_selectedServer != null)\n                    {\n                        _selectedServer.SubscribeChanged -= _selectedServer_SubscribeChanged;\n                        _selectedServer.SubscribeChanged += _selectedServer_SubscribeChanged;\n                    }\n                }\n            }\n        }\n\n        private void _selectedServer_SubscribeChanged(object sender, EventArgs e)\n        {\n            SubscribesChanged?.Invoke(this, EventArgs.Empty);\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/ViewModel/ViewModelBase.cs",
    "content": "using System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Runtime.CompilerServices;\n\nnamespace Shadowsocks.ViewModel\n{\n    public abstract class ViewModelBase : INotifyPropertyChanged\n    {\n        public event PropertyChangedEventHandler PropertyChanged;\n\n        protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n\n        protected virtual bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = @\"\")\n        {\n            if (EqualityComparer<T>.Default.Equals(field, value))\n            {\n                return false;\n            }\n\n            field = value;\n            OnPropertyChanged(propertyName);\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "shadowsocks-csharp/shadowsocksr.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>WinExe</OutputType>\n    <TargetFramework>net7.0-windows</TargetFramework>\n    <LangVersion>latest</LangVersion>\n    <UseWPF>true</UseWPF>\n    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>\n    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>\n    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>\n    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>\n    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>\n    <GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>\n    <AssemblyName>ShadowsocksR</AssemblyName>\n    <RootNamespace>Shadowsocks</RootNamespace>\n    <ApplicationIcon>shadowsocks.ico</ApplicationIcon>\n    <StartupObject>Shadowsocks.Program</StartupObject>\n    <LangVersion>latest</LangVersion>\n    <SelfContained>false</SelfContained>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;PROTOCOL_STATISTICS</DefineConstants>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|AnyCPU'\">\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE;PROTOCOL_STATISTICS</DefineConstants>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <DefineConstants Condition=\" $(SelfContained) \">$(DefineConstants);SelfContained</DefineConstants>\n    <DefineConstants Condition=\" $(RuntimeIdentifier.Contains('x64')) \">$(DefineConstants);Is64Bit</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Remove=\"View\\Controls\\MaskedTextBox.xaml\" />\n    <None Remove=\"View\\Controls\\NumberUpDown.xaml\" />\n    <None Remove=\"Resources\\ssw128.png\" />\n    <None Remove=\"View\\LogWindow.xaml\" />\n    <None Remove=\"View\\PortSettingsWindow.xaml\" />\n    <None Remove=\"View\\QRCodeSplashWindow.xaml\" />\n    <None Remove=\"View\\ServerLogWindow.xaml\" />\n    <None Remove=\"View\\ShowTextWindow.xaml\" />\n    <None Remove=\"View\\SubscribeWindow.xaml\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"ARSoft.Tools.Net\" Version=\"2.3.0\" />\n    <PackageReference Include=\"CryptoBase\" Version=\"1.7.2\" />\n    <PackageReference Include=\"Hardcodet.NotifyIcon.Wpf\" Version=\"2.0.1\" />\n    <PackageReference Include=\"HMBSbige.SingleInstance\" Version=\"6.0.1\" />\n    <PackageReference Include=\"HMBSbige.UpdateChecker\" Version=\"8.0.1\" />\n    <PackageReference Include=\"RouteMatcher\" Version=\"1.0.0\" />\n    <PackageReference Include=\"RunAtStartup\" Version=\"5.0.2\" />\n    <PackageReference Include=\"Shadowsocks.Protocol\" Version=\"1.0.2\" />\n    <PackageReference Include=\"Syncfusion.SfGrid.WPF\" Version=\"29.2.11\" />\n    <PackageReference Include=\"Syncfusion.SfTreeView.WPF\" Version=\"29.2.11\" />\n    <PackageReference Include=\"URIScheme\" Version=\"5.0.0\" />\n    <PackageReference Include=\"WindowsProxy\" Version=\"6.0.0\" />\n    <PackageReference Include=\"WpfColorFontDialog\" Version=\"1.0.8\" />\n    <PackageReference Include=\"ZXing.Net.Bindings.Windows.Compatibility\" Version=\"0.16.13\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Properties\\Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Properties\\Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Page Update=\"I18N\\SettingsWindow.en-US.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\SettingsWindow.zh-CN.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\SettingsWindow.zh-TW.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\PortSettingsWindow.en-US.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\PortSettingsWindow.zh-CN.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\PortSettingsWindow.zh-TW.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\ServerLogWindow.en-US.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\ServerLogWindow.zh-CN.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\ServerLogWindow.zh-TW.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\LogWindow.en-US.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\LogWindow.zh-CN.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\LogWindow.zh-TW.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\DnsSettingWindow.en-US.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\DnsSettingWindow.zh-CN.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\DnsSettingWindow.zh-TW.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\SubscribeWindow.en-US.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\SubscribeWindow.zh-CN.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\SubscribeWindow.zh-TW.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\ConfigWindow.en-US.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\ConfigWindow.zh-CN.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n    <Page Update=\"I18N\\ConfigWindow.zh-TW.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n  </ItemGroup>\n\n  <Target Name=\"PreBuild\" BeforeTargets=\"PreBuildEvent\">\n    <Exec Command=\"cd &quot;$(ProjectDir)&quot;&#xD;&#xA;&#xD;&#xA;SyncfusionLicenseRegister.bat PreBuild Program.cs\" />\n  </Target>\n\n  <Target Name=\"PostBuild\" AfterTargets=\"PostBuildEvent\">\n    <Exec Command=\"cd &quot;$(ProjectDir)&quot;&#xD;&#xA;&#xD;&#xA;SyncfusionLicenseRegister.bat PostBuild Program.cs\" />\n  </Target>\n\n</Project>"
  },
  {
    "path": "shadowsocks-csharp.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.28803.202\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"shadowsocksr\", \"shadowsocks-csharp\\shadowsocksr.csproj\", \"{0F2A0C8A-6C06-485B-AA13-AEEC19CA9637}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"UnitTest\", \"UnitTest\\UnitTest.csproj\", \"{C4B1E5EC-C6BE-4726-B8CA-B4C84D4852B9}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{0F2A0C8A-6C06-485B-AA13-AEEC19CA9637}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{0F2A0C8A-6C06-485B-AA13-AEEC19CA9637}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{0F2A0C8A-6C06-485B-AA13-AEEC19CA9637}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{0F2A0C8A-6C06-485B-AA13-AEEC19CA9637}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{C4B1E5EC-C6BE-4726-B8CA-B4C84D4852B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{C4B1E5EC-C6BE-4726-B8CA-B4C84D4852B9}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{C4B1E5EC-C6BE-4726-B8CA-B4C84D4852B9}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{C4B1E5EC-C6BE-4726-B8CA-B4C84D4852B9}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {A01216A5-279B-4D66-9408-F7B97F2B782F}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  }
]