├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ ├── detekt-analysis.yml │ ├── domain-resolve.yml │ ├── qodana.yml │ └── resortIp.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── config ├── codeQuality.gradle └── detekt.yml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── litespeed ├── lite └── lite.exe ├── localFilter ├── localFilter.bat ├── settings.gradle ├── src ├── main │ ├── java │ │ └── me │ │ │ └── leon │ │ │ ├── Clash.kt │ │ │ ├── Config.kt │ │ │ ├── GeoParser.kt │ │ │ ├── Parser.kt │ │ │ ├── Subs.kt │ │ │ ├── domain │ │ │ ├── DnsResolve.kt │ │ │ ├── Host.kt │ │ │ ├── Lanzou.kt │ │ │ ├── LiteSpeed.kt │ │ │ └── Quark.kt │ │ │ └── support │ │ │ ├── Encode.kt │ │ │ ├── Ext.kt │ │ │ ├── File.kt │ │ │ ├── FlagRemover.kt │ │ │ ├── GsonUtils.kt │ │ │ ├── IpExt.kt │ │ │ ├── Net.kt │ │ │ └── Yamls.kt │ └── resources │ │ └── GeoLite2-Country.mmdb └── test │ ├── java │ └── me │ │ └── leon │ │ ├── ConnectTest.kt │ │ ├── ExtTest.kt │ │ ├── FlagTest.kt │ │ ├── LocalFileSubTest.kt │ │ ├── NetworkSubTest.kt │ │ ├── NodeCrawler.kt │ │ ├── NodeProcess.kt │ │ ├── SpeedTest.kt │ │ ├── ThirdVpnCrack.kt │ │ ├── YamlTest.kt │ │ └── ip │ │ ├── GeoTest.kt │ │ ├── HostsTest.kt │ │ └── IpFilterTest.kt │ └── resources │ └── domains ├── sub ├── flags.txt ├── info.md ├── ipScore ├── pool │ ├── sublists │ └── subs ├── share │ ├── a11 │ ├── blackhosts │ ├── host │ ├── hysteria2 │ ├── ss │ ├── ssr │ ├── tr │ ├── v2 │ ├── vless │ └── whitehost ├── socketfail ├── subs.txt └── vpn │ └── quark │ └── asia.txt ├── up.bat └── up.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://afdian.com/a/leon406 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: crawler 4 | 5 | # Controls when the action will run. 6 | on: 7 | push: 8 | paths: 9 | - 'src/**' 10 | # Triggers the workflow on push or pull request events but only for the master branch 11 | schedule: 12 | # 定时任务 13 | - cron: '0 0/5 * * *' 14 | 15 | # Allows you to run this workflow manually from the Actions tab 16 | workflow_dispatch: 17 | 18 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 19 | jobs: 20 | # This workflow contains a single job called "build" 21 | build: 22 | # The type of runner that the job will run on 23 | runs-on: ubuntu-latest 24 | 25 | # Steps represent a sequence of tasks that will be executed as part of the job 26 | steps: 27 | - run: sudo timedatectl set-timezone Asia/Shanghai 28 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 29 | - uses: actions/checkout@v3 30 | - name: Cache Gradle packages 31 | uses: actions/cache@v3 32 | with: 33 | path: | 34 | ~/.gradle 35 | ~/.m2 36 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 37 | restore-keys: ${{ runner.os }}-gradle 38 | # Runs a single command using the runners shell 39 | - run: chmod 777 ./gradlew && chmod +x ./litespeed/lite 40 | - name: execute gradle test 41 | run: ./gradlew :test --tests "me.leon.NodeCrawler.crawl" 42 | - run: git config --global user.email "actions@github.com" &&git config --global user.name "GitHub Actions" 43 | - run: chmod 777 ./up.sh && ./up.sh 44 | 45 | -------------------------------------------------------------------------------- /.github/workflows/detekt-analysis.yml: -------------------------------------------------------------------------------- 1 | # This workflow performs a static analysis of your Kotlin source code using 2 | # Detekt. 3 | # 4 | # Scans are triggered: 5 | # 1. On every push to default and protected branches 6 | # 2. On every Pull Request targeting the default branch 7 | # 3. On a weekly schedule 8 | # 4. Manually, on demand, via the "workflow_dispatch" event 9 | # 10 | # The workflow should work with no modifications, but you might like to use a 11 | # later version of the Detekt CLI by modifying the $DETEKT_RELEASE_TAG 12 | # environment variable. 13 | name: Scan with Detekt 14 | 15 | on: 16 | # Triggers the workflow on push or pull request events but only for default and protected branches 17 | push: 18 | branches: [ main ] 19 | paths-ignore: 20 | - 'sub/**' 21 | - '**.md' 22 | - '**.json' 23 | - '**.yml' 24 | pull_request: 25 | branches: [ main ] 26 | paths-ignore: 27 | - 'sub/**' 28 | - '**.md' 29 | - '**.json' 30 | - '**.yml' 31 | 32 | # Allows you to run this workflow manually from the Actions tab 33 | workflow_dispatch: 34 | 35 | env: 36 | # Release tag associated with version of Detekt to be installed 37 | # SARIF support (required for this workflow) was introduced in Detekt v1.15.0 38 | DETEKT_RELEASE_TAG: v1.15.0 39 | 40 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 41 | jobs: 42 | # This workflow contains a single job called "scan" 43 | scan: 44 | name: Scan 45 | # The type of runner that the job will run on 46 | runs-on: ubuntu-latest 47 | 48 | # Steps represent a sequence of tasks that will be executed as part of the job 49 | steps: 50 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 51 | - uses: actions/checkout@v3 52 | 53 | # Gets the download URL associated with the $DETEKT_RELEASE_TAG 54 | - name: Get Detekt download URL 55 | id: detekt_info 56 | env: 57 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | run: | 59 | gh api graphql --field tagName=$DETEKT_RELEASE_TAG --raw-field query=' 60 | query getReleaseAssetDownloadUrl($tagName: String!) { 61 | repository(name: "detekt", owner: "detekt") { 62 | release(tagName: $tagName) { 63 | releaseAssets(name: "detekt", first: 1) { 64 | nodes { 65 | downloadUrl 66 | } 67 | } 68 | tagCommit { 69 | oid 70 | } 71 | } 72 | } 73 | } 74 | ' 1> gh_response.json 75 | DETEKT_DOWNLOAD_URL=$(jq --raw-output '.data.repository.release.releaseAssets.nodes[0].downloadUrl' gh_response.json) 76 | echo "::set-output name=download_url::$DETEKT_DOWNLOAD_URL" 77 | 78 | # Sets up the detekt cli 79 | - name: Setup Detekt 80 | run: | 81 | dest=$( mktemp -d ) 82 | curl --request GET \ 83 | --url ${{ steps.detekt_info.outputs.download_url }} \ 84 | --silent \ 85 | --location \ 86 | --output $dest/detekt 87 | chmod a+x $dest/detekt 88 | echo $dest >> $GITHUB_PATH 89 | 90 | # Performs static analysis using Detekt 91 | - name: Run Detekt 92 | continue-on-error: true 93 | run: | 94 | detekt --input ${{ github.workspace }} --report sarif:${{ github.workspace }}/detekt.sarif.json 95 | 96 | # Modifies the SARIF output produced by Detekt so that absolute URIs are relative 97 | # This is so we can easily map results onto their source files 98 | # This can be removed once relative URI support lands in Detekt: https://git.io/JLBbA 99 | - name: Make artifact location URIs relative 100 | continue-on-error: true 101 | run: | 102 | echo "$( 103 | jq \ 104 | --arg github_workspace ${{ github.workspace }} \ 105 | '. | ( .runs[].results[].locations[].physicalLocation.artifactLocation.uri |= if test($github_workspace) then .[($github_workspace | length | . + 1):] else . end )' \ 106 | ${{ github.workspace }}/detekt.sarif.json 107 | )" > ${{ github.workspace }}/detekt.sarif.json 108 | 109 | # Uploads results to GitHub repository using the upload-sarif action 110 | - uses: github/codeql-action/upload-sarif@v2 111 | with: 112 | # Path to SARIF file relative to the root of the repository 113 | sarif_file: ${{ github.workspace }}/detekt.sarif.json 114 | checkout_path: ${{ github.workspace }} -------------------------------------------------------------------------------- /.github/workflows/domain-resolve.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: domain-resolve 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | schedule: 9 | # # 定时任务 10 | - cron: '0 4 1/2 * *' 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 16 | jobs: 17 | # This workflow contains a single job called "build" 18 | build: 19 | # The type of runner that the job will run on 20 | runs-on: ubuntu-latest 21 | 22 | # Steps represent a sequence of tasks that will be executed as part of the job 23 | steps: 24 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 25 | - uses: actions/checkout@v3 26 | - name: Cache Gradle packages 27 | uses: actions/cache@v3 28 | with: 29 | path: | 30 | ~/.gradle 31 | ~/.m2 32 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 33 | restore-keys: ${{ runner.os }}-gradle 34 | # Runs a single command using the runners shell 35 | - run: chmod 777 ./gradlew 36 | - run: sudo timedatectl set-timezone Asia/Shanghai 37 | - name: execute gradle test 38 | run: ./gradlew :test --tests "me.leon.ip.HostsTest.dns" 39 | - run: git config --global user.email "actions@github.com" &&git config --global user.name "GitHub Actions" 40 | - run: chmod 777 ./up.sh && ./up.sh 41 | 42 | -------------------------------------------------------------------------------- /.github/workflows/qodana.yml: -------------------------------------------------------------------------------- 1 | name: Qodana - Code Inspection 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | qodana: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | 12 | - name: Cache Qodana dependencies 13 | uses: actions/cache@v3 14 | with: 15 | path: ~/work/_temp/_github_home/qodana-cache 16 | key: ${{ runner.os }}-qodana-${{ github.ref }} 17 | restore-keys: | 18 | ${{ runner.os }}-qodana-${{ github.ref }} 19 | ${{ runner.os }}-qodana- 20 | 21 | - name: Qodana - Code Inspection 22 | uses: JetBrains/qodana-action@v2.2.1-eap 23 | 24 | - uses: actions/upload-artifact@v3 25 | with: 26 | path: ${{ github.workspace }}/qodana -------------------------------------------------------------------------------- /.github/workflows/resortIp.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: resort 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | # schedule: 9 | # 定时任务 10 | # - cron: '0 0 3 * *' 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 16 | jobs: 17 | # This workflow contains a single job called "build" 18 | build: 19 | # The type of runner that the job will run on 20 | runs-on: ubuntu-latest 21 | 22 | # Steps represent a sequence of tasks that will be executed as part of the job 23 | steps: 24 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 25 | - uses: actions/checkout@v3 26 | # Gradle 缓存配置 https://docs.github.com/cn/actions/using-workflows/caching-dependencies-to-speed-up-workflows 27 | # GitHub 将删除 7 天内未被访问的任何缓存条目。 可以存储的缓存数没有限制,但大小10 GB 28 | - name: Cache Gradle packages 29 | uses: actions/cache@v3 30 | with: 31 | path: | 32 | ~/.gradle 33 | ~/.m2 34 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 35 | restore-keys: ${{ runner.os }}-gradle 36 | # Runs a single command using the runners shell 37 | - run: chmod 777 ./gradlew 38 | - name: execute gradle test 39 | run: ./gradlew :test --tests "me.leon.ip.IpFilterTest.reTestFailIps" 40 | - run: git config --global user.email "actions@github.com" &&git config --global user.name "GitHub Actions" 41 | - run: chmod 777 ./up.sh && ./up.sh 42 | 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /.gradle/ 3 | /build 4 | /.idea 5 | /out 6 | speedtest.txt 7 | pools 8 | config.json 9 | sub/share/available 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

访客数 :eyes:

2 | 3 |

4 | Sub :: Visitor's Count 5 | Leon406:: Visitor's Count 6 |

7 | 8 | ![Repo size](https://img.shields.io/github/repo-size/leon406/subcrawler) 9 | 10 | ## [Telegram群组](https://t.me/freenodeshare) 11 | 12 | ## 节点池搭建 13 | 14 | > 有服务器的可自行搭建 [proxypool](https://github.com/Leon406/proxypool) 配置文件 [source.yaml](https://github.com/Leon406/proxypool/blob/master/config/source.yaml) 15 | 16 | ## 订阅转换 17 | 18 | - [:star:本地搭建 推荐](https://github.com/tindy2013/subconverter/releases) 19 | - [github acl4ssr-sub](https://acl4ssr-sub.github.io/) 20 | - [sub v1](https://sub.v1.mk/) 21 | - [品云](https://id9.cc/) 22 | - [肥羊转换](https://sub.mcwy.cloud/) 23 | 24 | 25 | ## 节点测速 26 | 27 | - 本地测速 28 | - [stairspeedtest-reborn](https://github.com/tindy2013/stairspeedtest-reborn) 29 | - [:star:LiteSpeedTest](https://github.com/xxf098/LiteSpeedTest) 30 | - [nodescatch ](https://github.com/bulianglin/demo) [个人组件更新版 提取码 8c0d](https://leon.lanzoub.com/b0db6sooh#8c0d) 31 | 32 | - 在线测速(基于上面本地测速搭建的服务,建议自行搭建,目前大部分都挂了) 33 | 34 | - 国内自有服务器Linux测速,使用litespeed 35 | 36 | ``` 37 | # litespeed测速,建议关闭网速测试 38 | ./lite --config config.json --test 生成链接 39 | # 复制到静态nginx资源路径 40 | cp output.txt /usr/share/nginx/res/nodes.txt 41 | # base64编码,生成v2ray订阅 42 | base64 /usr/share/nginx/res/nodes.txt > /usr/share/nginx/res/node.txt 43 | 44 | ``` 45 | 46 | 参考config.json 配置 47 | 48 | ``` 49 | 50 | { 51 | "group": "Default", 52 | "speedtestMode": "pingonly", 53 | "pingMethod": "googleping", 54 | "sortMethod": "rspeed", 55 | "concurrency": 1024, 56 | "testMode": 2, 57 | "timeout": 5, 58 | "fontSize": 24, 59 | "outputMode": 4, 60 | "unique": true, 61 | "language": "en", 62 | "theme": "rainbow" 63 | } 64 | ``` 65 | 66 | 67 | 68 | 69 | 70 | ## 节点过滤 71 | 72 | 删除以下可能存在测速问题的节点 73 | 74 | - SSR 75 | - none 76 | - rc4 77 | - rc4-md5 78 | - SS 79 | - aes-128-cfb 80 | - aes-256-cfb 81 | - rc4-md5 82 | - VMESS 83 | - none 84 | - grpc 85 | - h2 86 | - auto 87 | 88 | ## 项目生成内容 89 | 90 | ### 节点 91 | 92 | - github action ( [节点详情](./sub/info.md) ) 93 | - [vless](https://raw.githubusercontent.com/Leon406/SubCrawler/master/sub/share/vless) 未测速 (litespeed不支持) 94 | - [hysteria2](https://raw.githubusercontent.com/Leon406/SubCrawler/master/sub/share/hysteria2) 未测速 (litespeed不支持) 95 | - [其他合并](https://raw.githubusercontent.com/Leon406/SubCrawler/main/sub/share/a11) 96 | 97 | 98 | - 本地构建 (github action 节点测试为国外服务器,国内不保证能用,**建议使用本地二次测速筛选后使用**) 99 | 100 | ``` 101 | ## windows系统执行 102 | localFilter.bat 103 | ## Linux /Mac OS系统执行 104 | bash localFilter 105 | ## 或者 106 | chmod +x localFilter && ./localFilter 107 | ``` 108 | 109 | 110 | 111 | 112 | > 默认生成的为base64编码(v2rayN/ss/ssr等客户端可直接使用),其他请自行使用[订阅转换](#subCon)进行转换 113 | 114 | ### Hosts 115 | 116 | - [广告屏蔽hosts](https://raw.fastgit.org/Leon406/SubCrawler/master/sub/share/blackhosts) 117 | - [googlehosts重筛](https://raw.fastgit.org/Leon406/SubCrawler/master/sub/share/whitehost) 118 | - [github及常用域名](https://raw.fastgit.org/Leon406/SubCrawler/master/sub/share/host) 119 | 120 | ## 走代理后ip匿名检测 121 | 122 | - https://bgp.he.net/ 123 | - https://browserleaks.com/ 124 | - https://ip.voidsec.com/ 125 | - https://ipinfo.io/ 126 | - https://ipleak.com/ 127 | - https://ipleak.net/ 128 | - https://ipleak.org/ 129 | - https://ipx.ac/run 130 | - https://nstool.netease.com/ 131 | - https://test-ipv6.com/ 132 | - https://whatismyipaddress.com/blacklist-check 133 | - https://whoer.net/ 134 | - https://www.astrill.com/dns-leak-test 135 | - https://www.astrill.com/ipv6-leak-test 136 | - https://www.astrill.com/port-scan 137 | - https://www.astrill.com/vpn-leak-test 138 | - https://www.astrill.com/what-is-my-ip 139 | - https://www.deviceinfo.me/ 140 | - https://www.dnsleaktest.com/ 141 | - https://www.doileak.com/ 142 | - https://www.expressvpn.com/webrtc-leak-test 143 | 144 | 145 | ## 使用软件 146 | 147 | | 平台 | 软件 | 支持协议 | 148 | | ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 149 | | Win/Mac/Linux | [GUI.for.SingBox](https://github.com/GUI-for-Cores/GUI.for.SingBox) | sing-box支持全协议 | 150 | | Win/Mac/Linux | [clash-verge-rev](https://github.com/clash-verge-rev/clash-verge-rev) | clash meta 支持协议 | 151 | | Windows | [V2rayN **(推荐)**](https://github.com/2dust/v2rayN/releases) | SS、Trojan、Vmess、VLESS | 152 | | Windows | [Clash CFW ](https://github.com/Fndroid/clash_for_windows_pkg/releases)
[Clash-for-Windows_Chinese (汉化修改版)](https://github.com/Z-Siqi/Clash-for-Windows_Chinese) | SS、SSR、Trojan、Vmess、VLESS | 153 | | macOS | [V2rayU](https://github.com/yanue/V2rayU/releases) | SS、SSR、Trojan、V2ray | 154 | | Android | [V2rayNG](https://github.com/2dust/v2rayNG/releases) | SS、Trojan、V2ray(Vmess、VLESS)、Xray | 155 | | Android | [ClashForAndroid ](https://github.com/Kr328/ClashForAndroid/releases) 已G自行搜索安装包
[ClashMetaForAndroid **(推荐)**](https://github.com/MetaCubeX/ClashMetaForAndroid) | SS、SSR、Trojan、Vmess、VLESS | 156 | | Android | [NekoBoxForAndroid **(推荐)**](https://github.com/MatsuriDayo/NekoBoxForAndroid) | VMess / VLESS / SSR / Trojan / Trojan-Go/ NaiveProxy / HTTP(S) / SOCKS5/etc. | 157 | | Android | [ClashMetaForAndroid](https://github.com/MetaCubeX/ClashMetaForAndroid) | clash meta 支持协议 | 158 | | IOS | Shadowrocket 小火箭 IOS非国区购买 | SS、SSR、Trojan、V2ray、VLESS | 159 | | IOS | Quantumult IOS非国区购买 | SS、SSR、Trojan、V2ray | 160 | | IOS | QuantumultX IOS非国区购买 | SS、SSR、Trojan、V2ray | 161 | 162 | 163 | 164 | ## Stargazers over time 165 | 166 | [![Stargazers over time](https://starchart.cc/Leon406/SubCrawler.svg)](https://starchart.cc/Leon406/SubCrawler) 167 | 168 | ## 声明 169 | 170 | 本项目仅限个人自己使用,禁止使用本项目进行营利和做其他违法事情,产生的一切后果本项目概不负责 171 | 172 | [回到顶部](#top) 173 | 174 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id "org.jetbrains.kotlin.jvm" version "2.1.0" 4 | id "com.diffplug.spotless" version "6.25.0" 5 | id "io.gitlab.arturbosch.detekt" version "1.23.6" 6 | } 7 | 8 | group 'me.leon' 9 | version '1.3.0' 10 | 11 | dependencies { 12 | detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:1.23.6" 13 | implementation 'org.jetbrains.kotlin:kotlin-stdlib' 14 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1' 15 | implementation 'com.google.code.gson:gson:2.11.0' 16 | //for yaml 1.1, 1.32 limit maxsize 3M 17 | implementation 'org.yaml:snakeyaml:2.2' 18 | //mmdb格式 19 | implementation 'com.maxmind.geoip2:geoip2:4.2.1' 20 | //dat格式 21 | // implementation 'com.maxmind.geoip:geoip-api:1.3.1' 22 | // implementation 'com.maxmind.db:maxmind-db:1.2.0' 23 | //for yaml 1.2 24 | // implementation "org.snakeyaml:snakeyaml-engine:2.3" 25 | 26 | // https://mvnrepository.com/artifact/org.jsoup/jsoup 27 | implementation 'org.jsoup:jsoup:1.18.3' 28 | 29 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.4' 30 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.4' 31 | } 32 | 33 | test { 34 | useJUnitPlatform() 35 | } 36 | apply from: "$rootProject.projectDir/config/codeQuality.gradle" 37 | def hook = new File("$rootProject.projectDir/.git/hooks/pre-commit") 38 | hook.parentFile.mkdirs() 39 | hook.text = """#!/bin/bash 40 | echo "run code format" 41 | ./gradlew spotlessCheck 42 | echo "run code smell check" 43 | ./gradlew detekt 44 | """ -------------------------------------------------------------------------------- /config/codeQuality.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.diffplug.spotless' 2 | apply plugin: 'io.gitlab.arturbosch.detekt' 3 | detekt { 4 | allRules = false // activate all available (even unstable) rules. 5 | // https://github.com/detekt/detekt/blob/main/config/detekt/detekt.yml 6 | config = files("$rootProject.projectDir/config/detekt.yml") 7 | // point to your custom config defining rules to run, overwriting default behavior 8 | parallel = true 9 | input = files( 10 | "$rootDir/buildSrc", 11 | "$rootDir/build.gradle.kts", 12 | "$rootDir/build.gradle", 13 | "$rootDir/settings.gradle.kts", 14 | "$rootDir/settings.gradle", 15 | "build.gradle.kts", 16 | "build.gradle", 17 | "src/main/kotlin", 18 | "src/test/kotlin" 19 | ) 20 | } 21 | 22 | spotless { 23 | java { 24 | target "src/**/*.java" 25 | // https://github.com/google/google-java-format/releases 26 | googleJavaFormat('1.15.0').aosp() 27 | } 28 | kotlin { 29 | target "src/**/*.kt" 30 | // https://github.com/facebookincubator/ktfmt/releases 31 | ktfmt('0.53').kotlinlangStyle() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /config/detekt.yml: -------------------------------------------------------------------------------- 1 | comments: 2 | active: true 3 | AbsentOrWrongFileLicense: 4 | active: false 5 | licenseTemplateFile: 'license.template' 6 | licenseTemplateIsRegex: false 7 | CommentOverPrivateFunction: 8 | active: false 9 | CommentOverPrivateProperty: 10 | active: false 11 | DeprecatedBlockTag: 12 | active: false 13 | EndOfSentenceFormat: 14 | active: false 15 | endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' 16 | UndocumentedPublicClass: 17 | active: false 18 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 19 | searchInNestedClass: true 20 | searchInInnerClass: true 21 | searchInInnerObject: true 22 | searchInInnerInterface: true 23 | UndocumentedPublicFunction: 24 | active: false 25 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 26 | UndocumentedPublicProperty: 27 | active: false 28 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 29 | 30 | complexity: 31 | active: true 32 | ComplexCondition: 33 | active: true 34 | threshold: 4 35 | StringLiteralDuplication: 36 | active: true 37 | excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] 38 | threshold: 5 39 | ignoreAnnotation: true 40 | excludeStringsWithLessThan5Characters: true 41 | ignoreStringsRegex: '$^' 42 | 43 | ComplexInterface: 44 | active: true 45 | threshold: 10 46 | includeStaticDeclarations: false 47 | includePrivateDeclarations: false 48 | CyclomaticComplexMethod: 49 | active: true 50 | threshold: 16 51 | ignoreSingleWhenExpression: true 52 | ignoreSimpleWhenEntries: true 53 | ignoreNestingFunctions: true 54 | nestingFunctions: 55 | - 'run' 56 | - 'let' 57 | - 'apply' 58 | - 'with' 59 | - 'also' 60 | - 'use' 61 | - 'forEach' 62 | - 'isNotNull' 63 | - 'ifNull' 64 | LargeClass: 65 | active: false 66 | threshold: 600 67 | excludes: ['**/test/**', '**/*.Test.kt', '**/*.Spec.kt'] 68 | MethodOverloading: 69 | active: true 70 | TooManyFunctions: 71 | active: true 72 | excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] 73 | thresholdInFiles: 24 74 | thresholdInClasses: 24 75 | thresholdInInterfaces: 24 76 | thresholdInObjects: 22 77 | thresholdInEnums: 24 78 | ignoreDeprecated: true 79 | ignorePrivate: true 80 | ignoreOverridden: true 81 | 82 | LongMethod: 83 | active: true 84 | threshold: 75 85 | ignoreAnnotated: [ ] 86 | LongParameterList: 87 | active: true 88 | functionThreshold: 10 89 | constructorThreshold: 8 90 | ignoreDefaultParameters: false 91 | ignoreDataClasses: true 92 | ignoreAnnotated: [ ] 93 | NamedArguments: 94 | active: false 95 | threshold: 3 96 | NestedBlockDepth: 97 | active: false 98 | threshold: 4 99 | ReplaceSafeCallChainWithRun: 100 | active: false 101 | 102 | coroutines: 103 | active: true 104 | GlobalCoroutineUsage: 105 | active: true 106 | RedundantSuspendModifier: 107 | active: true 108 | SleepInsteadOfDelay: 109 | active: true 110 | SuspendFunWithFlowReturnType: 111 | active: true 112 | empty-blocks: 113 | active: true 114 | EmptyCatchBlock: 115 | active: true 116 | allowedExceptionNameRegex: '_|(ignore|expected).*' 117 | EmptyClassBlock: 118 | active: true 119 | EmptyDefaultConstructor: 120 | active: true 121 | EmptyDoWhileBlock: 122 | active: true 123 | EmptyElseBlock: 124 | active: true 125 | EmptyFinallyBlock: 126 | active: true 127 | EmptyForBlock: 128 | active: true 129 | EmptyFunctionBlock: 130 | active: true 131 | ignoreOverridden: false 132 | EmptyIfBlock: 133 | active: true 134 | EmptyInitBlock: 135 | active: true 136 | EmptyKtFile: 137 | active: true 138 | EmptySecondaryConstructor: 139 | active: true 140 | EmptyTryBlock: 141 | active: true 142 | EmptyWhenBlock: 143 | active: true 144 | EmptyWhileBlock: 145 | active: true 146 | 147 | exceptions: 148 | InstanceOfCheckForException: 149 | active: true 150 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 151 | NotImplementedDeclaration: 152 | active: false 153 | ObjectExtendsThrowable: 154 | active: true 155 | RethrowCaughtException: 156 | active: true 157 | ReturnFromFinally: 158 | active: true 159 | ThrowingExceptionFromFinally: 160 | active: true 161 | ThrowingExceptionInMain: 162 | active: true 163 | ThrowingExceptionsWithoutMessageOrCause: 164 | active: true 165 | excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] 166 | exceptions: 167 | - 'ArrayIndexOutOfBoundsException' 168 | - 'Error' 169 | - 'Exception' 170 | - 'IllegalMonitorStateException' 171 | - 'NullPointerException' 172 | - 'IndexOutOfBoundsException' 173 | - 'RuntimeException' 174 | - 'Throwable' 175 | ThrowingNewInstanceOfSameException: 176 | active: true 177 | SwallowedException: 178 | active: true 179 | ignoredExceptionTypes: 180 | - 'NumberFormatException' 181 | - 'InterruptedException' 182 | - 'ParseException' 183 | - 'MalformedURLException' 184 | - 'UnknownHostException' 185 | allowedExceptionNameRegex: '_|(ignore|expected).*' 186 | TooGenericExceptionCaught: 187 | active: true 188 | excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] 189 | exceptionNames: 190 | - 'ArrayIndexOutOfBoundsException' 191 | - 'Error' 192 | - 'Exception' 193 | - 'IllegalMonitorStateException' 194 | - 'NullPointerException' 195 | - 'IndexOutOfBoundsException' 196 | - 'RuntimeException' 197 | - 'Throwable' 198 | allowedExceptionNameRegex: '_|(ignore|expected).*' 199 | TooGenericExceptionThrown: 200 | active: true 201 | exceptionNames: 202 | - 'Error' 203 | - 'Exception' 204 | - 'Throwable' 205 | - 'RuntimeException' 206 | 207 | naming: 208 | ClassNaming: 209 | excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] 210 | classPattern: '[A-Z][a-zA-Z0-9]*' 211 | ConstructorParameterNaming: 212 | active: true 213 | excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] 214 | parameterPattern: '[a-z][A-Za-z0-9]*' 215 | privateParameterPattern: '[a-z][A-Za-z0-9]*' 216 | excludeClassPattern: '$^' 217 | ignoreOverridden: true 218 | EnumNaming: 219 | active: true 220 | excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] 221 | enumEntryPattern: '[A-Z][_a-zA-Z0-9]*|`.*`' 222 | ForbiddenClassName: 223 | active: false 224 | excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] 225 | forbiddenName: [ ] 226 | FunctionNaming: 227 | active: true 228 | excludes: 229 | - '**/test/**' 230 | - '**/androidTest/**' 231 | - '**/commonTest/**' 232 | - '**/functionalTest/**' 233 | - '**/jvmTest/**' 234 | - '**/jsTest/**' 235 | - '**/iosTest/**' 236 | TopLevelPropertyNaming: 237 | constantPattern: '[a-z][_A-Za-z0-9]*|[A-Z][_A-Z0-9]*' 238 | InvalidPackageDeclaration: 239 | active: true 240 | excludes: ['**/build-logic/**/*.kt', '**/*.kts'] 241 | NoNameShadowing: 242 | active: false 243 | NonBooleanPropertyPrefixedWithIs: 244 | active: true 245 | VariableMaxLength: 246 | active: true 247 | VariableMinLength: 248 | active: true 249 | 250 | performance: 251 | active: true 252 | ArrayPrimitive: 253 | active: true 254 | ForEachOnRange: 255 | active: true 256 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 257 | SpreadOperator: 258 | active: true 259 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 260 | UnnecessaryTemporaryInstantiation: 261 | active: true 262 | 263 | potential-bugs: 264 | active: true 265 | AvoidReferentialEquality: 266 | active: true 267 | DontDowncastCollectionTypes: 268 | active: true 269 | DoubleMutabilityForCollection: 270 | active: false 271 | ElseCaseInsteadOfExhaustiveWhen: 272 | active: true 273 | ExitOutsideMain: 274 | active: false 275 | HasPlatformType: 276 | active: true 277 | IgnoredReturnValue: 278 | active: true 279 | restrictToConfig: true 280 | returnValueAnnotations: 281 | - '*.CheckReturnValue' 282 | - '*.CheckResult' 283 | ImplicitUnitReturnType: 284 | active: true 285 | MapGetWithNotNullAssertionOperator: 286 | active: false 287 | UnconditionalJumpStatementInLoop: 288 | active: true 289 | UnsafeCast: 290 | active: true 291 | excludes: ['**/test/**', '**/*.Test.kt', '**/*.Spec.kt'] 292 | UselessPostfixExpression: 293 | active: true 294 | CastToNullableType: 295 | active: false 296 | Deprecation: 297 | active: false 298 | style: 299 | CanBeNonNullable: 300 | active: false 301 | CascadingCallWrapping: 302 | active: true 303 | ClassOrdering: 304 | active: true 305 | CollapsibleIfStatements: 306 | active: true 307 | DestructuringDeclarationWithTooManyEntries: 308 | active: true 309 | EqualsOnSignatureLine: 310 | active: true 311 | ExplicitCollectionElementAccessMethod: 312 | active: true 313 | ExplicitItLambdaParameter: 314 | active: true 315 | ForbiddenComment: 316 | active: true 317 | values: 318 | - 'TODO:' 319 | - 'FIXME:' 320 | - 'STOPSHIP:' 321 | - '@author' 322 | - '@requiresTypeResolution' 323 | excludes: ['**/detekt-rules-style/**/ForbiddenComment.kt'] 324 | ForbiddenImport: 325 | active: true 326 | imports: 327 | - value: 'org.assertj.core.api.Assertions' 328 | reason: 'Import Assertions.assertThat instead.' 329 | - value: 'org.junit.jupiter.api.Assertions*' 330 | reason: 'Use AssertJ assertions instead.' 331 | ForbiddenMethodCall: 332 | active: false 333 | methods: 334 | - 'kotlin.io.print' 335 | - 'kotlin.io.println' 336 | - 'java.net.URL.openStream' 337 | - 'java.lang.Class.getResourceAsStream' 338 | - 'java.lang.ClassLoader.getResourceAsStream' 339 | - 'org.jetbrains.kotlin.diagnostics.DiagnosticUtils.getLineAndColumnInPsiFile' 340 | 341 | ForbiddenVoid: 342 | active: true 343 | MagicNumber: 344 | excludes: ['**/test/**', '**/*Test.kt', '**/*Spec.kt'] 345 | ignorePropertyDeclaration: true 346 | ignoreAnnotation: true 347 | ignoreEnums: true 348 | ignoreNumbers: 349 | - '-1' 350 | - '0' 351 | - '1' 352 | - '2' 353 | - '100' 354 | - '1000' 355 | MandatoryBracesLoops: 356 | active: true 357 | MaxLineLength: 358 | active: true 359 | excludes: ['**/test/**', '**/*Test.kt', '**/*Spec.kt'] 360 | excludeCommentStatements: true 361 | NestedClassesVisibility: 362 | active: true 363 | ObjectLiteralToLambda: 364 | active: true 365 | PreferToOverPairSyntax: 366 | active: true 367 | RedundantExplicitType: 368 | active: true 369 | RedundantHigherOrderMapUsage: 370 | active: true 371 | RedundantVisibilityModifierRule: 372 | active: true 373 | ReturnCount: 374 | active: true 375 | excludeGuardClauses: true 376 | SpacingBetweenPackageAndImports: 377 | active: true 378 | TrimMultilineRawString: 379 | active: true 380 | UnderscoresInNumericLiterals: 381 | active: true 382 | UnnecessaryAnnotationUseSiteTarget: 383 | active: true 384 | UnnecessaryFilter: 385 | active: true 386 | UnnecessaryLet: 387 | active: true 388 | UnnecessaryInnerClass: 389 | active: true 390 | ignoreAnnotated: ['Nested'] 391 | UntilInsteadOfRangeTo: 392 | active: true 393 | UnusedImports: 394 | active: false # formatting already have this rule enabled 395 | UnusedPrivateMember: 396 | active: true 397 | allowedNames: '(_|ignored|expected)' 398 | UseAnyOrNoneInsteadOfFind: 399 | active: true 400 | UseCheckOrError: 401 | active: true 402 | UseEmptyCounterpart: 403 | active: true 404 | UseIfEmptyOrIfBlank: 405 | active: true 406 | UseIsNullOrEmpty: 407 | active: true 408 | UseOrEmpty: 409 | active: true 410 | UseRequire: 411 | active: true 412 | UseRequireNotNull: 413 | active: true 414 | VarCouldBeVal: 415 | active: true 416 | ignoreAnnotated: ['Parameter'] 417 | formatting: 418 | active: true 419 | android: false 420 | autoCorrect: true 421 | AnnotationOnSeparateLine: 422 | active: false 423 | autoCorrect: true 424 | AnnotationSpacing: 425 | active: false 426 | autoCorrect: true 427 | ArgumentListWrapping: 428 | active: false 429 | autoCorrect: true 430 | indentSize: 4 431 | maxLineLength: 120 432 | ChainWrapping: 433 | active: true 434 | autoCorrect: true 435 | CommentSpacing: 436 | active: true 437 | autoCorrect: true 438 | EnumEntryNameCase: 439 | active: false 440 | autoCorrect: true 441 | Filename: 442 | active: false 443 | FunctionReturnTypeSpacing: 444 | active: true 445 | FunctionStartOfBodySpacing: 446 | active: true 447 | FinalNewline: 448 | active: true 449 | autoCorrect: true 450 | insertFinalNewLine: true 451 | ImportOrdering: 452 | active: false 453 | autoCorrect: true 454 | layout: '*,java.**,javax.**,kotlin.**,^' 455 | Indentation: 456 | active: false 457 | autoCorrect: true 458 | indentSize: 4 459 | MaximumLineLength: 460 | active: true 461 | maxLineLength: 120 462 | ignoreBackTickedIdentifier: false 463 | NullableTypeSpacing: 464 | active: true 465 | ParameterListSpacing: 466 | active: true 467 | SpacingBetweenFunctionNameAndOpeningParenthesis: 468 | active: true 469 | TypeParameterListSpacing: 470 | active: true 471 | ModifierOrdering: 472 | active: true 473 | autoCorrect: true 474 | MultiLineIfElse: 475 | active: true 476 | autoCorrect: true 477 | NoBlankLineBeforeRbrace: 478 | active: true 479 | autoCorrect: true 480 | NoConsecutiveBlankLines: 481 | active: true 482 | autoCorrect: true 483 | NoEmptyClassBody: 484 | active: true 485 | autoCorrect: true 486 | NoEmptyFirstLineInMethodBlock: 487 | active: false 488 | autoCorrect: true 489 | NoLineBreakAfterElse: 490 | active: true 491 | autoCorrect: true 492 | NoLineBreakBeforeAssignment: 493 | active: true 494 | autoCorrect: true 495 | NoMultipleSpaces: 496 | active: true 497 | autoCorrect: true 498 | NoSemicolons: 499 | active: true 500 | autoCorrect: true 501 | NoTrailingSpaces: 502 | active: true 503 | autoCorrect: true 504 | NoUnitReturn: 505 | active: true 506 | autoCorrect: true 507 | NoUnusedImports: 508 | active: true 509 | autoCorrect: true 510 | WildcardImport: 511 | active: true 512 | excludeImports: [] 513 | PackageName: 514 | active: true 515 | autoCorrect: true 516 | ParameterListWrapping: 517 | active: true 518 | autoCorrect: true 519 | maxLineLength: 120 520 | SpacingAroundAngleBrackets: 521 | active: false 522 | autoCorrect: true 523 | SpacingAroundColon: 524 | active: true 525 | autoCorrect: true 526 | SpacingAroundComma: 527 | active: true 528 | autoCorrect: true 529 | SpacingAroundCurly: 530 | active: true 531 | autoCorrect: true 532 | SpacingAroundDot: 533 | active: true 534 | autoCorrect: true 535 | SpacingAroundDoubleColon: 536 | active: false 537 | autoCorrect: true 538 | SpacingAroundKeyword: 539 | active: true 540 | autoCorrect: true 541 | SpacingAroundOperators: 542 | active: true 543 | autoCorrect: true 544 | SpacingAroundParens: 545 | active: true 546 | autoCorrect: true 547 | SpacingAroundRangeOperator: 548 | active: true 549 | autoCorrect: true 550 | SpacingAroundUnaryOperator: 551 | active: false 552 | autoCorrect: true 553 | SpacingBetweenDeclarationsWithAnnotations: 554 | active: false 555 | autoCorrect: true 556 | SpacingBetweenDeclarationsWithComments: 557 | active: false 558 | autoCorrect: true 559 | StringTemplate: 560 | active: true 561 | autoCorrect: true 562 | TrailingCommaOnCallSite: 563 | active: false 564 | autoCorrect: true 565 | useTrailingCommaOnCallSite: false 566 | TrailingCommaOnDeclarationSite: 567 | active: false 568 | autoCorrect: true 569 | useTrailingCommaOnDeclarationSite: false 570 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leon406/SubCrawler/b5029d06271b595e5872a7e5635d1723b9697815/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 134 | 135 | Please set the JAVA_HOME variable in your environment to match the 136 | location of your Java installation." 137 | fi 138 | 139 | # Increase the maximum file descriptors if we can. 140 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 141 | case $MAX_FD in #( 142 | max*) 143 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 144 | # shellcheck disable=SC3045 145 | MAX_FD=$( ulimit -H -n ) || 146 | warn "Could not query maximum file descriptor limit" 147 | esac 148 | case $MAX_FD in #( 149 | '' | soft) :;; #( 150 | *) 151 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 152 | # shellcheck disable=SC3045 153 | ulimit -n "$MAX_FD" || 154 | warn "Could not set maximum file descriptor limit to $MAX_FD" 155 | esac 156 | fi 157 | 158 | # Collect all arguments for the java command, stacking in reverse order: 159 | # * args from the command line 160 | # * the main class name 161 | # * -classpath 162 | # * -D...appname settings 163 | # * --module-path (only if needed) 164 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 165 | 166 | # For Cygwin or MSYS, switch paths to Windows format before running java 167 | if "$cygwin" || "$msys" ; then 168 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 169 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 170 | 171 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 172 | 173 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 174 | for arg do 175 | if 176 | case $arg in #( 177 | -*) false ;; # don't mess with options #( 178 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 179 | [ -e "$t" ] ;; #( 180 | *) false ;; 181 | esac 182 | then 183 | arg=$( cygpath --path --ignore --mixed "$arg" ) 184 | fi 185 | # Roll the args list around exactly as many times as the number of 186 | # args, so each arg winds up back in the position where it started, but 187 | # possibly modified. 188 | # 189 | # NB: a `for` loop captures its iteration list before it begins, so 190 | # changing the positional parameters here affects neither the number of 191 | # iterations, nor the values presented in `arg`. 192 | shift # remove old arg 193 | set -- "$@" "$arg" # push replacement arg 194 | done 195 | fi 196 | 197 | 198 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 199 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 200 | 201 | # Collect all arguments for the java command; 202 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 203 | # shell script including quotes and variable substitutions, so put them in 204 | # double quotes to make sure that they get re-expanded; and 205 | # * put everything else in single quotes, so that it's not re-expanded. 206 | 207 | set -- \ 208 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 209 | -classpath "$CLASSPATH" \ 210 | org.gradle.wrapper.GradleWrapperMain \ 211 | "$@" 212 | 213 | # Stop when "xargs" is not available. 214 | if ! command -v xargs >/dev/null 2>&1 215 | then 216 | die "xargs is not available" 217 | fi 218 | 219 | # Use "xargs" to parse quoted args. 220 | # 221 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 222 | # 223 | # In Bash we could simply go: 224 | # 225 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 226 | # set -- "${ARGS[@]}" "$@" 227 | # 228 | # but POSIX shell has neither arrays nor command substitution, so instead we 229 | # post-process each arg (as a line of input to sed) to backslash-escape any 230 | # character that might be a shell metacharacter, then use eval to reverse 231 | # that process (while maintaining the separation between arguments), and wrap 232 | # the whole thing up as a single "set" statement. 233 | # 234 | # This will of course break if any of these variables contains a newline or 235 | # an unmatched quote. 236 | # 237 | 238 | eval "set -- $( 239 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 240 | xargs -n1 | 241 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 242 | tr '\n' ' ' 243 | )" '"$@"' 244 | 245 | exec "$JAVACMD" "$@" 246 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /litespeed/lite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leon406/SubCrawler/b5029d06271b595e5872a7e5635d1723b9697815/litespeed/lite -------------------------------------------------------------------------------- /litespeed/lite.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leon406/SubCrawler/b5029d06271b595e5872a7e5635d1723b9697815/litespeed/lite.exe -------------------------------------------------------------------------------- /localFilter: -------------------------------------------------------------------------------- 1 | ./gradlew :test --tests "me.leon.NodeCrawler.crawl" -------------------------------------------------------------------------------- /localFilter.bat: -------------------------------------------------------------------------------- 1 | gradlew :test --tests "me.leon.NodeCrawler.crawl" -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenLocal() 4 | maven { url = uri("https://mirrors.tencent.com/nexus/repository/maven-public") } 5 | maven { url = uri("https://mirrors.huaweicloud.com/repository/maven") } 6 | // 新库同步较慢, 降低优先级 7 | maven { url = uri("https://maven.aliyun.com/repository/public") } 8 | maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") } 9 | maven { url = uri("https://maven.aliyun.com/repository/google") } 10 | gradlePluginPortal() 11 | } 12 | } 13 | 14 | dependencyResolutionManagement { 15 | repositories { 16 | mavenLocal() 17 | maven { url = uri("https://mirrors.tencent.com/nexus/repository/maven-public") } 18 | maven { url = uri("https://mirrors.huaweicloud.com/repository/maven") } 19 | maven { url = uri("https://maven.aliyun.com/repository/public") } 20 | maven { url = uri("https://maven.aliyun.com/repository/google") } 21 | } 22 | } 23 | 24 | rootProject.name = 'SubCrawler' 25 | -------------------------------------------------------------------------------- /src/main/java/me/leon/Clash.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | /** Clash完整配置 https://github.com/Dreamacro/clash/wiki/configuration */ 4 | @Suppress("ConstructorParameterNaming") 5 | data class Clash( 6 | var proxies: List = mutableListOf(), 7 | ) 8 | 9 | @Suppress("ConstructorParameterNaming") 10 | data class Node( 11 | var name: String = "", 12 | var type: String = "", 13 | var cipher: String = "", 14 | var country: String = "", 15 | var obfs: String = "", 16 | var password: String = "", 17 | var port: Int = 0, 18 | var protocol: String = "", 19 | var uuid: String = "", 20 | var alterId: String = "", 21 | var network: String = "", 22 | var `protocol-param`: String = "", 23 | var server: String = "", 24 | var servername: String = "" 25 | ) { 26 | var `ws-headers`: LinkedHashMap = linkedMapOf() 27 | var `ws-path`: String = "" 28 | var `ws-opts`: VmessWsOpts = VmessWsOpts() 29 | 30 | var `obfs-param`: String = "" 31 | var obfs_param: String = "" 32 | var sni: String = "" 33 | var tls: Any = Any() 34 | 35 | var `skip-cert-verify`: Boolean = false 36 | var `protocol_param`: String = "" 37 | var protocolparam: String = "" 38 | var protoparam: String = "" 39 | var obfsparam: String = "" 40 | 41 | data class VmessWsOpts( 42 | var path: String = "", 43 | var headers: LinkedHashMap = linkedMapOf() 44 | ) 45 | 46 | private fun properPath() = if (network == "ws") `ws-path`.ifEmpty { `ws-opts`.path } else "" 47 | 48 | private fun properHost() = 49 | if (network == "ws") { 50 | `ws-headers`["Host"] 51 | ?: `ws-headers`["host"] ?: `ws-opts`.headers["Host"] 52 | ?: `ws-opts`.headers["host"].orEmpty() 53 | } else { 54 | "" 55 | } 56 | 57 | fun toNode(): Sub { 58 | // 兼容某些异常节点池 59 | if (server == "NULL") return NoSub 60 | return when (type) { 61 | "ss" -> toSs() 62 | "ssr" -> toSsr() 63 | "vmess" -> if (network == "grpc") NoSub else toVmess() 64 | "trojan" -> toTrojan() 65 | else -> NoSub 66 | } 67 | } 68 | 69 | private fun toTrojan() = 70 | Trojan(password, server, port.toString()).apply { 71 | this.remark = this@Node.name 72 | query = "allowInsecure=${if (`skip-cert-verify`) 1 else 0}&sni=$sni" 73 | nation = country 74 | } 75 | 76 | private fun toVmess() = 77 | V2ray( 78 | aid = alterId, 79 | add = server, 80 | port = port.toString(), 81 | id = uuid, 82 | net = network, 83 | ) 84 | .apply { 85 | tls = 86 | when (this@Node.tls) { 87 | is Boolean -> if (this@Node.tls as Boolean) "true" else "" 88 | is Int -> if (this@Node.tls as Int == 1) "true" else "" 89 | else -> "" 90 | } 91 | path = properPath() 92 | host = properHost() 93 | ps = this@Node.name 94 | nation = country 95 | } 96 | 97 | private fun toSsr() = 98 | SSR( 99 | server, 100 | port.toString(), 101 | protocol, 102 | cipher, 103 | obfs, 104 | password, 105 | if (obfs == "plain") "" else `obfs-param` + obfs_param + obfsparam, 106 | `protocol-param` + `protocol_param` + protocolparam + protoparam 107 | ) 108 | .apply { 109 | remarks = this@Node.name 110 | nation = country 111 | } 112 | 113 | private fun toSs() = 114 | SS(cipher, password, server, port.toString()).apply { 115 | remark = this@Node.name 116 | nation = country 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/me/leon/Config.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import java.io.File 4 | 5 | val ROOT: String = File("sub").absolutePath 6 | val SHARE = "$ROOT/share" 7 | val HOST = "$SHARE/host" 8 | 9 | // 本地节点池 10 | val POOL = "$ROOT/pools" 11 | 12 | val NODE_OK = "$SHARE/available" 13 | val NODE_SS = "$SHARE/ss" 14 | val NODE_SSR = "$SHARE/ssr" 15 | val NODE_V2 = "$SHARE/v2" 16 | val NODE_ALL = "$SHARE/a11" 17 | val NODE_TR = "$SHARE/tr" 18 | val NODE_VLESS = "$SHARE/vless" 19 | val NODE_HYS2 = "$SHARE/hysteria2" 20 | val FAIL_IPS = "$ROOT/socketfail" 21 | val IP_SCORE = "$ROOT/ipScore" 22 | -------------------------------------------------------------------------------- /src/main/java/me/leon/GeoParser.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import com.maxmind.db.CHMCache 4 | import com.maxmind.geoip2.DatabaseReader 5 | import java.net.InetAddress 6 | import me.leon.GeoParser.cityReader 7 | import me.leon.GeoParser.countryReader 8 | import me.leon.support.* 9 | 10 | object GeoParser { 11 | // register at https://www.maxmind.com/, and download your file 12 | // https://download.maxmind.com/geoip/databases/GeoLite2-Country/download?suffix=tar.gz 13 | // todo change it to your own file 14 | private const val geoDir = "C:/Users/Leon/Desktop/geo" 15 | private val dbFile = "$geoDir/GeoLite2-City.mmdb".toFile() 16 | private val dbCountryFile = javaClass.getResource("/GeoLite2-Country.mmdb").file.toFile() 17 | 18 | val cityReader: DatabaseReader by lazy { 19 | DatabaseReader.Builder(dbFile).withCache(CHMCache()).build() 20 | } 21 | val countryReader: DatabaseReader by lazy { 22 | DatabaseReader.Builder(dbCountryFile).withCache(CHMCache()).build() 23 | } 24 | } 25 | 26 | private const val CN = "zh-CN" 27 | 28 | fun String.ipCountryZh() = 29 | runCatching { countryReader.country(this.toInetAddress()).country.names[CN] } 30 | .getOrElse { 31 | println("ipCountryZh error ${it.message}") 32 | ipInfo() 33 | } ?: ipInfo() 34 | 35 | fun InetAddress.ipCountryZh() = 36 | runCatching { countryReader.country(this).country.names[CN] }.getOrDefault("未知") 37 | 38 | fun Sub.ipCountryZh(): String = 39 | runCatching { countryReader.country(SERVER.toInetAddress()).country.names[CN] } 40 | .getOrDefault(SERVER.ipInfo()) 41 | ?: SERVER.ipInfo() 42 | 43 | private fun String.ipInfo() = runCatching { "CF中转".takeIf { ipCloudFlare() } ?: "未知" }.getOrElse { "未知" } 44 | 45 | fun String.ipCountryEn(): String = 46 | runCatching { countryReader.country(this.toInetAddress()).country.isoCode } 47 | .getOrDefault("UNKNOWN") 48 | 49 | fun InetAddress.ipCountryEn(): String = 50 | runCatching { countryReader.country(this).country.isoCode }.getOrDefault("UNKNOWN") 51 | 52 | fun String.ipCityZh() = 53 | runCatching { 54 | cityReader.city(this.toInetAddress()).run { 55 | mostSpecificSubdivision.names[CN] ?: country.names[CN] 56 | } 57 | } 58 | .getOrDefault("未知") 59 | 60 | fun String.ipCityEn() = 61 | runCatching { 62 | cityReader.city(this.toInetAddress()).run { 63 | mostSpecificSubdivision.names["en"] ?: country.names["en"] 64 | } 65 | } 66 | .getOrDefault("未知") 67 | -------------------------------------------------------------------------------- /src/main/java/me/leon/Parser.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import java.security.SecureRandom 4 | import java.security.cert.CertificateException 5 | import java.security.cert.X509Certificate 6 | import javax.net.ssl.* 7 | import me.leon.support.* 8 | 9 | private const val UUID_LENGTH = 36 10 | 11 | object Parser { 12 | private val REG_SCHEMA_HASH = "(\\w+)://([^ #]+)(?:#([^#]+)?)?".toRegex() 13 | private val REG_SS = "([^:]+):([^@]+)@([^:]+):(\\d{1,5})/?".toRegex() 14 | private val REG_SSR_PARAM = "([^/]+)/\\?(.+)".toRegex() 15 | private val REG_TROJAN = "([^@]+)@([^:]+):(\\d{1,5})/?(?:\\?(.+))?".toRegex() 16 | 17 | init { 18 | // 信任过期证书 19 | val trustAllCerts: Array = 20 | arrayOf( 21 | object : X509TrustManager { 22 | @Throws(CertificateException::class) 23 | override fun checkClientTrusted( 24 | chain: Array?, 25 | authType: String? 26 | ) { 27 | // if needed 28 | } 29 | 30 | @Throws(CertificateException::class) 31 | override fun checkServerTrusted( 32 | chain: Array?, 33 | authType: String? 34 | ) { 35 | // if needed 36 | } 37 | 38 | override fun getAcceptedIssuers(): Array { 39 | return emptyArray() 40 | } 41 | } 42 | ) 43 | // Install the all-trusting trust manager 44 | runCatching { 45 | val sc = SSLContext.getInstance("SSL") 46 | sc.init(null, trustAllCerts, SecureRandom()) 47 | val sslsc = sc.serverSessionContext 48 | sslsc.sessionTimeout = 0 49 | HttpsURLConnection.setDefaultSSLSocketFactory(sc.socketFactory) 50 | HttpsURLConnection.setDefaultHostnameVerifier { _, _ -> true } 51 | } 52 | .getOrElse { 53 | // if needed 54 | } 55 | } 56 | 57 | var debug = false 58 | 59 | fun parse(uri: String) = 60 | runCatching { 61 | when (uri.substringBefore(':')) { 62 | "vmess" -> parseV2ray(uri.trim()) 63 | "ss" -> parseSs(uri.trim()) 64 | "ssr" -> parseSsr(uri.trim()) 65 | "trojan" -> parseTrojan(uri.trim()) 66 | "vless" -> parseVless(uri.trim()) 67 | "hysteria2" -> parseHysteria2(uri.trim()) 68 | else -> NoSub 69 | } 70 | } 71 | .getOrDefault(NoSub) 72 | 73 | fun parseV2ray(uri: String): Sub = 74 | runCatching { 75 | "parseV2ray ".debug(uri) 76 | REG_SCHEMA_HASH.matchEntire(uri)?.run { 77 | groupValues[2] 78 | .b64SafeDecode() 79 | .also { "parseV2ray base64 decode: ".debug(it) } 80 | .fromJson() 81 | .takeIf { it.id.length == UUID_LENGTH && !it.add.contains("baidu.com") } 82 | } 83 | ?: NoSub 84 | } 85 | .getOrElse { 86 | "parseV2ray err".debug(uri) 87 | println("parseV2ray error ${it.stackTrace}") 88 | NoSub 89 | } 90 | 91 | fun parseSs(uri: String): Sub { 92 | "parseSs ".debug(uri) 93 | REG_SCHEMA_HASH.matchEntire(uri)?.run { 94 | val remark = groupValues[3].urlDecode() 95 | "parseSs match".debug(remark) 96 | "parseSs match".debug(groupValues[2]) 97 | val decoded = 98 | groupValues[2].takeUnless { it.contains("@") }?.b64Decode() 99 | // 兼容异常 100 | ?: with(groupValues[2]) { 101 | "${substringBefore('@').b64Decode()}${substring(indexOf('@'))}".also { 102 | "parseSs b64 format correct".debug("___$it") 103 | } 104 | } 105 | decoded.also { 106 | "parseSs b64 decode".debug(it) 107 | REG_SS.matchEntire(it)?.run { 108 | "parseSs ss match".debug(this.groupValues.toString()) 109 | return SS(groupValues[1], groupValues[2], groupValues[3], groupValues[4]) 110 | .apply { this.remark = remark } 111 | } 112 | } 113 | } 114 | "parseSs failed".debug(uri) 115 | return NoSub 116 | } 117 | 118 | fun parseSsr(uri: String): Sub { 119 | "parseSsr ".debug(uri) 120 | return runCatching { 121 | REG_SCHEMA_HASH.matchEntire(uri)?.run { 122 | groupValues[2].b64SafeDecode().split(":").run { 123 | "parseSsr query".debug(this[5]) 124 | REG_SSR_PARAM.matchEntire(this[5])?.let { 125 | "parseSsr query match".debug(it.groupValues[2]) 126 | val q = it.groupValues[2].queryParamMapB64() 127 | "parseSsr query maps".debug(q.toString()) 128 | return SSR( 129 | this[0], 130 | this[1], 131 | this[2], 132 | this[3], 133 | this[4], 134 | it.groupValues[1].b64SafeDecode(), 135 | q["obfsparam"].orEmpty(), 136 | q["protoparam"].orEmpty(), 137 | ) 138 | .apply { 139 | remarks = q["remarks"].orEmpty() 140 | group = q["group"].orEmpty() 141 | } 142 | } 143 | } 144 | } 145 | ?: NoSub 146 | } 147 | .getOrElse { 148 | "parseSsr err not match".debug(uri) 149 | NoSub 150 | } 151 | } 152 | 153 | fun parseTrojan(uri: String): Sub { 154 | "parseTrojan".debug(uri) 155 | REG_SCHEMA_HASH.matchEntire(uri)?.run { 156 | val remark = groupValues[3].urlDecode() 157 | "parseTrojan remark".debug(remark) 158 | groupValues[2].also { 159 | "parseTrojan data".debug(it) 160 | REG_TROJAN.matchEntire(it)?.run { 161 | return Trojan(groupValues[1], groupValues[2], groupValues[3]).apply { 162 | this.remark = remark 163 | query = groupValues[4] 164 | } 165 | } 166 | } 167 | } 168 | "parseTrojan ".debug("failed") 169 | return NoSub 170 | } 171 | 172 | fun parseVless(uri: String): Sub { 173 | "parseVless".debug(uri) 174 | REG_SCHEMA_HASH.matchEntire(uri)?.run { 175 | val remark = groupValues[3].urlDecode() 176 | "parseVless remark".debug(remark) 177 | groupValues[2].also { 178 | "parseVless data".debug(it) 179 | REG_TROJAN.matchEntire(it)?.run { 180 | return Vless(groupValues[1], groupValues[2], groupValues[3]).apply { 181 | this.remark = remark 182 | query = groupValues[4] 183 | } 184 | } 185 | } 186 | } 187 | "parseVless ".debug("failed") 188 | return NoSub 189 | } 190 | 191 | fun parseHysteria2(uri: String): Sub { 192 | "parseHysteria2".debug(uri) 193 | REG_SCHEMA_HASH.matchEntire(uri)?.run { 194 | val remark = groupValues[3].urlDecode() 195 | "parseHysteria2 remark".debug(remark) 196 | groupValues[2].also { 197 | "parseHysteria2 data".debug(it) 198 | REG_TROJAN.matchEntire(it)?.run { 199 | return Hysteria2(groupValues[1], groupValues[2], groupValues[3]).apply { 200 | this.remark = remark 201 | query = groupValues[4] 202 | } 203 | } 204 | } 205 | } 206 | "parseHysteria2 ".debug("failed") 207 | return NoSub 208 | } 209 | 210 | private fun parseFromFileSub(path: String): LinkedHashSet { 211 | "parseFromSub Local".debug(path) 212 | val data = path.readText().b64SafeDecode() 213 | return if (data.contains("proxies:")) { 214 | data.parseYaml().proxies.asSequence().map(Node::toNode).fold(linkedSetOf()) { acc, 215 | sub -> 216 | acc.also { acc.add(sub) } 217 | } 218 | } else { 219 | data 220 | // .also { println(it) } 221 | .split("\r\n|\n".toRegex()) 222 | .asSequence() 223 | .filter { it.isNotEmpty() } 224 | .map { it to parse(it) } 225 | .filterNot { it.second is NoSub } 226 | .fold(linkedSetOf()) { acc, sub -> 227 | acc.add(sub.second) 228 | acc 229 | } 230 | } 231 | } 232 | 233 | private fun parseFromNetwork(url: String): LinkedHashSet { 234 | "parseFromNetwork".debug(url) 235 | println(url) 236 | val data = url.readFromNet().b64SafeDecode() 237 | return runCatching { 238 | if (data.contains("proxies:")) 239 | // 移除yaml中的标签 240 | { 241 | data 242 | .replace("\\[[^\"]+?]".toRegex(), "") 243 | .parseYaml() 244 | .proxies 245 | .asSequence() 246 | .map(Node::toNode) 247 | .filterNot { it is NoSub } 248 | .fold(linkedSetOf()) { acc, sub -> acc.also { acc.add(sub) } } 249 | } else { 250 | data 251 | .also { "parseFromNetwork".debug(it) } 252 | .split("\r\n|\n".toRegex()) 253 | .asSequence() 254 | .filter { it.isNotEmpty() && it.contains("://") } 255 | .map { 256 | println(it) 257 | parse(it.replace("/#", "#").trim()) 258 | } 259 | .filterNot { it is NoSub } 260 | .fold(linkedSetOf()) { acc, sub -> acc.also { acc.add(sub) } } 261 | } 262 | } 263 | .getOrElse { 264 | it.printStackTrace() 265 | println("failed______ $url ${it.message}") 266 | linkedSetOf() 267 | } 268 | } 269 | 270 | fun parseFromSub(uri: String) = 271 | when { 272 | uri.startsWith("http") -> parseFromNetwork(uri) 273 | uri.startsWith("/") -> parseFromFileSub(uri) 274 | "^[A-Za-z]:".toRegex().find(uri) != null -> parseFromFileSub(uri) 275 | else -> linkedSetOf() 276 | } 277 | 278 | fun String.debug(extra: String = "") { 279 | if (debug) println("$this $extra") 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /src/main/java/me/leon/Subs.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import me.leon.support.b64Encode 4 | import me.leon.support.b64EncodeNoEqual 5 | import me.leon.support.toJson 6 | import me.leon.support.urlEncode 7 | 8 | interface Uri { 9 | 10 | var name: String 11 | var nation: String 12 | val SERVER: String 13 | val serverPort: Int 14 | fun toUri(): String 15 | fun info(): String 16 | } 17 | 18 | sealed class Sub : Uri 19 | 20 | object NoSub : Sub() { 21 | override var name: String 22 | get() = "nosub" 23 | set(value) {} 24 | override var nation: String 25 | get() = "N/A" 26 | set(value) {} 27 | override var serverPort = 0 28 | override val SERVER = "nosub" 29 | 30 | override fun toUri() = "nosub" 31 | override fun info() = "nosub" 32 | } 33 | 34 | data class V2ray( 35 | /** address 服务器 */ 36 | var add: String = "", 37 | var port: String = "", 38 | /** uuid */ 39 | var id: String = "", 40 | /** alertId */ 41 | var aid: String = "0", 42 | var scy: String = "auto", 43 | /** network */ 44 | var net: String = "tcp", 45 | ) : Sub() { 46 | var v: String = "2" 47 | var ps: String = "" 48 | 49 | /** 伪装域名 */ 50 | var host: String = "" 51 | 52 | /** 伪装路径 */ 53 | var path: String = "" 54 | 55 | /** 默认false,空串即可 */ 56 | var tls: String = "" 57 | get() = if (field == "tls") "true" else field 58 | var sni: String = "" 59 | 60 | /** 伪装类型 tcp/kcp/QUIC 默认none */ 61 | var type: String = "none" 62 | 63 | override var name: String 64 | get() = ps.ifEmpty { "$SERVER:$serverPort-V2-${hashCode()}" } 65 | set(value) { 66 | ps = value 67 | } 68 | override var serverPort: Int = 0 69 | get() = runCatching { port.toInt() }.getOrDefault(-1) 70 | override val SERVER 71 | get() = add 72 | override var nation: String = "" 73 | 74 | override fun toUri() = "vmess://${this.toJson().b64Encode()}" 75 | override fun info() = "$nation $name vmess $add:$port" 76 | } 77 | 78 | data class SS( 79 | val method: String = "", 80 | val pwd: String = "", 81 | val server: String = "", 82 | val port: String = "", 83 | ) : Sub() { 84 | var remark: String = "" 85 | override var nation: String = "" 86 | 87 | override var name: String 88 | get() = remark.ifEmpty { "$SERVER:$serverPort-SS-${hashCode()}" } 89 | set(value) { 90 | remark = value 91 | } 92 | override val serverPort 93 | get() = runCatching { port.toInt() }.getOrDefault(-1) 94 | override val SERVER 95 | get() = server 96 | 97 | override fun toUri() = "ss://${"$method:$pwd@$server:$port".b64Encode()}#${name.urlEncode()}" 98 | 99 | override fun info() = "$nation $remark ss $server:$port" 100 | } 101 | 102 | @Suppress("ConstructorParameterNaming") 103 | data class SSR( 104 | val server: String = "", 105 | val port: String = "", 106 | val protocol: String = "", 107 | val method: String = "", 108 | val obfs: String = "", 109 | val password: String = "", 110 | val obfs_param: String = "", 111 | val protocol_param: String = "", 112 | ) : Sub() { 113 | var remarks: String = "" 114 | var group: String = "" 115 | 116 | override var name: String 117 | get() = remarks.ifEmpty { "$SERVER:$serverPort-SSR-${hashCode()}" } 118 | set(value) { 119 | remarks = value 120 | } 121 | override val serverPort 122 | get() = runCatching { port.toInt() }.getOrDefault(-1) 123 | override val SERVER 124 | get() = server 125 | override var nation: String = "" 126 | 127 | @Suppress("TrimMultilineRawString") 128 | override fun toUri() = 129 | "ssr://${ 130 | ("$server:$port:$protocol:$method:$obfs:${password.b64Encode()}" + 131 | "/?obfsparam=${obfs_param.b64EncodeNoEqual()}" + 132 | "&protoparam=${protocol_param.b64EncodeNoEqual()}" + 133 | "&remarks=${name.b64EncodeNoEqual()}" + 134 | "&group=${group.b64EncodeNoEqual()}") 135 | .b64Encode() 136 | }" 137 | 138 | override fun info() = "$nation $remarks ssr $server:$port" 139 | } 140 | 141 | data class Trojan(val password: String = "", val server: String = "", val port: String = "") : 142 | Sub() { 143 | var remark: String = "" 144 | var query: String = "" 145 | override var name: String 146 | get() = remark.ifEmpty { "$SERVER:$serverPort-TR-${hashCode()}" } 147 | set(value) { 148 | remark = value 149 | } 150 | private val params 151 | get() = if (query.isEmpty()) "" else "?$query" 152 | override val serverPort 153 | get() = runCatching { port.toInt() }.getOrDefault(-1) 154 | override val SERVER 155 | get() = server 156 | override var nation: String = "" 157 | 158 | override fun toUri() = "trojan://${"$password@$server:$port$params"}#${name.urlEncode()}" 159 | override fun info() = 160 | if (query.isEmpty()) { 161 | "$nation $name trojan $server:$port" 162 | } else { 163 | "$nation $remark trojan $server:$port?$query" 164 | } 165 | } 166 | 167 | /** refer https://github.com/XTLS/Xray-core/issues/91 */ 168 | data class Vless(val uuid: String = "", val server: String = "", val port: String = "") : Sub() { 169 | var remark: String = "" 170 | var query: String = "" 171 | override var name: String 172 | get() = remark.ifEmpty { "$SERVER:$serverPort-VL-${hashCode()}" } 173 | set(value) { 174 | remark = value 175 | } 176 | private val params 177 | get() = if (query.isEmpty()) "" else "?$query" 178 | override val serverPort 179 | get() = runCatching { port.toInt() }.getOrDefault(-1) 180 | override val SERVER 181 | get() = server 182 | override var nation: String = "" 183 | 184 | override fun toUri() = 185 | "vless://${"${uuid.urlEncode()}@$server:$port$params"}#${name.urlEncode()}" 186 | 187 | override fun info() = 188 | if (query.isEmpty()) { 189 | "$nation $name vless $server:$port" 190 | } else { 191 | "$nation $remark vless $server:$port?$query" 192 | } 193 | } 194 | 195 | data class Hysteria2(val uuid: String = "", val server: String = "", val port: String = "") : Sub() { 196 | var remark: String = "" 197 | var query: String = "" 198 | override var name: String 199 | get() = remark.ifEmpty { "$SERVER:$serverPort-hys2-${hashCode()}" } 200 | set(value) { 201 | remark = value 202 | } 203 | private val params 204 | get() = if (query.isEmpty()) "" else "?$query" 205 | override val serverPort 206 | get() = runCatching { port.toInt() }.getOrDefault(-1) 207 | override val SERVER 208 | get() = server 209 | override var nation: String = "" 210 | 211 | override fun toUri() = 212 | "hysteria2://${"${uuid.urlEncode()}@$server:$port$params"}#${name.urlEncode()}" 213 | 214 | override fun info() = 215 | if (query.isEmpty()) { 216 | "$nation $name vless $server:$port" 217 | } else { 218 | "$nation $remark vless $server:$port?$query" 219 | } 220 | } 221 | 222 | fun Sub.methodUnSupported() = 223 | this is SSR && (method in SSR_unSupportMethod || protocol in SSR_unSupportProtocol) || 224 | this is SS && method in SS_unSupportCipher || 225 | this is V2ray && net in VMESS_unSupportProtocol 226 | 227 | val SSR_unSupportMethod = arrayOf("none", "rc4", "rc4-md5") 228 | val SSR_unSupportProtocol = arrayOf("auth_chain_a") 229 | val SS_unSupportCipher = arrayOf("rc4-md5", "aes-128-cfb", "aes-256-cfb", "none") 230 | val VMESS_unSupportProtocol = arrayOf("none", "grpc", "h2", "auto") 231 | -------------------------------------------------------------------------------- /src/main/java/me/leon/domain/DnsResolve.kt: -------------------------------------------------------------------------------- 1 | package me.leon.domain 2 | 3 | @Suppress("ConstructorParameterNaming") 4 | data class DnsResolve( 5 | val Status: Int?, 6 | val TC: Boolean?, 7 | val RD: Boolean?, 8 | val RA: Boolean?, 9 | val AD: Boolean?, 10 | val CD: Boolean?, 11 | val Question: List?, 12 | val Answer: List? 13 | ) 14 | 15 | data class Question(val name: String?, val type: Int?) 16 | 17 | @Suppress("ConstructorParameterNaming") 18 | data class Answer(val name: String?, val type: Int?, val TTL: Int?, val `data`: String?) 19 | -------------------------------------------------------------------------------- /src/main/java/me/leon/domain/Host.kt: -------------------------------------------------------------------------------- 1 | package me.leon.domain 2 | 3 | data class Host(val domain: String) { 4 | var ip: String = "" 5 | override fun toString(): String { 6 | return "$ip $domain" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/me/leon/domain/Lanzou.kt: -------------------------------------------------------------------------------- 1 | package me.leon.domain 2 | 3 | data class Lanzou(val dom: String = "", val inf: Int = 0, val url: String = "", val zt: Int = 0) 4 | -------------------------------------------------------------------------------- /src/main/java/me/leon/domain/LiteSpeed.kt: -------------------------------------------------------------------------------- 1 | package me.leon.domain 2 | 3 | data class LiteSpeed(val id: Int, val info: String) { 4 | 5 | var servers: List? = null 6 | 7 | private var speed: String = "" 8 | private var ping: Int = -1 9 | 10 | fun ping(): Int? { 11 | return if (info == GOT_PING && ping > 0) { 12 | ping 13 | } else { 14 | null 15 | } 16 | } 17 | 18 | fun isEnd() = info == END_ONE 19 | 20 | fun speed(): String? { 21 | return if (info == GOT_SPEED) { 22 | speed 23 | } else { 24 | null 25 | } 26 | } 27 | 28 | data class Server( 29 | val id: Int, 30 | val link: String, 31 | ) 32 | 33 | companion object { 34 | const val GOT_SERVERS = "gotservers" 35 | const val GOT_PING = "gotping" 36 | const val GOT_SPEED = "gotspeed" 37 | const val END_ONE = "endone" 38 | const val NA = "N/A" 39 | } 40 | } 41 | 42 | data class LiteSpeedConfig( 43 | val subscription: String = "", 44 | val group: String = "Default", 45 | val speedtestMode: String = "pingonly", 46 | val pingMethod: String = "googleping", 47 | val sortMethod: String = "pingonly", 48 | val concurrency: Int = 128, 49 | val testMode: Int = 2, 50 | val timeout: Int = 5, 51 | val fontSize: Int = 24, 52 | val generatePicMode: Int = 2, 53 | val unique: Boolean = true, 54 | val language: String = "en", 55 | val theme: String = "rainbow", 56 | ) 57 | -------------------------------------------------------------------------------- /src/main/java/me/leon/domain/Quark.kt: -------------------------------------------------------------------------------- 1 | package me.leon.domain 2 | 3 | @Suppress("ConstructorParameterNaming", "NonBooleanPropertyPrefixedWithIs") 4 | data class Quark( 5 | val area: String = "", 6 | val country: String = "", 7 | val `data`: List = emptyList(), 8 | val port: Port = Port(), 9 | val status: Int? = 0 10 | ) { 11 | data class Data( 12 | val area: String = "", 13 | val country: String = "", 14 | val host: String = "", 15 | val id: String = "", 16 | val is_full: Int = 0, 17 | val is_proxy: String = "", 18 | val is_vip: Int = 0, 19 | val name: String = "", 20 | val rate: Double = 0.0, 21 | val weight: Int = 0 22 | ) 23 | 24 | data class Port(val method: String = "", val password: String = "", val port: String = "") 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/me/leon/support/Encode.kt: -------------------------------------------------------------------------------- 1 | package me.leon.support 2 | 3 | import java.net.URLDecoder 4 | import java.net.URLEncoder 5 | import java.util.* 6 | 7 | fun String.b64Decode() = String(Base64.getDecoder().decode(this.filter { it.code < 128 })) 8 | 9 | fun String.b64SafeDecode() = 10 | if (this.contains(":")) { 11 | this 12 | } else { 13 | runCatching { 14 | if (contains("=[^=]+.+".toRegex())) { 15 | split("=") 16 | .filter { it.isNotEmpty() } 17 | .joinToString(System.lineSeparator()) { 18 | it.replace("_", "/").replace("-", "+").b64Decode() 19 | } 20 | } else { 21 | trim().replace("_", "/").replace("-", "+").b64Decode() 22 | } 23 | } 24 | .getOrElse { 25 | println("failed: $this ${it.message}") 26 | "" 27 | } 28 | } 29 | 30 | fun String.b64Encode(): String = Base64.getEncoder().encodeToString(toByteArray()) 31 | 32 | fun String.b64EncodeNoEqual() = Base64.getEncoder().encodeToString(toByteArray()).replace("=", "") 33 | 34 | fun String.urlEncode() = URLEncoder.encode(this).orEmpty() 35 | 36 | fun String.urlDecode() = URLDecoder.decode(this).orEmpty() 37 | -------------------------------------------------------------------------------- /src/main/java/me/leon/support/Ext.kt: -------------------------------------------------------------------------------- 1 | package me.leon.support 2 | 3 | import java.net.HttpURLConnection 4 | import java.net.URL 5 | import java.text.SimpleDateFormat 6 | import java.util.Calendar 7 | import java.util.TimeZone 8 | 9 | private const val DEFAULT_READ_TIME_OUT = 30_000 10 | private const val DEFAULT_CONNECT_TIME_OUT = 30_000 11 | 12 | fun String.httpRequest(timeout:Int = DEFAULT_READ_TIME_OUT) = (URL(this).openConnection().apply { 13 | // setRequestProperty("Referer", 14 | // "https://pc.woozooo.com/mydisk.php") 15 | connectTimeout = DEFAULT_CONNECT_TIME_OUT 16 | readTimeout = timeout 17 | setRequestProperty("Accept-Language", ACCEPT_LANGUAGE) 18 | setRequestProperty("user-agent", UA) 19 | } as HttpURLConnection) 20 | 21 | fun String.readFromNet() = 22 | runCatching { 23 | String( 24 | (URL(this).openConnection().apply { 25 | // setRequestProperty("Referer", 26 | // "https://pc.woozooo.com/mydisk.php") 27 | connectTimeout = DEFAULT_CONNECT_TIME_OUT 28 | readTimeout = DEFAULT_READ_TIME_OUT 29 | setRequestProperty("Accept-Language", ACCEPT_LANGUAGE) 30 | setRequestProperty("User-Agent", UA) 31 | } as HttpURLConnection) 32 | .takeIf { 33 | // println("$this __ ${it.responseCode}") 34 | it.responseCode == RESPONSE_OK 35 | } 36 | ?.inputStream 37 | ?.readBytes() 38 | ?: "".toByteArray() 39 | ) 40 | } 41 | .getOrElse { 42 | println("read err ${it.message}") 43 | "" 44 | } 45 | 46 | fun String.queryParamMap() = 47 | "(\\w+)=([^&]*)".toRegex().findAll(this).fold(mutableMapOf()) { acc, matchResult 48 | -> 49 | acc.apply { acc[matchResult.groupValues[1]] = matchResult.groupValues[2] } 50 | } 51 | 52 | fun String.queryParamMapB64() = 53 | "(\\w+)=([^&]*)".toRegex().findAll(this).fold(mutableMapOf()) { acc, matchResult 54 | -> 55 | acc.apply { 56 | acc[matchResult.groupValues[1]] = 57 | matchResult.groupValues[2].urlDecode().replace(" ", "+").b64SafeDecode() 58 | } 59 | } 60 | 61 | fun Int.slice(group: Int): MutableList { 62 | val slice = kotlin.math.ceil(this.toDouble() / group.toDouble()).toInt() 63 | return (0 until group).foldIndexed(mutableListOf()) { index, acc, i -> 64 | acc.apply { 65 | acc.add( 66 | slice * index until ((slice * (i + 1)).takeIf { group - 1 != index } ?: this@slice) 67 | ) 68 | } 69 | } 70 | } 71 | 72 | fun Any?.safeAs(): T? = this as? T? 73 | 74 | fun timeStamp(timeZone: String = "Asia/Shanghai"): String { 75 | val instance = Calendar.getInstance() 76 | TimeZone.setDefault(TimeZone.getTimeZone(timeZone)) 77 | return SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(instance.time) 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/me/leon/support/File.kt: -------------------------------------------------------------------------------- 1 | package me.leon.support 2 | 3 | import java.io.File 4 | import java.nio.charset.Charset 5 | 6 | fun String.readText(charset: Charset = Charsets.UTF_8) = 7 | File(this).canonicalFile.takeIf { it.exists() }?.readText(charset).orEmpty() 8 | 9 | fun String.writeLine(txt: String = "", isAppend: Boolean = true): Unit = 10 | if (txt.isEmpty() || !isAppend) { 11 | File(this).also { if (!it.parentFile.exists()) it.parentFile.mkdirs() }.writeText(txt) 12 | } else { 13 | File(this).appendText("$txt${System.lineSeparator()}") 14 | } 15 | 16 | fun String.readLines() = File(this).takeIf { it.exists() }?.readLines() ?: mutableListOf() 17 | -------------------------------------------------------------------------------- /src/main/java/me/leon/support/FlagRemover.kt: -------------------------------------------------------------------------------- 1 | package me.leon.support 2 | 3 | import me.leon.ROOT 4 | 5 | object FlagRemover { 6 | private val flagMaps = linkedMapOf() 7 | private val flagReg by lazy { 8 | "$ROOT/flags.txt" 9 | .readLines() 10 | .map { 11 | with(it.split("|")) { 12 | flagMaps[this[0]] = this[2] 13 | flagMaps[this[1]] = this[2] 14 | Triple(this[0], this[1], this[2]) 15 | } 16 | } 17 | .joinToString("|") { "(${it.first}) *(?:${it.second})?" } 18 | // .also { println(it) } 19 | .toRegex() 20 | } 21 | 22 | fun remove(s: String): String { 23 | var tmp = s 24 | flagReg 25 | .findAll(s) 26 | .map { 27 | it.groupValues 28 | .filterIndexed { i, item -> i != 0 && item.isNotEmpty() } 29 | .map { item -> 30 | // println("$item ${flagMaps[item]}") 31 | flagMaps[item]?.run { 32 | tmp = 33 | flagReg.replaceFirst( 34 | tmp, 35 | this.takeUnless { tmp.contains(this) }.orEmpty() 36 | ) 37 | } 38 | } 39 | } 40 | .lastOrNull() 41 | return tmp.replace("美国离岛美国|美国离岛".toRegex(), "美国") 42 | } 43 | } 44 | 45 | fun String.removeFlags() = FlagRemover.remove(this) 46 | -------------------------------------------------------------------------------- /src/main/java/me/leon/support/GsonUtils.kt: -------------------------------------------------------------------------------- 1 | package me.leon.support 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.JsonObject 5 | import com.google.gson.reflect.TypeToken 6 | 7 | object GsonUtils { 8 | private val gson: Gson = Gson() 9 | 10 | fun toJson(obj: Any): String = gson.toJson(obj) 11 | 12 | fun fromJson(json: String?, clazz: Class): D = gson.fromJson(json, clazz) 13 | 14 | fun jsonToList(json: String, clazz: Class>): List = 15 | gson.fromJson(json, clazz).toList() 16 | 17 | fun jsonToArrayList(json: String, clazz: Class): List { 18 | return gson 19 | .fromJson>(json, object : TypeToken>() {}.type) 20 | .map { gson.fromJson(it, clazz) } 21 | .toList() 22 | } 23 | } 24 | 25 | inline fun String.fromJson() = GsonUtils.fromJson(this, D::class.java) 26 | 27 | inline fun String.fromJsonArray() = GsonUtils.jsonToList(this, Array::class.java) 28 | 29 | inline fun String.fromJsonList() = GsonUtils.jsonToArrayList(this, D::class.java) 30 | 31 | fun Any.toJson() = GsonUtils.toJson(this) 32 | -------------------------------------------------------------------------------- /src/main/java/me/leon/support/IpExt.kt: -------------------------------------------------------------------------------- 1 | package me.leon.support 2 | 3 | import me.leon.IP_SCORE 4 | import org.jsoup.Jsoup 5 | import java.net.InetAddress 6 | import kotlin.math.pow 7 | 8 | @Throws 9 | fun String.toInetAddress(): InetAddress = InetAddress.getByName(this) 10 | 11 | 12 | val cfCidrs = 13 | setOf( 14 | "103.21.244.0/22", 15 | "103.22.200.0/22", 16 | "103.31.4.0/22", 17 | "104.16.0.0/13", 18 | "104.24.0.0/14", 19 | "108.162.192.0/18", 20 | "131.0.72.0/22", 21 | "141.101.64.0/18", 22 | "162.158.0.0/15", 23 | "172.64.0.0/13", 24 | "173.245.48.0/20", 25 | "188.114.96.0/20", 26 | "190.93.240.0/20", 27 | "197.234.240.0/22", 28 | "198.41.128.0/17" 29 | ) 30 | .map { it.cidrRange() } 31 | 32 | fun String.ip2Uint() = split(".").fold(0U) { acc, s -> acc * 256U + s.toUInt() } 33 | 34 | fun UInt.toIp() = "${shr(24)}.${shr(16) and 0xFFU}.${shr(8) and 0xFFU}.${this and 0xFFU}" 35 | 36 | fun String.ip2Binary() = 37 | split(".") 38 | .fold(StringBuilder()) { acc, s -> acc.append(s.toUInt().toString(2).padStart(8, '0')) } 39 | .toString() 40 | 41 | fun Int.ipMaskBinary() = "1".repeat(this) + "0".repeat(32 - this) 42 | 43 | fun Int.ipMask() = ipMaskBinary().binary2Ip() 44 | 45 | fun String.binary2Ip() = stripAllSpace().chunked(8).joinToString(".") { it.toUInt(2).toString() } 46 | 47 | fun String.cidrRange(): UIntRange { 48 | val (ipStr, cidrStr) = split("/").takeIf { it.size > 1 } ?: listOf(this, "24") 49 | val cidr = cidrStr.takeIf { it.isNotEmpty() }?.toInt() ?: 24 50 | val ip = ipStr.ip2Uint() 51 | val sub = 32 - cidr 52 | val count = 2.0.pow(sub).toInt() 53 | val mask = cidr.ipMask().ip2Uint() 54 | val net = mask and ip 55 | return (net + 1U)..(net + (count - 2).toUInt()) 56 | } 57 | 58 | fun String.ipCloudFlare() = cfCidrs.any { it.contains(ip2Uint()) } 59 | 60 | fun String.stripAllSpace() = replace("\\s+".toRegex(), "") 61 | 62 | val map = IP_SCORE.readLines().filter { it.isNotEmpty() }.associate { with(it.split("\t")) { first() to last().toInt() } }.toMutableMap() 63 | .also { println("ip score size ${it.size}") } 64 | 65 | fun String.ipScore() = 66 | map[this] ?: (Jsoup.connect("https://scamalytics.com/ip/$this") 67 | .get() 68 | .selectFirst(".score") 69 | ?.text()?.substringAfter("Fraud Score: ")?.toIntOrNull() ?: 0) 70 | .also { 71 | map[this] = it 72 | IP_SCORE.writeLine("$this\t$it") 73 | } 74 | 75 | val Int.lvl 76 | get() = 77 | when { 78 | this < 40 -> "L$this" 79 | this < 70 -> "M$this" 80 | this < 100 -> "H$this" 81 | else -> "H" 82 | } -------------------------------------------------------------------------------- /src/main/java/me/leon/support/Net.kt: -------------------------------------------------------------------------------- 1 | package me.leon.support 2 | 3 | import java.io.DataOutputStream 4 | import java.io.File 5 | import java.net.* 6 | import kotlin.system.measureTimeMillis 7 | import kotlinx.coroutines.Dispatchers 8 | import kotlinx.coroutines.ExperimentalCoroutinesApi 9 | import me.leon.FAIL_IPS 10 | 11 | val failIpPorts by lazy { FAIL_IPS.readLines().toHashSet() } 12 | val fails = mutableSetOf() 13 | val passes = mutableSetOf() 14 | const val UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " + 15 | "Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0" 16 | const val ACCEPT_LANGUAGE = "en-US" 17 | /** ip + port 测试 */ 18 | val Nop = { _: String, _: Int -> false } 19 | 20 | fun String.connect( 21 | port: Int = 80, 22 | timeout: Int = 1000, 23 | cache: (ip: String, port: Int) -> Boolean = Nop, 24 | exceptionHandler: (info: String) -> Unit = {} 25 | ) = 26 | if (!contains(".") || port < 0 || cache.invoke(this, port)) { 27 | // println("quick fail from cache") 28 | -1 29 | } else if (passes.contains("$this:$port")) { 30 | 1 31 | } else { 32 | runCatching { 33 | measureTimeMillis { 34 | Socket().connect(InetSocketAddress(this, port), timeout) 35 | passes.add("$this:$port") 36 | } 37 | } 38 | .getOrElse { 39 | exceptionHandler.invoke("$this:$port") 40 | -1 41 | } 42 | } 43 | 44 | /** ping 测试 */ 45 | fun String.ping( 46 | timeout: Int = 1000, 47 | cacheFailed: (ip: String, port: Int) -> Boolean = Nop, 48 | exceptionHandler: (info: String) -> Unit = {} 49 | ) = 50 | if (!contains(".") || cacheFailed.invoke(this, -1)) { 51 | println("fast failed") 52 | -1 53 | } else if (passes.contains(this)) { 54 | 1 55 | } else { 56 | runCatching { 57 | val start = System.currentTimeMillis() 58 | val reachable = InetAddress.getByName(this).isReachable(timeout) 59 | if (reachable) { 60 | (System.currentTimeMillis() - start).also { passes.add(this) } 61 | } else { 62 | exceptionHandler.invoke(this) 63 | -1 64 | } 65 | } 66 | .getOrElse { 67 | exceptionHandler.invoke(this) 68 | -1 69 | } 70 | } 71 | 72 | fun String.toFile() = File(this) 73 | 74 | const val RESPONSE_OK = 200 75 | 76 | fun String.post(params: MutableMap) = 77 | runCatching { 78 | val p = 79 | params.keys 80 | .foldIndexed(StringBuilder()) { index, acc, s -> 81 | acc.also { 82 | acc.append("${"&".takeUnless { index == 0 }.orEmpty()}$s=${params[s]}") 83 | } 84 | } 85 | .toString() 86 | String( 87 | URL(this) 88 | .openConnection() 89 | .safeAs() 90 | ?.apply { 91 | requestMethod = "POST" 92 | setRequestProperty("Content-Type", "application/x-www-form-urlencoded") 93 | setRequestProperty("Referer", "https://pc.woozooo.com/mydisk.php") 94 | setRequestProperty("Accept-Language","en-US") 95 | setRequestProperty("Content-Length", "${p.toByteArray().size}") 96 | setRequestProperty("user-agent",UA) 97 | useCaches = false 98 | doInput = true 99 | doOutput = true 100 | 101 | DataOutputStream(outputStream).use { it.writeBytes(p) } 102 | } 103 | ?.takeIf { 104 | // println("$this __ ${it.responseCode}") 105 | it.responseCode == RESPONSE_OK 106 | } 107 | ?.inputStream 108 | ?.readBytes() 109 | ?: "".toByteArray() 110 | ) 111 | } 112 | .getOrElse { 113 | println("$this read err ${it.message}") 114 | "" 115 | } 116 | 117 | fun String.readBytesFromNet( 118 | method: String = "GET", 119 | timeout: Int = 3000, 120 | data: String = "", 121 | headers: MutableMap = mutableMapOf() 122 | ) = 123 | runCatching { 124 | (URL(this).openConnection() as HttpURLConnection) 125 | .apply { 126 | connectTimeout = timeout 127 | readTimeout = timeout 128 | setRequestProperty("Content-Type", "application/json; charset=utf-8") 129 | setRequestProperty("Accept-Language", ACCEPT_LANGUAGE) 130 | setRequestProperty("user-agent", UA) 131 | for ((k, v) in headers) setRequestProperty(k, v.toString()) 132 | 133 | requestMethod = method 134 | 135 | if (method.equals("post", true)) { 136 | val dataBytes = data.toByteArray() 137 | if (dataBytes.isNotEmpty()) { 138 | addRequestProperty("Content-Length", dataBytes.size.toString()) 139 | } 140 | doOutput = true 141 | connect() 142 | outputStream.write(dataBytes) 143 | outputStream.flush() 144 | outputStream.close() 145 | } 146 | } 147 | .takeIf { it.responseCode == RESPONSE_OK } 148 | ?.inputStream 149 | ?.readBytes() 150 | ?: byteArrayOf() 151 | } 152 | .getOrElse { 153 | println("read bytes err ") 154 | byteArrayOf() 155 | } 156 | 157 | fun String.quickConnect(port: Int = 80, timeout: Int = 1000) = 158 | this.connect( 159 | port, 160 | timeout, 161 | { ip, p -> 162 | failIpPorts.contains(ip) || fails.contains("$ip:$p") || failIpPorts.contains("$ip:$p") 163 | } 164 | ) { 165 | // println("error $it") 166 | fails.add(it) 167 | FAIL_IPS.writeLine(it) 168 | } 169 | 170 | fun String.quickPing(timeout: Int = 1000) = 171 | this.ping(timeout, { ip, _ -> failIpPorts.contains(ip) || fails.contains(ip) }) { 172 | println("error $it") 173 | fails.add(it) 174 | FAIL_IPS.writeLine(it) 175 | } 176 | 177 | @OptIn(ExperimentalCoroutinesApi::class) val DISPATCHER = Dispatchers.IO.limitedParallelism(256) 178 | -------------------------------------------------------------------------------- /src/main/java/me/leon/support/Yamls.kt: -------------------------------------------------------------------------------- 1 | package me.leon.support 2 | 3 | import org.yaml.snakeyaml.DumperOptions 4 | import org.yaml.snakeyaml.LoaderOptions 5 | import org.yaml.snakeyaml.Yaml 6 | import org.yaml.snakeyaml.constructor.Constructor 7 | import org.yaml.snakeyaml.representer.Representer 8 | 9 | inline fun String.parseYaml() = (Yaml(Constructor(T::class.java, LoaderOptions().apply { 10 | codePointLimit = Int.MAX_VALUE 11 | }), Representer(DumperOptions()).apply { propertyUtils.isSkipMissingProperties = true }).load(fixYaml()) as T) 12 | 13 | fun String.fixYaml() = 14 | replace("!<[^>]+>".toRegex(), "") 15 | .replace(" password: \n", " password: xxxxx\n") 16 | .replace("server: $*@", "server: ") 17 | -------------------------------------------------------------------------------- /src/main/resources/GeoLite2-Country.mmdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leon406/SubCrawler/b5029d06271b595e5872a7e5635d1723b9697815/src/main/resources/GeoLite2-Country.mmdb -------------------------------------------------------------------------------- /src/test/java/me/leon/ConnectTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import kotlinx.coroutines.* 4 | import me.leon.support.* 5 | import org.junit.jupiter.api.Test 6 | 7 | class ConnectTest { 8 | 9 | @Test 10 | fun connect() { 11 | println("www.baidu.com".connect()) 12 | println("www.baidu.com".ping()) 13 | println("www.baidu.com".connect(443)) 14 | } 15 | 16 | @Test 17 | fun poolTest() { 18 | NODE_OK.writeLine() 19 | runBlocking { 20 | Parser.parseFromSub(POOL) 21 | .map { it to async(DISPATCHER) { it.SERVER.quickConnect(it.serverPort, 2000) } } 22 | .filter { it.second.await() > -1 } 23 | .forEach { 24 | println(it.first.info() + ":" + it.second) 25 | NODE_OK.writeLine(it.first.toUri()) 26 | } 27 | } 28 | } 29 | 30 | @Test 31 | fun poolPingTest() { 32 | runBlocking { 33 | Parser.parseFromSub(POOL) 34 | .map { it to async(DISPATCHER) { it.SERVER.quickPing(2000) } } 35 | .filter { it.second.await() > -1 } 36 | .also { println(it.size) } 37 | .forEach { println(it.first.info() + ":" + it.second) } 38 | } 39 | } 40 | 41 | @Test 42 | fun url404() { 43 | runBlocking { 44 | ("$ROOT/pool/sublists".readLines() + "$ROOT/pool/subs".readLines()) 45 | .filterNot { it.startsWith("#") } 46 | .map { 47 | async(DISPATCHER) { 48 | it to runCatching { it.httpRequest(10000).responseCode == 404 }.getOrDefault(false) 49 | } 50 | } 51 | .awaitAll() 52 | .filter { it.second } 53 | .forEach { 54 | println(it) 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/me/leon/ExtTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import java.io.File 4 | import java.text.NumberFormat 5 | import java.util.* 6 | import me.leon.domain.Lanzou 7 | import me.leon.support.* 8 | import org.junit.jupiter.api.Test 9 | 10 | class ExtTest { 11 | 12 | @Test 13 | fun encode() { 14 | println("https://suo.yt/WtbjDPJ".readFromNet()) 15 | println("你好Leon".b64Encode()) 16 | 17 | println("5L2g5aW9TGVvbg==".b64Decode()) 18 | println("你好Leon".urlEncode()) 19 | println("%E4%BD%A0%E5%A5%BDLeon".urlDecode()) 20 | } 21 | 22 | @Test 23 | fun v2rayTest() { 24 | val url = 25 | "vmess://ew0KICAidiI6ICIyIiwNCiAgInBzIjogIvCfh7rwn4e4576O5Zu9IOKYhuKYhiAgMDEg4piGTlRU4piGICAgMS4y5YCN" + 26 | "546HIiwNCiAgImFkZCI6ICJiai5rZWFpeXVuLnh5eiIsDQogICJwb3J0IjogIjMxMTAzIiwNCiAgImlkIjogIjQ0MTg5Mz" + 27 | "QxLTJjYzktM2JlOS1iYjEwLWMxMzVlOThjZDhlYiIsDQogICJhaWQiOiAiMiIsDQogICJzY3kiOiAiYXV0byIsDQogICJu" + 28 | "ZXQiOiAid3MiLA0KICAidHlwZSI6ICJub25lIiwNCiAgImhvc3QiOiAid3d3LmJhaWR1LmNvbSIsDQogICJwYXRoIjogIi9" + 29 | "2MnJheSIsDQogICJ0bHMiOiAiIiwNCiAgInNuaSI6ICIiDQp9" 30 | println(Parser.parseV2ray(url).toUri()) 31 | } 32 | 33 | @Test 34 | fun ssTest() { 35 | val url = 36 | "ss://YWVzLTI1Ni1nY206bjh3NFN0bmJWRDlkbVhZbjRBanQ4N0VBQDE1NC4xMjcuNTAuMTM4OjMxNTcy#(%e5%b7%b2%e5%9d%9" + 37 | "a%e6%8c%ba5%e5%a4%a9)%e5%8d%97%e9%9d%9e%e3%80%90%e5%88%86%e4%ba%ab%e6%9d%a5%e8%87%aaYoutube%e" + 38 | "4%b8%8d%e8%89%af%e6%9e%97%e3%80%91" 39 | println(Parser.parseSs(url).toUri()) 40 | 41 | val url2 = 42 | "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpyNFRlRXQ1YkswVURAc3MuY2Euc3NobWF4Lm5ldDoxNDQz" 43 | println(Parser.parseSs(url2).toUri()) 44 | } 45 | 46 | @Test 47 | fun ssrTest() { 48 | val url = 49 | "ssr://bnRlbXAxNi5ib29tLnBhcnR5OjIxMDAwOmF1dGhfYWVzMTI4X3NoYTE6YWVzLTI1Ni1jZmI6aHR0cF9zaW1wbGU6VldzNU1" + 50 | "rTlQvP29iZnNwYXJhbT1aRzkzYm14dllXUXVkMmx1Wkc5M2MzVndaR0YwWlM1amIyMCZwcm90b3BhcmFtPU1UUXpNRGN6T" + 51 | "2tONk9HRlBhUSZyZW1hcmtzPTZhYVo1cml2TFVJJmdyb3VwPU1R" 52 | println(Parser.parseSsr(url).toUri()) 53 | 54 | val url2 = 55 | "ssr://bjU3LmJvb20ucGFydHk6MjUwMDA6YXV0aF9hZXMxMjhfc2hhMTphZXMtMjU2LWNmYjpodHRwX3NpbXBsZTpWV3M1TWtOVC" + 56 | "8_b2Jmc3BhcmFtPVpHOTNibXh2WVdRdWQybHVaRzkzYzNWd1pHRjBaUzVqYjIwJnByb3RvcGFyYW09TVRRek1EY3pPa042" + 57 | "T0dGUGFRJnJlbWFya3M9NmFhWjVyaXZMVVEmZ3JvdXA9TVE" 58 | println(Parser.parseSsr(url2).toUri()) 59 | } 60 | 61 | @Test 62 | fun trojanTest() { 63 | val url3 = "trojan://N8l9RGMa@t2.ssrsub.one:8443?sni=t2.ssrsub.one" 64 | println(Parser.parse(url3).toUri()) 65 | } 66 | 67 | @Test 68 | fun queryParse() { 69 | val q = 70 | "obfsparam=ZG93bmxvYWQud2luZG93c3VwZGF0ZS5jb20&protoparam=" + 71 | "MTQzMDczOkN6OGFPaQ&remarks=6aaZ5rivLUI&group=MQ" 72 | println(q.queryParamMap()) 73 | 74 | val q2 = 75 | "obfsparam=&protoparam=" + 76 | "dC5tZS9TU1JTVUI&remarks=UmVsYXlf8J+HqPCfh6ZDQS3wn4eo8J+HpkNBXzQxOSB8IDMuNTNNYg&group=" 77 | println(q2.queryParamMapB64()) 78 | } 79 | 80 | @Test 81 | fun fileTest() { 82 | println(File("./").canonicalPath) 83 | println(this.javaClass.getResource("")) 84 | println(this.javaClass.getResource("/")) 85 | println(this.javaClass.classLoader.getResource("")) 86 | println(this.javaClass.classLoader.getResource("/")) 87 | } 88 | 89 | @Test 90 | fun sliceTest() { 91 | println(7.slice(3)) 92 | println(9.slice(3)) 93 | } 94 | 95 | @Test 96 | fun pingTest() { 97 | println("wwws.baidu.com".quickPing()) 98 | println("wwws.baidu.com".quickPing()) 99 | println("www.baidu.com".quickPing()) 100 | } 101 | 102 | @Test 103 | fun socketTest() { 104 | println("wwws.baidu.com".quickConnect(50)) 105 | println("www.baidu.com".quickConnect(80)) 106 | println("www.baidu.com".quickConnect(443)) 107 | } 108 | 109 | @Test 110 | fun lanzouDirectLink() { 111 | val url = "https://leon.lanzoub.com/icjqqmk38xg" 112 | 113 | url.readFromNet() 114 | .run { "(/fn\\?\\w{6,})\" frameborder".toRegex().find(this)!!.groupValues[1] } 115 | .also { 116 | println(it) 117 | "https://www.lanzouw.com/$it".readFromNet().also { 118 | println(it) 119 | val sign = "(?:vsign = +|'sign':)'(\\w+)'".toRegex().find(it)!!.groupValues[1] 120 | "https://www.lanzouw.com/ajaxm.php" 121 | .post( 122 | mutableMapOf( 123 | "action" to "downprocess", 124 | "signs" to "?ctdf", 125 | "sign" to sign, 126 | "ves" to "1" 127 | ) 128 | ) 129 | .fromJson() 130 | .run { println("$dom/file/${this.url}") } 131 | } 132 | } 133 | } 134 | 135 | @Test 136 | fun timeZone() { 137 | System.setProperty("user.timezone", "GMT +04") 138 | println(timeStamp()) 139 | println(timeStamp("GMT-3")) 140 | println(timeStamp("UTC")) 141 | println(timeStamp("America/New_York")) 142 | } 143 | 144 | @Test 145 | fun dd() { 146 | val d1 = 2.147483647E9 147 | val d = 2_147_483_647.toDouble() 148 | println(d.toString()) 149 | val instance = NumberFormat.getInstance() 150 | instance.isGroupingUsed = false // 设置不使用科学计数器 151 | instance.maximumFractionDigits = 2 // 小数点最大位数 152 | println(instance.format(d1)) 153 | "\uD83C\uDDFA\uD83C\uDDF8 美国(欢迎订阅YouTube:8度科技%" 154 | .replace("[【((].+[))%】]?".toRegex(), "") 155 | .also { println(it) } 156 | 157 | "(欢迎订阅youtube:8度科技".replace("[【((].+[))%】]?".toRegex(), "").also { println(it) } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/test/java/me/leon/FlagTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import me.leon.support.FlagRemover 4 | import me.leon.support.removeFlags 5 | import org.junit.jupiter.api.Test 6 | 7 | class FlagTest { 8 | @Test 9 | fun flagParse() { 10 | 11 | FlagRemover.remove("Relay_\uD83C\uDDE8\uD83C\uDDF3CN-\uD83C\uDDF8\uD83C\uDDECSG_1927") 12 | .also { println(it) } 13 | } 14 | 15 | @Test 16 | fun pool() { 17 | Parser.parseFromSub(NODE_OK).map { println("${it.name} ${it.name.removeFlags()}") } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/me/leon/LocalFileSubTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import kotlinx.coroutines.async 4 | import kotlinx.coroutines.runBlocking 5 | import me.leon.support.* 6 | import org.junit.jupiter.api.Test 7 | 8 | class LocalFileSubTest { 9 | @Test 10 | fun readLocal() { 11 | Parser.parseFromSub("$ROOT/V2RayN.txt") 12 | .joinToString("|") { it.toUri() } 13 | .also { println(it) } 14 | } 15 | 16 | @Test 17 | fun readLocal2() { 18 | Parser.parseFromSub("$ROOT/subs.txt").joinToString("|") { it.toUri() }.also { println(it) } 19 | } 20 | 21 | @Test 22 | fun readLocalDir() { 23 | runBlocking { 24 | "C:\\Users\\Leon\\Downloads\\Telegram Desktop" 25 | .toFile() 26 | .listFiles() 27 | .map { Parser.parseFromSub(it.absolutePath) } 28 | .flatten() 29 | .distinct() 30 | .map { it to async(DISPATCHER) { it.SERVER.quickConnect(it.serverPort, 2000) } } 31 | .filter { it.second.await() > -1 } 32 | .map { it.first } 33 | .also { println(it.size) } 34 | .also { println(it.joinToString("\n") { it.toUri() }) } 35 | } 36 | } 37 | 38 | @Test 39 | fun readLocal4() { 40 | Parser.parseFromSub(NODE_OK) 41 | .filterIsInstance() 42 | .filter { it.net == "grpc" } 43 | .filterNot { it.methodUnSupported().apply { if (this) println("____$it") } } 44 | .joinToString("\n") { it.info() + "${it.tls} ${it.path}" } 45 | .also { println(it) } 46 | } 47 | 48 | @Test 49 | fun readLocalSSR() { 50 | Parser.parseFromSub(NODE_SSR) 51 | .also { println(it.size) } 52 | .filterNot { it.methodUnSupported() } 53 | .filterIsInstance() 54 | // .joinToString("\n") { it.name } 55 | .also { println(it.map { it.protocol }.groupBy { it }.keys) } 56 | } 57 | 58 | @Test 59 | fun parseUri() { 60 | val uri = 61 | "trojan://413f2e36-0038-48e4-963a-a38c0007ef24@us-sp.okzdns.com:50001/#S2%E7%BE%8E%E5%9B%BD%7CNetFlix%7C04" 62 | Parser.parse(uri).also { println(it) } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/me/leon/NetworkSubTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import me.leon.support.urlDecode 4 | import org.junit.jupiter.api.Assertions 5 | import org.junit.jupiter.api.Test 6 | 7 | class NetworkSubTest { 8 | @Test 9 | fun subParse() { 10 | 11 | val e = 12 | "https://raw.githubusercontent.com/itsyebekhe/HiN-VPN/main/subscription/normal/mix" 13 | 14 | listOf( 15 | e, 16 | ) 17 | .forEach { 18 | kotlin 19 | .runCatching { 20 | Parser.parseFromSub(it) 21 | .also { println(it.size) } 22 | .joinToString( 23 | // "|", 24 | "\r\n", 25 | transform = Sub::toUri 26 | ) 27 | .also { 28 | println("___________") 29 | println(it) 30 | } 31 | } 32 | .onFailure { it.printStackTrace() } 33 | } 34 | } 35 | 36 | @Test 37 | fun sub() { 38 | val l1 = Parser.parseFromSub("https://etproxypool.ga/clash/proxies") 39 | val l2 = Parser.parseFromSub("https://suo.yt/v9UsfNr") 40 | val combine = l1 + l2 41 | val l1Only = combine - l2 42 | val l2Only = combine - l1 43 | val share = l1 - l1Only 44 | println("共享 ${share.size}") 45 | println("l1 ${l1.size} 独有 ${l1Only.size}") 46 | println("l2 ${l2.size} 独有 ${l2Only.size}") 47 | } 48 | 49 | @Test 50 | fun parseVless() { 51 | val uri = 52 | "vless://21f181f3-2f66-47a8-b4d5-7aef046cc087@104.19.146.137:443?encryption=none&security=tls&sni=ap.utopub.com&type=ws&host=ap.utopub.com&path=%2futopub-vless#NY%40vless" 53 | Parser.parseVless(uri).also { 54 | Assertions.assertEquals(uri, it.toUri()) 55 | println(it.info()) 56 | } 57 | } 58 | @Test 59 | fun parseHysteria2() { 60 | val uri = 61 | "hysteria2://HowdyHysteria2023w0W@hysteria.udpgw.com:8443?insecure=1&sni=sni-here.com&obfs=salamander&obfs-password=HysteriaHowdy#\uD83C\uDD94oneclickvpnkeys%20\uD83D\uDD12%20HY2-UDP-N/A%20\uD83C\uDDA5\uD83C\uDDA5%20%20117ms" 62 | println(Parser.parse(uri)) 63 | Parser.parseHysteria2(uri).also { 64 | println(it.toUri().urlDecode()) 65 | Assertions.assertEquals(uri.substringBefore("#"), it.toUri().substringBefore("#")) 66 | println(it.info()) 67 | } 68 | } 69 | @Test 70 | fun parseSs() { 71 | val uri = 72 | "ss://YWVzLTI1Ni1jZmI6OWQ2Y2NlYWEzNzNiZjJjOGFjYjIyZTYwYjZhNThiZTZANDUuNzkuMTExLjIxNDo0NDM=#%E7%BE%8E%E5%9B%BD" 73 | Parser.parseSs(uri).also { 74 | Assertions.assertEquals(uri, it.toUri()) 75 | println(it.info()) 76 | } 77 | } 78 | 79 | @Test 80 | fun parseText() { 81 | 82 | Parser.parseFromSub( 83 | "https://raw.iqiq.io/caijh/FreeProxiesScraper/2951ca40e0b93dc37be07a46ecc528bf245b6be8/README.md" 84 | ) 85 | .also { println(it.size) } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/me/leon/NodeCrawler.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import kotlinx.coroutines.async 4 | import kotlinx.coroutines.runBlocking 5 | import me.leon.support.* 6 | import org.junit.jupiter.api.Disabled 7 | import org.junit.jupiter.api.Test 8 | import java.text.SimpleDateFormat 9 | import java.util.* 10 | 11 | @Suppress("LongMethod") 12 | class NodeCrawler { 13 | 14 | private val onlyGenerateAll = true 15 | 16 | private val maps = linkedMapOf>() 17 | 18 | private val typeMapper = mapOf( 19 | SS::class.java to (NODE_SS to "ss节点: "), 20 | SSR::class.java to (NODE_SSR to "ssr节点: "), 21 | V2ray::class.java to (NODE_V2 to "v2ray节点: "), 22 | Trojan::class.java to (NODE_TR to "trojan节点: "), 23 | Vless::class.java to (NODE_VLESS to "vless节点: "), 24 | Hysteria2::class.java to (NODE_HYS2 to "hysteria2节点: "), 25 | ) 26 | 27 | 28 | /** 1.爬取配置文件对应链接的节点,并去重 2.同时进行可用性测试 tcping */ 29 | @Test 30 | fun crawl() { 31 | // 1.爬取配置文件的订阅 32 | crawlNodes() 33 | SpeedTest().exec() 34 | nodeGroup() 35 | } 36 | 37 | /** 爬取配置文件数据,并去重写入文件 */ 38 | @Test 39 | @Disabled 40 | fun crawlNodes() { 41 | val mergeSubs = mergeAllNodesUrl() 42 | println(mergeSubs.size) 43 | val prefix = SimpleDateFormat("MMddHH").format(Date()) 44 | val countryMap = mutableMapOf() 45 | val errorList = mutableListOf() 46 | POOL.writeLine() 47 | runBlocking { 48 | mergeSubs.map { sub -> 49 | sub to 50 | async(DISPATCHER) { 51 | runCatching { 52 | val uri = sub 53 | Parser.parseFromSub(uri).also { 54 | println("$uri ${it.size}") 55 | if (it.size == 0) { 56 | errorList.add(uri) 57 | } 58 | } 59 | } 60 | .getOrElse { 61 | println("___parse failed $sub ${it.message}") 62 | linkedSetOf() 63 | } 64 | } 65 | } 66 | .map { it.first to it.second.await() } 67 | .fold(linkedSetOf()) { acc, linkedHashSet -> 68 | maps[linkedHashSet.first] = linkedHashSet.second 69 | acc.apply { acc.addAll(linkedHashSet.second) } 70 | } 71 | .also { nodeCount = it.size } 72 | .filterNot { it.methodUnSupported() } 73 | .map { it to async(DISPATCHER) { it.SERVER.quickConnect(it.serverPort, 2000) } } 74 | .filter { it.second.await() > -1 } 75 | .map { 76 | it.first.apply { 77 | with(this.ipCountryZh()) { 78 | countryMap[this] = countryMap.getOrDefault(this, 0) + 1 79 | name = "${this}_$prefix${"%03d".format(countryMap[this])}" 80 | } 81 | } 82 | } 83 | .sortedBy { it.name } 84 | .also { 85 | NODE_OK.writeLine(it.joinToString("\n") { it.toUri() }, false) 86 | // 2.筛选可用节点 87 | println("有效节点: ${it.size}") 88 | nodeInfo.writeLine("更新时间${timeStamp()}\r\n", false) 89 | nodeInfo.writeLine("${System.lineSeparator()}**总订阅: $subCount**") 90 | nodeInfo.writeLine("**总节点: $nodeCount**") 91 | 92 | it.filterIsInstance() 93 | .groupBy { it.javaClass } 94 | .forEach { (clazz, subList) -> 95 | subList.firstOrNull()?.run { name = CUSTOM_INFO + name } 96 | val data = subList.joinToString("\n") { it.toUri() }.b64Encode() 97 | NODE_VLESS.writeLine() 98 | writeData(clazz, data, subList) 99 | } 100 | it.filterIsInstance() 101 | .groupBy { it.javaClass } 102 | .forEach { (clazz, subList) -> 103 | subList.firstOrNull()?.run { name = CUSTOM_INFO + name } 104 | val data = subList.joinToString("\n") { it.toUri() }.b64Encode() 105 | NODE_HYS2.writeLine() 106 | writeData(clazz, data, subList) 107 | } 108 | } 109 | } 110 | 111 | println("_________________ \n${errorList.joinToString(System.lineSeparator())}") 112 | } 113 | 114 | private fun nodeGroup() { 115 | val nodes = Parser.parseFromSub(NODE_OK) 116 | val regex = "[a-zA-Z]".toRegex() 117 | nodes.filterNot { it.SERVER.contains(regex) } 118 | .forEach { 119 | kotlin.runCatching { 120 | it.name += " "+it.SERVER.ipScore().lvl 121 | }.onFailure { 122 | println("${it.message}") 123 | } 124 | } 125 | nodeInfo.writeLine("\n**google ping有效节点: ${nodes.size}**") 126 | NODE_ALL.writeLine( 127 | nodes.filterNot { it is Vless || it is Hysteria2 }.joinToString("\n") { it.toUri() }.b64Encode(), 128 | false 129 | ) 130 | 131 | nodes 132 | .groupBy { it.javaClass } 133 | .forEach { (clazz, subList) -> 134 | subList.firstOrNull()?.run { name = CUSTOM_INFO + name } 135 | val data = subList.joinToString("\n") { it.toUri() }.b64Encode() 136 | writeData(clazz, data, subList) 137 | } 138 | } 139 | 140 | private fun writeData(clazz: Class, data: String, subList: List) { 141 | if (onlyGenerateAll && clazz != Vless::class.java && clazz != Hysteria2::class.java) { 142 | return 143 | } 144 | typeMapper[clazz]?.run { 145 | first.writeLine(data, false).also { 146 | println("$second${subList.size}".also { nodeInfo.writeLine("- $it") }) 147 | } 148 | } 149 | } 150 | 151 | private fun mergeAllNodesUrl(): HashSet { 152 | val sub1 = "$ROOT/pool/subs".readLines() 153 | val sublist = "$ROOT/pool/sublists".readLines() 154 | val sub2 = 155 | sublist 156 | .map { it.readFromNet() } 157 | .flatMap { it.split("\r\n|\n".toRegex()) } 158 | .distinct() 159 | .filterNot { it.startsWith("#") || it.trim().isEmpty() } 160 | .also { 161 | println(it) 162 | println("after ${it.size}") 163 | } 164 | val mergeSubs = (sub1 + sub2) 165 | .filterNot { it.trim().startsWith("#") || it.trim().isEmpty() } 166 | .toHashSet() 167 | .also { println("共有订阅源:${it.size.also { subCount = it }}") } 168 | 169 | return mergeSubs 170 | } 171 | 172 | companion object { 173 | private val nodeInfo = "$ROOT/info.md" 174 | const val CUSTOM_INFO = "防失效github SubCrawler" 175 | private var subCount = 0 176 | private var nodeCount = 0 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/test/java/me/leon/NodeProcess.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import org.junit.jupiter.api.Test 4 | 5 | class NodeProcess { 6 | 7 | @Test 8 | fun nodeNationGroup() { 9 | Parser.parseFromSub(NODE_OK) 10 | .filter { it.SERVER.contains("p3r.centaur.net") && it.SERVER.ipCountryZh() == "中国" } 11 | .groupBy { it.SERVER.ipCountryZh() } 12 | .forEach { (t, u) -> 13 | println("$t: ${u.size}") 14 | if (t == "UNKNOWN") println(u.map { it.SERVER }) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/me/leon/SpeedTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import me.leon.domain.LiteSpeed 4 | import me.leon.domain.LiteSpeedConfig 5 | import me.leon.support.* 6 | import org.junit.jupiter.api.Test 7 | import java.nio.charset.Charset 8 | 9 | class SpeedTest { 10 | @Test 11 | fun exec() { 12 | val config = "litespeed/config.json".toFile().absoluteFile 13 | if (!NODE_OK.toFile().exists()) { 14 | println("---------------------- error") 15 | return 16 | } 17 | config.writeBytes(LiteSpeedConfig(NODE_OK).toJson().toByteArray()) 18 | val nodes = mutableMapOf() 19 | val oks = mutableListOf() 20 | 21 | val process = 22 | Runtime.getRuntime().exec("litespeed/lite --config litespeed/config.json --test Leon") 23 | 24 | process.errorStream.bufferedReader(Charset.defaultCharset()).use { 25 | it.forEachLine { 26 | if (it.length <=19) { 27 | return@forEachLine 28 | } 29 | val message = it.substring(19) 30 | if (message.contains("json options: ")) { 31 | return@forEachLine 32 | } 33 | runCatching { 34 | val liteSpeed = message.fromJson() 35 | liteSpeed.servers?.forEach { nodes[it.id] = it.link } 36 | liteSpeed.ping()?.run { oks.add(liteSpeed.id) } 37 | }.getOrElse { 38 | println("$message ${it.stackTraceToString()}") 39 | } 40 | } 41 | } 42 | 43 | println("${oks.size} $oks ") 44 | NODE_OK.writeLine(nodes.filter { oks.contains(it.key) }.values.joinToString("\n"), false) 45 | } 46 | } 47 | 48 | const val INCREMENT = "█" 49 | const val EMPTY = "*" 50 | 51 | fun progress(cur: Int, max: Int, length: Int = 60, desc: String = "Progress") { 52 | require(max > 0) 53 | val p = cur * length / max 54 | print("\r$desc: [${INCREMENT.repeat(p)}${EMPTY.repeat(length - p)}]") 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/me/leon/ThirdVpnCrack.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import java.io.File 4 | import java.text.SimpleDateFormat 5 | import java.util.Date 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.runBlocking 8 | import me.leon.domain.Quark 9 | import me.leon.support.* 10 | import org.junit.jupiter.api.Test 11 | 12 | class ThirdVpnCrack { 13 | 14 | private val quarkVpnDir = "$ROOT/vpn/quark" 15 | 16 | @Test 17 | fun parseNet() { 18 | val key = SimpleDateFormat("yyyyMMdd").format(Date()).repeat(4) 19 | "https://ghproxy.com/https://raw.githubusercontent.com/webdao/v2ray/master/nodes.txt" 20 | .readFromNet() 21 | .b64Decode() 22 | .foldIndexed(StringBuilder()) { index, acc, c -> 23 | acc.also { acc.append((c.code xor key[index % key.length].code).toChar()) } 24 | } 25 | .also { println(it) } 26 | .split("\n") 27 | .also { println(it.joinToString("|")) } 28 | } 29 | 30 | @Test 31 | fun parseQuarkVpn() { 32 | runBlocking { 33 | File(quarkVpnDir) 34 | .listFiles() 35 | .map { 36 | String( 37 | it.readBytes() 38 | .mapIndexed { index, byte -> 39 | if (index % 2 == 0) (byte - 1).toByte() else (byte + 1).toByte() 40 | } 41 | .toByteArray() 42 | ) 43 | .fromJson() 44 | } 45 | .flatMap { it.data.map { it.host to it.name } } 46 | .distinctBy { it.first } 47 | .also { println("${it.size} $it") } 48 | .map { it to async(DISPATCHER) { it.first.ping(2000) } } 49 | .filter { it.second.await() > -1 } 50 | .also { println("ok ${it.size} ") } 51 | .map { 52 | SS("aes-256-cfb", "4415934295", it.first.first, "50004") 53 | .apply { remark = it.first.second } 54 | .toUri() 55 | } 56 | .also { println(it.joinToString("\n")) } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/me/leon/YamlTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon 2 | 3 | import me.leon.support.* 4 | import org.junit.jupiter.api.Test 5 | import org.yaml.snakeyaml.LoaderOptions 6 | import org.yaml.snakeyaml.Yaml 7 | import org.yaml.snakeyaml.constructor.Constructor 8 | 9 | class YamlTest { 10 | 11 | @Test 12 | fun yaml() { 13 | val list = 14 | listOf( 15 | "https://ghproxy.com/https://raw.githubusercontent.com/clashconfig/online/main/SurfShark(34687).yml", 16 | // 17 | // "https://ghproxy.com/https://raw.githubusercontent.com/mahdibland/SSAggregator/master/sub/sub_merge_yaml.yml", 18 | "https://ghproxy.com/https://raw.githubusercontent.com/vveg26/get_proxy/main/dist/clash.config.yaml", 19 | ) 20 | 21 | for (url in list) { 22 | println(url) 23 | val data = url.readFromNet() 24 | if (data.isNotEmpty()) { 25 | with(Yaml(Constructor(Clash::class.java, LoaderOptions())).load(data.fixYaml()) as Clash) { 26 | println( 27 | this.proxies.map(Node::toNode).filterIsInstance().joinToString( 28 | "|" 29 | ) { sub -> 30 | sub.also { println(it) }.toUri() 31 | } 32 | ) 33 | } 34 | } else { 35 | println("no content") 36 | } 37 | } 38 | } 39 | 40 | @Test 41 | fun str() { 42 | val raw = 43 | """ 44 | - cipher: aes-128-cfb 45 | name: '[10-12]-🇦🇶-本机地址-964-${'$'}*@14.29.124.174' 46 | password: 47 | server: ${'$'}*@14.29.124.174 48 | port: 11049 49 | type: ss 50 | """ 51 | .trimIndent() 52 | 53 | println(raw) 54 | raw.replace("!<[^>]+>".toRegex(), "") 55 | .replace(" password: \n", "") 56 | .replace("server: $*@", "server: ") 57 | .also { println(it) } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/me/leon/ip/GeoTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon.ip 2 | 3 | import me.leon.FAIL_IPS 4 | import me.leon.GeoParser.cityReader 5 | import me.leon.ipCityZh 6 | import me.leon.ipCountryEn 7 | import me.leon.ipCountryZh 8 | import me.leon.support.readLines 9 | import me.leon.support.toInetAddress 10 | import org.junit.jupiter.api.Test 11 | 12 | class GeoTest { 13 | 14 | @Test 15 | fun geoParse() { 16 | 17 | val ipAddress = "128.101.101.101" 18 | // val ipAddress = "104.19.45.161" 19 | 20 | println(ipAddress.ipCountryZh()) 21 | // println(ipAddress.ipCountryEn()) 22 | // println(ipAddress.ipCityZh()) 23 | // println(ipAddress.ipCountryEn()) 24 | } 25 | 26 | @Test 27 | fun ip_reader() { 28 | FAIL_IPS.readLines().forEach { 29 | """^(\d+(?:.\d+){3})(:\d+)?$""".toRegex().matchEntire(it)?.run { 30 | println(this.groupValues[1] to this.groupValues[1].toInetAddress().ipCountryZh()) 31 | } 32 | // println(reader2.country(InetAddress.getByName(it)).country.names["zh-CN"]) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/me/leon/ip/HostsTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon.ip 2 | 3 | import kotlin.streams.toList 4 | import kotlinx.coroutines.async 5 | import kotlinx.coroutines.runBlocking 6 | import me.leon.HOST 7 | import me.leon.SHARE 8 | import me.leon.domain.DnsResolve 9 | import me.leon.domain.Host 10 | import me.leon.support.* 11 | import org.junit.jupiter.api.Test 12 | 13 | class HostsTest { 14 | 15 | private val reg = "https://www\\.ipaddress\\.com/ipv4/(\\d+.\\d+.\\d+.\\d+)".toRegex() 16 | 17 | // https://raw.fastgit.org/VeleSila/yhosts/master/hosts 18 | // https://raw.fastgit.org/jdlingyu/ad-wars/master/hosts 19 | // https://raw.fastgit.org/Goooler/1024_hosts/master/hosts 20 | // https://winhelp2002.mvps.org/hosts.txt 21 | // https://raw.fastgit.org/StevenBlack/hosts/master/hosts 22 | // https://github.com/E7KMbb/AD-hosts 23 | @Test 24 | fun blacklist() { 25 | listOf( 26 | "https://raw.fastgit.org/VeleSila/yhosts/master/hosts", 27 | "https://raw.fastgit.org/jdlingyu/ad-wars/master/hosts", 28 | "https://raw.fastgit.org/Goooler/1024_hosts/master/hosts", 29 | "https://winhelp2002.mvps.org/hosts.txt", 30 | "https://raw.fastgit.org/StevenBlack/hosts/master/hosts", 31 | "https://raw.fastgit.org/E7KMbb/AD-hosts/master/system/etc/hosts", 32 | "https://raw.fastgit.org/ilpl/ad-hosts/master/hosts", 33 | "https://raw.fastgit.org/rentianyu/Ad-set-hosts/master/hosts" 34 | ) 35 | .flatMap { 36 | it.readFromNet() 37 | .split("\n|\r\n".toRegex()) 38 | .map(String::trim) 39 | .filterNot fn@{ it.isEmpty() || it.startsWith("#") } 40 | .map { 41 | it.split("\\s+".toRegex()).run { 42 | Host(this[1]).apply { 43 | ip = 44 | if (this@run[0] == "127.0.0.1" && domain != "localhost") { 45 | "0.0.0.0" 46 | } else { 47 | this@run[0] 48 | } 49 | } 50 | } 51 | } 52 | .filterNot { it.domain.contains("#") || it.domain == "0.0.0.0" } 53 | .also { println(it.size) } 54 | } 55 | .distinct() 56 | .sortedBy(Host::domain) 57 | .also { 58 | println(it.size) 59 | "$SHARE/blackhosts".writeLine(it.joinToString("\n"), false) 60 | } 61 | } 62 | 63 | // https://raw.fastgit.org/googlehosts/hosts/master/hosts-files/hosts 64 | // 需要单独走无污染 dns,获取最新的ip 65 | @Test 66 | fun whitelist() { 67 | runBlocking { 68 | listOf( 69 | "https://raw.fastgit.org/googlehosts/hosts/master/hosts-files/hosts", 70 | "https://raw.fastgit.org/Leon406/pyutil/master/github/hosts", 71 | "https://raw.fastgit.org/Leon406/jsdelivr/master/hosts/whitelist", 72 | ) 73 | .flatMap { 74 | it.readFromNet() 75 | .split("\n|\r\n".toRegex()) 76 | .map(String::trim) 77 | .filterNot { it.isEmpty() || it.startsWith("#") } 78 | .map { 79 | it.split("\\s+".toRegex()).run { 80 | Host(this[1]).apply { ip = this@run[0] } 81 | } 82 | } 83 | .filterNot { it.domain.contains("#") } 84 | .also { println(it.size) } 85 | } 86 | .distinct() 87 | // .sortedBy (Host::domain) 88 | .map { it to async(DISPATCHER) { it.ip.quickPing(1000) } } 89 | .map { it.second.await() to it.first } 90 | .forEach { 91 | if (it.first > -1) { 92 | println("ok ip ${it.second}") 93 | "$SHARE/whitehost".writeLine(it.second.toString(), true) 94 | } else { 95 | println("err ip ${it.second}") 96 | } 97 | } 98 | } 99 | } 100 | 101 | @Test 102 | fun dns() { 103 | 104 | val unReachableDomains = mutableListOf() 105 | HostsTest::class 106 | .java 107 | .getResourceAsStream("/domains")!! 108 | .bufferedReader() 109 | .use { it.lines().toList() } 110 | .filterNot { it.isEmpty() || it.startsWith("#") } 111 | .map { dnsResolve(it) + "\t" + it } 112 | .filter { 113 | val isEmp = it.startsWith("\t") 114 | if (isEmp) unReachableDomains.add(it.substring(1)) 115 | !isEmp 116 | } 117 | .also { 118 | HOST.toFile().writeText("##### 更新时间${timeStamp()} #####\n" + it.joinToString("\n")) 119 | } 120 | println(unReachableDomains) 121 | unReachableDomains 122 | .map { ipApiResolve(it) + "\t" + it } 123 | .filter { 124 | val isEmp = it.startsWith("\t") || it.contains(",") 125 | if (isEmp) println(it.substring(1)) 126 | !isEmp 127 | } 128 | .also { HOST.toFile().appendText("\n" + it.joinToString("\n")) } 129 | } 130 | 131 | @Test 132 | fun ipAddress() { 133 | ipApiResolve("baidu.com").also { println(it) } 134 | } 135 | 136 | private fun dnsResolve(url: String): String = 137 | runCatching { 138 | "https://1.1.1.1/dns-query?name=$url&type=1" 139 | .readBytesFromNet(headers = mutableMapOf("accept" to "application/dns-json")) 140 | .decodeToString() 141 | .fromJson() 142 | .Answer 143 | ?.find { it.type == 1 && it.data!!.quickPing() > 0 } 144 | ?.data 145 | .orEmpty() 146 | } 147 | .getOrDefault("") 148 | 149 | private fun ipApiResolve(url: String): String = 150 | runCatching { 151 | "https://ipaddress.com/website/$url" 152 | .readBytesFromNet( 153 | headers = mutableMapOf("referer" to "https://www.ipaddress.com/") 154 | ) 155 | .decodeToString() 156 | .run { reg.find(this)?.groupValues?.get(1).orEmpty() } 157 | } 158 | .getOrDefault("") 159 | } 160 | -------------------------------------------------------------------------------- /src/test/java/me/leon/ip/IpFilterTest.kt: -------------------------------------------------------------------------------- 1 | package me.leon.ip 2 | 3 | import kotlinx.coroutines.async 4 | import kotlinx.coroutines.runBlocking 5 | import me.leon.* 6 | import me.leon.support.* 7 | import org.junit.jupiter.api.Test 8 | import kotlin.system.measureTimeMillis 9 | 10 | class IpFilterTest { 11 | 12 | @Test 13 | fun reTestFailIps() { 14 | repeat(5) { 15 | failIp() 16 | removeOkPorts() 17 | } 18 | } 19 | 20 | @Test 21 | fun failIp() { 22 | val okIps = mutableSetOf() 23 | val failIps = mutableSetOf() 24 | val failPorts = mutableSetOf() 25 | val total = mutableSetOf() 26 | 27 | runBlocking { 28 | measureTimeMillis { 29 | FAIL_IPS.readLines() 30 | .also { println("before ${it.size}") } 31 | .sorted() 32 | .also { 33 | total.addAll(it) 34 | println("after deduplicate and sort ${total.size}") 35 | FAIL_IPS.writeLine() 36 | FAIL_IPS.writeLine(total.joinToString("\n")) 37 | } 38 | .map { it to async(DISPATCHER) { it.substringBeforeLast(':').ping(1000) } } 39 | .map { it.second.await() to it.first } 40 | .forEach { 41 | if (it.first > -1) { 42 | okIps.add(it.second.substringBeforeLast(":")) 43 | println("reAlive ip ${it.second}") 44 | } else { 45 | failIps.add(it.second.substringBeforeLast(":")) 46 | if (it.second.contains(":")) failPorts.add(it.second) 47 | } 48 | } 49 | 50 | println(failIps) 51 | println(failPorts) 52 | println("_______") 53 | println(okIps) 54 | total 55 | .also { 56 | println("before ${it.size}") 57 | it.removeAll(okIps) 58 | it.removeAll(failPorts) 59 | it.addAll(failIps) 60 | } 61 | .filterNot { 62 | it.contains(":") && failIps.contains(it.substringBeforeLast(":")) 63 | } 64 | .sorted() 65 | .also { 66 | FAIL_IPS.writeLine() 67 | FAIL_IPS.writeLine(it.joinToString("\n")) 68 | println("after ${it.size}") 69 | } 70 | } 71 | .also { println("time $it ms") } 72 | } 73 | } 74 | 75 | @Test 76 | fun removeOkPorts() { 77 | val total = mutableSetOf() 78 | runBlocking { 79 | FAIL_IPS.readLines() 80 | .also { 81 | total.addAll(it) 82 | println("before ${total.size}") 83 | } 84 | .filter { it.contains(":") && !it.contains("/") && !it.contains(" ") } 85 | .map { 86 | it to 87 | async(DISPATCHER) { 88 | runCatching { 89 | it.substringBeforeLast(":").connect(it.substringAfterLast(":").toInt()) 90 | }.getOrElse { -1 } 91 | } 92 | } 93 | .filter { it.second.await() > -1 } 94 | .forEach { 95 | println(it.first) 96 | total.remove(it.first) 97 | } 98 | } 99 | println("after ${total.size}") 100 | FAIL_IPS.writeLine() 101 | FAIL_IPS.writeLine(total.joinToString("\n")) 102 | } 103 | 104 | @Test 105 | fun checkAbuseIp() { 106 | Parser.parseFromSub("C:\\Users\\Leon\\Desktop\\local.yaml").map { it.SERVER } 107 | .distinct() 108 | .also { println(it.size) } 109 | .filterNot { it.contains("[a-zA-Z]".toRegex()) } 110 | .also { println(it) } 111 | .forEach { 112 | println("$it ${it.ipScore().lvl}") 113 | } 114 | } 115 | 116 | } 117 | 118 | -------------------------------------------------------------------------------- /src/test/resources/domains: -------------------------------------------------------------------------------- 1 | #stackoverflow 2 | stackoverflow.com 3 | stackexchange.com 4 | cdn.sstatic.net 5 | #js cdn 6 | cdn.jsdelivr.net 7 | unpkg.com 8 | code.jquery.com 9 | cdnjs.com 10 | cdnjs.cloudflare.com 11 | #oracle 12 | sdlc-esd.oracle.com 13 | download.oracle.com 14 | #hcaptcha 15 | hcaptcha.com 16 | www.hcaptcha.com 17 | assets.hcaptcha.com 18 | imgs.hcaptcha.com 19 | newassets.hcaptcha.com 20 | cf-assets.hcaptcha.com 21 | js.hcaptcha.com 22 | api.hcaptcha.com 23 | #recaptcha 24 | recaptcha.net 25 | api.recaptcha.net 26 | api-secure.recaptcha.net 27 | api-verify.recaptcha.net 28 | mailhide.recaptcha.net 29 | www.recaptcha.net 30 | #discord 31 | discord.com 32 | discordapp.com 33 | dl.discordapp.net 34 | gateway.discord.gg 35 | status.discordapp.com 36 | cdn.discordapp.com 37 | media.discordapp.net 38 | images-ext-2.discordapp.net 39 | images-ext-1.discordapp.net 40 | discordcdn.com 41 | #lastpass 42 | lastpass.com 43 | www.lastpass.com 44 | data.lastpass.com 45 | content.product.lastpass.com 46 | #microsoft 47 | logincdn.msauth.net 48 | acctcdn.msauth.net 49 | login.live.com 50 | storage.live.com 51 | public.bn.files.1drv.com 52 | storeedgefd.dsx.mp.microsoft.com 53 | store-images.s-microsoft.com 54 | #arkoselabs验证码 55 | client-api.arkoselabs.com 56 | cdn.arkoselabs.com 57 | prod-ireland.arkoselabs.com 58 | #github 59 | github-cloud.s3.amazonaws.com 60 | gist.github.com 61 | api.github.com 62 | live.github.com 63 | status.github.com 64 | github-production-release-asset-2e65be.s3.amazonaws.com 65 | github-production-user-asset-6210df.s3.amazonaws.com 66 | github.com 67 | www.github.com 68 | alive.github.com 69 | collector.githubapp.com 70 | github.githubassets.com 71 | help.github.com 72 | central.github.com 73 | pipelines.actions.githubusercontent.com 74 | collector.github.com 75 | github.community 76 | support.github.com 77 | assets-cdn.github.com 78 | pages.github.com 79 | training.github.com 80 | github.io 81 | githubstatus.com 82 | documentcloud.github.com 83 | customer-stories-feed.github.com 84 | docs.github.com 85 | githubapp.com 86 | codeload.github.com 87 | nodeload.github.com 88 | github-com.s3.amazonaws.com 89 | github-production-repository-file-5c1aeb.s3.amazonaws.com 90 | github.global.ssl.fastly.net 91 | github.blog 92 | avatars.githubusercontent.com 93 | favicons.githubusercontent.com 94 | camo.githubusercontent.com 95 | user-images.githubusercontent.com 96 | gist.githubusercontent.com 97 | raw.github.com 98 | raw.githubusercontent.com 99 | cloud.githubusercontent.com 100 | objects.githubusercontent.com 101 | media.githubusercontent.com 102 | github.map.fastly.net 103 | desktop.githubusercontent.com 104 | github.dev 105 | # 谷歌翻译 106 | translate.googleapis.com 107 | translate.google.com -------------------------------------------------------------------------------- /sub/flags.txt: -------------------------------------------------------------------------------- 1 | 🇦🇨|AC|阿森松岛 2 | 🇦🇩|AD|安道尔 3 | 🇦🇪|AE|阿拉伯联合酋长国 4 | 🇦🇫|AF|阿富汗 5 | 🇦🇬|AG|安提瓜和巴布达 6 | 🇦🇮|AI|安圭拉 7 | 🇦🇱|AL|阿尔巴尼亚 8 | 🇦🇲|AM|亚美尼亚 9 | 🇦🇴|AO|安哥拉 10 | 🇦🇶|AQ|南极洲 11 | 🇦🇷|AR|阿根廷 12 | 🇦🇸|AS|美属萨摩亚 13 | 🇦🇹|AT|奥地利 14 | 🇦🇺|AU|澳大利亚 15 | 🇦🇼|AW|阿鲁巴 16 | 🇦🇽|AX|奥兰群岛 17 | 🇦🇿|AZ|阿塞拜疆 18 | 🇧🇦|BA|波斯尼亚和黑塞哥维那 19 | 🇧🇧|BB|巴巴多斯 20 | 🇧🇩|BD|孟加拉国 21 | 🇧🇪|BE|比利时 22 | 🇧🇫|BF|布基纳法索 23 | 🇧🇬|BG|保加利亚 24 | 🇧🇭|BH|巴林 25 | 🇧🇮|BI|布隆迪 26 | 🇧🇯|BJ|贝宁 27 | 🇧🇱|BL|圣巴泰勒米 28 | 🇧🇲|BM|百慕大 29 | 🇧🇳|BN|文莱 30 | 🇧🇴|BO|玻利维亚 31 | 🇧🇶|BQ|荷属加勒比区 32 | 🇧🇷|BR|巴西 33 | 🇧🇸|BS|巴哈马 34 | 🇧🇹|BT|不丹 35 | 🇧🇻|BV|布韦岛 36 | 🇧🇼|BW|博茨瓦纳 37 | 🇧🇾|BY|白俄罗斯 38 | 🇧🇿|BZ|伯利兹 39 | 🇨🇦|CA|加拿大 40 | 🇨🇨|CC|科科斯(基林)群岛 41 | 🇨🇩|CD|刚果(金) 42 | 🇨🇫|CF|中非共和国 43 | 🇨🇬|CG|刚果(布) 44 | 🇨🇭|CH|瑞士 45 | 🇨🇮|CI|科特迪瓦 46 | 🇨🇰|CK|库克群岛 47 | 🇨🇱|CL|智利 48 | 🇨🇲|CM|喀麦隆 49 | 🇨🇳|CN|中国 50 | 🇨🇴|CO|哥伦比亚 51 | 🇨🇵|CP|克利珀顿岛 52 | 🇨🇷|CR|哥斯达黎加 53 | 🇨🇺|CU|古巴 54 | 🇨🇻|CV|佛得角 55 | 🇨🇼|CW|库拉索 56 | 🇨🇽|CX|圣诞岛 57 | 🇨🇾|CY|塞浦路斯 58 | 🇨🇿|CZ|捷克 59 | 🇩🇪|DE|德国 60 | 🇩🇬|DG|迪戈加西亚岛 61 | 🇩🇯|DJ|吉布提 62 | 🇩🇰|DK|丹麦 63 | 🇩🇲|DM|多米尼克 64 | 🇩🇴|DO|多米尼加共和国 65 | 🇩🇿|DZ|阿尔及利亚 66 | 🇪🇦|EA|休达及梅利利亚 67 | 🇪🇨|EC|厄瓜多尔 68 | 🇪🇪|EE|爱沙尼亚 69 | 🇪🇬|EG|埃及 70 | 🇪🇭|EH|西撒哈拉 71 | 🇪🇷|ER|厄立特里亚 72 | 🇪🇸|ES|西班牙 73 | 🇪🇹|ET|埃塞俄比亚 74 | 🇪🇺|EU|欧洲 75 | 🇫🇮|FI|芬兰 76 | 🇫🇯|FJ|斐济 77 | 🇫🇰|FK|福克兰群岛 78 | 🇫🇲|FM|密克罗尼西亚 79 | 🇫🇴|FO|法罗群岛 80 | 🇫🇷|FR|法国 81 | 🇬🇦|GA|加蓬 82 | 🇬🇧|GB|英国 83 | 🇬🇩|GD|格林纳达 84 | 🇬🇪|GE|格鲁吉亚 85 | 🇬🇫|GF|法属圭亚那 86 | 🇬🇬|GG|根西岛 87 | 🇬🇭|GH|加纳 88 | 🇬🇮|GI|直布罗陀 89 | 🇬🇱|GL|格陵兰 90 | 🇬🇲|GM|冈比亚 91 | 🇬🇳|GN|几内亚 92 | 🇬🇵|GP|瓜德罗普 93 | 🇬🇶|GQ|赤道几内亚 94 | 🇬🇷|GR|希腊 95 | 🇬🇸|GS|南乔治亚和南桑威奇群岛 96 | 🇬🇹|GT|危地马拉 97 | 🇬🇺|GU|关岛 98 | 🇬🇼|GW|几内亚比绍 99 | 🇬🇾|GY|圭亚那 100 | 🇭🇰|HK|香港 101 | 🇭🇲|HM|赫德岛和麦克唐纳群岛 102 | 🇭🇳|HN|洪都拉斯 103 | 🇭🇷|HR|克罗地亚 104 | 🇭🇹|HT|海地 105 | 🇭🇺|HU|匈牙利 106 | 🇮🇨|IC|加纳利群岛 107 | 🇮🇩|ID|印度尼西亚 108 | 🇮🇪|ED|爱尔兰 109 | 🇮🇱|IL|以色列 110 | 🇮🇲|IM|马恩岛 111 | 🇮🇳|IN|印度 112 | 🇮🇴|IO|英属印度洋领地 113 | 🇮🇶|IQ|伊拉克 114 | 🇮🇷|IR|伊朗 115 | 🇮🇸|IS|冰岛 116 | 🇮🇹|IT|意大利 117 | 🇯🇪|JE|泽西岛 118 | 🇯🇲|JM|牙买加 119 | 🇯🇴|JO|约旦 120 | 🇯🇵|JP|日本 121 | 🇰🇪|KE|肯尼亚 122 | 🇰🇬|KG|吉尔吉斯斯坦 123 | 🇰🇭|KH|柬埔寨 124 | 🇰🇮|KI|基里巴斯 125 | 🇰🇲|KM|科摩罗 126 | 🇰🇳|KN|圣基茨和尼维斯 127 | 🇰🇵|KP|朝鲜 128 | 🇰🇷|KR|韩国 129 | 🇰🇼|KW|科威特 130 | 🇰🇾|KY|开曼群岛 131 | 🇰🇿|KZ|哈萨克斯坦 132 | 🇱🇦|LA|老挝 133 | 🇱🇧|LB|黎巴嫩 134 | 🇱🇨|LC|圣卢西亚 135 | 🇱🇮|LI|列支敦士登 136 | 🇱🇰|LK|斯里兰卡 137 | 🇱🇷|LR|利比里亚 138 | 🇱🇸|LS|莱索托 139 | 🇱🇹|LT|立陶宛 140 | 🇱🇺|LU|卢森堡 141 | 🇱🇻|LV|拉脱维亚 142 | 🇱🇾|LY|利比亚 143 | 🇲🇦|MA|摩洛哥 144 | 🇲🇨|MC|摩纳哥 145 | 🇲🇩|MD|摩尔多瓦 146 | 🇲🇪|ME|黑山 147 | 🇲🇫|MF|法属圣马丁 148 | 🇲🇬|MG|马达加斯加 149 | 🇲🇭|MH|马绍尔群岛 150 | 🇲🇰|MK|北马其顿 151 | 🇲🇱|ML|马里 152 | 🇲🇲|MM|缅甸 153 | 🇲🇳|MN|蒙古 154 | 🇲🇴|MO|澳门 155 | 🇲🇵|MP|北马里亚纳群岛 156 | 🇲🇶|MQ|马提尼克 157 | 🇲🇷|MR|毛里塔尼亚 158 | 🇲🇸|MS|蒙特塞拉特 159 | 🇲🇹|MT|马耳他 160 | 🇲🇺|MU|毛里求斯 161 | 🇲🇻|MV|马尔代夫 162 | 🇲🇼|MW|马拉维 163 | 🇲🇽|MX|墨西哥 164 | 🇲🇾|MY|马来西亚 165 | 🇲🇿|MZ|莫桑比克 166 | 🇳🇦|NA|纳米比亚 167 | 🇳🇨|NC|新喀里多尼亚 168 | 🇳🇪|NE|尼日尔 169 | 🇳🇫|NF|诺福克岛 170 | 🇳🇬|NG|尼日利亚 171 | 🇳🇮|NI|尼加拉瓜 172 | 🇳🇱|NL|荷兰 173 | 🇳🇴|NO|挪威 174 | 🇳🇵|NP|尼泊尔 175 | 🇳🇷|NR|瑙鲁 176 | 🇳🇺|NU|纽埃 177 | 🇳🇿|NZ|新西兰 178 | 🇴🇲|OM|阿曼 179 | 🇵🇦|PA|巴拿马 180 | 🇵🇪|PE|秘鲁 181 | 🇵🇫|PF|法属波利尼西亚 182 | 🇵🇬|PG|巴布亚新几内亚 183 | 🇵🇭|PH|菲律宾 184 | 🇵🇰|PK|巴基斯坦 185 | 🇵🇱|PL|波兰 186 | 🇵🇲|PM|圣皮埃尔和密克隆群岛 187 | 🇵🇳|PN|皮特凯恩群岛 188 | 🇵🇷|PR|波多黎各 189 | 🇵🇸|PS|巴勒斯坦领土 190 | 🇵🇹|PT|葡萄牙 191 | 🇵🇼|PW|帕劳 192 | 🇵🇾|PY|巴拉圭 193 | 🇶🇦|QA|卡塔尔 194 | 🇷🇪|RE|留尼汪 195 | 🇷🇴|RO|罗马尼亚 196 | 🇷🇸|RS|塞尔维亚 197 | 🇷🇺|RU|俄罗斯 198 | 🇷🇼|RW|卢旺达 199 | 🇸🇦|SA|沙特阿拉伯 200 | 🇸🇧|SB|所罗门群岛 201 | 🇸🇨|SC|塞舌尔 202 | 🇸🇩|SD|苏丹 203 | 🇸🇪|SE|瑞典 204 | 🇸🇬|SG|新加坡 205 | 🇸🇭|SH|圣赫勒拿 206 | 🇸🇮|SI|斯洛文尼亚 207 | 🇸🇯|SJ|斯瓦尔巴和扬马延 208 | 🇸🇰|SK|斯洛伐克 209 | 🇸🇱|SL|塞拉利昂 210 | 🇸🇲|SM|圣马力诺 211 | 🇸🇳|SN|塞内加尔 212 | 🇸🇴|SO|索马里 213 | 🇸🇷|SR|苏里南 214 | 🇸🇸|SS|南苏丹 215 | 🇸🇹|ST|圣多美和普林西比 216 | 🇸🇻|SV|萨尔瓦多 217 | 🇸🇽|SX|荷属圣马丁 218 | 🇸🇾|SY|叙利亚 219 | 🇸🇿|SZ|斯威士兰 220 | 🇹🇦|TA|特里斯坦-达库尼亚群岛 221 | 🇹🇨|TC|特克斯和凯科斯群岛 222 | 🇹🇩|TD|乍得 223 | 🇹🇫|TF|法属南部领地 224 | 🇹🇬|TG|多哥 225 | 🇹🇭|TH|泰国 226 | 🇹🇯|TJ|塔吉克斯坦 227 | 🇹🇰|TK|托克劳 228 | 🇹🇱|TL|东帝汶 229 | 🇹🇲|TM|土库曼斯坦 230 | 🇹🇳|TN|突尼斯 231 | 🇹🇴|TO|汤加 232 | 🇹🇷|TR|土耳其 233 | 🇹🇹|TT|特立尼达和多巴哥 234 | 🇹🇻|TV|图瓦卢 235 | 🇹🇼|TW|台湾 236 | 🇹🇿|TZ|坦桑尼亚 237 | 🇺🇦|UA|乌克兰 238 | 🇺🇬|UG|乌干达 239 | 🇺🇲|UM|美国 240 | 🇺🇳|UN|联合国 241 | 🇺🇸|US|美国 242 | 🇺🇾|UY|乌拉圭 243 | 🇺🇿|UZ|乌兹别克斯坦 244 | 🇻🇦|VA|梵蒂冈 245 | 🇻🇨|VC|圣文森特和格林纳丁斯 246 | 🇻🇪|VE|委内瑞拉 247 | 🇻🇬|VG|英属维尔京群岛 248 | 🇻🇮|VI|美属维尔京群岛 249 | 🇻🇳|VN|越南 250 | 🇻🇺|VU|瓦努阿图 251 | 🇼🇫|WF|瓦利斯和富图纳 252 | 🇼🇸|WS|萨摩亚 253 | 🇽🇰|XK|科索沃 254 | 🇾🇪|YE|也门 255 | 🇾🇹|YT|马约特 256 | 🇿🇦|ZA|南非 257 | 🇿🇲|ZM|赞比亚 258 | 🇿🇼|ZW|津巴布韦 259 | 🏁|ZZ|未知 -------------------------------------------------------------------------------- /sub/info.md: -------------------------------------------------------------------------------- 1 | 更新时间2025-06-02 18:17:23 2 | 3 | **总订阅: 160** 4 | **总节点: 38787** 5 | - vless节点: 17938 6 | - hysteria2节点: 6 7 | 8 | **google ping有效节点: 308** 9 | -------------------------------------------------------------------------------- /sub/pool/sublists: -------------------------------------------------------------------------------- 1 | https://raw.githubusercontent.com/Leon406/jsdelivr/master/subscribe/sub.txt 2 | https://raw.githubusercontent.com/Leon406/jsdelivr/master/subscribe/subpool5 -------------------------------------------------------------------------------- /sub/pool/subs: -------------------------------------------------------------------------------- 1 | https://raw.githubusercontent.com/adiwzx/freenode/main/adispeed.yml 2 | https://raw.githubusercontent.com/freefq/free/master/v2 3 | https://raw.githubusercontent.com/huaxinCLUB/NodeSpider/master/newYaml/mattkaydiary.yaml 4 | https://raw.githubusercontent.com/ssrsub/ssr/master/Clash.yml 5 | https://raw.githubusercontent.com/zyzmzyz/free-nodes/master/Clash.yml 6 | https://raw.githubusercontent.com/pojiezhiyuanjun/freev2/master/0727clash.yml 7 | https://raw.githubusercontent.com/xiyaowong/freeFQ/main/v2ray 8 | https://raw.githubusercontent.com/iwxf/free-v2ray/master/index.html 9 | https://raw.githubusercontent.com/ermaozi/get_subscribe/main/subscribe/v2ray.txt 10 | https://raw.githubusercontent.com/wrfree/free/main/v2 11 | https://raw.githubusercontent.com/ronghuaxueleng/get_v2/main/pub/changfengoss.yaml 12 | https://raw.githubusercontent.com/anaer/Sub/main/clash.yaml 13 | https://v2ray.neocities.org/v2ray.txt 14 | https://raw.githubusercontent.com/mahdibland/SSAggregator/master/sub/sub_merge_yaml.yml -------------------------------------------------------------------------------- /sub/share/host: -------------------------------------------------------------------------------- 1 | ##### 更新时间2025-06-01 12:31:11 ##### 2 | 3 | -------------------------------------------------------------------------------- /sub/share/hysteria2: -------------------------------------------------------------------------------- 1 | aHlzdGVyaWEyOi8vY2RiNjNmZjktMTc2Ny00YTM1LTk3ZTUtOTAwMDQ4ZTRmZWIyQDEwNC4xOTIuOTIuOTk6NDQzP2luc2VjdXJlPTEmc25pPXRtcy5kaW5ndGFsay5jb20jJUU5JTk4JUIyJUU1JUE0JUIxJUU2JTk1JTg4Z2l0aHViK1N1YkNyYXdsZXIlRTYlOTYlQjAlRTUlOEElQTAlRTUlOUQlQTFfMDYwMjEwMDM1Cmh5c3RlcmlhMjovLzVkMTEwZjE4LTVhMzctNGRiMy04Y2Y2LWYwYmNlZDM4YTFhZUAxNTQuODUuMTguMjMzOjQ0Mz9pbnNlY3VyZT0xJnNuaT13d3cuYmluZy5jb20jJUU2JTk3JUE1JUU2JTlDJUFDXzA2MDIxMDAyMQpoeXN0ZXJpYTI6Ly9kb25ndGFpd2FuZy5jb21ANTEuMTU5LjExMS4zMjozMTE4MD9pbnNlY3VyZT0xJnNuaT1hcHBsZS5jb20jJUU2JUIzJTk1JUU1JTlCJUJEXzA2MDIxMDA1MgpoeXN0ZXJpYTI6Ly9zeXNhZG1pbi5zeXNhZG1pbkAxOTIuMjI3LjIzMS4xNDI6NDQzP2luc2VjdXJlPTEjJUU3JUJFJThFJUU1JTlCJUJEXzA2MDIxMDQ2NQpoeXN0ZXJpYTI6Ly9uZnNuNjY2QDEzMC4xNjIuMTgyLjI1MDo4ODg4P2luc2VjdXJlPTEmc25pPWxkLWFybS5uZnNuNjY2LmdxIyVFOCU4QiVCMSVFNSU5QiVCRF8wNjAyMTAwNTMKaHlzdGVyaWEyOi8vNWQxMTBmMTgtNWEzNy00ZGIzLThjZjYtZjBiY2VkMzhhMWFlQDg5LjE4NS4yNy4xMzM6NDQzP2luc2VjdXJlPTEmc25pPXd3dy5iaW5nLmNvbSMlRTklQTYlOTklRTYlQjglQUZfMDYwMjEwMDU3 -------------------------------------------------------------------------------- /sub/share/ss: -------------------------------------------------------------------------------- 1 | c3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WlRrMVkyVmpZakF0TVRJd09DMDBOV05rTFRnek4yUXROakV3WkRRM05tSm1NekkwUURFNE15NHlNekl1TWpRNUxqSXlPakV3TURRNCMlRTklOTglQjIlRTUlQTQlQjElRTYlOTUlODhnaXRodWIrU3ViQ3Jhd2xlciVFNCVCOCVBRCVFNSU5QiVCRF8xMjEzMjAyNTcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WlRrMVkyVmpZakF0TVRJd09DMDBOV05rTFRnek4yUXROakV3WkRRM05tSm1NekkwUURFNE15NHlNekl1TWpRNUxqSXlPakV3TURZeSMlRTQlQjglQUQlRTUlOUIlQkRfMTIxMzIwMjYwCnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UbzFWWGxXWTNnMGFsbHlZMkpHZDIxb1VHdG9lbWx0UURrMUxqRTJOQzQ0T1M0eE5ESTZOVGcyTURNPSMlRTQlQjklOEMlRTUlODUlOEIlRTUlODUlQjBfMTIxMzIwMDAxCnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcFBWMHBzV1dwWmVVQTVNUzR4T1RRdU1UWXhMamM2T0RNNE9BPT0jJUU0JUJGJTg0JUU3JUJEJTk3JUU2JTk2JUFGJUU4JTgxJTk0JUU5JTgyJUE2XzEyMTMyMDAwMQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHA1V21SU1ozTnJaVGcxU0c5MU9UWjZNbVJTWkhSSVFEUTFMakUwTkM0ek1DNHlNREk2TWpnME9UQT0jJUU0JUJGJTg0JUU3JUJEJTk3JUU2JTk2JUFGJUU4JTgxJTk0JUU5JTgyJUE2XzEyMTMyMDAwMwpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBrYUZoRVUzSlBNMGh1YTJoUFdsZDRUazl5ZGtsSlFEWXlMakV4TXk0eE1UUXVNVEUyT2pReU16SXcjJUU0JUJGJTg0JUU3JUJEJTk3JUU2JTk2JUFGJUU4JTgxJTk0JUU5JTgyJUE2XzEyMTMyMDAwNQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBQVjBwc1dXcFplVUE1TVM0eE9UUXVNVFl4TGpjNk1UUTBNdz09IyVFNCVCRiU4NCVFNyVCRCU5NyVFNiU5NiVBRiVFOCU4MSU5NCVFOSU4MiVBNl8xMjEzMjAwMTAKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRveGNUZFNUa3RoU1dzeWQxbFBPR1pGVUcxRldEQjJWMUUzVm1FclVWSlVRVUE1TVM0eE9USXVPREV1TWpFNk9ETTRPQT09IyVFNCVCRiU4NCVFNyVCRCU5NyVFNiU5NiVBRiVFOCU4MSU5NCVFOSU4MiVBNl8xMjEzMjAwMjEKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRveGNUZFNUa3RoU1dzeWQxbFBPR1pGVUcxRldEQjJWMUUzVm1FclVWSlVRVUF4TWpJemFtOXBiaTV2ZFhSc2FXNWxMWFp3Ymk1amJHOTFaRG80TXpnNCMlRTQlQkYlODQlRTclQkQlOTclRTYlOTYlQUYlRTglODElOTQlRTklODIlQTZfMTIxMzIwMDIyCnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcHZka0Y0Uld4TFRubzJhRWhsYTFvMlQwVkJObFUwYm5Vd1YwMWFaRlV6TlRGeldHMXVRVUUwUVhRM01VOU5ZVGxBTlM0eE1ERXVNakU0TGpFeU56bzFNVE0wT0E9PSMlRTQlQkYlODQlRTclQkQlOTclRTYlOTYlQUYlRTglODElOTQlRTklODIlQTZfMTIxMzIwMDIzCnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcGhUbkZGY1hSUlVXRmhRWEpKWW5SUVZXWlpRVFJNY25KS1dYZGtUa050Y0ZWM2N6QXlURFZHYkU4NWVrczVSRkpBTlM0eE9Ea3VNakF4TGpJMU1EbzFNVE0wT0E9PSMlRTQlQkYlODQlRTclQkQlOTclRTYlOTYlQUYlRTglODElOTQlRTklODIlQTZfMTIxMzIwMDI0CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd3Tnc9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDEyCnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd3Tmc9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDEzCnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd4TVE9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDE0CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd3TkE9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDE1CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd3TUE9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDE2CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd3TXc9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDE3CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd4TUE9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDE4CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd3T1E9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDMzCnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhJWGxDZDFCWFNETldZVzlBTVRNMExqRTVOUzR4T1RZdU1UYzRPamd3T0E9PSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDM0CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcDRNM1pyVEd0bFdHdHBRMjVPV25WTWVIVkVZMHA1UURZMExqSXlOeTR4TkRRdU1Ua3dPalV3TmprdyMlRTUlOEQlQjAlRTUlQkElQTZfMTIxMzIwMDEwCnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEhWMHhxUkhBMU5VRlRiMUE0TW5WVFVEQkZZemh1UURZMExqSXlOeTR4TkRRdU1Ua3dPalV3TmprdyMlRTUlOEQlQjAlRTUlQkElQTZfMTIxMzIwMDE1CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcFJNRGd4WjJGMlNGZFBVamRYVDNaUGJ6bGpXR05IUURZMExqSXlOeTR4TkRRdU1Ua3dPalV3TmprdyMlRTUlOEQlQjAlRTUlQkElQTZfMTIxMzIwMDE2CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcGpNR1ptTW1ZNU1DMDVaamd6TFRRMU1XRXRZVGRrTXkwd09UazBPRFExWkRreU1EaEFkSGN1Wkc5MWMyaHBiV1Z1Wnk1amIyMDZORFkyTmpFPSMlRTUlOEYlQjAlRTYlQjklQkVfMTIxMzIwMDM4CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEJSM0kxTmtjMk5VZEdaMnczY0dodllrMXZhWFJ6UURrekxqRTNNQzQzTXk0eE1EUTZOVEV6TkRnPSMlRTUlOTMlODglRTglOTAlQTglRTUlODUlOEIlRTYlOTYlQUYlRTUlOUQlQTZfMTIxMzIwMDAxCnNzOi8vWVdWekxUSTFOaTFuWTIwNllrazFNVlZqTjBOTU5rQTFNQzR4TVRRdU1UVTVMakkxTURvMk5qWTIjJUU1JUI3JUI0JUU1JTlGJUJBJUU2JTk2JUFGJUU1JTlEJUE2XzEyMTMyMDAwMQpzczovL1lXVnpMVEkxTmkxblkyMDZabUZDUVc5RU5UUnJPRGRWU2tjM1FESXhOeTR4T0RJdU1UazRMakl4T1RveU16YzIjJUU1JUJFJUI3JUU1JTlCJUJEXzEyMTMyMDAxMApzczovL1lXVnpMVEkxTmkxblkyMDZjRXRGVnpoS1VFSjVWRlpVVEhSTlFESXhOeTR4T0RJdU1UazRMakl4T1RvME5EUTAjJUU1JUJFJUI3JUU1JTlCJUJEXzEyMTMyMDA0MQpzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU1qRTNMakU0TWk0eE9UZ3VNakU1T2pVd01EQT0jJUU1JUJFJUI3JUU1JTlCJUJEXzEyMTMyMDA0MgpzczovL1lXVnpMVEkxTmkxblkyMDZabUZDUVc5RU5UUnJPRGRWU2tjM1FESXhOeTR4T0RJdU1UazRMakl4T1RveU16YzEjJUU1JUJFJUI3JUU1JTlCJUJEXzEyMTMyMDA0MwpzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU1qRTNMakU0TWk0eE9UZ3VNakU1T2pNek9Eaz0jJUU1JUJFJUI3JUU1JTlCJUJEXzEyMTMyMDA0NApzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU1qRTNMakU0TWk0eE9UZ3VNakU1T2pNek1EWT0jJUU1JUJFJUI3JUU1JTlCJUJEXzEyMTMyMDA0NQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVG93U1hsME4wNUVjWFZ5TXpkd2MwcHphMWxLZEZaWmJucDRkbmgzVDNOWVJtbHVOVFpuYjJNMVIzaDFkRkJXYVhkQU1UZzFMalE0TGpJME9DNHhNalk2TlRFek5EZz0jJUU2JTk2JUFGJUU2JUI0JTlCJUU0JUJDJTkwJUU1JTg1JThCXzEyMTMyMDAwMQpzczovL1lXVnpMVEkxTmkxblkyMDZRamRQTnpsWVVXUlhTVUE0TGpJeE9TNHhPREF1TlRnNk16WXhNalE9IyVFNiU5NiVCMCVFNSU4QSVBMCVFNSU5RCVBMV8xMjEzMjAwMDMKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwSElYbENkMUJYU0ROV1lXOUFNVGcxTGpFM01pNHhNVE11TVRneU9qZ3dPUT09IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAwMDIKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwSElYbENkMUJYU0ROV1lXOUFNVGcxTGpFM01pNHhNVE11TVRneU9qZ3hNUT09IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAwMDMKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwSElYbENkMUJYU0ROV1lXOUFNVGcxTGpFM01pNHhNVE11TVRneU9qZ3hNQT09IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAwMDQKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwSElYbENkMUJYU0ROV1lXOUFNVGcxTGpFM01pNHhNVE11TVRneU9qZ3dOQT09IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAwMDUKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwSElYbENkMUJYU0ROV1lXOUFNVGcxTGpFM01pNHhNVE11TVRneU9qZ3dOZz09IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAwMDYKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwSElYbENkMUJYU0ROV1lXOUFNVGcxTGpFM01pNHhNVE11TVRneU9qZ3hNZz09IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAwNTkKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwak1HWm1NbVk1TUMwNVpqZ3pMVFExTVdFdFlUZGtNeTB3T1RrME9EUTFaRGt5TURoQWFuQXVaRzkxYzJocGJXVnVaeTVqYjIwNk1qRTROVE09IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAxMzEKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwV1ZqVjJORWRxVFdSTGMwNTBPR293WW1aVVZ6WjVRRFV4TGpFMU9TNHhNRFl1TVRVM09qWTVNVGM9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMDEKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVFE1TGpJd01pNDRNaTR4TnpJNk16TTRPUT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMDMKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2UzJsNFRIWkxlbmRxWld0SE1EQnliVUF4TkRrdU1qQXlMamd5TGpFM01qbzRNREF3IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMDQKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Wm1GQ1FXOUVOVFJyT0RkVlNrYzNRREUwT1M0eU1ESXVPREl1TVRjeU9qSXpOelk9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMDUKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VkVWNmFtWkJXWEV5U1dwMGRXOVRRRFUwTGpNMkxqRTNOQzR4T0RFNk5qWTVOdz09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMDYKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VW1WNGJrSm5WVGRGVmpWQlJIaEhRREUwTlM0eU16a3VNUzR4TURBNk56QXdNUT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMDcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WnpWTlpVUTJSblF6UTFkc1NrbGtRREUwT1M0eU1ESXVPREl1TVRjeU9qVXdNRE09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMDgKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2UzJsNFRIWkxlbmRxWld0SE1EQnliVUF4TkRrdU1qQXlMamd5TGpFM01qbzFOVEF3IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMDkKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Wm1GQ1FXOUVOVFJyT0RkVlNrYzNRRFUwTGpNMkxqRTNOQzR4T0RFNk1qTTNOZz09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMTAKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V0V0R1Myd3ljbFZNYWtsd056UkFNVFE1TGpJd01pNDRNaTR4TnpJNk9EQXdPQT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMTEKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V0V0R1Myd3ljbFZNYWtsd056UkFOVFF1TXpZdU1UYzBMakU0TVRvNE1EQTQjJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDAxMgpzczovL1lXVnpMVEkxTmkxblkyMDZjRXRGVnpoS1VFSjVWRlpVVEhSTlFERTBPUzR5TURJdU9ESXVNVGN5T2pRME13PT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDAxNApzczovL1lXVnpMVEkxTmkxblkyMDZTMmw0VEhaTGVuZHFaV3RITURCeWJVQTFOQzR6Tmk0eE56UXVNVGd4T2pVMU1EQT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDAxNQpzczovL1lXVnpMVEkxTmkxblkyMDZVRU51YmtnMlUxRlRibVp2VXpJM1FEVTBMak0yTGpFM05DNHhPREU2T0RBNU1RPT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDAxNgpzczovL1lXVnpMVEkxTmkxblkyMDZaVFJHUTFkeVozQnJhbWt6VVZsQU5UUXVNell1TVRjMExqRTRNVG81TVRBeSMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDE3CnNzOi8vWVdWekxUSTFOaTFuWTIwNlZFVjZhbVpCV1hFeVNXcDBkVzlUUURVMExqTTJMakUzTkM0eE9ERTZOalkzT1E9PSMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDE4CnNzOi8vWVdWekxUSTFOaTFuWTIwNlJtOVBhVWRzYTBGQk9YbFFSVWRRUURVMExqTTJMakUzTkM0eE9ERTZOek13Tnc9PSMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDE5CnNzOi8vWVdWekxUSTFOaTFuWTIwNldUWlNPWEJCZEhaNGVIcHRSME5BTlRRdU16WXVNVGMwTGpFNE1UbzFNREF4IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjAKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2ZWtST1ZtVmtVa1pRVVdWNFJ6bDJRREUwTlM0eU16a3VNUzR4TURBNk5qTTNPUT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjEKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2UzJsNFRIWkxlbmRxWld0SE1EQnliVUF4TkRrdU1qQXlMamd5TGpFM01qbzRNRGd3IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2UzJsNFRIWkxlbmRxWld0SE1EQnliVUF4TkRVdU1qTTVMakV1TVRBd09qZ3dPREE9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjMKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVFE1TGpJd01pNDRNaTR4TnpJNk5UWXdNQT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjQKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVFE1TGpJd01pNDRNaTR4TnpJNk5UWXdNUT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjUKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WTJSQ1NVUldOREpFUTNkdVprbE9RREUwT1M0eU1ESXVPREl1TVRjeU9qZ3hNVGc9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjYKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VkVWNmFtWkJXWEV5U1dwMGRXOVRRREUwT1M0eU1ESXVPREl1TVRjeU9qWTJPVGM9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Um05UGFVZHNhMEZCT1hsUVJVZFFRREUwT1M0eU1ESXVPREl1TVRjeU9qY3pNRFk9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjgKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WlRSR1ExZHlaM0JyYW1relVWbEFNVFE1TGpJd01pNDRNaTR4TnpJNk9URXdNUT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMjkKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVFE1TGpJd01pNDRNaTR4TnpJNk5UQXdNUT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMzEKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VkVWNmFtWkJXWEV5U1dwMGRXOVRRREUwT1M0eU1ESXVPREl1TVRjeU9qWTJOems9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMzYKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVFE1TGpJd01pNDRNaTR4TnpJNk9EZzRPQT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMzcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VW1WNGJrSm5WVGRGVmpWQlJIaEhRREUwT1M0eU1ESXVPREl1TVRjeU9qY3dNREk9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwMzkKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WTJSQ1NVUldOREpFUTNkdVprbE9RREUwT1M0eU1ESXVPREl1TVRjeU9qZ3hNVGs9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDAKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WnpWTlpVUTJSblF6UTFkc1NrbGtRREUwT1M0eU1ESXVPREl1TVRjeU9qVXdNRFE9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDEKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2YTBSWGRsaFpXbTlVUW1OSGEwTTBRREUwT1M0eU1ESXVPREl1TVRjeU9qZzRPREk9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VUVOdWJrZzJVMUZUYm1adlV6STNRREUwT1M0eU1ESXVPREl1TVRjeU9qZ3dPVEU9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDMKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V0V0R1Myd3ljbFZNYWtsd056UkFNVFE1TGpJd01pNDRNaTR4TnpJNk9EQXdPUT09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDQKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VW1WNGJrSm5WVGRGVmpWQlJIaEhRREUwT1M0eU1ESXVPREl1TVRjeU9qY3dNREU9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDUKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2ZWtST1ZtVmtVa1pRVVdWNFJ6bDJRREUwT1M0eU1ESXVPREl1TVRjeU9qWXpOems9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDYKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WlRSR1ExZHlaM0JyYW1relVWbEFNVFE1TGpJd01pNDRNaTR4TnpJNk9URXdNZz09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Um05UGFVZHNhMEZCT1hsUVJVZFFRREUwTlM0eU16a3VNUzR4TURBNk56TXdOdz09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNDgKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVFExTGpJek9TNHhMakV3TURvMU1EQXcjJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDA0OQpzczovL1lXVnpMVEkxTmkxblkyMDZSbTlQYVVkc2EwRkJPWGxRUlVkUVFERTBPUzR5TURJdU9ESXVNVGN5T2pjek1EYz0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDA1MApzczovL1lXVnpMVEkxTmkxblkyMDZhMFJYZGxoWldtOVVRbU5IYTBNMFFERTBPUzR5TURJdU9ESXVNVGN5T2pnNE9ERT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDA1MQpzczovL1lXVnpMVEkxTmkxblkyMDZjRXRGVnpoS1VFSjVWRlpVVEhSTlFERTBPUzR5TURJdU9ESXVNVGN5T2pRME5EUT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDA1MgpzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU1UUTVMakl3TWk0NE1pNHhOekk2TlRBd01BPT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDA1MwpzczovL1lXVnpMVEkxTmkxblkyMDZVRU51YmtnMlUxRlRibVp2VXpJM1FERTBOUzR5TXprdU1TNHhNREE2T0RBNU1RPT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDA1OApzczovL1lXVnpMVEkxTmkxblkyMDZaVFJHUTFkeVozQnJhbWt6VVZsQU1UUTFMakl6T1M0eExqRXdNRG81TVRBeCMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDU5CnNzOi8vWVdWekxUSTFOaTFuWTIwNlptRkNRVzlFTlRSck9EZFZTa2MzUURFME9TNHlNREl1T0RJdU1UY3lPakl6TnpVPSMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDYwCnNzOi8vWVdWekxUSTFOaTFuWTIwNmNFdEZWemhLVUVKNVZGWlVUSFJOUURFME5TNHlNemt1Tmk0eU1ESTZORFEwTkE9PSMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDYxCnNzOi8vWVdWekxUSTFOaTFuWTIwNldFdEdTMnd5Y2xWTWFrbHdOelJBTVRRMUxqSXpPUzR4TGpFd01EbzRNREE1IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNjMKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVFE1TGpJd01pNDRNaTR4TnpJNk16TXdOZz09IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNjQKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2UzJsNFRIWkxlbmRxWld0SE1EQnliVUF4TkRVdU1qTTVMakV1TVRBd09qVTFNREE9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNjUKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2YkdOWVUxZzRhbHBvTWtBMU1TNDJPQzR5TVRRdU1qSTJPalF5TVRJNCMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDc0CnNzOi8vWVdWekxUSTFOaTFuWTIwNmJHTllVMWc0YWxwb01rQjFheTVtY21WbGMyaGhaRzkzYzI5amF5NWpiMjA2TkRJeE1qZz0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDA3NQpzczovL1lXVnpMVEkxTmkxblkyMDZVRU51YmtnMlUxRlRibVp2VXpJM1FERTBPUzR5TURJdU9ESXVNVGN5T2pnd09UQT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDA3NgpzczovL1lXVnpMVEkxTmkxblkyMDZOME5KVWtac1dYQldXa0ExTVM0M055NHlNekF1TWpjNk16WTVOamc9IyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAwNzcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2TmtZMVNWbFVlRmhLWkVBMU1TNDJPQzR4TnpJdU5Eb3lPVFl4TWc9PSMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDc4CnNzOi8vWVdWekxUSTFOaTFuWTIwNlVFTnVia2cyVTFGVGJtWnZVekkzUURVeExqYzNMalV6TGpJd01EbzRNRGt4IyVFNiVCMyVBMiVFNSU4NSVCMF8xMjEzMjAwMDEKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Wm1GQ1FXOUVOVFJyT0RkVlNrYzNRRFV4TGpjM0xqVXpMakl3TURveU16YzEjJUU2JUIzJUEyJUU1JTg1JUIwXzEyMTMyMDAwMgpzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU5URXVOemN1TlRNdU1qQXdPalV3TURFPSMlRTYlQjMlQTIlRTUlODUlQjBfMTIxMzIwMDAzCnNzOi8vWVdWekxUSTFOaTFuWTIwNmNFdEZWemhLVUVKNVZGWlVUSFJOUURVeExqYzNMalV6TGpJd01EbzBORFEwIyVFNiVCMyVBMiVFNSU4NSVCMF8xMjEzMjAwMDQKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VW1WNGJrSm5WVGRGVmpWQlJIaEhRRFV4TGpjM0xqVXpMakl3TURvM01EQXgjJUU2JUIzJUEyJUU1JTg1JUIwXzEyMTMyMDAwNQpzczovL1lXVnpMVEkxTmkxblkyMDZSbTlQYVVkc2EwRkJPWGxRUlVkUVFEVXhMamMzTGpVekxqSXdNRG8zTXpBMyMlRTYlQjMlQTIlRTUlODUlQjBfMTIxMzIwMDA2CnNzOi8vWVdWekxUSTFOaTFuWTIwNlJtOVBhVWRzYTBGQk9YbFFSVWRRUURVeExqYzNMalV6TGpJd01EbzNNekEyIyVFNiVCMyVBMiVFNSU4NSVCMF8xMjEzMjAwMDcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WTJSQ1NVUldOREpFUTNkdVprbE9RRFV4TGpjM0xqVXpMakl3TURvNE1URTUjJUU2JUIzJUEyJUU1JTg1JUIwXzEyMTMyMDAwOApzczovL1lXVnpMVEkxTmkxblkyMDZZMlJDU1VSV05ESkVRM2R1WmtsT1FEVXhMamMzTGpVekxqSXdNRG80TVRFNCMlRTYlQjMlQTIlRTUlODUlQjBfMTIxMzIwMDA5CnNzOi8vWVdWekxUSTFOaTFuWTIwNldFdEdTMnd5Y2xWTWFrbHdOelJBTlRFdU56Y3VOVE11TWpBd09qZ3dNRGs9IyVFNiVCMyVBMiVFNSU4NSVCMF8xMjEzMjAwMTAKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2UzJsNFRIWkxlbmRxWld0SE1EQnliVUExTVM0M055NDFNeTR5TURBNk9EQXdNQT09IyVFNiVCMyVBMiVFNSU4NSVCMF8xMjEzMjAwMTEKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2UzJsNFRIWkxlbmRxWld0SE1EQnliVUExTVM0M055NDFNeTR5TURBNk5UVXdNQT09IyVFNiVCMyVBMiVFNSU4NSVCMF8xMjEzMjAwMTIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WnpWTlpVUTJSblF6UTFkc1NrbGtRRFV4TGpjM0xqVXpMakl3TURvMU1EQTAjJUU2JUIzJUEyJUU1JTg1JUIwXzEyMTMyMDAxMwpzczovL1lXVnpMVEkxTmkxblkyMDZXRXRHUzJ3eWNsVk1ha2x3TnpSQU5URXVOemN1TlRNdU1qQXdPamd3TURnPSMlRTYlQjMlQTIlRTUlODUlQjBfMTIxMzIwMDE0CnNzOi8vWVdWekxUSTFOaTFuWTIwNlpUUkdRMWR5WjNCcmFta3pVVmxBTlRFdU56Y3VOVE11TWpBd09qa3hNREU9IyVFNiVCMyVBMiVFNSU4NSVCMF8xMjEzMjAwMTUKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2YTBSWGRsaFpXbTlVUW1OSGEwTTBRRFV4TGpjM0xqVXpMakl3TURvNE9EZ3gjJUU2JUIzJUEyJUU1JTg1JUIwXzEyMTMyMDAxNgpzczovL1lXVnpMVEkxTmkxblkyMDZWRVY2YW1aQldYRXlTV3AwZFc5VFFEVXhMamMzTGpVekxqSXdNRG8yTmprMyMlRTYlQjMlQTIlRTUlODUlQjBfMTIxMzIwMDE3CnNzOi8vWVdWekxUSTFOaTFuWTIwNldUWlNPWEJCZEhaNGVIcHRSME5BTlRFdU56Y3VOVE11TWpBd09qVXdNREE9IyVFNiVCMyVBMiVFNSU4NSVCMF8xMjEzMjAwMTgKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VUVOdWJrZzJVMUZUYm1adlV6STNRRFV4TGpjM0xqVXpMakl3TURvNE1Ea3cjJUU2JUIzJUEyJUU1JTg1JUIwXzEyMTMyMDAxOQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBHYTBKeVVtWmlUREo0V0hrNFEzRjVlV1IyY1VwWlFETXhMalF3TGpJeE5pNHlNRFE2TXpZeE5EQT0jJUU3JUFCJThCJUU5JTk5JUI2JUU1JUFFJTlCXzEyMTMyMDAwOQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBZZDFkV1VtMVBNbXRMZFRaeFN6RlliR2xvTTB4bVpUWk1hRE5TVW1FNWNrQXlNVE11TVRnekxqUTBMakUzT2pnek9EZz0jJUU3JUFCJThCJUU5JTk5JUI2JUU1JUFFJTlCXzEyMTMyMDAxMApzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBZZDFkV1VtMVBNbXRMZFRaeFN6RlliR2xvTTB4bVpUWk1hRE5TVW1FNWNrQTBNek00YW05cGJpNXZkWFJzYVc1bExYWndiaTVqYkc5MVpEbzRNemc0IyVFNyVBQiU4QiVFOSU5OSVCNiVFNSVBRSU5Ql8xMjEzMjAwMTEKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRvMWF6VTFZVWxWYWtwaFlWRTRXV3BGTmpjM01uZEdRRFV5TGpJekxqRTNOaTQ1Tnpvek5EVXhNUT09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAwMDcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VGpCck5uUlRWMkpzU1VBeE1qa3VNVFEyTGpFd01pNHlNam96TkRBeE53PT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDAxNgpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBsZW1WelFsaGxjMll6VWt0Q1EzQXhkbkZMZFVsNFFHSmxaV052Ym1ZdWVIbDZPamd3T0RBPSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMDIxCnNzOi8vWVdWekxUSTFOaTFuWTIwNk16Rk1aRmxvVURoQlpVQTBOUzQxT0M0ek9TNHhNem8xT0RReU9BPT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDAyMgpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBVTVhCaU4xaDRlSEp2YkhaUVUySXdkVEo0VTA5QlFHSmxZV052YldZdWVIbDZPamd3T0RBPSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMDI1CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcHhSMnB0U1RoWFVXeEdNSFJtYUVSaWEweHhSMlJPUUhCaGMzTmpiMjVtTG5oNWVqbzRNRGd3IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAwMjYKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WlRSR1ExZHlaM0JyYW1relVWbEFNVFkzTGpnNExqWXhMakUzTlRvNU1UQXkjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDAzMApzczovL1lXVnpMVEkxTmkxblkyMDZTMmw0VEhaTGVuZHFaV3RITURCeWJVQXhOamN1T0RndU5qRXVNVGMxT2pVMU1EQT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDAzMQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBZYkZWR1oyOVBjVVJzVm5Gc1drWkVNMHB6TUZsQlFHMWhjM1JwYm1jdWVIbDZPamd3T0RBPSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMDQwCnNzOi8vWVdWekxUSTFOaTFuWTIwNlEwOURRVEp4ZFVwTVowQTRPUzR4T0RVdU16RXVNVEEzT2pJNU5USTAjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDA0MQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBxUmtSd1ZXOUxWVVJhVUVWSFZFSktVbWxNV21kdlFERTJNaTR5TkRjdU1UVXpMakV3T0RveU9EZzVOZz09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAwNDIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2ZDNkeE5saHZOV2RLT0VBek9DNDFOQzR4TURRdU1UZzBPakU0T0RBNCMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMDQzCnNzOi8vWVdWekxUSTFOaTFuWTIwNlZVVmFURXRxTWpaMGVFQXpPQzQxTkM0eE1EUXVNVGM2TVRnNE1EZz0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDA0NApzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHA1VkhwRlpVbHRSRVJMYjI5VWFIVlJTMmhhYW05aVFEUTFMakUxTUM0Mk5TNHpORG94TVRJNE5RPT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDA0NQpzczovL1lXVnpMVEkxTmkxblkyMDZXRXRHUzJ3eWNsVk1ha2x3TnpSQU1UWTNMamc0TGpZeExqRTNOVG80TURBNCMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMDQ2CnNzOi8vWVdWekxUSTFOaTFuWTIwNlZFVjZhbVpCV1hFeVNXcDBkVzlUUURFMk55NDRPQzQyTVM0eE56VTZOalkzT1E9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMDQ3CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcGlUbFZsTUdwU09YSjZjM1pNUlhwbVVHMUpORTltUURrMExqRXpNUzR4TVRVdU1USTVPak00TVRBNCMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMDQ4CnNzOi8vWVdWekxUSTFOaTFuWTIwNldUWlNPWEJCZEhaNGVIcHRSME5BTVRZM0xqZzRMall4TGpFM05Ub3pNekEyIyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAwNDkKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwQ01ISjVOVFpZTWtGNFprWm5ZMmRKTjNOSVJGZEVRRGswTGpFek1TNHhNaTQxT0RveU5qWTJPUT09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAwOTQKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRvNVFuWnJkelZoZFhCT2VUaEFNakExTGpFek5DNHhPREF1TVRRM09qUTBNdz09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAwOTkKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Um05UGFVZHNhMEZCT1hsUVJVZFFRRE00TGpZNExqRXpOUzR5TXprNk56TXdOdz09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAxMDAKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNemd1TnpVdU1UTTNMamN4T2pVMk1ERT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDEwMwpzczovL1lXVnpMVEkxTmkxblkyMDZabUZDUVc5RU5UUnJPRGRWU2tjM1FETTRMamMxTGpFek55NDNNVG95TXpjMiMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTA0CnNzOi8vWVdWekxUSTFOaTFuWTIwNlVFTnVia2cyVTFGVGJtWnZVekkzUURNNExqYzFMakV6Tnk0M01UbzRNRGt4IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAxMDUKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Um05UGFVZHNhMEZCT1hsUVJVZFFRRE00TGpjMUxqRXpOeTQzTVRvM016QTIjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDEwNgpzczovL1lXVnpMVEkxTmkxblkyMDZTMmw0VEhaTGVuZHFaV3RITURCeWJVQXpPQzQzTlM0eE16Y3VOekU2T0RBNE1BPT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDEwNwpzczovL1lXVnpMVEkxTmkxblkyMDZWRVY2YW1aQldYRXlTV3AwZFc5VFFETTRMamMxTGpFek55NDNNVG8yTmpjNSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTA4CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UbzJhbXhoUjFKd1oySTNXR05vTWtsdVEzTkpaVzFGUURFM01pNHlNekl1TWpBNExqZ3dPamd3T0RBPSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTE3MApzczovL1lXVnpMVEkxTmkxblkyMDZabUZDUVc5RU5UUnJPRGRWU2tjM1FETTRMakV5TVM0ME15NDFNVG95TXpjMiMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTI5CnNzOi8vWVdWekxUSTFOaTFuWTIwNlptRkNRVzlFTlRSck9EZFZTa2MzUURNNExqWTRMakV6TlM0eU16azZNak0zTlE9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTMwCnNzOi8vWVdWekxUSTFOaTFuWTIwNlkyUkNTVVJXTkRKRVEzZHVaa2xPUURJekxqRXpOQzQ1TkM0eE56VTZPREV4T1E9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTMxCnNzOi8vWVdWekxUSTFOaTFuWTIwNlp6Vk5aVVEyUm5RelExZHNTa2xrUURFMk55NDRPQzQyTVM0eE56VTZOVEF3TkE9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTMyCnNzOi8vWVdWekxUSTFOaTFuWTIwNlVFTnVia2cyVTFGVGJtWnZVekkzUURFMk55NDRPQzQyTVM0eE56VTZPREE1TUE9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTMzCnNzOi8vWVdWekxUSTFOaTFuWTIwNlJtOVBhVWRzYTBGQk9YbFFSVWRRUURFMk55NDRPQzQyTVM0eE56VTZOek13Tnc9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMTM0CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UbzJZMlZ5U21sd2JsYzNhbmgxUzB0VFdWZFdUbEkwUURNdU9URXVNVGd4TGpFeU9Ub3lNREF4TlE9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzQ5CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcFlka3N3YkhSSU5qZFlhSFk1YUhRNVVtaFpjMFo1UUcxaGMzUnBibWN1ZUhsNk9qZ3dPREE9IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNTQKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwTlRVcFZkV0V3ZUhkUmJUUkxRVFJvZDJoblRsTkVRRE11T0RrdU1USXdMakU1TXpveE1UVTBOUT09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNTUKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Um05UGFVZHNhMEZCT1hsUVJVZFFRRE00TGpreExqRXdNUzR5TWpFNk56TXdOdz09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNTYKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Um05UGFVZHNhMEZCT1hsUVJVZFFRRE00TGpreExqRXdNUzR5TWpFNk56TXdOZz09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNTcKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WnpWTlpVUTJSblF6UTFkc1NrbGtRRE00TGpreExqRXdNUzR5TWpFNk5UQXdOQT09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNTgKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNemd1TmpndU1UTTBMalk1T2pNek9Eaz0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM2MApzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU16Z3VOamd1TVRNMExqWTVPak16TURZPSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzYxCnNzOi8vWVdWekxUSTFOaTFuWTIwNlZFVjZhbVpCV1hFeVNXcDBkVzlUUURJekxqRXpOQzQ1TkM0eE5ERTZOalk1Tnc9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzYyCnNzOi8vWVdWekxUSTFOaTFuWTIwNldUWlNPWEJCZEhaNGVIcHRSME5BTXpndU5qZ3VNVE0xTGpJek9Ub3pNekEyIyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNjMKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwVU1YQmlOMWg0ZUhKdmJIWlFVMkl3ZFRKNFUwOUJRREUzTWk0eU16SXVNVFEzTGpFM056bzRNRGd3IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNjQKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2Um05UGFVZHNhMEZCT1hsUVJVZFFRRE00TGpZNExqRXpOQzQyT1RvM016QTMjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM2NQpzczovL1lXVnpMVEkxTmkxblkyMDZjRXRGVnpoS1VFSjVWRlpVVEhSTlFETTRMakV5TVM0ME15NHhOREk2TkRRME5BPT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM2NgpzczovL1lXVnpMVEkxTmkxblkyMDZSbTlQYVVkc2EwRkJPWGxRUlVkUVFETTRMakV5TVM0ME15NHhOREk2TnpNd05nPT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM2NwpzczovL1lXVnpMVEkxTmkxblkyMDZhVlZDTURreU0xSkNRVUF4TlRRdU15NDRMakUxTVRvek1EQTJOdz09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNjgKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WlRSR1ExZHlaM0JyYW1relVWbEFNemd1TVRJeExqUXpMakUwTWpvNU1UQXgjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM2OQpzczovL1lXVnpMVEkxTmkxblkyMDZabUZDUVc5RU5UUnJPRGRWU2tjM1FETTRMamMxTGpFek55NDNNVG95TXpjMSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzcwCnNzOi8vWVdWekxUSTFOaTFuWTIwNlMybDRUSFpMZW5kcVpXdEhNREJ5YlVBek9DNDNOUzR4TXpjdU56RTZPREF3TUE9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzcxCnNzOi8vWVdWekxUSTFOaTFuWTIwNlp6Vk5aVVEyUm5RelExZHNTa2xrUURNNExqYzFMakV6Tnk0M01UbzFNREEwIyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNzIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VUVOdWJrZzJVMUZUYm1adlV6STNRRE00TGpjMUxqRXpOeTQzTVRvNE1Ea3cjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM3MwpzczovL1lXVnpMVEkxTmkxblkyMDZaelZOWlVRMlJuUXpRMWRzU2tsa1FETTRMamMxTGpFek55NDNNVG8xTURBeiMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzc0CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05Ub3lSVXgxU3pjd1JXbEpjM1I2ZVRkVmEwSjNTbEZsUURFM01pNHlNek11TkRjdU1UVXlPamd3IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzNzUKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNemd1TnpVdU1UTTNMamN4T2pNek9Eaz0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM3NwpzczovL1lXVnpMVEkxTmkxblkyMDZaelZOWlVRMlJuUXpRMWRzU2tsa1FETTRMamMxTGpFek55NDJOam8xTURBMCMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzc4CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcGxlbVZ6UWxobGMyWXpVa3RDUTNBeGRuRkxkVWw0UURFM01pNHlNek11TWpVekxqTXlPamd3T0RBPSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzc5CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcFRSVnAxV1Zoa1IxZHFRa1JaYlhoNVRrWm9OVlJJYUZwT1Z6VktUMVp3UkZWclJrcFJXRXBKVlZSYU5GSXhRbTVUVnpBMFVsaGtVVTFyYkZSVk0yZ3dZV3hHYWsxWVFqRmhlazV3WkZjeFRsZFlRak5OZHowOVFERTNNaTR5TlRJdU5Ua3VOamM2TkRJMU56ST0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM4MApzczovL1lXVnpMVEkxTmkxblkyMDZabUZDUVc5RU5UUnJPRGRWU2tjM1FETTRMamMxTGpFek55NDJOam95TXpjMiMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzgxCnNzOi8vWVdWekxUSTFOaTFuWTIwNlVFTnVia2cyVTFGVGJtWnZVekkzUURNNExqYzFMakV6Tnk0Mk5qbzRNRGt4IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzODIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2ZWtST1ZtVmtVa1pRVVdWNFJ6bDJRREUyTnk0NE9DNDJNUzR4TnpVNk5qTTNPUT09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzODQKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2YTBSWGRsaFpXbTlVUW1OSGEwTTBRREUyTnk0NE9DNDJNUzR4TnpVNk9EZzRNUT09IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAzODUKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRvMmFteGhSMUp3WjJJM1dHTm9Na2x1UTNOSlpXMUZRR0psWVdOdmJtWXVlSGw2T2pnd09EQT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM4NgpzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU1UWTNMamc0TGpZeExqRTNOVG80T0RnNCMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzg3CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcHhSMnB0U1RoWFVXeEdNSFJtYUVSaWEweHhSMlJPUURFM01pNHlNekl1TVRVeUxqRTBNam80TURndyMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzg4CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcHdlRkpGVVdwbmFsQkhhbE5MYjFoTVJXNTBObTU1ZW1oYVZXaHBOMU52TVVwc2MxTlRVbGRaVFdrMFRUUnBXRVJBT1RJdU16Z3VNVGN4TGpJeE5UbzFNVE0wT0E9PSMlRTclQkUlOEUlRTUlOUIlQkRfMTIxMzIwMzg5CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcGFNWGRDWjBOSlZqTXlPWEYwTnpkSlJuWkVSVWRGUUdKbFpXTnZibVl1ZUhsNk9qZ3dPREE9IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjA5NjQKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRvMlFrY3paMGN6Ykdad2JERXhUa1UwZVdaelNVTjRRSEJoYzNOamIyNW1Mbmg1ZWpvNE1EZ3cjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDk2NQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBhTVhkQ1owTkpWak15T1hGME56ZEpSblpFUlVkRlFERTNNaTR5TXpNdU1qVXpMak15T2pnd09EQT0jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDk4MQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVG8yUWtjelowY3piR1p3YkRFeFRrVTBlV1p6U1VONFFERTNNaTR5TXpJdU1UVXlMakUwTWpvNE1EZ3cjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDk4MgpzczovL1lXVnpMVEV5T0MxblkyMDZjMmhoWkc5M2MyOWphM05BTWpFeUxqRXdNaTQxTXk0eE9UUTZORFF6IyVFOCU4QiVCMSVFNSU5QiVCRF8xMjEzMjAwMDEKc3M6Ly9ZV1Z6TFRFeU9DMW5ZMjA2YzJoaFpHOTNjMjlqYTNOQU1qRXlMakV3TWk0MU15NHhPVGM2TkRReiMlRTglOEIlQjElRTUlOUIlQkRfMTIxMzIwMDAyCnNzOi8vWVdWekxURXlPQzFuWTIwNmMyaGhaRzkzYzI5amEzTkFNakV5TGpFd01pNDFNeTQzT1RvME5ETT0jJUU4JThCJUIxJUU1JTlCJUJEXzEyMTMyMDAwMwpzczovL1lXVnpMVEV5T0MxblkyMDZjMmhoWkc5M2MyOWphM05BTWpFeUxqRXdNaTQxTXk0eE9UZzZORFF6IyVFOCU4QiVCMSVFNSU5QiVCRF8xMjEzMjAwMDQKc3M6Ly9ZV1Z6TFRFeU9DMW5ZMjA2YzJoaFpHOTNjMjlqYTNOQU1qRXlMakV3TWk0MU15NHhPVFU2TkRReiMlRTglOEIlQjElRTUlOUIlQkRfMTIxMzIwMDA2CnNzOi8vWVdWekxURXlPQzFuWTIwNmMyaGhaRzkzYzI5amEzTkFNakV5TGpFd01pNDFNeTQzT0RvME5ETT0jJUU4JThCJUIxJUU1JTlCJUJEXzEyMTMyMDAwOQpzczovL1lXVnpMVEV5T0MxblkyMDZjMmhoWkc5M2MyOWphM05BTWpFeUxqRXdNaTQxTXk0NE1UbzBORE09IyVFOCU4QiVCMSVFNSU5QiVCRF8xMjEzMjAwMTAKc3M6Ly9ZV1Z6TFRFeU9DMW5ZMjA2YzJoaFpHOTNjMjlqYTNOQU1qRXlMakV3TWk0MU15NHhPVE02TkRReiMlRTglOEIlQjElRTUlOUIlQkRfMTIxMzIwMDExCnNzOi8vWVdWekxURXlPQzFuWTIwNmMyaGhaRzkzYzI5amEzTkFNakV5TGpFd01pNDFNeTR4T1RZNk5EUXojJUU4JThCJUIxJUU1JTlCJUJEXzEyMTMyMDAxMgpzczovL1lXVnpMVEkxTmkxblkyMDZTMmw0VEhaTGVuZHFaV3RITURCeWJVQTFNUzQyT0M0eU1EWXVNakk1T2pnd09EQT0jJUU4JThCJUIxJUU1JTlCJUJEXzEyMTMyMDAxMwpzczovL1lXVnpMVEV5T0MxblkyMDZjMmhoWkc5M2MyOWphM05BTWpFeUxqRXdNaTQxTXk0NE1EbzBORE09IyVFOCU4QiVCMSVFNSU5QiVCRF8xMjEzMjAwMTQKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WTJSQ1NVUldOREpFUTNkdVprbE9RRFV4TGpZNExqSXdOaTR5TWprNk9ERXhPQT09IyVFOCU4QiVCMSVFNSU5QiVCRF8xMjEzMjAwMjQKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwUllWaEpObVJGVTNoQlJFbFBlVUZCUlVwUlQyeFRRRFV4TGpFek1pNHhPUzQzTVRveE56QTRPUT09IyVFOCU4QiVCMSVFNSU5QiVCRF8xMjEzMjAwMjUKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwUGFsZzRVMEozUVhkWVRFdzBiMjVSZHpCQ2RESnpRRFEyTGpJMU1DNHlNemN1T1RFNk5EUXojJUU4JThCJUIxJUU1JTlCJUJEXzEyMTMyMDAzNQpzczovL1lXVnpMVEkxTmkxblkyMDZTMmw0VEhaTGVuZHFaV3RITURCeWJVQXhOekl1T1RrdU1UZzRMams1T2pVMU1EQT0jJUU4JThEJUI3JUU1JTg1JUIwXzEyMTMyMDAwNwpzczovL1lXVnpMVEkxTmkxblkyMDZla1JPVm1Wa1VrWlFVV1Y0UnpsMlFERTNNaTQ1T1M0eE9EZ3VPVGs2TmpNM09RPT0jJUU4JThEJUI3JUU1JTg1JUIwXzEyMTMyMDAwOApzczovL1lXVnpMVEkxTmkxblkyMDZaelZOWlVRMlJuUXpRMWRzU2tsa1FERTNNaTQ1T1M0eE9EZ3VPVGs2TlRBd05BPT0jJUU4JThEJUI3JUU1JTg1JUIwXzEyMTMyMDAwOQpzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU1UY3lMams1TGpFNE9DNDVPVG8xTURBdyMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDEwCnNzOi8vWVdWekxUSTFOaTFuWTIwNmEwUlhkbGhaV205VVFtTkhhME0wUURFM01pNDVPUzR4T0RndU9UazZPRGc0TWc9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDExCnNzOi8vWVdWekxUSTFOaTFuWTIwNldUWlNPWEJCZEhaNGVIcHRSME5BTVRjeUxqazVMakU0T0M0NU9UbzRPRGc0IyVFOCU4RCVCNyVFNSU4NSVCMF8xMjEzMjAwMTIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2WnpWTlpVUTJSblF6UTFkc1NrbGtRREUzTWk0NU9TNHhPRGd1T1RrNk5UQXdNdz09IyVFOCU4RCVCNyVFNSU4NSVCMF8xMjEzMjAwMTMKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVGN5TGprNUxqRTRPQzQ1T1RvMU1EQXgjJUU4JThEJUI3JUU1JTg1JUIwXzEyMTMyMDAxNApzczovL1lXVnpMVEkxTmkxblkyMDZabUZDUVc5RU5UUnJPRGRWU2tjM1FERTNNaTQ1T1M0eE9EZ3VPVGs2TWpNM05RPT0jJUU4JThEJUI3JUU1JTg1JUIwXzEyMTMyMDAxNQpzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU1UY3lMams1TGpFNE9DNDVPVG8xTmpBeCMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDE2CnNzOi8vWVdWekxUSTFOaTFuWTIwNlkyUkNTVVJXTkRKRVEzZHVaa2xPUURFM01pNDVPUzR4T0RndU9UazZPREV4T1E9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDE3CnNzOi8vWVdWekxUSTFOaTFuWTIwNlJtOVBhVWRzYTBGQk9YbFFSVWRRUURFM01pNDVPUzR4T0RndU9UazZOek13Tnc9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDE4CnNzOi8vWVdWekxUSTFOaTFuWTIwNlZFVjZhbVpCV1hFeVNXcDBkVzlUUURFM01pNDVPUzR4T0RndU9UazZOalkzT1E9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDE5CnNzOi8vWVdWekxUSTFOaTFuWTIwNlptRkNRVzlFTlRSck9EZFZTa2MzUURFM01pNDVPUzR4T0RndU9UazZNak0zTmc9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDIwCnNzOi8vWVdWekxUSTFOaTFuWTIwNmNFdEZWemhLVUVKNVZGWlVUSFJOUURFM01pNDVPUzR4T0RndU9UazZORFEwTkE9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDIxCnNzOi8vWVdWekxUSTFOaTFuWTIwNldUWlNPWEJCZEhaNGVIcHRSME5BTVRjeUxqazVMakU0T0M0NU9Ub3pNekEyIyVFOCU4RCVCNyVFNSU4NSVCMF8xMjEzMjAwMjIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2VW1WNGJrSm5WVGRGVmpWQlJIaEhRREUzTWk0NU9TNHhPRGd1T1RrNk56QXdNUT09IyVFOCU4RCVCNyVFNSU4NSVCMF8xMjEzMjAwMjMKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2V1RaU09YQkJkSFo0ZUhwdFIwTkFNVGN5TGprNUxqRTRPQzQ1T1Rvek16ZzUjJUU4JThEJUI3JUU1JTg1JUIwXzEyMTMyMDAyNApzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBET1VKcU9HNU1WRzVuY21GVmFuSjNhemd5UVhnM1FERTROUzR4TkRBdU1qQTVMamMwT2pJME1qSTAjJUU4JThEJUI3JUU1JTg1JUIwXzEyMTMyMDA0MQpzczovL1kyaGhZMmhoTWpBdGFXVjBaaTF3YjJ4NU1UTXdOVHBPYW1zeVRucGplVUExTGpFNE1TNHlNUzR4T1RvNE16ZzQjJUU4JThEJUI3JUU1JTg1JUIwXzEyMTMyMDA0MgpzczovL1lXVnpMVEkxTmkxblkyMDZXVFpTT1hCQmRIWjRlSHB0UjBOQU1UY3lMams1TGpFNE9DNDVPVG8xTmpBdyMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDQzCnNzOi8vWVdWekxUSTFOaTFuWTIwNmEwUlhkbGhaV205VVFtTkhhME0wUURFM01pNDVPUzR4T0RndU9UazZPRGc0TVE9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDQ0CnNzOi8vWVdWekxUSTFOaTFuWTIwNlVFTnVia2cyVTFGVGJtWnZVekkzUURFM01pNDVPUzR4T0RndU9UazZPREE1TVE9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDQ1CnNzOi8vWVdWekxUSTFOaTFuWTIwNlVtVjRia0puVlRkRlZqVkJSSGhIUURFM01pNDVPUzR4T0RndU9UazZOekF3TWc9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDQ2CnNzOi8vWVdWekxUSTFOaTFuWTIwNlkyUkNTVVJXTkRKRVEzZHVaa2xPUURFM01pNDVPUzR4T0RndU9UazZPREV4T0E9PSMlRTglOEQlQjclRTUlODUlQjBfMTIxMzIwMDQ3CnNzOi8vWTJoaFkyaGhNakF0YVdWMFppMXdiMng1TVRNd05UcEtaWFZXZEc1SFNEWXpUVXR4VDJWMVl6bEFNVEF6TGpFME15NHlNRGt1TVRNME9qVXhNelE0IyVFOCVCNiU4QSVFNSU4RCU5N18xMjEzMjAwMjQKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwak1HWm1NbVk1TUMwNVpqZ3pMVFExTVdFdFlUZGtNeTB3T1RrME9EUTFaRGt5TURoQVpHSXVaRzkxYzJocGJXVnVaeTVqYjIwNk1qTXlNREk9IyVFOSU5OCVCRiVFOCU4MSU5NCVFOSU4NSU4Ql8xMjEzMjAwMTIKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2TVRJek5EVTJOemhBTVRnekxqRXhNQzR4T1RRdU5EbzVPVGc0IyVFOSU5RiVBOSVFNSU5QiVCRF8xMjEzMjAwMDIKc3M6Ly9ZMmhoWTJoaE1qQXRhV1YwWmkxd2IyeDVNVE13TlRwak1HWm1NbVk1TUMwNVpqZ3pMVFExTVdFdFlUZGtNeTB3T1RrME9EUTFaRGt5TURoQWEzSXVaRzkxYzJocGJXVnVaeTVqYjIwNk1qSTVNRE09IyVFOSU5RiVBOSVFNSU5QiVCRF8xMjEzMjAwNjAKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2UjNobmQyZHpSWEZ5VFVBME55NHlOREl1TWpVMExqRTVPVG94TURZeU5RPT0jJUU5JUE2JTk5JUU2JUI4JUFGXzEyMTMyMDAwMgpzczovL1lXVnpMVEkxTmkxblkyMDZNMEk1ZGtaVVFsTnNjRUEwTnk0MU55NHlNekl1TVRFNU9qSXhNVGs9IyVFOSVBNiU5OSVFNiVCOCVBRl8xMjEzMjAwMDMKc3M6Ly9ZV1Z6TFRJMU5pMW5ZMjA2YW0xMFozTnRWelF3VWtBNExqSXhNQzR5TXpFdU1UUTJPakV4TkRZPSMlRTklQTYlOTklRTYlQjglQUZfMTIxMzIwMDA0CnNzOi8vWVdWekxUSTFOaTFuWTIwNmNsVjRPRzF4VlhOSk1FQTBOeTR5TkRNdU1UQTRMalF4T2pFd09EUXgjJUU5JUE2JTk5JUU2JUI4JUFGXzEyMTMyMDAxMA== 2 | -------------------------------------------------------------------------------- /sub/share/ssr: -------------------------------------------------------------------------------- 1 | c3NyOi8vTkRVdU5UVXVNaTR5TXpJNk1UUXlPVE02YjNKcFoybHVPbUZsY3kweU5UWXRZMlppT25Cc1lXbHVPazFxUlROTlIxazBMejl2WW1aemNHRnlZVzA5Sm5CeWIzUnZjR0Z5WVcwOUpuSmxiV0Z5YTNNOU5scHBlVFZoVTNnMWNGZEpXakpzTUdGSVZtbEpSazR4V1d0T2VWbFlaSE5hV0V4dWRtODNiRzAzTVdaTlZFbDRUWHBKZDAxNmF6UW1aM0p2ZFhBOQ== 2 | -------------------------------------------------------------------------------- /sub/share/tr: -------------------------------------------------------------------------------- 1 | dHJvamFuOi8vMDI3YzcxYWMtMDI2Yi00NzU1LTlhMzMtMjY1NThjZTZmNmEyQDE3Mi4xMDUuNS4xNTg6NDQzP2FsbG93SW5zZWN1cmU9MSZzbmk9ZGRyYWdvbi5sZWFndWVvZmxlZ2VuZHMuY29tIyVFOSU5OCVCMiVFNSVBNCVCMSVFNiU5NSU4OGdpdGh1YitTdWJDcmF3bGVyJUU1JThBJUEwJUU2JThCJUJGJUU1JUE0JUE3XzEyMTMyMDAwNQp0cm9qYW46Ly9iNWU0ZTM2MC01OTQ2LTQ3MGItYWFkMC1kYjk4ZjUwZmFhNTdAZnJvbnRlbmQueWlqaWFubGlhbi5hcHA6NTQ1OTA/YWxsb3dJbnNlY3VyZT0xJnNuaT0jJUU1JThBJUEwJUU2JThCJUJGJUU1JUE0JUE3XzEyMTMyMDAwNgp0cm9qYW46Ly81N2VkZmVjZi01Njk0LTRhMzQtODA3Mi01NGE0ZjA2MzZhNjJAZnJvbnRlbmQua3VhbmdiaWFveXVuLmNvbTo0MDAwMT9hbGxvd0luc2VjdXJlPTEmc25pPWZyb250ZW5kLmt1YW5nYmlhb3l1bi5jb20jJUU1JThBJUEwJUU2JThCJUJGJUU1JUE0JUE3XzEyMTMyMDAwNwp0cm9qYW46Ly81N2VkZmVjZi01Njk0LTRhMzQtODA3Mi01NGE0ZjA2MzZhNjJAZnJvbnRlbmQua3VhbmdiaWFveXVuLmNvbTo0MDAwNj9hbGxvd0luc2VjdXJlPTEmc25pPSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDA4CnRyb2phbjovLzU3ZWRmZWNmLTU2OTQtNGEzNC04MDcyLTU0YTRmMDYzNmE2MkBmcm9udGVuZC5rdWFuZ2JpYW95dW4uY29tOjQwMDA3P2FsbG93SW5zZWN1cmU9MSZzbmk9ZnJvbnRlbmQua3VhbmdiaWFveXVuLmNvbSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDA5CnRyb2phbjovLzU3ZWRmZWNmLTU2OTQtNGEzNC04MDcyLTU0YTRmMDYzNmE2MkBmcm9udGVuZC5rdWFuZ2JpYW95dW4uY29tOjQwMDA0P2FsbG93SW5zZWN1cmU9MSZzbmk9IyVFNSU4QSVBMCVFNiU4QiVCRiVFNSVBNCVBN18xMjEzMjAwMTEKdHJvamFuOi8vMDI3YzcxYWMtMDI2Yi00NzU1LTlhMzMtMjY1NThjZTZmNmEyQG1yYXJzaGFvcmRlbnNocGdhYW1lcmljYW5nMDBkLmFyc2hhcHJvcGx1cy5jZjo0NDM/YWxsb3dJbnNlY3VyZT0xJnNuaT1kZHJhZ29uLmxlYWd1ZW9mbGVnZW5kcy5jb20jJUU1JThBJUEwJUU2JThCJUJGJUU1JUE0JUE3XzEyMTMyMDAxOQp0cm9qYW46Ly8xZDI5NTM3YS0zZWMwLTQ3NzUtOTdlYy1jNTc3M2I2ZTQxMDNAZnJvbnRlbmQueWlqaWFubGlhbi5hcHA6NTQ1MzA/YWxsb3dJbnNlY3VyZT0xJnNuaT1mcm9udGVuZC55aWppYW5saWFuLmFwcCMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDIwCnRyb2phbjovLzg1YmEyMDliLTU0ZDEtNGFhZC04NzFlLTk4ZGY0ZWIyMjRiZkBmcm9udGVuZC55aWppYW5saWFuLmFwcDo1NDUzMD9hbGxvd0luc2VjdXJlPTEmc25pPWZyb250ZW5kLnlpamlhbmxpYW4uYXBwIyVFNSU4QSVBMCVFNiU4QiVCRiVFNSVBNCVBN18xMjEzMjAwMjEKdHJvamFuOi8vNTdlZGZlY2YtNTY5NC00YTM0LTgwNzItNTRhNGYwNjM2YTYyQGZyb250ZW5kLmt1YW5nYmlhb3l1bi5jb206NDAwMDU/YWxsb3dJbnNlY3VyZT0xJnNuaT1mcm9udGVuZC5rdWFuZ2JpYW95dW4uY29tIyVFNSU4QSVBMCVFNiU4QiVCRiVFNSVBNCVBN18xMjEzMjAwMjIKdHJvamFuOi8vY2Y4MmFjZmMtN2I5MC00NDVlLWFjNGEtNTZjZTBhNDgzMDVhQGZyb250ZW5kLnlpamlhbmxpYW4uYXBwOjU0NTMwP2FsbG93SW5zZWN1cmU9MSZzbmk9IyVFNSU4QSVBMCVFNiU4QiVCRiVFNSVBNCVBN18xMjEzMjAwMjQKdHJvamFuOi8vMTQ2OGVhZTQtZWIwMS00YjlmLWFlOGYtY2U1NWMzNzJkMWFmQGZyb250ZW5kLnlpamlhbmxpYW4uYXBwOjU0NTMwP2FsbG93SW5zZWN1cmU9MSZzbmk9IyVFNSU4QSVBMCVFNiU4QiVCRiVFNSVBNCVBN18xMjEzMjAwMjUKdHJvamFuOi8vYzc1ZGE2ZWMtMjE1MS00MTkxLWJjZGUtMTc3OGE1YzEyY2Y3QGZyb250ZW5kLnlpamlhbmxpYW4uYXBwOjU0NTcwP2FsbG93SW5zZWN1cmU9MSZzbmk9ZnJvbnRlbmQueWlqaWFubGlhbi5hcHAjJUU1JThBJUEwJUU2JThCJUJGJUU1JUE0JUE3XzEyMTMyMDAzNgp0cm9qYW46Ly9jNzVkYTZlYy0yMTUxLTQxOTEtYmNkZS0xNzc4YTVjMTJjZjdAZnJvbnRlbmQueWlqaWFubGlhbi5hcHA6NTQwMDA/YWxsb3dJbnNlY3VyZT0xJnNuaT1mcm9udGVuZC55aWppYW5saWFuLmFwcCMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDM3CnRyb2phbjovL2M3NWRhNmVjLTIxNTEtNDE5MS1iY2RlLTE3NzhhNWMxMmNmN0Bmcm9udGVuZC55aWppYW5saWFuLmFwcDo1NDQyMD9hbGxvd0luc2VjdXJlPTEmc25pPWZyb250ZW5kLnlpamlhbmxpYW4uYXBwIyVFNSU4QSVBMCVFNiU4QiVCRiVFNSVBNCVBN18xMjEzMjAwMzgKdHJvamFuOi8vYzc1ZGE2ZWMtMjE1MS00MTkxLWJjZGUtMTc3OGE1YzEyY2Y3QGZyb250ZW5kLnlpamlhbmxpYW4uYXBwOjU0NTMwP2FsbG93SW5zZWN1cmU9MSZzbmk9ZnJvbnRlbmQueWlqaWFubGlhbi5hcHAjJUU1JThBJUEwJUU2JThCJUJGJUU1JUE0JUE3XzEyMTMyMDAzOQp0cm9qYW46Ly9mNWEyNGY5OC01ODljLTQyYzQtYWE5Mi0zZTM3OTkzYWY3MDBAdDUuNTgzMTgxLnh5ejoxMjcyP2FsbG93SW5zZWN1cmU9MSZzbmk9d3d3LmJhaWR1LmNvbSMlRTUlOEElQTAlRTYlOEIlQkYlRTUlQTQlQTdfMTIxMzIwMDg4CnRyb2phbjovL3RlbGVncmFtLWlkLWRpcmVjdHZwbkAxOC4xOTcuMTkzLjE5NzoyMjIyMj9zZWN1cml0eT10bHMmc25pPXRyai5yb2xsaW5nbmV4dC5jby51ayMlRTUlQkUlQjclRTUlOUIlQkRfMTIxMzIwMDAyCnRyb2phbjovL3RlbGVncmFtLWlkLXByaXZhdGV2cG5zQDE4LjE5OS4xMS4yMzQ6MjIyMjI/YWxsb3dJbnNlY3VyZT0xJnNuaT10cmoucm9sbGluZ25leHQuY28udWsjJUU1JUJFJUI3JUU1JTlCJUJEXzEyMTMyMDA0Ngp0cm9qYW46Ly90ZWxlZ3JhbS1pZC1wcml2YXRldnBuc0AxOC4xOTkuMTEuMTg2OjIyMjIyP2FsbG93SW5zZWN1cmU9MSZzbmk9IyVFNSVCRSVCNyVFNSU5QiVCRF8xMjEzMjAwODcKdHJvamFuOi8vdGVsZWdyYW0taWQtcHJpdmF0ZXZwbnNAMTguMTUzLjIzNC40OjIyMjIyP2FsbG93SW5zZWN1cmU9MSZzbmk9dHJqLnJvbGxpbmduZXh0LmNvLnVrIyVFNSVCRSVCNyVFNSU5QiVCRF8xMjEzMjAxMTQKdHJvamFuOi8vUDFIYUxQUDloekAxODguMTY2LjIwOC42NDoxNjE4Mz9hbGxvd0luc2VjdXJlPTEmc25pPWFuZHJvaWQuZ29vZ2xlYXBpcy5jb20jJUU2JTk2JUIwJUU1JThBJUEwJUU1JTlEJUExXzEyMTMyMDAwNQp0cm9qYW46Ly9lYjJlMWNmMS1lZDAxLTQzOTItOWM5Zi1lYzBlYTM3YzcyMjFANDUuMzIuMTI0LjUyOjQ0Mz9hbGxvd0luc2VjdXJlPTEmc25pPWZhY2Vib29rLmNvbSMlRTYlOTYlQjAlRTUlOEElQTAlRTUlOUQlQTFfMTIxMzIwMDY3CnRyb2phbjovL2YyMDYyNDQ3LTUwY2MtNGRjNC1iZGZlLWI0NjA4MmFjY2ZiMEBkaXIwMS5uZXRvcmlnaW5zMnUuc2l0ZTozNjExNj9hbGxvd0luc2VjdXJlPTAmcGVlcj1qcDAxLmFicGlsb3QueHl6JnNuaT1qcDAxLmFicGlsb3QueHl6IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAwMTAKdHJvamFuOi8vZjIwNjI0NDctNTBjYy00ZGM0LWJkZmUtYjQ2MDgyYWNjZmIwQGRpcjAxLm5ldG9yaWdpbnMydS5zaXRlOjM2MjAxP2FsbG93SW5zZWN1cmU9MCZwZWVyPXNnMDEuYWJwaWxvdC54eXomc25pPXNnMDEuYWJwaWxvdC54eXojJUU2JTk3JUE1JUU2JTlDJUFDXzEyMTMyMDAxMQp0cm9qYW46Ly9mMjA2MjQ0Ny01MGNjLTRkYzQtYmRmZS1iNDYwODJhY2NmYjBAZGlyMDEubmV0b3JpZ2luczJ1LnNpdGU6MzY1MDE/YWxsb3dJbnNlY3VyZT0wJnBlZXI9dXMwMS5hYnBpbG90Lnh5eiZzbmk9dXMwMS5hYnBpbG90Lnh5eiMlRTYlOTclQTUlRTYlOUMlQUNfMTIxMzIwMDEyCnRyb2phbjovL2YyMDYyNDQ3LTUwY2MtNGRjNC1iZGZlLWI0NjA4MmFjY2ZiMEBkaXIwMS5uZXRvcmlnaW5zMnUuc2l0ZTozNjg2ND9hbGxvd0luc2VjdXJlPTAmcGVlcj1odTAxLmFicGlsb3QueHl6JnNuaT1odTAxLmFicGlsb3QueHl6IyVFNiU5NyVBNSVFNiU5QyVBQ18xMjEzMjAwMTMKdHJvamFuOi8vdGVsZWdyYW0taWQtZGlyZWN0dnBuQDUxLjIwLjEwMi44MjoyMjIyMj9zZWN1cml0eT10bHMmc25pPXRyai5yb2xsaW5nbmV4dC5jby51ayZ0eXBlPXRjcCZoZWFkZXJUeXBlPW5vbmUjJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDAzMwp0cm9qYW46Ly90ZWxlZ3JhbS1pZC1kaXJlY3R2cG5AMzUuMTgxLjIwMS4xNDA6MjIyMjI/YWxsb3dJbnNlY3VyZT0xJnNuaT10cmoucm9sbGluZ25leHQuY28udWsjJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDAzOAp0cm9qYW46Ly85ZWJkYmI0YS04YWU2LTQ1ZTgtOTE2OS0zM2ZlNjhmZGJhYWVAMTQxLjk0LjIyMS4xMjc6ODA/YWxsb3dJbnNlY3VyZT0xJnNuaT1mdHAuZGViaWFuLm9yZyMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDU2CnRyb2phbjovL3RlbGVncmFtLWlkLXByaXZhdGV2cG5zQDUxLjIxLjI0LjIxMToyMjIyMj9hbGxvd0luc2VjdXJlPTEmc25pPXRyai5yb2xsaW5nbmV4dC5jby51ayMlRTYlQjMlOTUlRTUlOUIlQkRfMTIxMzIwMDc5CnRyb2phbjovL3RlbGVncmFtLWlkLXByaXZhdGV2cG5zQDEzLjM3LjE1MC4xNTY6MjIyMjI/YWxsb3dJbnNlY3VyZT0xJnNuaT0jJUU2JUIzJTk1JUU1JTlCJUJEXzEyMTMyMDExMwp0cm9qYW46Ly90ZWxlZ3JhbS1pZC1wcml2YXRldnBuc0A1MS4yMS40MS42OjIyMjIyP2FsbG93SW5zZWN1cmU9MSZzbmk9dHJqLnJvbGxpbmduZXh0LmNvLnVrIyVFNiVCMyU5NSVFNSU5QiVCRF8xMjEzMjAxMTUKdHJvamFuOi8vZmQyZWYzZTYtNzViNy00NmNmLWJjNjAtZTg4OTk4NTFlZDU3QHdvcmxkYmVoaW5kbWllcHN5Y2hvLXBhc3NtYXJzaGEuc3Byb3RhcnNoYS50b3A6NDQzP2FsbG93SW5zZWN1cmU9MSZzbmk9ZnRwLmRlYmlhbi5vcmcjJUU2JUIzJUEyJUU1JTg1JUIwXzEyMTMyMDAyMAp0cm9qYW46Ly9mZDJlZjNlNi03NWI3LTQ2Y2YtYmM2MC1lODg5OTg1MWVkNTdANzAuMzQuMjUyLjIzMzo0NDM/YWxsb3dJbnNlY3VyZT0xJnNuaT1wcm94bW94LmNvbSMlRTYlQjMlQTIlRTUlODUlQjBfMTIxMzIwMDIxCnRyb2phbjovL3RlbGVncmFtLWlkLWRpcmVjdHZwbkA1NC4yNDcuMTczLjE5NToyMjIyMj9zZWN1cml0eT10bHMmc25pPXRyai5yb2xsaW5nbmV4dC5jby51ayZ0eXBlPXRjcCZoZWFkZXJUeXBlPW5vbmUjJUU3JTg4JUIxJUU1JUIwJTk0JUU1JTg1JUIwXzEyMTMyMDAwMQp0cm9qYW46Ly90ZWxlZ3JhbS1pZC1kaXJlY3R2cG5AMTMuNTMuMTUzLjExMDoyMjIyMj9hbGxvd0luc2VjdXJlPTEmc25pPXRyai5yb2xsaW5nbmV4dC5jby51ayMlRTclOTElOUUlRTUlODUlQjhfMTIxMzIwMDEyCnRyb2phbjovL3pJdlI3cnlPWHZAMTU5LjIyMy4yMDcuMTgyOjM0NDI4P2FsbG93SW5zZWN1cmU9MSZzbmk9IyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAwNjcKdHJvamFuOi8vdGVsZWdyYW0taWQtZGlyZWN0dnBuQDMuMTMzLjcyLjIxOToyMjIyMj9zZWN1cml0eT10bHMmc25pPXRyai5yb2xsaW5nbmV4dC5jby51ayZ0eXBlPXRjcCZoZWFkZXJUeXBlPW5vbmUjJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDA3NAp0cm9qYW46Ly9lNWY5Yzc1My1kNDAxLTQ4N2YtYTc3Yi0xMDA0YjdmMGY0MzlAdXMyLmx2d2Y4bi1oaDhlLTIzMDAtbm1vby1kMmU5bmFvYmVhY24uOWQ4ZjI2OWY5NmIyNTIzMi03NTljYmIzNmQ2NTQ4NTk3LmthdWZlbjo0NDM/YWxsb3dJbnNlY3VyZT0xJnNuaT0yMDYuMjM3LjUuMjIwIyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAxNDgKdHJvamFuOi8vcGpkbnF2QGF3cy11cy1kYWxsYXMtMS5mMXJvY2tldG5vZGUuY29tOjQ0Mz9hbGxvd0luc2VjdXJlPTEmc25pPWF3cy11cy1kYWxsYXMtMS5mMXJvY2tldG5vZGUuY29tIyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAxNTAKdHJvamFuOi8vcGpkbnF2QGF3cy11cy1ueWMtMS5mMXJvY2tldG5vZGUuY29tOjQ0Mz9hbGxvd0luc2VjdXJlPTEmc25pPWF3cy11cy1ueWMtMS5mMXJvY2tldG5vZGUuY29tIyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjAxNTIKdHJvamFuOi8vcGpkbnF2QDE1LjE4MS4xNjIuOTA6NDQzP2FsbG93SW5zZWN1cmU9MSZzbmk9YXdzLXVzLW55Yy0xLmYxcm9ja2V0bm9kZS5jb20jJUU3JUJFJThFJUU1JTlCJUJEXzEyMTMyMDM1OQp0cm9qYW46Ly85MjhkYzZlZS00OTViLTQ0NmYtOWYyMC04ODNkZWRjZTU2NGFAdXMyLmx2d2Y4bi1oaDhlLTIzMDAtbm1vby1kMmU5bmFvYmVhY24uOWQ4ZjI2OWY5NmIyNTIzMi03NTljYmIzNmQ2NTQ4NTk3LmthdWZlbjo0NDM/YWxsb3dJbnNlY3VyZT0xJnNuaT0yMDYuMjM3LjUuMjIwIyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjA4OTMKdHJvamFuOi8vdGVsZWdyYW0taWQtZGlyZWN0dnBuQDU0LjIwMy4xODguMTgyOjIyMjIyP2FsbG93SW5zZWN1cmU9MSZzbmk9dHJqLnJvbGxpbmduZXh0LmNvLnVrIyVFNyVCRSU4RSVFNSU5QiVCRF8xMjEzMjA5NjAKdHJvamFuOi8vdGVsZWdyYW0taWQtcHJpdmF0ZXZwbnNAMTguMTcxLjExOC4xODI6MjIyMjI/YWxsb3dJbnNlY3VyZT0xJnNuaT10cmoucm9sbGluZ25leHQuY28udWsjJUU4JThCJUIxJUU1JTlCJUJEXzEyMTMyMDAxOAp0cm9qYW46Ly85NzA3MGZjMC05ODFjLTExZWUtYmIwMy0xMjM5ZDAyNTUyNzJANTEuMzguNjUuMTU1OjQ0Mz9hbGxvd0luc2VjdXJlPTEmc25pPXd3dy50d2l0dGVyLmNvbSMlRTglOEIlQjElRTUlOUIlQkRfMTIxMzIwMDI2CnRyb2phbjovL3RlbGVncmFtLWlkLWRpcmVjdHZwbkA1Mi41Ni4xMjIuOTQ6MjIyMjI/YWxsb3dJbnNlY3VyZT0xJnNuaT10cmoucm9sbGluZ25leHQuY28udWsjJUU4JThCJUIxJUU1JTlCJUJEXzEyMTMyMDA0OAp0cm9qYW46Ly8wOTgzM2E2Zi00ZDQ2LTQyNmUtODdmZS03NzkzYTU0ODlmODRAZm9yZWlnbjA0LmxvdmVoanEueHl6OjQ2NTI3P2FsbG93SW5zZWN1cmU9MSZzbmk9bG92ZWhqcS54eXojJUU5JTlGJUE5JUU1JTlCJUJEXzEyMTMyMDAwNQp0cm9qYW46Ly8wOTgzM2E2Zi00ZDQ2LTQyNmUtODdmZS03NzkzYTU0ODlmODRAMTQ0LjI0Ljg3LjE4Njo0NjUyNz9hbGxvd0luc2VjdXJlPTEmc25pPWxvdmVoanEueHl6IyVFOSU5RiVBOSVFNSU5QiVCRF8xMjEzMjAwMDYKdHJvamFuOi8vMDk4MzNhNmYtNGQ0Ni00MjZlLTg3ZmUtNzc5M2E1NDg5Zjg0QGZvcmVpZ24wMS5sb3ZlaGpxLnh5ejo0NjUyMT9hbGxvd0luc2VjdXJlPTEmc25pPWxvdmVoanEueHl6IyVFOSU5RiVBOSVFNSU5QiVCRF8xMjEzMjAwMDcKdHJvamFuOi8vOTI4ZGM2ZWUtNDk1Yi00NDZmLTlmMjAtODgzZGVkY2U1NjRhQFVOTEsxLkxWV0Y4Ti1ISDhFLTIzMDAtTk1PTy1EMkU5TkFPQkVBQ04uOUQ4RjI2OUY5NkIyNTIzMi03NTlDQkIzNkQ2NTQ4NTk3LktBVUZFTjoyMDE1Mj9hbGxvd0luc2VjdXJlPTEmcGVlcj0xMy0yMzEtMTU1LTEzNC5uaG9zdC4wMGNkbi5jb20mc25pPTEzLTIzMS0xNTUtMTM0Lm5ob3N0LjAwY2RuLmNvbSMlRTklOUYlQTklRTUlOUIlQkRfMTIxMzIwMDQ4CnRyb2phbjovLzkyOGRjNmVlLTQ5NWItNDQ2Zi05ZjIwLTg4M2RlZGNlNTY0YUBVTkxLMy5MVldGOE4tSEg4RS0yMzAwLU5NT08tRDJFOU5BT0JFQUNOLjlEOEYyNjlGOTZCMjUyMzItNzU5Q0JCMzZENjU0ODU5Ny5LQVVGRU46MjAxNTI/YWxsb3dJbnNlY3VyZT0xJnBlZXI9aXAzNjkxMzc2MDc4Lm1vYmdzbGIudGJjYWNoZS5jb20mc25pPWlwMzY5MTM3NjA3OC5tb2Jnc2xiLnRiY2FjaGUuY29tIyVFOSU5RiVBOSVFNSU5QiVCRF8xMjEzMjAwNTAKdHJvamFuOi8vZDU2Y2I4ZGMtZTkzMi00ZDU3LWJkOTAtMTM4MWExMjQ1ZjkwQFVOTEszLkxWV0Y4Ti1ISDhFLTIzMDAtTk1PTy1EMkU5TkFPQkVBQ04uOUQ4RjI2OUY5NkIyNTIzMi03NTlDQkIzNkQ2NTQ4NTk3LktBVUZFTjoyMDE1Mj9hbGxvd0luc2VjdXJlPTEmc25pPWlwMzY5MTM3NjA3OC5tb2Jnc2xiLnRiY2FjaGUuY29tIyVFOSU5RiVBOSVFNSU5QiVCRF8xMjEzMjAwNTU= 2 | -------------------------------------------------------------------------------- /sub/subs.txt: -------------------------------------------------------------------------------- 1 | ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpHIXlCd1BXSDNWYW9AMzguNjQuMTM4LjIwNzo4MDI=#38.64.138.207%3A802-SS-2056452187 2 | ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpHIXlCd1BXSDNWYW9AMzguNjQuMTM4LjIwNzo4MDM=# 3 | trojan://7c9b7560-b0f7-11eb-a397-1239d0255272@fr-trojan.bonds.id:443#Relay_+%7C26.25Mb 4 | trojan://7e6256a0-b4ab-11eb-bc8f-1239d0255272@nl-trojan.bonds.id:443 5 | ssr://bjc0LmJvb20ucGFydHk6MjYwMDA6YXV0aF9hZXMxMjhfc2hhMTphZXMtMjU2LWNmYjpodHRwX3NpbXBsZTpWV3M1TWtOVC8_b2Jmc3BhcmFtPVpHOTNibXh2WVdRdWQybHVaRzkzYzNWd1pHRjBaUzVqYjIwJnByb3RvcGFyYW09TVRRek1EY3pPa042T0dGUGFRJnJlbWFya3M9NmFhWjVyaXZMVTAmZ3JvdXA9TVE 6 | ssr://bjkzLmJvb20ucGFydHk6MjgwMDA6YXV0aF9hZXMxMjhfc2hhMTphZXMtMjU2LWNmYjpodHRwX3NpbXBsZTpWV3M1TWtOVC8_b2Jmc3BhcmFtPVpHOTNibXh2WVdRdWQybHVaRzkzYzNWd1pHRjBaUzVqYjIwJnByb3RvcGFyYW09TVRRek1EY3pPa042T0dGUGFRJnJlbWFya3M9NmFhWjVyaXZMVkUmZ3JvdXA9TVE 7 | vmess://ewogICJhZGQiOiAiMTMuMjQ1LjE2LjEyNiIsCiAgImFpZCI6ICI2NCIsCiAgImhvc3QiOiAiMTMuMjQ1LjE2LjEyNiIsCiAgImlkIjogIjU1OTYzNmM3LWI1YTItNDUwYy05YjVlLTBkYzhmYzE0ZjRmNSIsCiAgIm5ldCI6ICJ0Y3AiLAogICJwYXRoIjogIiIsCiAgInBvcnQiOiAiMjA0MDQiLAogICJwcyI6ICJub25lIiwKICAidGxzIjogIiIsCiAgInR5cGUiOiAibm9uZSIsCiAgInVybF9ncm91cCI6ICJ2MnJheSIsCiAgInYiOiAiMSIKfQ== 8 | vmess://ew0KICAidiI6ICIyIiwNCiAgInBzIjogIkhLIEVDMiAwMSIsDQogICJhZGQiOiAiMTguMTY3Ljk0LjExMyIsDQogICJwb3J0IjogIjg5MyIsDQogICJpZCI6ICJjYTc4NDA1ZS1lNTU0LTNjZDMtOWI2ZC0yZWM5OGUyMWM4ZjEiLA0KICAiYWlkIjogIjEiLA0KICAibmV0IjogIndzIiwNCiAgInR5cGUiOiAibm9uZSIsDQogICJob3N0IjogIiIsDQogICJwYXRoIjogIi9obHMvY2N0djVwaGQubTN1OCIsDQogICJ0bHMiOiAiIg0KfQ== 9 | -------------------------------------------------------------------------------- /sub/vpn/quark/asia.txt: -------------------------------------------------------------------------------- 1 | |!tsbsvr#92+#cbsb!;Z|!jc#9#05/#+#mblf!;!QTCF)@thb(.RH,3/#+#gpru!;!2/4-2/8-289-261!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#0:4#+#mblf!;!D`o`e`.7#+#gpru!;!60/131/051/85!-!jr`evkm!;/-!dnvmuqz!;!d`#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{d`#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!248!-!o`nd#9#Ibobm.5#+#gpru!;!2/:-257-46/16!-!jr`evkm!;/-!dnvmuqz!;!ko#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}iq!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#040#+#mblf!;!N`m`zrj`.0#+#gpru!;!2/2-:8/81-2/8!-!jr`evkm!;/-!dnvmuqz!;!nx#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}lz!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#12/#+#mblf!;!Vmjsfc!Ru`udt,37#+#gpru!;!2/5-23:-23:-249!-!jr`evkm!;/-!dnvmuqz!;!vr#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{vr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!338!-!o`nd#9#Kvwflcnvqh,2!-!ints#9#83-314-2/6-5/#+#ht^gtmk#91+#bptossx#9#kv!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}kv!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#88!-!o`nd#9#Si`jkbme,2!-!ints#9#112/69-2/4-57#+#ht^gtmk#91+#bptossx#9#si!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{ug#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!332!-!o`nd#9#GpmhLnof.7#+#gpru!;!27/076/034/044#+#ht^gtmk#91+#bptossx#9#gl!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{ij#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!333!-!o`nd#9#Ibobm.8#+#gpru!;!27/087/164/028#+#ht^gtmk#91+#bptossx#9#iq!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{ko#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!337!-!o`nd#9#Es`obf,2/#+#gpru!;!6-279-:2/6:!-!jr`evkm!;/-!dnvmuqz!;!gq#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!beshd`}dvqpof{gq#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!215!-!o`nd#9#Htqbdm,4!-!ints#9#094/071/035/126#+#ht^gtmk#91+#bptossx#9#hm!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{jk#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!254!-!o`nd#9#GpmhLnof.5#+#gpru!;!3-65/058/8:!-!jr`evkm!;/-!dnvmuqz!;!ij#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}gl!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#044#+#mblf!;!Ugbhm`oc.3#+#gpru!;!3/4-87/012/84!-!jr`evkm!;/-!dnvmuqz!;!ug#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}si!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#056#+#mblf!;!QTCF)Dvqpof(.CF,21#+#gpru!;!55/074/163/064#+#ht^gtmk#91+#bptossx#9#cf!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}cf!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#45!-!o`nd#9#Rq`jm.0#+#gpru!;!:1/29-262-2/2!-!jr`evkm!;/-!dnvmuqz!;!fr#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{fr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!75#+#mblf!;!Qnm`oc.0#+#gpru!;!91/027/12-30#+#ht^gtmk#91+#bptossx#9#om!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}om!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#137#+#mblf!;!QTCF)@thb(.HO,7!-!ints#9#2/017/24-6!-!jr`evkm!;/-!dnvmuqz!;!jm#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}ho!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#142#+#mblf!;!Hdslbmz,25#+#gpru!;!226-216-327-31:!-!jr`evkm!;/-!dnvmuqz!;!ed#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{ed#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!86#+#mblf!;!Vmjsfc.Jjmhcpl.4#+#gpru!;!60/7:-255-95#+#ht^gtmk#91+#bptossx#9#fc!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}fc!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#14/#+#mblf!;!Ugbhm`oc.5#+#gpru!;!20:-68/022/035#+#ht^gtmk#91+#bptossx#9#si!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{ug#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!336!-!o`nd#9#OVAH'Brj`*,TF.2:!-!ints#9#42-88/082/092#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!:3#+#mblf!;!QTCF)JSIQ(.IQ,5!-!ints#9#081/013/025/142#+#ht^gtmk#91+#bptossx#9#iq!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{ko#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!221!-!o`nd#9#Mfsidskbmer.6#+#gpru!;!:1/028/088/53!-!jr`evkm!;/-!dnvmuqz!;!ok#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{ok#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!318!-!o`nd#9#Si`jkbme,6!-!ints#9#028/4:-204-212!-!jr`evkm!;/-!dnvmuqz!;!ug#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}si!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#057#+#mblf!;!Hdslbmz,22#+#gpru!;!55/074/163/072#+#ht^gtmk#91+#bptossx#9#cf!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`gqjbb{ftsnqd}cf!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#127#+#mblf!;!Nnchmd!Kfffmer.RH,41#+#gpru!;!22:-:8/52-236!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#074#+#mblf!;!BT.6qkvr.8#+#gpru!;!22:-:8/147/088#+#ht^gtmk#91+#bptossx#9#`v!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#nddbmj`}`v!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#126#+#mblf!;!Ugbhm`oc.2#+#gpru!;!20:-68/022/17!-!jr`evkm!;/-!dnvmuqz!;!ug#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}si!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#48!-!o`nd#9#TohudeTsbsfr.02!-!ints#9#4/097///047#+#ht^gtmk#91+#bptossx#9#tt!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}tt!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#128#+#mblf!;!Nnchmd!Kfffmer.RH,42#+#gpru!;!22:-:8/52-267!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#13/#+#mblf!;!Nnchmd!Kfffmer.RH,43#+#gpru!;!60/6:-236-47#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!82#+#mblf!;!D`o`e`.1#+#gpru!;!249-78/0/07!-!jr`evkm!;/-!dnvmuqz!;!d`#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{d`#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!303!-!o`nd#9#OVAH'Brj`*,TF.1:!-!ints#9#42-88/132/118#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!219!-!o`nd#9#Rxhuyfqm`oc.2#+#gpru!;!46/03//122/14/#+#ht^gtmk#91+#bptossx#9#bi!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}bi!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#075#+#mblf!;!Vmjsfc!Ru`udt,3/#+#gpru!;!2/5-23:-225-285!-!jr`evkm!;/-!dnvmuqz!;!vr#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{vr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!271!-!o`nd#9#TohudeTsbsfr.13!-!ints#9#83-47/058/082#+#ht^gtmk#91+#bptossx#9#tt!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}tt!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#041#+#mblf!;!BT.6qkvr.5#+#gpru!;!22:-:8/044/042#+#ht^gtmk#91+#bptossx#9#`v!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#nddbmj`}`v!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#120#+#mblf!;!Utsjfx.0#+#gpru!;!232-:7/025/03/#+#ht^gtmk#91+#bptossx#9#ss!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{uq#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!68#+#mblf!;!Gqbmdd.2#+#gpru!;!6-279-:2/028#+#ht^gtmk#91+#bptossx#9#es!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`gqjbb{ftsnqd}es!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#65!-!o`nd#9#OVAH'Brj`*,TF.03!-!ints#9#42-88/070/68!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#085#+#mblf!;!QTCF)@thb(.RH,35#+#gpru!;!22:-:8/7:-285!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#07/#+#mblf!;!Jrs`fk.3#+#gpru!;!40/042/01//3:!-!jr`evkm!;/-!dnvmuqz!;!jk#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}hm!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#051#+#mblf!;!Vmjsfc!Ru`udt,28#+#gpru!;!263-2/8-28:-201!-!jr`evkm!;/-!dnvmuqz!;!vr#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{vr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!2/3!-!o`nd#9#OVAH'TnvsiBlfqjbb(.AS,2!-!ints#9#41-8-2-36#+#ht^gtmk#91+#bptossx#9#as!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#rptugBlfqjbb{cq#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!71#+#mblf!;!Sttrj`.1#+#gpru!;!:1/29-22:-:4#+#ht^gtmk#91+#bptossx#9#qv!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}qv!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#42!-!o`nd#9#Qvrthb,2!-!ints#9#83-47/061/051#+#ht^gtmk#91+#bptossx#9#qv!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`gqjbb{ftsnqd}qv!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#138#+#mblf!;!QTCF)@thb(.HO,6!-!ints#9#2/017/38-264!-!jr`evkm!;/-!dnvmuqz!;!jm#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}ho!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#134#+#mblf!;!VJ.ACB!Hqkbxfq.04!-!ints#9#42-286-308-30#+#ht^gtmk#91+#bptossx#9#fc!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`gqjbb{ftsnqd}fc!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#52!-!o`nd#9#Rq`jm.1#+#gpru!;!:1/29-262-2/4!-!jr`evkm!;/-!dnvmuqz!;!fr#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!beshd`}dvqpof{fr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!205!-!o`nd#9#Bbmbcb,6!-!ints#9#82-284-7-75#+#ht^gtmk#91+#bptossx#9#bb!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}bb!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#047#+#mblf!;!Ghokbme,2!-!ints#9#86-307-6-345!-!jr`evkm!;/-!dnvmuqz!;!gh#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{gh#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!2/1!-!o`nd#9#OVAH'Ftsnqd*,ED.8#+#gpru!;!284-2/9-209-245!-!jr`evkm!;/-!dnvmuqz!;!ed#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!ftsnqd}cf!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#071#+#mblf!;!QTCF.EsdfGhsd.RH,32#+#gpru!;!60/6:-249-277!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#132#+#mblf!;!Vmjsfc.Jjmhcpl.03!-!ints#9#42-286-308-31#+#ht^gtmk#91+#bptossx#9#fc!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`gqjbb{ftsnqd}fc!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#032#+#mblf!;!Jrs`fk.1#+#gpru!;!276-253-216-:0#+#ht^gtmk#91+#bptossx#9#hm!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`gqjbb{brj`}hm!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#028#+#mblf!;!Vmjsfc.Jjmhcpl.6#+#gpru!;!279-331-80/051#+#ht^gtmk#91+#bptossx#9#fc!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}fc!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#086#+#mblf!;!N`m`zrj`.1#+#gpru!;!202-://06//030#+#ht^gtmk#91+#bptossx#9#lz!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{nx#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!232!-!o`nd#9#GpmhLnof.4#+#gpru!;!6-272-5-32:!-!jr`evkm!;/-!dnvmuqz!;!ij#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}gl!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#087#+#mblf!;!QTCF)JSIQ(.IQ,8!-!ints#9#094/07//17-63#+#ht^gtmk#91+#bptossx#9#iq!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{ko#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!312!-!o`nd#9#OVAH'Brj`*,TF.26!-!ints#9#42-88/054/0:2#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!313!-!o`nd#9#OVAH'Brj`*,TF.27!-!ints#9#42-88/054/01!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#78!-!o`nd#9#@s`cFljqbsfr.4#+#gpru!;!2/:-25:-81/86!-!jr`evkm!;/-!dnvmuqz!;!bd#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}`f!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#44!-!o`nd#9#Es`obf,3!-!ints#9#4/097/84-50#+#ht^gtmk#91+#bptossx#9#es!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}es!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#064#+#mblf!;!Utsjfx.2#+#gpru!;!6-279-45/02!-!jr`evkm!;/-!dnvmuqz!;!uq#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}ss!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#118#+#mblf!;!Vmjsfc!Ru`udt,36#+#gpru!;!2/5-23:-21:-217!-!jr`evkm!;/-!dnvmuqz!;!vr#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{vr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!274!-!o`nd#9#TohudeTsbsfr.16!-!ints#9#4/097///093#+#ht^gtmk#91+#bptossx#9#tt!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}tt!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#084#+#mblf!;!Thofbopqf,34#+#gpru!;!90/81-279-67#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!85#+#mblf!;!QTCF)@thb(.RH,23#+#gpru!;!60/6:-252-9/#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!272!-!o`nd#9#TohudeTsbsfr.14!-!ints#9#094/062/09//01!-!jr`evkm!;/-!dnvmuqz!;!vr#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{vr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!242!-!o`nd#9#Hsdm`oc.0#+#gpru!;!4-33:-61/057#+#ht^gtmk#91+#bptossx#9#hf!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}hf!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#091#+#mblf!;!Vmjsfc!Ru`udt,33#+#gpru!;!303-2/4-70/076#+#ht^gtmk#91+#bptossx#9#tt!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}tt!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#083#+#mblf!;!TnvsiBeshd`.1#+#gpru!;!2/3-221-212-328!-!jr`evkm!;/-!dnvmuqz!;!{`#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!beshd`}yb!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#058#+#mblf!;!Odugfqm`oct,9!-!ints#9#28-57/71-3/4!-!jr`evkm!;/-!dnvmuqz!;!ok#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!beshd`}dvqpof{ok#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!245!-!o`nd#9#Es`obf,9!-!ints#9#53-301-304-7!-!jr`evkm!;/-!dnvmuqz!;!gq#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{gq#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!255!-!o`nd#9#Bbmbcb,8!-!ints#9#42-313-95/113#+#ht^gtmk#91+#bptossx#9#bb!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}`thb{d`#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!249!-!o`nd#9#Tohude,Lhofenn,:!-!ints#9#42-286-227-3/:!-!jr`evkm!;/-!dnvmuqz!;!ha#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!beshd`}dvqpof{ha#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!228!-!o`nd#9#@s`cFljqbsfr.5#+#gpru!;!308-229-284-63#+#ht^gtmk#91+#bptossx#9#`f!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{bd#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!236!-!o`nd#9#Rptug!@gqjbb,2!-!ints#9#011/04//027/8:!-!jr`evkm!;/-!dnvmuqz!;!{`#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}yb!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#062#+#mblf!;!Jsbkz,5!-!ints#9#82-284-6-289!-!jr`evkm!;/-!dnvmuqz!;!js#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{js#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!21:!-!o`nd#9#Afkhhvl.0#+#gpru!;!98/158/64-3/7!-!jr`evkm!;/-!dnvmuqz!;!cd#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{cd#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!386!-!o`nd#9#TL,CADJom`zds,24#+#gpru!;!2/4-2/6-57/0:8#+#ht^gtmk#91+#bptossx#9#fc!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}fc!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#188#+#mblf!;!Oduemhy,Iap,Itmt.Cjrodz,Topsjez,48#+#gpru!;!2/4-229-82/027#+#ht^gtmk#91+#bptossx#9#tt!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}tt!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#19/#+#mblf!;!Oduemhy,Iap,Itmt.Cjrodz,Topsjez,5/#+#gpru!;!2/4-229-82/035#+#ht^gtmk#91+#bptossx#9#tt!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}tt!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#194#+#mblf!;!Nnchmd!Kfffmer.HE,2!-!ints#9#012/066/87-2/4!-!jr`evkm!;/-!dnvmuqz!;!jc#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}he!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#055#+#mblf!;!Ndyhdn.0#+#gpru!;!222-287-346-231!-!jr`evkm!;/-!dnvmuqz!;!nw#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!nw#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!413!-!o`nd#9#LpajkfMdhdoct,TF.45!-!ints#9#048/8:-70/063#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!406!-!o`nd#9#Rjmh`qnsd.38!-!ints#9#048/8:-70/072#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!372!-!o`nd#9#OVAH'Brj`*,TF.33!-!ints#9#048/8:-://03!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#15/#+#mblf!;!Vmjsfc!Ru`udt,24#+#gpru!;!246-:3/0:5/143#+#ht^gtmk#91+#bptossx#9#tt!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}tt!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#1:5#+#mblf!;!Vmjsfc!Jjmhcpl.07!-!ints#9#087/066/73-265!-!jr`evkm!;/-!dnvmuqz!;!ha#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{ha#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!4/1!-!o`nd#9#OFR.IQ,4!-!ints#9#094/081/022/49!-!jr`evkm!;/-!dnvmuqz!;!ko#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}iq!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#1:7#+#mblf!;!Snn`ohb,2!-!ints#9#094/134/0:-73#+#ht^gtmk#91+#bptossx#9#qp!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}qp!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#214#+#mblf!;!Hqfddd.0#+#gpru!;!276-334-305-64#+#ht^gtmk#91+#bptossx#9#fs!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}fs!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#215#+#mblf!;!Tvfcfm.0#+#gpru!;!276-334-306-278!-!jr`evkm!;/-!dnvmuqz!;!td#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{td#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!377!-!o`nd#9#OFR.IQ,2!-!ints#9#0:3/065/14//094#+#ht^gtmk#91+#bptossx#9#iq!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{ko#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!4/4!-!o`nd#9#Kbswhb,2!-!ints#9#0:4/032/118/087#+#ht^gtmk#91+#bptossx#9#kw!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}kw!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#211#+#mblf!;!DyfbiSdqtckjb.0#+#gpru!;!286-214-336-3/5!-!jr`evkm!;/-!dnvmuqz!;!dy#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{dy#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!227!-!o`nd#9#TohudeTsbsfr.09!-!ints#9#1/47-269-3/2!-!jr`evkm!;/-!dnvmuqz!;!vr#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{vr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!384!-!o`nd#9#LpajkfMdhdoct,TF.35!-!ints#9#115/098/77-25:!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#025#+#mblf!;!Ctmfbqj`.0#+#gpru!;!308-229-3/3-7!-!jr`evkm!;/-!dnvmuqz!;!cf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!beshd`}dvqpof{cf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!385!-!o`nd#9#Hddm`oc.0#+#gpru!;!46/144/3:-237!-!jr`evkm!;/-!dnvmuqz!;!jr#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{jr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!345!-!o`nd#9#Mfsgkjw.GCN.GVKV,EHTMFX.28!-!ints#9#29-:3/020/38!-!jr`evkm!;/-!dnvmuqz!;!vr#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{vr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!34:!-!o`nd#9#Mfsgkjw.Gcn.Gvkv,Ehtmfx.Rqnuhgx.29!-!ints#9#29-:3/020/56!-!jr`evkm!;/-!dnvmuqz!;!vr#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!tnvsi@ndshd`}mpqugBlfqjbb{vr#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!335!-!o`nd#9#Oihmhqojmfr.0#+#gpru!;!58/066/19-323!-!jr`evkm!;/-!dnvmuqz!;!qg#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}oi!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#221#+#mblf!;!QDT,KO.3#+#gpru!;!6-272-6-245!-!jr`evkm!;/-!dnvmuqz!;!ko#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}iq!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#1:8#+#mblf!;!Onsvbx.0#+#gpru!;!6-274-2/1-96#+#ht^gtmk#91+#bptossx#9#mp!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}mp!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#213#+#mblf!;!Edolbql,2!-!ints#9#4/092/010/138#+#ht^gtmk#91+#bptossx#9#cl!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}cl!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#1:6#+#mblf!;!Vjs`jmf,2!-!ints#9#4/097/5/023#+#ht^gtmk#91+#bptossx#9#tb!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}tb!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#196#+#mblf!;!QDT,KO.1#+#gpru!;!6-343-289-8/#+#ht^gtmk#91+#bptossx#9#iq!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{ko#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!368!-!o`nd#9#OVAH'Brj`*,TF.31!-!ints#9#42-88/053/057#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!373!-!o`nd#9#OVAH'Brj`*,TF.34!-!ints#9#42-88/053/23!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#187#+#mblf!;!Nnchmd!Kfffmer.RH,50#+#gpru!;!60/6:-236-215!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#228#+#mblf!;!Thofbopqf,60#+#gpru!;!60/6:-236-309!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#230#+#mblf!;!Nnchmd!Kfffmer.RH,62#+#gpru!;!60/6:-248-67#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!411!-!o`nd#9#LpajkfMdhdoct,TF.43!-!ints#9#42-88/068/03!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#223#+#mblf!;!Thofbopqf,55#+#gpru!;!60/6:-257-262!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#227#+#mblf!;!Thofbopqf,6/#+#gpru!;!60/6:-314-:5#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!404!-!o`nd#9#Rjmh`qnsd.36!-!ints#9#42-88/150/156#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!408!-!o`nd#9#Rjmh`qnsd.3:!-!ints#9#42-88/158/86!-!jr`evkm!;/-!dnvmuqz!;!tf#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}rh!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#225#+#mblf!;!Thofbopqf,57#+#gpru!;!60/6:-33:-:7#+#ht^gtmk#91+#bptossx#9#rh!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{tf#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!258!-!o`nd#9#Tohude,Lhofenn,2/#+#gpru!;!60/7:-229-253!-!jr`evkm!;/-!dnvmuqz!;!ha#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!beshd`}dvqpof{ha#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!24:!-!o`nd#9#OVAH'LQKO*,LQ.1#+#gpru!;!63/09//044/012#+#ht^gtmk#91+#bptossx#9#js!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`thb{lq#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!218!-!o`nd#9#TL,CADJom`zds,9!-!ints#9#68-338-216-36#+#ht^gtmk#91+#bptossx#9#fc!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}fc!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#210#+#mblf!;!Bttsshb,2!-!ints#9#6:-224-52/035#+#ht^gtmk#91+#bptossx#9#`u!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}`u!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#157#+#mblf!;!Oduemhy,VR.22!-!ints#9#73-2/3-4//12/#+#ht^gtmk#91+#bptossx#9#tt!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#rptugBlfqjbb{onssi@ndshd`}tt!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#43!-!o`nd#9#Hu`mx.0#+#gpru!;!:1/132/6:-85#+#ht^gtmk#91+#bptossx#9#hu!-!jr`ujo#92+#qbsf!;//2-!bqf`#9#`gqjbb{ftsnqd}hu!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#51!-!o`nd#9#Hu`mx.1#+#gpru!;!:1/132/84-231!-!jr`evkm!;/-!dnvmuqz!;!js#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!beshd`}dvqpof{js#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!383!-!o`nd#9#ES,UE2,20#+#gpru!;!:4/088/125/77!-!jr`evkm!;/-!dnvmuqz!;!gq#+#ht^whq!;0-!s`ud#91-4+#`sdb!;!beshd`}dvqpof{gq#+#vfhhgu!;/-!jr`osnyx#9#/#|-z#he!;!401!-!o`nd#9#Biho`.Ri`ofi`j,2!-!ints#9#010/82-212-338!-!jr`evkm!;/-!dnvmuqz!;!dm#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}bo!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#220#+#mblf!;!Dgjmb,Htbmhyinv,2!-!ints#9#012/35-342-325!-!jr`evkm!;/-!dnvmuqz!;!dm#+#ht^whq!;/-!s`ud#91-7+#`sdb!;!brj`}bo!-!xdjfis#91+#ht^qqpwz!;!1!~+|!jc#9#218#+#mblf!;!Dgjmb,Cdjijmh,2!-!ints#9#012/36-221-31#+#ht^gtmk#91+#bptossx#9#bo!-!jr`ujo#91+#qbsf!;//5-!bqf`#9#`thb{dm#+#vfhhgu!;/-!jr`osnyx#9#/#|^+#opqu!;z#opqu!;!6/1/5!-!q`trxnsc#9#3506843386!-!ndugpc#9#`fr.165.bga#|-!bqf`#9#`thb!-!dnvmuqz!;!dm#| -------------------------------------------------------------------------------- /up.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | git add . 3 | git commit -m "commit via auto upload shell" 4 | git push 5 | pause -------------------------------------------------------------------------------- /up.sh: -------------------------------------------------------------------------------- 1 | git add . 2 | git commit -m "ci: Auto update at $(date +"%m-%d %H:%M")" 3 | git push --------------------------------------------------------------------------------