提交Trustie通知系统第一个版本
This commit is contained in:
parent
895729e042
commit
3165c635ce
205
README.md
205
README.md
|
@ -1,20 +1,201 @@
|
|||
#### 从命令行创建一个新的仓库
|
||||
# TrustieJob& Notice 运维手册
|
||||
|
||||
```bash
|
||||
touch README.md
|
||||
git init
|
||||
git add README.md
|
||||
git commit -m "first commit"
|
||||
git remote add origin https://git.trustie.net/jasder/Trustie-Notice.git
|
||||
git push -u origin master
|
||||
## 1. 概述
|
||||
|
||||
> Trustie-Notice 采用JAVA开发,使用了XXL-Job 组件,这是一个分布式的任务管理和执行系统。
|
||||
>
|
||||
> 程序分为三个小工程
|
||||
>
|
||||
> xxl-job-core 核心包,必须先编译
|
||||
>
|
||||
> xxl-job-admin 主管理节点
|
||||
>
|
||||
> xxl-job-executor 执行节点
|
||||
>
|
||||
> 数据都存放在mysql 数据库
|
||||
|
||||
## 2. 版本编译
|
||||
|
||||
### 1.1 windows 编译
|
||||
|
||||
#### 1.1.1 程序结构
|
||||
|
||||
```
|
||||
暂无
|
||||
```
|
||||
|
||||
#### 1.1.2 编译
|
||||
|
||||
> 需要提前安装好 JDK8, maven, mysql
|
||||
|
||||
```
|
||||
# 进入工程对应目录,执行
|
||||
mvn clean install
|
||||
# 三个工程依次执行完以后,需要先编译xxl-job-core
|
||||
```
|
||||
|
||||
#### 1.1.3 配置文件
|
||||
|
||||
Trustie-Notice 采用分环境的方式来定义配置,配置文件放在src\main\resources目录下,分为主配置文件,开发配置文件,测试配置文件和生产配置文件。
|
||||
|
||||
主配置文件:application.properties
|
||||
|
||||
主配置文件只有一行代码,用来指定使用哪个配置文件。
|
||||
|
||||
```
|
||||
spring.profiles.active=dev
|
||||
# dev 代表使用application-dev.properties文件
|
||||
```
|
||||
|
||||
开发配置文件: application-dev.properties
|
||||
|
||||
测试配置文件: application-rc.properties
|
||||
|
||||
生产配置文件: application-prod.properties
|
||||
|
||||
**(1) xxl-job-core**
|
||||
|
||||
xxl-job-core 是通用核心包,没有配置文件,直接编译,会安装到本地的 maven 仓库中。
|
||||
|
||||
**(2)xxl-job-admin**
|
||||
|
||||
xxl-job-admin 启动后是一个管理网站,也是客户端连接的中心,运维人员需要配置的有下面几项:
|
||||
|
||||
```
|
||||
### web 服务器启动的端口和根路径
|
||||
server.port=80
|
||||
server.servlet.context-path=/xxl-job-admin
|
||||
|
||||
### xxl-job, datasource 数据库配置
|
||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=keep
|
||||
|
||||
### xxl-job, email ,xxl-job 本身出错发送的邮件
|
||||
spring.mail.host=smtp.qq.com
|
||||
spring.mail.port=25
|
||||
spring.mail.username=27447985@qq.com
|
||||
spring.mail.password=yklcprgatxxrbjaj
|
||||
|
||||
### xxl-job, access token , 简易的访问token
|
||||
xxl.job.accessToken=
|
||||
```
|
||||
|
||||
**(3) xxl-job-executor**
|
||||
|
||||
xxl-job-executor 是客户端执行器。
|
||||
|
||||
```
|
||||
# web port 客户端端口
|
||||
server.port=81
|
||||
|
||||
### xxl-job admin address list, such as "http://address" or "http://address01,http://address02" 访问服务器的地址
|
||||
xxl.job.admin.addresses=http://127.0.0.1:80/xxl-job-admin
|
||||
|
||||
### xxl-job, access token
|
||||
xxl.job.accessToken=
|
||||
|
||||
### xxl-job executor appname app名字和执行端口
|
||||
xxl.job.executor.appname=xxl-job-executor-trustie
|
||||
xxl.job.executor.port=82
|
||||
|
||||
### email config 发送统计邮件的邮箱
|
||||
spring.mail.host=smtp.qq.com
|
||||
spring.mail.port=25
|
||||
spring.mail.username=27447985@qq.com
|
||||
spring.mail.password=yklcprgatxxrbjaj
|
||||
spring.mail.properties.mail.smtp.auth=true
|
||||
spring.mail.properties.mail.smtp.starttls.enable=true
|
||||
spring.mail.properties.mail.smtp.starttls.required=true
|
||||
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
|
||||
|
||||
# 确实社区API链接地址
|
||||
trustie.url = https://testforgeplus.trustie.net/
|
||||
|
||||
```
|
||||
|
||||
#### 从命令行推送已经创建的仓库
|
||||
#### 1.1.4 拷贝jar包
|
||||
|
||||
```bash
|
||||
git remote add origin https://git.trustie.net/jasder/Trustie-Notice.git
|
||||
git push -u origin master
|
||||
```
|
||||
jar 包存放在 target 目录下。
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 1.1.5 自动发布
|
||||
|
||||
> TODO: Jekins 自动发布
|
||||
|
||||
## 2. 版本发布
|
||||
|
||||
### 2.1 Ubuntu发布
|
||||
|
||||
此次发布我们在Ubuntu上进行,先需要更新一下操作系统仓库,安装上必要的mysql客户端、文件上传下载工具 lrzsz和openjdk。
|
||||
|
||||
接下来,我们在opt下面建立trustie文件夹,把trustie-notice相关的jar包和数据库文件都放到trustie-notice 这个子文件夹中。
|
||||
|
||||
#### 2.1.1 安装必要组件
|
||||
|
||||
```
|
||||
# 更新系统
|
||||
sudo apt-get update
|
||||
|
||||
# 安装数据库客户端
|
||||
sudo apt-get install mysql-client
|
||||
|
||||
# 安装文件上传下载工具
|
||||
sodu apt-get install lrzsz
|
||||
|
||||
# 安装open-jdk8
|
||||
sudo apt-get install default-jdk
|
||||
|
||||
# 建立目录
|
||||
sudo mkdir -p /opt/trustie/trustie-notice
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.1.2 数据库导入
|
||||
|
||||
我们在程序开发目录下 doc\db 下面找到 tables_xxl_job.sql 文件。上传到trustie-notice 文件夹。
|
||||
|
||||
这里注意的是,xxl_job 默认的数据库名字是 xxl-job , 这里需要手动修改一下,因为我们使用的是 trustie_notice 这个数据库名字。
|
||||
|
||||
这里修改数据库脚本的前两行即可。
|
||||
|
||||
```
|
||||
mysql –u用户名 –p密码 –D数据库<【sql脚本文件路径全名】
|
||||
|
||||
mysql -h10.0.0.1 -utrustie_notice -p123456 < /opt/trustie/trustie-notice/tables_xxl_job.sql
|
||||
|
||||
mysql> use trustie_notice;
|
||||
Reading table information for completion of table and column names
|
||||
You can turn off this feature to get a quicker startup with -A
|
||||
|
||||
Database changed
|
||||
mysql> select * from xxl_job_info;
|
||||
|
||||
```
|
||||
|
||||
### 2.1.3 启动程序
|
||||
|
||||
上传版本发布下面的xxl-job-admin-2.2.0.jar 和xxl-job-executor-sample-springboot-2.2.0.jar到服务器目录/opt/trustie/trustie-notice下。
|
||||
|
||||
```
|
||||
nohup java -jar ./xxl-job-admin-2.2.0.jar >/dev/null 2>&1 &
|
||||
nohup java -jar ./xxl-job-executor-sample-springboot-2.2.0.jar >/dev/null 2>&1 &
|
||||
```
|
||||
|
||||
启动后如果没有问题,我们就可以登录我们的平台了
|
||||
|
||||
在浏览器中打开网址 http://106.75.110.152:50080/xxl-job-admin
|
||||
|
||||
使用用户名和密码
|
||||
|
||||
> admin
|
||||
>
|
||||
> 123456
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
FROM openjdk:8-jre-slim
|
||||
MAINTAINER xuxueli
|
||||
|
||||
ENV PARAMS=""
|
||||
|
||||
ENV TZ=PRC
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
ADD target/xxl-job-admin-*.jar /app.jar
|
||||
|
||||
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar $PARAMS"]
|
|
@ -0,0 +1,119 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</parent>
|
||||
<artifactId>TrustieJobAdmin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>nexus-aliyun</id>
|
||||
<name>Nexus aliyun</name>
|
||||
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- starter-web:spring-webmvc + autoconfigure + logback + yaml + tomcat -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- starter-test:junit + spring-test + mockito -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- freemarker-starter -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- mail-starter -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- starter-actuator -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- mybatis-starter:mybatis + mybatis-spring + hikari(default) -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${mybatis-spring-boot-starter.version}</version>
|
||||
</dependency>
|
||||
<!-- mysql -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql-connector-java.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- xxl-job-core -->
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- docker -->
|
||||
<plugin>
|
||||
<groupId>com.spotify</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<version>0.4.13</version>
|
||||
<configuration>
|
||||
<!-- made of '[a-z0-9-_.]' -->
|
||||
<imageName>${project.artifactId}:${project.version}</imageName>
|
||||
<dockerDirectory>${project.basedir}</dockerDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>/</targetPath>
|
||||
<directory>${project.build.directory}</directory>
|
||||
<include>${project.build.finalName}.jar</include>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,16 @@
|
|||
package com.xxl.job.admin;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2018-10-28 00:38:13
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class XxlJobAdminApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(XxlJobAdminApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package com.xxl.job.admin.controller;
|
||||
|
||||
import com.xxl.job.admin.controller.annotation.PermissionLimit;
|
||||
import com.xxl.job.admin.service.LoginService;
|
||||
import com.xxl.job.admin.service.XxlJobService;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import org.springframework.beans.propertyeditors.CustomDateEditor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* index controller
|
||||
* @author xuxueli 2015-12-19 16:13:16
|
||||
*/
|
||||
@Controller
|
||||
public class IndexController {
|
||||
|
||||
@Resource
|
||||
private XxlJobService xxlJobService;
|
||||
@Resource
|
||||
private LoginService loginService;
|
||||
|
||||
|
||||
@RequestMapping("/")
|
||||
public String index(Model model) {
|
||||
|
||||
Map<String, Object> dashboardMap = xxlJobService.dashboardInfo();
|
||||
model.addAllAttributes(dashboardMap);
|
||||
|
||||
return "index";
|
||||
}
|
||||
|
||||
@RequestMapping("/chartInfo")
|
||||
@ResponseBody
|
||||
public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
|
||||
ReturnT<Map<String, Object>> chartInfo = xxlJobService.chartInfo(startDate, endDate);
|
||||
return chartInfo;
|
||||
}
|
||||
|
||||
@RequestMapping("/toLogin")
|
||||
@PermissionLimit(limit=false)
|
||||
public String toLogin(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (loginService.ifLogin(request, response) != null) {
|
||||
return "redirect:/";
|
||||
}
|
||||
return "login";
|
||||
}
|
||||
|
||||
@RequestMapping(value="login", method=RequestMethod.POST)
|
||||
@ResponseBody
|
||||
@PermissionLimit(limit=false)
|
||||
public ReturnT<String> loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){
|
||||
boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
|
||||
return loginService.login(request, response, userName, password, ifRem);
|
||||
}
|
||||
|
||||
@RequestMapping(value="logout", method=RequestMethod.POST)
|
||||
@ResponseBody
|
||||
@PermissionLimit(limit=false)
|
||||
public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
|
||||
return loginService.logout(request, response);
|
||||
}
|
||||
|
||||
@RequestMapping("/help")
|
||||
public String help() {
|
||||
|
||||
/*if (!PermissionInterceptor.ifLogin(request)) {
|
||||
return "redirect:/toLogin";
|
||||
}*/
|
||||
|
||||
return "help";
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
dateFormat.setLenient(false);
|
||||
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package com.xxl.job.admin.controller;
|
||||
|
||||
import com.xxl.job.admin.controller.annotation.PermissionLimit;
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.core.biz.AdminBiz;
|
||||
import com.xxl.job.core.biz.model.HandleCallbackParam;
|
||||
import com.xxl.job.core.biz.model.RegistryParam;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.util.GsonTool;
|
||||
import com.xxl.job.core.util.XxlJobRemotingUtil;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/5/10.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/api")
|
||||
public class JobApiController {
|
||||
|
||||
@Resource
|
||||
private AdminBiz adminBiz;
|
||||
|
||||
/**
|
||||
* api
|
||||
*
|
||||
* @param uri
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/{uri}")
|
||||
@ResponseBody
|
||||
@PermissionLimit(limit=false)
|
||||
public ReturnT<String> api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) {
|
||||
|
||||
// valid
|
||||
if (!"POST".equalsIgnoreCase(request.getMethod())) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");
|
||||
}
|
||||
if (uri==null || uri.trim().length()==0) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");
|
||||
}
|
||||
if (XxlJobAdminConfig.getAdminConfig().getAccessToken()!=null
|
||||
&& XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length()>0
|
||||
&& !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, "The access token is wrong.");
|
||||
}
|
||||
|
||||
// services mapping
|
||||
if ("callback".equals(uri)) {
|
||||
List<HandleCallbackParam> callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class);
|
||||
return adminBiz.callback(callbackParamList);
|
||||
} else if ("registry".equals(uri)) {
|
||||
RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
|
||||
return adminBiz.registry(registryParam);
|
||||
} else if ("registryRemove".equals(uri)) {
|
||||
RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
|
||||
return adminBiz.registryRemove(registryParam);
|
||||
} else {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping("+ uri +") not found.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package com.xxl.job.admin.controller;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobLogGlue;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.dao.XxlJobInfoDao;
|
||||
import com.xxl.job.admin.dao.XxlJobLogGlueDao;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.glue.GlueTypeEnum;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* job code controller
|
||||
* @author xuxueli 2015-12-19 16:13:16
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/jobcode")
|
||||
public class JobCodeController {
|
||||
|
||||
@Resource
|
||||
private XxlJobInfoDao xxlJobInfoDao;
|
||||
@Resource
|
||||
private XxlJobLogGlueDao xxlJobLogGlueDao;
|
||||
|
||||
@RequestMapping
|
||||
public String index(HttpServletRequest request, Model model, int jobId) {
|
||||
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId);
|
||||
List<XxlJobLogGlue> jobLogGlues = xxlJobLogGlueDao.findByJobId(jobId);
|
||||
|
||||
if (jobInfo == null) {
|
||||
throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
|
||||
}
|
||||
if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) {
|
||||
throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid"));
|
||||
}
|
||||
|
||||
// valid permission
|
||||
JobInfoController.validPermission(request, jobInfo.getJobGroup());
|
||||
|
||||
// Glue类型-字典
|
||||
model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());
|
||||
|
||||
model.addAttribute("jobInfo", jobInfo);
|
||||
model.addAttribute("jobLogGlues", jobLogGlues);
|
||||
return "jobcode/jobcode.index";
|
||||
}
|
||||
|
||||
@RequestMapping("/save")
|
||||
@ResponseBody
|
||||
public ReturnT<String> save(Model model, int id, String glueSource, String glueRemark) {
|
||||
// valid
|
||||
if (glueRemark==null) {
|
||||
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")) );
|
||||
}
|
||||
if (glueRemark.length()<4 || glueRemark.length()>100) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_remark_limit"));
|
||||
}
|
||||
XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(id);
|
||||
if (exists_jobInfo == null) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
|
||||
}
|
||||
|
||||
// update new code
|
||||
exists_jobInfo.setGlueSource(glueSource);
|
||||
exists_jobInfo.setGlueRemark(glueRemark);
|
||||
exists_jobInfo.setGlueUpdatetime(new Date());
|
||||
|
||||
exists_jobInfo.setUpdateTime(new Date());
|
||||
xxlJobInfoDao.update(exists_jobInfo);
|
||||
|
||||
// log old code
|
||||
XxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue();
|
||||
xxlJobLogGlue.setJobId(exists_jobInfo.getId());
|
||||
xxlJobLogGlue.setGlueType(exists_jobInfo.getGlueType());
|
||||
xxlJobLogGlue.setGlueSource(glueSource);
|
||||
xxlJobLogGlue.setGlueRemark(glueRemark);
|
||||
|
||||
xxlJobLogGlue.setAddTime(new Date());
|
||||
xxlJobLogGlue.setUpdateTime(new Date());
|
||||
xxlJobLogGlueDao.save(xxlJobLogGlue);
|
||||
|
||||
// remove code backup more than 30
|
||||
xxlJobLogGlueDao.removeOld(exists_jobInfo.getId(), 30);
|
||||
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
package com.xxl.job.admin.controller;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import com.xxl.job.admin.core.model.XxlJobRegistry;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.dao.XxlJobGroupDao;
|
||||
import com.xxl.job.admin.dao.XxlJobInfoDao;
|
||||
import com.xxl.job.admin.dao.XxlJobRegistryDao;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.enums.RegistryConfig;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* job group controller
|
||||
* @author xuxueli 2016-10-02 20:52:56
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/jobgroup")
|
||||
public class JobGroupController {
|
||||
|
||||
@Resource
|
||||
public XxlJobInfoDao xxlJobInfoDao;
|
||||
@Resource
|
||||
public XxlJobGroupDao xxlJobGroupDao;
|
||||
@Resource
|
||||
private XxlJobRegistryDao xxlJobRegistryDao;
|
||||
|
||||
@RequestMapping
|
||||
public String index(Model model) {
|
||||
return "jobgroup/jobgroup.index";
|
||||
}
|
||||
|
||||
@RequestMapping("/pageList")
|
||||
@ResponseBody
|
||||
public Map<String, Object> pageList(HttpServletRequest request,
|
||||
@RequestParam(required = false, defaultValue = "0") int start,
|
||||
@RequestParam(required = false, defaultValue = "10") int length,
|
||||
String appname, String title) {
|
||||
|
||||
// page query
|
||||
List<XxlJobGroup> list = xxlJobGroupDao.pageList(start, length, appname, title);
|
||||
int list_count = xxlJobGroupDao.pageListCount(start, length, appname, title);
|
||||
|
||||
// package result
|
||||
Map<String, Object> maps = new HashMap<String, Object>();
|
||||
maps.put("recordsTotal", list_count); // 总记录数
|
||||
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
|
||||
maps.put("data", list); // 分页列表
|
||||
return maps;
|
||||
}
|
||||
|
||||
@RequestMapping("/save")
|
||||
@ResponseBody
|
||||
public ReturnT<String> save(XxlJobGroup xxlJobGroup){
|
||||
|
||||
// valid
|
||||
if (xxlJobGroup.getAppname()==null || xxlJobGroup.getAppname().trim().length()==0) {
|
||||
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
|
||||
}
|
||||
if (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appname_length") );
|
||||
}
|
||||
if (xxlJobGroup.getTitle()==null || xxlJobGroup.getTitle().trim().length()==0) {
|
||||
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
|
||||
}
|
||||
if (xxlJobGroup.getAddressType()!=0) {
|
||||
if (xxlJobGroup.getAddressList()==null || xxlJobGroup.getAddressList().trim().length()==0) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
|
||||
}
|
||||
String[] addresss = xxlJobGroup.getAddressList().split(",");
|
||||
for (String item: addresss) {
|
||||
if (item==null || item.trim().length()==0) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ret = xxlJobGroupDao.save(xxlJobGroup);
|
||||
return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
|
||||
}
|
||||
|
||||
@RequestMapping("/update")
|
||||
@ResponseBody
|
||||
public ReturnT<String> update(XxlJobGroup xxlJobGroup){
|
||||
// valid
|
||||
if (xxlJobGroup.getAppname()==null || xxlJobGroup.getAppname().trim().length()==0) {
|
||||
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
|
||||
}
|
||||
if (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appname_length") );
|
||||
}
|
||||
if (xxlJobGroup.getTitle()==null || xxlJobGroup.getTitle().trim().length()==0) {
|
||||
return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
|
||||
}
|
||||
if (xxlJobGroup.getAddressType() == 0) {
|
||||
// 0=自动注册
|
||||
List<String> registryList = findRegistryByAppName(xxlJobGroup.getAppname());
|
||||
String addressListStr = null;
|
||||
if (registryList!=null && !registryList.isEmpty()) {
|
||||
Collections.sort(registryList);
|
||||
addressListStr = "";
|
||||
for (String item:registryList) {
|
||||
addressListStr += item + ",";
|
||||
}
|
||||
addressListStr = addressListStr.substring(0, addressListStr.length()-1);
|
||||
}
|
||||
xxlJobGroup.setAddressList(addressListStr);
|
||||
} else {
|
||||
// 1=手动录入
|
||||
if (xxlJobGroup.getAddressList()==null || xxlJobGroup.getAddressList().trim().length()==0) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
|
||||
}
|
||||
String[] addresss = xxlJobGroup.getAddressList().split(",");
|
||||
for (String item: addresss) {
|
||||
if (item==null || item.trim().length()==0) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ret = xxlJobGroupDao.update(xxlJobGroup);
|
||||
return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
|
||||
}
|
||||
|
||||
private List<String> findRegistryByAppName(String appnameParam){
|
||||
HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
|
||||
List<XxlJobRegistry> list = xxlJobRegistryDao.findAll(RegistryConfig.DEAD_TIMEOUT, new Date());
|
||||
if (list != null) {
|
||||
for (XxlJobRegistry item: list) {
|
||||
if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
|
||||
String appname = item.getRegistryKey();
|
||||
List<String> registryList = appAddressMap.get(appname);
|
||||
if (registryList == null) {
|
||||
registryList = new ArrayList<String>();
|
||||
}
|
||||
|
||||
if (!registryList.contains(item.getRegistryValue())) {
|
||||
registryList.add(item.getRegistryValue());
|
||||
}
|
||||
appAddressMap.put(appname, registryList);
|
||||
}
|
||||
}
|
||||
}
|
||||
return appAddressMap.get(appnameParam);
|
||||
}
|
||||
|
||||
@RequestMapping("/remove")
|
||||
@ResponseBody
|
||||
public ReturnT<String> remove(int id){
|
||||
|
||||
// valid
|
||||
int count = xxlJobInfoDao.pageListCount(0, 10, id, -1, null, null, null);
|
||||
if (count > 0) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_0") );
|
||||
}
|
||||
|
||||
List<XxlJobGroup> allList = xxlJobGroupDao.findAll();
|
||||
if (allList.size() == 1) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_1") );
|
||||
}
|
||||
|
||||
int ret = xxlJobGroupDao.remove(id);
|
||||
return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
|
||||
}
|
||||
|
||||
@RequestMapping("/loadById")
|
||||
@ResponseBody
|
||||
public ReturnT<XxlJobGroup> loadById(int id){
|
||||
XxlJobGroup jobGroup = xxlJobGroupDao.load(id);
|
||||
return jobGroup!=null?new ReturnT<XxlJobGroup>(jobGroup):new ReturnT<XxlJobGroup>(ReturnT.FAIL_CODE, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package com.xxl.job.admin.controller;
|
||||
|
||||
import com.xxl.job.admin.core.cron.CronExpression;
|
||||
import com.xxl.job.admin.core.exception.XxlJobException;
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobUser;
|
||||
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
|
||||
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
|
||||
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.dao.XxlJobGroupDao;
|
||||
import com.xxl.job.admin.service.LoginService;
|
||||
import com.xxl.job.admin.service.XxlJobService;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
|
||||
import com.xxl.job.core.glue.GlueTypeEnum;
|
||||
import com.xxl.job.core.util.DateUtil;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* index controller
|
||||
* @author xuxueli 2015-12-19 16:13:16
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/jobinfo")
|
||||
public class JobInfoController {
|
||||
|
||||
@Resource
|
||||
private XxlJobGroupDao xxlJobGroupDao;
|
||||
@Resource
|
||||
private XxlJobService xxlJobService;
|
||||
|
||||
@RequestMapping
|
||||
public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
|
||||
|
||||
// 枚举-字典
|
||||
model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表
|
||||
model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); // Glue类型-字典
|
||||
model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values()); // 阻塞处理策略-字典
|
||||
|
||||
// 执行器列表
|
||||
List<XxlJobGroup> jobGroupList_all = xxlJobGroupDao.findAll();
|
||||
|
||||
// filter group
|
||||
List<XxlJobGroup> jobGroupList = filterJobGroupByRole(request, jobGroupList_all);
|
||||
if (jobGroupList==null || jobGroupList.size()==0) {
|
||||
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
|
||||
}
|
||||
|
||||
model.addAttribute("JobGroupList", jobGroupList);
|
||||
model.addAttribute("jobGroup", jobGroup);
|
||||
|
||||
return "jobinfo/jobinfo.index";
|
||||
}
|
||||
|
||||
public static List<XxlJobGroup> filterJobGroupByRole(HttpServletRequest request, List<XxlJobGroup> jobGroupList_all){
|
||||
List<XxlJobGroup> jobGroupList = new ArrayList<>();
|
||||
if (jobGroupList_all!=null && jobGroupList_all.size()>0) {
|
||||
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
|
||||
if (loginUser.getRole() == 1) {
|
||||
jobGroupList = jobGroupList_all;
|
||||
} else {
|
||||
List<String> groupIdStrs = new ArrayList<>();
|
||||
if (loginUser.getPermission()!=null && loginUser.getPermission().trim().length()>0) {
|
||||
groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
|
||||
}
|
||||
for (XxlJobGroup groupItem:jobGroupList_all) {
|
||||
if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
|
||||
jobGroupList.add(groupItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return jobGroupList;
|
||||
}
|
||||
public static void validPermission(HttpServletRequest request, int jobGroup) {
|
||||
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
|
||||
if (!loginUser.validPermission(jobGroup)) {
|
||||
throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username="+ loginUser.getUsername() +"]");
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/pageList")
|
||||
@ResponseBody
|
||||
public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
|
||||
@RequestParam(required = false, defaultValue = "10") int length,
|
||||
int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
|
||||
|
||||
return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
|
||||
}
|
||||
|
||||
@RequestMapping("/add")
|
||||
@ResponseBody
|
||||
public ReturnT<String> add(XxlJobInfo jobInfo) {
|
||||
return xxlJobService.add(jobInfo);
|
||||
}
|
||||
|
||||
@RequestMapping("/update")
|
||||
@ResponseBody
|
||||
public ReturnT<String> update(XxlJobInfo jobInfo) {
|
||||
return xxlJobService.update(jobInfo);
|
||||
}
|
||||
|
||||
@RequestMapping("/remove")
|
||||
@ResponseBody
|
||||
public ReturnT<String> remove(int id) {
|
||||
return xxlJobService.remove(id);
|
||||
}
|
||||
|
||||
@RequestMapping("/stop")
|
||||
@ResponseBody
|
||||
public ReturnT<String> pause(int id) {
|
||||
return xxlJobService.stop(id);
|
||||
}
|
||||
|
||||
@RequestMapping("/start")
|
||||
@ResponseBody
|
||||
public ReturnT<String> start(int id) {
|
||||
return xxlJobService.start(id);
|
||||
}
|
||||
|
||||
@RequestMapping("/trigger")
|
||||
@ResponseBody
|
||||
//@PermissionLimit(limit = false)
|
||||
public ReturnT<String> triggerJob(int id, String executorParam, String addressList) {
|
||||
// force cover job param
|
||||
if (executorParam == null) {
|
||||
executorParam = "";
|
||||
}
|
||||
|
||||
JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@RequestMapping("/nextTriggerTime")
|
||||
@ResponseBody
|
||||
public ReturnT<List<String>> nextTriggerTime(String cron) {
|
||||
List<String> result = new ArrayList<>();
|
||||
try {
|
||||
CronExpression cronExpression = new CronExpression(cron);
|
||||
Date lastTime = new Date();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
lastTime = cronExpression.getNextValidTimeAfter(lastTime);
|
||||
if (lastTime != null) {
|
||||
result.add(DateUtil.formatDateTime(lastTime));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
return new ReturnT<List<String>>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid"));
|
||||
}
|
||||
return new ReturnT<List<String>>(result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
package com.xxl.job.admin.controller;
|
||||
|
||||
import com.xxl.job.admin.core.exception.XxlJobException;
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.dao.XxlJobGroupDao;
|
||||
import com.xxl.job.admin.dao.XxlJobInfoDao;
|
||||
import com.xxl.job.admin.dao.XxlJobLogDao;
|
||||
import com.xxl.job.core.biz.ExecutorBiz;
|
||||
import com.xxl.job.core.biz.model.KillParam;
|
||||
import com.xxl.job.core.biz.model.LogParam;
|
||||
import com.xxl.job.core.biz.model.LogResult;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.util.DateUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* index controller
|
||||
* @author xuxueli 2015-12-19 16:13:16
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/joblog")
|
||||
public class JobLogController {
|
||||
private static Logger logger = LoggerFactory.getLogger(JobLogController.class);
|
||||
|
||||
@Resource
|
||||
private XxlJobGroupDao xxlJobGroupDao;
|
||||
@Resource
|
||||
public XxlJobInfoDao xxlJobInfoDao;
|
||||
@Resource
|
||||
public XxlJobLogDao xxlJobLogDao;
|
||||
|
||||
@RequestMapping
|
||||
public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "0") Integer jobId) {
|
||||
|
||||
// 执行器列表
|
||||
List<XxlJobGroup> jobGroupList_all = xxlJobGroupDao.findAll();
|
||||
|
||||
// filter group
|
||||
List<XxlJobGroup> jobGroupList = JobInfoController.filterJobGroupByRole(request, jobGroupList_all);
|
||||
if (jobGroupList==null || jobGroupList.size()==0) {
|
||||
throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
|
||||
}
|
||||
|
||||
model.addAttribute("JobGroupList", jobGroupList);
|
||||
|
||||
// 任务
|
||||
if (jobId > 0) {
|
||||
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId);
|
||||
if (jobInfo == null) {
|
||||
throw new RuntimeException(I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_unvalid"));
|
||||
}
|
||||
|
||||
model.addAttribute("jobInfo", jobInfo);
|
||||
|
||||
// valid permission
|
||||
JobInfoController.validPermission(request, jobInfo.getJobGroup());
|
||||
}
|
||||
|
||||
return "joblog/joblog.index";
|
||||
}
|
||||
|
||||
@RequestMapping("/getJobsByGroup")
|
||||
@ResponseBody
|
||||
public ReturnT<List<XxlJobInfo>> getJobsByGroup(int jobGroup){
|
||||
List<XxlJobInfo> list = xxlJobInfoDao.getJobsByGroup(jobGroup);
|
||||
return new ReturnT<List<XxlJobInfo>>(list);
|
||||
}
|
||||
|
||||
@RequestMapping("/pageList")
|
||||
@ResponseBody
|
||||
public Map<String, Object> pageList(HttpServletRequest request,
|
||||
@RequestParam(required = false, defaultValue = "0") int start,
|
||||
@RequestParam(required = false, defaultValue = "10") int length,
|
||||
int jobGroup, int jobId, int logStatus, String filterTime) {
|
||||
|
||||
// valid permission
|
||||
JobInfoController.validPermission(request, jobGroup); // 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup
|
||||
|
||||
// parse param
|
||||
Date triggerTimeStart = null;
|
||||
Date triggerTimeEnd = null;
|
||||
if (filterTime!=null && filterTime.trim().length()>0) {
|
||||
String[] temp = filterTime.split(" - ");
|
||||
if (temp.length == 2) {
|
||||
triggerTimeStart = DateUtil.parseDateTime(temp[0]);
|
||||
triggerTimeEnd = DateUtil.parseDateTime(temp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// page query
|
||||
List<XxlJobLog> list = xxlJobLogDao.pageList(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
|
||||
int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
|
||||
|
||||
// package result
|
||||
Map<String, Object> maps = new HashMap<String, Object>();
|
||||
maps.put("recordsTotal", list_count); // 总记录数
|
||||
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
|
||||
maps.put("data", list); // 分页列表
|
||||
return maps;
|
||||
}
|
||||
|
||||
@RequestMapping("/logDetailPage")
|
||||
public String logDetailPage(int id, Model model){
|
||||
|
||||
// base check
|
||||
ReturnT<String> logStatue = ReturnT.SUCCESS;
|
||||
XxlJobLog jobLog = xxlJobLogDao.load(id);
|
||||
if (jobLog == null) {
|
||||
throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
|
||||
}
|
||||
|
||||
model.addAttribute("triggerCode", jobLog.getTriggerCode());
|
||||
model.addAttribute("handleCode", jobLog.getHandleCode());
|
||||
model.addAttribute("executorAddress", jobLog.getExecutorAddress());
|
||||
model.addAttribute("triggerTime", jobLog.getTriggerTime().getTime());
|
||||
model.addAttribute("logId", jobLog.getId());
|
||||
return "joblog/joblog.detail";
|
||||
}
|
||||
|
||||
@RequestMapping("/logDetailCat")
|
||||
@ResponseBody
|
||||
public ReturnT<LogResult> logDetailCat(String executorAddress, long triggerTime, long logId, int fromLineNum){
|
||||
try {
|
||||
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(executorAddress);
|
||||
ReturnT<LogResult> logResult = executorBiz.log(new LogParam(triggerTime, logId, fromLineNum));
|
||||
|
||||
// is end
|
||||
if (logResult.getContent()!=null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
|
||||
XxlJobLog jobLog = xxlJobLogDao.load(logId);
|
||||
if (jobLog.getHandleCode() > 0) {
|
||||
logResult.getContent().setEnd(true);
|
||||
}
|
||||
}
|
||||
|
||||
return logResult;
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/logKill")
|
||||
@ResponseBody
|
||||
public ReturnT<String> logKill(int id){
|
||||
// base check
|
||||
XxlJobLog log = xxlJobLogDao.load(id);
|
||||
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId());
|
||||
if (jobInfo==null) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
|
||||
}
|
||||
if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("joblog_kill_log_limit"));
|
||||
}
|
||||
|
||||
// request of kill
|
||||
ReturnT<String> runResult = null;
|
||||
try {
|
||||
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(log.getExecutorAddress());
|
||||
runResult = executorBiz.kill(new KillParam(jobInfo.getId()));
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
runResult = new ReturnT<String>(500, e.getMessage());
|
||||
}
|
||||
|
||||
if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
|
||||
log.setHandleCode(ReturnT.FAIL_CODE);
|
||||
log.setHandleMsg( I18nUtil.getString("joblog_kill_log_byman")+":" + (runResult.getMsg()!=null?runResult.getMsg():""));
|
||||
log.setHandleTime(new Date());
|
||||
xxlJobLogDao.updateHandleInfo(log);
|
||||
return new ReturnT<String>(runResult.getMsg());
|
||||
} else {
|
||||
return new ReturnT<String>(500, runResult.getMsg());
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/clearLog")
|
||||
@ResponseBody
|
||||
public ReturnT<String> clearLog(int jobGroup, int jobId, int type){
|
||||
|
||||
Date clearBeforeTime = null;
|
||||
int clearBeforeNum = 0;
|
||||
if (type == 1) {
|
||||
clearBeforeTime = DateUtil.addMonths(new Date(), -1); // 清理一个月之前日志数据
|
||||
} else if (type == 2) {
|
||||
clearBeforeTime = DateUtil.addMonths(new Date(), -3); // 清理三个月之前日志数据
|
||||
} else if (type == 3) {
|
||||
clearBeforeTime = DateUtil.addMonths(new Date(), -6); // 清理六个月之前日志数据
|
||||
} else if (type == 4) {
|
||||
clearBeforeTime = DateUtil.addYears(new Date(), -1); // 清理一年之前日志数据
|
||||
} else if (type == 5) {
|
||||
clearBeforeNum = 1000; // 清理一千条以前日志数据
|
||||
} else if (type == 6) {
|
||||
clearBeforeNum = 10000; // 清理一万条以前日志数据
|
||||
} else if (type == 7) {
|
||||
clearBeforeNum = 30000; // 清理三万条以前日志数据
|
||||
} else if (type == 8) {
|
||||
clearBeforeNum = 100000; // 清理十万条以前日志数据
|
||||
} else if (type == 9) {
|
||||
clearBeforeNum = 0; // 清理所有日志数据
|
||||
} else {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_clean_type_unvalid"));
|
||||
}
|
||||
|
||||
List<Long> logIds = null;
|
||||
do {
|
||||
logIds = xxlJobLogDao.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000);
|
||||
if (logIds!=null && logIds.size()>0) {
|
||||
xxlJobLogDao.clearLog(logIds);
|
||||
}
|
||||
} while (logIds!=null && logIds.size()>0);
|
||||
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package com.xxl.job.admin.controller;
|
||||
|
||||
import com.xxl.job.admin.controller.annotation.PermissionLimit;
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import com.xxl.job.admin.core.model.XxlJobUser;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.dao.XxlJobGroupDao;
|
||||
import com.xxl.job.admin.dao.XxlJobUserDao;
|
||||
import com.xxl.job.admin.service.LoginService;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2019-05-04 16:39:50
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/user")
|
||||
public class UserController {
|
||||
|
||||
@Resource
|
||||
private XxlJobUserDao xxlJobUserDao;
|
||||
@Resource
|
||||
private XxlJobGroupDao xxlJobGroupDao;
|
||||
|
||||
@RequestMapping
|
||||
@PermissionLimit(adminuser = true)
|
||||
public String index(Model model) {
|
||||
|
||||
// 执行器列表
|
||||
List<XxlJobGroup> groupList = xxlJobGroupDao.findAll();
|
||||
model.addAttribute("groupList", groupList);
|
||||
|
||||
return "user/user.index";
|
||||
}
|
||||
|
||||
@RequestMapping("/pageList")
|
||||
@ResponseBody
|
||||
@PermissionLimit(adminuser = true)
|
||||
public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
|
||||
@RequestParam(required = false, defaultValue = "10") int length,
|
||||
String username, int role) {
|
||||
|
||||
// page list
|
||||
List<XxlJobUser> list = xxlJobUserDao.pageList(start, length, username, role);
|
||||
int list_count = xxlJobUserDao.pageListCount(start, length, username, role);
|
||||
|
||||
// package result
|
||||
Map<String, Object> maps = new HashMap<String, Object>();
|
||||
maps.put("recordsTotal", list_count); // 总记录数
|
||||
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
|
||||
maps.put("data", list); // 分页列表
|
||||
return maps;
|
||||
}
|
||||
|
||||
@RequestMapping("/add")
|
||||
@ResponseBody
|
||||
@PermissionLimit(adminuser = true)
|
||||
public ReturnT<String> add(XxlJobUser xxlJobUser) {
|
||||
|
||||
// valid username
|
||||
if (!StringUtils.hasText(xxlJobUser.getUsername())) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input")+I18nUtil.getString("user_username") );
|
||||
}
|
||||
xxlJobUser.setUsername(xxlJobUser.getUsername().trim());
|
||||
if (!(xxlJobUser.getUsername().length()>=4 && xxlJobUser.getUsername().length()<=20)) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
|
||||
}
|
||||
// valid password
|
||||
if (!StringUtils.hasText(xxlJobUser.getPassword())) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input")+I18nUtil.getString("user_password") );
|
||||
}
|
||||
xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
|
||||
if (!(xxlJobUser.getPassword().length()>=4 && xxlJobUser.getPassword().length()<=20)) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
|
||||
}
|
||||
// md5 password
|
||||
xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
|
||||
|
||||
// check repeat
|
||||
XxlJobUser existUser = xxlJobUserDao.loadByUserName(xxlJobUser.getUsername());
|
||||
if (existUser != null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("user_username_repeat") );
|
||||
}
|
||||
|
||||
// write
|
||||
xxlJobUserDao.save(xxlJobUser);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@RequestMapping("/update")
|
||||
@ResponseBody
|
||||
@PermissionLimit(adminuser = true)
|
||||
public ReturnT<String> update(HttpServletRequest request, XxlJobUser xxlJobUser) {
|
||||
|
||||
// avoid opt login seft
|
||||
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
|
||||
if (loginUser.getUsername().equals(xxlJobUser.getUsername())) {
|
||||
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
|
||||
}
|
||||
|
||||
// valid password
|
||||
if (StringUtils.hasText(xxlJobUser.getPassword())) {
|
||||
xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
|
||||
if (!(xxlJobUser.getPassword().length()>=4 && xxlJobUser.getPassword().length()<=20)) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
|
||||
}
|
||||
// md5 password
|
||||
xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
|
||||
} else {
|
||||
xxlJobUser.setPassword(null);
|
||||
}
|
||||
|
||||
// write
|
||||
xxlJobUserDao.update(xxlJobUser);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@RequestMapping("/remove")
|
||||
@ResponseBody
|
||||
@PermissionLimit(adminuser = true)
|
||||
public ReturnT<String> remove(HttpServletRequest request, int id) {
|
||||
|
||||
// avoid opt login seft
|
||||
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
|
||||
if (loginUser.getId() == id) {
|
||||
return new ReturnT<String>(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
|
||||
}
|
||||
|
||||
xxlJobUserDao.delete(id);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@RequestMapping("/updatePwd")
|
||||
@ResponseBody
|
||||
public ReturnT<String> updatePwd(HttpServletRequest request, String password){
|
||||
|
||||
// valid password
|
||||
if (password==null || password.trim().length()==0){
|
||||
return new ReturnT<String>(ReturnT.FAIL.getCode(), "密码不可为空");
|
||||
}
|
||||
password = password.trim();
|
||||
if (!(password.length()>=4 && password.length()<=20)) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
|
||||
}
|
||||
|
||||
// md5 password
|
||||
String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
|
||||
|
||||
// update pwd
|
||||
XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
|
||||
|
||||
// do write
|
||||
XxlJobUser existUser = xxlJobUserDao.loadByUserName(loginUser.getUsername());
|
||||
existUser.setPassword(md5Password);
|
||||
xxlJobUserDao.update(existUser);
|
||||
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.xxl.job.admin.controller.annotation;
|
||||
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 权限限制
|
||||
* @author xuxueli 2015-12-12 18:29:02
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PermissionLimit {
|
||||
|
||||
/**
|
||||
* 登录拦截 (默认拦截)
|
||||
*/
|
||||
boolean limit() default true;
|
||||
|
||||
/**
|
||||
* 要求管理员权限
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean adminuser() default false;
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.xxl.job.admin.controller.interceptor;
|
||||
|
||||
import com.xxl.job.admin.core.util.FtlUtil;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* push cookies to model as cookieMap
|
||||
*
|
||||
* @author xuxueli 2015-12-12 18:09:04
|
||||
*/
|
||||
@Component
|
||||
public class CookieInterceptor extends HandlerInterceptorAdapter {
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
ModelAndView modelAndView) throws Exception {
|
||||
|
||||
// cookie
|
||||
if (modelAndView!=null && request.getCookies()!=null && request.getCookies().length>0) {
|
||||
HashMap<String, Cookie> cookieMap = new HashMap<String, Cookie>();
|
||||
for (Cookie ck : request.getCookies()) {
|
||||
cookieMap.put(ck.getName(), ck);
|
||||
}
|
||||
modelAndView.addObject("cookieMap", cookieMap);
|
||||
}
|
||||
|
||||
// static method
|
||||
if (modelAndView != null) {
|
||||
modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName()));
|
||||
}
|
||||
|
||||
super.postHandle(request, response, handler, modelAndView);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.xxl.job.admin.controller.interceptor;
|
||||
|
||||
import com.xxl.job.admin.controller.annotation.PermissionLimit;
|
||||
import com.xxl.job.admin.core.model.XxlJobUser;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.service.LoginService;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 权限拦截
|
||||
*
|
||||
* @author xuxueli 2015-12-12 18:09:04
|
||||
*/
|
||||
@Component
|
||||
public class PermissionInterceptor extends HandlerInterceptorAdapter {
|
||||
|
||||
@Resource
|
||||
private LoginService loginService;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
|
||||
if (!(handler instanceof HandlerMethod)) {
|
||||
return super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
// if need login
|
||||
boolean needLogin = true;
|
||||
boolean needAdminuser = false;
|
||||
HandlerMethod method = (HandlerMethod)handler;
|
||||
PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class);
|
||||
if (permission!=null) {
|
||||
needLogin = permission.limit();
|
||||
needAdminuser = permission.adminuser();
|
||||
}
|
||||
|
||||
if (needLogin) {
|
||||
XxlJobUser loginUser = loginService.ifLogin(request, response);
|
||||
if (loginUser == null) {
|
||||
response.sendRedirect(request.getContextPath() + "/toLogin");
|
||||
//request.getRequestDispatcher("/toLogin").forward(request, response);
|
||||
return false;
|
||||
}
|
||||
if (needAdminuser && loginUser.getRole()!=1) {
|
||||
throw new RuntimeException(I18nUtil.getString("system_permission_limit"));
|
||||
}
|
||||
request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
|
||||
}
|
||||
|
||||
return super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.xxl.job.admin.controller.interceptor;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* web mvc config
|
||||
*
|
||||
* @author xuxueli 2018-04-02 20:48:20
|
||||
*/
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
@Resource
|
||||
private PermissionInterceptor permissionInterceptor;
|
||||
@Resource
|
||||
private CookieInterceptor cookieInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
|
||||
registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.xxl.job.admin.controller.resolver;
|
||||
|
||||
import com.xxl.job.admin.core.exception.XxlJobException;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.admin.core.util.JacksonUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* common exception resolver
|
||||
*
|
||||
* @author xuxueli 2016-1-6 19:22:18
|
||||
*/
|
||||
@Component
|
||||
public class WebExceptionResolver implements HandlerExceptionResolver {
|
||||
private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveException(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler, Exception ex) {
|
||||
|
||||
if (!(ex instanceof XxlJobException)) {
|
||||
logger.error("WebExceptionResolver:{}", ex);
|
||||
}
|
||||
|
||||
// if json
|
||||
boolean isJson = false;
|
||||
HandlerMethod method = (HandlerMethod)handler;
|
||||
ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
|
||||
if (responseBody != null) {
|
||||
isJson = true;
|
||||
}
|
||||
|
||||
// error result
|
||||
ReturnT<String> errorResult = new ReturnT<String>(ReturnT.FAIL_CODE, ex.toString().replaceAll("\n", "<br/>"));
|
||||
|
||||
// response
|
||||
ModelAndView mv = new ModelAndView();
|
||||
if (isJson) {
|
||||
try {
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.getWriter().print(JacksonUtil.writeValueAsString(errorResult));
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return mv;
|
||||
} else {
|
||||
|
||||
mv.addObject("exceptionMsg", errorResult.getMsg());
|
||||
mv.setViewName("/common/common.exception");
|
||||
return mv;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.xxl.job.admin.core.alarm;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2020-01-19
|
||||
*/
|
||||
public interface JobAlarm {
|
||||
|
||||
/**
|
||||
* job alarm
|
||||
*
|
||||
* @param info
|
||||
* @param jobLog
|
||||
* @return
|
||||
*/
|
||||
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog);
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.xxl.job.admin.core.alarm;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class JobAlarmer implements ApplicationContextAware, InitializingBean {
|
||||
private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class);
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
private List<JobAlarm> jobAlarmList;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Map<String, JobAlarm> serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class);
|
||||
if (serviceBeanMap != null && serviceBeanMap.size() > 0) {
|
||||
jobAlarmList = new ArrayList<JobAlarm>(serviceBeanMap.values());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* job alarm
|
||||
*
|
||||
* @param info
|
||||
* @param jobLog
|
||||
* @return
|
||||
*/
|
||||
public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) {
|
||||
|
||||
boolean result = false;
|
||||
if (jobAlarmList!=null && jobAlarmList.size()>0) {
|
||||
result = true; // success means all-success
|
||||
for (JobAlarm alarm: jobAlarmList) {
|
||||
boolean resultItem = false;
|
||||
try {
|
||||
resultItem = alarm.doAlarm(info, jobLog);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
if (!resultItem) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package com.xxl.job.admin.core.alarm.impl;
|
||||
|
||||
import com.xxl.job.admin.core.alarm.JobAlarm;
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* job alarm by email
|
||||
*
|
||||
* @author xuxueli 2020-01-19
|
||||
*/
|
||||
@Component
|
||||
public class EmailJobAlarm implements JobAlarm {
|
||||
private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class);
|
||||
|
||||
/**
|
||||
* fail alarm
|
||||
*
|
||||
* @param jobLog
|
||||
*/
|
||||
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog){
|
||||
boolean alarmResult = true;
|
||||
|
||||
// send monitor email
|
||||
if (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) {
|
||||
|
||||
// alarmContent
|
||||
String alarmContent = "Alarm Job LogId=" + jobLog.getId();
|
||||
if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) {
|
||||
alarmContent += "<br>TriggerMsg=<br>" + jobLog.getTriggerMsg();
|
||||
}
|
||||
if (jobLog.getHandleCode()>0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) {
|
||||
alarmContent += "<br>HandleCode=" + jobLog.getHandleMsg();
|
||||
}
|
||||
|
||||
// email info
|
||||
XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup()));
|
||||
String personal = I18nUtil.getString("admin_name_full");
|
||||
String title = I18nUtil.getString("jobconf_monitor");
|
||||
String content = MessageFormat.format(loadEmailJobAlarmTemplate(),
|
||||
group!=null?group.getTitle():"null",
|
||||
info.getId(),
|
||||
info.getJobDesc(),
|
||||
alarmContent);
|
||||
|
||||
Set<String> emailSet = new HashSet<String>(Arrays.asList(info.getAlarmEmail().split(",")));
|
||||
for (String email: emailSet) {
|
||||
|
||||
// make mail
|
||||
try {
|
||||
MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage();
|
||||
|
||||
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
|
||||
helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailUserName(), personal);
|
||||
helper.setTo(email);
|
||||
helper.setSubject(title);
|
||||
helper.setText(content, true);
|
||||
|
||||
XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage);
|
||||
} catch (Exception e) {
|
||||
logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e);
|
||||
|
||||
alarmResult = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return alarmResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* load email job alarm template
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static final String loadEmailJobAlarmTemplate(){
|
||||
String mailBodyTemplate = "<h5>" + I18nUtil.getString("jobconf_monitor_detail") + ":</span>" +
|
||||
"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +
|
||||
" <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
|
||||
" <tr>\n" +
|
||||
" <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobgroup") +"</td>\n" +
|
||||
" <td width=\"10%\" >"+ I18nUtil.getString("jobinfo_field_id") +"</td>\n" +
|
||||
" <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobdesc") +"</td>\n" +
|
||||
" <td width=\"10%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_title") +"</td>\n" +
|
||||
" <td width=\"40%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_content") +"</td>\n" +
|
||||
" </tr>\n" +
|
||||
" </thead>\n" +
|
||||
" <tbody>\n" +
|
||||
" <tr>\n" +
|
||||
" <td>{0}</td>\n" +
|
||||
" <td>{1}</td>\n" +
|
||||
" <td>{2}</td>\n" +
|
||||
" <td>"+ I18nUtil.getString("jobconf_monitor_alarm_type") +"</td>\n" +
|
||||
" <td>{3}</td>\n" +
|
||||
" </tr>\n" +
|
||||
" </tbody>\n" +
|
||||
"</table>";
|
||||
|
||||
return mailBodyTemplate;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
package com.xxl.job.admin.core.conf;
|
||||
|
||||
import com.xxl.job.admin.core.alarm.JobAlarmer;
|
||||
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
|
||||
import com.xxl.job.admin.dao.*;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* xxl-job config
|
||||
*
|
||||
* @author xuxueli 2017-04-28
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
|
||||
|
||||
private static XxlJobAdminConfig adminConfig = null;
|
||||
public static XxlJobAdminConfig getAdminConfig() {
|
||||
return adminConfig;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------- XxlJobScheduler ----------------------
|
||||
|
||||
private XxlJobScheduler xxlJobScheduler;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
adminConfig = this;
|
||||
|
||||
xxlJobScheduler = new XxlJobScheduler();
|
||||
xxlJobScheduler.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
xxlJobScheduler.destroy();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------- XxlJobScheduler ----------------------
|
||||
|
||||
// conf
|
||||
@Value("${xxl.job.i18n}")
|
||||
private String i18n;
|
||||
|
||||
@Value("${xxl.job.accessToken}")
|
||||
private String accessToken;
|
||||
|
||||
@Value("${spring.mail.username}")
|
||||
private String emailUserName;
|
||||
|
||||
@Value("${xxl.job.triggerpool.fast.max}")
|
||||
private int triggerPoolFastMax;
|
||||
|
||||
@Value("${xxl.job.triggerpool.slow.max}")
|
||||
private int triggerPoolSlowMax;
|
||||
|
||||
@Value("${xxl.job.logretentiondays}")
|
||||
private int logretentiondays;
|
||||
|
||||
// dao, service
|
||||
|
||||
@Resource
|
||||
private XxlJobLogDao xxlJobLogDao;
|
||||
@Resource
|
||||
private XxlJobInfoDao xxlJobInfoDao;
|
||||
@Resource
|
||||
private XxlJobRegistryDao xxlJobRegistryDao;
|
||||
@Resource
|
||||
private XxlJobGroupDao xxlJobGroupDao;
|
||||
@Resource
|
||||
private XxlJobLogReportDao xxlJobLogReportDao;
|
||||
@Resource
|
||||
private JavaMailSender mailSender;
|
||||
@Resource
|
||||
private DataSource dataSource;
|
||||
@Resource
|
||||
private JobAlarmer jobAlarmer;
|
||||
|
||||
|
||||
public String getI18n() {
|
||||
if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) {
|
||||
return "zh_CN";
|
||||
}
|
||||
return i18n;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public String getEmailUserName() {
|
||||
return emailUserName;
|
||||
}
|
||||
|
||||
public int getTriggerPoolFastMax() {
|
||||
if (triggerPoolFastMax < 200) {
|
||||
return 200;
|
||||
}
|
||||
return triggerPoolFastMax;
|
||||
}
|
||||
|
||||
public int getTriggerPoolSlowMax() {
|
||||
if (triggerPoolSlowMax < 100) {
|
||||
return 100;
|
||||
}
|
||||
return triggerPoolSlowMax;
|
||||
}
|
||||
|
||||
public int getLogretentiondays() {
|
||||
if (logretentiondays < 7) {
|
||||
return -1; // Limit greater than or equal to 7, otherwise close
|
||||
}
|
||||
return logretentiondays;
|
||||
}
|
||||
|
||||
public XxlJobLogDao getXxlJobLogDao() {
|
||||
return xxlJobLogDao;
|
||||
}
|
||||
|
||||
public XxlJobInfoDao getXxlJobInfoDao() {
|
||||
return xxlJobInfoDao;
|
||||
}
|
||||
|
||||
public XxlJobRegistryDao getXxlJobRegistryDao() {
|
||||
return xxlJobRegistryDao;
|
||||
}
|
||||
|
||||
public XxlJobGroupDao getXxlJobGroupDao() {
|
||||
return xxlJobGroupDao;
|
||||
}
|
||||
|
||||
public XxlJobLogReportDao getXxlJobLogReportDao() {
|
||||
return xxlJobLogReportDao;
|
||||
}
|
||||
|
||||
public JavaMailSender getMailSender() {
|
||||
return mailSender;
|
||||
}
|
||||
|
||||
public DataSource getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public JobAlarmer getJobAlarmer() {
|
||||
return jobAlarmer;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,14 @@
|
|||
package com.xxl.job.admin.core.exception;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2019-05-04 23:19:29
|
||||
*/
|
||||
public class XxlJobException extends RuntimeException {
|
||||
|
||||
public XxlJobException() {
|
||||
}
|
||||
public XxlJobException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.xxl.job.admin.core.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 16/9/30.
|
||||
*/
|
||||
public class XxlJobGroup {
|
||||
|
||||
private int id;
|
||||
private String appname;
|
||||
private String title;
|
||||
private int addressType; // 执行器地址类型:0=自动注册、1=手动录入
|
||||
private String addressList; // 执行器地址列表,多地址逗号分隔(手动录入)
|
||||
|
||||
// registry list
|
||||
private List<String> registryList; // 执行器地址列表(系统注册)
|
||||
public List<String> getRegistryList() {
|
||||
if (addressList!=null && addressList.trim().length()>0) {
|
||||
registryList = new ArrayList<String>(Arrays.asList(addressList.split(",")));
|
||||
}
|
||||
return registryList;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAppname() {
|
||||
return appname;
|
||||
}
|
||||
|
||||
public void setAppname(String appname) {
|
||||
this.appname = appname;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public int getAddressType() {
|
||||
return addressType;
|
||||
}
|
||||
|
||||
public void setAddressType(int addressType) {
|
||||
this.addressType = addressType;
|
||||
}
|
||||
|
||||
public String getAddressList() {
|
||||
return addressList;
|
||||
}
|
||||
|
||||
public void setAddressList(String addressList) {
|
||||
this.addressList = addressList;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
package com.xxl.job.admin.core.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* xxl-job info
|
||||
*
|
||||
* @author xuxueli 2016-1-12 18:25:49
|
||||
*/
|
||||
public class XxlJobInfo {
|
||||
|
||||
private int id; // 主键ID
|
||||
|
||||
private int jobGroup; // 执行器主键ID
|
||||
private String jobCron; // 任务执行CRON表达式
|
||||
private String jobDesc;
|
||||
|
||||
private Date addTime;
|
||||
private Date updateTime;
|
||||
|
||||
private String author; // 负责人
|
||||
private String alarmEmail; // 报警邮件
|
||||
|
||||
private String executorRouteStrategy; // 执行器路由策略
|
||||
private String executorHandler; // 执行器,任务Handler名称
|
||||
private String executorParam; // 执行器,任务参数
|
||||
private String executorBlockStrategy; // 阻塞处理策略
|
||||
private int executorTimeout; // 任务执行超时时间,单位秒
|
||||
private int executorFailRetryCount; // 失败重试次数
|
||||
|
||||
private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum
|
||||
private String glueSource; // GLUE源代码
|
||||
private String glueRemark; // GLUE备注
|
||||
private Date glueUpdatetime; // GLUE更新时间
|
||||
|
||||
private String childJobId; // 子任务ID,多个逗号分隔
|
||||
|
||||
private int triggerStatus; // 调度状态:0-停止,1-运行
|
||||
private long triggerLastTime; // 上次调度时间
|
||||
private long triggerNextTime; // 下次调度时间
|
||||
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getJobGroup() {
|
||||
return jobGroup;
|
||||
}
|
||||
|
||||
public void setJobGroup(int jobGroup) {
|
||||
this.jobGroup = jobGroup;
|
||||
}
|
||||
|
||||
public String getJobCron() {
|
||||
return jobCron;
|
||||
}
|
||||
|
||||
public void setJobCron(String jobCron) {
|
||||
this.jobCron = jobCron;
|
||||
}
|
||||
|
||||
public String getJobDesc() {
|
||||
return jobDesc;
|
||||
}
|
||||
|
||||
public void setJobDesc(String jobDesc) {
|
||||
this.jobDesc = jobDesc;
|
||||
}
|
||||
|
||||
public Date getAddTime() {
|
||||
return addTime;
|
||||
}
|
||||
|
||||
public void setAddTime(Date addTime) {
|
||||
this.addTime = addTime;
|
||||
}
|
||||
|
||||
public Date getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getAlarmEmail() {
|
||||
return alarmEmail;
|
||||
}
|
||||
|
||||
public void setAlarmEmail(String alarmEmail) {
|
||||
this.alarmEmail = alarmEmail;
|
||||
}
|
||||
|
||||
public String getExecutorRouteStrategy() {
|
||||
return executorRouteStrategy;
|
||||
}
|
||||
|
||||
public void setExecutorRouteStrategy(String executorRouteStrategy) {
|
||||
this.executorRouteStrategy = executorRouteStrategy;
|
||||
}
|
||||
|
||||
public String getExecutorHandler() {
|
||||
return executorHandler;
|
||||
}
|
||||
|
||||
public void setExecutorHandler(String executorHandler) {
|
||||
this.executorHandler = executorHandler;
|
||||
}
|
||||
|
||||
public String getExecutorParam() {
|
||||
return executorParam;
|
||||
}
|
||||
|
||||
public void setExecutorParam(String executorParam) {
|
||||
this.executorParam = executorParam;
|
||||
}
|
||||
|
||||
public String getExecutorBlockStrategy() {
|
||||
return executorBlockStrategy;
|
||||
}
|
||||
|
||||
public void setExecutorBlockStrategy(String executorBlockStrategy) {
|
||||
this.executorBlockStrategy = executorBlockStrategy;
|
||||
}
|
||||
|
||||
public int getExecutorTimeout() {
|
||||
return executorTimeout;
|
||||
}
|
||||
|
||||
public void setExecutorTimeout(int executorTimeout) {
|
||||
this.executorTimeout = executorTimeout;
|
||||
}
|
||||
|
||||
public int getExecutorFailRetryCount() {
|
||||
return executorFailRetryCount;
|
||||
}
|
||||
|
||||
public void setExecutorFailRetryCount(int executorFailRetryCount) {
|
||||
this.executorFailRetryCount = executorFailRetryCount;
|
||||
}
|
||||
|
||||
public String getGlueType() {
|
||||
return glueType;
|
||||
}
|
||||
|
||||
public void setGlueType(String glueType) {
|
||||
this.glueType = glueType;
|
||||
}
|
||||
|
||||
public String getGlueSource() {
|
||||
return glueSource;
|
||||
}
|
||||
|
||||
public void setGlueSource(String glueSource) {
|
||||
this.glueSource = glueSource;
|
||||
}
|
||||
|
||||
public String getGlueRemark() {
|
||||
return glueRemark;
|
||||
}
|
||||
|
||||
public void setGlueRemark(String glueRemark) {
|
||||
this.glueRemark = glueRemark;
|
||||
}
|
||||
|
||||
public Date getGlueUpdatetime() {
|
||||
return glueUpdatetime;
|
||||
}
|
||||
|
||||
public void setGlueUpdatetime(Date glueUpdatetime) {
|
||||
this.glueUpdatetime = glueUpdatetime;
|
||||
}
|
||||
|
||||
public String getChildJobId() {
|
||||
return childJobId;
|
||||
}
|
||||
|
||||
public void setChildJobId(String childJobId) {
|
||||
this.childJobId = childJobId;
|
||||
}
|
||||
|
||||
public int getTriggerStatus() {
|
||||
return triggerStatus;
|
||||
}
|
||||
|
||||
public void setTriggerStatus(int triggerStatus) {
|
||||
this.triggerStatus = triggerStatus;
|
||||
}
|
||||
|
||||
public long getTriggerLastTime() {
|
||||
return triggerLastTime;
|
||||
}
|
||||
|
||||
public void setTriggerLastTime(long triggerLastTime) {
|
||||
this.triggerLastTime = triggerLastTime;
|
||||
}
|
||||
|
||||
public long getTriggerNextTime() {
|
||||
return triggerNextTime;
|
||||
}
|
||||
|
||||
public void setTriggerNextTime(long triggerNextTime) {
|
||||
this.triggerNextTime = triggerNextTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
package com.xxl.job.admin.core.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* xxl-job log, used to track trigger process
|
||||
* @author xuxueli 2015-12-19 23:19:09
|
||||
*/
|
||||
public class XxlJobLog {
|
||||
|
||||
private long id;
|
||||
|
||||
// job info
|
||||
private int jobGroup;
|
||||
private int jobId;
|
||||
|
||||
// execute info
|
||||
private String executorAddress;
|
||||
private String executorHandler;
|
||||
private String executorParam;
|
||||
private String executorShardingParam;
|
||||
private int executorFailRetryCount;
|
||||
|
||||
// trigger info
|
||||
private Date triggerTime;
|
||||
private int triggerCode;
|
||||
private String triggerMsg;
|
||||
|
||||
// handle info
|
||||
private Date handleTime;
|
||||
private int handleCode;
|
||||
private String handleMsg;
|
||||
|
||||
// alarm info
|
||||
private int alarmStatus;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getJobGroup() {
|
||||
return jobGroup;
|
||||
}
|
||||
|
||||
public void setJobGroup(int jobGroup) {
|
||||
this.jobGroup = jobGroup;
|
||||
}
|
||||
|
||||
public int getJobId() {
|
||||
return jobId;
|
||||
}
|
||||
|
||||
public void setJobId(int jobId) {
|
||||
this.jobId = jobId;
|
||||
}
|
||||
|
||||
public String getExecutorAddress() {
|
||||
return executorAddress;
|
||||
}
|
||||
|
||||
public void setExecutorAddress(String executorAddress) {
|
||||
this.executorAddress = executorAddress;
|
||||
}
|
||||
|
||||
public String getExecutorHandler() {
|
||||
return executorHandler;
|
||||
}
|
||||
|
||||
public void setExecutorHandler(String executorHandler) {
|
||||
this.executorHandler = executorHandler;
|
||||
}
|
||||
|
||||
public String getExecutorParam() {
|
||||
return executorParam;
|
||||
}
|
||||
|
||||
public void setExecutorParam(String executorParam) {
|
||||
this.executorParam = executorParam;
|
||||
}
|
||||
|
||||
public String getExecutorShardingParam() {
|
||||
return executorShardingParam;
|
||||
}
|
||||
|
||||
public void setExecutorShardingParam(String executorShardingParam) {
|
||||
this.executorShardingParam = executorShardingParam;
|
||||
}
|
||||
|
||||
public int getExecutorFailRetryCount() {
|
||||
return executorFailRetryCount;
|
||||
}
|
||||
|
||||
public void setExecutorFailRetryCount(int executorFailRetryCount) {
|
||||
this.executorFailRetryCount = executorFailRetryCount;
|
||||
}
|
||||
|
||||
public Date getTriggerTime() {
|
||||
return triggerTime;
|
||||
}
|
||||
|
||||
public void setTriggerTime(Date triggerTime) {
|
||||
this.triggerTime = triggerTime;
|
||||
}
|
||||
|
||||
public int getTriggerCode() {
|
||||
return triggerCode;
|
||||
}
|
||||
|
||||
public void setTriggerCode(int triggerCode) {
|
||||
this.triggerCode = triggerCode;
|
||||
}
|
||||
|
||||
public String getTriggerMsg() {
|
||||
return triggerMsg;
|
||||
}
|
||||
|
||||
public void setTriggerMsg(String triggerMsg) {
|
||||
this.triggerMsg = triggerMsg;
|
||||
}
|
||||
|
||||
public Date getHandleTime() {
|
||||
return handleTime;
|
||||
}
|
||||
|
||||
public void setHandleTime(Date handleTime) {
|
||||
this.handleTime = handleTime;
|
||||
}
|
||||
|
||||
public int getHandleCode() {
|
||||
return handleCode;
|
||||
}
|
||||
|
||||
public void setHandleCode(int handleCode) {
|
||||
this.handleCode = handleCode;
|
||||
}
|
||||
|
||||
public String getHandleMsg() {
|
||||
return handleMsg;
|
||||
}
|
||||
|
||||
public void setHandleMsg(String handleMsg) {
|
||||
this.handleMsg = handleMsg;
|
||||
}
|
||||
|
||||
public int getAlarmStatus() {
|
||||
return alarmStatus;
|
||||
}
|
||||
|
||||
public void setAlarmStatus(int alarmStatus) {
|
||||
this.alarmStatus = alarmStatus;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.xxl.job.admin.core.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* xxl-job log for glue, used to track job code process
|
||||
* @author xuxueli 2016-5-19 17:57:46
|
||||
*/
|
||||
public class XxlJobLogGlue {
|
||||
|
||||
private int id;
|
||||
private int jobId; // 任务主键ID
|
||||
private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum
|
||||
private String glueSource;
|
||||
private String glueRemark;
|
||||
private Date addTime;
|
||||
private Date updateTime;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getJobId() {
|
||||
return jobId;
|
||||
}
|
||||
|
||||
public void setJobId(int jobId) {
|
||||
this.jobId = jobId;
|
||||
}
|
||||
|
||||
public String getGlueType() {
|
||||
return glueType;
|
||||
}
|
||||
|
||||
public void setGlueType(String glueType) {
|
||||
this.glueType = glueType;
|
||||
}
|
||||
|
||||
public String getGlueSource() {
|
||||
return glueSource;
|
||||
}
|
||||
|
||||
public void setGlueSource(String glueSource) {
|
||||
this.glueSource = glueSource;
|
||||
}
|
||||
|
||||
public String getGlueRemark() {
|
||||
return glueRemark;
|
||||
}
|
||||
|
||||
public void setGlueRemark(String glueRemark) {
|
||||
this.glueRemark = glueRemark;
|
||||
}
|
||||
|
||||
public Date getAddTime() {
|
||||
return addTime;
|
||||
}
|
||||
|
||||
public void setAddTime(Date addTime) {
|
||||
this.addTime = addTime;
|
||||
}
|
||||
|
||||
public Date getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.xxl.job.admin.core.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class XxlJobLogReport {
|
||||
|
||||
private int id;
|
||||
|
||||
private Date triggerDay;
|
||||
|
||||
private int runningCount;
|
||||
private int sucCount;
|
||||
private int failCount;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getTriggerDay() {
|
||||
return triggerDay;
|
||||
}
|
||||
|
||||
public void setTriggerDay(Date triggerDay) {
|
||||
this.triggerDay = triggerDay;
|
||||
}
|
||||
|
||||
public int getRunningCount() {
|
||||
return runningCount;
|
||||
}
|
||||
|
||||
public void setRunningCount(int runningCount) {
|
||||
this.runningCount = runningCount;
|
||||
}
|
||||
|
||||
public int getSucCount() {
|
||||
return sucCount;
|
||||
}
|
||||
|
||||
public void setSucCount(int sucCount) {
|
||||
this.sucCount = sucCount;
|
||||
}
|
||||
|
||||
public int getFailCount() {
|
||||
return failCount;
|
||||
}
|
||||
|
||||
public void setFailCount(int failCount) {
|
||||
this.failCount = failCount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.xxl.job.admin.core.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 16/9/30.
|
||||
*/
|
||||
public class XxlJobRegistry {
|
||||
|
||||
private int id;
|
||||
private String registryGroup;
|
||||
private String registryKey;
|
||||
private String registryValue;
|
||||
private Date updateTime;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getRegistryGroup() {
|
||||
return registryGroup;
|
||||
}
|
||||
|
||||
public void setRegistryGroup(String registryGroup) {
|
||||
this.registryGroup = registryGroup;
|
||||
}
|
||||
|
||||
public String getRegistryKey() {
|
||||
return registryKey;
|
||||
}
|
||||
|
||||
public void setRegistryKey(String registryKey) {
|
||||
this.registryKey = registryKey;
|
||||
}
|
||||
|
||||
public String getRegistryValue() {
|
||||
return registryValue;
|
||||
}
|
||||
|
||||
public void setRegistryValue(String registryValue) {
|
||||
this.registryValue = registryValue;
|
||||
}
|
||||
|
||||
public Date getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.xxl.job.admin.core.model;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2019-05-04 16:43:12
|
||||
*/
|
||||
public class XxlJobUser {
|
||||
|
||||
private int id;
|
||||
private String username; // 账号
|
||||
private String password; // 密码
|
||||
private int role; // 角色:0-普通用户、1-管理员
|
||||
private String permission; // 权限:执行器ID列表,多个逗号分割
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public int getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(int role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public void setPermission(String permission) {
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
// plugin
|
||||
public boolean validPermission(int jobGroup){
|
||||
if (this.role == 1) {
|
||||
return true;
|
||||
} else {
|
||||
if (StringUtils.hasText(this.permission)) {
|
||||
for (String permissionItem : this.permission.split(",")) {
|
||||
if (String.valueOf(jobGroup).equals(permissionItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//package com.xxl.job.admin.core.jobbean;
|
||||
//
|
||||
//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
|
||||
//import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
|
||||
//import org.quartz.JobExecutionContext;
|
||||
//import org.quartz.JobExecutionException;
|
||||
//import org.quartz.JobKey;
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
//
|
||||
///**
|
||||
// * http job bean
|
||||
// * “@DisallowConcurrentExecution” disable concurrent, thread size can not be only one, better given more
|
||||
// * @author xuxueli 2015-12-17 18:20:34
|
||||
// */
|
||||
////@DisallowConcurrentExecution
|
||||
//public class RemoteHttpJobBean extends QuartzJobBean {
|
||||
// private static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class);
|
||||
//
|
||||
// @Override
|
||||
// protected void executeInternal(JobExecutionContext context)
|
||||
// throws JobExecutionException {
|
||||
//
|
||||
// // load jobId
|
||||
// JobKey jobKey = context.getTrigger().getJobKey();
|
||||
// Integer jobId = Integer.valueOf(jobKey.getName());
|
||||
//
|
||||
//
|
||||
// }
|
||||
//
|
||||
//}
|
|
@ -0,0 +1,413 @@
|
|||
//package com.xxl.job.admin.core.schedule;
|
||||
//
|
||||
//import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
//import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean;
|
||||
//import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
//import com.xxl.job.admin.core.thread.JobFailMonitorHelper;
|
||||
//import com.xxl.job.admin.core.thread.JobRegistryMonitorHelper;
|
||||
//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
|
||||
//import com.xxl.job.admin.core.util.I18nUtil;
|
||||
//import com.xxl.job.core.biz.AdminBiz;
|
||||
//import com.xxl.job.core.biz.ExecutorBiz;
|
||||
//import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
|
||||
//import com.xxl.rpc.remoting.invoker.XxlRpcInvokerFactory;
|
||||
//import com.xxl.rpc.remoting.invoker.call.CallType;
|
||||
//import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean;
|
||||
//import com.xxl.rpc.remoting.invoker.route.LoadBalance;
|
||||
//import com.xxl.rpc.remoting.net.NetEnum;
|
||||
//import com.xxl.rpc.remoting.net.impl.servlet.server.ServletServerHandler;
|
||||
//import com.xxl.rpc.remoting.provider.XxlRpcProviderFactory;
|
||||
//import com.xxl.rpc.serialize.Serializer;
|
||||
//import org.quartz.*;
|
||||
//import org.quartz.Trigger.TriggerState;
|
||||
//import org.quartz.impl.triggers.CronTriggerImpl;
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import org.springframework.util.Assert;
|
||||
//
|
||||
//import javax.servlet.ServletException;
|
||||
//import javax.servlet.http.HttpServletRequest;
|
||||
//import javax.servlet.http.HttpServletResponse;
|
||||
//import java.io.IOException;
|
||||
//import java.util.Date;
|
||||
//import java.util.concurrent.ConcurrentHashMap;
|
||||
//
|
||||
///**
|
||||
// * base quartz scheduler util
|
||||
// * @author xuxueli 2015-12-19 16:13:53
|
||||
// */
|
||||
//public final class XxlJobDynamicScheduler {
|
||||
// private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler_old.class);
|
||||
//
|
||||
// // ---------------------- param ----------------------
|
||||
//
|
||||
// // scheduler
|
||||
// private static Scheduler scheduler;
|
||||
// public void setScheduler(Scheduler scheduler) {
|
||||
// XxlJobDynamicScheduler_old.scheduler = scheduler;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // ---------------------- init + destroy ----------------------
|
||||
// public void start() throws Exception {
|
||||
// // valid
|
||||
// Assert.notNull(scheduler, "quartz scheduler is null");
|
||||
//
|
||||
// // init i18n
|
||||
// initI18n();
|
||||
//
|
||||
// // admin registry monitor run
|
||||
// JobRegistryMonitorHelper.getInstance().start();
|
||||
//
|
||||
// // admin monitor run
|
||||
// JobFailMonitorHelper.getInstance().start();
|
||||
//
|
||||
// // admin-server
|
||||
// initRpcProvider();
|
||||
//
|
||||
// logger.info(">>>>>>>>> init xxl-job admin success.");
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public void destroy() throws Exception {
|
||||
// // admin trigger pool stop
|
||||
// JobTriggerPoolHelper.toStop();
|
||||
//
|
||||
// // admin registry stop
|
||||
// JobRegistryMonitorHelper.getInstance().toStop();
|
||||
//
|
||||
// // admin monitor stop
|
||||
// JobFailMonitorHelper.getInstance().toStop();
|
||||
//
|
||||
// // admin-server
|
||||
// stopRpcProvider();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // ---------------------- I18n ----------------------
|
||||
//
|
||||
// private void initI18n(){
|
||||
// for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {
|
||||
// item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name())));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // ---------------------- admin rpc provider (no server version) ----------------------
|
||||
// private static ServletServerHandler servletServerHandler;
|
||||
// private void initRpcProvider(){
|
||||
// // init
|
||||
// XxlRpcProviderFactory xxlRpcProviderFactory = new XxlRpcProviderFactory();
|
||||
// xxlRpcProviderFactory.initConfig(
|
||||
// NetEnum.NETTY_HTTP,
|
||||
// Serializer.SerializeEnum.HESSIAN.getSerializer(),
|
||||
// null,
|
||||
// 0,
|
||||
// XxlJobAdminConfig.getAdminConfig().getAccessToken(),
|
||||
// null,
|
||||
// null);
|
||||
//
|
||||
// // add services
|
||||
// xxlRpcProviderFactory.addService(AdminBiz.class.getName(), null, XxlJobAdminConfig.getAdminConfig().getAdminBiz());
|
||||
//
|
||||
// // servlet handler
|
||||
// servletServerHandler = new ServletServerHandler(xxlRpcProviderFactory);
|
||||
// }
|
||||
// private void stopRpcProvider() throws Exception {
|
||||
// XxlRpcInvokerFactory.getInstance().stop();
|
||||
// }
|
||||
// public static void invokeAdminService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
// servletServerHandler.handle(null, request, response);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // ---------------------- executor-client ----------------------
|
||||
// private static ConcurrentHashMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();
|
||||
// public static ExecutorBiz getExecutorBiz(String address) throws Exception {
|
||||
// // valid
|
||||
// if (address==null || address.trim().length()==0) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// // load-cache
|
||||
// address = address.trim();
|
||||
// ExecutorBiz executorBiz = executorBizRepository.get(address);
|
||||
// if (executorBiz != null) {
|
||||
// return executorBiz;
|
||||
// }
|
||||
//
|
||||
// // set-cache
|
||||
// executorBiz = (ExecutorBiz) new XxlRpcReferenceBean(
|
||||
// NetEnum.NETTY_HTTP,
|
||||
// Serializer.SerializeEnum.HESSIAN.getSerializer(),
|
||||
// CallType.SYNC,
|
||||
// LoadBalance.ROUND,
|
||||
// ExecutorBiz.class,
|
||||
// null,
|
||||
// 5000,
|
||||
// address,
|
||||
// XxlJobAdminConfig.getAdminConfig().getAccessToken(),
|
||||
// null,
|
||||
// null).getObject();
|
||||
//
|
||||
// executorBizRepository.put(address, executorBiz);
|
||||
// return executorBiz;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // ---------------------- schedule util ----------------------
|
||||
//
|
||||
// /**
|
||||
// * fill job info
|
||||
// *
|
||||
// * @param jobInfo
|
||||
// */
|
||||
// public static void fillJobInfo(XxlJobInfo jobInfo) {
|
||||
//
|
||||
// String name = String.valueOf(jobInfo.getId());
|
||||
//
|
||||
// // trigger key
|
||||
// TriggerKey triggerKey = TriggerKey.triggerKey(name);
|
||||
// try {
|
||||
//
|
||||
// // trigger cron
|
||||
// Trigger trigger = scheduler.getTrigger(triggerKey);
|
||||
// if (trigger!=null && trigger instanceof CronTriggerImpl) {
|
||||
// String cronExpression = ((CronTriggerImpl) trigger).getCronExpression();
|
||||
// jobInfo.setJobCron(cronExpression);
|
||||
// }
|
||||
//
|
||||
// // trigger state
|
||||
// TriggerState triggerState = scheduler.getTriggerState(triggerKey);
|
||||
// if (triggerState!=null) {
|
||||
// jobInfo.setJobStatus(triggerState.name());
|
||||
// }
|
||||
//
|
||||
// //JobKey jobKey = new JobKey(jobInfo.getJobName(), String.valueOf(jobInfo.getJobGroup()));
|
||||
// //JobDetail jobDetail = scheduler.getJobDetail(jobKey);
|
||||
// //String jobClass = jobDetail.getJobClass().getName();
|
||||
//
|
||||
// } catch (SchedulerException e) {
|
||||
// logger.error(e.getMessage(), e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * add trigger + job
|
||||
// *
|
||||
// * @param jobName
|
||||
// * @param cronExpression
|
||||
// * @return
|
||||
// * @throws SchedulerException
|
||||
// */
|
||||
// public static boolean addJob(String jobName, String cronExpression) throws SchedulerException {
|
||||
// // 1、job key
|
||||
// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
|
||||
// JobKey jobKey = new JobKey(jobName);
|
||||
//
|
||||
// // 2、valid
|
||||
// if (scheduler.checkExists(triggerKey)) {
|
||||
// return true; // PASS
|
||||
// }
|
||||
//
|
||||
// // 3、corn trigger
|
||||
// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); // withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度
|
||||
// CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
|
||||
//
|
||||
// // 4、job detail
|
||||
// Class<? extends Job> jobClass_ = RemoteHttpJobBean.class; // Class.forName(jobInfo.getJobClass());
|
||||
// JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();
|
||||
//
|
||||
// /*if (jobInfo.getJobData()!=null) {
|
||||
// JobDataMap jobDataMap = jobDetail.getJobDataMap();
|
||||
// jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));
|
||||
// // JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
|
||||
// }*/
|
||||
//
|
||||
// // 5、schedule job
|
||||
// Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
|
||||
//
|
||||
// logger.info(">>>>>>>>>>> addJob success(quartz), jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date);
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * remove trigger + job
|
||||
// *
|
||||
// * @param jobName
|
||||
// * @return
|
||||
// * @throws SchedulerException
|
||||
// */
|
||||
// public static boolean removeJob(String jobName) throws SchedulerException {
|
||||
//
|
||||
// JobKey jobKey = new JobKey(jobName);
|
||||
// scheduler.deleteJob(jobKey);
|
||||
//
|
||||
// /*TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
|
||||
// if (scheduler.checkExists(triggerKey)) {
|
||||
// scheduler.unscheduleJob(triggerKey); // trigger + job
|
||||
// }*/
|
||||
//
|
||||
// logger.info(">>>>>>>>>>> removeJob success(quartz), jobKey:{}", jobKey);
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * updateJobCron
|
||||
// *
|
||||
// * @param jobName
|
||||
// * @param cronExpression
|
||||
// * @return
|
||||
// * @throws SchedulerException
|
||||
// */
|
||||
// public static boolean updateJobCron(String jobName, String cronExpression) throws SchedulerException {
|
||||
//
|
||||
// // 1、job key
|
||||
// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
|
||||
//
|
||||
// // 2、valid
|
||||
// if (!scheduler.checkExists(triggerKey)) {
|
||||
// return true; // PASS
|
||||
// }
|
||||
//
|
||||
// CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
//
|
||||
// // 3、avoid repeat cron
|
||||
// String oldCron = oldTrigger.getCronExpression();
|
||||
// if (oldCron.equals(cronExpression)){
|
||||
// return true; // PASS
|
||||
// }
|
||||
//
|
||||
// // 4、new cron trigger
|
||||
// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
|
||||
// oldTrigger = oldTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
|
||||
//
|
||||
// // 5、rescheduleJob
|
||||
// scheduler.rescheduleJob(triggerKey, oldTrigger);
|
||||
//
|
||||
// /*
|
||||
// JobKey jobKey = new JobKey(jobName);
|
||||
//
|
||||
// // old job detail
|
||||
// JobDetail jobDetail = scheduler.getJobDetail(jobKey);
|
||||
//
|
||||
// // new trigger
|
||||
// HashSet<Trigger> triggerSet = new HashSet<Trigger>();
|
||||
// triggerSet.add(cronTrigger);
|
||||
// // cover trigger of job detail
|
||||
// scheduler.scheduleJob(jobDetail, triggerSet, true);*/
|
||||
//
|
||||
// logger.info(">>>>>>>>>>> resumeJob success, JobName:{}", jobName);
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * pause
|
||||
// *
|
||||
// * @param jobName
|
||||
// * @return
|
||||
// * @throws SchedulerException
|
||||
// */
|
||||
// /*public static boolean pauseJob(String jobName) throws SchedulerException {
|
||||
//
|
||||
// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
|
||||
//
|
||||
// boolean result = false;
|
||||
// if (scheduler.checkExists(triggerKey)) {
|
||||
// scheduler.pauseTrigger(triggerKey);
|
||||
// result = true;
|
||||
// }
|
||||
//
|
||||
// logger.info(">>>>>>>>>>> pauseJob {}, triggerKey:{}", (result?"success":"fail"),triggerKey);
|
||||
// return result;
|
||||
// }*/
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * resume
|
||||
// *
|
||||
// * @param jobName
|
||||
// * @return
|
||||
// * @throws SchedulerException
|
||||
// */
|
||||
// /*public static boolean resumeJob(String jobName) throws SchedulerException {
|
||||
//
|
||||
// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
|
||||
//
|
||||
// boolean result = false;
|
||||
// if (scheduler.checkExists(triggerKey)) {
|
||||
// scheduler.resumeTrigger(triggerKey);
|
||||
// result = true;
|
||||
// }
|
||||
//
|
||||
// logger.info(">>>>>>>>>>> resumeJob {}, triggerKey:{}", (result?"success":"fail"), triggerKey);
|
||||
// return result;
|
||||
// }*/
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * run
|
||||
// *
|
||||
// * @param jobName
|
||||
// * @return
|
||||
// * @throws SchedulerException
|
||||
// */
|
||||
// /*public static boolean triggerJob(String jobName) throws SchedulerException {
|
||||
// // TriggerKey : name + group
|
||||
// JobKey jobKey = new JobKey(jobName);
|
||||
// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
|
||||
//
|
||||
// boolean result = false;
|
||||
// if (scheduler.checkExists(triggerKey)) {
|
||||
// scheduler.triggerJob(jobKey);
|
||||
// result = true;
|
||||
// logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey);
|
||||
// } else {
|
||||
// logger.info(">>>>>>>>>>> runJob fail, jobKey:{}", jobKey);
|
||||
// }
|
||||
// return result;
|
||||
// }*/
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * finaAllJobList
|
||||
// *
|
||||
// * @return
|
||||
// *//*
|
||||
// @Deprecated
|
||||
// public static List<Map<String, Object>> finaAllJobList(){
|
||||
// List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();
|
||||
//
|
||||
// try {
|
||||
// if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {
|
||||
// return null;
|
||||
// }
|
||||
// String groupName = scheduler.getJobGroupNames().get(0);
|
||||
// Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
|
||||
// if (jobKeys!=null && jobKeys.size()>0) {
|
||||
// for (JobKey jobKey : jobKeys) {
|
||||
// TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);
|
||||
// Trigger trigger = scheduler.getTrigger(triggerKey);
|
||||
// JobDetail jobDetail = scheduler.getJobDetail(jobKey);
|
||||
// TriggerState triggerState = scheduler.getTriggerState(triggerKey);
|
||||
// Map<String, Object> jobMap = new HashMap<String, Object>();
|
||||
// jobMap.put("TriggerKey", triggerKey);
|
||||
// jobMap.put("Trigger", trigger);
|
||||
// jobMap.put("JobDetail", jobDetail);
|
||||
// jobMap.put("TriggerState", triggerState);
|
||||
// jobList.add(jobMap);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// } catch (SchedulerException e) {
|
||||
// logger.error(e.getMessage(), e);
|
||||
// return null;
|
||||
// }
|
||||
// return jobList;
|
||||
// }*/
|
||||
//
|
||||
//}
|
|
@ -0,0 +1,58 @@
|
|||
//package com.xxl.job.admin.core.quartz;
|
||||
//
|
||||
//import org.quartz.SchedulerConfigException;
|
||||
//import org.quartz.spi.ThreadPool;
|
||||
//
|
||||
///**
|
||||
// * single thread pool, for async trigger
|
||||
// *
|
||||
// * @author xuxueli 2019-03-06
|
||||
// */
|
||||
//public class XxlJobThreadPool implements ThreadPool {
|
||||
//
|
||||
// @Override
|
||||
// public boolean runInThread(Runnable runnable) {
|
||||
//
|
||||
// // async run
|
||||
// runnable.run();
|
||||
// return true;
|
||||
//
|
||||
// //return false;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int blockForAvailableThreads() {
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void initialize() throws SchedulerConfigException {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void shutdown(boolean waitForJobsToComplete) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getPoolSize() {
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void setInstanceId(String schedInstId) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void setInstanceName(String schedName) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// // support
|
||||
// public void setThreadCount(int count) {
|
||||
// //
|
||||
// }
|
||||
//
|
||||
//}
|
|
@ -0,0 +1,48 @@
|
|||
package com.xxl.job.admin.core.route;
|
||||
|
||||
import com.xxl.job.admin.core.route.strategy.*;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public enum ExecutorRouteStrategyEnum {
|
||||
|
||||
FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()),
|
||||
LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()),
|
||||
ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()),
|
||||
RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()),
|
||||
CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()),
|
||||
LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()),
|
||||
LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()),
|
||||
FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()),
|
||||
BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()),
|
||||
SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null);
|
||||
|
||||
ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
|
||||
this.title = title;
|
||||
this.router = router;
|
||||
}
|
||||
|
||||
private String title;
|
||||
private ExecutorRouter router;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
public ExecutorRouter getRouter() {
|
||||
return router;
|
||||
}
|
||||
|
||||
public static ExecutorRouteStrategyEnum match(String name, ExecutorRouteStrategyEnum defaultItem){
|
||||
if (name != null) {
|
||||
for (ExecutorRouteStrategyEnum item: ExecutorRouteStrategyEnum.values()) {
|
||||
if (item.name().equals(name)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultItem;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.xxl.job.admin.core.route;
|
||||
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public abstract class ExecutorRouter {
|
||||
protected static Logger logger = LoggerFactory.getLogger(ExecutorRouter.class);
|
||||
|
||||
/**
|
||||
* route address
|
||||
*
|
||||
* @param addressList
|
||||
* @return ReturnT.content=address
|
||||
*/
|
||||
public abstract ReturnT<String> route(TriggerParam triggerParam, List<String> addressList);
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.core.biz.ExecutorBiz;
|
||||
import com.xxl.job.core.biz.model.IdleBeatParam;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteBusyover extends ExecutorRouter {
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
|
||||
StringBuffer idleBeatResultSB = new StringBuffer();
|
||||
for (String address : addressList) {
|
||||
// beat
|
||||
ReturnT<String> idleBeatResult = null;
|
||||
try {
|
||||
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
|
||||
idleBeatResult = executorBiz.idleBeat(new IdleBeatParam(triggerParam.getJobId()));
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
idleBeatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
|
||||
}
|
||||
idleBeatResultSB.append( (idleBeatResultSB.length()>0)?"<br><br>":"")
|
||||
.append(I18nUtil.getString("jobconf_idleBeat") + ":")
|
||||
.append("<br>address:").append(address)
|
||||
.append("<br>code:").append(idleBeatResult.getCode())
|
||||
.append("<br>msg:").append(idleBeatResult.getMsg());
|
||||
|
||||
// beat success
|
||||
if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) {
|
||||
idleBeatResult.setMsg(idleBeatResultSB.toString());
|
||||
idleBeatResult.setContent(address);
|
||||
return idleBeatResult;
|
||||
}
|
||||
}
|
||||
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, idleBeatResultSB.toString());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* 分组下机器地址相同,不同JOB均匀散列在不同机器上,保证分组下机器分配JOB平均;且每个JOB固定调度其中一台机器;
|
||||
* a、virtual node:解决不均衡问题
|
||||
* b、hash method replace hashCode:String的hashCode可能重复,需要进一步扩大hashCode的取值范围
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteConsistentHash extends ExecutorRouter {
|
||||
|
||||
private static int VIRTUAL_NODE_NUM = 100;
|
||||
|
||||
/**
|
||||
* get hash code on 2^32 ring (md5散列的方式计算hash值)
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
private static long hash(String key) {
|
||||
|
||||
// md5 byte
|
||||
MessageDigest md5;
|
||||
try {
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("MD5 not supported", e);
|
||||
}
|
||||
md5.reset();
|
||||
byte[] keyBytes = null;
|
||||
try {
|
||||
keyBytes = key.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Unknown string :" + key, e);
|
||||
}
|
||||
|
||||
md5.update(keyBytes);
|
||||
byte[] digest = md5.digest();
|
||||
|
||||
// hash code, Truncate to 32-bits
|
||||
long hashCode = ((long) (digest[3] & 0xFF) << 24)
|
||||
| ((long) (digest[2] & 0xFF) << 16)
|
||||
| ((long) (digest[1] & 0xFF) << 8)
|
||||
| (digest[0] & 0xFF);
|
||||
|
||||
long truncateHashCode = hashCode & 0xffffffffL;
|
||||
return truncateHashCode;
|
||||
}
|
||||
|
||||
public String hashJob(int jobId, List<String> addressList) {
|
||||
|
||||
// ------A1------A2-------A3------
|
||||
// -----------J1------------------
|
||||
TreeMap<Long, String> addressRing = new TreeMap<Long, String>();
|
||||
for (String address: addressList) {
|
||||
for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
|
||||
long addressHash = hash("SHARD-" + address + "-NODE-" + i);
|
||||
addressRing.put(addressHash, address);
|
||||
}
|
||||
}
|
||||
|
||||
long jobHash = hash(String.valueOf(jobId));
|
||||
SortedMap<Long, String> lastRing = addressRing.tailMap(jobHash);
|
||||
if (!lastRing.isEmpty()) {
|
||||
return lastRing.get(lastRing.firstKey());
|
||||
}
|
||||
return addressRing.firstEntry().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
|
||||
String address = hashJob(triggerParam.getJobId(), addressList);
|
||||
return new ReturnT<String>(address);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.core.biz.ExecutorBiz;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteFailover extends ExecutorRouter {
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
|
||||
|
||||
StringBuffer beatResultSB = new StringBuffer();
|
||||
for (String address : addressList) {
|
||||
// beat
|
||||
ReturnT<String> beatResult = null;
|
||||
try {
|
||||
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
|
||||
beatResult = executorBiz.beat();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
beatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
|
||||
}
|
||||
beatResultSB.append( (beatResultSB.length()>0)?"<br><br>":"")
|
||||
.append(I18nUtil.getString("jobconf_beat") + ":")
|
||||
.append("<br>address:").append(address)
|
||||
.append("<br>code:").append(beatResult.getCode())
|
||||
.append("<br>msg:").append(beatResult.getMsg());
|
||||
|
||||
// beat success
|
||||
if (beatResult.getCode() == ReturnT.SUCCESS_CODE) {
|
||||
|
||||
beatResult.setMsg(beatResultSB.toString());
|
||||
beatResult.setContent(address);
|
||||
return beatResult;
|
||||
}
|
||||
}
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, beatResultSB.toString());
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteFirst extends ExecutorRouter {
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList){
|
||||
return new ReturnT<String>(addressList.get(0));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* 单个JOB对应的每个执行器,使用频率最低的优先被选举
|
||||
* a(*)、LFU(Least Frequently Used):最不经常使用,频率/次数
|
||||
* b、LRU(Least Recently Used):最近最久未使用,时间
|
||||
*
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteLFU extends ExecutorRouter {
|
||||
|
||||
private static ConcurrentMap<Integer, HashMap<String, Integer>> jobLfuMap = new ConcurrentHashMap<Integer, HashMap<String, Integer>>();
|
||||
private static long CACHE_VALID_TIME = 0;
|
||||
|
||||
public String route(int jobId, List<String> addressList) {
|
||||
|
||||
// cache clear
|
||||
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
|
||||
jobLfuMap.clear();
|
||||
CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
|
||||
}
|
||||
|
||||
// lfu item init
|
||||
HashMap<String, Integer> lfuItemMap = jobLfuMap.get(jobId); // Key排序可以用TreeMap+构造入参Compare;Value排序暂时只能通过ArrayList;
|
||||
if (lfuItemMap == null) {
|
||||
lfuItemMap = new HashMap<String, Integer>();
|
||||
jobLfuMap.putIfAbsent(jobId, lfuItemMap); // 避免重复覆盖
|
||||
}
|
||||
|
||||
// put new
|
||||
for (String address: addressList) {
|
||||
if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) >1000000 ) {
|
||||
lfuItemMap.put(address, new Random().nextInt(addressList.size())); // 初始化时主动Random一次,缓解首次压力
|
||||
}
|
||||
}
|
||||
// remove old
|
||||
List<String> delKeys = new ArrayList<>();
|
||||
for (String existKey: lfuItemMap.keySet()) {
|
||||
if (!addressList.contains(existKey)) {
|
||||
delKeys.add(existKey);
|
||||
}
|
||||
}
|
||||
if (delKeys.size() > 0) {
|
||||
for (String delKey: delKeys) {
|
||||
lfuItemMap.remove(delKey);
|
||||
}
|
||||
}
|
||||
|
||||
// load least userd count address
|
||||
List<Map.Entry<String, Integer>> lfuItemList = new ArrayList<Map.Entry<String, Integer>>(lfuItemMap.entrySet());
|
||||
Collections.sort(lfuItemList, new Comparator<Map.Entry<String, Integer>>() {
|
||||
@Override
|
||||
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
|
||||
return o1.getValue().compareTo(o2.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
Map.Entry<String, Integer> addressItem = lfuItemList.get(0);
|
||||
String minAddress = addressItem.getKey();
|
||||
addressItem.setValue(addressItem.getValue() + 1);
|
||||
|
||||
return addressItem.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
|
||||
String address = route(triggerParam.getJobId(), addressList);
|
||||
return new ReturnT<String>(address);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* 单个JOB对应的每个执行器,最久为使用的优先被选举
|
||||
* a、LFU(Least Frequently Used):最不经常使用,频率/次数
|
||||
* b(*)、LRU(Least Recently Used):最近最久未使用,时间
|
||||
*
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteLRU extends ExecutorRouter {
|
||||
|
||||
private static ConcurrentMap<Integer, LinkedHashMap<String, String>> jobLRUMap = new ConcurrentHashMap<Integer, LinkedHashMap<String, String>>();
|
||||
private static long CACHE_VALID_TIME = 0;
|
||||
|
||||
public String route(int jobId, List<String> addressList) {
|
||||
|
||||
// cache clear
|
||||
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
|
||||
jobLRUMap.clear();
|
||||
CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
|
||||
}
|
||||
|
||||
// init lru
|
||||
LinkedHashMap<String, String> lruItem = jobLRUMap.get(jobId);
|
||||
if (lruItem == null) {
|
||||
/**
|
||||
* LinkedHashMap
|
||||
* a、accessOrder:true=访问顺序排序(get/put时排序);false=插入顺序排期;
|
||||
* b、removeEldestEntry:新增元素时将会调用,返回true时会删除最老元素;可封装LinkedHashMap并重写该方法,比如定义最大容量,超出是返回true即可实现固定长度的LRU算法;
|
||||
*/
|
||||
lruItem = new LinkedHashMap<String, String>(16, 0.75f, true);
|
||||
jobLRUMap.putIfAbsent(jobId, lruItem);
|
||||
}
|
||||
|
||||
// put new
|
||||
for (String address: addressList) {
|
||||
if (!lruItem.containsKey(address)) {
|
||||
lruItem.put(address, address);
|
||||
}
|
||||
}
|
||||
// remove old
|
||||
List<String> delKeys = new ArrayList<>();
|
||||
for (String existKey: lruItem.keySet()) {
|
||||
if (!addressList.contains(existKey)) {
|
||||
delKeys.add(existKey);
|
||||
}
|
||||
}
|
||||
if (delKeys.size() > 0) {
|
||||
for (String delKey: delKeys) {
|
||||
lruItem.remove(delKey);
|
||||
}
|
||||
}
|
||||
|
||||
// load
|
||||
String eldestKey = lruItem.entrySet().iterator().next().getKey();
|
||||
String eldestValue = lruItem.get(eldestKey);
|
||||
return eldestValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
|
||||
String address = route(triggerParam.getJobId(), addressList);
|
||||
return new ReturnT<String>(address);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteLast extends ExecutorRouter {
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
|
||||
return new ReturnT<String>(addressList.get(addressList.size()-1));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteRandom extends ExecutorRouter {
|
||||
|
||||
private static Random localRandom = new Random();
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
|
||||
String address = addressList.get(localRandom.nextInt(addressList.size()));
|
||||
return new ReturnT<String>(address);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.xxl.job.admin.core.route.strategy;
|
||||
|
||||
import com.xxl.job.admin.core.route.ExecutorRouter;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 17/3/10.
|
||||
*/
|
||||
public class ExecutorRouteRound extends ExecutorRouter {
|
||||
|
||||
private static ConcurrentMap<Integer, Integer> routeCountEachJob = new ConcurrentHashMap<Integer, Integer>();
|
||||
private static long CACHE_VALID_TIME = 0;
|
||||
private static int count(int jobId) {
|
||||
// cache clear
|
||||
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
|
||||
routeCountEachJob.clear();
|
||||
CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
|
||||
}
|
||||
|
||||
// count++
|
||||
Integer count = routeCountEachJob.get(jobId);
|
||||
count = (count==null || count>1000000)?(new Random().nextInt(100)):++count; // 初始化时主动Random一次,缓解首次压力
|
||||
routeCountEachJob.put(jobId, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList) {
|
||||
String address = addressList.get(count(triggerParam.getJobId())%addressList.size());
|
||||
return new ReturnT<String>(address);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package com.xxl.job.admin.core.scheduler;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.thread.*;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.core.biz.ExecutorBiz;
|
||||
import com.xxl.job.core.biz.client.ExecutorBizClient;
|
||||
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2018-10-28 00:18:17
|
||||
*/
|
||||
|
||||
public class XxlJobScheduler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(XxlJobScheduler.class);
|
||||
|
||||
|
||||
public void init() throws Exception {
|
||||
// init i18n
|
||||
initI18n();
|
||||
|
||||
// admin registry monitor run
|
||||
JobRegistryMonitorHelper.getInstance().start();
|
||||
|
||||
// admin fail-monitor run
|
||||
JobFailMonitorHelper.getInstance().start();
|
||||
|
||||
// admin lose-monitor run
|
||||
JobLosedMonitorHelper.getInstance().start();
|
||||
|
||||
// admin trigger pool start
|
||||
JobTriggerPoolHelper.toStart();
|
||||
|
||||
// admin log report start
|
||||
JobLogReportHelper.getInstance().start();
|
||||
|
||||
// start-schedule
|
||||
JobScheduleHelper.getInstance().start();
|
||||
|
||||
logger.info(">>>>>>>>> init xxl-job admin success.");
|
||||
}
|
||||
|
||||
|
||||
public void destroy() throws Exception {
|
||||
|
||||
// stop-schedule
|
||||
JobScheduleHelper.getInstance().toStop();
|
||||
|
||||
// admin log report stop
|
||||
JobLogReportHelper.getInstance().toStop();
|
||||
|
||||
// admin trigger pool stop
|
||||
JobTriggerPoolHelper.toStop();
|
||||
|
||||
// admin lose-monitor stop
|
||||
JobLosedMonitorHelper.getInstance().toStop();
|
||||
|
||||
// admin fail-monitor stop
|
||||
JobFailMonitorHelper.getInstance().toStop();
|
||||
|
||||
// admin registry stop
|
||||
JobRegistryMonitorHelper.getInstance().toStop();
|
||||
|
||||
}
|
||||
|
||||
// ---------------------- I18n ----------------------
|
||||
|
||||
private void initI18n(){
|
||||
for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {
|
||||
item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name())));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------- executor-client ----------------------
|
||||
private static ConcurrentMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();
|
||||
public static ExecutorBiz getExecutorBiz(String address) throws Exception {
|
||||
// valid
|
||||
if (address==null || address.trim().length()==0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// load-cache
|
||||
address = address.trim();
|
||||
ExecutorBiz executorBiz = executorBizRepository.get(address);
|
||||
if (executorBiz != null) {
|
||||
return executorBiz;
|
||||
}
|
||||
|
||||
// set-cache
|
||||
executorBiz = new ExecutorBizClient(address, XxlJobAdminConfig.getAdminConfig().getAccessToken());
|
||||
|
||||
executorBizRepository.put(address, executorBiz);
|
||||
return executorBiz;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package com.xxl.job.admin.core.thread;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* job monitor instance
|
||||
*
|
||||
* @author xuxueli 2015-9-1 18:05:56
|
||||
*/
|
||||
public class JobFailMonitorHelper {
|
||||
private static Logger logger = LoggerFactory.getLogger(JobFailMonitorHelper.class);
|
||||
|
||||
private static JobFailMonitorHelper instance = new JobFailMonitorHelper();
|
||||
public static JobFailMonitorHelper getInstance(){
|
||||
return instance;
|
||||
}
|
||||
|
||||
// ---------------------- monitor ----------------------
|
||||
|
||||
private Thread monitorThread;
|
||||
private volatile boolean toStop = false;
|
||||
public void start(){
|
||||
monitorThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
// monitor
|
||||
while (!toStop) {
|
||||
try {
|
||||
|
||||
List<Long> failLogIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findFailJobLogIds(1000);
|
||||
if (failLogIds!=null && !failLogIds.isEmpty()) {
|
||||
for (long failLogId: failLogIds) {
|
||||
|
||||
// lock log
|
||||
int lockRet = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, 0, -1);
|
||||
if (lockRet < 1) {
|
||||
continue;
|
||||
}
|
||||
XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(failLogId);
|
||||
XxlJobInfo info = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(log.getJobId());
|
||||
|
||||
// 1、fail retry monitor
|
||||
if (log.getExecutorFailRetryCount() > 0) {
|
||||
JobTriggerPoolHelper.trigger(log.getJobId(), TriggerTypeEnum.RETRY, (log.getExecutorFailRetryCount()-1), log.getExecutorShardingParam(), log.getExecutorParam(), null);
|
||||
String retryMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_type_retry") +"<<<<<<<<<<< </span><br>";
|
||||
log.setTriggerMsg(log.getTriggerMsg() + retryMsg);
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(log);
|
||||
}
|
||||
|
||||
// 2、fail alarm monitor
|
||||
int newAlarmStatus = 0; // 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败
|
||||
if (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) {
|
||||
boolean alarmResult = XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log);
|
||||
newAlarmStatus = alarmResult?2:3;
|
||||
} else {
|
||||
newAlarmStatus = 1;
|
||||
}
|
||||
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, -1, newAlarmStatus);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
if (!toStop) {
|
||||
logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
} catch (Exception e) {
|
||||
if (!toStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.info(">>>>>>>>>>> xxl-job, job fail monitor thread stop");
|
||||
|
||||
}
|
||||
});
|
||||
monitorThread.setDaemon(true);
|
||||
monitorThread.setName("xxl-job, admin JobFailMonitorHelper");
|
||||
monitorThread.start();
|
||||
}
|
||||
|
||||
public void toStop(){
|
||||
toStop = true;
|
||||
// interrupt and wait
|
||||
monitorThread.interrupt();
|
||||
try {
|
||||
monitorThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package com.xxl.job.admin.core.thread;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.model.XxlJobLogReport;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* job log report helper
|
||||
*
|
||||
* @author xuxueli 2019-11-22
|
||||
*/
|
||||
public class JobLogReportHelper {
|
||||
private static Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class);
|
||||
|
||||
private static JobLogReportHelper instance = new JobLogReportHelper();
|
||||
public static JobLogReportHelper getInstance(){
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
private Thread logrThread;
|
||||
private volatile boolean toStop = false;
|
||||
public void start(){
|
||||
logrThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
// last clean log time
|
||||
long lastCleanLogTime = 0;
|
||||
|
||||
|
||||
while (!toStop) {
|
||||
|
||||
// 1、log-report refresh: refresh log report in 3 days
|
||||
try {
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
||||
// today
|
||||
Calendar itemDay = Calendar.getInstance();
|
||||
itemDay.add(Calendar.DAY_OF_MONTH, -i);
|
||||
itemDay.set(Calendar.HOUR_OF_DAY, 0);
|
||||
itemDay.set(Calendar.MINUTE, 0);
|
||||
itemDay.set(Calendar.SECOND, 0);
|
||||
itemDay.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
Date todayFrom = itemDay.getTime();
|
||||
|
||||
itemDay.set(Calendar.HOUR_OF_DAY, 23);
|
||||
itemDay.set(Calendar.MINUTE, 59);
|
||||
itemDay.set(Calendar.SECOND, 59);
|
||||
itemDay.set(Calendar.MILLISECOND, 999);
|
||||
|
||||
Date todayTo = itemDay.getTime();
|
||||
|
||||
// refresh log-report every minute
|
||||
XxlJobLogReport xxlJobLogReport = new XxlJobLogReport();
|
||||
xxlJobLogReport.setTriggerDay(todayFrom);
|
||||
xxlJobLogReport.setRunningCount(0);
|
||||
xxlJobLogReport.setSucCount(0);
|
||||
xxlJobLogReport.setFailCount(0);
|
||||
|
||||
Map<String, Object> triggerCountMap = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findLogReport(todayFrom, todayTo);
|
||||
if (triggerCountMap!=null && triggerCountMap.size()>0) {
|
||||
int triggerDayCount = triggerCountMap.containsKey("triggerDayCount")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCount"))):0;
|
||||
int triggerDayCountRunning = triggerCountMap.containsKey("triggerDayCountRunning")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountRunning"))):0;
|
||||
int triggerDayCountSuc = triggerCountMap.containsKey("triggerDayCountSuc")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountSuc"))):0;
|
||||
int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;
|
||||
|
||||
xxlJobLogReport.setRunningCount(triggerDayCountRunning);
|
||||
xxlJobLogReport.setSucCount(triggerDayCountSuc);
|
||||
xxlJobLogReport.setFailCount(triggerDayCountFail);
|
||||
}
|
||||
|
||||
// do refresh
|
||||
int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().update(xxlJobLogReport);
|
||||
if (ret < 1) {
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().save(xxlJobLogReport);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
if (!toStop) {
|
||||
logger.error(">>>>>>>>>>> xxl-job, job log report thread error:{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 2、log-clean: switch open & once each day
|
||||
if (XxlJobAdminConfig.getAdminConfig().getLogretentiondays()>0
|
||||
&& System.currentTimeMillis() - lastCleanLogTime > 24*60*60*1000) {
|
||||
|
||||
// expire-time
|
||||
Calendar expiredDay = Calendar.getInstance();
|
||||
expiredDay.add(Calendar.DAY_OF_MONTH, -1 * XxlJobAdminConfig.getAdminConfig().getLogretentiondays());
|
||||
expiredDay.set(Calendar.HOUR_OF_DAY, 0);
|
||||
expiredDay.set(Calendar.MINUTE, 0);
|
||||
expiredDay.set(Calendar.SECOND, 0);
|
||||
expiredDay.set(Calendar.MILLISECOND, 0);
|
||||
Date clearBeforeTime = expiredDay.getTime();
|
||||
|
||||
// clean expired log
|
||||
List<Long> logIds = null;
|
||||
do {
|
||||
logIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findClearLogIds(0, 0, clearBeforeTime, 0, 1000);
|
||||
if (logIds!=null && logIds.size()>0) {
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().clearLog(logIds);
|
||||
}
|
||||
} while (logIds!=null && logIds.size()>0);
|
||||
|
||||
// update clean time
|
||||
lastCleanLogTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
try {
|
||||
TimeUnit.MINUTES.sleep(1);
|
||||
} catch (Exception e) {
|
||||
if (!toStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.info(">>>>>>>>>>> xxl-job, job log report thread stop");
|
||||
|
||||
}
|
||||
});
|
||||
logrThread.setDaemon(true);
|
||||
logrThread.setName("xxl-job, admin JobLogReportHelper");
|
||||
logrThread.start();
|
||||
}
|
||||
|
||||
public void toStop(){
|
||||
toStop = true;
|
||||
// interrupt and wait
|
||||
logrThread.interrupt();
|
||||
try {
|
||||
logrThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package com.xxl.job.admin.core.thread;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.util.DateUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* job lose-monitor instance
|
||||
*
|
||||
* @author xuxueli 2015-9-1 18:05:56
|
||||
*/
|
||||
public class JobLosedMonitorHelper {
|
||||
private static Logger logger = LoggerFactory.getLogger(JobLosedMonitorHelper.class);
|
||||
|
||||
private static JobLosedMonitorHelper instance = new JobLosedMonitorHelper();
|
||||
public static JobLosedMonitorHelper getInstance(){
|
||||
return instance;
|
||||
}
|
||||
|
||||
// ---------------------- monitor ----------------------
|
||||
|
||||
private Thread monitorThread;
|
||||
private volatile boolean toStop = false;
|
||||
public void start(){
|
||||
monitorThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
// monitor
|
||||
while (!toStop) {
|
||||
try {
|
||||
// 任务结果丢失处理:调度记录停留在 "运行中" 状态超过10min,且对应执行器心跳注册失败不在线,则将本地调度主动标记失败;
|
||||
Date losedTime = DateUtil.addMinutes(new Date(), -10);
|
||||
List<Long> losedJobIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findLostJobIds(losedTime);
|
||||
|
||||
if (losedJobIds!=null && losedJobIds.size()>0) {
|
||||
for (Long logId: losedJobIds) {
|
||||
|
||||
XxlJobLog jobLog = new XxlJobLog();
|
||||
jobLog.setId(logId);
|
||||
|
||||
jobLog.setHandleTime(new Date());
|
||||
jobLog.setHandleCode(ReturnT.FAIL_CODE);
|
||||
jobLog.setHandleMsg( I18nUtil.getString("joblog_lost_fail") );
|
||||
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateHandleInfo(jobLog);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!toStop) {
|
||||
logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(60);
|
||||
} catch (Exception e) {
|
||||
if (!toStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.info(">>>>>>>>>>> xxl-job, JobLosedMonitorHelper stop");
|
||||
|
||||
}
|
||||
});
|
||||
monitorThread.setDaemon(true);
|
||||
monitorThread.setName("xxl-job, admin JobLosedMonitorHelper");
|
||||
monitorThread.start();
|
||||
}
|
||||
|
||||
public void toStop(){
|
||||
toStop = true;
|
||||
// interrupt and wait
|
||||
monitorThread.interrupt();
|
||||
try {
|
||||
monitorThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package com.xxl.job.admin.core.thread;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import com.xxl.job.admin.core.model.XxlJobRegistry;
|
||||
import com.xxl.job.core.enums.RegistryConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* job registry instance
|
||||
* @author xuxueli 2016-10-02 19:10:24
|
||||
*/
|
||||
public class JobRegistryMonitorHelper {
|
||||
private static Logger logger = LoggerFactory.getLogger(JobRegistryMonitorHelper.class);
|
||||
|
||||
private static JobRegistryMonitorHelper instance = new JobRegistryMonitorHelper();
|
||||
public static JobRegistryMonitorHelper getInstance(){
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Thread registryThread;
|
||||
private volatile boolean toStop = false;
|
||||
public void start(){
|
||||
registryThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!toStop) {
|
||||
try {
|
||||
// auto registry group
|
||||
List<XxlJobGroup> groupList = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().findByAddressType(0);
|
||||
if (groupList!=null && !groupList.isEmpty()) {
|
||||
|
||||
// remove dead address (admin/executor)
|
||||
List<Integer> ids = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findDead(RegistryConfig.DEAD_TIMEOUT, new Date());
|
||||
if (ids!=null && ids.size()>0) {
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().removeDead(ids);
|
||||
}
|
||||
|
||||
// fresh online address (admin/executor)
|
||||
HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
|
||||
List<XxlJobRegistry> list = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findAll(RegistryConfig.DEAD_TIMEOUT, new Date());
|
||||
if (list != null) {
|
||||
for (XxlJobRegistry item: list) {
|
||||
if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
|
||||
String appname = item.getRegistryKey();
|
||||
List<String> registryList = appAddressMap.get(appname);
|
||||
if (registryList == null) {
|
||||
registryList = new ArrayList<String>();
|
||||
}
|
||||
|
||||
if (!registryList.contains(item.getRegistryValue())) {
|
||||
registryList.add(item.getRegistryValue());
|
||||
}
|
||||
appAddressMap.put(appname, registryList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fresh group address
|
||||
for (XxlJobGroup group: groupList) {
|
||||
List<String> registryList = appAddressMap.get(group.getAppname());
|
||||
String addressListStr = null;
|
||||
if (registryList!=null && !registryList.isEmpty()) {
|
||||
Collections.sort(registryList);
|
||||
addressListStr = "";
|
||||
for (String item:registryList) {
|
||||
addressListStr += item + ",";
|
||||
}
|
||||
addressListStr = addressListStr.substring(0, addressListStr.length()-1);
|
||||
}
|
||||
group.setAddressList(addressListStr);
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().update(group);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!toStop) {
|
||||
logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
|
||||
} catch (InterruptedException e) {
|
||||
if (!toStop) {
|
||||
logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info(">>>>>>>>>>> xxl-job, job registry monitor thread stop");
|
||||
}
|
||||
});
|
||||
registryThread.setDaemon(true);
|
||||
registryThread.setName("xxl-job, admin JobRegistryMonitorHelper");
|
||||
registryThread.start();
|
||||
}
|
||||
|
||||
public void toStop(){
|
||||
toStop = true;
|
||||
// interrupt and wait
|
||||
registryThread.interrupt();
|
||||
try {
|
||||
registryThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,354 @@
|
|||
package com.xxl.job.admin.core.thread;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.cron.CronExpression;
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2019-05-21
|
||||
*/
|
||||
public class JobScheduleHelper {
|
||||
private static Logger logger = LoggerFactory.getLogger(JobScheduleHelper.class);
|
||||
|
||||
private static JobScheduleHelper instance = new JobScheduleHelper();
|
||||
public static JobScheduleHelper getInstance(){
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static final long PRE_READ_MS = 5000; // pre read
|
||||
|
||||
private Thread scheduleThread;
|
||||
private Thread ringThread;
|
||||
private volatile boolean scheduleThreadToStop = false;
|
||||
private volatile boolean ringThreadToStop = false;
|
||||
private volatile static Map<Integer, List<Integer>> ringData = new ConcurrentHashMap<>();
|
||||
|
||||
public void start(){
|
||||
|
||||
// schedule thread
|
||||
scheduleThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(5000 - System.currentTimeMillis()%1000 );
|
||||
} catch (InterruptedException e) {
|
||||
if (!scheduleThreadToStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
logger.info(">>>>>>>>> init xxl-job admin scheduler success.");
|
||||
|
||||
// pre-read count: treadpool-size * trigger-qps (each trigger cost 50ms, qps = 1000/50 = 20)
|
||||
int preReadCount = (XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax() + XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax()) * 20;
|
||||
|
||||
while (!scheduleThreadToStop) {
|
||||
|
||||
// Scan Job
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Connection conn = null;
|
||||
Boolean connAutoCommit = null;
|
||||
PreparedStatement preparedStatement = null;
|
||||
|
||||
boolean preReadSuc = true;
|
||||
try {
|
||||
|
||||
conn = XxlJobAdminConfig.getAdminConfig().getDataSource().getConnection();
|
||||
connAutoCommit = conn.getAutoCommit();
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
preparedStatement = conn.prepareStatement( "select * from xxl_job_lock where lock_name = 'schedule_lock' for update" );
|
||||
preparedStatement.execute();
|
||||
|
||||
// tx start
|
||||
|
||||
// 1、pre read
|
||||
long nowTime = System.currentTimeMillis();
|
||||
List<XxlJobInfo> scheduleList = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount);
|
||||
if (scheduleList!=null && scheduleList.size()>0) {
|
||||
// 2、push time-ring
|
||||
for (XxlJobInfo jobInfo: scheduleList) {
|
||||
|
||||
// time-ring jump
|
||||
if (nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS) {
|
||||
// 2.1、trigger-expire > 5s:pass && make next-trigger-time
|
||||
logger.warn(">>>>>>>>>>> xxl-job, schedule misfire, jobId = " + jobInfo.getId());
|
||||
|
||||
// fresh next
|
||||
refreshNextValidTime(jobInfo, new Date());
|
||||
|
||||
} else if (nowTime > jobInfo.getTriggerNextTime()) {
|
||||
// 2.2、trigger-expire < 5s:direct-trigger && make next-trigger-time
|
||||
|
||||
// 1、trigger
|
||||
JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.CRON, -1, null, null, null);
|
||||
logger.debug(">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " + jobInfo.getId() );
|
||||
|
||||
// 2、fresh next
|
||||
refreshNextValidTime(jobInfo, new Date());
|
||||
|
||||
// next-trigger-time in 5s, pre-read again
|
||||
if (jobInfo.getTriggerStatus()==1 && nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()) {
|
||||
|
||||
// 1、make ring second
|
||||
int ringSecond = (int)((jobInfo.getTriggerNextTime()/1000)%60);
|
||||
|
||||
// 2、push time ring
|
||||
pushTimeRing(ringSecond, jobInfo.getId());
|
||||
|
||||
// 3、fresh next
|
||||
refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// 2.3、trigger-pre-read:time-ring trigger && make next-trigger-time
|
||||
|
||||
// 1、make ring second
|
||||
int ringSecond = (int)((jobInfo.getTriggerNextTime()/1000)%60);
|
||||
|
||||
// 2、push time ring
|
||||
pushTimeRing(ringSecond, jobInfo.getId());
|
||||
|
||||
// 3、fresh next
|
||||
refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 3、update trigger info
|
||||
for (XxlJobInfo jobInfo: scheduleList) {
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleUpdate(jobInfo);
|
||||
}
|
||||
|
||||
} else {
|
||||
preReadSuc = false;
|
||||
}
|
||||
|
||||
// tx stop
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
if (!scheduleThreadToStop) {
|
||||
logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread error:{}", e);
|
||||
}
|
||||
} finally {
|
||||
|
||||
// commit
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.commit();
|
||||
} catch (SQLException e) {
|
||||
if (!scheduleThreadToStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
conn.setAutoCommit(connAutoCommit);
|
||||
} catch (SQLException e) {
|
||||
if (!scheduleThreadToStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
if (!scheduleThreadToStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// close PreparedStatement
|
||||
if (null != preparedStatement) {
|
||||
try {
|
||||
preparedStatement.close();
|
||||
} catch (SQLException e) {
|
||||
if (!scheduleThreadToStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
long cost = System.currentTimeMillis()-start;
|
||||
|
||||
|
||||
// Wait seconds, align second
|
||||
if (cost < 1000) { // scan-overtime, not wait
|
||||
try {
|
||||
// pre-read period: success > scan each second; fail > skip this period;
|
||||
TimeUnit.MILLISECONDS.sleep((preReadSuc?1000:PRE_READ_MS) - System.currentTimeMillis()%1000);
|
||||
} catch (InterruptedException e) {
|
||||
if (!scheduleThreadToStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread stop");
|
||||
}
|
||||
});
|
||||
scheduleThread.setDaemon(true);
|
||||
scheduleThread.setName("xxl-job, admin JobScheduleHelper#scheduleThread");
|
||||
scheduleThread.start();
|
||||
|
||||
|
||||
// ring thread
|
||||
ringThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
// align second
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis()%1000 );
|
||||
} catch (InterruptedException e) {
|
||||
if (!ringThreadToStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
while (!ringThreadToStop) {
|
||||
|
||||
try {
|
||||
// second data
|
||||
List<Integer> ringItemData = new ArrayList<>();
|
||||
int nowSecond = Calendar.getInstance().get(Calendar.SECOND); // 避免处理耗时太长,跨过刻度,向前校验一个刻度;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
List<Integer> tmpData = ringData.remove( (nowSecond+60-i)%60 );
|
||||
if (tmpData != null) {
|
||||
ringItemData.addAll(tmpData);
|
||||
}
|
||||
}
|
||||
|
||||
// ring trigger
|
||||
logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " + Arrays.asList(ringItemData) );
|
||||
if (ringItemData.size() > 0) {
|
||||
// do trigger
|
||||
for (int jobId: ringItemData) {
|
||||
// do trigger
|
||||
JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null);
|
||||
}
|
||||
// clear
|
||||
ringItemData.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (!ringThreadToStop) {
|
||||
logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// next second, align second
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis()%1000);
|
||||
} catch (InterruptedException e) {
|
||||
if (!ringThreadToStop) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop");
|
||||
}
|
||||
});
|
||||
ringThread.setDaemon(true);
|
||||
ringThread.setName("xxl-job, admin JobScheduleHelper#ringThread");
|
||||
ringThread.start();
|
||||
}
|
||||
|
||||
private void refreshNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws ParseException {
|
||||
Date nextValidTime = new CronExpression(jobInfo.getJobCron()).getNextValidTimeAfter(fromTime);
|
||||
if (nextValidTime != null) {
|
||||
jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime());
|
||||
jobInfo.setTriggerNextTime(nextValidTime.getTime());
|
||||
} else {
|
||||
jobInfo.setTriggerStatus(0);
|
||||
jobInfo.setTriggerLastTime(0);
|
||||
jobInfo.setTriggerNextTime(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void pushTimeRing(int ringSecond, int jobId){
|
||||
// push async ring
|
||||
List<Integer> ringItemData = ringData.get(ringSecond);
|
||||
if (ringItemData == null) {
|
||||
ringItemData = new ArrayList<Integer>();
|
||||
ringData.put(ringSecond, ringItemData);
|
||||
}
|
||||
ringItemData.add(jobId);
|
||||
|
||||
logger.debug(">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData) );
|
||||
}
|
||||
|
||||
public void toStop(){
|
||||
|
||||
// 1、stop schedule
|
||||
scheduleThreadToStop = true;
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1); // wait
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
if (scheduleThread.getState() != Thread.State.TERMINATED){
|
||||
// interrupt and wait
|
||||
scheduleThread.interrupt();
|
||||
try {
|
||||
scheduleThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// if has ring data
|
||||
boolean hasRingData = false;
|
||||
if (!ringData.isEmpty()) {
|
||||
for (int second : ringData.keySet()) {
|
||||
List<Integer> tmpData = ringData.get(second);
|
||||
if (tmpData!=null && tmpData.size()>0) {
|
||||
hasRingData = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasRingData) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(8);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// stop ring (wait job-in-memory stop)
|
||||
ringThreadToStop = true;
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
if (ringThread.getState() != Thread.State.TERMINATED){
|
||||
// interrupt and wait
|
||||
ringThread.interrupt();
|
||||
try {
|
||||
ringThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper stop");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
package com.xxl.job.admin.core.thread;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
|
||||
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* job trigger thread pool helper
|
||||
*
|
||||
* @author xuxueli 2018-07-03 21:08:07
|
||||
*/
|
||||
public class JobTriggerPoolHelper {
|
||||
private static Logger logger = LoggerFactory.getLogger(JobTriggerPoolHelper.class);
|
||||
|
||||
|
||||
// ---------------------- trigger pool ----------------------
|
||||
|
||||
// fast/slow thread pool
|
||||
private ThreadPoolExecutor fastTriggerPool = null;
|
||||
private ThreadPoolExecutor slowTriggerPool = null;
|
||||
|
||||
public void start(){
|
||||
fastTriggerPool = new ThreadPoolExecutor(
|
||||
10,
|
||||
XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax(),
|
||||
60L,
|
||||
TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(1000),
|
||||
new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-" + r.hashCode());
|
||||
}
|
||||
});
|
||||
|
||||
slowTriggerPool = new ThreadPoolExecutor(
|
||||
10,
|
||||
XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax(),
|
||||
60L,
|
||||
TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(2000),
|
||||
new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-" + r.hashCode());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void stop() {
|
||||
//triggerPool.shutdown();
|
||||
fastTriggerPool.shutdownNow();
|
||||
slowTriggerPool.shutdownNow();
|
||||
logger.info(">>>>>>>>> xxl-job trigger thread pool shutdown success.");
|
||||
}
|
||||
|
||||
|
||||
// job timeout count
|
||||
private volatile long minTim = System.currentTimeMillis()/60000; // ms > min
|
||||
private volatile ConcurrentMap<Integer, AtomicInteger> jobTimeoutCountMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* add trigger
|
||||
*/
|
||||
public void addTrigger(final int jobId,
|
||||
final TriggerTypeEnum triggerType,
|
||||
final int failRetryCount,
|
||||
final String executorShardingParam,
|
||||
final String executorParam,
|
||||
final String addressList) {
|
||||
|
||||
// choose thread pool
|
||||
ThreadPoolExecutor triggerPool_ = fastTriggerPool;
|
||||
AtomicInteger jobTimeoutCount = jobTimeoutCountMap.get(jobId);
|
||||
if (jobTimeoutCount!=null && jobTimeoutCount.get() > 10) { // job-timeout 10 times in 1 min
|
||||
triggerPool_ = slowTriggerPool;
|
||||
}
|
||||
|
||||
// trigger
|
||||
triggerPool_.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// do trigger
|
||||
XxlJobTrigger.trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} finally {
|
||||
|
||||
// check timeout-count-map
|
||||
long minTim_now = System.currentTimeMillis()/60000;
|
||||
if (minTim != minTim_now) {
|
||||
minTim = minTim_now;
|
||||
jobTimeoutCountMap.clear();
|
||||
}
|
||||
|
||||
// incr timeout-count-map
|
||||
long cost = System.currentTimeMillis()-start;
|
||||
if (cost > 500) { // ob-timeout threshold 500ms
|
||||
AtomicInteger timeoutCount = jobTimeoutCountMap.putIfAbsent(jobId, new AtomicInteger(1));
|
||||
if (timeoutCount != null) {
|
||||
timeoutCount.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------------------- helper ----------------------
|
||||
|
||||
private static JobTriggerPoolHelper helper = new JobTriggerPoolHelper();
|
||||
|
||||
public static void toStart() {
|
||||
helper.start();
|
||||
}
|
||||
public static void toStop() {
|
||||
helper.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jobId
|
||||
* @param triggerType
|
||||
* @param failRetryCount
|
||||
* >=0: use this param
|
||||
* <0: use param from job info config
|
||||
* @param executorShardingParam
|
||||
* @param executorParam
|
||||
* null: use job param
|
||||
* not null: cover job param
|
||||
*/
|
||||
public static void trigger(int jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, String executorParam, String addressList) {
|
||||
helper.addTrigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.xxl.job.admin.core.trigger;
|
||||
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
|
||||
/**
|
||||
* trigger type enum
|
||||
*
|
||||
* @author xuxueli 2018-09-16 04:56:41
|
||||
*/
|
||||
public enum TriggerTypeEnum {
|
||||
|
||||
MANUAL(I18nUtil.getString("jobconf_trigger_type_manual")),
|
||||
CRON(I18nUtil.getString("jobconf_trigger_type_cron")),
|
||||
RETRY(I18nUtil.getString("jobconf_trigger_type_retry")),
|
||||
PARENT(I18nUtil.getString("jobconf_trigger_type_parent")),
|
||||
API(I18nUtil.getString("jobconf_trigger_type_api"));
|
||||
|
||||
private TriggerTypeEnum(String title){
|
||||
this.title = title;
|
||||
}
|
||||
private String title;
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
package com.xxl.job.admin.core.trigger;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
|
||||
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.core.biz.ExecutorBiz;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.biz.model.TriggerParam;
|
||||
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
|
||||
import com.xxl.job.core.util.IpUtil;
|
||||
import com.xxl.job.core.util.ThrowableUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* xxl-job trigger
|
||||
* Created by xuxueli on 17/7/13.
|
||||
*/
|
||||
public class XxlJobTrigger {
|
||||
private static Logger logger = LoggerFactory.getLogger(XxlJobTrigger.class);
|
||||
|
||||
/**
|
||||
* trigger job
|
||||
*
|
||||
* @param jobId
|
||||
* @param triggerType
|
||||
* @param failRetryCount
|
||||
* >=0: use this param
|
||||
* <0: use param from job info config
|
||||
* @param executorShardingParam
|
||||
* @param executorParam
|
||||
* null: use job param
|
||||
* not null: cover job param
|
||||
* @param addressList
|
||||
* null: use executor addressList
|
||||
* not null: cover
|
||||
*/
|
||||
public static void trigger(int jobId,
|
||||
TriggerTypeEnum triggerType,
|
||||
int failRetryCount,
|
||||
String executorShardingParam,
|
||||
String executorParam,
|
||||
String addressList) {
|
||||
|
||||
// load data
|
||||
XxlJobInfo jobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(jobId);
|
||||
if (jobInfo == null) {
|
||||
logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid,jobId={}", jobId);
|
||||
return;
|
||||
}
|
||||
if (executorParam != null) {
|
||||
jobInfo.setExecutorParam(executorParam);
|
||||
}
|
||||
int finalFailRetryCount = failRetryCount>=0?failRetryCount:jobInfo.getExecutorFailRetryCount();
|
||||
XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(jobInfo.getJobGroup());
|
||||
|
||||
// cover addressList
|
||||
if (addressList!=null && addressList.trim().length()>0) {
|
||||
group.setAddressType(1);
|
||||
group.setAddressList(addressList.trim());
|
||||
}
|
||||
|
||||
// sharding param
|
||||
int[] shardingParam = null;
|
||||
if (executorShardingParam!=null){
|
||||
String[] shardingArr = executorShardingParam.split("/");
|
||||
if (shardingArr.length==2 && isNumeric(shardingArr[0]) && isNumeric(shardingArr[1])) {
|
||||
shardingParam = new int[2];
|
||||
shardingParam[0] = Integer.valueOf(shardingArr[0]);
|
||||
shardingParam[1] = Integer.valueOf(shardingArr[1]);
|
||||
}
|
||||
}
|
||||
if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST==ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null)
|
||||
&& group.getRegistryList()!=null && !group.getRegistryList().isEmpty()
|
||||
&& shardingParam==null) {
|
||||
for (int i = 0; i < group.getRegistryList().size(); i++) {
|
||||
processTrigger(group, jobInfo, finalFailRetryCount, triggerType, i, group.getRegistryList().size());
|
||||
}
|
||||
} else {
|
||||
if (shardingParam == null) {
|
||||
shardingParam = new int[]{0, 1};
|
||||
}
|
||||
processTrigger(group, jobInfo, finalFailRetryCount, triggerType, shardingParam[0], shardingParam[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean isNumeric(String str){
|
||||
try {
|
||||
int result = Integer.valueOf(str);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param group job group, registry list may be empty
|
||||
* @param jobInfo
|
||||
* @param finalFailRetryCount
|
||||
* @param triggerType
|
||||
* @param index sharding index
|
||||
* @param total sharding index
|
||||
*/
|
||||
private static void processTrigger(XxlJobGroup group, XxlJobInfo jobInfo, int finalFailRetryCount, TriggerTypeEnum triggerType, int index, int total){
|
||||
|
||||
// param
|
||||
ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), ExecutorBlockStrategyEnum.SERIAL_EXECUTION); // block strategy
|
||||
ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null); // route strategy
|
||||
String shardingParam = (ExecutorRouteStrategyEnum.SHARDING_BROADCAST==executorRouteStrategyEnum)?String.valueOf(index).concat("/").concat(String.valueOf(total)):null;
|
||||
|
||||
// 1、save log-id
|
||||
XxlJobLog jobLog = new XxlJobLog();
|
||||
jobLog.setJobGroup(jobInfo.getJobGroup());
|
||||
jobLog.setJobId(jobInfo.getId());
|
||||
jobLog.setTriggerTime(new Date());
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().save(jobLog);
|
||||
logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());
|
||||
|
||||
// 2、init trigger-param
|
||||
TriggerParam triggerParam = new TriggerParam();
|
||||
triggerParam.setJobId(jobInfo.getId());
|
||||
triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
|
||||
triggerParam.setExecutorParams(jobInfo.getExecutorParam());
|
||||
triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
|
||||
triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout());
|
||||
triggerParam.setLogId(jobLog.getId());
|
||||
triggerParam.setLogDateTime(jobLog.getTriggerTime().getTime());
|
||||
triggerParam.setGlueType(jobInfo.getGlueType());
|
||||
triggerParam.setGlueSource(jobInfo.getGlueSource());
|
||||
triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
|
||||
triggerParam.setBroadcastIndex(index);
|
||||
triggerParam.setBroadcastTotal(total);
|
||||
|
||||
// 3、init address
|
||||
String address = null;
|
||||
ReturnT<String> routeAddressResult = null;
|
||||
if (group.getRegistryList()!=null && !group.getRegistryList().isEmpty()) {
|
||||
if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) {
|
||||
if (index < group.getRegistryList().size()) {
|
||||
address = group.getRegistryList().get(index);
|
||||
} else {
|
||||
address = group.getRegistryList().get(0);
|
||||
}
|
||||
} else {
|
||||
routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList());
|
||||
if (routeAddressResult.getCode() == ReturnT.SUCCESS_CODE) {
|
||||
address = routeAddressResult.getContent();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
routeAddressResult = new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobconf_trigger_address_empty"));
|
||||
}
|
||||
|
||||
// 4、trigger remote executor
|
||||
ReturnT<String> triggerResult = null;
|
||||
if (address != null) {
|
||||
triggerResult = runExecutor(triggerParam, address);
|
||||
} else {
|
||||
triggerResult = new ReturnT<String>(ReturnT.FAIL_CODE, null);
|
||||
}
|
||||
|
||||
// 5、collection trigger info
|
||||
StringBuffer triggerMsgSb = new StringBuffer();
|
||||
triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_type")).append(":").append(triggerType.getTitle());
|
||||
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp());
|
||||
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":")
|
||||
.append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
|
||||
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList());
|
||||
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle());
|
||||
if (shardingParam != null) {
|
||||
triggerMsgSb.append("("+shardingParam+")");
|
||||
}
|
||||
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle());
|
||||
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_timeout")).append(":").append(jobInfo.getExecutorTimeout());
|
||||
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailRetryCount")).append(":").append(finalFailRetryCount);
|
||||
|
||||
triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_run") +"<<<<<<<<<<< </span><br>")
|
||||
.append((routeAddressResult!=null&&routeAddressResult.getMsg()!=null)?routeAddressResult.getMsg()+"<br><br>":"").append(triggerResult.getMsg()!=null?triggerResult.getMsg():"");
|
||||
|
||||
// 6、save log trigger-info
|
||||
jobLog.setExecutorAddress(address);
|
||||
jobLog.setExecutorHandler(jobInfo.getExecutorHandler());
|
||||
jobLog.setExecutorParam(jobInfo.getExecutorParam());
|
||||
jobLog.setExecutorShardingParam(shardingParam);
|
||||
jobLog.setExecutorFailRetryCount(finalFailRetryCount);
|
||||
//jobLog.setTriggerTime();
|
||||
jobLog.setTriggerCode(triggerResult.getCode());
|
||||
jobLog.setTriggerMsg(triggerMsgSb.toString());
|
||||
XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(jobLog);
|
||||
|
||||
logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* run executor
|
||||
* @param triggerParam
|
||||
* @param address
|
||||
* @return
|
||||
*/
|
||||
public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address){
|
||||
ReturnT<String> runResult = null;
|
||||
try {
|
||||
ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
|
||||
runResult = executorBiz.run(triggerParam);
|
||||
} catch (Exception e) {
|
||||
logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e);
|
||||
runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ThrowableUtil.toString(e));
|
||||
}
|
||||
|
||||
StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":");
|
||||
runResultSB.append("<br>address:").append(address);
|
||||
runResultSB.append("<br>code:").append(runResult.getCode());
|
||||
runResultSB.append("<br>msg:").append(runResult.getMsg());
|
||||
|
||||
runResult.setMsg(runResultSB.toString());
|
||||
return runResult;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.xxl.job.admin.core.util;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Cookie.Util
|
||||
*
|
||||
* @author xuxueli 2015-12-12 18:01:06
|
||||
*/
|
||||
public class CookieUtil {
|
||||
|
||||
// 默认缓存时间,单位/秒, 2H
|
||||
private static final int COOKIE_MAX_AGE = Integer.MAX_VALUE;
|
||||
// 保存路径,根路径
|
||||
private static final String COOKIE_PATH = "/";
|
||||
|
||||
/**
|
||||
* 保存
|
||||
*
|
||||
* @param response
|
||||
* @param key
|
||||
* @param value
|
||||
* @param ifRemember
|
||||
*/
|
||||
public static void set(HttpServletResponse response, String key, String value, boolean ifRemember) {
|
||||
int age = ifRemember?COOKIE_MAX_AGE:-1;
|
||||
set(response, key, value, null, COOKIE_PATH, age, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存
|
||||
*
|
||||
* @param response
|
||||
* @param key
|
||||
* @param value
|
||||
* @param maxAge
|
||||
*/
|
||||
private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) {
|
||||
Cookie cookie = new Cookie(key, value);
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setPath(path);
|
||||
cookie.setMaxAge(maxAge);
|
||||
cookie.setHttpOnly(isHttpOnly);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询value
|
||||
*
|
||||
* @param request
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static String getValue(HttpServletRequest request, String key) {
|
||||
Cookie cookie = get(request, key);
|
||||
if (cookie != null) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询Cookie
|
||||
*
|
||||
* @param request
|
||||
* @param key
|
||||
*/
|
||||
private static Cookie get(HttpServletRequest request, String key) {
|
||||
Cookie[] arr_cookie = request.getCookies();
|
||||
if (arr_cookie != null && arr_cookie.length > 0) {
|
||||
for (Cookie cookie : arr_cookie) {
|
||||
if (cookie.getName().equals(key)) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Cookie
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param key
|
||||
*/
|
||||
public static void remove(HttpServletRequest request, HttpServletResponse response, String key) {
|
||||
Cookie cookie = get(request, key);
|
||||
if (cookie != null) {
|
||||
set(response, key, "", null, COOKIE_PATH, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.xxl.job.admin.core.util;
|
||||
|
||||
import freemarker.ext.beans.BeansWrapper;
|
||||
import freemarker.ext.beans.BeansWrapperBuilder;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.TemplateHashModel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ftl util
|
||||
*
|
||||
* @author xuxueli 2018-01-17 20:37:48
|
||||
*/
|
||||
public class FtlUtil {
|
||||
private static Logger logger = LoggerFactory.getLogger(FtlUtil.class);
|
||||
|
||||
private static BeansWrapper wrapper = new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build(); //BeansWrapper.getDefaultInstance();
|
||||
|
||||
public static TemplateHashModel generateStaticModel(String packageName) {
|
||||
try {
|
||||
TemplateHashModel staticModels = wrapper.getStaticModels();
|
||||
TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName);
|
||||
return fileStatics;
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.xxl.job.admin.core.util;
|
||||
|
||||
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* i18n util
|
||||
*
|
||||
* @author xuxueli 2018-01-17 20:39:06
|
||||
*/
|
||||
public class I18nUtil {
|
||||
private static Logger logger = LoggerFactory.getLogger(I18nUtil.class);
|
||||
|
||||
private static Properties prop = null;
|
||||
public static Properties loadI18nProp(){
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
try {
|
||||
// build i18n prop
|
||||
String i18n = XxlJobAdminConfig.getAdminConfig().getI18n();
|
||||
String i18nFile = MessageFormat.format("i18n/message_{0}.properties", i18n);
|
||||
|
||||
// load prop
|
||||
Resource resource = new ClassPathResource(i18nFile);
|
||||
EncodedResource encodedResource = new EncodedResource(resource,"UTF-8");
|
||||
prop = PropertiesLoaderUtils.loadProperties(encodedResource);
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* get val of i18n key
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static String getString(String key) {
|
||||
return loadI18nProp().getProperty(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* get mult val of i18n mult key, as json
|
||||
*
|
||||
* @param keys
|
||||
* @return
|
||||
*/
|
||||
public static String getMultString(String... keys) {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
|
||||
Properties prop = loadI18nProp();
|
||||
if (keys!=null && keys.length>0) {
|
||||
for (String key: keys) {
|
||||
map.put(key, prop.getProperty(key));
|
||||
}
|
||||
} else {
|
||||
for (String key: prop.stringPropertyNames()) {
|
||||
map.put(key, prop.getProperty(key));
|
||||
}
|
||||
}
|
||||
|
||||
String json = JacksonUtil.writeValueAsString(map);
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.xxl.job.admin.core.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerationException;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Jackson util
|
||||
*
|
||||
* 1、obj need private and set/get;
|
||||
* 2、do not support inner class;
|
||||
*
|
||||
* @author xuxueli 2015-9-25 18:02:56
|
||||
*/
|
||||
public class JacksonUtil {
|
||||
private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class);
|
||||
|
||||
private final static ObjectMapper objectMapper = new ObjectMapper();
|
||||
public static ObjectMapper getInstance() {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* bean、array、List、Map --> json
|
||||
*
|
||||
* @param obj
|
||||
* @return json string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String writeValueAsString(Object obj) {
|
||||
try {
|
||||
return getInstance().writeValueAsString(obj);
|
||||
} catch (JsonGenerationException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (JsonMappingException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* string --> bean、Map、List(array)
|
||||
*
|
||||
* @param jsonStr
|
||||
* @param clazz
|
||||
* @return obj
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T> T readValue(String jsonStr, Class<T> clazz) {
|
||||
try {
|
||||
return getInstance().readValue(jsonStr, clazz);
|
||||
} catch (JsonParseException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (JsonMappingException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* string --> List<Bean>...
|
||||
*
|
||||
* @param jsonStr
|
||||
* @param parametrized
|
||||
* @param parameterClasses
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> T readValue(String jsonStr, Class<?> parametrized, Class<?>... parameterClasses) {
|
||||
try {
|
||||
JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses);
|
||||
return getInstance().readValue(jsonStr, javaType);
|
||||
} catch (JsonParseException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (JsonMappingException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package com.xxl.job.admin.core.util;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* local cache tool
|
||||
*
|
||||
* @author xuxueli 2018-01-22 21:37:34
|
||||
*/
|
||||
public class LocalCacheUtil {
|
||||
|
||||
private static ConcurrentMap<String, LocalCacheData> cacheRepository = new ConcurrentHashMap<String, LocalCacheData>(); // 类型建议用抽象父类,兼容性更好;
|
||||
private static class LocalCacheData{
|
||||
private String key;
|
||||
private Object val;
|
||||
private long timeoutTime;
|
||||
|
||||
public LocalCacheData() {
|
||||
}
|
||||
|
||||
public LocalCacheData(String key, Object val, long timeoutTime) {
|
||||
this.key = key;
|
||||
this.val = val;
|
||||
this.timeoutTime = timeoutTime;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Object getVal() {
|
||||
return val;
|
||||
}
|
||||
|
||||
public void setVal(Object val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public long getTimeoutTime() {
|
||||
return timeoutTime;
|
||||
}
|
||||
|
||||
public void setTimeoutTime(long timeoutTime) {
|
||||
this.timeoutTime = timeoutTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set cache
|
||||
*
|
||||
* @param key
|
||||
* @param val
|
||||
* @param cacheTime
|
||||
* @return
|
||||
*/
|
||||
public static boolean set(String key, Object val, long cacheTime){
|
||||
|
||||
// clean timeout cache, before set new cache (avoid cache too much)
|
||||
cleanTimeoutCache();
|
||||
|
||||
// set new cache
|
||||
if (key==null || key.trim().length()==0) {
|
||||
return false;
|
||||
}
|
||||
if (val == null) {
|
||||
remove(key);
|
||||
}
|
||||
if (cacheTime <= 0) {
|
||||
remove(key);
|
||||
}
|
||||
long timeoutTime = System.currentTimeMillis() + cacheTime;
|
||||
LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime);
|
||||
cacheRepository.put(localCacheData.getKey(), localCacheData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove cache
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static boolean remove(String key){
|
||||
if (key==null || key.trim().length()==0) {
|
||||
return false;
|
||||
}
|
||||
cacheRepository.remove(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* get cache
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static Object get(String key){
|
||||
if (key==null || key.trim().length()==0) {
|
||||
return null;
|
||||
}
|
||||
LocalCacheData localCacheData = cacheRepository.get(key);
|
||||
if (localCacheData!=null && System.currentTimeMillis()<localCacheData.getTimeoutTime()) {
|
||||
return localCacheData.getVal();
|
||||
} else {
|
||||
remove(key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clean timeout cache
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean cleanTimeoutCache(){
|
||||
if (!cacheRepository.keySet().isEmpty()) {
|
||||
for (String key: cacheRepository.keySet()) {
|
||||
LocalCacheData localCacheData = cacheRepository.get(key);
|
||||
if (localCacheData!=null && System.currentTimeMillis()>=localCacheData.getTimeoutTime()) {
|
||||
cacheRepository.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.xxl.job.admin.dao;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 16/9/30.
|
||||
*/
|
||||
@Mapper
|
||||
public interface XxlJobGroupDao {
|
||||
|
||||
public List<XxlJobGroup> findAll();
|
||||
|
||||
public List<XxlJobGroup> findByAddressType(@Param("addressType") int addressType);
|
||||
|
||||
public int save(XxlJobGroup xxlJobGroup);
|
||||
|
||||
public int update(XxlJobGroup xxlJobGroup);
|
||||
|
||||
public int remove(@Param("id") int id);
|
||||
|
||||
public XxlJobGroup load(@Param("id") int id);
|
||||
|
||||
public List<XxlJobGroup> pageList(@Param("offset") int offset,
|
||||
@Param("pagesize") int pagesize,
|
||||
@Param("appname") String appname,
|
||||
@Param("title") String title);
|
||||
|
||||
public int pageListCount(@Param("offset") int offset,
|
||||
@Param("pagesize") int pagesize,
|
||||
@Param("appname") String appname,
|
||||
@Param("title") String title);
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.xxl.job.admin.dao;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* job info
|
||||
* @author xuxueli 2016-1-12 18:03:45
|
||||
*/
|
||||
@Mapper
|
||||
public interface XxlJobInfoDao {
|
||||
|
||||
public List<XxlJobInfo> pageList(@Param("offset") int offset,
|
||||
@Param("pagesize") int pagesize,
|
||||
@Param("jobGroup") int jobGroup,
|
||||
@Param("triggerStatus") int triggerStatus,
|
||||
@Param("jobDesc") String jobDesc,
|
||||
@Param("executorHandler") String executorHandler,
|
||||
@Param("author") String author);
|
||||
public int pageListCount(@Param("offset") int offset,
|
||||
@Param("pagesize") int pagesize,
|
||||
@Param("jobGroup") int jobGroup,
|
||||
@Param("triggerStatus") int triggerStatus,
|
||||
@Param("jobDesc") String jobDesc,
|
||||
@Param("executorHandler") String executorHandler,
|
||||
@Param("author") String author);
|
||||
|
||||
public int save(XxlJobInfo info);
|
||||
|
||||
public XxlJobInfo loadById(@Param("id") int id);
|
||||
|
||||
public int update(XxlJobInfo xxlJobInfo);
|
||||
|
||||
public int delete(@Param("id") long id);
|
||||
|
||||
public List<XxlJobInfo> getJobsByGroup(@Param("jobGroup") int jobGroup);
|
||||
|
||||
public int findAllCount();
|
||||
|
||||
public List<XxlJobInfo> scheduleJobQuery(@Param("maxNextTime") long maxNextTime, @Param("pagesize") int pagesize );
|
||||
|
||||
public int scheduleUpdate(XxlJobInfo xxlJobInfo);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.xxl.job.admin.dao;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* job log
|
||||
* @author xuxueli 2016-1-12 18:03:06
|
||||
*/
|
||||
@Mapper
|
||||
public interface XxlJobLogDao {
|
||||
|
||||
// exist jobId not use jobGroup, not exist use jobGroup
|
||||
public List<XxlJobLog> pageList(@Param("offset") int offset,
|
||||
@Param("pagesize") int pagesize,
|
||||
@Param("jobGroup") int jobGroup,
|
||||
@Param("jobId") int jobId,
|
||||
@Param("triggerTimeStart") Date triggerTimeStart,
|
||||
@Param("triggerTimeEnd") Date triggerTimeEnd,
|
||||
@Param("logStatus") int logStatus);
|
||||
public int pageListCount(@Param("offset") int offset,
|
||||
@Param("pagesize") int pagesize,
|
||||
@Param("jobGroup") int jobGroup,
|
||||
@Param("jobId") int jobId,
|
||||
@Param("triggerTimeStart") Date triggerTimeStart,
|
||||
@Param("triggerTimeEnd") Date triggerTimeEnd,
|
||||
@Param("logStatus") int logStatus);
|
||||
|
||||
public XxlJobLog load(@Param("id") long id);
|
||||
|
||||
public long save(XxlJobLog xxlJobLog);
|
||||
|
||||
public int updateTriggerInfo(XxlJobLog xxlJobLog);
|
||||
|
||||
public int updateHandleInfo(XxlJobLog xxlJobLog);
|
||||
|
||||
public int delete(@Param("jobId") int jobId);
|
||||
|
||||
public Map<String, Object> findLogReport(@Param("from") Date from,
|
||||
@Param("to") Date to);
|
||||
|
||||
public List<Long> findClearLogIds(@Param("jobGroup") int jobGroup,
|
||||
@Param("jobId") int jobId,
|
||||
@Param("clearBeforeTime") Date clearBeforeTime,
|
||||
@Param("clearBeforeNum") int clearBeforeNum,
|
||||
@Param("pagesize") int pagesize);
|
||||
public int clearLog(@Param("logIds") List<Long> logIds);
|
||||
|
||||
public List<Long> findFailJobLogIds(@Param("pagesize") int pagesize);
|
||||
|
||||
public int updateAlarmStatus(@Param("logId") long logId,
|
||||
@Param("oldAlarmStatus") int oldAlarmStatus,
|
||||
@Param("newAlarmStatus") int newAlarmStatus);
|
||||
|
||||
public List<Long> findLostJobIds(@Param("losedTime") Date losedTime);
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.xxl.job.admin.dao;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobLogGlue;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* job log for glue
|
||||
* @author xuxueli 2016-5-19 18:04:56
|
||||
*/
|
||||
@Mapper
|
||||
public interface XxlJobLogGlueDao {
|
||||
|
||||
public int save(XxlJobLogGlue xxlJobLogGlue);
|
||||
|
||||
public List<XxlJobLogGlue> findByJobId(@Param("jobId") int jobId);
|
||||
|
||||
public int removeOld(@Param("jobId") int jobId, @Param("limit") int limit);
|
||||
|
||||
public int deleteByJobId(@Param("jobId") int jobId);
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.xxl.job.admin.dao;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobLogReport;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* job log
|
||||
* @author xuxueli 2019-11-22
|
||||
*/
|
||||
@Mapper
|
||||
public interface XxlJobLogReportDao {
|
||||
|
||||
public int save(XxlJobLogReport xxlJobLogReport);
|
||||
|
||||
public int update(XxlJobLogReport xxlJobLogReport);
|
||||
|
||||
public List<XxlJobLogReport> queryLogReport(@Param("triggerDayFrom") Date triggerDayFrom,
|
||||
@Param("triggerDayTo") Date triggerDayTo);
|
||||
|
||||
public XxlJobLogReport queryLogReportTotal();
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.xxl.job.admin.dao;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobRegistry;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by xuxueli on 16/9/30.
|
||||
*/
|
||||
@Mapper
|
||||
public interface XxlJobRegistryDao {
|
||||
|
||||
public List<Integer> findDead(@Param("timeout") int timeout,
|
||||
@Param("nowTime") Date nowTime);
|
||||
|
||||
public int removeDead(@Param("ids") List<Integer> ids);
|
||||
|
||||
public List<XxlJobRegistry> findAll(@Param("timeout") int timeout,
|
||||
@Param("nowTime") Date nowTime);
|
||||
|
||||
public int registryUpdate(@Param("registryGroup") String registryGroup,
|
||||
@Param("registryKey") String registryKey,
|
||||
@Param("registryValue") String registryValue,
|
||||
@Param("updateTime") Date updateTime);
|
||||
|
||||
public int registrySave(@Param("registryGroup") String registryGroup,
|
||||
@Param("registryKey") String registryKey,
|
||||
@Param("registryValue") String registryValue,
|
||||
@Param("updateTime") Date updateTime);
|
||||
|
||||
public int registryDelete(@Param("registryGroup") String registryGroup,
|
||||
@Param("registryKey") String registryKey,
|
||||
@Param("registryValue") String registryValue);
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.xxl.job.admin.dao;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobUser;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2019-05-04 16:44:59
|
||||
*/
|
||||
@Mapper
|
||||
public interface XxlJobUserDao {
|
||||
|
||||
public List<XxlJobUser> pageList(@Param("offset") int offset,
|
||||
@Param("pagesize") int pagesize,
|
||||
@Param("username") String username,
|
||||
@Param("role") int role);
|
||||
public int pageListCount(@Param("offset") int offset,
|
||||
@Param("pagesize") int pagesize,
|
||||
@Param("username") String username,
|
||||
@Param("role") int role);
|
||||
|
||||
public XxlJobUser loadByUserName(@Param("username") String username);
|
||||
|
||||
public int save(XxlJobUser xxlJobUser);
|
||||
|
||||
public int update(XxlJobUser xxlJobUser);
|
||||
|
||||
public int delete(@Param("id") int id);
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package com.xxl.job.admin.service;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobUser;
|
||||
import com.xxl.job.admin.core.util.CookieUtil;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.core.util.JacksonUtil;
|
||||
import com.xxl.job.admin.dao.XxlJobUserDao;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2019-05-04 22:13:264
|
||||
*/
|
||||
@Configuration
|
||||
public class LoginService {
|
||||
|
||||
public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
|
||||
|
||||
@Resource
|
||||
private XxlJobUserDao xxlJobUserDao;
|
||||
|
||||
|
||||
private String makeToken(XxlJobUser xxlJobUser){
|
||||
String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser);
|
||||
String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
|
||||
return tokenHex;
|
||||
}
|
||||
private XxlJobUser parseToken(String tokenHex){
|
||||
XxlJobUser xxlJobUser = null;
|
||||
if (tokenHex != null) {
|
||||
String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray()); // username_password(md5)
|
||||
xxlJobUser = JacksonUtil.readValue(tokenJson, XxlJobUser.class);
|
||||
}
|
||||
return xxlJobUser;
|
||||
}
|
||||
|
||||
|
||||
public ReturnT<String> login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember){
|
||||
|
||||
// param
|
||||
if (username==null || username.trim().length()==0 || password==null || password.trim().length()==0){
|
||||
return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
|
||||
}
|
||||
|
||||
// valid passowrd
|
||||
XxlJobUser xxlJobUser = xxlJobUserDao.loadByUserName(username);
|
||||
if (xxlJobUser == null) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
|
||||
}
|
||||
String passwordMd5 = DigestUtils.md5DigestAsHex(password.getBytes());
|
||||
if (!passwordMd5.equals(xxlJobUser.getPassword())) {
|
||||
return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
|
||||
}
|
||||
|
||||
String loginToken = makeToken(xxlJobUser);
|
||||
|
||||
// do login
|
||||
CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, ifRemember);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* logout
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
|
||||
CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* logout
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response){
|
||||
String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY);
|
||||
if (cookieToken != null) {
|
||||
XxlJobUser cookieUser = null;
|
||||
try {
|
||||
cookieUser = parseToken(cookieToken);
|
||||
} catch (Exception e) {
|
||||
logout(request, response);
|
||||
}
|
||||
if (cookieUser != null) {
|
||||
XxlJobUser dbUser = xxlJobUserDao.loadByUserName(cookieUser.getUsername());
|
||||
if (dbUser != null) {
|
||||
if (cookieUser.getPassword().equals(dbUser.getPassword())) {
|
||||
return dbUser;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package com.xxl.job.admin.service;
|
||||
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* core job action for xxl-job
|
||||
*
|
||||
* @author xuxueli 2016-5-28 15:30:33
|
||||
*/
|
||||
public interface XxlJobService {
|
||||
|
||||
/**
|
||||
* page list
|
||||
*
|
||||
* @param start
|
||||
* @param length
|
||||
* @param jobGroup
|
||||
* @param jobDesc
|
||||
* @param executorHandler
|
||||
* @param author
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Object> pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author);
|
||||
|
||||
/**
|
||||
* add job
|
||||
*
|
||||
* @param jobInfo
|
||||
* @return
|
||||
*/
|
||||
public ReturnT<String> add(XxlJobInfo jobInfo);
|
||||
|
||||
/**
|
||||
* update job
|
||||
*
|
||||
* @param jobInfo
|
||||
* @return
|
||||
*/
|
||||
public ReturnT<String> update(XxlJobInfo jobInfo);
|
||||
|
||||
/**
|
||||
* remove job
|
||||
* *
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public ReturnT<String> remove(int id);
|
||||
|
||||
/**
|
||||
* start job
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public ReturnT<String> start(int id);
|
||||
|
||||
/**
|
||||
* stop job
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public ReturnT<String> stop(int id);
|
||||
|
||||
/**
|
||||
* dashboard info
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<String,Object> dashboardInfo();
|
||||
|
||||
/**
|
||||
* chart info
|
||||
*
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @return
|
||||
*/
|
||||
public ReturnT<Map<String,Object>> chartInfo(Date startDate, Date endDate);
|
||||
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
package com.xxl.job.admin.service.impl;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.model.XxlJobLog;
|
||||
import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
|
||||
import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.dao.XxlJobGroupDao;
|
||||
import com.xxl.job.admin.dao.XxlJobInfoDao;
|
||||
import com.xxl.job.admin.dao.XxlJobLogDao;
|
||||
import com.xxl.job.admin.dao.XxlJobRegistryDao;
|
||||
import com.xxl.job.core.biz.AdminBiz;
|
||||
import com.xxl.job.core.biz.model.HandleCallbackParam;
|
||||
import com.xxl.job.core.biz.model.RegistryParam;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author xuxueli 2017-07-27 21:54:20
|
||||
*/
|
||||
@Service
|
||||
public class AdminBizImpl implements AdminBiz {
|
||||
private static Logger logger = LoggerFactory.getLogger(AdminBizImpl.class);
|
||||
|
||||
@Resource
|
||||
public XxlJobLogDao xxlJobLogDao;
|
||||
@Resource
|
||||
private XxlJobInfoDao xxlJobInfoDao;
|
||||
@Resource
|
||||
private XxlJobRegistryDao xxlJobRegistryDao;
|
||||
@Resource
|
||||
private XxlJobGroupDao xxlJobGroupDao;
|
||||
|
||||
|
||||
@Override
|
||||
public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {
|
||||
for (HandleCallbackParam handleCallbackParam: callbackParamList) {
|
||||
ReturnT<String> callbackResult = callback(handleCallbackParam);
|
||||
logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
|
||||
(callbackResult.getCode()==IJobHandler.SUCCESS.getCode()?"success":"fail"), handleCallbackParam, callbackResult);
|
||||
}
|
||||
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
private ReturnT<String> callback(HandleCallbackParam handleCallbackParam) {
|
||||
// valid log item
|
||||
XxlJobLog log = xxlJobLogDao.load(handleCallbackParam.getLogId());
|
||||
if (log == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, "log item not found.");
|
||||
}
|
||||
if (log.getHandleCode() > 0) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, "log repeate callback."); // avoid repeat callback, trigger child job etc
|
||||
}
|
||||
|
||||
// trigger success, to trigger child job
|
||||
String callbackMsg = null;
|
||||
if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) {
|
||||
XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId());
|
||||
if (xxlJobInfo!=null && xxlJobInfo.getChildJobId()!=null && xxlJobInfo.getChildJobId().trim().length()>0) {
|
||||
callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_child_run") +"<<<<<<<<<<< </span><br>";
|
||||
|
||||
String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
|
||||
for (int i = 0; i < childJobIds.length; i++) {
|
||||
int childJobId = (childJobIds[i]!=null && childJobIds[i].trim().length()>0 && isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1;
|
||||
if (childJobId > 0) {
|
||||
|
||||
JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null);
|
||||
ReturnT<String> triggerChildResult = ReturnT.SUCCESS;
|
||||
|
||||
// add msg
|
||||
callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
|
||||
(i+1),
|
||||
childJobIds.length,
|
||||
childJobIds[i],
|
||||
(triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")),
|
||||
triggerChildResult.getMsg());
|
||||
} else {
|
||||
callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
|
||||
(i+1),
|
||||
childJobIds.length,
|
||||
childJobIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// handle msg
|
||||
StringBuffer handleMsg = new StringBuffer();
|
||||
if (log.getHandleMsg()!=null) {
|
||||
handleMsg.append(log.getHandleMsg()).append("<br>");
|
||||
}
|
||||
if (handleCallbackParam.getExecuteResult().getMsg() != null) {
|
||||
handleMsg.append(handleCallbackParam.getExecuteResult().getMsg());
|
||||
}
|
||||
if (callbackMsg != null) {
|
||||
handleMsg.append(callbackMsg);
|
||||
}
|
||||
|
||||
if (handleMsg.length() > 15000) {
|
||||
handleMsg = new StringBuffer(handleMsg.substring(0, 15000)); // text最大64kb 避免长度过长
|
||||
}
|
||||
|
||||
// success, save log
|
||||
log.setHandleTime(new Date());
|
||||
log.setHandleCode(handleCallbackParam.getExecuteResult().getCode());
|
||||
log.setHandleMsg(handleMsg.toString());
|
||||
xxlJobLogDao.updateHandleInfo(log);
|
||||
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
private boolean isNumeric(String str){
|
||||
try {
|
||||
int result = Integer.valueOf(str);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> registry(RegistryParam registryParam) {
|
||||
|
||||
// valid
|
||||
if (!StringUtils.hasText(registryParam.getRegistryGroup())
|
||||
|| !StringUtils.hasText(registryParam.getRegistryKey())
|
||||
|| !StringUtils.hasText(registryParam.getRegistryValue())) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
|
||||
}
|
||||
|
||||
int ret = xxlJobRegistryDao.registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
|
||||
if (ret < 1) {
|
||||
xxlJobRegistryDao.registrySave(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
|
||||
|
||||
// fresh
|
||||
freshGroupRegistryInfo(registryParam);
|
||||
}
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> registryRemove(RegistryParam registryParam) {
|
||||
|
||||
// valid
|
||||
if (!StringUtils.hasText(registryParam.getRegistryGroup())
|
||||
|| !StringUtils.hasText(registryParam.getRegistryKey())
|
||||
|| !StringUtils.hasText(registryParam.getRegistryValue())) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
|
||||
}
|
||||
|
||||
int ret = xxlJobRegistryDao.registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());
|
||||
if (ret > 0) {
|
||||
|
||||
// fresh
|
||||
freshGroupRegistryInfo(registryParam);
|
||||
}
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
private void freshGroupRegistryInfo(RegistryParam registryParam){
|
||||
// Under consideration, prevent affecting core tables
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,372 @@
|
|||
package com.xxl.job.admin.service.impl;
|
||||
|
||||
import com.xxl.job.admin.core.model.XxlJobGroup;
|
||||
import com.xxl.job.admin.core.model.XxlJobInfo;
|
||||
import com.xxl.job.admin.core.cron.CronExpression;
|
||||
import com.xxl.job.admin.core.model.XxlJobLogReport;
|
||||
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
|
||||
import com.xxl.job.admin.core.thread.JobScheduleHelper;
|
||||
import com.xxl.job.admin.core.util.I18nUtil;
|
||||
import com.xxl.job.admin.dao.*;
|
||||
import com.xxl.job.admin.service.XxlJobService;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
|
||||
import com.xxl.job.core.glue.GlueTypeEnum;
|
||||
import com.xxl.job.core.util.DateUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* core job action for xxl-job
|
||||
* @author xuxueli 2016-5-28 15:30:33
|
||||
*/
|
||||
@Service
|
||||
public class XxlJobServiceImpl implements XxlJobService {
|
||||
private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);
|
||||
|
||||
@Resource
|
||||
private XxlJobGroupDao xxlJobGroupDao;
|
||||
@Resource
|
||||
private XxlJobInfoDao xxlJobInfoDao;
|
||||
@Resource
|
||||
public XxlJobLogDao xxlJobLogDao;
|
||||
@Resource
|
||||
private XxlJobLogGlueDao xxlJobLogGlueDao;
|
||||
@Resource
|
||||
private XxlJobLogReportDao xxlJobLogReportDao;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
|
||||
|
||||
// page list
|
||||
List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
|
||||
int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
|
||||
|
||||
// package result
|
||||
Map<String, Object> maps = new HashMap<String, Object>();
|
||||
maps.put("recordsTotal", list_count); // 总记录数
|
||||
maps.put("recordsFiltered", list_count); // 过滤后的总记录数
|
||||
maps.put("data", list); // 分页列表
|
||||
return maps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> add(XxlJobInfo jobInfo) {
|
||||
// valid
|
||||
XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
|
||||
if (group == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")) );
|
||||
}
|
||||
if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
|
||||
}
|
||||
if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
|
||||
}
|
||||
if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
|
||||
}
|
||||
if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
|
||||
}
|
||||
if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
|
||||
}
|
||||
if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype")+I18nUtil.getString("system_unvalid")) );
|
||||
}
|
||||
if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler()==null || jobInfo.getExecutorHandler().trim().length()==0) ) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") );
|
||||
}
|
||||
|
||||
// fix "\r" in shell
|
||||
if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource()!=null) {
|
||||
jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));
|
||||
}
|
||||
|
||||
// ChildJobId valid
|
||||
if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
|
||||
String[] childJobIds = jobInfo.getChildJobId().split(",");
|
||||
for (String childJobIdItem: childJobIds) {
|
||||
if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
|
||||
XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));
|
||||
if (childJobInfo==null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE,
|
||||
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
|
||||
}
|
||||
} else {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE,
|
||||
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
|
||||
}
|
||||
}
|
||||
|
||||
// join , avoid "xxx,,"
|
||||
String temp = "";
|
||||
for (String item:childJobIds) {
|
||||
temp += item + ",";
|
||||
}
|
||||
temp = temp.substring(0, temp.length()-1);
|
||||
|
||||
jobInfo.setChildJobId(temp);
|
||||
}
|
||||
|
||||
// add in db
|
||||
jobInfo.setAddTime(new Date());
|
||||
jobInfo.setUpdateTime(new Date());
|
||||
jobInfo.setGlueUpdatetime(new Date());
|
||||
xxlJobInfoDao.save(jobInfo);
|
||||
if (jobInfo.getId() < 1) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) );
|
||||
}
|
||||
|
||||
return new ReturnT<String>(String.valueOf(jobInfo.getId()));
|
||||
}
|
||||
|
||||
private boolean isNumeric(String str){
|
||||
try {
|
||||
int result = Integer.valueOf(str);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> update(XxlJobInfo jobInfo) {
|
||||
|
||||
// valid
|
||||
if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
|
||||
}
|
||||
if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
|
||||
}
|
||||
if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
|
||||
}
|
||||
if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
|
||||
}
|
||||
if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
|
||||
}
|
||||
|
||||
// ChildJobId valid
|
||||
if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
|
||||
String[] childJobIds = jobInfo.getChildJobId().split(",");
|
||||
for (String childJobIdItem: childJobIds) {
|
||||
if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
|
||||
XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));
|
||||
if (childJobInfo==null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE,
|
||||
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
|
||||
}
|
||||
} else {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE,
|
||||
MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
|
||||
}
|
||||
}
|
||||
|
||||
// join , avoid "xxx,,"
|
||||
String temp = "";
|
||||
for (String item:childJobIds) {
|
||||
temp += item + ",";
|
||||
}
|
||||
temp = temp.substring(0, temp.length()-1);
|
||||
|
||||
jobInfo.setChildJobId(temp);
|
||||
}
|
||||
|
||||
// group valid
|
||||
XxlJobGroup jobGroup = xxlJobGroupDao.load(jobInfo.getJobGroup());
|
||||
if (jobGroup == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_jobgroup")+I18nUtil.getString("system_unvalid")) );
|
||||
}
|
||||
|
||||
// stage job info
|
||||
XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());
|
||||
if (exists_jobInfo == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_not_found")) );
|
||||
}
|
||||
|
||||
// next trigger time (5s后生效,避开预读周期)
|
||||
long nextTriggerTime = exists_jobInfo.getTriggerNextTime();
|
||||
if (exists_jobInfo.getTriggerStatus() == 1 && !jobInfo.getJobCron().equals(exists_jobInfo.getJobCron()) ) {
|
||||
try {
|
||||
Date nextValidTime = new CronExpression(jobInfo.getJobCron()).getNextValidTimeAfter(new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
|
||||
if (nextValidTime == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_never_fire"));
|
||||
}
|
||||
nextTriggerTime = nextValidTime.getTime();
|
||||
} catch (ParseException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid")+" | "+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
exists_jobInfo.setJobGroup(jobInfo.getJobGroup());
|
||||
exists_jobInfo.setJobCron(jobInfo.getJobCron());
|
||||
exists_jobInfo.setJobDesc(jobInfo.getJobDesc());
|
||||
exists_jobInfo.setAuthor(jobInfo.getAuthor());
|
||||
exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());
|
||||
exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());
|
||||
exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler());
|
||||
exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());
|
||||
exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
|
||||
exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());
|
||||
exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());
|
||||
exists_jobInfo.setChildJobId(jobInfo.getChildJobId());
|
||||
exists_jobInfo.setTriggerNextTime(nextTriggerTime);
|
||||
|
||||
exists_jobInfo.setUpdateTime(new Date());
|
||||
xxlJobInfoDao.update(exists_jobInfo);
|
||||
|
||||
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> remove(int id) {
|
||||
XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
|
||||
if (xxlJobInfo == null) {
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
xxlJobInfoDao.delete(id);
|
||||
xxlJobLogDao.delete(id);
|
||||
xxlJobLogGlueDao.deleteByJobId(id);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> start(int id) {
|
||||
XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
|
||||
|
||||
// next trigger time (5s后生效,避开预读周期)
|
||||
long nextTriggerTime = 0;
|
||||
try {
|
||||
Date nextValidTime = new CronExpression(xxlJobInfo.getJobCron()).getNextValidTimeAfter(new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
|
||||
if (nextValidTime == null) {
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_never_fire"));
|
||||
}
|
||||
nextTriggerTime = nextValidTime.getTime();
|
||||
} catch (ParseException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid")+" | "+ e.getMessage());
|
||||
}
|
||||
|
||||
xxlJobInfo.setTriggerStatus(1);
|
||||
xxlJobInfo.setTriggerLastTime(0);
|
||||
xxlJobInfo.setTriggerNextTime(nextTriggerTime);
|
||||
|
||||
xxlJobInfo.setUpdateTime(new Date());
|
||||
xxlJobInfoDao.update(xxlJobInfo);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<String> stop(int id) {
|
||||
XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
|
||||
|
||||
xxlJobInfo.setTriggerStatus(0);
|
||||
xxlJobInfo.setTriggerLastTime(0);
|
||||
xxlJobInfo.setTriggerNextTime(0);
|
||||
|
||||
xxlJobInfo.setUpdateTime(new Date());
|
||||
xxlJobInfoDao.update(xxlJobInfo);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> dashboardInfo() {
|
||||
|
||||
int jobInfoCount = xxlJobInfoDao.findAllCount();
|
||||
int jobLogCount = 0;
|
||||
int jobLogSuccessCount = 0;
|
||||
XxlJobLogReport xxlJobLogReport = xxlJobLogReportDao.queryLogReportTotal();
|
||||
if (xxlJobLogReport != null) {
|
||||
jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount();
|
||||
jobLogSuccessCount = xxlJobLogReport.getSucCount();
|
||||
}
|
||||
|
||||
// executor count
|
||||
Set<String> executorAddressSet = new HashSet<String>();
|
||||
List<XxlJobGroup> groupList = xxlJobGroupDao.findAll();
|
||||
|
||||
if (groupList!=null && !groupList.isEmpty()) {
|
||||
for (XxlJobGroup group: groupList) {
|
||||
if (group.getRegistryList()!=null && !group.getRegistryList().isEmpty()) {
|
||||
executorAddressSet.addAll(group.getRegistryList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int executorCount = executorAddressSet.size();
|
||||
|
||||
Map<String, Object> dashboardMap = new HashMap<String, Object>();
|
||||
dashboardMap.put("jobInfoCount", jobInfoCount);
|
||||
dashboardMap.put("jobLogCount", jobLogCount);
|
||||
dashboardMap.put("jobLogSuccessCount", jobLogSuccessCount);
|
||||
dashboardMap.put("executorCount", executorCount);
|
||||
return dashboardMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
|
||||
|
||||
// process
|
||||
List<String> triggerDayList = new ArrayList<String>();
|
||||
List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();
|
||||
List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
|
||||
List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
|
||||
int triggerCountRunningTotal = 0;
|
||||
int triggerCountSucTotal = 0;
|
||||
int triggerCountFailTotal = 0;
|
||||
|
||||
List<XxlJobLogReport> logReportList = xxlJobLogReportDao.queryLogReport(startDate, endDate);
|
||||
|
||||
if (logReportList!=null && logReportList.size()>0) {
|
||||
for (XxlJobLogReport item: logReportList) {
|
||||
String day = DateUtil.formatDate(item.getTriggerDay());
|
||||
int triggerDayCountRunning = item.getRunningCount();
|
||||
int triggerDayCountSuc = item.getSucCount();
|
||||
int triggerDayCountFail = item.getFailCount();
|
||||
|
||||
triggerDayList.add(day);
|
||||
triggerDayCountRunningList.add(triggerDayCountRunning);
|
||||
triggerDayCountSucList.add(triggerDayCountSuc);
|
||||
triggerDayCountFailList.add(triggerDayCountFail);
|
||||
|
||||
triggerCountRunningTotal += triggerDayCountRunning;
|
||||
triggerCountSucTotal += triggerDayCountSuc;
|
||||
triggerCountFailTotal += triggerDayCountFail;
|
||||
}
|
||||
} else {
|
||||
for (int i = -6; i <= 0; i++) {
|
||||
triggerDayList.add(DateUtil.formatDate(DateUtil.addDays(new Date(), i)));
|
||||
triggerDayCountRunningList.add(0);
|
||||
triggerDayCountSucList.add(0);
|
||||
triggerDayCountFailList.add(0);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("triggerDayList", triggerDayList);
|
||||
result.put("triggerDayCountRunningList", triggerDayCountRunningList);
|
||||
result.put("triggerDayCountSucList", triggerDayCountSucList);
|
||||
result.put("triggerDayCountFailList", triggerDayCountFailList);
|
||||
|
||||
result.put("triggerCountRunningTotal", triggerCountRunningTotal);
|
||||
result.put("triggerCountSucTotal", triggerCountSucTotal);
|
||||
result.put("triggerCountFailTotal", triggerCountFailTotal);
|
||||
|
||||
return new ReturnT<Map<String, Object>>(result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
### web
|
||||
server.port=80
|
||||
server.servlet.context-path=/admin
|
||||
|
||||
### actuator
|
||||
management.server.servlet.context-path=/actuator
|
||||
management.health.mail.enabled=false
|
||||
|
||||
### resources
|
||||
spring.mvc.servlet.load-on-startup=0
|
||||
spring.mvc.static-path-pattern=/static/**
|
||||
spring.resources.static-locations=classpath:/static/
|
||||
|
||||
### freemarker
|
||||
spring.freemarker.templateLoaderPath=classpath:/templates/
|
||||
spring.freemarker.suffix=.ftl
|
||||
spring.freemarker.charset=UTF-8
|
||||
spring.freemarker.request-context-attribute=request
|
||||
spring.freemarker.settings.number_format=0.##########
|
||||
|
||||
### mybatis
|
||||
mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml
|
||||
#mybatis.type-aliases-package=com.xxl.job.admin.core.model
|
||||
|
||||
### xxl-job, datasource
|
||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=123456
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
### datasource-pool
|
||||
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
|
||||
spring.datasource.hikari.minimum-idle=10
|
||||
spring.datasource.hikari.maximum-pool-size=30
|
||||
spring.datasource.hikari.auto-commit=true
|
||||
spring.datasource.hikari.idle-timeout=30000
|
||||
spring.datasource.hikari.pool-name=HikariCP
|
||||
spring.datasource.hikari.max-lifetime=900000
|
||||
spring.datasource.hikari.connection-timeout=10000
|
||||
spring.datasource.hikari.connection-test-query=SELECT 1
|
||||
|
||||
### xxl-job, email
|
||||
spring.mail.host=smtp.qq.com
|
||||
spring.mail.port=25
|
||||
spring.mail.username=27447985@qq.com
|
||||
spring.mail.password=123456
|
||||
spring.mail.properties.mail.smtp.auth=true
|
||||
spring.mail.properties.mail.smtp.starttls.enable=true
|
||||
spring.mail.properties.mail.smtp.starttls.required=true
|
||||
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
|
||||
|
||||
### xxl-job, access token
|
||||
xxl.job.accessToken=
|
||||
|
||||
### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")
|
||||
xxl.job.i18n=zh_CN
|
||||
|
||||
## xxl-job, triggerpool max size
|
||||
xxl.job.triggerpool.fast.max=200
|
||||
xxl.job.triggerpool.slow.max=100
|
||||
|
||||
### xxl-job, log retention days
|
||||
xxl.job.logretentiondays=30
|
|
@ -0,0 +1 @@
|
|||
spring.profiles.active=dev
|
|
@ -0,0 +1,264 @@
|
|||
admin_name=Scheduling Center
|
||||
admin_name_full=Distributed Task Scheduling Platform
|
||||
admin_version=2.2.0
|
||||
admin_i18n=en
|
||||
|
||||
## system
|
||||
system_tips=System message
|
||||
system_ok=Confirm
|
||||
system_close=Close
|
||||
system_save=Save
|
||||
system_cancel=Cancel
|
||||
system_search=Search
|
||||
system_status=Status
|
||||
system_opt=Operate
|
||||
system_please_input=please input
|
||||
system_please_choose=please choose
|
||||
system_success=success
|
||||
system_fail=fail
|
||||
system_add_suc=add success
|
||||
system_add_fail=add fail
|
||||
system_update_suc=update success
|
||||
system_update_fail=update fail
|
||||
system_all=All
|
||||
system_api_error=net error
|
||||
system_show=Show
|
||||
system_empty=Empty
|
||||
system_opt_suc=operate success
|
||||
system_opt_fail=operate fail
|
||||
system_opt_edit=Edit
|
||||
system_opt_del=Delete
|
||||
system_opt_copy=Copy
|
||||
system_unvalid=illegal
|
||||
system_not_found=not exist
|
||||
system_nav=Navigation
|
||||
system_digits=digits
|
||||
system_lengh_limit=Length limit
|
||||
system_permission_limit=Permission limit
|
||||
system_welcome=Welcome
|
||||
|
||||
## daterangepicker
|
||||
daterangepicker_ranges_recent_hour=recent one hour
|
||||
daterangepicker_ranges_today=today
|
||||
daterangepicker_ranges_yesterday=yesterday
|
||||
daterangepicker_ranges_this_month=this month
|
||||
daterangepicker_ranges_last_month=last month
|
||||
daterangepicker_ranges_recent_week=recent one week
|
||||
daterangepicker_ranges_recent_month=recent one month
|
||||
daterangepicker_custom_name=custom
|
||||
daterangepicker_custom_starttime=start time
|
||||
daterangepicker_custom_endtime=end time
|
||||
daterangepicker_custom_daysofweek=Sun,Mon,Tue,Wed,Thu,Fri,Sat
|
||||
daterangepicker_custom_monthnames=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
|
||||
|
||||
## dataTable
|
||||
dataTable_sProcessing=processing...
|
||||
dataTable_sLengthMenu= _MENU_ records per page
|
||||
dataTable_sZeroRecords=No matching results
|
||||
dataTable_sInfo=page _PAGE_ ( Total _PAGES_ pages,_TOTAL_ records )
|
||||
dataTable_sInfoEmpty=No Record
|
||||
dataTable_sInfoFiltered=(Filtered by _MAX_ results)
|
||||
dataTable_sSearch=Search
|
||||
dataTable_sEmptyTable=Table data is empty
|
||||
dataTable_sLoadingRecords=Loading...
|
||||
dataTable_sFirst=FIRST PAGE
|
||||
dataTable_sPrevious=Previous Page
|
||||
dataTable_sNext=Next Page
|
||||
dataTable_sLast=LAST PAGE
|
||||
dataTable_sSortAscending=: Rank this column in ascending order
|
||||
dataTable_sSortDescending=: Rank this column in descending order
|
||||
|
||||
## login
|
||||
login_btn=Login
|
||||
login_remember_me=Remember Me
|
||||
login_username_placeholder=Please enter username
|
||||
login_password_placeholder=Please enter password
|
||||
login_username_empty=Please enter username
|
||||
login_username_lt_4=Username length should not be less than 4
|
||||
login_password_empty=Please enter password
|
||||
login_password_lt_4=Password length should not be less than 4
|
||||
login_success=Login success
|
||||
login_fail=Login fail
|
||||
login_param_empty=Username or password is empty
|
||||
login_param_unvalid=Username or password error
|
||||
|
||||
## logout
|
||||
logout_btn=Logout
|
||||
logout_confirm=Confirm logout?
|
||||
logout_success=Logout success
|
||||
logout_fail=Logout fail
|
||||
|
||||
## change pwd
|
||||
change_pwd=Change password
|
||||
change_pwd_suc_to_logout=Change password successful, about to log out login
|
||||
change_pwd_field_newpwd=new password
|
||||
|
||||
## dashboard
|
||||
job_dashboard_name=Run report
|
||||
job_dashboard_job_num=Job number
|
||||
job_dashboard_job_num_tip=The number of tasks running in the scheduling center
|
||||
job_dashboard_trigger_num=trigger number
|
||||
job_dashboard_trigger_num_tip=The number of trigger record scheduled by the scheduling center
|
||||
job_dashboard_jobgroup_num=Executor number
|
||||
job_dashboard_jobgroup_num_tip=The number of online executor machines perceived by the scheduling center
|
||||
job_dashboard_report=Scheduling report
|
||||
job_dashboard_report_loaddata_fail=Scheduling report load data error
|
||||
job_dashboard_date_report=Date distribution
|
||||
job_dashboard_rate_report=Percentage distribution
|
||||
|
||||
## job info
|
||||
jobinfo_name=Job Manage
|
||||
jobinfo_job=Job
|
||||
jobinfo_field_add=Add Job
|
||||
jobinfo_field_update=Edit Job
|
||||
jobinfo_field_id=Job ID
|
||||
jobinfo_field_jobgroup=Executor
|
||||
jobinfo_field_jobdesc=Job description
|
||||
jobinfo_field_timeout=Job timeout period
|
||||
jobinfo_field_gluetype=GLUE Type
|
||||
jobinfo_field_executorparam=Param
|
||||
jobinfo_field_cron_unvalid=The Cron is illegal
|
||||
jobinfo_field_cron_never_fire=The Cron will never fire
|
||||
jobinfo_field_author=Author
|
||||
jobinfo_field_alarmemail=Alarm email
|
||||
jobinfo_field_alarmemail_placeholder=Please enter alarm mail, if there are more than one comma separated
|
||||
jobinfo_field_executorRouteStrategy=Route Strategy
|
||||
jobinfo_field_childJobId=Child Job ID
|
||||
jobinfo_field_childJobId_placeholder=Please enter the Child job ID, if there are more than one comma separated
|
||||
jobinfo_field_executorBlockStrategy=Block Strategy
|
||||
jobinfo_field_executorFailRetryCount=Fail Retry Count
|
||||
jobinfo_field_executorFailRetryCount_placeholder=Fail Retry Count. effect if greater than zero
|
||||
jobinfo_script_location=Script location
|
||||
jobinfo_shard_index=Shard index
|
||||
jobinfo_shard_total=Shard total
|
||||
jobinfo_opt_stop=Stop
|
||||
jobinfo_opt_start=Start
|
||||
jobinfo_opt_log=Query Log
|
||||
jobinfo_opt_run=Run Once
|
||||
jobinfo_opt_run_tips=Please input the address for this trigger. Null will be obtained from the executor
|
||||
jobinfo_opt_registryinfo=Registry Info
|
||||
jobinfo_opt_next_time=Next trigger time
|
||||
jobinfo_glue_remark=Resource Remark
|
||||
jobinfo_glue_remark_limit=Resource Remark length is limited to 4~100
|
||||
jobinfo_glue_rollback=Version Backtrack
|
||||
jobinfo_glue_jobid_unvalid=Job ID is illegal
|
||||
jobinfo_glue_gluetype_unvalid=The job is not GLUE Type
|
||||
jobinfo_field_executorTimeout_placeholder=Job Timeout period,in seconds. effect if greater than zero
|
||||
|
||||
## job log
|
||||
joblog_name=Trigger Log
|
||||
joblog_status=Status
|
||||
joblog_status_all=All
|
||||
joblog_status_suc=Success
|
||||
joblog_status_fail=Fail
|
||||
joblog_status_running=Running
|
||||
joblog_field_triggerTime=Trigger Time
|
||||
joblog_field_triggerCode=Trigger Result
|
||||
joblog_field_triggerMsg=Trigger Msg
|
||||
joblog_field_handleTime=Handle Time
|
||||
joblog_field_handleCode=Handle Result
|
||||
joblog_field_handleMsg=Trigger Msg
|
||||
joblog_field_executorAddress=Executor Address
|
||||
joblog_clean=Clean
|
||||
joblog_clean_log=Clean Log
|
||||
joblog_clean_type=Clean Type
|
||||
joblog_clean_type_1=Clean up log data a month ago
|
||||
joblog_clean_type_2=Clean up log data three month ago
|
||||
joblog_clean_type_3=Clean up log data six month ago
|
||||
joblog_clean_type_4=Clean up log data a year ago
|
||||
joblog_clean_type_5=Clean up log data a thousand record ago
|
||||
joblog_clean_type_6=Clean up log data ten thousand record ago
|
||||
joblog_clean_type_7=Clean up log data thirty thousand record ago
|
||||
joblog_clean_type_8=Clean up log data hundred thousand record ago
|
||||
joblog_clean_type_9=Clean up all log data
|
||||
joblog_clean_type_unvalid=Clean type is illegal
|
||||
joblog_handleCode_200=Success
|
||||
joblog_handleCode_500=Fail
|
||||
joblog_handleCode_502=Timeout
|
||||
joblog_kill_log=Kill Job
|
||||
joblog_kill_log_limit=Trigger Fail, can not kill job
|
||||
joblog_kill_log_byman=Manual operation, kill job
|
||||
joblog_lost_fail=Job result lost, marked as failure
|
||||
joblog_rolling_log=Rolling log
|
||||
joblog_rolling_log_refresh=Refresh
|
||||
joblog_rolling_log_triggerfail=The job trigger fail, can not view the rolling log
|
||||
joblog_rolling_log_failoften=The request for the Rolling log is terminated, the number of failed requests exceeds the limit, Reload the log on the refresh page
|
||||
joblog_logid_unvalid=Log ID is illegal
|
||||
|
||||
## job group
|
||||
jobgroup_name=Executor Manage
|
||||
jobgroup_list=Executor List
|
||||
jobgroup_add=Add Executor
|
||||
jobgroup_edit=Edit Executor
|
||||
jobgroup_del=Delete Executor
|
||||
jobgroup_field_title=Title
|
||||
jobgroup_field_addressType=Registry Type
|
||||
jobgroup_field_addressType_0=Automatic registration
|
||||
jobgroup_field_addressType_1=Manual registration
|
||||
jobgroup_field_addressType_limit=Manually registration type, the machine address must not be empty
|
||||
jobgroup_field_registryList=machine address
|
||||
jobgroup_field_registryList_unvalid=registry machine address is illegal
|
||||
jobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated
|
||||
jobgroup_field_appname_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and hyphen.
|
||||
jobgroup_field_appname_length=AppName length is limited to 4~64
|
||||
jobgroup_field_title_length=Title length is limited to 4~12
|
||||
jobgroup_field_order_digits=Please enter a positive integer
|
||||
jobgroup_field_orderrange=Order is limited to 1~1000
|
||||
jobgroup_del_limit_0=Refuse to delete, the executor is being used
|
||||
jobgroup_del_limit_1=Refuses to delete, the system retains at least one executor
|
||||
jobgroup_empty=There is no valid executor. Please contact the administrator
|
||||
|
||||
## job conf
|
||||
jobconf_block_SERIAL_EXECUTION=Serial execution
|
||||
jobconf_block_DISCARD_LATER=Discard Later
|
||||
jobconf_block_COVER_EARLY=Cover Early
|
||||
jobconf_route_first=First
|
||||
jobconf_route_last=Last
|
||||
jobconf_route_round=Round
|
||||
jobconf_route_random=Random
|
||||
jobconf_route_consistenthash=Consistent Hash
|
||||
jobconf_route_lfu=Least Frequently Used
|
||||
jobconf_route_lru=Least Recently Used
|
||||
jobconf_route_failover=Failover
|
||||
jobconf_route_busyover=Busyover
|
||||
jobconf_route_shard=Sharding Broadcast
|
||||
jobconf_idleBeat=Idle check
|
||||
jobconf_beat=Heartbeats
|
||||
jobconf_monitor=Task Scheduling Center monitor alarm
|
||||
jobconf_monitor_detail=monitor alarm details
|
||||
jobconf_monitor_alarm_title=Alarm Type
|
||||
jobconf_monitor_alarm_type=Trigger Fail
|
||||
jobconf_monitor_alarm_content=Alarm Content
|
||||
jobconf_trigger_admin_adress=Trigger machine address
|
||||
jobconf_trigger_exe_regtype=Execotor-Registry Type
|
||||
jobconf_trigger_exe_regaddress=Execotor-Registry Address
|
||||
jobconf_trigger_address_empty=Trigger Fail:registry address is empty
|
||||
jobconf_trigger_run=Trigger Job
|
||||
jobconf_trigger_child_run=Trigger child job
|
||||
jobconf_callback_child_msg1={0}/{1} [Job ID={2}], Trigger {3}, Trigger msg: {4} <br>
|
||||
jobconf_callback_child_msg2={0}/{1} [Job ID={2}], Trigger Fail, Trigger msg: Job ID is illegal <br>
|
||||
jobconf_trigger_type=Job trigger type
|
||||
jobconf_trigger_type_cron=Cron trigger
|
||||
jobconf_trigger_type_manual=Manual trigger
|
||||
jobconf_trigger_type_parent=Parent job trigger
|
||||
jobconf_trigger_type_api=Api trigger
|
||||
jobconf_trigger_type_retry=Fail retry trigger
|
||||
|
||||
## user
|
||||
user_manage=User Manage
|
||||
user_username=Username
|
||||
user_password=Password
|
||||
user_role=Role
|
||||
user_role_admin=Admin User
|
||||
user_role_normal=Normal User
|
||||
user_permission=Permission
|
||||
user_add=Add User
|
||||
user_update=Edit User
|
||||
user_username_repeat=Username Repeat
|
||||
user_username_valid=Restrictions start with a lowercase letter and consist of lowercase letters and Numbers
|
||||
user_password_update_placeholder=Please input password, empty means not update
|
||||
user_update_loginuser_limit=Operation of current login account is not allowed
|
||||
|
||||
## help
|
||||
job_help=Tutorial
|
||||
job_help_document=Official Document
|
|
@ -0,0 +1,264 @@
|
|||
admin_name=确实任务调度中心
|
||||
admin_name_full=确实任务调度中心
|
||||
admin_version=2.2.0
|
||||
admin_i18n=
|
||||
|
||||
## system
|
||||
system_tips=系统提示
|
||||
system_ok=确定
|
||||
system_close=关闭
|
||||
system_save=保存
|
||||
system_cancel=取消
|
||||
system_search=搜索
|
||||
system_status=状态
|
||||
system_opt=操作
|
||||
system_please_input=请输入
|
||||
system_please_choose=请选择
|
||||
system_success=成功
|
||||
system_fail=失败
|
||||
system_add_suc=新增成功
|
||||
system_add_fail=新增失败
|
||||
system_update_suc=更新成功
|
||||
system_update_fail=更新失败
|
||||
system_all=全部
|
||||
system_api_error=接口异常
|
||||
system_show=查看
|
||||
system_empty=无
|
||||
system_opt_suc=操作成功
|
||||
system_opt_fail=操作失败
|
||||
system_opt_edit=编辑
|
||||
system_opt_del=删除
|
||||
system_opt_copy=复制
|
||||
system_unvalid=非法
|
||||
system_not_found=不存在
|
||||
system_nav=导航
|
||||
system_digits=整数
|
||||
system_lengh_limit=长度限制
|
||||
system_permission_limit=权限拦截
|
||||
system_welcome=欢迎
|
||||
|
||||
## daterangepicker
|
||||
daterangepicker_ranges_recent_hour=最近一小时
|
||||
daterangepicker_ranges_today=今日
|
||||
daterangepicker_ranges_yesterday=昨日
|
||||
daterangepicker_ranges_this_month=本月
|
||||
daterangepicker_ranges_last_month=上个月
|
||||
daterangepicker_ranges_recent_week=最近一周
|
||||
daterangepicker_ranges_recent_month=最近一月
|
||||
daterangepicker_custom_name=自定义
|
||||
daterangepicker_custom_starttime=起始时间
|
||||
daterangepicker_custom_endtime=结束时间
|
||||
daterangepicker_custom_daysofweek=日,一,二,三,四,五,六
|
||||
daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月
|
||||
|
||||
## dataTable
|
||||
dataTable_sProcessing=处理中...
|
||||
dataTable_sLengthMenu=每页 _MENU_ 条记录
|
||||
dataTable_sZeroRecords=没有匹配结果
|
||||
dataTable_sInfo=第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 )
|
||||
dataTable_sInfoEmpty=无记录
|
||||
dataTable_sInfoFiltered=(由 _MAX_ 项结果过滤)
|
||||
dataTable_sSearch=搜索
|
||||
dataTable_sEmptyTable=表中数据为空
|
||||
dataTable_sLoadingRecords=载入中...
|
||||
dataTable_sFirst=首页
|
||||
dataTable_sPrevious=上页
|
||||
dataTable_sNext=下页
|
||||
dataTable_sLast=末页
|
||||
dataTable_sSortAscending=: 以升序排列此列
|
||||
dataTable_sSortDescending=: 以降序排列此列
|
||||
|
||||
## login
|
||||
login_btn=登录
|
||||
login_remember_me=记住密码
|
||||
login_username_placeholder=请输入登录账号
|
||||
login_password_placeholder=请输入登录密码
|
||||
login_username_empty=请输入登录账号
|
||||
login_username_lt_4=登录账号不应低于4位
|
||||
login_password_empty=请输入登录密码
|
||||
login_password_lt_4=登录密码不应低于4位
|
||||
login_success=登录成功
|
||||
login_fail=登录失败
|
||||
login_param_empty=账号或密码为空
|
||||
login_param_unvalid=账号或密码错误
|
||||
|
||||
## logout
|
||||
logout_btn=注销
|
||||
logout_confirm=确认注销登录?
|
||||
logout_success=注销成功
|
||||
logout_fail=注销失败
|
||||
|
||||
## change pwd
|
||||
change_pwd=修改密码
|
||||
change_pwd_suc_to_logout=修改密码成功,即将注销登陆
|
||||
change_pwd_field_newpwd=新密码
|
||||
|
||||
## dashboard
|
||||
job_dashboard_name=运行报表
|
||||
job_dashboard_job_num=任务数量
|
||||
job_dashboard_job_num_tip=调度中心运行的任务数量
|
||||
job_dashboard_trigger_num=调度次数
|
||||
job_dashboard_trigger_num_tip=调度中心触发的调度次数
|
||||
job_dashboard_jobgroup_num=执行器数量
|
||||
job_dashboard_jobgroup_num_tip=调度中心在线的执行器机器数量
|
||||
job_dashboard_report=调度报表
|
||||
job_dashboard_report_loaddata_fail=调度报表数据加载异常
|
||||
job_dashboard_date_report=日期分布图
|
||||
job_dashboard_rate_report=成功比例图
|
||||
|
||||
## job info
|
||||
jobinfo_name=任务管理
|
||||
jobinfo_job=任务
|
||||
jobinfo_field_add=新增
|
||||
jobinfo_field_update=更新任务
|
||||
jobinfo_field_id=任务ID
|
||||
jobinfo_field_jobgroup=执行器
|
||||
jobinfo_field_jobdesc=任务描述
|
||||
jobinfo_field_gluetype=运行模式
|
||||
jobinfo_field_executorparam=任务参数
|
||||
jobinfo_field_cron_unvalid=Cron格式非法
|
||||
jobinfo_field_cron_never_fire=Cron非法,永远不会触发
|
||||
jobinfo_field_author=负责人
|
||||
jobinfo_field_timeout=任务超时时间
|
||||
jobinfo_field_alarmemail=报警邮件
|
||||
jobinfo_field_alarmemail_placeholder=请输入报警邮件,多个邮件地址则逗号分隔
|
||||
jobinfo_field_executorRouteStrategy=路由策略
|
||||
jobinfo_field_childJobId=子任务ID
|
||||
jobinfo_field_childJobId_placeholder=请输入子任务的任务ID,如存在多个则逗号分隔
|
||||
jobinfo_field_executorBlockStrategy=阻塞处理策略
|
||||
jobinfo_field_executorFailRetryCount=失败重试次数
|
||||
jobinfo_field_executorFailRetryCount_placeholder=失败重试次数,大于零时生效
|
||||
jobinfo_script_location=脚本位置
|
||||
jobinfo_shard_index=分片序号
|
||||
jobinfo_shard_total=分片总数
|
||||
jobinfo_opt_stop=停止
|
||||
jobinfo_opt_start=启动
|
||||
jobinfo_opt_log=查询日志
|
||||
jobinfo_opt_run=执行一次
|
||||
jobinfo_opt_run_tips=请输入本次执行的机器地址,为空则从执行器获取
|
||||
jobinfo_opt_registryinfo=注册节点
|
||||
jobinfo_opt_next_time=下次执行时间
|
||||
jobinfo_glue_remark=源码备注
|
||||
jobinfo_glue_remark_limit=源码备注长度限制为4~100
|
||||
jobinfo_glue_rollback=版本回溯
|
||||
jobinfo_glue_jobid_unvalid=任务ID非法
|
||||
jobinfo_glue_gluetype_unvalid=该任务非GLUE模式
|
||||
jobinfo_field_executorTimeout_placeholder=任务超时时间,单位秒,大于零时生效
|
||||
|
||||
## job log
|
||||
joblog_name=调度日志
|
||||
joblog_status=状态
|
||||
joblog_status_all=全部
|
||||
joblog_status_suc=成功
|
||||
joblog_status_fail=失败
|
||||
joblog_status_running=进行中
|
||||
joblog_field_triggerTime=调度时间
|
||||
joblog_field_triggerCode=调度结果
|
||||
joblog_field_triggerMsg=调度备注
|
||||
joblog_field_handleTime=执行时间
|
||||
joblog_field_handleCode=执行结果
|
||||
joblog_field_handleMsg=执行备注
|
||||
joblog_field_executorAddress=执行器地址
|
||||
joblog_clean=清理
|
||||
joblog_clean_log=日志清理
|
||||
joblog_clean_type=清理方式
|
||||
joblog_clean_type_1=清理一个月之前日志数据
|
||||
joblog_clean_type_2=清理三个月之前日志数据
|
||||
joblog_clean_type_3=清理六个月之前日志数据
|
||||
joblog_clean_type_4=清理一年之前日志数据
|
||||
joblog_clean_type_5=清理一千条以前日志数据
|
||||
joblog_clean_type_6=清理一万条以前日志数据
|
||||
joblog_clean_type_7=清理三万条以前日志数据
|
||||
joblog_clean_type_8=清理十万条以前日志数据
|
||||
joblog_clean_type_9=清理所有日志数据
|
||||
joblog_clean_type_unvalid=清理类型参数异常
|
||||
joblog_handleCode_200=成功
|
||||
joblog_handleCode_500=失败
|
||||
joblog_handleCode_502=失败(超时)
|
||||
joblog_kill_log=终止任务
|
||||
joblog_kill_log_limit=调度失败,无法终止日志
|
||||
joblog_kill_log_byman=人为操作,主动终止
|
||||
joblog_lost_fail=任务结果丢失,标记失败
|
||||
joblog_rolling_log=执行日志
|
||||
joblog_rolling_log_refresh=刷新
|
||||
joblog_rolling_log_triggerfail=任务发起调度失败,无法查看执行日志
|
||||
joblog_rolling_log_failoften=终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志
|
||||
joblog_logid_unvalid=日志ID非法
|
||||
|
||||
## job group
|
||||
jobgroup_name=执行器管理
|
||||
jobgroup_list=执行器列表
|
||||
jobgroup_add=新增执行器
|
||||
jobgroup_edit=编辑执行器
|
||||
jobgroup_del=删除执行器
|
||||
jobgroup_field_title=名称
|
||||
jobgroup_field_addressType=注册方式
|
||||
jobgroup_field_addressType_0=自动注册
|
||||
jobgroup_field_addressType_1=手动录入
|
||||
jobgroup_field_addressType_limit=手动录入注册方式,机器地址不可为空
|
||||
jobgroup_field_registryList=机器地址
|
||||
jobgroup_field_registryList_unvalid=机器地址格式非法
|
||||
jobgroup_field_registryList_placeholder=请输入执行器地址列表,多地址逗号分隔
|
||||
jobgroup_field_appname_limit=限制以小写字母开头,由小写字母、数字和中划线组成
|
||||
jobgroup_field_appname_length=AppName长度限制为4~64
|
||||
jobgroup_field_title_length=名称长度限制为4~12
|
||||
jobgroup_field_order_digits=请输入整数
|
||||
jobgroup_field_orderrange=取值范围为1~1000
|
||||
jobgroup_del_limit_0=拒绝删除,该执行器使用中
|
||||
jobgroup_del_limit_1=拒绝删除, 系统至少保留一个执行器
|
||||
jobgroup_empty=不存在有效执行器,请联系管理员
|
||||
|
||||
## job conf
|
||||
jobconf_block_SERIAL_EXECUTION=单机串行
|
||||
jobconf_block_DISCARD_LATER=丢弃后续调度
|
||||
jobconf_block_COVER_EARLY=覆盖之前调度
|
||||
jobconf_route_first=第一个
|
||||
jobconf_route_last=最后一个
|
||||
jobconf_route_round=轮询
|
||||
jobconf_route_random=随机
|
||||
jobconf_route_consistenthash=一致性HASH
|
||||
jobconf_route_lfu=最不经常使用
|
||||
jobconf_route_lru=最近最久未使用
|
||||
jobconf_route_failover=故障转移
|
||||
jobconf_route_busyover=忙碌转移
|
||||
jobconf_route_shard=分片广播
|
||||
jobconf_idleBeat=空闲检测
|
||||
jobconf_beat=心跳检测
|
||||
jobconf_monitor=任务调度中心监控报警
|
||||
jobconf_monitor_detail=监控告警明细
|
||||
jobconf_monitor_alarm_title=告警类型
|
||||
jobconf_monitor_alarm_type=调度失败
|
||||
jobconf_monitor_alarm_content=告警内容
|
||||
jobconf_trigger_admin_adress=调度机器
|
||||
jobconf_trigger_exe_regtype=执行器-注册方式
|
||||
jobconf_trigger_exe_regaddress=执行器-地址列表
|
||||
jobconf_trigger_address_empty=调度失败:执行器地址为空
|
||||
jobconf_trigger_run=触发调度
|
||||
jobconf_trigger_child_run=触发子任务
|
||||
jobconf_callback_child_msg1={0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4} <br>
|
||||
jobconf_callback_child_msg2={0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误 <br>
|
||||
jobconf_trigger_type=任务触发类型
|
||||
jobconf_trigger_type_cron=Cron触发
|
||||
jobconf_trigger_type_manual=手动触发
|
||||
jobconf_trigger_type_parent=父任务触发
|
||||
jobconf_trigger_type_api=API触发
|
||||
jobconf_trigger_type_retry=失败重试触发
|
||||
|
||||
## user
|
||||
user_manage=用户管理
|
||||
user_username=账号
|
||||
user_password=密码
|
||||
user_role=角色
|
||||
user_role_admin=管理员
|
||||
user_role_normal=普通用户
|
||||
user_permission=权限
|
||||
user_add=新增用户
|
||||
user_update=更新用户
|
||||
user_username_repeat=账号重复
|
||||
user_username_valid=限制以小写字母开头,由小写字母、数字组成
|
||||
user_password_update_placeholder=请输入新密码,为空则不更新密码
|
||||
user_update_loginuser_limit=禁止操作当前登录账号
|
||||
|
||||
## help
|
||||
job_help=使用教程
|
||||
job_help_document=官方文档
|
|
@ -0,0 +1,264 @@
|
|||
admin_name=任務調度中心
|
||||
admin_name_full=确实任務調度中心
|
||||
admin_version=2.2.0
|
||||
admin_i18n=
|
||||
|
||||
## system
|
||||
system_tips=系統提示
|
||||
system_ok=確定
|
||||
system_close=關閉
|
||||
system_save=儲存
|
||||
system_cancel=取消
|
||||
system_search=搜尋
|
||||
system_status=狀態
|
||||
system_opt=操作
|
||||
system_please_input=請輸入
|
||||
system_please_choose=请選擇
|
||||
system_success=成功
|
||||
system_fail=失敗
|
||||
system_add_suc=新增成功
|
||||
system_add_fail=新增失敗
|
||||
system_update_suc=更新成功
|
||||
system_update_fail=更新失敗
|
||||
system_all=全部
|
||||
system_api_error=API錯誤
|
||||
system_show=查看
|
||||
system_empty=無
|
||||
system_opt_suc=操作成功
|
||||
system_opt_fail=操作失敗
|
||||
system_opt_edit=編輯
|
||||
system_opt_del=刪除
|
||||
system_opt_copy=復制
|
||||
system_unvalid=非法
|
||||
system_not_found=不存在
|
||||
system_nav=導航
|
||||
system_digits=整數
|
||||
system_lengh_limit=長度限制
|
||||
system_permission_limit=權限控管
|
||||
system_welcome=歡迎
|
||||
|
||||
## daterangepicker
|
||||
daterangepicker_ranges_recent_hour=最近一小時
|
||||
daterangepicker_ranges_today=今日
|
||||
daterangepicker_ranges_yesterday=昨日
|
||||
daterangepicker_ranges_this_month=本月
|
||||
daterangepicker_ranges_last_month=上個月
|
||||
daterangepicker_ranges_recent_week=最近一周
|
||||
daterangepicker_ranges_recent_month=最近一月
|
||||
daterangepicker_custom_name=自定義
|
||||
daterangepicker_custom_starttime=起始時間
|
||||
daterangepicker_custom_endtime=結束時間
|
||||
daterangepicker_custom_daysofweek=日,一,二,三,四,五,六
|
||||
daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月
|
||||
|
||||
## dataTable
|
||||
dataTable_sProcessing=處理中...
|
||||
dataTable_sLengthMenu=每頁 _MENU_ 條記錄
|
||||
dataTable_sZeroRecords=沒有相符合記錄
|
||||
dataTable_sInfo=第 _PAGE_ 頁 ( 總共 _PAGES_ 頁,_TOTAL_ 條記錄 )
|
||||
dataTable_sInfoEmpty=無記錄
|
||||
dataTable_sInfoFiltered=(由 _MAX_ 項結果過濾)
|
||||
dataTable_sSearch=搜尋
|
||||
dataTable_sEmptyTable=表中資料為空
|
||||
dataTable_sLoadingRecords=載入中...
|
||||
dataTable_sFirst=首頁
|
||||
dataTable_sPrevious=上頁
|
||||
dataTable_sNext=下頁
|
||||
dataTable_sLast=末頁
|
||||
dataTable_sSortAscending=: 以升幂排序此列
|
||||
dataTable_sSortDescending=: 以降幂排序此列
|
||||
|
||||
## login
|
||||
login_btn=登入
|
||||
login_remember_me=記住密碼
|
||||
login_username_placeholder=請輸入登入帳號
|
||||
login_password_placeholder=請輸入登入密碼
|
||||
login_username_empty=請輸入登入帳號
|
||||
login_username_lt_4=登入帳號不應低於4位數
|
||||
login_password_empty=請輸入登入密碼
|
||||
login_password_lt_4=登入密碼不應低於4位數
|
||||
login_success=登入成功
|
||||
login_fail=登入失敗
|
||||
login_param_empty=帳號或密碼為空值
|
||||
login_param_unvalid=帳號或密碼錯誤
|
||||
|
||||
## logout
|
||||
logout_btn=登出
|
||||
logout_confirm=確認登出?
|
||||
logout_success=登出成功
|
||||
logout_fail=登出失敗
|
||||
|
||||
## change pwd
|
||||
change_pwd=修改密碼
|
||||
change_pwd_suc_to_logout=修改密碼成功,即將登出
|
||||
change_pwd_field_newpwd=新密碼
|
||||
|
||||
## dashboard
|
||||
job_dashboard_name=運行報表
|
||||
job_dashboard_job_num=任務數量
|
||||
job_dashboard_job_num_tip=調度中心運行的任務數量
|
||||
job_dashboard_trigger_num=調度次數
|
||||
job_dashboard_trigger_num_tip=調度中心觸發的調度次數
|
||||
job_dashboard_jobgroup_num=執行器數量
|
||||
job_dashboard_jobgroup_num_tip=調度中心在線的執行器機器數量
|
||||
job_dashboard_report=調度報表
|
||||
job_dashboard_report_loaddata_fail=調度報表資料加載異常
|
||||
job_dashboard_date_report=日期分布圖
|
||||
job_dashboard_rate_report=成功比例圖
|
||||
|
||||
## job info
|
||||
jobinfo_name=任務管理
|
||||
jobinfo_job=任務
|
||||
jobinfo_field_add=新增
|
||||
jobinfo_field_update=更新任務
|
||||
jobinfo_field_id=任務ID
|
||||
jobinfo_field_jobgroup=執行器
|
||||
jobinfo_field_jobdesc=任務描述
|
||||
jobinfo_field_gluetype=運行模式
|
||||
jobinfo_field_executorparam=任務參數
|
||||
jobinfo_field_cron_unvalid=Cron 格式非法
|
||||
jobinfo_field_cron_never_fire=Cron 格式非法,永遠不會觸發
|
||||
jobinfo_field_author=負責人
|
||||
jobinfo_field_timeout=任務超時秒數
|
||||
jobinfo_field_alarmemail=告警郵件
|
||||
jobinfo_field_alarmemail_placeholder=輸入多個告警郵件地址,請以逗號分隔
|
||||
jobinfo_field_executorRouteStrategy=路由策略
|
||||
jobinfo_field_childJobId=子任務ID
|
||||
jobinfo_field_childJobId_placeholder=輸入子任務ID,如有多個請以逗號分隔
|
||||
jobinfo_field_executorBlockStrategy=阻塞處理策略
|
||||
jobinfo_field_executorFailRetryCount=失敗重試次數
|
||||
jobinfo_field_executorFailRetryCount_placeholder=失敗重試次數,大於零時生效
|
||||
jobinfo_script_location=腳本位置
|
||||
jobinfo_shard_index=分片序號
|
||||
jobinfo_shard_total=分片總數
|
||||
jobinfo_opt_stop=停止
|
||||
jobinfo_opt_start=啟動
|
||||
jobinfo_opt_log=查詢日誌
|
||||
jobinfo_opt_run=執行一次
|
||||
jobinfo_opt_run_tips=請輸入本次執行的機器地址,為空則從執行器獲取
|
||||
jobinfo_opt_registryinfo=注冊節點
|
||||
jobinfo_opt_next_time=下次執行時間
|
||||
jobinfo_glue_remark=源碼備註
|
||||
jobinfo_glue_remark_limit=源碼備註長度限制為4~100
|
||||
jobinfo_glue_rollback=版本回復
|
||||
jobinfo_glue_jobid_unvalid=任務ID非法
|
||||
jobinfo_glue_gluetype_unvalid=該任務非GLUE模式
|
||||
jobinfo_field_executorTimeout_placeholder=任務超時時間,單位秒,大於零時生效
|
||||
|
||||
## job log
|
||||
joblog_name=調度日誌
|
||||
joblog_status=狀態
|
||||
joblog_status_all=全部
|
||||
joblog_status_suc=成功
|
||||
joblog_status_fail=失敗
|
||||
joblog_status_running=進行中
|
||||
joblog_field_triggerTime=調度時間
|
||||
joblog_field_triggerCode=調度結果
|
||||
joblog_field_triggerMsg=調度備註
|
||||
joblog_field_handleTime=執行時間
|
||||
joblog_field_handleCode=執行结果
|
||||
joblog_field_handleMsg=執行備註
|
||||
joblog_field_executorAddress=執行器地址
|
||||
joblog_clean=清理
|
||||
joblog_clean_log=日誌清理
|
||||
joblog_clean_type=清理方式
|
||||
joblog_clean_type_1=清理一個月之前日誌資料
|
||||
joblog_clean_type_2=清理三個月之前日誌資料
|
||||
joblog_clean_type_3=清理六個月之前日誌資料
|
||||
joblog_clean_type_4=清理一年之前日誌資料
|
||||
joblog_clean_type_5=清理一千條以前日誌資料
|
||||
joblog_clean_type_6=清理一萬條以前日誌資料
|
||||
joblog_clean_type_7=清理三萬條以前日誌資料
|
||||
joblog_clean_type_8=清理十萬條以前日誌資料
|
||||
joblog_clean_type_9=清理所有日誌資料
|
||||
joblog_clean_type_unvalid=清理類型參数異常
|
||||
joblog_handleCode_200=成功
|
||||
joblog_handleCode_500=失敗
|
||||
joblog_handleCode_502=失敗(超時)
|
||||
joblog_kill_log=终止任務
|
||||
joblog_kill_log_limit=調度失敗,無法终止日誌
|
||||
joblog_kill_log_byman=人為操作,主動終止
|
||||
joblog_lost_fail=任務結果丟失,標記失敗
|
||||
joblog_rolling_log=執行日誌
|
||||
joblog_rolling_log_refresh=更新
|
||||
joblog_rolling_log_triggerfail=任務發起調度失敗,無法查看執行日誌
|
||||
joblog_rolling_log_failoften=終止請求Rolling日誌,請求失敗次數超上限,可刷新頁面重新加載日誌
|
||||
joblog_logid_unvalid=日誌ID非法
|
||||
|
||||
## job group
|
||||
jobgroup_name=執行器管理
|
||||
jobgroup_list=執行器列表
|
||||
jobgroup_add=新增執行器
|
||||
jobgroup_edit=編輯執行器
|
||||
jobgroup_del=刪除執行器
|
||||
jobgroup_field_title=名稱
|
||||
jobgroup_field_addressType=注冊方式
|
||||
jobgroup_field_addressType_0=自動注冊
|
||||
jobgroup_field_addressType_1=手動登錄
|
||||
jobgroup_field_addressType_limit=手動登錄注冊方式,機器地址不可為空
|
||||
jobgroup_field_registryList=機器地址
|
||||
jobgroup_field_registryList_unvalid=機器地址格式非法
|
||||
jobgroup_field_registryList_placeholder=請輸入執行器地址列表,多個地址請以逗號分隔
|
||||
jobgroup_field_appname_limit=限制以小寫字母開頭,由小寫字母、數字和中划線組成
|
||||
jobgroup_field_appname_length=AppName長度限制為4~64
|
||||
jobgroup_field_title_length=名稱長度限制為4~12
|
||||
jobgroup_field_order_digits=請輸入整數
|
||||
jobgroup_field_orderrange=取值範圍為1~1000
|
||||
jobgroup_del_limit_0=拒絕刪除,該執行器使用中
|
||||
jobgroup_del_limit_1=拒絕删除,系统至少保留一個執行器
|
||||
jobgroup_empty=不存在有效執行器,請聯絡系統管理員
|
||||
|
||||
## job conf
|
||||
jobconf_block_SERIAL_EXECUTION=單機串行
|
||||
jobconf_block_DISCARD_LATER=丢棄后續調度
|
||||
jobconf_block_COVER_EARLY=覆蓋之前調度
|
||||
jobconf_route_first=第一個
|
||||
jobconf_route_last=最後一個
|
||||
jobconf_route_round=輪詢
|
||||
jobconf_route_random=隨機
|
||||
jobconf_route_consistenthash=一致性HASH
|
||||
jobconf_route_lfu=最不經常使用
|
||||
jobconf_route_lru=最近最久未使用
|
||||
jobconf_route_failover=故障轉移
|
||||
jobconf_route_busyover=忙碌轉移
|
||||
jobconf_route_shard=分片廣播
|
||||
jobconf_idleBeat=空閒檢測
|
||||
jobconf_beat=心跳檢測
|
||||
jobconf_monitor=任務調度中心監控告警
|
||||
jobconf_monitor_detail=監控告警明细
|
||||
jobconf_monitor_alarm_title=告警類型
|
||||
jobconf_monitor_alarm_type=調度失敗
|
||||
jobconf_monitor_alarm_content=告警内容
|
||||
jobconf_trigger_admin_adress=調度機器
|
||||
jobconf_trigger_exe_regtype=執行器-注冊方式
|
||||
jobconf_trigger_exe_regaddress=執行器-地址列表
|
||||
jobconf_trigger_address_empty=調度失敗:執行器地址為空
|
||||
jobconf_trigger_run=觸發調度
|
||||
jobconf_trigger_child_run=觸發子任務
|
||||
jobconf_callback_child_msg1={0}/{1} [任務ID={2}], 觸發{3}, 觸發備註: {4} <br>
|
||||
jobconf_callback_child_msg2={0}/{1} [任務ID={2}], 觸發失败, 觸發備註: 任務ID格式錯誤 <br>
|
||||
jobconf_trigger_type=任務觸發類型
|
||||
jobconf_trigger_type_cron=Cron觸發
|
||||
jobconf_trigger_type_manual=手動觸發
|
||||
jobconf_trigger_type_parent=父任務觸發
|
||||
jobconf_trigger_type_api=API觸發
|
||||
jobconf_trigger_type_retry=失敗重試觸發
|
||||
|
||||
## user
|
||||
user_manage=用户管理
|
||||
user_username=帳號
|
||||
user_password=密碼
|
||||
user_role=角色
|
||||
user_role_admin=管理員
|
||||
user_role_normal=普通用戶
|
||||
user_permission=權限
|
||||
user_add=新增用戶
|
||||
user_update=更新用戶
|
||||
user_username_repeat=帳號重複
|
||||
user_username_valid=限制以小寫字母開頭,由小寫字母、數字組成
|
||||
user_password_update_placeholder=請輸入新密碼,為空則不更新密碼
|
||||
user_update_loginuser_limit=禁止操作當前登入帳號
|
||||
|
||||
## help
|
||||
job_help=使用教程
|
||||
job_help_document=官方文件
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration debug="false" scan="true" scanPeriod="1 seconds">
|
||||
|
||||
<contextName>logback</contextName>
|
||||
<property name="log.path" value="/data/applogs/xxl-job/xxl-job-admin.log"/>
|
||||
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console"/>
|
||||
<appender-ref ref="file"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xxl.job.admin.dao.XxlJobGroupDao">
|
||||
|
||||
<resultMap id="XxlJobGroup" type="com.xxl.job.admin.core.model.XxlJobGroup" >
|
||||
<result column="id" property="id" />
|
||||
<result column="app_name" property="appname" />
|
||||
<result column="title" property="title" />
|
||||
<result column="address_type" property="addressType" />
|
||||
<result column="address_list" property="addressList" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
t.id,
|
||||
t.app_name,
|
||||
t.title,
|
||||
t.address_type,
|
||||
t.address_list
|
||||
</sql>
|
||||
|
||||
<select id="findAll" resultMap="XxlJobGroup">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_group AS t
|
||||
ORDER BY t.app_name, t.title, t.id ASC
|
||||
</select>
|
||||
|
||||
<select id="findByAddressType" parameterType="java.lang.Integer" resultMap="XxlJobGroup">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_group AS t
|
||||
WHERE t.address_type = #{addressType}
|
||||
ORDER BY t.app_name, t.title, t.id ASC
|
||||
</select>
|
||||
|
||||
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobGroup" useGeneratedKeys="true" keyProperty="id" >
|
||||
INSERT INTO xxl_job_group ( `app_name`, `title`, `address_type`, `address_list`)
|
||||
values ( #{appname}, #{title}, #{addressType}, #{addressList});
|
||||
</insert>
|
||||
|
||||
<update id="update" parameterType="com.xxl.job.admin.core.model.XxlJobGroup" >
|
||||
UPDATE xxl_job_group
|
||||
SET `app_name` = #{appname},
|
||||
`title` = #{title},
|
||||
`address_type` = #{addressType},
|
||||
`address_list` = #{addressList}
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="remove" parameterType="java.lang.Integer" >
|
||||
DELETE FROM xxl_job_group
|
||||
WHERE id = #{id}
|
||||
</delete>
|
||||
|
||||
<select id="load" parameterType="java.lang.Integer" resultMap="XxlJobGroup">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_group AS t
|
||||
WHERE t.id = #{id}
|
||||
</select>
|
||||
|
||||
<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobGroup">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_group AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="appname != null and appname != ''">
|
||||
AND t.app_name like CONCAT(CONCAT('%', #{appname}), '%')
|
||||
</if>
|
||||
<if test="title != null and title != ''">
|
||||
AND t.title like CONCAT(CONCAT('%', #{title}), '%')
|
||||
</if>
|
||||
</trim>
|
||||
ORDER BY t.app_name, t.title, t.id ASC
|
||||
LIMIT #{offset}, #{pagesize}
|
||||
</select>
|
||||
|
||||
<select id="pageListCount" parameterType="java.util.HashMap" resultType="int">
|
||||
SELECT count(1)
|
||||
FROM xxl_job_group AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="appname != null and appname != ''">
|
||||
AND t.app_name like CONCAT(CONCAT('%', #{appname}), '%')
|
||||
</if>
|
||||
<if test="title != null and title != ''">
|
||||
AND t.title like CONCAT(CONCAT('%', #{title}), '%')
|
||||
</if>
|
||||
</trim>
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,229 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xxl.job.admin.dao.XxlJobInfoDao">
|
||||
|
||||
<resultMap id="XxlJobInfo" type="com.xxl.job.admin.core.model.XxlJobInfo" >
|
||||
<result column="id" property="id" />
|
||||
|
||||
<result column="job_group" property="jobGroup" />
|
||||
<result column="job_cron" property="jobCron" />
|
||||
<result column="job_desc" property="jobDesc" />
|
||||
|
||||
<result column="add_time" property="addTime" />
|
||||
<result column="update_time" property="updateTime" />
|
||||
|
||||
<result column="author" property="author" />
|
||||
<result column="alarm_email" property="alarmEmail" />
|
||||
|
||||
<result column="executor_route_strategy" property="executorRouteStrategy" />
|
||||
<result column="executor_handler" property="executorHandler" />
|
||||
<result column="executor_param" property="executorParam" />
|
||||
<result column="executor_block_strategy" property="executorBlockStrategy" />
|
||||
<result column="executor_timeout" property="executorTimeout" />
|
||||
<result column="executor_fail_retry_count" property="executorFailRetryCount" />
|
||||
|
||||
<result column="glue_type" property="glueType" />
|
||||
<result column="glue_source" property="glueSource" />
|
||||
<result column="glue_remark" property="glueRemark" />
|
||||
<result column="glue_updatetime" property="glueUpdatetime" />
|
||||
|
||||
<result column="child_jobid" property="childJobId" />
|
||||
|
||||
<result column="trigger_status" property="triggerStatus" />
|
||||
<result column="trigger_last_time" property="triggerLastTime" />
|
||||
<result column="trigger_next_time" property="triggerNextTime" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
t.id,
|
||||
t.job_group,
|
||||
t.job_cron,
|
||||
t.job_desc,
|
||||
t.add_time,
|
||||
t.update_time,
|
||||
t.author,
|
||||
t.alarm_email,
|
||||
t.executor_route_strategy,
|
||||
t.executor_handler,
|
||||
t.executor_param,
|
||||
t.executor_block_strategy,
|
||||
t.executor_timeout,
|
||||
t.executor_fail_retry_count,
|
||||
t.glue_type,
|
||||
t.glue_source,
|
||||
t.glue_remark,
|
||||
t.glue_updatetime,
|
||||
t.child_jobid,
|
||||
t.trigger_status,
|
||||
t.trigger_last_time,
|
||||
t.trigger_next_time
|
||||
</sql>
|
||||
|
||||
<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_info AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="jobGroup gt 0">
|
||||
AND t.job_group = #{jobGroup}
|
||||
</if>
|
||||
<if test="triggerStatus gte 0">
|
||||
AND t.trigger_status = #{triggerStatus}
|
||||
</if>
|
||||
<if test="jobDesc != null and jobDesc != ''">
|
||||
AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
|
||||
</if>
|
||||
<if test="executorHandler != null and executorHandler != ''">
|
||||
AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
|
||||
</if>
|
||||
<if test="author != null and author != ''">
|
||||
AND t.author like CONCAT(CONCAT('%', #{author}), '%')
|
||||
</if>
|
||||
</trim>
|
||||
ORDER BY id DESC
|
||||
LIMIT #{offset}, #{pagesize}
|
||||
</select>
|
||||
|
||||
<select id="pageListCount" parameterType="java.util.HashMap" resultType="int">
|
||||
SELECT count(1)
|
||||
FROM xxl_job_info AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="jobGroup gt 0">
|
||||
AND t.job_group = #{jobGroup}
|
||||
</if>
|
||||
<if test="triggerStatus gte 0">
|
||||
AND t.trigger_status = #{triggerStatus}
|
||||
</if>
|
||||
<if test="jobDesc != null and jobDesc != ''">
|
||||
AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
|
||||
</if>
|
||||
<if test="executorHandler != null and executorHandler != ''">
|
||||
AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
|
||||
</if>
|
||||
<if test="author != null and author != ''">
|
||||
AND t.author like CONCAT(CONCAT('%', #{author}), '%')
|
||||
</if>
|
||||
</trim>
|
||||
</select>
|
||||
|
||||
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobInfo" useGeneratedKeys="true" keyProperty="id" >
|
||||
INSERT INTO xxl_job_info (
|
||||
job_group,
|
||||
job_cron,
|
||||
job_desc,
|
||||
add_time,
|
||||
update_time,
|
||||
author,
|
||||
alarm_email,
|
||||
executor_route_strategy,
|
||||
executor_handler,
|
||||
executor_param,
|
||||
executor_block_strategy,
|
||||
executor_timeout,
|
||||
executor_fail_retry_count,
|
||||
glue_type,
|
||||
glue_source,
|
||||
glue_remark,
|
||||
glue_updatetime,
|
||||
child_jobid,
|
||||
trigger_status,
|
||||
trigger_last_time,
|
||||
trigger_next_time
|
||||
) VALUES (
|
||||
#{jobGroup},
|
||||
#{jobCron},
|
||||
#{jobDesc},
|
||||
#{addTime},
|
||||
#{updateTime},
|
||||
#{author},
|
||||
#{alarmEmail},
|
||||
#{executorRouteStrategy},
|
||||
#{executorHandler},
|
||||
#{executorParam},
|
||||
#{executorBlockStrategy},
|
||||
#{executorTimeout},
|
||||
#{executorFailRetryCount},
|
||||
#{glueType},
|
||||
#{glueSource},
|
||||
#{glueRemark},
|
||||
#{glueUpdatetime},
|
||||
#{childJobId},
|
||||
#{triggerStatus},
|
||||
#{triggerLastTime},
|
||||
#{triggerNextTime}
|
||||
);
|
||||
<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
|
||||
SELECT LAST_INSERT_ID()
|
||||
/*SELECT @@IDENTITY AS id*/
|
||||
</selectKey>-->
|
||||
</insert>
|
||||
|
||||
<select id="loadById" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_info AS t
|
||||
WHERE t.id = #{id}
|
||||
</select>
|
||||
|
||||
<update id="update" parameterType="com.xxl.job.admin.core.model.XxlJobInfo" >
|
||||
UPDATE xxl_job_info
|
||||
SET
|
||||
job_group = #{jobGroup},
|
||||
job_cron = #{jobCron},
|
||||
job_desc = #{jobDesc},
|
||||
update_time = #{updateTime},
|
||||
author = #{author},
|
||||
alarm_email = #{alarmEmail},
|
||||
executor_route_strategy = #{executorRouteStrategy},
|
||||
executor_handler = #{executorHandler},
|
||||
executor_param = #{executorParam},
|
||||
executor_block_strategy = #{executorBlockStrategy},
|
||||
executor_timeout = ${executorTimeout},
|
||||
executor_fail_retry_count = ${executorFailRetryCount},
|
||||
glue_type = #{glueType},
|
||||
glue_source = #{glueSource},
|
||||
glue_remark = #{glueRemark},
|
||||
glue_updatetime = #{glueUpdatetime},
|
||||
child_jobid = #{childJobId},
|
||||
trigger_status = #{triggerStatus},
|
||||
trigger_last_time = #{triggerLastTime},
|
||||
trigger_next_time = #{triggerNextTime}
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="delete" parameterType="java.util.HashMap">
|
||||
DELETE
|
||||
FROM xxl_job_info
|
||||
WHERE id = #{id}
|
||||
</delete>
|
||||
|
||||
<select id="getJobsByGroup" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_info AS t
|
||||
WHERE t.job_group = #{jobGroup}
|
||||
</select>
|
||||
|
||||
<select id="findAllCount" resultType="int">
|
||||
SELECT count(1)
|
||||
FROM xxl_job_info
|
||||
</select>
|
||||
|
||||
|
||||
<select id="scheduleJobQuery" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_info AS t
|
||||
WHERE t.trigger_status = 1
|
||||
and t.trigger_next_time <![CDATA[ <= ]]> #{maxNextTime}
|
||||
ORDER BY id ASC
|
||||
LIMIT #{pagesize}
|
||||
</select>
|
||||
|
||||
<update id="scheduleUpdate" parameterType="com.xxl.job.admin.core.model.XxlJobInfo" >
|
||||
UPDATE xxl_job_info
|
||||
SET
|
||||
trigger_last_time = #{triggerLastTime},
|
||||
trigger_next_time = #{triggerNextTime},
|
||||
trigger_status = #{triggerStatus}
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xxl.job.admin.dao.XxlJobLogGlueDao">
|
||||
|
||||
<resultMap id="XxlJobLogGlue" type="com.xxl.job.admin.core.model.XxlJobLogGlue" >
|
||||
<result column="id" property="id" />
|
||||
<result column="job_id" property="jobId" />
|
||||
<result column="glue_type" property="glueType" />
|
||||
<result column="glue_source" property="glueSource" />
|
||||
<result column="glue_remark" property="glueRemark" />
|
||||
<result column="add_time" property="addTime" />
|
||||
<result column="update_time" property="updateTime" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
t.id,
|
||||
t.job_id,
|
||||
t.glue_type,
|
||||
t.glue_source,
|
||||
t.glue_remark,
|
||||
t.add_time,
|
||||
t.update_time
|
||||
</sql>
|
||||
|
||||
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobLogGlue" useGeneratedKeys="true" keyProperty="id" >
|
||||
INSERT INTO xxl_job_logglue (
|
||||
`job_id`,
|
||||
`glue_type`,
|
||||
`glue_source`,
|
||||
`glue_remark`,
|
||||
`add_time`,
|
||||
`update_time`
|
||||
) VALUES (
|
||||
#{jobId},
|
||||
#{glueType},
|
||||
#{glueSource},
|
||||
#{glueRemark},
|
||||
#{addTime},
|
||||
#{updateTime}
|
||||
);
|
||||
<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
|
||||
SELECT LAST_INSERT_ID()
|
||||
</selectKey>-->
|
||||
</insert>
|
||||
|
||||
<select id="findByJobId" parameterType="java.lang.Integer" resultMap="XxlJobLogGlue">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_logglue AS t
|
||||
WHERE t.job_id = #{jobId}
|
||||
ORDER BY id DESC
|
||||
</select>
|
||||
|
||||
<delete id="removeOld" >
|
||||
DELETE FROM xxl_job_logglue
|
||||
WHERE id NOT in(
|
||||
SELECT id FROM(
|
||||
SELECT id FROM xxl_job_logglue
|
||||
WHERE `job_id` = #{jobId}
|
||||
ORDER BY update_time desc
|
||||
LIMIT 0, #{limit}
|
||||
) t1
|
||||
) AND `job_id` = #{jobId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByJobId" parameterType="java.lang.Integer" >
|
||||
DELETE FROM xxl_job_logglue
|
||||
WHERE `job_id` = #{jobId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,261 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xxl.job.admin.dao.XxlJobLogDao">
|
||||
|
||||
<resultMap id="XxlJobLog" type="com.xxl.job.admin.core.model.XxlJobLog" >
|
||||
<result column="id" property="id" />
|
||||
|
||||
<result column="job_group" property="jobGroup" />
|
||||
<result column="job_id" property="jobId" />
|
||||
|
||||
<result column="executor_address" property="executorAddress" />
|
||||
<result column="executor_handler" property="executorHandler" />
|
||||
<result column="executor_param" property="executorParam" />
|
||||
<result column="executor_sharding_param" property="executorShardingParam" />
|
||||
<result column="executor_fail_retry_count" property="executorFailRetryCount" />
|
||||
|
||||
<result column="trigger_time" property="triggerTime" />
|
||||
<result column="trigger_code" property="triggerCode" />
|
||||
<result column="trigger_msg" property="triggerMsg" />
|
||||
|
||||
<result column="handle_time" property="handleTime" />
|
||||
<result column="handle_code" property="handleCode" />
|
||||
<result column="handle_msg" property="handleMsg" />
|
||||
|
||||
<result column="alarm_status" property="alarmStatus" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
t.id,
|
||||
t.job_group,
|
||||
t.job_id,
|
||||
t.executor_address,
|
||||
t.executor_handler,
|
||||
t.executor_param,
|
||||
t.executor_sharding_param,
|
||||
t.executor_fail_retry_count,
|
||||
t.trigger_time,
|
||||
t.trigger_code,
|
||||
t.trigger_msg,
|
||||
t.handle_time,
|
||||
t.handle_code,
|
||||
t.handle_msg,
|
||||
t.alarm_status
|
||||
</sql>
|
||||
|
||||
<select id="pageList" resultMap="XxlJobLog">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_log AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="jobId==0 and jobGroup gt 0">
|
||||
AND t.job_group = #{jobGroup}
|
||||
</if>
|
||||
<if test="jobId gt 0">
|
||||
AND t.job_id = #{jobId}
|
||||
</if>
|
||||
<if test="triggerTimeStart != null">
|
||||
AND t.trigger_time <![CDATA[ >= ]]> #{triggerTimeStart}
|
||||
</if>
|
||||
<if test="triggerTimeEnd != null">
|
||||
AND t.trigger_time <![CDATA[ <= ]]> #{triggerTimeEnd}
|
||||
</if>
|
||||
<if test="logStatus == 1" >
|
||||
AND t.handle_code = 200
|
||||
</if>
|
||||
<if test="logStatus == 2" >
|
||||
AND (
|
||||
t.trigger_code NOT IN (0, 200) OR
|
||||
t.handle_code NOT IN (0, 200)
|
||||
)
|
||||
</if>
|
||||
<if test="logStatus == 3" >
|
||||
AND t.trigger_code = 200
|
||||
AND t.handle_code = 0
|
||||
</if>
|
||||
</trim>
|
||||
ORDER BY t.trigger_time DESC
|
||||
LIMIT #{offset}, #{pagesize}
|
||||
</select>
|
||||
|
||||
<select id="pageListCount" resultType="int">
|
||||
SELECT count(1)
|
||||
FROM xxl_job_log AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="jobId==0 and jobGroup gt 0">
|
||||
AND t.job_group = #{jobGroup}
|
||||
</if>
|
||||
<if test="jobId gt 0">
|
||||
AND t.job_id = #{jobId}
|
||||
</if>
|
||||
<if test="triggerTimeStart != null">
|
||||
AND t.trigger_time <![CDATA[ >= ]]> #{triggerTimeStart}
|
||||
</if>
|
||||
<if test="triggerTimeEnd != null">
|
||||
AND t.trigger_time <![CDATA[ <= ]]> #{triggerTimeEnd}
|
||||
</if>
|
||||
<if test="logStatus == 1" >
|
||||
AND t.handle_code = 200
|
||||
</if>
|
||||
<if test="logStatus == 2" >
|
||||
AND (
|
||||
t.trigger_code NOT IN (0, 200) OR
|
||||
t.handle_code NOT IN (0, 200)
|
||||
)
|
||||
</if>
|
||||
<if test="logStatus == 3" >
|
||||
AND t.trigger_code = 200
|
||||
AND t.handle_code = 0
|
||||
</if>
|
||||
</trim>
|
||||
</select>
|
||||
|
||||
<select id="load" parameterType="java.lang.Long" resultMap="XxlJobLog">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_log AS t
|
||||
WHERE t.id = #{id}
|
||||
</select>
|
||||
|
||||
|
||||
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobLog" useGeneratedKeys="true" keyProperty="id" >
|
||||
INSERT INTO xxl_job_log (
|
||||
`job_group`,
|
||||
`job_id`,
|
||||
`trigger_time`,
|
||||
`trigger_code`,
|
||||
`handle_code`
|
||||
) VALUES (
|
||||
#{jobGroup},
|
||||
#{jobId},
|
||||
#{triggerTime},
|
||||
#{triggerCode},
|
||||
#{handleCode}
|
||||
);
|
||||
<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
|
||||
SELECT LAST_INSERT_ID()
|
||||
</selectKey>-->
|
||||
</insert>
|
||||
|
||||
<update id="updateTriggerInfo" >
|
||||
UPDATE xxl_job_log
|
||||
SET
|
||||
`trigger_time`= #{triggerTime},
|
||||
`trigger_code`= #{triggerCode},
|
||||
`trigger_msg`= #{triggerMsg},
|
||||
`executor_address`= #{executorAddress},
|
||||
`executor_handler`=#{executorHandler},
|
||||
`executor_param`= #{executorParam},
|
||||
`executor_sharding_param`= #{executorShardingParam},
|
||||
`executor_fail_retry_count`= #{executorFailRetryCount}
|
||||
WHERE `id`= #{id}
|
||||
</update>
|
||||
|
||||
<update id="updateHandleInfo">
|
||||
UPDATE xxl_job_log
|
||||
SET
|
||||
`handle_time`= #{handleTime},
|
||||
`handle_code`= #{handleCode},
|
||||
`handle_msg`= #{handleMsg}
|
||||
WHERE `id`= #{id}
|
||||
</update>
|
||||
|
||||
<delete id="delete" >
|
||||
delete from xxl_job_log
|
||||
WHERE job_id = #{jobId}
|
||||
</delete>
|
||||
|
||||
<!--<select id="triggerCountByDay" resultType="java.util.Map" >
|
||||
SELECT
|
||||
DATE_FORMAT(trigger_time,'%Y-%m-%d') triggerDay,
|
||||
COUNT(handle_code) triggerDayCount,
|
||||
SUM(CASE WHEN (trigger_code in (0, 200) and handle_code = 0) then 1 else 0 end) as triggerDayCountRunning,
|
||||
SUM(CASE WHEN handle_code = 200 then 1 else 0 end) as triggerDayCountSuc
|
||||
FROM xxl_job_log
|
||||
WHERE trigger_time BETWEEN #{from} and #{to}
|
||||
GROUP BY triggerDay
|
||||
ORDER BY triggerDay
|
||||
</select>-->
|
||||
|
||||
<select id="findLogReport" resultType="java.util.Map" >
|
||||
SELECT
|
||||
COUNT(handle_code) triggerDayCount,
|
||||
SUM(CASE WHEN (trigger_code in (0, 200) and handle_code = 0) then 1 else 0 end) as triggerDayCountRunning,
|
||||
SUM(CASE WHEN handle_code = 200 then 1 else 0 end) as triggerDayCountSuc
|
||||
FROM xxl_job_log
|
||||
WHERE trigger_time BETWEEN #{from} and #{to}
|
||||
</select>
|
||||
|
||||
<select id="findClearLogIds" resultType="long" >
|
||||
SELECT id FROM xxl_job_log
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="jobGroup gt 0">
|
||||
AND job_group = #{jobGroup}
|
||||
</if>
|
||||
<if test="jobId gt 0">
|
||||
AND job_id = #{jobId}
|
||||
</if>
|
||||
<if test="clearBeforeTime != null">
|
||||
AND trigger_time <![CDATA[ <= ]]> #{clearBeforeTime}
|
||||
</if>
|
||||
<if test="clearBeforeNum gt 0">
|
||||
AND id NOT in(
|
||||
SELECT id FROM(
|
||||
SELECT id FROM xxl_job_log AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="jobGroup gt 0">
|
||||
AND t.job_group = #{jobGroup}
|
||||
</if>
|
||||
<if test="jobId gt 0">
|
||||
AND t.job_id = #{jobId}
|
||||
</if>
|
||||
</trim>
|
||||
ORDER BY t.trigger_time desc
|
||||
LIMIT 0, #{clearBeforeNum}
|
||||
) t1
|
||||
)
|
||||
</if>
|
||||
</trim>
|
||||
order by id asc
|
||||
LIMIT #{pagesize}
|
||||
</select>
|
||||
|
||||
<delete id="clearLog" >
|
||||
delete from xxl_job_log
|
||||
WHERE id in
|
||||
<foreach collection="logIds" item="item" open="(" close=")" separator="," >
|
||||
#{item}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<select id="findFailJobLogIds" resultType="long" >
|
||||
SELECT id FROM `xxl_job_log`
|
||||
WHERE !(
|
||||
(trigger_code in (0, 200) and handle_code = 0)
|
||||
OR
|
||||
(handle_code = 200)
|
||||
)
|
||||
AND `alarm_status` = 0
|
||||
ORDER BY id ASC
|
||||
LIMIT #{pagesize}
|
||||
</select>
|
||||
|
||||
<update id="updateAlarmStatus" >
|
||||
UPDATE xxl_job_log
|
||||
SET
|
||||
`alarm_status` = #{newAlarmStatus}
|
||||
WHERE `id`= #{logId} AND `alarm_status` = #{oldAlarmStatus}
|
||||
</update>
|
||||
|
||||
<select id="findLostJobIds" resultType="long" >
|
||||
SELECT t.id
|
||||
FROM xxl_job_log AS t
|
||||
WHERE t.trigger_code = 200
|
||||
and t.handle_code = 0
|
||||
and t.trigger_time <![CDATA[ <= ]]> #{losedTime}
|
||||
and t.executor_address not in (
|
||||
SELECT t2.registry_value
|
||||
FROM xxl_job_registry AS t2
|
||||
)
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xxl.job.admin.dao.XxlJobLogReportDao">
|
||||
|
||||
<resultMap id="XxlJobLogReport" type="com.xxl.job.admin.core.model.XxlJobLogReport" >
|
||||
<result column="id" property="id" />
|
||||
<result column="trigger_day" property="triggerDay" />
|
||||
<result column="running_count" property="runningCount" />
|
||||
<result column="suc_count" property="sucCount" />
|
||||
<result column="fail_count" property="failCount" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
t.id,
|
||||
t.trigger_day,
|
||||
t.running_count,
|
||||
t.suc_count,
|
||||
t.fail_count
|
||||
</sql>
|
||||
|
||||
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobLogReport" useGeneratedKeys="true" keyProperty="id" >
|
||||
INSERT INTO xxl_job_log_report (
|
||||
`trigger_day`,
|
||||
`running_count`,
|
||||
`suc_count`,
|
||||
`fail_count`
|
||||
) VALUES (
|
||||
#{triggerDay},
|
||||
#{runningCount},
|
||||
#{sucCount},
|
||||
#{failCount}
|
||||
);
|
||||
<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
|
||||
SELECT LAST_INSERT_ID()
|
||||
</selectKey>-->
|
||||
</insert>
|
||||
|
||||
<update id="update" >
|
||||
UPDATE xxl_job_log_report
|
||||
SET `running_count` = #{runningCount},
|
||||
`suc_count` = #{sucCount},
|
||||
`fail_count` = #{failCount}
|
||||
WHERE `trigger_day` = #{triggerDay}
|
||||
</update>
|
||||
|
||||
<select id="queryLogReport" resultMap="XxlJobLogReport">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_log_report AS t
|
||||
WHERE t.trigger_day between #{triggerDayFrom} and #{triggerDayTo}
|
||||
ORDER BY t.trigger_day ASC
|
||||
</select>
|
||||
|
||||
<select id="queryLogReportTotal" resultMap="XxlJobLogReport">
|
||||
SELECT
|
||||
SUM(running_count) running_count,
|
||||
SUM(suc_count) suc_count,
|
||||
SUM(fail_count) fail_count
|
||||
FROM xxl_job_log_report AS t
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xxl.job.admin.dao.XxlJobRegistryDao">
|
||||
|
||||
<resultMap id="XxlJobRegistry" type="com.xxl.job.admin.core.model.XxlJobRegistry" >
|
||||
<result column="id" property="id" />
|
||||
<result column="registry_group" property="registryGroup" />
|
||||
<result column="registry_key" property="registryKey" />
|
||||
<result column="registry_value" property="registryValue" />
|
||||
<result column="update_time" property="updateTime" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
t.id,
|
||||
t.registry_group,
|
||||
t.registry_key,
|
||||
t.registry_value,
|
||||
t.update_time
|
||||
</sql>
|
||||
|
||||
<select id="findDead" parameterType="java.util.HashMap" resultType="java.lang.Integer" >
|
||||
SELECT t.id
|
||||
FROM xxl_job_registry AS t
|
||||
WHERE t.update_time <![CDATA[ < ]]> DATE_ADD(#{nowTime},INTERVAL -#{timeout} SECOND)
|
||||
</select>
|
||||
|
||||
<delete id="removeDead" parameterType="java.lang.Integer" >
|
||||
DELETE FROM xxl_job_registry
|
||||
WHERE id in
|
||||
<foreach collection="ids" item="item" open="(" close=")" separator="," >
|
||||
#{item}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<select id="findAll" parameterType="java.util.HashMap" resultMap="XxlJobRegistry">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_registry AS t
|
||||
WHERE t.update_time <![CDATA[ > ]]> DATE_ADD(#{nowTime},INTERVAL -#{timeout} SECOND)
|
||||
</select>
|
||||
|
||||
<update id="registryUpdate" >
|
||||
UPDATE xxl_job_registry
|
||||
SET `update_time` = #{updateTime}
|
||||
WHERE `registry_group` = #{registryGroup}
|
||||
AND `registry_key` = #{registryKey}
|
||||
AND `registry_value` = #{registryValue}
|
||||
</update>
|
||||
|
||||
<insert id="registrySave" >
|
||||
INSERT INTO xxl_job_registry( `registry_group` , `registry_key` , `registry_value`, `update_time`)
|
||||
VALUES( #{registryGroup} , #{registryKey} , #{registryValue}, #{updateTime})
|
||||
</insert>
|
||||
|
||||
<delete id="registryDelete" >
|
||||
DELETE FROM xxl_job_registry
|
||||
WHERE registry_group = #{registryGroup}
|
||||
AND registry_key = #{registryKey}
|
||||
AND registry_value = #{registryValue}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xxl.job.admin.dao.XxlJobUserDao">
|
||||
|
||||
<resultMap id="XxlJobUser" type="com.xxl.job.admin.core.model.XxlJobUser" >
|
||||
<result column="id" property="id" />
|
||||
<result column="username" property="username" />
|
||||
<result column="password" property="password" />
|
||||
<result column="role" property="role" />
|
||||
<result column="permission" property="permission" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
t.id,
|
||||
t.username,
|
||||
t.password,
|
||||
t.role,
|
||||
t.permission
|
||||
</sql>
|
||||
|
||||
<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobUser">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_user AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="username != null and username != ''">
|
||||
AND t.username like CONCAT(CONCAT('%', #{username}), '%')
|
||||
</if>
|
||||
<if test="role gt -1">
|
||||
AND t.role = #{role}
|
||||
</if>
|
||||
</trim>
|
||||
ORDER BY username ASC
|
||||
LIMIT #{offset}, #{pagesize}
|
||||
</select>
|
||||
|
||||
<select id="pageListCount" parameterType="java.util.HashMap" resultType="int">
|
||||
SELECT count(1)
|
||||
FROM xxl_job_user AS t
|
||||
<trim prefix="WHERE" prefixOverrides="AND | OR" >
|
||||
<if test="username != null and username != ''">
|
||||
AND t.username like CONCAT(CONCAT('%', #{username}), '%')
|
||||
</if>
|
||||
<if test="role gt -1">
|
||||
AND t.role = #{role}
|
||||
</if>
|
||||
</trim>
|
||||
</select>
|
||||
|
||||
<select id="loadByUserName" parameterType="java.util.HashMap" resultMap="XxlJobUser">
|
||||
SELECT <include refid="Base_Column_List" />
|
||||
FROM xxl_job_user AS t
|
||||
WHERE t.username = #{username}
|
||||
</select>
|
||||
|
||||
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobUser" useGeneratedKeys="true" keyProperty="id" >
|
||||
INSERT INTO xxl_job_user (
|
||||
username,
|
||||
password,
|
||||
role,
|
||||
permission
|
||||
) VALUES (
|
||||
#{username},
|
||||
#{password},
|
||||
#{role},
|
||||
#{permission}
|
||||
);
|
||||
</insert>
|
||||
|
||||
<update id="update" parameterType="com.xxl.job.admin.core.model.XxlJobUser" >
|
||||
UPDATE xxl_job_user
|
||||
SET
|
||||
<if test="password != null and password != ''">
|
||||
password = #{password},
|
||||
</if>
|
||||
role = #{role},
|
||||
permission = #{permission}
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="delete" parameterType="java.util.HashMap">
|
||||
DELETE
|
||||
FROM xxl_job_user
|
||||
WHERE id = #{id}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
File diff suppressed because one or more lines are too long
BIN
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.eot
vendored
Normal file
BIN
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.eot
vendored
Normal file
Binary file not shown.
2230
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.svg
vendored
Normal file
2230
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.svg
vendored
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 326 KiB |
BIN
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.ttf
vendored
Normal file
BIN
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.ttf
vendored
Normal file
Binary file not shown.
BIN
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.woff
vendored
Normal file
BIN
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.woff
vendored
Normal file
Binary file not shown.
2
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/PACE/pace.min.js
vendored
Normal file
2
TrustieJobAdmin/src/main/resources/static/adminlte/bower_components/PACE/pace.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,77 @@
|
|||
/* This is a compiled file, you should be editing the file in the templates directory */
|
||||
.pace {
|
||||
-webkit-pointer-events: none;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pace-inactive {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pace .pace-progress {
|
||||
background: #2299dd;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
top: 0;
|
||||
right: 100%;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.pace .pace-progress-inner {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 10px #2299dd, 0 0 5px #2299dd;
|
||||
opacity: 1.0;
|
||||
-webkit-transform: rotate(3deg) translate(0px, -4px);
|
||||
-moz-transform: rotate(3deg) translate(0px, -4px);
|
||||
-ms-transform: rotate(3deg) translate(0px, -4px);
|
||||
-o-transform: rotate(3deg) translate(0px, -4px);
|
||||
transform: rotate(3deg) translate(0px, -4px);
|
||||
}
|
||||
|
||||
.pace .pace-activity {
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: solid 2px transparent;
|
||||
border-top-color: #2299dd;
|
||||
border-left-color: #2299dd;
|
||||
border-radius: 10px;
|
||||
-webkit-animation: pace-spinner 400ms linear infinite;
|
||||
-moz-animation: pace-spinner 400ms linear infinite;
|
||||
-ms-animation: pace-spinner 400ms linear infinite;
|
||||
-o-animation: pace-spinner 400ms linear infinite;
|
||||
animation: pace-spinner 400ms linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes pace-spinner {
|
||||
0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }
|
||||
}
|
||||
@-moz-keyframes pace-spinner {
|
||||
0% { -moz-transform: rotate(0deg); transform: rotate(0deg); }
|
||||
100% { -moz-transform: rotate(360deg); transform: rotate(360deg); }
|
||||
}
|
||||
@-o-keyframes pace-spinner {
|
||||
0% { -o-transform: rotate(0deg); transform: rotate(0deg); }
|
||||
100% { -o-transform: rotate(360deg); transform: rotate(360deg); }
|
||||
}
|
||||
@-ms-keyframes pace-spinner {
|
||||
0% { -ms-transform: rotate(0deg); transform: rotate(0deg); }
|
||||
100% { -ms-transform: rotate(360deg); transform: rotate(360deg); }
|
||||
}
|
||||
@keyframes pace-spinner {
|
||||
0% { transform: rotate(0deg); transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); transform: rotate(360deg); }
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
.daterangepicker {
|
||||
position: absolute;
|
||||
color: inherit;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
width: 278px;
|
||||
padding: 4px;
|
||||
margin-top: 1px;
|
||||
top: 100px;
|
||||
left: 20px;
|
||||
/* Calendars */ }
|
||||
.daterangepicker:before, .daterangepicker:after {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
content: ''; }
|
||||
.daterangepicker:before {
|
||||
top: -7px;
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
border-bottom: 7px solid #ccc; }
|
||||
.daterangepicker:after {
|
||||
top: -6px;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
border-left: 6px solid transparent; }
|
||||
.daterangepicker.opensleft:before {
|
||||
right: 9px; }
|
||||
.daterangepicker.opensleft:after {
|
||||
right: 10px; }
|
||||
.daterangepicker.openscenter:before {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto; }
|
||||
.daterangepicker.openscenter:after {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto; }
|
||||
.daterangepicker.opensright:before {
|
||||
left: 9px; }
|
||||
.daterangepicker.opensright:after {
|
||||
left: 10px; }
|
||||
.daterangepicker.dropup {
|
||||
margin-top: -5px; }
|
||||
.daterangepicker.dropup:before {
|
||||
top: initial;
|
||||
bottom: -7px;
|
||||
border-bottom: initial;
|
||||
border-top: 7px solid #ccc; }
|
||||
.daterangepicker.dropup:after {
|
||||
top: initial;
|
||||
bottom: -6px;
|
||||
border-bottom: initial;
|
||||
border-top: 6px solid #fff; }
|
||||
.daterangepicker.dropdown-menu {
|
||||
max-width: none;
|
||||
z-index: 3001; }
|
||||
.daterangepicker.single .ranges, .daterangepicker.single .calendar {
|
||||
float: none; }
|
||||
.daterangepicker.show-calendar .calendar {
|
||||
display: block; }
|
||||
.daterangepicker .calendar {
|
||||
display: none;
|
||||
max-width: 270px;
|
||||
margin: 4px; }
|
||||
.daterangepicker .calendar.single .calendar-table {
|
||||
border: none; }
|
||||
.daterangepicker .calendar th, .daterangepicker .calendar td {
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
min-width: 32px; }
|
||||
.daterangepicker .calendar-table {
|
||||
border: 1px solid #fff;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
background-color: #fff; }
|
||||
.daterangepicker table {
|
||||
width: 100%;
|
||||
margin: 0; }
|
||||
.daterangepicker td, .daterangepicker th {
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
cursor: pointer; }
|
||||
.daterangepicker td.available:hover, .daterangepicker th.available:hover {
|
||||
background-color: #eee;
|
||||
border-color: transparent;
|
||||
color: inherit; }
|
||||
.daterangepicker td.week, .daterangepicker th.week {
|
||||
font-size: 80%;
|
||||
color: #ccc; }
|
||||
.daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date {
|
||||
background-color: #fff;
|
||||
border-color: transparent;
|
||||
color: #999; }
|
||||
.daterangepicker td.in-range {
|
||||
background-color: #ebf4f8;
|
||||
border-color: transparent;
|
||||
color: #000;
|
||||
border-radius: 0; }
|
||||
.daterangepicker td.start-date {
|
||||
border-radius: 4px 0 0 4px; }
|
||||
.daterangepicker td.end-date {
|
||||
border-radius: 0 4px 4px 0; }
|
||||
.daterangepicker td.start-date.end-date {
|
||||
border-radius: 4px; }
|
||||
.daterangepicker td.active, .daterangepicker td.active:hover {
|
||||
background-color: #357ebd;
|
||||
border-color: transparent;
|
||||
color: #fff; }
|
||||
.daterangepicker th.month {
|
||||
width: auto; }
|
||||
.daterangepicker td.disabled, .daterangepicker option.disabled {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
text-decoration: line-through; }
|
||||
.daterangepicker select.monthselect, .daterangepicker select.yearselect {
|
||||
font-size: 12px;
|
||||
padding: 1px;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
cursor: default; }
|
||||
.daterangepicker select.monthselect {
|
||||
margin-right: 2%;
|
||||
width: 56%; }
|
||||
.daterangepicker select.yearselect {
|
||||
width: 40%; }
|
||||
.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect {
|
||||
width: 50px;
|
||||
margin-bottom: 0; }
|
||||
.daterangepicker .input-mini {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
color: #555;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
display: block;
|
||||
vertical-align: middle;
|
||||
margin: 0 0 5px 0;
|
||||
padding: 0 6px 0 28px;
|
||||
width: 100%; }
|
||||
.daterangepicker .input-mini.active {
|
||||
border: 1px solid #08c;
|
||||
border-radius: 4px; }
|
||||
.daterangepicker .daterangepicker_input {
|
||||
position: relative; }
|
||||
.daterangepicker .daterangepicker_input i {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 8px; }
|
||||
.daterangepicker.rtl .input-mini {
|
||||
padding-right: 28px;
|
||||
padding-left: 6px; }
|
||||
.daterangepicker.rtl .daterangepicker_input i {
|
||||
left: auto;
|
||||
right: 8px; }
|
||||
.daterangepicker .calendar-time {
|
||||
text-align: center;
|
||||
margin: 5px auto;
|
||||
line-height: 30px;
|
||||
position: relative;
|
||||
padding-left: 28px; }
|
||||
.daterangepicker .calendar-time select.disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed; }
|
||||
|
||||
.ranges {
|
||||
font-size: 11px;
|
||||
float: none;
|
||||
margin: 4px;
|
||||
text-align: left; }
|
||||
.ranges ul {
|
||||
list-style: none;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100%; }
|
||||
.ranges li {
|
||||
font-size: 13px;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #f5f5f5;
|
||||
border-radius: 4px;
|
||||
color: #08c;
|
||||
padding: 3px 12px;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer; }
|
||||
.ranges li:hover {
|
||||
background-color: #08c;
|
||||
border: 1px solid #08c;
|
||||
color: #fff; }
|
||||
.ranges li.active {
|
||||
background-color: #08c;
|
||||
border: 1px solid #08c;
|
||||
color: #fff; }
|
||||
|
||||
/* Larger Screen Styling */
|
||||
@media (min-width: 564px) {
|
||||
.daterangepicker {
|
||||
width: auto; }
|
||||
.daterangepicker .ranges ul {
|
||||
width: 160px; }
|
||||
.daterangepicker.single .ranges ul {
|
||||
width: 100%; }
|
||||
.daterangepicker.single .calendar.left {
|
||||
clear: none; }
|
||||
.daterangepicker.single.ltr .ranges, .daterangepicker.single.ltr .calendar {
|
||||
float: left; }
|
||||
.daterangepicker.single.rtl .ranges, .daterangepicker.single.rtl .calendar {
|
||||
float: right; }
|
||||
.daterangepicker.ltr {
|
||||
direction: ltr;
|
||||
text-align: left; }
|
||||
.daterangepicker.ltr .calendar.left {
|
||||
clear: left;
|
||||
margin-right: 0; }
|
||||
.daterangepicker.ltr .calendar.left .calendar-table {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
.daterangepicker.ltr .calendar.right {
|
||||
margin-left: 0; }
|
||||
.daterangepicker.ltr .calendar.right .calendar-table {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0; }
|
||||
.daterangepicker.ltr .left .daterangepicker_input {
|
||||
padding-right: 12px; }
|
||||
.daterangepicker.ltr .calendar.left .calendar-table {
|
||||
padding-right: 12px; }
|
||||
.daterangepicker.ltr .ranges, .daterangepicker.ltr .calendar {
|
||||
float: left; }
|
||||
.daterangepicker.rtl {
|
||||
direction: rtl;
|
||||
text-align: right; }
|
||||
.daterangepicker.rtl .calendar.left {
|
||||
clear: right;
|
||||
margin-left: 0; }
|
||||
.daterangepicker.rtl .calendar.left .calendar-table {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0; }
|
||||
.daterangepicker.rtl .calendar.right {
|
||||
margin-right: 0; }
|
||||
.daterangepicker.rtl .calendar.right .calendar-table {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
.daterangepicker.rtl .left .daterangepicker_input {
|
||||
padding-left: 12px; }
|
||||
.daterangepicker.rtl .calendar.left .calendar-table {
|
||||
padding-left: 12px; }
|
||||
.daterangepicker.rtl .ranges, .daterangepicker.rtl .calendar {
|
||||
text-align: right;
|
||||
float: right; } }
|
||||
@media (min-width: 730px) {
|
||||
.daterangepicker .ranges {
|
||||
width: auto; }
|
||||
.daterangepicker.ltr .ranges {
|
||||
float: left; }
|
||||
.daterangepicker.rtl .ranges {
|
||||
float: right; }
|
||||
.daterangepicker .calendar.left {
|
||||
clear: none !important; } }
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -0,0 +1,288 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph horiz-adv-x="0" />
|
||||
<glyph horiz-adv-x="400" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
|
||||
<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="¥" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
|
||||
<glyph unicode=" " horiz-adv-x="650" />
|
||||
<glyph unicode=" " horiz-adv-x="1300" />
|
||||
<glyph unicode=" " horiz-adv-x="650" />
|
||||
<glyph unicode=" " horiz-adv-x="1300" />
|
||||
<glyph unicode=" " horiz-adv-x="433" />
|
||||
<glyph unicode=" " horiz-adv-x="325" />
|
||||
<glyph unicode=" " horiz-adv-x="216" />
|
||||
<glyph unicode=" " horiz-adv-x="216" />
|
||||
<glyph unicode=" " horiz-adv-x="162" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="325" />
|
||||
<glyph unicode="€" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
|
||||
<glyph unicode="₽" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
|
||||
<glyph unicode="−" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="⌛" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
|
||||
<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="☁" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
|
||||
<glyph unicode="⛺" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
|
||||
<glyph unicode="✉" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
|
||||
<glyph unicode="✏" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
|
||||
<glyph unicode="" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
|
||||
<glyph unicode="" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
|
||||
<glyph unicode="" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
|
||||
<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
|
||||
<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
|
||||
<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
|
||||
<glyph unicode="" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
|
||||
<glyph unicode="" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
|
||||
<glyph unicode="" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
|
||||
<glyph unicode="" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
|
||||
<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
|
||||
<glyph unicode="" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
|
||||
<glyph unicode="" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
|
||||
<glyph unicode="" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
|
||||
<glyph unicode="" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
|
||||
<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
|
||||
<glyph unicode="" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
|
||||
<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
|
||||
<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
|
||||
<glyph unicode="" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
|
||||
<glyph unicode="" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
|
||||
<glyph unicode="" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
|
||||
<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
|
||||
<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
|
||||
<glyph unicode="" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
|
||||
<glyph unicode="" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
|
||||
<glyph unicode="" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
|
||||
<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
|
||||
<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
|
||||
<glyph unicode="" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
|
||||
<glyph unicode="" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
|
||||
<glyph unicode="" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
|
||||
<glyph unicode="" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
|
||||
<glyph unicode="" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
|
||||
<glyph unicode="" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
|
||||
<glyph unicode="" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
|
||||
<glyph unicode="" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
|
||||
<glyph unicode="" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
|
||||
<glyph unicode="" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
|
||||
<glyph unicode="" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
|
||||
<glyph unicode="" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
|
||||
<glyph unicode="" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
|
||||
<glyph unicode="" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
|
||||
<glyph unicode="" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
|
||||
<glyph unicode="" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
|
||||
<glyph unicode="" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
|
||||
<glyph unicode="" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
|
||||
<glyph unicode="" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
|
||||
<glyph unicode="" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
|
||||
<glyph unicode="" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
|
||||
<glyph unicode="" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
|
||||
<glyph unicode="" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
|
||||
<glyph unicode="" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
|
||||
<glyph unicode="" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
|
||||
<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
|
||||
<glyph unicode="" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
|
||||
<glyph unicode="" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
|
||||
<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
|
||||
<glyph unicode="" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
|
||||
<glyph unicode="" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
|
||||
<glyph unicode="" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
|
||||
<glyph unicode="" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
|
||||
<glyph unicode="" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
|
||||
<glyph unicode="" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
|
||||
<glyph unicode="" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
|
||||
<glyph unicode="" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
|
||||
<glyph unicode="" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
|
||||
<glyph unicode="" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
|
||||
<glyph unicode="" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
|
||||
<glyph unicode="" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
|
||||
<glyph unicode="" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
|
||||
<glyph unicode="" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
|
||||
<glyph unicode="" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
|
||||
<glyph unicode="" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
|
||||
<glyph unicode="" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
|
||||
<glyph unicode="" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
|
||||
<glyph unicode="" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
|
||||
<glyph unicode="" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
|
||||
<glyph unicode="" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
|
||||
<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
|
||||
<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
|
||||
<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
|
||||
<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
|
||||
<glyph unicode="" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
|
||||
<glyph unicode="" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
|
||||
<glyph unicode="" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
|
||||
<glyph unicode="" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
|
||||
<glyph unicode="" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
|
||||
<glyph unicode="" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
|
||||
<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
|
||||
<glyph unicode="" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
|
||||
<glyph unicode="" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
|
||||
<glyph unicode="" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
|
||||
<glyph unicode="" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
|
||||
<glyph unicode="" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
|
||||
<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
|
||||
<glyph unicode="" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
|
||||
<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
|
||||
<glyph unicode="" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
|
||||
<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
|
||||
<glyph unicode="" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
|
||||
<glyph unicode="" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
|
||||
<glyph unicode="" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
|
||||
<glyph unicode="" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
|
||||
<glyph unicode="" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
|
||||
<glyph unicode="" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
|
||||
<glyph unicode="" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
|
||||
<glyph unicode="" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
|
||||
<glyph unicode="" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
|
||||
<glyph unicode="" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
|
||||
<glyph unicode="" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
|
||||
<glyph unicode="" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
|
||||
<glyph unicode="" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
|
||||
<glyph unicode="" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
|
||||
<glyph unicode="" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
|
||||
<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
|
||||
<glyph unicode="" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
|
||||
<glyph unicode="" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
|
||||
<glyph unicode="" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
|
||||
<glyph unicode="" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
|
||||
<glyph unicode="" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
|
||||
<glyph unicode="" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
|
||||
<glyph unicode="" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
|
||||
<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
|
||||
<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
|
||||
<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
|
||||
<glyph unicode="" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
|
||||
<glyph unicode="" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
|
||||
<glyph unicode="" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
|
||||
<glyph unicode="" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
|
||||
<glyph unicode="" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
|
||||
<glyph unicode="" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
|
||||
<glyph unicode="" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
|
||||
<glyph unicode="" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
|
||||
<glyph unicode="" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
|
||||
<glyph unicode="" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
|
||||
<glyph unicode="" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
|
||||
<glyph unicode="" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
|
||||
<glyph unicode="" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
|
||||
<glyph unicode="" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
|
||||
<glyph unicode="" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
|
||||
<glyph unicode="" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
|
||||
<glyph unicode="" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
|
||||
<glyph unicode="" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
|
||||
<glyph unicode="" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
|
||||
<glyph unicode="" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
|
||||
<glyph unicode="" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
|
||||
<glyph unicode="" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
|
||||
<glyph unicode="" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
|
||||
<glyph unicode="" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
|
||||
<glyph unicode="" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
|
||||
<glyph unicode="" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
|
||||
<glyph unicode="" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
|
||||
<glyph unicode="" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
|
||||
<glyph unicode="" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
|
||||
<glyph unicode="" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
|
||||
<glyph unicode="" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
|
||||
<glyph unicode="" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
|
||||
<glyph unicode="" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
|
||||
<glyph unicode="" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
|
||||
<glyph unicode="" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
|
||||
<glyph unicode="" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
|
||||
<glyph unicode="" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
|
||||
<glyph unicode="" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
|
||||
<glyph unicode="" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
|
||||
<glyph unicode="" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
|
||||
<glyph unicode="" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
|
||||
<glyph unicode="" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
|
||||
<glyph unicode="" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
|
||||
<glyph unicode="" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
|
||||
<glyph unicode="" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
|
||||
<glyph unicode="" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
|
||||
<glyph unicode="" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
|
||||
<glyph unicode="" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
|
||||
<glyph unicode="🔑" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
|
||||
<glyph unicode="🚪" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
|
||||
</font>
|
||||
</defs></svg>
|
After Width: | Height: | Size: 106 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:75px;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:8px;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:8px;right:8px;display:block;font-family:'Glyphicons Halflings';opacity:0.5}table.dataTable thead .sorting:after{opacity:0.2;content:"\e150"}table.dataTable thead .sorting_asc:after{content:"\e155"}table.dataTable thead .sorting_desc:after{content:"\e156"}table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{color:#eee}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table thead .sorting:after,div.dataTables_scrollBody table thead .sorting_asc:after,div.dataTables_scrollBody table thead .sorting_desc:after{display:none}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-condensed>thead>tr>th{padding-right:20px}table.dataTable.table-condensed .sorting:after,table.dataTable.table-condensed .sorting_asc:after,table.dataTable.table-condensed .sorting_desc:after{top:6px;right:6px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0}
|
|
@ -0,0 +1,8 @@
|
|||
/*!
|
||||
DataTables Bootstrap 3 integration
|
||||
©2011-2015 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
(function(b){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return b(a,window,document)}):"object"===typeof exports?module.exports=function(a,d){a||(a=window);if(!d||!d.fn.dataTable)d=require("datatables.net")(a,d).$;return b(d,a,a.document)}:b(jQuery,window,document)})(function(b,a,d,m){var f=b.fn.dataTable;b.extend(!0,f.defaults,{dom:"<'row'<'col-sm-6'l><'col-sm-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-5'i><'col-sm-7'p>>",renderer:"bootstrap"});b.extend(f.ext.classes,
|
||||
{sWrapper:"dataTables_wrapper form-inline dt-bootstrap",sFilterInput:"form-control input-sm",sLengthSelect:"form-control input-sm",sProcessing:"dataTables_processing panel panel-default"});f.ext.renderer.pageButton.bootstrap=function(a,h,r,s,j,n){var o=new f.Api(a),t=a.oClasses,k=a.oLanguage.oPaginate,u=a.oLanguage.oAria.paginate||{},e,g,p=0,q=function(d,f){var l,h,i,c,m=function(a){a.preventDefault();!b(a.currentTarget).hasClass("disabled")&&o.page()!=a.data.action&&o.page(a.data.action).draw("page")};
|
||||
l=0;for(h=f.length;l<h;l++)if(c=f[l],b.isArray(c))q(d,c);else{g=e="";switch(c){case "ellipsis":e="…";g="disabled";break;case "first":e=k.sFirst;g=c+(0<j?"":" disabled");break;case "previous":e=k.sPrevious;g=c+(0<j?"":" disabled");break;case "next":e=k.sNext;g=c+(j<n-1?"":" disabled");break;case "last":e=k.sLast;g=c+(j<n-1?"":" disabled");break;default:e=c+1,g=j===c?"active":""}e&&(i=b("<li>",{"class":t.sPageButton+" "+g,id:0===r&&"string"===typeof c?a.sTableId+"_"+c:null}).append(b("<a>",{href:"#",
|
||||
"aria-controls":a.sTableId,"aria-label":u[c],"data-dt-idx":p,tabindex:a.iTabIndex}).html(e)).appendTo(d),a.oApi._fnBindAction(i,{action:c},m),p++)}},i;try{i=b(h).find(d.activeElement).data("dt-idx")}catch(v){}q(b(h).empty().html('<ul class="pagination"/>').children("ul"),s);i!==m&&b(h).find("[data-dt-idx="+i+"]").focus()};return f});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue