提交 a8839722 authored 作者: 陈世营's avatar 陈世营

loit-file

上级 14c96b46
...@@ -24,7 +24,11 @@ public class LoitStrtupRunner implements ApplicationRunner { ...@@ -24,7 +24,11 @@ public class LoitStrtupRunner implements ApplicationRunner {
public void run(ApplicationArguments args) throws Exception { public void run(ApplicationArguments args) throws Exception {
//此处因为在日志拦截器每次获取服务Ip,netAddress.getLocalHost()为同步代码会导致性能超低,将此代码移动到服务启动加载,设置全局变量以供使用 //此处因为在日志拦截器每次获取服务Ip,netAddress.getLocalHost()为同步代码会导致性能超低,将此代码移动到服务启动加载,设置全局变量以供使用
InetAddress address = InetAddress.getLocalHost(); InetAddress address = InetAddress.getLocalHost();
Global.HOSTIP = address.getHostAddress(); String hostAddress = address.getHostAddress();
logger.info("获取本服务ip地址为:{}",Global.HOSTIP); System.out.println(hostAddress);
Global.HOSTIP = hostAddress;
logger.info("获取本服务ip地址为:{}", Global.HOSTIP);
} }
} }
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>loit-service</artifactId>
<groupId>com.loit</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>loit-file</artifactId>
<name>loit-file</name>
<version>1.0.0</version>
<url>http://maven.apache.org</url>
<dependencies>
<!-- activemq内置消息中间件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>com.loit</groupId>
<artifactId>loit-core-boot</artifactId>
<version>${loit-core-boot}</version>
</dependency>
<!-- nacos 注册中心 -->
<dependency>
<groupId>com.timeloit.cloud</groupId>
<artifactId>spring-cloud-starter-timeloit-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.timeloit.cloud</groupId>
<artifactId>spring-cloud-starter-timeloit-nacos-config</artifactId>
</dependency>
<!-- tomcat 的支持.-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- 集成fastdfs -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.0.12</version>
</dependency>
<dependency>
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27.0.0</version>
</dependency>
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.2</version>
</dependency>
</dependencies>
<build>
<finalName>loit-file</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.loit.FileServerApplication</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-extdirs</arg>
<arg>${project.basedir}/src/main/resources/lib</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<!-- 打包时将jsp文件拷贝到META-INF目录下 -->
<resource>
<directory>${project.basedir}/src/main/resources/lib</directory>
<targetPath>BOOT-INF/lib/</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/**</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
\ No newline at end of file
package com.loit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jmx.support.RegistrationPolicy;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.github.tobato.fastdfs.FdfsClientConfig;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
@ServletComponentScan
@EnableFeignClients
@RestController
@EnableSwagger2
@EnableJms
@Import(FdfsClientConfig.class)
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class FileServerApplication extends SpringBootServletInitializer{
@Override
protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(FileServerApplication.class);
}
public static void main(String[] args) {
long startTime=System.currentTimeMillis();
SpringApplication.run(FileServerApplication.class, args);
long endTime=System.currentTimeMillis();
float excTime=(float)(endTime-startTime)/1000;
System.out.println("############--- loit-file项目启动成功,执行用时:"+excTime+"秒 ---############");
}
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
package com.loit.common.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
*
* @ClassName: Test.java
* @Description: 该类的功能描述
*
* @version: v1.0.0
* @author: gaodengyun
* @date: 2019年4月24日 下午2:24:30
*
* Modification History:
* Date Author Version Description
*---------------------------------------------------------*
* 2019年4月24日 gaodengyun v1.0.0 修改原因
*/
@Component
public class FastDFSConfigInfo {
@Value("${fastdfs.file_server_prefix}")
private String fileServerPrefix;
public String getFileServerPrefix() {
return fileServerPrefix;
}
public void setFileServerPrefix(String fileServerPrefix) {
this.fileServerPrefix = fileServerPrefix;
}
}
package com.loit.common.config;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 自定义Feign的隔离策略;
* 在转发Feign的请求头的时候,如果开启了Hystrix,Hystrix的默认隔离策略是Thread(线程隔离策略)
* ,因此转发拦截器内是无法获取到请求的请求头信息的
* ,可以修改默认隔离策略为信号量模式:hystrix.command.default.execution.isolation.strategy=SEMAPHORE
* ,这样的话转发线程和请求线程实际上是一个线程,这并不是最好的解决方法,信号量模式也不是官方最为推荐的隔离策略;
* 另一个解决方法就是自定义Hystrix的隔离策略,思路是将现有的并发策略作为新并发策略的成员变量
* ,在新并发策略中,返回现有并发策略的线程池、Queue;将策略加到Spring容器即可;
*
* @author mozping
* @version 1.0
* @date 2018/7/5 9:08
* @see FeignHystrixConcurrencyStrategyIntellif
* @since JDK1.8
*/
@Component
public class FeignHystrixConcurrencyStrategyIntellif extends HystrixConcurrencyStrategy {
private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategyIntellif.class);
private HystrixConcurrencyStrategy delegate;
public FeignHystrixConcurrencyStrategyIntellif() {
try {
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
if (this.delegate instanceof FeignHystrixConcurrencyStrategyIntellif) {
// Welcome to singleton hell...
return;
}
HystrixCommandExecutionHook commandExecutionHook =
HystrixPlugins.getInstance().getCommandExecutionHook();
HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
HystrixPropertiesStrategy propertiesStrategy =
HystrixPlugins.getInstance().getPropertiesStrategy();
this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
HystrixPlugins.reset();
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
} catch (Exception e) {
log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
}
}
private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
HystrixMetricsPublisher metricsPublisher, HystrixPropertiesStrategy propertiesStrategy) {
if (log.isDebugEnabled()) {
log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy ["
+ this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
+ metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
}
}
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return new WrappedCallable<>(callable, requestAttributes);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixProperty<Integer> corePoolSize, HystrixProperty<Integer> maximumPoolSize,
HystrixProperty<Integer> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
unit, workQueue);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixThreadPoolProperties threadPoolProperties) {
return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
}
@Override
public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
return this.delegate.getBlockingQueue(maxQueueSize);
}
@Override
public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
return this.delegate.getRequestVariable(rv);
}
static class WrappedCallable<T> implements Callable<T> {
private final Callable<T> target;
private final RequestAttributes requestAttributes;
public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
this.target = target;
this.requestAttributes = requestAttributes;
}
@Override
public T call() throws Exception {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
return target.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
}
}
\ No newline at end of file
package com.loit.common.config;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.DefaultResourceLoader;
import com.google.common.collect.Maps;
/**
* 全局配置类
* @author loit
* @version 2014-06-25
*/
public class Global {
/**
* 当前对象实例
*/
private static Global global = new Global();
/**
* 保存全局属性值
*/
private static Map<String, String> map = Maps.newHashMap();
/**
* 属性文件加载对象
*/
private static PropertiesLoader loader = new PropertiesLoader("/config/custom.properties");
/**
* 显示/隐藏
*/
public static final String SHOW = "1";
public static final String HIDE = "0";
/**
* 是/否
*/
public static final String YES = "1";
public static final String NO = "0";
/**
* 对/错
*/
public static final String TRUE = "true";
public static final String FALSE = "false";
/**
* 上传文件基础虚拟路径
*/
public static final String USERFILES_BASE_URL = "/userfiles/";
public static String HOSTIP;
/**
* 获取当前对象实例
*/
public static Global getInstance() {
return global;
}
/**
* 获取配置
* @see ${fns:getConfig('adminPath')}
*/
public static String getConfig(String key) {
String value = map.get(key);
if (value == null){
value = loader.getProperty(key);
map.put(key, value != null ? value : StringUtils.EMPTY);
}
return value;
}
/**
* 获取管理端根路径
*/
public static String getAdminPath() {
return getConfig("adminPath");
}
/**
* 获取前端根路径
*/
public static String getFrontPath() {
return getConfig("frontPath");
}
/**
* 获取URL后缀
*/
public static String getUrlSuffix() {
return getConfig("urlSuffix");
}
/**
* 是否是演示模式,演示模式下不能修改用户、角色、密码、菜单、授权
*/
public static Boolean isDemoMode() {
String dm = getConfig("demoMode");
return "true".equals(dm) || "1".equals(dm);
}
/**
* 在修改系统用户和角色时是否同步到Activiti
*/
public static Boolean isSynActivitiIndetity() {
String dm = getConfig("activiti.isSynActivitiIndetity");
return "true".equals(dm) || "1".equals(dm);
}
/**
* 页面获取常量
* @see ${fns:getConst('YES')}
*/
public static Object getConst(String field) {
try {
return Global.class.getField(field).get(null);
} catch (Exception e) {
// 异常代表无配置,这里什么也不做
}
return null;
}
/**
* 获取上传文件的根目录
* @return
*/
public static String getUserfilesBaseDir() {
String dir = getConfig("userfiles.basedir");
if (StringUtils.isBlank(dir)){
try {
// dir = ServletContextFactory.getServletContext().getRealPath("/");
} catch (Exception e) {
return "";
}
}
if(!dir.endsWith("/")) {
dir += "/";
}
return dir;
}
/**
* 获取工程路径
* @return
*/
public static String getProjectPath(){
// 如果配置了工程路径,则直接返回,否则自动获取。
String projectPath = Global.getConfig("projectPath");
if (StringUtils.isNotBlank(projectPath)){
return projectPath;
}
try {
File file = new DefaultResourceLoader().getResource("").getFile();
if (file != null){
while(true){
File f = new File(file.getPath() + File.separator + "src" + File.separator + "main");
if (f == null || f.exists()){
break;
}
if (file.getParentFile() != null){
file = file.getParentFile();
}else{
break;
}
}
projectPath = file.toString();
}
} catch (IOException e) {
e.printStackTrace();
}
return projectPath;
}
}
/**
* Copyright (c) 2005-2011 springside.org.cn
*
* $Id: PropertiesLoader.java 1690 2012-02-22 13:42:00Z calvinxiu $
*/
package com.loit.common.config;
import java.io.IOException;
import java.io.InputStream;
import java.util.NoSuchElementException;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
/**
* Properties文件载入工具类. 可载入多个properties文件, 相同的属性在最后载入的文件中的值将会覆盖之前的值,但以System的Property优先.
* @author calvin
* @version 2013-05-15
*/
public class PropertiesLoader {
private static Logger logger = LoggerFactory.getLogger(PropertiesLoader.class);
private static ResourceLoader resourceLoader = new DefaultResourceLoader();
private final Properties properties;
public PropertiesLoader(String... resourcesPaths) {
properties = loadProperties(resourcesPaths);
}
public Properties getProperties() {
return properties;
}
/**
* 取出Property,但以System的Property优先,取不到返回空字符串.
*/
private String getValue(String key) {
String systemProperty = System.getProperty(key);
if (systemProperty != null) {
return systemProperty;
}
if (properties.containsKey(key)) {
return properties.getProperty(key);
}
return "";
}
/**
* 取出String类型的Property,但以System的Property优先,如果都为Null则抛出异常.
*/
public String getProperty(String key) {
String value = getValue(key);
if (value == null) {
throw new NoSuchElementException();
}
return value;
}
/**
* 取出String类型的Property,但以System的Property优先.如果都为Null则返回Default值.
*/
public String getProperty(String key, String defaultValue) {
String value = getValue(key);
return value != null ? value : defaultValue;
}
/**
* 取出Integer类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常.
*/
public Integer getInteger(String key) {
String value = getValue(key);
if (value == null) {
throw new NoSuchElementException();
}
return Integer.valueOf(value);
}
/**
* 取出Integer类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常
*/
public Integer getInteger(String key, Integer defaultValue) {
String value = getValue(key);
return value != null ? Integer.valueOf(value) : defaultValue;
}
/**
* 取出Double类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常.
*/
public Double getDouble(String key) {
String value = getValue(key);
if (value == null) {
throw new NoSuchElementException();
}
return Double.valueOf(value);
}
/**
* 取出Double类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常
*/
public Double getDouble(String key, Integer defaultValue) {
String value = getValue(key);
return value != null ? Double.valueOf(value) : defaultValue;
}
/**
* 取出Boolean类型的Property,但以System的Property优先.如果都为Null抛出异常,如果内容不是true/false则返回false.
*/
public Boolean getBoolean(String key) {
String value = getValue(key);
if (value == null) {
throw new NoSuchElementException();
}
return Boolean.valueOf(value);
}
/**
* 取出Boolean类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容不为true/false则返回false.
*/
public Boolean getBoolean(String key, boolean defaultValue) {
String value = getValue(key);
return value != null ? Boolean.valueOf(value) : defaultValue;
}
/**
* 载入多个文件, 文件路径使用Spring Resource格式.
*/
private Properties loadProperties(String... resourcesPaths) {
Properties props = new Properties();
for (String location : resourcesPaths) {
// logger.debug("Loading properties file from:" + location);
InputStream is = null;
try {
Resource resource = resourceLoader.getResource(location);
is = resource.getInputStream();
props.load(is);
} catch (IOException ex) {
logger.info("Could not load properties from path:" + location + ", " + ex.getMessage());
} finally {
IOUtils.closeQuietly(is);
}
}
return props;
}
}
package com.loit.common.config;
import java.util.Locale;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
*
* @ClassName: SpringContextUtil
* @Description: SpringContext相关
* @author gaodengyun
* @date 2019年5月11日 上午11:59:02
*
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context = null;
@SuppressWarnings("static-access")
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
// 传入线程中
@SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
return (T) context.getBean(beanName);
}
// 国际化使用
public static String getMessage(String key) {
return context.getMessage(key, null, Locale.getDefault());
}
/// 获取当前环境
public static String getActiveProfile() {
return context.getEnvironment().getActiveProfiles()[0];
}
}
package com.loit.common.config;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Swagger配置
* @author wbh
* @date 2018年12月15日
*/
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(Swagger2
.basePackage("com.loit.web")).paths(PathSelectors.any()).build();
}
/**
* Predicate that matches RequestHandler with given base package name for the class of the handler method.
* This predicate includes all request handlers matching the provided basePackage
*
* @param basePackage - base package of the classes
* @return this
*/
public static Predicate<RequestHandler> basePackage(final String basePackage) {
return new Predicate<RequestHandler>() {
@Override
public boolean apply(RequestHandler input) {
return declaringClass(input).transform(handlerPackage(basePackage)).or(true);
}
};
}
/**
* 处理包路径配置规则,支持多路径扫描匹配以逗号隔开
*
* @param basePackage 扫描包路径
* @return Function
*/
private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
return new Function<Class<?>, Boolean>() {
@Override
public Boolean apply(Class<?> input) {
for (String strPackage : basePackage.split(",")) {
boolean isMatch = input.getPackage().getName().startsWith(strPackage);
if (isMatch) {
return true;
}
}
return false;
}
};
}
/**
* @param input RequestHandler
* @return Optional
*/
@SuppressWarnings("deprecation")
private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
return Optional.fromNullable(input.declaringClass());
}
private ApiInfo apiInfo() {
InetAddress address;
String hostAddress=null;
try {
address = InetAddress.getLocalHost();
hostAddress = address.getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}//获取的是本地的IP地址
String projectName = Global.getConfig("productName");
return new ApiInfoBuilder()
.title(projectName+"api文档")
.description("v1.0 add by gaoyanyun (2514917157@qq.com) \n"
+ "v1.1 update by wangbh (wbh1213@qq.com)")
.termsOfServiceUrl("http://"+hostAddress+":7002/api-demo/swagger-ui.html")
.version("1.0")
.build();
}
}
package com.loit.common.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器配置
*
* @author wbh
* @date 2018年12月3日
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//和页面有关的静态目录都放在项目的static目录下
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
//上传的图片在D盘下的img目录下,访问路径如:http://localhost:7007/image/d3cf0281-bb7f-40e0-ab77-406db95ccf2c.jpg
//其中image表示访问的前缀。"file:E:/img/"是文件真实的存储路径
registry.addResourceHandler("/image/**");
}
/**
* 设置SpringBoot默认返回体Content-Type
*
* @param configurer
*/
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8);
}
}
package com.loit.common.json;
import java.io.Serializable;
import java.util.LinkedHashMap;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* $.ajax后需要接受的JSON
*
* @author
*
*/
public class AjaxJson implements Serializable{
public static final String CODE_COMMON_FAIL = LoitStatusCode.FAIL.statusCode;
/**
* @author wbh
* @date 2018年12月11日
*/
private static final long serialVersionUID = -7790919285662399570L;
private boolean success = true;// 是否成功
private String code = LoitStatusCode.SUCESS.statusCode;//返回码 100-成功,101失败,其他返回码参见LoitStatusCode
private String msg = "操作成功";// 提示信息
private LinkedHashMap<String, Object> body = new LinkedHashMap<String, Object>();//封装json的map
private String errorCode;
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public LinkedHashMap<String, Object> getBody() {
return body;
}
public void setBody(LinkedHashMap<String, Object> body) {
this.body = body;
}
public void put(String key, Object value){//向json中添加属性,在js中访问,请调用data.map.key
body.put(key, value);
}
public void remove(String key){
body.remove(key);
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {//向json中添加属性,在js中访问,请调用data.msg
this.msg = msg;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
@JsonIgnore//返回对象时忽略此属性
public String getJsonStr() {//返回json字符串数组,将访问msg和key的方式统一化,都使用data.key的方式直接访问。
String json = JsonMapper.getInstance().toJson(this);
return json;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return "AjaxJson [success=" + success + ", code=" + code + ", msg=" + msg + "]";
}
/**
* 返回普通异常信息。code=101
* @author wbh
* @date:2018年12月16日
* @param info
* @return
*/
public static AjaxJson returnExceptionInfo(String info) {
AjaxJson json = new AjaxJson();
json.setSuccess(false);
json.setCode(CODE_COMMON_FAIL);
json.setMsg(info);
return json;
}
/**
* 返回普通异常信息。code=101
* @author wbh
* @date:2018年12月16日
* @param info
* @return
*/
public static AjaxJson returnExceptionInfo(String info, AjaxJson json) {
json.setSuccess(false);
json.setCode(CODE_COMMON_FAIL);
json.setMsg(info);
return json;
}
/**
* 返回指定异常信息。
* @author wbh
* @date:2019年10月31日
* @param code 状态码
* @param info 返回信息
* @return
*/
public static AjaxJson returnExceptionInfo(LoitStatusCode info) {
AjaxJson json = new AjaxJson();
json.setSuccess(false);
json.setCode(info.statusCode);
json.setMsg(info.statusDesc);
return json;
}
/**
* 返回指定异常信息。
* @author wbh
* @date:2019年10月31日
* @param code 状态码
* @param info 返回信息
* @return
*/
public static AjaxJson returnExceptionInfo(LoitStatusCode info, AjaxJson json) {
json.setSuccess(false);
json.setCode(info.statusCode);
json.setMsg(info.statusDesc);
return json;
}
}
package com.loit.common.json;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* 简单封装Jackson,实现JSON String<->Java Object的Mapper.
* 封装不同的输出风格, 使用不同的builder函数创建实例.
* @author loit
* @version 2013-11-15
*/
@SuppressWarnings("deprecation")
public class JsonMapper extends ObjectMapper {
private static final long serialVersionUID = 1L;
private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);
private static JsonMapper mapper;
public JsonMapper() {
//this(Include.NON_EMPTY);
}
public JsonMapper(Include include) {
// 设置输出时包含属性的风格
if (include != null) {
this.setSerializationInclusion(include);
}
// 允许单引号、允许不带引号的字段名称
this.enableSimple();
// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 空值处理为空串
this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>(){
@Override
public void serialize(Object value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeString("");
}
});
// 进行HTML解码。
this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>(){
@Override
public void serialize(String value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
}
}));
// 设置时区
this.setTimeZone(TimeZone.getDefault());//getTimeZone("GMT+8:00")
}
/**
* 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
*/
public static JsonMapper getInstance() {
if (mapper == null){
mapper = new JsonMapper().enableSimple();
}
return mapper;
}
/**
* 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用。
*/
public static JsonMapper nonDefaultMapper() {
if (mapper == null){
mapper = new JsonMapper(Include.NON_DEFAULT);
}
return mapper;
}
/**
* Object可以是POJO,也可以是Collection或数组。
* 如果对象为Null, 返回"null".
* 如果集合为空集合, 返回"[]".
*/
public String toJson(Object object) {
try {
return this.writeValueAsString(object);
} catch (IOException e) {
logger.warn("write to json string error:" + object, e);
return null;
}
}
/**
* 反序列化POJO或简单Collection如List<String>.
*
* 如果JSON字符串为Null或"null"字符串, 返回Null.
* 如果JSON字符串为"[]", 返回空集合.
*
* 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String,JavaType)
* @see #fromJson(String, JavaType)
*/
public <T> T fromJson(String jsonString, Class<T> clazz) {
if (StringUtils.isEmpty(jsonString)) {
return null;
}
try {
return this.readValue(jsonString, clazz);
} catch (IOException e) {
logger.warn("parse json string error:" + jsonString, e);
return null;
}
}
/**
* 反序列化复杂Collection如List<Bean>, 先使用函數createCollectionType构造类型,然后调用本函数.
* @see #createCollectionType(Class, Class...)
*/
@SuppressWarnings("unchecked")
public <T> T fromJson(String jsonString, JavaType javaType) {
if (StringUtils.isEmpty(jsonString)) {
return null;
}
try {
return (T) this.readValue(jsonString, javaType);
} catch (IOException e) {
logger.warn("parse json string error:" + jsonString, e);
return null;
}
}
/**
* 構造泛型的Collection Type如:
* ArrayList<MyBean>, 则调用constructCollectionType(ArrayList.class,MyBean.class)
* HashMap<String,MyBean>, 则调用(HashMap.class,String.class, MyBean.class)
*/
public JavaType createCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
return this.getTypeFactory().constructParametricType(collectionClass, elementClasses);
}
/**
* 當JSON裡只含有Bean的部分屬性時,更新一個已存在Bean,只覆蓋該部分的屬性.
*/
@SuppressWarnings("unchecked")
public <T> T update(String jsonString, T object) {
try {
return (T) this.readerForUpdating(object).readValue(jsonString);
} catch (JsonProcessingException e) {
logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
} catch (IOException e) {
logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
}
return null;
}
/**
* 輸出JSONP格式數據.
*/
public String toJsonP(String functionName, Object object) {
return toJson(new JSONPObject(functionName, object));
}
/**
* 設定是否使用Enum的toString函數來讀寫Enum,
* 為False時時使用Enum的name()函數來讀寫Enum, 默認為False.
* 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用.
*/
public JsonMapper enableEnumUseToString() {
this.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
this.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
return this;
}
/**
* 支持使用Jaxb的Annotation,使得POJO上的annotation不用与Jackson耦合。
* 默认会先查找jaxb的annotation,如果找不到再找jackson的。
*/
public JsonMapper enableJaxbAnnotation() {
JaxbAnnotationModule module = new JaxbAnnotationModule();
this.registerModule(module);
return this;
}
/**
* 允许单引号
* 允许不带引号的字段名称
*/
public JsonMapper enableSimple() {
this.configure(Feature.ALLOW_SINGLE_QUOTES, true);
this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
return this;
}
/**
* 取出Mapper做进一步的设置或使用其他序列化API.
*/
public ObjectMapper getMapper() {
return this;
}
/**
* 对象转换为JSON字符串
* @param object
* @return
*/
public static String toJsonString(Object object){
return JsonMapper.getInstance().toJson(object);
}
/**
* JSON字符串转换为对象
* @param jsonString
* @param clazz
* @return
*/
public static Object fromJsonString(String jsonString, Class<?> clazz){
return JsonMapper.getInstance().fromJson(jsonString, clazz);
}
/**
* 测试
*/
public static void main(String[] args) {
List<Map<String, Object>> list = Lists.newArrayList();
Map<String, Object> map = Maps.newHashMap();
map.put("id", 1);
map.put("pId", -1);
map.put("name", "根节点");
list.add(map);
map = Maps.newHashMap();
map.put("id", 2);
map.put("pId", 1);
map.put("name", "你好");
map.put("open", true);
list.add(map);
// String json = JsonMapper.getInstance().toJson(list);
}
}
package com.loit.common.json;
/**
* @ClassName LoitStatusCode
* @Description: 系统状态码 编码:3位状态码中,第一位代表一个应用
* @Author gzx
* @Date 2019-10-17
* @Version V1.0
**/
public enum LoitStatusCode {
SUCESS("100","成功"),
FAIL("101","失败"),
UNKNOWN_EXCEPTION("102","未知异常,请联系管理员"),
USER_UNREGISTERED("103","用户未注册"),
USER_FORBID("104","用户被禁止登录"),
USER_PASSWORD_FAIL("105","登录失败"),
USER_TOKEN_ERRO("106","TOKEN验证错误"),
USER_TOKEN_INVALID("107","TOKEN验证失效"),
USER_ILLEGAL_AUTH("109","非法授权"),
USER_SESSION_ERRO("110","session验证错误"),
USER_SESSION_INVALID("111","session验证失效"),
/**
* 单点登录相关 TODO DEMN cas statuscode 需要修改
*/
CAS_URI_RESOLVE_ERROR("101", "CAS AccessToken换取用户信息的回调URI解析错误"),
CAS_REDIRECT_URL_NOT_USERNAME_ERROR("101", "CAS AccessToken换取用户信息的回调URI没有用户登录名称"),
CAS_USER_AUTH_FAIL("101","用户认证失败, 用户未登录或登录过期"),
CAS_USER_TOKEN_NOT_FOUND("101", "AccessToken 头部参数没找到"),
CAS_AUTHENTICATION_FAIL("101", "无权限访问该资源"),
CAS_AUTHENTICATION_NOT_APPID_FAIL("101", "鉴权失败,缓存中没有当前用户操作的应用id"),
CAS_NOT_IN_APPOINT_AREA("101", "不在指定区域,无法登录"),
CAS_LOGIN_FAIL("101", "登录失败"),
/**
* 密码策略相关
*/
POLICY_PASSWORD_SUCCESS("101", "密码格式正确"),
POLICY_PASSWORD_LENGTH_ERR("101", "密码长度错误"),
POLICY_PASSWORD_MIXLEVEL_ERR("101", "密码格式错误"),
/**
* 服务相关
*/
SERVICE_NOT_ONLINE_FOR_LOIT_PORTAL_ERROR("190", "loit-portal服务未在线"),
APP_ORG_ASSIGN("114","应用组织权限已分配"),
PRIMARY_KEY_ISNULL("115","主键为空"),
APP_IS_EXIST("116", "保存失败,应用已存在"),
SAVE_EXCEPTION("117", "保存异常,请联系管理员"),
UPDATE_EXCEPTION("118", "修改异常,请联系管理员"),
DELETE_EXCEPTION("119", "删除异常,请联系管理员"),
DISTRIBUTE_RESOURCES_EXCEPTION("120", "分配资源异常,请联系管理员"),
APP_ID_ISNULL("121", "应用id为空"),
CONTEXT_IS_EXIST("122", "保存失败,上下文配置已存在"),
RESOURCETYPE_IS_EXIST("123", "保存失败,资源类别已存在"),
MENU_IS_EXIST("124", "保存失败,菜单已存在"),
DICT_IS_EXIST("125", "保存失败,字典已存在"),
DICTDATA_IS_EXIST("126", "保存失败,字典项已存在"),
MENULAYOUT_IS_EXIST("127", "保存失败,菜单布局已存在"),
SKIN_IS_EXIST("128", "保存失败,皮肤设置已存在"),
FILE_PATH_ISNULL("140", "文件路径为空"),
FILE_ISNULL("141", "文件为空"),
FILE_UPLOAD_FAILED("142", "文件上传失败"),
FILE_NOT_EXIST("143", "文件不存在"),
FILE_DOWNLOAD_FAILED("144", "文件下载失败"),
FILE_DELETE_FAILED("145", "删除文件失败"),
FILE_SERVER_CONNECTION_FAILED("146", "文件服务器连接失败"),
FILE_OUT_SIZE("147", "文件超过大小"),
FILE_TYPE_ERROR_IMAGE("148", "图片类型错误"),
FILE_TYPE_ERROR_DOC("149", "文档类型错误"),
FILE_TYPE_ERROR_VIDEO("140", "音频类型错误"),
FILE_TYPE_ERROR_COMPRESS("141", "压缩文件类型错误"),
FILE_TYPE_ERROR_ALLOW("142", "不是允许的文件类型"),
REDIS_LINK_FAIL("145","redis连接异常"),
GRP_ADD_ORG_FAIL("146","该组织已添加"),
GRP_ADD_PERSON_FAIL("147","该用户已添加"),
GRP_NOT_EXIST("148","用户组不存在")
;
/**
* 状态编码号
*/
public String statusCode;
/**
* 状态描述
*/
public String statusDesc;
/**
* 构造函数
* @param statusCode
* @param statusDesc
*/
LoitStatusCode(String statusCode,String statusDesc){
this.statusCode = statusCode;
this.statusDesc = statusDesc;
}
}
package com.loit.common.tool;
import java.io.Serializable;
/**
* 上传后返回信息数据
*/
public class ApiResult<T> implements Serializable{
/**
*
*/
private static final long serialVersionUID = -1653378788978311892L;
private String code;
private String msg;
private T data;
public ApiResult() {
this.code = Constants.kCode_Fail;
this.msg = "";
}
public ApiResult(String code, String msg) {
this.code = code;
this.msg = msg;
}
public ApiResult(String code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
// 默认方法
public static ApiResult success(){
return successMsg("请求成功");
}
public static ApiResult successMsg(String msg){
ApiResult apiBean = new ApiResult(Constants.kCode_Success, msg, null);
return apiBean;
}
public static ApiResult success(Object data, String msg){
ApiResult apiBean = new ApiResult(Constants.kCode_Success, msg, data);
return apiBean;
}
public static ApiResult success(Object data){
ApiResult apiBean = new ApiResult(Constants.kCode_Success, "", data);
return apiBean;
}
public static ApiResult fail(){
return fail("请求失败");
}
public static ApiResult fail(String msg){
ApiResult apiBean = new ApiResult(Constants.kCode_Fail, msg);
return apiBean;
}
public static ApiResult fail(String code, String msg){
ApiResult apiBean = new ApiResult(code, msg);
return apiBean;
}
public static ApiResult sessionError(){
ApiResult apiBean = new ApiResult(Constants.kCode_SessionError, "登陆超时");
return apiBean;
}
}
package com.loit.common.tool;
/**
* 上传前文件检测
* @author fangshiquan
*/
public class CheckFileResult {
private String fileMd5;
//0:锁未占用,1:锁占用
private Integer lock;
//文件分块数量
private Integer chunkNum;
//每块文件大小
private Integer chunkSize;
//当前已传输到第几块
private Integer chunkCurr;
//当前文件总大小
private Long totalSize;
//访问路径
private String viewPath;
public String getViewPath() {
return viewPath;
}
public void setViewPath(String viewPath) {
this.viewPath = viewPath;
}
public String getFileMd5() {
return fileMd5;
}
public void setFileMd5(String fileMd5) {
this.fileMd5 = fileMd5;
}
public Integer getLock() {
return lock;
}
public void setLock(Integer lock) {
this.lock = lock;
}
public Integer getChunkNum() {
return chunkNum;
}
public void setChunkNum(Integer chunkNum) {
this.chunkNum = chunkNum;
}
public Integer getChunkSize() {
return chunkSize;
}
public void setChunkSize(Integer chunkSize) {
this.chunkSize = chunkSize;
}
public Integer getChunkCurr() {
return chunkCurr;
}
public void setChunkCurr(Integer chunkCurr) {
this.chunkCurr = chunkCurr;
}
public Long getTotalSize() {
return totalSize;
}
public void setTotalSize(Long totalSize) {
this.totalSize = totalSize;
}
}
package com.loit.common.tool;
/**
* 通用常量配置
*/
public class Constants {
// 全局配置
public final static int False = 0;
public final static int True = 1;
public final static String kCode_Success = "0"; // 成功
public final static String kCode_Fail = "1"; // 失败
public final static String kCode_SessionError = "1000"; // 登陆超时
}
package com.loit.common.tool;
/**
* 文件基础信息
* @author fangshiquan
*
*/
public class FileResult {
//文件名
private String url;
//文件md5
private String md5;
//文件名称
private String name;
//文件大小
private Long lenght;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMd5() {
return md5;
}
public void setMd5(String md5) {
this.md5 = md5;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getLenght() {
return lenght;
}
public void setLenght(Long lenght) {
this.lenght = lenght;
}
}
package com.loit.common.tool;
import java.io.InputStream;
import java.util.Properties;
import com.loit.common.config.SpringContextUtil;
/**
* 读取配置信息
* @author fangshiquan
*
*/
public class ReadProper {
public static String getResourceValue(String key) {
try {
String activeMode = SpringContextUtil.getActiveProfile();
String fileNamePath="";
switch (activeMode) {
case "proc":
fileNamePath="/application-proc.properties";
break;
case "dev":
fileNamePath="/application-dev.properties";
break;
default:
fileNamePath="/application-test.properties";
}
InputStream input = ReadProper.class.getResourceAsStream(fileNamePath);
Properties p = new Properties();
p.load(input);
input.close();
if (!p.containsKey(key)) {
return null;
}
return p.getProperty(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//读取国际化
public static String getI18n(String key) {
try {
InputStream input = ReadProper.class
.getResourceAsStream("/i18n_zh_CN.properties");
Properties p = new Properties();
p.load(input);
input.close();
if (!p.containsKey(key)) {
return null;
}
return p.getProperty(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package com.loit.common.tool;
import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
/**
* redis工具类
* @author fangshiquan
*
*/
public class RedisUtil {
private RedisUtil() {
}
private static Logger _logger = LoggerFactory.getLogger(RedisUtil.class);
public static final ThreadLocal<Jedis> threadLocalJedis = new ThreadLocal<Jedis>();
//Redis服务器IP
private static String ADDR_ARRAY = ReadProper.getResourceValue("spring.redis.host");
//Redis的端口号
private static int PORT = Integer.parseInt(ReadProper.getResourceValue("spring.redis.port"));
//访问密码
private static String AUTH = ReadProper.getResourceValue("spring.redis.password");
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = -1;
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 16;
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = 1000 * 5;
//超时时间
private static int TIMEOUT = 1000 * 5;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool ;
//默认的数据库为0
/**
* redis过期时间,以秒为单位
*/
public final static int EXRP_HOUR = 60 * 60; //一小时
public final static int EXRP_DAY = 60 * 60 * 24; //一天
public final static int EXRP_MONTH = 60 * 60 * 24 * 30; //一个月
/**
* 初始化Redis连接池,注意一定要在使用前初始化一次,一般在项目启动时初始化就行了
*/
public static JedisPool initialPool() {
JedisPool jp=null;
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
config.setTestOnCreate(true);
config.setTestWhileIdle(true);
config.setTestOnReturn(true);
config.setNumTestsPerEvictionRun(-1);
jp = new JedisPool(config, ADDR_ARRAY, PORT, TIMEOUT,AUTH,2);
jedisPool=jp;
threadLocalJedis.set(getJedis());
} catch (Exception e) {
e.printStackTrace();
_logger.error("redis服务器异常",e);
}
return jp;
}
public static void close(Jedis jedis) {
if (threadLocalJedis.get() == null && jedis != null){
System.out.println("关闭线程");
jedis.close();
}
}
/**
* 关闭连接
* @param jedis
*/
public static void closeAll(Jedis jedis) {
if (threadLocalJedis.get() != null){
threadLocalJedis.set(null);
}
if (jedis != null) {
jedis.close();
}
}
static {
initialPool();
}
/**
* 获取Jedis实例,一定先初始化
*
* @return Jedis
*/
@SuppressWarnings("resource")
public static Jedis getJedis() {
boolean success = false;
Jedis jedis = null;
int i=0;
while (!success) {
i++;
try {
if (jedisPool != null) {
jedis=threadLocalJedis.get();
if (jedis==null){
jedis = jedisPool.getResource();
}else {
if(! jedis.isConnected()&&!jedis.getClient().isBroken()){
threadLocalJedis.set(null);
jedis = jedisPool.getResource();
}
return jedis;
}
}else {
throw new RuntimeException("redis连接池初始化失败");
}
} catch (Exception e) {
System.out.println(Thread.currentThread().getName()+":第"+i+"次获取失败!!!");
success = false;
e.printStackTrace();
_logger.error("redis服务器异常",e);
}
if (jedis!=null){
success=true;
}
if (i>=10&&i<20){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i>=20&&i<30){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i>=30&&i<40){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (i>=40){
System.out.println("redis彻底连不上了~~~~(>_<)~~~~");
return null;
}
}
if (threadLocalJedis.get()==null){
threadLocalJedis.set(jedis);
}
return jedis;
}
/**
* 设置 String
*
* @param key
* @param value
*/
public static void setString(String key, String value) {
Jedis jo = null;
try {
value = StrUtil.isBlank(value) ? "" : value;
jo = getJedis();
jo.setex(key,3600, value);
} catch (Exception e) {
threadLocalJedis.set(null);
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis服务器异常");
} finally {
close(jo);
}
}
/**
* 设置 过期时间
*
* @param key
* @param seconds 以秒为单位
* @param value
*/
public static void setString(String key, int seconds, String value) {
Jedis jo = null;
try {
value = StrUtil.isBlank(value) ? "" : value;
jo = getJedis();
jo.setex(key, seconds, value);
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis服务器异常");
} finally {
close(jo);
}
}
/**
* 获取String值
*
* @param key
* @return value
*/
public static String getString(String key) {
Jedis jo = null;
try {
jo = getJedis();
if (jo == null || !jo.exists(key)) {
return null;
}
return jo.get(key);
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis操作错误");
} finally {
close(jo);
}
}
public static long incrBy(String key, long integer) {
Jedis jo = null;
try {
jo = getJedis();
return jo.incrBy(key, integer);
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis操作错误");
} finally {
close(jo);
}
}
public static long decrBy(String key, long integer) {
Jedis jo = null;
try {
jo = getJedis();
return jo.decrBy(key, integer);
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis操作错误");
} finally {
close(jo);
}
}
//删除多个key
public static long delKeys(String [] keys){
Jedis jo = null;
try {
jo = getJedis();
return jo.del(keys);
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis操作错误");
} finally {
close(jo);
}
}
//删除单个key
public static long delKey(String key){
Jedis jo = null;
try {
jo = getJedis();
return jo.del(key);
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis操作错误");
} finally {
close(jo);
}
}
//添加到队列尾
public static long rpush(String key,String node){
Jedis jo = null;
try {
jo = getJedis();
return jo.rpush(key,node);
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis操作错误");
} finally {
close(jo);
}
}
//删除list元素
public static long delListNode(String key,int count,String value){
Jedis jo = null;
try {
jo = getJedis();
return jo.lrem(key,count,value);
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis操作错误");
} finally {
close(jo);
}
}
//获取所有list
@SuppressWarnings("rawtypes")
public static List getListAll(String key){
Jedis jo = null;
List list=null;
try {
jo = getJedis();
list=jo.lrange(key,0,-1);
System.out.println("当前线程名:"+Thread.currentThread().getName());
} catch (Exception e) {
threadLocalJedis.set(null);
e.printStackTrace();
_logger.error("redis服务器异常",e);
throw new RuntimeException("redis操作错误");
} finally {
close(jo);
}
return list;
}
//清理缓存redis
public static void cleanLoacl(Jedis jo){
threadLocalJedis.set(null);
close(jo);
}
}
\ No newline at end of file
package com.loit.common.tool;
import java.util.HashMap;
import java.util.Map;
/**
* 模拟数据库
* @author fangshiquan
*
*/
public class Table {
private Table(){};
//用户表
public static Map<String,String> user=new HashMap<String,String>();
static {
//添加用户账号密码
user.put("admin","123456");
user.put("zhang","123456");
user.put("wang","123456");
}
}
package com.loit.common.tool;
/**
* 上传常量配置
* @author fangshiquan
*
*/
public class UpLoadConstant {
private UpLoadConstant() {
}
private final static String uploading="Uploading:";
private final static String lock=uploading+"lock:";
private final static String file=uploading+"file:";
//当前所有锁(用在不同用户的上传前或重传前对整个文件的锁)
public final static String currLocks=lock+"currLocks:";
//当前锁的拥有者
public final static String lockOwner=lock+"lockOwner:";
//当前文件传输到第几块
public final static String chunkCurr=file+"chunkCurr:";
//当前文件上传到fastdfs路径
public final static String fastDfsPath=file+"fastDfsPath:";
//默认分组
public final static String DEFAULT_GROUP = "group1";
//全部上传成功已完成
public final static String completedList=uploading+"completedList";
//文件块锁(解决同一个用户正在上传时并发解决,比如后端正在上传一个大文件块,前端页面点击删除按钮,
// 继续添加删除的文件,这时候要加锁来阻止其上传,否则会出现丢块问题,
// 因为fastdfs上传不像迅雷下载一样,下载时会创建一个完整的文件,如果上传第一块时,服务器能快速创建一个大文件0填充,那么这样可以支持并发乱序来下载文件块,上传速度会成倍提升,要实现乱序下载文件块,估计就得研究fastdfs源码了)
public final static String chunkLock=lock+"chunkLock:";
}
package com.loit.modules.fastdfs;
/**
*
*
* @ClassName: ErrorCode.java
* @Description: FastDFSErrorCode
* @version: v1.0.0
* @author: gaodengyun
* @date: 2019年4月24日 上午9:00:25
*/
public enum ErrorCode {
FILE_PATH_ISNULL("error.fastdfs.file_path_isnull", "文件路径为空"),
FILE_ISNULL("error.fastdfs.file_isnull", "文件为空"),
FILE_UPLOAD_FAILED("error.fastdfs.file_upload_failed", "文件上传失败"),
FILE_NOT_EXIST("error.fastdfs.file_not_exist", "文件不存在"),
FILE_DOWNLOAD_FAILED("error.fastdfs.file_download_failed", "文件下载失败"),
FILE_DELETE_FAILED("error.fastdfs.file_delete_failed", "删除文件失败"),
FILE_SERVER_CONNECTION_FAILED("error.fastdfs.file_server_connection_failed", "文件服务器连接失败"),
FILE_OUT_SIZE("error.fastdfs.file_server_connection_failed", "文件超过大小"),
FILE_TYPE_ERROR_IMAGE("error.file.type.image", "图片类型错误"),
FILE_TYPE_ERROR_DOC("error.file.type.doc", "文档类型错误"),
FILE_TYPE_ERROR_VIDEO("error.file.type.video", "音频类型错误"),
FILE_TYPE_ERROR_COMPRESS("error.file.type.compress", "压缩文件类型错误"),
FILE_TYPE_ERROR_ALLOW("error.file.type.allow", "不是允许的文件类型");
public String CODE;
public String MESSAGE;
ErrorCode(String CODE, String MESSAGE){
this.CODE = CODE;
this.MESSAGE = MESSAGE;
}
}
package com.loit.modules.fastdfs;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.FileInfo;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
/**
*
*
* @ClassName: FastDFSClient.java
* @Description: 文件上传下载主类.
*
* @version: v1.0.0
* @author: gaodengyun
* @date: 2019年4月24日 上午9:01:09
*/
public class FastDFSClient {
/**
* 路径分隔符
*/
public static final String SEPARATOR = "/";
/**
* Point
*/
public static final String POINT = ".";
/**
* ContentType
*/
public static final Map<String, String> EXT_MAPS = new HashMap<>();
/**
* org.slf4j.Logger
*/
private static Logger logger = LoggerFactory.getLogger(FastDFSClient.class);
/**
* 文件名称Key
*/
private static final String FILENAME = "filename";
/**
* 文件最大的大小
*/
private int maxFileSize = 100 * 1000 * 1000;
public FastDFSClient() {
initExt();
}
private void initExt() {
// image
EXT_MAPS.put("png", "image/png");
EXT_MAPS.put("gif", "image/gif");
EXT_MAPS.put("bmp", "image/bmp");
EXT_MAPS.put("ico", "image/x-ico");
EXT_MAPS.put("jpeg", "image/jpeg");
EXT_MAPS.put("jpg", "image/jpeg");
// 压缩文件
EXT_MAPS.put("zip", "application/zip");
EXT_MAPS.put("rar", "application/x-rar");
// doc
EXT_MAPS.put("pdf", "application/pdf");
EXT_MAPS.put("ppt", "application/vnd.ms-powerpoint");
EXT_MAPS.put("xls", "application/vnd.ms-excel");
EXT_MAPS.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
EXT_MAPS.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
EXT_MAPS.put("doc", "application/msword");
EXT_MAPS.put("doc", "application/wps-office.doc");
EXT_MAPS.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
EXT_MAPS.put("txt", "text/plain");
// 音频
EXT_MAPS.put("mp4", "video/mp4");
EXT_MAPS.put("flv", "video/x-flv");
}
/**
* MultipartFile 上传文件
*
* @param file MultipartFile
* @return 返回上传成功后的文件路径
*/
public String uploadFileWithMultipart(MultipartFile file) throws FastDFSException {
return upload(file, null);
}
/**
* MultipartFile 上传文件
*
* @param file MultipartFile
* @param descriptions 文件描述
* @return 返回上传成功后的文件路径
*/
public String uploadFileWithMultipart(MultipartFile file, Map<String, String> descriptions) throws FastDFSException {
return upload(file, descriptions);
}
/**
* 根据指定的路径上传文件
*
* @param filepath 文件路径
* @return 返回上传成功后的文件路径
*/
public String uploadFileWithFilepath(String filepath) throws FastDFSException {
return upload(filepath, null);
}
/**
* 根据指定的路径上传文件
*
* @param filepath 文件路径
* @param descriptions 文件描述
* @return 返回上传成功后的文件路径
*/
public String uploadFileWithFilepath(String filepath, Map<String, String> descriptions) throws FastDFSException {
return upload(filepath, descriptions);
}
/**
* 上传base64文件
*
* @param base64 文件base64
* @return 返回上传成功后的文件路径
*/
public String uploadFileWithBase64(String base64) throws FastDFSException {
return upload(base64, null, null);
}
/**
* 上传base64文件
*
* @param base64 文件base64
* @param filename 文件名
* @return 返回上传成功后的文件路径
*/
public String uploadFileWithBase64(String base64, String filename) throws FastDFSException {
return upload(base64, filename, null);
}
/**
* 上传base64文件
*
* @param base64 文件base64
* @param filename 文件名
* @param descriptions 文件描述信息
* @return 返回上传成功后的文件路径
*/
public String uploadFileWithBase64(String base64, String filename, Map<String, String> descriptions) throws FastDFSException {
return upload(base64, filename, descriptions);
}
/**
* 使用 MultipartFile 上传
*
* @param file MultipartFile
* @param descriptions 文件描述信息
* @return 文件路径
* @throws FastDFSException file为空则抛出异常
*/
public String upload(MultipartFile file, Map<String, String> descriptions) throws FastDFSException {
if(file == null || file.isEmpty()){
throw new FastDFSException(ErrorCode.FILE_ISNULL.CODE, ErrorCode.FILE_ISNULL.MESSAGE);
}
String path = null;
try {
path = upload(file.getInputStream(), file.getOriginalFilename(), descriptions);
} catch (IOException e) {
e.printStackTrace();
throw new FastDFSException(ErrorCode.FILE_ISNULL.CODE, ErrorCode.FILE_ISNULL.MESSAGE);
}
return path;
}
/**
* 根据指定的路径上传
*
* @param filepath 文件路径
* @param descriptions 文件描述
* @return 文件路径
* @throws FastDFSException 文件路径为空则抛出异常
*/
public String upload(String filepath, Map<String, String> descriptions) throws FastDFSException {
if(StringUtils.isBlank(filepath)){
throw new FastDFSException(ErrorCode.FILE_PATH_ISNULL.CODE, ErrorCode.FILE_PATH_ISNULL.MESSAGE);
}
File file = new File(filepath);
String path = null;
try {
InputStream is = new FileInputStream(file);
// 获取文件名
filepath = toLocal(filepath);
String filename = filepath.substring(filepath.lastIndexOf("/") + 1);
path = upload(is, filename, descriptions);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new FastDFSException(ErrorCode.FILE_NOT_EXIST.CODE, ErrorCode.FILE_NOT_EXIST.MESSAGE);
}
return path;
}
/**
*
* 上传base64文件
*
* @param base64
* @param filename 文件名
* @param descriptions 文件描述信息
* @return 文件路径
* @throws FastDFSException base64为空则抛出异常
*/
public String upload(String base64, String filename, Map<String, String> descriptions) throws FastDFSException {
if(StringUtils.isBlank(base64)){
throw new FastDFSException(ErrorCode.FILE_ISNULL.CODE, ErrorCode.FILE_ISNULL.MESSAGE);
}
return upload(new ByteArrayInputStream(Base64.decodeBase64(base64)), filename, descriptions);
}
/**
* 上传通用方法
*
* @param is 文件输入流
* @param filename 文件名
* @param descriptions 文件描述信息
* @return 组名+文件路径,如:group1/M00/00/00/wKgz6lnduTeAMdrcAAEoRmXZPp870.jpeg
* @throws FastDFSException
*/
public String upload(InputStream is, String filename, Map<String, String> descriptions) throws FastDFSException {
if(is == null){
throw new FastDFSException(ErrorCode.FILE_ISNULL.CODE, ErrorCode.FILE_ISNULL.MESSAGE);
}
try {
if(is.available() > maxFileSize){
throw new FastDFSException(ErrorCode.FILE_OUT_SIZE.CODE, ErrorCode.FILE_OUT_SIZE.MESSAGE);
}
} catch (IOException e) {
e.printStackTrace();
}
filename = toLocal(filename);
// 返回路径
String path = null;
// 文件描述
NameValuePair[] nvps = null;
List<NameValuePair> nvpsList = new ArrayList<>();
// 文件名后缀
String suffix = getFilenameSuffix(filename);
// 文件名
if (StringUtils.isNotBlank(filename)) {
nvpsList.add(new NameValuePair(FILENAME, filename));
}
// 描述信息
if (descriptions != null && descriptions.size() > 0) {
descriptions.forEach((key, value) -> {
nvpsList.add(new NameValuePair(key, value));
});
}
if (nvpsList.size() > 0) {
nvps = new NameValuePair[nvpsList.size()];
nvpsList.toArray(nvps);
}
TrackerServer trackerServer = TrackerServerPool.borrowObject();
StorageClient1 storageClient = new StorageClient1(trackerServer, null);
try {
// 读取流
byte[] fileBuff = new byte[is.available()];
is.read(fileBuff, 0, fileBuff.length);
// 上传
path = storageClient.upload_file1(fileBuff, suffix, nvps);
if(StringUtils.isBlank(path)) {
throw new FastDFSException(ErrorCode.FILE_UPLOAD_FAILED.CODE, ErrorCode.FILE_UPLOAD_FAILED.MESSAGE);
}
if (logger.isDebugEnabled()) {
logger.debug("upload file success, return path is {}", path);
}
} catch (IOException e) {
e.printStackTrace();
throw new FastDFSException(ErrorCode.FILE_UPLOAD_FAILED.CODE, ErrorCode.FILE_UPLOAD_FAILED.MESSAGE);
} catch (MyException e) {
e.printStackTrace();
throw new FastDFSException(ErrorCode.FILE_UPLOAD_FAILED.CODE, ErrorCode.FILE_UPLOAD_FAILED.MESSAGE);
} finally {
// 返还对象
TrackerServerPool.returnObject(trackerServer);
// 关闭流
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return path;
}
/**
* 以附件形式下载文件
*
* @param filepath 文件路径
* @param response
*/
public void downloadFile(String filepath, HttpServletResponse response) throws FastDFSException {
download(filepath, null, null, response);
}
/**
* 下载文件 输出文件
*
* @param filepath 文件路径
* @param os 输出流
*/
public void downloadFile(String filepath, OutputStream os) throws FastDFSException {
download(filepath, null, os, null);
}
/**
* 以附件形式下载文件 可以指定文件名称.
*
* @param filepath 文件路径
* @param filename 文件名称
* @param response HttpServletResponse
*/
public void downloadFile(String filepath, String filename, HttpServletResponse response) throws FastDFSException {
download(filepath, filename, null, response);
}
/**
* 下载文件
*
* @param filepath 文件路径
* @param filename 文件名称
* @param os 输出流
* @param response HttpServletResponse
*/
public void download(String filepath, String filename, OutputStream os, HttpServletResponse response) throws FastDFSException {
if(StringUtils.isBlank(filepath)){
throw new FastDFSException(ErrorCode.FILE_PATH_ISNULL.CODE, ErrorCode.FILE_PATH_ISNULL.MESSAGE);
}
filepath = toLocal(filepath);
// 文件名
if (StringUtils.isBlank(filename)) {
filename = getOriginalFilename(filepath);
}
String contentType = EXT_MAPS.get(getFilenameSuffix(filename));
if(logger.isDebugEnabled()){
logger.debug("download file, filepath = {}, filename = {}", filepath, filename);
}
TrackerServer trackerServer = TrackerServerPool.borrowObject();
StorageClient1 storageClient = new StorageClient1(trackerServer, null);
InputStream is = null;
try {
// 下载
byte[] fileByte = storageClient.download_file1(filepath);
if(fileByte == null){
throw new FastDFSException(ErrorCode.FILE_NOT_EXIST.CODE, ErrorCode.FILE_NOT_EXIST.MESSAGE);
}
if (response != null) {
os = response.getOutputStream();
// 设置响应头
if (StringUtils.isNotBlank(contentType)) {
// 文件编码 处理文件名中的 '+'、' ' 特殊字符
String encoderName = URLEncoder.encode(filename, "UTF-8").replace("+", "%20").replace("%2B", "+");
response.setHeader("Content-Disposition", "attachment;filename=\"" + encoderName + "\"");
response.setContentType(contentType + ";charset=UTF-8");
response.setHeader("Accept-Ranges", "bytes");
}
}
is = new ByteArrayInputStream(fileByte);
byte[] buffer = new byte[1024 * 5];
int len = 0;
while ((len = is.read(buffer)) > 0) {
os.write(buffer, 0, len);
}
os.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
throw new FastDFSException(ErrorCode.FILE_DOWNLOAD_FAILED.CODE, ErrorCode.FILE_DOWNLOAD_FAILED.MESSAGE);
} finally {
// 返还对象
TrackerServerPool.returnObject(trackerServer);
// 关闭流
try {
if(is != null){
is.close();
}
if(os != null){
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 下载文件
*
* @param filepath 文件路径
* @return 返回文件字节
* @throws FastDFSException
*/
public byte[] download(String filepath) throws FastDFSException {
if(StringUtils.isBlank(filepath)){
throw new FastDFSException(ErrorCode.FILE_PATH_ISNULL.CODE, ErrorCode.FILE_PATH_ISNULL.MESSAGE);
}
TrackerServer trackerServer = TrackerServerPool.borrowObject();
StorageClient1 storageClient = new StorageClient1(trackerServer, null);
byte[] fileByte = null;
try {
fileByte = storageClient.download_file1(filepath);
if(fileByte == null){
throw new FastDFSException(ErrorCode.FILE_NOT_EXIST.CODE, ErrorCode.FILE_NOT_EXIST.MESSAGE);
}
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
throw new FastDFSException(ErrorCode.FILE_DOWNLOAD_FAILED.CODE, ErrorCode.FILE_DOWNLOAD_FAILED.MESSAGE);
}finally {
// 返还对象
TrackerServerPool.returnObject(trackerServer);
}
return fileByte;
}
/**
* 删除文件
*
* @param filepath 文件路径
* @return 删除成功返回 0, 失败返回其它
*/
public int deleteFile(String filepath) throws FastDFSException {
if(StringUtils.isBlank(filepath)){
throw new FastDFSException(ErrorCode.FILE_PATH_ISNULL.CODE, ErrorCode.FILE_PATH_ISNULL.MESSAGE);
}
TrackerServer trackerServer = TrackerServerPool.borrowObject();
StorageClient1 storageClient = new StorageClient1(trackerServer, null);
int success = 0;
try {
success = storageClient.delete_file1(filepath);
if(success != 0){
throw new FastDFSException(ErrorCode.FILE_DELETE_FAILED.CODE, ErrorCode.FILE_NOT_EXIST.MESSAGE);
}
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
throw new FastDFSException(ErrorCode.FILE_DELETE_FAILED.CODE, ErrorCode.FILE_DELETE_FAILED.MESSAGE);
}finally {
// 返还对象
TrackerServerPool.returnObject(trackerServer);
}
return success;
}
/**
* 获取文件信息
*
* @param filepath 文件路径
* @return 文件信息
*
* <pre>
* {<br>
* "SourceIpAddr": 源IP <br>
* "FileSize": 文件大小 <br>
* "CreateTime": 创建时间 <br>
* "CRC32": 签名 <br>
* } <br>
* </pre>
*/
public Map<String, Object> getFileInfo(String filepath) throws FastDFSException {
TrackerServer trackerServer = TrackerServerPool.borrowObject();
StorageClient1 storageClient = new StorageClient1(trackerServer, null);
FileInfo fileInfo = null;
try {
fileInfo = storageClient.get_file_info1(filepath);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}finally {
// 返还对象
TrackerServerPool.returnObject(trackerServer);
}
Map<String, Object> infoMap = new HashMap<>(4);
infoMap.put("SourceIpAddr", fileInfo.getSourceIpAddr());
infoMap.put("FileSize", fileInfo.getFileSize());
infoMap.put("CreateTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(fileInfo.getCreateTimestamp()));
infoMap.put("CRC32", fileInfo.getCrc32());
return infoMap;
}
/**
* 获取文件描述信息
*
* @param filepath 文件路径
* @return 文件描述信息
*/
public Map<String, Object> getFileDescriptions(String filepath) throws FastDFSException {
TrackerServer trackerServer = TrackerServerPool.borrowObject();
StorageClient1 storageClient = new StorageClient1(trackerServer, null);
NameValuePair[] nvps = null;
try {
nvps = storageClient.get_metadata1(filepath);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}finally {
// 返还对象
TrackerServerPool.returnObject(trackerServer);
}
Map<String, Object> infoMap = null;
if (nvps != null && nvps.length > 0) {
infoMap = new HashMap<>(nvps.length);
for (NameValuePair nvp : nvps) {
infoMap.put(nvp.getName(), nvp.getValue());
}
}
return infoMap;
}
/**
* 获取源文件的文件名称
*
* @param filepath 文件路径
* @return 文件名称
*/
public String getOriginalFilename(String filepath) throws FastDFSException {
Map<String, Object> descriptions = getFileDescriptions(filepath);
if (descriptions.get(FILENAME) != null) {
return (String) descriptions.get(FILENAME);
}
return null;
}
/**
* 获取文件名称的后缀
*
* @param filename 文件名 或 文件路径
* @return 文件后缀
*/
public static String getFilenameSuffix(String filename) {
String suffix = null;
String originalFilename = filename;
if (StringUtils.isNotBlank(filename)) {
if (filename.contains(SEPARATOR)) {
filename = filename.substring(filename.lastIndexOf(SEPARATOR) + 1);
}
if (filename.contains(POINT)) {
suffix = filename.substring(filename.lastIndexOf(POINT) + 1);
} else {
if (logger.isErrorEnabled()) {
logger.error("filename error without suffix : {}", originalFilename);
}
}
}
return suffix;
}
/**
* 转换路径中的 '\' 为 '/' <br>
* 并把文件后缀转为小写
*
* @param path 路径
* @return
*/
public static String toLocal(String path) {
if (StringUtils.isNotBlank(path)) {
path = path.replaceAll("\\\\", SEPARATOR);
if (path.contains(POINT)) {
String pre = path.substring(0, path.lastIndexOf(POINT) + 1);
String suffix = path.substring(path.lastIndexOf(POINT) + 1).toLowerCase();
path = pre + suffix;
}
}
return path;
}
/**
* 获取FastDFS文件的名称,如:M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
*
* @param fileId 包含组名和文件名,如:group1/M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
* @return FastDFS 返回的文件名:M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
*/
public static String getFilename(String fileId){
String[] results = new String[2];
StorageClient1.split_file_id(fileId, results);
return results[1];
}
/**
* 获取访问服务器的token,拼接到地址后面
*
* @param filepath 文件路径 group1/M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
* @param httpSecretKey 秘钥
* @return 返回token,如: token=078d370098b03e9020b82c829c205e1f&ts=1508141521
*/
/* public static String getToken(String filepath, String httpSecretKey){
// unix seconds
int ts = (int) Instant.now().getEpochSecond();
// token
String token = "null";
try {
token = ProtoCommon.getToken(getFilename(filepath), ts, httpSecretKey);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
StringBuilder sb = new StringBuilder();
sb.append("token=").append(token);
sb.append("&ts=").append(ts);
return sb.toString();
}*/
/**
* @return the max file size
*/
public int getMaxFileSize() {
return maxFileSize;
}
/**
* Set max file size, default 100M
* @param maxFileSize the max file size
*/
public void setMaxFileSize(int maxFileSize) {
this.maxFileSize = maxFileSize;
}
/**
* 测试
*/
public static void main(String[] args) throws Exception {
}
}
package com.loit.modules.fastdfs;
/**
* FastDFS 上传下载时可能出现的一些异常信息
* <p>
*
* @author jiangzhou.bo@hand-china.com
* @version 1.0
* @name FastDFSException
* @date 2017-10-13 15:12
*/
public class FastDFSException extends Exception {
private static final long serialVersionUID = -7540424984113469133L;
/**
* 错误码
*/
private String code;
/**
* 错误消息
*/
private String message;
public FastDFSException(){}
public FastDFSException(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
package com.loit.modules.fastdfs;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
*
*
* @ClassName: FileCheck.java
* @Description: 文件检查工具类
*
* @version: v1.0.0
* @author: gaodengyun
* @date: 2019年4月24日 上午9:02:20
*
*/
public class FileCheck {
/**
* 图片类型
*/
private static final List<String> TYPE_IMAGE = new ArrayList<>();
/**
* 文档类型
*/
private static final List<String> TYPE_DOC = new ArrayList<>();
/**
* 音频类型
*/
private static final List<String> TYPE_VIDEO = new ArrayList<>();
/**
* 压缩文件类型
*/
private static final List<String> TYPE_COMPRESS = new ArrayList<>();
static {
TYPE_IMAGE.add("png");
TYPE_IMAGE.add("gif");
TYPE_IMAGE.add("jpeg");
TYPE_IMAGE.add("jpg");
TYPE_DOC.add("pdf");
TYPE_DOC.add("ppt");
TYPE_DOC.add("xls");
TYPE_DOC.add("xlsx");
TYPE_DOC.add("pptx");
TYPE_DOC.add("doc");
TYPE_DOC.add("docx");
TYPE_VIDEO.add("mp3");
TYPE_VIDEO.add("mp4");
TYPE_VIDEO.add("flv");
TYPE_COMPRESS.add("zip");
TYPE_COMPRESS.add("rar");
}
/**
* 检查图片类型. <br>
* 默认检查 ['png', 'gif', 'jpeg', 'jpg'] 几种类型
* @param filename 文件名称
* @return
*/
public static boolean checkImage(String filename){
return checkImage(null, filename);
}
/**
* 检查图片类型
* @param types 可自行传入文件的类型集合,默认检查 ['png', 'gif', 'jpeg', 'jpg'] 几种类型
* @param filename 文件名称
* @return
*/
public static boolean checkImage(List<String> types, String filename){
List<String> checkTypes = types;
if(types == null || types.size() == 0){
checkTypes = TYPE_IMAGE;
}
return checkType(checkTypes, filename);
}
/**
* 检查文档类型. <br>
* 默认检查 ['pdf', 'ppt', 'xls', 'xlsx', 'pptx', 'doc', 'docx'] 几种类型
* @param filename 文件名称
* @return
*/
public static boolean checkDoc(String filename){
return checkDoc(null, filename);
}
/**
* 检查文档类型
* @param types 可自行传入文件的类型集合,默认检查 ['pdf', 'ppt', 'xls', 'xlsx', 'pptx', 'doc', 'docx'] 几种类型
* @param filename 文件名称
* @return
*/
public static boolean checkDoc(List<String> types, String filename){
List<String> checkTypes = types;
if(types == null || types.size() == 0){
checkTypes = TYPE_DOC;
}
return checkType(checkTypes, filename);
}
/**
* 检查音频类型. <br>
* 默认检查 ['mp3', 'mp4', 'flv'] 几种类型
* @param filename 文件名称
* @return
*/
public static boolean checkVideo(String filename){
return checkVideo(null, filename);
}
/**
* 检查音频类型
* @param types 可自行传入文件的类型集合,默认检查 ['mp3', 'mp4', 'flv'] 几种类型
* @param filename 文件名称
* @return
*/
public static boolean checkVideo(List<String> types, String filename){
List<String> checkTypes = types;
if(types == null || types.size() == 0){
checkTypes = TYPE_VIDEO;
}
return checkType(checkTypes, filename);
}
/**
* 检查压缩文件类型. <br>
* 默认检查 ['zip', 'rar'] 几种类型
* @param filename 文件名称
* @return
*/
public static boolean checkCompress(String filename){
return checkCompress(null, filename);
}
/**
* 检查压缩文件类型
* @param types 可自行传入文件的类型集合,默认检查 ['zip', 'rar'] 几种类型
* @param filename 文件名称
* @return
*/
public static boolean checkCompress(List<String> types, String filename){
List<String> checkTypes = types;
if(types == null || types.size() == 0){
checkTypes = TYPE_COMPRESS;
}
return checkType(checkTypes, filename);
}
/**
* 检查类型通用方法
*/
private static boolean checkType(List<String> checkTypes, String filename){
return checkTypes.contains(getFilenameSuffix(filename));
}
/**
* 获取文件名称的后缀
*
* @param filename
* @return 文件后缀
*/
public static String getFilenameSuffix(String filename) {
String suffix = null;
if (StringUtils.isNotBlank(filename) && filename.contains(FastDFSClient.POINT)) {
suffix = filename.substring(filename.lastIndexOf(FastDFSClient.POINT) + 1).toLowerCase();
}
return suffix;
}
}
package com.loit.modules.fastdfs;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
/**
*
*
* @ClassName: FileResponseData.java
* @Description:上传文件后的数据返回对象,便于前台获取数据.
*
* @version: v1.0.0
* @author: gaodengyun
* @date: 2019年4月24日 上午10:20:51
*/
public class FileResponseData {
/**
* 返回状态编码
*/
@JsonInclude(Include.NON_NULL)
private String code;
/**
* 返回信息
*/
@JsonInclude(Include.NON_NULL)
private String message;
/**
* 成功标识
*/
private boolean success = true;
/**
* 文件路径
*/
@JsonInclude(Include.NON_NULL)
private String filePath;
/**
* 文件名称
*/
@JsonInclude(Include.NON_NULL)
private String fileName;
/**
* 文件类型
*/
@JsonInclude(Include.NON_NULL)
private String fileType;
/**
* Http URL
*/
@JsonInclude(Include.NON_NULL)
private String httpUrl;
/**
* Http Token
*/
/* @JsonInclude(Include.NON_NULL)
private String token;
*/
public FileResponseData(){}
public FileResponseData(boolean success) {
this.success = success;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public String getHttpUrl() {
return httpUrl;
}
public void setHttpUrl(String httpUrl) {
this.httpUrl = httpUrl;
}
/*public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}*/
}
package com.loit.modules.fastdfs;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
/**
*
*
* @ClassName: TrackerServerFactory.java
* @Description: 工厂类,创建对象池需要 BasePooledObjectFactory 对象或子类.
*
* @version: v1.0.0
* @author: gaodengyun
* @date: 2019年4月24日 上午9:04:13
*/
public class TrackerServerFactory extends BasePooledObjectFactory<TrackerServer> {
@Override
public TrackerServer create() throws Exception {
// TrackerClient
TrackerClient trackerClient = new TrackerClient();
// TrackerServer
TrackerServer trackerServer = trackerClient.getConnection();
return trackerServer;
}
@Override
public PooledObject<TrackerServer> wrap(TrackerServer trackerServer) {
return new DefaultPooledObject<TrackerServer>(trackerServer);
}
}
package com.loit.modules.fastdfs;
import java.io.IOException;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.csource.common.MyException;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.loit.common.config.SpringContextUtil;
/**
*
*
* @ClassName: TrackerServerPool.java
* @Description: TrackerServer 对象池
* @version: v1.0.0
* @author: gaodengyun
* @date: 2019年4月24日 上午9:03:19
*/
@Component
public class TrackerServerPool {
/**
* org.slf4j.Logger
*/
private static Logger logger = LoggerFactory.getLogger(TrackerServerPool.class);
/**
* TrackerServer 配置文件路径
*/
private static final String FASTDFS_CONFIG_DEV_PATH ="config/config-dev.properties";
/**
* TrackerServer 配置文件路径
*/
private static final String FASTDFS_CONFIG_PROC_PATH ="config/config-proc.properties";
/**
* TrackerServer 配置文件路径
*/
private static final String FASTDFS_CONFIG_TESST_PATH ="config/config-test.properties";
/**
* 最大连接数 default 8.
*/
private static int maxStorageConnection;
@Value("${fastdfs.max_storage_connection}")
public void setMaxStorageConnection(int maxStorageConnection) {
TrackerServerPool.maxStorageConnection = maxStorageConnection;
}
/**
* TrackerServer 对象池.
* GenericObjectPool 没有无参构造
*/
private static GenericObjectPool<TrackerServer> trackerServerPool;
private TrackerServerPool(){};
private static synchronized GenericObjectPool<TrackerServer> getObjectPool(){
if(trackerServerPool == null){
try {
// 加载配置文件
String activeMode = SpringContextUtil.getActiveProfile();
System.out.println("activeMode:==="+activeMode);
System.out.println("maxStorageConnection:==="+maxStorageConnection);
switch (activeMode) {
case "proc":
ClientGlobal.initByProperties(FASTDFS_CONFIG_PROC_PATH);
break;
case "dev":
ClientGlobal.initByProperties(FASTDFS_CONFIG_DEV_PATH);
break;
default:
ClientGlobal.initByProperties(FASTDFS_CONFIG_TESST_PATH);
}
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
if(logger.isDebugEnabled()){
logger.debug("ClientGlobal configInfo: {}", ClientGlobal.configInfo());
}
// Pool配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMinIdle(2);
if(maxStorageConnection > 0){
poolConfig.setMaxTotal(maxStorageConnection);
}
trackerServerPool = new GenericObjectPool<>(new TrackerServerFactory(), poolConfig);
}
return trackerServerPool;
}
/**
* 获取 TrackerServer
* @return TrackerServer
* @throws FastDFSException
*/
public static TrackerServer borrowObject() throws FastDFSException {
TrackerServer trackerServer = null;
try {
trackerServer = getObjectPool().borrowObject();
System.out.println(trackerServerPool.getBorrowedCount()+","+trackerServerPool.getCreatedCount()+","+trackerServerPool.getDestroyedByBorrowValidationCount()+","+trackerServerPool.getDestroyedByEvictorCount()+","+trackerServerPool.getDestroyedCount()+","+trackerServerPool.getReturnedCount());
} catch (Exception e) {
e.printStackTrace();
if(e instanceof FastDFSException){
throw (FastDFSException) e;
}
}
return trackerServer;
}
/**
* 回收 TrackerServer
* @param trackerServer 需要回收的 TrackerServer
*/
public static void returnObject(TrackerServer trackerServer){
getObjectPool().returnObject(trackerServer);
}
}
package com.loit.web.file.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.service.AppendFileStorageClient;
import com.loit.common.tool.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
*
* @ClassName: ChunkUploadController.java
* @Description: 分片上传
* @version: v1.0.0
* @author: fangshiquan
* @date: 2019年11月18日
*/
@Controller
@RequestMapping("/api/chunkfile")
public class ChunkUploadController {
@Autowired
private AppendFileStorageClient appendFileStorageClient;
protected Logger _logger = LoggerFactory.getLogger(this.getClass());
/**
* 获取配置
* @return 根目录与分块大小
*/
@RequestMapping("/config")
@ResponseBody
public String config(){
JSONObject jsonObject = new JSONObject();
jsonObject.put("fileServerUrl",ReadProper.getResourceValue("fastdfs.file_server_prefix")+"/");
jsonObject.put("maxSize", ReadProper.getResourceValue("zwup.maxSize"));
return jsonObject.toString();
}
/**
* @param paramMap 切片信息
* @param request 请求信息
* @param userName 用户名
* @return 上传完成信息
* @throws IOException 异常
*/
@SuppressWarnings("rawtypes")
@PostMapping("/chunkUpload")
@ResponseBody
public ApiResult chunkUpload(@RequestParam Map<String, Object> paramMap, HttpServletRequest request,String userName,@RequestParam(value = "file", required = true) MultipartFile file) throws IOException {
String noGroupPath;//存储在fastdfs不带组的路径
String fileMd5= (String) paramMap.get("fileMd5");
String chunklockName=UpLoadConstant.chunkLock+fileMd5;
boolean currOwner=false;//真正的拥有者
String fileName= (String) paramMap.get("name");
Long size=Convert.toLong(paramMap.get("size"));
Integer chunks_int=Convert.toInt(paramMap.get("chunks"));
try {
if (StrUtil.isEmpty(userName)){
userName= (String) request.getSession().getAttribute("name");
}
if (StrUtil.isEmpty(userName)){
return ApiResult.fail("请先登录");
}
if (!paramMap.containsKey("chunk")){
paramMap.put("chunk","0");
}
if (!paramMap.containsKey("chunks")){
paramMap.put("chunks","1");
}
Long lock= RedisUtil.incrBy(chunklockName,1);
if (lock>1){
return ApiResult.fail("请求块锁失败");
}
//写入锁的当前拥有者
currOwner=true;
String chunk= (String) paramMap.get("chunk");
String chunkCurrkey= UpLoadConstant.chunkCurr+fileMd5; //redis中记录当前应该穿第几块(从0开始)
String chunkCurr= RedisUtil.getString(chunkCurrkey);
noGroupPath = "";
Integer chunkSize=Convert.toInt(paramMap.get("chunkSize"));
if (StrUtil.isEmpty(chunkCurr)){
return ApiResult.fail("无法获取当前文件chunkCurr");
// throw new RuntimeException("无法获取当前文件chunkCurr");
}
Integer chunkCurr_int=Convert.toInt(chunkCurr);
Integer chunk_int=Convert.toInt(chunk);
if (chunk_int<chunkCurr_int){
return ApiResult.fail("当前文件块已上传");
}else if (chunk_int>chunkCurr_int){
return ApiResult.fail("当前文件块需要等待上传,稍后请重试");
}
// System.out.println("***********开始**********");
StorePath path = null;
//暂时不支持多文件上传,后续版本可以再加上
if (!file.isEmpty()) {
try {
if (chunk_int==0){
RedisUtil.setString(chunkCurrkey,Convert.toStr(chunkCurr_int+1));
_logger.debug(chunk+":redis块+1");
try {
path = appendFileStorageClient.uploadAppenderFile(UpLoadConstant.DEFAULT_GROUP, file.getInputStream(),
file.getSize(), FileUtil.extName((String) paramMap.get("name")));
_logger.debug(chunk+":更新完fastdfs");
if (path== null ){
RedisUtil.setString(chunkCurrkey,Convert.toStr(chunkCurr_int));
return ApiResult.fail("获取远程文件路径出错");
}
} catch (Exception e) {
RedisUtil.setString(chunkCurrkey,Convert.toStr(chunkCurr_int));
// e.printStackTrace();
//还原历史块
_logger.error("初次上传远程文件出错", e);
return ApiResult.fail("上传远程服务器文件出错");
}
noGroupPath=path.getPath();
RedisUtil.setString(UpLoadConstant.fastDfsPath+fileMd5,path.getPath());
_logger.debug("上传文件 result={}", path);
}else {
RedisUtil.setString(chunkCurrkey,Convert.toStr(chunkCurr_int+1));
_logger.debug(chunk+"大于0:redis块+1");
noGroupPath=RedisUtil.getString(UpLoadConstant.fastDfsPath+fileMd5);
if (noGroupPath== null ){
return ApiResult.fail("无法获取上传远程服务器文件出错");
}
try {
int offSet=chunkCurr_int*chunkSize;
if (chunk_int+1==chunks_int){
offSet=size.intValue()-chunkSize;
}
//追加方式实际实用如果中途出错多次,可能会出现重复追加情况,这里改成修改模式,即时多次传来重复文件块,依然可以保证文件拼接正确
appendFileStorageClient.modifyFile(UpLoadConstant.DEFAULT_GROUP, noGroupPath, file.getInputStream(),
file.getSize(),offSet);
_logger.debug(chunk+":更新完fastdfs");
} catch (Exception e) {
RedisUtil.setString(chunkCurrkey,Convert.toStr(chunkCurr_int));
_logger.error("更新远程文件出错", e);
// e.printStackTrace();
// throw new RuntimeException("初次上传远程文件出错");
System.out.println("更新远程文件出错");
return ApiResult.fail("更新远程文件出错");
}
}
//最后一块,清空upload,写入数据库
if (chunk_int+1==chunks_int){
//持久化上传完成文件,也可以存储在mysql中
FileResult fileResult=new FileResult();
fileResult.setMd5(fileMd5);
fileResult.setName(fileName);
fileResult.setLenght(size);
fileResult.setUrl(UpLoadConstant.DEFAULT_GROUP+"/"+noGroupPath);
RedisUtil.rpush(UpLoadConstant.completedList, JSONUtil.toJsonStr(fileResult));
RedisUtil.delKeys(new String[]{UpLoadConstant.chunkCurr+fileMd5,
UpLoadConstant.fastDfsPath+fileMd5,
UpLoadConstant.currLocks+fileMd5,
UpLoadConstant.lockOwner+fileMd5
});
}
} catch (Exception e) {
_logger.error("上传文件错误", e);
//e.printStackTrace();
return ApiResult.fail("上传错误 " + e.getMessage());
}
}
} finally {
//锁的当前拥有者才能释放块上传锁
if (currOwner){
RedisUtil.setString(chunklockName,"0");
}
//关闭连接
RedisUtil.threadLocalJedis.get().close();
RedisUtil.threadLocalJedis.set(null);
}
return ApiResult.success(UpLoadConstant.DEFAULT_GROUP+"/"+noGroupPath);
}
/**
* @param paramMap 切片信息
* @param request 请求信息
* @param userName 用户名
* @return 检查上传切片的顺序
* @throws IOException 异常
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@PostMapping("/checkFile")
@ResponseBody
public ApiResult checkFile(@RequestParam Map<String, Object> paramMap, HttpServletRequest request,String userName) throws IOException {
CheckFileResult checkFileResult=new CheckFileResult();
try {
if (StrUtil.isEmpty(userName)){
userName= (String) request.getSession().getAttribute("name");
}
if (StrUtil.isEmpty(userName)){
return ApiResult.fail("请先登录");
}
String fileMd5= (String) paramMap.get("fileMd5");
if (StrUtil.isEmpty(fileMd5)){
return ApiResult.fail("fileMd5不能为空");
}
//模拟从mysql中查询文件表的md5,这里从redis里查询
List<String> fileList=RedisUtil.getListAll(UpLoadConstant.completedList);
if (CollUtil.isNotEmpty(fileList)){
for (String e:fileList){
JSONObject obj=JSONUtil.parseObj(e);
if (obj.get("md5").equals(fileMd5)){
checkFileResult.setTotalSize(obj.getLong("lenght"));
checkFileResult.setViewPath(obj.getStr("url"));
return ApiResult.success(checkFileResult);
}
}
}
//查询锁占用
String lockName=UpLoadConstant.currLocks+fileMd5;
System.out.println("lockName:"+lockName);
Long lock= RedisUtil.incrBy(lockName,1);
String lockOwner=UpLoadConstant.lockOwner+ fileMd5;
String chunkCurrkey=UpLoadConstant.chunkCurr+fileMd5;
if (lock>1){
checkFileResult.setLock(1);
//检查是否为锁的拥有者,如果是放行
String oWner= RedisUtil.getString(lockOwner);
if (StrUtil.isEmpty(oWner)){
return ApiResult.fail("无法获取文件锁拥有者");
}else {
if (oWner.equals(request.getSession().getAttribute("name"))){
String chunkCurr= RedisUtil.getString(chunkCurrkey);
if (StrUtil.isEmpty(chunkCurr)){
return ApiResult.fail("无法获取当前文件chunkCurr");
}
checkFileResult.setChunkCurr(Convert.toInt(chunkCurr));
return ApiResult.success(checkFileResult);
}else {
return ApiResult.fail("当前文件已有人在上传,您暂无法上传该文件");
}
}
}else {
//初始化锁.分块
RedisUtil.setString(lockOwner, (String) request.getSession().getAttribute("name"));
RedisUtil.setString(chunkCurrkey,"0"); //第一块索引是0,与前端保持一致
checkFileResult.setChunkCurr(0);
}
} finally {
//关闭连接
RedisUtil.threadLocalJedis.get().close();
RedisUtil.threadLocalJedis.set(null);
}
return ApiResult.success(checkFileResult);
}
}
package com.loit.web.file.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.loit.common.config.FastDFSConfigInfo;
import com.loit.common.json.AjaxJson;
import com.loit.common.json.LoitStatusCode;
import com.loit.modules.fastdfs.ErrorCode;
import com.loit.modules.fastdfs.FastDFSClient;
import com.loit.modules.fastdfs.FastDFSException;
import com.loit.modules.fastdfs.FileResponseData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
/**
* @description 文件上传下载管理Controller
* @author fangshiquan
* @date 2019-11-08
* @version V1.0
*/
@RestController
@RequestMapping(value = "api/file")
@Api(tags = "文件管理", value = "FileRestController")
public class FileRestController {
@Autowired
private FastDFSConfigInfo fastDFSConfigInfo;
private FastDFSClient fastDFSClient = new FastDFSClient();
@GetMapping(value = "demo")
public String demo(HttpServletRequest request) {
System.out.println("dedmo");
System.out.println(request.getHeader("a"));
return "demo";
}
/**
* @description 上传文件
* @param file 文件参数
* @param request 请求
* @return AjaxJson
*/
@PostMapping(value = "upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiOperation(value="文件上传", notes="文件上传")
public AjaxJson fileUpload(@RequestParam(value = "file", required = true) MultipartFile file, HttpServletRequest request) {
AjaxJson json = new AjaxJson();
//文件保存
FileResponseData fileResponseData =uploadSample(file, request);
json.setSuccess(fileResponseData.isSuccess());
json.setMsg(fileResponseData.getMessage());
json.setErrorCode(fileResponseData.getCode());
json.put("fileResponseData", fileResponseData);
return json;
}
/**
* 以附件形式下载文件
*
* @param filePath 文件地址
* @param response
*/
@RequestMapping(value="/download", method=RequestMethod.GET)
@ApiImplicitParam(name = "filePath", value = "文件路径", required = true, dataType = "String",paramType = "query")
@ApiOperation(value="文件下载", notes="文件下载")
public void downloadFile(String filePath, HttpServletResponse response) throws FastDFSException {
try {
if (filePath.startsWith("http://")) {
filePath =filePath.replace(fastDFSConfigInfo.getFileServerPrefix(), "");
}
fastDFSClient.downloadFile(filePath, response);
} catch (FastDFSException e) {
e.printStackTrace();
throw e;
}
}
/**
* 根据指定的路径删除服务器文件,适用于没有保存数据库记录的文件
*
* @param filePath
*/
@ApiImplicitParam(name = "filePath", value = "filePath", required = true, dataType = "String",paramType = "query")
@ApiOperation(value="文件删除", notes="文件删除")
@RequestMapping(value="/delete", method=RequestMethod.DELETE)
public AjaxJson deleteFile(@RequestParam(value = "filePath") String filePath) {
AjaxJson json = new AjaxJson();
FileResponseData responseData = new FileResponseData();
try {
if (filePath.startsWith("http://")) {
filePath =filePath.replace(fastDFSConfigInfo.getFileServerPrefix(), "");
}
fastDFSClient.deleteFile(filePath);
} catch (FastDFSException e) {
e.printStackTrace();
responseData.setSuccess(false);
responseData.setCode(e.getCode());
responseData.setMessage(e.getMessage());
json.setSuccess(false);
json.setMsg(e.getMessage());
json.setErrorCode(LoitStatusCode.FILE_DELETE_FAILED.statusCode);
json.put("fileResponseData", responseData);
}
return json;
}
/**
* 上传通用方法,只上传到服务器,不保存记录到数据库
*
* @param file
* @param request
* @return
*/
@SuppressWarnings("static-access")
public FileResponseData uploadSample(MultipartFile file, HttpServletRequest request){
FileResponseData responseData = new FileResponseData();
try {
// 上传到服务器
String suffix =fastDFSClient.getFilenameSuffix(file.getOriginalFilename());
if(fastDFSClient.EXT_MAPS.get(suffix)!=null) {
String filepath = fastDFSClient.uploadFileWithMultipart(file);
responseData.setFileName(file.getOriginalFilename());
responseData.setFilePath(filepath);
responseData.setFileType(FastDFSClient.getFilenameSuffix(file.getOriginalFilename()));
// 设置访文件的Http地址. 有时效性.
/* String token = FastDFSClient.getToken(filepath, fastDFSHttpSecretKey);
responseData.setToken(token);*/
//responseData.setHttpUrl(fileServerAddr+"/"+filepath+"?"+token);
responseData.setHttpUrl(fastDFSConfigInfo.getFileServerPrefix()+"/"+filepath);
}else {
responseData.setSuccess(false);
responseData.setCode(ErrorCode.FILE_TYPE_ERROR_ALLOW.CODE);
responseData.setMessage(ErrorCode.FILE_TYPE_ERROR_ALLOW.MESSAGE);
}
} catch (FastDFSException e) {
responseData.setSuccess(false);
responseData.setCode(e.getCode());
responseData.setMessage(e.getMessage());
}
return responseData;
}
/**
* 并发接口测试
* @return
*/
@GetMapping("/getMapInfo")
public Map<String,Object> getMapInfo(){
Map<String,Object> map=new HashMap<String, Object>();
map.put("name","fangshiquan");
map.put("age","20");
map.put("sex","男");
map.put("where","datian");
map.put("daxia","令狐冲");
map.put("daxia2","令狐冲ee");
map.put("da6xia2","333令狐冲ee");
map.put("da6hhh","33kk狐冲ee");
map.put("da6hhh2","33kk狐冲ee");
map.put("da6hhh1","33kk狐冲ee");
map.put("da6hhh3","33kk狐冲ee");
map.put("da6hhh4","33kk狐冲ee");
map.put("da6hhh5","33kk狐冲ee");
map.put("da6hhh6","33kk狐冲ee");
map.put("da6hhh7","33kk狐冲ee");
map.put("da6哈哈ia2","333令狐冲ee");
map.put("d发给过hh","33kk狐冲ee");
map.put("da分为非h2","33kk狐冲ee");
map.put("da分为e非h1","33kk狐冲ee");
map.put("da6h发hh3","33kk狐冲ee");
map.put("da6hh分h4","33kk狐冲ee");
map.put("da6hh仍无法h5","33kk狐冲ee");
map.put("da6hh违法h6","33kk狐冲ee");
map.put("da6hhh7","33kk狐冲ee");
return map;
}
}
fastdfs:
file_server_prefix: http://39.100.254.140
max_storage_connection: 8
fdfs:
connect-timeout: 6000
pool:
jmx-name-base: 1
jmx-name-prefix: 1
max-wait-millis: 500
so-timeout: 6000
thumb-image:
height: 150
width: 150
tracker-list:
- 39.100.254.140:22122
pool:
max-total: 153
server:
port: 7003
tomcat:
basedir: D:\file\temp
spring:
application:
name: loit-file
freemarker:
allow-request-override: false
allow-session-override: false
cache: false
charset: UTF-8
check-template-location: true
content-type: text/html
enabled: true
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
order: 1
prefer-file-system-access: true
request-context-attribute: request
settings:
classic_compatible: true
datetime_format: yyyy-MM-dd HH:mm:ss
default_encoding: UTF-8
number_format: 0.##########
template_exception_handler: ignore
template_update_delay: 0
suffix: .ftl
template-loader-path: classpath:/templates/
redis:
host: 127.0.0.1
#password: portal2019
pool:
max-active: 1
max-idle: 8
max-wait: 20000
min-idle: 8
port: 6379
timeout: 20000
servlet:
multipart:
max-file-size: 2048MB
max-request-size: 2048MB
cloud:
nacos:
discovery:
# Nacos 注册中心地址
server-addr: 39.100.254.140:8103
namespace: 3ac84119-5558-4bf8-b309-034dd0e458e0
zwup:
maxSize: 102400
\ No newline at end of file
# 演示环境
#eureka:
# client:
# serviceUrl:
# defaultZone: http://localhost:8003/eureka/
# instance:
# prefer-ip-address: true
# instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
# leaseRenewalIntervalInSeconds: 10
# health-check-url-path: /actuator/health
#权限配置
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
info:
name: '@project.name@'
description: '@project.description@'
fastdfs:
file_server_prefix: http://39.100.254.140
max_storage_connection: 8
fdfs:
connect-timeout: 6000
pool:
jmx-name-base: 1
jmx-name-prefix: 1
max-wait-millis: 500
so-timeout: 6000
thumb-image:
height: 150
width: 150
tracker-list:
- 39.100.254.140:22122
pool:
max-total: 153
server:
port: 6001
tomcat:
basedir: /var/www/tomcat/temp
spring:
application:
name: loit-file
freemarker:
allow-request-override: false
allow-session-override: false
cache: false
charset: UTF-8
check-template-location: true
content-type: text/html
enabled: true
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
order: 1
prefer-file-system-access: true
request-context-attribute: request
settings:
classic_compatible: true
datetime_format: yyyy-MM-dd HH:mm:ss
default_encoding: UTF-8
number_format: 0.##########
template_exception_handler: ignore
template_update_delay: 0
suffix: .ftl
template-loader-path: classpath:/templates/
http:
multipart:
maxFileSize: 2048mb
maxRequestSize: 2048mb
redis:
host: 127.0.0.1
password: portal2019
pool:
max-active: 1
max-idle: 8
max-wait: 20000
min-idle: 8
port: 6379
timeout: 20000
servlet:
multipart:
max-file-size: 2048mb
max-request-size: 2048mb
cloud:
nacos:
discovery:
#Nacos 注册中心地址
server-addr: 39.100.254.140:8103
namespace: 0e1abf19-be7e-4940-b6da-ff5f697a226c
zwup:
maxSize: 102400
\ No newline at end of file
# 南巨马河环境
#eureka:
# client:
# serviceUrl:
# defaultZone: http://localhost:8003/eureka/
# instance:
# prefer-ip-address: true
# instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
# leaseRenewalIntervalInSeconds: 10
# health-check-url-path: /actuator/health
#权限配置
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
info:
name: '@project.name@'
description: '@project.description@'
fastdfs:
file_server_prefix: http://39.100.254.140
max_storage_connection: 8
fdfs:
connect-timeout: 6000
pool:
jmx-name-base: 1
jmx-name-prefix: 1
max-wait-millis: 500
so-timeout: 6000
thumb-image:
height: 150
width: 150
tracker-list:
- 39.100.254.140:22122
pool:
max-total: 153
server:
port: 6006
tomcat:
basedir: /var/www/tomcat/temp
spring:
application:
name: loit-file
freemarker:
allow-request-override: false
allow-session-override: false
cache: false
charset: UTF-8
check-template-location: true
content-type: text/html
enabled: true
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
order: 1
prefer-file-system-access: true
request-context-attribute: request
settings:
classic_compatible: true
datetime_format: yyyy-MM-dd HH:mm:ss
default_encoding: UTF-8
number_format: 0.##########
template_exception_handler: ignore
template_update_delay: 0
suffix: .ftl
template-loader-path: classpath:/templates/
http:
multipart:
maxFileSize: 2048mb
maxRequestSize: 2048mb
redis:
host: 127.0.0.1
password: portal2019
pool:
max-active: 1
max-idle: 8
max-wait: 20000
min-idle: 8
port: 6379
timeout: 20000
servlet:
multipart:
max-file-size: 2048mb
max-request-size: 2048mb
cloud:
nacos:
discovery:
#Nacos 注册中心地址
server-addr: 39.100.254.140:8103
namespace: 6c8fa2e5-a3b8-48a0-9ab6-c1097ecc0dc3
zwup:
maxSize: 102400
\ No newline at end of file
# 测试环境
#eureka:
# client:
# serviceUrl:
# defaultZone: http://localhost:8003/eureka/
# instance:
# prefer-ip-address: true
# instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
# leaseRenewalIntervalInSeconds: 10
# health-check-url-path: /actuator/health
#权限配置
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
info:
name: '@project.name@'
description: '@project.description@'
fastdfs:
file_server_prefix: http://39.100.254.140
max_storage_connection: 8
fdfs:
connect-timeout: 6000
pool:
jmx-name-base: 1
jmx-name-prefix: 1
max-wait-millis: 500
so-timeout: 6000
thumb-image:
height: 150
width: 150
tracker-list:
- 39.100.254.140:22122
pool:
max-total: 153
server:
port: 7004
tomcat:
basedir: /var/www/tomcat/temp
spring:
application:
name: loit-file
freemarker:
allow-request-override: false
allow-session-override: false
cache: false
charset: UTF-8
check-template-location: true
content-type: text/html
enabled: true
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
order: 1
prefer-file-system-access: true
request-context-attribute: request
settings:
classic_compatible: true
datetime_format: yyyy-MM-dd HH:mm:ss
default_encoding: UTF-8
number_format: 0.##########
template_exception_handler: ignore
template_update_delay: 0
suffix: .ftl
template-loader-path: classpath:/templates/
http:
multipart:
maxFileSize: 2048mb
maxRequestSize: 2048mb
redis:
host: 127.0.0.1
password: portal2019
pool:
max-active: 1
max-idle: 8
max-wait: 20000
min-idle: 8
port: 6379
timeout: 20000
servlet:
multipart:
max-file-size: 2048mb
max-request-size: 2048mb
cloud:
nacos:
discovery:
#Nacos 注册中心地址
server-addr: 39.100.254.140:8103
namespace: 68bb4674-3664-4d81-966a-41118dd00905
zwup:
maxSize: 102400
\ No newline at end of file
spring:
profiles:
active: dev
\ No newline at end of file
spring.profiles.active=dev
spring.application.name=loit-file
# Nacos ĵַ
spring.cloud.nacos.config.server-addr=39.100.254.140:8103
spring.cloud.nacos.config.namespace=3ac84119-5558-4bf8-b309-034dd0e458e0
spring.cloud.nacos.config.file-extension=yaml
\ No newline at end of file
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 39.100.254.140:22122
\ No newline at end of file
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 39.100.254.140:22122
\ No newline at end of file
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 39.100.254.140:22122
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form id="form1" method="post" action="http://localhost:7003/api/file/upload" class="form box" enctype="multipart/form-data">
<input type="file" name="file" id="file"/>
<input type="submit" value="weweweewewe">
</form>
</body>
</html>
\ No newline at end of file
/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */
!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=Array.isArray(d)))?(e?(e=!1,f=c&&Array.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e);return!1}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}return!1}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,N,e),g(f,c,O,e)):(f++,j.call(a,g(f,c,N,e),g(f,c,O,e),g(f,c,N,c.notifyWith))):(d!==N&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S),
a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},U=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function V(){this.expando=r.expando+V.uid++}V.uid=1,V.prototype={cache:function(a){var b=a[this.expando];return b||(b={},U(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){Array.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(L)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var W=new V,X=new V,Y=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function $(a){return"true"===a||"false"!==a&&("null"===a?null:a===+a+""?+a:Y.test(a)?JSON.parse(a):a)}function _(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Z,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c=$(c)}catch(e){}X.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return X.hasData(a)||W.hasData(a)},data:function(a,b,c){return X.access(a,b,c)},removeData:function(a,b){X.remove(a,b)},_data:function(a,b,c){return W.access(a,b,c)},_removeData:function(a,b){W.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=X.get(f),1===f.nodeType&&!W.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),_(f,d,e[d])));W.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){X.set(this,a)}):T(this,function(b){var c;if(f&&void 0===b){if(c=X.get(f,a),void 0!==c)return c;if(c=_(f,a),void 0!==c)return c}else this.each(function(){X.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=W.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var aa=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ba=new RegExp("^(?:([+-])=|)("+aa+")([a-z%]*)$","i"),ca=["Top","Right","Bottom","Left"],da=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ea=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function fa(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&ba.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ga={};function ha(a){var b,c=a.ownerDocument,d=a.nodeName,e=ga[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ga[d]=e,e)}function ia(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=W.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&da(d)&&(e[f]=ha(d))):"none"!==c&&(e[f]="none",W.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ia(this,!0)},hide:function(){return ia(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){da(this)?r(this).show():r(this).hide()})}});var ja=/^(?:checkbox|radio)$/i,ka=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c<d;c++)W.set(a[c],"globalEval",!b||W.get(b[c],"globalEval"))}var pa=/<|&#?\w+;/;function qa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(pa.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ka.exec(f)||["",""])[1].toLowerCase(),i=ma[h]||ma._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g,h=[],i=b.delegateCount,j=a.target;if(i&&j.nodeType&&!("click"===a.type&&a.button>=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c<i;c++)d=b[c],e=d.selector+" ",void 0===g[e]&&(g[e]=d.needsContext?r(e,this).index(j)>-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i<b.length&&h.push({elem:j,handlers:b.slice(i)}),h},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==xa()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===xa()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&B(this,"input"))return this.click(),!1},_default:function(a){return B(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?va:wa,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:wa,isPropagationStopped:wa,isImmediatePropagationStopped:wa,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=va,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=va,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=va,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&sa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ta.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return ya(this,a,b,c,d)},one:function(a,b,c,d){return ya(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=wa),this.each(function(){r.event.remove(this,a,c,b)})}});var za=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/<script|<style|<link/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,Ca=/^true\/(.*)/,Da=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}X.hasData(a)&&(h=X.access(a),i=r.extend({},h),X.set(b,i))}}function Ia(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ja.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ja(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,na(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ga),l=0;l<i;l++)j=h[l],la.test(j.type||"")&&!W.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Da,""),k))}return a}function Ka(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(na(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&oa(na(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(za,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d<e;d++)Ia(f[d],g[d]);if(b)if(c)for(f=f||na(a),g=g||na(h),d=0,e=f.length;d<e;d++)Ha(f[d],g[d]);else Ha(a,h);return g=na(h,"script"),g.length>0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(na(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ja(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(na(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var La=/^margin/,Ma=new RegExp("^("+aa+")(?!px)[a-z%]+$","i"),Na=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",ra.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,ra.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Oa(a,b,c){var d,e,f,g,h=a.style;return c=c||Na(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ma.test(g)&&La.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Pa(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Qa=/^(none|table(?!-c[ea]).+)/,Ra=/^--/,Sa={position:"absolute",visibility:"hidden",display:"block"},Ta={letterSpacing:"0",fontWeight:"400"},Ua=["Webkit","Moz","ms"],Va=d.createElement("div").style;function Wa(a){if(a in Va)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ua.length;while(c--)if(a=Ua[c]+b,a in Va)return a}function Xa(a){var b=r.cssProps[a];return b||(b=r.cssProps[a]=Wa(a)||a),b}function Ya(a,b,c){var d=ba.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Za(a,b,c,d,e){var f,g=0;for(f=c===(d?"border":"content")?4:"width"===b?1:0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+ca[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+ca[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+ca[f]+"Width",!0,e))):(g+=r.css(a,"padding"+ca[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+ca[f]+"Width",!0,e)));return g}function $a(a,b,c){var d,e=Na(a),f=Oa(a,b,e),g="border-box"===r.css(a,"boxSizing",!1,e);return Ma.test(f)?f:(d=g&&(o.boxSizingReliable()||f===a.style[b]),"auto"===f&&(f=a["offset"+b[0].toUpperCase()+b.slice(1)]),f=parseFloat(f)||0,f+Za(a,b,c||(g?"border":"content"),d,e)+"px")}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Oa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=Ra.test(b),j=a.style;return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:j[b]:(f=typeof c,"string"===f&&(e=ba.exec(c))&&e[1]&&(c=fa(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(j[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i?j.setProperty(b,c):j[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b),i=Ra.test(b);return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Oa(a,b,d)),"normal"===e&&b in Ta&&(e=Ta[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Qa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?$a(a,b,d):ea(a,Sa,function(){return $a(a,b,d)})},set:function(a,c,d){var e,f=d&&Na(a),g=d&&Za(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=ba.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ya(a,c,g)}}}),r.cssHooks.marginLeft=Pa(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Oa(a,"marginLeft"))||a.getBoundingClientRect().left-ea(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+ca[d]+b]=f[d]||f[d-2]||f[0];return e}},La.test(a)||(r.cssHooks[a+b].set=Ya)}),r.fn.extend({css:function(a,b){return T(this,function(a,b,c){var d,e,f={},g=0;if(Array.isArray(b)){for(d=Na(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&da(a),q=W.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],cb.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=W.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ia([a],!0),j=a.style.display||j,k=r.css(a,"display"),ia([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=W.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ia([a],!0),m.done(function(){p||ia([a]),W.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=hb(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],Array.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=kb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=ab||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(i||h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:ab||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);f<g;f++)if(d=kb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,hb,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j}r.Animation=r.extend(kb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return fa(c.elem,a,ba.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(L);for(var c,d=0,e=a.length;d<e;d++)c=a[d],kb.tweeners[c]=kb.tweeners[c]||[],kb.tweeners[c].unshift(b)},prefilters:[ib],prefilter:function(a,b){b?kb.prefilters.unshift(a):kb.prefilters.push(a)}}),r.speed=function(a,b,c){var d=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off?d.duration=0:"number"!=typeof d.duration&&(d.duration in r.fx.speeds?d.duration=r.fx.speeds[d.duration]:d.duration=r.fx.speeds._default),null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){r.isFunction(d.old)&&d.old.call(this),d.queue&&r.dequeue(this,d.queue)},d},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(da).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=kb(this,r.extend({},a),f);(e||W.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=W.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&db.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=W.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),r.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(ab=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),ab=void 0},r.fx.timer=function(a){r.timers.push(a),r.fx.start()},r.fx.interval=13,r.fx.start=function(){bb||(bb=!0,eb())},r.fx.stop=function(){bb=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var lb,mb=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),
null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d<i;d++)if(c=e[d],(c.selected||d===f)&&!c.disabled&&(!c.parentNode.disabled||!B(c.parentNode,"optgroup"))){if(b=r(c).val(),g)return b;h.push(b)}return h},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Tb=[],Ub=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Tb.pop()||r.expando+"_"+ub++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Ub.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ub.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Ub,"$1"+e):b.jsonp!==!1&&(b.url+=(vb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Tb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=C.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=qa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=pb(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length},r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),b=f.ownerDocument,c=b.documentElement,e=b.defaultView,{top:d.top+e.pageYOffset-c.clientTop,left:d.left+e.pageXOffset-c.clientLeft}):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),B(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||ra})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return T(this,function(a,d,e){var f;return r.isWindow(a)?f=a:9===a.nodeType&&(f=a.defaultView),void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Pa(o.pixelPosition,function(a,c){if(c)return c=Oa(a,b),Ma.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return T(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.holdReady=function(a){a?r.readyWait++:r.ready(!0)},r.isArray=Array.isArray,r.parseJSON=JSON.parse,r.nodeName=B,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Vb=a.jQuery,Wb=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Wb),b&&a.jQuery===r&&(a.jQuery=Vb),r},b||(a.jQuery=a.$=r),r});
/*! layer-v3.1.1 Web弹层组件 MIT License http://layer.layui.com/ By 贤心 */
;!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if("interactive"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["&#x786E;&#x5B9A;","&#x53D6;&#x6D88;"],type:["dialog","page","iframe","loading","tips"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName("head")[0],s=document.createElement("link");"string"==typeof i&&(n=i);var l=(n||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),"function"==typeof i&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(o.getStyle(document.getElementById(f),"width"))?i():setTimeout(u,100))}()}}},r={v:"3.1.1",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):o.link("theme/"+e.extend),this):this},ready:function(e){var t="layer",i="",n=(a?"modules/layer/":"theme/")+"default/layer.css?v="+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim-00","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"&#x4FE1;&#x606F;",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'<div class="layui-layer-title" style="'+(f?r.title[1]:"")+'">'+(f?r.title[0]:r.title)+"</div>":"";return r.zIndex=s,t([r.shade?'<div class="layui-layer-shade" id="layui-layer-shade'+a+'" times="'+a+'" style="'+("z-index:"+(s-1)+"; ")+'"></div>':"",'<div class="'+l[0]+(" layui-layer-"+o.type[r.type])+(0!=r.type&&2!=r.type||r.shade?"":" layui-layer-border")+" "+(r.skin||"")+'" id="'+l[0]+a+'" type="'+o.type[r.type]+'" times="'+a+'" showtime="'+r.time+'" conType="'+(e?"object":"string")+'" style="z-index: '+s+"; width:"+r.area[0]+";height:"+r.area[1]+(r.fixed?"":";position:absolute;")+'">'+(e&&2!=r.type?"":u)+'<div id="'+(r.id||"")+'" class="layui-layer-content'+(0==r.type&&r.icon!==-1?" layui-layer-padding":"")+(3==r.type?" layui-layer-loading"+r.icon:"")+'">'+(0==r.type&&r.icon!==-1?'<i class="layui-layer-ico layui-layer-ico'+r.icon+'"></i>':"")+(1==r.type&&e?"":r.content||"")+'</div><span class="layui-layer-setwin">'+function(){var e=c?'<a class="layui-layer-min" href="javascript:;"><cite></cite></a><a class="layui-layer-ico layui-layer-max" href="javascript:;"></a>':"";return r.closeBtn&&(e+='<a class="layui-layer-ico '+l[7]+" "+l[7]+(r.title?r.closeBtn:4==r.type?"1":"2")+'" href="javascript:;"></a>'),e}()+"</span>"+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t<i;t++)e+='<a class="'+l[6]+t+'">'+r.btn[t]+"</a>";return'<div class="'+l[6]+" layui-layer-btn-"+(r.btnAlign||"")+'">'+e+"</div>"}():"")+(r.resize?'<span class="layui-layer-resize"></span>':"")+"</div>"],u,i('<div class="layui-layer-move"></div>')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"http://layer.layui.com","auto"];t.content='<iframe scrolling="'+(t.content[1]||"auto")+'" allowtransparency="true" id="'+l[4]+a+'" name="'+l[4]+a+'" onload="this.className=\'\';" class="layui-layer-load" frameborder="0" src="'+t.content[0]+'"></iframe>';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'<i class="layui-layer-TipsG"></i>',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),i("#layui-layer-shade"+e.index).css({"background-color":t.shade[1]||"#000",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u="layer-anim "+l.anim[t.anim];e.layero.addClass(u).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i("#"+l[0]+e);""===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find("."+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css("padding-top"))))};switch(a.type){case 2:u("iframe");break;default:""===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u("."+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u("."+l[5])):u("."+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;a<c.stX&&(a=c.stX),a>f&&(a=f),o<c.stY&&(o=c.stY),o>u&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass("layer-anim "+a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'<textarea class="layui-layer-input"'+a+">"+(e.value||"")+"</textarea>":function(){return'<input type="'+(1==e.formType?"password":"text")+'" class="layui-layer-input" value="'+(e.value||"")+'">'}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["&#x786E;&#x5B9A;","&#x53D6;&#x6D88;"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(e){s=e.find(".layui-layer-input"),s.focus(),"function"==typeof f&&f(e)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("&#x6700;&#x591A;&#x8F93;&#x5165;"+(e.maxlength||500)+"&#x4E2A;&#x5B57;&#x6570;",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n="layui-this",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,a="";if(e>0)for(a='<span class="'+n+'">'+t[0].title+"</span>";i<e;i++)a+="<span>"+t[i].title+"</span>";return a}(),content:'<ul class="layui-layer-tabmain">'+function(){var e=t.length,i=1,a="";if(e>0)for(a='<li class="layui-layer-tabli '+n+'">'+(t[0].content||"no content")+"</li>";i<e;i++)a+='<li class="layui-layer-tabli">'+(t[i].content||"no content")+"</li>";return a}()+"</ul>",success:function(t){var o=t.find(".layui-layer-title").children(),r=t.find(".layui-layer-tabmain").children();o.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),"function"==typeof e.change&&e.change(o)}),"function"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("&#x6CA1;&#x6709;&#x56FE;&#x7247;")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]<r[1]&&(a[0]=a[0]/r[1],a[1]=a[1]/r[1])}return[a[0]+"px",a[1]+"px"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:".layui-layer-phimg img",moveType:1,scrollbar:!1,moveOut:!0,isOutAnim:!1,skin:"layui-layer-photos"+c("photos"),content:'<div class="layui-layer-phimg"><img src="'+u[d].src+'" alt="'+(u[d].alt||"")+'" layer-pid="'+u[d].pid+'"><div class="layui-layer-imgsee">'+(u.length>1?'<span class="layui-layer-imguide"><a href="javascript:;" class="layui-layer-iconext layui-layer-imgprev"></a><a href="javascript:;" class="layui-layer-iconext layui-layer-imgnext"></a></span>':"")+'<div class="layui-layer-imgbar" style="display:'+(a?"block":"")+'"><span class="layui-layer-imgtit"><a href="javascript:;">'+(u[d].alt||"")+"</a><em>"+s.imgIndex+"/"+u.length+"</em></span></div></div></div>",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;",{time:3e4,btn:["&#x4E0B;&#x4E00;&#x5F20;","&#x4E0D;&#x770B;&#x4E86;"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window);
\ No newline at end of file
/*! layer mobile-v2.0.0 Web弹层组件 MIT License http://layer.layui.com/mobile By 贤心 */
;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'<h3 style="'+(e?n.title[1]:"")+'">'+(e?n.title[0]:n.title)+"</h3>":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e='<span yes type="1">'+n.btn[0]+"</span>",2===t&&(e='<span no type="0">'+n.btn[1]+"</span>"+e),'<div class="layui-m-layerbtn">'+e+"</div>"):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='<i></i><i class="layui-m-layerload"></i><i></i><p>'+(n.content||"")+"</p>"),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"<div "+("string"==typeof n.shade?'style="'+n.shade+'"':"")+' class="layui-m-layershade"></div>':"")+'<div class="layui-m-layermain" '+(n.fixed?"":'style="position:static;"')+'><div class="layui-m-layersection"><div class="layui-m-layerchild '+(n.skin?"layui-m-layer-"+n.skin+" ":"")+(n.className?n.className:"")+" "+(n.anim?"layui-m-anim-"+n.anim:"")+'" '+(n.style?'style="'+n.style+'"':"")+">"+l+'<div class="layui-m-layercont">'+n.content+"</div>"+c+"</div></div></div>",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;o<r;o++)l.touch(s[o],a);if(e.shade&&e.shadeClose){var c=t[i]("layui-m-layershade")[0];l.touch(c,function(){layer.close(n.index,e.end)})}e.end&&(l.end[n.index]=e.end)},e.layer={v:"2.0",index:r,open:function(e){var t=new c(e||{});return t.index},close:function(e){var n=a("#"+o[0]+e)[0];n&&(n.innerHTML="",t.body.removeChild(n),clearTimeout(l.timer[e]),delete l.timer[e],"function"==typeof l.end[e]&&l.end[e](),delete l.end[e])},closeAll:function(){for(var e=t[i](o[0]),n=0,a=e.length;n<a;n++)layer.close(0|e[0].getAttribute("index"))}},"function"==typeof define?define(function(){return layer}):function(){var e=document.scripts,n=e[e.length-1],i=n.src,a=i.substring(0,i.lastIndexOf("/")+1);n.getAttribute("merge")||document.head.appendChild(function(){var e=t.createElement("link");return e.href=a+"need/layer.css?2.0",e.type="text/css",e.rel="styleSheet",e.id="layermcss",e}())}()}(window);
\ No newline at end of file
.layui-m-layer{position:relative;z-index:19891014}.layui-m-layer *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.layui-m-layermain,.layui-m-layershade{position:fixed;left:0;top:0;width:100%;height:100%}.layui-m-layershade{background-color:rgba(0,0,0,.7);pointer-events:auto}.layui-m-layermain{display:table;font-family:Helvetica,arial,sans-serif;pointer-events:none}.layui-m-layermain .layui-m-layersection{display:table-cell;vertical-align:middle;text-align:center}.layui-m-layerchild{position:relative;display:inline-block;text-align:left;background-color:#fff;font-size:14px;border-radius:5px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;-webkit-overflow-scrolling:touch;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@-webkit-keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.layui-m-anim-scale{animation-name:layui-m-anim-scale;-webkit-animation-name:layui-m-anim-scale}@-webkit-keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.layui-m-anim-up{-webkit-animation-name:layui-m-anim-up;animation-name:layui-m-anim-up}.layui-m-layer0 .layui-m-layerchild{width:90%;max-width:640px}.layui-m-layer1 .layui-m-layerchild{border:none;border-radius:0}.layui-m-layer2 .layui-m-layerchild{width:auto;max-width:260px;min-width:40px;border:none;background:0 0;box-shadow:none;color:#fff}.layui-m-layerchild h3{padding:0 10px;height:60px;line-height:60px;font-size:16px;font-weight:400;border-radius:5px 5px 0 0;text-align:center}.layui-m-layerbtn span,.layui-m-layerchild h3{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-m-layercont{padding:50px 30px;line-height:22px;text-align:center}.layui-m-layer1 .layui-m-layercont{padding:0;text-align:left}.layui-m-layer2 .layui-m-layercont{text-align:center;padding:0;line-height:0}.layui-m-layer2 .layui-m-layercont i{width:25px;height:25px;margin-left:8px;display:inline-block;background-color:#fff;border-radius:100%;-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;animation:layui-m-anim-loading 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-m-layerbtn,.layui-m-layerbtn span{position:relative;text-align:center;border-radius:0 0 5px 5px}.layui-m-layer2 .layui-m-layercont p{margin-top:20px}@-webkit-keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0;-webkit-animation-delay:-.32s;animation-delay:-.32s}.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay:-.16s;animation-delay:-.16s}.layui-m-layer2 .layui-m-layercont>div{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px}
\ No newline at end of file
.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:230px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:43px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}}
\ No newline at end of file
.webuploader-container {
position: relative;
}
.webuploader-element-invisible {
position: absolute !important;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px,1px,1px,1px);
}
.webuploader-pick {
position: relative;
display: inline-block;
cursor: pointer;
background: #00b7ee;
padding: 10px 15px;
color: #fff;
text-align: center;
border-radius: 3px;
overflow: hidden;
}
.webuploader-pick-hover {
background: #00a2d4;
}
.webuploader-pick-disable {
opacity: 0.6;
pointer-events:none;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
window.ZWUP = window.ZWUP || {};
ZWUP.basePath =getBaseUrl();
ZWUP.flashPath = ZWUP.basePath + "/api-file/script/Uploader.swf";
ZWUP.configUrl = ZWUP.basePath + "/api-file/api/chunkfile/config";
ZWUP.fileServerUrl = ZWUP.fileServerUrl || null;
ZWUP.isServerConfigLoaded = false;
ZWUP.maxSize = 1024 * 1024 * 100;
//uploadMap实例
var uploadMap=new myMap();
//线上文件块记录
var chunkMap=new myMap();
(function ($) {
$.fn.extend({
'zwUploader': function (option, args, fire) {
var items = this.each(function () {
console.log('插件this:',this);
if ($.isPlainObject(option))
this.controller = new Controller(this, option);
});
return items;
}
});
WebUploader.Uploader.register({
"before-send-file": "beforeSendFile"
, "before-send": "beforeSend"
}, {
beforeSendFile: function(file){
var fileName = file.name;
var fileSize = file.size;
var file_ruid=file.id;
var that=this.owner.controller;
console.log(file);
//秒传验证
var task = new $.Deferred();
(new WebUploader.Uploader()).md5File(file, 0, 10*1024*1024).progress(function(percentage){
}).then(function(val){
fileMd5 = val;
var url = that.option.baseUrlString + that.option.checkUrl;
var data = {
type: 0,
fileName: fileName,
fileMd5: fileMd5,
fileSize: fileSize
};
$.ajax({
type: "POST",
url: url,
data: data,
cache: false,
async: false, // 同步
dataType: "json",
error: function(XMLHttpRequest, textStatus, errorThrown) {
file.statusText = '服务器错误';
task.reject();
var up_self=uploadMap.get(file.source.rid);
}
}).then(function(data, textStatus, jqXHR) {
if(data.code == 0) {
if(data.data&&data.data.totalSize>0){
file.statusText = '该文件已上传过';
setProStyle(file,1);
var up_self=uploadMap.get(that.option.uploaderId);
up_self.skipFile(file);
file.viewPath=data.data.viewPath;
task.resolve()
return
}
if(!(data.data.chunkCurr>=0)){
file.statusText = '无法获取当前文件块';
task.reject();
return
}
chunkMap.put(file_ruid,{fileMd5:fileMd5,chunkCurr:data.data.chunkCurr});
task.resolve();
} else {
if(data&&data.msg){
alert(data.msg)
}else {
alert('服务器异常')
}
task.reject();
}
});
console.log('beforeSendFile:'+val)
//task.resolve();
});
return $.when(task);
}
, beforeSend: function(block){
// var that=this.owner.controller;
var task = new $.Deferred();
var ruid=block.file.id;
var chunkCurr=chunkMap.get(ruid).chunkCurr;
if(block.chunk<chunkCurr){
//console.log(block)
task.reject();
}else {
console.log("第"+block.chunk+"块开始上传")
task.resolve();
}
return $.when(task);
}
,
});
var Controller = function (input, option) {
console.log('插件input:',this);
var flashPath = ZWUP.flashPath;
var fileName = $(input).attr('data-ZW-upload-name') || "file";
var previewNames = $(input).attr('data-ZW-upload-preview') || "";
var perviewFileNames = $(input).attr('data-ZW-upload-preview-names') || "";
this.defaultAccept = {
title:'支持的文件类型',
extensions: 'jpg,jpeg,png,gif,bmp,doc,docx,pdf,xls,xlsx,ppt,pptx,zip,rar',
mimeTypes: 'image/jpg,image/jpeg,image/png,image/gif,image/bmp,application/msword,' +
'application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf,' +
'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,' +
'application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/x-zip-compressed,application/x-rar-compressed'
};
this.input = input;
this.option = $.extend(false, {
// url
'baseUrlString': ZWUP.basePath, // string
'checkUrl': getBaseUrl()+'/api-file/api/chunkfile/checkFile', // string
'uploadUrl': getBaseUrl()+'/api-file/api/chunkfile/chunkUpload', // string
'flashPath': flashPath, // string
// data
'accept': this.defaultAccept, // function
'fileName': fileName, // string
'previewNames': previewNames.split(","), // string
'perviewFileNames': perviewFileNames.split(","),// string
'minItems': 1, // number
'maxItems': 20, // number
'uploadFinishedHandler': null, // function 上传文件完成回调
}, option);
if (!ZWUP.isServerConfigLoaded) {
var that = this;
_loadServerConfig(function () {
_setup.apply(that, [input]);
}, that);
} else {
_setup.apply(this, [input]);
}
};
//设置进度条样式
var setProStyle=function (file,percentage) {
var progressVal = Math.min(toDecimal(percentage * 100,2), 100);
var item=$('#item_'+file.id);
var progressView=item.find('.upload-progress_bg');
progressView.width(progressVal+'%');
var progressText=item.find('.percent');
progressText.text(progressVal);
if(percentage>=1){
var upload_state=item.find('.upload_state');
file.statusText='上传成功@'
var delBtn=item.find('.ZW-upload-blank-delete');
delBtn.show();
}
}
var _loadServerConfig = function (callback, controller) {
var configUrl = ZWUP.configUrl;
var that = this;
$.ajax(configUrl, {
async:false,
'type': 'get',
'success': function (r) {
config=JSON.parse(r);
ZWUP.fileServerUrl = config.fileServerUrl || ZWUP.fileServerUrl;
ZWUP.isServerConfigLoaded = true;
ZWUP.maxSize = config.maxSize || ZWUP.maxSize;
callback();
},
'error': function () {
console.log('获取配置失败!');
}
});
};
// ------- Private Method Here -------------
var _setup = function (input) {
var that = this;
var $input = $(input);
var uploaderId = "file_" + new Date().getTime() + "_" + parseInt(Math.random() * 1000, 10);
that.option.uploaderId = uploaderId;
var $uploadContentView = that.option.createUploadBtn(that, uploaderId);
$input.append($uploadContentView);
var _uploader = this.uploader("#" + uploaderId);
_uploader.controller = that;
uploadMap.put(uploaderId,_uploader);
// 当有文件被添加进队列的时候
_uploader.on( 'fileQueued', function( file ) {
_appendFile.apply(that,['', file]);
// this.upload();
});
_uploader.on( 'beforeFileQueued', function( file ) {
var controller = _uploader.controller;
if (controller.option.isAllowAddFile){
return controller.option.isAllowAddFile(controller);
}
return true;
});
_uploader.on( 'uploadBeforeSend', function( block, data ) {
data.fileMd5 = chunkMap.get(block.file.id).fileMd5;
data.chunkSize=block.blob.size;
});
_uploader.on( 'uploadStart', function( file ) {
var item=$('#item_'+file.id);
item.find('.upload_state').text('开始上传');
item.find('.re_upload').hide();
// progressView.show();
});
// 文件上传过程中创建进度条实时显示。
_uploader.on( 'uploadProgress', function( file, percentage ) {
setProStyle(file,percentage);
});
_uploader.on('uploadAccept', function (file, response) {
console.log("uploadAccept-response:", response._raw)
var result
try
{
result= JSON.parse(response._raw)
if(result.code==1){
file.file.statusText=result.msg;
file.file.viewPath='';
}else {
file.file.viewPath=result.data
return true
}
}
catch(err)
{
console.log(err)
return false
}
return false
});
_uploader.on( 'uploadError', function( file ) {
var item=$('#item_'+file.id);
item.find('.upload_state').text('上传出错:'+file.statusText);
item.find('.re_upload').show();
console.log('上传error:'+file.statusText)
});
_uploader.on('uploadSuccess', function(file ,resp){
console.log('uploadSuccess:',file,resp)
var item=$('#item_'+file.id);
item.find('.upload_state').text(file.statusText);
//经过传输的file,即时在uploadAccept绑定viewPath,这里也接收不到
item.find('.item_file_url').val(file.viewPath||resp.data||'');
item.find('.zw-upload-blank-view').show();
if( this.controller.option.uploadFinishedHandler){
this.controller.option.uploadFinishedHandler(item);
}
});
_uploader.on( 'uploadComplete', function( file ) {
console.log('uploadComplete')
});
};
var _appendFile = function (fileUrl, file) {
// var fileId = "file_" + new Date().getTime() + "_" + parseInt(Math.random() * 1000, 10);
var fileId=file.id;
console.log("fileIdxxx:"+fileId);
var fileName = this.option.fileName;
var contentView = $(this.input);
var fileUrlWithHost = ZWUP.fileServerUrl + fileUrl;
file.url = fileUrl;
var $item = this.option.createUploadItem(this, contentView, fileId, fileName, fileUrlWithHost, file);
};
var _error = function (msg) {
if ($.isFunction(this.option.onerror)) {
this.option.onerror.apply(this, [msg]);
}
};
Controller.prototype.uploader = function (pick) {
var accept =this.option.accept()||this.defaultAccept;
var runtimeOrder = this.option.runtimeOrder;
var flashPath = this.option.flashPath;
var uploadURLString = this.option.baseUrlString + this.option.uploadUrl;
return WebUploader.create({
swf: flashPath,
pick: pick,
server: uploadURLString,
accept: accept,
runtimeOrder: runtimeOrder,
resize: false,
compress: false,
auto:true,
chunkSize: 1024 * 1024*10, //产品正式上线后尽量不要修改次参数,否则会影响所有上传,
chunked: true,
threads:1,
// auto: true,
});
};
})(jQuery);
////////////////////////////////////////////////////////////////工具类//////////////////////////////////////////////
//保留两位小数
//功能:将浮点数四舍五入,取小数点后n位
//http://www.cnblogs.com/hongchenok/archive/2011/11/02/2232810.html
function toDecimal(x, n) {
var num = arguments[1] ? arguments[1] : 2;
n=num;
var f = parseFloat(x);
function getN(n){
var sum =1;
for (var i=0 ;i< n;i++){
sum*=10;
}
return sum ;
}
if (isNaN(f)) {
return 0;
}
f = Math.round(x * getN(n)) / getN(n);
return f;
}
//map方法定义
function myMap() {
this.elements = new Array();
//获取MAP元素个数
this.size = function() {
return this.elements.length;
}
//判断MAP是否为空
this.isEmpty = function() {
return(this.elements.length < 1);
}
//删除MAP所有元素
this.clear = function() {
this.elements = new Array();
}
//向MAP中增加元素(key, value)
this.put = function(_key, _value) {
var exist=this.containsKey(_key);
if(exist){
this.remove(_key);
}
this.elements.push({
key: _key,
value: _value
});
}
//删除指定KEY的元素,成功返回True,失败返回False
this.remove = function(_key) {
var bln = false;
try {
for(i = 0; i < this.elements.length; i++) {
if(this.elements[i].key == _key) {
this.elements.splice(i, 1);
return true;
}
}
} catch(e) {
bln = false;
}
return bln;
}
//获取指定KEY的元素值VALUE,失败返回NULL
this.get = function(_key) {
try {
for(i = 0; i < this.elements.length; i++) {
if(this.elements[i].key == _key) {
return this.elements[i].value;
}
}
} catch(e) {
return null;
}
}
//获取指定索引的元素(使用element.key,element.value获取KEY和VALUE),失败返回NULL
this.element = function(_index) {
if(_index < 0 || _index >= this.elements.length) {
return null;
}
return this.elements[_index];
}
//判断MAP中是否含有指定KEY的元素
this.containsKey = function(_key) {
var bln = false;
try {
for(i = 0; i < this.elements.length; i++) {
if(this.elements[i].key == _key) {
bln = true;
}
}
} catch(e) {
bln = false;
}
return bln;
}
//判断MAP中是否含有指定VALUE的元素
this.containsValue = function(_value) {
var bln = false;
try {
for(i = 0; i < this.elements.length; i++) {
if(this.elements[i].value == _value) {
bln = true;
}
}
} catch(e) {
bln = false;
}
return bln;
}
//获取MAP中所有VALUE的数组(ARRAY)
this.values = function() {
var arr = new Array();
for(i = 0; i < this.elements.length; i++) {
arr.push(this.elements[i].value);
}
return arr;
}
//获取MAP中所有KEY的数组(ARRAY)
this.keys = function() {
var arr = new Array();
for(i = 0; i < this.elements.length; i++) {
arr.push(this.elements[i].key);
}
return arr;
}
}
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form id="form1" method="post" action="http://192.168.40.64:7002/upload/chunkUpload/upload_do" class="form box" enctype="multipart/form-data">
<input type="file" name="file" id="file"/>
<input type="submit" value="weweweewewe">
</form>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body style="background: #f0f0f0">
<div style="margin: 0 auto;width: 300px">
<div>
<span>用户名:</span>
<input id="name" type="text">
</div>
<div style="margin-top: 20px">
<span>密码:</span>
<input id="password" type="text" style="margin-left: 15px">
</div>
<div style="margin-top: 20px">
<button type="button" id="dl">登陆</button>
</div>
</div>
</body>
</html>
<script src="http://localhost:7002/api-file/js/jquery-3.2.1.min.js"></script>
<script>
$('#dl').click(function () {
$.post('http://localhost:7002/api-file/login/doLogin',{name:$('#name').val(),password:$('#password').val()},function (data) {
if(data.code==1){
alert(data.msg)
}else if (data.code==0){
location.href='http://localhost:7002/api-file/upload/Manage/upload_list'
}
})
})
</script>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传</title>
</head>
<body style="background: #f0f0f0">
<div style="margin: 0 auto;width: 1000px">
<div style="" class="adhust_upload" id="user_other_documents" data-zw-upload-name="user_other_documents"
data-zw-upload-preview=""
data-zw-upload-preview-names="">
</div>
</div>
</body>
</html>
<script src="http://localhost:7002/api-file/js/jquery-3.2.1.min.js"></script>
<#include "./upload_common.ftl" />
<div>
</div>
<script>
//上传
$("#user_other_documents").zwUploader({
accept: zwblankuploader_accept, //可以上传文件类型,一般用组件默认即可
createUploadBtn: zwblankuploader_createUploadBtn,
createUploadItem: zwblankuploader_createUploadItem,
uploadFinishedHandler:function (item) {
console.log('上传服务器路径:',item.find('.item_file_url').val())
}
});
</script>
\ No newline at end of file
<#assign base=request.contextPath />
<base href="${base}">
<script>
localStorage.setItem('basePath', '${base}');
function getBaseUrl() {
return '${base}'
}
</script>
<#assign base=request.contextPath />
<base href="${base}">
<script>
localStorage.setItem('basePath', '${base}');
function getBaseUrl() {
return '${base}'
}
</script>
<link rel="stylesheet" href="http://localhost:7002/api-file/js/zwUploader/webuploader.css">
<script src="http://localhost:7002/api-file/js/zwUploader/webuploader.nolog.js"></script>
<script src="http://localhost:7002/api-file/js/zwUploader/zwUploader.js"></script>
<#--<script src="http://localhost:7002/api-file/assets/plugins/zwUplozwUploaderader/zwUploader.js"></script>-->
<style>
.zw-document-uploader{position: relative; cursor: pointer;margin-top: 8px;}
.zw-document-uploader.zw-hidden{display: hidden;}
.zw-document-uploader.zw-ib{display: inline-block;}
.zw-document-uploader-item .zw-upload-blank-index{}
.zw-document-uploader-item .zw-upload-blank-view{color: deepskyblue;cursor:pointer;margin-left: 10px}
.zw-document-uploader-item .zw-upload-blank-file{margin: 4px 24px 4px 0;display: inline-block;}
.zw-document-uploader-item .zw-upload-blank-delete{color: red;cursor:pointer;margin-left: 5px}
.upload-progress-box{
display: inline-block;
font-size: 16px;
}
.upload-progress-box .upload-progress{
display: inline-block;
width: 150px;
height: 15px;
border: 1px solid #000;
margin-left: 10px;
position: relative;
top: 3px;
}
.upload-progress-box .upload-progress_bg{
background:rgba(3, 9, 162, 0.78);
width: 0%;
height: 100%;
display: inline-block;
position: absolute;
}
</style>
<script>
function zwblankuploader_accept(){
return false;
}
function zwblankuploader_createUploadBtn(controller, btnId) {
var hideCss = controller.option.isReadonly ? 'zw-hidden' : 'zw-ib';
var $btn = $("<div id='fileList_" + btnId + "' class='fileList' style=''></div><div id='" + btnId + "' class='zw-document-uploader "+hideCss+"' >点击上传附件 " + "</div>");
return $btn;
}
function zwblankuploader_createUploadItem(controller, contentView, fileId, fileName, fileUrlWithHost, file) {
var itemSize = contentView.find(".zw-upload-item").length
var itemIndex = itemSize + 1;
var indexItemString = "<span class='zw-upload-blank-index'>" + itemIndex + "、 " + "</span>";
var delItemString = controller.option.isReadonly ? '' : "<a fileId="+file.id+" data-id='" + fileId + "' class='zw-upload-blank-delete' >删除</a>";
var $item = $("<div id='item_" + fileId + "' class='zw-upload-item zw-document-uploader-item'>" +
"<div class='zw-upload-blank-file'>" + indexItemString + file.name + "</div>" +
"<input type='hidden' name='"+ fileName +"' class='item_file_url'>"+
"<div class='upload-progress-box'><span class='upload-progress'><span class='upload-progress_bg'></span></span> <span class='percent'>0</span><span>%</span> </div>"+
delItemString +
"<span class='upload_state' style='margin-left: 10px'>等待上传</span>"+
"<a class=re_upload style='margin-left: 10px;display: none'>重新上传</a>"+
"<a data-id='" + fileId + "' class='zw-upload-blank-view' style='display: none' >查看</a>" +
"</div>");
contentView.children(".fileList").append($item);
return $item;
}
$(document).on('click','.zw-upload-blank-delete',function () {
var uplodId=$(this).parents('.adhust_upload').get(0).controller.option.uploaderId;
var upload=uploadMap.get(uplodId);
upload.removeFile($(this).attr('fileId'),true);
var item= $(this).parents('.zw-document-uploader-item');
var itemParent=item.parent();
item.remove();
itemParent.children(".zw-upload-item").each(function (index) {
$(this).find(".zw-upload-blank-index").text( (index + 1 ) + "、 ");
});
});
$(document).on('click','.zw-upload-blank-view',function () {
var openurl=$(this).parents('.zw-document-uploader-item').find('.item_file_url').val();
window.open(ZWUP.fileServerUrl+openurl);
})
$(document).on('click','.re_upload',function () {
var uplodId=$(this).parents('.adhust_upload').get(0).controller.option.uploaderId;
var upload=uploadMap.get(uplodId);
upload.retry();
});
//修复当上传需要隐藏时,无法出现文件弹出框问题
$(document).on('click','.webuploader-pick',function () {
$(this).parent().find('.webuploader-element-invisible').click();
})
</script>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传管理</title>
</head>
<style>
table.hovertable {
width: 100%;
font-family: verdana,arial,sans-serif;
font-size:11px;
color:#333333;
border-width: 1px;
border-color: #999999;
border-collapse: collapse;
}
table.hovertable th {
background-color:#c3dde0;
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #a9c6c9;
}
table.hovertable tr {
background-color:#d4e3e5;
}
table.hovertable td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #a9c6c9;
}
<!-- Table goes in the document BODY -->
</style>
<body style="background: #f0f0f0">
<div id="contentBox" style="margin: 20px auto;width: 80%;">
<div >
<button id="go_login">去上传页面</button>
</div>
<div>
<div style="margin-top: 20px">当前数据库所有上传成功文件:</div>
<table class="hovertable">
<tr>
<th>序号</td>
<th>文件名</td>
<th>上传路径</td>
<th>md5</td>
<th>大小</td>
<th>操作</td>
</tr>
<#list fileList as e>
<tr>
<td>${e_index}</td>
<td>${e.name}</td>
<td>${e.url}</td>
<td>${e.md5}</td>
<td>${(e.lenght/1024)?string('#.##')}KB</td>
<td>
<a target="_blank" href="${fileServerUrl}/${e.url}">查看</a>
<a class="del" style="margin-left: 10px" md5="${e.md5}">删除</a>
</td>
</tr>
</#list>
</table>
</div>
</div>
</body>
</html>
<script src="http://localhost:7002/api-file/js/jquery-3.2.1.min.js"></script>
<script src="http://localhost:7002/api-file/js/layer/layer.js"></script>
<script>
$('.del').click(function () {
var self=$(this);
//询问框
layer.confirm('确定要删除吗', {
}, function(){
$.post('/upload/Manage/del',{md5:self.attr('md5')},function (data) {
if (data.code==0){
location.reload();
}else {
alert(data.msg)
}
})
});
})
$('#go_login').click(function () {
window.open('http://localhost:7002/api-file/upload/Manage/toUpload');
})
</script>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>loit-service</artifactId>
<groupId>com.loit</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>loit-notice</artifactId>
</project>
\ No newline at end of file
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
<version>1.0.0</version> <version>1.0.0</version>
<modules> <modules>
<module>loit-portal</module> <module>loit-portal</module>
<module>loit-file</module>
<module>loit-notice</module>
</modules> </modules>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>loit-service</name> <name>loit-service</name>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论