├── .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 |
5 |
6 |
7 |
8 | 
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 | [](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
--------------------------------------------------------------------------------