UNPKG

surgio

Version:

查看完整使用文档,前往 [surgio.royli.dev](https://surgio.royli.dev)。

765 lines 67.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const assert_1 = __importDefault(require("assert")); const axios_1 = __importDefault(require("axios")); const country_code_emoji_1 = __importDefault(require("country-code-emoji")); const fs_extra_1 = __importDefault(require("fs-extra")); const lodash_1 = __importDefault(require("lodash")); const lru_cache_1 = __importDefault(require("lru-cache")); const path_1 = __importDefault(require("path")); const query_string_1 = __importDefault(require("query-string")); const url_1 = __importDefault(require("url")); const urlsafe_base64_1 = __importDefault(require("urlsafe-base64")); const yaml_1 = __importDefault(require("yaml")); const os_1 = __importDefault(require("os")); const types_1 = require("../types"); const config_1 = require("./config"); exports.OBFS_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148'; const ConfigCache = new lru_cache_1.default({ maxAge: 10 * 60 * 1000, }); // istanbul ignore next exports.resolveRoot = (...args) => path_1.default.join(__dirname, '../../', ...args); exports.getDownloadUrl = (baseUrl = '/', artifactName) => `${baseUrl}${artifactName}`; exports.getBlackSSLConfig = async (config) => { assert_1.default(config.username, 'Lack of BlackSSL username.'); assert_1.default(config.password, 'Lack of BlackSSL password.'); const key = `blackssl_${config.username}`; async function requestConfigFromBlackSSL(username, password) { const response = await axios_1.default .get('https://api.darkssl.com/v1/service/ssl_info', { params: { username, password, }, timeout: 20000, proxy: false, headers: { 'User-Agent': 'GoAgentX/774 CFNetwork/901.1 Darwin/17.6.0 (x86_64)', }, }); const result = response.data.ssl_nodes.map(item => ({ nodeName: `${country_code_emoji_1.default(item.country_code)}${item.name}`, type: types_1.NodeTypeEnum.HTTPS, hostname: item.server, port: item.port, username, password, })); ConfigCache.set(key, result); return result; } return ConfigCache.has(key) ? ConfigCache.get(key) : await requestConfigFromBlackSSL(config.username, config.password); }; exports.getShadowsocksJSONConfig = async (config) => { assert_1.default(config.url, 'Lack of subscription url.'); async function requestConfigFromRemote(url) { const response = await axios_1.default.get(url, { proxy: false, timeout: 20000, }); const result = response.data.configs.map(item => { const nodeConfig = { nodeName: item.remarks, type: types_1.NodeTypeEnum.Shadowsocks, hostname: item.server, port: item.server_port, method: item.method, password: item.password, }; if (typeof config.udpRelay === 'boolean') { nodeConfig['udp-relay'] = config.udpRelay ? 'true' : 'false'; } if (item.plugin === 'obfs-local') { const obfs = item.plugin_opts.match(/obfs=(\w+)/); const obfsHost = item.plugin_opts.match(/obfs-host=(.+)$/); if (obfs) { nodeConfig.obfs = obfs[1]; nodeConfig['obfs-host'] = obfsHost ? obfsHost[1] : 'www.bing.com'; } } return nodeConfig; }); ConfigCache.set(url, result); return result; } return ConfigCache.has(config.url) ? ConfigCache.get(config.url) : await requestConfigFromRemote(config.url); }; exports.getShadowsocksSubscription = async (config) => { assert_1.default(config.url, 'Lack of subscription url.'); async function requestConfigFromRemote(url) { const response = await axios_1.default.get(url, { proxy: false, timeout: 20000, responseType: 'text', }); const configList = exports.fromBase64(response.data).split('\n').filter(item => !!item); const result = configList.map(item => { const scheme = url_1.default.parse(item, true); const userInfo = exports.fromUrlSafeBase64(scheme.auth).split(':'); const pluginInfo = typeof scheme.query.plugin === 'string' ? exports.decodeStringList(scheme.query.plugin.split(';')) : {}; return Object.assign(Object.assign({ type: types_1.NodeTypeEnum.Shadowsocks, nodeName: decodeURIComponent(scheme.hash.replace('#', '')), hostname: scheme.hostname, port: scheme.port, method: userInfo[0], password: userInfo[1] }, (typeof config.udpRelay === 'boolean' ? { 'udp-relay': config.udpRelay ? 'true' : 'false', } : null)), (pluginInfo['obfs-local'] ? { obfs: pluginInfo.obfs, 'obfs-host': pluginInfo['obfs-host'], } : null)); }); ConfigCache.set(url, result); return result; } return ConfigCache.has(config.url) ? ConfigCache.get(config.url) : await requestConfigFromRemote(config.url); }; exports.getShadowsocksrSubscription = async (config) => { assert_1.default(config.url, 'Lack of subscription url.'); async function requestConfigFromRemote(url) { const response = await axios_1.default.get(url, { proxy: false, timeout: 20000, responseType: 'text', }); const configList = exports.fromBase64(response.data).split('\n').filter(item => !!item); const result = configList.map(item => { const pair = exports.fromUrlSafeBase64(item.replace('ssr://', '')).split('/'); const basicInfo = pair[0].split(':'); const extras = pair[1] ? url_1.default.parse(pair[1], true) : null; const nodeName = extras ? exports.fromUrlSafeBase64(extras.query.remarks) : null; if (!nodeName) { throw new Error(`${item} doesn\`t contain a remark.`); } return { type: types_1.NodeTypeEnum.Shadowsocksr, nodeName, hostname: basicInfo[0], port: basicInfo[1], protocol: basicInfo[2], method: basicInfo[3], obfs: basicInfo[4], password: exports.fromUrlSafeBase64(basicInfo[5]), protoparam: extras ? exports.fromUrlSafeBase64(extras.query.protoparam || '') : '', obfsparam: extras ? exports.fromUrlSafeBase64(extras.query.obfsparam || '') : '', }; }); ConfigCache.set(url, result); return result; } return ConfigCache.has(config.url) ? ConfigCache.get(config.url) : await requestConfigFromRemote(config.url); }; exports.getV2rayNSubscription = async (config) => { assert_1.default(config.url, 'Lack of subscription url.'); async function requestConfigFromRemote(url) { const response = await axios_1.default.get(url, { proxy: false, timeout: 20000, responseType: 'text', }); const configList = exports.fromBase64(response.data).split('\n').filter(item => !!item); const result = configList.map(item => { const json = JSON.parse(exports.fromBase64(item.replace('vmess://', ''))); if (json.v !== '2') { throw new Error(`暂不支持该订阅类型:${url}`); } return { nodeName: json.ps, type: types_1.NodeTypeEnum.Vmess, hostname: json.add, port: json.port, method: 'auto', uuid: json.id, alterId: json.aid || '0', network: json.net, tls: json.tls === 'tls', host: json.host || '', path: json.path || '/', }; }); ConfigCache.set(url, result); return result; } return ConfigCache.has(config.url) ? ConfigCache.get(config.url) : await requestConfigFromRemote(config.url); }; exports.getSurgeNodes = (list, filter) => { const result = list .filter(item => filter ? filter(item) : true) .map(nodeConfig => { if (nodeConfig.enable === false) { return null; } switch (nodeConfig.type) { case types_1.NodeTypeEnum.Shadowsocks: { const config = nodeConfig; return ([ config.nodeName, [ 'custom', config.hostname, config.port, config.method, config.password, 'https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module', ...exports.pickAndFormatStringList(config, ['udp-relay', 'obfs', 'obfs-host']), ].join(', ') ].join(' = ')); } case types_1.NodeTypeEnum.HTTPS: { const config = nodeConfig; return ([ config.nodeName, [ 'https', config.hostname, config.port, config.username, config.password, ].join(', ') ].join(' = ')); } case types_1.NodeTypeEnum.Snell: { const config = nodeConfig; return ([ config.nodeName, [ 'snell', config.hostname, config.port, ...exports.pickAndFormatStringList(config, ['psk', 'obfs']), ].join(', '), ].join(' = ')); } case types_1.NodeTypeEnum.Shadowsocksr: { const config = nodeConfig; // istanbul ignore next if (!config.binPath) { throw new Error('You must specify a binary file path for Shadowsocksr.'); } const args = [ '-s', config.hostname, '-p', `${config.port}`, '-m', config.method, '-o', config.obfs, '-O', config.protocol, '-k', config.password, '-l', `${config.localPort}`, '-b', '127.0.0.1', ]; if (config.protoparam) { args.push('-G', config.protoparam); } if (config.obfsparam) { args.push('-g', config.obfsparam); } const configString = [ 'external', `exec = ${JSON.stringify(config.binPath)}`, ...(args).map(arg => `args = ${JSON.stringify(arg)}`), `local-port = ${config.localPort}`, `addresses = ${config.hostname}`, ].join(', '); return ([ config.nodeName, configString, ].join(' = ')); } case types_1.NodeTypeEnum.Vmess: { const config = nodeConfig; if (nodeConfig.surgeConfig && nodeConfig.surgeConfig.v2ray === 'native') { // Native support for vmess const configList = [ 'vmess', config.hostname, config.port, `username=${config.uuid}`, ]; function getHeader(host, ua = exports.OBFS_UA) { return [ `Host:${host}`, `User-Agent:${JSON.stringify(ua)}`, ].join('|'); } if (config.network === 'ws') { configList.push('ws=true'); configList.push(`ws-path=${config.path}`); configList.push('ws-headers=' + getHeader(config.host || config.hostname)); } if (config.tls) { configList.push('tls=true'); } return ([ config.nodeName, configList.join(', '), ].join(' = ')); } else { // Using external provider // istanbul ignore next if (!config.binPath) { throw new Error('You must specify a binary file path for V2Ray.'); } const jsonFileName = `v2ray_${config.localPort}_${config.hostname}_${config.port}.json`; const jsonFilePath = path_1.default.join(exports.ensureConfigFolder(), jsonFileName); const jsonFile = exports.formatV2rayConfig(config.localPort, nodeConfig); const args = [ '--config', jsonFilePath.replace(os_1.default.homedir(), '$HOME'), ]; const configString = [ 'external', `exec = ${JSON.stringify(config.binPath)}`, ...(args).map(arg => `args = ${JSON.stringify(arg)}`), `local-port = ${config.localPort}`, `addresses = ${config.hostname}`, ].join(', '); if (process.env.NODE_ENV !== 'test') { fs_extra_1.default.writeJSONSync(jsonFilePath, jsonFile); } return ([ config.nodeName, configString, ].join(' = ')); } } // istanbul ignore next default: console.info(`${nodeConfig.type} is not supported, ${nodeConfig.nodeName} will be ignored.`); return null; } }) .filter(item => item !== null); return result.join('\n'); }; exports.getClashNodes = (list, filter) => { return list .filter(item => filter ? filter(item) : true) .map(nodeConfig => { if (nodeConfig.enable === false) { return null; } switch (nodeConfig.type) { case types_1.NodeTypeEnum.Shadowsocks: return Object.assign({ type: 'ss', cipher: nodeConfig.method, name: nodeConfig.nodeName, password: nodeConfig.password, port: nodeConfig.port, server: nodeConfig.hostname, udp: nodeConfig['udp-relay'] === 'true' }, (nodeConfig.obfs ? { plugin: 'obfs', 'plugin-opts': { mode: nodeConfig.obfs, host: nodeConfig['obfs-host'], }, } : null)); case types_1.NodeTypeEnum.Vmess: return Object.assign(Object.assign(Object.assign({ type: 'vmess', cipher: nodeConfig.method, name: nodeConfig.nodeName, server: nodeConfig.hostname, port: nodeConfig.port, uuid: nodeConfig.uuid, alterId: nodeConfig.alterId }, (nodeConfig.network === 'tcp' ? null : { network: nodeConfig.network, })), { tls: nodeConfig.tls }), (nodeConfig.network === 'ws' ? { 'ws-path': nodeConfig.path, 'ws-headers': Object.assign({}, (nodeConfig.host ? { Host: nodeConfig.host } : null)), } : null)); case types_1.NodeTypeEnum.Shadowsocksr: return { type: 'ssr', name: nodeConfig.nodeName, server: nodeConfig.hostname, port: nodeConfig.port, password: nodeConfig.password, obfs: nodeConfig.obfs, obfsparam: nodeConfig.obfsparam, protocol: nodeConfig.protocol, protocolparam: nodeConfig.protoparam, cipher: nodeConfig.method, }; // istanbul ignore next default: console.info(`${nodeConfig.type} is not supported yet, ${nodeConfig.nodeName} will be ignored.`); return null; } }) .filter(item => item !== null); }; // istanbul ignore next exports.toUrlSafeBase64 = (str) => urlsafe_base64_1.default.encode(Buffer.from(str, 'utf8')); // istanbul ignore next exports.fromUrlSafeBase64 = (str) => urlsafe_base64_1.default.decode(str).toString(); // istanbul ignore next exports.toBase64 = (str) => Buffer.from(str, 'utf8').toString('base64'); // istanbul ignore next exports.fromBase64 = (str) => Buffer.from(str, 'base64').toString('utf8'); /** * @see https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme */ exports.getShadowsocksNodes = (list, groupName = 'Surgio') => { const result = list .map(nodeConfig => { if (nodeConfig.enable === false) { return null; } switch (nodeConfig.type) { case types_1.NodeTypeEnum.Shadowsocks: { const config = lodash_1.default.cloneDeep(nodeConfig); const query = Object.assign(Object.assign({}, (config.obfs ? { plugin: `${encodeURIComponent(`obfs-local;obfs=${config.obfs};obfs-host=${config['obfs-host']}`)}`, } : null)), (groupName ? { group: encodeURIComponent(groupName) } : null)); return [ 'ss://', exports.toUrlSafeBase64(`${config.method}:${config.password}`), '@', config.hostname, ':', config.port, '/?', query_string_1.default.stringify(query, { encode: false, sort: false, }), '#', encodeURIComponent(config.nodeName), ].join(''); } // istanbul ignore next default: console.info(`${nodeConfig.type} is not supported, ${nodeConfig.nodeName} will be ignored.`); return null; } }) .filter(item => item !== null); return result.join('\n'); }; exports.getShadowsocksrNodes = (list, groupName) => { const result = list .map(nodeConfig => { if (nodeConfig.enable === false) { return null; } switch (nodeConfig.type) { case types_1.NodeTypeEnum.Shadowsocksr: { const baseUri = [ nodeConfig.hostname, nodeConfig.port, nodeConfig.protocol, nodeConfig.method, nodeConfig.obfs, exports.toUrlSafeBase64(nodeConfig.password), ].join(':'); const query = { obfsparam: exports.toUrlSafeBase64(nodeConfig.obfsparam), protoparam: exports.toUrlSafeBase64(nodeConfig.protoparam), remarks: exports.toUrlSafeBase64(nodeConfig.nodeName), group: exports.toUrlSafeBase64(groupName), udpport: 0, uot: 0, }; return 'ssr://' + exports.toUrlSafeBase64([ baseUri, '/?', query_string_1.default.stringify(query), ].join('')); } // istanbul ignore next default: console.info(`${nodeConfig.type} is not supported, ${nodeConfig.nodeName} will be ignored.`); return null; } }) .filter(item => item !== null); return result.join('\n'); }; exports.getV2rayNNodes = (list) => { const result = list .map(nodeConfig => { if (nodeConfig.enable === false) { return null; } switch (nodeConfig.type) { case types_1.NodeTypeEnum.Vmess: { const json = { v: '2', ps: nodeConfig.nodeName, add: nodeConfig.hostname, port: `${nodeConfig.port}`, id: nodeConfig.uuid, aid: nodeConfig.alterId, net: nodeConfig.network, type: 'none', host: nodeConfig.host, path: nodeConfig.path, tls: nodeConfig.tls ? 'tls' : '', }; return 'vmess://' + exports.toBase64(JSON.stringify(json)); } // istanbul ignore next default: console.info(`${nodeConfig.type} is not supported, ${nodeConfig.nodeName} will be ignored.`); return null; } }) .filter(item => !!item); return result.join('\n'); }; exports.getQuantumultNodes = (list, groupName = 'Surgio') => { function getHeader(host, ua = exports.OBFS_UA) { return [ `Host:${host}`, `User-Agent:${ua}`, ].join('[Rr][Nn]'); } const result = list .map(nodeConfig => { if (nodeConfig.enable === false) { return null; } switch (nodeConfig.type) { case types_1.NodeTypeEnum.Vmess: { const config = [ 'vmess', nodeConfig.hostname, nodeConfig.port, (nodeConfig.method === 'auto' ? 'chacha20-ietf-poly1305' : nodeConfig.method), JSON.stringify(nodeConfig.uuid), nodeConfig.alterId, `group=${groupName}`, `over-tls=${nodeConfig.tls === true ? 'true' : 'false'}`, `certificate=1`, `obfs=${nodeConfig.network}`, `obfs-path=${JSON.stringify(nodeConfig.path || '/')}`, `obfs-header=${JSON.stringify(getHeader(nodeConfig.host || nodeConfig.hostname))}`, ].filter(value => !!value).join(','); return 'vmess://' + exports.toBase64([ nodeConfig.nodeName, config, ].join(' = ')); } case types_1.NodeTypeEnum.Shadowsocks: { return exports.getShadowsocksNodes([nodeConfig], groupName); } case types_1.NodeTypeEnum.Shadowsocksr: return exports.getShadowsocksrNodes([nodeConfig], groupName); case types_1.NodeTypeEnum.HTTPS: { const config = [ nodeConfig.nodeName, [ 'http', `upstream-proxy-address=${nodeConfig.hostname}`, `upstream-proxy-port=${nodeConfig.port}`, 'upstream-proxy-auth=true', `upstream-proxy-username=${nodeConfig.username}`, `upstream-proxy-password=${nodeConfig.password}`, 'over-tls=true', 'certificate=1' ].join(', ') ].join(' = '); return 'http://' + exports.toBase64(config); } // istanbul ignore next default: console.info(`${nodeConfig.type} is not supported yet, ${nodeConfig.nodeName} will be ignored.`); return null; } }) .filter(item => !!item); return result.join('\n'); }; exports.getShadowsocksNodesJSON = (list) => { const nodes = list .map(nodeConfig => { if (nodeConfig.enable === false) { return null; } switch (nodeConfig.type) { case types_1.NodeTypeEnum.Shadowsocks: { const useObfs = Boolean(nodeConfig.obfs && nodeConfig['obfs-host']); return Object.assign({ remarks: nodeConfig.nodeName, server: nodeConfig.hostname, server_port: nodeConfig.port, method: nodeConfig.method, remarks_base64: exports.toUrlSafeBase64(nodeConfig.nodeName), password: nodeConfig.password, tcp_over_udp: false, udp_over_tcp: false, enable: true }, (useObfs ? { plugin: 'obfs-local', 'plugin-opts': `obfs=${nodeConfig.obfs};obfs-host=${nodeConfig['obfs-host']}` } : null)); } // istanbul ignore next default: console.info(`${nodeConfig.type} is not supported, ${nodeConfig.nodeName} will be ignored.`); return null; } }) .filter(item => item !== null); return JSON.stringify(nodes, null, 2); }; exports.getNodeNames = (list, nodeTypeList = [types_1.NodeTypeEnum.Shadowsocks, types_1.NodeTypeEnum.HTTPS, types_1.NodeTypeEnum.Snell], filter) => { const nodes = list.filter(item => { const result = nodeTypeList.includes(item.type) && item.enable !== false; if (filter) { return filter(item) && result; } return result; }); return nodes.map(item => item.nodeName).join(', '); }; exports.getClashNodeNames = (ruleName, ruleType, nodeNameList, nodeTypeList = [types_1.NodeTypeEnum.Shadowsocks], filter) => { const nodes = nodeNameList.filter(item => { const result = nodeTypeList.includes(item.type) && item.enable !== false; if (filter) { return filter(item) && result; } return result; }); return Object.assign({ type: ruleType, name: ruleName, proxies: nodes.map(item => item.nodeName) }, (ruleType === 'url-test' ? { url: 'http://www.qualcomm.cn/generate_204', interval: 1200, } : null)); }; exports.toYaml = (obj) => yaml_1.default.stringify(obj); exports.pickAndFormatStringList = (obj, keyList) => { const result = []; keyList.forEach(key => { if (obj.hasOwnProperty(key)) { result.push(`${key}=${obj[key]}`); } }); return result; }; exports.decodeStringList = (stringList) => { const result = {}; stringList.forEach(item => { const pair = item.split('='); result[pair[0]] = pair[1] || true; }); return result; }; exports.loadConfig = (cwd, configPath, override) => { const absPath = path_1.default.resolve(cwd, configPath); if (!fs_extra_1.default.existsSync(absPath)) { throw new Error(`${absPath} cannot be found.`); } if (override) { return Object.assign(Object.assign({}, config_1.normalizeConfig(cwd, require(absPath))), override); } return config_1.normalizeConfig(cwd, require(absPath)); }; exports.normalizeClashProxyGroupConfig = (nodeList, customFilters, proxyGroupModifier) => { const proxyGroup = proxyGroupModifier(nodeList, customFilters); return proxyGroup.map(item => { if (item.filter) { return exports.getClashNodeNames(item.name, item.type, nodeList, [ types_1.NodeTypeEnum.Shadowsocks, types_1.NodeTypeEnum.Vmess, ], item.filter); } else if (item.proxies) { return item; } else { return exports.getClashNodeNames(item.name, item.type, nodeList, [ types_1.NodeTypeEnum.Shadowsocks, types_1.NodeTypeEnum.Vmess, ]); } }); }; exports.addProxyToSurgeRuleSet = (str, rule) => { const result = []; str .split('\n') .filter(item => item && item.trim() !== '') .forEach(item => { if (!item.startsWith('#') && !item.startsWith('//')) { const comment = item.split('//'); const line = comment[0].trim().split(','); if (line.length === 2) { line.push(rule); } else { line.splice(2, 0, rule); } result.push(line.join(',') + (comment[1] ? ` //${comment[1]}` : '')); } else { result.push(item); } }); return result.join('\n'); }; exports.loadRemoteSnippetList = (remoteSnippetList) => { function load(url) { console.log(`下载远程片段:${url}`); return axios_1.default.get(url, { timeout: 20000, proxy: false, responseType: 'text', }) .then(data => data.data) .catch(err => { console.error(`远程片段 ${url} 下载失败。`); throw err; }); } return Promise.all(remoteSnippetList.map(item => { return load(item.url) .then(res => ({ main: (rule) => exports.addProxyToSurgeRuleSet(res, rule), name: item.name, url: item.url, text: res, })); })); }; exports.ensureConfigFolder = (dir = os_1.default.homedir()) => { const configDir = path_1.default.join(dir, '.config/surgio'); fs_extra_1.default.mkdirpSync(configDir); return configDir; }; exports.formatV2rayConfig = (localPort, nodeConfig) => { const config = { log: { loglevel: 'warning' }, inbound: { port: localPort, listen: '127.0.0.1', protocol: 'socks', settings: { auth: 'noauth', } }, outbound: { protocol: 'vmess', settings: { vnext: [ { address: nodeConfig.hostname, port: nodeConfig.port, users: [ { id: nodeConfig.uuid, alterId: Number(nodeConfig.alterId), security: nodeConfig.method, level: 0, } ] } ] }, streamSettings: { security: 'none', }, } }; if (nodeConfig.tls) { config.outbound.streamSettings = Object.assign(Object.assign({}, config.outbound.streamSettings), { security: 'tls', tlsSettings: { serverName: nodeConfig.host || nodeConfig.hostname, } }); } if (nodeConfig.network === 'ws') { config.outbound.streamSettings = Object.assign(Object.assign({}, config.outbound.streamSettings), { network: nodeConfig.network, wsSettings: { path: nodeConfig.path, headers: { Host: nodeConfig.host, 'User-Agent': exports.OBFS_UA, }, } }); } return config; }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvdXRpbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsa0RBQTBCO0FBQzFCLDRFQUFzQztBQUN0Qyx3REFBMEI7QUFDMUIsb0RBQXVCO0FBQ3ZCLDBEQUE0QjtBQUM1QixnREFBd0I7QUFDeEIsZ0VBQXVDO0FBRXZDLDhDQUFzQjtBQUN0QixvRUFBMkM7QUFDM0MsZ0RBQXdCO0FBQ3hCLDRDQUFvQjtBQUVwQixvQ0FnQmtCO0FBQ2xCLHFDQUEyQztBQUU5QixRQUFBLE9BQU8sR0FBRyxpSEFBaUgsQ0FBQztBQUN6SSxNQUFNLFdBQVcsR0FBRyxJQUFJLG1CQUFHLENBQWM7SUFDdkMsTUFBTSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSTtDQUN2QixDQUFDLENBQUM7QUFFSCx1QkFBdUI7QUFDVixRQUFBLFdBQVcsR0FBRyxDQUFDLEdBQUcsSUFBdUIsRUFBVSxFQUFFLENBQUMsY0FBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7QUFFOUYsUUFBQSxjQUFjLEdBQUcsQ0FBQyxVQUFrQixHQUFHLEVBQUUsWUFBb0IsRUFBVSxFQUFFLENBQUMsR0FBRyxPQUFPLEdBQUcsWUFBWSxFQUFFLENBQUM7QUFFdEcsUUFBQSxpQkFBaUIsR0FBRyxLQUFLLEVBQUUsTUFHdkMsRUFBMkMsRUFBRTtJQUM1QyxnQkFBTSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsNEJBQTRCLENBQUMsQ0FBQztJQUN0RCxnQkFBTSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsNEJBQTRCLENBQUMsQ0FBQztJQUV0RCxNQUFNLEdBQUcsR0FBRyxZQUFZLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUUxQyxLQUFLLFVBQVUseUJBQXlCLENBQUMsUUFBZ0IsRUFBRSxRQUFnQjtRQUN6RSxNQUFNLFFBQVEsR0FBRyxNQUFNLGVBQUs7YUFDekIsR0FBRyxDQUFDLDZDQUE2QyxFQUFFO1lBQ2xELE1BQU0sRUFBRTtnQkFDTixRQUFRO2dCQUNSLFFBQVE7YUFDVDtZQUNELE9BQU8sRUFBRSxLQUFLO1lBQ2QsS0FBSyxFQUFFLEtBQUs7WUFDWixPQUFPLEVBQUU7Z0JBQ1AsWUFBWSxFQUFFLHFEQUFxRDthQUNwRTtTQUNGLENBQUMsQ0FBQztRQUVMLE1BQU0sTUFBTSxHQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBNEIsQ0FBQyxHQUFHLENBQWtCLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN2RixRQUFRLEVBQUUsR0FBRyw0QkFBSSxDQUFDLElBQUksQ0FBQyxZQUFzQixDQUFDLEdBQUcsSUFBSSxDQUFDLElBQWMsRUFBRTtZQUN0RSxJQUFJLEVBQUUsb0JBQVksQ0FBQyxLQUFLO1lBQ3hCLFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBZ0I7WUFDL0IsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFjO1lBQ3pCLFFBQVE7WUFDUixRQUFRO1NBQ1QsQ0FBQyxDQUFDLENBQUM7UUFFSixXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUU3QixPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsT0FBTyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDM0IsV0FBVyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3RCLE1BQU0seUJBQXlCLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDdEUsQ0FBQyxDQUFDO0FBRVcsUUFBQSx3QkFBd0IsR0FBRyxLQUFLLEVBQUUsTUFHOUMsRUFBaUQsRUFBRTtJQUNsRCxnQkFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsMkJBQTJCLENBQUMsQ0FBQztJQUVoRCxLQUFLLFVBQVUsdUJBQXVCLENBQUMsR0FBVztRQUNoRCxNQUFNLFFBQVEsR0FBRyxNQUFNLGVBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFO1lBQ3BDLEtBQUssRUFBRSxLQUFLO1lBQ1osT0FBTyxFQUFFLEtBQUs7U0FDZixDQUFDLENBQUM7UUFFSCxNQUFNLE1BQU0sR0FBSSxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQTBCLENBQUMsR0FBRyxDQUF3QixJQUFJLENBQUMsRUFBRTtZQUN6RixNQUFNLFVBQVUsR0FBUTtnQkFDdEIsUUFBUSxFQUFFLElBQUksQ0FBQyxPQUFpQjtnQkFDaEMsSUFBSSxFQUFFLG9CQUFZLENBQUMsV0FBVztnQkFDOUIsUUFBUSxFQUFFLElBQUksQ0FBQyxNQUFnQjtnQkFDL0IsSUFBSSxFQUFFLElBQUksQ0FBQyxXQUFxQjtnQkFDaEMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFnQjtnQkFDN0IsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFrQjthQUNsQyxDQUFDO1lBRUYsSUFBSSxPQUFPLE1BQU0sQ0FBQyxRQUFRLEtBQUssU0FBUyxFQUFFO2dCQUN4QyxVQUFVLENBQUMsV0FBVyxDQUFDLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7YUFDOUQ7WUFDRCxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssWUFBWSxFQUFFO2dCQUNoQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDbEQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztnQkFFM0QsSUFBSSxJQUFJLEVBQUU7b0JBQ1IsVUFBVSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQzFCLFVBQVUsQ0FBQyxXQUFXLENBQUMsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDO2lCQUNuRTthQUNGO1lBRUQsT0FBTyxVQUFVLENBQUM7UUFDcEIsQ0FBQyxDQUFDLENBQUM7UUFFSCxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUU3QixPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsT0FBTyxXQUFXLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ2xDLFdBQVcsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDN0IsTUFBTSx1QkFBdUIsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDOUMsQ0FBQyxDQUFDO0FBRVcsUUFBQSwwQkFBMEIsR0FBRyxLQUFLLEVBQUUsTUFHaEQsRUFBaUQsRUFBRTtJQUNsRCxnQkFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsMkJBQTJCLENBQUMsQ0FBQztJQUVoRCxLQUFLLFVBQVUsdUJBQXVCLENBQUMsR0FBVztRQUNoRCxNQUFNLFFBQVEsR0FBRyxNQUFNLGVBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFO1lBQ3BDLEtBQUssRUFBRSxLQUFLO1lBQ1osT0FBTyxFQUFFLEtBQUs7WUFDZCxZQUFZLEVBQUUsTUFBTTtTQUNyQixDQUFDLENBQUM7UUFFSCxNQUFNLFVBQVUsR0FBRyxrQkFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hGLE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQU0sSUFBSSxDQUFDLEVBQUU7WUFDeEMsTUFBTSxNQUFNLEdBQUcsYUFBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDckMsTUFBTSxRQUFRLEdBQUcseUJBQWlCLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMzRCxNQUFNLFVBQVUsR0FBRyxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsd0JBQWdCLENBQU0sTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUV4SCxxQ0FDRSxJQUFJLEVBQUUsb0JBQVksQ0FBQyxXQUFXLEVBQzlCLFFBQVEsRUFBRSxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFDMUQsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQ3pCLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxFQUNqQixNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUNuQixRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUNsQixDQUFDLE9BQU8sTUFBTSxDQUFDLFFBQVEsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDO2dCQUN6QyxXQUFXLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPO2FBQ2hELENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUNOLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDN0IsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJO2dCQUNyQixXQUFXLEVBQUUsVUFBVSxDQUFDLFdBQVcsQ0FBQzthQUNyQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFDVDtRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsV0FBVyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFN0IsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELE9BQU8sV0FBVyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNsQyxXQUFXLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzdCLE1BQU0sdUJBQXVCLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzlDLENBQUMsQ0FBQztBQUVXLFFBQUEsMkJBQTJCLEdBQUcsS0FBSyxFQUFFLE1BRWpELEVBQWtELEVBQUU7SUFDbkQsZ0JBQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLDJCQUEyQixDQUFDLENBQUM7SUFFaEQsS0FBSyxVQUFVLHVCQUF1QixDQUFDLEdBQVc7UUFDaEQsTUFBTSxRQUFRLEdBQUcsTUFBTSxlQUFLLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTtZQUNwQyxLQUFLLEVBQUUsS0FBSztZQUNaLE9BQU8sRUFBRSxLQUFLO1lBQ2QsWUFBWSxFQUFFLE1BQU07U0FDckIsQ0FBQyxDQUFDO1FBRUgsTUFBTSxVQUFVLEdBQUcsa0JBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoRixNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsR0FBRyxDQUF5QixJQUFJLENBQUMsRUFBRTtZQUMzRCxNQUFNLElBQUksR0FBRyx5QkFBaUIsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN0RSxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3JDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsYUFBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUN6RCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLHlCQUFpQixDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBaUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFFbkYsSUFBSSxDQUFDLFFBQVEsRUFBRTtnQkFDYixNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsSUFBSSw2QkFBNkIsQ0FBQyxDQUFDO2FBQ3ZEO1lBRUQsT0FBTztnQkFDTCxJQUFJLEVBQUUsb0JBQVksQ0FBQyxZQUFZO2dCQUMvQixRQUFRO2dCQUNSLFFBQVEsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO2dCQUN0QixJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztnQkFDbEIsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3RCLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO2dCQUNwQixJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztnQkFDbEIsUUFBUSxFQUFFLHlCQUFpQixDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDekMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMseUJBQWlCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFvQixJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFO2dCQUNwRixTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyx5QkFBaUIsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQW1CLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7YUFDbkYsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsV0FBVyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFN0IsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELE9BQU8sV0FBVyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNsQyxXQUFXLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzdCLE1BQU0sdUJBQXVCLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzlDLENBQUMsQ0FBQztBQUVXLFFBQUEscUJBQXFCLEdBQUcsS0FBSyxFQUFFLE1BRTNDLEVBQTJDLEVBQUU7SUFDNUMsZ0JBQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLDJCQUEyQixDQUFDLENBQUM7SUFFaEQsS0FBSyxVQUFVLHVCQUF1QixDQUFDLEdBQVc7UUFDaEQsTUFBTSxRQUFRLEdBQUcsTUFBTSxlQUFLLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRTtZQUNwQyxLQUFLLEVBQUUsS0FBSztZQUNaLE9BQU8sRUFBRSxLQUFLO1lBQ2QsWUFBWSxFQUFFLE1BQU07U0FDckIsQ0FBQyxDQUFDO1FBRUgsTUFBTSxVQUFVLEdBQUcsa0JBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoRixNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFrQixJQUFJLENBQUMsRUFBRTtZQUNwRCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGtCQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRWxFLElBQUksSUFBSSxDQUFDLENBQUMsS0FBSyxHQUFHLEVBQUU7Z0JBQ2xCLE1BQU0sSUFBSSxLQUFLLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQyxDQUFDO2FBQ3JDO1lBRUQsT0FBTztnQkFDTCxRQUFRLEVBQUUsSUFBSSxDQUFDLEVBQUU7Z0JBQ2pCLElBQUksRUFBRSxvQkFBWSxDQUFDLEtBQUs7Z0JBQ3hCLFFBQVEsRUFBRSxJQUFJLENBQUMsR0FBRztnQkFDbEIsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJO2dCQUNmLE1BQU0sRUFBRSxNQUFNO2dCQUNkLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRTtnQkFDYixPQUFPLEVBQUUsSUFBSSxDQUFDLEdBQUcsSUFBSSxHQUFHO2dCQUN4QixPQUFPLEVBQUUsSUFBSSxDQUFDLEdBQUc7Z0JBQ2pCLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxLQUFLLEtBQUs7Z0JBQ3ZCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxJQUFJLEVBQUU7Z0JBQ3JCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxJQUFJLEdBQUc7YUFDdkIsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsV0FBVyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFN0IsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELE9BQU8sV0FBVyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNsQyxXQUFXLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzdCLE1BQU0sdUJBQXVCLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzlDLENBQUMsQ0FBQztBQUVXLFFBQUEsYUFBYSxHQUFHLENBQzNCLElBQWlILEVBQ2pILE1BQXVCLEVBQ2YsRUFBRTtJQUNWLE1BQU0sTUFBTSxHQUFhLElBQUk7U0FDMUIsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztTQUM1QyxHQUFHLENBQVMsVUFBVSxDQUFDLEVBQUU7UUFDeEIsSUFBSSxVQUFVLENBQUMsTUFBTSxLQUFLLEtBQUssRUFBRTtZQUFFLE9BQU8sSUFBSSxDQUFDO1NBQUU7UUFFakQsUUFBUSxVQUFVLENBQUMsSUFBSSxFQUFFO1lBQ3ZCLEtBQUssb0JBQVksQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDN0IsTUFBTSxNQUFNLEdBQUcsVUFBbUMsQ0FBQztnQkFFbkQsT0FBTyxDQUFDO29CQUNOLE1BQU0sQ0FBQyxRQUFRO29CQUNmO3dCQUNFLFFBQVE7d0JBQ1IsTUFBTSxDQUFDLFFBQVE7d0JBQ2YsTUFBTSxDQUFDLElBQUk7d0JBQ1gsTUFBTSxDQUFDLE1BQU07d0JBQ2IsTUFBTSxDQUFDLFFBQVE7d0JBQ2YsZ0ZBQWdGO3dCQUNoRixHQUFHLCtCQUF1QixDQUFDLE1BQU0sRUFBRSxDQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsV0FBVyxDQUFDLENBQUM7cUJBQ3ZFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztpQkFDYixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO2FBQ2hCO1lBRUQsS0FBSyxvQkFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN2QixNQUFNLE1BQU0sR0FBRyxVQUE2QixDQUFDO2dCQUU3QyxPQUFPLENBQUM7b0JBQ04sTUFBTSxDQUFDLFFBQVE7b0JBQ2Y7d0JBQ0UsT0FBTzt3QkFDUCxNQUFNLENBQUMsUUFBUTt3QkFDZixNQUFNLENBQUMsSUFBSTt3QkFDWCxNQUFNLENBQUMsUUFBUTt3QkFDZixNQUFNLENBQUMsUUFBUTtxQkFDaEIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2lCQUNiLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7YUFDaEI7WUFFRCxLQUFLLG9CQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ3ZCLE1BQU0sTUFBTSxHQUFHLFVBQTZCLENBQUM7Z0JBRTdDLE9BQU8sQ0FBQztvQkFDTixNQUFNLENBQUMsUUFBUTtvQkFDZjt3QkFDRSxPQUFPO3dCQUNQLE1BQU0sQ0FBQyxRQUFRO3dCQUNmLE1BQU0sQ0FBQyxJQUFJO3dCQUNYLEdBQUcsK0JBQXVCLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO3FCQUNwRCxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7aUJBQ2IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQzthQUNoQjtZQUVELEtBQUssb0JBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDOUIsTUFBTSxNQUFNLEdBQUcsVUFBb0MsQ0FBQztnQkFFcEQsdUJBQXVCO2dCQUN2QixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtvQkFDbkIsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO2lCQUMxRTtnQkFFRCxNQUFNLElBQUksR0FBRztvQkFDWCxJQUFJLEVBQUUsTUFBTSxDQUFDLFFBQVE7b0JBQ3JCLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLEVBQUU7b0JBQ3RCLElBQUksRUFBRSxNQUFNLENBQUMsTUFBTTtvQkFDbkIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJO29CQUNqQixJQUFJLEVBQUUsTUFBTSxDQUFDLFFBQVE7b0JBQ3JCLElBQUksRUFBRSxNQUFNLENBQUMsUUFBUTtvQkFDckIsSUFBSSxFQUFFLEdBQUcsTUFBTSxDQUFDLFNBQVMsRUFBRTtvQkFDM0IsSUFBSSxFQUFFLFdBQVc7aUJBQ2xCLENBQUM7Z0JBRUYsSUFBSSxNQUFNLENBQUMsVUFBVSxFQUFFO29CQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7aUJBQ3BDO2dCQUNELElBQUksTUFBTSxDQUFDLFNBQVMsRUFBRTtvQkFDcEIsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2lCQUNuQztnQkFFRCxNQUFNLFlBQVksR0FBRztvQkFDbkIsVUFBVTtvQkFDVixVQUFVLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFO29CQUMxQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsVUFBVSxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ3JELGdCQUFnQixNQUFNLENBQUMsU0FBUyxFQUFFO29CQUNsQyxlQUFlLE1BQU0sQ0FBQyxRQUFRLEVBQUU7aUJBQ2pDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUViLE9BQU8sQ0FBQztvQkFDTixNQUFNLENBQUMsUUFBUTtvQkFDZixZQUFZO2lCQUNiLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7YUFDaEI7WUFFRCxLQUFLLG9CQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ3ZCLE1BQU0sTUFBTSxHQUFHLFVBQTZCLENBQUM7Z0JBRTdDLElBQ0UsVUFBVSxDQUFDLFdBQVc7b0JBQ3RCLFVBQVUsQ0FBQyxXQUFXLENBQUMsS0FBSyxLQUFLLFFBQVEsRUFDekM7b0JBQ0EsMkJBQTJCO29CQUUzQixNQUFNLFVBQVUsR0FBRzt3QkFDakIsT0FBTzt3QkFDUCxNQUFNLENBQUMsUUFBUTt3QkFDZixNQUFNLENBQUMsSUFBSTt3QkFDWCxZQUFZLE1BQU0sQ0FBQyxJQUFJLEVBQUU7cUJBQzFCLENBQUM7b0JBRUYsU0FBUyxTQUFTLENBQ2hCLElBQUksRUFDSixFQUFFLEdBQUcsZUFBTzt3QkFFWixPQUFPOzRCQUNMLFFBQVEsSUFBSSxFQUFFOzRCQUNkLGNBQWMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsRUFBRTt5QkFDbkMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7b0JBQ2QsQ0FBQztvQkFFRCxJQUFJLE1BQU0sQ0FBQyxPQUFPLEtBQUssSUFBSSxFQUFFO3dCQUMzQixVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO3dCQUMzQixVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7d0JBQzFDLFVBQVUsQ0FBQyxJQUFJLENBQ2IsYUFBYTs0QkFDYixTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLENBQzFDLENBQUM7cUJBQ0g7b0JBRUQsSUFBSSxNQUFNLENBQUMsR0FBRyxFQUFFO3dCQUNkLFVBQVUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7cUJBQzdCO29CQUVELE9BQU8sQ0FBQzt3QkFDTixNQUFNLENBQUMsUUFBUTt3QkFDZixVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztxQkFDdEIsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFDaEI7cUJBQU07b0JBQ0wsMEJBQTBCO29CQUUxQix1QkFBdUI7b0JBQ3ZCLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFO3dCQUNuQixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7cUJBQ25FO29CQUVELE1BQU0sWUFBWSxHQUFHLFNBQVMsTUFBTSxDQUFDLFNBQVMsSUFBSSxNQUFNLENBQUMsUUFBUSxJQUFJLE1BQU0sQ0FBQyxJQUFJLE9BQU8sQ0FBQztvQkFDeEYsTUFBTSxZQUFZLEdBQUcsY0FBSSxDQUFDLElBQUksQ0FBQywwQkFBa0IsRUFBRSxFQUFFLFlBQVksQ0FBQyxDQUFDO29CQUNuRSxNQUFNLFFBQVEsR0FBRyx5QkFBaUIsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO29CQUNqRSxNQUFNLElBQUksR0FBRzt3QkFDWCxVQUFVLEVBQUUsWUFBWSxDQUFDLE9BQU8sQ0FBQyxZQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsT0FBTyxDQUFDO3FCQUN4RCxDQUFDO29CQUNGLE1BQU0sWUFBWSxHQUFHO3dCQUNuQixVQUFVO3dCQUNWLFVBQVUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUU7d0JBQzFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxVQUFVLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQzt3QkFDckQsZ0JBQWdCLE1BQU0sQ0FBQyxTQUFTLEVBQUU7d0JBQ2xDLGVBQWUsTUFBTSxDQUFDLFFBQVEsRUFBRTtxQkFDakMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBRWIsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsS0FBSyxNQUFNLEVBQUU7d0JBQ25DLGtCQUFFLENBQUMsYUFBYSxDQUFDLFlBQVksRUFBRSxRQUFRLENBQUMsQ0FBQztxQkFDMUM7b0JBRUQsT0FBTyxDQUFDO3dCQUNOLE1BQU0sQ0FBQyxRQUFRO3dCQUNmLFlBQVk7cUJBQ2IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFDaEI7YUFDRjtZQUVELHVCQUF1QjtZQUN2QjtnQkFDRSxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsVUFBVyxDQUFDLElBQUksc0JBQXNCLFVBQVcsQ0FBQyxRQUFRLG1CQUFtQixDQUFDLENBQUM7Z0JBQy9GLE9BQU8sSUFBSSxDQUFDO1NBQ2Y7SUFDSCxDQUFDLENBQUM7U0FDRCxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUM7SUFFakMsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzNCLENBQUMsQ0FBQztBQUVXLFFBQUEsYUFBYSxHQUFHLENBQzNCLElBQTJDLEVBQzNDLE1BQXVCLEVBQ0gsRUFBRTtJQUN0QixPQUFPLElBQUk7U0FDUixNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1NBQzVDLEdBQUcsQ0FBQyxVQUFVLENBQUMsRUFBRTtRQUNoQixJQUFJLFVBQVUsQ0FBQyxNQUFNLEtBQUssS0FBSyxFQUFFO1lBQUUsT0FBTyxJQUFJLENBQUM7U0FBRTtRQUVqRCxRQUFRLFVBQVUsQ0FBQyxJQUFJLEVBQUU7WUFDdkIsS0FBSyxvQkFBWSxDQUFDLFdBQVc7Z0JBQzNCLHVCQUNFLElBQUksRUFBRSxJQUFJLEVBQ1YsTUFBTSxFQUFFLFVBQVUsQ0FBQyxNQUFNLEVBQ3pCLElBQUksRUFBRSxVQUFVLENBQUMsUUFBUSxFQUN6QixRQUFRLEVBQUUsVUFBVSxDQUFDLFFBQVEsRUFDN0IsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJLEVBQ3JCLE1BQU0sRUFBRSxVQUFVLENBQUMsUUFBUSxFQUMzQixHQUFHLEVBQUUsVUFBVSxDQUFDLFdBQVcsQ0FBQyxLQUFLLE1BQU0sSUFDcEMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztvQkFDcEIsTUFBTSxFQUFFLE1BQU07b0JBQ2QsYUFBYSxFQUFFO3dCQUNiLElBQUksRUFBRSxVQUFVLENBQUMsSUFBSTt3QkFDckIsSUFBSSxFQUFFLFVBQVUsQ0FBQyxXQUFXLENBQUM7cUJBQzlCO2lCQUNGLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUNUO1lBRUosS0FBSyxvQkFBWSxDQUFDLEtBQUs7Z0JBQ3JCLG1EQUNFLElBQUksRUFBRSxPQUFPLEVBQ2IsTUFBTSxFQUFFLFVBQVUsQ0FBQyxNQUFNLEVBQ3pCLElBQUksRUFBRSxVQUFVLENBQUMsUUFBUSxFQUN6QixNQUFNLEVBQUUsVUFBVSxDQUFDLFFBQVEsRUFDM0IsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJLEVBQ3JCLElBQUksRUFBRSxVQUFVLENBQUMsSUFBSSxFQUNyQixPQUFPLEVBQUUsVUFBVSxDQUFDLE9BQU8sSUFDeEIsQ0FBQyxVQUFVLENBQUMsT0FBTyxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztvQkFDeEMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxPQUFPO2lCQUM1QixDQUFDLEtBQ0YsR0FBRyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEtBQ2hCLENBQUMsVUFBVSxDQUFDLE9BQU8sS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDO29CQUNoQyxTQUFTLEVBQUUsVUFBVSxDQUFDLElBQUk7b0JBQzFCLFlBQVksb0JBQ1AsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUN4RDtpQkFDRixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFDVDtZQUVKLEtBQUssb0JBQVksQ0FBQyxZQUFZO2dCQUM1QixPQUFPO29CQUNMLElBQUksRUFBRSxLQUFLO29CQUNYLElBQUksRUFBRSxVQUFVLENBQUMsUUFBUTtvQkFDekIsTUFBTSxFQUFFLFVBQVUsQ0FBQyxRQUFRO29CQUMzQixJQUFJLEVBQUUsVUFBVSxDQUFDLElBQUk7b0JBQ3JCLFFBQVEsRUFBRSxVQUFVLENBQUMsUUFBUTtvQkFDN0IsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJO29CQUNyQixTQUFTLEVBQUUs