update
This commit is contained in:
39
tool-tech-file-view/src/main/assembly/dist-linux.xml
Normal file
39
tool-tech-file-view/src/main/assembly/dist-linux.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||
<id>assembly-linux</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>src/main/bin</directory>
|
||||
<outputDirectory>${file.separator}bin</outputDirectory>
|
||||
<includes>
|
||||
<include>*.sh</include>
|
||||
</includes>
|
||||
<fileMode>755</fileMode>
|
||||
<lineEnding>unix</lineEnding>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/config</directory>
|
||||
<outputDirectory>${file.separator}config</outputDirectory>
|
||||
<lineEnding>unix</lineEnding>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/log</directory>
|
||||
<outputDirectory>${file.separator}log</outputDirectory>
|
||||
<lineEnding>unix</lineEnding>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}</directory>
|
||||
<outputDirectory>${file.separator}bin</outputDirectory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
39
tool-tech-file-view/src/main/assembly/dist-win32.xml
Normal file
39
tool-tech-file-view/src/main/assembly/dist-win32.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||
<id>assembly-windows</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>src/main/bin</directory>
|
||||
<outputDirectory>${file.separator}bin</outputDirectory>
|
||||
<includes>
|
||||
<include>*.bat</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/config</directory>
|
||||
<outputDirectory>${file.separator}config</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/log</directory>
|
||||
<outputDirectory>${file.separator}log</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>LibreOfficePortable</directory>
|
||||
<outputDirectory>${file.separator}LibreOfficePortable</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}</directory>
|
||||
<outputDirectory>${file.separator}bin</outputDirectory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
36
tool-tech-file-view/src/main/bin/install.sh
Normal file
36
tool-tech-file-view/src/main/bin/install.sh
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
cd /tmp
|
||||
|
||||
install_redhat() {
|
||||
wget https://downloadarchive.documentfoundation.org/libreoffice/old/7.5.3.2/rpm/x86_64/LibreOffice_7.5.3.2_Linux_x86-64_rpm.tar.gz -cO LibreOffice_7_rpm.tar.gz && tar -zxf /tmp/LibreOffice_7_rpm.tar.gz && cd /tmp/LibreOffice_7.5.3.2_Linux_x86-64_rpm/RPMS
|
||||
echo $?
|
||||
if [ $? -eq 0 ];then
|
||||
yum install -y libSM.x86_64 libXrender.x86_64 libXext.x86_64
|
||||
yum groupinstall -y "X Window System"
|
||||
yum localinstall -y *.rpm
|
||||
echo 'install finshed...'
|
||||
else
|
||||
echo 'download package error...'
|
||||
fi
|
||||
}
|
||||
|
||||
install_ubuntu() {
|
||||
wget https://downloadarchive.documentfoundation.org/libreoffice/old/7.5.3.2/deb/x86_64/LibreOffice_7.5.3.2_Linux_x86-64_deb.tar.gz -cO LibreOffice_7_deb.tar.gz && tar -zxf /tmp/LibreOffice_7_deb.tar.gz && cd /tmp/LibreOffice_7.5.3.2_Linux_x86-64_deb/DEBS
|
||||
echo $?
|
||||
if [ $? -eq 0 ];then
|
||||
apt-get install -y libxinerama1 libcairo2 libcups2 libx11-xcb1
|
||||
dpkg -i *.deb
|
||||
echo 'install finshed...'
|
||||
else
|
||||
echo 'download package error...'
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [ -f "/etc/redhat-release" ]; then
|
||||
yum install -y wget
|
||||
install_redhat
|
||||
else
|
||||
apt-get install -y wget
|
||||
install_ubuntu
|
||||
fi
|
||||
2
tool-tech-file-view/src/main/bin/showlog.sh
Normal file
2
tool-tech-file-view/src/main/bin/showlog.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
tail -fn 300 ../log/kkFileView.log
|
||||
36
tool-tech-file-view/src/main/bin/shutdown.sh
Normal file
36
tool-tech-file-view/src/main/bin/shutdown.sh
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
#############################
|
||||
# Author: sanxi
|
||||
# Version: 1.0
|
||||
# Date: 2021/09/17
|
||||
# Description: v1.0:修改kkFileView关闭进程机制
|
||||
#############################
|
||||
#
|
||||
KKFILEVIEW_BIN_FOLDER=$(cd "$(dirname "$0")" || exit 1 ;pwd)
|
||||
PID_FILE_NAME="kkFileView.pid"
|
||||
PID_FILE="${KKFILEVIEW_BIN_FOLDER}/${PID_FILE_NAME}"
|
||||
export KKFILEVIEW_BIN_FOLDER=$KKFILEVIEW_BIN_FOLDER
|
||||
#
|
||||
## pid文件是否存在
|
||||
if [ ! -e "$PID_FILE" ]; then
|
||||
echo "kkFileView.pid文件不存在!"
|
||||
exit 1
|
||||
else
|
||||
## 文件不为空代表程序正在运行,则循环关闭进程。
|
||||
if [ -s "$PID_FILE" ]; then
|
||||
# 读取pid文件内容,开启while循环读取每一行文本赋予给变量PID_FILE。
|
||||
cat "${PID_FILE}" | while read PID;do
|
||||
## 如已读取完毕,则退出脚本。
|
||||
[ -z "$PID" ] && exit 2
|
||||
echo "正在停止进程:${PID}..."
|
||||
## 正常停止进程
|
||||
kill -15 "${PID}" && echo "进程:${PID}停止成功!"
|
||||
done
|
||||
# 关闭所有进程后,重置pid。
|
||||
cat /dev/null > "$PID_FILE"
|
||||
else
|
||||
echo "kkFileView进程尚未运行!"
|
||||
fi
|
||||
fi
|
||||
10
tool-tech-file-view/src/main/bin/startup.bat
Normal file
10
tool-tech-file-view/src/main/bin/startup.bat
Normal file
@@ -0,0 +1,10 @@
|
||||
@echo off
|
||||
set "KKFILEVIEW_BIN_FOLDER=%cd%"
|
||||
cd "%KKFILEVIEW_BIN_FOLDER%"
|
||||
echo Using KKFILEVIEW_BIN_FOLDER %KKFILEVIEW_BIN_FOLDER%
|
||||
echo Starting kkFileView...
|
||||
echo Please check log file in ../log/kkFileView.log for more information
|
||||
echo You can get help in our official home site: https://kkview.cn
|
||||
echo If you need further help, please join our kk opensource community: https://t.zsxq.com/09ZHSXbsQ
|
||||
echo If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers
|
||||
java -Dspring.config.location=..\config\application.properties -jar kkFileView-4.4.0-beta.jar -> ..\log\kkFileView.log
|
||||
62
tool-tech-file-view/src/main/bin/startup.sh
Normal file
62
tool-tech-file-view/src/main/bin/startup.sh
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
#############################
|
||||
# First_Author: 凯京科技
|
||||
# Second_Author: sanxi
|
||||
# Version: 1.1
|
||||
# Date: 2021/09/17
|
||||
# Description: v1.1:修改进程启动机制为pid形式。
|
||||
#############################
|
||||
#
|
||||
DIR_HOME=("/opt/openoffice.org3" "/opt/libreoffice" "/opt/libreoffice6.1" "/opt/libreoffice7.0" "/opt/libreoffice7.1" "/opt/libreoffice7.2" "/opt/libreoffice7.3" "/opt/libreoffice7.4" "/opt/libreoffice7.5" "/opt/libreoffice7.6" "/opt/openoffice4" "/usr/lib/openoffice" "/usr/lib/libreoffice")
|
||||
FLAG=
|
||||
OFFICE_HOME=
|
||||
KKFILEVIEW_BIN_FOLDER=$(cd "$(dirname "$0")" || exit 1 ;pwd)
|
||||
PID_FILE_NAME="kkFileView.pid"
|
||||
PID_FILE="${KKFILEVIEW_BIN_FOLDER}/${PID_FILE_NAME}"
|
||||
export KKFILEVIEW_BIN_FOLDER=$KKFILEVIEW_BIN_FOLDER
|
||||
#
|
||||
## 如pid文件不存在则自动创建
|
||||
if [ ! -f ${PID_FILE_NAME} ]; then
|
||||
touch "${KKFILEVIEW_BIN_FOLDER}/${PID_FILE_NAME}"
|
||||
fi
|
||||
## 判断当前是否有进程处于运行状态
|
||||
if [ -s "${PID_FILE}" ]; then
|
||||
PID=$(cat "${PID_FILE}")
|
||||
echo "进程已处于运行状态,进程号为:${PID}"
|
||||
exit 1
|
||||
else
|
||||
cd "$KKFILEVIEW_BIN_FOLDER" || exit 1
|
||||
echo "Using KKFILEVIEW_BIN_FOLDER $KKFILEVIEW_BIN_FOLDER"
|
||||
grep 'office\.home' ../config/application.properties | grep '!^#'
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Using customized office.home"
|
||||
else
|
||||
for i in ${DIR_HOME[@]}
|
||||
do
|
||||
if [ -f "$i/program/soffice.bin" ]; then
|
||||
FLAG=true
|
||||
OFFICE_HOME=${i}
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ ! -n "${FLAG}" ]; then
|
||||
echo "Installing LibreOffice"
|
||||
sh ./install.sh
|
||||
else
|
||||
echo "Detected office component has been installed in $OFFICE_HOME"
|
||||
fi
|
||||
fi
|
||||
|
||||
## 启动kkFileView
|
||||
echo "Starting kkFileView..."
|
||||
nohup java -Dfile.encoding=UTF-8 -Dspring.config.location=../config/application.properties -jar kkFileView-4.4.0-beta.jar > ../log/kkFileView.log 2>&1 &
|
||||
echo "Please execute ./showlog.sh to check log for more information"
|
||||
echo "You can get help in our official home site: https://kkview.cn"
|
||||
echo "If you need further help, please join our kk opensource community: https://t.zsxq.com/09ZHSXbsQ"
|
||||
echo "If this project is helpful to you, please star it on https://gitee.com/kekingcn/file-online-preview/stargazers"
|
||||
PROCESS=$(ps -ef | grep -v grep | grep java | grep kkFileView | awk 'NR==1{print $2}')
|
||||
# 启动成功后将进程号写入pid文件
|
||||
echo "$PROCESS" > "$PID_FILE"
|
||||
fi
|
||||
189
tool-tech-file-view/src/main/config/application.properties
Normal file
189
tool-tech-file-view/src/main/config/application.properties
Normal file
@@ -0,0 +1,189 @@
|
||||
#######################################不可动态配置,需要重启生效#######################################
|
||||
server.port = ${KK_SERVER_PORT:8012}
|
||||
server.servlet.context-path= ${KK_CONTEXT_PATH:/tool-tech-file-view}
|
||||
server.servlet.encoding.charset = utf-8
|
||||
#启用GZIP压缩功能
|
||||
server.compression.enable= true
|
||||
#允许压缩的响应缓冲区最小字节数,默认2048
|
||||
server.compression.min-response-size = 2048
|
||||
#压缩格式
|
||||
server.compression.mime-types=application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain,font/woff,application/font-woff,font/eot,image/svg+xml,image/x-icon
|
||||
# 文件上传限制前端
|
||||
spring.servlet.multipart.max-file-size=500MB
|
||||
#文件上传限制
|
||||
spring.servlet.multipart.max-request-size=500MB
|
||||
## Freemarker 配置
|
||||
spring.freemarker.template-loader-path = classpath:/web/
|
||||
spring.freemarker.cache = false
|
||||
spring.freemarker.charset = UTF-8
|
||||
spring.freemarker.check-template-location = true
|
||||
spring.freemarker.content-type = text/html
|
||||
spring.freemarker.expose-request-attributes = true
|
||||
spring.freemarker.expose-session-attributes = true
|
||||
spring.freemarker.request-context-attribute = request
|
||||
spring.freemarker.suffix = .ftl
|
||||
|
||||
# office设置
|
||||
#openoffice或LibreOffice home路径
|
||||
#office.home = C:\\Program Files (x86)\\OpenOffice 4
|
||||
office.home = ${KK_OFFICE_HOME:default}
|
||||
## office转换服务的端口,默认开启两个进程
|
||||
office.plugin.server.ports = 2001,2002
|
||||
## office 转换服务 task 超时时间,默认五分钟
|
||||
office.plugin.task.timeout = 5m
|
||||
#此属性设置office进程在重新启动之前可以执行的最大任务数。0表示无限数量的任务(永远不会重新启动)
|
||||
office.plugin.task.maxtasksperprocess = 200
|
||||
#此属性设置处理任务所允许的最长时间。如果任务的处理时间长于此超时,则此任务将中止,并处理下一个任务。
|
||||
office.plugin.task.taskexecutiontimeout = 5m
|
||||
#生成限制 默认不限制 使用方法 (1-5)
|
||||
office.pagerange = ${KK_OFFICE_PAGERANGE:false}
|
||||
#生成水印 默认不启用 使用方法 (kkFileView)
|
||||
office.watermark = ${KK_OFFICE_WATERMARK:false}
|
||||
#OFFICE JPEG图片压缩
|
||||
office.quality = ${KK_OFFICE_QUALITY:80}
|
||||
#图像分辨率限制
|
||||
office.maximageresolution = ${KK_OFFICE_MAXIMAGERESOLUTION:150}
|
||||
#导出书签
|
||||
office.exportbookmarks = ${KK_OFFICE_EXPORTBOOKMARKS:true}
|
||||
#批注作为PDF的注释
|
||||
office.exportnotes = ${KK_OFFICE_EXPORTNOTES:true}
|
||||
#加密文档 生成的PDF文档 添加密码(密码为加密文档的密码)
|
||||
office.documentopenpasswords = ${KK_OFFICE_DOCUMENTOPENPASSWORD:true}
|
||||
#xlsx格式前端解析
|
||||
office.type.web = ${KK_OFFICE_TYPE_WEB:web}
|
||||
|
||||
|
||||
# 其他核心设置
|
||||
#预览生成资源路径(默认为打包根路径下的file目录下)
|
||||
#file.dir = D:\\kkFileview\\
|
||||
file.dir = ${KK_FILE_DIR:default}
|
||||
#允许预览的本地文件夹 默认不允许任何本地文件被预览
|
||||
#WINDOWS参考 local.preview.dir = \D:\\kkFileview\\1\\1.txt (注意前面必须添加反斜杠)
|
||||
#LINUX参考 local.preview.dir = /opt/1.txt (注意前面必须是正斜杠)
|
||||
#使用方法 windows file://d:/1/1.txt linux file:/opt/1/1.txt
|
||||
#file 协议参考:https://datatracker.ietf.org/doc/html/rfc8089
|
||||
local.preview.dir = ${KK_LOCAL_PREVIEW_DIR:default}
|
||||
#是否启用缓存
|
||||
cache.enabled = ${KK_CACHE_ENABLED:true}
|
||||
#缓存实现类型,不配默认为内嵌RocksDB(type = default)实现,可配置为redis(type = redis)实现(需要配置spring.redisson.address等参数)和 JDK 内置对象实现(type = jdk),
|
||||
cache.type = ${KK_CACHE_TYPE:redis}
|
||||
#redis连接,只有当cache.type = redis时才有用
|
||||
spring.redisson.address = ${KK_SPRING_REDISSON_ADDRESS:192.168.1.168:6379}
|
||||
spring.redisson.password = ${KK_SPRING_REDISSON_PASSWORD:}
|
||||
#缓存是否自动清理 true 为开启,注释掉或其他值都为关闭
|
||||
cache.clean.enabled = ${KK_CACHE_CLEAN_ENABLED:true}
|
||||
#缓存自动清理时间,cache.clean.enabled = true时才有用,cron表达式,基于Quartz cron
|
||||
cache.clean.cron = ${KK_CACHE_CLEAN_CRON:0 0 3 * * ?}
|
||||
#######################################可在运行时动态配置#######################################
|
||||
#提供预览服务的地址,默认从请求url读,如果使用nginx等反向代理,需要手动设置
|
||||
#base.url = https://file.keking.cn
|
||||
base.url = ${KK_BASE_URL:default}
|
||||
#信任站点,多个用','隔开,设置了之后,会限制只能预览来自信任站点列表的文件,默认不限制
|
||||
#trust.host = kkview.cn
|
||||
trust.host = ${KK_TRUST_HOST:default}
|
||||
#不信任站点,多个用','隔开,设置了之后,会限制来自不信任站点列表的文件,默认不限制
|
||||
#not.trust.host = kkview.cn
|
||||
not.trust.host= ${KK_NOT_TRUST_HOST:default}
|
||||
#文本类型,默认如下,可自定义添加
|
||||
simText = ${KK_SIMTEXT:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd}
|
||||
|
||||
|
||||
#FTP模块设置
|
||||
#预览源为FTP时 FTP用户名,可在ftp url后面加参数ftp.username=ftpuser指定,不指定默认用配置的
|
||||
ftp.username = ${KK_FTP_USERNAME:ftpuser}
|
||||
#预览源为FTP时 FTP密码,可在ftp url后面加参数ftp.password=123456指定,不指定默认用配置的
|
||||
ftp.password = ${KK_FTP_PASSWORD:123456}
|
||||
#预览源为FTP时, FTP连接默认ControlEncoding(根据FTP服务器操作系统选择,Linux一般为UTF-8,Windows一般为GBK),可在ftp url后面加参数ftp.control.encoding=UTF-8指定,不指定默认用配置的
|
||||
ftp.control.encoding = ${KK_FTP_CONTROL_ENCODING:UTF-8}
|
||||
|
||||
#视频设置
|
||||
#多媒体类型,默认如下,可自定义添加
|
||||
media = ${KK_MEDIA:mp3,wav,mp4,flv,mpd,m3u8,ts,mpeg,m4a}
|
||||
#是否开启多媒体类型转视频格式转换,目前可转换视频格式有:avi,mov,wmv,3gp,rm
|
||||
#请谨慎开启此功能,建议异步调用添加到处理队列,并且增加任务队列处理线程,防止视频转换占用完线程资源,转换比较耗费时间,并且控制了只能串行处理转换任务
|
||||
media.convert.disable = ${KK_MEDIA_CONVERT_DISABLE:false}
|
||||
#支持转换的视频类型
|
||||
convertMedias = ${KK_CONVERTMEDIAS:avi,mov,wmv,mkv,3gp,rm}
|
||||
|
||||
|
||||
|
||||
#PDF预览模块设置
|
||||
#配置PDF文件生成图片的像素大小,dpi 越高,图片质量越清晰,同时也会消耗更多的计算资源。
|
||||
pdf2jpg.dpi = ${KK_PDF2JPG_DPI:144}
|
||||
#是否禁止演示模式
|
||||
pdf.presentationMode.disable = ${KK_PDF_PRESENTATION_MODE_DISABLE:true}
|
||||
#是否禁止打开文件
|
||||
pdf.openFile.disable = ${KK_PDF_OPEN_FILE_DISABLE:true}
|
||||
#是否禁止打印转换生成的pdf文件
|
||||
pdf.print.disable = ${KK_PDF_PRINT_DISABLE:true}
|
||||
#是否禁止下载转换生成的pdf文件
|
||||
pdf.download.disable = ${KK_PDF_DOWNLOAD_DISABLE:true}
|
||||
#是否禁止bookmark
|
||||
pdf.bookmark.disable = ${KK_PDF_BOOKMARK_DISABLE:true}
|
||||
#是否禁止签名
|
||||
pdf.disable.editing = ${KK_PDF_DISABLE_EDITING:false}
|
||||
#office类型文档(word ppt)样式,默认为图片(image),可配置为pdf(预览时也有按钮切换)
|
||||
office.preview.type = ${KK_OFFICE_PREVIEW_TYPE:image}
|
||||
#是否关闭office预览切换开关,默认为false,可配置为true关闭
|
||||
office.preview.switch.disabled = ${KK_OFFICE_PREVIEW_SWITCH_DISABLED:false}
|
||||
|
||||
|
||||
#水印内容
|
||||
#例:watermark.txt = ${WATERMARK_TXT:凯京科技内部文件,严禁外泄}
|
||||
#如需取消水印,内容设置为空即可,例:watermark.txt = ${WATERMARK_TXT:}
|
||||
watermark.txt = ${WATERMARK_TXT:}
|
||||
#水印x轴间隔
|
||||
watermark.x.space = ${WATERMARK_X_SPACE:10}
|
||||
#水印y轴间隔
|
||||
watermark.y.space = ${WATERMARK_Y_SPACE:10}
|
||||
#水印字体
|
||||
watermark.font = ${WATERMARK_FONT:微软雅黑}
|
||||
#水印字体大小
|
||||
watermark.fontsize = ${WATERMARK_FONTSIZE:18px}
|
||||
#水印字体颜色
|
||||
watermark.color = ${WATERMARK_COLOR:black}
|
||||
#水印透明度,要求设置在大于等于0.005,小于1
|
||||
watermark.alpha = ${WATERMARK_ALPHA:0.2}
|
||||
#水印宽度
|
||||
watermark.width = ${WATERMARK_WIDTH:180}
|
||||
#水印高度
|
||||
watermark.height = ${WATERMARK_HEIGHT:80}
|
||||
#水印倾斜度数,要求设置在大于等于0,小于90
|
||||
watermark.angle = ${WATERMARK_ANGLE:10}
|
||||
|
||||
|
||||
#首页功能设置
|
||||
#是否禁用首页文件上传
|
||||
file.upload.disable = ${KK_FILE_UPLOAD_ENABLED:false}
|
||||
# 备案信息,默认为空
|
||||
beian = ${KK_BEIAN:default}
|
||||
#禁止上传类型
|
||||
prohibit = ${KK_PROHIBIT:exe,dll,dat}
|
||||
#启用验证码删除文件 默认关闭
|
||||
delete.captcha= ${KK_DELETE_CAPTCHA:false}
|
||||
#删除密码
|
||||
delete.password = ${KK_DELETE_PASSWORD:123456}
|
||||
#删除 转换后OFFICE、CAD、TIFF、压缩包源文件 默认开启 节约磁盘空间
|
||||
delete.source.file = ${KK_DELETE_SOURCE_FILE:true}
|
||||
#首页初始化加载第一页
|
||||
home.pagenumber = ${DEFAULT_HOME_PAGENUMBER:1}
|
||||
#首页是否分页
|
||||
home.pagination = ${DEFAULT_HOME_PAGINATION:true}
|
||||
#首页初始化单页记录数
|
||||
home.pagesize = ${DEFAULT_HOME_PAGSIZE:15}
|
||||
#首页显示查询框
|
||||
home.search = ${DEFAULT_HOME_SEARCH:true}
|
||||
|
||||
#Tif类型设置
|
||||
#Tif类型图片浏览模式:tif(利用前端js插件浏览);jpg(转换为jpg后前端显示);pdf(转换为pdf后显示,便于打印)
|
||||
tif.preview.type = ${KK_TIF_PREVIEW_TYPE:pdf}
|
||||
|
||||
#Cad类型设置
|
||||
#Cad类型图片浏览模式:tif(利用前端js插件浏览);svg(转换为svg显示);pdf(转换为pdf后显示,便于打印)
|
||||
cad.preview.type = ${KK_CAD_PREVIEW_TYPE:pdf}
|
||||
#Cad转换超时设置
|
||||
cad.timeout =${KK_CAD_TIMEOUT:90}
|
||||
#Cad转换线程设置
|
||||
cad.thread =${KK_CAD_THREAD:5}
|
||||
|
||||
|
||||
29
tool-tech-file-view/src/main/config/freemarker_implicit.ftl
Normal file
29
tool-tech-file-view/src/main/config/freemarker_implicit.ftl
Normal file
@@ -0,0 +1,29 @@
|
||||
[#ftl]
|
||||
[#-- @implicitly included --]
|
||||
[#-- @ftlvariable name="initializeMemorySize" type="java.lang.Number" --]
|
||||
[#-- @ftlvariable name="currentUrl" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="file" type="cn.keking.model.FileAttribute" --]
|
||||
[#-- @ftlvariable name="fileName" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="fileTree" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="needFilePassword" type="java.lang.Boolean" --]
|
||||
[#-- @ftlvariable name="filePasswordError" type="java.lang.Boolean" --]
|
||||
[#-- @ftlvariable name="baseUrl" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="imgUrls" type="java.util.List<String>"--]
|
||||
[#-- @ftlvariable name="textData" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="xmlContent" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="textContent" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="textType" type="java.lang.String" --]
|
||||
[#-- @ftlvariable name="markdown" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="xml" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="switchDisabled" type="java.lang.Boolean"--]
|
||||
[#-- @ftlvariable name="watermarkAngle" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkHeight" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkWidth" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkAlpha" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkColor" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkFontsize" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkFont" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkYSpace" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkXSpace" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="watermarkTxt" type="java.lang.String"--]
|
||||
[#-- @ftlvariable name="ordinaryUrl" type="java.lang.String"--]
|
||||
36
tool-tech-file-view/src/main/java/cn/keking/ServerMain.java
Normal file
36
tool-tech-file-view/src/main/java/cn/keking/ServerMain.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package cn.keking;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@ComponentScan(value = "cn.keking.*")
|
||||
public class ServerMain {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ServerMain.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(ServerMain.class)
|
||||
.logStartupInfo(false)
|
||||
.run(args);
|
||||
stopWatch.stop();
|
||||
ServerProperties serverProperties = context.getBean(ServerProperties.class);
|
||||
Integer port = serverProperties.getPort();
|
||||
ServerProperties.Servlet servlet = serverProperties.getServlet();
|
||||
String contextPath = servlet.getContextPath();
|
||||
String urlSuffix = StringUtils.isBlank(contextPath)? String.valueOf(port):port+contextPath;
|
||||
logger.info("kkFileView 服务启动完成,耗时:{}s,演示页请访问: http://127.0.0.1:{} ", stopWatch.getTotalTimeSeconds(), urlSuffix);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,748 @@
|
||||
package cn.keking.config;
|
||||
|
||||
import cn.keking.utils.ConfigUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* @author: chenjh
|
||||
* @since: 2019/4/10 17:22
|
||||
*/
|
||||
@Component(value = ConfigConstants.BEAN_NAME)
|
||||
public class ConfigConstants {
|
||||
public static final String BEAN_NAME = "configConstants";
|
||||
|
||||
static {
|
||||
//pdfbox兼容低版本jdk
|
||||
System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");
|
||||
}
|
||||
|
||||
private static Boolean cacheEnabled;
|
||||
private static String[] simTexts = {};
|
||||
private static String[] medias = {};
|
||||
private static String[] convertMedias = {};
|
||||
private static String mediaConvertDisable;
|
||||
private static String officePreviewType;
|
||||
private static String officePreviewSwitchDisabled;
|
||||
private static String ftpUsername;
|
||||
private static String ftpPassword;
|
||||
private static String ftpControlEncoding;
|
||||
private static String baseUrl;
|
||||
private static String fileDir = ConfigUtils.getHomePath() + File.separator + "file" + File.separator;
|
||||
private static String localPreviewDir;
|
||||
private static CopyOnWriteArraySet<String> trustHostSet;
|
||||
private static CopyOnWriteArraySet<String> notTrustHostSet;
|
||||
private static String pdfPresentationModeDisable;
|
||||
private static String pdfDisableEditing;
|
||||
private static String pdfOpenFileDisable;
|
||||
private static String pdfPrintDisable;
|
||||
private static String pdfDownloadDisable;
|
||||
private static String pdfBookmarkDisable;
|
||||
private static Boolean fileUploadDisable;
|
||||
private static String tifPreviewType;
|
||||
private static String beian;
|
||||
private static String[] prohibit = {};
|
||||
private static String size;
|
||||
private static String password;
|
||||
private static int pdf2JpgDpi;
|
||||
private static String officeTypeWeb;
|
||||
private static String cadPreviewType;
|
||||
private static Boolean deleteSourceFile;
|
||||
private static Boolean deleteCaptcha;
|
||||
private static String officePageRange;
|
||||
private static String officeWatermark;
|
||||
private static String officeQuality;
|
||||
private static String officeMaxImageResolution;
|
||||
private static Boolean officeExportBookmarks;
|
||||
private static Boolean officeExportNotes;
|
||||
private static Boolean officeDocumentOpenPasswords;
|
||||
private static String cadTimeout;
|
||||
private static int cadThread;
|
||||
private static String homePageNumber;
|
||||
private static String homePagination;
|
||||
private static String homePageSize;
|
||||
private static String homeSearch;
|
||||
|
||||
public static final String DEFAULT_CACHE_ENABLED = "true";
|
||||
public static final String DEFAULT_TXT_TYPE = "txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd,xbrl";
|
||||
public static final String DEFAULT_MEDIA_TYPE = "mp3,wav,mp4,flv";
|
||||
public static final String DEFAULT_OFFICE_PREVIEW_TYPE = "image";
|
||||
public static final String DEFAULT_OFFICE_PREVIEW_SWITCH_DISABLED = "false";
|
||||
public static final String DEFAULT_FTP_USERNAME = null;
|
||||
public static final String DEFAULT_FTP_PASSWORD = null;
|
||||
public static final String DEFAULT_FTP_CONTROL_ENCODING = "UTF-8";
|
||||
public static final String DEFAULT_VALUE = "default";
|
||||
public static final String DEFAULT_PDF_PRESENTATION_MODE_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_OPEN_FILE_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_PRINT_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_DOWNLOAD_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_BOOKMARK_DISABLE = "true";
|
||||
public static final String DEFAULT_PDF_DISABLE_EDITING = "true";
|
||||
public static final String DEFAULT_FILE_UPLOAD_DISABLE = "false";
|
||||
public static final String DEFAULT_TIF_PREVIEW_TYPE = "tif";
|
||||
public static final String DEFAULT_CAD_PREVIEW_TYPE = "pdf";
|
||||
public static final String DEFAULT_BEIAN = "无";
|
||||
public static final String DEFAULT_SIZE = "500MB";
|
||||
public static final String DEFAULT_PROHIBIT = "exe,dll";
|
||||
public static final String DEFAULT_PASSWORD = "123456";
|
||||
public static final String DEFAULT_PDF2_JPG_DPI = "105";
|
||||
public static final String DEFAULT_OFFICE_TYPE_WEB = "web";
|
||||
public static final String DEFAULT_DELETE_SOURCE_FILE = "true";
|
||||
public static final String DEFAULT_DELETE_CAPTCHA = "false";
|
||||
public static final String DEFAULT_CAD_TIMEOUT = "90";
|
||||
public static final String DEFAULT_CAD_THREAD = "5";
|
||||
public static final String DEFAULT_OFFICE_PAQERANQE = "false";
|
||||
public static final String DEFAULT_OFFICE_WATERMARK = "false";
|
||||
public static final String DEFAULT_OFFICE_QUALITY = "80";
|
||||
public static final String DEFAULT_OFFICE_MAXIMAQERESOLUTION = "150";
|
||||
public static final String DEFAULT_OFFICE_EXPORTBOOKMARKS = "true";
|
||||
public static final String DEFAULT_OFFICE_EXPORTNOTES = "true";
|
||||
public static final String DEFAULT_OFFICE_EOCUMENTOPENPASSWORDS = "true";
|
||||
public static final String DEFAULT_HOME_PAGENUMBER = "1";
|
||||
public static final String DEFAULT_HOME_PAGINATION = "true";
|
||||
public static final String DEFAULT_HOME_PAGSIZE = "15";
|
||||
public static final String DEFAULT_HOME_SEARCH = "true";
|
||||
|
||||
public static Boolean isCacheEnabled() {
|
||||
return cacheEnabled;
|
||||
}
|
||||
|
||||
@Value("${cache.enabled:true}")
|
||||
public void setCacheEnabled(String cacheEnabled) {
|
||||
setCacheEnabledValueValue(Boolean.parseBoolean(cacheEnabled));
|
||||
}
|
||||
|
||||
public static void setCacheEnabledValueValue(Boolean cacheEnabled) {
|
||||
ConfigConstants.cacheEnabled = cacheEnabled;
|
||||
}
|
||||
|
||||
public static String[] getSimText() {
|
||||
return simTexts;
|
||||
}
|
||||
|
||||
@Value("${simText:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd,xbrl}")
|
||||
public void setSimText(String simText) {
|
||||
String[] simTextArr = simText.split(",");
|
||||
setSimTextValue(simTextArr);
|
||||
}
|
||||
|
||||
public static void setSimTextValue(String[] simText) {
|
||||
ConfigConstants.simTexts = simText;
|
||||
}
|
||||
|
||||
public static String[] getMedia() {
|
||||
return medias;
|
||||
}
|
||||
|
||||
@Value("${media:mp3,wav,mp4,flv}")
|
||||
public void setMedia(String media) {
|
||||
String[] mediaArr = media.split(",");
|
||||
setMediaValue(mediaArr);
|
||||
}
|
||||
|
||||
public static void setMediaValue(String[] Media) {
|
||||
ConfigConstants.medias = Media;
|
||||
}
|
||||
|
||||
public static String[] getConvertMedias() {
|
||||
return convertMedias;
|
||||
}
|
||||
|
||||
@Value("${convertMedias:avi,mov,wmv,mkv,3gp,rm}")
|
||||
public void setConvertMedias(String convertMedia) {
|
||||
String[] mediaArr = convertMedia.split(",");
|
||||
setConvertMediaValue(mediaArr);
|
||||
}
|
||||
|
||||
public static void setConvertMediaValue(String[] ConvertMedia) {
|
||||
ConfigConstants.convertMedias = ConvertMedia;
|
||||
}
|
||||
|
||||
public static String getMediaConvertDisable() {
|
||||
return mediaConvertDisable;
|
||||
}
|
||||
|
||||
|
||||
@Value("${media.convert.disable:true}")
|
||||
public void setMediaConvertDisable(String mediaConvertDisable) {
|
||||
setMediaConvertDisableValue(mediaConvertDisable);
|
||||
}
|
||||
|
||||
public static void setMediaConvertDisableValue(String mediaConvertDisable) {
|
||||
ConfigConstants.mediaConvertDisable = mediaConvertDisable;
|
||||
}
|
||||
|
||||
public static String getOfficePreviewType() {
|
||||
return officePreviewType;
|
||||
}
|
||||
|
||||
@Value("${office.preview.type:image}")
|
||||
public void setOfficePreviewType(String officePreviewType) {
|
||||
setOfficePreviewTypeValue(officePreviewType);
|
||||
}
|
||||
|
||||
public static void setOfficePreviewTypeValue(String officePreviewType) {
|
||||
ConfigConstants.officePreviewType = officePreviewType;
|
||||
}
|
||||
|
||||
public static String getFtpUsername() {
|
||||
return ftpUsername;
|
||||
}
|
||||
|
||||
@Value("${ftp.username:}")
|
||||
public void setFtpUsername(String ftpUsername) {
|
||||
setFtpUsernameValue(ftpUsername);
|
||||
}
|
||||
|
||||
public static void setFtpUsernameValue(String ftpUsername) {
|
||||
ConfigConstants.ftpUsername = ftpUsername;
|
||||
}
|
||||
|
||||
public static String getFtpPassword() {
|
||||
return ftpPassword;
|
||||
}
|
||||
|
||||
@Value("${ftp.password:}")
|
||||
public void setFtpPassword(String ftpPassword) {
|
||||
setFtpPasswordValue(ftpPassword);
|
||||
}
|
||||
|
||||
public static void setFtpPasswordValue(String ftpPassword) {
|
||||
ConfigConstants.ftpPassword = ftpPassword;
|
||||
}
|
||||
|
||||
public static String getFtpControlEncoding() {
|
||||
return ftpControlEncoding;
|
||||
}
|
||||
|
||||
@Value("${ftp.control.encoding:UTF-8}")
|
||||
public void setFtpControlEncoding(String ftpControlEncoding) {
|
||||
setFtpControlEncodingValue(ftpControlEncoding);
|
||||
}
|
||||
|
||||
public static void setFtpControlEncodingValue(String ftpControlEncoding) {
|
||||
ConfigConstants.ftpControlEncoding = ftpControlEncoding;
|
||||
}
|
||||
|
||||
public static String getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
@Value("${base.url:default}")
|
||||
public void setBaseUrl(String baseUrl) {
|
||||
setBaseUrlValue(baseUrl);
|
||||
}
|
||||
|
||||
public static void setBaseUrlValue(String baseUrl) {
|
||||
ConfigConstants.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
public static String getFileDir() {
|
||||
return fileDir;
|
||||
}
|
||||
|
||||
@Value("${file.dir:default}")
|
||||
public void setFileDir(String fileDir) {
|
||||
setFileDirValue(fileDir);
|
||||
}
|
||||
|
||||
public static void setFileDirValue(String fileDir) {
|
||||
if (!DEFAULT_VALUE.equalsIgnoreCase(fileDir)) {
|
||||
if (!fileDir.endsWith(File.separator)) {
|
||||
fileDir = fileDir + File.separator;
|
||||
}
|
||||
ConfigConstants.fileDir = fileDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getLocalPreviewDir() {
|
||||
return localPreviewDir;
|
||||
}
|
||||
|
||||
@Value("${local.preview.dir:default}")
|
||||
public void setLocalPreviewDir(String localPreviewDir) {
|
||||
setLocalPreviewDirValue(localPreviewDir);
|
||||
}
|
||||
|
||||
public static void setLocalPreviewDirValue(String localPreviewDir) {
|
||||
if (!DEFAULT_VALUE.equals(localPreviewDir)) {
|
||||
if (!localPreviewDir.endsWith(File.separator)) {
|
||||
localPreviewDir = localPreviewDir + File.separator;
|
||||
}
|
||||
}
|
||||
ConfigConstants.localPreviewDir = localPreviewDir;
|
||||
}
|
||||
|
||||
@Value("${trust.host:default}")
|
||||
public void setTrustHost(String trustHost) {
|
||||
setTrustHostSet(getHostValue(trustHost));
|
||||
}
|
||||
|
||||
public static void setTrustHostValue(String trustHost){
|
||||
setTrustHostSet(getHostValue(trustHost));
|
||||
}
|
||||
|
||||
@Value("${not.trust.host:default}")
|
||||
public void setNotTrustHost(String notTrustHost) {
|
||||
setNotTrustHostSet(getHostValue(notTrustHost));
|
||||
}
|
||||
|
||||
public static void setNotTrustHostValue(String notTrustHost){
|
||||
setNotTrustHostSet(getHostValue(notTrustHost));
|
||||
}
|
||||
|
||||
private static CopyOnWriteArraySet<String> getHostValue(String trustHost) {
|
||||
if (DEFAULT_VALUE.equalsIgnoreCase(trustHost)) {
|
||||
return new CopyOnWriteArraySet<>();
|
||||
} else {
|
||||
String[] trustHostArray = trustHost.toLowerCase().split(",");
|
||||
return new CopyOnWriteArraySet<>(Arrays.asList(trustHostArray));
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getTrustHostSet() {
|
||||
return trustHostSet;
|
||||
}
|
||||
|
||||
private static void setTrustHostSet(CopyOnWriteArraySet<String> trustHostSet) {
|
||||
ConfigConstants.trustHostSet = trustHostSet;
|
||||
}
|
||||
|
||||
public static Set<String> getNotTrustHostSet() {
|
||||
return notTrustHostSet;
|
||||
}
|
||||
|
||||
public static void setNotTrustHostSet(CopyOnWriteArraySet<String> notTrustHostSet) {
|
||||
ConfigConstants.notTrustHostSet = notTrustHostSet;
|
||||
}
|
||||
|
||||
|
||||
public static String getPdfPresentationModeDisable() {
|
||||
return pdfPresentationModeDisable;
|
||||
}
|
||||
|
||||
@Value("${pdf.presentationMode.disable:true}")
|
||||
public void setPdfPresentationModeDisable(String pdfPresentationModeDisable) {
|
||||
setPdfPresentationModeDisableValue(pdfPresentationModeDisable);
|
||||
}
|
||||
|
||||
public static void setPdfPresentationModeDisableValue(String pdfPresentationModeDisable) {
|
||||
ConfigConstants.pdfPresentationModeDisable = pdfPresentationModeDisable;
|
||||
}
|
||||
|
||||
public static String getPdfOpenFileDisable() {
|
||||
return pdfOpenFileDisable;
|
||||
}
|
||||
|
||||
@Value("${pdf.openFile.disable:true}")
|
||||
public void setPdfOpenFileDisable(String pdfOpenFileDisable) {
|
||||
setPdfOpenFileDisableValue(pdfOpenFileDisable);
|
||||
}
|
||||
|
||||
public static void setPdfOpenFileDisableValue(String pdfOpenFileDisable) {
|
||||
ConfigConstants.pdfOpenFileDisable = pdfOpenFileDisable;
|
||||
}
|
||||
|
||||
public static String getPdfPrintDisable() {
|
||||
return pdfPrintDisable;
|
||||
}
|
||||
|
||||
@Value("${pdf.print.disable:true}")
|
||||
public void setPdfPrintDisable(String pdfPrintDisable) {
|
||||
setPdfPrintDisableValue(pdfPrintDisable);
|
||||
}
|
||||
|
||||
public static void setPdfPrintDisableValue(String pdfPrintDisable) {
|
||||
ConfigConstants.pdfPrintDisable = pdfPrintDisable;
|
||||
}
|
||||
|
||||
public static String getPdfDownloadDisable() {
|
||||
return pdfDownloadDisable;
|
||||
}
|
||||
|
||||
@Value("${pdf.download.disable:true}")
|
||||
public void setPdfDownloadDisable(String pdfDownloadDisable) {
|
||||
setPdfDownloadDisableValue(pdfDownloadDisable);
|
||||
}
|
||||
|
||||
public static void setPdfDownloadDisableValue(String pdfDownloadDisable) {
|
||||
ConfigConstants.pdfDownloadDisable = pdfDownloadDisable;
|
||||
}
|
||||
|
||||
public static String getPdfBookmarkDisable() {
|
||||
return pdfBookmarkDisable;
|
||||
}
|
||||
|
||||
@Value("${pdf.bookmark.disable:true}")
|
||||
public void setPdfBookmarkDisable(String pdfBookmarkDisable) {
|
||||
setPdfBookmarkDisableValue(pdfBookmarkDisable);
|
||||
}
|
||||
|
||||
public static void setPdfBookmarkDisableValue(String pdfBookmarkDisable) {
|
||||
ConfigConstants.pdfBookmarkDisable = pdfBookmarkDisable;
|
||||
}
|
||||
|
||||
|
||||
public static String getPdfDisableEditing() {
|
||||
return pdfDisableEditing;
|
||||
}
|
||||
|
||||
@Value("${pdf.disable.editing:true}")
|
||||
public void setpdfDisableEditing(String pdfDisableEditing) {
|
||||
setPdfDisableEditingValue(pdfDisableEditing);
|
||||
}
|
||||
|
||||
public static void setPdfDisableEditingValue(String pdfDisableEditing) {
|
||||
ConfigConstants.pdfDisableEditing = pdfDisableEditing;
|
||||
}
|
||||
|
||||
public static String getOfficePreviewSwitchDisabled() {
|
||||
return officePreviewSwitchDisabled;
|
||||
}
|
||||
|
||||
@Value("${office.preview.switch.disabled:true}")
|
||||
public void setOfficePreviewSwitchDisabled(String officePreviewSwitchDisabled) {
|
||||
ConfigConstants.officePreviewSwitchDisabled = officePreviewSwitchDisabled;
|
||||
}
|
||||
|
||||
public static void setOfficePreviewSwitchDisabledValue(String officePreviewSwitchDisabled) {
|
||||
ConfigConstants.officePreviewSwitchDisabled = officePreviewSwitchDisabled;
|
||||
}
|
||||
|
||||
public static Boolean getFileUploadDisable() {
|
||||
return fileUploadDisable;
|
||||
}
|
||||
|
||||
@Value("${file.upload.disable:false}")
|
||||
public void setFileUploadDisable(Boolean fileUploadDisable) {
|
||||
setFileUploadDisableValue(fileUploadDisable);
|
||||
}
|
||||
|
||||
public static void setFileUploadDisableValue(Boolean fileUploadDisable) {
|
||||
ConfigConstants.fileUploadDisable = fileUploadDisable;
|
||||
}
|
||||
|
||||
|
||||
public static String getTifPreviewType() {
|
||||
return tifPreviewType;
|
||||
}
|
||||
|
||||
@Value("${tif.preview.type:tif}")
|
||||
public void setTifPreviewType(String tifPreviewType) {
|
||||
setTifPreviewTypeValue(tifPreviewType);
|
||||
}
|
||||
|
||||
public static void setTifPreviewTypeValue(String tifPreviewType) {
|
||||
ConfigConstants.tifPreviewType = tifPreviewType;
|
||||
}
|
||||
|
||||
public static String[] getProhibit() {
|
||||
return prohibit;
|
||||
}
|
||||
|
||||
@Value("${prohibit:exe,dll}")
|
||||
public void setProhibit(String prohibit) {
|
||||
String[] prohibitArr = prohibit.split(",");
|
||||
setProhibitValue(prohibitArr);
|
||||
}
|
||||
|
||||
public static void setProhibitValue(String[] prohibit) {
|
||||
ConfigConstants.prohibit = prohibit;
|
||||
}
|
||||
|
||||
public static String maxSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Value("${spring.servlet.multipart.max-file-size:500MB}")
|
||||
public void setSize(String size) {
|
||||
setSizeValue(size);
|
||||
}
|
||||
|
||||
public static void setSizeValue(String size) {
|
||||
ConfigConstants.size = size;
|
||||
}
|
||||
|
||||
public static String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Value("${delete.password:123456}")
|
||||
public void setPassword(String password) {
|
||||
setPasswordValue(password);
|
||||
}
|
||||
|
||||
public static void setPasswordValue(String password) {
|
||||
ConfigConstants.password = password;
|
||||
}
|
||||
|
||||
|
||||
public static int getPdf2JpgDpi() {
|
||||
return pdf2JpgDpi;
|
||||
}
|
||||
|
||||
@Value("${pdf2jpg.dpi:105}")
|
||||
public void pdf2JpgDpi(int pdf2JpgDpi) {
|
||||
setPdf2JpgDpiValue(pdf2JpgDpi);
|
||||
}
|
||||
|
||||
public static void setPdf2JpgDpiValue(int pdf2JpgDpi) {
|
||||
ConfigConstants.pdf2JpgDpi = pdf2JpgDpi;
|
||||
}
|
||||
|
||||
public static String getOfficeTypeWeb() {
|
||||
return officeTypeWeb;
|
||||
}
|
||||
|
||||
@Value("${office.type.web:web}")
|
||||
public void setOfficeTypeWeb(String officeTypeWeb) {
|
||||
setOfficeTypeWebValue(officeTypeWeb);
|
||||
}
|
||||
|
||||
public static void setOfficeTypeWebValue(String officeTypeWeb) {
|
||||
ConfigConstants.officeTypeWeb = officeTypeWeb;
|
||||
}
|
||||
|
||||
|
||||
public static Boolean getDeleteSourceFile() {
|
||||
return deleteSourceFile;
|
||||
}
|
||||
|
||||
@Value("${delete.source.file:true}")
|
||||
public void setDeleteSourceFile(Boolean deleteSourceFile) {
|
||||
setDeleteSourceFileValue(deleteSourceFile);
|
||||
}
|
||||
|
||||
public static void setDeleteSourceFileValue(Boolean deleteSourceFile) {
|
||||
ConfigConstants.deleteSourceFile = deleteSourceFile;
|
||||
}
|
||||
|
||||
public static Boolean getDeleteCaptcha() {
|
||||
return deleteCaptcha;
|
||||
}
|
||||
|
||||
@Value("${delete.captcha:false}")
|
||||
public void setDeleteCaptcha(Boolean deleteCaptcha) {
|
||||
setDeleteCaptchaValue(deleteCaptcha);
|
||||
}
|
||||
|
||||
public static void setDeleteCaptchaValue(Boolean deleteCaptcha) {
|
||||
ConfigConstants.deleteCaptcha = deleteCaptcha;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以下为cad转换模块设置
|
||||
*/
|
||||
|
||||
public static String getCadPreviewType() {
|
||||
return cadPreviewType;
|
||||
}
|
||||
|
||||
@Value("${cad.preview.type:svg}")
|
||||
public void setCadPreviewType(String cadPreviewType) {
|
||||
setCadPreviewTypeValue(cadPreviewType);
|
||||
}
|
||||
|
||||
public static void setCadPreviewTypeValue(String cadPreviewType) {
|
||||
ConfigConstants.cadPreviewType = cadPreviewType;
|
||||
}
|
||||
|
||||
|
||||
public static String getCadTimeout() {
|
||||
return cadTimeout;
|
||||
}
|
||||
|
||||
@Value("${cad.timeout:90}")
|
||||
public void setCadTimeout(String cadTimeout) {
|
||||
setCadTimeoutValue(cadTimeout);
|
||||
}
|
||||
|
||||
public static void setCadTimeoutValue(String cadTimeout) {
|
||||
ConfigConstants.cadTimeout = cadTimeout;
|
||||
}
|
||||
|
||||
|
||||
public static int getCadThread() {
|
||||
return cadThread;
|
||||
}
|
||||
|
||||
@Value("${cad.thread:5}")
|
||||
public void setCadThread(int cadThread) {
|
||||
setCadThreadValue(cadThread);
|
||||
}
|
||||
|
||||
public static void setCadThreadValue(int cadThread) {
|
||||
ConfigConstants.cadThread = cadThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以下为OFFICE转换模块设置
|
||||
*/
|
||||
|
||||
public static String getOfficePageRange() {
|
||||
return officePageRange;
|
||||
}
|
||||
|
||||
@Value("${office.pagerange:false}")
|
||||
public void setOfficePageRange(String officePageRange) {
|
||||
setOfficePageRangeValue(officePageRange);
|
||||
}
|
||||
|
||||
public static void setOfficePageRangeValue(String officePageRange) {
|
||||
ConfigConstants.officePageRange = officePageRange;
|
||||
}
|
||||
|
||||
public static String getOfficeWatermark() {
|
||||
return officeWatermark;
|
||||
}
|
||||
|
||||
@Value("${office.watermark:false}")
|
||||
public void setOfficeWatermark(String officeWatermark) {
|
||||
setOfficeWatermarkValue(officeWatermark);
|
||||
}
|
||||
|
||||
public static void setOfficeWatermarkValue(String officeWatermark) {
|
||||
ConfigConstants.officeWatermark = officeWatermark;
|
||||
}
|
||||
|
||||
public static String getOfficeQuality() {
|
||||
return officeQuality;
|
||||
}
|
||||
|
||||
@Value("${office.quality:80}")
|
||||
public void setOfficeQuality(String officeQuality) {
|
||||
setOfficeQualityValue(officeQuality);
|
||||
}
|
||||
|
||||
public static void setOfficeQualityValue(String officeQuality) {
|
||||
ConfigConstants.officeQuality = officeQuality;
|
||||
}
|
||||
|
||||
public static String getOfficeMaxImageResolution() {
|
||||
return officeMaxImageResolution;
|
||||
}
|
||||
|
||||
@Value("${office.maximageresolution:150}")
|
||||
public void setOfficeMaxImageResolution(String officeMaxImageResolution) {
|
||||
setOfficeMaxImageResolutionValue(officeMaxImageResolution);
|
||||
}
|
||||
|
||||
public static void setOfficeMaxImageResolutionValue(String officeMaxImageResolution) {
|
||||
ConfigConstants.officeMaxImageResolution = officeMaxImageResolution;
|
||||
}
|
||||
|
||||
public static Boolean getOfficeExportBookmarks() {
|
||||
return officeExportBookmarks;
|
||||
}
|
||||
|
||||
@Value("${office.exportbookmarks:true}")
|
||||
public void setOfficeExportBookmarks(Boolean officeExportBookmarks) {
|
||||
setOfficeExportBookmarksValue(officeExportBookmarks);
|
||||
}
|
||||
|
||||
public static void setOfficeExportBookmarksValue(Boolean officeExportBookmarks) {
|
||||
ConfigConstants.officeExportBookmarks = officeExportBookmarks;
|
||||
}
|
||||
|
||||
public static Boolean getOfficeExportNotes() {
|
||||
return officeExportNotes;
|
||||
}
|
||||
|
||||
@Value("${office.exportnotes:true}")
|
||||
public void setExportNotes(Boolean officeExportNotes) {
|
||||
setOfficeExportNotesValue(officeExportNotes);
|
||||
}
|
||||
|
||||
public static void setOfficeExportNotesValue(Boolean officeExportNotes) {
|
||||
ConfigConstants.officeExportNotes = officeExportNotes;
|
||||
}
|
||||
|
||||
public static Boolean getOfficeDocumentOpenPasswords() {
|
||||
return officeDocumentOpenPasswords;
|
||||
}
|
||||
|
||||
@Value("${office.documentopenpasswords:true}")
|
||||
public void setDocumentOpenPasswords(Boolean officeDocumentOpenPasswords) {
|
||||
setOfficeDocumentOpenPasswordsValue(officeDocumentOpenPasswords);
|
||||
}
|
||||
|
||||
public static void setOfficeDocumentOpenPasswordsValue(Boolean officeDocumentOpenPasswords) {
|
||||
ConfigConstants.officeDocumentOpenPasswords = officeDocumentOpenPasswords;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以下为首页显示
|
||||
*/
|
||||
|
||||
public static String getBeian() {
|
||||
return beian;
|
||||
}
|
||||
|
||||
@Value("${beian:default}")
|
||||
public void setBeian(String beian) {
|
||||
setBeianValue(beian);
|
||||
}
|
||||
|
||||
public static void setBeianValue(String beian) {
|
||||
ConfigConstants.beian = beian;
|
||||
}
|
||||
|
||||
|
||||
public static String getHomePageNumber() {
|
||||
return homePageNumber;
|
||||
}
|
||||
|
||||
@Value("${home.pagenumber:1}")
|
||||
public void setHomePageNumber(String homePageNumber) {
|
||||
setHomePageNumberValue(homePageNumber);
|
||||
}
|
||||
|
||||
public static void setHomePageNumberValue(String homePageNumber) {
|
||||
ConfigConstants.homePageNumber = homePageNumber;
|
||||
}
|
||||
|
||||
public static String getHomePagination() {
|
||||
return homePagination;
|
||||
}
|
||||
|
||||
@Value("${home.pagination:true}")
|
||||
public void setHomePagination(String homePagination) {
|
||||
setHomePaginationValue(homePagination);
|
||||
}
|
||||
|
||||
public static void setHomePaginationValue(String homePagination) {
|
||||
ConfigConstants.homePagination = homePagination;
|
||||
}
|
||||
|
||||
public static String getHomePageSize() {
|
||||
return homePageSize;
|
||||
}
|
||||
|
||||
@Value("${home.pagesize:15}")
|
||||
public void setHomePageSize(String homePageSize) {
|
||||
setHomePageSizeValue(homePageSize);
|
||||
}
|
||||
|
||||
public static void setHomePageSizeValue(String homePageSize) {
|
||||
ConfigConstants.homePageSize = homePageSize;
|
||||
}
|
||||
|
||||
public static String getHomeSearch() {
|
||||
return homeSearch;
|
||||
}
|
||||
|
||||
@Value("${home.search:1}")
|
||||
public void setHomeSearch(String homeSearch) {
|
||||
setHomeSearchValue(homeSearch);
|
||||
}
|
||||
|
||||
public static void setHomeSearchValue(String homeSearch) {
|
||||
ConfigConstants.homeSearch = homeSearch;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package cn.keking.config;
|
||||
|
||||
import cn.keking.utils.ConfigUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @auther: chenjh
|
||||
* @time: 2019/4/10 16:16
|
||||
* @description 每隔1s读取并更新一次配置文件
|
||||
*/
|
||||
@Component
|
||||
public class ConfigRefreshComponent {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigRefreshComponent.class);
|
||||
|
||||
@PostConstruct
|
||||
void refresh() {
|
||||
Thread configRefreshThread = new Thread(new ConfigRefreshThread());
|
||||
configRefreshThread.start();
|
||||
}
|
||||
|
||||
static class ConfigRefreshThread implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Properties properties = new Properties();
|
||||
String text;
|
||||
String media;
|
||||
boolean cacheEnabled;
|
||||
String[] textArray;
|
||||
String[] mediaArray;
|
||||
String officePreviewType;
|
||||
String officePreviewSwitchDisabled;
|
||||
String ftpUsername;
|
||||
String ftpPassword;
|
||||
String ftpControlEncoding;
|
||||
String configFilePath = ConfigUtils.getCustomizedConfigPath();
|
||||
String baseUrl;
|
||||
String trustHost;
|
||||
String notTrustHost;
|
||||
String pdfPresentationModeDisable;
|
||||
String pdfOpenFileDisable;
|
||||
String pdfPrintDisable;
|
||||
String pdfDownloadDisable;
|
||||
String pdfBookmarkDisable;
|
||||
String pdfDisableEditing;
|
||||
boolean fileUploadDisable;
|
||||
String tifPreviewType;
|
||||
String prohibit;
|
||||
String[] prohibitArray;
|
||||
String beian;
|
||||
String size;
|
||||
String password;
|
||||
int pdf2JpgDpi;
|
||||
String officeTypeWeb;
|
||||
String cadPreviewType;
|
||||
boolean deleteSourceFile;
|
||||
boolean deleteCaptcha;
|
||||
String officPageRange;
|
||||
String officWatermark;
|
||||
String officQuality;
|
||||
String officMaxImageResolution;
|
||||
boolean officExportBookmarks;
|
||||
boolean officeExportNotes;
|
||||
boolean officeDocumentOpenPasswords;
|
||||
String cadTimeout;
|
||||
int cadThread;
|
||||
String homePageNumber;
|
||||
String homePagination;
|
||||
String homePageSize;
|
||||
String homeSearch;
|
||||
while (true) {
|
||||
FileReader fileReader = new FileReader(configFilePath);
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
||||
properties.load(bufferedReader);
|
||||
ConfigUtils.restorePropertiesFromEnvFormat(properties);
|
||||
cacheEnabled = Boolean.parseBoolean(properties.getProperty("cache.enabled", ConfigConstants.DEFAULT_CACHE_ENABLED));
|
||||
text = properties.getProperty("simText", ConfigConstants.DEFAULT_TXT_TYPE);
|
||||
media = properties.getProperty("media", ConfigConstants.DEFAULT_MEDIA_TYPE);
|
||||
officePreviewType = properties.getProperty("office.preview.type", ConfigConstants.DEFAULT_OFFICE_PREVIEW_TYPE);
|
||||
officePreviewSwitchDisabled = properties.getProperty("office.preview.switch.disabled", ConfigConstants.DEFAULT_OFFICE_PREVIEW_SWITCH_DISABLED);
|
||||
ftpUsername = properties.getProperty("ftp.username", ConfigConstants.DEFAULT_FTP_USERNAME);
|
||||
ftpPassword = properties.getProperty("ftp.password", ConfigConstants.DEFAULT_FTP_PASSWORD);
|
||||
ftpControlEncoding = properties.getProperty("ftp.control.encoding", ConfigConstants.DEFAULT_FTP_CONTROL_ENCODING);
|
||||
textArray = text.split(",");
|
||||
mediaArray = media.split(",");
|
||||
baseUrl = properties.getProperty("base.url", ConfigConstants.DEFAULT_VALUE);
|
||||
trustHost = properties.getProperty("trust.host", ConfigConstants.DEFAULT_VALUE);
|
||||
notTrustHost = properties.getProperty("not.trust.host", ConfigConstants.DEFAULT_VALUE);
|
||||
pdfPresentationModeDisable = properties.getProperty("pdf.presentationMode.disable", ConfigConstants.DEFAULT_PDF_PRESENTATION_MODE_DISABLE);
|
||||
pdfOpenFileDisable = properties.getProperty("pdf.openFile.disable", ConfigConstants.DEFAULT_PDF_OPEN_FILE_DISABLE);
|
||||
pdfPrintDisable = properties.getProperty("pdf.print.disable", ConfigConstants.DEFAULT_PDF_PRINT_DISABLE);
|
||||
pdfDownloadDisable = properties.getProperty("pdf.download.disable", ConfigConstants.DEFAULT_PDF_DOWNLOAD_DISABLE);
|
||||
pdfBookmarkDisable = properties.getProperty("pdf.bookmark.disable", ConfigConstants.DEFAULT_PDF_BOOKMARK_DISABLE);
|
||||
pdfDisableEditing = properties.getProperty("pdf.disable.editing", ConfigConstants.DEFAULT_PDF_DISABLE_EDITING);
|
||||
fileUploadDisable = Boolean.parseBoolean(properties.getProperty("file.upload.disable", ConfigConstants.DEFAULT_FILE_UPLOAD_DISABLE));
|
||||
tifPreviewType = properties.getProperty("tif.preview.type", ConfigConstants.DEFAULT_TIF_PREVIEW_TYPE);
|
||||
cadPreviewType = properties.getProperty("cad.preview.type", ConfigConstants.DEFAULT_CAD_PREVIEW_TYPE);
|
||||
size = properties.getProperty("spring.servlet.multipart.max-file-size", ConfigConstants.DEFAULT_SIZE);
|
||||
beian = properties.getProperty("beian", ConfigConstants.DEFAULT_BEIAN);
|
||||
prohibit = properties.getProperty("prohibit", ConfigConstants.DEFAULT_PROHIBIT);
|
||||
password = properties.getProperty("delete.password", ConfigConstants.DEFAULT_PASSWORD);
|
||||
pdf2JpgDpi = Integer.parseInt(properties.getProperty("pdf2jpg.dpi", ConfigConstants.DEFAULT_PDF2_JPG_DPI));
|
||||
officeTypeWeb = properties.getProperty("office.type.web", ConfigConstants.DEFAULT_OFFICE_TYPE_WEB);
|
||||
deleteSourceFile = Boolean.parseBoolean(properties.getProperty("delete.source.file", ConfigConstants.DEFAULT_DELETE_SOURCE_FILE));
|
||||
deleteCaptcha = Boolean.parseBoolean(properties.getProperty("delete.captcha", ConfigConstants.DEFAULT_DELETE_CAPTCHA));
|
||||
officPageRange = properties.getProperty("office.pagerange", ConfigConstants.DEFAULT_OFFICE_PAQERANQE);
|
||||
officWatermark = properties.getProperty("office.watermark", ConfigConstants.DEFAULT_OFFICE_WATERMARK);
|
||||
officQuality = properties.getProperty("office.quality", ConfigConstants.DEFAULT_OFFICE_QUALITY);
|
||||
officMaxImageResolution = properties.getProperty("office.maximageresolution", ConfigConstants.DEFAULT_OFFICE_MAXIMAQERESOLUTION);
|
||||
officExportBookmarks = Boolean.parseBoolean(properties.getProperty("office.exportbookmarks", ConfigConstants.DEFAULT_OFFICE_EXPORTBOOKMARKS));
|
||||
officeExportNotes = Boolean.parseBoolean(properties.getProperty("office.exportnotes", ConfigConstants.DEFAULT_OFFICE_EXPORTNOTES));
|
||||
officeDocumentOpenPasswords = Boolean.parseBoolean(properties.getProperty("office.documentopenpasswords", ConfigConstants.DEFAULT_OFFICE_EOCUMENTOPENPASSWORDS));
|
||||
cadTimeout = properties.getProperty("cad.timeout", ConfigConstants.DEFAULT_CAD_TIMEOUT);
|
||||
homePageNumber = properties.getProperty("home.pagenumber", ConfigConstants.DEFAULT_HOME_PAGENUMBER);
|
||||
homePagination = properties.getProperty("home.pagination", ConfigConstants.DEFAULT_HOME_PAGINATION);
|
||||
homePageSize = properties.getProperty("home.pagesize", ConfigConstants.DEFAULT_HOME_PAGSIZE);
|
||||
homeSearch = properties.getProperty("home.search", ConfigConstants.DEFAULT_HOME_SEARCH);
|
||||
cadThread = Integer.parseInt(properties.getProperty("cad.thread", ConfigConstants.DEFAULT_CAD_THREAD));
|
||||
prohibitArray = prohibit.split(",");
|
||||
|
||||
ConfigConstants.setCacheEnabledValueValue(cacheEnabled);
|
||||
ConfigConstants.setSimTextValue(textArray);
|
||||
ConfigConstants.setMediaValue(mediaArray);
|
||||
ConfigConstants.setOfficePreviewTypeValue(officePreviewType);
|
||||
ConfigConstants.setFtpUsernameValue(ftpUsername);
|
||||
ConfigConstants.setFtpPasswordValue(ftpPassword);
|
||||
ConfigConstants.setFtpControlEncodingValue(ftpControlEncoding);
|
||||
ConfigConstants.setBaseUrlValue(baseUrl);
|
||||
ConfigConstants.setTrustHostValue(trustHost);
|
||||
ConfigConstants.setNotTrustHostValue(notTrustHost);
|
||||
ConfigConstants.setOfficePreviewSwitchDisabledValue(officePreviewSwitchDisabled);
|
||||
ConfigConstants.setPdfPresentationModeDisableValue(pdfPresentationModeDisable);
|
||||
ConfigConstants.setPdfOpenFileDisableValue(pdfOpenFileDisable);
|
||||
ConfigConstants.setPdfPrintDisableValue(pdfPrintDisable);
|
||||
ConfigConstants.setPdfDownloadDisableValue(pdfDownloadDisable);
|
||||
ConfigConstants.setPdfBookmarkDisableValue(pdfBookmarkDisable);
|
||||
ConfigConstants.setPdfDisableEditingValue(pdfDisableEditing);
|
||||
ConfigConstants.setFileUploadDisableValue(fileUploadDisable);
|
||||
ConfigConstants.setTifPreviewTypeValue(tifPreviewType);
|
||||
ConfigConstants.setCadPreviewTypeValue(cadPreviewType);
|
||||
ConfigConstants.setBeianValue(beian);
|
||||
ConfigConstants.setSizeValue(size);
|
||||
ConfigConstants.setProhibitValue(prohibitArray);
|
||||
ConfigConstants.setPasswordValue(password);
|
||||
ConfigConstants.setPdf2JpgDpiValue(pdf2JpgDpi);
|
||||
ConfigConstants.setOfficeTypeWebValue(officeTypeWeb);
|
||||
ConfigConstants.setOfficePageRangeValue(officPageRange);
|
||||
ConfigConstants.setOfficeWatermarkValue(officWatermark);
|
||||
ConfigConstants.setOfficeQualityValue(officQuality);
|
||||
ConfigConstants.setOfficeMaxImageResolutionValue(officMaxImageResolution);
|
||||
ConfigConstants.setOfficeExportBookmarksValue(officExportBookmarks);
|
||||
ConfigConstants.setOfficeExportNotesValue(officeExportNotes);
|
||||
ConfigConstants.setOfficeDocumentOpenPasswordsValue(officeDocumentOpenPasswords);
|
||||
ConfigConstants.setDeleteSourceFileValue(deleteSourceFile);
|
||||
ConfigConstants.setDeleteCaptchaValue(deleteCaptcha);
|
||||
ConfigConstants.setCadTimeoutValue(cadTimeout);
|
||||
ConfigConstants.setCadThreadValue(cadThread);
|
||||
ConfigConstants.setHomePageNumberValue(homePageNumber);
|
||||
ConfigConstants.setHomePaginationValue(homePagination);
|
||||
ConfigConstants.setHomePageSizeValue(homePageSize);
|
||||
ConfigConstants.setHomeSearchValue(homeSearch);
|
||||
setWatermarkConfig(properties);
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
LOGGER.error("读取配置文件异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setWatermarkConfig(Properties properties) {
|
||||
String watermarkTxt = properties.getProperty("watermark.txt", WatermarkConfigConstants.DEFAULT_WATERMARK_TXT);
|
||||
String watermarkXSpace = properties.getProperty("watermark.x.space", WatermarkConfigConstants.DEFAULT_WATERMARK_X_SPACE);
|
||||
String watermarkYSpace = properties.getProperty("watermark.y.space", WatermarkConfigConstants.DEFAULT_WATERMARK_Y_SPACE);
|
||||
String watermarkFont = properties.getProperty("watermark.font", WatermarkConfigConstants.DEFAULT_WATERMARK_FONT);
|
||||
String watermarkFontsize = properties.getProperty("watermark.fontsize", WatermarkConfigConstants.DEFAULT_WATERMARK_FONTSIZE);
|
||||
String watermarkColor = properties.getProperty("watermark.color", WatermarkConfigConstants.DEFAULT_WATERMARK_COLOR);
|
||||
String watermarkAlpha = properties.getProperty("watermark.alpha", WatermarkConfigConstants.DEFAULT_WATERMARK_ALPHA);
|
||||
String watermarkWidth = properties.getProperty("watermark.width", WatermarkConfigConstants.DEFAULT_WATERMARK_WIDTH);
|
||||
String watermarkHeight = properties.getProperty("watermark.height", WatermarkConfigConstants.DEFAULT_WATERMARK_HEIGHT);
|
||||
String watermarkAngle = properties.getProperty("watermark.angle", WatermarkConfigConstants.DEFAULT_WATERMARK_ANGLE);
|
||||
WatermarkConfigConstants.setWatermarkTxtValue(watermarkTxt);
|
||||
WatermarkConfigConstants.setWatermarkXSpaceValue(watermarkXSpace);
|
||||
WatermarkConfigConstants.setWatermarkYSpaceValue(watermarkYSpace);
|
||||
WatermarkConfigConstants.setWatermarkFontValue(watermarkFont);
|
||||
WatermarkConfigConstants.setWatermarkFontsizeValue(watermarkFontsize);
|
||||
WatermarkConfigConstants.setWatermarkColorValue(watermarkColor);
|
||||
WatermarkConfigConstants.setWatermarkAlphaValue(watermarkAlpha);
|
||||
WatermarkConfigConstants.setWatermarkWidthValue(watermarkWidth);
|
||||
WatermarkConfigConstants.setWatermarkHeightValue(watermarkHeight);
|
||||
WatermarkConfigConstants.setWatermarkAngleValue(watermarkAngle);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package cn.keking.config;
|
||||
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.redisson.client.codec.Codec;
|
||||
import org.redisson.config.Config;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Created by kl on 2017/09/26.
|
||||
* redisson 客户端配置
|
||||
*/
|
||||
@ConditionalOnExpression("'${cache.type:default}'.equals('redis')")
|
||||
@ConfigurationProperties(prefix = "spring.redisson")
|
||||
@Configuration
|
||||
public class RedissonConfig {
|
||||
|
||||
private String address;
|
||||
private int connectionMinimumIdleSize = 10;
|
||||
private int idleConnectionTimeout=10000;
|
||||
private int pingTimeout=1000;
|
||||
private int connectTimeout=10000;
|
||||
private int timeout=3000;
|
||||
private int retryAttempts=3;
|
||||
private int retryInterval=1500;
|
||||
private int reconnectionTimeout=3000;
|
||||
private int failedAttempts=3;
|
||||
private String password = null;
|
||||
private int subscriptionsPerConnection=5;
|
||||
private String clientName=null;
|
||||
private int subscriptionConnectionMinimumIdleSize = 1;
|
||||
private int subscriptionConnectionPoolSize = 50;
|
||||
private int connectionPoolSize = 64;
|
||||
private int database = 0;
|
||||
private boolean dnsMonitoring = false;
|
||||
private int dnsMonitoringInterval = 5000;
|
||||
|
||||
private int thread; //当前处理核数量 * 2
|
||||
|
||||
private String codec="org.redisson.codec.JsonJacksonCodec";
|
||||
|
||||
@Bean
|
||||
Config config() throws Exception {
|
||||
Config config = new Config();
|
||||
config.useSingleServer().setAddress(address)
|
||||
.setConnectionMinimumIdleSize(connectionMinimumIdleSize)
|
||||
.setConnectionPoolSize(connectionPoolSize)
|
||||
.setDatabase(database)
|
||||
.setDnsMonitoring(dnsMonitoring)
|
||||
.setDnsMonitoringInterval(dnsMonitoringInterval)
|
||||
.setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize)
|
||||
.setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize)
|
||||
.setSubscriptionsPerConnection(subscriptionsPerConnection)
|
||||
.setClientName(clientName)
|
||||
.setFailedAttempts(failedAttempts)
|
||||
.setRetryAttempts(retryAttempts)
|
||||
.setRetryInterval(retryInterval)
|
||||
.setReconnectionTimeout(reconnectionTimeout)
|
||||
.setTimeout(timeout)
|
||||
.setConnectTimeout(connectTimeout)
|
||||
.setIdleConnectionTimeout(idleConnectionTimeout)
|
||||
.setPingTimeout(pingTimeout)
|
||||
.setPassword(StringUtils.trimToNull(password));
|
||||
Codec codec=(Codec) ClassUtils.forName(getCodec(), ClassUtils.getDefaultClassLoader()).newInstance();
|
||||
config.setCodec(codec);
|
||||
config.setThreads(thread);
|
||||
config.setEventLoopGroup(new NioEventLoopGroup());
|
||||
config.setUseLinuxNativeEpoll(false);
|
||||
return config;
|
||||
}
|
||||
|
||||
public int getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
public void setThread(int thread) {
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public int getIdleConnectionTimeout() {
|
||||
return idleConnectionTimeout;
|
||||
}
|
||||
|
||||
public void setIdleConnectionTimeout(int idleConnectionTimeout) {
|
||||
this.idleConnectionTimeout = idleConnectionTimeout;
|
||||
}
|
||||
|
||||
public int getPingTimeout() {
|
||||
return pingTimeout;
|
||||
}
|
||||
|
||||
public void setPingTimeout(int pingTimeout) {
|
||||
this.pingTimeout = pingTimeout;
|
||||
}
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public int getRetryAttempts() {
|
||||
return retryAttempts;
|
||||
}
|
||||
|
||||
public void setRetryAttempts(int retryAttempts) {
|
||||
this.retryAttempts = retryAttempts;
|
||||
}
|
||||
|
||||
public int getRetryInterval() {
|
||||
return retryInterval;
|
||||
}
|
||||
|
||||
public void setRetryInterval(int retryInterval) {
|
||||
this.retryInterval = retryInterval;
|
||||
}
|
||||
|
||||
public int getReconnectionTimeout() {
|
||||
return reconnectionTimeout;
|
||||
}
|
||||
|
||||
public void setReconnectionTimeout(int reconnectionTimeout) {
|
||||
this.reconnectionTimeout = reconnectionTimeout;
|
||||
}
|
||||
|
||||
public int getFailedAttempts() {
|
||||
return failedAttempts;
|
||||
}
|
||||
|
||||
public void setFailedAttempts(int failedAttempts) {
|
||||
this.failedAttempts = failedAttempts;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public int getSubscriptionsPerConnection() {
|
||||
return subscriptionsPerConnection;
|
||||
}
|
||||
|
||||
public void setSubscriptionsPerConnection(int subscriptionsPerConnection) {
|
||||
this.subscriptionsPerConnection = subscriptionsPerConnection;
|
||||
}
|
||||
|
||||
public String getClientName() {
|
||||
return clientName;
|
||||
}
|
||||
|
||||
public void setClientName(String clientName) {
|
||||
this.clientName = clientName;
|
||||
}
|
||||
|
||||
public int getSubscriptionConnectionMinimumIdleSize() {
|
||||
return subscriptionConnectionMinimumIdleSize;
|
||||
}
|
||||
|
||||
public void setSubscriptionConnectionMinimumIdleSize(int subscriptionConnectionMinimumIdleSize) {
|
||||
this.subscriptionConnectionMinimumIdleSize = subscriptionConnectionMinimumIdleSize;
|
||||
}
|
||||
|
||||
public int getSubscriptionConnectionPoolSize() {
|
||||
return subscriptionConnectionPoolSize;
|
||||
}
|
||||
|
||||
public void setSubscriptionConnectionPoolSize(int subscriptionConnectionPoolSize) {
|
||||
this.subscriptionConnectionPoolSize = subscriptionConnectionPoolSize;
|
||||
}
|
||||
|
||||
public int getConnectionMinimumIdleSize() {
|
||||
return connectionMinimumIdleSize;
|
||||
}
|
||||
|
||||
public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) {
|
||||
this.connectionMinimumIdleSize = connectionMinimumIdleSize;
|
||||
}
|
||||
|
||||
public int getConnectionPoolSize() {
|
||||
return connectionPoolSize;
|
||||
}
|
||||
|
||||
public void setConnectionPoolSize(int connectionPoolSize) {
|
||||
this.connectionPoolSize = connectionPoolSize;
|
||||
}
|
||||
|
||||
public int getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
public void setDatabase(int database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
public boolean isDnsMonitoring() {
|
||||
return dnsMonitoring;
|
||||
}
|
||||
|
||||
public void setDnsMonitoring(boolean dnsMonitoring) {
|
||||
this.dnsMonitoring = dnsMonitoring;
|
||||
}
|
||||
|
||||
public int getDnsMonitoringInterval() {
|
||||
return dnsMonitoringInterval;
|
||||
}
|
||||
|
||||
public void setDnsMonitoringInterval(int dnsMonitoringInterval) {
|
||||
this.dnsMonitoringInterval = dnsMonitoringInterval;
|
||||
}
|
||||
|
||||
public String getCodec() {
|
||||
return codec;
|
||||
}
|
||||
|
||||
public void setCodec(String codec) {
|
||||
this.codec = codec;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package cn.keking.config;
|
||||
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @auther: chenjh
|
||||
* @since: 2019/6/11 7:45
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnExpression("'${cache.clean.enabled:false}'.equals('true')")
|
||||
public class SchedulerCleanConfig {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SchedulerCleanConfig.class);
|
||||
|
||||
private final CacheService cacheService;
|
||||
|
||||
public SchedulerCleanConfig(CacheService cacheService) {
|
||||
this.cacheService = cacheService;
|
||||
}
|
||||
|
||||
private final String fileDir = ConfigConstants.getFileDir();
|
||||
|
||||
//默认每晚3点执行一次
|
||||
@Scheduled(cron = "${cache.clean.cron:0 0 3 * * ?}")
|
||||
public void clean() {
|
||||
logger.info("Cache clean start");
|
||||
cacheService.cleanCache();
|
||||
KkFileUtils.deleteDirectory(fileDir);
|
||||
logger.info("Cache clean end");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package cn.keking.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
/**
|
||||
* @author chenjh
|
||||
* @since 2020/5/13 17:44
|
||||
*/
|
||||
public class WatermarkConfigConstants {
|
||||
|
||||
private static String WATERMARK_TXT;
|
||||
private static String WATERMARK_X_SPACE;
|
||||
private static String WATERMARK_Y_SPACE;
|
||||
private static String WATERMARK_FONT;
|
||||
private static String WATERMARK_FONTSIZE;
|
||||
private static String WATERMARK_COLOR;
|
||||
private static String WATERMARK_ALPHA;
|
||||
private static String WATERMARK_WIDTH;
|
||||
private static String WATERMARK_HEIGHT;
|
||||
private static String WATERMARK_ANGLE;
|
||||
|
||||
public static String DEFAULT_WATERMARK_TXT = "";
|
||||
public static String DEFAULT_WATERMARK_X_SPACE = "10";
|
||||
public static String DEFAULT_WATERMARK_Y_SPACE = "10";
|
||||
public static String DEFAULT_WATERMARK_FONT = "微软雅黑";
|
||||
public static String DEFAULT_WATERMARK_FONTSIZE = "18px";
|
||||
public static String DEFAULT_WATERMARK_COLOR = "black";
|
||||
public static String DEFAULT_WATERMARK_ALPHA = "0.2";
|
||||
public static String DEFAULT_WATERMARK_WIDTH = "240";
|
||||
public static String DEFAULT_WATERMARK_HEIGHT = "80";
|
||||
public static String DEFAULT_WATERMARK_ANGLE = "10";
|
||||
|
||||
public static String getWatermarkTxt() {
|
||||
return WATERMARK_TXT;
|
||||
}
|
||||
|
||||
public static void setWatermarkTxtValue(String watermarkTxt) {
|
||||
WATERMARK_TXT = watermarkTxt;
|
||||
}
|
||||
|
||||
@Value("${watermark.txt:}")
|
||||
public void setWatermarkTxt(String watermarkTxt) {
|
||||
setWatermarkTxtValue(watermarkTxt);
|
||||
}
|
||||
|
||||
public static String getWatermarkXSpace() {
|
||||
return WATERMARK_X_SPACE;
|
||||
}
|
||||
|
||||
public static void setWatermarkXSpaceValue(String watermarkXSpace) {
|
||||
WATERMARK_X_SPACE = watermarkXSpace;
|
||||
}
|
||||
|
||||
@Value("${watermark.x.space:10}")
|
||||
public void setWatermarkXSpace(String watermarkXSpace) {
|
||||
setWatermarkXSpaceValue(watermarkXSpace);
|
||||
}
|
||||
|
||||
public static String getWatermarkYSpace() {
|
||||
return WATERMARK_Y_SPACE;
|
||||
}
|
||||
|
||||
public static void setWatermarkYSpaceValue(String watermarkYSpace) {
|
||||
WATERMARK_Y_SPACE = watermarkYSpace;
|
||||
}
|
||||
|
||||
@Value("${watermark.y.space:10}")
|
||||
public void setWatermarkYSpace(String watermarkYSpace) {
|
||||
setWatermarkYSpaceValue(watermarkYSpace);
|
||||
}
|
||||
|
||||
public static String getWatermarkFont() {
|
||||
return WATERMARK_FONT;
|
||||
}
|
||||
|
||||
public static void setWatermarkFontValue(String watermarkFont) {
|
||||
WATERMARK_FONT = watermarkFont;
|
||||
}
|
||||
|
||||
@Value("${watermark.font:微软雅黑}")
|
||||
public void setWatermarkFont(String watermarkFont) {
|
||||
setWatermarkFontValue(watermarkFont);
|
||||
}
|
||||
|
||||
public static String getWatermarkFontsize() {
|
||||
return WATERMARK_FONTSIZE;
|
||||
}
|
||||
|
||||
public static void setWatermarkFontsizeValue(String watermarkFontsize) {
|
||||
WATERMARK_FONTSIZE = watermarkFontsize;
|
||||
}
|
||||
|
||||
@Value("${watermark.fontsize:18px}")
|
||||
public void setWatermarkFontsize(String watermarkFontsize) {
|
||||
setWatermarkFontsizeValue(watermarkFontsize);
|
||||
}
|
||||
|
||||
public static String getWatermarkColor() {
|
||||
return WATERMARK_COLOR;
|
||||
}
|
||||
|
||||
public static void setWatermarkColorValue(String watermarkColor) {
|
||||
WATERMARK_COLOR = watermarkColor;
|
||||
}
|
||||
|
||||
@Value("${watermark.color:black}")
|
||||
public void setWatermarkColor(String watermarkColor) {
|
||||
setWatermarkColorValue(watermarkColor);
|
||||
}
|
||||
|
||||
public static String getWatermarkAlpha() {
|
||||
return WATERMARK_ALPHA;
|
||||
}
|
||||
|
||||
public static void setWatermarkAlphaValue(String watermarkAlpha) {
|
||||
WATERMARK_ALPHA = watermarkAlpha;
|
||||
}
|
||||
|
||||
@Value("${watermark.alpha:0.2}")
|
||||
public void setWatermarkAlpha(String watermarkAlpha) {
|
||||
setWatermarkAlphaValue(watermarkAlpha);
|
||||
}
|
||||
|
||||
public static String getWatermarkWidth() {
|
||||
return WATERMARK_WIDTH;
|
||||
}
|
||||
|
||||
public static void setWatermarkWidthValue(String watermarkWidth) {
|
||||
WATERMARK_WIDTH = watermarkWidth;
|
||||
}
|
||||
|
||||
@Value("${watermark.width:240}")
|
||||
public void setWatermarkWidth(String watermarkWidth) {
|
||||
WATERMARK_WIDTH = watermarkWidth;
|
||||
}
|
||||
|
||||
public static String getWatermarkHeight() {
|
||||
return WATERMARK_HEIGHT;
|
||||
}
|
||||
|
||||
public static void setWatermarkHeightValue(String watermarkHeight) {
|
||||
WATERMARK_HEIGHT = watermarkHeight;
|
||||
}
|
||||
|
||||
@Value("${watermark.height:80}")
|
||||
public void setWatermarkHeight(String watermarkHeight) {
|
||||
WATERMARK_HEIGHT = watermarkHeight;
|
||||
}
|
||||
|
||||
public static String getWatermarkAngle() {
|
||||
return WATERMARK_ANGLE;
|
||||
}
|
||||
|
||||
public static void setWatermarkAngleValue(String watermarkAngle) {
|
||||
WATERMARK_ANGLE = watermarkAngle;
|
||||
}
|
||||
|
||||
@Value("${watermark.angle:10}")
|
||||
public void setWatermarkAngle(String watermarkAngle) {
|
||||
WATERMARK_ANGLE = watermarkAngle;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package cn.keking.config;
|
||||
|
||||
import cn.keking.web.filter.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author: chenjh
|
||||
* @since: 2019/4/16 20:04
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(WebConfig.class);
|
||||
/**
|
||||
* 访问外部文件配置
|
||||
*/
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
String filePath = ConfigConstants.getFileDir();
|
||||
LOGGER.info("Add resource locations: {}", filePath);
|
||||
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/","file:" + filePath);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<ChinesePathFilter> getChinesePathFilter() {
|
||||
ChinesePathFilter filter = new ChinesePathFilter();
|
||||
FilterRegistrationBean<ChinesePathFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setOrder(10);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TrustHostFilter> getTrustHostFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
filterUri.add("/getCorsFile");
|
||||
TrustHostFilter filter = new TrustHostFilter();
|
||||
FilterRegistrationBean<TrustHostFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TrustDirFilter> getTrustDirFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
filterUri.add("/getCorsFile");
|
||||
TrustDirFilter filter = new TrustDirFilter();
|
||||
FilterRegistrationBean<TrustDirFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<BaseUrlFilter> getBaseUrlFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
BaseUrlFilter filter = new BaseUrlFilter();
|
||||
FilterRegistrationBean<BaseUrlFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
registrationBean.setOrder(20);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<UrlCheckFilter> getUrlCheckFilter() {
|
||||
UrlCheckFilter filter = new UrlCheckFilter();
|
||||
FilterRegistrationBean<UrlCheckFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setOrder(30);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<AttributeSetFilter> getWatermarkConfigFilter() {
|
||||
Set<String> filterUri = new HashSet<>();
|
||||
filterUri.add("/index");
|
||||
filterUri.add("/");
|
||||
filterUri.add("/onlinePreview");
|
||||
filterUri.add("/picturesPreview");
|
||||
AttributeSetFilter filter = new AttributeSetFilter();
|
||||
FilterRegistrationBean<AttributeSetFilter> registrationBean = new FilterRegistrationBean<>();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.setUrlPatterns(filterUri);
|
||||
return registrationBean;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package cn.keking.model;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :
|
||||
*/
|
||||
public class FileAttribute {
|
||||
|
||||
private FileType type;
|
||||
private String suffix;
|
||||
private String name;
|
||||
private String url;
|
||||
private boolean isCompressFile = false;
|
||||
private String compressFileKey;
|
||||
private String filePassword;
|
||||
private boolean usePasswordCache;
|
||||
private String officePreviewType = ConfigConstants.getOfficePreviewType();
|
||||
private String tifPreviewType;
|
||||
private Boolean skipDownLoad = false;
|
||||
private Boolean forceUpdatedCache = false;
|
||||
private String cacheName;
|
||||
private String outFilePath;
|
||||
private String originFilePath;
|
||||
private String cacheListName;
|
||||
private boolean isHtmlView = false;
|
||||
|
||||
/**
|
||||
* 代理请求到文件服务器的认证请求头,格式如下:
|
||||
* {“username”:"test","password":"test"}
|
||||
* 请求文件服务器时,会将 json 直接塞到请求头里
|
||||
*/
|
||||
private String kkProxyAuthorization;
|
||||
|
||||
public FileAttribute() {
|
||||
}
|
||||
|
||||
public FileAttribute(FileType type, String suffix, String name, String url) {
|
||||
this.type = type;
|
||||
this.suffix = suffix;
|
||||
this.name = name;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public FileAttribute(FileType type, String suffix, String name, String url, String officePreviewType) {
|
||||
this.type = type;
|
||||
this.suffix = suffix;
|
||||
this.name = name;
|
||||
this.url = url;
|
||||
this.officePreviewType = officePreviewType;
|
||||
}
|
||||
|
||||
public boolean isCompressFile() {
|
||||
return isCompressFile;
|
||||
}
|
||||
|
||||
public void setCompressFile(boolean compressFile) {
|
||||
isCompressFile = compressFile;
|
||||
}
|
||||
|
||||
public String getFilePassword() {
|
||||
return filePassword;
|
||||
}
|
||||
|
||||
public void setFilePassword(String filePassword) {
|
||||
this.filePassword = filePassword;
|
||||
}
|
||||
|
||||
public boolean getUsePasswordCache() {
|
||||
return usePasswordCache;
|
||||
}
|
||||
|
||||
public void setUsePasswordCache(boolean usePasswordCache) {
|
||||
this.usePasswordCache = usePasswordCache;
|
||||
}
|
||||
|
||||
public String getOfficePreviewType() {
|
||||
return officePreviewType;
|
||||
}
|
||||
|
||||
public void setOfficePreviewType(String officePreviewType) {
|
||||
this.officePreviewType = officePreviewType;
|
||||
}
|
||||
|
||||
public FileType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(FileType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getSuffix() {
|
||||
return suffix;
|
||||
}
|
||||
|
||||
public void setSuffix(String suffix) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public String getCompressFileKey() {
|
||||
return compressFileKey;
|
||||
}
|
||||
|
||||
public void setCompressFileKey(String compressFileKey) {
|
||||
this.compressFileKey = compressFileKey;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getCacheName() {
|
||||
return cacheName;
|
||||
}
|
||||
public String getCacheListName() {
|
||||
return cacheListName;
|
||||
}
|
||||
public String getOutFilePath() {
|
||||
return outFilePath;
|
||||
}
|
||||
public String getOriginFilePath() {
|
||||
return originFilePath;
|
||||
}
|
||||
public boolean isHtmlView() {
|
||||
return isHtmlView;
|
||||
}
|
||||
|
||||
public void setCacheName(String cacheName) {
|
||||
this.cacheName = cacheName;
|
||||
}
|
||||
public void setCacheListName(String cacheListName) {
|
||||
this.cacheListName = cacheListName;
|
||||
}
|
||||
public void setOutFilePath(String outFilePath) {
|
||||
this.outFilePath = outFilePath;
|
||||
}
|
||||
public void setOriginFilePath(String originFilePath) {
|
||||
this.originFilePath = originFilePath;
|
||||
}
|
||||
public void setHtmlView(boolean isHtmlView) {
|
||||
this.isHtmlView = isHtmlView;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Boolean getSkipDownLoad() {
|
||||
return skipDownLoad;
|
||||
}
|
||||
|
||||
public void setSkipDownLoad(Boolean skipDownLoad) {
|
||||
this.skipDownLoad = skipDownLoad;
|
||||
}
|
||||
|
||||
public String getTifPreviewType() {
|
||||
return tifPreviewType;
|
||||
}
|
||||
|
||||
public void setTifPreviewType(String previewType) {
|
||||
this.tifPreviewType = previewType;
|
||||
}
|
||||
public Boolean forceUpdatedCache() {
|
||||
return forceUpdatedCache;
|
||||
}
|
||||
public void setForceUpdatedCache(Boolean forceUpdatedCache) {
|
||||
this.forceUpdatedCache = forceUpdatedCache;
|
||||
}
|
||||
|
||||
public String getKkProxyAuthorization() {
|
||||
return kkProxyAuthorization;
|
||||
}
|
||||
|
||||
public void setKkProxyAuthorization(String kkProxyAuthorization) {
|
||||
this.kkProxyAuthorization = kkProxyAuthorization;
|
||||
}
|
||||
}
|
||||
149
tool-tech-file-view/src/main/java/cn/keking/model/FileType.java
Normal file
149
tool-tech-file-view/src/main/java/cn/keking/model/FileType.java
Normal file
@@ -0,0 +1,149 @@
|
||||
package cn.keking.model;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :文件类型,文本,office,压缩包等等
|
||||
*/
|
||||
public enum FileType {
|
||||
|
||||
PICTURE("pictureFilePreviewImpl"),
|
||||
COMPRESS("compressFilePreviewImpl"),
|
||||
OFFICE("officeFilePreviewImpl"),
|
||||
SIMTEXT("simTextFilePreviewImpl"),
|
||||
PDF("pdfFilePreviewImpl"),
|
||||
CODE("codeFilePreviewImpl"),
|
||||
OTHER("otherFilePreviewImpl"),
|
||||
MEDIA("mediaFilePreviewImpl"),
|
||||
MEDIACONVERT("mediaFilePreviewImpl"),
|
||||
MARKDOWN("markdownFilePreviewImpl"),
|
||||
XML("xmlFilePreviewImpl"),
|
||||
CAD("cadFilePreviewImpl"),
|
||||
TIFF("tiffFilePreviewImpl"),
|
||||
OFD("ofdFilePreviewImpl"),
|
||||
EML("emlFilePreviewImpl"),
|
||||
ONLINE3D("online3DFilePreviewImpl"),
|
||||
XMIND("xmindFilePreviewImpl"),
|
||||
SVG("svgFilePreviewImpl"),
|
||||
EPUB("epubFilePreviewImpl"),
|
||||
BPMN("bpmnFilePreviewImpl"),
|
||||
DCM("dcmFilePreviewImpl"),
|
||||
DRAWIO("drawioFilePreviewImpl");
|
||||
|
||||
private static final String[] OFFICE_TYPES = {"docx", "wps", "doc", "docm", "xls", "xlsx", "csv" ,"xlsm", "ppt", "pptx", "vsd", "rtf", "odt", "wmf", "emf", "dps", "et", "ods", "ots", "tsv", "odp", "otp", "sxi", "ott", "vsdx", "fodt", "fods", "xltx","tga","psd","dotm","ett","xlt","xltm","wpt","dot","xlam","dotx","xla","pages", "eps"};
|
||||
private static final String[] PICTURE_TYPES = {"jpg", "jpeg", "png", "gif", "bmp", "ico", "jfif", "webp"};
|
||||
private static final String[] ARCHIVE_TYPES = {"rar", "zip", "jar", "7-zip", "tar", "gzip", "7z"};
|
||||
private static final String[] ONLINE3D_TYPES = {"obj", "3ds", "stl", "ply", "off", "3dm", "fbx", "dae", "wrl", "3mf", "ifc","glb","o3dv","gltf","stp","bim","fcstd","step","iges","brep"};
|
||||
private static final String[] EML_TYPES = {"eml"};
|
||||
private static final String[] XMIND_TYPES = {"xmind"};
|
||||
private static final String[] EPUB_TYPES = {"epub"};
|
||||
private static final String[] DCM_TYPES = {"dcm"};
|
||||
private static final String[] DRAWIO_TYPES = {"drawio"};
|
||||
private static final String[] XML_TYPES = {"xml","xbrl"};
|
||||
private static final String[] TIFF_TYPES = {"tif", "tiff"};
|
||||
private static final String[] OFD_TYPES = {"ofd"};
|
||||
private static final String[] SVG_TYPES = {"svg"};
|
||||
private static final String[] CAD_TYPES = {"dwg", "dxf", "dwf", "iges", "igs", "dwt", "dng", "ifc", "dwfx", "stl", "cf2", "plt"};
|
||||
private static final String[] SSIM_TEXT_TYPES = ConfigConstants.getSimText();
|
||||
private static final String[] CODES = {"java", "c", "php", "go", "python", "py", "js", "html", "ftl", "css", "lua", "sh", "rb", "yaml", "yml", "json", "h", "cpp", "cs", "aspx", "jsp", "sql"};
|
||||
private static final String[] MEDIA_TYPES = ConfigConstants.getMedia();
|
||||
public static final String[] MEDIA_CONVERT_TYPES = ConfigConstants.getConvertMedias();
|
||||
private static final Map<String, FileType> FILE_TYPE_MAPPER = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (String office : OFFICE_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(office, FileType.OFFICE);
|
||||
}
|
||||
for (String picture : PICTURE_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(picture, FileType.PICTURE);
|
||||
}
|
||||
for (String archive : ARCHIVE_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(archive, FileType.COMPRESS);
|
||||
}
|
||||
for (String text : SSIM_TEXT_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(text, FileType.SIMTEXT);
|
||||
}
|
||||
for (String media : MEDIA_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(media, FileType.MEDIA);
|
||||
}
|
||||
for (String MEDIACONVERT : MEDIA_CONVERT_TYPES) {
|
||||
FILE_TYPE_MAPPER.put( MEDIACONVERT, FileType. MEDIACONVERT);
|
||||
}
|
||||
for (String tif : TIFF_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(tif, FileType.TIFF);
|
||||
}
|
||||
for (String code : CODES) {
|
||||
FILE_TYPE_MAPPER.put(code, FileType.CODE);
|
||||
}
|
||||
for (String ofd : OFD_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(ofd, FileType.OFD);
|
||||
}
|
||||
for (String cad : CAD_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(cad, FileType.CAD);
|
||||
}
|
||||
for (String svg : SVG_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(svg, FileType.SVG);
|
||||
}
|
||||
for (String epub : EPUB_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(epub, FileType.EPUB);
|
||||
}
|
||||
for (String eml : EML_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(eml, FileType.EML);
|
||||
}
|
||||
for (String xmind : XMIND_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(xmind, FileType.XMIND);
|
||||
}
|
||||
for (String online3D : ONLINE3D_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(online3D, FileType.ONLINE3D);
|
||||
}
|
||||
for (String dcm : DCM_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(dcm, FileType.DCM);
|
||||
}
|
||||
for (String drawio : DRAWIO_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(drawio, FileType.DRAWIO);
|
||||
}
|
||||
for (String xml : XML_TYPES) {
|
||||
FILE_TYPE_MAPPER.put(xml, FileType.XML);
|
||||
}
|
||||
FILE_TYPE_MAPPER.put("md", FileType.MARKDOWN);
|
||||
FILE_TYPE_MAPPER.put("pdf", FileType.PDF);
|
||||
FILE_TYPE_MAPPER.put("bpmn", FileType.BPMN);
|
||||
}
|
||||
|
||||
private static FileType to(String fileType) {
|
||||
return FILE_TYPE_MAPPER.getOrDefault(fileType, OTHER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看文件类型(防止参数中存在.点号或者其他特殊字符,所以先抽取文件名,然后再获取文件类型)
|
||||
*
|
||||
* @param url url
|
||||
* @return 文件类型
|
||||
*/
|
||||
public static FileType typeFromUrl(String url) {
|
||||
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
||||
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
|
||||
return typeFromFileName(fileName);
|
||||
}
|
||||
|
||||
public static FileType typeFromFileName(String fileName) {
|
||||
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
String lowerCaseFileType = fileType.toLowerCase();
|
||||
return FileType.to(lowerCaseFileType);
|
||||
}
|
||||
|
||||
private final String instanceName;
|
||||
|
||||
FileType(String instanceName) {
|
||||
this.instanceName = instanceName;
|
||||
}
|
||||
|
||||
public String getInstanceName() {
|
||||
return instanceName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package cn.keking.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 接口返回值结构
|
||||
*
|
||||
* @author yudian-it
|
||||
* @date 2017/11/17
|
||||
*/
|
||||
public class ReturnResponse<T> implements Serializable {
|
||||
private static final long serialVersionUID = 313975329998789878L;
|
||||
|
||||
public static final int SUCCESS_CODE = 0;
|
||||
public static final int FAILURE_CODE = 1;
|
||||
public static final String SUCCESS_MSG = "SUCCESS";
|
||||
public static final String FAILURE_MSG = "FAILURE";
|
||||
|
||||
/**
|
||||
* 返回状态
|
||||
* 0. 成功
|
||||
* 1. 失败
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* 返回状态描述
|
||||
* XXX成功
|
||||
* XXX失败
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
private T content;
|
||||
|
||||
public ReturnResponse(int code, String msg, T content) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public static ReturnResponse<Object> failure(String errMsg) {
|
||||
return new ReturnResponse<>(FAILURE_CODE, errMsg, null);
|
||||
}
|
||||
|
||||
public static ReturnResponse<Object> failure() {
|
||||
return failure(FAILURE_MSG);
|
||||
}
|
||||
|
||||
public static ReturnResponse<Object> success(){
|
||||
return success(null);
|
||||
}
|
||||
|
||||
public static ReturnResponse<Object> success(Object content) {
|
||||
return new ReturnResponse<>(SUCCESS_CODE, SUCCESS_MSG, content);
|
||||
}
|
||||
|
||||
public boolean isSuccess(){
|
||||
return SUCCESS_CODE == code;
|
||||
}
|
||||
|
||||
public boolean isFailure(){
|
||||
return !isSuccess();
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public T getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(T content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.utils.RarUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import net.sf.sevenzipjbinding.ExtractOperationResult;
|
||||
import net.sf.sevenzipjbinding.IInArchive;
|
||||
import net.sf.sevenzipjbinding.SevenZip;
|
||||
import net.sf.sevenzipjbinding.SevenZipException;
|
||||
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
|
||||
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
|
||||
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
* create 2017/11/27
|
||||
*/
|
||||
@Component
|
||||
public class CompressFileReader {
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private static final String fileDir = ConfigConstants.getFileDir();
|
||||
|
||||
public CompressFileReader(FileHandlerService fileHandlerService) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
}
|
||||
|
||||
public String unRar(String filePath, String filePassword, String fileName, FileAttribute fileAttribute) throws Exception {
|
||||
List<String> imgUrls = new ArrayList<>();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
String packagePath = "_"; //防止文件名重复 压缩包统一生成文件添加_符号
|
||||
String folderName = filePath.replace(fileDir, ""); //修复压缩包 多重目录获取路径错误
|
||||
if (fileAttribute.isCompressFile()) { //压缩包文件 直接赋予路径 不予下载
|
||||
folderName = "_decompression" + folderName; //重新修改多重压缩包 生成文件路径
|
||||
}
|
||||
RandomAccessFile randomAccessFile = null;
|
||||
IInArchive inArchive = null;
|
||||
try {
|
||||
randomAccessFile = new RandomAccessFile(filePath, "r");
|
||||
inArchive = SevenZip.openInArchive(null, new RandomAccessFileInStream(randomAccessFile));
|
||||
ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();
|
||||
final String[] str = {null};
|
||||
for (final ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {
|
||||
if (!item.isFolder()) {
|
||||
ExtractOperationResult result;
|
||||
String finalFolderName = folderName;
|
||||
result = item.extractSlow(data -> {
|
||||
try {
|
||||
str[0] = RarUtils.getUtf8String(item.getPath());
|
||||
if (RarUtils.isMessyCode(str[0])) {
|
||||
str[0] = new String(item.getPath().getBytes(StandardCharsets.ISO_8859_1), "gbk");
|
||||
}
|
||||
str[0] = str[0].replace("\\", File.separator); //Linux 下路径错误
|
||||
String str1 = str[0].substring(0, str[0].lastIndexOf(File.separator) + 1);
|
||||
File file = new File(fileDir, finalFolderName + packagePath + File.separator + str1);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
OutputStream out = new FileOutputStream(fileDir + finalFolderName + packagePath + File.separator + str[0], true);
|
||||
IOUtils.write(data, out);
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Integer.parseInt(null);
|
||||
}
|
||||
return data.length;
|
||||
}, filePassword);
|
||||
if (result == ExtractOperationResult.OK) {
|
||||
FileType type = FileType.typeFromUrl(str[0]);
|
||||
if (type.equals(FileType.PICTURE)) {
|
||||
imgUrls.add(baseUrl + folderName + packagePath + "/" + str[0].replace("\\", "/"));
|
||||
}
|
||||
fileHandlerService.putImgCache(fileName + packagePath, imgUrls);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return folderName + packagePath;
|
||||
} catch (Exception e) {
|
||||
throw new Exception(e);
|
||||
} finally {
|
||||
if (inArchive != null) {
|
||||
try {
|
||||
inArchive.close();
|
||||
} catch (SevenZipException e) {
|
||||
System.err.println("Error closing archive: " + e);
|
||||
}
|
||||
}
|
||||
if (randomAccessFile != null) {
|
||||
try {
|
||||
randomAccessFile.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error closing file: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/19.
|
||||
* Content :消费队列中的转换文件
|
||||
*/
|
||||
@Service
|
||||
public class FileConvertQueueTask {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final FilePreviewFactory previewFactory;
|
||||
private final CacheService cacheService;
|
||||
private final FileHandlerService fileHandlerService;
|
||||
|
||||
public FileConvertQueueTask(FilePreviewFactory previewFactory, CacheService cacheService, FileHandlerService fileHandlerService) {
|
||||
this.previewFactory = previewFactory;
|
||||
this.cacheService = cacheService;
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void startTask() {
|
||||
new Thread(new ConvertTask(previewFactory, cacheService, fileHandlerService))
|
||||
.start();
|
||||
logger.info("队列处理文件转换任务启动完成 ");
|
||||
}
|
||||
|
||||
static class ConvertTask implements Runnable {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ConvertTask.class);
|
||||
private final FilePreviewFactory previewFactory;
|
||||
private final CacheService cacheService;
|
||||
private final FileHandlerService fileHandlerService;
|
||||
|
||||
public ConvertTask(FilePreviewFactory previewFactory,
|
||||
CacheService cacheService,
|
||||
FileHandlerService fileHandlerService) {
|
||||
this.previewFactory = previewFactory;
|
||||
this.cacheService = cacheService;
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
String url = null;
|
||||
try {
|
||||
url = cacheService.takeQueueTask();
|
||||
if (url != null) {
|
||||
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(url, null);
|
||||
FileType fileType = fileAttribute.getType();
|
||||
logger.info("正在处理预览转换任务,url:{},预览类型:{}", url, fileType);
|
||||
if (isNeedConvert(fileType)) {
|
||||
FilePreview filePreview = previewFactory.get(fileAttribute);
|
||||
filePreview.filePreviewHandle(url, new ExtendedModelMap(), fileAttribute);
|
||||
} else {
|
||||
logger.info("预览类型无需处理,url:{},预览类型:{}", url, fileType);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
} catch (Exception ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
ex.printStackTrace();
|
||||
}
|
||||
logger.info("处理预览转换任务异常,url:{}", url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNeedConvert(FileType fileType) {
|
||||
return fileType.equals(FileType.COMPRESS) || fileType.equals(FileType.OFFICE) || fileType.equals(FileType.CAD);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,589 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.service.cache.NotResourceCache;
|
||||
import cn.keking.utils.EncodingDetects;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.utils.UrlEncoderUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import com.aspose.cad.*;
|
||||
import com.aspose.cad.fileformats.cad.CadDrawTypeMode;
|
||||
import com.aspose.cad.fileformats.tiff.enums.TiffExpectedFormat;
|
||||
import com.aspose.cad.imageoptions.*;
|
||||
import com.itextpdf.text.pdf.PdfReader;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.ImageType;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
import org.apache.pdfbox.tools.imageio.ImageIOUtil;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
* @date 2017/11/13
|
||||
*/
|
||||
@Component
|
||||
@DependsOn(ConfigConstants.BEAN_NAME)
|
||||
public class FileHandlerService implements InitializingBean {
|
||||
|
||||
private static final String PDF2JPG_IMAGE_FORMAT = ".jpg";
|
||||
private static final String PDF_PASSWORD_MSG = "password";
|
||||
private final Logger logger = LoggerFactory.getLogger(FileHandlerService.class);
|
||||
private final String fileDir = ConfigConstants.getFileDir();
|
||||
private final CacheService cacheService;
|
||||
@Value("${server.tomcat.uri-encoding:UTF-8}")
|
||||
private String uriEncoding;
|
||||
|
||||
public FileHandlerService(CacheService cacheService) {
|
||||
this.cacheService = cacheService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 已转换过的文件集合(缓存)
|
||||
*/
|
||||
public Map<String, String> listConvertedFiles() {
|
||||
return cacheService.getPDFCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 已转换过的文件,根据文件名获取
|
||||
*/
|
||||
public String getConvertedFile(String key) {
|
||||
return cacheService.getPDFCache(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key pdf本地路径
|
||||
* @return 已将pdf转换成图片的图片本地相对路径
|
||||
*/
|
||||
public Integer getPdf2jpgCache(String key) {
|
||||
return cacheService.getPdfImageCache(key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从路径中获取文件负
|
||||
*
|
||||
* @param path 类似这种:C:\Users\yudian-it\Downloads
|
||||
* @return 文件名
|
||||
*/
|
||||
public String getFileNameFromPath(String path) {
|
||||
return path.substring(path.lastIndexOf(File.separator) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相对路径
|
||||
*
|
||||
* @param absolutePath 绝对路径
|
||||
* @return 相对路径
|
||||
*/
|
||||
public String getRelativePath(String absolutePath) {
|
||||
return absolutePath.substring(fileDir.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加转换后PDF缓存
|
||||
*
|
||||
* @param fileName pdf文件名
|
||||
* @param value 缓存相对路径
|
||||
*/
|
||||
public void addConvertedFile(String fileName, String value) {
|
||||
cacheService.putPDFCache(fileName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加转换后图片组缓存
|
||||
*
|
||||
* @param pdfFilePath pdf文件绝对路径
|
||||
* @param num 图片张数
|
||||
*/
|
||||
public void addPdf2jpgCache(String pdfFilePath, int num) {
|
||||
cacheService.putPdfImageCache(pdfFilePath, num);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取redis中压缩包内图片文件
|
||||
*
|
||||
* @param compressFileKey compressFileKey
|
||||
* @return 图片文件访问url列表
|
||||
*/
|
||||
public List<String> getImgCache(String compressFileKey) {
|
||||
return cacheService.getImgCache(compressFileKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置redis中压缩包内图片文件
|
||||
*
|
||||
* @param fileKey fileKey
|
||||
* @param imgs 图片文件访问url列表
|
||||
*/
|
||||
public void putImgCache(String fileKey, List<String> imgs) {
|
||||
cacheService.putImgCache(fileKey, imgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* cad定义线程池
|
||||
*/
|
||||
private ExecutorService pool = null;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
pool = Executors.newFixedThreadPool(ConfigConstants.getCadThread());
|
||||
}
|
||||
|
||||
/**
|
||||
* 对转换后的文件进行操作(改变编码方式)
|
||||
*
|
||||
* @param outFilePath 文件绝对路径
|
||||
*/
|
||||
public void doActionConvertedFile(String outFilePath) {
|
||||
String charset = EncodingDetects.getJavaEncode(outFilePath);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try (InputStream inputStream = new FileInputStream(outFilePath); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charset))) {
|
||||
String line;
|
||||
while (null != (line = reader.readLine())) {
|
||||
if (line.contains("charset=gb2312")) {
|
||||
line = line.replace("charset=gb2312", "charset=utf-8");
|
||||
}
|
||||
sb.append(line);
|
||||
}
|
||||
// 添加sheet控制头
|
||||
sb.append("<script src=\"js/jquery-3.6.1.min.js\" type=\"text/javascript\"></script>");
|
||||
sb.append("<script src=\"excel/excel.header.js\" type=\"text/javascript\"></script>");
|
||||
sb.append("<link rel=\"stylesheet\" href=\"excel/excel.css\">");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 重新写入文件
|
||||
try (FileOutputStream fos = new FileOutputStream(outFilePath); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8))) {
|
||||
writer.write(sb.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地 pdf 转 image 后的 web 访问地址
|
||||
*
|
||||
* @param pdfFilePath pdf文件名
|
||||
* @param index 图片索引
|
||||
* @return 图片访问地址
|
||||
*/
|
||||
private String getPdf2jpgUrl(String pdfFilePath, int index) {
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
pdfFilePath = pdfFilePath.replace(fileDir, "");
|
||||
String pdfFolder = pdfFilePath.substring(0, pdfFilePath.length() - 4);
|
||||
String urlPrefix;
|
||||
try {
|
||||
urlPrefix = baseUrl + URLEncoder.encode(pdfFolder, uriEncoding).replaceAll("\\+", "%20");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.error("UnsupportedEncodingException", e);
|
||||
urlPrefix = baseUrl + pdfFolder;
|
||||
}
|
||||
return urlPrefix + "/" + index + PDF2JPG_IMAGE_FORMAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存中的 pdf 转换成 jpg 图片集
|
||||
*
|
||||
* @param pdfFilePath pdf文件路径
|
||||
* @return 图片访问集合
|
||||
*/
|
||||
private List<String> loadPdf2jpgCache(String pdfFilePath) {
|
||||
List<String> imageUrls = new ArrayList<>();
|
||||
Integer imageCount = this.getPdf2jpgCache(pdfFilePath);
|
||||
if (Objects.isNull(imageCount)) {
|
||||
return imageUrls;
|
||||
}
|
||||
IntStream.range(0, imageCount).forEach(i -> {
|
||||
String imageUrl = this.getPdf2jpgUrl(pdfFilePath, i);
|
||||
imageUrls.add(imageUrl);
|
||||
});
|
||||
return imageUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* pdf文件转换成jpg图片集
|
||||
* fileNameFilePath pdf文件路径
|
||||
* pdfFilePath pdf输出文件路径
|
||||
* pdfName pdf文件名称
|
||||
* loadPdf2jpgCache 图片访问集合
|
||||
*/
|
||||
public List<String> pdf2jpg(String fileNameFilePath, String pdfFilePath, String pdfName, FileAttribute fileAttribute) throws Exception {
|
||||
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
|
||||
boolean usePasswordCache = fileAttribute.getUsePasswordCache();
|
||||
String filePassword = fileAttribute.getFilePassword();
|
||||
String pdfPassword = null;
|
||||
PDDocument doc = null;
|
||||
PdfReader pdfReader = null;
|
||||
if (!forceUpdatedCache) {
|
||||
List<String> cacheResult = this.loadPdf2jpgCache(pdfFilePath);
|
||||
if (!CollectionUtils.isEmpty(cacheResult)) {
|
||||
return cacheResult;
|
||||
}
|
||||
}
|
||||
List<String> imageUrls = new ArrayList<>();
|
||||
try {
|
||||
File pdfFile = new File(fileNameFilePath);
|
||||
if (!pdfFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
doc = PDDocument.load(pdfFile, filePassword);
|
||||
doc.setResourceCache(new NotResourceCache());
|
||||
int pageCount = doc.getNumberOfPages();
|
||||
PDFRenderer pdfRenderer = new PDFRenderer(doc);
|
||||
int index = pdfFilePath.lastIndexOf(".");
|
||||
String folder = pdfFilePath.substring(0, index);
|
||||
File path = new File(folder);
|
||||
if (!path.exists() && !path.mkdirs()) {
|
||||
logger.error("创建转换文件【{}】目录失败,请检查目录权限!", folder);
|
||||
}
|
||||
String imageFilePath;
|
||||
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
|
||||
imageFilePath = folder + File.separator + pageIndex + PDF2JPG_IMAGE_FORMAT;
|
||||
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, ConfigConstants.getPdf2JpgDpi(), ImageType.RGB);
|
||||
ImageIOUtil.writeImage(image, imageFilePath, ConfigConstants.getPdf2JpgDpi());
|
||||
String imageUrl = this.getPdf2jpgUrl(pdfFilePath, pageIndex);
|
||||
imageUrls.add(imageUrl);
|
||||
}
|
||||
try {
|
||||
if (!ObjectUtils.isEmpty(filePassword)) { //获取到密码 判断是否是加密文件
|
||||
pdfReader = new PdfReader(fileNameFilePath); //读取PDF文件 通过异常获取该文件是否有密码字符
|
||||
}
|
||||
} catch (Exception e) { //获取异常方法 判断是否有加密字符串
|
||||
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
||||
for (Throwable throwable : throwableArray) {
|
||||
if (throwable instanceof IOException || throwable instanceof EncryptedDocumentException) {
|
||||
if (e.getMessage().toLowerCase().contains(PDF_PASSWORD_MSG)) {
|
||||
pdfPassword = PDF_PASSWORD_MSG; //查询到该文件是密码文件 输出带密码的值
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!PDF_PASSWORD_MSG.equals(pdfPassword)) { //该文件异常 错误原因非密码原因输出错误
|
||||
logger.error("Convert pdf exception, pdfFilePath:{}", pdfFilePath, e);
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (pdfReader != null) { //关闭
|
||||
pdfReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (usePasswordCache || !PDF_PASSWORD_MSG.equals(pdfPassword)) { //加密文件 判断是否启用缓存命令
|
||||
this.addPdf2jpgCache(pdfFilePath, pageCount);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (!e.getMessage().contains(PDF_PASSWORD_MSG)) {
|
||||
logger.error("Convert pdf to jpg exception, pdfFilePath:{}", pdfFilePath, e);
|
||||
}
|
||||
throw new Exception(e);
|
||||
} finally {
|
||||
if (doc != null) { //关闭
|
||||
doc.close();
|
||||
}
|
||||
}
|
||||
return imageUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* cad文件转pdf
|
||||
*
|
||||
* @param inputFilePath cad文件路径
|
||||
* @param outputFilePath pdf输出文件路径
|
||||
* @return 转换是否成功
|
||||
*/
|
||||
public String cadToPdf(String inputFilePath, String outputFilePath, String cadPreviewType, FileAttribute fileAttribute) throws Exception {
|
||||
final InterruptionTokenSource source = new InterruptionTokenSource();//CAD延时
|
||||
final SvgOptions SvgOptions = new SvgOptions();
|
||||
final PdfOptions pdfOptions = new PdfOptions();
|
||||
final TiffOptions TiffOptions = new TiffOptions(TiffExpectedFormat.TiffJpegRgb);
|
||||
if (fileAttribute.isCompressFile()) { //判断 是压缩包的创建新的目录
|
||||
int index = outputFilePath.lastIndexOf("/"); //截取最后一个斜杠的前面的内容
|
||||
String folder = outputFilePath.substring(0, index);
|
||||
File path = new File(folder);
|
||||
//目录不存在 创建新的目录
|
||||
if (!path.exists()) {
|
||||
path.mkdirs();
|
||||
}
|
||||
}
|
||||
File outputFile = new File(outputFilePath);
|
||||
try {
|
||||
LoadOptions opts = new LoadOptions();
|
||||
opts.setSpecifiedEncoding(CodePages.SimpChinese);
|
||||
final Image cadImage = Image.load(inputFilePath, opts);
|
||||
try {
|
||||
RasterizationQuality rasterizationQuality = new RasterizationQuality();
|
||||
rasterizationQuality.setArc(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setHatch(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setText(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setOle(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setObjectsPrecision(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setTextThicknessNormalization(true);
|
||||
CadRasterizationOptions cadRasterizationOptions = new CadRasterizationOptions();
|
||||
cadRasterizationOptions.setBackgroundColor(Color.getWhite());
|
||||
cadRasterizationOptions.setPageWidth(cadImage.getWidth());
|
||||
cadRasterizationOptions.setPageHeight(cadImage.getHeight());
|
||||
cadRasterizationOptions.setUnitType(cadImage.getUnitType());
|
||||
cadRasterizationOptions.setAutomaticLayoutsScaling(false);
|
||||
cadRasterizationOptions.setNoScaling(false);
|
||||
cadRasterizationOptions.setQuality(rasterizationQuality);
|
||||
cadRasterizationOptions.setDrawType(CadDrawTypeMode.UseObjectColor);
|
||||
cadRasterizationOptions.setExportAllLayoutContent(true);
|
||||
cadRasterizationOptions.setVisibilityMode(VisibilityMode.AsScreen);
|
||||
switch (cadPreviewType) { //新增格式方法
|
||||
case "svg":
|
||||
SvgOptions.setVectorRasterizationOptions(cadRasterizationOptions);
|
||||
SvgOptions.setInterruptionToken(source.getToken());
|
||||
break;
|
||||
case "pdf":
|
||||
pdfOptions.setVectorRasterizationOptions(cadRasterizationOptions);
|
||||
pdfOptions.setInterruptionToken(source.getToken());
|
||||
break;
|
||||
case "tif":
|
||||
TiffOptions.setVectorRasterizationOptions(cadRasterizationOptions);
|
||||
TiffOptions.setInterruptionToken(source.getToken());
|
||||
break;
|
||||
}
|
||||
Callable<String> call = () -> {
|
||||
try (OutputStream stream = new FileOutputStream(outputFile)) {
|
||||
switch (cadPreviewType) {
|
||||
case "svg":
|
||||
cadImage.save(stream, SvgOptions);
|
||||
break;
|
||||
case "pdf":
|
||||
cadImage.save(stream, pdfOptions);
|
||||
break;
|
||||
case "tif":
|
||||
cadImage.save(stream, TiffOptions);
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("CADFileNotFoundException,inputFilePath:{}", inputFilePath, e);
|
||||
return null;
|
||||
} finally {
|
||||
cadImage.dispose();
|
||||
source.interrupt(); //结束任务
|
||||
source.dispose();
|
||||
}
|
||||
return "true";
|
||||
};
|
||||
Future<String> result = pool.submit(call);
|
||||
try {
|
||||
result.get(Long.parseLong(ConfigConstants.getCadTimeout()), TimeUnit.SECONDS);
|
||||
// 如果在超时时间内,没有数据返回:则抛出TimeoutException异常
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("CAD转换文件异常:", e);
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
logger.error("CAD转换在尝试取得任务结果时出错:", e);
|
||||
return null;
|
||||
} catch (TimeoutException e) {
|
||||
logger.error("CAD转换时间超时:", e);
|
||||
return null;
|
||||
} finally {
|
||||
source.interrupt(); //结束任务
|
||||
source.dispose();
|
||||
cadImage.dispose();
|
||||
// pool.shutdownNow();
|
||||
}
|
||||
} finally {
|
||||
source.dispose();
|
||||
cadImage.dispose();
|
||||
}
|
||||
} finally {
|
||||
source.dispose();
|
||||
}
|
||||
return "true";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str 原字符串(待截取原串)
|
||||
* @param posStr 指定字符串
|
||||
* @return 截取截取指定字符串之后的数据
|
||||
*/
|
||||
public static String getSubString(String str, String posStr) {
|
||||
return str.substring(str.indexOf(posStr) + posStr.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件属性
|
||||
*
|
||||
* @param url url
|
||||
* @return 文件属性
|
||||
*/
|
||||
public FileAttribute getFileAttribute(String url, HttpServletRequest req) {
|
||||
FileAttribute attribute = new FileAttribute();
|
||||
String suffix;
|
||||
FileType type;
|
||||
String originFileName; //原始文件名
|
||||
String outFilePath; //生成文件的路径
|
||||
String originFilePath; //原始文件路径
|
||||
String fullFileName = WebUtils.getUrlParameterReg(url, "fullfilename");
|
||||
String compressFileKey = WebUtils.getUrlParameterReg(url, "kkCompressfileKey"); //压缩包获取文件名
|
||||
String compressFilePath = WebUtils.getUrlParameterReg(url, "kkCompressfilepath"); //压缩包获取文件路径
|
||||
if (StringUtils.hasText(fullFileName)) {
|
||||
originFileName = fullFileName;
|
||||
type = FileType.typeFromFileName(fullFileName);
|
||||
suffix = KkFileUtils.suffixFromFileName(fullFileName);
|
||||
// 移除fullfilename参数
|
||||
url = WebUtils.clearFullfilenameParam(url);
|
||||
} else {
|
||||
originFileName = WebUtils.getFileNameFromURL(url);
|
||||
type = FileType.typeFromUrl(url);
|
||||
suffix = WebUtils.suffixFromUrl(url);
|
||||
}
|
||||
boolean isCompressFile = !ObjectUtils.isEmpty(compressFileKey);
|
||||
if (isCompressFile) { //判断是否使用特定压缩包符号
|
||||
try {
|
||||
// http://127.0.0.1:8012/各类型文件1 - 副本.zip_/各类型文件/正常预览/PPT转的PDF.pdf?kkCompressfileKey=各类型文件1 - 副本.zip_
|
||||
// http://127.0.0.1:8012/preview/各类型文件1 - 副本.zip_/各类型文件/正常预览/PPT转的PDF.pdf?kkCompressfileKey=各类型文件1 - 副本.zip_ 获取路径就会错误 需要下面的方法
|
||||
String urlStrr = getSubString(compressFilePath, compressFileKey); //反代情况下添加前缀,只获取有压缩包字符的路径
|
||||
originFileName = compressFileKey + urlStrr.trim(); //拼接完整路径
|
||||
originFileName = URLDecoder.decode(originFileName, uriEncoding); //压缩包文件中文编码问题
|
||||
attribute.setSkipDownLoad(true);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (UrlEncoderUtils.hasUrlEncoded(originFileName)) { //判断文件名是否转义
|
||||
try {
|
||||
originFileName = URLDecoder.decode(originFileName, uriEncoding); //转义的文件名 解下出原始文件名
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}else {
|
||||
url = WebUtils.encodeUrlFileName(url); //对未转义的url进行转义
|
||||
}
|
||||
originFileName = KkFileUtils.htmlEscape(originFileName); //文件名处理
|
||||
boolean isHtmlView = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx") || suffix.equalsIgnoreCase("csv") || suffix.equalsIgnoreCase("xlsm") || suffix.equalsIgnoreCase("xlt") || suffix.equalsIgnoreCase("xltm") || suffix.equalsIgnoreCase("et") || suffix.equalsIgnoreCase("ett") || suffix.equalsIgnoreCase("xlam");
|
||||
String cacheFilePrefixName = null;
|
||||
try {
|
||||
cacheFilePrefixName = originFileName.substring(0, originFileName.lastIndexOf(".")) + suffix + "."; //这里统一文件名处理 下面更具类型 各自添加后缀
|
||||
} catch (Exception e) {
|
||||
logger.error("获取文件名后缀错误:", e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
String cacheFileName = this.getCacheFileName(type, originFileName, cacheFilePrefixName, isHtmlView, isCompressFile);
|
||||
outFilePath = fileDir + cacheFileName;
|
||||
originFilePath = fileDir + originFileName;
|
||||
String cacheListName = cacheFilePrefixName + "ListName"; //文件列表缓存文件名
|
||||
attribute.setType(type);
|
||||
attribute.setName(originFileName);
|
||||
attribute.setCacheName(cacheFileName);
|
||||
attribute.setCacheListName(cacheListName);
|
||||
attribute.setHtmlView(isHtmlView);
|
||||
attribute.setOutFilePath(outFilePath);
|
||||
attribute.setOriginFilePath(originFilePath);
|
||||
attribute.setSuffix(suffix);
|
||||
attribute.setUrl(url);
|
||||
if (req != null) {
|
||||
String officePreviewType = req.getParameter("officePreviewType");
|
||||
String forceUpdatedCache = req.getParameter("forceUpdatedCache");
|
||||
String usePasswordCache = req.getParameter("usePasswordCache");
|
||||
if (StringUtils.hasText(officePreviewType)) {
|
||||
attribute.setOfficePreviewType(officePreviewType);
|
||||
}
|
||||
if (StringUtils.hasText(compressFileKey)) {
|
||||
attribute.setCompressFile(isCompressFile);
|
||||
attribute.setCompressFileKey(compressFileKey);
|
||||
}
|
||||
if ("true".equalsIgnoreCase(forceUpdatedCache)) {
|
||||
attribute.setForceUpdatedCache(true);
|
||||
}
|
||||
|
||||
String tifPreviewType = req.getParameter("tifPreviewType");
|
||||
if (StringUtils.hasText(tifPreviewType)) {
|
||||
attribute.setTifPreviewType(tifPreviewType);
|
||||
}
|
||||
|
||||
String filePassword = req.getParameter("filePassword");
|
||||
if (StringUtils.hasText(filePassword)) {
|
||||
attribute.setFilePassword(filePassword);
|
||||
}
|
||||
if ("true".equalsIgnoreCase(usePasswordCache)) {
|
||||
attribute.setUsePasswordCache(true);
|
||||
}
|
||||
String kkProxyAuthorization = req.getHeader("kk-proxy-authorization");
|
||||
attribute.setKkProxyAuthorization(kkProxyAuthorization);
|
||||
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的文件名
|
||||
*
|
||||
* @return 文件名
|
||||
*/
|
||||
private String getCacheFileName(FileType type, String originFileName, String cacheFilePrefixName, boolean isHtmlView, boolean isCompressFile) {
|
||||
String cacheFileName;
|
||||
if (type.equals(FileType.OFFICE)) {
|
||||
cacheFileName = cacheFilePrefixName + (isHtmlView ? "html" : "pdf"); //生成文件添加类型后缀 防止同名文件
|
||||
} else if (type.equals(FileType.PDF)) {
|
||||
cacheFileName = originFileName;
|
||||
} else if (type.equals(FileType.MEDIACONVERT)) {
|
||||
cacheFileName = cacheFilePrefixName + "mp4";
|
||||
} else if (type.equals(FileType.CAD)) {
|
||||
String cadPreviewType = ConfigConstants.getCadPreviewType();
|
||||
cacheFileName = cacheFilePrefixName + cadPreviewType; //生成文件添加类型后缀 防止同名文件
|
||||
} else if (type.equals(FileType.COMPRESS)) {
|
||||
cacheFileName = originFileName;
|
||||
} else if (type.equals(FileType.TIFF)) {
|
||||
cacheFileName = cacheFilePrefixName + ConfigConstants.getTifPreviewType();
|
||||
} else {
|
||||
cacheFileName = originFileName;
|
||||
}
|
||||
if (isCompressFile) { //判断是否使用特定压缩包符号
|
||||
cacheFileName = "_decompression" + cacheFileName;
|
||||
}
|
||||
return cacheFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 已转换过的视频文件集合(缓存)
|
||||
*/
|
||||
public Map<String, String> listConvertedMedias() {
|
||||
return cacheService.getMediaConvertCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加转换后的视频文件缓存
|
||||
*
|
||||
* @param fileName
|
||||
* @param value
|
||||
*/
|
||||
public void addConvertedMedias(String fileName, String value) {
|
||||
cacheService.putMediaConvertCache(fileName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 已转换视频文件缓存,根据文件名获取
|
||||
*/
|
||||
public String getConvertedMedias(String key) {
|
||||
return cacheService.getMediaConvertCache(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :
|
||||
*/
|
||||
public interface FilePreview {
|
||||
|
||||
String PDF_FILE_PREVIEW_PAGE = "pdf";
|
||||
String PPT_FILE_PREVIEW_PAGE = "ppt";
|
||||
String COMPRESS_FILE_PREVIEW_PAGE = "compress";
|
||||
String MEDIA_FILE_PREVIEW_PAGE = "media";
|
||||
String PICTURE_FILE_PREVIEW_PAGE = "picture";
|
||||
String TIFF_FILE_PREVIEW_PAGE = "tiff";
|
||||
String OFD_FILE_PREVIEW_PAGE = "ofd";
|
||||
String SVG_FILE_PREVIEW_PAGE = "svg";
|
||||
String ONLINE3D_PREVIEW_PAGE = "online3D";
|
||||
String EPUB_PREVIEW_PAGE = "epub";
|
||||
String XMIND_FILE_PREVIEW_PAGE = "xmind";
|
||||
String EML_FILE_PREVIEW_PAGE = "eml";
|
||||
String OFFICE_PICTURE_FILE_PREVIEW_PAGE = "officePicture";
|
||||
String TXT_FILE_PREVIEW_PAGE = "txt";
|
||||
String CODE_FILE_PREVIEW_PAGE = "code";
|
||||
String EXEL_FILE_PREVIEW_PAGE = "html";
|
||||
String XML_FILE_PREVIEW_PAGE = "xml";
|
||||
String MARKDOWN_FILE_PREVIEW_PAGE = "markdown";
|
||||
String BPMN_FILE_PREVIEW_PAGE = "bpmn";
|
||||
String DCM_FILE_PREVIEW_PAGE = "dcm";
|
||||
String DRAWUI_FILE_PREVIEW_PAGE = "drawio";
|
||||
String NOT_SUPPORTED_FILE_PAGE = "fileNotSupported";
|
||||
String XLSX_FILE_PREVIEW_PAGE = "officeweb";
|
||||
String CSV_FILE_PREVIEW_PAGE = "csv";
|
||||
|
||||
String filePreviewHandle(String url, Model model, FileAttribute fileAttribute);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :
|
||||
*/
|
||||
@Service
|
||||
public class FilePreviewFactory {
|
||||
|
||||
private final ApplicationContext context;
|
||||
|
||||
public FilePreviewFactory(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public FilePreview get(FileAttribute fileAttribute) {
|
||||
return context.getBean(fileAttribute.getType().getInstanceName(), FilePreview.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import cn.keking.utils.LocalOfficeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jodconverter.core.office.InstalledOfficeManagerHolder;
|
||||
import org.jodconverter.core.office.OfficeException;
|
||||
import org.jodconverter.core.office.OfficeUtils;
|
||||
import org.jodconverter.core.util.OSUtils;
|
||||
import org.jodconverter.local.office.LocalOfficeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.convert.DurationStyle;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 创建文件转换器
|
||||
*
|
||||
* @author chenjh
|
||||
* @since 2022-12-15
|
||||
*/
|
||||
@Component
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class OfficePluginManager {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OfficePluginManager.class);
|
||||
|
||||
private LocalOfficeManager officeManager;
|
||||
|
||||
@Value("${office.plugin.server.ports:2001,2002}")
|
||||
private String serverPorts;
|
||||
|
||||
@Value("${office.plugin.task.timeout:5m}")
|
||||
private String timeOut;
|
||||
|
||||
@Value("${office.plugin.task.taskexecutiontimeout:5m}")
|
||||
private String taskExecutionTimeout;
|
||||
|
||||
@Value("${office.plugin.task.maxtasksperprocess:5}")
|
||||
private int maxTasksPerProcess;
|
||||
|
||||
/**
|
||||
* 启动Office组件进程
|
||||
*/
|
||||
@PostConstruct
|
||||
public void startOfficeManager() throws OfficeException {
|
||||
File officeHome = LocalOfficeUtils.getDefaultOfficeHome();
|
||||
if (officeHome == null) {
|
||||
throw new RuntimeException("找不到office组件,请确认'office.home'配置是否有误");
|
||||
}
|
||||
boolean killOffice = killProcess();
|
||||
if (killOffice) {
|
||||
logger.warn("检测到有正在运行的office进程,已自动结束该进程");
|
||||
}
|
||||
try {
|
||||
String[] portsString = serverPorts.split(",");
|
||||
int[] ports = Arrays.stream(portsString).mapToInt(Integer::parseInt).toArray();
|
||||
long timeout = DurationStyle.detectAndParse(timeOut).toMillis();
|
||||
long taskexecutiontimeout = DurationStyle.detectAndParse(taskExecutionTimeout).toMillis();
|
||||
officeManager = LocalOfficeManager.builder()
|
||||
.officeHome(officeHome)
|
||||
.portNumbers(ports)
|
||||
.processTimeout(timeout)
|
||||
.maxTasksPerProcess(maxTasksPerProcess)
|
||||
.taskExecutionTimeout(taskexecutiontimeout)
|
||||
.build();
|
||||
officeManager.start();
|
||||
InstalledOfficeManagerHolder.setInstance(officeManager);
|
||||
} catch (Exception e) {
|
||||
logger.error("启动office组件失败,请检查office组件是否可用");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean killProcess() {
|
||||
boolean flag = false;
|
||||
try {
|
||||
if (OSUtils.IS_OS_WINDOWS) {
|
||||
Process p = Runtime.getRuntime().exec("cmd /c tasklist ");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream os = p.getInputStream();
|
||||
byte[] b = new byte[256];
|
||||
while (os.read(b) > 0) {
|
||||
baos.write(b);
|
||||
}
|
||||
String s = baos.toString();
|
||||
if (s.contains("soffice.bin")) {
|
||||
Runtime.getRuntime().exec("taskkill /im " + "soffice.bin" + " /f");
|
||||
flag = true;
|
||||
}
|
||||
} else if (OSUtils.IS_OS_MAC || OSUtils.IS_OS_MAC_OSX) {
|
||||
Process p = Runtime.getRuntime().exec(new String[]{"sh", "-c", "ps -ef | grep " + "soffice.bin"});
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream os = p.getInputStream();
|
||||
byte[] b = new byte[256];
|
||||
while (os.read(b) > 0) {
|
||||
baos.write(b);
|
||||
}
|
||||
String s = baos.toString();
|
||||
if (StringUtils.ordinalIndexOf(s, "soffice.bin", 3) > 0) {
|
||||
String[] cmd = {"sh", "-c", "kill -15 `ps -ef|grep " + "soffice.bin" + "|awk 'NR==1{print $2}'`"};
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
flag = true;
|
||||
}
|
||||
} else {
|
||||
Process p = Runtime.getRuntime().exec(new String[]{"sh", "-c", "ps -ef | grep " + "soffice.bin" + " |grep -v grep | wc -l"});
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream os = p.getInputStream();
|
||||
byte[] b = new byte[256];
|
||||
while (os.read(b) > 0) {
|
||||
baos.write(b);
|
||||
}
|
||||
String s = baos.toString();
|
||||
if (!s.startsWith("0")) {
|
||||
String[] cmd = {"sh", "-c", "ps -ef | grep soffice.bin | grep -v grep | awk '{print \"kill -9 \"$2}' | sh"};
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("检测office进程异常", e);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroyOfficeManager() {
|
||||
if (null != officeManager && officeManager.isRunning()) {
|
||||
logger.info("Shutting down office process");
|
||||
OfficeUtils.stopQuietly(officeManager);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package cn.keking.service;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import com.sun.star.document.UpdateDocMode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jodconverter.core.office.OfficeException;
|
||||
import org.jodconverter.local.LocalConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
*/
|
||||
@Component
|
||||
public class OfficeToPdfService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(OfficeToPdfService.class);
|
||||
|
||||
public void openOfficeToPDF(String inputFilePath, String outputFilePath, FileAttribute fileAttribute) throws OfficeException {
|
||||
office2pdf(inputFilePath, outputFilePath, fileAttribute);
|
||||
}
|
||||
|
||||
|
||||
public static void converterFile(File inputFile, String outputFilePath_end, FileAttribute fileAttribute) throws OfficeException {
|
||||
File outputFile = new File(outputFilePath_end);
|
||||
// 假如目标路径不存在,则新建该路径
|
||||
if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs()) {
|
||||
logger.error("创建目录【{}】失败,请检查目录权限!",outputFilePath_end);
|
||||
}
|
||||
LocalConverter.Builder builder;
|
||||
Map<String, Object> filterData = new HashMap<>();
|
||||
filterData.put("EncryptFile", true);
|
||||
if(!ConfigConstants.getOfficePageRange().equals("false")){
|
||||
filterData.put("PageRange", ConfigConstants.getOfficePageRange()); //限制页面
|
||||
}
|
||||
if(!ConfigConstants.getOfficeWatermark().equals("false")){
|
||||
filterData.put("Watermark", ConfigConstants.getOfficeWatermark()); //水印
|
||||
}
|
||||
filterData.put("Quality", ConfigConstants.getOfficeQuality()); //图片压缩
|
||||
filterData.put("MaxImageResolution", ConfigConstants.getOfficeMaxImageResolution()); //DPI
|
||||
if(ConfigConstants.getOfficeExportBookmarks()){
|
||||
filterData.put("ExportBookmarks", true); //导出书签
|
||||
}
|
||||
if(ConfigConstants.getOfficeExportNotes()){
|
||||
filterData.put("ExportNotes", true); //批注作为PDF的注释
|
||||
}
|
||||
if(ConfigConstants.getOfficeDocumentOpenPasswords()){
|
||||
filterData.put("DocumentOpenPassword", fileAttribute.getFilePassword()); //给PDF添加密码
|
||||
}
|
||||
Map<String, Object> customProperties = new HashMap<>();
|
||||
customProperties.put("FilterData", filterData);
|
||||
if (StringUtils.isNotBlank(fileAttribute.getFilePassword())) {
|
||||
Map<String, Object> loadProperties = new HashMap<>();
|
||||
loadProperties.put("Hidden", true);
|
||||
loadProperties.put("ReadOnly", true);
|
||||
loadProperties.put("UpdateDocMode", UpdateDocMode.NO_UPDATE);
|
||||
loadProperties.put("Password", fileAttribute.getFilePassword());
|
||||
builder = LocalConverter.builder().loadProperties(loadProperties).storeProperties(customProperties);
|
||||
} else {
|
||||
builder = LocalConverter.builder().storeProperties(customProperties);
|
||||
}
|
||||
builder.build().convert(inputFile).to(outputFile).execute();
|
||||
}
|
||||
|
||||
|
||||
public void office2pdf(String inputFilePath, String outputFilePath, FileAttribute fileAttribute) throws OfficeException {
|
||||
if (null != inputFilePath) {
|
||||
File inputFile = new File(inputFilePath);
|
||||
// 判断目标文件路径是否为空
|
||||
if (null == outputFilePath) {
|
||||
// 转换后的文件路径
|
||||
String outputFilePath_end = getOutputFilePath(inputFilePath);
|
||||
if (inputFile.exists()) {
|
||||
// 找不到源文件, 则返回
|
||||
converterFile(inputFile, outputFilePath_end, fileAttribute);
|
||||
}
|
||||
} else {
|
||||
if (inputFile.exists()) {
|
||||
// 找不到源文件, 则返回
|
||||
converterFile(inputFile, outputFilePath, fileAttribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getOutputFilePath(String inputFilePath) {
|
||||
return inputFilePath.replaceAll("."+ getPostfix(inputFilePath), ".pdf");
|
||||
}
|
||||
|
||||
public static String getPostfix(String inputFilePath) {
|
||||
return inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.keking.service;
|
||||
import java.util.List;
|
||||
public class ZtreeNodeVo {
|
||||
public String id;
|
||||
public String pid;
|
||||
public String name;
|
||||
public List<ZtreeNodeVo> children;
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public void setPid(String pid) {
|
||||
this.pid = pid;
|
||||
}
|
||||
public void setChildren(List<ZtreeNodeVo> children) {
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
42
tool-tech-file-view/src/main/java/cn/keking/service/cache/CacheService.java
vendored
Normal file
42
tool-tech-file-view/src/main/java/cn/keking/service/cache/CacheService.java
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package cn.keking.service.cache;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: chenjh
|
||||
* @since: 2019/4/2 16:45
|
||||
*/
|
||||
public interface CacheService {
|
||||
|
||||
String FILE_PREVIEW_PDF_KEY = "converted-preview-pdf-file";
|
||||
String FILE_PREVIEW_IMGS_KEY = "converted-preview-imgs-file";//压缩包内图片文件集合
|
||||
String FILE_PREVIEW_PDF_IMGS_KEY = "converted-preview-pdfimgs-file";
|
||||
String FILE_PREVIEW_MEDIA_CONVERT_KEY = "converted-preview-media-file";
|
||||
String TASK_QUEUE_NAME = "convert-task";
|
||||
|
||||
Integer DEFAULT_PDF_CAPACITY = 500000;
|
||||
Integer DEFAULT_IMG_CAPACITY = 500000;
|
||||
Integer DEFAULT_PDFIMG_CAPACITY = 500000;
|
||||
Integer DEFAULT_MEDIACONVERT_CAPACITY = 500000;
|
||||
|
||||
void initPDFCachePool(Integer capacity);
|
||||
void initIMGCachePool(Integer capacity);
|
||||
void initPdfImagesCachePool(Integer capacity);
|
||||
void initMediaConvertCachePool(Integer capacity);
|
||||
void putPDFCache(String key, String value);
|
||||
void putImgCache(String key, List<String> value);
|
||||
Map<String, String> getPDFCache();
|
||||
String getPDFCache(String key);
|
||||
Map<String, List<String>> getImgCache();
|
||||
List<String> getImgCache(String key);
|
||||
Integer getPdfImageCache(String key);
|
||||
void putPdfImageCache(String pdfFilePath, int num);
|
||||
Map<String, String> getMediaConvertCache();
|
||||
void putMediaConvertCache(String key, String value);
|
||||
String getMediaConvertCache(String key);
|
||||
void cleanCache();
|
||||
void addQueueTask(String url);
|
||||
String takeQueueTask() throws InterruptedException;
|
||||
|
||||
}
|
||||
20
tool-tech-file-view/src/main/java/cn/keking/service/cache/NotResourceCache.java
vendored
Normal file
20
tool-tech-file-view/src/main/java/cn/keking/service/cache/NotResourceCache.java
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package cn.keking.service.cache;
|
||||
|
||||
import org.apache.pdfbox.cos.COSObject;
|
||||
import org.apache.pdfbox.pdmodel.DefaultResourceCache;
|
||||
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author: Sawyer.Yong
|
||||
* @since: 2023/02/18 14:45
|
||||
* 解决图片 SoftReference 导致内存无法被回收导致的OOM, 详见 https://issues.apache.org/jira/browse/PDFBOX-3700
|
||||
*/
|
||||
public class NotResourceCache extends DefaultResourceCache {
|
||||
|
||||
@Override
|
||||
public void put(COSObject indirect, PDXObject xobject) throws IOException {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
145
tool-tech-file-view/src/main/java/cn/keking/service/cache/impl/CacheServiceJDKImpl.java
vendored
Normal file
145
tool-tech-file-view/src/main/java/cn/keking/service/cache/impl/CacheServiceJDKImpl.java
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
package cn.keking.service.cache.impl;
|
||||
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
|
||||
import com.googlecode.concurrentlinkedhashmap.Weighers;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
/**
|
||||
* @auther: chenjh
|
||||
* @time: 2019/4/2 17:21
|
||||
* @description
|
||||
*/
|
||||
@Service
|
||||
@ConditionalOnExpression("'${cache.type:default}'.equals('jdk')")
|
||||
public class CacheServiceJDKImpl implements CacheService {
|
||||
|
||||
private Map<String, String> pdfCache;
|
||||
private Map<String, List<String>> imgCache;
|
||||
private Map<String, Integer> pdfImagesCache;
|
||||
private Map<String, String> mediaConvertCache;
|
||||
private static final int QUEUE_SIZE = 500000;
|
||||
private final BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(QUEUE_SIZE);
|
||||
|
||||
@PostConstruct
|
||||
public void initCache(){
|
||||
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
|
||||
initIMGCachePool(CacheService.DEFAULT_IMG_CAPACITY);
|
||||
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
|
||||
initMediaConvertCachePool(CacheService.DEFAULT_MEDIACONVERT_CAPACITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putPDFCache(String key, String value) {
|
||||
pdfCache.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putImgCache(String key, List<String> value) {
|
||||
imgCache.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getPDFCache() {
|
||||
return pdfCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPDFCache(String key) {
|
||||
return pdfCache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getImgCache() {
|
||||
return imgCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getImgCache(String key) {
|
||||
if(StringUtils.isEmpty(key)){
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return imgCache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPdfImageCache(String key) {
|
||||
return pdfImagesCache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putPdfImageCache(String pdfFilePath, int num) {
|
||||
pdfImagesCache.put(pdfFilePath, num);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMediaConvertCache() {
|
||||
return mediaConvertCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putMediaConvertCache(String key, String value) {
|
||||
mediaConvertCache.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMediaConvertCache(String key) {
|
||||
return mediaConvertCache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanCache() {
|
||||
initPDFCachePool(CacheService.DEFAULT_PDF_CAPACITY);
|
||||
initIMGCachePool(CacheService.DEFAULT_IMG_CAPACITY);
|
||||
initPdfImagesCachePool(CacheService.DEFAULT_PDFIMG_CAPACITY);
|
||||
initMediaConvertCachePool(CacheService.DEFAULT_MEDIACONVERT_CAPACITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addQueueTask(String url) {
|
||||
blockingQueue.add(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String takeQueueTask() throws InterruptedException {
|
||||
return blockingQueue.take();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initPDFCachePool(Integer capacity) {
|
||||
pdfCache = new ConcurrentLinkedHashMap.Builder<String, String>()
|
||||
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initIMGCachePool(Integer capacity) {
|
||||
imgCache = new ConcurrentLinkedHashMap.Builder<String, List<String>>()
|
||||
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initPdfImagesCachePool(Integer capacity) {
|
||||
pdfImagesCache = new ConcurrentLinkedHashMap.Builder<String, Integer>()
|
||||
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initMediaConvertCachePool(Integer capacity) {
|
||||
mediaConvertCache = new ConcurrentLinkedHashMap.Builder<String, String>()
|
||||
.maximumWeightedCapacity(capacity).weigher(Weighers.singleton())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
144
tool-tech-file-view/src/main/java/cn/keking/service/cache/impl/CacheServiceRedisImpl.java
vendored
Normal file
144
tool-tech-file-view/src/main/java/cn/keking/service/cache/impl/CacheServiceRedisImpl.java
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
package cn.keking.service.cache.impl;
|
||||
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RBlockingQueue;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.config.Config;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @auther: chenjh
|
||||
* @time: 2019/4/2 18:02
|
||||
* @description
|
||||
*/
|
||||
@ConditionalOnExpression("'${cache.type:default}'.equals('redis')")
|
||||
@Service
|
||||
public class CacheServiceRedisImpl implements CacheService {
|
||||
|
||||
private final RedissonClient redissonClient;
|
||||
|
||||
public CacheServiceRedisImpl(Config config) {
|
||||
this.redissonClient = Redisson.create(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initPDFCachePool(Integer capacity) { }
|
||||
@Override
|
||||
public void initIMGCachePool(Integer capacity) { }
|
||||
@Override
|
||||
public void initPdfImagesCachePool(Integer capacity) { }
|
||||
|
||||
@Override
|
||||
public void initMediaConvertCachePool(Integer capacity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putPDFCache(String key, String value) {
|
||||
RMapCache<String, String> convertedList = redissonClient.getMapCache(FILE_PREVIEW_PDF_KEY);
|
||||
convertedList.fastPut(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putImgCache(String key, List<String> value) {
|
||||
RMapCache<String, List<String>> convertedList = redissonClient.getMapCache(FILE_PREVIEW_IMGS_KEY);
|
||||
convertedList.fastPut(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getPDFCache() {
|
||||
return redissonClient.getMapCache(FILE_PREVIEW_PDF_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPDFCache(String key) {
|
||||
RMapCache<String, String> convertedList = redissonClient.getMapCache(FILE_PREVIEW_PDF_KEY);
|
||||
return convertedList.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getImgCache() {
|
||||
return redissonClient.getMapCache(FILE_PREVIEW_IMGS_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getImgCache(String key) {
|
||||
RMapCache<String, List<String>> convertedList = redissonClient.getMapCache(FILE_PREVIEW_IMGS_KEY);
|
||||
return convertedList.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPdfImageCache(String key) {
|
||||
RMapCache<String, Integer> convertedList = redissonClient.getMapCache(FILE_PREVIEW_PDF_IMGS_KEY);
|
||||
return convertedList.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putPdfImageCache(String pdfFilePath, int num) {
|
||||
RMapCache<String, Integer> convertedList = redissonClient.getMapCache(FILE_PREVIEW_PDF_IMGS_KEY);
|
||||
convertedList.fastPut(pdfFilePath, num);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMediaConvertCache() {
|
||||
return redissonClient.getMapCache(FILE_PREVIEW_MEDIA_CONVERT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putMediaConvertCache(String key, String value) {
|
||||
RMapCache<String, String> convertedList = redissonClient.getMapCache(FILE_PREVIEW_MEDIA_CONVERT_KEY);
|
||||
convertedList.fastPut(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMediaConvertCache(String key) {
|
||||
RMapCache<String, String> convertedList = redissonClient.getMapCache(FILE_PREVIEW_MEDIA_CONVERT_KEY);
|
||||
return convertedList.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanCache() {
|
||||
cleanPdfCache();
|
||||
cleanImgCache();
|
||||
cleanPdfImgCache();
|
||||
cleanMediaConvertCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addQueueTask(String url) {
|
||||
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(TASK_QUEUE_NAME);
|
||||
queue.addAsync(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String takeQueueTask() throws InterruptedException {
|
||||
RBlockingQueue<String> queue = redissonClient.getBlockingQueue(TASK_QUEUE_NAME);
|
||||
return queue.take();
|
||||
}
|
||||
|
||||
private void cleanPdfCache() {
|
||||
RMapCache<String, String> pdfCache = redissonClient.getMapCache(FILE_PREVIEW_PDF_KEY);
|
||||
pdfCache.clear();
|
||||
}
|
||||
|
||||
private void cleanImgCache() {
|
||||
RMapCache<String, List<String>> imgCache = redissonClient.getMapCache(FILE_PREVIEW_IMGS_KEY);
|
||||
imgCache.clear();
|
||||
}
|
||||
|
||||
private void cleanPdfImgCache() {
|
||||
RMapCache<String, Integer> pdfImg = redissonClient.getMapCache(FILE_PREVIEW_PDF_IMGS_KEY);
|
||||
pdfImg.clear();
|
||||
}
|
||||
|
||||
private void cleanMediaConvertCache() {
|
||||
RMapCache<String, Integer> mediaConvertCache = redissonClient.getMapCache(FILE_PREVIEW_MEDIA_CONVERT_KEY);
|
||||
mediaConvertCache.clear();
|
||||
}
|
||||
}
|
||||
290
tool-tech-file-view/src/main/java/cn/keking/service/cache/impl/CacheServiceRocksDBImpl.java
vendored
Normal file
290
tool-tech-file-view/src/main/java/cn/keking/service/cache/impl/CacheServiceRocksDBImpl.java
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
package cn.keking.service.cache.impl;
|
||||
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.utils.ConfigUtils;
|
||||
import org.rocksdb.RocksDB;
|
||||
import org.rocksdb.RocksDBException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
/**
|
||||
* @auther: chenjh
|
||||
* @time: 2019/4/22 11:02
|
||||
* @description
|
||||
*/
|
||||
@ConditionalOnExpression("'${cache.type:default}'.equals('default')")
|
||||
@Service
|
||||
public class CacheServiceRocksDBImpl implements CacheService {
|
||||
|
||||
static {
|
||||
RocksDB.loadLibrary();
|
||||
}
|
||||
|
||||
private static final String DB_PATH = ConfigUtils.getHomePath() + File.separator + "cache";
|
||||
private static final int QUEUE_SIZE = 500000;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CacheServiceRocksDBImpl.class);
|
||||
private final BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(QUEUE_SIZE);
|
||||
|
||||
private RocksDB db;
|
||||
|
||||
{
|
||||
try {
|
||||
db = RocksDB.open(DB_PATH);
|
||||
if (db.get(FILE_PREVIEW_PDF_KEY.getBytes()) == null) {
|
||||
Map<String, String> initPDFCache = new HashMap<>();
|
||||
db.put(FILE_PREVIEW_PDF_KEY.getBytes(), toByteArray(initPDFCache));
|
||||
}
|
||||
if (db.get(FILE_PREVIEW_IMGS_KEY.getBytes()) == null) {
|
||||
Map<String, List<String>> initIMGCache = new HashMap<>();
|
||||
db.put(FILE_PREVIEW_IMGS_KEY.getBytes(), toByteArray(initIMGCache));
|
||||
}
|
||||
if (db.get(FILE_PREVIEW_PDF_IMGS_KEY.getBytes()) == null) {
|
||||
Map<String, Integer> initPDFIMGCache = new HashMap<>();
|
||||
db.put(FILE_PREVIEW_PDF_IMGS_KEY.getBytes(), toByteArray(initPDFIMGCache));
|
||||
}
|
||||
} catch (RocksDBException | IOException e) {
|
||||
LOGGER.error("Uable to init RocksDB" + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initPDFCachePool(Integer capacity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initIMGCachePool(Integer capacity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initPdfImagesCachePool(Integer capacity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initMediaConvertCachePool(Integer capacity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putPDFCache(String key, String value) {
|
||||
try {
|
||||
Map<String, String> pdfCacheItem = getPDFCache();
|
||||
pdfCacheItem.put(key, value);
|
||||
db.put(FILE_PREVIEW_PDF_KEY.getBytes(), toByteArray(pdfCacheItem));
|
||||
} catch (RocksDBException | IOException e) {
|
||||
LOGGER.error("Put into RocksDB Exception" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putImgCache(String key, List<String> value) {
|
||||
try {
|
||||
Map<String, List<String>> imgCacheItem = getImgCache();
|
||||
imgCacheItem.put(key, value);
|
||||
db.put(FILE_PREVIEW_IMGS_KEY.getBytes(), toByteArray(imgCacheItem));
|
||||
} catch (RocksDBException | IOException e) {
|
||||
LOGGER.error("Put into RocksDB Exception" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, String> getPDFCache() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
try {
|
||||
result = (Map<String, String>) toObject(db.get(FILE_PREVIEW_PDF_KEY.getBytes()));
|
||||
} catch (RocksDBException | IOException | ClassNotFoundException e) {
|
||||
LOGGER.error("Get from RocksDB Exception" + e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public String getPDFCache(String key) {
|
||||
String result = "";
|
||||
try {
|
||||
Map<String, String> map = (Map<String, String>) toObject(db.get(FILE_PREVIEW_PDF_KEY.getBytes()));
|
||||
result = map.get(key);
|
||||
} catch (RocksDBException | IOException | ClassNotFoundException e) {
|
||||
LOGGER.error("Get from RocksDB Exception" + e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, List<String>> getImgCache() {
|
||||
Map<String, List<String>> result = new HashMap<>();
|
||||
try {
|
||||
result = (Map<String, List<String>>) toObject(db.get(FILE_PREVIEW_IMGS_KEY.getBytes()));
|
||||
} catch (RocksDBException | IOException | ClassNotFoundException e) {
|
||||
LOGGER.error("Get from RocksDB Exception" + e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> getImgCache(String key) {
|
||||
List<String> result = new ArrayList<>();
|
||||
Map<String, List<String>> map;
|
||||
try {
|
||||
map = (Map<String, List<String>>) toObject(db.get(FILE_PREVIEW_IMGS_KEY.getBytes()));
|
||||
result = map.get(key);
|
||||
} catch (RocksDBException | IOException | ClassNotFoundException e) {
|
||||
LOGGER.error("Get from RocksDB Exception" + e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Integer getPdfImageCache(String key) {
|
||||
Integer result = 0;
|
||||
Map<String, Integer> map;
|
||||
try {
|
||||
map = (Map<String, Integer>) toObject(db.get(FILE_PREVIEW_PDF_IMGS_KEY.getBytes()));
|
||||
result = map.get(key);
|
||||
} catch (RocksDBException | IOException | ClassNotFoundException e) {
|
||||
LOGGER.error("Get from RocksDB Exception" + e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putPdfImageCache(String pdfFilePath, int num) {
|
||||
try {
|
||||
Map<String, Integer> pdfImageCacheItem = getPdfImageCaches();
|
||||
pdfImageCacheItem.put(pdfFilePath, num);
|
||||
db.put(FILE_PREVIEW_PDF_IMGS_KEY.getBytes(), toByteArray(pdfImageCacheItem));
|
||||
} catch (RocksDBException | IOException e) {
|
||||
LOGGER.error("Put into RocksDB Exception" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, String> getMediaConvertCache() {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
try {
|
||||
result = (Map<String, String>) toObject(db.get(FILE_PREVIEW_MEDIA_CONVERT_KEY.getBytes()));
|
||||
} catch (RocksDBException | IOException | ClassNotFoundException e) {
|
||||
LOGGER.error("Get from RocksDB Exception" + e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putMediaConvertCache(String key, String value) {
|
||||
try {
|
||||
Map<String, String> mediaConvertCacheItem = getMediaConvertCache();
|
||||
mediaConvertCacheItem.put(key, value);
|
||||
db.put(FILE_PREVIEW_MEDIA_CONVERT_KEY.getBytes(), toByteArray(mediaConvertCacheItem));
|
||||
} catch (RocksDBException | IOException e) {
|
||||
LOGGER.error("Put into RocksDB Exception" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public String getMediaConvertCache(String key) {
|
||||
String result = "";
|
||||
try {
|
||||
Map<String, String> map = (Map<String, String>) toObject(db.get(FILE_PREVIEW_MEDIA_CONVERT_KEY.getBytes()));
|
||||
result = map.get(key);
|
||||
} catch (RocksDBException | IOException | ClassNotFoundException e) {
|
||||
LOGGER.error("Get from RocksDB Exception" + e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanCache() {
|
||||
try {
|
||||
cleanPdfCache();
|
||||
cleanImgCache();
|
||||
cleanPdfImgCache();
|
||||
cleanMediaConvertCache();
|
||||
} catch (IOException | RocksDBException e) {
|
||||
LOGGER.error("Clean Cache Exception" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addQueueTask(String url) {
|
||||
blockingQueue.add(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String takeQueueTask() throws InterruptedException {
|
||||
return blockingQueue.take();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Integer> getPdfImageCaches() {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
try {
|
||||
map = (Map<String, Integer>) toObject(db.get(FILE_PREVIEW_PDF_IMGS_KEY.getBytes()));
|
||||
} catch (RocksDBException | IOException | ClassNotFoundException e) {
|
||||
LOGGER.error("Get from RocksDB Exception" + e);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
private byte[] toByteArray(Object obj) throws IOException {
|
||||
byte[] bytes;
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||
oos.writeObject(obj);
|
||||
oos.flush();
|
||||
bytes = bos.toByteArray();
|
||||
oos.close();
|
||||
bos.close();
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private Object toObject(byte[] bytes) throws IOException, ClassNotFoundException {
|
||||
Object obj;
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(bis);
|
||||
obj = ois.readObject();
|
||||
ois.close();
|
||||
bis.close();
|
||||
return obj;
|
||||
}
|
||||
|
||||
private void cleanPdfCache() throws IOException, RocksDBException {
|
||||
Map<String, String> initPDFCache = new HashMap<>();
|
||||
db.put(FILE_PREVIEW_PDF_KEY.getBytes(), toByteArray(initPDFCache));
|
||||
}
|
||||
|
||||
private void cleanImgCache() throws IOException, RocksDBException {
|
||||
Map<String, List<String>> initIMGCache = new HashMap<>();
|
||||
db.put(FILE_PREVIEW_IMGS_KEY.getBytes(), toByteArray(initIMGCache));
|
||||
}
|
||||
|
||||
private void cleanPdfImgCache() throws IOException, RocksDBException {
|
||||
Map<String, Integer> initPDFIMGCache = new HashMap<>();
|
||||
db.put(FILE_PREVIEW_PDF_IMGS_KEY.getBytes(), toByteArray(initPDFIMGCache));
|
||||
}
|
||||
|
||||
private void cleanMediaConvertCache() throws IOException, RocksDBException {
|
||||
Map<String, String> initMediaConvertCache = new HashMap<>();
|
||||
db.put(FILE_PREVIEW_MEDIA_CONVERT_KEY.getBytes(), toByteArray(initMediaConvertCache));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2023/3/9
|
||||
*/
|
||||
@Component
|
||||
public class BpmnFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public BpmnFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
model.addAttribute("fileName", fileAttribute.getName());
|
||||
return FilePreview.BPMN_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType;
|
||||
|
||||
/**
|
||||
* @author chenjh
|
||||
* @since 2019/11/21 14:28
|
||||
*/
|
||||
@Service
|
||||
public class CadFilePreviewImpl implements FilePreview {
|
||||
|
||||
private static final String OFFICE_PREVIEW_TYPE_IMAGE = "image";
|
||||
private static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages";
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public CadFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
// 预览Type,参数传了就取参数的,没传取系统默认
|
||||
String officePreviewType = fileAttribute.getOfficePreviewType() == null ? ConfigConstants.getOfficePreviewType() : fileAttribute.getOfficePreviewType();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
|
||||
String fileName = fileAttribute.getName();
|
||||
String cadPreviewType = ConfigConstants.getCadPreviewType();
|
||||
String cacheName = fileAttribute.getCacheName();
|
||||
String outFilePath = fileAttribute.getOutFilePath();
|
||||
// 判断之前是否已转换过,如果转换过,直接返回,否则执行转换
|
||||
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
String imageUrls = null;
|
||||
if (StringUtils.hasText(outFilePath)) {
|
||||
try {
|
||||
imageUrls = fileHandlerService.cadToPdf(filePath, outFilePath, cadPreviewType, fileAttribute);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (imageUrls == null) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "CAD转换异常,请联系管理员");
|
||||
}
|
||||
//是否保留CAD源文件
|
||||
if (!fileAttribute.isCompressFile() && ConfigConstants.getDeleteSourceFile()) {
|
||||
KkFileUtils.deleteFileByPath(filePath);
|
||||
}
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
cacheName= WebUtils.encodeFileName(cacheName);
|
||||
if ("tif".equalsIgnoreCase(cadPreviewType)) {
|
||||
model.addAttribute("currentUrl", cacheName);
|
||||
return TIFF_FILE_PREVIEW_PAGE;
|
||||
} else if ("svg".equalsIgnoreCase(cadPreviewType)) {
|
||||
model.addAttribute("currentUrl", cacheName);
|
||||
return SVG_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, cacheName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
|
||||
}
|
||||
model.addAttribute("pdfUrl", cacheName);
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2021/2/18
|
||||
*/
|
||||
@Component
|
||||
public class CodeFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final SimTextFilePreviewImpl filePreviewHandle;
|
||||
|
||||
public CodeFilePreviewImpl(SimTextFilePreviewImpl filePreviewHandle) {
|
||||
this.filePreviewHandle = filePreviewHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
filePreviewHandle.filePreviewHandle(url, model, fileAttribute);
|
||||
return CODE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :图片文件处理
|
||||
*/
|
||||
@Component("commonPreview")
|
||||
public class CommonPreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public CommonPreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, null);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
} else {
|
||||
String file = fileHandlerService.getRelativePath(response.getContent());
|
||||
model.addAttribute("currentUrl", file);
|
||||
}
|
||||
} else {
|
||||
model.addAttribute("currentUrl", url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.CompressFileReader;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :处理压缩包文件
|
||||
*/
|
||||
@Service
|
||||
public class CompressFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final CompressFileReader compressFileReader;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
private static final String Rar_PASSWORD_MSG = "password";
|
||||
public CompressFilePreviewImpl(FileHandlerService fileHandlerService, CompressFileReader compressFileReader, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.compressFileReader = compressFileReader;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
String fileName=fileAttribute.getName();
|
||||
String filePassword = fileAttribute.getFilePassword();
|
||||
boolean forceUpdatedCache=fileAttribute.forceUpdatedCache();
|
||||
String fileTree = null;
|
||||
// 判断文件名是否存在(redis缓存读取)
|
||||
if (forceUpdatedCache || !StringUtils.hasText(fileHandlerService.getConvertedFile(fileName)) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
try {
|
||||
fileTree = compressFileReader.unRar(filePath, filePassword,fileName, fileAttribute);
|
||||
} catch (Exception e) {
|
||||
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
||||
for (Throwable throwable : throwableArray) {
|
||||
if (throwable instanceof IOException || throwable instanceof EncryptedDocumentException) {
|
||||
if (e.getMessage().toLowerCase().contains(Rar_PASSWORD_MSG)) {
|
||||
model.addAttribute("needFilePassword", true);
|
||||
return EXEL_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(fileTree)) {
|
||||
//是否保留压缩包源文件
|
||||
if (!fileAttribute.isCompressFile() && ConfigConstants.getDeleteSourceFile()) {
|
||||
KkFileUtils.deleteFileByPath(filePath);
|
||||
}
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(fileName, fileTree);
|
||||
}
|
||||
}else {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "压缩文件密码错误! 压缩文件损坏! 压缩文件类型不受支持!");
|
||||
}
|
||||
} else {
|
||||
fileTree = fileHandlerService.getConvertedFile(fileName);
|
||||
}
|
||||
model.addAttribute("fileName", fileName);
|
||||
model.addAttribute("fileTree", fileTree);
|
||||
return COMPRESS_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* Dcm 文件处理
|
||||
*/
|
||||
@Service
|
||||
public class DcmFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public DcmFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return DCM_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* Drawio 文件处理
|
||||
*/
|
||||
@Service
|
||||
public class DrawioFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public DrawioFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return DRAWUI_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* EML 文件处理
|
||||
*/
|
||||
@Service
|
||||
public class EmlFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public EmlFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return EML_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* svg 图片文件处理
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2021/2/8
|
||||
*/
|
||||
@Service
|
||||
public class EpubFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public EpubFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return EPUB_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2020/12/25
|
||||
*/
|
||||
@Service
|
||||
public class MarkdownFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final SimTextFilePreviewImpl simTextFilePreview;
|
||||
|
||||
public MarkdownFilePreviewImpl(SimTextFilePreviewImpl simTextFilePreview) {
|
||||
this.simTextFilePreview = simTextFilePreview;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
|
||||
return MARKDOWN_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import org.bytedeco.ffmpeg.global.avcodec;
|
||||
import org.bytedeco.javacv.FFmpegFrameGrabber;
|
||||
import org.bytedeco.javacv.FFmpegFrameRecorder;
|
||||
import org.bytedeco.javacv.Frame;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author : kl
|
||||
* @authorboke : kailing.pub
|
||||
* @create : 2018-03-25 上午11:58
|
||||
* @description:
|
||||
**/
|
||||
@Service
|
||||
public class MediaFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
private static final String mp4 = "mp4";
|
||||
|
||||
public MediaFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
String fileName = fileAttribute.getName();
|
||||
String suffix = fileAttribute.getSuffix();
|
||||
String cacheName = fileAttribute.getCacheName();
|
||||
String outFilePath = fileAttribute.getOutFilePath();
|
||||
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
|
||||
FileType type = fileAttribute.getType();
|
||||
String[] mediaTypesConvert = FileType.MEDIA_CONVERT_TYPES; //获取支持的转换格式
|
||||
boolean mediaTypes = false;
|
||||
for (String temp : mediaTypesConvert) {
|
||||
if (suffix.equals(temp)) {
|
||||
mediaTypes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!url.toLowerCase().startsWith("http") || checkNeedConvert(mediaTypes)) { //不是http协议的 // 开启转换方式并是支持转换格式的
|
||||
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) { //查询是否开启缓存
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
String convertedUrl = null;
|
||||
try {
|
||||
if (mediaTypes) {
|
||||
convertedUrl = convertToMp4(filePath, outFilePath, fileAttribute);
|
||||
} else {
|
||||
convertedUrl = outFilePath; //其他协议的 不需要转换方式的文件 直接输出
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (convertedUrl == null) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "视频转换异常,请联系管理员");
|
||||
}
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
model.addAttribute("mediaUrl", fileHandlerService.getRelativePath(outFilePath));
|
||||
} else {
|
||||
model.addAttribute("mediaUrl", fileHandlerService.listConvertedFiles().get(cacheName));
|
||||
}
|
||||
return MEDIA_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
if (type.equals(FileType.MEDIA)) { // 支持输出 只限默认格式
|
||||
model.addAttribute("mediaUrl", url);
|
||||
return MEDIA_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "系统还不支持该格式文件的在线预览");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查视频文件转换是否已开启,以及当前文件是否需要转换
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean checkNeedConvert(boolean mediaTypes) {
|
||||
//1.检查开关是否开启
|
||||
if ("true".equals(ConfigConstants.getMediaConvertDisable())) {
|
||||
return mediaTypes;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String convertToMp4(String filePath, String outFilePath, FileAttribute fileAttribute) throws Exception {
|
||||
FFmpegFrameGrabber frameGrabber = FFmpegFrameGrabber.createDefault(filePath);
|
||||
Frame captured_frame;
|
||||
FFmpegFrameRecorder recorder = null;
|
||||
try {
|
||||
File desFile = new File(outFilePath);
|
||||
//判断一下防止重复转换
|
||||
if (desFile.exists()) {
|
||||
return outFilePath;
|
||||
}
|
||||
if (fileAttribute.isCompressFile()) { //判断 是压缩包的创建新的目录
|
||||
int index = outFilePath.lastIndexOf("/"); //截取最后一个斜杠的前面的内容
|
||||
String folder = outFilePath.substring(0, index);
|
||||
File path = new File(folder);
|
||||
//目录不存在 创建新的目录
|
||||
if (!path.exists()) {
|
||||
path.mkdirs();
|
||||
}
|
||||
}
|
||||
frameGrabber.start();
|
||||
recorder = new FFmpegFrameRecorder(outFilePath, frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());
|
||||
// recorder.setImageHeight(640);
|
||||
// recorder.setImageWidth(480);
|
||||
recorder.setFormat(mp4);
|
||||
recorder.setFrameRate(frameGrabber.getFrameRate());
|
||||
recorder.setSampleRate(frameGrabber.getSampleRate());
|
||||
//视频编码属性配置 H.264 H.265 MPEG
|
||||
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
|
||||
//设置视频比特率,单位:b
|
||||
recorder.setVideoBitrate(frameGrabber.getVideoBitrate());
|
||||
recorder.setAspectRatio(frameGrabber.getAspectRatio());
|
||||
// 设置音频通用编码格式
|
||||
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
|
||||
//设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 128000 = 182kb)
|
||||
recorder.setAudioBitrate(frameGrabber.getAudioBitrate());
|
||||
recorder.setAudioOptions(frameGrabber.getAudioOptions());
|
||||
recorder.setAudioChannels(frameGrabber.getAudioChannels());
|
||||
recorder.start();
|
||||
while (true) {
|
||||
captured_frame = frameGrabber.grabFrame();
|
||||
if (captured_frame == null) {
|
||||
System.out.println("转码完成:" + filePath);
|
||||
break;
|
||||
}
|
||||
recorder.record(captured_frame);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
if (recorder != null) { //关闭
|
||||
recorder.stop();
|
||||
recorder.close();
|
||||
}
|
||||
frameGrabber.stop();
|
||||
frameGrabber.close();
|
||||
}
|
||||
return outFilePath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* ofd 图片文件处理
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2021/2/8
|
||||
*/
|
||||
@Service
|
||||
public class OfdFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public OfdFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return OFD_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.service.OfficeToPdfService;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.utils.OfficeUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.jodconverter.core.office.OfficeException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :处理office文件
|
||||
*/
|
||||
@Service
|
||||
public class OfficeFilePreviewImpl implements FilePreview {
|
||||
|
||||
public static final String OFFICE_PREVIEW_TYPE_IMAGE = "image";
|
||||
public static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages";
|
||||
private static final String OFFICE_PASSWORD_MSG = "password";
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OfficeToPdfService officeToPdfService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, OfficeToPdfService officeToPdfService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.officeToPdfService = officeToPdfService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
// 预览Type,参数传了就取参数的,没传取系统默认
|
||||
String officePreviewType = fileAttribute.getOfficePreviewType();
|
||||
boolean userToken = fileAttribute.getUsePasswordCache();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
String suffix = fileAttribute.getSuffix(); //获取文件后缀
|
||||
String fileName = fileAttribute.getName(); //获取文件原始名称
|
||||
String filePassword = fileAttribute.getFilePassword(); //获取密码
|
||||
boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); //是否启用强制更新命令
|
||||
boolean isHtmlView = fileAttribute.isHtmlView(); //xlsx 转换成html
|
||||
String cacheName = fileAttribute.getCacheName(); //转换后的文件名
|
||||
String outFilePath = fileAttribute.getOutFilePath(); //转换后生成文件的路径
|
||||
if (!officePreviewType.equalsIgnoreCase("html")) {
|
||||
if (ConfigConstants.getOfficeTypeWeb() .equalsIgnoreCase("web")) {
|
||||
if (suffix.equalsIgnoreCase("xlsx")) {
|
||||
model.addAttribute("pdfUrl", KkFileUtils.htmlEscape(url)); //特殊符号处理
|
||||
return XLSX_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
if (suffix.equalsIgnoreCase("csv")) {
|
||||
model.addAttribute("csvUrl", KkFileUtils.htmlEscape(url));
|
||||
return CSV_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (forceUpdatedCache|| !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) {
|
||||
// 下载远程文件到本地,如果文件在本地已存在不会重复下载
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
boolean isPwdProtectedOffice = OfficeUtils.isPwdProtected(filePath); // 判断是否加密文件
|
||||
if (isPwdProtectedOffice && !StringUtils.hasLength(filePassword)) {
|
||||
// 加密文件需要密码
|
||||
model.addAttribute("needFilePassword", true);
|
||||
return EXEL_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
if (StringUtils.hasText(outFilePath)) {
|
||||
try {
|
||||
officeToPdfService.openOfficeToPDF(filePath, outFilePath, fileAttribute);
|
||||
} catch (OfficeException e) {
|
||||
if (isPwdProtectedOffice && !OfficeUtils.isCompatible(filePath, filePassword)) {
|
||||
// 加密文件密码错误,提示重新输入
|
||||
model.addAttribute("needFilePassword", true);
|
||||
model.addAttribute("filePasswordError", true);
|
||||
return EXEL_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "抱歉,该文件版本不兼容,文件版本错误。");
|
||||
}
|
||||
if (isHtmlView) {
|
||||
// 对转换后的文件进行操作(改变编码方式)
|
||||
fileHandlerService.doActionConvertedFile(outFilePath);
|
||||
}
|
||||
//是否保留OFFICE源文件
|
||||
if (!fileAttribute.isCompressFile() && ConfigConstants.getDeleteSourceFile()) {
|
||||
KkFileUtils.deleteFileByPath(filePath);
|
||||
}
|
||||
if (userToken || !isPwdProtectedOffice) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (!isHtmlView && baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
|
||||
return getPreviewType(model, fileAttribute, officePreviewType, cacheName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
|
||||
}
|
||||
model.addAttribute("pdfUrl", WebUtils.encodeFileName(cacheName)); //输出转义文件名 方便url识别
|
||||
return isHtmlView ? EXEL_FILE_PREVIEW_PAGE : PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
static String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String pdfName, String outFilePath, FileHandlerService fileHandlerService, String officePreviewTypeImage, OtherFilePreviewImpl otherFilePreview) {
|
||||
String suffix = fileAttribute.getSuffix();
|
||||
boolean isPPT = suffix.equalsIgnoreCase("ppt") || suffix.equalsIgnoreCase("pptx");
|
||||
List<String> imageUrls = null;
|
||||
try {
|
||||
imageUrls = fileHandlerService.pdf2jpg(outFilePath,outFilePath, pdfName, fileAttribute);
|
||||
} catch (Exception e) {
|
||||
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
||||
for (Throwable throwable : throwableArray) {
|
||||
if (throwable instanceof IOException || throwable instanceof EncryptedDocumentException) {
|
||||
if (e.getMessage().toLowerCase().contains(OFFICE_PASSWORD_MSG)) {
|
||||
model.addAttribute("needFilePassword", true);
|
||||
return EXEL_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (imageUrls == null || imageUrls.size() < 1) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "office转图片异常,请联系管理员");
|
||||
}
|
||||
model.addAttribute("imgUrls", imageUrls);
|
||||
model.addAttribute("currentUrl", imageUrls.get(0));
|
||||
if (officePreviewTypeImage.equals(officePreviewType)) {
|
||||
// PPT 图片模式使用专用预览页面
|
||||
return (isPPT ? PPT_FILE_PREVIEW_PAGE : OFFICE_PICTURE_FILE_PREVIEW_PAGE);
|
||||
} else {
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :图片文件处理
|
||||
*/
|
||||
@Service
|
||||
public class Online3DFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public Online3DFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return ONLINE3D_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :其他文件
|
||||
*/
|
||||
@Service
|
||||
public class OtherFilePreviewImpl implements FilePreview {
|
||||
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
return this.notSupportedFile(model, fileAttribute, "系统还不支持该格式文件的在线预览");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, FileAttribute fileAttribute, String errMsg) {
|
||||
return this.notSupportedFile(model, fileAttribute.getSuffix(), errMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, String errMsg) {
|
||||
return this.notSupportedFile(model, "未知", errMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的预览失败,导向到不支持的文件响应页面
|
||||
*
|
||||
* @return 页面
|
||||
*/
|
||||
public String notSupportedFile(Model model, String fileType, String errMsg) {
|
||||
model.addAttribute("fileType", KkFileUtils.htmlEscape(fileType));
|
||||
model.addAttribute("msg", KkFileUtils.htmlEscape(errMsg));
|
||||
return NOT_SUPPORTED_FILE_PAGE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :处理pdf文件
|
||||
*/
|
||||
@Service
|
||||
public class PdfFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
private static final String PDF_PASSWORD_MSG = "password";
|
||||
public PdfFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
String pdfName = fileAttribute.getName(); //获取原始文件名
|
||||
String officePreviewType = fileAttribute.getOfficePreviewType(); //转换类型
|
||||
boolean forceUpdatedCache=fileAttribute.forceUpdatedCache(); //是否启用强制更新命令
|
||||
String outFilePath = fileAttribute.getOutFilePath(); //生成的文件路径
|
||||
String originFilePath = fileAttribute.getOriginFilePath(); //原始文件路径
|
||||
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType)) {
|
||||
//当文件不存在时,就去下载
|
||||
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, pdfName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
originFilePath = response.getContent();
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(originFilePath));
|
||||
}
|
||||
}
|
||||
List<String> imageUrls;
|
||||
try {
|
||||
imageUrls = fileHandlerService.pdf2jpg(originFilePath,outFilePath, pdfName, fileAttribute);
|
||||
} catch (Exception e) {
|
||||
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
||||
for (Throwable throwable : throwableArray) {
|
||||
if (throwable instanceof IOException || throwable instanceof EncryptedDocumentException) {
|
||||
if (e.getMessage().toLowerCase().contains(PDF_PASSWORD_MSG)) {
|
||||
model.addAttribute("needFilePassword", true);
|
||||
return EXEL_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "pdf转图片异常,请联系管理员");
|
||||
}
|
||||
if (imageUrls == null || imageUrls.size() < 1) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "pdf转图片异常,请联系管理员");
|
||||
}
|
||||
model.addAttribute("imgUrls", imageUrls);
|
||||
model.addAttribute("currentUrl", imageUrls.get(0));
|
||||
if (OfficeFilePreviewImpl.OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType)) {
|
||||
return OFFICE_PICTURE_FILE_PREVIEW_PAGE;
|
||||
} else {
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
} else {
|
||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||
if (!fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, pdfName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
model.addAttribute("pdfUrl", fileHandlerService.getRelativePath(response.getContent()));
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(pdfName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
} else {
|
||||
model.addAttribute("pdfUrl", WebUtils.encodeFileName(pdfName));
|
||||
}
|
||||
} else {
|
||||
model.addAttribute("pdfUrl", url);
|
||||
}
|
||||
}
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :图片文件处理
|
||||
*/
|
||||
@Service
|
||||
public class PictureFilePreviewImpl extends CommonPreviewImpl {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
|
||||
public PictureFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
||||
super(fileHandlerService, otherFilePreview);
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
url= KkFileUtils.htmlEscape(url);
|
||||
List<String> imgUrls = new ArrayList<>();
|
||||
imgUrls.add(url);
|
||||
String compressFileKey = fileAttribute.getCompressFileKey();
|
||||
List<String> zipImgUrls = fileHandlerService.getImgCache(compressFileKey);
|
||||
if (!CollectionUtils.isEmpty(zipImgUrls)) {
|
||||
imgUrls.addAll(zipImgUrls);
|
||||
}
|
||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||
super.filePreviewHandle(url, model, fileAttribute);
|
||||
model.addAttribute("imgUrls", imgUrls);
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.utils.EncodingDetects;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/1/17.
|
||||
* Content :处理文本文件
|
||||
*/
|
||||
@Service
|
||||
public class SimTextFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
|
||||
public SimTextFilePreviewImpl(FileHandlerService fileHandlerService,OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
String fileName = fileAttribute.getName();
|
||||
boolean forceUpdatedCache=fileAttribute.forceUpdatedCache();
|
||||
String filePath = fileAttribute.getOriginFilePath();
|
||||
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(fileName) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
filePath = response.getContent();
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
fileHandlerService.addConvertedFile(fileName, filePath); //加入缓存
|
||||
}
|
||||
try {
|
||||
String fileData = HtmlUtils.htmlEscape(textData(filePath,fileName));
|
||||
model.addAttribute("textData", Base64.encodeBase64String(fileData.getBytes()));
|
||||
} catch (IOException e) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, e.getLocalizedMessage());
|
||||
}
|
||||
return TXT_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
String fileData = null;
|
||||
try {
|
||||
fileData = HtmlUtils.htmlEscape(textData(filePath,fileName));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
model.addAttribute("textData", Base64.encodeBase64String(fileData.getBytes()));
|
||||
return TXT_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
private String textData(String filePath,String fileName) throws IOException {
|
||||
File file = new File(filePath);
|
||||
if (KkFileUtils.isIllegalFileName(fileName)) {
|
||||
return null;
|
||||
}
|
||||
if (!file.exists() || file.length() == 0) {
|
||||
return "";
|
||||
} else {
|
||||
String charset = EncodingDetects.getJavaEncode(filePath);
|
||||
if ("ASCII".equals(charset)) {
|
||||
charset = StandardCharsets.US_ASCII.name();
|
||||
}
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), charset));
|
||||
StringBuilder result = new StringBuilder();
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
result.append(line).append("\r\n");
|
||||
}
|
||||
br.close();
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* svg 图片文件处理
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2021/2/8
|
||||
*/
|
||||
@Service
|
||||
public class SvgFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public SvgFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return SVG_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.utils.ConvertPicUtil;
|
||||
import cn.keking.utils.DownloadUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* tiff 图片文件处理
|
||||
*
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2021/2/8
|
||||
*/
|
||||
@Service
|
||||
public class TiffFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
public TiffFilePreviewImpl(FileHandlerService fileHandlerService,OtherFilePreviewImpl otherFilePreview) {
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
String fileName = fileAttribute.getName();
|
||||
String tifPreviewType = ConfigConstants.getTifPreviewType();
|
||||
String cacheName = fileAttribute.getCacheName();
|
||||
String outFilePath = fileAttribute.getOutFilePath();
|
||||
boolean forceUpdatedCache=fileAttribute.forceUpdatedCache();
|
||||
if ("jpg".equalsIgnoreCase(tifPreviewType) || "pdf".equalsIgnoreCase(tifPreviewType)) {
|
||||
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(cacheName) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
String filePath = response.getContent();
|
||||
if ("pdf".equalsIgnoreCase(tifPreviewType)) {
|
||||
try {
|
||||
ConvertPicUtil.convertJpg2Pdf(filePath, outFilePath);
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) {
|
||||
model.addAttribute("imgUrls", url);
|
||||
model.addAttribute("currentUrl", url);
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}else {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "TIF转pdf异常,请联系系统管理员!" );
|
||||
}
|
||||
}
|
||||
//是否保留TIFF源文件
|
||||
if (!fileAttribute.isCompressFile() && ConfigConstants.getDeleteSourceFile()) {
|
||||
// KkFileUtils.deleteFileByPath(filePath);
|
||||
}
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
model.addAttribute("pdfUrl", WebUtils.encodeFileName(cacheName));
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}else {
|
||||
// 将tif转换为jpg,返回转换后的文件路径、文件名的list
|
||||
List<String> listPic2Jpg;
|
||||
try {
|
||||
listPic2Jpg = ConvertPicUtil.convertTif2Jpg(filePath, outFilePath,forceUpdatedCache);
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) {
|
||||
model.addAttribute("imgUrls", url);
|
||||
model.addAttribute("currentUrl", url);
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}else {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "TIF转JPG异常,请联系系统管理员!" );
|
||||
}
|
||||
}
|
||||
//是否保留源文件,转换失败保留源文件,转换成功删除源文件
|
||||
if(!fileAttribute.isCompressFile() && ConfigConstants.getDeleteSourceFile()) {
|
||||
KkFileUtils.deleteFileByPath(filePath);
|
||||
}
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.putImgCache(cacheName, listPic2Jpg);
|
||||
fileHandlerService.addConvertedFile(cacheName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
model.addAttribute("imgUrls", listPic2Jpg);
|
||||
model.addAttribute("currentUrl", listPic2Jpg.get(0));
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
if ("pdf".equalsIgnoreCase(tifPreviewType)) {
|
||||
model.addAttribute("pdfUrl", WebUtils.encodeFileName(cacheName));
|
||||
return PDF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
else if ("jpg".equalsIgnoreCase(tifPreviewType)) {
|
||||
model.addAttribute("imgUrls", fileHandlerService.getImgCache(cacheName));
|
||||
model.addAttribute("currentUrl", fileHandlerService.getImgCache(cacheName).get(0));
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
// 不是http开头,浏览器不能直接访问,需下载到本地
|
||||
if (url != null && !url.toLowerCase().startsWith("http")) {
|
||||
if (forceUpdatedCache || !fileHandlerService.listConvertedFiles().containsKey(fileName) || !ConfigConstants.isCacheEnabled()) {
|
||||
ReturnResponse<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
|
||||
if (response.isFailure()) {
|
||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||
}
|
||||
model.addAttribute("currentUrl", fileHandlerService.getRelativePath(response.getContent()));
|
||||
if (ConfigConstants.isCacheEnabled()) {
|
||||
// 加入缓存
|
||||
fileHandlerService.addConvertedFile(fileName, fileHandlerService.getRelativePath(outFilePath));
|
||||
}
|
||||
} else {
|
||||
model.addAttribute("currentUrl", WebUtils.encodeFileName(fileName));
|
||||
}
|
||||
return TIFF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
model.addAttribute("currentUrl", url);
|
||||
return TIFF_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* svg 图片文件处理
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2021/2/8
|
||||
*/
|
||||
@Service
|
||||
public class XmindFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final CommonPreviewImpl commonPreview;
|
||||
|
||||
public XmindFilePreviewImpl(CommonPreviewImpl commonPreview) {
|
||||
this.commonPreview = commonPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
commonPreview.filePreviewHandle(url,model,fileAttribute);
|
||||
return XMIND_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.keking.service.impl;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FilePreview;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2020/12/25
|
||||
*/
|
||||
@Service
|
||||
public class XmlFilePreviewImpl implements FilePreview {
|
||||
|
||||
private final SimTextFilePreviewImpl simTextFilePreview;
|
||||
|
||||
public XmlFilePreviewImpl(SimTextFilePreviewImpl simTextFilePreview) {
|
||||
this.simTextFilePreview = simTextFilePreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||
simTextFilePreview.filePreviewHandle(url, model, fileAttribute);
|
||||
return XML_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Random;
|
||||
|
||||
public class CaptchaUtil {
|
||||
|
||||
public static final String CAPTCHA_CODE = "captchaCode";
|
||||
public static final String CAPTCHA_GENERATE_TIME = "captchaTime";
|
||||
|
||||
private static final int WIDTH = 100;// 定义图片的width
|
||||
private static final int HEIGHT = 30;// 定义图片的height
|
||||
private static final int CODE_LENGTH = 4;// 定义图片上显示验证码的个数
|
||||
private static final int FONT_HEIGHT = 28;
|
||||
private static final char[] CODE_SEQUENCE = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', '2', '3', '4', '5', '6', '7', '8', '9'};
|
||||
|
||||
/**
|
||||
* 指定验证码、生成验证码图片。
|
||||
* @param captchaCode 验证码
|
||||
* @return 验证码图片
|
||||
*/
|
||||
public static BufferedImage generateCaptchaPic(final String captchaCode) {
|
||||
Assert.notNull(captchaCode, "captchaCode must not be null");
|
||||
// 定义图像buffer
|
||||
BufferedImage buffImg = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics gd = buffImg.getGraphics();
|
||||
Random random = new Random();
|
||||
// 将图像填充为白色
|
||||
gd.setColor(Color.WHITE);
|
||||
gd.fillRect(0, 0, WIDTH, HEIGHT);
|
||||
Font font = new Font("Times New Roman", Font.BOLD, FONT_HEIGHT);
|
||||
gd.setFont(font);
|
||||
// 画边框。
|
||||
gd.setColor(Color.BLACK);
|
||||
gd.drawRect(0, 0, WIDTH - 1, HEIGHT - 1);
|
||||
|
||||
// 随机产生40条干扰线,使图象中的认证码不易被其它程序探测到。
|
||||
gd.setColor(Color.BLACK);
|
||||
for (int i = 0; i < 30; i++) {
|
||||
int x = random.nextInt(WIDTH);
|
||||
int y = random.nextInt(HEIGHT);
|
||||
int xl = random.nextInt(12);
|
||||
int yl = random.nextInt(12);
|
||||
gd.drawLine(x, y, x + xl, y + yl);
|
||||
}
|
||||
// randomCode用于保存随机产生的验证码,以便用户登录后进行验证。
|
||||
int red, green, blue;
|
||||
// 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同。
|
||||
red = random.nextInt(255);
|
||||
green = random.nextInt(255);
|
||||
blue = random.nextInt(255);
|
||||
// 用随机产生的颜色将验证码绘制到图像中。
|
||||
gd.setColor(new Color(red, green, blue));
|
||||
gd.drawString(captchaCode, 18, 27);
|
||||
return buffImg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机字符串。
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String generateCaptchaCode() {
|
||||
Random random = new Random();
|
||||
StringBuilder randomCode = new StringBuilder();
|
||||
for (int i = 0; i < CODE_LENGTH; i++) {
|
||||
randomCode.append(CODE_SEQUENCE[random.nextInt(52)]);
|
||||
}
|
||||
return randomCode.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author : kl
|
||||
**/
|
||||
public class ConfigUtils {
|
||||
|
||||
private static final String MAIN_DIRECTORY_NAME = "tool-tech-file-view";
|
||||
|
||||
public static String getHomePath() {
|
||||
String userDir = System.getenv("KKFILEVIEW_BIN_FOLDER");
|
||||
if (userDir == null) {
|
||||
userDir = System.getProperty("user.dir");
|
||||
}
|
||||
if (userDir.endsWith("bin")) {
|
||||
userDir = userDir.substring(0, userDir.length() - 4);
|
||||
} else {
|
||||
String separator = File.separator;
|
||||
if (userDir.endsWith(MAIN_DIRECTORY_NAME)) {
|
||||
userDir = userDir + separator + "src" + separator + "main";
|
||||
} else {
|
||||
userDir = userDir + separator + MAIN_DIRECTORY_NAME + separator + "src" + separator + "main";
|
||||
}
|
||||
}
|
||||
return userDir;
|
||||
}
|
||||
|
||||
// 获取环境变量,如果找不到则返回默认值
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static String getEnvOrDefault(String key, String def) {
|
||||
String value = System.getenv(key);
|
||||
return value == null ? def : value;
|
||||
}
|
||||
|
||||
// 返回参数列表中第一个真实存在的路径,或者 null
|
||||
private static String firstExists(File... paths) {
|
||||
for (File path : paths) {
|
||||
if (path.exists()) {
|
||||
return path.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getUserDir() {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String binFolder = getEnvOrDefault("KKFILEVIEW_BIN_FOLDER", userDir);
|
||||
|
||||
File pluginPath = new File(binFolder);
|
||||
|
||||
// 如果指定了 bin 或其父目录,则返回父目录
|
||||
if (new File(pluginPath, "bin").exists()) {
|
||||
return pluginPath.getAbsolutePath();
|
||||
|
||||
} else if (pluginPath.exists() && pluginPath.getName().equals("bin")) {
|
||||
return pluginPath.getParentFile().getAbsolutePath();
|
||||
|
||||
} else {
|
||||
return firstExists(new File(pluginPath, MAIN_DIRECTORY_NAME),
|
||||
new File(pluginPath.getParentFile(), MAIN_DIRECTORY_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCustomizedConfigPath() {
|
||||
String homePath = getHomePath();
|
||||
String separator = java.io.File.separator;
|
||||
return homePath + separator + "config" + separator + "application.properties";
|
||||
}
|
||||
|
||||
public synchronized static void restorePropertiesFromEnvFormat(Properties properties) {
|
||||
Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<Object, Object> entry = iterator.next();
|
||||
String key = entry.getKey().toString();
|
||||
String value = entry.getValue().toString();
|
||||
if (value.trim().startsWith("${") && value.trim().endsWith("}")) {
|
||||
int beginIndex = value.indexOf(":");
|
||||
if (beginIndex < 0) {
|
||||
beginIndex = value.length() - 1;
|
||||
}
|
||||
int endIndex = value.length() - 1;
|
||||
String envKey = value.substring(2, beginIndex);
|
||||
String envValue = System.getenv(envKey);
|
||||
if (envValue == null || "".equals(envValue.trim())) {
|
||||
value = value.substring(beginIndex + 1, endIndex);
|
||||
} else {
|
||||
value = envValue;
|
||||
}
|
||||
properties.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.Image;
|
||||
import com.itextpdf.text.io.FileChannelRandomAccessSource;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
|
||||
import com.itextpdf.text.pdf.codec.TiffImage;
|
||||
import com.sun.media.jai.codec.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.media.jai.JAI;
|
||||
import javax.media.jai.RenderedOp;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.renderable.ParameterBlock;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ConvertPicUtil {
|
||||
|
||||
private static final int FIT_WIDTH = 500;
|
||||
private static final int FIT_HEIGHT = 900;
|
||||
private final static Logger logger = LoggerFactory.getLogger(ConvertPicUtil.class);
|
||||
private final static String fileDir = ConfigConstants.getFileDir();
|
||||
/**
|
||||
* Tif 转 JPG。
|
||||
*
|
||||
* @param strInputFile 输入文件的路径和文件名
|
||||
* @param strOutputFile 输出文件的路径和文件名
|
||||
* @return boolean 是否转换成功
|
||||
*/
|
||||
public static List<String> convertTif2Jpg(String strInputFile, String strOutputFile, boolean forceUpdatedCache) throws Exception {
|
||||
List<String> listImageFiles = new ArrayList<>();
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
if (!new File(strInputFile).exists()) {
|
||||
logger.info("找不到文件【" + strInputFile + "】");
|
||||
return null;
|
||||
}
|
||||
strOutputFile = strOutputFile.replaceAll(".jpg", "");
|
||||
FileSeekableStream fileSeekStream = null;
|
||||
try {
|
||||
JPEGEncodeParam jpegEncodeParam = new JPEGEncodeParam();
|
||||
TIFFEncodeParam tiffEncodeParam = new TIFFEncodeParam();
|
||||
tiffEncodeParam.setCompression(TIFFEncodeParam.COMPRESSION_GROUP4);
|
||||
tiffEncodeParam.setLittleEndian(false);
|
||||
fileSeekStream = new FileSeekableStream(strInputFile);
|
||||
ImageDecoder imageDecoder = ImageCodec.createImageDecoder("TIFF", fileSeekStream, null);
|
||||
int intTifCount = imageDecoder.getNumPages();
|
||||
// logger.info("该tif文件共有【" + intTifCount + "】页");
|
||||
// 处理目标文件夹,如果不存在则自动创建
|
||||
File fileJpgPath = new File(strOutputFile);
|
||||
if (!fileJpgPath.exists() && !fileJpgPath.mkdirs()) {
|
||||
logger.error("{} 创建失败", strOutputFile);
|
||||
}
|
||||
// 循环,处理每页tif文件,转换为jpg
|
||||
for (int i = 0; i < intTifCount; i++) {
|
||||
String strJpg= strOutputFile + "/" + i + ".jpg";
|
||||
File fileJpg = new File(strJpg);
|
||||
// 如果文件不存在,则生成
|
||||
if (forceUpdatedCache|| !fileJpg.exists()) {
|
||||
RenderedImage renderedImage = imageDecoder.decodeAsRenderedImage(i);
|
||||
ParameterBlock pb = new ParameterBlock();
|
||||
pb.addSource(renderedImage);
|
||||
pb.add(fileJpg.toString());
|
||||
pb.add("JPEG");
|
||||
pb.add(jpegEncodeParam);
|
||||
RenderedOp renderedOp = JAI.create("filestore", pb);
|
||||
renderedOp.dispose();
|
||||
// logger.info("每页分别保存至: " + fileJpg.getCanonicalPath());
|
||||
}
|
||||
strJpg = baseUrl+strJpg.replace(fileDir, "");
|
||||
listImageFiles.add(strJpg);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (!e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) {
|
||||
logger.error("TIF转JPG异常,文件路径:" + strInputFile, e);
|
||||
}
|
||||
throw new Exception(e);
|
||||
} finally {
|
||||
if (fileSeekStream != null) {
|
||||
fileSeekStream.close();
|
||||
}
|
||||
}
|
||||
return listImageFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Jpg图片转换为Pdf文件
|
||||
*
|
||||
* @param strJpgFile 输入的jpg的路径和文件名
|
||||
* @param strPdfFile 输出的pdf的路径和文件名
|
||||
*/
|
||||
public static String convertJpg2Pdf(String strJpgFile, String strPdfFile) throws Exception {
|
||||
Document document = new Document();
|
||||
RandomAccessFileOrArray rafa = null;
|
||||
FileOutputStream outputStream = null;
|
||||
try {
|
||||
RandomAccessFile aFile = new RandomAccessFile(strJpgFile, "r");
|
||||
FileChannel inChannel = aFile.getChannel();
|
||||
FileChannelRandomAccessSource fcra = new FileChannelRandomAccessSource(inChannel);
|
||||
rafa = new RandomAccessFileOrArray(fcra);
|
||||
int pages = TiffImage.getNumberOfPages(rafa);
|
||||
outputStream = new FileOutputStream(strPdfFile);
|
||||
PdfWriter.getInstance(document, outputStream);
|
||||
document.open();
|
||||
Image image;
|
||||
for (int i = 1; i <= pages; i++) {
|
||||
image = TiffImage.getTiffImage(rafa, i);
|
||||
image.scaleToFit(FIT_WIDTH, FIT_HEIGHT);
|
||||
document.add(image);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (!e.getMessage().contains("Bad endianness tag (not 0x4949 or 0x4d4d)") ) {
|
||||
logger.error("TIF转JPG异常,文件路径:" + strPdfFile, e);
|
||||
}
|
||||
throw new Exception(e);
|
||||
} finally {
|
||||
if (document != null) {
|
||||
document.close();
|
||||
}
|
||||
if (rafa != null) {
|
||||
rafa.close();
|
||||
}
|
||||
if (outputStream != null) {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
return strPdfFile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* @author kl (http://kailing.pub)
|
||||
* @since 2023/8/11
|
||||
*/
|
||||
public class DateUtils {
|
||||
/**
|
||||
* 获取当前时间的秒级时间戳
|
||||
* @return
|
||||
*/
|
||||
public static long getCurrentSecond() {
|
||||
return Instant.now().getEpochSecond();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算当前时间与指定时间的秒级时间戳差值
|
||||
* @param datetime 指定时间
|
||||
* @return 差值
|
||||
*/
|
||||
public static long calculateCurrentTimeDifference(long datetime) {
|
||||
return getCurrentSecond() - datetime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.DefaultRedirectStrategy;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RequestCallback;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static cn.keking.utils.KkFileUtils.isFtpUrl;
|
||||
import static cn.keking.utils.KkFileUtils.isHttpUrl;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
*/
|
||||
public class DownloadUtils {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(DownloadUtils.class);
|
||||
private static final String fileDir = ConfigConstants.getFileDir();
|
||||
private static final String URL_PARAM_FTP_USERNAME = "ftp.username";
|
||||
private static final String URL_PARAM_FTP_PASSWORD = "ftp.password";
|
||||
private static final String URL_PARAM_FTP_CONTROL_ENCODING = "ftp.control.encoding";
|
||||
private static final RestTemplate restTemplate = new RestTemplate();
|
||||
private static final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
|
||||
/**
|
||||
* @param fileAttribute fileAttribute
|
||||
* @param fileName 文件名
|
||||
* @return 本地文件绝对路径
|
||||
*/
|
||||
public static ReturnResponse<String> downLoad(FileAttribute fileAttribute, String fileName) {
|
||||
// 忽略ssl证书
|
||||
String urlStr = null;
|
||||
try {
|
||||
SslUtils.ignoreSsl();
|
||||
urlStr = fileAttribute.getUrl().replaceAll("\\+", "%20").replaceAll(" ", "%20");
|
||||
} catch (Exception e) {
|
||||
logger.error("忽略SSL证书异常:", e);
|
||||
}
|
||||
ReturnResponse<String> response = new ReturnResponse<>(0, "下载成功!!!", "");
|
||||
String realPath = getRelFilePath(fileName, fileAttribute);
|
||||
|
||||
// 判断是否非法地址
|
||||
if (KkFileUtils.isIllegalFileName(realPath)) {
|
||||
response.setCode(1);
|
||||
response.setContent(null);
|
||||
response.setMsg("下载失败:文件名不合法!" + urlStr);
|
||||
return response;
|
||||
}
|
||||
if (!KkFileUtils.isAllowedUpload(realPath)) {
|
||||
response.setCode(1);
|
||||
response.setContent(null);
|
||||
response.setMsg("下载失败:不支持的类型!" + urlStr);
|
||||
return response;
|
||||
}
|
||||
if (fileAttribute.isCompressFile()) { //压缩包文件 直接赋予路径 不予下载
|
||||
response.setContent(fileDir + fileName);
|
||||
response.setMsg(fileName);
|
||||
return response;
|
||||
}
|
||||
// 如果文件是否已经存在、且不强制更新,则直接返回文件路径
|
||||
if (KkFileUtils.isExist(realPath) && !fileAttribute.forceUpdatedCache()) {
|
||||
response.setContent(realPath);
|
||||
response.setMsg(fileName);
|
||||
return response;
|
||||
}
|
||||
try {
|
||||
URL url = WebUtils.normalizedURL(urlStr);
|
||||
if (!fileAttribute.getSkipDownLoad()) {
|
||||
if (isHttpUrl(url)) {
|
||||
File realFile = new File(realPath);
|
||||
factory.setConnectionRequestTimeout(2000); //设置超时时间
|
||||
factory.setConnectTimeout(10000);
|
||||
factory.setReadTimeout(72000);
|
||||
HttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new DefaultRedirectStrategy()).build();
|
||||
factory.setHttpClient(httpClient); //加入重定向方法
|
||||
restTemplate.setRequestFactory(factory);
|
||||
RequestCallback requestCallback = request -> {
|
||||
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
||||
String proxyAuthorization = fileAttribute.getKkProxyAuthorization();
|
||||
if(StringUtils.hasText(proxyAuthorization)){
|
||||
Map<String,String> proxyAuthorizationMap = mapper.readValue(proxyAuthorization, Map.class);
|
||||
proxyAuthorizationMap.forEach((key, value) -> request.getHeaders().set(key, value));
|
||||
}
|
||||
};
|
||||
try {
|
||||
restTemplate.execute(url.toURI(), HttpMethod.GET, requestCallback, fileResponse -> {
|
||||
FileUtils.copyToFile(fileResponse.getBody(), realFile);
|
||||
return null;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
response.setCode(1);
|
||||
response.setContent(null);
|
||||
response.setMsg("下载失败:" + e);
|
||||
return response;
|
||||
}
|
||||
} else if (isFtpUrl(url)) {
|
||||
String ftpUsername = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_USERNAME);
|
||||
String ftpPassword = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_PASSWORD);
|
||||
String ftpControlEncoding = WebUtils.getUrlParameterReg(fileAttribute.getUrl(), URL_PARAM_FTP_CONTROL_ENCODING);
|
||||
FtpUtils.download(fileAttribute.getUrl(), realPath, ftpUsername, ftpPassword, ftpControlEncoding);
|
||||
} else {
|
||||
response.setCode(1);
|
||||
response.setMsg("url不能识别url" + urlStr);
|
||||
}
|
||||
}
|
||||
response.setContent(realPath);
|
||||
response.setMsg(fileName);
|
||||
return response;
|
||||
} catch (IOException | GalimatiasParseException e) {
|
||||
logger.error("文件下载失败,url:{}", urlStr);
|
||||
response.setCode(1);
|
||||
response.setContent(null);
|
||||
if (e instanceof FileNotFoundException) {
|
||||
response.setMsg("文件不存在!!!");
|
||||
} else {
|
||||
response.setMsg(e.getMessage());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取真实文件绝对路径
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 文件路径
|
||||
*/
|
||||
private static String getRelFilePath(String fileName, FileAttribute fileAttribute) {
|
||||
String type = fileAttribute.getSuffix();
|
||||
if (null == fileName) {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
fileName = uuid + "." + type;
|
||||
} else { // 文件后缀不一致时,以type为准(针对simText【将类txt文件转为txt】)
|
||||
fileName = fileName.replace(fileName.substring(fileName.lastIndexOf(".") + 1), type);
|
||||
}
|
||||
|
||||
String realPath = fileDir + fileName;
|
||||
File dirFile = new File(fileDir);
|
||||
if (!dirFile.exists() && !dirFile.mkdirs()) {
|
||||
logger.error("创建目录【{}】失败,可能是权限不够,请检查", fileDir);
|
||||
}
|
||||
return realPath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import org.mozilla.universalchardet.UniversalDetector;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* @author asiawu
|
||||
* @date 2023/07/20 17:26
|
||||
* @description: 自动获取文件的编码
|
||||
*/
|
||||
public class EncodingDetects {
|
||||
private static final int DEFAULT_LENGTH = 4096;
|
||||
private static final int LIMIT = 50;
|
||||
private static final Logger logger = LoggerFactory.getLogger(EncodingDetects.class);
|
||||
|
||||
public static String getJavaEncode(String filePath) {
|
||||
return getJavaEncode(new File(filePath));
|
||||
}
|
||||
|
||||
public static String getJavaEncode(File file) {
|
||||
int len = Math.min(DEFAULT_LENGTH, (int) file.length());
|
||||
byte[] content = new byte[len];
|
||||
try (InputStream fis = Files.newInputStream(file.toPath())) {
|
||||
fis.read(content, 0, len);
|
||||
} catch (IOException e) {
|
||||
logger.error("文件读取失败:{}", file.getPath());
|
||||
}
|
||||
return getJavaEncode(content);
|
||||
}
|
||||
|
||||
public static String getJavaEncode(byte[] content) {
|
||||
if (content != null && content.length <= LIMIT) {
|
||||
return SimpleEncodingDetects.getJavaEncode(content);
|
||||
}
|
||||
UniversalDetector detector = new UniversalDetector(null);
|
||||
detector.handleData(content, 0, content.length);
|
||||
detector.dataEnd();
|
||||
String charsetName = detector.getDetectedCharset();
|
||||
if (charsetName == null) {
|
||||
charsetName = Charset.defaultCharset().name();
|
||||
}
|
||||
return charsetName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
public class FileHeaderRar {
|
||||
|
||||
private String fileNameW;
|
||||
private Boolean isDirectory;
|
||||
|
||||
public FileHeaderRar(String fileNameW, Boolean isDirectory) {
|
||||
this.fileNameW = fileNameW;
|
||||
this.isDirectory = isDirectory;
|
||||
}
|
||||
|
||||
public String getFileNameW() {
|
||||
return fileNameW;
|
||||
}
|
||||
|
||||
public void setFileNameW(String fileNameW) {
|
||||
this.fileNameW = fileNameW;
|
||||
}
|
||||
|
||||
public Boolean getDirectory() {
|
||||
return isDirectory;
|
||||
}
|
||||
|
||||
public void setDirectory(Boolean directory) {
|
||||
isDirectory = directory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
import org.apache.commons.net.ftp.FTPReply;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* @auther: chenjh
|
||||
* @since: 2019/6/18 14:36
|
||||
*/
|
||||
public class FtpUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FtpUtils.class);
|
||||
|
||||
public static FTPClient connect(String host, int port, String username, String password, String controlEncoding) throws IOException {
|
||||
FTPClient ftpClient = new FTPClient();
|
||||
ftpClient.connect(host, port);
|
||||
if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
|
||||
ftpClient.login(username, password);
|
||||
}
|
||||
int reply = ftpClient.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
ftpClient.disconnect();
|
||||
}
|
||||
ftpClient.setControlEncoding(controlEncoding);
|
||||
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
|
||||
return ftpClient;
|
||||
}
|
||||
|
||||
public static void download(String ftpUrl, String localFilePath, String ftpUsername, String ftpPassword, String ftpControlEncoding) throws IOException {
|
||||
String username = StringUtils.isEmpty(ftpUsername) ? ConfigConstants.getFtpUsername() : ftpUsername;
|
||||
String password = StringUtils.isEmpty(ftpPassword) ? ConfigConstants.getFtpPassword() : ftpPassword;
|
||||
String controlEncoding = StringUtils.isEmpty(ftpControlEncoding) ? ConfigConstants.getFtpControlEncoding() : ftpControlEncoding;
|
||||
URL url = new URL(ftpUrl);
|
||||
String host = url.getHost();
|
||||
int port = (url.getPort() == -1) ? url.getDefaultPort() : url.getPort();
|
||||
String remoteFilePath = url.getPath();
|
||||
LOGGER.debug("FTP connection url:{}, username:{}, password:{}, controlEncoding:{}, localFilePath:{}", ftpUrl, username, password, controlEncoding, localFilePath);
|
||||
FTPClient ftpClient = connect(host, port, username, password, controlEncoding);
|
||||
OutputStream outputStream = Files.newOutputStream(Paths.get(localFilePath));
|
||||
ftpClient.enterLocalPassiveMode();
|
||||
boolean downloadResult = ftpClient.retrieveFile(new String(remoteFilePath.getBytes(controlEncoding), StandardCharsets.ISO_8859_1), outputStream);
|
||||
LOGGER.debug("FTP download result {}", downloadResult);
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
ftpClient.logout();
|
||||
ftpClient.disconnect();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class KkFileUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KkFileUtils.class);
|
||||
|
||||
public static final String DEFAULT_FILE_ENCODING = "UTF-8";
|
||||
|
||||
private static final List<String> illegalFileStrList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
illegalFileStrList.add("../");
|
||||
illegalFileStrList.add("./");
|
||||
illegalFileStrList.add("..\\");
|
||||
illegalFileStrList.add(".\\");
|
||||
illegalFileStrList.add("\\..");
|
||||
illegalFileStrList.add("\\.");
|
||||
illegalFileStrList.add("..");
|
||||
illegalFileStrList.add("...");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件名是否合规
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 合规结果, true:不合规,false:合规
|
||||
*/
|
||||
public static boolean isIllegalFileName(String fileName) {
|
||||
for (String str : illegalFileStrList) {
|
||||
if (fileName.contains(str)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否是数字
|
||||
*
|
||||
* @param str 文件名
|
||||
* @return 合规结果, true:不合规,false:合规
|
||||
*/
|
||||
public static boolean isInteger(String str) {
|
||||
if (StringUtils.hasText(str)) {
|
||||
boolean strResult = str.matches("-?[0-9]+.?[0-9]*");
|
||||
return strResult;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断url是否是http资源
|
||||
*
|
||||
* @param url url
|
||||
* @return 是否http
|
||||
*/
|
||||
public static boolean isHttpUrl(URL url) {
|
||||
return url.getProtocol().toLowerCase().startsWith("file") || url.getProtocol().toLowerCase().startsWith("http");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断url是否是ftp资源
|
||||
*
|
||||
* @param url url
|
||||
* @return 是否ftp
|
||||
*/
|
||||
public static boolean isFtpUrl(URL url) {
|
||||
return "ftp".equalsIgnoreCase(url.getProtocol());
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个文件
|
||||
*
|
||||
* @param fileName 要删除的文件的文件名
|
||||
* @return 单个文件删除成功返回true,否则返回false
|
||||
*/
|
||||
public static boolean deleteFileByName(String fileName) {
|
||||
File file = new File(fileName);
|
||||
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
|
||||
if (file.exists() && file.isFile()) {
|
||||
if (file.delete()) {
|
||||
LOGGER.info("删除单个文件" + fileName + "成功!");
|
||||
return true;
|
||||
} else {
|
||||
LOGGER.info("删除单个文件" + fileName + "失败!");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("删除单个文件失败:" + fileName + "不存在!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String htmlEscape(String input) {
|
||||
if (StringUtils.hasText(input)) {
|
||||
//input = input.replaceAll("\\{", "%7B").replaceAll("}", "%7D").replaceAll("\\\\", "%5C");
|
||||
String htmlStr = HtmlUtils.htmlEscape(input, "UTF-8");
|
||||
//& -> &
|
||||
return htmlStr.replace("&", "&");
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过文件名获取文件后缀
|
||||
*
|
||||
* @param fileName 文件名称
|
||||
* @return 文件后缀
|
||||
*/
|
||||
public static String suffixFromFileName(String fileName) {
|
||||
return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据文件路径删除文件
|
||||
*
|
||||
* @param filePath 绝对路径
|
||||
*/
|
||||
public static void deleteFileByPath(String filePath) {
|
||||
File file = new File(filePath);
|
||||
if (file.exists() && !file.delete()) {
|
||||
LOGGER.warn("压缩包源文件删除失败:{}!", filePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除目录及目录下的文件
|
||||
*
|
||||
* @param dir 要删除的目录的文件路径
|
||||
* @return 目录删除成功返回true,否则返回false
|
||||
*/
|
||||
public static boolean deleteDirectory(String dir) {
|
||||
// 如果dir不以文件分隔符结尾,自动添加文件分隔符
|
||||
if (!dir.endsWith(File.separator)) {
|
||||
dir = dir + File.separator;
|
||||
}
|
||||
File dirFile = new File(dir);
|
||||
// 如果dir对应的文件不存在,或者不是一个目录,则退出
|
||||
if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
|
||||
LOGGER.info("删除目录失败:" + dir + "不存在!");
|
||||
return false;
|
||||
}
|
||||
boolean flag = true;
|
||||
// 删除文件夹中的所有文件包括子目录
|
||||
File[] files = dirFile.listFiles();
|
||||
for (int i = 0; i < Objects.requireNonNull(files).length; i++) {
|
||||
// 删除子文件
|
||||
if (files[i].isFile()) {
|
||||
flag = KkFileUtils.deleteFileByName(files[i].getAbsolutePath());
|
||||
if (!flag) {
|
||||
break;
|
||||
}
|
||||
} else if (files[i].isDirectory()) {
|
||||
// 删除子目录
|
||||
flag = KkFileUtils.deleteDirectory(files[i].getAbsolutePath());
|
||||
if (!flag) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dirFile.delete() || !flag) {
|
||||
LOGGER.info("删除目录失败!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否允许上传
|
||||
*
|
||||
* @param file 文件扩展名
|
||||
* @return 是否允许上传
|
||||
*/
|
||||
public static boolean isAllowedUpload(String file) {
|
||||
String fileType = suffixFromFileName(file);
|
||||
for (String type : ConfigConstants.getProhibit()) {
|
||||
if (type.equals(fileType)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !ObjectUtils.isEmpty(fileType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件是否存在
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 是否存在 true:存在,false:不存在
|
||||
*/
|
||||
public static boolean isExist(String filePath) {
|
||||
File file = new File(filePath);
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import org.jodconverter.core.util.OSUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author chenjh
|
||||
* @since 2022-12-15
|
||||
*/
|
||||
public class LocalOfficeUtils {
|
||||
|
||||
public static final String OFFICE_HOME_KEY = "office.home";
|
||||
public static final String DEFAULT_OFFICE_HOME_VALUE = "default";
|
||||
|
||||
private static final String EXECUTABLE_DEFAULT = "program/soffice.bin";
|
||||
private static final String EXECUTABLE_MAC = "program/soffice";
|
||||
private static final String EXECUTABLE_MAC_41 = "MacOS/soffice";
|
||||
private static final String EXECUTABLE_WINDOWS = "program/soffice.exe";
|
||||
|
||||
public static File getDefaultOfficeHome() {
|
||||
Properties properties = new Properties();
|
||||
String customizedConfigPath = ConfigUtils.getCustomizedConfigPath();
|
||||
try {
|
||||
BufferedReader bufferedReader = new BufferedReader(new FileReader(customizedConfigPath));
|
||||
properties.load(bufferedReader);
|
||||
ConfigUtils.restorePropertiesFromEnvFormat(properties);
|
||||
} catch (Exception ignored) {}
|
||||
String officeHome = properties.getProperty(OFFICE_HOME_KEY);
|
||||
if (officeHome != null && !DEFAULT_OFFICE_HOME_VALUE.equals(officeHome)) {
|
||||
return new File(officeHome);
|
||||
}
|
||||
if (OSUtils.IS_OS_WINDOWS) {
|
||||
String userDir = ConfigUtils.getUserDir();
|
||||
// Try to find the most recent version of LibreOffice or OpenOffice,
|
||||
// starting with the 64-bit version. %ProgramFiles(x86)% on 64-bit
|
||||
// machines; %ProgramFiles% on 32-bit ones
|
||||
final String programFiles64 = System.getenv("ProgramFiles");
|
||||
final String programFiles32 = System.getenv("ProgramFiles(x86)");
|
||||
return findOfficeHome(EXECUTABLE_WINDOWS,
|
||||
userDir + File.separator + "LibreOfficePortable" + File.separator + "App" + File.separator + "libreoffice",
|
||||
programFiles32 + File.separator + "LibreOffice",
|
||||
programFiles64 + File.separator + "LibreOffice 7",
|
||||
programFiles32 + File.separator + "LibreOffice 7",
|
||||
programFiles64 + File.separator + "LibreOffice 6",
|
||||
programFiles32 + File.separator + "LibreOffice 6",
|
||||
programFiles64 + File.separator + "LibreOffice 5",
|
||||
programFiles32 + File.separator + "LibreOffice 5",
|
||||
programFiles64 + File.separator + "LibreOffice 4",
|
||||
programFiles32 + File.separator + "LibreOffice 4",
|
||||
programFiles32 + File.separator + "OpenOffice 4",
|
||||
programFiles64 + File.separator + "LibreOffice 3",
|
||||
programFiles32 + File.separator + "LibreOffice 3",
|
||||
programFiles32 + File.separator + "OpenOffice.org 3");
|
||||
} else if (OSUtils.IS_OS_MAC) {
|
||||
File homeDir = findOfficeHome(EXECUTABLE_MAC_41,
|
||||
"/Applications/LibreOffice.app/Contents",
|
||||
"/Applications/OpenOffice.app/Contents",
|
||||
"/Applications/OpenOffice.org.app/Contents");
|
||||
|
||||
if (homeDir == null) {
|
||||
homeDir = findOfficeHome(EXECUTABLE_MAC,
|
||||
"/Applications/LibreOffice.app/Contents",
|
||||
"/Applications/OpenOffice.app/Contents",
|
||||
"/Applications/OpenOffice.org.app/Contents");
|
||||
}
|
||||
return homeDir;
|
||||
} else {
|
||||
// Linux or other *nix variants
|
||||
return findOfficeHome(EXECUTABLE_DEFAULT,
|
||||
"/opt/libreoffice6.0",
|
||||
"/opt/libreoffice6.1",
|
||||
"/opt/libreoffice6.2",
|
||||
"/opt/libreoffice6.3",
|
||||
"/opt/libreoffice6.4",
|
||||
"/opt/libreoffice7.0",
|
||||
"/opt/libreoffice7.1",
|
||||
"/opt/libreoffice7.2",
|
||||
"/opt/libreoffice7.3",
|
||||
"/opt/libreoffice7.4",
|
||||
"/opt/libreoffice7.5",
|
||||
"/opt/libreoffice7.6",
|
||||
"/usr/lib64/libreoffice",
|
||||
"/usr/lib/libreoffice",
|
||||
"/usr/local/lib64/libreoffice",
|
||||
"/usr/local/lib/libreoffice",
|
||||
"/opt/libreoffice",
|
||||
"/usr/lib64/openoffice",
|
||||
"/usr/lib64/openoffice.org3",
|
||||
"/usr/lib64/openoffice.org",
|
||||
"/usr/lib/openoffice",
|
||||
"/usr/lib/openoffice.org3",
|
||||
"/usr/lib/openoffice.org",
|
||||
"/opt/openoffice4",
|
||||
"/opt/openoffice.org3");
|
||||
}
|
||||
}
|
||||
|
||||
private static File findOfficeHome(final String executablePath, final String... homePaths) {
|
||||
return Stream.of(homePaths)
|
||||
.filter(homePath -> Files.isRegularFile(Paths.get(homePath, executablePath)))
|
||||
.findFirst()
|
||||
.map(File::new)
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.apache.poi.extractor.ExtractorFactory;
|
||||
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Office工具类
|
||||
*
|
||||
* @author ylyue
|
||||
* @since 2022/7/5
|
||||
*/
|
||||
public class OfficeUtils {
|
||||
|
||||
private static final String POI_INVALID_PASSWORD_MSG = "password";
|
||||
|
||||
/**
|
||||
* 判断office(word,excel,ppt)文件是否受密码保护
|
||||
*
|
||||
* @param path office文件路径
|
||||
* @return 是否受密码保护
|
||||
*/
|
||||
public static boolean isPwdProtected(String path) {
|
||||
InputStream propStream = null;
|
||||
try {
|
||||
propStream = Files.newInputStream(Paths.get(path));
|
||||
ExtractorFactory.createExtractor(propStream);
|
||||
} catch (IOException | EncryptedDocumentException e) {
|
||||
if (e.getMessage().toLowerCase().contains(POI_INVALID_PASSWORD_MSG)) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
||||
for (Throwable throwable : throwableArray) {
|
||||
if (throwable instanceof IOException || throwable instanceof EncryptedDocumentException) {
|
||||
if (e.getMessage().toLowerCase().contains(POI_INVALID_PASSWORD_MSG)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}finally {
|
||||
if(propStream!=null) {//如果文件输入流不是null
|
||||
try {
|
||||
propStream.close();//关闭文件输入流
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 判断office文件是否可打开(兼容)
|
||||
*
|
||||
* @param path office文件路径
|
||||
* @param password 文件密码
|
||||
* @return 是否可打开(兼容)
|
||||
*/
|
||||
public static synchronized boolean isCompatible(String path, String password) {
|
||||
InputStream propStream = null;
|
||||
try {
|
||||
propStream = Files.newInputStream(Paths.get(path));
|
||||
Biff8EncryptionKey.setCurrentUserPassword(password);
|
||||
ExtractorFactory.createExtractor(propStream);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
} finally {
|
||||
Biff8EncryptionKey.setCurrentUserPassword(null);
|
||||
if(propStream!=null) {//如果文件输入流不是null
|
||||
try {
|
||||
propStream.close();//关闭文件输入流
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
133
tool-tech-file-view/src/main/java/cn/keking/utils/RarUtils.java
Normal file
133
tool-tech-file-view/src/main/java/cn/keking/utils/RarUtils.java
Normal file
@@ -0,0 +1,133 @@
|
||||
package cn.keking.utils;
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.service.ZtreeNodeVo;
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author : Gao
|
||||
* create : 2023-04-08
|
||||
**/
|
||||
public class RarUtils {
|
||||
private static final String fileDir = ConfigConstants.getFileDir();
|
||||
|
||||
public static byte[] getUTF8BytesFromGBKString(String gbkStr) {
|
||||
int n = gbkStr.length();
|
||||
byte[] utfBytes = new byte[3 * n];
|
||||
int k = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int m = gbkStr.charAt(i);
|
||||
if (m < 128 && m >= 0) {
|
||||
utfBytes[k++] = (byte) m;
|
||||
continue;
|
||||
}
|
||||
utfBytes[k++] = (byte) (0xe0 | (m >> 12));
|
||||
utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f));
|
||||
utfBytes[k++] = (byte) (0x80 | (m & 0x3f));
|
||||
}
|
||||
if (k < utfBytes.length) {
|
||||
byte[] tmp = new byte[k];
|
||||
System.arraycopy(utfBytes, 0, tmp, 0, k);
|
||||
return tmp;
|
||||
}
|
||||
return utfBytes;
|
||||
}
|
||||
|
||||
public static String getUtf8String(String str) {
|
||||
if (str != null && str.length() > 0) {
|
||||
String needEncodeCode = "ISO-8859-1";
|
||||
String neeEncodeCode = "ISO-8859-2";
|
||||
String gbkEncodeCode = "GBK";
|
||||
try {
|
||||
if (Charset.forName(needEncodeCode).newEncoder().canEncode(str)) {
|
||||
str = new String(str.getBytes(needEncodeCode), StandardCharsets.UTF_8);
|
||||
}
|
||||
if (Charset.forName(neeEncodeCode).newEncoder().canEncode(str)) {
|
||||
str = new String(str.getBytes(neeEncodeCode), StandardCharsets.UTF_8);
|
||||
}
|
||||
if (Charset.forName(gbkEncodeCode).newEncoder().canEncode(str)) {
|
||||
str = new String(getUTF8BytesFromGBKString(str), StandardCharsets.UTF_8);
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
/**
|
||||
* 判断是否是中日韩文字
|
||||
*/
|
||||
private static boolean isChinese(char c) {
|
||||
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
|
||||
return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|
||||
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|
||||
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|
||||
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|
||||
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|
||||
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS;
|
||||
}
|
||||
public static boolean judge(char c){
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
|
||||
}
|
||||
public static String specialSymbols(String str) {
|
||||
//去除压缩包文件字符串中特殊符号
|
||||
Pattern p = Pattern.compile("\\s|\t|\r|\n|\\+|#|&|=|\\p{P}");
|
||||
// Pattern p = Pattern.compile("\\s|\\+|#|&|=|\\p{P}");
|
||||
Matcher m = p.matcher(str);
|
||||
return m.replaceAll("");
|
||||
}
|
||||
public static boolean isMessyCode(String strName) {
|
||||
//去除字符串中的空格 制表符 换行 回车
|
||||
strName = specialSymbols(strName);
|
||||
//处理之后转换成字符数组
|
||||
char[] ch = strName.trim().toCharArray();
|
||||
for (char c : ch) {
|
||||
//判断是否是数字或者英文字符
|
||||
if (!judge(c)) {
|
||||
//判断是否是中日韩文
|
||||
if (!isChinese(c)) {
|
||||
//如果不是数字或者英文字符也不是中日韩文则表示是乱码返回true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
//表示不是乱码 返回false
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件目录树
|
||||
*/
|
||||
public static List<ZtreeNodeVo> getTree(String rootPath) {
|
||||
List<ZtreeNodeVo> nodes = new ArrayList<>();
|
||||
File file = new File(fileDir+rootPath);
|
||||
ZtreeNodeVo node = traverse(file);
|
||||
nodes.add(node);
|
||||
return nodes;
|
||||
}
|
||||
private static ZtreeNodeVo traverse(File file) {
|
||||
ZtreeNodeVo pathNodeVo = new ZtreeNodeVo();
|
||||
pathNodeVo.setId(file.getAbsolutePath().replace(fileDir, "").replace("\\", "/"));
|
||||
pathNodeVo.setName(file.getName());
|
||||
pathNodeVo.setPid(file.getParent().replace(fileDir, "").replace("\\", "/"));
|
||||
if (file.isDirectory()) {
|
||||
List<ZtreeNodeVo> subNodeVos = new ArrayList<>();
|
||||
File[] subFiles = file.listFiles();
|
||||
if (subFiles == null) {
|
||||
return pathNodeVo;
|
||||
}
|
||||
for (File subFile : subFiles) {
|
||||
ZtreeNodeVo subNodeVo = traverse(subFile);
|
||||
subNodeVos.add(subNodeVo);
|
||||
}
|
||||
pathNodeVo.setChildren(subNodeVos);
|
||||
}
|
||||
return pathNodeVo;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* @author 鞠玉果
|
||||
*/
|
||||
public class SslUtils {
|
||||
|
||||
private static void trustAllHttpsCertificates() throws Exception {
|
||||
TrustManager[] trustAllCerts = new TrustManager[1];
|
||||
TrustManager tm = new miTM();
|
||||
trustAllCerts[0] = tm;
|
||||
SSLContext sc = SSLContext.getInstance("SSL");
|
||||
sc.init(null, trustAllCerts, null);
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
}
|
||||
|
||||
static class miTM implements TrustManager, X509TrustManager {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略HTTPS请求的SSL证书,必须在openConnection之前调用
|
||||
*/
|
||||
public static void ignoreSsl() throws Exception {
|
||||
HostnameVerifier hv = (urlHostName, session) -> true;
|
||||
trustAllHttpsCertificates();
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(hv);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package cn.keking.utils;
|
||||
import java.util.BitSet;
|
||||
|
||||
|
||||
public class UrlEncoderUtils {
|
||||
|
||||
private static BitSet dontNeedEncoding;
|
||||
|
||||
static {
|
||||
dontNeedEncoding = new BitSet(256);
|
||||
int i;
|
||||
for (i = 'a'; i <= 'z'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
for (i = 'A'; i <= 'Z'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
for (i = '0'; i <= '9'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
dontNeedEncoding.set('+');
|
||||
/**
|
||||
* 这里会有误差,比如输入一个字符串 123+456,它到底是原文就是123+456还是123 456做了urlEncode后的内容呢?<br>
|
||||
* 其实问题是一样的,比如遇到123%2B456,它到底是原文即使如此,还是123+456 urlEncode后的呢? <br>
|
||||
* 在这里,我认为只要符合urlEncode规范的,就当作已经urlEncode过了<br>
|
||||
* 毕竟这个方法的初衷就是判断string是否urlEncode过<br>
|
||||
*/
|
||||
|
||||
dontNeedEncoding.set('-');
|
||||
dontNeedEncoding.set('_');
|
||||
dontNeedEncoding.set('.');
|
||||
dontNeedEncoding.set('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断str是否urlEncoder.encode过<br>
|
||||
* 经常遇到这样的情况,拿到一个URL,但是搞不清楚到底要不要encode.<Br>
|
||||
* 不做encode吧,担心出错,做encode吧,又怕重复了<Br>
|
||||
*
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
public static boolean hasUrlEncoded(String str) {
|
||||
|
||||
/**
|
||||
* 支持JAVA的URLEncoder.encode出来的string做判断。 即: 将' '转成'+' <br>
|
||||
* 0-9a-zA-Z保留 <br>
|
||||
* '-','_','.','*'保留 <br>
|
||||
* 其他字符转成%XX的格式,X是16进制的大写字符,范围是[0-9A-F]
|
||||
*/
|
||||
boolean needEncode = false;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char c = str.charAt(i);
|
||||
if (dontNeedEncoding.get((int) c)) {
|
||||
continue;
|
||||
}
|
||||
if (c == '%' && (i + 2) < str.length()) {
|
||||
// 判断是否符合urlEncode规范
|
||||
char c1 = str.charAt(++i);
|
||||
char c2 = str.charAt(++i);
|
||||
if (isDigit16Char(c1) && isDigit16Char(c2)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 其他字符,肯定需要urlEncode
|
||||
needEncode = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return !needEncode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断c是否是16进制的字符
|
||||
*
|
||||
* @param c
|
||||
* @return
|
||||
*/
|
||||
private static boolean isDigit16Char(char c) {
|
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
}
|
||||
372
tool-tech-file-view/src/main/java/cn/keking/utils/WebUtils.java
Normal file
372
tool-tech-file-view/src/main/java/cn/keking/utils/WebUtils.java
Normal file
@@ -0,0 +1,372 @@
|
||||
package cn.keking.utils;
|
||||
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author : kl
|
||||
* create : 2020-12-27 1:30 上午
|
||||
**/
|
||||
public class WebUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(WebUtils.class);
|
||||
private static final String BASE64_MSG = "base64";
|
||||
/**
|
||||
* 获取标准的URL
|
||||
*
|
||||
* @param urlStr url
|
||||
* @return 标准的URL
|
||||
*/
|
||||
public static URL normalizedURL(String urlStr) throws GalimatiasParseException, MalformedURLException {
|
||||
return io.mola.galimatias.URL.parse(urlStr).toJavaURL();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 对文件名进行编码
|
||||
*
|
||||
*/
|
||||
public static String encodeFileName(String name) {
|
||||
try {
|
||||
name = URLEncoder.encode(name, "UTF-8").replaceAll("\\+", "%20");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 去除fullfilename参数
|
||||
*
|
||||
* @param urlStr
|
||||
* @return
|
||||
*/
|
||||
public static String clearFullfilenameParam(String urlStr) {
|
||||
// 去除特定参数字段
|
||||
Pattern pattern = Pattern.compile("(&fullfilename=[^&]*)");
|
||||
Matcher matcher = pattern.matcher(urlStr);
|
||||
return matcher.replaceAll("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 对URL进行编码
|
||||
*/
|
||||
public static String urlEncoderencode(String urlStr) {
|
||||
|
||||
String fullFileName = getUrlParameterReg(urlStr, "fullfilename"); //获取流文件名
|
||||
if (org.springframework.util.StringUtils.hasText(fullFileName)) {
|
||||
// 移除fullfilename参数
|
||||
urlStr = clearFullfilenameParam(urlStr);
|
||||
} else {
|
||||
fullFileName = getFileNameFromURL(urlStr); //获取文件名
|
||||
|
||||
}
|
||||
if (!UrlEncoderUtils.hasUrlEncoded(fullFileName)) { //判断文件名是否转义
|
||||
try {
|
||||
urlStr = URLEncoder.encode(urlStr, "UTF-8").replaceAll("\\+", "%20").replaceAll("%3A", ":").replaceAll("%2F", "/").replaceAll("%3F", "?").replaceAll("%26", "&").replaceAll("%3D", "=");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return urlStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取url中的参数
|
||||
*
|
||||
* @param url url
|
||||
* @param name 参数名
|
||||
* @return 参数值
|
||||
*/
|
||||
public static String getUrlParameterReg(String url, String name) {
|
||||
Map<String, String> mapRequest = new HashMap<>();
|
||||
String strUrlParam = truncateUrlPage(url);
|
||||
if (strUrlParam == null) {
|
||||
return "";
|
||||
}
|
||||
//每个键值为一组
|
||||
String[] arrSplit = strUrlParam.split("[&]");
|
||||
for (String strSplit : arrSplit) {
|
||||
String[] arrSplitEqual = strSplit.split("[=]");
|
||||
//解析出键值
|
||||
if (arrSplitEqual.length > 1) {
|
||||
//正确解析
|
||||
mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
|
||||
} else if (!arrSplitEqual[0].equals("")) {
|
||||
//只有参数没有值,不加入
|
||||
mapRequest.put(arrSplitEqual[0], "");
|
||||
}
|
||||
}
|
||||
return mapRequest.get(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 去掉url中的路径,留下请求参数部分
|
||||
*
|
||||
* @param strURL url地址
|
||||
* @return url请求参数部分
|
||||
*/
|
||||
private static String truncateUrlPage(String strURL) {
|
||||
String strAllParam = null;
|
||||
strURL = strURL.trim();
|
||||
String[] arrSplit = strURL.split("[?]");
|
||||
if (strURL.length() > 1) {
|
||||
if (arrSplit.length > 1) {
|
||||
if (arrSplit[1] != null) {
|
||||
strAllParam = arrSplit[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return strAllParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从url中剥离出文件名
|
||||
*
|
||||
* @param url 格式如:http://www.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I D1NOFtAJSPT16E6imv6JWuq0k=
|
||||
* @return 文件名
|
||||
*/
|
||||
public static String getFileNameFromURL(String url) {
|
||||
if (url.toLowerCase().startsWith("file:")) {
|
||||
try {
|
||||
URL urlObj = new URL(url);
|
||||
url = urlObj.getPath().substring(1);
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// 因为url的参数中可能会存在/的情况,所以直接url.lastIndexOf("/")会有问题
|
||||
// 所以先从?处将url截断,然后运用url.lastIndexOf("/")获取文件名
|
||||
String noQueryUrl = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
||||
return noQueryUrl.substring(noQueryUrl.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从url中剥离出文件名
|
||||
* @param file 文件
|
||||
* @return 文件名
|
||||
*/
|
||||
public static String getFileNameFromMultipartFile(MultipartFile file) {
|
||||
String fileName = file.getOriginalFilename();
|
||||
//判断是否为IE浏览器的文件名,IE浏览器下文件名会带有盘符信
|
||||
// escaping dangerous characters to prevent XSS
|
||||
assert fileName != null;
|
||||
fileName = HtmlUtils.htmlEscape(fileName, KkFileUtils.DEFAULT_FILE_ENCODING);
|
||||
|
||||
// Check for Unix-style path
|
||||
int unixSep = fileName.lastIndexOf('/');
|
||||
// Check for Windows-style path
|
||||
int winSep = fileName.lastIndexOf('\\');
|
||||
// Cut off at latest possible point
|
||||
int pos = (Math.max(winSep, unixSep));
|
||||
if (pos != -1) {
|
||||
fileName = fileName.substring(pos + 1);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从url中获取文件后缀
|
||||
*
|
||||
* @param url url
|
||||
* @return 文件后缀
|
||||
*/
|
||||
public static String suffixFromUrl(String url) {
|
||||
String nonPramStr = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
||||
String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1);
|
||||
return KkFileUtils.suffixFromFileName(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对url中的文件名进行UTF-8编码
|
||||
*
|
||||
* @param url url
|
||||
* @return 文件名编码后的url
|
||||
*/
|
||||
public static String encodeUrlFileName(String url) {
|
||||
String encodedFileName;
|
||||
String noQueryUrl = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
|
||||
int fileNameStartIndex = noQueryUrl.lastIndexOf('/') + 1;
|
||||
int fileNameEndIndex = noQueryUrl.lastIndexOf('.');
|
||||
if (fileNameEndIndex < fileNameStartIndex) {
|
||||
return url;
|
||||
}
|
||||
try {
|
||||
encodedFileName = URLEncoder.encode(noQueryUrl.substring(fileNameStartIndex, fileNameEndIndex), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
return url.substring(0, fileNameStartIndex) + encodedFileName + url.substring(fileNameEndIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 ServletRequest 获取预览的源 url , 已 base64 解码
|
||||
*
|
||||
* @param request 请求 request
|
||||
* @return url
|
||||
*/
|
||||
public static String getSourceUrl(ServletRequest request) {
|
||||
String url = request.getParameter("url");
|
||||
String urls = request.getParameter("urls");
|
||||
String currentUrl = request.getParameter("currentUrl");
|
||||
String urlPath = request.getParameter("urlPath");
|
||||
if (StringUtils.isNotBlank(url)) {
|
||||
return decodeUrl(url);
|
||||
}
|
||||
if (StringUtils.isNotBlank(currentUrl)) {
|
||||
return decodeUrl(currentUrl);
|
||||
}
|
||||
if (StringUtils.isNotBlank(urlPath)) {
|
||||
return decodeUrl(urlPath);
|
||||
}
|
||||
if (StringUtils.isNotBlank(urls)) {
|
||||
urls = decodeUrl(urls);
|
||||
String[] images = urls.split("\\|");
|
||||
return images[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 判断地址是否正确
|
||||
* 高 2022/12/17
|
||||
*/
|
||||
public static boolean isValidUrl(String url) {
|
||||
String regStr = "^((https|http|ftp|rtsp|mms|file)://)";//[.?*]表示匹配的就是本身
|
||||
Pattern pattern = Pattern.compile(regStr);
|
||||
Matcher matcher = pattern.matcher(url);
|
||||
return matcher.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Base64 字符串解码,再解码URL参数, 默认使用 UTF-8
|
||||
* @param source 原始 Base64 字符串
|
||||
* @return decoded string
|
||||
*
|
||||
* aHR0cHM6Ly9maWxlLmtla2luZy5jbi9kZW1vL%2BS4reaWhy5wcHR4 -> https://file.keking.cn/demo/%E4%B8%AD%E6%96%87.pptx -> https://file.keking.cn/demo/中文.pptx
|
||||
*/
|
||||
public static String decodeUrl(String source) {
|
||||
String url = decodeBase64String(source, StandardCharsets.UTF_8);
|
||||
if (! StringUtils.isNotBlank(url)){
|
||||
return null;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Base64 字符串使用指定字符集解码
|
||||
* @param source 原始 Base64 字符串
|
||||
* @param charsets 字符集
|
||||
* @return decoded string
|
||||
*/
|
||||
public static String decodeBase64String(String source, Charset charsets) {
|
||||
/*
|
||||
* url 传入的参数里加号会被替换成空格,导致解析出错,这里需要把空格替换回加号
|
||||
* 有些 Base64 实现可能每 76 个字符插入换行符,也一并去掉
|
||||
* https://github.com/kekingcn/kkFileView/pull/340
|
||||
*/
|
||||
try {
|
||||
return new String(Base64Utils.decodeFromString(source.replaceAll(" ", "+").replaceAll("\n", "")), charsets);
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage().toLowerCase().contains(BASE64_MSG)) {
|
||||
LOGGER.error("url解码异常,接入方法错误未使用BASE64");
|
||||
}else {
|
||||
LOGGER.error("url解码异常,其他错误", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 url 的 host
|
||||
* @param urlStr url
|
||||
* @return host
|
||||
*/
|
||||
public static String getHost(String urlStr) {
|
||||
try {
|
||||
URL url = new URL(urlStr);
|
||||
return url.getHost().toLowerCase();
|
||||
} catch (MalformedURLException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 session 中的 String 属性
|
||||
* @param request 请求
|
||||
* @return 属性值
|
||||
*/
|
||||
public static String getSessionAttr(HttpServletRequest request, String key) {
|
||||
HttpSession session = request.getSession();
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
Object value = session.getAttribute(key);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 session 中的 long 属性
|
||||
* @param request 请求
|
||||
* @param key 属性名
|
||||
* @return 属性值
|
||||
*/
|
||||
public static long getLongSessionAttr(HttpServletRequest request, String key) {
|
||||
String value = getSessionAttr(request, key);
|
||||
if (value == null) {
|
||||
return 0;
|
||||
}
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* session 中设置属性
|
||||
* @param request 请求
|
||||
* @param key 属性名
|
||||
*/
|
||||
public static void setSessionAttr(HttpServletRequest request, String key, Object value) {
|
||||
HttpSession session = request.getSession();
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
session.setAttribute(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除 session 中的属性
|
||||
* @param request 请求
|
||||
* @param key 属性名
|
||||
*/
|
||||
public static void removeSessionAttr(HttpServletRequest request, String key) {
|
||||
HttpSession session = request.getSession();
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
session.removeAttribute(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
package cn.keking.web.controller;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.ReturnResponse;
|
||||
import cn.keking.utils.CaptchaUtil;
|
||||
import cn.keking.utils.DateUtils;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.utils.RarUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.keking.utils.CaptchaUtil.CAPTCHA_CODE;
|
||||
import static cn.keking.utils.CaptchaUtil.CAPTCHA_GENERATE_TIME;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
* 2017/12/1
|
||||
*/
|
||||
@RestController
|
||||
public class FileController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FileController.class);
|
||||
|
||||
private final String fileDir = ConfigConstants.getFileDir();
|
||||
private final String demoDir = "demo";
|
||||
|
||||
private final String demoPath = demoDir + File.separator;
|
||||
public static final String BASE64_DECODE_ERROR_MSG = "Base64解码失败,请检查你的 %s 是否采用 Base64 + urlEncode 双重编码了!";
|
||||
|
||||
@PostMapping("/fileUpload")
|
||||
public ReturnResponse<Object> fileUpload(@RequestParam("file") MultipartFile file) {
|
||||
ReturnResponse<Object> checkResult = this.fileUploadCheck(file);
|
||||
if (checkResult.isFailure()) {
|
||||
return checkResult;
|
||||
}
|
||||
File outFile = new File(fileDir + demoPath);
|
||||
if (!outFile.exists() && !outFile.mkdirs()) {
|
||||
logger.error("创建文件夹【{}】失败,请检查目录权限!", fileDir + demoPath);
|
||||
}
|
||||
String fileName = checkResult.getContent().toString();
|
||||
logger.info("上传文件:{}{}{}", fileDir, demoPath, fileName);
|
||||
try (InputStream in = file.getInputStream(); OutputStream out = Files.newOutputStream(Paths.get(fileDir + demoPath + fileName))) {
|
||||
StreamUtils.copy(in, out);
|
||||
return ReturnResponse.success(null);
|
||||
} catch (IOException e) {
|
||||
logger.error("文件上传失败", e);
|
||||
return ReturnResponse.failure();
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/deleteFile")
|
||||
public ReturnResponse<Object> deleteFile(HttpServletRequest request, String fileName, String password) {
|
||||
ReturnResponse<Object> checkResult = this.deleteFileCheck(request, fileName, password);
|
||||
if (checkResult.isFailure()) {
|
||||
return checkResult;
|
||||
}
|
||||
fileName = checkResult.getContent().toString();
|
||||
File file = new File(fileDir + demoPath + fileName);
|
||||
logger.info("删除文件:{}", file.getAbsolutePath());
|
||||
if (file.exists() && !file.delete()) {
|
||||
String msg = String.format("删除文件【%s】失败,请检查目录权限!", file.getPath());
|
||||
logger.error(msg);
|
||||
return ReturnResponse.failure(msg);
|
||||
}
|
||||
WebUtils.removeSessionAttr(request, CAPTCHA_CODE); //删除缓存验证码
|
||||
return ReturnResponse.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码方法
|
||||
*/
|
||||
@RequestMapping("/deleteFile/captcha")
|
||||
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
if (!ConfigConstants.getDeleteCaptcha()) {
|
||||
return;
|
||||
}
|
||||
|
||||
response.setContentType("image/jpeg");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
response.setDateHeader("Expires", -1);
|
||||
String captchaCode = WebUtils.getSessionAttr(request, CAPTCHA_CODE);
|
||||
long captchaGenerateTime = WebUtils.getLongSessionAttr(request, CAPTCHA_GENERATE_TIME);
|
||||
long timeDifference = DateUtils.calculateCurrentTimeDifference(captchaGenerateTime);
|
||||
|
||||
// 验证码为空,且生成验证码超过50秒,重新生成验证码
|
||||
if (timeDifference > 50 && ObjectUtils.isEmpty(captchaCode)) {
|
||||
captchaCode = CaptchaUtil.generateCaptchaCode();
|
||||
// 更新验证码
|
||||
WebUtils.setSessionAttr(request, CAPTCHA_CODE, captchaCode);
|
||||
WebUtils.setSessionAttr(request, CAPTCHA_GENERATE_TIME, DateUtils.getCurrentSecond());
|
||||
} else {
|
||||
captchaCode = ObjectUtils.isEmpty(captchaCode) ? "wait" : captchaCode;
|
||||
}
|
||||
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
ImageIO.write(CaptchaUtil.generateCaptchaPic(captchaCode), "jpeg", outputStream);
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
@GetMapping("/listFiles")
|
||||
public List<Map<String, String>> getFiles() {
|
||||
List<Map<String, String>> list = new ArrayList<>();
|
||||
File file = new File(fileDir + demoPath);
|
||||
if (file.exists()) {
|
||||
File[] files = Objects.requireNonNull(file.listFiles());
|
||||
Arrays.sort(files, (f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified()));
|
||||
Arrays.stream(files).forEach(file1 -> {
|
||||
Map<String, String> fileName = new HashMap<>();
|
||||
fileName.put("fileName", demoDir + "/" + file1.getName());
|
||||
list.add(fileName);
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件前校验
|
||||
*
|
||||
* @param file 文件
|
||||
* @return 校验结果
|
||||
*/
|
||||
private ReturnResponse<Object> fileUploadCheck(MultipartFile file) {
|
||||
if (ConfigConstants.getFileUploadDisable()) {
|
||||
return ReturnResponse.failure("文件传接口已禁用");
|
||||
}
|
||||
String fileName = WebUtils.getFileNameFromMultipartFile(file);
|
||||
if (fileName.lastIndexOf(".") == -1) {
|
||||
return ReturnResponse.failure("不允许上传的类型");
|
||||
}
|
||||
if (!KkFileUtils.isAllowedUpload(fileName)) {
|
||||
return ReturnResponse.failure("不允许上传的文件类型: " + fileName);
|
||||
}
|
||||
if (KkFileUtils.isIllegalFileName(fileName)) {
|
||||
return ReturnResponse.failure("不允许上传的文件名: " + fileName);
|
||||
}
|
||||
// 判断是否存在同名文件
|
||||
if (existsFile(fileName)) {
|
||||
return ReturnResponse.failure("存在同名文件,请先删除原有文件再次上传");
|
||||
}
|
||||
return ReturnResponse.success(fileName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除文件前校验
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return 校验结果
|
||||
*/
|
||||
private ReturnResponse<Object> deleteFileCheck(HttpServletRequest request, String fileName, String password) {
|
||||
if (ObjectUtils.isEmpty(fileName)) {
|
||||
return ReturnResponse.failure("文件名为空,删除失败!");
|
||||
}
|
||||
try {
|
||||
fileName = WebUtils.decodeUrl(fileName);
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, fileName);
|
||||
return ReturnResponse.failure(errorMsg + "删除失败!");
|
||||
}
|
||||
assert fileName != null;
|
||||
if (fileName.contains("/")) {
|
||||
fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
|
||||
}
|
||||
if (KkFileUtils.isIllegalFileName(fileName)) {
|
||||
return ReturnResponse.failure("非法文件名,删除失败!");
|
||||
}
|
||||
if (ObjectUtils.isEmpty(password)) {
|
||||
return ReturnResponse.failure("密码 or 验证码为空,删除失败!");
|
||||
}
|
||||
|
||||
String expectedPassword = ConfigConstants.getDeleteCaptcha() ? WebUtils.getSessionAttr(request, CAPTCHA_CODE) : ConfigConstants.getPassword();
|
||||
|
||||
if (!password.equalsIgnoreCase(expectedPassword)) {
|
||||
logger.error("删除文件【{}】失败,密码错误!", fileName);
|
||||
return ReturnResponse.failure("删除文件失败,密码错误!");
|
||||
}
|
||||
return ReturnResponse.success(fileName);
|
||||
}
|
||||
|
||||
@GetMapping("/directory")
|
||||
public Object directory(String urls) {
|
||||
String fileUrl;
|
||||
try {
|
||||
fileUrl = WebUtils.decodeUrl(urls);
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url");
|
||||
return ReturnResponse.failure(errorMsg);
|
||||
}
|
||||
if (KkFileUtils.isIllegalFileName(fileUrl)) {
|
||||
return ReturnResponse.failure("不允许访问的路径:");
|
||||
}
|
||||
return RarUtils.getTree(fileUrl);
|
||||
}
|
||||
|
||||
private boolean existsFile(String fileName) {
|
||||
File file = new File(fileDir + demoPath + fileName);
|
||||
return file.exists();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.keking.web.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
/**
|
||||
* 页面跳转
|
||||
* @author yudian-it
|
||||
* @date 2017/12/27
|
||||
*/
|
||||
@Controller
|
||||
public class IndexController {
|
||||
|
||||
@GetMapping( "/index")
|
||||
public String go2Index(){
|
||||
return "/main/index";
|
||||
}
|
||||
|
||||
@GetMapping( "/record")
|
||||
public String go2Record(){
|
||||
return "/main/record";
|
||||
}
|
||||
|
||||
@GetMapping( "/sponsor")
|
||||
public String go2Sponsor(){
|
||||
return "/main/sponsor";
|
||||
}
|
||||
|
||||
@GetMapping( "/integrated")
|
||||
public String go2Integrated(){
|
||||
return "/main/integrated";
|
||||
}
|
||||
|
||||
@GetMapping( "/")
|
||||
public String root() {
|
||||
return "/main/index";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package cn.keking.web.controller;
|
||||
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.service.FileHandlerService;
|
||||
import cn.keking.service.FilePreview;
|
||||
import cn.keking.service.FilePreviewFactory;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.service.impl.OtherFilePreviewImpl;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import fr.opensagres.xdocreport.core.io.IOUtils;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.DefaultRedirectStrategy;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.client.RequestCallback;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.keking.service.FilePreview.PICTURE_FILE_PREVIEW_PAGE;
|
||||
|
||||
/**
|
||||
* @author yudian-it
|
||||
*/
|
||||
@Controller
|
||||
public class OnlinePreviewController {
|
||||
|
||||
public static final String BASE64_DECODE_ERROR_MSG = "Base64解码失败,请检查你的 %s 是否采用 Base64 + urlEncode 双重编码了!";
|
||||
private final Logger logger = LoggerFactory.getLogger(OnlinePreviewController.class);
|
||||
|
||||
private final FilePreviewFactory previewFactory;
|
||||
private final CacheService cacheService;
|
||||
private final FileHandlerService fileHandlerService;
|
||||
private final OtherFilePreviewImpl otherFilePreview;
|
||||
private static final RestTemplate restTemplate = new RestTemplate();
|
||||
private static final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public OnlinePreviewController(FilePreviewFactory filePreviewFactory, FileHandlerService fileHandlerService, CacheService cacheService, OtherFilePreviewImpl otherFilePreview) {
|
||||
this.previewFactory = filePreviewFactory;
|
||||
this.fileHandlerService = fileHandlerService;
|
||||
this.cacheService = cacheService;
|
||||
this.otherFilePreview = otherFilePreview;
|
||||
}
|
||||
|
||||
@GetMapping( "/onlinePreview")
|
||||
public String onlinePreview(String url, Model model, HttpServletRequest req) {
|
||||
|
||||
String fileUrl;
|
||||
try {
|
||||
fileUrl = WebUtils.decodeUrl(url);
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "url");
|
||||
return otherFilePreview.notSupportedFile(model, errorMsg);
|
||||
}
|
||||
FileAttribute fileAttribute = fileHandlerService.getFileAttribute(fileUrl, req); //这里不在进行URL 处理了
|
||||
model.addAttribute("file", fileAttribute);
|
||||
FilePreview filePreview = previewFactory.get(fileAttribute);
|
||||
logger.info("预览文件url:{},previewType:{}", fileUrl, fileAttribute.getType());
|
||||
return filePreview.filePreviewHandle(WebUtils.urlEncoderencode(fileUrl), model, fileAttribute); //统一在这里处理 url
|
||||
}
|
||||
|
||||
@GetMapping( "/picturesPreview")
|
||||
public String picturesPreview(String urls, Model model, HttpServletRequest req) {
|
||||
String fileUrls;
|
||||
try {
|
||||
fileUrls = WebUtils.decodeUrl(urls);
|
||||
// 防止XSS攻击
|
||||
fileUrls = KkFileUtils.htmlEscape(fileUrls);
|
||||
} catch (Exception ex) {
|
||||
String errorMsg = String.format(BASE64_DECODE_ERROR_MSG, "urls");
|
||||
return otherFilePreview.notSupportedFile(model, errorMsg);
|
||||
}
|
||||
logger.info("预览文件url:{},urls:{}", fileUrls, urls);
|
||||
// 抽取文件并返回文件列表
|
||||
String[] images = fileUrls.split("\\|");
|
||||
List<String> imgUrls = Arrays.asList(images);
|
||||
model.addAttribute("imgUrls", imgUrls);
|
||||
String currentUrl = req.getParameter("currentUrl");
|
||||
if (StringUtils.hasText(currentUrl)) {
|
||||
String decodedCurrentUrl = new String(Base64.decodeBase64(currentUrl));
|
||||
decodedCurrentUrl = KkFileUtils.htmlEscape(decodedCurrentUrl); // 防止XSS攻击
|
||||
model.addAttribute("currentUrl", decodedCurrentUrl);
|
||||
} else {
|
||||
model.addAttribute("currentUrl", imgUrls.get(0));
|
||||
}
|
||||
return PICTURE_FILE_PREVIEW_PAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据url获取文件内容
|
||||
* 当pdfjs读取存在跨域问题的文件时将通过此接口读取
|
||||
*
|
||||
* @param urlPath url
|
||||
* @param response response
|
||||
*/
|
||||
@GetMapping("/getCorsFile")
|
||||
public void getCorsFile(String urlPath, HttpServletResponse response,FileAttribute fileAttribute) throws IOException {
|
||||
URL url;
|
||||
try {
|
||||
urlPath = WebUtils.decodeUrl(urlPath);
|
||||
url = WebUtils.normalizedURL(urlPath);
|
||||
} catch (Exception ex) {
|
||||
logger.error(String.format(BASE64_DECODE_ERROR_MSG, urlPath),ex);
|
||||
return;
|
||||
}
|
||||
assert urlPath != null;
|
||||
if (!urlPath.toLowerCase().startsWith("http") && !urlPath.toLowerCase().startsWith("https") && !urlPath.toLowerCase().startsWith("ftp")) {
|
||||
logger.info("读取跨域文件异常,可能存在非法访问,urlPath:{}", urlPath);
|
||||
return;
|
||||
}
|
||||
InputStream inputStream = null;
|
||||
logger.info("读取跨域pdf文件url:{}", urlPath);
|
||||
if (!urlPath.toLowerCase().startsWith("ftp:")) {
|
||||
factory.setConnectionRequestTimeout(2000);
|
||||
factory.setConnectTimeout(10000);
|
||||
factory.setReadTimeout(72000);
|
||||
HttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new DefaultRedirectStrategy()).build();
|
||||
factory.setHttpClient(httpClient);
|
||||
restTemplate.setRequestFactory(factory);
|
||||
RequestCallback requestCallback = request -> {
|
||||
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
|
||||
String proxyAuthorization = fileAttribute.getKkProxyAuthorization();
|
||||
if(StringUtils.hasText(proxyAuthorization)){
|
||||
Map<String,String> proxyAuthorizationMap = mapper.readValue(proxyAuthorization, Map.class);
|
||||
proxyAuthorizationMap.forEach((key, value) -> request.getHeaders().set(key, value));
|
||||
}
|
||||
};
|
||||
try {
|
||||
restTemplate.execute(url.toURI(), HttpMethod.GET, requestCallback, fileResponse -> {
|
||||
IOUtils.copy(fileResponse.getBody(), response.getOutputStream());
|
||||
return null;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
}else{
|
||||
try {
|
||||
if(urlPath.contains(".svg")) {
|
||||
response.setContentType("image/svg+xml");
|
||||
}
|
||||
inputStream = (url).openStream();
|
||||
IOUtils.copy(inputStream, response.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
logger.error("读取跨域文件异常,url:{}", urlPath);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过api接口入队
|
||||
*
|
||||
* @param url 请编码后在入队
|
||||
*/
|
||||
@GetMapping("/addTask")
|
||||
@ResponseBody
|
||||
public String addQueueTask(String url) {
|
||||
logger.info("添加转码队列url:{}", url);
|
||||
cacheService.addQueueTask(url);
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.config.WatermarkConfigConstants;
|
||||
import cn.keking.utils.KkFileUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author chenjh
|
||||
* @since 2020/5/13 18:34
|
||||
*/
|
||||
public class AttributeSetFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
this.setWatermarkAttribute(request);
|
||||
this.setFileAttribute(request);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置办公文具预览逻辑需要的属性
|
||||
* @param request request
|
||||
*/
|
||||
private void setFileAttribute(ServletRequest request){
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
request.setAttribute("pdfPresentationModeDisable", ConfigConstants.getPdfPresentationModeDisable());
|
||||
request.setAttribute("pdfOpenFileDisable", ConfigConstants.getPdfOpenFileDisable());
|
||||
request.setAttribute("pdfPrintDisable", ConfigConstants.getPdfPrintDisable());
|
||||
request.setAttribute("pdfDownloadDisable", ConfigConstants.getPdfDownloadDisable());
|
||||
request.setAttribute("pdfBookmarkDisable", ConfigConstants.getPdfBookmarkDisable());
|
||||
request.setAttribute("pdfDisableEditing", ConfigConstants.getPdfDisableEditing());
|
||||
request.setAttribute("switchDisabled", ConfigConstants.getOfficePreviewSwitchDisabled());
|
||||
request.setAttribute("fileUploadDisable", ConfigConstants.getFileUploadDisable());
|
||||
request.setAttribute("beian", ConfigConstants.getBeian());
|
||||
request.setAttribute("size", ConfigConstants.maxSize());
|
||||
request.setAttribute("deleteCaptcha", ConfigConstants.getDeleteCaptcha());
|
||||
request.setAttribute("homePageNumber", ConfigConstants.getHomePageNumber());
|
||||
request.setAttribute("homePagination", ConfigConstants.getHomePagination());
|
||||
request.setAttribute("homePageSize", ConfigConstants.getHomePageSize());
|
||||
request.setAttribute("homeSearch", ConfigConstants.getHomeSearch());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置水印属性
|
||||
* @param request request
|
||||
*/
|
||||
|
||||
private void setWatermarkAttribute(ServletRequest request) {
|
||||
String watermarkTxt= KkFileUtils.htmlEscape(request.getParameter("watermarkTxt"));
|
||||
request.setAttribute("watermarkTxt", watermarkTxt != null ? watermarkTxt : WatermarkConfigConstants.getWatermarkTxt());
|
||||
String watermarkXSpace = KkFileUtils.htmlEscape(request.getParameter("watermarkXSpace"));
|
||||
if (!KkFileUtils.isInteger(watermarkXSpace)){
|
||||
watermarkXSpace =null;
|
||||
}
|
||||
request.setAttribute("watermarkXSpace", watermarkXSpace != null ? watermarkXSpace : WatermarkConfigConstants.getWatermarkXSpace());
|
||||
String watermarkYSpace = KkFileUtils.htmlEscape(request.getParameter("watermarkYSpace"));
|
||||
if (!KkFileUtils.isInteger(watermarkYSpace)){
|
||||
watermarkYSpace =null;
|
||||
}
|
||||
request.setAttribute("watermarkYSpace", watermarkYSpace != null ? watermarkYSpace : WatermarkConfigConstants.getWatermarkYSpace());
|
||||
String watermarkFont = KkFileUtils.htmlEscape(request.getParameter("watermarkFont"));
|
||||
request.setAttribute("watermarkFont", watermarkFont != null ? watermarkFont : WatermarkConfigConstants.getWatermarkFont());
|
||||
String watermarkFontsize = KkFileUtils.htmlEscape(request.getParameter("watermarkFontsize"));
|
||||
request.setAttribute("watermarkFontsize", watermarkFontsize != null ? watermarkFontsize : WatermarkConfigConstants.getWatermarkFontsize());
|
||||
String watermarkColor = KkFileUtils.htmlEscape(request.getParameter("watermarkColor"));
|
||||
request.setAttribute("watermarkColor", watermarkColor != null ? watermarkColor : WatermarkConfigConstants.getWatermarkColor());
|
||||
String watermarkAlpha = KkFileUtils.htmlEscape(request.getParameter("watermarkAlpha"));
|
||||
if (!KkFileUtils.isInteger(watermarkAlpha)){
|
||||
watermarkAlpha =null;
|
||||
}
|
||||
request.setAttribute("watermarkAlpha", watermarkAlpha != null ? watermarkAlpha : WatermarkConfigConstants.getWatermarkAlpha());
|
||||
String watermarkWidth = KkFileUtils.htmlEscape(request.getParameter("watermarkWidth"));
|
||||
if (!KkFileUtils.isInteger(watermarkWidth)){
|
||||
watermarkWidth =null;
|
||||
}
|
||||
request.setAttribute("watermarkWidth", watermarkWidth != null ? watermarkWidth : WatermarkConfigConstants.getWatermarkWidth());
|
||||
String watermarkHeight = KkFileUtils.htmlEscape(request.getParameter("watermarkHeight"));
|
||||
if (!KkFileUtils.isInteger(watermarkHeight)){
|
||||
watermarkHeight =null;
|
||||
}
|
||||
request.setAttribute("watermarkHeight", watermarkHeight != null ? watermarkHeight : WatermarkConfigConstants.getWatermarkHeight());
|
||||
String watermarkAngle = KkFileUtils.htmlEscape(request.getParameter("watermarkAngle"));
|
||||
if (!KkFileUtils.isInteger(watermarkAngle)){
|
||||
watermarkAngle =null;
|
||||
}
|
||||
request.setAttribute("watermarkAngle", watermarkAngle != null ? watermarkAngle : WatermarkConfigConstants.getWatermarkAngle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author chenjh
|
||||
* @since 2020/5/13 18:27
|
||||
*/
|
||||
public class BaseUrlFilter implements Filter {
|
||||
|
||||
private static String BASE_URL;
|
||||
|
||||
public static String getBaseUrl() {
|
||||
String baseUrl;
|
||||
try {
|
||||
baseUrl = (String) RequestContextHolder.currentRequestAttributes().getAttribute("baseUrl", 0);
|
||||
} catch (Exception e) {
|
||||
baseUrl = BASE_URL;
|
||||
}
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
|
||||
String baseUrl;
|
||||
String configBaseUrl = ConfigConstants.getBaseUrl();
|
||||
|
||||
final HttpServletRequest servletRequest = (HttpServletRequest) request;
|
||||
//1、支持通过 http header 中 X-Base-Url 来动态设置 baseUrl 以支持多个域名/项目的共享使用
|
||||
final String urlInHeader = servletRequest.getHeader("X-Base-Url");
|
||||
if (StringUtils.isNotEmpty(urlInHeader)) {
|
||||
baseUrl = urlInHeader;
|
||||
} else if (configBaseUrl != null && !ConfigConstants.DEFAULT_VALUE.equalsIgnoreCase(configBaseUrl)) {
|
||||
//2、如果配置文件中配置了 baseUrl 且不为 default 则以配置文件为准
|
||||
baseUrl = configBaseUrl;
|
||||
} else {
|
||||
//3、默认动态拼接 baseUrl
|
||||
baseUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
|
||||
+ servletRequest.getContextPath() + "/";
|
||||
}
|
||||
|
||||
if (!baseUrl.endsWith("/")) {
|
||||
baseUrl = baseUrl.concat("/");
|
||||
}
|
||||
|
||||
BASE_URL = baseUrl;
|
||||
request.setAttribute("baseUrl", baseUrl);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author yudian-it
|
||||
* @date 2017/11/30
|
||||
*/
|
||||
public class ChinesePathFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
}
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@Configuration
|
||||
public class SecurityFilterProxy extends OncePerRequestFilter {
|
||||
|
||||
|
||||
private String NOT_ALLOW_METHODS = "TRACE";
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
if((","+NOT_ALLOW_METHODS+",").indexOf(","+request.getMethod().toUpperCase()+",") > -1) {
|
||||
response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
|
||||
response.setHeader("Content-Type", "text/html; charset=iso-8859-1");
|
||||
response.getWriter().println("Method Not Allowed");
|
||||
return;
|
||||
}
|
||||
super.doFilter(request, response, filterChain);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.utils.WebUtils;
|
||||
import io.mola.galimatias.GalimatiasParseException;
|
||||
import org.jodconverter.core.util.OSUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author : kl (http://kailing.pub)
|
||||
* @since : 2022-05-25 17:45
|
||||
*/
|
||||
public class TrustDirFilter implements Filter {
|
||||
|
||||
private String notTrustDirView;
|
||||
private final Logger logger = LoggerFactory.getLogger(TrustDirFilter.class);
|
||||
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
ClassPathResource classPathResource = new ClassPathResource("web/notTrustDir.html");
|
||||
try {
|
||||
classPathResource.getInputStream();
|
||||
byte[] bytes = FileCopyUtils.copyToByteArray(classPathResource.getInputStream());
|
||||
this.notTrustDirView = new String(bytes, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
String url = WebUtils.getSourceUrl(request);
|
||||
if (!allowPreview(url)) {
|
||||
response.getWriter().write(this.notTrustDirView);
|
||||
response.getWriter().close();
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
private boolean allowPreview(String urlPath) {
|
||||
//判断URL是否合法
|
||||
if(!StringUtils.hasText(urlPath) || !WebUtils.isValidUrl(urlPath)) {
|
||||
return false ;
|
||||
}
|
||||
try {
|
||||
URL url = WebUtils.normalizedURL(urlPath);
|
||||
if ("file".equals(url.getProtocol().toLowerCase(Locale.ROOT))) {
|
||||
String filePath = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8.name());
|
||||
if (OSUtils.IS_OS_WINDOWS) {
|
||||
filePath = filePath.replaceAll("/", "\\\\");
|
||||
}
|
||||
return filePath.startsWith(ConfigConstants.getFileDir()) || filePath.startsWith(ConfigConstants.getLocalPreviewDir());
|
||||
}
|
||||
return true;
|
||||
} catch (IOException | GalimatiasParseException e) {
|
||||
logger.error("解析URL异常,url:{}", urlPath, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.utils.WebUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* @author chenjh
|
||||
* @since 2020/2/18 19:13
|
||||
*/
|
||||
public class TrustHostFilter implements Filter {
|
||||
|
||||
private String notTrustHostHtmlView;
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
ClassPathResource classPathResource = new ClassPathResource("web/notTrustHost.html");
|
||||
try {
|
||||
classPathResource.getInputStream();
|
||||
byte[] bytes = FileCopyUtils.copyToByteArray(classPathResource.getInputStream());
|
||||
this.notTrustHostHtmlView = new String(bytes, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
String url = WebUtils.getSourceUrl(request);
|
||||
String host = WebUtils.getHost(url);
|
||||
assert host != null;
|
||||
if (isNotTrustHost(host)) {
|
||||
String html = this.notTrustHostHtmlView.replace("${current_host}", host);
|
||||
response.getWriter().write(html);
|
||||
response.getWriter().close();
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNotTrustHost(String host) {
|
||||
if (CollectionUtils.isNotEmpty(ConfigConstants.getNotTrustHostSet())) {
|
||||
return ConfigConstants.getNotTrustHostSet().contains(host);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(ConfigConstants.getTrustHostSet())) {
|
||||
return !ConfigConstants.getTrustHostSet().contains(host);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.keking.web.filter;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @date 2023/11/30
|
||||
*/
|
||||
public class UrlCheckFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
|
||||
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
String servletPath = httpServletRequest.getServletPath();
|
||||
|
||||
boolean redirect = false;
|
||||
|
||||
// servletPath 中不能包含 //
|
||||
if (servletPath.contains("//")) {
|
||||
servletPath = servletPath.replaceAll("//+", "/");
|
||||
redirect = true;
|
||||
}
|
||||
|
||||
// 不能以 / 结尾,同时考虑 **首页** 的特殊性
|
||||
if (servletPath.endsWith("/") && servletPath.length() > 1) {
|
||||
servletPath = servletPath.substring(0, servletPath.length() - 1);
|
||||
redirect = true;
|
||||
}
|
||||
if (redirect) {
|
||||
String redirectUrl;
|
||||
if (StringUtils.isBlank(BaseUrlFilter.getBaseUrl())) {
|
||||
// 正常 BaseUrlFilter 有限此 Filter 执行,不会执行到此
|
||||
redirectUrl = httpServletRequest.getContextPath() + servletPath;
|
||||
} else {
|
||||
if (BaseUrlFilter.getBaseUrl().endsWith("/") && servletPath.startsWith("/")) {
|
||||
// BaseUrlFilter.getBaseUrl() 以 / 结尾,servletPath 以 / 开头,需再去除一次 //
|
||||
redirectUrl = BaseUrlFilter.getBaseUrl() + servletPath.substring(1);
|
||||
} else {
|
||||
redirectUrl = BaseUrlFilter.getBaseUrl() + servletPath;
|
||||
}
|
||||
}
|
||||
((HttpServletResponse) response).sendRedirect(redirectUrl + "?" + httpServletRequest.getQueryString());
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
tool-tech-file-view/src/main/log/README.txt
Normal file
7
tool-tech-file-view/src/main/log/README.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
README.txt
|
||||
log目录是用来存放kkFileView.log的,预览服务的运行情况最终都会反映到这个日志文件里,
|
||||
可以提供给开发、运维排查系统问题。如果通过kkFileView.log还无法定位问题所在,请你在寻求
|
||||
kk官方支持时,QQ群一 613025121、QQ群二 484680571。将此日志文件一并携带,并按照这个
|
||||
格式重命名日志文件 kkFileView-QQ昵称-时间日期.log。如:kkFileView-kl博主-2020-12-27.log 。
|
||||
所有收集的日志文件我们都会存档,供所有的kk用户作为排查案例使用,所以在你提供日志前,请
|
||||
先自行处理日志文件里的业务敏感内容。
|
||||
14
tool-tech-file-view/src/main/resources/banner.txt
Normal file
14
tool-tech-file-view/src/main/resources/banner.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
_ _ ______ _ _ __ __ _
|
||||
| | | | | ____| (_) | | \ \ / / (_)
|
||||
| | __ | | __ | |__ _ | | ___ \ \ / / _ ___ __ __
|
||||
| |/ / | |/ / | __| | | | | / _ \ \ \/ / | | / _ \ \ \ /\ / /
|
||||
| < | < | | | | | | | __/ \ / | | | __/ \ V V /
|
||||
|_|\_\ |_|\_\ |_| |_| |_| \___| \/ |_| \___| \_/\_/
|
||||
|
||||
=> Spring Boot :: ${spring-boot.version}
|
||||
=> kkFileView :: 4.4.0-beta
|
||||
=> Home site :: https://kkview.cn
|
||||
=> Github :: https://github.com/kekingcn/kkFileView
|
||||
=> Gitee :: https://gitee.com/kekingcn/file-online-preview
|
||||
=> kk opensource community :: https://t.zsxq.com/09ZHSXbsQ
|
||||
10
tool-tech-file-view/src/main/resources/static/bootstrap-table/bootstrap-table.min.css
vendored
Normal file
10
tool-tech-file-view/src/main/resources/static/bootstrap-table/bootstrap-table.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4867
tool-tech-file-view/src/main/resources/static/bootstrap-table/bootstrap-table.min.js
vendored
Normal file
4867
tool-tech-file-view/src/main/resources/static/bootstrap-table/bootstrap-table.min.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
587
tool-tech-file-view/src/main/resources/static/bootstrap/css/bootstrap-theme.css
vendored
Normal file
587
tool-tech-file-view/src/main/resources/static/bootstrap/css/bootstrap-theme.css
vendored
Normal file
@@ -0,0 +1,587 @@
|
||||
/*!
|
||||
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
.btn-default,
|
||||
.btn-primary,
|
||||
.btn-success,
|
||||
.btn-info,
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-primary:active,
|
||||
.btn-success:active,
|
||||
.btn-info:active,
|
||||
.btn-warning:active,
|
||||
.btn-danger:active,
|
||||
.btn-default.active,
|
||||
.btn-primary.active,
|
||||
.btn-success.active,
|
||||
.btn-info.active,
|
||||
.btn-warning.active,
|
||||
.btn-danger.active {
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
.btn-default.disabled,
|
||||
.btn-primary.disabled,
|
||||
.btn-success.disabled,
|
||||
.btn-info.disabled,
|
||||
.btn-warning.disabled,
|
||||
.btn-danger.disabled,
|
||||
.btn-default[disabled],
|
||||
.btn-primary[disabled],
|
||||
.btn-success[disabled],
|
||||
.btn-info[disabled],
|
||||
.btn-warning[disabled],
|
||||
.btn-danger[disabled],
|
||||
fieldset[disabled] .btn-default,
|
||||
fieldset[disabled] .btn-primary,
|
||||
fieldset[disabled] .btn-success,
|
||||
fieldset[disabled] .btn-info,
|
||||
fieldset[disabled] .btn-warning,
|
||||
fieldset[disabled] .btn-danger {
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.btn-default .badge,
|
||||
.btn-primary .badge,
|
||||
.btn-success .badge,
|
||||
.btn-info .badge,
|
||||
.btn-warning .badge,
|
||||
.btn-danger .badge {
|
||||
text-shadow: none;
|
||||
}
|
||||
.btn:active,
|
||||
.btn.active {
|
||||
background-image: none;
|
||||
}
|
||||
.btn-default {
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dbdbdb;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
border-color: #ccc;
|
||||
}
|
||||
.btn-default:hover,
|
||||
.btn-default:focus {
|
||||
background-color: #e0e0e0;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-default.active {
|
||||
background-color: #e0e0e0;
|
||||
border-color: #dbdbdb;
|
||||
}
|
||||
.btn-default.disabled,
|
||||
.btn-default[disabled],
|
||||
fieldset[disabled] .btn-default,
|
||||
.btn-default.disabled:hover,
|
||||
.btn-default[disabled]:hover,
|
||||
fieldset[disabled] .btn-default:hover,
|
||||
.btn-default.disabled:focus,
|
||||
.btn-default[disabled]:focus,
|
||||
fieldset[disabled] .btn-default:focus,
|
||||
.btn-default.disabled.focus,
|
||||
.btn-default[disabled].focus,
|
||||
fieldset[disabled] .btn-default.focus,
|
||||
.btn-default.disabled:active,
|
||||
.btn-default[disabled]:active,
|
||||
fieldset[disabled] .btn-default:active,
|
||||
.btn-default.disabled.active,
|
||||
.btn-default[disabled].active,
|
||||
fieldset[disabled] .btn-default.active {
|
||||
background-color: #e0e0e0;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-primary {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #245580;
|
||||
}
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus {
|
||||
background-color: #265a88;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-primary:active,
|
||||
.btn-primary.active {
|
||||
background-color: #265a88;
|
||||
border-color: #245580;
|
||||
}
|
||||
.btn-primary.disabled,
|
||||
.btn-primary[disabled],
|
||||
fieldset[disabled] .btn-primary,
|
||||
.btn-primary.disabled:hover,
|
||||
.btn-primary[disabled]:hover,
|
||||
fieldset[disabled] .btn-primary:hover,
|
||||
.btn-primary.disabled:focus,
|
||||
.btn-primary[disabled]:focus,
|
||||
fieldset[disabled] .btn-primary:focus,
|
||||
.btn-primary.disabled.focus,
|
||||
.btn-primary[disabled].focus,
|
||||
fieldset[disabled] .btn-primary.focus,
|
||||
.btn-primary.disabled:active,
|
||||
.btn-primary[disabled]:active,
|
||||
fieldset[disabled] .btn-primary:active,
|
||||
.btn-primary.disabled.active,
|
||||
.btn-primary[disabled].active,
|
||||
fieldset[disabled] .btn-primary.active {
|
||||
background-color: #265a88;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-success:hover,
|
||||
.btn-success:focus {
|
||||
background-color: #419641;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-success:active,
|
||||
.btn-success.active {
|
||||
background-color: #419641;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-success.disabled,
|
||||
.btn-success[disabled],
|
||||
fieldset[disabled] .btn-success,
|
||||
.btn-success.disabled:hover,
|
||||
.btn-success[disabled]:hover,
|
||||
fieldset[disabled] .btn-success:hover,
|
||||
.btn-success.disabled:focus,
|
||||
.btn-success[disabled]:focus,
|
||||
fieldset[disabled] .btn-success:focus,
|
||||
.btn-success.disabled.focus,
|
||||
.btn-success[disabled].focus,
|
||||
fieldset[disabled] .btn-success.focus,
|
||||
.btn-success.disabled:active,
|
||||
.btn-success[disabled]:active,
|
||||
fieldset[disabled] .btn-success:active,
|
||||
.btn-success.disabled.active,
|
||||
.btn-success[disabled].active,
|
||||
fieldset[disabled] .btn-success.active {
|
||||
background-color: #419641;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-info:hover,
|
||||
.btn-info:focus {
|
||||
background-color: #2aabd2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-info:active,
|
||||
.btn-info.active {
|
||||
background-color: #2aabd2;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-info.disabled,
|
||||
.btn-info[disabled],
|
||||
fieldset[disabled] .btn-info,
|
||||
.btn-info.disabled:hover,
|
||||
.btn-info[disabled]:hover,
|
||||
fieldset[disabled] .btn-info:hover,
|
||||
.btn-info.disabled:focus,
|
||||
.btn-info[disabled]:focus,
|
||||
fieldset[disabled] .btn-info:focus,
|
||||
.btn-info.disabled.focus,
|
||||
.btn-info[disabled].focus,
|
||||
fieldset[disabled] .btn-info.focus,
|
||||
.btn-info.disabled:active,
|
||||
.btn-info[disabled]:active,
|
||||
fieldset[disabled] .btn-info:active,
|
||||
.btn-info.disabled.active,
|
||||
.btn-info[disabled].active,
|
||||
fieldset[disabled] .btn-info.active {
|
||||
background-color: #2aabd2;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-warning:hover,
|
||||
.btn-warning:focus {
|
||||
background-color: #eb9316;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-warning:active,
|
||||
.btn-warning.active {
|
||||
background-color: #eb9316;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-warning.disabled,
|
||||
.btn-warning[disabled],
|
||||
fieldset[disabled] .btn-warning,
|
||||
.btn-warning.disabled:hover,
|
||||
.btn-warning[disabled]:hover,
|
||||
fieldset[disabled] .btn-warning:hover,
|
||||
.btn-warning.disabled:focus,
|
||||
.btn-warning[disabled]:focus,
|
||||
fieldset[disabled] .btn-warning:focus,
|
||||
.btn-warning.disabled.focus,
|
||||
.btn-warning[disabled].focus,
|
||||
fieldset[disabled] .btn-warning.focus,
|
||||
.btn-warning.disabled:active,
|
||||
.btn-warning[disabled]:active,
|
||||
fieldset[disabled] .btn-warning:active,
|
||||
.btn-warning.disabled.active,
|
||||
.btn-warning[disabled].active,
|
||||
fieldset[disabled] .btn-warning.active {
|
||||
background-color: #eb9316;
|
||||
background-image: none;
|
||||
}
|
||||
.btn-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.btn-danger:hover,
|
||||
.btn-danger:focus {
|
||||
background-color: #c12e2a;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-danger:active,
|
||||
.btn-danger.active {
|
||||
background-color: #c12e2a;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.btn-danger.disabled,
|
||||
.btn-danger[disabled],
|
||||
fieldset[disabled] .btn-danger,
|
||||
.btn-danger.disabled:hover,
|
||||
.btn-danger[disabled]:hover,
|
||||
fieldset[disabled] .btn-danger:hover,
|
||||
.btn-danger.disabled:focus,
|
||||
.btn-danger[disabled]:focus,
|
||||
fieldset[disabled] .btn-danger:focus,
|
||||
.btn-danger.disabled.focus,
|
||||
.btn-danger[disabled].focus,
|
||||
fieldset[disabled] .btn-danger.focus,
|
||||
.btn-danger.disabled:active,
|
||||
.btn-danger[disabled]:active,
|
||||
fieldset[disabled] .btn-danger:active,
|
||||
.btn-danger.disabled.active,
|
||||
.btn-danger[disabled].active,
|
||||
fieldset[disabled] .btn-danger.active {
|
||||
background-color: #c12e2a;
|
||||
background-image: none;
|
||||
}
|
||||
.thumbnail,
|
||||
.img-thumbnail {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
.dropdown-menu > .active > a,
|
||||
.dropdown-menu > .active > a:hover,
|
||||
.dropdown-menu > .active > a:focus {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
background-color: #2e6da4;
|
||||
}
|
||||
.navbar-default {
|
||||
background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
|
||||
background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f8f8f8));
|
||||
background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.navbar-default .navbar-nav > .open > a,
|
||||
.navbar-default .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
|
||||
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
|
||||
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.navbar-brand,
|
||||
.navbar-nav > li > a {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
.navbar-inverse {
|
||||
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
|
||||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.navbar-inverse .navbar-nav > .open > a,
|
||||
.navbar-inverse .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
|
||||
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
|
||||
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.navbar-inverse .navbar-brand,
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.navbar-static-top,
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
border-radius: 0;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.navbar .navbar-nav .open .dropdown-menu > .active > a,
|
||||
.navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
|
||||
.navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
|
||||
color: #fff;
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
}
|
||||
.alert {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.alert-success {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b2dba1;
|
||||
}
|
||||
.alert-info {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #9acfea;
|
||||
}
|
||||
.alert-warning {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #f5e79e;
|
||||
}
|
||||
.alert-danger {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dca7a7;
|
||||
}
|
||||
.progress {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-striped {
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.list-group {
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
.list-group-item.active,
|
||||
.list-group-item.active:hover,
|
||||
.list-group-item.active:focus {
|
||||
text-shadow: 0 -1px 0 #286090;
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
.list-group-item.active .badge,
|
||||
.list-group-item.active:hover .badge,
|
||||
.list-group-item.active:focus .badge {
|
||||
text-shadow: none;
|
||||
}
|
||||
.panel {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.panel-default > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-primary > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
|
||||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-success > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-info > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-warning > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-danger > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.well {
|
||||
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
|
||||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dcdcdc;
|
||||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-theme.css.map */
|
||||
6
tool-tech-file-view/src/main/resources/static/bootstrap/css/bootstrap-theme.min.css
vendored
Normal file
6
tool-tech-file-view/src/main/resources/static/bootstrap/css/bootstrap-theme.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
tool-tech-file-view/src/main/resources/static/bootstrap/css/bootstrap.min.css
vendored
Normal file
6
tool-tech-file-view/src/main/resources/static/bootstrap/css/bootstrap.min.css
vendored
Normal file
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.
6
tool-tech-file-view/src/main/resources/static/bootstrap/js/bootstrap.min.js
vendored
Normal file
6
tool-tech-file-view/src/main/resources/static/bootstrap/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
144
tool-tech-file-view/src/main/resources/static/bpmn/bpmn-js.css
Normal file
144
tool-tech-file-view/src/main/resources/static/bpmn/bpmn-js.css
Normal file
@@ -0,0 +1,144 @@
|
||||
.bjs-container {
|
||||
--bjs-font-family: Arial, sans-serif;
|
||||
|
||||
--color-grey-225-10-15: hsl(225, 10%, 15%);
|
||||
--color-grey-225-10-35: hsl(225, 10%, 35%);
|
||||
--color-grey-225-10-55: hsl(225, 10%, 55%);
|
||||
--color-grey-225-10-75: hsl(225, 10%, 75%);
|
||||
--color-grey-225-10-80: hsl(225, 10%, 80%);
|
||||
--color-grey-225-10-85: hsl(225, 10%, 85%);
|
||||
--color-grey-225-10-90: hsl(225, 10%, 90%);
|
||||
--color-grey-225-10-95: hsl(225, 10%, 95%);
|
||||
--color-grey-225-10-97: hsl(225, 10%, 97%);
|
||||
|
||||
--color-blue-205-100-45: hsl(205, 100%, 45%);
|
||||
--color-blue-205-100-45-opacity-30: hsla(205, 100%, 45%, 30%);
|
||||
--color-blue-205-100-50: hsl(205, 100%, 50%);
|
||||
--color-blue-205-100-95: hsl(205, 100%, 95%);
|
||||
|
||||
--color-green-150-86-44: hsl(150, 86%, 44%);
|
||||
|
||||
--color-red-360-100-40: hsl(360, 100%, 40%);
|
||||
--color-red-360-100-45: hsl(360, 100%, 45%);
|
||||
--color-red-360-100-92: hsl(360, 100%, 92%);
|
||||
--color-red-360-100-97: hsl(360, 100%, 97%);
|
||||
|
||||
--color-white: hsl(0, 0%, 100%);
|
||||
--color-black: hsl(0, 0%, 0%);
|
||||
--color-black-opacity-05: hsla(0, 0%, 0%, 5%);
|
||||
--color-black-opacity-10: hsla(0, 0%, 0%, 10%);
|
||||
|
||||
--breadcrumbs-font-family: var(--bjs-font-family);
|
||||
--breadcrumbs-item-color: var(--color-blue-205-100-50);
|
||||
--breadcrumbs-arrow-color: var(--color-black);
|
||||
--drilldown-fill-color: var(--color-white);
|
||||
--drilldown-background-color: var(--color-blue-205-100-50);
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs {
|
||||
position: absolute;
|
||||
display: none;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
top: 30px;
|
||||
left: 30px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
font-family: var(--breadcrumbs-font-family);
|
||||
font-size: 16px;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs-shown .bjs-breadcrumbs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.djs-palette-shown .bjs-breadcrumbs {
|
||||
left: 90px;
|
||||
}
|
||||
|
||||
.djs-palette-shown.djs-palette-two-column .bjs-breadcrumbs {
|
||||
left: 140px;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs li {
|
||||
display: inline-flex;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs li a {
|
||||
cursor: pointer;
|
||||
color: var(--breadcrumbs-item-color);
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs li:last-of-type a {
|
||||
color: inherit;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs li:not(:first-child)::before {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" /><path d="M0 0h24v24H0z" fill="none" /></svg>');
|
||||
padding: 0 8px;
|
||||
color: var(--breadcrumbs-arrow-color);
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.bjs-breadcrumbs .bjs-crumb {
|
||||
display: inline-block;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bjs-drilldown {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
padding: 0px;
|
||||
margin-left: -20px;
|
||||
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
|
||||
fill: var(--drilldown-fill-color);
|
||||
background-color: var(--drilldown-background-color);
|
||||
}
|
||||
|
||||
.bjs-drilldown-empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selected .bjs-drilldown-empty {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-results {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-body [data-group] + [data-group] {
|
||||
border-left: 1px solid var(--popup-border-color);
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] [data-group="align"] {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-body .entry {
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-body .entry:not(:first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
[data-popup="align-elements"] .djs-popup-entry-icon {
|
||||
display: block;
|
||||
margin: 0;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
163
tool-tech-file-view/src/main/resources/static/bpmn/bpmn.css
Normal file
163
tool-tech-file-view/src/main/resources/static/bpmn/bpmn.css
Normal file
@@ -0,0 +1,163 @@
|
||||
@font-face {
|
||||
font-family: 'bpmn';
|
||||
src: url('../font/bpmn.eot?21877404');
|
||||
src: url('../font/bpmn.eot?21877404#iefix') format('embedded-opentype'),
|
||||
url('../font/bpmn.woff2?21877404') format('woff2'),
|
||||
url('../font/bpmn.woff?21877404') format('woff'),
|
||||
url('../font/bpmn.ttf?21877404') format('truetype'),
|
||||
url('../font/bpmn.svg?21877404#bpmn') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||
/*
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'bpmn';
|
||||
src: url('../font/bpmn.svg?21877404#bpmn') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
[class^="bpmn-icon-"]:before, [class*=" bpmn-icon-"]:before {
|
||||
font-family: "bpmn";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: never;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
/* margin-right: .2em; */
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
/* margin-left: .2em; */
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.bpmn-icon-trash:before { content: '\e801'; } /* '' */
|
||||
.bpmn-icon-gateway-parallel:before { content: '\e804'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-cancel:before { content: '\e805'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-message:before { content: '\e806'; } /* '' */
|
||||
.bpmn-icon-start-event-compensation:before { content: '\e807'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-parallel-multiple:before { content: '\e808'; } /* '' */
|
||||
.bpmn-icon-loop-marker:before { content: '\e809'; } /* '' */
|
||||
.bpmn-icon-parallel-mi-marker:before { content: '\e80a'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-signal:before { content: '\e80b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-timer:before { content: '\e80c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-parallel-multiple:before { content: '\e80d'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-compensation:before { content: '\e80e'; } /* '' */
|
||||
.bpmn-icon-gateway-xor:before { content: '\e80f'; } /* '' */
|
||||
.bpmn-icon-end-event-cancel:before { content: '\e811'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-condition:before { content: '\e812'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-parallel-multiple:before { content: '\e813'; } /* '' */
|
||||
.bpmn-icon-start-event-condition:before { content: '\e814'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-timer:before { content: '\e815'; } /* '' */
|
||||
.bpmn-icon-sequential-mi-marker:before { content: '\e816'; } /* '' */
|
||||
.bpmn-icon-user-task:before { content: '\e817'; } /* '' */
|
||||
.bpmn-icon-business-rule:before { content: '\e818'; } /* '' */
|
||||
.bpmn-icon-sub-process-marker:before { content: '\e819'; } /* '' */
|
||||
.bpmn-icon-start-event-parallel-multiple:before { content: '\e81a'; } /* '' */
|
||||
.bpmn-icon-start-event-error:before { content: '\e81b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-signal:before { content: '\e81c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-error:before { content: '\e81d'; } /* '' */
|
||||
.bpmn-icon-end-event-compensation:before { content: '\e81e'; } /* '' */
|
||||
.bpmn-icon-subprocess-collapsed:before { content: '\e81f'; } /* '' */
|
||||
.bpmn-icon-subprocess-expanded:before { content: '\e820'; } /* '' */
|
||||
.bpmn-icon-task:before { content: '\e821'; } /* '' */
|
||||
.bpmn-icon-end-event-error:before { content: '\e822'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-escalation:before { content: '\e823'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-timer:before { content: '\e824'; } /* '' */
|
||||
.bpmn-icon-start-event-escalation:before { content: '\e825'; } /* '' */
|
||||
.bpmn-icon-start-event-signal:before { content: '\e826'; } /* '' */
|
||||
.bpmn-icon-business-rule-task:before { content: '\e827'; } /* '' */
|
||||
.bpmn-icon-manual:before { content: '\e828'; } /* '' */
|
||||
.bpmn-icon-receive:before { content: '\e829'; } /* '' */
|
||||
.bpmn-icon-call-activity:before { content: '\e82a'; } /* '' */
|
||||
.bpmn-icon-start-event-timer:before { content: '\e82b'; } /* '' */
|
||||
.bpmn-icon-start-event-message:before { content: '\e82c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-none:before { content: '\e82d'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-link:before { content: '\e82e'; } /* '' */
|
||||
.bpmn-icon-end-event-escalation:before { content: '\e82f'; } /* '' */
|
||||
.bpmn-icon-bpmn-io:before { content: '\e831'; } /* '' */
|
||||
.bpmn-icon-gateway-complex:before { content: '\e832'; } /* '' */
|
||||
.bpmn-icon-gateway-eventbased:before { content: '\e833'; } /* '' */
|
||||
.bpmn-icon-gateway-none:before { content: '\e834'; } /* '' */
|
||||
.bpmn-icon-gateway-or:before { content: '\e835'; } /* '' */
|
||||
.bpmn-icon-end-event-terminate:before { content: '\e836'; } /* '' */
|
||||
.bpmn-icon-end-event-signal:before { content: '\e837'; } /* '' */
|
||||
.bpmn-icon-end-event-none:before { content: '\e838'; } /* '' */
|
||||
.bpmn-icon-end-event-multiple:before { content: '\e839'; } /* '' */
|
||||
.bpmn-icon-end-event-message:before { content: '\e83a'; } /* '' */
|
||||
.bpmn-icon-end-event-link:before { content: '\e83b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-message:before { content: '\e83c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-compensation:before { content: '\e83d'; } /* '' */
|
||||
.bpmn-icon-start-event-multiple:before { content: '\e83e'; } /* '' */
|
||||
.bpmn-icon-script:before { content: '\e83f'; } /* '' */
|
||||
.bpmn-icon-manual-task:before { content: '\e840'; } /* '' */
|
||||
.bpmn-icon-send:before { content: '\e841'; } /* '' */
|
||||
.bpmn-icon-service:before { content: '\e842'; } /* '' */
|
||||
.bpmn-icon-receive-task:before { content: '\e843'; } /* '' */
|
||||
.bpmn-icon-user:before { content: '\e844'; } /* '' */
|
||||
.bpmn-icon-start-event-none:before { content: '\e845'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-escalation:before { content: '\e846'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-multiple:before { content: '\e847'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-escalation:before { content: '\e848'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-link:before { content: '\e849'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-condition:before { content: '\e84a'; } /* '' */
|
||||
.bpmn-icon-data-object:before { content: '\e84b'; } /* '' */
|
||||
.bpmn-icon-script-task:before { content: '\e84c'; } /* '' */
|
||||
.bpmn-icon-send-task:before { content: '\e84d'; } /* '' */
|
||||
.bpmn-icon-data-store:before { content: '\e84e'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-escalation:before { content: '\e84f'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-message:before { content: '\e850'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-multiple:before { content: '\e851'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-signal:before { content: '\e852'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-multiple:before { content: '\e853'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-message:before { content: '\e854'; } /* '' */
|
||||
.bpmn-icon-ad-hoc-marker:before { content: '\e855'; } /* '' */
|
||||
.bpmn-icon-service-task:before { content: '\e856'; } /* '' */
|
||||
.bpmn-icon-task-none:before { content: '\e857'; } /* '' */
|
||||
.bpmn-icon-compensation-marker:before { content: '\e858'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-multiple:before { content: '\e859'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-signal:before { content: '\e85a'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-condition:before { content: '\e85b'; } /* '' */
|
||||
.bpmn-icon-participant:before { content: '\e85c'; } /* '' */
|
||||
.bpmn-icon-event-subprocess-expanded:before { content: '\e85d'; } /* '' */
|
||||
.bpmn-icon-lane-insert-below:before { content: '\e85e'; } /* '' */
|
||||
.bpmn-icon-space-tool:before { content: '\e85f'; } /* '' */
|
||||
.bpmn-icon-connection-multi:before { content: '\e860'; } /* '' */
|
||||
.bpmn-icon-lane:before { content: '\e861'; } /* '' */
|
||||
.bpmn-icon-lasso-tool:before { content: '\e862'; } /* '' */
|
||||
.bpmn-icon-lane-insert-above:before { content: '\e863'; } /* '' */
|
||||
.bpmn-icon-lane-divide-three:before { content: '\e864'; } /* '' */
|
||||
.bpmn-icon-lane-divide-two:before { content: '\e865'; } /* '' */
|
||||
.bpmn-icon-data-input:before { content: '\e866'; } /* '' */
|
||||
.bpmn-icon-data-output:before { content: '\e867'; } /* '' */
|
||||
.bpmn-icon-hand-tool:before { content: '\e868'; } /* '' */
|
||||
.bpmn-icon-group:before { content: '\e869'; } /* '' */
|
||||
.bpmn-icon-text-annotation:before { content: '\e86b'; } /* '' */
|
||||
.bpmn-icon-transaction:before { content: '\e8c4'; } /* '' */
|
||||
.bpmn-icon-screw-wrench:before { content: '\e8db'; } /* '' */
|
||||
.bpmn-icon-connection:before { content: '\e8dc'; } /* '' */
|
||||
.bpmn-icon-conditional-flow:before { content: '\e8e0'; } /* '' */
|
||||
.bpmn-icon-default-flow:before { content: '\e8e1'; } /* '' */
|
||||
@@ -0,0 +1,108 @@
|
||||
|
||||
.bpmn-icon-trash:before { content: '\e801'; } /* '' */
|
||||
.bpmn-icon-gateway-parallel:before { content: '\e804'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-cancel:before { content: '\e805'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-message:before { content: '\e806'; } /* '' */
|
||||
.bpmn-icon-start-event-compensation:before { content: '\e807'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-parallel-multiple:before { content: '\e808'; } /* '' */
|
||||
.bpmn-icon-loop-marker:before { content: '\e809'; } /* '' */
|
||||
.bpmn-icon-parallel-mi-marker:before { content: '\e80a'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-signal:before { content: '\e80b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-timer:before { content: '\e80c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-parallel-multiple:before { content: '\e80d'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-compensation:before { content: '\e80e'; } /* '' */
|
||||
.bpmn-icon-gateway-xor:before { content: '\e80f'; } /* '' */
|
||||
.bpmn-icon-end-event-cancel:before { content: '\e811'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-condition:before { content: '\e812'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-parallel-multiple:before { content: '\e813'; } /* '' */
|
||||
.bpmn-icon-start-event-condition:before { content: '\e814'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-timer:before { content: '\e815'; } /* '' */
|
||||
.bpmn-icon-sequential-mi-marker:before { content: '\e816'; } /* '' */
|
||||
.bpmn-icon-user-task:before { content: '\e817'; } /* '' */
|
||||
.bpmn-icon-business-rule:before { content: '\e818'; } /* '' */
|
||||
.bpmn-icon-sub-process-marker:before { content: '\e819'; } /* '' */
|
||||
.bpmn-icon-start-event-parallel-multiple:before { content: '\e81a'; } /* '' */
|
||||
.bpmn-icon-start-event-error:before { content: '\e81b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-signal:before { content: '\e81c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-error:before { content: '\e81d'; } /* '' */
|
||||
.bpmn-icon-end-event-compensation:before { content: '\e81e'; } /* '' */
|
||||
.bpmn-icon-subprocess-collapsed:before { content: '\e81f'; } /* '' */
|
||||
.bpmn-icon-subprocess-expanded:before { content: '\e820'; } /* '' */
|
||||
.bpmn-icon-task:before { content: '\e821'; } /* '' */
|
||||
.bpmn-icon-end-event-error:before { content: '\e822'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-escalation:before { content: '\e823'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-timer:before { content: '\e824'; } /* '' */
|
||||
.bpmn-icon-start-event-escalation:before { content: '\e825'; } /* '' */
|
||||
.bpmn-icon-start-event-signal:before { content: '\e826'; } /* '' */
|
||||
.bpmn-icon-business-rule-task:before { content: '\e827'; } /* '' */
|
||||
.bpmn-icon-manual:before { content: '\e828'; } /* '' */
|
||||
.bpmn-icon-receive:before { content: '\e829'; } /* '' */
|
||||
.bpmn-icon-call-activity:before { content: '\e82a'; } /* '' */
|
||||
.bpmn-icon-start-event-timer:before { content: '\e82b'; } /* '' */
|
||||
.bpmn-icon-start-event-message:before { content: '\e82c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-none:before { content: '\e82d'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-link:before { content: '\e82e'; } /* '' */
|
||||
.bpmn-icon-end-event-escalation:before { content: '\e82f'; } /* '' */
|
||||
.bpmn-icon-bpmn-io:before { content: '\e831'; } /* '' */
|
||||
.bpmn-icon-gateway-complex:before { content: '\e832'; } /* '' */
|
||||
.bpmn-icon-gateway-eventbased:before { content: '\e833'; } /* '' */
|
||||
.bpmn-icon-gateway-none:before { content: '\e834'; } /* '' */
|
||||
.bpmn-icon-gateway-or:before { content: '\e835'; } /* '' */
|
||||
.bpmn-icon-end-event-terminate:before { content: '\e836'; } /* '' */
|
||||
.bpmn-icon-end-event-signal:before { content: '\e837'; } /* '' */
|
||||
.bpmn-icon-end-event-none:before { content: '\e838'; } /* '' */
|
||||
.bpmn-icon-end-event-multiple:before { content: '\e839'; } /* '' */
|
||||
.bpmn-icon-end-event-message:before { content: '\e83a'; } /* '' */
|
||||
.bpmn-icon-end-event-link:before { content: '\e83b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-message:before { content: '\e83c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-compensation:before { content: '\e83d'; } /* '' */
|
||||
.bpmn-icon-start-event-multiple:before { content: '\e83e'; } /* '' */
|
||||
.bpmn-icon-script:before { content: '\e83f'; } /* '' */
|
||||
.bpmn-icon-manual-task:before { content: '\e840'; } /* '' */
|
||||
.bpmn-icon-send:before { content: '\e841'; } /* '' */
|
||||
.bpmn-icon-service:before { content: '\e842'; } /* '' */
|
||||
.bpmn-icon-receive-task:before { content: '\e843'; } /* '' */
|
||||
.bpmn-icon-user:before { content: '\e844'; } /* '' */
|
||||
.bpmn-icon-start-event-none:before { content: '\e845'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-escalation:before { content: '\e846'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-multiple:before { content: '\e847'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-escalation:before { content: '\e848'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-link:before { content: '\e849'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-condition:before { content: '\e84a'; } /* '' */
|
||||
.bpmn-icon-data-object:before { content: '\e84b'; } /* '' */
|
||||
.bpmn-icon-script-task:before { content: '\e84c'; } /* '' */
|
||||
.bpmn-icon-send-task:before { content: '\e84d'; } /* '' */
|
||||
.bpmn-icon-data-store:before { content: '\e84e'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-escalation:before { content: '\e84f'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-message:before { content: '\e850'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-multiple:before { content: '\e851'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-signal:before { content: '\e852'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-multiple:before { content: '\e853'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-message:before { content: '\e854'; } /* '' */
|
||||
.bpmn-icon-ad-hoc-marker:before { content: '\e855'; } /* '' */
|
||||
.bpmn-icon-service-task:before { content: '\e856'; } /* '' */
|
||||
.bpmn-icon-task-none:before { content: '\e857'; } /* '' */
|
||||
.bpmn-icon-compensation-marker:before { content: '\e858'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-multiple:before { content: '\e859'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-signal:before { content: '\e85a'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-condition:before { content: '\e85b'; } /* '' */
|
||||
.bpmn-icon-participant:before { content: '\e85c'; } /* '' */
|
||||
.bpmn-icon-event-subprocess-expanded:before { content: '\e85d'; } /* '' */
|
||||
.bpmn-icon-lane-insert-below:before { content: '\e85e'; } /* '' */
|
||||
.bpmn-icon-space-tool:before { content: '\e85f'; } /* '' */
|
||||
.bpmn-icon-connection-multi:before { content: '\e860'; } /* '' */
|
||||
.bpmn-icon-lane:before { content: '\e861'; } /* '' */
|
||||
.bpmn-icon-lasso-tool:before { content: '\e862'; } /* '' */
|
||||
.bpmn-icon-lane-insert-above:before { content: '\e863'; } /* '' */
|
||||
.bpmn-icon-lane-divide-three:before { content: '\e864'; } /* '' */
|
||||
.bpmn-icon-lane-divide-two:before { content: '\e865'; } /* '' */
|
||||
.bpmn-icon-data-input:before { content: '\e866'; } /* '' */
|
||||
.bpmn-icon-data-output:before { content: '\e867'; } /* '' */
|
||||
.bpmn-icon-hand-tool:before { content: '\e868'; } /* '' */
|
||||
.bpmn-icon-group:before { content: '\e869'; } /* '' */
|
||||
.bpmn-icon-text-annotation:before { content: '\e86b'; } /* '' */
|
||||
.bpmn-icon-transaction:before { content: '\e8c4'; } /* '' */
|
||||
.bpmn-icon-screw-wrench:before { content: '\e8db'; } /* '' */
|
||||
.bpmn-icon-connection:before { content: '\e8dc'; } /* '' */
|
||||
.bpmn-icon-conditional-flow:before { content: '\e8e0'; } /* '' */
|
||||
.bpmn-icon-default-flow:before { content: '\e8e1'; } /* '' */
|
||||
File diff suppressed because one or more lines are too long
163
tool-tech-file-view/src/main/resources/static/bpmn/css/bpmn.css
Normal file
163
tool-tech-file-view/src/main/resources/static/bpmn/css/bpmn.css
Normal file
@@ -0,0 +1,163 @@
|
||||
@font-face {
|
||||
font-family: 'bpmn';
|
||||
src: url('../font/bpmn.eot?21877404');
|
||||
src: url('../font/bpmn.eot?21877404#iefix') format('embedded-opentype'),
|
||||
url('../font/bpmn.woff2?21877404') format('woff2'),
|
||||
url('../font/bpmn.woff?21877404') format('woff'),
|
||||
url('../font/bpmn.ttf?21877404') format('truetype'),
|
||||
url('../font/bpmn.svg?21877404#bpmn') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||
/*
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'bpmn';
|
||||
src: url('../font/bpmn.svg?21877404#bpmn') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
[class^="bpmn-icon-"]:before, [class*=" bpmn-icon-"]:before {
|
||||
font-family: "bpmn";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: never;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
/* margin-right: .2em; */
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
/* margin-left: .2em; */
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.bpmn-icon-trash:before { content: '\e801'; } /* '' */
|
||||
.bpmn-icon-gateway-parallel:before { content: '\e804'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-cancel:before { content: '\e805'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-message:before { content: '\e806'; } /* '' */
|
||||
.bpmn-icon-start-event-compensation:before { content: '\e807'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-parallel-multiple:before { content: '\e808'; } /* '' */
|
||||
.bpmn-icon-loop-marker:before { content: '\e809'; } /* '' */
|
||||
.bpmn-icon-parallel-mi-marker:before { content: '\e80a'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-signal:before { content: '\e80b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-timer:before { content: '\e80c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-parallel-multiple:before { content: '\e80d'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-compensation:before { content: '\e80e'; } /* '' */
|
||||
.bpmn-icon-gateway-xor:before { content: '\e80f'; } /* '' */
|
||||
.bpmn-icon-end-event-cancel:before { content: '\e811'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-condition:before { content: '\e812'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-parallel-multiple:before { content: '\e813'; } /* '' */
|
||||
.bpmn-icon-start-event-condition:before { content: '\e814'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-timer:before { content: '\e815'; } /* '' */
|
||||
.bpmn-icon-sequential-mi-marker:before { content: '\e816'; } /* '' */
|
||||
.bpmn-icon-user-task:before { content: '\e817'; } /* '' */
|
||||
.bpmn-icon-business-rule:before { content: '\e818'; } /* '' */
|
||||
.bpmn-icon-sub-process-marker:before { content: '\e819'; } /* '' */
|
||||
.bpmn-icon-start-event-parallel-multiple:before { content: '\e81a'; } /* '' */
|
||||
.bpmn-icon-start-event-error:before { content: '\e81b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-signal:before { content: '\e81c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-error:before { content: '\e81d'; } /* '' */
|
||||
.bpmn-icon-end-event-compensation:before { content: '\e81e'; } /* '' */
|
||||
.bpmn-icon-subprocess-collapsed:before { content: '\e81f'; } /* '' */
|
||||
.bpmn-icon-subprocess-expanded:before { content: '\e820'; } /* '' */
|
||||
.bpmn-icon-task:before { content: '\e821'; } /* '' */
|
||||
.bpmn-icon-end-event-error:before { content: '\e822'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-escalation:before { content: '\e823'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-timer:before { content: '\e824'; } /* '' */
|
||||
.bpmn-icon-start-event-escalation:before { content: '\e825'; } /* '' */
|
||||
.bpmn-icon-start-event-signal:before { content: '\e826'; } /* '' */
|
||||
.bpmn-icon-business-rule-task:before { content: '\e827'; } /* '' */
|
||||
.bpmn-icon-manual:before { content: '\e828'; } /* '' */
|
||||
.bpmn-icon-receive:before { content: '\e829'; } /* '' */
|
||||
.bpmn-icon-call-activity:before { content: '\e82a'; } /* '' */
|
||||
.bpmn-icon-start-event-timer:before { content: '\e82b'; } /* '' */
|
||||
.bpmn-icon-start-event-message:before { content: '\e82c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-none:before { content: '\e82d'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-link:before { content: '\e82e'; } /* '' */
|
||||
.bpmn-icon-end-event-escalation:before { content: '\e82f'; } /* '' */
|
||||
.bpmn-icon-bpmn-io:before { content: '\e831'; } /* '' */
|
||||
.bpmn-icon-gateway-complex:before { content: '\e832'; } /* '' */
|
||||
.bpmn-icon-gateway-eventbased:before { content: '\e833'; } /* '' */
|
||||
.bpmn-icon-gateway-none:before { content: '\e834'; } /* '' */
|
||||
.bpmn-icon-gateway-or:before { content: '\e835'; } /* '' */
|
||||
.bpmn-icon-end-event-terminate:before { content: '\e836'; } /* '' */
|
||||
.bpmn-icon-end-event-signal:before { content: '\e837'; } /* '' */
|
||||
.bpmn-icon-end-event-none:before { content: '\e838'; } /* '' */
|
||||
.bpmn-icon-end-event-multiple:before { content: '\e839'; } /* '' */
|
||||
.bpmn-icon-end-event-message:before { content: '\e83a'; } /* '' */
|
||||
.bpmn-icon-end-event-link:before { content: '\e83b'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-message:before { content: '\e83c'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-compensation:before { content: '\e83d'; } /* '' */
|
||||
.bpmn-icon-start-event-multiple:before { content: '\e83e'; } /* '' */
|
||||
.bpmn-icon-script:before { content: '\e83f'; } /* '' */
|
||||
.bpmn-icon-manual-task:before { content: '\e840'; } /* '' */
|
||||
.bpmn-icon-send:before { content: '\e841'; } /* '' */
|
||||
.bpmn-icon-service:before { content: '\e842'; } /* '' */
|
||||
.bpmn-icon-receive-task:before { content: '\e843'; } /* '' */
|
||||
.bpmn-icon-user:before { content: '\e844'; } /* '' */
|
||||
.bpmn-icon-start-event-none:before { content: '\e845'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-escalation:before { content: '\e846'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-multiple:before { content: '\e847'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-escalation:before { content: '\e848'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-link:before { content: '\e849'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-condition:before { content: '\e84a'; } /* '' */
|
||||
.bpmn-icon-data-object:before { content: '\e84b'; } /* '' */
|
||||
.bpmn-icon-script-task:before { content: '\e84c'; } /* '' */
|
||||
.bpmn-icon-send-task:before { content: '\e84d'; } /* '' */
|
||||
.bpmn-icon-data-store:before { content: '\e84e'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-escalation:before { content: '\e84f'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-message:before { content: '\e850'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-multiple:before { content: '\e851'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-signal:before { content: '\e852'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-multiple:before { content: '\e853'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-message:before { content: '\e854'; } /* '' */
|
||||
.bpmn-icon-ad-hoc-marker:before { content: '\e855'; } /* '' */
|
||||
.bpmn-icon-service-task:before { content: '\e856'; } /* '' */
|
||||
.bpmn-icon-task-none:before { content: '\e857'; } /* '' */
|
||||
.bpmn-icon-compensation-marker:before { content: '\e858'; } /* '' */
|
||||
.bpmn-icon-start-event-non-interrupting-multiple:before { content: '\e859'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-throw-signal:before { content: '\e85a'; } /* '' */
|
||||
.bpmn-icon-intermediate-event-catch-non-interrupting-condition:before { content: '\e85b'; } /* '' */
|
||||
.bpmn-icon-participant:before { content: '\e85c'; } /* '' */
|
||||
.bpmn-icon-event-subprocess-expanded:before { content: '\e85d'; } /* '' */
|
||||
.bpmn-icon-lane-insert-below:before { content: '\e85e'; } /* '' */
|
||||
.bpmn-icon-space-tool:before { content: '\e85f'; } /* '' */
|
||||
.bpmn-icon-connection-multi:before { content: '\e860'; } /* '' */
|
||||
.bpmn-icon-lane:before { content: '\e861'; } /* '' */
|
||||
.bpmn-icon-lasso-tool:before { content: '\e862'; } /* '' */
|
||||
.bpmn-icon-lane-insert-above:before { content: '\e863'; } /* '' */
|
||||
.bpmn-icon-lane-divide-three:before { content: '\e864'; } /* '' */
|
||||
.bpmn-icon-lane-divide-two:before { content: '\e865'; } /* '' */
|
||||
.bpmn-icon-data-input:before { content: '\e866'; } /* '' */
|
||||
.bpmn-icon-data-output:before { content: '\e867'; } /* '' */
|
||||
.bpmn-icon-hand-tool:before { content: '\e868'; } /* '' */
|
||||
.bpmn-icon-group:before { content: '\e869'; } /* '' */
|
||||
.bpmn-icon-text-annotation:before { content: '\e86b'; } /* '' */
|
||||
.bpmn-icon-transaction:before { content: '\e8c4'; } /* '' */
|
||||
.bpmn-icon-screw-wrench:before { content: '\e8db'; } /* '' */
|
||||
.bpmn-icon-connection:before { content: '\e8dc'; } /* '' */
|
||||
.bpmn-icon-conditional-flow:before { content: '\e8e0'; } /* '' */
|
||||
.bpmn-icon-default-flow:before { content: '\e8e1'; } /* '' */
|
||||
@@ -0,0 +1,986 @@
|
||||
/**
|
||||
* color definitions
|
||||
*/
|
||||
.djs-parent {
|
||||
--color-grey-225-10-15: hsl(225, 10%, 15%);
|
||||
--color-grey-225-10-35: hsl(225, 10%, 35%);
|
||||
--color-grey-225-10-55: hsl(225, 10%, 55%);
|
||||
--color-grey-225-10-75: hsl(225, 10%, 75%);
|
||||
--color-grey-225-10-80: hsl(225, 10%, 80%);
|
||||
--color-grey-225-10-85: hsl(225, 10%, 85%);
|
||||
--color-grey-225-10-90: hsl(225, 10%, 90%);
|
||||
--color-grey-225-10-95: hsl(225, 10%, 95%);
|
||||
--color-grey-225-10-97: hsl(225, 10%, 97%);
|
||||
|
||||
--color-blue-205-100-45: hsl(205, 100%, 45%);
|
||||
--color-blue-205-100-45-opacity-30: hsla(205, 100%, 45%, 30%);
|
||||
--color-blue-205-100-50: hsl(205, 100%, 50%);
|
||||
--color-blue-205-100-50-opacity-15: hsla(205, 100%, 50%, 15%);
|
||||
--color-blue-205-100-70: hsl(205, 100%, 75%);
|
||||
--color-blue-205-100-95: hsl(205, 100%, 95%);
|
||||
|
||||
--color-green-150-86-44: hsl(150, 86%, 44%);
|
||||
|
||||
--color-red-360-100-40: hsl(360, 100%, 40%);
|
||||
--color-red-360-100-45: hsl(360, 100%, 45%);
|
||||
--color-red-360-100-92: hsl(360, 100%, 92%);
|
||||
--color-red-360-100-97: hsl(360, 100%, 97%);
|
||||
|
||||
--color-white: hsl(0, 0%, 100%);
|
||||
--color-black: hsl(0, 0%, 0%);
|
||||
--color-black-opacity-10: hsla(0, 0%, 0%, 10%);
|
||||
--color-black-opacity-30: hsla(0, 0%, 0%, 30%);
|
||||
|
||||
--canvas-fill-color: var(--color-white);
|
||||
|
||||
--bendpoint-fill-color: var(--color-blue-205-100-45);
|
||||
--bendpoint-stroke-color: var(--canvas-fill-color);
|
||||
|
||||
--context-pad-entry-background-color: var(--color-white);
|
||||
--context-pad-entry-hover-background-color: var(--color-grey-225-10-95);
|
||||
|
||||
--element-dragger-color: var(--color-blue-205-100-50);
|
||||
--element-hover-outline-fill-color: var(--color-blue-205-100-45);
|
||||
--element-selected-outline-stroke-color: var(--color-blue-205-100-50);
|
||||
--element-selected-outline-secondary-stroke-color: var(--color-blue-205-100-70);
|
||||
|
||||
--lasso-fill-color: var(--color-blue-205-100-50-opacity-15);
|
||||
--lasso-stroke-color: var(--element-selected-outline-stroke-color);
|
||||
|
||||
--palette-entry-color: var(--color-grey-225-10-15);
|
||||
--palette-entry-hover-color: var(--color-blue-205-100-45);
|
||||
--palette-entry-selected-color: var(--color-blue-205-100-50);
|
||||
--palette-separator-color: var(--color-grey-225-10-75);
|
||||
--palette-toggle-hover-background-color: var(--color-grey-225-10-55);
|
||||
--palette-background-color: var(--color-grey-225-10-97);
|
||||
--palette-border-color: var(--color-grey-225-10-75);
|
||||
|
||||
--popup-font-size: 14px;
|
||||
--popup-header-entry-selected-color: var(--color-blue-205-100-50);
|
||||
--popup-header-font-weight: bolder;
|
||||
--popup-background-color: var(--color-white);
|
||||
--popup-border-color: transparent;
|
||||
--popup-shadow-color: var(--color-black-opacity-30);
|
||||
--popup-description-color: var(--color-grey-225-10-55);
|
||||
--popup-no-results-color: var(--color-grey-225-10-55);
|
||||
--popup-entry-title-color: var(--color-grey-225-10-55);
|
||||
--popup-entry-hover-color: var(--color-grey-225-10-95);
|
||||
--popup-search-border-color: var(--color-grey-225-10-75);
|
||||
--popup-search-focus-border-color: var(--color-blue-205-100-50);
|
||||
--popup-search-focus-background-color: var(--color-blue-205-100-95);
|
||||
|
||||
--resizer-fill-color: var(--color-blue-205-100-45);
|
||||
--resizer-stroke-color: var(--canvas-fill-color);
|
||||
|
||||
--search-container-background-color: var(--color-grey-225-10-97);
|
||||
--search-container-border-color: var(--color-blue-205-100-50);
|
||||
--search-container-box-shadow-color: var(--color-blue-205-100-95);
|
||||
--search-container-box-shadow-inset-color: var(--color-grey-225-10-80);
|
||||
--search-input-border-color: var(--color-grey-225-10-75);
|
||||
--search-result-border-color: var(--color-grey-225-10-75);
|
||||
--search-result-highlight-color: var(--color-black);
|
||||
--search-result-selected-color: var(--color-blue-205-100-45-opacity-30);
|
||||
|
||||
--shape-attach-allowed-stroke-color: var(--color-blue-205-100-50);
|
||||
--shape-connect-allowed-fill-color: var(--color-grey-225-10-97);
|
||||
--shape-drop-allowed-fill-color: var(--color-grey-225-10-97);
|
||||
--shape-drop-not-allowed-fill-color: var(--color-red-360-100-97);
|
||||
--shape-resize-preview-stroke-color: var(--color-blue-205-100-50);
|
||||
|
||||
--snap-line-stroke-color: var(--color-blue-205-100-45-opacity-30);
|
||||
|
||||
--space-tool-crosshair-stroke-color: var(--color-black);
|
||||
|
||||
--tooltip-error-background-color: var(--color-red-360-100-97);
|
||||
--tooltip-error-border-color: var(--color-red-360-100-45);
|
||||
--tooltip-error-color: var(--color-red-360-100-45);
|
||||
}
|
||||
|
||||
/**
|
||||
* outline styles
|
||||
*/
|
||||
|
||||
.djs-outline,
|
||||
.djs-selection-outline {
|
||||
fill: none;
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.djs-outline {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.djs-selection-outline {
|
||||
stroke: var(--element-selected-outline-stroke-color);
|
||||
}
|
||||
|
||||
.djs-element.selected .djs-outline {
|
||||
visibility: visible;
|
||||
|
||||
stroke: var(--element-selected-outline-stroke-color);
|
||||
}
|
||||
|
||||
.djs-multi-select .djs-element.selected .djs-outline {
|
||||
stroke: var(--element-selected-outline-secondary-stroke-color);
|
||||
}
|
||||
|
||||
.djs-shape.connect-ok .djs-visual > :nth-child(1) {
|
||||
fill: var(--shape-connect-allowed-fill-color) !important;
|
||||
}
|
||||
|
||||
.djs-shape.connect-not-ok .djs-visual > :nth-child(1),
|
||||
.djs-shape.drop-not-ok .djs-visual > :nth-child(1) {
|
||||
fill: var(--shape-drop-not-allowed-fill-color) !important;
|
||||
}
|
||||
|
||||
.djs-shape.new-parent .djs-visual > :nth-child(1) {
|
||||
fill: var(--shape-drop-allowed-fill-color) !important;
|
||||
}
|
||||
|
||||
svg.drop-not-ok {
|
||||
background: var(--shape-drop-not-allowed-fill-color) !important;
|
||||
}
|
||||
|
||||
svg.new-parent {
|
||||
background: var(--shape-drop-allowed-fill-color) !important;
|
||||
}
|
||||
|
||||
|
||||
/* Override move cursor during drop and connect */
|
||||
.drop-not-ok,
|
||||
.connect-not-ok,
|
||||
.drop-not-ok *,
|
||||
.connect-not-ok * {
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
.drop-ok,
|
||||
.connect-ok,
|
||||
.drop-ok *,
|
||||
.connect-ok * {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
.djs-element.attach-ok .djs-visual > :nth-child(1) {
|
||||
stroke-width: 5px !important;
|
||||
stroke: var(--shape-attach-allowed-stroke-color) !important;
|
||||
}
|
||||
|
||||
.djs-frame.connect-not-ok .djs-visual > :nth-child(1),
|
||||
.djs-frame.drop-not-ok .djs-visual > :nth-child(1) {
|
||||
stroke-width: 3px !important;
|
||||
stroke: var(--shape-drop-not-allowed-fill-color) !important;
|
||||
fill: none !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selection box style
|
||||
*
|
||||
*/
|
||||
.djs-lasso-overlay {
|
||||
fill: var(--lasso-fill-color);
|
||||
stroke: var(--lasso-stroke-color);
|
||||
stroke-width: 2px;
|
||||
shape-rendering: geometricPrecision;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize styles
|
||||
*/
|
||||
.djs-resize-overlay {
|
||||
fill: none;
|
||||
|
||||
stroke-dasharray: 5 1 3 1;
|
||||
stroke: var(--shape-resize-preview-stroke-color);
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.djs-resizer-hit {
|
||||
fill: none;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.djs-resizer-visual {
|
||||
fill: var(--resizer-fill-color);
|
||||
stroke-width: 1px;
|
||||
stroke: var(--resizer-stroke-color);
|
||||
shape-rendering: geometricPrecision;
|
||||
}
|
||||
|
||||
.djs-resizer:hover .djs-resizer-visual {
|
||||
stroke: var(--resizer-stroke-color);
|
||||
stroke-opacity: 1;
|
||||
}
|
||||
|
||||
.djs-cursor-resize-ns,
|
||||
.djs-resizer-n,
|
||||
.djs-resizer-s {
|
||||
cursor: ns-resize;
|
||||
}
|
||||
|
||||
.djs-cursor-resize-ew,
|
||||
.djs-resizer-e,
|
||||
.djs-resizer-w {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.djs-cursor-resize-nwse,
|
||||
.djs-resizer-nw,
|
||||
.djs-resizer-se {
|
||||
cursor: nwse-resize;
|
||||
}
|
||||
|
||||
.djs-cursor-resize-nesw,
|
||||
.djs-resizer-ne,
|
||||
.djs-resizer-sw {
|
||||
cursor: nesw-resize;
|
||||
}
|
||||
|
||||
.djs-shape.djs-resizing > .djs-outline {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
.djs-shape.djs-resizing > .djs-resizer {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.djs-dragger > .djs-resizer {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* drag styles
|
||||
*/
|
||||
.djs-dragger * {
|
||||
fill: none !important;
|
||||
stroke: var(--element-dragger-color) !important;
|
||||
}
|
||||
|
||||
.djs-dragger tspan,
|
||||
.djs-dragger text {
|
||||
fill: var(--element-dragger-color) !important;
|
||||
stroke: none !important;
|
||||
}
|
||||
|
||||
marker.djs-dragger circle,
|
||||
marker.djs-dragger path,
|
||||
marker.djs-dragger polygon,
|
||||
marker.djs-dragger polyline,
|
||||
marker.djs-dragger rect {
|
||||
fill: var(--element-dragger-color) !important;
|
||||
stroke: none !important;
|
||||
}
|
||||
|
||||
marker.djs-dragger text,
|
||||
marker.djs-dragger tspan {
|
||||
fill: none !important;
|
||||
stroke: var(--element-dragger-color) !important;
|
||||
}
|
||||
|
||||
.djs-dragging {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.djs-dragging,
|
||||
.djs-dragging > * {
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.djs-dragging .djs-context-pad,
|
||||
.djs-dragging .djs-outline {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* no pointer events for visual
|
||||
*/
|
||||
.djs-visual,
|
||||
.djs-outline {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.djs-element.attach-ok .djs-hit {
|
||||
stroke-width: 60px !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* all pointer events for hit shape
|
||||
*/
|
||||
.djs-element > .djs-hit-all,
|
||||
.djs-element > .djs-hit-no-move {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.djs-element > .djs-hit-stroke,
|
||||
.djs-element > .djs-hit-click-stroke {
|
||||
pointer-events: stroke;
|
||||
}
|
||||
|
||||
/**
|
||||
* shape / connection basic styles
|
||||
*/
|
||||
.djs-connection .djs-visual {
|
||||
stroke-width: 2px;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.djs-cursor-grab {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.djs-cursor-grabbing {
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.djs-cursor-crosshair {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.djs-cursor-move {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.djs-cursor-resize-ns {
|
||||
cursor: ns-resize;
|
||||
}
|
||||
|
||||
.djs-cursor-resize-ew {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* snapping
|
||||
*/
|
||||
.djs-snap-line {
|
||||
stroke: var(--snap-line-stroke-color);
|
||||
stroke-linecap: round;
|
||||
stroke-width: 2px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* snapping
|
||||
*/
|
||||
.djs-crosshair {
|
||||
stroke: var(--space-tool-crosshair-stroke-color);
|
||||
stroke-linecap: round;
|
||||
stroke-width: 1px;
|
||||
pointer-events: none;
|
||||
shape-rendering: geometricPrecision;
|
||||
stroke-dasharray: 5, 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* palette
|
||||
*/
|
||||
|
||||
.djs-palette {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
|
||||
box-sizing: border-box;
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
.djs-palette .separator {
|
||||
margin: 5px;
|
||||
padding-top: 5px;
|
||||
|
||||
border: none;
|
||||
border-bottom: solid 1px var(--palette-separator-color);
|
||||
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.djs-palette .entry:before {
|
||||
vertical-align: initial;
|
||||
}
|
||||
|
||||
.djs-palette .djs-palette-toggle {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.djs-palette .entry,
|
||||
.djs-palette .djs-palette-toggle {
|
||||
color: var(--palette-entry-color);
|
||||
font-size: 30px;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.djs-palette .entry {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.djs-palette .entry img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.djs-palette .djs-palette-entries:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.djs-palette .djs-palette-toggle:hover {
|
||||
background: var(--palette-toggle-hover-background-color);
|
||||
}
|
||||
|
||||
.djs-palette .entry:hover {
|
||||
color: var(--palette-entry-hover-color);
|
||||
}
|
||||
|
||||
.djs-palette .highlighted-entry {
|
||||
color: var(--palette-entry-selected-color) !important;
|
||||
}
|
||||
|
||||
.djs-palette .entry,
|
||||
.djs-palette .djs-palette-toggle {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Palette open / two-column layout is controlled via
|
||||
* classes on the palette. Events to hook into palette
|
||||
* changed life-cycle are available in addition.
|
||||
*/
|
||||
.djs-palette.two-column.open {
|
||||
width: 94px;
|
||||
}
|
||||
|
||||
.djs-palette:not(.open) .djs-palette-entries {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.djs-palette:not(.open) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.djs-palette.open .djs-palette-toggle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* context-pad
|
||||
*/
|
||||
.djs-overlay-context-pad {
|
||||
width: 72px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.djs-context-pad {
|
||||
position: absolute;
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.djs-context-pad .entry {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
font-size: 22px;
|
||||
margin: 0 2px 2px 0;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
cursor: default;
|
||||
|
||||
background-color: var(--context-pad-entry-background-color);
|
||||
box-shadow: 0 0 2px 1px var(--context-pad-entry-background-color);
|
||||
pointer-events: all;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.djs-context-pad .entry:hover {
|
||||
background: var(--context-pad-entry-hover-background-color);
|
||||
}
|
||||
|
||||
.djs-context-pad.open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* popup styles
|
||||
*/
|
||||
.djs-popup-backdrop {
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 200;
|
||||
line-height: 1;
|
||||
font-family: "IBM Plex Sans", sans-serif;
|
||||
}
|
||||
|
||||
.djs-popup {
|
||||
box-sizing: border-box;
|
||||
width: min-content;
|
||||
background: var(--popup-background-color);
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
|
||||
box-shadow: 0px 2px 6px var(--popup-shadow-color);
|
||||
border: solid 1px var(--popup-border-color);
|
||||
min-width: 120px;
|
||||
outline: none;
|
||||
font-size: var(--popup-font-size);
|
||||
}
|
||||
|
||||
.djs-popup-search input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
font-size: var(--popup-font-size);
|
||||
padding: 3px 6px;
|
||||
border-radius: 2px;
|
||||
border: solid 1px var(--popup-search-border-color);
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.djs-popup-search input:focus {
|
||||
background-color: var(--popup-search-focus-background-color);
|
||||
border: solid 1px var(--popup-search-focus-border-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.djs-popup-header {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
line-height: 20px;
|
||||
margin: 10px 12px 10px 12px;
|
||||
}
|
||||
|
||||
.djs-popup-header .entry {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.djs-popup-header .entry.active {
|
||||
color: var(--popup-header-entry-selected-color);
|
||||
}
|
||||
|
||||
.djs-popup-header .entry.disabled {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.djs-popup-search {
|
||||
margin: 10px 12px;
|
||||
}
|
||||
|
||||
.djs-popup-title {
|
||||
font-size: var(--popup-font-size);
|
||||
font-weight: var(--popup-header-font-weight);
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.djs-popup-search {
|
||||
position: relative;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.djs-popup-search-icon {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
.djs-popup-search input {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.djs-popup-results {
|
||||
margin: 7px 3px 7px 12px;
|
||||
list-style: none;
|
||||
max-height: 280px;
|
||||
overflow: auto;
|
||||
padding-right: 9px;
|
||||
}
|
||||
|
||||
.djs-popup-group {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.djs-popup-body .entry,
|
||||
.djs-popup-body .entry-header {
|
||||
padding: 5px 7px;
|
||||
cursor: default;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.djs-popup-body .entry-header {
|
||||
font-weight: var(--popup-header-font-weight);
|
||||
color: var(--popup-entry-title-color);
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.djs-popup [class*="icon"] .djs-popup-label,
|
||||
.djs-popup-label:not(:first-child) {
|
||||
margin-left: .5em;
|
||||
}
|
||||
|
||||
.djs-popup [class*="icon"]:before,
|
||||
.djs-popup-entry-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
font-size: 1.4em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.djs-popup-body .entry-header:not(:first-child) {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.djs-popup-body .entry {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
height: min-content;
|
||||
}
|
||||
|
||||
.djs-popup .entry.selected {
|
||||
background-color: var(--popup-entry-hover-color);
|
||||
}
|
||||
|
||||
.djs-popup-body .entry:not(:first-child) {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.djs-popup-entry-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.djs-popup-entry-description {
|
||||
color: var(--popup-description-color);
|
||||
}
|
||||
|
||||
.djs-popup-label,
|
||||
.djs-popup-entry-description {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
.djs-popup-title,
|
||||
.djs-popup-label,
|
||||
.djs-popup-entry-description,
|
||||
.djs-popup .entry-header {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.djs-popup-entry-name {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.entry-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.djs-popup-body {
|
||||
flex-direction: column;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.djs-popup *::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.djs-popup *::-webkit-scrollbar-thumb {
|
||||
border-radius: 3px;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.djs-popup *::-webkit-scrollbar-track {
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.djs-popup-no-results {
|
||||
padding: 0 12px 12px 12px;
|
||||
color: var(--popup-no-results-color);
|
||||
}
|
||||
|
||||
.djs-popup-entry-docs {
|
||||
flex: 0;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding-left: 5px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.djs-popup-body .entry:hover .djs-popup-entry-docs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.djs-popup-entry-docs svg {
|
||||
vertical-align: middle;
|
||||
margin: auto 2px auto 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* palette styles
|
||||
*/
|
||||
.djs-palette {
|
||||
background: var(--palette-background-color);
|
||||
border: solid 1px var(--palette-border-color);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* touch
|
||||
*/
|
||||
|
||||
.djs-shape,
|
||||
.djs-connection {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.djs-segment-dragger,
|
||||
.djs-bendpoint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* bendpoints
|
||||
*/
|
||||
.djs-segment-dragger .djs-visual {
|
||||
display: none;
|
||||
|
||||
fill: var(--bendpoint-fill-color);
|
||||
stroke: var(--bendpoint-stroke-color);
|
||||
stroke-width: 1px;
|
||||
stroke-opacity: 1;
|
||||
}
|
||||
|
||||
.djs-segment-dragger:hover .djs-visual {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.djs-bendpoint .djs-visual {
|
||||
fill: var(--bendpoint-fill-color);
|
||||
stroke: var(--bendpoint-stroke-color);
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.djs-segment-dragger:hover,
|
||||
.djs-bendpoints.hover .djs-segment-dragger,
|
||||
.djs-bendpoints.selected .djs-segment-dragger,
|
||||
.djs-bendpoint:hover,
|
||||
.djs-bendpoints.hover .djs-bendpoint,
|
||||
.djs-bendpoints.selected .djs-bendpoint {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.djs-drag-active .djs-bendpoints * {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.djs-bendpoints:not(.hover) .floating {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.djs-segment-dragger:hover .djs-visual,
|
||||
.djs-segment-dragger.djs-dragging .djs-visual,
|
||||
.djs-bendpoint:hover .djs-visual,
|
||||
.djs-bendpoint.floating .djs-visual {
|
||||
fill: var(--bendpoint-fill-color);
|
||||
stroke: var(--bendpoint-stroke-color);
|
||||
stroke-opacity: 1;
|
||||
}
|
||||
|
||||
.djs-bendpoint.floating .djs-hit {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.djs-segment-dragger .djs-hit,
|
||||
.djs-bendpoint .djs-hit {
|
||||
fill: none;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.djs-segment-dragger.horizontal .djs-hit {
|
||||
cursor: ns-resize;
|
||||
}
|
||||
|
||||
.djs-segment-dragger.vertical .djs-hit {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.djs-segment-dragger.djs-dragging .djs-hit {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.djs-updating,
|
||||
.djs-updating > * {
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.djs-updating .djs-context-pad,
|
||||
.djs-updating .djs-outline,
|
||||
.djs-updating .djs-bendpoint,
|
||||
.djs-multi-select .djs-bendpoint,
|
||||
.djs-multi-select .djs-segment-dragger,
|
||||
.connect-ok .djs-bendpoint,
|
||||
.connect-not-ok .djs-bendpoint,
|
||||
.drop-ok .djs-bendpoint,
|
||||
.drop-not-ok .djs-bendpoint {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.djs-segment-dragger.djs-dragging,
|
||||
.djs-bendpoint.djs-dragging {
|
||||
display: block;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tooltips
|
||||
*/
|
||||
.djs-tooltip-error {
|
||||
width: 160px;
|
||||
padding: 6px;
|
||||
|
||||
background: var(--tooltip-error-background-color);
|
||||
border: solid 1px var(--tooltip-error-border-color);
|
||||
border-radius: 2px;
|
||||
color: var(--tooltip-error-color);
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.djs-tooltip-error:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* search pad
|
||||
*/
|
||||
.djs-search-container {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
width: 25%;
|
||||
min-width: 300px;
|
||||
max-width: 400px;
|
||||
z-index: 10;
|
||||
|
||||
font-size: 1.05em;
|
||||
opacity: 0.9;
|
||||
background: var(--search-container-background-color);
|
||||
border: solid 1px var(--search-container-border-color);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 0 2px var(--search-container-box-shadow-color), 0 0 0 1px var(--search-container-box-shadow-inset-color) inset;
|
||||
}
|
||||
|
||||
.djs-search-container:not(.open) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.djs-search-input input {
|
||||
font-size: 1.05em;
|
||||
width: 100%;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--search-input-border-color);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.djs-search-input input:focus {
|
||||
outline: none;
|
||||
border-color: var(--search-input-border-color);
|
||||
}
|
||||
|
||||
.djs-search-results {
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.djs-search-results:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.djs-search-result {
|
||||
width: 100%;
|
||||
padding: 6px 10px;
|
||||
background: white;
|
||||
border-bottom: solid 1px var(--search-result-border-color);
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.djs-search-highlight {
|
||||
color: var(--search-result-highlight-color);
|
||||
}
|
||||
|
||||
.djs-search-result-primary {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.djs-search-result-secondary {
|
||||
font-family: monospace;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.djs-search-result:hover {
|
||||
background: var(--search-result-selected-color);
|
||||
}
|
||||
|
||||
.djs-search-result-selected {
|
||||
background: var(--search-result-selected-color);
|
||||
}
|
||||
|
||||
.djs-search-result-selected:hover {
|
||||
background: var(--search-result-selected-color);
|
||||
}
|
||||
|
||||
.djs-search-overlay {
|
||||
background: var(--search-result-selected-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hidden styles
|
||||
*/
|
||||
.djs-element-hidden,
|
||||
.djs-element-hidden .djs-hit,
|
||||
.djs-element-hidden .djs-outline,
|
||||
.djs-label-hidden .djs-label {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.djs-element .djs-hit-stroke,
|
||||
.djs-element .djs-hit-click-stroke,
|
||||
.djs-element .djs-hit-all {
|
||||
cursor: move;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user