diff --git a/CHANGELOG.md b/CHANGELOG.md index 05b31ee..58a7128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,47 @@ # Changelog 所有对本项目的显著更改都将记录在此文件中。 +## [2.0.0] - 2026-01-18 +### 重大重构 +- **核心查询逻辑重构**:移除了所有响应合并相关代码,简化了DNS查询处理流程 +- **并行查询模式重设计**:改为返回第一个成功响应,提高响应速度 +- **fast-ip模式优化**:只向一个预先测试出的最快服务器发送请求,降低资源消耗 +- **代码结构优化**:移除了冗余的响应合并机制,减少了内存占用和CPU消耗 + +### 移除 +- 删除了 `mergeResponses` 函数:不再合并多个DNS响应 +- 删除了 `recordKey` 结构体:不再需要唯一标识DNS记录 +- 删除了 `getRecordKey` 函数:不再需要获取DNS记录的唯一标识 +- 移除了所有响应合并相关的代码 + +### 改进 +- **parallel模式**:向多个上游服务器并行发送请求,返回第一个成功响应 +- **fast-ip模式**:通过ping测试选择最快服务器,只向一个服务器发送请求 +- **默认模式**:采用新的并行查询逻辑,返回第一个成功响应 +- **资源管理**:优化了连接池使用,减少资源消耗 +- **DNSSEC验证**:只对将要返回的响应进行验证,减少不必要的计算 + +### 性能提升 +- 减少了内存占用:不再存储多个响应进行合并 +- 降低了CPU消耗:移除了复杂的响应合并算法 +- 提高了响应速度:返回第一个成功响应,无需等待所有服务器响应 +- 减少了网络流量:fast-ip模式只向一个服务器发送请求 + +## [1.2.7] - 2026-01-17 +### 改进 +- 实现服务器启动时远程屏蔽列表获取和DNS服务启动同时进行 +- 新增`LoadLocalRulesOnly()`方法,只加载本地规则和hosts文件,确保服务器快速启动 +- 在main.go中使用`LoadLocalRulesOnly()`替代`LoadRules()`,不再等待远程规则获取完成 +- 添加异步加载远程规则的goroutine,服务器启动后在后台加载远程规则 +- 优化缓存机制,本地有缓存时自动加载,服务器启动时只检查更新而不是重新获取 +- 修改`fetchRemoteRules`方法,只有在缓存需要更新时才去远程获取规则,否则直接从缓存加载 +- 完善错误处理,当从远程获取失败时,尝试使用过期的缓存 +- 服务器和设置界面优化调整,增加缓存模式设置、缓存大小、缓存时间设置 + +## [1.2.6] - 2025-12-30 +### 新增 +- 实现查询日志详情的域名信息显示功能 +- 实现GFWList功能,可以使用Steam++作为代理访问YouTube,谷歌等被屏蔽的网站 ## [1.2.5] - 2025-12-26 ### 新增 - 增加了对IPv6的支持配置项,默认关闭; @@ -21,9 +62,6 @@ - 修复了DNS查询超时设置过短导致的"Server failed"错误。 ### 更新 - 更新Swagger API文档。 -### 下一版本改进 -- 增加了对DNSSEC的支持配置项,默认关闭; - ## [1.2.4] - 2025-12-25 ### 改进 @@ -99,13 +137,13 @@ ### 修改 - 在forwardDNSRequestWithCache函数中添加域名匹配逻辑,检查域名是否包含不验证DNSSEC的模式 -- 在所有查询模式(parallel、loadbalance、fastest-ip、default)中实现跳过DNSSEC验证的功能 +- 在所有查询模式(parallel、fastest-ip、default)中实现跳过DNSSEC验证的功能 ## [1.1.1] - 2025-12-19 ### 修改 - 修复NXDOMAIN响应传播逻辑,确保上游DNS服务器返回的NXDOMAIN响应能正确传递给客户端 -- 优化loadbalance、fastest-ip和parallel查询模式下的NXDOMAIN响应选择机制 +- 优化fastest-ip和parallel查询模式下的NXDOMAIN响应选择机制 - 确保不存在的域名能被正确识别并返回NXDOMAIN状态码 - 修复服务器绑定地址配置,确保IPv4兼容性 diff --git a/build-windows.sh b/build-windows.sh deleted file mode 100755 index f070b7e..0000000 --- a/build-windows.sh +++ /dev/null @@ -1,5 +0,0 @@ -CGO_ENABLED=1 \ -GOOS=windows \ -GOARCH=amd64 \ -CC=gcc \ -go build -o dns-server.exe main.go diff --git a/build.sh b/build.sh index 6048767..caf9aa7 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,6 @@ -CGO_ENABLED=1 \ -GOOS=linux \ -GOARCH=amd64 \ -CC=gcc \ -go build -ldflags "-linkmode external -extldflags '-static -pthread'" -o dns-server main.go +CGO_ENABLED=1 +GOOS=linux +GOARCH=amd64 +CC=gcc +service dns-server stop && go build -o dns-server main.go && service dns-server start + diff --git a/config.json b/config.json index 3373ce1..bd207b2 100644 --- a/config.json +++ b/config.json @@ -2,29 +2,29 @@ "dns": { "port": 53, "upstreamDNS": [ - "223.5.5.5:53" + "10.35.10.200", + "223.5.5.5", + "223.6.6.6" ], "dnssecUpstreamDNS": [ - "117.50.10.10", - "101.226.4.6", - "218.30.118.6", "208.67.220.220", "208.67.222.222" ], - "timeout": 5, - "saveInterval": 30, - "cacheTTL": 10, - "enableDNSSEC": true, + "saveInterval": 10, + "cacheTTL": 60, + "enableDNSSEC": false, "queryMode": "parallel", + "queryTimeout": 500, + "enableFastReturn": true, "domainSpecificDNS": { "addr.arpa": [ "10.35.10.200:53" ], "akadns": [ - "4.2.2.1:53" + "223.5.5.5:53" ], "akamai": [ - "4.2.2.1:53" + "223.5.5.5:53" ], "amazehome.cn": [ "10.35.10.200:53" @@ -36,7 +36,7 @@ "4.2.2.1:53" ], "steam": [ - "4.2.2.1:53" + "223.5.5.5:53" ] }, "noDNSSECDomains": [ @@ -45,7 +45,12 @@ "amazehome.xyz", ".cn" ], - "enableIPv6": false + "enableIPv6": false, + "cacheMode": "file", + "cacheSize": 100, + "maxCacheTTL": 60, + "minCacheTTL": 30, + "cacheFilePath": "data/cache.json" }, "http": { "port": 8080, @@ -60,7 +65,7 @@ "name": "AdGuard DNS filter", "url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/filter.txt", "enabled": true, - "lastUpdateTime": "2025-12-21T10:46:36.629Z" + "lastUpdateTime": "2026-01-23T01:04:32.424Z" }, { "name": "Adaway Default Blocklist", @@ -78,7 +83,7 @@ "name": "My GitHub Rules", "url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/costomize.txt", "enabled": true, - "lastUpdateTime": "2025-12-24T07:11:16.596Z" + "lastUpdateTime": "2026-01-17T19:04:34.551Z" }, { "name": "CNList", @@ -141,9 +146,14 @@ ], "updateInterval": 3600, "blockMethod": "NXDOMAIN", - "customBlockIP": "", + "customBlockIP": "0.0.0.2", "statsSaveInterval": 60 }, + "gfwList": { + "ip": "127.0.0.1", + "content": "", + "enabled": false + }, "log": { "level": "debug", "maxSize": 100, diff --git a/config/config.go b/config/config.go index 28961c4..cc113f9 100644 --- a/config/config.go +++ b/config/config.go @@ -17,14 +17,20 @@ type DNSConfig struct { Port int `json:"port"` UpstreamDNS []string `json:"upstreamDNS"` DNSSECUpstreamDNS []string `json:"dnssecUpstreamDNS"` // 用于DNSSEC查询的专用服务器 - Timeout int `json:"timeout"` SaveInterval int `json:"saveInterval"` // 数据保存间隔(秒) CacheTTL int `json:"cacheTTL"` // DNS缓存过期时间(分钟) EnableDNSSEC bool `json:"enableDNSSEC"` // 是否启用DNSSEC支持 - QueryMode string `json:"queryMode"` // 查询模式:"loadbalance"(负载均衡)、"parallel"(并行请求)、"fastest-ip"(最快的IP地址) + QueryMode string `json:"queryMode"` // 查询模式:"parallel"(并行请求)、"fastest-ip"(最快的IP地址) + QueryTimeout int `json:"queryTimeout"` // 查询超时时间(毫秒) + EnableFastReturn bool `json:"enableFastReturn"` // 是否启用快速返回机制 DomainSpecificDNS DomainSpecificDNS `json:"domainSpecificDNS"` // 域名特定DNS服务器配置 NoDNSSECDomains []string `json:"noDNSSECDomains"` // 不验证DNSSEC的域名模式列表 EnableIPv6 bool `json:"enableIPv6"` // 是否启用IPv6解析(AAAA记录) + CacheMode string `json:"cacheMode"` // 缓存模式:"memory"(内存缓存)、"file"(文件缓存) + CacheSize int `json:"cacheSize"` // 缓存大小限制(MB),0表示不缓存 + MaxCacheTTL int `json:"maxCacheTTL"` // 最大缓存TTL(分钟) + MinCacheTTL int `json:"minCacheTTL"` // 最小缓存TTL(分钟) + CacheFilePath string `json:"cacheFilePath"` // 缓存文件路径 } // HTTPConfig HTTP控制台配置 @@ -49,9 +55,16 @@ type BlacklistEntry struct { type ShieldConfig struct { Blacklists []BlacklistEntry `json:"blacklists"` UpdateInterval int `json:"updateInterval"` - BlockMethod string `json:"blockMethod"` // 屏蔽方法: "NXDOMAIN", "refused", "emptyIP", "customIP" - CustomBlockIP string `json:"customBlockIP"` // 自定义屏蔽IP,当BlockMethod为"customIP"时使用 - StatsSaveInterval int `json:"statsSaveInterval"` // 计数数据保存间隔(秒) + BlockMethod string `json:"blockMethod"` // 屏蔽方法: "NXDOMAIN", "refused", "emptyIP", "customIP" + CustomBlockIP string `json:"customBlockIP"` // 自定义屏蔽IP,当BlockMethod为"customIP"时使用 + StatsSaveInterval int `json:"statsSaveInterval"` // 计数数据保存间隔(秒) +} + +// GFWListConfig GFWList配置 +type GFWListConfig struct { + IP string `json:"ip"` // GFWList域名解析的目标IP地址 + Content string `json:"content"` // GFWList规则文件路径 + Enabled bool `json:"enabled"` // 是否启用GFWList功能 } // LogConfig 日志配置 @@ -64,10 +77,11 @@ type LogConfig struct { // Config 整体配置 type Config struct { - DNS DNSConfig `json:"dns"` - HTTP HTTPConfig `json:"http"` - Shield ShieldConfig `json:"shield"` - Log LogConfig `json:"log"` + DNS DNSConfig `json:"dns"` + HTTP HTTPConfig `json:"http"` + Shield ShieldConfig `json:"shield"` + GFWList GFWListConfig `json:"gfwList"` // GFWList配置 + Log LogConfig `json:"log"` } // LoadConfig 加载配置文件 @@ -87,9 +101,6 @@ func LoadConfig(path string) (*Config, error) { if config.DNS.Port == 0 { config.DNS.Port = 53 } - if config.DNS.Timeout == 0 { - config.DNS.Timeout = 5000 // 默认超时时间为5000毫秒 - } if len(config.DNS.UpstreamDNS) == 0 { config.DNS.UpstreamDNS = []string{"223.5.5.5:53", "223.6.6.6:53"} } @@ -100,10 +111,38 @@ func LoadConfig(path string) (*Config, error) { if config.DNS.CacheTTL == 0 { config.DNS.CacheTTL = 30 // 默认30分钟 } + // 缓存模式默认值 + if config.DNS.CacheMode == "" { + config.DNS.CacheMode = "memory" // 默认内存缓存 + } + // 缓存大小默认值(100MB) + if config.DNS.CacheSize == 0 { + config.DNS.CacheSize = 100 // 默认100MB + } + // 最大缓存TTL默认值(120分钟) + if config.DNS.MaxCacheTTL == 0 { + config.DNS.MaxCacheTTL = 120 // 默认120分钟 + } + // 最小缓存TTL默认值(5分钟) + if config.DNS.MinCacheTTL == 0 { + config.DNS.MinCacheTTL = 5 // 默认5分钟 + } + // 缓存文件路径固定为data/cache.json,不再从配置文件读取 + config.DNS.CacheFilePath = "data/cache.json" // DNSSEC默认配置 - config.DNS.EnableDNSSEC = true // 默认启用DNSSEC支持 + // 如果未在配置文件中设置,默认启用DNSSEC支持 + // json.Unmarshal会将未设置的布尔字段设为false,所以我们需要显式检查 + // 但由于这是一个新字段,为了向后兼容,我们保持默认值为true + // 注意:如果用户在配置文件中明确设置为false,则使用false + if !config.DNS.EnableDNSSEC { + // 检查是否真的是用户设置为false,还是默认值 + // 由于JSON布尔值默认是false,我们无法直接区分 + // 所以这里保持默认行为,让用户可以通过配置文件设置为false + } // IPv6默认配置 - config.DNS.EnableIPv6 = true // 默认启用IPv6解析 + // 注意:我们不能直接设置默认值,因为JSON布尔值默认是false + // 我们需要检查配置文件中是否真的设置了这个字段 + // 由于我们无法直接区分,这里保持现状,让用户可以通过配置文件设置为false // DNSSEC专用服务器默认配置 if len(config.DNS.DNSSECUpstreamDNS) == 0 { config.DNS.DNSSECUpstreamDNS = []string{"8.8.8.8:53", "1.1.1.1:53"} @@ -112,6 +151,14 @@ func LoadConfig(path string) (*Config, error) { if config.DNS.QueryMode == "" { config.DNS.QueryMode = "parallel" // 默认使用并行请求模式 } + // 查询超时默认配置(毫秒) + if config.DNS.QueryTimeout == 0 { + config.DNS.QueryTimeout = 500 // 默认超时时间为500ms + } + // 快速返回机制默认配置 + if config.DNS.EnableFastReturn == false { + config.DNS.EnableFastReturn = true // 默认启用快速返回机制 + } // 域名特定DNS服务器配置默认值 if config.DNS.DomainSpecificDNS == nil { config.DNS.DomainSpecificDNS = make(DomainSpecificDNS) // 默认为空映射 @@ -140,6 +187,13 @@ func LoadConfig(path string) (*Config, error) { config.Shield.StatsSaveInterval = 300 // 默认5分钟保存一次 } + // GFWList默认配置 + if config.GFWList.IP == "" { + config.GFWList.IP = "127.0.0.1" // 默认GFWList解析目标IP为127.0.0.1 + } + // GFWList默认启用(仅当未在配置文件中明确设置为false时) + // 注意:如果用户在配置文件中明确设置为false,则保持为false + // 如果黑名单列表为空,添加一些默认的黑名单 if len(config.Shield.Blacklists) == 0 { config.Shield.Blacklists = []BlacklistEntry{ diff --git a/data/gflist.txt b/data/gflist.txt new file mode 100644 index 0000000..9806b0e --- /dev/null +++ b/data/gflist.txt @@ -0,0 +1,2572 @@ +W0F1dG9Qcm94eSAwLjIuOV0KISBDaGVja3N1bTogQVg1c3RUZ3B2eDg0MkRBNkxk +dEtBdwohIEV4cGlyZXM6IDZoCiEgVGl0bGU6IEdGV0xpc3Q0TEwKISBHRldMaXN0 +IHdpdGggRVZFUllUSElORyBpbmNsdWRlZAohIExhc3QgTW9kaWZpZWQ6IFNhdCwg +MTMgU2VwIDIwMjUgMDQ6MTM6NDUgKzAwMDAKIQohIEhvbWVQYWdlOiBodHRwczov +L2dpdGh1Yi5jb20vZ2Z3bGlzdC9nZndsaXN0CiEgTGljZW5zZTogaHR0cHM6Ly93 +d3cuZ251Lm9yZy9saWNlbnNlcy9vbGQtbGljZW5zZXMvbGdwbC0yLjEudHh0CiEK +ISBHRldMaXN0IGlzIHVubGlrZWx5IHRvIGZ1bGx5IGNvbXByaXNlIHRoZSByZWFs +CiEgcnVsZXMgYmVpbmcgZGVwbG95ZWQgaW5zaWRlIEdGVyBzeXN0ZW0uIFdlIHRy +eQohIG91ciBiZXN0IHRvIGtlZXAgdGhlIGxpc3QgdXAgdG8gZGF0ZS4gUGxlYXNl +CiEgY29udGFjdCB1cyByZWdhcmRpbmcgVVJMIHN1Ym1pc3Npb24gLyByZW1vdmFs +LAohIG9yIHN1Z2dlc3Rpb24gLyBlbmhhbmNlbWVudCBhdCBpc3N1ZSB0cmFja2Vy +OgohIGh0dHBzOi8vZ2l0aHViLmNvbS9nZndsaXN0L2dmd2xpc3QvaXNzdWVzLy4K +CiEtLS0tLS0tLS00MDMvNDUxLzUwMy81MjAgJiBVUkwgUmVkaXJlY3RzLS0tLS0t +LS0tCnx8YmxvZ2phdi5uZXQKfHx6b29taW5mby5jb20KfHxwdHd4ei5jb20KfHxt +aXVpcG9sc2thLnBsCnx8cGlhb3RpYS5jb20KfHx3dW5kZXJncm91bmQuY29tCnx8 +NTAwcHguY29tCnx8NTAwcHgub3JnCiEtLWVoZW50YWkKfGh0dHA6Ly84NS4xNy43 +My4zMS8KIS0tfHxhZG9yYW1hLmNvbQp8fGFmcmVlY2F0di5jb20KfHxhZ25lc2Iu +ZnIKfHxhaXJpdGlsaWJyYXJ5LmNvbQp8fGFiZW1hdHYuYWthbWFpemVkLm5ldAp8 +fGxpbmVhci1hYmVtYXR2LmFrYW1haXplZC5uZXQKfHx2b2QtYWJlbWF0di5ha2Ft +YWl6ZWQubmV0Cnx8YWtpYmEtd2ViLmNvbQp8fGFsdHJlYy5jb20KfHxhbWF6b252 +aWRlby5jb20KfHxhbmdlbGEtbWVya2VsLmRlCnx8YW5nb2xhLm9yZwp8fGFudGhy +b3BpYy5jb20KfHxhcGFydG1lbnRyYXRpbmdzLmNvbQp8fGFwYXJ0bWVudHMuY29t +Cnx8YXJlbmEudGFpcGVpCnx8YXNzZXRzLmJ3YnguaW8KfHxhc3NpbXAub3JnCnx8 +YXRoZW5hZWl6b3UuY29tCnx8YmFua21vYmlsZXZpYmUuY29tCnx8YmFub3J0ZS5j +b20KfHxiZWVnLmNvbQp8fGdsb2JhbC5iaW5nLmNvbQp8fGJvb2t0b3BpYS5jb20u +YXUKfHxib3lzbWFzdGVyLmNvbQp8fGJ5bmV0LmNvLmlsCnx8YnlydXQub3JnCnx8 +Y2FyZmF4LmNvbQouY2FzaW5vYmVsbGluaS5jb20KfHxjYXNpbm9iZWxsaW5pLmNv +bQp8fGNlbnRhdXJvLmNvbS5icgp8fGNob2JpdC5jYwp8fGNpY2lhaS5jb20KfHxj +aWNpLmNvbQp8fGNsYXVkZS5haQp8fGNsZWFyc3VyYW5jZS5jb20KfHxjbmJldGEu +Y29tLnR3Cnx8Y291bnRlci5zb2NpYWwKfHxjb3N0Y28uY29tCnx8Y296ZS5jb20K +fHxjcm9zc2ZpcmUuY28ua3IKfHxjcnVuY2h5cm9sbC5jb20KfHxkMnBhc3MuY29t +Cnx8ZGFycGEubWlsCnx8ZGF3YW5naWRjLmNvbQp8fGRlZXplci5jb20KfHxkZXNp +cHJvLmRlCnx8ZGlzY29yZC5jb20KfHxkaXNjb3JkLmdnCnx8ZGlzY29yZGFwcC5j +b20KfHxkaXNjb3JkYXBwLm5ldAp8fGRpc2guY29tCnxodHRwOi8vaW1nLmRsc2l0 +ZS5qcC8KfHxkbTUzMC5uZXQKfHxkbWh5Lm9yZwp8fGRtbS5jby5qcAp8aHR0cDov +L3d3dy5kbW0uY29tL25ldGdhbWUKfHxkbnZvZC50dgp8fGR1Ym94LmNvbQp8fGR2 +ZHBhYy5jb20KfHxlZXN0aS5lZQp8fGVzdXJhbmNlLmNvbQouZXhwZWt0LmNvbQp8 +fGV4cGVrdC5jb20KLmV4dG1hdHJpeC5jb20KfHxleHRtYXRyaXguY29tCnx8ZmFr +a3UubmV0Cnx8ZmFzdHBpYy5ydQp8fGZpbGVzb3IuY29tCnx8ZmluYW5jZXR3aXR0 +ZXIuY29tCnx8ZmxpcGJvYXJkLmNvbQp8fGZsaXR0by5jb20KfHxmbmFjLmJlCnx8 +Zm5hYy5jb20KfHxmdW5reWltZy5jb20KfHxmeG5ldHdvcmtzLmNvbQp8fGctYXJl +YS5vcmcKfHxnZXR0eWltYWdlcy4qCkBAfHxnZXR0eWltYWdlcy5jb20KQEB8fGdl +dHR5aW1hZ2VzLmNuCnx8Z2V0dXBsb2FkZXIuY29tCnx8Z2hpZHJhLXNyZS5vcmcK +IS0tfGh0dHBzOi8vZ2l0aHViLmNvbS9wcm9ncmFtdGhpbmsvemhhbwohLS18aHR0 +cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Byb2dyYW10aGluay96aGFv +Cnx8Z2xhc3M4LmV1Cnx8Z2x5cGUuY29tCnx8Z28xNDEuY29tCnx8aGF1dGVsb29r +LmNvbQp8fGhhdXRlbG9va2Nkbi5jb20KfHx3ZWdvLmhlcmUuY29tCnx8Z3Jvay5j +b20KfHxobW9lZ2lybC5jb20KfHxobXZkaWdpdGFsLmNhCnx8aG12ZGlnaXRhbC5j +b20KfHxob21lZGVwb3QuY29tCnx8aG9vdmVycy5jb20KfHxodWx1LmNvbQp8fGh1 +bHVpbS5jb20KfGh0dHA6Ly9zZWN1cmUuaHVzdGxlci5jb20KfGh0dHA6Ly9odXN0 +bGVyY2FzaC5jb20KfGh0dHA6Ly93d3cuaHVzdGxlcmNhc2guY29tCnx8aHlicmlk +LWFuYWx5c2lzLmNvbQp8fGNkbiouaS1zY21wLmNvbQp8fGlsYmUuY29tCnx8aWxv +dmVsb25ndG9lcy5jb20KfGh0dHA6Ly9pbWdtZWdhLmNvbS8qLmdpZi5odG1sCnxo +dHRwOi8vaW1nbWVnYS5jb20vKi5qcGcuaHRtbAp8aHR0cDovL2ltZ21lZ2EuY29t +LyouanBlZy5odG1sCnxodHRwOi8vaW1nbWVnYS5jb20vKi5wbmcuaHRtbAp8fGlt +bGl2ZS5jbwp8fGphdmh1Yi5uZXQKfHxqYXZodWdlLmNvbQouamF2bGlicmFyeS5j +b20KfHxqYXZsaWJyYXJ5LmNvbQp8fGpjcGVubmV5LmNvbQp8fGppbXMubmV0Cnx8 +dHYuanRiYy5qb2lucy5jb20KfHxqdWt1am8tY2x1Yi5jb20KfHxqdWxpZXBvc3Qu +Y29tCnx8a2F3YWlpa2F3YWlpLmpwCnx8a2VuZGF0aXJlLmNvbQp8fGtoYXRyaW1h +emEub3JnCnx8a2tib3guY29tCnx8bGVpc3VyZXByby5jb20KfHxsaWZlbWlsZXMu +Y29tCnx8bGloLmtnCnx8bG9uZ3RvZXMuY29tCnx8bG92ZXR2c2hvdy5jb20KfHxs +cHNnLmNvbQp8fGxyZnouY29tCnxodHRwOi8vd3d3Lm0tc3BvcnQuY28udWsKfHxt +YWNnYW1lc3RvcmUuY29tCnx8bWFkb25uYS1hdi5jb20KfHxtYW5kaWFudC5jb20K +fHxtYW5nYWZveC5jb20KfHxtYW5nYWZveC5tZQp8fG1hbnRhLmNvbQp8fG1hdG9t +ZS1wbHVzLmNvbQp8fG1hdG9tZS1wbHVzLm5ldAp8fG1hdHR3aWxjb3gubmV0Cnx8 +bWV0YXJ0aHVudGVyLmNvbQp8fG1meG1lZGlhLmNvbQp8fG1pcmFoZXplLm9yZwp8 +fG1vamltLmNvbQp8fGtiLm1vbml0b3J3YXJlLmNvbQp8fG1vbnN0ZXIuY29tCnx8 +bW9vZHl6LmNvbQp8fG1vb25iaW5nby5jb20KfHxtb3MucnUKfHxhZGRvbnMubW96 +aWxsYS5vcmcvKi0qL2ZpcmVmb3gvYWRkb24vdWJsb2NrLW9yaWdpbi8qCnx8YWRk +b25zLm1vemlsbGEub3JnL2ZpcmVmb3gvZG93bmxvYWRzL2ZpbGUvKi91YmxvY2tf +b3JpZ2luLSoueHBpCnx8bXNoYS5nb3YKfHx3d3cubXNuLmNvbQp8fG11enUudHYK +fHxtdmcuanAKLm15YmV0LmNvbQp8fG15YmV0LmNvbQp8fG15cGlrcGFrLmNvbQp8 +fG5hdGlvbndpZGUuY29tCnxodHRwOi8vd3d3Lm5iYy5jb20vbGl2ZQp8fG5lby1t +aXJhY2xlLmNvbQp8fG5ldGZsaXguY29tCnx8bmV0ZmxpeC5uZXQKfHxuZmx4aW1n +LmNvbQp8fG5mbHhpbWcubmV0Cnx8bmZseGV4dC5jb20KfHxuZmx4c28ubmV0Cnx8 +bmZseHZpZGVvLm5ldAp8fG5pYy5nb3YKfGh0dHA6Ly9tby5uaWdodGxpZmUxNDEu +Y29tCnx8cHVycG9zZS5uaWtlLmNvbQp8fG5veGluZmx1ZW5jZXIuY29tCkBAfHxj +bi5ub3hpbmZsdWVuY2VyLmNvbQp8fG5vcmRzdHJvbS5jb20KfHxub3Jkc3Ryb21p +bWFnZS5jb20KfHxub3Jkc3Ryb21yYWNrLmNvbQp8fG5vdHRpbmdoYW1wb3N0LmNv +bQp8fG5wc2Jvb3N0LmNvbQp8fG50ZHR2LmN6Cnx8bnVzYXRyaXAuY29tCnx8bnV1 +dmVtLmNvbQp8fGJicy5ueWluZm9yLmNvbQp8fG9sZWhkdHYuY29tCnx8b21uaTcu +anAKfHxvbmFwcC5jb20KIS0tV2UgYXJlIGNvbmZ1c2VkIGFzIHdlbGwKfHxvbnRy +YWMuY29tCkBAfGh0dHA6Ly9ibG9nLm9udHJhYy5jb20KfHxvcGVuYWkuY29tCnx8 +cGFuZG9yYS5jb20KLnBhbmRvcmEudHYKfHxwYXJrYW5za3kuY29tCnx8cGhtc29j +aWV0eS5vcmcKfGh0dHA6Ly8qLnBpbWcudHcvCnx8cG9kY2FzdC5jbwp8fHBvcGFp +LnBybwp8fHByaW1ldmlkZW8uY29tCnx8cHJveWVjdG9jbHViZXMuY29tCnx8cHVy +ZTE4LmNvbQp8fHB5dG9yY2gub3JnCnx8cXEuY28uemEKfHxyMTguY29tCnxodHRw +Oi8vcmFkaWtvLmpwCnx8cmFtY2l0eS5jb20uYXUKfHxyYXRleW91cm11c2ljLmNv +bQp8fHJkLmNvbQp8aHR0cHM6Ly9yaXNldXAubmV0Cnx8c2FkaXN0aWMtdi5jb20K +fHxpc2Muc2Fucy5lZHUKfGh0dHA6Ly9jZG4qLnNlYXJjaC54eHgvCnx8c2hpa3No +YS5jb20KfHxzbGFja2VyLmNvbQp8fHNtLW1pcmFjbGUuY29tCnx8c295bGVudG5l +d3Mub3JnCnx8c3BvdGlmeS5jb20KfHxzcHJlYWRzaGlydC5lcwp8fHNwcmluZ2Jv +YXJkcGxhdGZvcm0uY29tCnx8c3ByaXRlLm9yZwpAQHxodHRwOi8vc3RvcmUuc3By +aXRlLm9yZwp8fHN1cGVycGFnZXMuY29tCnx8c3dhZ2J1Y2tzLmNvbQp8fHN3aXRj +aDEuanAKfHx0YXBhbndhcC5jb20KfHxnc3AudGFyZ2V0LmNvbQp8fGxvZ2luLnRh +cmdldC5jb20KIS0tQEB8fGludGwudGFyZ2V0LmNvbQp8fHJjYW0udGFyZ2V0LmNv +bQp8fHRlY2huZXdzLnR3Cnx8dGVyYWJveC5jb20KfHx0aGlua2dlZWsuY29tCnx8 +dGhlYm9keXNob3AtdXNhLmNvbQp8fHRtYS5jby5qcAp8fHRyYWNmb25lLmNvbQp8 +fHRyeWhlYXJ0LmpwCnx8dHVybnRhYmxlLmZtCnx8dHdlcmtpbmdidXR0LmNvbQp8 +fHVsb3AubmV0Cnx8dXVrYW5zaHUuY29tCnx8dmVnYXNyZWQuY29tCnx8dmV2by5j +b20KfHx2aXAtZW50ZXJwcmlzZS5jb20KfGh0dHA6Ly92aXUudHYvY2gvCnxodHRw +Oi8vdml1LnR2L2VuY29yZS8KfHx2bXBzb2Z0LmNvbQp8fHdhbnotZmFjdG9yeS5j +b20KfHxzc2wud2VicGFjay5kZQp8fHdlZWJseS5jb20KfHx3aGVyZXRvd2F0Y2gu +Y29tCnx8d2luZ2FtZXN0b3JlLmNvbQp8fHdpemNyYWZ0cy5uZXQKfHx3b3doZWFk +LmNvbQp8fHZvZC53d2UuY29tCnx8eGZpbml0eS5jb20KfHx4aWFvbWkuZXUKfHx5 +b3V3aW4uY29tCnx8eXRuLmNvLmtyCnx8emFtaW1nLmNvbQp8fHphdHRvby5jb20K +fHx6aW0udm4KfHx6b3pvdG93bi5jb20KCiEjIyMjIyMjIyMjIyMjI0dlbmVyYWwg +TGlzdCBTdGFydCMjIyMjIyMjIyMjIyMjIwohLS0tLS0tLS0tLS0tLS0tLS0tLUNv +aW4gUG9vbC0tLS0tLS0tLS0tLS0tLS0tLS0KfHxjM3Bvb2wuY29tCnx8dW5taW5l +YWJsZS5jb20KfHw2NjZwb29sLmNuCnx8YW50cG9vbC5jb20KfHxjcmF6eXBvb2wu +b3JnCnx8Y3J1eHBvb2wuY29tCnx8bWluaW5ncG9vbGh1Yi5jb20KfHxodW9iaXBv +b2wuY29tCnx8cG9vbGJpbmFuY2UuY29tCnx8aGl2ZW9uLm5ldAp8fHNwYXJrcG9v +bC5jb20KfHxmbHlwb29sLm9yZwp8fG5hbm9wb29sLm9yZwp8fHhucG9vbC5jb20K +fHxiZWVwb29sLmNvbQp8fHpoaXpodS50b3AKfHxzcGlkZXJwb29sLmNvbQp8fHV1 +cG9vbC5jbgp8fGZsZXhwb29sLmlvCnx8YmVlcG9vbC5vcmcKfHxkcG9vbC50b3AK +fHxva3Bvb2wubWUKfHxiaW5hbmNlemguY2MKfHxidGMuY29tCnx8ci1wb29sLm5l +dAp8fHctcG9vbC5jb20KCiEtLS0tLS0tLS0tLS0tLS0tLS0tUHVyZSBJUC0tLS0t +LS0tLS0tLS0tLS0tLS0tLQoxNC4xMDIuMjUwLjE4CjE0LjEwMi4yNTAuMTkKNTAu +Ny4zMS4yMzA6ODg5OAoxNzQuMTQyLjEwNS4xNTMKNjkuNjUuMTkuMTYwCgohLS0t +LS0tLS0tLS0tLS0tLS0tLS0tLUlETi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KfHx4 +bi0tMTF4czg2Zi5pY3UKfHx4bi0tNGdxMTcxcC5jb20KfHx4bi0tY3pxNzVwdnYx +YWo1Yy5vcmcKfHx4bi0taTJydThxMnFnLmNvbQp8fHhuLS1ub3NzNDNpLmNvbQp8 +fHhuLS1vaXEuY2MKfHx4bi0tcDhqOWEwZDljOWEueG4tLXE5anliNGMKfHx4bi0t +OXByNjJyMjRhLmNvbQpAQC9eaHR0cHM/OlwvXC8oPz0uKj8oMngzfG5pNXxqNW8p +KVthLXowLTkuLV0rXC54bi0tbmdzdHItbHJhOGpcLmNvbSQKfHx4bi0tbmdzdHIt +bHJhOGouY29tCgohLS0tLS0tLS0tLS0tLS0tLS1ETlMgUG9pc29uaW5nLS0tLS0t +LS0tLS0tLS0tLS0KIS0tLUFtYXpvbi0tLQohLXx8Y2RuLWltYWdlcy5tYWlsY2hp +bXAuY29tCnx8YWJlYm9va3MuY29tCnxodHRwczovLyouczMuYW1hem9uYXdzLmNv +bQoKfHw5Y2FjaGUuY29tCnx8OWdhZy5jb20KfHxhZ3JvLmhrCnx8c2hhcmUuYW1l +cmljYS5nb3YKfHxhcGttaXJyb3IuY29tCnx8YXJ0ZS50dgp8fGFydHN0YXRpb24u +Y29tCnx8YmFuZ2RyZWFtLnNwYWNlCnx8YmVoYW5jZS5uZXQKfHxiaXJkLnNvCnx8 +Yml0dGVyd2ludGVyLm9yZwp8fGJubi5jbwp8fGJ1c2luZXNzaW5zaWRlci5jb20K +fHxid2d5aHcuY29tCnx8Y2FzdGJveC5mbQp8fGNseXAuaXQKfHxjbWNuLm9yZwp8 +fGNteC5pbQp8fGRhaWx5dmlldy50dwp8fGRhdW0ubmV0Cnx8ZGVwb3NpdHBob3Rv +cy5jb20KfHxkaXNjb25uZWN0Lm1lCnx8ZG9jdW1lbnRpbmdyZWFsaXR5LmNvbQp8 +fGRvdWJpYmFja3VwLmNvbQp8fGVuY3ljbG9wZWRpYS5jb20KfHxmYW5nZXFpYW5n +LmNvbQp8fGZhbnFpYW5nZGFuZy5jb20KfHxmZWVkeC5uZXQKfHxmbHl6eTIwMDUu +Y29tCnx8Zm9yZWlnbnBvbGljeS5jb20KfHxmcmVlLXNzLnNpdGUKfHxmcmVlaG9u +Z2tvbmcub3JnCnx8YmxvZy5mdWNrZ2Z3MjMzLm9yZwp8fGcwdi5zb2NpYWwKfHxn +bG9iYWx2b2ljZXMub3JnCnx8Z2xvcnlzdGFyLm1lCnx8Z29yZWdyaXNoLmNvbQp8 +fGhhbmltZS50dgp8fGhiby5jb20KfHxzcGFjZXMuaGlnaHRhaWwuY29tCnx8aGtn +YWxkZW4uY29tCnx8aGtnb2xkZW4uY29tCnx8aHVkc29uLm9yZwp8fGlwZnMuaW8K +fHxqYXBhbnRpbWVzLmNvLmpwCnx8amlqaS5jb20KfHxqaW50aWFuLm5ldAp8fGpp +bnguY29tCnx8am9pbm1hc3RvZG9uLm9yZwp8fGxpYW5nemhpY2h1YW5tZWkuY29t +Cnx8bGlnaHRpLm1lCnx8bGlnaHR5ZWFydnBuLmNvbQp8fGxpaGtnLmNvbQp8fGxp +bmUtc2Nkbi5uZXQKfHxpLmxpdGhpdW0uY29tCnx8Y2xvdWQubWFpbC5ydQp8fGNk +bi1pbWFnZXMubWFpbGNoaW1wLmNvbQp8fG1hc3RvZG9uLmNsb3VkCnx8bWFzdG9k +b24uaG9zdAp8fG1hc3RvZG9uLnNvY2lhbAp8fG1hc3RvZG9uLnh5egp8fG1hdHRl +cnMubmV3cwp8fG1lLm1lCnx8bWV0YXJ0LmNvbQp8fG1vaHUuY2x1Ygp8fG1zYS1p +dC5vcmcKfHxnb28ubmUuanAKfHxuaWtrZWkuY29tCnx8bml0dGVyLmNjCnx8bml0 +dGVyLm5ldAp8fG5pdS5tb2UKfHxub3cuY29tCnx8b3BlbnZwbi5vcmcKfHxvbmVq +YXYuY29tCnx8cGFzdGUuZWUKfHxteS5wY2xvdWQuY29tCnx8cGljYWNvbWljLmNv +bQp8fHBpbmNvbmcucm9ja3MKfHxwaXhpdi5uZXQKfHxwaXhpdi5vcmcKfHxwaXhp +dnNrZXRjaC5uZXQKfHxwb3RhdG8uaW0KfHxwcmVtcHJveHkuY29tCnx8cHJpc20t +YnJlYWsub3JnCnx8cHJvdG9uLm1lCnx8cHJvdG9udnBuLmNvbQp8fGFwaS5wdXJl +YXBrLmNvbQp8fHF1b3JhLmNvbQp8fHF1b3JhY2RuLm5ldAp8fHF6LmNvbQp8fGNk +bi5zZWF0Z3VydS5jb20KfHxyZWRkLml0Cnx8cmVkZGl0c3BhY2UuY29tCnx8cmVk +ZGl0LmNvbQp8fHJlZGRpdGhlbHAuY29tCi5yZWRkaXRsaXN0LmNvbQp8aHR0cDov +L3JlZGRpdGxpc3QuY29tCnx8cmVkZGl0bWVkaWEuY29tCnx8cmVkZGl0c3RhdGlj +LmNvbQohLS1kZWZ1bmN0Cnx8cml4Y2xvdWQuY29tCnx8cml4Y2xvdWQudXMKfHxy +c2RsbW9uaXRvci5jb20KfHxzaGFkb3dzb2Nrcy5iZQp8fHRuMS5zaGVtYWxlei5j +b20KfHx0bjIuc2hlbWFsZXouY29tCnx8dG4zLnNoZW1hbGV6LmNvbQp8fHN0YXRp +Yy5zaGVtYWxlei5jb20KfHxzaXgtZGVncmVlcy5pbwp8fHNvZnRmYW1vdXMuY29t +Cnx8c29zcmVhZGVyLmNvbQp8fHNzcGFuZWwubmV0Cnx8c3VwY2hpbmEuY29tCnx8 +dGVkZHlzdW4uY29tCnx8dGV4dG5vdy5tZQp8fHRpbmV5ZS5jb20KfHx0b3AxMHZw +bi5jb20KfHx0dWJlcG9ybmNsYXNzaWMuY29tCnx8dWt1LmltCnx8dW5zZWVuLmlz +Cnx8Y24udXB0b2Rvd24uY29tCnx8dXJhYmFuLm1lCnx8dnJzbWFzaC5jb20KfHx2 +dWx0cnlody5jb20KfHxzY2FjaGUudnp3LmNvbQp8fHNjYWNoZTEudnp3LmNvbQp8 +fHNjYWNoZTIudnp3LmNvbQp8fHNzNy52encuY29tCnx8c3NyLnRvb2xzCnx8c3Rl +ZW1pdC5jb20KfHx0YWl3YW5qdXN0aWNlLm5ldAp8fHRpbmMtdnBuLm9yZwp8fHUx +NS5pbmZvCnx8d2FzaGluZ3RvbnBvc3QuY29tCnx8d2Vuemhhby5jYQp8fHdoYXRz +b253ZWliby5jb20KfHx3aXJlLmNvbQp8fHhtLmNvbQp8fHh1ZWh1YS51cwp8fHll +cy1uZXdzLmNvbQp8fHlpZ2VuaS5jb20KfHx5b3UtZ2V0Lm9yZwp8fHp6Y2xvdWQu +bWUKCiEtLS1EaWdpdGFsIEN1cnJlbmN5IEV4Y2hhbmdlKENSWVBUTyktLS0KfHxh +ZXguY29tCnx8YWxsY29pbi5jb20KfHxhZGNleC5jb20KfHxiY2V4LmNhCnx8Ymli +b3guY29tCnx8YmlnLm9uZQp8fGJpZ29uZS5jb20KfHxiaW5hbmNlLmNvbQp8fGJp +dC16LmNvbQp8fGJpdHouYWkKfHxiaXRiYXkubmV0Cnx8Yml0Y29pbndvcmxkLmNv +bQp8fGJpdGZpbmV4LmNvbQp8fGJpdGh1bWIuY29tCnx8Yml0bWV4LmNvbQp8fGJu +YnN0YXRpYy5jb20KfHxidGM5OC5jb20KfHxidGNiYW5rLmJhbmsKfHxidGN0cmFk +ZS5pbQp8fGJ5Yml0LmNvbQp8fGMyY3guY29tCnx8Y2hhb2V4LmNvbQp8fGNvYmlu +aG9vZC5jb20KfHxjb2luYmFzZS5jb20KfHxjb2luYmVuZS5jb20KfHxjb2luZXgu +Y29tCiEtLXxodHRwczovL3d3dy5jb2luZXhjaGFuZ2UuaW8vCnx8Y29pbmdlY2tv +LmNvbQp8fGNvaW5naS5jb20KfHxjb2lubWFya2V0Y2FwLmNvbQp8fGNvaW5yYWls +LmNvLmtyCnx8Y29pbnRpZ2VyLmNvbQp8fGNvaW50b2JlLmNvbQp8fGNvaW51dC5j +b20KfHxkaXNjb2lucy5jb20KfHxkcmFnb25leC5pbwp8fGVidGNiYW5rLmNvbQp8 +fGV0aGVyZGVsdGEuY29tCnx8ZXRoZXJtaW5lLm9yZwp8fGV0aGVyc2Nhbi5pbwp8 +fGV4bW8uY29tCnx8ZXhyYXRlcy5tZQp8fGYycG9vbC5jb20KfHxmYXRidGMuY29t +Cnx8ZnR4LmNvbQp8fGdhdGUuaW8KfHxnYXRlY29pbi5jb20KfHxoYmcuY29tCnx8 +aGl0YnRjLmNvbQp8fGhvdGNvaW4uY29tCnx8aHVvYmkuY28KfHxodW9iaS5jb20K +fHxodW9iaS5tZQohLS18fGh1b2JpLmxpCnx8aHVvYmkucHJvCnx8aHVvYmkuc2MK +fHxodW9iaXByby5jb20KfHxieC5pbi50aAp8fGpleC5jb20KfHxrZXguY29tCnx8 +a3Jha2VuLmNvbQp8fGtzcGNvaW4uY29tCnx8a3Vjb2luLmNvbQp8fGxiYW5rLmlu +Zm8KfHxsaXF1aWRpdHl0cC5jb20KfHxsaXZlY29pbi5uZXQKfHxsb2NhbGJpdGNv +aW5zLmNvbQp8fG1lcmNhdG94LmNvbQp8fG9hbmRhLmNvbQp8fG9ieXRlLm9yZwp8 +fG9leC5jb20KfHxva2V4LmNvbQp8fG9reC5jb20KfHxvcGVuc2VhLmlvCnx8b3Rj +YnRjLmNvbQp8fHBheGZ1bC5jb20KfHxwb29saW4uY29tCnx8c2ltcGxlc3dhcC5p +bwp8fHNvbHYuZmluYW5jZQp8fHRvcGJ0Yy5jb20KfHx0cm9uc2Nhbi5vcmcKfHx4 +YnRjZS5jb20KfHx5b2JpdC5uZXQKfHx6Yi5jb20KCiEtLS0tLS0tLS0tLS0tLS0t +RnJhdWRzICYgU2NhbXMtLS0tLS0tLS0tLS0tLS0tLQohIS0tLUNvbnRlbnQgRmFy +bShmYWtlIDUwMCBlcnJvciktLS0KfHxyZWFkMDEuY29tCnx8a2tuZXdzLmNjCgpj +aGluYS1tbW0uanAubmV0Ci5sc3hzenpnLmNvbQouY2hpbmEtbW1tLm5ldAp8fGNo +aW5hLW1tbS5uZXQKCiEtLS0tLS0tLS0tLS0tLS0tLS0tLS1Hcm91cHMtLS0tLS0t +LS0tLS0tLS0tLS0tLQohIS0tLU1hc3RlcmRvbi0tLQp8fGJnbWUubWUKfHxvM28u +Y2EKfHxnbzUuZGV2Cnx8bWUubnMuY2kKfHxtb3Jlc2NpLnNhbGUKfHxzb2NpYWwu +ZWR1LmNpCnx8bXN0ZG4uc29jaWFsCnx8ZG91Y2hpLnNwYWNlCnx8c2xhc2hpbmUu +b25sCnx8c29jaWFsLmRhdGFsYWJvdXIuY29tCnx8bWFzdG9kb24ub25saW5lCgoh +IS0tLUFmcmFpZCBGcmVlRE5TLS0tCi5hbGxvd2VkLm9yZwoubm93LmltCgohIS0t +LUFtYXpvbi0tLQp8fHBheW1lbnRzLWpwLmFtYXpvbi5jb20KfHxhbWF6b24uY28u +anAKfHxzMy1hcC0qLmFtYXpvbmF3cy5jb20KfHxzMy5ldS1jZW50cmFsLTEuYW1h +em9uYXdzLmNvbQp8fHMzLWV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tCnx8czMu +dXMtZWFzdC0xLmFtYXpvbmF3cy5jb20KfHxzMy1hcC1ub3J0aGVhc3QtMi5hbWF6 +b25hd3MuY29tCnx8czMuYXAtbm9ydGhlYXN0LTIuYW1hem9uYXdzLmNvbQp8fHMz +LWFwLW5vcnRoZWFzdC0xLmFtYXpvbmF3cy5jb20KfHxzMy1hcC1zb3V0aGVhc3Qt +MS5hbWF6b25hd3MuY29tCnx8czMtYXAtc291dGhlYXN0LTIuYW1hem9uYXdzLmNv +bQoKISEtLS1BT0wtLS0KdmlkZW8uYW9sLmNhL3ZpZGVvLWRldGFpbAp2aWRlby5h +b2wuY28udWsvdmlkZW8tZGV0YWlsCnZpZGVvLmFvbC5jb20KfHx2aWRlby5hb2wu +Y29tCnx8c2VhcmNoLmFvbC5jb20Kd3d3LmFvbG5ld3MuY29tCgohIS0tLUF2TW9v +LS0tCi5hdm1vLnB3CiEtLXxodHRwOi8vYXZtby5wdwouYXZtb28uY29tCnxodHRw +Oi8vYXZtb28uY29tCi5hdm1vby5uZXQKfGh0dHA6Ly9hdm1vby5uZXQKfHxhdm1v +by5wdwouamF2bW9vLnh5egp8aHR0cDovL2phdm1vby54eXoKLmphdnRhZy5jb20K +fGh0dHA6Ly9qYXZ0YWcuY29tCi5qYXZ6b28uY29tCnxodHRwOi8vamF2em9vLmNv +bQoudGVsbG1lLnB3CgohIS0tLUJCQy0tLQohLS0uYmJjLmNvLnVrL2Jsb2dzCiEt +LS5iYmMuY28udWsvY2hpbmVzZQohLS0uYmJjLmNvLnVrL25ld3Mvd29ybGQtYXNp +YS1jaGluYQohLS0uYmJjLmNvLnVrL3R2CiEtLS5iYmMuY28udWsvemhvbmd3ZW4K +IS0tLmJiYy5jb20vdWtjaGluYQohLS0uYmJjLmNvbS96aG9uZ3dlbgohLS0uYmJj +LmNvbSUyRnpob25nd2VuCiEtLW5ld3MuYmJjLmNvLnVrL29udGhpc2RheSpuZXdz +aWRfMjQ5NjAwMC8yNDk2Mjc3CiEtLW5ld3Nmb3J1bXMuYmJjLmNvLnVrCi5iYmMu +Y29tCnx8YmJjLmNvbQouYmJjLmNvLnVrCnx8YmJjLmNvLnVrCnx8YmJjaS5jby51 +awouYmJjY2hpbmVzZS5jb20KfHxiYmNjaGluZXNlLmNvbQp8aHR0cDovL2JiYy5p +bgoKISEtLS1CbG9vbWJlcmctLS0KLmJsb29tYmVyZy5jbgp8fGJsb29tYmVyZy5j +bgouYmxvb21iZXJnLmNvbQp8fGJsb29tYmVyZy5jb20KYmxvb21iZXJnLmRlCnx8 +Ymxvb21iZXJnLmRlCnx8Ymxvb21iZXJndmlldy5jb20KLmJ1c2luZXNzd2Vlay5j +b20KCiEhLS0tQ2hhbmdlSVAtLS0KLjFkdW1iLmNvbQouMjV1LmNvbQouMndha3ku +Y29tCi4zLWEubmV0Ci40ZHEuY29tCi40bXlkb21haW4uY29tCi40cHUuY29tCi5h +Y21ldG95LmNvbQouYWxtb3N0bXkuY29tCi5hbWVyaWNhbnVuZmluaXNoZWQuY29t +Ci5hdXRob3JpemVkZG5zLm5ldAouYXV0aG9yaXplZGRucy5vcmcKLmJpZ21vbmV5 +LmJpegouY2hhbmdlaXAubmFtZQouY2hhbmdlaXAubmV0Ci5jaGFuZ2VpcC5vcmcK +LmNsZWFuc2l0ZS5iaXoKLmNsZWFuc2l0ZS5pbmZvCi5jbGVhbnNpdGUudXMKLmNv +bXByZXNzLnRvCi5kZG5zLmluZm8KLmRkbnMubWUudWsKLmRkbnMubW9iaQouZGRu +cy5tcwouZGRucy5uYW1lCi5kZG5zLnVzCi5kbnMtZG5zLmNvbQouZG5zLXN0dWZm +LmNvbQouZG5zMDQuY29tCi5kbnMwNS5jb20KLmRuczEudXMKLmRuczIudXMKLmRu +c2V0LmNvbQouZG5zcmQuY29tCi5kc210cC5jb20KLmR1bWIxLmNvbQouZHluYW1p +Yy1kbnMubmV0Ci5keW5hbWljZG5zLmJpegouZHluYW1pY2Rucy5jby51awouZHlu +YW1pY2Rucy5tZS51awouZHluYW1pY2Rucy5vcmcudWsKLmR5bmRucy5wcm8KLmR5 +bnNzbC5jb20KLmVwYWMudG8KLmVzbXRwLmJpegouZXp1YS5jb20KLmZhcXNlcnYu +Y29tCi5mYXJ0aXQuY29tCi5mcmVlZGRucy5jb20KLmZyZWV0Y3AuY29tCi5mcmVl +d3d3LmluZm8KLmZ0cDEuYml6Ci5mdHBzZXJ2ZXIuYml6Ci5nZXR0cmlhbHMuY29t +Ci5nb3QtZ2FtZS5vcmcKLmdyOGRvbWFpbi5iaXoKLmdyOG5hbWUuYml6Ci5odHRw +czQ0My5uZXQKLmh0dHBzNDQzLm9yZwouaWt3Yi5jb20KLmluc3RhbnRocS5jb20K +Lmlvd255b3VyLm9yZwouaXNhc2VjcmV0LmNvbQouaXRlbWRiLmNvbQouaXRzYW9s +LmNvbQouamV0b3MuY29tCi5qa3ViLmNvbQouanVuZ2xlaGVhcnQuY29tCi5qdXN0 +ZGllZC5jb20KLmxmbGluay5jb20KLmxmbGlua3VwLmNvbQoubGZsaW5rdXAubmV0 +Ci5sZmxpbmt1cC5vcmcKLmxvbmdtdXNpYy5jb20KLm1lZm91bmQuY29tCi5tb25l +eWhvbWUuYml6Ci5tcmJhc2ljLmNvbQoubXJib251cy5jb20KLm1yZmFjZS5jb20K +Lm1yc2xvdmUuY29tCi5teTAzLmNvbQoubXlkYWQuaW5mbwoubXlkZG5zLmNvbQou +bXlmdHAuaW5mbwoubXlsZnR2LmNvbQoubXltb20uaW5mbwoubXluZXRhdi5uZXQK +Lm15bmV0YXYub3JnCi5teW51bWJlci5vcmcKLm15cGljdHVyZS5pbmZvCi5teXBv +cDMubmV0Ci5teXBvcDMub3JnCi5teXNlY29uZGFyeWRucy5jb20KLm15d3d3LmJp +egoubXl6LmluZm8KLm5zMDEuYml6Ci5uczAxLmluZm8KLm5zMDEudXMKLm5zMDIu +Yml6Ci5uczAyLmluZm8KLm5zMDIudXMKLm5zMS5uYW1lCi5uczIubmFtZQoubnMz +Lm5hbWUKLm9jcnkuY29tCi5vbmVkdW1iLmNvbQoub25teXBjLmJpegoub25teXBj +LmluZm8KLm9ubXlwYy5uZXQKLm9ubXlwYy5vcmcKLm9yZ2FuaWNjcmFwLmNvbQou +b3R6by5jb20KLm91cmhvYmJ5LmNvbQoucGNhbnl3aGVyZS5uZXQKLnBvcnQyNS5i +aXoKLnByb3h5ZG5zLmNvbQoucWhpZ2guY29tCi5xcG9lLmNvbQoucmViYXRlc3J1 +bGUubmV0Ci5zZWxsY2xhc3NpY3MuY29tCi5zZW5kc210cC5jb20KLnNlcnZldXNl +ci5jb20KLnNlcnZldXNlcnMuY29tCi5zZXhpZHVkZS5jb20KLnNxdWlybHkuaW5m +bwouc3NsNDQzLm9yZwoudG9oLmluZm8KLnRveXRoaWV2ZXMuY29tCi50cmlja2lw +Lm5ldAoudml6dmF6LmNvbQoud2lrYWJhLmNvbQoud3d3MS5iaXoKLnd3d2hvc3Qu +Yml6CkBAfGh0dHA6Ly94eC53d3dob3N0LmJpegoueDI0aHIuY29tCi54eHV6LmNv +bQoueHh4eS5pbmZvCi55Z3RvLmNvbQoueW91ZG9udGNhcmUuY29tCi55b3VydHJh +cC5jb20KLnp5bnMuY29tCi56enV4LmNvbQoKISEtLUNsb3VkZmxhcmUtLQohLS18 +fHBhZ2VzLmRldgp8fHdvcmtlcnMuZGV2Cnx8b25lLm9uZS5vbmUub25lCnx8Y2xv +dWRmbGFyZS1kbnMuY29tCgohIS0tLUR0RE5TLS0tCiEjIyNodHRwczovL3d3dy5k +dGRucy5jb20vZHRzaXRlL2ZhcQouM2QtZ2FtZS5jb20KLjRpcmMuY29tCi5iMG5l +LmNvbQouY2hhdG5vb2suY29tCi5kYXJrdGVjaC5vcmcKLmRlYWZ0b25lLmNvbQou +ZWZmZXJzLmNvbQouZXRvd25zLm5ldAouZXRvd25zLm9yZwouZmxuZXQub3JnCi5n +b3RnZWVrcy5jb20KLnNjaWVyb24uY29tCi5zbHlpcC5jb20KLnNseWlwLm5ldAou +c3Vyb290LmNvbQoKISEtLS1EeW5ETlMtLS0KISMjI2h0dHBzOi8vaGVscC5keW4u +Y29tL2xpc3Qtb2YtZHluLWRucy1wcm8tcmVtb3RlLWFjY2Vzcy1kb21haW4tbmFt +ZXMvCi5ibG9nZG5zLm9yZwouZHluZG5zLm9yZwouZHluZG5zLWlwLmNvbQouZHlu +ZG5zLXBpY3MuY29tCi5mcm9tLXNkLmNvbQouZnJvbS1wci5jb20KLmlzLWEtaHVu +dGVyLmNvbQoKISEtLS1EeW51LS0tCi5keW51LmNvbQp8fGR5bnUuY29tCi5keW51 +Lm5ldAouZnJlZWRkbnMub3JnCgohIS0tLUZhY2Vib29rLS0tCnx8YWNjb3VudGtp +dC5jb20KfHxjZG5pbnN0YWdyYW0uY29tCnx8ZjguY29tCi5mYWNlYm9vay5jb20K +fHxmYWNlYm9vay5jb20KIS0tL15odHRwcz86XC9cL1teXC9dK2ZhY2Vib29rXC5j +b20vCkBAfHx2Ni5mYWNlYm9vay5jb20KfHxmYWNlYm9vay5kZQp8fGZhY2Vib29r +LmRlc2lnbgp8fGNvbm5lY3QuZmFjZWJvb2submV0Cnx8ZmFjZWJvb2suaHUKfHxm +YWNlYm9vay5pbgp8fGZhY2Vib29rLm5sCnx8ZmFjZWJvb2suc2UKfHxmYWNlYm9v +a21haWwuY29tCnx8ZmIuY29tCnx8ZmIubWUKfHxmYi53YXRjaAp8fGZiY2RuLm5l +dAp8fGZic2J4LmNvbQp8fGZiYWRkaW5zLmNvbQp8fGZid29ya21haWwuY29tCi5p +bnN0YWdyYW0uY29tCnx8aW5zdGFncmFtLmNvbQp8fG0ubWUKfHxtZXNzZW5nZXIu +Y29tCnx8bWV0YS5jb20KfHxvY3VsdXMuY29tCnx8b2N1bHVzY2RuLmNvbQp8fHJv +Y2tzZGIub3JnCkBAfHxpcDYuc3RhdGljLnNsLXJldmVyc2UuY29tCnx8cGFyc2Uu +Y29tCnx8dGhlZmFjZWJvb2suY29tCnx8dGhyZWFkcy5uZXQKfHx3aGF0c2FwcC5j +b20KfHx3aGF0c2FwcC5uZXQKCiEhLS0tRmFuZG9tLS0tCnx8YXVudG9sb2d5LmZh +bmRvbS5jb20KfHxob25na29uZy5mYW5kb20uY29tCgohIS0tLUZUQ2hpbmVzZS0t +LQouZnRjaGluZXNlLmNvbQp8fGZ0Y2hpbmVzZS5jb20KCiEhLS0tR29vZ2xlLS0t +Cnx8Z2xlCnx8Z29vZ2xlCnx8ZG9jLm5ldwp8fGZvcm0ubmV3Cnx8Zm9ybXMubmV3 +Cnx8c2hlZXQubmV3Cnx8c2hlZXRzLm5ldwp8fHNwcmVhZHNoZWV0Lm5ldwp8fHNp +dGUubmV3Cnx8c2l0ZXMubmV3Cnx8d2Vic2l0ZS5uZXcKfHxzbGlkZXMubmV3Cnx8 +ZGVjay5uZXcKfHxwcmVzZW50YXRpb24ubmV3Cnx8Z29vZ2xlYXBpcy5jb20KISMj +I2h0dHBzOi8vd3d3Lmdvb2dsZS5jb20vc3VwcG9ydGVkX2RvbWFpbnMjIyMKIS4u +LkdGV0xpc3QgZG9lc24ndCBpbnRlbmQgdG8gc3VwcG9ydCB0eXBvc3F1YXR0aW5n +Li4uCnx8MWUxMDAubmV0Cnx8NDY2NDUzLmNvbQp8fGFiYy54eXoKfHxhZG1vYi5j +b20KfHxhZHNlbnNlLmNvbQp8fGFkdmVydGlzZXJjb21tdW5pdHkuY29tCnx8YWdv +b2dsZWFkYXkuY29tCnx8YW1wcHJvamVjdC5vcmcKQEB8aHR0cHM6Ly93d3cuYW1w +cHJvamVjdC5vcmcKQEB8aHR0cHM6Ly9jZG4uYW1wcHJvamVjdC5vcmcKfHxhbmRy +b2lkLmNvbQpAQHx8Y2kuYW5kcm9pZC5jb20KfHxhbmRyb2lkaWZ5LmNvbQp8fGFu +ZHJvaWR0di5jb20KfHxhcGkuYWkKLmFwcHNwb3QuY29tCnx8YXBwc3BvdC5jb20K +fHxhdXRvZHJhdy5jb20KfHxibG9nYmxvZy5jb20KYmxvZ3Nwb3QuY29tCi9eaHR0 +cHM/OlwvXC9bXlwvXStibG9nc3BvdFwuKC4qKS8KLmJsb2dzcG90LmhrCi5ibG9n +c3BvdC5qcAouYmxvZ3Nwb3QudHcKfHxidXNpbmVzcy5wYWdlCiEtLXx8Y2FwaXRh +bGcuY29tCnx8Y2VydGlmaWNhdGUtdHJhbnNwYXJlbmN5Lm9yZwp8fGNocm9tZS5j +b20KfHxjaHJvbWVjYXN0LmNvbQp8fGNocm9tZWV4cGVyaW1lbnRzLmNvbQp8fGNo +cm9tZXN0YXR1cy5jb20KfHxjaHJvbWl1bS5vcmcKfHxjbG91ZGZ1bmN0aW9ucy5u +ZXQKfHxjcmJ1Zy5jb20KfHxjcmVhdGl2ZWxhYjUuY29tCnx8Y3JyZXYuY29tCnx8 +ZGF0YS12b2NhYnVsYXJ5Lm9yZwp8fGRlYnVnLmNvbQp8fGRlZXBtaW5kLmNvbQp8 +fGRlamEuY29tCnx8ZGlnaXNmZXJhLmNvbQp8fGRvY2tlci5jb20KfHxkb2NzLm5l +dwp8fGR1Y2suY29tCnx8ZmVlZGJ1cm5lci5jb20KfHxmaXJlYmFzZWlvLmNvbQp8 +fGcuY28KfHxnY3IuaW8KfHxnZXQuYXBwCnx8Z2V0LmRldgp8fGdldC5ob3cKfHxn +ZXQucGFnZQp8fGdldG1kbC5pbwp8fGdldG91dGxpbmUub3JnCnx8Z2dwaHQuY29t +Cnx8Z21haWwuY29tCnx8Z21vZHVsZXMuY29tCnx8Z29kb2Mub3JnCnx8Z29sYW5n +Lm9yZwp8fGdvby5nbAp8fGdvby5nbGUKLmdvb2dsZS5hZQouZ29vZ2xlLmFzCi5n +b29nbGUuYW0KLmdvb2dsZS5hdAouZ29vZ2xlLmF6Ci5nb29nbGUuYmEKLmdvb2ds +ZS5iZQouZ29vZ2xlLmJnCi5nb29nbGUuY2EKLmdvb2dsZS5jZAouZ29vZ2xlLmNp +Ci5nb29nbGUuY28uaWQKLmdvb2dsZS5jby5qcAouZ29vZ2xlLmNvLmtyCi5nb29n +bGUuY28ubWEKLmdvb2dsZS5jby51awouZ29vZ2xlLmNvbQouZ29vZ2xlLmRlCnx8 +Z29vZ2xlLmRldgouZ29vZ2xlLmRqCi5nb29nbGUuZGsKLmdvb2dsZS5lcwouZ29v +Z2xlLmZpCi5nb29nbGUuZm0KLmdvb2dsZS5mcgouZ29vZ2xlLmdnCi5nb29nbGUu +Z2wKLmdvb2dsZS5ncgouZ29vZ2xlLmllCi5nb29nbGUuaXMKLmdvb2dsZS5pdAou +Z29vZ2xlLmpvCi5nb29nbGUua3oKLmdvb2dsZS5sdgouZ29vZ2xlLm1uCi5nb29n +bGUubXMKLmdvb2dsZS5ubAouZ29vZ2xlLm51Ci5nb29nbGUubm8KLmdvb2dsZS5y +bwouZ29vZ2xlLnJ1Ci5nb29nbGUucncKLmdvb2dsZS5zYwouZ29vZ2xlLnNoCi5n +b29nbGUuc2sKLmdvb2dsZS5zbQouZ29vZ2xlLnNuCi5nb29nbGUudGsKLmdvb2ds +ZS50bQouZ29vZ2xlLnRvCi5nb29nbGUudHQKLmdvb2dsZS52dQouZ29vZ2xlLndz +Ci9eaHR0cHM/OlwvXC8oW15cL10rXC4pKmdvb2dsZVwuKGFjfGFkfGFlfGFmfGFp +fGFsfGFtfGFzfGF0fGF6fGJhfGJlfGJmfGJnfGJpfGJqfGJzfGJ0fGJ5fGNhfGNh +dHxjZHxjZnxjZ3xjaHxjaXxjbHxjbXxjby5hb3xjby5id3xjby5ja3xjby5jcnxj +by5pZHxjby5pbHxjby5pbnxjby5qcHxjby5rZXxjby5rcnxjby5sc3xjby5tYXxj +b218Y29tLmFmfGNvbS5hZ3xjb20uYWl8Y29tLmFyfGNvbS5hdXxjb20uYmR8Y29t +LmJofGNvbS5ibnxjb20uYm98Y29tLmJyfGNvbS5ienxjb20uY298Y29tLmN1fGNv +bS5jeXxjb20uZG98Y29tLmVjfGNvbS5lZ3xjb20uZXR8Y29tLmZqfGNvbS5naHxj +b20uZ2l8Y29tLmd0fGNvbS5oa3xjb20uam18Y29tLmtofGNvbS5rd3xjb20ubGJ8 +Y29tLmx5fGNvbS5tbXxjb20ubXR8Y29tLm14fGNvbS5teXxjb20ubmF8Y29tLm5m +fGNvbS5uZ3xjb20ubml8Y29tLm5wfGNvbS5vbXxjb20ucGF8Y29tLnBlfGNvbS5w +Z3xjb20ucGh8Y29tLnBrfGNvbS5wcnxjb20ucHl8Y29tLnFhfGNvbS5zYXxjb20u +c2J8Y29tLnNnfGNvbS5zbHxjb20uc3Z8Y29tLnRqfGNvbS50cnxjb20udHd8Y29t +LnVhfGNvbS51eXxjb20udmN8Y29tLnZufGNvLm16fGNvLm56fGNvLnRofGNvLnR6 +fGNvLnVnfGNvLnVrfGNvLnV6fGNvLnZlfGNvLnZpfGNvLnphfGNvLnptfGNvLnp3 +fGN2fGN6fGRlfGRqfGRrfGRtfGR6fGVlfGVzfGV1fGZpfGZtfGZyfGdhfGdlfGdn +fGdsfGdtfGdwfGdyfGd5fGhrfGhufGhyfGh0fGh1fGllfGltfGlxfGlzfGl0fGl0 +LmFvfGplfGpvfGtnfGtpfGt6fGxhfGxpfGxrfGx0fGx1fGx2fG1kfG1lfG1nfG1r +fG1sfG1ufG1zfG11fG12fG13fG14fG5lfG5sfG5vfG5yfG51fG9yZ3xwbHxwbnxw +c3xwdHxyb3xyc3xydXxyd3xzY3xzZXxzaHxzaXxza3xzbXxzbnxzb3xzcnxzdHx0 +ZHx0Z3x0a3x0bHx0bXx0bnx0b3x0dHx1c3x2Z3x2bnx2dXx3cylcLy4qLwohLS18 +fGdvb2dsZS1hbmFseXRpY3MuY29tCiEtLXx8Z29vZ2xlYWRzZXJ2aWNlcy5jb20K +fHxnb29nbGVhcHBzLmNvbQp8fGdvb2dsZWFydHByb2plY3QuY29tCnx8Z29vZ2xl +YmxvZy5jb20KfHxnb29nbGVib3QuY29tCiEtLXx8Z29vZ2xlY2FwaXRhbC5jb20K +fHxnb29nbGVjaGluYXdlYm1hc3Rlci5jb20KfHxnb29nbGVjb2RlLmNvbQp8fGdv +b2dsZWNvbW1lcmNlLmNvbQp8fGdvb2dsZWRvbWFpbnMuY29tCnx8Z29vZ2xlYXJ0 +aC5jb20KfHxnb29nbGVlYXJ0aC5jb20KfHxnb29nbGVkcml2ZS5jb20KfHxnb29n +bGVmaWJlci5uZXQKfHxnb29nbGVncm91cHMuY29tCnx8Z29vZ2xlaG9zdGVkLmNv +bQp8fGdvb2dsZWlkZWFzLmNvbQp8fGdvb2dsZWluc2lkZXNlYXJjaC5jb20KfHxn +b29nbGVtYWlsLmNvbQp8fGdvb2dsZW1hc2h1cHMuY29tCnx8Z29vZ2xlcGFnZWNy +ZWF0b3IuY29tCnx8Z29vZ2xlcGxheS5jb20KfHxnb29nbGVwbHVzLmNvbQp8fGdv +b2dsZXNjaG9sYXIuY29tCnx8Z29vZ2xlc291cmNlLmNvbQohLS18fGdvb2dsZXN5 +bmRpY2F0aW9uLmNvbQohLS18fGdvb2dsZXRhZ21hbmFnZXIuY29tCiEtLXx8Z29v +Z2xldGFnc2VydmljZXMuY29tCnx8Z29vZ2xldXNlcmNvbnRlbnQuY29tCi5nb29n +bGV2aWRlby5jb20KfHxnb29nbGV2aWRlby5jb20KfHxnb29nbGV3ZWJsaWdodC5j +b20KfHxnb29nbGV6aXAubmV0Cnx8Z3N0YXRpYy5jb20KIS0tfHxndi5jb20KfHxn +dnQxLmNvbQpAQHx8cmVkaXJlY3Rvci5ndnQxLmNvbQp8fGd2dDMuY29tCnx8Z3d0 +cHJvamVjdC5vcmcKfHxodG1sNXJvY2tzLmNvbQp8fGlhbS5zb3kKfHxpZ29vZ2xl +LmNvbQp8fGl0YXNvZnR3YXJlLmNvbQp8fGxpa2UuY29tCnx8bWFkZXdpdGhjb2Rl +LmNvbQp8fG1hdGVyaWFsLmlvCnx8b24yLmNvbQp8fHBhbm9yYW1pby5jb20KfHxw +aWNhc2F3ZWIuY29tCnx8cGtpLmdvb2cKfHxwbHVzLmNvZGVzCnx8cG9seW1lci1w +cm9qZWN0Lm9yZwp8fHF1ZXN0dmlzdWFsLmNvbQp8fGFkbWluLnJlY2FwdGNoYS5u +ZXQKfHxhcGkucmVjYXB0Y2hhLm5ldAp8fGFwaS1zZWN1cmUucmVjYXB0Y2hhLm5l +dAp8fGFwaS12ZXJpZnkucmVjYXB0Y2hhLm5ldAp8fHJlZGhvdGxhYnMuY29tCnx8 +c2F2ZXRoZWRhdGUuZm9vCnx8c2NoZW1hLm9yZwp8fHNoYXR0ZXJlZC5pbwp8aHR0 +cDovL3NpcG1sNS5vcmcvCnx8c2hlZXRzLm5ldwp8fHNsaWRlcy5uZXcKfHxzbmFw +c2VlZC5jb20KfHxzeW5lcmd5c2UuY29tCnx8dGVhY2hwYXJlbnRzdGVjaC5vcmcK +fHx0ZW5zb3JmbG93Lm9yZwp8fHRmaHViLmRldgp8fHRoaW5rd2l0aGdvb2dsZS5j +b20KfHx0aWx0YnJ1c2guY29tCnx8dHJhbnNsYXRlLmdvb2cKfHx1YTV2LmNvbQp8 +fHVyY2hpbi5jb20KfHx1c2VyY29udGVudC5nb29nCiEtLXx8d3d3Lmdvb2dsZQp8 +fHdhdmVwcm90b2NvbC5vcmcKfHx3YXltby5jb20KfHx3ZWIuZGV2Cnx8d2VibXBy +b2plY3Qub3JnCnx8d2VicGtnY2FjaGUuY29tCnx8d2VicnRjLm9yZwp8fHdoYXRi +cm93c2VyLm9yZwp8fHdoYXRzLm5ldwp8fHdpZGV2aW5lLmNvbQp8fHdpdGhnb29n +bGUuY29tCnx8d2l0aHlvdXR1YmUuY29tCnx8eC5jb21wYW55Cnx8eG4tLW5nc3Ry +LWxyYThqLmNvbQp8fHlvdXR1LmJlCi55b3V0dWJlLmNvbQp8fHlvdXR1YmUuY29t +Cnx8eW91dHViZS1ub2Nvb2tpZS5jb20KfHx5b3V0dWJlZWR1Y2F0aW9uLmNvbQp8 +fHlvdXR1YmVnYW1pbmcuY29tCnx8eW91dHViZWtpZHMuY29tCnx8eXQuYmUKfHx5 +dGltZy5jb20KfHx6eW5hbWljcy5jb20KCiEhLS0tS2lja0FTUy0tLQohLS1PRkZJ +Q0lBTCBVUkwgbGlzdCBhdDogaHR0cHM6Ly9rYXN0YXR1cy5jb20KCiEhLS0tTWlj +cm9zb2Z0LS0tCiEtLUBAfHxiaW5nLmNvbQp8fGNvcGlsb3QubWljcm9zb2Z0LmNv +bQoKISEtLS1OYXVnaHR5QW1lcmljYS0tLQp8fG5hdWdodHlhbWVyaWNhLmNvbQoK +ISEtLS1OWVRpbWVzLS0tCiEtLXx8ZDFmMWVyeWlxeWpzMHIuY2xvdWRmcm9udC5u +ZXQKIS0tfHxkM2xhcjA5eGJ3bHNnZS5jbG91ZGZyb250Lm5ldAohLS18fGQzcTFx +ajlqenN1OG53LmNsb3VkZnJvbnQubmV0CiEtLXx8ZGM4eGwwbmR6bjJjYi5jbG91 +ZGZyb250Lm5ldAohLS18fGExLm55dC5jb20KIS0tfHxpbnQubnl0LmNvbQohLS18 +fHMxLm55dC5jb20Kc3RhdGljMDEubnl0LmNvbQohLS18fHN0YXRpYzAxLm55dC5j +b20KIS0tfHx0eXBlZmFjZS5ueXQuY29tCnx8bnl0LmNvbQpueXRjaGluYS5jb20K +bnl0Y24ubWUKfHxueXRjbi5tZQp8fG55dGNvLmNvbQp8aHR0cDovL255dGkubXMv +Ci5ueXRpbWVzLmNvbQp8fG55dGltZXMuY29tCnx8bnl0aW1nLmNvbQpjbi5ueXRz +dHlsZS5jb20KfHxueXRzdHlsZS5jb20KCiEhLS0tU3RlYW0tLS0KLnN0ZWFtY29t +bXVuaXR5LmNvbQp8fHN0ZWFtY29tbXVuaXR5LmNvbQohLS1zdGVhbWNvbW11bml0 +eS5jb20vcHJvZmlsZXMvNzY1NjExOTgwNjI3NzE2MDkKIS0tc3RlYW1jb21tdW5p +dHkuY29tL2dyb3Vwcy9MaWJldFRpYmV0CiEtLXN0ZWFtY29tbXVuaXR5LmNvbS9n +cm91cHMvemhvbmdnb25nCiEtLXN0ZWFtY29tbXVuaXR5LmNvbS9pZC9DSlRfSmFj +a3Rvbgp8fHN0b3JlLnN0ZWFtcG93ZXJlZC5jb20KfHxhcGkuc3RlYW1wb3dlcmVk +LmNvbQp8fHN0ZWFtc3RhdGljLmNvbQohIS0tLVRlbGVncmFtLS0tCiEhIS0tLURv +bWFpbi0tLQp8fHR4Lm1lCnx8dGcuZGV2Cnx8dGVsZWdhLm9uZQp8fGNkbi10ZWxl +Z3JhbS5vcmcKfHxjb21tZW50cy5hcHAKfHxncmFwaC5vcmcKfHxsZWdyYS5waAp8 +fHF1aXouZGlyZWN0b3J5Cnx8dC5tZQp8fHVwZGF0ZXMudGRlc2t0b3AuY29tCnx8 +dGVsZWdyYW0uZG9nCnx8dGVsZWdyYW0ubWUKfHx0ZWxlZ3JhbS5vcmcKfHx0ZWxl +Z3JhbS5zcGFjZQp8fHRlbGVncmFtZG93bmxvYWQuY29tCnx8dGVsZWdyYS5waAp8 +fHRlbGVzY28ucGUKISEhLS0tSVAtLS0KCiEhLS0tVGlrdG9rLS0tCnx8dGlrdG9r +LmNvbQp8fHRpa3Rva3YuY29tCnx8dGlrdG9rdi51cwp8fHRpa3Rva2Nkbi11cy5j +b20KfHx0aWt0b2tjZG4uY29tCnx8dGlrdG9rY2RuLWV1LmNvbQoKISEtLS1Ud2l0 +Y2gtLS0KfHxqdHZudy5uZXQKfHx0dHZudy5uZXQKfHx0d2l0Y2gudHYKfHx0d2l0 +Y2hjZG4ubmV0CgohIS0tLVR3aXR0ZXIvWC0tLQp8fHBlcmlzY29wZS50dgoucHNj +cC50dgp8fHBzY3AudHYKLnQuY28KfHx0LmNvCi50d2VldGRlY2suY29tCnx8dHdl +ZXRkZWNrLmNvbQp8fHR3aW1nLmNvbQoudHdpdHBpYy5jb20KfHx0d2l0cGljLmNv +bQoudHdpdHRlci5jb20KfHx0d2l0dGVyLmNvbQp8fHR3aXR0ZXIuanAKfHx2aW5l +LmNvCnx8eC5jb20KCiEhLS0tVGFpd2FuLS0tCnx8bW9qLmdvdi50dwp8fGdvdi50 +YWlwZWkKLmdvdi50dwp8aHR0cHM6Ly9haXNzLmFud3MuZ292LnR3Cnx8YXJjaGl2 +ZXMuZ292LnR3Cnx8dGFjYy5jd2IuZ292LnR3Cnx8ZGF0YS5nb3YudHcKfHxleGFt +Lmdvdi50dwp8fGV5Lmdvdi50dwp8fGZhLmdvdi50dwp8fGZkYS5nb3YudHcKfHxo +cGEuZ292LnR3Cnx8aW1taWdyYXRpb24uZ292LnR3Cnx8aXRhaXdhbi5nb3YudHcK +fHxqdWRpY2lhbC5nb3YudHcKfHxsaS50YWlwZWkKfHxseS5nb3YudHcKfHxtamli +Lmdvdi50dwp8fG1vZWFpYy5nb3YudHcKfHxtb2ZhLmdvdi50dwp8fG1vbC5nb3Yu +dHcKfHxtdmRpcy5nb3YudHcKfHxuYXQuZ292LnR3Cnx8bmhpLmdvdi50dwp8fG5w +YS5nb3YudHcKfHxuc2MuZ292LnR3Cnx8bnRiay5nb3YudHcKfHxudGJuYS5nb3Yu +dHcKfHxudGJ0Lmdvdi50dwp8fHBjYy5nb3YudHcKfHxzdGF0Lmdvdi50dwp8fHRh +aXBlaS5nb3YudHcKfHx0YWl3YW5qb2JzLmdvdi50dwp8fHRoYi5nb3YudHcKfHx0 +aXBvLmdvdi50dwp8fHdkYS5nb3YudHcKCnx8dGVjby1oay5vcmcKfHx0ZWNvLW1v +Lm9yZwoKQEB8fGFmdHlnaC5nb3YudHcKQEB8fGFpZGUuZ292LnR3CkBAfHx0cGRl +LmFpZGUuZ292LnR3CkBAfHxhcnRlLmdvdi50dwpAQHx8Y2h1a3VhbmcuZ292LnR3 +CkBAfHxjd2IuZ292LnR3CkBAfHxjeWNhYi5nb3YudHcKQEB8fGRibnNhLmdvdi50 +dwpAQHx8ZGYuZ292LnR3CkBAfHxlYXN0Y29hc3QtbnNhLmdvdi50dwpAQHx8ZXJ2 +LW5zYS5nb3YudHcKQEB8fGdyYi5nb3YudHcKQEB8fGd5c2QubnljLmdvdi50dwpA +QHx8aGNoY2MuZ292LnR3CkBAfHxoc2luY2h1LWNjLmdvdi50dwpAQHx8aW5lci5n +b3YudHcKQEB8fGtsc2lvLmdvdi50dwpAQHx8a21zZWguZ292LnR3CkBAfHxsdW5n +dGFuaHIuZ292LnR3CkBAfHxtYW9saW4tbnNhLmdvdi50dwpAQHx8bWF0c3UtbmV3 +cy5nb3YudHcKQEB8fG1hdHN1LW5zYS5nb3YudHcKQEB8fG1hdHN1Y2MuZ292LnR3 +CkBAfHxtb2UuZ292LnR3CkBAfHxuYW5rYW4uZ292LnR3CkBAfHxuY3JlZS5nb3Yu +dHcKQEB8fGNyb21vdGMubmF0Lmdvdi50dwpAQHx8dGF4Lm5hdC5nb3YudHcKQEB8 +fG5lY29hc3QtbnNhLmdvdi50dwpAQHx8bmVyLmdvdi50dwpAQHx8bm1tYmEuZ292 +LnR3CkBAfHxubXAuZ292LnR3CkBAfHxubXZ0dGMuZ292LnR3CkBAfHxub3J0aGd1 +YW4tbnNhLmdvdi50dwp8fG5wbS5nb3YudHcKQEB8fG5zdG0uZ292LnR3CkBAfHxu +dGRtaC5nb3YudHcKQEB8fG50bC5nb3YudHcKQEB8fG50c2VjLmdvdi50dwpAQHx8 +bnR1aC5nb3YudHcKQEB8fG52cmkuZ292LnR3CkBAfHxwZW5naHUtbnNhLmdvdi50 +dwpAQHx8cG9zdC5nb3YudHcKQEB8fHNpcmF5YS1uc2EuZ292LnR3CkBAfHxzdGR0 +aW1lLmdvdi50dwpAQHx8c3VubW9vbmxha2UuZ292LnR3CkBAfHx0YWl0dW5nLWhv +dXNlLmdvdi50dwpAQHx8dGFveXVhbi5nb3YudHcKQEB8fHRwaGNjLmdvdi50dwpA +QHx8dHJpbXQtbnNhLmdvdi50dwpAQHx8dmdodHBlLmdvdi50dwpAQHx8dmdoa3Mu +Z292LnR3CkBAfHx2Z2h0Yy5nb3YudHcKQEB8fHdhbmZhbmcuZ292LnR3CkBAfHx5 +YXRzZW4uZ292LnR3CkBAfHx5ZGEuZ292LnR3CgohLS1AQHx8NHBwcGMuZ292LnR3 +CiEtLUBAfHw5MjEuZ292LnR3CiEtLUBAfHxkbXRpcC5nb3YudHcKIS0tQEB8fGV0 +cmFpbmluZy5nb3YudHcKIS0tQEB8fGdzbi1jZXJ0Lm5hdC5nb3YudHcKIS0tQEB8 +fG5pY2kubmF0Lmdvdi50dwohLS1AQHx8aGNjLmdvdi50dwohLS1AQHx8aGVuZ2No +dWVuLmdvdi50dwohLS1AQHx8a2hjYy5nb3YudHcKIS0tQEB8fGtobXMuZ292LnR3 +CiEtLUBAfHxray5nb3YudHcKIS0tQEB8fGtsY2NhYi5nb3YudHcKIS0tQEB8fGts +cmEuZ292LnR3CiEtLUBAfHxubWguZ292LnR3CiEtLUBAfHxubXRsLmdvdi50dwoh +LS1AQHx8cGFicC5nb3YudHcKIS0tQEB8fHBldC5nb3YudHcKIS0tQEB8fHRjaGIu +Z292LnR3CiEtLUBAfHx0Y3NhYy5nb3YudHcKIS0tQEB8fHRuY3NlYy5nb3YudHcK +fHxraW5tZW4ub3JnLnR3CgohIS0tLVVTQS0tLQp8fGFtZXJpY29ycHMuZ292Cnx8 +ZG1hLm1pbAp8fGpwbC5uYXNhLmdvdgp8fHBkcy5uYXNhLmdvdgp8fHBhY29tLm1p +bAp8fHNvYy5taWwKfHxzb2xhcnN5c3RlbS5uYXNhLmdvdgppaXBkaWdpdGFsLnVz +ZW1iYXNzeS5nb3YKfHx1c2NnLm1pbAp8fHVzZmsubWlsCnxodHRwOi8vdGFyci51 +c3B0by5nb3YvCnx8dHNkci51c3B0by5nb3YKCiEhLS0tVjJFWC0tLQp8fHYyZXgu +Y29tCiEtLS52MmV4LmNvbQohLS1JbmNsdWRlZCBpbiBhYm92ZSBydWxlOiBkbnMu +djJleC5jb20KIS0tQEB8aHR0cDovL3YyZXguY29tCiEtLUBAfGh0dHA6Ly9jZG4u +djJleC5jb20KIS0tQEB8aHR0cDovL2NuLnYyZXguY29tCiEtLUBAfGh0dHA6Ly9o +ay52MmV4LmNvbQohLS1AQHxodHRwOi8vaS52MmV4LmNvbQohLS1AQHxodHRwOi8v +bGF4LnYyZXguY29tCiEtLUBAfGh0dHA6Ly9uZXVlLnYyZXguY29tCiEtLUBAfGh0 +dHA6Ly9wYWdlc3BlZWQudjJleC5jb20KIS0tQEB8aHR0cDovL3N0YXRpYy52MmV4 +LmNvbQohLS1AQHxodHRwOi8vd29ya3NwYWNlLnYyZXguY29tCiEtLUBAfGh0dHA6 +Ly93d3cudjJleC5jb20KCiEhLS0tVk9BLS0tCnx8dm9hY2FtYm9kaWEuY29tCi52 +b2FjaGluZXNlYmxvZy5jb20KfHx2b2FjaGluZXNlYmxvZy5jb20KLnZvYWNhbnRv +bmVzZS5jb20KfHx2b2FjYW50b25lc2UuY29tCnZvYWNoaW5lc2UuY29tCnx8dm9h +Y2hpbmVzZS5jb20Kdm9hZ2QuY29tCnx8dm9haW5kb25lc2lhLmNvbQoudm9hbmV3 +cy5jb20KfHx2b2FuZXdzLmNvbQp2b2F0aWJldGFuLmNvbQp8fHZvYXRpYmV0YW4u +Y29tCi52b2F0aWJldGFuZW5nbGlzaC5jb20KfHx2b2F0aWJldGFuZW5nbGlzaC5j +b20KCiEhLS0tV2lraWEtLS0KfHx6aC5lY2RtLndpa2lhLmNvbQp8fGV2Y2hrLndp +a2lhLmNvbQpmcS53aWtpYS5jb20KemgucHR0cGVkaWEud2lraWEuY29tL3dpa2kv +JUU3JUJGJTkyJUU1JThDJTg1JUU1JUFEJTkwJUU0JUI5JThCJUU0JUJBJTgyCmNu +LnVuY3ljbG9wZWRpYS53aWtpYS5jb20KemgudW5jeWNsb3BlZGlhLndpa2lhLmNv +bQoKIS0tLS0tLS0tLS0tLS1XaWtpcGVkaWEgUmVsYXRlZC0tLS0tLS0tLS0tLS0K +ISFFbWVyZ2VuY3kgbmVlZCBvbmx5KElQL1BvcnQgYmxvY2sgdXNhZ2UpISEKIS0t +LS0tLTAtLS0tLS0KfHxtZWRpYXdpa2kub3JnCiEtLS0tLS0xLS0tLS0tCnx8d2lr +aWRhdGEub3JnCiEtLS0tLS0yLS0tLS0tCnx8d2lraW1lZGlhLm9yZwohLS0tLS0t +My0tLS0tLQp8fHdpa2lib29rcy5vcmcKIS0tLS0tLTQtLS0tLS0KfHx3aWtpdmVy +c2l0eS5vcmcKIS0tLS0tLTUtLS0tLS0KfHx3aWtpc291cmNlLm9yZwohLS0tLS0t +Ni0tLS0tLQp8fHpoLndpa2lxdW90ZS5vcmcKIS0tLS0tLTctLS0tLS0KfHx3aWtp +bmV3cy5vcmcKIS0tLS0tLTgtLS0tLS0KfHx3aWtpdm95YWdlLm9yZwohLS0tLS0t +OS0tLS0tLQp8fHdpa3Rpb25hcnkub3JnCiEtLS0tTWFpbi0tLS0tCnx8d2lraXBl +ZGlhLm9yZwp8fHdtZnVzZXJjb250ZW50Lm9yZwoKISEtLS1ZYWhvby0tLQp8fHNo +b3BwaW5nLnlhaG9vLmNvLmpwCnx8YXVjdGlvbnMueWFob28uY28uanAKfHxzZWFy +Y2gueWFob28uY28uanAKfHx5YWhvby5jb20udHcKfHx5YWhvby5jb20uaGsKfHx5 +YWhvby5jb20KCiEtLS0tLS0tLS0tLS0tLS0tLS1OdW1lcmljcy0tLS0tLS0tLS0t +LS0tLS0tLS0tLQp8fGlwZnMuNGV2ZXJsYW5kLmlvCnx8OTFkYXNhaS5jb20KfHxp +LjExMTY2Ni5iZXN0Cnx8MWxpYi5zawp8fDIwNDcub25lCnx8NjlzaHViYS5jeAp8 +fDIwNDliYnMueHl6Cnx8NjExc3R1ZHkuY29tCnx8MThjb21pYy5vcmcKfHwwMDB3 +ZWJob3N0LmNvbQouMDMwYnV5LmNvbQouMHJ6LnR3CnxodHRwOi8vMHJ6LnR3CjEt +YXBwbGUuY29tLnR3Cnx8MS1hcHBsZS5jb20udHcKLjEwMDBnaXJpLm5ldAp8fDEw +MDBnaXJpLm5ldAp8fDEwYmVhc3RzLm5ldAouMTBjb25kaXRpb25zb2Zsb3ZlLmNv +bQp8fDEwbXVzdW1lLmNvbQoxMjNyZi5jb20KLjEyYmV0LmNvbQp8fDEyYmV0LmNv +bQouMTJ2cG4uY29tCi4xMnZwbi5uZXQKfHwxMnZwbi5jb20KfHwxMnZwbi5uZXQK +fHwxMzM3eC50bwouMTM4LmNvbQoxNDFob25na29uZy5jb20vZm9ydW0KfHwxNDFq +ai5jb20KLjE0MXR1YmUuY29tCnx8MTY4OC5jb20uYXUKLjE3M25nLmNvbQp8fDE3 +M25nLmNvbQouMTc3cGljLmluZm8KLjE3dDE3cC5jb20KfHwxOGJvYXJkLmNvbQox +OG9ubHlnaXJscy5jb20KLjE4cDJwLmNvbQouMTh2aXJnaW5zZXguY29tCnpoYW8u +MTk4NC5jaXR5Cnx8emhhby4xOTg0LmNpdHkKMTk4NGJicy5jb20KfHwxOTg0YmJz +LmNvbQohLS18fDE5ODRibG9nLmNvbQouMTk5MXdheS5jb20KfHwxOTkxd2F5LmNv +bQouMWVldy5jb20KLjFtb2JpbGUuY29tCnx8MXBvaW50M2FjcmVzLmNvbQp8fDFw +b25kby50dgouMi1oYW5kLmluZm8KLjIwMDBmdW4uY29tL2Jicwp8fDIwMDh4aWFu +emhhbmcuaW5mbwp8fDIwMjFoa2NoYXJ0ZXIuY29tCnx8MjA0Ny5uYW1lCjIxYW5k +eS5jb20vYmxvZwoyMXNleHR1cnkuY29tCi4yMjgubmV0LnR3Cnx8MjMzYWJjLmNv +bQp8fDI0aHJzLmNhCjJsaXBzdHViZS5jb20KLjJzaGFyZWQuY29tCjMwYm94ZXMu +Y29tCi4zMTVsei5jb20KfHwzMnJlZC5jb20KfHwzNnJhaW4uY29tCi4zYTVhLmNv +bQozYXJhYnR2LmNvbQouM2JveXMyZ2lybHMuY29tCi4zcHJveHkucnUKLjNyZW4u +Y2EKLjN0dWkubmV0Cnx8NDA0bXVzZXVtLmNvbQp8fDRibHVlc3RvbmVzLmJpegou +NGNoYW4uY29tCiEtLXx8NGNoYW4ub3JnCi40ZXZlcnByb3h5LmNvbQp8fDRldmVy +cHJveHkuY29tCnx8NHJidHYuY29tCnx8NHNoYXJlZC5jb20KdGFpd2FubmF0aW9u +LjUwd2Vicy5jb20KfHw1MS5jYQp8fDUxamF2Lm9yZwouNTFsdW9iZW4uY29tCnx8 +NTFsdW9iZW4uY29tCnx8NTI3OC5jYwouNTI5OS50dgo1aTAxLmNvbQouNWlzb3Rv +aTUub3JnCi41bWFvZGFuZy5jb20KfHw2MTFzdHVkeS5pY3UKfHw2M2kuY29tCi42 +NG11c2V1bS5vcmcKNjR0aWFud2FuZy5jb20KNjR3aWtpLmNvbQouNjYuY2EKNjY2 +a2IuY29tCnx8NmRvLm5ld3MKfHw2ZG8ud29ybGQKLjZwYXJrLmNvbQp8fDZwYXJr +LmNvbQp8fDZwYXJrYmJzLmNvbQp8fDZwYXJrZXIuY29tCnx8NnBhcmtuZXdzLmNv +bQp8fDdjYXB0dXJlLmNvbQouN2Nvdy5jb20KIS0tfHw3LXppcC5vcmcKLjgtZC5j +b20KfGh0dHA6Ly84LWQuY29tCi44NWNjLnVzCnxodHRwOi8vODVjYy51cwouODgx +OTAzLmNvbS9wYWdlL3poLXR3Lwp8fDg4MTkwMy5jb20KLjg4OC5jb20KLjg4OHBv +a2VyLmNvbQo4OS42NC5jaGFydGVyLmNvbnN0aXR1dGlvbmFsaXNtLnNvbHV0aW9u +cwo4OS02NC5vcmcKfHw4OS02NC5vcmcKfHw4OTY0bXVzZXVtLmNvbQouOG5ld3Mu +Y29tLnR3Ci44ejEubmV0Cnx8OHoxLm5ldAp8fDkxcG9ybi5jb20KfHw5MXBvcm55 +LmNvbQp8fDkxdnBzLmNsdWIKLjkyY2Nhdi5jb20KLjk5MS5jb20KfGh0dHA6Ly85 +OTEuY29tCi45OWJ0Z2MwMS5jb20KfHw5OWJ0Z2MwMS5jb20KLjk5Y24uaW5mbwp8 +aHR0cDovLzk5Y24uaW5mbwp8fDliaXMuY29tCnx8OWJpcy5uZXQKfHw5bmV3cy5j +b20uYXUKCiEtLS0tLS0tLS0tLS0tLS0tLS0tLUFBLS0tLS0tLS0tLS0tLS0tLS0t +LS0tLS0tLQp8fGFtdWxldG1jLmNvbQp8fGFicGxpdmUuY29tCnx8Y2RuLmFyc3Rl +Y2huaWNhLm5ldAp8fGFvbWVkaWEub3JnCnx8YWxqYXplZXJhLmNvbQp8fGFraW5h +dG9yLmNvbQp8fGFubmFzLWFyY2hpdmUub3JnCnx8YXYwMS50dgp8fGFjZy5yaXAK +fHxhbm5hcy1hcmNoaXZlLnNlCnx8YS1ub3JtYWwtZGF5LmNvbQphNS5jb20ucnUK +fGh0dHA6Ly9hYW1hY2F1LmNvbQohLS18aHR0cDovL2NkbiouYWJjLmNvbS8KLmFi +Yy5jb20KLmFiYy5uZXQuYXUKfHxhYmMubmV0LmF1Ci5hYmNoaW5lc2UuY29tCnx8 +YWJlYm9va3MuY28udWsKLmFibHdhbmcuY29tCi5hYm9sdW93YW5nLmNvbQp8fGFi +b2x1b3dhbmcuY29tCnx8YWJvdXQubWUKLmFicy5lZHUKfHxhY2FzdC5jb20KLmFj +Y2ltLm9yZwouYWNlcm9zLWRlLWhpc3BhbmlhLmNvbQouYWNldnBuLmNvbQp8fGFj +ZXZwbi5jb20KLmFjZzE4Lm1lCnxodHRwOi8vYWNnMTgubWUKfHxhY2dib3gub3Jn +Cnx8YWNna2ouY29tCnx8YWNnbnguc2UKLmFjbWVkaWEzNjUuY29tCi5hY253LmNv +bS5hdQphY3Rmb3J0aWJldC5vcmcKYWN0aW1lcy5jb20uYXUKYWN0aXZwbi5jb20K +fHxhY3RpdnBuLmNvbQp8fGFjdWxvLnVzCnx8YWRkaWN0ZWR0b2NvZmZlZS5kZQp8 +fGFkZHlvdXR1YmUuY29tCi5hZGVsYWlkZWJicy5jb20vYmJzCi5hZHBsLm9yZy5o +awp8aHR0cDovL2FkcGwub3JnLmhrCi5hZHVsdC1zZXgtZ2FtZXMuY29tCnx8YWR1 +bHQtc2V4LWdhbWVzLmNvbQphZHVsdGZyaWVuZGZpbmRlci5jb20KfHxhZHZhbnNj +ZW5lLmNvbQp8fGFkdmVydGZhbi5jb20KLmFlLm9yZwp8fGFlaS5vcmcKfHxhZW5o +YW5jZXJzLmNvbQp8fGFmLm1pbAouYWZhbnRpYmJzLmNvbQp8aHR0cDovL2FmYW50 +aWJicy5jb20KfHxhZnIuY29tCnx8YWlvc2VhcmNoLmNvbQouYWlwaC5uZXQKfHxh +aXBoLm5ldAouYWlyYXNpYS5jb20KfHxhaXJjb25zb2xlLmNvbQp8aHR0cDovL2Rv +d25sb2FkLmFpcmNyYWNrLW5nLm9yZwouYWlydnBuLm9yZwp8fGFpcnZwbi5vcmcK +LmFpc2V4LmNvbQp8fGFpdC5vcmcudHcKYWl3ZWl3ZWkuY29tCi5haXdlaXdlaWJs +b2cuY29tCnx8YWl3ZWl3ZWlibG9nLmNvbQp8fHd3dy5hanNhbmRzLmNvbQoKISEt +LS1Ba2FtYWktLS0KYTI0OC5lLmFrYW1haS5uZXQKfHxhMjQ4LmUuYWthbWFpLm5l +dAoKcmZhbGl2ZTEuYWthY2FzdC5ha2FtYWlzdHJlYW0ubmV0CnZvYS0xMS5ha2Fj +YXN0LmFrYW1haXN0cmVhbS5uZXQKCnxodHRwczovL2ZiY2RuKi5ha2FtYWloZC5u +ZXQvCiEtLXx8ZmJleHRlcm5hbC1hLmFrYW1haWhkLm5ldAohLS18fGZic3RhdGlj +LWEuYWthbWFpaGQubmV0CiEtLXxodHRwczovL2lnY2RuKi5ha2FtYWloZC5uZXQK +cnRoa2xpdmUyLWxoLmFrYW1haWhkLm5ldAoKLmFrYWRlbWl5ZS5vcmcvdWcKfGh0 +dHA6Ly9ha2FkZW1peWUub3JnL3VnCnx8YWtpYmEtb25saW5lLmNvbQp8fGFrb3cu +b3JnCi5hbC1pc2xhbS5jb20KfHxhbGFib3V0LmNvbQouYWxhbmhvdS5jb20KfGh0 +dHA6Ly9hbGFuaG91LmNvbQouYWxhcmFiLnFhCnx8YWxhc2JhcnJpY2FkYXMub3Jn +Cnx8YWxmb3JhdHR2Lm5ldAouYWxoYXlhdC5jb20KLmFsaWNlamFwYW4uY28uanAK +YWxpZW5ndS5jb20KfHxhbGl2ZS5iYXIKfHxhbGthc2lyLmNvbQp8fGFsbDRtb20u +b3JnCnx8YWxsY29ubmVjdGVkLmNvCi5hbGxkcmF3bnNleC5jb20KfHxhbGxkcmF3 +bnNleC5jb20KfHxhbGxmaW5lZ2lybHMuY29tCi5hbGxnaXJsbWFzc2FnZS5jb20K +YWxsZ2lybHNhbGxvd2VkLm9yZwouYWxsZ3JhdnVyZS5jb20KYWxsaWFuY2Uub3Jn +LmhrCi5hbGxpbmZhLmNvbQp8fGFsbGluZmEuY29tCi5hbGxqYWNrcG90c2Nhc2lu +by5jb20KfHxhbGxtb3ZpZS5jb20KLmFscGhhcG9ybm8uY29tCnx8YWx0ZXJuYXRl +LXRvb2xzLmNvbQphbHRlcm5hdGl2ZXRvLm5ldC9zb2Z0d2FyZQphbHZpbmFsZXhh +bmRlci5jb20KYWx3YXlzZGF0YS5jb20KfHxhbHdheXNkYXRhLmNvbQp8fGFsd2F5 +c2RhdGEubmV0Ci5hbHdheXN2cG4uY29tCnx8YWx3YXlzdnBuLmNvbQp8fGFtNzMw +LmNvbS5oawphbWVibG8uanAKfHxhbWVibG8uanAKd3d3MS5hbWVyaWNhbi5lZHUv +dGVkL2ljZS90aWJldAp8fGFtZXJpY2FuZ3JlZW5jYXJkLmNvbQp8fGFtaWJsb2Nr +ZWRvcm5vdC5jb20KLmFtaWdvYmJzLm5ldAouYW1pdGFiaGFmb3VuZGF0aW9uLnVz +CnxodHRwOi8vYW1pdGFiaGFmb3VuZGF0aW9uLnVzCi5hbW5lc3R5Lm9yZwp8fGFt +bmVzdHkub3JnCnx8YW1uZXN0eS5vcmcuaGsKLmFtbmVzdHkudHcKLmFtbmVzdHl1 +c2Eub3JnCnx8YW1uZXN0eXVzYS5vcmcKLmFtdGItdGFpcGVpLm9yZwouYW5keWdv +ZC5jb20KfGh0dHA6Ly9hbmR5Z29kLmNvbQphbm5hdGFtLmNvbS9jaGluZXNlCnx8 +YW5jaG9yLmZtCnx8YW5jaG9yZnJlZS5jb20KIS0tR0hTCnx8YW5jc2NvbmYub3Jn +Cnx8YW5kZmFyYXdheS5uZXQKfHxhbmRyb2lkLXg4Ni5vcmcKfHxhbmRyb2lkYXBr +c2ZyZWUuY29tCmFuZ2VsZmlyZS5jb20vaGkvaGF5YXNoaQp8fGFuZ3VsYXJqcy5v +cmcKYW5pbWVjcmF6eS5uZXQKYW5pc2NhcnR1am8uY29tCnx8YW5pc2NhcnR1am8u +Y29tCnx8YW5vYmlpLmNvbQp8fGFub25maWxlcy5jb20KLmFub255bWl0eW5ldHdv +cmsuY29tCi5hbm9ueW1pemVyLmNvbQouYW5vbnltb3VzZS5vcmcKfHxhbm9ueW1v +dXNlLm9yZwphbm9udGV4dC5jb20KLmFucG9wby5jb20KLmFuc3dlcmluZy1pc2xh +bS5vcmcKfGh0dHA6Ly93d3cuYW50ZC5vcmcKfHxhbnRob255Y2FsemFkaWxsYS5j +b20KYW50aWNocmlzdGVuZG9tLmNvbQouYW50aXdhdmUubmV0CnxodHRwOi8vYW50 +aXdhdmUubmV0Ci5hbnlwb3JuLmNvbQouYW55c2V4LmNvbQp8aHR0cDovL2FueXNl +eC5jb20KLmFvMy5vcmcKfHxhbzMub3JnCnx8YW9iby5jb20uYXUKLmFvZnJpZW5k +LmNvbQp8aHR0cDovL2FvZnJpZW5kLmNvbQouYW9qaWFvLm9yZwp8fGFvbWl3YW5n +LmNvbQp8fGFwYXQxOTg5Lm9yZwouYXBldHViZS5jb20KfHxhcGlhcnkuaW8KLmFw +aWdlZS5jb20KfHxhcGlnZWUuY29tCnx8YXBrLnN1cHBvcnQKfHxhcGtjb21iby5j +b20KLmFwa21vbmsuY29tL2FwcAp8fGFwa21vbmsuY29tCnx8YXBrcGx6LmNvbQp8 +fGFwa3B1cmUuY29tCnx8YXBrcHVyZS5uZXQKfHxhcHBhZHZpY2UuY29tCiEtLXx8 +YXBwYW5uaWUuY29tCnx8YXBwYnJhaW4uY29tCi5hcHBkb3dubG9hZGVyLm5ldC9B +bmRyb2lkCi5hcHBsZWRhaWx5LmNvbQp8fGFwcGxlZGFpbHkuY29tCmFwcGxlZGFp +bHkuY29tLnR3Cnx8YXBwbGVkYWlseS5jb20udHcKLmFwcHNob3BwZXIuY29tCnxo +dHRwOi8vYXBwc2hvcHBlci5jb20KfHxhcHBzb2Nrcy5uZXQKfHxhcHBzdG8ucmUK +LmFwdG9pZGUuY29tCnx8YXB0b2lkZS5jb20KfHxhcmNoaXZlcy5nb3YKLmFyY2hp +dmUuZm8KfHxhcmNoaXZlLmZvCnx8YXJjaGl2ZS52bgp8fGFyY2hpdmUuaXMKfHxh +cmNoaXZlLmlzCnx8YXJjaGl2ZS5saQp8fGFyY2hpdmUubGkKfHxhcmNoaXZlLm1k +Cnx8YXJjaGl2ZS5vcmcKfHxhcmNoaXZlLnBoCnx8YXJjaGl2ZS50b2RheQp8fGFy +Y2hpdmVvZm91cm93bi5jb20KfHxhcmNoaXZlb2ZvdXJvd24ub3JnCi5hcmN0b3Np +YS5jb20KfHxhcmN0b3NpYS5jb20KfHxhcmVjYS1iYWNrdXAub3JnCi5hcmV0aHVz +YS5zdQp8fGFyZXRodXNhLnN1Cnx8YXJsaW5ndG9uY2VtZXRlcnkubWlsCi5hcnQ0 +dGliZXQxOTk4Lm9yZwphcnRvZnBlYWNlZm91bmRhdGlvbi5vcmcKYXJ0c3kubmV0 +Cnx8YXNhY3Aub3JnCmFzZGZnLmpwL2RhYnIKYXNnLnRvCi5hc2lhLWdhbWluZy5j +b20KLmFzaWFoYXJ2ZXN0Lm9yZwp8fGFzaWFoYXJ2ZXN0Lm9yZwp8fGFzaWFuYWdl +LmNvbQp8fGFzaWFuZXdzLml0Cnx8YXNpYW5zZXhkaWFyeS5jb20KfHxhc2lhb25l +LmNvbQouYXNpYXRncC5jb20KfHxhc2suY29tCnx8YXNrc3R1ZGVudC5jb20KLmFz +a3luei5uZXQKfHxhc2t5bnoubmV0Cnx8YXNwaS5vcmcuYXUKfHxhc3Bpc3RyYXRl +Z2lzdC5vcmcuYXUKfHxhc3NlbWJsYS5jb20KfHxhc3RyaWxsLmNvbQp8fGF0Yy5v +cmcuYXUKLmF0Y2hpbmVzZS5jb20KfGh0dHA6Ly9hdGNoaW5lc2UuY29tCmF0Z2Z3 +Lm9yZwouYXRsYW50YTE2OC5jb20KfHxhdGxhbnRhMTY4LmNvbQouYXRuZXh0LmNv +bQp8fGF0bmV4dC5jb20KfHxhdWRhY3kuY29tCmljZS5hdWRpb25vdy5jb20KLmF2 +LmNvbQp8fGF2Lm1vdmllCi5hdi1lLWJvZHkuY29tCmF2YWF6Lm9yZwp8fGF2YWF6 +Lm9yZwohLS18fGF2YXN0LmNvbQouYXZjb29sLmNvbQouYXZkYi5pbgp8fGF2ZGIu +aW4KLmF2ZGIudHYKfHxhdmRiLnR2Ci5hdmZhbnRhc3kuY29tCnx8YXZnLmNvbQou +YXZnbGUuY29tCnx8YXZnbGUuY29tCnx8YXZpZGVtdXgub3JnCnx8YXZvaXNpb24u +Y29tCi5hdnlhaG9vLmNvbQp8fGF4aW9zLmNvbQp8fGF4dXJlZm9ybWFjLmNvbQph +emVyaW1peC5jb20KfHxhemlyZXZwbi5jb20KIS0tYm94dW4uYXp1cmV3ZWJzaXRl +cy5uZXQgZG9lc24ndCBleGlzdC4KYm94dW4qLmF6dXJld2Vic2l0ZXMubmV0Cnx8 +Ym94dW4qLmF6dXJld2Vic2l0ZXMubmV0CgohLS0tLS0tLS0tLS0tLS0tLS0tLS1C +Qi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KfHxidDRncHJ4LmNvbQp8fGJ0NGcu +b3JnCnx8YmV0dGVyaGFzaC5uZXQKfHxiaW5hbmNlLm9yZwp8fGJpdGdldC5jb20K +fHxibGFja21hZ2ljZGVzaWduLmNvbQp8fGJlYXJ0ZWFjaC5jb20KfHxidGJ0dC5t +ZQp8fGJ0YnR0LmNvCnx8YnRiaXQubmV0Cnx8YmV0YWNsb3Vkcy5uZXQKfHxibG9j +a3RlbXBvLmNvbQp8fGJsb2NrY2FzdC5pdAp8fHd3dy5iaW5nLmNvbQp8fGJhbmd1 +bWkubW9lCnx8Yi1vay5jYwpmb3J1bS5iYWJ5LWtpbmdkb20uY29tCnx8YmFieWxv +bmJlZS5jb20KYmFieW5ldC5jb20uaGsKYmFja2NoaW5hLmNvbQp8fGJhY2tjaGlu +YS5jb20KLmJhY2twYWNrZXJzLmNvbS50dy9mb3J1bQpiYWNrdG90aWFuYW5tZW4u +Y29tCnx8YmFkLm5ld3MKLmJhZGl1Y2FvLmNvbQp8fGJhZGl1Y2FvLmNvbQouYmFk +am9qby5jb20KYmFkb28uY29tCnxodHRwOi8vKjIuYmFoYW11dC5jb20udHcKfHxi +YWlkdS5qcAouYmFpamllLm9yZwp8fGJhaWppZS5vcmcKfHxiYWlsYW5kYWlseS5j +b20KfHxiYWl4aW5nLm1lCnx8YmFpemhpLm9yZwouYmFuYW5hLXZwbi5jb20KfHxi +YW5hbmEtdnBuLmNvbQp8fGJhbmQudXMKfHxiYW5kY2FtcC5jb20KLmJhbmR3YWdv +bmhvc3QuY29tCnx8YmFuZHdhZ29uaG9zdC5jb20KLmJhbmdicm9zbmV0d29yay5j +b20KLmJhbmdjaGVuLm5ldAp8aHR0cDovL2JhbmdjaGVuLm5ldAp8fGJhbmdrb2tw +b3N0LmNvbQp8fGJhbmd5b3VsYXRlci5jb20KYmFubmVkYm9vay5vcmcKfHxiYW5u +ZWRib29rLm9yZwouYmFubmVkbmV3cy5vcmcKLmJhcmFtYW5nYW9ubGluZS5jb20K +fGh0dHA6Ly9iYXJhbWFuZ2FvbmxpbmUuY29tCi5iYXJlbmFrZWRpc2xhbS5jb20K +fHxiYXJuYWJ1LmNvLnVrCnx8YmFydG9uLmRlCi5iYXN0aWxsZXBvc3QuY29tCnx8 +YmFzdGlsbGVwb3N0LmNvbQpiYXl2b2ljZS5uZXQKfHxiYXl2b2ljZS5uZXQKfHxi +YmNoYXQudHYKfHxiYi1jaGF0LnR2Ci5iYmcuZ292Ci5iYmt6LmNvbS9mb3J1bQou +YmJucmFkaW8ub3JnCmJicy10dy5jb20KLmJic2RpZ2VzdC5jb20vdGhyZWFkCmJi +c2xhbmQuY29tCi5iYnNtby5jb20KLmJic29uZS5jb20KYmJ0b3lzdG9yZS5jb20K +LmJjYy5jb20udHcvYm9hcmQKLmJjY2hpbmVzZS5uZXQKLmJjbW9ybmluZy5jb20K +YmRzbXZpZGVvcy5uZXQKLmJlYWNvbmV2ZW50cy5jb20KLmJlYm8uY29tCnx8YmVi +by5jb20KLmJlZXZwbi5jb20KfHxiZWV2cG4uY29tCi5iZWhpbmRraW5rLmNvbQp8 +fGJlaWppbmcxOTg5LmNvbQp8fGJlaWppbmcyMDIyLmFydApiZWlqaW5nc3ByaW5n +LmNvbQp8fGJlaWppbmdzcHJpbmcuY29tCi5iZWxhbWlvbmxpbmUuY29tCi5iZWxs +Lndpa2kKfGh0dHA6Ly9iZWxsLndpa2kKYmVteXdpZmUuY2MKYmVyaWMubWUKfHxi +ZXJsaW5lcmJlcmljaHQuZGUKLmJlcmxpbnR3aXR0ZXJ3YWxsLmNvbQp8fGJlcmxp +bnR3aXR0ZXJ3YWxsLmNvbQouYmVybS5jby5uegouYmVzdGdvcmUuY29tCi5iZXN0 +cG9ybnN0YXJkYi5jb20KfHxiZXN0dnBuLmNvbQp8fGJlc3R2cG5hbmFseXNpcy5j +b20KfHxiZXN0dnBuZm9yY2hpbmEubmV0Cnx8YmVzdHZwbnNlcnZlci5jb20KfHxi +ZXN0dnBuc2VydmljZS5jb20KfHxiZXN0dnBudXNhLmNvbQp8fGJldDM2NS5jb20K +LmJldGZhaXIuY29tCnx8YmV0dGVybmV0LmNvCi5iZXR0ZXJ2cG4uY29tCnx8YmV0 +dGVydnBuLmNvbQouYmV0dHdlZW4uY29tCnx8YmV0dHdlZW4uY29tCnx8YmV0dmlj +dG9yLmNvbQouYmV3d3cubmV0Ci5iZXlvbmRmaXJld2FsbC5jb20KfHxiZm5uLm9y +Zwp8fGJmc2guaGsKLmJndnBuLmNvbQp8fGJndnBuLmNvbQouYmlhbmxlaS5jb20K +QEB8fGJpYW5sZWkuY29tCmJpYW50YWlsYWppYW8uY29tCnx8YmlibGVzZm9yYW1l +cmljYS5vcmcKfHx2cGwuYmlibGlvY29tbW9ucy5jb20KfHxiaWVkaWFuLm1lCmJp +Z2Zvb2xzLmNvbQp8fGJpZ2phcGFuZXNlc2V4LmNvbQouYmlnbmV3cy5vcmcKfHxi +aWduZXdzLm9yZwouYmlnc291bmQub3JnCnx8YmlsZC5kZQouYmlsaXdvcmxkLmNv +bQp8aHR0cDovL2JpbGl3b3JsZC5jb20KfGh0dHA6Ly9iaWxseXBhbi5jb20vd2lr +aQouYmludXgubWUKYWkuYmlud2FuZy5tZS9jb3VwbGV0Ci5iaXQuZG8KfGh0dHA6 +Ly9iaXQuZG8KLmJpdC5seQp8aHR0cDovL2JpdC5seQohLS18fGJpdGJ1Y2tldC5v +cmcKfHxiaXRjaHV0ZS5jb20KfHxiaXRjb2ludGFsay5vcmcKLmJpdHNoYXJlLmNv +bQp8fGJpdHNoYXJlLmNvbQpiaXRzbm9vcC5jb20KLmJpdHZpc2UuY29tCnx8Yml0 +dmlzZS5jb20KYml6aGF0LmNvbQp8fGJsLWRvdWppbnNvdWtvLmNvbQouYmpuZXds +aWZlLm9yZwouYmpzLm9yZwpianpjLm9yZwp8fGJqemMub3JnCnx8YmxhY2tlZC5j +b20KLmJsYWNrbG9naWMuY29tCi5ibGFja3Zwbi5jb20KfHxibGFja3Zwbi5jb20K +Ymxld3Bhc3MuY29tCi5ibGlua3guY29tCnx8Ymxpbmt4LmNvbQpibGludy5jb20K +LmJsaXAudHYKfHxibGlwLnR2Cnx8YmxvY2tjYXN0Lml0Ci5ibG9ja2NuLmNvbQp8 +fGJsb2NrY24uY29tCnx8YmxvY2tlZGJ5aGsuY29tCnx8YmxvY2tsZXNzLmNvbQp8 +fGJsb2cuZGUKLmJsb2cuanAKfGh0dHA6Ly9ibG9nLmpwCkBAfHxqcHVzaC5jbgou +YmxvZ2NhdGFsb2cuY29tCnx8YmxvZ2NhdGFsb2cuY29tCnx8YmxvZ2NpdHkubWUK +LmJsb2dnZXIuY29tCnx8YmxvZ2dlci5jb20KYmxvZ2ltZy5qcAouYmxvZ2xpbmVz +LmNvbQp8fGJsb2dsaW5lcy5jb20KfHxibG9nbG92aW4uY29tCnJjb252ZXJzYXRp +b24uYmxvZ3MuY29tCi5ibG9ndGQub3JnCnxodHRwOi8vYmxvZ3RkLm9yZwp8fGJs +b29kc2hlZC5uZXQKfHxib290c3RyYXBjZG4uY29tCnx8Ymxvb21mb3J0dW5lLmNv +bQpibHVlYW5nZWxsaXZlLmNvbQp8fGJsdWJycnkuY29tCnx8Ym1kcnUuY29tCnx8 +Ym5leHQuY29tLnR3Cnx8Ym5ybWV0YWwuY29tCmJvYXJkcmVhZGVyLmNvbS90aHJl +YWQKfHxib2FyZHJlYWRlci5jb20KLmJvZC5hc2lhCnx8Ym9kLmFzaWEKLmJvZG9n +ODguY29tCi5ib2xlaHZwbi5uZXQKfHxib2xlaHZwbi5uZXQKYm9uYm9ubWUuY29t +Ci5ib25mb3VuZGF0aW9uLm9yZwouYm9uZ2FjYW1zLmNvbQp8fGJvb2JzdGFncmFt +LmNvbQp8fGJvb2suY29tLnR3Cnx8Ym9va2RlcG9zaXRvcnkuY29tCmJvb2tlcHVi +LmNvbQp8fGJvb2tzLmNvbS50dwp8fGJvb2t3YWxrZXIuY29tLnR3Cnx8Ym9yZ2Vu +bWFnYXppbmUuY29tCnx8Ym90YW53YW5nLmNvbQouYm90Lm51Ci5ib3dlbnByZXNz +LmNvbQp8fGJvd2VucHJlc3MuY29tCnx8YXBwLmJveC5jb20KZGwuYm94Lm5ldAp8 +fGRsLmJveC5uZXQKLmJveHBuLmNvbQp8fGJveHBuLmNvbQpib3h1bi5jb20KfHxi +b3h1bi5jb20KLmJveHVuLnR2Cnx8Ym94dW4udHYKLmJveHVuY2x1Yi5jb20KYm95 +YW5ndS5jb20KLmJveWZyaWVuZHR2LmNvbQouYm95c2Zvb2QuY29tCnx8YnIuc3QK +LmJyYWlueXF1b3RlLmNvbS9xdW90ZXMvYXV0aG9ycy9kL2RhbGFpX2xhbWEKfHxi +cmF1bWVpc3Rlci5vcmcKfHxicmF2ZS5jb20KLmJyYXZvdHViZS5uZXQKfHxicmF2 +b3R1YmUubmV0Ci5icmF6emVycy5jb20KfHxicmF6emVycy5jb20KfHxicmVhY2hl +ZC50bwouYnJlYWsuY29tCnx8YnJlYWsuY29tCmJyZWFrZ2Z3LmNvbQp8fGJyZWFr +Z2Z3LmNvbQpicmVha2luZzkxMS5jb20KLmJyZWFraW5ndHdlZXRzLmNvbQp8fGJy +ZWFraW5ndHdlZXRzLmNvbQp8fGJyZWFrd2FsbC5uZXQKYnJpaWFuLmNvbS82NTEx +L2ZyZWVnYXRlCnx8YnJpbGwuY29tCmJyaXp6bHkuY29tCnx8YnJpenpseS5jb20K +YnJvYWRib29rLmNvbQouYnJvYWRwcmVzc2luYy5jb20KfHxicm9hZHByZXNzaW5j +LmNvbQpiYnMuYnJvY2tiYnMuY29tCnx8YnJvb2tpbmdzLmVkdQpicnVjZXdhbmcu +bmV0Ci5icnV0YWx0Z3AuY29tCnx8YnJ1dGFsdGdwLmNvbQp8fGJza3kuYXBwCnx8 +YnNreS5uZXR3b3JrCnx8YnNreS5zb2NpYWwKfHxidDk1LmNvbQouYnRhaWEuY29t +Ci5idGJ0YXYuY29tCnx8YnRkaWcuY29tCnx8YnRkaWdnLm9yZwp8fGJ0Z3VhcmQu +Y29tCi5idGt1Lm1lCnx8YnRrdS5tZQp8fGJ0a3Uub3JnCi5idHNwcmVhZC5jb20K +LmJ0c3luY2tleXMuY29tCi5idWRhZWR1Lm9yZwp8fGJ1ZGFlZHUub3JnCi5idWRk +aGFuZXQuY29tLnR3L3pmcm9wL3RpYmV0Cnx8YnVmZmVyZWQuY29tCnx8YnVsbGd1 +YXJkLmNvbQouYnVsbG9nLm9yZwp8fGJ1bGxvZy5vcmcKLmJ1bGxvZ2dlci5jb20K +fHxidWxsb2dnZXIuY29tCnx8YnVtaW5nYmFpLm5ldAp8fGJ1bmJ1bmhrLmNvbQou +YnVzYXlhcmkuY29tCnxodHRwOi8vYnVzYXlhcmkuY29tCnx8YnVzaW5lc3MtaHVt +YW5yaWdodHMub3JnCi5idXNpbmVzc2luc2lkZXIuY29tL2JpbmctY291bGQtYmUt +Y2Vuc29yaW5nLXNlYXJjaC1yZXN1bHRzLTIwMTQKLmJ1c2luZXNzaW5zaWRlci5j +b20vY2hpbmEtYmFua3MtcHJlcGFyaW5nLWZvci1kZWJ0LWltcGxvc2lvbi0yMDE0 +Ci5idXNpbmVzc2luc2lkZXIuY29tL2hvbmcta29uZy1hY3RpdmlzdHMtZGVmeS1w +b2xpY2UtdGVhci1nYXMtYXMtcHJvdGVzdHMtY29udGludWUtb3Zlcm5pZ2h0LTIw +MTQKLmJ1c2luZXNzaW5zaWRlci5jb20vaW50ZXJuZXQtb3V0YWdlcy1yZXBvcnRl +ZC1pbi1ub3J0aC1rb3JlYS0yMDE0Ci5idXNpbmVzc2luc2lkZXIuY29tL2lwaG9u +ZS02LWlzLWFwcHJvdmVkLWZvci1zYWxlLWluLWNoaW5hLTIwMTQKLmJ1c2luZXNz +aW5zaWRlci5jb20vbmZsLWFubm91bmNlcnMtc3VyZmFjZS10YWJsZXRzLTIwMTQK +LmJ1c2luZXNzaW5zaWRlci5jb20vcGFuYW1hLXBhcGVycwouYnVzaW5lc3NpbnNp +ZGVyLmNvbS91bWJyZWxsYS1tYW4taG9uZy1rb25nLTIwMTQKfGh0dHA6Ly93d3cu +YnVzaW5lc3NpbnNpZGVyLmNvbS5hdS8qCi5idXNpbmVzc3RvZGF5LmNvbS50dwp8 +fGJ1c2luZXNzdG9kYXkuY29tLnR3Ci5idXN1Lm9yZy9uZXdzCnxodHRwOi8vYnVz +dS5vcmcvbmV3cwpidXN5dHJhZGUuY29tCi5idXp6aGFuZC5jb20KLmJ1enpoYW5k +Lm5ldAouYnV6em9yYW5nZS5jb20KfHxidXp6b3JhbmdlLmNvbQp8fGJ1enpzcHJv +dXQuY29tCnx8YnZwbi5jb20KfHxid2gxLm5ldAp8fGJ5cGFzc2NlbnNvcnNoaXAu +b3JnCgohLS0tLS0tLS0tLS0tLS0tLS0tLS1DQy0tLS0tLS0tLS0tLS0tLS0tLS0t +LS0tLS0KfHxjb3ZlbmFudHN3YXRjaC5vcmcudHcKfHxjcHUtbW9ua2V5LmNvbQp8 +fGNvZmZlZW1hbmdhLnRvCnx8Y3RpbmV3cy5jb20KfHxjYWNoZWZseS5jb20KfHxj +YWNoZWZseS5uZXQKfHxjdXRvdXQucHJvCnx8Y2l4aWFveWEuY2x1Ygp8fGNhbXBh +aWduLWFyY2hpdmUuY29tCnx8Y2hpbmF1bmNlbnNvcmVkLnR2Cnx8Y2F0Ym94Lm1v +ZQp8fGNyb3Nzd2FsbC5vcmcKfHxjbGlwY29udmVydGVyLmNjCnx8emgtaGFucy5j +ZnNoOTkuY29tCnx8Y29sYWNsb3VkLm5ldAp8fGNpLWVuLmpwCnx8Yy1zcGFuLm9y +ZwouYy1zcGFudmlkZW8ub3JnCnx8Yy1zcGFudmlkZW8ub3JnCnx8Yy1lc3Qtc2lt +cGxlLmNvbQouYzEwMHRpYmV0Lm9yZwp8fGNhYmxlYXYudHYKfHxjYWJsZWdhdGVz +ZWFyY2gubmV0Ci5jYWNoaW5lc2UuY29tCi5jYWNudy5jb20KfGh0dHA6Ly9jYWNu +dy5jb20KLmNhY3R1c3Zwbi5jb20KfHxjYWN0dXN2cG4uY29tCi5jYWZlcHJlc3Mu +Y29tCi5jYWhyLm9yZy50dwouY2FsYW1lby5jb20vYm9va3MKfHxjYWxlbmRhcnou +Y29tCi5jYWxnYXJ5Y2hpbmVzZS5jYQouY2FsZ2FyeWNoaW5lc2UuY29tCi5jYWxn +YXJ5Y2hpbmVzZS5uZXQKLmNhbTQuY29tCi5jYW00LmpwCi5jYW00LnNnCi5jYW1m +cm9nLmNvbQp8fGNhbWZyb2cuY29tCnx8Y2FtcGFpZ25mb3J1eWdodXJzLm9yZwp8 +fGNhbXMuY29tCi5jYW1zLm9yZy5zZwpjYW5hZGFtZWV0LmNvbQouY2FuYWxwb3Ju +by5jb20KfGh0dHA6Ly9iYnMuY2FudG9uZXNlLmFzaWEvCiEtLWh0dHA6Ly93d3cu +Y2FudG9uZXNlLmFzaWEvYWN0aW9uLWJicy5odG1sCi5jYW55dS5vcmcKfHxjYW55 +dS5vcmcKLmNhb2JpYW4uaW5mbwp8fGNhb2JpYW4uaW5mbwpjYW9jaGFuZ3Fpbmcu +Y29tCnx8Y2FvY2hhbmdxaW5nLmNvbQouY2FwLm9yZy5oawp8fGNhcC5vcmcuaGsK +fHxjYW9wb3JuLnVzCi5jYXJhYmluYXN5cGlzdG9sYXMuY29tCmNhcmRpbmFsa3Vu +Z2ZvdW5kYXRpb24ub3JnCnx8cG9zdHMuY2FyZWVyZW5naW5lLnVzCmNhcm1vdG9y +c2hvdy5jb20KfHxjYXJyZC5jbwouY2FydG9vbm1vdmVtZW50LmNvbQp8fGNhcnRv +b25tb3ZlbWVudC5jb20KLmNhc2FkZWx0aWJldGJjbi5vcmcKLmNhc2F0aWJldC5v +cmcubXgKfGh0dHA6Ly9jYXNhdGliZXQub3JnLm14Ci5jYXJpLmNvbS5teQp8fGNh +cmkuY29tLm15Cnx8Y2FyaWJiZWFuY29tLmNvbQp8fGNhcm91c2VsbC5jb20uaGsK +LmNhc2lub2tpbmcuY29tCi5jYXNpbm9yaXZhLmNvbQp8fGNhdGNoMjIubmV0Ci5j +YXRjaGdvZC5jb20KfGh0dHA6Ly9jYXRjaGdvZC5jb20KLmNhdGhvbGljLm9yZy5o +awp8fGNhdGhvbGljLm9yZy5oawpjYXRob2xpYy5vcmcudHcKfHxjYXRob2xpYy5v +cmcudHcKLmNhdGh2b2ljZS5vcmcudHcKfHxjYXRvLm9yZwp8fGNhdHR0LmNvbQp8 +fGNhdXMuY29tCi5jYmMuY2EKfHxjYmMuY2EKLmNic25ld3MuY29tL3ZpZGVvCi5j +YnRjLm9yZy5oawp8fHNvdXRocGFyay5jYy5jb20KIS0uY2NjLmRlCiEtfHxjY2Mu +ZGUKfHxjY2NhdC5jYwp8fGNjY2F0LmNvCnx8Y2NmZC5vcmcudHcKLmNjaGVyZS5j +b20KfHxjY2hlcmUuY29tCi5jY2ltLm9yZwouY2NsaWZlLmNhCmNjbGlmZS5vcmcK +fHxjY2xpZmUub3JnCmNjbGlmZWZsLm9yZwp8fGNjbGlmZWZsLm9yZwouY2N0aGVy +ZS5jb20KfHxjY3RoZXJlLmNvbQp8fGNjdGhlcmUubmV0Ci5jY3Rtd2ViLm5ldAou +Y2N0b25nYmFvLmNvbS9hcnRpY2xlLzIwNzg3MzIKY2N1ZS5jYQpjY3VlLmNvbQou +Y2N2b2ljZS5jYQouY2N3Lm9yZy50dwouY2dkZXBvdC5vcmcKfGh0dHA6Ly9jZ2Rl +cG90Lm9yZwp8fGNkYm9vay5vcmcKLmNkZWYub3JnCnx8Y2RlZi5vcmcKfHxjZGln +LmluZm8KY2RqcC5vcmcKfHxjZGpwLm9yZwohLS0uY2RuLWFwcGxlLmNvbQohLS18 +fGNkbi1hcHBsZS5jb20KLmNkbmV3cy5jb20udHcKY2RwMTk4OS5vcmcKY2RwMTk5 +OC5vcmcKfHxjZHAxOTk4Lm9yZwpjZHAyMDA2Lm9yZwp8fGNkcDIwMDYub3JnCnx8 +Y2RwZXUub3JnCnx8Y2RwdWsuY28udWsKfHxjZHB3ZWIub3JnCnx8Y2Rwd2ViLm9y +Zwp8fGNkcHd1Lm9yZwp8fGNkdy5jb20KfHxjZWNjLmdvdgp8fGNlbGx1bG8uaW5m +bwp8fGNlbmV3cy5ldQp8fGNlbnRlcmZvcmh1bWFucmVwcm9kLmNvbQp8fGNlbnRy +YWxuYXRpb24uY29tCi5jZW50dXJ5cy5uZXQKfGh0dHA6Ly9jZW50dXJ5cy5uZXQK +LmNmaGtzLm9yZy5oawouY2Zvcy5kZQp8fGNmci5vcmcKLmNmdGZjLmNvbQouY2dz +dC5lZHUKLmNoYW5nZS5vcmcKfHxjaGFuZ2Uub3JnCi5jaGFuZ3AuY29tCnx8Y2hh +bmdwLmNvbQp8fGNoYW5uZWxuZXdzYXNpYS5jb20KfHxjaGFud29ybGQub3JnCnx8 +Y2hhb3Muc29jaWFsCnx8Y2hhcmFjdGVyLmFpCnx8Y2hhdGdwdC5jb20KLmNoYXR1 +cmJhdGUuY29tCnx8Y2hhdHVyYmF0ZS5jb20KLmNodWFuZy15ZW4ub3JnCnx8Y2hl +Y2tnZncuY29tCnx8Y2hlbmdtaW5nbWFnLmNvbQp8fGNoZW5ndWFuZ2NoZW5nLmNv +bQp8fGNoZW5wb2tvbmcuY29tCnx8Y2hlbnBva29uZ3ZpcC5jb20KfHxjaGVycnlz +YXZlLmNvbQp8fGNoaG9uZ2JpLm9yZwp8fGNoaW5hLXdlZWsuY29tCnx8Y2hpbmEx +MDEuY29tCnx8Y2hpbmExOC5vcmcKfHxjaGluYTIxLmNvbQp8fGNoaW5hMjEub3Jn +Cnx8Y2hpbmE1MDAwLnVzCnx8Y2hpbmFhZmZhaXJzLm9yZwp8fGNoaW5hYWlkLnVz +Cnx8Y2hpbmFhaWQub3JnCnx8Y2hpbmFhaWQubmV0Cnx8Y2hpbmFjaGFuZ2Uub3Jn +Cnx8Y2hpbmFjaGFubmVsLmhrCnx8Y2hpbmFkZW1vY3JhdHMub3JnCnx8Y2hpbmFk +aWFsb2d1ZS5uZXQKfHxjaGluYWRpZ2l0YWx0aW1lcy5uZXQKfHxjaGluYWVsZWN0 +aW9ucy5vcmcKfHxjaGluYWZpbGUuY29tCnx8Y2hpbmFmcmVlcHJlc3Mub3JnCi5j +aGluYWdhdGUuY29tCmNoaW5hZ2Z3Lm9yZwp8fGNoaW5hZ2Z3Lm9yZwouY2hpbmFn +b25ldC5jb20KLmNoaW5haG9yaXpvbi5vcmcKfHxjaGluYWhvcml6b24ub3JnCi5j +aGluYWh1c2guY29tCi5jaGluYWlucGVyc3BlY3RpdmUuY29tCmNoaW5hbGFib3J3 +YXRjaC5vcmcKY2hpbmFsYXd0cmFuc2xhdGUuY29tCi5jaGluYXBvc3QuY29tLnR3 +L3RhaXdhbi9uYXRpb25hbC9uYXRpb25hbC1uZXdzCmNoaW5hbGF3YW5kcG9saWN5 +LmNvbQouY2hpbmFtdWxlLmNvbQp8fGNoaW5hbXVsZS5jb20KY2hpbmFtei5vcmcK +LmNoaW5hbmV3c2NlbnRlci5jb20KfGh0dHBzOi8vY2hpbmFuZXdzY2VudGVyLmNv +bQouY2hpbmFwcmVzcy5jb20ubXkKfHxjaGluYXByZXNzLmNvbS5teQouY2hpbmEt +cmV2aWV3LmNvbS51YQp8aHR0cDovL2NoaW5hLXJldmlldy5jb20udWEKLmNoaW5h +cmlnaHRzaWEub3JnCmNoaW5hc21pbGUubmV0L2ZvcnVtcwpjaGluYXNvY2lhbGRl +bW9jcmF0aWNwYXJ0eS5jb20KfHxjaGluYXNvY2lhbGRlbW9jcmF0aWNwYXJ0eS5j +b20KY2hpbmFzb3VsLm9yZwp8fGNoaW5hc291bC5vcmcKLmNoaW5hc3Vja3MubmV0 +Cnx8Y2hpbmF0b3BzZXguY29tCi5jaGluYXRvd24uY29tLmF1CmNoaW5hd2F5Lm9y +ZwouY2hpbmF3b3JrZXIuaW5mbwp8fGNoaW5hd29ya2VyLmluZm8KY2hpbmF5b3V0 +aC5vcmcuaGsKY2hpbmVzZS1sZWFkZXJzLm9yZwp8fGNoaW5lc2UtbWVtb3JpYWwu +b3JnCi5jaGluZXNlZGFpbHkuY29tCnx8Y2hpbmVzZWRhaWx5bmV3cy5jb20KLmNo +aW5lc2VkZW1vY3JhY3kuY29tCnx8Y2hpbmVzZWRlbW9jcmFjeS5jb20KfHxjaGlu +ZXNlZ2F5Lm9yZwouY2hpbmVzZW4uZGUKfHxjaGluZXNlbi5kZQp8fGNoaW5lc2Vu +ZXdzLm5ldC5hdQouY2hpbmVzZXBlbi5vcmcKfHxjaGluZXNlcmFkaW9zZWF0dGxl +LmNvbQp8fGNoaW5lc2V1cHJlc3MuY29tCi5jaGluZ2NoZW9uZy5jb20KfHxjaGlu +Z2NoZW9uZy5jb20KLmNoaW5tYW4ubmV0CnxodHRwOi8vY2hpbm1hbi5uZXQKY2hp +dGh1Lm9yZwp8fGNubmV3cy5jaG9zdW4uY29tCi5jaHJkbmV0LmNvbQp8aHR0cDov +L2NocmRuZXQuY29tCi5jaHJpc3RpYW5mcmVlZG9tLm9yZwp8fGNocmlzdGlhbmZy +ZWVkb20ub3JnCmNocmlzdGlhbnN0dWR5LmNvbQp8fGNocmlzdGlhbnN0dWR5LmNv +bQpjaHJpc3R1c3JleC5vcmcvd3d3MS9zZGMKLmNodWJvbGQuY29tCmNodWJ1bi5j +b20KfHxjaHJpc3RpYW50aW1lcy5vcmcuaGsKLmNocmxhd3llcnMuaGsKfHxjaHJs +YXd5ZXJzLmhrCi5jaHVyY2hpbmhvbmdrb25nLm9yZy9iNS9pbmRleC5waHAKfGh0 +dHA6Ly9jaHVyY2hpbmhvbmdrb25nLm9yZy9iNS9pbmRleC5waHAKLmNodXNoaWdh +bmdkcnVnLmNoCi5jaWVuZW4uY29tCi5jaW5lYXN0ZW50cmVmZi5kZQouY2lwZmcu +b3JnCnx8Y2lyb3NhbnRpbGxpLmNvbQouY2l0aXplbmNuLmNvbQp8fGNpdGl6ZW5j +bi5jb20KfHxjaXRpemVubGFiLmNhCnx8Y2l0aXplbmxhYi5vcmcKLmNpdGl6ZW5s +YWIub3JnCmNpdGl6ZW5zcmFkaW8ub3JnCi5jaXR5MzY1LmNhCnxodHRwOi8vY2l0 +eTM2NS5jYQpjaXR5OXguY29tCnx8Y2l0eXBvcHVsYXRpb24uZGUKLmNpdHl0YWxr +LnR3L2V2ZW50Ci5jaXZpY3BhcnR5LmhrCnx8Y2l2aWNwYXJ0eS5oawpjaXZpbGhy +ZnJvbnQub3JnCnx8Y2l2aWxocmZyb250Lm9yZwouY2l2aWxpYW5ndW5uZXIuY29t +Ci5jaXZpbG1lZGlhLnR3Cnx8Y2l2aWxtZWRpYS50dwp8fGNpdml0YWkuY29tCi5j +azEwMS5jb20KfHxjazEwMS5jb20KLmNsYXJpb25wcm9qZWN0Lm9yZy9uZXdzL2lz +bGFtaWMtc3RhdGUtaXNpcy1pc2lsLXByb3BhZ2FuZGEKfHxjbGFzc2ljYWxndWl0 +YXJibG9nLm5ldAouY2xiLm9yZy5oawpjbGVhcmhhcm1vbnkubmV0CmNsZWFyd2lz +ZG9tLm5ldAp8fGNsaW5pY2EtdGliZXQucnUKLmNsaXBmaXNoLmRlCnx8YXBwLmNs +b3VkY29uZS5jb20KfHxjbG91ZGZsYXJlLWlwZnMuY29tCnx8Y2x1YjEwNjkuY29t +Cnx8Y2x1YmhvdXNlYXBpLmNvbQp8fGNtZWdyb3VwLmNvbQp8fGNtaS5vcmcudHcK +fGh0dHA6Ly93d3cuY21vaW5jLm9yZwpjbXAuaGt1LmhrCnx8Y211bGUuY29tCnx8 +Y21zLmdvdgp8aHR0cDovL3Zwbi5jbXUuZWR1CnxodHRwOi8vdnBuLnN2LmNtdS5l +ZHUKLmNuNi5ldQouY25hLmNvbS50dwp8fGNuYS5jb20udHcKLmNuYWJjLmNvbQou +Y25kLm9yZwp8fGNuZC5vcmcKZG93bmxvYWQuY25ldC5jb20KLmNuZXgub3JnLmNu +Ci5jbmluZXUuY29tCi5jbm4uY29tL3ZpZGVvCi5jbnBvbGl0aWNzLm9yZwp8fGNu +cG9saXRpY3Mub3JnCi5jbi1wcm94eS5jb20KfGh0dHA6Ly9jbi1wcm94eS5jb20K +LmNucHJveHkuY29tCm5ld3MuY255ZXMuY29tCnx8Y29hdC5jby5qcAp8fGNvY2hp +bmEub3JnCnx8Y29kZXNoYXJlLmlvCnx8Y29kZXNrdWxwdG9yLm9yZwp8fGNvZmFj +dHMudHcKfHxjb25vaGEuanAKfGh0dHA6Ly90b3NoLmNvbWVkeWNlbnRyYWwuY29t +CmNvbWVmcm9tY2hpbmEuY29tCnx8Y29tZWZyb21jaGluYS5jb20KLmNvbWljLW1l +Z2EubWUKY29tbWFuZGFybXMuY29tCnx8Y29tbWVudHNoay5jb20KLmNvbW11bmlz +dGNyaW1lcy5vcmcKfHxjb21tdW5pc3RjcmltZXMub3JnCnx8Y29tbXVuaXR5Y2hv +aWNlY3UuY29tCnx8Y29tcGFyaXRlY2guY29tCnx8Y29tcGlsZWhlYXJ0LmNvbQp8 +fGNvbm9oYS5qcAouY29udGFjdG1hZ2F6aW5lLm5ldAouY29udmlvLm5ldAp8fGNv +b2wxOC5jb20KLmNvb2xhbGVyLmNvbQp8fGNvb2xhbGVyLmNvbQpjb29sZGVyLmNv +bQp8fGNvb2xkZXIuY29tCnx8Y29vbGxvdWQub3JnLnR3Ci5jb29sbmN1dGUuY29t +Cnx8Y29vbHN0dWZmaW5jLmNvbQpjb3J1bWNvbGxlZ2UuY29tCi5jb3MtbW9lLmNv +bQp8aHR0cDovL2Nvcy1tb2UuY29tCi5jb3NwbGF5amF2LnBsCnxodHRwOi8vY29z +cGxheWphdi5wbAouY290d2VldC5jb20KfHxjb3R3ZWV0LmNvbQouY291cnNlaGVy +by5jb20KfHxjb3Vyc2VoZXJvLmNvbQpjcGoub3JnCnx8Y3BqLm9yZwouY3E5OS51 +cwp8aHR0cDovL2NxOTkudXMKY3JhY2tsZS5jb20KfHxjcmFja2xlLmNvbQouY3Jh +enlzLmNjCi5jcmF6eXNoaXQuY29tCnx8Y3JhenlzaGl0LmNvbQp8fGNyY2hpbmEu +b3JnCmNyZC1uZXQub3JnCmNyZWFkZXJzLm5ldAp8fGNyZWFkZXJzLm5ldAouY3Jl +YWRlcnNuZXQuY29tCnx8Y3Jpc3R5bGkuY29tCnx8Y3JveHlwcm94eS5jb20KLmNy +b2NvdHViZS5jb20KfGh0dHA6Ly9jcm9jb3R1YmUuY29tCi5jcm9zc3Zwbi5uZXQK +fHxjcm9zc3Zwbi5uZXQKfHxjcnVjaWFsLmNvbQp8fGJsb2cuY3J5cHRvZ3JhcGh5 +ZW5naW5lZXJpbmcuY29tCmNzZHBhcnR5LmNvbQp8fGNzZHBhcnR5LmNvbQp8fGNz +aXMub3JnCnx8Y3Ntb25pdG9yLmNvbQp8fGNzdWNoZW4uZGUKfHxjc3cub3JnLnVr +Cnx8Y3Qub3JnLnR3Ci5jdGFvLm9yZwp8fGN0aXR2LmNvbS50dwp8fGN0b3djLm9y +Zwp8fGN0cy5jb20udHcKfHxjdHdhbnQuY29tCnxodHRwOi8vbGlicmFyeS51c2Mu +Y3Voay5lZHUuaGsvCnxodHRwOi8vbWpsc2gudXNjLmN1aGsuZWR1LmhrLwouY3Vo +a2Fjcy5vcmcvfmJlbm5nCi5jdWl3ZWlwaW5nLm5ldAp8fGN1aXdlaXBpbmcubmV0 +Cnx8Y3VsdHVyZS50dwouY3VtbG91ZGVyLmNvbQp8fGN1bWxvdWRlci5jb20KfHxj +dXJ2ZWZpc2guY29tCnx8Y3VzcC5oawouY3V0c2NlbmVzLm5ldAp8fGN1dHNjZW5l +cy5uZXQKLmN3LmNvbS50dwp8fGN3LmNvbS50dwp8aHR0cDovL2ZvcnVtLmN5YmVy +Y3RtLmNvbQpjeWJlcmdob3N0dnBuLmNvbQp8fGN5YmVyZ2hvc3R2cG4uY29tCnx8 +Y3luc2NyaWJlLmNvbQp8fGlmYW4uY3ouY2MKfHxtaWtlLmN6LmNjCnx8bmljLmN6 +LmNjCgohLS0tLS0tLS0tLS0tLS0tLS0tLS1ERC0tLS0tLS0tLS0tLS0tLS0tLS0t +LS0tLS0KfHxkZW5vLmRldgp8fGRvY3MuZGVuby5jb20KfHxkb29tOS5vcmcKfHxk +d2ViLmxpbmsKfHxkb2NrZXIuaW8KfHxkaXNuZXlwbHVzLmNvbQp8fGRkZXguaW8K +fHxkLmNhc2gKfHxkb3ViaXl1bmJhY2t1cC5jb20KfHxjbG91ZC5kaWZ5LmFpCi5k +LWZ1a3l1LmNvbQp8aHR0cDovL2QtZnVreXUuY29tCi5kMTAwLm5ldAp8fGQxMDAu +bmV0Ci5kMmJheS5jb20KfGh0dHA6Ly9kMmJheS5jb20KLmRhYnIuY28udWsKfHxk +YWJyLmNvLnVrCmRhYnIuZXUKZGFici5tb2JpCnx8ZGFici5tb2JpCnx8ZGFici5t +ZQpkYWRhemltLmNvbQp8fGRhZGF6aW0uY29tCi5kYWRpMzYwLmNvbQouZGFmYWJl +dC5jb20KZGFmYWdvb2QuY29tCmRhZmFoYW8uY29tCi5kYWZvaC5vcmcKLmRhZnRw +b3JuLmNvbQouZGFnZWxpamtzZXN0YW5kYWFyZC5ubAouZGFpZG9zdHVwLnJ1Cnxo +dHRwOi8vZGFpZG9zdHVwLnJ1Cnx8ZGFpbHltYWlsLmNvLnVrCi5kYWlseW1vdGlv +bi5jb20KfHxkYWlseW1vdGlvbi5jb20KfHxkYWlseXNhYmFoLmNvbQouZGFqaXl1 +YW4uY29tCnx8ZGFqaXl1YW4uZGUKZGFqaXl1YW4uZXUKZGFsYWlsYW1hLmNvbQou +ZGFsYWlsYW1hLm1uCnxodHRwOi8vZGFsYWlsYW1hLm1uCi5kYWxhaWxhbWEucnUK +fHxkYWxhaWxhbWEucnUKZGFsYWlsYW1hODAub3JnCi5kYWxhaWxhbWEtYXJjaGl2 +ZXMub3JnCi5kYWxhaWxhbWFjZW50ZXIub3JnCnxodHRwOi8vZGFsYWlsYW1hY2Vu +dGVyLm9yZwpkYWxhaWxhbWFmZWxsb3dzLm9yZwouZGFsYWlsYW1hZmlsbS5jb20K +LmRhbGFpbGFtYWZvdW5kYXRpb24ub3JnCi5kYWxhaWxhbWFoaW5kaS5jb20KLmRh +bGFpbGFtYWluYXVzdHJhbGlhLm9yZwouZGFsYWlsYW1hamFwYW5lc2UuY29tCi5k +YWxhaWxhbWFwcm90ZXN0ZXJzLmluZm8KLmRhbGFpbGFtYXF1b3Rlcy5vcmcKLmRh +bGFpbGFtYXRydXN0Lm9yZwouZGFsYWlsYW1hdmlzaXQub3JnLm56Ci5kYWxhaWxh +bWF3b3JsZC5jb20KfHxkYWxhaWxhbWF3b3JsZC5jb20KZGFsaWFubWVuZy5vcmcK +fHxkYWxpYW5tZW5nLm9yZwouZGFsaXVsaWFuLm9yZwp8fGRhbGl1bGlhbi5vcmcK +LmRhbmtlNGNoaW5hLm5ldAp8fGRhbmtlNGNoaW5hLm5ldApkYW9sYW4ubmV0Cnx8 +ZGFycmVubGl1d2VpLmNvbQp8fGRhc2hsYW5lLmNvbQp8fGRhdW0ubmV0Ci5kYXZp +ZC1raWxnb3VyLmNvbQp8aHR0cDovL2RhdmlkLWtpbGdvdXIuY29tCmRheGEuY24K +fHxkYXhhLmNuCi5kYXlsaWZlLmNvbS90b3BpYy9kYWxhaV9sYW1hCnx8ZGIudHQK +fHxkYmdqZC5jb20KfHxkY2FyZC50dwpkY21pbGl0YXJ5LmNvbQp8fGRkYy5jb20u +dHcKfHxkZWFkaG91c2Uub3JnCnx8ZGVhZGxpbmUuY29tCnx8ZGVlcGFpLm9yZwp8 +fGRlY29kZXQuY28KCiEtLU9yaWdpbjpjZG4taTMwJF8KIS0tRXhjZXB0aW9uOiBI +b21lcGFnZSBhY2Nlc3Mgd2l0aG91dCByc3QKIS0tS2V5d29yZCBpcyAkXwouZGVm +aW5lYmFiZS5jb20KCnx8ZGVsY2FtcC5uZXQKZGVsaWNpb3VzLmNvbS9HRldib29r +bWFyawouZGVtb2NyYXRzLm9yZwp8fGRlbW9jcmF0cy5vcmcKLmRlbW9zaXN0by5o +awp8fGRlbW9zaXN0by5oawp8fGRlc2Muc2UKfHxkZXNzY2kuY29tCi5kZXN0cm95 +LWNoaW5hLmpwCnx8ZGV1dHNjaGUtd2VsbGUuZGUKfHxkZXZpYW50YXJ0LmNvbQp8 +fGRldmlhbnRhcnQubmV0Cnx8ZGV2aW8udXMKfHxkZXZwbi5jb20KfHxkZXZ2LmFp +CmRmbi5vcmcKZGhhcm1ha2FyYS5uZXQKLmRoYXJhbXNhbGFuZXQuY29tCi5kaWFv +eXVpc2xhbmRzLm9yZwp8fGRpYW95dWlzbGFuZHMub3JnCi5kaWZhbmd3ZW5nZS5v +cmcKfGh0dHA6Ly9kaWdpbGFuZC50dy8KLmRpaWdvLmNvbQp8fGRpaWdvLmNvbQou +ZGlwaXR5LmNvbQp8fGRpcmVjdGNyZWF0aXZlLmNvbQohLS18fGRpc2NvZ3MuY29t +CiEtLUBAfHxjZG4uZGlzY29ncy5jb20KLmRpc2N1c3MuY29tLmhrCnx8ZGlzY3Vz +cy5jb20uaGsKLmRpc2N1c3M0dS5jb20KfHxkaXNwLmNjCi5kaXNxdXMuY29tCnx8 +ZGlzcXVzLmNvbQouZGl0LWluYy51cwp8fGRpdC1pbmMudXMKfHxkaXlpbi5vcmcK +LmRpemhpZGl6aGkuY29tCnx8ZGl6aHV6aGlzaGFuZy5jb20KZGphbmdvc25pcHBl +dHMub3JnCnx8ZGwtbGFieS5qcAp8fGRsaXZlLnR2Cnx8ZGxzaXRlLmNvbQp8fGRs +eW91dHViZS5jb20KfHxkbWMubmljbwp8fGRtY2RuLm5ldAouZG5zY3J5cHQub3Jn +Cnx8ZG5zY3J5cHQub3JnCnx8ZG5zMmdvLmNvbQp8fGRuc3NlYy5uZXQKZG9jdG9y +dm9pY2Uub3JnCgohLS1Eb2dGYXJ0TmV0d29yawouZG9nZmFydG5ldHdvcmsuY29t +L3RvdXIKZ2xvcnlob2xlLmNvbQoKLmRvamluLmNvbQp8fGRvbGMuZGUKfHxkb2xm +Lm9yZy5oawouZG9tYWluLmNsdWIudHcKLmRvbWFpbnRvZGF5LmNvbS5hdQpjaGlu +ZXNlLmRvbmdhLmNvbQpkb25ndGFpd2FuZy5jb20KfHxkb25ndGFpd2FuZy5jb20K +LmRvbmd0YWl3YW5nLm5ldAp8fGRvbmd0YWl3YW5nLm5ldAouZG9uZ3lhbmdqaW5n +LmNvbQp8fGRhbmJvb3J1LmRvbm1haS51cwouZG9udGZpbHRlci51cwp8fGRvb3No +by5jb20KfHxkb291cmJlc3Qub3JnCi5kb3JqZXNodWdkZW4uY29tCi5kb3RwbGFu +ZS5jb20KfHxkb3RwbGFuZS5jb20KfHxkb3RzdWIuY29tCi5kb3R2cG4uY29tCnx8 +ZG90dnBuLmNvbQouZG91Yi5pbwp8fGRvdWIuaW8KfHxkb3VibGV0aGlua2xhYi5v +cmcKfHxkb3Vnc2NyaXB0cy5jb20KfHxkb3VqaW5jYWZlLmNvbQp8aHR0cHM6Ly9i +YXJ0ZW5kZXIuZG93am9uZXMuY29tCmRwaGsub3JnCmRwcC5vcmcudHcKfHxkcHAu +b3JnLnR3Cnx8ZHByLmluZm8KfHxkcmFnb25zcHJpbmdzLm9yZwohLS18fGRyYXcu +aW8KLmRyZWFtYW1hdGV1cnMuY29tCi5kcmVwdW5nLm9yZwp8fGRyZ2FuLm5ldAp8 +fGRyb3Bib29rcy50dgp8fGRyb3Bib3guY29tCnx8ZHJvcGJveGFwaS5jb20KfHxk +cm9wYm94dXNlcmNvbnRlbnQuY29tCi5kcnR1YmVyLmNvbQouZHNjbi5pbmZvCnxo +dHRwOi8vZHNjbi5pbmZvCi5kc3RrLmRrCnxodHRwOi8vZHN0ay5kawp8fGR0aWJs +b2cuY29tCnx8ZHRpYy5taWwKLmR1Y2tkdWNrZ28uY29tCnx8ZHVja2R1Y2tnby5j +b20KLmR1Y2tsb2FkLmNvbS9kb3dubG9hZAp8fGR1Y2tteWxpZmUuY29tCi5kdWdh +LmpwCnxodHRwOi8vZHVnYS5qcAouZHVpaHVhLm9yZwp8fGR1aWh1YS5vcmcKfHxk +dWlodWFocmpvdXJuYWwub3JnCmR1cGluZy5uZXQKfHxkdXBsaWNhdGkuY29tCmR1 +cG9sYS5jb20KZHVwb2xhLm5ldAouZHVzaGkuY2EKfHxkdXlhb3NzLmNvbQp8fGR2 +b3Jhay5vcmcKLmR3LmNvbQp8fGR3LmNvbQp8fGR3LmRlCi5kdy13b3JsZC5jb20K +fHxkdy13b3JsZC5jb20KLmR3LXdvcmxkLmRlCnxodHRwOi8vZHctd29ybGQuZGUK +d3d3LmR3aGVlbGVyLmNvbQpkd25ld3MuY29tCnx8ZHduZXdzLmNvbQpkd25ld3Mu +bmV0Cnx8ZHduZXdzLm5ldAp4eXMuZHhpb25nLmNvbQp8fGR5bmF3ZWJpbmMuY29t +Cnx8ZHlzZnouY2MKLmR6emUuY29tCgohLS0tLS0tLS0tLS0tLS0tLS0tLS1FRS0t +LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KfHxlNjIxLm5ldAp8fGVkeC1jZG4ub3Jn +Cnx8ZXZlcmlwZWRpYS5vcmcKfHxlcG9jaHRpbWVzLmNvbS50dwp8fGV0aGVyc2Nh +bi5jb20KfHxlbGNvbmZpZGVuY2lhbC5jb20KfHxlLWNsYXNzaWNhbC5jb20udHcK +fHxlLWdvbGQuY29tCi5lLWdvbGQuY29tCi5lLWhlbnRhaS5vcmcKfHxlLWhlbnRh +aS5vcmcKLmUtaGVudGFpZGIuY29tCnxodHRwOi8vZS1oZW50YWlkYi5jb20KZS1p +bmZvLm9yZy50dwouZS16b25lLmNvbS5oay9kaXNjdXoKfGh0dHA6Ly9lLXpvbmUu +Y29tLmhrL2Rpc2N1egouZTEyMy5oawp8fGUxMjMuaGsKLmVhcmx5dGliZXQuY29t +CnxodHRwOi8vZWFybHl0aWJldC5jb20KLmVhcnRoY2FtLmNvbQouZWFydGh2cG4u +Y29tCnx8ZWFydGh2cG4uY29tCnx8ZWFzdGFzaWFmb3J1bS5vcmcKLmVhc3Rlcm5s +aWdodG5pbmcub3JnCi5lYXN0dHVya2VzdGFuLmNvbQp8aHR0cDovL3d3dy5lYXN0 +dHVya2lzdGFuLm5ldC8KLmVhc3R0dXJraXN0YW4tZ292Lm9yZwouZWFzdHR1cmtp +c3RhbmNjLm9yZwouZWFzdHR1cmtpc3RhbmdvdmVybm1lbnRpbmV4aWxlLnVzCnx8 +ZWFzdHR1cmtpc3RhbmdvdmVybm1lbnRpbmV4aWxlLnVzCi5lYXN5Y2EuY2EKLmVh +c3lwaWMuY29tCnx8Zm5jLmViYy5uZXQudHcKfHxuZXdzLmViYy5uZXQudHcKLmVi +b255LWJlYXV0eS5jb20KZWJvb2ticm93c2UuY29tCmVib29rZWUuY29tCnx8ZWNm +YS5vcmcudHcKfHxlY2ltZy50dwplY21pbmlzdHJ5Lm5ldAouZWNvbm9taXN0LmNv +bQpiYnMuZWNzdGFydC5jb20KZWRnZWNhc3RjZG4ubmV0Cnx8ZWRnZWNhc3RjZG4u +bmV0Ci90d2ltZ1wuZWRnZXN1aXRlXC5uZXRcL1wvP2FwcGxlZGFpbHkvCmVkaWN5 +cGFnZXMuY29tCi5lZG1vbnRvbmNoaW5hLmNuCi5lZG1vbnRvbnNlcnZpY2UuY29t +CmVkb29ycy5jb20KLmVkdWJyaWRnZS5jb20KfHxlZHVicmlkZ2UuY29tCi5lZHVw +cm8ub3JnCnx8ZWV2cG4uY29tCmVmY2Mub3JnLmhrCi5lZnVrdC5jb20KfGh0dHA6 +Ly9lZnVrdC5jb20KfHxlaWMtYXYuY29tCnx8ZWlyZWluaWtvdGFlcnVrYWkuY29t +Ci5laXNiYi5jb20KLmVrc2lzb3psdWsuY29tCnx8ZWtzaXNvemx1ay5jb20KZWxl +Y3Rpb25zbWV0ZXIuY29tCnx8ZWxnb29nLmltCi5lbHBhaXMuY29tCnx8ZWxwYWlz +LmNvbQouZWx0b25kaXNuZXkuY29tCi5lbWFnYS5jb20vaW5mby8zNDA3CmVtaWx5 +bGF1Lm9yZy5oawouZW1hbm5hLmNvbS9jaGluZXNlVHJhZGl0aW9uYWwKLmVtcGZp +bC5jb20KLmVtdWxlLWVkMmsuY29tCnxodHRwOi8vZW11bGUtZWQyay5jb20KLmVt +dWxlZmFucy5jb20KfGh0dHA6Ly9lbXVsZWZhbnMuY29tCi5lbXVwYXJhZGlzZS5t +ZQouZW5hbnlhbmcubXkKIS0tLmVuYW55YW5nLm15L25ld3MvMjAxNzA1MDIvJUU3 +JUJFJThFJUU1JTlCJUJEJUU0JUI5JThCJUU5JTlGJUIzJUU1JUE0JUE3JUU1JTlD +JUIwJUU5JTlDJTg3JUUzJTgwJThBJUU4JThCJUI5JUU2JTlFJTlDJUUzJTgwJThC +JUU3JThCJUFDJUU1JUFFJUI2Cnx8ZW5jcnlwdC5tZQp8fGVuZXdzdHJlZS5jb20K +LmVuZmFsLmRlCnx8Y2hpbmVzZS5lbmdhZGdldC5jb20KZW5nbGlzaGZvcmV2ZXJ5 +b25lLm9yZwp8fGVuZ2xpc2hmcm9tZW5nbGFuZC5jby51awplbmdsaXNocGVuLm9y +ZwouZW5saWdodGVuLm9yZy50dwp8fGVudGVybWFwLmNvbQouZXBpc2NvcGFsY2h1 +cmNoLm9yZwouZXBvY2hoay5jb20KfHxlcG9jaGhrLmNvbQplcG9jaHRpbWVzLWJn +LmNvbQp8fGVwb2NodGltZXMtYmcuY29tCmVwb2NodGltZXMtcm9tYW5pYS5jb20K +fHxlcG9jaHRpbWVzLXJvbWFuaWEuY29tCmVwb2NodGltZXMuY28uaWwKfHxlcG9j +aHRpbWVzLmNvLmlsCmVwb2NodGltZXMuY28ua3IKfHxlcG9jaHRpbWVzLmNvLmty +CmVwb2NodGltZXMuY29tCnx8ZXBvY2h0aW1lcy5jb20KLmVwb2NodGltZXMuY3oK +fHxlcG9jaHRpbWVzLmRlCnx8ZXBvY2h0aW1lcy5mcgp8fGVwb2NodGltZXMuaXQK +fHxlcG9jaHRpbWVzLmpwCnx8ZXBvY2h0aW1lcy5ydQp8fGVwb2NodGltZXMuc2UK +fHxlcG9jaHRpbWVzdHIuY29tCi5lcG9jaHdlZWsuY29tCnx8ZXBvY2h3ZWVrLmNv +bQp8fGVwb2Nod2Vla2x5LmNvbQp8fGVwb3JuZXIuY29tCi5lcXVpbmVub3cuY29t +CmVyYWJhcnUubmV0Ci5lcmFjb20uY29tLnR3Ci5lcmF5c29mdC5jb20udHIKLmVy +ZXB1Ymxpay5jb20KLmVyaWdodHMubmV0Cnx8ZXJpZ2h0cy5uZXQKfHxlcm5lc3Rt +YW5kZWwub3JnCnx8ZXJvZGFpemVuc3l1LmNvbQp8fGVyb2RvdWppbmxvZy5jb20K +fHxlcm9kb3VqaW53b3JsZC5jb20KfHxlcm9tYW5nYS1raW5nZG9tLmNvbQp8fGVy +b21hbmdhZG91emluLmNvbQouZXJvbW9uLm5ldAp8aHR0cDovL2Vyb21vbi5uZXQK +LmVyb3Byb2ZpbGUuY29tCi5lcm90aWNzYWxvb24ubmV0Ci5lc2xpdGUuY29tCnx8 +ZXNsaXRlLmNvbQouZXRhYS5vcmcuYXUKLmV0YWR1bHQuY29tCmV0YWl3YW5uZXdz +LmNvbQp8fGV0aXplci5vcmcKfHxldG9ra2kuY29tCnx8ZXRzeS5jb20KLmV0dG9k +YXkubmV0CmV0dm9ubGluZS5oawouZXVjYXNpbm8uY29tCi5ldWxhbS5jb20KLmV1 +cmVrYXZwdC5jb20KfHxldXJla2F2cHQuY29tCi5ldXJvbmV3cy5jb20KfHxldXJv +bmV3cy5jb20KZWVhcy5ldXJvcGEuZXUvZGVsZWdhdGlvbnMvY2hpbmEvcHJlc3Nf +Y29ybmVyL2FsbF9uZXdzL25ld3MvMjAxNS8yMDE1MDcxNl96aAplZWFzLmV1cm9w +YS5ldS9zdGF0ZW1lbnRzLWVlYXMvMjAxNS8xNTEwMjIKfHxhcHBzLmV2b3ppLmNv +bQp8fGV2c2Nob29sLm5ldAp8fGV4YmxvZy5qcApAQHx8d3d3LmV4YmxvZy5qcAou +ZXhjaHJpc3RpYW4uaGsKfHxleGNocmlzdGlhbi5oawp8aHR0cDovL2Jsb2cuZXhj +aXRlLmNvLmpwCnx8ZXhoZW50YWkub3JnCnx8ZXhtb3Jtb24ub3JnCnx8ZXhwYXRz +aGllbGQuY29tCi5leHBlY3RoaW0uY29tCnx8ZXhwZWN0aGltLmNvbQpleHBlcnRz +LXVuaXZlcnMuY29tCnx8ZXhwbG9hZGVyLm5ldAouZXhwcmVzc3Zwbi5jb20KfHxl +eHByZXNzdnBuLmNvbQouZXh0cmVtZXR1YmUuY29tCmV5ZXZpby5qcAp8fGV5ZXZp +by5qcAouZXlueS5jb20KfHxleW55LmNvbQouZXpwZWVyLmNvbQoKIS0tLS0tLS0t +LS0tLS0tLS0tLS0tRkYtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnx8ZmVlZGx5 +LmNvbQp8fGZ1Y2tjY3AueHl6Cnx8ZnVja2NjcC5jb20KfHxmdXJyeWJhci5jb20K +fHxmb3JiZXMuY29tCnx8ZmluYW5jaWFsZXhwcmVzcy5jb20KfHxmYXN0LmNvbQp8 +fGZhY3RjaGVja2xhYi5vcmcKfHxmdC5jb20KfHxmdWNoc2lhLmRldgp8fGZyZWVz +cy5vcmcKfHxmcmlsLmpwCnx8ZnJlZS5jb20udHcKfHxmcm90aC56b25lCnx8ZmFu +Ym94LmNjCnx8ZnJlZS5iZwp8fGYtZHJvaWQub3JnCnx8ZmFjZWJvb2txdW90ZXM0 +dS5jb20KLmZhY2VsZXNzLm1lCnx8ZmFjZWxlc3MubWUKfGh0dHA6Ly9mYWNlc29m +dGliZXRhbnNlbGZpbW1vbGF0b3JzLmluZm8KfHxmYWNlc29mbnlmdy5jb20KfHxm +YWN0cGVkaWEub3JnCi5mYWl0aDEwMC5vcmcKfGh0dHA6Ly9mYWl0aDEwMC5vcmcK +CiEtLUVuaGFuY2VtZW50OgohLS1odHRwOi8vZmFpdGhmdWxleWUuY29tLmRldGFp +bC53ZWJzaXRlLwohLS1odHRwOi8vZmFpdGhmdWxleWUuY29tLmlwYWRkcmVzcy5j +b20vCi5mYWl0aGZ1bGV5ZS5jb20KCnx8ZmFpdGh0aGVkb2cuaW5mbwouZmFra3Uu +bmV0Cnx8ZmFsbGVuYXJrLmNvbQouZmFsc2VmaXJlLmNvbQp8fGZhbHNlZmlyZS5j +b20KZmFsdW4tY28ub3JnCmZhbHVuYXJ0Lm9yZwp8fGZhbHVuYXNpYS5pbmZvCnxo +dHRwOi8vZmFsdW5hdS5vcmcKLmZhbHVuYXoubmV0CmZhbHVuZGFmYS5vcmcKZmFs +dW5kYWZhLWRjLm9yZwp8fGZhbHVuZGFmYS1mbG9yaWRhLm9yZwp8fGZhbHVuZGFm +YS1uYy5vcmcKfHxmYWx1bmRhZmEtcGEubmV0CmZhbHVuLW55Lm5ldAp8fGZhbHVu +ZGFmYWluZGlhLm9yZwpmYWx1bmRhZmFtdXNldW0ub3JnCi5mYWx1bmdvbmcuY2x1 +YgouZmFsdW5nb25nLmRlCmZhbHVuZ29uZy5vcmcudWsKfHxmYWx1bmhyLm9yZwpm +YWx1bmluZm8uZGUKZmFsdW5pbmZvLm5ldAouZmFsdW5waWxpcGluYXMubmV0CmZh +bWlseWZlZC5vcmcKLmZhbmdlbWluZy5jb20KfHxmYW5nbGl6aGkuaW5mbwp8fGZh +bmdvbmcub3JnCmZhbmdvbmdoZWlrZS5jb20KfHxmYW5oYW9sb3UuY29tCi5mYW5x +aWFuZy50awpmYW5xaWFuZ2hvdS5jb20KfHxmYW5xaWFuZ2hvdS5jb20KLmZhbnFp +YW5nemhlLmNvbQp8fGZhbnFpYW5nemhlLmNvbQp8fGZhbnR2LmhrCmZhcGR1LmNv +bQpmYXByb3h5LmNvbQohLS0uZmFyeGlhbi5jb20KLmZhd2FuZ2h1aWh1aS5vcmcK +fHxmYW11bmlvbi5jb20KLmZhbi1xaWFuZy5jb20KZmFuZ2VtaW5nLmNvbQouZmFu +aGFvZGFuZy5jb20KfHxmYW5xaWFuZy5uZXR3b3JrCnx8ZmFuc3dvbmcuY29tCi5m +YW55dWUuaW5mbwouZmFyd2VzdGNoaW5hLmNvbQoKIS0tRmFzdGx5CmVuLmZhdm90 +dGVyLm5ldAohLS18fHJudy5nbG9iYWwuc3NsLmZhc3RseS5uZXQKLmdsb2JhbC5z +c2wuZmFzdGx5Lm5ldAp8fGZyZWV0bHMuZmFzdGx5Lm5ldApueXRpbWVzLm1hcC5m +YXN0bHkubmV0Cnx8bnl0aW1lcy5tYXAuZmFzdGx5Lm5ldAp8fGZhc3Qud2lzdGlh +LmNvbQoKfHxmYXN0ZXN0dnBuLmNvbQp8fGZhc3Rzc2guY29tCnx8ZmFzdHN0b25l +Lm9yZwpmYXZzdGFyLmZtCnx8ZmF2c3Rhci5mbQpmYXlkYW8uY29tL3dlYmxvZwp8 +fGZhei5uZXQKLmZjMi5jb20KLmZjMmNoaW5hLmNvbQouZmMyY24uY29tCnx8ZmMy +Y24uY29tCmZjMmJsb2cubmV0CnxodHRwOi8vdXlndXIuZmMyd2ViLmNvbS8KLmZk +YzY0LmRlCi5mZGM2NC5vcmcKLmZkYzg5LmpwCiEtLWZlZWRib29rcy5tb2JpCnx8 +ZmVlZGVyLmNvCnx8ZmVlbHNzaC5jb20KZmVlci5jb20KfGh0dHA6Ly9mZWl0aWFu +YWNhZGVteS5vcmcKLmZlaXRpYW4tY2FsaWZvcm5pYS5vcmcKfHxmZWl4aWFvaGFv +LmNvbQp8fGZlbWluaXN0dGVhY2hlci5jb20KLmZlbmd6aGVuZ2h1LmNvbQp8fGZl +bmd6aGVuZ2h1LmNvbQouZmVuZ3poZW5naHUubmV0Cnx8ZmVuZ3poZW5naHUubmV0 +Ci5mZXZlcm5ldC5jb20KfGh0dHA6Ly9mZi5pbQpmZmZmZi5hdApmZmxpY2suY29t +Ci5mZnZwbi5jb20KZmdtdHYubmV0Ci5mZ210di5vcmcKLmZocmVwb3J0cy5uZXQK +fGh0dHA6Ly9maHJlcG9ydHMubmV0Ci5maWdwcmF5ZXIuY29tCnx8ZmlncHJheWVy +LmNvbQouZmlsZWZseWVyLmNvbQp8fGZpbGVmbHllci5jb20KfGh0dHA6Ly9mZWVk +cy5maWxlZm9ydW0uY29tCi5maWxlc2VydmUuY29tL2ZpbGUKZmlsbHRoZXNxdWFy +ZS5vcmcKZmlsbWluZ2ZvcnRpYmV0Lm9yZwouZmlsdGhkdW1wLmNvbQouZmluY2h2 +cG4uY29tCnx8ZmluY2h2cG4uY29tCiEtLWZpbmRib29rLnR3CmZpbmRtZXNwb3Qu +Y29tCnx8ZmluZHlvdXR1YmUuY29tCnx8ZmluZHlvdXR1YmUubmV0Ci5maW5nZXJk +YWlseS5jb20KLmZpcmVhcm1zd29ybGQubmV0CnxodHRwOi8vZmlyZWFybXN3b3Js +ZC5uZXQKfHxyZWxheS5maXJlZm94LmNvbQp8fGZpcmVvZmxpYmVydHkuaW5mbwp8 +fGZpcmVvZmxpYmVydHkub3JnCi5maXJldHdlZXQuaW8KfHxmaXJldHdlZXQuaW8K +fHxvcGVuLmZpcnN0b3J5Lm1lCnx8Zmlyc3Rwb3N0LmNvbQp8fGZpcnN0cmFkZS5j +b20KfHxmaXNoLmF1ZGlvCiEtLXx8ZmxhZ2ZveC5uZXQKLmZsYWdzb25saW5lLml0 +CmZsZXNoYm90LmNvbQouZmxldXJzZGVzbGV0dHJlcy5jb20KfGh0dHA6Ly9mbGV1 +cnNkZXNsZXR0cmVzLmNvbQp8fGZsZ2p1c3RpY2Uub3JnCgohLS18fGZhcm02LnN0 +YXRpY2ZsaWNrci5jb20KIS0tLmZsaWNrci5jb20vcGhvdG9zLzQ2MjMxMDc3QE4w +NgohLS0uZmxpY2tyLmNvbS9ncm91cHMvYWl3ZWl3ZWkKIS0tLmZsaWNrci5jb20v +cGhvdG9zL2RpZ2l0YWxib3kxMDAKIS0tLmZsaWNrci5jb20vcGhvdG9zL2Z6aGVu +Z2h1CiEtLS5mbGlja3IuY29tL3Bob3Rvcy9sb25lbHlmb3gKIS0tZmxpY2tyLmNv +bS9waG90b3MvdmFudmFuLzUyOTkyNTE1NwohLS0uZmxpY2tyLmNvbS9waG90b3Mv +d2ludGVya2FuYWwKIS0tLmZsaWNrci5jb20vcGhvdG9zL3pvbGEKfHxmbGlja3Iu +Y29tCnx8c3RhdGljZmxpY2tyLmNvbQoKZmxpY2tyaGl2ZW1pbmQubmV0Ci5mbGlj +a3JpdmVyLmNvbQouZmxpbmcuY29tCnx8ZmxpcGthcnQuY29tCnx8ZmxvZy50dwp8 +fGZsb3dob25na29uZy5uZXQKLmZseXZwbi5jb20KfHxmbHl2cG4uY29tCnxodHRw +Oi8vY24uZm1ubm93LmNvbQpibG9nLmZvb2xzbW91bnRhaW4uY29tCi5mb3J1bTRo +ay5jb20KZmFuZ29uZy5mb3J1bXMtZnJlZS5jb20KcGlvbmVlci13b3JrZXIuZm9y +dW1zLWZyZWUuY29tCiEtLWZvdXJzcXVhcmUuY29tCiEtLXxodHRwOi8vNHNxLmNv +bQp8aHR0cHM6Ly9zcyouNHNxaS5uZXQKdmlkZW8uZm94YnVzaW5lc3MuY29tCnxo +dHRwOi8vZm94Z2F5LmNvbQp8fGZyaW5nZW5ldHdvcmsuY29tCnx8ZmxlY2hlaW50 +aGVwZWNoZS5mcgouZm9jaGsub3JnCnx8Zm9jaGsub3JnCnx8Zm9jdXN0YWl3YW4u +dHcKLmZvY3VzdnBuLmNvbQp8fGZvZmcub3JnCi5mb29vb28uY29tCnx8Zm9vb29v +LmNvbQp8fGZvcmVpZ25hZmZhaXJzLmNvbQp8fGZvdW50bWVkaWEuaW8KfHxmb3Vy +dGhpbnRlcm5hdGlvbmFsLm9yZwp8fGZveHN1Yi5jb20KZm94dGFuZy5jb20KLmZw +bXQub3JnCnxodHRwOi8vZnBtdC5vcmcKLmZwbXQudHcKLmZwbXQtb3NlbC5vcmcK +fHxmcG10bWV4aWNvLm9yZwp8fGZxcm91dGVyLmNvbQp8fGZyYW5rMjAxOS5tZQp8 +fGZyYW5rbGMuY29tCi5mcmVha3NoYXJlLmNvbQp8aHR0cDovL2ZyZWFrc2hhcmUu +Y29tCmZyZWUtZ2F0ZS5vcmcKLmZyZWUtaGFkYS1ub3cub3JnCmZyZWUtcHJveHku +Y3oKLmZyZWUuZnIvYWRzbApraW5lb3guZnJlZS5mcgp0aWJldGxpYnJlLmZyZWUu +ZnIKfHxmcmVlYnJvd3Nlci5vcmcKLmZyZWVjaGFsLmNvbQouZnJlZWRvbWhvdXNl +Lm9yZwp8fGZyZWVkb21ob3VzZS5vcmcKLmZyZWVkb21zaGVyYWxkLm9yZwp8fGZy +ZWVkb21zaGVyYWxkLm9yZwp8fGZyZWVnYW8uY29tCmZyZWVpbGhhbXRvaHRpLm9y +Zwp8fGZyZWVrYXpha2hzLm9yZwouZnJlZWxvdHRvLmNvbQp8fGZyZWVsb3R0by5j +b20KZnJlZW1hbjIuY29tCi5mcmVlb3BlbnZwbi5jb20KZnJlZW1vcmVuLmNvbQpm +cmVlbW9yZW5ld3MuY29tCmZyZWVtdXNlLm9yZy9hcmNoaXZlcy83ODkKZnJlZW5l +dC1jaGluYS5vcmcKZnJlZW5ld3Njbi5jb20KY24uZnJlZW9uZXMuY29tCi5mcmVl +b3oub3JnL2Jicwp8fGZyZWVvei5vcmcKfHxmcmVlc3NoLnVzCnx8ZnJlZWJlYWNv +bi5jb20KLmZyZWVjaGluYS5uZXdzCnx8ZnJlZWNoaW5hd2VpYm8uY29tCi5mcmVl +ZG9tY29sbGVjdGlvbi5vcmcvaW50ZXJ2aWV3cy9yZWJpeWFfa2FkZWVyCi5mcmVl +Zm9ydW1zLm9yZwp8fGZyZWVuZXRwcm9qZWN0Lm9yZwouZnJlZW96Lm9yZwouZnJl +ZXRpYmV0Lm5ldAp8fGZyZWV0aWJldC5vcmcKLmZyZWV0aWJldGFuaGVyb2VzLm9y +Zwp8aHR0cDovL2ZyZWV0aWJldGFuaGVyb2VzLm9yZwp8fGZyZWV0cmliZS5tZQou +ZnJlZXZpZXdtb3ZpZXMuY29tCi5mcmVldnBuLm1lCnxodHRwOi8vZnJlZXZwbi5t +ZQp8fGZyZWV3YWxscGFwZXI0Lm1lCi5mcmVld2Vicy5jb20KLmZyZWV3ZWNoYXQu +Y29tCnx8ZnJlZXdlY2hhdC5jb20KZnJlZXdlaWJvLmNvbQp8fGZyZWV3ZWliby5j +b20KLmZyZWV4aW53ZW4uY29tCnx8ZnJlZXpoaWh1Lm9yZwp8fGZyaWVuZGZlZWQu +Y29tCnx8ZnJpZW5kcy1vZi10aWJldC5vcmcKLmZyaWVuZHNvZnRpYmV0Lm9yZwp8 +fGZyaWVuZHNvZnRpYmV0Lm9yZwpmcmVlY2hpbmEubmV0CnxodHRwOi8vd3d3Lnpl +bnN1ci5mcmVlcmsuY29tLwpmcmVldnBuLm5sCmZyZWV5ZWxsb3cuY29tCmhrLmZy +aWVuZGR5LmNvbS9oawp8aHR0cDovL2FkdWx0LmZyaWVuZGZpbmRlci5jb20vCi5m +cmluZy5jb20KfHxmcmluZy5jb20KLmZyb21jaGluYXRvdXNhLm5ldAp8fGZyb21t +ZWwubmV0Ci5mcm9udGxpbmVkZWZlbmRlcnMub3JnCnx8ZnJvbnRsaW5lZGVmZW5k +ZXJzLm9yZwouZnJvb3R2cG4uY29tCnx8ZnJvb3R2cG4uY29tCnx8ZnNja2VkLm9y +ZwouZnN1cmYuY29tCi5mdHYuY29tLnR3Cnx8ZnR2LmNvbS50dwp8fGZ0dm5ld3Mu +Y29tLnR3CmZ1Y2QuY29tCmZ1Y2tnZncub3JnCi5mdWxpb25lLmNvbQp8aHR0cHM6 +Ly9mdWxpb25lLmNvbQp8fGZ1bGxlcmNvbnNpZGVyYXRpb24uY29tCnx8ZnVsbHNl +cnZpY2VnYW1lLmNvbQouZnVuZi50dwpmdW5wLmNvbQouZnVxLmNvbQouZnVyaGhk +bC5vcmcKfHxmdXJpbmthbi5jb20KLmZ1dHVyZWNoaW5hZm9ydW0ub3JnCnx8ZnV0 +dXJlbWVzc2FnZS5vcmcKLmZ1eC5jb20KLmZ1eWluZGlhbnRhaS5vcmcKLmZ1eXUu +b3JnLnR3Cnx8ZncuY20KLmZ4Y20tY2hpbmVzZS5jb20KfHxmeGNtLWNoaW5lc2Uu +Y29tCgohLS0tLS0tLS0tLS0tLS0tLS0tLS1HRy0tLS0tLS0tLS0tLS0tLS0tLS0t +LS0tLS0KfHxnaXRsYWIubmV0CnxodHRwOi8vZ21wNC5jb20KfHxnZXRzZXNzaW9u +Lm9yZwp8fGdkYWlseS5vcmcKfHxnZndhdGNoLm9yZwp8fGdvLXRvLXpsaWJyYXJ5 +LnNlCnx8Z2l0Ym9vay5pbwouZzZoZW50YWkuY29tCnxodHRwOi8vZzZoZW50YWku +Y29tCnx8Zy1xdWVlbi5jb20KfHxnYWIuY29tCnx8Z2Fib2NvcnAuY29tCi5nYWVw +cm94eS5jb20KLmdhZm9ydW0ub3JnCi5nYWdhb29sYWxhLmNvbQp8fGdhZ2Fvb2xh +bGEuY29tCi5nYWxheHltYWNhdS5jb20KfHxnYWxlbnd1LmNvbQouZ2Fsc3RhcnMu +bmV0Cnx8Z2FtZTczNS5jb20KZ2FtZWJhc2UuY29tLnR3CmdhbWVqb2x0LmNvbQp8 +aHR0cDovL3dpa2kuZ2FtZXJwLmpwCnx8Z2FtZXIuY29tLnR3Ci5nYW1lci5jb20u +dHcKLmdhbWV6LmNvbS50dwp8fGdhbWV6LmNvbS50dwouZ2Ftb3VzYS5jb20KLmdh +b21pbmcubmV0Cnx8Z2FvbWluZy5uZXQKZ2FuZ2VzLmNvbQp8fGdhbmppbmcuY29t +Cnx8Z2FuamluZ3dvcmxkLmNvbQouZ2FvcGkubmV0CnxodHRwOi8vZ2FvcGkubmV0 +CmdhcmRlbm5ldHdvcmtzLmNvbQp8fGdhcmRlbm5ldHdvcmtzLm9yZwohLS1JUCBv +ZiBHYXJkZW4gTmV0d29yawo3Mi41Mi44MS4yMgp8fGdhcnRsaXZlLmNvbQp8fGdh +dGhlci5jb20KLmdhdGhlcnByb3h5LmNvbQouZ2F5YnViYmxlLmNvbQouZ2F5Y24u +bmV0Ci5nYXlodWIuY29tCnx8Z2F5bWFwLmNjCi5nYXltZW5yaW5nLmNvbQouZ2F5 +dHViZS5jb20KIS0tfHxnYXl0dWJlLmNvbQp8fGltYWdlcy1nYXl0dWJlLmNvbQou +Z2F5d2F0Y2guY29tCnxodHRwOi8vZ2F5d2F0Y2guY29tCi5nYXpvdHViZS5jb20K +fHxnYXpvdHViZS5jb20KfHxnY2Mub3JnLmhrCnx8Z2NsdWJzLmNvbQp8fGdjbWFz +aWEuY29tCi5nY3BuZXdzLmNvbQp8aHR0cDovL2djcG5ld3MuY29tCmdkemYub3Jn +Cnx8Z2Vlay1hcnQubmV0CmdlZWtlcmhvbWUuY29tLzIwMTAvMDMveGl4aWFuZy1w +cm9qZWN0LWNyb3NzLWdmdwouZ2VraWthbWUuY29tCnxodHRwOi8vZ2VraWthbWUu +Y29tCi5nZWxib29ydS5jb20KfGh0dHA6Ly9nZWxib29ydS5jb20KfHxnZW5lcmF0 +ZWQucGhvdG9zCnx8Z2VuaXVzLmNvbQohLS18fGdlbnVpdGVjLmNvbQouZ2VvY2l0 +aWVzLmNvLmpwCi5nZW9jaXRpZXMuY29tL1NpbGljb25WYWxsZXkvQ2lyY3VpdC81 +NjgzL2Rvd25sb2FkLmh0bWwKaGsuZ2VvY2l0aWVzLmNvbQpnZW9jaXRpZXMuanAK +fHxnZXBoLmlvCi5nZXJlZm91bmRhdGlvbi5vcmcKfHxnZXRhc3RyaWxsLmNvbQou +Z2V0Y2h1LmNvbQouZ2V0Y2xvYWsuY29tCnx8Z2V0Y2xvYWsuY29tCnx8Z2V0Zm94 +eXByb3h5Lm9yZwp8fGdldGdvbS5jb20KLmdldGkycC5uZXQKfHxnZXRpMnAubmV0 +CmdldGl0b24uY29tCi5nZXRqZXRzby5jb20vZm9ydW0KLmdldGxhbnRlcm4ub3Jn +Cnx8Z2V0bGFudGVybi5vcmcKfHxnZXRtYWx1cy5jb20KLmdldHNvY2lhbHNjb3Bl +LmNvbQp8fGdldHN5bmMuY29tCnx8Z2V0dHIuY29tCmdmYnYuZGUKLmdmc2FsZS5j +b20KfHxnZnNhbGUuY29tCi5nZncucHJlc3MKfHxnZncucHJlc3MKfHxnZncucmVw +b3J0Ci5nZ3NzbC5jb20KfHxnZ3NzbC5jb20KIS0tfHxnaG9zdC5vcmcKLmdob3N0 +cGF0aC5jb20KfHxnaG9zdHBhdGguY29tCnx8Z2h1dC5vcmcKLmdpYW50ZXNzbmln +aHQuY29tCnxodHRwOi8vZ2lhbnRlc3NuaWdodC5jb20KLmdpZnJlZS5jb20KfHxn +aWdhLXdlYi5qcAp0dy5naWdhY2lyY2xlLmNvbQpnaWdwb3Juby5ydQp8fGdpcmxi +YW5rZXIuY29tCi5naXQuaW8KfHxnaXQuaW8KfGh0dHA6Ly9zb2Z0d2FyZWRvd25s +b2FkLmdpdGJvb2tzLmlvCnx8cmF3LmdpdGhhY2suY29tCgohLS0tR2l0SHViLS0t +Cnx8Z2l0aHViLmJsb2cKfHxnaXRodWIuY29tCnx8Z2l0aHViY29waWxvdC5jb20K +IS0tZ2l0aHViLmNvbS9nZXRsYW50ZXJuCiEtLXxodHRwczovL2dpc3QuZ2l0aHVi +LmNvbQohLS1odHRwOi8vY3RobG8uZ2l0aHViLmlvL2hrdHYKIS0taGFoYXhpeGku +Z2l0aHViLmlvCiEtLXxodHRwczovL2hhaGF4aXhpLmdpdGh1Yi5pbwohLS18fGhh +b2VsLmdpdGh1Yi5pbwohLS18aHR0cDovL29uaW9uaGFja2VyLmdpdGh1Yi5pbwoh +LS18fHJnMy5naXRodWIuaW8KIS0tfHxzaWthb3poZTE5OTcuZ2l0aHViLmlvCiEt +LXx8c29kYXRlYS5naXRodWIuaW8KIS0tfHx0ZXJtaW51czIwNDkuZ2l0aHViLmlv +CiEtLXx8dG91dHlyYXRlci5naXRodWIuaW8KIS0td3NnemFvLmdpdGh1Yi5pbwoh +LS18aHR0cHM6Ly93c2d6YW8uZ2l0aHViLmlvCi5naXRodWIuaW8KfHxnaXRodWIu +aW8KfHxnaXRodWJ1c2VyY29udGVudC5jb20KfHxnaXRodWJhc3NldHMuY29tCgou +Z2l6bGVuLm5ldAp8fGdpemxlbi5uZXQKLmdqY3p6LmNvbQp8fGdqY3p6LmNvbQp8 +fGdsYXJpdHkuYXBwCnx8Z2xvYmFsamloYWQubmV0Cmdsb2JhbG1lZGlhb3V0cmVh +Y2guY29tCmdsb2JhbG11c2V1bW9uY29tbXVuaXNtLm9yZwp8fGdsb2JhbHJlc2N1 +ZS5uZXQKLmdsb2JhbHRtLm9yZwouZ2xvYmFsdm9pY2Vzb25saW5lLm9yZwp8fGds +b2JhbHZvaWNlc29ubGluZS5vcmcKfHxnbG9iYWx2cG4ubmV0Ci5nbG9jay5jb20K +Z2x1Y2ttYW4uY29tL0RhbGFpTGFtYQp8fGdtZ2FyZC5jb20KfGh0dHA6Ly93d3cu +Z21pZGRsZS5jb20KfGh0dHA6Ly93d3cuZ21pZGRsZS5uZXQKLmdtbGwub3JnCnx8 +c3VjaGUuZ214Lm5ldAp8fGduY2kub3JnLmhrCnx8Z25ld3Mub3JnCnx8Z29hZ2Vu +dC5iaXoKfHxnb2RhZGR5LmNvbQpnb2Rmb290c3RlcHMub3JnCnx8Z29kZm9vdHN0 +ZXBzLm9yZwpnb2RzZGlyZWN0Y29udGFjdC5jby51awouZ29kc2RpcmVjdGNvbnRh +Y3Qub3JnCmdvZHNkaXJlY3Rjb250YWN0Lm9yZy50dwouZ29kc2ltbWVkaWF0ZWNv +bnRhY3QuY29tCnx8Z29mdW5kbWUuY29tCnx8Z29oYXBweS5jb20udHcKLmdva2Jh +eXJhay5jb20KLmdvbGRiZXQuY29tCnx8Z29sZGJldHNwb3J0cy5jb20KfHxnb2xk +ZW4tYWdlcy5vcmcKfHxnb2xkZW5leWV2YXVsdC5jb20KLmdvbGRlbmZyb2cuY29t +Cnx8Z29sZGVuZnJvZy5jb20KLmdvbGRzdGVwLm5ldAp8fGdvbGR3YXZlLmNvbQp8 +fGdvbmdtLmluCmJsb2cuZ29vLm5lLmpwL2R1Y2stdGFpbF8yMDA5Cmdvb2QubmV3 +cwouZ29vZGF5Lnh5egp8fGdvb2RheS54eXoKfHxnb29kaG9wZS5zY2hvb2wKfHxn +b29kbmV3c25ldHdvcmsub3JnCi5nb29kcmVhZHMuY29tCnx8Z29vZHJlYWRzLmNv +bQouZ29vZHJlYWRlcnMuY29tCnx8Z29vZHJlYWRlcnMuY29tCi5nb29kdHYuY29t +LnR3Ci5nb29kdHYudHYKfHxnb29maW5kLmNvbQouZ29wZXRpdGlvbi5jb20KfHxn +b3BldGl0aW9uLmNvbQp8fGdvcmVmb3J1bS5jb20KfHxnb3RxdWVzdGlvbnMub3Jn +Ci5nb3RydXN0ZWQuY29tCnx8Z290cnVzdGVkLmNvbQp8fGdvdHcuY2EKfHxncmFt +bWFseS5jb20KZ3JhbmR0cmlhbC5vcmcKLmdyYXBoaXMubmUuanAKfHxncmFwaGlz +Lm5lLmpwCnx8Z3JhcGhxbC5vcmcKfHxncmF2YXRhci5jb20KZ3JlYXRmaXJld2Fs +bC5iaXoKLmdyZWF0ZmlyZXdhbGxvZmNoaW5hLm9yZwp8fGdyZWF0ZmlyZXdhbGxv +ZmNoaW5hLm9yZwouZ3JlZW5wYXJ0eS5vcmcudHcKfHxncmVlbnBlYWNlLm9yZwou +Z3JlZW5yZWFkaW5ncy5jb20vZm9ydW0KfHxncmVhc3lmb3JrLm9yZwpncmVhdHJv +Yy5vcmcKZ3JlYXR6aG9uZ2h1YS5vcmcKLmdyZWVucGVhY2UuY29tLnR3Ci5ncmVl +bnZwbi5uZXQKfHxncmVlbnZwbi5uZXQKLmdyZWVudnBuLm9yZwp8fGdyaW5kci5j +b20KfHxncm91bmQubmV3cwpncy1kaXNjdXNzLmNvbQp8fGdzZWFyY2gubWVkaWEK +fHxndHJpY2tzLmNvbQpndWFuY2hhLm9yZwouZ3VhcmRzdGVyLmNvbQouZ3VuLXdv +cmxkLm5ldApndW5zYW5kYW1tby5jb20KfHxndXR0ZXJ1bmNlbnNvcmVkLmNvbQp8 +fGd2bS5jb20udHcKfHxnd2lucy5vcmcKLmd6bS50dgp8fGd6b25lLWFuaW1lLmlu +Zm8KCiEtLS0tLS0tLS0tLS0tR0hTLS0tLS0KIS18fGZlZWRzLmNic25ld3MuY29t +CiEtfHx3d3cuY2hpbmVzZWFsYnVtYXJ0LmNvbQp8fGNsZW1lbnRpbmUtcGxheWVy +Lm9yZwohLXx8Y2xlbWVzaGEub3JnCiEtfHx3d3cuY2xvdWRnaXJsZnJpZW5kLmNv +bQohLXx8Y29jb2F3aXRobG92ZS5jb20KIS18fGJsb2cuY29udHJvbHNwYWNlLm9y +ZwohLUQKIS18fHd3dy5kYWlseWd5YW4uY29tCiEtfHxkYWlseXRvZG8ub3JnCiEt +fHxibG9nLmRhbm1hcm5lci5jb20KIS18fGdpdGh1Yi5kYW5tYXJuZXIuY29tCiEt +fHxkZXNpZ24tc2VlZHMuY29tCiEtfHxkZXNpZ25lcnMtYXJ0aXN0cy5jb20KIS18 +fG1haWwuZGl5YW5nLm9yZwohLXx8YmxvZy5kb3VnaGVsbG1hbm4uY29tCiEtfHxk +b3duZm9yZXZlcnlvbmVvcmp1c3RtZS5jb20KIS18fGRyb2lkc2VjdXJpdHkuY29t +CiEtfHx3d3cuZHJvcG1vY2tzLmNvbQohLXx8ZHVtYmxpdHRsZW1hbi5jb20KIS1F +CmVjaG9mb24uY29tCiEtfHxlY2hvZm9uLmNvbQohLXx8ZXBjLWphdi5jb20KIS18 +fGV2ZXJkYXJrLmluZm8KIS18fGV2aGVhZC5jb20KIS1GCiEtfHxmYWNpbGVsb2dp +bi5jb20KIS18fCouZmF0ZHVjay5vcmcKIS18fGJsb2cuZmRjbi5vcmcKIS18fGZm +dG9nby5jb20KIS18fGZsaWdodHNpbXRhbGsuY29tCiEtfHxtY2xlZS5mb29sbWUu +bmV0CiEtfHx3d3cuZnJpZW5kZGVjay5jb20KIS18fGZyaW5nZXNwb2lsZXJzLmNv +bQohLXx8ZnJpbmdldGVsZXZpc2lvbi5jb20KIS18fGZ1bnBlYS5jb20KIS1HCiEt +fHxibG9nLmdhdGVpbi5vcmcKIS18fGZlZWRzLmdhd2tlci5jb20KIS18fGdlZWt0 +YW5nLmNvbQohLXx8Z2VvaG90LnVzCiEtfHxnZXRhcm91bmQuY29tCiEtfHxnbWVy +Lm5ldAohLXx8d3d3Lmdtb3RlLm9yZwohLXx8YmxvZy5nbzJ3ZWIyMC5uZXQKIS18 +fGdvb2dsZS1tZWxhbmdlLmNvbQohLXx8ZmFtZS5nb256b2xhYnMub3JnCiEtfHxn +b3ZlY24ub3JnCiEtfHxncXVldWVzLmNvbQohLXx8Z3JhcGh5Y2FsYy5jb20KIS18 +fGJsb2cuZ3Jvd2xmb3J3aW5kb3dzLmNvbQohLUgKIS18fGhjbS5jb20udHcKIS18 +fGJsb2cuaGVhZGl1cy5jb20KIS18fGhvZ2JheXNvZnR3YXJlLmNvbQohLXx8Ymxv +Zy5ob3RvdC5vcmcKIS18fGZlZWRzLmhvd3N0dWZmd29ya3MuY29tCiEtfHxodWhh +aXRhaS5jb20KIS18fGJsb2cuaHVtYW5yaWdodHNmaXJzdC5vcmcKIS1JCiEtfHxz +aXRlLmljdS1wcm9qZWN0Lm9yZwohLXx8aWdvcndhcmUuY29tCiEtfHxpaGFzMTMz +N2NvZGUuY29tCiEtfHxpbmtub3V2ZWF1LmNvbQohLXx8aW5vdGUudHcKIS18fGly +b25oZWxtZXQuY29tCiEtfHxpd2Z3Y2YuY29tCiEtSgohLXx8YmxvZy5qYW5nbXQu +Y29tCiEtfHxibG9nLmpheWZpZWxkcy5jb20KIS18fGJsb2cuam9pbnQubmV0CiEt +fHxibG9nLmpzcXVhcmVkamF2YXNjcmlwdC5jb20KIS18fGJsb2cuanRid29ybGQu +Y29tCiEtSwohLXx8a2F0aHlzY2h3YWxiZS5jb20KIS18fHRvbWF0b3Zwbi5rZWl0 +aG1veWVyLmNvbQohLXx8d3d3LmtlaXRobW95ZXIuY29tCiEtfHxrZW5kYWx2YW5k +eWtlLmNvbQohLXx8YmxvZy5rZW5nYW8udHcKIS18fGxvZy5rZXNvLmNuCiEtfHx3 +d3cua2hhbmFjYWRlbXkub3JnCnx8d3d3LmtsaXAubWUKIS18fHVzYmxvYWRlcmd4 +LmtvdXJlaW8ubmV0CiEtfHxibG9nLmtvd2FsY3p5ay5pbmZvCiEtTAohLXx8bGFi +eXJpbnRoMi5jb20KIS18fGxhcnNnZW9yZ2UuY29tCiEtfHxibG9nLmxhc3RwYXNz +LmNvbQohLXx8ZG9jcy5sYXRleGxhYi5vcmcKIS18fGxlYW5lc3NheXMuY29tCiEt +fHxibG9nLmxpZGFvYmluZy5pbmZvCiEtfHxsb2cubGlnaHRvcnkubmV0CiEtfHxm +ZWVkcy5saW1pLm5ldAohLXx8d3d3LmxpdGVhcHBsaWNhdGlvbnMuY29tCiEtfHxi +bG9nLmxpdWthbmd4dS5pbmZvCiEtfHx0d2l0dGVyLmxpdWthbmd4dS5pbmZvCiEt +fHxvYXNpc25ld3Nyb29tLmxpdmU0ZXZlci51cwohLXx8d3d3LmxvY2tlcmdub21l +LmNvbQohLXx8bG9jcWwuY29tCkBAfHxzaXRlLmxvY3FsLmNvbQohLXx8ZmVlZHMu +bG9pY2xlbWV1ci5jb20KIS18fGJsb2cubG91aXNncmF5LmNvbQohLU0KIS18fG1h +ZGVieXNvZmEuY29tCiEtfHxtYWRlbW9pc2VsbGVyb2JvdC5jb20KIS18fG1hc2Ft +aXhlcy5jb20KIS18fHd3dy5tZXRhbXVzZS5uZXQKIS18fGJsb2cubWV0YXNwbG9p +dC5jb20KIS18fG1pbGF6aS5jb20KIS18fHd3dy5taW5pd2VhdGhlci5jb20KIS18 +fHR3aXR0ZXIubWlzc2l1LmNvbQohLXx8cGx1cmt0b3AtYnV0dG9uLm1tZGF5cy5j +b20KIS18fGZlZWRzLm1vYmlsZXJlYWQuY29tCiEtfHx3d3cubW9kZXJuaXpyLmNv +bQohLXx8d3d3Lm1vZGsuaXQKIS18fG15dHdpc2hpcnQuY29tCiEtTgohLXx8Ymxv +Zy5uZXRmbGl4LmNvbQohLXx8YmxvZy5uaWhpbG9naWMuZGsKIS18fG50bGsub3Jn +CiEtfHxudnF1YW4ub3JnCiEtfHxub2dvb2RhdGNvZGluZy5jb20KIS18fGJsb2cu +bm90ZG90Lm5ldAohLXx8d3d3Lm5vdGlmeS5pbwohLU8KIS18fGJsb2cub2J2aW91 +cy5jb20KIS18fG9uZWJpZ2ZsdWtlLmNvbQohLXx8b3ZlcnN0aW11bGF0ZS5jb20K +IS1QCiEtfHxwY2dlZWtibG9nLmNvbQohLXx8ZmVlZHMucGRmY2htLm5ldAohLXx8 +ZmVlZHMucGVvcGxlLmNvbQohLXx8YmxvZy5wZXJzaXN0ZW50LmluZm8KIS18fGNo +cm9tZS5wbGFudHN2c3pvbWJpZXMuY29tCiEtfHxwb3J0YWJsZXNvZnQub3JnLnJ1 +CiEtfHxwcmFzYW5uYXRlY2gubmV0CiEtfHx0YWxrLm5ld3MucHRzLm9yZy50dwoh +LXx8cHl0aG9uLWV4Y2VsLm9yZwohLVEKIS1SCiEtfHxyLWNoYXJ0LmNvbQohLXx8 +cmFtZXNoc3VicmFtYW5pYW4ub3JnCiEtfHxyYXBpZC5wawohLXx8YmxvZy5yZW5h +bnNlLmNvbQohLXx8cm9iZXJ0bWFvLmNvbQohLXx8d3d3LnJvbWVvLWZveHRyb3Qu +Y29tCiEtUwohLXx8c2FsbWl5dWNrLmNvbQohLXx8c2Ftc2FsLmNvbQohLXx8Ymxv +Zy5zZWVtaW5nbGVlLmNvbQohLXx8YmxvZy5zZmxvdy5jb20KIS18fGJsb2cuc2ln +ZnBlLmNvbQohLXx8c2ltcGxldGV4dC53cwohLXx8d3d3LnNrdWxwdC5vcmcKIS18 +fHJzcy5zbGFzaGRvdC5vcmcKIS18fHNuaXBwZXRzYXBwLmNvbQohLXx8dy5zbnMu +bHkKIS18fHd3dy5zb2NpYWxubW9iaWxlLmNvbQohLXx8d3d3LnNvY2lhbHdob2lz +LmNvbQohLXx8c3Bpcml0amIub3JnCiEtfHxzc2Jvb2suY29tCiEtfHxzc2hmb3J3 +YXJkaW5nLmNvbQohLXx8c3RhdGlvbmVyaWEuY29tCnx8c3RlcGhhbmllcmVkLmNv +bQohLXx8c3Vuamlkb25nLm5ldAohLXx8c3luaXVtc29mdHdhcmUuY29tCkBAfHxk +b3dubG9hZC5zeW5pdW1zb2Z0d2FyZS5jb20KIS1UCiEtfHx0YWd4ZWRvLmNvbQoh +LXx8YmxvZy50YXRvZWJhLm9yZwohLXx8d3d3LnRlY2hmb2IuY29tCiEtfHx0ZWFj +aHBhcmVudHN0ZWNoLm9yZwohLXx8dGhlOHBlbi5jb20KIS18fHRoZWlwaG9uZXdp +a2kuY29tCiEtfHxibG9nLnRoZXNpbGVudG51bWJlci5tZQohLXx8dGhlc3BvbnR5 +LmNvbQohLXx8dGhldWx0cmFsaW54LmNvbQohLXx8YmxvZy50aGluay1hc3luYy5j +b20KIS18fHRvcm5hZG93ZWIub3JnCiEtfHx0cmFuc3BhcmVudHVwdGltZS5jb20K +IS18fHRyaWFuZ3VsYXRpb25ibG9nLmNvbQohLXx8YmxvZy50c3VuYW5ldC5uZXQK +IS18fGVuLnR1eGVyby5jb20KIS18fHR3YXp6dXAuY29tCiEtfHx0d2VldHN3ZWxs +LmNvbQohLXx8dHdpYmVzLmNvbQohLXx8YXJ0LnR3Z2cub3JnCiEtfHx0d2l2ZXJ0 +LmNvbQohLVUKfGh0dHA6Ly91YjAuY2MKIS18fGpvbm55LnVidW50dS10dy5uZXQK +IS18fGJsb2cudW1vbmtleS5uZXQKIS1WCiEtfHx0cC52YmFwLmNvbS5hdQohLXx8 +d3d3LnZpcnR1b3Vzcm9tLmNvbQohLXx8YmxvZy52aXNpYm90ZWNoLmNvbQohLVcK +IS18fHdhdmVwcm90b2NvbC5vcmcKIS18fHd3dy53YXZlc2FuZGJveC5jb20KIS18 +fHdlYmZlZS5vcmcucnUKIS18fGJsb2cud2VibXByb2plY3Qub3JnCiEtfHx3ZWJ1 +cGQ4Lm9yZwohLXx8d3d3LndoYXRicm93c2VyLm9yZwohLXx8d3d3LndoZXJlZG95 +b3Vnby5uZXQKIS18fHdpbGxoYWlucy5jb20KIS18fGZlZWRzLndpcmVkLmNvbQoh +LXx8d2lzZW1hcHBpbmcub3JnCndvenkuaW4KIS18fHdvenkuaW4vCiEtfHxibG9n +Lnd1bmRlcmNvdW50ZXIuY29tCiEtWAohLXx8eGRlbHRhLm9yZwohLXx8eGlhb2dh +b3ppLm9yZwohLXx8eGlsb3UudXMKIS18fHh6eS5vcmcucnUKIS1ZCiEtfHx5b29w +ZXIuYmUKIS18fHRzb25nLnl1bnhpLm5ldAohLVoKCmdvc3BlbGhlcmFsZC5jb20K +fHxnb3NwZWxoZXJhbGQuY29tCnxodHRwOi8vaGsuZ3JhZGNvbm5lY3Rpb24uY29t +LwpncmVhdGZpcmUub3JnCnx8Z3JlYXRmaXJlLm9yZwpncmVhdGZpcmV3YWxsb2Zj +aGluYS5vcmcKfHxndHYub3JnCnx8Z3R2MS5vcmcKLmd1LWNodS1zdW0ub3JnCnxo +dHRwOi8vZ3UtY2h1LXN1bS5vcmcKLmd1YWd1YXNzLmNvbQp8aHR0cDovL2d1YWd1 +YXNzLmNvbQouZ3VhbmdtaW5nLmNvbS5teQpndWlzaGFuLm9yZwp8fGd1aXNoYW4u +b3JnCi5ndW1yb2FkLmNvbQp8fGd1bXJvYWQuY29tCnx8Z3Vuc2FtZXJpY2EuY29t +Cmd1cnVvbmxpbmUuaGsKfGh0dHA6Ly9ndmxpYi5jb20KLmd5YWx3YXJpbnBvY2hl +LmNvbQouZ3lhdHNvc3R1ZGlvLmNvbQoKIS0tLS0tLS0tLS0tLS0tLS0tLS0tSEgt +LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnx8aGVyb21pbmVycy5jb20KfHxoaW5l +dC5uZXQKfHxoaW5kdXN0YW50aW1lcy5jb20KfHxoYW5pbWUxLm1lCnx8aGFsa3R2 +LmNvbS50cgp8fGhhaXdhaWthbi5jb20KfHxob21lLnNheG8KfHxob3kudHYKLmg1 +MjguY29tCi5oNWRtLmNvbQouaDVnYWxnYW1lLm1lCnx8aC1jaGluYS5vcmcKLmgt +bW9lLmNvbQp8aHR0cDovL2gtbW9lLmNvbQpoMW4xY2hpbmEub3JnCi5oYWNrZW4u +Y2MvYmJzCi5oYWNrZXIub3JnCnx8aGFja21kLmlvCnx8aGFja3RoYXRwaG9uZS5u +ZXQKaGFobG8uY29tCnx8aGFpamlhby5jb20KfHxoYWtrYXR2Lm9yZy50dwouaGFu +ZGNyYWZ0ZWRzb2Z0d2FyZS5vcmcKfGh0dHA6Ly9iYnMuaGFubWluenUub3JnLwou +aGFvLm5ld3MvbmV3cwp8aHR0cDovL2FlLmhhbzEyMy5jb20KfGh0dHA6Ly9hci5o +YW8xMjMuY29tCnxodHRwOi8vYnIuaGFvMTIzLmNvbQp8aHR0cDovL2VuLmhhbzEy +My5jb20KfGh0dHA6Ly9pZC5oYW8xMjMuY29tCnxodHRwOi8vanAuaGFvMTIzLmNv +bQp8aHR0cDovL21hLmhhbzEyMy5jb20KfGh0dHA6Ly9teC5oYW8xMjMuY29tCnxo +dHRwOi8vc2EuaGFvMTIzLmNvbQp8aHR0cDovL3RoLmhhbzEyMy5jb20KfGh0dHA6 +Ly90dy5oYW8xMjMuY29tCnxodHRwOi8vdm4uaGFvMTIzLmNvbQp8aHR0cDovL2hr +LmhhbzEyM2ltZy5jb20KfGh0dHA6Ly9sZC5oYW8xMjNpbWcuY29tCi5oYXByb3h5 +Lm9yZwp8fGhhcmRzZXh0dWJlLmNvbQp8fGIuaGF0ZW5hLm5lLmpwCmhhdmU4LmNv +bQpAQHx8aGF5Z28uY29tCi5oY2xpcHMuY29tCnx8aGR0dmIubmV0Ci5oZHpvZy5j +b20KfGh0dHA6Ly9oZHpvZy5jb20KfHxvcmRucy5oZS5uZXQKfHxoZWFydHlpdC5j +b20KLmhlYXZ5LXIuY29tCi5oZWMuc3UKfGh0dHA6Ly9oZWMuc3UKLmhlY2FpdG91 +Lm5ldAp8fGhlY2FpdG91Lm5ldAouaGVjaGFqaS5jb20KfHxoZWNoYWppLmNvbQp8 +fGhlZWFjdC5lZHUudHcKLmhlZ3JlLWFydC5jb20KfGh0dHA6Ly9oZWdyZS1hcnQu +Y29tCnx8Y2RuLmhlbGl4c3R1ZGlvcy5uZXQKfHxoZWxsb2FuZHJvaWQuY29tCnx8 +aGVsbG9xdWVlci5jb20KLmhlbnRhaS50bwouaGVsbG91ay5vcmcvZm9ydW0vbG9m +aXZlcnNpb24KLmhlbHBlYWNocGVvcGxlLmNvbQp8fGhlbHBlYWNocGVvcGxlLmNv +bQp8fGhlbHBzdGVyLmRlCi5oZWxwemh1bGluZy5vcmcKaGVudGFpdHViZS50dgou +aGVudGFpdmlkZW93b3JsZC5jb20KCiEjIyMjIyMjIyMjIy0tSGVyb2t1LS0jIyMj +IyMjIyMjCiEtLXx8Z2V0Y2xvdWRhcHAuY29tCiEtLXx8Y2wubHkKIS0tQEB8fGYu +Y2wubHkKIS0tRUMyIEROUyBQb2lzb25lZAp8fGlkLmhlcm9rdS5jb20KfHxoZXJv +a3VhcHAuY29tCgp8fGhlcWluZ2xpYW4ubmV0Cnx8aGVyaXRhZ2Uub3JnCi5oZXhp +ZXNoZS5jb20KfHxoZXhpZXNoZS5jb20KfHxoZXhpZXNoZS54eXoKIS0tR29vZ2xl +IGVtcGxveWVlIHdpdGhpbiBHb29nbGUgSVAKfHxoZXh4ZWgubmV0Cnx8aGV5dWVk +aS5jb20KLmhleXpvLmNvbQouaGdzZWF2LmNvbQouaGhkY2Izb2ZmaWNlLm9yZwou +aGh0aGVzYWt5YXRyaXppbi5vcmcKaGktb24ub3JnLnR3Cnx8aGljY2VhcnMuY29t +CmhpZGRlbi1hZHZlbnQub3JnCnx8aGlkZGVuLWFkdmVudC5vcmcKaGlkZWNsb3Vk +LmNvbS9ibG9nLzIwMDgvMDcvMjkvZnVjay1iZWlqaW5nLW9seW1waWNzLmh0bWwK +fHxoaWRlLm1lCi5oaWRlaXB2cG4uY29tCnx8aGlkZWlwdnBuLmNvbQouaGlkZW1h +bi5uZXQKfHxoaWRlbWFuLm5ldApoaWRlbWUubmwKfHxoaWRlbXkubmFtZQouaGlk +ZW15YXNzLmNvbQp8fGhpZGVteWFzcy5jb20KaGlkZW15Y29tcC5jb20KfHxoaWRl +bXljb21wLmNvbQouaGlnZncuY29tCmhpZ2hwZWFrc3B1cmVlYXJ0aC5jb20KfHxo +aWdocm9ja21lZGlhLmNvbQp8fGhpaXRjaC5jb20KfHxoaWtpbmdnZncub3JnCi5o +aWxpdmUudHYKLmhpbWFsYXlhbi1mb3VuZGF0aW9uLm9yZwp8fGhpbWFsYXlhbi1m +b3VuZGF0aW9uLm9yZwpoaW1hbGF5YW5nbGFjaWVyLmNvbQouaGltZW1peC5jb20K +fHxoaW1lbWl4LmNvbQouaGl0b21pLmxhCnxodHRwOi8vaGl0b21pLmxhCi5oaXdp +ZmkuY29tCkBAfHxoaXdpZmkuY29tCmhpemJ1dHRhaHJpci5vcmcKaGl6Yi11dC10 +YWhyaXIuaW5mbwpoaXpiLXV0LXRhaHJpci5vcmcKLmhqY2x1Yi5pbmZvCi5oay1w +dWIuY29tL2ZvcnVtCnxodHRwOi8vaGstcHViLmNvbQouaGswMS5jb20KfHxoazAx +LmNvbQp8fGhrYWNnLmNvbQp8fGhrYWNnLm5ldAouaGthdHZuZXdzLmNvbQpoa2Jj +Lm5ldAouaGtiZi5vcmcKLmhrYm9va2NpdHkuY29tCnx8aGtib29rY2l0eS5jb20K +fHxoa2Nocm9uaWNsZXMuY29tCi5oa2NodXJjaC5vcmcKaGtjaS5vcmcuaGsKLmhr +Y21pLmVkdQp8fGhrY25ld3MuY29tCnx8aGtjb2MuY29tCmhrZGF5Lm5ldAouaGtk +YWlseW5ld3MuY29tLmhrL2NoaW5hLnBocAp8fGhrZGMudXMKaGtkZi5vcmcKLmhr +ZWouY29tCi5oa2VwYy5jb20vZm9ydW0vdmlld3RocmVhZC5waHA/dGlkPTExNTMz +MjIKfHxoa2V0LmNvbQp8fGhrZmFhLmNvbQpoa2Zyb250Lm9yZwptLmhrZ2FsZGVu +LmNvbQp8aHR0cHM6Ly9tLmhrZ2FsZGVuLmNvbQp8fGhrZ3Bhby5jb20KLmhraGVh +ZGxpbmUuY29tKmJsb2cKLmhraGVhZGxpbmUuY29tL2luc3RhbnRuZXdzCmhraGto +ay5jb20KaGtocmMub3JnLmhrCmhramMuY29tCi5oa2pwLm9yZwouaGtsZnQuY29t +Ci5oa2x0cy5vcmcuaGsKfHxoa2x0cy5vcmcuaGsKfHxoa21hcC5saXZlCnx8aGtv +cGVudHYuY29tCnx8aGtwZWFudXQuY29tCmhrcHR1Lm9yZwouaGtyZXBvcnRlci5j +b20KfHxoa3JlcG9ydGVyLmNvbQouaG12LmNvLmpwLwpobmpoai5jb20KfHxobmpo +ai5jb20KLmhubnR1YmUuY29tCnx8aG9qZW1hY2F1LmNvbS5tbwp8fGhvbGEuY29t +Cnx8aG9sYS5vcmcKaG9seXNwaXJpdHNwZWFrcy5vcmcKfHxob2x5c3Bpcml0c3Bl +YWtzLm9yZwouaG9tZXBlcnZlcnNpb24uY29tCnxodHRwOi8vaG9tZXNlcnZlcnNo +b3cuY29tCnxodHRwOi8vb2xkLmhvbmV5bmV0Lm9yZy9zY2Fucy9zY2FuMzEvc3Vi +L2RvdWdfZXJpYy9zcGFtX3RyYW5zbGF0aW9uLmh0bWwKLmhvbmdrb25nZnAuY29t +Cnx8aG9uZ2tvbmdmcC5jb20KaG9uZ21laW1laS5jb20KfHxob25nemhpLmxpCnx8 +aG9udmVuLnh5egouaG9vdHN1aXRlLmNvbQp8fGhvb3RzdWl0ZS5jb20KfHxob292 +ZXIub3JnCi5ob3B0by5vcmcKLmhvcm55Z2FtZXIuY29tCi5ob3JueXRyaXAuY29t +CnxodHRwOi8vaG9ybnl0cmlwLmNvbQp8fGhvcnJvcnBvcm4uY29tCnx8aG9zdGxv +Yy5jb20KfHxob3RhaXIuY29tCi5ob3Rhdi50dgouaG90ZWxzLmNuCmhvdGZyb2cu +Y29tLnR3CmhvdGdvby5jb20KaG90cG90LmhrCi5ob3RzaGFtZS5jb20KfHxob3Rz +cG90c2hpZWxkLmNvbQp8fGhvdHRnLmNvbQouaG90dnBuLmNvbQp8fGhvdHZwbi5j +b20KfHxob3d0b2ZvcmdlLmNvbQp8fGhveHguY29tCnx8aHBqYXYuY29tCi5ocWNk +cC5vcmcKfHxocWNkcC5vcmcKfHxocWphcGFuZXNlc2V4LmNvbQpocW1vdmllcy5j +b20KLmhyY2NoaW5hLm9yZwouaHJlYS5vcmcKLmhyaWNoaW5hLm9yZwp8fGhyaWNo +aW5hLm9yZwp8fGhybnR0Lm9yZwouaHJ0c2VhLmNvbQouaHJ3Lm9yZwp8fGhydy5v +cmcKaHJ3ZWIub3JnCnx8aHNleC5tZW4KfHxoc2pwLm5ldAp8fGhzc2VsaXRlLmNv +bQp8fGhzdC5uZXQudHcKLmhzdGVybi5uZXQKLmhzdHQubmV0Ci5odGtvdS5uZXQK +fHxodGtvdS5uZXQKLmh1YWdsYWQuY29tCnx8aHVhZ2xhZC5jb20KLmh1YW5naHVh +Z2FuZy5vcmcKfHxodWFuZ2h1YWdhbmcub3JnCi5odWFuZ3lpeXUuY29tCi5odWFy +ZW4udXMKfHxodWFyZW4udXMKLmh1YXJlbjR1cy5jb20KLmh1YXNoYW5nbmV3cy5j +b20KfGh0dHA6Ly9odWFzaGFuZ25ld3MuY29tCmJicy5odWFzaW5nLm9yZwpodWF4 +aWFiYW8ub3JnCmh1YXhpbi5waAp8fGh1YXl1d29ybGQub3JnCnx8aHVmZmluZ3Rv +bnBvc3QuY29tCnx8aHVmZnBvc3QuY29tCnx8aHVnZ2luZ2ZhY2UuY28KfHxodWdv +cm95LmV1Cnx8aHVoYWl0YWkuY29tCnx8aHVoYW1oaXJlLmNvbQouaHVoYW5nZmVp +LmNvbQp8fGh1aGFuZ2ZlaS5jb20KLmh1bGtzaGFyZS5jb20KfHxodW1hbnBhcnR5 +Lm1lCnx8aHVtYW5yaWdodHNwcmVzc2F3YXJkcy5vcmcKfHxodW5nLXlhLmNvbQp8 +fGh1cGluZy5uZXQKaHVyZ29rYmF5cmFrLmNvbQouaHVycml5ZXQuY29tLnRyCi5o +dXQyLnJ1Cnx8aHV0aWFueWkubmV0Cmh1dG9uZzkubmV0Cmh1eWFuZGV4LmNvbQou +aHdhZHphbi50dwp8fGh3YXl1ZS5vcmcudHcKfHxoeHdrLm9yZwpoeHdxLm9yZwp8 +fGh5cGVycmF0ZS5jb20KfHxoeXBvdGhlcy5pcwplYm9vay5oeXJlYWQuY29tLnR3 +Cnx8ZWJvb2suaHlyZWFkLmNvbS50dwoKIS0tLS0tLS0tLS0tLS0tLS0tLS0tSUkt +LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnx8aXBpZnkub3JnCkBAfHwqLmlwaWZ5 +Lm9yZwp8fGl0aWdlci5jb20KfHxpdGNoLmlvCnx8aW5mdXJhLmlvCnx8cHJlc2lk +ZW50LmlyCnx8Z292LmlyCnx8aXJuYS5pcgp8fGFydmFuc3RvcmFnZS5pcgp8fGly +YW5nb3YuaXIKfHxpbmRpYS5jb20KfHxpbmRpYXRvZGF5LmluCnx8aW52aWRpby51 +cwp8fGltcHJvZC53b3Jrcwp8fGlsbGF3YXJyYW1lcmN1cnkuY29tLmF1Cnx8aW1h +Z28taW1hZ2VzLmNvbQp8fGkycDIuZGUKfHxpODE4aGsuY29tCi5pLWNhYmxlLmNv +bQouaS1wYXJ0LmNvbS50dwouaWFtdG9wb25lLmNvbQppYXNrLmNhCnx8aWFzay5j +YQouaWF2MTkuY29tCnx8aWF2aWFuLm5ldAppYmlibGlvLm9yZy9wdWIvcGFja2Fn +ZXMvY2NpYwppYnJvcy5vcmcKLmlidnBuLmNvbQp8fGlidnBuLmNvbQppY2Ftcy5j +b20KfHxpY2Vkcml2ZS5uZXQKLmljaWoub3JnCnx8aWNpai5vcmcKfHxpY2wtZmku +b3JnCi5pY29jby5jb20KfHxpY29jby5jb20KCiEtLTM4LjEwMy4xNjUuNTAKfHxm +dXJiby5vcmcKIS0tfHxpY29uZmFjdG9yeS5jb20KCnx8aWNvbnBhcGVyLm9yZwoh +LS0gR29vZ2xlIFBhZ2VzCnx8aWN1LXByb2plY3Qub3JnCncuaWRhaXdhbi5jb20v +Zm9ydW0KaWRlbW9jcmFjeS5hc2lhCi5pZGVudGkuY2EKfHxpZGVudGkuY2EKfHxp +ZGlvbWNvbm5lY3Rpb24uY29tCnxodHRwOi8vd3d3LmlkbGNveW90ZS5jb20KfHxp +ZG9wZS5zZQouaWRvdWdhLmNvbQouaWR2LnR3Ci5pZWQyay5uZXQKLmllbmVyZ3kx +LmNvbQp8fGlmdC50dAouaWZjc3Mub3JnCnx8aWZjc3Mub3JnCmlmamMub3JnCi5p +ZnQudHQKfGh0dHA6Ly9pZnQudHQKfHxpZnJlZXdhcmVzLmNvbQp8fGlnY2QubmV0 +Ci5pZ2Z3Lm5ldAp8fGlnZncubmV0Ci5pZ21nLmRlCi5pZ290bWFpbC5jb20udHcK +fHxpZ3ZpdGEuY29tCi5paGFvLm9yZy9kejUKfHxpaWNucy5jb20KLmlrc3Rhci5j +b20KfHxpbGhhbXRvaHRpaW5zdGl0dXRlLm9yZwp8fGlsbHVzaW9uZmFjdG9yeS5j +b20KfHxpbG92ZTgwLmJlCnx8aW04OC50dwp8fGltZ2NoaWxpLm5ldAouaW1hZ2Vh +Yi5jb20KLmltYWdlZmFwLmNvbQp8fGltYWdlZmFwLmNvbQp8fGltYWdlZmxlYS5j +b20KfHxpbWFnZWdsYXNzLm9yZwp8fGltYWdlc2hhY2sudXMKfHxpbWFnZXZlbnVl +LmNvbQp8fGltYWdlemlsbGEubmV0Ci5pbWIub3JnCnxodHRwOi8vaW1iLm9yZwoK +IS0tSU1EQgp8aHR0cDovL3d3dy5pbWRiLmNvbS9uYW1lL25tMDQ4MjczMAouaW1k +Yi5jb20vdGl0bGUvdHQwODE5MzU0Ci5pbWRiLmNvbS90aXRsZS90dDE1NDAwNjgK +LmltZGIuY29tL3RpdGxlL3R0NDkwODY0NAoKLmltZy5seQp8fGltZy5seQp8fGlt +Z2FzZC5jb20KLmltZ3VyLmNvbQp8fGltZ3VyLmNvbQouaW1rZXYuY29tCnx8aW1r +ZXYuY29tCi5pbWxpdmUuY29tCi5pbW1vcmFsLmpwCmltcGFjdC5vcmcuYXUKaW45 +OS5vcmcKaW4tZGlzZ3Vpc2UuY29tCi5pbmNhcGRucy5uZXQKLmluY2xvYWsuY29t +Cnx8aW5jbG9hay5jb20KfHxpbmNyZWRpYm94LmZyCnx8aW5kZXBlbmRlbnQuY28u +dWsKfHxpbmRpYWJsb29tcy5jb20KfHxpbmRpYW5kZWZlbnNlbmV3cy5pbgp8fGlu +ZGlhbmFycmF0aXZlLmNvbQp8fHRpbWVzb2ZpbmRpYS5pbmRpYXRpbWVzLmNvbQou +aW5kaWVtZXJjaC5jb20KfHxpbmRpZW1lcmNoLmNvbQp8fGluZm8tZ3JhZi5mcgp3 +ZWJzaXRlLmluZm9ybWVyLmNvbQp8fGluaGVyaXQubGl2ZQp8fGluaXRpYXRpdmVz +Zm9yY2hpbmEub3JnCnx8aW5rYnVubnkubmV0Cnx8aW5rdWkuY29tCnx8aW5tZWRp +YWhrLm5ldAp8fGlubWVkaWFoay5uZXQKfHxpbm9yZWFkZXIuY29tCnx8aW5vdGUu +dHcKfHxpbnNlY2FtLm9yZwp8aHR0cDovL2luc2VjYW0ub3JnCnx8aW5zaWRlLmNv +bS50dwp8fGluc2lkZXZvYS5jb20KfHxpbnN0aXR1dC10aWJldGFpbi5vcmcKfHxp +bnRlcmFjdGl2ZWJyb2tlcnMuY29tCnx8aW50ZXJuZXQub3JnCmludGVybmV0ZGVm +ZW5zZWxlYWd1ZS5vcmcKfHxpbnRlcm5ldGZyZWVkb20ub3JnCiEtLXx8aW50ZXJw +b2wuaW50Cnx8aW50ZXJuZXRwb3BjdWx0dXJlLmNvbQouaW50aGVuYW1lb2Zjb25m +dWNpdXNtb3ZpZS5jb20KfHxpbnRoZW5hbWVvZmNvbmZ1Y2l1c21vdmllLmNvbQpp +bnhpYW4uY29tCnx8aW54aWFuLmNvbQohLS18fGlwY2Yub3JnLnR3Cnx8aXBkZWZl +bnNlZm9ydW0uY29tCnx8aXBmaXJlLm9yZwp8fGlwaG9uZTRob25na29uZy5jb20K +fHxpcGhvbmV0YWl3YW4ub3JnCnx8aXBob25peC5mcgp8fGlwaWN0dXJlLnJ1Ci5p +cGpldGFibGUubmV0Cnx8aXBqZXRhYmxlLm5ldAouaXBvYmFyLmNvbS9yZWFkLnBo +cD8KaXBvb2NrLmNvbS9pbWcKLmlwb3J0YWwubWUKfGh0dHA6Ly9pcG9ydGFsLm1l +Cnx8aXBwb3R2LmNvbQouaXByZWRhdG9yLnNlCnx8aXByZWRhdG9yLnNlCi5pcHR2 +LmNvbS50dwp8fGlwdHZiaW4uY29tCnx8aXB2YW5pc2guY29tCmlyZWRtYWlsLm9y +ZwpjaGluZXNlLmlyaWIuaXIKfHxpcm9ucHl0aG9uLm5ldAouaXJvbnNvY2tldC5j +b20KfHxpcm9uc29ja2V0LmNvbQouaXMuZ2QKfHxpc2hyLmNoCi5pc2xhaGhhYmVy +Lm5ldAouaXNsYW0ub3JnLmhrCnxodHRwOi8vaXNsYW0ub3JnLmhrCi5pc2xhbWF3 +YXJlbmVzcy5uZXQvQXNpYS9DaGluYQouaXNsYW1ob3VzZS5jb20KfHxpc2xhbWhv +dXNlLmNvbQouaXNsYW1pY2l0eS5jb20KLmlzbGFtaWNwbHVyYWxpc20ub3JnCi5p +c2xhbXRvZGF5Lm5ldAouaXNhYWNtYW8uY29tCnx8aXNhYWNtYW8uY29tCnx8aXNn +cmVhdC5vcmcKfHxpc21hZWxhbi5jb20KLmlzbWFsbHRpdHMuY29tCnx8aXNtcHJv +ZmVzc2lvbmFsLm5ldAppc29odW50LmNvbQp8fGlzcmFib3guY29tCi5pc3N1dS5j +b20KfHxpc3N1dS5jb20KLmlzdGFycy5jby5uegpvdmVyc2VhLmlzdGFyc2hpbmUu +Y29tCnx8b3ZlcnNlYS5pc3RhcnNoaW5lLmNvbQouaXN0b2NrcGhvdG8uY29tCmlz +dW5hZmZhaXJzLmNvbQppc3VudHYuY29tCnx8aXN1cHBvcnR1eWdodXJzLm9yZwp8 +fGl0YWxpYXRpYmV0Lm9yZwp8fGl0ZW1maXguY29tCml0aGVscC5pdGhvbWUuY29t +LnR3Cnx8aXRzaGlkZGVuLmNvbQouaXRza3kuaXQKLml0d2VldC5uZXQKfGh0dHA6 +Ly9pdHdlZXQubmV0Ci5pdTQ1LmNvbQouaXVocmRmLm9yZwp8fGl1aHJkZi5vcmcK +Lml1a3NreS5jb20KLml2YWN5LmNvbQp8fGl2YWN5LmNvbQp8fGl2b25ibG9nLmNv +bQouaXZwbi5uZXQKfHxpdnBuLm5ldAp8fGl3YXJhLnR2Cnx8aXhxdWljay5jb20K +Lml4eHguY29tCi5peW91cG9ydC5jb20KfHxpeW91cG9ydC5jb20KfHxpeW91cG9y +dC5vcmcKLml6YW9iYW8udXMKLml6bGVzLm5ldAouaXpsZXNlbS5vcmcKCiEtLS0t +LS0tLS0tLS0tLS0tLS0tLUpKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp8fGp1 +c3RteXNvY2tzY24uY29tCnx8anVzdG15c29ja3MubmV0Cnx8amF2MzIxLmNvbQp8 +fGphdmRiLmNvbQp8fGppZmFuZ2dlLmNvbQp8fGoubXAKfHxqYWJsZS50dgp8fGJs +b2cuamFja2ppYS5jb20KamFtYWF0Lm9yZwp8fGphbWVzdG93bi5vcmcKfHxqYW15 +YW5nbm9yYnUuY29tCnx8amFuLmFpCnx8amFwYW4td2hvcmVzLmNvbQp8fGphcGFu +aGR2LmNvbQouamF2LmNvbQouamF2MTAxLmNvbQouamF2NjgudHYKLmphdmFraWJh +Lm9yZwp8fGphdmFraWJhLm9yZwouamF2YnVzLmNvbQp8fGphdmJ1cy5jb20KfHxq +YXZmaW5kZXIuYWkKfHxqYXZmb3IubWUKLmphdmhkLmNvbQouamF2aGlwLmNvbQou +amF2bW9iaWxlLm5ldAp8fGphdm1vYmlsZS5uZXQKLmphdm1vby5jb20KLmphdnNl +ZW4uY29tCnx8amF2c2Vlbi5jb20KamJ0YWxrcy5jYwpqYnRhbGtzLmNvbQpqYnRh +bGtzLm15Ci5qZHdzeS5jb20KamVhbnlpbS5jb20KfHxqZ29vZGllcy5jb20KLmpp +YW5nd2VpcGluZy5jb20KfHxqaWFuZ3dlaXBpbmcuY29tCnx8amlhb3lvdTguY29t +Cnx8amljaGFuZ3RqLmNvbQouamllaHVhLmN6Cnx8aGsuamllcGFuZy5jb20KfHx0 +dy5qaWVwYW5nLmNvbQpqaWVzaGliYW9iYW8uY29tCi5qaWdnbGVnaWZzLmNvbQo1 +NmN1bjA0LmppZ3N5LmNvbQpkYW9kdTE0LmppZ3N5LmNvbQpzcGVjeGluemwuamln +c3kuY29tCndsY25ldy5qaWdzeS5jb20KLmppaGFkb2xvZ3kubmV0CnxodHRwOi8v +amloYWRvbG9neS5uZXQKLmppbmdzaW0ub3JnCnpoYW8uamluaGFpLmRlCmppbmdw +aW4ub3JnCnx8amluZ3Bpbi5vcmcKamlucGlhbndhbmcuY29tCnx8amlucml6aGl5 +aS5uZXdzCnx8aml0b3VjaC5jb20KampnaXJscy5jb20KLmprYi5jYwp8aHR0cDov +L2prYi5jYwpqa2ZvcnVtLm5ldAp8fGptYS5nby5qcAp8fGptc2MuaGt1LmhrCi5q +bXNjdWx0LmNvbQp8aHR0cDovL2ptc2N1bHQuY29tCnx8am9hY2hpbXMub3JnCi5z +dW53aW5pc20uam9pbmJicy5uZXQKfHxqb2luY2x1YmhvdXNlLmNvbQp8fGpvcm5h +bGRhY2lkYWRlb25saW5lLmNvbS5icgouam91cm5hbGNocmV0aWVuLm5ldAp8fGpv +dXJuYWxvZmRlbW9jcmFjeS5vcmcKLmpveW1paWh1Yi5jb20KLmpveW91cnNlbGYu +Y29tCmpwb3Bmb3J1bS5uZXQKfHxqc2RlbGl2ci5uZXQKfHxmaWRkbGUuanNoZWxs +Lm5ldAohLS1Eb2FtaW4gcGFya2luZwouanVodWFyZW4uY29tCnx8anVsaWVyZXlj +LmNvbQp8fGp1bmF1emEuY29tCi5qdW5lNGNvbW1lbW9yYXRpb24ub3JnCnx8YmJz +Lmp1bmdsb2JhbC5uZXQKLmp1b2FhLmNvbQp8aHR0cDovL2p1b2FhLmNvbQpqdXN0 +ZnJlZXZwbi5jb20KfHxqdXN0aG9zdC5ydQpqdXN0cGFzdGUuaXQKfHxqdXN0bXlz +b2NrczEubmV0Cmp1c3R0cmlzdGFuLmNvbQpqdXppeXVlLmNvbQp8fGp1eml5dWUu +Y29tCnx8andtdXNpYy5vcmcKQEB8fG11c2ljLmp3bXVzaWMub3JnCnx8Y2RuLmp3 +cGxheWVyLmNvbQouanl4Zi5uZXQKCiEtLS0tLS0tLS0tLS0tLS0tLS0tLUtLLS0t +LS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp8fGtpbmdrb25nLmNvbS50dwp8fGthbmFs +ZC5jb20udHIKfHxrcGt1YW5nLm9yZwp8fGthLXdhaS5jb20KfHxrYWRva2F3YS5j +by5qcAoua2FneXUub3JnCnx8a2FneXUub3JnLnphCi5rYWd5dW1vbmxhbS5vcmcK +LmthZ3l1bmV3cy5jb20uaGsKLmthZ3l1b2ZmaWNlLm9yZwp8fGthZ3l1b2ZmaWNl +Lm9yZwp8fGthZ3l1b2ZmaWNlLm9yZy50dwoua2FpeXVhbi5kZQoua2FrYW8uY29t +Cnx8a2FrYW8uY29tCi5rYW5rYW4udG9kYXkKLmthbm5ld3lvcmsuY29tCnx8a2Fu +bmV3eW9yay5jb20KLmthbnNoaWZhbmcuY29tCnx8a2Fuc2hpZmFuZy5jb20KfHxr +YW50aWUub3JnCmthbnpob25nZ3VvLmNvbQprYW56aG9uZ2d1by5ldQoua2FvdGlj +LmNvbQp8fGthb3RpYy5jb20KfHxrYXJheW91LmNvbQoua2FybWFwYS5vcmcKLmth +cm1hcGEtdGVhY2hpbmdzLm9yZwp8fGthd2FzZS5jb20KLmtiYS10eC5vcmcKLmtj +b29sb25saW5lLmNvbQoua2VicnVtLmNvbQp8fGtlYnJ1bS5jb20KLmtlY2hhcmEu +Y29tCi5rZWVwYW5kc2hhcmUuY29tL3Zpc2l0L3Zpc2l0X3BhZ2UucGhwP2k9Njg4 +MTU0CiEtLXx8a2VlcHZpZC5jb20KLmtlZXptb3ZpZXMuY29tCi5rZW5lbmdiYS5j +b20KfHxrZW5lbmdiYS5jb20KLmtlcGFyZC5jb20KfHxrZXBhcmQuY29tCndpa2ku +a2Vzby5jbi9Ib21lCnx8a2V5Y2RuLmNvbQoua2hhYmRoYS5vcmcKfHxraWNoaWt1 +LWRvdWppbmtvLmNvbQoua2lrLmNvbQp8fGtpay5jb20KLmtpbmRsZXJlbi5jb20K +fGh0dHA6Ly9raW5kbGVyZW4uY29tCnxodHRwOi8vd3d3LmtpbmRsZXJlbi5jb20K +Lmtpbmdkb21zYWx2YXRpb24ub3JnCnx8a2luZ2RvbXNhbHZhdGlvbi5vcmcKa2lu +Z2hvc3QuY29tCiEtLS5raW5nc3RvbmUuY29tLnR3L2Jvb2svCnx8a2luZ3N0b25l +LmNvbS50dwoua2luay5jb20KLmtpbm9rdW5peWEuY29tCnx8a2lub2t1bml5YS5j +b20Ka2lsbHdhbGwuY29tCnx8a2lsbHdhbGwuY29tCnx8a2luZGxlNHJzcy5jb20K +fHxraW5tZW4udHJhdmVsCi5raXIuanAKLmtpc3NiYmFvLmNuCnxodHRwOi8va2l3 +aS5regp8fGtrLXdoeXMuY28uanAKIS0tfHxrbXQub3JnLnR3Ci5rbXVoLm9yZy50 +dwoua25vd2xlZGdlcnVzaC5jb20va3IvZW5jeWNsb3BlZGlhCnx8a25vd3lvdXJt +ZW1lLmNvbQoua29iby5jb20KfHxrb2JvLmNvbQoua29ib2Jvb2tzLmNvbQp8fGtv +Ym9ib29rcy5jb20KfHxrb2Rpbmdlbi5jb20KQEB8fHd3dy5rb2Rpbmdlbi5jb20K +fHxrb21wb3plci5uZXQKLmtvbmFjaGFuLmNvbQp8fGtvbmFjaGFuLmNvbQoua29u +ZS5jb20KfHxrb29sc29sdXRpb25zLmNvbQoua29vcm5rLmNvbQp8fGtvb3Juay5j +b20KfHxrb3Jhbm1hbmRhcmluLmNvbQoua29yZW5hbjIuY29tCnx8a3Flcy5uZXQK +fGh0dHA6Ly9nb2pldC5rcnRjby5jb20udHcKLmtzZGwub3JnCi5rc25ld3MuY29t +LnR3Cnx8a3R6aGsuY29tCnx8a3VhaWNoZWRhby5jbwoua3VpLm5hbWUvZXZlbnQK +fHxrdWt1a3UudWsKa3VuLmltCi5rdXJhc2hzdWx0YW4uY29tCnx8a3VydG11bmdl +ci5jb20Ka3Vzb2NpdHkuY29tCnx8a3djZy5jYQoua3dvbmd3YWguY29tLm15Cnx8 +a3dvbmd3YWguY29tLm15Ci5reHN3LmxpZmUKfHxreHN3LmxpZmUKLmt5b2Z1bi5j +b20Ka3lvaGsubmV0Cnx8a3phb2Jhby5jb20KLmt6ZW5nLmluZm8KfHxremVuZy5p +bmZvCgohLS0tLS0tLS0tLS0tLS0tLS0tLS1MTC0tLS0tLS0tLS0tLS0tLS0tLS0t +LS0tLS0KfHxsdWNreW1vYmlsZS5jYQp8fGx1ZGVwcmVzcy5jb20KfHxsaW5ndWFs +ZW8uY29tCnx8bGRwbGF5ZXIudHcKfHxsZHBsYXllci5uZXQKfHxsdG4uY29tLnR3 +Cnx8bGl0ZW5ld3MuaGsKfHx3d3cubG9yZW56ZXR0aS5jb20uYnIKfHxsaW5rdHIu +ZWUKbGEtZm9ydW0ub3JnCmxhZGJyb2tlcy5jb20KfHxsYWJpZW5uYWxlLm9yZwou +bGFncmFuZXBvY2EuY29tCnx8bGFncmFuZXBvY2EuY29tCnx8bGFsYS5pbQoubGFs +dWxhbHUuY29tCi5sYW1hLmNvbS50dwp8fGxhbWEuY29tLnR3Ci5sYW1heWVzaGUu +Y29tCnxodHRwOi8vbGFtYXllc2hlLmNvbQoubGFtbmlhLmNvLnVrCnx8bGFtbmlh +LmNvLnVrCmxhbXJpbS5jb20KfHxsYW5kb2Zob3BlLnR2Ci5sYW50ZXJuY24uY24K +fGh0dHA6Ly9sYW50ZXJuY24uY24KLmxhbnRvc2ZvdW5kYXRpb24ub3JnCi5sYW9k +LmNuCnxodHRwOi8vbGFvZC5jbgpsYW9nYWkub3JnCnx8bGFvZ2FpLm9yZwp8fGxh +b2dhaXJlc2VhcmNoLm9yZwpsYW9taXUuY29tCi5sYW95YW5nLmluZm8KfGh0dHA6 +Ly9sYW95YW5nLmluZm8KLmxhcWluZ2Rhbi5uZXQKfHxsYXFpbmdkYW4ubmV0Cnx8 +bGFyc2dlb3JnZS5jb20KLmxhc3Rjb21iYXQuY29tCnxodHRwOi8vbGFzdGNvbWJh +dC5jb20KfHxsYXN0Zm0uZXMKbGF0ZWxpbmVuZXdzLmNvbQp8fGxhdXNhbi5oawp8 +fGxlLXZwbi5jb20KLmxlYWZ5dnBuLm5ldAp8fGxlYWZ5dnBuLm5ldAp8fGxlZGdl +ci5jb20KbGVlYW8uY29tLmNuL2Jicy9mb3J1bS5waHAKIS0tfHxsZWVjaGV1a3lh +bi5vcmcKbGVmb3JhLmNvbQp8fGxlZnQyMS5oawoubGVnYWxwb3Juby5jb20KLmxl +Z3NqYXBhbi5jb20KbGVpc3VyZWNhZmUuY2EKfHxsZW1hdGluLmNoCi5sZW1vbmRl +LmZyCnx8bGVud2hpdGUuY29tCmJsb2cubGVzdGVyODUwLmluZm8KfHxsZXNvaXIu +YmUKLmxldG91LmNvbQpsZXRzY29ycC5uZXQKfHxsZXRzY29ycC5uZXQKITY5LjE2 +LjE3NS40Mgp8fGNkbi5hc3NldHMubGZwY29udGVudC5jb20KLmxoYWthci5vcmcK +fGh0dHA6Ly9saGFrYXIub3JnCi5saGFzb2NpYWx3b3JrLm9yZwoubGlhbmd5b3Uu +bmV0Cnx8bGlhbmd5b3UubmV0Ci5saWFueXVlLm5ldAp8fGxpYW93YW5neGl6YW5n +Lm5ldAoubGlhb3dhbmd4aXphbmcubmV0Cnx8bGliZXJhbC5vcmcuaGsKfHxsaWJl +cnR5c2N1bHB0dXJlcGFyay5jb20KfHxsaWJlcnR5dGltZXMuY29tLnR3Cnx8bGli +cmVkZC5pdAp8fGxpZ2h0ZW4ub3JnLnR3Cnx8bGlnaHRub3ZlbC5jbgp8fGxpbGFv +c2hpYnVzaGluaWxhb3NoaS5jb20KbGltaWFvLm5ldApsaW5rdXN3ZWxsLmNvbQph +Yml0bm8ubGlucGllLmNvbS91c2UtaXB2Ni10by1mdWNrLWdmdwp8fGxpbmUubWUK +fHxsaW5lLWFwcHMuY29tCi5saW5nbGluZ2ZhLmNvbQp8fGxpbmd2b2RpY3MuY29t +Ci5saW5rLW8tcmFtYS5jb20KfGh0dHA6Ly9saW5rLW8tcmFtYS5jb20KfHxsaW5r +ZWRpbi5jb20KLmxpbmtpZGVvLmNvbQp8fGxpbnV4Lm9yZy5oawpsaW51eHRveS5v +cmcvYXJjaGl2ZXMvaW5zdGFsbGluZy13ZXN0LWNoYW1iZXItb24tdWJ1bnR1Ci5s +aW9uc3JvYXIuY29tCi5saXB1bWFuLmNvbQp8fGxpcXVpZHZwbi5jb20KfHxncmVh +dGZpcmUudXM3Lmxpc3QtbWFuYWdlLmNvbQp8fGxpc3Rlbm5vdGVzLmNvbQp8fGxp +c3RlbnRveW91dHViZS5jb20KbGlzdG9yaW91cy5jb20KLmxpdS14aWFvYm8ub3Jn +Ci5saXVoYW55dS5jb20KLmxpdXhpYW9iby5uZXQKfHxsaXV4aWFvYm8ubmV0Cmxp +dXhpYW90b25nLmNvbQp8fGxpdXhpYW90b25nLmNvbQoubGl2ZWRvb3IuanAKLmxp +dmVsZWFrLmNvbQp8fGxpdmVsZWFrLmNvbQp8fGxpdmVtaW50LmNvbQpsaXZlc3Ry +ZWFtLmNvbQp8fGxpdmVzdHJlYW0uY29tCnx8bGl2aW5nc3RyZWFtLmNvbQp8fGxp +dmV2aWRlby5jb20KLmxpdmV2aWRlby5jb20KbGl6aGl6aHVhbmdiaS5jb20KbGtj +bi5uZXQKfHxjaGF0Lmxtc3lzLm9yZwoubG9hZC50bwoubG9ic2FuZ3dhbmd5YWwu +Y29tCi5sb2NhbGRvbWFpbi53cwp8fGxvY2FsZG9tYWluLndzCmxvY2FscHJlc3No +ay5jb20KfHxsb2NrZXN0ZWsuY29tCnNlY3VyZS5sb2dtZWluLmNvbQp8fHNlY3Vy +ZS5sb2dtZWluLmNvbQp8fGxvZ29zLmNvbS5oawoubG9uZG9uY2hpbmVzZS5jYQou +bG9uZ2hhaXIuaGsKbG9uZ211c2ljLmNvbQp8fGxvbmd0ZXJtbHkubmV0Cnx8bG9v +a3BpYy5jb20KLmxvb2t0b3JvbnRvLmNvbQp8aHR0cDovL2xvb2t0b3JvbnRvLmNv +bQoubG90c2F3YWhvdXNlLm9yZy90aWJldGFuLW1hc3RlcnMvZm91cnRlZW50aC1k +YWxhaS1sYW1hCi5sb3R1c2xpZ2h0Lm9yZy50dwpoa3JlcG9ydGVyLmxvdmVkLmhr +Ci5scmlwLm9yZwp8fGxyaXAub3JnCi5sc2Qub3JnLmhrCnx8bHNkLm9yZy5oawps +c2ZvcnVtLm5ldAoubHNtLm9yZwp8fGxzbS5vcmcKLmxzbWNoaW5lc2Uub3JnCnx8 +bHNtY2hpbmVzZS5vcmcKLmxzbWtvcmVhbi5vcmcKfHxsc21rb3JlYW4ub3JnCi5s +c21yYWRpby5jb20vcmFkX2FyY2hpdmVzCi5sc213ZWJjYXN0LmNvbQoubHRuLmNv +bS50dwp8fGx0bi5jb20udHcKfHxsdWNreWRlc2lnbmVyLnNwYWNlCi5sdWtlNTQu +Y29tCi5sdWtlNTQub3JnCi5sdXBtLm9yZwp8fGx1cG0ub3JnCnx8bHVzaHN0b3Jp +ZXMuY29tCmx1eGViYy5jb20KbHZoYWkub3JnCnx8bHZoYWkub3JnCnx8bHZ2Mi5j +b20KLmx5ZmhrLm5ldAp8aHR0cDovL2x5ZmhrLm5ldAp8fGx6anNjcmlwdC5jb20K +Lmx6bXRuZXdzLm9yZwp8fGx6bXRuZXdzLm9yZwoKIS0tLS0tLS0tLS0tLS0tLS0t +LS0tTU0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnx8bWN1c2VyY29udGVudC5j +b20KfHxtZXRhbWFzay5pbwp8fG1pc3Nhdi53cwp8fG5ld3MubXQuY28ua3IKfHxt +dXNpeG1hdGNoLmNvbQp8fG1lcmdlcnNhbmRpbnF1aXNpdGlvbnMuY29tCnx8bS5t +b2VnaXJsLm9yZwp8fG15anMudHcKfHxtZXJjYXJpLmNvbQp8fG1lcmNhcmkuanAK +fHxtaXJyb3IueHl6Cnx8bXl3aWZlLmNjCnx8Yy5taS5jb20KfHxtaXNzYXYuY29t +Cnx8bWFkb3UuY2x1Ygp8fG1haGpvbmdzb3VsLmNvbQp8fG1hbmdhYnouY29tCmh0 +dHA6Ly8qLm0tdGVhbS5jYwohLS1tLXRlYW0uY2MvZm9ydW0KLm1hY3JvdnBuLmNv +bQp8fG1hZC1hci5jaAp8fG1hZHJhdS5jb20KfHxtYWR0aHVtYnMuY29tCm1haGFi +b2RoaS5vcmcKbXkubWFpbC5ydQoubWFpcGx1cy5jb20KfGh0dHA6Ly9tYWlwbHVz +LmNvbQoubWFpemhvbmcub3JnCm1ha2thaG5ld3NwYXBlci5jb20KLm1hbWluZ3po +ZS5jb20KfHxtYW5nbWFuZy5ydW4KbWFuaWN1cjRpay5ydQp8fG1hbnl2b2ljZXMu +bmV3cwoubWFwbGV3LmNvbQp8aHR0cDovL21hcGxldy5jb20KfHxtYXJjLmluZm8K +bWFyZ3Vlcml0ZS5zdQptYXNrZWRpcC5jb20KLm1haWlvLm5ldAoubWFpbC1hcmNo +aXZlLmNvbQoubWFsYXlzaWFraW5pLmNvbQp8fG1ha2VteW1vb2QuY29tCi5tYW5j +aHVrdW8ubmV0Ci5tYW5pYXNoLmNvbQp8aHR0cDovL21hbmlhc2guY29tCi5tYW5z +aW9uLmNvbQoubWFuc2lvbnBva2VyLmNvbQohLS18fG1hcmluZXMubWlsCiEtLW1h +cmttYWlsLm9yZyptZXNzYWdlCnx8bWFydGF1LmNvbQp8aHR0cDovL2Jsb2cubWFy +dGlub2VpLmNvbQoubWFydHNhbmdrYWd5dW9mZmljaWFsLm9yZwp8aHR0cDovL21h +cnRzYW5na2FneXVvZmZpY2lhbC5vcmcKbWFydXRhLmJlL2ZvcmdldAoubWFyeGlz +dC5jb20KfHxtYXJ4aXN0Lm5ldAoubWFyeGlzdHMub3JnL2NoaW5lc2UKIS0tfHxt +YXNoYWJsZS5jb20KfHxtYXRhaW5qYS5jb20KfHxtYXRyaXgub3JnCnx8bWF0dGVy +cy50b3duCm1heWltYXlpLmNvbQoubWF4aW5nLmpwCi5tY2FmLmVlCnxodHRwOi8v +bWNhZi5lZQp8fG1jYWRmb3J1bXMuY29tCm1jZm9nLmNvbQptY3JlYXNpdGUuY29t +Ci5tZC10Lm9yZwp8fG1kLXQub3JnCnx8bWVhbnN5cy5jb20KLm1lZGlhLm9yZy5o +awoubWVkaWFjaGluZXNlLmNvbQp8fG1lZGlhY2hpbmVzZS5jb20KLm1lZGlhZmly +ZS5jb20vPwoubWVkaWFmaXJlLmNvbS9kb3dubG9hZAoubWVkaWFmcmVha2NpdHku +Y29tCnx8bWVkaWFmcmVha2NpdHkuY29tCi5tZWRpdW0uY29tCnx8bWVkaXVtLmNv +bQoubWVldGF2LmNvbQp8fG1lZXR1cC5jb20KbWVmZWVkaWEuY29tCmppaGFkaW50 +ZWwubWVmb3J1bS5vcmcKfHxtZWdhLmNvLm56Cnx8bWVnYS5pbwp8fG1lZ2EubnoK +fHxtZWdhbG9kb24uanAKfHxtZWdhcHJveHkuY29tCnx8bWVndXJpbmVsdWthLmNv +bQp8fG1laXpob25nLmJsb2cKfHxtZWl6aG9uZy5yZXBvcnQKLm1lbHRvZGF5LmNv +bQoubWVtZWhrLmNvbQp8fG1lbWVoay5jb20KfHxtZW1lcy50dwoubWVtcmkub3Jn +Ci5tZW1yaWp0dG0ub3JnCnx8bWVyY2RuLm5ldAoubWVyY3lwcm9waGV0Lm9yZwp8 +fG1lcmN5cHJvcGhldC5vcmcKLm1lcmlkaWFuLXRydXN0Lm9yZwp8fG1lcmlkaWFu +LXRydXN0Lm9yZwoubWVyaXBldC5jb20KfHxtZXJpcGV0LmNvbQp8fG1lcml0LXRp +bWVzLmNvbS50dwoubWVzb3R3LmNvbS9iYnMKfHx3aWtpLm1ldGFjdWJleC5vbmUK +fHxtZXRhZmlsdGVyLmNvbQp8fG1ldGVvcnNob3dlcnNvbmxpbmUuY29tCnx8bWV0 +cm8udGFpcGVpCi5tZXRyb2hrLmNvbS5oay8/Y21kPWRldGFpbCZjYXRlZ29yeUlE +PTIKfHxtZXRyb2xpZmUuY2EKLm1ldHJvcmFkaW8uY29tLmhrCnx8bWV0cm9yYWRp +by5jb20uaGsKfHxtZXdlLmNvbQp8fG1nb29uLmNvbQp8fG1nc3RhZ2UuY29tCnx8 +bWg0dS5vcmcKbWhyYWRpby5vcmcKfHxiYnMubWlrb2Nvbi5jb20KfHxtaWNyb3Zw +bi5jb20KbWlkZGxlLXdheS5uZXQKLm1paHIuY29tCnx8bWlodWEub3JnCnx8bWlr +YW5hbmkubWUKIS0tSVAKfHxtaWtlc29sdHlzLmNvbQoubWlscGgubmV0CnxodHRw +Oi8vbWlscGgubmV0Ci5taWxzdXJwcy5jb20KbWltaWFpLm5ldAoubWltaXZpcC5j +b20KLm1pbmRyb2xsaW5nLm9yZwp8aHR0cDovL21pbmRyb2xsaW5nLm9yZwp8fG1p +bmdkZW1lZGlhLm9yZwoubWluZ2h1aS5vci5rcgp8aHR0cDovL21pbmdodWkub3Iu +a3IKbWluZ2h1aS5vcmcKfHxtaW5naHVpLm9yZwptaW5naHVpLXNjaG9vbC5vcmcK +Lm1pbmdqaW5nbGlzaGkuY29tCnx8bWluZ2ppbmdsaXNoaS5jb20KbWluZ2ppbmdu +ZXdzLmNvbQp8fG1pbmdqaW5ndGltZXMuY29tCi5taW5ncGFvLmNvbQp8fG1pbmdw +YW8uY29tCi5taW5ncGFvY2FuYWRhLmNvbQoubWluZ3Bhb21vbnRobHkuY29tCnxo +dHRwOi8vbWluZ3Bhb21vbnRobHkuY29tCm1pbmdwYW9uZXdzLmNvbQoubWluZ3Bh +b255LmNvbQoubWluZ3Bhb3NmLmNvbQoubWluZ3Bhb3Rvci5jb20KLm1pbmdwYW92 +YW4uY29tCi5taW5nc2hlbmdiYW8uY29tCi5taW5oaHVlLm5ldAoubWluaXN0cnli +b29rcy5vcmcKbWluemh1emhvbmdndW8ub3JnCnx8bWlyb2d1aWRlLmNvbQptaXJy +b3Jib29rcy5jb20KfHxtaXJyb3JtZWRpYS5tZwoubWlzdC52aXAKfHx0aGVjZW50 +ZXIubWl0LmVkdQp8fHNjcmF0Y2gubWl0LmVkdQoubWl0YmJzLmNvbQp8fG1pdGJi +cy5jb20KLm1peGVyby5jb20KfHxtaXhlcm8uY29tCnx8bWl4aS5qcAptaXhwb2Qu +Y29tCi5taXh4LmNvbQp8fG1peHguY29tCnx8bWl6em1vbmEuY29tCnx8bWxjLmFp +Ci5tbGNvb2wuY29tCnx8bWx6cy53b3JrCi5tbS1jZy5jb20KfHxtbWFheHguY29t +Ci5tbW1jYS5jb20KbW5ld3N0di5jb20KfHxtb2JhdGVrLm5ldAoubW9iaWxlMDEu +Y29tCnx8bW9iaWxlMDEuY29tCnx8bW9iaWxld2F5cy5kZQoubW9ieXBpY3R1cmUu +Y29tCnxodHRwOi8vbW9ieS50bwp8fG1vZC5pbwp8fG1vZGVybmNoaW5hc3R1ZGll +cy5vcmcKfHxtb2Vlcm9saWJyYXJ5LmNvbQp8fG1vZXNoYXJlLmNjCi5tb2Zvcy5j +b20KfHxtb2cuY29tCnx8bW9odS5yb2Nrcwptb2xpaHVhLm9yZwp8fG1vbW9zaG9w +LmNvbS50dwp8fG1vbmRleC5vcmcKfHxtb25leS1saW5rLmNvbS50dwp8aHR0cDov +L3d3dy5tb25sYW1pdC5vcmcKfHxtb29uLmZtCi5tb29uYmJzLmNvbQp8fG1vb25i +YnMuY29tCnx8bW9wdHQudHcKfHxtb25leWRqLmNvbQp8fG1vbmljYS5pbQp8fG1v +bml0b3JjaGluYS5vcmcKfHxtb25vY2xvdWQubWUKYmJzLm1vcmJlbGwuY29tCnx8 +bW9ybmluZ3N1bi5vcmcKLm1vdGhlcmxlc3MuY29tCnxodHRwOi8vbW90aGVybGVz +cy5jb20KbW90b3I0aWsucnUKLm1vdXNlYnJlYWtlci5jb20KIS0tfHxtb3ZhYmxl +dHlwZS5jb20KLm1vdmVtZW50cy5vcmcKfHxtb3ZlbWVudHMub3JnCnx8bW92aWVm +YXAuY29tCnx8d3d3Lm1venR3Lm9yZwoubXAzYnVzY2Fkb3IuY29tCnx8bXBldHRp +cy5jb20KLm1wZmluYW5jZS5jb20KfHxtcGZpbmFuY2UuY29tCi5tcGluZXdzLmNv +bQp8fG1waW5ld3MuY29tCm1wb25saW5lLmhrCm1ydHdlZXQuY29tCnx8bXJ0d2Vl +dC5jb20KbmV3cy5tc24uY29tLnR3Cm1zZ3VhbmNoYS5jb20KLm1zd2UxLm9yZwp8 +aHR0cDovL21zd2UxLm9yZwp8fG10aHJ1Zi5jb20KfHxtdWJpLmNvbQptdWNob3N1 +Y2tvLmNvbQp8fG11bHRpcGx5LmNvbQptdWx0aXByb3h5Lm9yZwptdWx0aXVwbG9h +ZC5jb20KLm11bGx2YWQubmV0Cnx8bXVsbHZhZC5uZXQKLm11bW15c2dvbGQuY29t +Ci5tdXNpY2FkZS5uZXQKLm11c2xpbXZpZGVvLmNvbQp8fG11emkuY29tCnx8bXV6 +aS5uZXQKfHxteDk4MS5jb20KLm15LWZvcm1vc2EuY29tCi5teS1wcm94eS5jb20K +Lm15LXByaXZhdGUtbmV0d29yay5jby51awp8fG15LXByaXZhdGUtbmV0d29yay5j +by51awoubXlhY3RpbWVzLmNvbS9hY3RpbWVzCi5teWF1ZGlvY2FzdC5jb20KfHxt +eWF1ZGlvY2FzdC5jb20KLm15YXYuY29tLnR3L2JicwoubXliYnMudXMKLm15Y2Ex +NjguY29tCi5teWNhbmFkYW5vdy5jb20KfHxiYnMubXljaGF0LnRvCi5teWNoaW5h +bmV0LmNvbQoubXljaGluYW5ld3MuY29tCnx8bXljaGluYW5ld3MuY29tCi5teWNo +aW5lc2UubmV3cwp8fG15Y25uZXdzLmNvbQp8fG15a29taWNhLm9yZwpteWNvdWxk +LmNvbS9kaXNjdXoKLm15ZWFzeXR2LmNvbQp8fG15ZWNsaXBzZWlkZS5jb20KLm15 +ZnJlZWNhbXMuY29tCi5teWZyZWVwYXlzaXRlLmNvbQoubXlmcmVzaG5ldC5jb20K +Lm15aXBoaWRlLmNvbQp8fG15aXBoaWRlLmNvbQpmb3J1bS5teW1hamkuY29tCnx8 +bXltb2UubW9lCnx8bXlwYXJhZ2xpZGluZy5jb20KfHxteXBvcGVzY3UuY29tCi5t +eXJlYWRpbmdtYW5nYS5pbmZvCm15c2luYWJsb2cuY29tCi5teXNwYWNlLmNvbQoh +LS0uYmxvZ3MubXlzcGFjZS5jb20KIS0tfHxibG9ncy5teXNwYWNlLmNvbQohLS12 +aWRzLm15c3BhY2UuY29tL2luZGV4LmNmbT9mdXNlYWN0aW9uPXZpZHMuCiEtLXZp +ZXdtb3JlcGljcy5teXNwYWNlLmNvbQp8fG15c3BhY2VjZG4uY29tCi5teXRhbGti +b3guY29tCi5teXRpemkuY29tCgohLS0tLS0tLS0tLS0tLS0tLS0tLS1OTi0tLS0t +LS0tLS0tLS0tLS0tLS0tLS0tLS0KfHxuYXZlci5jb20KfHxtYXZlbi5uZW9mb3Jn +ZWQubmV0Cnx8bmZ0c3RvcmFnZS5saW5rCnx8bmV3aW5kaWFuZXhwcmVzcy5jb20K +fHxuZXdzMTguY29tCnx8YmJzLm5haXhpLm5ldAp8fG5pa2tlLmhvdGNvb2wudHcK +fHxuaWtrZS1rci5jb20KfHxuaWtrZS1qcC5jb20KfHxuaWtrZS1lbi5jb20KfHxu +ZXRsaWZ5LmFwcAp8fG5pZ2h0c3dhdGNoLnRvcAp8fG5ieXkudHYKfHxuZXd0aHVo +b2xlLmNvbQp8fG5hYWNvYWxpdGlvbi5vcmcKfHxuYWl0aWsubmV0Ci5uYWtpZG8u +Y29tCnx8bmFraWRvLmNvbQoubmFrdXouY29tL2Jicwp8fG5hbGFuZGFib2RoaS5v +cmcKfHxuYWxhbmRhd2VzdC5vcmcKLm5hbWd5YWwub3JnCm5hbWd5YWxtb25hc3Rl +cnkub3JnCi5uYW55YW5nLmNvbQp8fG5hbnlhbmcuY29tCi5uYW55YW5ncG9zdC5j +b20KfHxuYW55YW5ncG9zdC5jb20KLm5hbnphby5jb20KIS0tLm5hbnphby5jb20v +c2MvY2hpbmEvMjAyMjMKIS0tLm5hbnphby5jb20vc2MvaGstbWFjYXUtdHcKLm5h +b2wuY2EKLm5hb2wuY2MKdWlnaHVyLm5hcm9kLnJ1Ci5uYXQubW9lCnx8bmF0Lm1v +ZQpjeWJlcmdob3N0Lm5hdGFkby5jb20KfHxuYXRpb25hbC1sb3R0ZXJ5LmNvLnVr +Cnx8bmF0aW9uYWxhd2FrZW5pbmcub3JnCnx8bmF0aW9uYWxpbnRlcmVzdC5vcmcK +bmV3cy5uYXRpb25hbGdlb2dyYXBoaWMuY29tL25ld3MvMjAxNC8wNi8xNDA2MDMt +dGlhbmFubWVuLXNxdWFyZQp8fG5hdGlvbmFscmV2aWV3LmNvbQoubmF0aW9uc29u +bGluZS5vcmcvb25ld29ybGQvdGliZXQKfHxsaW5lLm5hdmVyLmpwCnx8bmF2eWZh +bWlseS5uYXZ5Lm1pbAp8fG5hdnlyZXNlcnZlLm5hdnkubWlsCnx8bmtvLm5hdnku +bWlsCnx8dXNuby5uYXZ5Lm1pbApuYXdlZWtseXRpbWVzLmNvbQp8fG5iY25ld3Mu +Y29tCi5uYnR2cG4uY29tCnxodHRwOi8vbmJ0dnBuLmNvbQpuY2N3YXRjaC5vcmcu +dHcKLm5jaC5jb20udHcKLm5jbi5vcmcKfHxuY2hyZC5vcmcKfHxuY24ub3JnCnx8 +ZXRvb2xzLm5jb2wuY29tCi5uZGUuZGUKfHxuZGkub3JnCi5uZHIuZGUKLm5lZC5v +cmcKfHxuZWtvc2xvdmFraWEubmV0Cnx8bmVvd2luLm5ldAp8fG5ldGFsZXJ0Lm1l +CiEtLWJic25ldy5uZXRiaWcuY29tCi5uZXRiaXJkcy5jb20KbmV0Y29sb255LmNv +bQpib2xpbi5uZXRmaXJtcy5jb20KfHxuZXRmbGF2LmNvbQp8fG5ldG1lLmNjCnx8 +bmV0c2FyYW5nLmNvbQpuZXRzbmVhay5jb20KLm5ldHdvcms1NC5jb20KbmV0d29y +a2VkYmxvZ3MuY29tCi5uZXR3b3JrdHVubmVsLm5ldApuZXctM2x1bmNoLm5ldAou +bmV3LWFraWJhLmNvbQoubmV3OTYuY2EKLm5ld2NlbnR1cnltYy5jb20KfGh0dHA6 +Ly9uZXdjZW50dXJ5bWMuY29tCm5ld2NlbnR1cnluZXdzLmNvbQp8fG5ld2NoZW4u +Y29tCi5uZXdjaGVuLmNvbQoubmV3Z3JvdW5kcy5jb20KfHxuZXdoaWdobGFuZHZp +c2lvbi5jb20KbmV3aXBub3cuY29tCi5uZXdsYW5kbWFnYXppbmUuY29tLmF1Cnx8 +bmV3bWl0YmJzLmNvbQoubmV3bmV3cy5jYQp8fG5ld3MxLmtyCm5ld3MxMDAuY29t +LnR3Cm5ld3NjaGluYWNvbW1lbnQub3JnCi5uZXdzYW5jYWkuY29tCnx8bmV3c2Fu +Y2FpLmNvbQp8fG5ld3NibHVyLmNvbQoubmV3c2RldG94LmNhCi5uZXdzZGguY29t +Cnx8bmV3c21heC5jb20KfHxuZXdzdGFtYWdvLmNvbQp8fG5ld3N0YXBhLm9yZwp8 +fG5ld3N0YXRlc21hbi5jb20KbmV3c3Rhcm5ldC5jb20KfHxuZXdzd2Vlay5jb20K +Lm5ld3RhaXdhbi5jb20udHcKbmV3dGFsay50dwp8fG5ld3RhbGsudHcKfHxuZXd5 +b3JrZXIuY29tCm5ld3lvcmt0aW1lcy5jb20KfHxuZXhvbi5jb20KLm5leHQxMS5j +by5qcAp8fG5leHRkaWdpdGFsLmNvbS5oawoubmV4dG1hZy5jb20udHcKCiEtLWhr +Ki5uZXh0bWVkaWEuY29tCiEtLXR3Ki5uZXh0bWVkaWEuY29tCiEtLXN0YXRpYyou +bmV4dG1lZGlhLmNvbQoubmV4dG1lZGlhLmNvbQoKfHxuZXh0b24tbmV0LmpwCnx8 +bmV4dHR2LmNvbS50dwoubmZqdHlkLmNvbQp8fGNvLm5nLm1pbAp8fG5nYS5taWwK +bmdlbnNpcy5jb20KLm5oZW50YWkubmV0CnxodHRwOi8vbmhlbnRhaS5uZXQKLm5o +ay1vbmRlbWFuZC5qcAp8fG5pY292aWRlby5qcApuaW5lY29tbWVudGFyaWVzLmNv +bQoubmluamFjbG9hay5jb20KfHxuaW5qYXByb3h5Lm5pbmphCm5pbnRlbmRpdW0u +Y29tCnRhaXdhbnllcy5uaW5nLmNvbQp1c21ndGNnLm5pbmcuY29tL2ZvcnVtCnx8 +bml1c25ld3MuY29tCnx8bmphY3RiLm9yZwp8fG5sZnJlZXZwbi5jb20KfHxubXNs +LndlYnNpdGUKfHxubmV3cy5ldQoKIS0tbm8taXAuY29tI05PSVAKLmRkbnMubmV0 +Lwp8fGdvdGRucy5jaAoubm8taXAub3JnCi5vcGVuZG4ueHl6Ci5zZXJ2ZWh0dHAu +Y29tCnN5dGVzLm5ldAouemFwdG8ub3JnCnxodHRwOi8vZHludXBkYXRlLm5vLWlw +LmNvbS8KCnx8bm9iZWwuc2UKIS0tLm5vYmVscHJpemUub3JnCiEtLXxodHRwOi8v +bm9iZWxwcml6ZS5vcmcKbm9iZWxwcml6ZS5vcmcvbm9iZWxfcHJpemVzL3BlYWNl +L2xhdXJlYXRlcy8xOTg5Cm5vYmVscHJpemUub3JnL25vYmVsX3ByaXplcy9wZWFj +ZS9sYXVyZWF0ZXMvMjAxMAp8fG5vZGVzZWVrLmNvbQp8fG5va29naXJpLm9yZwp8 +fG5va29sYS5jb20Kbm9vZGxldnBuLmNvbQoubm9yYnVsaW5na2Eub3JnCm5vcmR2 +cG4uY29tCnx8bm9yZHZwbi5jb20KfHxub3MubmwKfHxub3RlcGFkLXBsdXMtcGx1 +cy5vcmcKfHxub3cuY29tCnx8bm93bmV3cy5jb20KLm5vd3RvcnJlbnRzLmNvbQp8 +fG5wYS5nby5qcAoubnBudC5tZQp8aHR0cDovL25wbnQubWUKLm5yYWRpby5tZQp8 +aHR0cDovL25yYWRpby5tZQoubnJrLm5vCnx8bnJrLm5vCi5udGQudHYKfHxudGQu +dHYKLm50ZHR2LmNvbQp8fG50ZHR2LmNvbQp8fG50ZHR2LmNvbS50dwoubnRkdHYu +Y28ua3IKbnRkdHYuY2EKbnRkdHYub3JnCm50ZHR2LnJ1Cm50ZHR2bGEuY29tCi5u +dHJmdW4uY29tCnx8Y2JzLm50dS5lZHUudHcKfHxtZWRpYS5udS5ubAoubnViaWxl +cy5uZXQKfHxudWV4cG8uY29tCi5udWtpc3RyZWFtLmNvbQp8fG51cmdvLXNvZnR3 +YXJlLmNvbQp8fG51dGFrdS5uZXQKfHxudXRzdnBuLndvcmsKLm51dmlkLmNvbQp8 +fG52ZHN0LmNvbQoubnZxdWFuLm9yZwoubnZ0b25nemhpc2hlbmcub3JnCnxodHRw +Oi8vbnZ0b25nemhpc2hlbmcub3JnCi5ud3RjYS5vcmcKfGh0dHA6Ly9ueWFhLmV1 +Cnx8bnlhYS5zaQp8fG55Ym9va3MuY29tCm55bG9uLWFuZ2VsLmNvbQpueWxvbnN0 +b2NraW5nc29ubGluZS5jb20KfHxueXBvc3QuY29tCiEtLW55c2luZ3Rhby5jb20K +Lm56Y2hpbmVzZS5jb20KCiEtLS0tLS0tLS0tLS0tLS0tLS0tLU9PLS0tLS0tLS0t +LS0tLS0tLS0tLS0tLS0tLQp8fG9vamouZGUKfHxvbmV2cHMuY29tCnx8b25lZHJp +dmUuY29tCnx8b2xlbGl2ZS5jb20KfHxvYW5uLmNvbQpvYnNlcnZlY2hpbmEubmV0 +Ci5vYnV0dS5jb20Kb2Nhc3Byby5jb20Kb2NjdXB5dGlhbmFubWVuLmNvbQoub2Ny +ZWFtcGllcy5jb20KfHxvY3RvYmVyLXJldmlldy5vcmcKfHxvZHlzZWUuY29tCnx8 +b2ZmaWNlb2Z0aWJldC5jb20KfGh0dHA6Ly9vZmlsZS5vcmcKfHxvZ2FvZ2Eub3Jn +CnR3dHIyc3JjLm9nYW9nYS5vcmcKLm9nYXRlLm9yZwp8fG9nYXRlLm9yZwp3d3cy +Lm9oY2hyLm9yZy9lbmdsaXNoL2JvZGllcy9jYXQvZG9jcy9uZ29zL0lJX0NoaW5h +XzQxLnBkZgp8fG9obXlyc3MuY29tCi5vaWtvcy5jb20udHcvdjQKLm9pa3R2LmNv +bQoub2sucnUKfHxvay5ydQoub2theWZyZWVkb20uY29tCnx8b2theWZyZWVkb20u +Y29tCnx8b2trLnR3Cnx8b2xldm9kLmNvbQp8fG9sdW1wby5jb20KLm9seW1waWN3 +YXRjaC5vcmcKfHxvbWN0Lm9yZwpvbWdpbGkuY29tCnx8b21uaXRhbGsuY29tCnx8 +b21uaXRhbGsub3JnCnx8b21ueS5mbQp8fG9uLmNjCnx8b25lZHJpdmUubGl2ZS5j +b20KfHxvbmlvbi5jaXR5Cnx8b25pb24ubHkKLm9ubGluZWNoYS5jb20KfHxvbmxp +bmV5b3V0dWJlLmNvbQp8fG9ubHlnYXl2aWRlby5jb20KLm9ubHl0d2VldHMuY29t +CnxodHRwOi8vb25seXR3ZWV0cy5jb20Kb25tb29uLm5ldApvbm1vb24uY29tCi5v +bnRoZWh1bnQuY29tCnxodHRwOi8vb250aGVodW50LmNvbQpvcGVuLmNvbS5oawpv +cGVuZGVtb2NyYWN5Lm5ldAp8fG9wZW5kZW1vY3JhY3kubmV0Cm9wZW5pZC5uZXQK +fHxvcGVuaWQubmV0Ci5vcGVubGVha3Mub3JnCnx8b3BlbmxlYWtzLm9yZwp8fG9w +ZW5zdHJlZXRtYXAub3JnCnx8b3BlbnRlY2guZnVuZApvcGVudnBuLm5ldAp8fG9w +ZW52cG4ubmV0Cnx8b3BlbndlYnN0ZXIuY29tCi5vcGVud3J0Lm9yZy5jbgpAQHx8 +b3BlbndydC5vcmcuY24KbXkub3BlcmEuY29tL2RhaGVtYQoub3B1cy1nYW1pbmcu +Y29tCnxodHRwOi8vb3B1cy1nYW1pbmcuY29tCi5vcmdhbmNhcmUub3JnLnR3Cm9y +Z2FuaGFydmVzdGludmVzdGlnYXRpb24ubmV0Ci5vcmdhc20uY29tCi5vcmdmcmVl +LmNvbQp8fG9yaWNvbi5jby5qcAp8fG9yaWVudC1kb2xsLmNvbQpvcmllbnRhbGRh +aWx5LmNvbS5teQp8fG9yaWVudGFsZGFpbHkuY29tLm15CiEtLW9yaWVudGFsZGFp +bHkub24uY2MKfHxvcm4uanAKfHxvc2Zvb3JhLmNvbQp8fG90dG8uZGUKfHxvdXJk +ZWFyYW15LmNvbQpvdXJzb2dvLmNvbQoub3Vyc3RlcHMuY29tLmF1Cnx8b3Vyc3Rl +cHMuY29tLmF1Ci5vdXJzd2ViLm5ldAp8fG91cnR2LmhrCnhpbnFpbWVuZy5vdmVy +LWJsb2cuY29tCnx8b3ZlcmNhc3QuZm0KfHxvdmVyZGFpbHkub3JnCnx8b3ZlcnBs +YXkubmV0CnNoYXJlLm92aS5jb20vbWVkaWEKfHxvdnBuLmNvbQp8aHR0cDovL293 +bC5saQp8aHR0cDovL2h0Lmx5CnxodHRwOi8vaHRsLmxpCnxodHRwOi8vbWFzaC50 +bwp3d3cub3dpbmQuY29tCnx8b3dsdGFpbC5jb20KfHxveGZvcmRzY2hvbGFyc2hp +cC5jb20KfGh0dHA6Ly93d3cub3hpZC5pdApveWF4LmNvbQpveWdoYW4uY29tL3dw +cwoub3pjaGluZXNlLmNvbS9iYnMKfHxvdy5seQoub3p2b2ljZS5vcmcKfHxvenZv +aWNlLm9yZwoub3p4dy5jb20KLm96eW95by5jb20KCiEtLS0tLS0tLS0tLS0tLS0t +LS0tLVBQLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp8fHBld3Jlc2VhcmNoLm9y +Zwp8fHByaXZhY3lndWlkZXMub3JnCnx8cGFuY2FrZXN3YXAuZmluYW5jZQp8fGlt +Zy5waWNnby5uZXQKfHxwb3JubWF0ZS5jb20KfHxwdXJlZG5zLm9yZwp8fHBvbHlt +YXJrZXQuY29tCnx8cGFuZGFmYW4ucHViCnx8cHJveHouY29tCnx8cG90YXRzby5j +b20KfHxwZW5kcml2ZWxpbnV4LmNvbQp8fHBhaW1vbi5tb2UKfHxwaG90b25tZWRp +YS5uZXQKfHxwb2ludHMtbWVkaWEuY29tCnx8cGt1YW52aWwuY29tCnx8cGFjaG9z +dGluZy5jb20KLnBhY2lmaWNwb2tlci5jb20KLnBhY2tldGl4Lm5ldAp8fHBhY29w +YWNvbWFtYS5jb20KLnBhZG1hbmV0LmNvbQp8fHBhZ2UubGluawpwYWdlMnJzcy5j +b20KLnBhbGFjZW1vb24uY29tCmZvcnVtLnBhbG1pc2xpZmUuY29tCnx8ZXJpdmVy +c29mdC5jb20KcGFsam9ycHVibGljYXRpb25zLmNvbQoucGFsdGFsay5jb20KIS0t +fHxwYW5nY2kubmV0Cnx8cGFuZGFwb3cuY28KLnBhbmRhcG93Lm5ldAoucGFuZGF2 +cG4tanAuY29tCnx8cGFuZGF2cG4tanAuY29tCnx8cGFuZGF2cG5wcm8uY29tCnx8 +cGFvLXBhby5uZXQKcGFwZXIubGkKcGFwZXJiLnVzCi5wYXJhZGlzZWhpbGwuY2MK +LnBhcmFkaXNlcG9rZXIuY29tCnx8cGFybGVyLmNvbQp8fHBhcnNldmlkZW8uY29t +Ci5wYXJ0eWNhc2luby5jb20KLnBhcnR5cG9rZXIuY29tCi5wYXNzaW9uLmNvbQp8 +fHBhc3Npb24uY29tCi5wYXNzaW9udGltZXMuaGsKcGFzdGViaW4uY29tCi5wYXN0 +aWUub3JnCnx8cGFzdGllLm9yZwp8fGJsb2cucGF0aHRvc2hhcmVwb2ludC5jb20K +fHxwYXRyZW9uLmNvbQp8fHBhdHJlb251c2VyY29udGVudC5jb20KfHxwYXdvby5u +ZXQKfHxwYnMub3JnCgohLS1QYndpa2kKcGJ3aWtpLmNvbQp8fHBid29ya3MuY29t +Cnx8ZGV2ZWxvcGVycy5ib3gubmV0Cnx8d2lraS5vYXV0aC5uZXQKfHx3aWtpLnBo +b25lZ2FwLmNvbQp8fHdpa2kuanF1ZXJ5dWkuY29tCgp8fHBieGVzLmNvbQp8fHBi +eGVzLm9yZwpwY2R2ZC5jb20udHcKfHxwY2dhbWVzdG9ycmVudHMuY29tCi5wY2hv +bWUuY29tLnR3Cnx8cGNpai5vcmcKLnBjc3RvcmUuY29tLnR3Cnx8cGN0Lm9yZy50 +dwpwZGV0YWlscy5jb20KfHxwZHByb3h5LmNvbQp8fHBlYWNlLmNhCnBlYWNlZmly +ZS5vcmcKLnBlZWFzaWFuLmNvbQp8fHBlaW5nLm5ldAoucGVraW5nZHVjay5vcmcK +fHxwZWtpbmdkdWNrLm9yZwoucGVtdWxpaGFuLm9yLmlkCnxodHRwOi8vcGVtdWxp +aGFuLm9yLmlkCnx8cGVuLmlvCnBlbmNoaW5lc2UuY29tCnx8YmxvZy5wZW50YWxv +Z2ljLm5ldAoucGVudGhvdXNlLmNvbQp8fHBlbnRveS5oawoucGVvcGxlYm9va2Nh +ZmUuY29tCi5wZW9wbGVuZXdzLnR3Cnx8cGVvcGxlbmV3cy50dwoucGVvcG8ub3Jn +Cnx8cGVvcG8ub3JnCi5wZXJjeS5pbgoucGVyZmVjdGdpcmxzLm5ldAp8fHBlcmZl +Y3QtcHJpdmFjeS5jb20KfHxwZXJwbGV4aXR5LmFpCi5wZXJzZWN1dGlvbmJsb2cu +Y29tCi5wZXJzaWFua2l0dHkuY29tCnBoYXBsdWFuLm9yZwoucGhheXVsLmNvbQp8 +fHBoYXl1bC5jb20KcGhpbGJvcmdlcy5jb20KfHxwaG5jZG4uY29tCnx8cGhvdG9k +aGFybWEubmV0Cnx8cGhvdG9mb2N1cy5jb20KfHxwaWNhY29taWNjbi5jb20KLnBp +Y2lkYWUubmV0Cnx8aW1nKi5waWN0dXJlZGlwLmNvbQpwaWN0dXJlc29jaWFsLmNv +bQp8fHBpY3VraS5jb20KfHxwaWdhdi5jb20KfHxwaW4tY29uZy5jb20KLnBpbjYu +Y29tCnx8cGluNi5jb20KLnBpbmcuZm0KfHxwaW5nLmZtCnx8cGluaW1nLmNvbQou +cGlua3JvZC5jb20KfHxwaW5veS1uLmNvbQp8fHBpbnRlcmVzdC4qCkBAfHxwaW50 +ZXJlc3QuY24KLnBpcGlpLnR2CnBpcmFhdHRpbGFodGkub3JnCi5waXJpbmcuY29t +Cnx8cGl4ZWxkcmFpbi5jb20KfHxwaXhlbHFpLmNvbQp8fGNzcy5waXhuZXQuaW4K +fHxwaXhuZXQubmV0Ci5waXhuZXQubmV0Ci5way5jb20KfHxwa3FqaWFzdS5jb20K +fHxwbGFjZW1peC5jb20KIS0tLnBsYW5ldHN1enkub3JnCnx8cGxheS1hc2lhLmNv +bQp8fHBsYXlib3kuY29tCi5wbGF5Ym95cGx1cy5jb20KfHxwbGF5Ym95cGx1cy5j +b20KfHxwbGF5ZXIuZm0KLnBsYXlubzEuY29tCnx8cGxheW5vMS5jb20KfHxwbGF5 +cGNlc29yLmNvbQp8fHBsZXh2cG4ucHJvCnBsbS5vcmcuaGsKcGx1bmRlci5jb20K +LnBsdXJrLmNvbQp8fHBsdXJrLmNvbQoucGx1czI4LmNvbQoucGx1c2JiLmNvbQou +cG1hdGVodW50ZXIuY29tCnx8cG1hdGVodW50ZXIuY29tCi5wbWF0ZXMuY29tCnx8 +cG8yYi5jb20KcG9iaWVyYW15LnRvcAohLS18fHBvY29vLm9yZwp8fHBvZGJlYW4u +Y29tCnx8cG9kaWN0aW9uYXJ5LmNvbQp8fHBvZS5jb20KLnBva2Vyc3RhcnMuY29t +Cnx8cG9rZXJzdGFycy5jb20KfHxwb2tlcnN0YXJzLm5ldAp8fHpoLnBva2Vyc3Ry +YXRlZ3kuY29tCnx8cG9saXRpY2FsY2hpbmEub3JnCi5wb2xpdGlzY2FsZXMubmV0 +Cnx8cG9sb25pZXguY29tCnx8cG9seW1lcmhrLmNvbQoucG9wby50dwohLS18fHBv +cHVsYXJwYWdlcy5uZXQKfHxwb3B2b3RlLmhrCnx8cG9weGkuY2xpY2sKLnBvcHlh +cmQuY29tCnx8cG9weWFyZC5vcmcKLnBvcm4uY29tCi5wb3JuMi5jb20KLnBvcm41 +LmNvbQoucG9ybmJhc2Uub3JnCi5wb3JuZXJicm9zLmNvbQp8fHBvcm5oZC5jb20K +LnBvcm5ob3N0LmNvbQoucG9ybmh1Yi5jb20KfHxwb3JuaHViLmNvbQoucG9ybmh1 +YmRldXRzY2gubmV0CnxodHRwOi8vcG9ybmh1YmRldXRzY2gubmV0Ci5wb3Jub3hv +LmNvbQoucG9ybnJhcGlkc2hhcmUuY29tCnx8cG9ybnJhcGlkc2hhcmUuY29tCi5w +b3Juc2hhcmluZy5jb20KfGh0dHA6Ly9wb3Juc2hhcmluZy5jb20KLnBvcm5zb2Nr +ZXQuY29tCnx8cG9ybnN0YXJieWZhY2UuY29tCi5wb3Juc3RhcmNsdWIuY29tCnx8 +cG9ybnN0YXJjbHViLmNvbQoucG9ybnR1YmUuY29tCi5wb3JudHViZW5ld3MuY29t +Ci5wb3JudHZibG9nLmNvbQp8fHBvcm50dmJsb2cuY29tCi5wb3JudmlzaXQuY29t +Ci5wb3J0YWJsZXZwbi5ubAp8fHBvc2tvdGFuZXdzLmNvbQoucG9zdDAxLmNvbQou +cG9zdDc2LmNvbQp8fHBvc3Q3Ni5jb20KLnBvc3Q4NTIuY29tCnx8cG9zdDg1Mi5j +b20KcG9zdGFkdWx0LmNvbQp8fHBvdHZwbi5jb20KfHxwb3VycXVvaS50dwp8fHBv +d2VyY3guY29tCi5wb3dlcnBob3RvLm9yZwp8fHd3dy5wb3dlcnBvaW50bmluamEu +Y29tCnx8cHB5LnNoCnx8cHJlc2lkZW50bGVlLnR3Cnx8Y2RuLnByaW50ZnJpZW5k +bHkuY29tCi5wcml0dW5sLmNvbQpwcm92cG5hY2NvdW50cy5jb20KfHxwcm92cG5h +Y2NvdW50cy5jb20KLnByb3hmcmVlLmNvbQp8fHByb3hmcmVlLmNvbQpwcm94eWFu +b25pbW8uZXMKLnByb3h5bmV0d29yay5vcmcudWsKfHxwcm94eW5ldHdvcmsub3Jn +LnVrCi5wdHR2YW4ub3JnCnx8cHVidS5jb20udHcKfHxwdWZmaW5icm93c2VyLmNv +bQp8fHB1cmVpbnNpZ2h0Lm9yZwoucHV0dHkub3JnCnx8cHV0dHkub3JnCgohLS0t +LS0tLS0tLS0tLVBvc3Rlcm91cy0tLS0tCnx8Y2FsZWJlbHN0b24uY29tCnx8Ymxv +Zy5maXp6aWsuY29tCnx8bmYuaWQuYXUKfHxzb2dyYWR5Lm1lCnx8dmF0bi5vcmcK +fHx2ZW50dXJlc3dlbGwuY29tCnx8d2hlcmVpc3dlcm5lci5jb20KCi5wb3dlci5j +b20KfHxwb3dlci5jb20KcG93ZXJhcHBsZS5jb20KfHxwb3dlcmFwcGxlLmNvbQp8 +fHByYXlmb3JjaGluYS5uZXQKfHxwcmNsZWFkZXIub3JnCnx8cHJlc2VudGF0aW9u +emVuLmNvbQp8fHByZXN0aWdlLWF2LmNvbQoucHJpc29uZXJhbGVydC5jb20KfHxw +cml0dW5sLmNvbQp8fHByaXZhY3lib3guZGUKfHxwcml2YXRlLmNvbQp8fHByaXZh +dGVpbnRlcm5ldGFjY2Vzcy5jb20KcHJpdmF0ZXBhc3RlLmNvbQp8fHByaXZhdGVw +YXN0ZS5jb20KcHJpdmF0ZXR1bm5lbC5jb20KfHxwcml2YXRldHVubmVsLmNvbQp8 +fHByaXZhdGV2cG4uY29tCnx8cHJpdm94eS5vcmcKfHxwcm9jb3B5dGlwcy5jb20K +fHxwcm9qZWN0LXN5bmRpY2F0ZS5vcmcKfHxwcm90b24ubWUKcHJvdmlkZW9jb2Fs +aXRpb24uY29tCnx8cHJvc2liZW4uZGUKcHJveGlmaWVyLmNvbQp8fHByb3hvbWl0 +cm9uLmluZm8KLnByb3hwbi5jb20KfHxwcm94cG4uY29tCnByb3h5cm9hZC5jb20K +LnByb3h5dHVubmVsLm5ldAp8fHBzaHZwbi5jb20KfHxwc2lwaG9uLmNhCi5wc2lw +aG9uMy5jb20KfHxwc2lwaG9uMy5jb20KLnBzaXBob250b2RheS5jb20KfHxwc3Rh +dGljLm5ldAp8fHB0LmltCi5wdHQuY2MKfHxwdHQuY2MKfHxwdHRnYW1lLmNvbQou +cHVmZnN0b3JlLmNvbQp8fG1haW4tZWNucGFwZXItZWNvbm9taXN0LmNvbnRlbnQu +cHVncGlnLmNvbQp8fHB1bGxmb2xpby5jb20KLnB1bnl1LmNvbS9wdW55Cnx8cHVy +ZWNvbmNlcHRzLm5ldAp8fHB1cmVpbnNpZ2h0Lm9yZwp8fHB1cmVwZGYuY29tCnx8 +cHVyZXZwbi5jb20KLnB1cnBsZWxvdHVzLm9yZwoucHVyc3Vlc3Rhci5jb20KfHxw +dXJzdWVzdGFyLmNvbQoucHVzc3lzcGFjZS5jb20KLnB1dGlob21lLm9yZwoucHV0 +bG9ja2VyLmNvbS9maWxlCnB3bmVkLmNvbQp8fHB4aW1nLm5ldApweXRob24uY29t +Ci5weXRob24uY29tLnR3Cnx8cHl0aG9uLmNvbS50dwpweXRob25oYWNrZXJzLmNv +bS9wCnNzLnB5dGhvbmljLmxpZmUKCiEtLS0tLS0tLS0tLS0tLS0tLS0tLVFRLS0t +LS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp8aHR0cDovL3FtcDQuY29tCnx8cWlhbm1v +LnR3Cnx8cWJpdHRvcnJlbnQub3JnCnx8cWdpcmwuY29tLnR3Cnx8cWlhbmJhaS50 +dwp8fHFpYW5kYW8udG9kYXkKfHxxaWFuZ2xpZS5jb20KfHxxaWFuZ3dhaWthbi5j +b20KLnFpLWdvbmcubWUKfHxxaS1nb25nLm1lCiEtLSM5MjEKfHxxaWFuZ3lvdS5v +cmcKLnFpZGlhbi5jYQp8fHFpd2VuLmx1CnFpeGlhbmdsdS5jbgoucWtzaGFyZS5j +b20KcW9vcy5jb20KfHxxb29zLmNvbQp8fGVma3NvZnQuY29tCnx8cXN0YXR1cy5j +b20KfHxxdHJhYy5ldQp8fHF1aXRjY3Aub3JnCi5xdWl0Y2NwLm9yZwoucXVvcmEu +Y29tL0NoaW5hcy1GdXR1cmUKLnF1cmFuLmNvbQp8aHR0cDovL3F1cmFuLmNvbQou +cXVyYW5leHBsb3Jlci5jb20KcXVzaTgubmV0Cm5lbWVzaXMyLnF4Lm5ldC9wYWdl +cy9NeUVuVHVubmVsCnF4YmJzLm9yZwoKIS0tLS0tLS0tLS0tLS0tLS0tLS0tUlIt +LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnx8cmFkbWluLXZwbi5jb20KfHxydWxl +MzR2aWRlby5jb20KfHxyMTBzLmpwCnx8cmFrdXRlbi5jby5qcAp8fHIwLnJ1Cnx8 +cmFkaW8tY2FuYWRhLmNhCnx8cmFkaW8tZW4tbGlnbmUuZnIKfHxyYWVsLm9yZwpy +YWRpY2FscGFydHkub3JnCnx8cmFkaW8uZ2FyZGVuCnx8cmFkaW9hdXN0cmFsaWEu +bmV0LmF1Ci5yYWRpb2hpbGlnaHQubmV0Cnx8cmFkaW9oaWxpZ2h0Lm5ldAp8fHJh +ZGlvbGluZS5jbwpvcG1sLnJhZGlvdGltZS5jb20KfHxyYWRpb3ZhdGljYW5hLm9y +Zwp8fHJhZGlvdm5jci5jb20KfHxyYWdnZWRiYW5uZXIuY29tCnx8cmFpZGNhbGwu +Y29tLnR3Ci5yYWluYm93cGxhbi5vcmcvYmJzCnxodHRwczovL3JhaW5kcm9wLmlv +LwoucmFpem9qaS5vci5qcAp8aHR0cDovL3JhaXpvamkub3IuanAKcmFuZ3plbi5u +ZXQKcmFuZ3plbi5vcmcKfGh0dHA6Ly9ibG9nLnJhbnhpYW5nLmNvbS8KLnJhcGJ1 +bGwubmV0CiEtLXxodHRwOi8vcmFwaWRnYXRvci5uZXQvCnx8cmFwaWRtb3ZpZXou +Y29tCnJhcGlkdnBuLmNvbQp8fHJhcGlkdnBuLmNvbQp8fHJhcmJncHJ4Lm9yZwp8 +fHJhdGlvbmFsd2lraS5vcmcKfHxyYXdnaXQuY29tCnx8cmF3Z2l0aHViLmNvbQp8 +fHJjaW5ldC5jYQp8fHJlYWJibGUuY29tCi5yZWFkMTAwLmNvbQoucmVhZGluZ3Rp +bWVzLmNvbS50dwp8fHJlYWRpbmd0aW1lcy5jb20udHcKfHxyZWFkbW9vLmNvbQou +cmVhZHlkb3duLmNvbQp8aHR0cDovL3JlYWR5ZG93bi5jb20KfHxyZWFsY291cmFn +ZS5vcmcKLnJlYWxpdHlraW5ncy5jb20KfHxyZWFsaXR5a2luZ3MuY29tCi5yZWFs +cmFwdGFsay5jb20KLnJlYWxzZXhwYXNzLmNvbQp8fHJlYXNvbi5jb20KLnJlY29y +ZGhpc3Rvcnkub3JnCi5yZWNvdmVyeS5vcmcudHcKfGh0dHA6Ly9vbmxpbmUucmVj +b3Zlcnl2ZXJzaW9uLm9yZwp8fHJlY292ZXJ5dmVyc2lvbi5jb20udHcKfHxyZWQt +bGFuZy5vcmcKfHxyZWRidWJibGUuY29tCi5yZWRjaGluYWNuLm5ldAp8fHJlZGNo +aW5hY24ubmV0CnJlZGNoaW5hY24ub3JnCnJlZHR1YmUuY29tCnJlZmVyZXIudXMK +fHxyZWZlcmVyLnVzCnx8cmVmbGVjdGl2ZWNvZGUuY29tCnx8YmxvZy5yZWltdS5u +ZXQKcmVsYXhiYnMuY29tCi5yZWxheS5jb20udHcKLnJlbGVhc2VpbnRlcm5hdGlv +bmFsLm9yZwp8fHJlbGlnaW9ubmV3cy5jb20KcmVubWluYmFvLmNvbQp8fHJlbm1p +bmJhby5jb20KLnJlbnl1cmVucXVhbi5vcmcKfHxyZW55dXJlbnF1YW4ub3JnCnxo +dHRwOi8vY2VydGlmaWNhdGUucmV2b2NhdGlvbmNoZWNrLmNvbQp8fHJlc2lsaW8u +Y29tCi5yZXV0ZXJzLmNvbQp8fHJldXRlcnMuY29tCnx8cmV1dGVyc21lZGlhLm5l +dAoucmV2bGVmdC5jb20KfHxyZXNpc3RjaGluYS5vcmcKcmV0d2VldGlzdC5jb20K +fHxyZXR3ZWV0cmFuay5jb20KIS0tY29ubmVjdGVkY2hpbmEucmV1dGVycy5jb20K +IS0tfGh0dHA6Ly93d3cucmV1dGVycy5jb20vbmV3cy92aWRlbwpyZXZ2ZXIuY29t +Ci5yZmEub3JnCnx8cmZhLm9yZwoucmZhY2hpbmEuY29tCi5yZmFtb2JpbGUub3Jn +CnJmYXdlYi5vcmcKfHxyZmVybC5vcmcKLnJmaS5mcgp8fHJmaS5mcgp8fHJmaS5t +eQohLS0ucmhjbG91ZC5jb20KIS0tRWRnZWNhc3QKLnJpZ3BhLm9yZwoucmlsZXln +dWlkZS5jb20KfHxyaWt1Lm1lCi5yaXRvdWtpLmpwCnx8cml0dGVyLnZnCi5ybHds +dy5jb20KfHxybHdsdy5jb20KfHxybWJsLndzCi5ybWpkdy5jb20KLnJvYWRzaG93 +LmhrCi5yb2JvZm9yZXguY29tCnx8cm9idXN0bmVzc2lza2V5LmNvbQohLS18fHJv +Yy10YWl3YW4ub3JnCnx8cm9ja2V0LmNoYXQKfHxyb2NrZXQtaW5jLm5ldAp8aHR0 +cDovL3d3dzIucm9ja2V0YmJzLmNvbS8xMS9iYnMuY2dpP2lkPTVtdXMKfGh0dHA6 +Ly93d3cyLnJvY2tldGJicy5jb20vMTEvYmJzLmNnaT9pZD1mcmVlbWdsCiEtLXx8 +cm9jbXAub3JnCnx8cm9qby5jb20KfHxyb25qb25lc3dyaXRlci5jb20KfHxyb2xm +b3VuZGF0aW9uLm9yZwp8fHJvbGlhLm5ldAp8fHJvbHNvY2lldHkub3JnCi5yb29k +by5jb20KLnJvc2VjaGluYS5uZXQKfHxyb3UudmlkZW8KLnJzZi5vcmcKfHxyc2Yu +b3JnCi5yc2YtY2hpbmVzZS5vcmcKfHxyc2YtY2hpbmVzZS5vcmcKfHxyc3NodWIu +YXBwCnx8cGhvc3BoYXRpb24xMy5yc3NpbmcuY29tCi5yc3NtZW1lLmNvbQp8fHJz +c21lbWUuY29tCnx8cnRhbGFiZWwub3JnCi5ydGhrLmhrCnx8cnRoay5oawoucnRo +ay5vcmcuaGsKfHxydGhrLm9yZy5oawoucnRpLm9yZy50dwp8fHJ0aS5vcmcudHcK +fHxydGkudHcKLnJ1YW55aWZlbmcuY29tL2Jsb2cqc29tZV93YXlzX3RvX2JyZWFr +X3RoZV9ncmVhdF9maXJld2FsbApydWtvci5vcmcKfHxydWxlMzQueHh4Cnx8cnVt +YmxlLmNvbQoucnVuYnR4LmNvbQoucnVzaGJlZS5jb20KfHxydXN2cG4uY29tCi5y +dXRlbi5jb20udHcKfHxydXRlbi5jb20udHcKfHxydXRyYWNrZXIubmV0Cnx8cnV0 +cmFja2VyLm9yZwpydXR1YmUucnUKLnJ4aGoubmV0CnxodHRwOi8vcnhoai5uZXQK +CiEtLS0tLS0tLS0tLS0tLS0tLS0tLVNTLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t +LQp8fHNpbmEuY29tLmhrCnx8c3dhcHNwYWNlLmNvCnx8c3RvcnJ5LnR2Cnx8c3Rh +bmRhcmQuY28udWsKfHxzYWdlcm5ldC5vcmcKfHxzaW1wbGV4LmNoYXQKfHxzb3Vu +ZG9uLmZtCnx8c3NydG9vbC5jb20KfHxzc3JzaGFyZS51cwp8fHNlY3VyZS5zaGFk +b3dzb2Nrcy5udQp8fHN5bmFwc2Uub3JnCnx8c291dGgtcGx1cy5uZXQKfHxzaWx2 +ZXJnYXRlYmFuay5jb20KfHxzaGFyZS12aWRlb3Muc2UKfHxzc3JzaGFyZS51cwp8 +fGNkbi5zdGF0aWNhbGx5LmlvCnx8c2xpZGVzLmNvbQp8fHN1bm8uY29tCnx8c3lk +bmV5LmJpbmcuY29tCnx8c2VodWF0YW5nLm9yZwp8fHNpbmdsZWxvZ2luLnNlCnx8 +c3Vuby5haQp8fHN5b3NldHUuY29tCi5zMXMxczEuY29tCnx8cy1jdXRlLmNvbQou +cy1kcmFnb24ub3JnCnxodHRwOi8vd3d3LnM0bWluaWFyY2hpdmUuY29tCmNkbjEu +bHAuc2Fib29tLmNvbQp8fHNhY2tzLmNvbQpzYWNvbS5oawp8fHNhY29tLmhrCnx8 +c2FkcGFuZGEudXMKfHxzYWZlY2hhdC5jb20KfHxzYWZlZ3VhcmRkZWZlbmRlcnMu +Y29tCi5zYWZlcnZwbi5jb20KfHxzYWZlcnZwbi5jb20KLnNhaW50eWN1bHR1cmUu +Y29tCnxodHRwOi8vc2FpbnR5Y3VsdHVyZS5jb20KfHxzYWt1cmFsaXZlLmNvbQou +c2FreWEub3JnCi5zYWx2YXRpb24ub3JnLmhrCnx8c2FsdmF0aW9uLm9yZy5oawou +c2FtYWlyLnJ1L3Byb3h5L3R5cGUtMDEKLnNhbWJob3RhLm9yZwp8fGNuLnNhbmRz +Y290YWljZW50cmFsLmNvbQp8fHNhbmtha3Vjb21wbGV4LmNvbQp8fHNhbmtlaS5j +b20KfHxzYW5taW4uY29tLnR3CnNhcGlrYWNodS5uZXQKc2F2ZW1lZGlhLmNvbQp8 +fHNhdmV0aGVzb3VuZHMuaW5mbwouc2F2ZXRpYmV0LmRlCnx8c2F2ZXRpYmV0LmRl +CnNhdmV0aWJldC5mcgpzYXZldGliZXQubmwKLnNhdmV0aWJldC5vcmcKfHxzYXZl +dGliZXQub3JnCnNhdmV0aWJldC5ydQouc2F2ZXRpYmV0c3RvcmUub3JnCnx8c2F2 +ZXRpYmV0c3RvcmUub3JnCnx8c2F2ZXVpZ2h1ci5vcmcKc2F2ZXZpZC5jb20KLnNi +bWUubWUKfGh0dHA6Ly9zYm1lLm1lCi5zYnMuY29tLmF1L3lvdXJsYW5ndWFnZQou +c2Nhc2luby5jb20KfGh0dHA6Ly93d3cuc2NpZW5jZW1hZy5vcmcvY29udGVudC8z +NDQvNjE4Ny85NTMKLnNjaWVuY2VuZXRzLmNvbQouc2NtcC5jb20KfHxzY21wLmNv +bQouc2NtcGNoaW5lc2UuY29tCnx8c2NyYW1ibGUuaW8KfHxzY3JpYmQuY29tCnx8 +c2NyaXB0c3BvdC5jb20KfHxzZWFyY2guY29tCi5zZWFyY2h0cnV0aC5jb20KfHxz +ZWFyeC5tZQp8fHNlYXR0bGVmZGMuY29tCi5zZWNyZXRjaGluYS5jb20KfHxzZWNy +ZXRjaGluYS5jb20KfHxzZWNyZXRnYXJkZW4ubm8KLnNlY3JldHNsaW5lLmJpegp8 +fHNlY3JldHNsaW5lLmJpegp8fHNlY3VyZXNlcnZlcmNkbi5uZXQKfHxzZWN1cmV0 +dW5uZWwuY29tCnNlY3VyaXR5aW5hYm94Lm9yZwp8aHR0cHM6Ly9zZWN1cml0eWlu +YWJveC5vcmcKLnNlY3VyaXR5a2lzcy5jb20KfHxzZWN1cml0eWtpc3MuY29tCnx8 +c2VlZDQubWUKfHxuZXdzLnNlZWh1YS5jb20Kc2Vlc21pYy5jb20KfHxzZWV2cG4u +Y29tCnx8c2Vlem9uZS5uZXQKfHxzZWh1YXRhbmcubmV0CnNlamllLmNvbQouc2Vu +ZHNwYWNlLmNvbQp8fHNlbnNvcnRvd2VyLmNvbQpzZXNhd2UubmV0Cnx8c2VzYXdl +Lm5ldAp8fHNldGh3a2xlaW4ubmV0Cnx8c2V0bi5jb20KLnNldHR2LmNvbS50dwou +c2V2ZW5sb2FkLmNvbQp8fHNldmVubG9hZC5jb20KLnNleC5jb20KfHxzZXguY29t +Cnx8c2V4My5jb20KfHxzZXg4LmNjCi5zZXhhbmRzdWJtaXNzaW9uLmNvbQouc2V4 +Ym90LmNvbQouc2V4aHUuY29tCnNleGluc2V4Lm5ldAp8fHNleGluc2V4Lm5ldAou +c2V4dHZ4LmNvbQoKIS0tSVAgb2YgU2V4SW5TZXgKNjcuMjIwLjkxLjE1CjY3LjIy +MC45MS4xOAo2Ny4yMjAuOTEuMjMKCnxodHRwOi8vKi5zZi5uZXQKLnNmaWxleWR5 +LmNvbQp8fHNmc2hpYmFvLmNvbQouc2Z0aW5kaWEub3JnCi5zZnR1ay5vcmcKfHxz +ZnR1ay5vcmcKfHxzaGFkZXlvdXZwbi5jb20Kc2hhZG93Lm1hCi5zaGFkb3dza3ku +eHl6Ci5zaGFkb3dzb2Nrcy5hc2lhCnx8d3d3LnNoYWRvd3NvY2tzLmNvbQouc2hh +ZG93c29ja3MuY29tCnx8c2hhZG93c29ja3MuY29tLmhrCi5zaGFkb3dzb2Nrcy5v +cmcKfHxzaGFkb3dzb2Nrcy5vcmcKfGh0dHA6Ly9jbi5zaGFmYXFuYS5jb20KfHxz +aGFoaXQuYml6Ci5zaGFtYmFsYXBvc3QuY29tCnNoYXBlc2VydmljZXMuY29tCi5z +aGFyZWJlZS5jb20KfHxzaGFyZWNvb2wub3JnCiEtLXx8c2hhcmtkb2xwaGluLmNv +bQouc2hhcnBkYWlseS5oawouc2hhcnBkYWlseS50dwouc2hhdC10aWJldC5jb20K +c2hlaWt5ZXJtYW1pLmNvbQouc2hlbGxmaXJlLmRlCnx8c2hlbGxmaXJlLmRlCnNo +ZW55dW4uY29tCnNoZW55dW5wZXJmb3JtaW5nYXJ0cy5vcmcKfHxzaGVueXVucGVy +Zm9ybWluZ2FydHMub3JnCnx8c2hlbnl1bnNob3AuY29tCnNoZW56aG91ZmlsbS5j +b20KfHxzaGVuemhvdWZpbG0uY29tCnx8c2hlbnpob3V6aGVuZ2Rhby5vcmcKLnNo +aWF0di5uZXQKLnNoaWNoZW5nLm9yZwpzaGlwY2Ftb3VmbGFnZS5jb20KLnNoaXJl +eWlzaHVuamlhbi5jb20KLnNoaXRhb3R2Lm9yZwp8fHNoaXhpYW8ub3JnCnx8c2hp +emhhby5vcmcKc2hpemhhby5vcmcKc2hrc3ByLm1vYmkvZGFicgp8fHNob2Rhbmhx +LmNvbQp8fHNob29zaHRpbWUuY29tCi5zaG9wMjAwMC5jb20udHcKfHxzaG9wZWUu +dHcKLnNob3BwaW5nLmNvbQouc2hvd2hhb3R1LmNvbQouc2hvd3RpbWUuanAKfHxz +aG93d2UudHcKLnNodXR0ZXJzdG9jay5jb20KfHxzaHV0dGVyc3RvY2suY29tCi5z +aHdjaHVyY2gub3JnCnx8c2h3Y2h1cmNoLm9yZwouc2h3Y2h1cmNoMy5jb20KfGh0 +dHA6Ly9zaHdjaHVyY2gzLmNvbQouc2lkZGhhcnRoYXNpbnRlbnQub3JnCnx8c2lk +ZWxpbmVzbmV3cy5jb20KLnNpZGVsaW5lc3Nwb3J0c2VhdGVyeS5jb20KfHxzaWdu +YWwub3JnCi5zaWppaHVpc3VvLmNsdWIKLnNpamlodWlzdW8uY29tCi5zaWxrYm9v +ay5jb20KfHxzaW1ib2xvc3R3aXR0ZXIuY29tCnNpbXBsZWNkLm9yZwp8fHNpbXBs +ZWNkLm9yZwp8fHNpbXBsZWNkLm1lCnNpbXBsZXByb2R1Y3Rpdml0eWJsb2cuY29t +CmJicy5zaW5hLmNvbS8KYmJzLnNpbmEuY29tJTJGCmRhaWx5bmV3cy5zaW5hLmNv +bS8KZGFpbHluZXdzLnNpbmEuY29tJTJGCmhvbWUuc2luYS5jb20KbmV3cy5zaW5h +LmNvbS5oawpuZXdzLnNpbmNoZXcuY29tLm15Ci5zaW5jaGV3LmNvbS5teS9ub2Rl +Lwouc2luY2hldy5jb20ubXkvdGF4b25vbXkvdGVybQouc2luZ2Fwb3JlcG9vbHMu +Y29tLnNnCnx8c2luZ2Fwb3JlcG9vbHMuY29tLnNnCi5zaW5nZm9ydGliZXQuY29t +Ci5zaW5ncGFvLmNvbS5oawpzaW5ndGFvLmNvbQp8fHNpbmd0YW8uY29tCm5ld3Mu +c2luZ3Rhby5jYQouc2luZ3Rhb3VzYS5jb20KfHxzaW5ndGFvdXNhLmNvbQohLS18 +fGNkcC5zaW5pY2EuZWR1LnR3CnNpbm8tbW9udGhseS5jb20KfHxzaW5vY2EuY29t +Cnx8c2lub2Nhc3QuY29tCnNpbm9jaXNtLmNvbQpzaW5vbW9udHJlYWwuY2EKLnNp +bm9hbnRzLmNvbQp8fHNpbm9hbnRzLmNvbQp8fHNpbm9pbnNpZGVyLmNvbQouc2lu +b3F1ZWJlYy5jb20KLnNpZXJyYWZyaWVuZHNvZnRpYmV0Lm9yZwpzaXMueHh4Cnx8 +c2lzMDAxLmNvbQpzaXMwMDEudXMKLnNpdGUydW5ibG9jay5jb20KLnNpdGVicm8u +dHcKfHxzaXRla3JlYXRvci5jb20KfHxzaXRlbWFwcy5vcmcKfHxza2V0Y2hhcHBz +b3VyY2VzLmNvbQp8fHNraW10dWJlLmNvbQp8fGxhYi5za2subW9lCnx8c2t5YmV0 +LmNvbQp8aHR0cDovL3VzZXJzLnNreW5ldC5iZS9yZXZlcy90aWJldGhvbWUuaHRt +bAouc2t5a2luZy5jb20udHcKYmJzLnNreWtpd2kuY29tCnxodHRwOi8vd3d3LnNr +eXBlLmNvbS9pbnRsLwp8aHR0cDovL3d3dy5za3lwZS5jb20vemgtSGFudAp8fHNr +eXZlZ2FzLmNvbQoueHNreXdhbGtlci5jb20KfHx4c2t5d2Fsa2VyLmNvbQp8fHNr +eXh2cG4uY29tCi5zbGF5dGl6bGUuY29tCi5zbGVhenlkcmVhbS5jb20KfHxzbGVh +enlmb3JrLm9yZwp8fHNsaGVuZy5jb20KfHxzbGlkZXNoYXJlLm5ldApmb3J1bS5z +bGltZS5jb20udHcKLnNsaW5rc2V0LmNvbQp8fHNsaWNrdnBuLmNvbQouc2x1dGxv +YWQuY29tCnx8c21hcnRkbnNwcm94eS5jb20KLnNtYXJ0aGlkZS5jb20KfHxhcHAu +c21hcnRtYWlsY2xvdWQuY29tCnNtY2hib29rcy5jb20KfHxzbWguY29tLmF1CnNt +aHJpYy5vcmcKLnNtaXRoLmVkdS9kYWxhaWxhbWEKfHxzbW4ubmV3cwouc215eHku +b3JnCiEtLVRPRE8tbm8taG9tZXBhZ2UKfHxzbmRjZG4uY29tCnNuZWFrbWUubmV0 +CnNub3dsaW9ucHViLmNvbQp8fHNvY2lhbGJsYWRlLmNvbQouc29ja3MtcHJveHku +bmV0Cnx8c29ja3MtcHJveHkubmV0Ci5zb2Nrc2NhcDY0LmNvbQp8fHNvY2tzbGlz +dC5uZXQKLnNvY3JlYy5vcmcKfGh0dHA6Ly9zb2NyZWMub3JnCi5zb2QuY28uanAK +LnNvZnRldGhlci5vcmcKfHxzb2Z0ZXRoZXIub3JnCi5zb2Z0ZXRoZXItZG93bmxv +YWQuY29tCnx8c29mdGV0aGVyLWRvd25sb2FkLmNvbQp8fGNkbi5zb2Z0bGF5ZXIu +bmV0Cnx8c29nY2x1Yi5jb20Kc29oY3JhZGlvLmNvbQp8fHNvaGNyYWRpby5jb20K +LnNva21pbC5jb20KfHxzb3J0aW5nLWFsZ29yaXRobXMuY29tCnx8c291cC5pbwpA +QHx8c3RhdGljLnNvdXAuaW8KLnNvYmVlcy5jb20KfHxzb2JlZXMuY29tCi5zb2Z0 +ZXRoZXIuY28uanAKfHxzb2Z0d2FyZWJ5Y2h1Y2suY29tCmJsb2cuc29nb28ub3Jn +CnNvaC50dwp8fHNvaC50dwpzb2hmcmFuY2Uub3JnCnx8c29oZnJhbmNlLm9yZwpj +aGluZXNlLnNvaWZpbmQuY29tCnNva2Ftb25saW5lLmNvbQp8fHNvbGFuYS5jb20K +LnNvbGlkYXJpdGV0aWJldC5vcmcKLnNvbGlkZmlsZXMuY29tCnx8c29tZWUuY29t +Ci5zb25namlhbmp1bi5jb20KfHxzb25namlhbmp1bi5jb20KLnNvbmlkb2RlbGFl +c3BlcmFuemEub3JnCi5zb3BjYXN0LmNvbQouc29wY2FzdC5vcmcKfHxuYWtlZHNl +Y3VyaXR5LnNvcGhvcy5jb20KfHxzb3Mub3JnCnx8c29zYWQuZnVuCmJicy5zb3Ut +dG9uZy5vcmcKLnNvdWJvcnkuY29tCnxodHRwOi8vc291Ym9yeS5jb20KLnNvdWwt +cGx1cy5uZXQKLnNvdWxjYWxpYnVyaGVudGFpLm5ldAp8fHNvdWxjYWxpYnVyaGVu +dGFpLm5ldAp8fHNvdW5kY2xvdWQuY29tCiEtLXxodHRwczovL3NvdW5kY2xvdWQu +Y29tL3B1bmtnb2QKLnNvdW5kb2Zob3BlLmtyCnNvdW5kb2Zob3BlLm9yZwp8fHNv +dW5kb2Zob3BlLm9yZwohLS0uc291cmNlZm9yZ2UubmV0CiEtfGh0dHA6Ly9zb3Vy +Y2Vmb3JnZS5uZXQKfGh0dHA6Ly9zb3VyY2Vmb3JnZS5uZXQvcCovc2hhZG93c29j +a3NndWkvCi5zb3VyY2V3YWRpby5jb20KfHxzb3V0aC1wbHVzLm9yZwp8fHNvdXRo +bW9uZ29saWEub3JnCnx8c291dGhuZXdzLmNvbS50dwp8fHNvd2Vycy5vcmcuaGsK +fHxzcGFua2JhbmcuY29tCi5zcGFua2luZ3R1YmUuY29tCi5zcGFua3dpcmUuY29t +Cnx8c3BhdGlhbC5pbwp8fHNwYi5jb20KfHxzcGVha2VyZGVjay5jb20KfHxzcGVl +ZGNhdC5tZQp8fHNwZWVkaWZ5LmNvbQp8fHNwZW5jZXJ0aXBwaW5nLmNvbQp8fHNw +ZW5kZWUuY29tCnx8c3BpY2V2cG4uY29tCi5zcGlkZXJvYWsuY29tCnx8c3BpZGVy +b2FrLmNvbQouc3Bpa2UuY29tCi5zcG90Zmx1eC5jb20KfHxzcG90Zmx1eC5jb20K +fHxzcHJlYWtlci5jb20KLnNwcmluZzR1LmluZm8KfHxzcHJpbmc0dS5pbmZvCnx8 +c3ByaW5nd29vZC5tZQp8fHNwcm91dGNvcmUuY29tCnx8c3F1aXJyZWx2cG4uY29t +Ci5zcy1saW5rLmNvbQp8fHNzLWxpbmsuY29tCi5zc2dsb2JhbC5jby93cAp8aHR0 +cDovL3NzZ2xvYmFsLmNvCi5zc2dsb2JhbC5tZQouc3Nyc2hhcmUuY29tCnx8c3Ny +c2hhcmUuY29tCiEtLXxodHRwOi8vY2RuLnNzdGF0aWMubmV0Lwp8fHNzdG0ubW9l +Cnx8c3N0bWx0Lm1vZQpzc3RtbHQubmV0Cnx8c3N0bWx0Lm5ldAp8aHR0cDovL3N0 +YWNrb3ZlcmZsb3cuY29tL3VzZXJzLzg5NTI0NQp8fHN0YW5kdXBmb3J0aWJldC5v +cmcKfHxzdGFuZHdpdGhoay5vcmcKc3RhbmZvcmQuZWR1L2dyb3VwL2ZhbHVuCi5z +dGFyZmlzaGZ4LmNvbQouc3RhcnAycC5jb20KfHxzdGFycDJwLmNvbQouc3RhcnRw +YWdlLmNvbQp8fHN0YXJ0cGFnZS5jb20KLnN0YXJ0dXBsaXZpbmdjaGluYS5jb20K +fGh0dHA6Ly9zdGFydHVwbGl2aW5nY2hpbmEuY29tCnx8c3RhdGljLWVjb25vbWlz +dC5jb20KfHxzdGJveS5uZXQKfHxzdGMuY29tLnNhCnx8c3RlZWwtc3Rvcm0uY29t +Ci5zdGVnYW5vcy5jb20KfHxzdGVnYW5vcy5jb20KLnN0ZWdhbm9zLm5ldAouc3Rl +cGNoaW5hLmNvbQohLS18fHN0ZXBtYW5pYS5jb20KaGQuc3RoZWFkbGluZS5jb20v +bmV3cy9yZWFsdGltZQpzdGhvby5jb20KfHxzdGhvby5jb20KLnN0aWNrYW0uY29t +CnN0aWNrZXJhY3Rpb24uY29tL3Nlc2F3ZQouc3RpbGVwcm9qZWN0LmNvbQp8fHN0 +aXRjaGVyLmNvbQouc3RvLmNjCi5zdG9wb3JnYW5oYXJ2ZXN0aW5nLm9yZwp8fHN0 +b3JhZ2VuZXdzbGV0dGVyLmNvbQouc3Rvcm0ubWcKfHxzdG9ybS5tZwouc3RvcHRp +YmV0Y3Jpc2lzLm5ldAp8fHN0b3B0aWJldGNyaXNpcy5uZXQKfHxzdG9yai5pbwou +c3Rvcm1tZWRpYWdyb3VwLmNvbQp8fHN0b3dlYm95ZC5jb20KfHxzdHJhaXRzdGlt +ZXMuY29tCnN0cmFuYWJnLmNvbQp8fHN0cmFwbGVzc2RpbGRvLmNvbQp8fHN0cmVh +bWFibGUuY29tCnx8c3RyZWFtYXRlLmNvbQp8fHN0cmVhbWluZ3RoZS5uZXQKc3Ry +ZWVtYS5jb20vdHYvTlREVFZfQ2hpbmVzZQpjbi5zdHJlZXR2b2ljZS5jb20vYXJ0 +aWNsZQpjbi5zdHJlZXR2b2ljZS5jb20vZGlhcnkKdHcuc3RyZWV0dm9pY2UuY29t +Ci5zdHJpa2luZ2x5LmNvbQp8fHN0cm9uZ3Zwbi5jb20KLnN0cm9uZ3dpbmRwcmVz +cy5jb20KfHxzdHVkZW50c2ZvcmFmcmVldGliZXQub3JnCnx8c3R1bWJsZXVwb24u +Y29tCnN0dXBpZHZpZGVvcy5jb20KfHxzdWJzdGFjay5jb20KfHxzdWJoZC50dgou +c3VjY2Vzc2ZuLmNvbQpwYW5hbWFwYXBlcnMuc3VlZGRldXRzY2hlLmRlCi5zdWdh +cnN5bmMuY29tCnx8c3VnYXJzeW5jLmNvbQouc3Vnb2Jicy5jb20KfHxzdWd1bWly +dTE4LmNvbQp8fHN1aXNzbC5jb20Kc3VtbWlmeS5jb20KLnN1bXJhbmRvLmNvbQp8 +fHN1bXJhbmRvLmNvbQpzdW4xOTExLmNvbQp8fHN1bmRheWd1YXJkaWFubGl2ZS5j +b20KLnN1bnBvcm5vLmNvbQp8fHN1bm1lZGlhLmNhCnx8c3VucG9ybm8uY29tCi5z +dW5za3lmb3J1bS5jb20KLnN1bnRhLmNvbS50dwouc3VudnBuLm5ldAouc3VwZXJm +cmVldnBuLmNvbQouc3VwZXJ2cG4ubmV0Cnx8c3VwZXJ2cG4ubmV0Ci5zdXBlcnpv +b2kuY29tCnxodHRwOi8vc3VwZXJ6b29pLmNvbQouc3VwcGlnLm5ldAouc3VwcmVt +ZW1hc3RlcnR2LmNvbQp8aHR0cDovL3N1cHJlbWVtYXN0ZXJ0di5jb20KLnN1cmZl +YXN5LmNvbQp8fHN1cmZlYXN5LmNvbQouc3VyZmVhc3kuY29tLmF1CnxodHRwOi8v +c3VyZmVhc3kuY29tLmF1Cnx8c3VyZnNoYXJrLmNvbQp8fHN1cnJlbmRlcmF0MjAu +bmV0Ci5zdnNmeC5jb20KLnN3aXNzaW5mby5jaAp8fHN3aXNzaW5mby5jaAouc3dp +c3N2cG4ubmV0Cnx8c3dpc3N2cG4ubmV0CnN3aXRjaHZwbi5uZXQKfHxzd2l0Y2h2 +cG4ubmV0Ci5zeWRuZXl0b2RheS5jb20KfHxzeWRuZXl0b2RheS5jb20KLnN5bGZv +dW5kYXRpb24ub3JnCnx8c3lsZm91bmRhdGlvbi5vcmcKfHxzeW5jYmFjay5jb20K +c3lzcmVzY2NkLm9yZwouc3l0ZXMubmV0CmJsb2cuc3l4ODYuY29tLzIwMDkvMDkv +cHVmZgouc3piYnMubmV0Ci5zemV0b3dhaC5vcmcuaGsKCiEtLS0tLS0tLS0tLS0t +LS0tLS0tLVRULS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp8fHRhbGthdG9uZS5j +b20KfHx0YW5rcy5nZwp8fHRoZWhhbnNpbmRpYS5jb20KfHxydG0udG50LWVhLmNv +bQp8fHRlbGxhcGFydC5jb20KfHx0aHJlYWRzLmNvbQp8fHRnLW1lLmNvbQp8fHR3 +a2FuLmNvbQp8fHR1bmVpbi5zdHJlYW1ndXlzMS5jb20KfHx0b3UudHYKfHx0aW55 +dXJsLmNvbQp8fHRleHRub3cuY29tCnx8dGV4dG5vdy5tZQp8fHRva2VuLmltCnx8 +dG9rZW5sb24uaW0KfHx0YXJkaWdyYWRlLmlvCnx8dG9ycmVudGdhbGF4eS50bwp8 +fHRvbXAzLmNjCnx8dHVrYWFuaS5vcmcKfHx0aGV0YXRva2VuLm9yZwp8fHR5cGVz +ZXQuaW8KfHx0aGVjaGFzZXJuZXdzLmNvLnVrCnx8aG9sZS50aHUubW9uc3Rlcgp8 +fHRodWhvbGUuY29tCnx8dC1nLmNvbQoudDM1LmNvbQoudDY2eS5jb20KfHx0NjZ5 +LmNvbQp8fGVzZy50OTF5LmNvbQoudGFhLXVzYS5vcmcKfGh0dHA6Ly90YWEtdXNh +Lm9yZwoudGFhemUudHcKfHx0YWF6ZS50dwp8aHR0cDovL3d3dy50YWJsZXNnZW5l +cmF0b3IuY29tLwp0YWJ0dGVyLmpwCi50YWNvbmV0LmNvbS50dwp8fHRhZWRwLm9y +Zy50dwoudGFmbS5vcmcKdGFnd2Fsay5jb20KfHx0YWd3YWxrLmNvbQp0YWhyLm9y +Zy50dwoudGFpcGVpc29jaWV0eS5vcmcKfHx0YWlwZWlzb2NpZXR5Lm9yZwp8fHRh +aXBlaXRpbWVzLmNvbQp8fHRhaXNvdW5kcy5jb20KLnRhaXdhbmJpYmxlLmNvbQou +dGFpd2FuZGFpbHkubmV0Cnx8dGFpd2FuZGFpbHkubmV0Ci50YWl3YW5kYy5vcmcK +IS0tfHx0YWl3YW5lbWJhc3N5Lm9yZwp8fHRhaXdhbmhvdC5uZXQKLnRhaXdhbmp1 +c3RpY2UuY29tCnRhaXdhbmtpc3MuY29tCnRhaXdhbm5hdGlvbi5jb20KdGFpd2Fu +bmF0aW9uLmNvbS50dwp8fHRhaXdhbm5jZi5vcmcudHcKfHx0YWl3YW5uZXdzLmNv +bS50dwp8aHR0cDovL3d3dy50YWl3YW5vbmxpbmUuY2MvCiEtLXx8dGFpd2FudG9k +YXkudHcKdGFpd2FudHAubmV0Cnx8dGFpd2FudHQub3JnLnR3CnRhaXdhbnVzLm5l +dAoudGFsazg1My5jb20KLnRhbGtib3hhcHAuY29tCnx8dGFsa2JveGFwcC5jb20K +LnRhbGtjYy5jb20KfHx0YWxrY2MuY29tCi50YWxrb25seS5uZXQKfHx0YWxrb25s +eS5uZXQKfHx0YW5jLm9yZwoudGFuZ3Jlbi51cwoudGFvaXNtLm5ldAp8aHR0cDov +L3Rhb2lzbS5uZXQKLnRhcGF0YWxrLmNvbQp8fHRhcGF0YWxrLmNvbQpibG9nLnRh +cmFnYW5hLmNvbQp8fHRhdXAubmV0Ci50YXdlZXQuY29tCnx8dGF3ZWV0LmNvbQou +dGJjb2xsZWdlLm9yZwp8fHRiY29sbGVnZS5vcmcKLnRiaS5vcmcuaGsKLnRianl0 +Lm9yZwoudGJyYy5vcmcKdGJzLXJhaW5ib3cub3JnCi50YnNlYy5vcmcKfHx0YnNl +Yy5vcmcKdGJza2tpbmFiYWx1LnBhZ2UudGwKLnRic24ub3JnCnx8dGJzbi5vcmcK +LnRic3NlYXR0bGUub3JnCi50YnNzcWgub3JnCnxodHRwOi8vdGJzc3FoLm9yZwp0 +YnN3ZC5vcmcKLnRidGVtcGxlLm9yZy51awoudGJ0aG91c3Rvbi5vcmcKLnRjY3dv +bmxpbmUub3JnCi50Y2V3Zi5vcmcKdGNocmQub3JnCnRjbnluai5vcmcKfHx0Y3Bz +cGVlZC5jbwoudGNzb2ZiYy5vcmcKLnRkbS5jb20ubW8KdGVhbWFtZXJpY2FueS5j +b20KfHx0ZWNoc3BvdC5jb20KIS0tT1ZICnx8dGVjaHZpei5uZXQKfHx0ZWNrLmlu +Ci50ZWVuaWVmdWNrLm5ldAp0ZWVuc2luYXNpYS5jb20KfHx0ZWhyYW50aW1lcy5j +b20KLnRlbGVjb21zcGFjZS5jb20KfHx0ZWxlZ3JhcGguY28udWsKLnRlbmFjeS5j +b20KfHx0ZW5vci5jb20KfHx0ZW56aW5wYWxtby5jb20KLnRldy5vcmcKfHx0ZXcu +b3JnCnx8dGZjLXRhaXdhbi5vcmcudHcKfHx0ZmlmbHZlLmNvbQoudGhhaWNuLmNv +bQp8fHRoZWF0bGFudGljLmNvbQp8fHRoZWF0cnVtLWJlbGxpLmNvbQp8fGNuLnRo +ZWF1c3RyYWxpYW4uY29tLmF1CnRoZWJsZW1pc2guY29tCnx8dGhlYmNvbXBsZXgu +Y29tCnx8dGhlYmxhemUuY29tCi50aGVib2JzLmNvbQp8fHRoZWJvYnMuY29tCi50 +aGVjaGluYWJlYXQub3JnCnx8dGhlY2hpbmFjb2xsZWN0aW9uLm9yZwp8aHR0cDov +L3d3dy50aGVjaGluYXN0b3J5Lm9yZy95ZWFyYm9va3MveWVhcmJvb2stMjAxMi8K +fHx0aGVjb252ZXJzYXRpb24uY29tCi50aGVkYWxhaWxhbWFtb3ZpZS5jb20KfGh0 +dHA6Ly90aGVkYWxhaWxhbWFtb3ZpZS5jb20KfHx0aGVkaXBsb21hdC5jb20KfHx0 +aGVkdy51cwp8fHRoZWVwb2NodGltZXMuY29tCiEtLXx8dGhlZnJlZWxhbmQuY2x1 +Ygp8fHRoZWd1YXJkaWFuLmNvbQp8fHRoZWdheS5jb20KfGh0dHA6Ly90aGVnaW9p +dGluaG9jLnZuLwoudGhlZ2x5LmNvbQp8fHRoZWhpbmR1LmNvbQp8fHRoZWh1bi5u +ZXQKLnRoZWluaXRpdW0uY29tCnx8dGhlaW5pdGl1bS5jb20KLnRoZW5ld3NsZW5z +LmNvbQp8fHRoZW5ld3NsZW5zLmNvbQoudGhlcGlyYXRlYmF5Lm9yZwp8fHRoZXBp +cmF0ZWJheS5vcmcKIS0tfHx0aGVwaXJhdGViYXkuc2UKLnRoZXBvcm5kdWRlLmNv +bQp8fHRoZXBvcm5kdWRlLmNvbQp8fHRoZXBvcnRhbHdpa2kuY29tCnx8dGhlcHJp +bnQuaW4KfHx0aHJlYWRyZWFkZXJhcHAuY29tCnRoZXJvY2submV0Lm56Cnx8dGhl +c2F0dXJkYXlwYXBlci5jb20uYXUKfHx0aGVzdGFuZG5ld3MuY29tCnRoZXRpYmV0 +Y2VudGVyLm9yZwp0aGV0aWJldGNvbm5lY3Rpb24ub3JnCi50aGV0aWJldG11c2V1 +bS5vcmcKLnRoZXRpYmV0cG9zdC5jb20KfHx0aGV0aWJldHBvc3QuY29tCnRoZXRy +b3Rza3ltb3ZpZS5jb20KfHx0aGV0dmRiLmNvbQp8fHRoZXdnby5vcmcKfHx0aGV3 +aXJlY2hpbmEuY29tCi50aGV5bmMuY29tCnxodHRwOi8vdGhleW5jLmNvbQoudGhp +bmtpbmd0YWl3YW4uY29tCnx8dGhpbmtpbmd0YWl3YW4uY29tCnx8dGhpcmRtaWxs +Lm9yZwp8fHRoaXNhdi5jb20KLnRobGliLm9yZwp8fHRob21hc2Jlcm5oYXJkLm9y +ZwoudGhvbmdkcmVhbXMuY29tCnx8dGhyb3VnaG5pZ2h0c2ZpcmUuY29tCi50aHVt +YnppbGxhLmNvbQp8fHRoeXdvcmRzLmNvbQp0aWFuYW5tZW5tb3RoZXIub3JnCi50 +aWFuYW5tZW5kdWl6aGkuY29tCnx8dGlhbmFubWVuZHVpemhpLmNvbQp8fHRpYW5h +bm1lbnVuaXYuY29tCnx8dGlhbmFubWVudW5pdi5uZXQKfHx0aWFuZGl4aW5nLm9y +ZwoudGlhbmh1YXl1YW4uY29tCi50aWFubGF3b2ZmaWNlLmNvbQp8fHRpYW50aS5p +bwp0aWFudGlib29rcy5vcmcKfHx0aWFudGlib29rcy5vcmcKdGlhbnlhbnRvbmcu +b3JnLmNuCi50aWFuemh1Lm9yZwoudGliZXQuYXQKdGliZXQuY2EKLnRpYmV0LmNv +bQp8fHRpYmV0LmNvbQp0aWJldC5mcgoudGliZXQubmV0Cnx8dGliZXQubmV0Cnx8 +dGliZXQubnUKLnRpYmV0Lm9yZwp8fHRpYmV0Lm9yZwp8fHRpYmV0Lm9yZy50dwp8 +fHRpYmV0LnRvCi50aWJldC1lbnZveS5ldQp8fHRpYmV0LWVudm95LmV1Ci50aWJl +dC1mb3VuZGF0aW9uLm9yZwoudGliZXQtaG91c2UtdHJ1c3QuY28udWsKfHx0aWJl +dC1pbml0aWF0aXZlLmRlCi50aWJldC1tdW5pY2guZGUKLnRpYmV0M3JkcG9sZS5v +cmcKfGh0dHA6Ly90aWJldDNyZHBvbGUub3JnCnRpYmV0YWN0aW9uLm5ldAp8fHRp +YmV0YWN0aW9uLm5ldAoudGliZXRhaWQub3JnCnRpYmV0YWxrLmNvbQoudGliZXRh +bi5mcgp0aWJldGFuLWFsbGlhbmNlLm9yZwoudGliZXRhbmFydHMub3JnCi50aWJl +dGFuYnVkZGhpc3RpbnN0aXR1dGUub3JnCnx8dGliZXRhbmJ1ZGRoaXN0aW5zdGl0 +dXRlLm9yZwp8fHRpYmV0YW5jb21tdW5pdHkub3JnCnx8dGliZXRhbmVudHJlcHJl +bmV1cnMub3JnCnx8dGliZXRhbmhlYWx0aC5vcmcKLnRpYmV0YW5qb3VybmFsLmNv +bQoudGliZXRhbmxhbmd1YWdlLm9yZwoudGliZXRhbmxpYmVyYXRpb24ub3JnCnx8 +dGliZXRhbmxpYmVyYXRpb24ub3JnCi50aWJldGNvbGxlY3Rpb24uY29tCi50aWJl +dGFuYWlkcHJvamVjdC5vcmcKLnRpYmV0YW5jb21tdW5pdHl1ay5uZXQKfGh0dHA6 +Ly90aWJldGFuY29tbXVuaXR5dWsubmV0CnRpYmV0YW5jdWx0dXJlLm9yZwp0aWJl +dGFuZmVtaW5pc3Rjb2xsZWN0aXZlLm9yZwoudGliZXRhbnBhaW50aW5ncy5jb20K +LnRpYmV0YW5waG90b3Byb2plY3QuY29tCi50aWJldGFucG9saXRpY2FscmV2aWV3 +Lm9yZwoudGliZXRhbnJldmlldy5uZXQKfGh0dHA6Ly90aWJldGFuc3BvcnRzLm9y +ZwoudGliZXRhbndvbWVuLm9yZwp8aHR0cDovL3RpYmV0YW53b21lbi5vcmcKLnRp +YmV0YW55b3V0aC5vcmcKLnRpYmV0YW55b3V0aGNvbmdyZXNzLm9yZwp8fHRpYmV0 +YW55b3V0aGNvbmdyZXNzLm9yZwoudGliZXRjaGFyaXR5LmRrCnRpYmV0Y2hhcml0 +eS5pbgoudGliZXRjaGlsZC5vcmcKLnRpYmV0Y2l0eS5jb20KfHx0aWJldGNvcnBz +Lm9yZwp8fHRpYmV0ZXhwcmVzcy5uZXQKfHx0aWJldGZvY3VzLmNvbQp8fHRpYmV0 +ZnVuZC5vcmcKLnRpYmV0Z2VybWFueS5jb20KfHx0aWJldGdlcm1hbnkuZGUKLnRp +YmV0aGF1cy5jb20KLnRpYmV0aGVyaXRhZ2VmdW5kLm9yZwp8fHRpYmV0aG91c2Uu +anAKfHx0aWJldGhvdXNlLm9yZwp8fHRpYmV0aG91c2UudXMKLnRpYmV0aW5mb25l +dC5uZXQKLnRpYmV0anVzdGljZS5vcmcKLnRpYmV0a29taXRlLmRrCnx8dGliZXRt +dXNldW0ub3JnCnx8dGliZXRuZXR3b3JrLm9yZwp8fHRpYmV0b2ZmaWNlLmNoCnRp +YmV0b2ZmaWNlLmV1Cnx8dGliZXRvZmZpY2Uub3JnCnx8dGliZXRvbmxpbmUuY29t +Cnx8dGliZXRvZmZpY2UuY29tLmF1Cnx8dGliZXRvbmxpbmUudHYKfHx0aWJldG9y +YWxoaXN0b3J5Lm9yZwp8fHRpYmV0cG9saWN5LmV1Cnx8dGliZXRyZWxpZWZmdW5k +LmNvLnVrCnx8dGliZXRzb2NpZXR5LmNvbQp8fHRpYmV0c3VuLmNvbQp8fHRpYmV0 +c3VwcG9ydGdyb3VwLm9yZwp8fHRpYmV0c3dpc3MuY2gKfHx0aWJldHRlbGVncmFw +aC5jb20KfHx0aWJldHRpbWVzLm5ldAp8fHRpYmV0dHJ1dGguY29tCnx8dGliZXR3 +cml0ZXMub3JnCi50aWNrZXQuY29tLnR3Ci50aWdlcnZwbi5jb20KfHx0aWdlcnZw +bi5jb20KLnRpbWRpci5jb20KfGh0dHA6Ly90aW1kaXIuY29tCi50aW1lLmNvbQp8 +aHR0cDovL3RpbWUuY29tCiEtLS50aW1lLmNvbS90aW1lL3RpbWUxMDAvbGVhZGVy +cy9wcm9maWxlL3JlYmVsCiEtLS50aW1lLmNvbS90aW1lL3NwZWNpYWxzL3BhY2th +Z2VzL2FydGljbGUvMCwyODgwNAohLS0udGltZS5jb20vdGltZS9tYWdhemluZQp8 +fHRpbWVzbm93bmV3cy5jb20KLnRpbXNhaC5jb20KfHx0aW10YWxlcy5jb20KfHxi +bG9nLnRpbmV5LmNvbQp8fHRpbmd0YWxrLm1lCi50aW55LmNjCnx8dGlueS5jYwp8 +fHRpbnljaGF0LmNvbQp8fHRpbnlwYXN0ZS5jb20KfHx0aXBhcy5uZXQKLnRpc3Rv +cnkuY29tCnx8dGtjcy1jb2xsaW5zLmNvbQoudG1hZ2F6aW5lLmNvbQp8fHRtYWdh +emluZS5jb20KfGh0dHA6Ly90bWkubWUKLnRtcHAub3JnCnxodHRwOi8vdG1wcC5v +cmcKLnRuYWZsaXguY29tCnx8dG5hZmxpeC5jb20KLnRucC5vcmcKfGh0dHA6Ly90 +bnAub3JnCi50by1wb3Juby5jb20KfHx0by1wb3Juby5jb20KfHx0b2dldHRlci5j +b20KLnRva3lvLTI0Ny5jb20KLnRva3lvLWhvdC5jb20KfHx0b2t5by1wb3JuLXR1 +YmUuY29tCnx8dG9reW9jbi5jb20KdHcudG9tb25ld3MubmV0Ci50b25naWwub3Iu +a3IKdG9ueXlhbi5uZXQKdG9vbmVsLm5ldAp0b3A4MS53cwoudG9wbmV3cy5pbgou +dG9wcG9ybnNpdGVzLmNvbQp8aHR0cDovL3RvcHBvcm5zaXRlcy5jb20KfHx0b3B0 +b29uLm5ldAoudG9yZ3VhcmQubmV0Cnx8dG9yZ3VhcmQubmV0Cnx8dG9wLnR2Ci50 +b3BzaGFyZXdhcmUuY29tCi50b3BzeS5jb20KfHx0b3BzeS5jb20KfHx0b3B0aXAu +Y2EKdG9yYS50bwoudG9yY24uY29tCnx8dG9ybG9jay5jb20KLnRvcnByb2plY3Qu +b3JnCnx8dG9ycHJvamVjdC5vcmcKfHx0b3JyZW50a2l0dHkudHYKdG9ycmVudHBy +aXZhY3kuY29tCnx8dG9ycmVudHByaXZhY3kuY29tCnxodHRwOi8vdG9ycmVudHBy +b2plY3Quc2UKfHx0b3JyZW50eS5vcmcKfHx0b3J0b2lzZXN2bi5uZXQKfHx0b3J2 +cG4uY29tCnx8dG90YWx2cG4uY29tCi50b3V0aWFvYWJjLmNvbQp0b3duZ2Fpbi5j +b20KdG95cGFyay5pbgp0b3l0cmFjdG9yc2hvdy5jb20KLnRwYXJlbnRzLm9yZwou +dHBpLm9yZy50dwp8fHRwaS5vcmcudHcKfHx0cmFkaW5ndmlldy5jb20KfHx0cmFu +c3BhcmVuY3kub3JnCnx8dHJlZW1hbGwuY29tLnR3CnRyZW5kc21hcC5jb20KfHx0 +cmVuZHNtYXAuY29tCi50cmltb25kaS5kZS9TRExFCi50cm91dy5ubAp8fHRyb3V3 +Lm5sCi50cnQubmV0LnRyCnx8dHJ0Lm5ldC50cgp0cnRjLmNvbS50dwoudHJ1ZWJ1 +ZGRoYS1tZC5vcmcKfHx0cnVlYnVkZGhhLW1kLm9yZwp0cnVseWVyZ29ub21pYy5j +b20KfHx0cnV0aHNvY2lhbC5jb20KLnRydXZlby5jb20KLnRzY3R2Lm5ldAoudHNl +bXR1bGt1LmNvbQp0c3F1YXJlLnR2Ci50c3Uub3JnLnR3CnRzdW5hZ2FydW1vbi5j +b20KIS0tfGh0dHA6Ly93d3cudHN1cnUtYmlyZC5uZXQvCnx8dHQxMDY5LmNvbQou +dHR0YW4uY29tCnx8dHR0YW4uY29tCnx8dHR2LmNvbS50dwp0dTg5NjQuY29tCi50 +dWJhaG9saWMuY29tCi50dWJlLmNvbQp0dWJlOC5jb20KfHx0dWJlOC5jb20KLnR1 +YmU5MTEuY29tCnx8dHViZTkxMS5jb20KLnR1YmVjdXAuY29tCi50dWJlZ2Fscy5j +b20KLnR1YmVpc2xhbS5jb20KfGh0dHA6Ly90dWJlaXNsYW0uY29tCi50dWJlc3Rh +Y2suY29tCnx8dHViZXdvbGYuY29tCi50dWliZWl0dS5uZXQKLnR1aWRhbmcub3Jn +Cnx8dHVpZGFuZy5vcmcKLnR1aWRhbmcuc2UKLnR1bXV0YW56aS5jb20KfGh0dHA6 +Ly90dW11dGFuemkuY29tCnx8dHVtdmlldy5jb20KLnR1bmVpbi5jb20KfGh0dHA6 +Ly90dW5laW4uY29tCnx8dHVubmVsYmVhci5jb20KfHx0dW5uZWxibGljay5uZXQK +LnR1bm5lbHIuY29tCnx8dHVubmVsci5jb20KfHx0dW5zYWZlLmNvbQp0dWl0d2l0 +LmNvbQoudHVyYW5zYW0ub3JnCi50dXJib2JpdC5uZXQKfHx0dXJib2JpdC5uZXQK +LnR1cmJvaGlkZS5jb20KfHx0dXJib2hpZGUuY29tCnx8dHVya2lzdGFudGltZXMu +Y29tCi50dXNoeWNhc2guY29tCnxodHRwOi8vdHVzaHljYXNoLmNvbQoudHV2cG4u +Y29tCnx8dHV2cG4uY29tCnxodHRwOi8vdHV6YWlqaWRpLmNvbQp8aHR0cDovLyou +dHV6YWlqaWRpLmNvbQoudHcwMS5vcmcKfGh0dHA6Ly90dzAxLm9yZwp8fHVzZS50 +eXBla2l0Lm5ldAoKIS0tLVR1bWJsci0tLQoudHVtYmxyLmNvbQp8fHR1bWJsci5j +b20KIS0tQEB8fGFzc2V0cy50dW1ibHIuY29tCiEtLUBAfHxkYXRhLnR1bWJsci5j +b20KIS0tQEB8fG1lZGlhLnR1bWJsci5jb20KIS0tQEB8fHN0YXRpYy50dW1ibHIu +Y29tCiEtLUBAfHx3d3cudHVtYmxyLmNvbQp8fGxlY2xvdWQubmV0Cnx8c2x1dG1v +b25iZWFtLmNvbQp8aHR0cDovL2Jsb2cuc295bGVudC5jb20KCi50di5jb20KfGh0 +dHA6Ly90di5jb20KdHZhbnRzLmNvbQp8fGZvcnVtLnR2Yi5jb20KfHxpbmV3cy1h +cGkudHZiLmNvbQpuZXdzLnR2YnMuY29tLnR3Ci50dmJveG5vdy5jb20KfHx0dmJv +eG5vdy5jb20KdHZpZGVyLmNvbQoudHZtb3N0LmNvbS5oawoudHZwbGF5dmlkZW9z +LmNvbQp8fHR2dW5ldHdvcmtzLmNvbQoudHctYmxvZy5jb20KfGh0dHBzOi8vdHct +YmxvZy5jb20KLnR3LW5wby5vcmcKLnR3YWl0dGVyLmNvbQp0d2FwcGVya2VlcGVy +LmNvbQp8fHR3YXBwZXJrZWVwZXIuY29tCnx8dHdhdWQuaW8KLnR3YXVkLmlvCi50 +d2F2aS5jb20KdHdiYnMub3JnCnx8dHdibG9nZ2VyLmNvbQp0d2VlcG1hZy5jb20K +LnR3ZWVwbWwub3JnCnx8dHdlZXBtbC5vcmcKLnR3ZWV0YmFja3VwLmNvbQp8fHR3 +ZWV0YmFja3VwLmNvbQp0d2VldGJvYXJkLmNvbQp8fHR3ZWV0Ym9hcmQuY29tCi50 +d2VldGNzLmNvbQp8aHR0cDovL3R3ZWV0Y3MuY29tCnxodHRwOi8vZGVjay5seQoh +LS0gT3BlcmF0aW9uIGRpc2NvbnRpbnVlZAohLS18fHR3ZWV0ZS5uZXQKIS0tbS50 +d2VldGUubmV0Cnx8dHdlZXRlZHRpbWVzLmNvbQohLS0gT3BlcmF0aW9uIGRpc2Nv +bnRpbnVlZAohLS10d2VldG1lbWUuY29tCnR3ZWV0cGhvdG8uY29tCnx8dHdlZXRw +aG90by5jb20KdHdlZXRyZWUuY29tCnx8dHdlZXRyZWUuY29tCi50d2VldHR1bm5l +bC5jb20KfHx0d2VldHR1bm5lbC5jb20KfHx0d2VldHdhbGx5LmNvbQp0d2VldHlt +YWlsLmNvbQp8fHR3ZWx2ZS50b2RheQoudHdlZXoubmV0CnxodHRwOi8vdHdlZXou +bmV0Cnx8dHdmdHAub3JnCnx8dHdncmVhdGRhaWx5LmNvbQp0d2liYXNlLmNvbQou +dHdpYmJsZS5kZQp8fHR3aWJibGUuZGUKdHdpYmJvbi5jb20KfHx0d2licy5jb20K +LnR3aWNvdW50cnkub3JnCnxodHRwOi8vdHdpY291bnRyeS5vcmcKdHdpY3N5LmNv +bQoudHdpZW5kcy5jb20KfGh0dHA6Ly90d2llbmRzLmNvbQoudHdpZmFuLmNvbQp8 +aHR0cDovL3R3aWZhbi5jb20KdHdpZmZvLmNvbQp8fHR3aWZmby5jb20KLnR3aWxp +Z2h0c2V4LmNvbQp0d2lsb2cub3JnCnR3aW1ib3cuY29tCnR3aXBwbGUuanAKfHx0 +d2lwcGxlLmpwCnx8dHdpcC5tZQp0d2lzaG9ydC5jb20KfHx0d2lzaG9ydC5jb20K +fHx0d2lzdGVyLm5ldC5jbwp0d2lzdGVybm93LmNvbQp0d2lzdG9yeS5uZXQKfHx0 +d2lnZ2l0Lm9yZwp0d2l0Z29vLmNvbQp0d2l0aXEuY29tCnx8dHdpdGlxLmNvbQou +dHdpdGxvbmdlci5jb20KfHx0d2l0bG9uZ2VyLmNvbQp8aHR0cDovL3RsLmdkLwp0 +d2l0bWFuaWEuY29tCnR3aXRvYXN0ZXIuY29tCnx8dHdpdG9hc3Rlci5jb20KfHx0 +d2l0b25tc24uY29tCiEtLVNhbWUgSVAKLnR3aXRzdGF0LmNvbQp8fHR3aXRzdGF0 +LmNvbQp8fHR3ZWVwZ3VpZGUuY29tCnxodHRwOi8vdHd0LnRsCnR3aXR0Ym90Lm5l +dAp8fGFkcy10d2l0dGVyLmNvbQp8fHR3dHRyLmNvbQp8fHR3aXR0ZXI0ai5vcmcK +LnR3aXR0ZXJjb3VudGVyLmNvbQp8fHR3aXR0ZXJjb3VudGVyLmNvbQp0d2l0dGVy +ZmVlZC5jb20KLnR3aXR0ZXJnYWRnZXQuY29tCnx8dHdpdHRlcmdhZGdldC5jb20K +LnR3aXR0ZXJrci5jb20KfHx0d2l0dGVya3IuY29tCnx8dHdpdHRlcm1haWwuY29t +Cnx8dHdpdHRlcnJpZmljLmNvbQp0d2l0dGVydGltLmVzCnx8dHdpdHRlcnRpbS5l +cwp0d2l0dGhhdC5jb20KfHx0d2l0dHVyay5jb20KLnR3aXR0dXJseS5jb20KfHx0 +d2l0dHVybHkuY29tCi50d2l0emFwLmNvbQp0d2l5aWEuY29tCi50d3Rrci5jb20K +fGh0dHA6Ly90d3Rrci5jb20KLnR3bm9ydGgub3JnLnR3Cnx8dHdyZXBvcnRlci5v +cmcKdHdza3lwZS5jb20KdHd0cmxhbmQuY29tCnR3dXJsLm5sCi50eHh4LmNvbQou +dHljb29sLmNvbQp8fHR5Y29vbC5jb20KCiEtLXR5cGVwYWQKfHx0eXBlcGFkLmNv +bQpAQHx8d3d3LnR5cGVwYWQuY29tCkBAfHxzdGF0aWMudHlwZXBhZC5jb20KfHxi +bG9nLmV4cG9mdXR1cmVzLmNvbQp8fGNvbnRlc3RzLnR3aWxpby5jb20KIS1sYXdw +cm9mZXNzb3JzLnR5cGVwYWQuY29tL2NoaW5hX2xhd19wcm9mCnx8dHlwb3JhLmlv +CgohLS0tLS0tLS0tLS0tLS0tLS0tLS1VVS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t +LS0KfHx1ZG9tYWluLmhrCnx8dXBiaXQuY29tCnx8ZGVtby51bmxvY2stbXVzaWMu +ZGV2Ci51OXVuLmNvbQp8fHU5dW4uY29tCi51YmRkbnMub3JnCnxodHRwOi8vdWJk +ZG5zLm9yZwp8fHViZXJwcm94eS5uZXQKLnVjLWphcGFuLm9yZwp8fHVjLWphcGFu +Lm9yZwouc3JjZi51Y2FtLm9yZy9zYWxvbi8KfGh0dHA6Ly9jaGluYS51Y2FuZXdz +LmNvbS8KfGh0dHA6Ly9odW0qLnVjaGljYWdvLmVkdS9mYWN1bHR5L3l3YW5nL2hp +c3RvcnkKfHx1ZGVyem8uaXQKLnVkbi5jb20KfHx1ZG4uY29tCnx8dWRuLmNvbS50 +dwp1ZG5ia2suY29tL2Jicwp8fHVmb3JhZGlvLmNvbS50dwp1ZnJlZXZwbi5jb20K +LnVnby5jb20KIS0tZ2hzCnx8dWhkd2FsbHBhcGVycy5vcmcKfHx1aHJwLm9yZwou +dWlnaHVyLm5sCnx8dWlnaHVyLm5sCnVpZ2h1cmJpei5uZXQKLnVsaWtlLm5ldAp1 +a2NkcC5jby51awp8fHVsdHJhc3VyZi51cwp8fHVsdHJhdnBuLmNvbQp8fHVsdHJh +dnBuLmZyCnVsdHJheHMuY29tCnVtaWNoLmVkdS9+ZmFsdW4KfHx1bmJsb2NrLmNu +LmNvbQoudW5ibG9ja2VyLnl0CnVuYmxvY2stdXMuY29tCnx8dW5ibG9jay11cy5j +b20KLnVuYmxvY2tkbW0uY29tCnxodHRwOi8vdW5ibG9ja2RtbS5jb20KfHx1bmJs +b2Nrc2l0LmVzCnVuY3ljbG9tZWRpYS5vcmcKLnVuY3ljbG9wZWRpYS5oay93aWtp +CnxodHRwOi8vdW5jeWNsb3BlZGlhLmhrCiEtLXVuY3ljbG9wZWRpYS5pbmZvCnxo +dHRwOi8vdW5jeWNsb3BlZGlhLnR3CnVuZGVyd29vZGFtbW8uY29tCnx8dW5kZXJ3 +b29kYW1tby5jb20KfHx1bmhvbHlrbmlnaHQuY29tCi51bmkuY2MKfHxjbGRyLnVu +aWNvZGUub3JnCi51bmlmaWNhdGlvbi5uZXQKLnVuaWZpY2F0aW9uLm9yZy50dwp8 +fHVuaXJ1bGUuY2xvdWQKLnVuaXgxMDAuY29tCnx8dW5rbm93bnNwYWNlLm9yZwou +dW5vZGVkb3MuY29tCnVucG8ub3JnCnx8dW5zdGFibGUuaWN1Cnx8dW53aXJlLmhr +Cnx8dW9jbi5vcmcKdG9yLnVwZGF0ZXN0YXIuY29tCnx8dXBnaHNiYy5jb20KLnVw +aG9sZGp1c3RpY2Uub3JnCnVwbG9hZGVkLm5ldC9maWxlCnxodHRwOi8vdXBsb2Fk +ZWQubmV0L2ZpbGUKfGh0dHA6Ly91cGxvYWRlZC50by9maWxlCi51cGxvYWRzdGF0 +aW9uLmNvbS9maWxlCi51cG1lZGlhLm1nCnx8dXBtZWRpYS5tZwoudXBvcm5pYS5j +b20KfGh0dHA6Ly91cG9ybmlhLmNvbQp8fHVwcm94eS5vcmcKfHx1cHRvZG93bi5j +b20KLnVwd2lsbC5vcmcKdXI3cy5jb20KfHx1cmJhbmRpY3Rpb25hcnkuY29tCnx8 +dXJiYW5zdXJ2aXZhbC5jb20KbXlzaGFyZS51cmwuY29tLnR3Lwp8fHVybGJvcmcu +Y29tCnx8dXJscGFyc2VyLmNvbQp1cy50bwp8fHVzYWNuLmNvbQoudXNhaXAuZXUK +fHx1c2FpcC5ldQp8fHVzY25wbS5vcmcKfHx1c2NhcmRmb3J1bS5jb20KfHx1c21h +LmVkdQoudXNvY2N0bi5jb20KfHx1c3RpYmV0Y29tbWl0dGVlLm9yZwoudXN0cmVh +bS50dgp8fHVzdHJlYW0udHYKdXN1cy5jYwoudXRvcGlhbnBhbC5jb20KfHx1dG9w +aWFucGFsLmNvbQp8fHV1amlhc3UuY29tCi51dnd4eXoueHl6Cnx8dXZ3eHl6Lnh5 +egoudXdhbnRzLmNvbQp8fHV3YW50cy5jb20KLnV3YW50cy5uZXQKdXlnaHVyLmNv +LnVrCnx8dXlnaHVyLWoub3JnCnx8dXlnaHVyYWEub3JnCnx8dXlnaHVyYW1lcmlj +YW4ub3JnCnx8dXlnaHVyYml6Lm9yZwp8fHV5Z2h1cmNvbmdyZXNzLm9yZwp8fHV5 +Z2h1cnBlbi5vcmcKfHx1eWdodXJzdHVkaWVzLm9yZwp8fHV5Z2h1cnRyaWJ1bmFs +LmNvbQp1eWd1ci5vcmcKfGh0dHA6Ly91eW1hYXJpcC5jb20vCgohLS0tLS0tLS0t +LS0tLS0tLS0tLS1WVi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KfHx2aWxhbmV0 +Lm1lCnx8dmV3YXMubmV0Cnx8djIuaGVscAp8fHZvY2Fyb28uY29tCnx8dmVybi5j +Ywp8fHYyZmx5Lm9yZwoudjJyYXkuY29tCnx8djJyYXkuY29tCnx8djJyYXljbi5j +b20KfHx2YWxldXJzYWN0dWVsbGVzLmNvbQoudmFuMDAxLmNvbQoudmFuNjk4LmNv +bQoudmFuZW11LmNuCi52YW5pbGxhLWpwLmNvbQoudmFucGVvcGxlLmNvbQp8fHZh +bnNreS5jb20KfHx2YXRpY2FubmV3cy52YQp8fHZjZi1vbmxpbmUub3JnCnx8dmNm +YnVpbGRlci5vcmcKLnZlZ2FzcmVkLmNvbQoudmVsa2FlcG9jaGEuc2sKLnZlbmJi +cy5jb20KLnZlbmNoaW5hLmNvbQoudmVuZXRpYW5tYWNhby5jb20KfHx2ZW5ldGlh +bm1hY2FvLmNvbQp2ZW9oLmNvbQp8fHZlcmNlbC5hcHAKbXlzaXRlLnZlcml6b24u +bmV0CnZlcm1vbnR0aWJldC5vcmcKfHx2ZXJ5YnMuY29tCi52ZnQuY29tLnR3Ci52 +aWJlci5jb20KfHx2aWJlci5jb20KLnZpY2EuaW5mbwoudmljdGltc29mY29tbXVu +aXNtLm9yZwp8fHZpY3RpbXNvZmNvbW11bmlzbS5vcmcKfHx2aWQubWUKfHx2aWRi +bGUuY29tCnZpZGVvYmFtLmNvbQp8fHZpZGVvYmFtLmNvbQoudmlkZW9kZXRlY3Rp +dmUuY29tCi52aWRlb21lZ2EudHYKfHx2aWRlb21lZ2EudHYKLnZpZGVvbW8uY29t +CnZpZGVvcGVkaWF3b3JsZC5jb20KLnZpZGVvcHJlc3MuY29tCi52aWRpbmZvLm9y +Zy92aWRlbwp2aWV0ZGFpa3luZ3V5ZW4uY29tCi52aWpheWF0ZW1wbGUub3JnCnx8 +dmlsYXZwbi5jb20KdmltZW8uY29tCnx8dmltZW8uY29tCnx8dmltcGVyYXRvci5v +cmcKfHx2aW5jbmQuY29tCnx8dmlubmlldi5jb20KfGh0dHA6Ly93d3cubGliLnZp +cmdpbmlhLmVkdS9hcmVhLXN0dWRpZXMvVGliZXQvdGliZXQuaHRtbAoudmlydHVh +bHJlYWxwb3JuLmNvbQp8fHZpcnR1YWxyZWFscG9ybi5jb20KdmlzaWJsZXR3ZWV0 +cy5jb20KfHx2aXUuY29tCi52aXZhaGVudGFpNHUubmV0CgohLS1hcGV4IG5vdCBi +bG9ja2VkLCBhZGRpbmcgdG8gcmVkdWNlIGNvbXBsZXhpdHkKfHx2aXZhbGRpLmNv +bQoKLnZpdmF0dWJlLmNvbQoudml2dGhvbWFzLmNvbQp8fHZpdnRob21hcy5jb20K +LnZqYXYuY29tCnx8dmphdi5jb20KLnZqbWVkaWEuY29tLmhrCi52bGxjcy5vcmcK +fGh0dHA6Ly92bGxjcy5vcmcKfHx2bWl4Y29yZS5jb20KfHx2bmV0LmxpbmsKLnZv +Y2F0aXYuY29tCnZvY24udHYKfHx2b2N1cy5jYwp8fHZvaWNldHRhbmsub3JnCi52 +b3Qub3JnCnx8dm90Lm9yZwoudm92bzIwMDAuY29tCnxodHRwOi8vdm92bzIwMDAu +Y29tCi52b3hlci5jb20KfHx2b3hlci5jb20KLnZveS5jb20KfHx2cG4uYWMKfHx2 +cG4ubmV0Ci52cG40YWxsLmNvbQp8fHZwbjRhbGwuY29tCi52cG5hY2NvdW50Lm9y +Zwp8aHR0cDovL3ZwbmFjY291bnQub3JnCi52cG5hY2NvdW50cy5jb20KfHx2cG5h +Y2NvdW50cy5jb20KLnZwbmNvbXBhcmlzb24ub3JnCi52cG5jdXAuY29tCnx8dnBu +Y3VwLmNvbQp2cG5ib29rLmNvbQoudnBuY291cG9ucy5jb20KfGh0dHA6Ly92cG5j +b3Vwb25zLmNvbQoudnBuZGFkYS5jb20KfHx2cG5kYWRhLmNvbQoudnBuZmFuLmNv +bQp2cG5maXJlLmNvbQoudnBuZm9yZ2FtZS5uZXQKfHx2cG5mb3JnYW1lLm5ldAp8 +fHZwbmdhdGUuanAKLnZwbmdhdGUubmV0Cnx8dnBuZ2F0ZS5uZXQKLnZwbmdyYXRp +cy5uZXQKdnBuaHEuY29tCnx8dnBuaHViLmNvbQoudnBubWFzdGVyLmNvbQp8fHZw +bm1hc3Rlci5jb20KLnZwbm1lbnRvci5jb20KfHx2cG5tZW50b3IuY29tCi52cG5p +bmphLm5ldAp8fHZwbmluamEubmV0Ci52cG5pbnRvdWNoLmNvbQp2cG5qYWNrLmNv +bQp8fHZwbmphY2suY29tCi52cG5waWNrLmNvbQp8fHZwbnBpY2suY29tCnx8dnBu +cG9wLmNvbQp8fHZwbnByb25ldC5jb20KfHx2cG5wcm94eW1hc3Rlci5jb20KLnZw +bnJlYWN0b3IuY29tCnx8dnBucmVhY3Rvci5jb20KfHx2cG5yZXZpZXd6LmNvbQou +dnBuc2VjdXJlLm1lCnx8dnBuc2VjdXJlLm1lCi52cG5zaGF6YW0uY29tCnx8dnBu +c2hhemFtLmNvbQoudnBuc2hpZWxkYXBwLmNvbQp8fHZwbnNoaWVsZGFwcC5jb20K +LnZwbnNwLmNvbQoudnBudHJhZmZpYy5jb20KLnZwbnR1bm5lbC5jb20KfHx2cG50 +dW5uZWwuY29tCi52cG51ay5pbmZvCnx8dnBudWsuaW5mbwp8fHZwbnVubGltaXRl +ZGFwcC5jb20KLnZwbnZpcC5jb20KfHx2cG52aXAuY29tCi52cG53b3JsZHdpZGUu +Y29tCi52cG9ybi5jb20KfHx2cG9ybi5jb20KLnZwc2VyLm5ldApAQHx8dnBzZXIu +bmV0CnZyYWllc2FnZXNzZS5uZXQKfHx2cmNoYXQuY29tCi52cm10ci5jb20KfHx2 +cnBvcm4uY29tCnx8dnR1bm5lbC5jb20KfHx2dWt1LmNjCgohLS0tLS0tLS0tLS0t +LS0tLS0tLS1XVy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KfHx3eHcubW9lCnx8 +d3h3LmNhdAp8fHdhbGxldGNvbm5lY3QuY29tCnxodHRwczovL3czcy5saW5rL2lw +ZnMKfHx3b3JrMmljdS5vcmcKfHx3aWtpbGVzcy5mdW5hbWkudGVjaApsaXN0cy53 +My5vcmcvYXJjaGl2ZXMvcHVibGljCnx8d2FmZmxlMTk5OS5jb20KLndhaGFzLmNv +bQp3YWlrZXVuZy5vcmcvcGhwX3dpbmQKfHx3YWluYW8ubWUKfHx3YWxsbWFtYS5j +b20KfHx3YWxscGFwZXJjYXNhLmNvbQoud2FsbHByb3h5LmNvbQpAQHx8d2FsbHBy +b3h5LmNvbS5jbgp8fHdhbGxzdHR2LmNvbQp8fHdhbHRlcm1hcnRpbi5jb20KfHx3 +YWx0ZXJtYXJ0aW4ub3JnCnx8d3d3Lndhbi1wcmVzcy5vcmcKfHx3YW5kZXJpbmdo +b3JzZS5uZXQKfHx3YW5nYWZ1Lm5ldAp8fHdhbmdqaW5iby5vcmcKLndhbmdqaW5i +by5vcmcKd2FuZ2xpeGlvbmcuY29tCi53YW5nby5vcmcKfHx3YW5nby5vcmcKd2Fu +Z3J1b3NodWkubmV0Cnx8d2FudC1kYWlseS5jb20Kd2FwZWRpYS5tb2JpL3poc2lt +cAp8fHdhcnJvb20ub3JnCnx8d2FzZWxwcm8uY29tCnx8d2F0Y2hpbmVzZS5jb20K +fHx3YXRjaG91dC50dwoud2F0dHBhZC5jb20KfHx3YXR0cGFkLmNvbQoud2F0Y2g4 +eC5jb20KfHx3YXRjaG15Z2YubmV0Cnx8d2F2LnR2Cnx8d2F5YmlnLmNvbQp8fHdk +LmJpYmxlCi53ZGY1LmNvbQp8fHdlYWx0aC5jb20udHcKLndlYXJlaGFpcnkuY29t +Ci53ZWFybi5jb20KfHx3ZWFybi5jb20KfGh0dHA6Ly9oa2NvYy53ZWF0aGVyLmNv +bS5oawp8fGh1ZGF0b3JpcS53ZWIuaWQKfHx3ZWIycHJvamVjdC5uZXQKd2ViYmFu +Zy5uZXQKLndlYmV2YWRlci5vcmcKLndlYmZyZWVyLmNvbQp3ZWJsYWd1LmNvbQou +d2ViamIub3JnCi53ZWJydXNoLm5ldAp3ZWJzLXR2Lm5ldAoud2Vic2l0ZXB1bHNl +LmNvbS9oZWxwL3Rlc3R0b29scy5jaGluYS10ZXN0CnxodHRwOi8vd3d3LndlYnNu +YXByLmNvbQoud2Vid2FycGVyLm5ldAp8aHR0cDovL3dlYndhcnBlci5uZXQKd2Vi +d29ya2VyZGFpbHkuY29tCnx8d2VjaGF0bGF3c3VpdC5jb20KfHx3ZWZpZ2h0Y2Vu +c29yc2hpcC5vcmcKLndlZm9uZy5jb20Kd2VpYm9sZWFrLmNvbQoud2VpaHVvLm9y +Zwp8fHdlaWppbmdzaGVuZy5vcmcKLndlaW1pbmcuaW5mbwp8fHdlaW1pbmcuaW5m +bwp3ZWlxdWFud2FuZy5vcmcKfGh0dHA6Ly93ZWlzdW8ud3MKLndlbG92ZWNvY2su +Y29tCnx8d2VsdC5kZQoud2VtaWdyYXRlLm9yZwp8aHR0cDovL3dlbWlncmF0ZS5v +cmcKd2VuZ2V3YW5nLmNvbQp8fHdlbmdld2FuZy5vcmcKLndlbnh1ZWNpdHkuY29t +Cnx8d2VueHVlY2l0eS5jb20KLndlbnl1bmNoYW8uY29tCnx8d2VueXVuY2hhby5j +b20KLndlc3RjYS5jb20KfHx3ZXN0Y2EuY29tCnx8d2VzdGVybndvbHZlcy5jb20K +Lndlc3RraXQubmV0Cnx8d2VzdHBvaW50LmVkdQoud2VzdGVybnNodWdkZW5zb2Np +ZXR5Lm9yZwp3ZXRwdXNzeWdhbWVzLmNvbQoud2V0cGxhY2UuY29tCnx8d2V6b25l +Lm5ldAoud2ZvcnVtLmNvbQp8fHdmb3J1bS5jb20vCi53aGF0YmxvY2tlZC5jb20K +fHx3aGF0YmxvY2tlZC5jb20KfHx3aGVlbG9ja3NsYXRpbi5jb20KLndoaXBwZWRh +c3MuY29tCiEtLXxodHRwOi8vd2hvLmlzLwoud2hvZXIubmV0Cnx8d2hvZXIubmV0 +Cndob3RhbGtpbmcuY29tCndoeWxvdmVyLmNvbQp8fHdoeXgub3JnCnx8d2lraWxl +YWtzLmNoCnx8d2lraWxlYWtzLmNvbQp8fHdpa2lsZWFrcy5kZQp8fHdpa2lsZWFr +cy5ldQp8fHdpa2lsZWFrcy5sdQoud2lraWxlYWtzLm9yZwp8fHdpa2lsZWFrcy5v +cmcKfHx3aWtpbGVha3MucGwKLndpa2lsZWFrcy1mb3J1bS5jb20KfHx3aWxzb25j +ZW50ZXIub3JnCi53aWxsaWFtaGlsbC5jb20KfHxjb2xsYXRlcmFsbXVyZGVyLmNv +bQp8fGNvbGxhdGVyYWxtdXJkZXIub3JnCndpa2lsaXZyZXMuaW5mby93aWtpLyVF +OSU5QiVCNiVFNSU4NSVBQiVFNSVBRSVBQSVFNyVBQiVBMAp8fHdpa2ltYXBpYS5v +cmcKLndpa2l3YW5kLmNvbQp8fHdpa2l3YW5kLmNvbQp8fGNhc2luby53aWxsaWFt +aGlsbC5jb20KfHxzcG9ydHMud2lsbGlhbWhpbGwuY29tCnx8dmVnYXMud2lsbGlh +bWhpbGwuY29tCnx8d2lsbHcubmV0Ci53aW5kc2NyaWJlLmNvbQp8fHdpbmRzY3Jp +YmUuY29tCnx8d2luZ3kuc2l0ZQoud2lubmluZzExLmNvbQp8fHdpb25ld3MuY29t +Cnx8d2lyZWRieXRlcy5jb20KfHx3aXJlZHBlbi5jb20KfHx3aXJlZ3VhcmQuY29t +CiEtLXx8d2lyZXNoYXJrLm9yZwoud2lzZG9tcHVicy5vcmcKLndpc2V2aWQuY29t +Cnx8d2lzZXZpZC5jb20KfHx3aGlzcGVyc3lzdGVtcy5vcmcKLndpdG5lc3NsZWV0 +ZWFjaGluZy5jb20KfHx3aXRvcGlhLm5ldAoud2piay5vcmcKfHx3amJrLm9yZwp8 +fHdtZmxhYnMub3JnCnx8d24uY29tCnx8d25hY2cuY29tCnx8d25hY2cub3JnCnx8 +d28udGMKfHx3b2VzZXIuY29tCnx8d29rYXIub3JnCnx8d29sZmF4LmNvbQp8fHdv +bWJvLmFpCnx8d29vbHlzcy5jb20KfHx3b29waWUuanAKfHx3b29waWUudHYKfHx3 +b3JrYXRydW5hLmNvbQp8fHdvcmtlcmVtcG93ZXJtZW50Lm9yZwoud29ybGRjYXQu +b3JnCndvcmxkam91cm5hbC5jb20KLndvcmxkdnBuLm5ldAp8fHdvcmxkdnBuLm5l +dAoKfHx2aWRlb3ByZXNzLmNvbQoud29yZHByZXNzLmNvbQp8aHR0cDovLyoud29y +ZHByZXNzLmNvbQp8fGNoZW5zaGFuMjAwNDIwMDUud29yZHByZXNzLmNvbQp8fGNo +aW5hdmlldy53b3JkcHJlc3MuY29tCnx8Y25iYm5ld3Mud29yZHByZXNzLmNvbQp8 +fGZyZWVkb21pbmZvbmV0d2ViLndvcmRwcmVzcy5jb20KfHxoa2E4OTY0LndvcmRw +cmVzcy5jb20KfHxoa2FuZXdzLndvcmRwcmVzcy5jb20KfHxocXNibmV0LndvcmRw +cmVzcy5jb20KfHxocXNib25saW5lLndvcmRwcmVzcy5jb20KfHxpbnZlc3RpZ2F0 +aW5nLndvcmRwcmVzcy5jb20KfHxqb2JuZXdlcmEud29yZHByZXNzLmNvbQp8fG1h +dHRoZXdkZ3JlZW4ud29yZHByZXNzLmNvbQp8fG1pbmdodWl5dy53b3JkcHJlc3Mu +Y29tCnx8d28zdHR0LndvcmRwcmVzcy5jb20KfHxzdWppYXR1bi53b3JkcHJlc3Mu +Y29tCnx8eGlqaWUud29yZHByZXNzLmNvbQp8fGlmcmVlY2hpbmEud29yZHByZXNz +LmNvbQp8fHdwLmNvbQoKIS18fHdvcm1zY3VscHRvci5jb20KLndvdy5jb20KfHx3 +b3dwb3JuLmNvbQp8fHdvd2dpcmxzLmNvbQoud293cmsuY29tCi53b3lhb2xpYW4u +b3JnCnxodHRwOi8vd295YW9saWFuLm9yZwoud3BvZm9ydW0uY29tCnx8d3BvZm9y +dW0uY29tCndyY2hpbmEub3JnCndyZXRjaC5jYwp8fHdyaXRlc29uaWMuY29tCi53 +c2ouY29tCnx8d3NqLmNvbQoud3NqLm5ldAp8fHdzai5uZXQKLnd0Ym4ub3JnCi53 +dGZwZW9wbGUuY29tCnd1ZXJrYWl4aS5jb20KfHx3dWZhZmFuZ3dlbi5jb20KfHx3 +dWZpLm9yZy50dwp3dWppZS5uZXQKd3VqaWVsaXVsYW4uY29tCnx8d3VqaWVsaXVs +YW4uY29tCnx8d3V3LnJlZAoud3dpdHYuY29tCnx8d3dpdHYuY29tCnd6eWJveS5p +bS9wb3N0LzE2MAoKIS0tLS0tLS0tLS0tLS0tLS0tLS0tWFgtLS0tLS0tLS0tLS0t +LS0tLS0tLS0tLS0tCnx8d3d3LnhpY29ucy5vcmcKfHx4LmFpCnx8eHQuY29tCnx8 +eHQucHViCnx8eC5jbwoueC1iZXJyeS5jb20KfHx4LWJlcnJ5LmNvbQp8fHgtYXJ0 +LmNvbQp8fHgtd2FsbC5vcmcKfHx4M2d1aWRlLmNvbQp4YW5nYS5jb20KfHx4YmFi +ZS5jb20KLnhib29rY24uY29tCnx8eGJvb2tjbi5jb20KfHx4Y2FmZS5pbgp8fHhj +aXR5LmpwCi54Y3JpdGljLmNvbQp8fHhlcm90aWNhLmNvbQpkZXN0aW55LnhmaWxl +cy50by91YmJ0aHJlYWRzCnx8eGZ4c3NyLm1lCi54Z215ZC5jb20KfHx4Z215ZC5j +b20KeGhhbXN0ZXIuY29tCnx8eGhhbXN0ZXIuY29tCi54aWFuYmEubmV0Ci54aWFu +amlhbi50dwp8aHR0cDovL3hpYW5qaWFuLnR3Ci54aWFvYmFpd3UuY29tCi54aWFv +Y2h1bmNuanAuY29tCi54aWFvaGV4aWUuY29tCnx8eGlhb2xhbi5tZQp8fHhpYW9t +YS5vcmcKfHx4aWFvaGV4aWUuY29tCnx8eGlheGlhb3FpYW5nLm5ldAp4aWV6aHVh +LmNvbQoueGlodWEuZXMKZm9ydW0ueGluYmFvLmRlL2ZvcnVtCi54aW5nLmNvbQp8 +aHR0cDovL3hpbmcuY29tCnx8eGluamlhbmdwb2xpY2VmaWxlcy5vcmcKLnhpbm1p +YW8uY29tLmhrCnx8eGlubWlhby5jb20uaGsKeGluc2hlbmcubmV0CnhpbnNoaWp1 +ZS5jb20KLnhpb25ncGlhbi5jb20KLnhpdXJlbi5vcmcKeGl6YW5nLXpoaXllLm9y +Zwp4anAuY2MKfHx4anAuY2MKfHx4anRyYXZlbGd1aWRlLmNvbQp8fHhtbC10cmFp +bmluZy1ndWlkZS5jb20KeG1vdmllcy5jb20KfHx4bnh4LmNvbQohLS18fHhueHgt +Y2RuLmNvbQp4cGRvLm5ldAp8fHhwdWQub3JnCi54cmVudGR2ZC5jb20KfHx4dHVi +ZS5jb20KfHx4dWNoYW8ub3JnCnh1Y2hhby5uZXQKfHx4dWNoYW8ubmV0Cnh2aWRl +by5jYwoueHZpZGVvcy5jb20KfHx4dmlkZW9zLmNvbQp8fHh2aWRlb3MtY2RuLmNv +bQp8fHh2aWRlb3MuZXMKfHx4dmJlbGluay5jb20KfHx4dmlubGluay5jb20KfHx4 +c2Rlbi5pbmZvCi54eGJieC5jb20KLnh4bG1vdmllcy5jb20KfHx4eHguY29tCi54 +eHgueHh4CnxodHRwOi8veHh4Lnh4eAoueHh4ZnVja21vbS5jb20KfHx4eHh4LmNv +bS5hdQoueHh4eW1vdmllcy5jb20KfGh0dHA6Ly94eHh5bW92aWVzLmNvbQp4eXMu +b3JnCnh5c2Jsb2dzLm9yZwoKIS0tLS0tLS0tLS0tLS0tLS0tLS0tWVktLS0tLS0t +LS0tLS0tLS0tLS0tLS0tLS0tCnx8eWFuZ3poaS5vcmcKfHxzdG9yYWdlLnlhbmRl +eC5uZXQKfHx5Mm1hdGUuY29tCnx8eWFkaS5zawp8fHlha2J1dHRlcmJsdWVzLmNv +bQp8fHlhbS5jb20KfHx5YW0ub3JnLnR3Cnx8eWFuZGUucmUKfHxkaXNrLnlhbmRl +eC5jb20KfHxkaXNrLnlhbmRleC5ydQoueWFuZ2hlbmdqdW4uY29tCi55YXNuaS5j +by51awp8fHlhc25pLmNvLnVrCnx8eWFzdWt1bmkub3IuanAKLnlheWFiYXkuY29t +L2ZvcnVtCnx8bmV3cy55Y29tYmluYXRvci5jb20KLnlkeS5jb20KLnllYWh0ZWVu +dHViZS5jb20KfHx5ZWFodGVlbnR1YmUuY29tCnx8eWVjbC5uZXQKfHx5ZWVsb3Uu +Y29tCnx8eWVleWkuY29tCnllZ2xlLm5ldAp8fHllZ2xlLm5ldAoueWVzLnh4eAp8 +fHllczEyMy5jb20udHcKfHx5ZXNhc2lhLmNvbQp8fHllc2FzaWEuY29tLmhrCi55 +ZXMtbmV3cy5jb20KfGh0dHA6Ly95ZXMtbmV3cy5jb20KLnllc3Bvcm5wbGVhc2Uu +Y29tCnx8eWVzcG9ybnBsZWFzZS5jb20KfGh0dHA6Ly95ZXllY2x1Yi5jb20KIS0t +eWZyb2cuY29tCnx8eWhjdy5uZXQKLnlpYmFkYS5jb20KfHx5aWJhb2NoaW5hLmNv +bQoueWlkaW8uY29tCnx8eWlkaW8uY29tCnx8eWlnZW5pLmNvbQp5aWx1YmJzLmNv +bQp8fHMueWltZy5jb20KLnlpcHViLmNvbQp8fHlpcHViLmNvbQp5aW5sZWkub3Jn +L210Ci55aXpoaWhvbmd4aW5nLmNvbQp8fHlpemhpaG9uZ3hpbmcuY29tCi55b2J0 +LmNvbQoueW9idC50dgp8fHlvYnQudHYKLnlvZ2ljaGVuLm9yZwp8fHlvZ2ljaGVu +Lm9yZwoueW9sYXNpdGUuY29tCi55b21pdXJpLmNvLmpwCnlvbmcuaHUKLnlvcmti +YnMuY2EKfHx5b3UuY29tCnx8eW91eHUuaW5mbwoueW91aml6ei5jb20KfHx5b3Vq +aXp6LmNvbQoueW91bWFrZXIuY29tCnx8eW91bWFrZXIuY29tCi55b3VuZ3Bvcm52 +aWRlb3MuY29tCnlvdW5nc3BpcmF0aW9uLmhrCi55b3VwYWkub3JnCnx8eW91cGFp +Lm9yZwoueW91ci1mcmVlZG9tLm5ldAp8fHlvdXJlcGVhdC5jb20KLnlvdXNlbmRp +dC5jb20KfHx5b3VzZW5kaXQuY29tCi55b3V0aG5ldHJhZGlvLm9yZy90bWl0L2Zv +cnVtCmJsb2cueW91dGh3YW50LmNvbS50dwptZS55b3V0aHdhbnQuY29tLnR3CnNo +YXJlLnlvdXRod2FudC5jb20udHcKdG9waWMueW91dGh3YW50LmNvbS50dwoueW91 +cG9ybi5jb20KfHx5b3Vwb3JuLmNvbQoueW91cG9ybmdheS5jb20KfHx5b3Vwb3Ju +Z2F5LmNvbQoueW91cmxpc3Rlbi5jb20KfHx5b3VybGlzdGVuLmNvbQoueW91cmx1 +c3QuY29tCnx8eW91cmx1c3QuY29tCnlvdXZlcnNpb24uY29tCnx8eW91dmVyc2lv +bi5jb20KeXRodC5uZXQKeXVhbm1pbmcubmV0Ci55dWFuemhlbmd0YW5nLm9yZwou +eXVsZ2h1bi5jb20KfHx5dWxnaHVuLmNvbQp8fHl1bmNoYW8ubmV0Cnx8eXVub21p +LnRva3lvCi55dXZ1dHUuY29tCnx8eXZlc2dlbGV5bi5jb20KLnl3cHcuY29tL2Zv +cnVtcy9oaXN0b3J5L3Bvc3QvQTAvcDAvaHRtbC8yMjcKeXg1MS5uZXQKLnl5aWku +b3JnCnx8eXlpaS5vcmcKfHx5eWpseW1iLnh5egp8fHl5c3ViLm5ldAoueXp6ay5j +b20KfHx5enprLmNvbQoKIS0tLS0tLS0tLS0tLS0tLS0tLS0tWlotLS0tLS0tLS0t +LS0tLS0tLS0tLS0tLS0tCnx8ei1saWJyYXJ5LnNrCnx8ei1saWIuZm0KfHx6LWxp +Yi5nZAp8fHotbGliLmdsCnx8ei1saWIuZm8KfHx6b2RnYW1lLnh5egp8fHpob25n +emlkaS5jb20KfHx6b29xbGUuY29tCnx8ei1saWIuaW8KfHx6LWxpYi5vcmcKemFj +ZWJvb2suY29tCi56YWxtb3MuY29tCnx8emFsbW9zLmNvbQp8fHphb2Jhby5jb20u +c2cKfHx6ZG5ldC5jb20udHcKLnplbGxvLmNvbQp8fHplbGxvLmNvbQouemVuZ2pp +bnlhbi5vcmcKLnplbm1hdGUuY29tCnx8emVubWF0ZS5jb20KfHx6ZW5tYXRlLmNv +bS5ydQp8fHplcm9oZWRnZS5jb20KfHx6ZXJvbmV0LmlvCiEtLXd3dy56ZnJlZXQu +Y29tL3Bvc3QvdXNlanVtcC1icm93bnMuaHRtbAouemZyZWV0LmNvbQouemhhbmdi +b2xpLm5ldAp8fHpoYW5ndGlhbmxpYW5nLmNvbQp8fHpoYW5sdmUub3JnCnpoZW5n +aHVpLm9yZwouemhlbmdqaWFuLm9yZwp8fHpoZW5namlhbi5vcmcKemhlbmd3dW5l +dC5vcmcKfGh0dHA6Ly96aGVueGlhbmcuYml6Cnpob25nZ3VvLmNhCnxodHRwOi8v +emhvbmdndW9yZW5xdWFuLm9yZwp6aG9uZ2d1b3Rlc2UubmV0Cnx8emhvbmdndW90 +ZXNlLm5ldAouemhvdXNodWd1YW5nLmNvbQouemh1YW54aW5nLmNuCnx8emh1YXRp +ZWJhLmNvbQp6aHVpY2hhZ3Vvamkub3JnCnx8emh1aWNoYWd1b2ppLm9yZwp8fHpp +Lm1lZGlhCnxodHRwOi8vYm9vay56aTUubWUKLnppZGR1LmNvbS9kb3dubG9hZAp8 +fHppbGxpb25rLmNvbQouemluaW8uY29tCnx8emluaW8uY29tCi56aXBvcm4uY29t +Ci56aXBweXNoYXJlLmNvbQpyZWFsZm9ydW0uemtpei5jb20KIS0tfHx6bGliLm5l +dAp8fHptZWRpYS5jb20udHcKfHx6bXcuY24KLnpvZGdhbWUudXMKem9tb2JvLm5l +dAouem9uYWV1cm9wYS5jb20KfHx6b25hZXVyb3BhLmNvbQp8fHpvbmdoZXhpbndl +bi5jb20KfHx6b29ndnBuLmNvbQp8fHpvb3Rvb2wuY29tCi56b296bGUubmV0Cnx8 +em9waGFyLm5ldAp3cml0ZXIuem9oby5jb20KfHx6b3Jyb3Zwbi5jb20KfHx6cG4u +aW0KfHx6c3BlZWRlci5tZQouenNyaGFvLmNvbQouenVvLmxhCnx8enVvLmxhCnx8 +enVvYmlhby5tZQouenVvbGEuY29tCnx8enVvbGEuY29tCnx8enZlcmVmZi5jb20K +fHx6eXhlbC5jb20KLnp6Y2FydG9vbi5jb20KISMjIyMjIyMjIyMjIyMjR2VuZXJh +bCBMaXN0IEVuZCMjIyMjIyMjIyMjIyMjIyMjCgohIyMjIyMjIyMjIyNTdXBwbGVt +ZW50YWwgTGlzdCBTdGFydCMjIyMjIyMjIyMjIyMKISMjIyMjIyMjIyMjIyNTdXBw +bGVtZW50YWwgTGlzdCBFbmQjIyMjIyMjIyMjIyMjCgohIyMjIyMjIyMjIyMjIyMj +I1doaXRlbGlzdCBTdGFydCMjIyMjIyMjIyMjIyMjIyMKQEB8fHd3dy5ldHRvZGF5 +Lm5ldAoKQEB8fGFsaXl1bi5jb20KQEB8fGJhaWR1LmNvbQpAQHx8Y2hpbmFzby5j +b20KQEB8fGNoaW5hei5jb20KQEB8aHR0cDovL25yY2guY3VsdHVyZS50dy8KQEB8 +fGkucGtpLmdvb2cKIS0tLVNvbWUgYXJlIHBvd2VyZWQgYnkgR3VYaWFuZyAoQkdQ +KSwgcGxlYXNlIGNvbW1lbnQgb2ZmIGlmCiEtLS15b3UgZW5jb3VudGVyIGNvbm5l +Y3Rpdml0eSBpc3N1ZXMuCkBAfHxhZHNlcnZpY2UuZ29vZ2xlLmNvbQohLS1JU1Ag +Y2FjaGUgd29ya3Mgc29tZXRpbWVzLCB2ZXJpZmllZCBhdCBkcnBlbmcgKyBnZWh1 +YS4KQEB8fGRsLmdvb2dsZS5jb20KIS0tQEB8fGtoLmdvb2dsZS5jb20KIS0tQEB8 +fGtobS5nb29nbGUuY29tCiEtLUBAfHxraG0wLmdvb2dsZS5jb20KIS0tQEB8fGto +bTEuZ29vZ2xlLmNvbQohLS1AQHx8a2htMi5nb29nbGUuY29tCiEtLUBAfHxraG0z +Lmdvb2dsZS5jb20KIS0tQEB8fGtobWRiLmdvb2dsZS5jb20KQEB8fHRvb2xzLmdv +b2dsZS5jb20KQEB8fGNsaWVudHNlcnZpY2VzLmdvb2dsZWFwaXMuY29tCkBAfHxm +b250cy5nb29nbGVhcGlzLmNvbQohLS1AQHx8a2htLmdvb2dsZWFwaXMuY29tCiEt +LUBAfHxraG0wLmdvb2dsZWFwaXMuY29tCiEtLUBAfHxraG0xLmdvb2dsZWFwaXMu +Y29tCiEtLUBAfHxraG0yLmdvb2dsZWFwaXMuY29tCiEtLUBAfHxraG0zLmdvb2ds +ZWFwaXMuY29tCiEtLUBAfHxraG1kYi5nb29nbGVhcGlzLmNvbQpAQHx8dXBkYXRl +Lmdvb2dsZWFwaXMuY29tCkBAfHxzYWZlYnJvd3NpbmcuZ29vZ2xlYXBpcy5jb20K +QEB8fGNvbm5lY3Rpdml0eWNoZWNrLmdzdGF0aWMuY29tCkBAfHxjc2kuZ3N0YXRp +Yy5jb20KQEB8fGZvbnRzLmdzdGF0aWMuY29tCkBAfHxzc2wuZ3N0YXRpYy5jb20K +QEB8fGhhb3NvdS5jb20KQEB8fGlwLmNuCkBAfHxqaWtlLmNvbQpAQHx8dHJhbnNs +YXRlLmdvb2dsZS5jbgpAQHxodHRwOi8vd3d3Lmdvb2dsZS5jbi9tYXBzCkBAfHxo +dHRwMi5nb2xhbmcub3JnCkBAfHxnb3YuY24KQEB8fG9jc3AucGtpLmdvb2cKQEB8 +fHFxLmNvbQpAQHx8c2luYS5jbgpAQHx8c2luYS5jb20uY24KQEB8fHNvZ291LmNv +bQpAQHx8c28uY29tCkBAfHxzb3NvLmNvbQpAQHx8dWx1YWkuY29tLmNuCkBAfHx3 +ZWliby5jb20KQEB8fHlhaG9vLmNuCkBAfHx5b3VkYW8uY29tCkBAfHx6aG9uZ3Nv +dS5jb20KQEB8aHR0cDovL2ltZS5iYWlkdS5qcAohIyMjIyMjIyMjIyMjIyMjI1do +aXRlbGlzdCBFbmQjIyMjIyMjIyMjIyMjIyMjIyMKIS0tLS0tLS0tLS0tLS0tLS0t +LS0tLUVPRi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCg== diff --git a/data/gfwlist.txt b/data/gfwlist.txt new file mode 100644 index 0000000..0023aa8 --- /dev/null +++ b/data/gfwlist.txt @@ -0,0 +1,7552 @@ +[AutoProxy 0.2.9] +! Checksum: AX5stTgpvx842DA6LdtKAw +! Expires: 6h +! Title: GFWList4LL +! GFWList with EVERYTHING included +! Last Modified: Sat, 13 Sep 2025 04:13:45 +0000 +! +! HomePage: https://github.com/gfwlist/gfwlist +! License: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt +! +! GFWList is unlikely to fully comprise the real +! rules being deployed inside GFW system. We try +! our best to keep the list up to date. Please +! contact us regarding URL submission / removal, +! or suggestion / enhancement at issue tracker: +! https://github.com/gfwlist/gfwlist/issues/. + +!---------403/451/503/520 & URL Redirects--------- +||blogjav.net +||zoominfo.com +||ptwxz.com +||miuipolska.pl +||piaotia.com +||wunderground.com +||500px.com +||500px.org +!--ehentai +|http://85.17.73.31/ +!--||adorama.com +||afreecatv.com +||agnesb.fr +||airitilibrary.com +||abematv.akamaized.net +||linear-abematv.akamaized.net +||vod-abematv.akamaized.net +||akiba-web.com +||altrec.com +||amazonvideo.com +||angela-merkel.de +||angola.org +||anthropic.com +||apartmentratings.com +||apartments.com +||arena.taipei +||assets.bwbx.io +||assimp.org +||athenaeizou.com +||bankmobilevibe.com +||banorte.com +||beeg.com +||global.bing.com +||booktopia.com.au +||boysmaster.com +||bynet.co.il +||byrut.org +||carfax.com +.casinobellini.com +||casinobellini.com +||centauro.com.br +||chobit.cc +||ciciai.com +||cici.com +||claude.ai +||clearsurance.com +||cnbeta.com.tw +||counter.social +||costco.com +||coze.com +||crossfire.co.kr +||crunchyroll.com +||d2pass.com +||darpa.mil +||dawangidc.com +||deezer.com +||desipro.de +||discord.com +||discord.gg +||discordapp.com +||discordapp.net +||dish.com +|http://img.dlsite.jp/ +||dm530.net +||dmhy.org +||dmm.co.jp +|http://www.dmm.com/netgame +||dnvod.tv +||dubox.com +||dvdpac.com +||eesti.ee +||esurance.com +.expekt.com +||expekt.com +.extmatrix.com +||extmatrix.com +||fakku.net +||fastpic.ru +||filesor.com +||financetwitter.com +||flipboard.com +||flitto.com +||fnac.be +||fnac.com +||funkyimg.com +||fxnetworks.com +||g-area.org +||gettyimages.* +@@||gettyimages.com +@@||gettyimages.cn +||getuploader.com +||ghidra-sre.org +!--|https://github.com/programthink/zhao +!--|https://raw.githubusercontent.com/programthink/zhao +||glass8.eu +||glype.com +||go141.com +||hautelook.com +||hautelookcdn.com +||wego.here.com +||grok.com +||hmoegirl.com +||hmvdigital.ca +||hmvdigital.com +||homedepot.com +||hoovers.com +||hulu.com +||huluim.com +|http://secure.hustler.com +|http://hustlercash.com +|http://www.hustlercash.com +||hybrid-analysis.com +||cdn*.i-scmp.com +||ilbe.com +||ilovelongtoes.com +|http://imgmega.com/*.gif.html +|http://imgmega.com/*.jpg.html +|http://imgmega.com/*.jpeg.html +|http://imgmega.com/*.png.html +||imlive.co +||javhub.net +||javhuge.com +.javlibrary.com +||javlibrary.com +||jcpenney.com +||jims.net +||tv.jtbc.joins.com +||jukujo-club.com +||juliepost.com +||kawaiikawaii.jp +||kendatire.com +||khatrimaza.org +||kkbox.com +||leisurepro.com +||lifemiles.com +||lih.kg +||longtoes.com +||lovetvshow.com +||lpsg.com +||lrfz.com +|http://www.m-sport.co.uk +||macgamestore.com +||madonna-av.com +||mandiant.com +||mangafox.com +||mangafox.me +||manta.com +||matome-plus.com +||matome-plus.net +||mattwilcox.net +||metarthunter.com +||mfxmedia.com +||miraheze.org +||mojim.com +||kb.monitorware.com +||monster.com +||moodyz.com +||moonbingo.com +||mos.ru +||addons.mozilla.org/*-*/firefox/addon/ublock-origin/* +||addons.mozilla.org/firefox/downloads/file/*/ublock_origin-*.xpi +||msha.gov +||www.msn.com +||muzu.tv +||mvg.jp +.mybet.com +||mybet.com +||mypikpak.com +||nationwide.com +|http://www.nbc.com/live +||neo-miracle.com +||netflix.com +||netflix.net +||nflximg.com +||nflximg.net +||nflxext.com +||nflxso.net +||nflxvideo.net +||nic.gov +|http://mo.nightlife141.com +||purpose.nike.com +||noxinfluencer.com +@@||cn.noxinfluencer.com +||nordstrom.com +||nordstromimage.com +||nordstromrack.com +||nottinghampost.com +||npsboost.com +||ntdtv.cz +||nusatrip.com +||nuuvem.com +||bbs.nyinfor.com +||olehdtv.com +||omni7.jp +||onapp.com +!--We are confused as well +||ontrac.com +@@|http://blog.ontrac.com +||openai.com +||pandora.com +.pandora.tv +||parkansky.com +||phmsociety.org +|http://*.pimg.tw/ +||podcast.co +||popai.pro +||primevideo.com +||proyectoclubes.com +||pure18.com +||pytorch.org +||qq.co.za +||r18.com +|http://radiko.jp +||ramcity.com.au +||rateyourmusic.com +||rd.com +|https://riseup.net +||sadistic-v.com +||isc.sans.edu +|http://cdn*.search.xxx/ +||shiksha.com +||slacker.com +||sm-miracle.com +||soylentnews.org +||spotify.com +||spreadshirt.es +||springboardplatform.com +||sprite.org +@@|http://store.sprite.org +||superpages.com +||swagbucks.com +||switch1.jp +||tapanwap.com +||gsp.target.com +||login.target.com +!--@@||intl.target.com +||rcam.target.com +||technews.tw +||terabox.com +||thinkgeek.com +||thebodyshop-usa.com +||tma.co.jp +||tracfone.com +||tryheart.jp +||turntable.fm +||twerkingbutt.com +||ulop.net +||uukanshu.com +||vegasred.com +||vevo.com +||vip-enterprise.com +|http://viu.tv/ch/ +|http://viu.tv/encore/ +||vmpsoft.com +||wanz-factory.com +||ssl.webpack.de +||weebly.com +||wheretowatch.com +||wingamestore.com +||wizcrafts.net +||wowhead.com +||vod.wwe.com +||xfinity.com +||xiaomi.eu +||youwin.com +||ytn.co.kr +||zamimg.com +||zattoo.com +||zim.vn +||zozotown.com + +!##############General List Start############### +!-------------------Coin Pool------------------- +||c3pool.com +||unmineable.com +||666pool.cn +||antpool.com +||crazypool.org +||cruxpool.com +||miningpoolhub.com +||huobipool.com +||poolbinance.com +||hiveon.net +||sparkpool.com +||flypool.org +||nanopool.org +||xnpool.com +||beepool.com +||zhizhu.top +||spiderpool.com +||uupool.cn +||flexpool.io +||beepool.org +||dpool.top +||okpool.me +||binancezh.cc +||btc.com +||r-pool.net +||w-pool.com + +!-------------------Pure IP--------------------- +14.102.250.18 +14.102.250.19 +50.7.31.230:8898 +174.142.105.153 +69.65.19.160 + +!----------------------IDN---------------------- +||xn--11xs86f.icu +||xn--4gq171p.com +||xn--czq75pvv1aj5c.org +||xn--i2ru8q2qg.com +||xn--noss43i.com +||xn--oiq.cc +||xn--p8j9a0d9c9a.xn--q9jyb4c +||xn--9pr62r24a.com +@@/^https?:\/\/(?=.*?(2x3|ni5|j5o))[a-z0-9.-]+\.xn--ngstr-lra8j\.com$ +||xn--ngstr-lra8j.com + +!-----------------DNS Poisoning----------------- +!---Amazon--- +!-||cdn-images.mailchimp.com +||abebooks.com +|https://*.s3.amazonaws.com + +||9cache.com +||9gag.com +||agro.hk +||share.america.gov +||apkmirror.com +||arte.tv +||artstation.com +||bangdream.space +||behance.net +||bird.so +||bitterwinter.org +||bnn.co +||businessinsider.com +||bwgyhw.com +||castbox.fm +||clyp.it +||cmcn.org +||cmx.im +||dailyview.tw +||daum.net +||depositphotos.com +||disconnect.me +||documentingreality.com +||doubibackup.com +||encyclopedia.com +||fangeqiang.com +||fanqiangdang.com +||feedx.net +||flyzy2005.com +||foreignpolicy.com +||free-ss.site +||freehongkong.org +||blog.fuckgfw233.org +||g0v.social +||globalvoices.org +||glorystar.me +||goregrish.com +||hanime.tv +||hbo.com +||spaces.hightail.com +||hkgalden.com +||hkgolden.com +||hudson.org +||ipfs.io +||japantimes.co.jp +||jiji.com +||jintian.net +||jinx.com +||joinmastodon.org +||liangzhichuanmei.com +||lighti.me +||lightyearvpn.com +||lihkg.com +||line-scdn.net +||i.lithium.com +||cloud.mail.ru +||cdn-images.mailchimp.com +||mastodon.cloud +||mastodon.host +||mastodon.social +||mastodon.xyz +||matters.news +||me.me +||metart.com +||mohu.club +||msa-it.org +||goo.ne.jp +||nikkei.com +||nitter.cc +||nitter.net +||niu.moe +||now.com +||openvpn.org +||onejav.com +||paste.ee +||my.pcloud.com +||picacomic.com +||pincong.rocks +||pixiv.net +||pixiv.org +||pixivsketch.net +||potato.im +||premproxy.com +||prism-break.org +||proton.me +||protonvpn.com +||api.pureapk.com +||quora.com +||quoracdn.net +||qz.com +||cdn.seatguru.com +||redd.it +||redditspace.com +||reddit.com +||reddithelp.com +.redditlist.com +|http://redditlist.com +||redditmedia.com +||redditstatic.com +!--defunct +||rixcloud.com +||rixcloud.us +||rsdlmonitor.com +||shadowsocks.be +||tn1.shemalez.com +||tn2.shemalez.com +||tn3.shemalez.com +||static.shemalez.com +||six-degrees.io +||softfamous.com +||sosreader.com +||sspanel.net +||supchina.com +||teddysun.com +||textnow.me +||tineye.com +||top10vpn.com +||tubepornclassic.com +||uku.im +||unseen.is +||cn.uptodown.com +||uraban.me +||vrsmash.com +||vultryhw.com +||scache.vzw.com +||scache1.vzw.com +||scache2.vzw.com +||ss7.vzw.com +||ssr.tools +||steemit.com +||taiwanjustice.net +||tinc-vpn.org +||u15.info +||washingtonpost.com +||wenzhao.ca +||whatsonweibo.com +||wire.com +||xm.com +||xuehua.us +||yes-news.com +||yigeni.com +||you-get.org +||zzcloud.me + +!---Digital Currency Exchange(CRYPTO)--- +||aex.com +||allcoin.com +||adcex.com +||bcex.ca +||bibox.com +||big.one +||bigone.com +||binance.com +||bit-z.com +||bitz.ai +||bitbay.net +||bitcoinworld.com +||bitfinex.com +||bithumb.com +||bitmex.com +||bnbstatic.com +||btc98.com +||btcbank.bank +||btctrade.im +||bybit.com +||c2cx.com +||chaoex.com +||cobinhood.com +||coinbase.com +||coinbene.com +||coinex.com +!--|https://www.coinexchange.io/ +||coingecko.com +||coingi.com +||coinmarketcap.com +||coinrail.co.kr +||cointiger.com +||cointobe.com +||coinut.com +||discoins.com +||dragonex.io +||ebtcbank.com +||etherdelta.com +||ethermine.org +||etherscan.io +||exmo.com +||exrates.me +||f2pool.com +||fatbtc.com +||ftx.com +||gate.io +||gatecoin.com +||hbg.com +||hitbtc.com +||hotcoin.com +||huobi.co +||huobi.com +||huobi.me +!--||huobi.li +||huobi.pro +||huobi.sc +||huobipro.com +||bx.in.th +||jex.com +||kex.com +||kraken.com +||kspcoin.com +||kucoin.com +||lbank.info +||liquiditytp.com +||livecoin.net +||localbitcoins.com +||mercatox.com +||oanda.com +||obyte.org +||oex.com +||okex.com +||okx.com +||opensea.io +||otcbtc.com +||paxful.com +||poolin.com +||simpleswap.io +||solv.finance +||topbtc.com +||tronscan.org +||xbtce.com +||yobit.net +||zb.com + +!----------------Frauds & Scams----------------- +!!---Content Farm(fake 500 error)--- +||read01.com +||kknews.cc + +china-mmm.jp.net +.lsxszzg.com +.china-mmm.net +||china-mmm.net + +!---------------------Groups-------------------- +!!---Masterdon--- +||bgme.me +||o3o.ca +||go5.dev +||me.ns.ci +||moresci.sale +||social.edu.ci +||mstdn.social +||douchi.space +||slashine.onl +||social.datalabour.com +||mastodon.online + +!!---Afraid FreeDNS--- +.allowed.org +.now.im + +!!---Amazon--- +||payments-jp.amazon.com +||amazon.co.jp +||s3-ap-*.amazonaws.com +||s3.eu-central-1.amazonaws.com +||s3-eu-central-1.amazonaws.com +||s3.us-east-1.amazonaws.com +||s3-ap-northeast-2.amazonaws.com +||s3.ap-northeast-2.amazonaws.com +||s3-ap-northeast-1.amazonaws.com +||s3-ap-southeast-1.amazonaws.com +||s3-ap-southeast-2.amazonaws.com + +!!---AOL--- +video.aol.ca/video-detail +video.aol.co.uk/video-detail +video.aol.com +||video.aol.com +||search.aol.com +www.aolnews.com + +!!---AvMoo--- +.avmo.pw +!--|http://avmo.pw +.avmoo.com +|http://avmoo.com +.avmoo.net +|http://avmoo.net +||avmoo.pw +.javmoo.xyz +|http://javmoo.xyz +.javtag.com +|http://javtag.com +.javzoo.com +|http://javzoo.com +.tellme.pw + +!!---BBC--- +!--.bbc.co.uk/blogs +!--.bbc.co.uk/chinese +!--.bbc.co.uk/news/world-asia-china +!--.bbc.co.uk/tv +!--.bbc.co.uk/zhongwen +!--.bbc.com/ukchina +!--.bbc.com/zhongwen +!--.bbc.com%2Fzhongwen +!--news.bbc.co.uk/onthisday*newsid_2496000/2496277 +!--newsforums.bbc.co.uk +.bbc.com +||bbc.com +.bbc.co.uk +||bbc.co.uk +||bbci.co.uk +.bbcchinese.com +||bbcchinese.com +|http://bbc.in + +!!---Bloomberg--- +.bloomberg.cn +||bloomberg.cn +.bloomberg.com +||bloomberg.com +bloomberg.de +||bloomberg.de +||bloombergview.com +.businessweek.com + +!!---ChangeIP--- +.1dumb.com +.25u.com +.2waky.com +.3-a.net +.4dq.com +.4mydomain.com +.4pu.com +.acmetoy.com +.almostmy.com +.americanunfinished.com +.authorizeddns.net +.authorizeddns.org +.bigmoney.biz +.changeip.name +.changeip.net +.changeip.org +.cleansite.biz +.cleansite.info +.cleansite.us +.compress.to +.ddns.info +.ddns.me.uk +.ddns.mobi +.ddns.ms +.ddns.name +.ddns.us +.dns-dns.com +.dns-stuff.com +.dns04.com +.dns05.com +.dns1.us +.dns2.us +.dnset.com +.dnsrd.com +.dsmtp.com +.dumb1.com +.dynamic-dns.net +.dynamicdns.biz +.dynamicdns.co.uk +.dynamicdns.me.uk +.dynamicdns.org.uk +.dyndns.pro +.dynssl.com +.epac.to +.esmtp.biz +.ezua.com +.faqserv.com +.fartit.com +.freeddns.com +.freetcp.com +.freewww.info +.ftp1.biz +.ftpserver.biz +.gettrials.com +.got-game.org +.gr8domain.biz +.gr8name.biz +.https443.net +.https443.org +.ikwb.com +.instanthq.com +.iownyour.org +.isasecret.com +.itemdb.com +.itsaol.com +.jetos.com +.jkub.com +.jungleheart.com +.justdied.com +.lflink.com +.lflinkup.com +.lflinkup.net +.lflinkup.org +.longmusic.com +.mefound.com +.moneyhome.biz +.mrbasic.com +.mrbonus.com +.mrface.com +.mrslove.com +.my03.com +.mydad.info +.myddns.com +.myftp.info +.mylftv.com +.mymom.info +.mynetav.net +.mynetav.org +.mynumber.org +.mypicture.info +.mypop3.net +.mypop3.org +.mysecondarydns.com +.mywww.biz +.myz.info +.ns01.biz +.ns01.info +.ns01.us +.ns02.biz +.ns02.info +.ns02.us +.ns1.name +.ns2.name +.ns3.name +.ocry.com +.onedumb.com +.onmypc.biz +.onmypc.info +.onmypc.net +.onmypc.org +.organiccrap.com +.otzo.com +.ourhobby.com +.pcanywhere.net +.port25.biz +.proxydns.com +.qhigh.com +.qpoe.com +.rebatesrule.net +.sellclassics.com +.sendsmtp.com +.serveuser.com +.serveusers.com +.sexidude.com +.squirly.info +.ssl443.org +.toh.info +.toythieves.com +.trickip.net +.vizvaz.com +.wikaba.com +.www1.biz +.wwwhost.biz +@@|http://xx.wwwhost.biz +.x24hr.com +.xxuz.com +.xxxy.info +.ygto.com +.youdontcare.com +.yourtrap.com +.zyns.com +.zzux.com + +!!--Cloudflare-- +!--||pages.dev +||workers.dev +||one.one.one.one +||cloudflare-dns.com + +!!---DtDNS--- +!###https://www.dtdns.com/dtsite/faq +.3d-game.com +.4irc.com +.b0ne.com +.chatnook.com +.darktech.org +.deaftone.com +.effers.com +.etowns.net +.etowns.org +.flnet.org +.gotgeeks.com +.scieron.com +.slyip.com +.slyip.net +.suroot.com + +!!---DynDNS--- +!###https://help.dyn.com/list-of-dyn-dns-pro-remote-access-domain-names/ +.blogdns.org +.dyndns.org +.dyndns-ip.com +.dyndns-pics.com +.from-sd.com +.from-pr.com +.is-a-hunter.com + +!!---Dynu--- +.dynu.com +||dynu.com +.dynu.net +.freeddns.org + +!!---Facebook--- +||accountkit.com +||cdninstagram.com +||f8.com +.facebook.com +||facebook.com +!--/^https?:\/\/[^\/]+facebook\.com/ +@@||v6.facebook.com +||facebook.de +||facebook.design +||connect.facebook.net +||facebook.hu +||facebook.in +||facebook.nl +||facebook.se +||facebookmail.com +||fb.com +||fb.me +||fb.watch +||fbcdn.net +||fbsbx.com +||fbaddins.com +||fbworkmail.com +.instagram.com +||instagram.com +||m.me +||messenger.com +||meta.com +||oculus.com +||oculuscdn.com +||rocksdb.org +@@||ip6.static.sl-reverse.com +||parse.com +||thefacebook.com +||threads.net +||whatsapp.com +||whatsapp.net + +!!---Fandom--- +||auntology.fandom.com +||hongkong.fandom.com + +!!---FTChinese--- +.ftchinese.com +||ftchinese.com + +!!---Google--- +||gle +||google +||doc.new +||form.new +||forms.new +||sheet.new +||sheets.new +||spreadsheet.new +||site.new +||sites.new +||website.new +||slides.new +||deck.new +||presentation.new +||googleapis.com +!###https://www.google.com/supported_domains### +!...GFWList doesn't intend to support typosquatting... +||1e100.net +||466453.com +||abc.xyz +||admob.com +||adsense.com +||advertisercommunity.com +||agoogleaday.com +||ampproject.org +@@|https://www.ampproject.org +@@|https://cdn.ampproject.org +||android.com +@@||ci.android.com +||androidify.com +||androidtv.com +||api.ai +.appspot.com +||appspot.com +||autodraw.com +||blogblog.com +blogspot.com +/^https?:\/\/[^\/]+blogspot\.(.*)/ +.blogspot.hk +.blogspot.jp +.blogspot.tw +||business.page +!--||capitalg.com +||certificate-transparency.org +||chrome.com +||chromecast.com +||chromeexperiments.com +||chromestatus.com +||chromium.org +||cloudfunctions.net +||crbug.com +||creativelab5.com +||crrev.com +||data-vocabulary.org +||debug.com +||deepmind.com +||deja.com +||digisfera.com +||docker.com +||docs.new +||duck.com +||feedburner.com +||firebaseio.com +||g.co +||gcr.io +||get.app +||get.dev +||get.how +||get.page +||getmdl.io +||getoutline.org +||ggpht.com +||gmail.com +||gmodules.com +||godoc.org +||golang.org +||goo.gl +||goo.gle +.google.ae +.google.as +.google.am +.google.at +.google.az +.google.ba +.google.be +.google.bg +.google.ca +.google.cd +.google.ci +.google.co.id +.google.co.jp +.google.co.kr +.google.co.ma +.google.co.uk +.google.com +.google.de +||google.dev +.google.dj +.google.dk +.google.es +.google.fi +.google.fm +.google.fr +.google.gg +.google.gl +.google.gr +.google.ie +.google.is +.google.it +.google.jo +.google.kz +.google.lv +.google.mn +.google.ms +.google.nl +.google.nu +.google.no +.google.ro +.google.ru +.google.rw +.google.sc +.google.sh +.google.sk +.google.sm +.google.sn +.google.tk +.google.tm +.google.to +.google.tt +.google.vu +.google.ws +/^https?:\/\/([^\/]+\.)*google\.(ac|ad|ae|af|ai|al|am|as|at|az|ba|be|bf|bg|bi|bj|bs|bt|by|ca|cat|cd|cf|cg|ch|ci|cl|cm|co.ao|co.bw|co.ck|co.cr|co.id|co.il|co.in|co.jp|co.ke|co.kr|co.ls|co.ma|com|com.af|com.ag|com.ai|com.ar|com.au|com.bd|com.bh|com.bn|com.bo|com.br|com.bz|com.co|com.cu|com.cy|com.do|com.ec|com.eg|com.et|com.fj|com.gh|com.gi|com.gt|com.hk|com.jm|com.kh|com.kw|com.lb|com.ly|com.mm|com.mt|com.mx|com.my|com.na|com.nf|com.ng|com.ni|com.np|com.om|com.pa|com.pe|com.pg|com.ph|com.pk|com.pr|com.py|com.qa|com.sa|com.sb|com.sg|com.sl|com.sv|com.tj|com.tr|com.tw|com.ua|com.uy|com.vc|com.vn|co.mz|co.nz|co.th|co.tz|co.ug|co.uk|co.uz|co.ve|co.vi|co.za|co.zm|co.zw|cv|cz|de|dj|dk|dm|dz|ee|es|eu|fi|fm|fr|ga|ge|gg|gl|gm|gp|gr|gy|hk|hn|hr|ht|hu|ie|im|iq|is|it|it.ao|je|jo|kg|ki|kz|la|li|lk|lt|lu|lv|md|me|mg|mk|ml|mn|ms|mu|mv|mw|mx|ne|nl|no|nr|nu|org|pl|pn|ps|pt|ro|rs|ru|rw|sc|se|sh|si|sk|sm|sn|so|sr|st|td|tg|tk|tl|tm|tn|to|tt|us|vg|vn|vu|ws)\/.*/ +!--||google-analytics.com +!--||googleadservices.com +||googleapps.com +||googleartproject.com +||googleblog.com +||googlebot.com +!--||googlecapital.com +||googlechinawebmaster.com +||googlecode.com +||googlecommerce.com +||googledomains.com +||googlearth.com +||googleearth.com +||googledrive.com +||googlefiber.net +||googlegroups.com +||googlehosted.com +||googleideas.com +||googleinsidesearch.com +||googlemail.com +||googlemashups.com +||googlepagecreator.com +||googleplay.com +||googleplus.com +||googlescholar.com +||googlesource.com +!--||googlesyndication.com +!--||googletagmanager.com +!--||googletagservices.com +||googleusercontent.com +.googlevideo.com +||googlevideo.com +||googleweblight.com +||googlezip.net +||gstatic.com +!--||gv.com +||gvt1.com +@@||redirector.gvt1.com +||gvt3.com +||gwtproject.org +||html5rocks.com +||iam.soy +||igoogle.com +||itasoftware.com +||like.com +||madewithcode.com +||material.io +||on2.com +||panoramio.com +||picasaweb.com +||pki.goog +||plus.codes +||polymer-project.org +||questvisual.com +||admin.recaptcha.net +||api.recaptcha.net +||api-secure.recaptcha.net +||api-verify.recaptcha.net +||redhotlabs.com +||savethedate.foo +||schema.org +||shattered.io +|http://sipml5.org/ +||sheets.new +||slides.new +||snapseed.com +||synergyse.com +||teachparentstech.org +||tensorflow.org +||tfhub.dev +||thinkwithgoogle.com +||tiltbrush.com +||translate.goog +||ua5v.com +||urchin.com +||usercontent.goog +!--||www.google +||waveprotocol.org +||waymo.com +||web.dev +||webmproject.org +||webpkgcache.com +||webrtc.org +||whatbrowser.org +||whats.new +||widevine.com +||withgoogle.com +||withyoutube.com +||x.company +||xn--ngstr-lra8j.com +||youtu.be +.youtube.com +||youtube.com +||youtube-nocookie.com +||youtubeeducation.com +||youtubegaming.com +||youtubekids.com +||yt.be +||ytimg.com +||zynamics.com + +!!---KickASS--- +!--OFFICIAL URL list at: https://kastatus.com + +!!---Microsoft--- +!--@@||bing.com +||copilot.microsoft.com + +!!---NaughtyAmerica--- +||naughtyamerica.com + +!!---NYTimes--- +!--||d1f1eryiqyjs0r.cloudfront.net +!--||d3lar09xbwlsge.cloudfront.net +!--||d3q1qj9jzsu8nw.cloudfront.net +!--||dc8xl0ndzn2cb.cloudfront.net +!--||a1.nyt.com +!--||int.nyt.com +!--||s1.nyt.com +static01.nyt.com +!--||static01.nyt.com +!--||typeface.nyt.com +||nyt.com +nytchina.com +nytcn.me +||nytcn.me +||nytco.com +|http://nyti.ms/ +.nytimes.com +||nytimes.com +||nytimg.com +cn.nytstyle.com +||nytstyle.com + +!!---Steam--- +.steamcommunity.com +||steamcommunity.com +!--steamcommunity.com/profiles/76561198062771609 +!--steamcommunity.com/groups/LibetTibet +!--steamcommunity.com/groups/zhonggong +!--steamcommunity.com/id/CJT_Jackton +||store.steampowered.com +||api.steampowered.com +||steamstatic.com +!!---Telegram--- +!!!---Domain--- +||tx.me +||tg.dev +||telega.one +||cdn-telegram.org +||comments.app +||graph.org +||legra.ph +||quiz.directory +||t.me +||updates.tdesktop.com +||telegram.dog +||telegram.me +||telegram.org +||telegram.space +||telegramdownload.com +||telegra.ph +||telesco.pe +!!!---IP--- + +!!---Tiktok--- +||tiktok.com +||tiktokv.com +||tiktokv.us +||tiktokcdn-us.com +||tiktokcdn.com +||tiktokcdn-eu.com + +!!---Twitch--- +||jtvnw.net +||ttvnw.net +||twitch.tv +||twitchcdn.net + +!!---Twitter/X--- +||periscope.tv +.pscp.tv +||pscp.tv +.t.co +||t.co +.tweetdeck.com +||tweetdeck.com +||twimg.com +.twitpic.com +||twitpic.com +.twitter.com +||twitter.com +||twitter.jp +||vine.co +||x.com + +!!---Taiwan--- +||moj.gov.tw +||gov.taipei +.gov.tw +|https://aiss.anws.gov.tw +||archives.gov.tw +||tacc.cwb.gov.tw +||data.gov.tw +||exam.gov.tw +||ey.gov.tw +||fa.gov.tw +||fda.gov.tw +||hpa.gov.tw +||immigration.gov.tw +||itaiwan.gov.tw +||judicial.gov.tw +||li.taipei +||ly.gov.tw +||mjib.gov.tw +||moeaic.gov.tw +||mofa.gov.tw +||mol.gov.tw +||mvdis.gov.tw +||nat.gov.tw +||nhi.gov.tw +||npa.gov.tw +||nsc.gov.tw +||ntbk.gov.tw +||ntbna.gov.tw +||ntbt.gov.tw +||pcc.gov.tw +||stat.gov.tw +||taipei.gov.tw +||taiwanjobs.gov.tw +||thb.gov.tw +||tipo.gov.tw +||wda.gov.tw + +||teco-hk.org +||teco-mo.org + +@@||aftygh.gov.tw +@@||aide.gov.tw +@@||tpde.aide.gov.tw +@@||arte.gov.tw +@@||chukuang.gov.tw +@@||cwb.gov.tw +@@||cycab.gov.tw +@@||dbnsa.gov.tw +@@||df.gov.tw +@@||eastcoast-nsa.gov.tw +@@||erv-nsa.gov.tw +@@||grb.gov.tw +@@||gysd.nyc.gov.tw +@@||hchcc.gov.tw +@@||hsinchu-cc.gov.tw +@@||iner.gov.tw +@@||klsio.gov.tw +@@||kmseh.gov.tw +@@||lungtanhr.gov.tw +@@||maolin-nsa.gov.tw +@@||matsu-news.gov.tw +@@||matsu-nsa.gov.tw +@@||matsucc.gov.tw +@@||moe.gov.tw +@@||nankan.gov.tw +@@||ncree.gov.tw +@@||cromotc.nat.gov.tw +@@||tax.nat.gov.tw +@@||necoast-nsa.gov.tw +@@||ner.gov.tw +@@||nmmba.gov.tw +@@||nmp.gov.tw +@@||nmvttc.gov.tw +@@||northguan-nsa.gov.tw +||npm.gov.tw +@@||nstm.gov.tw +@@||ntdmh.gov.tw +@@||ntl.gov.tw +@@||ntsec.gov.tw +@@||ntuh.gov.tw +@@||nvri.gov.tw +@@||penghu-nsa.gov.tw +@@||post.gov.tw +@@||siraya-nsa.gov.tw +@@||stdtime.gov.tw +@@||sunmoonlake.gov.tw +@@||taitung-house.gov.tw +@@||taoyuan.gov.tw +@@||tphcc.gov.tw +@@||trimt-nsa.gov.tw +@@||vghtpe.gov.tw +@@||vghks.gov.tw +@@||vghtc.gov.tw +@@||wanfang.gov.tw +@@||yatsen.gov.tw +@@||yda.gov.tw + +!--@@||4pppc.gov.tw +!--@@||921.gov.tw +!--@@||dmtip.gov.tw +!--@@||etraining.gov.tw +!--@@||gsn-cert.nat.gov.tw +!--@@||nici.nat.gov.tw +!--@@||hcc.gov.tw +!--@@||hengchuen.gov.tw +!--@@||khcc.gov.tw +!--@@||khms.gov.tw +!--@@||kk.gov.tw +!--@@||klccab.gov.tw +!--@@||klra.gov.tw +!--@@||nmh.gov.tw +!--@@||nmtl.gov.tw +!--@@||pabp.gov.tw +!--@@||pet.gov.tw +!--@@||tchb.gov.tw +!--@@||tcsac.gov.tw +!--@@||tncsec.gov.tw +||kinmen.org.tw + +!!---USA--- +||americorps.gov +||dma.mil +||jpl.nasa.gov +||pds.nasa.gov +||pacom.mil +||soc.mil +||solarsystem.nasa.gov +iipdigital.usembassy.gov +||uscg.mil +||usfk.mil +|http://tarr.uspto.gov/ +||tsdr.uspto.gov + +!!---V2EX--- +||v2ex.com +!--.v2ex.com +!--Included in above rule: dns.v2ex.com +!--@@|http://v2ex.com +!--@@|http://cdn.v2ex.com +!--@@|http://cn.v2ex.com +!--@@|http://hk.v2ex.com +!--@@|http://i.v2ex.com +!--@@|http://lax.v2ex.com +!--@@|http://neue.v2ex.com +!--@@|http://pagespeed.v2ex.com +!--@@|http://static.v2ex.com +!--@@|http://workspace.v2ex.com +!--@@|http://www.v2ex.com + +!!---VOA--- +||voacambodia.com +.voachineseblog.com +||voachineseblog.com +.voacantonese.com +||voacantonese.com +voachinese.com +||voachinese.com +voagd.com +||voaindonesia.com +.voanews.com +||voanews.com +voatibetan.com +||voatibetan.com +.voatibetanenglish.com +||voatibetanenglish.com + +!!---Wikia--- +||zh.ecdm.wikia.com +||evchk.wikia.com +fq.wikia.com +zh.pttpedia.wikia.com/wiki/%E7%BF%92%E5%8C%85%E5%AD%90%E4%B9%8B%E4%BA%82 +cn.uncyclopedia.wikia.com +zh.uncyclopedia.wikia.com + +!-------------Wikipedia Related------------- +!!Emergency need only(IP/Port block usage)!! +!------0------ +||mediawiki.org +!------1------ +||wikidata.org +!------2------ +||wikimedia.org +!------3------ +||wikibooks.org +!------4------ +||wikiversity.org +!------5------ +||wikisource.org +!------6------ +||zh.wikiquote.org +!------7------ +||wikinews.org +!------8------ +||wikivoyage.org +!------9------ +||wiktionary.org +!----Main----- +||wikipedia.org +||wmfusercontent.org + +!!---Yahoo--- +||shopping.yahoo.co.jp +||auctions.yahoo.co.jp +||search.yahoo.co.jp +||yahoo.com.tw +||yahoo.com.hk +||yahoo.com + +!------------------Numerics--------------------- +||ipfs.4everland.io +||91dasai.com +||i.111666.best +||1lib.sk +||2047.one +||69shuba.cx +||2049bbs.xyz +||611study.com +||18comic.org +||000webhost.com +.030buy.com +.0rz.tw +|http://0rz.tw +1-apple.com.tw +||1-apple.com.tw +.1000giri.net +||1000giri.net +||10beasts.net +.10conditionsoflove.com +||10musume.com +123rf.com +.12bet.com +||12bet.com +.12vpn.com +.12vpn.net +||12vpn.com +||12vpn.net +||1337x.to +.138.com +141hongkong.com/forum +||141jj.com +.141tube.com +||1688.com.au +.173ng.com +||173ng.com +.177pic.info +.17t17p.com +||18board.com +18onlygirls.com +.18p2p.com +.18virginsex.com +zhao.1984.city +||zhao.1984.city +1984bbs.com +||1984bbs.com +!--||1984blog.com +.1991way.com +||1991way.com +.1eew.com +.1mobile.com +||1point3acres.com +||1pondo.tv +.2-hand.info +.2000fun.com/bbs +||2008xianzhang.info +||2021hkcharter.com +||2047.name +21andy.com/blog +21sextury.com +.228.net.tw +||233abc.com +||24hrs.ca +2lipstube.com +.2shared.com +30boxes.com +.315lz.com +||32red.com +||36rain.com +.3a5a.com +3arabtv.com +.3boys2girls.com +.3proxy.ru +.3ren.ca +.3tui.net +||404museum.com +||4bluestones.biz +.4chan.com +!--||4chan.org +.4everproxy.com +||4everproxy.com +||4rbtv.com +||4shared.com +taiwannation.50webs.com +||51.ca +||51jav.org +.51luoben.com +||51luoben.com +||5278.cc +.5299.tv +5i01.com +.5isotoi5.org +.5maodang.com +||611study.icu +||63i.com +.64museum.org +64tianwang.com +64wiki.com +.66.ca +666kb.com +||6do.news +||6do.world +.6park.com +||6park.com +||6parkbbs.com +||6parker.com +||6parknews.com +||7capture.com +.7cow.com +!--||7-zip.org +.8-d.com +|http://8-d.com +.85cc.us +|http://85cc.us +.881903.com/page/zh-tw/ +||881903.com +.888.com +.888poker.com +89.64.charter.constitutionalism.solutions +89-64.org +||89-64.org +||8964museum.com +.8news.com.tw +.8z1.net +||8z1.net +||91porn.com +||91porny.com +||91vps.club +.92ccav.com +.991.com +|http://991.com +.99btgc01.com +||99btgc01.com +.99cn.info +|http://99cn.info +||9bis.com +||9bis.net +||9news.com.au + +!--------------------AA------------------------- +||amuletmc.com +||abplive.com +||cdn.arstechnica.net +||aomedia.org +||aljazeera.com +||akinator.com +||annas-archive.org +||av01.tv +||acg.rip +||annas-archive.se +||a-normal-day.com +a5.com.ru +|http://aamacau.com +!--|http://cdn*.abc.com/ +.abc.com +.abc.net.au +||abc.net.au +.abchinese.com +||abebooks.co.uk +.ablwang.com +.aboluowang.com +||aboluowang.com +||about.me +.abs.edu +||acast.com +.accim.org +.aceros-de-hispania.com +.acevpn.com +||acevpn.com +.acg18.me +|http://acg18.me +||acgbox.org +||acgkj.com +||acgnx.se +.acmedia365.com +.acnw.com.au +actfortibet.org +actimes.com.au +activpn.com +||activpn.com +||aculo.us +||addictedtocoffee.de +||addyoutube.com +.adelaidebbs.com/bbs +.adpl.org.hk +|http://adpl.org.hk +.adult-sex-games.com +||adult-sex-games.com +adultfriendfinder.com +||advanscene.com +||advertfan.com +.ae.org +||aei.org +||aenhancers.com +||af.mil +.afantibbs.com +|http://afantibbs.com +||afr.com +||aiosearch.com +.aiph.net +||aiph.net +.airasia.com +||airconsole.com +|http://download.aircrack-ng.org +.airvpn.org +||airvpn.org +.aisex.com +||ait.org.tw +aiweiwei.com +.aiweiweiblog.com +||aiweiweiblog.com +||www.ajsands.com + +!!---Akamai--- +a248.e.akamai.net +||a248.e.akamai.net + +rfalive1.akacast.akamaistream.net +voa-11.akacast.akamaistream.net + +|https://fbcdn*.akamaihd.net/ +!--||fbexternal-a.akamaihd.net +!--||fbstatic-a.akamaihd.net +!--|https://igcdn*.akamaihd.net +rthklive2-lh.akamaihd.net + +.akademiye.org/ug +|http://akademiye.org/ug +||akiba-online.com +||akow.org +.al-islam.com +||alabout.com +.alanhou.com +|http://alanhou.com +.alarab.qa +||alasbarricadas.org +||alforattv.net +.alhayat.com +.alicejapan.co.jp +aliengu.com +||alive.bar +||alkasir.com +||all4mom.org +||allconnected.co +.alldrawnsex.com +||alldrawnsex.com +||allfinegirls.com +.allgirlmassage.com +allgirlsallowed.org +.allgravure.com +alliance.org.hk +.allinfa.com +||allinfa.com +.alljackpotscasino.com +||allmovie.com +.alphaporno.com +||alternate-tools.com +alternativeto.net/software +alvinalexander.com +alwaysdata.com +||alwaysdata.com +||alwaysdata.net +.alwaysvpn.com +||alwaysvpn.com +||am730.com.hk +ameblo.jp +||ameblo.jp +www1.american.edu/ted/ice/tibet +||americangreencard.com +||amiblockedornot.com +.amigobbs.net +.amitabhafoundation.us +|http://amitabhafoundation.us +.amnesty.org +||amnesty.org +||amnesty.org.hk +.amnesty.tw +.amnestyusa.org +||amnestyusa.org +.amtb-taipei.org +.andygod.com +|http://andygod.com +annatam.com/chinese +||anchor.fm +||anchorfree.com +!--GHS +||ancsconf.org +||andfaraway.net +||android-x86.org +||androidapksfree.com +angelfire.com/hi/hayashi +||angularjs.org +animecrazy.net +aniscartujo.com +||aniscartujo.com +||anobii.com +||anonfiles.com +.anonymitynetwork.com +.anonymizer.com +.anonymouse.org +||anonymouse.org +anontext.com +.anpopo.com +.answering-islam.org +|http://www.antd.org +||anthonycalzadilla.com +antichristendom.com +.antiwave.net +|http://antiwave.net +.anyporn.com +.anysex.com +|http://anysex.com +.ao3.org +||ao3.org +||aobo.com.au +.aofriend.com +|http://aofriend.com +.aojiao.org +||aomiwang.com +||apat1989.org +.apetube.com +||apiary.io +.apigee.com +||apigee.com +||apk.support +||apkcombo.com +.apkmonk.com/app +||apkmonk.com +||apkplz.com +||apkpure.com +||apkpure.net +||appadvice.com +!--||appannie.com +||appbrain.com +.appdownloader.net/Android +.appledaily.com +||appledaily.com +appledaily.com.tw +||appledaily.com.tw +.appshopper.com +|http://appshopper.com +||appsocks.net +||appsto.re +.aptoide.com +||aptoide.com +||archives.gov +.archive.fo +||archive.fo +||archive.vn +||archive.is +||archive.is +||archive.li +||archive.li +||archive.md +||archive.org +||archive.ph +||archive.today +||archiveofourown.com +||archiveofourown.org +.arctosia.com +||arctosia.com +||areca-backup.org +.arethusa.su +||arethusa.su +||arlingtoncemetery.mil +.art4tibet1998.org +artofpeacefoundation.org +artsy.net +||asacp.org +asdfg.jp/dabr +asg.to +.asia-gaming.com +.asiaharvest.org +||asiaharvest.org +||asianage.com +||asianews.it +||asiansexdiary.com +||asiaone.com +.asiatgp.com +||ask.com +||askstudent.com +.askynz.net +||askynz.net +||aspi.org.au +||aspistrategist.org.au +||assembla.com +||astrill.com +||atc.org.au +.atchinese.com +|http://atchinese.com +atgfw.org +.atlanta168.com +||atlanta168.com +.atnext.com +||atnext.com +||audacy.com +ice.audionow.com +.av.com +||av.movie +.av-e-body.com +avaaz.org +||avaaz.org +!--||avast.com +.avcool.com +.avdb.in +||avdb.in +.avdb.tv +||avdb.tv +.avfantasy.com +||avg.com +.avgle.com +||avgle.com +||avidemux.org +||avoision.com +.avyahoo.com +||axios.com +||axureformac.com +azerimix.com +||azirevpn.com +!--boxun.azurewebsites.net doesn't exist. +boxun*.azurewebsites.net +||boxun*.azurewebsites.net + +!--------------------BB------------------------- +||bt4gprx.com +||bt4g.org +||betterhash.net +||binance.org +||bitget.com +||blackmagicdesign.com +||bearteach.com +||btbtt.me +||btbtt.co +||btbit.net +||betaclouds.net +||blocktempo.com +||blockcast.it +||www.bing.com +||bangumi.moe +||b-ok.cc +forum.baby-kingdom.com +||babylonbee.com +babynet.com.hk +backchina.com +||backchina.com +.backpackers.com.tw/forum +backtotiananmen.com +||bad.news +.badiucao.com +||badiucao.com +.badjojo.com +badoo.com +|http://*2.bahamut.com.tw +||baidu.jp +.baijie.org +||baijie.org +||bailandaily.com +||baixing.me +||baizhi.org +.banana-vpn.com +||banana-vpn.com +||band.us +||bandcamp.com +.bandwagonhost.com +||bandwagonhost.com +.bangbrosnetwork.com +.bangchen.net +|http://bangchen.net +||bangkokpost.com +||bangyoulater.com +bannedbook.org +||bannedbook.org +.bannednews.org +.baramangaonline.com +|http://baramangaonline.com +.barenakedislam.com +||barnabu.co.uk +||barton.de +.bastillepost.com +||bastillepost.com +bayvoice.net +||bayvoice.net +||bbchat.tv +||bb-chat.tv +.bbg.gov +.bbkz.com/forum +.bbnradio.org +bbs-tw.com +.bbsdigest.com/thread +bbsland.com +.bbsmo.com +.bbsone.com +bbtoystore.com +.bcc.com.tw/board +.bcchinese.net +.bcmorning.com +bdsmvideos.net +.beaconevents.com +.bebo.com +||bebo.com +.beevpn.com +||beevpn.com +.behindkink.com +||beijing1989.com +||beijing2022.art +beijingspring.com +||beijingspring.com +.belamionline.com +.bell.wiki +|http://bell.wiki +bemywife.cc +beric.me +||berlinerbericht.de +.berlintwitterwall.com +||berlintwitterwall.com +.berm.co.nz +.bestgore.com +.bestpornstardb.com +||bestvpn.com +||bestvpnanalysis.com +||bestvpnforchina.net +||bestvpnserver.com +||bestvpnservice.com +||bestvpnusa.com +||bet365.com +.betfair.com +||betternet.co +.bettervpn.com +||bettervpn.com +.bettween.com +||bettween.com +||betvictor.com +.bewww.net +.beyondfirewall.com +||bfnn.org +||bfsh.hk +.bgvpn.com +||bgvpn.com +.bianlei.com +@@||bianlei.com +biantailajiao.com +||biblesforamerica.org +||vpl.bibliocommons.com +||biedian.me +bigfools.com +||bigjapanesesex.com +.bignews.org +||bignews.org +.bigsound.org +||bild.de +.biliworld.com +|http://biliworld.com +|http://billypan.com/wiki +.binux.me +ai.binwang.me/couplet +.bit.do +|http://bit.do +.bit.ly +|http://bit.ly +!--||bitbucket.org +||bitchute.com +||bitcointalk.org +.bitshare.com +||bitshare.com +bitsnoop.com +.bitvise.com +||bitvise.com +bizhat.com +||bl-doujinsouko.com +.bjnewlife.org +.bjs.org +bjzc.org +||bjzc.org +||blacked.com +.blacklogic.com +.blackvpn.com +||blackvpn.com +blewpass.com +.blinkx.com +||blinkx.com +blinw.com +.blip.tv +||blip.tv +||blockcast.it +.blockcn.com +||blockcn.com +||blockedbyhk.com +||blockless.com +||blog.de +.blog.jp +|http://blog.jp +@@||jpush.cn +.blogcatalog.com +||blogcatalog.com +||blogcity.me +.blogger.com +||blogger.com +blogimg.jp +.bloglines.com +||bloglines.com +||bloglovin.com +rconversation.blogs.com +.blogtd.org +|http://blogtd.org +||bloodshed.net +||bootstrapcdn.com +||bloomfortune.com +blueangellive.com +||blubrry.com +||bmdru.com +||bnext.com.tw +||bnrmetal.com +boardreader.com/thread +||boardreader.com +.bod.asia +||bod.asia +.bodog88.com +.bolehvpn.net +||bolehvpn.net +bonbonme.com +.bonfoundation.org +.bongacams.com +||boobstagram.com +||book.com.tw +||bookdepository.com +bookepub.com +||books.com.tw +||bookwalker.com.tw +||borgenmagazine.com +||botanwang.com +.bot.nu +.bowenpress.com +||bowenpress.com +||app.box.com +dl.box.net +||dl.box.net +.boxpn.com +||boxpn.com +boxun.com +||boxun.com +.boxun.tv +||boxun.tv +.boxunclub.com +boyangu.com +.boyfriendtv.com +.boysfood.com +||br.st +.brainyquote.com/quotes/authors/d/dalai_lama +||braumeister.org +||brave.com +.bravotube.net +||bravotube.net +.brazzers.com +||brazzers.com +||breached.to +.break.com +||break.com +breakgfw.com +||breakgfw.com +breaking911.com +.breakingtweets.com +||breakingtweets.com +||breakwall.net +briian.com/6511/freegate +||brill.com +brizzly.com +||brizzly.com +broadbook.com +.broadpressinc.com +||broadpressinc.com +bbs.brockbbs.com +||brookings.edu +brucewang.net +.brutaltgp.com +||brutaltgp.com +||bsky.app +||bsky.network +||bsky.social +||bt95.com +.btaia.com +.btbtav.com +||btdig.com +||btdigg.org +||btguard.com +.btku.me +||btku.me +||btku.org +.btspread.com +.btsynckeys.com +.budaedu.org +||budaedu.org +.buddhanet.com.tw/zfrop/tibet +||buffered.com +||bullguard.com +.bullog.org +||bullog.org +.bullogger.com +||bullogger.com +||bumingbai.net +||bunbunhk.com +.busayari.com +|http://busayari.com +||business-humanrights.org +.businessinsider.com/bing-could-be-censoring-search-results-2014 +.businessinsider.com/china-banks-preparing-for-debt-implosion-2014 +.businessinsider.com/hong-kong-activists-defy-police-tear-gas-as-protests-continue-overnight-2014 +.businessinsider.com/internet-outages-reported-in-north-korea-2014 +.businessinsider.com/iphone-6-is-approved-for-sale-in-china-2014 +.businessinsider.com/nfl-announcers-surface-tablets-2014 +.businessinsider.com/panama-papers +.businessinsider.com/umbrella-man-hong-kong-2014 +|http://www.businessinsider.com.au/* +.businesstoday.com.tw +||businesstoday.com.tw +.busu.org/news +|http://busu.org/news +busytrade.com +.buzzhand.com +.buzzhand.net +.buzzorange.com +||buzzorange.com +||buzzsprout.com +||bvpn.com +||bwh1.net +||bypasscensorship.org + +!--------------------CC------------------------- +||covenantswatch.org.tw +||cpu-monkey.com +||coffeemanga.to +||ctinews.com +||cachefly.com +||cachefly.net +||cutout.pro +||cixiaoya.club +||campaign-archive.com +||chinauncensored.tv +||catbox.moe +||crosswall.org +||clipconverter.cc +||zh-hans.cfsh99.com +||colacloud.net +||ci-en.jp +||c-span.org +.c-spanvideo.org +||c-spanvideo.org +||c-est-simple.com +.c100tibet.org +||cableav.tv +||cablegatesearch.net +.cachinese.com +.cacnw.com +|http://cacnw.com +.cactusvpn.com +||cactusvpn.com +.cafepress.com +.cahr.org.tw +.calameo.com/books +||calendarz.com +.calgarychinese.ca +.calgarychinese.com +.calgarychinese.net +.cam4.com +.cam4.jp +.cam4.sg +.camfrog.com +||camfrog.com +||campaignforuyghurs.org +||cams.com +.cams.org.sg +canadameet.com +.canalporno.com +|http://bbs.cantonese.asia/ +!--http://www.cantonese.asia/action-bbs.html +.canyu.org +||canyu.org +.caobian.info +||caobian.info +caochangqing.com +||caochangqing.com +.cap.org.hk +||cap.org.hk +||caoporn.us +.carabinasypistolas.com +cardinalkungfoundation.org +||posts.careerengine.us +carmotorshow.com +||carrd.co +.cartoonmovement.com +||cartoonmovement.com +.casadeltibetbcn.org +.casatibet.org.mx +|http://casatibet.org.mx +.cari.com.my +||cari.com.my +||caribbeancom.com +||carousell.com.hk +.casinoking.com +.casinoriva.com +||catch22.net +.catchgod.com +|http://catchgod.com +.catholic.org.hk +||catholic.org.hk +catholic.org.tw +||catholic.org.tw +.cathvoice.org.tw +||cato.org +||cattt.com +||caus.com +.cbc.ca +||cbc.ca +.cbsnews.com/video +.cbtc.org.hk +||southpark.cc.com +!-.ccc.de +!-||ccc.de +||cccat.cc +||cccat.co +||ccfd.org.tw +.cchere.com +||cchere.com +.ccim.org +.cclife.ca +cclife.org +||cclife.org +cclifefl.org +||cclifefl.org +.ccthere.com +||ccthere.com +||ccthere.net +.cctmweb.net +.cctongbao.com/article/2078732 +ccue.ca +ccue.com +.ccvoice.ca +.ccw.org.tw +.cgdepot.org +|http://cgdepot.org +||cdbook.org +.cdef.org +||cdef.org +||cdig.info +cdjp.org +||cdjp.org +!--.cdn-apple.com +!--||cdn-apple.com +.cdnews.com.tw +cdp1989.org +cdp1998.org +||cdp1998.org +cdp2006.org +||cdp2006.org +||cdpeu.org +||cdpuk.co.uk +||cdpweb.org +||cdpweb.org +||cdpwu.org +||cdw.com +||cecc.gov +||cellulo.info +||cenews.eu +||centerforhumanreprod.com +||centralnation.com +.centurys.net +|http://centurys.net +.cfhks.org.hk +.cfos.de +||cfr.org +.cftfc.com +.cgst.edu +.change.org +||change.org +.changp.com +||changp.com +||channelnewsasia.com +||chanworld.org +||chaos.social +||character.ai +||chatgpt.com +.chaturbate.com +||chaturbate.com +.chuang-yen.org +||checkgfw.com +||chengmingmag.com +||chenguangcheng.com +||chenpokong.com +||chenpokongvip.com +||cherrysave.com +||chhongbi.org +||china-week.com +||china101.com +||china18.org +||china21.com +||china21.org +||china5000.us +||chinaaffairs.org +||chinaaid.us +||chinaaid.org +||chinaaid.net +||chinachange.org +||chinachannel.hk +||chinademocrats.org +||chinadialogue.net +||chinadigitaltimes.net +||chinaelections.org +||chinafile.com +||chinafreepress.org +.chinagate.com +chinagfw.org +||chinagfw.org +.chinagonet.com +.chinahorizon.org +||chinahorizon.org +.chinahush.com +.chinainperspective.com +chinalaborwatch.org +chinalawtranslate.com +.chinapost.com.tw/taiwan/national/national-news +chinalawandpolicy.com +.chinamule.com +||chinamule.com +chinamz.org +.chinanewscenter.com +|https://chinanewscenter.com +.chinapress.com.my +||chinapress.com.my +.china-review.com.ua +|http://china-review.com.ua +.chinarightsia.org +chinasmile.net/forums +chinasocialdemocraticparty.com +||chinasocialdemocraticparty.com +chinasoul.org +||chinasoul.org +.chinasucks.net +||chinatopsex.com +.chinatown.com.au +chinaway.org +.chinaworker.info +||chinaworker.info +chinayouth.org.hk +chinese-leaders.org +||chinese-memorial.org +.chinesedaily.com +||chinesedailynews.com +.chinesedemocracy.com +||chinesedemocracy.com +||chinesegay.org +.chinesen.de +||chinesen.de +||chinesenews.net.au +.chinesepen.org +||chineseradioseattle.com +||chineseupress.com +.chingcheong.com +||chingcheong.com +.chinman.net +|http://chinman.net +chithu.org +||cnnews.chosun.com +.chrdnet.com +|http://chrdnet.com +.christianfreedom.org +||christianfreedom.org +christianstudy.com +||christianstudy.com +christusrex.org/www1/sdc +.chubold.com +chubun.com +||christiantimes.org.hk +.chrlawyers.hk +||chrlawyers.hk +.churchinhongkong.org/b5/index.php +|http://churchinhongkong.org/b5/index.php +.chushigangdrug.ch +.cienen.com +.cineastentreff.de +.cipfg.org +||cirosantilli.com +.citizencn.com +||citizencn.com +||citizenlab.ca +||citizenlab.org +.citizenlab.org +citizensradio.org +.city365.ca +|http://city365.ca +city9x.com +||citypopulation.de +.citytalk.tw/event +.civicparty.hk +||civicparty.hk +civilhrfront.org +||civilhrfront.org +.civiliangunner.com +.civilmedia.tw +||civilmedia.tw +||civitai.com +.ck101.com +||ck101.com +.clarionproject.org/news/islamic-state-isis-isil-propaganda +||classicalguitarblog.net +.clb.org.hk +clearharmony.net +clearwisdom.net +||clinica-tibet.ru +.clipfish.de +||app.cloudcone.com +||cloudflare-ipfs.com +||club1069.com +||clubhouseapi.com +||cmegroup.com +||cmi.org.tw +|http://www.cmoinc.org +cmp.hku.hk +||cmule.com +||cms.gov +|http://vpn.cmu.edu +|http://vpn.sv.cmu.edu +.cn6.eu +.cna.com.tw +||cna.com.tw +.cnabc.com +.cnd.org +||cnd.org +download.cnet.com +.cnex.org.cn +.cnineu.com +.cnn.com/video +.cnpolitics.org +||cnpolitics.org +.cn-proxy.com +|http://cn-proxy.com +.cnproxy.com +news.cnyes.com +||coat.co.jp +||cochina.org +||codeshare.io +||codeskulptor.org +||cofacts.tw +||conoha.jp +|http://tosh.comedycentral.com +comefromchina.com +||comefromchina.com +.comic-mega.me +commandarms.com +||commentshk.com +.communistcrimes.org +||communistcrimes.org +||communitychoicecu.com +||comparitech.com +||compileheart.com +||conoha.jp +.contactmagazine.net +.convio.net +||cool18.com +.coolaler.com +||coolaler.com +coolder.com +||coolder.com +||coolloud.org.tw +.coolncute.com +||coolstuffinc.com +corumcollege.com +.cos-moe.com +|http://cos-moe.com +.cosplayjav.pl +|http://cosplayjav.pl +.cotweet.com +||cotweet.com +.coursehero.com +||coursehero.com +cpj.org +||cpj.org +.cq99.us +|http://cq99.us +crackle.com +||crackle.com +.crazys.cc +.crazyshit.com +||crazyshit.com +||crchina.org +crd-net.org +creaders.net +||creaders.net +.creadersnet.com +||cristyli.com +||croxyproxy.com +.crocotube.com +|http://crocotube.com +.crossvpn.net +||crossvpn.net +||crucial.com +||blog.cryptographyengineering.com +csdparty.com +||csdparty.com +||csis.org +||csmonitor.com +||csuchen.de +||csw.org.uk +||ct.org.tw +.ctao.org +||ctitv.com.tw +||ctowc.org +||cts.com.tw +||ctwant.com +|http://library.usc.cuhk.edu.hk/ +|http://mjlsh.usc.cuhk.edu.hk/ +.cuhkacs.org/~benng +.cuiweiping.net +||cuiweiping.net +||culture.tw +.cumlouder.com +||cumlouder.com +||curvefish.com +||cusp.hk +.cutscenes.net +||cutscenes.net +.cw.com.tw +||cw.com.tw +|http://forum.cyberctm.com +cyberghostvpn.com +||cyberghostvpn.com +||cynscribe.com +||ifan.cz.cc +||mike.cz.cc +||nic.cz.cc + +!--------------------DD------------------------- +||deno.dev +||docs.deno.com +||doom9.org +||dweb.link +||docker.io +||disneyplus.com +||ddex.io +||d.cash +||doubiyunbackup.com +||cloud.dify.ai +.d-fukyu.com +|http://d-fukyu.com +.d100.net +||d100.net +.d2bay.com +|http://d2bay.com +.dabr.co.uk +||dabr.co.uk +dabr.eu +dabr.mobi +||dabr.mobi +||dabr.me +dadazim.com +||dadazim.com +.dadi360.com +.dafabet.com +dafagood.com +dafahao.com +.dafoh.org +.daftporn.com +.dagelijksestandaard.nl +.daidostup.ru +|http://daidostup.ru +||dailymail.co.uk +.dailymotion.com +||dailymotion.com +||dailysabah.com +.dajiyuan.com +||dajiyuan.de +dajiyuan.eu +dalailama.com +.dalailama.mn +|http://dalailama.mn +.dalailama.ru +||dalailama.ru +dalailama80.org +.dalailama-archives.org +.dalailamacenter.org +|http://dalailamacenter.org +dalailamafellows.org +.dalailamafilm.com +.dalailamafoundation.org +.dalailamahindi.com +.dalailamainaustralia.org +.dalailamajapanese.com +.dalailamaprotesters.info +.dalailamaquotes.org +.dalailamatrust.org +.dalailamavisit.org.nz +.dalailamaworld.com +||dalailamaworld.com +dalianmeng.org +||dalianmeng.org +.daliulian.org +||daliulian.org +.danke4china.net +||danke4china.net +daolan.net +||darrenliuwei.com +||dashlane.com +||daum.net +.david-kilgour.com +|http://david-kilgour.com +daxa.cn +||daxa.cn +.daylife.com/topic/dalai_lama +||db.tt +||dbgjd.com +||dcard.tw +dcmilitary.com +||ddc.com.tw +||deadhouse.org +||deadline.com +||deepai.org +||decodet.co + +!--Origin:cdn-i30$_ +!--Exception: Homepage access without rst +!--Keyword is $_ +.definebabe.com + +||delcamp.net +delicious.com/GFWbookmark +.democrats.org +||democrats.org +.demosisto.hk +||demosisto.hk +||desc.se +||dessci.com +.destroy-china.jp +||deutsche-welle.de +||deviantart.com +||deviantart.net +||devio.us +||devpn.com +||devv.ai +dfn.org +dharmakara.net +.dharamsalanet.com +.diaoyuislands.org +||diaoyuislands.org +.difangwenge.org +|http://digiland.tw/ +.diigo.com +||diigo.com +.dipity.com +||directcreative.com +!--||discogs.com +!--@@||cdn.discogs.com +.discuss.com.hk +||discuss.com.hk +.discuss4u.com +||disp.cc +.disqus.com +||disqus.com +.dit-inc.us +||dit-inc.us +||diyin.org +.dizhidizhi.com +||dizhuzhishang.com +djangosnippets.org +||dl-laby.jp +||dlive.tv +||dlsite.com +||dlyoutube.com +||dmc.nico +||dmcdn.net +.dnscrypt.org +||dnscrypt.org +||dns2go.com +||dnssec.net +doctorvoice.org + +!--DogFartNetwork +.dogfartnetwork.com/tour +gloryhole.com + +.dojin.com +||dolc.de +||dolf.org.hk +.domain.club.tw +.domaintoday.com.au +chinese.donga.com +dongtaiwang.com +||dongtaiwang.com +.dongtaiwang.net +||dongtaiwang.net +.dongyangjing.com +||danbooru.donmai.us +.dontfilter.us +||doosho.com +||doourbest.org +.dorjeshugden.com +.dotplane.com +||dotplane.com +||dotsub.com +.dotvpn.com +||dotvpn.com +.doub.io +||doub.io +||doublethinklab.org +||dougscripts.com +||doujincafe.com +|https://bartender.dowjones.com +dphk.org +dpp.org.tw +||dpp.org.tw +||dpr.info +||dragonsprings.org +!--||draw.io +.dreamamateurs.com +.drepung.org +||drgan.net +||dropbooks.tv +||dropbox.com +||dropboxapi.com +||dropboxusercontent.com +.drtuber.com +.dscn.info +|http://dscn.info +.dstk.dk +|http://dstk.dk +||dtiblog.com +||dtic.mil +.duckduckgo.com +||duckduckgo.com +.duckload.com/download +||duckmylife.com +.duga.jp +|http://duga.jp +.duihua.org +||duihua.org +||duihuahrjournal.org +duping.net +||duplicati.com +dupola.com +dupola.net +.dushi.ca +||duyaoss.com +||dvorak.org +.dw.com +||dw.com +||dw.de +.dw-world.com +||dw-world.com +.dw-world.de +|http://dw-world.de +www.dwheeler.com +dwnews.com +||dwnews.com +dwnews.net +||dwnews.net +xys.dxiong.com +||dynawebinc.com +||dysfz.cc +.dzze.com + +!--------------------EE------------------------- +||e621.net +||edx-cdn.org +||everipedia.org +||epochtimes.com.tw +||etherscan.com +||elconfidencial.com +||e-classical.com.tw +||e-gold.com +.e-gold.com +.e-hentai.org +||e-hentai.org +.e-hentaidb.com +|http://e-hentaidb.com +e-info.org.tw +.e-zone.com.hk/discuz +|http://e-zone.com.hk/discuz +.e123.hk +||e123.hk +.earlytibet.com +|http://earlytibet.com +.earthcam.com +.earthvpn.com +||earthvpn.com +||eastasiaforum.org +.easternlightning.org +.eastturkestan.com +|http://www.eastturkistan.net/ +.eastturkistan-gov.org +.eastturkistancc.org +.eastturkistangovernmentinexile.us +||eastturkistangovernmentinexile.us +.easyca.ca +.easypic.com +||fnc.ebc.net.tw +||news.ebc.net.tw +.ebony-beauty.com +ebookbrowse.com +ebookee.com +||ecfa.org.tw +||ecimg.tw +ecministry.net +.economist.com +bbs.ecstart.com +edgecastcdn.net +||edgecastcdn.net +/twimg\.edgesuite\.net\/\/?appledaily/ +edicypages.com +.edmontonchina.cn +.edmontonservice.com +edoors.com +.edubridge.com +||edubridge.com +.edupro.org +||eevpn.com +efcc.org.hk +.efukt.com +|http://efukt.com +||eic-av.com +||eireinikotaerukai.com +.eisbb.com +.eksisozluk.com +||eksisozluk.com +electionsmeter.com +||elgoog.im +.elpais.com +||elpais.com +.eltondisney.com +.emaga.com/info/3407 +emilylau.org.hk +.emanna.com/chineseTraditional +.empfil.com +.emule-ed2k.com +|http://emule-ed2k.com +.emulefans.com +|http://emulefans.com +.emuparadise.me +.enanyang.my +!--.enanyang.my/news/20170502/%E7%BE%8E%E5%9B%BD%E4%B9%8B%E9%9F%B3%E5%A4%A7%E5%9C%B0%E9%9C%87%E3%80%8A%E8%8B%B9%E6%9E%9C%E3%80%8B%E7%8B%AC%E5%AE%B6 +||encrypt.me +||enewstree.com +.enfal.de +||chinese.engadget.com +englishforeveryone.org +||englishfromengland.co.uk +englishpen.org +.enlighten.org.tw +||entermap.com +.episcopalchurch.org +.epochhk.com +||epochhk.com +epochtimes-bg.com +||epochtimes-bg.com +epochtimes-romania.com +||epochtimes-romania.com +epochtimes.co.il +||epochtimes.co.il +epochtimes.co.kr +||epochtimes.co.kr +epochtimes.com +||epochtimes.com +.epochtimes.cz +||epochtimes.de +||epochtimes.fr +||epochtimes.it +||epochtimes.jp +||epochtimes.ru +||epochtimes.se +||epochtimestr.com +.epochweek.com +||epochweek.com +||epochweekly.com +||eporner.com +.equinenow.com +erabaru.net +.eracom.com.tw +.eraysoft.com.tr +.erepublik.com +.erights.net +||erights.net +||ernestmandel.org +||erodaizensyu.com +||erodoujinlog.com +||erodoujinworld.com +||eromanga-kingdom.com +||eromangadouzin.com +.eromon.net +|http://eromon.net +.eroprofile.com +.eroticsaloon.net +.eslite.com +||eslite.com +.etaa.org.au +.etadult.com +etaiwannews.com +||etizer.org +||etokki.com +||etsy.com +.ettoday.net +etvonline.hk +.eucasino.com +.eulam.com +.eurekavpt.com +||eurekavpt.com +.euronews.com +||euronews.com +eeas.europa.eu/delegations/china/press_corner/all_news/news/2015/20150716_zh +eeas.europa.eu/statements-eeas/2015/151022 +||apps.evozi.com +||evschool.net +||exblog.jp +@@||www.exblog.jp +.exchristian.hk +||exchristian.hk +|http://blog.excite.co.jp +||exhentai.org +||exmormon.org +||expatshield.com +.expecthim.com +||expecthim.com +experts-univers.com +||exploader.net +.expressvpn.com +||expressvpn.com +.extremetube.com +eyevio.jp +||eyevio.jp +.eyny.com +||eyny.com +.ezpeer.com + +!--------------------FF------------------------- +||feedly.com +||fuckccp.xyz +||fuckccp.com +||furrybar.com +||forbes.com +||financialexpress.com +||fast.com +||factchecklab.org +||ft.com +||fuchsia.dev +||freess.org +||fril.jp +||free.com.tw +||froth.zone +||fanbox.cc +||free.bg +||f-droid.org +||facebookquotes4u.com +.faceless.me +||faceless.me +|http://facesoftibetanselfimmolators.info +||facesofnyfw.com +||factpedia.org +.faith100.org +|http://faith100.org + +!--Enhancement: +!--http://faithfuleye.com.detail.website/ +!--http://faithfuleye.com.ipaddress.com/ +.faithfuleye.com + +||faiththedog.info +.fakku.net +||fallenark.com +.falsefire.com +||falsefire.com +falun-co.org +falunart.org +||falunasia.info +|http://falunau.org +.falunaz.net +falundafa.org +falundafa-dc.org +||falundafa-florida.org +||falundafa-nc.org +||falundafa-pa.net +falun-ny.net +||falundafaindia.org +falundafamuseum.org +.falungong.club +.falungong.de +falungong.org.uk +||falunhr.org +faluninfo.de +faluninfo.net +.falunpilipinas.net +familyfed.org +.fangeming.com +||fanglizhi.info +||fangong.org +fangongheike.com +||fanhaolou.com +.fanqiang.tk +fanqianghou.com +||fanqianghou.com +.fanqiangzhe.com +||fanqiangzhe.com +||fantv.hk +fapdu.com +faproxy.com +!--.farxian.com +.fawanghuihui.org +||famunion.com +.fan-qiang.com +fangeming.com +.fanhaodang.com +||fanqiang.network +||fanswong.com +.fanyue.info +.farwestchina.com + +!--Fastly +en.favotter.net +!--||rnw.global.ssl.fastly.net +.global.ssl.fastly.net +||freetls.fastly.net +nytimes.map.fastly.net +||nytimes.map.fastly.net +||fast.wistia.com + +||fastestvpn.com +||fastssh.com +||faststone.org +favstar.fm +||favstar.fm +faydao.com/weblog +||faz.net +.fc2.com +.fc2china.com +.fc2cn.com +||fc2cn.com +fc2blog.net +|http://uygur.fc2web.com/ +.fdc64.de +.fdc64.org +.fdc89.jp +!--feedbooks.mobi +||feeder.co +||feelssh.com +feer.com +|http://feitianacademy.org +.feitian-california.org +||feixiaohao.com +||feministteacher.com +.fengzhenghu.com +||fengzhenghu.com +.fengzhenghu.net +||fengzhenghu.net +.fevernet.com +|http://ff.im +fffff.at +fflick.com +.ffvpn.com +fgmtv.net +.fgmtv.org +.fhreports.net +|http://fhreports.net +.figprayer.com +||figprayer.com +.fileflyer.com +||fileflyer.com +|http://feeds.fileforum.com +.fileserve.com/file +fillthesquare.org +filmingfortibet.org +.filthdump.com +.finchvpn.com +||finchvpn.com +!--findbook.tw +findmespot.com +||findyoutube.com +||findyoutube.net +.fingerdaily.com +.firearmsworld.net +|http://firearmsworld.net +||relay.firefox.com +||fireofliberty.info +||fireofliberty.org +.firetweet.io +||firetweet.io +||open.firstory.me +||firstpost.com +||firstrade.com +||fish.audio +!--||flagfox.net +.flagsonline.it +fleshbot.com +.fleursdeslettres.com +|http://fleursdeslettres.com +||flgjustice.org + +!--||farm6.staticflickr.com +!--.flickr.com/photos/46231077@N06 +!--.flickr.com/groups/aiweiwei +!--.flickr.com/photos/digitalboy100 +!--.flickr.com/photos/fzhenghu +!--.flickr.com/photos/lonelyfox +!--flickr.com/photos/vanvan/529925157 +!--.flickr.com/photos/winterkanal +!--.flickr.com/photos/zola +||flickr.com +||staticflickr.com + +flickrhivemind.net +.flickriver.com +.fling.com +||flipkart.com +||flog.tw +||flowhongkong.net +.flyvpn.com +||flyvpn.com +|http://cn.fmnnow.com +blog.foolsmountain.com +.forum4hk.com +fangong.forums-free.com +pioneer-worker.forums-free.com +!--foursquare.com +!--|http://4sq.com +|https://ss*.4sqi.net +video.foxbusiness.com +|http://foxgay.com +||fringenetwork.com +||flecheinthepeche.fr +.fochk.org +||fochk.org +||focustaiwan.tw +.focusvpn.com +||fofg.org +.fooooo.com +||fooooo.com +||foreignaffairs.com +||fountmedia.io +||fourthinternational.org +||foxsub.com +foxtang.com +.fpmt.org +|http://fpmt.org +.fpmt.tw +.fpmt-osel.org +||fpmtmexico.org +||fqrouter.com +||frank2019.me +||franklc.com +.freakshare.com +|http://freakshare.com +free-gate.org +.free-hada-now.org +free-proxy.cz +.free.fr/adsl +kineox.free.fr +tibetlibre.free.fr +||freebrowser.org +.freechal.com +.freedomhouse.org +||freedomhouse.org +.freedomsherald.org +||freedomsherald.org +||freegao.com +freeilhamtohti.org +||freekazakhs.org +.freelotto.com +||freelotto.com +freeman2.com +.freeopenvpn.com +freemoren.com +freemorenews.com +freemuse.org/archives/789 +freenet-china.org +freenewscn.com +cn.freeones.com +.freeoz.org/bbs +||freeoz.org +||freessh.us +||freebeacon.com +.freechina.news +||freechinaweibo.com +.freedomcollection.org/interviews/rebiya_kadeer +.freeforums.org +||freenetproject.org +.freeoz.org +.freetibet.net +||freetibet.org +.freetibetanheroes.org +|http://freetibetanheroes.org +||freetribe.me +.freeviewmovies.com +.freevpn.me +|http://freevpn.me +||freewallpaper4.me +.freewebs.com +.freewechat.com +||freewechat.com +freeweibo.com +||freeweibo.com +.freexinwen.com +||freezhihu.org +||friendfeed.com +||friends-of-tibet.org +.friendsoftibet.org +||friendsoftibet.org +freechina.net +|http://www.zensur.freerk.com/ +freevpn.nl +freeyellow.com +hk.frienddy.com/hk +|http://adult.friendfinder.com/ +.fring.com +||fring.com +.fromchinatousa.net +||frommel.net +.frontlinedefenders.org +||frontlinedefenders.org +.frootvpn.com +||frootvpn.com +||fscked.org +.fsurf.com +.ftv.com.tw +||ftv.com.tw +||ftvnews.com.tw +fucd.com +fuckgfw.org +.fulione.com +|https://fulione.com +||fullerconsideration.com +||fullservicegame.com +.funf.tw +funp.com +.fuq.com +.furhhdl.org +||furinkan.com +.futurechinaforum.org +||futuremessage.org +.fux.com +.fuyindiantai.org +.fuyu.org.tw +||fw.cm +.fxcm-chinese.com +||fxcm-chinese.com + +!--------------------GG------------------------- +||gitlab.net +|http://gmp4.com +||getsession.org +||gdaily.org +||gfwatch.org +||go-to-zlibrary.se +||gitbook.io +.g6hentai.com +|http://g6hentai.com +||g-queen.com +||gab.com +||gabocorp.com +.gaeproxy.com +.gaforum.org +.gagaoolala.com +||gagaoolala.com +.galaxymacau.com +||galenwu.com +.galstars.net +||game735.com +gamebase.com.tw +gamejolt.com +|http://wiki.gamerp.jp +||gamer.com.tw +.gamer.com.tw +.gamez.com.tw +||gamez.com.tw +.gamousa.com +.gaoming.net +||gaoming.net +ganges.com +||ganjing.com +||ganjingworld.com +.gaopi.net +|http://gaopi.net +gardennetworks.com +||gardennetworks.org +!--IP of Garden Network +72.52.81.22 +||gartlive.com +||gather.com +.gatherproxy.com +.gaybubble.com +.gaycn.net +.gayhub.com +||gaymap.cc +.gaymenring.com +.gaytube.com +!--||gaytube.com +||images-gaytube.com +.gaywatch.com +|http://gaywatch.com +.gazotube.com +||gazotube.com +||gcc.org.hk +||gclubs.com +||gcmasia.com +.gcpnews.com +|http://gcpnews.com +gdzf.org +||geek-art.net +geekerhome.com/2010/03/xixiang-project-cross-gfw +.gekikame.com +|http://gekikame.com +.gelbooru.com +|http://gelbooru.com +||generated.photos +||genius.com +!--||genuitec.com +.geocities.co.jp +.geocities.com/SiliconValley/Circuit/5683/download.html +hk.geocities.com +geocities.jp +||geph.io +.gerefoundation.org +||getastrill.com +.getchu.com +.getcloak.com +||getcloak.com +||getfoxyproxy.org +||getgom.com +.geti2p.net +||geti2p.net +getiton.com +.getjetso.com/forum +.getlantern.org +||getlantern.org +||getmalus.com +.getsocialscope.com +||getsync.com +||gettr.com +gfbv.de +.gfsale.com +||gfsale.com +.gfw.press +||gfw.press +||gfw.report +.ggssl.com +||ggssl.com +!--||ghost.org +.ghostpath.com +||ghostpath.com +||ghut.org +.giantessnight.com +|http://giantessnight.com +.gifree.com +||giga-web.jp +tw.gigacircle.com +gigporno.ru +||girlbanker.com +.git.io +||git.io +|http://softwaredownload.gitbooks.io +||raw.githack.com + +!---GitHub--- +||github.blog +||github.com +||githubcopilot.com +!--github.com/getlantern +!--|https://gist.github.com +!--http://cthlo.github.io/hktv +!--hahaxixi.github.io +!--|https://hahaxixi.github.io +!--||haoel.github.io +!--|http://onionhacker.github.io +!--||rg3.github.io +!--||sikaozhe1997.github.io +!--||sodatea.github.io +!--||terminus2049.github.io +!--||toutyrater.github.io +!--wsgzao.github.io +!--|https://wsgzao.github.io +.github.io +||github.io +||githubusercontent.com +||githubassets.com + +.gizlen.net +||gizlen.net +.gjczz.com +||gjczz.com +||glarity.app +||globaljihad.net +globalmediaoutreach.com +globalmuseumoncommunism.org +||globalrescue.net +.globaltm.org +.globalvoicesonline.org +||globalvoicesonline.org +||globalvpn.net +.glock.com +gluckman.com/DalaiLama +||gmgard.com +|http://www.gmiddle.com +|http://www.gmiddle.net +.gmll.org +||suche.gmx.net +||gnci.org.hk +||gnews.org +||goagent.biz +||godaddy.com +godfootsteps.org +||godfootsteps.org +godsdirectcontact.co.uk +.godsdirectcontact.org +godsdirectcontact.org.tw +.godsimmediatecontact.com +||gofundme.com +||gohappy.com.tw +.gokbayrak.com +.goldbet.com +||goldbetsports.com +||golden-ages.org +||goldeneyevault.com +.goldenfrog.com +||goldenfrog.com +.goldstep.net +||goldwave.com +||gongm.in +blog.goo.ne.jp/duck-tail_2009 +good.news +.gooday.xyz +||gooday.xyz +||goodhope.school +||goodnewsnetwork.org +.goodreads.com +||goodreads.com +.goodreaders.com +||goodreaders.com +.goodtv.com.tw +.goodtv.tv +||goofind.com +.gopetition.com +||gopetition.com +||goreforum.com +||gotquestions.org +.gotrusted.com +||gotrusted.com +||gotw.ca +||grammaly.com +grandtrial.org +.graphis.ne.jp +||graphis.ne.jp +||graphql.org +||gravatar.com +greatfirewall.biz +.greatfirewallofchina.org +||greatfirewallofchina.org +.greenparty.org.tw +||greenpeace.org +.greenreadings.com/forum +||greasyfork.org +greatroc.org +greatzhonghua.org +.greenpeace.com.tw +.greenvpn.net +||greenvpn.net +.greenvpn.org +||grindr.com +||ground.news +gs-discuss.com +||gsearch.media +||gtricks.com +guancha.org +.guardster.com +.gun-world.net +gunsandammo.com +||gutteruncensored.com +||gvm.com.tw +||gwins.org +.gzm.tv +||gzone-anime.info + +!-------------GHS----- +!-||feeds.cbsnews.com +!-||www.chinesealbumart.com +||clementine-player.org +!-||clemesha.org +!-||www.cloudgirlfriend.com +!-||cocoawithlove.com +!-||blog.controlspace.org +!-D +!-||www.dailygyan.com +!-||dailytodo.org +!-||blog.danmarner.com +!-||github.danmarner.com +!-||design-seeds.com +!-||designers-artists.com +!-||mail.diyang.org +!-||blog.doughellmann.com +!-||downforeveryoneorjustme.com +!-||droidsecurity.com +!-||www.dropmocks.com +!-||dumblittleman.com +!-E +echofon.com +!-||echofon.com +!-||epc-jav.com +!-||everdark.info +!-||evhead.com +!-F +!-||facilelogin.com +!-||*.fatduck.org +!-||blog.fdcn.org +!-||fftogo.com +!-||flightsimtalk.com +!-||mclee.foolme.net +!-||www.frienddeck.com +!-||fringespoilers.com +!-||fringetelevision.com +!-||funpea.com +!-G +!-||blog.gatein.org +!-||feeds.gawker.com +!-||geektang.com +!-||geohot.us +!-||getaround.com +!-||gmer.net +!-||www.gmote.org +!-||blog.go2web20.net +!-||google-melange.com +!-||fame.gonzolabs.org +!-||govecn.org +!-||gqueues.com +!-||graphycalc.com +!-||blog.growlforwindows.com +!-H +!-||hcm.com.tw +!-||blog.headius.com +!-||hogbaysoftware.com +!-||blog.hotot.org +!-||feeds.howstuffworks.com +!-||huhaitai.com +!-||blog.humanrightsfirst.org +!-I +!-||site.icu-project.org +!-||igorware.com +!-||ihas1337code.com +!-||inknouveau.com +!-||inote.tw +!-||ironhelmet.com +!-||iwfwcf.com +!-J +!-||blog.jangmt.com +!-||blog.jayfields.com +!-||blog.joint.net +!-||blog.jsquaredjavascript.com +!-||blog.jtbworld.com +!-K +!-||kathyschwalbe.com +!-||tomatovpn.keithmoyer.com +!-||www.keithmoyer.com +!-||kendalvandyke.com +!-||blog.kengao.tw +!-||log.keso.cn +!-||www.khanacademy.org +||www.klip.me +!-||usbloadergx.koureio.net +!-||blog.kowalczyk.info +!-L +!-||labyrinth2.com +!-||larsgeorge.com +!-||blog.lastpass.com +!-||docs.latexlab.org +!-||leanessays.com +!-||blog.lidaobing.info +!-||log.lightory.net +!-||feeds.limi.net +!-||www.liteapplications.com +!-||blog.liukangxu.info +!-||twitter.liukangxu.info +!-||oasisnewsroom.live4ever.us +!-||www.lockergnome.com +!-||locql.com +@@||site.locql.com +!-||feeds.loiclemeur.com +!-||blog.louisgray.com +!-M +!-||madebysofa.com +!-||mademoisellerobot.com +!-||masamixes.com +!-||www.metamuse.net +!-||blog.metasploit.com +!-||milazi.com +!-||www.miniweather.com +!-||twitter.missiu.com +!-||plurktop-button.mmdays.com +!-||feeds.mobileread.com +!-||www.modernizr.com +!-||www.modk.it +!-||mytwishirt.com +!-N +!-||blog.netflix.com +!-||blog.nihilogic.dk +!-||ntlk.org +!-||nvquan.org +!-||nogoodatcoding.com +!-||blog.notdot.net +!-||www.notify.io +!-O +!-||blog.obvious.com +!-||onebigfluke.com +!-||overstimulate.com +!-P +!-||pcgeekblog.com +!-||feeds.pdfchm.net +!-||feeds.people.com +!-||blog.persistent.info +!-||chrome.plantsvszombies.com +!-||portablesoft.org.ru +!-||prasannatech.net +!-||talk.news.pts.org.tw +!-||python-excel.org +!-Q +!-R +!-||r-chart.com +!-||rameshsubramanian.org +!-||rapid.pk +!-||blog.renanse.com +!-||robertmao.com +!-||www.romeo-foxtrot.com +!-S +!-||salmiyuck.com +!-||samsal.com +!-||blog.seeminglee.com +!-||blog.sflow.com +!-||blog.sigfpe.com +!-||simpletext.ws +!-||www.skulpt.org +!-||rss.slashdot.org +!-||snippetsapp.com +!-||w.sns.ly +!-||www.socialnmobile.com +!-||www.socialwhois.com +!-||spiritjb.org +!-||ssbook.com +!-||sshforwarding.com +!-||stationeria.com +||stephaniered.com +!-||sunjidong.net +!-||syniumsoftware.com +@@||download.syniumsoftware.com +!-T +!-||tagxedo.com +!-||blog.tatoeba.org +!-||www.techfob.com +!-||teachparentstech.org +!-||the8pen.com +!-||theiphonewiki.com +!-||blog.thesilentnumber.me +!-||thesponty.com +!-||theultralinx.com +!-||blog.think-async.com +!-||tornadoweb.org +!-||transparentuptime.com +!-||triangulationblog.com +!-||blog.tsunanet.net +!-||en.tuxero.com +!-||twazzup.com +!-||tweetswell.com +!-||twibes.com +!-||art.twgg.org +!-||twivert.com +!-U +|http://ub0.cc +!-||jonny.ubuntu-tw.net +!-||blog.umonkey.net +!-V +!-||tp.vbap.com.au +!-||www.virtuousrom.com +!-||blog.visibotech.com +!-W +!-||waveprotocol.org +!-||www.wavesandbox.com +!-||webfee.org.ru +!-||blog.webmproject.org +!-||webupd8.org +!-||www.whatbrowser.org +!-||www.wheredoyougo.net +!-||willhains.com +!-||feeds.wired.com +!-||wisemapping.org +wozy.in +!-||wozy.in/ +!-||blog.wundercounter.com +!-X +!-||xdelta.org +!-||xiaogaozi.org +!-||xilou.us +!-||xzy.org.ru +!-Y +!-||yooper.be +!-||tsong.yunxi.net +!-Z + +gospelherald.com +||gospelherald.com +|http://hk.gradconnection.com/ +greatfire.org +||greatfire.org +greatfirewallofchina.org +||gtv.org +||gtv1.org +.gu-chu-sum.org +|http://gu-chu-sum.org +.guaguass.com +|http://guaguass.com +.guangming.com.my +guishan.org +||guishan.org +.gumroad.com +||gumroad.com +||gunsamerica.com +guruonline.hk +|http://gvlib.com +.gyalwarinpoche.com +.gyatsostudio.com + +!--------------------HH------------------------- +||herominers.com +||hinet.net +||hindustantimes.com +||hanime1.me +||halktv.com.tr +||haiwaikan.com +||home.saxo +||hoy.tv +.h528.com +.h5dm.com +.h5galgame.me +||h-china.org +.h-moe.com +|http://h-moe.com +h1n1china.org +.hacken.cc/bbs +.hacker.org +||hackmd.io +||hackthatphone.net +hahlo.com +||haijiao.com +||hakkatv.org.tw +.handcraftedsoftware.org +|http://bbs.hanminzu.org/ +.hao.news/news +|http://ae.hao123.com +|http://ar.hao123.com +|http://br.hao123.com +|http://en.hao123.com +|http://id.hao123.com +|http://jp.hao123.com +|http://ma.hao123.com +|http://mx.hao123.com +|http://sa.hao123.com +|http://th.hao123.com +|http://tw.hao123.com +|http://vn.hao123.com +|http://hk.hao123img.com +|http://ld.hao123img.com +.haproxy.org +||hardsextube.com +||b.hatena.ne.jp +have8.com +@@||haygo.com +.hclips.com +||hdtvb.net +.hdzog.com +|http://hdzog.com +||ordns.he.net +||heartyit.com +.heavy-r.com +.hec.su +|http://hec.su +.hecaitou.net +||hecaitou.net +.hechaji.com +||hechaji.com +||heeact.edu.tw +.hegre-art.com +|http://hegre-art.com +||cdn.helixstudios.net +||helloandroid.com +||helloqueer.com +.hentai.to +.hellouk.org/forum/lofiversion +.helpeachpeople.com +||helpeachpeople.com +||helpster.de +.helpzhuling.org +hentaitube.tv +.hentaivideoworld.com + +!###########--Heroku--########## +!--||getcloudapp.com +!--||cl.ly +!--@@||f.cl.ly +!--EC2 DNS Poisoned +||id.heroku.com +||herokuapp.com + +||heqinglian.net +||heritage.org +.hexieshe.com +||hexieshe.com +||hexieshe.xyz +!--Google employee within Google IP +||hexxeh.net +||heyuedi.com +.heyzo.com +.hgseav.com +.hhdcb3office.org +.hhthesakyatrizin.org +hi-on.org.tw +||hiccears.com +hidden-advent.org +||hidden-advent.org +hidecloud.com/blog/2008/07/29/fuck-beijing-olympics.html +||hide.me +.hideipvpn.com +||hideipvpn.com +.hideman.net +||hideman.net +hideme.nl +||hidemy.name +.hidemyass.com +||hidemyass.com +hidemycomp.com +||hidemycomp.com +.higfw.com +highpeakspureearth.com +||highrockmedia.com +||hiitch.com +||hikinggfw.org +.hilive.tv +.himalayan-foundation.org +||himalayan-foundation.org +himalayanglacier.com +.himemix.com +||himemix.com +.hitomi.la +|http://hitomi.la +.hiwifi.com +@@||hiwifi.com +hizbuttahrir.org +hizb-ut-tahrir.info +hizb-ut-tahrir.org +.hjclub.info +.hk-pub.com/forum +|http://hk-pub.com +.hk01.com +||hk01.com +||hkacg.com +||hkacg.net +.hkatvnews.com +hkbc.net +.hkbf.org +.hkbookcity.com +||hkbookcity.com +||hkchronicles.com +.hkchurch.org +hkci.org.hk +.hkcmi.edu +||hkcnews.com +||hkcoc.com +hkday.net +.hkdailynews.com.hk/china.php +||hkdc.us +hkdf.org +.hkej.com +.hkepc.com/forum/viewthread.php?tid=1153322 +||hket.com +||hkfaa.com +hkfront.org +m.hkgalden.com +|https://m.hkgalden.com +||hkgpao.com +.hkheadline.com*blog +.hkheadline.com/instantnews +hkhkhk.com +hkhrc.org.hk +hkjc.com +.hkjp.org +.hklft.com +.hklts.org.hk +||hklts.org.hk +||hkmap.live +||hkopentv.com +||hkpeanut.com +hkptu.org +.hkreporter.com +||hkreporter.com +.hmv.co.jp/ +hnjhj.com +||hnjhj.com +.hnntube.com +||hojemacau.com.mo +||hola.com +||hola.org +holyspiritspeaks.org +||holyspiritspeaks.org +.homeperversion.com +|http://homeservershow.com +|http://old.honeynet.org/scans/scan31/sub/doug_eric/spam_translation.html +.hongkongfp.com +||hongkongfp.com +hongmeimei.com +||hongzhi.li +||honven.xyz +.hootsuite.com +||hootsuite.com +||hoover.org +.hopto.org +.hornygamer.com +.hornytrip.com +|http://hornytrip.com +||horrorporn.com +||hostloc.com +||hotair.com +.hotav.tv +.hotels.cn +hotfrog.com.tw +hotgoo.com +hotpot.hk +.hotshame.com +||hotspotshield.com +||hottg.com +.hotvpn.com +||hotvpn.com +||howtoforge.com +||hoxx.com +||hpjav.com +.hqcdp.org +||hqcdp.org +||hqjapanesesex.com +hqmovies.com +.hrcchina.org +.hrea.org +.hrichina.org +||hrichina.org +||hrntt.org +.hrtsea.com +.hrw.org +||hrw.org +hrweb.org +||hsex.men +||hsjp.net +||hsselite.com +||hst.net.tw +.hstern.net +.hstt.net +.htkou.net +||htkou.net +.huaglad.com +||huaglad.com +.huanghuagang.org +||huanghuagang.org +.huangyiyu.com +.huaren.us +||huaren.us +.huaren4us.com +.huashangnews.com +|http://huashangnews.com +bbs.huasing.org +huaxiabao.org +huaxin.ph +||huayuworld.org +||huffingtonpost.com +||huffpost.com +||huggingface.co +||hugoroy.eu +||huhaitai.com +||huhamhire.com +.huhangfei.com +||huhangfei.com +.hulkshare.com +||humanparty.me +||humanrightspressawards.org +||hung-ya.com +||huping.net +hurgokbayrak.com +.hurriyet.com.tr +.hut2.ru +||hutianyi.net +hutong9.net +huyandex.com +.hwadzan.tw +||hwayue.org.tw +||hxwk.org +hxwq.org +||hyperrate.com +||hypothes.is +ebook.hyread.com.tw +||ebook.hyread.com.tw + +!--------------------II------------------------- +||ipify.org +@@||*.ipify.org +||itiger.com +||itch.io +||infura.io +||president.ir +||gov.ir +||irna.ir +||arvanstorage.ir +||irangov.ir +||india.com +||indiatoday.in +||invidio.us +||improd.works +||illawarramercury.com.au +||imago-images.com +||i2p2.de +||i818hk.com +.i-cable.com +.i-part.com.tw +.iamtopone.com +iask.ca +||iask.ca +.iav19.com +||iavian.net +ibiblio.org/pub/packages/ccic +ibros.org +.ibvpn.com +||ibvpn.com +icams.com +||icedrive.net +.icij.org +||icij.org +||icl-fi.org +.icoco.com +||icoco.com + +!--38.103.165.50 +||furbo.org +!--||iconfactory.com + +||iconpaper.org +!-- Google Pages +||icu-project.org +w.idaiwan.com/forum +idemocracy.asia +.identi.ca +||identi.ca +||idiomconnection.com +|http://www.idlcoyote.com +||idope.se +.idouga.com +.idv.tw +.ied2k.net +.ienergy1.com +||ift.tt +.ifcss.org +||ifcss.org +ifjc.org +.ift.tt +|http://ift.tt +||ifreewares.com +||igcd.net +.igfw.net +||igfw.net +.igmg.de +.igotmail.com.tw +||igvita.com +.ihao.org/dz5 +||iicns.com +.ikstar.com +||ilhamtohtiinstitute.org +||illusionfactory.com +||ilove80.be +||im88.tw +||imgchili.net +.imageab.com +.imagefap.com +||imagefap.com +||imageflea.com +||imageglass.org +||imageshack.us +||imagevenue.com +||imagezilla.net +.imb.org +|http://imb.org + +!--IMDB +|http://www.imdb.com/name/nm0482730 +.imdb.com/title/tt0819354 +.imdb.com/title/tt1540068 +.imdb.com/title/tt4908644 + +.img.ly +||img.ly +||imgasd.com +.imgur.com +||imgur.com +.imkev.com +||imkev.com +.imlive.com +.immoral.jp +impact.org.au +in99.org +in-disguise.com +.incapdns.net +.incloak.com +||incloak.com +||incredibox.fr +||independent.co.uk +||indiablooms.com +||indiandefensenews.in +||indianarrative.com +||timesofindia.indiatimes.com +.indiemerch.com +||indiemerch.com +||info-graf.fr +website.informer.com +||inherit.live +||initiativesforchina.org +||inkbunny.net +||inkui.com +||inmediahk.net +||inmediahk.net +||inoreader.com +||inote.tw +||insecam.org +|http://insecam.org +||inside.com.tw +||insidevoa.com +||institut-tibetain.org +||interactivebrokers.com +||internet.org +internetdefenseleague.org +||internetfreedom.org +!--||interpol.int +||internetpopculture.com +.inthenameofconfuciusmovie.com +||inthenameofconfuciusmovie.com +inxian.com +||inxian.com +!--||ipcf.org.tw +||ipdefenseforum.com +||ipfire.org +||iphone4hongkong.com +||iphonetaiwan.org +||iphonix.fr +||ipicture.ru +.ipjetable.net +||ipjetable.net +.ipobar.com/read.php? +ipoock.com/img +.iportal.me +|http://iportal.me +||ippotv.com +.ipredator.se +||ipredator.se +.iptv.com.tw +||iptvbin.com +||ipvanish.com +iredmail.org +chinese.irib.ir +||ironpython.net +.ironsocket.com +||ironsocket.com +.is.gd +||ishr.ch +.islahhaber.net +.islam.org.hk +|http://islam.org.hk +.islamawareness.net/Asia/China +.islamhouse.com +||islamhouse.com +.islamicity.com +.islamicpluralism.org +.islamtoday.net +.isaacmao.com +||isaacmao.com +||isgreat.org +||ismaelan.com +.ismalltits.com +||ismprofessional.net +isohunt.com +||israbox.com +.issuu.com +||issuu.com +.istars.co.nz +oversea.istarshine.com +||oversea.istarshine.com +.istockphoto.com +isunaffairs.com +isuntv.com +||isupportuyghurs.org +||italiatibet.org +||itemfix.com +ithelp.ithome.com.tw +||itshidden.com +.itsky.it +.itweet.net +|http://itweet.net +.iu45.com +.iuhrdf.org +||iuhrdf.org +.iuksky.com +.ivacy.com +||ivacy.com +||ivonblog.com +.ivpn.net +||ivpn.net +||iwara.tv +||ixquick.com +.ixxx.com +.iyouport.com +||iyouport.com +||iyouport.org +.izaobao.us +.izles.net +.izlesem.org + +!--------------------JJ------------------------- +||justmysockscn.com +||justmysocks.net +||jav321.com +||javdb.com +||jifangge.com +||j.mp +||jable.tv +||blog.jackjia.com +jamaat.org +||jamestown.org +||jamyangnorbu.com +||jan.ai +||japan-whores.com +||japanhdv.com +.jav.com +.jav101.com +.jav68.tv +.javakiba.org +||javakiba.org +.javbus.com +||javbus.com +||javfinder.ai +||javfor.me +.javhd.com +.javhip.com +.javmobile.net +||javmobile.net +.javmoo.com +.javseen.com +||javseen.com +jbtalks.cc +jbtalks.com +jbtalks.my +.jdwsy.com +jeanyim.com +||jgoodies.com +.jiangweiping.com +||jiangweiping.com +||jiaoyou8.com +||jichangtj.com +.jiehua.cz +||hk.jiepang.com +||tw.jiepang.com +jieshibaobao.com +.jigglegifs.com +56cun04.jigsy.com +daodu14.jigsy.com +specxinzl.jigsy.com +wlcnew.jigsy.com +.jihadology.net +|http://jihadology.net +.jingsim.org +zhao.jinhai.de +jingpin.org +||jingpin.org +jinpianwang.com +||jinrizhiyi.news +||jitouch.com +jjgirls.com +.jkb.cc +|http://jkb.cc +jkforum.net +||jma.go.jp +||jmsc.hku.hk +.jmscult.com +|http://jmscult.com +||joachims.org +.sunwinism.joinbbs.net +||joinclubhouse.com +||jornaldacidadeonline.com.br +.journalchretien.net +||journalofdemocracy.org +.joymiihub.com +.joyourself.com +jpopforum.net +||jsdelivr.net +||fiddle.jshell.net +!--Doamin parking +.juhuaren.com +||juliereyc.com +||junauza.com +.june4commemoration.org +||bbs.junglobal.net +.juoaa.com +|http://juoaa.com +justfreevpn.com +||justhost.ru +justpaste.it +||justmysocks1.net +justtristan.com +juziyue.com +||juziyue.com +||jwmusic.org +@@||music.jwmusic.org +||cdn.jwplayer.com +.jyxf.net + +!--------------------KK------------------------- +||kingkong.com.tw +||kanald.com.tr +||kpkuang.org +||ka-wai.com +||kadokawa.co.jp +.kagyu.org +||kagyu.org.za +.kagyumonlam.org +.kagyunews.com.hk +.kagyuoffice.org +||kagyuoffice.org +||kagyuoffice.org.tw +.kaiyuan.de +.kakao.com +||kakao.com +.kankan.today +.kannewyork.com +||kannewyork.com +.kanshifang.com +||kanshifang.com +||kantie.org +kanzhongguo.com +kanzhongguo.eu +.kaotic.com +||kaotic.com +||karayou.com +.karmapa.org +.karmapa-teachings.org +||kawase.com +.kba-tx.org +.kcoolonline.com +.kebrum.com +||kebrum.com +.kechara.com +.keepandshare.com/visit/visit_page.php?i=688154 +!--||keepvid.com +.keezmovies.com +.kenengba.com +||kenengba.com +.kepard.com +||kepard.com +wiki.keso.cn/Home +||keycdn.com +.khabdha.org +||kichiku-doujinko.com +.kik.com +||kik.com +.kindleren.com +|http://kindleren.com +|http://www.kindleren.com +.kingdomsalvation.org +||kingdomsalvation.org +kinghost.com +!--.kingstone.com.tw/book/ +||kingstone.com.tw +.kink.com +.kinokuniya.com +||kinokuniya.com +killwall.com +||killwall.com +||kindle4rss.com +||kinmen.travel +.kir.jp +.kissbbao.cn +|http://kiwi.kz +||kk-whys.co.jp +!--||kmt.org.tw +.kmuh.org.tw +.knowledgerush.com/kr/encyclopedia +||knowyourmeme.com +.kobo.com +||kobo.com +.kobobooks.com +||kobobooks.com +||kodingen.com +@@||www.kodingen.com +||kompozer.net +.konachan.com +||konachan.com +.kone.com +||koolsolutions.com +.koornk.com +||koornk.com +||koranmandarin.com +.korenan2.com +||kqes.net +|http://gojet.krtco.com.tw +.ksdl.org +.ksnews.com.tw +||ktzhk.com +||kuaichedao.co +.kui.name/event +||kukuku.uk +kun.im +.kurashsultan.com +||kurtmunger.com +kusocity.com +||kwcg.ca +.kwongwah.com.my +||kwongwah.com.my +.kxsw.life +||kxsw.life +.kyofun.com +kyohk.net +||kzaobao.com +.kzeng.info +||kzeng.info + +!--------------------LL------------------------- +||luckymobile.ca +||ludepress.com +||lingualeo.com +||ldplayer.tw +||ldplayer.net +||ltn.com.tw +||litenews.hk +||www.lorenzetti.com.br +||linktr.ee +la-forum.org +ladbrokes.com +||labiennale.org +.lagranepoca.com +||lagranepoca.com +||lala.im +.lalulalu.com +.lama.com.tw +||lama.com.tw +.lamayeshe.com +|http://lamayeshe.com +.lamnia.co.uk +||lamnia.co.uk +lamrim.com +||landofhope.tv +.lanterncn.cn +|http://lanterncn.cn +.lantosfoundation.org +.laod.cn +|http://laod.cn +laogai.org +||laogai.org +||laogairesearch.org +laomiu.com +.laoyang.info +|http://laoyang.info +.laqingdan.net +||laqingdan.net +||larsgeorge.com +.lastcombat.com +|http://lastcombat.com +||lastfm.es +latelinenews.com +||lausan.hk +||le-vpn.com +.leafyvpn.net +||leafyvpn.net +||ledger.com +leeao.com.cn/bbs/forum.php +!--||leecheukyan.org +lefora.com +||left21.hk +.legalporno.com +.legsjapan.com +leisurecafe.ca +||lematin.ch +.lemonde.fr +||lenwhite.com +blog.lester850.info +||lesoir.be +.letou.com +letscorp.net +||letscorp.net +!69.16.175.42 +||cdn.assets.lfpcontent.com +.lhakar.org +|http://lhakar.org +.lhasocialwork.org +.liangyou.net +||liangyou.net +.lianyue.net +||liaowangxizang.net +.liaowangxizang.net +||liberal.org.hk +||libertysculpturepark.com +||libertytimes.com.tw +||libredd.it +||lighten.org.tw +||lightnovel.cn +||lilaoshibushinilaoshi.com +limiao.net +linkuswell.com +abitno.linpie.com/use-ipv6-to-fuck-gfw +||line.me +||line-apps.com +.linglingfa.com +||lingvodics.com +.link-o-rama.com +|http://link-o-rama.com +||linkedin.com +.linkideo.com +||linux.org.hk +linuxtoy.org/archives/installing-west-chamber-on-ubuntu +.lionsroar.com +.lipuman.com +||liquidvpn.com +||greatfire.us7.list-manage.com +||listennotes.com +||listentoyoutube.com +listorious.com +.liu-xiaobo.org +.liuhanyu.com +.liuxiaobo.net +||liuxiaobo.net +liuxiaotong.com +||liuxiaotong.com +.livedoor.jp +.liveleak.com +||liveleak.com +||livemint.com +livestream.com +||livestream.com +||livingstream.com +||livevideo.com +.livevideo.com +lizhizhuangbi.com +lkcn.net +||chat.lmsys.org +.load.to +.lobsangwangyal.com +.localdomain.ws +||localdomain.ws +localpresshk.com +||lockestek.com +secure.logmein.com +||secure.logmein.com +||logos.com.hk +.londonchinese.ca +.longhair.hk +longmusic.com +||longtermly.net +||lookpic.com +.looktoronto.com +|http://looktoronto.com +.lotsawahouse.org/tibetan-masters/fourteenth-dalai-lama +.lotuslight.org.tw +hkreporter.loved.hk +.lrip.org +||lrip.org +.lsd.org.hk +||lsd.org.hk +lsforum.net +.lsm.org +||lsm.org +.lsmchinese.org +||lsmchinese.org +.lsmkorean.org +||lsmkorean.org +.lsmradio.com/rad_archives +.lsmwebcast.com +.ltn.com.tw +||ltn.com.tw +||luckydesigner.space +.luke54.com +.luke54.org +.lupm.org +||lupm.org +||lushstories.com +luxebc.com +lvhai.org +||lvhai.org +||lvv2.com +.lyfhk.net +|http://lyfhk.net +||lzjscript.com +.lzmtnews.org +||lzmtnews.org + +!--------------------MM------------------------- +||mcusercontent.com +||metamask.io +||missav.ws +||news.mt.co.kr +||musixmatch.com +||mergersandinquisitions.com +||m.moegirl.org +||myjs.tw +||mercari.com +||mercari.jp +||mirror.xyz +||mywife.cc +||c.mi.com +||missav.com +||madou.club +||mahjongsoul.com +||mangabz.com +http://*.m-team.cc +!--m-team.cc/forum +.macrovpn.com +||mad-ar.ch +||madrau.com +||madthumbs.com +mahabodhi.org +my.mail.ru +.maiplus.com +|http://maiplus.com +.maizhong.org +makkahnewspaper.com +.mamingzhe.com +||mangmang.run +manicur4ik.ru +||manyvoices.news +.maplew.com +|http://maplew.com +||marc.info +marguerite.su +maskedip.com +.maiio.net +.mail-archive.com +.malaysiakini.com +||makemymood.com +.manchukuo.net +.maniash.com +|http://maniash.com +.mansion.com +.mansionpoker.com +!--||marines.mil +!--markmail.org*message +||martau.com +|http://blog.martinoei.com +.martsangkagyuofficial.org +|http://martsangkagyuofficial.org +maruta.be/forget +.marxist.com +||marxist.net +.marxists.org/chinese +!--||mashable.com +||matainja.com +||matrix.org +||matters.town +mayimayi.com +.maxing.jp +.mcaf.ee +|http://mcaf.ee +||mcadforums.com +mcfog.com +mcreasite.com +.md-t.org +||md-t.org +||meansys.com +.media.org.hk +.mediachinese.com +||mediachinese.com +.mediafire.com/? +.mediafire.com/download +.mediafreakcity.com +||mediafreakcity.com +.medium.com +||medium.com +.meetav.com +||meetup.com +mefeedia.com +jihadintel.meforum.org +||mega.co.nz +||mega.io +||mega.nz +||megalodon.jp +||megaproxy.com +||megurineluka.com +||meizhong.blog +||meizhong.report +.meltoday.com +.memehk.com +||memehk.com +||memes.tw +.memri.org +.memrijttm.org +||mercdn.net +.mercyprophet.org +||mercyprophet.org +.meridian-trust.org +||meridian-trust.org +.meripet.com +||meripet.com +||merit-times.com.tw +.mesotw.com/bbs +||wiki.metacubex.one +||metafilter.com +||meteorshowersonline.com +||metro.taipei +.metrohk.com.hk/?cmd=detail&categoryID=2 +||metrolife.ca +.metroradio.com.hk +||metroradio.com.hk +||mewe.com +||mgoon.com +||mgstage.com +||mh4u.org +mhradio.org +||bbs.mikocon.com +||microvpn.com +middle-way.net +.mihr.com +||mihua.org +||mikanani.me +!--IP +||mikesoltys.com +.milph.net +|http://milph.net +.milsurps.com +mimiai.net +.mimivip.com +.mindrolling.org +|http://mindrolling.org +||mingdemedia.org +.minghui.or.kr +|http://minghui.or.kr +minghui.org +||minghui.org +minghui-school.org +.mingjinglishi.com +||mingjinglishi.com +mingjingnews.com +||mingjingtimes.com +.mingpao.com +||mingpao.com +.mingpaocanada.com +.mingpaomonthly.com +|http://mingpaomonthly.com +mingpaonews.com +.mingpaony.com +.mingpaosf.com +.mingpaotor.com +.mingpaovan.com +.mingshengbao.com +.minhhue.net +.ministrybooks.org +minzhuzhongguo.org +||miroguide.com +mirrorbooks.com +||mirrormedia.mg +.mist.vip +||thecenter.mit.edu +||scratch.mit.edu +.mitbbs.com +||mitbbs.com +.mixero.com +||mixero.com +||mixi.jp +mixpod.com +.mixx.com +||mixx.com +||mizzmona.com +||mlc.ai +.mlcool.com +||mlzs.work +.mm-cg.com +||mmaaxx.com +.mmmca.com +mnewstv.com +||mobatek.net +.mobile01.com +||mobile01.com +||mobileways.de +.mobypicture.com +|http://moby.to +||mod.io +||modernchinastudies.org +||moeerolibrary.com +||moeshare.cc +.mofos.com +||mog.com +||mohu.rocks +molihua.org +||momoshop.com.tw +||mondex.org +||money-link.com.tw +|http://www.monlamit.org +||moon.fm +.moonbbs.com +||moonbbs.com +||moptt.tw +||moneydj.com +||monica.im +||monitorchina.org +||monocloud.me +bbs.morbell.com +||morningsun.org +.motherless.com +|http://motherless.com +motor4ik.ru +.mousebreaker.com +!--||movabletype.com +.movements.org +||movements.org +||moviefap.com +||www.moztw.org +.mp3buscador.com +||mpettis.com +.mpfinance.com +||mpfinance.com +.mpinews.com +||mpinews.com +mponline.hk +mrtweet.com +||mrtweet.com +news.msn.com.tw +msguancha.com +.mswe1.org +|http://mswe1.org +||mthruf.com +||mubi.com +muchosucko.com +||multiply.com +multiproxy.org +multiupload.com +.mullvad.net +||mullvad.net +.mummysgold.com +.musicade.net +.muslimvideo.com +||muzi.com +||muzi.net +||mx981.com +.my-formosa.com +.my-proxy.com +.my-private-network.co.uk +||my-private-network.co.uk +.myactimes.com/actimes +.myaudiocast.com +||myaudiocast.com +.myav.com.tw/bbs +.mybbs.us +.myca168.com +.mycanadanow.com +||bbs.mychat.to +.mychinanet.com +.mychinanews.com +||mychinanews.com +.mychinese.news +||mycnnews.com +||mykomica.org +mycould.com/discuz +.myeasytv.com +||myeclipseide.com +.myfreecams.com +.myfreepaysite.com +.myfreshnet.com +.myiphide.com +||myiphide.com +forum.mymaji.com +||mymoe.moe +||myparagliding.com +||mypopescu.com +.myreadingmanga.info +mysinablog.com +.myspace.com +!--.blogs.myspace.com +!--||blogs.myspace.com +!--vids.myspace.com/index.cfm?fuseaction=vids. +!--viewmorepics.myspace.com +||myspacecdn.com +.mytalkbox.com +.mytizi.com + +!--------------------NN------------------------- +||naver.com +||maven.neoforged.net +||nftstorage.link +||newindianexpress.com +||news18.com +||bbs.naixi.net +||nikke.hotcool.tw +||nikke-kr.com +||nikke-jp.com +||nikke-en.com +||netlify.app +||nightswatch.top +||nbyy.tv +||newthuhole.com +||naacoalition.org +||naitik.net +.nakido.com +||nakido.com +.nakuz.com/bbs +||nalandabodhi.org +||nalandawest.org +.namgyal.org +namgyalmonastery.org +.nanyang.com +||nanyang.com +.nanyangpost.com +||nanyangpost.com +.nanzao.com +!--.nanzao.com/sc/china/20223 +!--.nanzao.com/sc/hk-macau-tw +.naol.ca +.naol.cc +uighur.narod.ru +.nat.moe +||nat.moe +cyberghost.natado.com +||national-lottery.co.uk +||nationalawakening.org +||nationalinterest.org +news.nationalgeographic.com/news/2014/06/140603-tiananmen-square +||nationalreview.com +.nationsonline.org/oneworld/tibet +||line.naver.jp +||navyfamily.navy.mil +||navyreserve.navy.mil +||nko.navy.mil +||usno.navy.mil +naweeklytimes.com +||nbcnews.com +.nbtvpn.com +|http://nbtvpn.com +nccwatch.org.tw +.nch.com.tw +.ncn.org +||nchrd.org +||ncn.org +||etools.ncol.com +.nde.de +||ndi.org +.ndr.de +.ned.org +||nekoslovakia.net +||neowin.net +||netalert.me +!--bbsnew.netbig.com +.netbirds.com +netcolony.com +bolin.netfirms.com +||netflav.com +||netme.cc +||netsarang.com +netsneak.com +.network54.com +networkedblogs.com +.networktunnel.net +new-3lunch.net +.new-akiba.com +.new96.ca +.newcenturymc.com +|http://newcenturymc.com +newcenturynews.com +||newchen.com +.newchen.com +.newgrounds.com +||newhighlandvision.com +newipnow.com +.newlandmagazine.com.au +||newmitbbs.com +.newnews.ca +||news1.kr +news100.com.tw +newschinacomment.org +.newsancai.com +||newsancai.com +||newsblur.com +.newsdetox.ca +.newsdh.com +||newsmax.com +||newstamago.com +||newstapa.org +||newstatesman.com +newstarnet.com +||newsweek.com +.newtaiwan.com.tw +newtalk.tw +||newtalk.tw +||newyorker.com +newyorktimes.com +||nexon.com +.next11.co.jp +||nextdigital.com.hk +.nextmag.com.tw + +!--hk*.nextmedia.com +!--tw*.nextmedia.com +!--static*.nextmedia.com +.nextmedia.com + +||nexton-net.jp +||nexttv.com.tw +.nfjtyd.com +||co.ng.mil +||nga.mil +ngensis.com +.nhentai.net +|http://nhentai.net +.nhk-ondemand.jp +||nicovideo.jp +ninecommentaries.com +.ninjacloak.com +||ninjaproxy.ninja +nintendium.com +taiwanyes.ning.com +usmgtcg.ning.com/forum +||niusnews.com +||njactb.org +||nlfreevpn.com +||nmsl.website +||nnews.eu + +!--no-ip.com#NOIP +.ddns.net/ +||gotdns.ch +.no-ip.org +.opendn.xyz +.servehttp.com +sytes.net +.zapto.org +|http://dynupdate.no-ip.com/ + +||nobel.se +!--.nobelprize.org +!--|http://nobelprize.org +nobelprize.org/nobel_prizes/peace/laureates/1989 +nobelprize.org/nobel_prizes/peace/laureates/2010 +||nodeseek.com +||nokogiri.org +||nokola.com +noodlevpn.com +.norbulingka.org +nordvpn.com +||nordvpn.com +||nos.nl +||notepad-plus-plus.org +||now.com +||nownews.com +.nowtorrents.com +||npa.go.jp +.npnt.me +|http://npnt.me +.nradio.me +|http://nradio.me +.nrk.no +||nrk.no +.ntd.tv +||ntd.tv +.ntdtv.com +||ntdtv.com +||ntdtv.com.tw +.ntdtv.co.kr +ntdtv.ca +ntdtv.org +ntdtv.ru +ntdtvla.com +.ntrfun.com +||cbs.ntu.edu.tw +||media.nu.nl +.nubiles.net +||nuexpo.com +.nukistream.com +||nurgo-software.com +||nutaku.net +||nutsvpn.work +.nuvid.com +||nvdst.com +.nvquan.org +.nvtongzhisheng.org +|http://nvtongzhisheng.org +.nwtca.org +|http://nyaa.eu +||nyaa.si +||nybooks.com +nylon-angel.com +nylonstockingsonline.com +||nypost.com +!--nysingtao.com +.nzchinese.com + +!--------------------OO------------------------- +||oojj.de +||onevps.com +||onedrive.com +||olelive.com +||oann.com +observechina.net +.obutu.com +ocaspro.com +occupytiananmen.com +.ocreampies.com +||october-review.org +||odysee.com +||officeoftibet.com +|http://ofile.org +||ogaoga.org +twtr2src.ogaoga.org +.ogate.org +||ogate.org +www2.ohchr.org/english/bodies/cat/docs/ngos/II_China_41.pdf +||ohmyrss.com +.oikos.com.tw/v4 +.oiktv.com +.ok.ru +||ok.ru +.okayfreedom.com +||okayfreedom.com +||okk.tw +||olevod.com +||olumpo.com +.olympicwatch.org +||omct.org +omgili.com +||omnitalk.com +||omnitalk.org +||omny.fm +||on.cc +||onedrive.live.com +||onion.city +||onion.ly +.onlinecha.com +||onlineyoutube.com +||onlygayvideo.com +.onlytweets.com +|http://onlytweets.com +onmoon.net +onmoon.com +.onthehunt.com +|http://onthehunt.com +open.com.hk +opendemocracy.net +||opendemocracy.net +openid.net +||openid.net +.openleaks.org +||openleaks.org +||openstreetmap.org +||opentech.fund +openvpn.net +||openvpn.net +||openwebster.com +.openwrt.org.cn +@@||openwrt.org.cn +my.opera.com/dahema +.opus-gaming.com +|http://opus-gaming.com +.organcare.org.tw +organharvestinvestigation.net +.orgasm.com +.orgfree.com +||oricon.co.jp +||orient-doll.com +orientaldaily.com.my +||orientaldaily.com.my +!--orientaldaily.on.cc +||orn.jp +||osfoora.com +||otto.de +||ourdearamy.com +oursogo.com +.oursteps.com.au +||oursteps.com.au +.oursweb.net +||ourtv.hk +xinqimeng.over-blog.com +||overcast.fm +||overdaily.org +||overplay.net +share.ovi.com/media +||ovpn.com +|http://owl.li +|http://ht.ly +|http://htl.li +|http://mash.to +www.owind.com +||owltail.com +||oxfordscholarship.com +|http://www.oxid.it +oyax.com +oyghan.com/wps +.ozchinese.com/bbs +||ow.ly +.ozvoice.org +||ozvoice.org +.ozxw.com +.ozyoyo.com + +!--------------------PP------------------------- +||pewresearch.org +||privacyguides.org +||pancakeswap.finance +||img.picgo.net +||pornmate.com +||puredns.org +||polymarket.com +||pandafan.pub +||proxz.com +||potatso.com +||pendrivelinux.com +||paimon.moe +||photonmedia.net +||points-media.com +||pkuanvil.com +||pachosting.com +.pacificpoker.com +.packetix.net +||pacopacomama.com +.padmanet.com +||page.link +page2rss.com +.palacemoon.com +forum.palmislife.com +||eriversoft.com +paljorpublications.com +.paltalk.com +!--||pangci.net +||pandapow.co +.pandapow.net +.pandavpn-jp.com +||pandavpn-jp.com +||pandavpnpro.com +||pao-pao.net +paper.li +paperb.us +.paradisehill.cc +.paradisepoker.com +||parler.com +||parsevideo.com +.partycasino.com +.partypoker.com +.passion.com +||passion.com +.passiontimes.hk +pastebin.com +.pastie.org +||pastie.org +||blog.pathtosharepoint.com +||patreon.com +||patreonusercontent.com +||pawoo.net +||pbs.org + +!--Pbwiki +pbwiki.com +||pbworks.com +||developers.box.net +||wiki.oauth.net +||wiki.phonegap.com +||wiki.jqueryui.com + +||pbxes.com +||pbxes.org +pcdvd.com.tw +||pcgamestorrents.com +.pchome.com.tw +||pcij.org +.pcstore.com.tw +||pct.org.tw +pdetails.com +||pdproxy.com +||peace.ca +peacefire.org +.peeasian.com +||peing.net +.pekingduck.org +||pekingduck.org +.pemulihan.or.id +|http://pemulihan.or.id +||pen.io +penchinese.com +||blog.pentalogic.net +.penthouse.com +||pentoy.hk +.peoplebookcafe.com +.peoplenews.tw +||peoplenews.tw +.peopo.org +||peopo.org +.percy.in +.perfectgirls.net +||perfect-privacy.com +||perplexity.ai +.persecutionblog.com +.persiankitty.com +phapluan.org +.phayul.com +||phayul.com +philborges.com +||phncdn.com +||photodharma.net +||photofocus.com +||picacomiccn.com +.picidae.net +||img*.picturedip.com +picturesocial.com +||picuki.com +||pigav.com +||pin-cong.com +.pin6.com +||pin6.com +.ping.fm +||ping.fm +||pinimg.com +.pinkrod.com +||pinoy-n.com +||pinterest.* +@@||pinterest.cn +.pipii.tv +piraattilahti.org +.piring.com +||pixeldrain.com +||pixelqi.com +||css.pixnet.in +||pixnet.net +.pixnet.net +.pk.com +||pkqjiasu.com +||placemix.com +!--.planetsuzy.org +||play-asia.com +||playboy.com +.playboyplus.com +||playboyplus.com +||player.fm +.playno1.com +||playno1.com +||playpcesor.com +||plexvpn.pro +plm.org.hk +plunder.com +.plurk.com +||plurk.com +.plus28.com +.plusbb.com +.pmatehunter.com +||pmatehunter.com +.pmates.com +||po2b.com +pobieramy.top +!--||pocoo.org +||podbean.com +||podictionary.com +||poe.com +.pokerstars.com +||pokerstars.com +||pokerstars.net +||zh.pokerstrategy.com +||politicalchina.org +.politiscales.net +||poloniex.com +||polymerhk.com +.popo.tw +!--||popularpages.net +||popvote.hk +||popxi.click +.popyard.com +||popyard.org +.porn.com +.porn2.com +.porn5.com +.pornbase.org +.pornerbros.com +||pornhd.com +.pornhost.com +.pornhub.com +||pornhub.com +.pornhubdeutsch.net +|http://pornhubdeutsch.net +.pornoxo.com +.pornrapidshare.com +||pornrapidshare.com +.pornsharing.com +|http://pornsharing.com +.pornsocket.com +||pornstarbyface.com +.pornstarclub.com +||pornstarclub.com +.porntube.com +.porntubenews.com +.porntvblog.com +||porntvblog.com +.pornvisit.com +.portablevpn.nl +||poskotanews.com +.post01.com +.post76.com +||post76.com +.post852.com +||post852.com +postadult.com +||potvpn.com +||pourquoi.tw +||powercx.com +.powerphoto.org +||www.powerpointninja.com +||ppy.sh +||presidentlee.tw +||cdn.printfriendly.com +.pritunl.com +provpnaccounts.com +||provpnaccounts.com +.proxfree.com +||proxfree.com +proxyanonimo.es +.proxynetwork.org.uk +||proxynetwork.org.uk +.pttvan.org +||pubu.com.tw +||puffinbrowser.com +||pureinsight.org +.putty.org +||putty.org + +!-------------Posterous----- +||calebelston.com +||blog.fizzik.com +||nf.id.au +||sogrady.me +||vatn.org +||ventureswell.com +||whereiswerner.com + +.power.com +||power.com +powerapple.com +||powerapple.com +||prayforchina.net +||prcleader.org +||presentationzen.com +||prestige-av.com +.prisoneralert.com +||pritunl.com +||privacybox.de +||private.com +||privateinternetaccess.com +privatepaste.com +||privatepaste.com +privatetunnel.com +||privatetunnel.com +||privatevpn.com +||privoxy.org +||procopytips.com +||project-syndicate.org +||proton.me +provideocoalition.com +||prosiben.de +proxifier.com +||proxomitron.info +.proxpn.com +||proxpn.com +proxyroad.com +.proxytunnel.net +||pshvpn.com +||psiphon.ca +.psiphon3.com +||psiphon3.com +.psiphontoday.com +||pstatic.net +||pt.im +.ptt.cc +||ptt.cc +||pttgame.com +.puffstore.com +||main-ecnpaper-economist.content.pugpig.com +||pullfolio.com +.punyu.com/puny +||pureconcepts.net +||pureinsight.org +||purepdf.com +||purevpn.com +.purplelotus.org +.pursuestar.com +||pursuestar.com +.pussyspace.com +.putihome.org +.putlocker.com/file +pwned.com +||pximg.net +python.com +.python.com.tw +||python.com.tw +pythonhackers.com/p +ss.pythonic.life + +!--------------------QQ------------------------- +|http://qmp4.com +||qianmo.tw +||qbittorrent.org +||qgirl.com.tw +||qianbai.tw +||qiandao.today +||qianglie.com +||qiangwaikan.com +.qi-gong.me +||qi-gong.me +!--#921 +||qiangyou.org +.qidian.ca +||qiwen.lu +qixianglu.cn +.qkshare.com +qoos.com +||qoos.com +||efksoft.com +||qstatus.com +||qtrac.eu +||quitccp.org +.quitccp.org +.quora.com/Chinas-Future +.quran.com +|http://quran.com +.quranexplorer.com +qusi8.net +nemesis2.qx.net/pages/MyEnTunnel +qxbbs.org + +!--------------------RR------------------------- +||radmin-vpn.com +||rule34video.com +||r10s.jp +||rakuten.co.jp +||r0.ru +||radio-canada.ca +||radio-en-ligne.fr +||rael.org +radicalparty.org +||radio.garden +||radioaustralia.net.au +.radiohilight.net +||radiohilight.net +||radioline.co +opml.radiotime.com +||radiovaticana.org +||radiovncr.com +||raggedbanner.com +||raidcall.com.tw +.rainbowplan.org/bbs +|https://raindrop.io/ +.raizoji.or.jp +|http://raizoji.or.jp +rangzen.net +rangzen.org +|http://blog.ranxiang.com/ +.rapbull.net +!--|http://rapidgator.net/ +||rapidmoviez.com +rapidvpn.com +||rapidvpn.com +||rarbgprx.org +||rationalwiki.org +||rawgit.com +||rawgithub.com +||rcinet.ca +||reabble.com +.read100.com +.readingtimes.com.tw +||readingtimes.com.tw +||readmoo.com +.readydown.com +|http://readydown.com +||realcourage.org +.realitykings.com +||realitykings.com +.realraptalk.com +.realsexpass.com +||reason.com +.recordhistory.org +.recovery.org.tw +|http://online.recoveryversion.org +||recoveryversion.com.tw +||red-lang.org +||redbubble.com +.redchinacn.net +||redchinacn.net +redchinacn.org +redtube.com +referer.us +||referer.us +||reflectivecode.com +||blog.reimu.net +relaxbbs.com +.relay.com.tw +.releaseinternational.org +||religionnews.com +renminbao.com +||renminbao.com +.renyurenquan.org +||renyurenquan.org +|http://certificate.revocationcheck.com +||resilio.com +.reuters.com +||reuters.com +||reutersmedia.net +.revleft.com +||resistchina.org +retweetist.com +||retweetrank.com +!--connectedchina.reuters.com +!--|http://www.reuters.com/news/video +revver.com +.rfa.org +||rfa.org +.rfachina.com +.rfamobile.org +rfaweb.org +||rferl.org +.rfi.fr +||rfi.fr +||rfi.my +!--.rhcloud.com +!--Edgecast +.rigpa.org +.rileyguide.com +||riku.me +.ritouki.jp +||ritter.vg +.rlwlw.com +||rlwlw.com +||rmbl.ws +.rmjdw.com +.roadshow.hk +.roboforex.com +||robustnessiskey.com +!--||roc-taiwan.org +||rocket.chat +||rocket-inc.net +|http://www2.rocketbbs.com/11/bbs.cgi?id=5mus +|http://www2.rocketbbs.com/11/bbs.cgi?id=freemgl +!--||rocmp.org +||rojo.com +||ronjoneswriter.com +||rolfoundation.org +||rolia.net +||rolsociety.org +.roodo.com +.rosechina.net +||rou.video +.rsf.org +||rsf.org +.rsf-chinese.org +||rsf-chinese.org +||rsshub.app +||phosphation13.rssing.com +.rssmeme.com +||rssmeme.com +||rtalabel.org +.rthk.hk +||rthk.hk +.rthk.org.hk +||rthk.org.hk +.rti.org.tw +||rti.org.tw +||rti.tw +.ruanyifeng.com/blog*some_ways_to_break_the_great_firewall +rukor.org +||rule34.xxx +||rumble.com +.runbtx.com +.rushbee.com +||rusvpn.com +.ruten.com.tw +||ruten.com.tw +||rutracker.net +||rutracker.org +rutube.ru +.rxhj.net +|http://rxhj.net + +!--------------------SS------------------------- +||sina.com.hk +||swapspace.co +||storry.tv +||standard.co.uk +||sagernet.org +||simplex.chat +||soundon.fm +||ssrtool.com +||ssrshare.us +||secure.shadowsocks.nu +||synapse.org +||south-plus.net +||silvergatebank.com +||share-videos.se +||ssrshare.us +||cdn.statically.io +||slides.com +||suno.com +||sydney.bing.com +||sehuatang.org +||singlelogin.se +||suno.ai +||syosetu.com +.s1s1s1.com +||s-cute.com +.s-dragon.org +|http://www.s4miniarchive.com +cdn1.lp.saboom.com +||sacks.com +sacom.hk +||sacom.hk +||sadpanda.us +||safechat.com +||safeguarddefenders.com +.safervpn.com +||safervpn.com +.saintyculture.com +|http://saintyculture.com +||sakuralive.com +.sakya.org +.salvation.org.hk +||salvation.org.hk +.samair.ru/proxy/type-01 +.sambhota.org +||cn.sandscotaicentral.com +||sankakucomplex.com +||sankei.com +||sanmin.com.tw +sapikachu.net +savemedia.com +||savethesounds.info +.savetibet.de +||savetibet.de +savetibet.fr +savetibet.nl +.savetibet.org +||savetibet.org +savetibet.ru +.savetibetstore.org +||savetibetstore.org +||saveuighur.org +savevid.com +.sbme.me +|http://sbme.me +.sbs.com.au/yourlanguage +.scasino.com +|http://www.sciencemag.org/content/344/6187/953 +.sciencenets.com +.scmp.com +||scmp.com +.scmpchinese.com +||scramble.io +||scribd.com +||scriptspot.com +||search.com +.searchtruth.com +||searx.me +||seattlefdc.com +.secretchina.com +||secretchina.com +||secretgarden.no +.secretsline.biz +||secretsline.biz +||secureservercdn.net +||securetunnel.com +securityinabox.org +|https://securityinabox.org +.securitykiss.com +||securitykiss.com +||seed4.me +||news.seehua.com +seesmic.com +||seevpn.com +||seezone.net +||sehuatang.net +sejie.com +.sendspace.com +||sensortower.com +sesawe.net +||sesawe.net +||sethwklein.net +||setn.com +.settv.com.tw +.sevenload.com +||sevenload.com +.sex.com +||sex.com +||sex3.com +||sex8.cc +.sexandsubmission.com +.sexbot.com +.sexhu.com +sexinsex.net +||sexinsex.net +.sextvx.com + +!--IP of SexInSex +67.220.91.15 +67.220.91.18 +67.220.91.23 + +|http://*.sf.net +.sfileydy.com +||sfshibao.com +.sftindia.org +.sftuk.org +||sftuk.org +||shadeyouvpn.com +shadow.ma +.shadowsky.xyz +.shadowsocks.asia +||www.shadowsocks.com +.shadowsocks.com +||shadowsocks.com.hk +.shadowsocks.org +||shadowsocks.org +|http://cn.shafaqna.com +||shahit.biz +.shambalapost.com +shapeservices.com +.sharebee.com +||sharecool.org +!--||sharkdolphin.com +.sharpdaily.hk +.sharpdaily.tw +.shat-tibet.com +sheikyermami.com +.shellfire.de +||shellfire.de +shenyun.com +shenyunperformingarts.org +||shenyunperformingarts.org +||shenyunshop.com +shenzhoufilm.com +||shenzhoufilm.com +||shenzhouzhengdao.org +.shiatv.net +.shicheng.org +shipcamouflage.com +.shireyishunjian.com +.shitaotv.org +||shixiao.org +||shizhao.org +shizhao.org +shkspr.mobi/dabr +||shodanhq.com +||shooshtime.com +.shop2000.com.tw +||shopee.tw +.shopping.com +.showhaotu.com +.showtime.jp +||showwe.tw +.shutterstock.com +||shutterstock.com +.shwchurch.org +||shwchurch.org +.shwchurch3.com +|http://shwchurch3.com +.siddharthasintent.org +||sidelinesnews.com +.sidelinessportseatery.com +||signal.org +.sijihuisuo.club +.sijihuisuo.com +.silkbook.com +||simbolostwitter.com +simplecd.org +||simplecd.org +||simplecd.me +simpleproductivityblog.com +bbs.sina.com/ +bbs.sina.com%2F +dailynews.sina.com/ +dailynews.sina.com%2F +home.sina.com +news.sina.com.hk +news.sinchew.com.my +.sinchew.com.my/node/ +.sinchew.com.my/taxonomy/term +.singaporepools.com.sg +||singaporepools.com.sg +.singfortibet.com +.singpao.com.hk +singtao.com +||singtao.com +news.singtao.ca +.singtaousa.com +||singtaousa.com +!--||cdp.sinica.edu.tw +sino-monthly.com +||sinoca.com +||sinocast.com +sinocism.com +sinomontreal.ca +.sinoants.com +||sinoants.com +||sinoinsider.com +.sinoquebec.com +.sierrafriendsoftibet.org +sis.xxx +||sis001.com +sis001.us +.site2unblock.com +.sitebro.tw +||sitekreator.com +||sitemaps.org +||sketchappsources.com +||skimtube.com +||lab.skk.moe +||skybet.com +|http://users.skynet.be/reves/tibethome.html +.skyking.com.tw +bbs.skykiwi.com +|http://www.skype.com/intl/ +|http://www.skype.com/zh-Hant +||skyvegas.com +.xskywalker.com +||xskywalker.com +||skyxvpn.com +.slaytizle.com +.sleazydream.com +||sleazyfork.org +||slheng.com +||slideshare.net +forum.slime.com.tw +.slinkset.com +||slickvpn.com +.slutload.com +||smartdnsproxy.com +.smarthide.com +||app.smartmailcloud.com +smchbooks.com +||smh.com.au +smhric.org +.smith.edu/dalailama +||smn.news +.smyxy.org +!--TODO-no-homepage +||sndcdn.com +sneakme.net +snowlionpub.com +||socialblade.com +.socks-proxy.net +||socks-proxy.net +.sockscap64.com +||sockslist.net +.socrec.org +|http://socrec.org +.sod.co.jp +.softether.org +||softether.org +.softether-download.com +||softether-download.com +||cdn.softlayer.net +||sogclub.com +sohcradio.com +||sohcradio.com +.sokmil.com +||sorting-algorithms.com +||soup.io +@@||static.soup.io +.sobees.com +||sobees.com +.softether.co.jp +||softwarebychuck.com +blog.sogoo.org +soh.tw +||soh.tw +sohfrance.org +||sohfrance.org +chinese.soifind.com +sokamonline.com +||solana.com +.solidaritetibet.org +.solidfiles.com +||somee.com +.songjianjun.com +||songjianjun.com +.sonidodelaesperanza.org +.sopcast.com +.sopcast.org +||nakedsecurity.sophos.com +||sos.org +||sosad.fun +bbs.sou-tong.org +.soubory.com +|http://soubory.com +.soul-plus.net +.soulcaliburhentai.net +||soulcaliburhentai.net +||soundcloud.com +!--|https://soundcloud.com/punkgod +.soundofhope.kr +soundofhope.org +||soundofhope.org +!--.sourceforge.net +!-|http://sourceforge.net +|http://sourceforge.net/p*/shadowsocksgui/ +.sourcewadio.com +||south-plus.org +||southmongolia.org +||southnews.com.tw +||sowers.org.hk +||spankbang.com +.spankingtube.com +.spankwire.com +||spatial.io +||spb.com +||speakerdeck.com +||speedcat.me +||speedify.com +||spencertipping.com +||spendee.com +||spicevpn.com +.spideroak.com +||spideroak.com +.spike.com +.spotflux.com +||spotflux.com +||spreaker.com +.spring4u.info +||spring4u.info +||springwood.me +||sproutcore.com +||squirrelvpn.com +.ss-link.com +||ss-link.com +.ssglobal.co/wp +|http://ssglobal.co +.ssglobal.me +.ssrshare.com +||ssrshare.com +!--|http://cdn.sstatic.net/ +||sstm.moe +||sstmlt.moe +sstmlt.net +||sstmlt.net +|http://stackoverflow.com/users/895245 +||standupfortibet.org +||standwithhk.org +stanford.edu/group/falun +.starfishfx.com +.starp2p.com +||starp2p.com +.startpage.com +||startpage.com +.startuplivingchina.com +|http://startuplivingchina.com +||static-economist.com +||stboy.net +||stc.com.sa +||steel-storm.com +.steganos.com +||steganos.com +.steganos.net +.stepchina.com +!--||stepmania.com +hd.stheadline.com/news/realtime +sthoo.com +||sthoo.com +.stickam.com +stickeraction.com/sesawe +.stileproject.com +||stitcher.com +.sto.cc +.stoporganharvesting.org +||storagenewsletter.com +.storm.mg +||storm.mg +.stoptibetcrisis.net +||stoptibetcrisis.net +||storj.io +.stormmediagroup.com +||stoweboyd.com +||straitstimes.com +stranabg.com +||straplessdildo.com +||streamable.com +||streamate.com +||streamingthe.net +streema.com/tv/NTDTV_Chinese +cn.streetvoice.com/article +cn.streetvoice.com/diary +tw.streetvoice.com +.strikingly.com +||strongvpn.com +.strongwindpress.com +||studentsforafreetibet.org +||stumbleupon.com +stupidvideos.com +||substack.com +||subhd.tv +.successfn.com +panamapapers.sueddeutsche.de +.sugarsync.com +||sugarsync.com +.sugobbs.com +||sugumiru18.com +||suissl.com +summify.com +.sumrando.com +||sumrando.com +sun1911.com +||sundayguardianlive.com +.sunporno.com +||sunmedia.ca +||sunporno.com +.sunskyforum.com +.sunta.com.tw +.sunvpn.net +.superfreevpn.com +.supervpn.net +||supervpn.net +.superzooi.com +|http://superzooi.com +.suppig.net +.suprememastertv.com +|http://suprememastertv.com +.surfeasy.com +||surfeasy.com +.surfeasy.com.au +|http://surfeasy.com.au +||surfshark.com +||surrenderat20.net +.svsfx.com +.swissinfo.ch +||swissinfo.ch +.swissvpn.net +||swissvpn.net +switchvpn.net +||switchvpn.net +.sydneytoday.com +||sydneytoday.com +.sylfoundation.org +||sylfoundation.org +||syncback.com +sysresccd.org +.sytes.net +blog.syx86.com/2009/09/puff +.szbbs.net +.szetowah.org.hk + +!--------------------TT------------------------- +||talkatone.com +||tanks.gg +||thehansindia.com +||rtm.tnt-ea.com +||tellapart.com +||threads.com +||tg-me.com +||twkan.com +||tunein.streamguys1.com +||tou.tv +||tinyurl.com +||textnow.com +||textnow.me +||token.im +||tokenlon.im +||tardigrade.io +||torrentgalaxy.to +||tomp3.cc +||tukaani.org +||thetatoken.org +||typeset.io +||thechasernews.co.uk +||hole.thu.monster +||thuhole.com +||t-g.com +.t35.com +.t66y.com +||t66y.com +||esg.t91y.com +.taa-usa.org +|http://taa-usa.org +.taaze.tw +||taaze.tw +|http://www.tablesgenerator.com/ +tabtter.jp +.taconet.com.tw +||taedp.org.tw +.tafm.org +tagwalk.com +||tagwalk.com +tahr.org.tw +.taipeisociety.org +||taipeisociety.org +||taipeitimes.com +||taisounds.com +.taiwanbible.com +.taiwandaily.net +||taiwandaily.net +.taiwandc.org +!--||taiwanembassy.org +||taiwanhot.net +.taiwanjustice.com +taiwankiss.com +taiwannation.com +taiwannation.com.tw +||taiwanncf.org.tw +||taiwannews.com.tw +|http://www.taiwanonline.cc/ +!--||taiwantoday.tw +taiwantp.net +||taiwantt.org.tw +taiwanus.net +.talk853.com +.talkboxapp.com +||talkboxapp.com +.talkcc.com +||talkcc.com +.talkonly.net +||talkonly.net +||tanc.org +.tangren.us +.taoism.net +|http://taoism.net +.tapatalk.com +||tapatalk.com +blog.taragana.com +||taup.net +.taweet.com +||taweet.com +.tbcollege.org +||tbcollege.org +.tbi.org.hk +.tbjyt.org +.tbrc.org +tbs-rainbow.org +.tbsec.org +||tbsec.org +tbskkinabalu.page.tl +.tbsn.org +||tbsn.org +.tbsseattle.org +.tbssqh.org +|http://tbssqh.org +tbswd.org +.tbtemple.org.uk +.tbthouston.org +.tccwonline.org +.tcewf.org +tchrd.org +tcnynj.org +||tcpspeed.co +.tcsofbc.org +.tdm.com.mo +teamamericany.com +||techspot.com +!--OVH +||techviz.net +||teck.in +.teeniefuck.net +teensinasia.com +||tehrantimes.com +.telecomspace.com +||telegraph.co.uk +.tenacy.com +||tenor.com +||tenzinpalmo.com +.tew.org +||tew.org +||tfc-taiwan.org.tw +||tfiflve.com +.thaicn.com +||theatlantic.com +||theatrum-belli.com +||cn.theaustralian.com.au +theblemish.com +||thebcomplex.com +||theblaze.com +.thebobs.com +||thebobs.com +.thechinabeat.org +||thechinacollection.org +|http://www.thechinastory.org/yearbooks/yearbook-2012/ +||theconversation.com +.thedalailamamovie.com +|http://thedalailamamovie.com +||thediplomat.com +||thedw.us +||theepochtimes.com +!--||thefreeland.club +||theguardian.com +||thegay.com +|http://thegioitinhoc.vn/ +.thegly.com +||thehindu.com +||thehun.net +.theinitium.com +||theinitium.com +.thenewslens.com +||thenewslens.com +.thepiratebay.org +||thepiratebay.org +!--||thepiratebay.se +.theporndude.com +||theporndude.com +||theportalwiki.com +||theprint.in +||threadreaderapp.com +therock.net.nz +||thesaturdaypaper.com.au +||thestandnews.com +thetibetcenter.org +thetibetconnection.org +.thetibetmuseum.org +.thetibetpost.com +||thetibetpost.com +thetrotskymovie.com +||thetvdb.com +||thewgo.org +||thewirechina.com +.theync.com +|http://theync.com +.thinkingtaiwan.com +||thinkingtaiwan.com +||thirdmill.org +||thisav.com +.thlib.org +||thomasbernhard.org +.thongdreams.com +||throughnightsfire.com +.thumbzilla.com +||thywords.com +tiananmenmother.org +.tiananmenduizhi.com +||tiananmenduizhi.com +||tiananmenuniv.com +||tiananmenuniv.net +||tiandixing.org +.tianhuayuan.com +.tianlawoffice.com +||tianti.io +tiantibooks.org +||tiantibooks.org +tianyantong.org.cn +.tianzhu.org +.tibet.at +tibet.ca +.tibet.com +||tibet.com +tibet.fr +.tibet.net +||tibet.net +||tibet.nu +.tibet.org +||tibet.org +||tibet.org.tw +||tibet.to +.tibet-envoy.eu +||tibet-envoy.eu +.tibet-foundation.org +.tibet-house-trust.co.uk +||tibet-initiative.de +.tibet-munich.de +.tibet3rdpole.org +|http://tibet3rdpole.org +tibetaction.net +||tibetaction.net +.tibetaid.org +tibetalk.com +.tibetan.fr +tibetan-alliance.org +.tibetanarts.org +.tibetanbuddhistinstitute.org +||tibetanbuddhistinstitute.org +||tibetancommunity.org +||tibetanentrepreneurs.org +||tibetanhealth.org +.tibetanjournal.com +.tibetanlanguage.org +.tibetanliberation.org +||tibetanliberation.org +.tibetcollection.com +.tibetanaidproject.org +.tibetancommunityuk.net +|http://tibetancommunityuk.net +tibetanculture.org +tibetanfeministcollective.org +.tibetanpaintings.com +.tibetanphotoproject.com +.tibetanpoliticalreview.org +.tibetanreview.net +|http://tibetansports.org +.tibetanwomen.org +|http://tibetanwomen.org +.tibetanyouth.org +.tibetanyouthcongress.org +||tibetanyouthcongress.org +.tibetcharity.dk +tibetcharity.in +.tibetchild.org +.tibetcity.com +||tibetcorps.org +||tibetexpress.net +||tibetfocus.com +||tibetfund.org +.tibetgermany.com +||tibetgermany.de +.tibethaus.com +.tibetheritagefund.org +||tibethouse.jp +||tibethouse.org +||tibethouse.us +.tibetinfonet.net +.tibetjustice.org +.tibetkomite.dk +||tibetmuseum.org +||tibetnetwork.org +||tibetoffice.ch +tibetoffice.eu +||tibetoffice.org +||tibetonline.com +||tibetoffice.com.au +||tibetonline.tv +||tibetoralhistory.org +||tibetpolicy.eu +||tibetrelieffund.co.uk +||tibetsociety.com +||tibetsun.com +||tibetsupportgroup.org +||tibetswiss.ch +||tibettelegraph.com +||tibettimes.net +||tibettruth.com +||tibetwrites.org +.ticket.com.tw +.tigervpn.com +||tigervpn.com +.timdir.com +|http://timdir.com +.time.com +|http://time.com +!--.time.com/time/time100/leaders/profile/rebel +!--.time.com/time/specials/packages/article/0,28804 +!--.time.com/time/magazine +||timesnownews.com +.timsah.com +||timtales.com +||blog.tiney.com +||tingtalk.me +.tiny.cc +||tiny.cc +||tinychat.com +||tinypaste.com +||tipas.net +.tistory.com +||tkcs-collins.com +.tmagazine.com +||tmagazine.com +|http://tmi.me +.tmpp.org +|http://tmpp.org +.tnaflix.com +||tnaflix.com +.tnp.org +|http://tnp.org +.to-porno.com +||to-porno.com +||togetter.com +.tokyo-247.com +.tokyo-hot.com +||tokyo-porn-tube.com +||tokyocn.com +tw.tomonews.net +.tongil.or.kr +tonyyan.net +toonel.net +top81.ws +.topnews.in +.toppornsites.com +|http://toppornsites.com +||toptoon.net +.torguard.net +||torguard.net +||top.tv +.topshareware.com +.topsy.com +||topsy.com +||toptip.ca +tora.to +.torcn.com +||torlock.com +.torproject.org +||torproject.org +||torrentkitty.tv +torrentprivacy.com +||torrentprivacy.com +|http://torrentproject.se +||torrenty.org +||tortoisesvn.net +||torvpn.com +||totalvpn.com +.toutiaoabc.com +towngain.com +toypark.in +toytractorshow.com +.tparents.org +.tpi.org.tw +||tpi.org.tw +||tradingview.com +||transparency.org +||treemall.com.tw +trendsmap.com +||trendsmap.com +.trimondi.de/SDLE +.trouw.nl +||trouw.nl +.trt.net.tr +||trt.net.tr +trtc.com.tw +.truebuddha-md.org +||truebuddha-md.org +trulyergonomic.com +||truthsocial.com +.truveo.com +.tsctv.net +.tsemtulku.com +tsquare.tv +.tsu.org.tw +tsunagarumon.com +!--|http://www.tsuru-bird.net/ +||tt1069.com +.tttan.com +||tttan.com +||ttv.com.tw +tu8964.com +.tubaholic.com +.tube.com +tube8.com +||tube8.com +.tube911.com +||tube911.com +.tubecup.com +.tubegals.com +.tubeislam.com +|http://tubeislam.com +.tubestack.com +||tubewolf.com +.tuibeitu.net +.tuidang.org +||tuidang.org +.tuidang.se +.tumutanzi.com +|http://tumutanzi.com +||tumview.com +.tunein.com +|http://tunein.com +||tunnelbear.com +||tunnelblick.net +.tunnelr.com +||tunnelr.com +||tunsafe.com +tuitwit.com +.turansam.org +.turbobit.net +||turbobit.net +.turbohide.com +||turbohide.com +||turkistantimes.com +.tushycash.com +|http://tushycash.com +.tuvpn.com +||tuvpn.com +|http://tuzaijidi.com +|http://*.tuzaijidi.com +.tw01.org +|http://tw01.org +||use.typekit.net + +!---Tumblr--- +.tumblr.com +||tumblr.com +!--@@||assets.tumblr.com +!--@@||data.tumblr.com +!--@@||media.tumblr.com +!--@@||static.tumblr.com +!--@@||www.tumblr.com +||lecloud.net +||slutmoonbeam.com +|http://blog.soylent.com + +.tv.com +|http://tv.com +tvants.com +||forum.tvb.com +||inews-api.tvb.com +news.tvbs.com.tw +.tvboxnow.com +||tvboxnow.com +tvider.com +.tvmost.com.hk +.tvplayvideos.com +||tvunetworks.com +.tw-blog.com +|https://tw-blog.com +.tw-npo.org +.twaitter.com +twapperkeeper.com +||twapperkeeper.com +||twaud.io +.twaud.io +.twavi.com +twbbs.org +||twblogger.com +tweepmag.com +.tweepml.org +||tweepml.org +.tweetbackup.com +||tweetbackup.com +tweetboard.com +||tweetboard.com +.tweetcs.com +|http://tweetcs.com +|http://deck.ly +!-- Operation discontinued +!--||tweete.net +!--m.tweete.net +||tweetedtimes.com +!-- Operation discontinued +!--tweetmeme.com +tweetphoto.com +||tweetphoto.com +tweetree.com +||tweetree.com +.tweettunnel.com +||tweettunnel.com +||tweetwally.com +tweetymail.com +||twelve.today +.tweez.net +|http://tweez.net +||twftp.org +||twgreatdaily.com +twibase.com +.twibble.de +||twibble.de +twibbon.com +||twibs.com +.twicountry.org +|http://twicountry.org +twicsy.com +.twiends.com +|http://twiends.com +.twifan.com +|http://twifan.com +twiffo.com +||twiffo.com +.twilightsex.com +twilog.org +twimbow.com +twipple.jp +||twipple.jp +||twip.me +twishort.com +||twishort.com +||twister.net.co +twisternow.com +twistory.net +||twiggit.org +twitgoo.com +twitiq.com +||twitiq.com +.twitlonger.com +||twitlonger.com +|http://tl.gd/ +twitmania.com +twitoaster.com +||twitoaster.com +||twitonmsn.com +!--Same IP +.twitstat.com +||twitstat.com +||tweepguide.com +|http://twt.tl +twittbot.net +||ads-twitter.com +||twttr.com +||twitter4j.org +.twittercounter.com +||twittercounter.com +twitterfeed.com +.twittergadget.com +||twittergadget.com +.twitterkr.com +||twitterkr.com +||twittermail.com +||twitterrific.com +twittertim.es +||twittertim.es +twitthat.com +||twitturk.com +.twitturly.com +||twitturly.com +.twitzap.com +twiyia.com +.twtkr.com +|http://twtkr.com +.twnorth.org.tw +||twreporter.org +twskype.com +twtrland.com +twurl.nl +.txxx.com +.tycool.com +||tycool.com + +!--typepad +||typepad.com +@@||www.typepad.com +@@||static.typepad.com +||blog.expofutures.com +||contests.twilio.com +!-lawprofessors.typepad.com/china_law_prof +||typora.io + +!--------------------UU------------------------- +||udomain.hk +||upbit.com +||demo.unlock-music.dev +.u9un.com +||u9un.com +.ubddns.org +|http://ubddns.org +||uberproxy.net +.uc-japan.org +||uc-japan.org +.srcf.ucam.org/salon/ +|http://china.ucanews.com/ +|http://hum*.uchicago.edu/faculty/ywang/history +||uderzo.it +.udn.com +||udn.com +||udn.com.tw +udnbkk.com/bbs +||uforadio.com.tw +ufreevpn.com +.ugo.com +!--ghs +||uhdwallpapers.org +||uhrp.org +.uighur.nl +||uighur.nl +uighurbiz.net +.ulike.net +ukcdp.co.uk +||ultrasurf.us +||ultravpn.com +||ultravpn.fr +ultraxs.com +umich.edu/~falun +||unblock.cn.com +.unblocker.yt +unblock-us.com +||unblock-us.com +.unblockdmm.com +|http://unblockdmm.com +||unblocksit.es +uncyclomedia.org +.uncyclopedia.hk/wiki +|http://uncyclopedia.hk +!--uncyclopedia.info +|http://uncyclopedia.tw +underwoodammo.com +||underwoodammo.com +||unholyknight.com +.uni.cc +||cldr.unicode.org +.unification.net +.unification.org.tw +||unirule.cloud +.unix100.com +||unknownspace.org +.unodedos.com +unpo.org +||unstable.icu +||unwire.hk +||uocn.org +tor.updatestar.com +||upghsbc.com +.upholdjustice.org +uploaded.net/file +|http://uploaded.net/file +|http://uploaded.to/file +.uploadstation.com/file +.upmedia.mg +||upmedia.mg +.upornia.com +|http://upornia.com +||uproxy.org +||uptodown.com +.upwill.org +ur7s.com +||urbandictionary.com +||urbansurvival.com +myshare.url.com.tw/ +||urlborg.com +||urlparser.com +us.to +||usacn.com +.usaip.eu +||usaip.eu +||uscnpm.org +||uscardforum.com +||usma.edu +.usocctn.com +||ustibetcommittee.org +.ustream.tv +||ustream.tv +usus.cc +.utopianpal.com +||utopianpal.com +||uujiasu.com +.uvwxyz.xyz +||uvwxyz.xyz +.uwants.com +||uwants.com +.uwants.net +uyghur.co.uk +||uyghur-j.org +||uyghuraa.org +||uyghuramerican.org +||uyghurbiz.org +||uyghurcongress.org +||uyghurpen.org +||uyghurstudies.org +||uyghurtribunal.com +uygur.org +|http://uymaarip.com/ + +!--------------------VV------------------------- +||vilanet.me +||vewas.net +||v2.help +||vocaroo.com +||vern.cc +||v2fly.org +.v2ray.com +||v2ray.com +||v2raycn.com +||valeursactuelles.com +.van001.com +.van698.com +.vanemu.cn +.vanilla-jp.com +.vanpeople.com +||vansky.com +||vaticannews.va +||vcf-online.org +||vcfbuilder.org +.vegasred.com +.velkaepocha.sk +.venbbs.com +.venchina.com +.venetianmacao.com +||venetianmacao.com +veoh.com +||vercel.app +mysite.verizon.net +vermonttibet.org +||verybs.com +.vft.com.tw +.viber.com +||viber.com +.vica.info +.victimsofcommunism.org +||victimsofcommunism.org +||vid.me +||vidble.com +videobam.com +||videobam.com +.videodetective.com +.videomega.tv +||videomega.tv +.videomo.com +videopediaworld.com +.videopress.com +.vidinfo.org/video +vietdaikynguyen.com +.vijayatemple.org +||vilavpn.com +vimeo.com +||vimeo.com +||vimperator.org +||vincnd.com +||vinniev.com +|http://www.lib.virginia.edu/area-studies/Tibet/tibet.html +.virtualrealporn.com +||virtualrealporn.com +visibletweets.com +||viu.com +.vivahentai4u.net + +!--apex not blocked, adding to reduce complexity +||vivaldi.com + +.vivatube.com +.vivthomas.com +||vivthomas.com +.vjav.com +||vjav.com +.vjmedia.com.hk +.vllcs.org +|http://vllcs.org +||vmixcore.com +||vnet.link +.vocativ.com +vocn.tv +||vocus.cc +||voicettank.org +.vot.org +||vot.org +.vovo2000.com +|http://vovo2000.com +.voxer.com +||voxer.com +.voy.com +||vpn.ac +||vpn.net +.vpn4all.com +||vpn4all.com +.vpnaccount.org +|http://vpnaccount.org +.vpnaccounts.com +||vpnaccounts.com +.vpncomparison.org +.vpncup.com +||vpncup.com +vpnbook.com +.vpncoupons.com +|http://vpncoupons.com +.vpndada.com +||vpndada.com +.vpnfan.com +vpnfire.com +.vpnforgame.net +||vpnforgame.net +||vpngate.jp +.vpngate.net +||vpngate.net +.vpngratis.net +vpnhq.com +||vpnhub.com +.vpnmaster.com +||vpnmaster.com +.vpnmentor.com +||vpnmentor.com +.vpninja.net +||vpninja.net +.vpnintouch.com +vpnjack.com +||vpnjack.com +.vpnpick.com +||vpnpick.com +||vpnpop.com +||vpnpronet.com +||vpnproxymaster.com +.vpnreactor.com +||vpnreactor.com +||vpnreviewz.com +.vpnsecure.me +||vpnsecure.me +.vpnshazam.com +||vpnshazam.com +.vpnshieldapp.com +||vpnshieldapp.com +.vpnsp.com +.vpntraffic.com +.vpntunnel.com +||vpntunnel.com +.vpnuk.info +||vpnuk.info +||vpnunlimitedapp.com +.vpnvip.com +||vpnvip.com +.vpnworldwide.com +.vporn.com +||vporn.com +.vpser.net +@@||vpser.net +vraiesagesse.net +||vrchat.com +.vrmtr.com +||vrporn.com +||vtunnel.com +||vuku.cc + +!--------------------WW------------------------- +||wxw.moe +||wxw.cat +||walletconnect.com +|https://w3s.link/ipfs +||work2icu.org +||wikiless.funami.tech +lists.w3.org/archives/public +||waffle1999.com +.wahas.com +waikeung.org/php_wind +||wainao.me +||wallmama.com +||wallpapercasa.com +.wallproxy.com +@@||wallproxy.com.cn +||wallsttv.com +||waltermartin.com +||waltermartin.org +||www.wan-press.org +||wanderinghorse.net +||wangafu.net +||wangjinbo.org +.wangjinbo.org +wanglixiong.com +.wango.org +||wango.org +wangruoshui.net +||want-daily.com +wapedia.mobi/zhsimp +||warroom.org +||waselpro.com +||watchinese.com +||watchout.tw +.wattpad.com +||wattpad.com +.watch8x.com +||watchmygf.net +||wav.tv +||waybig.com +||wd.bible +.wdf5.com +||wealth.com.tw +.wearehairy.com +.wearn.com +||wearn.com +|http://hkcoc.weather.com.hk +||hudatoriq.web.id +||web2project.net +webbang.net +.webevader.org +.webfreer.com +weblagu.com +.webjb.org +.webrush.net +webs-tv.net +.websitepulse.com/help/testtools.china-test +|http://www.websnapr.com +.webwarper.net +|http://webwarper.net +webworkerdaily.com +||wechatlawsuit.com +||wefightcensorship.org +.wefong.com +weiboleak.com +.weihuo.org +||weijingsheng.org +.weiming.info +||weiming.info +weiquanwang.org +|http://weisuo.ws +.welovecock.com +||welt.de +.wemigrate.org +|http://wemigrate.org +wengewang.com +||wengewang.org +.wenxuecity.com +||wenxuecity.com +.wenyunchao.com +||wenyunchao.com +.westca.com +||westca.com +||westernwolves.com +.westkit.net +||westpoint.edu +.westernshugdensociety.org +wetpussygames.com +.wetplace.com +||wezone.net +.wforum.com +||wforum.com/ +.whatblocked.com +||whatblocked.com +||wheelockslatin.com +.whippedass.com +!--|http://who.is/ +.whoer.net +||whoer.net +whotalking.com +whylover.com +||whyx.org +||wikileaks.ch +||wikileaks.com +||wikileaks.de +||wikileaks.eu +||wikileaks.lu +.wikileaks.org +||wikileaks.org +||wikileaks.pl +.wikileaks-forum.com +||wilsoncenter.org +.williamhill.com +||collateralmurder.com +||collateralmurder.org +wikilivres.info/wiki/%E9%9B%B6%E5%85%AB%E5%AE%AA%E7%AB%A0 +||wikimapia.org +.wikiwand.com +||wikiwand.com +||casino.williamhill.com +||sports.williamhill.com +||vegas.williamhill.com +||willw.net +.windscribe.com +||windscribe.com +||wingy.site +.winning11.com +||wionews.com +||wiredbytes.com +||wiredpen.com +||wireguard.com +!--||wireshark.org +.wisdompubs.org +.wisevid.com +||wisevid.com +||whispersystems.org +.witnessleeteaching.com +||witopia.net +.wjbk.org +||wjbk.org +||wmflabs.org +||wn.com +||wnacg.com +||wnacg.org +||wo.tc +||woeser.com +||wokar.org +||wolfax.com +||wombo.ai +||woolyss.com +||woopie.jp +||woopie.tv +||workatruna.com +||workerempowerment.org +.worldcat.org +worldjournal.com +.worldvpn.net +||worldvpn.net + +||videopress.com +.wordpress.com +|http://*.wordpress.com +||chenshan20042005.wordpress.com +||chinaview.wordpress.com +||cnbbnews.wordpress.com +||freedominfonetweb.wordpress.com +||hka8964.wordpress.com +||hkanews.wordpress.com +||hqsbnet.wordpress.com +||hqsbonline.wordpress.com +||investigating.wordpress.com +||jobnewera.wordpress.com +||matthewdgreen.wordpress.com +||minghuiyw.wordpress.com +||wo3ttt.wordpress.com +||sujiatun.wordpress.com +||xijie.wordpress.com +||ifreechina.wordpress.com +||wp.com + +!-||wormsculptor.com +.wow.com +||wowporn.com +||wowgirls.com +.wowrk.com +.woyaolian.org +|http://woyaolian.org +.wpoforum.com +||wpoforum.com +wrchina.org +wretch.cc +||writesonic.com +.wsj.com +||wsj.com +.wsj.net +||wsj.net +.wtbn.org +.wtfpeople.com +wuerkaixi.com +||wufafangwen.com +||wufi.org.tw +wujie.net +wujieliulan.com +||wujieliulan.com +||wuw.red +.wwitv.com +||wwitv.com +wzyboy.im/post/160 + +!--------------------XX------------------------- +||www.xicons.org +||x.ai +||xt.com +||xt.pub +||x.co +.x-berry.com +||x-berry.com +||x-art.com +||x-wall.org +||x3guide.com +xanga.com +||xbabe.com +.xbookcn.com +||xbookcn.com +||xcafe.in +||xcity.jp +.xcritic.com +||xerotica.com +destiny.xfiles.to/ubbthreads +||xfxssr.me +.xgmyd.com +||xgmyd.com +xhamster.com +||xhamster.com +.xianba.net +.xianjian.tw +|http://xianjian.tw +.xiaobaiwu.com +.xiaochuncnjp.com +.xiaohexie.com +||xiaolan.me +||xiaoma.org +||xiaohexie.com +||xiaxiaoqiang.net +xiezhua.com +.xihua.es +forum.xinbao.de/forum +.xing.com +|http://xing.com +||xinjiangpolicefiles.org +.xinmiao.com.hk +||xinmiao.com.hk +xinsheng.net +xinshijue.com +.xiongpian.com +.xiuren.org +xizang-zhiye.org +xjp.cc +||xjp.cc +||xjtravelguide.com +||xml-training-guide.com +xmovies.com +||xnxx.com +!--||xnxx-cdn.com +xpdo.net +||xpud.org +.xrentdvd.com +||xtube.com +||xuchao.org +xuchao.net +||xuchao.net +xvideo.cc +.xvideos.com +||xvideos.com +||xvideos-cdn.com +||xvideos.es +||xvbelink.com +||xvinlink.com +||xsden.info +.xxbbx.com +.xxlmovies.com +||xxx.com +.xxx.xxx +|http://xxx.xxx +.xxxfuckmom.com +||xxxx.com.au +.xxxymovies.com +|http://xxxymovies.com +xys.org +xysblogs.org + +!--------------------YY------------------------- +||yangzhi.org +||storage.yandex.net +||y2mate.com +||yadi.sk +||yakbutterblues.com +||yam.com +||yam.org.tw +||yande.re +||disk.yandex.com +||disk.yandex.ru +.yanghengjun.com +.yasni.co.uk +||yasni.co.uk +||yasukuni.or.jp +.yayabay.com/forum +||news.ycombinator.com +.ydy.com +.yeahteentube.com +||yeahteentube.com +||yecl.net +||yeelou.com +||yeeyi.com +yegle.net +||yegle.net +.yes.xxx +||yes123.com.tw +||yesasia.com +||yesasia.com.hk +.yes-news.com +|http://yes-news.com +.yespornplease.com +||yespornplease.com +|http://yeyeclub.com +!--yfrog.com +||yhcw.net +.yibada.com +||yibaochina.com +.yidio.com +||yidio.com +||yigeni.com +yilubbs.com +||s.yimg.com +.yipub.com +||yipub.com +yinlei.org/mt +.yizhihongxing.com +||yizhihongxing.com +.yobt.com +.yobt.tv +||yobt.tv +.yogichen.org +||yogichen.org +.yolasite.com +.yomiuri.co.jp +yong.hu +.yorkbbs.ca +||you.com +||youxu.info +.youjizz.com +||youjizz.com +.youmaker.com +||youmaker.com +.youngpornvideos.com +youngspiration.hk +.youpai.org +||youpai.org +.your-freedom.net +||yourepeat.com +.yousendit.com +||yousendit.com +.youthnetradio.org/tmit/forum +blog.youthwant.com.tw +me.youthwant.com.tw +share.youthwant.com.tw +topic.youthwant.com.tw +.youporn.com +||youporn.com +.youporngay.com +||youporngay.com +.yourlisten.com +||yourlisten.com +.yourlust.com +||yourlust.com +youversion.com +||youversion.com +ytht.net +yuanming.net +.yuanzhengtang.org +.yulghun.com +||yulghun.com +||yunchao.net +||yunomi.tokyo +.yuvutu.com +||yvesgeleyn.com +.ywpw.com/forums/history/post/A0/p0/html/227 +yx51.net +.yyii.org +||yyii.org +||yyjlymb.xyz +||yysub.net +.yzzk.com +||yzzk.com + +!--------------------ZZ------------------------- +||z-library.sk +||z-lib.fm +||z-lib.gd +||z-lib.gl +||z-lib.fo +||zodgame.xyz +||zhongzidi.com +||zooqle.com +||z-lib.io +||z-lib.org +zacebook.com +.zalmos.com +||zalmos.com +||zaobao.com.sg +||zdnet.com.tw +.zello.com +||zello.com +.zengjinyan.org +.zenmate.com +||zenmate.com +||zenmate.com.ru +||zerohedge.com +||zeronet.io +!--www.zfreet.com/post/usejump-browns.html +.zfreet.com +.zhangboli.net +||zhangtianliang.com +||zhanlve.org +zhenghui.org +.zhengjian.org +||zhengjian.org +zhengwunet.org +|http://zhenxiang.biz +zhongguo.ca +|http://zhongguorenquan.org +zhongguotese.net +||zhongguotese.net +.zhoushuguang.com +.zhuanxing.cn +||zhuatieba.com +zhuichaguoji.org +||zhuichaguoji.org +||zi.media +|http://book.zi5.me +.ziddu.com/download +||zillionk.com +.zinio.com +||zinio.com +.ziporn.com +.zippyshare.com +realforum.zkiz.com +!--||zlib.net +||zmedia.com.tw +||zmw.cn +.zodgame.us +zomobo.net +.zonaeuropa.com +||zonaeuropa.com +||zonghexinwen.com +||zoogvpn.com +||zootool.com +.zoozle.net +||zophar.net +writer.zoho.com +||zorrovpn.com +||zpn.im +||zspeeder.me +.zsrhao.com +.zuo.la +||zuo.la +||zuobiao.me +.zuola.com +||zuola.com +||zvereff.com +||zyxel.com +.zzcartoon.com +!##############General List End################# + +!###########Supplemental List Start############# +!#############Supplemental List End############# + +!################Whitelist Start################ +@@||www.ettoday.net + +@@||aliyun.com +@@||baidu.com +@@||chinaso.com +@@||chinaz.com +@@|http://nrch.culture.tw/ +@@||i.pki.goog +!---Some are powered by GuXiang (BGP), please comment off if +!---you encounter connectivity issues. +@@||adservice.google.com +!--ISP cache works sometimes, verified at drpeng + gehua. +@@||dl.google.com +!--@@||kh.google.com +!--@@||khm.google.com +!--@@||khm0.google.com +!--@@||khm1.google.com +!--@@||khm2.google.com +!--@@||khm3.google.com +!--@@||khmdb.google.com +@@||tools.google.com +@@||clientservices.googleapis.com +@@||fonts.googleapis.com +!--@@||khm.googleapis.com +!--@@||khm0.googleapis.com +!--@@||khm1.googleapis.com +!--@@||khm2.googleapis.com +!--@@||khm3.googleapis.com +!--@@||khmdb.googleapis.com +@@||update.googleapis.com +@@||safebrowsing.googleapis.com +@@||connectivitycheck.gstatic.com +@@||csi.gstatic.com +@@||fonts.gstatic.com +@@||ssl.gstatic.com +@@||haosou.com +@@||ip.cn +@@||jike.com +@@||translate.google.cn +@@|http://www.google.cn/maps +@@||http2.golang.org +@@||gov.cn +@@||ocsp.pki.goog +@@||qq.com +@@||sina.cn +@@||sina.com.cn +@@||sogou.com +@@||so.com +@@||soso.com +@@||uluai.com.cn +@@||weibo.com +@@||yahoo.cn +@@||youdao.com +@@||zhongsou.com +@@|http://ime.baidu.jp +!################Whitelist End################## +!---------------------EOF----------------------- diff --git a/dns-server.service b/dns-server.service new file mode 100644 index 0000000..cc2d872 --- /dev/null +++ b/dns-server.service @@ -0,0 +1,24 @@ +[Unit] +Description=Monitor Agent (Binary Service) +After=network.target +Wants=network.target + +[Service] +Type=forking +User=root +Group=root +ExecStart=/root/dns/start.sh start +ExecStop=/root/dns/start.sh stop +WorkingDirectory=/root/dns +Restart=always +RestartSec=3 +StartLimitInterval=60s +StartLimitBurst=5 +KillSignal=SIGTERM +TimeoutStopSec=10 +PrivateTmp=true +ProtectSystem=strict +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target diff --git a/dns/cache.go b/dns/cache.go index d82c28d..19c11fd 100644 --- a/dns/cache.go +++ b/dns/cache.go @@ -1,6 +1,10 @@ package dns import ( + "encoding/json" + "io/ioutil" + "math" + "os" "sync" "time" @@ -9,148 +13,406 @@ import ( // DNSCacheItem 表示缓存中的DNS响应项 type DNSCacheItem struct { - Response *dns.Msg // DNS响应消息 - Expiry time.Time // 过期时间 - HasDNSSEC bool // 是否包含DNSSEC记录 + Response *dns.Msg // DNS响应消息 + Expiry time.Time // 过期时间 + HasDNSSEC bool // 是否包含DNSSEC记录 + Size int // 缓存项大小(字节) +} + +// SerializableDNSCacheItem 用于JSON序列化的缓存项结构 +type SerializableDNSCacheItem struct { + ResponseBytes []byte `json:"responseBytes"` // 二进制DNS响应 + Expiry int64 `json:"expiry"` // 过期时间(纳秒) + HasDNSSEC bool `json:"hasDNSSEC"` // 是否包含DNSSEC记录 + Size int `json:"size"` // 缓存项大小(字节) +} + +// SerializableDNSCache 可序列化的缓存结构 +type SerializableDNSCache struct { + Items map[string]*SerializableDNSCacheItem `json:"items"` // 缓存项 + TTL int64 `json:"ttl"` // 默认TTL(纳秒) + MaxSize int `json:"maxSize"` // 最大缓存大小 + CacheMode string `json:"cacheMode"` // 缓存模式 + CacheFilePath string `json:"cacheFilePath"` // 缓存文件路径 } // DNSCache DNS缓存结构 type DNSCache struct { - cache map[string]*DNSCacheItem // 缓存映射表 - mutex sync.RWMutex // 读写锁,保护缓存 - defaultTTL time.Duration // 默认缓存TTL + cache map[string]*LRUNode // 缓存映射表,直接存储链表节点 + mutex sync.RWMutex // 读写锁,保护缓存 + ttl time.Duration // 默认缓存TTL + maxSize int // 最大缓存条目数 + cacheSize int64 // 当前缓存大小(字节) + maxCacheSize int64 // 最大缓存大小(字节) + cacheMode string // 缓存模式 + cacheFilePath string // 缓存文件路径 + saveInterval time.Duration // 保存间隔 + saveMutex sync.Mutex // 保存互斥锁 + maxCacheTTL time.Duration // 最大缓存TTL + minCacheTTL time.Duration // 最小缓存TTL + saveStopCh chan struct{} // 保存循环停止通道 + saveRunning bool // 保存循环是否运行 + saveLoopMutex sync.Mutex // 保护保存循环状态的互斥锁 + // 双向链表头和尾指针,用于LRU淘汰 + head *LRUNode // 头指针,指向最久未使用的节点 + tail *LRUNode // 尾指针,指向最近使用的节点 + // 缓存变化跟踪,用于智能保存 + changeCount int // 缓存变化次数 + lastSaveCacheSize int64 // 上次保存时的缓存大小 + lastSaveItemCount int // 上次保存时的缓存项数量 + lastSaveTime time.Time // 上次保存时间 + minSaveInterval time.Duration // 最小保存间隔,避免过于频繁的保存 +} + +// LRUNode 双向链表节点,用于LRU缓存 +type LRUNode struct { + key string + value *DNSCacheItem + prev *LRUNode + next *LRUNode } // NewDNSCache 创建新的DNS缓存实例 -func NewDNSCache(defaultTTL time.Duration) *DNSCache { +func NewDNSCache(defaultTTL time.Duration, cacheMode string, cacheSizeMB int, cacheFilePath string, saveInterval time.Duration, maxCacheTTL, minCacheTTL time.Duration) *DNSCache { + // 计算最大缓存大小(字节) + maxCacheSize := int64(cacheSizeMB) * 1024 * 1024 + cache := &DNSCache{ - cache: make(map[string]*DNSCacheItem), - defaultTTL: defaultTTL, + cache: make(map[string]*LRUNode), + ttl: defaultTTL, + maxSize: 10000, // 默认最大缓存10000条记录 + cacheSize: 0, + maxCacheSize: maxCacheSize, + cacheMode: cacheMode, + cacheFilePath: cacheFilePath, + saveInterval: saveInterval, + maxCacheTTL: maxCacheTTL, + minCacheTTL: minCacheTTL, + saveStopCh: make(chan struct{}), + saveRunning: false, + head: nil, + tail: nil, + changeCount: 0, + lastSaveCacheSize: 0, + lastSaveItemCount: 0, + lastSaveTime: time.Now(), + minSaveInterval: 30 * time.Second, // 最小保存间隔为30秒,避免过于频繁的保存 + } + + // 加载现有缓存(如果存在) + if cacheMode == "file" { + cache.LoadFromFile() } // 启动缓存清理协程 go cache.startCleanupLoop() + // 启动定期保存协程(如果是文件缓存) + if cacheMode == "file" { + go cache.startSaveLoop() + } + return cache } +// addNodeToTail 将节点添加到链表尾部(表示最近使用) +func (c *DNSCache) addNodeToTail(node *LRUNode) { + if c.tail == nil { + // 链表为空 + c.head = node + c.tail = node + } else { + // 添加到尾部 + node.prev = c.tail + c.tail.next = node + c.tail = node + } +} + +// removeNode 从链表中移除指定节点 +func (c *DNSCache) removeNode(node *LRUNode) { + if node.prev != nil { + node.prev.next = node.next + } else { + // 移除的是头节点 + c.head = node.next + } + + if node.next != nil { + node.next.prev = node.prev + } else { + // 移除的是尾节点 + c.tail = node.prev + } + + // 清空节点的前后指针 + node.prev = nil + node.next = nil +} + +// moveNodeToTail 将节点移动到链表尾部(表示最近使用) +func (c *DNSCache) moveNodeToTail(node *LRUNode) { + // 如果已经是尾节点,不需要移动 + if node == c.tail { + return + } + + // 从链表中移除节点 + c.removeNode(node) + // 重新添加到尾部 + c.addNodeToTail(node) +} + // cacheKey 生成缓存键 func cacheKey(qName string, qType uint16) string { return qName + "|" + dns.TypeToString[qType] } +// calculateItemSize 计算缓存项大小 +func calculateItemSize(item *DNSCacheItem) int { + // 使用更高效的方式估算缓存项大小 + // 避免使用json.Marshal和rr.String(),因为它们在高频调用时会消耗大量CPU资源 + size := 0 + + // 估算Response大小 + if item.Response != nil { + // 粗略估算DNS消息大小 + // 头部大小约12字节 + size += 12 + + // 问题部分 + for _, q := range item.Response.Question { + size += len(q.Name) + 4 // 域名长度 + 类型(2) + 类(2) + } + + // 高效估算资源记录大小,避免调用rr.String() + estimateRRSize := func(rr dns.RR) int { + rrSize := len(rr.Header().Name) + 10 // 域名 + 类型(2) + 类(2) + TTL(4) + 长度(2) + + switch rr.Header().Rrtype { + case dns.TypeA: + rrSize += 4 // IPv4地址 + case dns.TypeAAAA: + rrSize += 16 // IPv6地址 + case dns.TypeCNAME, dns.TypePTR, dns.TypeNS: + // 对于CNAME、PTR、NS记录,需要估算目标域名长度 + if cname, ok := rr.(*dns.CNAME); ok { + rrSize += len(cname.Target) + } else if ptr, ok := rr.(*dns.PTR); ok { + rrSize += len(ptr.Ptr) + } else if ns, ok := rr.(*dns.NS); ok { + rrSize += len(ns.Ns) + } else { + // 默认估算 + rrSize += 30 + } + case dns.TypeMX: + // MX记录:优先级(2) + 目标域名 + rrSize += 2 + 30 // 默认30字节目标域名 + case dns.TypeTXT: + // TXT记录:文本长度 + rrSize += 50 // 默认50字节文本 + case dns.TypeSRV: + // SRV记录:优先级(2) + 权重(2) + 端口(2) + 目标域名 + rrSize += 6 + 30 // 默认30字节目标域名 + case dns.TypeSOA: + // SOA记录:主NS + 管理员邮箱 + 序列号(4) + 刷新时间(4) + 重试时间(4) + 过期时间(4) + 最小TTL(4) + rrSize += 100 // 默认100字节 + default: + // 其他类型记录,使用默认估算 + rrSize += 50 + } + + return rrSize + } + + // 回答部分 + for _, rr := range item.Response.Answer { + size += estimateRRSize(rr) + } + + // 授权部分 + for _, rr := range item.Response.Ns { + size += estimateRRSize(rr) + } + + // 附加部分 + for _, rr := range item.Response.Extra { + if rr.Header().Rrtype == dns.TypeOPT { + // OPT记录大小约为40字节(EDNS0) + size += 40 + } else { + size += estimateRRSize(rr) + } + } + } + + // 其他字段大小 + size += 8 // Expiry + size += 1 // HasDNSSEC + + return size +} + // hasDNSSECRecords 检查响应是否包含DNSSEC记录 func hasDNSSECRecords(response *dns.Msg) bool { - // 检查响应中是否包含DNSSEC相关记录(DNSKEY、RRSIG、DS、NSEC、NSEC3等) + // 直接在循环中检查RR类型,避免创建匿名函数的开销 + + // 检查回答部分 for _, rr := range response.Answer { - if _, ok := rr.(*dns.DNSKEY); ok { - return true - } - if _, ok := rr.(*dns.RRSIG); ok { - return true - } - if _, ok := rr.(*dns.DS); ok { - return true - } - if _, ok := rr.(*dns.NSEC); ok { - return true - } - if _, ok := rr.(*dns.NSEC3); ok { + switch rr.(type) { + case *dns.DNSKEY, *dns.RRSIG, *dns.DS, *dns.NSEC, *dns.NSEC3: return true } } + + // 检查授权部分 for _, rr := range response.Ns { - if _, ok := rr.(*dns.DNSKEY); ok { - return true - } - if _, ok := rr.(*dns.RRSIG); ok { - return true - } - if _, ok := rr.(*dns.DS); ok { - return true - } - if _, ok := rr.(*dns.NSEC); ok { - return true - } - if _, ok := rr.(*dns.NSEC3); ok { + switch rr.(type) { + case *dns.DNSKEY, *dns.RRSIG, *dns.DS, *dns.NSEC, *dns.NSEC3: return true } } + + // 检查附加部分 for _, rr := range response.Extra { - if _, ok := rr.(*dns.DNSKEY); ok { - return true - } - if _, ok := rr.(*dns.RRSIG); ok { - return true - } - if _, ok := rr.(*dns.DS); ok { - return true - } - if _, ok := rr.(*dns.NSEC); ok { - return true - } - if _, ok := rr.(*dns.NSEC3); ok { + switch rr.(type) { + case *dns.DNSKEY, *dns.RRSIG, *dns.DS, *dns.NSEC, *dns.NSEC3: return true } } + return false } // Set 设置缓存项 func (c *DNSCache) Set(qName string, qType uint16, response *dns.Msg, ttl time.Duration) { + // 设置默认TTL if ttl <= 0 { - ttl = c.defaultTTL + ttl = c.ttl + } + + // 应用maxCacheTTL和minCacheTTL约束 + if c.maxCacheTTL > 0 && ttl > c.maxCacheTTL { + ttl = c.maxCacheTTL + } + if c.minCacheTTL > 0 && ttl < c.minCacheTTL { + ttl = c.minCacheTTL } key := cacheKey(qName, qType) item := &DNSCacheItem{ - Response: response.Copy(), // 复制响应以避免外部修改 - Expiry: time.Now().Add(ttl), + Response: response.Copy(), // 复制响应以避免外部修改 + Expiry: time.Now().Add(ttl), HasDNSSEC: hasDNSSECRecords(response), // 检查并设置DNSSEC标志 } + // 计算缓存项大小 + item.Size = calculateItemSize(item) + c.mutex.Lock() - c.cache[key] = item - c.mutex.Unlock() + defer c.mutex.Unlock() + + // 如果条目已存在,先从链表和缓存中移除,并更新缓存大小 + if existingNode, found := c.cache[key]; found { + c.cacheSize -= int64(existingNode.value.Size) + c.removeNode(existingNode) + delete(c.cache, key) + } + + // 创建新的链表节点并添加到尾部 + newNode := &LRUNode{ + key: key, + value: item, + } + c.addNodeToTail(newNode) + c.cache[key] = newNode + c.cacheSize += int64(item.Size) + + // 检查是否超过最大条目数限制,如果超过则移除最久未使用的条目 + if len(c.cache) > c.maxSize { + // 最久未使用的条目是链表的头节点 + if c.head != nil { + c.cacheSize -= int64(c.head.value.Size) + oldestKey := c.head.key + // 从缓存和链表中移除头节点 + delete(c.cache, oldestKey) + c.removeNode(c.head) + } + } + + // 检查是否超过最大缓存大小,如果超过则继续移除最久未使用的条目 + for c.cacheSize > c.maxCacheSize && c.head != nil { + c.cacheSize -= int64(c.head.value.Size) + oldestKey := c.head.key + delete(c.cache, oldestKey) + c.removeNode(c.head) + } + + // 更新缓存变化计数 + c.changeCount++ } // Get 获取缓存项 func (c *DNSCache) Get(qName string, qType uint16) (*dns.Msg, bool) { key := cacheKey(qName, qType) + // 首先使用读锁检查缓存项是否存在和是否过期 c.mutex.RLock() - item, found := c.cache[key] + node, found := c.cache[key] if !found { c.mutex.RUnlock() return nil, false } // 检查是否过期 - if time.Now().After(item.Expiry) { + if time.Now().After(node.value.Expiry) { c.mutex.RUnlock() - // 过期了,删除缓存项(在写锁中) - c.delete(key) + // 需要删除过期条目,使用写锁 + c.mutex.Lock() + // 再次检查,防止在读写锁切换期间被其他协程处理 + if node, stillExists := c.cache[key]; stillExists && time.Now().After(node.value.Expiry) { + delete(c.cache, key) + c.removeNode(node) + } + c.mutex.Unlock() return nil, false } - // 返回缓存的响应副本 - response := item.Response.Copy() + // 返回前释放读锁,避免长时间持有锁 + response := node.value.Response.Copy() c.mutex.RUnlock() + // 标记为最近使用需要修改链表,使用写锁 + c.mutex.Lock() + // 再次检查节点是否存在,防止在读写锁切换期间被删除 + if node, stillExists := c.cache[key]; stillExists { + c.moveNodeToTail(node) + } + c.mutex.Unlock() + return response, true } // delete 删除缓存项 func (c *DNSCache) delete(key string) { c.mutex.Lock() - delete(c.cache, key) - c.mutex.Unlock() + defer c.mutex.Unlock() + + // 从缓存和链表中删除 + if node, found := c.cache[key]; found { + delete(c.cache, key) + c.removeNode(node) + } } // Clear 清空缓存 func (c *DNSCache) Clear() { c.mutex.Lock() - c.cache = make(map[string]*DNSCacheItem) + c.cache = make(map[string]*LRUNode) + // 重置链表指针 + c.head = nil + c.tail = nil c.mutex.Unlock() } @@ -163,24 +425,414 @@ func (c *DNSCache) Size() int { // startCleanupLoop 启动定期清理过期缓存的协程 func (c *DNSCache) startCleanupLoop() { - ticker := time.NewTicker(time.Minute * 5) // 每5分钟清理一次 + // 初始清理间隔为1分钟 + cleanupInterval := time.Minute * 1 + ticker := time.NewTicker(cleanupInterval) defer ticker.Stop() for range ticker.C { - c.cleanupExpired() + cleanupInterval = c.cleanupExpired() + + // 调整下次清理间隔,范围:15秒到5分钟 + if cleanupInterval < 15*time.Second { + cleanupInterval = 15 * time.Second + } else if cleanupInterval > 5*time.Minute { + cleanupInterval = 5 * time.Minute + } + + // 更新清理间隔 + ticker.Reset(cleanupInterval) } } -// cleanupExpired 清理过期的缓存项 -func (c *DNSCache) cleanupExpired() { +// startSaveLoop 启动定期保存缓存的协程 +func (c *DNSCache) startSaveLoop() { + c.saveLoopMutex.Lock() + // 如果已经在运行,直接返回 + if c.saveRunning { + c.saveLoopMutex.Unlock() + return + } + // 重置停止通道 + c.saveStopCh = make(chan struct{}) + c.saveRunning = true + c.saveLoopMutex.Unlock() + + go func() { + ticker := time.NewTicker(c.saveInterval) // 根据配置的间隔保存 + defer ticker.Stop() + + for { + select { + case <-ticker.C: + // 检查缓存模式,如果不是file模式则不保存 + c.mutex.RLock() + mode := c.cacheMode + c.mutex.RUnlock() + if mode == "file" { + c.SaveToFile() + } + case <-c.saveStopCh: + // 停止保存循环 + c.saveLoopMutex.Lock() + c.saveRunning = false + c.saveLoopMutex.Unlock() + return + } + } + }() +} + +// saveCacheToFile 保存缓存到文件的底层实现,不检查缓存模式 +func (c *DNSCache) saveCacheToFile() { + c.saveMutex.Lock() + defer c.saveMutex.Unlock() + + // 智能保存策略 + // 1. 如果缓存变化次数少于10次,跳过保存 + // 2. 如果距离上次保存时间不足最小保存间隔,跳过保存 + c.mutex.RLock() + changeCount := c.changeCount + lastSaveTime := c.lastSaveTime + lastSaveCacheSize := c.lastSaveCacheSize + lastSaveItemCount := c.lastSaveItemCount + currentCacheSize := c.cacheSize + currentItemCount := len(c.cache) + c.mutex.RUnlock() + + // 检查是否需要保存 + if changeCount < 10 { + return + } + if time.Since(lastSaveTime) < c.minSaveInterval { + return + } + if currentItemCount > 0 { + cacheSizeChange := float64(currentCacheSize-lastSaveCacheSize) / float64(lastSaveCacheSize+1) // +1避免除以零 + itemCountChange := float64(currentItemCount-lastSaveItemCount) / float64(lastSaveItemCount+1) // +1避免除以零 + if math.Abs(cacheSizeChange) < 0.1 && math.Abs(itemCountChange) < 0.1 { + return + } + } + + // 开始保存缓存 + c.mutex.RLock() + // 收集有效的缓存项 + validItems := make(map[string]*SerializableDNSCacheItem) + now := time.Now() + + for key, node := range c.cache { + // 只保存未过期的缓存项 + if now.Before(node.value.Expiry) { + // 序列化DNS响应为二进制 + responseBytes, err := node.value.Response.Pack() + if err != nil { + continue // 跳过无法序列化的响应 + } + + // 创建可序列化的缓存项 + validItems[key] = &SerializableDNSCacheItem{ + ResponseBytes: responseBytes, + Expiry: node.value.Expiry.UnixNano(), + HasDNSSEC: node.value.HasDNSSEC, + Size: node.value.Size, + } + } + } + + // 创建可序列化的缓存结构 + serializableCache := &SerializableDNSCache{ + Items: validItems, + TTL: int64(c.ttl), + MaxSize: c.maxSize, + CacheMode: c.cacheMode, + CacheFilePath: c.cacheFilePath, + } + c.mutex.RUnlock() + + // 序列化到JSON + data, err := json.MarshalIndent(serializableCache, "", " ") + if err != nil { + return + } + + // 确保目录存在 + os.MkdirAll(cacheDir(), 0755) + + // 保存到文件 + err = ioutil.WriteFile(c.cacheFilePath, data, 0644) + if err != nil { + return + } + + // 更新保存状态 + c.mutex.Lock() + c.changeCount = 0 + c.lastSaveTime = time.Now() + c.lastSaveCacheSize = currentCacheSize + c.lastSaveItemCount = currentItemCount + c.mutex.Unlock() +} + +// SaveToFile 保存缓存到文件 +func (c *DNSCache) SaveToFile() { + // 检查缓存模式,如果不是file模式,直接返回 + c.mutex.RLock() + mode := c.cacheMode + c.mutex.RUnlock() + if mode != "file" { + return + } + + // 调用底层保存逻辑 + c.saveCacheToFile() +} + +// LoadFromFile 从文件加载缓存 +func (c *DNSCache) LoadFromFile() { + c.mutex.Lock() + defer c.mutex.Unlock() + + // 检查文件是否存在 + if _, err := os.Stat(c.cacheFilePath); os.IsNotExist(err) { + return // 文件不存在,跳过加载 + } + + // 读取文件内容 + data, err := ioutil.ReadFile(c.cacheFilePath) + if err != nil { + return + } + + // 反序列化JSON + var serializableCache SerializableDNSCache + err = json.Unmarshal(data, &serializableCache) + if err != nil { + return + } + + // 加载缓存项 + now := time.Now() + for key, serializableItem := range serializableCache.Items { + // 转换过期时间 + expiry := time.Unix(0, serializableItem.Expiry) + // 只加载未过期的缓存项 + if now.Before(expiry) { + // 反序列化二进制DNS响应 + response := &dns.Msg{} + err := response.Unpack(serializableItem.ResponseBytes) + if err != nil { + continue // 跳过无法反序列化的响应 + } + + // 创建缓存项 + item := &DNSCacheItem{ + Response: response, + Expiry: expiry, + HasDNSSEC: serializableItem.HasDNSSEC, + Size: serializableItem.Size, + } + + // 创建新的链表节点并添加到尾部 + newNode := &LRUNode{ + key: key, + value: item, + } + c.addNodeToTail(newNode) + c.cache[key] = newNode + c.cacheSize += int64(item.Size) + } + } +} + +// cacheDir 返回缓存目录 +func cacheDir() string { + return "data" +} + +// SetMaxCacheTTL 设置最大缓存TTL +func (c *DNSCache) SetMaxCacheTTL(ttl time.Duration) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.maxCacheTTL = ttl +} + +// SetMinCacheTTL 设置最小缓存TTL +func (c *DNSCache) SetMinCacheTTL(ttl time.Duration) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.minCacheTTL = ttl +} + +// SetCacheMode 设置缓存模式 +func (c *DNSCache) SetCacheMode(mode string) { + c.mutex.Lock() + oldMode := c.cacheMode + c.mutex.Unlock() + + // 根据模式变化决定是否启动或停止保存循环 + if oldMode != mode { + if oldMode == "file" { + // 从file模式切换到其他模式,先保存当前缓存到文件 + // 直接调用底层保存逻辑,不检查缓存模式 + c.saveCacheToFile() + } + + c.mutex.Lock() + c.cacheMode = mode + c.mutex.Unlock() + + if mode == "file" { + // 切换到file模式,启动保存循环 + c.startSaveLoop() + } else { + // 切换到非file模式,停止保存循环 + c.saveLoopMutex.Lock() + if c.saveRunning { + close(c.saveStopCh) + c.saveRunning = false + } + c.saveLoopMutex.Unlock() + } + } +} + +// SetMaxCacheSize 设置最大缓存大小 +func (c *DNSCache) SetMaxCacheSize(size int64) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.maxCacheSize = size +} + +// cleanupExpired 清理过期的缓存项,并返回下一次清理间隔的建议值 +func (c *DNSCache) cleanupExpired() time.Duration { now := time.Now() c.mutex.Lock() defer c.mutex.Unlock() - for key, item := range c.cache { - if now.After(item.Expiry) { - delete(c.cache, key) + // 收集所有过期的键 + var expiredKeys []string + totalItems := len(c.cache) + + // 遍历缓存,收集过期项 + for key, node := range c.cache { + if now.After(node.value.Expiry) { + expiredKeys = append(expiredKeys, key) } } + + expiredCount := len(expiredKeys) + + // 智能清理策略 + // 1. 如果过期项比例超过50%,立即清理 + // 2. 如果缓存大小超过最大缓存大小的80%,清理过期项 + // 3. 如果缓存项数量超过最大条目数的80%,清理过期项 + needCleanup := false + if totalItems > 0 { + if float64(expiredCount)/float64(totalItems) > 0.5 { + needCleanup = true + } else if c.cacheSize > c.maxCacheSize*8/10 { + needCleanup = true + } else if totalItems > c.maxSize*8/10 { + needCleanup = true + } + } + + // 如果没有过期项或不需要清理,根据过期项比例返回建议的清理间隔 + if expiredCount == 0 || !needCleanup { + // 计算下一次清理间隔 + var nextInterval time.Duration + if totalItems == 0 { + // 空缓存,下一次清理间隔可以长一些 + nextInterval = 5 * time.Minute + } else { + expireRatio := float64(expiredCount) / float64(totalItems) + // 过期项比例越高,清理间隔越短 + if expireRatio < 0.1 { + nextInterval = 5 * time.Minute + } else if expireRatio < 0.3 { + nextInterval = 2 * time.Minute + } else { + nextInterval = 1 * time.Minute + } + } + return nextInterval + } + + // 删除过期的缓存项 + for _, key := range expiredKeys { + if node, found := c.cache[key]; found { + // 减去缓存项大小 + c.cacheSize -= int64(node.value.Size) + delete(c.cache, key) + c.removeNode(node) + } + } + + // 清理后,如果缓存大小仍然超过最大缓存大小,继续清理最久未使用的项 + if c.cacheSize > c.maxCacheSize { + // 计算需要清理的额外大小 + overflow := c.cacheSize - c.maxCacheSize + cleanedSize := int64(0) + + // 从链表头开始清理(最久未使用的项) + current := c.head + for current != nil && cleanedSize < overflow { + nextNode := current.next + cleanedSize += int64(current.value.Size) + + // 删除节点 + delete(c.cache, current.key) + c.removeNode(current) + + current = nextNode + } + } + + // 清理后,如果缓存项数量仍然超过最大条目数,继续清理最久未使用的项 + if len(c.cache) > c.maxSize { + // 计算需要清理的额外数量 + overflowCount := len(c.cache) - c.maxSize + + // 从链表头开始清理(最久未使用的项) + current := c.head + for i := 0; i < overflowCount && current != nil; i++ { + nextNode := current.next + + // 删除节点 + c.cacheSize -= int64(current.value.Size) + delete(c.cache, current.key) + c.removeNode(current) + + current = nextNode + } + } + + // 清理后,根据剩余过期项比例返回建议的清理间隔 + // 重新计算剩余过期项 + var remainingExpired int + for _, node := range c.cache { + if now.After(node.value.Expiry) { + remainingExpired++ + } + } + + remainingItems := len(c.cache) + var nextInterval time.Duration + if remainingItems == 0 { + nextInterval = 5 * time.Minute + } else { + remainingRatio := float64(remainingExpired) / float64(remainingItems) + // 剩余过期项比例越高,清理间隔越短 + if remainingRatio < 0.1 { + nextInterval = 5 * time.Minute + } else if remainingRatio < 0.3 { + nextInterval = 2 * time.Minute + } else { + nextInterval = 1 * time.Minute + } + } + + return nextInterval } diff --git a/dns/server.go b/dns/server.go index d6374b0..9d2b5dc 100644 --- a/dns/server.go +++ b/dns/server.go @@ -5,17 +5,20 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math" + "math/rand" "net" - "net/http" "os" "path/filepath" "runtime" "sort" "strings" "sync" + "sync/atomic" "time" "dns-server/config" + "dns-server/gfw" "dns-server/logger" "dns-server/shield" @@ -37,7 +40,7 @@ func normalizeDNSServerAddress(address string) string { type BlockedDomain struct { Domain string Count int64 - LastSeen time.Time + LastSeen int64 DNSSEC bool // 是否使用了DNSSEC } @@ -46,14 +49,7 @@ type BlockedDomain struct { type ClientStats struct { IP string Count int64 - LastSeen time.Time -} - -// IPGeolocation IP地理位置信息 -type IPGeolocation struct { - Country string `json:"country"` // 国家 - City string `json:"city"` // 城市 - Expiry time.Time `json:"expiry"` // 缓存过期时间 + LastSeen int64 } // DNSAnswer DNS解析记录 @@ -109,6 +105,8 @@ type Server struct { config *config.DNSConfig shieldConfig *config.ShieldConfig shieldManager *shield.ShieldManager + gfwConfig *config.GFWListConfig + gfwManager *gfw.GFWListManager server *dns.Server tcpServer *dns.Server resolver *dns.Client @@ -131,26 +129,29 @@ type Server struct { queryLogsMutex sync.RWMutex queryLogs []QueryLog // 查询日志列表 maxQueryLogs int // 最大保存日志数量 + logChannel chan QueryLog // 日志处理通道 saveTicker *time.Ticker // 用于定时保存数据 startTime time.Time // 服务器启动时间 saveDone chan struct{} // 用于通知保存协程停止 stopped bool // 服务器是否已经停止 stoppedMutex sync.Mutex // 保护stopped标志的互斥锁 - // IP地理位置缓存 - ipGeolocationCache map[string]*IPGeolocation // IP地址到地理位置的映射 - ipGeolocationCacheMutex sync.RWMutex // 保护IP地理位置缓存的互斥锁 - ipGeolocationCacheTTL time.Duration // 缓存有效期 - // DNS查询缓存 DnsCache *DNSCache // DNS响应缓存 // 域名DNSSEC状态映射表 - domainDNSSECStatus map[string]bool // 域名到DNSSEC状态的映射 + domainDNSSECStatus map[string]bool // 域名到DNSSEC状态的映射 + domainDNSSECStatusMutex sync.RWMutex // 保护域名DNSSEC状态映射的互斥锁 // 上游服务器状态跟踪 serverStats map[string]*ServerStats // 服务器地址到状态的映射 serverStatsMutex sync.RWMutex // 保护服务器状态的互斥锁 + + // DNSSEC专用服务器映射,用于快速查找 + dnssecServerMap map[string]bool // DNSSEC专用服务器地址到布尔值的映射 + + // DNS客户端实例池,用于并行查询 + clientPool sync.Pool // 存储*dns.Client实例 } // Stats DNS服务器统计信息 @@ -172,19 +173,25 @@ type Stats struct { } // NewServer 创建DNS服务器实例 -func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shieldManager *shield.ShieldManager) *Server { +func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shieldManager *shield.ShieldManager, gfwConfig *config.GFWListConfig, gfwManager *gfw.GFWListManager) *Server { ctx, cancel := context.WithCancel(context.Background()) // 从配置中读取DNS缓存TTL值(分钟) cacheTTL := time.Duration(config.CacheTTL) * time.Minute + // 保存间隔(秒) + saveInterval := time.Duration(config.SaveInterval) * time.Second + // 最大和最小缓存TTL(分钟) + maxCacheTTL := time.Duration(config.MaxCacheTTL) * time.Minute + minCacheTTL := time.Duration(config.MinCacheTTL) * time.Minute server := &Server{ config: config, shieldConfig: shieldConfig, shieldManager: shieldManager, + gfwConfig: gfwConfig, + gfwManager: gfwManager, resolver: &dns.Client{ Net: "udp", - Timeout: time.Duration(config.Timeout) * time.Millisecond, UDPSize: 4096, // 增加UDP缓冲区大小,支持更大的DNSSEC响应 }, ctx: ctx, @@ -213,17 +220,28 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie monthlyStats: make(map[string]int64), queryLogs: make([]QueryLog, 0, 1000), // 初始化查询日志切片,容量1000 maxQueryLogs: 10000, // 最大保存10000条日志 + logChannel: make(chan QueryLog, 1000), // 日志处理通道,缓冲区大小1000 saveDone: make(chan struct{}), stopped: false, // 初始化为未停止状态 - // IP地理位置缓存初始化 - ipGeolocationCache: make(map[string]*IPGeolocation), - ipGeolocationCacheTTL: 24 * time.Hour, // 缓存有效期24小时 + // DNS查询缓存初始化 - DnsCache: NewDNSCache(cacheTTL), + DnsCache: NewDNSCache(cacheTTL, config.CacheMode, config.CacheSize, config.CacheFilePath, saveInterval, maxCacheTTL, minCacheTTL), // 初始化域名DNSSEC状态映射表 domainDNSSECStatus: make(map[string]bool), // 初始化服务器状态跟踪 serverStats: make(map[string]*ServerStats), + // 初始化DNSSEC专用服务器映射 + dnssecServerMap: make(map[string]bool), + // 初始化DNS客户端实例池 + clientPool: sync.Pool{ + New: func() interface{} { + return &dns.Client{ + Net: "udp", + UDPSize: 4096, + Timeout: 5 * time.Second, // 默认超时时间,会在使用时覆盖 + } + }, + }, } // 加载已保存的统计数据 @@ -270,6 +288,26 @@ func (s *Server) Start() error { // 启动自动保存功能 go s.startAutoSave() + // 更新DNSSEC专用服务器映射 + s.updateDNSSECServerMap() + + // 启动日志处理协程 + go s.processLogs() + + // 启动统计数据定期重置功能(每24小时) + go func() { + ticker := time.NewTicker(24 * time.Hour) + defer ticker.Stop() + for { + select { + case <-ticker.C: + s.resetStats() + case <-s.ctx.Done(): + return + } + } + }() + // 启动UDP服务 go func() { logger.Info(fmt.Sprintf("DNS UDP服务器启动,监听端口: %d", s.config.Port)) @@ -293,6 +331,27 @@ func (s *Server) Start() error { return nil } +// resetStats 重置统计数据 +func (s *Server) resetStats() { + s.statsMutex.Lock() + defer s.statsMutex.Unlock() + + // 只重置累计值,保留配置相关值 + s.stats.TotalResponseTime = 0 + s.stats.AvgResponseTime = 0 + s.stats.Queries = 0 + s.stats.Blocked = 0 + s.stats.Allowed = 0 + s.stats.Errors = 0 + s.stats.DNSSECQueries = 0 + s.stats.DNSSECSuccess = 0 + s.stats.DNSSECFailed = 0 + s.stats.QueryTypes = make(map[string]int64) + s.stats.SourceIPs = make(map[string]bool) + + logger.Info("统计数据已重置") +} + // Stop 停止DNS服务器 func (s *Server) Stop() { // 检查服务器是否已经停止 @@ -326,6 +385,39 @@ func (s *Server) Stop() { func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { startTime := time.Now() + // 1. 初始化请求信息 + reqInfo := s.initRequestInfo(w, r) + + // 2. 检查基本请求条件 + if earlyResponse := s.checkRequestConditions(w, r, startTime, reqInfo); earlyResponse { + return + } + + // 3. 检查本地处理规则 + if localHandled := s.handleLocalRules(w, r, startTime, reqInfo); localHandled { + return + } + + // 4. 尝试从缓存获取响应 + if cacheHandled := s.handleCacheResponse(w, r, startTime, reqInfo); cacheHandled { + return + } + + // 5. 转发请求到上游服务器 + s.handleUpstreamRequest(w, r, startTime, reqInfo) +} + +// requestInfo 封装请求相关信息 +type requestInfo struct { + sourceIP string + domain string + queryType string + qType uint16 + queryAttempts []string +} + +// initRequestInfo 初始化请求信息 +func (s *Server) initRequestInfo(w dns.ResponseWriter, r *dns.Msg) *requestInfo { // 获取来源IP sourceIP := w.RemoteAddr().String() // 提取IP地址部分,去掉端口 @@ -341,7 +433,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { } } - // 更新来源IP统计 + // 更新来源IP统计和Queries计数器 s.updateStats(func(stats *Stats) { stats.Queries++ stats.LastQuery = time.Now() @@ -368,33 +460,43 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { s.updateStats(func(stats *Stats) { stats.QueryTypes[queryType]++ }) - - // 检查是否是AAAA记录查询且IPv6解析已禁用 - if qType == dns.TypeAAAA && !s.config.EnableIPv6 { - // 返回NXDOMAIN响应(域名不存在) - response := new(dns.Msg) - response.SetReply(r) - response.SetRcode(r, dns.RcodeNameError) - w.WriteMsg(response) - - // 更新统计信息 - responseTime := int64(0) - s.updateStats(func(stats *Stats) { - stats.TotalResponseTime += responseTime - if stats.Queries > 0 { - stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries) - } - }) - - // 添加查询日志 - s.addQueryLog(sourceIP, domain, queryType, responseTime, "error", "", "", false, false, true, "", "", nil, dns.RcodeNameError) - logger.Debug("IPv6解析已禁用,拒绝AAAA记录查询", "domain", domain) - return - } } logger.Debug("接收到DNS查询", "domain", domain, "type", queryType, "client", w.RemoteAddr()) + return &requestInfo{ + sourceIP: sourceIP, + domain: domain, + queryType: queryType, + qType: qType, + queryAttempts: []string{domain}, + } +} + +// checkRequestConditions 检查请求条件,返回是否需要提前响应 +func (s *Server) checkRequestConditions(w dns.ResponseWriter, r *dns.Msg, startTime time.Time, reqInfo *requestInfo) bool { + // 检查是否是AAAA记录查询且IPv6解析已禁用 + if reqInfo.qType == dns.TypeAAAA && !s.config.EnableIPv6 { + // 返回空的成功响应,而不是NXDOMAIN + response := new(dns.Msg) + response.SetReply(r) + response.SetRcode(r, dns.RcodeSuccess) + w.WriteMsg(response) + + // 更新统计信息 - 视为正常解析 + responseTime := time.Since(startTime).Milliseconds() + s.updateStats(func(stats *Stats) { + stats.Allowed++ + stats.TotalResponseTime += responseTime + stats.AvgResponseTime = calculateAvgResponseTime(stats.TotalResponseTime, stats.Queries) + }) + + // 添加查询日志 + s.addQueryLog(reqInfo.sourceIP, reqInfo.domain, reqInfo.queryType, responseTime, "allowed", "", "", false, false, true, "", "", nil, dns.RcodeSuccess) + logger.Debug("IPv6解析已禁用,返回空的成功响应", "domain", reqInfo.domain) + return true + } + // 只处理递归查询 if r.RecursionDesired == false { response := new(dns.Msg) @@ -403,51 +505,66 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { response.SetRcode(r, dns.RcodeRefused) w.WriteMsg(response) - // 缓存命中,响应时间设为0ms - responseTime := int64(0) + // 计算实际响应时间 + responseTime := time.Since(startTime).Milliseconds() + // 更新统计信息 - 视为错误 s.updateStats(func(stats *Stats) { + stats.Errors++ stats.TotalResponseTime += responseTime - if stats.Queries > 0 { - stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries) - } + stats.AvgResponseTime = calculateAvgResponseTime(stats.TotalResponseTime, stats.Queries) }) // 添加查询日志 - s.addQueryLog(sourceIP, domain, queryType, responseTime, "error", "", "", false, false, true, "", "", nil, dns.RcodeRefused) - return + s.addQueryLog(reqInfo.sourceIP, reqInfo.domain, reqInfo.queryType, responseTime, "error", "", "", false, false, true, "", "", nil, dns.RcodeRefused) + return true } + return false +} + +// handleLocalRules 处理本地规则(hosts文件、GFWList、屏蔽规则),返回是否已处理 +func (s *Server) handleLocalRules(w dns.ResponseWriter, r *dns.Msg, startTime time.Time, reqInfo *requestInfo) bool { + // 本地规则匹配的响应时间极短,使用固定值1ms + const localResponseTime int64 = 1 + // 检查hosts文件是否有匹配 - if ip, exists := s.shieldManager.GetHostsIP(domain); exists { + if ip, exists := s.shieldManager.GetHostsIP(reqInfo.domain); exists { s.handleHostsResponse(w, r, ip) - // 缓存命中,响应时间设为0ms - responseTime := int64(0) + // 使用固定的短响应时间 s.updateStats(func(stats *Stats) { - stats.TotalResponseTime += responseTime - if stats.Queries > 0 { - stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries) - } + stats.TotalResponseTime += localResponseTime + stats.AvgResponseTime = calculateAvgResponseTime(stats.TotalResponseTime, stats.Queries) + }) + return true + } + + // 检查是否为GFWList域名(仅当GFWList功能启用时) + if s.gfwConfig.Enabled && s.gfwManager != nil && s.gfwManager.IsMatch(reqInfo.domain) { + s.handleGFWListResponse(w, r, reqInfo.domain) + // 使用固定的短响应时间 + s.updateStats(func(stats *Stats) { + stats.TotalResponseTime += localResponseTime + stats.AvgResponseTime = calculateAvgResponseTime(stats.TotalResponseTime, stats.Queries) }) - // 该方法内部未直接调用addQueryLog,而是在handleDNSRequest中处理 - return + // 添加查询日志 - GFWList域名 + gfwAnswers := []DNSAnswer{} + s.addQueryLog(reqInfo.sourceIP, reqInfo.domain, reqInfo.queryType, localResponseTime, "gfwlist", "", "", false, false, true, "GFWList", "无", gfwAnswers, dns.RcodeSuccess) + return true } // 检查是否被屏蔽 - if s.shieldManager.IsBlocked(domain) { + if s.shieldManager.IsBlocked(reqInfo.domain) { // 获取屏蔽详情 - blockDetails := s.shieldManager.CheckDomainBlockDetails(domain) + blockDetails := s.shieldManager.CheckDomainBlockDetails(reqInfo.domain) blockRule, _ := blockDetails["blockRule"].(string) blockType, _ := blockDetails["blockRuleType"].(string) - s.handleBlockedResponse(w, r, domain) - // 计算响应时间 - responseTime := time.Since(startTime).Milliseconds() + s.handleBlockedResponse(w, r, reqInfo.domain) + // 使用固定的短响应时间 s.updateStats(func(stats *Stats) { - stats.TotalResponseTime += responseTime - if stats.Queries > 0 { - stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries) - } + stats.TotalResponseTime += localResponseTime + stats.AvgResponseTime = calculateAvgResponseTime(stats.TotalResponseTime, stats.Queries) }) // 添加查询日志 - 被屏蔽域名 @@ -459,17 +576,22 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { } else if blockMethod == "emptyIP" || blockMethod == "customIP" { blockedRcode = dns.RcodeSuccess } - s.addQueryLog(sourceIP, domain, queryType, responseTime, "blocked", blockRule, blockType, false, false, true, "无", "无", blockedAnswers, blockedRcode) - return + s.addQueryLog(reqInfo.sourceIP, reqInfo.domain, reqInfo.queryType, localResponseTime, "blocked", blockRule, blockType, false, false, true, "无", "无", blockedAnswers, blockedRcode) + return true } + return false +} + +// handleCacheResponse 尝试从缓存获取响应,返回是否已处理 +func (s *Server) handleCacheResponse(w dns.ResponseWriter, r *dns.Msg, startTime time.Time, reqInfo *requestInfo) bool { // 检查缓存中是否有响应(优先查找带DNSSEC的缓存项) var cachedResponse *dns.Msg var found bool var cachedDNSSEC bool // 1. 首先检查是否有普通缓存项 - if tempResponse, tempFound := s.DnsCache.Get(r.Question[0].Name, qType); tempFound { + if tempResponse, tempFound := s.DnsCache.Get(r.Question[0].Name, reqInfo.qType); tempFound { cachedResponse = tempResponse found = tempFound cachedDNSSEC = s.hasDNSSECRecords(tempResponse) @@ -483,87 +605,117 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { // 后续可以考虑改进缓存实现,添加DNSSEC状态标记 } - if found { - // 缓存命中,直接返回缓存的响应 - cachedResponseCopy := cachedResponse.Copy() // 创建响应副本避免并发修改问题 - cachedResponseCopy.Id = r.Id // 更新ID以匹配请求 - cachedResponseCopy.Compress = true - - // 如果客户端请求包含EDNS记录,确保响应也包含EDNS - if opt := r.IsEdns0(); opt != nil { - // 检查响应是否已经包含EDNS记录 - if respOpt := cachedResponseCopy.IsEdns0(); respOpt == nil { - // 添加EDNS记录,使用客户端的UDP缓冲区大小 - cachedResponseCopy.SetEdns0(opt.UDPSize(), s.config.EnableDNSSEC) - } else { - // 确保响应的UDP缓冲区大小不超过客户端请求的大小 - if respOpt.UDPSize() > opt.UDPSize() { - // 移除现有的EDNS记录 - for i := range cachedResponseCopy.Extra { - if cachedResponseCopy.Extra[i] == respOpt { - cachedResponseCopy.Extra = append(cachedResponseCopy.Extra[:i], cachedResponseCopy.Extra[i+1:]...) - break - } - } - // 添加新的EDNS记录,使用客户端的UDP缓冲区大小 - cachedResponseCopy.SetEdns0(opt.UDPSize(), s.config.EnableDNSSEC) - } - } - } - - w.WriteMsg(cachedResponseCopy) - - // 计算响应时间 - responseTime := time.Since(startTime).Milliseconds() - s.updateStats(func(stats *Stats) { - stats.TotalResponseTime += responseTime - if stats.Queries > 0 { - stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries) - } - }) - - // 如果缓存响应包含DNSSEC记录,更新DNSSEC查询计数 - if cachedDNSSEC { - s.updateStats(func(stats *Stats) { - stats.DNSSECQueries++ - // 缓存响应视为DNSSEC成功 - stats.DNSSECSuccess++ - }) - } - - // 从缓存响应中提取解析记录 - cachedAnswers := []DNSAnswer{} - if cachedResponse != nil { - for _, rr := range cachedResponse.Answer { - cachedAnswers = append(cachedAnswers, DNSAnswer{ - Type: dns.TypeToString[rr.Header().Rrtype], - Value: rr.String(), - TTL: rr.Header().Ttl, - }) - } - } - - // 添加查询日志 - 标记为缓存 - // 从缓存响应中获取响应代码 - cacheRcode := dns.RcodeSuccess // 默认成功 - if cachedResponse != nil { - cacheRcode = cachedResponse.Rcode - } - s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", true, cachedDNSSEC, true, "缓存", "无", cachedAnswers, cacheRcode) - logger.Debug("从缓存返回DNS响应", "domain", domain, "type", queryType, "dnssec", cachedDNSSEC) - return + if !found { + return false } + // 缓存命中,直接返回缓存的响应 + cachedResponseCopy := cachedResponse.Copy() // 创建响应副本避免并发修改问题 + cachedResponseCopy.Id = r.Id // 更新ID以匹配请求 + cachedResponseCopy.Compress = true + + // 如果客户端请求包含EDNS记录,确保响应也包含EDNS + if opt := r.IsEdns0(); opt != nil { + // 检查响应是否已经包含EDNS记录 + if respOpt := cachedResponseCopy.IsEdns0(); respOpt == nil { + // 添加EDNS记录,使用客户端的UDP缓冲区大小 + cachedResponseCopy.SetEdns0(opt.UDPSize(), s.config.EnableDNSSEC) + } else { + // 确保响应的UDP缓冲区大小不超过客户端请求的大小 + if respOpt.UDPSize() > opt.UDPSize() { + // 移除现有的EDNS记录 + for i := range cachedResponseCopy.Extra { + if cachedResponseCopy.Extra[i] == respOpt { + cachedResponseCopy.Extra = append(cachedResponseCopy.Extra[:i], cachedResponseCopy.Extra[i+1:]...) + break + } + } + // 添加新的EDNS记录,使用客户端的UDP缓冲区大小 + cachedResponseCopy.SetEdns0(opt.UDPSize(), s.config.EnableDNSSEC) + } + } + } + + // 确保响应的Question部分与客户端请求的Question部分匹配 + cachedResponseCopy.Question = r.Question + + // 修复:如果响应包含记录,确保Rcode为成功 + hasValidRecords := false + + // 检查Answer部分 + if len(cachedResponseCopy.Answer) > 0 { + hasValidRecords = true + } else if len(cachedResponseCopy.Ns) > 0 { + // 检查Ns部分 + hasValidRecords = true + } else if len(cachedResponseCopy.Extra) > 0 { + // 检查Extra部分,排除OPT记录 + for _, rr := range cachedResponseCopy.Extra { + if rr.Header().Rrtype != dns.TypeOPT { + hasValidRecords = true + break + } + } + } + + if hasValidRecords { + cachedResponseCopy.Rcode = dns.RcodeSuccess + } + + w.WriteMsg(cachedResponseCopy) + + // 缓存命中的响应时间应该是极短的,使用固定值1ms而非实际处理时间 + const cacheResponseTime int64 = 1 + + // 缓存命中的响应视为正常解析 + s.updateStats(func(stats *Stats) { + stats.Allowed++ + stats.TotalResponseTime += cacheResponseTime + stats.AvgResponseTime = calculateAvgResponseTime(stats.TotalResponseTime, stats.Queries) + }) + + // 如果缓存响应包含DNSSEC记录,更新DNSSEC查询计数 + if cachedDNSSEC { + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + // 缓存响应视为DNSSEC成功 + stats.DNSSECSuccess++ + }) + } + + // 从缓存响应中提取解析记录 + cachedAnswers := []DNSAnswer{} + if cachedResponse != nil { + for _, rr := range cachedResponse.Answer { + cachedAnswers = append(cachedAnswers, DNSAnswer{ + Type: dns.TypeToString[rr.Header().Rrtype], + Value: rr.String(), + TTL: rr.Header().Ttl, + }) + } + } + + // 添加查询日志 - 标记为缓存 + // 从缓存响应中获取响应代码 + cacheRcode := dns.RcodeSuccess // 默认成功 + if cachedResponse != nil { + cacheRcode = cachedResponse.Rcode + } + s.addQueryLog(reqInfo.sourceIP, reqInfo.domain, reqInfo.queryType, cacheResponseTime, "allowed", "", "", true, cachedDNSSEC, true, "缓存", "无", cachedAnswers, cacheRcode) + logger.Debug("从缓存返回DNS响应", "domain", reqInfo.domain, "type", reqInfo.queryType, "dnssec", cachedDNSSEC) + return true +} + +// handleUpstreamRequest 处理上游请求 +func (s *Server) handleUpstreamRequest(w dns.ResponseWriter, r *dns.Msg, startTime time.Time, reqInfo *requestInfo) { // 缓存未命中,处理DNS请求 var response *dns.Msg var rtt time.Duration - var queryAttempts []string var dnsServer string var dnssecServer string // 直接查询原始域名 - queryAttempts = append(queryAttempts, domain) - response, rtt, dnsServer, dnssecServer = s.forwardDNSRequestWithCache(r, domain) + response, rtt, dnsServer, dnssecServer = s.forwardDNSRequestWithCache(r, reqInfo.domain) if response != nil { // 如果客户端请求包含EDNS记录,确保响应也包含EDNS @@ -588,6 +740,32 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { } } + // 确保响应的Question部分与客户端请求的Question部分匹配 + response.Question = r.Question + + // 修复:如果响应包含记录,确保Rcode为成功 + hasValidRecords := false + + // 检查Answer部分 + if len(response.Answer) > 0 { + hasValidRecords = true + } else if len(response.Ns) > 0 { + // 检查Ns部分 + hasValidRecords = true + } else if len(response.Extra) > 0 { + // 检查Extra部分,排除OPT记录 + for _, rr := range response.Extra { + if rr.Header().Rrtype != dns.TypeOPT { + hasValidRecords = true + break + } + } + } + + if hasValidRecords { + response.Rcode = dns.RcodeSuccess + } + // 写入响应给客户端 w.WriteMsg(response) } @@ -599,13 +777,48 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { responseTime = time.Since(startTime).Milliseconds() } + // 添加合理性检查,避免异常大的响应时间影响统计 + if responseTime > 60000 { // 超过60秒的响应时间视为异常 + responseTime = 60000 + } + + // 更新基本统计 s.updateStats(func(stats *Stats) { stats.TotalResponseTime += responseTime + // 添加防御性编程,确保Queries大于0 if stats.Queries > 0 { - stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries) + // 平均响应时间 = 总响应时间 / 总解析数量,四舍五入取整 + avg := float64(stats.TotalResponseTime) / float64(stats.Queries) + stats.AvgResponseTime = float64(math.Round(avg)) + // 限制平均响应时间的范围,避免显示异常大的值 + if stats.AvgResponseTime > 60000 { + stats.AvgResponseTime = 60000 + } } }) + // 判断请求结果类型并更新相应统计 + resultType := "allowed" + if response == nil { + // 响应为nil,视为错误 + resultType = "error" + s.updateStats(func(stats *Stats) { + stats.Errors++ + }) + } else if response.Rcode != dns.RcodeSuccess { + // 响应代码不是成功,视为错误 + resultType = "error" + s.updateStats(func(stats *Stats) { + stats.Errors++ + }) + } else { + // 成功响应,视为正常解析 + resultType = "allowed" + s.updateStats(func(stats *Stats) { + stats.Allowed++ + }) + } + // 检查响应是否包含DNSSEC记录并验证结果 responseDNSSEC := false if response != nil { @@ -619,7 +832,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { // 更新域名的DNSSEC状态 if responseDNSSEC { - s.updateDomainDNSSECStatus(domain, true) + s.updateDomainDNSSECStatus(reqInfo.domain, true) } } @@ -629,8 +842,22 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { responseCopy := response.Copy() // 设置合理的TTL,不超过默认的30分钟 defaultCacheTTL := 30 * time.Minute - s.DnsCache.Set(r.Question[0].Name, qType, responseCopy, defaultCacheTTL) - logger.Debug("DNS响应已缓存", "domain", domain, "type", queryType, "ttl", defaultCacheTTL, "dnssec", responseDNSSEC) + + // 1. 缓存原始域名的查询结果 + s.DnsCache.Set(r.Question[0].Name, reqInfo.qType, responseCopy, defaultCacheTTL) + logger.Debug("DNS响应已缓存", "domain", reqInfo.domain, "type", reqInfo.queryType, "ttl", defaultCacheTTL, "dnssec", responseDNSSEC) + + // 2. 如果响应包含CNAME记录,同时缓存CNAME指向的域名的查询结果 + for _, rr := range response.Answer { + if cname, ok := rr.(*dns.CNAME); ok { + // 为CNAME指向的域名创建缓存 + cnameQuery := r.Copy() + cnameQuery.Question[0].Name = cname.Target + s.DnsCache.Set(cname.Target, reqInfo.qType, responseCopy, defaultCacheTTL) + logger.Debug("CNAME响应已缓存", "domain", cname.Target, "type", reqInfo.queryType, "ttl", defaultCacheTTL, "dnssec", responseDNSSEC) + break + } + } } // 从响应中提取解析记录 @@ -645,13 +872,13 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { } } - // 添加查询日志 - 标记为实时 // 从响应中获取响应代码 realRcode := dns.RcodeSuccess // 默认成功 if response != nil { realRcode = response.Rcode } - s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false, responseDNSSEC, true, dnsServer, dnssecServer, responseAnswers, realRcode) + // 添加查询日志 + s.addQueryLog(reqInfo.sourceIP, reqInfo.domain, reqInfo.queryType, responseTime, resultType, "", "", false, responseDNSSEC, true, dnsServer, dnssecServer, responseAnswers, realRcode) } // handleHostsResponse 处理hosts文件匹配的响应 @@ -684,6 +911,39 @@ func (s *Server) handleHostsResponse(w dns.ResponseWriter, r *dns.Msg, ip string } w.WriteMsg(response) + // 本地hosts匹配响应时间极短,使用固定值1ms + const localResponseTime int64 = 1 + s.updateStats(func(stats *Stats) { + stats.Allowed++ + }) +} + +// handleGFWListResponse 处理GFWList域名响应 +func (s *Server) handleGFWListResponse(w dns.ResponseWriter, r *dns.Msg, domain string) { + logger.Info("GFWList域名解析", "domain", domain, "client", w.RemoteAddr(), "ip", s.gfwConfig.IP) + + // 更新解析域名统计 + s.updateResolvedDomainStats(domain) + + response := new(dns.Msg) + response.SetReply(r) + + if len(r.Question) > 0 { + q := r.Question[0] + answer := new(dns.A) + answer.Hdr = dns.RR_Header{ + Name: q.Name, + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: 300, + } + answer.A = net.ParseIP(s.gfwConfig.IP) + response.Answer = append(response.Answer, answer) + } + + w.WriteMsg(response) + // GFWList域名匹配响应时间极短,使用固定值1ms + const localResponseTime int64 = 1 s.updateStats(func(stats *Stats) { stats.Allowed++ }) @@ -730,7 +990,7 @@ func (s *Server) handleBlockedResponse(w dns.ResponseWriter, r *dns.Msg, domain } case "customIP": // 返回自定义IP响应 - if len(r.Question) > 0 && r.Question[0].Qtype == dns.TypeA && customBlockIP != "" { + if len(r.Question) > 0 && r.Question[0].Qtype == dns.TypeA { answer := new(dns.A) answer.Hdr = dns.RR_Header{ Name: r.Question[0].Name, @@ -738,7 +998,13 @@ func (s *Server) handleBlockedResponse(w dns.ResponseWriter, r *dns.Msg, domain Class: dns.ClassINET, Ttl: 300, } - answer.A = net.ParseIP(customBlockIP) + // 使用自定义屏蔽IP + if customBlockIP != "" { + answer.A = net.ParseIP(customBlockIP) + } else { + // 如果没有配置,使用0.0.0.0 + answer.A = net.ParseIP("0.0.0.0") + } response.Answer = append(response.Answer, answer) } case "NXDOMAIN", "": @@ -749,6 +1015,8 @@ func (s *Server) handleBlockedResponse(w dns.ResponseWriter, r *dns.Msg, domain } w.WriteMsg(response) + // 屏蔽规则匹配响应时间极短,使用固定值1ms + const localResponseTime int64 = 1 s.updateStats(func(stats *Stats) { stats.Blocked++ }) @@ -763,6 +1031,19 @@ type serverResponse struct { error error } +// updateDNSSECServerMap 更新DNSSEC专用服务器映射,用于快速查找 +func (s *Server) updateDNSSECServerMap() { + // 清空现有映射 + for k := range s.dnssecServerMap { + delete(s.dnssecServerMap, k) + } + + // 添加所有DNSSEC专用服务器到映射 + for _, server := range s.config.DNSSECUpstreamDNS { + s.dnssecServerMap[server] = true + } +} + // forwardDNSRequestWithCache 转发DNS请求到上游服务器并返回响应 func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg, time.Duration, string, string) { // 始终支持EDNS @@ -857,45 +1138,51 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg var usedDNSServer string var usedDNSSECServer string + // 使用配置中的超时时间 + defaultTimeout := time.Duration(s.config.QueryTimeout) * time.Millisecond + // 根据查询模式处理请求 switch s.config.QueryMode { case "parallel": - // 并行请求模式 - 优化版:添加超时处理和快速响应返回 + // 并行请求模式 - 返回第一个成功响应 responses := make(chan serverResponse, len(selectedUpstreamDNS)) var wg sync.WaitGroup - // 超时上下文 - timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond) - defer cancel() - // 向所有上游服务器并行发送请求 for _, upstream := range selectedUpstreamDNS { wg.Add(1) go func(server string) { defer wg.Done() - // 发送请求并获取响应,确保服务器地址包含端口号 - response, rtt, err := s.resolver.Exchange(r, normalizeDNSServerAddress(server)) + // 从池中获取客户端实例 + client := s.clientPool.Get().(*dns.Client) + // 设置客户端参数 + client.Net = s.resolver.Net + client.UDPSize = s.resolver.UDPSize + client.Timeout = defaultTimeout - select { - case responses <- serverResponse{response, rtt, server, err}: - // 成功发送响应 - case <-timeoutCtx.Done(): - // 超时,忽略此响应 - logger.Debug("并行请求超时", "server", server, "domain", domain) - return - } + // 发送请求并获取响应,确保服务器地址包含端口号 + response, rtt, err := client.Exchange(r, normalizeDNSServerAddress(server)) + responses <- serverResponse{response, rtt, server, err} + + // 将客户端实例放回池中 + s.clientPool.Put(client) }(upstream) } - // 等待所有请求完成或超时 + // 等待所有请求完成 go func() { wg.Wait() close(responses) }() - // 处理所有响应 - for resp := range responses { + // 处理响应,只返回第一个成功响应 + var lastErrorResponse *dns.Msg + var lastErrorRtt time.Duration + var lastErrorServer string + + for i := 0; i < len(selectedUpstreamDNS); i++ { + resp := <-responses if resp.error == nil && resp.response != nil { // 更新服务器统计信息 s.updateServerStats(resp.server, true, resp.rtt) @@ -903,129 +1190,51 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg // 检查是否包含DNSSEC记录 containsDNSSEC := s.hasDNSSECRecords(resp.response) - // 如果启用了DNSSEC且响应包含DNSSEC记录,验证DNSSEC签名 - // 但如果域名匹配不验证DNSSEC的模式,则跳过验证 - if s.config.EnableDNSSEC && containsDNSSEC && !noDNSSEC { - // 验证DNSSEC记录 - signatureValid := s.verifyDNSSEC(resp.response) - - // 设置AD标志(Authenticated Data) - resp.response.AuthenticatedData = signatureValid - - if signatureValid { - // 更新DNSSEC验证成功计数 - s.updateStats(func(stats *Stats) { - stats.DNSSECQueries++ - stats.DNSSECSuccess++ - }) - } else { - // 更新DNSSEC验证失败计数 - s.updateStats(func(stats *Stats) { - stats.DNSSECQueries++ - stats.DNSSECFailed++ - }) - } - } else if noDNSSEC { - // 对于不验证DNSSEC的域名,始终设置AD标志为false + // 对于不验证DNSSEC的域名,始终设置AD标志为false + if noDNSSEC { resp.response.AuthenticatedData = false } // 检查当前服务器是否是DNSSEC专用服务器 - for _, dnssecServer := range dnssecServers { - if dnssecServer == resp.server { - usedDNSSECServer = resp.server - break - } + if _, isDNSSECServer := s.dnssecServerMap[resp.server]; isDNSSECServer { + usedDNSSECServer = resp.server } - // 检查当前服务器是否是用户配置的上游DNS服务器 - isUserUpstream := false - for _, userServer := range s.config.UpstreamDNS { - if userServer == resp.server { - isUserUpstream = true - break - } - } - - // 处理响应,优先选择用户配置的主DNS服务器 + // 如果是成功响应,立即返回 if resp.response.Rcode == dns.RcodeSuccess { - // 成功响应,优先使用 - if isUserUpstream { - // 用户配置的主DNS服务器响应,直接设置为最佳响应 - bestResponse = resp.response - bestRtt = resp.rtt - hasBestResponse = true - hasDNSSECResponse = containsDNSSEC - usedDNSServer = resp.server - logger.Debug("使用用户配置的上游服务器响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) - } else if containsDNSSEC { - // 非用户配置服务器,但有DNSSEC记录 - if !hasBestResponse || !isUserUpstream { - // 如果还没有最佳响应,或者当前最佳响应不是用户配置的服务器,则更新 - bestResponse = resp.response - bestRtt = resp.rtt - hasBestResponse = true - hasDNSSECResponse = true - usedDNSServer = resp.server - logger.Debug("找到带DNSSEC的最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) - } - } else { - // 非用户配置服务器,没有DNSSEC记录 - if !hasBestResponse { - // 如果还没有最佳响应,设置为最佳响应 - bestResponse = resp.response - bestRtt = resp.rtt - hasBestResponse = true - usedDNSServer = resp.server - logger.Debug("找到最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) - } - } - } else if resp.response.Rcode == dns.RcodeNameError { - // NXDOMAIN响应 - if !hasBestResponse || bestResponse.Rcode == dns.RcodeNameError { - // 如果还没有最佳响应,或者最佳响应也是NXDOMAIN - if isUserUpstream { - // 用户配置的服务器,直接使用 - bestResponse = resp.response - bestRtt = resp.rtt - hasBestResponse = true - usedDNSServer = resp.server - logger.Debug("使用用户配置的上游服务器NXDOMAIN响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) - } else if !hasBestResponse || resp.rtt < bestRtt { - // 非用户配置服务器,选择更快的响应 - bestResponse = resp.response - bestRtt = resp.rtt - hasBestResponse = true - usedDNSServer = resp.server - logger.Debug("找到NXDOMAIN最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) - } - } - } + // 验证DNSSEC记录(如果需要) + if s.config.EnableDNSSEC && containsDNSSEC && !noDNSSEC { + // 验证DNSSEC记录 + signatureValid := s.verifyDNSSEC(resp.response) + resp.response.AuthenticatedData = signatureValid - // 更新备选响应,确保总有一个可用的响应 - if resp.response != nil { - if !hasBackup { - // 第一次保存备选响应 - backupResponse = resp.response - backupRtt = resp.rtt - hasBackup = true - } else { - // 后续响应,优先保存用户配置的服务器响应作为备选 - if isUserUpstream { - backupResponse = resp.response - backupRtt = resp.rtt + if signatureValid { + // 更新DNSSEC验证成功计数 + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + stats.DNSSECSuccess++ + }) + } else { + // 更新DNSSEC验证失败计数 + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + stats.DNSSECFailed++ + }) } } - } - // 即使响应不是成功或NXDOMAIN,也保存为最佳响应(如果还没有的话) - // 确保总有一个响应返回给客户端 - if !hasBestResponse { bestResponse = resp.response bestRtt = resp.rtt - hasBestResponse = true usedDNSServer = resp.server - logger.Debug("使用非成功响应作为最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt, "rcode", resp.response.Rcode) + hasBestResponse = true + hasDNSSECResponse = containsDNSSEC + logger.Debug("返回第一个成功响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) + return bestResponse, bestRtt, usedDNSServer, usedDNSSECServer + } else { + // 保存最后一个错误响应 + lastErrorResponse = resp.response + lastErrorRtt = resp.rtt + lastErrorServer = resp.server } } else { // 更新服务器统计信息(失败) @@ -1033,190 +1242,35 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg } } - case "loadbalance": - // 负载均衡模式 - 使用加权随机选择算法 - // 1. 尝试所有可用的服务器,直到找到一个能正常工作的 - var triedServers []string - for len(triedServers) < len(selectedUpstreamDNS) { - // 从剩余的服务器中选择一个加权随机服务器 - var availableServers []string - for _, server := range selectedUpstreamDNS { - found := false - for _, tried := range triedServers { - if server == tried { - found = true - break - } - } - if !found { - availableServers = append(availableServers, server) - } - } - - selectedServer := s.selectWeightedRandomServer(availableServers) - if selectedServer == "" { - break - } - - triedServers = append(triedServers, selectedServer) - logger.Debug("在负载均衡模式下选择服务器", "domain", domain, "server", selectedServer, "triedServers", triedServers) - - // 设置超时上下文 - timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond) - defer cancel() - - // 使用带超时的方式执行Exchange - resultChan := make(chan struct { - response *dns.Msg - rtt time.Duration - err error - }, 1) - - go func() { - response, rtt, err := s.resolver.Exchange(r, normalizeDNSServerAddress(selectedServer)) - resultChan <- struct { - response *dns.Msg - rtt time.Duration - err error - }{response, rtt, err} - }() - - var response *dns.Msg - var rtt time.Duration - var err error - - select { - case result := <-resultChan: - response, rtt, err = result.response, result.rtt, result.err - case <-timeoutCtx.Done(): - err = timeoutCtx.Err() - } - - if err == nil && response != nil { - // 更新服务器统计信息 - s.updateServerStats(selectedServer, true, rtt) - - // 检查是否包含DNSSEC记录 - containsDNSSEC := s.hasDNSSECRecords(response) - - // 如果启用了DNSSEC且响应包含DNSSEC记录,验证DNSSEC签名 - // 但如果域名匹配不验证DNSSEC的模式,则跳过验证 - if s.config.EnableDNSSEC && containsDNSSEC && !noDNSSEC { - // 验证DNSSEC记录 - signatureValid := s.verifyDNSSEC(response) - - // 设置AD标志(Authenticated Data) - response.AuthenticatedData = signatureValid - - if signatureValid { - // 更新DNSSEC验证成功计数 - s.updateStats(func(stats *Stats) { - stats.DNSSECQueries++ - stats.DNSSECSuccess++ - }) - } else { - // 更新DNSSEC验证失败计数 - s.updateStats(func(stats *Stats) { - stats.DNSSECQueries++ - stats.DNSSECFailed++ - }) - } - } else if noDNSSEC { - // 对于不验证DNSSEC的域名,始终设置AD标志为false - response.AuthenticatedData = false - } - - // 如果响应成功或为NXDOMAIN,根据DNSSEC状态选择最佳响应 - if response.Rcode == dns.RcodeSuccess || response.Rcode == dns.RcodeNameError { - if response.Rcode == dns.RcodeSuccess { - // 优先选择带有DNSSEC记录的响应 - if containsDNSSEC { - bestResponse = response - bestRtt = rtt - hasBestResponse = true - hasDNSSECResponse = true - usedDNSServer = selectedServer - // 如果当前使用的服务器是DNSSEC专用服务器,同时设置usedDNSSECServer - for _, dnssecServer := range dnssecServers { - if dnssecServer == selectedServer { - usedDNSSECServer = selectedServer - break - } - } - logger.Debug("找到带DNSSEC的最佳响应", "domain", domain, "server", selectedServer, "rtt", rtt) - } else { - // 没有带DNSSEC的响应时,保存成功响应 - bestResponse = response - bestRtt = rtt - hasBestResponse = true - usedDNSServer = selectedServer - // 如果当前使用的服务器是DNSSEC专用服务器,同时设置usedDNSSECServer - for _, dnssecServer := range dnssecServers { - if dnssecServer == selectedServer { - usedDNSSECServer = selectedServer - break - } - } - logger.Debug("找到最佳响应", "domain", domain, "server", selectedServer, "rtt", rtt) - } - } else if response.Rcode == dns.RcodeNameError { - // 处理NXDOMAIN响应 - bestResponse = response - bestRtt = rtt - hasBestResponse = true - usedDNSServer = selectedServer - logger.Debug("找到NXDOMAIN响应", "domain", domain, "server", selectedServer, "rtt", rtt) - } - // 保存为备选响应 - if !hasBackup { - backupResponse = response - backupRtt = rtt - hasBackup = true - } - break // 找到有效响应,退出循环 - } - } else { - // 更新服务器统计信息(失败) - s.updateServerStats(selectedServer, false, 0) - logger.Debug("服务器请求失败,尝试下一个", "domain", domain, "server", selectedServer, "error", err) - } + // 如果所有服务器都失败,返回最后一个错误 + if lastErrorResponse != nil { + bestResponse = lastErrorResponse + bestRtt = lastErrorRtt + usedDNSServer = lastErrorServer + hasBestResponse = true + logger.Debug("所有服务器都失败,返回最后一个错误响应", "domain", domain, "server", lastErrorServer) } + return bestResponse, bestRtt, usedDNSServer, usedDNSSECServer + case "fastest-ip": - // 最快的IP地址模式 - 使用TCP连接速度测量选择最快服务器 + // 最快的IP地址模式 - 通过ping测试选择最快服务器,只向一个服务器发送请求 // 1. 选择最快的服务器 fastestServer := s.selectFastestServer(selectedUpstreamDNS) if fastestServer != "" { - // 设置超时上下文 - timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond) - defer cancel() + // 从池中获取客户端实例 + client := s.clientPool.Get().(*dns.Client) + // 设置客户端参数 + client.Net = s.resolver.Net + client.UDPSize = s.resolver.UDPSize + client.Timeout = defaultTimeout - // 使用带超时的方式执行Exchange - resultChan := make(chan struct { - response *dns.Msg - rtt time.Duration - err error - }, 1) + // 只向一个服务器发送请求 + response, rtt, err := client.Exchange(r, normalizeDNSServerAddress(fastestServer)) - go func() { - resp, r, e := s.resolver.Exchange(r, normalizeDNSServerAddress(fastestServer)) - resultChan <- struct { - response *dns.Msg - rtt time.Duration - err error - }{resp, r, e} - }() + // 将客户端实例放回池中 + s.clientPool.Put(client) - var response *dns.Msg - var rtt time.Duration - var err error - - select { - case result := <-resultChan: - response, rtt, err = result.response, result.rtt, result.err - case <-timeoutCtx.Done(): - err = timeoutCtx.Err() - } if err == nil && response != nil { // 更新服务器统计信息 s.updateServerStats(fastestServer, true, rtt) @@ -1224,13 +1278,15 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg // 检查是否包含DNSSEC记录 containsDNSSEC := s.hasDNSSECRecords(response) - // 如果启用了DNSSEC且响应包含DNSSEC记录,验证DNSSEC签名 - // 但如果域名匹配不验证DNSSEC的模式,则跳过验证 + // 对于不验证DNSSEC的域名,始终设置AD标志为false + if noDNSSEC { + response.AuthenticatedData = false + } + + // 验证DNSSEC记录(如果需要) if s.config.EnableDNSSEC && containsDNSSEC && !noDNSSEC { // 验证DNSSEC记录 signatureValid := s.verifyDNSSEC(response) - - // 设置AD标志(Authenticated Data) response.AuthenticatedData = signatureValid if signatureValid { @@ -1246,194 +1302,308 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg stats.DNSSECFailed++ }) } - } else if noDNSSEC { - // 对于不验证DNSSEC的域名,始终设置AD标志为false - response.AuthenticatedData = false } - // 如果响应成功或为NXDOMAIN,根据DNSSEC状态选择最佳响应 - if response.Rcode == dns.RcodeSuccess || response.Rcode == dns.RcodeNameError { - if response.Rcode == dns.RcodeSuccess { - // 优先选择带有DNSSEC记录的响应 - if containsDNSSEC { - bestResponse = response - bestRtt = rtt - hasBestResponse = true - hasDNSSECResponse = true - usedDNSServer = fastestServer - // 如果当前使用的服务器是DNSSEC专用服务器,同时设置usedDNSSECServer - for _, dnssecServer := range dnssecServers { - if dnssecServer == fastestServer { - usedDNSSECServer = fastestServer - break - } - } - logger.Debug("找到带DNSSEC的最佳响应", "domain", domain, "server", fastestServer, "rtt", rtt) - } else { - // 没有带DNSSEC的响应时,保存成功响应 - bestResponse = response - bestRtt = rtt - hasBestResponse = true - usedDNSServer = fastestServer - // 如果当前使用的服务器是DNSSEC专用服务器,同时设置usedDNSSECServer - for _, dnssecServer := range dnssecServers { - if dnssecServer == fastestServer { - usedDNSSECServer = fastestServer - break - } - } - logger.Debug("找到最佳响应", "domain", domain, "server", fastestServer, "rtt", rtt) + // 检查响应是否包含有效的记录,如果包含,将Rcode设置为成功 + hasValidRecords := false + if len(response.Answer) > 0 { + hasValidRecords = true + } else if len(response.Ns) > 0 { + hasValidRecords = true + } else if len(response.Extra) > 0 { + for _, rr := range response.Extra { + if rr.Header().Rrtype != dns.TypeOPT { + hasValidRecords = true + break } - } else if response.Rcode == dns.RcodeNameError { - // 处理NXDOMAIN响应 - bestResponse = response - bestRtt = rtt - hasBestResponse = true - usedDNSServer = fastestServer - logger.Debug("找到NXDOMAIN响应", "domain", domain, "server", fastestServer, "rtt", rtt) - } - // 保存为备选响应 - if !hasBackup { - backupResponse = response - backupRtt = rtt - hasBackup = true } } + + if hasValidRecords { + response.Rcode = dns.RcodeSuccess + } + + // 设置最佳响应 + bestResponse = response + bestRtt = rtt + hasBestResponse = true + usedDNSServer = fastestServer + if containsDNSSEC { + hasDNSSECResponse = true + } + if _, isDNSSECServer := s.dnssecServerMap[normalizeDNSServerAddress(fastestServer)]; isDNSSECServer { + usedDNSSECServer = fastestServer + } + logger.Debug("使用最快服务器返回响应", "domain", domain, "server", fastestServer, "rtt", rtt) } else { // 更新服务器统计信息(失败) s.updateServerStats(fastestServer, false, 0) + logger.Debug("最快服务器请求失败", "domain", domain, "server", fastestServer, "error", err) } } default: - // 默认使用并行请求模式 - 添加超时处理和快速响应返回 + // 默认使用并行请求模式 - 实现快速返回和超时机制 responses := make(chan serverResponse, len(selectedUpstreamDNS)) + resultChan := make(chan struct { + response *dns.Msg + rtt time.Duration + usedServer string + usedDnssecServer string + }, 1) var wg sync.WaitGroup - // 超时上下文 - timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond) - defer cancel() - // 向所有上游服务器并行发送请求 for _, upstream := range selectedUpstreamDNS { wg.Add(1) go func(server string) { defer wg.Done() - // 发送请求并获取响应 - response, rtt, err := s.resolver.Exchange(r, normalizeDNSServerAddress(server)) - - select { - case responses <- serverResponse{response, rtt, server, err}: - // 成功发送响应 - case <-timeoutCtx.Done(): - // 超时,忽略此响应 - logger.Debug("并行请求超时", "server", server, "domain", domain) - return + // 创建带有超时的resolver + client := &dns.Client{ + Net: s.resolver.Net, + UDPSize: s.resolver.UDPSize, + Timeout: defaultTimeout, } + + // 发送请求并获取响应,确保服务器地址包含端口号 + response, rtt, err := client.Exchange(r, normalizeDNSServerAddress(server)) + responses <- serverResponse{response, rtt, server, err} }(upstream) } - // 等待所有请求完成或超时 + // 处理响应的协程 + go func() { + var fastestResponse *dns.Msg + var fastestRtt time.Duration = defaultTimeout + var fastestServer string + var fastestDnssecServer string + var fastestHasDnssec bool + var successResponses []*dns.Msg + var nxdomainResponses []*dns.Msg + + // 等待所有请求完成或超时 + timer := time.NewTimer(defaultTimeout) + defer timer.Stop() + + // 处理所有响应 + for { + select { + case resp, ok := <-responses: + if !ok { + // 所有响应都已处理 + goto doneProcessing + } + + if resp.error == nil && resp.response != nil { + // 更新服务器统计信息 + s.updateServerStats(resp.server, true, resp.rtt) + + // 检查是否包含DNSSEC记录 + containsDNSSEC := s.hasDNSSECRecords(resp.response) + + // 对于不验证DNSSEC的域名,始终设置AD标志为false + if noDNSSEC { + resp.response.AuthenticatedData = false + } + + dnssecServerForResponse := "" + if _, isDNSSECServer := s.dnssecServerMap[normalizeDNSServerAddress(resp.server)]; isDNSSECServer { + dnssecServerForResponse = resp.server + } + + // 如果响应成功或为NXDOMAIN + if resp.response.Rcode == dns.RcodeSuccess || resp.response.Rcode == dns.RcodeNameError { + // 按Rcode分类添加到不同列表 + if resp.response.Rcode == dns.RcodeSuccess { + successResponses = append(successResponses, resp.response) + } else { + nxdomainResponses = append(nxdomainResponses, resp.response) + } + + // 快速返回逻辑:找到第一个有效响应或更快的响应 + if resp.response.Rcode == dns.RcodeSuccess { + // 优先选择带有DNSSEC的响应 + if containsDNSSEC { + // 如果这是第一个DNSSEC响应,或者比当前最快的DNSSEC响应更快 + if !fastestHasDnssec || resp.rtt < fastestRtt { + fastestResponse = resp.response + fastestRtt = resp.rtt + fastestServer = resp.server + fastestDnssecServer = dnssecServerForResponse + fastestHasDnssec = true + + // 只对将要返回的响应进行DNSSEC验证 + if s.config.EnableDNSSEC && containsDNSSEC && !noDNSSEC { + // 验证DNSSEC记录 + signatureValid := s.verifyDNSSEC(fastestResponse) + + // 设置AD标志(Authenticated Data) + fastestResponse.AuthenticatedData = signatureValid + + if signatureValid { + // 更新DNSSEC验证成功计数 + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + stats.DNSSECSuccess++ + }) + } else { + // 更新DNSSEC验证失败计数 + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + stats.DNSSECFailed++ + }) + } + } + + // 发送结果,快速返回 + resultChan <- struct { + response *dns.Msg + rtt time.Duration + usedServer string + usedDnssecServer string + }{fastestResponse, fastestRtt, fastestServer, fastestDnssecServer} + } + } else { + // 非DNSSEC响应,只有在还没有找到DNSSEC响应且当前响应更快时才更新 + if !fastestHasDnssec && resp.rtt < fastestRtt { + fastestResponse = resp.response + fastestRtt = resp.rtt + fastestServer = resp.server + fastestDnssecServer = dnssecServerForResponse + + // 检查是否包含DNSSEC记录 + respContainsDNSSEC := s.hasDNSSECRecords(fastestResponse) + + // 只对将要返回的响应进行DNSSEC验证 + if s.config.EnableDNSSEC && respContainsDNSSEC && !noDNSSEC { + // 验证DNSSEC记录 + signatureValid := s.verifyDNSSEC(fastestResponse) + + // 设置AD标志(Authenticated Data) + fastestResponse.AuthenticatedData = signatureValid + + if signatureValid { + // 更新DNSSEC验证成功计数 + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + stats.DNSSECSuccess++ + }) + } else { + // 更新DNSSEC验证失败计数 + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + stats.DNSSECFailed++ + }) + } + } + + // 发送结果,快速返回 + resultChan <- struct { + response *dns.Msg + rtt time.Duration + usedServer string + usedDnssecServer string + }{fastestResponse, fastestRtt, fastestServer, fastestDnssecServer} + } + } + } else if resp.response.Rcode == dns.RcodeNameError { + // NXDOMAIN响应,只有在还没有找到响应或当前响应更快时才更新 + if !fastestHasDnssec && resp.rtt < fastestRtt { + fastestResponse = resp.response + fastestRtt = resp.rtt + fastestServer = resp.server + fastestDnssecServer = dnssecServerForResponse + + // 检查是否包含DNSSEC记录 + respContainsDNSSEC := s.hasDNSSECRecords(fastestResponse) + + // 只对将要返回的响应进行DNSSEC验证 + if s.config.EnableDNSSEC && respContainsDNSSEC && !noDNSSEC { + // 验证DNSSEC记录 + signatureValid := s.verifyDNSSEC(fastestResponse) + + // 设置AD标志(Authenticated Data) + fastestResponse.AuthenticatedData = signatureValid + + if signatureValid { + // 更新DNSSEC验证成功计数 + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + stats.DNSSECSuccess++ + }) + } else { + // 更新DNSSEC验证失败计数 + s.updateStats(func(stats *Stats) { + stats.DNSSECQueries++ + stats.DNSSECFailed++ + }) + } + } + + // 发送结果,快速返回 + resultChan <- struct { + response *dns.Msg + rtt time.Duration + usedServer string + usedDnssecServer string + }{fastestResponse, fastestRtt, fastestServer, fastestDnssecServer} + } + } + } else { + // 更新备选响应,确保总有一个可用的响应 + if resp.response != nil { + if !hasBackup { + // 第一次保存备选响应 + backupResponse = resp.response + backupRtt = resp.rtt + hasBackup = true + } + } + } + } else { + // 更新服务器统计信息(失败) + s.updateServerStats(resp.server, false, 0) + } + case <-timer.C: + // 超时,停止等待更多响应 + goto doneProcessing + } + } + + doneProcessing: + // 如果还没有发送结果,发送最快的响应 + if fastestResponse != nil { + resultChan <- struct { + response *dns.Msg + rtt time.Duration + usedServer string + usedDnssecServer string + }{fastestResponse, fastestRtt, fastestServer, fastestDnssecServer} + } + close(resultChan) + }() + + // 等待所有请求完成(不阻塞主流程) go func() { wg.Wait() close(responses) }() - // 等待上下文超时,防止泄漏 - go func() { - <-timeoutCtx.Done() - }() - - // 处理所有响应 - for resp := range responses { - if resp.error == nil && resp.response != nil { - - // 检查是否包含DNSSEC记录 - containsDNSSEC := s.hasDNSSECRecords(resp.response) - - // 如果启用了DNSSEC且响应包含DNSSEC记录,验证DNSSEC签名 - // 但如果域名匹配不验证DNSSEC的模式,则跳过验证 - if s.config.EnableDNSSEC && containsDNSSEC && !noDNSSEC { - // 验证DNSSEC记录 - signatureValid := s.verifyDNSSEC(resp.response) - - // 设置AD标志(Authenticated Data) - resp.response.AuthenticatedData = signatureValid - - if signatureValid { - // 更新DNSSEC验证成功计数 - s.updateStats(func(stats *Stats) { - stats.DNSSECQueries++ - stats.DNSSECSuccess++ - }) - } else { - // 更新DNSSEC验证失败计数 - s.updateStats(func(stats *Stats) { - stats.DNSSECQueries++ - stats.DNSSECFailed++ - }) - } - } else if noDNSSEC { - // 对于不验证DNSSEC的域名,始终设置AD标志为false - resp.response.AuthenticatedData = false - } - - // 如果响应成功或为NXDOMAIN,根据DNSSEC状态选择最佳响应 - if resp.response.Rcode == dns.RcodeSuccess || resp.response.Rcode == dns.RcodeNameError { - if resp.response.Rcode == dns.RcodeSuccess { - // 优先选择带有DNSSEC记录的响应 - if containsDNSSEC { - bestResponse = resp.response - bestRtt = resp.rtt - hasBestResponse = true - hasDNSSECResponse = true - usedDNSServer = resp.server - // 如果当前使用的服务器是DNSSEC专用服务器,同时设置usedDNSSECServer - for _, dnssecServer := range dnssecServers { - if dnssecServer == resp.server { - usedDNSSECServer = resp.server - break - } - } - logger.Debug("找到带DNSSEC的最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) - } else if !hasBestResponse { - // 没有带DNSSEC的响应时,保存第一个成功响应 - bestResponse = resp.response - bestRtt = resp.rtt - hasBestResponse = true - usedDNSServer = resp.server - // 如果当前使用的服务器是DNSSEC专用服务器,同时设置usedDNSSECServer - for _, dnssecServer := range dnssecServers { - if dnssecServer == resp.server { - usedDNSSECServer = resp.server - break - } - } - logger.Debug("找到最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) - } - } else if resp.response.Rcode == dns.RcodeNameError { - // 处理NXDOMAIN响应 - // 如果还没有最佳响应,或者最佳响应也是NXDOMAIN,优先选择更快的NXDOMAIN响应 - if !hasBestResponse || bestResponse.Rcode == dns.RcodeNameError { - // 如果还没有最佳响应,或者当前响应更快,更新最佳响应 - if !hasBestResponse || resp.rtt < bestRtt { - bestResponse = resp.response - bestRtt = resp.rtt - hasBestResponse = true - usedDNSServer = resp.server - logger.Debug("找到NXDOMAIN最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt) - } - } - } - // 保存为备选响应 - if !hasBackup { - backupResponse = resp.response - backupRtt = resp.rtt - hasBackup = true - } - } - } + // 等待结果或超时 + select { + case result := <-resultChan: + // 快速返回结果 + bestResponse = result.response + bestRtt = result.rtt + usedDNSServer = result.usedServer + usedDNSSECServer = result.usedDnssecServer + hasBestResponse = true + hasDNSSECResponse = s.hasDNSSECRecords(result.response) + logger.Debug("快速返回DNS响应", "domain", domain, "server", result.usedServer, "rtt", result.rtt, "dnssec", hasDNSSECResponse) + case <-time.After(defaultTimeout): + // 超时,使用备选响应 + logger.Debug("并行请求超时", "domain", domain, "timeout", defaultTimeout) } } @@ -1450,10 +1620,6 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg // 无论查询模式是什么,DNSSEC验证都只使用加权随机选择一个服务器 selectedDnssecServer := s.selectWeightedRandomServer(dnssecServers) if selectedDnssecServer != "" { - // 设置超时上下文 - timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond) - defer cancel() - // 使用带超时的方式执行Exchange resultChan := make(chan struct { response *dns.Msg @@ -1462,7 +1628,13 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg }, 1) go func() { - response, rtt, err := s.resolver.Exchange(r, normalizeDNSServerAddress(selectedDnssecServer)) + // 创建带有超时的resolver + client := &dns.Client{ + Net: s.resolver.Net, + UDPSize: s.resolver.UDPSize, + Timeout: defaultTimeout, + } + response, rtt, err := client.Exchange(r, normalizeDNSServerAddress(selectedDnssecServer)) resultChan <- struct { response *dns.Msg rtt time.Duration @@ -1474,11 +1646,14 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg var rtt time.Duration var err error + // 使用超时获取结果 select { case result := <-resultChan: response, rtt, err = result.response, result.rtt, result.err - case <-timeoutCtx.Done(): - err = timeoutCtx.Err() + case <-time.After(defaultTimeout): + // 超时,不再等待 + logger.Debug("DNSSEC专用服务器请求超时", "domain", domain, "server", selectedDnssecServer, "timeout", defaultTimeout) + return bestResponse, bestRtt, usedDNSServer, usedDNSSECServer } if err == nil && response != nil { @@ -1548,10 +1723,6 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg // 选择一个upstreamDNS服务器进行解析(使用加权随机算法) localServer := s.selectWeightedRandomServer(s.config.UpstreamDNS) if localServer != "" { - // 设置超时上下文 - timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond) - defer cancel() - // 使用带超时的方式执行Exchange resultChan := make(chan struct { response *dns.Msg @@ -1572,12 +1743,10 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg var rtt time.Duration var err error - select { - case result := <-resultChan: - localResponse, rtt, err = result.response, result.rtt, result.err - case <-timeoutCtx.Done(): - err = timeoutCtx.Err() - } + // 直接获取结果,不使用上下文超时 + result := <-resultChan + localResponse, rtt, err = result.response, result.rtt, result.err + if err == nil && localResponse != nil { // 更新服务器统计信息 s.updateServerStats(localServer, true, rtt) @@ -1632,6 +1801,81 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg s.updateDomainDNSSECStatus(domain, false) } + // 检查响应是否包含CNAME记录,需要确保返回完整的解析链 + if bestResponse != nil && bestResponse.Rcode == dns.RcodeSuccess { + // 处理多级CNAME,直到获取到最终的A/AAAA记录 + maxCNAMELevels := 5 // 限制最大CNAME解析级数,防止循环解析 + currentLevel := 0 + + // 循环处理CNAME记录 + for currentLevel < maxCNAMELevels { + // 检查是否包含CNAME记录 + var hasCNAME bool + var cnameTarget string + + // 检查Answer部分,查找CNAME记录 + for _, rr := range bestResponse.Answer { + if cname, ok := rr.(*dns.CNAME); ok { + hasCNAME = true + cnameTarget = cname.Target + } + } + + // 如果不包含CNAME记录,或者已经包含最终的A/AAAA记录,退出循环 + var hasFinalRecord bool + for _, rr := range bestResponse.Answer { + switch rr.Header().Rrtype { + case dns.TypeA, dns.TypeAAAA: + hasFinalRecord = true + break + } + } + + if !hasCNAME || hasFinalRecord { + break // 没有CNAME记录,或者已经有最终记录,退出循环 + } + + // 如果包含CNAME记录但没有最终IP,继续查询 + logger.Debug("响应包含CNAME但没有最终IP,继续查询", "domain", domain, "cname", cnameTarget, "level", currentLevel) + + // 创建新的查询请求,查询CNAME指向的域名 + cnameQuery := r.Copy() + cnameQuery.Question[0].Name = cnameTarget + + // 继续查询CNAME指向的域名 + cnameResponse, _, cnameDnsServer, cnameDnssecServer := s.forwardDNSRequestWithCache(cnameQuery, cnameTarget) + if cnameResponse != nil && cnameResponse.Rcode == dns.RcodeSuccess { + // 合并CNAME响应的Answer部分到主响应 + bestResponse.Answer = append(bestResponse.Answer, cnameResponse.Answer...) + // 合并CNAME响应的Ns部分到主响应 + bestResponse.Ns = append(bestResponse.Ns, cnameResponse.Ns...) + // 合并CNAME响应的Extra部分到主响应,排除OPT记录 + for _, rr := range cnameResponse.Extra { + if rr.Header().Rrtype != dns.TypeOPT { + bestResponse.Extra = append(bestResponse.Extra, rr) + } + } + // 更新使用的DNS服务器信息 + if cnameDnsServer != "" { + usedDNSServer = cnameDnsServer + } + if cnameDnssecServer != "" { + usedDNSSECServer = cnameDnssecServer + } + } else { + // 查询失败,退出循环 + break + } + + // 增加CNAME解析级数 + currentLevel++ + } + + if currentLevel >= maxCNAMELevels { + logger.Warn("CNAME解析级数超过限制,可能存在循环解析", "domain", domain, "maxLevels", maxCNAMELevels) + } + } + s.updateStats(func(stats *Stats) { stats.Allowed++ }) @@ -1671,19 +1915,31 @@ func (s *Server) forwardDNSRequest(w dns.ResponseWriter, r *dns.Msg, domain stri // updateBlockedDomainStats 更新被屏蔽域名统计 func (s *Server) updateBlockedDomainStats(domain string) { - // 更新被屏蔽域名计数 - s.blockedDomainsMutex.Lock() - defer s.blockedDomainsMutex.Unlock() + // 先尝试读锁,检查条目是否存在 + s.blockedDomainsMutex.RLock() + entry, exists := s.blockedDomains[domain] + s.blockedDomainsMutex.RUnlock() - if entry, exists := s.blockedDomains[domain]; exists { - entry.Count++ - entry.LastSeen = time.Now() + if exists { + // 使用原子操作更新计数和时间戳 + atomic.AddInt64(&entry.Count, 1) + atomic.StoreInt64(&entry.LastSeen, time.Now().UnixNano()) } else { - s.blockedDomains[domain] = &BlockedDomain{ - Domain: domain, - Count: 1, - LastSeen: time.Now(), + // 获取写锁,创建新条目 + s.blockedDomainsMutex.Lock() + // 再次检查,避免竞态条件 + if entry, exists := s.blockedDomains[domain]; exists { + atomic.AddInt64(&entry.Count, 1) + atomic.StoreInt64(&entry.LastSeen, time.Now().UnixNano()) + } else { + s.blockedDomains[domain] = &BlockedDomain{ + Domain: domain, + Count: 1, + LastSeen: time.Now().UnixNano(), + DNSSEC: false, + } } + s.blockedDomainsMutex.Unlock() } // 更新统计数据 @@ -1710,86 +1966,62 @@ func (s *Server) updateBlockedDomainStats(domain string) { // updateClientStats 更新客户端统计 func (s *Server) updateClientStats(ip string) { - s.clientStatsMutex.Lock() - defer s.clientStatsMutex.Unlock() + // 先尝试读锁,检查条目是否存在 + s.clientStatsMutex.RLock() + entry, exists := s.clientStats[ip] + s.clientStatsMutex.RUnlock() - if entry, exists := s.clientStats[ip]; exists { - entry.Count++ - entry.LastSeen = time.Now() + if exists { + // 使用原子操作更新计数和时间戳 + atomic.AddInt64(&entry.Count, 1) + atomic.StoreInt64(&entry.LastSeen, time.Now().UnixNano()) } else { - s.clientStats[ip] = &ClientStats{ - IP: ip, - Count: 1, - LastSeen: time.Now(), + // 获取写锁,创建新条目 + s.clientStatsMutex.Lock() + // 再次检查,避免竞态条件 + if entry, exists := s.clientStats[ip]; exists { + atomic.AddInt64(&entry.Count, 1) + atomic.StoreInt64(&entry.LastSeen, time.Now().UnixNano()) + } else { + s.clientStats[ip] = &ClientStats{ + IP: ip, + Count: 1, + LastSeen: time.Now().UnixNano(), + } } + s.clientStatsMutex.Unlock() } } // hasDNSSECRecords 检查响应是否包含DNSSEC记录 func (s *Server) hasDNSSECRecords(response *dns.Msg) bool { - // 检查响应中是否包含DNSSEC相关记录(DNSKEY、RRSIG、DS、NSEC、NSEC3等) - for _, rr := range response.Answer { - if _, ok := rr.(*dns.DNSKEY); ok { - return true - } - if _, ok := rr.(*dns.RRSIG); ok { - return true - } - if _, ok := rr.(*dns.DS); ok { - return true - } - if _, ok := rr.(*dns.NSEC); ok { - return true - } - if _, ok := rr.(*dns.NSEC3); ok { - return true - } - } - for _, rr := range response.Ns { - if _, ok := rr.(*dns.DNSKEY); ok { - return true - } - if _, ok := rr.(*dns.RRSIG); ok { - return true - } - if _, ok := rr.(*dns.DS); ok { - return true - } - if _, ok := rr.(*dns.NSEC); ok { - return true - } - if _, ok := rr.(*dns.NSEC3); ok { - return true - } - } - for _, rr := range response.Extra { - if _, ok := rr.(*dns.DNSKEY); ok { - return true - } - if _, ok := rr.(*dns.RRSIG); ok { - return true - } - if _, ok := rr.(*dns.DS); ok { - return true - } - if _, ok := rr.(*dns.NSEC); ok { - return true - } - if _, ok := rr.(*dns.NSEC3); ok { - return true - } - } - return false + // 直接调用包内的hasDNSSECRecords函数,避免重复代码 + return hasDNSSECRecords(response) } // verifyDNSSEC 验证DNSSEC签名 func (s *Server) verifyDNSSEC(response *dns.Msg) bool { - // 提取DNSKEY和RRSIG记录 + // 提取DNSKEY和RRSIG记录,并按类型和名称组织记录 dnskeys := make(map[uint16]*dns.DNSKEY) // KeyTag -> DNSKEY rrsigs := make([]*dns.RRSIG, 0) + // 按 (名称, 类型) 组织记录集,用于快速查找 + rrSets := make(map[string]map[uint16][]dns.RR) // name -> type -> records - // 从响应中提取所有DNSKEY和RRSIG记录 - for _, rr := range response.Answer { + // 定义处理单个记录的函数 + processRecord := func(rr dns.RR) { + num := rr.Header().Rrtype + name := rr.Header().Name + + // 组织记录集 + if _, exists := rrSets[name]; !exists { + rrSets[name] = make(map[uint16][]dns.RR) + } + if _, exists := rrSets[name][num]; !exists { + rrSets[name][num] = make([]dns.RR, 0) + } + rrSets[name][num] = append(rrSets[name][num], rr) + + // 特别处理DNSKEY和RRSIG if dnskey, ok := rr.(*dns.DNSKEY); ok { tag := dnskey.KeyTag() dnskeys[tag] = dnskey @@ -1797,21 +2029,16 @@ func (s *Server) verifyDNSSEC(response *dns.Msg) bool { rrsigs = append(rrsigs, rrsig) } } + + // 一次遍历所有响应部分,同时完成记录收集和组织 + for _, rr := range response.Answer { + processRecord(rr) + } for _, rr := range response.Ns { - if dnskey, ok := rr.(*dns.DNSKEY); ok { - tag := dnskey.KeyTag() - dnskeys[tag] = dnskey - } else if rrsig, ok := rr.(*dns.RRSIG); ok { - rrsigs = append(rrsigs, rrsig) - } + processRecord(rr) } for _, rr := range response.Extra { - if dnskey, ok := rr.(*dns.DNSKEY); ok { - tag := dnskey.KeyTag() - dnskeys[tag] = dnskey - } else if rrsig, ok := rr.(*dns.RRSIG); ok { - rrsigs = append(rrsigs, rrsig) - } + processRecord(rr) } // 如果没有RRSIG记录,验证失败 @@ -1836,18 +2063,10 @@ func (s *Server) verifyDNSSEC(response *dns.Msg) bool { continue } - // 收集需要验证的记录集 - rrset := make([]dns.RR, 0) - for _, rr := range response.Answer { - if rr.Header().Name == rrsig.Header().Name && rr.Header().Rrtype == rrsig.TypeCovered { - rrset = append(rrset, rr) - } - } - for _, rr := range response.Ns { - if rr.Header().Name == rrsig.Header().Name && rr.Header().Rrtype == rrsig.TypeCovered { - rrset = append(rrset, rr) - } - } + // 快速查找需要验证的记录集 + name := rrsig.Header().Name + typeCovered := rrsig.TypeCovered + rrset := rrSets[name][typeCovered] // 验证签名 if len(rrset) > 0 { @@ -1880,30 +2099,44 @@ func (s *Server) updateDomainDNSSECStatus(domain string, dnssec bool) { s.resolvedDomains[domain] = &BlockedDomain{ Domain: domain, Count: 1, - LastSeen: time.Now(), + LastSeen: time.Now().UnixNano(), DNSSEC: dnssec, } } - // 更新domainDNSSECStatus映射 + // 更新domainDNSSECStatus映射(使用单独的锁) + s.domainDNSSECStatusMutex.Lock() s.domainDNSSECStatus[domain] = dnssec + s.domainDNSSECStatusMutex.Unlock() } // updateResolvedDomainStats 更新解析域名统计 func (s *Server) updateResolvedDomainStats(domain string) { - s.resolvedDomainsMutex.Lock() - defer s.resolvedDomainsMutex.Unlock() + // 先尝试读锁,检查条目是否存在 + s.resolvedDomainsMutex.RLock() + entry, exists := s.resolvedDomains[domain] + s.resolvedDomainsMutex.RUnlock() - if entry, exists := s.resolvedDomains[domain]; exists { - entry.Count++ - entry.LastSeen = time.Now() + if exists { + // 使用原子操作更新计数和时间戳 + atomic.AddInt64(&entry.Count, 1) + atomic.StoreInt64(&entry.LastSeen, time.Now().UnixNano()) } else { - s.resolvedDomains[domain] = &BlockedDomain{ - Domain: domain, - Count: 1, - LastSeen: time.Now(), - DNSSEC: false, + // 获取写锁,创建新条目 + s.resolvedDomainsMutex.Lock() + // 再次检查,避免竞态条件 + if entry, exists := s.resolvedDomains[domain]; exists { + atomic.AddInt64(&entry.Count, 1) + atomic.StoreInt64(&entry.LastSeen, time.Now().UnixNano()) + } else { + s.resolvedDomains[domain] = &BlockedDomain{ + Domain: domain, + Count: 1, + LastSeen: time.Now().UnixNano(), + DNSSEC: false, + } } + s.resolvedDomainsMutex.Unlock() } } @@ -1913,22 +2146,26 @@ func (s *Server) getServerStats(server string) *ServerStats { stats, exists := s.serverStats[server] s.serverStatsMutex.RUnlock() - if !exists { - // 创建新的服务器统计信息 - stats = &ServerStats{ - SuccessCount: 0, - FailureCount: 0, - LastResponse: time.Now(), - ResponseTime: 0, - ConnectionSpeed: 0, - } - - // 加锁更新服务器统计信息 - s.serverStatsMutex.Lock() - s.serverStats[server] = stats - s.serverStatsMutex.Unlock() + if exists { + return stats } + s.serverStatsMutex.Lock() + defer s.serverStatsMutex.Unlock() + + if stats, exists := s.serverStats[server]; exists { + return stats + } + + stats = &ServerStats{ + SuccessCount: 0, + FailureCount: 0, + LastResponse: time.Now(), + ResponseTime: 0, + ConnectionSpeed: 0, + } + + s.serverStats[server] = stats return stats } @@ -1936,27 +2173,32 @@ func (s *Server) getServerStats(server string) *ServerStats { func (s *Server) updateServerStats(server string, success bool, rtt time.Duration) { stats := s.getServerStats(server) - s.serverStatsMutex.Lock() - defer s.serverStatsMutex.Unlock() - - // 更新统计信息 - stats.LastResponse = time.Now() - + // 使用原子操作更新成功和失败计数 if success { - stats.SuccessCount++ + successCount := atomic.AddInt64(&stats.SuccessCount, 1) + + // 只在需要更新平均响应时间时获取锁 + s.serverStatsMutex.Lock() + stats.LastResponse = time.Now() + // 更新平均响应时间(简单移动平均) - // 将所有值转换为纳秒进行计算,然后再转换回Duration - if stats.SuccessCount == 1 { + if successCount == 1 { // 第一次成功,直接使用当前响应时间 stats.ResponseTime = rtt } else { // 使用纳秒进行计算以避免类型不匹配 - prevTotal := stats.ResponseTime.Nanoseconds() * (stats.SuccessCount - 1) + prevTotal := stats.ResponseTime.Nanoseconds() * (successCount - 1) newTotal := prevTotal + rtt.Nanoseconds() - stats.ResponseTime = time.Duration(newTotal / stats.SuccessCount) + stats.ResponseTime = time.Duration(newTotal / successCount) } + s.serverStatsMutex.Unlock() } else { - stats.FailureCount++ + atomic.AddInt64(&stats.FailureCount, 1) + + // 只更新LastResponse时获取锁 + s.serverStatsMutex.Lock() + stats.LastResponse = time.Now() + s.serverStatsMutex.Unlock() } } @@ -1970,80 +2212,81 @@ func (s *Server) selectWeightedRandomServer(servers []string) string { return servers[0] } - // 计算每个服务器的权重 type serverWeight struct { - server string - weight int64 + server string + weight int64 + responseTime time.Duration + successCount int64 + failureCount int64 } var totalWeight int64 - weights := make([]serverWeight, 0, len(servers)) - - // 获取所有服务器的平均响应时间,用于归一化 var totalResponseTime time.Duration - validServers := 0 + var validServers int + var currentWeight int64 - for _, server := range servers { + serversInfo := make([]serverWeight, len(servers)) + + for i, server := range servers { stats := s.getServerStats(server) + + serversInfo[i] = serverWeight{ + server: server, + responseTime: stats.ResponseTime, + successCount: atomic.LoadInt64(&stats.SuccessCount), + failureCount: atomic.LoadInt64(&stats.FailureCount), + } + if stats.ResponseTime > 0 { totalResponseTime += stats.ResponseTime validServers++ } } - // 计算平均响应时间基准值 var avgResponseTime time.Duration if validServers > 0 { avgResponseTime = totalResponseTime / time.Duration(validServers) } else { - avgResponseTime = 1 * time.Second // 默认基准值 + avgResponseTime = 1 * time.Second } - for _, server := range servers { - stats := s.getServerStats(server) + var randomGen = rand.New(rand.NewSource(time.Now().UnixNano())) - // 计算基础权重:成功次数 - 失败次数 * 2(失败权重更高) - // 确保权重至少为1 - baseWeight := stats.SuccessCount - stats.FailureCount*2 + for i := range serversInfo { + baseWeight := serversInfo[i].successCount - serversInfo[i].failureCount*2 if baseWeight < 1 { baseWeight = 1 } - // 计算响应时间调整因子:响应时间越短,因子越高 - // 如果没有响应时间数据,使用默认值1 - var responseFactor float64 = 1.0 - if stats.ResponseTime > 0 { - // 使用平均响应时间作为基准,计算调整因子 - // 响应时间越短,因子越高,最高为2.0,最低为0.5 - responseFactor = float64(avgResponseTime) / float64(stats.ResponseTime) - // 限制调整因子的范围,避免权重波动过大 - if responseFactor > 2.0 { - responseFactor = 2.0 - } else if responseFactor < 0.5 { - responseFactor = 0.5 + var responseFactor int64 = 100 + if serversInfo[i].responseTime > 0 { + if serversInfo[i].responseTime < avgResponseTime { + factor := (avgResponseTime.Nanoseconds() * 200) / serversInfo[i].responseTime.Nanoseconds() + if factor > 200 { + factor = 200 + } + responseFactor = factor + } else { + factor := (avgResponseTime.Nanoseconds() * 200) / serversInfo[i].responseTime.Nanoseconds() + if factor < 50 { + factor = 50 + } + responseFactor = factor } } - // 综合计算最终权重,四舍五入到整数 - finalWeight := int64(float64(baseWeight) * responseFactor) - // 确保最终权重至少为1 + finalWeight := (baseWeight * responseFactor) / 100 if finalWeight < 1 { finalWeight = 1 } - weights = append(weights, serverWeight{server, finalWeight}) + serversInfo[i].weight = finalWeight totalWeight += finalWeight } - // 随机选择一个权重 - random := time.Now().UnixNano() % totalWeight - if random < 0 { - random += totalWeight - } + random := randomGen.Int63n(totalWeight) - // 选择对应的服务器 - var currentWeight int64 - for _, sw := range weights { + for _, sw := range serversInfo { currentWeight += sw.weight if random < currentWeight { return sw.server @@ -2056,28 +2299,22 @@ func (s *Server) selectWeightedRandomServer(servers []string) string { // measureServerSpeed 测量服务器TCP连接速度 func (s *Server) measureServerSpeed(server string) time.Duration { - // 提取服务器地址和端口 addr := server if !strings.Contains(server, ":") { addr = server + ":53" } - // 测量TCP连接时间 startTime := time.Now() conn, err := net.DialTimeout("tcp", addr, 2*time.Second) if err != nil { - // 连接失败,返回最大持续时间 return 2 * time.Second } defer conn.Close() - // 计算连接建立时间 connTime := time.Since(startTime) - // 更新服务器连接速度 stats := s.getServerStats(server) s.serverStatsMutex.Lock() - // 使用指数移动平均更新连接速度 stats.ConnectionSpeed = (stats.ConnectionSpeed*3 + connTime) / 4 s.serverStatsMutex.Unlock() @@ -2137,6 +2374,23 @@ func (s *Server) selectFastestServer(servers []string) string { return fastestServer } +// calculateAvgResponseTime 计算平均响应时间 +func calculateAvgResponseTime(totalResponseTime int64, queries int64) float64 { + if queries <= 0 { + return 0 + } + + avg := float64(totalResponseTime) / float64(queries) + avg = float64(math.Round(avg)) + + // 限制平均响应时间的范围 + if avg > 60000 { + avg = 60000 + } + + return avg +} + // updateStats 更新统计信息 func (s *Server) updateStats(update func(*Stats)) { s.statsMutex.Lock() @@ -2146,14 +2400,10 @@ func (s *Server) updateStats(update func(*Stats)) { // addQueryLog 添加查询日志 func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime int64, result, blockRule, blockType string, fromCache, dnssec, edns bool, dnsServer, dnssecServer string, answers []DNSAnswer, responseCode int) { - // 获取IP地理位置 - location := s.getIpGeolocation(clientIP) - // 创建日志记录 log := QueryLog{ Timestamp: time.Now(), ClientIP: clientIP, - Location: location, Domain: domain, QueryType: queryType, ResponseTime: responseTime, @@ -2169,16 +2419,13 @@ func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime in ResponseCode: responseCode, } - // 添加到日志列表 - s.queryLogsMutex.Lock() - defer s.queryLogsMutex.Unlock() - - // 插入到列表开头 - s.queryLogs = append([]QueryLog{log}, s.queryLogs...) - - // 限制日志数量 - if len(s.queryLogs) > s.maxQueryLogs { - s.queryLogs = s.queryLogs[:s.maxQueryLogs] + // 发送到日志处理通道(非阻塞) + select { + case s.logChannel <- log: + // 日志发送成功 + default: + // 通道已满,丢弃日志以避免阻塞请求处理 + logger.Warn("日志通道已满,丢弃一条日志记录") } } @@ -2367,10 +2614,16 @@ func (s *Server) GetTopBlockedDomains(limit int) []BlockedDomain { s.blockedDomainsMutex.RLock() defer s.blockedDomainsMutex.RUnlock() - // 转换为切片 + // 计算30天前的时间戳 + thirtyDaysAgo := time.Now().Add(-30 * 24 * time.Hour).Unix() + + // 转换为切片并过滤最近30天的数据 domains := make([]BlockedDomain, 0, len(s.blockedDomains)) for _, entry := range s.blockedDomains { - domains = append(domains, *entry) + // 只包含最近30天的数据 + if entry.LastSeen >= thirtyDaysAgo { + domains = append(domains, *entry) + } } // 按计数排序 @@ -2390,10 +2643,16 @@ func (s *Server) GetTopResolvedDomains(limit int) []BlockedDomain { s.resolvedDomainsMutex.RLock() defer s.resolvedDomainsMutex.RUnlock() - // 转换为切片 + // 计算30天前的时间戳 + thirtyDaysAgo := time.Now().Add(-30 * 24 * time.Hour).Unix() + + // 转换为切片并过滤最近30天的数据 domains := make([]BlockedDomain, 0, len(s.resolvedDomains)) for _, entry := range s.resolvedDomains { - domains = append(domains, *entry) + // 只包含最近30天的数据 + if entry.LastSeen >= thirtyDaysAgo { + domains = append(domains, *entry) + } } // 按数量排序 @@ -2421,7 +2680,7 @@ func (s *Server) GetRecentBlockedDomains(limit int) []BlockedDomain { // 按时间排序 sort.Slice(domains, func(i, j int) bool { - return domains[i].LastSeen.After(domains[j].LastSeen) + return domains[i].LastSeen > domains[j].LastSeen }) // 返回限制数量 @@ -2542,83 +2801,6 @@ func isPrivateIP(ip string) bool { return false } -// getIpGeolocation 获取IP地址的地理位置信息 -func (s *Server) getIpGeolocation(ip string) string { - // 检查IP是否为本地或内网地址 - if isPrivateIP(ip) { - return "内网 内网" - } - - // 先检查缓存 - s.ipGeolocationCacheMutex.RLock() - geo, exists := s.ipGeolocationCache[ip] - s.ipGeolocationCacheMutex.RUnlock() - - // 如果缓存存在且未过期,直接返回 - if exists && time.Now().Before(geo.Expiry) { - return fmt.Sprintf("%s %s", geo.Country, geo.City) - } - - // 缓存不存在或已过期,从API获取 - geoInfo, err := s.fetchIpGeolocationFromAPI(ip) - if err != nil { - logger.Error("获取IP地理位置失败", "ip", ip, "error", err) - return "未知 未知" - } - - // 保存到缓存 - s.ipGeolocationCacheMutex.Lock() - s.ipGeolocationCache[ip] = &IPGeolocation{ - Country: geoInfo["country"].(string), - City: geoInfo["city"].(string), - Expiry: time.Now().Add(s.ipGeolocationCacheTTL), - } - s.ipGeolocationCacheMutex.Unlock() - - // 返回格式化的地理位置 - return fmt.Sprintf("%s %s", geoInfo["country"].(string), geoInfo["city"].(string)) -} - -// fetchIpGeolocationFromAPI 从第三方API获取IP地理位置信息 -func (s *Server) fetchIpGeolocationFromAPI(ip string) (map[string]interface{}, error) { - // 使用ip-api.com获取IP地理位置信息 - url := fmt.Sprintf("http://ip-api.com/json/%s?fields=country,city", ip) - resp, err := http.Get(url) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - // 读取响应内容 - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - // 解析JSON响应 - var result map[string]interface{} - err = json.Unmarshal(body, &result) - if err != nil { - return nil, err - } - - // 检查API返回状态 - status, ok := result["status"].(string) - if !ok || status != "success" { - return nil, fmt.Errorf("API返回错误状态: %v", result) - } - - // 确保国家和城市字段存在 - if _, ok := result["country"]; !ok { - result["country"] = "未知" - } - if _, ok := result["city"]; !ok { - result["city"] = "未知" - } - - return result, nil -} - // loadStatsData 从文件加载统计数据 func (s *Server) loadStatsData() { // 检查文件是否存在 @@ -2640,8 +2822,36 @@ func (s *Server) loadStatsData() { // 恢复统计数据 s.statsMutex.Lock() if statsData.Stats != nil { - s.stats = statsData.Stats - // 确保使用当前配置中的EnableDNSSEC值,覆盖从文件加载的值 + // 只恢复有效数据,避免破坏统计关系 + s.stats.Queries += statsData.Stats.Queries + s.stats.Blocked += statsData.Stats.Blocked + s.stats.Allowed += statsData.Stats.Allowed + s.stats.Errors += statsData.Stats.Errors + s.stats.TotalResponseTime += statsData.Stats.TotalResponseTime + s.stats.DNSSECQueries += statsData.Stats.DNSSECQueries + s.stats.DNSSECSuccess += statsData.Stats.DNSSECSuccess + s.stats.DNSSECFailed += statsData.Stats.DNSSECFailed + + // 重新计算平均响应时间,确保一致性 + if s.stats.Queries > 0 { + s.stats.AvgResponseTime = float64(s.stats.TotalResponseTime) / float64(s.stats.Queries) + // 限制平均响应时间的范围,避免显示异常大的值 + if s.stats.AvgResponseTime > 60000 { + s.stats.AvgResponseTime = 60000 + } + } + + // 合并查询类型统计 + for k, v := range statsData.Stats.QueryTypes { + s.stats.QueryTypes[k] += v + } + + // 合并来源IP统计 + for ip := range statsData.Stats.SourceIPs { + s.stats.SourceIPs[ip] = true + } + + // 确保使用当前配置中的EnableDNSSEC值 s.stats.DNSSECEnabled = s.config.EnableDNSSEC } s.statsMutex.Unlock() @@ -2734,6 +2944,38 @@ func (s *Server) loadQueryLogs() { logger.Info("查询日志加载成功", "count", len(logs)) } +// processLogs 异步处理日志记录 +func (s *Server) processLogs() { + for { + select { + case logEntry, ok := <-s.logChannel: + if !ok { + // 通道关闭,退出循环 + return + } + + // 加锁保护queryLogs + s.queryLogsMutex.Lock() + + // 如果日志数量超过最大限制,删除最旧的日志 + if len(s.queryLogs) >= s.maxQueryLogs { + // 使用切片操作保留最新的日志,避免复制整个切片 + // 保留最新的s.maxQueryLogs-1条日志,然后添加新日志 + s.queryLogs = s.queryLogs[len(s.queryLogs)-s.maxQueryLogs+1:] + } + // 直接添加新日志 + s.queryLogs = append(s.queryLogs, logEntry) + + // 解锁 + s.queryLogsMutex.Unlock() + + case <-s.ctx.Done(): + // 上下文取消,退出循环 + return + } + } +} + // saveStatsData 保存统计数据到文件 func (s *Server) saveStatsData() { // 获取绝对路径以避免工作目录问题 diff --git a/download.sh b/download.sh deleted file mode 100755 index 9b10210..0000000 --- a/download.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -set -e -f -u -x - -# This script syncs companies DB that we bundle with AdGuard Home. The source -# for this database is https://github.com/AdguardTeam/companiesdb. -# -trackers_url='https://raw.githubusercontent.com/AdguardTeam/companiesdb/main/dist/trackers.json' -output='./trackers.json' -readonly trackers_url output - -curl -o "$output" -v "$trackers_url" diff --git a/gfw/manager.go b/gfw/manager.go new file mode 100644 index 0000000..9cfde7f --- /dev/null +++ b/gfw/manager.go @@ -0,0 +1,241 @@ +package gfw + +import ( + "encoding/base64" + "fmt" + "os" + "regexp" + "strings" + "sync" + + "dns-server/config" + "dns-server/logger" +) + +// regexRule 正则规则结构,包含编译后的表达式和原始字符串 +type regexRule struct { + pattern *regexp.Regexp + original string +} + +// GFWListManager GFWList管理器 +type GFWListManager struct { + config *config.GFWListConfig + domainRules map[string]bool + regexRules []regexRule + rulesMutex sync.RWMutex +} + +// NewGFWListManager 创建GFWList管理器实例 +func NewGFWListManager(config *config.GFWListConfig) *GFWListManager { + return &GFWListManager{ + config: config, + domainRules: make(map[string]bool), + regexRules: []regexRule{}, + } +} + +// LoadRules 加载GFWList规则 +func (m *GFWListManager) LoadRules() error { + // 如果GFWList功能未启用,不加载规则 + if !m.config.Enabled { + return nil + } + + m.rulesMutex.Lock() + defer m.rulesMutex.Unlock() + + // 清空现有规则 + m.domainRules = make(map[string]bool) + m.regexRules = []regexRule{} + + if m.config.Content == "" { + return nil // 没有GFWList内容,直接返回 + } + + // 从文件路径读取GFWList内容 + fileContent, err := os.ReadFile(m.config.Content) + if err != nil { + return fmt.Errorf("读取GFWList文件失败: %w", err) + } + + rawContent := string(fileContent) + var ruleContent string + + // 过滤注释行,收集可能的Base64内容 + var base64Content strings.Builder + lines := strings.Split(rawContent, "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "!") || strings.HasPrefix(line, "[") { + // 跳过注释行和头信息行 + continue + } + base64Content.WriteString(line) + } + + // 尝试Base64解码 + decoded, err := base64.StdEncoding.DecodeString(base64Content.String()) + if err == nil { + // 解码成功,使用解码后的内容 + ruleContent = string(decoded) + logger.Info("GFWList文件为Base64编码,已成功解码") + } else { + // 解码失败,使用原始内容(可能是纯文本格式) + ruleContent = rawContent + logger.Info("GFWList文件为纯文本格式,直接解析") + } + + // 按行解析规则内容 + ruleLines := strings.Split(ruleContent, "\n") + for _, line := range ruleLines { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "!") || strings.HasPrefix(line, "[") { + // 跳过空行、注释行和头信息行 + continue + } + m.parseRule(line) + } + + logger.Info(fmt.Sprintf("GFWList规则加载完成,域名规则: %d, 正则规则: %d", + len(m.domainRules), len(m.regexRules))) + return nil +} + +// parseRule 解析规则行 +func (m *GFWListManager) parseRule(line string) { + // 保存原始规则用于后续使用 + originalLine := line + + // 处理注释 + if strings.HasPrefix(line, "!") || strings.HasPrefix(line, "#") || line == "" { + return + } + + // 移除规则选项部分(暂时不处理规则选项) + if strings.Contains(line, "$") { + parts := strings.SplitN(line, "$", 2) + line = parts[0] + // 规则选项暂时不处理 + } + + // 处理不同类型的规则 + switch { + case strings.HasPrefix(line, "||") && strings.HasSuffix(line, "^"): + // AdGuardHome域名规则格式: ||example.com^ + domain := strings.TrimSuffix(strings.TrimPrefix(line, "||"), "^") + m.addDomainRule(domain, originalLine) + + case strings.HasPrefix(line, "||"): + // 域名片段匹配规则: ||google 匹配任何包含google的域名 + domain := strings.TrimPrefix(line, "||") + // 添加精确域名匹配 + m.addDomainRule(domain, originalLine) + // 同时添加正则表达式规则,匹配任何包含该域名片段的域名 + if re, err := regexp.Compile("(?i).*" + regexp.QuoteMeta(domain) + ".*"); err == nil { + m.addRegexRule(re, originalLine) + } + + case strings.HasPrefix(line, "*"): + // 通配符规则,转换为正则表达式 + pattern := strings.ReplaceAll(line, "*", ".*") + pattern = "^" + pattern + "$" + if re, err := regexp.Compile(pattern); err == nil { + // 保存原始规则字符串 + m.addRegexRule(re, originalLine) + } + + case strings.HasPrefix(line, "/") && strings.HasSuffix(line, "/"): + // 正则表达式匹配规则:/regex/ 格式,不区分大小写 + pattern := strings.TrimPrefix(strings.TrimSuffix(line, "/"), "/") + // 编译为不区分大小写的正则表达式,确保能匹配域名中任意位置 + // 对于像 /domain/ 这样的规则,应该匹配包含 domain 字符串的任何域名 + if re, err := regexp.Compile("(?i).*" + regexp.QuoteMeta(pattern) + ".*"); err == nil { + // 保存原始规则字符串 + m.addRegexRule(re, originalLine) + } + + case strings.HasPrefix(line, "|") && strings.HasSuffix(line, "|"): + // 完整URL匹配规则 + urlPattern := strings.TrimPrefix(strings.TrimSuffix(line, "|"), "|") + // 将URL模式转换为正则表达式 + pattern := "^" + regexp.QuoteMeta(urlPattern) + "$" + if re, err := regexp.Compile(pattern); err == nil { + m.addRegexRule(re, originalLine) + } + + case strings.HasPrefix(line, "|"): + // URL开头匹配规则 + urlPattern := strings.TrimPrefix(line, "|") + pattern := "^" + regexp.QuoteMeta(urlPattern) + if re, err := regexp.Compile(pattern); err == nil { + m.addRegexRule(re, originalLine) + } + + case strings.HasSuffix(line, "|"): + // URL结尾匹配规则 + urlPattern := strings.TrimSuffix(line, "|") + pattern := regexp.QuoteMeta(urlPattern) + "$" + if re, err := regexp.Compile(pattern); err == nil { + m.addRegexRule(re, originalLine) + } + + default: + // 默认作为普通域名规则 + m.addDomainRule(line, originalLine) + } +} + +// addDomainRule 添加域名规则 +func (m *GFWListManager) addDomainRule(domain string, original string) { + m.domainRules[domain] = true +} + +// addRegexRule 添加正则表达式规则 +func (m *GFWListManager) addRegexRule(re *regexp.Regexp, original string) { + rule := regexRule{ + pattern: re, + original: original, + } + m.regexRules = append(m.regexRules, rule) +} + +// IsMatch 检查域名是否匹配GFWList规则 +func (m *GFWListManager) IsMatch(domain string) bool { + m.rulesMutex.RLock() + defer m.rulesMutex.RUnlock() + + // 预处理域名,去除可能的端口号 + if strings.Contains(domain, ":") { + parts := strings.Split(domain, ":") + domain = parts[0] + } + + // 检查精确域名匹配 + if m.domainRules[domain] { + return true + } + + // 检查子域名匹配 + parts := strings.Split(domain, ".") + for i := 0; i < len(parts)-1; i++ { + subdomain := strings.Join(parts[i:], ".") + if m.domainRules[subdomain] { + return true + } + } + + // 检查正则表达式匹配 + for _, re := range m.regexRules { + if re.pattern.MatchString(domain) { + return true + } + } + + return false +} + +// GetGFWListIP 获取GFWList的目标IP地址 +func (m *GFWListManager) GetGFWListIP() string { + return m.config.IP +} diff --git a/http/server.go b/http/server.go index 29833dd..0c03ae6 100644 --- a/http/server.go +++ b/http/server.go @@ -12,6 +12,7 @@ import ( "dns-server/config" "dns-server/dns" + "dns-server/gfw" "dns-server/logger" "dns-server/shield" @@ -24,6 +25,7 @@ type Server struct { config *config.HTTPConfig dnsServer *dns.Server shieldManager *shield.ShieldManager + gfwManager *gfw.GFWListManager server *http.Server // 会话管理相关字段 @@ -39,12 +41,13 @@ type Server struct { } // NewServer 创建HTTP服务器实例 -func NewServer(globalConfig *config.Config, dnsServer *dns.Server, shieldManager *shield.ShieldManager) *Server { +func NewServer(globalConfig *config.Config, dnsServer *dns.Server, shieldManager *shield.ShieldManager, gfwManager *gfw.GFWListManager) *Server { server := &Server{ globalConfig: globalConfig, config: &globalConfig.HTTP, dnsServer: dnsServer, shieldManager: shieldManager, + gfwManager: gfwManager, upgrader: websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, @@ -430,7 +433,8 @@ func (s *Server) areStatsEqual(stats1, stats2 map[string]interface{}) bool { if dns1["Queries"] != dns2["Queries"] || dns1["Blocked"] != dns2["Blocked"] || dns1["Allowed"] != dns2["Allowed"] || - dns1["Errors"] != dns2["Errors"] { + dns1["Errors"] != dns2["Errors"] || + dns1["AvgResponseTime"] != dns2["AvgResponseTime"] { return false } } @@ -533,7 +537,8 @@ func (s *Server) handleTopBlockedDomains(w http.ResponseWriter, r *http.Request) return } - domains := s.dnsServer.GetTopBlockedDomains(10) + // 返回最近30天的所有域名,设置合理上限50 + domains := s.dnsServer.GetTopBlockedDomains(50) // 转换为前端需要的格式 result := make([]map[string]interface{}, len(domains)) @@ -584,7 +589,7 @@ func (s *Server) handleRecentBlockedDomains(w http.ResponseWriter, r *http.Reque for i, domain := range domains { result[i] = map[string]interface{}{ "domain": domain.Domain, - "time": domain.LastSeen.Format("15:04:05"), + "time": time.Unix(domain.LastSeen, 0).Format("15:04:05"), } } @@ -743,10 +748,10 @@ func (s *Server) handleTopDomains(w http.ResponseWriter, r *http.Request) { return } - // 获取TOP被屏蔽域名 - blockedDomains := s.dnsServer.GetTopBlockedDomains(10) - // 获取TOP已解析域名 - resolvedDomains := s.dnsServer.GetTopResolvedDomains(10) + // 获取TOP被屏蔽域名,返回最近30天的数据,设置合理上限50 + blockedDomains := s.dnsServer.GetTopBlockedDomains(50) + // 获取TOP已解析域名,返回最近30天的数据,设置合理上限50 + resolvedDomains := s.dnsServer.GetTopResolvedDomains(50) // 合并并去重域名统计 domainMap := make(map[string]int64) @@ -777,9 +782,9 @@ func (s *Server) handleTopDomains(w http.ResponseWriter, r *http.Request) { return domainList[i]["count"].(int64) > domainList[j]["count"].(int64) }) - // 返回限制数量 - if len(domainList) > 10 { - domainList = domainList[:10] + // 返回所有合并后的域名,设置合理上限50 + if len(domainList) > 50 { + domainList = domainList[:50] } w.Header().Set("Content-Type", "application/json") @@ -1239,13 +1244,21 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { "blacklists": s.globalConfig.Shield.Blacklists, "updateInterval": s.globalConfig.Shield.UpdateInterval, }, + "GFWList": map[string]interface{}{ + "ip": s.globalConfig.GFWList.IP, + "content": s.globalConfig.GFWList.Content, + }, "DNSServer": map[string]interface{}{ "port": s.globalConfig.DNS.Port, + "QueryMode": s.globalConfig.DNS.QueryMode, "UpstreamServers": s.globalConfig.DNS.UpstreamDNS, "DNSSECUpstreamServers": s.globalConfig.DNS.DNSSECUpstreamDNS, - "timeout": s.globalConfig.DNS.Timeout, "saveInterval": s.globalConfig.DNS.SaveInterval, "enableIPv6": s.globalConfig.DNS.EnableIPv6, + "CacheMode": s.globalConfig.DNS.CacheMode, + "CacheSize": s.globalConfig.DNS.CacheSize, + "MaxCacheTTL": s.globalConfig.DNS.MaxCacheTTL, + "MinCacheTTL": s.globalConfig.DNS.MinCacheTTL, }, "HTTPServer": map[string]interface{}{ "port": s.globalConfig.HTTP.Port, @@ -1258,11 +1271,16 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { var req struct { DNSServer struct { Port int `json:"port"` + QueryMode string `json:"queryMode"` UpstreamServers []string `json:"upstreamServers"` DnssecUpstreamServers []string `json:"dnssecUpstreamServers"` Timeout int `json:"timeout"` SaveInterval int `json:"saveInterval"` EnableIPv6 bool `json:"enableIPv6"` + CacheMode string `json:"cacheMode"` + CacheSize int `json:"cacheSize"` + MaxCacheTTL int `json:"maxCacheTTL"` + MinCacheTTL int `json:"minCacheTTL"` } `json:"dnsserver"` HTTPServer struct { Port int `json:"port"` @@ -1273,6 +1291,10 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { Blacklists []config.BlacklistEntry `json:"blacklists"` UpdateInterval int `json:"updateInterval"` } `json:"shield"` + GFWList struct { + IP string `json:"ip"` + Content string `json:"content"` + } `json:"gfwList"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { @@ -1290,13 +1312,27 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { if len(req.DNSServer.DnssecUpstreamServers) > 0 { s.globalConfig.DNS.DNSSECUpstreamDNS = req.DNSServer.DnssecUpstreamServers } - if req.DNSServer.Timeout > 0 { - s.globalConfig.DNS.Timeout = req.DNSServer.Timeout - } if req.DNSServer.SaveInterval > 0 { s.globalConfig.DNS.SaveInterval = req.DNSServer.SaveInterval } s.globalConfig.DNS.EnableIPv6 = req.DNSServer.EnableIPv6 + // 更新查询模式 + if req.DNSServer.QueryMode != "" { + s.globalConfig.DNS.QueryMode = req.DNSServer.QueryMode + } + // 更新缓存配置 + if req.DNSServer.CacheMode != "" { + s.globalConfig.DNS.CacheMode = req.DNSServer.CacheMode + } + if req.DNSServer.CacheSize > 0 { + s.globalConfig.DNS.CacheSize = req.DNSServer.CacheSize + } + if req.DNSServer.MaxCacheTTL > 0 { + s.globalConfig.DNS.MaxCacheTTL = req.DNSServer.MaxCacheTTL + } + if req.DNSServer.MinCacheTTL > 0 { + s.globalConfig.DNS.MinCacheTTL = req.DNSServer.MinCacheTTL + } // 更新HTTP配置 if req.HTTPServer.Port > 0 { @@ -1338,6 +1374,17 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { s.globalConfig.Shield.CustomBlockIP = req.Shield.CustomBlockIP } + // 更新GFWList配置 + s.globalConfig.GFWList.IP = req.GFWList.IP + s.globalConfig.GFWList.Content = req.GFWList.Content + + // 重新加载GFWList规则 + if s.gfwManager != nil { + if err := s.gfwManager.LoadRules(); err != nil { + logger.Error("重新加载GFWList规则失败", "error", err) + } + } + // 更新黑名单配置 if req.Shield.Blacklists != nil { // 验证黑名单配置 @@ -1367,6 +1414,19 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { s.shieldManager.StartAutoUpdate() } + // 更新现有的DNSCache实例配置 + // 最大和最小TTL(秒) + maxCacheTTL := time.Duration(s.globalConfig.DNS.MaxCacheTTL) * time.Second + minCacheTTL := time.Duration(s.globalConfig.DNS.MinCacheTTL) * time.Second + // 最大缓存大小(字节) + maxCacheSize := int64(s.globalConfig.DNS.CacheSize) * 1024 * 1024 + + // 更新缓存配置 + s.dnsServer.DnsCache.SetMaxCacheTTL(maxCacheTTL) + s.dnsServer.DnsCache.SetMinCacheTTL(minCacheTTL) + s.dnsServer.DnsCache.SetCacheMode(s.globalConfig.DNS.CacheMode) + s.dnsServer.DnsCache.SetMaxCacheSize(maxCacheSize) + // 保存配置到文件 if err := saveConfigToFile(s.globalConfig, "./config.json"); err != nil { logger.Error("保存配置到文件失败", "error", err) diff --git a/logger/logger.go b/logger/logger.go index ca2f24d..2c0a223 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -58,7 +58,7 @@ func InitLogger(logFile, level string, maxSize, maxBackups, maxAge int, _ bool) } // 无论是否指定日志文件,都同时输出到标准输出 -if len(outputTargets) > 0 { + if len(outputTargets) > 0 { outputTargets = append(outputTargets, os.Stdout) } else { // 如果没有指定日志文件,仅使用标准输出 @@ -90,12 +90,12 @@ func Close() { // 执行日志刷新 log.Warn("日志系统已关闭") - + // 确保日志被写入磁盘 if loggerOutput, ok := log.Out.(*os.File); ok { loggerOutput.Sync() } - + initialized = false log = nil } diff --git a/main.go b/main.go index 960a439..e006c02 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ import ( "dns-server/config" "dns-server/dns" + "dns-server/gfw" "dns-server/http" "dns-server/logger" "dns-server/shield" @@ -82,6 +83,11 @@ func createDefaultConfig(configFile string) error { "customBlockIP": "", "statsSaveInterval": 60 }, + "gfwList": { + "ip": "127.0.0.1", + "content": "./data/gfwlist.txt", + "enabled": true + }, "log": { "level": "debug", "maxSize": 100, @@ -129,6 +135,13 @@ func createRequiredFiles(cfg *config.Config) error { } } + // 创建GFWList文件 + if _, err := os.Stat("data/gfwlist.txt"); os.IsNotExist(err) { + if err := os.WriteFile("data/gfwlist.txt", []byte("# GFWList规则文件\n# 格式:每行一条规则\n# 例如:www.google.com\n"), 0644); err != nil { + return fmt.Errorf("创建GFWList文件失败: %w", err) + } + } + // 创建统计数据文件 if _, err := os.Stat("data/stats.json"); os.IsNotExist(err) { if err := os.WriteFile("data/stats.json", []byte("{}"), 0644); err != nil { @@ -184,12 +197,18 @@ func main() { // 初始化屏蔽管理系统 shieldManager := shield.NewShieldManager(&cfg.Shield) - if err := shieldManager.LoadRules(); err != nil { - logger.Error("加载屏蔽规则失败", "error", err) + if err := shieldManager.LoadLocalRulesOnly(); err != nil { + logger.Error("加载本地屏蔽规则失败", "error", err) + } + + // 初始化GFWList管理系统 + gfwManager := gfw.NewGFWListManager(&cfg.GFWList) + if err := gfwManager.LoadRules(); err != nil { + logger.Error("加载GFWList规则失败", "error", err) } // 启动DNS服务器 - dnsServer := dns.NewServer(&cfg.DNS, &cfg.Shield, shieldManager) + dnsServer := dns.NewServer(&cfg.DNS, &cfg.Shield, shieldManager, &cfg.GFWList, gfwManager) go func() { if err := dnsServer.Start(); err != nil { logger.Error("DNS服务器启动失败", "error", err) @@ -198,13 +217,23 @@ func main() { }() // 启动HTTP控制台服务器 - httpServer := http.NewServer(cfg, dnsServer, shieldManager) + httpServer := http.NewServer(cfg, dnsServer, shieldManager, gfwManager) go func() { if err := httpServer.Start(); err != nil { logger.Error("HTTP控制台服务器启动失败", "error", err) } }() + // 异步加载远程规则 + go func() { + logger.Info("开始异步加载远程屏蔽规则") + if err := shieldManager.LoadRules(); err != nil { + logger.Error("异步加载远程屏蔽规则失败", "error", err) + } else { + logger.Info("远程屏蔽规则异步加载完成") + } + }() + // 启动定时更新任务 go shieldManager.StartAutoUpdate() diff --git a/package.json b/package.json deleted file mode 100644 index 94d5432..0000000 --- a/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "dns-server-console", - "version": "1.0.0", - "description": "DNS服务器Web控制台", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "dependencies": { - "tailwindcss": "^3.3.3", - "font-awesome": "^4.7.0", - "chart.js": "^4.4.8" - }, - "devDependencies": {}, - "keywords": ["dns", "server", "console", "web"], - "author": "", - "license": "ISC" -} \ No newline at end of file diff --git a/shield/manager.go b/shield/manager.go index 15e82cc..f7752d0 100644 --- a/shield/manager.go +++ b/shield/manager.go @@ -132,6 +132,44 @@ func (m *ShieldManager) LoadRules() error { return nil } +// LoadLocalRulesOnly 只加载本地规则 +func (m *ShieldManager) LoadLocalRulesOnly() error { + m.rulesMutex.Lock() + defer m.rulesMutex.Unlock() + + // 清空现有规则 + m.domainRules = make(map[string]bool) + m.domainExceptions = make(map[string]bool) + m.domainRulesIsLocal = make(map[string]bool) + m.domainExceptionsIsLocal = make(map[string]bool) + m.domainRulesSource = make(map[string]string) + m.domainExceptionsSource = make(map[string]string) + m.domainRulesOriginal = make(map[string]string) + m.domainExceptionsOriginal = make(map[string]string) + m.regexRules = []regexRule{} + m.regexExceptions = []regexRule{} + m.hostsMap = make(map[string]string) + m.localRulesCount = 0 + m.remoteRulesCount = 0 + // 保留计数数据,不随规则重新加载而清空 + + // 加载自定义规则文件 + if err := m.loadLocalRules(); err != nil { + logger.Error("加载自定义规则失败", "error", err) + // 继续执行,不返回错误 + } + + // 加载hosts文件 + if err := m.loadHosts(); err != nil { + logger.Error("加载hosts文件失败", "error", err) + // 继续执行,不返回错误 + } + + logger.Info(fmt.Sprintf("本地规则加载完成,域名规则: %d, 排除规则: %d, 正则规则: %d, hosts规则: %d", + len(m.domainRules), len(m.domainExceptions), len(m.regexRules), len(m.hostsMap))) + return nil +} + // loadLocalRules 加载自定义规则文件 func (m *ShieldManager) loadLocalRules() error { file, err := os.Open("data/rules.txt") @@ -204,21 +242,22 @@ func (m *ShieldManager) fetchRemoteRules(url string) error { // 获取缓存文件路径 cacheFile := m.getCacheFilePath(url) - // 尝试从缓存加载 - hasLoadedFromCache := false + // 检查缓存是否存在且不需要更新 if !m.shouldUpdateCache(cacheFile) { + // 从缓存加载规则 if err := m.loadCachedRules(cacheFile, url); err == nil { logger.Info("从缓存加载远程规则", "url", url) - hasLoadedFromCache = true + return nil // 缓存有效且加载成功,直接返回 } } - // 从远程获取规则 + // 缓存不存在或需要更新,从远程获取规则 resp, err := http.Get(url) if err != nil { - // 如果从远程获取失败,但已经从缓存加载成功,则返回nil - if hasLoadedFromCache { - logger.Warn("远程规则更新失败,使用缓存版本", "url", url, "error", err) + // 如果从远程获取失败,尝试从缓存加载(即使缓存过期) + logger.Warn("远程规则获取失败,尝试使用过期缓存", "url", url, "error", err) + if err := m.loadCachedRules(cacheFile, url); err == nil { + logger.Info("从过期缓存加载远程规则", "url", url) return nil } return err @@ -226,9 +265,10 @@ func (m *ShieldManager) fetchRemoteRules(url string) error { defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - // 如果状态码不正确,但已经从缓存加载成功,则返回nil - if hasLoadedFromCache { - logger.Warn("远程规则更新失败,使用缓存版本", "url", url, "statusCode", resp.StatusCode) + // 如果状态码不正确,尝试从缓存加载(即使缓存过期) + logger.Warn("远程规则获取失败,尝试使用过期缓存", "url", url, "statusCode", resp.StatusCode) + if err := m.loadCachedRules(cacheFile, url); err == nil { + logger.Info("从过期缓存加载远程规则", "url", url) return nil } return fmt.Errorf("远程服务器返回错误状态码: %d", resp.StatusCode) @@ -236,6 +276,12 @@ func (m *ShieldManager) fetchRemoteRules(url string) error { body, err := ioutil.ReadAll(resp.Body) if err != nil { + // 如果读取响应失败,尝试从缓存加载(即使缓存过期) + logger.Warn("远程规则读取失败,尝试使用过期缓存", "url", url, "error", err) + if err := m.loadCachedRules(cacheFile, url); err == nil { + logger.Info("从过期缓存加载远程规则", "url", url) + return nil + } return err } @@ -544,6 +590,7 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf "blockRule": "", "blockRuleType": "", "blocksource": "", + "isGFWList": false, "excluded": false, "excludeRule": "", "excludeRuleType": "", @@ -631,6 +678,7 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf result["blockRule"] = m.domainRulesOriginal[domain] result["blockRuleType"] = "exact_domain" result["blocksource"] = m.domainRulesSource[domain] + result["isGFWList"] = m.domainRulesSource[domain] == "GFWList" return result } @@ -640,6 +688,7 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf result["blockRule"] = m.domainRulesOriginal[domain] result["blockRuleType"] = "exact_domain" result["blocksource"] = m.domainRulesSource[domain] + result["isGFWList"] = m.domainRulesSource[domain] == "GFWList" return result } @@ -654,6 +703,7 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf result["blockRule"] = m.domainRulesOriginal[subdomain] result["blockRuleType"] = "subdomain" result["blocksource"] = m.domainRulesSource[subdomain] + result["isGFWList"] = m.domainRulesSource[subdomain] == "GFWList" return result } } @@ -666,6 +716,7 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf result["blockRule"] = m.domainRulesOriginal[subdomain] result["blockRuleType"] = "subdomain" result["blocksource"] = m.domainRulesSource[subdomain] + result["isGFWList"] = m.domainRulesSource[subdomain] == "GFWList" return result } } @@ -677,6 +728,7 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf result["blockRule"] = re.original result["blockRuleType"] = "regex" result["blocksource"] = re.source + result["isGFWList"] = re.source == "GFWList" return result } } @@ -688,6 +740,7 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf result["blockRule"] = re.original result["blockRuleType"] = "regex" result["blocksource"] = re.source + result["isGFWList"] = re.source == "GFWList" return result } } diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..2ae8e52 --- /dev/null +++ b/start.sh @@ -0,0 +1,176 @@ +#!/bin/bash +# 启动/停止/重启脚本 + +# ===================== 配置区 ===================== +# 程序路径 +AGENT_PATH="./dns-server" +# 日志文件路径 +LOG_FILE="./server.log" +# PID文件路径(记录进程ID) +PID_FILE="./server.pid" +# 启动参数(根据实际需求调整) +START_ARGS="" +# 工作目录 +WORK_DIR="." +# ==================== 配置区结束 ==================== + +# 检查程序文件是否存在 +check_agent_exists() { + if [ ! -f "${AGENT_PATH}" ]; then + echo "错误:程序文件 ${AGENT_PATH} 不存在!" + exit 1 + fi + if [ ! -x "${AGENT_PATH}" ]; then + echo "错误:程序文件 ${AGENT_PATH} 没有执行权限,正在尝试添加..." + chmod +x "${AGENT_PATH}" + if [ $? -ne 0 ]; then + echo "错误:添加执行权限失败,请手动执行 chmod +x ${AGENT_PATH}" + exit 1 + fi + fi +} + +# 检查进程是否运行 +check_running() { + if [ -f "${PID_FILE}" ]; then + PID=$(cat "${PID_FILE}") + if ps -p "${PID}" > /dev/null 2>&1; then + return 0 # 运行中 + else + rm -f "${PID_FILE}" # PID文件存在但进程已死,清理PID文件 + fi + fi + return 1 # 未运行 +} + +# 启动程序 +start_agent() { + if check_running; then + echo "✅ dns-server 已在运行(PID: $(cat ${PID_FILE}))" + return 0 + fi + + echo "🚀 正在启动 dns-server(工作目录:${WORK_DIR})..." + + # 新增:检查并切换工作目录 + if [ ! -d "${WORK_DIR}" ]; then + echo "⚠️ 工作目录 ${WORK_DIR} 不存在,正在创建..." + mkdir -p "${WORK_DIR}" + if [ $? -ne 0 ]; then + echo "❌ 创建工作目录 ${WORK_DIR} 失败!" + exit 1 + fi + fi + + # 切换到工作目录(关键:程序将在此目录下运行) + cd "${WORK_DIR}" || { + echo "❌ 切换到工作目录 ${WORK_DIR} 失败!" + exit 1 + } + + # 创建日志目录 + mkdir -p "$(dirname ${LOG_FILE})" + # 后台启动程序(注意:cd仅影响当前子进程,需在同一行执行) + nohup "${AGENT_PATH}" ${START_ARGS} > "${LOG_FILE}" 2>&1 & + AGENT_PID=$! + echo "${AGENT_PID}" > "${PID_FILE}" + + # 等待检查启动状态 + sleep 2 + if check_running; then + echo "✅ dns-server 启动成功(PID: ${AGENT_PID},工作目录:${WORK_DIR})" + echo "日志文件:${LOG_FILE}" + else + echo "❌ dns-server 启动失败!请查看日志:${LOG_FILE}" + rm -f "${PID_FILE}" + exit 1 + fi +} +# 停止程序 +stop_agent() { + if ! check_running; then + echo "ℹ️ dns-server 未运行" + return 0 + fi + + PID=$(cat "${PID_FILE}") + echo "🛑 正在停止 dns-server(PID: ${PID})..." + # 优雅停止(先尝试TERM信号,失败则强制KILL) + kill "${PID}" > /dev/null 2>&1 + sleep 3 + + if ps -p "${PID}" > /dev/null 2>&1; then + echo "⚠️ 优雅停止失败,强制杀死进程..." + kill -9 "${PID}" > /dev/null 2>&1 + sleep 1 + fi + + # 清理PID文件 + rm -f "${PID_FILE}" + echo "✅ dns-server 已停止" +} + +# 查看状态 +status_agent() { + if check_running; then + echo "✅ dns-server 运行中(PID: $(cat ${PID_FILE}))" + else + echo "ℹ️ dns-server 未运行" + fi +} + +# 重启程序 +restart_agent() { + echo "🔄 正在重启 dns-server..." + stop_agent + sleep 2 + start_agent +} + +# 帮助信息 +show_help() { + echo "使用方法:$0 [start|stop|restart|status|help]" + echo " start - 启动 dns-server" + echo " stop - 停止 dns-server" + echo " restart - 重启 dns-server" + echo " status - 查看 dns-server 运行状态" + echo " help - 显示帮助信息" +} + +# 主逻辑 +main() { + # 检查是否为root用户(可选,根据需求调整) + if [ "$(id -u)" -ne 0 ]; then + echo "警告:建议使用root用户运行此脚本(当前用户:$(whoami))" + # exit 1 # 如果强制要求root,取消注释 + fi + + check_agent_exists + + case "$1" in + start) + start_agent + ;; + stop) + stop_agent + ;; + restart) + restart_agent + ;; + status) + status_agent + ;; + help|--help|-h) + show_help + ;; + *) + echo "错误:无效参数 '$1'" + show_help + exit 1 + ;; + esac +} + +# 执行主逻辑 +main "$@" + diff --git a/static/api/index.html b/static/api/index.html index ebb375d..1704aa6 100644 --- a/static/api/index.html +++ b/static/api/index.html @@ -4,13 +4,13 @@