diff --git a/.eslintignore b/.eslintignore
index 52ee69b..e9f080c 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -13,4 +13,6 @@ app/web/store
plugins/
app/web/asset/
app/view/
-test.js
\ No newline at end of file
+test.js
+
+config/manifest.json
diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 213f055..0000000
--- a/.eslintrc
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "parser": "babel-eslint",
- "env": {
- "node": true,
- "es6": true,
- "mocha": true
- },
- "parserOptions": {
- "sourceType": "module",
- "ecmaVersion": 8,
- "ecmaFeatures": {
- "jsx": true
- }
- },
- "rules": {
- "indent": [
- "error",
- 4
- ],
- "new-cap": "off",
- "newline-after-var": "off",
- "no-invalid-this": "off",
- "guard-for-in": "off",
- "no-console": "off",
- "no-undefined": "off",
- "array-bracket-spacing": "off",
- "no-unused-expressions": "off",
- "linebreak-style": "off",
- "func-style": 0,
- "comma-dangle": [
- "error",
- "never"
- ]
- },
- "plugins": [
- "react"
- ],
- "globals": {
- "EASY_ENV_IS_PROD": true,
- "EASY_ENV_IS_NODE": true,
- "EASY_ENV_IS_BROWSER": true,
- "EASY_ENV_IS_DEV": true
- }
-}
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..6a0d9a7
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,12 @@
+module.exports = {
+ extends: [require.resolve('ko-lint-config/.eslintrc')],
+ rules: {
+ 'no-param-reassign': 0,
+ 'prefer-rest-params': 0,
+ 'no-octal-escape': 0,
+ 'new-cap': 0,
+ 'no-new': 0,
+ 'react/no-unescaped-entities': 0,
+ 'no-control-regex': 0,
+ },
+};
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
new file mode 100644
index 0000000..0a38429
--- /dev/null
+++ b/.github/workflows/CI.yml
@@ -0,0 +1,43 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - 'master'
+ pull_request:
+ branches:
+ - '*'
+
+jobs:
+ setup:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ node-version: [14.x, 16.x]
+ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+
+ - name: Install dependencies
+ run: yarn
+
+ - name: Run Prettier
+ run: yarn prettier
+
+ - name: Run Eslint
+ run: yarn eslint
+
+ - name: Run Stylelint
+ run: yarn stylelint
+
+ - name: Run check-types
+ run: yarn check-types
+
+ - name: Run build
+ run: yarn build
diff --git a/.gitignore b/.gitignore
index 99440b3..ebb9c12 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-.vscode
node_modules
config/manifest.json
run
@@ -7,4 +6,4 @@ cache
.history
public
resources
-app/view
\ No newline at end of file
+app/view
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..6e10cd7
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,8 @@
+# Please Checkout And Make Sure Patterns Isn't Exist In .gitignore File First
+*.md
+**/iconfont*/*
+*.yml
+app/view/
+public
+
+config/manifest.json
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000..91db763
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,5 @@
+const prettier = require('ko-lint-config/.prettierrc');
+
+module.exports = {
+ ...prettier,
+};
diff --git a/.stylelintignore b/.stylelintignore
new file mode 100644
index 0000000..348aa40
--- /dev/null
+++ b/.stylelintignore
@@ -0,0 +1,5 @@
+# Please Checkout And Make Sure Patterns Isn't Exist In .gitignore File First
+
+**/iconfont*/*
+app/view/
+public
diff --git a/.stylelintrc.js b/.stylelintrc.js
new file mode 100644
index 0000000..16a21d6
--- /dev/null
+++ b/.stylelintrc.js
@@ -0,0 +1,6 @@
+module.exports = {
+ extends: ['ko-lint-config/.stylelintrc'],
+ rules: {
+ 'value-no-vendor-prefix': null,
+ },
+};
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..23b9698
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,4 @@
+{
+ "editor.formatOnSave": true,
+ "cSpell.words": ["SUBSCRIPTIONSENDTYPE", "SUBSCRIPTIONSENDTYPECN", "SUBSCRIPTIONSTATUS"]
+}
diff --git a/DingBot.js b/DingBot.js
index 592fec4..807626e 100644
--- a/DingBot.js
+++ b/DingBot.js
@@ -3,7 +3,7 @@ const version = require('./package.json').version;
const config = require('./env.json');
const Logger = require('egg-logger').Logger;
const logger = new Logger('DingdingBot');
-const botWebhookUrl = config && config.webhookUrls ? config.webhookUrls : []; //钉钉通知群
+const botWebhookUrl = config && config.webhookUrls ? config.webhookUrls : []; // 钉钉通知群
const ApplicationTypeHeader = 'application/json;charset=utf-8';
// DingdingBot
class DingdingBot {
@@ -12,36 +12,35 @@ class DingdingBot {
this._webhookUrl = webhookUrl;
}
- pushMsg(msg, atMobiles) {
+ pushMsg(msg, _atMobiles) {
try {
-
- let options = {
+ const options = {
headers: {
- 'Content-Type': ApplicationTypeHeader
+ 'Content-Type': ApplicationTypeHeader,
},
json: {
- 'msgtype': 'actionCard',
- 'actionCard': {
- 'title': 'Doraemon发布通知',
- 'text': `### Doraemon v${version} 发布成功  \n>致力于解放更多生产力,让日常工作变的更加高效、轻松、便捷、愉快~`,
- 'btnOrientation': '0',
- 'singleTitle': '阅读全文',
- 'singleURL': config && config.msgSingleUrl ? config.msgSingleUrl : ''
- }
- }
+ msgtype: 'actionCard',
+ actionCard: {
+ title: 'Doraemon发布通知',
+ text: `### Doraemon v${version} 发布成功  \n>致力于解放更多生产力,让日常工作变的更加高效、轻松、便捷、愉快~`,
+ btnOrientation: '0',
+ singleTitle: '阅读全文',
+ singleURL: config && config.msgSingleUrl ? config.msgSingleUrl : '',
+ },
+ },
};
+ // eslint-disable-next-line n/handle-callback-err
request.post(this._webhookUrl, options, function (error, response, body) {
logger.debug(`push msg ${msg}, response: ${JSON.stringify(body)}`);
});
- }
- catch (err) {
+ } catch (err) {
console.error(err);
return false;
}
}
}
-botWebhookUrl.forEach(item => {
- let bot = new DingdingBot(item);;
+botWebhookUrl.forEach((item) => {
+ const bot = new DingdingBot(item);
// 直接推送消息
bot.pushMsg('发布通知');
-})
+});
diff --git a/agent.js b/agent.js
index c475a84..d58dcad 100644
--- a/agent.js
+++ b/agent.js
@@ -1,29 +1,35 @@
-const { createTimedTask, changeTimedTask, cancelTimedTask, timedTaskList, timedTaskResult } = require('./app/utils/timedTask')
+const {
+ createTimedTask,
+ changeTimedTask,
+ cancelTimedTask,
+ timedTaskList,
+ timedTaskResult,
+} = require('./app/utils/timedTask');
// 接收 app 发送来的消息并作出反应
-module.exports = agent => {
+module.exports = (agent) => {
// 创建文章订阅任务
agent.messenger.on('createTimedTask', ({ id, sendCron }) => {
- createTimedTask(id, sendCron, agent)
- })
+ createTimedTask(id, sendCron, agent);
+ });
// 改变文章订阅任务
agent.messenger.on('changeTimedTask', ({ id, sendCron }) => {
- changeTimedTask(id, sendCron, agent)
- })
+ changeTimedTask(id, sendCron, agent);
+ });
// 取消文章订阅任务
agent.messenger.on('cancelTimedTask', ({ id }) => {
- cancelTimedTask(id, agent)
- })
+ cancelTimedTask(id, agent);
+ });
// 文章订阅任务列表
agent.messenger.on('timedTaskList', () => {
- timedTaskList(agent)
- })
+ timedTaskList(agent);
+ });
// 打印文章订阅任务的执行结果
agent.messenger.on('timedTaskResult', ({ result }) => {
- timedTaskResult(result, agent)
- })
-}
+ timedTaskResult(result, agent);
+ });
+};
diff --git a/app.js b/app.js
index f9be6aa..f76c343 100644
--- a/app.js
+++ b/app.js
@@ -6,20 +6,20 @@ module.exports = class AppBootHook {
this.app = app;
}
async serverDidReady() {
- const {app} = this;
+ const { app } = this;
app.utils = utils;
- const {cacheDirectory} = app.config;
- if (!fs.existsSync(cacheDirectory)){
+ const { cacheDirectory } = app.config;
+ if (!fs.existsSync(cacheDirectory)) {
fs.mkdirSync(cacheDirectory);
}
// 监听 agent 进程发出的信息并作出反应
app.messenger.on('sendArticleSubscription', (id) => {
// create an anonymous context to access service
- const ctx = app.createAnonymousContext()
+ const ctx = app.createAnonymousContext();
ctx.runInBackground(async () => {
- await ctx.service.articleSubscription.sendArticleSubscription(id)
- })
- })
+ await ctx.service.articleSubscription.sendArticleSubscription(id);
+ });
+ });
}
-}
+};
diff --git a/app/consts/index.js b/app/consts/index.js
index ee72038..216b951 100644
--- a/app/consts/index.js
+++ b/app/consts/index.js
@@ -2,16 +2,16 @@
const SITE_NAME = {
GITHUB: 'Github',
JUEJIN: '掘金',
- ENGLISH: '英文'
-}
+ ENGLISH: '英文',
+};
// 订阅网站的二级分类 - 话题
const TOPIC_NAME = {
DEV_ARCHITECTURE: 'DEV Architecture',
- REACT_STATUS: 'React Status'
-}
+ REACT_STATUS: 'React Status',
+};
module.exports = {
SITE_NAME,
- TOPIC_NAME
-}
+ TOPIC_NAME,
+};
diff --git a/app/controller/appCenters.js b/app/controller/appCenters.js
index 0ad4a12..0163a0b 100644
--- a/app/controller/appCenters.js
+++ b/app/controller/appCenters.js
@@ -3,9 +3,9 @@ const _ = require('lodash');
const moment = require('moment');
const path = require('path');
const fs = require('fs');
-//异步二进制 写入流
+// 异步二进制 写入流
const awaitWriteStream = require('await-stream-ready').write;
-//管道读入一个虫洞。
+// 管道读入一个虫洞。
const sendToWormhole = require('stream-wormhole');
class AppCentersController extends Controller {
@@ -13,30 +13,44 @@ class AppCentersController extends Controller {
const { app, ctx } = this;
const { appName = '', appTags } = ctx.request.query;
const appResult = await app.model.AppCenters.findAndCountAll({
- attributes: ['id', 'appName', 'appTags', 'appDesc', 'appUrl', 'appType', 'clickCount', 'logoUrl', 'created_at', 'updated_at'],
- order: [['appType', 'ASC'], ['clickCount', 'DESC']],
+ attributes: [
+ 'id',
+ 'appName',
+ 'appTags',
+ 'appDesc',
+ 'appUrl',
+ 'appType',
+ 'clickCount',
+ 'logoUrl',
+ 'created_at',
+ 'updated_at',
+ ],
+ order: [
+ ['appType', 'ASC'],
+ ['clickCount', 'DESC'],
+ ],
where: {
status: 1,
appName: {
- '$like': `%${appName}%`
- }
- }
+ $like: `%${appName}%`,
+ },
+ },
});
- let tagsResult = await ctx.model.TagManagement.findAll(); // query
- let result = [];
- appResult.rows.forEach(item => {
+ const tagsResult = await ctx.model.TagManagement.findAll(); // query
+ const result = [];
+ appResult.rows.forEach((item) => {
const tags = item.get('appTags');
- let tagids = tags ? tags.split(',') : '';
- let tagArrs = tagsResult.filter(ele => {
- return tagids.includes(`${ele.get('id')}`)
+ const tagids = tags ? tags.split(',') : '';
+ const tagArrs = tagsResult.filter((ele) => {
+ return tagids.includes(`${ele.get('id')}`);
});
item.set('appTags', tagArrs);
if (appTags) {
- if (appTags.split(',').some(ele => tagids.includes(`${ele}`))) {
- result.push(item)
+ if (appTags.split(',').some((ele) => tagids.includes(`${ele}`))) {
+ result.push(item);
}
} else {
- result.push(item)
+ result.push(item);
}
});
ctx.body = app.utils.response(true, { data: result, count: result.length });
@@ -57,36 +71,47 @@ class AppCentersController extends Controller {
appDesc,
appTags: appTags.join(),
id,
- updated_at: moment().format('YYYY-MM-DD')
- })
+ updated_at: moment().format('YYYY-MM-DD'),
+ });
if (id) {
- ctx.body = app.utils.response(true, null)
- return
+ ctx.body = app.utils.response(true, null);
+ return;
}
- ctx.body = app.utils.response(true, result.get({
- plain: true
- }));
+ ctx.body = app.utils.response(
+ true,
+ result.get({
+ plain: true,
+ })
+ );
}
async getApplicationById() {
const { app, ctx } = this;
- const { id } = ctx.request.query
+ const { id } = ctx.request.query;
const result = await app.model.AppCenters.findOne({
- attributes: ['id', 'appName', 'appDesc', 'appTags', 'appUrl', 'created_at', 'updated_at'],
+ attributes: [
+ 'id',
+ 'appName',
+ 'appDesc',
+ 'appTags',
+ 'appUrl',
+ 'created_at',
+ 'updated_at',
+ ],
where: {
- id
- }
+ id,
+ },
});
ctx.body = app.utils.response(true, result);
}
async clickApplications() {
const { app, ctx } = this;
- const { params } = ctx.request.body
+ const { params } = ctx.request.body;
const result = await ctx.service.appCenters.clickApplications({
- ...params
- })
+ ...params,
+ });
ctx.body = app.utils.response(true, result);
}
@@ -107,25 +132,34 @@ class AppCentersController extends Controller {
const fileName = stream.filename;
// 目标文件夹,没有就创建,创建多级目录存储
const date = new Date();
- const dirTree = ['resources', 'imgs', date.getFullYear(), date.getMonth() + 1, date.getDate()];
+ const dirTree = [
+ 'resources',
+ 'imgs',
+ date.getFullYear(),
+ date.getMonth() + 1,
+ date.getDate(),
+ ];
const dir = app.utils.createFolder(dirTree);
// 创建文件
const target = path.join(dir, fileName);
const writeStream = fs.createWriteStream(target);
try {
- //异步把文件流 写入
+ // 异步把文件流 写入
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
- //如果出现错误,关闭管道
+ // 如果出现错误,关闭管道
await sendToWormhole(stream);
throw new Error('图片上传出错');
}
- const result = await this.ctx.model.AppCenters.update({ logoUrl: [...dirTree, fileName].join('/') }, {
- where: {
- id
+ const result = await this.ctx.model.AppCenters.update(
+ { logoUrl: [...dirTree, fileName].join('/') },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
ctx.body = app.utils.response(true, result);
}
}
-module.exports = AppCentersController;
\ No newline at end of file
+module.exports = AppCentersController;
diff --git a/app/controller/articleSubscription.js b/app/controller/articleSubscription.js
index 988fbe0..5ec14c9 100644
--- a/app/controller/articleSubscription.js
+++ b/app/controller/articleSubscription.js
@@ -9,22 +9,39 @@ class ArticleSubscriptionController extends Controller {
if (_.isNil(current)) throw new Error('缺少必要参 current');
if (_.isNil(size)) throw new Error('缺少必要参数 size');
- const data = await ctx.service.articleSubscription.getSubscriptionList({ current, size, searchText });
+ const data = await ctx.service.articleSubscription.getSubscriptionList({
+ current,
+ size,
+ searchText,
+ });
ctx.body = app.utils.response(true, {
- data: data.rows.map(item => {
+ data: data.rows.map((item) => {
return {
...item,
- topicIds: item.topicIds.split(',').map(i => +i)
- }
+ topicIds: item.topicIds.split(',').map((i) => +i),
+ };
}),
- count: data.count
+ count: data.count,
});
}
// 新增
async createSubscription() {
const { app, ctx } = this;
- const { groupName, webHook, remark, topicIds = [], siteNames, sendType, sendCron, time, status, messageTitle, message, isAtAll } = ctx.request.body;
+ const {
+ groupName,
+ webHook,
+ remark,
+ topicIds = [],
+ siteNames,
+ sendType,
+ sendCron,
+ time,
+ status,
+ messageTitle,
+ message,
+ isAtAll,
+ } = ctx.request.body;
if (_.isNil(groupName)) throw new Error('缺少必要参数 groupName');
if (_.isNil(webHook)) throw new Error('缺少必要参数 webHook');
if (_.isNil(siteNames)) throw new Error('缺少必要参数 siteNames');
@@ -32,27 +49,71 @@ class ArticleSubscriptionController extends Controller {
if (_.isNil(sendCron)) throw new Error('缺少必要参数 sendCron');
if (_.isNil(time)) throw new Error('缺少必要参数 time');
// 数据库插入数据
- const data = await ctx.service.articleSubscription.createSubscription({ groupName, webHook, remark, topicIds: topicIds?.join(','), siteNames, sendType, sendCron, time, status, messageTitle, message, isAtAll });
- const { id } = data
+ const data = await ctx.service.articleSubscription.createSubscription({
+ groupName,
+ webHook,
+ remark,
+ topicIds: topicIds?.join(','),
+ siteNames,
+ sendType,
+ sendCron,
+ time,
+ status,
+ messageTitle,
+ message,
+ isAtAll,
+ });
+ const { id } = data;
if (_.isNil(id)) throw new Error('创建失败');
// 向 agent 进程发消息
- app.messenger.sendToAgent('createTimedTask', { id, sendCron })
+ app.messenger.sendToAgent('createTimedTask', { id, sendCron });
ctx.body = app.utils.response(true, id);
}
// 更新
async updateSubscription() {
const { ctx, app } = this;
- const { id, groupName, webHook, remark, topicIds = [], siteNames, sendType, sendCron, time, status, messageTitle, message, isAtAll } = ctx.request.body;
+ const {
+ id,
+ groupName,
+ webHook,
+ remark,
+ topicIds = [],
+ siteNames,
+ sendType,
+ sendCron,
+ time,
+ status,
+ messageTitle,
+ message,
+ isAtAll,
+ } = ctx.request.body;
if (_.isNil(id)) throw new Error('缺少必要参数 id');
if (_.isNil(groupName)) throw new Error('缺少必要参数 groupName');
if (_.isNil(webHook)) throw new Error('缺少必要参数 webHook');
if (_.isNil(siteNames)) throw new Error('缺少必要参数 siteNames');
if (_.isNil(sendType)) throw new Error('缺少必要参数 sendType');
if (_.isNil(sendCron)) throw new Error('缺少必要参数 sendCron');
- await ctx.service.articleSubscription.updateSubscription(id, { groupName, webHook, remark, topicIds: topicIds?.join(','), siteNames, sendType, sendCron, time, status, messageTitle, message, isAtAll, updated_at: new Date() })
+ await ctx.service.articleSubscription.updateSubscription(id, {
+ groupName,
+ webHook,
+ remark,
+ topicIds: topicIds?.join(','),
+ siteNames,
+ sendType,
+ sendCron,
+ time,
+ status,
+ messageTitle,
+ message,
+ isAtAll,
+ updated_at: new Date(),
+ });
// 向 agent 进程发消息
- app.messenger.sendToAgent(status === 1 ? 'changeTimedTask' : 'cancelTimedTask', { id, sendCron })
+ app.messenger.sendToAgent(status === 1 ? 'changeTimedTask' : 'cancelTimedTask', {
+ id,
+ sendCron,
+ });
ctx.body = app.utils.response(true, id);
}
@@ -61,9 +122,12 @@ class ArticleSubscriptionController extends Controller {
const { ctx, app } = this;
const { id } = ctx.request.body;
if (_.isNil(id)) throw new Error('缺少必要参数 id');
- await ctx.service.articleSubscription.updateSubscription(id, { is_delete: 1, updated_at: new Date() });
+ await ctx.service.articleSubscription.updateSubscription(id, {
+ is_delete: 1,
+ updated_at: new Date(),
+ });
// 向 agent 进程发消息
- app.messenger.sendToAgent('cancelTimedTask', { id })
+ app.messenger.sendToAgent('cancelTimedTask', { id });
ctx.body = app.utils.response(true, id);
}
@@ -71,7 +135,7 @@ class ArticleSubscriptionController extends Controller {
async getTimedTaskList() {
const { ctx, app } = this;
// 向 agent 进程发消息
- app.messenger.sendToAgent('timedTaskList')
+ app.messenger.sendToAgent('timedTaskList');
ctx.body = app.utils.response(true, '请前往服务器 /logs/egg-agent.log 查看');
}
@@ -79,7 +143,7 @@ class ArticleSubscriptionController extends Controller {
async getSubscriptionInfo() {
const { ctx, app } = this;
const { id } = ctx.query;
- if (_.isNil(id)) throw new Error('缺少必要参数 id')
+ if (_.isNil(id)) throw new Error('缺少必要参数 id');
const data = await ctx.service.articleSubscription.getSubscriptionInfo(id);
if (_.isNil(data)) throw new Error('找不到该 id 下的相关信息');
ctx.body = app.utils.response(true, data);
diff --git a/app/controller/articleTopic.js b/app/controller/articleTopic.js
index b6ce719..ed5134d 100644
--- a/app/controller/articleTopic.js
+++ b/app/controller/articleTopic.js
@@ -4,22 +4,22 @@ class ArticleController extends Controller {
// 获取订阅项列表
async getTopicList() {
const { ctx, app } = this;
- const data = await ctx.service.articleTopic.getTopicList() || [];
- const nameList = Array.from(new Set(data.map(item => item.siteName)))
- let list = []
+ const data = (await ctx.service.articleTopic.getTopicList()) || [];
+ const nameList = Array.from(new Set(data.map((item) => item.siteName)));
+ const list = [];
- for (let name of nameList) {
- let children = []
- for (let item of data) {
+ for (const name of nameList) {
+ const children = [];
+ for (const item of data) {
if (name === item.siteName) {
- let { id, siteName, topicName, topicUrl } = item
- children.push({ id, name: `${ siteName } - ${ topicName }`, siteName, topicUrl })
+ const { id, siteName, topicName, topicUrl } = item;
+ children.push({ id, name: `${siteName} - ${topicName}`, siteName, topicUrl });
}
}
list.push({
name,
- children
- })
+ children,
+ });
}
ctx.body = app.utils.response(true, list);
}
diff --git a/app/controller/common.js b/app/controller/common.js
index 4f8ff6b..05711db 100644
--- a/app/controller/common.js
+++ b/app/controller/common.js
@@ -5,19 +5,26 @@ class CommonController extends Controller {
const { app, ctx } = this;
const { owner, configRepositoryName } = app.config.github;
const { name } = ctx.request.query;
- const result = await ctx.curl(`https://${owner}.github.io/${configRepositoryName}/${name}`, {
- dataType: 'json'
- });
- ctx.body = app.utils.response(result.status === 200, result.data, result.status === 200 ? null : '请求失败');
+ const result = await ctx.curl(
+ `https://${owner}.github.io/${configRepositoryName}/${name}`,
+ {
+ dataType: 'json',
+ }
+ );
+ ctx.body = app.utils.response(
+ result.status === 200,
+ result.data,
+ result.status === 200 ? null : '请求失败'
+ );
}
async getLocalIp() {
const { app, ctx } = this;
- const localIp = ctx.header['x-real-ip']||ctx.ip;
+ const localIp = ctx.header['x-real-ip'] || ctx.ip;
ctx.body = app.utils.response(true, {
localIp,
host: ctx.host,
- protocol: ctx.protocol
+ protocol: ctx.protocol,
});
}
}
-module.exports = CommonController;
\ No newline at end of file
+module.exports = CommonController;
diff --git a/app/controller/configCenter.js b/app/controller/configCenter.js
index 0e7d718..62c3325 100644
--- a/app/controller/configCenter.js
+++ b/app/controller/configCenter.js
@@ -1,8 +1,7 @@
const Controller = require('egg').Controller;
const _ = require('lodash');
-
-class ConfigCenter extends Controller{
+class ConfigCenter extends Controller {
async getConfigList() {
const { ctx, app } = this;
const { current, size, tags, search } = ctx.request.body;
@@ -10,62 +9,79 @@ class ConfigCenter extends Controller{
current,
size,
tags,
- search
+ search,
});
ctx.body = app.utils.response(true, {
data: data.rows,
- count: data.count
+ count: data.count,
});
}
- async addConfig(){
- const {ctx,app} = this;
- const {filename,filePath,hostId,remark,tagIds} = ctx.request.body;
- if(_.isNil(filename)) throw new Error('缺少必要参数filename');
- if(_.isNil(filePath)) throw new Error('缺少必要参数filePath');
- if(_.isNil(hostId)) throw new Error('缺少必要参数hostId');
- if(_.isNil(tagIds)) throw new Error('缺少必要参数tagIds');
+ async addConfig() {
+ const { ctx, app } = this;
+ const { filename, filePath, hostId, remark, tagIds } = ctx.request.body;
+ if (_.isNil(filename)) throw new Error('缺少必要参数filename');
+ if (_.isNil(filePath)) throw new Error('缺少必要参数filePath');
+ if (_.isNil(hostId)) throw new Error('缺少必要参数hostId');
+ if (_.isNil(tagIds)) throw new Error('缺少必要参数tagIds');
const result = await ctx.service.configCenter.addConfig({
- filename,filePath,hostId,remark,tagIds
+ filename,
+ filePath,
+ hostId,
+ remark,
+ tagIds,
});
- ctx.body = app.utils.response(true,result.get({
- plain: true
- }));
+ ctx.body = app.utils.response(
+ true,
+ result.get({
+ plain: true,
+ })
+ );
}
- async editConfig(){
- const {ctx,app} = this;
- const {id,filename,filePath,hostId,remark,tagIds} = ctx.request.body;
- if(_.isNil(id)) throw new Error('缺少必要参数id');
+ async editConfig() {
+ const { ctx, app } = this;
+ const { id, filename, filePath, hostId, remark, tagIds } = ctx.request.body;
+ if (_.isNil(id)) throw new Error('缺少必要参数id');
await ctx.service.configCenter.editConfig({
id,
filename,
filePath,
remark,
hostId,
- tagIds
+ tagIds,
});
const basicInfo = await ctx.service.configDetail.getConfigBasicInfo(id);
- const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id,'config-center')
- noticeUrlList.forEach(item => {
- app.utils.sendMsg(item.webHook,basicInfo.dataValues,'已更新',ctx.request.header.referer)
- })
+ const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id, 'config-center');
+ noticeUrlList.forEach((item) => {
+ app.utils.sendMsg(
+ item.webHook,
+ basicInfo.dataValues,
+ '已更新',
+ ctx.request.header.referer
+ );
+ });
ctx.body = app.utils.response(true);
}
- async deleteConfig(){
- const {ctx,app} = this;
- const {id} = ctx.request.query;
- if(_.isNil(id)) throw new Error('缺少必要参数id');
+ async deleteConfig() {
+ const { ctx, app } = this;
+ const { id } = ctx.request.query;
+ if (_.isNil(id)) throw new Error('缺少必要参数id');
await ctx.service.configCenter.deleteConfig(id);
const basicInfo = await ctx.service.configDetail.getConfigBasicInfo(id);
- const type = 'config-center'
- const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id,type)
- noticeUrlList.forEach(item => {
- app.utils.sendMsg(item.webHook,basicInfo.dataValues,'已删除',ctx.request.header.referer)
- })
- await ctx.service.configDetail.updateNoticeAllUrl(id,type,{
- is_delete: 1
+ const type = 'config-center';
+ const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id, type);
+ noticeUrlList.forEach((item) => {
+ app.utils.sendMsg(
+ item.webHook,
+ basicInfo.dataValues,
+ '已删除',
+ ctx.request.header.referer
+ );
});
- ctx.body = app.utils.response(true)
+ await ctx.service.configDetail.updateNoticeAllUrl(id, type, {
+ is_delete: 1,
+ });
+ ctx.body = app.utils.response(true);
}
}
-module.exports = ConfigCenter;
\ No newline at end of file
+module.exports = ConfigCenter;
diff --git a/app/controller/configDetail.js b/app/controller/configDetail.js
index fbe7429..3e39df9 100644
--- a/app/controller/configDetail.js
+++ b/app/controller/configDetail.js
@@ -2,109 +2,126 @@ const fs = require('fs');
const path = require('path');
const Controller = require('egg').Controller;
const _ = require('lodash');
-const NodeSsh = require('node-ssh')
+const NodeSsh = require('node-ssh');
-class ConfigDetail extends Controller{
- async getBasicInfo(){
- const {ctx,app} = this;
- const {id} = ctx.query;
- if(_.isNil(id)) throw new Error('缺少必要参数id');
+class ConfigDetail extends Controller {
+ async getBasicInfo() {
+ const { ctx, app } = this;
+ const { id } = ctx.query;
+ if (_.isNil(id)) throw new Error('缺少必要参数id');
const data = await ctx.service.configDetail.getConfigBasicInfo(id);
- if(_.isNil(data)) throw new Error('获取不到该文件的相关信息');
- ctx.body = app.utils.response(true,data);
+ if (_.isNil(data)) throw new Error('获取不到该文件的相关信息');
+ ctx.body = app.utils.response(true, data);
}
async getNoticeList() {
- const {ctx,app} = this;
- const {id,type} = ctx.query;
- if(_.isNil(id)) throw new Error('缺少必要参数id');
- const data = await ctx.service.configDetail.getNoticeListById(id,type);
- ctx.body = app.utils.response(true,data);
+ const { ctx, app } = this;
+ const { id, type } = ctx.query;
+ if (_.isNil(id)) throw new Error('缺少必要参数id');
+ const data = await ctx.service.configDetail.getNoticeListById(id, type);
+ ctx.body = app.utils.response(true, data);
}
async delNoticeUrl() {
- const {ctx,app} = this;
- const {id,type} = ctx.query;
- if(_.isNil(id)) throw new Error('缺少必要参数id');
- const data = await ctx.service.configDetail.updateNoticeUrl(id,type,{
- is_delete: 1
+ const { ctx, app } = this;
+ const { id, type } = ctx.query;
+ if (_.isNil(id)) throw new Error('缺少必要参数id');
+ const data = await ctx.service.configDetail.updateNoticeUrl(id, type, {
+ is_delete: 1,
});
- ctx.body = app.utils.response(true,data);
+ ctx.body = app.utils.response(true, data);
}
async addNoticeUrl() {
- const {ctx,app} = this;
- const {id,accept_group,type,webHook} = ctx.request.body;
- if(_.isNil(id)) throw new Error('缺少必要参数id');
- if(_.isNil(webHook)) throw new Error('缺少必要参数webHook');
- const data = await ctx.service.configDetail.addNoticeUrl(id,webHook,type,accept_group);
- ctx.body = app.utils.response(true,data);
+ const { ctx, app } = this;
+ const { id, accept_group, type, webHook } = ctx.request.body;
+ if (_.isNil(id)) throw new Error('缺少必要参数id');
+ if (_.isNil(webHook)) throw new Error('缺少必要参数webHook');
+ const data = await ctx.service.configDetail.addNoticeUrl(id, webHook, type, accept_group);
+ ctx.body = app.utils.response(true, data);
}
- async getRemoteConfig(){
- const {ctx,app} = this;
- const {id} = ctx.query;
- const configDetail = await ctx.service.configDetail.getConfigSpecificInfo(id,['id','filename','filePath',[app.Sequelize.col('host_management.host_ip'),'hostIp'],[app.Sequelize.col('host_management.username'),'username'],[app.Sequelize.col('host_management.password'),'password']]);
- if(_.isNil(configDetail)){
+ async getRemoteConfig() {
+ const { ctx, app } = this;
+ const { id } = ctx.query;
+ const configDetail = await ctx.service.configDetail.getConfigSpecificInfo(id, [
+ 'id',
+ 'filename',
+ 'filePath',
+ [app.Sequelize.col('host_management.host_ip'), 'hostIp'],
+ [app.Sequelize.col('host_management.username'), 'username'],
+ [app.Sequelize.col('host_management.password'), 'password'],
+ ]);
+ if (_.isNil(configDetail)) {
throw new Error('获取不到该文件的相关信息');
- }else{
- const {filePath,filename,hostIp,username,password} = configDetail.dataValues;
+ } else {
+ const { filePath, filename, hostIp, username, password } = configDetail.dataValues;
const ssh = new NodeSsh();
app.logger.info(`开始连接服务器${hostIp}...`);
await ssh.connect({
- host:hostIp,
+ host: hostIp,
username,
port: 22,
- password
+ password,
});
- const {stdout,stderr} = await ssh.execCommand(`cat ${path.join(filePath,filename)}`);
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { stdout, stderr } = await ssh.execCommand(
+ `cat ${path.join(filePath, filename)}`
+ );
ssh.dispose();
app.logger.info(`服务器${hostIp}断开`);
- ctx.body = app.utils.response(true,stdout);
+ ctx.body = app.utils.response(true, stdout);
// ctx.body = app.utils.response(true,_.isEmpty(stderr)?stdout:'');
}
}
- async saveConfig(){
- const {ctx,app} = this;
- const {id,config,shell,basicInfo} = ctx.request.body;
- const configDetail = await ctx.service.configDetail.getConfigSpecificInfo(id,['id','filename','filePath',[app.Sequelize.col('host_management.host_ip'),'hostIp'],[app.Sequelize.col('host_management.username'),'username'],[app.Sequelize.col('host_management.password'),'password']]);
- const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id,'config-center')
- noticeUrlList.forEach(item => {
- app.utils.sendMsg(item.webHook,basicInfo,'已更新',ctx.request.header.referer)
- })
- const {filePath,filename,hostIp,username,password} = configDetail.dataValues;
- const configFilePath = path.join(__dirname,'../../cache/',filename);
- const shellPath = path.join(__dirname,'../../cache',`${filename}_shell`);
- fs.writeFileSync(configFilePath,config);
- fs.writeFileSync(shellPath,shell);
- const remoteConfigFilePath = path.join(filePath,filename);
- const remoteShellPath = path.join(filePath,`${filename}_shell`);
+ async saveConfig() {
+ const { ctx, app } = this;
+ const { id, config, shell, basicInfo } = ctx.request.body;
+ const configDetail = await ctx.service.configDetail.getConfigSpecificInfo(id, [
+ 'id',
+ 'filename',
+ 'filePath',
+ [app.Sequelize.col('host_management.host_ip'), 'hostIp'],
+ [app.Sequelize.col('host_management.username'), 'username'],
+ [app.Sequelize.col('host_management.password'), 'password'],
+ ]);
+ const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id, 'config-center');
+ noticeUrlList.forEach((item) => {
+ app.utils.sendMsg(item.webHook, basicInfo, '已更新', ctx.request.header.referer);
+ });
+ const { filePath, filename, hostIp, username, password } = configDetail.dataValues;
+ const configFilePath = path.join(__dirname, '../../cache/', filename);
+ const shellPath = path.join(__dirname, '../../cache', `${filename}_shell`);
+ fs.writeFileSync(configFilePath, config);
+ fs.writeFileSync(shellPath, shell);
+ const remoteConfigFilePath = path.join(filePath, filename);
+ const remoteShellPath = path.join(filePath, `${filename}_shell`);
const ssh = new NodeSsh();
- try{
+ try {
app.logger.info(`开始连接服务器${hostIp}...`);
await ssh.connect({
- host:hostIp,
+ host: hostIp,
username,
port: 22,
- password
+ password,
});
- await ssh.putFile(configFilePath,remoteConfigFilePath);
- await ssh.putFile(shellPath,remoteShellPath);
- const {stderr:execShellStderr} = await ssh.execCommand(`bash ${remoteShellPath}`);
- const {stderr:deleteShellStderr} = await ssh.execCommand(`rm ${remoteShellPath}`);
- if(deleteShellStderr){
+ await ssh.putFile(configFilePath, remoteConfigFilePath);
+ await ssh.putFile(shellPath, remoteShellPath);
+ const { stderr: execShellStderr } = await ssh.execCommand(`bash ${remoteShellPath}`);
+ const { stderr: deleteShellStderr } = await ssh.execCommand(`rm ${remoteShellPath}`);
+ if (deleteShellStderr) {
throw new Error(deleteShellStderr);
}
- if(execShellStderr){
+ if (execShellStderr) {
await ssh.execCommand(`rm ${remoteShellPath}`);
throw new Error(execShellStderr);
}
await ctx.service.configCenter.editConfig({
id,
- updateShell:shell
+ updateShell: shell,
});
ssh.dispose();
app.logger.info(`服务器${hostIp}断开`);
fs.unlinkSync(configFilePath);
fs.unlinkSync(shellPath);
ctx.body = app.utils.response(true);
- }catch(err){
+ } catch (err) {
ssh.dispose();
app.logger.info(`服务器${hostIp}断开`);
fs.unlinkSync(configFilePath);
@@ -114,4 +131,4 @@ class ConfigDetail extends Controller{
}
}
-module.exports=ConfigDetail;
\ No newline at end of file
+module.exports = ConfigDetail;
diff --git a/app/controller/envManagement.js b/app/controller/envManagement.js
index 580bafa..fb02683 100644
--- a/app/controller/envManagement.js
+++ b/app/controller/envManagement.js
@@ -1,31 +1,38 @@
const Controller = require('egg').Controller;
const _ = require('lodash');
-class EnvManagementController extends Controller{
- //环境列表
+class EnvManagementController extends Controller {
+ // 环境列表
async queryEnvs() {
const { ctx, app } = this;
const { tags, search } = ctx.request.query;
const data = await ctx.service.envManagement.queryEnvs({ tags, search });
ctx.body = app.utils.response(true, data);
}
- //新增环境
- async addEnv(){
- const {ctx, app} = this;
- const {envName, hostIp, url, remark, tagIds} = ctx.request.body;
+ // 新增环境
+ async addEnv() {
+ const { ctx, app } = this;
+ const { envName, hostIp, url, remark, tagIds } = ctx.request.body;
if (_.isNil(envName)) throw new Error('缺少必要参数 envName');
if (_.isNil(url)) throw new Error('缺少必要参数 url');
const result = await ctx.service.envManagement.addEnv({
- envName,hostIp,url,remark,tags:tagIds.join(',')
+ envName,
+ hostIp,
+ url,
+ remark,
+ tags: tagIds.join(','),
});
- ctx.body = app.utils.response(true,result.get({
- plain: true
- }));
+ ctx.body = app.utils.response(
+ true,
+ result.get({
+ plain: true,
+ })
+ );
}
- //编辑环境
- async editEnv(){
- const {ctx,app} = this;
- const {id,envName,hostIp,url,remark,tagIds} = ctx.request.body;
+ // 编辑环境
+ async editEnv() {
+ const { ctx, app } = this;
+ const { id, envName, hostIp, url, remark, tagIds } = ctx.request.body;
if (_.isNil(id)) throw new Error('缺少必要参数id');
await ctx.service.envManagement.editEnv({
id,
@@ -33,17 +40,17 @@ class EnvManagementController extends Controller{
hostIp,
url,
remark,
- tags: tagIds ? tagIds.join(',') : undefined
+ tags: tagIds ? tagIds.join(',') : undefined,
});
ctx.body = app.utils.response(true);
}
- //删除环境
- async deleteEnv(){
- const {ctx,app} = this;
- const {id} = ctx.request.query;
+ // 删除环境
+ async deleteEnv() {
+ const { ctx, app } = this;
+ const { id } = ctx.request.query;
if (_.isNil(id)) throw new Error('缺少必要参数id');
await ctx.service.envManagement.deleteEnv(id);
- ctx.body = app.utils.response(true)
+ ctx.body = app.utils.response(true);
}
}
diff --git a/app/controller/home.js b/app/controller/home.js
index 08b3898..b3fa018 100644
--- a/app/controller/home.js
+++ b/app/controller/home.js
@@ -1,9 +1,9 @@
const Model = require('../mocks/article/list');
-module.exports = app => {
+module.exports = (app) => {
return class AppController extends app.Controller {
async index() {
const { ctx } = this;
- if (ctx.url==='/'){
+ if (ctx.url === '/') {
ctx.response.redirect('/page/toolbox');
} else {
await ctx.render('app.js', { url: ctx.url });
@@ -15,4 +15,4 @@ module.exports = app => {
await ctx.renderClient('app.js', Model.getPage(1, 10));
}
};
-};
\ No newline at end of file
+};
diff --git a/app/controller/hostManagement.js b/app/controller/hostManagement.js
index 8ee4b97..6a98eee 100644
--- a/app/controller/hostManagement.js
+++ b/app/controller/hostManagement.js
@@ -1,33 +1,41 @@
const Controller = require('egg').Controller;
const _ = require('lodash');
-class HostManagementController extends Controller{
- //主机列表
+class HostManagementController extends Controller {
+ // 主机列表
async queryHosts() {
const { ctx, app } = this;
const { tags, search } = ctx.request.query;
const data = await ctx.service.hostManagement.queryHosts({ tags, search });
ctx.body = app.utils.response(true, data);
}
- //新增主机
- async addHost(){
- const {ctx,app} = this;
- const {hostIp,hostName,username,password,remark,tagIds} = ctx.request.body;
+ // 新增主机
+ async addHost() {
+ const { ctx, app } = this;
+ const { hostIp, hostName, username, password, remark, tagIds } = ctx.request.body;
if (_.isNil(hostIp)) throw new Error('缺少必要参数hostIp');
if (_.isNil(hostName)) throw new Error('缺少必要参数hostName');
if (_.isNil(username)) throw new Error('缺少必要参数username');
if (_.isNil(password)) throw new Error('缺少必要参数password');
const result = await ctx.service.hostManagement.addHost({
- hostIp,hostName,username,password,remark,tags:tagIds.join(',')
+ hostIp,
+ hostName,
+ username,
+ password,
+ remark,
+ tags: tagIds.join(','),
});
- ctx.body = app.utils.response(true,result.get({
- plain: true
- }));
+ ctx.body = app.utils.response(
+ true,
+ result.get({
+ plain: true,
+ })
+ );
}
- //编辑主机
- async editHost(){
- const {ctx,app} = this;
- const {id,hostIp,hostName,username,password,remark,tagIds} = ctx.request.body;
+ // 编辑主机
+ async editHost() {
+ const { ctx, app } = this;
+ const { id, hostIp, hostName, username, password, remark, tagIds } = ctx.request.body;
if (_.isNil(id)) throw new Error('缺少必要参数id');
await ctx.service.hostManagement.editHost({
id,
@@ -36,18 +44,18 @@ class HostManagementController extends Controller{
remark,
username,
password,
- tags: tagIds ? tagIds.join(',') : undefined
+ tags: tagIds ? tagIds.join(',') : undefined,
});
ctx.body = app.utils.response(true);
}
- //删除主机
- async deleteHost(){
- const {ctx,app} = this;
- const {id} = ctx.request.query;
+ // 删除主机
+ async deleteHost() {
+ const { ctx, app } = this;
+ const { id } = ctx.request.query;
if (_.isNil(id)) throw new Error('缺少必要参数id');
await ctx.service.hostManagement.deleteHost(id);
- ctx.body = app.utils.response(true)
+ ctx.body = app.utils.response(true);
}
}
-module.exports = HostManagementController;
\ No newline at end of file
+module.exports = HostManagementController;
diff --git a/app/controller/proxy.js b/app/controller/proxy.js
index 742708f..744eaef 100644
--- a/app/controller/proxy.js
+++ b/app/controller/proxy.js
@@ -1,30 +1,39 @@
const Controller = require('egg').Controller;
const _ = require('lodash');
-class ProxyServerController extends Controller{
- //获取服务列表
+class ProxyServerController extends Controller {
+ // 获取服务列表
async list() {
const { pageSize, pageNo, search, projectId } = this.ctx.request.body;
- let where = {
- '$or': [
- { name: { '$like': `%${search}%` } },
- { proxy_server_address: { '$like': `%${search}%` } }
+ const where = {
+ $or: [
+ { name: { $like: `%${search}%` } },
+ { proxy_server_address: { $like: `%${search}%` } },
],
- is_delete: 0
- }
+ is_delete: 0,
+ };
if (projectId) {
- where.id = projectId
+ where.id = projectId;
}
const result = await this.app.model.ProxyServer.findAndCountAll({
- attributes: ['id', 'name', 'proxy_server_address', 'api_doc_url', 'status', 'target', 'created_at', 'updated_at'],
+ attributes: [
+ 'id',
+ 'name',
+ 'proxy_server_address',
+ 'api_doc_url',
+ 'status',
+ 'target',
+ 'created_at',
+ 'updated_at',
+ ],
where,
limit: pageSize,
order: [['updated_at', 'DESC']],
- offset: (pageNo - 1) * pageSize
+ offset: (pageNo - 1) * pageSize,
});
this.ctx.body = this.app.utils.response(true, { data: result.rows, count: result.count });
}
- //创建服务
- async add(){
+ // 创建服务
+ async add() {
const { proxyServer, targetAddrs } = this.ctx.request.body;
// 创建服务
const result = await this.ctx.service.proxyServer.create(proxyServer);
@@ -41,155 +50,180 @@ class ProxyServerController extends Controller{
const result = await this.ctx.service.proxyServerAddrs.queryAddrs(id);
this.ctx.body = this.app.utils.response(true, result);
}
-
- //更新服务
- async update(){
+
+ // 更新服务
+ async update() {
const { proxyServer, targetAddrs } = this.ctx.request.body;
- await this.app.model.ProxyServer.update(proxyServer,{
- where:{
- id:proxyServer.id
- }
+ await this.app.model.ProxyServer.update(proxyServer, {
+ where: {
+ id: proxyServer.id,
+ },
});
await this.ctx.service.proxyServerAddrs.update(targetAddrs, proxyServer.id);
this.ctx.body = this.app.utils.response(true, null);
}
- //删除服务
- async delete(){
- const {id} = this.ctx.request.query;
+ // 删除服务
+ async delete() {
+ const { id } = this.ctx.request.query;
// 逻辑删除代理服务下的项目
- await this.app.model.ProxyServer.update({
- is_delete: 1
- }, {
- where: {
- id
+ await this.app.model.ProxyServer.update(
+ {
+ is_delete: 1,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
// 逻辑删除代理服务下的项目下的代理服务
- await this.app.model.ProxyRule.update({
- is_delete: 1
- }, {
- where: {
- proxy_server_id: id
+ await this.app.model.ProxyRule.update(
+ {
+ is_delete: 1,
+ },
+ {
+ where: {
+ proxy_server_id: id,
+ },
}
- });
+ );
this.ctx.body = this.app.utils.response(true, null);
}
- //改变状态
- async changeStatus(){
- const {status,id} = this.ctx.request.query;
- let closeResult = false ;
+ // 改变状态
+ async changeStatus() {
+ const { status, id } = this.ctx.request.query;
+ let closeResult = false;
let restartResult = true;
- if (status==='0'){
- closeResult = this.ctx.service.proxyServer.close(id);
+ if (status === '0') {
+ closeResult = this.ctx.service.proxyServer.close(id);
} else {
restartResult = this.ctx.service.proxyServer.restart(id);
}
- this.ctx.body = this.app.utils.response(status==='0'?closeResult:restartResult,null);
+ this.ctx.body = this.app.utils.response(status === '0' ? closeResult : restartResult, null);
}
- //获取代理服务下的代理规则
- async ruleList(){
- const {proxy_server_id} = this.ctx.request.query;
+ // 获取代理服务下的代理规则
+ async ruleList() {
+ const { proxy_server_id } = this.ctx.request.query;
const result = await this.app.model.ProxyRule.findAndCountAll({
- attributes:['id','proxy_server_id','status','ip','target','remark','mode'],
- where:{
- is_delete:0,
- proxy_server_id
- }
+ attributes: ['id', 'proxy_server_id', 'status', 'ip', 'target', 'remark', 'mode'],
+ where: {
+ is_delete: 0,
+ proxy_server_id,
+ },
});
- this.ctx.body = this.app.utils.response(true,{
- data:result.rows,
- count:result.count
+ this.ctx.body = this.app.utils.response(true, {
+ data: result.rows,
+ count: result.count,
});
}
- //新增代理规则
- async addRule(){
- const {proxy_server_id,target,ip,remark,mode} = this.ctx.request.body;
+ // 新增代理规则
+ async addRule() {
+ const { proxy_server_id, target, ip, remark, mode } = this.ctx.request.body;
const result = await this.app.model.ProxyRule.create({
proxy_server_id,
target,
ip,
remark,
- status:1,
- mode
+ status: 1,
+ mode,
});
- this.ctx.body = this.app.utils.response(result,null);
+ this.ctx.body = this.app.utils.response(result, null);
}
- //更新代理规则
- async updateRule(){
- const {id,target,ip,remark,mode} = this.ctx.request.body;
- const result = await this.app.model.ProxyRule.update({
- target,
- ip,
- remark,
- mode
- },{
- where:{
- id
+ // 更新代理规则
+ async updateRule() {
+ const { id, target, ip, remark, mode } = this.ctx.request.body;
+ const result = await this.app.model.ProxyRule.update(
+ {
+ target,
+ ip,
+ remark,
+ mode,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
- this.ctx.body = this.app.utils.response(result,null);
+ );
+ this.ctx.body = this.app.utils.response(result, null);
}
- //更新代理规则状态
- async updateRuleStatus(){
- const {id,status} = this.ctx.request.body;
- const result = await this.app.model.ProxyRule.update({
- status
- },{
- where:{
- id
+ // 更新代理规则状态
+ async updateRuleStatus() {
+ const { id, status } = this.ctx.request.body;
+ const result = await this.app.model.ProxyRule.update(
+ {
+ status,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
- this.ctx.body = this.app.utils.response(result,null);
+ );
+ this.ctx.body = this.app.utils.response(result, null);
}
- //删除代理规则
- async deleteRule(){
- const {id} = this.ctx.request.query;
- const result = await this.app.model.ProxyRule.update({
- is_delete:1
- },{
- where:{
- id
+ // 删除代理规则
+ async deleteRule() {
+ const { id } = this.ctx.request.query;
+ const result = await this.app.model.ProxyRule.update(
+ {
+ is_delete: 1,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
- this.ctx.body = this.app.utils.response(result,null);
+ );
+ this.ctx.body = this.app.utils.response(result, null);
}
- //根据用户IP查询所在的项目列表
+ // 根据用户IP查询所在的项目列表
async projectListByUserIP() {
const { userIP } = this.ctx.request.body;
- this.app.model.ProxyRule.belongsTo(this.app.model.ProxyServer,{ foreignKey: 'proxy_server_id', targetKey: 'id'});
+ this.app.model.ProxyRule.belongsTo(this.app.model.ProxyServer, {
+ foreignKey: 'proxy_server_id',
+ targetKey: 'id',
+ });
const result = await this.app.model.ProxyRule.findAndCountAll({
- attributes:['id','status','ip','target','remark'],
- where:{
- is_delete:0,
- ip: userIP
+ attributes: ['id', 'status', 'ip', 'target', 'remark'],
+ where: {
+ is_delete: 0,
+ ip: userIP,
},
- include: [{
- model: this.app.model.ProxyServer,
- where: {
- is_delete:0
+ include: [
+ {
+ model: this.app.model.ProxyServer,
+ where: {
+ is_delete: 0,
+ },
+ attributes: [
+ ['id', 'serverId'],
+ ['name', 'serverName'],
+ ['proxy_server_address', 'address'],
+ 'target',
+ ],
},
- attributes:[['id', 'serverId'], ['name', 'serverName'], ['proxy_server_address', 'address'], 'target']
- }]
+ ],
});
- let dataObj = {};
- result.rows.forEach(item => {
+ const dataObj = {};
+ result.rows.forEach((item) => {
const { proxy_server = {}, id, ip, status, target, remark } = item || {};
const rule = { id, ip, status, target, remark };
const { serverId, serverName, address } = proxy_server?.dataValues || {};
- if(dataObj.hasOwnProperty(serverId)) {
+ if (dataObj.hasOwnProperty(serverId)) {
dataObj[serverId].rules.push(rule);
} else {
dataObj[serverId] = {
serverName,
address,
- rules: [
- rule
- ]
- }
+ rules: [rule],
+ };
}
});
- const data = Object.keys(dataObj).map((key) => Object.assign({}, { serverId: key }, dataObj[key]))
+ const data = Object.keys(dataObj).map((key) =>
+ Object.assign({}, { serverId: key }, dataObj[key])
+ );
this.ctx.body = this.app.utils.response(true, data);
}
}
diff --git a/app/controller/switchHosts.js b/app/controller/switchHosts.js
index b538032..30a0330 100644
--- a/app/controller/switchHosts.js
+++ b/app/controller/switchHosts.js
@@ -1,5 +1,4 @@
const Controller = require('egg').Controller;
-const path = require('path');
const fs = require('fs');
const _ = require('lodash');
// const { createWS } = require('../utils/ws');
@@ -14,11 +13,11 @@ class SwitchHostsController extends Controller {
const data = await ctx.service.switchHosts.getHostsList({
size,
current,
- searchText
+ searchText,
});
ctx.body = app.utils.response(true, {
data: data.rows,
- count: data.count
+ count: data.count,
});
}
@@ -31,13 +30,13 @@ class SwitchHostsController extends Controller {
const data = await ctx.service.switchHosts.createHosts({
groupName,
groupDesc,
- is_push
+ is_push,
});
if (_.isNil(data)) throw new Error('创建失败');
// 创建对应hosts文件
const fileName = 'hosts_' + data.id;
const paths = ['resources', 'hosts'];
- const filePath = app.utils.createFileSync(paths,fileName,hosts);
+ const filePath = app.utils.createFileSync(paths, fileName, hosts);
// 创建websocket连接
// createWS(8080, '/websocket_' + data.id);
// 更新数据
@@ -45,7 +44,7 @@ class SwitchHostsController extends Controller {
const result = await ctx.service.switchHosts.updateHosts(data.id, {
groupApi,
// groupId,
- groupAddr:filePath
+ groupAddr: filePath,
});
data.dataValues.groupAddr = filePath;
data.dataValues.groupApi = groupApi;
@@ -57,7 +56,6 @@ class SwitchHostsController extends Controller {
const { ctx, app } = this;
const { hosts, id, groupName, groupDesc, is_push } = ctx.request.body;
const { origin, referer } = ctx.request.header;
- const type = 'switch-hosts';
if (_.isNil(id)) throw new Error('缺少必要参数id');
if (_.isNil(groupName)) throw new Error('缺少必要参数groupName');
// 更新hosts
@@ -72,13 +70,13 @@ class SwitchHostsController extends Controller {
groupName,
groupDesc,
is_push,
- updated_at: new Date()
- })
+ updated_at: new Date(),
+ });
const { dataValues } = await ctx.service.switchHosts.getHostsInfo(id);
- const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id,'switch-hosts')
- noticeUrlList.forEach(({webHook}) => {
- app.utils.sendHostsUpdateMsg(webHook,dataValues,origin,referer,'已更新')
- })
+ const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id, 'switch-hosts');
+ noticeUrlList.forEach(({ webHook }) => {
+ app.utils.sendHostsUpdateMsg(webHook, dataValues, origin, referer, '已更新');
+ });
ctx.body = app.utils.response(result);
}
// 推送
@@ -88,7 +86,7 @@ class SwitchHostsController extends Controller {
if (_.isNil(id)) throw new Error('缺少必要参数id');
const result = await ctx.service.switchHosts.updateHosts(id, {
is_push: 1,
- updated_at: new Date()
+ updated_at: new Date(),
});
ctx.body = app.utils.response(result);
}
@@ -102,15 +100,15 @@ class SwitchHostsController extends Controller {
if (_.isNil(id)) throw new Error('缺少必要参数id');
const result = await ctx.service.switchHosts.updateHosts(id, {
is_delete: 1,
- updated_at: new Date()
+ updated_at: new Date(),
});
const { dataValues } = await ctx.service.switchHosts.getHostsInfo(id);
- const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id,'switch-hosts')
- noticeUrlList.forEach(({webHook}) => {
- app.utils.sendHostsUpdateMsg(webHook,dataValues,origin,referer,'已删除')
- })
- await ctx.service.configDetail.updateNoticeAllUrl(id,type,{
- is_delete: 1
+ const noticeUrlList = await ctx.service.configDetail.getNoticeListById(id, 'switch-hosts');
+ noticeUrlList.forEach(({ webHook }) => {
+ app.utils.sendHostsUpdateMsg(webHook, dataValues, origin, referer, '已删除');
+ });
+ await ctx.service.configDetail.updateNoticeAllUrl(id, type, {
+ is_delete: 1,
});
ctx.body = app.utils.response(result);
}
@@ -119,7 +117,7 @@ class SwitchHostsController extends Controller {
async getHostsInfo() {
const { ctx, app } = this;
const { id } = ctx.query;
- if (_.isNil(id)) throw new Error('缺少必要参数id')
+ if (_.isNil(id)) throw new Error('缺少必要参数id');
const data = await ctx.service.switchHosts.getHostsInfo(id);
if (_.isNil(data)) throw new Error('找不到该id下的相关信息');
await this.readHostsConfig(id, data.groupAddr, (hosts) => {
@@ -130,9 +128,9 @@ class SwitchHostsController extends Controller {
// 获取该id下的hosts内容
async getHostsConfig() {
- const { ctx, app } = this;
+ const { ctx } = this;
const id = ctx.params.id;
- if (_.isNil(id)) throw new Error('缺少必要参数id')
+ if (_.isNil(id)) throw new Error('缺少必要参数id');
const groupAddr = await this.ctx.service.switchHosts.getGroupAddr(id);
await this.readHostsConfig(id, groupAddr, (hosts) => {
ctx.body = hosts;
@@ -145,4 +143,4 @@ class SwitchHostsController extends Controller {
}
}
-module.exports = SwitchHostsController;
\ No newline at end of file
+module.exports = SwitchHostsController;
diff --git a/app/controller/tagManagement.js b/app/controller/tagManagement.js
index ddfcb86..ca23f5c 100644
--- a/app/controller/tagManagement.js
+++ b/app/controller/tagManagement.js
@@ -1,8 +1,8 @@
const Controller = require('egg').Controller;
const _ = require('lodash');
-class TagsManagementController extends Controller{
- //获取标签列表
+class TagsManagementController extends Controller {
+ // 获取标签列表
async getTagsList() {
const { app, ctx } = this;
const { current, size, searchText } = ctx.request.body;
@@ -11,60 +11,65 @@ class TagsManagementController extends Controller{
const data = await ctx.service.tagManagement.getTagsList({
size,
current,
- searchText
+ searchText,
});
ctx.body = app.utils.response(true, {
data: data.rows,
- count: data.count
+ count: data.count,
});
}
- //获取标签列表
+ // 获取标签列表
async getAllTagsList() {
const { app, ctx } = this;
const { searchText } = ctx.request.query;
const data = await ctx.service.tagManagement.getAllTagsList({
- searchText
+ searchText,
});
ctx.body = app.utils.response(true, {
data: data.rows,
- count: data.count
+ count: data.count,
});
}
- //新增标签
- async addTag(){
- const {ctx,app} = this;
- const { tagName,tagDesc,tagColor } = ctx.request.body;
+ // 新增标签
+ async addTag() {
+ const { ctx, app } = this;
+ const { tagName, tagDesc, tagColor } = ctx.request.body;
if (_.isNil(tagName)) throw new Error('缺少必要参数tagName');
if (_.isNil(tagDesc)) throw new Error('缺少必要参数tagDesc');
if (_.isNil(tagColor)) throw new Error('缺少必要参数tagColor');
const result = await ctx.service.tagManagement.addTag({
- tagName,tagDesc,tagColor
+ tagName,
+ tagDesc,
+ tagColor,
});
- ctx.body = app.utils.response(true,result.get({
- plain: true
- }));
+ ctx.body = app.utils.response(
+ true,
+ result.get({
+ plain: true,
+ })
+ );
}
- //编辑标签
- async editTag(){
- const {ctx,app} = this;
- const {id,tagName,tagDesc,tagColor} = ctx.request.body;
+ // 编辑标签
+ async editTag() {
+ const { ctx, app } = this;
+ const { id, tagName, tagDesc, tagColor } = ctx.request.body;
if (_.isNil(id)) throw new Error('缺少必要参数id');
await ctx.service.tagManagement.editTag({
id,
tagName,
tagDesc,
- tagColor
+ tagColor,
});
ctx.body = app.utils.response(true);
}
- //删除标签
- async deleteTag(){
- const {ctx,app} = this;
- const {id} = ctx.request.body;
+ // 删除标签
+ async deleteTag() {
+ const { ctx, app } = this;
+ const { id } = ctx.request.body;
if (_.isNil(id)) throw new Error('缺少必要参数id');
await ctx.service.tagManagement.deleteTag(id);
- ctx.body = app.utils.response(true)
+ ctx.body = app.utils.response(true);
}
}
-module.exports = TagsManagementController;
\ No newline at end of file
+module.exports = TagsManagementController;
diff --git a/app/io/controller/home.js b/app/io/controller/home.js
index f95ac1f..0c9c621 100644
--- a/app/io/controller/home.js
+++ b/app/io/controller/home.js
@@ -1,6 +1,6 @@
const { createNewServer } = require('../../utils/createServer');
-module.exports = app => {
+module.exports = (app) => {
return class Controller extends app.Controller {
// async getShellCommand () {
// const { ctx, logger, app } = this;
@@ -9,15 +9,18 @@ module.exports = app => {
// logger.info(' ======= command ======= ', command)
// }
- async loginServer () {
- const { ctx } = this
- const { host, username, password } = ctx.args[0]
+ async loginServer() {
+ const { ctx } = this;
+ const { host, username, password } = ctx.args[0];
- createNewServer({
- host,
- username,
- password
- }, ctx)
+ createNewServer(
+ {
+ host,
+ username,
+ password,
+ },
+ ctx
+ );
}
- }
-}
\ No newline at end of file
+ };
+};
diff --git a/app/io/middleware/connection.js b/app/io/middleware/connection.js
index b50e400..1e3765a 100644
--- a/app/io/middleware/connection.js
+++ b/app/io/middleware/connection.js
@@ -1,9 +1,9 @@
module.exports = () => {
return async (ctx, next) => {
ctx.logger.info('*** SOCKET IO CONNECTION SUCCESS ***');
- ctx.socket.emit('serverMsg', '\r\n*** SOCKET IO CONNECTION SUCCESS ***\r\n')
+ ctx.socket.emit('serverMsg', '\r\n*** SOCKET IO CONNECTION SUCCESS ***\r\n');
await next();
ctx.logger.info('*** SOCKET IO DISCONNECTION ***');
- ctx.socket.emit('serverMsg', '\r\n*** SOCKET IO DISCONNECTION ***\r\n')
+ ctx.socket.emit('serverMsg', '\r\n*** SOCKET IO DISCONNECTION ***\r\n');
};
-};
\ No newline at end of file
+};
diff --git a/app/middleware/access.js b/app/middleware/access.js
index b184839..53e17fd 100644
--- a/app/middleware/access.js
+++ b/app/middleware/access.js
@@ -2,7 +2,7 @@ const path = require('path');
const util = require('util');
module.exports = () => {
- const skipExt = [ '.png', '.jpeg', '.jpg', '.ico', '.gif' ];
+ const skipExt = ['.png', '.jpeg', '.jpg', '.ico', '.gif'];
return function* (next) {
const start = new Date().getTime();
@@ -26,10 +26,21 @@ module.exports = () => {
const referrer = this.get('referrer') || '-';
const ua = this.get('user-agent') || '-';
const serverTime = this.response.get('X-Server-Response-Time') || '-';
- const message = util.format('[access] %s:%s - %s %s %s/%s %s %s %s %s %s',
- ip, port, method, url, protocol, status, length, referrer, rs, serverTime, ua);
+ const message = util.format(
+ '[access] %s:%s - %s %s %s/%s %s %s %s %s %s',
+ ip,
+ port,
+ method,
+ url,
+ protocol,
+ status,
+ length,
+ referrer,
+ rs,
+ serverTime,
+ ua
+ );
this.logger.info(message);
}
};
};
-
diff --git a/app/middleware/proxy.js b/app/middleware/proxy.js
index 1c9cf4b..92e5b5a 100644
--- a/app/middleware/proxy.js
+++ b/app/middleware/proxy.js
@@ -2,53 +2,55 @@ const c2k = require('koa-connect');
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = async function httpproxy(ctx, next) {
await next();
- const {app} = ctx;
- //获取代理服务id
+ const { app } = ctx;
+ // 获取代理服务id
const serverId = ctx.params.id;
- //获取真实访问者ip
+ // 获取真实访问者ip
const realIp = ctx.header['x-real-ip'];
- //根据代理服务id查询代理服务
+ // 根据代理服务id查询代理服务
const proxyServer = await app.model.ProxyServer.findOne({
- attributes:['target','status'],
- where:{
- is_delete:0,
- id:serverId
- }
+ attributes: ['target', 'status'],
+ where: {
+ is_delete: 0,
+ id: serverId,
+ },
});
- //判断代理服务是否被禁用
- if (proxyServer.status===0){
- ctx.body = app.utils.response(false,null,'该代理服务已关闭');
+ // 判断代理服务是否被禁用
+ if (proxyServer.status === 0) {
+ ctx.body = app.utils.response(false, null, '该代理服务已关闭');
} else {
let target = '';
- //根据代理服务id和真实访问者ip查询代理规则
+ // 根据代理服务id和真实访问者ip查询代理规则
const proxyRule = await app.model.ProxyRule.findOne({
- attributes:['target'],
- where:{
- is_delete:0,
- status:1,
- ip:realIp,
- proxy_server_id:serverId
- }
+ attributes: ['target'],
+ where: {
+ is_delete: 0,
+ status: 1,
+ ip: realIp,
+ proxy_server_id: serverId,
+ },
});
- //判断代理服务id和真实访问者ip是否有对应的代理规则
- if (proxyRule){
- target=proxyRule.target.trim();
+ // 判断代理服务id和真实访问者ip是否有对应的代理规则
+ if (proxyRule) {
+ target = proxyRule.target.trim();
} else {
- target=proxyServer.target.trim();
+ target = proxyServer.target.trim();
}
- if (target){
- await c2k(createProxyMiddleware({
- target,
- pathRewrite:{
- [`^/proxy/${serverId}`]:''
- },
- timeout: 5 * 60 * 1000, // 五分钟
- proxyTimeout: 5 * 60 * 1000, // 五分钟
- changeOrigin: true,
- onError: (err, req, res, target) => {
- app.logger.info('http-proxy-middleware error', err, target);
- }
- }))(ctx,next)
+ if (target) {
+ await c2k(
+ createProxyMiddleware({
+ target,
+ pathRewrite: {
+ [`^/proxy/${serverId}`]: '',
+ },
+ timeout: 5 * 60 * 1000, // 五分钟
+ proxyTimeout: 5 * 60 * 1000, // 五分钟
+ changeOrigin: true,
+ onError: (err, req, res, target) => {
+ app.logger.info('http-proxy-middleware error', err, target);
+ },
+ })
+ )(ctx, next);
}
}
};
diff --git a/app/mocks/article/list.js b/app/mocks/article/list.js
index bc6dbb8..4fc0455 100644
--- a/app/mocks/article/list.js
+++ b/app/mocks/article/list.js
@@ -1,98 +1,119 @@
'use strict';
const data = {
- list: [{
- title: `Egg + React 服务端渲染骨架`,
- summary: '基于Egg + React + Webpack3/Webpack2 多页面和单页面服务器渲染同构工程骨架项目',
- hits: 550,
- url: 'https://github.com/hubcarl/egg-react-webpack-boilerplate'
- }, {
- id: 1,
- title: '前端工程化解决方案easywebpack',
- summary: 'programming instead of configuration, webpack is so easy',
- hits: 550,
- url: 'https://github.com/hubcarl/easywebpack'
- }, {
- id: 2,
- title: '前端工程化解决方案脚手架easywebpack-cli',
- summary: 'easywebpack command tool, support init Vue/Reac/Weex boilerplate',
- hits: 278,
- url: 'https://github.com/hubcarl/easywebpack-cli'
- }, {
- title: 'react-渐进式JavaScript 框架',
- summary: '简单小巧的核心,渐进式技术栈,足以应付任何规模的应用',
- hits: 200,
- url: 'https://cn.reactjs.org'
- }, {
- title: 'webpack配置官方文档',
- summary: 'webpack is a module bundler for modern JavaScript applications.',
- hits: 550,
- url: 'https://webpack.js.org/configuration/'
- }, {
- title: 'egg-为企业级框架和应用而生',
- summary: 'Born to buildbetter enterprise frameworks and apps with Node.js & Koa',
- hits: 278,
- url: 'https://eggjs.org/'
- }, {
- title: 'axios-基于 Promise 的 HTTP 请求客户端',
- summary: '基于 Promise 的 HTTP 请求客户端,可同时在浏览器和 node.js 中使用',
- hits: 998,
- url: 'https://www.awesomes.cn/repo/mzabriskie/axios'
- }, {
- title: 'Centralized State Management for react.js',
- summary: 'reactx 是一个专为react.js 应用程序开发的状态管理模式',
- hits: 232,
- url: 'https://github.com/reactjs/reactx'
- }, {
- title: 'react服务器渲染',
- summary: '服务器渲染可以加快首屏速度,利于SEO',
- hits: 565,
- url: 'http://csbun.github.io/blog/2016/08/react-2-0-server-side-rendering/'
- }, {
- title: 'webpack服务器构建',
- summary: 'Webpack is an amazing tool.',
- hits: 988,
- url: 'http://jlongster.com/Backend-Apps-with-Webpack--Part-I'
- }, {
- title: 'react component loader for Webpack',
- summary: 'Webpack loader for react.js components',
- hits: 322,
- url: 'https://github.com/reactjs/react-loader'
- }, {
- title: 'react-router--The official router for react.js',
- summary: 'It deeply integrates with react.js core to make building Single Page Applications with react.js a breeze',
- hits: 566,
- url: 'https://github.com/reactjs/react-router'
- }, {
- title: 'react生命周期',
- summary: 'react.js 生命周期和route的生命周期讲解',
- hits: 434,
- url: 'http://www.jianshu.com/p/e9f884b6ba6c'
- }, {
- title: 'babel到底将代码转换成什么鸟样',
- summary: '将babel捧作前端一个划时代的工具一定也不为过,它的出现让许多程序员幸福地用上了es6新语法',
- hits: 432,
- url: 'https://github.com/lcxfs1991/blog/issues/9'
- }, {
- title: 'HTTP2 的真正性能到底如何',
- summary: 'HTTP2 的真正性能到底如何',
- hits: 565,
- url: 'https://segmentfault.com/a/1190000007219256?utm_source=weekly&utm_medium=email&utm_campaign=email_weekly'
- }, {
- title: 'HTTP,HTTP2.0,SPDY,HTTPS讲解',
- summary: '使用SPDY加快你的网站速度',
- hits: 787,
- url: 'http://www.alloyteam.com/2016/07/httphttp2-0spdyhttps-reading-this-is-enough/'
- }, {
- title: 'git - 简明指南',
- summary: '助你入门 git 的简明指南',
- hits: 121,
- url: 'http://rogerdudler.github.io/git-guide/index.zh.html'
- }, {
- title: 'react从1升级到2',
- summary: 'Migrating from v1 to v2',
- hits: 555,
- url: 'https://webpack.js.org/guides/migrating/'
- }]
+ list: [
+ {
+ title: `Egg + React 服务端渲染骨架`,
+ summary: '基于Egg + React + Webpack3/Webpack2 多页面和单页面服务器渲染同构工程骨架项目',
+ hits: 550,
+ url: 'https://github.com/hubcarl/egg-react-webpack-boilerplate',
+ },
+ {
+ id: 1,
+ title: '前端工程化解决方案easywebpack',
+ summary: 'programming instead of configuration, webpack is so easy',
+ hits: 550,
+ url: 'https://github.com/hubcarl/easywebpack',
+ },
+ {
+ id: 2,
+ title: '前端工程化解决方案脚手架easywebpack-cli',
+ summary: 'easywebpack command tool, support init Vue/Reac/Weex boilerplate',
+ hits: 278,
+ url: 'https://github.com/hubcarl/easywebpack-cli',
+ },
+ {
+ title: 'react-渐进式JavaScript 框架',
+ summary: '简单小巧的核心,渐进式技术栈,足以应付任何规模的应用',
+ hits: 200,
+ url: 'https://cn.reactjs.org',
+ },
+ {
+ title: 'webpack配置官方文档',
+ summary: 'webpack is a module bundler for modern JavaScript applications.',
+ hits: 550,
+ url: 'https://webpack.js.org/configuration/',
+ },
+ {
+ title: 'egg-为企业级框架和应用而生',
+ summary: 'Born to buildbetter enterprise frameworks and apps with Node.js & Koa',
+ hits: 278,
+ url: 'https://eggjs.org/',
+ },
+ {
+ title: 'axios-基于 Promise 的 HTTP 请求客户端',
+ summary: '基于 Promise 的 HTTP 请求客户端,可同时在浏览器和 node.js 中使用',
+ hits: 998,
+ url: 'https://www.awesomes.cn/repo/mzabriskie/axios',
+ },
+ {
+ title: 'Centralized State Management for react.js',
+ summary: 'reactx 是一个专为react.js 应用程序开发的状态管理模式',
+ hits: 232,
+ url: 'https://github.com/reactjs/reactx',
+ },
+ {
+ title: 'react服务器渲染',
+ summary: '服务器渲染可以加快首屏速度,利于SEO',
+ hits: 565,
+ url: 'http://csbun.github.io/blog/2016/08/react-2-0-server-side-rendering/',
+ },
+ {
+ title: 'webpack服务器构建',
+ summary: 'Webpack is an amazing tool.',
+ hits: 988,
+ url: 'http://jlongster.com/Backend-Apps-with-Webpack--Part-I',
+ },
+ {
+ title: 'react component loader for Webpack',
+ summary: 'Webpack loader for react.js components',
+ hits: 322,
+ url: 'https://github.com/reactjs/react-loader',
+ },
+ {
+ title: 'react-router--The official router for react.js',
+ summary:
+ 'It deeply integrates with react.js core to make building Single Page Applications with react.js a breeze',
+ hits: 566,
+ url: 'https://github.com/reactjs/react-router',
+ },
+ {
+ title: 'react生命周期',
+ summary: 'react.js 生命周期和route的生命周期讲解',
+ hits: 434,
+ url: 'http://www.jianshu.com/p/e9f884b6ba6c',
+ },
+ {
+ title: 'babel到底将代码转换成什么鸟样',
+ summary:
+ '将babel捧作前端一个划时代的工具一定也不为过,它的出现让许多程序员幸福地用上了es6新语法',
+ hits: 432,
+ url: 'https://github.com/lcxfs1991/blog/issues/9',
+ },
+ {
+ title: 'HTTP2 的真正性能到底如何',
+ summary: 'HTTP2 的真正性能到底如何',
+ hits: 565,
+ url: 'https://segmentfault.com/a/1190000007219256?utm_source=weekly&utm_medium=email&utm_campaign=email_weekly',
+ },
+ {
+ title: 'HTTP,HTTP2.0,SPDY,HTTPS讲解',
+ summary: '使用SPDY加快你的网站速度',
+ hits: 787,
+ url: 'http://www.alloyteam.com/2016/07/httphttp2-0spdyhttps-reading-this-is-enough/',
+ },
+ {
+ title: 'git - 简明指南',
+ summary: '助你入门 git 的简明指南',
+ hits: 121,
+ url: 'http://rogerdudler.github.io/git-guide/index.zh.html',
+ },
+ {
+ title: 'react从1升级到2',
+ summary: 'Migrating from v1 to v2',
+ hits: 555,
+ url: 'https://webpack.js.org/guides/migrating/',
+ },
+ ],
};
let id = 1;
@@ -100,20 +121,21 @@ let id = 1;
data.list = data.list.concat(data.list);
data.list = data.list.concat(data.list);
-data.list.forEach(item => {
- item.id = id++;
+data.list.forEach((item) => {
+ item.id = id++;
});
-
const total = data.list.length;
-exports.getPage = (pageIndex = 1, pageSize = 10)=> {
- const start = (pageIndex - 1) * pageSize;
- const end = start + Number(pageSize);
- return { list: data.list.slice(start, end), total };
+exports.getPage = (pageIndex = 1, pageSize = 10) => {
+ const start = (pageIndex - 1) * pageSize;
+ const end = start + Number(pageSize);
+ return { list: data.list.slice(start, end), total };
};
-exports.getDetail = id => {
- return data.list.filter(item => {
- return item.id === id;
- }).slice(0, 1);
-};
\ No newline at end of file
+exports.getDetail = (id) => {
+ return data.list
+ .filter((item) => {
+ return item.id === id;
+ })
+ .slice(0, 1);
+};
diff --git a/app/model/app_centers.js b/app/model/app_centers.js
index ce9b7e4..c278ef3 100644
--- a/app/model/app_centers.js
+++ b/app/model/app_centers.js
@@ -1,20 +1,23 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const AppCenters = app.model.define('app_centers', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- appName: STRING(100),
- appUrl: STRING(255),
- appTags: STRING(255),
- appType: { type: INTEGER(2), defaultValue: 1 },
- appDesc: STRING(255),
- logoUrl: STRING(255),
- status: { type: INTEGER(2), defaultValue: 1 },
- clickCount: { type: INTEGER(2), defaultValue: 0 },
- created_at: DATE,
- updated_at: DATE
- },{
- freezeTableName: true
- });
+ const AppCenters = app.model.define(
+ 'app_centers',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ appName: STRING(100),
+ appUrl: STRING(255),
+ appTags: STRING(255),
+ appType: { type: INTEGER(2), defaultValue: 1 },
+ appDesc: STRING(255),
+ logoUrl: STRING(255),
+ status: { type: INTEGER(2), defaultValue: 1 },
+ clickCount: { type: INTEGER(2), defaultValue: 0 },
+ created_at: DATE,
+ updated_at: DATE,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return AppCenters;
};
-
\ No newline at end of file
diff --git a/app/model/article_subscription.js b/app/model/article_subscription.js
index f25fd59..747e12b 100644
--- a/app/model/article_subscription.js
+++ b/app/model/article_subscription.js
@@ -1,25 +1,28 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const ArticleSubscription = app.model.define('article_subscription', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- groupName: STRING(64),
- webHook: STRING(500),
- remark: STRING(255),
- topicIds: STRING(255),
- siteNames: STRING(255),
- sendType: { type: INTEGER(2), defaultValue: 1 },
- sendCron: STRING(255),
- time: STRING(255),
- status: { type: INTEGER(2), defaultValue: 1 },
- is_delete: { type: INTEGER(2), defaultValue: 0 },
- created_at: DATE,
- updated_at: DATE,
- messageTitle: STRING(64),
- message: STRING(2000),
- isAtAll: { type: INTEGER(2), defaultValue: 0 }
- },{
- freezeTableName: true
- });
+ const ArticleSubscription = app.model.define(
+ 'article_subscription',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ groupName: STRING(64),
+ webHook: STRING(500),
+ remark: STRING(255),
+ topicIds: STRING(255),
+ siteNames: STRING(255),
+ sendType: { type: INTEGER(2), defaultValue: 1 },
+ sendCron: STRING(255),
+ time: STRING(255),
+ status: { type: INTEGER(2), defaultValue: 1 },
+ is_delete: { type: INTEGER(2), defaultValue: 0 },
+ created_at: DATE,
+ updated_at: DATE,
+ messageTitle: STRING(64),
+ message: STRING(2000),
+ isAtAll: { type: INTEGER(2), defaultValue: 0 },
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return ArticleSubscription;
};
-
\ No newline at end of file
diff --git a/app/model/article_topic.js b/app/model/article_topic.js
index 20d3534..13f8ed4 100644
--- a/app/model/article_topic.js
+++ b/app/model/article_topic.js
@@ -1,17 +1,20 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const ArticleTopic = app.model.define('article_topic', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- siteName: STRING(64),
- topicName: STRING(255),
- topicUrl: STRING(255),
- sort: INTEGER,
- is_delete: { type: INTEGER(2), defaultValue: 0 },
- created_at: DATE,
- updated_at: DATE
- },{
- freezeTableName: true
- });
+ const ArticleTopic = app.model.define(
+ 'article_topic',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ siteName: STRING(64),
+ topicName: STRING(255),
+ topicUrl: STRING(255),
+ sort: INTEGER,
+ is_delete: { type: INTEGER(2), defaultValue: 0 },
+ created_at: DATE,
+ updated_at: DATE,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return ArticleTopic;
};
-
\ No newline at end of file
diff --git a/app/model/config_management.js b/app/model/config_management.js
index 4d11eb5..34d8f71 100644
--- a/app/model/config_management.js
+++ b/app/model/config_management.js
@@ -1,22 +1,33 @@
-module.exports = app => {
- const { STRING, INTEGER, DATE,TEXT} = app.Sequelize;
- const ConfigManagement = app.model.define('config_management', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- filename:STRING(30),
- filePath:{type:STRING(80),field:'file_path'},
- tagIds:{type:STRING(100),field:'tag_ids'},
- hostId:{type:INTEGER,field:'host_id'},
- remark: STRING(255),
- updateShell:{type:TEXT,field:'update_shell'},
- status: {type:INTEGER(2),defaultValue:1},
- createdAt: DATE,
- updatedAt: DATE
- },{
- freezeTableName: true
- });
- ConfigManagement.associate = function() {
- app.model.ConfigManagement.belongsTo(app.model.HostManagement,{ foreignKey: 'host_id', targetKey: 'id'});
- app.model.ConfigManagement.belongsTo(app.model.TagManagement,{ as:'tags',foreignKey: 'tag_ids', targetKey: 'id'});
- }
+module.exports = (app) => {
+ const { STRING, INTEGER, DATE, TEXT } = app.Sequelize;
+ const ConfigManagement = app.model.define(
+ 'config_management',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ filename: STRING(30),
+ filePath: { type: STRING(80), field: 'file_path' },
+ tagIds: { type: STRING(100), field: 'tag_ids' },
+ hostId: { type: INTEGER, field: 'host_id' },
+ remark: STRING(255),
+ updateShell: { type: TEXT, field: 'update_shell' },
+ status: { type: INTEGER(2), defaultValue: 1 },
+ createdAt: DATE,
+ updatedAt: DATE,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
+ ConfigManagement.associate = function () {
+ app.model.ConfigManagement.belongsTo(app.model.HostManagement, {
+ foreignKey: 'host_id',
+ targetKey: 'id',
+ });
+ app.model.ConfigManagement.belongsTo(app.model.TagManagement, {
+ as: 'tags',
+ foreignKey: 'tag_ids',
+ targetKey: 'id',
+ });
+ };
return ConfigManagement;
};
diff --git a/app/model/config_notice_url.js b/app/model/config_notice_url.js
index 93adc88..68c66e7 100644
--- a/app/model/config_notice_url.js
+++ b/app/model/config_notice_url.js
@@ -1,15 +1,19 @@
-module.exports = app => {
- const { INTEGER,STRING} = app.Sequelize;
- const ConfigNoticeUrl = app.model.define('config_notice_url', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- webHook:STRING(255),
- type:STRING(255),
- accept_group:STRING(255),
- is_delete: INTEGER,
- configId:{type:INTEGER,field:'config_id'}
- },{
- freezeTableName: true,
- timestamps: false
- });
+module.exports = (app) => {
+ const { INTEGER, STRING } = app.Sequelize;
+ const ConfigNoticeUrl = app.model.define(
+ 'config_notice_url',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ webHook: STRING(255),
+ type: STRING(255),
+ accept_group: STRING(255),
+ is_delete: INTEGER,
+ configId: { type: INTEGER, field: 'config_id' },
+ },
+ {
+ freezeTableName: true,
+ timestamps: false,
+ }
+ );
return ConfigNoticeUrl;
-};
\ No newline at end of file
+};
diff --git a/app/model/config_tag_rel.js b/app/model/config_tag_rel.js
index 5447db3..05823c6 100644
--- a/app/model/config_tag_rel.js
+++ b/app/model/config_tag_rel.js
@@ -1,15 +1,18 @@
-module.exports = app => {
+module.exports = (app) => {
const { INTEGER, DATE } = app.Sequelize;
- const ConfigTagRelServer = app.model.define('config_tag_rel', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- configId:{type:INTEGER,field:'config_id'},
- tagId:{type:INTEGER,field:'tag_id'},
- created_at: DATE,
- updated_at: DATE,
- is_delete: INTEGER
- },{
- freezeTableName: true
- });
+ const ConfigTagRelServer = app.model.define(
+ 'config_tag_rel',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ configId: { type: INTEGER, field: 'config_id' },
+ tagId: { type: INTEGER, field: 'tag_id' },
+ created_at: DATE,
+ updated_at: DATE,
+ is_delete: INTEGER,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return ConfigTagRelServer;
};
-
\ No newline at end of file
diff --git a/app/model/env_management.js b/app/model/env_management.js
index 7c18565..f97bb24 100644
--- a/app/model/env_management.js
+++ b/app/model/env_management.js
@@ -1,18 +1,22 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const EnvManagement = app.model.define('env_management', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- envName:{type:STRING(255),field:'env_name'},
- hostIp:{type:STRING(20),field:'host_ip'},
- url:{type:STRING(2048),field:'url'},
- remark: STRING(255),
- tags:{type:STRING(60),field:'tag_ids'},
- status: {type:INTEGER(2),defaultValue:1},
- createdAt: DATE,
- updatedAt: DATE
- },{
- freezeTableName: true
- });
+ const EnvManagement = app.model.define(
+ 'env_management',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ envName: { type: STRING(255), field: 'env_name' },
+ hostIp: { type: STRING(20), field: 'host_ip' },
+ url: { type: STRING(2048), field: 'url' },
+ remark: STRING(255),
+ tags: { type: STRING(60), field: 'tag_ids' },
+ status: { type: INTEGER(2), defaultValue: 1 },
+ createdAt: DATE,
+ updatedAt: DATE,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return EnvManagement;
};
diff --git a/app/model/host_management.js b/app/model/host_management.js
index b6ae356..9171cc2 100644
--- a/app/model/host_management.js
+++ b/app/model/host_management.js
@@ -1,19 +1,23 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const HostManagement = app.model.define('host_management', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- hostIp:{type:STRING(20),field:'host_ip'},
- hostName:{type:STRING(60),field:'host_name'},
- username:STRING(60),
- password:STRING(60),
- remark: STRING(255),
- tags:{type:STRING(60),field:'tag_ids'},
- status: {type:INTEGER(2),defaultValue:1},
- createdAt: DATE,
- updatedAt: DATE
- },{
- freezeTableName: true
- });
+ const HostManagement = app.model.define(
+ 'host_management',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ hostIp: { type: STRING(20), field: 'host_ip' },
+ hostName: { type: STRING(60), field: 'host_name' },
+ username: STRING(60),
+ password: STRING(60),
+ remark: STRING(255),
+ tags: { type: STRING(60), field: 'tag_ids' },
+ status: { type: INTEGER(2), defaultValue: 1 },
+ createdAt: DATE,
+ updatedAt: DATE,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return HostManagement;
};
diff --git a/app/model/proxy_rule.js b/app/model/proxy_rule.js
index 1468742..64c2069 100644
--- a/app/model/proxy_rule.js
+++ b/app/model/proxy_rule.js
@@ -1,18 +1,22 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const ProxyServer = app.model.define('proxy_rule', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- ip: INTEGER,
- target: STRING(60),
- remark: STRING(255),
- proxy_server_id: INTEGER,
- status: INTEGER,
- is_delete: INTEGER,
- created_at: DATE,
- updated_at: DATE
- },{
- freezeTableName: true
- });
+ const ProxyServer = app.model.define(
+ 'proxy_rule',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ ip: INTEGER,
+ target: STRING(60),
+ remark: STRING(255),
+ proxy_server_id: INTEGER,
+ status: INTEGER,
+ is_delete: INTEGER,
+ created_at: DATE,
+ updated_at: DATE,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return ProxyServer;
};
diff --git a/app/model/proxy_server.js b/app/model/proxy_server.js
index 5f2d228..3829f6b 100644
--- a/app/model/proxy_server.js
+++ b/app/model/proxy_server.js
@@ -1,17 +1,21 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const ProxyServer = app.model.define('proxy_server', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- name: INTEGER,
- target: STRING(60),
- api_doc_url: STRING(255),
- proxy_server_address: STRING(100),
- status: INTEGER,
- is_delete: INTEGER,
- created_at: DATE,
- updated_at: DATE
- },{
- freezeTableName: true
- });
+ const ProxyServer = app.model.define(
+ 'proxy_server',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ name: INTEGER,
+ target: STRING(60),
+ api_doc_url: STRING(255),
+ proxy_server_address: STRING(100),
+ status: INTEGER,
+ is_delete: INTEGER,
+ created_at: DATE,
+ updated_at: DATE,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return ProxyServer;
};
diff --git a/app/model/proxy_server_addrs.js b/app/model/proxy_server_addrs.js
index 25e50ca..1e2172c 100644
--- a/app/model/proxy_server_addrs.js
+++ b/app/model/proxy_server_addrs.js
@@ -1,15 +1,19 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const ProxyServer = app.model.define('proxy_server_addrs', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- target: STRING(255),
- remark: STRING(255),
- proxy_server_id: INTEGER,
- is_delete: INTEGER,
- created_at: DATE,
- updated_at: DATE
- }, {
- freezeTableName: true
- });
+ const ProxyServer = app.model.define(
+ 'proxy_server_addrs',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ target: STRING(255),
+ remark: STRING(255),
+ proxy_server_id: INTEGER,
+ is_delete: INTEGER,
+ created_at: DATE,
+ updated_at: DATE,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return ProxyServer;
};
diff --git a/app/model/switch_hosts.js b/app/model/switch_hosts.js
index f2b27a4..a608a01 100644
--- a/app/model/switch_hosts.js
+++ b/app/model/switch_hosts.js
@@ -1,20 +1,23 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const SwitchHostsServer = app.model.define('switch_hosts', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- groupName: STRING(64),
- groupId: STRING(255),
- groupApi: STRING(255),
- groupDesc: STRING(255),
- groupAddr: STRING(255),
- created_at: DATE,
- updated_at: DATE,
- is_delete: INTEGER,
- is_close: INTEGER,
- is_push: INTEGER
- },{
- freezeTableName: true
- });
+ const SwitchHostsServer = app.model.define(
+ 'switch_hosts',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ groupName: STRING(64),
+ groupId: STRING(255),
+ groupApi: STRING(255),
+ groupDesc: STRING(255),
+ groupAddr: STRING(255),
+ created_at: DATE,
+ updated_at: DATE,
+ is_delete: INTEGER,
+ is_close: INTEGER,
+ is_push: INTEGER,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return SwitchHostsServer;
};
-
\ No newline at end of file
diff --git a/app/model/tag_management.js b/app/model/tag_management.js
index 39108e4..028e604 100644
--- a/app/model/tag_management.js
+++ b/app/model/tag_management.js
@@ -1,18 +1,21 @@
-module.exports = app => {
+module.exports = (app) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
- const TagManagementServer = app.model.define('tag_management', {
- id: { type: INTEGER, primaryKey: true, autoIncrement: true },
- tagName: STRING(64),
- tagDesc: STRING(255),
- tagColor: STRING(255),
- created_at: DATE,
- updated_at: DATE,
- isAdmin:{type:INTEGER,field:'is_admin'},
- is_delete: INTEGER,
- is_close: INTEGER
- },{
- freezeTableName: true
- });
+ const TagManagementServer = app.model.define(
+ 'tag_management',
+ {
+ id: { type: INTEGER, primaryKey: true, autoIncrement: true },
+ tagName: STRING(64),
+ tagDesc: STRING(255),
+ tagColor: STRING(255),
+ created_at: DATE,
+ updated_at: DATE,
+ isAdmin: { type: INTEGER, field: 'is_admin' },
+ is_delete: INTEGER,
+ is_close: INTEGER,
+ },
+ {
+ freezeTableName: true,
+ }
+ );
return TagManagementServer;
};
-
\ No newline at end of file
diff --git a/app/router.js b/app/router.js
index 8d21b42..347c1c3 100644
--- a/app/router.js
+++ b/app/router.js
@@ -1,11 +1,11 @@
-module.exports = app => {
- const { io } = app
+module.exports = (app) => {
+ // const { io } = app;
app.get('/', app.controller.home.index);
app.get('/page/*', app.controller.home.index);
app.get('/c', app.controller.home.client);
/**
- * 代理服务增删改查以及状态修改
- */
+ * 代理服务增删改查以及状态修改
+ */
app.post('/api/proxy-server/server-list', app.controller.proxy.list);
app.post('/api/proxy-server/add-server', app.controller.proxy.add);
app.get('/api/proxy-server/target-addrs-list', app.controller.proxy.getTargetAddrs);
@@ -13,51 +13,54 @@ module.exports = app => {
app.delete('/api/proxy-server/delete-server', app.controller.proxy.delete);
app.get('/api/proxy-server/change-server-status', app.controller.proxy.changeStatus);
/**
- * 代理服务规则增删改查
- */
+ * 代理服务规则增删改查
+ */
app.get('/api/proxy-server/rule-list', app.controller.proxy.ruleList);
app.post('/api/proxy-server/add-rule', app.controller.proxy.addRule);
app.post('/api/proxy-server/update-rule', app.controller.proxy.updateRule);
app.post('/api/proxy-server/update-rule-status', app.controller.proxy.updateRuleStatus);
app.delete('/api/proxy-server/delete-rule', app.controller.proxy.deleteRule);
- app.post('/api/proxy-server/get-project-list-by-user-ip', app.controller.proxy.projectListByUserIP);
+ app.post(
+ '/api/proxy-server/get-project-list-by-user-ip',
+ app.controller.proxy.projectListByUserIP
+ );
/**
- * 主机管理
- */
+ * 主机管理
+ */
app.get('/api/host-management/host-list', app.controller.hostManagement.queryHosts);
app.post('/api/host-management/add-host', app.controller.hostManagement.addHost);
app.post('/api/host-management/edit-host', app.controller.hostManagement.editHost);
app.delete('/api/host-management/delete-host', app.controller.hostManagement.deleteHost);
/**
- * 环境管理
- */
+ * 环境管理
+ */
app.get('/api/env-management/env-list', app.controller.envManagement.queryEnvs);
app.post('/api/env-management/add-env', app.controller.envManagement.addEnv);
app.post('/api/env-management/edit-env', app.controller.envManagement.editEnv);
app.delete('/api/env-management/delete-env', app.controller.envManagement.deleteEnv);
/**
- * 配置中心
- */
+ * 配置中心
+ */
app.post('/api/config-center/config-list', app.controller.configCenter.getConfigList);
app.post('/api/config-center/add-config', app.controller.configCenter.addConfig);
app.post('/api/config-center/edit-config', app.controller.configCenter.editConfig);
app.delete('/api/config-center/delete-config', app.controller.configCenter.deleteConfig);
/**
- * 配置详情
- */
+ * 配置详情
+ */
app.get('/api/config-detail/get-basic-info', app.controller.configDetail.getBasicInfo);
- app.get('/api/config-detail/get-notice-list', app.controller.configDetail.getNoticeList)
- app.post('/api/config-detail/add-config-notice-url', app.controller.configDetail.addNoticeUrl)
- app.get('/api/config-detail/del-config-notice-url', app.controller.configDetail.delNoticeUrl)
+ app.get('/api/config-detail/get-notice-list', app.controller.configDetail.getNoticeList);
+ app.post('/api/config-detail/add-config-notice-url', app.controller.configDetail.addNoticeUrl);
+ app.get('/api/config-detail/del-config-notice-url', app.controller.configDetail.delNoticeUrl);
app.get('/api/config-detail/get-remote-config', app.controller.configDetail.getRemoteConfig);
- app.post('/api/config-detail/save', app.controller.configDetail.saveConfig)
+ app.post('/api/config-detail/save', app.controller.configDetail.saveConfig);
/**
* 服务代理
*/
app.all('/proxy/:id/*', app.middleware.proxy);
/**
- * 通用接口
- */
+ * 通用接口
+ */
app.get('/api/appCenters/get-app-list', app.controller.appCenters.getAppCenterList);
app.get('/api/github/get-local-ip', app.controller.common.getLocalIp);
app.post('/api/appCenters/update-applications', app.controller.appCenters.updateApplications);
@@ -66,13 +69,13 @@ module.exports = app => {
app.get('/api/appCenters/get-app-by-id', app.controller.appCenters.getApplicationById);
app.post('/api/appCenters/upload-logo/:id', app.controller.appCenters.uploadLogo);
/**
- * switch hosts 管理列表
- */
+ * switch hosts 管理列表
+ */
app.post('/api/switch-hosts/get-hosts-list', app.controller.switchHosts.getHostsList);
app.post('/api/switch-hosts/push-hosts', app.controller.switchHosts.pushHosts);
/**
- * switch hosts 配置内容 增删改查
- */
+ * switch hosts 配置内容 增删改查
+ */
app.post('/api/switch-hosts/create-hosts', app.controller.switchHosts.createHosts);
app.post('/api/switch-hosts/delete-hosts', app.controller.switchHosts.deleteHosts);
app.post('/api/switch-hosts/update-hosts', app.controller.switchHosts.updateHosts);
@@ -82,18 +85,39 @@ module.exports = app => {
/**
* 文章订阅
*/
- app.get('/api/article-subscription/test-article', app.controller.articleSubscription.testArticle);
- app.post('/api/article-subscription/create-subscription', app.controller.articleSubscription.createSubscription);
- app.post('/api/article-subscription/delete-subscription', app.controller.articleSubscription.deleteSubscription);
- app.post('/api/article-subscription/update-subscription', app.controller.articleSubscription.updateSubscription);
- app.post('/api/article-subscription/get-subscription-list', app.controller.articleSubscription.getSubscriptionList);
- app.get('/api/article-subscription/get-subscription-info', app.controller.articleSubscription.getSubscriptionInfo);
- app.get('/api/article-subscription/get-timed-task-list', app.controller.articleSubscription.getTimedTaskList);
+ app.get(
+ '/api/article-subscription/test-article',
+ app.controller.articleSubscription.testArticle
+ );
+ app.post(
+ '/api/article-subscription/create-subscription',
+ app.controller.articleSubscription.createSubscription
+ );
+ app.post(
+ '/api/article-subscription/delete-subscription',
+ app.controller.articleSubscription.deleteSubscription
+ );
+ app.post(
+ '/api/article-subscription/update-subscription',
+ app.controller.articleSubscription.updateSubscription
+ );
+ app.post(
+ '/api/article-subscription/get-subscription-list',
+ app.controller.articleSubscription.getSubscriptionList
+ );
+ app.get(
+ '/api/article-subscription/get-subscription-info',
+ app.controller.articleSubscription.getSubscriptionInfo
+ );
+ app.get(
+ '/api/article-subscription/get-timed-task-list',
+ app.controller.articleSubscription.getTimedTaskList
+ );
app.get('/api/article-topic/get-topic-list', app.controller.articleTopic.getTopicList);
/**
- * tag management 配置内容 增删改查
- */
+ * tag management 配置内容 增删改查
+ */
app.get('/api/tags/get-all-tag-list', app.controller.tagManagement.getAllTagsList);
app.post('/api/tags/get-tag-list', app.controller.tagManagement.getTagsList);
app.post('/api/tags/create-tag', app.controller.tagManagement.addTag);
diff --git a/app/schedule/articleSubscription.js b/app/schedule/articleSubscription.js
index 5d4f64e..69f98e3 100644
--- a/app/schedule/articleSubscription.js
+++ b/app/schedule/articleSubscription.js
@@ -1,10 +1,10 @@
module.exports = {
schedule: {
- interval: '0 55 23 ? * 6L', // 每月的最后一个星期五 23:55 触发
+ interval: '0 55 23 ? * 6L', // 每月的最后一个星期五 23:55 触发
type: 'worker',
- immediate: true
+ immediate: true,
},
async task(ctx) {
- ctx.service.articleSubscription.startSubscriptionTimedTask()
- }
-}
+ ctx.service.articleSubscription.startSubscriptionTimedTask();
+ },
+};
diff --git a/app/service/appCenters.js b/app/service/appCenters.js
index 65d6671..65ca3c2 100644
--- a/app/service/appCenters.js
+++ b/app/service/appCenters.js
@@ -1,39 +1,45 @@
const Service = require('egg').Service;
-const _ = require('lodash');
class AppCentersService extends Service {
updateApplications(config) {
const { id, appName, appUrl, appDesc, appTags } = config;
- if (id) return this.ctx.model.AppCenters.update(config, {
- where:{
- id
- }
- });
+ if (id)
+ return this.ctx.model.AppCenters.update(config, {
+ where: {
+ id,
+ },
+ });
return this.ctx.model.AppCenters.create({
appName,
appUrl,
appDesc,
- appTags
+ appTags,
});
}
- clickApplications (config) {
+ clickApplications(config) {
const { id, clickCount } = config;
- return this.ctx.model.AppCenters.update({ clickCount: clickCount + 1 }, {
- where:{
- id
+ return this.ctx.model.AppCenters.update(
+ { clickCount: clickCount + 1 },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
}
- deleteApplications (id) {
- return this.ctx.model.AppCenters.update({
- status:0
- },{
- where:{
- id
+ deleteApplications(id) {
+ return this.ctx.model.AppCenters.update(
+ {
+ status: 0,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
}
}
-module.exports = AppCentersService;
\ No newline at end of file
+module.exports = AppCentersService;
diff --git a/app/service/articleSubscription.js b/app/service/articleSubscription.js
index c9f1b43..7176202 100644
--- a/app/service/articleSubscription.js
+++ b/app/service/articleSubscription.js
@@ -1,35 +1,41 @@
-const Service = require('egg').Service
-const { SITE_NAME, TOPIC_NAME } = require('../consts')
-const { getGithubTrendingFromServerless, getJueJinHot, getDevArchitectureHot, getReactStatusHot, customMessage } = require('../utils/articleSubscription')
+const Service = require('egg').Service;
+const { SITE_NAME, TOPIC_NAME } = require('../consts');
+const {
+ getGithubTrendingFromServerless,
+ getJueJinHot,
+ getDevArchitectureHot,
+ getReactStatusHot,
+ customMessage,
+} = require('../utils/articleSubscription');
class ArticleSubscriptionService extends Service {
// 获取列表
getSubscriptionList(reqParams) {
- const { size, current, searchText } = reqParams
+ const { size, current, searchText } = reqParams;
return this.ctx.model.ArticleSubscription.findAndCountAll({
where: {
groupName: {
- '$like':`%${ searchText }%`
+ $like: `%${searchText}%`,
},
- is_delete: 0
+ is_delete: 0,
},
order: [['created_at', 'DESC']],
limit: size,
offset: size * (current - 1),
- raw: true
- })
+ raw: true,
+ });
}
// 新增
createSubscription(params) {
- return this.ctx.model.ArticleSubscription.create(params)
+ return this.ctx.model.ArticleSubscription.create(params);
}
// 更新
updateSubscription(id, updateParams) {
return this.ctx.model.ArticleSubscription.update(updateParams, {
- where: { id }
- })
+ where: { id },
+ });
}
// 通过订阅 id 查询需要发送的文章订阅消息
@@ -37,24 +43,65 @@ class ArticleSubscriptionService extends Service {
const articleSubscription = await this.app.model.ArticleSubscription.findOne({
where: {
id,
- is_delete: 0
+ is_delete: 0,
},
- raw: true
- })
- const { webHook, groupName, siteNames, messageTitle, message, isAtAll } = articleSubscription
+ raw: true,
+ });
+ const { webHook, groupName, siteNames, messageTitle, message, isAtAll } =
+ articleSubscription;
if (siteNames === '自定义消息') {
- customMessage(id, groupName, siteNames, messageTitle, message, isAtAll, webHook, this.app)
+ customMessage(
+ id,
+ groupName,
+ siteNames,
+ messageTitle,
+ message,
+ isAtAll,
+ webHook,
+ this.app
+ );
} else {
- const topicAll = await this.app.model.ArticleTopic.findAll({ where: { is_delete: 0 }, raw: true });
+ const topicAll = await this.app.model.ArticleTopic.findAll({
+ where: { is_delete: 0 },
+ raw: true,
+ });
const topicIds = articleSubscription.topicIds?.split(',') || [];
- const topicList = topicAll.filter(item => topicIds.includes(`${ item.id }`))
+ const topicList = topicAll.filter((item) => topicIds.includes(`${item.id}`));
- for (let item of topicList) {
- const { siteName, topicName, topicUrl } = item
- siteName === SITE_NAME.GITHUB && getGithubTrendingFromServerless(id, groupName, siteName, topicName, topicUrl, webHook, this.app)
- siteName === SITE_NAME.JUEJIN && getJueJinHot(id, groupName, siteName, topicName, topicUrl, webHook, this.app)
- topicName === TOPIC_NAME.DEV_ARCHITECTURE && getDevArchitectureHot(id, groupName, siteName, topicName, topicUrl, webHook, this.app)
- topicName === TOPIC_NAME.REACT_STATUS && getReactStatusHot(id, groupName, siteName, topicName, topicUrl, webHook, this.app)
+ for (const item of topicList) {
+ const { siteName, topicName, topicUrl } = item;
+ siteName === SITE_NAME.GITHUB &&
+ getGithubTrendingFromServerless(
+ id,
+ groupName,
+ siteName,
+ topicName,
+ topicUrl,
+ webHook,
+ this.app
+ );
+ siteName === SITE_NAME.JUEJIN &&
+ getJueJinHot(id, groupName, siteName, topicName, topicUrl, webHook, this.app);
+ topicName === TOPIC_NAME.DEV_ARCHITECTURE &&
+ getDevArchitectureHot(
+ id,
+ groupName,
+ siteName,
+ topicName,
+ topicUrl,
+ webHook,
+ this.app
+ );
+ topicName === TOPIC_NAME.REACT_STATUS &&
+ getReactStatusHot(
+ id,
+ groupName,
+ siteName,
+ topicName,
+ topicUrl,
+ webHook,
+ this.app
+ );
}
}
}
@@ -64,25 +111,25 @@ class ArticleSubscriptionService extends Service {
const subscriptionList = await this.app.model.ArticleSubscription.findAll({
where: {
is_delete: 0,
- status: 1
+ status: 1,
},
order: [['created_at', 'DESC']],
- raw: true
- })
+ raw: true,
+ });
- for (let i of subscriptionList) {
- const { id, sendCron } = i
- this.app.messenger.sendToAgent('createTimedTask', { id, sendCron })
+ for (const i of subscriptionList) {
+ const { id, sendCron } = i;
+ this.app.messenger.sendToAgent('createTimedTask', { id, sendCron });
}
}
// 获取详情 - 暂未使用
async getSubscriptionInfo(id) {
const data = await this.ctx.model.ArticleSubscription.findOne({
- where: { id }
- })
- return data
+ where: { id },
+ });
+ return data;
}
}
-module.exports = ArticleSubscriptionService
+module.exports = ArticleSubscriptionService;
diff --git a/app/service/articleTopic.js b/app/service/articleTopic.js
index 22ea9a0..b860fbb 100644
--- a/app/service/articleTopic.js
+++ b/app/service/articleTopic.js
@@ -1,16 +1,16 @@
-const Service = require('egg').Service
+const Service = require('egg').Service;
class ArticleTopicService extends Service {
// 获取订阅项列表
getTopicList() {
return this.ctx.model.ArticleTopic.findAll({
where: {
- is_delete: 0
+ is_delete: 0,
},
order: [['sort']],
- raw: true
- })
+ raw: true,
+ });
}
}
-module.exports = ArticleTopicService
+module.exports = ArticleTopicService;
diff --git a/app/service/configCenter.js b/app/service/configCenter.js
index 2c03586..5aacc47 100644
--- a/app/service/configCenter.js
+++ b/app/service/configCenter.js
@@ -2,78 +2,87 @@ const Service = require('egg').Service;
const _ = require('lodash');
class ConfigCenterService extends Service {
- queryConfigs({
- current,
- size,
- tags,
- search = ''
- }) {
+ queryConfigs({ current, size, tags, search = '' }) {
const { ctx, app } = this;
- let whereParams = {
- status: 1
- }
+ const whereParams = {
+ status: 1,
+ };
if (tags && tags.length) {
whereParams['tag_ids'] = {
- $in: tags
- }
+ $in: tags,
+ };
}
if (search) {
whereParams['$or'] = [
- {
- filename: { '$like': `%${search}%` }
- }, {
- '$host_management.host_ip$': { '$like': `%${search}%` }
- }
- ]
+ {
+ filename: { $like: `%${search}%` },
+ },
+ {
+ '$host_management.host_ip$': { $like: `%${search}%` },
+ },
+ ];
}
- let params = {
- attributes: ['id', 'filename', 'filePath', 'remark', 'hostId', [app.Sequelize.col('host_management.host_ip'), 'hostIp'], 'created_at', 'updated_at'],
+ const params = {
+ attributes: [
+ 'id',
+ 'filename',
+ 'filePath',
+ 'remark',
+ 'hostId',
+ [app.Sequelize.col('host_management.host_ip'), 'hostIp'],
+ 'created_at',
+ 'updated_at',
+ ],
where: whereParams,
- include: [{
- model: ctx.model.HostManagement,
- attributes: []
- },
- {
- model: ctx.model.TagManagement,
- as: 'tags',
- attributes: ['id', 'tagName', 'tagColor', 'tagDesc']
- }],
+ include: [
+ {
+ model: ctx.model.HostManagement,
+ attributes: [],
+ },
+ {
+ model: ctx.model.TagManagement,
+ as: 'tags',
+ attributes: ['id', 'tagName', 'tagColor', 'tagDesc'],
+ },
+ ],
// raw:true, // 这个属性表示开启原生查询,原生查询支持的功能更多,自定义更强
limit: size,
order: [['updated_at', 'DESC']],
- offset: size * (current - 1)
- }
- return ctx.model.ConfigManagement.findAndCountAll(params)
+ offset: size * (current - 1),
+ };
+ return ctx.model.ConfigManagement.findAndCountAll(params);
}
- addConfig(config){
+ addConfig(config) {
return this.ctx.model.ConfigManagement.create(config);
}
- editConfig(config){
- const {id,filename,filePath,remark,hostId,updateShell,tagIds} = config;
+ editConfig(config) {
+ const { id, filename, filePath, remark, hostId, updateShell, tagIds } = config;
const newConfig = {};
- if (!_.isNil(filename)) newConfig.filename=filename;
- if (!_.isNil(filePath)) newConfig.filePath=filePath;
- if (!_.isNil(remark)) newConfig.remark=remark;
- if (!_.isNil(hostId)) newConfig.hostId=hostId;
- if (!_.isNil(tagIds)) newConfig.tagIds=tagIds;
- if (!_.isNil(updateShell)) newConfig.updateShell=updateShell;
-
+ if (!_.isNil(filename)) newConfig.filename = filename;
+ if (!_.isNil(filePath)) newConfig.filePath = filePath;
+ if (!_.isNil(remark)) newConfig.remark = remark;
+ if (!_.isNil(hostId)) newConfig.hostId = hostId;
+ if (!_.isNil(tagIds)) newConfig.tagIds = tagIds;
+ if (!_.isNil(updateShell)) newConfig.updateShell = updateShell;
- return this.ctx.model.ConfigManagement.update(newConfig,{
- where:{
- id
- }
- })
+ return this.ctx.model.ConfigManagement.update(newConfig, {
+ where: {
+ id,
+ },
+ });
}
- deleteConfig(id){
- return this.ctx.model.ConfigManagement.update({
- status:0
- },{
- where:{
- id
+ deleteConfig(id) {
+ return this.ctx.model.ConfigManagement.update(
+ {
+ status: 0,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
}
}
-module.exports = ConfigCenterService;
\ No newline at end of file
+module.exports = ConfigCenterService;
diff --git a/app/service/configDetail.js b/app/service/configDetail.js
index 16b6d89..8133dce 100644
--- a/app/service/configDetail.js
+++ b/app/service/configDetail.js
@@ -1,68 +1,88 @@
const Service = require('egg').Service;
-const _ = require('lodash');
class ConfigDetailService extends Service {
- async getConfigBasicInfo(id){
- const {ctx,app} = this;
- ctx.model.ConfigManagement.belongsTo(ctx.model.HostManagement,{ foreignKey: 'host_id', targetKey: 'id'});
+ async getConfigBasicInfo(id) {
+ const { ctx, app } = this;
+ ctx.model.ConfigManagement.belongsTo(ctx.model.HostManagement, {
+ foreignKey: 'host_id',
+ targetKey: 'id',
+ });
return ctx.model.ConfigManagement.findOne({
- attributes:['id','filename','filePath','remark','updateShell','hostId',[app.Sequelize.col('host_management.host_ip'),'hostIp'],[app.Sequelize.col('host_management.host_name'),'hostName'],[app.Sequelize.col('host_management.username'),'username'],[app.Sequelize.col('host_management.password'),'password']],
- where:{
- id
+ attributes: [
+ 'id',
+ 'filename',
+ 'filePath',
+ 'remark',
+ 'updateShell',
+ 'hostId',
+ [app.Sequelize.col('host_management.host_ip'), 'hostIp'],
+ [app.Sequelize.col('host_management.host_name'), 'hostName'],
+ [app.Sequelize.col('host_management.username'), 'username'],
+ [app.Sequelize.col('host_management.password'), 'password'],
+ ],
+ where: {
+ id,
},
- include: [{
- model: ctx.model.HostManagement,
- attributes:[]
- }]
- })
+ include: [
+ {
+ model: ctx.model.HostManagement,
+ attributes: [],
+ },
+ ],
+ });
}
- async getNoticeListById(id,type) {
- const {ctx} = this;
+ async getNoticeListById(id, type) {
+ const { ctx } = this;
return ctx.model.ConfigNoticeUrl.findAll({
- attributes:['id','webHook','accept_group'],
- where:{
+ attributes: ['id', 'webHook', 'accept_group'],
+ where: {
configId: id,
type,
- is_delete: 0
- }
- })
+ is_delete: 0,
+ },
+ });
}
- async addNoticeUrl(id,webHook,type,accept_group) {
- const {ctx} = this;
+ async addNoticeUrl(id, webHook, type, accept_group) {
+ const { ctx } = this;
return ctx.model.ConfigNoticeUrl.create({
configId: id,
webHook,
type,
accept_group,
- is_delete: 0
- })
+ is_delete: 0,
+ });
}
async updateNoticeUrl(id, type, updateParams) {
const { ctx } = this;
return ctx.model.ConfigNoticeUrl.update(updateParams, {
- where: { id, type }
- })
+ where: { id, type },
+ });
}
async updateNoticeAllUrl(id, type, updateParams) {
const { ctx } = this;
return ctx.model.ConfigNoticeUrl.update(updateParams, {
- where: { type, configId: id }
- })
+ where: { type, configId: id },
+ });
}
- async getConfigSpecificInfo(id,attributes=[]){
- const {ctx,app} = this;
- ctx.model.ConfigManagement.belongsTo(ctx.model.HostManagement,{ foreignKey: 'host_id', targetKey: 'id'});
+ async getConfigSpecificInfo(id, attributes = []) {
+ const { ctx } = this;
+ ctx.model.ConfigManagement.belongsTo(ctx.model.HostManagement, {
+ foreignKey: 'host_id',
+ targetKey: 'id',
+ });
return ctx.model.ConfigManagement.findOne({
attributes,
- where:{
- id
+ where: {
+ id,
},
- include: [{
- model: ctx.model.HostManagement,
- attributes:[]
- }]
- })
+ include: [
+ {
+ model: ctx.model.HostManagement,
+ attributes: [],
+ },
+ ],
+ });
}
}
-module.exports = ConfigDetailService
\ No newline at end of file
+module.exports = ConfigDetailService;
diff --git a/app/service/envManagement.js b/app/service/envManagement.js
index e5a0ef5..cf0a6e8 100644
--- a/app/service/envManagement.js
+++ b/app/service/envManagement.js
@@ -5,45 +5,45 @@ class EnvManagementService extends Service {
async queryEnvs(params) {
const { ctx } = this;
const { tags = '', search = '' } = params;
- let envResult = await ctx.model.EnvManagement.findAll({
+ const envResult = await ctx.model.EnvManagement.findAll({
attributes: ['id', 'envName', 'hostIp', 'url', 'remark', 'tags'],
where: {
status: 1,
$or: [
{
- envName: { '$like': `%${search}%` }
+ envName: { $like: `%${search}%` },
},
{
- hostIp: { '$like': `%${search}%` }
- }
- ]
- }
+ hostIp: { $like: `%${search}%` },
+ },
+ ],
+ },
});
- let tagsResult = await ctx.model.TagManagement.findAll();
- let result = [];
- envResult.forEach(item => {
- let tagids = item.get('tags').split(',');
- let tagArrs = tagsResult.filter(ele => {
- return tagids.includes(`${ele.get('id')}`)
+ const tagsResult = await ctx.model.TagManagement.findAll();
+ const result = [];
+ envResult.forEach((item) => {
+ const tagids = item.get('tags').split(',');
+ const tagArrs = tagsResult.filter((ele) => {
+ return tagids.includes(`${ele.get('id')}`);
});
item.set('tags', tagArrs);
if (tags) {
- if (tags.split(',').some(ele => tagids.includes(`${ele}`))) {
- result.push(item)
+ if (tags.split(',').some((ele) => tagids.includes(`${ele}`))) {
+ result.push(item);
}
} else {
- result.push(item)
+ result.push(item);
}
});
- return result
+ return result;
}
- addEnv(env){
- const {ctx} = this;
+ addEnv(env) {
+ const { ctx } = this;
return ctx.model.EnvManagement.create(env);
}
- editEnv(env){
- const {ctx} = this;
- const {id, envName, hostIp, url, remark, tags} = env;
+ editEnv(env) {
+ const { ctx } = this;
+ const { id, envName, hostIp, url, remark, tags } = env;
const newEnv = {};
if (!_.isNil(envName)) newEnv.envName = envName;
if (!_.isNil(hostIp)) newEnv.hostIp = hostIp;
@@ -51,21 +51,24 @@ class EnvManagementService extends Service {
if (!_.isNil(remark)) newEnv.remark = remark;
if (!_.isNil(tags)) newEnv.tags = tags;
- return ctx.model.EnvManagement.update(newEnv,{
- where:{
- id
- }
- })
+ return ctx.model.EnvManagement.update(newEnv, {
+ where: {
+ id,
+ },
+ });
}
- deleteEnv(id){
- const {ctx} = this;
- return ctx.model.EnvManagement.update({
- status:0
- },{
- where:{
- id
+ deleteEnv(id) {
+ const { ctx } = this;
+ return ctx.model.EnvManagement.update(
+ {
+ status: 0,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
}
}
module.exports = EnvManagementService;
diff --git a/app/service/hostManagement.js b/app/service/hostManagement.js
index 79dd3b8..4737a3d 100644
--- a/app/service/hostManagement.js
+++ b/app/service/hostManagement.js
@@ -5,69 +5,71 @@ class HostManagementService extends Service {
async queryHosts(params) {
const { ctx } = this;
const { tags = '', search = '' } = params;
- let hostReulst = await ctx.model.HostManagement.findAll({
+ const hostReulst = await ctx.model.HostManagement.findAll({
attributes: ['id', 'hostIp', 'hostName', 'remark', 'username', 'password', 'tags'],
where: {
status: 1,
$or: [
- {
- hostIp: { '$like': `%${search}%` }
+ {
+ hostIp: { $like: `%${search}%` },
},
{
- hostName: { '$like': `%${search}%` }
- }
- ]
-
- }
+ hostName: { $like: `%${search}%` },
+ },
+ ],
+ },
});
- let tagsResult = await ctx.model.TagManagement.findAll();
- let result = [];
- hostReulst.forEach(item => {
- let tagids = item.get('tags').split(',');
- let tagArrs = tagsResult.filter(ele => {
- return tagids.includes(`${ele.get('id')}`)
+ const tagsResult = await ctx.model.TagManagement.findAll();
+ const result = [];
+ hostReulst.forEach((item) => {
+ const tagids = item.get('tags').split(',');
+ const tagArrs = tagsResult.filter((ele) => {
+ return tagids.includes(`${ele.get('id')}`);
});
item.set('tags', tagArrs);
if (tags) {
- if (tags.split(',').some(ele => tagids.includes(`${ele}`))) {
- result.push(item)
+ if (tags.split(',').some((ele) => tagids.includes(`${ele}`))) {
+ result.push(item);
}
} else {
- result.push(item)
+ result.push(item);
}
});
- return result
+ return result;
}
- addHost(host){
- const {ctx} = this;
+ addHost(host) {
+ const { ctx } = this;
return ctx.model.HostManagement.create(host);
}
- editHost(host){
- const {ctx} = this;
- const {id,hostIp,hostName,remark,username,password,tags} = host;
+ editHost(host) {
+ const { ctx } = this;
+ const { id, hostIp, hostName, remark, username, password, tags } = host;
const newHost = {};
- if (!_.isNil(hostIp)) newHost.hostIp=hostIp;
- if (!_.isNil(hostName)) newHost.hostName=hostName;
- if (!_.isNil(remark)) newHost.remark=remark;
- if (!_.isNil(username)) newHost.username=username;
- if (!_.isNil(password)) newHost.password=password;
- if (!_.isNil(tags)) newHost.tags=tags;
+ if (!_.isNil(hostIp)) newHost.hostIp = hostIp;
+ if (!_.isNil(hostName)) newHost.hostName = hostName;
+ if (!_.isNil(remark)) newHost.remark = remark;
+ if (!_.isNil(username)) newHost.username = username;
+ if (!_.isNil(password)) newHost.password = password;
+ if (!_.isNil(tags)) newHost.tags = tags;
- return ctx.model.HostManagement.update(newHost,{
- where:{
- id
- }
- })
+ return ctx.model.HostManagement.update(newHost, {
+ where: {
+ id,
+ },
+ });
}
- deleteHost(id){
- const {ctx} = this;
- return ctx.model.HostManagement.update({
- status:0
- },{
- where:{
- id
+ deleteHost(id) {
+ const { ctx } = this;
+ return ctx.model.HostManagement.update(
+ {
+ status: 0,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
}
}
-module.exports = HostManagementService;
\ No newline at end of file
+module.exports = HostManagementService;
diff --git a/app/service/proxyServer.js b/app/service/proxyServer.js
index fbe0e2d..0372e2f 100644
--- a/app/service/proxyServer.js
+++ b/app/service/proxyServer.js
@@ -1,42 +1,52 @@
const Service = require('egg').Service;
class ProxyServerService extends Service {
- //创建
+ // 创建
async create(proxyServer) {
- const {host,protocol} = this.ctx;
- proxyServer.proxy_server_address=`${protocol}://${host}/proxy`;
+ const { host, protocol } = this.ctx;
+ proxyServer.proxy_server_address = `${protocol}://${host}/proxy`;
proxyServer.status = 1;
const insertResult = await this.ctx.model.ProxyServer.create(proxyServer);
- const {id,proxy_server_address} = insertResult;
- const updateResult = await this.ctx.model.ProxyServer.update({
- proxy_server_address:`${proxy_server_address}/${id}`
- },{
- where:{
- id
+ const { id, proxy_server_address } = insertResult;
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const updateResult = await this.ctx.model.ProxyServer.update(
+ {
+ proxy_server_address: `${proxy_server_address}/${id}`,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
return { id };
}
- //关闭
- async close(id){
- return await this.ctx.model.ProxyServer.update({
- status:0
- },{
- where:{
- id
+ // 关闭
+ async close(id) {
+ return await this.ctx.model.ProxyServer.update(
+ {
+ status: 0,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
}
- //重启
- async restart(id){
- return await this.ctx.model.ProxyServer.update({
- status:1
- },{
- where:{
- id
+ // 重启
+ async restart(id) {
+ return await this.ctx.model.ProxyServer.update(
+ {
+ status: 1,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
}
}
-module.exports = ProxyServerService;
\ No newline at end of file
+module.exports = ProxyServerService;
diff --git a/app/service/proxyServerAddrs.js b/app/service/proxyServerAddrs.js
index 7587947..d699c82 100644
--- a/app/service/proxyServerAddrs.js
+++ b/app/service/proxyServerAddrs.js
@@ -1,13 +1,13 @@
const Service = require('egg').Service;
-const _ = require('lodash');
class ProxyServerAddrsService extends Service {
// 创建
async create(addrs, proxy_server_id) {
- Array.isArray(addrs) && addrs.forEach(async (addr) => {
- addr.proxy_server_id = proxy_server_id;
- await this.ctx.model.ProxyServerAddrs.create(addr);
- })
+ Array.isArray(addrs) &&
+ addrs.forEach(async (addr) => {
+ addr.proxy_server_id = proxy_server_id;
+ await this.ctx.model.ProxyServerAddrs.create(addr);
+ });
return true;
}
@@ -16,28 +16,29 @@ class ProxyServerAddrsService extends Service {
return this.ctx.model.ProxyServerAddrs.findAll({
where: {
proxy_server_id,
- is_delete: 0
+ is_delete: 0,
},
- order: [['updated_at', 'DESC']]
- })
+ order: [['updated_at', 'DESC']],
+ });
}
// 更新 | 新增
// 删除,同更新,让前端传个is_delete = 1
async update(addrs, proxy_server_id) {
- Array.isArray(addrs) && addrs.forEach(async (addr) => {
- addr.proxy_server_id = proxy_server_id;
- if (addr.id) {
- await this.ctx.model.ProxyServerAddrs.update(addr, {
- where: {
- id: addr.id
- }
- })
- } else {
- await this.ctx.model.ProxyServerAddrs.create(addr);
- }
- })
+ Array.isArray(addrs) &&
+ addrs.forEach(async (addr) => {
+ addr.proxy_server_id = proxy_server_id;
+ if (addr.id) {
+ await this.ctx.model.ProxyServerAddrs.update(addr, {
+ where: {
+ id: addr.id,
+ },
+ });
+ } else {
+ await this.ctx.model.ProxyServerAddrs.create(addr);
+ }
+ });
}
}
-module.exports = ProxyServerAddrsService;
\ No newline at end of file
+module.exports = ProxyServerAddrsService;
diff --git a/app/service/switchHosts.js b/app/service/switchHosts.js
index 1595370..d4d29a6 100644
--- a/app/service/switchHosts.js
+++ b/app/service/switchHosts.js
@@ -7,15 +7,15 @@ class SwitchHostsService extends Service {
const { size, current, searchText } = reqParams;
return this.ctx.model.SwitchHosts.findAndCountAll({
where: {
- groupName:{
- '$like':`%${searchText}%`
+ groupName: {
+ $like: `%${searchText}%`,
},
- is_delete: 0
+ is_delete: 0,
},
limit: size,
order: [['updated_at', 'DESC']],
- offset: size * (current - 1)
- })
+ offset: size * (current - 1),
+ });
}
// 创建
@@ -28,8 +28,8 @@ class SwitchHostsService extends Service {
groupId: '',
groupAddr: '',
created_at: new Date(),
- updated_at: new Date()
- }
+ updated_at: new Date(),
+ };
return this.ctx.model.SwitchHosts.create(hostsParams);
}
@@ -37,15 +37,15 @@ class SwitchHostsService extends Service {
updateHosts(id, updateParams) {
const { ctx } = this;
return ctx.model.SwitchHosts.update(updateParams, {
- where: { id }
- })
+ where: { id },
+ });
}
// 获取hosts详细信息
getHostsInfo(id) {
const { ctx } = this;
return ctx.model.SwitchHosts.findOne({
- where: { id }
+ where: { id },
});
}
@@ -53,11 +53,11 @@ class SwitchHostsService extends Service {
async getGroupAddr(id) {
const data = await this.ctx.model.SwitchHosts.findOne({
attributes: ['groupAddr'],
- where: { id }
+ where: { id },
});
if (_.isNil(data)) throw new Error('获取不到该分组下存储的hosts文件');
return data.groupAddr;
}
}
-module.exports = SwitchHostsService;
\ No newline at end of file
+module.exports = SwitchHostsService;
diff --git a/app/service/tagManagement.js b/app/service/tagManagement.js
index 56f0752..5a36428 100644
--- a/app/service/tagManagement.js
+++ b/app/service/tagManagement.js
@@ -7,54 +7,57 @@ class TagManagementService extends Service {
const { size, current, searchText } = reqParams;
return this.ctx.model.TagManagement.findAndCountAll({
where: {
- tagName:{
- '$like':`%${searchText}%`
+ tagName: {
+ $like: `%${searchText}%`,
},
- is_delete: 0
+ is_delete: 0,
},
limit: size,
order: [['updated_at', 'DESC']],
- offset: size * (current - 1)
- })
+ offset: size * (current - 1),
+ });
}
// 获取列表数据
getAllTagsList(reqParams) {
- const { searchText='' } = reqParams;
+ const { searchText = '' } = reqParams;
return this.ctx.model.TagManagement.findAndCountAll({
where: {
- tagName:{
- '$like':`%${searchText}%`
+ tagName: {
+ $like: `%${searchText}%`,
},
- is_delete: 0
- }
- })
+ is_delete: 0,
+ },
+ });
}
- addTag(params){
- const {ctx} = this;
+ addTag(params) {
+ const { ctx } = this;
return ctx.model.TagManagement.create(params);
}
- editTag(params){
- const {ctx} = this;
- const {id,tagName,tagDesc,tagColor} = params;
+ editTag(params) {
+ const { ctx } = this;
+ const { id, tagName, tagDesc, tagColor } = params;
const newParams = {};
- if (!_.isNil(tagName)) newParams.tagName=tagName;
- if (!_.isNil(tagDesc)) newParams.tagDesc=tagDesc;
- if (!_.isNil(tagColor)) newParams.tagColor=tagColor;
- return ctx.model.TagManagement.update(newParams,{
- where:{
- id
- }
- })
+ if (!_.isNil(tagName)) newParams.tagName = tagName;
+ if (!_.isNil(tagDesc)) newParams.tagDesc = tagDesc;
+ if (!_.isNil(tagColor)) newParams.tagColor = tagColor;
+ return ctx.model.TagManagement.update(newParams, {
+ where: {
+ id,
+ },
+ });
}
- deleteTag(id){
- const {ctx} = this;
- return ctx.model.TagManagement.update({
- is_delete:1
- },{
- where:{
- id
+ deleteTag(id) {
+ const { ctx } = this;
+ return ctx.model.TagManagement.update(
+ {
+ is_delete: 1,
+ },
+ {
+ where: {
+ id,
+ },
}
- });
+ );
}
}
-module.exports = TagManagementService;
\ No newline at end of file
+module.exports = TagManagementService;
diff --git a/app/utils/articleSubscription.js b/app/utils/articleSubscription.js
index 75e0cef..07d1a12 100644
--- a/app/utils/articleSubscription.js
+++ b/app/utils/articleSubscription.js
@@ -2,168 +2,268 @@
* 文章订阅
* 功能说明文档:https://dtstack.yuque.com/rd-center/sm6war/tyz0bp
*/
-const cheerio = require('cheerio')
-const axios = require('axios')
-const config = require('../../env.json')
-const { sendArticleMsg, sendMsgAfterSendArticle } = require('./index')
-const articleResultWebhook = config.articleResultWebhook // 文章订阅结果通知机器人
-const timeout = 30_000
+const cheerio = require('cheerio');
+const axios = require('axios');
+const config = require('../../env.json');
+const { sendArticleMsg, sendMsgAfterSendArticle } = require('./index');
+const articleResultWebhook = config.articleResultWebhook; // 文章订阅结果通知机器人
+const timeout = 30_000;
// github trending from github
-const getGithubTrendingFromGithub = async (id, groupName, siteName, topicName, topicUrl, webHook, app) => {
+const getGithubTrendingFromGithub = async (
+ id,
+ groupName,
+ siteName,
+ topicName,
+ topicUrl,
+ webHook,
+ app
+) => {
try {
- const pageSize = app.config.articleSubscription.pageSize
- const { data } = await axios.get(`https://github.com/trending/${ topicUrl }?since=daily`, { timeout })
- let msg = `## Github Trending ${ topicName } 今日 Top5\n\n`
+ const pageSize = app.config.articleSubscription.pageSize;
+ const { data } = await axios.get(`https://github.com/trending/${topicUrl}?since=daily`, {
+ timeout,
+ });
+ let msg = `## Github Trending ${topicName} 今日 Top5\n\n`;
- const $ = cheerio.load(data)
- const items = $('article')
+ const $ = cheerio.load(data);
+ const items = $('article');
for (let i = 0; i < pageSize; i++) {
- const result = items.eq(i).find('h1.lh-condensed').text().replace(/\n/g, '').replace(/\s*/g, '')
- msg += `${ i + 1 }、[${ result }](https://github.com/${ result })\n\n`
+ const result = items
+ .eq(i)
+ .find('h1.lh-condensed')
+ .text()
+ .replace(/\n/g, '')
+ .replace(/\s*/g, '');
+ msg += `${i + 1}、[${result}](https://github.com/${result})\n\n`;
}
- msg += `[点击查看更多内容](https://github.com/trending/${ topicUrl }?since=daily)`
- sendArticleMsg('Github Trending 今日 Top5', msg, webHook)
- logFunc(app, id, groupName, siteName, topicName, '成功')
+ msg += `[点击查看更多内容](https://github.com/trending/${topicUrl}?since=daily)`;
+ sendArticleMsg('Github Trending 今日 Top5', msg, webHook);
+ logFunc(app, id, groupName, siteName, topicName, '成功');
} catch (err) {
- logFunc(app, id, groupName, siteName, topicName, `失败`, `Github 网络不佳 ${ JSON.stringify(err) }`)
+ logFunc(
+ app,
+ id,
+ groupName,
+ siteName,
+ topicName,
+ `失败`,
+ `Github 网络不佳 ${JSON.stringify(err)}`
+ );
}
-}
+};
// github trending from 掘金 chrome 插件
-const getGithubTrendingFromJueJin = async (id, groupName, siteName, topicName, topicUrl, webHook, app) => {
+const getGithubTrendingFromJueJin = async (
+ id,
+ groupName,
+ siteName,
+ topicName,
+ topicUrl,
+ webHook,
+ app
+) => {
try {
- const pageSize = app.config.articleSubscription.pageSize
+ const pageSize = app.config.articleSubscription.pageSize;
const params = {
category: 'trending',
period: 'day',
lang: topicUrl,
offset: 0,
- limit: pageSize
- }
- const res = await axios.post(`https://e.juejin.cn/resources/github`, params)
- const { data } = res.data
- let msg = `## Github Trending ${ topicName } 今日 Top5\n\n`
+ limit: pageSize,
+ };
+ const res = await axios.post(`https://e.juejin.cn/resources/github`, params);
+ const { data } = res.data;
+ let msg = `## Github Trending ${topicName} 今日 Top5\n\n`;
for (let i = 0; i < pageSize; i++) {
- msg += `${ i + 1 }、[${ data[i].username } / ${ data[i].reponame }](${ data[i].url })\n\n`
+ msg += `${i + 1}、[${data[i].username} / ${data[i].reponame}](${data[i].url})\n\n`;
}
- msg += `[点击查看更多内容](https://github.com/trending/${ topicUrl }?since=daily)`
- sendArticleMsg('Github Trending 今日 Top5', msg, webHook)
- logFunc(app, id, groupName, siteName, topicName, '成功')
+ msg += `[点击查看更多内容](https://github.com/trending/${topicUrl}?since=daily)`;
+ sendArticleMsg('Github Trending 今日 Top5', msg, webHook);
+ logFunc(app, id, groupName, siteName, topicName, '成功');
} catch (err) {
- logFunc(app, id, groupName, siteName, topicName, `失败`, `Github 网络不佳 ${ JSON.stringify(err) }`)
+ logFunc(
+ app,
+ id,
+ groupName,
+ siteName,
+ topicName,
+ `失败`,
+ `Github 网络不佳 ${JSON.stringify(err)}`
+ );
}
-}
+};
// github trending from Serverless,目前使用的是该方法
-const getGithubTrendingFromServerless = async (id, groupName, siteName, topicName, topicUrl, webHook, app) => {
+const getGithubTrendingFromServerless = async (
+ id,
+ groupName,
+ siteName,
+ topicName,
+ topicUrl,
+ webHook,
+ app
+) => {
try {
- const pageSize = app.config.articleSubscription.pageSize
- const res = await axios.get(`http://github-trending-api.liuxianyu.cn/repository/list?language=${ topicUrl }&pageSize=${ pageSize }`, { timeout })
- const { data } = res.data
- let msg = `## Github Trending ${ topicName } 今日 Top5\n\n`
+ const pageSize = app.config.articleSubscription.pageSize;
+ const res = await axios.get(
+ `http://github-trending-api.liuxianyu.cn/repository/list?language=${topicUrl}&pageSize=${pageSize}`,
+ { timeout }
+ );
+ const { data } = res.data;
+ let msg = `## Github Trending ${topicName} 今日 Top5\n\n`;
for (let i = 0; i < pageSize; i++) {
- msg += `${ i + 1 }、[${ data.list[i].username } / ${ data.list[i].repositoryName }](${ data.list[i].url })\n\n`
+ msg += `${i + 1}、[${data.list[i].username} / ${data.list[i].repositoryName}](${
+ data.list[i].url
+ })\n\n`;
}
- msg += `[点击查看更多](https://github.com/trending/${ topicUrl }?since=daily)`
- sendArticleMsg('Github Trending 今日 Top5', msg, webHook)
- logFunc(app, id, groupName, siteName, topicName, '成功')
+ msg += `[点击查看更多](https://github.com/trending/${topicUrl}?since=daily)`;
+ sendArticleMsg('Github Trending 今日 Top5', msg, webHook);
+ logFunc(app, id, groupName, siteName, topicName, '成功');
} catch (err) {
- logFunc(app, id, groupName, siteName, topicName, `失败`, `Github 网络不佳 ${ JSON.stringify(err) }`)
+ logFunc(
+ app,
+ id,
+ groupName,
+ siteName,
+ topicName,
+ `失败`,
+ `Github 网络不佳 ${JSON.stringify(err)}`
+ );
}
-}
+};
// 掘金热门 https://juejin.cn/frontend
const getJueJinHot = async (id, groupName, siteName, topicName, topicUrl, webHook, app) => {
try {
- const pageSize = app.config.articleSubscription.pageSize
+ const pageSize = app.config.articleSubscription.pageSize;
const params = {
id_type: 2,
sort_type: 200,
cate_id: topicUrl,
- cursor: "0",
- limit: pageSize
- }
- const res = await axios.post('https://api.juejin.cn/recommend_api/v1/article/recommend_cate_feed', params)
- const { data } = res.data
- let msg = `## 掘金热门 ${ topicName } Top5\n\n`
+ cursor: '0',
+ limit: pageSize,
+ };
+ const res = await axios.post(
+ 'https://api.juejin.cn/recommend_api/v1/article/recommend_cate_feed',
+ params
+ );
+ const { data } = res.data;
+ let msg = `## 掘金热门 ${topicName} Top5\n\n`;
for (let i = 0; i < pageSize; i++) {
- msg += `${ i + 1 }、[${ data[i].article_info.title }](https://juejin.cn/post/${ data[i].article_id })\n\n`
+ msg += `${i + 1}、[${data[i].article_info.title}](https://juejin.cn/post/${
+ data[i].article_id
+ })\n\n`;
}
- sendArticleMsg('掘金热门 Top5', msg, webHook)
- logFunc(app, id, groupName, siteName, topicName, '成功')
+ sendArticleMsg('掘金热门 Top5', msg, webHook);
+ logFunc(app, id, groupName, siteName, topicName, '成功');
} catch (err) {
- logFunc(app, id, groupName, siteName, topicName, `失败`, `${ JSON.stringify(err) }`)
+ logFunc(app, id, groupName, siteName, topicName, `失败`, `${JSON.stringify(err)}`);
}
-}
+};
// https://dev.to/t/architecture/top/week
-const getDevArchitectureHot = async (id, groupName, siteName, topicName, topicUrl, webHook, app) => {
+const getDevArchitectureHot = async (
+ id,
+ groupName,
+ siteName,
+ topicName,
+ topicUrl,
+ webHook,
+ app
+) => {
try {
- const pageSize = app.config.articleSubscription.pageSize
- const res = await axios.get(`https://dev.to/search/feed_content?per_page=5&page=0&tag=architecture&sort_by=public_reactions_count&sort_direction=desc&tag_names%5B%5D=architecture&approved=&class_name=Article&published_at%5Bgte%5D=2024-11-10T02%3A43%3A45Z`, { timeout })
- let msg = `## DEV Architecture 每周 Top5\n\n`
+ const pageSize = app.config.articleSubscription.pageSize;
+ const res = await axios.get(
+ `https://dev.to/search/feed_content?per_page=5&page=0&tag=architecture&sort_by=public_reactions_count&sort_direction=desc&tag_names%5B%5D=architecture&approved=&class_name=Article&published_at%5Bgte%5D=2024-11-10T02%3A43%3A45Z`,
+ { timeout }
+ );
+ let msg = `## DEV Architecture 每周 Top5\n\n`;
- const data = res?.data?.result || []
+ const data = res?.data?.result || [];
for (let i = 0; i < pageSize; i++) {
- msg += `${ i + 1 }、[${ data[i].title }](https://dev.to${ data[i].path })\n\n`
+ msg += `${i + 1}、[${data[i].title}](https://dev.to${data[i].path})\n\n`;
}
- msg += `[点击查看更多内容](https://dev.to/t/architecture/top/week)`
- sendArticleMsg('DEV Architecture 每周 Top5', msg, webHook)
- logFunc(app, id, groupName, siteName, topicName, '成功')
+ msg += `[点击查看更多内容](https://dev.to/t/architecture/top/week)`;
+ sendArticleMsg('DEV Architecture 每周 Top5', msg, webHook);
+ logFunc(app, id, groupName, siteName, topicName, '成功');
} catch (err) {
- logFunc(app, id, groupName, siteName, topicName, `失败`, `${ JSON.stringify(err) }`)
+ logFunc(app, id, groupName, siteName, topicName, `失败`, `${JSON.stringify(err)}`);
}
-}
+};
// https://react.statuscode.com/latest
const getReactStatusHot = async (id, groupName, siteName, topicName, topicUrl, webHook, app) => {
try {
- const pageSize = app.config.articleSubscription.pageSize
- const { data } = await axios.get(`https://react.statuscode.com/latest`, { timeout })
- let msg = `## React Status\n\n`
+ const pageSize = app.config.articleSubscription.pageSize;
+ const { data } = await axios.get(`https://react.statuscode.com/latest`, { timeout });
+ let msg = `## React Status\n\n`;
- const $ = cheerio.load(data)
- const items = $('table.el-item').find('span.mainlink')
+ const $ = cheerio.load(data);
+ const items = $('table.el-item').find('span.mainlink');
for (let i = 0; i < pageSize; i++) {
- const name = items.eq(i).text()
- const url = items.eq(i).find('a').attr('href')
- msg += `${ i + 1 }、[${ name }](${ url })\n\n`
+ const name = items.eq(i).text();
+ const url = items.eq(i).find('a').attr('href');
+ msg += `${i + 1}、[${name}](${url})\n\n`;
}
- msg += `[点击查看更多内容](https://react.statuscode.com/latest)`
- sendArticleMsg('React Status', msg, webHook)
- logFunc(app, id, groupName, siteName, topicName, '成功')
+ msg += `[点击查看更多内容](https://react.statuscode.com/latest)`;
+ sendArticleMsg('React Status', msg, webHook);
+ logFunc(app, id, groupName, siteName, topicName, '成功');
} catch (err) {
- logFunc(app, id, groupName, siteName, topicName, `失败`, `Github 网络不佳 ${ JSON.stringify(err) }`)
+ logFunc(
+ app,
+ id,
+ groupName,
+ siteName,
+ topicName,
+ `失败`,
+ `Github 网络不佳 ${JSON.stringify(err)}`
+ );
}
-}
+};
// 自定义消息
-const customMessage = async (id, groupName, siteName, messageTitle, message, isAtAll, webHook, app) => {
+const customMessage = async (
+ id,
+ groupName,
+ siteName,
+ messageTitle,
+ message,
+ isAtAll,
+ webHook,
+ app
+) => {
try {
- sendArticleMsg(messageTitle, message?.replace(/\\n/g, '\n')?.replace(/\\r/g, '\r'), webHook, { isAtAll })
- logFunc(app, id, groupName, siteName, messageTitle, '成功')
+ sendArticleMsg(
+ messageTitle,
+ message?.replace(/\\n/g, '\n')?.replace(/\\r/g, '\r'),
+ webHook,
+ { isAtAll }
+ );
+ logFunc(app, id, groupName, siteName, messageTitle, '成功');
} catch (err) {
- logFunc(app, id, groupName, siteName, messageTitle, `失败`, `${ JSON.stringify(err) }`)
+ logFunc(app, id, groupName, siteName, messageTitle, `失败`, `${JSON.stringify(err)}`);
}
-}
+};
// 打印文章订阅任务结果
const logFunc = (app, id, groupName, siteName, topicName, msg, errMsg = '') => {
- if (!articleResultWebhook) return
- const result = `文章订阅任务, id: ${ id } 执行${ msg }, 钉钉群名称: ${ groupName }, 订阅项: ${ siteName }-${ topicName } ${ errMsg ? ', ' + errMsg : '' }`
+ if (!articleResultWebhook) return;
+ const result = `文章订阅任务, id: ${id} 执行${msg}, 钉钉群名称: ${groupName}, 订阅项: ${siteName}-${topicName} ${
+ errMsg ? ', ' + errMsg : ''
+ }`;
// 向 agent 进程发消息
- app.messenger.sendToAgent('timedTaskResult', { result })
+ app.messenger.sendToAgent('timedTaskResult', { result });
// 文章订阅发送后,发出是否成功的通知
- const text = `文章订阅结果:${ msg }
- \n\n钉钉群名称:${ groupName }
- \n\n订阅项:${ siteName }-${ topicName }
- ${ msg === '失败' ? '\n\n请前往服务器查看对应日志!' : '' }`
- sendMsgAfterSendArticle(`发送${ msg }`, text, articleResultWebhook)
-}
+ const text = `文章订阅结果:${msg}
+ \n\n钉钉群名称:${groupName}
+ \n\n订阅项:${siteName}-${topicName}
+ ${msg === '失败' ? '\n\n请前往服务器查看对应日志!' : ''}`;
+ sendMsgAfterSendArticle(`发送${msg}`, text, articleResultWebhook);
+};
module.exports = {
getGithubTrendingFromGithub,
@@ -172,5 +272,5 @@ module.exports = {
getJueJinHot,
getDevArchitectureHot,
getReactStatusHot,
- customMessage
-}
+ customMessage,
+};
diff --git a/app/utils/createServer.js b/app/utils/createServer.js
index 5fc0587..81ebe71 100644
--- a/app/utils/createServer.js
+++ b/app/utils/createServer.js
@@ -1,47 +1,47 @@
-const SSHClient = require('ssh2').Client
-const utf8 = require('utf8')
-
+const SSHClient = require('ssh2').Client;
+const utf8 = require('utf8');
const createNewServer = (machineConfig, ctx) => {
const ssh = new SSHClient();
- const { host, username, password } = machineConfig
- const { socket } = ctx
+ const { host, username, password } = machineConfig;
+ const { socket } = ctx;
// 连接成功
ssh.on('ready', () => {
-
- socket.emit('serverMsg', '\r\n*** SSH CONNECTION SUCCESS ***\r\n')
+ socket.emit('serverMsg', '\r\n*** SSH CONNECTION SUCCESS ***\r\n');
ssh.shell((err, stream) => {
-
if (err) {
return socket.send('\r\n*** SSH SHELL ERROR: ' + err.message + ' ***\r\n');
}
socket.on('shellCommand', (command) => {
- stream.write(command)
- })
-
- stream.on('data', (msg) => {
- socket.emit('serverMsg', utf8.decode(msg.toString('binary')))
-
- }).on('close', () => {
- ssh.end();
+ stream.write(command);
});
- })
- }).on('close', () => {
- socket.emit('serverMsg', '\r\n*** SSH CONNECTION CLOSED ***\r\n')
- }).on('error', (err) => {
- socket.emit('serverMsg', '\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n')
- }).connect({
- port: 22,
- host,
- username,
- password
+ stream
+ .on('data', (msg) => {
+ socket.emit('serverMsg', utf8.decode(msg.toString('binary')));
+ })
+ .on('close', () => {
+ ssh.end();
+ });
+ });
})
-}
+ .on('close', () => {
+ socket.emit('serverMsg', '\r\n*** SSH CONNECTION CLOSED ***\r\n');
+ })
+ .on('error', (err) => {
+ socket.emit('serverMsg', '\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n');
+ })
+ .connect({
+ port: 22,
+ host,
+ username,
+ password,
+ });
+};
module.exports = {
- createNewServer
-}
+ createNewServer,
+};
diff --git a/app/utils/index.js b/app/utils/index.js
index 568f05a..584da8d 100644
--- a/app/utils/index.js
+++ b/app/utils/index.js
@@ -3,74 +3,85 @@ const fs = require('fs');
const ROOT_PATH = path.join(__dirname, '../../');
const ChatBot = require('dingtalk-robot-sender');
-const createFolder = (paths) => {
+const createFolder = (paths) => {
let dirPath = ROOT_PATH;
try {
- paths.forEach(dir => {
+ paths.forEach((dir) => {
dirPath = path.join(dirPath, dir.toString());
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath);
}
- })
+ });
return dirPath;
} catch {
- throw new Error('创建文件夹出错')
+ throw new Error('创建文件夹出错');
}
-}
-const createFileSync = (paths,fileName,data) => {
+};
+const createFileSync = (paths, fileName, data) => {
try {
const dir = createFolder(paths);
- const filePath = path.join(dir,fileName)
- fs.writeFileSync(filePath,data);
+ const filePath = path.join(dir, fileName);
+ fs.writeFileSync(filePath, data);
return filePath;
} catch {
- throw new Error('创建文件出错')
+ throw new Error('创建文件出错');
}
-}
+};
const sendMsg = async (webhook_url, basicInfo, operation, address) => {
- const { filename, hostIp, hostName } = basicInfo
+ const { filename, hostIp, hostName } = basicInfo;
const feChatRobot = new ChatBot({
- webhook: webhook_url
+ webhook: webhook_url,
});
- const mdTxt = "Doraemon - 配置中心变更通知:\n\n\n" +
- "文件名:" + filename + "\n\n\n" +
- "主机:" + hostIp + "(" + hostName + ")\n\n" +
- "详情地址:" + address + "\n\n\n" +
- "该配置文件" + operation
- feChatRobot
- .markdown('配置中心变更通知', mdTxt)
- .catch(ex => console.error(ex));
-}
+ const mdTxt =
+ 'Doraemon - 配置中心变更通知:\n\n\n' +
+ '文件名:' +
+ filename +
+ '\n\n\n' +
+ '主机:' +
+ hostIp +
+ '(' +
+ hostName +
+ ')\n\n' +
+ '详情地址:' +
+ address +
+ '\n\n\n' +
+ '该配置文件' +
+ operation;
+ feChatRobot.markdown('配置中心变更通知', mdTxt).catch((ex) => console.error(ex));
+};
const sendHostsUpdateMsg = async (webhook_url, basicInfo, ip, address, operation) => {
- const { groupName, groupApi } = basicInfo
+ const { groupName, groupApi } = basicInfo;
const feChatRobot = new ChatBot({
- webhook: webhook_url
+ webhook: webhook_url,
});
- const mdTxt = "Doraemon - Hosts管理变更通知:\n\n\n" +
- "分组名称:" + groupName + "\n\n\n" +
- "API:" + ip + groupApi + "\n\n\n" +
- "详情地址:" + address + "\n\n\n" +
- "该Hosts文件" + operation
- feChatRobot
- .markdown('Hosts管理变更通知', mdTxt)
- .catch(ex => console.error(ex));
-}
+ const mdTxt =
+ 'Doraemon - Hosts管理变更通知:\n\n\n' +
+ '分组名称:' +
+ groupName +
+ '\n\n\n' +
+ 'API:' +
+ ip +
+ groupApi +
+ '\n\n\n' +
+ '详情地址:' +
+ address +
+ '\n\n\n' +
+ '该Hosts文件' +
+ operation;
+ feChatRobot.markdown('Hosts管理变更通知', mdTxt).catch((ex) => console.error(ex));
+};
// 发送文章订阅消息
const sendArticleMsg = async (title, text, webhook, at = {}) => {
- const feChatRobot = new ChatBot({ webhook })
- feChatRobot
- .markdown(title, text, at)
- .catch(ex => console.error(ex))
-}
+ const feChatRobot = new ChatBot({ webhook });
+ feChatRobot.markdown(title, text, at).catch((ex) => console.error(ex));
+};
// 文章订阅发送后,发出是否成功的通知
const sendMsgAfterSendArticle = async (title, text, webhook) => {
- const feChatRobot = new ChatBot({ webhook })
- feChatRobot
- .markdown(title, text)
- .catch(ex => console.error(ex))
-}
+ const feChatRobot = new ChatBot({ webhook });
+ feChatRobot.markdown(title, text).catch((ex) => console.error(ex));
+};
module.exports = {
createFolder,
@@ -79,14 +90,14 @@ module.exports = {
sendHostsUpdateMsg,
sendArticleMsg,
sendMsgAfterSendArticle,
- response: (success, data = null, message)=>{
- if(success) {
- message='执行成功';
+ response: (success, data = null, message) => {
+ if (success) {
+ message = '执行成功';
}
return {
success,
data,
- message
- }
- }
-}
+ message,
+ };
+ },
+};
diff --git a/app/utils/timedTask.js b/app/utils/timedTask.js
index f06db32..fe25c7c 100644
--- a/app/utils/timedTask.js
+++ b/app/utils/timedTask.js
@@ -1,60 +1,60 @@
/**
* 文章订阅任务
*/
-const schedule = require('node-schedule')
+const schedule = require('node-schedule');
// 判断文章订阅任务是否存在
const timedTaskIsExist = (name, agent) => {
- const timedTask = schedule.scheduledJobs[`${ name }`]
- log(agent, `文章订阅任务, id:${ name } ${ timedTask === undefined ? '不存在' : '存在' }`)
- return timedTask !== undefined
-}
+ const timedTask = schedule.scheduledJobs[`${name}`];
+ log(agent, `文章订阅任务, id:${name} ${timedTask === undefined ? '不存在' : '存在'}`);
+ return timedTask !== undefined;
+};
// 开始文章订阅任务
const createTimedTask = (name, cron, agent) => {
- if (timedTaskIsExist(name, agent)) return
- log(agent, `创建文章订阅任务, id: ${ name }, Cron: ${ cron }`)
- schedule.scheduleJob(`${ name }`, cron, () => {
+ if (timedTaskIsExist(name, agent)) return;
+ log(agent, `创建文章订阅任务, id: ${name}, Cron: ${cron}`);
+ schedule.scheduleJob(`${name}`, cron, () => {
// agent 进程随机给一个 app 进程发消息(由 master 来控制发送给谁)
- agent.messenger.sendRandom('sendArticleSubscription', name)
- })
-}
+ agent.messenger.sendRandom('sendArticleSubscription', name);
+ });
+};
// 改变文章订阅任务的时间规则
const changeTimedTask = (name, cron, agent) => {
- if (!timedTaskIsExist(name, agent)) return createTimedTask(name, cron, agent)
- schedule.rescheduleJob(schedule.scheduledJobs[`${ name }`], cron)
- log(agent, `编辑文章订阅任务, id: ${ name }, Cron: ${ cron }`)
-}
+ if (!timedTaskIsExist(name, agent)) return createTimedTask(name, cron, agent);
+ schedule.rescheduleJob(schedule.scheduledJobs[`${name}`], cron);
+ log(agent, `编辑文章订阅任务, id: ${name}, Cron: ${cron}`);
+};
// 取消指定文章订阅任务
const cancelTimedTask = (name, agent) => {
- if (!timedTaskIsExist(name, agent)) return
- log(agent, `取消文章订阅任务, id: ${ name }`)
- schedule.scheduledJobs[`${ name }`].cancel()
-}
+ if (!timedTaskIsExist(name, agent)) return;
+ log(agent, `取消文章订阅任务, id: ${name}`);
+ schedule.scheduledJobs[`${name}`].cancel();
+};
// 文章订阅任务列表
const timedTaskList = (agent) => {
- const result = Object.keys(schedule.scheduledJobs)
- log(agent, `文章订阅任务 id 列表: [${ result.join(',') }]`)
- return result
-}
+ const result = Object.keys(schedule.scheduledJobs);
+ log(agent, `文章订阅任务 id 列表: [${result.join(',')}]`);
+ return result;
+};
// 打印文章订阅任务的执行结果
const timedTaskResult = (result, agent) => {
- log(agent, result)
-}
+ log(agent, result);
+};
// 打印文章订阅任务信息
const log = (agent, msg) => {
- agent.logger.info(`${ msg }`)
-}
+ agent.logger.info(`${msg}`);
+};
module.exports = {
createTimedTask,
changeTimedTask,
cancelTimedTask,
timedTaskList,
- timedTaskResult
-}
+ timedTaskResult,
+};
diff --git a/app/view/app.js b/app/view/app.js
index 8bc6972..e145135 100644
--- a/app/view/app.js
+++ b/app/view/app.js
@@ -1 +1 @@
-!function(n,t){for(var e in t)n[e]=t[e]}(exports,function(n){var t={};function e(a){if(t[a])return t[a].exports;var o=t[a]={i:a,l:!1,exports:{}};return n[a].call(o.exports,o,o.exports,e),o.l=!0,o.exports}return e.m=n,e.c=t,e.d=function(n,t,a){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:a})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var a=Object.create(null);if(e.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var o in n)e.d(a,o,function(t){return n[t]}.bind(null,o));return a},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="/public/",e(e.s=67)}([function(n,t){n.exports=require("react")},function(n,t){n.exports=require("antd")},function(n,t){n.exports=function(n){var t=[];return t.toString=function(){return this.map((function(t){var e=function(n,t){var e=n[1]||"",a=n[3];if(!a)return e;if(t&&"function"==typeof btoa){var o=(i=a,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(i))))+" */"),r=a.sources.map((function(n){return"/*# sourceURL="+a.sourceRoot+n+" */"}));return[e].concat(r).concat([o]).join("\n")}var i;return[e].join("\n")}(t,n);return t[2]?"@media "+t[2]+"{"+e+"}":e})).join("")},t.i=function(n,e){"string"==typeof n&&(n=[[null,n,""]]);for(var a={},o=0;o1&&void 0!==arguments[1]?arguments[1]:{},e=t.replace,r=void 0!==e&&e,c=t.prepend,d=void 0!==c&&c,p=[],u=0;u0&&o[o.length-1])||6!==r[0]&&2!==r[0])){i=0;continue}if(3===r[0]&&(!o||r[1]>o[0]&&r[1]0?a:e)(n)}},function(n,t,e){var a=e(46)("keys"),o=e(47);n.exports=function(n){return a[n]||(a[n]=o(n))}},function(n){n.exports=JSON.parse('{"webhookUrls":[],"msgSingleUrl":"https://dtstack.github.io/doraemon/docsify/#/","helpDocUrl":"https://dtstack.github.io/doraemon/docsify/#/","articleHelpDocUrl":"https://dtstack.github.io/doraemon/docsify/#/zh-cn/guide/%E6%96%87%E7%AB%A0%E8%AE%A2%E9%98%85","proxyHelpDocUrl":"https://dtstack.github.io/doraemon/docsify/#/zh-cn/guide/%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1","mysql":{"prod":{}}}')},function(n,t){n.exports=require("js-cookie")},function(n,t){n.exports=require("prop-types")},function(n,t){n.exports=require("socket.io-parser")},function(n,t,e){"use strict";var a,o;Object.defineProperty(t,"__esModule",{value:!0}),t.SUBSCRIPTIONSENDTYPECN=t.SUBSCRIPTIONSENDTYPE=t.SUBSCRIPTIONSTATUS=void 0,function(n){n[n.OPEN=1]="OPEN",n[n.CLOSE=2]="CLOSE"}(t.SUBSCRIPTIONSTATUS||(t.SUBSCRIPTIONSTATUS={})),function(n){n[n.WORKDAY=1]="WORKDAY",n[n.EVERYDAY=2]="EVERYDAY"}(o=t.SUBSCRIPTIONSENDTYPE||(t.SUBSCRIPTIONSENDTYPE={})),t.SUBSCRIPTIONSENDTYPECN=((a={})[o.WORKDAY]="周一至周五",a[o.EVERYDAY]="每天",a)},function(n,t){n.exports=require("redux")},function(n,t,e){"use strict";var a=e(15);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=a(e(75)),r=a(e(76)),i=a(e(36)),l={lang:(0,o.default)({placeholder:"请选择日期",yearPlaceholder:"请选择年份",quarterPlaceholder:"请选择季度",monthPlaceholder:"请选择月份",weekPlaceholder:"请选择周",rangePlaceholder:["开始日期","结束日期"],rangeYearPlaceholder:["开始年份","结束年份"],rangeMonthPlaceholder:["开始月份","结束月份"],rangeWeekPlaceholder:["开始周","结束周"]},r.default),timePickerLocale:(0,o.default)({},i.default)};l.lang.ok="确 定";var s=l;t.default=s},function(n,t,e){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a={placeholder:"请选择时间",rangePlaceholder:["开始时间","结束时间"]};t.default=a},function(n,t,e){"use strict";var a=this&&this.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(t,"__esModule",{value:!0});var o=a(e(78)),r=a(e(117)),i=a(e(121)),l=a(e(132)),s=a(e(138)),c=a(e(153)),d=a(e(162)),p=a(e(189)),u=a(e(193)),b=a(e(199)),f=a(e(200)),m=a(e(202)),h=a(e(209)),g=a(e(217)),x=[{path:"/",component:o.default,routes:[{path:"/page/toolbox",component:s.default},{path:"/page/home",component:r.default},{path:"/page/internal-url-navigation",component:l.default},{path:"/page/proxy-server",component:i.default},{path:"/page/mail-sign",component:c.default},{path:"/page/host-management",component:d.default},{path:"/page/config-center",component:p.default},{path:"/page/config-detail/:id",component:u.default},{path:"/page/switch-hosts-list",component:b.default},{path:"/page/switch-hosts-edit/:id/:type",component:f.default},{path:"/page/article-subscription-list",component:m.default},{path:"/page/tags",component:h.default},{path:"*",component:g.default}]}];t.default=x},function(n,t){n.exports=require("classnames")},function(n,t,e){e(86);for(var a=e(11),o=e(13),r=e(12),i=e(8)("toStringTag"),l="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),s=0;s=t.length?{value:void 0,done:!0}:(n=a(t,e),this._i+=n.length,{value:n,done:!1})}))},function(n,t,e){var a=e(40),o=e(8)("toStringTag"),r="Arguments"==a(function(){return arguments}());n.exports=function(n){var t,e,i;return void 0===n?"Undefined":null===n?"Null":"string"==typeof(e=function(n,t){try{return n[t]}catch(n){}}(t=Object(n),o))?e:r?a(t):"Object"==(i=a(t))&&"function"==typeof t.callee?"Arguments":i}},function(n,t,e){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.urlReg=void 0,t.urlReg=new RegExp(/(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/,"i")},function(n,t,e){n.exports=e.p+"img/help-icon.3d0854a5.png"},function(n,t,e){var a=e(178),o=e(55),r=e(56),i=e(32),l=e(57),s=e(58),c=e(20)("socket.io-client:manager"),d=e(181),p=e(182),u=Object.prototype.hasOwnProperty;function b(n,t){if(!(this instanceof b))return new b(n,t);n&&"object"==typeof n&&(t=n,n=void 0),(t=t||{}).path=t.path||"/socket.io",this.nsps={},this.subs=[],this.opts=t,this.reconnection(!1!==t.reconnection),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor(t.randomizationFactor||.5),this.backoff=new p({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(null==t.timeout?2e4:t.timeout),this.readyState="closed",this.uri=n,this.connecting=[],this.lastPing=null,this.encoding=!1,this.packetBuffer=[],this.encoder=new i.Encoder,this.decoder=new i.Decoder,this.autoConnect=!1!==t.autoConnect,this.autoConnect&&this.open()}n.exports=b,b.prototype.emitAll=function(){for(var n in this.emit.apply(this,arguments),this.nsps)u.call(this.nsps,n)&&this.nsps[n].emit.apply(this.nsps[n],arguments)},b.prototype.updateSocketIds=function(){for(var n in this.nsps)u.call(this.nsps,n)&&(this.nsps[n].id=this.engine.id)},r(b.prototype),b.prototype.reconnection=function(n){return arguments.length?(this._reconnection=!!n,this):this._reconnection},b.prototype.reconnectionAttempts=function(n){return arguments.length?(this._reconnectionAttempts=n,this):this._reconnectionAttempts},b.prototype.reconnectionDelay=function(n){return arguments.length?(this._reconnectionDelay=n,this.backoff&&this.backoff.setMin(n),this):this._reconnectionDelay},b.prototype.randomizationFactor=function(n){return arguments.length?(this._randomizationFactor=n,this.backoff&&this.backoff.setJitter(n),this):this._randomizationFactor},b.prototype.reconnectionDelayMax=function(n){return arguments.length?(this._reconnectionDelayMax=n,this.backoff&&this.backoff.setMax(n),this):this._reconnectionDelayMax},b.prototype.timeout=function(n){return arguments.length?(this._timeout=n,this):this._timeout},b.prototype.maybeReconnectOnOpen=function(){!this.reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()},b.prototype.open=b.prototype.connect=function(n,t){if(c("readyState %s",this.readyState),~this.readyState.indexOf("open"))return this;c("opening %s",this.uri),this.engine=a(this.uri,this.opts);var e=this.engine,o=this;this.readyState="opening",this.skipReconnect=!1;var r=l(e,"open",(function(){o.onopen(),n&&n()})),i=l(e,"error",(function(t){if(c("connect_error"),o.cleanup(),o.readyState="closed",o.emitAll("connect_error",t),n){var e=new Error("Connection error");e.data=t,n(e)}else o.maybeReconnectOnOpen()}));if(!1!==this._timeout){var s=this._timeout;c("connect attempt will timeout after %d",s);var d=setTimeout((function(){c("connect attempt timed out after %d",s),r.destroy(),e.close(),e.emit("error","timeout"),o.emitAll("connect_timeout",s)}),s);this.subs.push({destroy:function(){clearTimeout(d)}})}return this.subs.push(r),this.subs.push(i),this},b.prototype.onopen=function(){c("open"),this.cleanup(),this.readyState="open",this.emit("open");var n=this.engine;this.subs.push(l(n,"data",s(this,"ondata"))),this.subs.push(l(n,"ping",s(this,"onping"))),this.subs.push(l(n,"pong",s(this,"onpong"))),this.subs.push(l(n,"error",s(this,"onerror"))),this.subs.push(l(n,"close",s(this,"onclose"))),this.subs.push(l(this.decoder,"decoded",s(this,"ondecoded")))},b.prototype.onping=function(){this.lastPing=new Date,this.emitAll("ping")},b.prototype.onpong=function(){this.emitAll("pong",new Date-this.lastPing)},b.prototype.ondata=function(n){this.decoder.add(n)},b.prototype.ondecoded=function(n){this.emit("packet",n)},b.prototype.onerror=function(n){c("error",n),this.emitAll("error",n)},b.prototype.socket=function(n,t){var e=this.nsps[n];if(!e){e=new o(this,n,t),this.nsps[n]=e;var a=this;e.on("connecting",r),e.on("connect",(function(){e.id=a.engine.id})),this.autoConnect&&r()}function r(){~d(a.connecting,e)||a.connecting.push(e)}return e},b.prototype.destroy=function(n){var t=d(this.connecting,n);~t&&this.connecting.splice(t,1),this.connecting.length||this.close()},b.prototype.packet=function(n){c("writing packet %j",n);var t=this;n.query&&0===n.type&&(n.nsp+="?"+n.query),t.encoding?t.packetBuffer.push(n):(t.encoding=!0,this.encoder.encode(n,(function(e){for(var a=0;a0&&!this.encoding){var n=this.packetBuffer.shift();this.packet(n)}},b.prototype.cleanup=function(){c("cleanup");for(var n=this.subs.length,t=0;t=this._reconnectionAttempts)c("reconnect failed"),this.backoff.reset(),this.emitAll("reconnect_failed"),this.reconnecting=!1;else{var t=this.backoff.duration();c("will wait %dms before reconnect attempt",t),this.reconnecting=!0;var e=setTimeout((function(){n.skipReconnect||(c("attempting reconnect"),n.emitAll("reconnect_attempt",n.backoff.attempts),n.emitAll("reconnecting",n.backoff.attempts),n.skipReconnect||n.open((function(t){t?(c("reconnect attempt error"),n.reconnecting=!1,n.reconnect(),n.emitAll("reconnect_error",t.data)):(c("reconnect success"),n.onreconnect())})))}),t);this.subs.push({destroy:function(){clearTimeout(e)}})}},b.prototype.onreconnect=function(){var n=this.backoff.attempts;this.reconnecting=!1,this.backoff.reset(),this.updateSocketIds(),this.emitAll("reconnect",n)}},function(n,t,e){var a=e(32),o=e(56),r=e(179),i=e(57),l=e(58),s=e(20)("socket.io-client:socket"),c=e(180);n.exports=u;var d={connect:1,connect_error:1,connect_timeout:1,connecting:1,disconnect:1,error:1,reconnect:1,reconnect_attempt:1,reconnect_failed:1,reconnect_error:1,reconnecting:1,ping:1,pong:1},p=o.prototype.emit;function u(n,t,e){this.io=n,this.nsp=t,this.json=this,this.ids=0,this.acks={},this.receiveBuffer=[],this.sendBuffer=[],this.connected=!1,this.disconnected=!0,e&&e.query&&(this.query=e.query),this.io.autoConnect&&this.open()}o(u.prototype),u.prototype.subEvents=function(){if(!this.subs){var n=this.io;this.subs=[i(n,"open",l(this,"onopen")),i(n,"packet",l(this,"onpacket")),i(n,"close",l(this,"onclose"))]}},u.prototype.open=u.prototype.connect=function(){return this.connected||(this.subEvents(),this.io.open(),"open"===this.io.readyState&&this.onopen(),this.emit("connecting")),this},u.prototype.send=function(){var n=r(arguments);return n.unshift("message"),this.emit.apply(this,n),this},u.prototype.emit=function(n){if(d.hasOwnProperty(n))return p.apply(this,arguments),this;var t=r(arguments),e=a.EVENT;c(t)&&(e=a.BINARY_EVENT);var o={type:e,data:t,options:{}};return o.options.compress=!this.flags||!1!==this.flags.compress,"function"==typeof t[t.length-1]&&(s("emitting packet with ack id %d",this.ids),this.acks[this.ids]=t.pop(),o.id=this.ids++),this.connected?this.packet(o):this.sendBuffer.push(o),delete this.flags,this},u.prototype.packet=function(n){n.nsp=this.nsp,this.io.packet(n)},u.prototype.onopen=function(){s("transport is open - connecting"),"/"!==this.nsp&&(this.query?this.packet({type:a.CONNECT,query:this.query}):this.packet({type:a.CONNECT}))},u.prototype.onclose=function(n){s("close (%s)",n),this.connected=!1,this.disconnected=!0,delete this.id,this.emit("disconnect",n)},u.prototype.onpacket=function(n){if(n.nsp===this.nsp)switch(n.type){case a.CONNECT:this.onconnect();break;case a.EVENT:case a.BINARY_EVENT:this.onevent(n);break;case a.ACK:case a.BINARY_ACK:this.onack(n);break;case a.DISCONNECT:this.ondisconnect();break;case a.ERROR:this.emit("error",n.data)}},u.prototype.onevent=function(n){var t=n.data||[];s("emitting event %j",t),null!=n.id&&(s("attaching ack callback to event"),t.push(this.ack(n.id))),this.connected?p.apply(this,t):this.receiveBuffer.push(t)},u.prototype.ack=function(n){var t=this,e=!1;return function(){if(!e){e=!0;var o=r(arguments);s("sending ack %j",o);var i=c(o)?a.BINARY_ACK:a.ACK;t.packet({type:i,id:n,data:o})}}},u.prototype.onack=function(n){var t=this.acks[n.id];"function"==typeof t?(s("calling ack %s with %j",n.id,n.data),t.apply(this,n.data),delete this.acks[n.id]):s("bad ack %s",n.id)},u.prototype.onconnect=function(){this.connected=!0,this.disconnected=!1,this.emit("connect"),this.emitBuffered()},u.prototype.emitBuffered=function(){var n;for(n=0;n*\/]/.test(p)?l(null,"select-op"):/[;{}:\[\]]/.test(p)?l(null,p):(n.eatWhile(/[\w\\\-]/),l("variable","variable")):l(null,"compare"):void l(null,"compare")}function c(n,t){for(var e,a=!1;null!=(e=n.next());){if(a&&"/"==e){t.tokenize=s;break}a="*"==e}return l("comment","comment")}function d(n,t){for(var e,a=0;null!=(e=n.next());){if(a>=2&&">"==e){t.tokenize=s;break}a="-"==e?a+1:0}return l("comment","comment")}return{startState:function(n){return{tokenize:s,baseIndent:n||0,stack:[]}},token:function(n,t){if(n.eatSpace())return null;e=null;var a=t.tokenize(n,t),o=t.stack[t.stack.length-1];return"hash"==e&&"rule"==o?a="atom":"variable"==a&&("rule"==o?a="number":o&&"@media{"!=o||(a="tag")),"rule"==o&&/^[\{\};]$/.test(e)&&t.stack.pop(),"{"==e?"@media"==o?t.stack[t.stack.length-1]="@media{":t.stack.push("{"):"}"==e?t.stack.pop():"@media"==e?t.stack.push("@media"):"{"==o&&"comment"!=e&&t.stack.push("rule"),a},indent:function(n,t){var e=n.stack.length;return/^\}/.test(t)&&(e-="rule"==n.stack[n.stack.length-1]?2:1),n.baseIndent+e*i},electricChars:"}"}})),n.defineMIME("text/x-nginx-conf","nginx")}(e(62))},function(n,t,e){n.exports=function(){"use strict";var n=navigator.userAgent,t=navigator.platform,e=/gecko\/\d/i.test(n),a=/MSIE \d/.test(n),o=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(n),r=/Edge\/(\d+)/.exec(n),i=a||o||r,l=i&&(a?document.documentMode||6:+(r||o)[1]),s=!r&&/WebKit\//.test(n),c=s&&/Qt\/\d+\.\d+/.test(n),d=!r&&/Chrome\//.test(n),p=/Opera\//.test(n),u=/Apple Computer/.test(navigator.vendor),b=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(n),f=/PhantomJS/.test(n),m=u&&(/Mobile\/\w+/.test(n)||navigator.maxTouchPoints>2),h=/Android/.test(n),g=m||h||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(n),x=m||/Mac/.test(t),v=/\bCrOS\b/.test(n),y=/win/i.test(t),w=p&&n.match(/Version\/(\d*\.\d*)/);w&&(w=Number(w[1])),w&&w>=15&&(p=!1,s=!0);var k=x&&(c||p&&(null==w||w<12.11)),z=e||i&&l>=9;function _(n){return new RegExp("(^|\\s)"+n+"(?:$|\\s)\\s*")}var F,C=function(n,t){var e=n.className,a=_(t).exec(e);if(a){var o=e.slice(a.index+a[0].length);n.className=e.slice(0,a.index)+(o?a[1]+o:"")}};function E(n){for(var t=n.childNodes.length;t>0;--t)n.removeChild(n.firstChild);return n}function S(n,t){return E(n).appendChild(t)}function O(n,t,e,a){var o=document.createElement(n);if(e&&(o.className=e),a&&(o.style.cssText=a),"string"==typeof t)o.appendChild(document.createTextNode(t));else if(t)for(var r=0;r=t)return i+(t-r);i+=l-r,i+=e-i%e,r=l+1}}m?T=function(n){n.selectionStart=0,n.selectionEnd=n.value.length}:i&&(T=function(n){try{n.select()}catch(n){}});var j=function(){this.id=null,this.f=null,this.time=0,this.handler=I(this.onTimeout,this)};function R(n,t){for(var e=0;e=t)return a+Math.min(i,t-o);if(o+=r-a,a=r+1,(o+=e-o%e)>=t)return a}}var K=[""];function G(n){for(;K.length<=n;)K.push(V(K)+" ");return K[n]}function V(n){return n[n.length-1]}function X(n,t){for(var e=[],a=0;a""&&(n.toUpperCase()!=n.toLowerCase()||Q.test(n))}function nn(n,t){return t?!!(t.source.indexOf("\\w")>-1&&J(n))||t.test(n):J(n)}function tn(n){for(var t in n)if(n.hasOwnProperty(t)&&n[t])return!1;return!0}var en=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function an(n){return n.charCodeAt(0)>=768&&en.test(n)}function on(n,t,e){for(;(e<0?t>0:te?-1:1;;){if(t==e)return t;var o=(t+e)/2,r=a<0?Math.ceil(o):Math.floor(o);if(r==t)return n(r)?t:e;n(r)?e=r:t=r+a}}var ln=null;function sn(n,t,e){var a;ln=null;for(var o=0;ot)return o;r.to==t&&(r.from!=r.to&&"before"==e?a=o:ln=o),r.from==t&&(r.from!=r.to&&"before"!=e?a=o:ln=o)}return null!=a?a:ln}var cn=function(){var n=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,t=/[stwN]/,e=/[LRr]/,a=/[Lb1n]/,o=/[1n]/;function r(n,t,e){this.level=n,this.from=t,this.to=e}return function(i,l){var s="ltr"==l?"L":"R";if(0==i.length||"ltr"==l&&!n.test(i))return!1;for(var c,d=i.length,p=[],u=0;u-1&&(a[t]=o.slice(0,r).concat(o.slice(r+1)))}}}function mn(n,t){var e=bn(n,t);if(e.length)for(var a=Array.prototype.slice.call(arguments,2),o=0;o0}function vn(n){n.prototype.on=function(n,t){un(this,n,t)},n.prototype.off=function(n,t){fn(this,n,t)}}function yn(n){n.preventDefault?n.preventDefault():n.returnValue=!1}function wn(n){n.stopPropagation?n.stopPropagation():n.cancelBubble=!0}function kn(n){return null!=n.defaultPrevented?n.defaultPrevented:0==n.returnValue}function zn(n){yn(n),wn(n)}function _n(n){return n.target||n.srcElement}function Fn(n){var t=n.which;return null==t&&(1&n.button?t=1:2&n.button?t=3:4&n.button&&(t=2)),x&&n.ctrlKey&&1==t&&(t=3),t}var Cn,En,Sn=function(){if(i&&l<9)return!1;var n=O("div");return"draggable"in n||"dragDrop"in n}();function On(n){if(null==Cn){var t=O("span","");S(n,O("span",[t,document.createTextNode("x")])),0!=n.firstChild.offsetHeight&&(Cn=t.offsetWidth<=1&&t.offsetHeight>2&&!(i&&l<8))}var e=Cn?O("span",""):O("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return e.setAttribute("cm-text",""),e}function Dn(n){if(null!=En)return En;var t=S(n,document.createTextNode("AخA")),e=F(t,0,1).getBoundingClientRect(),a=F(t,1,2).getBoundingClientRect();return E(n),!(!e||e.left==e.right)&&(En=a.right-e.right<3)}var Mn,Bn=3!="\n\nb".split(/\n/).length?function(n){for(var t=0,e=[],a=n.length;t<=a;){var o=n.indexOf("\n",t);-1==o&&(o=n.length);var r=n.slice(t,"\r"==n.charAt(o-1)?o-1:o),i=r.indexOf("\r");-1!=i?(e.push(r.slice(0,i)),t+=i+1):(e.push(r),t=o+1)}return e}:function(n){return n.split(/\r\n?|\n/)},An=window.getSelection?function(n){try{return n.selectionStart!=n.selectionEnd}catch(n){return!1}}:function(n){var t;try{t=n.ownerDocument.selection.createRange()}catch(n){}return!(!t||t.parentElement()!=n)&&0!=t.compareEndPoints("StartToEnd",t)},Ln="oncopy"in(Mn=O("div"))||(Mn.setAttribute("oncopy","return;"),"function"==typeof Mn.oncopy),Tn=null,In={},Pn={};function Nn(n,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),In[n]=t}function jn(n){if("string"==typeof n&&Pn.hasOwnProperty(n))n=Pn[n];else if(n&&"string"==typeof n.name&&Pn.hasOwnProperty(n.name)){var t=Pn[n.name];"string"==typeof t&&(t={name:t}),(n=$(t,n)).name=t.name}else{if("string"==typeof n&&/^[\w\-]+\/[\w\-]+\+xml$/.test(n))return jn("application/xml");if("string"==typeof n&&/^[\w\-]+\/[\w\-]+\+json$/.test(n))return jn("application/json")}return"string"==typeof n?{name:n}:n||{name:"null"}}function Rn(n,t){t=jn(t);var e=In[t.name];if(!e)return Rn(n,"text/plain");var a=e(n,t);if(Hn.hasOwnProperty(t.name)){var o=Hn[t.name];for(var r in o)o.hasOwnProperty(r)&&(a.hasOwnProperty(r)&&(a["_"+r]=a[r]),a[r]=o[r])}if(a.name=t.name,t.helperType&&(a.helperType=t.helperType),t.modeProps)for(var i in t.modeProps)a[i]=t.modeProps[i];return a}var Hn={};function Wn(n,t){P(t,Hn.hasOwnProperty(n)?Hn[n]:Hn[n]={})}function Un(n,t){if(!0===t)return t;if(n.copyState)return n.copyState(t);var e={};for(var a in t){var o=t[a];o instanceof Array&&(o=o.concat([])),e[a]=o}return e}function Yn(n,t){for(var e;n.innerMode&&(e=n.innerMode(t))&&e.mode!=n;)t=e.state,n=e.mode;return e||{mode:n,state:t}}function qn(n,t,e){return!n.startState||n.startState(t,e)}var Kn=function(n,t,e){this.pos=this.start=0,this.string=n,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=e};function Gn(n,t){if((t-=n.first)<0||t>=n.size)throw new Error("There is no line "+(t+n.first)+" in the document.");for(var e=n;!e.lines;)for(var a=0;;++a){var o=e.children[a],r=o.chunkSize();if(t=n.first&&te?tt(e,Gn(n,e).text.length):function(n,t){var e=n.ch;return null==e||e>t?tt(n.line,t):e<0?tt(n.line,0):n}(t,Gn(n,t.line).text.length)}function ct(n,t){for(var e=[],a=0;a=this.string.length},Kn.prototype.sol=function(){return this.pos==this.lineStart},Kn.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},Kn.prototype.next=function(){if(this.post},Kn.prototype.eatSpace=function(){for(var n=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>n},Kn.prototype.skipToEnd=function(){this.pos=this.string.length},Kn.prototype.skipTo=function(n){var t=this.string.indexOf(n,this.pos);if(t>-1)return this.pos=t,!0},Kn.prototype.backUp=function(n){this.pos-=n},Kn.prototype.column=function(){return this.lastColumnPos0?null:(a&&!1!==t&&(this.pos+=a[0].length),a)}var o=function(n){return e?n.toLowerCase():n};if(o(this.string.substr(this.pos,n.length))==o(n))return!1!==t&&(this.pos+=n.length),!0},Kn.prototype.current=function(){return this.string.slice(this.start,this.pos)},Kn.prototype.hideFirstChars=function(n,t){this.lineStart+=n;try{return t()}finally{this.lineStart-=n}},Kn.prototype.lookAhead=function(n){var t=this.lineOracle;return t&&t.lookAhead(n)},Kn.prototype.baseToken=function(){var n=this.lineOracle;return n&&n.baseToken(this.pos)};var dt=function(n,t){this.state=n,this.lookAhead=t},pt=function(n,t,e,a){this.state=t,this.doc=n,this.line=e,this.maxLookAhead=a||0,this.baseTokens=null,this.baseTokenPos=1};function ut(n,t,e,a){var o=[n.state.modeGen],r={};wt(n,t.text,n.doc.mode,e,(function(n,t){return o.push(n,t)}),r,a);for(var i=e.state,l=function(a){e.baseTokens=o;var l=n.state.overlays[a],s=1,c=0;e.state=!0,wt(n,t.text,l.mode,e,(function(n,t){for(var e=s;cn&&o.splice(s,1,n,o[s+1],a),s+=2,c=Math.min(n,a)}if(t)if(l.opaque)o.splice(e,s-e,n,"overlay "+t),s=e+2;else for(;en.options.maxHighlightLength&&Un(n.doc.mode,a.state),r=ut(n,t,a);o&&(a.state=o),t.stateAfter=a.save(!o),t.styles=r.styles,r.classes?t.styleClasses=r.classes:t.styleClasses&&(t.styleClasses=null),e===n.doc.highlightFrontier&&(n.doc.modeFrontier=Math.max(n.doc.modeFrontier,++n.doc.highlightFrontier))}return t.styles}function ft(n,t,e){var a=n.doc,o=n.display;if(!a.mode.startState)return new pt(a,!0,t);var r=function(n,t,e){for(var a,o,r=n.doc,i=e?-1:t-(n.doc.mode.innerMode?1e3:100),l=t;l>i;--l){if(l<=r.first)return r.first;var s=Gn(r,l-1),c=s.stateAfter;if(c&&(!e||l+(c instanceof dt?c.lookAhead:0)<=r.modeFrontier))return l;var d=N(s.text,null,n.options.tabSize);(null==o||a>d)&&(o=l-1,a=d)}return o}(n,t,e),i=r>a.first&&Gn(a,r-1).stateAfter,l=i?pt.fromSaved(a,i,r):new pt(a,qn(a.mode),r);return a.iter(r,t,(function(e){mt(n,e.text,l);var a=l.line;e.stateAfter=a==t-1||a%5==0||a>=o.viewFrom&&at.start)return r}throw new Error("Mode "+n.name+" failed to advance stream.")}pt.prototype.lookAhead=function(n){var t=this.doc.getLine(this.line+n);return null!=t&&n>this.maxLookAhead&&(this.maxLookAhead=n),t},pt.prototype.baseToken=function(n){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=n;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-n}},pt.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},pt.fromSaved=function(n,t,e){return t instanceof dt?new pt(n,Un(n.mode,t.state),e,t.lookAhead):new pt(n,Un(n.mode,t),e)},pt.prototype.save=function(n){var t=!1!==n?Un(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new dt(t,this.maxLookAhead):t};var xt=function(n,t,e){this.start=n.start,this.end=n.pos,this.string=n.current(),this.type=t||null,this.state=e};function vt(n,t,e,a){var o,r,i=n.doc,l=i.mode,s=Gn(i,(t=st(i,t)).line),c=ft(n,t.line,e),d=new Kn(s.text,n.options.tabSize,c);for(a&&(r=[]);(a||d.posn.options.maxHighlightLength?(l=!1,i&&mt(n,t,a,p.pos),p.pos=t.length,s=null):s=yt(gt(e,p,a.state,u),r),u){var b=u[0].name;b&&(s="m-"+(s?b+" "+s:b))}if(!l||d!=s){for(;c=t:r.to>t);(a||(a=[])).push(new _t(i,r.from,l?null:r.to))}}return a}(e,o,i),s=function(n,t,e){var a;if(n)for(var o=0;o=t:r.to>t)||r.from==t&&"bookmark"==i.type&&(!e||r.marker.insertLeft)){var l=null==r.from||(i.inclusiveLeft?r.from<=t:r.from0&&l)for(var v=0;vt)&&(!e||At(e,r.marker)<0)&&(e=r.marker)}return e}function Nt(n,t,e,a,o){var r=Gn(n,t),i=zt&&r.markedSpans;if(i)for(var l=0;l=0&&p<=0||d<=0&&p>=0)&&(d<=0&&(s.marker.inclusiveRight&&o.inclusiveLeft?et(c.to,e)>=0:et(c.to,e)>0)||d>=0&&(s.marker.inclusiveRight&&o.inclusiveLeft?et(c.from,a)<=0:et(c.from,a)<0)))return!0}}}function jt(n){for(var t;t=Tt(n);)n=t.find(-1,!0).line;return n}function Rt(n,t){var e=Gn(n,t),a=jt(e);return e==a?t:$n(a)}function Ht(n,t){if(t>n.lastLine())return t;var e,a=Gn(n,t);if(!Wt(n,a))return t;for(;e=It(a);)a=e.find(1,!0).line;return $n(a)+1}function Wt(n,t){var e=zt&&t.markedSpans;if(e)for(var a=void 0,o=0;ot.maxLineLength&&(t.maxLineLength=e,t.maxLine=n)}))}var Gt=function(n,t,e){this.text=n,Dt(this,t),this.height=e?e(this):1};function Vt(n){n.parent=null,Ot(n)}Gt.prototype.lineNo=function(){return $n(this)},vn(Gt);var Xt={},Zt={};function $t(n,t){if(!n||/^\s*$/.test(n))return null;var e=t.addModeClass?Zt:Xt;return e[n]||(e[n]=n.replace(/\S+/g,"cm-$&"))}function Qt(n,t){var e=D("span",null,null,s?"padding-right: .1px":null),a={pre:D("pre",[e],"CodeMirror-line"),content:e,col:0,pos:0,cm:n,trailingSpace:!1,splitSpaces:n.getOption("lineWrapping")};t.measure={};for(var o=0;o<=(t.rest?t.rest.length:0);o++){var r=o?t.rest[o-1]:t.line,i=void 0;a.pos=0,a.addToken=ne,Dn(n.display.measure)&&(i=dn(r,n.doc.direction))&&(a.addToken=te(a.addToken,i)),a.map=[],ae(r,a,bt(n,r,t!=n.display.externalMeasured&&$n(r))),r.styleClasses&&(r.styleClasses.bgClass&&(a.bgClass=L(r.styleClasses.bgClass,a.bgClass||"")),r.styleClasses.textClass&&(a.textClass=L(r.styleClasses.textClass,a.textClass||""))),0==a.map.length&&a.map.push(0,0,a.content.appendChild(On(n.display.measure))),0==o?(t.measure.map=a.map,t.measure.cache={}):((t.measure.maps||(t.measure.maps=[])).push(a.map),(t.measure.caches||(t.measure.caches=[])).push({}))}if(s){var l=a.content.lastChild;(/\bcm-tab\b/.test(l.className)||l.querySelector&&l.querySelector(".cm-tab"))&&(a.content.className="cm-tab-wrap-hack")}return mn(n,"renderLine",n,t.line,a.pre),a.pre.className&&(a.textClass=L(a.pre.className,a.textClass||"")),a}function Jt(n){var t=O("span","•","cm-invalidchar");return t.title="\\u"+n.charCodeAt(0).toString(16),t.setAttribute("aria-label",t.title),t}function ne(n,t,e,a,o,r,s){if(t){var c,d=n.splitSpaces?function(n,t){if(n.length>1&&!/ /.test(n))return n;for(var e=t,a="",o=0;oc&&p.from<=c);u++);if(p.to>=d)return n(e,a,o,r,i,l,s);n(e,a.slice(0,p.to-c),o,r,null,l,s),r=null,a=a.slice(p.to-c),c=p.to}}}function ee(n,t,e,a){var o=!a&&e.widgetNode;o&&n.map.push(n.pos,n.pos+t,o),!a&&n.cm.display.input.needsContentAttribute&&(o||(o=n.content.appendChild(document.createElement("span"))),o.setAttribute("cm-marker",e.id)),o&&(n.cm.display.input.setUneditable(o),n.content.appendChild(o)),n.pos+=t,n.trailingSpace=!1}function ae(n,t,e){var a=n.markedSpans,o=n.text,r=0;if(a)for(var i,l,s,c,d,p,u,b=o.length,f=0,m=1,h="",g=0;;){if(g==f){s=c=d=l="",u=null,p=null,g=1/0;for(var x=[],v=void 0,y=0;yf||k.collapsed&&w.to==f&&w.from==f)){if(null!=w.to&&w.to!=f&&g>w.to&&(g=w.to,c=""),k.className&&(s+=" "+k.className),k.css&&(l=(l?l+";":"")+k.css),k.startStyle&&w.from==f&&(d+=" "+k.startStyle),k.endStyle&&w.to==g&&(v||(v=[])).push(k.endStyle,w.to),k.title&&((u||(u={})).title=k.title),k.attributes)for(var z in k.attributes)(u||(u={}))[z]=k.attributes[z];k.collapsed&&(!p||At(p.marker,k)<0)&&(p=w)}else w.from>f&&g>w.from&&(g=w.from)}if(v)for(var _=0;_=b)break;for(var C=Math.min(b,g);;){if(h){var E=f+h.length;if(!p){var S=E>C?h.slice(0,C-f):h;t.addToken(t,S,i?i+s:s,d,f+S.length==g?c:"",l,u)}if(E>=C){h=h.slice(C-f),f=C;break}f=E,d=""}h=o.slice(r,r=e[m++]),i=$t(e[m++],t.cm.options)}}else for(var O=1;Oe)return{map:n.measure.maps[o],cache:n.measure.caches[o],before:!0}}function De(n,t,e,a){return Ae(n,Be(n,t),e,a)}function Me(n,t){if(t>=n.display.viewFrom&&t=e.lineN&&t2&&r.push((s.bottom+c.top)/2-e.top)}}r.push(e.bottom-e.top)}}(n,t.view,t.rect),t.hasHeights=!0),(r=function(n,t,e,a){var o,r=Ie(t.map,e,a),s=r.node,c=r.start,d=r.end,p=r.collapse;if(3==s.nodeType){for(var u=0;u<4;u++){for(;c&&an(t.line.text.charAt(r.coverStart+c));)--c;for(;r.coverStart+d1}(n))return t;var e=screen.logicalXDPI/screen.deviceXDPI,a=screen.logicalYDPI/screen.deviceYDPI;return{left:t.left*e,right:t.right*e,top:t.top*a,bottom:t.bottom*a}}(n.display.measure,o))}else{var b;c>0&&(p=a="right"),o=n.options.lineWrapping&&(b=s.getClientRects()).length>1?b["right"==a?b.length-1:0]:s.getBoundingClientRect()}if(i&&l<9&&!c&&(!o||!o.left&&!o.right)){var f=s.parentNode.getClientRects()[0];o=f?{left:f.left,right:f.left+oa(n.display),top:f.top,bottom:f.bottom}:Te}for(var m=o.top-t.rect.top,h=o.bottom-t.rect.top,g=(m+h)/2,x=t.view.measure.heights,v=0;vt)&&(o=(r=s-l)-1,t>=s&&(i="right")),null!=o){if(a=n[c+2],l==s&&e==(a.insertLeft?"left":"right")&&(i=e),"left"==e&&0==o)for(;c&&n[c-2]==n[c-3]&&n[c-1].insertLeft;)a=n[2+(c-=3)],i="left";if("right"==e&&o==s-l)for(;c=0&&(e=n[o]).left==e.right;o--);return e}function Ne(n){if(n.measure&&(n.measure.cache={},n.measure.heights=null,n.rest))for(var t=0;t=a.text.length?(s=a.text.length,c="before"):s<=0&&(s=0,c="after"),!l)return i("before"==c?s-1:s,"before"==c);function d(n,t,e){return i(e?n-1:n,1==l[t].level!=e)}var p=sn(l,s,c),u=ln,b=d(s,p,"before"==c);return null!=u&&(b.other=d(s,u,"before"!=c)),b}function Ve(n,t){var e=0;t=st(n.doc,t),n.options.lineWrapping||(e=oa(n.display)*t.ch);var a=Gn(n.doc,t.line),o=Yt(a)+ze(n.display);return{left:e,right:e,top:o,bottom:o+a.height}}function Xe(n,t,e,a,o){var r=tt(n,t,e);return r.xRel=o,a&&(r.outside=a),r}function Ze(n,t,e){var a=n.doc;if((e+=n.display.viewOffset)<0)return Xe(a.first,0,null,-1,-1);var o=Qn(a,e),r=a.first+a.size-1;if(o>r)return Xe(a.first+a.size-1,Gn(a,r).text.length,null,1,1);t<0&&(t=0);for(var i=Gn(a,o);;){var l=na(n,i,o,t,e),s=Pt(i,l.ch+(l.xRel>0||l.outside>0?1:0));if(!s)return l;var c=s.find(1);if(c.line==o)return c;i=Gn(a,o=c.line)}}function $e(n,t,e,a){a-=Ue(t);var o=t.text.length,r=rn((function(t){return Ae(n,e,t-1).bottom<=a}),o,0);return{begin:r,end:o=rn((function(t){return Ae(n,e,t).top>a}),r,o)}}function Qe(n,t,e,a){return e||(e=Be(n,t)),$e(n,t,e,Ye(n,t,Ae(n,e,a),"line").top)}function Je(n,t,e,a){return!(n.bottom<=e)&&(n.top>e||(a?n.left:n.right)>t)}function na(n,t,e,a,o){o-=Yt(t);var r=Be(n,t),i=Ue(t),l=0,s=t.text.length,c=!0,d=dn(t,n.doc.direction);if(d){var p=(n.options.lineWrapping?ea:ta)(n,t,e,r,d,a,o);l=(c=1!=p.level)?p.from:p.to-1,s=c?p.to:p.from-1}var u,b,f=null,m=null,h=rn((function(t){var e=Ae(n,r,t);return e.top+=i,e.bottom+=i,!!Je(e,a,o,!1)&&(e.top<=o&&e.left<=a&&(f=t,m=e),!0)}),l,s),g=!1;if(m){var x=a-m.left=y.bottom?1:0}return Xe(e,h=on(t.text,h,1),b,g,a-u)}function ta(n,t,e,a,o,r,i){var l=rn((function(l){var s=o[l],c=1!=s.level;return Je(Ge(n,tt(e,c?s.to:s.from,c?"before":"after"),"line",t,a),r,i,!0)}),0,o.length-1),s=o[l];if(l>0){var c=1!=s.level,d=Ge(n,tt(e,c?s.from:s.to,c?"after":"before"),"line",t,a);Je(d,r,i,!0)&&d.top>i&&(s=o[l-1])}return s}function ea(n,t,e,a,o,r,i){var l=$e(n,t,a,i),s=l.begin,c=l.end;/\s/.test(t.text.charAt(c-1))&&c--;for(var d=null,p=null,u=0;u=c||b.to<=s)){var f=Ae(n,a,1!=b.level?Math.min(c,b.to)-1:Math.max(s,b.from)).right,m=fm)&&(d=b,p=m)}}return d||(d=o[o.length-1]),d.fromc&&(d={from:d.from,to:c,level:d.level}),d}function aa(n){if(null!=n.cachedTextHeight)return n.cachedTextHeight;if(null==Le){Le=O("pre",null,"CodeMirror-line-like");for(var t=0;t<49;++t)Le.appendChild(document.createTextNode("x")),Le.appendChild(O("br"));Le.appendChild(document.createTextNode("x"))}S(n.measure,Le);var e=Le.offsetHeight/50;return e>3&&(n.cachedTextHeight=e),E(n.measure),e||1}function oa(n){if(null!=n.cachedCharWidth)return n.cachedCharWidth;var t=O("span","xxxxxxxxxx"),e=O("pre",[t],"CodeMirror-line-like");S(n.measure,e);var a=t.getBoundingClientRect(),o=(a.right-a.left)/10;return o>2&&(n.cachedCharWidth=o),o||10}function ra(n){for(var t=n.display,e={},a={},o=t.gutters.clientLeft,r=t.gutters.firstChild,i=0;r;r=r.nextSibling,++i){var l=n.display.gutterSpecs[i].className;e[l]=r.offsetLeft+r.clientLeft+o,a[l]=r.clientWidth}return{fixedPos:ia(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:e,gutterWidth:a,wrapperWidth:t.wrapper.clientWidth}}function ia(n){return n.scroller.getBoundingClientRect().left-n.sizer.getBoundingClientRect().left}function la(n){var t=aa(n.display),e=n.options.lineWrapping,a=e&&Math.max(5,n.display.scroller.clientWidth/oa(n.display)-3);return function(o){if(Wt(n.doc,o))return 0;var r=0;if(o.widgets)for(var i=0;i0&&(s=Gn(n.doc,c.line).text).length==c.ch){var d=N(s,s.length,n.options.tabSize)-s.length;c=tt(c.line,Math.max(0,Math.round((r-Fe(n.display).left)/oa(n.display))-d))}return c}function da(n,t){if(t>=n.display.viewTo)return null;if((t-=n.display.viewFrom)<0)return null;for(var e=n.display.view,a=0;at)&&(o.updateLineNumbers=t),n.curOp.viewChanged=!0,t>=o.viewTo)zt&&Rt(n.doc,t)o.viewFrom?ba(n):(o.viewFrom+=a,o.viewTo+=a);else if(t<=o.viewFrom&&e>=o.viewTo)ba(n);else if(t<=o.viewFrom){var r=fa(n,e,e+a,1);r?(o.view=o.view.slice(r.index),o.viewFrom=r.lineN,o.viewTo+=a):ba(n)}else if(e>=o.viewTo){var i=fa(n,t,t,-1);i?(o.view=o.view.slice(0,i.index),o.viewTo=i.lineN):ba(n)}else{var l=fa(n,t,t,-1),s=fa(n,e,e+a,1);l&&s?(o.view=o.view.slice(0,l.index).concat(re(n,l.lineN,s.lineN)).concat(o.view.slice(s.index)),o.viewTo+=a):ba(n)}var c=o.externalMeasured;c&&(e=o.lineN&&t=a.viewTo)){var r=a.view[da(n,t)];if(null!=r.node){var i=r.changes||(r.changes=[]);-1==R(i,e)&&i.push(e)}}}function ba(n){n.display.viewFrom=n.display.viewTo=n.doc.first,n.display.view=[],n.display.viewOffset=0}function fa(n,t,e,a){var o,r=da(n,t),i=n.display.view;if(!zt||e==n.doc.first+n.doc.size)return{index:r,lineN:e};for(var l=n.display.viewFrom,s=0;s0){if(r==i.length-1)return null;o=l+i[r].size-t,r++}else o=l-t;t+=o,e+=o}for(;Rt(n.doc,e)!=e;){if(r==(a<0?0:i.length-1))return null;e+=a*i[r-(a<0?1:0)].size,r+=a}return{index:r,lineN:e}}function ma(n){for(var t=n.display.view,e=0,a=0;a=n.display.viewTo||l.to().line0&&(o.style.width=r.right-r.left+"px")}if(a.other){var i=e.appendChild(O("div"," ","CodeMirror-cursor CodeMirror-secondarycursor"));i.style.display="",i.style.left=a.other.left+"px",i.style.top=a.other.top+"px",i.style.height=.85*(a.other.bottom-a.other.top)+"px"}}function va(n,t){return n.top-t.top||n.left-t.left}function ya(n,t,e){var a=n.display,o=n.doc,r=document.createDocumentFragment(),i=Fe(n.display),l=i.left,s=Math.max(a.sizerWidth,Ee(n)-a.sizer.offsetLeft)-i.right,c="ltr"==o.direction;function d(n,t,e,a){t<0&&(t=0),t=Math.round(t),a=Math.round(a),r.appendChild(O("div",null,"CodeMirror-selected","position: absolute; left: "+n+"px;\n top: "+t+"px; width: "+(null==e?s-n:e)+"px;\n height: "+(a-t)+"px"))}function p(t,e,a){var r,i,p=Gn(o,t),u=p.text.length;function b(e,a){return Ke(n,tt(t,e),"div",p,a)}function f(t,e,a){var o=Qe(n,p,null,t),r="ltr"==e==("after"==a)?"left":"right";return b("after"==a?o.begin:o.end-(/\s/.test(p.text.charAt(o.end-1))?2:1),r)[r]}var m=dn(p,o.direction);return function(n,t,e,a){if(!n)return a(t,e,"ltr",0);for(var o=!1,r=0;rt||t==e&&i.to==t)&&(a(Math.max(i.from,t),Math.min(i.to,e),1==i.level?"rtl":"ltr",r),o=!0)}o||a(t,e,"ltr")}(m,e||0,null==a?u:a,(function(n,t,o,p){var h="ltr"==o,g=b(n,h?"left":"right"),x=b(t-1,h?"right":"left"),v=null==e&&0==n,y=null==a&&t==u,w=0==p,k=!m||p==m.length-1;if(x.top-g.top<=3){var z=(c?y:v)&&k,_=(c?v:y)&&w?l:(h?g:x).left,F=z?s:(h?x:g).right;d(_,g.top,F-_,g.bottom)}else{var C,E,S,O;h?(C=c&&v&&w?l:g.left,E=c?s:f(n,o,"before"),S=c?l:f(t,o,"after"),O=c&&y&&k?s:x.right):(C=c?f(n,o,"before"):l,E=!c&&v&&w?s:g.right,S=!c&&y&&k?l:x.left,O=c?f(t,o,"after"):s),d(C,g.top,E-C,g.bottom),g.bottom0?t.blinker=setInterval((function(){n.hasFocus()||Fa(n),t.cursorDiv.style.visibility=(e=!e)?"":"hidden"}),n.options.cursorBlinkRate):n.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function ka(n){n.hasFocus()||(n.display.input.focus(),n.state.focused||_a(n))}function za(n){n.state.delayingBlurEvent=!0,setTimeout((function(){n.state.delayingBlurEvent&&(n.state.delayingBlurEvent=!1,n.state.focused&&Fa(n))}),100)}function _a(n,t){n.state.delayingBlurEvent&&!n.state.draggingText&&(n.state.delayingBlurEvent=!1),"nocursor"!=n.options.readOnly&&(n.state.focused||(mn(n,"focus",n,t),n.state.focused=!0,A(n.display.wrapper,"CodeMirror-focused"),n.curOp||n.display.selForContextMenu==n.doc.sel||(n.display.input.reset(),s&&setTimeout((function(){return n.display.input.reset(!0)}),20)),n.display.input.receivedFocus()),wa(n))}function Fa(n,t){n.state.delayingBlurEvent||(n.state.focused&&(mn(n,"blur",n,t),n.state.focused=!1,C(n.display.wrapper,"CodeMirror-focused")),clearInterval(n.display.blinker),setTimeout((function(){n.state.focused||(n.display.shift=!1)}),150))}function Ca(n){for(var t=n.display,e=t.lineDiv.offsetTop,a=Math.max(0,t.scroller.getBoundingClientRect().top),o=t.lineDiv.getBoundingClientRect().top,r=0,s=0;s.005||m<-.005)&&(on.display.sizerWidth){var g=Math.ceil(u/oa(n.display));g>n.display.maxLineLength&&(n.display.maxLineLength=g,n.display.maxLine=c.line,n.display.maxLineChanged=!0)}}}Math.abs(r)>2&&(t.scroller.scrollTop+=r)}function Ea(n){if(n.widgets)for(var t=0;t=i&&(r=Qn(t,Yt(Gn(t,s))-n.wrapper.clientHeight),i=s)}return{from:r,to:Math.max(i,r+1)}}function Oa(n,t){var e=n.display,a=aa(n.display);t.top<0&&(t.top=0);var o=n.curOp&&null!=n.curOp.scrollTop?n.curOp.scrollTop:e.scroller.scrollTop,r=Se(n),i={};t.bottom-t.top>r&&(t.bottom=t.top+r);var l=n.doc.height+_e(e),s=t.topl-a;if(t.topo+r){var d=Math.min(t.top,(c?l:t.bottom)-r);d!=o&&(i.scrollTop=d)}var p=n.options.fixedGutter?0:e.gutters.offsetWidth,u=n.curOp&&null!=n.curOp.scrollLeft?n.curOp.scrollLeft:e.scroller.scrollLeft-p,b=Ee(n)-e.gutters.offsetWidth,f=t.right-t.left>b;return f&&(t.right=t.left+b),t.left<10?i.scrollLeft=0:t.leftb+u-3&&(i.scrollLeft=t.right+(f?0:10)-b),i}function Da(n,t){null!=t&&(Aa(n),n.curOp.scrollTop=(null==n.curOp.scrollTop?n.doc.scrollTop:n.curOp.scrollTop)+t)}function Ma(n){Aa(n);var t=n.getCursor();n.curOp.scrollToPos={from:t,to:t,margin:n.options.cursorScrollMargin}}function Ba(n,t,e){null==t&&null==e||Aa(n),null!=t&&(n.curOp.scrollLeft=t),null!=e&&(n.curOp.scrollTop=e)}function Aa(n){var t=n.curOp.scrollToPos;t&&(n.curOp.scrollToPos=null,La(n,Ve(n,t.from),Ve(n,t.to),t.margin))}function La(n,t,e,a){var o=Oa(n,{left:Math.min(t.left,e.left),top:Math.min(t.top,e.top)-a,right:Math.max(t.right,e.right),bottom:Math.max(t.bottom,e.bottom)+a});Ba(n,o.scrollLeft,o.scrollTop)}function Ta(n,t){Math.abs(n.doc.scrollTop-t)<2||(e||so(n,{top:t}),Ia(n,t,!0),e&&so(n),ao(n,100))}function Ia(n,t,e){t=Math.max(0,Math.min(n.display.scroller.scrollHeight-n.display.scroller.clientHeight,t)),(n.display.scroller.scrollTop!=t||e)&&(n.doc.scrollTop=t,n.display.scrollbars.setScrollTop(t),n.display.scroller.scrollTop!=t&&(n.display.scroller.scrollTop=t))}function Pa(n,t,e,a){t=Math.max(0,Math.min(t,n.display.scroller.scrollWidth-n.display.scroller.clientWidth)),(e?t==n.doc.scrollLeft:Math.abs(n.doc.scrollLeft-t)<2)&&!a||(n.doc.scrollLeft=t,uo(n),n.display.scroller.scrollLeft!=t&&(n.display.scroller.scrollLeft=t),n.display.scrollbars.setScrollLeft(t))}function Na(n){var t=n.display,e=t.gutters.offsetWidth,a=Math.round(n.doc.height+_e(n.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:n.options.fixedGutter?e:0,docHeight:a,scrollHeight:a+Ce(n)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:e}}var ja=function(n,t,e){this.cm=e;var a=this.vert=O("div",[O("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),o=this.horiz=O("div",[O("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");a.tabIndex=o.tabIndex=-1,n(a),n(o),un(a,"scroll",(function(){a.clientHeight&&t(a.scrollTop,"vertical")})),un(o,"scroll",(function(){o.clientWidth&&t(o.scrollLeft,"horizontal")})),this.checkedZeroWidth=!1,i&&l<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};ja.prototype.update=function(n){var t=n.scrollWidth>n.clientWidth+1,e=n.scrollHeight>n.clientHeight+1,a=n.nativeBarWidth;if(e){this.vert.style.display="block",this.vert.style.bottom=t?a+"px":"0";var o=n.viewHeight-(t?a:0);this.vert.firstChild.style.height=Math.max(0,n.scrollHeight-n.clientHeight+o)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=e?a+"px":"0",this.horiz.style.left=n.barLeft+"px";var r=n.viewWidth-n.barLeft-(e?a:0);this.horiz.firstChild.style.width=Math.max(0,n.scrollWidth-n.clientWidth+r)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&n.clientHeight>0&&(0==a&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:e?a:0,bottom:t?a:0}},ja.prototype.setScrollLeft=function(n){this.horiz.scrollLeft!=n&&(this.horiz.scrollLeft=n),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},ja.prototype.setScrollTop=function(n){this.vert.scrollTop!=n&&(this.vert.scrollTop=n),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},ja.prototype.zeroWidthHack=function(){var n=x&&!b?"12px":"18px";this.horiz.style.height=this.vert.style.width=n,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new j,this.disableVert=new j},ja.prototype.enableZeroWidthBar=function(n,t,e){n.style.pointerEvents="auto",t.set(1e3,(function a(){var o=n.getBoundingClientRect();("vert"==e?document.elementFromPoint(o.right-1,(o.top+o.bottom)/2):document.elementFromPoint((o.right+o.left)/2,o.bottom-1))!=n?n.style.pointerEvents="none":t.set(1e3,a)}))},ja.prototype.clear=function(){var n=this.horiz.parentNode;n.removeChild(this.horiz),n.removeChild(this.vert)};var Ra=function(){};function Ha(n,t){t||(t=Na(n));var e=n.display.barWidth,a=n.display.barHeight;Wa(n,t);for(var o=0;o<4&&e!=n.display.barWidth||a!=n.display.barHeight;o++)e!=n.display.barWidth&&n.options.lineWrapping&&Ca(n),Wa(n,Na(n)),e=n.display.barWidth,a=n.display.barHeight}function Wa(n,t){var e=n.display,a=e.scrollbars.update(t);e.sizer.style.paddingRight=(e.barWidth=a.right)+"px",e.sizer.style.paddingBottom=(e.barHeight=a.bottom)+"px",e.heightForcer.style.borderBottom=a.bottom+"px solid transparent",a.right&&a.bottom?(e.scrollbarFiller.style.display="block",e.scrollbarFiller.style.height=a.bottom+"px",e.scrollbarFiller.style.width=a.right+"px"):e.scrollbarFiller.style.display="",a.bottom&&n.options.coverGutterNextToScrollbar&&n.options.fixedGutter?(e.gutterFiller.style.display="block",e.gutterFiller.style.height=a.bottom+"px",e.gutterFiller.style.width=t.gutterWidth+"px"):e.gutterFiller.style.display=""}Ra.prototype.update=function(){return{bottom:0,right:0}},Ra.prototype.setScrollLeft=function(){},Ra.prototype.setScrollTop=function(){},Ra.prototype.clear=function(){};var Ua={native:ja,null:Ra};function Ya(n){n.display.scrollbars&&(n.display.scrollbars.clear(),n.display.scrollbars.addClass&&C(n.display.wrapper,n.display.scrollbars.addClass)),n.display.scrollbars=new Ua[n.options.scrollbarStyle]((function(t){n.display.wrapper.insertBefore(t,n.display.scrollbarFiller),un(t,"mousedown",(function(){n.state.focused&&setTimeout((function(){return n.display.input.focus()}),0)})),t.setAttribute("cm-not-content","true")}),(function(t,e){"horizontal"==e?Pa(n,t):Ta(n,t)}),n),n.display.scrollbars.addClass&&A(n.display.wrapper,n.display.scrollbars.addClass)}var qa=0;function Ka(n){var t;n.curOp={cm:n,viewChanged:!1,startHeight:n.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++qa,markArrays:null},t=n.curOp,ie?ie.ops.push(t):t.ownsGroup=ie={ops:[t],delayedCallbacks:[]}}function Ga(n){var t=n.curOp;t&&function(n,t){var e=n.ownsGroup;if(e)try{!function(n){var t=n.delayedCallbacks,e=0;do{for(;e=e.viewTo)||e.maxLineChanged&&t.options.lineWrapping,n.update=n.mustUpdate&&new ro(t,n.mustUpdate&&{top:n.scrollTop,ensure:n.scrollToPos},n.forceUpdate)}function Xa(n){n.updatedDisplay=n.mustUpdate&&io(n.cm,n.update)}function Za(n){var t=n.cm,e=t.display;n.updatedDisplay&&Ca(t),n.barMeasure=Na(t),e.maxLineChanged&&!t.options.lineWrapping&&(n.adjustWidthTo=De(t,e.maxLine,e.maxLine.text.length).left+3,t.display.sizerWidth=n.adjustWidthTo,n.barMeasure.scrollWidth=Math.max(e.scroller.clientWidth,e.sizer.offsetLeft+n.adjustWidthTo+Ce(t)+t.display.barWidth),n.maxScrollLeft=Math.max(0,e.sizer.offsetLeft+n.adjustWidthTo-Ee(t))),(n.updatedDisplay||n.selectionChanged)&&(n.preparedSelection=e.input.prepareSelection())}function $a(n){var t=n.cm;null!=n.adjustWidthTo&&(t.display.sizer.style.minWidth=n.adjustWidthTo+"px",n.maxScrollLeft(window.innerHeight||document.documentElement.clientHeight)&&(o=!1),null!=o&&!f){var r=O("div","",null,"position: absolute;\n top: "+(t.top-e.viewOffset-ze(n.display))+"px;\n height: "+(t.bottom-t.top+Ce(n)+e.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");n.display.lineSpace.appendChild(r),r.scrollIntoView(o),n.display.lineSpace.removeChild(r)}}}(t,function(n,t,e,a){var o;null==a&&(a=0),n.options.lineWrapping||t!=e||(e="before"==t.sticky?tt(t.line,t.ch+1,"before"):t,t=t.ch?tt(t.line,"before"==t.sticky?t.ch-1:t.ch,"after"):t);for(var r=0;r<5;r++){var i=!1,l=Ge(n,t),s=e&&e!=t?Ge(n,e):l,c=Oa(n,o={left:Math.min(l.left,s.left),top:Math.min(l.top,s.top)-a,right:Math.max(l.left,s.left),bottom:Math.max(l.bottom,s.bottom)+a}),d=n.doc.scrollTop,p=n.doc.scrollLeft;if(null!=c.scrollTop&&(Ta(n,c.scrollTop),Math.abs(n.doc.scrollTop-d)>1&&(i=!0)),null!=c.scrollLeft&&(Pa(n,c.scrollLeft),Math.abs(n.doc.scrollLeft-p)>1&&(i=!0)),!i)break}return o}(t,st(a,n.scrollToPos.from),st(a,n.scrollToPos.to),n.scrollToPos.margin));var o=n.maybeHiddenMarkers,r=n.maybeUnhiddenMarkers;if(o)for(var i=0;i=n.display.viewTo)){var e=+new Date+n.options.workTime,a=ft(n,t.highlightFrontier),o=[];t.iter(a.line,Math.min(t.first+t.size,n.display.viewTo+500),(function(r){if(a.line>=n.display.viewFrom){var i=r.styles,l=r.text.length>n.options.maxHighlightLength?Un(t.mode,a.state):null,s=ut(n,r,a,!0);l&&(a.state=l),r.styles=s.styles;var c=r.styleClasses,d=s.classes;d?r.styleClasses=d:c&&(r.styleClasses=null);for(var p=!i||i.length!=r.styles.length||c!=d&&(!c||!d||c.bgClass!=d.bgClass||c.textClass!=d.textClass),u=0;!p&&ue)return ao(n,n.options.workDelay),!0})),t.highlightFrontier=a.line,t.modeFrontier=Math.max(t.modeFrontier,a.line),o.length&&Ja(n,(function(){for(var t=0;t=e.viewFrom&&t.visible.to<=e.viewTo&&(null==e.updateLineNumbers||e.updateLineNumbers>=e.viewTo)&&e.renderedView==e.view&&0==ma(n))return!1;bo(n)&&(ba(n),t.dims=ra(n));var o=a.first+a.size,r=Math.max(t.visible.from-n.options.viewportMargin,a.first),i=Math.min(o,t.visible.to+n.options.viewportMargin);e.viewFromi&&e.viewTo-i<20&&(i=Math.min(o,e.viewTo)),zt&&(r=Rt(n.doc,r),i=Ht(n.doc,i));var l=r!=e.viewFrom||i!=e.viewTo||e.lastWrapHeight!=t.wrapperHeight||e.lastWrapWidth!=t.wrapperWidth;!function(n,t,e){var a=n.display;0==a.view.length||t>=a.viewTo||e<=a.viewFrom?(a.view=re(n,t,e),a.viewFrom=t):(a.viewFrom>t?a.view=re(n,t,a.viewFrom).concat(a.view):a.viewFrome&&(a.view=a.view.slice(0,da(n,e)))),a.viewTo=e}(n,r,i),e.viewOffset=Yt(Gn(n.doc,e.viewFrom)),n.display.mover.style.top=e.viewOffset+"px";var c=ma(n);if(!l&&0==c&&!t.force&&e.renderedView==e.view&&(null==e.updateLineNumbers||e.updateLineNumbers>=e.viewTo))return!1;var d=function(n){if(n.hasFocus())return null;var t=B();if(!t||!M(n.display.lineDiv,t))return null;var e={activeElt:t};if(window.getSelection){var a=window.getSelection();a.anchorNode&&a.extend&&M(n.display.lineDiv,a.anchorNode)&&(e.anchorNode=a.anchorNode,e.anchorOffset=a.anchorOffset,e.focusNode=a.focusNode,e.focusOffset=a.focusOffset)}return e}(n);return c>4&&(e.lineDiv.style.display="none"),function(n,t,e){var a=n.display,o=n.options.lineNumbers,r=a.lineDiv,i=r.firstChild;function l(t){var e=t.nextSibling;return s&&x&&n.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),e}for(var c=a.view,d=a.viewFrom,p=0;p-1&&(b=!1),de(n,u,d,e)),b&&(E(u.lineNumber),u.lineNumber.appendChild(document.createTextNode(nt(n.options,d)))),i=u.node.nextSibling}else{var f=ge(n,u,d,e);r.insertBefore(f,i)}d+=u.size}for(;i;)i=l(i)}(n,e.updateLineNumbers,t.dims),c>4&&(e.lineDiv.style.display=""),e.renderedView=e.view,function(n){if(n&&n.activeElt&&n.activeElt!=B()&&(n.activeElt.focus(),!/^(INPUT|TEXTAREA)$/.test(n.activeElt.nodeName)&&n.anchorNode&&M(document.body,n.anchorNode)&&M(document.body,n.focusNode))){var t=window.getSelection(),e=document.createRange();e.setEnd(n.anchorNode,n.anchorOffset),e.collapse(!1),t.removeAllRanges(),t.addRange(e),t.extend(n.focusNode,n.focusOffset)}}(d),E(e.cursorDiv),E(e.selectionDiv),e.gutters.style.height=e.sizer.style.minHeight=0,l&&(e.lastWrapHeight=t.wrapperHeight,e.lastWrapWidth=t.wrapperWidth,ao(n,400)),e.updateLineNumbers=null,!0}function lo(n,t){for(var e=t.viewport,a=!0;;a=!1){if(a&&n.options.lineWrapping&&t.oldDisplayWidth!=Ee(n))a&&(t.visible=Sa(n.display,n.doc,e));else if(e&&null!=e.top&&(e={top:Math.min(n.doc.height+_e(n.display)-Se(n),e.top)}),t.visible=Sa(n.display,n.doc,e),t.visible.from>=n.display.viewFrom&&t.visible.to<=n.display.viewTo)break;if(!io(n,t))break;Ca(n);var o=Na(n);ha(n),Ha(n,o),po(n,o),t.force=!1}t.signal(n,"update",n),n.display.viewFrom==n.display.reportedViewFrom&&n.display.viewTo==n.display.reportedViewTo||(t.signal(n,"viewportChange",n,n.display.viewFrom,n.display.viewTo),n.display.reportedViewFrom=n.display.viewFrom,n.display.reportedViewTo=n.display.viewTo)}function so(n,t){var e=new ro(n,t);if(io(n,e)){Ca(n),lo(n,e);var a=Na(n);ha(n),Ha(n,a),po(n,a),e.finish()}}function co(n){var t=n.gutters.offsetWidth;n.sizer.style.marginLeft=t+"px",se(n,"gutterChanged",n)}function po(n,t){n.display.sizer.style.minHeight=t.docHeight+"px",n.display.heightForcer.style.top=t.docHeight+"px",n.display.gutters.style.height=t.docHeight+n.display.barHeight+Ce(n)+"px"}function uo(n){var t=n.display,e=t.view;if(t.alignWidgets||t.gutters.firstChild&&n.options.fixedGutter){for(var a=ia(t)-t.scroller.scrollLeft+n.doc.scrollLeft,o=t.gutters.offsetWidth,r=a+"px",i=0;ic.clientWidth,u=c.scrollHeight>c.clientHeight;if(o&&d||r&&u){if(r&&x&&s)n:for(var b=t.target,f=l.view;b!=c;b=b.parentNode)for(var m=0;m=0&&et(n,a.to())<=0)return e}return-1};var _o=function(n,t){this.anchor=n,this.head=t};function Fo(n,t,e){var a=n&&n.options.selectionsMayTouch,o=t[e];t.sort((function(n,t){return et(n.from(),t.from())})),e=R(t,o);for(var r=1;r0:s>=0){var c=it(l.from(),i.from()),d=rt(l.to(),i.to()),p=l.empty()?i.from()==i.head:l.from()==l.head;r<=e&&--e,t.splice(--r,2,new _o(p?d:c,p?c:d))}}return new zo(t,e)}function Co(n,t){return new zo([new _o(n,t||n)],0)}function Eo(n){return n.text?tt(n.from.line+n.text.length-1,V(n.text).length+(1==n.text.length?n.from.ch:0)):n.to}function So(n,t){if(et(n,t.from)<0)return n;if(et(n,t.to)<=0)return Eo(t);var e=n.line+t.text.length-(t.to.line-t.from.line)-1,a=n.ch;return n.line==t.to.line&&(a+=Eo(t).ch-t.to.ch),tt(e,a)}function Oo(n,t){for(var e=[],a=0;a1&&n.remove(l.line+1,f-1),n.insert(l.line+1,g)}se(n,"change",n,t)}function To(n,t,e){!function n(a,o,r){if(a.linked)for(var i=0;il-(n.cm?n.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(r=function(n,t){return t?(Ro(n.done),V(n.done)):n.done.length&&!V(n.done).ranges?V(n.done):n.done.length>1&&!n.done[n.done.length-2].ranges?(n.done.pop(),V(n.done)):void 0}(o,o.lastOp==a)))i=V(r.changes),0==et(t.from,t.to)&&0==et(t.from,i.to)?i.to=Eo(t):r.changes.push(jo(n,t));else{var s=V(o.done);for(s&&s.ranges||Uo(n.sel,o.done),r={changes:[jo(n,t)],generation:o.generation},o.done.push(r);o.done.length>o.undoDepth;)o.done.shift(),o.done[0].ranges||o.done.shift()}o.done.push(e),o.generation=++o.maxGeneration,o.lastModTime=o.lastSelTime=l,o.lastOp=o.lastSelOp=a,o.lastOrigin=o.lastSelOrigin=t.origin,i||mn(n,"historyAdded")}function Wo(n,t,e,a){var o=n.history,r=a&&a.origin;e==o.lastSelOp||r&&o.lastSelOrigin==r&&(o.lastModTime==o.lastSelTime&&o.lastOrigin==r||function(n,t,e,a){var o=t.charAt(0);return"*"==o||"+"==o&&e.ranges.length==a.ranges.length&&e.somethingSelected()==a.somethingSelected()&&new Date-n.history.lastSelTime<=(n.cm?n.cm.options.historyEventDelay:500)}(n,r,V(o.done),t))?o.done[o.done.length-1]=t:Uo(t,o.done),o.lastSelTime=+new Date,o.lastSelOrigin=r,o.lastSelOp=e,a&&!1!==a.clearRedo&&Ro(o.undone)}function Uo(n,t){var e=V(t);e&&e.ranges&&e.equals(n)||t.push(n)}function Yo(n,t,e,a){var o=t["spans_"+n.id],r=0;n.iter(Math.max(n.first,e),Math.min(n.first+n.size,a),(function(e){e.markedSpans&&((o||(o=t["spans_"+n.id]={}))[r]=e.markedSpans),++r}))}function qo(n){if(!n)return null;for(var t,e=0;e-1&&(V(l)[p]=c[p],delete c[p])}}}return a}function Vo(n,t,e,a){if(a){var o=n.anchor;if(e){var r=et(t,o)<0;r!=et(e,o)<0?(o=t,t=e):r!=et(t,e)<0&&(t=e)}return new _o(o,t)}return new _o(e||t,t)}function Xo(n,t,e,a,o){null==o&&(o=n.cm&&(n.cm.display.shift||n.extend)),nr(n,new zo([Vo(n.sel.primary(),t,e,o)],0),a)}function Zo(n,t,e){for(var a=[],o=n.cm&&(n.cm.display.shift||n.extend),r=0;r=t.ch:l.to>t.ch))){if(o&&(mn(s,"beforeCursorEnter"),s.explicitlyCleared)){if(r.markedSpans){--i;continue}break}if(!s.atomic)continue;if(e){var p=s.find(a<0?1:-1),u=void 0;if((a<0?d:c)&&(p=lr(n,p,-a,p&&p.line==t.line?r:null)),p&&p.line==t.line&&(u=et(p,e))&&(a<0?u<0:u>0))return rr(n,p,t,a,o)}var b=s.find(a<0?-1:1);return(a<0?c:d)&&(b=lr(n,b,a,b.line==t.line?r:null)),b?rr(n,b,t,a,o):null}}return t}function ir(n,t,e,a,o){var r=a||1,i=rr(n,t,e,r,o)||!o&&rr(n,t,e,r,!0)||rr(n,t,e,-r,o)||!o&&rr(n,t,e,-r,!0);return i||(n.cantEdit=!0,tt(n.first,0))}function lr(n,t,e,a){return e<0&&0==t.ch?t.line>n.first?st(n,tt(t.line-1)):null:e>0&&t.ch==(a||Gn(n,t.line)).text.length?t.line0)){var d=[s,1],p=et(c.from,l.from),u=et(c.to,l.to);(p<0||!i.inclusiveLeft&&!p)&&d.push({from:c.from,to:l.from}),(u>0||!i.inclusiveRight&&!u)&&d.push({from:l.to,to:c.to}),o.splice.apply(o,d),s+=d.length-3}}return o}(n,t.from,t.to);if(a)for(var o=a.length-1;o>=0;--o)pr(n,{from:a[o].from,to:a[o].to,text:o?[""]:t.text,origin:t.origin});else pr(n,t)}}function pr(n,t){if(1!=t.text.length||""!=t.text[0]||0!=et(t.from,t.to)){var e=Oo(n,t);Ho(n,t,e,n.cm?n.cm.curOp.id:NaN),fr(n,t,e,Et(n,t));var a=[];To(n,(function(n,e){e||-1!=R(a,n.history)||(xr(n.history,t),a.push(n.history)),fr(n,t,null,Et(n,t))}))}}function ur(n,t,e){var a=n.cm&&n.cm.state.suppressEdits;if(!a||e){for(var o,r=n.history,i=n.sel,l="undo"==t?r.done:r.undone,s="undo"==t?r.undone:r.done,c=0;c=0;--b){var f=u(b);if(f)return f.v}}}}function br(n,t){if(0!=t&&(n.first+=t,n.sel=new zo(X(n.sel.ranges,(function(n){return new _o(tt(n.anchor.line+t,n.anchor.ch),tt(n.head.line+t,n.head.ch))})),n.sel.primIndex),n.cm)){pa(n.cm,n.first,n.first-t,t);for(var e=n.cm.display,a=e.viewFrom;an.lastLine())){if(t.from.liner&&(t={from:t.from,to:tt(r,Gn(n,r).text.length),text:[t.text[0]],origin:t.origin}),t.removed=Vn(n,t.from,t.to),e||(e=Oo(n,t)),n.cm?function(n,t,e){var a=n.doc,o=n.display,r=t.from,i=t.to,l=!1,s=r.line;n.options.lineWrapping||(s=$n(jt(Gn(a,r.line))),a.iter(s,i.line+1,(function(n){if(n==o.maxLine)return l=!0,!0}))),a.sel.contains(t.from,t.to)>-1&&gn(n),Lo(a,t,e,la(n)),n.options.lineWrapping||(a.iter(s,r.line+t.text.length,(function(n){var t=qt(n);t>o.maxLineLength&&(o.maxLine=n,o.maxLineLength=t,o.maxLineChanged=!0,l=!1)})),l&&(n.curOp.updateMaxLine=!0)),function(n,t){if(n.modeFrontier=Math.min(n.modeFrontier,t),!(n.highlightFrontiere;a--){var o=Gn(n,a).stateAfter;if(o&&(!(o instanceof dt)||a+o.lookAhead1||!(this.children[0]instanceof yr))){var l=[];this.collapse(l),this.children=[new yr(l)],this.children[0].parent=this}},collapse:function(n){for(var t=0;t50){for(var i=o.lines.length%25+25,l=i;l10);n.parent.maybeSpill()}},iterN:function(n,t,e){for(var a=0;a0||0==i&&!1!==r.clearWhenEmpty)return r;if(r.replacedWith&&(r.collapsed=!0,r.widgetNode=D("span",[r.replacedWith],"CodeMirror-widget"),a.handleMouseEvents||r.widgetNode.setAttribute("cm-ignore-events","true"),a.insertLeft&&(r.widgetNode.insertLeft=!0)),r.collapsed){if(Nt(n,t.line,t,e,r)||t.line!=e.line&&Nt(n,e.line,t,e,r))throw new Error("Inserting collapsed marker partially overlapping an existing one");zt=!0}r.addToHistory&&Ho(n,{from:t,to:e,origin:"markText"},n.sel,NaN);var l,s=t.line,c=n.cm;if(n.iter(s,e.line+1,(function(a){c&&r.collapsed&&!c.options.lineWrapping&&jt(a)==c.display.maxLine&&(l=!0),r.collapsed&&s!=t.line&&Zn(a,0),function(n,t,e){var a=e&&window.WeakSet&&(e.markedSpans||(e.markedSpans=new WeakSet));a&&a.has(n.markedSpans)?n.markedSpans.push(t):(n.markedSpans=n.markedSpans?n.markedSpans.concat([t]):[t],a&&a.add(n.markedSpans)),t.marker.attachLine(n)}(a,new _t(r,s==t.line?t.ch:null,s==e.line?e.ch:null),n.cm&&n.cm.curOp),++s})),r.collapsed&&n.iter(t.line,e.line+1,(function(t){Wt(n,t)&&Zn(t,0)})),r.clearOnEnter&&un(r,"beforeCursorEnter",(function(){return r.clear()})),r.readOnly&&(kt=!0,(n.history.done.length||n.history.undone.length)&&n.clearHistory()),r.collapsed&&(r.id=++_r,r.atomic=!0),c){if(l&&(c.curOp.updateMaxLine=!0),r.collapsed)pa(c,t.line,e.line+1);else if(r.className||r.startStyle||r.endStyle||r.css||r.attributes||r.title)for(var d=t.line;d<=e.line;d++)ua(c,d,"text");r.atomic&&ar(c.doc),se(c,"markerAdded",c,r)}return r}Fr.prototype.clear=function(){if(!this.explicitlyCleared){var n=this.doc.cm,t=n&&!n.curOp;if(t&&Ka(n),xn(this,"clear")){var e=this.find();e&&se(this,"clear",e.from,e.to)}for(var a=null,o=null,r=0;rn.display.maxLineLength&&(n.display.maxLine=c,n.display.maxLineLength=d,n.display.maxLineChanged=!0)}null!=a&&n&&this.collapsed&&pa(n,a,o+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,n&&ar(n.doc)),n&&se(n,"markerCleared",n,this,a,o),t&&Ga(n),this.parent&&this.parent.clear()}},Fr.prototype.find=function(n,t){var e,a;null==n&&"bookmark"==this.type&&(n=1);for(var o=0;o=0;s--)dr(this,a[s]);l?Jo(this,l):this.cm&&Ma(this.cm)})),undo:eo((function(){ur(this,"undo")})),redo:eo((function(){ur(this,"redo")})),undoSelection:eo((function(){ur(this,"undo",!0)})),redoSelection:eo((function(){ur(this,"redo",!0)})),setExtending:function(n){this.extend=n},getExtending:function(){return this.extend},historySize:function(){for(var n=this.history,t=0,e=0,a=0;a=n.ch)&&t.push(o.marker.parent||o.marker)}return t},findMarks:function(n,t,e){n=st(this,n),t=st(this,t);var a=[],o=n.line;return this.iter(n.line,t.line+1,(function(r){var i=r.markedSpans;if(i)for(var l=0;l=s.to||null==s.from&&o!=n.line||null!=s.from&&o==t.line&&s.from>=t.ch||e&&!e(s.marker)||a.push(s.marker.parent||s.marker)}++o})),a},getAllMarks:function(){var n=[];return this.iter((function(t){var e=t.markedSpans;if(e)for(var a=0;an)return t=n,!0;n-=r,++e})),st(this,tt(e,t))},indexFromPos:function(n){var t=(n=st(this,n)).ch;if(n.linet&&(t=n.from),null!=n.to&&n.to-1)return t.state.draggingText(n),void setTimeout((function(){return t.display.input.focus()}),20);try{var p=n.dataTransfer.getData("Text");if(p){var u;if(t.state.draggingText&&!t.state.draggingText.copy&&(u=t.listSelections()),tr(t.doc,Co(e,e)),u)for(var b=0;b=0;t--)mr(n.doc,"",a[t].from,a[t].to,"+delete");Ma(n)}))}function Qr(n,t,e){var a=on(n.text,t+e,e);return a<0||a>n.text.length?null:a}function Jr(n,t,e){var a=Qr(n,t.ch,e);return null==a?null:new tt(t.line,a,e<0?"after":"before")}function ni(n,t,e,a,o){if(n){"rtl"==t.doc.direction&&(o=-o);var r=dn(e,t.doc.direction);if(r){var i,l=o<0?V(r):r[0],s=o<0==(1==l.level)?"after":"before";if(l.level>0||"rtl"==t.doc.direction){var c=Be(t,e);i=o<0?e.text.length-1:0;var d=Ae(t,c,i).top;i=rn((function(n){return Ae(t,c,n).top==d}),o<0==(1==l.level)?l.from:l.to-1,i),"before"==s&&(i=Qr(e,i,1))}else i=o<0?l.to:l.from;return new tt(a,i,s)}}return new tt(a,o<0?e.text.length:0,o<0?"before":"after")}Ur.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},Ur.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},Ur.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},Ur.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},Ur.default=x?Ur.macDefault:Ur.pcDefault;var ti={selectAll:sr,singleSelection:function(n){return n.setSelection(n.getCursor("anchor"),n.getCursor("head"),W)},killLine:function(n){return $r(n,(function(t){if(t.empty()){var e=Gn(n.doc,t.head.line).text.length;return t.head.ch==e&&t.head.line0)o=new tt(o.line,o.ch+1),n.replaceRange(r.charAt(o.ch-1)+r.charAt(o.ch-2),tt(o.line,o.ch-2),o,"+transpose");else if(o.line>n.doc.first){var i=Gn(n.doc,o.line-1).text;i&&(o=new tt(o.line,1),n.replaceRange(r.charAt(0)+n.doc.lineSeparator()+i.charAt(i.length-1),tt(o.line-1,i.length-1),o,"+transpose"))}e.push(new _o(o,o))}n.setSelections(e)}))},newlineAndIndent:function(n){return Ja(n,(function(){for(var t=n.listSelections(),e=t.length-1;e>=0;e--)n.replaceRange(n.doc.lineSeparator(),t[e].anchor,t[e].head,"+input");t=n.listSelections();for(var a=0;a-1&&(et((o=c.ranges[o]).from(),t)<0||t.xRel>0)&&(et(o.to(),t)>0||t.xRel<0)?function(n,t,e,a){var o=n.display,r=!1,c=no(n,(function(t){s&&(o.scroller.draggable=!1),n.state.draggingText=!1,n.state.delayingBlurEvent&&(n.hasFocus()?n.state.delayingBlurEvent=!1:za(n)),fn(o.wrapper.ownerDocument,"mouseup",c),fn(o.wrapper.ownerDocument,"mousemove",d),fn(o.scroller,"dragstart",p),fn(o.scroller,"drop",c),r||(yn(t),a.addNew||Xo(n.doc,e,null,null,a.extend),s&&!u||i&&9==l?setTimeout((function(){o.wrapper.ownerDocument.body.focus({preventScroll:!0}),o.input.focus()}),20):o.input.focus())})),d=function(n){r=r||Math.abs(t.clientX-n.clientX)+Math.abs(t.clientY-n.clientY)>=10},p=function(){return r=!0};s&&(o.scroller.draggable=!0),n.state.draggingText=c,c.copy=!a.moveOnDrag,un(o.wrapper.ownerDocument,"mouseup",c),un(o.wrapper.ownerDocument,"mousemove",d),un(o.scroller,"dragstart",p),un(o.scroller,"drop",c),n.state.delayingBlurEvent=!0,setTimeout((function(){return o.input.focus()}),20),o.scroller.dragDrop&&o.scroller.dragDrop()}(n,a,t,r):function(n,t,e,a){i&&za(n);var o=n.display,r=n.doc;yn(t);var l,s,c=r.sel,d=c.ranges;if(a.addNew&&!a.extend?(s=r.sel.contains(e),l=s>-1?d[s]:new _o(e,e)):(l=r.sel.primary(),s=r.sel.primIndex),"rectangle"==a.unit)a.addNew||(l=new _o(e,e)),e=ca(n,t,!0,!0),s=-1;else{var p=gi(n,e,a.unit);l=a.extend?Vo(l,p.anchor,p.head,a.extend):p}a.addNew?-1==s?(s=d.length,nr(r,Fo(n,d.concat([l]),s),{scroll:!1,origin:"*mouse"})):d.length>1&&d[s].empty()&&"char"==a.unit&&!a.extend?(nr(r,Fo(n,d.slice(0,s).concat(d.slice(s+1)),0),{scroll:!1,origin:"*mouse"}),c=r.sel):$o(r,s,l,U):(s=0,nr(r,new zo([l],0),U),c=r.sel);var u=e;function b(t){if(0!=et(u,t))if(u=t,"rectangle"==a.unit){for(var o=[],i=n.options.tabSize,d=N(Gn(r,e.line).text,e.ch,i),p=N(Gn(r,t.line).text,t.ch,i),b=Math.min(d,p),f=Math.max(d,p),m=Math.min(e.line,t.line),h=Math.min(n.lastLine(),Math.max(e.line,t.line));m<=h;m++){var g=Gn(r,m).text,x=q(g,b,i);b==f?o.push(new _o(tt(m,x),tt(m,x))):g.length>x&&o.push(new _o(tt(m,x),tt(m,q(g,f,i))))}o.length||o.push(new _o(e,e)),nr(r,Fo(n,c.ranges.slice(0,s).concat(o),s),{origin:"*mouse",scroll:!1}),n.scrollIntoView(t)}else{var v,y=l,w=gi(n,t,a.unit),k=y.anchor;et(w.anchor,k)>0?(v=w.head,k=it(y.from(),w.anchor)):(v=w.anchor,k=rt(y.to(),w.head));var z=c.ranges.slice(0);z[s]=function(n,t){var e=t.anchor,a=t.head,o=Gn(n.doc,e.line);if(0==et(e,a)&&e.sticky==a.sticky)return t;var r=dn(o);if(!r)return t;var i=sn(r,e.ch,e.sticky),l=r[i];if(l.from!=e.ch&&l.to!=e.ch)return t;var s,c=i+(l.from==e.ch==(1!=l.level)?0:1);if(0==c||c==r.length)return t;if(a.line!=e.line)s=(a.line-e.line)*("ltr"==n.doc.direction?1:-1)>0;else{var d=sn(r,a.ch,a.sticky),p=d-i||(a.ch-e.ch)*(1==l.level?-1:1);s=d==c-1||d==c?p<0:p>0}var u=r[c+(s?-1:0)],b=s==(1==u.level),f=b?u.from:u.to,m=b?"after":"before";return e.ch==f&&e.sticky==m?t:new _o(new tt(e.line,f,m),a)}(n,new _o(st(r,k),v)),nr(r,Fo(n,z,s),U)}}var f=o.wrapper.getBoundingClientRect(),m=0;function h(t){n.state.selectingText=!1,m=1/0,t&&(yn(t),o.input.focus()),fn(o.wrapper.ownerDocument,"mousemove",g),fn(o.wrapper.ownerDocument,"mouseup",x),r.history.lastSelOrigin=null}var g=no(n,(function(t){0!==t.buttons&&Fn(t)?function t(e){var i=++m,l=ca(n,e,!0,"rectangle"==a.unit);if(l)if(0!=et(l,u)){n.curOp.focus=B(),b(l);var s=Sa(o,r);(l.line>=s.to||l.linef.bottom?20:0;c&&setTimeout(no(n,(function(){m==i&&(o.scroller.scrollTop+=c,t(e))})),50)}}(t):h(t)})),x=no(n,h);n.state.selectingText=x,un(o.wrapper.ownerDocument,"mousemove",g),un(o.wrapper.ownerDocument,"mouseup",x)}(n,a,t,r)}(t,a,r,n):_n(n)==e.scroller&&yn(n):2==o?(a&&Xo(t.doc,a),setTimeout((function(){return e.input.focus()}),20)):3==o&&(z?t.display.input.onContextMenu(n):za(t)))}}function gi(n,t,e){if("char"==e)return new _o(t,t);if("word"==e)return n.findWordAt(t);if("line"==e)return new _o(tt(t.line,0),st(n.doc,tt(t.line+1,0)));var a=e(n,t);return new _o(a.from,a.to)}function xi(n,t,e,a){var o,r;if(t.touches)o=t.touches[0].clientX,r=t.touches[0].clientY;else try{o=t.clientX,r=t.clientY}catch(n){return!1}if(o>=Math.floor(n.display.gutters.getBoundingClientRect().right))return!1;a&&yn(t);var i=n.display,l=i.lineDiv.getBoundingClientRect();if(r>l.bottom||!xn(n,e))return kn(t);r-=l.top-i.viewOffset;for(var s=0;s=o)return mn(n,e,n,Qn(n.doc,r),n.display.gutterSpecs[s].className,t),kn(t)}}function vi(n,t){return xi(n,t,"gutterClick",!0)}function yi(n,t){ke(n.display,t)||function(n,t){return!!xn(n,"gutterContextMenu")&&xi(n,t,"gutterContextMenu",!1)}(n,t)||hn(n,t,"contextmenu")||z||n.display.input.onContextMenu(t)}function wi(n){n.display.wrapper.className=n.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+n.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Re(n)}mi.prototype.compare=function(n,t,e){return this.time+400>n&&0==et(t,this.pos)&&e==this.button};var ki={toString:function(){return"CodeMirror.Init"}},zi={},_i={};function Fi(n,t,e){if(!t!=!(e&&e!=ki)){var a=n.display.dragFunctions,o=t?un:fn;o(n.display.scroller,"dragstart",a.start),o(n.display.scroller,"dragenter",a.enter),o(n.display.scroller,"dragover",a.over),o(n.display.scroller,"dragleave",a.leave),o(n.display.scroller,"drop",a.drop)}}function Ci(n){n.options.lineWrapping?(A(n.display.wrapper,"CodeMirror-wrap"),n.display.sizer.style.minWidth="",n.display.sizerWidth=null):(C(n.display.wrapper,"CodeMirror-wrap"),Kt(n)),sa(n),pa(n),Re(n),setTimeout((function(){return Ha(n)}),100)}function Ei(n,t){var e=this;if(!(this instanceof Ei))return new Ei(n,t);this.options=t=t?P(t):{},P(zi,t,!1);var a=t.value;"string"==typeof a?a=new Mr(a,t.mode,null,t.lineSeparator,t.direction):t.mode&&(a.modeOption=t.mode),this.doc=a;var o=new Ei.inputStyles[t.inputStyle](this),r=this.display=new go(n,a,o,t);for(var c in r.wrapper.CodeMirror=this,wi(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),Ya(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new j,keySeq:null,specialChars:null},t.autofocus&&!g&&r.input.focus(),i&&l<11&&setTimeout((function(){return e.display.input.reset(!0)}),20),function(n){var t=n.display;un(t.scroller,"mousedown",no(n,hi)),un(t.scroller,"dblclick",i&&l<11?no(n,(function(t){if(!hn(n,t)){var e=ca(n,t);if(e&&!vi(n,t)&&!ke(n.display,t)){yn(t);var a=n.findWordAt(e);Xo(n.doc,a.anchor,a.head)}}})):function(t){return hn(n,t)||yn(t)}),un(t.scroller,"contextmenu",(function(t){return yi(n,t)})),un(t.input.getField(),"contextmenu",(function(e){t.scroller.contains(e.target)||yi(n,e)}));var e,a={end:0};function o(){t.activeTouch&&(e=setTimeout((function(){return t.activeTouch=null}),1e3),(a=t.activeTouch).end=+new Date)}function r(n,t){if(null==t.left)return!0;var e=t.left-n.left,a=t.top-n.top;return e*e+a*a>400}un(t.scroller,"touchstart",(function(o){if(!hn(n,o)&&!function(n){if(1!=n.touches.length)return!1;var t=n.touches[0];return t.radiusX<=1&&t.radiusY<=1}(o)&&!vi(n,o)){t.input.ensurePolled(),clearTimeout(e);var r=+new Date;t.activeTouch={start:r,moved:!1,prev:r-a.end<=300?a:null},1==o.touches.length&&(t.activeTouch.left=o.touches[0].pageX,t.activeTouch.top=o.touches[0].pageY)}})),un(t.scroller,"touchmove",(function(){t.activeTouch&&(t.activeTouch.moved=!0)})),un(t.scroller,"touchend",(function(e){var a=t.activeTouch;if(a&&!ke(t,e)&&null!=a.left&&!a.moved&&new Date-a.start<300){var i,l=n.coordsChar(t.activeTouch,"page");i=!a.prev||r(a,a.prev)?new _o(l,l):!a.prev.prev||r(a,a.prev.prev)?n.findWordAt(l):new _o(tt(l.line,0),st(n.doc,tt(l.line+1,0))),n.setSelection(i.anchor,i.head),n.focus(),yn(e)}o()})),un(t.scroller,"touchcancel",o),un(t.scroller,"scroll",(function(){t.scroller.clientHeight&&(Ta(n,t.scroller.scrollTop),Pa(n,t.scroller.scrollLeft,!0),mn(n,"scroll",n))})),un(t.scroller,"mousewheel",(function(t){return ko(n,t)})),un(t.scroller,"DOMMouseScroll",(function(t){return ko(n,t)})),un(t.wrapper,"scroll",(function(){return t.wrapper.scrollTop=t.wrapper.scrollLeft=0})),t.dragFunctions={enter:function(t){hn(n,t)||zn(t)},over:function(t){hn(n,t)||(function(n,t){var e=ca(n,t);if(e){var a=document.createDocumentFragment();xa(n,e,a),n.display.dragCursor||(n.display.dragCursor=O("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),n.display.lineSpace.insertBefore(n.display.dragCursor,n.display.cursorDiv)),S(n.display.dragCursor,a)}}(n,t),zn(t))},start:function(t){return function(n,t){if(i&&(!n.state.draggingText||+new Date-Br<100))zn(t);else if(!hn(n,t)&&!ke(n.display,t)&&(t.dataTransfer.setData("Text",n.getSelection()),t.dataTransfer.effectAllowed="copyMove",t.dataTransfer.setDragImage&&!u)){var e=O("img",null,null,"position: fixed; left: 0; top: 0;");e.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",p&&(e.width=e.height=1,n.display.wrapper.appendChild(e),e._top=e.offsetTop),t.dataTransfer.setDragImage(e,0,0),p&&e.parentNode.removeChild(e)}}(n,t)},drop:no(n,Ar),leave:function(t){hn(n,t)||Lr(n)}};var s=t.input.getField();un(s,"keyup",(function(t){return pi.call(n,t)})),un(s,"keydown",no(n,di)),un(s,"keypress",no(n,ui)),un(s,"focus",(function(t){return _a(n,t)})),un(s,"blur",(function(t){return Fa(n,t)}))}(this),Pr(),Ka(this),this.curOp.forceUpdate=!0,Io(this,a),t.autofocus&&!g||this.hasFocus()?setTimeout((function(){e.hasFocus()&&!e.state.focused&&_a(e)}),20):Fa(this),_i)_i.hasOwnProperty(c)&&_i[c](this,t[c],ki);bo(this),t.finishInit&&t.finishInit(this);for(var d=0;d150)){if(!a)return;e="prev"}}else c=0,e="not";"prev"==e?c=t>r.first?N(Gn(r,t-1).text,null,i):0:"add"==e?c=s+n.options.indentUnit:"subtract"==e?c=s-n.options.indentUnit:"number"==typeof e&&(c=s+e),c=Math.max(0,c);var p="",u=0;if(n.options.indentWithTabs)for(var b=Math.floor(c/i);b;--b)u+=i,p+="\t";if(ui,s=Bn(t),c=null;if(l&&a.ranges.length>1)if(Di&&Di.text.join("\n")==t){if(a.ranges.length%Di.text.length==0){c=[];for(var d=0;d=0;u--){var b=a.ranges[u],f=b.from(),m=b.to();b.empty()&&(e&&e>0?f=tt(f.line,f.ch-e):n.state.overwrite&&!l?m=tt(m.line,Math.min(Gn(r,m.line).text.length,m.ch+V(s).length)):l&&Di&&Di.lineWise&&Di.text.join("\n")==s.join("\n")&&(f=m=tt(f.line,0)));var h={from:f,to:m,text:c?c[u%c.length]:s,origin:o||(l?"paste":n.state.cutIncoming>i?"cut":"+input")};dr(n.doc,h),se(n,"inputRead",n,h)}t&&!l&&Li(n,t),Ma(n),n.curOp.updateInput<2&&(n.curOp.updateInput=p),n.curOp.typing=!0,n.state.pasteIncoming=n.state.cutIncoming=-1}function Ai(n,t){var e=n.clipboardData&&n.clipboardData.getData("Text");if(e)return n.preventDefault(),t.isReadOnly()||t.options.disableInput||Ja(t,(function(){return Bi(t,e,0,null,"paste")})),!0}function Li(n,t){if(n.options.electricChars&&n.options.smartIndent)for(var e=n.doc.sel,a=e.ranges.length-1;a>=0;a--){var o=e.ranges[a];if(!(o.head.ch>100||a&&e.ranges[a-1].head.line==o.head.line)){var r=n.getModeAt(o.head),i=!1;if(r.electricChars){for(var l=0;l-1){i=Oi(n,o.head.line,"smart");break}}else r.electricInput&&r.electricInput.test(Gn(n.doc,o.head.line).text.slice(0,o.head.ch))&&(i=Oi(n,o.head.line,"smart"));i&&se(n,"electricInput",n,o.head.line)}}}function Ti(n){for(var t=[],e=[],a=0;a0?0:-1));if(isNaN(d))i=null;else{var p=e>0?d>=55296&&d<56320:d>=56320&&d<57343;i=new tt(t.line,Math.max(0,Math.min(l.text.length,t.ch+e*(p?2:1))),-e)}}else i=o?function(n,t,e,a){var o=dn(t,n.doc.direction);if(!o)return Jr(t,e,a);e.ch>=t.text.length?(e.ch=t.text.length,e.sticky="before"):e.ch<=0&&(e.ch=0,e.sticky="after");var r=sn(o,e.ch,e.sticky),i=o[r];if("ltr"==n.doc.direction&&i.level%2==0&&(a>0?i.to>e.ch:i.from=i.from&&u>=d.begin)){var b=p?"before":"after";return new tt(e.line,u,b)}}var f=function(n,t,a){for(var r=function(n,t){return t?new tt(e.line,s(n,1),"before"):new tt(e.line,n,"after")};n>=0&&n0==(1!=i.level),c=l?a.begin:s(a.end,-1);if(i.from<=c&&c0?d.end:s(d.begin,-1);return null==h||a>0&&h==t.text.length||!(m=f(a>0?0:o.length-1,a,c(h)))?null:m}(n.cm,l,t,e):Jr(l,t,e);if(null==i){if(r||(c=t.line+s)=n.first+n.size||(t=new tt(c,t.ch,t.sticky),!(l=Gn(n,c))))return!1;t=ni(o,n.cm,l,t.line,s)}else t=i;return!0}if("char"==a||"codepoint"==a)c();else if("column"==a)c(!0);else if("word"==a||"group"==a)for(var d=null,p="group"==a,u=n.cm&&n.cm.getHelper(t,"wordChars"),b=!0;!(e<0)||c(!b);b=!1){var f=l.text.charAt(t.ch)||"\n",m=nn(f,u)?"w":p&&"\n"==f?"n":!p||/\s/.test(f)?null:"p";if(!p||b||m||(m="s"),d&&d!=m){e<0&&(e=1,c(),t.sticky="after");break}if(m&&(d=m),e>0&&!c(!b))break}var h=ir(n,t,r,i,!0);return at(r,h)&&(h.hitSide=!0),h}function ji(n,t,e,a){var o,r,i=n.doc,l=t.left;if("page"==a){var s=Math.min(n.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),c=Math.max(s-.5*aa(n.display),3);o=(e>0?t.bottom:t.top)+e*c}else"line"==a&&(o=e>0?t.bottom+3:t.top-3);for(;(r=Ze(n,l,o)).outside;){if(e<0?o<=0:o>=i.height){r.hitSide=!0;break}o+=5*e}return r}var Ri=function(n){this.cm=n,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new j,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};function Hi(n,t){var e=Me(n,t.line);if(!e||e.hidden)return null;var a=Gn(n.doc,t.line),o=Oe(e,a,t.line),r=dn(a,n.doc.direction),i="left";r&&(i=sn(r,t.ch)%2?"right":"left");var l=Ie(o.map,t.ch,i);return l.offset="right"==l.collapse?l.end:l.start,l}function Wi(n,t){return t&&(n.bad=!0),n}function Ui(n,t,e){var a;if(t==n.display.lineDiv){if(!(a=n.display.lineDiv.childNodes[e]))return Wi(n.clipPos(tt(n.display.viewTo-1)),!0);t=null,e=0}else for(a=t;;a=a.parentNode){if(!a||a==n.display.lineDiv)return null;if(a.parentNode&&a.parentNode==n.display.lineDiv)break}for(var o=0;o=t.display.viewTo||r.line=t.display.viewFrom&&Hi(t,o)||{node:s[0].measure.map[2],offset:0},d=r.linea.firstLine()&&(i=tt(i.line-1,Gn(a.doc,i.line-1).length)),l.ch==Gn(a.doc,l.line).text.length&&l.lineo.viewTo-1)return!1;i.line==o.viewFrom||0==(n=da(a,i.line))?(t=$n(o.view[0].line),e=o.view[0].node):(t=$n(o.view[n].line),e=o.view[n-1].node.nextSibling);var s,c,d=da(a,l.line);if(d==o.view.length-1?(s=o.viewTo-1,c=o.lineDiv.lastChild):(s=$n(o.view[d+1].line)-1,c=o.view[d+1].node.previousSibling),!e)return!1;for(var p=a.doc.splitLines(function(n,t,e,a,o){var r="",i=!1,l=n.doc.lineSeparator(),s=!1;function c(){i&&(r+=l,s&&(r+=l),i=s=!1)}function d(n){n&&(c(),r+=n)}function p(t){if(1==t.nodeType){var e=t.getAttribute("cm-text");if(e)return void d(e);var r,u=t.getAttribute("cm-marker");if(u){var b=n.findMarks(tt(a,0),tt(o+1,0),(h=+u,function(n){return n.id==h}));return void(b.length&&(r=b[0].find(0))&&d(Vn(n.doc,r.from,r.to).join(l)))}if("false"==t.getAttribute("contenteditable"))return;var f=/^(pre|div|p|li|table|br)$/i.test(t.nodeName);if(!/^br$/i.test(t.nodeName)&&0==t.textContent.length)return;f&&c();for(var m=0;m1&&u.length>1;)if(V(p)==V(u))p.pop(),u.pop(),s--;else{if(p[0]!=u[0])break;p.shift(),u.shift(),t++}for(var b=0,f=0,m=p[0],h=u[0],g=Math.min(m.length,h.length);bi.ch&&x.charCodeAt(x.length-f-1)==v.charCodeAt(v.length-f-1);)b--,f++;p[p.length-1]=x.slice(0,x.length-f).replace(/^\u200b+/,""),p[0]=p[0].slice(b).replace(/\u200b+$/,"");var w=tt(t,b),k=tt(s,u.length?V(u).length-f:0);return p.length>1||p[0]||et(w,k)?(mr(a.doc,p,w,k,"+input"),!0):void 0},Ri.prototype.ensurePolled=function(){this.forceCompositionEnd()},Ri.prototype.reset=function(){this.forceCompositionEnd()},Ri.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},Ri.prototype.readFromDOMSoon=function(){var n=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout((function(){if(n.readDOMTimeout=null,n.composing){if(!n.composing.done)return;n.composing=null}n.updateFromDOM()}),80))},Ri.prototype.updateFromDOM=function(){var n=this;!this.cm.isReadOnly()&&this.pollContent()||Ja(this.cm,(function(){return pa(n.cm)}))},Ri.prototype.setUneditable=function(n){n.contentEditable="false"},Ri.prototype.onKeyPress=function(n){0==n.charCode||this.composing||(n.preventDefault(),this.cm.isReadOnly()||no(this.cm,Bi)(this.cm,String.fromCharCode(null==n.charCode?n.keyCode:n.charCode),0))},Ri.prototype.readOnlyChanged=function(n){this.div.contentEditable=String("nocursor"!=n)},Ri.prototype.onContextMenu=function(){},Ri.prototype.resetPosition=function(){},Ri.prototype.needsContentAttribute=!0;var qi=function(n){this.cm=n,this.prevInput="",this.pollingFast=!1,this.polling=new j,this.hasSelection=!1,this.composing=null};qi.prototype.init=function(n){var t=this,e=this,a=this.cm;this.createField(n);var o=this.textarea;function r(n){if(!hn(a,n)){if(a.somethingSelected())Mi({lineWise:!1,text:a.getSelections()});else{if(!a.options.lineWiseCopyCut)return;var t=Ti(a);Mi({lineWise:!0,text:t.text}),"cut"==n.type?a.setSelections(t.ranges,null,W):(e.prevInput="",o.value=t.text.join("\n"),T(o))}"cut"==n.type&&(a.state.cutIncoming=+new Date)}}n.wrapper.insertBefore(this.wrapper,n.wrapper.firstChild),m&&(o.style.width="0px"),un(o,"input",(function(){i&&l>=9&&t.hasSelection&&(t.hasSelection=null),e.poll()})),un(o,"paste",(function(n){hn(a,n)||Ai(n,a)||(a.state.pasteIncoming=+new Date,e.fastPoll())})),un(o,"cut",r),un(o,"copy",r),un(n.scroller,"paste",(function(t){if(!ke(n,t)&&!hn(a,t)){if(!o.dispatchEvent)return a.state.pasteIncoming=+new Date,void e.focus();var r=new Event("paste");r.clipboardData=t.clipboardData,o.dispatchEvent(r)}})),un(n.lineSpace,"selectstart",(function(t){ke(n,t)||yn(t)})),un(o,"compositionstart",(function(){var n=a.getCursor("from");e.composing&&e.composing.range.clear(),e.composing={start:n,range:a.markText(n,a.getCursor("to"),{className:"CodeMirror-composing"})}})),un(o,"compositionend",(function(){e.composing&&(e.poll(),e.composing.range.clear(),e.composing=null)}))},qi.prototype.createField=function(n){this.wrapper=Pi(),this.textarea=this.wrapper.firstChild},qi.prototype.screenReaderLabelChanged=function(n){n?this.textarea.setAttribute("aria-label",n):this.textarea.removeAttribute("aria-label")},qi.prototype.prepareSelection=function(){var n=this.cm,t=n.display,e=n.doc,a=ga(n);if(n.options.moveInputWithCursor){var o=Ge(n,e.sel.primary().head,"div"),r=t.wrapper.getBoundingClientRect(),i=t.lineDiv.getBoundingClientRect();a.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,o.top+i.top-r.top)),a.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,o.left+i.left-r.left))}return a},qi.prototype.showSelection=function(n){var t=this.cm.display;S(t.cursorDiv,n.cursors),S(t.selectionDiv,n.selection),null!=n.teTop&&(this.wrapper.style.top=n.teTop+"px",this.wrapper.style.left=n.teLeft+"px")},qi.prototype.reset=function(n){if(!this.contextMenuPending&&!this.composing){var t=this.cm;if(t.somethingSelected()){this.prevInput="";var e=t.getSelection();this.textarea.value=e,t.state.focused&&T(this.textarea),i&&l>=9&&(this.hasSelection=e)}else n||(this.prevInput=this.textarea.value="",i&&l>=9&&(this.hasSelection=null))}},qi.prototype.getField=function(){return this.textarea},qi.prototype.supportsTouch=function(){return!1},qi.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!g||B()!=this.textarea))try{this.textarea.focus()}catch(n){}},qi.prototype.blur=function(){this.textarea.blur()},qi.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},qi.prototype.receivedFocus=function(){this.slowPoll()},qi.prototype.slowPoll=function(){var n=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,(function(){n.poll(),n.cm.state.focused&&n.slowPoll()}))},qi.prototype.fastPoll=function(){var n=!1,t=this;t.pollingFast=!0,t.polling.set(20,(function e(){t.poll()||n?(t.pollingFast=!1,t.slowPoll()):(n=!0,t.polling.set(60,e))}))},qi.prototype.poll=function(){var n=this,t=this.cm,e=this.textarea,a=this.prevInput;if(this.contextMenuPending||!t.state.focused||An(e)&&!a&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var o=e.value;if(o==a&&!t.somethingSelected())return!1;if(i&&l>=9&&this.hasSelection===o||x&&/[\uf700-\uf7ff]/.test(o))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var r=o.charCodeAt(0);if(8203!=r||a||(a=""),8666==r)return this.reset(),this.cm.execCommand("undo")}for(var s=0,c=Math.min(a.length,o.length);s1e3||o.indexOf("\n")>-1?e.value=n.prevInput="":n.prevInput=o,n.composing&&(n.composing.range.clear(),n.composing.range=t.markText(n.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))})),!0},qi.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},qi.prototype.onKeyPress=function(){i&&l>=9&&(this.hasSelection=null),this.fastPoll()},qi.prototype.onContextMenu=function(n){var t=this,e=t.cm,a=e.display,o=t.textarea;t.contextMenuPending&&t.contextMenuPending();var r=ca(e,n),c=a.scroller.scrollTop;if(r&&!p){e.options.resetSelectionOnContextMenu&&-1==e.doc.sel.contains(r)&&no(e,nr)(e.doc,Co(r),W);var d,u=o.style.cssText,b=t.wrapper.style.cssText,f=t.wrapper.offsetParent.getBoundingClientRect();if(t.wrapper.style.cssText="position: static",o.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(n.clientY-f.top-5)+"px; left: "+(n.clientX-f.left-5)+"px;\n z-index: 1000; background: "+(i?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",s&&(d=window.scrollY),a.input.focus(),s&&window.scrollTo(null,d),a.input.reset(),e.somethingSelected()||(o.value=t.prevInput=" "),t.contextMenuPending=g,a.selForContextMenu=e.doc.sel,clearTimeout(a.detectingSelectAll),i&&l>=9&&h(),z){zn(n);var m=function(){fn(window,"mouseup",m),setTimeout(g,20)};un(window,"mouseup",m)}else setTimeout(g,50)}function h(){if(null!=o.selectionStart){var n=e.somethingSelected(),r=""+(n?o.value:"");o.value="⇚",o.value=r,t.prevInput=n?"":"",o.selectionStart=1,o.selectionEnd=r.length,a.selForContextMenu=e.doc.sel}}function g(){if(t.contextMenuPending==g&&(t.contextMenuPending=!1,t.wrapper.style.cssText=b,o.style.cssText=u,i&&l<9&&a.scrollbars.setScrollTop(a.scroller.scrollTop=c),null!=o.selectionStart)){(!i||i&&l<9)&&h();var n=0,r=function(){a.selForContextMenu==e.doc.sel&&0==o.selectionStart&&o.selectionEnd>0&&""==t.prevInput?no(e,sr)(e):n++<10?a.detectingSelectAll=setTimeout(r,500):(a.selForContextMenu=null,a.input.reset())};a.detectingSelectAll=setTimeout(r,200)}}},qi.prototype.readOnlyChanged=function(n){n||this.reset(),this.textarea.disabled="nocursor"==n,this.textarea.readOnly=!!n},qi.prototype.setUneditable=function(){},qi.prototype.needsContentAttribute=!1,function(n){var t=n.optionHandlers;function e(e,a,o,r){n.defaults[e]=a,o&&(t[e]=r?function(n,t,e){e!=ki&&o(n,t,e)}:o)}n.defineOption=e,n.Init=ki,e("value","",(function(n,t){return n.setValue(t)}),!0),e("mode",null,(function(n,t){n.doc.modeOption=t,Mo(n)}),!0),e("indentUnit",2,Mo,!0),e("indentWithTabs",!1),e("smartIndent",!0),e("tabSize",4,(function(n){Bo(n),Re(n),pa(n)}),!0),e("lineSeparator",null,(function(n,t){if(n.doc.lineSep=t,t){var e=[],a=n.doc.first;n.doc.iter((function(n){for(var o=0;;){var r=n.text.indexOf(t,o);if(-1==r)break;o=r+t.length,e.push(tt(a,r))}a++}));for(var o=e.length-1;o>=0;o--)mr(n.doc,t,e[o],tt(e[o].line,e[o].ch+t.length))}})),e("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g,(function(n,t,e){n.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),e!=ki&&n.refresh()})),e("specialCharPlaceholder",Jt,(function(n){return n.refresh()}),!0),e("electricChars",!0),e("inputStyle",g?"contenteditable":"textarea",(function(){throw new Error("inputStyle can not (yet) be changed in a running editor")}),!0),e("spellcheck",!1,(function(n,t){return n.getInputField().spellcheck=t}),!0),e("autocorrect",!1,(function(n,t){return n.getInputField().autocorrect=t}),!0),e("autocapitalize",!1,(function(n,t){return n.getInputField().autocapitalize=t}),!0),e("rtlMoveVisually",!y),e("wholeLineUpdateBefore",!0),e("theme","default",(function(n){wi(n),ho(n)}),!0),e("keyMap","default",(function(n,t,e){var a=Zr(t),o=e!=ki&&Zr(e);o&&o.detach&&o.detach(n,a),a.attach&&a.attach(n,o||null)})),e("extraKeys",null),e("configureMouse",null),e("lineWrapping",!1,Ci,!0),e("gutters",[],(function(n,t){n.display.gutterSpecs=fo(t,n.options.lineNumbers),ho(n)}),!0),e("fixedGutter",!0,(function(n,t){n.display.gutters.style.left=t?ia(n.display)+"px":"0",n.refresh()}),!0),e("coverGutterNextToScrollbar",!1,(function(n){return Ha(n)}),!0),e("scrollbarStyle","native",(function(n){Ya(n),Ha(n),n.display.scrollbars.setScrollTop(n.doc.scrollTop),n.display.scrollbars.setScrollLeft(n.doc.scrollLeft)}),!0),e("lineNumbers",!1,(function(n,t){n.display.gutterSpecs=fo(n.options.gutters,t),ho(n)}),!0),e("firstLineNumber",1,ho,!0),e("lineNumberFormatter",(function(n){return n}),ho,!0),e("showCursorWhenSelecting",!1,ha,!0),e("resetSelectionOnContextMenu",!0),e("lineWiseCopyCut",!0),e("pasteLinesPerSelection",!0),e("selectionsMayTouch",!1),e("readOnly",!1,(function(n,t){"nocursor"==t&&(Fa(n),n.display.input.blur()),n.display.input.readOnlyChanged(t)})),e("screenReaderLabel",null,(function(n,t){t=""===t?null:t,n.display.input.screenReaderLabelChanged(t)})),e("disableInput",!1,(function(n,t){t||n.display.input.reset()}),!0),e("dragDrop",!0,Fi),e("allowDropFileTypes",null),e("cursorBlinkRate",530),e("cursorScrollMargin",0),e("cursorHeight",1,ha,!0),e("singleCursorHeightPerLine",!0,ha,!0),e("workTime",100),e("workDelay",100),e("flattenSpans",!0,Bo,!0),e("addModeClass",!1,Bo,!0),e("pollInterval",100),e("undoDepth",200,(function(n,t){return n.doc.history.undoDepth=t})),e("historyEventDelay",1250),e("viewportMargin",10,(function(n){return n.refresh()}),!0),e("maxHighlightLength",1e4,Bo,!0),e("moveInputWithCursor",!0,(function(n,t){t||n.display.input.resetPosition()})),e("tabindex",null,(function(n,t){return n.display.input.getField().tabIndex=t||""})),e("autofocus",null),e("direction","ltr",(function(n,t){return n.doc.setDirection(t)}),!0),e("phrases",null)}(Ei),function(n){var t=n.optionHandlers,e=n.helpers={};n.prototype={constructor:n,focus:function(){window.focus(),this.display.input.focus()},setOption:function(n,e){var a=this.options,o=a[n];a[n]==e&&"mode"!=n||(a[n]=e,t.hasOwnProperty(n)&&no(this,t[n])(this,e,o),mn(this,"optionChange",this,n))},getOption:function(n){return this.options[n]},getDoc:function(){return this.doc},addKeyMap:function(n,t){this.state.keyMaps[t?"push":"unshift"](Zr(n))},removeKeyMap:function(n){for(var t=this.state.keyMaps,e=0;ee&&(Oi(this,o.head.line,n,!0),e=o.head.line,a==this.doc.sel.primIndex&&Ma(this));else{var r=o.from(),i=o.to(),l=Math.max(e,r.line);e=Math.min(this.lastLine(),i.line-(i.ch?0:1))+1;for(var s=l;s0&&$o(this.doc,a,new _o(r,c[a].to()),W)}}})),getTokenAt:function(n,t){return vt(this,n,t)},getLineTokens:function(n,t){return vt(this,tt(n),t,!0)},getTokenTypeAt:function(n){n=st(this.doc,n);var t,e=bt(this,Gn(this.doc,n.line)),a=0,o=(e.length-1)/2,r=n.ch;if(0==r)t=e[2];else for(;;){var i=a+o>>1;if((i?e[2*i-1]:0)>=r)o=i;else{if(!(e[2*i+1]r&&(n=r,o=!0),a=Gn(this.doc,n)}else a=n;return Ye(this,a,{top:0,left:0},t||"page",e||o).top+(o?this.doc.height-Yt(a):0)},defaultTextHeight:function(){return aa(this.display)},defaultCharWidth:function(){return oa(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(n,t,e,a,o){var r,i,l,s=this.display,c=(n=Ge(this,st(this.doc,n))).bottom,d=n.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),s.sizer.appendChild(t),"over"==a)c=n.top;else if("above"==a||"near"==a){var p=Math.max(s.wrapper.clientHeight,this.doc.height),u=Math.max(s.sizer.clientWidth,s.lineSpace.clientWidth);("above"==a||n.bottom+t.offsetHeight>p)&&n.top>t.offsetHeight?c=n.top-t.offsetHeight:n.bottom+t.offsetHeight<=p&&(c=n.bottom),d+t.offsetWidth>u&&(d=u-t.offsetWidth)}t.style.top=c+"px",t.style.left=t.style.right="","right"==o?(d=s.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==o?d=0:"middle"==o&&(d=(s.sizer.clientWidth-t.offsetWidth)/2),t.style.left=d+"px"),e&&(r=this,i={left:d,top:c,right:d+t.offsetWidth,bottom:c+t.offsetHeight},null!=(l=Oa(r,i)).scrollTop&&Ta(r,l.scrollTop),null!=l.scrollLeft&&Pa(r,l.scrollLeft))},triggerOnKeyDown:to(di),triggerOnKeyPress:to(ui),triggerOnKeyUp:pi,triggerOnMouseDown:to(hi),execCommand:function(n){if(ti.hasOwnProperty(n))return ti[n].call(null,this)},triggerElectric:to((function(n){Li(this,n)})),findPosH:function(n,t,e,a){var o=1;t<0&&(o=-1,t=-t);for(var r=st(this.doc,n),i=0;i0&&i(t.charAt(e-1));)--e;for(;a.5||this.options.lineWrapping)&&sa(this),mn(this,"refresh",this)})),swapDoc:to((function(n){var t=this.doc;return t.cm=null,this.state.selectingText&&this.state.selectingText(),Io(this,n),Re(this),this.display.input.reset(),Ba(this,n.scrollLeft,n.scrollTop),this.curOp.forceScroll=!0,se(this,"swapDoc",this,t),t})),phrase:function(n){var t=this.options.phrases;return t&&Object.prototype.hasOwnProperty.call(t,n)?t[n]:n},getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},vn(n),n.registerHelper=function(t,a,o){e.hasOwnProperty(t)||(e[t]=n[t]={_global:[]}),e[t][a]=o},n.registerGlobalHelper=function(t,a,o,r){n.registerHelper(t,a,r),e[t]._global.push({pred:o,val:r})}}(Ei);var Ki="iter insert remove copy getEditor constructor".split(" ");for(var Gi in Mr.prototype)Mr.prototype.hasOwnProperty(Gi)&&R(Ki,Gi)<0&&(Ei.prototype[Gi]=function(n){return function(){return n.apply(this.doc,arguments)}}(Mr.prototype[Gi]));return vn(Mr),Ei.inputStyles={textarea:qi,contenteditable:Ri},Ei.defineMode=function(n){Ei.defaults.mode||"null"==n||(Ei.defaults.mode=n),Nn.apply(this,arguments)},Ei.defineMIME=function(n,t){Pn[n]=t},Ei.defineMode("null",(function(){return{token:function(n){return n.skipToEnd()}}})),Ei.defineMIME("text/plain","null"),Ei.defineExtension=function(n,t){Ei.prototype[n]=t},Ei.defineDocExtension=function(n,t){Mr.prototype[n]=t},Ei.fromTextArea=function(n,t){if((t=t?P(t):{}).value=n.value,!t.tabindex&&n.tabIndex&&(t.tabindex=n.tabIndex),!t.placeholder&&n.placeholder&&(t.placeholder=n.placeholder),null==t.autofocus){var e=B();t.autofocus=e==n||null!=n.getAttribute("autofocus")&&e==document.body}function a(){n.value=l.getValue()}var o;if(n.form&&(un(n.form,"submit",a),!t.leaveSubmitMethodAlone)){var r=n.form;o=r.submit;try{var i=r.submit=function(){a(),r.submit=o,r.submit(),r.submit=i}}catch(n){}}t.finishInit=function(e){e.save=a,e.getTextArea=function(){return n},e.toTextArea=function(){e.toTextArea=isNaN,a(),n.parentNode.removeChild(e.getWrapperElement()),n.style.display="",n.form&&(fn(n.form,"submit",a),t.leaveSubmitMethodAlone||"function"!=typeof n.form.submit||(n.form.submit=o))}},n.style.display="none";var l=Ei((function(t){return n.parentNode.insertBefore(t,n.nextSibling)}),t);return l},function(n){n.off=fn,n.on=un,n.wheelEventPixels=wo,n.Doc=Mr,n.splitLines=Bn,n.countColumn=N,n.findColumn=q,n.isWordChar=J,n.Pass=H,n.signal=mn,n.Line=Gt,n.changeEnd=Eo,n.scrollbarModel=Ua,n.Pos=tt,n.cmpPos=et,n.modes=In,n.mimeModes=Pn,n.resolveMode=jn,n.getMode=Rn,n.modeExtensions=Hn,n.extendMode=Wn,n.copyState=Un,n.startState=qn,n.innerMode=Yn,n.commands=ti,n.keyMap=Ur,n.keyName=Xr,n.isModifierKey=Gr,n.lookupKey=Kr,n.normalizeKeyMap=qr,n.StringStream=Kn,n.SharedTextMarker=Er,n.TextMarker=Fr,n.LineWidget=kr,n.e_preventDefault=yn,n.e_stopPropagation=wn,n.e_stop=zn,n.addClass=A,n.contains=M,n.rmClass=C,n.keyNames=jr}(Ei),Ei.version="5.63.3",Ei}()},function(n,t,e){!function(n){"use strict";n.defineMode("shell",(function(){var t={};function e(n,e){for(var a=0;a1&&n.eat("$");var e=n.next();return/['"({]/.test(e)?(t.tokens[0]=l(e,"("==e?"quote":"{"==e?"def":"string"),d(n,t)):(/\d/.test(e)||n.eatWhile(/\w/),t.tokens.shift(),"def")};function d(n,t){return(t.tokens[0]||i)(n,t)}return{startState:function(){return{tokens:[]}},token:function(n,t){return d(n,t)},closeBrackets:"()[]{}''\"\"``",lineComment:"#",fold:"brace"}})),n.defineMIME("text/x-sh","shell"),n.defineMIME("application/x-sh","shell")}(e(62))},function(n,t,e){var a=e(198),o=e(3);"string"==typeof a&&(a=[[n.i,a,""]]),n.exports=a.locals||{},n.exports._getContent=function(){return a},n.exports._getCss=function(){return a.toString()},n.exports._insertCss=function(n){return o(a,n)}},function(n,t,e){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.CHANGE_LOCAL_IP=void 0,t.CHANGE_LOCAL_IP="CHANGE_LOCAL_IP"},function(n,t,e){n.exports=e.p+"font/iconfont.35d9a9ed.eot"},function(n,t,e){"use strict";var a=this&&this.__createBinding||(Object.create?function(n,t,e,a){void 0===a&&(a=e),Object.defineProperty(n,a,{enumerable:!0,get:function(){return t[e]}})}:function(n,t,e,a){void 0===a&&(a=e),n[a]=t[e]}),o=this&&this.__setModuleDefault||(Object.create?function(n,t){Object.defineProperty(n,"default",{enumerable:!0,value:t})}:function(n,t){n.default=t}),r=this&&this.__importStar||function(n){if(n&&n.__esModule)return n;var t={};if(null!=n)for(var e in n)"default"!==e&&Object.prototype.hasOwnProperty.call(n,e)&&a(t,n,e);return o(t,n),t},i=this&&this.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(t,"__esModule",{value:!0});var l=r(e(0)),s=(r(e(68)),e(9)),c=e(6),d=e(22),p=(e(69),i(e(70))),u=i(e(71)),b=e(230),f=i(e(37));e(234),e(236);t.default=function(n,t){var e=n.state.url,a=(0,d.matchRoutes)(f.default,e).map((function(n){var t=n.route,e=t.component&&t.component.fetch;return e instanceof Function?e():Promise.resolve(null)}));return Promise.all(a).then((function(t){var a=n.state;t.forEach((function(n){Object.assign(a,n)})),n.state=Object.assign({},n.state,a);var o=(0,b.create)(a);return function(){return l.createElement(p.default,null,l.createElement("div",{style:{height:"100%"}},l.createElement(s.Provider,{store:o},l.createElement(c.StaticRouter,{location:e,context:{}},l.createElement(u.default,null)))))}}))}},function(n,t){n.exports=require("react-dom")},function(n,t){n.exports=require("react-hot-loader")},function(n,t,e){"use strict";var a,o=this&&this.__extends||(a=function(n,t){return(a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,t){n.__proto__=t}||function(n,t){for(var e in t)Object.prototype.hasOwnProperty.call(t,e)&&(n[e]=t[e])})(n,t)},function(n,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function e(){this.constructor=n}a(n,t),n.prototype=null===t?Object.create(t):(e.prototype=t.prototype,new e)}),r=this&&this.__createBinding||(Object.create?function(n,t,e,a){void 0===a&&(a=e),Object.defineProperty(n,a,{enumerable:!0,get:function(){return t[e]}})}:function(n,t,e,a){void 0===a&&(a=e),n[a]=t[e]}),i=this&&this.__setModuleDefault||(Object.create?function(n,t){Object.defineProperty(n,"default",{enumerable:!0,value:t})}:function(n,t){n.default=t}),l=this&&this.__importStar||function(n){if(n&&n.__esModule)return n;var t={};if(null!=n)for(var e in n)"default"!==e&&Object.prototype.hasOwnProperty.call(n,e)&&r(t,n,e);return i(t,n),t};Object.defineProperty(t,"__esModule",{value:!0});var s=l(e(0)),c=function(n){function t(){return null!==n&&n.apply(this,arguments)||this}return o(t,n),t.prototype.render=function(){return s.createElement("html",null,s.createElement("head",null,s.createElement("title",null,this.props.title),s.createElement("meta",{charSet:"utf-8"}),s.createElement("meta",{name:"viewport",content:"initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui"}),s.createElement("meta",{name:"keywords",content:this.props.keywords}),s.createElement("meta",{name:"description",content:this.props.description}),s.createElement("link",{rel:"shortcut icon",href:"/favicon.ico",type:"image/x-icon"}),s.createElement("link",null),s.createElement("link",{href:"https://cdn.bootcss.com/codemirror/5.48.4/codemirror.min.css",rel:"stylesheet"}),s.createElement("link",{href:"https://cdn.bootcss.com/codemirror/5.48.4/theme/dracula.min.css",rel:"stylesheet"}),s.createElement("script",{src:"https://cdn.bootcss.com/codemirror/5.48.4/codemirror.min.js"}),s.createElement("script",{src:"https://cdn.bootcss.com/codemirror/5.48.4/mode/nginx/nginx.min.js"})),s.createElement("body",null,s.createElement("div",{id:"app"},this.props.children)))},t}(s.Component);t.default=c},function(n,t,e){"use strict";var a=this&&this.__createBinding||(Object.create?function(n,t,e,a){void 0===a&&(a=e),Object.defineProperty(n,a,{enumerable:!0,get:function(){return t[e]}})}:function(n,t,e,a){void 0===a&&(a=e),n[a]=t[e]}),o=this&&this.__setModuleDefault||(Object.create?function(n,t){Object.defineProperty(n,"default",{enumerable:!0,value:t})}:function(n,t){n.default=t}),r=this&&this.__importStar||function(n){if(n&&n.__esModule)return n;var t={};if(null!=n)for(var e in n)"default"!==e&&Object.prototype.hasOwnProperty.call(n,e)&&a(t,n,e);return o(t,n),t},i=this&&this.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(t,"__esModule",{value:!0});var l=r(e(0)),s=e(6),c=e(34),d=e(9),p=e(1),u=i(e(72)),b=i(e(37)),f=e(22),m=r(e(223));e(224),e(226),e(228);t.default=function(){var n=(0,c.bindActionCreators)(m,(0,d.useDispatch)()).changeLocalIp;return(0,l.useEffect)((function(){var t,e,a,o;t=window,e=document,t.hj=t.hj||function(){(t.hj.q=t.hj.q||[]).push(arguments)},t._hjSettings={hjid:2133522,hjsv:6},a=e.getElementsByTagName("head")[0],(o=e.createElement("script")).async=1,o.src="https://static.hotjar.com/c/hotjar-"+t._hjSettings.hjid+".js?sv="+t._hjSettings.hjsv,a.appendChild(o),n()}),[]),l.default.createElement("div",{style:{height:"100%"}},l.default.createElement(p.ConfigProvider,{locale:u.default},l.default.createElement(s.Switch,null,(0,f.renderRoutes)(b.default))))}},function(n,t,e){"use strict";var a=e(15);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=a(e(73)).default;t.default=o},function(n,t,e){"use strict";var a=e(15);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=a(e(74)),r=a(e(35)),i=a(e(36)),l=a(e(77)),s="${label}不是一个有效的${type}",c={locale:"zh-cn",Pagination:o.default,DatePicker:r.default,TimePicker:i.default,Calendar:l.default,global:{placeholder:"请选择"},Table:{filterTitle:"筛选",filterConfirm:"确定",filterReset:"重置",filterEmptyText:"无筛选项",selectAll:"全选当页",selectInvert:"反选当页",selectNone:"清空所有",selectionAll:"全选所有",sortTitle:"排序",expand:"展开行",collapse:"关闭行",triggerDesc:"点击降序",triggerAsc:"点击升序",cancelSort:"取消排序"},Modal:{okText:"确定",cancelText:"取消",justOkText:"知道了"},Popconfirm:{cancelText:"取消",okText:"确定"},Transfer:{searchPlaceholder:"请输入搜索内容",itemUnit:"项",itemsUnit:"项",remove:"删除",selectCurrent:"全选当页",removeCurrent:"删除当页",selectAll:"全选所有",removeAll:"删除全部",selectInvert:"反选当页"},Upload:{uploading:"文件上传中",removeFile:"删除文件",uploadError:"上传错误",previewFile:"预览文件",downloadFile:"下载文件"},Empty:{description:"暂无数据"},Icon:{icon:"图标"},Text:{edit:"编辑",copy:"复制",copied:"复制成功",expand:"展开"},PageHeader:{back:"返回"},Form:{optional:"(可选)",defaultValidateMessages:{default:"字段验证错误${label}",required:"请输入${label}",enum:"${label}必须是其中一个[${enum}]",whitespace:"${label}不能为空字符",date:{format:"${label}日期格式无效",parse:"${label}不能转换为日期",invalid:"${label}是一个无效日期"},types:{string:s,method:s,array:s,object:s,number:s,date:s,boolean:s,integer:s,float:s,regexp:s,email:s,url:s,hex:s},string:{len:"${label}须为${len}个字符",min:"${label}最少${min}个字符",max:"${label}最多${max}个字符",range:"${label}须在${min}-${max}字符之间"},number:{len:"${label}必须等于${len}",min:"${label}最小值为${min}",max:"${label}最大值为${max}",range:"${label}须在${min}-${max}之间"},array:{len:"须为${len}个${label}",min:"最少${min}个${label}",max:"最多${max}个${label}",range:"${label}数量须在${min}-${max}之间"},pattern:{mismatch:"${label}与模式不匹配${pattern}"}}},Image:{preview:"预览"}};t.default=c},function(n,t,e){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;t.default={items_per_page:"条/页",jump_to:"跳至",jump_to_confirm:"确定",page:"页",prev_page:"上一页",next_page:"下一页",prev_5:"向前 5 页",next_5:"向后 5 页",prev_3:"向前 3 页",next_3:"向后 3 页"}},function(n,t){function e(){return n.exports=e=Object.assign||function(n){for(var t=1;t=n.length?(this._t=void 0,o(1)):o(0,"keys"==t?e:"values"==t?n[e]:[e,n[e]])}),"values"),r.Arguments=r.Array,a("keys"),a("values"),a("entries")},function(n,t){n.exports=function(){}},function(n,t){n.exports=function(n,t){return{value:t,done:!!n}}},function(n,t,e){var a=e(40);n.exports=Object("z").propertyIsEnumerable(0)?Object:function(n){return"String"==a(n)?n.split(""):Object(n)}},function(n,t,e){var a=e(11),o=e(10),r=e(91),i=e(13),l=e(18),s=function(n,t,e){var c,d,p,u=n&s.F,b=n&s.G,f=n&s.S,m=n&s.P,h=n&s.B,g=n&s.W,x=b?o:o[t]||(o[t]={}),v=x.prototype,y=b?a:f?a[t]:(a[t]||{}).prototype;for(c in b&&(e=t),e)(d=!u&&y&&void 0!==y[c])&&l(x,c)||(p=d?y[c]:e[c],x[c]=b&&"function"!=typeof y[c]?e[c]:h&&d?r(p,a):g&&y[c]==p?function(n){var t=function(t,e,a){if(this instanceof n){switch(arguments.length){case 0:return new n;case 1:return new n(t);case 2:return new n(t,e)}return new n(t,e,a)}return n.apply(this,arguments)};return t.prototype=n.prototype,t}(p):m&&"function"==typeof p?r(Function.call,p):p,m&&((x.virtual||(x.virtual={}))[c]=p,n&s.R&&v&&!v[c]&&i(v,c,p)))};s.F=1,s.G=2,s.S=4,s.P=8,s.B=16,s.W=32,s.U=64,s.R=128,n.exports=s},function(n,t,e){var a=e(92);n.exports=function(n,t,e){if(a(n),void 0===t)return n;switch(e){case 1:return function(e){return n.call(t,e)};case 2:return function(e,a){return n.call(t,e,a)};case 3:return function(e,a,o){return n.call(t,e,a,o)}}return function(){return n.apply(t,arguments)}}},function(n,t){n.exports=function(n){if("function"!=typeof n)throw TypeError(n+" is not a function!");return n}},function(n,t,e){n.exports=!e(17)&&!e(43)((function(){return 7!=Object.defineProperty(e(44)("div"),"a",{get:function(){return 7}}).a}))},function(n,t,e){var a=e(26);n.exports=function(n,t){if(!a(n))return n;var e,o;if(t&&"function"==typeof(e=n.toString)&&!a(o=e.call(n)))return o;if("function"==typeof(e=n.valueOf)&&!a(o=e.call(n)))return o;if(!t&&"function"==typeof(e=n.toString)&&!a(o=e.call(n)))return o;throw TypeError("Can't convert object to primitive value")}},function(n,t,e){n.exports=e(13)},function(n,t,e){"use strict";var a=e(97),o=e(45),r=e(49),i={};e(13)(i,e(8)("iterator"),(function(){return this})),n.exports=function(n,t,e){n.prototype=a(i,{next:o(1,e)}),r(n,t+" Iterator")}},function(n,t,e){var a=e(16),o=e(98),r=e(48),i=e(28)("IE_PROTO"),l=function(){},s=function(){var n,t=e(44)("iframe"),a=r.length;for(t.style.display="none",e(104).appendChild(t),t.src="javascript:",(n=t.contentWindow.document).open(),n.write("
-
-
- {this.props.children}
-