diff --git a/.gitignore b/.gitignore index 6143e53f9..1dcd5ec12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,41 @@ -# Compiled class file -*.class +target/ +!.mvn/wrapper/maven-wrapper.jar -# Log file -*.log +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans -# BlueJ files -*.ctxt +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr -# Mobile Tools for Java (J2ME) -.mtj.tmp/ +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ +/*.iml -# Package Files # -*.jar -*.war -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* +**/target/ +.classpath +.project +**/.settings +**/bin/ +**/build/ +**/.externalToolBuilders/ +*.iml +**/.idea/ +**/disconf +**/rpc.properties +/producer/tmp +/.temfile +.temfile +convertedFile/ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..9e84fb407 --- /dev/null +++ b/pom.xml @@ -0,0 +1,172 @@ + + + 4.0.0 + + com.yudianbank + filepreview + 0.0.1-SNAPSHOT + jar + + file-online-preview + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.8.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 1.0-SNAPSHOT + ${basedir}/target/classes/logs + file-preview + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + org.springframework.boot + spring-boot-starter-web + + + + com.ctrip.framework.apollo + apollo-client + 0.8.0 + + + net.logstash.logback + logstash-logback-encoder + 4.11 + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.redisson + redisson + 3.2.0 + + + org.apache.poi + poi + 3.12 + + + org.apache.poi + poi-scratchpad + 3.12 + + + fr.opensagres.xdocreport + org.apache.poi.xwpf.converter.core + 1.0.5 + + + poi + org.apache.poi + + + + + fr.opensagres.xdocreport + org.apache.poi.xwpf.converter.xhtml + 1.0.5 + + + fr.opensagres.xdocreport + fr.opensagres.xdocreport.document + 1.0.5 + + + commons-io + commons-io + 2.4 + + + + org.apache.commons + commons-compress + 1.9 + + + + com.github.junrar + junrar + 0.7 + + + net.sourceforge.jchardet + jchardet + 1.0 + + + antlr + antlr + 2.7.7 + + + commons-httpclient + commons-httpclient + 3.1 + test + + + commons-logging + commons-logging + + + + + org.artofsolving.jodconverter + jodconverter-core + 3.0-SNAPSHOT + + + commons-io + commons-io + + + + + commons-cli + commons-cli + 1.2 + + + com.thoughtworks.xstream + xstream + 1.3.1 + + + + + + ${basedir}/src/main/resources + + **/* + + true + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/src/main/java/com/yudianbank/FilePreviewApplication.java b/src/main/java/com/yudianbank/FilePreviewApplication.java new file mode 100644 index 000000000..7fb84035e --- /dev/null +++ b/src/main/java/com/yudianbank/FilePreviewApplication.java @@ -0,0 +1,23 @@ +package com.yudianbank; + +import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.PropertySource; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.Enumeration; +import java.util.Properties; + +@SpringBootApplication +@EnableScheduling +@ComponentScan(value = "com.yudianbank.*") +//@EnableApolloConfig +public class FilePreviewApplication { + public static void main(String[] args) { + Properties properties = System.getProperties(); + System.out.println(properties.get("user.dir")); + SpringApplication.run(FilePreviewApplication.class, args); + } +} diff --git a/src/main/java/com/yudianbank/config/RedissonConfig.java b/src/main/java/com/yudianbank/config/RedissonConfig.java new file mode 100644 index 000000000..071b74632 --- /dev/null +++ b/src/main/java/com/yudianbank/config/RedissonConfig.java @@ -0,0 +1,242 @@ +package com.yudianbank.config; + +import io.netty.channel.nio.NioEventLoopGroup; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.Codec; +import org.redisson.config.Config; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.ClassUtils; + +/** + * Created by kl on 2017/09/26. + * redisson 客户端配置 + */ +@ConfigurationProperties(prefix = "spring.redisson") +@Configuration +public class RedissonConfig { + + private String address; + private int connectionMinimumIdleSize = 10; + private int idleConnectionTimeout=10000; + private int pingTimeout=1000; + private int connectTimeout=10000; + private int timeout=3000; + private int retryAttempts=3; + private int retryInterval=1500; + private int reconnectionTimeout=3000; + private int failedAttempts=3; + private String password = null; + private int subscriptionsPerConnection=5; + private String clientName=null; + private int subscriptionConnectionMinimumIdleSize = 1; + private int subscriptionConnectionPoolSize = 50; + private int connectionPoolSize = 64; + private int database = 0; + private boolean dnsMonitoring = false; + private int dnsMonitoringInterval = 5000; + + private int thread; //当前处理核数量 * 2 + + private String codec="org.redisson.codec.JsonJacksonCodec"; + + @Bean(destroyMethod = "shutdown") + RedissonClient redisson() throws Exception { + Config config = new Config(); + config.useSingleServer().setAddress(address) + .setConnectionMinimumIdleSize(connectionMinimumIdleSize) + .setConnectionPoolSize(connectionPoolSize) + .setDatabase(database) + .setDnsMonitoring(dnsMonitoring) + .setDnsMonitoringInterval(dnsMonitoringInterval) + .setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize) + .setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize) + .setSubscriptionsPerConnection(subscriptionsPerConnection) + .setClientName(clientName) + .setFailedAttempts(failedAttempts) + .setRetryAttempts(retryAttempts) + .setRetryInterval(retryInterval) + .setReconnectionTimeout(reconnectionTimeout) + .setTimeout(timeout) + .setConnectTimeout(connectTimeout) + .setIdleConnectionTimeout(idleConnectionTimeout) + .setPingTimeout(pingTimeout) + .setPassword(password); + Codec codec=(Codec) ClassUtils.forName(getCodec(), ClassUtils.getDefaultClassLoader()).newInstance(); + config.setCodec(codec); + config.setThreads(thread); + config.setEventLoopGroup(new NioEventLoopGroup()); + config.setUseLinuxNativeEpoll(false); + return Redisson.create(config); + } + + public int getThread() { + return thread; + } + + public void setThread(int thread) { + this.thread = thread; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public int getIdleConnectionTimeout() { + return idleConnectionTimeout; + } + + public void setIdleConnectionTimeout(int idleConnectionTimeout) { + this.idleConnectionTimeout = idleConnectionTimeout; + } + + public int getPingTimeout() { + return pingTimeout; + } + + public void setPingTimeout(int pingTimeout) { + this.pingTimeout = pingTimeout; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public int getTimeout() { + return timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public int getRetryAttempts() { + return retryAttempts; + } + + public void setRetryAttempts(int retryAttempts) { + this.retryAttempts = retryAttempts; + } + + public int getRetryInterval() { + return retryInterval; + } + + public void setRetryInterval(int retryInterval) { + this.retryInterval = retryInterval; + } + + public int getReconnectionTimeout() { + return reconnectionTimeout; + } + + public void setReconnectionTimeout(int reconnectionTimeout) { + this.reconnectionTimeout = reconnectionTimeout; + } + + public int getFailedAttempts() { + return failedAttempts; + } + + public void setFailedAttempts(int failedAttempts) { + this.failedAttempts = failedAttempts; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public int getSubscriptionsPerConnection() { + return subscriptionsPerConnection; + } + + public void setSubscriptionsPerConnection(int subscriptionsPerConnection) { + this.subscriptionsPerConnection = subscriptionsPerConnection; + } + + public String getClientName() { + return clientName; + } + + public void setClientName(String clientName) { + this.clientName = clientName; + } + + public int getSubscriptionConnectionMinimumIdleSize() { + return subscriptionConnectionMinimumIdleSize; + } + + public void setSubscriptionConnectionMinimumIdleSize(int subscriptionConnectionMinimumIdleSize) { + this.subscriptionConnectionMinimumIdleSize = subscriptionConnectionMinimumIdleSize; + } + + public int getSubscriptionConnectionPoolSize() { + return subscriptionConnectionPoolSize; + } + + public void setSubscriptionConnectionPoolSize(int subscriptionConnectionPoolSize) { + this.subscriptionConnectionPoolSize = subscriptionConnectionPoolSize; + } + + public int getConnectionMinimumIdleSize() { + return connectionMinimumIdleSize; + } + + public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) { + this.connectionMinimumIdleSize = connectionMinimumIdleSize; + } + + public int getConnectionPoolSize() { + return connectionPoolSize; + } + + public void setConnectionPoolSize(int connectionPoolSize) { + this.connectionPoolSize = connectionPoolSize; + } + + public int getDatabase() { + return database; + } + + public void setDatabase(int database) { + this.database = database; + } + + public boolean isDnsMonitoring() { + return dnsMonitoring; + } + + public void setDnsMonitoring(boolean dnsMonitoring) { + this.dnsMonitoring = dnsMonitoring; + } + + public int getDnsMonitoringInterval() { + return dnsMonitoringInterval; + } + + public void setDnsMonitoringInterval(int dnsMonitoringInterval) { + this.dnsMonitoringInterval = dnsMonitoringInterval; + } + + public String getCodec() { + return codec; + } + + public void setCodec(String codec) { + this.codec = codec; + } +} diff --git a/src/main/java/com/yudianbank/extend/ControlDocumentFormatRegistry.java b/src/main/java/com/yudianbank/extend/ControlDocumentFormatRegistry.java new file mode 100644 index 000000000..99632680d --- /dev/null +++ b/src/main/java/com/yudianbank/extend/ControlDocumentFormatRegistry.java @@ -0,0 +1,211 @@ +package com.yudianbank.extend; + +import com.google.common.collect.Maps; +import com.sun.star.beans.PropertyValue; +import org.artofsolving.jodconverter.document.DocumentFamily; +import org.artofsolving.jodconverter.document.DocumentFormat; +import org.artofsolving.jodconverter.document.SimpleDocumentFormatRegistry; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 重写了DefaultDocumentFormatRegistry类,因为要添加自定义行为,比如字符编码。。。 + * @author yudian-it + * @date 2017/12/5 + */ +public class ControlDocumentFormatRegistry extends SimpleDocumentFormatRegistry { + + public ControlDocumentFormatRegistry() { + DocumentFormat pdf = new DocumentFormat("Portable Document Format", "pdf", "application/pdf"); + pdf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer_pdf_Export")); + pdf.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc_pdf_Export")); + pdf.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_pdf_Export")); + pdf.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_pdf_Export")); + addFormat(pdf); + + DocumentFormat swf = new DocumentFormat("Macromedia Flash", "swf", "application/x-shockwave-flash"); + swf.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_flash_Export")); + swf.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_flash_Export")); + addFormat(swf); + + // disabled because it's not always available + //DocumentFormat xhtml = new DocumentFormat("XHTML", "xhtml", "application/xhtml+xml"); + //xhtml.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "XHTML Writer File")); + //xhtml.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "XHTML Calc File")); + //xhtml.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "XHTML Impress File")); + //addFormat(xhtml); + + DocumentFormat html = new DocumentFormat("HTML", "html", "text/html"); + // HTML is treated as Text when supplied as input, but as an output it is also + // available for exporting Spreadsheet and Presentation formats + html.setInputFamily(DocumentFamily.TEXT); + html.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "HTML (StarWriter)")); + Map htmlLoadAndStoreProperties = new LinkedHashMap(); + htmlLoadAndStoreProperties.put("FilterName", "HTML (StarCalc)"); + htmlLoadAndStoreProperties.put("FilterOptions", "utf8"); + html.setStoreProperties(DocumentFamily.SPREADSHEET, htmlLoadAndStoreProperties); + html.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress_html_Export")); + addFormat(html); + + DocumentFormat odt = new DocumentFormat("OpenDocument Text", "odt", "application/vnd.oasis.opendocument.text"); + odt.setInputFamily(DocumentFamily.TEXT); + odt.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "writer8")); + addFormat(odt); + + DocumentFormat sxw = new DocumentFormat("OpenOffice.org 1.0 Text Document", "sxw", "application/vnd.sun.xml.writer"); + sxw.setInputFamily(DocumentFamily.TEXT); + sxw.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "StarOffice XML (Writer)")); + addFormat(sxw); + + DocumentFormat doc = new DocumentFormat("Microsoft Word", "doc", "application/msword"); + doc.setInputFamily(DocumentFamily.TEXT); + doc.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "MS Word 97")); + addFormat(doc); + + DocumentFormat docx = new DocumentFormat("Microsoft Word 2007 XML", "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + docx.setInputFamily(DocumentFamily.TEXT); + addFormat(docx); + + DocumentFormat rtf = new DocumentFormat("Rich Text Format", "rtf", "text/rtf"); + rtf.setInputFamily(DocumentFamily.TEXT); + rtf.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "Rich Text Format")); + addFormat(rtf); + + DocumentFormat wpd = new DocumentFormat("WordPerfect", "wpd", "application/wordperfect"); + wpd.setInputFamily(DocumentFamily.TEXT); + addFormat(wpd); + + DocumentFormat txt = new DocumentFormat("Plain Text", "txt", "text/plain"); + txt.setInputFamily(DocumentFamily.TEXT); + Map txtLoadAndStoreProperties = new LinkedHashMap(); + txtLoadAndStoreProperties.put("FilterName", "Text (encoded)"); + txtLoadAndStoreProperties.put("FilterOptions", "utf8"); + txt.setLoadProperties(txtLoadAndStoreProperties); + txt.setStoreProperties(DocumentFamily.TEXT, txtLoadAndStoreProperties); + addFormat(txt); + + DocumentFormat wikitext = new DocumentFormat("MediaWiki wikitext", "wiki", "text/x-wiki"); + wikitext.setStoreProperties(DocumentFamily.TEXT, Collections.singletonMap("FilterName", "MediaWiki")); + //addFormat(wikitext); + + DocumentFormat ods = new DocumentFormat("OpenDocument Spreadsheet", "ods", "application/vnd.oasis.opendocument.spreadsheet"); + ods.setInputFamily(DocumentFamily.SPREADSHEET); + ods.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "calc8")); + addFormat(ods); + + DocumentFormat sxc = new DocumentFormat("OpenOffice.org 1.0 Spreadsheet", "sxc", "application/vnd.sun.xml.calc"); + sxc.setInputFamily(DocumentFamily.SPREADSHEET); + sxc.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "StarOffice XML (Calc)")); + addFormat(sxc); + + DocumentFormat xls = new DocumentFormat("Microsoft Excel", "xls", "application/vnd.ms-excel"); + xls.setInputFamily(DocumentFamily.SPREADSHEET); + xls.setStoreProperties(DocumentFamily.SPREADSHEET, Collections.singletonMap("FilterName", "MS Excel 97")); + addFormat(xls); + + DocumentFormat xlsx = new DocumentFormat("Microsoft Excel 2007 XML", "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + xlsx.setInputFamily(DocumentFamily.SPREADSHEET); + addFormat(xlsx); + + DocumentFormat csv = new DocumentFormat("Comma Separated Values", "csv", "text/csv"); + csv.setInputFamily(DocumentFamily.SPREADSHEET); + Map csvLoadAndStoreProperties = new LinkedHashMap(); + csvLoadAndStoreProperties.put("FilterName", "Text - txt - csv (StarCalc)"); + csvLoadAndStoreProperties.put("FilterOptions", "44,34,0"); // Field Separator: ','; Text Delimiter: '"' + csv.setLoadProperties(csvLoadAndStoreProperties); + csv.setStoreProperties(DocumentFamily.SPREADSHEET, csvLoadAndStoreProperties); + addFormat(csv); + + DocumentFormat tsv = new DocumentFormat("Tab Separated Values", "tsv", "text/tab-separated-values"); + tsv.setInputFamily(DocumentFamily.SPREADSHEET); + Map tsvLoadAndStoreProperties = new LinkedHashMap(); + tsvLoadAndStoreProperties.put("FilterName", "Text - txt - csv (StarCalc)"); + tsvLoadAndStoreProperties.put("FilterOptions", "9,34,0"); // Field Separator: '\t'; Text Delimiter: '"' + tsv.setLoadProperties(tsvLoadAndStoreProperties); + tsv.setStoreProperties(DocumentFamily.SPREADSHEET, tsvLoadAndStoreProperties); + addFormat(tsv); + + DocumentFormat odp = new DocumentFormat("OpenDocument Presentation", "odp", "application/vnd.oasis.opendocument.presentation"); + odp.setInputFamily(DocumentFamily.PRESENTATION); + odp.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "impress8")); + addFormat(odp); + + DocumentFormat sxi = new DocumentFormat("OpenOffice.org 1.0 Presentation", "sxi", "application/vnd.sun.xml.impress"); + sxi.setInputFamily(DocumentFamily.PRESENTATION); + sxi.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "StarOffice XML (Impress)")); + addFormat(sxi); + + DocumentFormat ppt = new DocumentFormat("Microsoft PowerPoint", "ppt", "application/vnd.ms-powerpoint"); + ppt.setInputFamily(DocumentFamily.PRESENTATION); + ppt.setStoreProperties(DocumentFamily.PRESENTATION, Collections.singletonMap("FilterName", "MS PowerPoint 97")); + addFormat(ppt); + + DocumentFormat pptx = new DocumentFormat("Microsoft PowerPoint 2007 XML", "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"); + pptx.setInputFamily(DocumentFamily.PRESENTATION); + addFormat(pptx); + + DocumentFormat odg = new DocumentFormat("OpenDocument Drawing", "odg", "application/vnd.oasis.opendocument.graphics"); + odg.setInputFamily(DocumentFamily.DRAWING); + odg.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw8")); + addFormat(odg); + + DocumentFormat svg = new DocumentFormat("Scalable Vector Graphics", "svg", "image/svg+xml"); + svg.setStoreProperties(DocumentFamily.DRAWING, Collections.singletonMap("FilterName", "draw_svg_Export")); + addFormat(svg); + } + + /** + * 创建默认的导出属性 + * @return + */ + private PropertyValue[] getCommonPropertyValue() { + PropertyValue[] aFilterData = new PropertyValue[11]; + // 不显示文档标题 + aFilterData[0] = new PropertyValue(); + aFilterData[0].Name = "DisplayPDFDocumentTitle"; + aFilterData[0].Value= true; + // 导出文件编码方式 + aFilterData[1] = new PropertyValue(); + aFilterData[1].Name = "Encoding"; + aFilterData[1].Value= "UTF-8"; + // 隐藏工具条 + aFilterData[2] = new PropertyValue(); + aFilterData[2].Name = "HideViewerToolbar"; + aFilterData[2].Value= false; + // 隐藏窗口控制条 + aFilterData[3] = new PropertyValue(); + aFilterData[3].Name = "HideViewerWindowControls"; + aFilterData[3].Value= true; + // 全屏展示 + aFilterData[4] = new PropertyValue(); + aFilterData[4].Name = "OpenInFullScreenMode"; + aFilterData[4].Value= false; + // 第一页左边展示 + aFilterData[5] = new PropertyValue(); + aFilterData[5].Name = "MathToMathType"; + aFilterData[5].Value= true; + // 文档标题内容 + aFilterData[6] = new PropertyValue(); + aFilterData[6].Name = "Watermark"; + aFilterData[6].Value= "KEKING.CN"; + // 导出文件编码方式 + aFilterData[7] = new PropertyValue(); + aFilterData[7].Name = "CharacterSet"; + aFilterData[7].Value= "UTF-8"; + // 导出文件编码方式 + aFilterData[8] = new PropertyValue(); + aFilterData[8].Name = "Encoding"; + aFilterData[8].Value= "UTF-8"; + // 导出文件编码方式 + aFilterData[9] = new PropertyValue(); + aFilterData[9].Name = "CharSet"; + aFilterData[9].Value= "UTF-8"; + // 导出文件编码方式 + aFilterData[10] = new PropertyValue(); + aFilterData[10].Name = "charset"; + aFilterData[10].Value= "UTF-8"; + return aFilterData; + } +} diff --git a/src/main/java/com/yudianbank/filters/ChinesePathFilter.java b/src/main/java/com/yudianbank/filters/ChinesePathFilter.java new file mode 100644 index 000000000..ea0b18da8 --- /dev/null +++ b/src/main/java/com/yudianbank/filters/ChinesePathFilter.java @@ -0,0 +1,28 @@ +package com.yudianbank.filters; + +import javax.servlet.*; +import java.io.IOException; + +/** + * + * @author yudian-it + * @date 2017/11/30 + */ +public class ChinesePathFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + request.setCharacterEncoding("UTF-8"); + response.setCharacterEncoding("UTF-8"); + chain.doFilter(request, response); + } + + @Override + public void destroy() { + + } +} diff --git a/src/main/java/com/yudianbank/filters/FilterConfiguration.java b/src/main/java/com/yudianbank/filters/FilterConfiguration.java new file mode 100644 index 000000000..246a4611d --- /dev/null +++ b/src/main/java/com/yudianbank/filters/FilterConfiguration.java @@ -0,0 +1,23 @@ +package com.yudianbank.filters; + +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +/** + * + * @author yudian-it + * @date 2017/11/30 + */ +@Configuration +public class FilterConfiguration { + + @Bean + public FilterRegistrationBean getChinesePathFilter(){ + ChinesePathFilter filter = new ChinesePathFilter(); + FilterRegistrationBean registrationBean = new FilterRegistrationBean(); + registrationBean.setFilter(filter); + return registrationBean; + } +} diff --git a/src/main/java/com/yudianbank/param/ReturnResponse.java b/src/main/java/com/yudianbank/param/ReturnResponse.java new file mode 100644 index 000000000..d1438662b --- /dev/null +++ b/src/main/java/com/yudianbank/param/ReturnResponse.java @@ -0,0 +1,57 @@ +package com.yudianbank.param; + +import java.io.Serializable; + +/** + * 接口返回值结构 + * @author yudian-it + * @date 2017/11/17 + */ +public class ReturnResponse implements Serializable{ + private static final long serialVersionUID = 313975329998789878L; + /** + * 返回状态 + * 0. 成功 + * 1. 失败 + */ + private int code; + + /** + * 返回状态描述 + * XXX成功 + * XXX失败 + */ + private String msg; + + private T content; + + public ReturnResponse(int code, String msg, T content) { + this.code = code; + this.msg = msg; + this.content = content; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getContent() { + return content; + } + + public void setContent(T content) { + this.content = content; + } +} diff --git a/src/main/java/com/yudianbank/utils/ConverterUtils.java b/src/main/java/com/yudianbank/utils/ConverterUtils.java new file mode 100644 index 000000000..53a306cc2 --- /dev/null +++ b/src/main/java/com/yudianbank/utils/ConverterUtils.java @@ -0,0 +1,68 @@ +package com.yudianbank.utils; + +import com.sun.star.document.UpdateDocMode; +import com.yudianbank.extend.ControlDocumentFormatRegistry; +import org.artofsolving.jodconverter.OfficeDocumentConverter; +import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration; +import org.artofsolving.jodconverter.office.OfficeManager; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; + +/** + * 创建文件转换器 + * + * @author yudian-it + * @date 2017/11/13 + */ +@Component +public class ConverterUtils { + + @Value("${office.home}") + String officeHome; +// OpenOfficeConnection connection; + OfficeManager officeManager; + + @PostConstruct + public void initOfficeManager() { + //// connection = new SocketOpenOfficeConnection(host,8100); +//// connection.connect(); + DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration(); + configuration.setOfficeHome(officeHome); + configuration.setPortNumber(8100); + officeManager = configuration.buildOfficeManager(); + officeManager.start(); + // 设置任务执行超时为5分钟 + // configuration.setTaskExecutionTimeout(1000 * 60 * 5L);// + // 设置任务队列超时为24小时 + // configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);// + } + + public OfficeDocumentConverter getDocumentConverter() { + OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager, new ControlDocumentFormatRegistry()); + converter.setDefaultLoadProperties(getLoadProperties()); + return converter; + } + + private Map getLoadProperties() { + Map loadProperties = new HashMap<>(10); + loadProperties.put("Hidden", true); + loadProperties.put("ReadOnly", true); + loadProperties.put("UpdateDocMode", UpdateDocMode.QUIET_UPDATE); + loadProperties.put("CharacterSet", Charset.forName("UTF-8").name()); + return loadProperties; + } + + @PreDestroy + public void destroyOfficeManager(){ + if (null != officeManager && officeManager.isRunning()) { + officeManager.stop(); + } + } + +} diff --git a/src/main/java/com/yudianbank/utils/DeleteFileUtil.java b/src/main/java/com/yudianbank/utils/DeleteFileUtil.java new file mode 100644 index 000000000..896ef78d7 --- /dev/null +++ b/src/main/java/com/yudianbank/utils/DeleteFileUtil.java @@ -0,0 +1,74 @@ +package com.yudianbank.utils; + +import java.io.File; + +public class DeleteFileUtil { + /** + * 删除单个文件 + * + * @param fileName + * 要删除的文件的文件名 + * @return 单个文件删除成功返回true,否则返回false + */ + public static boolean deleteFile(String fileName) { + File file = new File(fileName); + // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除 + if (file.exists() && file.isFile()) { + if (file.delete()) { + System.out.println("删除单个文件" + fileName + "成功!"); + return true; + } else { + System.out.println("删除单个文件" + fileName + "失败!"); + return false; + } + } else { + System.out.println("删除单个文件失败:" + fileName + "不存在!"); + return false; + } + } + + + /** + * 删除目录及目录下的文件 + * + * @param dir + * 要删除的目录的文件路径 + * @return 目录删除成功返回true,否则返回false + */ + public static boolean deleteDirectory(String dir) { + // 如果dir不以文件分隔符结尾,自动添加文件分隔符 + if (!dir.endsWith(File.separator)) { + dir = dir + File.separator; + } + File dirFile = new File(dir); + // 如果dir对应的文件不存在,或者不是一个目录,则退出 + if ((!dirFile.exists()) || (!dirFile.isDirectory())) { + System.out.println("删除目录失败:" + dir + "不存在!"); + return false; + } + boolean flag = true; + // 删除文件夹中的所有文件包括子目录 + File[] files = dirFile.listFiles(); + for (int i = 0; i < files.length; i++) { + // 删除子文件 + if (files[i].isFile()) { + flag = DeleteFileUtil.deleteFile(files[i].getAbsolutePath()); + if (!flag) + break; + } + // 删除子目录 + else if (files[i].isDirectory()) { + flag = DeleteFileUtil.deleteDirectory(files[i] + .getAbsolutePath()); + if (!flag) + break; + } + } + if (!flag) { + System.out.println("删除目录失败!"); + return false; + } + return true; + } + +} diff --git a/src/main/java/com/yudianbank/utils/DownloadUtils.java b/src/main/java/com/yudianbank/utils/DownloadUtils.java new file mode 100644 index 000000000..5980feec2 --- /dev/null +++ b/src/main/java/com/yudianbank/utils/DownloadUtils.java @@ -0,0 +1,151 @@ +package com.yudianbank.utils; + +import com.yudianbank.param.ReturnResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import java.io.*; +import java.net.*; +import java.util.UUID; + +/** + * @author yudian-it + */ +@Component +public class DownloadUtils { + + @Value("${file.dir}") + String fileDir; + + /** + * 一开始测试的时候发现有些文件没有下载下来,而有些可以;当时也是郁闷了好一阵,但是最终还是不得解 + * 再次测试的时候,通过前台对比url发现,原来参数中有+号特殊字符存在,但是到后之后却变成了空格,突然恍然大悟 + * 应该是转义出了问题,url转义中会把+号当成空格来计算,所以才会出现这种情况,遂想要通过整体替换空格为加号,因为url + * 中的参数部分是不会出现空格的,但是文件名中就不好确定了,所以只对url参数部分做替换 + * @param urlAddress + * @param type + * @param needEncode + * 在处理本地文件(测试预览界面的,非ufile)的时候要对中文进行转码, + * 因为tomcat对[英文字母(a-z,A-Z)、数字(0-9)、- _ . ~ 4个特殊字符以及所有保留字符] + * 以外的字符会处理不正常,导致失败 + * @return + */ + public ReturnResponse downLoad(String urlAddress, String type, String fileName, String needEncode){ +// type = dealWithMS2013(type); + ReturnResponse response = new ReturnResponse<>(0, "下载成功!!!", ""); + URL url = null; + try { + if (null != needEncode) { + urlAddress = encodeUrlParam(urlAddress); + // 因为tomcat不能处理'+'号,所以讲'+'号替换成'%20%' + urlAddress = urlAddress.replaceAll("\\+", "%20"); + }else{ + urlAddress = replacePlusMark(urlAddress); + } + url = new URL(urlAddress); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + UUID uuid = UUID.randomUUID(); + if (null == fileName) { + fileName = uuid+ "."+type; + } + String realPath = fileDir + fileName; + File dirFile = new File(fileDir); + if (!dirFile.exists()) { + dirFile.mkdirs(); + } + try { + URLConnection connection = url.openConnection(); + InputStream in = connection.getInputStream(); + + FileOutputStream os = new FileOutputStream(realPath); + byte[] buffer = new byte[4 * 1024]; + int read; + while ((read = in.read(buffer)) > 0) { + os.write(buffer, 0, read); + } + os.close(); + in.close(); + response.setContent(realPath); + return response; + } catch (IOException e) { + e.printStackTrace(); + response.setCode(1); + response.setContent(null); + if (e instanceof FileNotFoundException) { + response.setMsg("文件不存在!!!"); + }else { + response.setMsg(e.getMessage()); + } + return response; + } + } + + /** + * 转换url参数部分的空格为加号(因为在url编解码的过程中出现+转为空格的情况) + * @param urlAddress + * @return + */ + private String replacePlusMark(String urlAddress) { + String nonParamStr = urlAddress.substring(0,urlAddress.indexOf("?") + 1); + String paramStr = urlAddress.substring(nonParamStr.length()); + return nonParamStr + paramStr.replace(" ", "+"); + } + + /** + * 对最有一个路径进行转码 + * @param urlAddress + * http://192.168.2.111:8013/demo/Handle中文.zip + * @return + */ + private String encodeUrlParam(String urlAddress) { + String newUrl = ""; + try { + String path = ""; + String param = ""; + if (urlAddress.contains("?")) { + path = urlAddress.substring(0, urlAddress.indexOf("?")); + param = urlAddress.substring(urlAddress.indexOf("?") + 1); + }else { + path = urlAddress; + } + String lastPath = path.substring(path.lastIndexOf("/") + 1); + String leftPath = path.substring(0, path.lastIndexOf("/") + 1); + String encodeLastPath = URLEncoder.encode(lastPath, "UTF-8"); + newUrl += leftPath + encodeLastPath; + if (urlAddress.contains("?")) { + newUrl += param; + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return newUrl; + } + + + + /** + * 因为jodConvert2.1不支持ms2013版本的office转换,这里偷懒,尝试看改一下文件类型,让jodConvert2.1去 + * 处理ms2013,看结果如何,如果问题很大的话只能采取其他方式,如果没有问题,暂时使用该版本来转换 + * @param type + * @return + */ + private String dealWithMS2013(String type) { + String newType = null; + switch (type){ + case "docx": + newType = "doc"; + break; + case "xlsx": + newType = "doc"; + break; + case "pptx": + newType = "ppt"; + break; + default: + newType = type; + break; + } + return newType; + } +} diff --git a/src/main/java/com/yudianbank/utils/FileUtils.java b/src/main/java/com/yudianbank/utils/FileUtils.java new file mode 100644 index 000000000..0b59fc8c2 --- /dev/null +++ b/src/main/java/com/yudianbank/utils/FileUtils.java @@ -0,0 +1,192 @@ +package com.yudianbank.utils; + +import com.google.common.collect.Lists; +import org.redisson.api.RMapCache; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.*; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Map; + +/** + * + * @author yudian-it + * @date 2017/11/13 + */ +@Component +public class FileUtils { + + final String REDIS_FILE_PREVIEW_PDF_KEY = "converted-preview-pdf-file"; + + @Autowired + RedissonClient redissonClient; + @Value("${file.dir}") + String fileDir; + + @Value("${converted.file.charset}") + String charset; + + /** + * 已转换过的文件集合(redis缓存) + * @return + */ + public Map listConvertedFiles() { + RMapCache convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY); + return convertedList; + } + + /** + * 已转换过的文件,根据文件名获取 + * @return + */ + public String getConvertedFile(String key) { + RMapCache convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY); + return convertedList.get(key); + } + + /** + * 从url中剥离出文件名 + * @param url + * 格式如:http://keking.ufile.ucloud.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I D1NOFtAJSPT16E6imv6JWuq0k= + * @return + */ + public String getFileNameFromURL(String url) { + // 因为url的参数中可能会存在/的情况,所以直接url.lastIndexOf("/")会有问题 + // 所以先从?处将url截断,然后运用url.lastIndexOf("/")获取文件名 + String noQueryUrl = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?"): url.length()); + String fileName = noQueryUrl.substring(noQueryUrl.lastIndexOf("/") + 1); + return fileName; + } + + /** + * 获取文件后缀 + * @param fileName + * @return + */ + public String getSuffixFromFileName(String fileName) { + String suffix = fileName.substring(fileName.lastIndexOf(".")); + return suffix; + } + + /** + * 从路径中获取 + * @param path + * 类似这种:C:\Users\yudian-it\Downloads + * @return + */ + public String getFileNameFromPath(String path) { + return path.substring(path.lastIndexOf(File.separator) + 1); + } + + public List listPictureTypes(){ + List list = Lists.newArrayList(); + list.add("jpg"); + list.add("jpeg"); + list.add("png"); + list.add("gif"); + list.add("bmp"); + return list; + } + + public List listArchiveTypes(){ + List list = Lists.newArrayList(); + list.add("rar"); + list.add("zip"); + list.add("jar"); + list.add("7-zip"); + list.add("tar"); + list.add("gzip"); + list.add("7z"); + return list; + } + + public List listOfficeTypes() { + List list = Lists.newArrayList(); + list.add("docx"); + list.add("doc"); + list.add("xls"); + list.add("xlsx"); + list.add("ppt"); + list.add("pptx"); + return list; + } + + /** + * 获取相对路径 + * @param absolutePath + * @return + */ + public String getRelativePath(String absolutePath) { + return absolutePath.substring(fileDir.length()); + } + + public void addConvertedFile(String fileName, String value){ + RMapCache convertedList = redissonClient.getMapCache(REDIS_FILE_PREVIEW_PDF_KEY); + convertedList.fastPut(fileName, value); + } + + /** + * 判断文件编码格式 + * @param path + * @return + */ + public String getFileEncodeUTFGBK(String path){ + String enc = Charset.forName("GBK").name(); + File file = new File(path); + InputStream in= null; + try { + in = new FileInputStream(file); + byte[] b = new byte[3]; + in.read(b); + in.close(); + if (b[0] == -17 && b[1] == -69 && b[2] == -65) { + enc = Charset.forName("UTF-8").name(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + System.out.println("文件编码格式为:" + enc); + return enc; + } + + /** + * 对转换后的文件进行操作(改变编码方式) + * @param outFilePath + */ + public void doActionConvertedFile(String outFilePath) { + StringBuffer sb = new StringBuffer(); + try (InputStream inputStream = new FileInputStream(outFilePath); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charset))){ + String line; + while(null != (line = reader.readLine())){ + if (line.contains("charset=gb2312")) { + line = line.replace("charset=gb2312", "charset=utf-8"); + } + sb.append(line); + } + // 添加sheet控制头 + sb.append(""); + sb.append(""); + sb.append(""); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + // 重新写入文件 + try(FileOutputStream fos = new FileOutputStream(outFilePath); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos))){ + writer.write(sb.toString()); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/yudianbank/utils/OfficeToPdf.java b/src/main/java/com/yudianbank/utils/OfficeToPdf.java new file mode 100644 index 000000000..7f8334463 --- /dev/null +++ b/src/main/java/com/yudianbank/utils/OfficeToPdf.java @@ -0,0 +1,129 @@ +package com.yudianbank.utils; +import org.artofsolving.jodconverter.OfficeDocumentConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.File; +@Component +public class OfficeToPdf { + /** + * 获取OpenOffice.org 3的安装目录 + * + * @return OpenOffice.org 3的安装目录 + */ + @Value("${openOfficePath}") + private String openOfficePath; + @Autowired + ConverterUtils converterUtils; + /** + * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件
+ * + * @param inputFilePath + * 源文件路径,如:"e:/test.docx" + * @param outputFilePath + * 目标文件路径,如:"e:/test_docx.pdf" + * @return + */ + public boolean openOfficeToPDF(String inputFilePath, String outputFilePath) { + return office2pdf(inputFilePath, outputFilePath); + } + + + + /** + * 连接OpenOffice.org 并且启动OpenOffice.org + * + * @return + */ + /*public OfficeManager getOfficeManager() { + DefaultOfficeManagerConfiguration config = new DefaultOfficeManagerConfiguration(); + // 获取OpenOffice.org 3的安装目录 + String officeHome = openOfficePath; + config.setOfficeHome(officeHome); + // 启动OpenOffice的服务 + OfficeManager officeManager = config.buildOfficeManager(); + officeManager.start(); + return officeManager; + }*/ + + /** + * 转换文件 + * + * @param inputFile + * @param outputFilePath_end + * @param inputFilePath + * @param outputFilePath + * @param converter + */ + public static void converterFile(File inputFile, String outputFilePath_end, + String inputFilePath, String outputFilePath, + OfficeDocumentConverter converter) { + File outputFile = new File(outputFilePath_end); + // 假如目标路径不存在,则新建该路径 + if (!outputFile.getParentFile().exists()) { + outputFile.getParentFile().mkdirs(); + } + converter.convert(inputFile, outputFile); + } + + /** + * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件 + * + * @param inputFilePath + * 源文件路径,如:"e:/test.docx" + * @param outputFilePath + * 目标文件路径,如:"e:/test_docx.pdf" + * @return + */ + public boolean office2pdf(String inputFilePath, String outputFilePath) { + boolean flag = false; + OfficeDocumentConverter converter = converterUtils.getDocumentConverter(); + if (null != inputFilePath) { + File inputFile = new File(inputFilePath); + // 判断目标文件路径是否为空 + if (null == outputFilePath) { + // 转换后的文件路径 + String outputFilePath_end = getOutputFilePath(inputFilePath); + if (inputFile.exists()) {// 找不到源文件, 则返回 + converterFile(inputFile, outputFilePath_end, inputFilePath, + outputFilePath, converter); + flag = true; + } + } else { + if (inputFile.exists()) {// 找不到源文件, 则返回 + converterFile(inputFile, outputFilePath, inputFilePath, + outputFilePath, converter); + flag = true; + } + } +// officeManager.stop(); + } else { + flag = false; + } + return flag; + } + + /** + * 获取输出文件 + * + * @param inputFilePath + * @return + */ + public static String getOutputFilePath(String inputFilePath) { + String outputFilePath = inputFilePath.replaceAll("." + + getPostfix(inputFilePath), ".pdf"); + return outputFilePath; + } + + /** + * 获取inputFilePath的后缀名,如:"e:/test.pptx"的后缀名为:"pptx" + * + * @param inputFilePath + * @return + */ + public static String getPostfix(String inputFilePath) { + return inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1); + } + +} diff --git a/src/main/java/com/yudianbank/utils/PoiExcelToHtml.java b/src/main/java/com/yudianbank/utils/PoiExcelToHtml.java new file mode 100644 index 000000000..e08883bf3 --- /dev/null +++ b/src/main/java/com/yudianbank/utils/PoiExcelToHtml.java @@ -0,0 +1,194 @@ +package com.yudianbank.utils; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.poi.hssf.converter.ExcelToHtmlConverter; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hwpf.converter.PicturesManager; +import org.apache.poi.hwpf.converter.WordToHtmlConverter; +import org.apache.poi.hwpf.usermodel.Picture; +import org.apache.poi.hwpf.usermodel.PictureType; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.w3c.dom.Document; + + +public class PoiExcelToHtml { +// String path = getClass().getClassLoader().getResource(".").getPath()+File.separator+"static"+File.separator; + public static void excelConvert(URL url) { + try { + String path = ""; + +// http://keking.ufile.ucloud.com.cn/20171101152525_左晓晖2017年9.xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=1n8ASiYMcfiF30YHxwpzwfqmlM0= +// URL url = new URL("http://keking.ufile.ucloud.com.cn/20171101150322_运费贷信审资料(给予客户收集版).xlsx?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=RRVFIICITMNFed1LQgB10WdKHiE="); + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + //设置超时间为3秒 + conn.setConnectTimeout(3*1000); + //防止屏蔽程序抓取而返回403错误 + conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); + //得到输入流 + InputStream inputStream = conn.getInputStream(); + HSSFWorkbook excelBook = new HSSFWorkbook(inputStream); + ExcelToHtmlConverter excelToHtmlConverter = new ExcelToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()); + excelToHtmlConverter.processWorkbook(excelBook); + List pics = excelBook.getAllPictures(); + if (pics != null) { + for (int i = 0; i < pics.size(); i++) { + Picture pic = (Picture) pics.get(i); + try { + pic.writeImageContent(new FileOutputStream(path + pic.suggestFullFileName())); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + Document htmlDocument = excelToHtmlConverter.getDocument(); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DOMSource domSource = new DOMSource(htmlDocument); + StreamResult streamResult = new StreamResult(outStream); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer serializer = tf.newTransformer(); + serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8"); + serializer.setOutputProperty(OutputKeys.INDENT, "yes"); + serializer.setOutputProperty(OutputKeys.METHOD, "html"); + serializer.transform(domSource, streamResult); + outStream.close(); + + String content = new String(outStream.toByteArray()); + + } catch (IOException e) { + e.printStackTrace(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } catch (TransformerException e) { + e.printStackTrace(); + } + } + + /** + * excel07转html + * filename:要读取的文件所在文件夹 + * filepath:文件名 + * htmlname:生成html名称 + * path:html存放路径 + * */ + public static void excelToHtml () throws Exception{ + String htmlname="exportExcel"+"07Test"+".html"; + + + URL url = new URL("http://keking.ufile.ucloud.com.cn/20171101150322_运费贷信审资料(给予客户收集版).xlsx?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=RRVFIICITMNFed1LQgB10WdKHiE="); + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + //设置超时间为3秒 + conn.setConnectTimeout(3*1000); + //防止屏蔽程序抓取而返回403错误 + conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); + //得到输入流 + InputStream is = conn.getInputStream(); + + Workbook workbook = null; +// InputStream is = new FileInputStream(filename+"/"+filepath); + try { + String html=""; + workbook = new XSSFWorkbook(is); + for (int numSheet = 0; numSheet < workbook.getNumberOfSheets(); numSheet++) { + Sheet sheet = workbook.getSheetAt(numSheet); + if (sheet == null) { + continue; + } + html+="=======================" + sheet.getSheetName() + "=========================

"; + + int firstRowIndex = sheet.getFirstRowNum(); + int lastRowIndex = sheet.getLastRowNum(); + html+=""; + Row firstRow = sheet.getRow(firstRowIndex); + for (int i = firstRow.getFirstCellNum(); i <= firstRow.getLastCellNum(); i++) { + Cell cell = firstRow.getCell(i); + String cellValue = getCellValue(cell, true); + html+=""; + } + + + //行 + for (int rowIndex = firstRowIndex + 1; rowIndex <= lastRowIndex; rowIndex++) { + Row currentRow = sheet.getRow(rowIndex); + html+=""; + if(currentRow!=null){ + + int firstColumnIndex = currentRow.getFirstCellNum(); + int lastColumnIndex = currentRow.getLastCellNum(); + //列 + for (int columnIndex = firstColumnIndex; columnIndex <= lastColumnIndex; columnIndex++) { + Cell currentCell = currentRow.getCell(columnIndex); + String currentCellValue = getCellValue(currentCell, true); + html+=""; + } + }else{ + html+=" "; + } + html+=""; + } + html+="
" + cellValue + "
"+currentCellValue + "
"; + + + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DOMSource domSource = new DOMSource (); + StreamResult streamResult = new StreamResult (outStream); + + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer serializer = tf.newTransformer(); + serializer.setOutputProperty (OutputKeys.ENCODING, "utf-8"); + serializer.setOutputProperty (OutputKeys.INDENT, "yes"); + serializer.setOutputProperty (OutputKeys.METHOD, "html"); + serializer.transform (domSource, streamResult); + outStream.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + /** + * 读取单元格 + * + */ + private static String getCellValue(Cell cell, boolean treatAsStr) { + if (cell == null) { + return ""; + } + + if (treatAsStr) { + cell.setCellType(Cell.CELL_TYPE_STRING); + } + + if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) { + return String.valueOf(cell.getBooleanCellValue()); + } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) { + return String.valueOf(cell.getNumericCellValue()); + } else { + return String.valueOf(cell.getStringCellValue()); + } + } +} diff --git a/src/main/java/com/yudianbank/utils/ShedulerClean.java b/src/main/java/com/yudianbank/utils/ShedulerClean.java new file mode 100644 index 000000000..761a464df --- /dev/null +++ b/src/main/java/com/yudianbank/utils/ShedulerClean.java @@ -0,0 +1,19 @@ +package com.yudianbank.utils; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.io.File; + +@Component +public class ShedulerClean { + @Value("${file.dir}") + String fileDir; + + @Scheduled(cron = "0 0 23 * * ?") //每晚23点执行一次 + public void clean(){ + System.out.println("执行一次清空文件夹"); + DeleteFileUtil.deleteDirectory(fileDir); + } +} diff --git a/src/main/java/com/yudianbank/utils/WordToHtml.java b/src/main/java/com/yudianbank/utils/WordToHtml.java new file mode 100644 index 000000000..9184e28d1 --- /dev/null +++ b/src/main/java/com/yudianbank/utils/WordToHtml.java @@ -0,0 +1,61 @@ +package com.yudianbank.utils; + +import java.io.*; +import java.util.*; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; + +import com.github.junrar.Archive; +import com.github.junrar.exception.RarException; +import com.github.junrar.rarfile.FileHeader; +import org.apache.commons.compress.archivers.ArchiveException; +import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.apache.poi.xwpf.converter.core.FileImageExtractor; +import org.apache.poi.xwpf.converter.core.FileURIResolver; +import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter; +import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions; +import org.apache.poi.xwpf.usermodel.XWPFDocument; + +public class WordToHtml { + /** 这是2007版本 转html 已测试成功的代码 07和03版要用两种代码转 但因为后面说要用 + * 38 * 2007版本word转换成html + * 39 * @throws IOException + * 40 + */ + + public static String Word2007ToHtml(InputStream inputStream) throws IOException { + // 1) 加载word文档生成 XWPFDocument对象 + XWPFDocument document = new XWPFDocument(inputStream); + + // 2) 解析 XHTML配置 (这里设置IURIResolver来设置图片存放的目录) +// File imageFolderFile = new File("/Users/zuoxiaohui/IdeaProjects/yudian-preview-boot/yudian-preview-boot/src/main/resources/picture/"); + File imageFolderFile = new File("/Users/zuoxiaohui/IdeaProjects/yudian-preview-boot/yudian-preview-boot/src/main/resources/static/"); + XHTMLOptions options = XHTMLOptions.create().URIResolver(new FileURIResolver(imageFolderFile)); + options.setExtractor(new FileImageExtractor(imageFolderFile)); + options.setIgnoreStylesIfUnused(false); + options.setFragment(true); + + File file = new File("/Users/zuoxiaohui/Test/" + "test.html"); + // 3) 将 XWPFDocument转换成XHTML + OutputStream out = new FileOutputStream(file); + XHTMLConverter.getInstance().convert(document, out, options); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + XHTMLConverter.getInstance().convert(document, baos, options); + String content = baos.toString(); + System.out.println(content); + baos.close(); + return content; + + + } + + public static void main(String[] args) throws IOException, ArchiveException, RarException { + File file = new File("C:\\Users\\yudian-it\\Downloads\\Downloads.zip"); + System.out.println("Objects.equals(new Integer(1000), new Integer(1000)) :" + Objects.equals(new Integer(1000), new Integer(1000))); + System.out.println(Integer.valueOf("-129") == Integer.valueOf("-129")); + } + +} diff --git a/src/main/java/com/yudianbank/utils/ZipReader.java b/src/main/java/com/yudianbank/utils/ZipReader.java new file mode 100644 index 000000000..2f774eac3 --- /dev/null +++ b/src/main/java/com/yudianbank/utils/ZipReader.java @@ -0,0 +1,392 @@ +package com.yudianbank.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.junrar.Archive; +import com.github.junrar.exception.RarException; +import com.github.junrar.rarfile.FileHeader; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.*; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * + * @author yudian-it + * @date 2017/11/27 + */ +@Component +public class ZipReader { + + @Autowired + FileUtils fileUtils; + @Value("${file.dir}") + String fileDir; + + ExecutorService executors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + + /** + * 读取压缩文件 + * 文件压缩到统一目录fileDir下,并且命名使用压缩文件名+文件名因为文件名 + * 可能会重复(在系统中对于同一种类型的材料压缩文件内的文件是一样的,如果文件名 + * 重复,那么这里会被覆盖[同一个压缩文件中的不同目录中的相同文件名暂时不考虑]) + * 注: + *

+ * 文件名命名中的参数的说明: + * 1.archiveName,为避免解压的文件中有重名的文件会彼此覆盖,所以加上了archiveName,因为在ufile中archiveName + * 是不会重复的。 + * 2.level,这里层级结构的列表我是通过一个map来构造的,map的key是文件的名字,值是对应的文件,这样每次向map中 + * 加入节点的时候都会获取父节点是否存在,存在则会获取父节点的value并将当前节点加入到父节点的childList中(这里利用 + * 的是java语言的引用的特性)。 + *

+ * @param filePath + */ + public String readZipFile(String filePath) { + String archiveSeparator = "/"; + Map appender = Maps.newHashMap(); + String archiveFileName = fileUtils.getFileNameFromPath(filePath); + try { + ZipFile zipFile = new ZipFile(filePath, fileUtils.getFileEncodeUTFGBK(filePath)); + Enumeration entries = zipFile.getEntries(); + // 排序 + entries = sortZipEntries(entries); + List> entriesToBeExtracted = Lists.newArrayList(); + while (entries.hasMoreElements()){ + ZipArchiveEntry entry = entries.nextElement(); + String fullName = entry.getName(); + int level = fullName.split(archiveSeparator).length; + // 展示名 + String originName = getLastFileName(fullName, archiveSeparator); + String childName = level + "_" + originName; + boolean directory = entry.isDirectory(); + if (!directory) { + childName = archiveFileName + "_" + originName; + entriesToBeExtracted.add(Collections.singletonMap(childName, entry)); + } + String parentName = getLast2FileName(fullName, archiveSeparator, archiveFileName); + parentName = (level-1) + "_" + parentName; + FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory); + addNodes(appender, parentName, node); + appender.put(childName, node); + } + // 开启新的线程处理文件解压 + executors.submit(new ZipExtractorWorker(entriesToBeExtracted, zipFile, filePath)); + return new ObjectMapper().writeValueAsString(appender.get("")); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 排序zipEntries(对原来列表倒序) + * @param entries + */ + private Enumeration sortZipEntries(Enumeration entries) { + List sortedEntries = Lists.newArrayList(); + while(entries.hasMoreElements()){ + sortedEntries.add(entries.nextElement()); + } + Collections.sort(sortedEntries, Comparator.comparingInt(o -> o.getName().length())); + return Collections.enumeration(sortedEntries); + } + + public String unRar(String filePath){ + Map appender = Maps.newHashMap(); + try { + Archive archive = new Archive(new File(filePath)); + List headers = archive.getFileHeaders(); + headers = sortedHeaders(headers); + String archiveFileName = fileUtils.getFileNameFromPath(filePath); + List> headersToBeExtracted = Lists.newArrayList(); + for (FileHeader header : headers) { + String fullName; + if (header.isUnicode()) { + fullName = header.getFileNameW(); + }else { + fullName = header.getFileNameString(); + } + // 展示名 + String originName = getLastFileName(fullName, "\\"); + String childName = originName; + boolean directory = header.isDirectory(); + if (!directory) { + childName = archiveFileName + "_" + originName; + headersToBeExtracted.add(Collections.singletonMap(childName, header)); + } + String parentName = getLast2FileName(fullName, "\\", archiveFileName); + FileNode node = new FileNode(originName, childName, parentName, new ArrayList<>(), directory); + addNodes(appender, parentName, node); + appender.put(childName, node); + } + executors.submit(new RarExtractorWorker(headersToBeExtracted, archive, filePath)); + return new ObjectMapper().writeValueAsString(appender.get("")); + } catch (RarException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + private void addNodes(Map appender, String parentName, FileNode node) { + if (appender.containsKey(parentName)) { + appender.get(parentName).getChildList().add(node); + }else { // 根节点 + FileNode nodeRoot = new FileNode(parentName, parentName, "", new ArrayList<>(), true); + nodeRoot.getChildList().add(node); + appender.put("", nodeRoot); + appender.put(parentName, nodeRoot); + } + } + + private List sortedHeaders(List headers) { + List sortedHeaders = new ArrayList<>(); + Map mapHeaders = new TreeMap<>(); + headers.forEach(header -> mapHeaders.put(header.getFileNameW().length(), header)); + for (Map.Entry entry : mapHeaders.entrySet()){ + for (FileHeader header : headers) { + if (entry.getKey().intValue() == header.getFileNameW().length()) { + sortedHeaders.add(header); + } + } + } + return sortedHeaders; + } + + /** + * 获取倒数第二个文件(夹)名 + * @param fullName + * @param seperator + * 压缩文件解压后,不同的压缩格式分隔符不一样zip是/,而rar是\ + * @param rootName + * 根目录名:如果倒数第二个路径为空,那么赋值为rootName + * @return + */ + private static String getLast2FileName(String fullName, String seperator, String rootName) { + if (fullName.endsWith(seperator)) { + fullName = fullName.substring(0, fullName.length()-1); + } + // 1.获取剩余部分 + int endIndex = fullName.lastIndexOf(seperator); + String leftPath = fullName.substring(0, endIndex == -1 ? 0 : endIndex); + if (null != leftPath && leftPath.length() > 1) { + // 2.获取倒数第二个 + return getLastFileName(leftPath, seperator); + }else { + return rootName; + } + } + + /** + * 获取最后一个文件(夹)的名字 + * @param fullName + * @param seperator + * 压缩文件解压后,不同的压缩格式分隔符不一样zip是/,而rar是\ + * @return + */ + private static String getLastFileName(String fullName, String seperator) { + if (fullName.endsWith(seperator)) { + fullName = fullName.substring(0, fullName.length()-1); + } + String newName = fullName; + if (null != fullName && fullName.contains(seperator)) { + newName = fullName.substring(fullName.lastIndexOf(seperator) + 1); + } + return newName; + } + + /** + * 文件节点(区分文件上下级) + */ + public class FileNode{ + + private String originName; + private String fileName; + private String parentFileName; + private boolean directory; + + private List childList; + + public FileNode(String originName, String fileName, String parentFileName, List childList, boolean directory) { + this.originName = originName; + this.fileName = fileName; + this.parentFileName = parentFileName; + this.childList = childList; + this.directory = directory; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getParentFileName() { + return parentFileName; + } + + public void setParentFileName(String parentFileName) { + this.parentFileName = parentFileName; + } + + public List getChildList() { + return childList; + } + + public void setChildList(List childList) { + this.childList = childList; + } + + @Override + public String toString() { + try { + return new ObjectMapper().writeValueAsString(this); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return ""; + } + } + + public String getOriginName() { + return originName; + } + + public void setOriginName(String originName) { + this.originName = originName; + } + + public boolean isDirectory() { + return directory; + } + + public void setDirectory(boolean directory) { + this.directory = directory; + } + } + + /** + * Zip文件抽取线程 + */ + class ZipExtractorWorker implements Runnable { + + private List> entriesToBeExtracted; + private ZipFile zipFile; + private String filePath; + + public ZipExtractorWorker(List> entriesToBeExtracted, ZipFile zipFile, String filePath) { + this.entriesToBeExtracted = entriesToBeExtracted; + this.zipFile = zipFile; + this.filePath = filePath; + } + + @Override + public void run() { + System.out.println("解析压缩文件开始《《《《《《《《《《《《《《《《《《《《《《《"); + for (Map entryMap : entriesToBeExtracted) { + String childName = entryMap.keySet().iterator().next(); + ZipArchiveEntry entry = entryMap.values().iterator().next(); + try { + extractZipFile(childName, zipFile.getInputStream(entry)); + } catch (IOException e) { + e.printStackTrace(); + } + } + try { + zipFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + if (new File(filePath).exists()) { + new File(filePath).delete(); + } + System.out.println("解析压缩文件结束《《《《《《《《《《《《《《《《《《《《《《《"); + } + + + /** + * 读取压缩文件并写入到fileDir文件夹下 + * @param childName + * @param zipFile + */ + private void extractZipFile(String childName, InputStream zipFile) { + String outPath = fileDir + childName; + try (OutputStream ot = new FileOutputStream(outPath)){ + byte[] inByte = new byte[1024]; + int len; + while ((-1 != (len = zipFile.read(inByte)))){ + ot.write(inByte, 0, len); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * Rar文件抽取 + */ + class RarExtractorWorker implements Runnable { + private List> headersToBeExtracted; + private Archive archive; + /** + * 用以删除源文件 + */ + private String filePath; + + public RarExtractorWorker(List> headersToBeExtracted, Archive archive, String filePath) { + this.headersToBeExtracted = headersToBeExtracted; + this.archive = archive; + this.filePath = filePath; + } + + @Override + public void run() { + System.out.println("解析压缩文件开始《《《《《《《《《《《《《《《《《《《《《《《"); + for (Map entryMap : headersToBeExtracted) { + String childName = entryMap.keySet().iterator().next(); + extractRarFile(childName, entryMap.values().iterator().next(), archive); + } + try { + archive.close(); + } catch (IOException e) { + e.printStackTrace(); + } + if (new File(filePath).exists()) { + new File(filePath).delete(); + } + System.out.println("解析压缩文件结束《《《《《《《《《《《《《《《《《《《《《《《"); + } + + /** + * 抽取rar文件到指定目录下 + * @param childName + * @param header + * @param archive + */ + private void extractRarFile(String childName, FileHeader header, Archive archive) { + String outPath = fileDir + childName; + try(OutputStream ot = new FileOutputStream(outPath)) { + archive.extractFile(header, ot); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (RarException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/yudianbank/web/controller/FileController.java b/src/main/java/com/yudianbank/web/controller/FileController.java new file mode 100644 index 000000000..331032bcc --- /dev/null +++ b/src/main/java/com/yudianbank/web/controller/FileController.java @@ -0,0 +1,113 @@ +package com.yudianbank.web.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.yudianbank.param.ReturnResponse; +import com.yudianbank.utils.FileUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +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 javax.servlet.http.HttpServletRequest; +import java.io.*; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * + * @author yudian-it + * @date 2017/12/1 + */ +@RestController +public class FileController { + @Value("${file.dir}") + String fileDir; + @Autowired + FileUtils fileUtils; + String demoDir = "demo"; + String demoPath = demoDir + File.separator; + + @RequestMapping(value = "fileUpload", method = RequestMethod.POST) + public String fileUpload(@RequestParam("file") MultipartFile file, + HttpServletRequest request) throws JsonProcessingException { + String fileName = file.getOriginalFilename(); + // 判断该文件类型是否有上传过,如果上传过则提示不允许再次上传 + if (existsTypeFile(fileName)) { + return new ObjectMapper().writeValueAsString(new ReturnResponse(1, "每一种类型只可以上传一个文件,请先删除原有文件再次上传", null)); + } + File outFile = new File(fileDir + demoPath); + if (!outFile.exists()) { + outFile.mkdirs(); + } + try(InputStream in = file.getInputStream(); + OutputStream ot = new FileOutputStream(fileDir + demoPath + fileName)){ + byte[] buffer = new byte[1024]; + int len; + while ((-1 != (len = in.read(buffer)))) { + ot.write(buffer, 0, len); + } + return new ObjectMapper().writeValueAsString(new ReturnResponse(0, "SUCCESS", null)); + } catch (IOException e) { + e.printStackTrace(); + return new ObjectMapper().writeValueAsString(new ReturnResponse(1, "FAILURE", null)); + } + } + + @RequestMapping(value = "deleteFile", method = RequestMethod.GET) + public String deleteFile(String fileName) throws JsonProcessingException { + if (fileName.contains("/")) { + fileName = fileName.substring(fileName.lastIndexOf("/") + 1); + } + File file = new File(fileDir + demoPath + fileName); + if (file.exists()) { + file.delete(); + } + return new ObjectMapper().writeValueAsString(new ReturnResponse(0, "SUCCESS", null)); + } + + @RequestMapping(value = "listFiles", method = RequestMethod.GET) + public String getFiles() throws JsonProcessingException { + List> list = Lists.newArrayList(); + File file = new File(fileDir + demoPath); + if (file.exists()) { + Arrays.stream(file.listFiles()).forEach(file1 -> list.add(ImmutableMap.of("fileName", demoDir + "/" + file1.getName()))); + } + return new ObjectMapper().writeValueAsString(list); + } + + private String getFileName(String name) { + String suffix = name.substring(name.lastIndexOf(".")); + String nameNoSuffix = name.substring(0, name.lastIndexOf(".")); + String uuid = UUID.randomUUID().toString(); + return uuid + "-" + nameNoSuffix + suffix; + } + + /** + * 是否存在该类型的文件 + * @return + * @param fileName + */ + private boolean existsTypeFile(String fileName) { + boolean result = false; + String suffix = fileUtils.getSuffixFromFileName(fileName); + File file = new File(fileDir + demoPath); + if (file.exists()) { + for(File file1 : file.listFiles()){ + String existsFileSuffix = fileUtils.getSuffixFromFileName(file1.getName()); + if (suffix.equals(existsFileSuffix)) { + result = true; + break; + } + } + } + return result; + } +} diff --git a/src/main/java/com/yudianbank/web/controller/OnlinePreviewController.java b/src/main/java/com/yudianbank/web/controller/OnlinePreviewController.java new file mode 100644 index 000000000..eece64f08 --- /dev/null +++ b/src/main/java/com/yudianbank/web/controller/OnlinePreviewController.java @@ -0,0 +1,170 @@ +package com.yudianbank.web.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yudianbank.param.ReturnResponse; +import com.yudianbank.utils.DownloadUtils; +import com.yudianbank.utils.FileUtils; +import com.yudianbank.utils.OfficeToPdf; +import com.yudianbank.utils.ZipReader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +/** + * @author yudian-it + */ +@Controller +public class OnlinePreviewController { + @Autowired + private OfficeToPdf officeToPdf; + @Autowired + FileUtils fileUtils; + @Autowired + DownloadUtils downloadUtils; + @Autowired + ZipReader zipReader; + + @Value("${file.dir}") + String fileDir; + + /** + * xls:http://keking.ufile.ucloud.com.cn/20171113164107_月度绩效表模板(新).xls?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=I+D1NOFtAJSPT16E6imv6JWuq0k= + * img:http://keking.ufile.ucloud.com.cn/ufile-a703a5a2-788f-488c-a9bf-f36878d5e308.JPG?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=W9TKj5Kp9oxg85fn5/0zgwF2PL4= + * doc:http://keking.ufile.ucloud.com.cn/20171113173342_凯京新员工试用期评估与转正确认表.doc?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=v1fC5ijYs8WnPzbSYa/bb0Z2Jf4= + * docx:http://keking.ufile.ucloud.com.cn/20171103180053_财产线索类需求20170920(1).docx?UCloudPublicKey=ucloudtangshd@weifenf.com14355492830001993909323&Expires=&Signature=p7/L1W3iwktzRtkY5Ef2vK7kn3o= + * @param url + * @param model + * @return + */ + @RequestMapping(value = "onlinePreview",method = RequestMethod.GET) + public String onlinePreview(String url, String needEncode, Model model) throws UnsupportedEncodingException { + // 路径转码 + url = URLDecoder.decode(url, "utf-8"); + String type = typeFromUrl(url); + String suffix = suffixFromUrl(url); + model.addAttribute("fileType", suffix); + if (type.equalsIgnoreCase("picture")) { + model.addAttribute("imgurl", url); + return "picture"; + } else if (type.equalsIgnoreCase("txt") + || type.equalsIgnoreCase("html") + || type.equalsIgnoreCase("xml") + || type.equalsIgnoreCase("java") + || type.equalsIgnoreCase("properties") + || type.equalsIgnoreCase("mp3")){ + model.addAttribute("ordinaryUrl",url); + return "txt"; + } else if(type.equalsIgnoreCase("pdf")){ + model.addAttribute("pdfUrl",url); + return "pdf"; + } else if(type.equalsIgnoreCase("compress")){ + // 抽取文件并返回文件列表 + String fileName = fileUtils.getFileNameFromURL(url); + String fileTree = null; + // 判断文件名是否存在(redis缓存读取) + if (!StringUtils.hasText(fileUtils.getConvertedFile(fileName))) { + ReturnResponse response = downloadUtils.downLoad(url, suffix, fileName, needEncode); + if (0 != response.getCode()) { + model.addAttribute("msg", response.getMsg()); + return "fileNotSupported"; + } + String filePath = response.getContent(); + if ("zip".equalsIgnoreCase(suffix) + || "jar".equalsIgnoreCase(suffix) + || "gzip".equalsIgnoreCase(suffix)) { + fileTree = zipReader.readZipFile(filePath); + } else if ("rar".equalsIgnoreCase(suffix)) { + fileTree = zipReader.unRar(filePath); + } + fileUtils.addConvertedFile(fileName, fileTree); + }else { + fileTree = fileUtils.getConvertedFile(fileName); + } + System.out.println("返回文件tree》》》》》》》》》》》》》》》》》》》"); + if (null != fileTree) { + model.addAttribute("fileTree",fileTree); + return "compress"; + }else { + model.addAttribute("msg", "压缩文件类型不受支持,尝试在压缩的时候选择RAR4格式"); + return "fileNotSupported"; + } + } else if ("office".equalsIgnoreCase(type)) { + String fileName = fileUtils.getFileNameFromURL(url); + String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + + ((suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx")) ? + "html" : "pdf"); + // 判断之前是否已转换过,如果转换过,直接返回,否则执行转换 + if (!fileUtils.listConvertedFiles().containsKey(pdfName)) { + String filePath = fileDir + fileName; + if (!new File(filePath).exists()) { + ReturnResponse response = downloadUtils.downLoad(url, suffix, null, needEncode); + if (0 != response.getCode()) { + model.addAttribute("msg", response.getMsg()); + return "fileNotSupported"; + } + filePath = response.getContent(); + } + String outFilePath = fileDir + pdfName; + if (StringUtils.hasText(outFilePath)) { + officeToPdf.openOfficeToPDF(filePath, outFilePath); + File f = new File(filePath); + if (f.exists()) { + f.delete(); + } + if (suffix.equalsIgnoreCase("xls") + || suffix.equalsIgnoreCase("xlsx")) { + // 对转换后的文件进行操作(改变编码方式) + fileUtils.doActionConvertedFile(outFilePath); + } + // 加入缓存 + fileUtils.addConvertedFile(pdfName, fileUtils.getRelativePath(outFilePath)); + } + } + model.addAttribute("pdfUrl", pdfName); + return "pdf"; + }else { + model.addAttribute("msg", "系统还不支持该格式文件的在线预览," + "如有需要请按下方显示的邮箱地址联系系统维护人员"); + return "fileNotSupported"; + } + } + + private String suffixFromUrl(String url) { + String nonPramStr = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?"): url.length()); + String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1); + String fileType = fileName.substring(fileName.lastIndexOf(".") + 1); + return fileType; + } + + /** + * 查看文件类型(防止参数中存在.点号或者其他特殊字符,所以先抽取文件名,然后再获取文件类型) + * @param url + * @return + */ + private String typeFromUrl(String url) { + String nonPramStr = url.substring(0, url.indexOf("?") != -1 ? url.indexOf("?"): url.length()); + String fileName = nonPramStr.substring(nonPramStr.lastIndexOf("/") + 1); + String fileType = fileName.substring(fileName.lastIndexOf(".") + 1); + if (fileUtils.listPictureTypes().contains(fileType.toLowerCase())) { + fileType = "picture"; + } + if (fileUtils.listArchiveTypes().contains(fileType.toLowerCase())) { + fileType = "compress"; + } + if (fileUtils.listOfficeTypes().contains(fileType.toLowerCase())) { + fileType = "office"; + } + return fileType; + } + + +} diff --git a/src/main/resources/META-INF/app.properties b/src/main/resources/META-INF/app.properties new file mode 100644 index 000000000..ca9d3a6d2 --- /dev/null +++ b/src/main/resources/META-INF/app.properties @@ -0,0 +1 @@ +app.id=file-preview diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 000000000..830769bd9 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,30 @@ +server.port = 8012 +spring.http.encoding.charset = utf8 + +## Freemarker 配置 +## 文件配置路径 +spring.freemarker.template-loader-path = classpath:/web/ +spring.freemarker.cache = false +spring.freemarker.charset = UTF-8 +spring.freemarker.check-template-location = true +spring.freemarker.content-type = text/html +spring.freemarker.expose-request-attributes = true +spring.freemarker.expose-session-attributes = true +spring.freemarker.request-context-attribute = request +spring.freemarker.suffix = .ftl + +#=============================================#spring Redisson配置#===================================# +spring.redisson.address = 192.168.1.204:6379 +#Redisson配置end + +##资源映射路径(因为jar方式运行的原因) +file.dir = C:\\Users\\yudian\\Desktop\\dev\\ +spring.resources.static-locations = classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${file.dir} + +## openoffice相关配置 +openOfficePath = /Applications/OpenOffice.app/Contents +office.home = C:\\Program Files (x86)\\OpenOffice 4 +server.tomcat.uri-encoding = UTF-8 +converted.file.charset = GBK +#======================================#文件上传限制#======================================# +spring.http.multipart.max-file-size=100MB \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 000000000..cb40b4099 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,18 @@ + + + + + + + + 10800 + 192.168.1.109 + true + {"app_name":"@appName@"} + + + + + + \ No newline at end of file diff --git a/src/main/resources/static/config.js b/src/main/resources/static/config.js new file mode 100644 index 000000000..51ac0bd76 --- /dev/null +++ b/src/main/resources/static/config.js @@ -0,0 +1,8 @@ +env_base_config = { + server_base_url:'http://127.0.0.1:8012/', +} +env_config = { + server_base_url:env_base_config.server_base_url, + server_preview_url:env_base_config.server_base_url + 'onlinePreview?url=', + server_delete_url:env_base_config.server_base_url + 'deleteFile?fileName=', +} \ No newline at end of file diff --git a/src/main/resources/static/css/img/diy/1_close.png b/src/main/resources/static/css/img/diy/1_close.png new file mode 100644 index 000000000..68ccb3c3b Binary files /dev/null and b/src/main/resources/static/css/img/diy/1_close.png differ diff --git a/src/main/resources/static/css/img/diy/1_open.png b/src/main/resources/static/css/img/diy/1_open.png new file mode 100644 index 000000000..d6ff36d3a Binary files /dev/null and b/src/main/resources/static/css/img/diy/1_open.png differ diff --git a/src/main/resources/static/css/img/diy/2.png b/src/main/resources/static/css/img/diy/2.png new file mode 100644 index 000000000..9eff506ba Binary files /dev/null and b/src/main/resources/static/css/img/diy/2.png differ diff --git a/src/main/resources/static/css/img/diy/3.png b/src/main/resources/static/css/img/diy/3.png new file mode 100644 index 000000000..d7ba6d0c6 Binary files /dev/null and b/src/main/resources/static/css/img/diy/3.png differ diff --git a/src/main/resources/static/css/img/diy/4.png b/src/main/resources/static/css/img/diy/4.png new file mode 100644 index 000000000..753e2bfd5 Binary files /dev/null and b/src/main/resources/static/css/img/diy/4.png differ diff --git a/src/main/resources/static/css/img/diy/5.png b/src/main/resources/static/css/img/diy/5.png new file mode 100644 index 000000000..0c5eccd56 Binary files /dev/null and b/src/main/resources/static/css/img/diy/5.png differ diff --git a/src/main/resources/static/css/img/diy/6.png b/src/main/resources/static/css/img/diy/6.png new file mode 100644 index 000000000..070b8352d Binary files /dev/null and b/src/main/resources/static/css/img/diy/6.png differ diff --git a/src/main/resources/static/css/img/diy/7.png b/src/main/resources/static/css/img/diy/7.png new file mode 100644 index 000000000..532b037f2 Binary files /dev/null and b/src/main/resources/static/css/img/diy/7.png differ diff --git a/src/main/resources/static/css/img/diy/8.png b/src/main/resources/static/css/img/diy/8.png new file mode 100644 index 000000000..a8f3a86e7 Binary files /dev/null and b/src/main/resources/static/css/img/diy/8.png differ diff --git a/src/main/resources/static/css/img/diy/9.png b/src/main/resources/static/css/img/diy/9.png new file mode 100644 index 000000000..4db73cd41 Binary files /dev/null and b/src/main/resources/static/css/img/diy/9.png differ diff --git a/src/main/resources/static/css/img/line_conn.gif b/src/main/resources/static/css/img/line_conn.gif new file mode 100644 index 000000000..d561d36a9 Binary files /dev/null and b/src/main/resources/static/css/img/line_conn.gif differ diff --git a/src/main/resources/static/css/img/loading.gif b/src/main/resources/static/css/img/loading.gif new file mode 100644 index 000000000..e8c289293 Binary files /dev/null and b/src/main/resources/static/css/img/loading.gif differ diff --git a/src/main/resources/static/css/img/zTreeStandard.gif b/src/main/resources/static/css/img/zTreeStandard.gif new file mode 100644 index 000000000..50c94fd41 Binary files /dev/null and b/src/main/resources/static/css/img/zTreeStandard.gif differ diff --git a/src/main/resources/static/css/img/zTreeStandard.png b/src/main/resources/static/css/img/zTreeStandard.png new file mode 100644 index 000000000..ffda01ef1 Binary files /dev/null and b/src/main/resources/static/css/img/zTreeStandard.png differ diff --git a/src/main/resources/static/css/loading.css b/src/main/resources/static/css/loading.css new file mode 100644 index 000000000..771a6d8eb --- /dev/null +++ b/src/main/resources/static/css/loading.css @@ -0,0 +1,121 @@ +.loading_container{ + margin:0; + padding:0; + position: absolute; + left:0; + top:0; + width:100%; + display: none; + opacity: 0.5; + background-color: black; +} +.spinner { + margin: 245px auto; + width: 60px; + height: 60px; + position: relative; +} + +.container1 > div, .container2 > div, .container3 > div { + width: 16px; + height: 16px; + background-color: #67CF22; + + border-radius: 100%; + position: absolute; + -webkit-animation: bouncedelay 1.2s infinite ease-in-out; + animation: bouncedelay 1.2s infinite ease-in-out; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} + +.spinner .spinner-container { + position: absolute; + width: 100%; + height: 100%; +} + +.container2 { + -webkit-transform: rotateZ(45deg); + transform: rotateZ(45deg); +} + +.container3 { + -webkit-transform: rotateZ(90deg); + transform: rotateZ(90deg); +} + +.circle1 { top: 0; left: 0; } +.circle2 { top: 0; right: 0; } +.circle3 { right: 0; bottom: 0; } +.circle4 { left: 0; bottom: 0; } + +.container2 .circle1 { + -webkit-animation-delay: -1.1s; + animation-delay: -1.1s; +} + +.container3 .circle1 { + -webkit-animation-delay: -1.0s; + animation-delay: -1.0s; +} + +.container1 .circle2 { + -webkit-animation-delay: -0.9s; + animation-delay: -0.9s; +} + +.container2 .circle2 { + -webkit-animation-delay: -0.8s; + animation-delay: -0.8s; +} + +.container3 .circle2 { + -webkit-animation-delay: -0.7s; + animation-delay: -0.7s; +} + +.container1 .circle3 { + -webkit-animation-delay: -0.6s; + animation-delay: -0.6s; +} + +.container2 .circle3 { + -webkit-animation-delay: -0.5s; + animation-delay: -0.5s; +} + +.container3 .circle3 { + -webkit-animation-delay: -0.4s; + animation-delay: -0.4s; +} + +.container1 .circle4 { + -webkit-animation-delay: -0.3s; + animation-delay: -0.3s; +} + +.container2 .circle4 { + -webkit-animation-delay: -0.2s; + animation-delay: -0.2s; +} + +.container3 .circle4 { + -webkit-animation-delay: -0.1s; + animation-delay: -0.1s; +} + +@-webkit-keyframes bouncedelay { + 0%, 80%, 100% { -webkit-transform: scale(0.0) } + 40% { -webkit-transform: scale(1.0) } +} + +@keyframes bouncedelay { + 0%, 80%, 100% { + transform: scale(0.0); + -webkit-transform: scale(0.0); + } 40% { + transform: scale(1.0); + -webkit-transform: scale(1.0); + } +} \ No newline at end of file diff --git a/src/main/resources/static/css/viewer.min.css b/src/main/resources/static/css/viewer.min.css new file mode 100644 index 000000000..10f7a6398 --- /dev/null +++ b/src/main/resources/static/css/viewer.min.css @@ -0,0 +1,9 @@ +/*! + * Viewer.js v0.3.1 + * https://github.com/fengyuanchen/viewerjs + * + * Copyright (c) 2015-2016 Fengyuan Chen + * Released under the MIT license + * + * Date: 2016-02-02T11:35:36.273Z + */.viewer-container,.viewer-navbar{background-color:#000;overflow:hidden}.viewer-canvas,.viewer-container,.viewer-footer,.viewer-player{right:0;bottom:0;left:0}.viewer-button,.viewer-canvas,.viewer-container,.viewer-footer,.viewer-list,.viewer-navbar,.viewer-open,.viewer-title,.viewer-toolbar,.viewer-toolbar>li{overflow:hidden}.viewer-close:before,.viewer-flip-horizontal:before,.viewer-flip-vertical:before,.viewer-fullscreen-exit:before,.viewer-fullscreen:before,.viewer-next:before,.viewer-one-to-one:before,.viewer-play:before,.viewer-prev:before,.viewer-reset:before,.viewer-rotate-left:before,.viewer-rotate-right:before,.viewer-zoom-in:before,.viewer-zoom-out:before{font-size:0;line-height:0;display:block;width:20px;height:20px;color:transparent;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC);background-repeat:no-repeat}.viewer-zoom-in:before{content:'Zoom In';background-position:0 0}.viewer-zoom-out:before{content:'Zoom Out';background-position:-20px 0}.viewer-one-to-one:before{content:'One to One';background-position:-40px 0}.viewer-reset:before{content:'Reset';background-position:-60px 0}.viewer-prev:before{content:'Previous';background-position:-80px 0}.viewer-play:before{content:'Play';background-position:-100px 0}.viewer-next:before{content:'Next';background-position:-120px 0}.viewer-rotate-left:before{content:'Rotate Left';background-position:-140px 0}.viewer-rotate-right:before{content:'Rotate Right';background-position:-160px 0}.viewer-flip-horizontal:before{content:'Flip Horizontal';background-position:-180px 0}.viewer-flip-vertical:before{content:'Flip Vertical';background-position:-200px 0}.viewer-fullscreen:before{content:'Enter Full Screen';background-position:-220px 0}.viewer-fullscreen-exit:before{content:'Exit Full Screen';background-position:-240px 0}.viewer-close:before{content:'Close';background-position:-260px 0}.viewer-container{font-size:0;line-height:0;position:absolute;top:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:rgba(0,0,0,.5);direction:ltr!important;-ms-touch-action:none;touch-action:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.viewer-container ::-moz-selection,.viewer-container::-moz-selection{background-color:transparent}.viewer-container ::selection,.viewer-container::selection{background-color:transparent}.viewer-container img{display:block;width:100%;min-width:0!important;max-width:none!important;height:auto;min-height:0!important;max-height:none!important}.viewer-player,.viewer-tooltip{display:none;position:absolute}.viewer-canvas{position:absolute;top:0}.viewer-canvas>img{width:auto;max-width:90%!important;height:auto;margin:15px auto}.viewer-footer{position:absolute;text-align:center}.viewer-navbar{background-color:rgba(0,0,0,.5)}.viewer-list{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:50px;margin:0;padding:1px 0}.viewer-list>li{font-size:0;line-height:0;float:left;overflow:hidden;width:30px;height:50px;cursor:pointer;opacity:.5;color:transparent;filter:alpha(opacity=50)}.viewer-list>li+li{margin-left:1px}.viewer-list>.viewer-active{opacity:1;filter:alpha(opacity=100)}.viewer-player{top:0;cursor:none;background-color:#000}.viewer-player>img{position:absolute;top:0;left:0}.viewer-toolbar{width:280px;margin:0 auto 5px;padding:3px 0}.viewer-toolbar>li{float:left;width:24px;height:24px;cursor:pointer;border-radius:50%;background-color:#000;background-color:rgba(0,0,0,.5)}.viewer-toolbar>li:hover{background-color:#000;background-color:rgba(0,0,0,.8)}.viewer-toolbar>li:before{margin:2px}.viewer-toolbar>li+li{margin-left:1px}.viewer-toolbar>.viewer-play{width:30px;height:30px;margin-top:-3px;margin-bottom:-3px}.viewer-toolbar>.viewer-play:before{margin:5px}.viewer-tooltip{font-size:12px;line-height:20px;top:50%;left:50%;width:50px;height:20px;margin-top:-10px;margin-left:-25px;text-align:center;color:#fff;border-radius:10px;background-color:#000;background-color:rgba(0,0,0,.8)}.viewer-title{font-size:12px;line-height:1;display:inline-block;max-width:90%;margin:0 5% 5px;white-space:nowrap;text-overflow:ellipsis;opacity:.8;color:#ccc;filter:alpha(opacity=80)}.viewer-title:hover{opacity:1;filter:alpha(opacity=100)}.viewer-button{position:absolute;top:-40px;right:-40px;width:80px;height:80px;cursor:pointer;border-radius:50%;background-color:#000;background-color:rgba(0,0,0,.5)}.viewer-button:before{position:absolute;bottom:15px;left:15px}.viewer-fixed{position:fixed}.viewer-show{display:block}.viewer-hide{display:none}.viewer-invisible{visibility:hidden}.viewer-move{cursor:move;cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.viewer-fade{opacity:0;filter:alpha(opacity=0)}.viewer-in{opacity:1;filter:alpha(opacity=100)}.viewer-transition{-webkit-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}@media (max-width:767px){.viewer-hide-xs-down{display:none}}@media (max-width:991px){.viewer-hide-sm-down{display:none}}@media (max-width:1199px){.viewer-hide-md-down{display:none}} \ No newline at end of file diff --git a/src/main/resources/static/css/zTreeStyle.css b/src/main/resources/static/css/zTreeStyle.css new file mode 100644 index 000000000..4a1705b14 --- /dev/null +++ b/src/main/resources/static/css/zTreeStyle.css @@ -0,0 +1,97 @@ +/*------------------------------------- +zTree Style + +version: 3.5.19 +author: Hunter.z +email: hunter.z@263.net +website: http://code.google.com/p/jquerytree/ + +-------------------------------------*/ + +.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif} +.ztree {margin:0; padding:5px; color:#333} +.ztree li{padding:0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0} +.ztree li ul{ margin:0; padding:0 0 0 18px} +.ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;} + +.ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:17px; color:#333; background-color: transparent; + text-decoration:none; vertical-align:top; display: inline-block} +.ztree li a:hover {text-decoration:underline} +.ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;} +.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;} +.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid; + opacity:0.8; filter:alpha(opacity=80)} +.ztree li a.tmpTargetNode_prev {} +.ztree li a.tmpTargetNode_next {} +.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0; + font-size:12px; border:1px #7EC4CC solid; *border:0px} +.ztree li span {line-height:16px; margin-right:2px} +.ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle; + border:0 none; cursor: pointer;outline:none; + background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; + background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")} + +.ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto} +.ztree li span.button.chk.checkbox_false_full {background-position:0 0} +.ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px} +.ztree li span.button.chk.checkbox_false_part {background-position:0 -28px} +.ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px} +.ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px} +.ztree li span.button.chk.checkbox_true_full {background-position:-14px 0} +.ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px} +.ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px} +.ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px} +.ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px} +.ztree li span.button.chk.radio_false_full {background-position:-28px 0} +.ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px} +.ztree li span.button.chk.radio_false_part {background-position:-28px -28px} +.ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px} +.ztree li span.button.chk.radio_false_disable {background-position:-28px -56px} +.ztree li span.button.chk.radio_true_full {background-position:-42px 0} +.ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px} +.ztree li span.button.chk.radio_true_part {background-position:-42px -28px} +.ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px} +.ztree li span.button.chk.radio_true_disable {background-position:-42px -56px} + +.ztree li span.button.switch {width:18px; height:18px} +.ztree li span.button.root_open{background-position:-92px -54px} +.ztree li span.button.root_close{background-position:-74px -54px} +.ztree li span.button.roots_open{background-position:-92px 0} +.ztree li span.button.roots_close{background-position:-74px 0} +.ztree li span.button.center_open{background-position:-92px -18px} +.ztree li span.button.center_close{background-position:-74px -18px} +.ztree li span.button.bottom_open{background-position:-92px -36px} +.ztree li span.button.bottom_close{background-position:-74px -36px} +.ztree li span.button.noline_open{background-position:-92px -72px} +.ztree li span.button.noline_close{background-position:-74px -72px} +.ztree li span.button.root_docu{ background:none;} +.ztree li span.button.roots_docu{background-position:-56px 0} +.ztree li span.button.center_docu{background-position:-56px -18px} +.ztree li span.button.bottom_docu{background-position:-56px -36px} +.ztree li span.button.noline_docu{ background:none;} + +.ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle} +.ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle} +.ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; vertical-align:top; *vertical-align:middle} +.ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle} +.ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle} + +.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle} + +ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)} + +span.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute; + background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; + background-position:-110px -80px; background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")} + +ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)} +.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute} + +/* level style*/ +/*.ztree li span.button.level0 { + display:none; +} +.ztree li ul.level0 { + padding:0; + background:none; +}*/ \ No newline at end of file diff --git a/src/main/resources/static/images/sorry.jpg b/src/main/resources/static/images/sorry.jpg new file mode 100644 index 000000000..03c9dd37e Binary files /dev/null and b/src/main/resources/static/images/sorry.jpg differ diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html new file mode 100644 index 000000000..f235f26a9 --- /dev/null +++ b/src/main/resources/static/index.html @@ -0,0 +1,172 @@ + + + + + 图片预览图 + + + + + + + + +

文件预览项目接入和测试界面

+
+
+ +
+
+
+ 如果你的项目需要接入文件预览项目,达到对docx、excel、ppt、jpg等文件的预览效果,那么通过在你的项目中加入下面的代码就可以 + 成功实现: +
+                        $scope.openWin = function (fileUrl) {
+                            var url = configuration.previewUrl + encodeURIComponent(fileUrl);
+                            var winHeight = window.document.documentElement.clientHeight-10;
+                            $window.open(url, "_blank", "height=" + winHeight
+                                + ",top=80,left=80,toolbar=no, menubar=no, scrollbars=yes, resizable=yes");
+                        };
+                    
+ 说明: +

1.这里的fileUrl即是需要预览的服务器文件,一般是ufile文件

+

2.只所以使用encodeURIComponent转码是因为ufile文件中可能会存在&等特殊字符,那么如果不转码会被浏览器处理成多参数 + 这样后台获取的就不是需要预览的文件的全路径了。

+

3.configuration.previewUrl是需要接入项目中配置文件预览项目的地址的配置 + 现在开发和测试地址都是: + http://106.75.31.215:8012/onlinePreview?url=服务器(ufile)文件路径

+
+
+
+
+ +
+ +
+
+

因为是测试所以一种文件只允许上传一个

+
+
+ + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/static/js/excel.header.js b/src/main/resources/static/js/excel.header.js new file mode 100644 index 000000000..8852d1f8e --- /dev/null +++ b/src/main/resources/static/js/excel.header.js @@ -0,0 +1,19 @@ +/**创建一个div并固定在底部,将center中的所有a标签放在改div中**/ +$("body").append($("
").css({"width":"100%","height":"30px","position":"fixed","top":"0","left":"0" + ,"background-color":"rgba(53, 53, 53, 1)","line-height":"30px","font-size":"13px"}).attr("id","excel-header-nav")); +$("center").css("display", "none"); +var centerChildrenA = $("center").children("a"); +if (centerChildrenA.length === 0) { + $("#excel-header-nav").hide(); +} +$(centerChildrenA).each(function (a, b) { + // 获取a标签对应的target的name值,并设置name对应标签的样式以避免锚点标签标题被覆盖 + var href = $(b).attr("href"); + var name = href.substr(1); + console.log(href + ":" + name); + $("[name=" + name + "]").css({"display":"block","padding-top":"14.01px"}); + $(b).css({"padding":"5px","border-right":"1px solid white","color":"#f9f9f9"}); + $("#excel-header-nav").append(b); +}); +/**给所有的table添加class=table table-striped样式**/ +$("table").addClass("table table-striped"); \ No newline at end of file diff --git a/src/main/resources/static/js/jquery-3.0.0.min.js b/src/main/resources/static/js/jquery-3.0.0.min.js new file mode 100644 index 000000000..62d410d95 --- /dev/null +++ b/src/main/resources/static/js/jquery-3.0.0.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.0.0 | (c) jQuery Foundation | 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.0.0",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?0>a?this[a+this.length]:this[a]:f.call(this)},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+(0>a?b:0);return this.pushStack(c>=0&&b>c?[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--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=r.isArray(d)))?(e?(e=!1,f=c&&r.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)},isArray:Array.isArray,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):!0:!1},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)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;c>d;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;c>d;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;g>f;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;d>f;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;return"string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a)?(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):void 0},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)?!1:"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;d>c;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-]|[^\x00-\\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:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,ca=function(a,b){return b?"\x00"===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},{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"label"in b&&b.disabled===a||"form"in b&&b.disabled===a||"form"in b&&b.disabled===!1&&(b.isDisabled===a||b.isDisabled!==!a&&("label"in b||!ea(b))!==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:!1},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.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){return a.getAttribute("id")===b}}):(delete d.find.ID,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.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){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",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="";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+"-":!1):!0}},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[0>c?c+b:c]}),even:pa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=0>c?c+b:c;++db;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)}: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}}}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;e>d;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;i>h;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}];f>i;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;f>e;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,e>i&&ya(a.slice(i,e)),f>e&&ya(a=a.slice(e)),f>e&&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,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(_,aa),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=V.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(_,aa),$.test(j[0].type)&&qa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&sa(j),!a)return G.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||$.test(a)&&qa(b.parentNode)||b),e},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.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;return c?void 0: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,B=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,C=/^.[^:#\[\.,]*$/;function D(a,b,c){if(r.isFunction(b))return r.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return r.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(C.test(b))return r.filter(b,a,c);b=r.filter(b,a)}return 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;d>b;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;d>b;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(D(this,a||[],!1))},not:function(a){return this.pushStack(D(this,a||[],!0))},is:function(a){return!!D(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var E,F=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,G=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||E,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:F.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)),B.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)};G.prototype=r.fn,E=r(d);var H=/^(?:parents|prev(?:Until|All))/,I={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;c>a;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(;e>d;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 J(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 J(a,"nextSibling")},prev:function(a){return J(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 a.contentDocument||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&&(I[a]||r.uniqueSort(e),H.test(a)&&e.reverse()),this.pushStack(e)}});var K=/\S+/g;function L(a){var b={};return r.each(a.match(K)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?L(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&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 M(a){return a}function N(a){throw a}function O(a,b,c){var d;try{a&&r.isFunction(d=a.promise)?d.call(a).done(b).fail(c):a&&r.isFunction(d=a.then)?d.call(a,b,c):b.call(void 0,a)}catch(a){c.call(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(!(f>b)){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,M,e),g(f,c,N,e)):(f++,j.call(a,g(f,c,M,e),g(f,c,N,e),g(f,c,M,c.notifyWith))):(d!==M&&(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!==N&&(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:M,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:M)),c[2][3].add(g(0,a,r.isFunction(d)?d:N))}).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(1>=b&&(O(a,g.done(h(c)).resolve,g.reject),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)O(e[c],h(c),g.reject);return g.promise()}});var P=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&P.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)};var Q=r.Deferred();r.fn.ready=function(a){return Q.then(a),this},r.extend({isReady:!1,readyWait:1,holdReady:function(a){a?r.readyWait++:r.ready(!0)},ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||Q.resolveWith(d,[r]))}}),r.ready.then=Q.then;function R(){d.removeEventListener("DOMContentLoaded",R),a.removeEventListener("load",R),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",R),a.addEventListener("load",R));var S=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)S(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(;i>h;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},T=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function U(){this.expando=r.expando+U.uid++}U.uid=1,U.prototype={cache:function(a){var b=a[this.expando];return b||(b={},T(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){r.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(K)||[]),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 V=new U,W=new U,X=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Y=/[A-Z]/g;function Z(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Y,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:X.test(c)?JSON.parse(c):c}catch(e){}W.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return W.hasData(a)||V.hasData(a)},data:function(a,b,c){return W.access(a,b,c)},removeData:function(a,b){W.remove(a,b)},_data:function(a,b,c){return V.access(a,b,c)},_removeData:function(a,b){V.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=W.get(f),1===f.nodeType&&!V.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),Z(f,d,e[d])));V.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){W.set(this,a)}):S(this,function(b){var c;if(f&&void 0===b){if(c=W.get(f,a),void 0!==c)return c;if(c=Z(f,a),void 0!==c)return c}else this.each(function(){W.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){W.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=V.get(a,b),c&&(!d||r.isArray(c)?d=V.access(a,b,r.makeArray(c)):d.push(c)),d||[]):void 0},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 V.get(a,c)||V.access(a,c,{empty:r.Callbacks("once memory").add(function(){V.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.lengthf;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=V.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&ba(d)&&(e[f]=fa(d))):"none"!==c&&(e[f]="none",V.set(d,"display",c)));for(f=0;g>f;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ga(this,!0)},hide:function(){return ga(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){ba(this)?r(this).show():r(this).hide()})}});var ha=/^(?:checkbox|radio)$/i,ia=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,ja=/^$|\/(?:java|ecma)script/i,ka={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ka.optgroup=ka.option,ka.tbody=ka.tfoot=ka.colgroup=ka.caption=ka.thead,ka.th=ka.td;function la(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&r.nodeName(a,b)?r.merge([a],c):c}function ma(a,b){for(var c=0,d=a.length;d>c;c++)V.set(a[c],"globalEval",!b||V.get(b[c],"globalEval"))}var na=/<|&#?\w+;/;function oa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;o>n;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(na.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ia.exec(f)||["",""])[1].toLowerCase(),i=ka[h]||ka._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=la(l.appendChild(f),"script"),j&&ma(g),c){k=0;while(f=g[k++])ja.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="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var pa=d.documentElement,qa=/^key/,ra=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,sa=/^([^.]*)(?:\.(.+)|)/;function ta(){return!0}function ua(){return!1}function va(){try{return d.activeElement}catch(a){}}function wa(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)wa(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=ua;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=V.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(pa,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(K)||[""],j=b.length;while(j--)h=sa.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=V.hasData(a)&&V.get(a);if(q&&(i=q.events)){b=(b||"").match(K)||[""],j=b.length;while(j--)if(h=sa.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)&&V.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=(V.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;cc;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?r(e,this).index(i)>-1:r.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h\x20\t\r\n\f]*)[^>]*)\/>/gi,ya=/\s*$/g;function Ca(a,b){return r.nodeName(a,"table")&&r.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function Da(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ea(a){var b=Aa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(V.hasData(a)&&(f=V.access(a),g=V.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)r.event.add(b,e,j[e][c])}W.hasData(a)&&(h=W.access(a),i=r.extend({},h),W.set(b,i))}}function Ga(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ha.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ha(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&&za.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(m&&(e=oa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(la(e,"script"),Da),i=h.length;m>l;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,la(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ea),l=0;i>l;l++)j=h[l],ja.test(j.type||"")&&!V.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Ba,""),k))}return a}function Ia(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(la(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&ma(la(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(xa,"<$1>")},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=la(h),f=la(a),d=0,e=f.length;e>d;d++)Ga(f[d],g[d]);if(b)if(c)for(f=f||la(a),g=g||la(h),d=0,e=f.length;e>d;d++)Fa(f[d],g[d]);else Fa(a,h);return g=la(h,"script"),g.length>0&&ma(g,!i&&la(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(T(c)){if(b=c[V.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[V.expando]=void 0}c[W.expando]&&(c[W.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return S(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 Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(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(la(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return S(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&&!ya.test(a)&&!ka[(ia.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(la(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(la(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;f>=g;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var Ja=/^margin/,Ka=new RegExp("^("+$+")(?!px)[a-z%]+$","i"),La=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="",pa.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,pa.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 Ma(a,b,c){var d,e,f,g,h=a.style;return c=c||La(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ka.test(g)&&Ja.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 Na(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Oa=/^(none|table(?!-c[ea]).+)/,Pa={position:"absolute",visibility:"hidden",display:"block"},Qa={letterSpacing:"0",fontWeight:"400"},Ra=["Webkit","Moz","ms"],Sa=d.createElement("div").style;function Ta(a){if(a in Sa)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ra.length;while(c--)if(a=Ra[c]+b,a in Sa)return a}function Ua(a,b,c){var d=_.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Va(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=r.css(a,c+aa[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+aa[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+aa[f]+"Width",!0,e))):(g+=r.css(a,"padding"+aa[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+aa[f]+"Width",!0,e)));return g}function Wa(a,b,c){var d,e=!0,f=La(a),g="border-box"===r.css(a,"boxSizing",!1,f);if(a.getClientRects().length&&(d=a.getBoundingClientRect()[b]),0>=d||null==d){if(d=Ma(a,b,f),(0>d||null==d)&&(d=a.style[b]),Ka.test(d))return d;e=g&&(o.boxSizingReliable()||d===a.style[b]),d=parseFloat(d)||0}return d+Va(a,b,c||(g?"border":"content"),e,f)+"px"}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Ma(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=a.style;return b=r.cssProps[h]||(r.cssProps[h]=Ta(h)||h),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=_.exec(c))&&e[1]&&(c=da(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")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b);return b=r.cssProps[h]||(r.cssProps[h]=Ta(h)||h),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Ma(a,b,d)),"normal"===e&&b in Qa&&(e=Qa[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){return c?!Oa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?Wa(a,b,d):ca(a,Pa,function(){return Wa(a,b,d)}):void 0},set:function(a,c,d){var e,f=d&&La(a),g=d&&Va(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=_.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ua(a,c,g)}}}),r.cssHooks.marginLeft=Na(o.reliableMarginLeft,function(a,b){return b?(parseFloat(Ma(a,"marginLeft"))||a.getBoundingClientRect().left-ca(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px":void 0}),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];4>d;d++)e[a+aa[d]+b]=f[d]||f[d-2]||f[0];return e}},Ja.test(a)||(r.cssHooks[a+b].set=Ua)}),r.fn.extend({css:function(a,b){return S(this,function(a,b,c){var d,e,f={},g=0;if(r.isArray(b)){for(d=La(a),e=b.length;e>g;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 Xa(a,b,c,d,e){return new Xa.prototype.init(a,b,c,d,e)}r.Tween=Xa,Xa.prototype={constructor:Xa,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=Xa.propHooks[this.prop];return a&&a.get?a.get(this):Xa.propHooks._default.get(this)},run:function(a){var b,c=Xa.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):Xa.propHooks._default.set(this),this}},Xa.prototype.init.prototype=Xa.prototype,Xa.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)}}},Xa.propHooks.scrollTop=Xa.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=Xa.prototype.init,r.fx.step={};var Ya,Za,$a=/^(?:toggle|show|hide)$/,_a=/queueHooks$/;function ab(){Za&&(a.requestAnimationFrame(ab),r.fx.tick())}function bb(){return a.setTimeout(function(){Ya=void 0}),Ya=r.now()}function cb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=aa[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function db(a,b,c){for(var d,e=(gb.tweeners[b]||[]).concat(gb.tweeners["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function eb(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&&ba(a),q=V.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],$a.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=V.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ga([a],!0),j=a.style.display||j,k=r.css(a,"display"),ga([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=V.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ga([a],!0),m.done(function(){p||ga([a]),V.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=db(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function fb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],r.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 gb(a,b,c){var d,e,f=0,g=gb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Ya||bb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(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:Ya||bb(),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;d>c;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(fb(k,j.opts.specialEasing);g>f;f++)if(d=gb.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,db,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}r.Animation=r.extend(gb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return da(c.elem,a,_.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(K);for(var c,d=0,e=a.length;e>d;d++)c=a[d],gb.tweeners[c]=gb.tweeners[c]||[],gb.tweeners[c].unshift(b)},prefilters:[eb],prefilter:function(a,b){b?gb.prefilters.unshift(a):gb.prefilters.push(a)}}),r.speed=function(a,b,c){var e=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.hidden?e.duration=0:e.duration="number"==typeof e.duration?e.duration:e.duration in r.fx.speeds?r.fx.speeds[e.duration]:r.fx.speeds._default,null!=e.queue&&e.queue!==!0||(e.queue="fx"),e.old=e.complete,e.complete=function(){r.isFunction(e.old)&&e.old.call(this),e.queue&&r.dequeue(this,e.queue)},e},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(ba).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=gb(this,r.extend({},a),f);(e||V.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=V.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&_a.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=V.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;g>b;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(cb(b,!0),a,d,e)}}),r.each({slideDown:cb("show"),slideUp:cb("hide"),slideToggle:cb("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(Ya=r.now();b1)},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)?hb: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&&r.nodeName(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(K);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c); +}}),hb={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=ib[b]||r.find.attr;ib[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=ib[g],ib[g]=e,e=null!=c(a,b,d)?g:null,ib[g]=f),e}});var jb=/^(?:input|select|textarea|button)$/i,kb=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return S(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):jb.test(a.nodeName)||kb.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});var lb=/[\t\r\n\f]/g;function mb(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,mb(this)))});if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=r.trim(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,mb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=r.trim(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,mb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(K)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=mb(this),b&&V.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":V.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+mb(c)+" ").replace(lb," ").indexOf(b)>-1)return!0;return!1}});var nb=/\r/g,ob=/[\x20\t\r\n\f]+/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+="":r.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(nb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:r.trim(r.text(a)).replace(ob," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&!c.disabled&&(!c.parentNode.disabled||!r.nodeName(c.parentNode,"optgroup"))){if(b=r(c).val(),f)return b;g.push(b)}return g},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){return r.isArray(b)?a.checked=r.inArray(r(a).val(),b)>-1:void 0}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var pb=/^(?: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&&!pb.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,pb.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=(V.get(h,"events")||{})[b.type]&&V.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&T(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||!T(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];return c?r.event.trigger(a,b,c,!0):void 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=V.access(d,b);e||d.addEventListener(a,c,!0),V.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=V.access(d,b)-1;e?V.access(d,b,e):(d.removeEventListener(a,c,!0),V.remove(d,b))}}});var qb=a.location,rb=r.now(),sb=/\?/;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 tb=/\[\]$/,ub=/\r?\n/g,vb=/^(?:submit|button|image|reset|file)$/i,wb=/^(?:input|select|textarea|keygen)/i;function xb(a,b,c,d){var e;if(r.isArray(b))r.each(b,function(b,e){c||tb.test(a)?d(a,e):xb(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)xb(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(r.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)xb(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")&&wb.test(this.nodeName)&&!vb.test(a)&&(this.checked||!ha.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:r.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(ub,"\r\n")}}):{name:b.name,value:c.replace(ub,"\r\n")}}).get()}});var yb=/%20/g,zb=/#.*$/,Ab=/([?&])_=[^&]*/,Bb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Cb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Db=/^(?:GET|HEAD)$/,Eb=/^\/\//,Fb={},Gb={},Hb="*/".concat("*"),Ib=d.createElement("a");Ib.href=qb.href;function Jb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(K)||[];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 Kb(a,b,c,d){var e={},f=a===Gb;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 Lb(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 Mb(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}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Nb(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:qb.href,type:"GET",isLocal:Cb.test(qb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Hb,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?Lb(Lb(a,r.ajaxSettings),b):Lb(r.ajaxSettings,a)},ajaxPrefilter:Jb(Fb),ajaxTransport:Jb(Gb),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=Bb.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||qb.href)+"").replace(Eb,qb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(K)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Ib.protocol+"//"+Ib.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)),Kb(Fb,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=!Db.test(o.type),f=o.url.replace(zb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(yb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(sb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Ab,""),n=(sb.test(f)?"&":"?")+"_="+rb++ +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]?", "+Hb+"; 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=Kb(Gb,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&&300>b||304===b,d&&(v=Mb(o,y,d)),v=Nb(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",0>b&&(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 Ob={0:200,1223:204},Pb=r.ajaxSettings.xhr();o.cors=!!Pb&&"withCredentials"in Pb,o.ajax=Pb=!!Pb,r.ajaxTransport(function(b){var c,d;return o.cors||Pb&&!b.crossDomain?{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(Ob[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()}}:void 0}),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(" + + + + \ No newline at end of file diff --git a/src/main/resources/web/doc.ftl b/src/main/resources/web/doc.ftl new file mode 100644 index 000000000..4d4d3cfd6 --- /dev/null +++ b/src/main/resources/web/doc.ftl @@ -0,0 +1,9 @@ + + + + + +${doc} + + + \ No newline at end of file diff --git a/src/main/resources/web/docxConvert.ftl b/src/main/resources/web/docxConvert.ftl new file mode 100644 index 000000000..3b2ad7de8 --- /dev/null +++ b/src/main/resources/web/docxConvert.ftl @@ -0,0 +1,11 @@ + + + + + + +${docxConvert} + + + + \ No newline at end of file diff --git a/src/main/resources/web/fileNotSupported.ftl b/src/main/resources/web/fileNotSupported.ftl new file mode 100644 index 000000000..a11323b64 --- /dev/null +++ b/src/main/resources/web/fileNotSupported.ftl @@ -0,0 +1,41 @@ + + + + + + + +
+ + + 该文件类型(${fileType})系统暂时不支持在线预览,说明: +

${msg}

+ 如有需要请联系@HappyPig +
+
+ + + \ No newline at end of file diff --git a/src/main/resources/web/pdf.ftl b/src/main/resources/web/pdf.ftl new file mode 100644 index 000000000..148dcafba --- /dev/null +++ b/src/main/resources/web/pdf.ftl @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/web/picture.ftl b/src/main/resources/web/picture.ftl new file mode 100644 index 000000000..bc5f9d555 --- /dev/null +++ b/src/main/resources/web/picture.ftl @@ -0,0 +1,33 @@ + + + + + 图片预览图 + + + + +

如果图片质量很好,首次加载图片时间可能会有点长,请耐心等待

+ +
    +
  • + +
+ + + + + + diff --git a/src/main/resources/web/txt.ftl b/src/main/resources/web/txt.ftl new file mode 100644 index 000000000..60555044c --- /dev/null +++ b/src/main/resources/web/txt.ftl @@ -0,0 +1,18 @@ + + + + + 普通文件预览 + + + + + + + + + + + diff --git a/src/test/java/com/yudianbank/FilePreviewApplicationTests.java b/src/test/java/com/yudianbank/FilePreviewApplicationTests.java new file mode 100644 index 000000000..d92b62453 --- /dev/null +++ b/src/test/java/com/yudianbank/FilePreviewApplicationTests.java @@ -0,0 +1,16 @@ +package com.yudianbank; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class FilePreviewApplicationTests { + + @Test + public void contextLoads() { + } + +}